#
tokens: 49509/50000 6/1633 files (page 58/190)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 58 of 190. Use http://codebase.md/xmlui-org/xmlui/xmlui/mockApiDef.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-optimized.yml
│       ├── deploy-blog-swa.yml
│       ├── deploy-blog.yml
│       ├── deploy-docs-optimized.yml
│       ├── deploy-docs-swa.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
│   ├── package.json
│   ├── public
│   │   ├── blog
│   │   │   ├── images
│   │   │   │   ├── an-advanced-codefence.gif
│   │   │   │   ├── an-advanced-codefence.mp4
│   │   │   │   ├── blog-page-component.png
│   │   │   │   ├── blog-scrabble.png
│   │   │   │   ├── codefence-runner.png
│   │   │   │   ├── integrated-blog-search.png
│   │   │   │   ├── lorem-ipsum.png
│   │   │   │   ├── playground-checkbox-source.png
│   │   │   │   ├── playground.png
│   │   │   │   ├── use-xmlui-mcp-to-find-a-howto.png
│   │   │   │   └── xmlui-demo-gallery.png
│   │   │   ├── introducing-xmlui.md
│   │   │   ├── lorem-ipsum.md
│   │   │   ├── newest-post.md
│   │   │   ├── older-post.md
│   │   │   ├── xmlui-playground.md
│   │   │   └── xmlui-powered-blog.md
│   │   ├── mockServiceWorker.js
│   │   ├── resources
│   │   │   ├── favicon.ico
│   │   │   ├── files
│   │   │   │   └── for-download
│   │   │   │       └── xmlui
│   │   │   │           └── xmlui-standalone.umd.js
│   │   │   ├── github.svg
│   │   │   ├── icons
│   │   │   │   ├── github.svg
│   │   │   │   └── rss.svg
│   │   │   ├── llms.txt
│   │   │   ├── logo-dark.svg
│   │   │   ├── logo.svg
│   │   │   ├── pg-popout.svg
│   │   │   ├── rss.svg
│   │   │   └── xmlui-logo.svg
│   │   ├── serve.json
│   │   ├── staticwebapp.config.json
│   │   └── web.config
│   ├── scripts
│   │   ├── download-latest-xmlui.js
│   │   ├── generate-rss.js
│   │   ├── get-releases.js
│   │   └── utils.js
│   ├── src
│   │   ├── components
│   │   │   ├── BlogOverview.xmlui
│   │   │   ├── BlogPage.xmlui
│   │   │   ├── LinkButton.xmlui
│   │   │   ├── PageNotFound.xmlui
│   │   │   └── Separator.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
│   │           ├── FancyButton.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
│   │   │   │   ├── control-cache-invalidation.md
│   │   │   │   ├── debounce-user-input-for-api-calls.md
│   │   │   │   ├── debounce-with-changelistener.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
│   │   │   ├── icons
│   │   │   │   ├── github.svg
│   │   │   │   └── rss.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
│   │   ├── staticwebapp.config.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
│   │   │   ├── LinkButton.xmlui
│   │   │   ├── NameValue.xmlui
│   │   │   ├── PageNotFound.xmlui
│   │   │   ├── PaletteItem.xmlui
│   │   │   ├── Palettes.xmlui
│   │   │   ├── SectionHeader.xmlui
│   │   │   ├── Separator.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
│   ├── tsconfig.json
│   ├── 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
│   ├── 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
│   │   └── 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
│   ├── 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
│   ├── 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
│   ├── 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.module.scss
│   │       │   ├── 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.tsx
│   │       │   ├── StandalonePlayground.tsx
│   │       │   ├── StandalonePlaygroundNative.module.scss
│   │       │   ├── StandalonePlaygroundNative.tsx
│   │       │   ├── ThemeSwitcher.module.scss
│   │       │   ├── ThemeSwitcher.tsx
│   │       │   └── utils.ts
│   │       ├── providers
│   │       │   ├── Toast.module.scss
│   │       │   └── ToastProvider.tsx
│   │       ├── state
│   │       │   └── store.ts
│   │       ├── themes
│   │       │   └── theme.ts
│   │       └── utils
│   │           └── helpers.ts
│   ├── 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
│   ├── xmlui-spreadsheet
│   │   ├── .gitignore
│   │   ├── demo
│   │   │   └── Main.xmlui
│   │   ├── index.html
│   │   ├── index.ts
│   │   ├── meta
│   │   │   └── componentsMetadata.ts
│   │   ├── package.json
│   │   └── src
│   │       ├── index.tsx
│   │       ├── Spreadsheet.tsx
│   │       └── SpreadsheetNative.tsx
│   └── 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.spec.ts
│           │   ├── HeroSection.tsx
│           │   └── HeroSectionNative.tsx
│           ├── index.tsx
│           ├── ScrollToTop
│           │   ├── ScrollToTop.module.scss
│           │   ├── ScrollToTop.tsx
│           │   └── ScrollToTopNative.tsx
│           └── vite-env.d.ts
├── playwright.config.ts
├── 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.cjs
    │   ├── 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
    │   ├── component-metadata.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
    │   ├── theme-variables-refactoring.md
    │   ├── ud-components.md
    │   └── xmlui-repo.md
    ├── package.json
    ├── scripts
    │   ├── coverage-only.js
    │   ├── e2e-test-summary.js
    │   ├── extract-component-metadata.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
    │   ├── generate-metadata-markdown.js
    │   ├── get-langserver-metadata.js
    │   ├── 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.module.scss
    │   │   │   │   ├── LabelList.spec.ts
    │   │   │   │   ├── LabelList.tsx
    │   │   │   │   └── 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
    │   │   │   └── test-padding.xmlui
    │   │   ├── 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.js
    │   ├── 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
    │   │   │   ├── index.ts
    │   │   │   ├── ModalDialogDriver.ts
    │   │   │   ├── NumberBoxDriver.ts
    │   │   │   ├── TextBoxDriver.ts
    │   │   │   ├── TimeInputDriver.ts
    │   │   │   ├── TimerDriver.ts
    │   │   │   └── TreeDriver.ts
    │   │   ├── fixtures.ts
    │   │   ├── index.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.json
    ├── tsdown.config.ts
    ├── vite.config.ts
    └── vitest.config.ts
