#
tokens: 47865/50000 8/1633 files (page 42/144)
lines: off (toggle) GitHub
raw markdown copy
This is page 42 of 144. Use http://codebase.md/xmlui-org/xmlui/%7Bnode.props.src?page={x} to view the full context.

# Directory Structure

```
├── .changeset
│   ├── config.json
│   ├── cyan-tools-design.md
│   ├── every-moments-teach.md
│   ├── full-symbols-accept.md
│   └── tricky-zoos-crash.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
│   │           ├── HelloMd.md
│   │           ├── HeroSection.md
│   │           └── ScrollToTop.md
│   ├── extensions.ts
│   ├── index.html
│   ├── index.ts
│   ├── package.json
│   ├── public
│   │   ├── feed.rss
│   │   ├── mockServiceWorker.js
│   │   ├── pages
│   │   │   ├── _meta.json
│   │   │   ├── app-structure.md
│   │   │   ├── build-editor-component.md
│   │   │   ├── build-hello-world-component.md
│   │   │   ├── components-intro.md
│   │   │   ├── context-variables.md
│   │   │   ├── forms.md
│   │   │   ├── globals.md
│   │   │   ├── glossary.md
│   │   │   ├── helper-tags.md
│   │   │   ├── hosted-deployment.md
│   │   │   ├── howto
│   │   │   │   ├── assign-a-complex-json-literal-to-a-component-variable.md
│   │   │   │   ├── chain-a-refetch.md
│   │   │   │   ├── 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.module.scss
│   │       │   ├── CodeSelector.tsx
│   │       │   ├── ConfirmationDialog.module.scss
│   │       │   ├── ConfirmationDialog.tsx
│   │       │   ├── Editor.tsx
│   │       │   ├── Header.module.scss
│   │       │   ├── Header.tsx
│   │       │   ├── Playground.tsx
│   │       │   ├── PlaygroundContent.module.scss
│   │       │   ├── PlaygroundContent.tsx
│   │       │   ├── PlaygroundNative.module.scss
│   │       │   ├── PlaygroundNative.tsx
│   │       │   ├── Preview.tsx
│   │       │   ├── StandalonePlayground.tsx
│   │       │   ├── StandalonePlaygroundNative.module.scss
│   │       │   ├── StandalonePlaygroundNative.tsx
│   │       │   ├── ThemeSwitcher.module.scss
│   │       │   ├── ThemeSwitcher.tsx
│   │       │   └── utils.ts
│   │       ├── providers
│   │       │   ├── Toast.module.scss
│   │       │   └── ToastProvider.tsx
│   │       ├── state
│   │       │   └── store.ts
│   │       ├── themes
│   │       │   └── theme.ts
│   │       └── utils
│   │           └── helpers.ts
│   ├── xmlui-search
│   │   ├── .gitignore
│   │   ├── CHANGELOG.md
│   │   ├── demo
│   │   │   └── Main.xmlui
│   │   ├── index.html
│   │   ├── index.ts
│   │   ├── meta
│   │   │   └── componentsMetadata.ts
│   │   ├── package.json
│   │   └── src
│   │       ├── index.tsx
│   │       ├── Search.module.scss
│   │       └── Search.tsx
│   ├── xmlui-spreadsheet
│   │   ├── .gitignore
│   │   ├── demo
│   │   │   └── Main.xmlui
│   │   ├── index.html
│   │   ├── index.ts
│   │   ├── meta
│   │   │   └── componentsMetadata.ts
│   │   ├── package.json
│   │   └── src
│   │       ├── index.tsx
│   │       ├── Spreadsheet.tsx
│   │       └── SpreadsheetNative.tsx
│   └── xmlui-website-blocks
│       ├── .gitignore
│       ├── CHANGELOG.md
│       ├── demo
│       │   ├── components
│       │   │   ├── HeroBackgroundBreakoutPage.xmlui
│       │   │   ├── HeroBackgroundsPage.xmlui
│       │   │   ├── HeroContentsPage.xmlui
│       │   │   ├── HeroTextAlignPage.xmlui
│       │   │   ├── HeroTextPage.xmlui
│       │   │   └── HeroTonesPage.xmlui
│       │   ├── Main.xmlui
│       │   └── themes
│       │       └── default.ts
│       ├── index.html
│       ├── index.ts
│       ├── meta
│       │   └── componentsMetadata.ts
│       ├── package.json
│       ├── public
│       │   └── resources
│       │       ├── building.jpg
│       │       └── xmlui-logo.svg
│       └── src
│           ├── Carousel
│           │   ├── Carousel.module.scss
│           │   ├── Carousel.tsx
│           │   ├── CarouselContext.tsx
│           │   └── CarouselNative.tsx
│           ├── FancyButton
│           │   ├── FancyButton.module.scss
│           │   ├── FancyButton.tsx
│           │   └── FancyButton.xmlui
│           ├── Hello
│           │   ├── Hello.tsx
│           │   ├── Hello.xmlui
│           │   └── Hello.xmlui.xs
│           ├── HeroSection
│           │   ├── HeroSection.module.scss
│           │   ├── HeroSection.spec.ts
│           │   ├── HeroSection.tsx
│           │   └── HeroSectionNative.tsx
│           ├── index.tsx
│           ├── ScrollToTop
│           │   ├── ScrollToTop.module.scss
│           │   ├── ScrollToTop.tsx
│           │   └── ScrollToTopNative.tsx
│           └── vite-env.d.ts
├── playwright.config.ts
├── README.md
├── tools
│   ├── codefence
│   │   └── xmlui-code-fence-docs.md
│   ├── create-app
│   │   ├── .gitignore
│   │   ├── CHANGELOG.md
│   │   ├── create-app.ts
│   │   ├── helpers
│   │   │   ├── copy.ts
│   │   │   ├── get-pkg-manager.ts
│   │   │   ├── git.ts
│   │   │   ├── install.ts
│   │   │   ├── is-folder-empty.ts
│   │   │   ├── is-writeable.ts
│   │   │   ├── make-dir.ts
│   │   │   └── validate-pkg.ts
│   │   ├── index.ts
│   │   ├── package.json
│   │   ├── templates
│   │   │   ├── default
│   │   │   │   └── ts
│   │   │   │       ├── gitignore
│   │   │   │       ├── index.html
│   │   │   │       ├── index.ts
│   │   │   │       ├── public
│   │   │   │       │   ├── mockServiceWorker.js
│   │   │   │       │   ├── resources
│   │   │   │       │   │   ├── favicon.ico
│   │   │   │       │   │   └── xmlui-logo.svg
│   │   │   │       │   └── serve.json
│   │   │   │       └── src
│   │   │   │           ├── components
│   │   │   │           │   ├── ApiAware.xmlui
│   │   │   │           │   ├── Home.xmlui
│   │   │   │           │   ├── IncButton.xmlui
│   │   │   │           │   └── PagePanel.xmlui
│   │   │   │           ├── config.ts
│   │   │   │           └── Main.xmlui
│   │   │   ├── index.ts
│   │   │   └── types.ts
│   │   └── tsconfig.json
│   ├── create-xmlui-hello-world
│   │   ├── index.js
│   │   └── package.json
│   └── vscode
│       ├── .gitignore
│       ├── .vscode
│       │   ├── launch.json
│       │   └── tasks.json
│       ├── .vscodeignore
│       ├── build.sh
│       ├── CHANGELOG.md
│       ├── esbuild.js
│       ├── eslint.config.mjs
│       ├── formatter-docs.md
│       ├── generate-test-sample.sh
│       ├── LICENSE.md
│       ├── package-lock.json
│       ├── package.json
│       ├── README.md
│       ├── resources
│       │   ├── xmlui-logo.png
│       │   └── xmlui-markup-syntax-highlighting.png
│       ├── src
│       │   ├── extension.ts
│       │   └── server.ts
│       ├── syntaxes
│       │   └── xmlui.tmLanguage.json
│       ├── test-samples
│       │   └── sample.xmlui
│       ├── tsconfig.json
│       └── tsconfig.tsbuildinfo
├── turbo.json
└── xmlui
    ├── .gitignore
    ├── bin
    │   ├── bootstrap.cjs
    │   ├── bootstrap.js
    │   ├── build-lib.ts
    │   ├── build.ts
    │   ├── index.ts
    │   ├── preview.ts
    │   ├── start.ts
    │   ├── vite-xmlui-plugin.ts
    │   └── viteConfig.ts
    ├── CHANGELOG.md
    ├── conventions
    │   ├── component-qa-checklist.md
    │   ├── copilot-conventions.md
    │   ├── create-xmlui-components.md
    │   ├── mermaid.md
    │   ├── testing-conventions.md
    │   └── xmlui-in-a-nutshell.md
    ├── dev-docs
    │   ├── accessibility.md
    │   ├── build-system.md
    │   ├── build-xmlui.md
    │   ├── component-behaviors.md
    │   ├── component-metadata.md
    │   ├── components-with-options.md
    │   ├── containers.md
    │   ├── data-operations.md
    │   ├── glossary.md
    │   ├── index.md
    │   ├── next
    │   │   ├── component-dev-guide.md
    │   │   ├── configuration-management-enhancement-summary.md
    │   │   ├── documentation-scripts-refactoring-complete-summary.md
    │   │   ├── documentation-scripts-refactoring-plan.md
    │   │   ├── duplicate-pattern-extraction-summary.md
    │   │   ├── error-handling-standardization-summary.md
    │   │   ├── generating-component-reference.md
    │   │   ├── index.md
    │   │   ├── logging-consistency-implementation-summary.md
    │   │   ├── project-build.md
    │   │   ├── project-structure.md
    │   │   ├── theme-context.md
    │   │   ├── tiptap-design-considerations.md
    │   │   ├── working-with-code.md
    │   │   ├── xmlui-runtime-architecture
    │   │   └── xmlui-wcag-accessibility-report.md
    │   ├── react-fundamentals.md
    │   ├── release-method.md
    │   ├── standalone-app.md
    │   ├── theme-variables-refactoring.md
    │   ├── ud-components.md
    │   └── xmlui-repo.md
    ├── package.json
    ├── scripts
    │   ├── coverage-only.js
    │   ├── e2e-test-summary.js
    │   ├── extract-component-metadata.js
    │   ├── generate-docs
    │   │   ├── build-downloads-map.mjs
    │   │   ├── build-pages-map.mjs
    │   │   ├── components-config.json
    │   │   ├── configuration-management.mjs
    │   │   ├── constants.mjs
    │   │   ├── create-theme-files.mjs
    │   │   ├── DocsGenerator.mjs
    │   │   ├── error-handling.mjs
    │   │   ├── extensions-config.json
    │   │   ├── folders.mjs
    │   │   ├── generate-summary-files.mjs
    │   │   ├── get-docs.mjs
    │   │   ├── input-handler.mjs
    │   │   ├── logger.mjs
    │   │   ├── logging-standards.mjs
    │   │   ├── MetadataProcessor.mjs
    │   │   ├── pattern-utilities.mjs
    │   │   └── utils.mjs
    │   ├── generate-metadata-markdown.js
    │   ├── get-langserver-metadata.js
    │   ├── inline-links.mjs
    │   └── README-e2e-summary.md
    ├── src
    │   ├── abstractions
    │   │   ├── _conventions.md
    │   │   ├── ActionDefs.ts
    │   │   ├── AppContextDefs.ts
    │   │   ├── ComponentDefs.ts
    │   │   ├── ContainerDefs.ts
    │   │   ├── ExtensionDefs.ts
    │   │   ├── FunctionDefs.ts
    │   │   ├── RendererDefs.ts
    │   │   ├── scripting
    │   │   │   ├── BlockScope.ts
    │   │   │   ├── Compilation.ts
    │   │   │   ├── LogicalThread.ts
    │   │   │   ├── LoopScope.ts
    │   │   │   ├── modules.ts
    │   │   │   ├── ScriptParserError.ts
    │   │   │   ├── Token.ts
    │   │   │   ├── TryScope.ts
    │   │   │   └── TryScopeExp.ts
    │   │   └── ThemingDefs.ts
    │   ├── components
    │   │   ├── _conventions.md
    │   │   ├── abstractions.ts
    │   │   ├── Accordion
    │   │   │   ├── Accordion.md
    │   │   │   ├── Accordion.module.scss
    │   │   │   ├── Accordion.spec.ts
    │   │   │   ├── Accordion.tsx
    │   │   │   ├── AccordionContext.tsx
    │   │   │   ├── AccordionItem.tsx
    │   │   │   ├── AccordionItemNative.tsx
    │   │   │   └── AccordionNative.tsx
    │   │   ├── Animation
    │   │   │   └── AnimationNative.tsx
    │   │   ├── APICall
    │   │   │   ├── APICall.md
    │   │   │   ├── APICall.spec.ts
    │   │   │   ├── APICall.tsx
    │   │   │   └── APICallNative.tsx
    │   │   ├── App
    │   │   │   ├── App.md
    │   │   │   ├── App.module.scss
    │   │   │   ├── App.spec.ts
    │   │   │   ├── App.tsx
    │   │   │   ├── AppLayoutContext.ts
    │   │   │   ├── AppNative.tsx
    │   │   │   ├── AppStateContext.ts
    │   │   │   ├── doc-resources
    │   │   │   │   ├── condensed-sticky.xmlui
    │   │   │   │   ├── condensed.xmlui
    │   │   │   │   ├── horizontal-sticky.xmlui
    │   │   │   │   ├── horizontal.xmlui
    │   │   │   │   ├── vertical-full-header.xmlui
    │   │   │   │   ├── vertical-sticky.xmlui
    │   │   │   │   └── vertical.xmlui
    │   │   │   ├── IndexerContext.ts
    │   │   │   ├── LinkInfoContext.ts
    │   │   │   ├── SearchContext.tsx
    │   │   │   ├── Sheet.module.scss
    │   │   │   └── Sheet.tsx
    │   │   ├── AppHeader
    │   │   │   ├── AppHeader.md
    │   │   │   ├── AppHeader.module.scss
    │   │   │   ├── AppHeader.spec.ts
    │   │   │   ├── AppHeader.tsx
    │   │   │   └── AppHeaderNative.tsx
    │   │   ├── AppState
    │   │   │   ├── AppState.md
    │   │   │   ├── AppState.spec.ts
    │   │   │   ├── AppState.tsx
    │   │   │   └── AppStateNative.tsx
    │   │   ├── AutoComplete
    │   │   │   ├── AutoComplete.md
    │   │   │   ├── AutoComplete.module.scss
    │   │   │   ├── AutoComplete.spec.ts
    │   │   │   ├── AutoComplete.tsx
    │   │   │   ├── AutoCompleteContext.tsx
    │   │   │   └── AutoCompleteNative.tsx
    │   │   ├── Avatar
    │   │   │   ├── Avatar.md
    │   │   │   ├── Avatar.module.scss
    │   │   │   ├── Avatar.spec.ts
    │   │   │   ├── Avatar.tsx
    │   │   │   └── AvatarNative.tsx
    │   │   ├── Backdrop
    │   │   │   ├── Backdrop.md
    │   │   │   ├── Backdrop.module.scss
    │   │   │   ├── Backdrop.spec.ts
    │   │   │   ├── Backdrop.tsx
    │   │   │   └── BackdropNative.tsx
    │   │   ├── Badge
    │   │   │   ├── Badge.md
    │   │   │   ├── Badge.module.scss
    │   │   │   ├── Badge.spec.ts
    │   │   │   ├── Badge.tsx
    │   │   │   └── BadgeNative.tsx
    │   │   ├── Bookmark
    │   │   │   ├── Bookmark.md
    │   │   │   ├── Bookmark.module.scss
    │   │   │   ├── Bookmark.spec.ts
    │   │   │   ├── Bookmark.tsx
    │   │   │   └── BookmarkNative.tsx
    │   │   ├── Breakout
    │   │   │   ├── Breakout.module.scss
    │   │   │   ├── Breakout.spec.ts
    │   │   │   ├── Breakout.tsx
    │   │   │   └── BreakoutNative.tsx
    │   │   ├── Button
    │   │   │   ├── Button-style.spec.ts
    │   │   │   ├── Button.md
    │   │   │   ├── Button.module.scss
    │   │   │   ├── Button.spec.ts
    │   │   │   ├── Button.tsx
    │   │   │   └── ButtonNative.tsx
    │   │   ├── Card
    │   │   │   ├── Card.md
    │   │   │   ├── Card.module.scss
    │   │   │   ├── Card.spec.ts
    │   │   │   ├── Card.tsx
    │   │   │   └── CardNative.tsx
    │   │   ├── Carousel
    │   │   │   ├── Carousel.md
    │   │   │   ├── Carousel.module.scss
    │   │   │   ├── Carousel.spec.ts
    │   │   │   ├── Carousel.tsx
    │   │   │   ├── CarouselContext.tsx
    │   │   │   ├── CarouselItem.tsx
    │   │   │   ├── CarouselItemNative.tsx
    │   │   │   └── CarouselNative.tsx
    │   │   ├── ChangeListener
    │   │   │   ├── ChangeListener.md
    │   │   │   ├── ChangeListener.spec.ts
    │   │   │   ├── ChangeListener.tsx
    │   │   │   └── ChangeListenerNative.tsx
    │   │   ├── chart-color-schemes.ts
    │   │   ├── Charts
    │   │   │   ├── AreaChart
    │   │   │   │   ├── AreaChart.md
    │   │   │   │   ├── AreaChart.spec.ts
    │   │   │   │   ├── AreaChart.tsx
    │   │   │   │   └── AreaChartNative.tsx
    │   │   │   ├── BarChart
    │   │   │   │   ├── BarChart.md
    │   │   │   │   ├── BarChart.module.scss
    │   │   │   │   ├── BarChart.spec.ts
    │   │   │   │   ├── BarChart.tsx
    │   │   │   │   └── BarChartNative.tsx
    │   │   │   ├── DonutChart
    │   │   │   │   ├── DonutChart.spec.ts
    │   │   │   │   └── DonutChart.tsx
    │   │   │   ├── LabelList
    │   │   │   │   ├── LabelList.module.scss
    │   │   │   │   ├── LabelList.spec.ts
    │   │   │   │   ├── LabelList.tsx
    │   │   │   │   └── LabelListNative.tsx
    │   │   │   ├── Legend
    │   │   │   │   ├── Legend.spec.ts
    │   │   │   │   ├── Legend.tsx
    │   │   │   │   └── LegendNative.tsx
    │   │   │   ├── LineChart
    │   │   │   │   ├── LineChart.md
    │   │   │   │   ├── LineChart.module.scss
    │   │   │   │   ├── LineChart.spec.ts
    │   │   │   │   ├── LineChart.tsx
    │   │   │   │   └── LineChartNative.tsx
    │   │   │   ├── PieChart
    │   │   │   │   ├── PieChart.md
    │   │   │   │   ├── PieChart.spec.ts
    │   │   │   │   ├── PieChart.tsx
    │   │   │   │   ├── PieChartNative.module.scss
    │   │   │   │   └── PieChartNative.tsx
    │   │   │   ├── RadarChart
    │   │   │   │   ├── RadarChart.md
    │   │   │   │   ├── RadarChart.spec.ts
    │   │   │   │   ├── RadarChart.tsx
    │   │   │   │   └── RadarChartNative.tsx
    │   │   │   ├── Tooltip
    │   │   │   │   ├── TooltipContent.module.scss
    │   │   │   │   ├── TooltipContent.spec.ts
    │   │   │   │   └── TooltipContent.tsx
    │   │   │   └── utils
    │   │   │       ├── abstractions.ts
    │   │   │       └── ChartProvider.tsx
    │   │   ├── Checkbox
    │   │   │   ├── Checkbox.md
    │   │   │   ├── Checkbox.spec.ts
    │   │   │   └── Checkbox.tsx
    │   │   ├── CodeBlock
    │   │   │   ├── CodeBlock.module.scss
    │   │   │   ├── CodeBlock.spec.ts
    │   │   │   ├── CodeBlock.tsx
    │   │   │   ├── CodeBlockNative.tsx
    │   │   │   └── highlight-code.ts
    │   │   ├── collectedComponentMetadata.ts
    │   │   ├── ColorPicker
    │   │   │   ├── ColorPicker.md
    │   │   │   ├── ColorPicker.module.scss
    │   │   │   ├── ColorPicker.spec.ts
    │   │   │   ├── ColorPicker.tsx
    │   │   │   └── ColorPickerNative.tsx
    │   │   ├── Column
    │   │   │   ├── Column.md
    │   │   │   ├── Column.tsx
    │   │   │   ├── ColumnNative.tsx
    │   │   │   ├── doc-resources
    │   │   │   │   └── list-component-data.js
    │   │   │   └── TableContext.tsx
    │   │   ├── component-utils.ts
    │   │   ├── ComponentProvider.tsx
    │   │   ├── ComponentRegistryContext.tsx
    │   │   ├── container-helpers.tsx
    │   │   ├── ContentSeparator
    │   │   │   ├── ContentSeparator.md
    │   │   │   ├── ContentSeparator.module.scss
    │   │   │   ├── ContentSeparator.spec.ts
    │   │   │   ├── ContentSeparator.tsx
    │   │   │   ├── ContentSeparatorNative.tsx
    │   │   │   └── test-padding.xmlui
    │   │   ├── DataSource
    │   │   │   ├── DataSource.md
    │   │   │   └── DataSource.tsx
    │   │   ├── DateInput
    │   │   │   ├── DateInput.md
    │   │   │   ├── DateInput.module.scss
    │   │   │   ├── DateInput.spec.ts
    │   │   │   ├── DateInput.tsx
    │   │   │   └── DateInputNative.tsx
    │   │   ├── DatePicker
    │   │   │   ├── DatePicker.md
    │   │   │   ├── DatePicker.module.scss
    │   │   │   ├── DatePicker.spec.ts
    │   │   │   ├── DatePicker.tsx
    │   │   │   └── DatePickerNative.tsx
    │   │   ├── DropdownMenu
    │   │   │   ├── DropdownMenu.md
    │   │   │   ├── DropdownMenu.module.scss
    │   │   │   ├── DropdownMenu.spec.ts
    │   │   │   ├── DropdownMenu.tsx
    │   │   │   ├── DropdownMenuNative.tsx
    │   │   │   ├── MenuItem.md
    │   │   │   └── SubMenuItem.md
    │   │   ├── EmojiSelector
    │   │   │   ├── EmojiSelector.md
    │   │   │   ├── EmojiSelector.spec.ts
    │   │   │   ├── EmojiSelector.tsx
    │   │   │   └── EmojiSelectorNative.tsx
    │   │   ├── ExpandableItem
    │   │   │   ├── ExpandableItem.module.scss
    │   │   │   ├── ExpandableItem.spec.ts
    │   │   │   ├── ExpandableItem.tsx
    │   │   │   └── ExpandableItemNative.tsx
    │   │   ├── FileInput
    │   │   │   ├── FileInput.md
    │   │   │   ├── FileInput.module.scss
    │   │   │   ├── FileInput.spec.ts
    │   │   │   ├── FileInput.tsx
    │   │   │   └── FileInputNative.tsx
    │   │   ├── FileUploadDropZone
    │   │   │   ├── FileUploadDropZone.md
    │   │   │   ├── FileUploadDropZone.module.scss
    │   │   │   ├── FileUploadDropZone.spec.ts
    │   │   │   ├── FileUploadDropZone.tsx
    │   │   │   └── FileUploadDropZoneNative.tsx
    │   │   ├── FlowLayout
    │   │   │   ├── FlowLayout.md
    │   │   │   ├── FlowLayout.module.scss
    │   │   │   ├── FlowLayout.spec.ts
    │   │   │   ├── FlowLayout.spec.ts-snapshots
    │   │   │   │   └── Edge-cases-boxShadow-is-not-clipped-1-non-smoke-darwin.png
    │   │   │   ├── FlowLayout.tsx
    │   │   │   └── FlowLayoutNative.tsx
    │   │   ├── Footer
    │   │   │   ├── Footer.md
    │   │   │   ├── Footer.module.scss
    │   │   │   ├── Footer.spec.ts
    │   │   │   ├── Footer.tsx
    │   │   │   └── FooterNative.tsx
    │   │   ├── Form
    │   │   │   ├── Form.md
    │   │   │   ├── Form.module.scss
    │   │   │   ├── Form.spec.ts
    │   │   │   ├── Form.tsx
    │   │   │   ├── formActions.ts
    │   │   │   ├── FormContext.ts
    │   │   │   └── FormNative.tsx
    │   │   ├── FormItem
    │   │   │   ├── FormItem.md
    │   │   │   ├── FormItem.module.scss
    │   │   │   ├── FormItem.spec.ts
    │   │   │   ├── FormItem.tsx
    │   │   │   ├── FormItemNative.tsx
    │   │   │   ├── HelperText.module.scss
    │   │   │   ├── HelperText.tsx
    │   │   │   ├── ItemWithLabel.tsx
    │   │   │   └── Validations.ts
    │   │   ├── FormSection
    │   │   │   ├── FormSection.md
    │   │   │   ├── FormSection.ts
    │   │   │   └── FormSection.xmlui
    │   │   ├── Fragment
    │   │   │   ├── Fragment.spec.ts
    │   │   │   └── Fragment.tsx
    │   │   ├── Heading
    │   │   │   ├── abstractions.ts
    │   │   │   ├── H1.md
    │   │   │   ├── H1.spec.ts
    │   │   │   ├── H2.md
    │   │   │   ├── H2.spec.ts
    │   │   │   ├── H3.md
    │   │   │   ├── H3.spec.ts
    │   │   │   ├── H4.md
    │   │   │   ├── H4.spec.ts
    │   │   │   ├── H5.md
    │   │   │   ├── H5.spec.ts
    │   │   │   ├── H6.md
    │   │   │   ├── H6.spec.ts
    │   │   │   ├── Heading.md
    │   │   │   ├── Heading.module.scss
    │   │   │   ├── Heading.spec.ts
    │   │   │   ├── Heading.tsx
    │   │   │   └── HeadingNative.tsx
    │   │   ├── HoverCard
    │   │   │   ├── HoverCard.tsx
    │   │   │   └── HovercardNative.tsx
    │   │   ├── HtmlTags
    │   │   │   ├── HtmlTags.module.scss
    │   │   │   ├── HtmlTags.spec.ts
    │   │   │   └── HtmlTags.tsx
    │   │   ├── Icon
    │   │   │   ├── AdmonitionDanger.tsx
    │   │   │   ├── AdmonitionInfo.tsx
    │   │   │   ├── AdmonitionNote.tsx
    │   │   │   ├── AdmonitionTip.tsx
    │   │   │   ├── AdmonitionWarning.tsx
    │   │   │   ├── ApiIcon.tsx
    │   │   │   ├── ArrowDropDown.module.scss
    │   │   │   ├── ArrowDropDown.tsx
    │   │   │   ├── ArrowDropUp.module.scss
    │   │   │   ├── ArrowDropUp.tsx
    │   │   │   ├── ArrowLeft.module.scss
    │   │   │   ├── ArrowLeft.tsx
    │   │   │   ├── ArrowRight.module.scss
    │   │   │   ├── ArrowRight.tsx
    │   │   │   ├── Attach.tsx
    │   │   │   ├── Binding.module.scss
    │   │   │   ├── Binding.tsx
    │   │   │   ├── BoardIcon.tsx
    │   │   │   ├── BoxIcon.tsx
    │   │   │   ├── CheckIcon.tsx
    │   │   │   ├── ChevronDownIcon.tsx
    │   │   │   ├── ChevronLeft.tsx
    │   │   │   ├── ChevronRight.tsx
    │   │   │   ├── ChevronUpIcon.tsx
    │   │   │   ├── CodeFileIcon.tsx
    │   │   │   ├── CodeSandbox.tsx
    │   │   │   ├── CompactListIcon.tsx
    │   │   │   ├── ContentCopyIcon.tsx
    │   │   │   ├── DarkToLightIcon.tsx
    │   │   │   ├── DatabaseIcon.module.scss
    │   │   │   ├── DatabaseIcon.tsx
    │   │   │   ├── DocFileIcon.tsx
    │   │   │   ├── DocIcon.tsx
    │   │   │   ├── DotMenuHorizontalIcon.tsx
    │   │   │   ├── DotMenuIcon.tsx
    │   │   │   ├── EmailIcon.tsx
    │   │   │   ├── EmptyFolderIcon.tsx
    │   │   │   ├── ErrorIcon.tsx
    │   │   │   ├── ExpressionIcon.tsx
    │   │   │   ├── FillPlusCricleIcon.tsx
    │   │   │   ├── FilterIcon.tsx
    │   │   │   ├── FolderIcon.tsx
    │   │   │   ├── GlobeIcon.tsx
    │   │   │   ├── HomeIcon.tsx
    │   │   │   ├── HyperLinkIcon.tsx
    │   │   │   ├── Icon.md
    │   │   │   ├── Icon.module.scss
    │   │   │   ├── Icon.spec.ts
    │   │   │   ├── Icon.tsx
    │   │   │   ├── IconNative.tsx
    │   │   │   ├── ImageFileIcon.tsx
    │   │   │   ├── Inspect.tsx
    │   │   │   ├── LightToDark.tsx
    │   │   │   ├── LinkIcon.tsx
    │   │   │   ├── ListIcon.tsx
    │   │   │   ├── LooseListIcon.tsx
    │   │   │   ├── MoonIcon.tsx
    │   │   │   ├── MoreOptionsIcon.tsx
    │   │   │   ├── NoSortIcon.tsx
    │   │   │   ├── PDFIcon.tsx
    │   │   │   ├── PenIcon.tsx
    │   │   │   ├── PhoneIcon.tsx
    │   │   │   ├── PhotoIcon.tsx
    │   │   │   ├── PlusIcon.tsx
    │   │   │   ├── SearchIcon.tsx
    │   │   │   ├── ShareIcon.tsx
    │   │   │   ├── SortAscendingIcon.tsx
    │   │   │   ├── SortDescendingIcon.tsx
    │   │   │   ├── StarsIcon.tsx
    │   │   │   ├── SunIcon.tsx
    │   │   │   ├── svg
    │   │   │   │   ├── admonition_danger.svg
    │   │   │   │   ├── admonition_info.svg
    │   │   │   │   ├── admonition_note.svg
    │   │   │   │   ├── admonition_tip.svg
    │   │   │   │   ├── admonition_warning.svg
    │   │   │   │   ├── api.svg
    │   │   │   │   ├── arrow-dropdown.svg
    │   │   │   │   ├── arrow-left.svg
    │   │   │   │   ├── arrow-right.svg
    │   │   │   │   ├── arrow-up.svg
    │   │   │   │   ├── attach.svg
    │   │   │   │   ├── binding.svg
    │   │   │   │   ├── box.svg
    │   │   │   │   ├── bulb.svg
    │   │   │   │   ├── code-file.svg
    │   │   │   │   ├── code-sandbox.svg
    │   │   │   │   ├── dark_to_light.svg
    │   │   │   │   ├── database.svg
    │   │   │   │   ├── doc.svg
    │   │   │   │   ├── empty-folder.svg
    │   │   │   │   ├── expression.svg
    │   │   │   │   ├── eye-closed.svg
    │   │   │   │   ├── eye-dark.svg
    │   │   │   │   ├── eye.svg
    │   │   │   │   ├── file-text.svg
    │   │   │   │   ├── filter.svg
    │   │   │   │   ├── folder.svg
    │   │   │   │   ├── img.svg
    │   │   │   │   ├── inspect.svg
    │   │   │   │   ├── light_to_dark.svg
    │   │   │   │   ├── moon.svg
    │   │   │   │   ├── pdf.svg
    │   │   │   │   ├── photo.svg
    │   │   │   │   ├── share.svg
    │   │   │   │   ├── stars.svg
    │   │   │   │   ├── sun.svg
    │   │   │   │   ├── trending-down.svg
    │   │   │   │   ├── trending-level.svg
    │   │   │   │   ├── trending-up.svg
    │   │   │   │   ├── txt.svg
    │   │   │   │   ├── unknown-file.svg
    │   │   │   │   ├── unlink.svg
    │   │   │   │   └── xls.svg
    │   │   │   ├── TableDeleteColumnIcon.tsx
    │   │   │   ├── TableDeleteRowIcon.tsx
    │   │   │   ├── TableInsertColumnIcon.tsx
    │   │   │   ├── TableInsertRowIcon.tsx
    │   │   │   ├── TrashIcon.tsx
    │   │   │   ├── TrendingDownIcon.tsx
    │   │   │   ├── TrendingLevelIcon.tsx
    │   │   │   ├── TrendingUpIcon.tsx
    │   │   │   ├── TxtIcon.tsx
    │   │   │   ├── UnknownFileIcon.tsx
    │   │   │   ├── UnlinkIcon.tsx
    │   │   │   ├── UserIcon.tsx
    │   │   │   ├── WarningIcon.tsx
    │   │   │   └── XlsIcon.tsx
    │   │   ├── IconProvider.tsx
    │   │   ├── IconRegistryContext.tsx
    │   │   ├── IFrame
    │   │   │   ├── IFrame.md
    │   │   │   ├── IFrame.module.scss
    │   │   │   ├── IFrame.spec.ts
    │   │   │   ├── IFrame.tsx
    │   │   │   └── IFrameNative.tsx
    │   │   ├── Image
    │   │   │   ├── Image.md
    │   │   │   ├── Image.module.scss
    │   │   │   ├── Image.spec.ts
    │   │   │   ├── Image.tsx
    │   │   │   └── ImageNative.tsx
    │   │   ├── Input
    │   │   │   ├── index.ts
    │   │   │   ├── InputAdornment.module.scss
    │   │   │   ├── InputAdornment.tsx
    │   │   │   ├── InputDivider.module.scss
    │   │   │   ├── InputDivider.tsx
    │   │   │   ├── InputLabel.module.scss
    │   │   │   ├── InputLabel.tsx
    │   │   │   ├── PartialInput.module.scss
    │   │   │   └── PartialInput.tsx
    │   │   ├── InspectButton
    │   │   │   ├── InspectButton.module.scss
    │   │   │   └── InspectButton.tsx
    │   │   ├── Items
    │   │   │   ├── Items.md
    │   │   │   ├── Items.spec.ts
    │   │   │   ├── Items.tsx
    │   │   │   └── ItemsNative.tsx
    │   │   ├── Link
    │   │   │   ├── Link.md
    │   │   │   ├── Link.module.scss
    │   │   │   ├── Link.spec.ts
    │   │   │   ├── Link.tsx
    │   │   │   └── LinkNative.tsx
    │   │   ├── List
    │   │   │   ├── doc-resources
    │   │   │   │   └── list-component-data.js
    │   │   │   ├── List.md
    │   │   │   ├── List.module.scss
    │   │   │   ├── List.spec.ts
    │   │   │   ├── List.tsx
    │   │   │   └── ListNative.tsx
    │   │   ├── Logo
    │   │   │   ├── doc-resources
    │   │   │   │   └── xmlui-logo.svg
    │   │   │   ├── Logo.md
    │   │   │   ├── Logo.tsx
    │   │   │   └── LogoNative.tsx
    │   │   ├── Markdown
    │   │   │   ├── CodeText.module.scss
    │   │   │   ├── CodeText.tsx
    │   │   │   ├── Markdown.md
    │   │   │   ├── Markdown.module.scss
    │   │   │   ├── Markdown.spec.ts
    │   │   │   ├── Markdown.tsx
    │   │   │   ├── MarkdownNative.tsx
    │   │   │   ├── parse-binding-expr.ts
    │   │   │   └── utils.ts
    │   │   ├── metadata-helpers.ts
    │   │   ├── ModalDialog
    │   │   │   ├── ConfirmationModalContextProvider.tsx
    │   │   │   ├── Dialog.module.scss
    │   │   │   ├── Dialog.tsx
    │   │   │   ├── ModalDialog.md
    │   │   │   ├── ModalDialog.module.scss
    │   │   │   ├── ModalDialog.spec.ts
    │   │   │   ├── ModalDialog.tsx
    │   │   │   ├── ModalDialogNative.tsx
    │   │   │   └── ModalVisibilityContext.tsx
    │   │   ├── NavGroup
    │   │   │   ├── NavGroup.md
    │   │   │   ├── NavGroup.module.scss
    │   │   │   ├── NavGroup.spec.ts
    │   │   │   ├── NavGroup.tsx
    │   │   │   ├── NavGroupContext.ts
    │   │   │   └── NavGroupNative.tsx
    │   │   ├── NavLink
    │   │   │   ├── NavLink.md
    │   │   │   ├── NavLink.module.scss
    │   │   │   ├── NavLink.spec.ts
    │   │   │   ├── NavLink.tsx
    │   │   │   └── NavLinkNative.tsx
    │   │   ├── NavPanel
    │   │   │   ├── NavPanel.md
    │   │   │   ├── NavPanel.module.scss
    │   │   │   ├── NavPanel.spec.ts
    │   │   │   ├── NavPanel.tsx
    │   │   │   └── NavPanelNative.tsx
    │   │   ├── NestedApp
    │   │   │   ├── AppWithCodeView.module.scss
    │   │   │   ├── AppWithCodeView.tsx
    │   │   │   ├── AppWithCodeViewNative.tsx
    │   │   │   ├── defaultProps.tsx
    │   │   │   ├── logo.svg
    │   │   │   ├── NestedApp.module.scss
    │   │   │   ├── NestedApp.tsx
    │   │   │   ├── NestedAppNative.tsx
    │   │   │   ├── Tooltip.module.scss
    │   │   │   ├── Tooltip.tsx
    │   │   │   └── utils.ts
    │   │   ├── NoResult
    │   │   │   ├── NoResult.md
    │   │   │   ├── NoResult.module.scss
    │   │   │   ├── NoResult.spec.ts
    │   │   │   ├── NoResult.tsx
    │   │   │   └── NoResultNative.tsx
    │   │   ├── NumberBox
    │   │   │   ├── numberbox-abstractions.ts
    │   │   │   ├── NumberBox.md
    │   │   │   ├── NumberBox.module.scss
    │   │   │   ├── NumberBox.spec.ts
    │   │   │   ├── NumberBox.tsx
    │   │   │   └── NumberBoxNative.tsx
    │   │   ├── Option
    │   │   │   ├── Option.md
    │   │   │   ├── Option.spec.ts
    │   │   │   ├── Option.tsx
    │   │   │   ├── OptionNative.tsx
    │   │   │   └── OptionTypeProvider.tsx
    │   │   ├── PageMetaTitle
    │   │   │   ├── PageMetaTilteNative.tsx
    │   │   │   ├── PageMetaTitle.md
    │   │   │   ├── PageMetaTitle.spec.ts
    │   │   │   └── PageMetaTitle.tsx
    │   │   ├── Pages
    │   │   │   ├── Page.md
    │   │   │   ├── Pages.md
    │   │   │   ├── Pages.module.scss
    │   │   │   ├── Pages.tsx
    │   │   │   └── PagesNative.tsx
    │   │   ├── Pagination
    │   │   │   ├── Pagination.md
    │   │   │   ├── Pagination.module.scss
    │   │   │   ├── Pagination.spec.ts
    │   │   │   ├── Pagination.tsx
    │   │   │   └── PaginationNative.tsx
    │   │   ├── PositionedContainer
    │   │   │   ├── PositionedContainer.module.scss
    │   │   │   ├── PositionedContainer.tsx
    │   │   │   └── PositionedContainerNative.tsx
    │   │   ├── ProfileMenu
    │   │   │   ├── ProfileMenu.module.scss
    │   │   │   └── ProfileMenu.tsx
    │   │   ├── ProgressBar
    │   │   │   ├── ProgressBar.md
    │   │   │   ├── ProgressBar.module.scss
    │   │   │   ├── ProgressBar.spec.ts
    │   │   │   ├── ProgressBar.tsx
    │   │   │   └── ProgressBarNative.tsx
    │   │   ├── Queue
    │   │   │   ├── Queue.md
    │   │   │   ├── Queue.spec.ts
    │   │   │   ├── Queue.tsx
    │   │   │   ├── queueActions.ts
    │   │   │   └── QueueNative.tsx
    │   │   ├── RadioGroup
    │   │   │   ├── RadioGroup.md
    │   │   │   ├── RadioGroup.module.scss
    │   │   │   ├── RadioGroup.spec.ts
    │   │   │   ├── RadioGroup.tsx
    │   │   │   ├── RadioGroupNative.tsx
    │   │   │   ├── RadioItem.tsx
    │   │   │   └── RadioItemNative.tsx
    │   │   ├── RealTimeAdapter
    │   │   │   ├── RealTimeAdapter.tsx
    │   │   │   └── RealTimeAdapterNative.tsx
    │   │   ├── Redirect
    │   │   │   ├── Redirect.md
    │   │   │   ├── Redirect.spec.ts
    │   │   │   └── Redirect.tsx
    │   │   ├── ResponsiveBar
    │   │   │   ├── README.md
    │   │   │   ├── ResponsiveBar.md
    │   │   │   ├── ResponsiveBar.module.scss
    │   │   │   ├── ResponsiveBar.spec.ts
    │   │   │   ├── ResponsiveBar.tsx
    │   │   │   └── ResponsiveBarNative.tsx
    │   │   ├── Select
    │   │   │   ├── HiddenOption.tsx
    │   │   │   ├── OptionContext.ts
    │   │   │   ├── Select.md
    │   │   │   ├── Select.module.scss
    │   │   │   ├── Select.spec.ts
    │   │   │   ├── Select.tsx
    │   │   │   ├── SelectContext.tsx
    │   │   │   └── SelectNative.tsx
    │   │   ├── SelectionStore
    │   │   │   ├── SelectionStore.md
    │   │   │   ├── SelectionStore.tsx
    │   │   │   └── SelectionStoreNative.tsx
    │   │   ├── Slider
    │   │   │   ├── Slider.md
    │   │   │   ├── Slider.module.scss
    │   │   │   ├── Slider.spec.ts
    │   │   │   ├── Slider.tsx
    │   │   │   └── SliderNative.tsx
    │   │   ├── Slot
    │   │   │   ├── Slot.md
    │   │   │   ├── Slot.spec.ts
    │   │   │   └── Slot.ts
    │   │   ├── SlotItem.tsx
    │   │   ├── SpaceFiller
    │   │   │   ├── SpaceFiller.md
    │   │   │   ├── SpaceFiller.module.scss
    │   │   │   ├── SpaceFiller.spec.ts
    │   │   │   ├── SpaceFiller.tsx
    │   │   │   └── SpaceFillerNative.tsx
    │   │   ├── Spinner
    │   │   │   ├── Spinner.md
    │   │   │   ├── Spinner.module.scss
    │   │   │   ├── Spinner.spec.ts
    │   │   │   ├── Spinner.tsx
    │   │   │   └── SpinnerNative.tsx
    │   │   ├── Splitter
    │   │   │   ├── HSplitter.md
    │   │   │   ├── HSplitter.spec.ts
    │   │   │   ├── Splitter.md
    │   │   │   ├── Splitter.module.scss
    │   │   │   ├── Splitter.spec.ts
    │   │   │   ├── Splitter.tsx
    │   │   │   ├── SplitterNative.tsx
    │   │   │   ├── utils.ts
    │   │   │   ├── VSplitter.md
    │   │   │   └── VSplitter.spec.ts
    │   │   ├── Stack
    │   │   │   ├── CHStack.md
    │   │   │   ├── CHStack.spec.ts
    │   │   │   ├── CVStack.md
    │   │   │   ├── CVStack.spec.ts
    │   │   │   ├── HStack.md
    │   │   │   ├── HStack.spec.ts
    │   │   │   ├── Stack.md
    │   │   │   ├── Stack.module.scss
    │   │   │   ├── Stack.spec.ts
    │   │   │   ├── Stack.tsx
    │   │   │   ├── StackNative.tsx
    │   │   │   ├── VStack.md
    │   │   │   └── VStack.spec.ts
    │   │   ├── StickyBox
    │   │   │   ├── StickyBox.md
    │   │   │   ├── StickyBox.module.scss
    │   │   │   ├── StickyBox.tsx
    │   │   │   └── StickyBoxNative.tsx
    │   │   ├── Switch
    │   │   │   ├── Switch.md
    │   │   │   ├── Switch.spec.ts
    │   │   │   └── Switch.tsx
    │   │   ├── Table
    │   │   │   ├── doc-resources
    │   │   │   │   └── list-component-data.js
    │   │   │   ├── react-table-config.d.ts
    │   │   │   ├── Table.md
    │   │   │   ├── Table.module.scss
    │   │   │   ├── Table.spec.ts
    │   │   │   ├── Table.tsx
    │   │   │   ├── TableNative.tsx
    │   │   │   └── useRowSelection.tsx
    │   │   ├── TableOfContents
    │   │   │   ├── TableOfContents.module.scss
    │   │   │   ├── TableOfContents.spec.ts
    │   │   │   ├── TableOfContents.tsx
    │   │   │   └── TableOfContentsNative.tsx
    │   │   ├── Tabs
    │   │   │   ├── TabContext.tsx
    │   │   │   ├── TabItem.md
    │   │   │   ├── TabItem.tsx
    │   │   │   ├── TabItemNative.tsx
    │   │   │   ├── Tabs.md
    │   │   │   ├── Tabs.module.scss
    │   │   │   ├── Tabs.spec.ts
    │   │   │   ├── Tabs.tsx
    │   │   │   └── TabsNative.tsx
    │   │   ├── Text
    │   │   │   ├── Text.md
    │   │   │   ├── Text.module.scss
    │   │   │   ├── Text.spec.ts
    │   │   │   ├── Text.tsx
    │   │   │   └── TextNative.tsx
    │   │   ├── TextArea
    │   │   │   ├── TextArea.md
    │   │   │   ├── TextArea.module.scss
    │   │   │   ├── TextArea.spec.ts
    │   │   │   ├── TextArea.tsx
    │   │   │   ├── TextAreaNative.tsx
    │   │   │   ├── TextAreaResizable.tsx
    │   │   │   └── useComposedRef.ts
    │   │   ├── TextBox
    │   │   │   ├── TextBox.md
    │   │   │   ├── TextBox.module.scss
    │   │   │   ├── TextBox.spec.ts
    │   │   │   ├── TextBox.tsx
    │   │   │   └── TextBoxNative.tsx
    │   │   ├── Theme
    │   │   │   ├── NotificationToast.tsx
    │   │   │   ├── Theme.md
    │   │   │   ├── Theme.module.scss
    │   │   │   ├── Theme.spec.ts
    │   │   │   ├── Theme.tsx
    │   │   │   └── ThemeNative.tsx
    │   │   ├── TimeInput
    │   │   │   ├── TimeInput.md
    │   │   │   ├── TimeInput.module.scss
    │   │   │   ├── TimeInput.spec.ts
    │   │   │   ├── TimeInput.tsx
    │   │   │   ├── TimeInputNative.tsx
    │   │   │   └── utils.ts
    │   │   ├── Timer
    │   │   │   ├── Timer.md
    │   │   │   ├── Timer.spec.ts
    │   │   │   ├── Timer.tsx
    │   │   │   └── TimerNative.tsx
    │   │   ├── Toggle
    │   │   │   ├── Toggle.module.scss
    │   │   │   └── Toggle.tsx
    │   │   ├── ToneChangerButton
    │   │   │   ├── ToneChangerButton.md
    │   │   │   ├── ToneChangerButton.spec.ts
    │   │   │   └── ToneChangerButton.tsx
    │   │   ├── ToneSwitch
    │   │   │   ├── ToneSwitch.md
    │   │   │   ├── ToneSwitch.module.scss
    │   │   │   ├── ToneSwitch.spec.ts
    │   │   │   ├── ToneSwitch.tsx
    │   │   │   └── ToneSwitchNative.tsx
    │   │   ├── Tooltip
    │   │   │   ├── Tooltip.md
    │   │   │   ├── Tooltip.module.scss
    │   │   │   ├── Tooltip.spec.ts
    │   │   │   ├── Tooltip.tsx
    │   │   │   └── TooltipNative.tsx
    │   │   ├── Tree
    │   │   │   ├── testData.ts
    │   │   │   ├── Tree-dynamic.spec.ts
    │   │   │   ├── Tree-icons.spec.ts
    │   │   │   ├── Tree.md
    │   │   │   ├── Tree.spec.ts
    │   │   │   ├── TreeComponent.module.scss
    │   │   │   ├── TreeComponent.tsx
    │   │   │   └── TreeNative.tsx
    │   │   ├── TreeDisplay
    │   │   │   ├── TreeDisplay.md
    │   │   │   ├── TreeDisplay.module.scss
    │   │   │   ├── TreeDisplay.tsx
    │   │   │   └── TreeDisplayNative.tsx
    │   │   ├── ValidationSummary
    │   │   │   ├── ValidationSummary.module.scss
    │   │   │   └── ValidationSummary.tsx
    │   │   └── VisuallyHidden.tsx
    │   ├── components-core
    │   │   ├── abstractions
    │   │   │   ├── ComponentRenderer.ts
    │   │   │   ├── LoaderRenderer.ts
    │   │   │   ├── standalone.ts
    │   │   │   └── treeAbstractions.ts
    │   │   ├── action
    │   │   │   ├── actions.ts
    │   │   │   ├── APICall.tsx
    │   │   │   ├── FileDownloadAction.tsx
    │   │   │   ├── FileUploadAction.tsx
    │   │   │   ├── NavigateAction.tsx
    │   │   │   └── TimedAction.tsx
    │   │   ├── ApiBoundComponent.tsx
    │   │   ├── appContext
    │   │   │   ├── date-functions.ts
    │   │   │   ├── math-function.ts
    │   │   │   └── misc-utils.ts
    │   │   ├── AppContext.tsx
    │   │   ├── behaviors
    │   │   │   ├── Behavior.tsx
    │   │   │   └── CoreBehaviors.tsx
    │   │   ├── component-hooks.ts
    │   │   ├── ComponentDecorator.tsx
    │   │   ├── ComponentViewer.tsx
    │   │   ├── CompoundComponent.tsx
    │   │   ├── constants.ts
    │   │   ├── DebugViewProvider.tsx
    │   │   ├── descriptorHelper.ts
    │   │   ├── devtools
    │   │   │   ├── InspectorDialog.module.scss
    │   │   │   ├── InspectorDialog.tsx
    │   │   │   └── InspectorDialogVisibilityContext.tsx
    │   │   ├── EngineError.ts
    │   │   ├── event-handlers.ts
    │   │   ├── InspectorButton.module.scss
    │   │   ├── InspectorContext.tsx
    │   │   ├── interception
    │   │   │   ├── abstractions.ts
    │   │   │   ├── ApiInterceptor.ts
    │   │   │   ├── ApiInterceptorProvider.tsx
    │   │   │   ├── apiInterceptorWorker.ts
    │   │   │   ├── Backend.ts
    │   │   │   ├── Errors.ts
    │   │   │   ├── IndexedDb.ts
    │   │   │   ├── initMock.ts
    │   │   │   ├── InMemoryDb.ts
    │   │   │   ├── ReadonlyCollection.ts
    │   │   │   └── useApiInterceptorContext.tsx
    │   │   ├── loader
    │   │   │   ├── ApiLoader.tsx
    │   │   │   ├── DataLoader.tsx
    │   │   │   ├── ExternalDataLoader.tsx
    │   │   │   ├── Loader.tsx
    │   │   │   ├── MockLoaderRenderer.tsx
    │   │   │   └── PageableLoader.tsx
    │   │   ├── LoaderComponent.tsx
    │   │   ├── markup-check.ts
    │   │   ├── parts.ts
    │   │   ├── renderers.ts
    │   │   ├── rendering
    │   │   │   ├── AppContent.tsx
    │   │   │   ├── AppRoot.tsx
    │   │   │   ├── AppWrapper.tsx
    │   │   │   ├── buildProxy.ts
    │   │   │   ├── collectFnVarDeps.ts
    │   │   │   ├── ComponentAdapter.tsx
    │   │   │   ├── ComponentWrapper.tsx
    │   │   │   ├── Container.tsx
    │   │   │   ├── containers.ts
    │   │   │   ├── ContainerWrapper.tsx
    │   │   │   ├── ErrorBoundary.module.scss
    │   │   │   ├── ErrorBoundary.tsx
    │   │   │   ├── InvalidComponent.module.scss
    │   │   │   ├── InvalidComponent.tsx
    │   │   │   ├── nodeUtils.ts
    │   │   │   ├── reducer.ts
    │   │   │   ├── renderChild.tsx
    │   │   │   ├── StandaloneComponent.tsx
    │   │   │   ├── StateContainer.tsx
    │   │   │   ├── UnknownComponent.module.scss
    │   │   │   ├── UnknownComponent.tsx
    │   │   │   └── valueExtractor.ts
    │   │   ├── reportEngineError.ts
    │   │   ├── RestApiProxy.ts
    │   │   ├── script-runner
    │   │   │   ├── asyncProxy.ts
    │   │   │   ├── AttributeValueParser.ts
    │   │   │   ├── bannedFunctions.ts
    │   │   │   ├── BindingTreeEvaluationContext.ts
    │   │   │   ├── eval-tree-async.ts
    │   │   │   ├── eval-tree-common.ts
    │   │   │   ├── eval-tree-sync.ts
    │   │   │   ├── ParameterParser.ts
    │   │   │   ├── process-statement-async.ts
    │   │   │   ├── process-statement-common.ts
    │   │   │   ├── process-statement-sync.ts
    │   │   │   ├── ScriptingSourceTree.ts
    │   │   │   ├── simplify-expression.ts
    │   │   │   ├── statement-queue.ts
    │   │   │   └── visitors.ts
    │   │   ├── StandaloneApp.tsx
    │   │   ├── StandaloneExtensionManager.ts
    │   │   ├── TableOfContentsContext.tsx
    │   │   ├── theming
    │   │   │   ├── _themes.scss
    │   │   │   ├── component-layout-resolver.ts
    │   │   │   ├── extendThemeUtils.ts
    │   │   │   ├── hvar.ts
    │   │   │   ├── layout-resolver.ts
    │   │   │   ├── parse-layout-props.ts
    │   │   │   ├── StyleContext.tsx
    │   │   │   ├── StyleRegistry.ts
    │   │   │   ├── ThemeContext.tsx
    │   │   │   ├── ThemeProvider.tsx
    │   │   │   ├── themes
    │   │   │   │   ├── base-utils.ts
    │   │   │   │   ├── palette.ts
    │   │   │   │   ├── root.ts
    │   │   │   │   ├── solid.ts
    │   │   │   │   ├── theme-colors.ts
    │   │   │   │   └── xmlui.ts
    │   │   │   ├── themeVars.module.scss
    │   │   │   ├── themeVars.ts
    │   │   │   ├── transformThemeVars.ts
    │   │   │   └── utils.ts
    │   │   ├── utils
    │   │   │   ├── actionUtils.ts
    │   │   │   ├── audio-utils.ts
    │   │   │   ├── base64-utils.ts
    │   │   │   ├── compound-utils.ts
    │   │   │   ├── css-utils.ts
    │   │   │   ├── DataLoaderQueryKeyGenerator.ts
    │   │   │   ├── date-utils.ts
    │   │   │   ├── extractParam.ts
    │   │   │   ├── hooks.tsx
    │   │   │   ├── LruCache.ts
    │   │   │   ├── mergeProps.ts
    │   │   │   ├── misc.ts
    │   │   │   ├── request-params.ts
    │   │   │   ├── statementUtils.ts
    │   │   │   └── treeUtils.ts
    │   │   └── xmlui-parser.ts
    │   ├── index-standalone.ts
    │   ├── index.scss
    │   ├── index.ts
    │   ├── language-server
    │   │   ├── server-common.ts
    │   │   ├── server-web-worker.ts
    │   │   ├── server.ts
    │   │   ├── services
    │   │   │   ├── common
    │   │   │   │   ├── docs-generation.ts
    │   │   │   │   ├── lsp-utils.ts
    │   │   │   │   ├── metadata-utils.ts
    │   │   │   │   └── syntax-node-utilities.ts
    │   │   │   ├── completion.ts
    │   │   │   ├── diagnostic.ts
    │   │   │   ├── format.ts
    │   │   │   └── hover.ts
    │   │   └── xmlui-metadata-generated.js
    │   ├── logging
    │   │   ├── LoggerContext.tsx
    │   │   ├── LoggerInitializer.tsx
    │   │   ├── LoggerService.ts
    │   │   └── xmlui.ts
    │   ├── logo.svg
    │   ├── parsers
    │   │   ├── common
    │   │   │   ├── GenericToken.ts
    │   │   │   ├── InputStream.ts
    │   │   │   └── utils.ts
    │   │   ├── scripting
    │   │   │   ├── code-behind-collect.ts
    │   │   │   ├── Lexer.ts
    │   │   │   ├── modules.ts
    │   │   │   ├── Parser.ts
    │   │   │   ├── ParserError.ts
    │   │   │   ├── ScriptingNodeTypes.ts
    │   │   │   ├── TokenTrait.ts
    │   │   │   ├── TokenType.ts
    │   │   │   └── tree-visitor.ts
    │   │   ├── style-parser
    │   │   │   ├── errors.ts
    │   │   │   ├── source-tree.ts
    │   │   │   ├── StyleInputStream.ts
    │   │   │   ├── StyleLexer.ts
    │   │   │   ├── StyleParser.ts
    │   │   │   └── tokens.ts
    │   │   └── xmlui-parser
    │   │       ├── CharacterCodes.ts
    │   │       ├── diagnostics.ts
    │   │       ├── fileExtensions.ts
    │   │       ├── index.ts
    │   │       ├── lint.ts
    │   │       ├── parser.ts
    │   │       ├── ParserError.ts
    │   │       ├── scanner.ts
    │   │       ├── syntax-kind.ts
    │   │       ├── syntax-node.ts
    │   │       ├── transform.ts
    │   │       ├── utils.ts
    │   │       ├── xmlui-serializer.ts
    │   │       └── xmlui-tree.ts
    │   ├── react-app-env.d.ts
    │   ├── syntax
    │   │   ├── monaco
    │   │   │   ├── grammar.monacoLanguage.ts
    │   │   │   ├── index.ts
    │   │   │   ├── xmlui-dark.ts
    │   │   │   ├── xmlui-light.ts
    │   │   │   └── xmluiscript.monacoLanguage.ts
    │   │   └── textMate
    │   │       ├── index.ts
    │   │       ├── xmlui-dark.json
    │   │       ├── xmlui-light.json
    │   │       ├── xmlui.json
    │   │       └── xmlui.tmLanguage.json
    │   ├── testing
    │   │   ├── assertions.ts
    │   │   ├── component-test-helpers.ts
    │   │   ├── ComponentDrivers.ts
    │   │   ├── drivers
    │   │   │   ├── DateInputDriver.ts
    │   │   │   ├── index.ts
    │   │   │   ├── ModalDialogDriver.ts
    │   │   │   ├── NumberBoxDriver.ts
    │   │   │   ├── TextBoxDriver.ts
    │   │   │   ├── TimeInputDriver.ts
    │   │   │   ├── TimerDriver.ts
    │   │   │   └── TreeDriver.ts
    │   │   ├── fixtures.ts
    │   │   ├── index.ts
    │   │   ├── infrastructure
    │   │   │   ├── index.html
    │   │   │   ├── main.tsx
    │   │   │   ├── public
    │   │   │   │   ├── mockServiceWorker.js
    │   │   │   │   ├── resources
    │   │   │   │   │   ├── bell.svg
    │   │   │   │   │   ├── box.svg
    │   │   │   │   │   ├── doc.svg
    │   │   │   │   │   ├── eye.svg
    │   │   │   │   │   ├── flower-640x480.jpg
    │   │   │   │   │   ├── sun.svg
    │   │   │   │   │   ├── test-image-100x100.jpg
    │   │   │   │   │   └── txt.svg
    │   │   │   │   └── serve.json
    │   │   │   └── TestBed.tsx
    │   │   └── themed-app-test-helpers.ts
    │   └── vite-env.d.ts
    ├── tests
    │   ├── components
    │   │   ├── CodeBlock
    │   │   │   └── hightlight-code.test.ts
    │   │   ├── playground-pattern.test.ts
    │   │   └── Tree
    │   │       └── Tree-states.test.ts
    │   ├── components-core
    │   │   ├── abstractions
    │   │   │   └── treeAbstractions.test.ts
    │   │   ├── container
    │   │   │   └── buildProxy.test.ts
    │   │   ├── interception
    │   │   │   ├── orderBy.test.ts
    │   │   │   ├── ReadOnlyCollection.test.ts
    │   │   │   └── request-param-converter.test.ts
    │   │   ├── scripts-runner
    │   │   │   ├── AttributeValueParser.test.ts
    │   │   │   ├── eval-tree-arrow-async.test.ts
    │   │   │   ├── eval-tree-arrow.test.ts
    │   │   │   ├── eval-tree-func-decl-async.test.ts
    │   │   │   ├── eval-tree-func-decl.test.ts
    │   │   │   ├── eval-tree-pre-post.test.ts
    │   │   │   ├── eval-tree-regression.test.ts
    │   │   │   ├── eval-tree.test.ts
    │   │   │   ├── function-proxy.test.ts
    │   │   │   ├── parser-regression.test.ts
    │   │   │   ├── process-event.test.ts
    │   │   │   ├── process-function.test.ts
    │   │   │   ├── process-implicit-context.test.ts
    │   │   │   ├── process-statement-asgn.test.ts
    │   │   │   ├── process-statement-destruct.test.ts
    │   │   │   ├── process-statement-regs.test.ts
    │   │   │   ├── process-statement-sync.test.ts
    │   │   │   ├── process-statement.test.ts
    │   │   │   ├── process-switch-sync.test.ts
    │   │   │   ├── process-switch.test.ts
    │   │   │   ├── process-try-sync.test.ts
    │   │   │   ├── process-try.test.ts
    │   │   │   └── test-helpers.ts
    │   │   ├── test-metadata-handler.ts
    │   │   ├── theming
    │   │   │   ├── border-segments.test.ts
    │   │   │   ├── component-layout.resolver.test.ts
    │   │   │   ├── layout-property-parser.test.ts
    │   │   │   ├── layout-resolver.test.ts
    │   │   │   ├── layout-resolver2.test.ts
    │   │   │   ├── layout-vp-override.test.ts
    │   │   │   └── padding-segments.test.ts
    │   │   └── utils
    │   │       ├── date-utils.test.ts
    │   │       ├── format-human-elapsed-time.test.ts
    │   │       └── LruCache.test.ts
    │   ├── language-server
    │   │   ├── completion.test.ts
    │   │   ├── format.test.ts
    │   │   ├── hover.test.ts
    │   │   └── mockData.ts
    │   └── parsers
    │       ├── common
    │       │   └── input-stream.test.ts
    │       ├── markdown
    │       │   └── parse-binding-expression.test.ts
    │       ├── parameter-parser.test.ts
    │       ├── paremeter-parser.test.ts
    │       ├── scripting
    │       │   ├── eval-tree-arrow.test.ts
    │       │   ├── eval-tree-pre-post.test.ts
    │       │   ├── eval-tree.test.ts
    │       │   ├── function-proxy.test.ts
    │       │   ├── lexer-literals.test.ts
    │       │   ├── lexer-misc.test.ts
    │       │   ├── module-parse.test.ts
    │       │   ├── parser-arrow.test.ts
    │       │   ├── parser-assignments.test.ts
    │       │   ├── parser-binary.test.ts
    │       │   ├── parser-destructuring.test.ts
    │       │   ├── parser-errors.test.ts
    │       │   ├── parser-expressions.test.ts
    │       │   ├── parser-function.test.ts
    │       │   ├── parser-literals.test.ts
    │       │   ├── parser-primary.test.ts
    │       │   ├── parser-regex.test.ts
    │       │   ├── parser-statements.test.ts
    │       │   ├── parser-unary.test.ts
    │       │   ├── process-event.test.ts
    │       │   ├── process-implicit-context.test.ts
    │       │   ├── process-statement-asgn.test.ts
    │       │   ├── process-statement-destruct.test.ts
    │       │   ├── process-statement-regs.test.ts
    │       │   ├── process-statement-sync.test.ts
    │       │   ├── process-statement.test.ts
    │       │   ├── process-switch-sync.test.ts
    │       │   ├── process-switch.test.ts
    │       │   ├── process-try-sync.test.ts
    │       │   ├── process-try.test.ts
    │       │   ├── simplify-expression.test.ts
    │       │   ├── statement-hooks.test.ts
    │       │   └── test-helpers.ts
    │       ├── style-parser
    │       │   ├── generateHvarChain.test.ts
    │       │   ├── parseHVar.test.ts
    │       │   ├── parser.test.ts
    │       │   └── tokens.test.ts
    │       └── xmlui
    │           ├── lint.test.ts
    │           ├── parser.test.ts
    │           ├── scanner.test.ts
    │           ├── transform.attr.test.ts
    │           ├── transform.circular.test.ts
    │           ├── transform.element.test.ts
    │           ├── transform.errors.test.ts
    │           ├── transform.escape.test.ts
    │           ├── transform.regression.test.ts
    │           ├── transform.script.test.ts
    │           ├── transform.test.ts
    │           └── xmlui.ts
    ├── tests-e2e
    │   ├── api-bound-component-regression.spec.ts
    │   ├── api-call-as-extracted-component.spec.ts
    │   ├── assign-to-object-or-array-regression.spec.ts
    │   ├── binding-regression.spec.ts
    │   ├── children-as-template-context-vars.spec.ts
    │   ├── compound-component.spec.ts
    │   ├── context-vars-regression.spec.ts
    │   ├── data-bindings.spec.ts
    │   ├── datasource-and-api-usage-in-var.spec.ts
    │   ├── datasource-direct-binding.spec.ts
    │   ├── datasource-onLoaded-regression.spec.ts
    │   ├── modify-array-item-regression.spec.ts
    │   ├── namespaces.spec.ts
    │   ├── push-to-array-regression.spec.ts
    │   ├── screen-breakpoints.spec.ts
    │   ├── scripting.spec.ts
    │   ├── state-scope-in-pages.spec.ts
    │   └── state-var-scopes.spec.ts
    ├── tsconfig.json
    ├── tsdown.config.ts
    ├── vite.config.ts
    └── vitest.config.ts
```

