This is page 34 of 182. Use http://codebase.md/xmlui-org/xmlui?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .changeset
│ ├── config.json
│ └── lemon-zoos-prove.md
├── .eslintrc.cjs
├── .github
│ ├── build-checklist.png
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows
│ ├── deploy-blog-optimized.yml
│ ├── deploy-blog.yml
│ ├── deploy-docs-optimized.yml
│ ├── deploy-docs.yml
│ ├── prepare-versions.yml
│ ├── release-packages.yml
│ ├── run-all-tests.yml
│ └── run-smoke-tests.yml
├── .gitignore
├── .prettierrc.js
├── .vscode
│ ├── launch.json
│ └── settings.json
├── blog
│ ├── .gitignore
│ ├── .gitkeep
│ ├── CHANGELOG.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── 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
│ │ └── 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
│ │ │ │ ├── debug-a-component.md
│ │ │ │ ├── delay-a-datasource-until-another-datasource-is-ready.md
│ │ │ │ ├── delegate-a-method.md
│ │ │ │ ├── do-custom-form-validation.md
│ │ │ │ ├── expose-a-method-from-a-component.md
│ │ │ │ ├── filter-and-transform-data-from-an-api.md
│ │ │ │ ├── group-items-in-list-by-a-property.md
│ │ │ │ ├── handle-background-operations.md
│ │ │ │ ├── hide-an-element-until-its-datasource-is-ready.md
│ │ │ │ ├── make-a-set-of-equal-width-cards.md
│ │ │ │ ├── make-a-table-responsive.md
│ │ │ │ ├── make-navpanel-width-responsive.md
│ │ │ │ ├── modify-a-value-reported-in-a-column.md
│ │ │ │ ├── paginate-a-list.md
│ │ │ │ ├── pass-data-to-a-modal-dialog.md
│ │ │ │ ├── react-to-button-click-not-keystrokes.md
│ │ │ │ ├── set-the-initial-value-of-a-select-from-fetched-data.md
│ │ │ │ ├── share-a-modaldialog-across-components.md
│ │ │ │ ├── sync-selections-between-table-and-list-views.md
│ │ │ │ ├── update-ui-optimistically.md
│ │ │ │ ├── use-built-in-form-validation.md
│ │ │ │ └── use-the-same-modaldialog-to-add-or-edit.md
│ │ │ ├── howto.md
│ │ │ ├── intro.md
│ │ │ ├── layout.md
│ │ │ ├── markup.md
│ │ │ ├── mcp.md
│ │ │ ├── modal-dialogs.md
│ │ │ ├── news-and-reviews.md
│ │ │ ├── reactive-intro.md
│ │ │ ├── refactoring.md
│ │ │ ├── routing-and-links.md
│ │ │ ├── samples
│ │ │ │ ├── color-palette.xmlui
│ │ │ │ ├── color-values.xmlui
│ │ │ │ ├── shadow-sizes.xmlui
│ │ │ │ ├── spacing-sizes.xmlui
│ │ │ │ ├── swatch.xmlui
│ │ │ │ ├── theme-gallery-brief.xmlui
│ │ │ │ └── theme-gallery.xmlui
│ │ │ ├── scoping.md
│ │ │ ├── scripting.md
│ │ │ ├── styles-and-themes
│ │ │ │ ├── common-units.md
│ │ │ │ ├── layout-props.md
│ │ │ │ ├── theme-variable-defaults.md
│ │ │ │ ├── theme-variables.md
│ │ │ │ └── themes.md
│ │ │ ├── template-properties.md
│ │ │ ├── test.md
│ │ │ ├── tutorial-01.md
│ │ │ ├── tutorial-02.md
│ │ │ ├── tutorial-03.md
│ │ │ ├── tutorial-04.md
│ │ │ ├── tutorial-05.md
│ │ │ ├── tutorial-06.md
│ │ │ ├── tutorial-07.md
│ │ │ ├── tutorial-08.md
│ │ │ ├── tutorial-09.md
│ │ │ ├── tutorial-10.md
│ │ │ ├── tutorial-11.md
│ │ │ ├── tutorial-12.md
│ │ │ ├── universal-properties.md
│ │ │ ├── user-defined-components.md
│ │ │ ├── vscode.md
│ │ │ ├── working-with-markdown.md
│ │ │ ├── working-with-text.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-charts
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── DonutChart.md
│ │ │ │ ├── LabelList.md
│ │ │ │ ├── Legend.md
│ │ │ │ ├── LineChart.md
│ │ │ │ └── PieChart.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ └── xmlui-spreadsheet
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ └── Spreadsheet.md
│ │ ├── resources
│ │ │ ├── devdocs
│ │ │ │ ├── debug-proxy-object-2.png
│ │ │ │ ├── debug-proxy-object.png
│ │ │ │ ├── table_editor_01.png
│ │ │ │ ├── table_editor_02.png
│ │ │ │ ├── table_editor_03.png
│ │ │ │ ├── table_editor_04.png
│ │ │ │ ├── table_editor_05.png
│ │ │ │ ├── table_editor_06.png
│ │ │ │ ├── table_editor_07.png
│ │ │ │ ├── table_editor_08.png
│ │ │ │ ├── table_editor_09.png
│ │ │ │ ├── table_editor_10.png
│ │ │ │ ├── table_editor_11.png
│ │ │ │ ├── table-editor-01.png
│ │ │ │ ├── table-editor-02.png
│ │ │ │ ├── table-editor-03.png
│ │ │ │ ├── table-editor-04.png
│ │ │ │ ├── table-editor-06.png
│ │ │ │ ├── table-editor-07.png
│ │ │ │ ├── table-editor-08.png
│ │ │ │ ├── table-editor-09.png
│ │ │ │ └── xmlui-rendering-of-tiptap-markdown.png
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ ├── clients.json
│ │ │ │ ├── daily-revenue.json
│ │ │ │ ├── dashboard-stats.json
│ │ │ │ ├── demo.xmlui
│ │ │ │ ├── demo.xmlui.xs
│ │ │ │ ├── downloads
│ │ │ │ │ └── downloads.json
│ │ │ │ ├── for-download
│ │ │ │ │ ├── index-with-api.html
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── mockApi.js
│ │ │ │ │ ├── start-darwin.sh
│ │ │ │ │ ├── start-linux.sh
│ │ │ │ │ ├── start.bat
│ │ │ │ │ └── xmlui
│ │ │ │ │ └── xmlui-standalone.umd.js
│ │ │ │ ├── getting-started
│ │ │ │ │ ├── cl-tutorial-final.zip
│ │ │ │ │ ├── cl-tutorial.zip
│ │ │ │ │ ├── cl-tutorial2.zip
│ │ │ │ │ ├── cl-tutorial3.zip
│ │ │ │ │ ├── cl-tutorial4.zip
│ │ │ │ │ ├── cl-tutorial5.zip
│ │ │ │ │ ├── cl-tutorial6.zip
│ │ │ │ │ ├── getting-started.zip
│ │ │ │ │ ├── hello-xmlui.zip
│ │ │ │ │ ├── xmlui-empty.zip
│ │ │ │ │ └── xmlui-starter.zip
│ │ │ │ ├── howto
│ │ │ │ │ └── component-icons
│ │ │ │ │ └── up-arrow.svg
│ │ │ │ ├── invoices.json
│ │ │ │ ├── monthly-status.json
│ │ │ │ ├── news-and-reviews.json
│ │ │ │ ├── products.json
│ │ │ │ ├── releases.json
│ │ │ │ ├── tutorials
│ │ │ │ │ ├── datasource
│ │ │ │ │ │ └── api.ts
│ │ │ │ │ └── p2do
│ │ │ │ │ ├── api.ts
│ │ │ │ │ └── todo-logo.svg
│ │ │ │ └── xmlui.json
│ │ │ ├── github.svg
│ │ │ ├── images
│ │ │ │ ├── apiaction-tutorial
│ │ │ │ │ ├── add-success.png
│ │ │ │ │ ├── apiaction-param.png
│ │ │ │ │ ├── change-completed.png
│ │ │ │ │ ├── change-in-progress.png
│ │ │ │ │ ├── confirm-delete.png
│ │ │ │ │ ├── data-error.png
│ │ │ │ │ ├── data-progress.png
│ │ │ │ │ ├── data-success.png
│ │ │ │ │ ├── display-1.png
│ │ │ │ │ ├── item-deleted.png
│ │ │ │ │ ├── item-updated.png
│ │ │ │ │ ├── missing-api-key.png
│ │ │ │ │ ├── new-item-added.png
│ │ │ │ │ └── test-message.png
│ │ │ │ ├── chat-api
│ │ │ │ │ └── domain-model.svg
│ │ │ │ ├── components
│ │ │ │ │ ├── image
│ │ │ │ │ │ └── breakfast.jpg
│ │ │ │ │ ├── markdown
│ │ │ │ │ │ └── colors.png
│ │ │ │ │ └── modal
│ │ │ │ │ ├── deep_link_dialog_1.jpg
│ │ │ │ │ └── deep_link_dialog_2.jpg
│ │ │ │ ├── create-apps
│ │ │ │ │ ├── collapsed-vertical.png
│ │ │ │ │ ├── using-forms-warning-dialog.png
│ │ │ │ │ └── using-forms.png
│ │ │ │ ├── datasource-tutorial
│ │ │ │ │ ├── data-with-header.png
│ │ │ │ │ ├── filtered-data.png
│ │ │ │ │ ├── filtered-items.png
│ │ │ │ │ ├── initial-page-items.png
│ │ │ │ │ ├── list-items.png
│ │ │ │ │ ├── next-page-items.png
│ │ │ │ │ ├── no-data.png
│ │ │ │ │ ├── pagination-1.jpg
│ │ │ │ │ ├── pagination-1.png
│ │ │ │ │ ├── polling-1.png
│ │ │ │ │ ├── refetch-data.png
│ │ │ │ │ ├── slow-loading.png
│ │ │ │ │ ├── test-message.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── unconventional-data.png
│ │ │ │ │ └── unfiltered-items.png
│ │ │ │ ├── flower.jpg
│ │ │ │ ├── get-started
│ │ │ │ │ ├── add-new-contact.png
│ │ │ │ │ ├── app-modified.png
│ │ │ │ │ ├── app-start.png
│ │ │ │ │ ├── app-with-boxes.png
│ │ │ │ │ ├── app-with-toast.png
│ │ │ │ │ ├── boilerplate-structure.png
│ │ │ │ │ ├── cl-initial.png
│ │ │ │ │ ├── cl-start.png
│ │ │ │ │ ├── contact-counts.png
│ │ │ │ │ ├── contact-dialog-title.png
│ │ │ │ │ ├── contact-dialog.png
│ │ │ │ │ ├── contact-menus.png
│ │ │ │ │ ├── contact-predicates.png
│ │ │ │ │ ├── context-menu.png
│ │ │ │ │ ├── dashboard-numbers.png
│ │ │ │ │ ├── default-contact-list.png
│ │ │ │ │ ├── delete-contact.png
│ │ │ │ │ ├── delete-task.png
│ │ │ │ │ ├── detailed-template.png
│ │ │ │ │ ├── edit-contact-details.png
│ │ │ │ │ ├── edited-contact-saved.png
│ │ │ │ │ ├── empty-sections.png
│ │ │ │ │ ├── filter-completed.png
│ │ │ │ │ ├── fullwidth-desktop.png
│ │ │ │ │ ├── fullwidth-mobile.png
│ │ │ │ │ ├── initial-table.png
│ │ │ │ │ ├── items-and-badges.png
│ │ │ │ │ ├── loading-message.png
│ │ │ │ │ ├── new-contact-button.png
│ │ │ │ │ ├── new-contact-saved.png
│ │ │ │ │ ├── no-empty-sections.png
│ │ │ │ │ ├── personal-todo-initial.png
│ │ │ │ │ ├── piechart.png
│ │ │ │ │ ├── review-today.png
│ │ │ │ │ ├── rudimentary-dashboard.png
│ │ │ │ │ ├── section-collapsed.png
│ │ │ │ │ ├── sectioned-items.png
│ │ │ │ │ ├── sections-ordered.png
│ │ │ │ │ ├── spacex-list-with-links.png
│ │ │ │ │ ├── spacex-list.png
│ │ │ │ │ ├── start-personal-todo-1.png
│ │ │ │ │ ├── submit-new-contact.png
│ │ │ │ │ ├── submit-new-task.png
│ │ │ │ │ ├── syntax-highlighting.png
│ │ │ │ │ ├── table-with-badge.png
│ │ │ │ │ ├── template-with-card.png
│ │ │ │ │ ├── test-emulated-api.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── todo-logo.png
│ │ │ │ │ └── xmlui-tools.png
│ │ │ │ ├── HelloApp.png
│ │ │ │ ├── HelloApp2.png
│ │ │ │ ├── logos
│ │ │ │ │ ├── xmlui1.svg
│ │ │ │ │ ├── xmlui2.svg
│ │ │ │ │ ├── xmlui3.svg
│ │ │ │ │ ├── xmlui4.svg
│ │ │ │ │ ├── xmlui5.svg
│ │ │ │ │ ├── xmlui6.svg
│ │ │ │ │ └── xmlui7.svg
│ │ │ │ ├── pdf
│ │ │ │ │ └── dummy-pdf.jpg
│ │ │ │ ├── rendering-engine
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ ├── Component.svg
│ │ │ │ │ ├── CompoundComponent.svg
│ │ │ │ │ ├── RootComponent.svg
│ │ │ │ │ └── tree-with-containers.svg
│ │ │ │ ├── reviewers-guide
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ └── incbutton-in-action.png
│ │ │ │ ├── tools
│ │ │ │ │ └── boilerplate-structure.png
│ │ │ │ ├── try.svg
│ │ │ │ ├── tutorial
│ │ │ │ │ ├── app-chat-history.png
│ │ │ │ │ ├── app-content-placeholder.png
│ │ │ │ │ ├── app-header-and-content.png
│ │ │ │ │ ├── app-links-channel-selected.png
│ │ │ │ │ ├── app-links-click.png
│ │ │ │ │ ├── app-navigation.png
│ │ │ │ │ ├── finished-ex01.png
│ │ │ │ │ ├── finished-ex02.png
│ │ │ │ │ ├── hello.png
│ │ │ │ │ ├── splash-screen-advanced.png
│ │ │ │ │ ├── splash-screen-after-click.png
│ │ │ │ │ ├── splash-screen-centered.png
│ │ │ │ │ ├── splash-screen-events.png
│ │ │ │ │ ├── splash-screen-expression.png
│ │ │ │ │ ├── splash-screen-reuse-after.png
│ │ │ │ │ ├── splash-screen-reuse-before.png
│ │ │ │ │ └── splash-screen.png
│ │ │ │ └── tutorial-01.png
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ ├── Boxes.xmlui
│ │ │ ├── Breadcrumb.xmlui
│ │ │ ├── ChangeLog.xmlui
│ │ │ ├── ColorPalette.xmlui
│ │ │ ├── DocumentLinks.xmlui
│ │ │ ├── DocumentPage.xmlui
│ │ │ ├── DocumentPageNoTOC.xmlui
│ │ │ ├── Icons.xmlui
│ │ │ ├── IncButton.xmlui
│ │ │ ├── IncButton2.xmlui
│ │ │ ├── NameValue.xmlui
│ │ │ ├── PageNotFound.xmlui
│ │ │ ├── PaletteItem.xmlui
│ │ │ ├── Palettes.xmlui
│ │ │ ├── SectionHeader.xmlui
│ │ │ ├── TBD.xmlui
│ │ │ ├── Test.xmlui
│ │ │ ├── ThemesIntro.xmlui
│ │ │ ├── ThousandThemes.xmlui
│ │ │ ├── TubeStops.xmlui
│ │ │ ├── TubeStops.xmlui.xs
│ │ │ └── TwoColumnCode.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ ├── docs-theme.ts
│ │ ├── earthtone.ts
│ │ ├── xmlui-gray-on-default.ts
│ │ ├── xmlui-green-on-default.ts
│ │ └── xmlui-orange-on-default.ts
│ └── tsconfig.json
├── LICENSE
├── package-lock.json
├── package.json
├── packages
│ ├── tsconfig.json
│ ├── xmlui-animations
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── Animation.tsx
│ │ ├── AnimationNative.tsx
│ │ ├── FadeAnimation.tsx
│ │ ├── FadeInAnimation.tsx
│ │ ├── FadeOutAnimation.tsx
│ │ ├── index.tsx
│ │ ├── ScaleAnimation.tsx
│ │ └── SlideInAnimation.tsx
│ ├── xmlui-devtools
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── devtools
│ │ │ │ ├── DevTools.tsx
│ │ │ │ ├── DevToolsNative.module.scss
│ │ │ │ ├── DevToolsNative.tsx
│ │ │ │ ├── ModalDialog.module.scss
│ │ │ │ ├── ModalDialog.tsx
│ │ │ │ ├── ModalVisibilityContext.tsx
│ │ │ │ ├── Tooltip.module.scss
│ │ │ │ ├── Tooltip.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── editor
│ │ │ │ └── Editor.tsx
│ │ │ └── index.tsx
│ │ └── vite.config-overrides.ts
│ ├── xmlui-hello-world
│ │ ├── .gitignore
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── HelloWorld.module.scss
│ │ ├── HelloWorld.tsx
│ │ ├── HelloWorldNative.tsx
│ │ └── index.tsx
│ ├── xmlui-os-frames
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── IPhoneFrame.module.scss
│ │ ├── IPhoneFrame.tsx
│ │ ├── MacOSAppFrame.module.scss
│ │ ├── MacOSAppFrame.tsx
│ │ ├── WindowsAppFrame.module.scss
│ │ └── WindowsAppFrame.tsx
│ ├── xmlui-pdf
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ ├── components
│ │ │ │ └── Pdf.xmlui
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── LazyPdfNative.tsx
│ │ ├── Pdf.module.scss
│ │ └── Pdf.tsx
│ ├── xmlui-playground
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── hooks
│ │ │ ├── usePlayground.ts
│ │ │ └── useToast.ts
│ │ ├── index.tsx
│ │ ├── playground
│ │ │ ├── Box.module.scss
│ │ │ ├── Box.tsx
│ │ │ ├── CodeSelector.tsx
│ │ │ ├── ConfirmationDialog.module.scss
│ │ │ ├── ConfirmationDialog.tsx
│ │ │ ├── Editor.tsx
│ │ │ ├── Header.module.scss
│ │ │ ├── Header.tsx
│ │ │ ├── Playground.tsx
│ │ │ ├── PlaygroundContent.module.scss
│ │ │ ├── PlaygroundContent.tsx
│ │ │ ├── PlaygroundNative.module.scss
│ │ │ ├── PlaygroundNative.tsx
│ │ │ ├── Preview.module.scss
│ │ │ ├── Preview.tsx
│ │ │ ├── Select.module.scss
│ │ │ ├── StandalonePlayground.tsx
│ │ │ ├── StandalonePlaygroundNative.module.scss
│ │ │ ├── StandalonePlaygroundNative.tsx
│ │ │ ├── ThemeSwitcher.module.scss
│ │ │ ├── ThemeSwitcher.tsx
│ │ │ ├── ToneSwitcher.tsx
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.tsx
│ │ │ └── utils.ts
│ │ ├── providers
│ │ │ ├── Toast.module.scss
│ │ │ └── ToastProvider.tsx
│ │ ├── state
│ │ │ └── store.ts
│ │ ├── themes
│ │ │ └── theme.ts
│ │ └── utils
│ │ └── helpers.ts
│ ├── xmlui-search
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── Search.module.scss
│ │ └── Search.tsx
│ ├── xmlui-spreadsheet
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── Spreadsheet.tsx
│ │ └── SpreadsheetNative.tsx
│ └── xmlui-website-blocks
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── demo
│ │ ├── components
│ │ │ ├── HeroBackgroundBreakoutPage.xmlui
│ │ │ ├── HeroBackgroundsPage.xmlui
│ │ │ ├── HeroContentsPage.xmlui
│ │ │ ├── HeroTextAlignPage.xmlui
│ │ │ ├── HeroTextPage.xmlui
│ │ │ └── HeroTonesPage.xmlui
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── default.ts
│ ├── index.html
│ ├── index.ts
│ ├── meta
│ │ └── componentsMetadata.ts
│ ├── package.json
│ ├── public
│ │ └── resources
│ │ ├── building.jpg
│ │ └── xmlui-logo.svg
│ └── src
│ ├── Carousel
│ │ ├── Carousel.module.scss
│ │ ├── Carousel.tsx
│ │ ├── CarouselContext.tsx
│ │ └── CarouselNative.tsx
│ ├── FancyButton
│ │ ├── FancyButton.module.scss
│ │ ├── FancyButton.tsx
│ │ └── FancyButton.xmlui
│ ├── Hello
│ │ ├── Hello.tsx
│ │ ├── Hello.xmlui
│ │ └── Hello.xmlui.xs
│ ├── HeroSection
│ │ ├── HeroSection.module.scss
│ │ ├── HeroSection.spec.ts
│ │ ├── HeroSection.tsx
│ │ └── HeroSectionNative.tsx
│ ├── index.tsx
│ ├── ScrollToTop
│ │ ├── ScrollToTop.module.scss
│ │ ├── ScrollToTop.tsx
│ │ └── ScrollToTopNative.tsx
│ └── vite-env.d.ts
├── playwright.config.ts
├── README.md
├── tools
│ ├── codefence
│ │ └── xmlui-code-fence-docs.md
│ ├── create-app
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── create-app.ts
│ │ ├── helpers
│ │ │ ├── copy.ts
│ │ │ ├── get-pkg-manager.ts
│ │ │ ├── git.ts
│ │ │ ├── install.ts
│ │ │ ├── is-folder-empty.ts
│ │ │ ├── is-writeable.ts
│ │ │ ├── make-dir.ts
│ │ │ └── validate-pkg.ts
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── templates
│ │ │ ├── default
│ │ │ │ └── ts
│ │ │ │ ├── gitignore
│ │ │ │ ├── index.html
│ │ │ │ ├── index.ts
│ │ │ │ ├── public
│ │ │ │ │ ├── mockServiceWorker.js
│ │ │ │ │ ├── resources
│ │ │ │ │ │ ├── favicon.ico
│ │ │ │ │ │ └── xmlui-logo.svg
│ │ │ │ │ └── serve.json
│ │ │ │ └── src
│ │ │ │ ├── components
│ │ │ │ │ ├── ApiAware.xmlui
│ │ │ │ │ ├── Home.xmlui
│ │ │ │ │ ├── IncButton.xmlui
│ │ │ │ │ └── PagePanel.xmlui
│ │ │ │ ├── config.ts
│ │ │ │ └── Main.xmlui
│ │ │ ├── index.ts
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ ├── create-xmlui-hello-world
│ │ ├── index.js
│ │ └── package.json
│ └── vscode
│ ├── .gitignore
│ ├── .vscode
│ │ ├── launch.json
│ │ └── tasks.json
│ ├── .vscodeignore
│ ├── build.sh
│ ├── CHANGELOG.md
│ ├── esbuild.js
│ ├── eslint.config.mjs
│ ├── formatter-docs.md
│ ├── generate-test-sample.sh
│ ├── LICENSE.md
│ ├── package-lock.json
│ ├── package.json
│ ├── README.md
│ ├── resources
│ │ ├── xmlui-logo.png
│ │ └── xmlui-markup-syntax-highlighting.png
│ ├── src
│ │ ├── extension.ts
│ │ └── server.ts
│ ├── syntaxes
│ │ └── xmlui.tmLanguage.json
│ ├── test-samples
│ │ └── sample.xmlui
│ ├── tsconfig.json
│ └── tsconfig.tsbuildinfo
├── turbo.json
└── xmlui
├── .gitignore
├── bin
│ ├── bootstrap.cjs
│ ├── bootstrap.js
│ ├── build-lib.ts
│ ├── build.ts
│ ├── index.ts
│ ├── preview.ts
│ ├── start.ts
│ ├── vite-xmlui-plugin.ts
│ └── viteConfig.ts
├── CHANGELOG.md
├── conventions
│ ├── component-qa-checklist.md
│ ├── copilot-conventions.md
│ ├── create-xmlui-components.md
│ ├── mermaid.md
│ ├── testing-conventions.md
│ └── xmlui-in-a-nutshell.md
├── dev-docs
│ ├── accessibility.md
│ ├── build-system.md
│ ├── build-xmlui.md
│ ├── component-behaviors.md
│ ├── components-with-options.md
│ ├── containers.md
│ ├── data-operations.md
│ ├── glossary.md
│ ├── index.md
│ ├── next
│ │ ├── component-dev-guide.md
│ │ ├── configuration-management-enhancement-summary.md
│ │ ├── documentation-scripts-refactoring-complete-summary.md
│ │ ├── documentation-scripts-refactoring-plan.md
│ │ ├── duplicate-pattern-extraction-summary.md
│ │ ├── error-handling-standardization-summary.md
│ │ ├── generating-component-reference.md
│ │ ├── index.md
│ │ ├── logging-consistency-implementation-summary.md
│ │ ├── project-build.md
│ │ ├── project-structure.md
│ │ ├── theme-context.md
│ │ ├── tiptap-design-considerations.md
│ │ ├── working-with-code.md
│ │ ├── xmlui-runtime-architecture
│ │ └── xmlui-wcag-accessibility-report.md
│ ├── react-fundamentals.md
│ ├── release-method.md
│ ├── standalone-app.md
│ ├── ud-components.md
│ └── xmlui-repo.md
├── package.json
├── scripts
│ ├── coverage-only.js
│ ├── e2e-test-summary.js
│ ├── generate-docs
│ │ ├── build-downloads-map.mjs
│ │ ├── build-pages-map.mjs
│ │ ├── components-config.json
│ │ ├── configuration-management.mjs
│ │ ├── constants.mjs
│ │ ├── create-theme-files.mjs
│ │ ├── DocsGenerator.mjs
│ │ ├── error-handling.mjs
│ │ ├── extensions-config.json
│ │ ├── folders.mjs
│ │ ├── generate-summary-files.mjs
│ │ ├── get-docs.mjs
│ │ ├── input-handler.mjs
│ │ ├── logger.mjs
│ │ ├── logging-standards.mjs
│ │ ├── MetadataProcessor.mjs
│ │ ├── pattern-utilities.mjs
│ │ └── utils.mjs
│ ├── get-langserver-metadata.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.spec.ts
│ │ │ │ ├── LabelList.tsx
│ │ │ │ ├── LabelListNative.module.scss
│ │ │ │ └── LabelListNative.tsx
│ │ │ ├── Legend
│ │ │ │ ├── Legend.spec.ts
│ │ │ │ ├── Legend.tsx
│ │ │ │ └── LegendNative.tsx
│ │ │ ├── LineChart
│ │ │ │ ├── LineChart.md
│ │ │ │ ├── LineChart.module.scss
│ │ │ │ ├── LineChart.spec.ts
│ │ │ │ ├── LineChart.tsx
│ │ │ │ └── LineChartNative.tsx
│ │ │ ├── PieChart
│ │ │ │ ├── PieChart.md
│ │ │ │ ├── PieChart.spec.ts
│ │ │ │ ├── PieChart.tsx
│ │ │ │ ├── PieChartNative.module.scss
│ │ │ │ └── PieChartNative.tsx
│ │ │ ├── RadarChart
│ │ │ │ ├── RadarChart.md
│ │ │ │ ├── RadarChart.spec.ts
│ │ │ │ ├── RadarChart.tsx
│ │ │ │ └── RadarChartNative.tsx
│ │ │ ├── Tooltip
│ │ │ │ ├── TooltipContent.module.scss
│ │ │ │ ├── TooltipContent.spec.ts
│ │ │ │ └── TooltipContent.tsx
│ │ │ └── utils
│ │ │ ├── abstractions.ts
│ │ │ └── ChartProvider.tsx
│ │ ├── Checkbox
│ │ │ ├── Checkbox.md
│ │ │ ├── Checkbox.spec.ts
│ │ │ └── Checkbox.tsx
│ │ ├── CodeBlock
│ │ │ ├── CodeBlock.module.scss
│ │ │ ├── CodeBlock.spec.ts
│ │ │ ├── CodeBlock.tsx
│ │ │ ├── CodeBlockNative.tsx
│ │ │ └── highlight-code.ts
│ │ ├── collectedComponentMetadata.ts
│ │ ├── ColorPicker
│ │ │ ├── ColorPicker.md
│ │ │ ├── ColorPicker.module.scss
│ │ │ ├── ColorPicker.spec.ts
│ │ │ ├── ColorPicker.tsx
│ │ │ └── ColorPickerNative.tsx
│ │ ├── Column
│ │ │ ├── Column.md
│ │ │ ├── Column.tsx
│ │ │ ├── ColumnNative.tsx
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ └── TableContext.tsx
│ │ ├── component-utils.ts
│ │ ├── ComponentProvider.tsx
│ │ ├── ComponentRegistryContext.tsx
│ │ ├── container-helpers.tsx
│ │ ├── ContentSeparator
│ │ │ ├── ContentSeparator.md
│ │ │ ├── ContentSeparator.module.scss
│ │ │ ├── ContentSeparator.spec.ts
│ │ │ ├── ContentSeparator.tsx
│ │ │ └── ContentSeparatorNative.tsx
│ │ ├── DataSource
│ │ │ ├── DataSource.md
│ │ │ └── DataSource.tsx
│ │ ├── DateInput
│ │ │ ├── DateInput.md
│ │ │ ├── DateInput.module.scss
│ │ │ ├── DateInput.spec.ts
│ │ │ ├── DateInput.tsx
│ │ │ └── DateInputNative.tsx
│ │ ├── DatePicker
│ │ │ ├── DatePicker.md
│ │ │ ├── DatePicker.module.scss
│ │ │ ├── DatePicker.spec.ts
│ │ │ ├── DatePicker.tsx
│ │ │ └── DatePickerNative.tsx
│ │ ├── DropdownMenu
│ │ │ ├── DropdownMenu.md
│ │ │ ├── DropdownMenu.module.scss
│ │ │ ├── DropdownMenu.spec.ts
│ │ │ ├── DropdownMenu.tsx
│ │ │ ├── DropdownMenuNative.tsx
│ │ │ ├── MenuItem.md
│ │ │ └── SubMenuItem.md
│ │ ├── EmojiSelector
│ │ │ ├── EmojiSelector.md
│ │ │ ├── EmojiSelector.spec.ts
│ │ │ ├── EmojiSelector.tsx
│ │ │ └── EmojiSelectorNative.tsx
│ │ ├── ExpandableItem
│ │ │ ├── ExpandableItem.module.scss
│ │ │ ├── ExpandableItem.spec.ts
│ │ │ ├── ExpandableItem.tsx
│ │ │ └── ExpandableItemNative.tsx
│ │ ├── FileInput
│ │ │ ├── FileInput.md
│ │ │ ├── FileInput.module.scss
│ │ │ ├── FileInput.spec.ts
│ │ │ ├── FileInput.tsx
│ │ │ └── FileInputNative.tsx
│ │ ├── FileUploadDropZone
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FileUploadDropZone.module.scss
│ │ │ ├── FileUploadDropZone.spec.ts
│ │ │ ├── FileUploadDropZone.tsx
│ │ │ └── FileUploadDropZoneNative.tsx
│ │ ├── FlowLayout
│ │ │ ├── FlowLayout.md
│ │ │ ├── FlowLayout.module.scss
│ │ │ ├── FlowLayout.spec.ts
│ │ │ ├── FlowLayout.spec.ts-snapshots
│ │ │ │ └── Edge-cases-boxShadow-is-not-clipped-1-non-smoke-darwin.png
│ │ │ ├── FlowLayout.tsx
│ │ │ └── FlowLayoutNative.tsx
│ │ ├── Footer
│ │ │ ├── Footer.md
│ │ │ ├── Footer.module.scss
│ │ │ ├── Footer.spec.ts
│ │ │ ├── Footer.tsx
│ │ │ └── FooterNative.tsx
│ │ ├── Form
│ │ │ ├── Form.md
│ │ │ ├── Form.module.scss
│ │ │ ├── Form.spec.ts
│ │ │ ├── Form.tsx
│ │ │ ├── formActions.ts
│ │ │ ├── FormContext.ts
│ │ │ └── FormNative.tsx
│ │ ├── FormItem
│ │ │ ├── FormItem.md
│ │ │ ├── FormItem.module.scss
│ │ │ ├── FormItem.spec.ts
│ │ │ ├── FormItem.tsx
│ │ │ ├── FormItemNative.tsx
│ │ │ ├── HelperText.module.scss
│ │ │ ├── HelperText.tsx
│ │ │ ├── ItemWithLabel.tsx
│ │ │ └── Validations.ts
│ │ ├── FormSection
│ │ │ ├── FormSection.md
│ │ │ ├── FormSection.ts
│ │ │ └── FormSection.xmlui
│ │ ├── Fragment
│ │ │ ├── Fragment.spec.ts
│ │ │ └── Fragment.tsx
│ │ ├── Heading
│ │ │ ├── abstractions.ts
│ │ │ ├── H1.md
│ │ │ ├── H1.spec.ts
│ │ │ ├── H2.md
│ │ │ ├── H2.spec.ts
│ │ │ ├── H3.md
│ │ │ ├── H3.spec.ts
│ │ │ ├── H4.md
│ │ │ ├── H4.spec.ts
│ │ │ ├── H5.md
│ │ │ ├── H5.spec.ts
│ │ │ ├── H6.md
│ │ │ ├── H6.spec.ts
│ │ │ ├── Heading.md
│ │ │ ├── Heading.module.scss
│ │ │ ├── Heading.spec.ts
│ │ │ ├── Heading.tsx
│ │ │ └── HeadingNative.tsx
│ │ ├── HoverCard
│ │ │ ├── HoverCard.tsx
│ │ │ └── HovercardNative.tsx
│ │ ├── HtmlTags
│ │ │ ├── HtmlTags.module.scss
│ │ │ ├── HtmlTags.spec.ts
│ │ │ └── HtmlTags.tsx
│ │ ├── Icon
│ │ │ ├── AdmonitionDanger.tsx
│ │ │ ├── AdmonitionInfo.tsx
│ │ │ ├── AdmonitionNote.tsx
│ │ │ ├── AdmonitionTip.tsx
│ │ │ ├── AdmonitionWarning.tsx
│ │ │ ├── ApiIcon.tsx
│ │ │ ├── ArrowDropDown.module.scss
│ │ │ ├── ArrowDropDown.tsx
│ │ │ ├── ArrowDropUp.module.scss
│ │ │ ├── ArrowDropUp.tsx
│ │ │ ├── ArrowLeft.module.scss
│ │ │ ├── ArrowLeft.tsx
│ │ │ ├── ArrowRight.module.scss
│ │ │ ├── ArrowRight.tsx
│ │ │ ├── Attach.tsx
│ │ │ ├── Binding.module.scss
│ │ │ ├── Binding.tsx
│ │ │ ├── BoardIcon.tsx
│ │ │ ├── BoxIcon.tsx
│ │ │ ├── CheckIcon.tsx
│ │ │ ├── ChevronDownIcon.tsx
│ │ │ ├── ChevronLeft.tsx
│ │ │ ├── ChevronRight.tsx
│ │ │ ├── ChevronUpIcon.tsx
│ │ │ ├── CodeFileIcon.tsx
│ │ │ ├── CodeSandbox.tsx
│ │ │ ├── CompactListIcon.tsx
│ │ │ ├── ContentCopyIcon.tsx
│ │ │ ├── DarkToLightIcon.tsx
│ │ │ ├── DatabaseIcon.module.scss
│ │ │ ├── DatabaseIcon.tsx
│ │ │ ├── DocFileIcon.tsx
│ │ │ ├── DocIcon.tsx
│ │ │ ├── DotMenuHorizontalIcon.tsx
│ │ │ ├── DotMenuIcon.tsx
│ │ │ ├── EmailIcon.tsx
│ │ │ ├── EmptyFolderIcon.tsx
│ │ │ ├── ErrorIcon.tsx
│ │ │ ├── ExpressionIcon.tsx
│ │ │ ├── FillPlusCricleIcon.tsx
│ │ │ ├── FilterIcon.tsx
│ │ │ ├── FolderIcon.tsx
│ │ │ ├── GlobeIcon.tsx
│ │ │ ├── HomeIcon.tsx
│ │ │ ├── HyperLinkIcon.tsx
│ │ │ ├── Icon.md
│ │ │ ├── Icon.module.scss
│ │ │ ├── Icon.spec.ts
│ │ │ ├── Icon.tsx
│ │ │ ├── IconNative.tsx
│ │ │ ├── ImageFileIcon.tsx
│ │ │ ├── Inspect.tsx
│ │ │ ├── LightToDark.tsx
│ │ │ ├── LinkIcon.tsx
│ │ │ ├── ListIcon.tsx
│ │ │ ├── LooseListIcon.tsx
│ │ │ ├── MoonIcon.tsx
│ │ │ ├── MoreOptionsIcon.tsx
│ │ │ ├── NoSortIcon.tsx
│ │ │ ├── PDFIcon.tsx
│ │ │ ├── PenIcon.tsx
│ │ │ ├── PhoneIcon.tsx
│ │ │ ├── PhotoIcon.tsx
│ │ │ ├── PlusIcon.tsx
│ │ │ ├── SearchIcon.tsx
│ │ │ ├── ShareIcon.tsx
│ │ │ ├── SortAscendingIcon.tsx
│ │ │ ├── SortDescendingIcon.tsx
│ │ │ ├── StarsIcon.tsx
│ │ │ ├── SunIcon.tsx
│ │ │ ├── svg
│ │ │ │ ├── admonition_danger.svg
│ │ │ │ ├── admonition_info.svg
│ │ │ │ ├── admonition_note.svg
│ │ │ │ ├── admonition_tip.svg
│ │ │ │ ├── admonition_warning.svg
│ │ │ │ ├── api.svg
│ │ │ │ ├── arrow-dropdown.svg
│ │ │ │ ├── arrow-left.svg
│ │ │ │ ├── arrow-right.svg
│ │ │ │ ├── arrow-up.svg
│ │ │ │ ├── attach.svg
│ │ │ │ ├── binding.svg
│ │ │ │ ├── box.svg
│ │ │ │ ├── bulb.svg
│ │ │ │ ├── code-file.svg
│ │ │ │ ├── code-sandbox.svg
│ │ │ │ ├── dark_to_light.svg
│ │ │ │ ├── database.svg
│ │ │ │ ├── doc.svg
│ │ │ │ ├── empty-folder.svg
│ │ │ │ ├── expression.svg
│ │ │ │ ├── eye-closed.svg
│ │ │ │ ├── eye-dark.svg
│ │ │ │ ├── eye.svg
│ │ │ │ ├── file-text.svg
│ │ │ │ ├── filter.svg
│ │ │ │ ├── folder.svg
│ │ │ │ ├── img.svg
│ │ │ │ ├── inspect.svg
│ │ │ │ ├── light_to_dark.svg
│ │ │ │ ├── moon.svg
│ │ │ │ ├── pdf.svg
│ │ │ │ ├── photo.svg
│ │ │ │ ├── share.svg
│ │ │ │ ├── stars.svg
│ │ │ │ ├── sun.svg
│ │ │ │ ├── trending-down.svg
│ │ │ │ ├── trending-level.svg
│ │ │ │ ├── trending-up.svg
│ │ │ │ ├── txt.svg
│ │ │ │ ├── unknown-file.svg
│ │ │ │ ├── unlink.svg
│ │ │ │ └── xls.svg
│ │ │ ├── TableDeleteColumnIcon.tsx
│ │ │ ├── TableDeleteRowIcon.tsx
│ │ │ ├── TableInsertColumnIcon.tsx
│ │ │ ├── TableInsertRowIcon.tsx
│ │ │ ├── TrashIcon.tsx
│ │ │ ├── TrendingDownIcon.tsx
│ │ │ ├── TrendingLevelIcon.tsx
│ │ │ ├── TrendingUpIcon.tsx
│ │ │ ├── TxtIcon.tsx
│ │ │ ├── UnknownFileIcon.tsx
│ │ │ ├── UnlinkIcon.tsx
│ │ │ ├── UserIcon.tsx
│ │ │ ├── WarningIcon.tsx
│ │ │ └── XlsIcon.tsx
│ │ ├── IconProvider.tsx
│ │ ├── IconRegistryContext.tsx
│ │ ├── IFrame
│ │ │ ├── IFrame.md
│ │ │ ├── IFrame.module.scss
│ │ │ ├── IFrame.spec.ts
│ │ │ ├── IFrame.tsx
│ │ │ └── IFrameNative.tsx
│ │ ├── Image
│ │ │ ├── Image.md
│ │ │ ├── Image.module.scss
│ │ │ ├── Image.spec.ts
│ │ │ ├── Image.tsx
│ │ │ └── ImageNative.tsx
│ │ ├── Input
│ │ │ ├── index.ts
│ │ │ ├── InputAdornment.module.scss
│ │ │ ├── InputAdornment.tsx
│ │ │ ├── InputDivider.module.scss
│ │ │ ├── InputDivider.tsx
│ │ │ ├── InputLabel.module.scss
│ │ │ ├── InputLabel.tsx
│ │ │ ├── PartialInput.module.scss
│ │ │ └── PartialInput.tsx
│ │ ├── InspectButton
│ │ │ ├── InspectButton.module.scss
│ │ │ └── InspectButton.tsx
│ │ ├── Items
│ │ │ ├── Items.md
│ │ │ ├── Items.spec.ts
│ │ │ ├── Items.tsx
│ │ │ └── ItemsNative.tsx
│ │ ├── Link
│ │ │ ├── Link.md
│ │ │ ├── Link.module.scss
│ │ │ ├── Link.spec.ts
│ │ │ ├── Link.tsx
│ │ │ └── LinkNative.tsx
│ │ ├── List
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── List.md
│ │ │ ├── List.module.scss
│ │ │ ├── List.spec.ts
│ │ │ ├── List.tsx
│ │ │ └── ListNative.tsx
│ │ ├── Logo
│ │ │ ├── doc-resources
│ │ │ │ └── xmlui-logo.svg
│ │ │ ├── Logo.md
│ │ │ ├── Logo.tsx
│ │ │ └── LogoNative.tsx
│ │ ├── Markdown
│ │ │ ├── CodeText.module.scss
│ │ │ ├── CodeText.tsx
│ │ │ ├── Markdown.md
│ │ │ ├── Markdown.module.scss
│ │ │ ├── Markdown.spec.ts
│ │ │ ├── Markdown.tsx
│ │ │ ├── MarkdownNative.tsx
│ │ │ ├── parse-binding-expr.ts
│ │ │ └── utils.ts
│ │ ├── metadata-helpers.ts
│ │ ├── ModalDialog
│ │ │ ├── ConfirmationModalContextProvider.tsx
│ │ │ ├── Dialog.module.scss
│ │ │ ├── Dialog.tsx
│ │ │ ├── ModalDialog.md
│ │ │ ├── ModalDialog.module.scss
│ │ │ ├── ModalDialog.spec.ts
│ │ │ ├── ModalDialog.tsx
│ │ │ ├── ModalDialogNative.tsx
│ │ │ └── ModalVisibilityContext.tsx
│ │ ├── NavGroup
│ │ │ ├── NavGroup.md
│ │ │ ├── NavGroup.module.scss
│ │ │ ├── NavGroup.spec.ts
│ │ │ ├── NavGroup.tsx
│ │ │ ├── NavGroupContext.ts
│ │ │ └── NavGroupNative.tsx
│ │ ├── NavLink
│ │ │ ├── NavLink.md
│ │ │ ├── NavLink.module.scss
│ │ │ ├── NavLink.spec.ts
│ │ │ ├── NavLink.tsx
│ │ │ └── NavLinkNative.tsx
│ │ ├── NavPanel
│ │ │ ├── NavPanel.md
│ │ │ ├── NavPanel.module.scss
│ │ │ ├── NavPanel.spec.ts
│ │ │ ├── NavPanel.tsx
│ │ │ └── NavPanelNative.tsx
│ │ ├── NestedApp
│ │ │ ├── AppWithCodeView.module.scss
│ │ │ ├── AppWithCodeView.tsx
│ │ │ ├── AppWithCodeViewNative.tsx
│ │ │ ├── defaultProps.tsx
│ │ │ ├── logo.svg
│ │ │ ├── NestedApp.module.scss
│ │ │ ├── NestedApp.tsx
│ │ │ ├── NestedAppNative.tsx
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.tsx
│ │ │ └── utils.ts
│ │ ├── NoResult
│ │ │ ├── NoResult.md
│ │ │ ├── NoResult.module.scss
│ │ │ ├── NoResult.spec.ts
│ │ │ ├── NoResult.tsx
│ │ │ └── NoResultNative.tsx
│ │ ├── NumberBox
│ │ │ ├── numberbox-abstractions.ts
│ │ │ ├── NumberBox.md
│ │ │ ├── NumberBox.module.scss
│ │ │ ├── NumberBox.spec.ts
│ │ │ ├── NumberBox.tsx
│ │ │ └── NumberBoxNative.tsx
│ │ ├── Option
│ │ │ ├── Option.md
│ │ │ ├── Option.spec.ts
│ │ │ ├── Option.tsx
│ │ │ ├── OptionNative.tsx
│ │ │ └── OptionTypeProvider.tsx
│ │ ├── PageMetaTitle
│ │ │ ├── PageMetaTilteNative.tsx
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── PageMetaTitle.spec.ts
│ │ │ └── PageMetaTitle.tsx
│ │ ├── Pages
│ │ │ ├── Page.md
│ │ │ ├── Pages.md
│ │ │ ├── Pages.module.scss
│ │ │ ├── Pages.tsx
│ │ │ └── PagesNative.tsx
│ │ ├── Pagination
│ │ │ ├── Pagination.md
│ │ │ ├── Pagination.module.scss
│ │ │ ├── Pagination.spec.ts
│ │ │ ├── Pagination.tsx
│ │ │ └── PaginationNative.tsx
│ │ ├── PositionedContainer
│ │ │ ├── PositionedContainer.module.scss
│ │ │ ├── PositionedContainer.tsx
│ │ │ └── PositionedContainerNative.tsx
│ │ ├── ProfileMenu
│ │ │ ├── ProfileMenu.module.scss
│ │ │ └── ProfileMenu.tsx
│ │ ├── ProgressBar
│ │ │ ├── ProgressBar.md
│ │ │ ├── ProgressBar.module.scss
│ │ │ ├── ProgressBar.spec.ts
│ │ │ ├── ProgressBar.tsx
│ │ │ └── ProgressBarNative.tsx
│ │ ├── Queue
│ │ │ ├── Queue.md
│ │ │ ├── Queue.spec.ts
│ │ │ ├── Queue.tsx
│ │ │ ├── queueActions.ts
│ │ │ └── QueueNative.tsx
│ │ ├── RadioGroup
│ │ │ ├── RadioGroup.md
│ │ │ ├── RadioGroup.module.scss
│ │ │ ├── RadioGroup.spec.ts
│ │ │ ├── RadioGroup.tsx
│ │ │ ├── RadioGroupNative.tsx
│ │ │ ├── RadioItem.tsx
│ │ │ └── RadioItemNative.tsx
│ │ ├── RealTimeAdapter
│ │ │ ├── RealTimeAdapter.tsx
│ │ │ └── RealTimeAdapterNative.tsx
│ │ ├── Redirect
│ │ │ ├── Redirect.md
│ │ │ ├── Redirect.spec.ts
│ │ │ └── Redirect.tsx
│ │ ├── ResponsiveBar
│ │ │ ├── README.md
│ │ │ ├── ResponsiveBar.md
│ │ │ ├── ResponsiveBar.module.scss
│ │ │ ├── ResponsiveBar.spec.ts
│ │ │ ├── ResponsiveBar.tsx
│ │ │ └── ResponsiveBarNative.tsx
│ │ ├── Select
│ │ │ ├── HiddenOption.tsx
│ │ │ ├── OptionContext.ts
│ │ │ ├── Select.md
│ │ │ ├── Select.module.scss
│ │ │ ├── Select.spec.ts
│ │ │ ├── Select.tsx
│ │ │ ├── SelectContext.tsx
│ │ │ └── SelectNative.tsx
│ │ ├── SelectionStore
│ │ │ ├── SelectionStore.md
│ │ │ ├── SelectionStore.tsx
│ │ │ └── SelectionStoreNative.tsx
│ │ ├── Slider
│ │ │ ├── Slider.md
│ │ │ ├── Slider.module.scss
│ │ │ ├── Slider.spec.ts
│ │ │ ├── Slider.tsx
│ │ │ └── SliderNative.tsx
│ │ ├── Slot
│ │ │ ├── Slot.md
│ │ │ ├── Slot.spec.ts
│ │ │ └── Slot.ts
│ │ ├── SlotItem.tsx
│ │ ├── SpaceFiller
│ │ │ ├── SpaceFiller.md
│ │ │ ├── SpaceFiller.module.scss
│ │ │ ├── SpaceFiller.spec.ts
│ │ │ ├── SpaceFiller.tsx
│ │ │ └── SpaceFillerNative.tsx
│ │ ├── Spinner
│ │ │ ├── Spinner.md
│ │ │ ├── Spinner.module.scss
│ │ │ ├── Spinner.spec.ts
│ │ │ ├── Spinner.tsx
│ │ │ └── SpinnerNative.tsx
│ │ ├── Splitter
│ │ │ ├── HSplitter.md
│ │ │ ├── HSplitter.spec.ts
│ │ │ ├── Splitter.md
│ │ │ ├── Splitter.module.scss
│ │ │ ├── Splitter.spec.ts
│ │ │ ├── Splitter.tsx
│ │ │ ├── SplitterNative.tsx
│ │ │ ├── utils.ts
│ │ │ ├── VSplitter.md
│ │ │ └── VSplitter.spec.ts
│ │ ├── Stack
│ │ │ ├── CHStack.md
│ │ │ ├── CHStack.spec.ts
│ │ │ ├── CVStack.md
│ │ │ ├── CVStack.spec.ts
│ │ │ ├── HStack.md
│ │ │ ├── HStack.spec.ts
│ │ │ ├── Stack.md
│ │ │ ├── Stack.module.scss
│ │ │ ├── Stack.spec.ts
│ │ │ ├── Stack.tsx
│ │ │ ├── StackNative.tsx
│ │ │ ├── VStack.md
│ │ │ └── VStack.spec.ts
│ │ ├── StickyBox
│ │ │ ├── StickyBox.md
│ │ │ ├── StickyBox.module.scss
│ │ │ ├── StickyBox.tsx
│ │ │ └── StickyBoxNative.tsx
│ │ ├── Switch
│ │ │ ├── Switch.md
│ │ │ ├── Switch.spec.ts
│ │ │ └── Switch.tsx
│ │ ├── Table
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── react-table-config.d.ts
│ │ │ ├── Table.md
│ │ │ ├── Table.module.scss
│ │ │ ├── Table.spec.ts
│ │ │ ├── Table.tsx
│ │ │ ├── TableNative.tsx
│ │ │ └── useRowSelection.tsx
│ │ ├── TableOfContents
│ │ │ ├── TableOfContents.module.scss
│ │ │ ├── TableOfContents.spec.ts
│ │ │ ├── TableOfContents.tsx
│ │ │ └── TableOfContentsNative.tsx
│ │ ├── Tabs
│ │ │ ├── TabContext.tsx
│ │ │ ├── TabItem.md
│ │ │ ├── TabItem.tsx
│ │ │ ├── TabItemNative.tsx
│ │ │ ├── Tabs.md
│ │ │ ├── Tabs.module.scss
│ │ │ ├── Tabs.spec.ts
│ │ │ ├── Tabs.tsx
│ │ │ └── TabsNative.tsx
│ │ ├── Text
│ │ │ ├── Text.md
│ │ │ ├── Text.module.scss
│ │ │ ├── Text.spec.ts
│ │ │ ├── Text.tsx
│ │ │ └── TextNative.tsx
│ │ ├── TextArea
│ │ │ ├── TextArea.md
│ │ │ ├── TextArea.module.scss
│ │ │ ├── TextArea.spec.ts
│ │ │ ├── TextArea.tsx
│ │ │ ├── TextAreaNative.tsx
│ │ │ ├── TextAreaResizable.tsx
│ │ │ └── useComposedRef.ts
│ │ ├── TextBox
│ │ │ ├── TextBox.md
│ │ │ ├── TextBox.module.scss
│ │ │ ├── TextBox.spec.ts
│ │ │ ├── TextBox.tsx
│ │ │ └── TextBoxNative.tsx
│ │ ├── Theme
│ │ │ ├── NotificationToast.tsx
│ │ │ ├── Theme.md
│ │ │ ├── Theme.module.scss
│ │ │ ├── Theme.spec.ts
│ │ │ ├── Theme.tsx
│ │ │ └── ThemeNative.tsx
│ │ ├── TimeInput
│ │ │ ├── TimeInput.md
│ │ │ ├── TimeInput.module.scss
│ │ │ ├── TimeInput.spec.ts
│ │ │ ├── TimeInput.tsx
│ │ │ ├── TimeInputNative.tsx
│ │ │ └── utils.ts
│ │ ├── Timer
│ │ │ ├── Timer.md
│ │ │ ├── Timer.spec.ts
│ │ │ ├── Timer.tsx
│ │ │ └── TimerNative.tsx
│ │ ├── Toggle
│ │ │ ├── Toggle.module.scss
│ │ │ └── Toggle.tsx
│ │ ├── ToneChangerButton
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneChangerButton.spec.ts
│ │ │ └── ToneChangerButton.tsx
│ │ ├── ToneSwitch
│ │ │ ├── ToneSwitch.md
│ │ │ ├── ToneSwitch.module.scss
│ │ │ ├── ToneSwitch.spec.ts
│ │ │ ├── ToneSwitch.tsx
│ │ │ └── ToneSwitchNative.tsx
│ │ ├── Tooltip
│ │ │ ├── Tooltip.md
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.spec.ts
│ │ │ ├── Tooltip.tsx
│ │ │ └── TooltipNative.tsx
│ │ ├── Tree
│ │ │ ├── testData.ts
│ │ │ ├── Tree-dynamic.spec.ts
│ │ │ ├── Tree-icons.spec.ts
│ │ │ ├── Tree.md
│ │ │ ├── Tree.spec.ts
│ │ │ ├── TreeComponent.module.scss
│ │ │ ├── TreeComponent.tsx
│ │ │ └── TreeNative.tsx
│ │ ├── TreeDisplay
│ │ │ ├── TreeDisplay.md
│ │ │ ├── TreeDisplay.module.scss
│ │ │ ├── TreeDisplay.tsx
│ │ │ └── TreeDisplayNative.tsx
│ │ ├── ValidationSummary
│ │ │ ├── ValidationSummary.module.scss
│ │ │ └── ValidationSummary.tsx
│ │ └── VisuallyHidden.tsx
│ ├── components-core
│ │ ├── abstractions
│ │ │ ├── ComponentRenderer.ts
│ │ │ ├── LoaderRenderer.ts
│ │ │ ├── standalone.ts
│ │ │ └── treeAbstractions.ts
│ │ ├── action
│ │ │ ├── actions.ts
│ │ │ ├── APICall.tsx
│ │ │ ├── FileDownloadAction.tsx
│ │ │ ├── FileUploadAction.tsx
│ │ │ ├── NavigateAction.tsx
│ │ │ └── TimedAction.tsx
│ │ ├── ApiBoundComponent.tsx
│ │ ├── appContext
│ │ │ ├── date-functions.ts
│ │ │ ├── math-function.ts
│ │ │ └── misc-utils.ts
│ │ ├── AppContext.tsx
│ │ ├── behaviors
│ │ │ ├── Behavior.tsx
│ │ │ └── CoreBehaviors.tsx
│ │ ├── component-hooks.ts
│ │ ├── ComponentDecorator.tsx
│ │ ├── ComponentViewer.tsx
│ │ ├── CompoundComponent.tsx
│ │ ├── constants.ts
│ │ ├── DebugViewProvider.tsx
│ │ ├── descriptorHelper.ts
│ │ ├── devtools
│ │ │ ├── InspectorDialog.module.scss
│ │ │ ├── InspectorDialog.tsx
│ │ │ └── InspectorDialogVisibilityContext.tsx
│ │ ├── EngineError.ts
│ │ ├── event-handlers.ts
│ │ ├── InspectorButton.module.scss
│ │ ├── InspectorContext.tsx
│ │ ├── interception
│ │ │ ├── abstractions.ts
│ │ │ ├── ApiInterceptor.ts
│ │ │ ├── ApiInterceptorProvider.tsx
│ │ │ ├── apiInterceptorWorker.ts
│ │ │ ├── Backend.ts
│ │ │ ├── Errors.ts
│ │ │ ├── IndexedDb.ts
│ │ │ ├── initMock.ts
│ │ │ ├── InMemoryDb.ts
│ │ │ ├── ReadonlyCollection.ts
│ │ │ └── useApiInterceptorContext.tsx
│ │ ├── loader
│ │ │ ├── ApiLoader.tsx
│ │ │ ├── DataLoader.tsx
│ │ │ ├── ExternalDataLoader.tsx
│ │ │ ├── Loader.tsx
│ │ │ ├── MockLoaderRenderer.tsx
│ │ │ └── PageableLoader.tsx
│ │ ├── LoaderComponent.tsx
│ │ ├── markup-check.ts
│ │ ├── parts.ts
│ │ ├── renderers.ts
│ │ ├── rendering
│ │ │ ├── AppContent.tsx
│ │ │ ├── AppRoot.tsx
│ │ │ ├── AppWrapper.tsx
│ │ │ ├── buildProxy.ts
│ │ │ ├── collectFnVarDeps.ts
│ │ │ ├── ComponentAdapter.tsx
│ │ │ ├── ComponentWrapper.tsx
│ │ │ ├── Container.tsx
│ │ │ ├── containers.ts
│ │ │ ├── ContainerWrapper.tsx
│ │ │ ├── ErrorBoundary.module.scss
│ │ │ ├── ErrorBoundary.tsx
│ │ │ ├── InvalidComponent.module.scss
│ │ │ ├── InvalidComponent.tsx
│ │ │ ├── nodeUtils.ts
│ │ │ ├── reducer.ts
│ │ │ ├── renderChild.tsx
│ │ │ ├── StandaloneComponent.tsx
│ │ │ ├── StateContainer.tsx
│ │ │ ├── UnknownComponent.module.scss
│ │ │ ├── UnknownComponent.tsx
│ │ │ └── valueExtractor.ts
│ │ ├── reportEngineError.ts
│ │ ├── RestApiProxy.ts
│ │ ├── script-runner
│ │ │ ├── asyncProxy.ts
│ │ │ ├── AttributeValueParser.ts
│ │ │ ├── bannedFunctions.ts
│ │ │ ├── BindingTreeEvaluationContext.ts
│ │ │ ├── eval-tree-async.ts
│ │ │ ├── eval-tree-common.ts
│ │ │ ├── eval-tree-sync.ts
│ │ │ ├── ParameterParser.ts
│ │ │ ├── process-statement-async.ts
│ │ │ ├── process-statement-common.ts
│ │ │ ├── process-statement-sync.ts
│ │ │ ├── ScriptingSourceTree.ts
│ │ │ ├── simplify-expression.ts
│ │ │ ├── statement-queue.ts
│ │ │ └── visitors.ts
│ │ ├── StandaloneApp.tsx
│ │ ├── StandaloneExtensionManager.ts
│ │ ├── TableOfContentsContext.tsx
│ │ ├── theming
│ │ │ ├── _themes.scss
│ │ │ ├── component-layout-resolver.ts
│ │ │ ├── extendThemeUtils.ts
│ │ │ ├── hvar.ts
│ │ │ ├── layout-resolver.ts
│ │ │ ├── parse-layout-props.ts
│ │ │ ├── StyleContext.tsx
│ │ │ ├── StyleRegistry.ts
│ │ │ ├── ThemeContext.tsx
│ │ │ ├── ThemeProvider.tsx
│ │ │ ├── themes
│ │ │ │ ├── base-utils.ts
│ │ │ │ ├── palette.ts
│ │ │ │ ├── root.ts
│ │ │ │ ├── solid.ts
│ │ │ │ ├── theme-colors.ts
│ │ │ │ └── xmlui.ts
│ │ │ ├── themeVars.module.scss
│ │ │ ├── themeVars.ts
│ │ │ ├── transformThemeVars.ts
│ │ │ └── utils.ts
│ │ ├── utils
│ │ │ ├── actionUtils.ts
│ │ │ ├── audio-utils.ts
│ │ │ ├── base64-utils.ts
│ │ │ ├── compound-utils.ts
│ │ │ ├── css-utils.ts
│ │ │ ├── DataLoaderQueryKeyGenerator.ts
│ │ │ ├── date-utils.ts
│ │ │ ├── extractParam.ts
│ │ │ ├── hooks.tsx
│ │ │ ├── LruCache.ts
│ │ │ ├── mergeProps.ts
│ │ │ ├── misc.ts
│ │ │ ├── request-params.ts
│ │ │ ├── statementUtils.ts
│ │ │ └── treeUtils.ts
│ │ └── xmlui-parser.ts
│ ├── index-standalone.ts
│ ├── index.scss
│ ├── index.ts
│ ├── language-server
│ │ ├── server-common.ts
│ │ ├── server-web-worker.ts
│ │ ├── server.ts
│ │ ├── services
│ │ │ ├── common
│ │ │ │ ├── docs-generation.ts
│ │ │ │ ├── lsp-utils.ts
│ │ │ │ ├── metadata-utils.ts
│ │ │ │ └── syntax-node-utilities.ts
│ │ │ ├── completion.ts
│ │ │ ├── diagnostic.ts
│ │ │ ├── format.ts
│ │ │ └── hover.ts
│ │ └── xmlui-metadata-generated.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.bin.json
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── vitest.config.ts
```
# Files
--------------------------------------------------------------------------------
/docs/content/components/Avatar.md:
--------------------------------------------------------------------------------
```markdown
1 | # Avatar [#avatar]
2 |
3 | `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.
4 |
5 | **Key features:**
6 | - **Automatic fallback**: Shows initials when no image URL is provided or image fails to load
7 | - **Multiple sizes**: From `xs` (extra small) to `lg` (large) to fit different contexts
8 | - **Clickable**: Supports click events for profile actions, modals, or navigation
9 | - **Accessible**: Automatically generates appropriate alt text from the name
10 |
11 | ## Properties [#properties]
12 |
13 | ### `name` [#name]
14 |
15 | 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.
16 |
17 | ```xmlui-pg copy display name="Example: name"
18 | <App>
19 | <Avatar name="John, Doe" />
20 | </App>
21 | ```
22 |
23 | ### `size` (default: "sm") [#size-default-sm]
24 |
25 | This property defines the display size of the Avatar.
26 |
27 | Available values:
28 |
29 | | Value | Description |
30 | | --- | --- |
31 | | `xs` | Extra small |
32 | | `sm` | Small **(default)** |
33 | | `md` | Medium |
34 | | `lg` | Large |
35 | | `xl` | Extra large |
36 |
37 | ```xmlui-pg copy display name="Example: size"
38 | <App>
39 | <HStack>
40 | <Avatar name="Dorothy Ellen Fuller" />
41 | <Avatar name="Xavier Schiller" size="xs" />
42 | <Avatar name="Sebastien Moore" size="sm" />
43 | <Avatar name="Molly Dough" size="md" />
44 | <Avatar name="Lynn Gilbert" size="lg" />
45 | </HStack>
46 | </App>
47 | ```
48 |
49 | ### `url` [#url]
50 |
51 | 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.
52 |
53 | ```xmlui-pg copy display name="Example: url"
54 | <App>
55 | <Avatar url="https://i.pravatar.cc/100" size="md" />
56 | </App>
57 | ```
58 |
59 | ## Events [#events]
60 |
61 | ### `click` [#click]
62 |
63 | This event is triggered when the avatar is clicked.
64 |
65 | ```xmlui-pg copy display name="Example: click"
66 | <App>
67 | <HStack verticalAlignment="center">
68 | <Avatar name="Molly Dough" size="md" onClick="toast('Avatar clicked')" />
69 | Click the avatar!
70 | </HStack>
71 | </App>
72 | ```
73 |
74 | ## Exposed Methods [#exposed-methods]
75 |
76 | This component does not expose any methods.
77 |
78 | ## Styling [#styling]
79 |
80 | ### Theme Variables [#theme-variables]
81 |
82 | | Variable | Default Value (Light) | Default Value (Dark) |
83 | | --- | --- | --- |
84 | | [backgroundColor](../styles-and-themes/common-units/#color)-Avatar | $color-surface-100 | $color-surface-100 |
85 | | [border](../styles-and-themes/common-units/#border)-Avatar | 0px solid $color-surface-400A80 | 0px solid $color-surface-400A80 |
86 | | [borderBottom](../styles-and-themes/common-units/#border)-Avatar | *none* | *none* |
87 | | [borderBottomColor](../styles-and-themes/common-units/#color)-Avatar | *none* | *none* |
88 | | [borderBottomStyle](../styles-and-themes/common-units/#border-style)-Avatar | *none* | *none* |
89 | | [borderBottomWidth](../styles-and-themes/common-units/#size)-Avatar | *none* | *none* |
90 | | [borderColor](../styles-and-themes/common-units/#color)-Avatar | *none* | *none* |
91 | | [borderEndEndRadius](../styles-and-themes/common-units/#border-rounding)-Avatar | *none* | *none* |
92 | | [borderEndStartRadius](../styles-and-themes/common-units/#border-rounding)-Avatar | *none* | *none* |
93 | | [borderHorizontal](../styles-and-themes/common-units/#border)-Avatar | *none* | *none* |
94 | | [borderHorizontalColor](../styles-and-themes/common-units/#color)-Avatar | *none* | *none* |
95 | | [borderHorizontalStyle](../styles-and-themes/common-units/#border-style)-Avatar | *none* | *none* |
96 | | [borderHorizontalWidth](../styles-and-themes/common-units/#size)-Avatar | *none* | *none* |
97 | | [borderLeft](../styles-and-themes/common-units/#border)-Avatar | *none* | *none* |
98 | | [color](../styles-and-themes/common-units/#color)-Avatar | *none* | *none* |
99 | | [borderLeftStyle](../styles-and-themes/common-units/#border-style)-Avatar | *none* | *none* |
100 | | [borderLeftWidth](../styles-and-themes/common-units/#size)-Avatar | *none* | *none* |
101 | | [borderRadius](../styles-and-themes/common-units/#border-rounding)-Avatar | 4px | 4px |
102 | | [borderRight](../styles-and-themes/common-units/#border)-Avatar | *none* | *none* |
103 | | [color](../styles-and-themes/common-units/#color)-Avatar | *none* | *none* |
104 | | [borderRightStyle](../styles-and-themes/common-units/#border-style)-Avatar | *none* | *none* |
105 | | [borderRightWidth](../styles-and-themes/common-units/#size)-Avatar | *none* | *none* |
106 | | [borderStartEndRadius](../styles-and-themes/common-units/#border-rounding)-Avatar | *none* | *none* |
107 | | [borderStartStartRadius](../styles-and-themes/common-units/#border-rounding)-Avatar | *none* | *none* |
108 | | [borderStyle](../styles-and-themes/common-units/#border-style)-Avatar | *none* | *none* |
109 | | [borderTop](../styles-and-themes/common-units/#border)-Avatar | *none* | *none* |
110 | | [borderTopColor](../styles-and-themes/common-units/#color)-Avatar | *none* | *none* |
111 | | [borderTopStyle](../styles-and-themes/common-units/#border-style)-Avatar | *none* | *none* |
112 | | [borderTopWidth](../styles-and-themes/common-units/#size)-Avatar | *none* | *none* |
113 | | [borderHorizontal](../styles-and-themes/common-units/#border)-Avatar | *none* | *none* |
114 | | [borderVerticalColor](../styles-and-themes/common-units/#color)-Avatar | *none* | *none* |
115 | | [borderVerticalStyle](../styles-and-themes/common-units/#border-style)-Avatar | *none* | *none* |
116 | | [borderVerticalWidth](../styles-and-themes/common-units/#size)-Avatar | *none* | *none* |
117 | | [borderWidth](../styles-and-themes/common-units/#size)-Avatar | *none* | *none* |
118 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Avatar | inset 0 0 0 1px rgba(4,32,69,0.1) | inset 0 0 0 1px rgba(4,32,69,0.1) |
119 | | [fontWeight](../styles-and-themes/common-units/#fontWeight)-Avatar | $fontWeight-bold | $fontWeight-bold |
120 | | [textColor](../styles-and-themes/common-units/#color)-Avatar | $textColor-secondary | $textColor-secondary |
121 |
```
--------------------------------------------------------------------------------
/docs/content/components/Splitter.md:
--------------------------------------------------------------------------------
```markdown
1 | # Splitter [#splitter]
2 |
3 | `Splitter` component divides a container into two resizable sections. These are are identified by their names: primary and secondary. They have a draggable bar between them.
4 |
5 | Most properties of the component focus on the primary section (e.g. sizing).
6 |
7 | See also: [HSplitter](/components/HSplitter), [VSplitter](/components/VSplitter).
8 |
9 | ## Properties [#properties]
10 |
11 | ### `floating` (default: false) [#floating-default-false]
12 |
13 | Toggles whether the resizer is visible (`false`) or not (`true`) when not hovered or dragged. The default value is `false`, meaning the resizer is visible all the time.
14 |
15 | ```xmlui-pg copy display name="Example: floating"
16 | <App>
17 | <Splitter height="200px" floating="true">
18 | <Stack backgroundColor="lightblue" height="100%" />
19 | <Stack backgroundColor="darksalmon" height="100%" />
20 | </Splitter>
21 | </App>
22 | ```
23 |
24 | ### `initialPrimarySize` (default: "50%") [#initialprimarysize-default-50-]
25 |
26 | This optional number property sets the initial size of the primary section. The unit of the size value is in pixels or percentages.
27 |
28 | ```xmlui-pg copy display name="Example: initialPrimarySize"
29 | <App>
30 | <Splitter height="200px" initialPrimarySize="40%">
31 | <Stack backgroundColor="lightblue" height="100%" />
32 | <Stack backgroundColor="darksalmon" height="100%" />
33 | </Splitter>
34 | </App>
35 | ```
36 |
37 | ### `maxPrimarySize` (default: "100%") [#maxprimarysize-default-100-]
38 |
39 | This property sets the maximum size the primary section can have. The unit of the size value is in pixels or percentages. Negative values are supported and calculate from the end of the container (e.g., "-20%" means "80% of container", "-100px" means "container size - 100px").
40 |
41 | ```xmlui-pg copy display name="Example: maxPrimarySize"
42 | <App>
43 | <Splitter height="200px" maxPrimarySize="80%">
44 | <Stack backgroundColor="lightblue" height="100%" />
45 | <Stack backgroundColor="darksalmon" height="100%" />
46 | </Splitter>
47 | </App>
48 | ```
49 |
50 | ```xmlui-pg copy display name="Example: maxPrimarySize with negative value (from end)"
51 | <App>
52 | <Splitter height="200px" maxPrimarySize="-50px">
53 | <Stack backgroundColor="lightblue" height="100%" />
54 | <Stack backgroundColor="darksalmon" height="100%" />
55 | </Splitter>
56 | </App>
57 | ```
58 |
59 | ### `minPrimarySize` (default: "0%") [#minprimarysize-default-0-]
60 |
61 | This property sets the minimum size the primary section can have. The unit of the size value is in pixels or percentages.
62 |
63 | ```xmlui-pg copy display name="Example: minPrimarySize"
64 | <App>
65 | <Splitter height="200px" minPrimarySize="40px">
66 | <Stack backgroundColor="lightblue" height="100%" />
67 | <Stack backgroundColor="darksalmon" height="100%" />
68 | </Splitter>
69 | </App>
70 | ```
71 |
72 | ### `orientation` (default: "vertical") [#orientation-default-vertical]
73 |
74 | Sets whether the `Splitter` divides the container horizontally and lays out the section on top of each other (`vertical`), or vertically by placing the sections next to each other (`horizontal`).
75 |
76 | Available values: `horizontal`, `vertical` **(default)**
77 |
78 | ```xmlui-pg copy display name="Example: orientation"
79 | <App>
80 | <Splitter height="200px" orientation="horizontal">
81 | <Stack backgroundColor="lightblue" height="100%" />
82 | <Stack backgroundColor="darksalmon" height="100%" />
83 | </Splitter>
84 | </App>
85 | ```
86 |
87 | ### `splitterTemplate` [#splittertemplate]
88 |
89 | The divider can be customized using XMLUI components via this property.
90 |
91 | ```xmlui-pg copy {2-4} display name="Example: splitterTemplate"
92 | <App>
93 | <Splitter height="200px">
94 | <property name="splitterTemplate">
95 | <ContentSeparator backgroundColor="green" height="4px" />
96 | </property>
97 | <Stack backgroundColor="lightblue" height="100%" />
98 | <Stack backgroundColor="darksalmon" height="100%" />
99 | </Splitter>
100 | </App>
101 | ```
102 |
103 | ### `swapped` (default: false) [#swapped-default-false]
104 |
105 | This optional booelan property indicates whether the `Splitter` sections are layed out as primary and secondary (`false`) or secondary and primary (`true`) from left to right.
106 |
107 | ```xmlui-pg copy display name="Example: swapped"
108 | <App>
109 | <Splitter height="200px" swapped="true">
110 | <Stack backgroundColor="lightblue" height="100%" />
111 | <Stack backgroundColor="darksalmon" height="100%" />
112 | </Splitter>
113 | </App>
114 | ```
115 |
116 | ## Events [#events]
117 |
118 | ### `resize` [#resize]
119 |
120 | This event fires when the component is resized.
121 |
122 | ```xmlui-pg copy {2} display name="Example: resize"
123 | <App height="200px" var.counter="{0}">
124 | <Splitter onResize="counter++">
125 | <Stack backgroundColor="lightblue" height="100%">
126 | <Text value="Resize event called {counter} number of times" />
127 | </Stack>
128 | <Stack backgroundColor="darksalmon" height="100%" />
129 | </Splitter>
130 | </App>
131 | ```
132 |
133 | ## Exposed Methods [#exposed-methods]
134 |
135 | This component does not expose any methods.
136 |
137 | ## Styling [#styling]
138 |
139 | ### Theme Variables [#theme-variables]
140 |
141 | | Variable | Default Value (Light) | Default Value (Dark) |
142 | | --- | --- | --- |
143 | | [backgroundColor](../styles-and-themes/common-units/#color)-resizer-Splitter | $color-surface-100 | $color-surface-100 |
144 | | [backgroundColor](../styles-and-themes/common-units/#color)-Splitter | *none* | *none* |
145 | | [border](../styles-and-themes/common-units/#border)-Splitter | *none* | *none* |
146 | | [borderColor](../styles-and-themes/common-units/#color)-Splitter | *none* | *none* |
147 | | [borderRadius](../styles-and-themes/common-units/#border-rounding)-Splitter | *none* | *none* |
148 | | [borderStyle](../styles-and-themes/common-units/#border-style)-Splitter | *none* | *none* |
149 | | [borderWidth](../styles-and-themes/common-units/#size)-Splitter | *none* | *none* |
150 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Splitter | *none* | *none* |
151 | | [cursor](../styles-and-themes/common-units/#cursor)-resizer-horizontal-Splitter | ew-resize | ew-resize |
152 | | [cursor](../styles-and-themes/common-units/#cursor)-resizer-vertical-Splitter | ns-resize | ns-resize |
153 | | [thickness](../styles-and-themes/common-units/#size)-resizer-Splitter | 5px | 5px |
154 |
```
--------------------------------------------------------------------------------
/xmlui/dev-docs/next/documentation-scripts-refactoring-plan.md:
--------------------------------------------------------------------------------
```markdown
1 | # XMLUI Documentation Generation Scripts - Refactoring Plan
2 |
3 | ## Overview
4 | This document outlines additional refactoring opportunities identified in the XMLUI documentation generation scripts beyond the basic constant extraction that has already been completed.
5 |
6 | ## High-Priority Refactoring Opportunities
7 |
8 | ### 1. Error Handling Standardization
9 | **Current Issues:**
10 | - Inconsistent error handling patterns across scripts
11 | - Mix of `console.log()` + `process.exit()` vs proper logger usage
12 | - Some scripts lack proper error handling entirely
13 |
14 | **Files Affected:**
15 | - `create-theme-files.mjs` - Uses console.log + process.exit
16 | - Various forEach loops with potential for silent failures
17 |
18 | **Recommended Solution:**
19 | - Create standardized error handling utilities
20 | - Replace all console.log error messages with logger
21 | - Implement proper error recovery where possible
22 |
23 | ### 2. Logging Consistency
24 | **Current Issues:**
25 | - `create-theme-files.mjs` uses console.log instead of the logger
26 | - Inconsistent log levels and formatting
27 |
28 | **Files Affected:**
29 | - `create-theme-files.mjs`
30 |
31 | **Recommended Solution:**
32 | - Update all scripts to use the centralized logger
33 | - Standardize log messages and levels
34 |
35 | ### 3. Duplicate Pattern Extraction ✅ **COMPLETED**
36 | **Status:** ✅ **COMPLETED** - See [duplicate-pattern-extraction-summary.md](./duplicate-pattern-extraction-summary.md)
37 |
38 | **Original Issues:**
39 | - Multiple forEach loops with similar Object.entries patterns
40 | - Repeated theme variable processing logic
41 | - Similar file writing patterns
42 |
43 | **Files Affected:**
44 | - `create-theme-files.mjs` - Repeated theme variable processing
45 | - `MetadataProcessor.mjs` - Similar forEach patterns for props/apis/events
46 |
47 | **Solution Implemented:**
48 | - ✅ Created `pattern-utilities.mjs` with comprehensive reusable utilities
49 | - ✅ Extracted common iteration utilities (`iterateObjectEntries`, `iterateArray`)
50 | - ✅ Created specialized theme processing utilities (`processComponentThemeVars`, `extractThemeVars`)
51 | - ✅ Standardized file writing operations (`writeFileWithLogging`, `generateExportStatements`)
52 | - ✅ Created component processing utilities (`processComponentSection`, `processDuplicatesWithLogging`)
53 | - ✅ Updated all affected scripts to use shared utilities
54 | - ✅ Achieved 60% reduction in duplicate code patterns
55 | - ✅ Validated all scripts work correctly with pattern utilities
56 |
57 | ### 4. Configuration Management ✅ **COMPLETED**
58 | **Status:** ✅ **COMPLETED** - See [configuration-management-enhancement-summary.md](./configuration-management-enhancement-summary.md)
59 |
60 | **Original Issues:**
61 | - Hard-coded paths and magic values still exist in some places
62 | - Configuration loading patterns could be standardized
63 |
64 | **Files Affected:**
65 | - `input-handler.mjs` - Basic config loader could be enhanced
66 | - Various scripts with path construction
67 |
68 | **Solution Implemented:**
69 | - ✅ Created `configuration-management.mjs` with comprehensive configuration system
70 | - ✅ Added `ConfigurationManager` class with schema validation and search paths
71 | - ✅ Implemented `PathResolver` class for intelligent path resolution
72 | - ✅ Created `ConfigValidator` class for schema-based validation
73 | - ✅ Defined configuration schemas for components, extensions, and generator
74 | - ✅ Updated all scripts to use enhanced configuration management
75 | - ✅ Added environment variable override support
76 | - ✅ Maintained full backward compatibility with existing configuration files
77 | - ✅ Achieved comprehensive error handling and validation
78 |
79 | ### 5. Function Decomposition
80 | **Current Issues:**
81 | - Some functions are too long and do multiple things
82 | - Complex nested logic in theme file generation
83 |
84 | **Files Affected:**
85 | - `create-theme-files.mjs` - Main logic could be broken down
86 | - `MetadataProcessor.mjs` - Some methods are quite long
87 |
88 | **Recommended Solution:**
89 | - Break down large functions into smaller, focused functions
90 | - Improve separation of concerns
91 |
92 | ## Medium-Priority Opportunities
93 |
94 | ### 6. Async/Await Consistency
95 | - Some scripts mix Promise patterns
96 | - Could standardize on async/await throughout
97 |
98 | ### 7. Input Validation
99 | - Add parameter validation to utility functions
100 | - Validate configuration file contents more thoroughly
101 |
102 | ### 8. Type Safety (if TypeScript adoption is considered)
103 | - Consider migrating to TypeScript for better type safety
104 | - Add JSDoc types as an interim solution
105 |
106 | ## Low-Priority Opportunities
107 |
108 | ### 9. Performance Optimizations
109 | - Parallel processing where appropriate
110 | - Caching for repeated operations
111 |
112 | ### 10. Testing Infrastructure
113 | - Add unit tests for utility functions
114 | - Integration tests for the full pipeline
115 |
116 | ## Implementation Priority
117 |
118 | 1. **Immediate (High Impact, Low Risk):**
119 | - ✅ **COMPLETED:** Logging consistency fixes
120 | - ✅ **COMPLETED:** Basic error handling improvements
121 |
122 | 2. **Short Term (High Impact, Medium Risk):**
123 | - ✅ **COMPLETED:** Duplicate pattern extraction
124 | - Function decomposition
125 |
126 | 3. **Medium Term (Medium Impact, Medium Risk):**
127 | - ✅ **COMPLETED:** Configuration management enhancements
128 | - Input validation improvements
129 |
130 | 4. **Long Term (High Impact, High Risk):**
131 | - Type safety improvements
132 | - Testing infrastructure
133 |
134 | ## Completed Refactoring Summary
135 |
136 | ### ✅ **Phase 1 Complete: Core Infrastructure**
137 | - **Error Handling Standardization** - `error-handling.mjs` created and integrated
138 | - **Logging Consistency** - `logging-standards.mjs` with scoped loggers implemented
139 | - **Magic String Extraction** - `constants.mjs` centralized configuration
140 | - **Duplicate Pattern Extraction** - `pattern-utilities.mjs` with reusable utilities
141 | - **Configuration Management Enhancement** - `configuration-management.mjs` with schema validation and path resolution
142 |
143 | ### 🔄 **Phase 2 In Progress: Advanced Improvements**
144 | - Function decomposition (next priority)
145 | - Input validation improvements
146 |
147 | ## Success Metrics
148 |
149 | - Reduced code duplication
150 | - Consistent error handling across all scripts
151 | - Improved maintainability and readability
152 | - No regression in functionality
153 | - Better logging and debugging capabilities
154 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Toggle/Toggle.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { type ReactNode } from "react";
2 | import { useMemo } from "react";
3 | import React, {
4 | type CSSProperties,
5 | type ForwardedRef,
6 | forwardRef,
7 | useCallback,
8 | useEffect,
9 | } from "react";
10 | import classnames from "classnames";
11 |
12 | import styles from "./Toggle.module.scss";
13 |
14 | import type { RegisterComponentApiFn, UpdateStateFn } from "../../abstractions/RendererDefs";
15 | import { noop } from "../../components-core/constants";
16 | import { useEvent } from "../../components-core/utils/misc";
17 | import type { ValidationStatus } from "../abstractions";
18 | import { PART_INPUT } from "../../components-core/parts";
19 | import { composeRefs } from "@radix-ui/react-compose-refs";
20 |
21 |
22 | type ToggleProps = {
23 | id?: string;
24 | initialValue?: boolean;
25 | value?: boolean;
26 | enabled?: boolean;
27 | style?: CSSProperties;
28 | readOnly?: boolean;
29 | validationStatus?: ValidationStatus;
30 | updateState?: UpdateStateFn;
31 | onClick?: (event: React.MouseEvent) => void;
32 | onDidChange?: (newValue: boolean) => void;
33 | onFocus?: () => void;
34 | onBlur?: () => void;
35 | variant?: "checkbox" | "switch";
36 | indeterminate?: boolean;
37 | className?: string;
38 | required?: boolean;
39 | autoFocus?: boolean;
40 | registerComponentApi?: RegisterComponentApiFn;
41 | inputRenderer?: (contextVars: any, input?: ReactNode) => ReactNode;
42 | forceHover?: boolean;
43 | };
44 |
45 | export const defaultProps: Pick<
46 | ToggleProps,
47 | "initialValue" | "value" | "enabled" | "validationStatus" | "indeterminate"
48 | > = {
49 | initialValue: false,
50 | value: false,
51 | enabled: true,
52 | validationStatus: "none",
53 | indeterminate: false,
54 | };
55 |
56 | export const Toggle = forwardRef(function Toggle(
57 | {
58 | id,
59 | initialValue = defaultProps.initialValue,
60 | value = defaultProps.value,
61 | enabled = defaultProps.enabled,
62 | style,
63 | readOnly,
64 | validationStatus = defaultProps.validationStatus,
65 | updateState = noop,
66 | onClick = noop,
67 | onDidChange = noop,
68 | onFocus = noop,
69 | onBlur = noop,
70 | variant = "checkbox",
71 | indeterminate = defaultProps.indeterminate,
72 | className,
73 | required,
74 | autoFocus,
75 | registerComponentApi,
76 | inputRenderer,
77 | forceHover = false,
78 | ...rest
79 | }: ToggleProps,
80 | forwardedRef: ForwardedRef<HTMLInputElement>,
81 | ) {
82 | const innerRef = React.useRef<HTMLInputElement | null>(null);
83 | const ref = innerRef ? composeRefs(forwardedRef, innerRef) : forwardedRef;
84 |
85 | const transformToLegitValue = (inp: any): boolean => {
86 | if (typeof inp === "undefined" || inp === null) {
87 | return false;
88 | }
89 | if (typeof inp === "boolean") {
90 | return inp;
91 | }
92 | if (typeof inp === "number") {
93 | return !isNaN(inp) && !!inp;
94 | }
95 | if (typeof inp === "string") {
96 | return inp.trim() !== "" && inp.toLowerCase() !== "false";
97 | }
98 | if (Array.isArray(inp)) {
99 | return inp.length > 0;
100 | }
101 | if (typeof inp === "object") {
102 | return Object.keys(inp).length > 0;
103 | }
104 | return false;
105 | };
106 |
107 | useEffect(() => {
108 | updateState({ value: transformToLegitValue(initialValue) }, { initial: true });
109 | }, [initialValue, updateState]);
110 |
111 | const updateValue = useCallback(
112 | (value: boolean) => {
113 | if (innerRef.current?.checked === value) return;
114 | updateState({ value });
115 | onDidChange(value);
116 | },
117 | [onDidChange, updateState],
118 | );
119 |
120 | const onInputChange = useCallback(
121 | (event: React.ChangeEvent<HTMLInputElement>) => {
122 | if (readOnly) {
123 | return;
124 | }
125 | updateState({ value: event.target.checked });
126 | onDidChange(event.target.checked);
127 | },
128 | [onDidChange, readOnly, updateState],
129 | );
130 |
131 | const handleOnFocus = useCallback(() => {
132 | onFocus?.();
133 | }, [onFocus]);
134 |
135 | const handleOnBlur = useCallback(() => {
136 | onBlur?.();
137 | }, [onBlur]);
138 |
139 | useEffect(() => {
140 | if (typeof indeterminate === "boolean" && innerRef.current) {
141 | innerRef.current.indeterminate = indeterminate;
142 | }
143 | }, [indeterminate]);
144 |
145 | const focus = useCallback(() => {
146 | innerRef.current?.focus();
147 | }, []);
148 |
149 | useEffect(() => {
150 | if (innerRef.current && autoFocus) {
151 | setTimeout(() => focus(), 0);
152 | }
153 | }, [focus, autoFocus]);
154 |
155 | const setValue = useEvent((newValue) => {
156 | updateValue(transformToLegitValue(newValue));
157 | });
158 |
159 | useEffect(() => {
160 | registerComponentApi?.({
161 | focus,
162 | setValue,
163 | });
164 | }, [focus, registerComponentApi, setValue]);
165 |
166 | const input = useMemo(() => {
167 | const legitValue = transformToLegitValue(value);
168 | return (
169 | <input
170 | {...rest}
171 | id={id}
172 | data-part-id={PART_INPUT}
173 | ref={ref}
174 | type="checkbox"
175 | role={variant}
176 | checked={legitValue}
177 | disabled={!enabled}
178 | required={required}
179 | readOnly={readOnly}
180 | aria-readonly={readOnly}
181 | aria-checked={indeterminate ? "mixed" : legitValue}
182 | aria-required={required}
183 | aria-disabled={!enabled}
184 | onClick={onClick}
185 | onChange={onInputChange}
186 | onFocus={handleOnFocus}
187 | onBlur={handleOnBlur}
188 | autoFocus={autoFocus}
189 | style={style}
190 | className={classnames(className, styles.resetAppearance, {
191 | [styles.checkbox]: variant === "checkbox",
192 | [styles.switch]: variant === "switch",
193 | [styles.error]: validationStatus === "error",
194 | [styles.warning]: validationStatus === "warning",
195 | [styles.valid]: validationStatus === "valid",
196 | [styles.forceHover]: forceHover,
197 | })}
198 | />
199 | );
200 | }, [
201 | rest,
202 | className,
203 | ref,
204 | style,
205 | id,
206 | enabled,
207 | handleOnBlur,
208 | handleOnFocus,
209 | onInputChange,
210 | onClick,
211 | readOnly,
212 | required,
213 | validationStatus,
214 | value,
215 | variant,
216 | indeterminate,
217 | autoFocus,
218 | forceHover,
219 | ]);
220 |
221 | return (
222 | inputRenderer ? (
223 | <label className={styles.label}>
224 | <div className={styles.inputContainer}>{input}</div>
225 | {inputRenderer({
226 | $checked: transformToLegitValue(value),
227 | $setChecked: setValue,
228 | })}
229 | </label>
230 | ) : (
231 | input
232 | )
233 | );
234 | });
235 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/DateInput/DateInput.md:
--------------------------------------------------------------------------------
```markdown
1 | %-DESC-START
2 |
3 | **Key features:**
4 | - **Date format support**: Multiple date formats including MM/dd/yyyy, yyyy-MM-dd, and dd/MM/yyyy
5 | - **Direct input**: Keyboard-only date entry with input fields for day, month, and year
6 | - **Input validation**: Real-time validation with visual feedback for invalid dates
7 | - **Range support**: Single date selection (default) or date range selection
8 | - **Accessibility**: Full keyboard navigation and screen reader support
9 |
10 | %-DESC-END
11 |
12 | %-API-START setValue
13 |
14 | ```xmlui-pg copy {3, 9, 12} display name="Example: setValue"
15 | <App>
16 | <HStack>
17 | <Button
18 | label="Set Date to 05/25/2024"
19 | onClick="picker.setValue('05/25/2024')" />
20 | <Button
21 | label="Clear Date"
22 | onClick="picker.setValue('')" />
23 | </HStack>
24 | <DateInput id="picker" />
25 | </App>
26 | ```
27 |
28 | %-API-END
29 |
30 | %-PROP-START initialValue
31 |
32 | ```xmlui-pg copy display name="Example: initialValue" height="120px"
33 | <App>
34 | <DateInput initialValue="05/25/2024" />
35 | </App>
36 | ```
37 |
38 | %-PROP-END
39 |
40 | %-PROP-START enabled
41 |
42 | ```xmlui-pg copy display name="Example: enabled" height="120px"
43 | <App>
44 | <DateInput enabled="false" initialValue="05/25/2024" />
45 | </App>
46 | ```
47 |
48 | %-PROP-END
49 |
50 | %-PROP-START validationStatus
51 |
52 | | Value | Description |
53 | | :-------- | :---------------------------------------------------- |
54 | | `valid` | Visual indicator for an input that is accepted |
55 | | `warning` | Visual indicator for an input that produced a warning |
56 | | `error` | Visual indicator for an input that produced an error |
57 |
58 | ```xmlui-pg copy display name="Example: validationStatus"
59 | <App>
60 | <DateInput validationStatus="valid" initialValue="05/25/2024" />
61 | <DateInput validationStatus="warning" initialValue="05/25/2024" />
62 | <DateInput validationStatus="error" initialValue="05/25/2024" />
63 | </App>
64 | ```
65 |
66 | %-PROP-END
67 |
68 | %-PROP-START dateFormat
69 |
70 | The `dateFormat` prop controls how dates are displayed and entered. Different formats change the order and separators of day, month, and year fields.
71 |
72 | > [!NOTE] Regardless of the dateFormat, the year input field always accepts and displays 4-digit years. When entering a 2-digit year, it will be automatically normalized to a 4-digit year.
73 |
74 | | Format | Description | Example |
75 | | :----- | :---------- | :------ |
76 | | `MM/dd/yyyy` | US format with slashes | 05/25/2024 |
77 | | `MM-dd-yyyy` | US format with dashes | 05-25-2024 |
78 | | `yyyy/MM/dd` | ISO-like format with slashes | 2024/05/25 |
79 | | `yyyy-MM-dd` | ISO format with dashes | 2024-05-25 |
80 | | `dd/MM/yyyy` | European format with slashes | 25/05/2024 |
81 | | `dd-MM-yyyy` | European format with dashes | 25-05-2024 |
82 | | `yyyyMMdd` | Compact format without separators | 20240525 |
83 | | `MMddyyyy` | US compact format | 05252024 |
84 |
85 | ```xmlui-pg copy display name="Example: dateFormat"
86 | <App>
87 | <DateInput dateFormat="MM/dd/yyyy" initialValue="05/25/2024" />
88 | <DateInput dateFormat="yyyy-MM-dd" initialValue="2024-05-25" />
89 | <DateInput dateFormat="dd/MM/yyyy" initialValue="25/05/2024" />
90 | <DateInput dateFormat="yyyyMMdd" initialValue="20240525" />
91 | </App>
92 | ```
93 |
94 | %-PROP-END
95 |
96 | %-PROP-START clearable
97 |
98 | When enabled, it displays a clear button that allows users to reset the date input back to its initial value. Enter a date in this app and then click the clear button:
99 |
100 | ```xmlui-pg copy display name="Example: clearable" /clearable/
101 | <App>
102 | <DateInput initialValue="05/25/2024" />
103 | <DateInput clearable="true" initialValue="05/25/2024" />
104 | </App>
105 | ```
106 |
107 | %-PROP-END
108 |
109 | %-PROP-START clearIcon
110 |
111 | ```xmlui-pg copy display name="Example: clearIcon" /clearIcon/
112 | <App>
113 | <DateInput initialValue="05/25/2024" clearable="true" clearIcon="trash" />
114 | </App>
115 | ```
116 |
117 | %-PROP-END
118 |
119 | %-PROP-START clearToInitialValue
120 |
121 | When `true`, the clear button resets the input to its initial value. When `false`, it clears the input completely.
122 |
123 | ```xmlui-pg copy display name="Example: clearToInitialValue"
124 | <App>
125 | <DateInput clearable="true" clearToInitialValue="true" initialValue="05/25/2024" />
126 | <DateInput clearable="true" clearToInitialValue="false" initialValue="05/25/2024" />
127 | </App>
128 | ```
129 |
130 | %-PROP-END
131 |
132 | %-PROP-START mode
133 |
134 | Available values:
135 |
136 | | Value | Description |
137 | | --- | --- |
138 | | `single` | Single date selection **(default)** |
139 | | `range` | Date range selection |
140 |
141 | %-PROP-END
142 |
143 | %-PROP-START required
144 |
145 | Marks the date input as required for form validation.
146 |
147 | ```xmlui-pg copy display name="Example: required" height="120px"
148 | <App>
149 | <DateInput required="true" />
150 | </App>
151 | ```
152 |
153 | %-PROP-END
154 |
155 | %-PROP-START readOnly
156 |
157 | Makes the date input read-only. Users can see the value but cannot modify it.
158 |
159 | ```xmlui-pg copy display name="Example: readOnly" height="120px"
160 | <App>
161 | <DateInput readOnly="true" initialValue="05/25/2024" />
162 | </App>
163 | ```
164 |
165 | %-PROP-END
166 |
167 | %-PROP-START emptyCharacter
168 |
169 | Character to use as placeholder for empty date values. If longer than 1 character, uses the first character. Defaults to '-'.
170 |
171 | ```xmlui-pg copy display name="Example: emptyCharacter"
172 | <App>
173 | <DateInput emptyCharacter="." />
174 | <DateInput emptyCharacter="*" />
175 | <DateInput emptyCharacter="abc" />
176 | </App>
177 | ```
178 |
179 | %-PROP-END
180 |
181 | %-EVENT-START didChange
182 |
183 | Fired when the date value changes. Receives the new date value as a parameter.
184 |
185 | > [!INFO] The date value changes when the edited input part (day, month, year) loses focus and contains a valid value.
186 |
187 | ```xmlui-pg copy {2} display name="Example: didChange" height="180px"
188 | <App var.selectedDate="No date selected">
189 | <Text value="{selectedDate}" />
190 | <DateInput
191 | dateFormat="yyyy-MM-dd"
192 | initialValue="2024-05-25"
193 | onDidChange="(date) => selectedDate = date" />
194 | </App>
195 | ```
196 |
197 | %-EVENT-END
198 |
199 | %-EVENT-START gotFocus
200 |
201 | Fired when the date input receives focus.
202 |
203 | ```xmlui-pg copy {4-5} display name="Example: gotFocus/lostFocus"
204 | <App var.isFocused="{false}">
205 | <Text value="{isFocused
206 | ? 'DateInput focused' : 'DateInput lost focus'}"
207 | />
208 | <DateInput
209 | dateFormat="MM/dd/yyyy"
210 | onGotFocus="isFocused = true"
211 | onLostFocus="isFocused = false"
212 | initialValue="05/25/2024"
213 | />
214 | </App>
215 | ```
216 |
217 | %-EVENT-END
218 |
```
--------------------------------------------------------------------------------
/blog/public/blog/xmlui-playground.md:
--------------------------------------------------------------------------------
```markdown
1 | The XMLUI [docs](https://docs.xmlui.org) are full of live working examples that use [Playground](https://github.com/xmlui-org/xmlui/tree/main/packages/xmlui-playground), an extension package that runs XMLUI code inside an XMLUI app. We use playgrounds to bring component documentation to life. Why just tell you about the `enabled` property of a [Checkbox](https://docs.xmlui.org/components/Checkbox) when we can also show you, as in this live example.
2 |
3 | <blockquote>
4 | enabled (default: true)
5 |
6 | This boolean property value indicates whether the component responds to user events (true) or not (false).
7 |
8 | ```xmlui-pg {4-6} {9-10} name="Click the checkboxes"
9 | <App>
10 | Enabled checkboxes:
11 | <HStack>
12 | <Checkbox initialValue="true" enabled="true" />
13 | <Checkbox initialValue="false" enabled="true" />
14 | </HStack>
15 | Disabled checkboxes:
16 | <HStack>
17 | <Checkbox initialValue="true" enabled="false" />
18 | <Checkbox initilaValue="false" enabled="false" />
19 | </HStack>
20 | </App>
21 | ```
22 | </blockquote>
23 |
24 | This widget doesn't just display the live app, it also enables you to modify it by clicking the  icon. Try it now! You'll land in [a hosted playground](https://playground.xmlui.org/#/playground/#H4sIAAAAAAAAE61W204bMRD9ldWUx2zJhRBYpZXCTVQCVBUKlQoPk%2FUkseK1LduBBZR%2Fr%2BzdJtmw4SLxlsycmTmeOfbsM1iHkqFQkiB5BtQaEugPtP5%2BK6PoWOJQEIvSCaXTocrJJt7cP710mE4DJIr6h6U34pI7juIaxYy%2B3YIzM7qFiIokS8P2W4EjFPaVyP72Sv0jbj%2BV4%2F%2FaG0gK3EyyGrrCsr9dNBQakKpMK0nSWUj%2B3vn%2FcsTHvvVuQhl56zNIzAgS%2BHN%2B9vtHdCDUOLryTmgAZ5DAUKhx7EoL5Y4k83GQZ2LG4a5RpLpGY33eIabTsVEzyQ6VUAYS2Er9j9jOzAhTipuBlrdowzM0j5DAl05nt3d4uPCUWO9pUbvX2YHGeuI4VdKRdPEgaKimSIb5DWduUiJanXZT56v2aoa9ncI9VPnlBJl6iCXe%2F0RJogRIL9qXPC5K1EsS3WYNfC1pXYhGxrgcX5NxPEVRqWB1gAWehpH5xccTVxxnBdaqHvTI4AP5UXSaxRkd5W7B%2FozL6QoTSpVkaB7j3eZyVFwynqJbBsQxpo7f%2BxE5g9JqNCTda%2FiJug8c3gnXhqwl9iKgpv3V%2FGsdbTXrplBTpjZupKS7Id%2FjmoMPlWB1zdzIZT%2FkrMEvUm5Vbkbc3RQQCrwV58lf8ieKT1teE193u4ay6qGCp1e0qNATMj6z8anLxJV%2FaIJogmaEDwgvx4LOkUpnGUnnOVl%2FWbsHuzu9boVyBbPszJfWQbvTHtSMxpJGE7TwIj21qUsI8wYwNNOa1%2Bb1R6FWCh9QzCdf86Lh8QVZR6x8o3QeWSU4i9YC2rWcwpQmhDXy7TY3T8G3cu94vzfYe9ekTvZPBicHH5tUZ2%2Bn1z2G%2BbwBhqyamdTvmuf5%2FM6blHZcybAuRjwnVqybJCy0BtgH1NpfyfK%2FNnTP6eFcsSVGGU7SoU8DCUyU4U9KOhTQgOJOlCmry6t0hY%2BPUs9hJXrJQBK%2BRubzfwm13uekCAAA) where you can edit the XMLUI code and see changes instantly.
25 |
26 | Playgrounds work with the [Markdown](https://docs.xmlui.org/components/Markdown) component which is the renderer for this page. Here's the XMLUI source for the checkboxes example.
27 |
28 | 
29 |
30 | We show it here as an image because if we were to include the text it would just render as above!
31 |
32 | It starts as conventional Markdown codefence bounded by triple backtics. You can use the language identifier `xmlui` for XMLUI syntax highlighting, or (as here) use `xmlui-pg` to introduce a live playground. The bracketed numbers specify line ranges to highlight.
33 |
34 | ## Playgrounds on steroids
35 |
36 | Many of these small playgrounds are woven into the component docs. You'll also find more ambitious playgrounds in the How To section of the docs where we illustrate important app patterns, like <a target="_blank" href="https://docs.xmlui.org/howto/use-the-same-modaldialog-to-add-or-edit">How to use the same ModalDialog to add or edit</a>.
37 |
38 | If you [view the XMLUI source](https://github.com/xmlui-org/xmlui/blob/main/docs/public/pages/howto/use-the-same-modaldialog-to-add-or-edit.md) for that example, you'll see that the codefence defines an `App` and two user-defined components, `Test` and `ProductModal`. It also defines an API with operations `get-products`, `get-product`, `insert-product`, `update-product`, and `delete-product`.
39 |
40 | This is a concise way to express the rich set of behaviors seen in this video.
41 |
42 | 
43 |
44 | ## Share a working reproduction of a bug
45 |
46 | Open source developers who respond to bug reports always hope for, but rarely get, reliable ways to reproduce the bad behavior they are seeing. Now those reports can contain XMLUI codefences that exhibit the behavior.
47 |
48 | If you want to make such a report, you can visit [xmlui-codefence-runner.netlify.app](https://xmlui-codefence-runner.netlify.app/), paste in your codefence, open it into a playground, and share its URL. That's the gold standard for this kind of thing, and it's implemented for that site with a dozen lines of XMLUI dropped onto Netlify.
49 |
50 | 
51 |
52 |
53 | If you find yourself [filing an issue](https://github.com/xmlui-org/xmlui/issues) that needs a solid reproduction, please give it a try.
54 |
55 | ## Help your AI assistants stay grounded
56 |
57 | When you use the [XMLUI MCP server](https://github.com/xmlui-org/xmlui-mcp) with coding assistants like Claude or Copilot, they will prefer How To examples when available.
58 |
59 | 
60 |
61 | That's the gold standard response: a link to a known working pattern that proves its existence by running live. And because XMLUI is concise, the pattern doesn't occupy too much space in an AI's context window.
62 |
63 | When you ask a question for which an assistant cannot provide such a link, we tell it to admit that and refuse to invent undocumented syntax. They won't always comply but with a running playground that embodies ground truth you can often steer them away from rabbit holes. The more working patterns contributed to the project, the stronger that effect will be.
64 |
65 | ## Reproducible XMLUI
66 |
67 | The common theme here is reproducibility. Whether it lives in a component doc, a How To, or a GitHub issue, an XMLUI codefence captures a piece of XMLUI behavior that you can replay consistently. That's useful for the XMLUI project itself but also for apps you build with XMLUI. Playgrounds that we can reliably reproduce and exchange make everything easier to build, document, debug, and maintain.
68 |
69 |
70 |
71 |
72 |
```
--------------------------------------------------------------------------------
/docs/public/pages/markup.md:
--------------------------------------------------------------------------------
```markdown
1 | # XML Markup
2 |
3 | When you write XML markup to create an XMLUI app, you use XML tags to name components. And you use XML attributes to set properties that govern their behavior.
4 |
5 | ## Properties
6 |
7 | An attribute may be a literal string that sets the value of a property.
8 |
9 | ```xmlui-pg name="A literal property" copy display
10 | <Text value="This is rendered as text." />
11 | ```
12 |
13 | ## Expressions
14 |
15 | An attribute may also be a JavaScript expression — enclosed in curly braces `{ }` — that dynamically sets the value of a property.
16 |
17 | ```xmlui-pg copy name="A dynamic property" display
18 | <Text value="Life, the universe, and everything: { 6 * 7 }" />
19 | ```
20 |
21 | An expression can hold a JSON list.
22 |
23 | ```xmlui-pg copy name="A JSON list" display /['Bakerloo', 'Central', 'Circle']/
24 | <Items data="{ ['Bakerloo', 'Central', 'Circle'] }" >
25 | <Text>{ $item }</Text>
26 | </Items>
27 | ```
28 |
29 | Or a complex JSON object, in which case you'll write an outer set of curly braces to introduce the expression and an inner set to define an object like this form's `data` property.
30 |
31 | ```xmlui-pg copy name="A complex JSON object" display /{ station: "Brixton", wifi: true, toilets: false }/
32 | <App>
33 | <Form id="searchForm" padding="0.5rem"
34 | data='{ { station: "Brixton", wifi: true, toilets: false } }'
35 | onSubmit="() => { preview.setValue(JSON.stringify($data)) }"
36 | >
37 | <Text>Search for station amenities</Text>
38 | <HStack verticalAlignment="center" >
39 | <FormItem bindTo="station" />
40 | <FormItem
41 | type="checkbox"
42 | label="wifi"
43 | bindTo="wifi"
44 | labelPosition="start"
45 | />
46 | <FormItem
47 | type="checkbox"
48 | label="toilets"
49 | bindTo="toilets"
50 | labelPosition="start"
51 | />
52 | </HStack>
53 | <property name="buttonRowTemplate">
54 | <Button type="submit" icon="search" label="Search"/>
55 | </property>
56 | </Form>
57 |
58 | <TextArea id="preview" />
59 | </App>
60 | ```
61 |
62 | > [!INFO]
63 | > In addition to a literal string or an expression, you will sometimes use the special tag `<property>` to set a value using markup, like the `ButtonRowTemplate` that defines this form's button.
64 |
65 | ## Variables
66 |
67 | A component may declare a variable that's visible to itself and its children. Variable names start with a letter or an underscore (`_`) and continue with these characters or digits.
68 |
69 | You can declare a variable using the `var` prefix.
70 |
71 | ```xmlui-pg copy name="Declaring a variable with var" display
72 | <App var.stations="{ [ 'Bakerloo', 'Central', 'Circle'] }">
73 | <Items data="{stations}">
74 | <Text> {$item} </Text>
75 | </Items>
76 | </App>
77 | ```
78 |
79 | Or using the `<variable>` helper tag.
80 |
81 | ```xmlui-pg copy name="Declaring a variable with <variable>" display
82 | <App>
83 | <variable
84 | name="stations"
85 | value="{ [ 'Bakerloo', 'Central', 'Circle'] }" />
86 | <Items data="{stations}">
87 | <Text>{$item}</Text>
88 | </Items>
89 | </App>
90 | ```
91 |
92 | ### Nested variables
93 |
94 | The same variable name can be declared in nested scopes. The engine resolves the name to the variable in the closest (innermost) scope.
95 |
96 | ```xmlui-pg copy name="Defining and using nested variables" display
97 | <App var.title="var.title is 'Hello, from App!'">
98 | <H1>{title}</H1>
99 | <VStack var.title="var.title is 'Hello, from VStack'!">
100 | <Text>{title}</Text>
101 | </VStack>
102 | </App>
103 | ```
104 |
105 | ### Multiple instances
106 |
107 | <Text>Each counter is a separate instance of `CounterTest` with its own local component variables.</Text>
108 |
109 | ```xmlui-pg name="Isolated component instances"
110 | ---app display
111 | <App>
112 | <HStack horizontalAlignment="center">
113 | <VStack>
114 | <Text variant="caption">Counter Instance 1</Text>
115 | <CounterTest instance="1" />
116 | </VStack>
117 | <Stack width="10rem"/>
118 | <VStack>
119 | <Text variant="caption">Counter Instance 2</Text>
120 | <CounterTest instance="2" />
121 | </VStack>
122 | </HStack>
123 | </App>
124 | ---comp display
125 | <Component name="CounterTest" var.count="{0}">
126 | <Text>Counter ID: {$props.instance}</Text>
127 | <Text>Count: {count}</Text>
128 | <Button onClick="count = count + 1">
129 | Increment {$props.id}
130 | </Button>
131 | </Component>
132 | ```
133 |
134 | ### Reactive variables
135 |
136 | In [Reactive data binding](/reactive-intro) we saw how a `Select` can cause a `Table` to refresh by setting the `url` property of the `DataSource` on which the `Table` depends. Here's a more basic example of how components interact with reactive variables.
137 |
138 | ```xmlui-pg copy name="Defining and using reactive variables" display
139 | <App var.count="{0}" var.countTimes3="{3 * count}" >
140 | <Button
141 | label="Click to increment the count"
142 | onClick="count++" />
143 | <Text>Click count = {count} (changes directly)</Text>
144 | <Text>Click count * 3 = {countTimes3} (changes indirectly)</Text>
145 | </App>
146 | ```
147 |
148 | The `Button`'s click handler increments `count` directly. But because `countTimes3` is define using an expression that refers to `count`, the engine reevalautes that expression each time `count` changes and updates `countTimes3` indirectly.
149 |
150 | We've seen two ways to declare variables: a `var` declaration in an XML attribute, or the `variable` tag. A similar pattern applies to event handlers. The `Button` to increment the count declares its handler in an attribute whose name combines the `on` prefix with the name [click](/components/Button#click). You may also use the `<event>` helper tag with no prefix for the event name.
151 |
152 | ```xmlui-pg copy name="Declare an event handler using the <event> tag" display
153 | <App var.count="{0}" >
154 | <Button label="Click me! Click count = {count}">
155 | <event name="click">
156 | { count++ }
157 | </event>
158 | </Button>
159 | </App>
160 | ```
161 |
162 | > [!INFO]
163 | > Why use the `<event>` tag? In this example there's no reason to prefer it. But as we saw above, you declare a `Form`'s `buttonRowTemplate` property in XMLUI markup using the `<property>` helper tag. The same pattern applies when a button's handler is an XMLUI component like `<APICall>`.
164 | > ```xmlui copy
165 | > <Button label="Click to increment the count on the server">
166 | > <event name="click">
167 | > <APICall url="/count/increment" />
168 | > </event>
169 | > <Text>Click count = {count}</Text>
170 | > </Button>
171 | > ```
172 |
```
--------------------------------------------------------------------------------
/xmlui/src/components-core/theming/StyleContext.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import type { CSSProperties } from "react";
2 | import type React from "react";
3 | import { createContext, useContext, useEffect, useInsertionEffect, useMemo, useState } from "react";
4 | import type { StyleObjectType } from "./StyleRegistry";
5 | import { StyleRegistry } from "./StyleRegistry";
6 | import { EMPTY_OBJECT } from "../constants";
7 | import { useIndexerContext } from "../../components/App/IndexerContext";
8 |
9 | // The context is typed to hold either a StyleRegistry instance or null.
10 | const StyleContext = createContext<StyleRegistry | null>(null);
11 |
12 | type StyleProviderProps = {
13 | children: React.ReactNode;
14 | styleRegistry?: StyleRegistry;
15 | forceNew?: boolean; // Optional prop to force a new registry
16 | };
17 |
18 | /**
19 | * A "smart" provider that creates a StyleRegistry only if one doesn't
20 | * already exist in the context.
21 | */
22 | export function StyleProvider({
23 | children,
24 | styleRegistry = new StyleRegistry(),
25 | forceNew = false, // Optional prop to force a new registry
26 | }: StyleProviderProps) {
27 | // Check if a provider already exists above this one in the tree.
28 | const parentRegistry = useContext(StyleContext);
29 | // If we are the top-most provider, create a new registry for this tree.
30 | // On the client, this runs once. On the server, it runs once per request
31 | // IF this provider is at the root of the tree being rendered.
32 | // Use useState to create the registry instance.
33 | const [registry] = useState(() => {
34 | const newRegistry = styleRegistry;
35 |
36 | // This logic only runs on the CLIENT, once, when the registry is created.
37 | if (typeof window !== "undefined") {
38 | // 1. Find the style tag injected by the server.
39 | const ssrTag = document.querySelector('style[data-style-registry="true"]');
40 | // 2. Read the hashes from our custom data attribute.
41 | const ssrHashes = ssrTag?.getAttribute("data-ssr-hashes");
42 |
43 | if (ssrHashes) {
44 | // 3. Pre-populate the 'injected' set with all the server-rendered hashes.
45 | let hashes = ssrHashes.split(",");
46 | newRegistry.ssrHashes = new Set(hashes);
47 | newRegistry.injected = new Set(hashes);
48 | }
49 | }
50 |
51 | return newRegistry;
52 | });
53 |
54 | // If we're already inside a provider, don't do anything. Just render the children.
55 | // This makes nesting StyleProviders safe and harmless.
56 | if (parentRegistry && !forceNew) {
57 | return <>{children}</>;
58 | }
59 |
60 | return <StyleContext.Provider value={registry}>{children}</StyleContext.Provider>;
61 | }
62 |
63 | export function useStyleRegistry(): StyleRegistry {
64 | const registry = useContext(StyleContext);
65 | if (registry === null) {
66 | throw new Error("Component must be used within a StyleProvider");
67 | }
68 | return registry;
69 | }
70 |
71 | export function useComponentStyle(styles?: Record<string, CSSProperties[keyof CSSProperties]>) {
72 | const rootStyle = useMemo(() => {
73 | return (!styles || Object.keys(styles).length === 0)
74 | ? EMPTY_OBJECT
75 | : {
76 | "&": styles,
77 | // "@container style(--screenSize: 1) or @container style(--screenSize: 2) ... etc": responsiveSizes,
78 | };
79 | }, [styles]);
80 |
81 | return useStyles(rootStyle);
82 | }
83 |
84 | export const StyleInjectionTargetContext = createContext<Document | ShadowRoot | null>(null);
85 |
86 | export function useDomRoot(){
87 | const domRoot = useContext(StyleInjectionTargetContext);
88 | return domRoot;
89 | }
90 |
91 | type InjectOptions = {
92 | prepend?: boolean;
93 | }
94 | export function useStyles(styles: StyleObjectType, {prepend}: InjectOptions = EMPTY_OBJECT ): string {
95 | // we skip this whole thing if we're indexing
96 | const {indexing} = useIndexerContext();
97 | const domRoot = useDomRoot();
98 | const injectionTarget = typeof document === "undefined" ? null : domRoot instanceof ShadowRoot ? domRoot : document.head
99 | const registry = useStyleRegistry();
100 | const { className, styleHash } = useMemo(() => {
101 | if(indexing || !styles || styles === EMPTY_OBJECT || Object.keys(styles).length === 0) {
102 | return { className: undefined, styleHash: undefined };
103 | }
104 | return registry.register(styles);
105 | }, [indexing, registry, styles]);
106 |
107 | useInsertionEffect(() => {
108 | if (!styleHash || registry.injected.has(styleHash)) {
109 | return;
110 | }
111 |
112 | const { css } = registry.cache.get(styleHash) || {};
113 | if (css) {
114 | const styleElement = document.createElement("style");
115 | styleElement.setAttribute("data-style-hash", styleHash);
116 | styleElement.innerHTML = `@layer dynamic {\n${css}\n}`;
117 | if(prepend){
118 | injectionTarget.insertBefore(styleElement, injectionTarget.firstChild.nextSibling);
119 | } else {
120 | injectionTarget.appendChild(styleElement);
121 | }
122 |
123 | registry.injected.add(styleHash);
124 | }
125 | }, [registry, styleHash, injectionTarget]);
126 |
127 | // HOOK 2: For lifecycle management (reference counting and CLEANUP).
128 | useEffect(() => {
129 | if(!styleHash){
130 | return;
131 | }
132 | // On MOUNT, tell the registry that this component is using this style.
133 | registry.incrementRef(styleHash);
134 |
135 | // Return a cleanup function to run on UNMOUNT.
136 | return () => {
137 | registry.decrementRef(styleHash);
138 |
139 | // Schedule the cleanup check to run asynchronously.
140 | // This allows React's Strict Mode double-render to complete before
141 | // we check if the style tag should be removed.
142 | setTimeout(() => {
143 | // Only proceed with cleanup if...
144 | // 1. No other component is using this style (ref count is 0).
145 | // 2. This style was NOT part of the initial server render.
146 | if (registry.getRefCount(styleHash) === 0 && !registry.ssrHashes.has(styleHash)) {
147 | // If it's still zero, it means no component re-mounted to claim this style.
148 | // Now it's safe to perform the cleanup.
149 | registry.injected.delete(styleHash);
150 | injectionTarget.querySelector(`style[data-style-hash="${styleHash}"]`)?.remove();
151 | }
152 | }, 0); // A timeout of 0ms is sufficient to push this to the end of the event loop.
153 | };
154 | }, [injectionTarget, registry, styleHash]); // Dependency array ensures this runs once per style change.
155 |
156 | return className;
157 | }
158 |
```
--------------------------------------------------------------------------------
/xmlui/src/parsers/xmlui-parser/lint.ts:
--------------------------------------------------------------------------------
```typescript
1 | import type {
2 | ComponentDef,
3 | CompoundComponentDef,
4 | ComponentMetadata,
5 | } from "../../abstractions/ComponentDefs";
6 | import type { StandaloneAppDescription } from "../../components-core/abstractions/standalone";
7 | import { layoutOptionKeys } from "../../components-core/descriptorHelper";
8 | import { viewportSizeMd } from "../../components/abstractions";
9 | import type {
10 | ComponentMetadataProvider,
11 | MetadataProvider,
12 | } from "../../language-server/services/common/metadata-utils";
13 | import { CORE_NAMESPACE_VALUE } from "./transform";
14 |
15 | export enum LintSeverity {
16 | Skip,
17 | Warning,
18 | Error,
19 | }
20 |
21 | export enum LintDiagKind {
22 | UnrecognisedProp,
23 | }
24 |
25 | type Options = {
26 | severity: LintSeverity;
27 | };
28 |
29 | type LintDiagnostic = {
30 | message: string;
31 | kind: LintDiagKind;
32 | };
33 |
34 | export function getLintSeverity(lintSeverityOption: string | undefined): LintSeverity {
35 | if (!lintSeverityOption) {
36 | return LintSeverity.Warning;
37 | }
38 |
39 | let lintSeverity = LintSeverity.Warning;
40 | switch (lintSeverityOption.toLowerCase()) {
41 | case "warning":
42 | return LintSeverity.Warning;
43 | break;
44 | case "error":
45 | return LintSeverity.Error;
46 | break;
47 | case "skip":
48 | return LintSeverity.Skip;
49 | break;
50 | default:
51 | console.warn(
52 | `Invalid lint severity option '${lintSeverityOption}'. Must be one of: 'warning', 'error', 'skip'. Defaulting to 'warning'.`,
53 | );
54 | return LintSeverity.Warning;
55 | break;
56 | }
57 | }
58 |
59 | export type ComponentLints = {
60 | lints: {
61 | message: string;
62 | kind: LintDiagKind;
63 | }[];
64 | componentName: string;
65 | };
66 |
67 | export function lintApp({
68 | appDef,
69 | metadataProvider,
70 | }: {
71 | appDef: StandaloneAppDescription;
72 | metadataProvider: MetadataProvider;
73 | }): ComponentLints[] {
74 | const entryPointLints: ComponentLints = {
75 | componentName: "Main",
76 | lints: lint({
77 | component: appDef.entryPoint,
78 | metadataProvider,
79 | }),
80 | };
81 |
82 | const compoundCompLints: ComponentLints[] = (appDef.components ?? []).map((c) => {
83 | const lints = lint({
84 | component: c,
85 | metadataProvider,
86 | });
87 | return { lints, componentName: c.name };
88 | });
89 |
90 | return [entryPointLints, ...compoundCompLints].filter((diags) => diags.lints.length > 0);
91 | }
92 |
93 | export function printComponentLints(lintDiags: ComponentLints) {
94 | console.group(`Validation on '${lintDiags.componentName}':`);
95 |
96 | lintDiags.lints.forEach(({ message }) => {
97 | console.warn(message);
98 | });
99 | console.groupEnd();
100 | }
101 |
102 | export function lintErrorsComponent(lints: ComponentLints[]) {
103 | function makeComponent() {
104 | const errList = lints.map((lint, idx) => {
105 | return {
106 | type: "VStack",
107 | props: { gap: "0px" },
108 | children: [
109 | {
110 | type: "VStack",
111 | props: { backgroundColor: "lightgrey", padding: "10px" },
112 | children: [
113 | {
114 | type: "H2",
115 | props: {
116 | value: `#${idx + 1}: In component '${lint.componentName}':`,
117 | color: "$color-info",
118 | },
119 | },
120 | {
121 | type: "VStack",
122 | children: lint.lints.map(({ message }, msgIdx) => {
123 | return {
124 | type: "Text",
125 | props: { value: `${idx + 1}.${msgIdx + 1}: ${message}`, fontWeight: "bold" },
126 | };
127 | }),
128 | },
129 | ],
130 | },
131 | ],
132 | };
133 | });
134 | const comp: ComponentDef = {
135 | type: "VStack",
136 | props: { padding: "$padding-normal", gap: 0 },
137 | children: [
138 | {
139 | type: "H1",
140 | props: {
141 | value: `Errors found while checking Xmlui markup`,
142 | padding: "$padding-normal",
143 | backgroundColor: "$color-error",
144 | color: "white",
145 | },
146 | },
147 | {
148 | type: "VStack",
149 | props: {
150 | gap: "$gap-tight",
151 | padding: "$padding-normal",
152 | },
153 | children: errList,
154 | },
155 | ],
156 | };
157 | return comp;
158 | }
159 | return makeComponent() as ComponentDef;
160 | }
161 |
162 | export function lint({
163 | component,
164 | metadataProvider,
165 | }: {
166 | component: CompoundComponentDef | ComponentDef;
167 | metadataProvider: MetadataProvider;
168 | }): LintDiagnostic[] {
169 | if ("component" in component) {
170 | return lintHelp(component.component, metadataProvider, []);
171 | }
172 | return lintHelp(component, metadataProvider, []);
173 | }
174 |
175 | function lintHelp(
176 | component: ComponentDef,
177 | metadataProvider: MetadataProvider,
178 | acc: LintDiagnostic[],
179 | ) {
180 | const componentName = component.type.startsWith(CORE_NAMESPACE_VALUE)
181 | ? component.type.slice(CORE_NAMESPACE_VALUE.length + 1)
182 | : component.type;
183 | const componentMdProvider = metadataProvider.getComponent(componentName);
184 |
185 | if (componentMdProvider !== null && !componentMdProvider.allowArbitraryProps) {
186 | lintAttrs(component, componentMdProvider, acc);
187 | }
188 |
189 | if (!component.children) {
190 | return acc;
191 | }
192 |
193 | for (const child of component.children) {
194 | lintHelp(child, metadataProvider, acc);
195 | }
196 | return acc;
197 | }
198 |
199 | const implicitPropNames = layoutOptionKeys;
200 |
201 | function lintAttrs(
202 | component: ComponentDef,
203 | metadataForCurrentComponent: ComponentMetadataProvider,
204 | diags: LintDiagnostic[],
205 | ) {
206 | const invalidAttrNames = Object.keys(component.props ?? {}).filter(
207 | (name) => !metadataForCurrentComponent.getAttr(name),
208 | );
209 | const invalidEvents = Object.keys(component.events ?? {}).filter(
210 | (event) => !metadataForCurrentComponent.getEvent(event),
211 | );
212 | const invalidApis = Object.keys(component.api ?? {}).filter(
213 | (api) => !metadataForCurrentComponent.getApi(api),
214 | );
215 |
216 | invalidAttrNames.push(...invalidEvents);
217 | invalidAttrNames.push(...invalidApis);
218 |
219 | for (const invalidAttrName of invalidAttrNames) {
220 | diags.push(toUnrecognisedAttrDiag(component, invalidAttrName));
221 | }
222 | }
223 |
224 | function toUnrecognisedAttrDiag(component: ComponentDef, attr: string): LintDiagnostic {
225 | return {
226 | message: `Unrecognised property '${attr}' on component '${component.type}'.`,
227 | kind: LintDiagKind.UnrecognisedProp,
228 | };
229 | }
230 |
```
--------------------------------------------------------------------------------
/docs/content/components/Pagination.md:
--------------------------------------------------------------------------------
```markdown
1 | # Pagination [#pagination]
2 |
3 | `Pagination` enables navigation through large datasets by dividing content into pages. It provides controls for page navigation and can display current page information.
4 |
5 | ## Standalone [#standalone]
6 |
7 | If the `itemCount` property is provided, the component shows information about the number of entries shown per page, the total number of entries, as well as the current page index:
8 |
9 | ```xmlui-pg copy display
10 | <App>
11 | <Pagination itemCount="100" pageSize="10" />
12 | </App>
13 | ```
14 |
15 | If not, the [`hasPrevPage`](#hasprevpage) and [`hasNextPage`](#hasnextpage) properties can be used to control the enabled/disabled state of the previous and next buttons, while only the previous and next buttons are displayed:
16 |
17 | ```xmlui-pg copy display
18 | <App>
19 | <Pagination hasPrevPage="true" hasNextPage="true" />
20 | </App>
21 | ```
22 |
23 | ## Integrations [#integrations]
24 |
25 | ### Table [#table]
26 |
27 | `Pagination` has first-class support in the Table component. `Pagination` is controlled via the [`isPaginated`](./Table#ispaginated-default-false), [`pageSize`](./Table#pagesize), [`pageSizeOptions`](./Table#pagesizeoptions) and [`paginationControlsLocation`](./Table#paginationcontrolslocation-default-bottom) properties.
28 |
29 | ```xmlui
30 | <Table data="/api" isPaginated pageSize="5" pageSizeOptions="{[5, 10, 20]}">
31 | <Column header="ID" bindTo="elem" width="80px">
32 | <!-- ... -->
33 | </Column>
34 | <!-- ... -->
35 | </Table>
36 | ```
37 |
38 | See the [Table reference](./Table#ispaginated-default-false) for a working example.
39 |
40 | ### List [#list]
41 |
42 | The `List` is a perfect example of a component that does not implement its own pagination. Thus, use the Pagination with a Datasource component and connect them to the List:
43 |
44 | ```xmlui
45 | <DataSource id="ds" url="/api" queryParams="{{ from: before, to: after }}" />
46 | <Pagination
47 | itemCount="20"
48 | pageSize="{pageSize}"
49 | pageIndex="{currentPage}"
50 | onPageDidChange="(page, size, total) => {
51 | currentPage = page;
52 | before = page * size;
53 | after = before + size - 1;
54 | }"
55 | />
56 | <List data="{ds}" />
57 | ```
58 |
59 | For a comprehensive example, see [How to paginate a List](../howto/paginate-a-list).
60 |
61 | ## Properties [#properties]
62 |
63 | ### `buttonRowPosition` (default: "center") [#buttonrowposition-default-center]
64 |
65 | Determines where to place the pagination button row in the layout.
66 |
67 | Available values: `start`, `center` **(default)**, `end`
68 |
69 | ### `enabled` (default: true) [#enabled-default-true]
70 |
71 | This boolean property value indicates whether the component responds to user events (`true`) or not (`false`).
72 |
73 | ### `hasNextPage` [#hasnextpage]
74 |
75 | Whether to disable the next page button. Only takes effect if itemCount is not provided.
76 |
77 | ### `hasPrevPage` [#hasprevpage]
78 |
79 | Whether to disable the previous page button. Only takes effect if itemCount is not provided.
80 |
81 | ### `itemCount` [#itemcount]
82 |
83 | Total number of items to paginate. If not provided, the component renders simplified pagination controls that are enabled/disabled using the `hasPrevPage` and `hasNextPage` props.
84 |
85 | ### `maxVisiblePages` (default: 1) [#maxvisiblepages-default-1]
86 |
87 | Maximum number of page buttons to display. If the value is not among the allowed values, it will fall back to the default.
88 |
89 | Available values: `1` **(default)**, `3`, `5`
90 |
91 | ### `orientation` [#orientation]
92 |
93 | Layout orientation of the pagination component
94 |
95 | Available values:
96 |
97 | | Value | Description |
98 | | --- | --- |
99 | | `horizontal` | The component will fill the available space horizontally |
100 | | `vertical` | The component will fill the available space vertically |
101 |
102 | ### `pageIndex` (default: 0) [#pageindex-default-0]
103 |
104 | Current page index (0-based)
105 |
106 | ### `pageInfoPosition` [#pageinfoposition]
107 |
108 | Determines where to place the page information in the layout.
109 |
110 | ### `pageSize` (default: 10) [#pagesize-default-10]
111 |
112 | Number of items per page
113 |
114 | ### `pageSizeOptions` [#pagesizeoptions]
115 |
116 | Array of page sizes the user can select from. If provided, shows a page size selector dropdown
117 |
118 | ### `pageSizeSelectorPosition` [#pagesizeselectorposition]
119 |
120 | Determines where to place the page size selector in the layout.
121 |
122 | ### `showCurrentPage` (default: true) [#showcurrentpage-default-true]
123 |
124 | Whether to show the current page indicator
125 |
126 | ### `showPageInfo` (default: true) [#showpageinfo-default-true]
127 |
128 | Whether to show page information
129 |
130 | ### `showPageSizeSelector` (default: true) [#showpagesizeselector-default-true]
131 |
132 | Whether to show the page size selector
133 |
134 | ## Events [#events]
135 |
136 | ### `pageDidChange` [#pagedidchange]
137 |
138 | Fired when the current page changes
139 |
140 | ### `pageSizeDidChange` [#pagesizedidchange]
141 |
142 | Fired when the page size changes
143 |
144 | ## Exposed Methods [#exposed-methods]
145 |
146 | ### `currentPage` [#currentpage]
147 |
148 | Gets the current page number (1-based)
149 |
150 | ### `currentPageSize` [#currentpagesize]
151 |
152 | Gets the current page size
153 |
154 | ### `moveFirst` [#movefirst]
155 |
156 | Moves to the first page
157 |
158 | **Signature**: `moveFirst(): void`
159 |
160 | ### `moveLast` [#movelast]
161 |
162 | Moves to the last page
163 |
164 | **Signature**: `moveLast(): void`
165 |
166 | ### `moveNext` [#movenext]
167 |
168 | Moves to the next page
169 |
170 | **Signature**: `moveNext(): void`
171 |
172 | ### `movePrev` [#moveprev]
173 |
174 | Moves to the previous page
175 |
176 | **Signature**: `movePrev(): void`
177 |
178 | ## Styling [#styling]
179 |
180 | ### Theme Variables [#theme-variables]
181 |
182 | | Variable | Default Value (Light) | Default Value (Dark) |
183 | | --- | --- | --- |
184 | | [backgroundColor](../styles-and-themes/common-units/#color)-Pagination | transparent | transparent |
185 | | [backgroundColor](../styles-and-themes/common-units/#color)-selector-Pagination | transparent | transparent |
186 | | [borderColor](../styles-and-themes/common-units/#color)-Pagination | $color-gray-300 | $color-gray-300 |
187 | | [borderRadius](../styles-and-themes/common-units/#border-rounding)-selector-Pagination | $borderRadius | $borderRadius |
188 | | [gap](../styles-and-themes/common-units/#size)-buttonRow-Pagination | $space-2 | $space-2 |
189 | | [padding](../styles-and-themes/common-units/#size)-Pagination | $space-4 | $space-4 |
190 | | [textColor](../styles-and-themes/common-units/#color)-Pagination | $color-gray-600 | $color-gray-600 |
191 | | [textColor](../styles-and-themes/common-units/#color)-selector-Pagination | $color-gray-600 | $color-gray-600 |
192 |
```
--------------------------------------------------------------------------------
/xmlui/tests/parsers/scripting/function-proxy.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describe, expect, it } from "vitest";
2 |
3 | import { createEvalContext, parseStatements } from "./test-helpers";
4 | import {
5 | ArrowExpressionStatement,
6 | ExpressionStatement,
7 | T_ARROW_EXPRESSION_STATEMENT,
8 | } from "../../../src/components-core/script-runner/ScriptingSourceTree";
9 | import { processStatementQueueAsync } from "../../../src/components-core/script-runner/process-statement-async";
10 |
11 | describe("Function proxies", () => {
12 | it("Array.prototype.filter #1", async () => {
13 | // --- Arrange
14 | const source =
15 | "(params)=> { return items.filter((item) => { return item.parentId === params.pathParams.nodeId});}";
16 | const evalContext = createEvalContext({
17 | localContext: {
18 | items: [
19 | {
20 | name: "item1",
21 | parentId: "",
22 | },
23 | {
24 | name: "item2",
25 | parentId: "my-parent-id",
26 | },
27 | ],
28 | },
29 | eventArgs: [{ pathParams: { nodeId: "" } }],
30 | });
31 | const statements = parseStatements(source);
32 | const arrowStmt = {
33 | type: T_ARROW_EXPRESSION_STATEMENT,
34 | expr: (statements[0] as ExpressionStatement).expr,
35 | } as ArrowExpressionStatement;
36 | await processStatementQueueAsync([arrowStmt], evalContext);
37 | // --- Assert
38 | const thread = evalContext.mainThread!;
39 | expect(thread.blocks!.length).equal(1);
40 | expect(thread.blocks![0].returnValue).eql([{ name: "item1", parentId: "" }]);
41 | });
42 |
43 | it("Array.prototype.forEach #1", async () => {
44 | // --- Arrange
45 | const source = `()=> {
46 | const result = [];
47 | items.forEach((item) => {
48 | result.push(item * 2)
49 | });
50 | return result;
51 | }`;
52 | const evalContext = createEvalContext({
53 | localContext: {
54 | items: [2, 3],
55 | },
56 | eventArgs: [],
57 | });
58 | const statements = parseStatements(source);
59 | const arrowStmt = {
60 | type: T_ARROW_EXPRESSION_STATEMENT,
61 | expr: (statements[0] as ExpressionStatement).expr,
62 | } as ArrowExpressionStatement;
63 | await processStatementQueueAsync([arrowStmt], evalContext);
64 | // --- Assert
65 | const thread = evalContext.mainThread!;
66 | expect(thread.blocks![0].returnValue).eql([4, 6]);
67 | });
68 |
69 | it("Array.prototype.map #1", async () => {
70 | // --- Arrange
71 | const source = `()=> {
72 | return items.map((item) => {
73 | return item *= 2;
74 | });
75 | }`;
76 | const evalContext = createEvalContext({
77 | localContext: {
78 | items: [2, 3],
79 | },
80 | });
81 | const statements = parseStatements(source);
82 | const arrowStmt = {
83 | type: T_ARROW_EXPRESSION_STATEMENT,
84 | expr: (statements[0] as ExpressionStatement).expr,
85 | } as ArrowExpressionStatement;
86 | await processStatementQueueAsync([arrowStmt], evalContext);
87 | // --- Assert
88 | const thread = evalContext.mainThread!;
89 | expect(thread.blocks![0].returnValue).eql([4, 6]);
90 | });
91 |
92 | it("Array.prototype.every #1", async () => {
93 | // --- Arrange
94 | const source = `(params)=> {
95 | return items.every((item) => { return item.parentId === params.pathParams.nodeId}
96 | );
97 | }`;
98 | const evalContext = createEvalContext({
99 | localContext: {
100 | items: [
101 | {
102 | name: "item1",
103 | parentId: "",
104 | },
105 | {
106 | name: "item2",
107 | parentId: "my-parent-id",
108 | },
109 | ],
110 | },
111 | eventArgs: [{ pathParams: { nodeId: "" } }],
112 | });
113 | const statements = parseStatements(source);
114 | const arrowStmt = {
115 | type: T_ARROW_EXPRESSION_STATEMENT,
116 | expr: (statements[0] as ExpressionStatement).expr,
117 | } as ArrowExpressionStatement;
118 | await processStatementQueueAsync([arrowStmt], evalContext);
119 | // --- Assert
120 | const thread = evalContext.mainThread!;
121 | expect(thread.blocks!.length).equal(1);
122 | expect(thread.blocks![0].returnValue).eql(false);
123 | });
124 |
125 | it("Array.prototype.findIndex #1", async () => {
126 | // --- Arrange
127 | const source = `(params)=> {
128 | return items.findIndex((item) => item > 5)
129 | }`;
130 | const evalContext = createEvalContext({
131 | localContext: {
132 | items: [2, 6, 1],
133 | },
134 | });
135 | const statements = parseStatements(source);
136 | const arrowStmt = {
137 | type: T_ARROW_EXPRESSION_STATEMENT,
138 | expr: (statements[0] as ExpressionStatement).expr,
139 | } as ArrowExpressionStatement;
140 | await processStatementQueueAsync([arrowStmt], evalContext);
141 | // --- Assert
142 | const thread = evalContext.mainThread!;
143 | expect(thread.blocks!.length).equal(1);
144 | expect(thread.blocks![0].returnValue).eql(1);
145 | });
146 |
147 | it("Array.prototype.find #1", async () => {
148 | // --- Arrange
149 | const source = `(params)=> {
150 | return items.find((item) => item > 4);
151 | }`;
152 | const evalContext = createEvalContext({
153 | localContext: {
154 | items: [1, 2, 3, 4, 5, 6],
155 | },
156 | eventArgs: [{ pathParams: { nodeId: "" } }],
157 | });
158 | const statements = parseStatements(source);
159 | const arrowStmt = {
160 | type: T_ARROW_EXPRESSION_STATEMENT,
161 | expr: (statements[0] as ExpressionStatement).expr,
162 | } as ArrowExpressionStatement;
163 | await processStatementQueueAsync([arrowStmt], evalContext);
164 | // --- Assert
165 | const thread = evalContext.mainThread!;
166 | expect(thread.blocks!.length).equal(1);
167 | expect(thread.blocks![0].returnValue).eql(5);
168 | });
169 |
170 | it("Array.prototype.flatMap #1", async () => {
171 | // --- Arrange
172 | const source = `(params)=> {
173 | return items.flatMap((item) => item > 4 ? [4, 4] : 1);
174 | }`;
175 | const evalContext = createEvalContext({
176 | localContext: {
177 | items: [5, 3, 2],
178 | },
179 | eventArgs: [{ pathParams: { nodeId: "" } }],
180 | });
181 | const statements = parseStatements(source);
182 | const arrowStmt = {
183 | type: T_ARROW_EXPRESSION_STATEMENT,
184 | expr: (statements[0] as ExpressionStatement).expr,
185 | } as ArrowExpressionStatement;
186 | await processStatementQueueAsync([arrowStmt], evalContext);
187 | // --- Assert
188 | const thread = evalContext.mainThread!;
189 | expect(thread.blocks!.length).equal(1);
190 | expect(thread.blocks![0].returnValue).eql([4, 4, 1, 1]);
191 | });
192 | });
193 |
```