```

# Files

--------------------------------------------------------------------------------
/docs/content/components/Slider.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Slider [#slider]
  2 | 
  3 | `Slider` provides an interactive control for selecting numeric values within a defined range, supporting both single value selection and range selection with multiple thumbs. It offers precise control through customizable steps and visual feedback with formatted value display.Hover over the component to see the tooltip with the current value. On mobile, tap the thumb to see the tooltip.
  4 | 
  5 | **Key features:**
  6 | - **Range selection**: Single value or dual-thumb range selection with configurable minimum separation
  7 | - **Step control**: Precise incremental selection with customizable step values
  8 | - **Value formatting**: Custom display formatting for current values and visual feedback
  9 | 
 10 | ## Properties [#properties]
 11 | 
 12 | ### `autoFocus` (default: false) [#autofocus-default-false]
 13 | 
 14 | If this property is set to `true`, the component gets the focus automatically when displayed.
 15 | 
 16 | ### `enabled` (default: true) [#enabled-default-true]
 17 | 
 18 | This boolean property value indicates whether the component responds to user events (`true`) or not (`false`).
 19 | 
 20 | ### `initialValue` [#initialvalue]
 21 | 
 22 | This property sets the component's initial value.
 23 | 
 24 | ```xmlui-pg
 25 | <Slider initialValue="5" />
 26 | ```
 27 | 
 28 | ### `maxValue` (default: 10) [#maxvalue-default-10]
 29 | 
 30 | This property specifies the maximum value of the allowed input range.
 31 | 
 32 | ```xmlui-pg
 33 | <Slider maxValue="30" />
 34 | ```
 35 | 
 36 | ### `minStepsBetweenThumbs` (default: 1) [#minstepsbetweenthumbs-default-1]
 37 | 
 38 | This property sets the minimum number of steps required between multiple thumbs on the slider, ensuring they maintain a specified distance.
 39 | 
 40 | ### `minValue` (default: 0) [#minvalue-default-0]
 41 | 
 42 | This property specifies the minimum value of the allowed input range.
 43 | 
 44 | ```xmlui-pg
 45 | <Slider minValue="10" />
 46 | ```
 47 | 
 48 | ### `rangeStyle` [#rangestyle]
 49 | 
 50 | This optional property allows you to apply custom styles to the range element of the slider.
 51 | 
 52 | ### `readOnly` (default: false) [#readonly-default-false]
 53 | 
 54 | Set this property to `true` to disallow changing the component value.
 55 | 
 56 | ### `required` (default: false) [#required-default-false]
 57 | 
 58 | Set this property to `true` to indicate it must have a value before submitting the containing form.
 59 | 
 60 | ### `showValues` (default: true) [#showvalues-default-true]
 61 | 
 62 | This property controls whether the slider shows the current values of the thumbs.
 63 | 
 64 | ### `step` (default: 1) [#step-default-1]
 65 | 
 66 | This property defines the increment value for the slider, determining the allowed intervals between selectable values.
 67 | 
 68 | ### `thumbStyle` [#thumbstyle]
 69 | 
 70 | This optional property allows you to apply custom styles to the thumb elements of the slider.
 71 | 
 72 | ### `validationStatus` (default: "none") [#validationstatus-default-none]
 73 | 
 74 | This property allows you to set the validation status of the input component.
 75 | 
 76 | Available values:
 77 | 
 78 | | Value | Description |
 79 | | --- | --- |
 80 | | `valid` | Visual indicator for an input that is accepted |
 81 | | `warning` | Visual indicator for an input that produced a warning |
 82 | | `error` | Visual indicator for an input that produced an error |
 83 | 
 84 | ### `valueFormat` (default: "(value) => value.toString()") [#valueformat-default-value-value-tostring]
 85 | 
 86 | This property allows you to customize how the values are displayed.
 87 | 
 88 | ## Events [#events]
 89 | 
 90 | ### `didChange` [#didchange]
 91 | 
 92 | This event is triggered when value of Slider has changed.
 93 | 
 94 | ### `gotFocus` [#gotfocus]
 95 | 
 96 | This event is triggered when the Slider has received the focus.
 97 | 
 98 | ### `lostFocus` [#lostfocus]
 99 | 
100 | This event is triggered when the Slider has lost the focus.
101 | 
102 | ## Exposed Methods [#exposed-methods]
103 | 
104 | ### `focus` [#focus]
105 | 
106 | This method sets the focus on the slider component.
107 | 
108 | **Signature**: `focus(): void`
109 | 
110 | ### `setValue` [#setvalue]
111 | 
112 | This API sets the value of the `Slider`. You can use it to programmatically change the value.
113 | 
114 | **Signature**: `setValue(value: number | [number, number] | undefined): void`
115 | 
116 | - `value`: The new value to set. Can be a single value or an array of values for range sliders.
117 | 
118 | ### `value` [#value]
119 | 
120 | This API retrieves the current value of the `Slider`. You can use it to get the value programmatically.
121 | 
122 | **Signature**: `get value(): number | [number, number] | undefined`
123 | 
124 | ## Styling [#styling]
125 | 
126 | ### Theme Variables [#theme-variables]
127 | 
128 | | Variable | Default Value (Light) | Default Value (Dark) |
129 | | --- | --- | --- |
130 | | [backgroundColor](../styles-and-themes/common-units/#color)-range-Slider | $color-primary | $color-primary |
131 | | [backgroundColor](../styles-and-themes/common-units/#color)-range-Slider | $color-primary | $color-primary |
132 | | [backgroundColor](../styles-and-themes/common-units/#color)-range-Slider--disabled | $color-surface-400 | $color-surface-800 |
133 | | [backgroundColor](../styles-and-themes/common-units/#color)-range-Slider--disabled | $color-surface-400 | $color-surface-800 |
134 | | [backgroundColor](../styles-and-themes/common-units/#color)-thumb-Slider | $color-primary-500 | $color-primary-400 |
135 | | [backgroundColor](../styles-and-themes/common-units/#color)-thumb-Slider | $color-primary-500 | $color-primary-400 |
136 | | [backgroundColor](../styles-and-themes/common-units/#color)-thumb-Slider--active | $color-primary-400 | $color-primary-400 |
137 | | [backgroundColor](../styles-and-themes/common-units/#color)-thumb-Slider--active | $color-primary-400 | $color-primary-400 |
138 | | [backgroundColor](../styles-and-themes/common-units/#color)-thumb-Slider--focus | $color-primary | $color-primary |
139 | | [backgroundColor](../styles-and-themes/common-units/#color)-thumb-Slider--focus | $color-primary | $color-primary |
140 | | [backgroundColor](../styles-and-themes/common-units/#color)-thumb-Slider--hover | $color-primary | $color-primary |
141 | | [backgroundColor](../styles-and-themes/common-units/#color)-thumb-Slider--hover | $color-primary | $color-primary |
142 | | [backgroundColor](../styles-and-themes/common-units/#color)-track-Slider | $color-surface-200 | $color-surface-200 |
143 | | [backgroundColor](../styles-and-themes/common-units/#color)-track-Slider | $color-surface-200 | $color-surface-200 |
144 | | [backgroundColor](../styles-and-themes/common-units/#color)-track-Slider--disabled | $color-surface-300 | $color-surface-600 |
145 | | [backgroundColor](../styles-and-themes/common-units/#color)-track-Slider--disabled | $color-surface-300 | $color-surface-600 |
146 | | [borderColor](../styles-and-themes/common-units/#color)-Slider--default | transparent | transparent |
147 | | [borderColor](../styles-and-themes/common-units/#color)-Slider--default | transparent | transparent |
148 | | [borderColor](../styles-and-themes/common-units/#color)-Slider--default--focus | *none* | *none* |
149 | | [borderColor](../styles-and-themes/common-units/#color)-Slider--default--hover | *none* | *none* |
150 | | [borderColor](../styles-and-themes/common-units/#color)-Slider--error | *none* | *none* |
151 | | [borderColor](../styles-and-themes/common-units/#color)-Slider--error--focus | *none* | *none* |
152 | | [borderColor](../styles-and-themes/common-units/#color)-Slider--error--hover | *none* | *none* |
153 | | [borderColor](../styles-and-themes/common-units/#color)-Slider--success | *none* | *none* |
154 | | [borderColor](../styles-and-themes/common-units/#color)-Slider--success--focus | *none* | *none* |
155 | | [borderColor](../styles-and-themes/common-units/#color)-Slider--success--hover | *none* | *none* |
156 | | [borderColor](../styles-and-themes/common-units/#color)-Slider--warning | *none* | *none* |
157 | | [borderColor](../styles-and-themes/common-units/#color)-Slider--warning--focus | *none* | *none* |
158 | | [borderColor](../styles-and-themes/common-units/#color)-Slider--warning--hover | *none* | *none* |
159 | | [borderColor](../styles-and-themes/common-units/#color)-thumb-Slider | $color-surface-50 | $color-surface-950 |
160 | | [borderColor](../styles-and-themes/common-units/#color)-thumb-Slider | $color-surface-50 | $color-surface-950 |
161 | | [borderRadius](../styles-and-themes/common-units/#border-rounding)-Slider--default | $borderRadius | $borderRadius |
162 | | [borderRadius](../styles-and-themes/common-units/#border-rounding)-Slider--default | $borderRadius | $borderRadius |
163 | | [borderRadius](../styles-and-themes/common-units/#border-rounding)-Slider--error | *none* | *none* |
164 | | [borderRadius](../styles-and-themes/common-units/#border-rounding)-Slider--success | *none* | *none* |
165 | | [borderRadius](../styles-and-themes/common-units/#border-rounding)-Slider--warning | *none* | *none* |
166 | | [borderStyle](../styles-and-themes/common-units/#border-style)-Slider--default | solid | solid |
167 | | [borderStyle](../styles-and-themes/common-units/#border-style)-Slider--default | solid | solid |
168 | | [borderStyle](../styles-and-themes/common-units/#border-style)-Slider--error | *none* | *none* |
169 | | [borderStyle](../styles-and-themes/common-units/#border-style)-Slider--success | *none* | *none* |
170 | | [borderStyle](../styles-and-themes/common-units/#border-style)-Slider--warning | *none* | *none* |
171 | | [borderStyle](../styles-and-themes/common-units/#border-style)-thumb-Slider | solid | solid |
172 | | [borderStyle](../styles-and-themes/common-units/#border-style)-thumb-Slider | solid | solid |
173 | | [borderWidth](../styles-and-themes/common-units/#size)-Slider--default | 0 | 0 |
174 | | [borderWidth](../styles-and-themes/common-units/#size)-Slider--default | 0 | 0 |
175 | | [borderWidth](../styles-and-themes/common-units/#size)-Slider--error | *none* | *none* |
176 | | [borderWidth](../styles-and-themes/common-units/#size)-Slider--success | *none* | *none* |
177 | | [borderWidth](../styles-and-themes/common-units/#size)-Slider--warning | *none* | *none* |
178 | | [borderWidth](../styles-and-themes/common-units/#size)-thumb-Slider | 2px | 2px |
179 | | [borderWidth](../styles-and-themes/common-units/#size)-thumb-Slider | 2px | 2px |
180 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Slider--default | none | none |
181 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Slider--default | none | none |
182 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Slider--default--focus | *none* | *none* |
183 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Slider--default--hover | *none* | *none* |
184 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Slider--error | *none* | *none* |
185 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Slider--error--focus | *none* | *none* |
186 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Slider--error--hover | *none* | *none* |
187 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Slider--success | *none* | *none* |
188 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Slider--success--focus | *none* | *none* |
189 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Slider--success--hover | *none* | *none* |
190 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Slider--warning | *none* | *none* |
191 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Slider--warning--focus | *none* | *none* |
192 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Slider--warning--hover | *none* | *none* |
193 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-thumb-Slider | *none* | *none* |
194 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-thumb-Slider--active | 0 0 0 6px rgb(from $color-primary r g b / 0.4) | 0 0 0 6px rgb(from $color-primary r g b / 0.4) |
195 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-thumb-Slider--active | 0 0 0 6px rgb(from $color-primary r g b / 0.4) | 0 0 0 6px rgb(from $color-primary r g b / 0.4) |
196 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-thumb-Slider--focus | 0 0 0 6px rgb(from $color-primary r g b / 0.4) | 0 0 0 6px rgb(from $color-primary r g b / 0.4) |
197 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-thumb-Slider--focus | 0 0 0 6px rgb(from $color-primary r g b / 0.4) | 0 0 0 6px rgb(from $color-primary r g b / 0.4) |
198 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-thumb-Slider--hover | 0 0 0 6px rgb(from $color-primary r g b / 0.4) | 0 0 0 6px rgb(from $color-primary r g b / 0.4) |
199 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-thumb-Slider--hover | 0 0 0 6px rgb(from $color-primary r g b / 0.4) | 0 0 0 6px rgb(from $color-primary r g b / 0.4) |
200 | 
```