# Files

--------------------------------------------------------------------------------
/xmlui/src/language-server/services/completion.ts:
--------------------------------------------------------------------------------

```typescript
import type { MarkupContent, CompletionItem, Position } from "vscode-languageserver";
import { CompletionItemKind, MarkupKind } from "vscode-languageserver";
import type { GetText, ParseResult } from "../../parsers/xmlui-parser/parser";
import { findTokenAtPos } from "../../parsers/xmlui-parser/utils";
import { SyntaxKind } from "../../parsers/xmlui-parser/syntax-kind";
import type { Node } from "../../parsers/xmlui-parser/syntax-node";
import * as docGen from "./common/docs-generation";
import {
  compNameForTagNameNode,
  findTagNameNodeInStack,
  getFirstNodeFromAncestorChain,
  insideClosingTag,
  visitAncestorsInChain,
} from "./common/syntax-node-utilities";
import {
  addOnPrefix,
  type AttributeKind,
  type MetadataProvider,
  type TaggedAttribute,
} from "./common/metadata-utils";

type Override<Type, NewType extends { [key in keyof Type]?: NewType[key] }> = Omit<
  Type,
  keyof NewType
> &
  NewType;

/**
 * Additional data that a completion item contains.
 * with that, a completion item can be resolved, thus
 * the sever can query the documentation of a component,
 * prop, event etc...
 */
type XmluiCompletionData = {
  metadataAccessInfo: {
    componentName: string;
    attribute?: TaggedAttribute;
  };
};

export type XmluiCompletionItem = Override<CompletionItem, { data?: XmluiCompletionData }>;

type CompletionResolveContext = {
  item: XmluiCompletionItem;
  metaByComp: MetadataProvider;
};

export function handleCompletionResolve({
  item,
  metaByComp: metaByComp,
}: CompletionResolveContext): CompletionItem {
  const metadataAccessInfo = item?.data?.metadataAccessInfo;
  if (metadataAccessInfo) {
    const { componentName, attribute } = metadataAccessInfo;
    const componentMeta = metaByComp.getComponent(componentName);
    if (!componentMeta) {
      return null;
    }
    if (attribute) {
      const attributeMetadata = componentMeta.getAttrForKind(attribute);
      item.documentation = markupContent(
        docGen.generateAttrDescription(attribute.name, attributeMetadata),
      );
    } else {
      item.documentation = markupContent(
        docGen.generateCompNameDescription(componentName, componentMeta.getMetadata()),
      );
    }
  }
  return item;
}

type CompletionContext = {
  parseResult: ParseResult;
  getText: GetText;
  metaByComp: MetadataProvider;
  offsetToPos: (offset: number) => Position;
};

export function handleCompletion(
  { parseResult: { node }, getText, metaByComp, offsetToPos }: CompletionContext,
  position: number,
): XmluiCompletionItem[] | null {
  const findRes = findTokenAtPos(node, position);
  if (!findRes) {
    return null;
  }
  const { chainAtPos, chainBeforePos } = findRes;

  if (findRes.chainBeforePos === undefined) {
    return handleCompletionInsideToken(chainAtPos, position, metaByComp, getText);
  }

  const nodeBefore = chainBeforePos.at(-1);
  switch (nodeBefore.kind) {
    case SyntaxKind.OpenNodeStart:
      const defaultCompNames = allComponentNames(metaByComp);
      const closestElementNodeSuspect = chainBeforePos.at(-2);

      if (closestElementNodeSuspect && closestElementNodeSuspect.kind === SyntaxKind.ElementNode) {
        const matchingNode = getFirstNodeFromAncestorChain(
          chainBeforePos.slice(0, -3),
          SyntaxKind.ElementNode,
        );
        if (!matchingNode) return defaultCompNames;

        const compName = getNameFromElement(matchingNode, getText);
        if (!compName) return defaultCompNames;

        const compNameSuggestion = closingComponentCompletionItem(compName, offsetToPos, position);
        return [compNameSuggestion, ...defaultCompNames.map((c) => ({ ...c, sortText: "1" }))];
      }
      return defaultCompNames;

    case SyntaxKind.CloseNodeStart: {
      //TODO: this can be substituted for an function that finds the first ElementNode up the tree
      const closestElementNodeSuspect = chainBeforePos.at(-2);
      if (closestElementNodeSuspect && closestElementNodeSuspect.kind === SyntaxKind.ElementNode) {
        const compName = getNameFromElement(closestElementNodeSuspect, getText);
        if (!compName) return allComponentNames(metaByComp);
        return [componentCompletionItem(compName)];
      } else {
        return allComponentNames(metaByComp);
      }
    }
    case SyntaxKind.Identifier:
      const pathToElementNode = visitAncestorsInChain(
        chainBeforePos,
        (n) => n.kind === SyntaxKind.ElementNode,
      );
      const parentOfnodeBefore = chainBeforePos.at(-2);
      const completeCompName =
        parentOfnodeBefore?.kind === SyntaxKind.TagNameNode && position === nodeBefore.end;
      if (completeCompName) {
        if (pathToElementNode && insideClosingTag(pathToElementNode)) {
          const compName = getNameFromElement(pathToElementNode.at(-1), getText);
          if (!compName) return allComponentNames(metaByComp);
          return [componentCompletionItem(compName)];
        }
        return allComponentNames(metaByComp);
      }
  }

  const completeForProp = chainBeforePos.some(
    (n) =>
      n.kind === SyntaxKind.AttributeKeyNode ||
      n.kind === SyntaxKind.TagNameNode ||
      n.kind === SyntaxKind.AttributeNode,
  );

  if (completeForProp) {
    const tagNameNode = findTagNameNodeInStack(chainBeforePos);
    if (!tagNameNode) {
      return null;
    }
    const compName = compNameForTagNameNode(tagNameNode, getText);
    if (!compName) {
      return null;
    }
    return completionForNewAttr(compName, metaByComp);
  }
  return null;
}

function allComponentNames(md: MetadataProvider): XmluiCompletionItem[] {
  return md.componentNames().map(componentCompletionItem);
}

/**
 * Retrieves the name from an ElementNode
 * @param elementNode has to point to a ElementNode
 * @returns
 */
function getNameFromElement(elementNode: Node, getText: GetText): string | null {
  const nameNode = elementNode.children!.find((c) => c.kind === SyntaxKind.TagNameNode);
  if (nameNode === undefined) {
    return null;
  }
  // --- Handle namespaces
  const colonIdx = nameNode.children!.findIndex((c) => c.kind === SyntaxKind.Colon);
  let nameSpace: string | undefined = undefined;
  let nameIdentSearchSpace = nameNode.children!;
  let name: string | undefined = undefined;
  if (colonIdx !== -1) {
    nameIdentSearchSpace = nameNode.children!.slice(colonIdx + 1);
    const nameSpaceIdx = nameNode.children!.findIndex((c) => c.kind === SyntaxKind.Identifier);
    if (nameSpaceIdx < colonIdx) {
      nameSpace = getText(nameNode.children![nameSpaceIdx]);
    }
  }
  const nameIdent = nameIdentSearchSpace.find((c) => c.kind === SyntaxKind.Identifier);
  if (nameIdent === undefined) {
    return null;
  }
  name = getText(nameIdent);
  const value = nameSpace !== undefined ? nameSpace + ":" + name : name;
  return value;
}

function handleCompletionInsideToken(
  chainAtPos: Node[],
  position: number,
  metaByComp: MetadataProvider,
  getText: (n: Node) => string,
): CompletionItem[] | null {
  const parent = chainAtPos.at(-2);
  if (!parent) {
    return null;
  }
  switch (parent.kind) {
    case SyntaxKind.TagNameNode: {
      const tagNameNodeParent = chainAtPos.at(-3);
      const tagNameNodeIdx = tagNameNodeParent.children!.findIndex((c) => c === parent);
      if (tagNameNodeIdx <= 0) {
        return null;
      }
      const previousNode = tagNameNodeParent.children![tagNameNodeIdx - 1];
      if (
        previousNode.kind === SyntaxKind.CloseNodeStart &&
        tagNameNodeParent.kind === SyntaxKind.ElementNode
      ) {
        const compName = getNameFromElement(tagNameNodeParent, getText);
        if (!compName) return allComponentNames(metaByComp);
        return [componentCompletionItem(compName)];
      }
      return allComponentNames(metaByComp);
    }
    case SyntaxKind.AttributeKeyNode: {
      const tagNameNode = findTagNameNodeInStack(chainAtPos);
      const compName = compNameForTagNameNode(tagNameNode, getText);
      return completionForNewAttr(compName, metaByComp);
    }
  }
  return null;
}

function completionForNewAttr(
  compName: string,
  metaByComp: MetadataProvider,
): CompletionItem[] | null {
  const metadata = metaByComp.getComponent(compName);
  if (!metadata) {
    return null;
  }

  const completionItemFromAttr = attributeCompletionItem.bind({}, compName);
  return metadata.getAllAttributes().map(completionItemFromAttr);
}

function attrKindToCompletionItemKind(attrKind: AttributeKind) {
  switch (attrKind) {
    case "api":
      return CompletionItemKind.Function;
    case "event":
      return CompletionItemKind.Event;
    case "layout":
      return CompletionItemKind.Unit;
    case "prop":
    case "implicit":
      return CompletionItemKind.Property;
    default:
      const _exhaustiveCheck: never = attrKind;
      return _exhaustiveCheck;
  }
}

function attributeCompletionItem(
  componentName: string,
  attribute: TaggedAttribute,
): XmluiCompletionItem {
  const label = attribute.kind === "event" ? addOnPrefix(attribute.name) : attribute.name;
  return {
    label,
    kind: attrKindToCompletionItemKind(attribute.kind),
    sortText: attributeDisplayOrder(attribute.kind) + label,
    data: {
      metadataAccessInfo: {
        componentName,
        attribute,
      },
    },
  };
}

function componentCompletionItem(
  componentName: string,
  sortingOrder?: number,
): XmluiCompletionItem {
  const sortText =
    sortingOrder !== undefined &&
    sortingOrder !== 0 &&
    sortingOrder !== null &&
    !isNaN(sortingOrder)
      ? sortingOrder.toString()
      : "";
  return {
    label: componentName,
    kind: CompletionItemKind.Constructor,
    sortText,
    data: {
      metadataAccessInfo: {
        componentName,
      },
    },
  };
}

function closingComponentCompletionItem(
  componentName: string,
  offsetToPos: (offset: number) => Position,
  cursorOffset: number,
): XmluiCompletionItem {
  const cursorPos = offsetToPos(cursorOffset);
  const updatedText = /* TODO globals.clientSupports.insertReplaceEdit ? Handle this case : */ {
    newText: `/${componentName}>`,
    range: { start: cursorPos, end: cursorPos },
  };
  return {
    label: `/${componentName}`,
    kind: CompletionItemKind.Constructor,
    sortText: "0",
    textEdit: updatedText,
    data: {
      metadataAccessInfo: {
        componentName,
      },
    },
  };
}

function markupContent(content: string): MarkupContent {
  return {
    kind: MarkupKind.Markdown,
    value: content,
  };
}
function attributeDisplayOrder(kind: AttributeKind): string {
  switch (kind) {
    case "api":
    case "prop":
    case "implicit":
    case "event":
      return "0";

    case "layout":
      return "1";
    default: {
      const _exhaustiveCheck: never = kind;
      return _exhaustiveCheck;
    }
  }
}

```

