This is page 30 of 181. Use http://codebase.md/xmlui-org/xmlui/%7Bnode.props.src?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .changeset
│ └── config.json
├── .eslintrc.cjs
├── .github
│ ├── build-checklist.png
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows
│ ├── deploy-blog-optimized.yml
│ ├── deploy-blog.yml
│ ├── deploy-docs-optimized.yml
│ ├── deploy-docs.yml
│ ├── prepare-versions.yml
│ ├── release-packages.yml
│ ├── run-all-tests.yml
│ └── run-smoke-tests.yml
├── .gitignore
├── .prettierrc.js
├── .vscode
│ ├── launch.json
│ └── settings.json
├── blog
│ ├── .gitignore
│ ├── .gitkeep
│ ├── CHANGELOG.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── package.json
│ ├── public
│ │ ├── blog
│ │ │ ├── images
│ │ │ │ ├── an-advanced-codefence.gif
│ │ │ │ ├── an-advanced-codefence.mp4
│ │ │ │ ├── blog-page-component.png
│ │ │ │ ├── blog-scrabble.png
│ │ │ │ ├── codefence-runner.png
│ │ │ │ ├── integrated-blog-search.png
│ │ │ │ ├── lorem-ipsum.png
│ │ │ │ ├── playground-checkbox-source.png
│ │ │ │ ├── playground.png
│ │ │ │ ├── use-xmlui-mcp-to-find-a-howto.png
│ │ │ │ └── xmlui-demo-gallery.png
│ │ │ ├── introducing-xmlui.md
│ │ │ ├── lorem-ipsum.md
│ │ │ ├── newest-post.md
│ │ │ ├── older-post.md
│ │ │ ├── xmlui-playground.md
│ │ │ └── xmlui-powered-blog.md
│ │ ├── mockServiceWorker.js
│ │ ├── resources
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ └── for-download
│ │ │ │ └── xmlui
│ │ │ │ └── xmlui-standalone.umd.js
│ │ │ ├── github.svg
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ ├── rss.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ └── PageNotFound.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── blog-theme.ts
│ └── tsconfig.json
├── CONTRIBUTING.md
├── docs
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── ComponentRefLinks.txt
│ ├── content
│ │ ├── _meta.json
│ │ ├── components
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── APICall.md
│ │ │ ├── App.md
│ │ │ ├── AppHeader.md
│ │ │ ├── AppState.md
│ │ │ ├── AutoComplete.md
│ │ │ ├── Avatar.md
│ │ │ ├── Backdrop.md
│ │ │ ├── Badge.md
│ │ │ ├── BarChart.md
│ │ │ ├── Bookmark.md
│ │ │ ├── Breakout.md
│ │ │ ├── Button.md
│ │ │ ├── Card.md
│ │ │ ├── Carousel.md
│ │ │ ├── ChangeListener.md
│ │ │ ├── Checkbox.md
│ │ │ ├── CHStack.md
│ │ │ ├── ColorPicker.md
│ │ │ ├── Column.md
│ │ │ ├── ContentSeparator.md
│ │ │ ├── CVStack.md
│ │ │ ├── DataSource.md
│ │ │ ├── DateInput.md
│ │ │ ├── DatePicker.md
│ │ │ ├── DonutChart.md
│ │ │ ├── DropdownMenu.md
│ │ │ ├── EmojiSelector.md
│ │ │ ├── ExpandableItem.md
│ │ │ ├── FileInput.md
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FlowLayout.md
│ │ │ ├── Footer.md
│ │ │ ├── Form.md
│ │ │ ├── FormItem.md
│ │ │ ├── FormSection.md
│ │ │ ├── Fragment.md
│ │ │ ├── H1.md
│ │ │ ├── H2.md
│ │ │ ├── H3.md
│ │ │ ├── H4.md
│ │ │ ├── H5.md
│ │ │ ├── H6.md
│ │ │ ├── Heading.md
│ │ │ ├── HSplitter.md
│ │ │ ├── HStack.md
│ │ │ ├── Icon.md
│ │ │ ├── IFrame.md
│ │ │ ├── Image.md
│ │ │ ├── Items.md
│ │ │ ├── LabelList.md
│ │ │ ├── Legend.md
│ │ │ ├── LineChart.md
│ │ │ ├── Link.md
│ │ │ ├── List.md
│ │ │ ├── Logo.md
│ │ │ ├── Markdown.md
│ │ │ ├── MenuItem.md
│ │ │ ├── MenuSeparator.md
│ │ │ ├── ModalDialog.md
│ │ │ ├── NavGroup.md
│ │ │ ├── NavLink.md
│ │ │ ├── NavPanel.md
│ │ │ ├── NoResult.md
│ │ │ ├── NumberBox.md
│ │ │ ├── Option.md
│ │ │ ├── Page.md
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── Pages.md
│ │ │ ├── Pagination.md
│ │ │ ├── PasswordInput.md
│ │ │ ├── PieChart.md
│ │ │ ├── ProgressBar.md
│ │ │ ├── Queue.md
│ │ │ ├── RadioGroup.md
│ │ │ ├── RealTimeAdapter.md
│ │ │ ├── Redirect.md
│ │ │ ├── Select.md
│ │ │ ├── Slider.md
│ │ │ ├── Slot.md
│ │ │ ├── SpaceFiller.md
│ │ │ ├── Spinner.md
│ │ │ ├── Splitter.md
│ │ │ ├── Stack.md
│ │ │ ├── StickyBox.md
│ │ │ ├── SubMenuItem.md
│ │ │ ├── Switch.md
│ │ │ ├── TabItem.md
│ │ │ ├── Table.md
│ │ │ ├── TableOfContents.md
│ │ │ ├── Tabs.md
│ │ │ ├── Text.md
│ │ │ ├── TextArea.md
│ │ │ ├── TextBox.md
│ │ │ ├── Theme.md
│ │ │ ├── TimeInput.md
│ │ │ ├── Timer.md
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneSwitch.md
│ │ │ ├── Tooltip.md
│ │ │ ├── Tree.md
│ │ │ ├── VSplitter.md
│ │ │ ├── VStack.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ ├── xmlui-spreadsheet
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Spreadsheet.md
│ │ │ └── xmlui-website-blocks
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Carousel.md
│ │ │ ├── HelloMd.md
│ │ │ ├── HeroSection.md
│ │ │ └── ScrollToTop.md
│ │ └── extensions
│ │ ├── _meta.json
│ │ ├── xmlui-animations
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Animation.md
│ │ │ ├── FadeAnimation.md
│ │ │ ├── FadeInAnimation.md
│ │ │ ├── FadeOutAnimation.md
│ │ │ ├── ScaleAnimation.md
│ │ │ └── SlideInAnimation.md
│ │ └── xmlui-website-blocks
│ │ ├── _meta.json
│ │ ├── _overview.md
│ │ ├── Carousel.md
│ │ ├── HelloMd.md
│ │ ├── HeroSection.md
│ │ └── ScrollToTop.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── package.json
│ ├── public
│ │ ├── feed.rss
│ │ ├── mockServiceWorker.js
│ │ ├── pages
│ │ │ ├── _meta.json
│ │ │ ├── app-structure.md
│ │ │ ├── build-editor-component.md
│ │ │ ├── build-hello-world-component.md
│ │ │ ├── components-intro.md
│ │ │ ├── context-variables.md
│ │ │ ├── forms.md
│ │ │ ├── globals.md
│ │ │ ├── glossary.md
│ │ │ ├── helper-tags.md
│ │ │ ├── hosted-deployment.md
│ │ │ ├── howto
│ │ │ │ ├── assign-a-complex-json-literal-to-a-component-variable.md
│ │ │ │ ├── chain-a-refetch.md
│ │ │ │ ├── control-cache-invalidation.md
│ │ │ │ ├── debounce-user-input-for-api-calls.md
│ │ │ │ ├── debug-a-component.md
│ │ │ │ ├── delay-a-datasource-until-another-datasource-is-ready.md
│ │ │ │ ├── delegate-a-method.md
│ │ │ │ ├── do-custom-form-validation.md
│ │ │ │ ├── expose-a-method-from-a-component.md
│ │ │ │ ├── filter-and-transform-data-from-an-api.md
│ │ │ │ ├── group-items-in-list-by-a-property.md
│ │ │ │ ├── handle-background-operations.md
│ │ │ │ ├── hide-an-element-until-its-datasource-is-ready.md
│ │ │ │ ├── make-a-set-of-equal-width-cards.md
│ │ │ │ ├── make-a-table-responsive.md
│ │ │ │ ├── make-navpanel-width-responsive.md
│ │ │ │ ├── modify-a-value-reported-in-a-column.md
│ │ │ │ ├── paginate-a-list.md
│ │ │ │ ├── pass-data-to-a-modal-dialog.md
│ │ │ │ ├── react-to-button-click-not-keystrokes.md
│ │ │ │ ├── set-the-initial-value-of-a-select-from-fetched-data.md
│ │ │ │ ├── share-a-modaldialog-across-components.md
│ │ │ │ ├── sync-selections-between-table-and-list-views.md
│ │ │ │ ├── update-ui-optimistically.md
│ │ │ │ ├── use-built-in-form-validation.md
│ │ │ │ └── use-the-same-modaldialog-to-add-or-edit.md
│ │ │ ├── howto.md
│ │ │ ├── intro.md
│ │ │ ├── layout.md
│ │ │ ├── markup.md
│ │ │ ├── mcp.md
│ │ │ ├── modal-dialogs.md
│ │ │ ├── news-and-reviews.md
│ │ │ ├── reactive-intro.md
│ │ │ ├── refactoring.md
│ │ │ ├── routing-and-links.md
│ │ │ ├── samples
│ │ │ │ ├── color-palette.xmlui
│ │ │ │ ├── color-values.xmlui
│ │ │ │ ├── shadow-sizes.xmlui
│ │ │ │ ├── spacing-sizes.xmlui
│ │ │ │ ├── swatch.xmlui
│ │ │ │ ├── theme-gallery-brief.xmlui
│ │ │ │ └── theme-gallery.xmlui
│ │ │ ├── scoping.md
│ │ │ ├── scripting.md
│ │ │ ├── styles-and-themes
│ │ │ │ ├── common-units.md
│ │ │ │ ├── layout-props.md
│ │ │ │ ├── theme-variable-defaults.md
│ │ │ │ ├── theme-variables.md
│ │ │ │ └── themes.md
│ │ │ ├── template-properties.md
│ │ │ ├── test.md
│ │ │ ├── tutorial-01.md
│ │ │ ├── tutorial-02.md
│ │ │ ├── tutorial-03.md
│ │ │ ├── tutorial-04.md
│ │ │ ├── tutorial-05.md
│ │ │ ├── tutorial-06.md
│ │ │ ├── tutorial-07.md
│ │ │ ├── tutorial-08.md
│ │ │ ├── tutorial-09.md
│ │ │ ├── tutorial-10.md
│ │ │ ├── tutorial-11.md
│ │ │ ├── tutorial-12.md
│ │ │ ├── universal-properties.md
│ │ │ ├── user-defined-components.md
│ │ │ ├── vscode.md
│ │ │ ├── working-with-markdown.md
│ │ │ ├── working-with-text.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-charts
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── DonutChart.md
│ │ │ │ ├── LabelList.md
│ │ │ │ ├── Legend.md
│ │ │ │ ├── LineChart.md
│ │ │ │ └── PieChart.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ └── xmlui-spreadsheet
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ └── Spreadsheet.md
│ │ ├── resources
│ │ │ ├── devdocs
│ │ │ │ ├── debug-proxy-object-2.png
│ │ │ │ ├── debug-proxy-object.png
│ │ │ │ ├── table_editor_01.png
│ │ │ │ ├── table_editor_02.png
│ │ │ │ ├── table_editor_03.png
│ │ │ │ ├── table_editor_04.png
│ │ │ │ ├── table_editor_05.png
│ │ │ │ ├── table_editor_06.png
│ │ │ │ ├── table_editor_07.png
│ │ │ │ ├── table_editor_08.png
│ │ │ │ ├── table_editor_09.png
│ │ │ │ ├── table_editor_10.png
│ │ │ │ ├── table_editor_11.png
│ │ │ │ ├── table-editor-01.png
│ │ │ │ ├── table-editor-02.png
│ │ │ │ ├── table-editor-03.png
│ │ │ │ ├── table-editor-04.png
│ │ │ │ ├── table-editor-06.png
│ │ │ │ ├── table-editor-07.png
│ │ │ │ ├── table-editor-08.png
│ │ │ │ ├── table-editor-09.png
│ │ │ │ └── xmlui-rendering-of-tiptap-markdown.png
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ ├── clients.json
│ │ │ │ ├── daily-revenue.json
│ │ │ │ ├── dashboard-stats.json
│ │ │ │ ├── demo.xmlui
│ │ │ │ ├── demo.xmlui.xs
│ │ │ │ ├── downloads
│ │ │ │ │ └── downloads.json
│ │ │ │ ├── for-download
│ │ │ │ │ ├── index-with-api.html
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── mockApi.js
│ │ │ │ │ ├── start-darwin.sh
│ │ │ │ │ ├── start-linux.sh
│ │ │ │ │ ├── start.bat
│ │ │ │ │ └── xmlui
│ │ │ │ │ └── xmlui-standalone.umd.js
│ │ │ │ ├── getting-started
│ │ │ │ │ ├── cl-tutorial-final.zip
│ │ │ │ │ ├── cl-tutorial.zip
│ │ │ │ │ ├── cl-tutorial2.zip
│ │ │ │ │ ├── cl-tutorial3.zip
│ │ │ │ │ ├── cl-tutorial4.zip
│ │ │ │ │ ├── cl-tutorial5.zip
│ │ │ │ │ ├── cl-tutorial6.zip
│ │ │ │ │ ├── getting-started.zip
│ │ │ │ │ ├── hello-xmlui.zip
│ │ │ │ │ ├── xmlui-empty.zip
│ │ │ │ │ └── xmlui-starter.zip
│ │ │ │ ├── howto
│ │ │ │ │ └── component-icons
│ │ │ │ │ └── up-arrow.svg
│ │ │ │ ├── invoices.json
│ │ │ │ ├── monthly-status.json
│ │ │ │ ├── news-and-reviews.json
│ │ │ │ ├── products.json
│ │ │ │ ├── releases.json
│ │ │ │ ├── tutorials
│ │ │ │ │ ├── datasource
│ │ │ │ │ │ └── api.ts
│ │ │ │ │ └── p2do
│ │ │ │ │ ├── api.ts
│ │ │ │ │ └── todo-logo.svg
│ │ │ │ └── xmlui.json
│ │ │ ├── github.svg
│ │ │ ├── images
│ │ │ │ ├── apiaction-tutorial
│ │ │ │ │ ├── add-success.png
│ │ │ │ │ ├── apiaction-param.png
│ │ │ │ │ ├── change-completed.png
│ │ │ │ │ ├── change-in-progress.png
│ │ │ │ │ ├── confirm-delete.png
│ │ │ │ │ ├── data-error.png
│ │ │ │ │ ├── data-progress.png
│ │ │ │ │ ├── data-success.png
│ │ │ │ │ ├── display-1.png
│ │ │ │ │ ├── item-deleted.png
│ │ │ │ │ ├── item-updated.png
│ │ │ │ │ ├── missing-api-key.png
│ │ │ │ │ ├── new-item-added.png
│ │ │ │ │ └── test-message.png
│ │ │ │ ├── chat-api
│ │ │ │ │ └── domain-model.svg
│ │ │ │ ├── components
│ │ │ │ │ ├── image
│ │ │ │ │ │ └── breakfast.jpg
│ │ │ │ │ ├── markdown
│ │ │ │ │ │ └── colors.png
│ │ │ │ │ └── modal
│ │ │ │ │ ├── deep_link_dialog_1.jpg
│ │ │ │ │ └── deep_link_dialog_2.jpg
│ │ │ │ ├── create-apps
│ │ │ │ │ ├── collapsed-vertical.png
│ │ │ │ │ ├── using-forms-warning-dialog.png
│ │ │ │ │ └── using-forms.png
│ │ │ │ ├── datasource-tutorial
│ │ │ │ │ ├── data-with-header.png
│ │ │ │ │ ├── filtered-data.png
│ │ │ │ │ ├── filtered-items.png
│ │ │ │ │ ├── initial-page-items.png
│ │ │ │ │ ├── list-items.png
│ │ │ │ │ ├── next-page-items.png
│ │ │ │ │ ├── no-data.png
│ │ │ │ │ ├── pagination-1.jpg
│ │ │ │ │ ├── pagination-1.png
│ │ │ │ │ ├── polling-1.png
│ │ │ │ │ ├── refetch-data.png
│ │ │ │ │ ├── slow-loading.png
│ │ │ │ │ ├── test-message.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── unconventional-data.png
│ │ │ │ │ └── unfiltered-items.png
│ │ │ │ ├── flower.jpg
│ │ │ │ ├── get-started
│ │ │ │ │ ├── add-new-contact.png
│ │ │ │ │ ├── app-modified.png
│ │ │ │ │ ├── app-start.png
│ │ │ │ │ ├── app-with-boxes.png
│ │ │ │ │ ├── app-with-toast.png
│ │ │ │ │ ├── boilerplate-structure.png
│ │ │ │ │ ├── cl-initial.png
│ │ │ │ │ ├── cl-start.png
│ │ │ │ │ ├── contact-counts.png
│ │ │ │ │ ├── contact-dialog-title.png
│ │ │ │ │ ├── contact-dialog.png
│ │ │ │ │ ├── contact-menus.png
│ │ │ │ │ ├── contact-predicates.png
│ │ │ │ │ ├── context-menu.png
│ │ │ │ │ ├── dashboard-numbers.png
│ │ │ │ │ ├── default-contact-list.png
│ │ │ │ │ ├── delete-contact.png
│ │ │ │ │ ├── delete-task.png
│ │ │ │ │ ├── detailed-template.png
│ │ │ │ │ ├── edit-contact-details.png
│ │ │ │ │ ├── edited-contact-saved.png
│ │ │ │ │ ├── empty-sections.png
│ │ │ │ │ ├── filter-completed.png
│ │ │ │ │ ├── fullwidth-desktop.png
│ │ │ │ │ ├── fullwidth-mobile.png
│ │ │ │ │ ├── initial-table.png
│ │ │ │ │ ├── items-and-badges.png
│ │ │ │ │ ├── loading-message.png
│ │ │ │ │ ├── new-contact-button.png
│ │ │ │ │ ├── new-contact-saved.png
│ │ │ │ │ ├── no-empty-sections.png
│ │ │ │ │ ├── personal-todo-initial.png
│ │ │ │ │ ├── piechart.png
│ │ │ │ │ ├── review-today.png
│ │ │ │ │ ├── rudimentary-dashboard.png
│ │ │ │ │ ├── section-collapsed.png
│ │ │ │ │ ├── sectioned-items.png
│ │ │ │ │ ├── sections-ordered.png
│ │ │ │ │ ├── spacex-list-with-links.png
│ │ │ │ │ ├── spacex-list.png
│ │ │ │ │ ├── start-personal-todo-1.png
│ │ │ │ │ ├── submit-new-contact.png
│ │ │ │ │ ├── submit-new-task.png
│ │ │ │ │ ├── syntax-highlighting.png
│ │ │ │ │ ├── table-with-badge.png
│ │ │ │ │ ├── template-with-card.png
│ │ │ │ │ ├── test-emulated-api.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── todo-logo.png
│ │ │ │ │ └── xmlui-tools.png
│ │ │ │ ├── HelloApp.png
│ │ │ │ ├── HelloApp2.png
│ │ │ │ ├── logos
│ │ │ │ │ ├── xmlui1.svg
│ │ │ │ │ ├── xmlui2.svg
│ │ │ │ │ ├── xmlui3.svg
│ │ │ │ │ ├── xmlui4.svg
│ │ │ │ │ ├── xmlui5.svg
│ │ │ │ │ ├── xmlui6.svg
│ │ │ │ │ └── xmlui7.svg
│ │ │ │ ├── pdf
│ │ │ │ │ └── dummy-pdf.jpg
│ │ │ │ ├── rendering-engine
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ ├── Component.svg
│ │ │ │ │ ├── CompoundComponent.svg
│ │ │ │ │ ├── RootComponent.svg
│ │ │ │ │ └── tree-with-containers.svg
│ │ │ │ ├── reviewers-guide
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ └── incbutton-in-action.png
│ │ │ │ ├── tools
│ │ │ │ │ └── boilerplate-structure.png
│ │ │ │ ├── try.svg
│ │ │ │ ├── tutorial
│ │ │ │ │ ├── app-chat-history.png
│ │ │ │ │ ├── app-content-placeholder.png
│ │ │ │ │ ├── app-header-and-content.png
│ │ │ │ │ ├── app-links-channel-selected.png
│ │ │ │ │ ├── app-links-click.png
│ │ │ │ │ ├── app-navigation.png
│ │ │ │ │ ├── finished-ex01.png
│ │ │ │ │ ├── finished-ex02.png
│ │ │ │ │ ├── hello.png
│ │ │ │ │ ├── splash-screen-advanced.png
│ │ │ │ │ ├── splash-screen-after-click.png
│ │ │ │ │ ├── splash-screen-centered.png
│ │ │ │ │ ├── splash-screen-events.png
│ │ │ │ │ ├── splash-screen-expression.png
│ │ │ │ │ ├── splash-screen-reuse-after.png
│ │ │ │ │ ├── splash-screen-reuse-before.png
│ │ │ │ │ └── splash-screen.png
│ │ │ │ └── tutorial-01.png
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ ├── Boxes.xmlui
│ │ │ ├── Breadcrumb.xmlui
│ │ │ ├── ChangeLog.xmlui
│ │ │ ├── ColorPalette.xmlui
│ │ │ ├── DocumentLinks.xmlui
│ │ │ ├── DocumentPage.xmlui
│ │ │ ├── DocumentPageNoTOC.xmlui
│ │ │ ├── Icons.xmlui
│ │ │ ├── IncButton.xmlui
│ │ │ ├── IncButton2.xmlui
│ │ │ ├── NameValue.xmlui
│ │ │ ├── PageNotFound.xmlui
│ │ │ ├── PaletteItem.xmlui
│ │ │ ├── Palettes.xmlui
│ │ │ ├── SectionHeader.xmlui
│ │ │ ├── TBD.xmlui
│ │ │ ├── Test.xmlui
│ │ │ ├── ThemesIntro.xmlui
│ │ │ ├── ThousandThemes.xmlui
│ │ │ ├── TubeStops.xmlui
│ │ │ ├── TubeStops.xmlui.xs
│ │ │ └── TwoColumnCode.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ ├── docs-theme.ts
│ │ ├── earthtone.ts
│ │ ├── xmlui-gray-on-default.ts
│ │ ├── xmlui-green-on-default.ts
│ │ └── xmlui-orange-on-default.ts
│ └── tsconfig.json
├── LICENSE
├── package-lock.json
├── package.json
├── packages
│ ├── tsconfig.json
│ ├── xmlui-animations
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── Animation.tsx
│ │ ├── AnimationNative.tsx
│ │ ├── FadeAnimation.tsx
│ │ ├── FadeInAnimation.tsx
│ │ ├── FadeOutAnimation.tsx
│ │ ├── index.tsx
│ │ ├── ScaleAnimation.tsx
│ │ └── SlideInAnimation.tsx
│ ├── xmlui-devtools
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── devtools
│ │ │ │ ├── DevTools.tsx
│ │ │ │ ├── DevToolsNative.module.scss
│ │ │ │ ├── DevToolsNative.tsx
│ │ │ │ ├── ModalDialog.module.scss
│ │ │ │ ├── ModalDialog.tsx
│ │ │ │ ├── ModalVisibilityContext.tsx
│ │ │ │ ├── Tooltip.module.scss
│ │ │ │ ├── Tooltip.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── editor
│ │ │ │ └── Editor.tsx
│ │ │ └── index.tsx
│ │ └── vite.config-overrides.ts
│ ├── xmlui-hello-world
│ │ ├── .gitignore
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── HelloWorld.module.scss
│ │ ├── HelloWorld.tsx
│ │ ├── HelloWorldNative.tsx
│ │ └── index.tsx
│ ├── xmlui-os-frames
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── IPhoneFrame.module.scss
│ │ ├── IPhoneFrame.tsx
│ │ ├── MacOSAppFrame.module.scss
│ │ ├── MacOSAppFrame.tsx
│ │ ├── WindowsAppFrame.module.scss
│ │ └── WindowsAppFrame.tsx
│ ├── xmlui-pdf
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ ├── components
│ │ │ │ └── Pdf.xmlui
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── LazyPdfNative.tsx
│ │ ├── Pdf.module.scss
│ │ └── Pdf.tsx
│ ├── xmlui-playground
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── hooks
│ │ │ ├── usePlayground.ts
│ │ │ └── useToast.ts
│ │ ├── index.tsx
│ │ ├── playground
│ │ │ ├── Box.module.scss
│ │ │ ├── Box.tsx
│ │ │ ├── CodeSelector.tsx
│ │ │ ├── ConfirmationDialog.module.scss
│ │ │ ├── ConfirmationDialog.tsx
│ │ │ ├── Editor.tsx
│ │ │ ├── Header.module.scss
│ │ │ ├── Header.tsx
│ │ │ ├── Playground.tsx
│ │ │ ├── PlaygroundContent.module.scss
│ │ │ ├── PlaygroundContent.tsx
│ │ │ ├── PlaygroundNative.module.scss
│ │ │ ├── PlaygroundNative.tsx
│ │ │ ├── Preview.module.scss
│ │ │ ├── Preview.tsx
│ │ │ ├── Select.module.scss
│ │ │ ├── StandalonePlayground.tsx
│ │ │ ├── StandalonePlaygroundNative.module.scss
│ │ │ ├── StandalonePlaygroundNative.tsx
│ │ │ ├── ThemeSwitcher.module.scss
│ │ │ ├── ThemeSwitcher.tsx
│ │ │ ├── ToneSwitcher.tsx
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.tsx
│ │ │ └── utils.ts
│ │ ├── providers
│ │ │ ├── Toast.module.scss
│ │ │ └── ToastProvider.tsx
│ │ ├── state
│ │ │ └── store.ts
│ │ ├── themes
│ │ │ └── theme.ts
│ │ └── utils
│ │ └── helpers.ts
│ ├── xmlui-search
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── Search.module.scss
│ │ └── Search.tsx
│ ├── xmlui-spreadsheet
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── Spreadsheet.tsx
│ │ └── SpreadsheetNative.tsx
│ └── xmlui-website-blocks
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── demo
│ │ ├── components
│ │ │ ├── HeroBackgroundBreakoutPage.xmlui
│ │ │ ├── HeroBackgroundsPage.xmlui
│ │ │ ├── HeroContentsPage.xmlui
│ │ │ ├── HeroTextAlignPage.xmlui
│ │ │ ├── HeroTextPage.xmlui
│ │ │ └── HeroTonesPage.xmlui
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── default.ts
│ ├── index.html
│ ├── index.ts
│ ├── meta
│ │ └── componentsMetadata.ts
│ ├── package.json
│ ├── public
│ │ └── resources
│ │ ├── building.jpg
│ │ └── xmlui-logo.svg
│ └── src
│ ├── Carousel
│ │ ├── Carousel.module.scss
│ │ ├── Carousel.tsx
│ │ ├── CarouselContext.tsx
│ │ └── CarouselNative.tsx
│ ├── FancyButton
│ │ ├── FancyButton.module.scss
│ │ ├── FancyButton.tsx
│ │ └── FancyButton.xmlui
│ ├── Hello
│ │ ├── Hello.tsx
│ │ ├── Hello.xmlui
│ │ └── Hello.xmlui.xs
│ ├── HeroSection
│ │ ├── HeroSection.module.scss
│ │ ├── HeroSection.spec.ts
│ │ ├── HeroSection.tsx
│ │ └── HeroSectionNative.tsx
│ ├── index.tsx
│ ├── ScrollToTop
│ │ ├── ScrollToTop.module.scss
│ │ ├── ScrollToTop.tsx
│ │ └── ScrollToTopNative.tsx
│ └── vite-env.d.ts
├── playwright.config.ts
├── README.md
├── tools
│ ├── codefence
│ │ └── xmlui-code-fence-docs.md
│ ├── create-app
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── create-app.ts
│ │ ├── helpers
│ │ │ ├── copy.ts
│ │ │ ├── get-pkg-manager.ts
│ │ │ ├── git.ts
│ │ │ ├── install.ts
│ │ │ ├── is-folder-empty.ts
│ │ │ ├── is-writeable.ts
│ │ │ ├── make-dir.ts
│ │ │ └── validate-pkg.ts
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── templates
│ │ │ ├── default
│ │ │ │ └── ts
│ │ │ │ ├── gitignore
│ │ │ │ ├── index.html
│ │ │ │ ├── index.ts
│ │ │ │ ├── public
│ │ │ │ │ ├── mockServiceWorker.js
│ │ │ │ │ ├── resources
│ │ │ │ │ │ ├── favicon.ico
│ │ │ │ │ │ └── xmlui-logo.svg
│ │ │ │ │ └── serve.json
│ │ │ │ └── src
│ │ │ │ ├── components
│ │ │ │ │ ├── ApiAware.xmlui
│ │ │ │ │ ├── Home.xmlui
│ │ │ │ │ ├── IncButton.xmlui
│ │ │ │ │ └── PagePanel.xmlui
│ │ │ │ ├── config.ts
│ │ │ │ └── Main.xmlui
│ │ │ ├── index.ts
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ ├── create-xmlui-hello-world
│ │ ├── index.js
│ │ └── package.json
│ └── vscode
│ ├── .gitignore
│ ├── .vscode
│ │ ├── launch.json
│ │ └── tasks.json
│ ├── .vscodeignore
│ ├── build.sh
│ ├── CHANGELOG.md
│ ├── esbuild.js
│ ├── eslint.config.mjs
│ ├── formatter-docs.md
│ ├── generate-test-sample.sh
│ ├── LICENSE.md
│ ├── package-lock.json
│ ├── package.json
│ ├── README.md
│ ├── resources
│ │ ├── xmlui-logo.png
│ │ └── xmlui-markup-syntax-highlighting.png
│ ├── src
│ │ ├── extension.ts
│ │ └── server.ts
│ ├── syntaxes
│ │ └── xmlui.tmLanguage.json
│ ├── test-samples
│ │ └── sample.xmlui
│ ├── tsconfig.json
│ └── tsconfig.tsbuildinfo
├── turbo.json
└── xmlui
├── .gitignore
├── bin
│ ├── bootstrap.cjs
│ ├── bootstrap.js
│ ├── build-lib.ts
│ ├── build.ts
│ ├── index.ts
│ ├── preview.ts
│ ├── start.ts
│ ├── vite-xmlui-plugin.ts
│ └── viteConfig.ts
├── CHANGELOG.md
├── conventions
│ ├── component-qa-checklist.md
│ ├── copilot-conventions.md
│ ├── create-xmlui-components.md
│ ├── mermaid.md
│ ├── testing-conventions.md
│ └── xmlui-in-a-nutshell.md
├── dev-docs
│ ├── accessibility.md
│ ├── build-system.md
│ ├── build-xmlui.md
│ ├── component-behaviors.md
│ ├── components-with-options.md
│ ├── containers.md
│ ├── data-operations.md
│ ├── glossary.md
│ ├── index.md
│ ├── next
│ │ ├── component-dev-guide.md
│ │ ├── configuration-management-enhancement-summary.md
│ │ ├── documentation-scripts-refactoring-complete-summary.md
│ │ ├── documentation-scripts-refactoring-plan.md
│ │ ├── duplicate-pattern-extraction-summary.md
│ │ ├── error-handling-standardization-summary.md
│ │ ├── generating-component-reference.md
│ │ ├── index.md
│ │ ├── logging-consistency-implementation-summary.md
│ │ ├── project-build.md
│ │ ├── project-structure.md
│ │ ├── theme-context.md
│ │ ├── tiptap-design-considerations.md
│ │ ├── working-with-code.md
│ │ ├── xmlui-runtime-architecture
│ │ └── xmlui-wcag-accessibility-report.md
│ ├── react-fundamentals.md
│ ├── release-method.md
│ ├── standalone-app.md
│ ├── ud-components.md
│ └── xmlui-repo.md
├── package.json
├── scripts
│ ├── coverage-only.js
│ ├── e2e-test-summary.js
│ ├── generate-docs
│ │ ├── build-downloads-map.mjs
│ │ ├── build-pages-map.mjs
│ │ ├── components-config.json
│ │ ├── configuration-management.mjs
│ │ ├── constants.mjs
│ │ ├── create-theme-files.mjs
│ │ ├── DocsGenerator.mjs
│ │ ├── error-handling.mjs
│ │ ├── extensions-config.json
│ │ ├── folders.mjs
│ │ ├── generate-summary-files.mjs
│ │ ├── get-docs.mjs
│ │ ├── input-handler.mjs
│ │ ├── logger.mjs
│ │ ├── logging-standards.mjs
│ │ ├── MetadataProcessor.mjs
│ │ ├── pattern-utilities.mjs
│ │ └── utils.mjs
│ ├── get-langserver-metadata.js
│ ├── inline-links.mjs
│ └── README-e2e-summary.md
├── src
│ ├── abstractions
│ │ ├── _conventions.md
│ │ ├── ActionDefs.ts
│ │ ├── AppContextDefs.ts
│ │ ├── ComponentDefs.ts
│ │ ├── ContainerDefs.ts
│ │ ├── ExtensionDefs.ts
│ │ ├── FunctionDefs.ts
│ │ ├── RendererDefs.ts
│ │ ├── scripting
│ │ │ ├── BlockScope.ts
│ │ │ ├── Compilation.ts
│ │ │ ├── LogicalThread.ts
│ │ │ ├── LoopScope.ts
│ │ │ ├── modules.ts
│ │ │ ├── ScriptParserError.ts
│ │ │ ├── Token.ts
│ │ │ ├── TryScope.ts
│ │ │ └── TryScopeExp.ts
│ │ └── ThemingDefs.ts
│ ├── components
│ │ ├── _conventions.md
│ │ ├── abstractions.ts
│ │ ├── Accordion
│ │ │ ├── Accordion.md
│ │ │ ├── Accordion.module.scss
│ │ │ ├── Accordion.spec.ts
│ │ │ ├── Accordion.tsx
│ │ │ ├── AccordionContext.tsx
│ │ │ ├── AccordionItem.tsx
│ │ │ ├── AccordionItemNative.tsx
│ │ │ └── AccordionNative.tsx
│ │ ├── Animation
│ │ │ └── AnimationNative.tsx
│ │ ├── APICall
│ │ │ ├── APICall.md
│ │ │ ├── APICall.spec.ts
│ │ │ ├── APICall.tsx
│ │ │ └── APICallNative.tsx
│ │ ├── App
│ │ │ ├── App.md
│ │ │ ├── App.module.scss
│ │ │ ├── App.spec.ts
│ │ │ ├── App.tsx
│ │ │ ├── AppLayoutContext.ts
│ │ │ ├── AppNative.tsx
│ │ │ ├── AppStateContext.ts
│ │ │ ├── doc-resources
│ │ │ │ ├── condensed-sticky.xmlui
│ │ │ │ ├── condensed.xmlui
│ │ │ │ ├── horizontal-sticky.xmlui
│ │ │ │ ├── horizontal.xmlui
│ │ │ │ ├── vertical-full-header.xmlui
│ │ │ │ ├── vertical-sticky.xmlui
│ │ │ │ └── vertical.xmlui
│ │ │ ├── IndexerContext.ts
│ │ │ ├── LinkInfoContext.ts
│ │ │ ├── SearchContext.tsx
│ │ │ ├── Sheet.module.scss
│ │ │ └── Sheet.tsx
│ │ ├── AppHeader
│ │ │ ├── AppHeader.md
│ │ │ ├── AppHeader.module.scss
│ │ │ ├── AppHeader.spec.ts
│ │ │ ├── AppHeader.tsx
│ │ │ └── AppHeaderNative.tsx
│ │ ├── AppState
│ │ │ ├── AppState.md
│ │ │ ├── AppState.spec.ts
│ │ │ ├── AppState.tsx
│ │ │ └── AppStateNative.tsx
│ │ ├── AutoComplete
│ │ │ ├── AutoComplete.md
│ │ │ ├── AutoComplete.module.scss
│ │ │ ├── AutoComplete.spec.ts
│ │ │ ├── AutoComplete.tsx
│ │ │ ├── AutoCompleteContext.tsx
│ │ │ └── AutoCompleteNative.tsx
│ │ ├── Avatar
│ │ │ ├── Avatar.md
│ │ │ ├── Avatar.module.scss
│ │ │ ├── Avatar.spec.ts
│ │ │ ├── Avatar.tsx
│ │ │ └── AvatarNative.tsx
│ │ ├── Backdrop
│ │ │ ├── Backdrop.md
│ │ │ ├── Backdrop.module.scss
│ │ │ ├── Backdrop.spec.ts
│ │ │ ├── Backdrop.tsx
│ │ │ └── BackdropNative.tsx
│ │ ├── Badge
│ │ │ ├── Badge.md
│ │ │ ├── Badge.module.scss
│ │ │ ├── Badge.spec.ts
│ │ │ ├── Badge.tsx
│ │ │ └── BadgeNative.tsx
│ │ ├── Bookmark
│ │ │ ├── Bookmark.md
│ │ │ ├── Bookmark.module.scss
│ │ │ ├── Bookmark.spec.ts
│ │ │ ├── Bookmark.tsx
│ │ │ └── BookmarkNative.tsx
│ │ ├── Breakout
│ │ │ ├── Breakout.module.scss
│ │ │ ├── Breakout.spec.ts
│ │ │ ├── Breakout.tsx
│ │ │ └── BreakoutNative.tsx
│ │ ├── Button
│ │ │ ├── Button-style.spec.ts
│ │ │ ├── Button.md
│ │ │ ├── Button.module.scss
│ │ │ ├── Button.spec.ts
│ │ │ ├── Button.tsx
│ │ │ └── ButtonNative.tsx
│ │ ├── Card
│ │ │ ├── Card.md
│ │ │ ├── Card.module.scss
│ │ │ ├── Card.spec.ts
│ │ │ ├── Card.tsx
│ │ │ └── CardNative.tsx
│ │ ├── Carousel
│ │ │ ├── Carousel.md
│ │ │ ├── Carousel.module.scss
│ │ │ ├── Carousel.spec.ts
│ │ │ ├── Carousel.tsx
│ │ │ ├── CarouselContext.tsx
│ │ │ ├── CarouselItem.tsx
│ │ │ ├── CarouselItemNative.tsx
│ │ │ └── CarouselNative.tsx
│ │ ├── ChangeListener
│ │ │ ├── ChangeListener.md
│ │ │ ├── ChangeListener.spec.ts
│ │ │ ├── ChangeListener.tsx
│ │ │ └── ChangeListenerNative.tsx
│ │ ├── chart-color-schemes.ts
│ │ ├── Charts
│ │ │ ├── AreaChart
│ │ │ │ ├── AreaChart.md
│ │ │ │ ├── AreaChart.spec.ts
│ │ │ │ ├── AreaChart.tsx
│ │ │ │ └── AreaChartNative.tsx
│ │ │ ├── BarChart
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── BarChart.module.scss
│ │ │ │ ├── BarChart.spec.ts
│ │ │ │ ├── BarChart.tsx
│ │ │ │ └── BarChartNative.tsx
│ │ │ ├── DonutChart
│ │ │ │ ├── DonutChart.spec.ts
│ │ │ │ └── DonutChart.tsx
│ │ │ ├── LabelList
│ │ │ │ ├── LabelList.spec.ts
│ │ │ │ ├── LabelList.tsx
│ │ │ │ ├── LabelListNative.module.scss
│ │ │ │ └── LabelListNative.tsx
│ │ │ ├── Legend
│ │ │ │ ├── Legend.spec.ts
│ │ │ │ ├── Legend.tsx
│ │ │ │ └── LegendNative.tsx
│ │ │ ├── LineChart
│ │ │ │ ├── LineChart.md
│ │ │ │ ├── LineChart.module.scss
│ │ │ │ ├── LineChart.spec.ts
│ │ │ │ ├── LineChart.tsx
│ │ │ │ └── LineChartNative.tsx
│ │ │ ├── PieChart
│ │ │ │ ├── PieChart.md
│ │ │ │ ├── PieChart.spec.ts
│ │ │ │ ├── PieChart.tsx
│ │ │ │ ├── PieChartNative.module.scss
│ │ │ │ └── PieChartNative.tsx
│ │ │ ├── RadarChart
│ │ │ │ ├── RadarChart.md
│ │ │ │ ├── RadarChart.spec.ts
│ │ │ │ ├── RadarChart.tsx
│ │ │ │ └── RadarChartNative.tsx
│ │ │ ├── Tooltip
│ │ │ │ ├── TooltipContent.module.scss
│ │ │ │ ├── TooltipContent.spec.ts
│ │ │ │ └── TooltipContent.tsx
│ │ │ └── utils
│ │ │ ├── abstractions.ts
│ │ │ └── ChartProvider.tsx
│ │ ├── Checkbox
│ │ │ ├── Checkbox.md
│ │ │ ├── Checkbox.spec.ts
│ │ │ └── Checkbox.tsx
│ │ ├── CodeBlock
│ │ │ ├── CodeBlock.module.scss
│ │ │ ├── CodeBlock.spec.ts
│ │ │ ├── CodeBlock.tsx
│ │ │ ├── CodeBlockNative.tsx
│ │ │ └── highlight-code.ts
│ │ ├── collectedComponentMetadata.ts
│ │ ├── ColorPicker
│ │ │ ├── ColorPicker.md
│ │ │ ├── ColorPicker.module.scss
│ │ │ ├── ColorPicker.spec.ts
│ │ │ ├── ColorPicker.tsx
│ │ │ └── ColorPickerNative.tsx
│ │ ├── Column
│ │ │ ├── Column.md
│ │ │ ├── Column.tsx
│ │ │ ├── ColumnNative.tsx
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ └── TableContext.tsx
│ │ ├── component-utils.ts
│ │ ├── ComponentProvider.tsx
│ │ ├── ComponentRegistryContext.tsx
│ │ ├── container-helpers.tsx
│ │ ├── ContentSeparator
│ │ │ ├── ContentSeparator.md
│ │ │ ├── ContentSeparator.module.scss
│ │ │ ├── ContentSeparator.spec.ts
│ │ │ ├── ContentSeparator.tsx
│ │ │ └── ContentSeparatorNative.tsx
│ │ ├── DataSource
│ │ │ ├── DataSource.md
│ │ │ └── DataSource.tsx
│ │ ├── DateInput
│ │ │ ├── DateInput.md
│ │ │ ├── DateInput.module.scss
│ │ │ ├── DateInput.spec.ts
│ │ │ ├── DateInput.tsx
│ │ │ └── DateInputNative.tsx
│ │ ├── DatePicker
│ │ │ ├── DatePicker.md
│ │ │ ├── DatePicker.module.scss
│ │ │ ├── DatePicker.spec.ts
│ │ │ ├── DatePicker.tsx
│ │ │ └── DatePickerNative.tsx
│ │ ├── DropdownMenu
│ │ │ ├── DropdownMenu.md
│ │ │ ├── DropdownMenu.module.scss
│ │ │ ├── DropdownMenu.spec.ts
│ │ │ ├── DropdownMenu.tsx
│ │ │ ├── DropdownMenuNative.tsx
│ │ │ ├── MenuItem.md
│ │ │ └── SubMenuItem.md
│ │ ├── EmojiSelector
│ │ │ ├── EmojiSelector.md
│ │ │ ├── EmojiSelector.spec.ts
│ │ │ ├── EmojiSelector.tsx
│ │ │ └── EmojiSelectorNative.tsx
│ │ ├── ExpandableItem
│ │ │ ├── ExpandableItem.module.scss
│ │ │ ├── ExpandableItem.spec.ts
│ │ │ ├── ExpandableItem.tsx
│ │ │ └── ExpandableItemNative.tsx
│ │ ├── FileInput
│ │ │ ├── FileInput.md
│ │ │ ├── FileInput.module.scss
│ │ │ ├── FileInput.spec.ts
│ │ │ ├── FileInput.tsx
│ │ │ └── FileInputNative.tsx
│ │ ├── FileUploadDropZone
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FileUploadDropZone.module.scss
│ │ │ ├── FileUploadDropZone.spec.ts
│ │ │ ├── FileUploadDropZone.tsx
│ │ │ └── FileUploadDropZoneNative.tsx
│ │ ├── FlowLayout
│ │ │ ├── FlowLayout.md
│ │ │ ├── FlowLayout.module.scss
│ │ │ ├── FlowLayout.spec.ts
│ │ │ ├── FlowLayout.spec.ts-snapshots
│ │ │ │ └── Edge-cases-boxShadow-is-not-clipped-1-non-smoke-darwin.png
│ │ │ ├── FlowLayout.tsx
│ │ │ └── FlowLayoutNative.tsx
│ │ ├── Footer
│ │ │ ├── Footer.md
│ │ │ ├── Footer.module.scss
│ │ │ ├── Footer.spec.ts
│ │ │ ├── Footer.tsx
│ │ │ └── FooterNative.tsx
│ │ ├── Form
│ │ │ ├── Form.md
│ │ │ ├── Form.module.scss
│ │ │ ├── Form.spec.ts
│ │ │ ├── Form.tsx
│ │ │ ├── formActions.ts
│ │ │ ├── FormContext.ts
│ │ │ └── FormNative.tsx
│ │ ├── FormItem
│ │ │ ├── FormItem.md
│ │ │ ├── FormItem.module.scss
│ │ │ ├── FormItem.spec.ts
│ │ │ ├── FormItem.tsx
│ │ │ ├── FormItemNative.tsx
│ │ │ ├── HelperText.module.scss
│ │ │ ├── HelperText.tsx
│ │ │ ├── ItemWithLabel.tsx
│ │ │ └── Validations.ts
│ │ ├── FormSection
│ │ │ ├── FormSection.md
│ │ │ ├── FormSection.ts
│ │ │ └── FormSection.xmlui
│ │ ├── Fragment
│ │ │ ├── Fragment.spec.ts
│ │ │ └── Fragment.tsx
│ │ ├── Heading
│ │ │ ├── abstractions.ts
│ │ │ ├── H1.md
│ │ │ ├── H1.spec.ts
│ │ │ ├── H2.md
│ │ │ ├── H2.spec.ts
│ │ │ ├── H3.md
│ │ │ ├── H3.spec.ts
│ │ │ ├── H4.md
│ │ │ ├── H4.spec.ts
│ │ │ ├── H5.md
│ │ │ ├── H5.spec.ts
│ │ │ ├── H6.md
│ │ │ ├── H6.spec.ts
│ │ │ ├── Heading.md
│ │ │ ├── Heading.module.scss
│ │ │ ├── Heading.spec.ts
│ │ │ ├── Heading.tsx
│ │ │ └── HeadingNative.tsx
│ │ ├── HoverCard
│ │ │ ├── HoverCard.tsx
│ │ │ └── HovercardNative.tsx
│ │ ├── HtmlTags
│ │ │ ├── HtmlTags.module.scss
│ │ │ ├── HtmlTags.spec.ts
│ │ │ └── HtmlTags.tsx
│ │ ├── Icon
│ │ │ ├── AdmonitionDanger.tsx
│ │ │ ├── AdmonitionInfo.tsx
│ │ │ ├── AdmonitionNote.tsx
│ │ │ ├── AdmonitionTip.tsx
│ │ │ ├── AdmonitionWarning.tsx
│ │ │ ├── ApiIcon.tsx
│ │ │ ├── ArrowDropDown.module.scss
│ │ │ ├── ArrowDropDown.tsx
│ │ │ ├── ArrowDropUp.module.scss
│ │ │ ├── ArrowDropUp.tsx
│ │ │ ├── ArrowLeft.module.scss
│ │ │ ├── ArrowLeft.tsx
│ │ │ ├── ArrowRight.module.scss
│ │ │ ├── ArrowRight.tsx
│ │ │ ├── Attach.tsx
│ │ │ ├── Binding.module.scss
│ │ │ ├── Binding.tsx
│ │ │ ├── BoardIcon.tsx
│ │ │ ├── BoxIcon.tsx
│ │ │ ├── CheckIcon.tsx
│ │ │ ├── ChevronDownIcon.tsx
│ │ │ ├── ChevronLeft.tsx
│ │ │ ├── ChevronRight.tsx
│ │ │ ├── ChevronUpIcon.tsx
│ │ │ ├── CodeFileIcon.tsx
│ │ │ ├── CodeSandbox.tsx
│ │ │ ├── CompactListIcon.tsx
│ │ │ ├── ContentCopyIcon.tsx
│ │ │ ├── DarkToLightIcon.tsx
│ │ │ ├── DatabaseIcon.module.scss
│ │ │ ├── DatabaseIcon.tsx
│ │ │ ├── DocFileIcon.tsx
│ │ │ ├── DocIcon.tsx
│ │ │ ├── DotMenuHorizontalIcon.tsx
│ │ │ ├── DotMenuIcon.tsx
│ │ │ ├── EmailIcon.tsx
│ │ │ ├── EmptyFolderIcon.tsx
│ │ │ ├── ErrorIcon.tsx
│ │ │ ├── ExpressionIcon.tsx
│ │ │ ├── FillPlusCricleIcon.tsx
│ │ │ ├── FilterIcon.tsx
│ │ │ ├── FolderIcon.tsx
│ │ │ ├── GlobeIcon.tsx
│ │ │ ├── HomeIcon.tsx
│ │ │ ├── HyperLinkIcon.tsx
│ │ │ ├── Icon.md
│ │ │ ├── Icon.module.scss
│ │ │ ├── Icon.spec.ts
│ │ │ ├── Icon.tsx
│ │ │ ├── IconNative.tsx
│ │ │ ├── ImageFileIcon.tsx
│ │ │ ├── Inspect.tsx
│ │ │ ├── LightToDark.tsx
│ │ │ ├── LinkIcon.tsx
│ │ │ ├── ListIcon.tsx
│ │ │ ├── LooseListIcon.tsx
│ │ │ ├── MoonIcon.tsx
│ │ │ ├── MoreOptionsIcon.tsx
│ │ │ ├── NoSortIcon.tsx
│ │ │ ├── PDFIcon.tsx
│ │ │ ├── PenIcon.tsx
│ │ │ ├── PhoneIcon.tsx
│ │ │ ├── PhotoIcon.tsx
│ │ │ ├── PlusIcon.tsx
│ │ │ ├── SearchIcon.tsx
│ │ │ ├── ShareIcon.tsx
│ │ │ ├── SortAscendingIcon.tsx
│ │ │ ├── SortDescendingIcon.tsx
│ │ │ ├── StarsIcon.tsx
│ │ │ ├── SunIcon.tsx
│ │ │ ├── svg
│ │ │ │ ├── admonition_danger.svg
│ │ │ │ ├── admonition_info.svg
│ │ │ │ ├── admonition_note.svg
│ │ │ │ ├── admonition_tip.svg
│ │ │ │ ├── admonition_warning.svg
│ │ │ │ ├── api.svg
│ │ │ │ ├── arrow-dropdown.svg
│ │ │ │ ├── arrow-left.svg
│ │ │ │ ├── arrow-right.svg
│ │ │ │ ├── arrow-up.svg
│ │ │ │ ├── attach.svg
│ │ │ │ ├── binding.svg
│ │ │ │ ├── box.svg
│ │ │ │ ├── bulb.svg
│ │ │ │ ├── code-file.svg
│ │ │ │ ├── code-sandbox.svg
│ │ │ │ ├── dark_to_light.svg
│ │ │ │ ├── database.svg
│ │ │ │ ├── doc.svg
│ │ │ │ ├── empty-folder.svg
│ │ │ │ ├── expression.svg
│ │ │ │ ├── eye-closed.svg
│ │ │ │ ├── eye-dark.svg
│ │ │ │ ├── eye.svg
│ │ │ │ ├── file-text.svg
│ │ │ │ ├── filter.svg
│ │ │ │ ├── folder.svg
│ │ │ │ ├── img.svg
│ │ │ │ ├── inspect.svg
│ │ │ │ ├── light_to_dark.svg
│ │ │ │ ├── moon.svg
│ │ │ │ ├── pdf.svg
│ │ │ │ ├── photo.svg
│ │ │ │ ├── share.svg
│ │ │ │ ├── stars.svg
│ │ │ │ ├── sun.svg
│ │ │ │ ├── trending-down.svg
│ │ │ │ ├── trending-level.svg
│ │ │ │ ├── trending-up.svg
│ │ │ │ ├── txt.svg
│ │ │ │ ├── unknown-file.svg
│ │ │ │ ├── unlink.svg
│ │ │ │ └── xls.svg
│ │ │ ├── TableDeleteColumnIcon.tsx
│ │ │ ├── TableDeleteRowIcon.tsx
│ │ │ ├── TableInsertColumnIcon.tsx
│ │ │ ├── TableInsertRowIcon.tsx
│ │ │ ├── TrashIcon.tsx
│ │ │ ├── TrendingDownIcon.tsx
│ │ │ ├── TrendingLevelIcon.tsx
│ │ │ ├── TrendingUpIcon.tsx
│ │ │ ├── TxtIcon.tsx
│ │ │ ├── UnknownFileIcon.tsx
│ │ │ ├── UnlinkIcon.tsx
│ │ │ ├── UserIcon.tsx
│ │ │ ├── WarningIcon.tsx
│ │ │ └── XlsIcon.tsx
│ │ ├── IconProvider.tsx
│ │ ├── IconRegistryContext.tsx
│ │ ├── IFrame
│ │ │ ├── IFrame.md
│ │ │ ├── IFrame.module.scss
│ │ │ ├── IFrame.spec.ts
│ │ │ ├── IFrame.tsx
│ │ │ └── IFrameNative.tsx
│ │ ├── Image
│ │ │ ├── Image.md
│ │ │ ├── Image.module.scss
│ │ │ ├── Image.spec.ts
│ │ │ ├── Image.tsx
│ │ │ └── ImageNative.tsx
│ │ ├── Input
│ │ │ ├── index.ts
│ │ │ ├── InputAdornment.module.scss
│ │ │ ├── InputAdornment.tsx
│ │ │ ├── InputDivider.module.scss
│ │ │ ├── InputDivider.tsx
│ │ │ ├── InputLabel.module.scss
│ │ │ ├── InputLabel.tsx
│ │ │ ├── PartialInput.module.scss
│ │ │ └── PartialInput.tsx
│ │ ├── InspectButton
│ │ │ ├── InspectButton.module.scss
│ │ │ └── InspectButton.tsx
│ │ ├── Items
│ │ │ ├── Items.md
│ │ │ ├── Items.spec.ts
│ │ │ ├── Items.tsx
│ │ │ └── ItemsNative.tsx
│ │ ├── Link
│ │ │ ├── Link.md
│ │ │ ├── Link.module.scss
│ │ │ ├── Link.spec.ts
│ │ │ ├── Link.tsx
│ │ │ └── LinkNative.tsx
│ │ ├── List
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── List.md
│ │ │ ├── List.module.scss
│ │ │ ├── List.spec.ts
│ │ │ ├── List.tsx
│ │ │ └── ListNative.tsx
│ │ ├── Logo
│ │ │ ├── doc-resources
│ │ │ │ └── xmlui-logo.svg
│ │ │ ├── Logo.md
│ │ │ ├── Logo.tsx
│ │ │ └── LogoNative.tsx
│ │ ├── Markdown
│ │ │ ├── CodeText.module.scss
│ │ │ ├── CodeText.tsx
│ │ │ ├── Markdown.md
│ │ │ ├── Markdown.module.scss
│ │ │ ├── Markdown.spec.ts
│ │ │ ├── Markdown.tsx
│ │ │ ├── MarkdownNative.tsx
│ │ │ ├── parse-binding-expr.ts
│ │ │ └── utils.ts
│ │ ├── metadata-helpers.ts
│ │ ├── ModalDialog
│ │ │ ├── ConfirmationModalContextProvider.tsx
│ │ │ ├── Dialog.module.scss
│ │ │ ├── Dialog.tsx
│ │ │ ├── ModalDialog.md
│ │ │ ├── ModalDialog.module.scss
│ │ │ ├── ModalDialog.spec.ts
│ │ │ ├── ModalDialog.tsx
│ │ │ ├── ModalDialogNative.tsx
│ │ │ └── ModalVisibilityContext.tsx
│ │ ├── NavGroup
│ │ │ ├── NavGroup.md
│ │ │ ├── NavGroup.module.scss
│ │ │ ├── NavGroup.spec.ts
│ │ │ ├── NavGroup.tsx
│ │ │ ├── NavGroupContext.ts
│ │ │ └── NavGroupNative.tsx
│ │ ├── NavLink
│ │ │ ├── NavLink.md
│ │ │ ├── NavLink.module.scss
│ │ │ ├── NavLink.spec.ts
│ │ │ ├── NavLink.tsx
│ │ │ └── NavLinkNative.tsx
│ │ ├── NavPanel
│ │ │ ├── NavPanel.md
│ │ │ ├── NavPanel.module.scss
│ │ │ ├── NavPanel.spec.ts
│ │ │ ├── NavPanel.tsx
│ │ │ └── NavPanelNative.tsx
│ │ ├── NestedApp
│ │ │ ├── AppWithCodeView.module.scss
│ │ │ ├── AppWithCodeView.tsx
│ │ │ ├── AppWithCodeViewNative.tsx
│ │ │ ├── defaultProps.tsx
│ │ │ ├── logo.svg
│ │ │ ├── NestedApp.module.scss
│ │ │ ├── NestedApp.tsx
│ │ │ ├── NestedAppNative.tsx
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.tsx
│ │ │ └── utils.ts
│ │ ├── NoResult
│ │ │ ├── NoResult.md
│ │ │ ├── NoResult.module.scss
│ │ │ ├── NoResult.spec.ts
│ │ │ ├── NoResult.tsx
│ │ │ └── NoResultNative.tsx
│ │ ├── NumberBox
│ │ │ ├── numberbox-abstractions.ts
│ │ │ ├── NumberBox.md
│ │ │ ├── NumberBox.module.scss
│ │ │ ├── NumberBox.spec.ts
│ │ │ ├── NumberBox.tsx
│ │ │ └── NumberBoxNative.tsx
│ │ ├── Option
│ │ │ ├── Option.md
│ │ │ ├── Option.spec.ts
│ │ │ ├── Option.tsx
│ │ │ ├── OptionNative.tsx
│ │ │ └── OptionTypeProvider.tsx
│ │ ├── PageMetaTitle
│ │ │ ├── PageMetaTilteNative.tsx
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── PageMetaTitle.spec.ts
│ │ │ └── PageMetaTitle.tsx
│ │ ├── Pages
│ │ │ ├── Page.md
│ │ │ ├── Pages.md
│ │ │ ├── Pages.module.scss
│ │ │ ├── Pages.tsx
│ │ │ └── PagesNative.tsx
│ │ ├── Pagination
│ │ │ ├── Pagination.md
│ │ │ ├── Pagination.module.scss
│ │ │ ├── Pagination.spec.ts
│ │ │ ├── Pagination.tsx
│ │ │ └── PaginationNative.tsx
│ │ ├── PositionedContainer
│ │ │ ├── PositionedContainer.module.scss
│ │ │ ├── PositionedContainer.tsx
│ │ │ └── PositionedContainerNative.tsx
│ │ ├── ProfileMenu
│ │ │ ├── ProfileMenu.module.scss
│ │ │ └── ProfileMenu.tsx
│ │ ├── ProgressBar
│ │ │ ├── ProgressBar.md
│ │ │ ├── ProgressBar.module.scss
│ │ │ ├── ProgressBar.spec.ts
│ │ │ ├── ProgressBar.tsx
│ │ │ └── ProgressBarNative.tsx
│ │ ├── Queue
│ │ │ ├── Queue.md
│ │ │ ├── Queue.spec.ts
│ │ │ ├── Queue.tsx
│ │ │ ├── queueActions.ts
│ │ │ └── QueueNative.tsx
│ │ ├── RadioGroup
│ │ │ ├── RadioGroup.md
│ │ │ ├── RadioGroup.module.scss
│ │ │ ├── RadioGroup.spec.ts
│ │ │ ├── RadioGroup.tsx
│ │ │ ├── RadioGroupNative.tsx
│ │ │ ├── RadioItem.tsx
│ │ │ └── RadioItemNative.tsx
│ │ ├── RealTimeAdapter
│ │ │ ├── RealTimeAdapter.tsx
│ │ │ └── RealTimeAdapterNative.tsx
│ │ ├── Redirect
│ │ │ ├── Redirect.md
│ │ │ ├── Redirect.spec.ts
│ │ │ └── Redirect.tsx
│ │ ├── ResponsiveBar
│ │ │ ├── README.md
│ │ │ ├── ResponsiveBar.md
│ │ │ ├── ResponsiveBar.module.scss
│ │ │ ├── ResponsiveBar.spec.ts
│ │ │ ├── ResponsiveBar.tsx
│ │ │ └── ResponsiveBarNative.tsx
│ │ ├── Select
│ │ │ ├── HiddenOption.tsx
│ │ │ ├── OptionContext.ts
│ │ │ ├── Select.md
│ │ │ ├── Select.module.scss
│ │ │ ├── Select.spec.ts
│ │ │ ├── Select.tsx
│ │ │ ├── SelectContext.tsx
│ │ │ └── SelectNative.tsx
│ │ ├── SelectionStore
│ │ │ ├── SelectionStore.md
│ │ │ ├── SelectionStore.tsx
│ │ │ └── SelectionStoreNative.tsx
│ │ ├── Slider
│ │ │ ├── Slider.md
│ │ │ ├── Slider.module.scss
│ │ │ ├── Slider.spec.ts
│ │ │ ├── Slider.tsx
│ │ │ └── SliderNative.tsx
│ │ ├── Slot
│ │ │ ├── Slot.md
│ │ │ ├── Slot.spec.ts
│ │ │ └── Slot.ts
│ │ ├── SlotItem.tsx
│ │ ├── SpaceFiller
│ │ │ ├── SpaceFiller.md
│ │ │ ├── SpaceFiller.module.scss
│ │ │ ├── SpaceFiller.spec.ts
│ │ │ ├── SpaceFiller.tsx
│ │ │ └── SpaceFillerNative.tsx
│ │ ├── Spinner
│ │ │ ├── Spinner.md
│ │ │ ├── Spinner.module.scss
│ │ │ ├── Spinner.spec.ts
│ │ │ ├── Spinner.tsx
│ │ │ └── SpinnerNative.tsx
│ │ ├── Splitter
│ │ │ ├── HSplitter.md
│ │ │ ├── HSplitter.spec.ts
│ │ │ ├── Splitter.md
│ │ │ ├── Splitter.module.scss
│ │ │ ├── Splitter.spec.ts
│ │ │ ├── Splitter.tsx
│ │ │ ├── SplitterNative.tsx
│ │ │ ├── utils.ts
│ │ │ ├── VSplitter.md
│ │ │ └── VSplitter.spec.ts
│ │ ├── Stack
│ │ │ ├── CHStack.md
│ │ │ ├── CHStack.spec.ts
│ │ │ ├── CVStack.md
│ │ │ ├── CVStack.spec.ts
│ │ │ ├── HStack.md
│ │ │ ├── HStack.spec.ts
│ │ │ ├── Stack.md
│ │ │ ├── Stack.module.scss
│ │ │ ├── Stack.spec.ts
│ │ │ ├── Stack.tsx
│ │ │ ├── StackNative.tsx
│ │ │ ├── VStack.md
│ │ │ └── VStack.spec.ts
│ │ ├── StickyBox
│ │ │ ├── StickyBox.md
│ │ │ ├── StickyBox.module.scss
│ │ │ ├── StickyBox.tsx
│ │ │ └── StickyBoxNative.tsx
│ │ ├── Switch
│ │ │ ├── Switch.md
│ │ │ ├── Switch.spec.ts
│ │ │ └── Switch.tsx
│ │ ├── Table
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── react-table-config.d.ts
│ │ │ ├── Table.md
│ │ │ ├── Table.module.scss
│ │ │ ├── Table.spec.ts
│ │ │ ├── Table.tsx
│ │ │ ├── TableNative.tsx
│ │ │ └── useRowSelection.tsx
│ │ ├── TableOfContents
│ │ │ ├── TableOfContents.module.scss
│ │ │ ├── TableOfContents.spec.ts
│ │ │ ├── TableOfContents.tsx
│ │ │ └── TableOfContentsNative.tsx
│ │ ├── Tabs
│ │ │ ├── TabContext.tsx
│ │ │ ├── TabItem.md
│ │ │ ├── TabItem.tsx
│ │ │ ├── TabItemNative.tsx
│ │ │ ├── Tabs.md
│ │ │ ├── Tabs.module.scss
│ │ │ ├── Tabs.spec.ts
│ │ │ ├── Tabs.tsx
│ │ │ └── TabsNative.tsx
│ │ ├── Text
│ │ │ ├── Text.md
│ │ │ ├── Text.module.scss
│ │ │ ├── Text.spec.ts
│ │ │ ├── Text.tsx
│ │ │ └── TextNative.tsx
│ │ ├── TextArea
│ │ │ ├── TextArea.md
│ │ │ ├── TextArea.module.scss
│ │ │ ├── TextArea.spec.ts
│ │ │ ├── TextArea.tsx
│ │ │ ├── TextAreaNative.tsx
│ │ │ ├── TextAreaResizable.tsx
│ │ │ └── useComposedRef.ts
│ │ ├── TextBox
│ │ │ ├── TextBox.md
│ │ │ ├── TextBox.module.scss
│ │ │ ├── TextBox.spec.ts
│ │ │ ├── TextBox.tsx
│ │ │ └── TextBoxNative.tsx
│ │ ├── Theme
│ │ │ ├── NotificationToast.tsx
│ │ │ ├── Theme.md
│ │ │ ├── Theme.module.scss
│ │ │ ├── Theme.spec.ts
│ │ │ ├── Theme.tsx
│ │ │ └── ThemeNative.tsx
│ │ ├── TimeInput
│ │ │ ├── TimeInput.md
│ │ │ ├── TimeInput.module.scss
│ │ │ ├── TimeInput.spec.ts
│ │ │ ├── TimeInput.tsx
│ │ │ ├── TimeInputNative.tsx
│ │ │ └── utils.ts
│ │ ├── Timer
│ │ │ ├── Timer.md
│ │ │ ├── Timer.spec.ts
│ │ │ ├── Timer.tsx
│ │ │ └── TimerNative.tsx
│ │ ├── Toggle
│ │ │ ├── Toggle.module.scss
│ │ │ └── Toggle.tsx
│ │ ├── ToneChangerButton
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneChangerButton.spec.ts
│ │ │ └── ToneChangerButton.tsx
│ │ ├── ToneSwitch
│ │ │ ├── ToneSwitch.md
│ │ │ ├── ToneSwitch.module.scss
│ │ │ ├── ToneSwitch.spec.ts
│ │ │ ├── ToneSwitch.tsx
│ │ │ └── ToneSwitchNative.tsx
│ │ ├── Tooltip
│ │ │ ├── Tooltip.md
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.spec.ts
│ │ │ ├── Tooltip.tsx
│ │ │ └── TooltipNative.tsx
│ │ ├── Tree
│ │ │ ├── testData.ts
│ │ │ ├── Tree-dynamic.spec.ts
│ │ │ ├── Tree-icons.spec.ts
│ │ │ ├── Tree.md
│ │ │ ├── Tree.spec.ts
│ │ │ ├── TreeComponent.module.scss
│ │ │ ├── TreeComponent.tsx
│ │ │ └── TreeNative.tsx
│ │ ├── TreeDisplay
│ │ │ ├── TreeDisplay.md
│ │ │ ├── TreeDisplay.module.scss
│ │ │ ├── TreeDisplay.tsx
│ │ │ └── TreeDisplayNative.tsx
│ │ ├── ValidationSummary
│ │ │ ├── ValidationSummary.module.scss
│ │ │ └── ValidationSummary.tsx
│ │ └── VisuallyHidden.tsx
│ ├── components-core
│ │ ├── abstractions
│ │ │ ├── ComponentRenderer.ts
│ │ │ ├── LoaderRenderer.ts
│ │ │ ├── standalone.ts
│ │ │ └── treeAbstractions.ts
│ │ ├── action
│ │ │ ├── actions.ts
│ │ │ ├── APICall.tsx
│ │ │ ├── FileDownloadAction.tsx
│ │ │ ├── FileUploadAction.tsx
│ │ │ ├── NavigateAction.tsx
│ │ │ └── TimedAction.tsx
│ │ ├── ApiBoundComponent.tsx
│ │ ├── appContext
│ │ │ ├── date-functions.ts
│ │ │ ├── math-function.ts
│ │ │ └── misc-utils.ts
│ │ ├── AppContext.tsx
│ │ ├── behaviors
│ │ │ ├── Behavior.tsx
│ │ │ └── CoreBehaviors.tsx
│ │ ├── component-hooks.ts
│ │ ├── ComponentDecorator.tsx
│ │ ├── ComponentViewer.tsx
│ │ ├── CompoundComponent.tsx
│ │ ├── constants.ts
│ │ ├── DebugViewProvider.tsx
│ │ ├── descriptorHelper.ts
│ │ ├── devtools
│ │ │ ├── InspectorDialog.module.scss
│ │ │ ├── InspectorDialog.tsx
│ │ │ └── InspectorDialogVisibilityContext.tsx
│ │ ├── EngineError.ts
│ │ ├── event-handlers.ts
│ │ ├── InspectorButton.module.scss
│ │ ├── InspectorContext.tsx
│ │ ├── interception
│ │ │ ├── abstractions.ts
│ │ │ ├── ApiInterceptor.ts
│ │ │ ├── ApiInterceptorProvider.tsx
│ │ │ ├── apiInterceptorWorker.ts
│ │ │ ├── Backend.ts
│ │ │ ├── Errors.ts
│ │ │ ├── IndexedDb.ts
│ │ │ ├── initMock.ts
│ │ │ ├── InMemoryDb.ts
│ │ │ ├── ReadonlyCollection.ts
│ │ │ └── useApiInterceptorContext.tsx
│ │ ├── loader
│ │ │ ├── ApiLoader.tsx
│ │ │ ├── DataLoader.tsx
│ │ │ ├── ExternalDataLoader.tsx
│ │ │ ├── Loader.tsx
│ │ │ ├── MockLoaderRenderer.tsx
│ │ │ └── PageableLoader.tsx
│ │ ├── LoaderComponent.tsx
│ │ ├── markup-check.ts
│ │ ├── parts.ts
│ │ ├── renderers.ts
│ │ ├── rendering
│ │ │ ├── AppContent.tsx
│ │ │ ├── AppRoot.tsx
│ │ │ ├── AppWrapper.tsx
│ │ │ ├── buildProxy.ts
│ │ │ ├── collectFnVarDeps.ts
│ │ │ ├── ComponentAdapter.tsx
│ │ │ ├── ComponentWrapper.tsx
│ │ │ ├── Container.tsx
│ │ │ ├── containers.ts
│ │ │ ├── ContainerWrapper.tsx
│ │ │ ├── ErrorBoundary.module.scss
│ │ │ ├── ErrorBoundary.tsx
│ │ │ ├── InvalidComponent.module.scss
│ │ │ ├── InvalidComponent.tsx
│ │ │ ├── nodeUtils.ts
│ │ │ ├── reducer.ts
│ │ │ ├── renderChild.tsx
│ │ │ ├── StandaloneComponent.tsx
│ │ │ ├── StateContainer.tsx
│ │ │ ├── UnknownComponent.module.scss
│ │ │ ├── UnknownComponent.tsx
│ │ │ └── valueExtractor.ts
│ │ ├── reportEngineError.ts
│ │ ├── RestApiProxy.ts
│ │ ├── script-runner
│ │ │ ├── asyncProxy.ts
│ │ │ ├── AttributeValueParser.ts
│ │ │ ├── bannedFunctions.ts
│ │ │ ├── BindingTreeEvaluationContext.ts
│ │ │ ├── eval-tree-async.ts
│ │ │ ├── eval-tree-common.ts
│ │ │ ├── eval-tree-sync.ts
│ │ │ ├── ParameterParser.ts
│ │ │ ├── process-statement-async.ts
│ │ │ ├── process-statement-common.ts
│ │ │ ├── process-statement-sync.ts
│ │ │ ├── ScriptingSourceTree.ts
│ │ │ ├── simplify-expression.ts
│ │ │ ├── statement-queue.ts
│ │ │ └── visitors.ts
│ │ ├── StandaloneApp.tsx
│ │ ├── StandaloneExtensionManager.ts
│ │ ├── TableOfContentsContext.tsx
│ │ ├── theming
│ │ │ ├── _themes.scss
│ │ │ ├── component-layout-resolver.ts
│ │ │ ├── extendThemeUtils.ts
│ │ │ ├── hvar.ts
│ │ │ ├── layout-resolver.ts
│ │ │ ├── parse-layout-props.ts
│ │ │ ├── StyleContext.tsx
│ │ │ ├── StyleRegistry.ts
│ │ │ ├── ThemeContext.tsx
│ │ │ ├── ThemeProvider.tsx
│ │ │ ├── themes
│ │ │ │ ├── base-utils.ts
│ │ │ │ ├── palette.ts
│ │ │ │ ├── root.ts
│ │ │ │ ├── solid.ts
│ │ │ │ ├── theme-colors.ts
│ │ │ │ └── xmlui.ts
│ │ │ ├── themeVars.module.scss
│ │ │ ├── themeVars.ts
│ │ │ ├── transformThemeVars.ts
│ │ │ └── utils.ts
│ │ ├── utils
│ │ │ ├── actionUtils.ts
│ │ │ ├── audio-utils.ts
│ │ │ ├── base64-utils.ts
│ │ │ ├── compound-utils.ts
│ │ │ ├── css-utils.ts
│ │ │ ├── DataLoaderQueryKeyGenerator.ts
│ │ │ ├── date-utils.ts
│ │ │ ├── extractParam.ts
│ │ │ ├── hooks.tsx
│ │ │ ├── LruCache.ts
│ │ │ ├── mergeProps.ts
│ │ │ ├── misc.ts
│ │ │ ├── request-params.ts
│ │ │ ├── statementUtils.ts
│ │ │ └── treeUtils.ts
│ │ └── xmlui-parser.ts
│ ├── index-standalone.ts
│ ├── index.scss
│ ├── index.ts
│ ├── language-server
│ │ ├── server-common.ts
│ │ ├── server-web-worker.ts
│ │ ├── server.ts
│ │ ├── services
│ │ │ ├── common
│ │ │ │ ├── docs-generation.ts
│ │ │ │ ├── lsp-utils.ts
│ │ │ │ ├── metadata-utils.ts
│ │ │ │ └── syntax-node-utilities.ts
│ │ │ ├── completion.ts
│ │ │ ├── diagnostic.ts
│ │ │ ├── format.ts
│ │ │ └── hover.ts
│ │ └── xmlui-metadata-generated.js
│ ├── logging
│ │ ├── LoggerContext.tsx
│ │ ├── LoggerInitializer.tsx
│ │ ├── LoggerService.ts
│ │ └── xmlui.ts
│ ├── logo.svg
│ ├── parsers
│ │ ├── common
│ │ │ ├── GenericToken.ts
│ │ │ ├── InputStream.ts
│ │ │ └── utils.ts
│ │ ├── scripting
│ │ │ ├── code-behind-collect.ts
│ │ │ ├── Lexer.ts
│ │ │ ├── modules.ts
│ │ │ ├── Parser.ts
│ │ │ ├── ParserError.ts
│ │ │ ├── ScriptingNodeTypes.ts
│ │ │ ├── TokenTrait.ts
│ │ │ ├── TokenType.ts
│ │ │ └── tree-visitor.ts
│ │ ├── style-parser
│ │ │ ├── errors.ts
│ │ │ ├── source-tree.ts
│ │ │ ├── StyleInputStream.ts
│ │ │ ├── StyleLexer.ts
│ │ │ ├── StyleParser.ts
│ │ │ └── tokens.ts
│ │ └── xmlui-parser
│ │ ├── CharacterCodes.ts
│ │ ├── diagnostics.ts
│ │ ├── fileExtensions.ts
│ │ ├── index.ts
│ │ ├── lint.ts
│ │ ├── parser.ts
│ │ ├── ParserError.ts
│ │ ├── scanner.ts
│ │ ├── syntax-kind.ts
│ │ ├── syntax-node.ts
│ │ ├── transform.ts
│ │ ├── utils.ts
│ │ ├── xmlui-serializer.ts
│ │ └── xmlui-tree.ts
│ ├── react-app-env.d.ts
│ ├── syntax
│ │ ├── monaco
│ │ │ ├── grammar.monacoLanguage.ts
│ │ │ ├── index.ts
│ │ │ ├── xmlui-dark.ts
│ │ │ ├── xmlui-light.ts
│ │ │ └── xmluiscript.monacoLanguage.ts
│ │ └── textMate
│ │ ├── index.ts
│ │ ├── xmlui-dark.json
│ │ ├── xmlui-light.json
│ │ ├── xmlui.json
│ │ └── xmlui.tmLanguage.json
│ ├── testing
│ │ ├── assertions.ts
│ │ ├── component-test-helpers.ts
│ │ ├── ComponentDrivers.ts
│ │ ├── drivers
│ │ │ ├── DateInputDriver.ts
│ │ │ ├── index.ts
│ │ │ ├── ModalDialogDriver.ts
│ │ │ ├── NumberBoxDriver.ts
│ │ │ ├── TextBoxDriver.ts
│ │ │ ├── TimeInputDriver.ts
│ │ │ ├── TimerDriver.ts
│ │ │ └── TreeDriver.ts
│ │ ├── fixtures.ts
│ │ ├── index.ts
│ │ ├── infrastructure
│ │ │ ├── index.html
│ │ │ ├── main.tsx
│ │ │ ├── public
│ │ │ │ ├── mockServiceWorker.js
│ │ │ │ ├── resources
│ │ │ │ │ ├── bell.svg
│ │ │ │ │ ├── box.svg
│ │ │ │ │ ├── doc.svg
│ │ │ │ │ ├── eye.svg
│ │ │ │ │ ├── flower-640x480.jpg
│ │ │ │ │ ├── sun.svg
│ │ │ │ │ ├── test-image-100x100.jpg
│ │ │ │ │ └── txt.svg
│ │ │ │ └── serve.json
│ │ │ └── TestBed.tsx
│ │ └── themed-app-test-helpers.ts
│ └── vite-env.d.ts
├── tests
│ ├── components
│ │ ├── CodeBlock
│ │ │ └── hightlight-code.test.ts
│ │ ├── playground-pattern.test.ts
│ │ └── Tree
│ │ └── Tree-states.test.ts
│ ├── components-core
│ │ ├── abstractions
│ │ │ └── treeAbstractions.test.ts
│ │ ├── container
│ │ │ └── buildProxy.test.ts
│ │ ├── interception
│ │ │ ├── orderBy.test.ts
│ │ │ ├── ReadOnlyCollection.test.ts
│ │ │ └── request-param-converter.test.ts
│ │ ├── scripts-runner
│ │ │ ├── AttributeValueParser.test.ts
│ │ │ ├── eval-tree-arrow-async.test.ts
│ │ │ ├── eval-tree-arrow.test.ts
│ │ │ ├── eval-tree-func-decl-async.test.ts
│ │ │ ├── eval-tree-func-decl.test.ts
│ │ │ ├── eval-tree-pre-post.test.ts
│ │ │ ├── eval-tree-regression.test.ts
│ │ │ ├── eval-tree.test.ts
│ │ │ ├── function-proxy.test.ts
│ │ │ ├── parser-regression.test.ts
│ │ │ ├── process-event.test.ts
│ │ │ ├── process-function.test.ts
│ │ │ ├── process-implicit-context.test.ts
│ │ │ ├── process-statement-asgn.test.ts
│ │ │ ├── process-statement-destruct.test.ts
│ │ │ ├── process-statement-regs.test.ts
│ │ │ ├── process-statement-sync.test.ts
│ │ │ ├── process-statement.test.ts
│ │ │ ├── process-switch-sync.test.ts
│ │ │ ├── process-switch.test.ts
│ │ │ ├── process-try-sync.test.ts
│ │ │ ├── process-try.test.ts
│ │ │ └── test-helpers.ts
│ │ ├── test-metadata-handler.ts
│ │ ├── theming
│ │ │ ├── border-segments.test.ts
│ │ │ ├── component-layout.resolver.test.ts
│ │ │ ├── layout-property-parser.test.ts
│ │ │ ├── layout-resolver.test.ts
│ │ │ ├── layout-resolver2.test.ts
│ │ │ ├── layout-vp-override.test.ts
│ │ │ └── padding-segments.test.ts
│ │ └── utils
│ │ ├── date-utils.test.ts
│ │ ├── format-human-elapsed-time.test.ts
│ │ └── LruCache.test.ts
│ ├── language-server
│ │ ├── completion.test.ts
│ │ ├── format.test.ts
│ │ ├── hover.test.ts
│ │ └── mockData.ts
│ └── parsers
│ ├── common
│ │ └── input-stream.test.ts
│ ├── markdown
│ │ └── parse-binding-expression.test.ts
│ ├── parameter-parser.test.ts
│ ├── paremeter-parser.test.ts
│ ├── scripting
│ │ ├── eval-tree-arrow.test.ts
│ │ ├── eval-tree-pre-post.test.ts
│ │ ├── eval-tree.test.ts
│ │ ├── function-proxy.test.ts
│ │ ├── lexer-literals.test.ts
│ │ ├── lexer-misc.test.ts
│ │ ├── module-parse.test.ts
│ │ ├── parser-arrow.test.ts
│ │ ├── parser-assignments.test.ts
│ │ ├── parser-binary.test.ts
│ │ ├── parser-destructuring.test.ts
│ │ ├── parser-errors.test.ts
│ │ ├── parser-expressions.test.ts
│ │ ├── parser-function.test.ts
│ │ ├── parser-literals.test.ts
│ │ ├── parser-primary.test.ts
│ │ ├── parser-regex.test.ts
│ │ ├── parser-statements.test.ts
│ │ ├── parser-unary.test.ts
│ │ ├── process-event.test.ts
│ │ ├── process-implicit-context.test.ts
│ │ ├── process-statement-asgn.test.ts
│ │ ├── process-statement-destruct.test.ts
│ │ ├── process-statement-regs.test.ts
│ │ ├── process-statement-sync.test.ts
│ │ ├── process-statement.test.ts
│ │ ├── process-switch-sync.test.ts
│ │ ├── process-switch.test.ts
│ │ ├── process-try-sync.test.ts
│ │ ├── process-try.test.ts
│ │ ├── simplify-expression.test.ts
│ │ ├── statement-hooks.test.ts
│ │ └── test-helpers.ts
│ ├── style-parser
│ │ ├── generateHvarChain.test.ts
│ │ ├── parseHVar.test.ts
│ │ ├── parser.test.ts
│ │ └── tokens.test.ts
│ └── xmlui
│ ├── lint.test.ts
│ ├── parser.test.ts
│ ├── scanner.test.ts
│ ├── transform.attr.test.ts
│ ├── transform.circular.test.ts
│ ├── transform.element.test.ts
│ ├── transform.errors.test.ts
│ ├── transform.escape.test.ts
│ ├── transform.regression.test.ts
│ ├── transform.script.test.ts
│ ├── transform.test.ts
│ └── xmlui.ts
├── tests-e2e
│ ├── api-bound-component-regression.spec.ts
│ ├── api-call-as-extracted-component.spec.ts
│ ├── assign-to-object-or-array-regression.spec.ts
│ ├── binding-regression.spec.ts
│ ├── children-as-template-context-vars.spec.ts
│ ├── compound-component.spec.ts
│ ├── context-vars-regression.spec.ts
│ ├── data-bindings.spec.ts
│ ├── datasource-and-api-usage-in-var.spec.ts
│ ├── datasource-direct-binding.spec.ts
│ ├── datasource-onLoaded-regression.spec.ts
│ ├── modify-array-item-regression.spec.ts
│ ├── namespaces.spec.ts
│ ├── push-to-array-regression.spec.ts
│ ├── screen-breakpoints.spec.ts
│ ├── scripting.spec.ts
│ ├── state-scope-in-pages.spec.ts
│ └── state-var-scopes.spec.ts
├── tsconfig.bin.json
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── vitest.config.ts
```
# Files
--------------------------------------------------------------------------------
/xmlui/src/components/DataSource/DataSource.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { httpMethodNames } from "../abstractions";
2 | import { createMetadata, d } from "../metadata-helpers";
3 |
4 | // NOTE: Original component this is based on is the `Loader` component
5 |
6 | const COMP = "DataSource";
7 |
8 | export const DataSourceMd = createMetadata({
9 | status: "stable",
10 | description:
11 | "`DataSource` fetches and caches data from API endpoints, versus " +
12 | "[`APICall`](/components/APICall) which creates, updates or deletes data.",
13 | props: {
14 | method: {
15 | description: `Set the HTTP method.`,
16 | defaultValue: "get",
17 | availableValues: httpMethodNames,
18 | },
19 | id: {
20 | description:
21 | `Set the ID used by other components to access the retrieved data in the \`value\`` +
22 | "property of a \`DataSource\`, or status info in the \`loaded\` and \`error\` properties." +
23 | "When no `id` is set, the component cannot be used programmatically.",
24 | isRequired: true,
25 | valueType: "string",
26 | },
27 | url: {
28 | description: `Set the URL.`,
29 | isRequired: true,
30 | valueType: "string",
31 | },
32 | body: {
33 | description: `Set the optional request body. The object you pass is serialized as a JSON string.`,
34 | valueType: "any",
35 | },
36 | rawBody: {
37 | description:
38 | `Set the request body with no serialization. Use it to send a payload ` +
39 | `that has already been serialized to a JSON string.`,
40 | valueType: "string",
41 | },
42 | queryParams: {
43 | description: `Append optional key-value pairs to the URL.`,
44 | valueType: "any",
45 | },
46 | headers: {
47 | description: `Set request headers. Pass an object whose keys are header names and values are header values.`,
48 | valueType: "any",
49 | },
50 | pollIntervalInSeconds: {
51 | description:
52 | "Set the interval for periodic data fetching. If the data changes on refresh, " +
53 | "XMLUI will re-render components that refer directly or indirectly to the \`DataSource\`. " +
54 | "If not set or set to zero, the component does not poll for data.",
55 | valueType: "number",
56 | },
57 | inProgressNotificationMessage: {
58 | description:
59 | "Set the message to display when the data fetch is in progress. " +
60 | "If the property value is not set, no progress message is displayed.",
61 | valueType: "string",
62 | },
63 | completedNotificationMessage: {
64 | description:
65 | "Set the message to display when the data fetch completes." +
66 | "If the property value is not set, no completion message is displayed.",
67 | valueType: "string",
68 | },
69 | errorNotificationMessage: {
70 | description:
71 | "Set the message to display when the there is an error. " +
72 | "You can use the `$error` context value in an expression to " +
73 | "refer to the original error message.",
74 | valueType: "string",
75 | },
76 | resultSelector: {
77 | description:
78 | "Set an optional object key to extract a subset of the response data. If this " +
79 | "value is not set, the entire response body is considered the result.",
80 | valueType: "string",
81 | },
82 | transformResult: {
83 | description:
84 | "Set an optional function to perform a final transformation of the " +
85 | "response data. If this value is not set, the result is not transformed.",
86 | },
87 | prevPageSelector: {
88 | description:
89 | `When using \`${COMP}\` with paging, the response may contain information about the ` +
90 | `previous and next page. This property defines the selector that extracts the ` +
91 | `previous page information from the response deserialized to an object.`,
92 | },
93 | nextPageSelector: {
94 | description:
95 | `When using \`${COMP}\` with paging, the response may contain information about ` +
96 | `the previous and next page. This property defines the selector that extracts ` +
97 | `the next page information from the response deserialized to an object.`,
98 | },
99 | structuralSharing: {
100 | description:
101 | "This property allows structural sharing. When turned on, `DataSource` will keep " +
102 | "the original reference if nothing has changed in the data. If a subset has " +
103 | "changed, `DataSource` will keep the unchanged parts and only replace the changed " +
104 | "parts. If you do not need this behavior, set this property to `false`.",
105 | defaultValue: "true",
106 | },
107 | },
108 | events: {
109 | loaded: d(
110 | "The component triggers this event when the fetch operation has been completed " +
111 | "and the data is loaded. The event has two arguments. The first is the data " +
112 | "loaded; the second indicates if the event is a result of a refetch.",
113 | ),
114 | error: d(`This event fires when a request results in an error.`),
115 | },
116 | apis: {
117 | value: {
118 | description: `This property retrieves the data queried from the source after optional transformations.`,
119 | signature: "get value(): any",
120 | },
121 | inProgress: {
122 | description: "This property indicates if the data is being fetched.",
123 | signature: "get inProgress(): boolean",
124 | },
125 | isRefetching: {
126 | description: "This property indicates if the data is being re-fetched.",
127 | signature: "get isRefetching(): boolean",
128 | },
129 | loaded: {
130 | description: "This property indicates if the data has been loaded.",
131 | signature: "get loaded(): boolean",
132 | },
133 | refetch: {
134 | description: "This method requests the re-fetch of the data.",
135 | signature: "refetch(): void",
136 | },
137 | },
138 | });
139 |
```
--------------------------------------------------------------------------------
/xmlui/src/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | import type {
2 | StandaloneAppDescription,
3 | StandaloneJsonConfig,
4 | } from "./components-core/abstractions/standalone";
5 | import type { ApiInterceptorDefinition } from "./components-core/interception/abstractions";
6 | import StandaloneApp, { startApp } from "./components-core/StandaloneApp";
7 | import type {
8 | ComponentDef,
9 | ComponentLike,
10 | ComponentMetadata,
11 | CompoundComponentDef,
12 | PropertyValueDescription,
13 | } from "./abstractions/ComponentDefs";
14 | import { AppRoot } from "./components-core/rendering/AppRoot";
15 | import {
16 | createComponentRenderer,
17 | createUserDefinedComponentRenderer,
18 | } from "./components-core/renderers";
19 | import type { TreeNode } from "./components-core/abstractions/treeAbstractions";
20 | import { Icon } from "./components/Icon/IconNative";
21 | import { ErrorBoundary } from "./components-core/rendering/ErrorBoundary";
22 | import { Stack } from "./components/Stack/StackNative";
23 | import { Button } from "./components/Button/ButtonNative";
24 | import { Splitter } from "./components/Splitter/SplitterNative";
25 | import { useTheme, useThemes } from "./components-core/theming/ThemeContext";
26 | import { toCssVar } from "./parsers/style-parser/StyleParser";
27 | import { getColor } from "./components-core/utils/css-utils";
28 | import { useColors } from "./components-core/utils/hooks";
29 | import type {
30 | ComponentRendererDef,
31 | RegisterComponentApiFn,
32 | RendererContext,
33 | } from "./abstractions/RendererDefs";
34 | import { parseScssVar } from "./components-core/theming/themeVars";
35 | import StandaloneExtensionManager from "./components-core/StandaloneExtensionManager";
36 | import type { ThemeDefinition, ThemeTone } from "./abstractions/ThemingDefs";
37 | import { useDevTools } from "./components-core/InspectorContext";
38 | import { useLogger } from "./logging/LoggerContext";
39 | import { TabItemComponent } from "./components/Tabs/TabItemNative";
40 | import { Tabs } from "./components/Tabs/TabsNative";
41 | import { errReportComponent, xmlUiMarkupToComponent } from "./components-core/xmlui-parser";
42 | import { ApiInterceptorProvider } from "./components-core/interception/ApiInterceptorProvider";
43 | import { Spinner } from "./components/Spinner/SpinnerNative";
44 | import type { XmlUiNode } from "./parsers/xmlui-parser";
45 | import { XmlUiHelper } from "./parsers/xmlui-parser";
46 | import { Text } from "./components/Text/TextNative";
47 | import { TextBox } from "./components/TextBox/TextBoxNative";
48 | import { NestedApp } from "./components/NestedApp/NestedAppNative";
49 | import { builtInThemes } from "./components-core/theming/ThemeProvider";
50 | import { VisuallyHidden } from "./components/VisuallyHidden";
51 | import { LinkNative } from "./components/Link/LinkNative";
52 | import { Breakout } from "./components/Breakout/BreakoutNative";
53 | import { ToneChangerButton } from "./components/ToneChangerButton/ToneChangerButton";
54 | import { Logo } from "./components/Logo/LogoNative";
55 | import { Theme } from "./components/Theme/ThemeNative";
56 | import { useSearchContextContent } from "./components/App/SearchContext";
57 | import { useAppLayoutContext } from "./components/App/AppLayoutContext";
58 | import { StyleProvider } from "./components-core/theming/StyleContext";
59 | import { StyleRegistry } from "./components-core/theming/StyleRegistry";
60 | import { useEvent } from "./components-core/utils/misc";
61 | import {
62 | createMetadata,
63 | d,
64 | dComponent,
65 | dAutoFocus,
66 | dClick,
67 | dCollapse,
68 | dDidChange,
69 | dDidClose,
70 | dDidOpen,
71 | dEnabled,
72 | dFocus,
73 | dEndIcon,
74 | dEndText,
75 | dExpanded,
76 | dExpand,
77 | dGotFocus,
78 | dIndeterminate,
79 | dInitialValue,
80 | dInternal,
81 | dLabel,
82 | dLabelBreak,
83 | dLabelPosition,
84 | dLabelWidth,
85 | dLostFocus,
86 | dMaxLength,
87 | dMulti,
88 | dOrientation,
89 | dPlaceholder,
90 | dReadonly,
91 | dRequired,
92 | dStartIcon,
93 | dStartText,
94 | dSetValueApi,
95 | dTriggerTemplate,
96 | dValidationStatus,
97 | dValue,
98 | dValueApi,
99 | } from "./components/metadata-helpers";
100 | import StandaloneComponent from "./components-core/rendering/StandaloneComponent";
101 |
102 | export type {
103 | ThemeDefinition,
104 | ComponentDef,
105 | ComponentRendererDef,
106 | CompoundComponentDef,
107 | PropertyValueDescription,
108 | ComponentLike,
109 | StandaloneAppDescription,
110 | StandaloneJsonConfig,
111 | ApiInterceptorDefinition,
112 | RegisterComponentApiFn,
113 | //TODO review from here (added for playground)
114 | TreeNode, //TODO REMOVE
115 | RendererContext,
116 | ComponentMetadata,
117 | ThemeTone,
118 | XmlUiNode,
119 | };
120 | export {
121 | StandaloneApp,
122 | StandaloneExtensionManager,
123 | createComponentRenderer,
124 | createUserDefinedComponentRenderer,
125 | createMetadata,
126 | d,
127 | dComponent,
128 | dAutoFocus,
129 | dClick,
130 | dCollapse,
131 | dDidChange,
132 | dDidClose,
133 | dDidOpen,
134 | dEnabled,
135 | dFocus,
136 | dEndIcon,
137 | dEndText,
138 | dExpanded,
139 | dExpand,
140 | dGotFocus,
141 | dIndeterminate,
142 | dInitialValue,
143 | dInternal,
144 | dLabel,
145 | dLabelBreak,
146 | dLabelPosition,
147 | dLabelWidth,
148 | dLostFocus,
149 | dMaxLength,
150 | dMulti,
151 | dOrientation,
152 | dPlaceholder,
153 | dReadonly,
154 | dRequired,
155 | dStartIcon,
156 | dStartText,
157 | dSetValueApi,
158 | dTriggerTemplate,
159 | dValidationStatus,
160 | dValue,
161 | dValueApi,
162 | parseScssVar,
163 | startApp,
164 | useTheme,
165 | AppRoot,
166 | ErrorBoundary,
167 | Icon,
168 | Stack,
169 | Button,
170 | Splitter,
171 | getColor,
172 | TabItemComponent as TabItem,
173 | Tabs,
174 | useColors,
175 | toCssVar,
176 | useDevTools,
177 | useLogger,
178 | errReportComponent,
179 | xmlUiMarkupToComponent,
180 | ApiInterceptorProvider,
181 | Spinner,
182 | useThemes,
183 | builtInThemes,
184 | XmlUiHelper,
185 | Text,
186 | TextBox,
187 | NestedApp,
188 | VisuallyHidden,
189 | LinkNative,
190 | ToneChangerButton,
191 | Logo,
192 | Breakout,
193 | useSearchContextContent,
194 | useAppLayoutContext,
195 | StyleProvider,
196 | StyleRegistry,
197 | useEvent,
198 | StandaloneComponent,
199 | Theme,
200 | };
201 |
```
--------------------------------------------------------------------------------
/docs/content/components/Splitter.md:
--------------------------------------------------------------------------------
```markdown
1 | # Splitter [#splitter]
2 |
3 | `Splitter` component divides a container into two resizable sections. These are are identified by their names: primary and secondary. They have a draggable bar between them.
4 |
5 | Most properties of the component focus on the primary section (e.g. sizing).
6 |
7 | See also: [HSplitter](/components/HSplitter), [VSplitter](/components/VSplitter).
8 |
9 | ## Properties [#properties]
10 |
11 | ### `floating` (default: false) [#floating-default-false]
12 |
13 | Toggles whether the resizer is visible (`false`) or not (`true`) when not hovered or dragged. The default value is `false`, meaning the resizer is visible all the time.
14 |
15 | ```xmlui-pg copy display name="Example: floating"
16 | <App>
17 | <Splitter height="200px" floating="true">
18 | <Stack backgroundColor="lightblue" height="100%" />
19 | <Stack backgroundColor="darksalmon" height="100%" />
20 | </Splitter>
21 | </App>
22 | ```
23 |
24 | ### `initialPrimarySize` (default: "50%") [#initialprimarysize-default-50-]
25 |
26 | This optional number property sets the initial size of the primary section. The unit of the size value is in pixels or percentages.
27 |
28 | ```xmlui-pg copy display name="Example: initialPrimarySize"
29 | <App>
30 | <Splitter height="200px" initialPrimarySize="40%">
31 | <Stack backgroundColor="lightblue" height="100%" />
32 | <Stack backgroundColor="darksalmon" height="100%" />
33 | </Splitter>
34 | </App>
35 | ```
36 |
37 | ### `maxPrimarySize` (default: "100%") [#maxprimarysize-default-100-]
38 |
39 | This property sets the maximum size the primary section can have. The unit of the size value is in pixels or percentages.
40 |
41 | ```xmlui-pg copy display name="Example: maxPrimarySize"
42 | <App>
43 | <Splitter height="200px" maxPrimarySize="80%">
44 | <Stack backgroundColor="lightblue" height="100%" />
45 | <Stack backgroundColor="darksalmon" height="100%" />
46 | </Splitter>
47 | </App>
48 | ```
49 |
50 | ### `minPrimarySize` (default: "0%") [#minprimarysize-default-0-]
51 |
52 | This property sets the minimum size the primary section can have. The unit of the size value is in pixels or percentages.
53 |
54 | ```xmlui-pg copy display name="Example: minPrimarySize"
55 | <App>
56 | <Splitter height="200px" minPrimarySize="40px">
57 | <Stack backgroundColor="lightblue" height="100%" />
58 | <Stack backgroundColor="darksalmon" height="100%" />
59 | </Splitter>
60 | </App>
61 | ```
62 |
63 | ### `orientation` (default: "vertical") [#orientation-default-vertical]
64 |
65 | Sets whether the `Splitter` divides the container horizontally and lays out the section on top of each other (`vertical`), or vertically by placing the sections next to each other (`horizontal`).
66 |
67 | Available values: `horizontal`, `vertical` **(default)**
68 |
69 | ```xmlui-pg copy display name="Example: orientation"
70 | <App>
71 | <Splitter height="200px" orientation="horizontal">
72 | <Stack backgroundColor="lightblue" height="100%" />
73 | <Stack backgroundColor="darksalmon" height="100%" />
74 | </Splitter>
75 | </App>
76 | ```
77 |
78 | ### `splitterTemplate` [#splittertemplate]
79 |
80 | The divider can be customized using XMLUI components via this property.
81 |
82 | ```xmlui-pg copy {2-4} display name="Example: splitterTemplate"
83 | <App>
84 | <Splitter height="200px">
85 | <property name="splitterTemplate">
86 | <ContentSeparator backgroundColor="green" height="4px" />
87 | </property>
88 | <Stack backgroundColor="lightblue" height="100%" />
89 | <Stack backgroundColor="darksalmon" height="100%" />
90 | </Splitter>
91 | </App>
92 | ```
93 |
94 | ### `swapped` (default: false) [#swapped-default-false]
95 |
96 | This optional booelan property indicates whether the `Splitter` sections are layed out as primary and secondary (`false`) or secondary and primary (`true`) from left to right.
97 |
98 | ```xmlui-pg copy display name="Example: swapped"
99 | <App>
100 | <Splitter height="200px" swapped="true">
101 | <Stack backgroundColor="lightblue" height="100%" />
102 | <Stack backgroundColor="darksalmon" height="100%" />
103 | </Splitter>
104 | </App>
105 | ```
106 |
107 | ## Events [#events]
108 |
109 | ### `resize` [#resize]
110 |
111 | This event fires when the component is resized.
112 |
113 | ```xmlui-pg copy {2} display name="Example: resize"
114 | <App height="200px" var.counter="{0}">
115 | <Splitter onResize="counter++">
116 | <Stack backgroundColor="lightblue" height="100%">
117 | <Text value="Resize event called {counter} number of times" />
118 | </Stack>
119 | <Stack backgroundColor="darksalmon" height="100%" />
120 | </Splitter>
121 | </App>
122 | ```
123 |
124 | ## Exposed Methods [#exposed-methods]
125 |
126 | This component does not expose any methods.
127 |
128 | ## Styling [#styling]
129 |
130 | ### Theme Variables [#theme-variables]
131 |
132 | | Variable | Default Value (Light) | Default Value (Dark) |
133 | | --- | --- | --- |
134 | | [backgroundColor](../styles-and-themes/common-units/#color)-resizer-Splitter | $color-surface-100 | $color-surface-100 |
135 | | [backgroundColor](../styles-and-themes/common-units/#color)-Splitter | *none* | *none* |
136 | | [border](../styles-and-themes/common-units/#border)-Splitter | *none* | *none* |
137 | | [borderColor](../styles-and-themes/common-units/#color)-Splitter | *none* | *none* |
138 | | [borderRadius](../styles-and-themes/common-units/#border-rounding)-Splitter | *none* | *none* |
139 | | [borderStyle](../styles-and-themes/common-units/#border-style)-Splitter | *none* | *none* |
140 | | [borderWidth](../styles-and-themes/common-units/#size)-Splitter | *none* | *none* |
141 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-Splitter | *none* | *none* |
142 | | [cursor](../styles-and-themes/common-units/#cursor)-resizer-horizontal-Splitter | ew-resize | ew-resize |
143 | | [cursor](../styles-and-themes/common-units/#cursor)-resizer-vertical-Splitter | ns-resize | ns-resize |
144 | | [thickness](../styles-and-themes/common-units/#size)-resizer-Splitter | 5px | 5px |
145 |
```
--------------------------------------------------------------------------------
/docs/content/components/APICall.md:
--------------------------------------------------------------------------------
```markdown
1 | # APICall [#apicall]
2 |
3 | `APICall` creates, updates or deletes data on the backend, versus [`DataSource`](/components/DataSource) which fetches data. Unlike DataSource, APICall doesn't automatically execute - you must trigger it manually with the `execute()` method, typically from form submissions or button clicks.
4 |
5 | **Key characteristics:**
6 | - **Manual execution**: Call `execute()` method to trigger the API request
7 | - **Form integration**: Commonly used in `<event name="submit">` handlers for forms
8 | - **Parameter passing**: Pass data to the API call via `execute()` parameters
9 | - **Built-in notifications**: Supports automatic progress, success, and error messages
10 |
11 | **Context variables available during execution:**
12 |
13 | - `$error`: Error details (available in `errorNotificationMessage`)
14 | - `$param`: The first parameter passed to `execute()` method
15 | - `$params`: Array of all parameters passed to `execute()` method (access with `$params[0]`, `$params[1]`, etc.)
16 | - `$result`: Response data (available in `completedNotificationMessage`)
17 |
18 | ## Properties [#properties]
19 |
20 | ### `body` [#body]
21 |
22 | This optional property sets the request body. Use to pass an object that will be serialized as a JSON string. If you have an object that is already serialized as a JSON string, use `rawBody` instead.
23 |
24 | ### `completedNotificationMessage` [#completednotificationmessage]
25 |
26 | This property defines the message to display automatically when the operation has been completed. When this property is not defined, the completion does not display any message.
27 |
28 | This property customizes the success message displayed in a toast after the finished API invocation. The `$result` context variable can refer to the response body. For example, you can use the following code snippet to display the first 100 characters in the completed operation's response body:
29 |
30 | ```xmlui copy
31 | <APICall
32 | id="ds"
33 | method="post"
34 | url="/api/shopping-list"
35 | completedNotificationMessage="Result: {JSON.stringify($result).substring(0, 100)}" />
36 | ```
37 |
38 | ### `confirmButtonLabel` [#confirmbuttonlabel]
39 |
40 | This optional string property enables the customization of the submit button in the confirmation dialog that is displayed before the `APICall` is executed.
41 |
42 | ### `confirmMessage` [#confirmmessage]
43 |
44 | This optional string sets the message in the confirmation dialog that is displayed before the `APICall` is executed.
45 |
46 | ### `confirmTitle` [#confirmtitle]
47 |
48 | This optional string sets the title in the confirmation dialog that is displayed before the `APICall` is executed.
49 |
50 | ### `errorNotificationMessage` [#errornotificationmessage]
51 |
52 | This property defines the message to display automatically when the operation results in an error. You can use the `$error` context value in an expression to refer to the original error message.
53 |
54 | This property customizes the message displayed in a toast when the API invocation results in an error. The `$error.statusCode` context variable can refer to the response's status code, while `$error. details` to the response body. For example, you can use the following code snippet to display the status code and the details:
55 |
56 | ```xmlui copy
57 | <APICall
58 | id="ds"
59 | method="post"
60 | url="/api/shopping-list"
61 | errorNotificationMessage="${error.statusCode}, {JSON.stringify($error.details)}" />
62 | ```
63 |
64 | ### `headers` [#headers]
65 |
66 | You can optionally define request header values as key-value pairs, where the key is the ID of the particular header and the value is that header's corresponding value.
67 |
68 | ### `inProgressNotificationMessage` [#inprogressnotificationmessage]
69 |
70 | This property customizes the message that is displayed in a toast while the API operation is in progress. If not defined, no progress message is displayed.
71 |
72 | ### `method` (default: "get") [#method-default-get]
73 |
74 | The method of data manipulation can be done via setting this property.
75 |
76 | Available values: `get` **(default)**, `post`, `put`, `delete`, `patch`, `head`, `options`, `trace`, `connect`
77 |
78 | ### `queryParams` [#queryparams]
79 |
80 | This optional property sets the query parameters for the request. The object you pass here will be serialized to a query string and appended to the request URL. You can specify key and value pairs where the key is the name of a particular query parameter and the value is that parameter's value.
81 |
82 | ### `rawBody` [#rawbody]
83 |
84 | This optional property sets the request body to the value provided here without any conversion. Use the * `body` property if you want the object sent in JSON. When you define `body` and `rawBody`, the latest one prevails.
85 |
86 | ### `url` (required) [#url-required]
87 |
88 | Use this property to set the URL to which data will be sent. If not provided, an empty URL is used.
89 |
90 | ## Events [#events]
91 |
92 | ### `beforeRequest` [#beforerequest]
93 |
94 | This event fires before the request is sent. Returning an explicit boolean`false` value will prevent the request from being sent.
95 |
96 | ### `error` [#error]
97 |
98 | This event fires when a request results in an error.
99 |
100 | ### `success` [#success]
101 |
102 | This event fires when a request results in a success.
103 |
104 | ## Exposed Methods [#exposed-methods]
105 |
106 | ### `execute` [#execute]
107 |
108 | This method triggers the invocation of the API. You can pass an arbitrary number of parameters to the method. In the `APICall` instance, you can access those with the `$param` and `$params` context values.
109 |
110 | **Signature**: `execute(...params: any[])`
111 |
112 | - `params`: An arbitrary number of parameters that can be used in the API call.
113 |
114 | ## Styling [#styling]
115 |
116 | This component does not have any styles.
117 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Charts/RadarChart/RadarChartNative.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import {
2 | RadarChart as RRadarChart,
3 | Radar,
4 | PolarGrid,
5 | PolarAngleAxis,
6 | PolarRadiusAxis,
7 | ResponsiveContainer,
8 | Tooltip,
9 | Legend as RLegend,
10 | } from "recharts";
11 |
12 | import type { ReactNode} from "react";
13 | import { useEffect, useRef, useState, useCallback } from "react";
14 | import { useMemo } from "react";
15 | import ChartProvider, { useChartContextValue } from "../utils/ChartProvider";
16 | import { TooltipContent } from "../Tooltip/TooltipContent";
17 | import { useTheme } from "../../../components-core/theming/ThemeContext";
18 |
19 | export type RadarChartProps = {
20 | data: any[];
21 | nameKey: string;
22 | dataKeys?: string[];
23 | className?: string;
24 | hideGrid?: boolean;
25 | hideAngleAxis?: boolean;
26 | hideRadiusAxis?: boolean;
27 | hideTooltip?: boolean;
28 | children?: ReactNode;
29 | showLegend?: boolean;
30 | filled?: boolean;
31 | strokeWidth?: number;
32 | fillOpacity?: number;
33 | tooltipRenderer?: (tooltipData: any) => ReactNode;
34 | };
35 |
36 | export const defaultProps: Pick<
37 | RadarChartProps,
38 | | "hideGrid"
39 | | "hideAngleAxis"
40 | | "hideRadiusAxis"
41 | | "hideTooltip"
42 | | "showLegend"
43 | | "filled"
44 | | "strokeWidth"
45 | | "fillOpacity"
46 | > = {
47 | hideGrid: false,
48 | hideAngleAxis: false,
49 | hideRadiusAxis: false,
50 | hideTooltip: false,
51 | showLegend: false,
52 | filled: true,
53 | strokeWidth: 2,
54 | fillOpacity: 0.3,
55 | };
56 |
57 | export function RadarChart({
58 | data = [],
59 | nameKey,
60 | dataKeys = [],
61 | hideGrid = defaultProps.hideGrid,
62 | hideAngleAxis = defaultProps.hideAngleAxis,
63 | hideRadiusAxis = defaultProps.hideRadiusAxis,
64 | hideTooltip = defaultProps.hideTooltip,
65 | className,
66 | children,
67 | showLegend = defaultProps.showLegend,
68 | filled = defaultProps.filled,
69 | strokeWidth = defaultProps.strokeWidth,
70 | fillOpacity = defaultProps.fillOpacity,
71 | tooltipRenderer,
72 | }: RadarChartProps) {
73 | // Validate and normalize data
74 | const validData = Array.isArray(data) ? data : [];
75 | const { getThemeVar } = useTheme();
76 |
77 | const colorValues = useMemo(() => {
78 | return [
79 | getThemeVar("color-primary-500"),
80 | getThemeVar("color-primary-300"),
81 | getThemeVar("color-success-500"),
82 | getThemeVar("color-success-300"),
83 | getThemeVar("color-warn-500"),
84 | getThemeVar("color-warn-300"),
85 | getThemeVar("color-danger-500"),
86 | getThemeVar("color-danger-300"),
87 | getThemeVar("color-info-500"),
88 | getThemeVar("color-info-300"),
89 | getThemeVar("color-secondary-500"),
90 | getThemeVar("color-secondary-300"),
91 | ];
92 | }, [getThemeVar]);
93 |
94 | const config = useMemo(() => {
95 | return Object.assign(
96 | {},
97 | ...dataKeys.map((key, index) => {
98 | return {
99 | [key]: {
100 | label: key,
101 | color: colorValues[index % colorValues.length],
102 | },
103 | };
104 | }),
105 | );
106 | }, [colorValues, dataKeys]);
107 |
108 | const chartContextValue = useChartContextValue({ dataKeys, nameKey });
109 |
110 | // Process data and create radar elements based on dataKeys
111 | const radarElements = useMemo(() => {
112 | return dataKeys.map((key, index) => {
113 | const color = colorValues[index % colorValues.length];
114 |
115 | return (
116 | <Radar
117 | key={key}
118 | name={key}
119 | dataKey={key}
120 | stroke={color}
121 | fill={filled ? color : "none"}
122 | fillOpacity={filled ? fillOpacity : 0}
123 | strokeWidth={strokeWidth}
124 | />
125 | );
126 | });
127 | }, [dataKeys, colorValues, filled, fillOpacity, strokeWidth]);
128 |
129 | // Handle responsive behavior
130 | const [containerSize, setContainerSize] = useState({ width: 0, height: 0 });
131 | const containerRef = useRef<HTMLDivElement>(null);
132 |
133 | useEffect(() => {
134 | const updateSize = () => {
135 | if (containerRef.current) {
136 | const { width, height } = containerRef.current.getBoundingClientRect();
137 | setContainerSize({ width, height });
138 | }
139 | };
140 |
141 | updateSize();
142 | window.addEventListener('resize', updateSize);
143 | return () => window.removeEventListener('resize', updateSize);
144 | }, []);
145 |
146 | // Determine if we're in mini mode (very small container)
147 | const isMiniMode = containerSize.height < 150;
148 |
149 | const safeTooltipRenderer = useCallback(
150 | (props: any) => {
151 | if (!tooltipRenderer) return <TooltipContent {...props} />;
152 |
153 | const payloadObject: Record<string, any> = {};
154 |
155 | if (props.payload && props.payload.length > 0 && props.payload[0].payload) {
156 | Object.assign(payloadObject, props.payload[0].payload);
157 | }
158 |
159 | // Extract tooltip data from Recharts props
160 | const tooltipData = {
161 | label: props.label,
162 | payload: payloadObject,
163 | active: props.active,
164 | };
165 |
166 | return tooltipRenderer(tooltipData);
167 | },
168 | [tooltipRenderer],
169 | );
170 |
171 | return (
172 | <ChartProvider value={chartContextValue}>
173 | <div ref={containerRef} className={className}>
174 | <ResponsiveContainer width="100%" height="100%">
175 | <RRadarChart data={validData}>
176 | {!hideGrid && <PolarGrid />}
177 | {!hideAngleAxis && (
178 | <PolarAngleAxis
179 | dataKey={nameKey}
180 | hide={isMiniMode}
181 | />
182 | )}
183 | {!hideRadiusAxis && (
184 | <PolarRadiusAxis
185 | hide={isMiniMode}
186 | />
187 | )}
188 | {!isMiniMode && !hideTooltip && (
189 | <Tooltip content={safeTooltipRenderer} />
190 | )}
191 | {showLegend && !isMiniMode && <RLegend />}
192 | {radarElements}
193 | {children}
194 | </RRadarChart>
195 | </ResponsiveContainer>
196 | </div>
197 | </ChartProvider>
198 | );
199 | }
200 |
```
--------------------------------------------------------------------------------
/xmlui/tests/components-core/interception/request-param-converter.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describe, expect, it } from "vitest";
2 | import { convertRequestParamPart } from "../../../src/components-core/utils/request-params"
3 |
4 | describe("Request parameter converter", () => {
5 | it("string to integer #1", () => {
6 | // --- Arrange
7 | const data = {
8 | a: "123",
9 | b: true,
10 | c: 345
11 | }
12 |
13 | // --- Act
14 | const types = {
15 | a: "integer"
16 | }
17 | const res = convertRequestParamPart(data, types)
18 |
19 | // --- Assert
20 | expect(res).deep.equal({
21 | a: 123,
22 | b: true,
23 | c: 345
24 | })
25 | });
26 |
27 | it("string to integer #2", () => {
28 | // --- Arrange
29 | const data = {
30 | a: "123",
31 | b: "-444",
32 | c: 345
33 | }
34 |
35 | // --- Act
36 | const types = {
37 | a: "integer",
38 | b: "integer"
39 | }
40 | const res = convertRequestParamPart(data, types)
41 |
42 | // --- Assert
43 | expect(res).deep.equal({
44 | a: 123,
45 | b: -444,
46 | c: 345
47 | })
48 | });
49 |
50 | it("string to float #1", () => {
51 | // --- Arrange
52 | const data = {
53 | a: "123.25",
54 | b: true,
55 | c: 345
56 | }
57 |
58 | // --- Act
59 | const types = {
60 | a: "float"
61 | }
62 | const res = convertRequestParamPart(data, types)
63 |
64 | // --- Assert
65 | expect(res).deep.equal({
66 | a: 123.25,
67 | b: true,
68 | c: 345
69 | })
70 | });
71 |
72 | it("string to float #2", () => {
73 | // --- Arrange
74 | const data = {
75 | a: "123.25",
76 | b: "234.5",
77 | c: 345
78 | }
79 |
80 | // --- Act
81 | const types = {
82 | a: "float",
83 | b: "real"
84 | }
85 | const res = convertRequestParamPart(data, types)
86 |
87 | // --- Assert
88 | expect(res).deep.equal({
89 | a: 123.25,
90 | b: 234.5,
91 | c: 345
92 | })
93 | });
94 |
95 | it("string to float #3", () => {
96 | // --- Arrange
97 | const data = {
98 | a: "123.25",
99 | b: "234.5",
100 | c: 345
101 | }
102 |
103 | // --- Act
104 | const types = {
105 | a: "double",
106 | b: "real"
107 | }
108 | const res = convertRequestParamPart(data, types)
109 |
110 | // --- Assert
111 | expect(res).deep.equal({
112 | a: 123.25,
113 | b: 234.5,
114 | c: 345
115 | })
116 | });
117 |
118 | const stringToBoolCases = [
119 | { s: "true", exp: true},
120 | { s: "yes", exp: true},
121 | { s: "on", exp: true},
122 | { s: "false", exp: false},
123 | { s: "no", exp: false},
124 | { s: "off", exp: false},
125 | ]
126 |
127 | stringToBoolCases.forEach((tc, idx) => it(`string to bool #${idx + 1}`, () => {
128 | // --- Arrange
129 | const data = {
130 | a: tc.s,
131 | b: "234.5",
132 | c: 345
133 | }
134 |
135 | // --- Act
136 | const types = {
137 | a: "boolean",
138 | b: "real"
139 | }
140 | const res = convertRequestParamPart(data, types)
141 |
142 | // --- Assert
143 | expect(res).deep.equal({
144 | a: tc.exp,
145 | b: 234.5,
146 | c: 345
147 | })
148 | }))
149 |
150 | it("number to integer #1", () => {
151 | // --- Arrange
152 | const data = {
153 | a: 123.25,
154 | b: true,
155 | c: 345
156 | }
157 |
158 | // --- Act
159 | const types = {
160 | a: "integer"
161 | }
162 | const res = convertRequestParamPart(data, types)
163 |
164 | // --- Assert
165 | expect(res).deep.equal({
166 | a: 123,
167 | b: true,
168 | c: 345
169 | })
170 | });
171 |
172 | it("number to integer #2", () => {
173 | // --- Arrange
174 | const data = {
175 | a: 123.25,
176 | b: 234,
177 | c: 345.5
178 | }
179 |
180 | // --- Act
181 | const types = {
182 | a: "integer",
183 | b: "integer",
184 | c: "integer"
185 | }
186 | const res = convertRequestParamPart(data, types)
187 |
188 | // --- Assert
189 | expect(res).deep.equal({
190 | a: 123,
191 | b: 234,
192 | c: 346
193 | })
194 | });
195 |
196 | it("number to bool", () => {
197 | // --- Arrange
198 | const data = {
199 | a: 123.25,
200 | b: true,
201 | c: 0
202 | }
203 |
204 | // --- Act
205 | const types = {
206 | a: "boolean",
207 | c: "boolean"
208 | }
209 | const res = convertRequestParamPart(data, types)
210 |
211 | // --- Assert
212 | expect(res).deep.equal({
213 | a: true,
214 | b: true,
215 | c: false
216 | })
217 | });
218 |
219 | it("boolean to integer", () => {
220 | // --- Arrange
221 | const data = {
222 | a: true,
223 | b: "123",
224 | c: false
225 | }
226 |
227 | // --- Act
228 | const types = {
229 | a: "integer",
230 | c: "integer"
231 | }
232 | const res = convertRequestParamPart(data, types)
233 |
234 | // --- Assert
235 | expect(res).deep.equal({
236 | a: 1,
237 | b: "123",
238 | c: 0
239 | })
240 | });
241 |
242 | it("boolean to real", () => {
243 | // --- Arrange
244 | const data = {
245 | a: true,
246 | b: true,
247 | c: false
248 | }
249 |
250 | // --- Act
251 | const types = {
252 | a: "real",
253 | b: "double",
254 | c: "float"
255 | }
256 | const res = convertRequestParamPart(data, types)
257 |
258 | // --- Assert
259 | expect(res).deep.equal({
260 | a: 1,
261 | b: 1,
262 | c: 0
263 | })
264 | });
265 |
266 |
267 | });
```
--------------------------------------------------------------------------------
/.github/workflows/release-packages.yml:
--------------------------------------------------------------------------------
```yaml
1 | name: Release Packages
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 | types:
7 | - closed
8 | branches:
9 | - main
10 |
11 | permissions:
12 | contents: write
13 | pull-requests: write
14 | id-token: write
15 |
16 | jobs:
17 | publish_and_github_release:
18 | name: Publish Stable and Create GitHub Release
19 | if: >
20 | github.event_name == 'workflow_dispatch' ||
21 | (github.event_name == 'pull_request' &&
22 | github.event.action == 'closed' &&
23 | github.event.pull_request.merged == true &&
24 | (startsWith(github.event.pull_request.title, 'Version Packages for Stable Release') || contains(github.event.pull_request.labels.*.name, 'changeset-release')))
25 | runs-on: ubuntu-latest-8-core
26 | timeout-minutes: 60
27 | env:
28 | NODE_OPTIONS: "--max-old-space-size=8192"
29 | # needs: [create_version_pr] # This is implied by the trigger conditions
30 | steps:
31 | - name: Checkout Repo
32 | uses: actions/checkout@v4
33 | with:
34 | fetch-depth: 0
35 |
36 | - name: Setup Node.js
37 | uses: actions/setup-node@v4
38 | with:
39 | node-version: 22
40 | cache: "npm"
41 | registry-url: "https://registry.npmjs.org"
42 |
43 | - name: Install dependencies
44 | run: npm ci --prefer-offline
45 |
46 | - name: Cache for Turbo
47 | uses: rharkor/[email protected]
48 |
49 | - name: Store Playwright's Version
50 | run: |
51 | PLAYWRIGHT_VERSION=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | sort | head -n 1)
52 | echo "Playwright's Version: $PLAYWRIGHT_VERSION"
53 | echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV
54 |
55 | - name: Cache Playwright Browsers for Playwright's Version
56 | id: cache-playwright-browsers
57 | uses: actions/cache@v4
58 | with:
59 | path: ~/.cache/ms-playwright
60 | key: playwright-browsers-${{ env.PLAYWRIGHT_VERSION }}
61 |
62 | - name: Install Playwright Browsers
63 | if: steps.cache-playwright-browsers.outputs.cache-hit != 'true'
64 | run: npx playwright install --with-deps
65 |
66 | - name: ensure we can build xmlui and the extensions
67 | run: npm run build-xmlui
68 |
69 | - name: run all tests
70 | run: npm run test
71 |
72 | - name: Create Version PR or Publish to NPM and Create GitHub Releases
73 | id: changesets_publish
74 | uses: changesets/action@v1
75 | with:
76 | publish: npm run changeset:publish
77 | env:
78 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
79 | NODE_AUTH_TOKEN: ${{secrets.PUBLISH_NPM_TOKEN}}
80 |
81 | - name: Output Published Packages Info
82 | if: steps.changesets_publish.outputs.published == 'true'
83 | run: |
84 | echo "Packages published: ${{ steps.changesets_publish.outputs.publishedPackages }}"
85 |
86 | - name: Prepare standalone js file
87 | id: prepare_standalone
88 | if: steps.changesets_publish.outputs.published == 'true' && contains(fromJSON(steps.changesets_publish.outputs.publishedPackages).*.name, 'xmlui')
89 | run: |
90 | XMLUI_VERSION=$(jq -r .version xmlui/package.json)
91 | STANDALONE_FILENAME="xmlui-${XMLUI_VERSION}.js"
92 | cp xmlui/dist/standalone/xmlui-standalone.umd.js $STANDALONE_FILENAME
93 | echo "version=$XMLUI_VERSION" >> $GITHUB_OUTPUT
94 | echo "filename=$STANDALONE_FILENAME" >> $GITHUB_OUTPUT
95 |
96 | echo "prepared xmlui-standalone.umd.js for release with filename: $STANDALONE_FILENAME"
97 |
98 | - name: Upload standalone js file
99 | if: steps.prepare_standalone.outputs.filename != ''
100 | uses: softprops/action-gh-release@v1
101 | with:
102 | files: "${{ steps.prepare_standalone.outputs.filename }}"
103 | tag_name: xmlui@${{ steps.prepare_standalone.outputs.version }}
104 | fail_on_unmatched_files: true
105 |
106 | - name: Get VSCode Extension release info
107 | id: xmlui_vscode_info
108 | if: steps.changesets_publish.outputs.published == 'true'
109 | run: |
110 | XMLUI_VSCODE_VERSION=$(jq -r .version tools/vscode/package.json)
111 |
112 | XMLUI_VSCODE_TAG="xmlui-vscode@${XMLUI_VSCODE_VERSION}"
113 | echo "tag=$XMLUI_VSCODE_TAG" >> $GITHUB_OUTPUT
114 |
115 | XMLUI_VSCODE_TAG_EXISTING=$(git tag --list $XMLUI_VSCODE_TAG)
116 | TAG_EXISTS="false"
117 | if [ ! -z "$XMLUI_VSCODE_TAG_EXISTING" ]; then
118 | TAG_EXISTS="true"
119 | fi
120 | echo "tagExists=$TAG_EXISTS" >> $GITHUB_OUTPUT
121 |
122 | echo "current VSCode extension version: $XMLUI_VSCODE_VERSION"
123 | echo "release tag for VSCode extension: $XMLUI_VSCODE_TAG"
124 | echo "tag already exists: $TAG_EXISTS"
125 |
126 | - name: Build VSCode extension
127 | if: steps.changesets_publish.outputs.published == 'true' && steps.xmlui_vscode_info.outputs.tagExists == 'false'
128 | run: npm run build-vscode-extension
129 |
130 | - name: Upload VSIX to Release
131 | if: steps.changesets_publish.outputs.published == 'true' && steps.xmlui_vscode_info.outputs.tagExists == 'false'
132 | uses: softprops/action-gh-release@v1
133 | with:
134 | files: "tools/vscode/*.vsix"
135 | tag_name: ${{ steps.xmlui_vscode_info.outputs.tag }}
136 | fail_on_unmatched_files: true
137 |
138 | - name: Publish VSCode Extension to Marketplace
139 | if: steps.changesets_publish.outputs.published == 'true' && steps.xmlui_vscode_info.outputs.tagExists == 'false'
140 | run: |
141 | cd tools/vscode
142 | npx vsce publish \
143 | --packagePath *.vsix \
144 | --no-git-tag-version \
145 | --no-update-package-json \
146 | env:
147 | VSCE_PAT: ${{ secrets.VSCE_PAT }}
148 |
```
--------------------------------------------------------------------------------
/docs/public/pages/scoping.md:
--------------------------------------------------------------------------------
```markdown
1 | # Scoping
2 |
3 | ## Variables
4 |
5 | A variable declared in a Main.xmlui component is visible to built-in child components (e.g. `Text`) at any level.
6 |
7 | ```xmlui-pg
8 | ---app display filename="Main.xmlui" /grandparent/ /parent/ /child/
9 | <App var.message="Hello from App">
10 | <Card id="grandparent">
11 | <Text>Message: {message}</Text>
12 | <Card id="parent" var.message2="Hello from Card">
13 | <Text>Message: {message}</Text>
14 | <Text>Message2: {message2}</Text>
15 | <Card id="child">
16 | <Text>Message: {message}</Text>
17 | <Text>Message2: {message2}</Text>
18 | </Card>
19 | </Card>
20 | </Card>
21 | </App>
22 | ```
23 |
24 | A variable declared in a Main.xmlui component is not automatically visible to a user-defined child component.
25 |
26 | ```xmlui-pg
27 | ---app display filename="Main.xmlui"
28 | <App var.message="Hello from App">
29 | <Card>
30 | <Text>Message: {message}</Text>
31 | </Card>
32 | <MyCard />
33 | </App>
34 | ---comp display filename="MyCard"
35 | <Component name="MyCard">
36 | <Card>
37 | <Text>Message: {message}</Text>
38 | </Card>
39 | </Component>
40 | ```
41 |
42 | The variable can be passed into a user-defined component.
43 |
44 | ```xmlui-pg
45 | ---app display filename="Main.xmlui"
46 | <App var.message="Hello from App">
47 | <Card>
48 | <Text>Message: {message}</Text>
49 | </Card>
50 | <MyCard message="{message}" />
51 | </App>
52 | ---comp display filename="MyCard"
53 | <Component name="MyCard">
54 | <Card>
55 | <Text>Message: {$props.message}</Text>
56 | </Card>
57 | </Component>
58 | ```
59 |
60 |
61 | Or the variable can be transposed into the user-defined component by means of the [Slot](/components/Slot) mechanism. The `Slot` content evaluates in the parent's scope, so it can see parent vars and IDs, but renders inside the child’s layout.
62 |
63 | ```xmlui-pg
64 | ---app display filename="Main.xmlui"
65 | <App var.message="Hello from App">
66 | <Card>
67 | <Text>Message: {message}</Text>
68 | </Card>
69 | <MyCard>
70 | <Text>Message: {message}</Text>
71 | </MyCard>
72 | </App>
73 | ---comp display filename="MyCard.xmlui"
74 | <Component name="MyCard">
75 | <Card>
76 | <Slot/>
77 | </Card>
78 | </Component>
79 | ```
80 |
81 | A child component can redeclare a variable.
82 |
83 | ```xmlui-pg
84 | ---app display filename="Main.xmlui" /grandparent/ /parent/ /child/
85 | <App var.message="Hello from App">
86 | <Card id="grandparent">
87 | <Text>Message: {message}</Text>
88 | <Card id="parent" var.message="Hello from parent Card">
89 | <Text>Message: {message}</Text>
90 | <Card id="child" var.message="Hello from child Card">
91 | <Text>Message: {message}</Text>
92 | </Card>
93 | </Card>
94 | </Card>
95 | </App>
96 | ```
97 |
98 |
99 | All these rules apply within a user-defined component defined in a file like `MyComponent.xmlui`.
100 |
101 | ```xmlui-pg
102 | ---app display filename="Main.xmlui"
103 | <App>
104 | <MyComponent />
105 | </App>
106 | ---comp display filename="MyComponent.xmlui"
107 | <Component name="MyComponent" var.message="Hello from MyComponent">
108 | <Card id="grandparent">
109 | <Text>Message: {message}</Text>
110 | <Card id="parent" var.message2="Hello from Card">
111 | <Text>Message: {message}</Text>
112 | <Text>Message2: {message2}</Text>
113 | <Card id="child">
114 | <Text>Message: {message}</Text>
115 | <Text>Message2: {message2}</Text>
116 | </Card>
117 | </Card>
118 | </Card>
119 | </Component>
120 | ```
121 |
122 | A variable declared in a user-defined component can be passed into another user-defined component.
123 |
124 |
125 | ```xmlui-pg
126 | ---app display filename="Main.xmlui"
127 | <App>
128 | <MyComponent />
129 | </App>
130 | ---comp display filename="MyComponent.xmlui"
131 | <Component name="MyComponent" var.message="Hello from MyComponent">
132 | <Card>
133 | <Text>Message: {message}</Text>
134 | </Card>
135 | <MyOtherComponent message="{message}" />
136 | </Component>
137 | ---comp display filename="MyOtherComponent.xmlui"
138 | <Component name="MyOtherComponent">
139 | <Card>
140 | <Text>Passed message: {$props.message}</Text>
141 | </Card>
142 | </Component>
143 | ```
144 |
145 |
146 |
147 |
148 | ## Component IDs
149 |
150 | A component ID declared on a Main.xmlui component is visible to built-in child components (e.g. `Text`) at any level.
151 |
152 | ```xmlui-pg
153 | ---app display filename="Main.xmlui" /parent/ /child/ /textBox/
154 | <App var.message="Hello from App">
155 | <TextBox id="textBox" initialValue="{message}" />
156 | <Card id="parent">
157 | <Text>
158 | { textBox.value }
159 | </Text>
160 | <Card id="child">
161 | <Text>
162 | { textBox.value }
163 | </Text>
164 | </Card>
165 | </Card>
166 | </App>
167 | ```
168 |
169 | A component ID declared on a Main.xmlui component is not automatically visible to a user-defined child component.
170 |
171 |
172 | ```xmlui-pg
173 | ---app display filename="Main.xmlui"
174 | <App var.message="Hello from App">
175 | <TextBox id="textBox" initialValue="{message}" />
176 | <MyCard />
177 | </App>
178 | ---comp display filename="MyCard.xmlui"
179 | <Component name="MyCard">
180 | <Card>
181 | <Text>Message: {textBox.value}</Text>
182 | </Card>
183 | </Component>
184 | ```
185 |
186 | The id can be passed into a user-defined component.
187 |
188 | ```xmlui-pg
189 | ---app display filename="Main.xmlui"
190 | <App var.message="Hello from App">
191 | <TextBox id="textBox" initialValue="{message}" />
192 | <MyCard textBox="{textBox}" />
193 | </App>
194 | ---comp display filename="MyCard.xmlui"
195 | <Component name="MyCard">
196 | <Card>
197 | <Text>Message: {$props.textBox.value}</Text>
198 | </Card>
199 | </Component>
200 | ```
201 |
202 | Or the component ID can be transposed into the user-defined component by means of the [Slot](/components/Slot) mechanism.
203 |
204 | ```xmlui-pg
205 | ---app display filename="Main.xmlui"
206 | <App var.message="Hello from App">
207 | <TextBox id="textBox" initialValue="{message}" />
208 | <MyCard>
209 | <Text>Message: {textBox.value}</Text>
210 | </MyCard>
211 | </App>
212 | ---comp display filename="MyCard.xmlui"
213 | <Component name="MyCard">
214 | <Card>
215 | <Slot/>
216 | </Card>
217 | </Component>
218 | ```
219 |
220 | All these rules apply within a user-defined component defined in a file like `MyComponent.xmlui`.
221 |
```
--------------------------------------------------------------------------------
/docs/public/pages/tutorial-06.md:
--------------------------------------------------------------------------------
```markdown
1 | # Slider
2 |
3 | The `Dashboard` page continues with a chart of daily revenue that uses a [Slider](/components/Slider) to control both ends of a date range.
4 |
5 | Here is a simplified version of that mechanism. Try using both slider handles to adjust the date range and corresponding total revenue.
6 |
7 | ```xmlui-pg noHeader
8 | ---app display
9 | <App>
10 | <SliderDemo />
11 | </App>
12 | ---comp
13 | <Component name="SliderDemo">
14 | <variable name="startDate" value="2022-06-01" />
15 | <variable name="endDate" value="2022-06-30" />
16 |
17 | <variable name="dailyData" value="{[
18 | {date: '2022-06-01', total: 1200},
19 | {date: '2022-06-02', total: 1850},
20 | {date: '2022-06-03', total: 0},
21 | {date: '2022-06-04', total: 950},
22 | {date: '2022-06-05', total: 1650},
23 | {date: '2022-06-06', total: 2200},
24 | {date: '2022-06-07', total: 1400},
25 | {date: '2022-06-08', total: 0},
26 | {date: '2022-06-09', total: 1750},
27 | {date: '2022-06-10', total: 1300},
28 | {date: '2022-06-11', total: 1900},
29 | {date: '2022-06-12', total: 2350},
30 | {date: '2022-06-13', total: 0},
31 | {date: '2022-06-14', total: 1800},
32 | {date: '2022-06-15', total: 2150},
33 | {date: '2022-06-16', total: 1450},
34 | {date: '2022-06-17', total: 0},
35 | {date: '2022-06-18', total: 2000},
36 | {date: '2022-06-19', total: 1250},
37 | {date: '2022-06-20', total: 1950},
38 | {date: '2022-06-21', total: 0},
39 | {date: '2022-06-22', total: 1600},
40 | {date: '2022-06-23', total: 1850},
41 | {date: '2022-06-24', total: 2250},
42 | {date: '2022-06-25', total: 0},
43 | {date: '2022-06-26', total: 1750},
44 | {date: '2022-06-27', total: 2050},
45 | {date: '2022-06-28', total: 1500},
46 | {date: '2022-06-29', total: 0},
47 | {date: '2022-06-30', total: 2200}
48 | ]}" />
49 |
50 | <variable name="filteredData" value="{
51 | dailyData.filter(item => item.date >= startDate && item.date <= endDate)
52 | }" />
53 |
54 | <VStack>
55 | <H1>Slider Demo</H1>
56 |
57 | <Text>Selected records: {filteredData.length}</Text>
58 |
59 | <Slider
60 | id="dateSlider"
61 | label="Date range"
62 | minValue="{1}"
63 | maxValue="{30}"
64 | initialValue="{[1, 30]}"
65 | step="{1}"
66 | onDidChange="{
67 | startDate = window.sliderValueToDate(dateSlider.value[0]);
68 | endDate = window.sliderValueToDate(dateSlider.value[1]);
69 | }"
70 | valueFormat="{ (value) => {
71 | const result = window.sliderValueToDate(value);
72 | return result;
73 | }
74 | }"
75 | />
76 |
77 | <Text>Total Revenue: ${filteredData.reduce((sum, item) => sum + item.total, 0)}</Text>
78 |
79 | </VStack>
80 | </Component>
81 | ```
82 |
83 | Here's `SliderDemo`.
84 |
85 | ```xmlui /filteredData/ /startDate/ /endDate/ /sliderValueToDate/
86 | <Component name="SliderDemo">
87 | <variable name="startDate" value="2022-06-01" />
88 | <variable name="endDate" value="2022-06-30" />
89 |
90 | <variable name="dailyData" value="{[
91 | {date: '2022-06-01', total: 1200},
92 | {date: '2022-06-02', total: 1850},
93 | ...
94 | {date: '2022-06-29', total: 0},
95 | {date: '2022-06-30', total: 2200}
96 | ]}" />
97 |
98 | <variable name="filteredData" value="{
99 | dailyData.filter(item => item.date >= startDate && item.date <= endDate)
100 | }" />
101 |
102 | <VStack>
103 | <H1>Slider Demo</H1>
104 |
105 | <Text>Selected records: {filteredData.length}</Text>
106 |
107 | <Slider
108 | id="dateSlider"
109 | label="Date range"
110 | minValue="{1}"
111 | maxValue="{30}"
112 | initialValue="{[1, 30]}"
113 | step="{1}"
114 | onDidChange="{
115 | startDate = window.sliderValueToDate(dateSlider.value[0]);
116 | endDate = window.sliderValueToDate(dateSlider.value[1]);
117 | }"
118 | valueFormat="{ (value) => {
119 | const result = window.sliderValueToDate(value);
120 | return result;
121 | }
122 | }"
123 | />
124 |
125 | <Text>
126 | Total Revenue: ${filteredData.reduce((sum, item) => sum + item.total, 0)}
127 | </Text>
128 |
129 | </VStack>
130 | </Component>
131 | ```
132 |
133 | When the handles move, the slider's `onDidChange` event updates `startDate` and `endDate` using a function, `sliderValueToDate`, that translates the slider position to a date in the range of dates. In the Invoices app those variables form part of a `DataSource` URL that fires when there's a change; here they update the `filteredData` variable to simulate the real `DataSource`.
134 |
135 | The slider's `valueFormat` property uses the same function to report the new `startDate` and `endDate`.
136 |
137 | ## A custom Slider
138 |
139 | The Invoices app encapsulates this behavior in a custom component called `DateRangeSlider`.
140 |
141 | ```xmlui /updateState/
142 | <Component name="DateRangeSlider">
143 | <variable name="originalStartDate" value="{ $props.minDate }"/>
144 | <variable name="maxEndDate" value="{ $props.maxDate }"/>
145 | <variable name="startDate" value="{ originalStartDate }"/>
146 | <variable name="endDate" value="{ maxEndDate }"/>
147 | <variable
148 | name="totalDays"
149 | value="{ window.daysBetween(originalStartDate, maxEndDate)}"/>
150 |
151 | <ChangeListener
152 | listenTo="{slider.value}"
153 | onDidChange="{() => {
154 | // Update the start and end dates based on slider values
155 | updateState({
156 | value: {
157 | startDate: window.sliderValueToDate(slider.value[0], originalStartDate),
158 | endDate: window.sliderValueToDate(slider.value[1], originalStartDate)
159 | }
160 | });
161 | }}"
162 | />
163 |
164 | <Slider
165 | id="slider"
166 | label="dateRange"
167 | minValue="{0}"
168 | maxValue="{ totalDays }"
169 | initialValue="{ [0, totalDays] }"
170 | step="10"
171 | valueFormat="{ (value) => {
172 | const date = window.sliderValueToDate(value, originalStartDate);
173 | return date;
174 | }}"
175 | />
176 | </Component>
177 | ```
178 |
179 | The `updateState` method, available in all components, is a merge operation that can set multiple variables.
180 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Tabs/Tabs.module.scss:
--------------------------------------------------------------------------------
```scss
1 | @use "../../components-core/theming/themes" as t;
2 |
3 | // --- This code snippet is required to collect the theme variables used in this module
4 | $component: "Tabs";
5 | $themeVars: ();
6 | @function createThemeVar($componentVariable) {
7 | $themeVars: t.appendThemeVar($themeVars, $componentVariable) !global;
8 | @return t.getThemeVar($themeVars, $componentVariable);
9 | }
10 |
11 | $themeVars: t.composePaddingVars($themeVars, "trigger-Tabs");
12 |
13 | $backgroundColor-Tabs: createThemeVar("backgroundColor-Tabs");
14 | $borderColor-Tabs: createThemeVar("borderColor-Tabs");
15 | $borderWidth-Tabs: createThemeVar("borderWidth-Tabs");
16 | $borderColor-active-Tabs: createThemeVar("borderColor-active-Tabs");
17 | $backgroundColor-trigger-Tabs: createThemeVar("backgroundColor-trigger-Tabs");
18 | $borderRadius-trigger-Tabs: createThemeVar("borderRadius-trigger-Tabs");
19 | $border-trigger-Tabs: createThemeVar("border-trigger-Tabs");
20 | $textColor-trigger-Tabs: createThemeVar("textColor-trigger-Tabs");
21 | $backgroundColor-trigger-Tabs--hover: createThemeVar("backgroundColor-trigger-Tabs--hover");
22 | $backgroundColor-trigger-Tabs--active: createThemeVar("backgroundColor-trigger-Tabs--active");
23 | $backgroundColor-list-Tabs: createThemeVar("backgroundColor-list-Tabs");
24 | $borderRadius-list-Tabs: createThemeVar("borderRadius-list-Tabs");
25 | $border-list-Tabs: createThemeVar("border-list-Tabs");
26 |
27 | @layer components {
28 | .tabs {
29 | display: flex;
30 | width: 100%;
31 | background-color: $backgroundColor-Tabs;
32 | overflow: hidden;
33 | &[data-orientation="vertical"] {
34 | flex-direction: row;
35 | }
36 |
37 | &[data-orientation="horizontal"] {
38 | flex-direction: column;
39 | }
40 | }
41 |
42 | .filler {
43 | flex: 1 1 auto;
44 |
45 | &[data-orientation="vertical"] {
46 | border-right-width: $borderWidth-Tabs;
47 | border-right-style: solid;
48 | border-right-color: $borderColor-Tabs;
49 | }
50 |
51 | &[data-orientation="horizontal"] {
52 | border-bottom-width: $borderWidth-Tabs;
53 | border-bottom-style: solid;
54 | border-bottom-color: $borderColor-Tabs;
55 | }
56 | }
57 |
58 | .tabTrigger {
59 | @include t.paddingVars($themeVars, "trigger-Tabs");
60 | &.distributeEvenly {
61 | flex: 1 1 auto;
62 | }
63 |
64 | color: $textColor-trigger-Tabs;
65 | background-color: $backgroundColor-trigger-Tabs;
66 | border-radius: $borderRadius-trigger-Tabs;
67 | display: flex;
68 | align-items: center;
69 | justify-content: center;
70 | font-size: t.$fontSize-base;
71 | line-height: 1;
72 | user-select: none;
73 | //border-color: transparent;
74 | border: $border-trigger-Tabs;
75 |
76 | &:hover {
77 | background-color: $backgroundColor-trigger-Tabs--hover;
78 | }
79 |
80 | &[data-orientation="vertical"] {
81 | border-right-width: $borderWidth-Tabs;
82 | border-right-style: solid;
83 | border-right-color: $borderColor-Tabs;
84 |
85 | &[data-state="active"] {
86 | border-right-width: $borderWidth-Tabs;
87 | border-right-style: solid;
88 | border-right-color: $borderColor-active-Tabs;
89 | background-color: $backgroundColor-trigger-Tabs--active;
90 | }
91 | }
92 |
93 | &[data-orientation="horizontal"] {
94 | border-bottom-width: $borderWidth-Tabs;
95 | border-bottom-style: solid;
96 | border-bottom-color: $borderColor-Tabs;
97 |
98 | &[data-state="active"] {
99 | border-bottom-width: $borderWidth-Tabs;
100 | border-bottom-style: solid;
101 | border-bottom-color: $borderColor-active-Tabs;
102 | background-color: $backgroundColor-trigger-Tabs--active;
103 | }
104 | }
105 |
106 | &:hover {
107 | cursor: pointer;
108 | }
109 | }
110 |
111 | .tabsList {
112 | background-color: $backgroundColor-list-Tabs;
113 | border-radius: $borderRadius-list-Tabs;
114 | border: $border-list-Tabs;
115 | position: relative;
116 | z-index: 99;
117 | overflow: hidden;
118 | display: flex;
119 | flex-shrink: 0;
120 | scrollbar-width: thin;
121 |
122 | &[data-orientation="vertical"] {
123 | flex-direction: column;
124 | }
125 |
126 | &[data-orientation="horizontal"] {
127 | flex-direction: row;
128 | }
129 |
130 | &.alignStart {
131 | justify-content: flex-start;
132 | }
133 |
134 | &.alignEnd {
135 | justify-content: flex-end;
136 | }
137 |
138 | &.alignCenter {
139 | justify-content: center;
140 | }
141 |
142 | &.alignStretch {
143 | justify-content: stretch;
144 | }
145 | }
146 |
147 | .tabsList:hover {
148 | overflow: auto;
149 | }
150 |
151 | .tabsContent {
152 | flex-grow: 1;
153 | outline: none;
154 | }
155 |
156 | // Accordion view styles
157 | .accordionView {
158 | width: 100%;
159 | }
160 |
161 | .accordionRoot {
162 | display: flex;
163 | flex-direction: column !important;
164 | width: 100%;
165 | }
166 |
167 | .accordionInterleaved {
168 | display: flex;
169 | flex-direction: column;
170 | width: 100%;
171 | }
172 |
173 | .accordionList {
174 | display: contents; // Makes children act as direct children of parent
175 | background-color: transparent;
176 | border: none;
177 | border-radius: 0;
178 | overflow: visible;
179 | }
180 |
181 | .accordionItem {
182 | display: flex;
183 | flex-direction: column;
184 | width: 100%;
185 | }
186 |
187 | .accordionTrigger {
188 | width: 100%;
189 | justify-content: flex-start;
190 | border-bottom-width: $borderWidth-Tabs;
191 | border-bottom-style: solid;
192 | border-bottom-color: $borderColor-Tabs;
193 | border-right: none !important;
194 |
195 | &[data-state="active"] {
196 | border-bottom-width: $borderWidth-Tabs;
197 | border-bottom-style: solid;
198 | border-bottom-color: $borderColor-active-Tabs;
199 | background-color: $backgroundColor-trigger-Tabs--active;
200 | border-right: none !important;
201 | }
202 | }
203 |
204 | // Style for accordion content to appear inline with headers
205 | .accordionInterleaved .tabsContent {
206 | width: 100%;
207 | order: inherit;
208 | }
209 | }
210 |
211 | // --- We export the theme variables to add them to the component renderer
212 | :export {
213 | themeVars: t.json-stringify($themeVars);
214 | }
215 |
```
--------------------------------------------------------------------------------
/docs/content/components/FlowLayout.md:
--------------------------------------------------------------------------------
```markdown
1 | # FlowLayout [#flowlayout]
2 |
3 | `FlowLayout` positions content in rows with automatic wrapping. When items exceed the available horizontal space, they automatically wrap to a new line.
4 |
5 | For details on how to work with \`FlowLayout\` (like sizing children), see [this guide](/layout#flowlayout).
6 |
7 | ## Using `SpaceFiller` with `FlowLayout` [#using-spacefiller-with-flowlayout]
8 |
9 | The `SpaceFiller` component can be used as a line break.
10 | See the [reference docs](/components/SpaceFiller) for details.
11 |
12 | ## Properties [#properties]
13 |
14 | ### `columnGap` (default: "$gap-normal") [#columngap-default-gap-normal]
15 |
16 | The `columnGap` property specifies the space between items in a single row; it overrides the `gap` value.
17 |
18 | The `columnGap` property specifies the space between items in a single row; it overrides the `gap` value.
19 |
20 | ```xmlui-pg copy display name="Example: columnGap"
21 | ---app copy display
22 | <App>
23 | <FlowLayout columnGap="$space-8">
24 | <Stack width="25%" height="32px" backgroundColor="red" />
25 | <Stack width="25%" height="32px" backgroundColor="blue" />
26 | <Stack width="25%" height="32px" backgroundColor="green" />
27 | <Stack width="25%" height="32px" backgroundColor="yellow" />
28 | <Stack width="25%" height="32px" backgroundColor="maroon" />
29 | <Stack width="25%" height="32px" backgroundColor="teal" />
30 | <Stack width="25%" height="32px" backgroundColor="seagreen" />
31 | <Stack width="25%" height="32px" backgroundColor="olive" />
32 | </FlowLayout>
33 | </App>
34 | ---desc
35 | You can observe no gap between the rows of the `FlowLayout`, as `columnGap` keeps the space between rows intact:
36 | ```
37 |
38 | ### `gap` (default: "$gap-normal") [#gap-default-gap-normal]
39 |
40 | This property defines the gap between items in the same row and between rows. The FlowLayout component creates a new row when an item is about to overflow the current row.
41 |
42 | The `gap` property defines the gap between items in the same row and between rows. The `FlowLayout` component creates a new row when an item is about to overflow the current row.
43 |
44 | ```xmlui-pg copy display name="Example: gap"
45 | ---app copy display
46 | <App>
47 | <FlowLayout gap="$space-12">
48 | <Stack width="25%" height="32px" backgroundColor="red" />
49 | <Stack width="25%" height="32px" backgroundColor="blue" />
50 | <Stack width="25%" height="32px" backgroundColor="green" />
51 | <Stack width="25%" height="32px" backgroundColor="yellow" />
52 | <Stack width="25%" height="32px" backgroundColor="maroon" />
53 | <Stack width="25%" height="32px" backgroundColor="teal" />
54 | <Stack width="25%" height="32px" backgroundColor="seagreen" />
55 | <Stack width="25%" height="32px" backgroundColor="olive" />
56 | </FlowLayout>
57 | </App>
58 | ---desc
59 | In this markup, only four items fit in a single row.
60 | The `gap` property sets the same gaps within and between rows.
61 | ```
62 |
63 | This markup demonstrates different `gap` values:
64 |
65 | ```xmlui-pg copy display name="Example: different size units"
66 | ---app copy display
67 | <App>
68 | <FlowLayout>
69 | <Stack width="25%" height="32px" backgroundColor="red" />
70 | <Stack width="25%" height="32px" backgroundColor="blue" />
71 | <Stack width="25%" height="32px" backgroundColor="green" />
72 | <Stack width="25%" height="32px" backgroundColor="yellow" />
73 | </FlowLayout>
74 | <FlowLayout gap="10px">
75 | <Stack width="25%" height="32px" backgroundColor="red" />
76 | <Stack width="25%" height="32px" backgroundColor="blue" />
77 | <Stack width="25%" height="32px" backgroundColor="green" />
78 | <Stack width="25%" height="32px" backgroundColor="yellow" />
79 | </FlowLayout>
80 | <FlowLayout gap="1rem">
81 | <Stack width="25%" height="32px" backgroundColor="red" />
82 | <Stack width="25%" height="32px" backgroundColor="blue" />
83 | <Stack width="25%" height="32px" backgroundColor="green" />
84 | <Stack width="25%" height="32px" backgroundColor="yellow" />
85 | </FlowLayout>
86 | <FlowLayout gap="4ch">
87 | <Stack width="25%" height="32px" backgroundColor="red" />
88 | <Stack width="25%" height="32px" backgroundColor="blue" />
89 | <Stack width="25%" height="32px" backgroundColor="green" />
90 | <Stack width="25%" height="32px" backgroundColor="yellow" />
91 | </FlowLayout>
92 | </App>
93 | ---desc
94 | All items within a `FlowLayout` instance fit in a single row, so `gap` affects only the space between items. The space between rows comes from the outermost `Stack`.
95 | ```
96 |
97 | ### `rowGap` (default: "$gap-normal") [#rowgap-default-gap-normal]
98 |
99 | The `rowGap` property specifies the space between the FlowLayout rows; it overrides the `gap` value.
100 |
101 | The `rowGap` property specifies the space between the `FlowLayout` rows; it overrides the `gap` value.
102 |
103 | ```xmlui-pg copy display name="Example: rowGap"
104 | ---app copy display
105 | <App>
106 | <FlowLayout rowGap="2px">
107 | <Stack width="25%" height="32px" backgroundColor="red" />
108 | <Stack width="25%" height="32px" backgroundColor="blue" />
109 | <Stack width="25%" height="32px" backgroundColor="green" />
110 | <Stack width="25%" height="32px" backgroundColor="yellow" />
111 | <Stack width="25%" height="32px" backgroundColor="maroon" />
112 | <Stack width="25%" height="32px" backgroundColor="teal" />
113 | <Stack width="25%" height="32px" backgroundColor="seagreen" />
114 | <Stack width="25%" height="32px" backgroundColor="olive" />
115 | </FlowLayout>
116 | </App>
117 | ---desc
118 | You can observe no gap between the items in a single row of the `FlowLayout`, as `rowGap` keeps the gap within a row intact:
119 | ```
120 |
121 | ## Events [#events]
122 |
123 | This component does not have any events.
124 |
125 | ## Exposed Methods [#exposed-methods]
126 |
127 | This component does not expose any methods.
128 |
129 | ## Styling [#styling]
130 |
131 | This component does not have any styles.
132 |
```
--------------------------------------------------------------------------------
/docs/content/components/MenuItem.md:
--------------------------------------------------------------------------------
```markdown
1 | # MenuItem [#menuitem]
2 |
3 | `MenuItem` represents individual clickable items within dropdown menus and other menu components. Each menu item can display text, icons, and respond to clicks with either navigation or custom actions, making it the building block for interactive menu systems.
4 |
5 | **Key features:**
6 | - **Action handling**: Support both navigation (`to` property) and custom click handlers
7 | - **Visual feedback**: Built-in active, hover, and disabled states for clear user interaction
8 | - **Icon support**: Optional icons with flexible positioning (start or end)
9 | - **Menu integration**: Designed to work seamlessly within `DropdownMenu` and `SubMenuItem` hierarchies
10 |
11 | **Usage pattern:**
12 | Always used within menu containers like `DropdownMenu`. Use `to` for navigation or `onClick` for custom actions. For complex menu structures, combine with `MenuSeparator` and `SubMenuItem` components.
13 |
14 | ## Properties [#properties]
15 |
16 | ### `active` (default: false) [#active-default-false]
17 |
18 | This property indicates if the specified menu item is active.
19 |
20 | ```xmlui-pg copy display name="Example: active" height="200px"
21 | <App>
22 | <DropdownMenu label="DropdownMenu">
23 | <MenuItem icon="drive" active="true">Item 1</MenuItem>
24 | <MenuItem icon="trash">Item 2</MenuItem>
25 | <MenuItem icon="email">Item 3</MenuItem>
26 | </DropdownMenu>
27 | </App>
28 | ```
29 |
30 | ### `enabled` (default: true) [#enabled-default-true]
31 |
32 | This boolean property value indicates whether the component responds to user events (`true`) or not (`false`).
33 |
34 | ### `icon` [#icon]
35 |
36 | This property names an optional icon to display with the menu item. You can use component-specific icons in the format "iconName:MenuItem".
37 |
38 | ```xmlui-pg copy display name="Example: icon" height="200px"
39 | <App>
40 | <DropdownMenu label="DropdownMenu">
41 | <MenuItem icon="drive">Item 1</MenuItem>
42 | <MenuItem icon="trash">Item 2</MenuItem>
43 | <MenuItem icon="email">Item 3</MenuItem>
44 | </DropdownMenu>
45 | </App>
46 | ```
47 |
48 | ### `iconPosition` (default: "start") [#iconposition-default-start]
49 |
50 | This property allows you to determine the position of the icon displayed in the menu item.
51 |
52 | Available values:
53 |
54 | | Value | Description |
55 | | --- | --- |
56 | | `start` | The icon will appear at the start (left side when the left-to-right direction is set) **(default)** |
57 | | `end` | The icon will appear at the end (right side when the left-to-right direction is set) |
58 |
59 | ```xmlui-pg copy display name="Example: iconPosition" height="200px"
60 | <App>
61 | <DropdownMenu label="DropdownMenu">
62 | <MenuItem icon="drive" iconPosition="start">Item 1</MenuItem>
63 | <MenuItem icon="trash" iconPosition="end">Item 2</MenuItem>
64 | <MenuItem icon="email">Item 3</MenuItem>
65 | </DropdownMenu>
66 | </App>
67 | ```
68 |
69 | ### `label` [#label]
70 |
71 | This property sets the label of the component. If not set, the component will not display a label.
72 |
73 | ### `to` [#to]
74 |
75 | This property defines the URL of the menu item. If this property is defined (and the `click` event does not have an event handler), clicking the menu item navigates to this link.
76 |
77 | ## Events [#events]
78 |
79 | ### `click` [#click]
80 |
81 | This event is triggered when the MenuItem is clicked.
82 |
83 | This event is fired when the user clicks the menu item. With an event handler, you can define how to respond to the user's click. If this event does not have an associated event handler but the `to` property has a value, clicking the component navigates the URL set in `to`.
84 |
85 | If both properties are defined, `click` takes precedence.
86 |
87 | ```xmlui-pg copy display name="Example: click" height="200px"
88 | <DropdownMenu label="DropdownMenu">
89 | <MenuItem onClick="toast('Item 1 clicked')">Item 1</MenuItem>
90 | <MenuItem onClick="toast('Item 2 clicked')">Item 2</MenuItem>
91 | <MenuItem onClick="toast('Item 3 clicked')">Item 3</MenuItem>
92 | </DropdownMenu>
93 | ```
94 |
95 | ## Exposed Methods [#exposed-methods]
96 |
97 | This component does not expose any methods.
98 |
99 | ## Styling [#styling]
100 |
101 | ### Theme Variables [#theme-variables]
102 |
103 | | Variable | Default Value (Light) | Default Value (Dark) |
104 | | --- | --- | --- |
105 | | [backgroundColor](../styles-and-themes/common-units/#color)-MenuItem | $backgroundColor-dropdown-item | $backgroundColor-dropdown-item |
106 | | [backgroundColor](../styles-and-themes/common-units/#color)-MenuItem--active | $backgroundColor-dropdown-item--active | $backgroundColor-dropdown-item--active |
107 | | [backgroundColor](../styles-and-themes/common-units/#color)-MenuItem--active--hover | *none* | *none* |
108 | | [backgroundColor](../styles-and-themes/common-units/#color)-MenuItem--hover | $backgroundColor-dropdown-item--hover | $backgroundColor-dropdown-item--hover |
109 | | [color](../styles-and-themes/common-units/#color)-MenuItem | $textColor-primary | $textColor-primary |
110 | | [color](../styles-and-themes/common-units/#color)-MenuItem--active | $color-primary | $color-primary |
111 | | [color](../styles-and-themes/common-units/#color)-MenuItem--active--hover | *none* | *none* |
112 | | [color](../styles-and-themes/common-units/#color)-MenuItem--disabled | $textColor--disabled | $textColor--disabled |
113 | | [color](../styles-and-themes/common-units/#color)-MenuItem--hover | inherit | inherit |
114 | | [fontFamily](../styles-and-themes/common-units/#fontFamily)-MenuItem | $fontFamily | $fontFamily |
115 | | [fontSize](../styles-and-themes/common-units/#size)-MenuItem | $fontSize-sm | $fontSize-sm |
116 | | [gap](../styles-and-themes/common-units/#size)-MenuItem | $space-2 | $space-2 |
117 | | [paddingHorizontal](../styles-and-themes/common-units/#size)-MenuItem | $space-3 | $space-3 |
118 | | [paddingVertical](../styles-and-themes/common-units/#size)-MenuItem | $space-2 | $space-2 |
119 |
```