--------------------------------------------------------------------------------
/xmlui/bin/build.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | 
  3 | import { cp, mkdir, rm, writeFile } from "fs/promises";
  4 | import * as dotenv from "dotenv";
  5 | import { existsSync } from "fs";
  6 | import * as glob from "glob";
  7 | import type { InlineConfig } from "vite";
  8 | import { build as viteBuild } from "vite";
  9 | import { getViteConfig } from "./viteConfig";
 10 | import * as fs from "node:fs";
 11 | 
 12 | type ApiInterceptorDefinition = any;
 13 | type CompoundComponentDef = any;
 14 | type ThemeDefinition = any;
 15 | 
 16 | // --- Set up the configuration
 17 | dotenv.config({ path: `${process.cwd()}/.env` });
 18 | dotenv.config({ path: `${process.cwd()}/.env.local`, override: true });
 19 | 
 20 | type StandaloneJsonConfig = {
 21 |   name: string;
 22 |   appGlobals?: Record<string, any>;
 23 |   entryPoint?: string;
 24 |   components?: string[];
 25 |   themes?: string[];
 26 |   defaultTheme?: string;
 27 |   resources?: Record<string, string>;
 28 |   apiInterceptor?: ApiInterceptorDefinition;
 29 |   resourceMap?: Record<string, string>;
 30 | };
 31 | 
 32 | async function getExportedJsObjects<T>(path: string): Promise<Array<T>> {
 33 |   return await new Promise((resolve, reject) => {
 34 |     glob.glob(`${process.cwd()}/${path}`, (err: any, matches = []) => {
 35 |       const modules = Promise.all(
 36 |         matches.map(async (file: string) => {
 37 |           return (await import(file)).default;
 38 |         })
 39 |       );
 40 |       resolve(modules);
 41 |     });
 42 |   });
 43 | }
 44 | 
 45 | async function convertResourcesDir(distRoot: string, flatDist: boolean, filePrefix: string) {
 46 |   if (!flatDist) {
 47 |     return undefined;
 48 |   }
 49 |   distRoot = distRoot.replaceAll("\\", "/");
 50 |   const resourcesDir = `${distRoot}/resources`;
 51 |   if (!existsSync(resourcesDir)) {
 52 |     return undefined;
 53 |   }
 54 |   const files = await new Promise<string[]>((resolve, reject) => {
 55 |     glob.glob(`${resourcesDir}/**/*`, (err: any, matches = []) => {
 56 |       resolve(matches);
 57 |     });
 58 |   });
 59 | 
 60 |   const ret: Record<string, string> = {};
 61 |   for (let i = 0; i < files.length; i++) {
 62 |     const file = files[i];
 63 |     if (fs.statSync(file).isDirectory()) {
 64 |       continue;
 65 |     }
 66 |     const relativePath = file.replace(`${distRoot}/`, "");
 67 |     const convertedResource = `${filePrefix}${relativePath.replaceAll("/", "_")}`;
 68 | 
 69 |     await cp(file, `${distRoot}/${convertedResource}`);
 70 |     ret[relativePath] = convertedResource;
 71 |   }
 72 |   return ret;
 73 | }
 74 | 
 75 | export function removeLeadingSlashForPath(path: string): string {
 76 |   if (path.startsWith("/")) {
 77 |     return path.substring(1);
 78 |   }
 79 |   return path;
 80 | }
 81 | 
 82 | type UEBuildOptions = {
 83 |   buildMode?: "CONFIG_ONLY" | "INLINE_ALL" | "ALL";
 84 |   flatDist?: boolean;
 85 |   withMock?: boolean;
 86 |   withHostingMetaFiles?: boolean;
 87 |   withRelativeRoot?: boolean;
 88 | };
 89 | 
 90 | export const build = async ({
 91 |   buildMode = "CONFIG_ONLY",
 92 |   flatDist = false,
 93 |   withMock = false,
 94 |   withHostingMetaFiles = false,
 95 |   withRelativeRoot = false,
 96 | }: UEBuildOptions) => {
 97 |   const flatDistUiPrefix = "ui_";
 98 |   console.log("Building with options:", {
 99 |     buildMode,
100 |     flatDist,
101 |     withMock,
102 |     withHostingMetaFiles,
103 |     withRelativeRoot,
104 |   });
105 | 
106 |   await viteBuild({
107 |     ...(await getViteConfig({
108 |       flatDist,
109 |       withRelativeRoot,
110 |       flatDistUiPrefix,
111 |     })),
112 |     define: {
113 |       "process.env.VITE_BUILD_MODE": JSON.stringify(buildMode),
114 |       "process.env.VITE_DEV_MODE": false,
115 |       "process.env.VITE_MOCK_ENABLED": withMock,
116 |       "process.env.VITE_APP_VERSION": JSON.stringify(process.env.VITE_APP_VERSION),
117 | 
118 |       "process.env.VITE_USED_COMPONENTS_App": JSON.stringify(process.env.VITE_USED_COMPONENTS_App),
119 |       "process.env.VITE_USED_COMPONENTS_Chart": JSON.stringify(process.env.VITE_USED_COMPONENTS_Chart),
120 |       "process.env.VITE_USED_COMPONENTS_AppHeader": JSON.stringify(process.env.VITE_USED_COMPONENTS_AppHeader),
121 |       "process.env.VITE_USED_COMPONENTS_Stack": JSON.stringify(process.env.VITE_USED_COMPONENTS_Stack),
122 |       "process.env.VITE_USED_COMPONENTS_Link": JSON.stringify(process.env.VITE_USED_COMPONENTS_Link),
123 |       "process.env.VITE_USED_COMPONENTS_Text": JSON.stringify(process.env.VITE_USED_COMPONENTS_Text),
124 |       "process.env.VITE_USED_COMPONENTS_Button": JSON.stringify(process.env.VITE_USED_COMPONENTS_Button),
125 |       "process.env.VITE_USED_COMPONENTS_Card": JSON.stringify(process.env.VITE_USED_COMPONENTS_Card),
126 |       "process.env.VITE_USED_COMPONENTS_Image": JSON.stringify(process.env.VITE_USED_COMPONENTS_Image),
127 |       "process.env.VITE_USED_COMPONENTS_Footer": JSON.stringify(process.env.VITE_USED_COMPONENTS_Footer),
128 |       "process.env.VITE_USED_COMPONENTS_SpaceFiller": JSON.stringify(process.env.VITE_USED_COMPONENTS_SpaceFiller),
129 |       "process.env.VITE_USED_COMPONENTS_Pdf": JSON.stringify(process.env.VITE_USED_COMPONENTS_Pdf),
130 |       "process.env.VITE_USED_COMPONENTS_Textarea": JSON.stringify(process.env.VITE_USED_COMPONENTS_Textarea),
131 |       "process.env.VITE_USED_COMPONENTS_Logo": JSON.stringify(process.env.VITE_USED_COMPONENTS_Logo),
132 |       "process.env.VITE_USED_COMPONENTS_NavLink": JSON.stringify(process.env.VITE_USED_COMPONENTS_NavLink),
133 |       "process.env.VITE_USED_COMPONENTS_NavGroup": JSON.stringify(process.env.VITE_USED_COMPONENTS_NavGroup),
134 |       "process.env.VITE_USED_COMPONENTS_Form": JSON.stringify(process.env.VITE_USED_COMPONENTS_Form),
135 |       "process.env.VITE_USED_COMPONENTS_Tree": JSON.stringify(process.env.VITE_USED_COMPONENTS_Tree),
136 |       "process.env.VITE_USED_COMPONENTS_Checkbox": JSON.stringify(process.env.VITE_USED_COMPONENTS_Checkbox),
137 |       "process.env.VITE_USED_COMPONENTS_Switch": JSON.stringify(process.env.VITE_USED_COMPONENTS_Switch),
138 |       "process.env.VITE_USED_COMPONENTS_DotMenu": JSON.stringify(process.env.VITE_USED_COMPONENTS_DotMenu),
139 |       "process.env.VITE_USED_COMPONENTS_Heading": JSON.stringify(process.env.VITE_USED_COMPONENTS_Heading),
140 |       "process.env.VITE_USED_COMPONENTS_Fragment": JSON.stringify(process.env.VITE_USED_COMPONENTS_Fragment),
141 |       "process.env.VITE_USED_COMPONENTS_Table": JSON.stringify(process.env.VITE_USED_COMPONENTS_Table),
142 |       "process.env.VITE_USED_COMPONENTS_List": JSON.stringify(process.env.VITE_USED_COMPONENTS_List),
143 |       "process.env.VITE_USED_COMPONENTS_XmluiCodeHightlighter": JSON.stringify(process.env.VITE_USED_COMPONENTS_XmluiCodeHightlighter),
144 |       "process.env.VITE_USED_COMPONENTS_Charts": JSON.stringify(process.env.VITE_USED_COMPONENTS_Charts),
145 |       "process.env.VITE_INCLUDE_HTML_COMPONENTS": JSON.stringify(process.env.VITE_INCLUDE_HTML_COMPONENTS),
146 |       "process.env.VITE_USED_COMPONENTS_DatePicker": JSON.stringify(process.env.VITE_USED_COMPONENTS_DatePicker),
147 |       "process.env.VITE_USED_COMPONENTS_NavPanel": JSON.stringify(process.env.VITE_USED_COMPONENTS_NavPanel),
148 |       "process.env.VITE_USED_COMPONENTS_Pages": JSON.stringify(process.env.VITE_USED_COMPONENTS_Pages),
149 |       "process.env.VITE_USED_COMPONENTS_StickyBox": JSON.stringify(process.env.VITE_USED_COMPONENTS_StickyBox),
150 |       "process.env.VITE_USED_COMPONENTS_Badge": JSON.stringify(process.env.VITE_USED_COMPONENTS_Badge),
151 |       "process.env.VITE_USED_COMPONENTS_Avatar": JSON.stringify(process.env.VITE_USED_COMPONENTS_Avatar),
152 |       "process.env.VITE_USED_COMPONENTS_ContentSeparator": JSON.stringify(
153 |         process.env.VITE_USED_COMPONENTS_ContentSeparator
154 |       ),
155 |       "process.env.VITE_USED_COMPONENTS_FlowLayout": JSON.stringify(process.env.VITE_USED_COMPONENTS_FlowLayout),
156 |       "process.env.VITE_USED_COMPONENTS_ModalDialog": JSON.stringify(process.env.VITE_USED_COMPONENTS_ModalDialog),
157 |       "process.env.VITE_USED_COMPONENTS_NoResult": JSON.stringify(process.env.VITE_USED_COMPONENTS_NoResult),
158 |       "process.env.VITE_USED_COMPONENTS_Option": JSON.stringify(process.env.VITE_USED_COMPONENTS_Option),
159 |       "process.env.VITE_USED_COMPONENTS_FileUploadDropZone": JSON.stringify(
160 |         process.env.VITE_USED_COMPONENTS_FileUploadDropZone
161 |       ),
162 |       "process.env.VITE_USED_COMPONENTS_Icon": JSON.stringify(process.env.VITE_USED_COMPONENTS_Icon),
163 |       "process.env.VITE_USED_COMPONENTS_Items": JSON.stringify(process.env.VITE_USED_COMPONENTS_Items),
164 |       "process.env.VITE_USED_COMPONENTS_SelectionStore": JSON.stringify(
165 |         process.env.VITE_USED_COMPONENTS_SelectionStore
166 |       ),
167 |       "process.env.VITE_INCLUDE_REST_COMPONENTS": JSON.stringify(process.env.VITE_INCLUDE_REST_COMPONENTS),
168 |       "process.env.VITE_USED_COMPONENTS_EmojiSelector": JSON.stringify(process.env.VITE_USED_COMPONENTS_EmojiSelector),
169 |     },
170 |   } as InlineConfig);
171 | 
172 |   if (buildMode === "INLINE_ALL") {
173 |     return;
174 |   }
175 |   const distPath = "/dist";
176 |   const themesFolder = flatDist ? "" : "themes";
177 |   const componentsFolder = flatDist ? "" : "components";
178 |   const themesFolderPath = flatDist ? distPath : `${distPath}/${themesFolder}`;
179 |   const componentsFolderPath = flatDist ? distPath : `${distPath}/${componentsFolder}`;
180 | 
181 |   function getThemeFileName(theme: ThemeDefinition) {
182 |     return flatDist ? `${flatDistUiPrefix}theme_${theme.id}` : theme.id;
183 |   }
184 | 
185 |   function getComponentFileName(component: CompoundComponentDef) {
186 |     return flatDist ? `${flatDistUiPrefix}component_${component.name}` : component.name;
187 |   }
188 | 
189 |   function getEntrypointFileName() {
190 |     return flatDist ? `${flatDistUiPrefix}entrypoint` : `app`;
191 |   }
192 | 
193 |   if (buildMode === "CONFIG_ONLY") {
194 |     let appDef;
195 |     try {
196 |       appDef = (await import(process.cwd() + "/src/config")).default;
197 |     } catch (e) {
198 |       console.log("couldn't find config");
199 |     }
200 | 
201 |     const themePaths: string[] = [];
202 |     const themes = await getExportedJsObjects<ThemeDefinition>("/src/themes/**.*");
203 |     const fullDistPath = `${process.cwd()}${distPath}`;
204 |     if (themes) {
205 |       for (const theme of themes) {
206 |         if (!existsSync(process.cwd() + themesFolderPath)) {
207 |           await mkdir(process.cwd() + themesFolderPath, { recursive: true });
208 |         }
209 |         await writeFile(
210 |           `${process.cwd()}${themesFolderPath}/${getThemeFileName(theme)}.json`,
211 |           JSON.stringify(theme, null, 4)
212 |         );
213 |         themePaths.push(removeLeadingSlashForPath(`${themesFolder}/${getThemeFileName(theme)}.json`));
214 |       }
215 |     }
216 | 
217 |     const configJson: StandaloneJsonConfig = {
218 |       ...appDef,
219 |       resourceMap: await convertResourcesDir(fullDistPath, flatDist, flatDistUiPrefix),
220 |       themes: themePaths,
221 |     };
222 |     delete configJson["components"];
223 |     delete configJson["entryPoint"];
224 |     if (!withMock) {
225 |       delete configJson.apiInterceptor;
226 |     }
227 |     await writeFile(`${process.cwd()}${distPath}/config.json`, JSON.stringify(configJson, null, 4));
228 |   } else if (buildMode === "ALL") {
229 |     // const componentPaths: string[] = [];
230 |     //   const components = await getExportedJsObjects<CompoundComponentDef>("/src/components/**.*");
231 |     //   if (components) {
232 |     //     for (const component of components) {
233 |     //       if (!existsSync(`${process.cwd()}${componentsFolderPath}`)) {
234 |     //         await mkdir(`${process.cwd()}${componentsFolderPath}`, { recursive: true });
235 |     //       }
236 |     //       await writeFile(
237 |     //           `${process.cwd()}${componentsFolderPath}/${getComponentFileName(component)}.json`,
238 |     //           JSON.stringify(component, null, 4)
239 |     //       );
240 |     //       componentPaths.push(removeLeadingSlashForPath(`${componentsFolder}/${getComponentFileName(component)}.json`));
241 |     //     }
242 |     //   }
243 |     //
244 |     // await writeFile(
245 |     //   `${process.cwd()}${distPath}/${getEntrypointFileName()}.json`,
246 |     //   JSON.stringify(appDef.entryPoint, null, 4)
247 |     // );
248 |     //
249 |     // configJson = {
250 |     //   ...configJson,
251 |     //   entryPoint: `${getEntrypointFileName()}.json`,
252 |     //   components: componentPaths,
253 |     // };
254 |   }
255 | 
256 |   //TODO temp, we should enforce user(who writes the metadata)-added-resources to be put in the resources folder
257 |   if (flatDist) {
258 |     await rm(`${process.cwd()}${distPath}/resources`, { recursive: true, force: true });
259 |   }
260 |   if (!withMock) {
261 |     try {
262 |       await rm(`${process.cwd()}${distPath}/mockServiceWorker.js`);
263 |     } catch (ignored) {}
264 |   }
265 |   if (!withHostingMetaFiles) {
266 |     try {
267 |       await rm(`${process.cwd()}${distPath}/serve.json`);
268 |     } catch (ignored) {}
269 | 
270 |     try {
271 |       await rm(`${process.cwd()}${distPath}/web.config`);
272 |     } catch (ignored) {}
273 |     try {
274 |       await rm(`${process.cwd()}${distPath}/_redirects`);
275 |     } catch (ignored) {}
276 |   }
277 | };
278 | 
```

--------------------------------------------------------------------------------
/xmlui/src/components/Text/TextNative.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | import type { CSSProperties } from "react";
  2 | import type React from "react";
  3 | import { forwardRef, useMemo, useRef, useCallback, useEffect, memo } from "react";
  4 | import { composeRefs } from "@radix-ui/react-compose-refs";
  5 | import classnames from "classnames";
  6 | 
  7 | import styles from "./Text.module.scss";
  8 | 
  9 | import { getMaxLinesStyle } from "../../components-core/utils/css-utils";
 10 | import {
 11 |   type BreakMode,
 12 |   type OverflowMode,
 13 |   type TextVariant,
 14 |   TextVariantElement,
 15 | } from "../abstractions";
 16 | import type { RegisterComponentApiFn } from "../..";
 17 | import { useComponentStyle } from "../../components-core/theming/StyleContext";
 18 | import { EMPTY_OBJECT } from "../../components-core/constants";
 19 | import { toCssVar } from "../../components-core/theming/layout-resolver";
 20 | 
 21 | // =============================================================================
 22 | // Custom Variant CSS Cache Infrastructure
 23 | // =============================================================================
 24 | 
 25 | /**
 26 |  * Cached CSS information for a custom variant.
 27 |  */
 28 | interface CustomVariantCacheEntry {
 29 |   /** The generated CSS class name for this variant */
 30 |   className: string;
 31 |   /** The CSS text content that defines the styles for this variant */
 32 |   cssText: string;
 33 |   /** Timestamp when this entry was created (for debugging/cleanup) */
 34 |   createdAt: number;
 35 | }
 36 | 
 37 | /**
 38 |  * Global cache that stores custom variant CSS styles.
 39 |  * Key: variant value (string)
 40 |  *
 41 |  * This cache ensures the same variant value always generates the same CSS.
 42 |  */
 43 | const customVariantCache = new Map<string, CustomVariantCacheEntry>();
 44 | 
 45 | /**
 46 |  * Retrieves a cached custom variant entry if it exists.
 47 |  */
 48 | export function getCustomVariantCache(
 49 |   variant: string,
 50 | ): CustomVariantCacheEntry | undefined {
 51 |   return customVariantCache.get(variant);
 52 | }
 53 | 
 54 | /**
 55 |  * Stores a custom variant entry in the cache.
 56 |  */
 57 | export function setCustomVariantCache(
 58 |   variant: string,
 59 |   entry: Omit<CustomVariantCacheEntry, "createdAt">,
 60 | ): void {
 61 |   customVariantCache.set(variant, {
 62 |     ...entry,
 63 |     createdAt: Date.now(),
 64 |   });
 65 | }
 66 | 
 67 | /**
 68 |  * Checks if a custom variant is already cached.
 69 |  */
 70 | export function hasCustomVariantCache(variant: string): boolean {
 71 |   return customVariantCache.has(variant);
 72 | }
 73 | 
 74 | /**
 75 |  * Clears the entire custom variant cache.
 76 |  * Useful for testing or full app resets.
 77 |  */
 78 | export function clearCustomVariantCache(): void {
 79 |   customVariantCache.clear();
 80 | }
 81 | 
 82 | /**
 83 |  * Gets cache statistics for debugging.
 84 |  */
 85 | export function getCustomVariantCacheStats() {
 86 |   return {
 87 |     totalEntries: customVariantCache.size,
 88 |     entries: Array.from(customVariantCache.entries()).map(([key, entry]) => ({
 89 |       key,
 90 |       className: entry.className,
 91 |       createdAt: new Date(entry.createdAt).toISOString(),
 92 |     })),
 93 |   };
 94 | }
 95 | 
 96 | // =============================================================================
 97 | // Component Definition
 98 | // =============================================================================
 99 | 
100 | type TextProps = {
101 |   uid?: string;
102 |   children?: React.ReactNode;
103 |   variant?: TextVariant;
104 |   maxLines?: number;
105 |   preserveLinebreaks?: boolean;
106 |   ellipses?: boolean;
107 |   overflowMode?: OverflowMode;
108 |   breakMode?: BreakMode;
109 |   style?: CSSProperties;
110 |   className?: string;
111 |   registerComponentApi?: RegisterComponentApiFn;
112 |   [variantSpecificProps: string]: any;
113 | };
114 | 
115 | export const defaultProps = {
116 |   maxLines: 0,
117 |   preserveLinebreaks: false,
118 |   ellipses: true,
119 |   overflowMode: undefined as OverflowMode | undefined,
120 |   breakMode: "normal" as BreakMode | undefined,
121 | };
122 | 
123 | export const Text = forwardRef(function Text(
124 |   {
125 |     uid,
126 |     variant,
127 |     maxLines = defaultProps.maxLines,
128 |     style,
129 |     className,
130 |     children,
131 |     preserveLinebreaks = defaultProps.preserveLinebreaks,
132 |     ellipses = defaultProps.ellipses,
133 |     overflowMode = defaultProps.overflowMode,
134 |     breakMode = defaultProps.breakMode,
135 |     registerComponentApi,
136 |     ...variantSpecificProps
137 |   }: TextProps,
138 |   forwardedRef,
139 | ) {
140 |   const innerRef = useRef<HTMLElement>(null);
141 |   const ref = forwardedRef ? composeRefs(innerRef, forwardedRef) : innerRef;
142 | 
143 |   // Implement hasOverflow function
144 |   const hasOverflow = useCallback((): boolean => {
145 |     const element = innerRef.current;
146 |     if (!element) return false;
147 | 
148 |     // Check both horizontal and vertical overflow
149 |     const hasHorizontalOverflow = element.scrollWidth > element.clientWidth;
150 |     const hasVerticalOverflow = element.scrollHeight > element.clientHeight;
151 | 
152 |     return hasHorizontalOverflow || hasVerticalOverflow;
153 |   }, []);
154 | 
155 |   // Register API with XMLUI if provided
156 |   useEffect(() => {
157 |     if (registerComponentApi) {
158 |       registerComponentApi({ hasOverflow });
159 |     }
160 |   }, [registerComponentApi, hasOverflow]);
161 | 
162 |   // NOTE: This is to accept syntax highlight classes coming from shiki
163 |   // classes need not to be added to the rendered html element, so we remove them from props
164 |   const { syntaxHighlightClasses, ...restVariantSpecificProps } = variantSpecificProps;
165 | 
166 |   const Element = useMemo(() => {
167 |     if (!variant || !TextVariantElement[variant]) return "div";
168 |     return TextVariantElement[variant];
169 |   }, [variant]);
170 | 
171 |   // Custom variant CSS generation
172 |   // Following React hook rules: hooks must be called unconditionally
173 |   // We always call useComponentStyle, passing empty object for known variants
174 |   const isCustomVariant = useMemo(() => {
175 |     return variant && !TextVariantElement[variant];
176 |   }, [variant]);
177 | 
178 |   // Always call useComponentStyle (React hook rule: no conditional hooks)
179 |   // For now, pass empty object; later this will contain assembled CSS properties
180 |   const variantSpec = useMemo(
181 |     () => {
182 |       if (!isCustomVariant) return EMPTY_OBJECT;
183 |       const subject = `-Text-${variant}`;
184 |       const cssInput = {
185 |         color: toCssVar(`$textColor${subject}`),
186 |         "font-family": toCssVar(`$fontFamily${subject}`),
187 |         "font-size": toCssVar(`$fontSize${subject}`),
188 |         "font-style": toCssVar(`$fontStyle${subject}`),
189 |         "font-weight": toCssVar(`$fontWeight${subject}`),
190 |         "font-stretch": toCssVar(`$fontStretch${subject}`),
191 |         "text-decoration-line": toCssVar(`$textDecorationLine${subject}`),
192 |         "text-decoration-color": toCssVar(`$textDecorationColor${subject}`),
193 |         "text-decoration-style": toCssVar(`$textDecorationStyle${subject}`),
194 |         "text-decoration-thickness": toCssVar(`$textDecorationThickness${subject}`),
195 |         "text-underline-offset": toCssVar(`$textUnderlineOffset${subject}`),
196 |         "line-height": toCssVar(`$lineHeight${subject}`),
197 |         "background-color": toCssVar(`$backgroundColor${subject}`),
198 |         "text-transform": toCssVar(`$textTransform${subject}`),
199 |         "letter-spacing": toCssVar(`$letterSpacing${subject}`),
200 |         "word-spacing": toCssVar(`$wordSpacing${subject}`),
201 |         "text-shadow": toCssVar(`$textShadow${subject}`),
202 |         "text-indent": toCssVar(`$textIndent${subject}`),
203 |         "text-align": toCssVar(`$textAlign${subject}`),
204 |         "text-align-last": toCssVar(`$textAlignLast${subject}`),
205 |         "word-break": toCssVar(`$wordBreak${subject}`),
206 |         "word-wrap": toCssVar(`$wordWrap${subject}`),
207 |         direction: toCssVar(`$direction${subject}`),
208 |         "writing-mode": toCssVar(`$writingMode${subject}`),
209 |         "line-break": toCssVar(`$lineBreak${subject}`),
210 |       };
211 |       return cssInput;
212 |     },
213 |     [isCustomVariant, variant],
214 |   );
215 |   const customVariantClassName = useComponentStyle(variantSpec);
216 | 
217 |   // Store custom variant in cache if it's a new custom variant
218 |   useEffect(() => {
219 |     if (isCustomVariant && variant && customVariantClassName) {
220 |       // Check if this variant is already cached
221 |       if (!hasCustomVariantCache(variant)) {
222 |         // TODO: When CSS generation is implemented, extract the actual CSS text
223 |         // For now, store placeholder information
224 |         setCustomVariantCache(variant, {
225 |           className: customVariantClassName,
226 |           cssText: "", // Will be populated when CSS generation is implemented
227 |         });
228 |       }
229 |     }
230 |   }, [isCustomVariant, variant, customVariantClassName]);
231 | 
232 |   // Determine overflow mode classes based on overflowMode and existing props
233 |   const overflowClasses = useMemo(() => {
234 |     const classes: Record<string, boolean> = {};
235 | 
236 |     // If overflowMode is not explicitly set, use original behavior
237 |     if (!overflowMode) {
238 |       classes[styles.truncateOverflow] = maxLines > 0;
239 |       classes[styles.noEllipsis] = !ellipses;
240 |       return classes;
241 |     }
242 | 
243 |     switch (overflowMode) {
244 |       case "none":
245 |         // CSS: overflow: hidden + text-overflow: clip + normal wrapping
246 |         // Effect: Text wraps normally but clips cleanly at container boundaries without ellipsis
247 |         classes[styles.overflowNone] = true;
248 |         break;
249 |       case "scroll":
250 |         // CSS: white-space: nowrap + overflow-x: auto + overflow-y: hidden
251 |         // Effect: Forces single line, enables horizontal scrollbar when content overflows
252 |         classes[styles.overflowScroll] = true;
253 |         break;
254 |       case "ellipsis":
255 |         // CSS: Uses -webkit-line-clamp for multi-line or white-space: nowrap + text-overflow: ellipsis for single line
256 |         // Effect: Shows "..." when text is truncated, respects maxLines for multi-line truncation
257 |         classes[styles.truncateOverflow] = true;
258 |         classes[styles.noEllipsis] = !ellipses;
259 |         break;
260 |       case "flow":
261 |         // CSS: white-space: normal + overflow-y: auto + overflow-x: hidden
262 |         // Effect: Text wraps to multiple lines with vertical scrolling when needed, no horizontal scrollbar
263 |         // Note: Flow mode ignores maxLines to allow unlimited text wrapping
264 |         classes[styles.overflowFlow] = true;
265 |         break;
266 |     }
267 | 
268 |     return classes;
269 |   }, [overflowMode, maxLines, ellipses]);
270 | 
271 |   // Determine break mode classes
272 |   const breakClasses = useMemo(() => {
273 |     const classes: Record<string, boolean> = {};
274 | 
275 |     // Only apply break mode classes if explicitly set (preserves theme variable support)
276 |     if (breakMode) {
277 |       switch (breakMode) {
278 |         case "normal":
279 |           // CSS: word-break: normal + overflow-wrap: normal
280 |           // Effect: Standard word breaking at natural boundaries (spaces, hyphens)
281 |           classes[styles.breakNormal] = true;
282 |           break;
283 |         case "word":
284 |           // CSS: overflow-wrap: break-word
285 |           // Effect: Breaks long words only when necessary to prevent overflow, preserves word boundaries when possible
286 |           classes[styles.breakWord] = true;
287 |           break;
288 |         case "anywhere":
289 |           // CSS: word-break: break-all + overflow-wrap: anywhere
290 |           // Effect: Most aggressive breaking - allows breaking between any characters to fit container
291 |           classes[styles.breakAnywhere] = true;
292 |           break;
293 |         case "keep":
294 |           // CSS: word-break: keep-all
295 |           // Effect: Prevents breaking within words entirely (useful for CJK text or technical terms)
296 |           classes[styles.breakKeep] = true;
297 |           break;
298 |         case "hyphenate":
299 |           // CSS: hyphens: auto + overflow-wrap: break-word
300 |           // Effect: Uses browser's hyphenation dictionary to break words with proper hyphens
301 |           classes[styles.breakHyphenate] = true;
302 |           break;
303 |       }
304 |     }
305 | 
306 |     return classes;
307 |   }, [breakMode]);
308 | 
309 |   return (
310 |     <Element
311 |       {...restVariantSpecificProps}
312 |       ref={ref as any}
313 |       className={classnames(
314 |         syntaxHighlightClasses,
315 |         styles.text,
316 |         // Use custom variant className if it's a custom variant, otherwise use predefined variant style
317 |         isCustomVariant ? customVariantClassName : styles[variant || "default"],
318 |         {
319 |           [styles.preserveLinebreaks]: preserveLinebreaks,
320 |           ...overflowClasses,
321 |           ...breakClasses,
322 |         },
323 |         className,
324 |       )}
325 |       style={{
326 |         ...style,
327 |         // Apply maxLines style for "ellipsis" mode and default behavior
328 |         // "none", "scroll", and "flow" modes ignore maxLines for predictable, reliable behavior
329 |         ...(overflowMode === "ellipsis" || (!overflowMode && maxLines)
330 |           ? getMaxLinesStyle(maxLines)
331 |           : {}),
332 |       }}
333 |     >
334 |       {children}
335 |     </Element>
336 |   );
337 | });
338 | 
```