--------------------------------------------------------------------------------
/xmlui/dev-docs/next/generating-component-reference.md:
--------------------------------------------------------------------------------

```markdown
# Generate Component Reference Documentation

This document describes how to generate and maintain component reference documentation for XMLUI components, including automated documentation extraction from source code and manual documentation creation.

## Overview

XMLUI component reference documentation is generated from multiple sources:
- **Component Metadata** - The XMLUI framework has a particular metadata structure that describes an XMLUI component including its properties, events, exposed methods, and other component traits. Each component must define its metadata.
- **Component Documentation Files** - Markdown files with directive-based content injection. These files can declare additional metadata content in markdown format, such as code samples, tables, additional explanations, etc. While the component metadata is available within the framework and its tools (and also for external tools), the content in component documentation files is just for generating the reference documentation of components.

## Prerequisites

All documentation generation commands should be run from the `xmlui` subfolder:

```bash
cd xmlui
npm run generate-all-docs
```

## Documentation Generation Workflow

1. **Build component metadata** (`npm run build:xmlui-metadata`) - Export component metadata to a JSON file using Vite's metadata build mode
2. **Build extension metadata** (`npm run build:ext-meta`) - Process extension package metadata 
3. **Generate component docs** (`npm run generate-docs`) - Merge component metadata with component documentation files using the DocsGenerator
4. **Generate summary files** (`npm run generate-docs-summaries`) - Create overview documents and metadata files
5. **Output to docs folder** - Place generated documents into `docs/content/components/`

> **Note**
> The `npm run generate-all-docs` command runs the complete pipeline in the correct order: metadata extraction, extension processing, documentation generation, and summary creation.

### Available Scripts

- `npm run build:xmlui-metadata` - Extract component metadata only
- `npm run generate-docs` - Generate docs from existing metadata
- `npm run generate-docs-summaries` - Generate overview and meta files
- `npm run generate-all-docs` - Complete documentation generation pipeline (recommended)

## Sample Component Folder Structure

```bash
xmlui/src/components/
├── ...
├── Button/
│   ├── Button.tsx              # Component implementation (includes metadata) 📖 used for docs
│   ├── ButtonNative.tsx        # Underlying React component
│   ├── Button.md               # Component documentation file 📖 used for docs
│   ├── Button.module.scss      # Component styles
│   ├── Button.spec.ts          # Component tests
│   └── Button-style.spec.ts    # Style-specific tests
├── ...
├── Text/
│   ├── Text.tsx                # Component implementation (includes metadata) 📖 used for docs
│   ├── TextNative.tsx          # Underlying React component
│   ├── Text.md                 # Component documentation file 📖 used for docs
│   ├── Text.module.scss        # Component styles
│   └── Text.spec.ts            # Component tests
└── ...
```

The system uses a sophisticated multi-stage process involving npm scripts and Node.js modules to automatically generate comprehensive component documentation.

## Component Documentation Patterns: Metadata-Driven vs. Markdown-Driven

XMLUI supports two main patterns for generating component reference documentation, depending on where the component is located in the codebase:

### 1. Metadata-Driven Documentation (`components-core`)

- Components in `xmlui/src/components-core/` (such as `Fragment`) define their documentation primarily through metadata in their TypeScript source files.
- The metadata is created using the `createMetadata()` function, which includes descriptions, property definitions, events, and more.
- Example (in `Fragment.tsx`):
  ```ts
  export const FragmentMd = createMetadata({
    description: "...",
    props: {
      when: {
        description: "...",
        valueType: "boolean | expression"
      }
    }
  });
  ```
- The documentation generator uses this metadata to produce the reference docs. If a Markdown file exists for the component, it will merge in any matching %-PROP-START/END blocks, but only for properties present in the metadata.

### 2. Markdown-Driven Documentation (`components`)

- Components in `xmlui/src/components/` (such as `Image`) have a dedicated Markdown file (e.g., `Image.md`) located alongside the component source.
- This Markdown file contains detailed documentation, examples, and property/event explanations using directive blocks:
  ```
  %-PROP-START propertyName
  ...documentation and examples...
  %-PROP-END
  ```
- The documentation generator merges the Markdown content with the component’s metadata, allowing for rich, user-friendly docs.

### Key Differences

- **Location**:  
  - `components-core`: Metadata-driven, TypeScript source is primary.
  - `components`: Markdown-driven, `.md` file is primary.
- **Customization**:  
  - `components-core`: Customization is limited to what’s in the metadata unless a Markdown file is added.
  - `components`: Full Markdown flexibility for examples, tables, and extended explanations.
- **Doc Generation**:  
  - In both cases, the doc generator merges metadata and Markdown, but only properties/events present in the metadata will be documented.

### Best Practices

- For new user-facing components, prefer the Markdown-driven approach for richer documentation.
- For foundational or internal components, metadata-driven docs may be sufficient, but you can always add a Markdown file for more detail.
- Always ensure that any property or event you want documented in Markdown is also present in the component’s metadata.


## Sample Component Metadata

```typescript
export const AvatarMd = createMetadata({
  description:
    "`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.",
  props: {
    size: {
      description: `This property defines the display size of the Avatar.`,
      availableValues: sizeMd,
      valueType: "string",
      defaultValue: defaultProps.size,
    },
    name: {
      description:
        `This property sets the name value the Avatar uses to display initials. If neither ` +
        "this property nor \`url\` is defined, an empty avatar is displayed.",
      valueType: "string",
    },
    url: {
      description:
        `This property specifies the URL of the image to display in the Avatar. ` +
        "If neither this property nor \`name\` is defined, an empty avatar is displayed.",
      valueType: "string",
    },
  },
  events: {
    click: d("This event is triggered when the avatar is clicked."),
  },
  themeVars: parseScssVar(styles.themeVars),
  defaultThemeVars: {
    [`borderRadius-Avatar`]: "4px",
    [`boxShadow-Avatar`]: "inset 0 0 0 1px rgba(4,32,69,0.1)",
    [`textColor-Avatar`]: "$textColor-secondary",
    [`fontWeight-Avatar`]: "$fontWeight-bold",
    [`border-Avatar`]: "0px solid $color-surface-400A80",
    [`backgroundColor-Avatar`]: "$color-surface-100",
  },
});
```

This metadata structure includes:

- **`description`** - A comprehensive description of the component's purpose and usage
- **`props`** - Component properties with descriptions, value types, available values, and default values
- **`events`** - Event handlers the component supports (e.g., click events)
- **`themeVars`** - Theme variables extracted from the component's SCSS module
- **`defaultThemeVars`** - Default values for theme variables used for styling customization

The metadata is created using the `createMetadata()` function and exported so it can be collected and processed during documentation generation.

## Technical Implementation

The documentation generation system consists of several key components:

- **Metadata Extraction**: Uses Vite in metadata mode to extract component metadata from TypeScript files
- **DocsGenerator Class**: Processes component metadata and documentation files to create final docs
- **Directive Processing**: Merges manual content with auto-generated metadata using special markers
- **Output Management**: Handles file cleanup, organization, and metadata file generation

The main entry point is `scripts/generate-docs/get-docs.mjs`, which orchestrates the entire process.

## Component Documentation File Directives

Component documentation files (e.g., `Button.md`) use special directive markers to inject auto-generated content from the component metadata. These directives allow manual documentation to be seamlessly merged with extracted metadata.

**Directive Format:**
```markdown
%-SECTION_NAME-START [optional_parameter]
Content goes here
%-SECTION_NAME-END
```

**Available Directives:**

- **`%-DESC-START` / `%-DESC-END`** - Component description from metadata
- **`%-PROP-START propName` / `%-PROP-END`** - Specific property documentation with details from metadata
- **`%-EVENT-START eventName` / `%-EVENT-END`** - Event documentation from metadata
- **`%-API-START apiName` / `%-API-END`** - API method documentation from metadata
- **`%-STYLE-START` / `%-STYLE-END`** - Styling information and theme variables

**Example Usage:**

Here's the actual content from `Avatar.md` showing how directives are used:

````text
%-DESC-START

**Key features:**
- **Automatic fallback**: Shows initials when no image URL is provided or image fails to load
- **Multiple sizes**: From `xs` (extra small) to `lg` (large) to fit different contexts
- **Clickable**: Supports click events for profile actions, modals, or navigation
- **Accessible**: Automatically generates appropriate alt text from the name

%-DESC-END

%-PROP-START name

```xmlui-pg copy display name="Example: name"
<App>
  <Avatar name="John, Doe" />
