This is page 26 of 188. Use http://codebase.md/xmlui-org/xmlui/tools/vscode/resources/%7Bimage%7D?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .changeset
│ ├── config.json
│ ├── cyan-tools-design.md
│ ├── every-moments-teach.md
│ ├── full-symbols-accept.md
│ └── tricky-zoos-crash.md
├── .eslintrc.cjs
├── .github
│ ├── build-checklist.png
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows
│ ├── deploy-blog-optimized.yml
│ ├── deploy-blog-swa.yml
│ ├── deploy-blog.yml
│ ├── deploy-docs-optimized.yml
│ ├── deploy-docs-swa.yml
│ ├── deploy-docs.yml
│ ├── prepare-versions.yml
│ ├── release-packages.yml
│ ├── run-all-tests.yml
│ └── run-smoke-tests.yml
├── .gitignore
├── .prettierrc.js
├── .vscode
│ ├── launch.json
│ └── settings.json
├── blog
│ ├── .gitignore
│ ├── .gitkeep
│ ├── CHANGELOG.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── package.json
│ ├── public
│ │ ├── blog
│ │ │ ├── images
│ │ │ │ ├── an-advanced-codefence.gif
│ │ │ │ ├── an-advanced-codefence.mp4
│ │ │ │ ├── blog-page-component.png
│ │ │ │ ├── blog-scrabble.png
│ │ │ │ ├── codefence-runner.png
│ │ │ │ ├── integrated-blog-search.png
│ │ │ │ ├── lorem-ipsum.png
│ │ │ │ ├── playground-checkbox-source.png
│ │ │ │ ├── playground.png
│ │ │ │ ├── use-xmlui-mcp-to-find-a-howto.png
│ │ │ │ └── xmlui-demo-gallery.png
│ │ │ ├── introducing-xmlui.md
│ │ │ ├── lorem-ipsum.md
│ │ │ ├── newest-post.md
│ │ │ ├── older-post.md
│ │ │ ├── xmlui-playground.md
│ │ │ └── xmlui-powered-blog.md
│ │ ├── mockServiceWorker.js
│ │ ├── resources
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ └── for-download
│ │ │ │ └── xmlui
│ │ │ │ └── xmlui-standalone.umd.js
│ │ │ ├── github.svg
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ ├── rss.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ ├── staticwebapp.config.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ └── PageNotFound.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── blog-theme.ts
│ └── tsconfig.json
├── CONTRIBUTING.md
├── docs
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── ComponentRefLinks.txt
│ ├── content
│ │ ├── _meta.json
│ │ ├── components
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── APICall.md
│ │ │ ├── App.md
│ │ │ ├── AppHeader.md
│ │ │ ├── AppState.md
│ │ │ ├── AutoComplete.md
│ │ │ ├── Avatar.md
│ │ │ ├── Backdrop.md
│ │ │ ├── Badge.md
│ │ │ ├── BarChart.md
│ │ │ ├── Bookmark.md
│ │ │ ├── Breakout.md
│ │ │ ├── Button.md
│ │ │ ├── Card.md
│ │ │ ├── Carousel.md
│ │ │ ├── ChangeListener.md
│ │ │ ├── Checkbox.md
│ │ │ ├── CHStack.md
│ │ │ ├── ColorPicker.md
│ │ │ ├── Column.md
│ │ │ ├── ContentSeparator.md
│ │ │ ├── CVStack.md
│ │ │ ├── DataSource.md
│ │ │ ├── DateInput.md
│ │ │ ├── DatePicker.md
│ │ │ ├── DonutChart.md
│ │ │ ├── DropdownMenu.md
│ │ │ ├── EmojiSelector.md
│ │ │ ├── ExpandableItem.md
│ │ │ ├── FileInput.md
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FlowLayout.md
│ │ │ ├── Footer.md
│ │ │ ├── Form.md
│ │ │ ├── FormItem.md
│ │ │ ├── FormSection.md
│ │ │ ├── Fragment.md
│ │ │ ├── H1.md
│ │ │ ├── H2.md
│ │ │ ├── H3.md
│ │ │ ├── H4.md
│ │ │ ├── H5.md
│ │ │ ├── H6.md
│ │ │ ├── Heading.md
│ │ │ ├── HSplitter.md
│ │ │ ├── HStack.md
│ │ │ ├── Icon.md
│ │ │ ├── IFrame.md
│ │ │ ├── Image.md
│ │ │ ├── Items.md
│ │ │ ├── LabelList.md
│ │ │ ├── Legend.md
│ │ │ ├── LineChart.md
│ │ │ ├── Link.md
│ │ │ ├── List.md
│ │ │ ├── Logo.md
│ │ │ ├── Markdown.md
│ │ │ ├── MenuItem.md
│ │ │ ├── MenuSeparator.md
│ │ │ ├── ModalDialog.md
│ │ │ ├── NavGroup.md
│ │ │ ├── NavLink.md
│ │ │ ├── NavPanel.md
│ │ │ ├── NoResult.md
│ │ │ ├── NumberBox.md
│ │ │ ├── Option.md
│ │ │ ├── Page.md
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── Pages.md
│ │ │ ├── Pagination.md
│ │ │ ├── PasswordInput.md
│ │ │ ├── PieChart.md
│ │ │ ├── ProgressBar.md
│ │ │ ├── Queue.md
│ │ │ ├── RadioGroup.md
│ │ │ ├── RealTimeAdapter.md
│ │ │ ├── Redirect.md
│ │ │ ├── Select.md
│ │ │ ├── Slider.md
│ │ │ ├── Slot.md
│ │ │ ├── SpaceFiller.md
│ │ │ ├── Spinner.md
│ │ │ ├── Splitter.md
│ │ │ ├── Stack.md
│ │ │ ├── StickyBox.md
│ │ │ ├── SubMenuItem.md
│ │ │ ├── Switch.md
│ │ │ ├── TabItem.md
│ │ │ ├── Table.md
│ │ │ ├── TableOfContents.md
│ │ │ ├── Tabs.md
│ │ │ ├── Text.md
│ │ │ ├── TextArea.md
│ │ │ ├── TextBox.md
│ │ │ ├── Theme.md
│ │ │ ├── TimeInput.md
│ │ │ ├── Timer.md
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneSwitch.md
│ │ │ ├── Tooltip.md
│ │ │ ├── Tree.md
│ │ │ ├── VSplitter.md
│ │ │ ├── VStack.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ ├── xmlui-spreadsheet
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Spreadsheet.md
│ │ │ └── xmlui-website-blocks
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Carousel.md
│ │ │ ├── HelloMd.md
│ │ │ ├── HeroSection.md
│ │ │ └── ScrollToTop.md
│ │ └── extensions
│ │ ├── _meta.json
│ │ ├── xmlui-animations
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Animation.md
│ │ │ ├── FadeAnimation.md
│ │ │ ├── FadeInAnimation.md
│ │ │ ├── FadeOutAnimation.md
│ │ │ ├── ScaleAnimation.md
│ │ │ └── SlideInAnimation.md
│ │ └── xmlui-website-blocks
│ │ ├── _meta.json
│ │ ├── _overview.md
│ │ ├── Carousel.md
│ │ ├── HelloMd.md
│ │ ├── HeroSection.md
│ │ └── ScrollToTop.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── package.json
│ ├── public
│ │ ├── feed.rss
│ │ ├── mockServiceWorker.js
│ │ ├── pages
│ │ │ ├── _meta.json
│ │ │ ├── app-structure.md
│ │ │ ├── build-editor-component.md
│ │ │ ├── build-hello-world-component.md
│ │ │ ├── components-intro.md
│ │ │ ├── context-variables.md
│ │ │ ├── forms.md
│ │ │ ├── globals.md
│ │ │ ├── glossary.md
│ │ │ ├── helper-tags.md
│ │ │ ├── hosted-deployment.md
│ │ │ ├── howto
│ │ │ │ ├── assign-a-complex-json-literal-to-a-component-variable.md
│ │ │ │ ├── chain-a-refetch.md
│ │ │ │ ├── control-cache-invalidation.md
│ │ │ │ ├── debounce-user-input-for-api-calls.md
│ │ │ │ ├── debounce-with-changelistener.md
│ │ │ │ ├── debug-a-component.md
│ │ │ │ ├── delay-a-datasource-until-another-datasource-is-ready.md
│ │ │ │ ├── delegate-a-method.md
│ │ │ │ ├── do-custom-form-validation.md
│ │ │ │ ├── expose-a-method-from-a-component.md
│ │ │ │ ├── filter-and-transform-data-from-an-api.md
│ │ │ │ ├── group-items-in-list-by-a-property.md
│ │ │ │ ├── handle-background-operations.md
│ │ │ │ ├── hide-an-element-until-its-datasource-is-ready.md
│ │ │ │ ├── make-a-set-of-equal-width-cards.md
│ │ │ │ ├── make-a-table-responsive.md
│ │ │ │ ├── make-navpanel-width-responsive.md
│ │ │ │ ├── modify-a-value-reported-in-a-column.md
│ │ │ │ ├── paginate-a-list.md
│ │ │ │ ├── pass-data-to-a-modal-dialog.md
│ │ │ │ ├── react-to-button-click-not-keystrokes.md
│ │ │ │ ├── set-the-initial-value-of-a-select-from-fetched-data.md
│ │ │ │ ├── share-a-modaldialog-across-components.md
│ │ │ │ ├── sync-selections-between-table-and-list-views.md
│ │ │ │ ├── update-ui-optimistically.md
│ │ │ │ ├── use-built-in-form-validation.md
│ │ │ │ └── use-the-same-modaldialog-to-add-or-edit.md
│ │ │ ├── howto.md
│ │ │ ├── intro.md
│ │ │ ├── layout.md
│ │ │ ├── markup.md
│ │ │ ├── mcp.md
│ │ │ ├── modal-dialogs.md
│ │ │ ├── news-and-reviews.md
│ │ │ ├── reactive-intro.md
│ │ │ ├── refactoring.md
│ │ │ ├── routing-and-links.md
│ │ │ ├── samples
│ │ │ │ ├── color-palette.xmlui
│ │ │ │ ├── color-values.xmlui
│ │ │ │ ├── shadow-sizes.xmlui
│ │ │ │ ├── spacing-sizes.xmlui
│ │ │ │ ├── swatch.xmlui
│ │ │ │ ├── theme-gallery-brief.xmlui
│ │ │ │ └── theme-gallery.xmlui
│ │ │ ├── scoping.md
│ │ │ ├── scripting.md
│ │ │ ├── styles-and-themes
│ │ │ │ ├── common-units.md
│ │ │ │ ├── layout-props.md
│ │ │ │ ├── theme-variable-defaults.md
│ │ │ │ ├── theme-variables.md
│ │ │ │ └── themes.md
│ │ │ ├── template-properties.md
│ │ │ ├── test.md
│ │ │ ├── tutorial-01.md
│ │ │ ├── tutorial-02.md
│ │ │ ├── tutorial-03.md
│ │ │ ├── tutorial-04.md
│ │ │ ├── tutorial-05.md
│ │ │ ├── tutorial-06.md
│ │ │ ├── tutorial-07.md
│ │ │ ├── tutorial-08.md
│ │ │ ├── tutorial-09.md
│ │ │ ├── tutorial-10.md
│ │ │ ├── tutorial-11.md
│ │ │ ├── tutorial-12.md
│ │ │ ├── universal-properties.md
│ │ │ ├── user-defined-components.md
│ │ │ ├── vscode.md
│ │ │ ├── working-with-markdown.md
│ │ │ ├── working-with-text.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-charts
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── DonutChart.md
│ │ │ │ ├── LabelList.md
│ │ │ │ ├── Legend.md
│ │ │ │ ├── LineChart.md
│ │ │ │ └── PieChart.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ └── xmlui-spreadsheet
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ └── Spreadsheet.md
│ │ ├── resources
│ │ │ ├── devdocs
│ │ │ │ ├── debug-proxy-object-2.png
│ │ │ │ ├── debug-proxy-object.png
│ │ │ │ ├── table_editor_01.png
│ │ │ │ ├── table_editor_02.png
│ │ │ │ ├── table_editor_03.png
│ │ │ │ ├── table_editor_04.png
│ │ │ │ ├── table_editor_05.png
│ │ │ │ ├── table_editor_06.png
│ │ │ │ ├── table_editor_07.png
│ │ │ │ ├── table_editor_08.png
│ │ │ │ ├── table_editor_09.png
│ │ │ │ ├── table_editor_10.png
│ │ │ │ ├── table_editor_11.png
│ │ │ │ ├── table-editor-01.png
│ │ │ │ ├── table-editor-02.png
│ │ │ │ ├── table-editor-03.png
│ │ │ │ ├── table-editor-04.png
│ │ │ │ ├── table-editor-06.png
│ │ │ │ ├── table-editor-07.png
│ │ │ │ ├── table-editor-08.png
│ │ │ │ ├── table-editor-09.png
│ │ │ │ └── xmlui-rendering-of-tiptap-markdown.png
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ ├── clients.json
│ │ │ │ ├── daily-revenue.json
│ │ │ │ ├── dashboard-stats.json
│ │ │ │ ├── demo.xmlui
│ │ │ │ ├── demo.xmlui.xs
│ │ │ │ ├── downloads
│ │ │ │ │ └── downloads.json
│ │ │ │ ├── for-download
│ │ │ │ │ ├── index-with-api.html
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── mockApi.js
│ │ │ │ │ ├── start-darwin.sh
│ │ │ │ │ ├── start-linux.sh
│ │ │ │ │ ├── start.bat
│ │ │ │ │ └── xmlui
│ │ │ │ │ └── xmlui-standalone.umd.js
│ │ │ │ ├── getting-started
│ │ │ │ │ ├── cl-tutorial-final.zip
│ │ │ │ │ ├── cl-tutorial.zip
│ │ │ │ │ ├── cl-tutorial2.zip
│ │ │ │ │ ├── cl-tutorial3.zip
│ │ │ │ │ ├── cl-tutorial4.zip
│ │ │ │ │ ├── cl-tutorial5.zip
│ │ │ │ │ ├── cl-tutorial6.zip
│ │ │ │ │ ├── getting-started.zip
│ │ │ │ │ ├── hello-xmlui.zip
│ │ │ │ │ ├── xmlui-empty.zip
│ │ │ │ │ └── xmlui-starter.zip
│ │ │ │ ├── howto
│ │ │ │ │ └── component-icons
│ │ │ │ │ └── up-arrow.svg
│ │ │ │ ├── invoices.json
│ │ │ │ ├── monthly-status.json
│ │ │ │ ├── news-and-reviews.json
│ │ │ │ ├── products.json
│ │ │ │ ├── releases.json
│ │ │ │ ├── tutorials
│ │ │ │ │ ├── datasource
│ │ │ │ │ │ └── api.ts
│ │ │ │ │ └── p2do
│ │ │ │ │ ├── api.ts
│ │ │ │ │ └── todo-logo.svg
│ │ │ │ └── xmlui.json
│ │ │ ├── github.svg
│ │ │ ├── images
│ │ │ │ ├── apiaction-tutorial
│ │ │ │ │ ├── add-success.png
│ │ │ │ │ ├── apiaction-param.png
│ │ │ │ │ ├── change-completed.png
│ │ │ │ │ ├── change-in-progress.png
│ │ │ │ │ ├── confirm-delete.png
│ │ │ │ │ ├── data-error.png
│ │ │ │ │ ├── data-progress.png
│ │ │ │ │ ├── data-success.png
│ │ │ │ │ ├── display-1.png
│ │ │ │ │ ├── item-deleted.png
│ │ │ │ │ ├── item-updated.png
│ │ │ │ │ ├── missing-api-key.png
│ │ │ │ │ ├── new-item-added.png
│ │ │ │ │ └── test-message.png
│ │ │ │ ├── chat-api
│ │ │ │ │ └── domain-model.svg
│ │ │ │ ├── components
│ │ │ │ │ ├── image
│ │ │ │ │ │ └── breakfast.jpg
│ │ │ │ │ ├── markdown
│ │ │ │ │ │ └── colors.png
│ │ │ │ │ └── modal
│ │ │ │ │ ├── deep_link_dialog_1.jpg
│ │ │ │ │ └── deep_link_dialog_2.jpg
│ │ │ │ ├── create-apps
│ │ │ │ │ ├── collapsed-vertical.png
│ │ │ │ │ ├── using-forms-warning-dialog.png
│ │ │ │ │ └── using-forms.png
│ │ │ │ ├── datasource-tutorial
│ │ │ │ │ ├── data-with-header.png
│ │ │ │ │ ├── filtered-data.png
│ │ │ │ │ ├── filtered-items.png
│ │ │ │ │ ├── initial-page-items.png
│ │ │ │ │ ├── list-items.png
│ │ │ │ │ ├── next-page-items.png
│ │ │ │ │ ├── no-data.png
│ │ │ │ │ ├── pagination-1.jpg
│ │ │ │ │ ├── pagination-1.png
│ │ │ │ │ ├── polling-1.png
│ │ │ │ │ ├── refetch-data.png
│ │ │ │ │ ├── slow-loading.png
│ │ │ │ │ ├── test-message.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── unconventional-data.png
│ │ │ │ │ └── unfiltered-items.png
│ │ │ │ ├── flower.jpg
│ │ │ │ ├── get-started
│ │ │ │ │ ├── add-new-contact.png
│ │ │ │ │ ├── app-modified.png
│ │ │ │ │ ├── app-start.png
│ │ │ │ │ ├── app-with-boxes.png
│ │ │ │ │ ├── app-with-toast.png
│ │ │ │ │ ├── boilerplate-structure.png
│ │ │ │ │ ├── cl-initial.png
│ │ │ │ │ ├── cl-start.png
│ │ │ │ │ ├── contact-counts.png
│ │ │ │ │ ├── contact-dialog-title.png
│ │ │ │ │ ├── contact-dialog.png
│ │ │ │ │ ├── contact-menus.png
│ │ │ │ │ ├── contact-predicates.png
│ │ │ │ │ ├── context-menu.png
│ │ │ │ │ ├── dashboard-numbers.png
│ │ │ │ │ ├── default-contact-list.png
│ │ │ │ │ ├── delete-contact.png
│ │ │ │ │ ├── delete-task.png
│ │ │ │ │ ├── detailed-template.png
│ │ │ │ │ ├── edit-contact-details.png
│ │ │ │ │ ├── edited-contact-saved.png
│ │ │ │ │ ├── empty-sections.png
│ │ │ │ │ ├── filter-completed.png
│ │ │ │ │ ├── fullwidth-desktop.png
│ │ │ │ │ ├── fullwidth-mobile.png
│ │ │ │ │ ├── initial-table.png
│ │ │ │ │ ├── items-and-badges.png
│ │ │ │ │ ├── loading-message.png
│ │ │ │ │ ├── new-contact-button.png
│ │ │ │ │ ├── new-contact-saved.png
│ │ │ │ │ ├── no-empty-sections.png
│ │ │ │ │ ├── personal-todo-initial.png
│ │ │ │ │ ├── piechart.png
│ │ │ │ │ ├── review-today.png
│ │ │ │ │ ├── rudimentary-dashboard.png
│ │ │ │ │ ├── section-collapsed.png
│ │ │ │ │ ├── sectioned-items.png
│ │ │ │ │ ├── sections-ordered.png
│ │ │ │ │ ├── spacex-list-with-links.png
│ │ │ │ │ ├── spacex-list.png
│ │ │ │ │ ├── start-personal-todo-1.png
│ │ │ │ │ ├── submit-new-contact.png
│ │ │ │ │ ├── submit-new-task.png
│ │ │ │ │ ├── syntax-highlighting.png
│ │ │ │ │ ├── table-with-badge.png
│ │ │ │ │ ├── template-with-card.png
│ │ │ │ │ ├── test-emulated-api.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── todo-logo.png
│ │ │ │ │ └── xmlui-tools.png
│ │ │ │ ├── HelloApp.png
│ │ │ │ ├── HelloApp2.png
│ │ │ │ ├── logos
│ │ │ │ │ ├── xmlui1.svg
│ │ │ │ │ ├── xmlui2.svg
│ │ │ │ │ ├── xmlui3.svg
│ │ │ │ │ ├── xmlui4.svg
│ │ │ │ │ ├── xmlui5.svg
│ │ │ │ │ ├── xmlui6.svg
│ │ │ │ │ └── xmlui7.svg
│ │ │ │ ├── pdf
│ │ │ │ │ └── dummy-pdf.jpg
│ │ │ │ ├── rendering-engine
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ ├── Component.svg
│ │ │ │ │ ├── CompoundComponent.svg
│ │ │ │ │ ├── RootComponent.svg
│ │ │ │ │ └── tree-with-containers.svg
│ │ │ │ ├── reviewers-guide
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ └── incbutton-in-action.png
│ │ │ │ ├── tools
│ │ │ │ │ └── boilerplate-structure.png
│ │ │ │ ├── try.svg
│ │ │ │ ├── tutorial
│ │ │ │ │ ├── app-chat-history.png
│ │ │ │ │ ├── app-content-placeholder.png
│ │ │ │ │ ├── app-header-and-content.png
│ │ │ │ │ ├── app-links-channel-selected.png
│ │ │ │ │ ├── app-links-click.png
│ │ │ │ │ ├── app-navigation.png
│ │ │ │ │ ├── finished-ex01.png
│ │ │ │ │ ├── finished-ex02.png
│ │ │ │ │ ├── hello.png
│ │ │ │ │ ├── splash-screen-advanced.png
│ │ │ │ │ ├── splash-screen-after-click.png
│ │ │ │ │ ├── splash-screen-centered.png
│ │ │ │ │ ├── splash-screen-events.png
│ │ │ │ │ ├── splash-screen-expression.png
│ │ │ │ │ ├── splash-screen-reuse-after.png
│ │ │ │ │ ├── splash-screen-reuse-before.png
│ │ │ │ │ └── splash-screen.png
│ │ │ │ └── tutorial-01.png
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ ├── Boxes.xmlui
│ │ │ ├── Breadcrumb.xmlui
│ │ │ ├── ChangeLog.xmlui
│ │ │ ├── ColorPalette.xmlui
│ │ │ ├── DocumentLinks.xmlui
│ │ │ ├── DocumentPage.xmlui
│ │ │ ├── DocumentPageNoTOC.xmlui
│ │ │ ├── Icons.xmlui
│ │ │ ├── IncButton.xmlui
│ │ │ ├── IncButton2.xmlui
│ │ │ ├── NameValue.xmlui
│ │ │ ├── PageNotFound.xmlui
│ │ │ ├── PaletteItem.xmlui
│ │ │ ├── Palettes.xmlui
│ │ │ ├── SectionHeader.xmlui
│ │ │ ├── TBD.xmlui
│ │ │ ├── Test.xmlui
│ │ │ ├── ThemesIntro.xmlui
│ │ │ ├── ThousandThemes.xmlui
│ │ │ ├── TubeStops.xmlui
│ │ │ ├── TubeStops.xmlui.xs
│ │ │ └── TwoColumnCode.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ ├── docs-theme.ts
│ │ ├── earthtone.ts
│ │ ├── xmlui-gray-on-default.ts
│ │ ├── xmlui-green-on-default.ts
│ │ └── xmlui-orange-on-default.ts
│ └── tsconfig.json
├── LICENSE
├── package-lock.json
├── package.json
├── packages
│ ├── tsconfig.json
│ ├── xmlui-animations
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── Animation.tsx
│ │ ├── AnimationNative.tsx
│ │ ├── FadeAnimation.tsx
│ │ ├── FadeInAnimation.tsx
│ │ ├── FadeOutAnimation.tsx
│ │ ├── index.tsx
│ │ ├── ScaleAnimation.tsx
│ │ └── SlideInAnimation.tsx
│ ├── xmlui-devtools
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── devtools
│ │ │ │ ├── DevTools.tsx
│ │ │ │ ├── DevToolsNative.module.scss
│ │ │ │ ├── DevToolsNative.tsx
│ │ │ │ ├── ModalDialog.module.scss
│ │ │ │ ├── ModalDialog.tsx
│ │ │ │ ├── ModalVisibilityContext.tsx
│ │ │ │ ├── Tooltip.module.scss
│ │ │ │ ├── Tooltip.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── editor
│ │ │ │ └── Editor.tsx
│ │ │ └── index.tsx
│ │ └── vite.config-overrides.ts
│ ├── xmlui-hello-world
│ │ ├── .gitignore
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── HelloWorld.module.scss
│ │ ├── HelloWorld.tsx
│ │ ├── HelloWorldNative.tsx
│ │ └── index.tsx
│ ├── xmlui-os-frames
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── IPhoneFrame.module.scss
│ │ ├── IPhoneFrame.tsx
│ │ ├── MacOSAppFrame.module.scss
│ │ ├── MacOSAppFrame.tsx
│ │ ├── WindowsAppFrame.module.scss
│ │ └── WindowsAppFrame.tsx
│ ├── xmlui-pdf
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ ├── components
│ │ │ │ └── Pdf.xmlui
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── LazyPdfNative.tsx
│ │ ├── Pdf.module.scss
│ │ └── Pdf.tsx
│ ├── xmlui-playground
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── hooks
│ │ │ ├── usePlayground.ts
│ │ │ └── useToast.ts
│ │ ├── index.tsx
│ │ ├── playground
│ │ │ ├── Box.module.scss
│ │ │ ├── Box.tsx
│ │ │ ├── CodeSelector.module.scss
│ │ │ ├── CodeSelector.tsx
│ │ │ ├── ConfirmationDialog.module.scss
│ │ │ ├── ConfirmationDialog.tsx
│ │ │ ├── Editor.tsx
│ │ │ ├── Header.module.scss
│ │ │ ├── Header.tsx
│ │ │ ├── Playground.tsx
│ │ │ ├── PlaygroundContent.module.scss
│ │ │ ├── PlaygroundContent.tsx
│ │ │ ├── PlaygroundNative.module.scss
│ │ │ ├── PlaygroundNative.tsx
│ │ │ ├── Preview.tsx
│ │ │ ├── StandalonePlayground.tsx
│ │ │ ├── StandalonePlaygroundNative.module.scss
│ │ │ ├── StandalonePlaygroundNative.tsx
│ │ │ ├── ThemeSwitcher.module.scss
│ │ │ ├── ThemeSwitcher.tsx
│ │ │ └── utils.ts
│ │ ├── providers
│ │ │ ├── Toast.module.scss
│ │ │ └── ToastProvider.tsx
│ │ ├── state
│ │ │ └── store.ts
│ │ ├── themes
│ │ │ └── theme.ts
│ │ └── utils
│ │ └── helpers.ts
│ ├── xmlui-search
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── Search.module.scss
│ │ └── Search.tsx
│ ├── xmlui-spreadsheet
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── Spreadsheet.tsx
│ │ └── SpreadsheetNative.tsx
│ └── xmlui-website-blocks
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── demo
│ │ ├── components
│ │ │ ├── HeroBackgroundBreakoutPage.xmlui
│ │ │ ├── HeroBackgroundsPage.xmlui
│ │ │ ├── HeroContentsPage.xmlui
│ │ │ ├── HeroTextAlignPage.xmlui
│ │ │ ├── HeroTextPage.xmlui
│ │ │ └── HeroTonesPage.xmlui
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── default.ts
│ ├── index.html
│ ├── index.ts
│ ├── meta
│ │ └── componentsMetadata.ts
│ ├── package.json
│ ├── public
│ │ └── resources
│ │ ├── building.jpg
│ │ └── xmlui-logo.svg
│ └── src
│ ├── Carousel
│ │ ├── Carousel.module.scss
│ │ ├── Carousel.tsx
│ │ ├── CarouselContext.tsx
│ │ └── CarouselNative.tsx
│ ├── FancyButton
│ │ ├── FancyButton.module.scss
│ │ ├── FancyButton.tsx
│ │ └── FancyButton.xmlui
│ ├── Hello
│ │ ├── Hello.tsx
│ │ ├── Hello.xmlui
│ │ └── Hello.xmlui.xs
│ ├── HeroSection
│ │ ├── HeroSection.module.scss
│ │ ├── HeroSection.spec.ts
│ │ ├── HeroSection.tsx
│ │ └── HeroSectionNative.tsx
│ ├── index.tsx
│ ├── ScrollToTop
│ │ ├── ScrollToTop.module.scss
│ │ ├── ScrollToTop.tsx
│ │ └── ScrollToTopNative.tsx
│ └── vite-env.d.ts
├── playwright.config.ts
├── README.md
├── tools
│ ├── codefence
│ │ └── xmlui-code-fence-docs.md
│ ├── create-app
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── create-app.ts
│ │ ├── helpers
│ │ │ ├── copy.ts
│ │ │ ├── get-pkg-manager.ts
│ │ │ ├── git.ts
│ │ │ ├── install.ts
│ │ │ ├── is-folder-empty.ts
│ │ │ ├── is-writeable.ts
│ │ │ ├── make-dir.ts
│ │ │ └── validate-pkg.ts
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── templates
│ │ │ ├── default
│ │ │ │ └── ts
│ │ │ │ ├── gitignore
│ │ │ │ ├── index.html
│ │ │ │ ├── index.ts
│ │ │ │ ├── public
│ │ │ │ │ ├── mockServiceWorker.js
│ │ │ │ │ ├── resources
│ │ │ │ │ │ ├── favicon.ico
│ │ │ │ │ │ └── xmlui-logo.svg
│ │ │ │ │ └── serve.json
│ │ │ │ └── src
│ │ │ │ ├── components
│ │ │ │ │ ├── ApiAware.xmlui
│ │ │ │ │ ├── Home.xmlui
│ │ │ │ │ ├── IncButton.xmlui
│ │ │ │ │ └── PagePanel.xmlui
│ │ │ │ ├── config.ts
│ │ │ │ └── Main.xmlui
│ │ │ ├── index.ts
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ ├── create-xmlui-hello-world
│ │ ├── index.js
│ │ └── package.json
│ └── vscode
│ ├── .gitignore
│ ├── .vscode
│ │ ├── launch.json
│ │ └── tasks.json
│ ├── .vscodeignore
│ ├── build.sh
│ ├── CHANGELOG.md
│ ├── esbuild.js
│ ├── eslint.config.mjs
│ ├── formatter-docs.md
│ ├── generate-test-sample.sh
│ ├── LICENSE.md
│ ├── package-lock.json
│ ├── package.json
│ ├── README.md
│ ├── resources
│ │ ├── xmlui-logo.png
│ │ └── xmlui-markup-syntax-highlighting.png
│ ├── src
│ │ ├── extension.ts
│ │ └── server.ts
│ ├── syntaxes
│ │ └── xmlui.tmLanguage.json
│ ├── test-samples
│ │ └── sample.xmlui
│ ├── tsconfig.json
│ └── tsconfig.tsbuildinfo
├── turbo.json
└── xmlui
├── .gitignore
├── bin
│ ├── bootstrap.cjs
│ ├── bootstrap.js
│ ├── build-lib.ts
│ ├── build.ts
│ ├── index.ts
│ ├── preview.ts
│ ├── start.ts
│ ├── vite-xmlui-plugin.ts
│ └── viteConfig.ts
├── CHANGELOG.md
├── conventions
│ ├── component-qa-checklist.md
│ ├── copilot-conventions.md
│ ├── create-xmlui-components.md
│ ├── mermaid.md
│ ├── testing-conventions.md
│ └── xmlui-in-a-nutshell.md
├── dev-docs
│ ├── accessibility.md
│ ├── build-system.md
│ ├── build-xmlui.md
│ ├── component-behaviors.md
│ ├── component-metadata.md
│ ├── components-with-options.md
│ ├── containers.md
│ ├── data-operations.md
│ ├── glossary.md
│ ├── index.md
│ ├── next
│ │ ├── component-dev-guide.md
│ │ ├── configuration-management-enhancement-summary.md
│ │ ├── documentation-scripts-refactoring-complete-summary.md
│ │ ├── documentation-scripts-refactoring-plan.md
│ │ ├── duplicate-pattern-extraction-summary.md
│ │ ├── error-handling-standardization-summary.md
│ │ ├── generating-component-reference.md
│ │ ├── index.md
│ │ ├── logging-consistency-implementation-summary.md
│ │ ├── project-build.md
│ │ ├── project-structure.md
│ │ ├── theme-context.md
│ │ ├── tiptap-design-considerations.md
│ │ ├── working-with-code.md
│ │ ├── xmlui-runtime-architecture
│ │ └── xmlui-wcag-accessibility-report.md
│ ├── react-fundamentals.md
│ ├── release-method.md
│ ├── standalone-app.md
│ ├── theme-variables-refactoring.md
│ ├── ud-components.md
│ └── xmlui-repo.md
├── package.json
├── scripts
│ ├── coverage-only.js
│ ├── e2e-test-summary.js
│ ├── extract-component-metadata.js
│ ├── generate-docs
│ │ ├── build-downloads-map.mjs
│ │ ├── build-pages-map.mjs
│ │ ├── components-config.json
│ │ ├── configuration-management.mjs
│ │ ├── constants.mjs
│ │ ├── create-theme-files.mjs
│ │ ├── DocsGenerator.mjs
│ │ ├── error-handling.mjs
│ │ ├── extensions-config.json
│ │ ├── folders.mjs
│ │ ├── generate-summary-files.mjs
│ │ ├── get-docs.mjs
│ │ ├── input-handler.mjs
│ │ ├── logger.mjs
│ │ ├── logging-standards.mjs
│ │ ├── MetadataProcessor.mjs
│ │ ├── pattern-utilities.mjs
│ │ └── utils.mjs
│ ├── generate-metadata-markdown.js
│ ├── get-langserver-metadata.js
│ ├── inline-links.mjs
│ └── README-e2e-summary.md
├── src
│ ├── abstractions
│ │ ├── _conventions.md
│ │ ├── ActionDefs.ts
│ │ ├── AppContextDefs.ts
│ │ ├── ComponentDefs.ts
│ │ ├── ContainerDefs.ts
│ │ ├── ExtensionDefs.ts
│ │ ├── FunctionDefs.ts
│ │ ├── RendererDefs.ts
│ │ ├── scripting
│ │ │ ├── BlockScope.ts
│ │ │ ├── Compilation.ts
│ │ │ ├── LogicalThread.ts
│ │ │ ├── LoopScope.ts
│ │ │ ├── modules.ts
│ │ │ ├── ScriptParserError.ts
│ │ │ ├── Token.ts
│ │ │ ├── TryScope.ts
│ │ │ └── TryScopeExp.ts
│ │ └── ThemingDefs.ts
│ ├── components
│ │ ├── _conventions.md
│ │ ├── abstractions.ts
│ │ ├── Accordion
│ │ │ ├── Accordion.md
│ │ │ ├── Accordion.module.scss
│ │ │ ├── Accordion.spec.ts
│ │ │ ├── Accordion.tsx
│ │ │ ├── AccordionContext.tsx
│ │ │ ├── AccordionItem.tsx
│ │ │ ├── AccordionItemNative.tsx
│ │ │ └── AccordionNative.tsx
│ │ ├── Animation
│ │ │ └── AnimationNative.tsx
│ │ ├── APICall
│ │ │ ├── APICall.md
│ │ │ ├── APICall.spec.ts
│ │ │ ├── APICall.tsx
│ │ │ └── APICallNative.tsx
│ │ ├── App
│ │ │ ├── App.md
│ │ │ ├── App.module.scss
│ │ │ ├── App.spec.ts
│ │ │ ├── App.tsx
│ │ │ ├── AppLayoutContext.ts
│ │ │ ├── AppNative.tsx
│ │ │ ├── AppStateContext.ts
│ │ │ ├── doc-resources
│ │ │ │ ├── condensed-sticky.xmlui
│ │ │ │ ├── condensed.xmlui
│ │ │ │ ├── horizontal-sticky.xmlui
│ │ │ │ ├── horizontal.xmlui
│ │ │ │ ├── vertical-full-header.xmlui
│ │ │ │ ├── vertical-sticky.xmlui
│ │ │ │ └── vertical.xmlui
│ │ │ ├── IndexerContext.ts
│ │ │ ├── LinkInfoContext.ts
│ │ │ ├── SearchContext.tsx
│ │ │ ├── Sheet.module.scss
│ │ │ └── Sheet.tsx
│ │ ├── AppHeader
│ │ │ ├── AppHeader.md
│ │ │ ├── AppHeader.module.scss
│ │ │ ├── AppHeader.spec.ts
│ │ │ ├── AppHeader.tsx
│ │ │ └── AppHeaderNative.tsx
│ │ ├── AppState
│ │ │ ├── AppState.md
│ │ │ ├── AppState.spec.ts
│ │ │ ├── AppState.tsx
│ │ │ └── AppStateNative.tsx
│ │ ├── AutoComplete
│ │ │ ├── AutoComplete.md
│ │ │ ├── AutoComplete.module.scss
│ │ │ ├── AutoComplete.spec.ts
│ │ │ ├── AutoComplete.tsx
│ │ │ ├── AutoCompleteContext.tsx
│ │ │ └── AutoCompleteNative.tsx
│ │ ├── Avatar
│ │ │ ├── Avatar.md
│ │ │ ├── Avatar.module.scss
│ │ │ ├── Avatar.spec.ts
│ │ │ ├── Avatar.tsx
│ │ │ └── AvatarNative.tsx
│ │ ├── Backdrop
│ │ │ ├── Backdrop.md
│ │ │ ├── Backdrop.module.scss
│ │ │ ├── Backdrop.spec.ts
│ │ │ ├── Backdrop.tsx
│ │ │ └── BackdropNative.tsx
│ │ ├── Badge
│ │ │ ├── Badge.md
│ │ │ ├── Badge.module.scss
│ │ │ ├── Badge.spec.ts
│ │ │ ├── Badge.tsx
│ │ │ └── BadgeNative.tsx
│ │ ├── Bookmark
│ │ │ ├── Bookmark.md
│ │ │ ├── Bookmark.module.scss
│ │ │ ├── Bookmark.spec.ts
│ │ │ ├── Bookmark.tsx
│ │ │ └── BookmarkNative.tsx
│ │ ├── Breakout
│ │ │ ├── Breakout.module.scss
│ │ │ ├── Breakout.spec.ts
│ │ │ ├── Breakout.tsx
│ │ │ └── BreakoutNative.tsx
│ │ ├── Button
│ │ │ ├── Button-style.spec.ts
│ │ │ ├── Button.md
│ │ │ ├── Button.module.scss
│ │ │ ├── Button.spec.ts
│ │ │ ├── Button.tsx
│ │ │ └── ButtonNative.tsx
│ │ ├── Card
│ │ │ ├── Card.md
│ │ │ ├── Card.module.scss
│ │ │ ├── Card.spec.ts
│ │ │ ├── Card.tsx
│ │ │ └── CardNative.tsx
│ │ ├── Carousel
│ │ │ ├── Carousel.md
│ │ │ ├── Carousel.module.scss
│ │ │ ├── Carousel.spec.ts
│ │ │ ├── Carousel.tsx
│ │ │ ├── CarouselContext.tsx
│ │ │ ├── CarouselItem.tsx
│ │ │ ├── CarouselItemNative.tsx
│ │ │ └── CarouselNative.tsx
│ │ ├── ChangeListener
│ │ │ ├── ChangeListener.md
│ │ │ ├── ChangeListener.spec.ts
│ │ │ ├── ChangeListener.tsx
│ │ │ └── ChangeListenerNative.tsx
│ │ ├── chart-color-schemes.ts
│ │ ├── Charts
│ │ │ ├── AreaChart
│ │ │ │ ├── AreaChart.md
│ │ │ │ ├── AreaChart.spec.ts
│ │ │ │ ├── AreaChart.tsx
│ │ │ │ └── AreaChartNative.tsx
│ │ │ ├── BarChart
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── BarChart.module.scss
│ │ │ │ ├── BarChart.spec.ts
│ │ │ │ ├── BarChart.tsx
│ │ │ │ └── BarChartNative.tsx
│ │ │ ├── DonutChart
│ │ │ │ ├── DonutChart.spec.ts
│ │ │ │ └── DonutChart.tsx
│ │ │ ├── LabelList
│ │ │ │ ├── LabelList.module.scss
│ │ │ │ ├── LabelList.spec.ts
│ │ │ │ ├── LabelList.tsx
│ │ │ │ └── LabelListNative.tsx
│ │ │ ├── Legend
│ │ │ │ ├── Legend.spec.ts
│ │ │ │ ├── Legend.tsx
│ │ │ │ └── LegendNative.tsx
│ │ │ ├── LineChart
│ │ │ │ ├── LineChart.md
│ │ │ │ ├── LineChart.module.scss
│ │ │ │ ├── LineChart.spec.ts
│ │ │ │ ├── LineChart.tsx
│ │ │ │ └── LineChartNative.tsx
│ │ │ ├── PieChart
│ │ │ │ ├── PieChart.md
│ │ │ │ ├── PieChart.spec.ts
│ │ │ │ ├── PieChart.tsx
│ │ │ │ ├── PieChartNative.module.scss
│ │ │ │ └── PieChartNative.tsx
│ │ │ ├── RadarChart
│ │ │ │ ├── RadarChart.md
│ │ │ │ ├── RadarChart.spec.ts
│ │ │ │ ├── RadarChart.tsx
│ │ │ │ └── RadarChartNative.tsx
│ │ │ ├── Tooltip
│ │ │ │ ├── TooltipContent.module.scss
│ │ │ │ ├── TooltipContent.spec.ts
│ │ │ │ └── TooltipContent.tsx
│ │ │ └── utils
│ │ │ ├── abstractions.ts
│ │ │ └── ChartProvider.tsx
│ │ ├── Checkbox
│ │ │ ├── Checkbox.md
│ │ │ ├── Checkbox.spec.ts
│ │ │ └── Checkbox.tsx
│ │ ├── CodeBlock
│ │ │ ├── CodeBlock.module.scss
│ │ │ ├── CodeBlock.spec.ts
│ │ │ ├── CodeBlock.tsx
│ │ │ ├── CodeBlockNative.tsx
│ │ │ └── highlight-code.ts
│ │ ├── collectedComponentMetadata.ts
│ │ ├── ColorPicker
│ │ │ ├── ColorPicker.md
│ │ │ ├── ColorPicker.module.scss
│ │ │ ├── ColorPicker.spec.ts
│ │ │ ├── ColorPicker.tsx
│ │ │ └── ColorPickerNative.tsx
│ │ ├── Column
│ │ │ ├── Column.md
│ │ │ ├── Column.tsx
│ │ │ ├── ColumnNative.tsx
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ └── TableContext.tsx
│ │ ├── component-utils.ts
│ │ ├── ComponentProvider.tsx
│ │ ├── ComponentRegistryContext.tsx
│ │ ├── container-helpers.tsx
│ │ ├── ContentSeparator
│ │ │ ├── ContentSeparator.md
│ │ │ ├── ContentSeparator.module.scss
│ │ │ ├── ContentSeparator.spec.ts
│ │ │ ├── ContentSeparator.tsx
│ │ │ ├── ContentSeparatorNative.tsx
│ │ │ └── test-padding.xmlui
│ │ ├── DataSource
│ │ │ ├── DataSource.md
│ │ │ └── DataSource.tsx
│ │ ├── DateInput
│ │ │ ├── DateInput.md
│ │ │ ├── DateInput.module.scss
│ │ │ ├── DateInput.spec.ts
│ │ │ ├── DateInput.tsx
│ │ │ └── DateInputNative.tsx
│ │ ├── DatePicker
│ │ │ ├── DatePicker.md
│ │ │ ├── DatePicker.module.scss
│ │ │ ├── DatePicker.spec.ts
│ │ │ ├── DatePicker.tsx
│ │ │ └── DatePickerNative.tsx
│ │ ├── DropdownMenu
│ │ │ ├── DropdownMenu.md
│ │ │ ├── DropdownMenu.module.scss
│ │ │ ├── DropdownMenu.spec.ts
│ │ │ ├── DropdownMenu.tsx
│ │ │ ├── DropdownMenuNative.tsx
│ │ │ ├── MenuItem.md
│ │ │ └── SubMenuItem.md
│ │ ├── EmojiSelector
│ │ │ ├── EmojiSelector.md
│ │ │ ├── EmojiSelector.spec.ts
│ │ │ ├── EmojiSelector.tsx
│ │ │ └── EmojiSelectorNative.tsx
│ │ ├── ExpandableItem
│ │ │ ├── ExpandableItem.module.scss
│ │ │ ├── ExpandableItem.spec.ts
│ │ │ ├── ExpandableItem.tsx
│ │ │ └── ExpandableItemNative.tsx
│ │ ├── FileInput
│ │ │ ├── FileInput.md
│ │ │ ├── FileInput.module.scss
│ │ │ ├── FileInput.spec.ts
│ │ │ ├── FileInput.tsx
│ │ │ └── FileInputNative.tsx
│ │ ├── FileUploadDropZone
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FileUploadDropZone.module.scss
│ │ │ ├── FileUploadDropZone.spec.ts
│ │ │ ├── FileUploadDropZone.tsx
│ │ │ └── FileUploadDropZoneNative.tsx
│ │ ├── FlowLayout
│ │ │ ├── FlowLayout.md
│ │ │ ├── FlowLayout.module.scss
│ │ │ ├── FlowLayout.spec.ts
│ │ │ ├── FlowLayout.spec.ts-snapshots
│ │ │ │ └── Edge-cases-boxShadow-is-not-clipped-1-non-smoke-darwin.png
│ │ │ ├── FlowLayout.tsx
│ │ │ └── FlowLayoutNative.tsx
│ │ ├── Footer
│ │ │ ├── Footer.md
│ │ │ ├── Footer.module.scss
│ │ │ ├── Footer.spec.ts
│ │ │ ├── Footer.tsx
│ │ │ └── FooterNative.tsx
│ │ ├── Form
│ │ │ ├── Form.md
│ │ │ ├── Form.module.scss
│ │ │ ├── Form.spec.ts
│ │ │ ├── Form.tsx
│ │ │ ├── formActions.ts
│ │ │ ├── FormContext.ts
│ │ │ └── FormNative.tsx
│ │ ├── FormItem
│ │ │ ├── FormItem.md
│ │ │ ├── FormItem.module.scss
│ │ │ ├── FormItem.spec.ts
│ │ │ ├── FormItem.tsx
│ │ │ ├── FormItemNative.tsx
│ │ │ ├── HelperText.module.scss
│ │ │ ├── HelperText.tsx
│ │ │ ├── ItemWithLabel.tsx
│ │ │ └── Validations.ts
│ │ ├── FormSection
│ │ │ ├── FormSection.md
│ │ │ ├── FormSection.ts
│ │ │ └── FormSection.xmlui
│ │ ├── Fragment
│ │ │ ├── Fragment.spec.ts
│ │ │ └── Fragment.tsx
│ │ ├── Heading
│ │ │ ├── abstractions.ts
│ │ │ ├── H1.md
│ │ │ ├── H1.spec.ts
│ │ │ ├── H2.md
│ │ │ ├── H2.spec.ts
│ │ │ ├── H3.md
│ │ │ ├── H3.spec.ts
│ │ │ ├── H4.md
│ │ │ ├── H4.spec.ts
│ │ │ ├── H5.md
│ │ │ ├── H5.spec.ts
│ │ │ ├── H6.md
│ │ │ ├── H6.spec.ts
│ │ │ ├── Heading.md
│ │ │ ├── Heading.module.scss
│ │ │ ├── Heading.spec.ts
│ │ │ ├── Heading.tsx
│ │ │ └── HeadingNative.tsx
│ │ ├── HoverCard
│ │ │ ├── HoverCard.tsx
│ │ │ └── HovercardNative.tsx
│ │ ├── HtmlTags
│ │ │ ├── HtmlTags.module.scss
│ │ │ ├── HtmlTags.spec.ts
│ │ │ └── HtmlTags.tsx
│ │ ├── Icon
│ │ │ ├── AdmonitionDanger.tsx
│ │ │ ├── AdmonitionInfo.tsx
│ │ │ ├── AdmonitionNote.tsx
│ │ │ ├── AdmonitionTip.tsx
│ │ │ ├── AdmonitionWarning.tsx
│ │ │ ├── ApiIcon.tsx
│ │ │ ├── ArrowDropDown.module.scss
│ │ │ ├── ArrowDropDown.tsx
│ │ │ ├── ArrowDropUp.module.scss
│ │ │ ├── ArrowDropUp.tsx
│ │ │ ├── ArrowLeft.module.scss
│ │ │ ├── ArrowLeft.tsx
│ │ │ ├── ArrowRight.module.scss
│ │ │ ├── ArrowRight.tsx
│ │ │ ├── Attach.tsx
│ │ │ ├── Binding.module.scss
│ │ │ ├── Binding.tsx
│ │ │ ├── BoardIcon.tsx
│ │ │ ├── BoxIcon.tsx
│ │ │ ├── CheckIcon.tsx
│ │ │ ├── ChevronDownIcon.tsx
│ │ │ ├── ChevronLeft.tsx
│ │ │ ├── ChevronRight.tsx
│ │ │ ├── ChevronUpIcon.tsx
│ │ │ ├── CodeFileIcon.tsx
│ │ │ ├── CodeSandbox.tsx
│ │ │ ├── CompactListIcon.tsx
│ │ │ ├── ContentCopyIcon.tsx
│ │ │ ├── DarkToLightIcon.tsx
│ │ │ ├── DatabaseIcon.module.scss
│ │ │ ├── DatabaseIcon.tsx
│ │ │ ├── DocFileIcon.tsx
│ │ │ ├── DocIcon.tsx
│ │ │ ├── DotMenuHorizontalIcon.tsx
│ │ │ ├── DotMenuIcon.tsx
│ │ │ ├── EmailIcon.tsx
│ │ │ ├── EmptyFolderIcon.tsx
│ │ │ ├── ErrorIcon.tsx
│ │ │ ├── ExpressionIcon.tsx
│ │ │ ├── FillPlusCricleIcon.tsx
│ │ │ ├── FilterIcon.tsx
│ │ │ ├── FolderIcon.tsx
│ │ │ ├── GlobeIcon.tsx
│ │ │ ├── HomeIcon.tsx
│ │ │ ├── HyperLinkIcon.tsx
│ │ │ ├── Icon.md
│ │ │ ├── Icon.module.scss
│ │ │ ├── Icon.spec.ts
│ │ │ ├── Icon.tsx
│ │ │ ├── IconNative.tsx
│ │ │ ├── ImageFileIcon.tsx
│ │ │ ├── Inspect.tsx
│ │ │ ├── LightToDark.tsx
│ │ │ ├── LinkIcon.tsx
│ │ │ ├── ListIcon.tsx
│ │ │ ├── LooseListIcon.tsx
│ │ │ ├── MoonIcon.tsx
│ │ │ ├── MoreOptionsIcon.tsx
│ │ │ ├── NoSortIcon.tsx
│ │ │ ├── PDFIcon.tsx
│ │ │ ├── PenIcon.tsx
│ │ │ ├── PhoneIcon.tsx
│ │ │ ├── PhotoIcon.tsx
│ │ │ ├── PlusIcon.tsx
│ │ │ ├── SearchIcon.tsx
│ │ │ ├── ShareIcon.tsx
│ │ │ ├── SortAscendingIcon.tsx
│ │ │ ├── SortDescendingIcon.tsx
│ │ │ ├── StarsIcon.tsx
│ │ │ ├── SunIcon.tsx
│ │ │ ├── svg
│ │ │ │ ├── admonition_danger.svg
│ │ │ │ ├── admonition_info.svg
│ │ │ │ ├── admonition_note.svg
│ │ │ │ ├── admonition_tip.svg
│ │ │ │ ├── admonition_warning.svg
│ │ │ │ ├── api.svg
│ │ │ │ ├── arrow-dropdown.svg
│ │ │ │ ├── arrow-left.svg
│ │ │ │ ├── arrow-right.svg
│ │ │ │ ├── arrow-up.svg
│ │ │ │ ├── attach.svg
│ │ │ │ ├── binding.svg
│ │ │ │ ├── box.svg
│ │ │ │ ├── bulb.svg
│ │ │ │ ├── code-file.svg
│ │ │ │ ├── code-sandbox.svg
│ │ │ │ ├── dark_to_light.svg
│ │ │ │ ├── database.svg
│ │ │ │ ├── doc.svg
│ │ │ │ ├── empty-folder.svg
│ │ │ │ ├── expression.svg
│ │ │ │ ├── eye-closed.svg
│ │ │ │ ├── eye-dark.svg
│ │ │ │ ├── eye.svg
│ │ │ │ ├── file-text.svg
│ │ │ │ ├── filter.svg
│ │ │ │ ├── folder.svg
│ │ │ │ ├── img.svg
│ │ │ │ ├── inspect.svg
│ │ │ │ ├── light_to_dark.svg
│ │ │ │ ├── moon.svg
│ │ │ │ ├── pdf.svg
│ │ │ │ ├── photo.svg
│ │ │ │ ├── share.svg
│ │ │ │ ├── stars.svg
│ │ │ │ ├── sun.svg
│ │ │ │ ├── trending-down.svg
│ │ │ │ ├── trending-level.svg
│ │ │ │ ├── trending-up.svg
│ │ │ │ ├── txt.svg
│ │ │ │ ├── unknown-file.svg
│ │ │ │ ├── unlink.svg
│ │ │ │ └── xls.svg
│ │ │ ├── TableDeleteColumnIcon.tsx
│ │ │ ├── TableDeleteRowIcon.tsx
│ │ │ ├── TableInsertColumnIcon.tsx
│ │ │ ├── TableInsertRowIcon.tsx
│ │ │ ├── TrashIcon.tsx
│ │ │ ├── TrendingDownIcon.tsx
│ │ │ ├── TrendingLevelIcon.tsx
│ │ │ ├── TrendingUpIcon.tsx
│ │ │ ├── TxtIcon.tsx
│ │ │ ├── UnknownFileIcon.tsx
│ │ │ ├── UnlinkIcon.tsx
│ │ │ ├── UserIcon.tsx
│ │ │ ├── WarningIcon.tsx
│ │ │ └── XlsIcon.tsx
│ │ ├── IconProvider.tsx
│ │ ├── IconRegistryContext.tsx
│ │ ├── IFrame
│ │ │ ├── IFrame.md
│ │ │ ├── IFrame.module.scss
│ │ │ ├── IFrame.spec.ts
│ │ │ ├── IFrame.tsx
│ │ │ └── IFrameNative.tsx
│ │ ├── Image
│ │ │ ├── Image.md
│ │ │ ├── Image.module.scss
│ │ │ ├── Image.spec.ts
│ │ │ ├── Image.tsx
│ │ │ └── ImageNative.tsx
│ │ ├── Input
│ │ │ ├── index.ts
│ │ │ ├── InputAdornment.module.scss
│ │ │ ├── InputAdornment.tsx
│ │ │ ├── InputDivider.module.scss
│ │ │ ├── InputDivider.tsx
│ │ │ ├── InputLabel.module.scss
│ │ │ ├── InputLabel.tsx
│ │ │ ├── PartialInput.module.scss
│ │ │ └── PartialInput.tsx
│ │ ├── InspectButton
│ │ │ ├── InspectButton.module.scss
│ │ │ └── InspectButton.tsx
│ │ ├── Items
│ │ │ ├── Items.md
│ │ │ ├── Items.spec.ts
│ │ │ ├── Items.tsx
│ │ │ └── ItemsNative.tsx
│ │ ├── Link
│ │ │ ├── Link.md
│ │ │ ├── Link.module.scss
│ │ │ ├── Link.spec.ts
│ │ │ ├── Link.tsx
│ │ │ └── LinkNative.tsx
│ │ ├── List
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── List.md
│ │ │ ├── List.module.scss
│ │ │ ├── List.spec.ts
│ │ │ ├── List.tsx
│ │ │ └── ListNative.tsx
│ │ ├── Logo
│ │ │ ├── doc-resources
│ │ │ │ └── xmlui-logo.svg
│ │ │ ├── Logo.md
│ │ │ ├── Logo.tsx
│ │ │ └── LogoNative.tsx
│ │ ├── Markdown
│ │ │ ├── CodeText.module.scss
│ │ │ ├── CodeText.tsx
│ │ │ ├── Markdown.md
│ │ │ ├── Markdown.module.scss
│ │ │ ├── Markdown.spec.ts
│ │ │ ├── Markdown.tsx
│ │ │ ├── MarkdownNative.tsx
│ │ │ ├── parse-binding-expr.ts
│ │ │ └── utils.ts
│ │ ├── metadata-helpers.ts
│ │ ├── ModalDialog
│ │ │ ├── ConfirmationModalContextProvider.tsx
│ │ │ ├── Dialog.module.scss
│ │ │ ├── Dialog.tsx
│ │ │ ├── ModalDialog.md
│ │ │ ├── ModalDialog.module.scss
│ │ │ ├── ModalDialog.spec.ts
│ │ │ ├── ModalDialog.tsx
│ │ │ ├── ModalDialogNative.tsx
│ │ │ └── ModalVisibilityContext.tsx
│ │ ├── NavGroup
│ │ │ ├── NavGroup.md
│ │ │ ├── NavGroup.module.scss
│ │ │ ├── NavGroup.spec.ts
│ │ │ ├── NavGroup.tsx
│ │ │ ├── NavGroupContext.ts
│ │ │ └── NavGroupNative.tsx
│ │ ├── NavLink
│ │ │ ├── NavLink.md
│ │ │ ├── NavLink.module.scss
│ │ │ ├── NavLink.spec.ts
│ │ │ ├── NavLink.tsx
│ │ │ └── NavLinkNative.tsx
│ │ ├── NavPanel
│ │ │ ├── NavPanel.md
│ │ │ ├── NavPanel.module.scss
│ │ │ ├── NavPanel.spec.ts
│ │ │ ├── NavPanel.tsx
│ │ │ └── NavPanelNative.tsx
│ │ ├── NestedApp
│ │ │ ├── AppWithCodeView.module.scss
│ │ │ ├── AppWithCodeView.tsx
│ │ │ ├── AppWithCodeViewNative.tsx
│ │ │ ├── defaultProps.tsx
│ │ │ ├── logo.svg
│ │ │ ├── NestedApp.module.scss
│ │ │ ├── NestedApp.tsx
│ │ │ ├── NestedAppNative.tsx
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.tsx
│ │ │ └── utils.ts
│ │ ├── NoResult
│ │ │ ├── NoResult.md
│ │ │ ├── NoResult.module.scss
│ │ │ ├── NoResult.spec.ts
│ │ │ ├── NoResult.tsx
│ │ │ └── NoResultNative.tsx
│ │ ├── NumberBox
│ │ │ ├── numberbox-abstractions.ts
│ │ │ ├── NumberBox.md
│ │ │ ├── NumberBox.module.scss
│ │ │ ├── NumberBox.spec.ts
│ │ │ ├── NumberBox.tsx
│ │ │ └── NumberBoxNative.tsx
│ │ ├── Option
│ │ │ ├── Option.md
│ │ │ ├── Option.spec.ts
│ │ │ ├── Option.tsx
│ │ │ ├── OptionNative.tsx
│ │ │ └── OptionTypeProvider.tsx
│ │ ├── PageMetaTitle
│ │ │ ├── PageMetaTilteNative.tsx
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── PageMetaTitle.spec.ts
│ │ │ └── PageMetaTitle.tsx
│ │ ├── Pages
│ │ │ ├── Page.md
│ │ │ ├── Pages.md
│ │ │ ├── Pages.module.scss
│ │ │ ├── Pages.tsx
│ │ │ └── PagesNative.tsx
│ │ ├── Pagination
│ │ │ ├── Pagination.md
│ │ │ ├── Pagination.module.scss
│ │ │ ├── Pagination.spec.ts
│ │ │ ├── Pagination.tsx
│ │ │ └── PaginationNative.tsx
│ │ ├── PositionedContainer
│ │ │ ├── PositionedContainer.module.scss
│ │ │ ├── PositionedContainer.tsx
│ │ │ └── PositionedContainerNative.tsx
│ │ ├── ProfileMenu
│ │ │ ├── ProfileMenu.module.scss
│ │ │ └── ProfileMenu.tsx
│ │ ├── ProgressBar
│ │ │ ├── ProgressBar.md
│ │ │ ├── ProgressBar.module.scss
│ │ │ ├── ProgressBar.spec.ts
│ │ │ ├── ProgressBar.tsx
│ │ │ └── ProgressBarNative.tsx
│ │ ├── Queue
│ │ │ ├── Queue.md
│ │ │ ├── Queue.spec.ts
│ │ │ ├── Queue.tsx
│ │ │ ├── queueActions.ts
│ │ │ └── QueueNative.tsx
│ │ ├── RadioGroup
│ │ │ ├── RadioGroup.md
│ │ │ ├── RadioGroup.module.scss
│ │ │ ├── RadioGroup.spec.ts
│ │ │ ├── RadioGroup.tsx
│ │ │ ├── RadioGroupNative.tsx
│ │ │ ├── RadioItem.tsx
│ │ │ └── RadioItemNative.tsx
│ │ ├── RealTimeAdapter
│ │ │ ├── RealTimeAdapter.tsx
│ │ │ └── RealTimeAdapterNative.tsx
│ │ ├── Redirect
│ │ │ ├── Redirect.md
│ │ │ ├── Redirect.spec.ts
│ │ │ └── Redirect.tsx
│ │ ├── ResponsiveBar
│ │ │ ├── README.md
│ │ │ ├── ResponsiveBar.md
│ │ │ ├── ResponsiveBar.module.scss
│ │ │ ├── ResponsiveBar.spec.ts
│ │ │ ├── ResponsiveBar.tsx
│ │ │ └── ResponsiveBarNative.tsx
│ │ ├── Select
│ │ │ ├── HiddenOption.tsx
│ │ │ ├── OptionContext.ts
│ │ │ ├── Select.md
│ │ │ ├── Select.module.scss
│ │ │ ├── Select.spec.ts
│ │ │ ├── Select.tsx
│ │ │ ├── SelectContext.tsx
│ │ │ └── SelectNative.tsx
│ │ ├── SelectionStore
│ │ │ ├── SelectionStore.md
│ │ │ ├── SelectionStore.tsx
│ │ │ └── SelectionStoreNative.tsx
│ │ ├── Slider
│ │ │ ├── Slider.md
│ │ │ ├── Slider.module.scss
│ │ │ ├── Slider.spec.ts
│ │ │ ├── Slider.tsx
│ │ │ └── SliderNative.tsx
│ │ ├── Slot
│ │ │ ├── Slot.md
│ │ │ ├── Slot.spec.ts
│ │ │ └── Slot.ts
│ │ ├── SlotItem.tsx
│ │ ├── SpaceFiller
│ │ │ ├── SpaceFiller.md
│ │ │ ├── SpaceFiller.module.scss
│ │ │ ├── SpaceFiller.spec.ts
│ │ │ ├── SpaceFiller.tsx
│ │ │ └── SpaceFillerNative.tsx
│ │ ├── Spinner
│ │ │ ├── Spinner.md
│ │ │ ├── Spinner.module.scss
│ │ │ ├── Spinner.spec.ts
│ │ │ ├── Spinner.tsx
│ │ │ └── SpinnerNative.tsx
│ │ ├── Splitter
│ │ │ ├── HSplitter.md
│ │ │ ├── HSplitter.spec.ts
│ │ │ ├── Splitter.md
│ │ │ ├── Splitter.module.scss
│ │ │ ├── Splitter.spec.ts
│ │ │ ├── Splitter.tsx
│ │ │ ├── SplitterNative.tsx
│ │ │ ├── utils.ts
│ │ │ ├── VSplitter.md
│ │ │ └── VSplitter.spec.ts
│ │ ├── Stack
│ │ │ ├── CHStack.md
│ │ │ ├── CHStack.spec.ts
│ │ │ ├── CVStack.md
│ │ │ ├── CVStack.spec.ts
│ │ │ ├── HStack.md
│ │ │ ├── HStack.spec.ts
│ │ │ ├── Stack.md
│ │ │ ├── Stack.module.scss
│ │ │ ├── Stack.spec.ts
│ │ │ ├── Stack.tsx
│ │ │ ├── StackNative.tsx
│ │ │ ├── VStack.md
│ │ │ └── VStack.spec.ts
│ │ ├── StickyBox
│ │ │ ├── StickyBox.md
│ │ │ ├── StickyBox.module.scss
│ │ │ ├── StickyBox.tsx
│ │ │ └── StickyBoxNative.tsx
│ │ ├── Switch
│ │ │ ├── Switch.md
│ │ │ ├── Switch.spec.ts
│ │ │ └── Switch.tsx
│ │ ├── Table
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── react-table-config.d.ts
│ │ │ ├── Table.md
│ │ │ ├── Table.module.scss
│ │ │ ├── Table.spec.ts
│ │ │ ├── Table.tsx
│ │ │ ├── TableNative.tsx
│ │ │ └── useRowSelection.tsx
│ │ ├── TableOfContents
│ │ │ ├── TableOfContents.module.scss
│ │ │ ├── TableOfContents.spec.ts
│ │ │ ├── TableOfContents.tsx
│ │ │ └── TableOfContentsNative.tsx
│ │ ├── Tabs
│ │ │ ├── TabContext.tsx
│ │ │ ├── TabItem.md
│ │ │ ├── TabItem.tsx
│ │ │ ├── TabItemNative.tsx
│ │ │ ├── Tabs.md
│ │ │ ├── Tabs.module.scss
│ │ │ ├── Tabs.spec.ts
│ │ │ ├── Tabs.tsx
│ │ │ └── TabsNative.tsx
│ │ ├── Text
│ │ │ ├── Text.md
│ │ │ ├── Text.module.scss
│ │ │ ├── Text.spec.ts
│ │ │ ├── Text.tsx
│ │ │ └── TextNative.tsx
│ │ ├── TextArea
│ │ │ ├── TextArea.md
│ │ │ ├── TextArea.module.scss
│ │ │ ├── TextArea.spec.ts
│ │ │ ├── TextArea.tsx
│ │ │ ├── TextAreaNative.tsx
│ │ │ ├── TextAreaResizable.tsx
│ │ │ └── useComposedRef.ts
│ │ ├── TextBox
│ │ │ ├── TextBox.md
│ │ │ ├── TextBox.module.scss
│ │ │ ├── TextBox.spec.ts
│ │ │ ├── TextBox.tsx
│ │ │ └── TextBoxNative.tsx
│ │ ├── Theme
│ │ │ ├── NotificationToast.tsx
│ │ │ ├── Theme.md
│ │ │ ├── Theme.module.scss
│ │ │ ├── Theme.spec.ts
│ │ │ ├── Theme.tsx
│ │ │ └── ThemeNative.tsx
│ │ ├── TimeInput
│ │ │ ├── TimeInput.md
│ │ │ ├── TimeInput.module.scss
│ │ │ ├── TimeInput.spec.ts
│ │ │ ├── TimeInput.tsx
│ │ │ ├── TimeInputNative.tsx
│ │ │ └── utils.ts
│ │ ├── Timer
│ │ │ ├── Timer.md
│ │ │ ├── Timer.spec.ts
│ │ │ ├── Timer.tsx
│ │ │ └── TimerNative.tsx
│ │ ├── Toggle
│ │ │ ├── Toggle.module.scss
│ │ │ └── Toggle.tsx
│ │ ├── ToneChangerButton
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneChangerButton.spec.ts
│ │ │ └── ToneChangerButton.tsx
│ │ ├── ToneSwitch
│ │ │ ├── ToneSwitch.md
│ │ │ ├── ToneSwitch.module.scss
│ │ │ ├── ToneSwitch.spec.ts
│ │ │ ├── ToneSwitch.tsx
│ │ │ └── ToneSwitchNative.tsx
│ │ ├── Tooltip
│ │ │ ├── Tooltip.md
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.spec.ts
│ │ │ ├── Tooltip.tsx
│ │ │ └── TooltipNative.tsx
│ │ ├── Tree
│ │ │ ├── testData.ts
│ │ │ ├── Tree-dynamic.spec.ts
│ │ │ ├── Tree-icons.spec.ts
│ │ │ ├── Tree.md
│ │ │ ├── Tree.spec.ts
│ │ │ ├── TreeComponent.module.scss
│ │ │ ├── TreeComponent.tsx
│ │ │ └── TreeNative.tsx
│ │ ├── TreeDisplay
│ │ │ ├── TreeDisplay.md
│ │ │ ├── TreeDisplay.module.scss
│ │ │ ├── TreeDisplay.tsx
│ │ │ └── TreeDisplayNative.tsx
│ │ ├── ValidationSummary
│ │ │ ├── ValidationSummary.module.scss
│ │ │ └── ValidationSummary.tsx
│ │ └── VisuallyHidden.tsx
│ ├── components-core
│ │ ├── abstractions
│ │ │ ├── ComponentRenderer.ts
│ │ │ ├── LoaderRenderer.ts
│ │ │ ├── standalone.ts
│ │ │ └── treeAbstractions.ts
│ │ ├── action
│ │ │ ├── actions.ts
│ │ │ ├── APICall.tsx
│ │ │ ├── FileDownloadAction.tsx
│ │ │ ├── FileUploadAction.tsx
│ │ │ ├── NavigateAction.tsx
│ │ │ └── TimedAction.tsx
│ │ ├── ApiBoundComponent.tsx
│ │ ├── appContext
│ │ │ ├── date-functions.ts
│ │ │ ├── math-function.ts
│ │ │ └── misc-utils.ts
│ │ ├── AppContext.tsx
│ │ ├── behaviors
│ │ │ ├── Behavior.tsx
│ │ │ └── CoreBehaviors.tsx
│ │ ├── component-hooks.ts
│ │ ├── ComponentDecorator.tsx
│ │ ├── ComponentViewer.tsx
│ │ ├── CompoundComponent.tsx
│ │ ├── constants.ts
│ │ ├── DebugViewProvider.tsx
│ │ ├── descriptorHelper.ts
│ │ ├── devtools
│ │ │ ├── InspectorDialog.module.scss
│ │ │ ├── InspectorDialog.tsx
│ │ │ └── InspectorDialogVisibilityContext.tsx
│ │ ├── EngineError.ts
│ │ ├── event-handlers.ts
│ │ ├── InspectorButton.module.scss
│ │ ├── InspectorContext.tsx
│ │ ├── interception
│ │ │ ├── abstractions.ts
│ │ │ ├── ApiInterceptor.ts
│ │ │ ├── ApiInterceptorProvider.tsx
│ │ │ ├── apiInterceptorWorker.ts
│ │ │ ├── Backend.ts
│ │ │ ├── Errors.ts
│ │ │ ├── IndexedDb.ts
│ │ │ ├── initMock.ts
│ │ │ ├── InMemoryDb.ts
│ │ │ ├── ReadonlyCollection.ts
│ │ │ └── useApiInterceptorContext.tsx
│ │ ├── loader
│ │ │ ├── ApiLoader.tsx
│ │ │ ├── DataLoader.tsx
│ │ │ ├── ExternalDataLoader.tsx
│ │ │ ├── Loader.tsx
│ │ │ ├── MockLoaderRenderer.tsx
│ │ │ └── PageableLoader.tsx
│ │ ├── LoaderComponent.tsx
│ │ ├── markup-check.ts
│ │ ├── parts.ts
│ │ ├── renderers.ts
│ │ ├── rendering
│ │ │ ├── AppContent.tsx
│ │ │ ├── AppRoot.tsx
│ │ │ ├── AppWrapper.tsx
│ │ │ ├── buildProxy.ts
│ │ │ ├── collectFnVarDeps.ts
│ │ │ ├── ComponentAdapter.tsx
│ │ │ ├── ComponentWrapper.tsx
│ │ │ ├── Container.tsx
│ │ │ ├── containers.ts
│ │ │ ├── ContainerWrapper.tsx
│ │ │ ├── ErrorBoundary.module.scss
│ │ │ ├── ErrorBoundary.tsx
│ │ │ ├── InvalidComponent.module.scss
│ │ │ ├── InvalidComponent.tsx
│ │ │ ├── nodeUtils.ts
│ │ │ ├── reducer.ts
│ │ │ ├── renderChild.tsx
│ │ │ ├── StandaloneComponent.tsx
│ │ │ ├── StateContainer.tsx
│ │ │ ├── UnknownComponent.module.scss
│ │ │ ├── UnknownComponent.tsx
│ │ │ └── valueExtractor.ts
│ │ ├── reportEngineError.ts
│ │ ├── RestApiProxy.ts
│ │ ├── script-runner
│ │ │ ├── asyncProxy.ts
│ │ │ ├── AttributeValueParser.ts
│ │ │ ├── bannedFunctions.ts
│ │ │ ├── BindingTreeEvaluationContext.ts
│ │ │ ├── eval-tree-async.ts
│ │ │ ├── eval-tree-common.ts
│ │ │ ├── eval-tree-sync.ts
│ │ │ ├── ParameterParser.ts
│ │ │ ├── process-statement-async.ts
│ │ │ ├── process-statement-common.ts
│ │ │ ├── process-statement-sync.ts
│ │ │ ├── ScriptingSourceTree.ts
│ │ │ ├── simplify-expression.ts
│ │ │ ├── statement-queue.ts
│ │ │ └── visitors.ts
│ │ ├── StandaloneApp.tsx
│ │ ├── StandaloneExtensionManager.ts
│ │ ├── TableOfContentsContext.tsx
│ │ ├── theming
│ │ │ ├── _themes.scss
│ │ │ ├── component-layout-resolver.ts
│ │ │ ├── extendThemeUtils.ts
│ │ │ ├── hvar.ts
│ │ │ ├── layout-resolver.ts
│ │ │ ├── parse-layout-props.ts
│ │ │ ├── StyleContext.tsx
│ │ │ ├── StyleRegistry.ts
│ │ │ ├── ThemeContext.tsx
│ │ │ ├── ThemeProvider.tsx
│ │ │ ├── themes
│ │ │ │ ├── base-utils.ts
│ │ │ │ ├── palette.ts
│ │ │ │ ├── root.ts
│ │ │ │ ├── solid.ts
│ │ │ │ ├── theme-colors.ts
│ │ │ │ └── xmlui.ts
│ │ │ ├── themeVars.module.scss
│ │ │ ├── themeVars.ts
│ │ │ ├── transformThemeVars.ts
│ │ │ └── utils.ts
│ │ ├── utils
│ │ │ ├── actionUtils.ts
│ │ │ ├── audio-utils.ts
│ │ │ ├── base64-utils.ts
│ │ │ ├── compound-utils.ts
│ │ │ ├── css-utils.ts
│ │ │ ├── DataLoaderQueryKeyGenerator.ts
│ │ │ ├── date-utils.ts
│ │ │ ├── extractParam.ts
│ │ │ ├── hooks.tsx
│ │ │ ├── LruCache.ts
│ │ │ ├── mergeProps.ts
│ │ │ ├── misc.ts
│ │ │ ├── request-params.ts
│ │ │ ├── statementUtils.ts
│ │ │ └── treeUtils.ts
│ │ └── xmlui-parser.ts
│ ├── index-standalone.ts
│ ├── index.scss
│ ├── index.ts
│ ├── language-server
│ │ ├── server-common.ts
│ │ ├── server-web-worker.ts
│ │ ├── server.ts
│ │ ├── services
│ │ │ ├── common
│ │ │ │ ├── docs-generation.ts
│ │ │ │ ├── lsp-utils.ts
│ │ │ │ ├── metadata-utils.ts
│ │ │ │ └── syntax-node-utilities.ts
│ │ │ ├── completion.ts
│ │ │ ├── diagnostic.ts
│ │ │ ├── format.ts
│ │ │ └── hover.ts
│ │ └── xmlui-metadata-generated.js
│ ├── logging
│ │ ├── LoggerContext.tsx
│ │ ├── LoggerInitializer.tsx
│ │ ├── LoggerService.ts
│ │ └── xmlui.ts
│ ├── logo.svg
│ ├── parsers
│ │ ├── common
│ │ │ ├── GenericToken.ts
│ │ │ ├── InputStream.ts
│ │ │ └── utils.ts
│ │ ├── scripting
│ │ │ ├── code-behind-collect.ts
│ │ │ ├── Lexer.ts
│ │ │ ├── modules.ts
│ │ │ ├── Parser.ts
│ │ │ ├── ParserError.ts
│ │ │ ├── ScriptingNodeTypes.ts
│ │ │ ├── TokenTrait.ts
│ │ │ ├── TokenType.ts
│ │ │ └── tree-visitor.ts
│ │ ├── style-parser
│ │ │ ├── errors.ts
│ │ │ ├── source-tree.ts
│ │ │ ├── StyleInputStream.ts
│ │ │ ├── StyleLexer.ts
│ │ │ ├── StyleParser.ts
│ │ │ └── tokens.ts
│ │ └── xmlui-parser
│ │ ├── CharacterCodes.ts
│ │ ├── diagnostics.ts
│ │ ├── fileExtensions.ts
│ │ ├── index.ts
│ │ ├── lint.ts
│ │ ├── parser.ts
│ │ ├── ParserError.ts
│ │ ├── scanner.ts
│ │ ├── syntax-kind.ts
│ │ ├── syntax-node.ts
│ │ ├── transform.ts
│ │ ├── utils.ts
│ │ ├── xmlui-serializer.ts
│ │ └── xmlui-tree.ts
│ ├── react-app-env.d.ts
│ ├── syntax
│ │ ├── monaco
│ │ │ ├── grammar.monacoLanguage.ts
│ │ │ ├── index.ts
│ │ │ ├── xmlui-dark.ts
│ │ │ ├── xmlui-light.ts
│ │ │ └── xmluiscript.monacoLanguage.ts
│ │ └── textMate
│ │ ├── index.ts
│ │ ├── xmlui-dark.json
│ │ ├── xmlui-light.json
│ │ ├── xmlui.json
│ │ └── xmlui.tmLanguage.json
│ ├── testing
│ │ ├── assertions.ts
│ │ ├── component-test-helpers.ts
│ │ ├── ComponentDrivers.ts
│ │ ├── drivers
│ │ │ ├── DateInputDriver.ts
│ │ │ ├── index.ts
│ │ │ ├── ModalDialogDriver.ts
│ │ │ ├── NumberBoxDriver.ts
│ │ │ ├── TextBoxDriver.ts
│ │ │ ├── TimeInputDriver.ts
│ │ │ ├── TimerDriver.ts
│ │ │ └── TreeDriver.ts
│ │ ├── fixtures.ts
│ │ ├── index.ts
│ │ ├── infrastructure
│ │ │ ├── index.html
│ │ │ ├── main.tsx
│ │ │ ├── public
│ │ │ │ ├── mockServiceWorker.js
│ │ │ │ ├── resources
│ │ │ │ │ ├── bell.svg
│ │ │ │ │ ├── box.svg
│ │ │ │ │ ├── doc.svg
│ │ │ │ │ ├── eye.svg
│ │ │ │ │ ├── flower-640x480.jpg
│ │ │ │ │ ├── sun.svg
│ │ │ │ │ ├── test-image-100x100.jpg
│ │ │ │ │ └── txt.svg
│ │ │ │ └── serve.json
│ │ │ └── TestBed.tsx
│ │ └── themed-app-test-helpers.ts
│ └── vite-env.d.ts
├── tests
│ ├── components
│ │ ├── CodeBlock
│ │ │ └── hightlight-code.test.ts
│ │ ├── playground-pattern.test.ts
│ │ └── Tree
│ │ └── Tree-states.test.ts
│ ├── components-core
│ │ ├── abstractions
│ │ │ └── treeAbstractions.test.ts
│ │ ├── container
│ │ │ └── buildProxy.test.ts
│ │ ├── interception
│ │ │ ├── orderBy.test.ts
│ │ │ ├── ReadOnlyCollection.test.ts
│ │ │ └── request-param-converter.test.ts
│ │ ├── scripts-runner
│ │ │ ├── AttributeValueParser.test.ts
│ │ │ ├── eval-tree-arrow-async.test.ts
│ │ │ ├── eval-tree-arrow.test.ts
│ │ │ ├── eval-tree-func-decl-async.test.ts
│ │ │ ├── eval-tree-func-decl.test.ts
│ │ │ ├── eval-tree-pre-post.test.ts
│ │ │ ├── eval-tree-regression.test.ts
│ │ │ ├── eval-tree.test.ts
│ │ │ ├── function-proxy.test.ts
│ │ │ ├── parser-regression.test.ts
│ │ │ ├── process-event.test.ts
│ │ │ ├── process-function.test.ts
│ │ │ ├── process-implicit-context.test.ts
│ │ │ ├── process-statement-asgn.test.ts
│ │ │ ├── process-statement-destruct.test.ts
│ │ │ ├── process-statement-regs.test.ts
│ │ │ ├── process-statement-sync.test.ts
│ │ │ ├── process-statement.test.ts
│ │ │ ├── process-switch-sync.test.ts
│ │ │ ├── process-switch.test.ts
│ │ │ ├── process-try-sync.test.ts
│ │ │ ├── process-try.test.ts
│ │ │ └── test-helpers.ts
│ │ ├── test-metadata-handler.ts
│ │ ├── theming
│ │ │ ├── border-segments.test.ts
│ │ │ ├── component-layout.resolver.test.ts
│ │ │ ├── layout-property-parser.test.ts
│ │ │ ├── layout-resolver.test.ts
│ │ │ ├── layout-resolver2.test.ts
│ │ │ ├── layout-vp-override.test.ts
│ │ │ └── padding-segments.test.ts
│ │ └── utils
│ │ ├── date-utils.test.ts
│ │ ├── format-human-elapsed-time.test.ts
│ │ └── LruCache.test.ts
│ ├── language-server
│ │ ├── completion.test.ts
│ │ ├── format.test.ts
│ │ ├── hover.test.ts
│ │ └── mockData.ts
│ └── parsers
│ ├── common
│ │ └── input-stream.test.ts
│ ├── markdown
│ │ └── parse-binding-expression.test.ts
│ ├── parameter-parser.test.ts
│ ├── paremeter-parser.test.ts
│ ├── scripting
│ │ ├── eval-tree-arrow.test.ts
│ │ ├── eval-tree-pre-post.test.ts
│ │ ├── eval-tree.test.ts
│ │ ├── function-proxy.test.ts
│ │ ├── lexer-literals.test.ts
│ │ ├── lexer-misc.test.ts
│ │ ├── module-parse.test.ts
│ │ ├── parser-arrow.test.ts
│ │ ├── parser-assignments.test.ts
│ │ ├── parser-binary.test.ts
│ │ ├── parser-destructuring.test.ts
│ │ ├── parser-errors.test.ts
│ │ ├── parser-expressions.test.ts
│ │ ├── parser-function.test.ts
│ │ ├── parser-literals.test.ts
│ │ ├── parser-primary.test.ts
│ │ ├── parser-regex.test.ts
│ │ ├── parser-statements.test.ts
│ │ ├── parser-unary.test.ts
│ │ ├── process-event.test.ts
│ │ ├── process-implicit-context.test.ts
│ │ ├── process-statement-asgn.test.ts
│ │ ├── process-statement-destruct.test.ts
│ │ ├── process-statement-regs.test.ts
│ │ ├── process-statement-sync.test.ts
│ │ ├── process-statement.test.ts
│ │ ├── process-switch-sync.test.ts
│ │ ├── process-switch.test.ts
│ │ ├── process-try-sync.test.ts
│ │ ├── process-try.test.ts
│ │ ├── simplify-expression.test.ts
│ │ ├── statement-hooks.test.ts
│ │ └── test-helpers.ts
│ ├── style-parser
│ │ ├── generateHvarChain.test.ts
│ │ ├── parseHVar.test.ts
│ │ ├── parser.test.ts
│ │ └── tokens.test.ts
│ └── xmlui
│ ├── lint.test.ts
│ ├── parser.test.ts
│ ├── scanner.test.ts
│ ├── transform.attr.test.ts
│ ├── transform.circular.test.ts
│ ├── transform.element.test.ts
│ ├── transform.errors.test.ts
│ ├── transform.escape.test.ts
│ ├── transform.regression.test.ts
│ ├── transform.script.test.ts
│ ├── transform.test.ts
│ └── xmlui.ts
├── tests-e2e
│ ├── api-bound-component-regression.spec.ts
│ ├── api-call-as-extracted-component.spec.ts
│ ├── assign-to-object-or-array-regression.spec.ts
│ ├── binding-regression.spec.ts
│ ├── children-as-template-context-vars.spec.ts
│ ├── compound-component.spec.ts
│ ├── context-vars-regression.spec.ts
│ ├── data-bindings.spec.ts
│ ├── datasource-and-api-usage-in-var.spec.ts
│ ├── datasource-direct-binding.spec.ts
│ ├── datasource-onLoaded-regression.spec.ts
│ ├── modify-array-item-regression.spec.ts
│ ├── namespaces.spec.ts
│ ├── push-to-array-regression.spec.ts
│ ├── screen-breakpoints.spec.ts
│ ├── scripting.spec.ts
│ ├── state-scope-in-pages.spec.ts
│ └── state-var-scopes.spec.ts
├── tsconfig.json
├── tsdown.config.ts
├── vite.config.ts
└── vitest.config.ts
```
# Files
--------------------------------------------------------------------------------
/xmlui/src/components/Button/Button.md:
--------------------------------------------------------------------------------
```markdown
1 | %-DESC-START
2 |
3 | **Key features:**
4 | - **Visual hierarchy**: Choose from `solid`, `outlined`, or `ghost` variants to indicate importance
5 | - **Theme colors**: Use `primary`, `secondary`, or `attention` colors for different action types
6 | - **Icon support**: Add icons before or after text, or create icon-only buttons
7 | - **Form integration**: Automatically handles form submission when used in forms
8 |
9 | %-DESC-END
10 |
11 | %-PROP-START autoFocus
12 |
13 | %-PROP-END
14 |
15 | %-PROP-START contentPosition
16 |
17 | ```xmlui-pg copy display name="Example: content position"
18 | <App>
19 | <Button width="200px" icon="drive" label="Button" contentPosition="center" />
20 | <Button width="200px" icon="drive" label="Button" contentPosition="start" />
21 | <Button width="200px" icon="drive" label="Button" contentPosition="end" />
22 | <Button width="200px" contentPosition="end">
23 | This is a nested text
24 | </Button>
25 | </App>
26 | ```
27 |
28 | %-PROP-END
29 |
30 | %-PROP-START icon
31 |
32 | ```xmlui-pg copy display name="Example: icon"
33 | <App>
34 | <HStack>
35 | <Button icon="drive" label="Let there be drive" />
36 | <Button icon="drive" />
37 | </HStack>
38 | </App>
39 | ```
40 |
41 | %-PROP-END
42 |
43 | %-PROP-START iconPosition
44 |
45 | ```xmlui-pg copy display name="Example: icon position"
46 | <App>
47 | <HStack>
48 | <Button icon="drive" label="Left" />
49 | <Button icon="drive" label="Right" iconPosition="right" />
50 | </HStack>
51 | <HStack>
52 | <Button icon="drive" label="Start" iconPosition="start" />
53 | <Button icon="drive" label="End" iconPosition="end" />
54 | </HStack>
55 | <HStack>
56 | <Button
57 | icon="drive"
58 | label="Start (right-to-left)"
59 | iconPosition="start"
60 | direction="rtl" />
61 | <Button
62 | icon="drive"
63 | label="End (right-to-left)"
64 | iconPosition="end"
65 | direction="rtl" />
66 | </HStack>
67 | </App>
68 | ```
69 |
70 | %-PROP-END
71 |
72 | %-PROP-START label
73 |
74 | ```xmlui-pg copy display name="Example: label"
75 | <App>
76 | <Button label="I am the button label" />
77 | <Button />
78 | <Button label="I am the button label">
79 | <Icon name="trash" />
80 | I am a text nested into Button
81 | </Button>
82 | </App>
83 | ```
84 |
85 | %-PROP-END
86 |
87 | %-PROP-START variant
88 |
89 | ```xmlui-pg copy display name="Example: variant"
90 | <App>
91 | <HStack>
92 | <Button label="default (solid)" />
93 | <Button label="solid" variant="solid" />
94 | <Button label="outlined" variant="outlined" />
95 | <Button label="ghost" variant="ghost" />
96 | </HStack>
97 | </App>
98 | ```
99 |
100 | %-PROP-END
101 |
102 | %-PROP-START themeColor
103 |
104 | ```xmlui-pg copy display name="Example: theme colors"
105 | <App>
106 | <HStack>
107 | <Button label="Button" themeColor="primary" />
108 | <Button label="Button" themeColor="secondary" />
109 | <Button label="Button" themeColor="attention" />
110 | </HStack>
111 | </App>
112 | ```
113 |
114 | %-PROP-END
115 |
116 | %-PROP-START enabled
117 |
118 | ```xmlui-pg copy display name="Example: enabled"
119 | <App>
120 | <HStack>
121 | <Button label="I am enabled (by default)" />
122 | <Button label="I am enabled explicitly" enabled="true" />
123 | <Button label="I am not enabled" enabled="false" />
124 | </HStack>
125 | </App>
126 | ```
127 |
128 | %-PROP-END
129 |
130 | %-PROP-START size
131 |
132 | ```xmlui-pg copy display name="Example: size"
133 | <App>
134 | <HStack>
135 | <Button icon="drive" label="default" />
136 | <Button icon="drive" label="extra-small" size="xs" />
137 | <Button icon="drive" label="small" size="sm" />
138 | <Button icon="drive" label="medium" size="md" />
139 | <Button icon="drive" label="large" size="lg" />
140 | </HStack>
141 | <HStack>
142 | <Button label="default" />
143 | <Button label="extra-small" size="xs" />
144 | <Button label="small" size="sm" />
145 | <Button label="medium" size="md" />
146 | <Button label="large" size="lg" />
147 | </HStack>
148 | </App>
149 | ```
150 |
151 | %-PROP-END
152 |
153 | %-EVENT-START click
154 |
155 | ```xmlui-pg copy display name="Example: click"
156 | <App>
157 | <Button label="Click me!" onClick="toast('Button clicked')" />
158 | </App>
159 | ```
160 |
161 | %-EVENT-END
162 |
163 | %-EVENT-START gotFocus
164 |
165 | ```xmlui-pg copy display name="Example: gotFocus"
166 | <App var.text="No event" >
167 | <HStack verticalAlignment="center" >
168 | <Button label="First, click me!"
169 | onGotFocus="text = 'Focus received'"
170 | onLostFocus="text = 'Focus lost'" />
171 | <Text value="Then, me!"/>
172 | </HStack>
173 | <Text value="{text}" />
174 | </App>
175 | ```
176 |
177 | %-EVENT-END
178 |
179 | %-EVENT-START lostFocus
180 |
181 | (See the example above)
182 |
183 | %-EVENT-END
184 |
185 | %-STYLE-START
186 |
187 | ### Fixed width and height
188 |
189 | Using a set of buttons with a fixed width or height is often helpful. So `Button` supports these theme variables:
190 | - `width-Button`
191 | - `height-Button`
192 |
193 | Avoid setting the `width-Button` and `height-Button` styles in the theme definition. Instead, wrap the affected button group into a `Theme` component as in the following example:
194 |
195 | ```xmlui-pg copy name="Example: Buttons with fixed width"
196 | <App>
197 | <HStack>
198 | <Theme width-Button="120px">
199 | <Button label="Short" />
200 | <Button label="Longer" />
201 | <Button label="Longest" />
202 | <Button label="Disabled" enabled="false" />
203 | <Button label="Outlined" variant="outlined" />
204 | </Theme>
205 | </HStack>
206 | </App>
207 | ```
208 |
209 | %-STYLE-END
210 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Accordion/Accordion.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import styles from "./Accordion.module.scss";
2 |
3 | import { createComponentRenderer } from "../../components-core/renderers";
4 | import { parseScssVar } from "../../components-core/theming/themeVars";
5 | import {
6 | createMetadata,
7 | dCollapse,
8 | dDidChange,
9 | dExpand,
10 | dExpanded,
11 | dFocus,
12 | } from "../../components/metadata-helpers";
13 | import { triggerPositionNames } from "../../components/abstractions";
14 | import { AccordionComponent, defaultProps } from "./AccordionNative";
15 |
16 | const COMP = "Accordion";
17 |
18 | // See reference implementation here: https://getbootstrap.com/docs/5.3/components/accordion/
19 | // Make the header focusable, handle ARIA attributes, and manage the state of the accordion.
20 |
21 | export const AccordionMd = createMetadata({
22 | status: "in progress",
23 | description:
24 | `(**NOT IMPLEMENTED YET**) The \`${COMP}\` component is a collapsible container that toggles ` +
25 | `the display of content sections. It helps organize information by expanding or collapsing it ` +
26 | `based on user interaction.`,
27 | props: {
28 | triggerPosition: {
29 | description:
30 | `This property indicates the position where the trigger icon should be displayed. The \`start\` ` +
31 | `value signs the trigger is before the header text (template), and \`end\` indicates that it ` +
32 | `follows the header.`,
33 | defaultValue: defaultProps.triggerPosition,
34 | valueType: "string",
35 | availableValues: triggerPositionNames,
36 | },
37 | collapsedIcon: {
38 | description:
39 | "This property is the name of the icon that is displayed when the accordion is " +
40 | "collapsed. This property is the name of the icon that is displayed when the accordion is expanded. If not provided, a chevron-down icon is used.",
41 | valueType: "string",
42 | defaultValue: defaultProps.collapsedIcon,
43 | },
44 | expandedIcon: {
45 | description:
46 | "This property is the name of the icon that is displayed when the accordion is " +
47 | "expanded. If not provided, a chevron-up icon is used.",
48 | valueType: "string",
49 | },
50 | hideIcon: {
51 | description: `This property indicates that the trigger icon is not displayed (\`true\`).`,
52 | defaultValue: defaultProps.hideIcon,
53 | valueType: "boolean",
54 | },
55 | rotateExpanded: {
56 | description: `This optional property defines the rotation angle of the expanded icon (relative to the collapsed icon).`,
57 | valueType: "string",
58 | defaultValue: defaultProps.rotateExpanded,
59 | },
60 | },
61 | events: {
62 | displayDidChange: dDidChange(COMP),
63 | },
64 | apis: {
65 | expanded: {
66 | description: `This method returns \`true\` if the accordion is expanded, and \`false\` if it is collapsed.`,
67 | signature: "get expanded(): boolean",
68 | },
69 | expand: {
70 | description: `This method expands the accordion, making its content visible.`,
71 | signature: "expand()",
72 | },
73 | collapse: {
74 | description: `This method collapses the accordion, hiding its content.`,
75 | signature: "collapse()",
76 | },
77 | toggle: {
78 | description: `This method toggles the state of the ${COMP} between expanded and collapsed.`,
79 | signature: "toggle()",
80 | },
81 | focus: dFocus(COMP),
82 | },
83 | themeVars: parseScssVar(styles.themeVars),
84 | defaultThemeVars: {
85 | [`paddingHorizontal-header-${COMP}`]: "$space-3",
86 | [`paddingVertical-header-${COMP}`]: "$space-3",
87 | [`verticalAlignment-header-${COMP}`]: "center",
88 | [`fontSize-header-${COMP}`]: "$fontSize-base",
89 | [`fontWeight-header-${COMP}`]: "$fontWeight-normal",
90 | [`fontFamily-header-${COMP}`]: "$fontFamily",
91 | [`border-${COMP}`]: "0px solid $borderColor",
92 | [`width-icon-${COMP}`]: "",
93 | [`height-icon-${COMP}`]: "",
94 | [`backgroundColor-header-${COMP}`]: "$color-primary-500",
95 | [`backgroundColor-header-${COMP}-hover`]: "$color-primary-400",
96 | [`color-header-${COMP}`]: "$color-surface-50",
97 | [`color-content-${COMP}`]: "$textColor-primary",
98 | [`backgroundColor-content-${COMP}`]: "transparent",
99 | [`color-icon-${COMP}`]: "$color-surface-50",
100 | },
101 | });
102 |
103 | export const accordionComponentRenderer = createComponentRenderer(
104 | COMP,
105 | AccordionMd,
106 | ({ node, renderChild, extractValue, lookupEventHandler, registerComponentApi, className }) => {
107 | return (
108 | <AccordionComponent
109 | className={className}
110 | triggerPosition={extractValue(node.props?.triggerPosition)}
111 | collapsedIcon={extractValue(node.props.collapsedIcon)}
112 | expandedIcon={extractValue(node.props.expandedIcon)}
113 | hideIcon={extractValue.asOptionalBoolean(node.props.hideIcon)}
114 | rotateExpanded={extractValue(node.props.rotateExpanded)}
115 | onDisplayDidChange={lookupEventHandler("displayDidChange")}
116 | registerComponentApi={registerComponentApi}
117 | >
118 | {renderChild(node.children)}
119 | </AccordionComponent>
120 | );
121 | },
122 | );
123 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Checkbox/Checkbox.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import styles from "../Toggle/Toggle.module.scss";
2 |
3 | import { createComponentRenderer } from "../../components-core/renderers";
4 | import { parseScssVar } from "../../components-core/theming/themeVars";
5 | import {
6 | createMetadata,
7 | dAutoFocus,
8 | dClick,
9 | dComponent,
10 | dDidChange,
11 | dEnabled,
12 | dGotFocus,
13 | dIndeterminate,
14 | dInitialValue,
15 | dInternal,
16 | dLostFocus,
17 | dReadonly,
18 | dRequired,
19 | dValidationStatus,
20 | } from "../../components/metadata-helpers";
21 | import { defaultProps as toggleDefaultProps, Toggle } from "../Toggle/Toggle";
22 | import { MemoizedItem } from "../container-helpers";
23 |
24 | export const defaultProps = {
25 | ...toggleDefaultProps,
26 | labelPosition: "end",
27 | };
28 |
29 | const COMP = "Checkbox";
30 |
31 | export const CheckboxMd = createMetadata({
32 | status: "stable",
33 | description:
34 | "`Checkbox` allows users to make binary choices with a clickable box that shows " +
35 | "checked/unchecked states. It's essential for settings, preferences, multi-select " +
36 | "lists, and accepting terms or conditions.",
37 | parts: {
38 | label: {
39 | description: "The label displayed for the checkbox.",
40 | },
41 | input: {
42 | description: "The checkbox input area.",
43 | },
44 | },
45 | props: {
46 | indeterminate: dIndeterminate(toggleDefaultProps.indeterminate),
47 | required: dRequired(),
48 | initialValue: dInitialValue(toggleDefaultProps.initialValue),
49 | autoFocus: dAutoFocus(),
50 | readOnly: dReadonly(),
51 | enabled: dEnabled(),
52 | validationStatus: dValidationStatus(toggleDefaultProps.validationStatus),
53 | description: dInternal(
54 | `(*** NOT IMPLEMENTED YET ***) This optional property displays an alternate description ` +
55 | `of the ${COMP} besides its label.`,
56 | ),
57 | inputTemplate: dComponent("This property is used to define a custom checkbox input template"),
58 | },
59 | childrenAsTemplate: "inputTemplate",
60 | events: {
61 | click: dClick(COMP),
62 | gotFocus: dGotFocus(COMP),
63 | lostFocus: dLostFocus(COMP),
64 | didChange: dDidChange(COMP),
65 | },
66 | apis: {
67 | value: {
68 | description: `This method returns the current value of the ${COMP}.`,
69 | signature: "get value(): boolean",
70 | },
71 | setValue: {
72 | description: `This method sets the current value of the ${COMP}.`,
73 | signature: "set value(value: boolean): void",
74 | parameters: {
75 | value: "The new value to set for the checkbox.",
76 | },
77 | },
78 | },
79 | themeVars: parseScssVar(styles.themeVars),
80 | limitThemeVarsToComponent: true,
81 | defaultThemeVars: {
82 | [`borderColor-checked-${COMP}--error`]: `$borderColor-${COMP}--error`,
83 | [`backgroundColor-checked-${COMP}--error`]: `$borderColor-${COMP}--error`,
84 | [`borderColor-checked-${COMP}--warning`]: `$borderColor-${COMP}--warning`,
85 | [`backgroundColor-checked-${COMP}--warning`]: `$borderColor-${COMP}--warning`,
86 | [`borderColor-checked-${COMP}--success`]: `$borderColor-${COMP}--success`,
87 | [`backgroundColor-checked-${COMP}--success`]: `$borderColor-${COMP}--success`,
88 | [`backgroundColor-indicator-${COMP}`]: "$backgroundColor-primary",
89 | [`borderColor-checked-${COMP}`]: "$color-primary-500",
90 | [`backgroundColor-checked-${COMP}`]: "$color-primary-500",
91 | [`backgroundColor-${COMP}--disabled`]: "$color-surface-200",
92 | },
93 | });
94 |
95 | export const checkboxComponentRenderer = createComponentRenderer(
96 | COMP,
97 | CheckboxMd,
98 | ({
99 | node,
100 | extractValue,
101 | className,
102 | updateState,
103 | lookupEventHandler,
104 | state,
105 | registerComponentApi,
106 | renderChild,
107 | layoutContext,
108 | }) => {
109 | const inputTemplate = node.props.inputTemplate;
110 | return (
111 | <Toggle
112 | inputRenderer={
113 | inputTemplate
114 | ? (contextVars) => (
115 | <MemoizedItem
116 | contextVars={contextVars}
117 | node={inputTemplate}
118 | renderChild={renderChild}
119 | layoutContext={layoutContext}
120 | />
121 | )
122 | : undefined
123 | }
124 | enabled={extractValue.asOptionalBoolean(node.props.enabled)}
125 | className={className}
126 | initialValue={extractValue.asOptionalBoolean(
127 | node.props.initialValue,
128 | defaultProps.initialValue,
129 | )}
130 | value={state?.value}
131 | readOnly={extractValue.asOptionalBoolean(node.props.readOnly)}
132 | validationStatus={extractValue(node.props.validationStatus)}
133 | updateState={updateState}
134 | onClick={lookupEventHandler("click")}
135 | onDidChange={lookupEventHandler("didChange")}
136 | onFocus={lookupEventHandler("gotFocus")}
137 | onBlur={lookupEventHandler("lostFocus")}
138 | required={extractValue.asOptionalBoolean(node.props.required)}
139 | indeterminate={extractValue.asOptionalBoolean(node.props.indeterminate)}
140 | registerComponentApi={registerComponentApi}
141 | autoFocus={extractValue.asOptionalBoolean(node.props.autoFocus)}
142 | />
143 | );
144 | },
145 | );
146 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Charts/RadarChart/RadarChart.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { RadarChart, defaultProps } from "./RadarChartNative";
2 | import { createComponentRenderer } from "../../../components-core/renderers";
3 | import { createMetadata } from "../../metadata-helpers";
4 | import { MemoizedItem } from "../../container-helpers";
5 |
6 | const COMP = "RadarChart";
7 |
8 | export const RadarChartMd = createMetadata({
9 | status: "experimental",
10 | description: "Interactive radar chart for displaying multivariate data in a two-dimensional chart of three or more quantitative variables",
11 | docFolder: "Charts/RadarChart",
12 |
13 | props: {
14 | data: {
15 | description:
16 | "This property is used to provide the component with data to display. " +
17 | "The data needs to be an array of objects.",
18 | },
19 | dataKeys: {
20 | description:
21 | "This property specifies the keys in the data objects that should be used for rendering the chart elements. " +
22 | "E.g. 'value' or 'amount'.",
23 | valueType: "string",
24 | },
25 | nameKey: {
26 | description:
27 | "Specifies the key in the data objects that will be used to label the different data series.",
28 | valueType: "string",
29 | },
30 | hideGrid: {
31 | description:
32 | "Determines whether the polar grid should be hidden. If set to `true`, the grid will not be rendered.",
33 | valueType: "boolean",
34 | defaultValue: defaultProps.hideGrid,
35 | },
36 | hideAngleAxis: {
37 | description:
38 | "Determines whether the angle axis should be hidden. If set to `true`, the angle axis will not be rendered.",
39 | valueType: "boolean",
40 | defaultValue: defaultProps.hideAngleAxis,
41 | },
42 | hideRadiusAxis: {
43 | description:
44 | "Determines whether the radius axis should be hidden. If set to `true`, the radius axis will not be rendered.",
45 | valueType: "boolean",
46 | defaultValue: defaultProps.hideRadiusAxis,
47 | },
48 | hideTooltip: {
49 | description:
50 | "Determines whether the tooltip should be hidden. If set to `true`, the tooltip will not be rendered.",
51 | valueType: "boolean",
52 | defaultValue: defaultProps.hideTooltip,
53 | },
54 | showLegend: {
55 | description:
56 | "Determines whether the legend should be shown. If set to `true`, the legend will be rendered.",
57 | valueType: "boolean",
58 | defaultValue: defaultProps.showLegend,
59 | },
60 | filled: {
61 | description:
62 | "Determines whether the radar areas should be filled. If set to `true`, areas will be filled with color.",
63 | valueType: "boolean",
64 | defaultValue: defaultProps.filled,
65 | },
66 | strokeWidth: {
67 | description:
68 | "Sets the stroke width for the radar lines. Higher values create thicker lines.",
69 | valueType: "number",
70 | defaultValue: defaultProps.strokeWidth,
71 | },
72 | fillOpacity: {
73 | description:
74 | "Sets the fill opacity for the radar areas when filled is true. Value between 0 and 1.",
75 | valueType: "number",
76 | defaultValue: defaultProps.fillOpacity,
77 | },
78 | tooltipTemplate: {
79 | description: "This property allows replacing the default template to display a tooltip.",
80 | },
81 | },
82 |
83 | events: {
84 | // Standard chart events - customize based on chart type
85 | },
86 |
87 | apis: {
88 | // Chart-specific APIs if needed
89 | },
90 |
91 | contextVars: {
92 | // Add context variables if needed
93 | },
94 | });
95 |
96 | // Component renderer
97 | export const radarChartComponentRenderer = createComponentRenderer(
98 | COMP,
99 | RadarChartMd,
100 | ({ extractValue, node, className, renderChild }: any) => {
101 | return (
102 | <RadarChart
103 | className={className}
104 | data={extractValue(node.props?.data)}
105 | nameKey={extractValue(node.props?.nameKey)}
106 | dataKeys={extractValue(node.props?.dataKeys)}
107 | hideGrid={extractValue.asOptionalBoolean(node.props?.hideGrid)}
108 | hideAngleAxis={extractValue.asOptionalBoolean(node.props?.hideAngleAxis)}
109 | hideRadiusAxis={extractValue.asOptionalBoolean(node.props?.hideRadiusAxis)}
110 | hideTooltip={extractValue.asOptionalBoolean(node.props?.hideTooltip)}
111 | showLegend={extractValue.asOptionalBoolean(node.props?.showLegend)}
112 | filled={extractValue.asOptionalBoolean(node.props?.filled)}
113 | strokeWidth={extractValue.asOptionalNumber(node.props?.strokeWidth)}
114 | fillOpacity={extractValue.asOptionalNumber(node.props?.fillOpacity)}
115 | tooltipRenderer={
116 | node.props.tooltipTemplate
117 | ? (tooltipData) => {
118 | return (
119 | <MemoizedItem
120 | node={node.props.tooltipTemplate}
121 | item={tooltipData}
122 | contextVars={{
123 | $tooltip: tooltipData,
124 | }}
125 | renderChild={renderChild}
126 | />
127 | );
128 | }
129 | : undefined
130 | }
131 | >
132 | {renderChild(node.children)}
133 | </RadarChart>
134 | );
135 | },
136 | );
137 |
```
--------------------------------------------------------------------------------
/xmlui/dev-docs/next/tiptap-design-considerations.md:
--------------------------------------------------------------------------------
```markdown
1 | # Tiptap Design Considerations for XMLUI Markdown Interop
2 |
3 | ## Context
4 |
5 | XMLUI uses Markdown as the source of truth for all documentation and rich text content. The Markdown component supports a wide range of features, including GFM (GitHub Flavored Markdown) extensions, and maps Markdown/HTML tags to XMLUI's own React components for consistent theming and behavior.
6 |
7 | ## Interop Challenges
8 |
9 | - **Tiptap (rich editor) natively produces HTML, not Markdown.**
10 | - **Markdown is less expressive than HTML.** Some HTML features cannot be round-tripped to Markdown.
11 | - **XMLUI Markdown only supports a subset of HTML tags,** mapped via the HTMLTags component. Arbitrary HTML is not guaranteed to render.
12 |
13 | ## Design Options
14 |
15 | ### 1. Plain Markdown Editor
16 | - Simple `<textarea>` for raw Markdown editing.
17 | - No conversion needed; what the user sees is what is stored.
18 | - Power users can use all Markdown features.
19 |
20 | ### 2. Rich Editor Producing Markdown
21 | - Use Tiptap for WYSIWYG editing, but restrict features to those that map cleanly to Markdown and XMLUI's Markdown component.
22 | - On save, convert Tiptap's HTML output to Markdown (using a library like turndown).
23 | - On load, convert Markdown to HTML for editing (using marked or markdown-it).
24 | - Warn users about possible formatting loss if switching between modes.
25 |
26 | ## Supported Features
27 |
28 | | Feature/Tag | Markdown | HTML | XMLUI Markdown Support | Notes |
29 | |------------------|----------|-----------------------------|-----------------------|------------------------------|
30 | | Headings | Yes | `<h1>`-`<h6>` | Yes | Standard |
31 | | Bold/Italic | Yes | `<b>`, `<i>`, `<strong>`, `<em>` | Yes | Mapped to Text variants |
32 | | Lists | Yes | `<ul>`, `<ol>`, `<li>` | Yes | Standard |
33 | | Links | Yes | `<a>` | Yes | Mapped to LinkNative |
34 | | Code/Pre | Yes | `<code>`, `<pre>` | Yes | Mapped to Text/PreTag |
35 | | Tables | GFM | `<table>` | Yes (GFM) | Supported via remark-gfm |
36 | | Images | Yes | `<img>` | Yes | Standard |
37 | | Blockquote | Yes | `<blockquote>` | Yes | Standard |
38 | | Details/Section | No (MD) | `<details>`, `<section>` | Yes (custom) | Special handling |
39 | | Custom HTML | No | Most | No/Partial | Only mapped tags allowed |
40 |
41 | ## Best Practices
42 |
43 | - **Keep Markdown as the canonical format.**
44 | - **Restrict Tiptap features to those that map to XMLUI Markdown/HTMLTags.**
45 | - **Warn users about possible formatting loss when switching between rich/plain modes.**
46 | - **Test round-tripping** (Markdown → HTML → Markdown) for fidelity.
47 | - **Document any limitations or unsupported features.**
48 |
49 | ## Open Questions
50 |
51 | - Should the conversion logic live in the editor component or in global handlers?
52 | - How should we handle features/extensions that are not supported by XMLUI Markdown?
53 | - What is the best UX for switching between plain and rich modes?
54 |
55 | ## Focused Scope for Tiptap/TableEditor Exercise
56 |
57 | ### Motivation
58 | The primary motivation for the Tiptap exercise is to demonstrate, in developer documentation, how to wrap a real, useful component in XMLUI. The chosen example is a TableEditor, which addresses a common pain point: creating and editing Markdown tables for documentation.
59 |
60 | ### Scope and Workflow
61 | - The TableEditor provides a spreadsheet-like UI for editing tables.
62 | - Users can switch to a code view to see the generated Markdown table.
63 | - The workflow is: edit your table visually, copy the Markdown, and paste it into your documentation (e.g., in VSCode).
64 | - There is no need to solve file persistence, in-situ editing, or live site integration for this exercise.
65 | - This mirrors the current workflow where developers use external tools to generate Markdown tables, but brings the experience into the XMLUI/React context.
66 |
67 | ### Rationale
68 | - This approach is practical and developer-focused, providing immediate utility without overcomplicating the implementation.
69 | - It showcases XMLUI's extensibility and ability to integrate rich, interactive components.
70 | - The TableEditor can be demonstrated as a standalone tool or as a Tiptap node/component, but the main value is in Markdown table generation.
71 |
72 | ### Next Step
73 | The next step is to rename the Editor component to TableEditor to reflect this focused scope.
74 |
75 | ---
76 |
77 | *This document is a living record of design considerations for Tiptap/Markdown interop in XMLUI. Update as the implementation evolves.*
```
--------------------------------------------------------------------------------
/xmlui/src/components-core/devtools/InspectorDialog.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import React, { type CSSProperties, type ReactNode, useEffect, useRef, useState } from "react";
2 | import { composeRefs } from "@radix-ui/react-compose-refs";
3 | import classnames from "classnames";
4 | import * as Dialog from "@radix-ui/react-dialog";
5 |
6 | import styles from "./InspectorDialog.module.scss";
7 | import { motion, AnimatePresence } from "framer-motion";
8 | import { useTheme } from "../theming/ThemeContext";
9 |
10 | // =====================================================================================================================
11 | // React component definition
12 |
13 | const MotionContent = motion.create(Dialog.Content);
14 |
15 | type ModalProps = {
16 | style?: CSSProperties;
17 | children?: ReactNode;
18 | isOpen: boolean;
19 | setIsOpen: (isOpen: boolean) => void;
20 | clickPosition: { x: number; y: number };
21 | };
22 |
23 | const overlayVariants = {
24 | visible: { opacity: 1 },
25 | hidden: { opacity: 0 },
26 | };
27 |
28 | const contentVariants = {
29 | initial: (custom: { x: number; y: number }) => ({
30 | opacity: 0,
31 | scale: 0.2,
32 | x: custom.x - window.innerWidth / 2,
33 | y: custom.y - window.innerHeight / 2,
34 | }),
35 | animate: {
36 | opacity: 1,
37 | scale: 1,
38 | x: 0,
39 | y: 0,
40 | },
41 | exit: {
42 | opacity: 0,
43 | scale: 0.2,
44 | transition: { duration: 0.2 },
45 | },
46 | };
47 |
48 | function durationToSeconds(durationString?: string) {
49 | if (!durationString) {
50 | return undefined;
51 | }
52 | const trimmedString = durationString.trim();
53 |
54 | if (trimmedString.endsWith("ms")) {
55 | const milliseconds = parseFloat(trimmedString);
56 | return milliseconds / 1000;
57 | } else if (trimmedString.endsWith("s")) {
58 | return parseFloat(trimmedString);
59 | } else {
60 | return parseFloat(trimmedString);
61 | }
62 | }
63 |
64 | export const InspectorDialog = React.forwardRef(
65 | (
66 | { children, style, isOpen, setIsOpen, clickPosition }: ModalProps,
67 | ref: React.Ref<HTMLDivElement>,
68 | ) => {
69 | const { root, getThemeVar } = useTheme();
70 | const modalRef = useRef<HTMLDivElement>(null);
71 | const composedRef = ref ? composeRefs(ref, modalRef) : modalRef;
72 | const [rendered, setRendered] = useState(true);
73 |
74 | useEffect(() => {
75 | if (isOpen) {
76 | modalRef.current?.focus();
77 | }
78 | }, [isOpen]);
79 |
80 | // https://github.com/radix-ui/primitives/issues/2122#issuecomment-2140827998
81 | useEffect(() => {
82 | if (isOpen) {
83 | // Pushing the change to the end of the call stack
84 | const timer = setTimeout(() => {
85 | document.body.style.pointerEvents = "";
86 | }, 0);
87 |
88 | return () => clearTimeout(timer);
89 | } else {
90 | document.body.style.pointerEvents = "auto";
91 | }
92 | }, [isOpen]);
93 |
94 | if (!root) {
95 | return null;
96 | }
97 |
98 | const onExitComplete = () => {
99 | setIsOpen(false);
100 | };
101 |
102 | return (
103 | <Dialog.Root defaultOpen={false} open={isOpen} onOpenChange={setRendered}>
104 | <Dialog.Portal container={root}>
105 | <AnimatePresence onExitComplete={onExitComplete}>
106 | {rendered && (
107 | <Dialog.Overlay className={styles.overlay} forceMount>
108 | <motion.div
109 | key="overlay"
110 | className={styles.overlayBg}
111 | variants={overlayVariants}
112 | initial="hidden"
113 | animate="visible"
114 | exit="hidden"
115 | transition={{
116 | duration: 0.2,
117 | ease: [0.16, 1, 0.3, 1],
118 | }}
119 | />
120 | <MotionContent
121 | forceMount
122 | onPointerDownOutside={(event) => {
123 | if (
124 | event.target instanceof Element &&
125 | event.target.closest("._debug-inspect-button") !== null
126 | ) {
127 | //we prevent the auto modal close on clicking the inspect button
128 | event.preventDefault();
129 | }
130 | }}
131 | >
132 | <motion.div
133 | ref={composedRef}
134 | className={classnames(styles.content, styles.contentWrapper)}
135 | variants={contentVariants}
136 | custom={{ x: clickPosition.x, y: clickPosition.y }}
137 | initial="initial"
138 | animate="animate"
139 | exit="exit"
140 | transition={{
141 | duration:
142 | durationToSeconds(getThemeVar("duration-startAnimation-ModalDialog")) ||
143 | 0.8,
144 | ease: [0.16, 1, 0.3, 1],
145 | }}
146 | style={{ ...style, gap: undefined }}
147 | >
148 | {children}
149 | </motion.div>
150 | </MotionContent>
151 | </Dialog.Overlay>
152 | )}
153 | </AnimatePresence>
154 | </Dialog.Portal>
155 | </Dialog.Root>
156 | );
157 | },
158 | );
159 |
160 | InspectorDialog.displayName = "InspectorDialog";
161 |
```
--------------------------------------------------------------------------------
/docs/content/components/ContentSeparator.md:
--------------------------------------------------------------------------------
```markdown
1 | # ContentSeparator [#contentseparator]
2 |
3 | `ContentSeparator` creates visual dividers between content sections using horizontal or vertical lines. It's essential for improving readability by breaking up dense content, separating list items, or creating clear boundaries between different UI sections.
4 |
5 | **Key features:**
6 | - **Flexible orientation**: Create horizontal dividers (default) or vertical dividers between content
7 | - **Customizable sizing**: Control thickness with the `size` property
8 | - **Automatic spacing**: Takes full width/height of container unless size is specified
9 |
10 | ## Properties [#properties]
11 |
12 | ### `orientation` (default: "horizontal") [#orientation-default-horizontal]
13 |
14 | Sets the main axis of the component
15 |
16 | Available values:
17 |
18 | | Value | Description |
19 | | --- | --- |
20 | | `horizontal` | The component will fill the available space horizontally **(default)** |
21 | | `vertical` | The component will fill the available space vertically |
22 |
23 | See the demo for an example under [`size`](#size).
24 |
25 | >[!INFO]
26 | > The component will not be displayed if the orientation is set to `vertical` but the height of the parent container is not explicitly set to a value other than 0 or percentage is used as the size unit (e.g. 20%).
27 | > This is true even if the `ContentSeparator` has siblings in the container.
28 | > The demo below illustrates this.
29 | > Notice how the first `ContentSeparator` does not show up while the second does:
30 |
31 | ```xmlui-pg copy display name="Example: no vertical space"
32 | <App>
33 | <HStack horizontalAlignment="center">
34 | <ContentSeparator orientation="vertical" size="8px" backgroundColor="blue" />
35 | </HStack>
36 | <HStack horizontalAlignment="center" height="48px">
37 | <ContentSeparator orientation="vertical" size="8px" backgroundColor="red" />
38 | </HStack>
39 | </App>
40 | ```
41 |
42 | ### `size` [#size]
43 |
44 | This property defines the component's height (if the `orientation` is horizontal) or the width (if the `orientation` is vertical). If not defined, the component uses the entire available width or height.
45 |
46 | ```xmlui-pg copy display name="Example: size"
47 | <App>
48 | <Heading level="h2">
49 | Lorem Ipsum
50 | </Heading>
51 | <ContentSeparator />
52 | Lorem ipsum dolor sit amet, consectetur adipiscing elit,
53 | sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
54 | Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi
55 | ut aliquip ex ea commodo consequat.
56 | <ContentSeparator size="4px" />
57 | <HStack height="120px">
58 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
59 | dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
60 | non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
61 | <ContentSeparator orientation="vertical" size="10px" />
62 | Sed ut perspiciatis unde omnis iste natus error sit voluptatem
63 | accusantium doloremque laudantium, totam rem aperiam,
64 | eaque ipsa quae ab illo inventore veritatis et quasi architecto
65 | beatae vitae dicta sunt explicabo.
66 | </HStack>
67 | </App>
68 | ```
69 |
70 | >[!INFO]
71 | > You can use the `width` and `height` layout properties to set the `ContentSeparator` dimensions.
72 | > For the horizontal separator, you can set the `height` property; the vertical separator offers the `width` property instead of `size`.
73 | > Nonetheless, we suggest you use the `size` property.
74 |
75 | ## Events [#events]
76 |
77 | This component does not have any events.
78 |
79 | ## Exposed Methods [#exposed-methods]
80 |
81 | This component does not expose any methods.
82 |
83 | ## Styling [#styling]
84 |
85 | ### Theme Variables [#theme-variables]
86 |
87 | | Variable | Default Value (Light) | Default Value (Dark) |
88 | | --- | --- | --- |
89 | | [backgroundColor](../styles-and-themes/common-units/#color)-ContentSeparator | $color-surface-200 | $color-surface-200 |
90 | | [marginBottom](../styles-and-themes/common-units/#size)-ContentSeparator | *none* | *none* |
91 | | [margin](../styles-and-themes/common-units/#size)Horizontal-ContentSeparator | 0 | 0 |
92 | | [marginLeft](../styles-and-themes/common-units/#size)-ContentSeparator | *none* | *none* |
93 | | [marginRight](../styles-and-themes/common-units/#size)-ContentSeparator | *none* | *none* |
94 | | [marginTop](../styles-and-themes/common-units/#size)-ContentSeparator | *none* | *none* |
95 | | [margin](../styles-and-themes/common-units/#size)Vertical-ContentSeparator | 0 | 0 |
96 | | [paddingBottom](../styles-and-themes/common-units/#size)-ContentSeparator | *none* | *none* |
97 | | [paddingHorizontal](../styles-and-themes/common-units/#size)-ContentSeparator | 0 | 0 |
98 | | [paddingLeft](../styles-and-themes/common-units/#size)-ContentSeparator | *none* | *none* |
99 | | [paddingRight](../styles-and-themes/common-units/#size)-ContentSeparator | *none* | *none* |
100 | | [paddingTop](../styles-and-themes/common-units/#size)-ContentSeparator | *none* | *none* |
101 | | [paddingVertical](../styles-and-themes/common-units/#size)-ContentSeparator | 0 | 0 |
102 | | [size](../styles-and-themes/common-units/#size)-ContentSeparator | 1px | 1px |
103 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Charts/AreaChart/AreaChart.md:
--------------------------------------------------------------------------------
```markdown
1 | %-DESC-START
2 |
3 | Interactive area chart for showing data trends over time with filled areas under the curve.
4 |
5 | **Key features:**
6 | - **Time series visualization**: Perfect for showing data trends over time with filled areas under the curve
7 | - **Multiple data series**: Display several metrics on the same chart with different colored areas
8 | - **Stacked vs overlapping**: Stack areas on top of each other or display them overlapping
9 | - **Curved lines**: Use smooth curves for more visually appealing continuous data
10 | - **Custom formatting**: Use `tickFormatter` to format axis labels
11 |
12 | %-DESC-END
13 |
14 | %-PROP-START data
15 |
16 | ```xml
17 | <AreaChart
18 | nameKey="name"
19 | data="{[
20 | { name: 'Jan', value: 100 },
21 | { name: 'Feb', value: 150 },
22 | { name: 'Mar', value: 120 }
23 | ]}"
24 | dataKeys="{['value']}"
25 | />
26 | ```
27 |
28 | %-PROP-END
29 |
30 | %-PROP-START nameKey
31 |
32 | ```xml
33 | <AreaChart
34 | nameKey="month"
35 | data="{[
36 | { month: 'Jan', sales: 1200, profit: 400 },
37 | { month: 'Feb', sales: 1900, profit: 600 },
38 | { month: 'Mar', sales: 1500, profit: 500 }
39 | ]}"
40 | dataKeys="{['sales', 'profit']}"
41 | />
42 | ```
43 |
44 | %-PROP-END
45 |
46 | %-PROP-START dataKeys
47 |
48 | ```xml
49 | <AreaChart
50 | nameKey="category"
51 | data="{[
52 | { category: 'A', value1: 100, value2: 200 },
53 | { category: 'B', value1: 150, value2: 250 },
54 | { category: 'C', value1: 120, value2: 180 }
55 | ]}"
56 | dataKeys="{['value1', 'value2']}"
57 | />
58 | ```
59 |
60 | %-PROP-END
61 |
62 | %-PROP-START hideX
63 |
64 | ```xml
65 | <AreaChart
66 | nameKey="name"
67 | data="{[
68 | { name: 'A', value: 100 },
69 | { name: 'B', value: 200 },
70 | { name: 'C', value: 150 }
71 | ]}"
72 | dataKeys="{['value']}"
73 | hideX="true"
74 | />
75 | ```
76 |
77 | %-PROP-END
78 |
79 | %-PROP-START hideY
80 |
81 | ```xml
82 | <AreaChart
83 | nameKey="name"
84 | data="{[
85 | { name: 'A', value: 100 },
86 | { name: 'B', value: 200 },
87 | { name: 'C', value: 150 }
88 | ]}"
89 | dataKeys="{['value']}"
90 | hideY="true"
91 | />
92 | ```
93 |
94 | %-PROP-END
95 |
96 | %-PROP-START hideTickX
97 |
98 | ```xml
99 | <AreaChart
100 | nameKey="name"
101 | data="{[
102 | { name: 'A', value: 100 },
103 | { name: 'B', value: 200 },
104 | { name: 'C', value: 150 }
105 | ]}"
106 | dataKeys="{['value']}"
107 | hideTickX="true"
108 | />
109 | ```
110 |
111 | %-PROP-END
112 |
113 | %-PROP-START hideTickY
114 |
115 | ```xml
116 | <AreaChart
117 | nameKey="name"
118 | data="{[
119 | { name: 'A', value: 100 },
120 | { name: 'B', value: 200 },
121 | { name: 'C', value: 150 }
122 | ]}"
123 | dataKeys="{['value']}"
124 | hideTickY="true"
125 | />
126 | ```
127 |
128 | %-PROP-END
129 |
130 | %-PROP-START hideTooltip
131 |
132 | ```xml
133 | <AreaChart
134 | nameKey="name"
135 | data="{[
136 | { name: 'A', value: 100 },
137 | { name: 'B', value: 200 },
138 | { name: 'C', value: 150 }
139 | ]}"
140 | dataKeys="{['value']}"
141 | hideTooltip="true"
142 | />
143 | ```
144 |
145 | %-PROP-END
146 |
147 | %-PROP-START showLegend
148 |
149 | ```xml
150 | <AreaChart
151 | nameKey="quarter"
152 | data="{[
153 | { quarter: 'Q1', revenue: 1000, expenses: 800, profit: 200 },
154 | { quarter: 'Q2', revenue: 1200, expenses: 900, profit: 300 },
155 | { quarter: 'Q3', revenue: 1100, expenses: 850, profit: 250 },
156 | { quarter: 'Q4', revenue: 1400, expenses: 1000, profit: 400 }
157 | ]}"
158 | dataKeys="{['revenue', 'expenses', 'profit']}"
159 | showLegend="true"
160 | />
161 | ```
162 |
163 | %-PROP-END
164 |
165 | %-PROP-START stacked
166 |
167 | ```xml
168 | <AreaChart
169 | nameKey="category"
170 | data="{[
171 | { category: 'A', value1: 100, value2: 200 },
172 | { category: 'B', value1: 150, value2: 250 },
173 | { category: 'C', value1: 120, value2: 180 }
174 | ]}"
175 | dataKeys="{['value1', 'value2']}"
176 | stacked="true"
177 | />
178 | ```
179 |
180 | %-PROP-END
181 |
182 | %-PROP-START curved
183 |
184 | ```xml
185 | <AreaChart
186 | nameKey="time"
187 | data="{[
188 | { time: '00:00', temperature: 18 },
189 | { time: '06:00', temperature: 15 },
190 | { time: '12:00', temperature: 25 },
191 | { time: '18:00', temperature: 22 },
192 | { time: '24:00', temperature: 19 }
193 | ]}"
194 | dataKeys="{['temperature']}"
195 | curved="true"
196 | />
197 | ```
198 |
199 | %-PROP-END
200 |
201 | %-PROP-START tooltipTemplate
202 |
203 | ```xmlui-pg copy display height="320px" name="Example: tooltipTemplate" /tooltipTemplate/
204 | <App>
205 | <AreaChart
206 | height="240px"
207 | data="{[
208 | { 'month': 'Jan', 'sales': 1200, 'profit': 400 },
209 | { 'month': 'Feb', 'sales': 1900, 'profit': 600 },
210 | { 'month': 'Mar', 'sales': 1500, 'profit': 500 },
211 | { 'month': 'Apr', 'sales': 1800, 'profit': 700 }
212 | ]}"
213 | dataKeys="{['sales', 'profit']}"
214 | nameKey="month"
215 | >
216 | <property name="tooltipTemplate">
217 | <VStack backgroundColor='white' padding="$space-2">
218 | <Text fontWeight='bold'>{$tooltip.label}</Text>
219 | <HStack>
220 | <Text color='blue'>Sales: {$tooltip.payload.sales}</Text>
221 | <Text color='green'>Profit: {$tooltip.payload.profit}</Text>
222 | </HStack>
223 | </VStack>
224 | </property>
225 | </AreaChart>
226 | </App>
227 | ```
228 |
229 | The `tooltipTemplate` prop allows you to customize the appearance and content of chart tooltips. The template receives a `$tooltip` context variable containing:
230 |
231 | - `$tooltip.label`: The label for the data point (typically the nameKey value)
232 | - `$tooltip.payload`: An object containing all data values for the hovered point
233 | - `$tooltip.active`: Boolean indicating if the tooltip is currently active
234 |
235 | %-PROP-END
236 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Heading/HeadingNative.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import React, {
2 | type CSSProperties,
3 | type ForwardedRef,
4 | forwardRef,
5 | type ReactNode,
6 | useCallback,
7 | useContext,
8 | useEffect,
9 | useRef,
10 | useState,
11 | } from "react";
12 | import { composeRefs } from "@radix-ui/react-compose-refs";
13 | import classnames from "classnames";
14 |
15 | import styles from "./Heading.module.scss";
16 |
17 | import { getMaxLinesStyle } from "../../components-core/utils/css-utils";
18 | import { TableOfContentsContext } from "../../components-core/TableOfContentsContext";
19 | import { useIsomorphicLayoutEffect } from "../../components-core/utils/hooks";
20 | import type { HeadingLevel } from "./abstractions";
21 | import { Link } from "@remix-run/react";
22 | import { useAppContext } from "../../components-core/AppContext";
23 | import type { RegisterComponentApiFn } from "../../abstractions/RendererDefs";
24 |
25 | export type HeadingProps = {
26 | uid?: string;
27 | level?: HeadingLevel;
28 | children: ReactNode;
29 | sx?: CSSProperties;
30 | style?: CSSProperties;
31 | maxLines?: number;
32 | preserveLinebreaks?: boolean;
33 | ellipses?: boolean;
34 | title?: string;
35 | className?: string;
36 | showAnchor?: boolean;
37 | registerComponentApi?: RegisterComponentApiFn;
38 | [furtherProps: string]: any;
39 | };
40 |
41 | export const defaultProps: Pick<
42 | HeadingProps,
43 | "level" | "ellipses" | "omitFromToc" | "maxLines" | "preserveLinebreaks" | "showAnchor"
44 | > = {
45 | level: "h1",
46 | ellipses: true,
47 | omitFromToc: false,
48 | maxLines: 0,
49 | preserveLinebreaks: false,
50 | showAnchor: false,
51 | };
52 |
53 | export const Heading = forwardRef(function Heading(
54 | {
55 | uid,
56 | level = defaultProps.level,
57 | children,
58 | sx,
59 | style,
60 | title,
61 | maxLines = defaultProps.maxLines,
62 | preserveLinebreaks,
63 | ellipses = defaultProps.ellipses,
64 | className,
65 | omitFromToc = defaultProps.omitFromToc,
66 | showAnchor,
67 | registerComponentApi,
68 | ...furtherProps
69 | }: HeadingProps,
70 | forwardedRef: ForwardedRef<HTMLHeadingElement>,
71 | ) {
72 | const Element = level?.toLowerCase() as HeadingLevel;
73 | const elementRef = useRef<HTMLHeadingElement>(null);
74 | const [anchorId, setAnchorId] = useState<string | null>(null);
75 | const anchorRef = useRef<HTMLAnchorElement>(null);
76 |
77 | const tableOfContentsContext = useContext(TableOfContentsContext);
78 | const registerHeading = tableOfContentsContext?.registerHeading;
79 | const appContext = useAppContext();
80 | if (showAnchor === undefined) {
81 | showAnchor = appContext?.appGlobals?.showHeadingAnchors ?? false;
82 | }
83 |
84 | const ref = forwardedRef ? composeRefs(elementRef, forwardedRef) : elementRef;
85 |
86 | const scrollIntoView = useCallback((options?: ScrollIntoViewOptions) => {
87 | if (elementRef.current) {
88 | elementRef.current.scrollIntoView({
89 | behavior: 'smooth',
90 | block: 'start',
91 | ...options,
92 | });
93 | }
94 | }, []);
95 |
96 | const hasOverflow = useCallback(() => {
97 | if (elementRef.current) {
98 | const element = elementRef.current;
99 | return element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight;
100 | }
101 | return false;
102 | }, []);
103 |
104 | useEffect(() => {
105 | registerComponentApi?.({
106 | scrollIntoView,
107 | hasOverflow,
108 | });
109 | }, [registerComponentApi, scrollIntoView, hasOverflow]);
110 |
111 | useEffect(() => {
112 | if (elementRef.current) {
113 | const newAnchorId = elementRef.current.textContent
114 | ?.trim()
115 | ?.replace(/[^\w\s-]/g, "")
116 | ?.replace(/\s+/g, "-")
117 | ?.toLowerCase();
118 | setAnchorId(newAnchorId || null);
119 | }
120 | }, []);
121 |
122 | useIsomorphicLayoutEffect(() => {
123 | if (elementRef.current && anchorId && !omitFromToc) {
124 | return registerHeading?.({
125 | id: anchorId,
126 | level: parseInt(level.replace("h", "")),
127 | text: elementRef.current.textContent!.trim().replace(/#$/, ""), // Remove trailing #
128 | anchor: anchorRef.current,
129 | });
130 | }
131 | }, [anchorId, registerHeading, level, omitFromToc]);
132 |
133 | return (
134 | <Element
135 | {...furtherProps}
136 | ref={ref}
137 | id={uid}
138 | title={title}
139 | style={{ ...sx, ...style, ...getMaxLinesStyle(maxLines) }}
140 | className={classnames(styles.heading, styles[Element], className, {
141 | [styles.truncateOverflow]: maxLines > 0,
142 | [styles.preserveLinebreaks]: preserveLinebreaks,
143 | [styles.noEllipsis]: !ellipses,
144 | })}
145 | >
146 | {anchorId && (
147 | <span ref={anchorRef} id={anchorId} className={styles.anchorRef} data-anchor={true} />
148 | )}
149 | {children}
150 | {showAnchor && anchorId && (
151 | <Link
152 | to={`#${anchorId}`}
153 | aria-hidden="true"
154 | onClick={(event) => {
155 | // cmd/ctrl + click - open in new tab, don't prevent that
156 | if (tableOfContentsContext) {
157 | if (!event.ctrlKey && !event.metaKey && !event.metaKey) {
158 | event.preventDefault();
159 | }
160 | tableOfContentsContext.scrollToAnchor(anchorId, true);
161 | }
162 | }}
163 | >
164 | #
165 | </Link>
166 | )}
167 | </Element>
168 | );
169 | });
170 |
```
--------------------------------------------------------------------------------
/xmlui/bin/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | #!/usr/bin/env node
2 |
3 | import { build } from "./build";
4 | import { start } from "./start";
5 |
6 | import { preview } from "./preview";
7 | import yargs from "yargs/yargs";
8 | import { hideBin } from "yargs/helpers";
9 | import AdmZip from "adm-zip";
10 | import { buildLib } from "./build-lib";
11 |
12 | process.on("unhandledRejection", (err) => {
13 | throw err;
14 | });
15 |
16 | async function zipDirectory(sourceDir: string, outPath: string = sourceDir) {
17 | const zip = new AdmZip();
18 | zip.addLocalFolder(sourceDir);
19 | await zip.writeZipPromise(outPath);
20 | console.log(`Zip file created: ${outPath}`);
21 | }
22 |
23 | async function zipDist({
24 | target = "ui.zip",
25 | source = "dist",
26 | }: {
27 | target?: string;
28 | source?: string;
29 | }) {
30 | await zipDirectory(`${process.cwd()}/${source}`, `${process.cwd()}/${target}`);
31 | }
32 |
33 | function dedupeArg(arg: any) {
34 | if (Array.isArray(arg)) {
35 | return arg[arg.length - 1];
36 | }
37 | return arg;
38 | }
39 |
40 | function getBoolArg(arg: any, defaultValue?: boolean | undefined) {
41 | if (arg === undefined) {
42 | return defaultValue;
43 | }
44 | return dedupeArg(arg) !== "false";
45 | }
46 |
47 | function getStringArg(arg: any, defaultValue: string | undefined) {
48 | if (arg === undefined) {
49 | return defaultValue;
50 | }
51 | return dedupeArg(arg);
52 | }
53 |
54 | // Configure yargs with proper typing
55 | interface BuildArgs {
56 | flatDist?: boolean;
57 | prod?: boolean;
58 | buildMode?: string;
59 | withMock?: boolean;
60 | withHostingMetaFiles?: boolean;
61 | withRelativeRoot?: boolean;
62 | }
63 |
64 | interface BuildLibArgs {
65 | watch?: boolean;
66 | mode?: string;
67 | }
68 |
69 | interface StartArgs {
70 | port?: number;
71 | withMock?: boolean;
72 | proxy?: string;
73 | }
74 |
75 | interface PreviewArgs {
76 | proxy?: string;
77 | }
78 |
79 | interface ZipDistArgs {
80 | target?: string;
81 | source?: string;
82 | }
83 |
84 | const argv = yargs(hideBin(process.argv))
85 | .command<BuildArgs>("build", "Build the project", (yargs) => {
86 | return yargs
87 | .option("flatDist", {
88 | type: "boolean",
89 | description: "Create flat distribution",
90 | })
91 | .option("prod", {
92 | type: "boolean",
93 | description: "Production build",
94 | })
95 | .option("buildMode", {
96 | type: "string",
97 | description: "Build mode",
98 | })
99 | .option("withMock", {
100 | type: "boolean",
101 | description: "Include mock data",
102 | })
103 | .option("withHostingMetaFiles", {
104 | type: "boolean",
105 | description: "Include hosting meta files",
106 | })
107 | .option("withRelativeRoot", {
108 | type: "boolean",
109 | description: "Use relative root",
110 | });
111 | })
112 | .command<BuildLibArgs>("build-lib", "Build library", (yargs) => {
113 | return yargs
114 | .option("watch", {
115 | type: "boolean",
116 | description: "Watch mode",
117 | })
118 | .option("mode", {
119 | type: "string",
120 | description: "Build mode",
121 | });
122 | })
123 | .command<StartArgs>("start", "Start development server", (yargs) => {
124 | return yargs
125 | .option("port", {
126 | type: "number",
127 | description: "Port number",
128 | })
129 | .option("withMock", {
130 | type: "boolean",
131 | description: "Include mock data",
132 | })
133 | .option("proxy", {
134 | type: "string",
135 | description: "Proxy target",
136 | });
137 | })
138 | .command<PreviewArgs>("preview", "Preview build", (yargs) => {
139 | return yargs.option("proxy", {
140 | type: "string",
141 | description: "Proxy target",
142 | });
143 | })
144 | .command<ZipDistArgs>("zip-dist", "Zip distribution", (yargs) => {
145 | return yargs
146 | .option("target", {
147 | type: "string",
148 | description: "Target zip file",
149 | })
150 | .option("source", {
151 | type: "string",
152 | description: "Source directory",
153 | });
154 | })
155 | .help()
156 | .parseSync();
157 |
158 | const command = argv._[0] as string;
159 |
160 | switch (command) {
161 | case "build": {
162 | const { flatDist, prod, buildMode, withMock, withHostingMetaFiles, withRelativeRoot } =
163 | argv as BuildArgs;
164 |
165 | build({
166 | buildMode: getStringArg(buildMode, prod ? "CONFIG_ONLY" : undefined),
167 | withMock: getBoolArg(withMock, prod ? false : undefined),
168 | withHostingMetaFiles: getBoolArg(withHostingMetaFiles, prod ? false : undefined),
169 | withRelativeRoot: getBoolArg(withRelativeRoot, prod ? true : undefined),
170 | flatDist: getBoolArg(flatDist, prod ? true : undefined),
171 | });
172 | break;
173 | }
174 | case "build-lib": {
175 | const { watch, mode } = argv as BuildLibArgs;
176 | buildLib({ watchMode: getBoolArg(watch, false), mode: getStringArg(mode, "") });
177 | break;
178 | }
179 | case "start": {
180 | const { port, withMock, proxy } = argv as StartArgs;
181 | start({ port, withMock: getBoolArg(withMock), proxy });
182 | break;
183 | }
184 | case "preview": {
185 | const { proxy } = argv as PreviewArgs;
186 | preview({ proxy });
187 | break;
188 | }
189 | case "zip-dist": {
190 | const { target, source } = argv as ZipDistArgs;
191 | zipDist({ target, source });
192 | break;
193 | }
194 | default: {
195 | console.log('Unknown command "' + command + '".');
196 | console.log("Perhaps you need to update xmlui?");
197 | process.exit(1);
198 | }
199 | }
200 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Splitter/VSplitter.spec.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { getBounds } from "../../testing/component-test-helpers";
2 | import { expect, test } from "../../testing/fixtures";
3 |
4 | // =============================================================================
5 | // BASIC FUNCTIONALITY TESTS
6 | // =============================================================================
7 |
8 | test.describe("Basic Functionality", () => {
9 | test("renders with basic setup", async ({ initTestBed, page }) => {
10 | await initTestBed(`
11 | <VSplitter height="200px" width="400px" testId="vsplitter">
12 | <Stack backgroundColor="lightblue" height="100%" testId="primary"/>
13 | <Stack backgroundColor="darksalmon" height="100%" testId="secondary"/>
14 | </VSplitter>
15 | `);
16 |
17 | await expect(page.getByTestId("vsplitter")).toBeVisible();
18 | await expect(page.getByTestId("primary")).toBeVisible();
19 | await expect(page.getByTestId("secondary")).toBeVisible();
20 | });
21 |
22 | test("defaults to vertical orientation", async ({ initTestBed, page }) => {
23 | await initTestBed(`
24 | <VSplitter height="200px" width="400px" testId="vsplitter">
25 | <Stack backgroundColor="lightblue" height="100%" testId="primary"/>
26 | <Stack backgroundColor="darksalmon" height="100%" testId="secondary"/>
27 | </VSplitter>
28 | `);
29 |
30 | const primary = page.getByTestId("primary");
31 | const secondary = page.getByTestId("secondary");
32 |
33 | const primaryBounds = await getBounds(primary);
34 | const secondaryBounds = await getBounds(secondary);
35 |
36 | // In vertical orientation, primary should be above secondary
37 | expect(primaryBounds.bottom).toBeLessThanOrEqual(secondaryBounds.top + 10); // Allow for small overlap due to resizer
38 | });
39 |
40 | test("ignores orientation property when explicitly set", async ({ initTestBed, page }) => {
41 | await initTestBed(`
42 | <VSplitter height="200px" width="400px" orientation="horizontal" testId="vsplitter">
43 | <Stack backgroundColor="lightblue" height="100%" testId="primary"/>
44 | <Stack backgroundColor="darksalmon" height="100%" testId="secondary"/>
45 | </VSplitter>
46 | `);
47 |
48 | const primary = page.getByTestId("primary");
49 | const secondary = page.getByTestId("secondary");
50 |
51 | const primaryBounds = await getBounds(primary);
52 | const secondaryBounds = await getBounds(secondary);
53 |
54 | // Even with orientation="horizontal", VSplitter should still be vertical
55 | // Primary should be above secondary, NOT to the left of it
56 | expect(primaryBounds.bottom).toBeLessThanOrEqual(secondaryBounds.top + 10);
57 | });
58 |
59 | test("works with swapped property", async ({ initTestBed, page }) => {
60 | await initTestBed(`
61 | <VSplitter height="200px" width="400px" swapped="true" testId="vsplitter">
62 | <Stack backgroundColor="lightblue" height="100%" testId="primary"/>
63 | <Stack backgroundColor="darksalmon" height="100%" testId="secondary"/>
64 | </VSplitter>
65 | `);
66 |
67 | const primary = page.getByTestId("primary");
68 | const secondary = page.getByTestId("secondary");
69 |
70 | const primaryBounds = await getBounds(primary);
71 | const secondaryBounds = await getBounds(secondary);
72 |
73 | // With swapped=true, secondary should be above primary
74 | expect(secondaryBounds.bottom).toBeLessThanOrEqual(primaryBounds.top + 10);
75 | });
76 |
77 | test("maintains vertical orientation even with invalid orientation values", async ({ initTestBed, page }) => {
78 | await initTestBed(`
79 | <VSplitter height="200px" width="400px" orientation="invalid-value" testId="vsplitter">
80 | <Stack backgroundColor="lightblue" height="100%" testId="primary"/>
81 | <Stack backgroundColor="darksalmon" height="100%" testId="secondary"/>
82 | </VSplitter>
83 | `);
84 |
85 | const primary = page.getByTestId("primary");
86 | const secondary = page.getByTestId("secondary");
87 |
88 | const primaryBounds = await getBounds(primary);
89 | const secondaryBounds = await getBounds(secondary);
90 |
91 | // Should still be vertical regardless of invalid orientation value
92 | expect(primaryBounds.bottom).toBeLessThanOrEqual(secondaryBounds.top + 10);
93 | });
94 | });
95 |
96 | // =============================================================================
97 | // ACCESSIBILITY TESTS
98 | // =============================================================================
99 |
100 | test.describe("Accessibility", () => {
101 | test("resizer has vertical cursor style", async ({ initTestBed, page, createSplitterDriver }) => {
102 | await initTestBed(`
103 | <VSplitter height="200px" width="400px" testId="vsplitter">
104 | <Stack backgroundColor="lightblue" height="100%"/>
105 | <Stack backgroundColor="darksalmon" height="100%"/>
106 | </VSplitter>
107 | `);
108 |
109 | const vsplitter = page.getByTestId("vsplitter");
110 | const driver = await createSplitterDriver(vsplitter);
111 | const resizer = await driver.getResizer();
112 |
113 | // VSplitter should always use vertical cursor (ns-resize)
114 | await expect(resizer).toHaveCSS("cursor", "ns-resize");
115 | });
116 | });
117 |
```
--------------------------------------------------------------------------------
/docs/content/components/Footer.md:
--------------------------------------------------------------------------------
```markdown
1 | # Footer [#footer]
2 |
3 | `Footer` provides a designated area at the bottom of your application for footer content such as branding, copyright notices, or utility controls like theme toggles.
4 |
5 | ## Properties [#properties]
6 |
7 | This component does not have any properties.
8 |
9 | ## Events [#events]
10 |
11 | This component does not have any events.
12 |
13 | ## Exposed Methods [#exposed-methods]
14 |
15 | This component does not expose any methods.
16 |
17 | ## Styling [#styling]
18 |
19 | ### Theme Variables [#theme-variables]
20 |
21 | | Variable | Default Value (Light) | Default Value (Dark) |
22 | | --- | --- | --- |
23 | | [backgroundColor](../styles-and-themes/common-units/#color)-Footer | $backgroundColor-AppHeader | $backgroundColor-AppHeader |
24 | | [border](../styles-and-themes/common-units/#border)-Footer | *none* | *none* |
25 | | [borderBottom](../styles-and-themes/common-units/#border)-Footer | *none* | *none* |
26 | | [borderBottomColor](../styles-and-themes/common-units/#color)-Footer | *none* | *none* |
27 | | [borderBottomStyle](../styles-and-themes/common-units/#border-style)-Footer | *none* | *none* |
28 | | [borderBottomWidth](../styles-and-themes/common-units/#size)-Footer | *none* | *none* |
29 | | [borderColor](../styles-and-themes/common-units/#color)-Footer | *none* | *none* |
30 | | [borderEndEndRadius](../styles-and-themes/common-units/#border-rounding)-Footer | *none* | *none* |
31 | | [borderEndStartRadius](../styles-and-themes/common-units/#border-rounding)-Footer | *none* | *none* |
32 | | [borderHorizontal](../styles-and-themes/common-units/#border)-Footer | *none* | *none* |
33 | | [borderHorizontalColor](../styles-and-themes/common-units/#color)-Footer | *none* | *none* |
34 | | [borderHorizontalStyle](../styles-and-themes/common-units/#border-style)-Footer | *none* | *none* |
35 | | [borderHorizontalWidth](../styles-and-themes/common-units/#size)-Footer | *none* | *none* |
36 | | [borderLeft](../styles-and-themes/common-units/#border)-Footer | *none* | *none* |
37 | | [color](../styles-and-themes/common-units/#color)-Footer | *none* | *none* |
38 | | [borderLeftStyle](../styles-and-themes/common-units/#border-style)-Footer | *none* | *none* |
39 | | [borderLeftWidth](../styles-and-themes/common-units/#size)-Footer | *none* | *none* |
40 | | [borderRight](../styles-and-themes/common-units/#border)-Footer | *none* | *none* |
41 | | [color](../styles-and-themes/common-units/#color)-Footer | *none* | *none* |
42 | | [borderRightStyle](../styles-and-themes/common-units/#border-style)-Footer | *none* | *none* |
43 | | [borderRightWidth](../styles-and-themes/common-units/#size)-Footer | *none* | *none* |
44 | | [borderStartEndRadius](../styles-and-themes/common-units/#border-rounding)-Footer | *none* | *none* |
45 | | [borderStartStartRadius](../styles-and-themes/common-units/#border-rounding)-Footer | *none* | *none* |
46 | | [borderStyle](../styles-and-themes/common-units/#border-style)-Footer | *none* | *none* |
47 | | [borderTop](../styles-and-themes/common-units/#border)-Footer | 1px solid $borderColor | 1px solid $borderColor |
48 | | [borderTopColor](../styles-and-themes/common-units/#color)-Footer | *none* | *none* |
49 | | [borderTopStyle](../styles-and-themes/common-units/#border-style)-Footer | *none* | *none* |
50 | | [borderTopWidth](../styles-and-themes/common-units/#size)-Footer | *none* | *none* |
51 | | [borderHorizontal](../styles-and-themes/common-units/#border)-Footer | *none* | *none* |
52 | | [borderVerticalColor](../styles-and-themes/common-units/#color)-Footer | *none* | *none* |
53 | | [borderVerticalStyle](../styles-and-themes/common-units/#border-style)-Footer | *none* | *none* |
54 | | [borderVerticalWidth](../styles-and-themes/common-units/#size)-Footer | *none* | *none* |
55 | | [borderWidth](../styles-and-themes/common-units/#size)-Footer | *none* | *none* |
56 | | [fontSize](../styles-and-themes/common-units/#size)-Footer | $fontSize-sm | $fontSize-sm |
57 | | [gap](../styles-and-themes/common-units/#size)-Footer | $space-normal | $space-normal |
58 | | [height](../styles-and-themes/common-units/#size)-Footer | *none* | *none* |
59 | | [margin](../styles-and-themes/common-units/#size)-Footer | 0 auto | 0 auto |
60 | | [maxWidth-content](../styles-and-themes/common-units/#size)-Footer | $maxWidth-content | $maxWidth-content |
61 | | [padding](../styles-and-themes/common-units/#size)-Footer | $space-2 $space-4 | $space-2 $space-4 |
62 | | [paddingBottom](../styles-and-themes/common-units/#size)-Footer | *none* | *none* |
63 | | [paddingHorizontal](../styles-and-themes/common-units/#size)-Footer | *none* | *none* |
64 | | [paddingLeft](../styles-and-themes/common-units/#size)-Footer | *none* | *none* |
65 | | [paddingRight](../styles-and-themes/common-units/#size)-Footer | *none* | *none* |
66 | | [paddingTop](../styles-and-themes/common-units/#size)-Footer | *none* | *none* |
67 | | [paddingVertical](../styles-and-themes/common-units/#size)-Footer | *none* | *none* |
68 | | [textColor](../styles-and-themes/common-units/#color)-Footer | $textColor-secondary | $textColor-secondary |
69 | | [verticalAlignment](../styles-and-themes/common-units/#alignment)-Footer | center | center |
70 |
```
--------------------------------------------------------------------------------
/xmlui/src/components-core/theming/parse-layout-props.ts:
--------------------------------------------------------------------------------
```typescript
1 | import type { MediaBreakpointType} from "../../abstractions/AppContextDefs";
2 | import { MediaBreakpointKeys } from "../../abstractions/AppContextDefs";
3 |
4 | export type ParsedLayout = {
5 | property: string;
6 | part?: string;
7 | component?: string;
8 | screenSizes?: MediaBreakpointType[];
9 | states?: string[];
10 | }
11 |
12 | /**
13 | * Mapping exceptions for camelCase property names to CSS property names.
14 | * These properties don't follow the standard camelCase-to-kebab-case conversion.
15 | */
16 | export const CSS_PROPERTY_EXCEPTIONS: Record<string, string> = {
17 | textColor: "color",
18 | paddingVertical: "",
19 | paddingHorizontal: "",
20 | marginVertical: "",
21 | marginHorizontal: "",
22 | borderVertical: "",
23 | borderHorizontal: "",
24 | };
25 |
26 | export function parseLayoutProperty(prop: string, parseComponent: boolean = false): ParsedLayout | string {
27 | if (!prop || typeof prop !== 'string') {
28 | return "Property string cannot be empty";
29 | }
30 |
31 | // Split by '--' to separate states from the rest
32 | const parts = prop.split('--');
33 | const mainPart = parts[0];
34 | const stateParts = parts.slice(1);
35 |
36 | // Validate state names
37 | const states: string[] = [];
38 | for (const statePart of stateParts) {
39 | if (!statePart) {
40 | return "State name cannot be empty";
41 | }
42 | if (!isValidName(statePart)) {
43 | return `Invalid state name: ${statePart}`;
44 | }
45 | states.push(statePart);
46 | }
47 |
48 | // Split main part by '-' to get segments
49 | const segments = mainPart.split('-').filter(segment => segment.length > 0);
50 |
51 | if (segments.length === 0) {
52 | return "CSS property name is required";
53 | }
54 |
55 | // The first segment is always the CSS property name (camelCase, no dashes)
56 | const property = segments[0];
57 |
58 | // Validate CSS property name (camelCase)
59 | if (!isValidPropertyName(property)) {
60 | return `Invalid CSS property name: ${property}`;
61 | }
62 |
63 | const result: ParsedLayout = {
64 | property,
65 | states: states.length > 0 ? states : undefined
66 | };
67 |
68 | let segmentIndex = 1;
69 | const screenSizes: MediaBreakpointType[] = [];
70 |
71 | // Process remaining segments
72 | while (segmentIndex < segments.length) {
73 | const segment = segments[segmentIndex];
74 |
75 | // Check if it's a screen size
76 | if (isMediaBreakpoint(segment)) {
77 | screenSizes.push(segment as MediaBreakpointType);
78 | segmentIndex++;
79 | continue;
80 | }
81 |
82 | // Check if it's a component name (starts with uppercase)
83 | if (isComponentName(segment)) {
84 | if (!parseComponent) {
85 | return `Component names are not allowed when parseComponent is false: ${segment}`;
86 | }
87 | if (result.component) {
88 | return "Multiple component names found";
89 | }
90 | result.component = segment;
91 | segmentIndex++;
92 | continue;
93 | }
94 |
95 | // Check if it's a part name (starts with lowercase)
96 | if (isValidPartName(segment)) {
97 | if (result.part) {
98 | return "Multiple part names found";
99 | }
100 | result.part = segment;
101 | segmentIndex++;
102 | continue;
103 | }
104 |
105 | // If we reach here, the segment is invalid
106 | return `Invalid segment: ${segment}`;
107 | }
108 |
109 | // Set screen sizes if any were found
110 | if (screenSizes.length > 0) {
111 | result.screenSizes = screenSizes;
112 | }
113 |
114 | return result;
115 | }
116 |
117 | /**
118 | * Transforms a camelCase property name (as used in ParsedLayout.property)
119 | * to its corresponding CSS style property name.
120 | *
121 | * Handles special cases defined in CSS_PROPERTY_EXCEPTIONS, otherwise
122 | * converts camelCase to kebab-case (e.g., "fontSize" -> "font-size").
123 | *
124 | * @param property - The camelCase property name from ParsedLayout
125 | * @returns The CSS property name in kebab-case or the mapped exception
126 | *
127 | * @example
128 | * toCssPropertyName('fontSize') // returns 'font-size'
129 | * toCssPropertyName('textColor') // returns 'color' (exception)
130 | * toCssPropertyName('backgroundColor') // returns 'background-color'
131 | */
132 | export function toCssPropertyName(property: string): string {
133 | // Check if there's a mapping exception
134 | if (property in CSS_PROPERTY_EXCEPTIONS) {
135 | return CSS_PROPERTY_EXCEPTIONS[property];
136 | }
137 |
138 | // Convert camelCase to kebab-case
139 | return property.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
140 | }
141 |
142 | function isValidPropertyName(name: string): boolean {
143 | // CSS property names in camelCase - start with lowercase letter, can contain letters and numbers
144 | return /^[a-z][a-zA-Z0-9]*$/.test(name);
145 | }
146 |
147 | function isValidName(name: string): boolean {
148 | // Names start with a letter and can contain letters, numbers, or underscores
149 | return /^[a-zA-Z][a-zA-Z0-9_]*$/.test(name);
150 | }
151 |
152 | function isValidPartName(name: string): boolean {
153 | // Part names start with lowercase letter and can contain letters, numbers, or underscores
154 | return /^[a-z][a-zA-Z0-9_]*$/.test(name);
155 | }
156 |
157 | function isComponentName(name: string): boolean {
158 | // Component names start with uppercase letter
159 | return /^[A-Z][a-zA-Z0-9_]*$/.test(name);
160 | }
161 |
162 | function isMediaBreakpoint(value: string): boolean {
163 | return MediaBreakpointKeys.includes(value as MediaBreakpointType);
164 | }
165 |
166 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Charts/AreaChart/AreaChart.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { AreaChart, defaultProps } from "./AreaChartNative";
2 | import { createComponentRenderer } from "../../../components-core/renderers";
3 | import { createMetadata } from "../../metadata-helpers";
4 | import { MemoizedItem } from "../../container-helpers";
5 |
6 | const COMP = "AreaChart";
7 |
8 | export const AreaChartMd = createMetadata({
9 | status: "experimental",
10 | description: "Interactive area chart for showing data trends over time with filled areas under the curve",
11 | docFolder: "Charts/AreaChart",
12 |
13 | props: {
14 | data: {
15 | description:
16 | "This property is used to provide the component with data to display. " +
17 | "The data needs to be an array of objects.",
18 | },
19 | dataKeys: {
20 | description:
21 | "This property specifies the keys in the data objects that should be used for rendering the chart elements. " +
22 | "E.g. 'value' or 'amount'.",
23 | valueType: "string",
24 | },
25 | nameKey: {
26 | description:
27 | "Specifies the key in the data objects that will be used to label the different data series.",
28 | valueType: "string",
29 | },
30 | hideX: {
31 | description:
32 | "Determines whether the X-axis should be hidden. If set to `true`, the axis will not be rendered.",
33 | valueType: "boolean",
34 | defaultValue: defaultProps.hideX,
35 | },
36 | hideY: {
37 | description:
38 | "Determines whether the Y-axis should be hidden. If set to `true`, the axis will not be rendered.",
39 | valueType: "boolean",
40 | defaultValue: defaultProps.hideY,
41 | },
42 | hideTickX: {
43 | description:
44 | "Determines whether the X-axis tick labels should be hidden. If set to `true`, the tick labels will not be rendered.",
45 | valueType: "boolean",
46 | defaultValue: defaultProps.hideTickX,
47 | },
48 | hideTickY: {
49 | description:
50 | "Determines whether the Y-axis tick labels should be hidden. If set to `true`, the tick labels will not be rendered.",
51 | valueType: "boolean",
52 | defaultValue: defaultProps.hideTickY,
53 | },
54 | hideTooltip: {
55 | description:
56 | "Determines whether the tooltip should be hidden. If set to `true`, the tooltip will not be rendered.",
57 | valueType: "boolean",
58 | defaultValue: defaultProps.hideTooltip,
59 | },
60 | showLegend: {
61 | description:
62 | "Determines whether the legend should be shown. If set to `true`, the legend will be rendered.",
63 | valueType: "boolean",
64 | defaultValue: defaultProps.showLegend,
65 | },
66 | stacked: {
67 | description:
68 | "Determines whether multiple areas should be stacked on top of each other. If set to `true`, areas will be stacked.",
69 | valueType: "boolean",
70 | defaultValue: defaultProps.stacked,
71 | },
72 | curved: {
73 | description:
74 | "Determines whether the area lines should be curved (smooth) or straight. If set to `true`, lines will be curved.",
75 | valueType: "boolean",
76 | defaultValue: defaultProps.curved,
77 | },
78 | tooltipTemplate: {
79 | description: "This property allows replacing the default template to display a tooltip.",
80 | },
81 | },
82 |
83 | events: {
84 | // Standard chart events - customize based on chart type
85 | },
86 |
87 | apis: {
88 | // Chart-specific APIs if needed
89 | },
90 |
91 | contextVars: {
92 | // Add context variables if needed
93 | },
94 | });
95 |
96 | // Component renderer
97 | export const areaChartComponentRenderer = createComponentRenderer(
98 | COMP,
99 | AreaChartMd,
100 | ({ extractValue, node, className, lookupSyncCallback, renderChild }: any) => {
101 | return (
102 | <AreaChart
103 | className={className}
104 | tickFormatterX={lookupSyncCallback(node.props?.tickFormatterX)}
105 | tickFormatterY={lookupSyncCallback(node.props?.tickFormatterY)}
106 | data={extractValue(node.props?.data)}
107 | nameKey={extractValue(node.props?.nameKey)}
108 | dataKeys={extractValue(node.props?.dataKeys)}
109 | hideX={extractValue.asOptionalBoolean(node.props?.hideX)}
110 | hideY={extractValue.asOptionalBoolean(node.props?.hideY)}
111 | hideTickX={extractValue.asOptionalBoolean(node.props?.hideTickX)}
112 | hideTickY={extractValue.asOptionalBoolean(node.props?.hideTickY)}
113 | hideTooltip={extractValue.asOptionalBoolean(node.props?.hideTooltip)}
114 | showLegend={extractValue.asOptionalBoolean(node.props?.showLegend)}
115 | stacked={extractValue.asOptionalBoolean(node.props?.stacked)}
116 | curved={extractValue.asOptionalBoolean(node.props?.curved)}
117 | tooltipRenderer={
118 | node.props.tooltipTemplate
119 | ? (tooltipData) => {
120 | return (
121 | <MemoizedItem
122 | node={node.props.tooltipTemplate}
123 | item={tooltipData}
124 | contextVars={{
125 | $tooltip: tooltipData,
126 | }}
127 | renderChild={renderChild}
128 | />
129 | );
130 | }
131 | : undefined
132 | }
133 | >
134 | {renderChild(node.children)}
135 | </AreaChart>
136 | );
137 | },
138 | );
139 |
```