This is page 19 of 181. Use http://codebase.md/xmlui-org/xmlui/xmlui-latest.js?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .changeset
│ └── config.json
├── .eslintrc.cjs
├── .github
│ ├── build-checklist.png
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows
│ ├── deploy-blog.yml
│ ├── deploy-docs-optimized.yml
│ ├── deploy-docs.yml
│ ├── prepare-versions.yml
│ ├── release-packages.yml
│ ├── run-all-tests.yml
│ └── run-smoke-tests.yml
├── .gitignore
├── .prettierrc.js
├── .vscode
│ ├── launch.json
│ └── settings.json
├── blog
│ ├── .gitignore
│ ├── .gitkeep
│ ├── CHANGELOG.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── layout-changes.md
│ ├── package.json
│ ├── public
│ │ ├── blog
│ │ │ ├── images
│ │ │ │ ├── blog-page-component.png
│ │ │ │ ├── blog-scrabble.png
│ │ │ │ ├── integrated-blog-search.png
│ │ │ │ └── lorem-ipsum.png
│ │ │ ├── lorem-ipsum.md
│ │ │ ├── newest-post.md
│ │ │ ├── older-post.md
│ │ │ └── welcome-to-the-xmlui-blog.md
│ │ ├── mockServiceWorker.js
│ │ ├── resources
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ └── for-download
│ │ │ │ └── xmlui
│ │ │ │ └── xmlui-standalone.umd.js
│ │ │ ├── github.svg
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ ├── rss.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ └── PageNotFound.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── blog-theme.ts
│ └── tsconfig.json
├── CONTRIBUTING.md
├── docs
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── ComponentRefLinks.txt
│ ├── content
│ │ ├── _meta.json
│ │ ├── components
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── APICall.md
│ │ │ ├── App.md
│ │ │ ├── AppHeader.md
│ │ │ ├── AppState.md
│ │ │ ├── AutoComplete.md
│ │ │ ├── Avatar.md
│ │ │ ├── Backdrop.md
│ │ │ ├── Badge.md
│ │ │ ├── BarChart.md
│ │ │ ├── Bookmark.md
│ │ │ ├── Breakout.md
│ │ │ ├── Button.md
│ │ │ ├── Card.md
│ │ │ ├── Carousel.md
│ │ │ ├── ChangeListener.md
│ │ │ ├── Checkbox.md
│ │ │ ├── CHStack.md
│ │ │ ├── ColorPicker.md
│ │ │ ├── Column.md
│ │ │ ├── ContentSeparator.md
│ │ │ ├── CVStack.md
│ │ │ ├── DataSource.md
│ │ │ ├── DateInput.md
│ │ │ ├── DatePicker.md
│ │ │ ├── DonutChart.md
│ │ │ ├── DropdownMenu.md
│ │ │ ├── EmojiSelector.md
│ │ │ ├── ExpandableItem.md
│ │ │ ├── FileInput.md
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FlowLayout.md
│ │ │ ├── Footer.md
│ │ │ ├── Form.md
│ │ │ ├── FormItem.md
│ │ │ ├── FormSection.md
│ │ │ ├── Fragment.md
│ │ │ ├── H1.md
│ │ │ ├── H2.md
│ │ │ ├── H3.md
│ │ │ ├── H4.md
│ │ │ ├── H5.md
│ │ │ ├── H6.md
│ │ │ ├── Heading.md
│ │ │ ├── HSplitter.md
│ │ │ ├── HStack.md
│ │ │ ├── Icon.md
│ │ │ ├── IFrame.md
│ │ │ ├── Image.md
│ │ │ ├── Items.md
│ │ │ ├── LabelList.md
│ │ │ ├── Legend.md
│ │ │ ├── LineChart.md
│ │ │ ├── Link.md
│ │ │ ├── List.md
│ │ │ ├── Logo.md
│ │ │ ├── Markdown.md
│ │ │ ├── MenuItem.md
│ │ │ ├── MenuSeparator.md
│ │ │ ├── ModalDialog.md
│ │ │ ├── NavGroup.md
│ │ │ ├── NavLink.md
│ │ │ ├── NavPanel.md
│ │ │ ├── NoResult.md
│ │ │ ├── NumberBox.md
│ │ │ ├── Option.md
│ │ │ ├── Page.md
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── Pages.md
│ │ │ ├── Pagination.md
│ │ │ ├── PasswordInput.md
│ │ │ ├── PieChart.md
│ │ │ ├── ProgressBar.md
│ │ │ ├── Queue.md
│ │ │ ├── RadioGroup.md
│ │ │ ├── RealTimeAdapter.md
│ │ │ ├── Redirect.md
│ │ │ ├── Select.md
│ │ │ ├── Slider.md
│ │ │ ├── Slot.md
│ │ │ ├── SpaceFiller.md
│ │ │ ├── Spinner.md
│ │ │ ├── Splitter.md
│ │ │ ├── Stack.md
│ │ │ ├── StickyBox.md
│ │ │ ├── SubMenuItem.md
│ │ │ ├── Switch.md
│ │ │ ├── TabItem.md
│ │ │ ├── Table.md
│ │ │ ├── TableOfContents.md
│ │ │ ├── Tabs.md
│ │ │ ├── Text.md
│ │ │ ├── TextArea.md
│ │ │ ├── TextBox.md
│ │ │ ├── Theme.md
│ │ │ ├── TimeInput.md
│ │ │ ├── Timer.md
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneSwitch.md
│ │ │ ├── Tooltip.md
│ │ │ ├── Tree.md
│ │ │ ├── VSplitter.md
│ │ │ ├── VStack.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ ├── xmlui-spreadsheet
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Spreadsheet.md
│ │ │ └── xmlui-website-blocks
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Carousel.md
│ │ │ ├── HelloMd.md
│ │ │ ├── HeroSection.md
│ │ │ └── ScrollToTop.md
│ │ └── extensions
│ │ ├── _meta.json
│ │ ├── xmlui-animations
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Animation.md
│ │ │ ├── FadeAnimation.md
│ │ │ ├── FadeInAnimation.md
│ │ │ ├── FadeOutAnimation.md
│ │ │ ├── ScaleAnimation.md
│ │ │ └── SlideInAnimation.md
│ │ └── xmlui-website-blocks
│ │ ├── _meta.json
│ │ ├── _overview.md
│ │ ├── Carousel.md
│ │ ├── HelloMd.md
│ │ ├── HeroSection.md
│ │ └── ScrollToTop.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── package.json
│ ├── public
│ │ ├── feed.rss
│ │ ├── mockServiceWorker.js
│ │ ├── pages
│ │ │ ├── _meta.json
│ │ │ ├── app-structure.md
│ │ │ ├── build-editor-component.md
│ │ │ ├── build-hello-world-component.md
│ │ │ ├── components-intro.md
│ │ │ ├── context-variables.md
│ │ │ ├── forms.md
│ │ │ ├── globals.md
│ │ │ ├── glossary.md
│ │ │ ├── helper-tags.md
│ │ │ ├── hosted-deployment.md
│ │ │ ├── howto
│ │ │ │ ├── assign-a-complex-json-literal-to-a-component-variable.md
│ │ │ │ ├── chain-a-refetch.md
│ │ │ │ ├── debug-a-component.md
│ │ │ │ ├── delay-a-datasource-until-another-datasource-is-ready.md
│ │ │ │ ├── delegate-a-method.md
│ │ │ │ ├── do-custom-form-validation.md
│ │ │ │ ├── expose-a-method-from-a-component.md
│ │ │ │ ├── filter-and-transform-data-from-an-api.md
│ │ │ │ ├── group-items-in-list-by-a-property.md
│ │ │ │ ├── handle-background-operations.md
│ │ │ │ ├── hide-an-element-until-its-datasource-is-ready.md
│ │ │ │ ├── make-a-set-of-equal-width-cards.md
│ │ │ │ ├── make-a-table-responsive.md
│ │ │ │ ├── make-navpanel-width-responsive.md
│ │ │ │ ├── modify-a-value-reported-in-a-column.md
│ │ │ │ ├── paginate-a-list.md
│ │ │ │ ├── pass-data-to-a-modal-dialog.md
│ │ │ │ ├── react-to-button-click-not-keystrokes.md
│ │ │ │ ├── set-the-initial-value-of-a-select-from-fetched-data.md
│ │ │ │ ├── share-a-modaldialog-across-components.md
│ │ │ │ ├── sync-selections-between-table-and-list-views.md
│ │ │ │ ├── update-ui-optimistically.md
│ │ │ │ ├── use-built-in-form-validation.md
│ │ │ │ └── use-the-same-modaldialog-to-add-or-edit.md
│ │ │ ├── howto.md
│ │ │ ├── intro.md
│ │ │ ├── layout.md
│ │ │ ├── markup.md
│ │ │ ├── mcp.md
│ │ │ ├── modal-dialogs.md
│ │ │ ├── news-and-reviews.md
│ │ │ ├── reactive-intro.md
│ │ │ ├── refactoring.md
│ │ │ ├── routing-and-links.md
│ │ │ ├── samples
│ │ │ │ ├── color-palette.xmlui
│ │ │ │ ├── color-values.xmlui
│ │ │ │ ├── shadow-sizes.xmlui
│ │ │ │ ├── spacing-sizes.xmlui
│ │ │ │ ├── swatch.xmlui
│ │ │ │ ├── theme-gallery-brief.xmlui
│ │ │ │ └── theme-gallery.xmlui
│ │ │ ├── scoping.md
│ │ │ ├── scripting.md
│ │ │ ├── styles-and-themes
│ │ │ │ ├── common-units.md
│ │ │ │ ├── layout-props.md
│ │ │ │ ├── theme-variable-defaults.md
│ │ │ │ ├── theme-variables.md
│ │ │ │ └── themes.md
│ │ │ ├── template-properties.md
│ │ │ ├── test.md
│ │ │ ├── tutorial-01.md
│ │ │ ├── tutorial-02.md
│ │ │ ├── tutorial-03.md
│ │ │ ├── tutorial-04.md
│ │ │ ├── tutorial-05.md
│ │ │ ├── tutorial-06.md
│ │ │ ├── tutorial-07.md
│ │ │ ├── tutorial-08.md
│ │ │ ├── tutorial-09.md
│ │ │ ├── tutorial-10.md
│ │ │ ├── tutorial-11.md
│ │ │ ├── tutorial-12.md
│ │ │ ├── universal-properties.md
│ │ │ ├── user-defined-components.md
│ │ │ ├── vscode.md
│ │ │ ├── working-with-markdown.md
│ │ │ ├── working-with-text.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-charts
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── DonutChart.md
│ │ │ │ ├── LabelList.md
│ │ │ │ ├── Legend.md
│ │ │ │ ├── LineChart.md
│ │ │ │ └── PieChart.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ └── xmlui-spreadsheet
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ └── Spreadsheet.md
│ │ ├── resources
│ │ │ ├── devdocs
│ │ │ │ ├── debug-proxy-object-2.png
│ │ │ │ ├── debug-proxy-object.png
│ │ │ │ ├── table_editor_01.png
│ │ │ │ ├── table_editor_02.png
│ │ │ │ ├── table_editor_03.png
│ │ │ │ ├── table_editor_04.png
│ │ │ │ ├── table_editor_05.png
│ │ │ │ ├── table_editor_06.png
│ │ │ │ ├── table_editor_07.png
│ │ │ │ ├── table_editor_08.png
│ │ │ │ ├── table_editor_09.png
│ │ │ │ ├── table_editor_10.png
│ │ │ │ ├── table_editor_11.png
│ │ │ │ ├── table-editor-01.png
│ │ │ │ ├── table-editor-02.png
│ │ │ │ ├── table-editor-03.png
│ │ │ │ ├── table-editor-04.png
│ │ │ │ ├── table-editor-06.png
│ │ │ │ ├── table-editor-07.png
│ │ │ │ ├── table-editor-08.png
│ │ │ │ ├── table-editor-09.png
│ │ │ │ └── xmlui-rendering-of-tiptap-markdown.png
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ ├── clients.json
│ │ │ │ ├── daily-revenue.json
│ │ │ │ ├── dashboard-stats.json
│ │ │ │ ├── demo.xmlui
│ │ │ │ ├── demo.xmlui.xs
│ │ │ │ ├── downloads
│ │ │ │ │ └── downloads.json
│ │ │ │ ├── for-download
│ │ │ │ │ ├── index-with-api.html
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── mockApi.js
│ │ │ │ │ ├── start-darwin.sh
│ │ │ │ │ ├── start-linux.sh
│ │ │ │ │ ├── start.bat
│ │ │ │ │ └── xmlui
│ │ │ │ │ └── xmlui-standalone.umd.js
│ │ │ │ ├── getting-started
│ │ │ │ │ ├── cl-tutorial-final.zip
│ │ │ │ │ ├── cl-tutorial.zip
│ │ │ │ │ ├── cl-tutorial2.zip
│ │ │ │ │ ├── cl-tutorial3.zip
│ │ │ │ │ ├── cl-tutorial4.zip
│ │ │ │ │ ├── cl-tutorial5.zip
│ │ │ │ │ ├── cl-tutorial6.zip
│ │ │ │ │ ├── getting-started.zip
│ │ │ │ │ ├── hello-xmlui.zip
│ │ │ │ │ ├── xmlui-empty.zip
│ │ │ │ │ └── xmlui-starter.zip
│ │ │ │ ├── howto
│ │ │ │ │ └── component-icons
│ │ │ │ │ └── up-arrow.svg
│ │ │ │ ├── invoices.json
│ │ │ │ ├── monthly-status.json
│ │ │ │ ├── news-and-reviews.json
│ │ │ │ ├── products.json
│ │ │ │ ├── releases.json
│ │ │ │ ├── tutorials
│ │ │ │ │ ├── datasource
│ │ │ │ │ │ └── api.ts
│ │ │ │ │ └── p2do
│ │ │ │ │ ├── api.ts
│ │ │ │ │ └── todo-logo.svg
│ │ │ │ └── xmlui.json
│ │ │ ├── github.svg
│ │ │ ├── images
│ │ │ │ ├── apiaction-tutorial
│ │ │ │ │ ├── add-success.png
│ │ │ │ │ ├── apiaction-param.png
│ │ │ │ │ ├── change-completed.png
│ │ │ │ │ ├── change-in-progress.png
│ │ │ │ │ ├── confirm-delete.png
│ │ │ │ │ ├── data-error.png
│ │ │ │ │ ├── data-progress.png
│ │ │ │ │ ├── data-success.png
│ │ │ │ │ ├── display-1.png
│ │ │ │ │ ├── item-deleted.png
│ │ │ │ │ ├── item-updated.png
│ │ │ │ │ ├── missing-api-key.png
│ │ │ │ │ ├── new-item-added.png
│ │ │ │ │ └── test-message.png
│ │ │ │ ├── chat-api
│ │ │ │ │ └── domain-model.svg
│ │ │ │ ├── components
│ │ │ │ │ ├── image
│ │ │ │ │ │ └── breakfast.jpg
│ │ │ │ │ ├── markdown
│ │ │ │ │ │ └── colors.png
│ │ │ │ │ └── modal
│ │ │ │ │ ├── deep_link_dialog_1.jpg
│ │ │ │ │ └── deep_link_dialog_2.jpg
│ │ │ │ ├── create-apps
│ │ │ │ │ ├── collapsed-vertical.png
│ │ │ │ │ ├── using-forms-warning-dialog.png
│ │ │ │ │ └── using-forms.png
│ │ │ │ ├── datasource-tutorial
│ │ │ │ │ ├── data-with-header.png
│ │ │ │ │ ├── filtered-data.png
│ │ │ │ │ ├── filtered-items.png
│ │ │ │ │ ├── initial-page-items.png
│ │ │ │ │ ├── list-items.png
│ │ │ │ │ ├── next-page-items.png
│ │ │ │ │ ├── no-data.png
│ │ │ │ │ ├── pagination-1.jpg
│ │ │ │ │ ├── pagination-1.png
│ │ │ │ │ ├── polling-1.png
│ │ │ │ │ ├── refetch-data.png
│ │ │ │ │ ├── slow-loading.png
│ │ │ │ │ ├── test-message.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── unconventional-data.png
│ │ │ │ │ └── unfiltered-items.png
│ │ │ │ ├── flower.jpg
│ │ │ │ ├── get-started
│ │ │ │ │ ├── add-new-contact.png
│ │ │ │ │ ├── app-modified.png
│ │ │ │ │ ├── app-start.png
│ │ │ │ │ ├── app-with-boxes.png
│ │ │ │ │ ├── app-with-toast.png
│ │ │ │ │ ├── boilerplate-structure.png
│ │ │ │ │ ├── cl-initial.png
│ │ │ │ │ ├── cl-start.png
│ │ │ │ │ ├── contact-counts.png
│ │ │ │ │ ├── contact-dialog-title.png
│ │ │ │ │ ├── contact-dialog.png
│ │ │ │ │ ├── contact-menus.png
│ │ │ │ │ ├── contact-predicates.png
│ │ │ │ │ ├── context-menu.png
│ │ │ │ │ ├── dashboard-numbers.png
│ │ │ │ │ ├── default-contact-list.png
│ │ │ │ │ ├── delete-contact.png
│ │ │ │ │ ├── delete-task.png
│ │ │ │ │ ├── detailed-template.png
│ │ │ │ │ ├── edit-contact-details.png
│ │ │ │ │ ├── edited-contact-saved.png
│ │ │ │ │ ├── empty-sections.png
│ │ │ │ │ ├── filter-completed.png
│ │ │ │ │ ├── fullwidth-desktop.png
│ │ │ │ │ ├── fullwidth-mobile.png
│ │ │ │ │ ├── initial-table.png
│ │ │ │ │ ├── items-and-badges.png
│ │ │ │ │ ├── loading-message.png
│ │ │ │ │ ├── new-contact-button.png
│ │ │ │ │ ├── new-contact-saved.png
│ │ │ │ │ ├── no-empty-sections.png
│ │ │ │ │ ├── personal-todo-initial.png
│ │ │ │ │ ├── piechart.png
│ │ │ │ │ ├── review-today.png
│ │ │ │ │ ├── rudimentary-dashboard.png
│ │ │ │ │ ├── section-collapsed.png
│ │ │ │ │ ├── sectioned-items.png
│ │ │ │ │ ├── sections-ordered.png
│ │ │ │ │ ├── spacex-list-with-links.png
│ │ │ │ │ ├── spacex-list.png
│ │ │ │ │ ├── start-personal-todo-1.png
│ │ │ │ │ ├── submit-new-contact.png
│ │ │ │ │ ├── submit-new-task.png
│ │ │ │ │ ├── syntax-highlighting.png
│ │ │ │ │ ├── table-with-badge.png
│ │ │ │ │ ├── template-with-card.png
│ │ │ │ │ ├── test-emulated-api.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── todo-logo.png
│ │ │ │ │ └── xmlui-tools.png
│ │ │ │ ├── HelloApp.png
│ │ │ │ ├── HelloApp2.png
│ │ │ │ ├── logos
│ │ │ │ │ ├── xmlui1.svg
│ │ │ │ │ ├── xmlui2.svg
│ │ │ │ │ ├── xmlui3.svg
│ │ │ │ │ ├── xmlui4.svg
│ │ │ │ │ ├── xmlui5.svg
│ │ │ │ │ ├── xmlui6.svg
│ │ │ │ │ └── xmlui7.svg
│ │ │ │ ├── pdf
│ │ │ │ │ └── dummy-pdf.jpg
│ │ │ │ ├── rendering-engine
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ ├── Component.svg
│ │ │ │ │ ├── CompoundComponent.svg
│ │ │ │ │ ├── RootComponent.svg
│ │ │ │ │ └── tree-with-containers.svg
│ │ │ │ ├── reviewers-guide
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ └── incbutton-in-action.png
│ │ │ │ ├── tools
│ │ │ │ │ └── boilerplate-structure.png
│ │ │ │ ├── try.svg
│ │ │ │ ├── tutorial
│ │ │ │ │ ├── app-chat-history.png
│ │ │ │ │ ├── app-content-placeholder.png
│ │ │ │ │ ├── app-header-and-content.png
│ │ │ │ │ ├── app-links-channel-selected.png
│ │ │ │ │ ├── app-links-click.png
│ │ │ │ │ ├── app-navigation.png
│ │ │ │ │ ├── finished-ex01.png
│ │ │ │ │ ├── finished-ex02.png
│ │ │ │ │ ├── hello.png
│ │ │ │ │ ├── splash-screen-advanced.png
│ │ │ │ │ ├── splash-screen-after-click.png
│ │ │ │ │ ├── splash-screen-centered.png
│ │ │ │ │ ├── splash-screen-events.png
│ │ │ │ │ ├── splash-screen-expression.png
│ │ │ │ │ ├── splash-screen-reuse-after.png
│ │ │ │ │ ├── splash-screen-reuse-before.png
│ │ │ │ │ └── splash-screen.png
│ │ │ │ └── tutorial-01.png
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ ├── Boxes.xmlui
│ │ │ ├── Breadcrumb.xmlui
│ │ │ ├── ChangeLog.xmlui
│ │ │ ├── ColorPalette.xmlui
│ │ │ ├── DocumentLinks.xmlui
│ │ │ ├── DocumentPage.xmlui
│ │ │ ├── DocumentPageNoTOC.xmlui
│ │ │ ├── Icons.xmlui
│ │ │ ├── IncButton.xmlui
│ │ │ ├── IncButton2.xmlui
│ │ │ ├── NameValue.xmlui
│ │ │ ├── PageNotFound.xmlui
│ │ │ ├── PaletteItem.xmlui
│ │ │ ├── Palettes.xmlui
│ │ │ ├── SectionHeader.xmlui
│ │ │ ├── TBD.xmlui
│ │ │ ├── Test.xmlui
│ │ │ ├── ThemesIntro.xmlui
│ │ │ ├── ThousandThemes.xmlui
│ │ │ ├── TubeStops.xmlui
│ │ │ ├── TubeStops.xmlui.xs
│ │ │ └── TwoColumnCode.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ ├── docs-theme.ts
│ │ ├── earthtone.ts
│ │ ├── xmlui-gray-on-default.ts
│ │ ├── xmlui-green-on-default.ts
│ │ └── xmlui-orange-on-default.ts
│ └── tsconfig.json
├── LICENSE
├── package-lock.json
├── package.json
├── packages
│ ├── xmlui-animations
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── Animation.tsx
│ │ │ ├── AnimationNative.tsx
│ │ │ ├── FadeAnimation.tsx
│ │ │ ├── FadeInAnimation.tsx
│ │ │ ├── FadeOutAnimation.tsx
│ │ │ ├── index.tsx
│ │ │ ├── ScaleAnimation.tsx
│ │ │ └── SlideInAnimation.tsx
│ │ └── tsconfig.json
│ ├── xmlui-devtools
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── devtools
│ │ │ │ ├── DevTools.tsx
│ │ │ │ ├── DevToolsNative.module.scss
│ │ │ │ ├── DevToolsNative.tsx
│ │ │ │ ├── ModalDialog.module.scss
│ │ │ │ ├── ModalDialog.tsx
│ │ │ │ ├── ModalVisibilityContext.tsx
│ │ │ │ ├── Tooltip.module.scss
│ │ │ │ ├── Tooltip.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── editor
│ │ │ │ └── Editor.tsx
│ │ │ └── index.tsx
│ │ ├── tsconfig.json
│ │ └── vite.config-overrides.ts
│ ├── xmlui-hello-world
│ │ ├── .gitignore
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── HelloWorld.module.scss
│ │ │ ├── HelloWorld.tsx
│ │ │ ├── HelloWorldNative.tsx
│ │ │ └── index.tsx
│ │ └── tsconfig.json
│ ├── xmlui-os-frames
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── index.tsx
│ │ │ ├── IPhoneFrame.module.scss
│ │ │ ├── IPhoneFrame.tsx
│ │ │ ├── MacOSAppFrame.module.scss
│ │ │ ├── MacOSAppFrame.tsx
│ │ │ ├── WindowsAppFrame.module.scss
│ │ │ └── WindowsAppFrame.tsx
│ │ └── tsconfig.json
│ ├── xmlui-pdf
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ ├── components
│ │ │ │ └── Pdf.xmlui
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── index.tsx
│ │ │ ├── LazyPdfNative.tsx
│ │ │ ├── Pdf.module.scss
│ │ │ └── Pdf.tsx
│ │ └── tsconfig.json
│ ├── xmlui-playground
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── hooks
│ │ │ │ ├── usePlayground.ts
│ │ │ │ └── useToast.ts
│ │ │ ├── index.tsx
│ │ │ ├── playground
│ │ │ │ ├── Box.module.scss
│ │ │ │ ├── Box.tsx
│ │ │ │ ├── CodeSelector.tsx
│ │ │ │ ├── ConfirmationDialog.module.scss
│ │ │ │ ├── ConfirmationDialog.tsx
│ │ │ │ ├── Editor.tsx
│ │ │ │ ├── Header.module.scss
│ │ │ │ ├── Header.tsx
│ │ │ │ ├── Playground.tsx
│ │ │ │ ├── PlaygroundContent.module.scss
│ │ │ │ ├── PlaygroundContent.tsx
│ │ │ │ ├── PlaygroundNative.module.scss
│ │ │ │ ├── PlaygroundNative.tsx
│ │ │ │ ├── Preview.module.scss
│ │ │ │ ├── Preview.tsx
│ │ │ │ ├── Select.module.scss
│ │ │ │ ├── StandalonePlayground.tsx
│ │ │ │ ├── StandalonePlaygroundNative.module.scss
│ │ │ │ ├── StandalonePlaygroundNative.tsx
│ │ │ │ ├── ThemeSwitcher.module.scss
│ │ │ │ ├── ThemeSwitcher.tsx
│ │ │ │ ├── ToneSwitcher.tsx
│ │ │ │ ├── Tooltip.module.scss
│ │ │ │ ├── Tooltip.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── providers
│ │ │ │ ├── Toast.module.scss
│ │ │ │ └── ToastProvider.tsx
│ │ │ ├── state
│ │ │ │ └── store.ts
│ │ │ ├── themes
│ │ │ │ └── theme.ts
│ │ │ └── utils
│ │ │ └── helpers.ts
│ │ └── tsconfig.json
│ ├── xmlui-search
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── index.tsx
│ │ │ ├── Search.module.scss
│ │ │ └── Search.tsx
│ │ └── tsconfig.json
│ ├── xmlui-spreadsheet
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── index.tsx
│ │ │ ├── Spreadsheet.tsx
│ │ │ └── SpreadsheetNative.tsx
│ │ └── tsconfig.json
│ └── xmlui-website-blocks
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── demo
│ │ ├── components
│ │ │ ├── HeroBackgroundBreakoutPage.xmlui
│ │ │ ├── HeroBackgroundsPage.xmlui
│ │ │ ├── HeroContentsPage.xmlui
│ │ │ ├── HeroTextAlignPage.xmlui
│ │ │ ├── HeroTextPage.xmlui
│ │ │ └── HeroTonesPage.xmlui
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── default.ts
│ ├── index.html
│ ├── index.ts
│ ├── meta
│ │ └── componentsMetadata.ts
│ ├── package.json
│ ├── public
│ │ └── resources
│ │ ├── building.jpg
│ │ └── xmlui-logo.svg
│ ├── src
│ │ ├── Carousel
│ │ │ ├── Carousel.module.scss
│ │ │ ├── Carousel.tsx
│ │ │ ├── CarouselContext.tsx
│ │ │ └── CarouselNative.tsx
│ │ ├── FancyButton
│ │ │ ├── FancyButton.module.scss
│ │ │ ├── FancyButton.tsx
│ │ │ └── FancyButton.xmlui
│ │ ├── Hello
│ │ │ ├── Hello.tsx
│ │ │ ├── Hello.xmlui
│ │ │ └── Hello.xmlui.xs
│ │ ├── HeroSection
│ │ │ ├── HeroSection.module.scss
│ │ │ ├── HeroSection.tsx
│ │ │ └── HeroSectionNative.tsx
│ │ ├── index.tsx
│ │ ├── ScrollToTop
│ │ │ ├── ScrollToTop.module.scss
│ │ │ ├── ScrollToTop.tsx
│ │ │ └── ScrollToTopNative.tsx
│ │ └── vite-env.d.ts
│ └── tsconfig.json
├── README.md
├── tools
│ ├── codefence
│ │ └── xmlui-code-fence-docs.md
│ ├── create-app
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── create-app.ts
│ │ ├── helpers
│ │ │ ├── copy.ts
│ │ │ ├── get-pkg-manager.ts
│ │ │ ├── git.ts
│ │ │ ├── install.ts
│ │ │ ├── is-folder-empty.ts
│ │ │ ├── is-writeable.ts
│ │ │ ├── make-dir.ts
│ │ │ └── validate-pkg.ts
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── templates
│ │ │ ├── default
│ │ │ │ └── ts
│ │ │ │ ├── gitignore
│ │ │ │ ├── index.html
│ │ │ │ ├── index.ts
│ │ │ │ ├── public
│ │ │ │ │ ├── mockServiceWorker.js
│ │ │ │ │ ├── resources
│ │ │ │ │ │ ├── favicon.ico
│ │ │ │ │ │ └── xmlui-logo.svg
│ │ │ │ │ └── serve.json
│ │ │ │ └── src
│ │ │ │ ├── components
│ │ │ │ │ ├── ApiAware.xmlui
│ │ │ │ │ ├── Home.xmlui
│ │ │ │ │ ├── IncButton.xmlui
│ │ │ │ │ └── PagePanel.xmlui
│ │ │ │ ├── config.ts
│ │ │ │ └── Main.xmlui
│ │ │ ├── index.ts
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ ├── create-xmlui-hello-world
│ │ ├── index.js
│ │ └── package.json
│ └── vscode
│ ├── .gitignore
│ ├── .vscode
│ │ ├── launch.json
│ │ └── tasks.json
│ ├── .vscodeignore
│ ├── build.sh
│ ├── CHANGELOG.md
│ ├── esbuild.js
│ ├── eslint.config.mjs
│ ├── formatter-docs.md
│ ├── generate-test-sample.sh
│ ├── LICENSE.md
│ ├── package-lock.json
│ ├── package.json
│ ├── README.md
│ ├── resources
│ │ ├── xmlui-logo.png
│ │ └── xmlui-markup-syntax-highlighting.png
│ ├── src
│ │ ├── extension.ts
│ │ └── server.ts
│ ├── syntaxes
│ │ └── xmlui.tmLanguage.json
│ ├── test-samples
│ │ └── sample.xmlui
│ ├── tsconfig.json
│ └── tsconfig.tsbuildinfo
├── turbo.json
└── xmlui
├── .gitignore
├── bin
│ ├── bootstrap.js
│ ├── build-lib.ts
│ ├── build.ts
│ ├── index.ts
│ ├── preview.ts
│ ├── start.ts
│ ├── vite-xmlui-plugin.ts
│ └── viteConfig.ts
├── CHANGELOG.md
├── conventions
│ ├── component-qa-checklist.md
│ ├── copilot-conventions.md
│ ├── create-xmlui-components.md
│ ├── mermaid.md
│ ├── testing-conventions.md
│ └── xmlui-in-a-nutshell.md
├── dev-docs
│ ├── accessibility.md
│ ├── build-system.md
│ ├── build-xmlui.md
│ ├── component-behaviors.md
│ ├── components-with-options.md
│ ├── containers.md
│ ├── data-operations.md
│ ├── glossary.md
│ ├── index.md
│ ├── next
│ │ ├── component-dev-guide.md
│ │ ├── configuration-management-enhancement-summary.md
│ │ ├── documentation-scripts-refactoring-complete-summary.md
│ │ ├── documentation-scripts-refactoring-plan.md
│ │ ├── duplicate-pattern-extraction-summary.md
│ │ ├── error-handling-standardization-summary.md
│ │ ├── generating-component-reference.md
│ │ ├── index.md
│ │ ├── logging-consistency-implementation-summary.md
│ │ ├── project-build.md
│ │ ├── project-structure.md
│ │ ├── theme-context.md
│ │ ├── tiptap-design-considerations.md
│ │ ├── working-with-code.md
│ │ ├── xmlui-runtime-architecture
│ │ └── xmlui-wcag-accessibility-report.md
│ ├── react-fundamentals.md
│ ├── release-method.md
│ ├── standalone-app.md
│ ├── ud-components.md
│ └── xmlui-repo.md
├── package.json
├── playwright.config.ts
├── scripts
│ ├── coverage-only.js
│ ├── e2e-test-summary.js
│ ├── generate-docs
│ │ ├── build-downloads-map.mjs
│ │ ├── build-pages-map.mjs
│ │ ├── components-config.json
│ │ ├── configuration-management.mjs
│ │ ├── constants.mjs
│ │ ├── create-theme-files.mjs
│ │ ├── DocsGenerator.mjs
│ │ ├── error-handling.mjs
│ │ ├── extensions-config.json
│ │ ├── folders.mjs
│ │ ├── generate-summary-files.mjs
│ │ ├── get-docs.mjs
│ │ ├── input-handler.mjs
│ │ ├── logger.mjs
│ │ ├── logging-standards.mjs
│ │ ├── MetadataProcessor.mjs
│ │ ├── pattern-utilities.mjs
│ │ └── utils.mjs
│ ├── get-langserver-metadata.mjs
│ ├── inline-links.mjs
│ └── README-e2e-summary.md
├── src
│ ├── abstractions
│ │ ├── _conventions.md
│ │ ├── ActionDefs.ts
│ │ ├── AppContextDefs.ts
│ │ ├── ComponentDefs.ts
│ │ ├── ContainerDefs.ts
│ │ ├── ExtensionDefs.ts
│ │ ├── FunctionDefs.ts
│ │ ├── RendererDefs.ts
│ │ ├── scripting
│ │ │ ├── BlockScope.ts
│ │ │ ├── Compilation.ts
│ │ │ ├── LogicalThread.ts
│ │ │ ├── LoopScope.ts
│ │ │ ├── modules.ts
│ │ │ ├── ScriptParserError.ts
│ │ │ ├── Token.ts
│ │ │ ├── TryScope.ts
│ │ │ └── TryScopeExp.ts
│ │ └── ThemingDefs.ts
│ ├── components
│ │ ├── _conventions.md
│ │ ├── abstractions.ts
│ │ ├── Accordion
│ │ │ ├── Accordion.md
│ │ │ ├── Accordion.module.scss
│ │ │ ├── Accordion.spec.ts
│ │ │ ├── Accordion.tsx
│ │ │ ├── AccordionContext.tsx
│ │ │ ├── AccordionItem.tsx
│ │ │ ├── AccordionItemNative.tsx
│ │ │ └── AccordionNative.tsx
│ │ ├── Animation
│ │ │ └── AnimationNative.tsx
│ │ ├── APICall
│ │ │ ├── APICall.md
│ │ │ ├── APICall.spec.ts
│ │ │ ├── APICall.tsx
│ │ │ └── APICallNative.tsx
│ │ ├── App
│ │ │ ├── App.md
│ │ │ ├── App.module.scss
│ │ │ ├── App.spec.ts
│ │ │ ├── App.tsx
│ │ │ ├── AppLayoutContext.ts
│ │ │ ├── AppNative.tsx
│ │ │ ├── AppStateContext.ts
│ │ │ ├── doc-resources
│ │ │ │ ├── condensed-sticky.xmlui
│ │ │ │ ├── condensed.xmlui
│ │ │ │ ├── horizontal-sticky.xmlui
│ │ │ │ ├── horizontal.xmlui
│ │ │ │ ├── vertical-full-header.xmlui
│ │ │ │ ├── vertical-sticky.xmlui
│ │ │ │ └── vertical.xmlui
│ │ │ ├── IndexerContext.ts
│ │ │ ├── LinkInfoContext.ts
│ │ │ ├── SearchContext.tsx
│ │ │ ├── Sheet.module.scss
│ │ │ └── Sheet.tsx
│ │ ├── AppHeader
│ │ │ ├── AppHeader.md
│ │ │ ├── AppHeader.module.scss
│ │ │ ├── AppHeader.spec.ts
│ │ │ ├── AppHeader.tsx
│ │ │ └── AppHeaderNative.tsx
│ │ ├── AppState
│ │ │ ├── AppState.md
│ │ │ ├── AppState.spec.ts
│ │ │ ├── AppState.tsx
│ │ │ └── AppStateNative.tsx
│ │ ├── AutoComplete
│ │ │ ├── AutoComplete.md
│ │ │ ├── AutoComplete.module.scss
│ │ │ ├── AutoComplete.spec.ts
│ │ │ ├── AutoComplete.tsx
│ │ │ ├── AutoCompleteContext.tsx
│ │ │ └── AutoCompleteNative.tsx
│ │ ├── Avatar
│ │ │ ├── Avatar.md
│ │ │ ├── Avatar.module.scss
│ │ │ ├── Avatar.spec.ts
│ │ │ ├── Avatar.tsx
│ │ │ └── AvatarNative.tsx
│ │ ├── Backdrop
│ │ │ ├── Backdrop.md
│ │ │ ├── Backdrop.module.scss
│ │ │ ├── Backdrop.spec.ts
│ │ │ ├── Backdrop.tsx
│ │ │ └── BackdropNative.tsx
│ │ ├── Badge
│ │ │ ├── Badge.md
│ │ │ ├── Badge.module.scss
│ │ │ ├── Badge.spec.ts
│ │ │ ├── Badge.tsx
│ │ │ └── BadgeNative.tsx
│ │ ├── Bookmark
│ │ │ ├── Bookmark.md
│ │ │ ├── Bookmark.module.scss
│ │ │ ├── Bookmark.spec.ts
│ │ │ ├── Bookmark.tsx
│ │ │ └── BookmarkNative.tsx
│ │ ├── Breakout
│ │ │ ├── Breakout.module.scss
│ │ │ ├── Breakout.spec.ts
│ │ │ ├── Breakout.tsx
│ │ │ └── BreakoutNative.tsx
│ │ ├── Button
│ │ │ ├── Button-style.spec.ts
│ │ │ ├── Button.md
│ │ │ ├── Button.module.scss
│ │ │ ├── Button.spec.ts
│ │ │ ├── Button.tsx
│ │ │ └── ButtonNative.tsx
│ │ ├── Card
│ │ │ ├── Card.md
│ │ │ ├── Card.module.scss
│ │ │ ├── Card.spec.ts
│ │ │ ├── Card.tsx
│ │ │ └── CardNative.tsx
│ │ ├── Carousel
│ │ │ ├── Carousel.md
│ │ │ ├── Carousel.module.scss
│ │ │ ├── Carousel.spec.ts
│ │ │ ├── Carousel.tsx
│ │ │ ├── CarouselContext.tsx
│ │ │ ├── CarouselItem.tsx
│ │ │ ├── CarouselItemNative.tsx
│ │ │ └── CarouselNative.tsx
│ │ ├── ChangeListener
│ │ │ ├── ChangeListener.md
│ │ │ ├── ChangeListener.spec.ts
│ │ │ ├── ChangeListener.tsx
│ │ │ └── ChangeListenerNative.tsx
│ │ ├── chart-color-schemes.ts
│ │ ├── Charts
│ │ │ ├── AreaChart
│ │ │ │ ├── AreaChart.md
│ │ │ │ ├── AreaChart.spec.ts
│ │ │ │ ├── AreaChart.tsx
│ │ │ │ └── AreaChartNative.tsx
│ │ │ ├── BarChart
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── BarChart.module.scss
│ │ │ │ ├── BarChart.spec.ts
│ │ │ │ ├── BarChart.tsx
│ │ │ │ └── BarChartNative.tsx
│ │ │ ├── DonutChart
│ │ │ │ ├── DonutChart.spec.ts
│ │ │ │ └── DonutChart.tsx
│ │ │ ├── LabelList
│ │ │ │ ├── LabelList.spec.ts
│ │ │ │ ├── LabelList.tsx
│ │ │ │ ├── LabelListNative.module.scss
│ │ │ │ └── LabelListNative.tsx
│ │ │ ├── Legend
│ │ │ │ ├── Legend.spec.ts
│ │ │ │ ├── Legend.tsx
│ │ │ │ └── LegendNative.tsx
│ │ │ ├── LineChart
│ │ │ │ ├── LineChart.md
│ │ │ │ ├── LineChart.module.scss
│ │ │ │ ├── LineChart.spec.ts
│ │ │ │ ├── LineChart.tsx
│ │ │ │ └── LineChartNative.tsx
│ │ │ ├── PieChart
│ │ │ │ ├── PieChart.md
│ │ │ │ ├── PieChart.spec.ts
│ │ │ │ ├── PieChart.tsx
│ │ │ │ ├── PieChartNative.module.scss
│ │ │ │ └── PieChartNative.tsx
│ │ │ ├── RadarChart
│ │ │ │ ├── RadarChart.md
│ │ │ │ ├── RadarChart.spec.ts
│ │ │ │ ├── RadarChart.tsx
│ │ │ │ └── RadarChartNative.tsx
│ │ │ ├── Tooltip
│ │ │ │ ├── TooltipContent.module.scss
│ │ │ │ ├── TooltipContent.spec.ts
│ │ │ │ └── TooltipContent.tsx
│ │ │ └── utils
│ │ │ ├── abstractions.ts
│ │ │ └── ChartProvider.tsx
│ │ ├── Checkbox
│ │ │ ├── Checkbox.md
│ │ │ ├── Checkbox.spec.ts
│ │ │ └── Checkbox.tsx
│ │ ├── CodeBlock
│ │ │ ├── CodeBlock.module.scss
│ │ │ ├── CodeBlock.spec.ts
│ │ │ ├── CodeBlock.tsx
│ │ │ ├── CodeBlockNative.tsx
│ │ │ └── highlight-code.ts
│ │ ├── collectedComponentMetadata.ts
│ │ ├── ColorPicker
│ │ │ ├── ColorPicker.md
│ │ │ ├── ColorPicker.module.scss
│ │ │ ├── ColorPicker.spec.ts
│ │ │ ├── ColorPicker.tsx
│ │ │ └── ColorPickerNative.tsx
│ │ ├── Column
│ │ │ ├── Column.md
│ │ │ ├── Column.tsx
│ │ │ ├── ColumnNative.tsx
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ └── TableContext.tsx
│ │ ├── component-utils.ts
│ │ ├── ComponentProvider.tsx
│ │ ├── ComponentRegistryContext.tsx
│ │ ├── container-helpers.tsx
│ │ ├── ContentSeparator
│ │ │ ├── ContentSeparator.md
│ │ │ ├── ContentSeparator.module.scss
│ │ │ ├── ContentSeparator.spec.ts
│ │ │ ├── ContentSeparator.tsx
│ │ │ └── ContentSeparatorNative.tsx
│ │ ├── DataSource
│ │ │ ├── DataSource.md
│ │ │ └── DataSource.tsx
│ │ ├── DateInput
│ │ │ ├── DateInput.md
│ │ │ ├── DateInput.module.scss
│ │ │ ├── DateInput.spec.ts
│ │ │ ├── DateInput.tsx
│ │ │ └── DateInputNative.tsx
│ │ ├── DatePicker
│ │ │ ├── DatePicker.md
│ │ │ ├── DatePicker.module.scss
│ │ │ ├── DatePicker.spec.ts
│ │ │ ├── DatePicker.tsx
│ │ │ └── DatePickerNative.tsx
│ │ ├── DropdownMenu
│ │ │ ├── DropdownMenu.md
│ │ │ ├── DropdownMenu.module.scss
│ │ │ ├── DropdownMenu.spec.ts
│ │ │ ├── DropdownMenu.tsx
│ │ │ ├── DropdownMenuNative.tsx
│ │ │ ├── MenuItem.md
│ │ │ └── SubMenuItem.md
│ │ ├── EmojiSelector
│ │ │ ├── EmojiSelector.md
│ │ │ ├── EmojiSelector.spec.ts
│ │ │ ├── EmojiSelector.tsx
│ │ │ └── EmojiSelectorNative.tsx
│ │ ├── ExpandableItem
│ │ │ ├── ExpandableItem.module.scss
│ │ │ ├── ExpandableItem.spec.ts
│ │ │ ├── ExpandableItem.tsx
│ │ │ └── ExpandableItemNative.tsx
│ │ ├── FileInput
│ │ │ ├── FileInput.md
│ │ │ ├── FileInput.module.scss
│ │ │ ├── FileInput.spec.ts
│ │ │ ├── FileInput.tsx
│ │ │ └── FileInputNative.tsx
│ │ ├── FileUploadDropZone
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FileUploadDropZone.module.scss
│ │ │ ├── FileUploadDropZone.spec.ts
│ │ │ ├── FileUploadDropZone.tsx
│ │ │ └── FileUploadDropZoneNative.tsx
│ │ ├── FlowLayout
│ │ │ ├── FlowLayout.md
│ │ │ ├── FlowLayout.module.scss
│ │ │ ├── FlowLayout.spec.ts
│ │ │ ├── FlowLayout.spec.ts-snapshots
│ │ │ │ └── Edge-cases-boxShadow-is-not-clipped-1-non-smoke-darwin.png
│ │ │ ├── FlowLayout.tsx
│ │ │ └── FlowLayoutNative.tsx
│ │ ├── Footer
│ │ │ ├── Footer.md
│ │ │ ├── Footer.module.scss
│ │ │ ├── Footer.spec.ts
│ │ │ ├── Footer.tsx
│ │ │ └── FooterNative.tsx
│ │ ├── Form
│ │ │ ├── Form.md
│ │ │ ├── Form.module.scss
│ │ │ ├── Form.spec.ts
│ │ │ ├── Form.tsx
│ │ │ ├── formActions.ts
│ │ │ ├── FormContext.ts
│ │ │ └── FormNative.tsx
│ │ ├── FormItem
│ │ │ ├── FormItem.md
│ │ │ ├── FormItem.module.scss
│ │ │ ├── FormItem.spec.ts
│ │ │ ├── FormItem.tsx
│ │ │ ├── FormItemNative.tsx
│ │ │ ├── HelperText.module.scss
│ │ │ ├── HelperText.tsx
│ │ │ ├── ItemWithLabel.tsx
│ │ │ └── Validations.ts
│ │ ├── FormSection
│ │ │ ├── FormSection.md
│ │ │ ├── FormSection.ts
│ │ │ └── FormSection.xmlui
│ │ ├── Fragment
│ │ │ ├── Fragment.spec.ts
│ │ │ └── Fragment.tsx
│ │ ├── Heading
│ │ │ ├── abstractions.ts
│ │ │ ├── H1.md
│ │ │ ├── H1.spec.ts
│ │ │ ├── H2.md
│ │ │ ├── H2.spec.ts
│ │ │ ├── H3.md
│ │ │ ├── H3.spec.ts
│ │ │ ├── H4.md
│ │ │ ├── H4.spec.ts
│ │ │ ├── H5.md
│ │ │ ├── H5.spec.ts
│ │ │ ├── H6.md
│ │ │ ├── H6.spec.ts
│ │ │ ├── Heading.md
│ │ │ ├── Heading.module.scss
│ │ │ ├── Heading.spec.ts
│ │ │ ├── Heading.tsx
│ │ │ └── HeadingNative.tsx
│ │ ├── HoverCard
│ │ │ ├── HoverCard.tsx
│ │ │ └── HovercardNative.tsx
│ │ ├── HtmlTags
│ │ │ ├── HtmlTags.module.scss
│ │ │ ├── HtmlTags.spec.ts
│ │ │ └── HtmlTags.tsx
│ │ ├── Icon
│ │ │ ├── AdmonitionDanger.tsx
│ │ │ ├── AdmonitionInfo.tsx
│ │ │ ├── AdmonitionNote.tsx
│ │ │ ├── AdmonitionTip.tsx
│ │ │ ├── AdmonitionWarning.tsx
│ │ │ ├── ApiIcon.tsx
│ │ │ ├── ArrowDropDown.module.scss
│ │ │ ├── ArrowDropDown.tsx
│ │ │ ├── ArrowDropUp.module.scss
│ │ │ ├── ArrowDropUp.tsx
│ │ │ ├── ArrowLeft.module.scss
│ │ │ ├── ArrowLeft.tsx
│ │ │ ├── ArrowRight.module.scss
│ │ │ ├── ArrowRight.tsx
│ │ │ ├── Attach.tsx
│ │ │ ├── Binding.module.scss
│ │ │ ├── Binding.tsx
│ │ │ ├── BoardIcon.tsx
│ │ │ ├── BoxIcon.tsx
│ │ │ ├── CheckIcon.tsx
│ │ │ ├── ChevronDownIcon.tsx
│ │ │ ├── ChevronLeft.tsx
│ │ │ ├── ChevronRight.tsx
│ │ │ ├── ChevronUpIcon.tsx
│ │ │ ├── CodeFileIcon.tsx
│ │ │ ├── CodeSandbox.tsx
│ │ │ ├── CompactListIcon.tsx
│ │ │ ├── ContentCopyIcon.tsx
│ │ │ ├── DarkToLightIcon.tsx
│ │ │ ├── DatabaseIcon.module.scss
│ │ │ ├── DatabaseIcon.tsx
│ │ │ ├── DocFileIcon.tsx
│ │ │ ├── DocIcon.tsx
│ │ │ ├── DotMenuHorizontalIcon.tsx
│ │ │ ├── DotMenuIcon.tsx
│ │ │ ├── EmailIcon.tsx
│ │ │ ├── EmptyFolderIcon.tsx
│ │ │ ├── ErrorIcon.tsx
│ │ │ ├── ExpressionIcon.tsx
│ │ │ ├── FillPlusCricleIcon.tsx
│ │ │ ├── FilterIcon.tsx
│ │ │ ├── FolderIcon.tsx
│ │ │ ├── GlobeIcon.tsx
│ │ │ ├── HomeIcon.tsx
│ │ │ ├── HyperLinkIcon.tsx
│ │ │ ├── Icon.md
│ │ │ ├── Icon.module.scss
│ │ │ ├── Icon.spec.ts
│ │ │ ├── Icon.tsx
│ │ │ ├── IconNative.tsx
│ │ │ ├── ImageFileIcon.tsx
│ │ │ ├── Inspect.tsx
│ │ │ ├── LightToDark.tsx
│ │ │ ├── LinkIcon.tsx
│ │ │ ├── ListIcon.tsx
│ │ │ ├── LooseListIcon.tsx
│ │ │ ├── MoonIcon.tsx
│ │ │ ├── MoreOptionsIcon.tsx
│ │ │ ├── NoSortIcon.tsx
│ │ │ ├── PDFIcon.tsx
│ │ │ ├── PenIcon.tsx
│ │ │ ├── PhoneIcon.tsx
│ │ │ ├── PhotoIcon.tsx
│ │ │ ├── PlusIcon.tsx
│ │ │ ├── SearchIcon.tsx
│ │ │ ├── ShareIcon.tsx
│ │ │ ├── SortAscendingIcon.tsx
│ │ │ ├── SortDescendingIcon.tsx
│ │ │ ├── StarsIcon.tsx
│ │ │ ├── SunIcon.tsx
│ │ │ ├── svg
│ │ │ │ ├── admonition_danger.svg
│ │ │ │ ├── admonition_info.svg
│ │ │ │ ├── admonition_note.svg
│ │ │ │ ├── admonition_tip.svg
│ │ │ │ ├── admonition_warning.svg
│ │ │ │ ├── api.svg
│ │ │ │ ├── arrow-dropdown.svg
│ │ │ │ ├── arrow-left.svg
│ │ │ │ ├── arrow-right.svg
│ │ │ │ ├── arrow-up.svg
│ │ │ │ ├── attach.svg
│ │ │ │ ├── binding.svg
│ │ │ │ ├── box.svg
│ │ │ │ ├── bulb.svg
│ │ │ │ ├── code-file.svg
│ │ │ │ ├── code-sandbox.svg
│ │ │ │ ├── dark_to_light.svg
│ │ │ │ ├── database.svg
│ │ │ │ ├── doc.svg
│ │ │ │ ├── empty-folder.svg
│ │ │ │ ├── expression.svg
│ │ │ │ ├── eye-closed.svg
│ │ │ │ ├── eye-dark.svg
│ │ │ │ ├── eye.svg
│ │ │ │ ├── file-text.svg
│ │ │ │ ├── filter.svg
│ │ │ │ ├── folder.svg
│ │ │ │ ├── img.svg
│ │ │ │ ├── inspect.svg
│ │ │ │ ├── light_to_dark.svg
│ │ │ │ ├── moon.svg
│ │ │ │ ├── pdf.svg
│ │ │ │ ├── photo.svg
│ │ │ │ ├── share.svg
│ │ │ │ ├── stars.svg
│ │ │ │ ├── sun.svg
│ │ │ │ ├── trending-down.svg
│ │ │ │ ├── trending-level.svg
│ │ │ │ ├── trending-up.svg
│ │ │ │ ├── txt.svg
│ │ │ │ ├── unknown-file.svg
│ │ │ │ ├── unlink.svg
│ │ │ │ └── xls.svg
│ │ │ ├── TableDeleteColumnIcon.tsx
│ │ │ ├── TableDeleteRowIcon.tsx
│ │ │ ├── TableInsertColumnIcon.tsx
│ │ │ ├── TableInsertRowIcon.tsx
│ │ │ ├── TrashIcon.tsx
│ │ │ ├── TrendingDownIcon.tsx
│ │ │ ├── TrendingLevelIcon.tsx
│ │ │ ├── TrendingUpIcon.tsx
│ │ │ ├── TxtIcon.tsx
│ │ │ ├── UnknownFileIcon.tsx
│ │ │ ├── UnlinkIcon.tsx
│ │ │ ├── UserIcon.tsx
│ │ │ ├── WarningIcon.tsx
│ │ │ └── XlsIcon.tsx
│ │ ├── IconProvider.tsx
│ │ ├── IconRegistryContext.tsx
│ │ ├── IFrame
│ │ │ ├── IFrame.md
│ │ │ ├── IFrame.module.scss
│ │ │ ├── IFrame.spec.ts
│ │ │ ├── IFrame.tsx
│ │ │ └── IFrameNative.tsx
│ │ ├── Image
│ │ │ ├── Image.md
│ │ │ ├── Image.module.scss
│ │ │ ├── Image.spec.ts
│ │ │ ├── Image.tsx
│ │ │ └── ImageNative.tsx
│ │ ├── Input
│ │ │ ├── index.ts
│ │ │ ├── InputAdornment.module.scss
│ │ │ ├── InputAdornment.tsx
│ │ │ ├── InputDivider.module.scss
│ │ │ ├── InputDivider.tsx
│ │ │ ├── InputLabel.module.scss
│ │ │ ├── InputLabel.tsx
│ │ │ ├── PartialInput.module.scss
│ │ │ └── PartialInput.tsx
│ │ ├── InspectButton
│ │ │ ├── InspectButton.module.scss
│ │ │ └── InspectButton.tsx
│ │ ├── Items
│ │ │ ├── Items.md
│ │ │ ├── Items.spec.ts
│ │ │ ├── Items.tsx
│ │ │ └── ItemsNative.tsx
│ │ ├── Link
│ │ │ ├── Link.md
│ │ │ ├── Link.module.scss
│ │ │ ├── Link.spec.ts
│ │ │ ├── Link.tsx
│ │ │ └── LinkNative.tsx
│ │ ├── List
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── List.md
│ │ │ ├── List.module.scss
│ │ │ ├── List.spec.ts
│ │ │ ├── List.tsx
│ │ │ └── ListNative.tsx
│ │ ├── Logo
│ │ │ ├── doc-resources
│ │ │ │ └── xmlui-logo.svg
│ │ │ ├── Logo.md
│ │ │ ├── Logo.tsx
│ │ │ └── LogoNative.tsx
│ │ ├── Markdown
│ │ │ ├── CodeText.module.scss
│ │ │ ├── CodeText.tsx
│ │ │ ├── Markdown.md
│ │ │ ├── Markdown.module.scss
│ │ │ ├── Markdown.spec.ts
│ │ │ ├── Markdown.tsx
│ │ │ ├── MarkdownNative.tsx
│ │ │ ├── parse-binding-expr.ts
│ │ │ └── utils.ts
│ │ ├── metadata-helpers.ts
│ │ ├── ModalDialog
│ │ │ ├── ConfirmationModalContextProvider.tsx
│ │ │ ├── Dialog.module.scss
│ │ │ ├── Dialog.tsx
│ │ │ ├── ModalDialog.md
│ │ │ ├── ModalDialog.module.scss
│ │ │ ├── ModalDialog.spec.ts
│ │ │ ├── ModalDialog.tsx
│ │ │ ├── ModalDialogNative.tsx
│ │ │ └── ModalVisibilityContext.tsx
│ │ ├── NavGroup
│ │ │ ├── NavGroup.md
│ │ │ ├── NavGroup.module.scss
│ │ │ ├── NavGroup.spec.ts
│ │ │ ├── NavGroup.tsx
│ │ │ ├── NavGroupContext.ts
│ │ │ └── NavGroupNative.tsx
│ │ ├── NavLink
│ │ │ ├── NavLink.md
│ │ │ ├── NavLink.module.scss
│ │ │ ├── NavLink.spec.ts
│ │ │ ├── NavLink.tsx
│ │ │ └── NavLinkNative.tsx
│ │ ├── NavPanel
│ │ │ ├── NavPanel.md
│ │ │ ├── NavPanel.module.scss
│ │ │ ├── NavPanel.spec.ts
│ │ │ ├── NavPanel.tsx
│ │ │ └── NavPanelNative.tsx
│ │ ├── NestedApp
│ │ │ ├── AppWithCodeView.module.scss
│ │ │ ├── AppWithCodeView.tsx
│ │ │ ├── AppWithCodeViewNative.tsx
│ │ │ ├── defaultProps.tsx
│ │ │ ├── logo.svg
│ │ │ ├── NestedApp.module.scss
│ │ │ ├── NestedApp.tsx
│ │ │ ├── NestedAppNative.tsx
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.tsx
│ │ │ └── utils.ts
│ │ ├── NoResult
│ │ │ ├── NoResult.md
│ │ │ ├── NoResult.module.scss
│ │ │ ├── NoResult.spec.ts
│ │ │ ├── NoResult.tsx
│ │ │ └── NoResultNative.tsx
│ │ ├── NumberBox
│ │ │ ├── numberbox-abstractions.ts
│ │ │ ├── NumberBox.md
│ │ │ ├── NumberBox.module.scss
│ │ │ ├── NumberBox.spec.ts
│ │ │ ├── NumberBox.tsx
│ │ │ └── NumberBoxNative.tsx
│ │ ├── Option
│ │ │ ├── Option.md
│ │ │ ├── Option.spec.ts
│ │ │ ├── Option.tsx
│ │ │ ├── OptionNative.tsx
│ │ │ └── OptionTypeProvider.tsx
│ │ ├── PageMetaTitle
│ │ │ ├── PageMetaTilteNative.tsx
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── PageMetaTitle.spec.ts
│ │ │ └── PageMetaTitle.tsx
│ │ ├── Pages
│ │ │ ├── Page.md
│ │ │ ├── Pages.md
│ │ │ ├── Pages.module.scss
│ │ │ ├── Pages.tsx
│ │ │ └── PagesNative.tsx
│ │ ├── Pagination
│ │ │ ├── Pagination.md
│ │ │ ├── Pagination.module.scss
│ │ │ ├── Pagination.spec.ts
│ │ │ ├── Pagination.tsx
│ │ │ └── PaginationNative.tsx
│ │ ├── PositionedContainer
│ │ │ ├── PositionedContainer.module.scss
│ │ │ ├── PositionedContainer.tsx
│ │ │ └── PositionedContainerNative.tsx
│ │ ├── ProfileMenu
│ │ │ ├── ProfileMenu.module.scss
│ │ │ └── ProfileMenu.tsx
│ │ ├── ProgressBar
│ │ │ ├── ProgressBar.md
│ │ │ ├── ProgressBar.module.scss
│ │ │ ├── ProgressBar.spec.ts
│ │ │ ├── ProgressBar.tsx
│ │ │ └── ProgressBarNative.tsx
│ │ ├── Queue
│ │ │ ├── Queue.md
│ │ │ ├── Queue.spec.ts
│ │ │ ├── Queue.tsx
│ │ │ ├── queueActions.ts
│ │ │ └── QueueNative.tsx
│ │ ├── RadioGroup
│ │ │ ├── RadioGroup.md
│ │ │ ├── RadioGroup.module.scss
│ │ │ ├── RadioGroup.spec.ts
│ │ │ ├── RadioGroup.tsx
│ │ │ ├── RadioGroupNative.tsx
│ │ │ ├── RadioItem.tsx
│ │ │ └── RadioItemNative.tsx
│ │ ├── RealTimeAdapter
│ │ │ ├── RealTimeAdapter.tsx
│ │ │ └── RealTimeAdapterNative.tsx
│ │ ├── Redirect
│ │ │ ├── Redirect.md
│ │ │ ├── Redirect.spec.ts
│ │ │ └── Redirect.tsx
│ │ ├── ResponsiveBar
│ │ │ ├── README.md
│ │ │ ├── ResponsiveBar.md
│ │ │ ├── ResponsiveBar.module.scss
│ │ │ ├── ResponsiveBar.spec.ts
│ │ │ ├── ResponsiveBar.tsx
│ │ │ └── ResponsiveBarNative.tsx
│ │ ├── Select
│ │ │ ├── HiddenOption.tsx
│ │ │ ├── OptionContext.ts
│ │ │ ├── Select.md
│ │ │ ├── Select.module.scss
│ │ │ ├── Select.spec.ts
│ │ │ ├── Select.tsx
│ │ │ ├── SelectContext.tsx
│ │ │ └── SelectNative.tsx
│ │ ├── SelectionStore
│ │ │ ├── SelectionStore.md
│ │ │ ├── SelectionStore.tsx
│ │ │ └── SelectionStoreNative.tsx
│ │ ├── Slider
│ │ │ ├── Slider.md
│ │ │ ├── Slider.module.scss
│ │ │ ├── Slider.spec.ts
│ │ │ ├── Slider.tsx
│ │ │ └── SliderNative.tsx
│ │ ├── Slot
│ │ │ ├── Slot.md
│ │ │ ├── Slot.spec.ts
│ │ │ └── Slot.ts
│ │ ├── SlotItem.tsx
│ │ ├── SpaceFiller
│ │ │ ├── SpaceFiller.md
│ │ │ ├── SpaceFiller.module.scss
│ │ │ ├── SpaceFiller.spec.ts
│ │ │ ├── SpaceFiller.tsx
│ │ │ └── SpaceFillerNative.tsx
│ │ ├── Spinner
│ │ │ ├── Spinner.md
│ │ │ ├── Spinner.module.scss
│ │ │ ├── Spinner.spec.ts
│ │ │ ├── Spinner.tsx
│ │ │ └── SpinnerNative.tsx
│ │ ├── Splitter
│ │ │ ├── HSplitter.md
│ │ │ ├── HSplitter.spec.ts
│ │ │ ├── Splitter.md
│ │ │ ├── Splitter.module.scss
│ │ │ ├── Splitter.spec.ts
│ │ │ ├── Splitter.tsx
│ │ │ ├── SplitterNative.tsx
│ │ │ ├── utils.ts
│ │ │ ├── VSplitter.md
│ │ │ └── VSplitter.spec.ts
│ │ ├── Stack
│ │ │ ├── CHStack.md
│ │ │ ├── CHStack.spec.ts
│ │ │ ├── CVStack.md
│ │ │ ├── CVStack.spec.ts
│ │ │ ├── HStack.md
│ │ │ ├── HStack.spec.ts
│ │ │ ├── Stack.md
│ │ │ ├── Stack.module.scss
│ │ │ ├── Stack.spec.ts
│ │ │ ├── Stack.tsx
│ │ │ ├── StackNative.tsx
│ │ │ ├── VStack.md
│ │ │ └── VStack.spec.ts
│ │ ├── StickyBox
│ │ │ ├── StickyBox.md
│ │ │ ├── StickyBox.module.scss
│ │ │ ├── StickyBox.tsx
│ │ │ └── StickyBoxNative.tsx
│ │ ├── Switch
│ │ │ ├── Switch.md
│ │ │ ├── Switch.spec.ts
│ │ │ └── Switch.tsx
│ │ ├── Table
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── react-table-config.d.ts
│ │ │ ├── Table.md
│ │ │ ├── Table.module.scss
│ │ │ ├── Table.spec.ts
│ │ │ ├── Table.tsx
│ │ │ ├── TableNative.tsx
│ │ │ └── useRowSelection.tsx
│ │ ├── TableOfContents
│ │ │ ├── TableOfContents.module.scss
│ │ │ ├── TableOfContents.spec.ts
│ │ │ ├── TableOfContents.tsx
│ │ │ └── TableOfContentsNative.tsx
│ │ ├── Tabs
│ │ │ ├── TabContext.tsx
│ │ │ ├── TabItem.md
│ │ │ ├── TabItem.tsx
│ │ │ ├── TabItemNative.tsx
│ │ │ ├── Tabs.md
│ │ │ ├── Tabs.module.scss
│ │ │ ├── Tabs.spec.ts
│ │ │ ├── Tabs.tsx
│ │ │ └── TabsNative.tsx
│ │ ├── Text
│ │ │ ├── Text.md
│ │ │ ├── Text.module.scss
│ │ │ ├── Text.spec.ts
│ │ │ ├── Text.tsx
│ │ │ └── TextNative.tsx
│ │ ├── TextArea
│ │ │ ├── TextArea.md
│ │ │ ├── TextArea.module.scss
│ │ │ ├── TextArea.spec.ts
│ │ │ ├── TextArea.tsx
│ │ │ ├── TextAreaNative.tsx
│ │ │ ├── TextAreaResizable.tsx
│ │ │ └── useComposedRef.ts
│ │ ├── TextBox
│ │ │ ├── TextBox.md
│ │ │ ├── TextBox.module.scss
│ │ │ ├── TextBox.spec.ts
│ │ │ ├── TextBox.tsx
│ │ │ └── TextBoxNative.tsx
│ │ ├── Theme
│ │ │ ├── NotificationToast.tsx
│ │ │ ├── Theme.md
│ │ │ ├── Theme.module.scss
│ │ │ ├── Theme.spec.ts
│ │ │ ├── Theme.tsx
│ │ │ └── ThemeNative.tsx
│ │ ├── TimeInput
│ │ │ ├── TimeInput.md
│ │ │ ├── TimeInput.module.scss
│ │ │ ├── TimeInput.spec.ts
│ │ │ ├── TimeInput.tsx
│ │ │ ├── TimeInputNative.tsx
│ │ │ └── utils.ts
│ │ ├── Timer
│ │ │ ├── Timer.md
│ │ │ ├── Timer.spec.ts
│ │ │ ├── Timer.tsx
│ │ │ └── TimerNative.tsx
│ │ ├── Toggle
│ │ │ ├── Toggle.module.scss
│ │ │ └── Toggle.tsx
│ │ ├── ToneChangerButton
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneChangerButton.spec.ts
│ │ │ └── ToneChangerButton.tsx
│ │ ├── ToneSwitch
│ │ │ ├── ToneSwitch.md
│ │ │ ├── ToneSwitch.module.scss
│ │ │ ├── ToneSwitch.spec.ts
│ │ │ ├── ToneSwitch.tsx
│ │ │ └── ToneSwitchNative.tsx
│ │ ├── Tooltip
│ │ │ ├── Tooltip.md
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.spec.ts
│ │ │ ├── Tooltip.tsx
│ │ │ └── TooltipNative.tsx
│ │ ├── Tree
│ │ │ ├── testData.ts
│ │ │ ├── Tree-dynamic.spec.ts
│ │ │ ├── Tree-icons.spec.ts
│ │ │ ├── Tree.md
│ │ │ ├── Tree.spec.ts
│ │ │ ├── TreeComponent.module.scss
│ │ │ ├── TreeComponent.tsx
│ │ │ └── TreeNative.tsx
│ │ ├── TreeDisplay
│ │ │ ├── TreeDisplay.md
│ │ │ ├── TreeDisplay.module.scss
│ │ │ ├── TreeDisplay.tsx
│ │ │ └── TreeDisplayNative.tsx
│ │ ├── ValidationSummary
│ │ │ ├── ValidationSummary.module.scss
│ │ │ └── ValidationSummary.tsx
│ │ └── VisuallyHidden.tsx
│ ├── components-core
│ │ ├── abstractions
│ │ │ ├── ComponentRenderer.ts
│ │ │ ├── LoaderRenderer.ts
│ │ │ ├── standalone.ts
│ │ │ └── treeAbstractions.ts
│ │ ├── action
│ │ │ ├── actions.ts
│ │ │ ├── APICall.tsx
│ │ │ ├── FileDownloadAction.tsx
│ │ │ ├── FileUploadAction.tsx
│ │ │ ├── NavigateAction.tsx
│ │ │ └── TimedAction.tsx
│ │ ├── ApiBoundComponent.tsx
│ │ ├── appContext
│ │ │ ├── date-functions.ts
│ │ │ ├── math-function.ts
│ │ │ └── misc-utils.ts
│ │ ├── AppContext.tsx
│ │ ├── behaviors
│ │ │ ├── Behavior.tsx
│ │ │ └── CoreBehaviors.tsx
│ │ ├── component-hooks.ts
│ │ ├── ComponentDecorator.tsx
│ │ ├── ComponentViewer.tsx
│ │ ├── CompoundComponent.tsx
│ │ ├── constants.ts
│ │ ├── DebugViewProvider.tsx
│ │ ├── descriptorHelper.ts
│ │ ├── devtools
│ │ │ ├── InspectorDialog.module.scss
│ │ │ ├── InspectorDialog.tsx
│ │ │ └── InspectorDialogVisibilityContext.tsx
│ │ ├── EngineError.ts
│ │ ├── event-handlers.ts
│ │ ├── InspectorButton.module.scss
│ │ ├── InspectorContext.tsx
│ │ ├── interception
│ │ │ ├── abstractions.ts
│ │ │ ├── ApiInterceptor.ts
│ │ │ ├── ApiInterceptorProvider.tsx
│ │ │ ├── apiInterceptorWorker.ts
│ │ │ ├── Backend.ts
│ │ │ ├── Errors.ts
│ │ │ ├── IndexedDb.ts
│ │ │ ├── initMock.ts
│ │ │ ├── InMemoryDb.ts
│ │ │ ├── ReadonlyCollection.ts
│ │ │ └── useApiInterceptorContext.tsx
│ │ ├── loader
│ │ │ ├── ApiLoader.tsx
│ │ │ ├── DataLoader.tsx
│ │ │ ├── ExternalDataLoader.tsx
│ │ │ ├── Loader.tsx
│ │ │ ├── MockLoaderRenderer.tsx
│ │ │ └── PageableLoader.tsx
│ │ ├── LoaderComponent.tsx
│ │ ├── markup-check.ts
│ │ ├── parts.ts
│ │ ├── renderers.ts
│ │ ├── rendering
│ │ │ ├── AppContent.tsx
│ │ │ ├── AppRoot.tsx
│ │ │ ├── AppWrapper.tsx
│ │ │ ├── buildProxy.ts
│ │ │ ├── collectFnVarDeps.ts
│ │ │ ├── ComponentAdapter.tsx
│ │ │ ├── ComponentWrapper.tsx
│ │ │ ├── Container.tsx
│ │ │ ├── containers.ts
│ │ │ ├── ContainerWrapper.tsx
│ │ │ ├── ErrorBoundary.module.scss
│ │ │ ├── ErrorBoundary.tsx
│ │ │ ├── InvalidComponent.module.scss
│ │ │ ├── InvalidComponent.tsx
│ │ │ ├── nodeUtils.ts
│ │ │ ├── reducer.ts
│ │ │ ├── renderChild.tsx
│ │ │ ├── StandaloneComponent.tsx
│ │ │ ├── StateContainer.tsx
│ │ │ ├── UnknownComponent.module.scss
│ │ │ ├── UnknownComponent.tsx
│ │ │ └── valueExtractor.ts
│ │ ├── reportEngineError.ts
│ │ ├── RestApiProxy.ts
│ │ ├── script-runner
│ │ │ ├── asyncProxy.ts
│ │ │ ├── AttributeValueParser.ts
│ │ │ ├── bannedFunctions.ts
│ │ │ ├── BindingTreeEvaluationContext.ts
│ │ │ ├── eval-tree-async.ts
│ │ │ ├── eval-tree-common.ts
│ │ │ ├── eval-tree-sync.ts
│ │ │ ├── ParameterParser.ts
│ │ │ ├── process-statement-async.ts
│ │ │ ├── process-statement-common.ts
│ │ │ ├── process-statement-sync.ts
│ │ │ ├── ScriptingSourceTree.ts
│ │ │ ├── simplify-expression.ts
│ │ │ ├── statement-queue.ts
│ │ │ └── visitors.ts
│ │ ├── StandaloneApp.tsx
│ │ ├── StandaloneExtensionManager.ts
│ │ ├── TableOfContentsContext.tsx
│ │ ├── theming
│ │ │ ├── _themes.scss
│ │ │ ├── component-layout-resolver.ts
│ │ │ ├── extendThemeUtils.ts
│ │ │ ├── hvar.ts
│ │ │ ├── layout-resolver.ts
│ │ │ ├── parse-layout-props.ts
│ │ │ ├── StyleContext.tsx
│ │ │ ├── StyleRegistry.ts
│ │ │ ├── ThemeContext.tsx
│ │ │ ├── ThemeProvider.tsx
│ │ │ ├── themes
│ │ │ │ ├── base-utils.ts
│ │ │ │ ├── palette.ts
│ │ │ │ ├── root.ts
│ │ │ │ ├── solid.ts
│ │ │ │ ├── theme-colors.ts
│ │ │ │ └── xmlui.ts
│ │ │ ├── themeVars.module.scss
│ │ │ ├── themeVars.ts
│ │ │ ├── transformThemeVars.ts
│ │ │ └── utils.ts
│ │ ├── utils
│ │ │ ├── actionUtils.ts
│ │ │ ├── audio-utils.ts
│ │ │ ├── base64-utils.ts
│ │ │ ├── compound-utils.ts
│ │ │ ├── css-utils.ts
│ │ │ ├── DataLoaderQueryKeyGenerator.ts
│ │ │ ├── date-utils.ts
│ │ │ ├── extractParam.ts
│ │ │ ├── hooks.tsx
│ │ │ ├── LruCache.ts
│ │ │ ├── mergeProps.ts
│ │ │ ├── misc.ts
│ │ │ ├── request-params.ts
│ │ │ ├── statementUtils.ts
│ │ │ └── treeUtils.ts
│ │ └── xmlui-parser.ts
│ ├── index-standalone.ts
│ ├── index.scss
│ ├── index.ts
│ ├── language-server
│ │ ├── server-common.ts
│ │ ├── server-web-worker.ts
│ │ ├── server.ts
│ │ ├── services
│ │ │ ├── common
│ │ │ │ ├── docs-generation.ts
│ │ │ │ ├── lsp-utils.ts
│ │ │ │ ├── metadata-utils.ts
│ │ │ │ └── syntax-node-utilities.ts
│ │ │ ├── completion.ts
│ │ │ ├── diagnostic.ts
│ │ │ ├── format.ts
│ │ │ └── hover.ts
│ │ └── xmlui-metadata-generated.mjs
│ ├── logging
│ │ ├── LoggerContext.tsx
│ │ ├── LoggerInitializer.tsx
│ │ ├── LoggerService.ts
│ │ └── xmlui.ts
│ ├── logo.svg
│ ├── parsers
│ │ ├── common
│ │ │ ├── GenericToken.ts
│ │ │ ├── InputStream.ts
│ │ │ └── utils.ts
│ │ ├── scripting
│ │ │ ├── code-behind-collect.ts
│ │ │ ├── Lexer.ts
│ │ │ ├── modules.ts
│ │ │ ├── Parser.ts
│ │ │ ├── ParserError.ts
│ │ │ ├── ScriptingNodeTypes.ts
│ │ │ ├── TokenTrait.ts
│ │ │ ├── TokenType.ts
│ │ │ └── tree-visitor.ts
│ │ ├── style-parser
│ │ │ ├── errors.ts
│ │ │ ├── source-tree.ts
│ │ │ ├── StyleInputStream.ts
│ │ │ ├── StyleLexer.ts
│ │ │ ├── StyleParser.ts
│ │ │ └── tokens.ts
│ │ └── xmlui-parser
│ │ ├── CharacterCodes.ts
│ │ ├── diagnostics.ts
│ │ ├── fileExtensions.ts
│ │ ├── index.ts
│ │ ├── lint.ts
│ │ ├── parser.ts
│ │ ├── ParserError.ts
│ │ ├── scanner.ts
│ │ ├── syntax-kind.ts
│ │ ├── syntax-node.ts
│ │ ├── transform.ts
│ │ ├── utils.ts
│ │ ├── xmlui-serializer.ts
│ │ └── xmlui-tree.ts
│ ├── react-app-env.d.ts
│ ├── syntax
│ │ ├── monaco
│ │ │ ├── grammar.monacoLanguage.ts
│ │ │ ├── index.ts
│ │ │ ├── xmlui-dark.ts
│ │ │ ├── xmlui-light.ts
│ │ │ └── xmluiscript.monacoLanguage.ts
│ │ └── textMate
│ │ ├── index.ts
│ │ ├── xmlui-dark.json
│ │ ├── xmlui-light.json
│ │ ├── xmlui.json
│ │ └── xmlui.tmLanguage.json
│ ├── testing
│ │ ├── assertions.ts
│ │ ├── component-test-helpers.ts
│ │ ├── ComponentDrivers.ts
│ │ ├── drivers
│ │ │ ├── DateInputDriver.ts
│ │ │ ├── ModalDialogDriver.ts
│ │ │ ├── NumberBoxDriver.ts
│ │ │ ├── TextBoxDriver.ts
│ │ │ ├── TimeInputDriver.ts
│ │ │ ├── TimerDriver.ts
│ │ │ └── TreeDriver.ts
│ │ ├── fixtures.ts
│ │ ├── infrastructure
│ │ │ ├── index.html
│ │ │ ├── main.tsx
│ │ │ ├── public
│ │ │ │ ├── mockServiceWorker.js
│ │ │ │ ├── resources
│ │ │ │ │ ├── bell.svg
│ │ │ │ │ ├── box.svg
│ │ │ │ │ ├── doc.svg
│ │ │ │ │ ├── eye.svg
│ │ │ │ │ ├── flower-640x480.jpg
│ │ │ │ │ ├── sun.svg
│ │ │ │ │ ├── test-image-100x100.jpg
│ │ │ │ │ └── txt.svg
│ │ │ │ └── serve.json
│ │ │ └── TestBed.tsx
│ │ └── themed-app-test-helpers.ts
│ └── vite-env.d.ts
├── tests
│ ├── components
│ │ ├── CodeBlock
│ │ │ └── hightlight-code.test.ts
│ │ ├── playground-pattern.test.ts
│ │ └── Tree
│ │ └── Tree-states.test.ts
│ ├── components-core
│ │ ├── abstractions
│ │ │ └── treeAbstractions.test.ts
│ │ ├── container
│ │ │ └── buildProxy.test.ts
│ │ ├── interception
│ │ │ ├── orderBy.test.ts
│ │ │ ├── ReadOnlyCollection.test.ts
│ │ │ └── request-param-converter.test.ts
│ │ ├── scripts-runner
│ │ │ ├── AttributeValueParser.test.ts
│ │ │ ├── eval-tree-arrow-async.test.ts
│ │ │ ├── eval-tree-arrow.test.ts
│ │ │ ├── eval-tree-func-decl-async.test.ts
│ │ │ ├── eval-tree-func-decl.test.ts
│ │ │ ├── eval-tree-pre-post.test.ts
│ │ │ ├── eval-tree-regression.test.ts
│ │ │ ├── eval-tree.test.ts
│ │ │ ├── function-proxy.test.ts
│ │ │ ├── parser-regression.test.ts
│ │ │ ├── process-event.test.ts
│ │ │ ├── process-function.test.ts
│ │ │ ├── process-implicit-context.test.ts
│ │ │ ├── process-statement-asgn.test.ts
│ │ │ ├── process-statement-destruct.test.ts
│ │ │ ├── process-statement-regs.test.ts
│ │ │ ├── process-statement-sync.test.ts
│ │ │ ├── process-statement.test.ts
│ │ │ ├── process-switch-sync.test.ts
│ │ │ ├── process-switch.test.ts
│ │ │ ├── process-try-sync.test.ts
│ │ │ ├── process-try.test.ts
│ │ │ └── test-helpers.ts
│ │ ├── test-metadata-handler.ts
│ │ ├── theming
│ │ │ ├── border-segments.test.ts
│ │ │ ├── component-layout.resolver.test.ts
│ │ │ ├── layout-property-parser.test.ts
│ │ │ ├── layout-resolver.test.ts
│ │ │ ├── layout-resolver2.test.ts
│ │ │ ├── layout-vp-override.test.ts
│ │ │ └── padding-segments.test.ts
│ │ └── utils
│ │ ├── date-utils.test.ts
│ │ ├── format-human-elapsed-time.test.ts
│ │ └── LruCache.test.ts
│ ├── language-server
│ │ ├── completion.test.ts
│ │ ├── format.test.ts
│ │ ├── hover.test.ts
│ │ └── mockData.ts
│ └── parsers
│ ├── common
│ │ └── input-stream.test.ts
│ ├── markdown
│ │ └── parse-binding-expression.test.ts
│ ├── parameter-parser.test.ts
│ ├── paremeter-parser.test.ts
│ ├── scripting
│ │ ├── eval-tree-arrow.test.ts
│ │ ├── eval-tree-pre-post.test.ts
│ │ ├── eval-tree.test.ts
│ │ ├── function-proxy.test.ts
│ │ ├── lexer-literals.test.ts
│ │ ├── lexer-misc.test.ts
│ │ ├── module-parse.test.ts
│ │ ├── parser-arrow.test.ts
│ │ ├── parser-assignments.test.ts
│ │ ├── parser-binary.test.ts
│ │ ├── parser-destructuring.test.ts
│ │ ├── parser-errors.test.ts
│ │ ├── parser-expressions.test.ts
│ │ ├── parser-function.test.ts
│ │ ├── parser-literals.test.ts
│ │ ├── parser-primary.test.ts
│ │ ├── parser-regex.test.ts
│ │ ├── parser-statements.test.ts
│ │ ├── parser-unary.test.ts
│ │ ├── process-event.test.ts
│ │ ├── process-implicit-context.test.ts
│ │ ├── process-statement-asgn.test.ts
│ │ ├── process-statement-destruct.test.ts
│ │ ├── process-statement-regs.test.ts
│ │ ├── process-statement-sync.test.ts
│ │ ├── process-statement.test.ts
│ │ ├── process-switch-sync.test.ts
│ │ ├── process-switch.test.ts
│ │ ├── process-try-sync.test.ts
│ │ ├── process-try.test.ts
│ │ ├── simplify-expression.test.ts
│ │ ├── statement-hooks.test.ts
│ │ └── test-helpers.ts
│ ├── style-parser
│ │ ├── generateHvarChain.test.ts
│ │ ├── parseHVar.test.ts
│ │ ├── parser.test.ts
│ │ └── tokens.test.ts
│ └── xmlui
│ ├── lint.test.ts
│ ├── parser.test.ts
│ ├── scanner.test.ts
│ ├── transform.attr.test.ts
│ ├── transform.circular.test.ts
│ ├── transform.element.test.ts
│ ├── transform.errors.test.ts
│ ├── transform.escape.test.ts
│ ├── transform.regression.test.ts
│ ├── transform.script.test.ts
│ ├── transform.test.ts
│ └── xmlui.ts
├── tests-e2e
│ ├── api-bound-component-regression.spec.ts
│ ├── api-call-as-extracted-component.spec.ts
│ ├── assign-to-object-or-array-regression.spec.ts
│ ├── binding-regression.spec.ts
│ ├── children-as-template-context-vars.spec.ts
│ ├── compound-component.spec.ts
│ ├── context-vars-regression.spec.ts
│ ├── data-bindings.spec.ts
│ ├── datasource-and-api-usage-in-var.spec.ts
│ ├── datasource-direct-binding.spec.ts
│ ├── datasource-onLoaded-regression.spec.ts
│ ├── modify-array-item-regression.spec.ts
│ ├── namespaces.spec.ts
│ ├── push-to-array-regression.spec.ts
│ ├── screen-breakpoints.spec.ts
│ ├── scripting.spec.ts
│ ├── state-scope-in-pages.spec.ts
│ └── state-var-scopes.spec.ts
├── tsconfig.bin.json
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── vitest.config.ts
```
# Files
--------------------------------------------------------------------------------
/xmlui/src/components/Accordion/AccordionItemNative.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import {
2 | type ForwardedRef,
3 | forwardRef,
4 | type ReactNode,
5 | useEffect,
6 | useId,
7 | useMemo,
8 | useState,
9 | } from "react";
10 | import * as RAccordion from "@radix-ui/react-accordion";
11 | import classnames from "classnames";
12 |
13 | import styles from "../../components/Accordion/Accordion.module.scss";
14 |
15 | import { useAccordionContext } from "../../components/Accordion/AccordionContext";
16 | import Icon from "../../components/Icon/IconNative";
17 |
18 | function defaultRenderer(header: string) {
19 | return <div>{header}</div>;
20 | }
21 |
22 | type Props = {
23 | id: string;
24 | /**
25 | * The header of the accordion.
26 | */
27 | header: string;
28 |
29 | headerRenderer?: (header: string) => ReactNode;
30 |
31 | /**
32 | * The content of the accordion.
33 | */
34 | content: ReactNode;
35 |
36 | initiallyExpanded?: boolean;
37 |
38 | style?: React.CSSProperties;
39 | className?: string;
40 | };
41 |
42 | export const defaultProps: Pick<Props, "initiallyExpanded" | "headerRenderer"> = {
43 | initiallyExpanded: false,
44 | headerRenderer: defaultRenderer,
45 | };
46 |
47 | export const AccordionItemComponent = forwardRef(function AccordionItemComponent(
48 | {
49 | id,
50 | header,
51 | headerRenderer = defaultProps.headerRenderer,
52 | content,
53 | initiallyExpanded = defaultProps.initiallyExpanded,
54 | style,
55 | className,
56 | ...rest
57 | }: Props,
58 | forwardedRef: ForwardedRef<HTMLDivElement>,
59 | ) {
60 | const generatedId = useId();
61 | const itemId = useMemo(() => (id ? `${id}` : generatedId), [id, generatedId]);
62 | const triggerId = useMemo(() => `trigger_${itemId}`, [itemId]);
63 | const {
64 | rotateExpanded,
65 | expandedItems,
66 | hideIcon,
67 | expandedIcon,
68 | collapsedIcon,
69 | triggerPosition,
70 | expandItem,
71 | register,
72 | unRegister,
73 | } = useAccordionContext();
74 | const expanded = useMemo(() => (expandedItems ?? []).includes(itemId), [itemId, expandedItems]);
75 | const [initialised, setInitialised] = useState(false);
76 |
77 | useEffect(() => {
78 | if (!initialised) {
79 | setInitialised(true);
80 | if (initiallyExpanded) {
81 | expandItem(itemId);
82 | }
83 | }
84 | }, [expandItem, itemId, initiallyExpanded, initialised]);
85 |
86 | useEffect(() => {
87 | register(triggerId);
88 | }, [register, triggerId]);
89 |
90 | useEffect(() => {
91 | return () => {
92 | unRegister(triggerId);
93 | };
94 | }, [triggerId, unRegister]);
95 |
96 | return (
97 | <RAccordion.Item
98 | id={itemId}
99 | key={itemId}
100 | value={itemId}
101 | className={classnames(styles.item, className)}
102 | ref={forwardedRef}
103 | style={style}
104 | >
105 | <RAccordion.Header className={styles.header}>
106 | <RAccordion.Trigger
107 | {...rest}
108 | id={triggerId}
109 | className={classnames(styles.trigger, {
110 | [styles.triggerStart]: triggerPosition === "start",
111 | })}
112 | >
113 | {headerRenderer(header)}
114 | {!hideIcon && (
115 | <span
116 | style={{
117 | transform: expanded && !expandedIcon ? `rotate(${rotateExpanded})` : "rotate(0deg)",
118 | transition: "transform 300ms cubic-bezier(0.87, 0, 0.13, 1)",
119 | }}
120 | >
121 | <Icon
122 | name={!expanded ? collapsedIcon : expandedIcon || collapsedIcon}
123 | className={styles.chevron}
124 | aria-hidden="true"
125 | />
126 | </span>
127 | )}
128 | </RAccordion.Trigger>
129 | </RAccordion.Header>
130 | <RAccordion.Content className={styles.contentWrapper}>
131 | <div className={styles.content}>{content}</div>
132 | </RAccordion.Content>
133 | </RAccordion.Item>
134 | );
135 | });
136 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/CodeBlock/CodeBlock.module.scss:
--------------------------------------------------------------------------------
```scss
1 | @use "../../components-core/theming/themes" as t;
2 |
3 | $themeVars: ();
4 | @function createThemeVar($componentVariable) {
5 | $themeVars: t.appendThemeVar($themeVars, $componentVariable) !global;
6 | @return t.getThemeVar($themeVars, $componentVariable);
7 | }
8 |
9 | $themeVars: t.composePaddingVars($themeVars, "CodeBlock");
10 | $themeVars: t.composeBorderVars($themeVars, "CodeBlock");
11 | $backgroundColor-CodeBlock: createThemeVar("backgroundColor-CodeBlock");
12 | $backgroundColor-CodeBlock-header: createThemeVar("backgroundColor-CodeBlock-header");
13 | $color-CodeBlock-headerSeparator: createThemeVar("color-CodeBlock-headerSeparator");
14 | $marginTop-CodeBlock: createThemeVar("marginTop-CodeBlock");
15 | $marginBottom-CodeBlock: createThemeVar("marginBottom-CodeBlock");
16 | $backgroundColor-CodeBlock-highlightRow: createThemeVar("backgroundColor-CodeBlock-highlightRow");
17 | $backgroundColor-CodeBlock-highlightString: createThemeVar("backgroundColor-CodeBlock-highlightString");
18 | $borderColor-CodeBlock-highlightString-emphasis: createThemeVar("borderColor-CodeBlock-highlightString-emphasis");
19 | $borderRadius-CodeBlock: createThemeVar("borderRadius-CodeBlock");
20 | $border-CodeBlock: createThemeVar("border-CodeBlock");
21 | $boxShadow-CodeBlock: createThemeVar("boxShadow-CodeBlock");
22 | $height-CodeBlock: createThemeVar("height-CodeBlock");
23 | $paddingHorizontal-content-CodeBlock: createThemeVar("paddingHorizontal-content-CodeBlock");
24 | $paddingVertical-content-CodeBlock: createThemeVar("paddingVertical-content-CodeBlock");
25 |
26 | @layer components {
27 | .codeBlock {
28 | @include t.borderVars($themeVars, "CodeBlock");
29 | @include t.paddingVars($themeVars, "CodeBlock");
30 | margin-top: $marginTop-CodeBlock;
31 | margin-bottom: $marginBottom-CodeBlock;
32 | background-color: $backgroundColor-CodeBlock;
33 | height: $height-CodeBlock;
34 | border-radius: $borderRadius-CodeBlock;
35 | //overflow: hidden;
36 | border: $border-CodeBlock;
37 | box-shadow: $boxShadow-CodeBlock;
38 | }
39 |
40 | .copyButton {
41 | opacity: 0.7;
42 |
43 | &:hover {
44 | opacity: 1;
45 | }
46 | }
47 |
48 | .codeBlockHeader {
49 | padding: t.$space-1;
50 | padding-left: t.$space-3;
51 | background-color: $backgroundColor-CodeBlock-header;
52 | border-bottom: $color-CodeBlock-headerSeparator solid 2px;
53 | font-size: t.$fontSize-sm;
54 | border-start-start-radius: t.getThemeVar($themeVars, "borderStartStartRadius-CodeBlock");
55 | border-start-end-radius: t.getThemeVar($themeVars, "borderStartEndRadius-CodeBlock");
56 | }
57 |
58 | .codeBlockContent {
59 | padding: $paddingVertical-content-CodeBlock $paddingHorizontal-content-CodeBlock;
60 | position: relative;
61 | display: flex;
62 | //align-items: center;
63 | min-height: 48px;
64 | height: 100%;
65 | overflow: auto;
66 |
67 | .codeBlockCopyButton {
68 | position: absolute;
69 | top: t.$space-1_5;
70 | right: t.$space-1_5;
71 | z-index: 1;
72 | display: none;
73 | background-color: $backgroundColor-CodeBlock;
74 | }
75 |
76 | &:hover {
77 | .codeBlockCopyButton {
78 | display: block;
79 | }
80 | }
81 |
82 | pre {
83 | flex-grow: 1;
84 | }
85 | }
86 |
87 | :global {
88 | .codeBlockHighlightRow {
89 | background-color: $backgroundColor-CodeBlock-highlightRow;
90 | }
91 |
92 | .codeBlockHighlightString {
93 | background-color: $backgroundColor-CodeBlock-highlightString;
94 | padding: 1px;
95 | }
96 |
97 | .codeBlockHighlightStringEmphasis {
98 | border: 2px solid $borderColor-CodeBlock-highlightString-emphasis;
99 | border-radius: 2px;
100 | padding: 1px;
101 | }
102 | }
103 | }
104 |
105 |
106 | :export {
107 | themeVars: t.json-stringify($themeVars);
108 | }
109 |
```
--------------------------------------------------------------------------------
/docs/content/components/Bookmark.md:
--------------------------------------------------------------------------------
```markdown
1 | # Bookmark [#bookmark]
2 |
3 | As its name suggests, this component places a bookmark into its parent component's view. The component has an `id` that you can use in links to navigate (scroll to) the bookmark's location.
4 |
5 | > [!INFO]
6 | > Pop out the examples in this article to view them on full screen.
7 |
8 | ## Using Bookmark [#using-bookmark]
9 |
10 | Use `Bookmark` as a standalone tag or wrap children with it.
11 |
12 | > [!INFO]
13 | > We suggest using a standalone bookmark, which does not increase the nesting depth of the source code, whenever possible. Note that a standalone bookmark will act as an additional child for its parent component, which can affect the layout (a `Stack` puts `gap`s between `Bookmark`s too).
14 |
15 | ### Standalone [#standalone]
16 |
17 | Add an `id` property to `Bookmark` instances and use the same identifiers in links with hash tags, as the following example shows:
18 |
19 | ```xmlui-pg copy display height="320px" name="Example: standalone Bookmark"
20 | ---app display copy
21 | <App layout="vertical-full-header" scrollWholePage="false">
22 | <NavPanel>
23 | <Link to="/#red">Jump to red</Link>
24 | <Link to="/#green">Jump to green</Link>
25 | <Link to="/#blue">Jump to blue</Link>
26 | </NavPanel>
27 | <Pages>
28 | <Page url="/">
29 | <Bookmark id="red">
30 | <VStack height="200px" backgroundColor="red" />
31 | </Bookmark>
32 | <Bookmark id="green">
33 | <VStack height="200px" backgroundColor="green" />
34 | </Bookmark>
35 | <Bookmark id="blue">
36 | <VStack height="200px" backgroundColor="blue" />
37 | </Bookmark>
38 | </Page>
39 | </Pages>
40 | </App>
41 | ---desc
42 | Clicking a link scrolls the bookmarked component adjacent to the corresponding `Bookmark` tag into the view:
43 | ```
44 |
45 | ### With nested children [#with-nested-children]
46 |
47 | Alternatively, you can nest components into `Bookmark`:
48 |
49 | ```xmlui-pg copy display height="320px" name="Example: Bookmark with nested children"
50 | ---app display copy
51 | <App layout="vertical-full-header" scrollWholePage="false">
52 | <NavPanel>
53 | <Link to="/#red">Jump to red</Link>
54 | <Link to="/#green">Jump to green</Link>
55 | <Link to="/#blue">Jump to blue</Link>
56 | </NavPanel>
57 | <Pages>
58 | <Page url="/">
59 | <Bookmark id="red">
60 | <VStack height="200px" backgroundColor="red" />
61 | </Bookmark>
62 | <Bookmark id="green">
63 | <VStack height="200px" backgroundColor="green" />
64 | </Bookmark>
65 | <Bookmark id="blue">
66 | <VStack height="200px" backgroundColor="blue" />
67 | </Bookmark>
68 | </Page>
69 | </Pages>
70 | </App>
71 | ---desc
72 | You can try; this example works like the previous one:
73 | ```
74 |
75 | ## Properties [#properties]
76 |
77 | ### `id` [#id]
78 |
79 | The unique identifier of the bookmark. You can use this identifier in links to navigate to this component's location. If this identifier is not set, you cannot programmatically visit this bookmark.
80 |
81 | ### `level` (default: 1) [#level-default-1]
82 |
83 | The level of the bookmark. The level is used to determine the bookmark's position in the table of contents.
84 |
85 | ### `omitFromToc` (default: false) [#omitfromtoc-default-false]
86 |
87 | If true, this bookmark will be excluded from the table of contents.
88 |
89 | ### `title` [#title]
90 |
91 | Defines the text to display the bookmark in the table of contents. If this property is empty, the text falls back to the value of `id`.
92 |
93 | ## Events [#events]
94 |
95 | This component does not have any events.
96 |
97 | ## Exposed Methods [#exposed-methods]
98 |
99 | ### `scrollIntoView` [#scrollintoview]
100 |
101 | Scrolls the bookmark into view.
102 |
103 | **Signature**: `scrollIntoView()`
104 |
105 | ## Styling [#styling]
106 |
107 | This component does not have any styles.
108 |
```
--------------------------------------------------------------------------------
/xmlui/src/components-core/loader/ExternalDataLoader.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { useCallback } from "react";
2 |
3 | import type {
4 | LoaderErrorFn,
5 | LoaderInProgressChangedFn,
6 | LoaderLoadedFn,
7 | } from "../abstractions/LoaderRenderer";
8 | import type { ComponentDef} from "../../abstractions/ComponentDefs";
9 | import type { ContainerState } from "../rendering/ContainerWrapper";
10 | import { removeNullProperties } from "../utils/misc";
11 | import { extractParam } from "../utils/extractParam";
12 | import { createLoaderRenderer } from "../renderers";
13 | import { useAppContext } from "../AppContext";
14 | import { Loader } from "./Loader";
15 | import { createMetadata, d } from "../../components/metadata-helpers";
16 |
17 | /**
18 | * Properties of the Data loader component
19 | */
20 | type ExternalDataLoaderProps = {
21 | loader: ExternalDataLoaderDef;
22 | state: ContainerState;
23 | doNotRemoveNulls?: boolean;
24 | loaderInProgressChanged: LoaderInProgressChangedFn;
25 | loaderIsRefetchingChanged: LoaderInProgressChangedFn;
26 | loaderLoaded: LoaderLoadedFn;
27 | loaderError: LoaderErrorFn;
28 | structuralSharing?: boolean;
29 | };
30 |
31 | /**
32 | * Represents a non-displayed React component, which handles the specified API loader
33 | */
34 | function ExternalDataLoader({
35 | loader,
36 | loaderInProgressChanged,
37 | loaderIsRefetchingChanged,
38 | loaderError,
39 | loaderLoaded,
40 | state,
41 | doNotRemoveNulls,
42 | structuralSharing = true,
43 | }: ExternalDataLoaderProps) {
44 | const appContext = useAppContext();
45 | const method = extractParam(state, loader.props.method, appContext);
46 | const headers: Record<string, string> = extractParam(state, loader.props.headers, appContext);
47 | const data = extractParam(state, loader.props.data, appContext);
48 |
49 | const url = extractParam(state, loader.props.url, appContext);
50 | const urlLoadable = !!url;
51 |
52 | const doLoad = useCallback(async () => {
53 | if (!urlLoadable) {
54 | return;
55 | }
56 | const response = await fetch(url, {
57 | method: method || "POST",
58 | headers: {
59 | "Content-Type": "application/json",
60 | ...headers,
61 | },
62 | body: JSON.stringify(data),
63 | });
64 | const responseObj = await response.json();
65 | if (!doNotRemoveNulls) {
66 | removeNullProperties(responseObj);
67 | }
68 | return responseObj;
69 | }, [urlLoadable, headers, data, url, method, doNotRemoveNulls]);
70 |
71 | return (
72 | <Loader
73 | state={state}
74 | loader={loader}
75 | loaderInProgressChanged={loaderInProgressChanged}
76 | loaderIsRefetchingChanged={loaderIsRefetchingChanged}
77 | loaderLoaded={loaderLoaded}
78 | loaderError={loaderError}
79 | loaderFn={doLoad}
80 | structuralSharing={structuralSharing}
81 | />
82 | );
83 | }
84 |
85 | export const ExternalDataLoaderMd = createMetadata({
86 | status: "stable",
87 | description: `Represents a loader that calls an API through an HTTP/HTTPS GET request`,
88 | props: {
89 | url: d("URL segment to use in the GET request"),
90 | method: d("The HTTP method to use"),
91 | headers: d("Headers to send with the request"),
92 | data: d("The body of the request to be sent as JSON"),
93 | },
94 | });
95 |
96 | type ExternalDataLoaderDef = ComponentDef<typeof ExternalDataLoaderMd>;
97 |
98 | export const externalDataLoaderRenderer = createLoaderRenderer(
99 | "ExternalDataLoader",
100 | ({ loader, state, loaderInProgressChanged, loaderIsRefetchingChanged, loaderError, loaderLoaded }) => {
101 | return (
102 | <ExternalDataLoader
103 | loader={loader}
104 | state={state}
105 | loaderInProgressChanged={loaderInProgressChanged}
106 | loaderIsRefetchingChanged={loaderIsRefetchingChanged}
107 | loaderLoaded={loaderLoaded}
108 | loaderError={loaderError}
109 | />
110 | );
111 | },
112 | ExternalDataLoaderMd,
113 | );
114 |
```
--------------------------------------------------------------------------------
/xmlui/scripts/generate-docs/logger.mjs:
--------------------------------------------------------------------------------
```
1 | /**
2 | * Logger class.
3 | * - severity indicates message importance
4 | * - levels control what messages will be logged
5 | */
6 | class Logger {
7 | // TODO: make class a singleton
8 |
9 | static severity = {
10 | info: "info",
11 | warning: "warning",
12 | error: "error",
13 | };
14 |
15 | constructor(...levels) {
16 | this.setLevels(...levels);
17 | }
18 |
19 | isValidSeverity(severity) {
20 | return Object.keys(Logger.severity).includes(severity);
21 | }
22 |
23 | isValidLevel(level) {
24 | return Object.keys(LOGGER_LEVELS).includes(level);
25 | }
26 |
27 | defaultSeverity = Logger.severity.error;
28 | defaultLogLevel = LOGGER_LEVELS.all;
29 |
30 | setLevels(...levels) {
31 | levels = Array.from(new Set(levels));
32 | let validLevels = levels.filter((level) => this.isValidLevel(level));
33 | if (validLevels.length === 0) {
34 | this._logError(`No valid log levels provided. Using defaults: ${this.defaultLogLevel}.`);
35 | validLevels = [this.defaultLogLevel];
36 | }
37 |
38 | this.info = this._noop;
39 | this.warning = this._noop;
40 | this.error = this._noop;
41 |
42 | if (validLevels.find((level) => level === LOGGER_LEVELS.none)) {
43 | return;
44 | }
45 | if (validLevels.find((level) => level === LOGGER_LEVELS.all)) {
46 | this.info = this._logInfo;
47 | this.warning = this._logWarning;
48 | this.error = this._logError;
49 | return;
50 | }
51 | for (const level of validLevels) {
52 | this[level] = this[`_log${level.charAt(0).toUpperCase() + level.slice(1)}`];
53 | }
54 | }
55 |
56 | log(severity = Logger.severity.info, ...args) {
57 | if (!this.isValidSeverity(severity)) {
58 | this.warning(
59 | `Invalid log severity: ${severity}. Defaulting to message severity: ${this.defaultSeverity}.`,
60 | );
61 | severity = this.defaultSeverity;
62 | }
63 | if (severity === Logger.severity.info) {
64 | this.info(...args);
65 | } else if (severity === Logger.severity.warning) {
66 | this.warning(...args);
67 | } else if (severity === Logger.severity.error) {
68 | this.error(...args);
69 | }
70 | }
71 |
72 | info(...args) {}
73 | warning(...args) {}
74 | warn(...args) {
75 | // Alias for warning() for consistency
76 | this.warning(...args);
77 | }
78 | error(...args) {}
79 |
80 | _logInfo(...args) {
81 | console.log("[INFO]", ...args);
82 | }
83 |
84 | _logWarning(...args) {
85 | console.log("[WARN]", ...args);
86 | }
87 |
88 | _logError(...args) {
89 | if (args[0] instanceof Error) {
90 | console.error("[ERR]", args[0].message + "\n", args[0].stack.split("\n").slice(1).join("\n "));
91 | } else {
92 | console.error("[ERR]", ...args);
93 | }
94 | }
95 |
96 | _noop(...args) {}
97 | }
98 |
99 | export const LOGGER_LEVELS = {
100 | ...Logger.severity,
101 | all: "all",
102 | none: "none",
103 | };
104 |
105 | // --- Usable logger instance
106 | export const logger = new Logger(LOGGER_LEVELS.all);
107 |
108 | // --- Error classes
109 |
110 | export class ErrorWithSeverity extends Error {
111 | constructor(message, severity = Logger.severity.error) {
112 | super(message);
113 | this.name = "ErrorWithSeverity";
114 | this.severity = severity;
115 | }
116 | }
117 |
118 | /**
119 | * Logs error to console depending on the type of the error thrown.
120 | * - ErrorWithSeverity type errors are logged with the severity specified.
121 | * - Other errors are logged with severity ERROR.
122 | * @param {ErrorWithSeverity | Error | string} error
123 | */
124 | export function processError(error) {
125 | if (error instanceof ErrorWithSeverity) {
126 | // We log the stack trace only for errors with severity ERROR
127 | error.severity === Logger.severity.error
128 | ? logger.log(error.severity, error)
129 | : logger.log(error.severity, error.message);
130 | } else if (error instanceof Error) {
131 | logger.error(error);
132 | } else {
133 | logger.error(error);
134 | }
135 | }
136 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/NavLink/NavLinkNative.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import type { CSSProperties, MouseEventHandler, ReactNode, Ref } from "react";
2 | import type React from "react";
3 | import { forwardRef, useContext, useMemo } from "react";
4 | import { NavLink as RrdNavLink } from "@remix-run/react";
5 | import type { To } from "react-router-dom";
6 | import classnames from "classnames";
7 |
8 | import styles from "./NavLink.module.scss";
9 | import type { LinkAria, LinkTarget } from "../abstractions";
10 | import { createUrlWithQueryParams } from "../component-utils";
11 | import { getAppLayoutOrientation } from "../App/AppNative";
12 | import { useAppLayoutContext } from "../App/AppLayoutContext";
13 | import { NavPanelContext } from "../NavPanel/NavPanelNative";
14 | import { NavGroupContext } from "../NavGroup/NavGroupContext";
15 |
16 | // Default props for NavLink component
17 | export const defaultProps = {
18 | active: false,
19 | displayActive: true,
20 | };
21 |
22 | type Props = {
23 | uid?: string;
24 | to?: string;
25 | target?: LinkTarget;
26 | disabled?: boolean;
27 | children?: ReactNode;
28 | displayActive?: boolean;
29 | forceActive?: boolean;
30 | vertical?: boolean;
31 | style?: CSSProperties;
32 | className?: string;
33 | onClick?: MouseEventHandler;
34 | icon?: React.ReactNode;
35 | accessibilityProps?: any;
36 | } & Pick<React.HTMLAttributes<HTMLAnchorElement>, LinkAria>;
37 |
38 | export const NavLink = forwardRef(function NavLink(
39 | {
40 | /* eslint-disable react/prop-types */
41 | uid,
42 | children,
43 | disabled,
44 | to,
45 | displayActive = defaultProps.displayActive,
46 | vertical,
47 | style,
48 | onClick,
49 | icon,
50 | forceActive,
51 | className,
52 | ...rest
53 | }: Props,
54 | ref: Ref<any>,
55 | ) {
56 | const appLayoutContext = useAppLayoutContext();
57 | const layoutIsVertical =
58 | !!appLayoutContext && getAppLayoutOrientation(appLayoutContext.layout).includes("vertical");
59 | const navPanelContext = useContext(NavPanelContext);
60 | const inDrawer = navPanelContext?.inDrawer;
61 |
62 | const { level } = useContext(NavGroupContext);
63 | let safeVertical = vertical;
64 |
65 | if (safeVertical === undefined) {
66 | safeVertical = layoutIsVertical || inDrawer;
67 | }
68 | const smartTo = useMemo(() => {
69 | if (to) {
70 | return createUrlWithQueryParams(to) as To;
71 | }
72 | }, [to]) as To;
73 |
74 | const styleObj = useMemo(() => {
75 | return {
76 | "--nav-link-level": layoutIsVertical ? level + 1 : 0,
77 | ...style,
78 | };
79 | }, [level, style, layoutIsVertical]);
80 |
81 | const baseClasses = classnames(styles.content, styles.base, className, {
82 | [styles.disabled]: disabled,
83 | [styles.vertical]: safeVertical,
84 | [styles.includeHoverIndicator]: displayActive,
85 | [styles.navItemActive]: displayActive && forceActive,
86 | });
87 |
88 | let innerContent = (
89 | <div className={styles.innerContent}>
90 | {icon}
91 | {children}
92 | </div>
93 | );
94 | let content: React.ReactNode = null;
95 | if (disabled || !smartTo) {
96 | content = (
97 | <button
98 | {...rest}
99 | ref={ref}
100 | onClick={onClick}
101 | className={baseClasses}
102 | style={styleObj}
103 | disabled={disabled}
104 | >
105 | {innerContent}
106 | </button>
107 | );
108 | } else {
109 | content = (
110 | <RrdNavLink
111 | {...rest}
112 | id={uid}
113 | ref={ref}
114 | to={smartTo as To}
115 | style={styleObj}
116 | onClick={onClick}
117 | className={({ isActive }) =>
118 | classnames(baseClasses, {
119 | [styles.displayActive]: displayActive,
120 | [styles.navItemActive]: displayActive && (isActive || forceActive),
121 | "xmlui-navlink-active": isActive || forceActive,
122 | })
123 | }
124 | >
125 | {innerContent}
126 | </RrdNavLink>
127 | );
128 | }
129 |
130 | return content;
131 | });
132 |
```
--------------------------------------------------------------------------------
/xmlui/src/parsers/scripting/code-behind-collect.ts:
--------------------------------------------------------------------------------
```typescript
1 | import {
2 | T_ARROW_EXPRESSION,
3 | T_FUNCTION_DECLARATION,
4 | T_VAR_STATEMENT,
5 | type ArrowExpression,
6 | type CodeDeclaration,
7 | type CollectedDeclarations,
8 | type Expression,
9 | type FunctionDeclaration,
10 | type Statement,
11 | } from "../../components-core/script-runner/ScriptingSourceTree";
12 | import type { VisitorState } from "./tree-visitor";
13 | import { visitNode } from "./tree-visitor";
14 | import { isModuleErrors, parseScriptModule } from "./modules";
15 |
16 | export const PARSED_MARK_PROP = "__PARSED__";
17 |
18 | // --- Collect module statements from a parsed module
19 | export function collectCodeBehindFromSource(
20 | moduleName: string,
21 | source: string
22 | ): CollectedDeclarations {
23 | const result: CollectedDeclarations = {
24 | vars: {},
25 | moduleErrors: {},
26 | functions: {},
27 | };
28 |
29 | const collectedFunctions: Record<string, CodeDeclaration> = {};
30 |
31 | // --- Parse the module (recursively, including imported modules) in restrictive mode
32 | const parsedModule = parseScriptModule(moduleName, source);
33 | if (isModuleErrors(parsedModule)) {
34 | return { ...result, moduleErrors: parsedModule };
35 | }
36 |
37 | // --- Collect statements from the module
38 | parsedModule.statements.forEach((stmt) => {
39 | switch (stmt.type) {
40 | case T_VAR_STATEMENT:
41 | stmt.decls.forEach((decl) => {
42 | if (decl.id.name in result.vars) {
43 | throw new Error(`Duplicated var declaration: '${decl.id.name}'`);
44 | }
45 | result.vars[decl.id.name] = {
46 | [PARSED_MARK_PROP]: true,
47 | tree: decl.expr,
48 | };
49 | });
50 | break;
51 | case T_FUNCTION_DECLARATION:
52 | addFunctionDeclaration(stmt);
53 | break;
54 | default:
55 | throw new Error(`Only reactive variable and function definitions are allowed in a code-behind module.`);
56 | }
57 | });
58 | return result;
59 |
60 | // --- Collect function declaration data
61 | function addFunctionDeclaration(stmt: FunctionDeclaration): void {
62 | if (collectedFunctions?.[stmt.id.name] !== undefined) {
63 | return;
64 | }
65 | if (stmt.id.name in result.functions) {
66 | throw new Error(`Duplicated function declaration: '${stmt.id.name}'`);
67 | }
68 | const arrow: ArrowExpression = {
69 | type: T_ARROW_EXPRESSION,
70 | args: stmt.args.slice(),
71 | statement: stmt.stmt,
72 | // closureContext: obtainClosures({
73 | // childThreads: [],
74 | // blocks: [{ vars: {} }],
75 | // loops: [],
76 | // breakLabelValue: -1,
77 | // }),
78 | } as ArrowExpression;
79 |
80 | collectedFunctions[stmt.id.name] = {
81 | [PARSED_MARK_PROP]: true,
82 | tree: arrow,
83 | };
84 | result.functions[stmt.id.name] = {
85 | [PARSED_MARK_PROP]: true,
86 | tree: arrow,
87 | };
88 | }
89 | }
90 |
91 | // --- Remove all code-behind tokens from the tree
92 | export function removeCodeBehindTokensFromTree(declarations: CollectedDeclarations): void {
93 | if (!declarations) return;
94 |
95 | const state: VisitorState = {
96 | data: null,
97 | cancel: false,
98 | skipChildren: false,
99 | };
100 |
101 | Object.keys(declarations.vars).forEach((key) => {
102 | removeTokens(declarations.vars[key]);
103 | });
104 | Object.keys(declarations.functions).forEach((key) => {
105 | removeTokens(declarations.functions[key]);
106 | });
107 |
108 | function removeTokens(declaration: CodeDeclaration): void {
109 | const nodeVisitor = (before: boolean, visited: Expression | Statement, state: VisitorState) => {
110 | if (before) {
111 | if (visited) {
112 | delete visited.startToken
113 | delete visited.endToken;
114 | }
115 | }
116 | return state;
117 | };
118 |
119 | visitNode(declaration.tree, state, nodeVisitor, nodeVisitor);
120 | }
121 | }
122 |
```
--------------------------------------------------------------------------------
/xmlui/scripts/generate-docs/error-handling.mjs:
--------------------------------------------------------------------------------
```
1 | import { logger, ErrorWithSeverity, LOGGER_LEVELS, processError } from "./logger.mjs";
2 | import { ERROR_HANDLING, ERROR_MESSAGES } from "./constants.mjs";
3 |
4 | /**
5 | * Standardized error handling utilities for documentation generation scripts
6 | */
7 |
8 | /**
9 | * Handles errors and exits gracefully with appropriate exit codes
10 | * @param {Error | ErrorWithSeverity | string} error - The error to handle
11 | * @param {number} exitCode - Optional exit code (defaults to GENERAL_ERROR)
12 | * @param {string} context - Optional context about where the error occurred
13 | */
14 | export function handleFatalError(error, exitCode = ERROR_HANDLING.EXIT_CODES.GENERAL_ERROR, context = null) {
15 | if (context) {
16 | logger.error(`Error in ${context}:`);
17 | }
18 |
19 | processError(error);
20 | process.exit(exitCode);
21 | }
22 |
23 | /**
24 | * Handles non-fatal errors that should be logged but don't stop execution
25 | * @param {Error | ErrorWithSeverity | string} error - The error to handle
26 | * @param {string} context - Optional context about where the error occurred
27 | */
28 | export function handleNonFatalError(error, context = null) {
29 | if (context) {
30 | logger.warn(`Warning in ${context}:`);
31 | }
32 |
33 | if (error instanceof ErrorWithSeverity) {
34 | logger.log(error.severity, error.message);
35 | } else if (error instanceof Error) {
36 | logger.warn(error.message);
37 | } else {
38 | logger.warn(error);
39 | }
40 | }
41 |
42 | /**
43 | * Validates required dependencies and throws appropriate errors
44 | * @param {Object} dependencies - Object with dependency checks
45 | * @throws {ErrorWithSeverity} If any required dependency is missing
46 | */
47 | export function validateDependencies(dependencies) {
48 | for (const [name, value] of Object.entries(dependencies)) {
49 | if (value === undefined || value === null) {
50 | throw new ErrorWithSeverity(
51 | ERROR_MESSAGES[`NO_${name.toUpperCase()}`] || `Missing required dependency: ${name}`,
52 | LOGGER_LEVELS.error
53 | );
54 | }
55 | }
56 | }
57 |
58 | /**
59 | * Wraps async operations with standardized error handling
60 | * @param {Function} operation - The async operation to execute
61 | * @param {string} operationName - Name of the operation for logging
62 | * @param {number} exitCode - Exit code to use if operation fails
63 | * @returns {Promise<any>} The result of the operation
64 | */
65 | export async function withErrorHandling(operation, operationName, exitCode = ERROR_HANDLING.EXIT_CODES.GENERAL_ERROR) {
66 | try {
67 | return await operation();
68 | } catch (error) {
69 | handleFatalError(error, exitCode, operationName);
70 | }
71 | }
72 |
73 | /**
74 | * Wraps file operations with standardized error handling
75 | * @param {Function} fileOperation - The file operation to execute
76 | * @param {string} filePath - Path of the file being operated on
77 | * @param {string} operationType - Type of operation (read, write, delete, etc.)
78 | * @returns {Promise<any>} The result of the operation
79 | */
80 | export async function withFileErrorHandling(fileOperation, filePath, operationType) {
81 | try {
82 | return await fileOperation();
83 | } catch (error) {
84 | const errorMessage = `${ERROR_MESSAGES.FILE_WRITE_ERROR}: ${filePath} (${operationType})`;
85 | throw new ErrorWithSeverity(errorMessage, LOGGER_LEVELS.error);
86 | }
87 | }
88 |
89 | /**
90 | * Creates a standardized error for missing metadata
91 | * @param {string} metadataType - Type of metadata that's missing
92 | * @returns {ErrorWithSeverity}
93 | */
94 | export function createMetadataError(metadataType) {
95 | const message = ERROR_MESSAGES[`NO_${metadataType.toUpperCase()}`] ||
96 | `${ERROR_MESSAGES.METADATA_LOAD_ERROR}: ${metadataType}`;
97 | return new ErrorWithSeverity(message, LOGGER_LEVELS.error);
98 | }
99 |
```
--------------------------------------------------------------------------------
/xmlui/tests/components/Tree/Tree-states.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describe, expect, it } from "vitest";
2 | import { NodeLoadingState } from '../../../src/components-core/abstractions/treeAbstractions';
3 |
4 | // Helper functions to test (these would normally be extracted from TreeNative for testing)
5 | type NodeStatesMap = Map<string, NodeLoadingState>;
6 |
7 | function createNodeStateHelpers() {
8 | let nodeStates: NodeStatesMap = new Map();
9 |
10 | const setNodeLoadingState = (nodeId: string, state: NodeLoadingState) => {
11 | nodeStates.set(nodeId, state);
12 | };
13 |
14 | const getNodeLoadingState = (nodeId: string): NodeLoadingState => {
15 | return nodeStates.get(nodeId) || 'unloaded';
16 | };
17 |
18 | const clearNodeLoadingState = (nodeId: string) => {
19 | nodeStates.delete(nodeId);
20 | };
21 |
22 | const getAllNodeStates = (): NodeStatesMap => {
23 | return new Map(nodeStates);
24 | };
25 |
26 | const clearAllNodeStates = () => {
27 | nodeStates.clear();
28 | };
29 |
30 | return {
31 | setNodeLoadingState,
32 | getNodeLoadingState,
33 | clearNodeLoadingState,
34 | getAllNodeStates,
35 | clearAllNodeStates
36 | };
37 | }
38 |
39 | describe('Tree Node States Management - Unit Tests', () => {
40 | it('should set and get node loading state', () => {
41 | const helpers = createNodeStateHelpers();
42 |
43 | helpers.setNodeLoadingState('node1', 'loading');
44 | expect(helpers.getNodeLoadingState('node1')).toBe('loading');
45 |
46 | helpers.setNodeLoadingState('node1', 'loaded');
47 | expect(helpers.getNodeLoadingState('node1')).toBe('loaded');
48 | });
49 |
50 | it('should return unloaded for unknown nodes', () => {
51 | const helpers = createNodeStateHelpers();
52 |
53 | expect(helpers.getNodeLoadingState('unknown')).toBe('unloaded');
54 | });
55 |
56 | it('should clear node loading state', () => {
57 | const helpers = createNodeStateHelpers();
58 |
59 | helpers.setNodeLoadingState('node1', 'loaded');
60 | expect(helpers.getNodeLoadingState('node1')).toBe('loaded');
61 |
62 | helpers.clearNodeLoadingState('node1');
63 | expect(helpers.getNodeLoadingState('node1')).toBe('unloaded');
64 | });
65 |
66 | it('should handle multiple node states', () => {
67 | const helpers = createNodeStateHelpers();
68 |
69 | helpers.setNodeLoadingState('node1', 'loading');
70 | helpers.setNodeLoadingState('node2', 'loaded');
71 | helpers.setNodeLoadingState('node3', 'unloaded');
72 |
73 | expect(helpers.getNodeLoadingState('node1')).toBe('loading');
74 | expect(helpers.getNodeLoadingState('node2')).toBe('loaded');
75 | expect(helpers.getNodeLoadingState('node3')).toBe('unloaded');
76 |
77 | const allStates = helpers.getAllNodeStates();
78 | expect(allStates.size).toBe(3);
79 | expect(allStates.get('node1')).toBe('loading');
80 | expect(allStates.get('node2')).toBe('loaded');
81 | expect(allStates.get('node3')).toBe('unloaded');
82 | });
83 |
84 | it('should clear all node states', () => {
85 | const helpers = createNodeStateHelpers();
86 |
87 | helpers.setNodeLoadingState('node1', 'loading');
88 | helpers.setNodeLoadingState('node2', 'loaded');
89 |
90 | expect(helpers.getAllNodeStates().size).toBe(2);
91 |
92 | helpers.clearAllNodeStates();
93 |
94 | expect(helpers.getAllNodeStates().size).toBe(0);
95 | expect(helpers.getNodeLoadingState('node1')).toBe('unloaded');
96 | expect(helpers.getNodeLoadingState('node2')).toBe('unloaded');
97 | });
98 |
99 | it('should validate NodeLoadingState enum values', () => {
100 | const helpers = createNodeStateHelpers();
101 |
102 | // Test all valid enum values
103 | const validStates: NodeLoadingState[] = ['unloaded', 'loading', 'loaded'];
104 |
105 | validStates.forEach(state => {
106 | helpers.setNodeLoadingState('test', state);
107 | expect(helpers.getNodeLoadingState('test')).toBe(state);
108 | });
109 | });
110 | });
```
--------------------------------------------------------------------------------
/docs/public/pages/howto/pass-data-to-a-modal-dialog.md:
--------------------------------------------------------------------------------
```markdown
1 | # Pass data to a Modal Dialog
2 |
3 | ```xmlui-pg name="Click on a team member to edit details"
4 | ---app
5 | <App>
6 | <Test />
7 | </App>
8 | ---api
9 | {
10 | "apiUrl": "/api",
11 | "initialize": "$state.team_members = [
12 | { id: 1, name: 'Sarah Chen', role: 'Product Manager', email: '[email protected]', avatar: 'https://i.pravatar.cc/100?u=sarah', department: 'Product', startDate: '2022-03-15' },
13 | { id: 2, name: 'Marcus Johnson', role: 'Senior Developer', email: '[email protected]', avatar: 'https://i.pravatar.cc/100?u=marcus', department: 'Engineering', startDate: '2021-08-20' },
14 | { id: 3, name: 'Elena Rodriguez', role: 'UX Designer', email: '[email protected]', avatar: 'https://i.pravatar.cc/100?u=elena', department: 'Design', startDate: '2023-01-10' }
15 | ]",
16 | "operations": {
17 | "get_team_members": {
18 | "url": "/team_members",
19 | "method": "get",
20 | "handler": "return $state.team_members"
21 | }
22 | }
23 | }
24 | ---comp display
25 | <Component name="Test">
26 |
27 | <DataSource
28 | id="team_members"
29 | url="/api/team_members"
30 | />
31 |
32 | <ModalDialog id="memberDetailsDialog" title="Team Member Details">
33 | <Theme backgroundColor-overlay="$color-surface-900">
34 | <VStack gap="1rem" padding="1rem">
35 | <!-- Avatar and Basic Info -->
36 | <HStack gap="1rem" alignItems="center">
37 | <Avatar
38 | url="{$param.avatar}"
39 | size="lg"
40 | name="{$param.name}"
41 | />
42 | <VStack gap="0.25rem" alignItems="start">
43 | <Text variant="strong" fontSize="1.2rem">{$param.name}</Text>
44 | <Text variant="caption">{$param.role}</Text>
45 | <Text variant="caption" color="blue">{$param.email}</Text>
46 | </VStack>
47 | </HStack>
48 |
49 | <!-- Details Card -->
50 | <Card padding="1rem">
51 | <VStack gap="0.5rem">
52 | <HStack>
53 | <Text variant="strong">Department:</Text>
54 | <Text>{$param.department}</Text>
55 | </HStack>
56 | <HStack>
57 | <Text variant="strong">Start Date:</Text>
58 | <Text>{$param.startDate}</Text>
59 | </HStack>
60 | <HStack>
61 | <Text variant="strong">Employee ID:</Text>
62 | <Text>#{$param.id}</Text>
63 | </HStack>
64 | </VStack>
65 | </Card>
66 |
67 | <!-- Actions -->
68 | <HStack gap="0.5rem">
69 | <Button
70 | label="Send Email"
71 | size="sm"
72 | onClick="console.log('Email to:', $param.email)"
73 | />
74 | <Button
75 | label="View Calendar"
76 | size="sm"
77 | variant="secondary"
78 | onClick="console.log('Calendar for:', $param.name)"
79 | />
80 | </HStack>
81 | </VStack>
82 | </Theme>
83 | </ModalDialog>
84 |
85 | <Text variant="strong" marginBottom="1rem">Team Directory</Text>
86 |
87 | <VStack gap="0.5rem">
88 | <Items data="{team_members}">
89 | <Card
90 | padding="1rem"
91 | cursor="pointer"
92 | onClick="{
93 | memberDetailsDialog.open({
94 | id: $item.id,
95 | name: $item.name,
96 | role: $item.role,
97 | email: $item.email,
98 | avatar: $item.avatar,
99 | department: $item.department,
100 | startDate: $item.startDate
101 | })
102 | }"
103 | >
104 | <HStack gap="1rem" alignItems="center">
105 | <Avatar
106 | url="{$item.avatar}"
107 | size="sm"
108 | name="{$item.name}"
109 | />
110 | <VStack gap="0.25rem" alignItems="start">
111 | <Text variant="strong">{$item.name}</Text>
112 | <Text variant="caption">{$item.role} - {$item.department}</Text>
113 | </VStack>
114 | </HStack>
115 | </Card>
116 | </Items>
117 | </VStack>
118 |
119 | </Component>
120 | ```
121 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Heading/Heading.md:
--------------------------------------------------------------------------------
```markdown
1 | %-DESC-START
2 |
3 | **Key features:**
4 | - **Semantic levels**: Choose from h1 through h6 for proper document structure and accessibility
5 | - **Text overflow control**: Automatic ellipses and line limiting for long headings
6 | - **Anchor generation**: Optional hover anchors for deep linking to specific sections
7 |
8 | For the shorthand versions see: [H1](./H1), [H2](./H2), [H3](./H3), [H4](./H4), [H5](./H5), [H6](./H6).
9 |
10 | ```xmlui-pg copy display name="Example: Headings with levels"
11 | <App>
12 | <Heading level="h1" value="Heading Level 1" />
13 | <Text>Text following H1</Text>
14 | <Heading level="h2" value="Heading Level 2" />
15 | <Text>Text following H2</Text>
16 | <Heading level="h3" value="Heading Level 3" />
17 | <Text>Text following H3</Text>
18 | <Heading level="h4" value="Heading Level 4" />
19 | <Text>Text following H4</Text>
20 | <Heading level="h5" value="Heading Level 5" />
21 | <Text>Text following H5</Text>
22 | <Heading level="h6" value="Heading Level 6" />
23 | <Text>Text following H6</Text>
24 | </App>
25 | ```
26 |
27 | %-DESC-END
28 |
29 | %-PROP-START value
30 |
31 | ```xmlui-pg copy display name="Example: value"
32 | <App>
33 | <Heading value="This is level 3 (value)" level="h3" />
34 | <Heading level="h3">This is level 3 (child)</Heading>
35 | <Heading value="Value" level="h3"><Icon name="trash" /></Heading>
36 | </App>
37 | ```
38 |
39 | %-PROP-END
40 |
41 | %-PROP-START level
42 |
43 | | Value | Description |
44 | | :---- | :---------------------------------------------------- |
45 | | `h1` | **(default)** Equivalent to the `<h1 />` HTML element |
46 | | `h2` | Equivalent to the `<h2 />` HTML element |
47 | | `h3` | Equivalent to the `<h3 />` HTML element |
48 | | `h4` | Equivalent to the `<h4 />` HTML element |
49 | | `h5` | Equivalent to the `<h5 />` HTML element |
50 | | `h6` | Equivalent to the `<h6 />` HTML element |
51 |
52 | For a visual example, see the component description.
53 |
54 | %-PROP-END
55 |
56 | %-PROP-START maxLines
57 |
58 | ```xmlui-pg copy display name="Example: maxLines"
59 | <App>
60 | <H2
61 | maxWidth="160px"
62 | backgroundColor="cyan"
63 | value="A long heading text that will likely overflow" maxLines="2" />
64 | </App>
65 | ```
66 |
67 | %-PROP-END
68 |
69 | %-PROP-START preserveLinebreaks
70 |
71 | ```xmlui-pg copy display name="Example: preserveLinebreaks"
72 | ---app copy display {5}
73 | <App>
74 | <HStack>
75 | <H3
76 | width="200px"
77 | backgroundColor="cyan"
78 | preserveLinebreaks="true"
79 | value="(preserve) This long text
80 | with several line breaks
81 | does not fit into a viewport with a 200-pixel width." />
82 | <H3
83 | width="200px"
84 | backgroundColor="cyan"
85 | value="(do not preserve) This long text
86 | with several line breaks
87 | does not fit into a viewport with a 200-pixel width." />
88 | </HStack>
89 | </App>
90 | ---desc
91 | You can observe the effect of using `preserveLinebreaks`:
92 | ```
93 |
94 | >[!INFO]
95 | > Remember to use the `value` property of `Heading`.
96 | > Linebreaks are converted to spaces when nesting the text in the `Heading` component.
97 |
98 | %-PROP-END
99 |
100 | %-PROP-START ellipses
101 |
102 | ```xmlui-pg copy {4} display name="Example: ellipses"
103 | <App>
104 | <VStack width="200px">
105 | <H3
106 | backgroundColor="cyan"
107 | maxLines="1"
108 | ellipses="false">
109 | Though this long text does is about to crop!
110 | </H3>
111 | <H3
112 | backgroundColor="cyan"
113 | maxLines="1">
114 | Though this long text does is about to crop!
115 | </H3>
116 | </VStack>
117 | </App>
118 | ```
119 |
120 | %-PROP-END
121 |
122 | %-PROP-START showAnchor
123 |
124 | If this property is not set, the engine checks if `showHeadingAnchors` flag is turned on in the global configuration (in the `appGlobals` configuration object) and displays the heading anchor accordingly.
125 |
126 | %-PROP-END
```
--------------------------------------------------------------------------------
/docs/public/pages/helper-tags.md:
--------------------------------------------------------------------------------
```markdown
1 | # Helper Tags
2 |
3 | Helper tags provide alternative XML markup syntax for declaring variables, properties, and event handlers in XMLUI.
4 |
5 | ## variable
6 |
7 | Use `<variable>` as an alternative to the `var.` attribute prefix syntax. Instead of this:
8 |
9 | ```xmlui
10 | <App var.count="{0}" var.message="Hello, World!">
11 | <Text>{message}</Text>
12 | <Button onClick="count++" label="Count: {count}" />
13 | </App>
14 | ```
15 |
16 | You can do this:
17 |
18 | ```xmlui
19 | <App>
20 | <variable name="count" value="{0}" />
21 | <variable name="message" value="Hello, World!" />
22 | <Text>{message}</Text>
23 | <Button onClick="count++" label="Count: {count}" />
24 | </App>
25 | ```
26 |
27 | ## property
28 |
29 | Use `<property>` to declare properties with nested markup
30 |
31 | ```xmlui
32 | <Form data='{{ name: "", email: "" }}'>
33 | <FormItem bindTo="name" label="Name" />
34 | <FormItem bindTo="email" label="Email" />
35 |
36 | <property name="buttonRowTemplate">
37 | <HStack gap="1rem">
38 | <Button type="submit" label="Save" variant="primary" />
39 | <Button type="reset" label="Cancel" variant="secondary" />
40 | </HStack>
41 | </property>
42 | </Form>
43 | ```
44 |
45 | App headers can use logo templates for custom branding:
46 |
47 | ```xmlui
48 | <AppHeader>
49 | <property name="logoTemplate">
50 | <HStack verticalAlignment="center" gap="0.5rem">
51 | <Icon name="star" size="lg" color="primary" />
52 | <H2>My App</H2>
53 | </HStack>
54 | </property>
55 | </AppHeader>
56 | ```
57 |
58 | Lists and other data-driven components can use item templates:
59 |
60 | ```xmlui
61 | <List data="{users}">
62 | <property name="itemTemplate">
63 | <HStack gap="1rem" padding="0.5rem">
64 | <Avatar url="{$item.avatar}" name="{$item.name}" />
65 | <VStack>
66 | <Text weight="bold">{$item.name}</Text>
67 | <Text color="muted">{$item.email}</Text>
68 | </VStack>
69 | </HStack>
70 | </property>
71 | </List>
72 | ```
73 |
74 | Dropdown components can have rich option layouts:
75 |
76 | ```xmlui
77 | <Select data="{countries}" bindTo="selectedCountry">
78 | <property name="optionTemplate">
79 | <HStack gap="0.5rem">
80 | <Image src="{$item.flag}" width="20px" height="15px" />
81 | <Text>{$item.name}</Text>
82 | <Text color="muted">({$item.code})</Text>
83 | </HStack>
84 | </property>
85 | </Select>
86 | ```
87 |
88 | ## event
89 |
90 | Use `<event>` to declare event handlers as markup and enable the use of component-based handlers.
91 |
92 | Instead of using the `on` attribute prefix:
93 |
94 | ```xmlui
95 | <Button label="Click me" onClick="count++" />
96 | ```
97 |
98 | You can use the `<event>` tag:
99 |
100 | ```xmlui
101 | <Button label="Click me">
102 | <event name="click">
103 | count++
104 | </event>
105 | </Button>
106 | ```
107 |
108 | `<event>` is necessary when using `<APICall>` as an event handler.
109 |
110 | ```xmlui
111 | <Button label="Save Data">
112 | <event name="click">
113 | <APICall
114 | url="/api/save"
115 | method="POST"
116 | body="{formData}"
117 | onSuccess="toast('Data saved successfully!')"
118 | onError="toast('Failed to save data', 'error')" />
119 | </event>
120 | </Button>
121 | ```
122 |
123 | ## method
124 |
125 | Use `<method>` to export a method from a component.
126 |
127 | ```xmlui
128 | <App>
129 | <UsingInternalModal id="component"/>
130 | <Button label="Open the internal dialog" onClick="component.openDialog()" />
131 | </App>
132 |
133 |
134 | Component name="UsingInternalModal">
135 | <ModalDialog id="dialog" title="Example Dialog">
136 | <Button label="Close Dialog" onClick="dialog.close()" />
137 | </ModalDialog>
138 |
139 | <H1>Using an Internal Modal Dialog</H1>
140 |
141 | <method name="openDialog">
142 | console.log('internal method called')
143 | dialog.open();
144 | </method>
145 | </Component>
146 | ```
147 |
148 | ## script
149 |
150 | Use `<script>` to declare inline JavaScript code.
151 |
152 | ```xmlui
153 | <Component name="ImportProducts">
154 | <script>
155 | var parsedCsv = null;
156 |
157 | function isDuplicate(name) {
158 | return existingProducts.value.some(p => p.name === name);
159 | }
160 | </script>
161 | ...
162 | ```
163 |
164 |
```
--------------------------------------------------------------------------------
/xmlui/src/parsers/xmlui-parser/utils.ts:
--------------------------------------------------------------------------------
```typescript
1 | import type { Node } from "./syntax-node";
2 | import type { GetText } from "./parser";
3 | import { SyntaxKind, getSyntaxKindStrRepr, isInnerNode } from "./syntax-kind";
4 |
5 | export function toDbgString(
6 | node: Node,
7 | getText: (node: Node) => string,
8 | indentationLvl: number = 0,
9 | ): string {
10 | const prefix = `${" ".repeat(indentationLvl)} ${getSyntaxKindStrRepr(node.kind)} @${node.start}..${node.end}`;
11 | if (!isInnerNode(node.kind)) {
12 | let tokenText = getText(node);
13 | if (node.kind === SyntaxKind.NewLineTrivia) {
14 | tokenText = "*newline*";
15 | }
16 | return prefix + ` "${tokenText}"`;
17 | } else {
18 | return (
19 | prefix +
20 | "\n" +
21 | node.children?.map((c) => toDbgString(c, getText, indentationLvl + 1)).join("\n")
22 | );
23 | }
24 | }
25 |
26 | /** Disregards error nodes amongst the children of the 2 compared name node. (Those reported an error earlyer anyways)*/
27 | export function tagNameNodesWithoutErrorsMatch(
28 | name1: Node,
29 | name2: Node,
30 | getText: GetText,
31 | ): boolean {
32 | const children1 = name1.children?.filter((c) => c.kind !== SyntaxKind.ErrorNode) ?? [];
33 | const children2 = name2.children?.filter((c) => c.kind !== SyntaxKind.ErrorNode) ?? [];
34 |
35 | if (children1.length !== children2.length) {
36 | return false;
37 | }
38 | for (let i = 0; i < children1.length; ++i) {
39 | if (getText(children1[i]) !== getText(children2[i])) {
40 | return false;
41 | }
42 | }
43 | return true;
44 | }
45 |
46 | /** If the position is in-between two tokens, the chain to the token just before the cursor is provided as well*/
47 | export type FindTokenSuccess =
48 | | {
49 | chainAtPos: Node[];
50 |
51 | /** If the position is in-between two tokens, the chain to the token just before the position is provided. */
52 | chainBeforePos: Node[];
53 |
54 | /**
55 | * This field specifies the first index where
56 | * `chainBeforePos` differs from chainAtPos
57 | */
58 | sharedParents: number;
59 | }
60 | | {
61 | chainBeforePos: undefined;
62 | chainAtPos: Node[];
63 | sharedParents: undefined;
64 | };
65 |
66 | export function findTokenAtPos(node: Node, position: number): FindTokenSuccess | undefined {
67 | const chain: Node[] = [node];
68 | let sharedParents: number;
69 |
70 | if (node.start > position || position > node.end) {
71 | return undefined;
72 | }
73 |
74 | const res: FindTokenSuccess = {
75 | chainAtPos: chain,
76 | chainBeforePos: undefined,
77 | sharedParents: undefined,
78 | };
79 |
80 | while (node.children !== undefined && node.children.length > 0) {
81 | //todo: make it a binary search before finding a fork
82 | const nodeAtPosIdx = node.children.findIndex(
83 | (n) =>
84 | n.start <= position &&
85 | (position < n.end || (n.kind === SyntaxKind.EndOfFileToken && n.start <= n.end)),
86 | );
87 |
88 | const nodeAtPos = node.children[nodeAtPosIdx];
89 | const nodeBeforePos = node.children[nodeAtPosIdx - 1];
90 |
91 | if (nodeBeforePos !== undefined && position <= nodeAtPos.pos) {
92 | sharedParents = chain.length;
93 |
94 | return {
95 | chainBeforePos: chain.concat(findLastToken(nodeBeforePos)),
96 | sharedParents,
97 |
98 | chainAtPos: chain.concat(findFirstToken(nodeAtPos)),
99 | };
100 | }
101 |
102 | node = nodeAtPos;
103 | res.chainAtPos!.push(node);
104 | }
105 | return res;
106 | }
107 |
108 | function findFirstToken(node: Node): Node[] {
109 | const chain = [node];
110 | while (node.children !== undefined && node.children.length > 0) {
111 | node = node.children[0];
112 | chain.push(node);
113 | }
114 | return chain;
115 | }
116 |
117 | function findLastToken(node: Node): Node[] {
118 | const chain = [node];
119 | while (node.children !== undefined && node.children.length > 0) {
120 | node = node.children[node.children.length - 1];
121 | chain.push(node);
122 | }
123 | return chain;
124 | }
125 |
```
--------------------------------------------------------------------------------
/xmlui/src/components-core/script-runner/ParameterParser.ts:
--------------------------------------------------------------------------------
```typescript
1 | import type { Expression } from "./ScriptingSourceTree";
2 | import { Parser } from "../../parsers/scripting/Parser";
3 |
4 | /**
5 | * This function parses a parameter string and splits them into string literal and binding expression sections
6 | * @param source String to parse
7 | * @returns Parameter string sections
8 | */
9 | export function parseParameterString (source: string): (StringLiteralSection | ExpressionSection)[] {
10 | const result: (StringLiteralSection | ExpressionSection)[] = [];
11 | if (source === undefined || source === null) return result;
12 |
13 | let phase = ParsePhase.StringLiteral;
14 | let section = "";
15 | let escape = "";
16 | for (let i = 0; i < source.length; i++) {
17 | const ch = source[i];
18 | switch (phase) {
19 | case ParsePhase.StringLiteral:
20 | if (ch === "\\") {
21 | phase = ParsePhase.Escape;
22 | escape = "\\";
23 | } else if (ch === "{") {
24 | // --- A new expression starts, close the previous string literal
25 | if (section !== "") {
26 | result.push({
27 | type: "literal",
28 | value: section
29 | });
30 | }
31 | // --- Start a new section
32 | section = "";
33 | phase = ParsePhase.ExprStart;
34 | } else {
35 | section += ch;
36 | }
37 | break;
38 |
39 | case ParsePhase.Escape:
40 | if (ch === "\\") {
41 | // --- Go on with escape
42 | escape += ch;
43 | break;
44 | }
45 |
46 | if (ch === "{") {
47 | // --- End escape as a literal section without the first "\" escape character
48 | section += escape.substring(1) + ch;
49 | } else {
50 | // --- End escape as a literal section with the full sequence
51 | section += escape + ch;
52 | }
53 | phase = ParsePhase.StringLiteral;
54 | break;
55 |
56 | case ParsePhase.ExprStart:
57 | const exprSource = source.substring(i);
58 | const parser = new Parser(source.substring(i));
59 | let expr: Expression | null = null;
60 | try {
61 | expr = parser.parseExpr();
62 | } catch (err) {
63 | throw new Error(`Cannot parse expression: '${exprSource}': ${err}`);
64 | }
65 | const tail = parser.getTail();
66 | if (!tail || tail.trim().length < 1 || tail.trim()[0] !== "}") {
67 | // --- Unclosed expression, back to its beginning
68 | throw new Error(`Unclosed expression: '${source}'\n'${exprSource}'`);
69 | } else {
70 | // --- Successfully parsed expression
71 | result.push({
72 | type: "expression",
73 | value: expr!
74 | });
75 |
76 | // --- Skip the parsed part of the expression, and start a new literal section
77 | i = source.length - tail.length;
78 | section = "";
79 | }
80 | phase = ParsePhase.StringLiteral;
81 | break;
82 | }
83 | }
84 |
85 | // --- Process the last segment
86 | switch (phase) {
87 | case ParsePhase.StringLiteral:
88 | if (section !== "") {
89 | result.push({
90 | type: "literal",
91 | value: section
92 | });
93 | }
94 | break;
95 | case ParsePhase.Escape:
96 | result.push({
97 | type: "literal",
98 | value: section + escape
99 | });
100 | break;
101 | case ParsePhase.ExprStart:
102 | result.push({
103 | type: "literal",
104 | value: section + "{"
105 | });
106 | break;
107 | }
108 |
109 | // --- Done.
110 | return result;
111 | }
112 |
113 | enum ParsePhase {
114 | StringLiteral,
115 | Escape,
116 | ExprStart
117 | }
118 | /**
119 | * Represents a literal segment
120 | */
121 | type StringLiteralSection = {
122 | type: "literal";
123 |
124 | // --- The string literal
125 | value: string;
126 | };
127 |
128 | type ExpressionSection = {
129 | type: "expression";
130 |
131 | // --- The expression string to parse
132 | value: Expression;
133 | };
134 |
```
--------------------------------------------------------------------------------
/xmlui/src/components-core/theming/hvar.ts:
--------------------------------------------------------------------------------
```typescript
1 | export type HVar = {
2 | classes: Array<string>;
3 | attribute: string;
4 | component: string;
5 | traits: Array<string>;
6 | states: Array<string>;
7 | };
8 |
9 | const parsedHVarCache: Record<string, HVar | null> = {};
10 |
11 | //extremely dummy solution, will come back later
12 | export function parseHVar(input: string): HVar | null {
13 | if (parsedHVarCache[input] !== undefined) {
14 | return parsedHVarCache[input];
15 | }
16 | // Split the input string into parts using regex
17 | const parts = input.split(/-[A-Z]+/);
18 | if (parts.length !== 2) {
19 | parsedHVarCache[input] = null;
20 | return parsedHVarCache[input];
21 | }
22 |
23 | const firstPart = parts[0];
24 | const classessParts = firstPart.split(":");
25 | const attribute = classessParts[classessParts.length - 1];
26 | const classes = classessParts.length > 1 ? classessParts.slice(0, classessParts.length - 1) : [];
27 | const secondPart = input.substring(firstPart.length + 1);
28 | const [compName, ...rest] = secondPart.split("-");
29 | const traitsAndStates = secondPart.substring(compName.length).split("--");
30 |
31 | const states: Array<string> = [];
32 | const traits: Array<string> = [];
33 | traitsAndStates.forEach((part) => {
34 | if (!part.includes("-") && part) {
35 | states.push(part);
36 | } else {
37 | part.split("-").forEach((trait) => {
38 | if (trait) {
39 | traits.push(trait);
40 | }
41 | });
42 | }
43 | });
44 |
45 | parsedHVarCache[input] = {
46 | classes: classes,
47 | attribute: attribute,
48 | component: compName,
49 | traits: traits,
50 | states: states,
51 | };
52 |
53 | return parsedHVarCache[input];
54 | }
55 |
56 | function createCombinations(arr: Array<any> = []) {
57 | const stateCombinations = [];
58 |
59 | for (let i = 1; i <= arr.length; i++) {
60 | for (let j = 0; j <= arr.length - i; j++) {
61 | stateCombinations.push(arr.slice(j, j + i));
62 | }
63 | }
64 | return stateCombinations.sort((a, b) => b.length - a.length);
65 | }
66 |
67 | export type ThemeVarMatchResult = {
68 | forValue: string;
69 | matchedValue: string | undefined;
70 | from: Array<string>;
71 | };
72 |
73 | export function matchThemeVar(
74 | themeVar: string,
75 | availableThemeVars: Array<Record<string, string>> = []
76 | ): ThemeVarMatchResult | undefined {
77 | const hvar = parseHVar(themeVar);
78 | if (!hvar) {
79 | return;
80 | }
81 | const stateCombinations = createCombinations(hvar.states);
82 | const traitCombinations = createCombinations(hvar.traits);
83 |
84 | const sortedTraitCombinations: Array<string> = [];
85 | traitCombinations.forEach((traitComb) => {
86 | let result = "";
87 | traitComb.forEach((t) => {
88 | result = `${result}-${t}`;
89 | });
90 | sortedTraitCombinations.push(result);
91 | });
92 | sortedTraitCombinations.push("");
93 |
94 | const sortedStateCombinations: Array<string> = [];
95 | stateCombinations.forEach((stateComb) => {
96 | let result = "";
97 | stateComb.forEach((s) => {
98 | result = `${result}--${s}`;
99 | });
100 | sortedStateCombinations.push(result);
101 | });
102 | sortedStateCombinations.push("");
103 |
104 | const componentParts = [hvar.component, ...hvar.classes];
105 | const from: Array<string> = [];
106 | sortedStateCombinations.forEach((stateComb) => {
107 | sortedTraitCombinations.forEach((traitComb) => {
108 | componentParts.forEach((componentPart) => {
109 | from.push(`${hvar.attribute}-${componentPart}${traitComb}${stateComb}`);
110 | });
111 | });
112 | });
113 |
114 | let matchedValue;
115 | for (let i = availableThemeVars.length - 1; i >= 0; i--) {
116 | const themeVars = availableThemeVars[i];
117 | let foundValue = from.find((themeVar) => themeVars[themeVar] !== undefined);
118 | if (foundValue) {
119 | matchedValue = foundValue;
120 | break;
121 | }
122 | }
123 | const forValue = from[0];
124 | return {
125 | forValue: forValue,
126 | matchedValue: matchedValue,
127 | from: from,
128 | };
129 | }
130 |
```
--------------------------------------------------------------------------------
/xmlui/scripts/generate-docs/build-pages-map.mjs:
--------------------------------------------------------------------------------
```
1 | import { writeFileSync, statSync, readFileSync } from "fs";
2 | import { extname } from "path";
3 | import {
4 | gatherAndRemoveDuplicates,
5 | strBufferToLines,
6 | toHeadingPath,
7 | toNormalizedUpperCase,
8 | traverseDirectory,
9 | } from "./utils.mjs";
10 | import { createScopedLogger } from "./logging-standards.mjs";
11 | import {
12 | generateExportStatements,
13 | processDuplicatesWithLogging
14 | } from "./pattern-utilities.mjs";
15 | import { PAGES_MAP_CONFIG } from "./constants.mjs";
16 |
17 | const pathCutoff = PAGES_MAP_CONFIG.PATH_CUTOFF;
18 | const includedFileExtensions = PAGES_MAP_CONFIG.INCLUDED_FILE_EXTENSIONS;
19 |
20 | /**
21 | * Creates a file containing link constant variables to components/articles in the pages folder.
22 | * @param {string} pagesFolder The path to the pages folder (use UNIX delimiters)
23 | * @param {string} outFilePathAndName The path and name of the output file (use UNIX delimiters)
24 | */
25 | export function buildPagesMap(pagesFolder, outFilePathAndName) {
26 | const logger = createScopedLogger("PagesMapBuilder");
27 | logger.operationStart("building pages map");
28 | const pages = [];
29 | traverseDirectory({ name: "", path: pagesFolder }, (item, _) => {
30 | /**
31 | * name: the folder's/file's name (eg. "hello-app-engine")
32 | * path: the path to the root of the given folder from the project root (eg. "src/apps/1_basic/samples/hello-app-engine")
33 | * parent: parent node
34 | * children: children file/folder names
35 | */
36 | if (statSync(item.path).isDirectory()) {
37 | // Node is a folder
38 | } else {
39 | // Node is a file
40 | if (includedFileExtensions.includes(extname(item.name))) {
41 | const articleHeadings = getArticleIds(item);
42 | if (articleHeadings) {
43 | pages.push(...articleHeadings);
44 | }
45 | }
46 | }
47 | });
48 |
49 | const { filtered: filteredPages, duplicates } = gatherAndRemoveDuplicates(pages);
50 |
51 | // Process duplicates with standardized logging
52 | processDuplicatesWithLogging(duplicates, logger, "article IDs and paths");
53 |
54 | // Generate export statements using utility
55 | const pagesStr = generateExportStatements(filteredPages);
56 |
57 | writeFileSync(outFilePathAndName, pagesStr);
58 | }
59 |
60 | function getArticleIds(article) {
61 | const content = readFileSync(article.path, { encoding: "utf8" });
62 | const relativeArticlePath = article.path.split(pathCutoff)[1]?.replace(extname(article.name), "");
63 |
64 | const lines = strBufferToLines(content);
65 |
66 | const titleId = getTitleId(lines);
67 | if (!titleId) return null;
68 |
69 | const subHeadingIds = getSubHeadingIds(lines);
70 | return [
71 | { id: toNormalizedUpperCase(titleId), path: relativeArticlePath },
72 | ...subHeadingIds.map((id) => ({
73 | id: `${toNormalizedUpperCase(titleId)}_${toNormalizedUpperCase(id)}`,
74 | path: `${relativeArticlePath}#${toHeadingPath(id)}`,
75 | })),
76 | ];
77 |
78 | // ---
79 |
80 | function getTitleId(lines) {
81 | for (const line of lines) {
82 | const match = line.match(/^#\s+.+?\s*(\[#[\w-]+\])?$/);
83 | if (!match) continue;
84 | if (match[1]) {
85 | // Has ID, extract it and use that
86 | return match[1].replace(/\[#(.*?)\]/, (_, p1) => p1);
87 | } else {
88 | // Generate new ID from the heading title
89 | return match[0].slice(1);
90 | }
91 | }
92 | }
93 |
94 | function getSubHeadingIds(lines) {
95 | const headings = [];
96 | for (const line of lines) {
97 | // We only gather headings which have an explicit ID defined and they are not leveled as h1
98 | const match = line.match(/^##+\s+.+?\s*(\[#[\w-]+\])$/);
99 | if (!match) continue;
100 | if (!match[1]) continue;
101 | // Has ID, extract it and use that
102 | headings.push(match[1].replace(/\[#(.*?)\]/, (_, p1) => p1));
103 | }
104 | return headings;
105 | }
106 | }
107 |
```
--------------------------------------------------------------------------------
/packages/xmlui-website-blocks/src/HeroSection/HeroSection.module.scss:
--------------------------------------------------------------------------------
```scss
1 | @use "xmlui/themes.scss" as t;
2 |
3 | // --- This code snippet is required to collect the theme variables used in this module
4 | $themeVars: ();
5 | @function createThemeVar($componentVariable) {
6 | $themeVars: t.appendThemeVar($themeVars, $componentVariable) !global;
7 | @return t.getThemeVar($themeVars, $componentVariable);
8 | }
9 |
10 | $component: "HeroSection";
11 | $preamble: "preamble-#{$component}";
12 | $headline: "headline-#{$component}";
13 | $subheadline: "subheadline-#{$component}";
14 | $mainText: "mainText-#{$component}";
15 |
16 | $themeVars: t.composePaddingVars($themeVars, $component);
17 | $themeVars: t.composeTextVars($themeVars, $headline);
18 | $themeVars: t.composeTextVars($themeVars, $subheadline);
19 | $themeVars: t.composeTextVars($themeVars, $preamble);
20 | $themeVars: t.composeTextVars($themeVars, $mainText);
21 |
22 | @layer components {
23 | .heroWrapper {
24 | display: flex;
25 | flex-direction: column;
26 | position: relative;
27 | z-index: 0; // Create a stacking context to contain z-index values
28 | overflow: hidden; // Prevent background from extending beyond bounds
29 |
30 | .backgroundTemplate {
31 | position: absolute;
32 | top: 0;
33 | left: 0;
34 | right: 0;
35 | bottom: 0;
36 | z-index: -1; // Place behind content but within the hero wrapper's context
37 | }
38 |
39 | .heroContent {
40 | position: relative;
41 | z-index: 0; // Above background but within normal document flow
42 | display: flex;
43 | flex-direction: column;
44 | @include t.paddingVars($themeVars, $component);
45 | // --- Here, 2 * t.$space-4 accounts for the left and right padding of the page area
46 | width: calc(createThemeVar("maxWidth-content") - 2 * t.$space-4);
47 | margin: 0 auto; // Center horizontally within parent
48 |
49 | &.horizontal {
50 | flex-direction: row;
51 | align-items: flex-start;
52 | }
53 |
54 | &.vertical {
55 | flex-direction: column;
56 | }
57 | }
58 |
59 | .header {
60 | display: flex;
61 | flex-direction: column;
62 | }
63 |
64 | .content {
65 | display: flex;
66 | flex-direction: column;
67 | flex: 1;
68 |
69 | &.contentStart {
70 | align-items: flex-start;
71 | }
72 |
73 | &.contentCenter {
74 | align-items: center;
75 | }
76 |
77 | &.contentEnd {
78 | align-items: flex-end;
79 | }
80 | }
81 |
82 | .headingSection {
83 | display: flex;
84 | flex-direction: column;
85 |
86 | &.start {
87 | text-align: start;
88 | align-items: flex-start;
89 | }
90 |
91 | &.center {
92 | text-align: center;
93 | align-items: center;
94 | }
95 |
96 | &.end {
97 | text-align: end;
98 | align-items: flex-end;
99 | }
100 | }
101 | }
102 |
103 | .preamble {
104 | @include t.textVars($themeVars, $preamble);
105 | white-space: pre-wrap;
106 | display: inline-block;
107 | margin: 0;
108 | padding-bottom: createThemeVar("gap-#{$preamble}");
109 | }
110 |
111 | .headline {
112 | @include t.textVars($themeVars, $headline);
113 | white-space: pre-wrap;
114 | display: inline-block;
115 | margin: 0;
116 | padding-bottom: createThemeVar("gap-#{$headline}");
117 | }
118 |
119 | .subheadline {
120 | @include t.textVars($themeVars, $subheadline);
121 | white-space: pre-wrap;
122 | display: inline-block;
123 | margin: 0;
124 | padding-bottom: createThemeVar("gap-#{$subheadline}");
125 | }
126 |
127 | .textWrapper {
128 | display: flex;
129 | flex-direction: column;
130 | white-space: pre-wrap;
131 | padding-bottom: createThemeVar("gap-#{$mainText}");
132 | }
133 |
134 | .mainText {
135 | @include t.textVars($themeVars, $mainText);
136 | white-space: pre-wrap;
137 | display: inline-block;
138 | margin: 0;
139 | padding-bottom: createThemeVar("gap-#{$mainText}");
140 | }
141 |
142 | .ctaButtonWrapper {
143 | margin-top: t.$space-16;
144 | }
145 |
146 | .ctaButton {
147 | font-size: 1.5em;
148 | }
149 | }
150 |
151 | :export {
152 | themeVars: t.json-stringify($themeVars);
153 | }
154 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/DropdownMenu/DropdownMenu.md:
--------------------------------------------------------------------------------
```markdown
1 | %-DESC-START
2 |
3 | **Key features:**
4 | - **Hierarchical organization**: Supports nested submenus for complex menu structures
5 | - **Flexible triggers**: Customizable button trigger or use your own trigger component
6 | - **Progressive disclosure**: Reveals options on demand
7 |
8 | You can nest `MenuItem`, `MenuSeparator`, and `SubMenuItem` components into `DropdownMenu` to define a menu hierarchy. The component provides a trigger to display the menu items:
9 |
10 | ```xmlui-pg copy display name="Example: Using DropdownMenu" height="240px"
11 | ---app copy display
12 | <App>
13 | <DropdownMenu label="DropdownMenu">
14 | <MenuItem>Item 1</MenuItem>
15 | <MenuItem>Item 2</MenuItem>
16 | <MenuSeparator />
17 | <SubMenuItem label="Submenu">
18 | <MenuItem>Submenu Item 1</MenuItem>
19 | <MenuItem>Submenu Item 2</MenuItem>
20 | </SubMenuItem>
21 | </DropdownMenu>
22 | </App>
23 | ---desc
24 | Try this dropdown menu:
25 | ```
26 |
27 | %-DESC-END
28 |
29 | %-PROP-START alignment
30 |
31 | Available values are:
32 | - `start`: Menu items are aligned to the start of the trigger component (default).
33 | - `end`: Menu items are aligned to the end of the trigger component.
34 |
35 | ```xmlui-pg copy display name="Example: alignment" height="240px"
36 | <App>
37 | <HStack>
38 | <DropdownMenu label="Start-aligned menu (open it!)">
39 | <MenuItem>Item 1</MenuItem>
40 | <MenuItem>Item 2</MenuItem>
41 | <MenuItem>Item 3</MenuItem>
42 | </DropdownMenu>
43 | <DropdownMenu label="End-aligned menu (open it!)" alignment="end">
44 | <MenuItem>Item 1</MenuItem>
45 | <MenuItem>Item 2</MenuItem>
46 | <MenuItem>Item 3</MenuItem>
47 | </DropdownMenu>
48 | </HStack>
49 | </App>
50 | ```
51 |
52 | %-PROP-END
53 |
54 | %-PROP-START triggerTemplate
55 |
56 | ```xmlui-pg copy {3-5} display name="Example: triggerTemplate" height="240px"
57 | <App>
58 | <DropdownMenu label="(ignored)">
59 | <property name="triggerTemplate">
60 | <Button label="Custom trigger" icon="chevrondown" iconPosition="end"/>
61 | </property>
62 | <MenuItem>Item 1</MenuItem>
63 | <MenuItem>Item 2</MenuItem>
64 | <MenuItem>Item 3</MenuItem>
65 | </DropdownMenu>
66 | </App>
67 | ```
68 |
69 | %-PROP-END
70 |
71 | %-PROP-START enabled
72 |
73 | ```xmlui-pg copy {4, 11} display name="Example: enabled" height="240px"
74 | <App>
75 | <HStack>
76 | <DropdownMenu
77 | enabled="true"
78 | label="Enabled Dropdown">
79 | <MenuItem>Item 1</MenuItem>
80 | <MenuItem>Item 2</MenuItem>
81 | <MenuItem>Item 3</MenuItem>
82 | </DropdownMenu>
83 | <DropdownMenu
84 | enabled="false"
85 | label="Disabled Dropdown">
86 | <MenuItem>Item 1</MenuItem>
87 | <MenuItem>Item 2</MenuItem>
88 | <MenuItem>Item 3</MenuItem>
89 | </DropdownMenu>
90 | </HStack>
91 | </App>
92 | ```
93 |
94 | %-PROP-END
95 |
96 | %-EVENT-START willOpen
97 |
98 | ```xmlui-pg copy {6} display name="Example: willOpen" height="240px"
99 | <App>
100 | <variable name="counter" value="{0}" />
101 | <Text value="Number of times the dropdown was opened: {counter}" />
102 | <DropdownMenu
103 | label="Dropdown"
104 | onWillOpen="counter += 1">
105 | <MenuItem>Item 1</MenuItem>
106 | <MenuItem>Item 2</MenuItem>
107 | <MenuItem>Item 3</MenuItem>
108 | </DropdownMenu>
109 | </App>
110 | ```
111 |
112 | %-EVENT-END
113 |
114 | %-API-START close
115 |
116 | ```xmlui-pg copy {4} display name="Example: close" height="240px"
117 | <App>
118 | <DropdownMenu id="emojiDropdown" label="Emoji Dropdown">
119 | <EmojiSelector
120 | onSelect="(reaction) => { emojiDropdown.close(); }"
121 | autoFocus="true"
122 | />
123 | </DropdownMenu>
124 | </App>
125 | ```
126 |
127 | %-API-END
128 |
129 | %-API-START open
130 |
131 | ```xmlui-pg copy {2} display name="Example: open" height="300px"
132 | <App>
133 | <Button onClick="emojiDropdown.open()">Open the Dropdown</Button>
134 | <DropdownMenu id="emojiDropdown" label="Emoji Dropdown">
135 | <EmojiSelector
136 | onSelect="(reaction) => { emojiDropdown.close(); }"
137 | autoFocus="true"
138 | />
139 | </DropdownMenu>
140 | </App>
141 | ```
142 |
143 | %-API-END
144 |
```