</App>
```
%-PROP-END

%-PROP-START size

```xmlui-pg copy display name="Example: size"
<App>
  <HStack>
    <Avatar name="Dorothy Ellen Fuller" />
    <Avatar name="Xavier Schiller" size="xs" />
    <Avatar name="Sebastien Moore" size="sm" />
    <Avatar name="Molly Dough" size="md" />
    <Avatar name="Lynn Gilbert" size="lg" />
  </HStack>
</App>
```

%-PROP-END

%-PROP-START url

```xmlui-pg copy display name="Example: url"
<App>
  <Avatar url="https://i.pravatar.cc/100" size="md" />
</App>
```

%-PROP-END

%-EVENT-START click

```xmlui-pg copy display name="Example: click"
<App>
  <HStack verticalAlignment="center">
    <Avatar name="Molly Dough" size="md" onClick="toast('Avatar clicked')" />
    Click the avatar!
  </HStack>
</App>
```

%-EVENT-END
````


```

--------------------------------------------------------------------------------
/xmlui/src/abstractions/AppContextDefs.ts:
--------------------------------------------------------------------------------

```typescript
import type { To, NavigateOptions } from "react-router-dom";
import type { QueryClient } from "@tanstack/react-query";

import type {
  ToastOptions,
  Renderable,
  ValueOrFunction,
  DefaultToastOptions,
  Toast,
} from "react-hot-toast";
import type { ActionFunction } from "./ActionDefs";
import type { SetupWorker } from "msw/browser";
import type { ApiInterceptor } from "../components-core/interception/ApiInterceptor";

// This interface defines the properties and services of an app context that the 
// application components can use when implementing their behavior.
export type AppContextObject = {
  // Accept other methods
  [x: string]: unknown;

  // ==============================================================================================
  // Engine-realated

  version: string;

  // ==============================================================================================
  // Actions namespace

  Actions: Record<string, ActionFunction>;

  // ==============================================================================================
  // App-Specific

  // This property returns the context object of the API interceptor.
  apiInterceptorContext: IApiInterceptorContext;

  // This property returns a hash object containing all application-global settings
  // defined in the app's configuration file.
  appGlobals?: Record<string, any>;

  // Indicates that the application is running in debug-enabled mode.
  debugEnabled?: boolean;

  // Indicates that components are decorated with test IDs used for e2e tests.
  decorateComponentsWithTestId?: boolean;

  // This property returns an object with some properties of the current environment.
  environment: { isWindowFocused: boolean };

  // This property returns an object with information about the current media size.
  mediaSize: MediaSize;

  // The `QueryClient` object of the react-query library XMLUI uses for data 
  // fetching purposes
  queryClient: QueryClient | null;

  // This property returns `true` if the app is a standalone XMLUI app; otherwise
  // (for example, as part of a website), it returns `false`.
  standalone?: boolean;

  // Indicates that the app is running in a shadow DOM.
  appIsInShadowDom?: boolean;

  // ==============================================================================================
  // Date Utilities

  // This function formats the specified value's date part into a local date string
  // (according to the machine's local settings).
  formatDate: (date: string | Date) => string | undefined;

  // This function formats the specified value into a local date and time string
  // (according to the machine's local settings).
  formatDateTime: (date: any) => string | undefined;

  // This function formats the specified value's date part (without year)
  // into a local date string (according to the machine's local settings).
  formatDateWithoutYear: (date: string | Date) => string | undefined;

  // This function formats the specified value's time part into a local date
  // string (according to the machine's local settings).
  formatTime: (date: any) => string | undefined;

  // This function formats the specified value's time part (without seconds)
  // into a local date string (according to the machine's local settings).
  formatTimeWithoutSeconds: (date: string | Date) => string | undefined;

  // This function creates a date from the specified input value. If no input
  // is provided, it returns the current date and time.
  getDate: (date?: string | number | Date) => Date;

  // This function calculates the difference between the current date and the
  // provided one and returns it in a human-readable form, such as "1 month",
  // "2 weeks", etc.
  
  getDateUntilNow: (date?: string | number | Date, nowLabel?: string, time?: string) => string;

  // This function converts the input string into a date value and returns
  // the ISO 8601 string representation of the date. It can pass dates between
  // the UI and backend APIs in a standard format.
  isoDateString: (date?: string) => string;

  // This function checks if the specified date is today.
  isToday: (date: string | Date) => boolean;

  // This function checks if the specified date is tomorrow.
  isTomorrow: (date: string | Date) => boolean;

  // This function checks if the specified date is yesterday.
  isYesterday: (date: string | Date) => boolean;

  // This function checks the date value provided for some particular
  // values and returns accordingly. Otherwise, returns it as `formatDate` would.
  smartFormatDate: (date?: string | number | Date) => string;

  // This function checks the date value provided for some particular values and
  // returns accordingly. Otherwise, returns it as `formatDateTime` would.
  smartFormatDateTime: (date: string | Date) => string | undefined;

  // This functions creates the difference between two dates in minutes.
  differenceInMinutes: (date1: number | Date, date2: number | Date) => number;

  // This function checks if the specified dates are on the same day.
  isSameDay: (dateLeft: number | Date, dateRight: number | Date) => boolean;

  // This function checks if the specified date is in the current calendar year.
  // True, if the date is in the current year; otherwise, false.
  isThisYear: (date: Date | number) => boolean;

  // Formats a date into a human-readable elapsed time string.
  // Returns strings like "now", "12 seconds ago", "3 hours ago", 
  // "today", "yesterday", "3 weeks ago", etc.
  formatHumanElapsedTime: (date: string | Date) => string;

  // ==============================================================================================
  // Math Utilities

  // This function calculates the average of the specified values and returns it.
  avg: (values: number[], decimals?: number) => number;

  // This function calculates the sum of the specified values and returns it.
  sum: (values: number[]) => number;

  // ==============================================================================================
  // File Utilities

  // This function returns the specified file size in a compact form, such as
  // "112 B", "2.0 KiB", "23.4 KiB", "2.3 MiB", etc.
  formatFileSizeInBytes: (bytes: number) => string | undefined;

  // This function returns the type of the specified file.
  getFileExtension: (fileName: string) => string | undefined;

  // ==============================================================================================
  // Navigation Utilities

  // This function navigates to the specified `url`.
  navigate: (url: To, options?: NavigateOptions) => void;

  // This property determines the base name used for the router.
  routerBaseName: string;

  // ==============================================================================================
  // Notifications and Dialogs

  // Instructs the browser to display a dialog with an optional message, and to 
  // wait until the user either confirms or cancels the dialog. It returns a 
  // boolean indicating whether OK (`true`) or Cancel (`false`) was selected.
  confirm: (title: string, message?: string, actionLabel?: string) => Promise<boolean>;

  // This method displays the specified `error` (error message) on the UI.
  signError(error: Error | string): void;

  // The toast service that displays messages in the UI.
  toast: {
    (message: Message, opts?: ToastOptions): string;
    error: ToastHandler;
    success: ToastHandler;
    loading: ToastHandler;
    custom: ToastHandler;
    dismiss(toastId?: string): void;
    remove(toastId?: string): void;
    promise<T>(
      promise: Promise<T>,
      msgs: {
        loading: Renderable;
        success: ValueOrFunction<Renderable, T>;
        error: ValueOrFunction<Renderable, any>;
      },
      opts?: DefaultToastOptions,
    ): Promise<T>;
  };

  // ==============================================================================================
  // Theme-related

  // This property returns the ID of the currently active theme.
  activeThemeId: string;

  // This property returns the tone of the currently active theme ("light" or "dark").
  activeThemeTone: "light" | "dark";

  // This property returns an array of all available theme IDs.
  availableThemeIds: string[];

  // This function sets the current theme to the one with the specified `themeId`.
  setTheme: (themId: string) => void;

  // This function sets the current theme tone to the specified `tone` value
  // ("light" or "dark").
  setThemeTone: (newTone: "light" | "dark") => void;

  // This function toggles the current theme tone from "light" to "dark" or vice versa.
  toggleThemeTone: () => void;

  // ==============================================================================================
  // Users

  // This property gets the information about the logged-in user. If `null`, no user is
  // logged in. The user information may have any value; the app must be able to
  // leverage this information.
  loggedInUser: LoggedInUserDto | null;

  // This function sets the information about the logged-in user. The user information
  // may have any value; the app must be able to leverage this information.
  setLoggedInUser: (loggedInUser: any) => void;

  readonly resources?: Record<string, string>;

  // ==============================================================================================
  // Various Utilities

  capitalize: (s?: string) => string;
  pluralize: (number: number, singular: string, plural: string) => string;
  delay: (timeInMs: number, callback?: any) => Promise<void>;
  debounce: <F extends (...args: any[]) => any>(
    delayMs: number,
    func: F,
    ...args: any[]
  ) => void;
  toHashObject: (arr: any[], keyProp: string, valueProp: string) => any;
  findByField: (arr: any[], field: string, value: any) => any;
  readonly embed: { isInIFrame: boolean };
  distinct: (arr: any[]) => any[];
  forceRefreshAnchorScroll: () => void;
};

export const MediaBreakpointKeys = ["xs", "sm", "md", "lg", "xl", "xxl"] as const;
export type MediaBreakpointType = (typeof MediaBreakpointKeys)[number];

export type MediaSize = {
  phone: boolean;
  landscapePhone: boolean;
  tablet: boolean;
  desktop: boolean;
  largeDesktop: boolean;
  xlDesktop: boolean;
  smallScreen: boolean;
  largeScreen: boolean;
  size: MediaBreakpointType;
  sizeIndex: number;
};

export type LoggedInUserDto = {
  id: number;
  email: string;
  name: string;
  imageRelativeUrl: string;
  permissions: Record<string, string>;
};

export interface IApiInterceptorContext {
  isMocked: (url: string) => boolean;
  initialized: boolean;
  forceInitialize: ()=>void;
  interceptorWorker: SetupWorker | null;
  apiInstance: ApiInterceptor | null;
}

type Message = ValueOrFunction<Renderable, Toast>;
type ToastHandler = (message: Message, options?: ToastOptions) => string;

```

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