--------------------------------------------------------------------------------
/xmlui/src/testing/component-test-helpers.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import type { Locator } from "@playwright/test";
  2 | 
  3 | import { type ParserResult, xmlUiMarkupToComponent } from "../components-core/xmlui-parser";
  4 | import type { ComponentDef, CompoundComponentDef } from "../abstractions/ComponentDefs";
  5 | 
  6 | import chroma, { type Color } from "chroma-js";
  7 | import { ComponentDriver } from "./ComponentDrivers";
  8 | 
  9 | export type ThemeTestDesc = {
 10 |   themeVar: string;
 11 |   themeVarAsCSS: string;
 12 |   expected: string;
 13 |   dependsOnVars?: Record<string, string>;
 14 | };
 15 | 
 16 | export function mapObject<K extends (val: any) => any, V extends (val: string) => string | number>(
 17 |   obj: Record<string, any>,
 18 |   valFn: K = ((val) => val) as K,
 19 |   keyFn: V = ((val) => val) as V,
 20 | ) {
 21 |   const newObject = {} as Record<ReturnType<V>, ReturnType<K>>;
 22 |   Object.entries(obj).forEach(([key, value]) => {
 23 |     newObject[keyFn(key)] = valFn(value);
 24 |   });
 25 |   return newObject;
 26 | }
 27 | 
 28 | export function getComponentTagName(locator: Locator) {
 29 |   return locator.evaluate((el) => el.tagName.toLowerCase());
 30 | }
 31 | 
 32 | export function parseComponentIfNecessary(
 33 |   rawComponent: ComponentDef<any> | CompoundComponentDef | string,
 34 | ): ParserResult {
 35 |   if (typeof rawComponent === "string") {
 36 |     return xmlUiMarkupToComponent(rawComponent);
 37 |   }
 38 |   return {
 39 |     component: rawComponent,
 40 |     errors: [],
 41 |     erroneousCompoundComponentName: undefined,
 42 |   };
 43 | }
 44 | 
 45 | /**
 46 |  * Scales a value by a percentage, using NumericCSS for parsing and clarity.
 47 |  * @param scalarOf100Percent The value representing 100%.
 48 |  * @param percentage A percentage string in the format "NN%", e.g., "40%". Must end with '%'.
 49 |  * @returns The scaled value.
 50 |  */
 51 | export function scaleByPercent(scalarOf100Percent: number, percentage: string) {
 52 |   const parsed = parseAsNumericCss(percentage);
 53 |   if (parsed.unit !== "%") {
 54 |     throw new Error(`Expected percentage unit (%), got: ${parsed.unit}`);
 55 |   }
 56 |   return (scalarOf100Percent / 100) * parsed.value;
 57 | }
 58 | 
 59 | export function getBoundingRect(locator: Locator) {
 60 |   return locator.evaluate((element) => element.getBoundingClientRect());
 61 | }
 62 | 
 63 | export function getElementStyle(specifier: Locator, style: string) {
 64 |   return specifier.evaluate(
 65 |     (element, style) => window.getComputedStyle(element).getPropertyValue(style),
 66 |     style,
 67 |   );
 68 | }
 69 | 
 70 | /**
 71 |  * Retreives all the provided style properties from the locator
 72 |  * @returns an object with the keys being the elements of the styles argument
 73 |  */
 74 | export function getElementStyles(locator: Locator, styles: string[] = []) {
 75 |   return locator.evaluate(
 76 |     (element, styles) =>
 77 |       Object.fromEntries(
 78 |         styles.map((styleName) => [
 79 |           styleName,
 80 |           window.getComputedStyle(element).getPropertyValue(styleName),
 81 |         ]),
 82 |       ),
 83 |     styles,
 84 |   );
 85 | }
 86 | 
 87 | export function isIndeterminate(specifier: ComponentDriver | Locator) {
 88 |   if (specifier instanceof ComponentDriver) specifier = specifier.component;
 89 |   return specifier.evaluate((el: HTMLInputElement) => el.indeterminate);
 90 | }
 91 | 
 92 | export async function overflows(locator: Locator, direction: "x" | "y" | "both" = "both") {
 93 |   const [width, height, scrollWidth, scrollHeight] = await locator.evaluate((element) => [
 94 |     element.clientWidth,
 95 |     element.clientHeight,
 96 |     element.scrollWidth,
 97 |     element.scrollHeight,
 98 |   ]);
 99 |   if (direction === "x") return scrollWidth > width;
100 |   if (direction === "y") return scrollHeight > height;
101 |   return scrollWidth > width && scrollHeight > height;
102 | }
103 | 
104 | // ----------------------------------
105 | // ComponentDriver style helpers
106 | // ----------------------------------
107 | 
108 | export function getStyles(specifier: ComponentDriver | Locator, style: string | string[]) {
109 |   if (specifier instanceof ComponentDriver) specifier = specifier.component;
110 |   style = Array.isArray(style) ? style : [style];
111 |   return specifier.evaluate(
112 |     (element, styles) =>
113 |       Object.fromEntries(
114 |         styles.map((styleName) => [
115 |           styleName
116 |             .trim()
117 |             .split("-")
118 |             .map((n, idx) => (idx === 0 ? n : n[0].toUpperCase() + n.slice(1)))
119 |             .join(""),
120 |           window.getComputedStyle(element).getPropertyValue(styleName),
121 |         ]),
122 |       ),
123 |     style,
124 |   );
125 | }
126 | 
127 | export function getPseudoStyles(
128 |   specifier: ComponentDriver | Locator,
129 |   pseudoElement: string,
130 |   style: string | string[],
131 | ) {
132 |   if (specifier instanceof ComponentDriver) specifier = specifier.component;
133 |   style = Array.isArray(style) ? style : [style];
134 |   return specifier.evaluate(
135 |     (element, obj) =>
136 |       Object.fromEntries(
137 |         obj.style.map((styleName) => [
138 |           styleName
139 |             .trim()
140 |             .split("-")
141 |             .map((n, idx) => (idx === 0 ? n : n[0].toUpperCase() + n.slice(1)))
142 |             .join(""),
143 |           window.getComputedStyle(element, obj.pseudoElement).getPropertyValue(styleName),
144 |         ]),
145 |       ),
146 |     { style, pseudoElement },
147 |   );
148 | }
149 | 
150 | export async function getHtmlAttributes(
151 |   specifier: ComponentDriver | Locator,
152 |   attributes: string | string[],
153 | ): Promise<{ [k: string]: string }> {
154 |   if (specifier instanceof ComponentDriver) specifier = specifier.component;
155 |   attributes = Array.isArray(attributes) ? attributes : [attributes];
156 | 
157 |   const mapped = await Promise.all(
158 |     attributes.map(async (attr) => {
159 |       return [attr, await specifier.getAttribute(attr)];
160 |     }),
161 |   );
162 |   return Object.fromEntries(mapped);
163 | }
164 | 
165 | export async function getPaddings(specifier: ComponentDriver | Locator) {
166 |   const paddings = mapObject(
167 |     await getStyles(specifier, ["padding-left", "padding-right", "padding-top", "padding-bottom"]),
168 |     parseAsNumericCss,
169 |   );
170 |   return {
171 |     left: paddings.paddingLeft,
172 |     right: paddings.paddingRight,
173 |     top: paddings.paddingTop,
174 |     bottom: paddings.paddingBottom,
175 |   };
176 | }
177 | 
178 | export async function getBorders(specifier: ComponentDriver | Locator) {
179 |   const borders = mapObject(
180 |     await getStyles(specifier, ["border-left", "border-right", "border-top", "border-bottom"]),
181 |     parseAsCssBorder,
182 |   );
183 |   return {
184 |     left: borders.borderLeft,
185 |     right: borders.borderRight,
186 |     top: borders.borderTop,
187 |     bottom: borders.borderBottom,
188 |   };
189 | }
190 | 
191 | export function getMargins(specifier: ComponentDriver | Locator) {
192 |   return getStyles(specifier, ["margin-left", "margin-right", "margin-top", "margin-bottom"]);
193 | }
194 | 
195 | /**
196 |  * Retrieves the bounding rectangle of the component including **margins** and **padding**
197 |  * added to the dimensions.
198 |  */
199 | export async function getBounds(specifier: ComponentDriver | Locator) {
200 |   if (specifier instanceof ComponentDriver) specifier = specifier.component;
201 |   const boundingRect = await specifier.evaluate((element) => element.getBoundingClientRect());
202 |   const m = mapObject(await getMargins(specifier), parseFloat);
203 | 
204 |   const width = boundingRect.width + m.marginLeft + m.marginRight;
205 |   const height = boundingRect.height + m.marginTop + m.marginBottom;
206 |   const left = boundingRect.left - m.marginLeft;
207 |   const right = boundingRect.right + m.marginRight;
208 |   const top = boundingRect.top - m.marginTop;
209 |   const bottom = boundingRect.bottom + m.marginBottom;
210 | 
211 |   return {
212 |     width,
213 |     height,
214 |     left,
215 |     right,
216 |     top,
217 |     bottom,
218 |   };
219 | }
220 | 
221 | /**
222 |  * Provides annotations for skipped tests and the ability to specify a reason.
223 |  * Use it via the SKIP_REASON exported variable.
224 |  */
225 | class TestSkipReason {
226 |   private addAnnotation(type: string, description?: string) {
227 |     return {
228 |       annotation: {
229 |         type,
230 |         description: description ?? "",
231 |       },
232 |     };
233 |   }
234 | 
235 |   NOT_IMPLEMENTED_XMLUI(description?: string) {
236 |     return this.addAnnotation("not implemented in xmlui", description);
237 |   }
238 | 
239 |   TO_BE_IMPLEMENTED(description?: string) {
240 |     return this.addAnnotation("to be implemented", description);
241 |   }
242 | 
243 |   XMLUI_BUG(description?: string) {
244 |     return this.addAnnotation("xmlui bug", description);
245 |   }
246 | 
247 |   TEST_INFRA_BUG(description?: string) {
248 |     return this.addAnnotation("test infra bug", description);
249 |   }
250 | 
251 |   TEST_NOT_WORKING(description?: string) {
252 |     return this.addAnnotation("test not working", description);
253 |   }
254 | 
255 |   TEST_INFRA_NOT_IMPLEMENTED(description?: string) {
256 |     return this.addAnnotation("test infra not implemented", description);
257 |   }
258 | 
259 |   REFACTOR(description?: string) {
260 |     return this.addAnnotation("refactor", description);
261 |   }
262 | 
263 |   // Need to specify a reason here!
264 |   UNSURE(description: string) {
265 |     return this.addAnnotation("unsure", description);
266 |   }
267 | }
268 | 
269 | /**
270 |  * Provides annotations for skipped tests and the ability to specify a reason.
271 |  *
272 |  * Usage:
273 |  *
274 |  * ```ts
275 |  * import { SKIP_REASON } from "./tests/component-test-helpers";
276 |  *
277 |  * test.skip(
278 |  *   "test name",
279 |  *   SKIP_REASON.NOT_IMPLEMENTED_XMLUI("This test is not implemented in xmlui")
280 |  *   async ({}) => {},
281 |  * );
282 |  * ```
283 |  */
284 | export const SKIP_REASON = new TestSkipReason();
285 | 
286 | // --- CSS types and parsers
287 | 
288 | export function pixelStrToNum(pixelStr: string) {
289 |   return Number(pixelStr.replace("px", ""));
290 | }
291 | 
292 | export function parseAsCssBorder(str: string) {
293 |   const parts = str.split(/\s+(?=[a-z]+|\()/i);
294 |   if (parts.length > 3) {
295 |     throw new Error(`Provided value ${str} cannot be parsed as a CSS border`);
296 |   }
297 |   const style = parts.filter(isCSSBorderStyle);
298 |   if (style.length > 1) {
299 |     throw new Error(`Too many border styles provided in ${str}`);
300 |   }
301 | 
302 |   const width = parts.filter(isNumericCSS);
303 |   if (width.length > 1) {
304 |     throw new Error(`Too many border widths provided in ${str}`);
305 |   }
306 | 
307 |   const color = parts.filter((p) => chroma.valid(p));
308 |   if (color.length > 1) {
309 |     throw new Error(`Too many border colors provided in ${str}`);
310 |   }
311 | 
312 |   const result: CSSBorder = {
313 |     width: !!width[0] ? parseAsNumericCss(width[0]) : undefined,
314 |     style: style[0],
315 |     color: chroma(color[0]),
316 |   };
317 |   return result;
318 | }
319 | 
320 | export interface NumericCSS {
321 |   value: number;
322 |   unit: CSSUnit;
323 | }
324 | 
325 | const numericCSSRegex = /^([+-]?(?:\d+|\d*\.\d+))([a-z]*|%)$/;
326 | 
327 | export function isNumericCSS(str: any): str is NumericCSS {
328 |   const parts = str.match(numericCSSRegex);
329 | 
330 |   if (!parts) return false;
331 |   if (parts.length < 3) return false;
332 |   if (isNaN(parseFloat(parts[1]))) return false;
333 |   if (!isCSSUnit(parts[2])) return false;
334 | 
335 |   return true;
336 | }
337 | 
338 | export function parseAsNumericCss(str: string) {
339 |   const parts = str.match(numericCSSRegex);
340 |   if (!parts) {
341 |     throw new Error(`Provided value ${str} cannot be parsed as a numeric CSS value`);
342 |   }
343 |   if (parts.length < 3) {
344 |     throw new Error(`${parts[0]} is not a correct numeric CSS value`);
345 |   }
346 |   const value = parseFloat(parts[1]);
347 |   if (isNaN(value)) {
348 |     throw new Error(`${value} is not a valid number in ${str}`);
349 |   }
350 |   const unit = parts[2];
351 |   if (!isCSSUnit(unit)) {
352 |     throw new Error(`${unit} is not have a valid CSS unit in ${str}`);
353 |   }
354 |   const result: NumericCSS = { value, unit };
355 |   return result;
356 | }
357 | 
358 | export function numericCSSToString(cssValue: NumericCSS) {
359 |   return `${cssValue.value}${cssValue.unit}`;
360 | }
361 | 
362 | export type CSSColor = chroma.Color;
363 | 
364 | export function isCSSColor(str: any): str is CSSColor {
365 |   return chroma.valid(str);
366 | }
367 | 
368 | export function parseAsCSSColor(str: string): CSSColor {
369 |   return chroma(str);
370 | }
371 | 
372 | const CSSUnitValues = [
373 |   "px",
374 |   "em",
375 |   "rem",
376 |   "vh",
377 |   "vw",
378 |   "%",
379 |   "cm",
380 |   "mm",
381 |   "in",
382 |   "pt",
383 |   "pc",
384 |   "ex",
385 |   "ch",
386 |   "vmin",
387 |   "vmax",
388 | ] as const;
389 | type CSSUnit = (typeof CSSUnitValues)[number];
390 | 
391 | function isCSSUnit(str: string): str is CSSUnit {
392 |   return CSSUnitValues.includes(str as any);
393 | }
394 | 
395 | export type CSSBorder = {
396 |   width?: NumericCSS;
397 |   style?: CSSBorderStyle;
398 |   color?: Color;
399 | };
400 | 
401 | const CSSBorderStyleValues = [
402 |   "solid",
403 |   "dotted",
404 |   "dashed",
405 |   "double",
406 |   "none",
407 |   "hidden",
408 |   "groove",
409 |   "ridge",
410 |   "inset",
411 |   "outset",
412 | ] as const;
413 | export type CSSBorderStyle = (typeof CSSBorderStyleValues)[number];
414 | 
415 | export function isCSSBorderStyle(str: string): str is CSSBorderStyle {
416 |   return CSSBorderStyleValues.includes(str as any);
417 | }
418 | export function parseAsCSSBorderStyle(str: string) {
419 |   if (!isCSSBorderStyle(str)) {
420 |     throw new Error(`Provided value ${str} cannot be parsed as a CSS border style`);
421 |   }
422 |   return str;
423 | }
424 | 
425 | export const BorderSideValues = ["top", "bottom", "left", "right"] as const;
426 | export type BorderSide = (typeof BorderSideValues)[number];
427 | 
428 | export function isBorderSide(str: string): str is BorderSide {
429 |   return BorderSideValues.includes(str as any);
430 | }
431 | 
```

--------------------------------------------------------------------------------
/xmlui/src/components/Tree/Tree.md:
--------------------------------------------------------------------------------

```markdown
  1 | %-DESC-START
  2 | 
  3 | **Key features:**
  4 | - **Flat and hierarchical data structures**: You can select the most convenient data format to represent the tree. A set of properties enables you to map your data structure to the visual representation of the tree.
  5 | - **Flexible expand/collapse**: You have several properties to represent the expanded and collapsed state of tree nodes. You can also specify several options that determine which tree items are collapsed initially. 
  6 | - **Tree API**: Several exposed methods allow you to manage the tree's view state imperatively.
  7 | 
  8 | ## Specifying Data
  9 | 
 10 | With the `dataFormat` property, you can select between "flat" or "hierarchy" formats. The component transforms the data according to the value of this property into a visual representation.
 11 | 
 12 | The "flat" and "hierarchy" data structures both use these fields for a particular tree node:
 13 | - `id`: Unique ID of tree node
 14 | - `name`: The field to be used as the display label
 15 | - `icon`: An optional icon identifier. If specified, this icon is displayed with the tree item.
 16 | - `iconExpanded`: An optional icon identifier. This icon is displayed when the field is expanded.
 17 | - `iconCollapsed`: An optional icon identifier. This icon is displayed when the field is collapsed.
 18 | - `selectable`: Indicates if the node can be selected.
 19 | 
 20 | The "flat" structure refers to its direct parent node via the `parentId` property, which contains the ID of the node it is referring to.
 21 | 
 22 | The "hierarchy" structure uses a `children` property, which is an array of nested child nodes (using the common node property set above).
 23 | 
 24 | This example demonstrates the use of the "flat" data mode:
 25 | 
 26 | ```xmlui-pg display copy height="220px" /"flat"/ /parentId/ name="Example: flat data format"
 27 | <App>
 28 |   <Tree
 29 |     testId="tree"
 30 |     dataFormat="flat"
 31 |     defaultExpanded="all"
 32 |     data='{[
 33 |       { id: 1, icon:"folder", name: "Root Item 1", parentId: null },
 34 |       { id: 2, icon:"folder", name: "Child Item 1.1", parentId: 1 },
 35 |       { id: 3, icon: "code", name: "Child Item 1.2", parentId: 1 },
 36 |       { id: 4, icon: "code", name: "Grandchild Item 1.1.1", parentId: 2 },
 37 |     ]}'>
 38 |   </Tree>
 39 | </App>
 40 | ```
 41 | 
 42 | This example demonstrates the use of the "hiearchy" data mode:
 43 | 
 44 | ```xmlui-pg display copy height="220px" /"flat"/ /children/ name="Example: hierarchical data format"
 45 | <App>
 46 |   <Tree
 47 |     testId="tree"
 48 |     dataFormat="hierarchy"
 49 |     defaultExpanded="all"
 50 |     data='{[
 51 |       {
 52 |         id: 1, icon: "folder", name: "Root Item 1",
 53 |         children: [
 54 |           { id: 2, icon: "code", name: "Child Item 1.1" },
 55 |           { id: 3, icon: "folder", name: "Child Item 1.2",
 56 |             children: [
 57 |               { id: 4, icon: "code", name: "Grandchild Item 1.2.1"}
 58 |             ],
 59 |           }
 60 |         ],
 61 |       },
 62 |     ]}'>
 63 |   </Tree>
 64 | </App>
 65 | ```
 66 | 
 67 | When you use data (for example, retrieved from a backend), those structures may use different property names. The `Tree` component allows mapping data field names through these properties: 
 68 | - `idField` (default: `id`)
 69 | - `nameField` (default: `name`)
 70 | - `iconField`  (default: `icon`)
 71 | - `iconExpandedField` (default: `iconExpanded`)
 72 | - `iconCollapsedField` (default: `iconCollapsed`)
 73 | - `parentIdField` (default: `parentId`)
 74 | - `childrenField` (default: `children`)
 75 | - `selectableField` (default: `selectable`)
 76 | 
 77 | The following example uses the `idField`, `nameField`, and `parentIdField` mapping properties:
 78 | 
 79 | ```xmlui-pg display copy height="220px" /idField/ /nameField/ /parentIdField/ /uid/ /label/ /parent/ name="Example: mapping data fields"
 80 | <App>
 81 |   <Tree
 82 |     testId="tree"
 83 |     dataFormat="flat"
 84 |     defaultExpanded="all"
 85 |     idField="uid"
 86 |     nameField="label"
 87 |     parentIdField="parent"
 88 |     data='{[
 89 |       { uid: 1, icon:"folder", label: "Root Item 1", parent: null },
 90 |       { uid: 2, icon:"folder", label: "Child Item 1.1", parent: 1 },
 91 |       { uid: 3, icon: "code", label: "Child Item 1.2", parent: 1 },
 92 |       { uid: 4, icon: "code", label: "Grandchild Item 1.1.1", parent: 2 },
 93 |     ]}'>
 94 |   </Tree>
 95 | </App>
 96 | ```
 97 | 
 98 | ## Expanding and collapsing tree nodes
 99 | 
100 | By default, when you click a tree node outside of its expand/collapse icon,  the specified item is selected. With the `expandOnItemClick` property (using the `true` value), you can change this behavior to expand or collapse the item when clicking its surface anywhere.
101 | 
102 | You can use the `defaultExpanded` property to specify what nodes you want to see expanded initially. You can set this property to a list of node IDs or a string. When you specify IDs, the component expands the hierarchy to reveal the specified nodes. When the value is a string, you can use these options:
103 | - `none`: all nodes are collapsed (default)
104 | - `first-level`: all first-level nodes are expanded
105 | - `all`: all nodes are expanded
106 | 
107 | The following example demonstrates the use of `defaultExpanded` with tree node IDs:
108 | 
109 | ```xmlui-pg display copy height="300px" /doc-root/ /proj-web/ /media-profile-pic/ name="Example: defaultExpanded with node IDs"
110 | <App>
111 |   <Tree
112 |     testId="tree"
113 |     dataFormat="flat"
114 |     defaultExpanded="{['doc-root', 'proj-web', 'media-profile-pic']}"
115 |     data='{[
116 |       // Branch A: Documents
117 |       { id: "doc-root", name: "[Documents]", parentId: null },
118 |       { id: "doc-reports", name: "Reports", parentId: "doc-root" },
119 |       { id: "doc-invoices", name: "Invoices", parentId: "doc-root" },
120 |       { id: "doc-q1-report", name: "Q1 Report.pdf", parentId: "doc-reports" },
121 |       { id: "doc-q2-report", name: "Q2 Report.pdf", parentId: "doc-reports" },
122 |       { id: "doc-inv-001", name: "Invoice-001.pdf", parentId: "doc-invoices" },
123 | 
124 |       // Branch B: Projects
125 |       { id: "proj-root", name: "Projects", parentId: null },
126 |       { id: "proj-web", name: "[Web Apps]", parentId: "proj-root" },
127 |       { id: "proj-mobile", name: "Mobile Apps", parentId: "proj-root" },
128 |       { id: "proj-ecommerce", name: "E-commerce Site", parentId: "proj-web" },
129 |       { id: "proj-dashboard", name: "Admin Dashboard", parentId: "proj-web" },
130 |       { id: "proj-ios-app", name: "iOS Shopping App", parentId: "proj-mobile" },
131 | 
132 |       // Branch C: Media
133 |       { id: "media-root", name: "Media", parentId: null },
134 |       { id: "media-images", name: "Images", parentId: "media-root" },
135 |       { id: "media-videos", name: "Videos", parentId: "media-root" },
136 |       { id: "media-profile-pic", name: "[profile.jpg]", parentId: "media-images" },
137 |       { id: "media-banner", name: "banner.png", parentId: "media-images" },
138 |     ]}'>
139 |   </Tree>
140 | </App>
141 | ```
142 | 
143 | You have several options to style the icons representing the expanded or collapsed state:
144 | - The icons used for the expanded and collapsed states can be changed with the `iconExpanded` and `iconCollapsed` properties, respectively.
145 | - You can specify a different size with the `iconSize` property (using only numeric values considered as pixels)
146 | - Using a rotate animation when changing the state with the `animateExpand` flag.
147 | The following option demonstrates the last two options:
148 | 
149 | ```xmlui-pg display copy {4-5} height="220px" name="Example: expand/collapse options"
150 | <App>
151 |   <Tree
152 |     testId="tree"
153 |     iconSize="24"
154 |     animateExpand
155 |     dataFormat="flat"
156 |     defaultExpanded="all"
157 |     data='{[
158 |       { id: 1, name: "Root Item 1", parentId: null },
159 |       { id: 2, name: "Child Item 1.1", parentId: 1 },
160 |       { id: 3, name: "Child Item 1.2", parentId: 1 },
161 |       { id: 4, name: "Grandchild Item 1.1.1", parentId: 2 },
162 |     ]}'>
163 |   </Tree>
164 | </App>
165 | ```
166 | 
167 | ## Selection
168 | 
169 | Each tree node is selectable by default, unless the node item's data does not have a `selectable` property (or the one specified in `selectedField`).
170 | A selectable item can be selected by clicking the mouse or pressing the Enter or Space keys when it has focus.
171 | 
172 | You can set the `selectedValue` property to define the selected tree item, ot use the `selectNode` exposed method for imperative selection.
173 | 
174 | ## Item templates
175 | 
176 | You can override the default template used to display a tree item with the `itemTemplate` property. The template definition can use the `$item` context variable to access the item's attributes for display. `$item` provides these properties:
177 | - `id`: The unique node ID
178 | - `name`: The name of the node
179 | - `depth`: The depth level in the tree
180 | - `isExpanded`: Indicates if the tree node is expanded
181 | - `hasChildren`: Indicates if the tree node has children
182 | - `children`: The children of the tree node
183 | - `selectable`: Indicates if the node can be selected
184 | - `parentId`: The ID of the node's parent
185 | - `parentIds`: A list of parent IDs from the root node to the direct parent of the node
186 | - `path`: An array with the node names following the path from the root node to the displayed node.
187 | - `loadingState`: The current state of a dynamic node ("unloaded", "loading", or "loaded")
188 | 
189 | This example demonstrates these concepts:
190 | 
191 | ```xmlui-pg display copy {20-30} height="400px" /$item.id/ /$item.name/ /$item.hasChildren/ name="Example: itemTemplate"
192 | <App>
193 |   <Tree
194 |     testId="tree"
195 |     id="tree"
196 |     defaultExpanded="all"
197 |     data='{[
198 |         { id: "root", name: "My Files", parentId: null },
199 |         { id: "doc-root", name: "Documents", parentId: "root" },
200 |         { id: "doc-reports", name: "Reports", parentId: "doc-root" },
201 |         { id: "doc-q1-report", name: "Q1 Report.pdf", parentId: "doc-reports" },
202 |         { id: "doc-q2-report", name: "Q2 Report.pdf", parentId: "doc-reports" },
203 |         { id: "proj-root", name: "Projects", parentId: "root" },
204 |         { id: "proj-web", name: "Web Apps", parentId: "proj-root" },
205 |         { id: "proj-ecommerce", name: "E-commerce Site", parentId: "proj-web" },
206 |         { id: "proj-dashboard", name: "Admin Dashboard", parentId: "proj-web" },
207 |         { id: "media-root", name: "Media", parentId: "root" },
208 |         { id: "media-images", name: "Images", parentId: "media-root" },
209 |         { id: "media-videos", name: "Videos", parentId: "media-root" },
210 |       ]}'>
211 |     <property name="itemTemplate">
212 |       <HStack testId="{$item.id}" verticalAlignment="center" gap="$space-1">
213 |         <Icon name="{$item.hasChildren ? 'folder' : 'code'}" />
214 |         <Text>
215 |           ({$item.id}):
216 |         </Text>
217 |         <Text variant="strong">
218 |           {$item.name}
219 |         </Text>
220 |       </HStack>
221 |     </property>
222 |   </Tree>
223 | </App>
224 | ```
225 | 
226 | ## Dynamic tree nodes
227 | 
228 | When initializing the tree with its `data` property, you can set the `dynamic` property of the node to `true` (you can use a field name alias with the `dynamicField` property). When you extend a dynamic node, the tree fires the `loadChildren` event, and the nodes returned by the event handler will be the actual nodes.
229 | 
230 | By default, nodes are not dynamic.
231 | 
232 | While the child nodes are being queried, the tree node displays a spinner to indicate the loading state.
233 | 
234 | You can use the `markNodeUnloaded` exposed method to reset the state of an already loaded dynamic tree node. The next time the user expands the node, its content will be loaded again.
235 | 
236 | The following sample demonstrates this feature. Click the "Child Item 1.2" node to check how it loads its children. Click the Unload button to reload the items when the node is expanded the next time.
237 | 
238 | ```xmlui-pg display copy {16-19} height="340px" /dynamic: true/ /onLoadChildren/ name="Example: dynamic nodes"
239 | <App var.loadCount="{0}">
240 |   <Tree
241 |     testId="tree"
242 |     defaultExpanded="all"
243 |     id="tree"
244 |     itemClickExpands
245 |     data='{[
246 |       { id: 1, name: "Root Item 1", parentId: null },
247 |       { id: 2, name: "Child Item 1.1", parentId: 1 },
248 |       { id: 3, name: "Child Item 1.2", parentId: 1, dynamic: true },
249 |       { id: 4, name: "Child Item 1.3", parentId: 1 },
250 |     ]}'
251 |     onLoadChildren="(node) => {
252 |       loadCount++;
253 |       delay(1000); 
254 |       return ([
255 |         { id: 5, name: `Dynamic Item 1.2.1 (${loadCount})` },
256 |         { id: 6, name: `Dynamic Item 2.2.2 (${loadCount})` },
257 |       ])
258 |     }"
259 |     >
260 |     <property name="itemTemplate">
261 |       <HStack testId="{$item.id}" verticalAlignment="center" gap="$space-1">
262 |         <Icon name="{$item.hasChildren 
263 |           ? ($item.loadingState === 'loaded' ? 'folder' : 'folder-outline' ) 
264 |           : 'code'}" 
265 |         />
266 |         <Text>{$item.name}</Text>
267 |       </HStack>
268 |     </property>
269 |   </Tree>
270 |   <Button onClick="tree.markNodeUnloaded(3)">Unload</Button>
271 | </App>
272 | ```
273 | 
274 | %-DESC-END
```

--------------------------------------------------------------------------------
/xmlui/tests/parsers/scripting/statement-hooks.test.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { describe, expect, it } from "vitest";
  2 | 
  3 | import { processStatementQueueAsync } from "../../../src/components-core/script-runner/process-statement-async";
  4 | import { processStatementQueue } from "../../../src/components-core/script-runner/process-statement-sync";
  5 | import { createEvalContext, parseStatements } from "./test-helpers";
  6 | 
  7 | describe("Statement hooks", () => {
  8 |   const stmtCases = [
  9 |     { src: "let x = 0;", exp: 1 },
 10 |     { src: "let x = 0; x++;", exp: 2 },
 11 |     { src: "let x = 0; while (x < 1) { x++ };", exp: 6 },
 12 |   ];
 13 | 
 14 |   stmtCases.forEach((c) => {
 15 |     it(`onStatementStarted (async) works ${c.src}`, async () => {
 16 |       // --- Arrange
 17 |       let counter = 0;
 18 |       const evalContext = createEvalContext({
 19 |         localContext: {},
 20 |         onStatementStarted: () => {
 21 |           counter++;
 22 |         },
 23 |       });
 24 |       const statements = parseStatements(c.src);
 25 | 
 26 |       // --- Act
 27 |       await processStatementQueueAsync(statements, evalContext);
 28 | 
 29 |       // --- Assert
 30 |       expect(counter).equal(c.exp);
 31 |     });
 32 |   });
 33 | 
 34 |   stmtCases.forEach((c) => {
 35 |     it(`onStatementStarted (sync) works ${c.src}`, () => {
 36 |       // --- Arrange
 37 |       let counter = 0;
 38 |       const evalContext = createEvalContext({
 39 |         localContext: {},
 40 |         onStatementStarted: () => {
 41 |           counter++;
 42 |         },
 43 |       });
 44 |       const statements = parseStatements(c.src);
 45 | 
 46 |       // --- Act
 47 |       processStatementQueue(statements, evalContext);
 48 | 
 49 |       // --- Assert
 50 |       expect(counter).equal(c.exp);
 51 |     });
 52 |   });
 53 | 
 54 |   stmtCases.forEach((c) => {
 55 |     it(`onStatementCompleted (async) works ${c.src}`, async () => {
 56 |       // --- Arrange
 57 |       let counter = 0;
 58 |       const evalContext = createEvalContext({
 59 |         localContext: {},
 60 |         onStatementCompleted: () => {
 61 |           counter++;
 62 |         },
 63 |       });
 64 |       const statements = parseStatements(c.src);
 65 | 
 66 |       // --- Act
 67 |       await processStatementQueueAsync(statements, evalContext);
 68 | 
 69 |       // --- Assert
 70 |       expect(counter).equal(c.exp);
 71 |     });
 72 |   });
 73 | 
 74 |   stmtCases.forEach((c) => {
 75 |     it(`onStatementCompleted (sync) works ${c.src}`, () => {
 76 |       // --- Arrange
 77 |       let counter = 0;
 78 |       const evalContext = createEvalContext({
 79 |         localContext: {},
 80 |         onStatementCompleted: () => {
 81 |           counter++;
 82 |         },
 83 |       });
 84 |       const statements = parseStatements(c.src);
 85 | 
 86 |       // --- Act
 87 |       processStatementQueue(statements, evalContext);
 88 | 
 89 |       // --- Assert
 90 |       expect(counter).equal(c.exp);
 91 |     });
 92 |   });
 93 | 
 94 |   stmtCases.forEach((c) => {
 95 |     it(`onStatementStarted&Completed (async) works ${c.src}`, async () => {
 96 |       // --- Arrange
 97 |       let counter = 0;
 98 |       const evalContext = createEvalContext({
 99 |         localContext: {},
100 |         onStatementStarted: () => {
101 |           counter++;
102 |         },
103 |         onStatementCompleted: () => {
104 |           counter++;
105 |         },
106 |       });
107 |       const statements = parseStatements(c.src);
108 | 
109 |       // --- Act
110 |       await processStatementQueueAsync(statements, evalContext);
111 | 
112 |       // --- Assert
113 |       expect(counter).equal(c.exp + c.exp);
114 |     });
115 |   });
116 | 
117 |   stmtCases.forEach((c) => {
118 |     it(`onStatementStarted&Completed (sync) works ${c.src}`, () => {
119 |       // --- Arrange
120 |       let counter = 0;
121 |       const evalContext = createEvalContext({
122 |         localContext: {},
123 |         onStatementStarted: () => {
124 |           counter++;
125 |         },
126 |         onStatementCompleted: () => {
127 |           counter++;
128 |         },
129 |       });
130 |       const statements = parseStatements(c.src);
131 | 
132 |       // --- Act
133 |       processStatementQueue(statements, evalContext);
134 | 
135 |       // --- Assert
136 |       expect(counter).equal(c.exp + c.exp);
137 |     });
138 |   });
139 | 
140 |   const updateAsgnCases = [
141 |     { src: "let x = 0; x = 3", exp: [] },
142 |     { src: "x = 0;", exp: ["x"] },
143 |     { src: "x.a = 0;", exp: ["x"] },
144 |     { src: "x.a = []; x.a[3] = 12", exp: ["x", "x"] },
145 |     { src: "x.a = []; x.a[3] = {}; x.a[3].f = 24", exp: ["x", "x", "x"] },
146 |     { src: "x = 0; y = 0;", exp: ["x", "y"] },
147 |   ];
148 | 
149 |   updateAsgnCases.forEach((c) => {
150 |     it(`onWillUpdate (async) works ${c.src}`, async () => {
151 |       // --- Arrange
152 |       let updated: string[] = [];
153 |       const evalContext = createEvalContext({
154 |         localContext: {
155 |           x: {},
156 |           y: {},
157 |         },
158 |         onWillUpdate: (_scope, index, type) => {
159 |           if (type === "assignment") {
160 |             updated.push(index as string);
161 |           }
162 |         },
163 |       });
164 |       const statements = parseStatements(c.src);
165 | 
166 |       // --- Act
167 |       await processStatementQueueAsync(statements, evalContext);
168 | 
169 |       // --- Assert
170 |       expect(updated).toStrictEqual(c.exp);
171 |     });
172 |   });
173 | 
174 |   updateAsgnCases.forEach((c) => {
175 |     it(`onWillUpdate (sync) works ${c.src}`, () => {
176 |       // --- Arrange
177 |       let updated: string[] = [];
178 |       const evalContext = createEvalContext({
179 |         localContext: {
180 |           x: {},
181 |           y: {},
182 |         },
183 |         onWillUpdate: (_scope, index, type) => {
184 |           if (type === "assignment") {
185 |             updated.push(index as string);
186 |           }
187 |         },
188 |       });
189 |       const statements = parseStatements(c.src);
190 | 
191 |       // --- Act
192 |       processStatementQueue(statements, evalContext);
193 | 
194 |       // --- Assert
195 |       expect(updated).toStrictEqual(c.exp);
196 |     });
197 |   });
198 | 
199 |   updateAsgnCases.forEach((c) => {
200 |     it(`onDidUpdate (async) works ${c.src}`, async () => {
201 |       // --- Arrange
202 |       let updated: string[] = [];
203 |       const evalContext = createEvalContext({
204 |         localContext: {
205 |           x: {},
206 |           y: {},
207 |         },
208 |         onDidUpdate: (_scope, index, type) => {
209 |           if (type === "assignment") {
210 |             updated.push(index as string);
211 |           }
212 |         },
213 |       });
214 |       const statements = parseStatements(c.src);
215 | 
216 |       // --- Act
217 |       await processStatementQueueAsync(statements, evalContext);
218 | 
219 |       // --- Assert
220 |       expect(updated).toStrictEqual(c.exp);
221 |     });
222 |   });
223 | 
224 |   updateAsgnCases.forEach((c) => {
225 |     it(`onDidUpdate (sync) works ${c.src}`, () => {
226 |       // --- Arrange
227 |       let updated: string[] = [];
228 |       const evalContext = createEvalContext({
229 |         localContext: {
230 |           x: {},
231 |           y: {},
232 |         },
233 |         onDidUpdate: (_scope, index, type) => {
234 |           if (type === "assignment") {
235 |             updated.push(index as string);
236 |           }
237 |         },
238 |       });
239 |       const statements = parseStatements(c.src);
240 | 
241 |       // --- Act
242 |       processStatementQueue(statements, evalContext);
243 | 
244 |       // --- Assert
245 |       expect(updated).toStrictEqual(c.exp);
246 |     });
247 |   });
248 | 
249 |   const prePostCases = [
250 |     { src: "let x = 0; x++", exp: [] },
251 |     { src: "x = 0; x++", exp: ["x"] },
252 |     { src: "x.a = 0; ++x.a", exp: ["x"] },
253 |     { src: "x.a = []; x.a[3] = 12; --x.a[3]", exp: ["x"] },
254 |     { src: "x.a = []; x.a[3] = {}; x.a[3].f = 24; x.a[3].f--", exp: ["x"] },
255 |     { src: "x = 0; x++; y = 0; --y;", exp: ["x", "y"] },
256 |   ];
257 | 
258 |   prePostCases.forEach((c) => {
259 |     it(`onWillUpdate (async) works ${c.src}`, async () => {
260 |       // --- Arrange
261 |       let updated: string[] = [];
262 |       const evalContext = createEvalContext({
263 |         localContext: {
264 |           x: {},
265 |           y: {},
266 |         },
267 |         onWillUpdate: (_scope, index, type) => {
268 |           if (type === "pre-post") {
269 |             updated.push(index as string);
270 |           }
271 |         },
272 |       });
273 |       const statements = parseStatements(c.src);
274 | 
275 |       // --- Act
276 |       await processStatementQueueAsync(statements, evalContext);
277 | 
278 |       // --- Assert
279 |       expect(updated).toStrictEqual(c.exp);
280 |     });
281 |   });
282 | 
283 |   prePostCases.forEach((c) => {
284 |     it(`onWillUpdate (sync) works ${c.src}`, () => {
285 |       // --- Arrange
286 |       let updated: string[] = [];
287 |       const evalContext = createEvalContext({
288 |         localContext: {
289 |           x: {},
290 |           y: {},
291 |         },
292 |         onWillUpdate: (_scope, index, type) => {
293 |           if (type === "pre-post") {
294 |             updated.push(index as string);
295 |           }
296 |         },
297 |       });
298 |       const statements = parseStatements(c.src);
299 | 
300 |       // --- Act
301 |       processStatementQueue(statements, evalContext);
302 | 
303 |       // --- Assert
304 |       expect(updated).toStrictEqual(c.exp);
305 |     });
306 |   });
307 | 
308 |   prePostCases.forEach((c) => {
309 |     it(`onDidUpdate (async) works ${c.src}`, async () => {
310 |       // --- Arrange
311 |       let updated: string[] = [];
312 |       const evalContext = createEvalContext({
313 |         localContext: {
314 |           x: {},
315 |           y: {},
316 |         },
317 |         onDidUpdate: (_scope, index, type) => {
318 |           if (type === "pre-post") {
319 |             updated.push(index as string);
320 |           }
321 |         },
322 |       });
323 |       const statements = parseStatements(c.src);
324 | 
325 |       // --- Act
326 |       await processStatementQueueAsync(statements, evalContext);
327 | 
328 |       // --- Assert
329 |       expect(updated).toStrictEqual(c.exp);
330 |     });
331 |   });
332 | 
333 |   prePostCases.forEach((c) => {
334 |     it(`onDidUpdate (sync) works ${c.src}`, () => {
335 |       // --- Arrange
336 |       let updated: string[] = [];
337 |       const evalContext = createEvalContext({
338 |         localContext: {
339 |           x: {},
340 |           y: {},
341 |         },
342 |         onDidUpdate: (_scope, index, type) => {
343 |           if (type === "pre-post") {
344 |             updated.push(index as string);
345 |           }
346 |         },
347 |       });
348 |       const statements = parseStatements(c.src);
349 | 
350 |       // --- Act
351 |       processStatementQueue(statements, evalContext);
352 | 
353 |       // --- Assert
354 |       expect(updated).toStrictEqual(c.exp);
355 |     });
356 |   });
357 | 
358 |   const funcCallCases = [
359 |     { src: "let x = () => {}; x()", exp: [] },
360 |     { src: "x = () => {}; x()", exp: ["x"] },
361 |     { src: "x.a = () => {}; x.a()", exp: ["x"] },
362 |     { src: "x.a = []; x.a[3] = () => {}; x.a[3]()", exp: ["x"] },
363 |     { src: "x.a = []; x.a[3] = {}; x.a[3].f = () => {}; x.a[3].f()", exp: ["x"] },
364 |     { src: "x = () => {}; x(); y = () => {}; y();", exp: ["x", "y"] },
365 |   ];
366 | 
367 |   funcCallCases.forEach((c) => {
368 |     it(`onWillUpdate (async) works ${c.src}`, async () => {
369 |       // --- Arrange
370 |       let updated: string[] = [];
371 |       const evalContext = createEvalContext({
372 |         localContext: {
373 |           x: {},
374 |           y: {},
375 |         },
376 |         onWillUpdate: (_scope, index, type) => {
377 |           if (type === "function-call") {
378 |             updated.push(index as string);
379 |           }
380 |         },
381 |       });
382 |       const statements = parseStatements(c.src);
383 | 
384 |       // --- Act
385 |       await processStatementQueueAsync(statements, evalContext);
386 | 
387 |       // --- Assert
388 |       expect(updated).toStrictEqual(c.exp);
389 |     });
390 |   });
391 | 
392 |   funcCallCases.forEach((c) => {
393 |     it(`onWillUpdate (sync) works ${c.src}`, () => {
394 |       // --- Arrange
395 |       let updated: string[] = [];
396 |       const evalContext = createEvalContext({
397 |         localContext: {
398 |           x: {},
399 |           y: {},
400 |         },
401 |         onWillUpdate: (_scope, index, type) => {
402 |           if (type === "function-call") {
403 |             updated.push(index as string);
404 |           }
405 |         },
406 |       });
407 |       const statements = parseStatements(c.src);
408 | 
409 |       // --- Act
410 |       processStatementQueue(statements, evalContext);
411 | 
412 |       // --- Assert
413 |       expect(updated).toStrictEqual(c.exp);
414 |     });
415 |   });
416 | 
417 |   funcCallCases.forEach((c) => {
418 |     it(`onDidUpdate (async) works ${c.src}`, async () => {
419 |       // --- Arrange
420 |       let updated: string[] = [];
421 |       const evalContext = createEvalContext({
422 |         localContext: {
423 |           x: {},
424 |           y: {},
425 |         },
426 |         onDidUpdate: (_scope, index, type) => {
427 |           if (type === "function-call") {
428 |             updated.push(index as string);
429 |           }
430 |         },
431 |       });
432 |       const statements = parseStatements(c.src);
433 | 
434 |       // --- Act
435 |       await processStatementQueueAsync(statements, evalContext);
436 | 
437 |       // --- Assert
438 |       expect(updated).toStrictEqual(c.exp);
439 |     });
440 |   });
441 | 
442 |   funcCallCases.forEach((c) => {
443 |     it(`onDidUpdate (sync) works ${c.src}`, () => {
444 |       // --- Arrange
445 |       let updated: string[] = [];
446 |       const evalContext = createEvalContext({
447 |         localContext: {
448 |           x: {},
449 |           y: {},
450 |         },
451 |         onDidUpdate: (_scope, index, type) => {
452 |           if (type === "function-call") {
453 |             updated.push(index as string);
454 |           }
455 |         },
456 |       });
457 |       const statements = parseStatements(c.src);
458 | 
459 |       // --- Act
460 |       processStatementQueue(statements, evalContext);
461 | 
462 |       // --- Assert
463 |       expect(updated).toStrictEqual(c.exp);
464 |     });
465 |   });
466 | });
467 | 
```
Page 58/190FirstPrevNextLast