#
tokens: 43994/50000 3/1634 files (page 96/187)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 96 of 187. Use http://codebase.md/xmlui-org/xmlui/xmlui/tools/vscode/resources/xmlui-markup-syntax-highlighting.png?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .changeset
│   ├── config.json
│   └── itchy-cases-deny.md
├── .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
│   │   │   ├── 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
│   │   │   └── PageNotFound.xmlui
│   │   ├── config.ts
│   │   ├── Main.xmlui
│   │   └── themes
│   │       └── blog-theme.ts
│   └── tsconfig.json
├── CONTRIBUTING.md
├── docs
│   ├── .gitignore
│   ├── CHANGELOG.md
│   ├── ComponentRefLinks.txt
│   ├── content
│   │   ├── _meta.json
│   │   ├── components
│   │   │   ├── _meta.json
│   │   │   ├── _overview.md
│   │   │   ├── APICall.md
│   │   │   ├── App.md
│   │   │   ├── AppHeader.md
│   │   │   ├── AppState.md
│   │   │   ├── AutoComplete.md
│   │   │   ├── Avatar.md
│   │   │   ├── Backdrop.md
│   │   │   ├── Badge.md
│   │   │   ├── BarChart.md
│   │   │   ├── Bookmark.md
│   │   │   ├── Breakout.md
│   │   │   ├── Button.md
│   │   │   ├── Card.md
│   │   │   ├── Carousel.md
│   │   │   ├── ChangeListener.md
│   │   │   ├── Checkbox.md
│   │   │   ├── CHStack.md
│   │   │   ├── ColorPicker.md
│   │   │   ├── Column.md
│   │   │   ├── ContentSeparator.md
│   │   │   ├── CVStack.md
│   │   │   ├── DataSource.md
│   │   │   ├── DateInput.md
│   │   │   ├── DatePicker.md
│   │   │   ├── DonutChart.md
│   │   │   ├── DropdownMenu.md
│   │   │   ├── EmojiSelector.md
│   │   │   ├── ExpandableItem.md
│   │   │   ├── FileInput.md
│   │   │   ├── FileUploadDropZone.md
│   │   │   ├── FlowLayout.md
│   │   │   ├── Footer.md
│   │   │   ├── Form.md
│   │   │   ├── FormItem.md
│   │   │   ├── FormSection.md
│   │   │   ├── Fragment.md
│   │   │   ├── H1.md
│   │   │   ├── H2.md
│   │   │   ├── H3.md
│   │   │   ├── H4.md
│   │   │   ├── H5.md
│   │   │   ├── H6.md
│   │   │   ├── Heading.md
│   │   │   ├── HSplitter.md
│   │   │   ├── HStack.md
│   │   │   ├── Icon.md
│   │   │   ├── IFrame.md
│   │   │   ├── Image.md
│   │   │   ├── Items.md
│   │   │   ├── LabelList.md
│   │   │   ├── Legend.md
│   │   │   ├── LineChart.md
│   │   │   ├── Link.md
│   │   │   ├── List.md
│   │   │   ├── Logo.md
│   │   │   ├── Markdown.md
│   │   │   ├── MenuItem.md
│   │   │   ├── MenuSeparator.md
│   │   │   ├── ModalDialog.md
│   │   │   ├── NavGroup.md
│   │   │   ├── NavLink.md
│   │   │   ├── NavPanel.md
│   │   │   ├── NoResult.md
│   │   │   ├── NumberBox.md
│   │   │   ├── Option.md
│   │   │   ├── Page.md
│   │   │   ├── PageMetaTitle.md
│   │   │   ├── Pages.md
│   │   │   ├── Pagination.md
│   │   │   ├── PasswordInput.md
│   │   │   ├── PieChart.md
│   │   │   ├── ProgressBar.md
│   │   │   ├── Queue.md
│   │   │   ├── RadioGroup.md
│   │   │   ├── RealTimeAdapter.md
│   │   │   ├── Redirect.md
│   │   │   ├── Select.md
│   │   │   ├── Slider.md
│   │   │   ├── Slot.md
│   │   │   ├── SpaceFiller.md
│   │   │   ├── Spinner.md
│   │   │   ├── Splitter.md
│   │   │   ├── Stack.md
│   │   │   ├── StickyBox.md
│   │   │   ├── SubMenuItem.md
│   │   │   ├── Switch.md
│   │   │   ├── TabItem.md
│   │   │   ├── Table.md
│   │   │   ├── TableOfContents.md
│   │   │   ├── Tabs.md
│   │   │   ├── Text.md
│   │   │   ├── TextArea.md
│   │   │   ├── TextBox.md
│   │   │   ├── Theme.md
│   │   │   ├── TimeInput.md
│   │   │   ├── Timer.md
│   │   │   ├── ToneChangerButton.md
│   │   │   ├── ToneSwitch.md
│   │   │   ├── Tooltip.md
│   │   │   ├── Tree.md
│   │   │   ├── VSplitter.md
│   │   │   ├── VStack.md
│   │   │   ├── xmlui-animations
│   │   │   │   ├── _meta.json
│   │   │   │   ├── _overview.md
│   │   │   │   ├── Animation.md
│   │   │   │   ├── FadeAnimation.md
│   │   │   │   ├── FadeInAnimation.md
│   │   │   │   ├── FadeOutAnimation.md
│   │   │   │   ├── ScaleAnimation.md
│   │   │   │   └── SlideInAnimation.md
│   │   │   ├── xmlui-pdf
│   │   │   │   ├── _meta.json
│   │   │   │   ├── _overview.md
│   │   │   │   └── Pdf.md
│   │   │   ├── xmlui-spreadsheet
│   │   │   │   ├── _meta.json
│   │   │   │   ├── _overview.md
│   │   │   │   └── Spreadsheet.md
│   │   │   └── xmlui-website-blocks
│   │   │       ├── _meta.json
│   │   │       ├── _overview.md
│   │   │       ├── Carousel.md
│   │   │       ├── HelloMd.md
│   │   │       ├── HeroSection.md
│   │   │       └── ScrollToTop.md
│   │   └── extensions
│   │       ├── _meta.json
│   │       ├── xmlui-animations
│   │       │   ├── _meta.json
│   │       │   ├── _overview.md
│   │       │   ├── Animation.md
│   │       │   ├── FadeAnimation.md
│   │       │   ├── FadeInAnimation.md
│   │       │   ├── FadeOutAnimation.md
│   │       │   ├── ScaleAnimation.md
│   │       │   └── SlideInAnimation.md
│   │       └── xmlui-website-blocks
│   │           ├── _meta.json
│   │           ├── _overview.md
│   │           ├── Carousel.md
│   │           ├── 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
│   │   │   ├── github.svg
│   │   │   ├── images
│   │   │   │   ├── apiaction-tutorial
│   │   │   │   │   ├── add-success.png
│   │   │   │   │   ├── apiaction-param.png
│   │   │   │   │   ├── change-completed.png
│   │   │   │   │   ├── change-in-progress.png
│   │   │   │   │   ├── confirm-delete.png
│   │   │   │   │   ├── data-error.png
│   │   │   │   │   ├── data-progress.png
│   │   │   │   │   ├── data-success.png
│   │   │   │   │   ├── display-1.png
│   │   │   │   │   ├── item-deleted.png
│   │   │   │   │   ├── item-updated.png
│   │   │   │   │   ├── missing-api-key.png
│   │   │   │   │   ├── new-item-added.png
│   │   │   │   │   └── test-message.png
│   │   │   │   ├── chat-api
│   │   │   │   │   └── domain-model.svg
│   │   │   │   ├── components
│   │   │   │   │   ├── image
│   │   │   │   │   │   └── breakfast.jpg
│   │   │   │   │   ├── markdown
│   │   │   │   │   │   └── colors.png
│   │   │   │   │   └── modal
│   │   │   │   │       ├── deep_link_dialog_1.jpg
│   │   │   │   │       └── deep_link_dialog_2.jpg
│   │   │   │   ├── create-apps
│   │   │   │   │   ├── collapsed-vertical.png
│   │   │   │   │   ├── using-forms-warning-dialog.png
│   │   │   │   │   └── using-forms.png
│   │   │   │   ├── datasource-tutorial
│   │   │   │   │   ├── data-with-header.png
│   │   │   │   │   ├── filtered-data.png
│   │   │   │   │   ├── filtered-items.png
│   │   │   │   │   ├── initial-page-items.png
│   │   │   │   │   ├── list-items.png
│   │   │   │   │   ├── next-page-items.png
│   │   │   │   │   ├── no-data.png
│   │   │   │   │   ├── pagination-1.jpg
│   │   │   │   │   ├── pagination-1.png
│   │   │   │   │   ├── polling-1.png
│   │   │   │   │   ├── refetch-data.png
│   │   │   │   │   ├── slow-loading.png
│   │   │   │   │   ├── test-message.png
│   │   │   │   │   ├── Thumbs.db
│   │   │   │   │   ├── unconventional-data.png
│   │   │   │   │   └── unfiltered-items.png
│   │   │   │   ├── flower.jpg
│   │   │   │   ├── get-started
│   │   │   │   │   ├── add-new-contact.png
│   │   │   │   │   ├── app-modified.png
│   │   │   │   │   ├── app-start.png
│   │   │   │   │   ├── app-with-boxes.png
│   │   │   │   │   ├── app-with-toast.png
│   │   │   │   │   ├── boilerplate-structure.png
│   │   │   │   │   ├── cl-initial.png
│   │   │   │   │   ├── cl-start.png
│   │   │   │   │   ├── contact-counts.png
│   │   │   │   │   ├── contact-dialog-title.png
│   │   │   │   │   ├── contact-dialog.png
│   │   │   │   │   ├── contact-menus.png
│   │   │   │   │   ├── contact-predicates.png
│   │   │   │   │   ├── context-menu.png
│   │   │   │   │   ├── dashboard-numbers.png
│   │   │   │   │   ├── default-contact-list.png
│   │   │   │   │   ├── delete-contact.png
│   │   │   │   │   ├── delete-task.png
│   │   │   │   │   ├── detailed-template.png
│   │   │   │   │   ├── edit-contact-details.png
│   │   │   │   │   ├── edited-contact-saved.png
│   │   │   │   │   ├── empty-sections.png
│   │   │   │   │   ├── filter-completed.png
│   │   │   │   │   ├── fullwidth-desktop.png
│   │   │   │   │   ├── fullwidth-mobile.png
│   │   │   │   │   ├── initial-table.png
│   │   │   │   │   ├── items-and-badges.png
│   │   │   │   │   ├── loading-message.png
│   │   │   │   │   ├── new-contact-button.png
│   │   │   │   │   ├── new-contact-saved.png
│   │   │   │   │   ├── no-empty-sections.png
│   │   │   │   │   ├── personal-todo-initial.png
│   │   │   │   │   ├── piechart.png
│   │   │   │   │   ├── review-today.png
│   │   │   │   │   ├── rudimentary-dashboard.png
│   │   │   │   │   ├── section-collapsed.png
│   │   │   │   │   ├── sectioned-items.png
│   │   │   │   │   ├── sections-ordered.png
│   │   │   │   │   ├── spacex-list-with-links.png
│   │   │   │   │   ├── spacex-list.png
│   │   │   │   │   ├── start-personal-todo-1.png
│   │   │   │   │   ├── submit-new-contact.png
│   │   │   │   │   ├── submit-new-task.png
│   │   │   │   │   ├── syntax-highlighting.png
│   │   │   │   │   ├── table-with-badge.png
│   │   │   │   │   ├── template-with-card.png
│   │   │   │   │   ├── test-emulated-api.png
│   │   │   │   │   ├── Thumbs.db
│   │   │   │   │   ├── todo-logo.png
│   │   │   │   │   └── xmlui-tools.png
│   │   │   │   ├── HelloApp.png
│   │   │   │   ├── HelloApp2.png
│   │   │   │   ├── logos
│   │   │   │   │   ├── xmlui1.svg
│   │   │   │   │   ├── xmlui2.svg
│   │   │   │   │   ├── xmlui3.svg
│   │   │   │   │   ├── xmlui4.svg
│   │   │   │   │   ├── xmlui5.svg
│   │   │   │   │   ├── xmlui6.svg
│   │   │   │   │   └── xmlui7.svg
│   │   │   │   ├── pdf
│   │   │   │   │   └── dummy-pdf.jpg
│   │   │   │   ├── rendering-engine
│   │   │   │   │   ├── AppEngine-flow.svg
│   │   │   │   │   ├── Component.svg
│   │   │   │   │   ├── CompoundComponent.svg
│   │   │   │   │   ├── RootComponent.svg
│   │   │   │   │   └── tree-with-containers.svg
│   │   │   │   ├── reviewers-guide
│   │   │   │   │   ├── AppEngine-flow.svg
│   │   │   │   │   └── incbutton-in-action.png
│   │   │   │   ├── tools
│   │   │   │   │   └── boilerplate-structure.png
│   │   │   │   ├── try.svg
│   │   │   │   ├── tutorial
│   │   │   │   │   ├── app-chat-history.png
│   │   │   │   │   ├── app-content-placeholder.png
│   │   │   │   │   ├── app-header-and-content.png
│   │   │   │   │   ├── app-links-channel-selected.png
│   │   │   │   │   ├── app-links-click.png
│   │   │   │   │   ├── app-navigation.png
│   │   │   │   │   ├── finished-ex01.png
│   │   │   │   │   ├── finished-ex02.png
│   │   │   │   │   ├── hello.png
│   │   │   │   │   ├── splash-screen-advanced.png
│   │   │   │   │   ├── splash-screen-after-click.png
│   │   │   │   │   ├── splash-screen-centered.png
│   │   │   │   │   ├── splash-screen-events.png
│   │   │   │   │   ├── splash-screen-expression.png
│   │   │   │   │   ├── splash-screen-reuse-after.png
│   │   │   │   │   ├── splash-screen-reuse-before.png
│   │   │   │   │   └── splash-screen.png
│   │   │   │   └── tutorial-01.png
│   │   │   ├── llms.txt
│   │   │   ├── logo-dark.svg
│   │   │   ├── logo.svg
│   │   │   ├── pg-popout.svg
│   │   │   └── xmlui-logo.svg
│   │   ├── serve.json
│   │   └── web.config
│   ├── scripts
│   │   ├── download-latest-xmlui.js
│   │   ├── generate-rss.js
│   │   ├── get-releases.js
│   │   └── utils.js
│   ├── src
│   │   ├── components
│   │   │   ├── BlogOverview.xmlui
│   │   │   ├── BlogPage.xmlui
│   │   │   ├── Boxes.xmlui
│   │   │   ├── Breadcrumb.xmlui
│   │   │   ├── ChangeLog.xmlui
│   │   │   ├── ColorPalette.xmlui
│   │   │   ├── DocumentLinks.xmlui
│   │   │   ├── DocumentPage.xmlui
│   │   │   ├── DocumentPageNoTOC.xmlui
│   │   │   ├── Icons.xmlui
│   │   │   ├── IncButton.xmlui
│   │   │   ├── IncButton2.xmlui
│   │   │   ├── NameValue.xmlui
│   │   │   ├── PageNotFound.xmlui
│   │   │   ├── PaletteItem.xmlui
│   │   │   ├── Palettes.xmlui
│   │   │   ├── SectionHeader.xmlui
│   │   │   ├── TBD.xmlui
│   │   │   ├── Test.xmlui
│   │   │   ├── ThemesIntro.xmlui
│   │   │   ├── ThousandThemes.xmlui
│   │   │   ├── TubeStops.xmlui
│   │   │   ├── TubeStops.xmlui.xs
│   │   │   └── TwoColumnCode.xmlui
│   │   ├── config.ts
│   │   ├── Main.xmlui
│   │   └── themes
│   │       ├── docs-theme.ts
│   │       ├── earthtone.ts
│   │       ├── xmlui-gray-on-default.ts
│   │       ├── xmlui-green-on-default.ts
│   │       └── xmlui-orange-on-default.ts
│   └── tsconfig.json
├── LICENSE
├── package-lock.json
├── package.json
├── packages
│   ├── 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.tsx
│   │       │   ├── ConfirmationDialog.module.scss
│   │       │   ├── ConfirmationDialog.tsx
│   │       │   ├── Editor.tsx
│   │       │   ├── Header.module.scss
│   │       │   ├── Header.tsx
│   │       │   ├── Playground.tsx
│   │       │   ├── PlaygroundContent.module.scss
│   │       │   ├── PlaygroundContent.tsx
│   │       │   ├── PlaygroundNative.module.scss
│   │       │   ├── PlaygroundNative.tsx
│   │       │   ├── Preview.module.scss
│   │       │   ├── Preview.tsx
│   │       │   ├── Select.module.scss
│   │       │   ├── StandalonePlayground.tsx
│   │       │   ├── StandalonePlaygroundNative.module.scss
│   │       │   ├── StandalonePlaygroundNative.tsx
│   │       │   ├── ThemeSwitcher.module.scss
│   │       │   ├── ThemeSwitcher.tsx
│   │       │   ├── ToneSwitcher.tsx
│   │       │   ├── Tooltip.module.scss
│   │       │   ├── Tooltip.tsx
│   │       │   └── utils.ts
│   │       ├── providers
│   │       │   ├── Toast.module.scss
│   │       │   └── ToastProvider.tsx
│   │       ├── state
│   │       │   └── store.ts
│   │       ├── themes
│   │       │   └── theme.ts
│   │       └── utils
│   │           └── helpers.ts
│   ├── 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
    │   │   ├── 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/_overview.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Components Overview [#components-overview]
  2 | 
  3 | | Component | Description |
  4 | | :---: | --- |
  5 | | [APICall](./APICall) | `APICall` creates, updates or deletes data on the backend, versus [`DataSource`](/components/DataSource) which fetches data. Unlike DataSource, APICall doesn't automatically execute - you must trigger it manually with the `execute()` method, typically from form submissions or button clicks. |
  6 | | [App](./App) | The `App` component is the root container that defines your application's overall structure and layout. It provides a complete UI framework with built-in navigation, header, footer, and content areas that work together seamlessly. |
  7 | | [AppHeader](./AppHeader) | `AppHeader` defines the top navigation bar of your application within the [`App`](/components/App) component. It automatically handles logo placement, application title, and user profile areas with built-in responsive behavior. |
  8 | | [AppState](./AppState) | `AppState` is an invisible component that provides global state management across your entire application. Unlike component variables that are scoped locally, AppState allows any component to access and update shared state without prop drilling. |
  9 | | [AutoComplete](./AutoComplete) | `AutoComplete` is a searchable dropdown input that allows users to type and filter through options, with support for single or multiple selections. Unlike a basic [`Select`](/components/Select), it provides type-ahead functionality and can allow users to create new options. |
 10 | | [Avatar](./Avatar) | `Avatar` displays a user or entity's profile picture as a circular image, with automatic fallback to initials when no image is provided. It's commonly used in headers, user lists, comments, and anywhere you need to represent a person or organization. |
 11 | | [Backdrop](./Backdrop) | The `Backdrop` component is a semi-transparent overlay that appears on top of its child component to obscure or highlight the content behind it. |
 12 | | [Badge](./Badge) | `Badge` displays small text labels with colored backgrounds, commonly used for status indicators, categories, tags, and counts. It supports dynamic color mapping based on content values, useful for status systems and data categorization. |
 13 | | [BarChart](./BarChart) | `BarChart` displays data as horizontal or vertical bars, supporting both grouped and stacked layouts. It's ideal for comparing values across categories, showing revenue trends, or displaying any quantitative data over time or categories. |
 14 | | [Bookmark](./Bookmark) | As its name suggests, this component places a bookmark into its parent component's view. The component has an `id` that you can use in links to navigate (scroll to) the bookmark's location. |
 15 | | [Breakout](./Breakout) | The `Breakout` component creates a breakout section. It allows its child to occupy the entire width of the UI even if the app or the parent container constrains the maximum content width. |
 16 | | [Button](./Button) | `Button` is the primary interactive component for triggering actions like form submissions, navigation, opening modals, and API calls. It supports multiple visual styles and sizes to match different UI contexts and importance levels. |
 17 | | [Card](./Card) | `Card` is a versatile container that groups related content with a visual boundary, typically featuring background color, padding, borders, and rounded corners. It's ideal for organizing information, creating sections, and establishing visual hierarchy in your interface. |
 18 | | [Carousel](./Carousel) | This component displays a slideshow by cycling through elements (images, text, or custom slides) like a carousel. |
 19 | | [ChangeListener](./ChangeListener) | `ChangeListener` is an invisible component that watches for changes in values and triggers actions in response. It's essential for creating reactive behavior when you need to respond to data changes, state updates, or component property modifications outside of normal event handlers. |
 20 | | [Checkbox](./Checkbox) | `Checkbox` allows users to make binary choices with a clickable box that shows checked/unchecked states. It's essential for settings, preferences, multi-select lists, and accepting terms or conditions. |
 21 | | [CHStack](./CHStack) | This component represents a stack that renders its contents horizontally and aligns that in the center along both axes. |
 22 | | [ColorPicker](./ColorPicker) | `ColorPicker` enables users to choose colors by specifying RGB, HSL, or HEX values. |
 23 | | [Column](./Column) | `Column` defines the structure and behavior of individual table columns within a [`Table`](/components/Table) component. Each Column controls data binding, header display, sorting capabilities, sizing, and can contain any XMLUI components for rich cell content. |
 24 | | [ContentSeparator](./ContentSeparator) | `ContentSeparator` creates visual dividers between content sections using horizontal or vertical lines. It's essential for improving readability by breaking up dense content, separating list items, or creating clear boundaries between different UI sections. |
 25 | | [CVStack](./CVStack) | This component represents a stack that renders its contents vertically and aligns that in the center along both axes. |
 26 | | [DataSource](./DataSource) | `DataSource` fetches and caches data from API endpoints, versus [`APICall`](/components/APICall) which creates, updates or deletes data. |
 27 | | [DateInput](./DateInput) | `DateInput` provides a text-based date input interface for selecting single dates or date ranges, with direct keyboard input similar to TimeInput. It offers customizable formatting and validation options without dropdown calendars. |
 28 | | [DatePicker](./DatePicker) | `DatePicker` provides an interactive calendar interface for selecting single dates or date ranges, with customizable formatting and validation options. It displays a text input that opens a calendar popup when clicked, offering both keyboard and mouse interaction. |
 29 | | [DonutChart](./DonutChart) | A derivative of [PieChart](/components/PieChart) with a hollow center. Note that the height of the component or its parent needs to be set explicitly. |
 30 | | [DropdownMenu](./DropdownMenu) | `DropdownMenu` provides a space-efficient way to present multiple options or actions through a collapsible interface. When clicked, the trigger button reveals a menu that can include items, separators, and nested submenus, making it ideal for navigation, action lists, or any situation requiring many options without permanent screen space. |
 31 | | [EmojiSelector](./EmojiSelector) | `EmojiSelector` enables users to browse, search and select emojis from their system's native emoji set. |
 32 | | [ExpandableItem](./ExpandableItem) | `ExpandableItem` creates expandable/collapsible section, similar to the HTML details disclosure element. When the user clicks on the `summary` the content expands or collapses. |
 33 | | [FileInput](./FileInput) | `FileInput` enables users to select files from their device's file system for upload or processing. It combines a text field displaying selected files with a customizable button that opens the system file browser. Use it for forms, media uploads, and document processing workflows. |
 34 | | [FileUploadDropZone](./FileUploadDropZone) | `FileUploadDropZone` enables users to upload files by dragging and dropping files from their local file system onto a designated area within the UI. |
 35 | | [FlowLayout](./FlowLayout) | `FlowLayout` positions content in rows with automatic wrapping. When items exceed the available horizontal space, they automatically wrap to a new line. |
 36 | | [Footer](./Footer) | `Footer` provides a designated area at the bottom of your application for footer content such as branding, copyright notices, or utility controls like theme toggles. |
 37 | | [Form](./Form) | `Form` provides a structured container for collecting and validating user input, with built-in data binding, validation, and submission handling. It automatically manages form state and provides context for nested form controls to work together. |
 38 | | [FormItem](./FormItem) | `FormItem` wraps individual input controls within a `Form`, providing data binding, validation, labeling, and layout functionality. It connects form controls to the parent form's data model and handles validation feedback automatically.
 39 | 
 40 | > **Note:** `FormItem` must be used inside a `Form` component. |
 41 | | [FormSection](./FormSection) | `FormSection` groups elements within a `Form`. Child components are placed in a [FlowLayout](/components/FlowLayout). |
 42 | | [Fragment](./Fragment) | `Fragment` provides conditional rendering. You can use `when=` on any component to render it conditionally, use `Fragment` to apply `when` to a group of components. |
 43 | | [H1](./H1) | Represents a heading level 1 text |
 44 | | [H2](./H2) | Represents a heading level 2 text |
 45 | | [H3](./H3) | Represents a heading level 3 text |
 46 | | [H4](./H4) | Represents a heading level 4 text |
 47 | | [H5](./H5) | Represents a heading level 5 text |
 48 | | [H6](./H6) | Represents a heading level 6 text |
 49 | | [Heading](./Heading) | `Heading` displays hierarchical text headings with semantic importance levels from H1 to H6, following HTML heading standards. It provides text overflow handling, anchor link generation, and integrates with [TableOfContents](/components/TableOfContents). |
 50 | | [HSplitter](./HSplitter) | `Splitter` component divides a container into two resizable sections. These are are identified by their names: primary and secondary. They have a draggable bar between them. |
 51 | | [HStack](./HStack) | This component represents a stack rendering its contents horizontally. |
 52 | | [Icon](./Icon) | `Icon` displays scalable vector icons from XMLUI's built-in icon registry using simple name references. Icons are commonly used in buttons, navigation elements, and status indicators. |
 53 | | [IFrame](./IFrame) | `IFrame` embeds external content from another HTML document into the current page. It provides security controls through sandbox and allow attributes, and supports features like fullscreen display and referrer policy configuration. |
 54 | | [Image](./Image) | `Image` displays pictures from URLs or local sources with built-in responsive sizing, aspect ratio control, and accessibility features. It handles different image formats and provides options for lazy loading and click interactions. |
 55 | | [Items](./Items) | `Items` renders data arrays without built-in layout or styling, providing a lightweight alternative to `List`. Unlike `List`, it provides no virtualization, grouping, or visual formatting — just pure data iteration. |
 56 | | [LabelList](./LabelList) | `LabelList` adds custom data labels to chart components when automatic labeling isn't sufficient. It's a specialized component for advanced chart customization scenarios where you need precise control over label positioning and appearance. |
 57 | | [Legend](./Legend) | `Legend` provides a standalone legend for chart components when you need custom positioning or styling beyond the chart's built-in `showLegend` property. Most charts can display legends automatically, but this component offers precise control over legend placement and alignment. |
 58 | | [LineChart](./LineChart) | `LineChart` displays data as connected points over a continuous axis, ideal for showing trends, changes over time, or relationships between variables. Use it time series data, progress tracking, and comparing multiple data series on the same scale. |
 59 | | [Link](./Link) | `Link` creates clickable navigation elements for internal app routes or external URLs. You can use the `label` and `icon` properties for simple text links, or embed custom components like buttons, cards, or complex layouts for rich interactive link presentations. |
 60 | | [List](./List) | `List` is a high-performance, virtualized container for rendering large datasets with built-in grouping, sorting, and visual formatting. It only renders visible items in the viewport, making it ideal for displaying thousands of records while maintaining smooth scrolling performance. |
 61 | | [Logo](./Logo) | `Logo` displays your application's brand symbol by automatically loading logo images defined in the app manifest. While logos are typically configured using App-level properties (`logo`, `logo-dark`), this component provides direct control when you need custom logo placement or templating. |
 62 | | [Markdown](./Markdown) | `Markdown` renders formatted text using markdown syntax. Use [Text](/working-with-text) for simple, styled text content, and `Markdown` when you need [rich formatting](/working-with-markdown). |
 63 | | [MenuItem](./MenuItem) | `MenuItem` represents individual clickable items within dropdown menus and other menu components. Each menu item can display text, icons, and respond to clicks with either navigation or custom actions, making it the building block for interactive menu systems. |
 64 | | [MenuSeparator](./MenuSeparator) | `MenuSeparator` displays a separator line between menu items to group related menu options within `DropdownMenu`. |
 65 | | [ModalDialog](./ModalDialog) | `ModalDialog` creates overlay dialogs that appear on top of the main interface, ideal for forms, confirmations, detailed views, or any content that requires focused user attention. Dialogs are programmatically opened using the `open()` method and can receive parameters for dynamic content. |
 66 | | [NavGroup](./NavGroup) | `NavGroup` creates collapsible containers for organizing related navigation items into hierarchical menu structures. It groups `NavLink` components and other `NavGroup` components, providing expandable submenus with customizable icons and states. |
 67 | | [NavLink](./NavLink) | `NavLink` creates interactive navigation items that connect users to different destinations within an app or external URLs. It automatically indicates active states, supports custom icons and labels, and can execute custom actions instead of navigation when needed. |
 68 | | [NavPanel](./NavPanel) | `NavPanel` defines the navigation structure within an App, serving as a container for NavLink and NavGroup components that create your application's primary navigation menu. Its appearance and behavior automatically adapt based on the App's layout configuration. |
 69 | | [NoResult](./NoResult) | `NoResult` displays a visual indication that a query or search returned nothing. |
 70 | | [NumberBox](./NumberBox) | `NumberBox` provides a specialized input field for numeric values with built-in validation, spinner buttons, and flexible formatting options. It supports both integer and floating-point numbers, handles empty states as null values, and integrates seamlessly with form validation. |
 71 | | [Option](./Option) | `Option` defines selectable items for choice-based components, providing both the underlying value and display text for selection interfaces. It serves as a non-visual data structure that describes individual choices within [Select](/components/Select), [AutoComplete](/components/AutoComplete), and other selection components. |
 72 | | [Page](./Page) | `Page` defines route endpoints within an application, mapping specific URL patterns to content that displays when users navigate to those routes. Each Page represents a distinct view or screen in your single-page application's routing system. |
 73 | | [PageMetaTitle](./PageMetaTitle) | `PageMetaTitle` dynamically sets or updates the browser tab title, enabling pages and components to override the default application name with context-specific titles. |
 74 | | [Pages](./Pages) | `Pages` serves as the routing coordinator within an [App](/components/App), managing which [Page](/components/Page)  displays based on the current URL. |
 75 | | [Pagination](./Pagination) | `Pagination` enables navigation through large datasets by dividing content into pages. It provides controls for page navigation and can display current page information. |
 76 | | [PasswordInput](./PasswordInput) | `Password` is a specialized [TextBox](/components/TextBox) that enables users to input and edit passwords. |
 77 | | [PieChart](./PieChart) | `PieChart` visualizes proportional data as circular segments; each slice represents a percentage of the whole. Note that the height of the component or its parent needs to be set explicitly. |
 78 | | [ProgressBar](./ProgressBar) | `ProgressBar` provides a visual indicator showing the completion percentage of tasks, processes, or any measurable progress. It displays as a horizontal bar that fills from left to right based on the provided value between 0 (empty) and 1 (complete). |
 79 | | [Queue](./Queue) | `Queue` manages sequential processing of items in FIFO (first-in, first-out) order. It is a non-visual component but provides UI progress reporting and result display. |
 80 | | [RadioGroup](./RadioGroup) | `RadioGroup` creates a mutually exclusive selection interface where users can choose only one option from a group of radio buttons. It manages the selection state and ensures that selecting one option automatically deselects all others in the group.
 81 | 
 82 | Radio options store their values as strings. Numbers and booleans are converted to strings when assigned, while objects, functions and arrays default to an empty string unless resolved via binding expressions. |
 83 | | [RealTimeAdapter](./RealTimeAdapter) | `RealTimeAdapter` is a non-visual component that listens to real-time events. |
 84 | | [Redirect](./Redirect) | `Redirect` immediately redirects the browser to the URL in its `to` property when it gets visible (its `when` property gets `true`). It works only within [App](/components/App), not externally. |
 85 | | [Select](./Select) | `Select` provides a dropdown interface for choosing from a list of options, supporting both single and multiple selection modes. It offers extensive customization capabilities including search functionality, custom templates, and comprehensive form integration. |
 86 | | [Slider](./Slider) | `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.
 87 | 
 88 | Hover over the component to see the tooltip with the current value. On mobile, tap the thumb to see the tooltip. |
 89 | | [Slot](./Slot) | Placeholder in a reusable component. Signs the slot where the component's injected children should be rendered. |
 90 | | [SpaceFiller](./SpaceFiller) | `SpaceFiller` works well in layout containers to fill remaining (unused) space. Its behavior depends on the layout container in which it is used. |
 91 | | [Spinner](./Spinner) | `Spinner` is an animated indicator that represents an action in progress with no deterministic progress value. |
 92 | | [Splitter](./Splitter) | `Splitter` component divides a container into two resizable sections. These are are identified by their names: primary and secondary. They have a draggable bar between them. |
 93 | | [Stack](./Stack) | `Stack` is the fundamental layout container that organizes child elements in configurable horizontal or vertical arrangements. As the most versatile building block in XMLUI's layout system, it provides comprehensive alignment, spacing, and flow control options that serve as the foundation for all specialized stack variants. |
 94 | | [StickyBox](./StickyBox) | `StickyBox` remains fixed at the top or bottom of the screen as the user scrolls. |
 95 | | [SubMenuItem](./SubMenuItem) | `SubMenuItem` creates hierarchical menu structures by acting as both a menu item and a container for nested menu items. When clicked or hovered, it reveals a submenu containing additional [MenuItem](/components/MenuItem), [MenuSeparator](/components/MenuSeparator), or other [SubMenuItem](/components/SubMenuItems) components, enabling complex multi-level navigation and action organization. |
 96 | | [Switch](./Switch) | `Switch` enables users to toggle between two states: on and off. |
 97 | | [TabItem](./TabItem) | `TabItem` defines individual tabs within a [Tabs](/components/Tabs) component, providing both the tab header label and the content that displays when the tab is selected. As a non-visual structural component, it serves as a container that organizes content into distinct, switchable sections. |
 98 | | [Table](./Table) | `Table` presents structured data for viewing, sorting, selection, and interaction. |
 99 | | [TableOfContents](./TableOfContents) | `TableOfContents` component collects [Heading](/components/Heading) and [Bookmark](/components/Bookmark) within the current page and displays them in a navigable tree. |
100 | | [Tabs](./Tabs) | `Tabs` enables users to switch among content panels using clickable tab headers. It provides an efficient way to present multiple related sections in a single interface area, with each tab containing distinct content defined by [TabItem](/components/TabItem) components. |
101 | | [Text](./Text) | The `Text` component displays textual information in a number of optional styles and variants. |
102 | | [TextArea](./TextArea) | `TextArea` provides a multiline text input area. |
103 | | [TextBox](./TextBox) | `TextBox` captures user text input for forms, search fields, and data entry with support for validation, icons, and formatting hints. |
104 | | [Theme](./Theme) | `Theme` creates styling contexts to customize the appearance of nested components without using CSS. |
105 | | [TimeInput](./TimeInput) | `TimeInput` provides time input with support for 12-hour and 24-hour formats and configurable precision for hours, minutes, and seconds. |
106 | | [Timer](./Timer) | `Timer` is a non-visual component that fires events at regular intervals. It can be enabled or disabled and ensures that the timer event handler completes before firing the next event. |
107 | | [ToneChangerButton](./ToneChangerButton) | `ToneChangerButton` enables the user to switch between light and dark modes. |
108 | | [ToneSwitch](./ToneSwitch) | `ToneSwitch` enables the user to switch between light and dark modes using a switch control. |
109 | | [Tooltip](./Tooltip) | A tooltip component that displays text when hovering over trigger content. |
110 | | [Tree](./Tree) | The `Tree` component is a virtualized tree component that displays hierarchical data with support for flat and hierarchy data formats. |
111 | | [VSplitter](./VSplitter) | `Splitter` component divides a container into two resizable sections. These are are identified by their names: primary and secondary. They have a draggable bar between them. |
112 | | [VStack](./VStack) | This component represents a stack rendering its contents vertically. |
113 | 
114 | 
```

--------------------------------------------------------------------------------
/xmlui/src/components/ExpandableItem/ExpandableItem.spec.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { test, expect } from "../../testing/fixtures";
  2 | import { ExpandableItemDriver } from "../../testing/ComponentDrivers";
  3 | 
  4 | // =============================================================================
  5 | // BASIC FUNCTIONALITY TESTS
  6 | // =============================================================================
  7 | 
  8 | test("component renders with basic props", async ({ initTestBed, createExpandableItemDriver }) => {
  9 |   await initTestBed(`<ExpandableItem summary="Test Summary">Content here</ExpandableItem>`, {});
 10 |   const driver = await createExpandableItemDriver();
 11 |   
 12 |   await expect(driver.component).toBeVisible();
 13 |   await expect(driver.getSummaryContent()).toContainText("Test Summary");
 14 |   await expect(driver.getContent()).not.toBeVisible(); // Initially collapsed
 15 | });
 16 | 
 17 | test("component displays summary content correctly", async ({ initTestBed, createExpandableItemDriver }) => {
 18 |   await initTestBed(`<ExpandableItem summary="My Summary">Content</ExpandableItem>`, {});
 19 |   const driver = await createExpandableItemDriver();
 20 |   
 21 |   await expect(driver.getSummaryContent()).toContainText("My Summary");
 22 |   await expect(driver.getSummary()).toBeVisible();
 23 | });
 24 | 
 25 | test("component handles initiallyExpanded prop", async ({ initTestBed, createExpandableItemDriver }) => {
 26 |   await initTestBed(`<ExpandableItem summary="Test" initiallyExpanded="true">Content here</ExpandableItem>`, {});
 27 |   const driver = await createExpandableItemDriver();
 28 |   
 29 |   await expect(driver.getContent()).toBeVisible();
 30 |   await expect(driver.getContent()).toContainText("Content here");
 31 | });
 32 | 
 33 | test("component toggles on summary click", async ({ initTestBed, createExpandableItemDriver }) => {
 34 |   await initTestBed(`<ExpandableItem summary="Click me">Hidden content</ExpandableItem>`, {});
 35 |   const driver = await createExpandableItemDriver();
 36 |   
 37 |   // Initially collapsed
 38 |   await expect(driver.getContent()).not.toBeVisible();
 39 |   
 40 |   // Click to expand
 41 |   await driver.getSummary().click();
 42 |   await expect(driver.getContent()).toBeVisible();
 43 |   
 44 |   // Click to collapse
 45 |   await driver.getSummary().click();
 46 |   await expect(driver.getContent()).not.toBeVisible();
 47 | });
 48 | 
 49 | test("component displays correct icons for collapsed and expanded states", async ({ initTestBed, createExpandableItemDriver }) => {
 50 |   await initTestBed(`<ExpandableItem summary="Test">Content</ExpandableItem>`, {});
 51 |   const driver = await createExpandableItemDriver();
 52 |   
 53 |   // Initially collapsed - should show chevronright icon
 54 |   await expect(driver.getIcon()).toBeVisible();
 55 |   
 56 |   // Expand and check icon changes
 57 |   await driver.getSummary().click();
 58 |   await expect(driver.getIcon()).toBeVisible();
 59 | });
 60 | 
 61 | test("component handles custom icons", async ({ initTestBed, createExpandableItemDriver }) => {
 62 |   await initTestBed(`
 63 |     <ExpandableItem 
 64 |       summary="Test" 
 65 |       iconCollapsed="plus" 
 66 |       iconExpanded="minus">
 67 |       Content
 68 |     </ExpandableItem>
 69 |   `, {});
 70 |   const driver = await createExpandableItemDriver();
 71 |   
 72 |   await expect(driver.getIcon()).toBeVisible();
 73 |   
 74 |   // Expand to see expanded icon
 75 |   await driver.getSummary().click();
 76 |   await expect(driver.getIcon()).toBeVisible();
 77 | });
 78 | 
 79 | test("component supports iconPosition prop", async ({ initTestBed, createExpandableItemDriver }) => {
 80 |   await initTestBed(`<ExpandableItem summary="Test" iconPosition="start">Content</ExpandableItem>`, {});
 81 |   const driver = await createExpandableItemDriver();
 82 |   
 83 |   const className = await driver.getSummary().getAttribute('class');
 84 |   expect(className).toMatch(/iconStart/);
 85 |   await expect(driver.getIcon()).toBeVisible();
 86 | });
 87 | 
 88 | test("component handles withSwitch prop", async ({ initTestBed, createExpandableItemDriver }) => {
 89 |   await initTestBed(`<ExpandableItem summary="Test" withSwitch="true">Content</ExpandableItem>`, {});
 90 |   const driver = await createExpandableItemDriver();
 91 |   
 92 |   // Check that the switch container (aria-hidden div) is present
 93 |   const switchContainer = driver.getSummary().locator('[aria-hidden="true"]');
 94 |   await expect(switchContainer).toBeVisible();
 95 |   await expect(driver.getIcon()).not.toBeVisible();
 96 | });
 97 | 
 98 | // =============================================================================
 99 | // ACCESSIBILITY TESTS
100 | // =============================================================================
101 | 
102 | test("component has correct accessibility attributes", async ({ initTestBed, createExpandableItemDriver, page }) => {
103 |   await initTestBed(`<ExpandableItem summary="Test Summary">Content here</ExpandableItem>`, {});
104 |   const driver = await createExpandableItemDriver();
105 |   
106 |   const summary = driver.getSummary();
107 |   
108 |   // Summary should have proper button role and ARIA attributes
109 |   await expect(summary).toHaveRole("button");
110 |   await expect(summary).toHaveAttribute("aria-expanded", "false");
111 |   await expect(summary).toHaveAttribute("aria-disabled", "false");
112 |   await expect(summary).toHaveAttribute("tabindex", "0");
113 |   await expect(summary).toHaveAttribute("aria-controls");
114 |   await expect(summary).toHaveAttribute("id");
115 | });
116 | 
117 | test("component ARIA attributes update with expansion state", async ({ initTestBed, createExpandableItemDriver, page }) => {
118 |   await initTestBed(`<ExpandableItem summary="Test Summary">Content here</ExpandableItem>`, {});
119 |   const driver = await createExpandableItemDriver();
120 |   
121 |   const summary = driver.getSummary();
122 |   
123 |   // Initially collapsed
124 |   await expect(summary).toHaveAttribute("aria-expanded", "false");
125 |   
126 |   // Expand
127 |   await summary.click();
128 |   await expect(summary).toHaveAttribute("aria-expanded", "true");
129 |   
130 |   // Collapse
131 |   await summary.click();
132 |   await expect(summary).toHaveAttribute("aria-expanded", "false");
133 | });
134 | 
135 | test("component content region has correct ARIA attributes", async ({ initTestBed, createExpandableItemDriver, page }) => {
136 |   await initTestBed(`<ExpandableItem summary="Test Summary" initiallyExpanded="true">Content here</ExpandableItem>`, {});
137 |   const driver = await createExpandableItemDriver();
138 |   
139 |   const summary = driver.getSummary();
140 |   const content = driver.getContent();
141 |   
142 |   // Content should have region role and proper labeling
143 |   await expect(content).toHaveRole("region");
144 |   await expect(content).toHaveAttribute("aria-labelledby");
145 |   await expect(content).toHaveAttribute("id");
146 |   
147 |   // Verify ARIA relationship between summary and content
148 |   const summaryId = await summary.getAttribute("id");
149 |   const contentAriaLabelledBy = await content.getAttribute("aria-labelledby");
150 |   const summaryAriaControls = await summary.getAttribute("aria-controls");
151 |   const contentId = await content.getAttribute("id");
152 |   
153 |   expect(contentAriaLabelledBy).toBe(summaryId);
154 |   expect(summaryAriaControls).toBe(contentId);
155 | });
156 | 
157 | test("component is keyboard accessible with Enter key", async ({ initTestBed, createExpandableItemDriver, page }) => {
158 |   const { testStateDriver } = await initTestBed(`<ExpandableItem summary="Test" onExpandedChange="arg => testState = arg">Content</ExpandableItem>`, {});
159 |   const driver = await createExpandableItemDriver();
160 |   
161 |   const summary = driver.getSummary();
162 |   
163 |   // Focus the summary button
164 |   await summary.focus();
165 |   await expect(summary).toBeFocused();
166 |   
167 |   // Press Enter to toggle
168 |   await summary.press("Enter");
169 |   await expect.poll(testStateDriver.testState).toEqual(true);
170 |   await expect(driver.getContent()).toBeVisible();
171 |   
172 |   // Press Enter again to collapse
173 |   await summary.press("Enter");
174 |   await expect.poll(testStateDriver.testState).toEqual(false);
175 |   await expect(driver.getContent()).not.toBeVisible();
176 | });
177 | 
178 | test("component is keyboard accessible with Space key", async ({ initTestBed, createExpandableItemDriver, page }) => {
179 |   const { testStateDriver } = await initTestBed(`<ExpandableItem summary="Test" onExpandedChange="arg => testState = arg">Content</ExpandableItem>`, {});
180 |   const driver = await createExpandableItemDriver();
181 |   
182 |   const summary = driver.getSummary();
183 |   
184 |   // Focus the summary button
185 |   await summary.focus();
186 |   await expect(summary).toBeFocused();
187 |   
188 |   // Press Space to toggle
189 |   await summary.press(" ");
190 |   await expect.poll(testStateDriver.testState).toEqual(true);
191 |   await expect(driver.getContent()).toBeVisible();
192 |   
193 |   // Press Space again to collapse
194 |   await summary.press(" ");
195 |   await expect.poll(testStateDriver.testState).toEqual(false);
196 |   await expect(driver.getContent()).not.toBeVisible();
197 | });
198 | 
199 | test("component maintains focus after keyboard toggle", async ({ initTestBed, createExpandableItemDriver, page }) => {
200 |   await initTestBed(`<ExpandableItem summary="Test">Content</ExpandableItem>`, {});
201 |   const driver = await createExpandableItemDriver();
202 |   
203 |   const summary = driver.getSummary();
204 |   
205 |   // Focus and expand with keyboard
206 |   await summary.focus();
207 |   await expect(summary).toBeFocused();
208 |   await summary.press("Enter");
209 |   await expect(driver.getContent()).toBeVisible();
210 |   await expect(summary).toBeFocused(); // Focus should remain
211 |   
212 |   // Collapse with keyboard
213 |   await summary.press("Space");
214 |   await expect(driver.getContent()).not.toBeVisible();
215 |   await expect(summary).toBeFocused(); // Focus should still remain
216 | });
217 | 
218 | test("component is focusable only when enabled", async ({ initTestBed, createExpandableItemDriver, page }) => {
219 |   await initTestBed(`<ExpandableItem summary="Test" enabled="false">Content</ExpandableItem>`, {});
220 |   const driver = await createExpandableItemDriver();
221 |   
222 |   const summary = driver.getSummary();
223 |   
224 |   // Disabled component should not be focusable (no tabindex attribute)
225 |   await expect(summary).not.toHaveAttribute("tabindex");
226 |   await expect(summary).toHaveAttribute("aria-disabled", "true");
227 | });
228 | 
229 | test("component keyboard interaction works with switch variant", async ({ initTestBed, createExpandableItemDriver, page }) => {
230 |   const { testStateDriver } = await initTestBed(`<ExpandableItem summary="Test" withSwitch="true" onExpandedChange="arg => testState = arg">Content</ExpandableItem>`, {});
231 |   const driver = await createExpandableItemDriver();
232 |   
233 |   const summary = driver.getSummary();
234 |   
235 |   // Focus and activate with Enter
236 |   await summary.focus();
237 |   await summary.press("Enter");
238 |   await expect.poll(testStateDriver.testState).toEqual(true);
239 |   await expect(driver.getContent()).toBeVisible();
240 |   
241 |   // Deactivate with Space
242 |   await summary.press(" ");
243 |   await expect.poll(testStateDriver.testState).toEqual(false);
244 |   await expect(driver.getContent()).not.toBeVisible();
245 | });
246 | 
247 | test("component icon/switch container is hidden from screen readers", async ({ initTestBed, createExpandableItemDriver, page }) => {
248 |   await initTestBed(`<ExpandableItem summary="Test">Content</ExpandableItem>`, {});
249 |   const driver = await createExpandableItemDriver();
250 |   
251 |   // Icon container should be aria-hidden
252 |   const iconContainer = driver.getSummary().locator('[class*="icon"]');
253 |   await expect(iconContainer).toHaveAttribute("aria-hidden", "true");
254 | });
255 | 
256 | test("component supports screen reader navigation", async ({ initTestBed, createExpandableItemDriver }) => {
257 |   await initTestBed(`<ExpandableItem summary="Accessible Summary">Screen reader content</ExpandableItem>`, {});
258 |   const driver = await createExpandableItemDriver();
259 |   
260 |   // Summary should be properly announced as a button
261 |   const summary = driver.getSummary();
262 |   await expect(summary).toHaveRole("button");
263 |   await summary.click();
264 |   await expect(driver.getContent()).toBeVisible();
265 | });
266 | 
267 | // =============================================================================
268 | // VISUAL STATE TESTS
269 | // =============================================================================
270 | 
271 | test("component applies theme variables", async ({ initTestBed, createExpandableItemDriver }) => {
272 |   await initTestBed(`<ExpandableItem summary="Test">Content</ExpandableItem>`, {
273 |     testThemeVars: { "backgroundColor-ExpandableItem": "rgb(255, 0, 0)" }
274 |   });
275 |   const driver = await createExpandableItemDriver();
276 |   await expect(driver.component).toHaveCSS("background-color", "rgb(255, 0, 0)");
277 | });
278 | 
279 | test("component applies disabled visual state", async ({ initTestBed, createExpandableItemDriver }) => {
280 |   await initTestBed(`<ExpandableItem summary="Test" enabled="false">Content</ExpandableItem>`, {});
281 |   const driver = await createExpandableItemDriver();
282 |   
283 |   const className = await driver.component.getAttribute('class');
284 |   expect(className).toMatch(/disabled/);
285 | });
286 | 
287 | test("component applies expanded visual state", async ({ initTestBed, createExpandableItemDriver }) => {
288 |   await initTestBed(`<ExpandableItem summary="Test" initiallyExpanded="true">Content</ExpandableItem>`, {});
289 |   const driver = await createExpandableItemDriver();
290 |   
291 |   // Instead of checking for CSS class, check that content is visible when initially expanded
292 |   await expect(driver.getContent()).toBeVisible();
293 |   await expect(driver.getContent()).toContainText("Content");
294 | });
295 | 
296 | test("component applies withSwitch visual state", async ({ initTestBed, createExpandableItemDriver }) => {
297 |   await initTestBed(`<ExpandableItem summary="Test" withSwitch="true">Content</ExpandableItem>`, {});
298 |   const driver = await createExpandableItemDriver();
299 |   
300 |   const className = await driver.component.getAttribute('class');
301 |   expect(className).toMatch(/withSwitch/);
302 | });
303 | 
304 | test("component handles icon position styling", async ({ initTestBed, createExpandableItemDriver }) => {
305 |   await initTestBed(`<ExpandableItem summary="Test" iconPosition="end">Content</ExpandableItem>`, {});
306 |   const driver = await createExpandableItemDriver();
307 |   
308 |   const className = await driver.getSummary().getAttribute('class');
309 |   expect(className).toMatch(/iconEnd/);
310 | });
311 | 
312 | // =============================================================================
313 | // EDGE CASE TESTS
314 | // =============================================================================
315 | 
316 | test("component handles null and undefined props gracefully", async ({ initTestBed, createExpandableItemDriver }) => {
317 |   await initTestBed(`<ExpandableItem>Content without summary</ExpandableItem>`, {});
318 |   const driver = await createExpandableItemDriver();
319 |   
320 |   await expect(driver.component).toBeVisible();
321 |   await expect(driver.getSummary()).toBeVisible();
322 | });
323 | 
324 | test("component handles empty summary", async ({ initTestBed, createExpandableItemDriver }) => {
325 |   await initTestBed(`<ExpandableItem summary="">Content</ExpandableItem>`, {});
326 |   const driver = await createExpandableItemDriver();
327 |   
328 |   await expect(driver.component).toBeVisible();
329 |   await expect(driver.getSummary()).toBeVisible();
330 | });
331 | 
332 | test("component handles empty content", async ({ initTestBed, createExpandableItemDriver }) => {
333 |   await initTestBed(`<ExpandableItem summary="Test"></ExpandableItem>`, {});
334 |   const driver = await createExpandableItemDriver();
335 |   
336 |   await expect(driver.component).toBeVisible();
337 |   await driver.getSummary().click();
338 |   await expect(driver.getContent()).toBeVisible();
339 | });
340 | 
341 | test("component handles special characters in summary", async ({ initTestBed, createExpandableItemDriver }) => {
342 |   await initTestBed(`<ExpandableItem summary="Test with émojis 🚀 & quotes">Content</ExpandableItem>`, {});
343 |   const driver = await createExpandableItemDriver();
344 |   
345 |   await expect(driver.getSummaryContent()).toContainText("Test with émojis 🚀 & quotes");
346 | });
347 | 
348 | test("component handles complex summary content", async ({ initTestBed, createExpandableItemDriver }) => {
349 |   await initTestBed(`
350 |     <ExpandableItem summary="Complex Summary">
351 |       Content here
352 |     </ExpandableItem>
353 |   `, {});
354 |   const driver = await createExpandableItemDriver();
355 |   
356 |   await expect(driver.getSummary()).toBeVisible();
357 |   await expect(driver.getSummaryContent()).toContainText("Complex Summary");
358 | });
359 | 
360 | test("component handles disabled state interaction", async ({ initTestBed, createExpandableItemDriver }) => {
361 |   await initTestBed(`<ExpandableItem summary="Test" enabled="false">Content</ExpandableItem>`, {});
362 |   const driver = await createExpandableItemDriver();
363 |   
364 |   // Should not expand when disabled - use force click since the element is aria-disabled
365 |   await driver.getSummary().click({ force: true });
366 |   await expect(driver.getContent()).not.toBeVisible();
367 | });
368 | 
369 | // =============================================================================
370 | // PERFORMANCE TESTS
371 | // =============================================================================
372 | 
373 | test("component memoization prevents unnecessary re-renders", async ({ initTestBed, createExpandableItemDriver }) => {
374 |   const { testStateDriver } = await initTestBed(`
375 |     <ExpandableItem 
376 |       summary="Test" 
377 |       onExpandedChange="testState = (testState || 0) + 1">
378 |       Content
379 |     </ExpandableItem>
380 |   `, {});
381 |   const driver = await createExpandableItemDriver();
382 |   
383 |   // Expand
384 |   await driver.getSummary().click();
385 |   await expect.poll(testStateDriver.testState).toEqual(1);
386 |   
387 |   // Collapse
388 |   await driver.getSummary().click();
389 |   await expect.poll(testStateDriver.testState).toEqual(2);
390 | });
391 | 
392 | test("component handles rapid toggling", async ({ initTestBed, createExpandableItemDriver }) => {
393 |   await initTestBed(`<ExpandableItem summary="Test">Content</ExpandableItem>`, {});
394 |   const driver = await createExpandableItemDriver();
395 |   
396 |   // Rapid clicks
397 |   await driver.getSummary().click();
398 |   await driver.getSummary().click();
399 |   await driver.getSummary().click();
400 |   
401 |   // Should end up collapsed (odd number of clicks)
402 |   await expect(driver.getContent()).toBeVisible();
403 | });
404 | 
405 | test("component handles large content efficiently", async ({ initTestBed, createExpandableItemDriver }) => {
406 |   const largeContent = "Very long content ".repeat(100);
407 |   await initTestBed(`<ExpandableItem summary="Test">${largeContent}</ExpandableItem>`, {});
408 |   const driver = await createExpandableItemDriver();
409 |   
410 |   await driver.getSummary().click();
411 |   await expect(driver.getContent()).toBeVisible();
412 |   await expect(driver.getContent()).toContainText("Very long content");
413 | });
414 | 
415 | // =============================================================================
416 | // INTEGRATION TESTS
417 | // =============================================================================
418 | 
419 | test("component works in layout contexts", async ({ initTestBed, createExpandableItemDriver }) => {
420 |   await initTestBed(`
421 |     <VStack gap="2">
422 |       <ExpandableItem summary="First Item">First content</ExpandableItem>
423 |       <ExpandableItem summary="Second Item">Second content</ExpandableItem>
424 |     </VStack>
425 |   `, {});
426 |   const driver = await createExpandableItemDriver();
427 |   
428 |   await expect(driver.component).toBeVisible();
429 |   // Use first() to get the first ExpandableItem's summary content
430 |   await expect(driver.getSummaryContent().first()).toContainText("First Item");
431 | });
432 | 
433 | test("component API methods work correctly", async ({ initTestBed, page }) => {
434 |   await initTestBed(`
435 |     <Fragment>
436 |       <ExpandableItem id="expandable" summary="Test">Content</ExpandableItem>
437 |       <Button testId="expandBtn" onClick="expandable.expand()">Expand</Button>
438 |       <Button testId="collapseBtn" onClick="expandable.collapse()">Collapse</Button>
439 |       <Button testId="toggleBtn" onClick="expandable.toggle()">Toggle</Button>
440 |       <Button testId="checkBtn" onClick="testState = expandable.isExpanded()">Check</Button>
441 |     </Fragment>
442 |   `, {});
443 |   
444 |   const { testStateDriver } = await initTestBed(`
445 |     <Fragment>
446 |       <ExpandableItem id="expandable" summary="Test">Content</ExpandableItem>
447 |       <Button testId="expandBtn" onClick="expandable.expand()">Expand</Button>
448 |       <Button testId="collapseBtn" onClick="expandable.collapse()">Collapse</Button>
449 |       <Button testId="toggleBtn" onClick="expandable.toggle()">Toggle</Button>
450 |       <Button testId="checkBtn" onClick="testState = expandable.isExpanded()">Check</Button>
451 |     </Fragment>
452 |   `, {});
453 |   
454 |   // Test expand API
455 |   await page.getByTestId("expandBtn").click();
456 |   await expect(page.locator('[class*="_content_"]')).toBeVisible();
457 |   
458 |   // Test isExpanded API
459 |   await page.getByTestId("checkBtn").click();
460 |   await expect.poll(testStateDriver.testState).toEqual(true);
461 |   
462 |   // Test collapse API
463 |   await page.getByTestId("collapseBtn").click();
464 |   await expect(page.locator('[class*="_content_"]')).not.toBeVisible();
465 |   
466 |   // Test toggle API
467 |   await page.getByTestId("toggleBtn").click();
468 |   await expect(page.locator('[class*="_content_"]')).toBeVisible();
469 | });
470 | 
471 | test("component works with forms", async ({ initTestBed, createExpandableItemDriver }) => {
472 |   await initTestBed(`
473 |     <Form>
474 |       <ExpandableItem summary="Advanced Options">
475 |         <FormItem label="Advanced Setting">
476 |           <TextBox name="advanced" />
477 |         </FormItem>
478 |       </ExpandableItem>
479 |     </Form>
480 |   `, {});
481 |   const driver = await createExpandableItemDriver();
482 |   
483 |   await driver.getSummary().click();
484 |   await expect(driver.getContent()).toBeVisible();
485 |   await expect(driver.getContent()).toContainText("Advanced Setting");
486 | });
487 | 
488 | test("component event handlers work correctly", async ({ initTestBed, createExpandableItemDriver }) => {
489 |   const { testStateDriver } = await initTestBed(`
490 |     <ExpandableItem 
491 |       summary="Test" 
492 |       onExpandedChange="arg =>testState = arg">
493 |       Content
494 |     </ExpandableItem>
495 |   `, {});
496 |   const driver = await createExpandableItemDriver();
497 |   
498 |   // Click to expand - should set testState to true
499 |   await driver.getSummary().click();
500 |   await expect.poll(testStateDriver.testState).toEqual(true);
501 |   
502 |   // Click to collapse - should set testState to false
503 |   await driver.getSummary().click();
504 |   await expect.poll(testStateDriver.testState).toEqual(false);
505 | });
506 | 
507 | test("component works with switch variant", async ({ initTestBed, createExpandableItemDriver, page }) => {
508 |   await initTestBed(`<ExpandableItem summary="Test" withSwitch="true">Content</ExpandableItem>`, {});
509 |   const driver = await createExpandableItemDriver();
510 |   
511 |   // With switch variant, users should click the summary (button) to toggle
512 |   // The switch itself is decorative and aria-hidden
513 |   await driver.getSummary().click();
514 |   await expect(driver.getContent()).toBeVisible();
515 |   
516 |   // Click the summary again to toggle back
517 |   await driver.getSummary().click();
518 |   await expect(driver.getContent()).not.toBeVisible();
519 | });
520 | 
521 | test("component works in nested scenarios", async ({ initTestBed, createExpandableItemDriver }) => {
522 |   await initTestBed(`
523 |     <ExpandableItem summary="Parent">
524 |       <ExpandableItem summary="Child">
525 |         Nested content
526 |       </ExpandableItem>
527 |     </ExpandableItem>
528 |   `, {});
529 |   const driver = await createExpandableItemDriver();
530 |   
531 |   // Expand parent
532 |   await driver.getSummary().click();
533 |   await expect(driver.getContent()).toBeVisible();
534 |   
535 |   // Should see nested expandable item
536 |   await expect(driver.getContent()).toContainText("Child");
537 | });
538 | 
```

--------------------------------------------------------------------------------
/xmlui/scripts/generate-docs/get-docs.mjs:
--------------------------------------------------------------------------------

```
  1 | import { basename, join, extname, relative } from "path";
  2 | import { lstatSync } from "fs";
  3 | import { unlink, readdir, mkdir, writeFile, rm, readFile } from "fs/promises";
  4 | import { ErrorWithSeverity, LOGGER_LEVELS, logger } from "./logger.mjs";
  5 | import { winPathToPosix, deleteFileIfExists, fromKebabtoReadable } from "./utils.mjs";
  6 | import { DocsGenerator } from "./DocsGenerator.mjs";
  7 | import { collectedComponentMetadata } from "../../dist/metadata/xmlui-metadata.js";
  8 | import { FOLDERS } from "./folders.mjs";
  9 | import { existsSync } from "fs";
 10 | import { configManager, pathResolver } from "./configuration-management.mjs";
 11 | import {
 12 |   COMPONENT_STATES,
 13 |   FILE_EXTENSIONS,
 14 |   FOLDER_NAMES,
 15 |   SUMMARY_CONFIG,
 16 |   PACKAGE_PATTERNS,
 17 |   METADATA_PROPERTIES,
 18 |   TEMPLATE_STRINGS,
 19 |   ERROR_HANDLING,
 20 |   URL_REFERENCES,
 21 |   COMPONENT_NAVIGATION,
 22 |   FILE_PATHS,
 23 |   PATH_CONSTANTS,
 24 |   TEXT_CONSTANTS,
 25 |   ERROR_CONTEXTS,
 26 |   COMPONENT_NAV_ERRORS,
 27 |   EXTENSIONS_NAVIGATION,
 28 | } from "./constants.mjs";
 29 | import { handleNonFatalError, withErrorHandling } from "./error-handling.mjs";
 30 | 
 31 | // --- Main
 32 | 
 33 | // Prefilter metadata by isHtmlTag
 34 | const filterByProps = { [METADATA_PROPERTIES.IS_HTML_TAG]: true };
 35 | const [components] = partitionMetadata(collectedComponentMetadata, filterByProps);
 36 | 
 37 | await generateComponents(components);
 38 | 
 39 | // --- Extensions
 40 | const extensionsConfig = await configManager.loadExtensionsConfig();
 41 | const packagesMetadata = await dynamicallyLoadExtensionPackages(extensionsConfig);
 42 | await generateExtensionPackages(packagesMetadata, extensionsConfig);
 43 | 
 44 | /**
 45 |  * Generates NavLink elements for components and replaces the generated content in Main.xmlui
 46 |  * @param {Record<string, string>} componentsAndFileNames The components and their filenames
 47 |  */
 48 | async function generateComponentRefLinks(
 49 |   componentsAndFileNames,
 50 |   navConfigObj = COMPONENT_NAVIGATION,
 51 | ) {
 52 |   try {
 53 |     // Get component names (excluding the summary file)
 54 |     const componentNames = Object.keys(componentsAndFileNames)
 55 |       .filter((name) => name !== SUMMARY_CONFIG.COMPONENTS.fileName)
 56 |       .sort();
 57 | 
 58 |     // Create NavLink elements for each component
 59 |     const componentNavLinks = componentNames.map((componentName) =>
 60 |       navConfigObj.TEMPLATES.NAVLINK(componentName),
 61 |     );
 62 | 
 63 |     // Add the Components Overview link at the top
 64 |     const allNavLinks = [
 65 |       navConfigObj.OVERVIEW_LINK
 66 |         ? navConfigObj.TEMPLATES.OVERVIEW_NAVLINK(
 67 |             navConfigObj.OVERVIEW_LINK.LABEL,
 68 |             navConfigObj.OVERVIEW_LINK.TO,
 69 |           )
 70 |         : [],
 71 |       ...componentNavLinks,
 72 |     ];
 73 | 
 74 |     // Join with newlines - store in memory instead of writing to file
 75 |     const navLinksContent = allNavLinks.join(TEXT_CONSTANTS.NEWLINE_SEPARATOR);
 76 | 
 77 |     // Find and display content between GENERATED CONTENT delimiters in Main.xmlui
 78 |     const { indentationDepth } = await findAndDisplayGeneratedContent();
 79 | 
 80 |     // Replace the generated content with the in-memory NavLinks content
 81 |     await replaceGeneratedContentInMainXmlui(navLinksContent, indentationDepth);
 82 |   } catch (error) {
 83 |     throw new Error(COMPONENT_NAV_ERRORS.COMPONENT_NAV_FAILED);
 84 |   }
 85 | }
 86 | 
 87 | /**
 88 |  * Finds and displays the content between GENERATED CONTENT delimiters in Main.xmlui
 89 |  */
 90 | async function findAndDisplayGeneratedContent() {
 91 |   try {
 92 |     const mainXmluiPath = join(FOLDERS.docsRoot, FILE_PATHS.MAIN_XMLUI);
 93 | 
 94 |     if (!existsSync(mainXmluiPath)) {
 95 |       throw new Error(COMPONENT_NAV_ERRORS.MAIN_XMLUI_NOT_FOUND(mainXmluiPath));
 96 |     }
 97 | 
 98 |     const fileContent = await readFile(mainXmluiPath, TEXT_CONSTANTS.UTF8_ENCODING);
 99 | 
100 |     // Define the delimiter patterns using regex
101 |     const startDelimiterRegex = COMPONENT_NAVIGATION.DELIMITERS.START_REGEX;
102 |     const endDelimiterRegex = COMPONENT_NAVIGATION.DELIMITERS.END_REGEX;
103 | 
104 |     const startMatch = fileContent.match(startDelimiterRegex);
105 |     const endMatch = fileContent.match(endDelimiterRegex);
106 | 
107 |     if (!startMatch) {
108 |       throw new Error(COMPONENT_NAV_ERRORS.START_DELIMITER_NOT_FOUND);
109 |     }
110 | 
111 |     if (!endMatch) {
112 |       throw new Error(COMPONENT_NAV_ERRORS.END_DELIMITER_NOT_FOUND);
113 |     }
114 | 
115 |     const startIndex = startMatch.index;
116 |     const endIndex = endMatch.index;
117 | 
118 |     if (startIndex >= endIndex) {
119 |       throw new Error(COMPONENT_NAV_ERRORS.INVALID_DELIMITER_ORDER);
120 |     }
121 | 
122 |     // Extract content between delimiters (excluding the delimiters themselves)
123 |     const generatedContentStart = startIndex + startMatch[0].length;
124 |     const generatedContent = fileContent.substring(generatedContentStart, endIndex);
125 | 
126 |     // Calculate indentation depth
127 |     const indentationDepth = calculateIndentationDepth(generatedContent);
128 | 
129 |     return { indentationDepth };
130 |   } catch (error) {
131 |     return { indentationDepth: 0 };
132 |   }
133 | }
134 | 
135 | /**
136 |  * Generates a comprehensive components overview file with a table of all components
137 |  * @param {string} overviewFile - Path to the overview file to generate
138 |  * @param {string} summaryTitle - Title for the overview section
139 |  * @param {object} componentsAndFileNames - Object containing component metadata
140 |  */
141 | async function generateComponentsOverview(overviewFile, summaryTitle, componentsAndFileNames) {
142 |   try {
143 |     // Get component names (excluding the summary file)
144 |     const componentNames = Object.keys(componentsAndFileNames)
145 |       .filter((name) => name !== SUMMARY_CONFIG.COMPONENTS.fileName)
146 |       .sort();
147 | 
148 |     // Log the number of components
149 |     logger.info(`Components Overview: ${componentNames.length} components`);
150 | 
151 |     // Create table header
152 |     const tableHeader = `# ${summaryTitle} [#components-overview]
153 | 
154 | | Component | Description |
155 | | :---: | --- |`;
156 | 
157 |     // Create table rows for each component from the original metadata
158 |     const tableRows = componentNames.map((componentName) => {
159 |       // Get description from original metadata
160 |       const originalMetadata = collectedComponentMetadata[componentName];
161 |       const description = originalMetadata?.description || TEXT_CONSTANTS.NO_DESCRIPTION_AVAILABLE;
162 | 
163 |       // Format the table row with correct relative path
164 |       return `| [${componentName}](./${componentName}) | ${description} |`;
165 |     });
166 | 
167 |     // Combine header and rows
168 |     const tableContent = [tableHeader, ...tableRows].join(TEXT_CONSTANTS.NEWLINE_SEPARATOR);
169 | 
170 |     // Write to file
171 |     await writeFile(overviewFile, tableContent);
172 |   } catch (error) {
173 |     throw new Error(COMPONENT_NAV_ERRORS.OVERVIEW_GENERATION_FAILED);
174 |   }
175 | }
176 | 
177 | // --- Helpers
178 | 
179 | async function generateExtensionPackages(metadata, extensionsConfig) {
180 |   const outputPaths = pathResolver.getOutputPaths();
181 |   const extensionsFolder = outputPaths.extensions;
182 | 
183 |   const extensionNamesAndCompNames = [];
184 |   const unlistedFolders = [];
185 |   for (const packageName in metadata) {
186 |     // Just to be sure we don't generate anything internal
187 |     if (metadata[packageName].state === COMPONENT_STATES.INTERNAL) {
188 |       continue;
189 |     }
190 | 
191 |     const packageFolder = join(extensionsFolder, packageName);
192 | 
193 |     if (!existsSync(packageFolder)) {
194 |       await mkdir(packageFolder, { recursive: true });
195 |     }
196 | 
197 |     const extensionGenerator = new DocsGenerator(
198 |       metadata[packageName].metadata,
199 |       {
200 |         sourceFolder: metadata[packageName].sourceFolder,
201 |         outFolder: packageFolder,
202 |         examplesFolder: join(FOLDERS.docsRoot, FOLDER_NAMES.COMPONENT_SAMPLES),
203 |       },
204 |       { excludeComponentStatuses: extensionsConfig?.excludeComponentStatuses },
205 |     );
206 | 
207 |     if (extensionsConfig?.cleanFolder) {
208 |       await cleanFolder(packageFolder);
209 |     }
210 | 
211 |     let componentsAndFileNames = extensionGenerator.generateDocs();
212 |     if (Object.keys(componentsAndFileNames).length === 0) {
213 |       if (existsSync(packageFolder)) {
214 |         await rm(packageFolder, { recursive: true });
215 |       }
216 |       unlistedFolders.push(packageName);
217 |       continue;
218 |     }
219 | 
220 |     const summaryTitle = SUMMARY_CONFIG.EXTENSIONS.title;
221 |     const summaryFileName = SUMMARY_CONFIG.EXTENSIONS.fileName;
222 | 
223 |     // In both of these cases, we are writing to the same file
224 |     const indexFile = join(packageFolder, `${summaryFileName}.md`);
225 |     deleteFileIfExists(indexFile);
226 | 
227 |     await extensionGenerator.exportMetadataToJson(FOLDER_NAMES.EXTENSIONS, packageName);
228 | 
229 |     componentsAndFileNames = insertKeyAt(summaryFileName, summaryTitle, componentsAndFileNames, 0);
230 |     await extensionGenerator.generatePackageDescription(
231 |       metadata[packageName].description,
232 |       TEMPLATE_STRINGS.PACKAGE_HEADER(packageName),
233 |       indexFile,
234 |     );
235 | 
236 |     // Generate a _meta.json for the files in the extension
237 |     extensionGenerator.writeMetaSummary(componentsAndFileNames, packageFolder);
238 | 
239 |     extensionNamesAndCompNames.push({
240 |       packageName,
241 |       fileNames: Object.keys(componentsAndFileNames).filter(
242 |         (n) => SUMMARY_CONFIG.EXTENSIONS.fileName !== n,
243 |       ),
244 |     });
245 |   }
246 | 
247 |   const packageGroupsWithComponentLinks = extensionNamesAndCompNames.map((ext) => {
248 |     logger.info(`Generating NavLinks for Extension Package: ${ext.packageName}`);
249 | 
250 |     const compLinks = ext.fileNames.map((compName) => {
251 |       return EXTENSIONS_NAVIGATION.TEMPLATES.NAVLINK(ext.packageName, compName);
252 |     });
253 | 
254 |     // Add the Extensions Overview link at the top
255 |     const packageLinks = [
256 |       EXTENSIONS_NAVIGATION.TEMPLATES.OVERVIEW_NAVLINK(
257 |         EXTENSIONS_NAVIGATION.OVERVIEW_LINK.LABEL,
258 |         EXTENSIONS_NAVIGATION.OVERVIEW_LINK.TO(ext.packageName),
259 |       ),
260 |       ...compLinks,
261 |     ];
262 | 
263 |     return EXTENSIONS_NAVIGATION.TEMPLATES.NAVGROUP(
264 |       fromKebabtoReadable(ext.packageName),
265 |       packageLinks.join("\n"),
266 |     );
267 |   });
268 |   // Join with newlines - store in memory instead of writing to file
269 |   const navLinksContent = packageGroupsWithComponentLinks.join(TEXT_CONSTANTS.NEWLINE_SEPARATOR);
270 | 
271 |   // Find and display content between GENERATED CONTENT delimiters in Main.xmlui
272 |   const { indentationDepth } = await findAndDisplayGeneratedContent();
273 | 
274 |   // Replace the generated content with the in-memory NavLinks content
275 |   await replaceGeneratedContentInMainXmlui(
276 |     navLinksContent,
277 |     indentationDepth,
278 |     EXTENSIONS_NAVIGATION,
279 |   );
280 | 
281 |   // generate a _meta.json for the folder names
282 |   await withErrorHandling(
283 |     async () => {
284 |       const extensionPackagesMetafile = join(extensionsFolder, FILE_EXTENSIONS.METADATA);
285 | 
286 |       const folderNames = Object.fromEntries(
287 |         Object.keys(metadata)
288 |           .filter((m) => !unlistedFolders.includes(m))
289 |           .map((name) => {
290 |             return [name, `${fromKebabtoReadable(name)} Package`];
291 |           }),
292 |       );
293 | 
294 |       /* const existingMeta = JSON.parse(readFileSync(extensionPackagesMetafile, "utf-8"));
295 |       const updatedMeta = Object.entries(folderNames).reduce((acc, [key, value], idx) => {
296 |         return insertKeyAt(key, value, acc, Object.keys(acc).length === 0 ? 0 : idx + 1);
297 |       }, existingMeta || {}); */
298 | 
299 |       // Do not include the summary file in the _meta.json
300 |       deleteFileIfExists(extensionPackagesMetafile);
301 |       await writeFile(extensionPackagesMetafile, JSON.stringify(folderNames, null, 2));
302 |     },
303 |     ERROR_CONTEXTS.EXTENSION_PACKAGES_METADATA,
304 |     ERROR_HANDLING.EXIT_CODES.FILE_NOT_FOUND,
305 |   );
306 | }
307 | 
308 | async function generateComponents(metadata) {
309 |   const componentsConfig = await configManager.loadComponentsConfig();
310 |   const outputPaths = pathResolver.getOutputPaths();
311 |   const outputFolder = outputPaths.components;
312 | 
313 |   const metadataGenerator = new DocsGenerator(
314 |     metadata,
315 |     {
316 |       sourceFolder: pathResolver.resolvePath(
317 |         PATH_CONSTANTS.XMLUI_SRC_COMPONENTS,
318 |         PATH_CONSTANTS.WORKSPACE,
319 |       ),
320 |       // --- CHANGE: Now documents are generated in the a new folder, outside of pages
321 |       outFolder: outputFolder,
322 |       // outFolder: join(FOLDERS.docsRoot, FOLDER_NAMES.PAGES, FOLDER_NAMES.COMPONENTS),
323 |       examplesFolder: pathResolver.resolvePath(
324 |         PATH_CONSTANTS.DOCS_COMPONENT_SAMPLES,
325 |         PATH_CONSTANTS.WORKSPACE,
326 |       ),
327 |     },
328 |     { excludeComponentStatuses: componentsConfig?.excludeComponentStatuses },
329 |   );
330 | 
331 |   if (componentsConfig?.cleanFolder) {
332 |     // --- CHANGE: Now documents are generated in the a new folder, outside of pages
333 |     // await cleanFolder(join(FOLDERS.pages, FOLDER_NAMES.COMPONENTS));
334 |     await cleanFolder(outputFolder);
335 |   }
336 | 
337 |   let componentsAndFileNames = metadataGenerator.generateDocs();
338 | 
339 |   // Generate ComponentRefLinks.txt with component names
340 |   await generateComponentRefLinks(componentsAndFileNames);
341 | 
342 |   const summaryTitle = SUMMARY_CONFIG.COMPONENTS.title;
343 |   const summaryFileName = SUMMARY_CONFIG.COMPONENTS.fileName;
344 |   await metadataGenerator.exportMetadataToJson(FOLDER_NAMES.COMPONENTS);
345 |   componentsAndFileNames = insertKeyAt(summaryFileName, summaryTitle, componentsAndFileNames, 0);
346 | 
347 |   // Generate the overview file for components
348 |   const overviewFile = join(outputFolder, `${summaryFileName}.md`);
349 |   await generateComponentsOverview(overviewFile, summaryTitle, componentsAndFileNames);
350 | 
351 |   metadataGenerator.writeMetaSummary(componentsAndFileNames, outputFolder);
352 | 
353 |   await metadataGenerator.generatePermalinksForHeaders();
354 | 
355 |   await metadataGenerator.createMetadataJsonForLanding(URL_REFERENCES.DOCS, "components");
356 | }
357 | 
358 | // NOTE: Unused - we are not generating Html component docs
359 | async function generateHtmlTagComponents(metadata) {
360 |   const componentsConfig = await configManager.loadComponentsConfig();
361 |   const outputPaths = pathResolver.getOutputPaths();
362 |   const metadataGenerator = new DocsGenerator(
363 |     metadata,
364 |     {
365 |       sourceFolder: pathResolver.resolvePath("xmlui/src/components", "project"),
366 |       outFolder: outputPaths.pages + "/components",
367 |       examplesFolder: pathResolver.resolvePath("docs/component-samples", "project"),
368 |     },
369 |     { excludeComponentStatuses: componentsConfig?.excludeComponentStatuses },
370 |   );
371 | }
372 | 
373 | async function cleanFolder(folderToClean) {
374 |   if (!existsSync(folderToClean)) return;
375 | 
376 |   // NOTE: This is the important part: we only delete .mdx and .md files and the _meta.json
377 |   const cleanCondition = (file) =>
378 |     FILE_EXTENSIONS.MARKDOWN.includes(extname(file)) || basename(file) === FILE_EXTENSIONS.METADATA;
379 | 
380 |   await withErrorHandling(
381 |     async () => {
382 |       const files = await readdir(folderToClean);
383 |       const unlinkPromises = files
384 |         .filter(cleanCondition)
385 |         .map((file) => unlink(join(folderToClean, file)));
386 | 
387 |       await Promise.all(unlinkPromises).catch((err) => {
388 |         throw new ErrorWithSeverity(err.message, LOGGER_LEVELS.error);
389 |       });
390 |     },
391 |     ERROR_CONTEXTS.FOLDER_CLEANUP,
392 |     ERROR_HANDLING.EXIT_CODES.FILE_NOT_FOUND,
393 |   );
394 | }
395 | 
396 | /**
397 |  * Dynamically loads extension package metadata from the `packages` folder.
398 |  * Loading of metadata is only possible if the package has a `dist` folder
399 |  * and is built using the `build:meta` script which produces a {file-name}-metadata.js file.
400 |  * To do this, the package must export a `componentMetadata` object in the `meta` folder containing:
401 |  * - name: The name of the package
402 |  * - description: A brief description of the package
403 |  * - metadata: An object containing component metadata
404 |  * - state: The state of the package (e.g., "experimental", "stable", "internal")
405 |  *
406 |  * @param {object} extensionsConfig Configuration object for extensions
407 |  * @returns {Promise<Record<
408 |  *  string,
409 |  *  { sourceFolder: string, description: string, metadata: Record<string, any> }
410 |  * >>} imported metadata
411 |  */
412 | async function dynamicallyLoadExtensionPackages(extensionsConfig) {
413 |   const defaultPackageState = COMPONENT_STATES.EXPERIMENTAL;
414 | 
415 |   // --- Find all packages in the `packages` folder that start with xmlui- OR are listed in the config
416 |   const extensionPackagesFolder = join(FOLDERS.projectRoot, PATH_CONSTANTS.PACKAGES);
417 |   let packageDirectories = [];
418 |   if (!!extensionsConfig?.includeByName && extensionsConfig.includeByName.length > 0) {
419 |     packageDirectories = extensionsConfig.includeByName
420 |       .map((name) => join(extensionPackagesFolder, name))
421 |       .filter((dir) => existsSync(dir) && lstatSync(dir).isDirectory());
422 |   } else {
423 |     packageDirectories = (await readdir(extensionPackagesFolder))
424 |       .filter((entry) => {
425 |         return (
426 |           entry.startsWith(PACKAGE_PATTERNS.XMLUI_PREFIX) &&
427 |           lstatSync(join(extensionPackagesFolder, entry)).isDirectory()
428 |         );
429 |       })
430 |       .map((dir) => join(extensionPackagesFolder, dir));
431 |   }
432 |   if (extensionsConfig?.excludeByName && extensionsConfig.excludeByName.length > 0) {
433 |     packageDirectories = packageDirectories.filter(
434 |       (dir) => !extensionsConfig?.excludeByName?.includes(basename(dir)),
435 |     );
436 |   }
437 | 
438 |   const importedMetadata = {};
439 |   for (let dir of packageDirectories) {
440 |     const extensionPackage = {
441 |       sourceFolder: dir, //join(dir, FOLDER_NAMES.SRC),
442 |       description: "",
443 |       metadata: {},
444 |       state: defaultPackageState,
445 |     };
446 |     try {
447 |       const packageFolderDist = join(dir, FOLDER_NAMES.DIST);
448 |       if (!existsSync(packageFolderDist)) {
449 |         continue;
450 |       }
451 |       const distContents = await readdir(packageFolderDist);
452 |       for (const file of distContents) {
453 |         let filePath = join(packageFolderDist, file);
454 |         if (
455 |           filePath.endsWith(`${basename(dir)}${PACKAGE_PATTERNS.METADATA_SUFFIX}`) &&
456 |           existsSync(filePath)
457 |         ) {
458 |           filePath = winPathToPosix(relative(FOLDERS.script, filePath));
459 |           const { componentMetadata } = await import(filePath);
460 |           if (!componentMetadata) {
461 |             continue;
462 |           }
463 |           if (!componentMetadata.metadata) {
464 |             continue;
465 |           }
466 | 
467 |           extensionPackage.metadata = componentMetadata.metadata ?? {};
468 |           extensionPackage.description = componentMetadata.description ?? "";
469 |           extensionPackage.state = componentMetadata.state ?? defaultPackageState;
470 |         }
471 |       }
472 |       // Ignore internal packages
473 |       if (extensionPackage.state === COMPONENT_STATES.INTERNAL) {
474 |         continue;
475 |       }
476 |       importedMetadata[basename(dir)] = extensionPackage;
477 |     } catch (error) {
478 |       handleNonFatalError(error, `${ERROR_CONTEXTS.LOADING_EXTENSION_PACKAGE}: ${basename(dir)}`);
479 |     }
480 |   }
481 |   return importedMetadata;
482 | }
483 | 
484 | function partitionMetadata(metadata, filterByProps) {
485 |   const [components, htmlTagComponents] = partitionObject(metadata, (compData, c) => {
486 |     if (!filterByProps || Object.keys(filterByProps).length === 0) {
487 |       return true;
488 |     }
489 |     for (const [propName, propValue] of Object.entries(filterByProps)) {
490 |       if (compData[propName] === undefined) {
491 |         return true;
492 |       }
493 |       if (compData[propName] === propValue) {
494 |         return false;
495 |       }
496 |     }
497 |   });
498 | 
499 |   return [components, htmlTagComponents];
500 | }
501 | 
502 | /**
503 |  * Partition an object into two objects based on a discriminator function.
504 |  * @template T
505 |  * @param {Record<string, T>} obj Input object to partition
506 |  * @param {(value: T, key: string) => boolean} discriminator Function to decide partitioning
507 |  * @returns {[Record<string, T>, Record<string, T>]} An array containing two disjoint objects
508 |  */
509 | function partitionObject(obj, discriminator) {
510 |   return Object.entries(obj).reduce(
511 |     ([pass, fail], [key, value]) => {
512 |       if (discriminator(value, key)) {
513 |         return [{ ...pass, [key]: value }, fail];
514 |       } else {
515 |         return [pass, { ...fail, [key]: value }];
516 |       }
517 |     },
518 |     [{}, {}],
519 |   );
520 | }
521 | 
522 | function insertKeyAt(key, value, obj, pos) {
523 |   return Object.keys(obj).reduce((ac, a, i) => {
524 |     if (i === pos) ac[key] = value;
525 |     ac[a] = obj[a];
526 |     return ac;
527 |   }, {});
528 | }
529 | 
530 | /**
531 |  * Calculates the indentation depth of content by finding the minimum leading whitespace
532 |  * @param {string} content - The content to analyze
533 |  * @returns {number} The number of whitespace characters representing the indentation depth
534 |  */
535 | function calculateIndentationDepth(content) {
536 |   if (!content || content.trim().length === 0) {
537 |     return 0;
538 |   }
539 | 
540 |   const lines = content.split("\n");
541 |   let minIndentation = Infinity;
542 | 
543 |   for (const line of lines) {
544 |     // Skip empty lines
545 |     if (line.trim().length === 0) {
546 |       continue;
547 |     }
548 | 
549 |     // Count leading whitespace characters
550 |     const leadingWhitespace = line.match(/^(\s*)/)[1];
551 |     const indentationCount = leadingWhitespace.length;
552 | 
553 |     // Track minimum indentation
554 |     if (indentationCount < minIndentation) {
555 |       minIndentation = indentationCount;
556 |     }
557 |   }
558 | 
559 |   // Return 0 if no lines had content or all lines were empty
560 |   return minIndentation === Infinity ? 0 : minIndentation;
561 | }
562 | 
563 | /**
564 |  * Replaces the content between GENERATED CONTENT delimiters in Main.xmlui with NavLink content
565 |  * @param {string} navLinksContent - The NavLink content to insert
566 |  * @param {number} indentationDepth - Number of spaces to indent each line
567 |  */
568 | async function replaceGeneratedContentInMainXmlui(
569 |   navLinksContent,
570 |   indentationDepth,
571 |   NavConfigObj = COMPONENT_NAVIGATION,
572 | ) {
573 |   try {
574 |     const mainXmluiPath = join(FOLDERS.docsRoot, FILE_PATHS.MAIN_XMLUI);
575 | 
576 |     if (!existsSync(mainXmluiPath)) {
577 |       throw new Error(COMPONENT_NAV_ERRORS.MAIN_XMLUI_NOT_FOUND(mainXmluiPath));
578 |     }
579 | 
580 |     // Read the Main.xmlui file
581 |     const fileContent = await readFile(mainXmluiPath, TEXT_CONSTANTS.UTF8_ENCODING);
582 | 
583 |     // Define the delimiter patterns using regex
584 |     const startDelimiterRegex = NavConfigObj.DELIMITERS.START_REGEX;
585 |     const endDelimiterRegex = NavConfigObj.DELIMITERS.END_REGEX;
586 | 
587 |     const startMatch = fileContent.match(startDelimiterRegex);
588 |     const endMatch = fileContent.match(endDelimiterRegex);
589 | 
590 |     if (!startMatch || !endMatch) {
591 |       throw new Error(COMPONENT_NAV_ERRORS.DELIMITERS_NOT_FOUND);
592 |     }
593 | 
594 |     const startIndex = startMatch.index;
595 |     const endIndex = endMatch.index;
596 | 
597 |     // Create indented content from the in-memory NavLinks content
598 |     const indentString = " ".repeat(indentationDepth);
599 |     const indentedLines = navLinksContent
600 |       .split(TEXT_CONSTANTS.NEWLINE_SEPARATOR)
601 |       .filter((line) => line.trim().length > 0) // Remove empty lines
602 |       .map((line) => indentString + line);
603 | 
604 |     // Build the new content with proper formatting
605 |     const newGeneratedContent =
606 |       TEXT_CONSTANTS.NEWLINE_SEPARATOR +
607 |       indentedLines.join(TEXT_CONSTANTS.NEWLINE_SEPARATOR) +
608 |       TEXT_CONSTANTS.NEWLINE_SEPARATOR +
609 |       indentString;
610 | 
611 |     // Replace the content between delimiters
612 |     const beforeDelimiter = fileContent.substring(0, startIndex + startMatch[0].length);
613 |     const afterDelimiter = fileContent.substring(endIndex);
614 |     const newFileContent = beforeDelimiter + newGeneratedContent + afterDelimiter;
615 | 
616 |     // Write the updated content back to the file
617 |     await writeFile(mainXmluiPath, newFileContent, TEXT_CONSTANTS.UTF8_ENCODING);
618 |   } catch (error) {
619 |     throw new Error(COMPONENT_NAV_ERRORS.CONTENT_REPLACEMENT_FAILED);
620 |   }
621 | }
622 | 
```
Page 96/187FirstPrevNextLast