```markdown
# 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.

**Key features:**
- **Overlay presentation**: Appears above existing content with backdrop dimming
- **Programmatic control**: Open and close via exposed methods like `open()` and `close()`
- **Parameter passing**: Accept data when opened for dynamic dialog content
- **Focus management**: Automatically handles focus trapping and accessibility
- **Form integration**: When containing Form components, automatically closes on form submission or cancellation (unless overridden)

## Using the Component [#using-the-component]

>[!INFO]
> When using the examples in this article, pop them out to the full screen to check how they work.

Opening and closing the modal dialog can be done in two ways depending on circumstances.

### With Imperative API [#with-imperative-api]

Event-driven display of the `ModalDialog` dialog is also possible using imperative API.

This method is a good way to toggle the display of the `ModalDialog` if no deep linking is necessary.
It also lends to itself that these events can be triggered programmatically from codebehind.

Note the `id` property of the `ModalDialog` in the example below and how it is used to call the [`open`](#open-api) and [`close`](#close-api)
operations of the component in the `onClick` event handlers.

```xmlui-pg copy display name="Example: imperative API" height="220px"
<App>
  <ModalDialog id="dialog" title="Example Dialog">
    <Button label="Close Dialog" onClick="dialog.close()" />
  </ModalDialog>
  <Button label="Open Dialog" onClick="dialog.open()" />
</App>
```

>[!INFO]
> The imperative approach is perhaps the most intuitive way to display and hide modal dialogs.

### With `when` [#with-when]

The `when` property accepts a primitive boolean or a binding expression resolving to a boolean value to toggle the display of a component.

Using the `when` property in a `ModalDialog` dialog component is commonly used with deep linking:
showing the modal in conjunction with an updated URL so that the opened state of the modal dialog is referable.

```xmlui-pg height="220px"
---app copy display name="Example: when"
<App>
  <variable name="isDialogShown" value="{false}"/>
  <Button label="Open Dialog" onClick="isDialogShown = true" />
  <ModalDialog 
    when="{isDialogShown}" 
    title="Example Dialog" 
    onClose="isDialogShown = false" />
</App>
---desc
Click on the button in the demo below to open the modal dialog. Click anywhere outside the opened dialog or the close button to close it.
```

Setting the `when` property is the most straightforward way for deep-linked modals. If you use deep links with query parameters to show a particular dialog, you can set the `when` property to show or hide the dialog according to parameter values.

### The `ModalDialog` as a Container [#the-modaldialog-as-a-container]

The `ModalDialog` component is also a container such as the [`Card`](/components/Card), that it also accepts child components.

```xmlui-pg copy {3-8} display name="Example: children" height="340px"
<App>
  <Button label="Open Dialog" onClick="dialog.open()" />
  <ModalDialog id="dialog" title="Example Dialog">
    <Form data="{{ firstName: 'Billy', lastName: 'Bob' }}">
      <FormItem bindTo="firstName" required="true" />
      <FormItem bindTo="lastName" required="true" />
    </Form>
  </ModalDialog>
</App>
```

>[!INFO]
> When a form is nested into a modal dialog, closing the form (canceling it or completing its submit action) automatically closes the dialog.

**Context variables available during execution:**

- `$param`: First parameter passed to the `open()` method
- `$params`: Array of all parameters passed to `open()` method (access with `$params[0]`, `$params[1]`, etc.)

## Properties [#properties]

### `closeButtonVisible` (default: true) [#closebuttonvisible-default-true]

Shows (`true`) or hides (`false`) the visibility of the close button on the dialog.

```xmlui-pg height="220px"
---app copy display name="Example: closeButtonVisible"
<App>
  <Button label="Open Dialog" onClick="dialog.open()" />
  <ModalDialog id="dialog" closeButtonVisible="false" title="Example Dialog" />
</App>
---desc
Click outside the dialog to close it.
```

### `fullScreen` (default: false) [#fullscreen-default-false]

Toggles whether the dialog encompasses the whole UI (`true`) or not and has a minimum width and height (`false`).

```xmlui-pg height="220px"
---app copy display name="Example: fullScreen"
<App>
  <Button label="Open Dialog" onClick="dialog.open()" />
  <ModalDialog id="dialog" fullScreen="true" title="Example Dialog" />
</App>
---desc
Click the button to display a full-screen dialog. The icon at the top-right corner of the dialog allows you to close it.
```

### `title` [#title]

Provides a prestyled heading to display the intent of the dialog.

```xmlui-pg copy {3} display name="Example: title" height="220px"
<App>
  <Button label="Open Dialog" onClick="dialog.open()" />
  <ModalDialog id="dialog" title="Example Title" />
</App>
```

## Events [#events]

### `close` [#close]

This event is fired when the close button is pressed or the user clicks outside the `ModalDialog`.

In this example, the `close` event counts how many times you closed the dialog:

```xmlui-pg height="220px"
---app copy {6-8} display name="Example: open/close events"
<App>
  <Button label="Open Dialog" onClick="myDialog.open()" />
  <ModalDialog
    id="myDialog"
    title="Example Dialog"
    var.counter="{0}"
    onClose="counter++">
    <Text value="Dialog closed {counter} number of times." />
  </ModalDialog>
</App>
---desc
Open and close the dialog several times to test that it changes the counter.
```

### `open` [#open]

This event is fired when the `ModalDialog` is opened either via a `when` or an imperative API call (`open()`).

In this example, the `open` event counts how many times you opened the dialog:

```xmlui-pg height="220px"
---app copy {6-8} display name="Example: open/close events"
<App>
  <Button label="Open Dialog" onClick="myDialog.open()" />
  <ModalDialog
    id="myDialog"
    title="Example Dialog"
    var.counter="{0}"
    onOpen="counter++">
    <Text value="Dialog opened {counter} number of times." />
  </ModalDialog>
</App>
---desc
Open and close the dialog several times to test that it changes the counter.
```

## Exposed Methods [#exposed-methods]

### `close` [#close]

This method is used to close the `ModalDialog`. Invoke it using `modalId.close()` where `modalId` refers to a `ModalDialog` component.

**Signature**: `close(): void`

See the [\`With Imperative API\`](#with-imperative-api) subsection for an example.

### `open` [#open]

This method imperatively opens the modal dialog. You can pass an arbitrary number of parameters to the method. In the `ModalDialog` instance, you can access those with the `$param` and `$params` context values.

**Signature**: `open(...params: any[]): void`

- `params`: An arbitrary number of parameters that can be used to pass data to the dialog.

See the [\`With Imperative API\`](#with-imperative-api) subsection for an example.

## Parts [#parts]

The component has some parts that can be styled through layout properties and theme variables separately:

- **`content`**: The main content area of the modal dialog.
- **`title`**: The title area of the modal dialog.

## Styling [#styling]

### Theme Variables [#theme-variables]

| Variable | Default Value (Light) | Default Value (Dark) |
| --- | --- | --- |
| [backgroundColor](../styles-and-themes/common-units/#color)-ModalDialog | $backgroundColor-primary | $backgroundColor-primary |
| [backgroundColor](../styles-and-themes/common-units/#color)-ModalDialog | $backgroundColor-primary | $backgroundColor-primary |
| [backgroundColor](../styles-and-themes/common-units/#color)-overlay-ModalDialog | $backgroundColor-overlay | $backgroundColor-overlay |
| [backgroundColor](../styles-and-themes/common-units/#color)-overlay-ModalDialog | $backgroundColor-overlay | $backgroundColor-overlay |
| [borderRadius](../styles-and-themes/common-units/#border-rounding)-ModalDialog | $borderRadius | $borderRadius |
| [borderRadius](../styles-and-themes/common-units/#border-rounding)-ModalDialog | $borderRadius | $borderRadius |
| [fontFamily](../styles-and-themes/common-units/#fontFamily)-ModalDialog | $fontFamily | $fontFamily |
| [fontFamily](../styles-and-themes/common-units/#fontFamily)-ModalDialog | $fontFamily | $fontFamily |
| [marginBottom](../styles-and-themes/common-units/#size)-title-ModalDialog | 0 | 0 |
| [marginBottom](../styles-and-themes/common-units/#size)-title-ModalDialog | 0 | 0 |
| [maxWidth](../styles-and-themes/common-units/#size)-ModalDialog | 450px | 450px |
| [maxWidth](../styles-and-themes/common-units/#size)-ModalDialog | 450px | 450px |
| [minWidth](../styles-and-themes/common-units/#size)-ModalDialog | *none* | *none* |
| [padding](../styles-and-themes/common-units/#size)-ModalDialog | $space-7 | $space-7 |
| [padding](../styles-and-themes/common-units/#size)-overlay-ModalDialog | *none* | *none* |
| [paddingBottom](../styles-and-themes/common-units/#size)-ModalDialog | $paddingVertical-ModalDialog | $paddingVertical-ModalDialog |
| [paddingBottom](../styles-and-themes/common-units/#size)-overlay-ModalDialog | *none* | *none* |
| [paddingHorizontal](../styles-and-themes/common-units/#size)-ModalDialog | *none* | *none* |
| [paddingHorizontal](../styles-and-themes/common-units/#size)-overlay-ModalDialog | *none* | *none* |
| [paddingLeft](../styles-and-themes/common-units/#size)-ModalDialog | $paddingHorizontal-ModalDialog | $paddingHorizontal-ModalDialog |
| [paddingLeft](../styles-and-themes/common-units/#size)-overlay-ModalDialog | *none* | *none* |
| [paddingRight](../styles-and-themes/common-units/#size)-ModalDialog | $paddingHorizontal-ModalDialog | $paddingHorizontal-ModalDialog |
| [paddingRight](../styles-and-themes/common-units/#size)-overlay-ModalDialog | *none* | *none* |
| [paddingTop](../styles-and-themes/common-units/#size)-ModalDialog | $paddingVertical-ModalDialog | $paddingVertical-ModalDialog |
| [paddingTop](../styles-and-themes/common-units/#size)-overlay-ModalDialog | *none* | *none* |
| [paddingVertical](../styles-and-themes/common-units/#size)-ModalDialog | *none* | *none* |
| [paddingVertical](../styles-and-themes/common-units/#size)-overlay-ModalDialog | *none* | *none* |
| [textColor](../styles-and-themes/common-units/#color)-ModalDialog | $textColor-primary | $textColor-primary |
| [textColor](../styles-and-themes/common-units/#color)-ModalDialog | $textColor-primary | $textColor-primary |

```

--------------------------------------------------------------------------------
/xmlui/src/components/Markdown/Markdown.module.scss:
--------------------------------------------------------------------------------

```scss
@use "../../components-core/theming/themes" as t;

// --- This code snippet is required to collect the theme variables used in this module
$themeVars: ();
@function createThemeVar($componentVariable) {
  $themeVars: t.appendThemeVar($themeVars, $componentVariable) !global;
  @return t.getThemeVar($themeVars, $componentVariable);
}

$themeVars: t.composeTextVars($themeVars, "Text") !global;

$paddingTop-MarkDown: createThemeVar("paddingTop-Markdown");
$paddingBottom-MarkDown: createThemeVar("paddingBottom-Markdown");
$backgroundColor-MarkDown: createThemeVar("backgroundColor-Markdown");

$themeVars: t.composePaddingVars($themeVars, "Blockquote");
$themeVars: t.composeBorderVars($themeVars, "Blockquote");
$color-accent-Blockquote: createThemeVar("color-accent-Blockquote");
$width-accent-Blockquote: createThemeVar("width-accent-Blockquote");
$backgroundColor-Blockquote: createThemeVar("backgroundColor-Blockquote");
$paddingLeft-Blockquote: createThemeVar("paddingLeft-Blockquote");
$borderRadius-Blockquote: createThemeVar("borderRadius-Blockquote");
$marginTop-Blockquote: createThemeVar("marginTop-Blockquote");
$marginBottom-Blockquote: createThemeVar("marginBottom-Blockquote");

$themeVars: t.composePaddingVars($themeVars, "Admonition");
$themeVars: t.composeBorderVars($themeVars, "Admonition");
$backgroundColor-Admonition: createThemeVar("backgroundColor-Admonition");
$borderRadius-Admonition: createThemeVar("borderRadius-Admonition");
$size-icon-Admonition: createThemeVar("size-icon-Admonition");
$marginTop-Admonition: createThemeVar("marginTop-Admonition");
$marginBottom-Admonition: createThemeVar("marginBottom-Admonition");
$marginLeft-Admonition-content: createThemeVar("marginLeft-Admonition-content");

$marginTop-HtmlVideo: createThemeVar("marginTop-HtmlVideo");
$marginBottom-HtmlVideo: createThemeVar("marginBottom-HtmlVideo");

// Variables for @layer section - Text-markdown
$marginTop-Text-markdown: createThemeVar("marginTop-Text-markdown");
$marginBottom-Text-markdown: createThemeVar("marginBottom-Text-markdown");
$marginLeft-Text-markdown: createThemeVar("marginLeft-Text-markdown");
$marginRight-Text-markdown: createThemeVar("marginRight-Text-markdown");

// Variables for @layer section - Heading margins in markdown
$marginTop-H1-markdown: createThemeVar("marginTop-H1-markdown");
$marginBottom-H1-markdown: createThemeVar("marginBottom-H1-markdown");
$fontSize-H1-markdown: createThemeVar("fontSize-H1-markdown");
$marginTop-H2-markdown: createThemeVar("marginTop-H2-markdown");
$marginBottom-H2-markdown: createThemeVar("marginBottom-H2-markdown");
$marginTop-H3-markdown: createThemeVar("marginTop-H3-markdown");
$marginBottom-H3-markdown: createThemeVar("marginBottom-H3-markdown");
$marginTop-H4-markdown: createThemeVar("marginTop-H4-markdown");
$marginBottom-H4-markdown: createThemeVar("marginBottom-H4-markdown");
$marginTop-H5-markdown: createThemeVar("marginTop-H5-markdown");
$marginBottom-H5-markdown: createThemeVar("marginBottom-H5-markdown");
$marginTop-H6-markdown: createThemeVar("marginTop-H6-markdown");
$marginBottom-H6-markdown: createThemeVar("marginBottom-H6-markdown");

// Variables for @layer section - Image in markdown
$marginTop-Image-markdown: createThemeVar("marginTop-Image-markdown");
$marginBottom-Image-markdown: createThemeVar("marginBottom-Image-markdown");
$marginLeft-Image-markdown: createThemeVar("marginLeft-Image-markdown");
$marginRight-Image-markdown: createThemeVar("marginRight-Image-markdown");

// Variables for @layer section - Admonition variants
$backgroundColor-Admonition-info: createThemeVar("backgroundColor-Admonition-info");
$borderColor-Admonition-info: createThemeVar("borderColor-Admonition-info");
$backgroundColor-Admonition-warning: createThemeVar("backgroundColor-Admonition-warning");
$borderColor-Admonition-warning: createThemeVar("borderColor-Admonition-warning");
$backgroundColor-Admonition-danger: createThemeVar("backgroundColor-Admonition-danger");
$borderColor-Admonition-danger: createThemeVar("borderColor-Admonition-danger");
$backgroundColor-Admonition-note: createThemeVar("backgroundColor-Admonition-note");
$borderColor-Admonition-note: createThemeVar("borderColor-Admonition-note");
$backgroundColor-Admonition-tip: createThemeVar("backgroundColor-Admonition-tip");
$borderColor-Admonition-tip: createThemeVar("borderColor-Admonition-tip");

// Variables for @layer section - HorizontalRule
$borderColor-HorizontalRule: createThemeVar("borderColor-HorizontalRule");
$borderStyle-HorizontalRule: createThemeVar("borderStyle-HorizontalRule");
$borderWidth-HorizontalRule: createThemeVar("borderWidth-HorizontalRule");

@layer components {
  .markdownContent {
    padding-top: $paddingTop-MarkDown;
    padding-bottom: $paddingBottom-MarkDown;
    background-color: $backgroundColor-MarkDown;
    min-width: 0;
    width: 100%;
    @include t.textVars($themeVars, "Text");

    .markdown {
      $component: "Text";
      $variantName: "Text-markdown";
      $themeVars: t.composePaddingVars($themeVars, variantName);
      $themeVars: t.composeBorderVars($themeVars, $variantName);
      $themeVars: t.composeTextVars($themeVars, $variantName, $component);
      @include t.paddingVars($themeVars, $variantName);
      @include t.borderVars($themeVars, $variantName);
      @include t.textVars($themeVars, $variantName);
      margin-top: $marginTop-Text-markdown;
      margin-bottom: $marginBottom-Text-markdown;
      margin-left: $marginLeft-Text-markdown;
      margin-right: $marginRight-Text-markdown;
      overflow: visible;
      display: block;
    }

    // --- Additional Heading styles
    h1 {
      margin-top: $marginTop-H1-markdown !important;
      margin-bottom: $marginBottom-H1-markdown !important;
      font-size: $fontSize-H1-markdown !important;
    }

    h2 {
      margin-top: $marginTop-H2-markdown !important;
      margin-bottom: $marginBottom-H2-markdown !important;
    }

    h3 {
      margin-top: $marginTop-H3-markdown !important;
      margin-bottom: $marginBottom-H3-markdown !important;
    }

    h4 {
      margin-top: $marginTop-H4-markdown !important;
      margin-bottom: $marginBottom-H4-markdown !important;
    }

    h5 {
      margin-top: $marginTop-H5-markdown !important;
      margin-bottom: $marginBottom-H5-markdown !important;
    }

    h6 {
      margin-top: $marginTop-H6-markdown !important;
      margin-bottom: $marginBottom-H6-markdown !important;
    }

    // --- Image
    .block {
      margin-top: $marginTop-Image-markdown;
      margin-bottom: $marginBottom-Image-markdown;
      margin-left: $marginLeft-Image-markdown;
      margin-right: $marginRight-Image-markdown;
    }

    // --- Blockquote

    .blockquote {
      position: relative;
      margin-top: $marginTop-Blockquote;
      margin-bottom: $marginBottom-Blockquote;
      background-color: $backgroundColor-Blockquote;

      &::before {
        background-color: $color-accent-Blockquote;
        position: absolute;
        top: 0;
        left: 0;
        display: block;
        content: "";
        height: 100%;
        width: $width-accent-Blockquote;
      }
    }

    .blockquoteContainer {
      @include t.borderVars($themeVars, "Blockquote");
      @include t.paddingVars($themeVars, "Blockquote");
    }

    .admonitionBlockquote {
      margin-top: $marginTop-Admonition;
      margin-bottom: $marginBottom-Admonition;
      background-color: $backgroundColor-Admonition;
      border-radius: $borderRadius-Admonition;
      @include t.borderVars($themeVars, "Admonition");
      @include t.paddingVars($themeVars, "Admonition");

      &.info {
        background-color: $backgroundColor-Admonition-info;
        border-color: $borderColor-Admonition-info;
      }
      &.warning {
        background-color: $backgroundColor-Admonition-warning;
        border-color: $borderColor-Admonition-warning;
      }
      &.danger {
        background-color: $backgroundColor-Admonition-danger;
        border-color: $borderColor-Admonition-danger;
      }
      &.note {
        background-color: $backgroundColor-Admonition-note;
        border-color: $borderColor-Admonition-note;
      }
      &.tip {
        background-color: $backgroundColor-Admonition-tip;
        border-color: $borderColor-Admonition-tip;
      }
    }

    .admonitionContainer {
      padding: 0.5rem;
      display: flex;
      align-items: flex-start;
    }

    .admonitionIcon {
      font-size: $size-icon-Admonition;
      line-height: 1;
    }

    .admonitionContent {
      margin-left: $marginLeft-Admonition-content;
      flex: 1;
      min-width: 0;
    }

    .admonitionBlockquote {
      .admonitionContent {
        [class*="text_"][class*="markdown_"],
        ul,
        ol {
          margin-top: 0;
          margin-bottom: 0;
        }
      }
    }

    .horizontalRule {
      border-top-color: $borderColor-HorizontalRule;
      border-top-style: $borderStyle-HorizontalRule;
      border-top-width: $borderWidth-HorizontalRule;
    }

    li:has(> input[type="checkbox"]),
    li:has(> input[type="checkbox"]) {
      display: flex;
      align-items: flex-start;

      > input[type="checkbox"] {
        margin-right: 8px;
        margin-top: 4px;
        flex-shrink: 0;
      }
    }

    // First element should have no top margin
    > *:first-child {
      margin-top: 0;
    }

    // Last element should have no bottom margin
    > *:last-child {
      margin-bottom: 0;
    }

    // --- Table
    .tableScrollContainer {
      overflow-x: auto;
      width: 100%;
    }

    // --- Details adornment
    .detailsAdornment {
      margin-top: $marginTop-Admonition;
      margin-bottom: $marginBottom-Admonition;
      border-radius: $borderRadius-Admonition;
      background-color: $backgroundColor-Admonition;
      @include t.borderVars($themeVars, "Admonition");

      // Override ExpandableItem styles for better integration
      :global(.summary) {
        padding: 0.5rem 1rem;
        font-weight: 600; // Make summary text bold
      }

      :global(.content) {
        padding: 0 1rem 0.5rem 1rem;
      }
    }
  }

  // --- UnorderedList
  /*

  $paddingLeft-UnorderedList: createThemeVar("paddingLeft-UnorderedList");

  // the basic <ul> and <ol> styles are the same in tabler.io too
  .unorderedList {
    list-style-type: revert;
    list-style-position: outside;
    padding-left: $paddingLeft-UnorderedList;
  }

  // --- OrderedList
  $paddingLeft-OrderedList: createThemeVar("paddingLeft-OrderedList");

  // the basic <ul> and <ol> styles are the same in tabler.io too
  .orderedList {
    list-style-type: revert;
    list-style-position: outside;
    padding-left: $paddingLeft-OrderedList;
  }

  // --- ListItem

  $paddingLeft-ListItem: createThemeVar("paddingLeft-ListItem");
  $color-marker-ListItem: createThemeVar("color-marker-ListItem");

  .listItem {
    padding-left: $paddingLeft-ListItem;
  }

  .listItem::marker {
    color: $color-marker-ListItem;
  }
  */
}

// --- We export the theme variables to add them to the component renderer
:export {
  themeVars: t.json-stringify($themeVars);
}

```

--------------------------------------------------------------------------------
/packages/xmlui-playground/src/state/store.ts:
--------------------------------------------------------------------------------

```typescript
import type { Dispatch } from "react";
import { createContext } from "react";
import produce from "immer";
import type {
  ApiInterceptorDefinition,
  CompoundComponentDef,
  ThemeDefinition,
  ThemeTone,
} from "xmlui";
import { errReportComponent, xmlUiMarkupToComponent, builtInThemes } from "xmlui";

type Orientation = "horizontal" | "vertical";

type Options = {
  previewMode?: boolean;
  swapped?: boolean;
  orientation?: Orientation;
  content: string;
  allowStandalone?: boolean;
  id: number;
  activeTheme?: string;
  activeTone?: ThemeTone;
  language: "xmlui" | "json";
  emulatedApi?: string;
  fixedTheme?: boolean;
};

type AppDescription = {
  config: {
    name: string;
    description?: string;
    appGlobals: any;
    resources: any;
    themes: ThemeDefinition[];
    defaultTheme?: string;
    defaultTone?: string;
  };
  components: any[];
  app: any;
  availableThemes?: Array<ThemeDefinition>;
  api?: ApiInterceptorDefinition;
};

export interface IPlaygroundContext {
  status: "loading" | "loaded" | "idle";
  editorStatus?: "loading" | "loaded" | "idle";
  appDescription: AppDescription;
  originalAppDescription: AppDescription;
  dispatch: Dispatch<PlaygroundAction>;
  text: string;
  options: Options;
  playgroundId: string;
  error: string | null;
}

export const PlaygroundContext = createContext<IPlaygroundContext>(
  undefined as unknown as IPlaygroundContext,
);

enum PlaygroundActionKind {
  TEXT_CHANGED = "PlaygroundActionKind:TEXT_CHANGED",
  CONTENT_CHANGED = "PlaygroundActionKind:CONTENT_CHANGED",
  PREVIEW_MODE = "PlaygroundActionKind:PREVIEW_MODE",
  RESET_APP = "PlaygroundActionKind:RESET_APP",
  APP_SWAPPED = "PlaygroundActionKind:APP_SWAPPED",
  ORIENTATION_CHANGED = "PlaygroundActionKind:ORIENTATION_CHANGED",
  APP_DESCRIPTION_INITIALIZED = "PlaygroundActionKind:APP_DESCRIPTION_INITIALIZED",
  EDITOR_STATUS_CHANGED = "PlaygroundActionKind:EDITOR_STATUS_CHANGED",
  OPTIONS_INITIALIZED = "PlaygroundActionKind:OPTIONS_INITIALIZED",
  ACTIVE_THEME_CHANGED = "PlaygroundActionKind:ACTIVE_THEME_CHANGED",
  TONE_CHANGED = "PlaygroundActionKind:TONE_CHANGED",
  ERROR_CLEARED = "PlaygroundActionKind:ERROR_CLEARED",
}

type PlaygroundAction = {
  type: PlaygroundActionKind;
  payload: {
    text?: string;
    appDescription?: AppDescription;
    options?: Options;
    activeTone?: ThemeTone;
    activeTheme?: string;
    content?: string;
    themes?: ThemeDefinition[];
    previewMode?: boolean;
    editorStatus?: "loading" | "loaded";
    error?: string | null;
  };
};

export interface PlaygroundState {
  editorStatus: "loading" | "loaded" | "idle";
  status: "loading" | "loaded" | "idle";
  text: string;
  appDescription: AppDescription;
  originalAppDescription: AppDescription;
  options: Options;
  error: string | null;
}

export function toneChanged(activeTone: ThemeTone) {
  return {
    type: PlaygroundActionKind.TONE_CHANGED,
    payload: {
      activeTone,
    },
  };
}

export function textChanged(text: string) {
  return {
    type: PlaygroundActionKind.TEXT_CHANGED,
    payload: {
      text,
    },
  };
}

export function contentChanged(content: string) {
  return {
    type: PlaygroundActionKind.CONTENT_CHANGED,
    payload: {
      content,
    },
  };
}

export function previewMode(previewMode: boolean) {
  return {
    type: PlaygroundActionKind.PREVIEW_MODE,
    payload: {
      previewMode,
    },
  };
}

export function resetApp() {
  return {
    type: PlaygroundActionKind.RESET_APP,
    payload: {},
  };
}

export function swapApp() {
  return {
    type: PlaygroundActionKind.APP_SWAPPED,
    payload: {},
  };
}

export function changeOrientation() {
  return {
    type: PlaygroundActionKind.ORIENTATION_CHANGED,
    payload: {},
  };
}

export function appDescriptionInitialized(appDescription: any) {
  return {
    type: PlaygroundActionKind.APP_DESCRIPTION_INITIALIZED,
    payload: {
      appDescription,
    },
  };
}

export function optionsInitialized(options: Options) {
  return {
    type: PlaygroundActionKind.OPTIONS_INITIALIZED,
    payload: {
      options,
    },
  };
}

export function activeThemeChanged(activeTheme: string) {
  return {
    type: PlaygroundActionKind.ACTIVE_THEME_CHANGED,
    payload: {
      activeTheme,
    },
  };
}

export function editorStatusChanged(editorStatus: "loading" | "loaded") {
  return {
    type: PlaygroundActionKind.EDITOR_STATUS_CHANGED,
    payload: {
      editorStatus,
    },
  };
}

export function clearError() {
  return {
    type: PlaygroundActionKind.ERROR_CLEARED,
    payload: {},
  };
}

export const playgroundReducer = produce((state: PlaygroundState, action: PlaygroundAction) => {
  switch (action.type) {
    case PlaygroundActionKind.TONE_CHANGED: {
      state.options.id = state.options.id + 1;
      state.options.activeTone = action.payload.activeTone;
      break;
    }
    case PlaygroundActionKind.EDITOR_STATUS_CHANGED: {
      state.editorStatus = action.payload.editorStatus || "idle";
      break;
    }
    case PlaygroundActionKind.APP_DESCRIPTION_INITIALIZED: {
      state.status = "loading";
      if (action.payload.appDescription) {
        const compoundComponents: CompoundComponentDef[] =
          action.payload.appDescription.components.map((src) => {
            if (typeof src === "string") {
              let { errors, component, erroneousCompoundComponentName } =
                xmlUiMarkupToComponent(src);
              if (errors.length > 0) {
                return errReportComponent(
                  errors,
                  "Preview source file",
                  erroneousCompoundComponentName,
                );
              }
              return {
                name: (component as CompoundComponentDef).name,
                component: src,
              };
            }
            return src;
          });
        state.appDescription.components = compoundComponents;
        state.appDescription.app = action.payload.appDescription.app;
        state.appDescription.config = action.payload.appDescription.config;
        state.appDescription.api = action.payload.appDescription.api;
        state.text = action.payload.appDescription.app;
        const themes = action.payload.appDescription.config.themes || [];
        state.appDescription.availableThemes = [...themes, ...builtInThemes];
        state.options.activeTheme =
          state.appDescription.config.defaultTheme || state.appDescription.availableThemes[0].id;
        state.originalAppDescription = { ...state.appDescription };
      }
      state.status = "loaded";
      break;
    }
    case PlaygroundActionKind.OPTIONS_INITIALIZED: {
      state.options = action.payload.options || state.options;
      break;
    }
    case PlaygroundActionKind.ACTIVE_THEME_CHANGED: {
      if (action.payload.activeTheme) {
        state.options.activeTheme = action.payload.activeTheme;
      }
      break;
    }
    case PlaygroundActionKind.PREVIEW_MODE: {
      state.options.previewMode = action.payload.previewMode || false;
      break;
    }
    case PlaygroundActionKind.APP_SWAPPED: {
      state.options.swapped = !state.options.swapped;
      break;
    }
    case PlaygroundActionKind.ORIENTATION_CHANGED: {
      state.options.orientation =
        state.options.orientation === "horizontal" ? "vertical" : "horizontal";
      break;
    }
    case PlaygroundActionKind.RESET_APP: {
      state.options = { ...state.options, id: state.options.id + 1 };
      state.appDescription = { ...state.originalAppDescription };
      if (state.options.content === "app") {
        state.text = state.originalAppDescription.app;
      }
      if (state.options.content === "config") {
        state.text = JSON.stringify(state.originalAppDescription.config, null, 2);
      } else if (
        state.appDescription.components
          .map((c) => c.name.toLowerCase())
          .includes(state.options.content?.toLowerCase())
      ) {
        state.text =
          state.originalAppDescription.components.find(
            (component: CompoundComponentDef) => component.name === state.options.content,
          )?.component || "";
      }
      break;
    }
    case PlaygroundActionKind.CONTENT_CHANGED: {
      state.options.content = action.payload.content || "app";
      if (state.options.content === "app") {
        state.text = state.appDescription.app;
        state.options.language = "xmlui";
      } else if (state.options.content === "config") {
        state.text = JSON.stringify(state.appDescription.config, null, 2);
        state.options.language = "json";
      } else if (
        state.appDescription.components
          .map((c) => c.name.toLowerCase())
          .includes(state.options.content?.toLowerCase())
      ) {
        state.text =
          state.appDescription.components.find(
            (component: CompoundComponentDef) => component.name === state.options.content,
          )?.component || "";
        state.options.language = "xmlui";
      } else if (
        state.appDescription.config.themes
          .map((t) => t.id.toLowerCase())
          .includes(state.options.content?.toLowerCase())
      ) {
        state.text = JSON.stringify(
          state.appDescription.config.themes.find(
            (theme: ThemeDefinition) => theme.id === state.options.content,
          ),
          null,
          2,
        );
        state.options.language = "json";
      }
      break;
    }
    case PlaygroundActionKind.ERROR_CLEARED: {
      state.error = null;
      break;
    }
    case PlaygroundActionKind.TEXT_CHANGED:
      state.options.id = state.options.id + 1;
      {
        state.text = action.payload.text || "";
        state.error = null;
        if (state.options.content === "app") {
          state.appDescription.app = state.text;
        } else if (state.options.content === "config") {
          try {
            state.appDescription.config = JSON.parse(state.text || "");
          } catch (e: any) {
            state.error = e.message;
          }
        } else if (
          state.appDescription.components?.some(
            (component: CompoundComponentDef) => component.name === state.options.content,
          )
        ) {
          state.appDescription.components = state.appDescription.components.map(
            (component: CompoundComponentDef) => {
              if (component.name === state.options.content) {
                return {
                  name: component.name,
                  component: state.text || "",
                };
              }
              return component;
            },
          );
        } else if (
          state.appDescription.config.themes?.some(
            (theme: ThemeDefinition) => theme.id === state.options.content,
          )
        ) {
          try {
            state.appDescription.config.themes = state.appDescription.config.themes.map(
              (theme: ThemeDefinition) => {
                if (theme.id === state.options.content) {
                  return JSON.parse(state.text || "");
                }
                return theme;
              },
            );
          } catch (e: any) {
            state.error = e.message;
          }
        }
      }
      break;
  }
});

```

--------------------------------------------------------------------------------
/xmlui/tests/components-core/utils/date-utils.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
import { formatHumanElapsedTime } from "../../../src/components-core/utils/date-utils";
import * as dateFns from "date-fns";

// Mock date-fns functions used by formatHumanElapsedTime
vi.mock("date-fns", async () => {
  const actual = await vi.importActual("date-fns");
  return {
    ...(actual as object),
    isToday: vi.fn(),
    isYesterday: vi.fn(),
  };
});

describe("formatHumanElapsedTime tests", () => {
  const fixedDate = new Date("2025-07-15T12:00:00Z");
  
  beforeEach(() => {
    // Use fake timers to control the current date
    vi.useFakeTimers();
    vi.setSystemTime(fixedDate);
    
    // Setup mocks for date-fns functions that are used in the implementation
    vi.mocked(dateFns.isToday).mockImplementation((date) => {
      const d = new Date(date);
      return (
        d.getDate() === fixedDate.getDate() &&
        d.getMonth() === fixedDate.getMonth() &&
        d.getFullYear() === fixedDate.getFullYear()
      );
    });
    
    vi.mocked(dateFns.isYesterday).mockImplementation((date) => {
      const d = new Date(date);
      const yesterday = new Date(fixedDate);
      yesterday.setDate(yesterday.getDate() - 1);
      return (
        d.getDate() === yesterday.getDate() &&
        d.getMonth() === yesterday.getMonth() &&
        d.getFullYear() === yesterday.getFullYear()
      );
    });
  });

  afterEach(() => {
    vi.useRealTimers();
    vi.restoreAllMocks();
  });

  // =============================================================================
  // BASIC FUNCTIONALITY TESTS
  // =============================================================================

  it("should return 'now' for times within 10 seconds", () => {
    // Create dates within 10 seconds of the fixed date
    const now = new Date(fixedDate);
    const fiveSecondsAgo = new Date(fixedDate.getTime() - 5 * 1000);
    
    expect(formatHumanElapsedTime(now)).toBe("now");
    expect(formatHumanElapsedTime(fiveSecondsAgo)).toBe("now");
  });

  it("should format seconds correctly", () => {
    const fifteenSecondsAgo = new Date(fixedDate.getTime() - 15 * 1000);
    const elevenSecondsAgo = new Date(fixedDate.getTime() - 11 * 1000);
    const fiftyNineSecondsAgo = new Date(fixedDate.getTime() - 59 * 1000);
    
    expect(formatHumanElapsedTime(fifteenSecondsAgo)).toBe("15 seconds ago");
    expect(formatHumanElapsedTime(elevenSecondsAgo)).toBe("11 seconds ago");
    expect(formatHumanElapsedTime(fiftyNineSecondsAgo)).toBe("59 seconds ago");
  });

  it("should format minutes correctly", () => {
    const oneMinuteAgo = new Date(fixedDate.getTime() - 1 * 60 * 1000);
    const thirtyMinutesAgo = new Date(fixedDate.getTime() - 30 * 60 * 1000);
    const fiftyNineMinutesAgo = new Date(fixedDate.getTime() - 59 * 60 * 1000);
    
    expect(formatHumanElapsedTime(oneMinuteAgo)).toBe("1 minute ago");
    expect(formatHumanElapsedTime(thirtyMinutesAgo)).toBe("30 minutes ago");
    expect(formatHumanElapsedTime(fiftyNineMinutesAgo)).toBe("59 minutes ago");
  });

  it("should format hours correctly for today", () => {
    const oneHourAgo = new Date(fixedDate.getTime() - 1 * 60 * 60 * 1000);
    const sixHoursAgo = new Date(fixedDate.getTime() - 6 * 60 * 60 * 1000);
    
    expect(formatHumanElapsedTime(oneHourAgo)).toBe("1 hour ago");
    expect(formatHumanElapsedTime(sixHoursAgo)).toBe("6 hours ago");
  });

  it("should return 'yesterday' for yesterday's dates", () => {
    // Create a date that is exactly yesterday (24 hours ago)
    const yesterday = new Date(fixedDate);
    yesterday.setDate(yesterday.getDate() - 1);
    
    expect(formatHumanElapsedTime(yesterday)).toBe("yesterday");
  });

  it("should format days correctly for dates within a week", () => {
    const twoDaysAgo = new Date(fixedDate.getTime() - 2 * 24 * 60 * 60 * 1000);
    const sixDaysAgo = new Date(fixedDate.getTime() - 6 * 24 * 60 * 60 * 1000);
    
    // Ensure these aren't identified as "yesterday"
    vi.mocked(dateFns.isYesterday).mockReturnValue(false);
    
    expect(formatHumanElapsedTime(twoDaysAgo)).toBe("2 days ago");
    expect(formatHumanElapsedTime(sixDaysAgo)).toBe("6 days ago");
  });

  it("should format weeks correctly for dates within a month", () => {
    const oneWeekAgo = new Date(fixedDate.getTime() - 7 * 24 * 60 * 60 * 1000);
    const threeWeeksAgo = new Date(fixedDate.getTime() - 21 * 24 * 60 * 60 * 1000);
    
    expect(formatHumanElapsedTime(oneWeekAgo)).toBe("1 week ago");
    expect(formatHumanElapsedTime(threeWeeksAgo)).toBe("3 weeks ago");
  });

  it("should format months correctly for dates within a year", () => {
    const oneMonthAgo = new Date(fixedDate.getTime() - 30 * 24 * 60 * 60 * 1000);
    const sixMonthsAgo = new Date(fixedDate.getTime() - 180 * 24 * 60 * 60 * 1000);
    const elevenMonthsAgo = new Date(fixedDate.getTime() - 330 * 24 * 60 * 60 * 1000);
    
    expect(formatHumanElapsedTime(oneMonthAgo)).toBe("1 month ago");
    expect(formatHumanElapsedTime(sixMonthsAgo)).toBe("6 months ago");
    expect(formatHumanElapsedTime(elevenMonthsAgo)).toBe("11 months ago");
  });

  it("should format years correctly for older dates", () => {
    const oneYearAgo = new Date(fixedDate.getTime() - 365 * 24 * 60 * 60 * 1000);
    const fiveYearsAgo = new Date(fixedDate.getTime() - 5 * 365 * 24 * 60 * 60 * 1000);
    
    expect(formatHumanElapsedTime(oneYearAgo)).toBe("1 year ago");
    expect(formatHumanElapsedTime(fiveYearsAgo)).toBe("5 years ago");
  });

  // =============================================================================
  // EDGE CASE TESTS
  // =============================================================================

  it("should handle string date input correctly", () => {
    const dateStr = new Date(fixedDate.getTime() - 15 * 1000).toISOString();
    expect(formatHumanElapsedTime(dateStr)).toBe("15 seconds ago");
  });

  it("should handle future dates by returning the formatted date", () => {
    const tomorrow = new Date(fixedDate.getTime() + 24 * 60 * 60 * 1000);
    expect(formatHumanElapsedTime(tomorrow)).toBe(tomorrow.toLocaleDateString());
  });

  it("should handle dates at exactly the boundary between time units", () => {
    // Exactly 60 seconds = 1 minute
    const exactlyOneMinute = new Date(fixedDate.getTime() - 60 * 1000);
    expect(formatHumanElapsedTime(exactlyOneMinute)).toBe("1 minute ago");
    
    // Exactly 60 minutes = 1 hour
    const exactlyOneHour = new Date(fixedDate.getTime() - 60 * 60 * 1000);
    expect(formatHumanElapsedTime(exactlyOneHour)).toBe("1 hour ago");
  });

  it("should handle invalid date inputs gracefully", () => {
    const invalidDate = new Date("invalid date");
    expect(() => formatHumanElapsedTime(invalidDate)).not.toThrow();
  });

  // =============================================================================
  // SHORT FORMAT TESTS
  // =============================================================================
  
  it("should return 'now' for short format within 10 seconds", () => {
    // Create dates within 10 seconds of the fixed date
    const now = new Date(fixedDate);
    const fiveSecondsAgo = new Date(fixedDate.getTime() - 5 * 1000);
    
    expect(formatHumanElapsedTime(now, true)).toBe("now");
    expect(formatHumanElapsedTime(fiveSecondsAgo, true)).toBe("now");
  });

  it("should format seconds correctly with short format", () => {
    const fifteenSecondsAgo = new Date(fixedDate.getTime() - 15 * 1000);
    const elevenSecondsAgo = new Date(fixedDate.getTime() - 11 * 1000);
    const fiftyNineSecondsAgo = new Date(fixedDate.getTime() - 59 * 1000);
    
    expect(formatHumanElapsedTime(fifteenSecondsAgo, true)).toBe("15 s ago");
    expect(formatHumanElapsedTime(elevenSecondsAgo, true)).toBe("11 s ago");
    expect(formatHumanElapsedTime(fiftyNineSecondsAgo, true)).toBe("59 s ago");
  });

  it("should format minutes correctly with short format", () => {
    const oneMinuteAgo = new Date(fixedDate.getTime() - 1 * 60 * 1000);
    const thirtyMinutesAgo = new Date(fixedDate.getTime() - 30 * 60 * 1000);
    const fiftyNineMinutesAgo = new Date(fixedDate.getTime() - 59 * 60 * 1000);
    
    expect(formatHumanElapsedTime(oneMinuteAgo, true)).toBe("1 min ago");
    expect(formatHumanElapsedTime(thirtyMinutesAgo, true)).toBe("30 min ago");
    expect(formatHumanElapsedTime(fiftyNineMinutesAgo, true)).toBe("59 min ago");
  });

  it("should format hours correctly for today with short format", () => {
    const oneHourAgo = new Date(fixedDate.getTime() - 1 * 60 * 60 * 1000);
    const sixHoursAgo = new Date(fixedDate.getTime() - 6 * 60 * 60 * 1000);
    
    expect(formatHumanElapsedTime(oneHourAgo, true)).toBe("1 hr ago");
    expect(formatHumanElapsedTime(sixHoursAgo, true)).toBe("6 hrs ago");
  });

  it("should return 'yesterday' for yesterday's dates with short format", () => {
    // Create a date that is exactly yesterday (24 hours ago)
    const yesterday = new Date(fixedDate);
    yesterday.setDate(yesterday.getDate() - 1);
    
    expect(formatHumanElapsedTime(yesterday, true)).toBe("yesterday");
  });

  it("should format days correctly for dates within a week with short format", () => {
    const twoDaysAgo = new Date(fixedDate.getTime() - 2 * 24 * 60 * 60 * 1000);
    const sixDaysAgo = new Date(fixedDate.getTime() - 6 * 24 * 60 * 60 * 1000);
    
    // Ensure these aren't identified as "yesterday"
    vi.mocked(dateFns.isYesterday).mockReturnValue(false);
    
    expect(formatHumanElapsedTime(twoDaysAgo, true)).toBe("2 d ago");
    expect(formatHumanElapsedTime(sixDaysAgo, true)).toBe("6 d ago");
  });

  it("should format weeks correctly for dates within a month with short format", () => {
    const oneWeekAgo = new Date(fixedDate.getTime() - 7 * 24 * 60 * 60 * 1000);
    const threeWeeksAgo = new Date(fixedDate.getTime() - 21 * 24 * 60 * 60 * 1000);
    
    expect(formatHumanElapsedTime(oneWeekAgo, true)).toBe("1 wk ago");
    expect(formatHumanElapsedTime(threeWeeksAgo, true)).toBe("3 wks ago");
  });

  it("should format months correctly for dates within a year with short format", () => {
    const oneMonthAgo = new Date(fixedDate.getTime() - 30 * 24 * 60 * 60 * 1000);
    const sixMonthsAgo = new Date(fixedDate.getTime() - 180 * 24 * 60 * 60 * 1000);
    const elevenMonthsAgo = new Date(fixedDate.getTime() - 330 * 24 * 60 * 60 * 1000);
    
    expect(formatHumanElapsedTime(oneMonthAgo, true)).toBe("1 mo ago");
    expect(formatHumanElapsedTime(sixMonthsAgo, true)).toBe("6 mos ago");
    expect(formatHumanElapsedTime(elevenMonthsAgo, true)).toBe("11 mos ago");
  });

  it("should format years correctly for older dates with short format", () => {
    const oneYearAgo = new Date(fixedDate.getTime() - 365 * 24 * 60 * 60 * 1000);
    const fiveYearsAgo = new Date(fixedDate.getTime() - 5 * 365 * 24 * 60 * 60 * 1000);
    
    expect(formatHumanElapsedTime(oneYearAgo, true)).toBe("1 y ago");
    expect(formatHumanElapsedTime(fiveYearsAgo, true)).toBe("5 yrs ago");
  });

  it("should handle string date input correctly with short format", () => {
    const dateStr = new Date(fixedDate.getTime() - 15 * 1000).toISOString();
    expect(formatHumanElapsedTime(dateStr, true)).toBe("15 s ago");
  });
});

```

--------------------------------------------------------------------------------
/xmlui/tests/parsers/scripting/parser-function.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, expect, assert, it } from "vitest";

import { Parser } from "../../../src/parsers/scripting/Parser";
import {
  Destructure,
  FunctionDeclaration,
  Identifier,
  SpreadExpression,
  T_BLOCK_STATEMENT,
  T_DESTRUCTURE,
  T_FUNCTION_DECLARATION,
  T_IDENTIFIER,
  T_SPREAD_EXPRESSION,
} from "../../../src/components-core/script-runner/ScriptingSourceTree";

describe("Parser - function declarations", () => {
  it("No param", () => {
    // --- Arrange
    const source = "function myFunc() { return 2*v; }";
    const wParser = new Parser(source);

    // --- Act
    const stmts = wParser.parseStatements()!;

    // --- Assert
    expect(stmts.length).toEqual(1);
    const stmt = stmts[0] as FunctionDeclaration;
    expect(stmt.type).toEqual(T_FUNCTION_DECLARATION);
    expect(stmt.id.name).toEqual("myFunc");
    expect(stmt.args.length).toEqual(0);
    expect(stmt.stmt.type).toEqual(T_BLOCK_STATEMENT);
  });

  it("Single param", () => {
    // --- Arrange
    const source = "function myFunc(v) { return 2*v; }";
    const wParser = new Parser(source);

    // --- Act
    const stmts = wParser.parseStatements()!;

    // --- Assert
    expect(stmts.length).toEqual(1);
    const stmt = stmts[0] as FunctionDeclaration;
    expect(stmt.type).toEqual(T_FUNCTION_DECLARATION);
    expect(stmt.id.name).toEqual("myFunc");
    expect(stmt.args.length).toEqual(1);
    expect(stmt.args[0].type).toEqual(T_IDENTIFIER);
    expect((stmt.args[0] as Identifier).name).toEqual("v");
    expect(stmt.stmt.type).toEqual(T_BLOCK_STATEMENT);
  });

  it("multiple params", () => {
    // --- Arrange
    const source = "function myFunc(v, w) { return 2*v; }";
    const wParser = new Parser(source);

    // --- Act
    const stmts = wParser.parseStatements()!;

    // --- Assert
    expect(stmts.length).toEqual(1);
    const stmt = stmts[0] as FunctionDeclaration;
    expect(stmt.type).toEqual(T_FUNCTION_DECLARATION);
    expect(stmt.id.name).toEqual("myFunc");
    expect(stmt.args.length).toEqual(2);
    expect(stmt.args[0].type).toEqual(T_IDENTIFIER);
    expect((stmt.args[0] as Identifier).name).toEqual("v");
    expect(stmt.args[1].type).toEqual(T_IDENTIFIER);
    expect((stmt.args[1] as Identifier).name).toEqual("w");
    expect(stmt.stmt.type).toEqual(T_BLOCK_STATEMENT);
  });

  it("Single object destructure #1", () => {
    // --- Arrange
    const source = "function myFunc({x, y}) { return 2*v; }";
    const wParser = new Parser(source);

    // --- Act
    const stmts = wParser.parseStatements()!;

    // --- Assert
    expect(stmts.length).toEqual(1);
    const stmt = stmts[0] as FunctionDeclaration;
    expect(stmt.type).toEqual(T_FUNCTION_DECLARATION);
    expect(stmt.id.name).toEqual("myFunc");
    expect(stmt.args.length).toEqual(1);
    expect(stmt.args[0].type).toEqual(T_DESTRUCTURE);
    expect((stmt.args[0] as Destructure).oDestr!.length).toEqual(2);
    expect((stmt.args[0] as Destructure).oDestr![0].id).toEqual("x");
    expect((stmt.args[0] as Destructure).oDestr![1].id).toEqual("y");
    expect(stmt.stmt.type).toEqual(T_BLOCK_STATEMENT);
  });

  it("Single object destructure #2", () => {
    // --- Arrange
    const source = "function myFunc({x, y:q}) { return 2*v; }";
    const wParser = new Parser(source);

    // --- Act
    const stmts = wParser.parseStatements()!;

    // --- Assert
    expect(stmts.length).toEqual(1);
    const stmt = stmts[0] as FunctionDeclaration;
    expect(stmt.type).toEqual(T_FUNCTION_DECLARATION);
    expect(stmt.id.name).toEqual("myFunc");
    expect(stmt.args.length).toEqual(1);
    expect(stmt.args[0].type).toEqual(T_DESTRUCTURE);
    expect((stmt.args[0] as Destructure).oDestr!.length).toEqual(2);
    expect((stmt.args[0] as Destructure).oDestr![0].id).toEqual("x");
    expect((stmt.args[0] as Destructure).oDestr![1].id).toEqual("y");
    expect((stmt.args[0] as Destructure).oDestr![1].alias).toEqual("q");
    expect(stmt.stmt.type).toEqual(T_BLOCK_STATEMENT);
  });

  it("Single object destructure #3", () => {
    // --- Arrange
    const source = "function myFunc({x, y: {v, w}}) { return 2*v; }";
    const wParser = new Parser(source);

    // --- Act
    const stmts = wParser.parseStatements()!;

    // --- Assert
    expect(stmts.length).toEqual(1);
    const stmt = stmts[0] as FunctionDeclaration;
    expect(stmt.type).toEqual(T_FUNCTION_DECLARATION);
    expect(stmt.id.name).toEqual("myFunc");
    expect(stmt.args.length).toEqual(1);
    expect(stmt.args[0].type).toEqual(T_DESTRUCTURE);
    expect((stmt.args[0] as Destructure).oDestr![0].id).toEqual("x");
    expect((stmt.args[0] as Destructure).oDestr![1].oDestr!.length).toEqual(2);
    expect((stmt.args[0] as Destructure).oDestr![1].oDestr![0].id).toEqual("v");
    expect((stmt.args[0] as Destructure).oDestr![1].oDestr![1].id).toEqual("w");
    expect(stmt.stmt.type).toEqual(T_BLOCK_STATEMENT);
  });

  it("Single array destructure #1", () => {
    // --- Arrange
    const source = "function myFunc([x, y]) { return 2*v; }";
    const wParser = new Parser(source);

    // --- Act
    const stmts = wParser.parseStatements()!;

    // --- Assert
    expect(stmts.length).toEqual(1);
    const stmt = stmts[0] as FunctionDeclaration;
    expect(stmt.type).toEqual(T_FUNCTION_DECLARATION);
    expect(stmt.id.name).toEqual("myFunc");
    expect(stmt.args.length).toEqual(1);
    expect(stmt.args[0].type).toEqual(T_DESTRUCTURE);
    expect((stmt.args[0] as Destructure).aDestr!.length).toEqual(2);
    expect((stmt.args[0] as Destructure).aDestr![0].id).toEqual("x");
    expect((stmt.args[0] as Destructure).aDestr![1].id).toEqual("y");
    expect(stmt.stmt.type).toEqual(T_BLOCK_STATEMENT);
  });

  it("Single array destructure #2", () => {
    // --- Arrange
    const source = "function myFunc([x,, y]) { return 2*v; }";
    const wParser = new Parser(source);

    // --- Act
    const stmts = wParser.parseStatements()!;

    // --- Assert
    expect(stmts.length).toEqual(1);
    const stmt = stmts[0] as FunctionDeclaration;
    expect(stmt.type).toEqual(T_FUNCTION_DECLARATION);
    expect(stmt.id.name).toEqual("myFunc");
    expect(stmt.args.length).toEqual(1);
    expect(stmt.args[0].type).toEqual(T_DESTRUCTURE);
    expect((stmt.args[0] as Destructure).aDestr!.length).toEqual(3);
    expect((stmt.args[0] as Destructure).aDestr![0].id).toEqual("x");
    expect((stmt.args[0] as Destructure).aDestr![1].id).toEqual(undefined);
    expect((stmt.args[0] as Destructure).aDestr![2].id).toEqual("y");
    expect(stmt.stmt.type).toEqual(T_BLOCK_STATEMENT);
  });

  it("Complex destructure #1", () => {
    // --- Arrange
    const source = "function myFunc([a,, b], {c, y:d}) { return 2*v; }";
    const wParser = new Parser(source);

    // --- Act
    const stmts = wParser.parseStatements()!;

    // --- Assert
    expect(stmts.length).toEqual(1);
    const stmt = stmts[0] as FunctionDeclaration;
    expect(stmt.type).toEqual(T_FUNCTION_DECLARATION);
    expect(stmt.id.name).toEqual("myFunc");
    expect(stmt.args.length).toEqual(2);
    expect(stmt.args[0].type).toEqual(T_DESTRUCTURE);
    expect((stmt.args[0] as Destructure).aDestr!.length).toEqual(3);
    expect((stmt.args[0] as Destructure).aDestr![0].id).toEqual("a");
    expect((stmt.args[0] as Destructure).aDestr![1].id).toEqual(undefined);
    expect((stmt.args[0] as Destructure).aDestr![2].id).toEqual("b");
    expect(stmt.args[1].type).toEqual(T_DESTRUCTURE);
    expect((stmt.args[1] as Destructure).oDestr!.length).toEqual(2);
    expect((stmt.args[1] as Destructure).oDestr![0].id).toEqual("c");
    expect((stmt.args[1] as Destructure).oDestr![1].id).toEqual("y");
    expect((stmt.args[1] as Destructure).oDestr![1].alias).toEqual("d");
    expect(stmt.stmt.type).toEqual(T_BLOCK_STATEMENT);
  });

  it("Complex destructure #2", () => {
    // --- Arrange
    const source = "function myFunc([a,, b], {c, y:d}, e) { return 2*v; }";
    const wParser = new Parser(source);

    // --- Act
    const stmts = wParser.parseStatements()!;

    // --- Assert
    expect(stmts.length).toEqual(1);
    const stmt = stmts[0] as FunctionDeclaration;
    expect(stmt.type).toEqual(T_FUNCTION_DECLARATION);
    expect(stmt.id.name).toEqual("myFunc");
    expect(stmt.args.length).toEqual(3);
    expect(stmt.args[0].type).toEqual(T_DESTRUCTURE);
    expect((stmt.args[0] as Destructure).aDestr!.length).toEqual(3);
    expect((stmt.args[0] as Destructure).aDestr![0].id).toEqual("a");
    expect((stmt.args[0] as Destructure).aDestr![1].id).toEqual(undefined);
    expect((stmt.args[0] as Destructure).aDestr![2].id).toEqual("b");
    expect(stmt.args[1].type).toEqual(T_DESTRUCTURE);
    expect((stmt.args[1] as Destructure).oDestr!.length).toEqual(2);
    expect((stmt.args[1] as Destructure).oDestr![0].id).toEqual("c");
    expect((stmt.args[1] as Destructure).oDestr![1].id).toEqual("y");
    expect((stmt.args[1] as Destructure).oDestr![1].alias).toEqual("d");
    expect(stmt.args[2].type).toEqual(T_IDENTIFIER);
    expect((stmt.args[2] as Identifier).name).toEqual("e");
    expect(stmt.stmt.type).toEqual(T_BLOCK_STATEMENT);
  });

  it("Single rest param", () => {
    // --- Arrange
    const source = "function myFunc(...v) { return 2*v; }";
    const wParser = new Parser(source);

    // --- Act
    const stmts = wParser.parseStatements()!;

    // --- Assert
    expect(stmts.length).toEqual(1);
    const stmt = stmts[0] as FunctionDeclaration;
    expect(stmt.type).toEqual(T_FUNCTION_DECLARATION);
    expect(stmt.id.name).toEqual("myFunc");
    expect(stmt.args.length).toEqual(1);
    expect(stmt.args[0].type).toEqual(T_SPREAD_EXPRESSION);
    const spread = stmt.args[0] as SpreadExpression;
    expect((spread.expr as Identifier).name).toEqual("v");
    expect(stmt.stmt.type).toEqual(T_BLOCK_STATEMENT);
  });

  it("Multiple params with rest", () => {
    // --- Arrange
    const source = "function myFunc(v, ...w) { return 2*v; }";
    const wParser = new Parser(source);

    // --- Act
    const stmts = wParser.parseStatements()!;

    // --- Assert
    expect(stmts.length).toEqual(1);
    const stmt = stmts[0] as FunctionDeclaration;
    expect(stmt.type).toEqual(T_FUNCTION_DECLARATION);
    expect(stmt.id.name).toEqual("myFunc");
    expect(stmt.args.length).toEqual(2);
    expect(stmt.args[0].type).toEqual(T_IDENTIFIER);
    expect((stmt.args[0] as Identifier).name).toEqual("v");
    expect(stmt.args[1].type).toEqual(T_SPREAD_EXPRESSION);
    const spread = stmt.args[1] as SpreadExpression;
    expect((spread.expr as Identifier).name).toEqual("w");
    expect(stmt.stmt.type).toEqual(T_BLOCK_STATEMENT);
  });

  it("Fails with rest params #1", () => {
    // --- Arrange
    const source = "function myFunc(...a, b) { return 2*v; }";
    const wParser = new Parser(source);

    // --- Act
    try {
      wParser.parseStatements()!;
    } catch (err) {
      // --- Assert
      expect(err.toString().includes("argument")).toBe(true);
      return;
    }
    assert.fail("Exception expected");
  });

  it("Fails with rest params #2", () => {
    // --- Arrange
    const source = "function myFunc(...(a+b)) { return 2*v; }";
    const wParser = new Parser(source);

    // --- Act
    try {
      wParser.parseStatements()!;
    } catch (err) {
      // --- Assert
      expect(err.toString().includes("argument")).toBe(true);
      return;
    }
    assert.fail("Exception expected");
  });
});

```
Page 42/144FirstPrevNextLast