This is page 50 of 143. Use http://codebase.md/xmlui-org/xmlui/xmlui/mockApiDef.js?lines=false&page={x} to view the full context.
# Directory Structure
```
├── .changeset
│ ├── config.json
│ └── cyan-tools-design.md
├── .eslintrc.cjs
├── .github
│ ├── build-checklist.png
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows
│ ├── deploy-blog-optimized.yml
│ ├── deploy-blog-swa.yml
│ ├── deploy-blog.yml
│ ├── deploy-docs-optimized.yml
│ ├── deploy-docs-swa.yml
│ ├── deploy-docs.yml
│ ├── prepare-versions.yml
│ ├── release-packages.yml
│ ├── run-all-tests.yml
│ └── run-smoke-tests.yml
├── .gitignore
├── .prettierrc.js
├── .vscode
│ ├── launch.json
│ └── settings.json
├── blog
│ ├── .gitignore
│ ├── .gitkeep
│ ├── CHANGELOG.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── package.json
│ ├── public
│ │ ├── blog
│ │ │ ├── images
│ │ │ │ ├── an-advanced-codefence.gif
│ │ │ │ ├── an-advanced-codefence.mp4
│ │ │ │ ├── blog-page-component.png
│ │ │ │ ├── blog-scrabble.png
│ │ │ │ ├── codefence-runner.png
│ │ │ │ ├── integrated-blog-search.png
│ │ │ │ ├── lorem-ipsum.png
│ │ │ │ ├── playground-checkbox-source.png
│ │ │ │ ├── playground.png
│ │ │ │ ├── use-xmlui-mcp-to-find-a-howto.png
│ │ │ │ └── xmlui-demo-gallery.png
│ │ │ ├── introducing-xmlui.md
│ │ │ ├── lorem-ipsum.md
│ │ │ ├── newest-post.md
│ │ │ ├── older-post.md
│ │ │ ├── xmlui-playground.md
│ │ │ └── xmlui-powered-blog.md
│ │ ├── mockServiceWorker.js
│ │ ├── resources
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ └── for-download
│ │ │ │ └── xmlui
│ │ │ │ └── xmlui-standalone.umd.js
│ │ │ ├── github.svg
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ ├── rss.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ ├── staticwebapp.config.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ └── PageNotFound.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── blog-theme.ts
│ └── tsconfig.json
├── CONTRIBUTING.md
├── docs
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── ComponentRefLinks.txt
│ ├── content
│ │ ├── _meta.json
│ │ ├── components
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── APICall.md
│ │ │ ├── App.md
│ │ │ ├── AppHeader.md
│ │ │ ├── AppState.md
│ │ │ ├── AutoComplete.md
│ │ │ ├── Avatar.md
│ │ │ ├── Backdrop.md
│ │ │ ├── Badge.md
│ │ │ ├── BarChart.md
│ │ │ ├── Bookmark.md
│ │ │ ├── Breakout.md
│ │ │ ├── Button.md
│ │ │ ├── Card.md
│ │ │ ├── Carousel.md
│ │ │ ├── ChangeListener.md
│ │ │ ├── Checkbox.md
│ │ │ ├── CHStack.md
│ │ │ ├── ColorPicker.md
│ │ │ ├── Column.md
│ │ │ ├── ContentSeparator.md
│ │ │ ├── CVStack.md
│ │ │ ├── DataSource.md
│ │ │ ├── DateInput.md
│ │ │ ├── DatePicker.md
│ │ │ ├── DonutChart.md
│ │ │ ├── DropdownMenu.md
│ │ │ ├── EmojiSelector.md
│ │ │ ├── ExpandableItem.md
│ │ │ ├── FileInput.md
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FlowLayout.md
│ │ │ ├── Footer.md
│ │ │ ├── Form.md
│ │ │ ├── FormItem.md
│ │ │ ├── FormSection.md
│ │ │ ├── Fragment.md
│ │ │ ├── H1.md
│ │ │ ├── H2.md
│ │ │ ├── H3.md
│ │ │ ├── H4.md
│ │ │ ├── H5.md
│ │ │ ├── H6.md
│ │ │ ├── Heading.md
│ │ │ ├── HSplitter.md
│ │ │ ├── HStack.md
│ │ │ ├── Icon.md
│ │ │ ├── IFrame.md
│ │ │ ├── Image.md
│ │ │ ├── Items.md
│ │ │ ├── LabelList.md
│ │ │ ├── Legend.md
│ │ │ ├── LineChart.md
│ │ │ ├── Link.md
│ │ │ ├── List.md
│ │ │ ├── Logo.md
│ │ │ ├── Markdown.md
│ │ │ ├── MenuItem.md
│ │ │ ├── MenuSeparator.md
│ │ │ ├── ModalDialog.md
│ │ │ ├── NavGroup.md
│ │ │ ├── NavLink.md
│ │ │ ├── NavPanel.md
│ │ │ ├── NoResult.md
│ │ │ ├── NumberBox.md
│ │ │ ├── Option.md
│ │ │ ├── Page.md
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── Pages.md
│ │ │ ├── Pagination.md
│ │ │ ├── PasswordInput.md
│ │ │ ├── PieChart.md
│ │ │ ├── ProgressBar.md
│ │ │ ├── Queue.md
│ │ │ ├── RadioGroup.md
│ │ │ ├── RealTimeAdapter.md
│ │ │ ├── Redirect.md
│ │ │ ├── Select.md
│ │ │ ├── Slider.md
│ │ │ ├── Slot.md
│ │ │ ├── SpaceFiller.md
│ │ │ ├── Spinner.md
│ │ │ ├── Splitter.md
│ │ │ ├── Stack.md
│ │ │ ├── StickyBox.md
│ │ │ ├── SubMenuItem.md
│ │ │ ├── Switch.md
│ │ │ ├── TabItem.md
│ │ │ ├── Table.md
│ │ │ ├── TableOfContents.md
│ │ │ ├── Tabs.md
│ │ │ ├── Text.md
│ │ │ ├── TextArea.md
│ │ │ ├── TextBox.md
│ │ │ ├── Theme.md
│ │ │ ├── TimeInput.md
│ │ │ ├── Timer.md
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneSwitch.md
│ │ │ ├── Tooltip.md
│ │ │ ├── Tree.md
│ │ │ ├── VSplitter.md
│ │ │ ├── VStack.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ ├── xmlui-spreadsheet
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Spreadsheet.md
│ │ │ └── xmlui-website-blocks
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Carousel.md
│ │ │ ├── HelloMd.md
│ │ │ ├── HeroSection.md
│ │ │ └── ScrollToTop.md
│ │ └── extensions
│ │ ├── _meta.json
│ │ ├── xmlui-animations
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Animation.md
│ │ │ ├── FadeAnimation.md
│ │ │ ├── FadeInAnimation.md
│ │ │ ├── FadeOutAnimation.md
│ │ │ ├── ScaleAnimation.md
│ │ │ └── SlideInAnimation.md
│ │ └── xmlui-website-blocks
│ │ ├── _meta.json
│ │ ├── _overview.md
│ │ ├── Carousel.md
│ │ ├── FancyButton.md
│ │ ├── HeroSection.md
│ │ └── ScrollToTop.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── package.json
│ ├── public
│ │ ├── feed.rss
│ │ ├── mockServiceWorker.js
│ │ ├── pages
│ │ │ ├── _meta.json
│ │ │ ├── app-structure.md
│ │ │ ├── build-editor-component.md
│ │ │ ├── build-hello-world-component.md
│ │ │ ├── components-intro.md
│ │ │ ├── context-variables.md
│ │ │ ├── forms.md
│ │ │ ├── globals.md
│ │ │ ├── glossary.md
│ │ │ ├── helper-tags.md
│ │ │ ├── hosted-deployment.md
│ │ │ ├── howto
│ │ │ │ ├── assign-a-complex-json-literal-to-a-component-variable.md
│ │ │ │ ├── chain-a-refetch.md
│ │ │ │ ├── control-cache-invalidation.md
│ │ │ │ ├── debounce-user-input-for-api-calls.md
│ │ │ │ ├── debounce-with-changelistener.md
│ │ │ │ ├── debug-a-component.md
│ │ │ │ ├── delay-a-datasource-until-another-datasource-is-ready.md
│ │ │ │ ├── delegate-a-method.md
│ │ │ │ ├── do-custom-form-validation.md
│ │ │ │ ├── expose-a-method-from-a-component.md
│ │ │ │ ├── filter-and-transform-data-from-an-api.md
│ │ │ │ ├── group-items-in-list-by-a-property.md
│ │ │ │ ├── handle-background-operations.md
│ │ │ │ ├── hide-an-element-until-its-datasource-is-ready.md
│ │ │ │ ├── make-a-set-of-equal-width-cards.md
│ │ │ │ ├── make-a-table-responsive.md
│ │ │ │ ├── make-navpanel-width-responsive.md
│ │ │ │ ├── modify-a-value-reported-in-a-column.md
│ │ │ │ ├── paginate-a-list.md
│ │ │ │ ├── pass-data-to-a-modal-dialog.md
│ │ │ │ ├── react-to-button-click-not-keystrokes.md
│ │ │ │ ├── set-the-initial-value-of-a-select-from-fetched-data.md
│ │ │ │ ├── share-a-modaldialog-across-components.md
│ │ │ │ ├── sync-selections-between-table-and-list-views.md
│ │ │ │ ├── update-ui-optimistically.md
│ │ │ │ ├── use-built-in-form-validation.md
│ │ │ │ └── use-the-same-modaldialog-to-add-or-edit.md
│ │ │ ├── howto.md
│ │ │ ├── intro.md
│ │ │ ├── layout.md
│ │ │ ├── markup.md
│ │ │ ├── mcp.md
│ │ │ ├── modal-dialogs.md
│ │ │ ├── news-and-reviews.md
│ │ │ ├── reactive-intro.md
│ │ │ ├── refactoring.md
│ │ │ ├── routing-and-links.md
│ │ │ ├── samples
│ │ │ │ ├── color-palette.xmlui
│ │ │ │ ├── color-values.xmlui
│ │ │ │ ├── shadow-sizes.xmlui
│ │ │ │ ├── spacing-sizes.xmlui
│ │ │ │ ├── swatch.xmlui
│ │ │ │ ├── theme-gallery-brief.xmlui
│ │ │ │ └── theme-gallery.xmlui
│ │ │ ├── scoping.md
│ │ │ ├── scripting.md
│ │ │ ├── styles-and-themes
│ │ │ │ ├── common-units.md
│ │ │ │ ├── layout-props.md
│ │ │ │ ├── theme-variable-defaults.md
│ │ │ │ ├── theme-variables.md
│ │ │ │ └── themes.md
│ │ │ ├── template-properties.md
│ │ │ ├── test.md
│ │ │ ├── tutorial-01.md
│ │ │ ├── tutorial-02.md
│ │ │ ├── tutorial-03.md
│ │ │ ├── tutorial-04.md
│ │ │ ├── tutorial-05.md
│ │ │ ├── tutorial-06.md
│ │ │ ├── tutorial-07.md
│ │ │ ├── tutorial-08.md
│ │ │ ├── tutorial-09.md
│ │ │ ├── tutorial-10.md
│ │ │ ├── tutorial-11.md
│ │ │ ├── tutorial-12.md
│ │ │ ├── universal-properties.md
│ │ │ ├── user-defined-components.md
│ │ │ ├── vscode.md
│ │ │ ├── working-with-markdown.md
│ │ │ ├── working-with-text.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-charts
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── DonutChart.md
│ │ │ │ ├── LabelList.md
│ │ │ │ ├── Legend.md
│ │ │ │ ├── LineChart.md
│ │ │ │ └── PieChart.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ └── xmlui-spreadsheet
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ └── Spreadsheet.md
│ │ ├── resources
│ │ │ ├── devdocs
│ │ │ │ ├── debug-proxy-object-2.png
│ │ │ │ ├── debug-proxy-object.png
│ │ │ │ ├── table_editor_01.png
│ │ │ │ ├── table_editor_02.png
│ │ │ │ ├── table_editor_03.png
│ │ │ │ ├── table_editor_04.png
│ │ │ │ ├── table_editor_05.png
│ │ │ │ ├── table_editor_06.png
│ │ │ │ ├── table_editor_07.png
│ │ │ │ ├── table_editor_08.png
│ │ │ │ ├── table_editor_09.png
│ │ │ │ ├── table_editor_10.png
│ │ │ │ ├── table_editor_11.png
│ │ │ │ ├── table-editor-01.png
│ │ │ │ ├── table-editor-02.png
│ │ │ │ ├── table-editor-03.png
│ │ │ │ ├── table-editor-04.png
│ │ │ │ ├── table-editor-06.png
│ │ │ │ ├── table-editor-07.png
│ │ │ │ ├── table-editor-08.png
│ │ │ │ ├── table-editor-09.png
│ │ │ │ └── xmlui-rendering-of-tiptap-markdown.png
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ ├── clients.json
│ │ │ │ ├── daily-revenue.json
│ │ │ │ ├── dashboard-stats.json
│ │ │ │ ├── demo.xmlui
│ │ │ │ ├── demo.xmlui.xs
│ │ │ │ ├── downloads
│ │ │ │ │ └── downloads.json
│ │ │ │ ├── for-download
│ │ │ │ │ ├── index-with-api.html
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── mockApi.js
│ │ │ │ │ ├── start-darwin.sh
│ │ │ │ │ ├── start-linux.sh
│ │ │ │ │ ├── start.bat
│ │ │ │ │ └── xmlui
│ │ │ │ │ └── xmlui-standalone.umd.js
│ │ │ │ ├── getting-started
│ │ │ │ │ ├── cl-tutorial-final.zip
│ │ │ │ │ ├── cl-tutorial.zip
│ │ │ │ │ ├── cl-tutorial2.zip
│ │ │ │ │ ├── cl-tutorial3.zip
│ │ │ │ │ ├── cl-tutorial4.zip
│ │ │ │ │ ├── cl-tutorial5.zip
│ │ │ │ │ ├── cl-tutorial6.zip
│ │ │ │ │ ├── getting-started.zip
│ │ │ │ │ ├── hello-xmlui.zip
│ │ │ │ │ ├── xmlui-empty.zip
│ │ │ │ │ └── xmlui-starter.zip
│ │ │ │ ├── howto
│ │ │ │ │ └── component-icons
│ │ │ │ │ └── up-arrow.svg
│ │ │ │ ├── invoices.json
│ │ │ │ ├── monthly-status.json
│ │ │ │ ├── news-and-reviews.json
│ │ │ │ ├── products.json
│ │ │ │ ├── releases.json
│ │ │ │ ├── tutorials
│ │ │ │ │ ├── datasource
│ │ │ │ │ │ └── api.ts
│ │ │ │ │ └── p2do
│ │ │ │ │ ├── api.ts
│ │ │ │ │ └── todo-logo.svg
│ │ │ │ └── xmlui.json
│ │ │ ├── github.svg
│ │ │ ├── images
│ │ │ │ ├── apiaction-tutorial
│ │ │ │ │ ├── add-success.png
│ │ │ │ │ ├── apiaction-param.png
│ │ │ │ │ ├── change-completed.png
│ │ │ │ │ ├── change-in-progress.png
│ │ │ │ │ ├── confirm-delete.png
│ │ │ │ │ ├── data-error.png
│ │ │ │ │ ├── data-progress.png
│ │ │ │ │ ├── data-success.png
│ │ │ │ │ ├── display-1.png
│ │ │ │ │ ├── item-deleted.png
│ │ │ │ │ ├── item-updated.png
│ │ │ │ │ ├── missing-api-key.png
│ │ │ │ │ ├── new-item-added.png
│ │ │ │ │ └── test-message.png
│ │ │ │ ├── chat-api
│ │ │ │ │ └── domain-model.svg
│ │ │ │ ├── components
│ │ │ │ │ ├── image
│ │ │ │ │ │ └── breakfast.jpg
│ │ │ │ │ ├── markdown
│ │ │ │ │ │ └── colors.png
│ │ │ │ │ └── modal
│ │ │ │ │ ├── deep_link_dialog_1.jpg
│ │ │ │ │ └── deep_link_dialog_2.jpg
│ │ │ │ ├── create-apps
│ │ │ │ │ ├── collapsed-vertical.png
│ │ │ │ │ ├── using-forms-warning-dialog.png
│ │ │ │ │ └── using-forms.png
│ │ │ │ ├── datasource-tutorial
│ │ │ │ │ ├── data-with-header.png
│ │ │ │ │ ├── filtered-data.png
│ │ │ │ │ ├── filtered-items.png
│ │ │ │ │ ├── initial-page-items.png
│ │ │ │ │ ├── list-items.png
│ │ │ │ │ ├── next-page-items.png
│ │ │ │ │ ├── no-data.png
│ │ │ │ │ ├── pagination-1.jpg
│ │ │ │ │ ├── pagination-1.png
│ │ │ │ │ ├── polling-1.png
│ │ │ │ │ ├── refetch-data.png
│ │ │ │ │ ├── slow-loading.png
│ │ │ │ │ ├── test-message.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── unconventional-data.png
│ │ │ │ │ └── unfiltered-items.png
│ │ │ │ ├── flower.jpg
│ │ │ │ ├── get-started
│ │ │ │ │ ├── add-new-contact.png
│ │ │ │ │ ├── app-modified.png
│ │ │ │ │ ├── app-start.png
│ │ │ │ │ ├── app-with-boxes.png
│ │ │ │ │ ├── app-with-toast.png
│ │ │ │ │ ├── boilerplate-structure.png
│ │ │ │ │ ├── cl-initial.png
│ │ │ │ │ ├── cl-start.png
│ │ │ │ │ ├── contact-counts.png
│ │ │ │ │ ├── contact-dialog-title.png
│ │ │ │ │ ├── contact-dialog.png
│ │ │ │ │ ├── contact-menus.png
│ │ │ │ │ ├── contact-predicates.png
│ │ │ │ │ ├── context-menu.png
│ │ │ │ │ ├── dashboard-numbers.png
│ │ │ │ │ ├── default-contact-list.png
│ │ │ │ │ ├── delete-contact.png
│ │ │ │ │ ├── delete-task.png
│ │ │ │ │ ├── detailed-template.png
│ │ │ │ │ ├── edit-contact-details.png
│ │ │ │ │ ├── edited-contact-saved.png
│ │ │ │ │ ├── empty-sections.png
│ │ │ │ │ ├── filter-completed.png
│ │ │ │ │ ├── fullwidth-desktop.png
│ │ │ │ │ ├── fullwidth-mobile.png
│ │ │ │ │ ├── initial-table.png
│ │ │ │ │ ├── items-and-badges.png
│ │ │ │ │ ├── loading-message.png
│ │ │ │ │ ├── new-contact-button.png
│ │ │ │ │ ├── new-contact-saved.png
│ │ │ │ │ ├── no-empty-sections.png
│ │ │ │ │ ├── personal-todo-initial.png
│ │ │ │ │ ├── piechart.png
│ │ │ │ │ ├── review-today.png
│ │ │ │ │ ├── rudimentary-dashboard.png
│ │ │ │ │ ├── section-collapsed.png
│ │ │ │ │ ├── sectioned-items.png
│ │ │ │ │ ├── sections-ordered.png
│ │ │ │ │ ├── spacex-list-with-links.png
│ │ │ │ │ ├── spacex-list.png
│ │ │ │ │ ├── start-personal-todo-1.png
│ │ │ │ │ ├── submit-new-contact.png
│ │ │ │ │ ├── submit-new-task.png
│ │ │ │ │ ├── syntax-highlighting.png
│ │ │ │ │ ├── table-with-badge.png
│ │ │ │ │ ├── template-with-card.png
│ │ │ │ │ ├── test-emulated-api.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── todo-logo.png
│ │ │ │ │ └── xmlui-tools.png
│ │ │ │ ├── HelloApp.png
│ │ │ │ ├── HelloApp2.png
│ │ │ │ ├── logos
│ │ │ │ │ ├── xmlui1.svg
│ │ │ │ │ ├── xmlui2.svg
│ │ │ │ │ ├── xmlui3.svg
│ │ │ │ │ ├── xmlui4.svg
│ │ │ │ │ ├── xmlui5.svg
│ │ │ │ │ ├── xmlui6.svg
│ │ │ │ │ └── xmlui7.svg
│ │ │ │ ├── pdf
│ │ │ │ │ └── dummy-pdf.jpg
│ │ │ │ ├── rendering-engine
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ ├── Component.svg
│ │ │ │ │ ├── CompoundComponent.svg
│ │ │ │ │ ├── RootComponent.svg
│ │ │ │ │ └── tree-with-containers.svg
│ │ │ │ ├── reviewers-guide
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ └── incbutton-in-action.png
│ │ │ │ ├── tools
│ │ │ │ │ └── boilerplate-structure.png
│ │ │ │ ├── try.svg
│ │ │ │ ├── tutorial
│ │ │ │ │ ├── app-chat-history.png
│ │ │ │ │ ├── app-content-placeholder.png
│ │ │ │ │ ├── app-header-and-content.png
│ │ │ │ │ ├── app-links-channel-selected.png
│ │ │ │ │ ├── app-links-click.png
│ │ │ │ │ ├── app-navigation.png
│ │ │ │ │ ├── finished-ex01.png
│ │ │ │ │ ├── finished-ex02.png
│ │ │ │ │ ├── hello.png
│ │ │ │ │ ├── splash-screen-advanced.png
│ │ │ │ │ ├── splash-screen-after-click.png
│ │ │ │ │ ├── splash-screen-centered.png
│ │ │ │ │ ├── splash-screen-events.png
│ │ │ │ │ ├── splash-screen-expression.png
│ │ │ │ │ ├── splash-screen-reuse-after.png
│ │ │ │ │ ├── splash-screen-reuse-before.png
│ │ │ │ │ └── splash-screen.png
│ │ │ │ └── tutorial-01.png
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ ├── Boxes.xmlui
│ │ │ ├── Breadcrumb.xmlui
│ │ │ ├── ChangeLog.xmlui
│ │ │ ├── ColorPalette.xmlui
│ │ │ ├── DocumentLinks.xmlui
│ │ │ ├── DocumentPage.xmlui
│ │ │ ├── DocumentPageNoTOC.xmlui
│ │ │ ├── Icons.xmlui
│ │ │ ├── IncButton.xmlui
│ │ │ ├── IncButton2.xmlui
│ │ │ ├── NameValue.xmlui
│ │ │ ├── PageNotFound.xmlui
│ │ │ ├── PaletteItem.xmlui
│ │ │ ├── Palettes.xmlui
│ │ │ ├── SectionHeader.xmlui
│ │ │ ├── TBD.xmlui
│ │ │ ├── Test.xmlui
│ │ │ ├── ThemesIntro.xmlui
│ │ │ ├── ThousandThemes.xmlui
│ │ │ ├── TubeStops.xmlui
│ │ │ ├── TubeStops.xmlui.xs
│ │ │ └── TwoColumnCode.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ ├── docs-theme.ts
│ │ ├── earthtone.ts
│ │ ├── xmlui-gray-on-default.ts
│ │ ├── xmlui-green-on-default.ts
│ │ └── xmlui-orange-on-default.ts
│ └── tsconfig.json
├── LICENSE
├── package-lock.json
├── package.json
├── packages
│ ├── tsconfig.json
│ ├── xmlui-animations
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── Animation.tsx
│ │ ├── AnimationNative.tsx
│ │ ├── FadeAnimation.tsx
│ │ ├── FadeInAnimation.tsx
│ │ ├── FadeOutAnimation.tsx
│ │ ├── index.tsx
│ │ ├── ScaleAnimation.tsx
│ │ └── SlideInAnimation.tsx
│ ├── xmlui-devtools
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── devtools
│ │ │ │ ├── DevTools.tsx
│ │ │ │ ├── DevToolsNative.module.scss
│ │ │ │ ├── DevToolsNative.tsx
│ │ │ │ ├── ModalDialog.module.scss
│ │ │ │ ├── ModalDialog.tsx
│ │ │ │ ├── ModalVisibilityContext.tsx
│ │ │ │ ├── Tooltip.module.scss
│ │ │ │ ├── Tooltip.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── editor
│ │ │ │ └── Editor.tsx
│ │ │ └── index.tsx
│ │ └── vite.config-overrides.ts
│ ├── xmlui-hello-world
│ │ ├── .gitignore
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── HelloWorld.module.scss
│ │ ├── HelloWorld.tsx
│ │ ├── HelloWorldNative.tsx
│ │ └── index.tsx
│ ├── xmlui-os-frames
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── IPhoneFrame.module.scss
│ │ ├── IPhoneFrame.tsx
│ │ ├── MacOSAppFrame.module.scss
│ │ ├── MacOSAppFrame.tsx
│ │ ├── WindowsAppFrame.module.scss
│ │ └── WindowsAppFrame.tsx
│ ├── xmlui-pdf
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ ├── components
│ │ │ │ └── Pdf.xmlui
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── LazyPdfNative.tsx
│ │ ├── Pdf.module.scss
│ │ └── Pdf.tsx
│ ├── xmlui-playground
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── hooks
│ │ │ ├── usePlayground.ts
│ │ │ └── useToast.ts
│ │ ├── index.tsx
│ │ ├── playground
│ │ │ ├── Box.module.scss
│ │ │ ├── Box.tsx
│ │ │ ├── CodeSelector.module.scss
│ │ │ ├── CodeSelector.tsx
│ │ │ ├── ConfirmationDialog.module.scss
│ │ │ ├── ConfirmationDialog.tsx
│ │ │ ├── Editor.tsx
│ │ │ ├── Header.module.scss
│ │ │ ├── Header.tsx
│ │ │ ├── Playground.tsx
│ │ │ ├── PlaygroundContent.module.scss
│ │ │ ├── PlaygroundContent.tsx
│ │ │ ├── PlaygroundNative.module.scss
│ │ │ ├── PlaygroundNative.tsx
│ │ │ ├── Preview.tsx
│ │ │ ├── StandalonePlayground.tsx
│ │ │ ├── StandalonePlaygroundNative.module.scss
│ │ │ ├── StandalonePlaygroundNative.tsx
│ │ │ ├── ThemeSwitcher.module.scss
│ │ │ ├── ThemeSwitcher.tsx
│ │ │ └── utils.ts
│ │ ├── providers
│ │ │ ├── Toast.module.scss
│ │ │ └── ToastProvider.tsx
│ │ ├── state
│ │ │ └── store.ts
│ │ ├── themes
│ │ │ └── theme.ts
│ │ └── utils
│ │ └── helpers.ts
│ ├── xmlui-search
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── Search.module.scss
│ │ └── Search.tsx
│ ├── xmlui-spreadsheet
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── Spreadsheet.tsx
│ │ └── SpreadsheetNative.tsx
│ └── xmlui-website-blocks
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── demo
│ │ ├── components
│ │ │ ├── HeroBackgroundBreakoutPage.xmlui
│ │ │ ├── HeroBackgroundsPage.xmlui
│ │ │ ├── HeroContentsPage.xmlui
│ │ │ ├── HeroTextAlignPage.xmlui
│ │ │ ├── HeroTextPage.xmlui
│ │ │ └── HeroTonesPage.xmlui
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── default.ts
│ ├── index.html
│ ├── index.ts
│ ├── meta
│ │ └── componentsMetadata.ts
│ ├── package.json
│ ├── public
│ │ └── resources
│ │ ├── building.jpg
│ │ └── xmlui-logo.svg
│ └── src
│ ├── Carousel
│ │ ├── Carousel.module.scss
│ │ ├── Carousel.tsx
│ │ ├── CarouselContext.tsx
│ │ └── CarouselNative.tsx
│ ├── FancyButton
│ │ ├── FancyButton.module.scss
│ │ ├── FancyButton.tsx
│ │ └── FancyButton.xmlui
│ ├── Hello
│ │ ├── Hello.tsx
│ │ ├── Hello.xmlui
│ │ └── Hello.xmlui.xs
│ ├── HeroSection
│ │ ├── HeroSection.module.scss
│ │ ├── HeroSection.spec.ts
│ │ ├── HeroSection.tsx
│ │ └── HeroSectionNative.tsx
│ ├── index.tsx
│ ├── ScrollToTop
│ │ ├── ScrollToTop.module.scss
│ │ ├── ScrollToTop.tsx
│ │ └── ScrollToTopNative.tsx
│ └── vite-env.d.ts
├── playwright.config.ts
├── README.md
├── tools
│ ├── codefence
│ │ └── xmlui-code-fence-docs.md
│ ├── create-app
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── create-app.ts
│ │ ├── helpers
│ │ │ ├── copy.ts
│ │ │ ├── get-pkg-manager.ts
│ │ │ ├── git.ts
│ │ │ ├── install.ts
│ │ │ ├── is-folder-empty.ts
│ │ │ ├── is-writeable.ts
│ │ │ ├── make-dir.ts
│ │ │ └── validate-pkg.ts
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── templates
│ │ │ ├── default
│ │ │ │ └── ts
│ │ │ │ ├── gitignore
│ │ │ │ ├── index.html
│ │ │ │ ├── index.ts
│ │ │ │ ├── public
│ │ │ │ │ ├── mockServiceWorker.js
│ │ │ │ │ ├── resources
│ │ │ │ │ │ ├── favicon.ico
│ │ │ │ │ │ └── xmlui-logo.svg
│ │ │ │ │ └── serve.json
│ │ │ │ └── src
│ │ │ │ ├── components
│ │ │ │ │ ├── ApiAware.xmlui
│ │ │ │ │ ├── Home.xmlui
│ │ │ │ │ ├── IncButton.xmlui
│ │ │ │ │ └── PagePanel.xmlui
│ │ │ │ ├── config.ts
│ │ │ │ └── Main.xmlui
│ │ │ ├── index.ts
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ ├── create-xmlui-hello-world
│ │ ├── index.js
│ │ └── package.json
│ └── vscode
│ ├── .gitignore
│ ├── .vscode
│ │ ├── launch.json
│ │ └── tasks.json
│ ├── .vscodeignore
│ ├── build.sh
│ ├── CHANGELOG.md
│ ├── esbuild.js
│ ├── eslint.config.mjs
│ ├── formatter-docs.md
│ ├── generate-test-sample.sh
│ ├── LICENSE.md
│ ├── package-lock.json
│ ├── package.json
│ ├── README.md
│ ├── resources
│ │ ├── xmlui-logo.png
│ │ └── xmlui-markup-syntax-highlighting.png
│ ├── src
│ │ ├── extension.ts
│ │ └── server.ts
│ ├── syntaxes
│ │ └── xmlui.tmLanguage.json
│ ├── test-samples
│ │ └── sample.xmlui
│ ├── tsconfig.json
│ └── tsconfig.tsbuildinfo
├── turbo.json
└── xmlui
├── .gitignore
├── bin
│ ├── bootstrap.cjs
│ ├── bootstrap.js
│ ├── build-lib.ts
│ ├── build.ts
│ ├── index.ts
│ ├── preview.ts
│ ├── start.ts
│ ├── vite-xmlui-plugin.ts
│ └── viteConfig.ts
├── CHANGELOG.md
├── conventions
│ ├── component-qa-checklist.md
│ ├── copilot-conventions.md
│ ├── create-xmlui-components.md
│ ├── mermaid.md
│ ├── testing-conventions.md
│ └── xmlui-in-a-nutshell.md
├── dev-docs
│ ├── accessibility.md
│ ├── build-system.md
│ ├── build-xmlui.md
│ ├── component-behaviors.md
│ ├── component-metadata.md
│ ├── components-with-options.md
│ ├── containers.md
│ ├── data-operations.md
│ ├── glossary.md
│ ├── index.md
│ ├── next
│ │ ├── component-dev-guide.md
│ │ ├── configuration-management-enhancement-summary.md
│ │ ├── documentation-scripts-refactoring-complete-summary.md
│ │ ├── documentation-scripts-refactoring-plan.md
│ │ ├── duplicate-pattern-extraction-summary.md
│ │ ├── error-handling-standardization-summary.md
│ │ ├── generating-component-reference.md
│ │ ├── index.md
│ │ ├── logging-consistency-implementation-summary.md
│ │ ├── project-build.md
│ │ ├── project-structure.md
│ │ ├── theme-context.md
│ │ ├── tiptap-design-considerations.md
│ │ ├── working-with-code.md
│ │ ├── xmlui-runtime-architecture
│ │ └── xmlui-wcag-accessibility-report.md
│ ├── react-fundamentals.md
│ ├── release-method.md
│ ├── standalone-app.md
│ ├── theme-variables-refactoring.md
│ ├── ud-components.md
│ └── xmlui-repo.md
├── package.json
├── scripts
│ ├── coverage-only.js
│ ├── e2e-test-summary.js
│ ├── extract-component-metadata.js
│ ├── generate-docs
│ │ ├── build-downloads-map.mjs
│ │ ├── build-pages-map.mjs
│ │ ├── components-config.json
│ │ ├── configuration-management.mjs
│ │ ├── constants.mjs
│ │ ├── create-theme-files.mjs
│ │ ├── DocsGenerator.mjs
│ │ ├── error-handling.mjs
│ │ ├── extensions-config.json
│ │ ├── folders.mjs
│ │ ├── generate-summary-files.mjs
│ │ ├── get-docs.mjs
│ │ ├── input-handler.mjs
│ │ ├── logger.mjs
│ │ ├── logging-standards.mjs
│ │ ├── MetadataProcessor.mjs
│ │ ├── pattern-utilities.mjs
│ │ └── utils.mjs
│ ├── generate-metadata-markdown.js
│ ├── get-langserver-metadata.js
│ ├── inline-links.mjs
│ └── README-e2e-summary.md
├── src
│ ├── abstractions
│ │ ├── _conventions.md
│ │ ├── ActionDefs.ts
│ │ ├── AppContextDefs.ts
│ │ ├── ComponentDefs.ts
│ │ ├── ContainerDefs.ts
│ │ ├── ExtensionDefs.ts
│ │ ├── FunctionDefs.ts
│ │ ├── RendererDefs.ts
│ │ ├── scripting
│ │ │ ├── BlockScope.ts
│ │ │ ├── Compilation.ts
│ │ │ ├── LogicalThread.ts
│ │ │ ├── LoopScope.ts
│ │ │ ├── modules.ts
│ │ │ ├── ScriptParserError.ts
│ │ │ ├── Token.ts
│ │ │ ├── TryScope.ts
│ │ │ └── TryScopeExp.ts
│ │ └── ThemingDefs.ts
│ ├── components
│ │ ├── _conventions.md
│ │ ├── abstractions.ts
│ │ ├── Accordion
│ │ │ ├── Accordion.md
│ │ │ ├── Accordion.module.scss
│ │ │ ├── Accordion.spec.ts
│ │ │ ├── Accordion.tsx
│ │ │ ├── AccordionContext.tsx
│ │ │ ├── AccordionItem.tsx
│ │ │ ├── AccordionItemNative.tsx
│ │ │ └── AccordionNative.tsx
│ │ ├── Animation
│ │ │ └── AnimationNative.tsx
│ │ ├── APICall
│ │ │ ├── APICall.md
│ │ │ ├── APICall.spec.ts
│ │ │ ├── APICall.tsx
│ │ │ └── APICallNative.tsx
│ │ ├── App
│ │ │ ├── App.md
│ │ │ ├── App.module.scss
│ │ │ ├── App.spec.ts
│ │ │ ├── App.tsx
│ │ │ ├── AppLayoutContext.ts
│ │ │ ├── AppNative.tsx
│ │ │ ├── AppStateContext.ts
│ │ │ ├── doc-resources
│ │ │ │ ├── condensed-sticky.xmlui
│ │ │ │ ├── condensed.xmlui
│ │ │ │ ├── horizontal-sticky.xmlui
│ │ │ │ ├── horizontal.xmlui
│ │ │ │ ├── vertical-full-header.xmlui
│ │ │ │ ├── vertical-sticky.xmlui
│ │ │ │ └── vertical.xmlui
│ │ │ ├── IndexerContext.ts
│ │ │ ├── LinkInfoContext.ts
│ │ │ ├── SearchContext.tsx
│ │ │ ├── Sheet.module.scss
│ │ │ └── Sheet.tsx
│ │ ├── AppHeader
│ │ │ ├── AppHeader.md
│ │ │ ├── AppHeader.module.scss
│ │ │ ├── AppHeader.spec.ts
│ │ │ ├── AppHeader.tsx
│ │ │ └── AppHeaderNative.tsx
│ │ ├── AppState
│ │ │ ├── AppState.md
│ │ │ ├── AppState.spec.ts
│ │ │ ├── AppState.tsx
│ │ │ └── AppStateNative.tsx
│ │ ├── AutoComplete
│ │ │ ├── AutoComplete.md
│ │ │ ├── AutoComplete.module.scss
│ │ │ ├── AutoComplete.spec.ts
│ │ │ ├── AutoComplete.tsx
│ │ │ ├── AutoCompleteContext.tsx
│ │ │ └── AutoCompleteNative.tsx
│ │ ├── Avatar
│ │ │ ├── Avatar.md
│ │ │ ├── Avatar.module.scss
│ │ │ ├── Avatar.spec.ts
│ │ │ ├── Avatar.tsx
│ │ │ └── AvatarNative.tsx
│ │ ├── Backdrop
│ │ │ ├── Backdrop.md
│ │ │ ├── Backdrop.module.scss
│ │ │ ├── Backdrop.spec.ts
│ │ │ ├── Backdrop.tsx
│ │ │ └── BackdropNative.tsx
│ │ ├── Badge
│ │ │ ├── Badge.md
│ │ │ ├── Badge.module.scss
│ │ │ ├── Badge.spec.ts
│ │ │ ├── Badge.tsx
│ │ │ └── BadgeNative.tsx
│ │ ├── Bookmark
│ │ │ ├── Bookmark.md
│ │ │ ├── Bookmark.module.scss
│ │ │ ├── Bookmark.spec.ts
│ │ │ ├── Bookmark.tsx
│ │ │ └── BookmarkNative.tsx
│ │ ├── Breakout
│ │ │ ├── Breakout.module.scss
│ │ │ ├── Breakout.spec.ts
│ │ │ ├── Breakout.tsx
│ │ │ └── BreakoutNative.tsx
│ │ ├── Button
│ │ │ ├── Button-style.spec.ts
│ │ │ ├── Button.md
│ │ │ ├── Button.module.scss
│ │ │ ├── Button.spec.ts
│ │ │ ├── Button.tsx
│ │ │ └── ButtonNative.tsx
│ │ ├── Card
│ │ │ ├── Card.md
│ │ │ ├── Card.module.scss
│ │ │ ├── Card.spec.ts
│ │ │ ├── Card.tsx
│ │ │ └── CardNative.tsx
│ │ ├── Carousel
│ │ │ ├── Carousel.md
│ │ │ ├── Carousel.module.scss
│ │ │ ├── Carousel.spec.ts
│ │ │ ├── Carousel.tsx
│ │ │ ├── CarouselContext.tsx
│ │ │ ├── CarouselItem.tsx
│ │ │ ├── CarouselItemNative.tsx
│ │ │ └── CarouselNative.tsx
│ │ ├── ChangeListener
│ │ │ ├── ChangeListener.md
│ │ │ ├── ChangeListener.spec.ts
│ │ │ ├── ChangeListener.tsx
│ │ │ └── ChangeListenerNative.tsx
│ │ ├── chart-color-schemes.ts
│ │ ├── Charts
│ │ │ ├── AreaChart
│ │ │ │ ├── AreaChart.md
│ │ │ │ ├── AreaChart.spec.ts
│ │ │ │ ├── AreaChart.tsx
│ │ │ │ └── AreaChartNative.tsx
│ │ │ ├── BarChart
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── BarChart.module.scss
│ │ │ │ ├── BarChart.spec.ts
│ │ │ │ ├── BarChart.tsx
│ │ │ │ └── BarChartNative.tsx
│ │ │ ├── DonutChart
│ │ │ │ ├── DonutChart.spec.ts
│ │ │ │ └── DonutChart.tsx
│ │ │ ├── LabelList
│ │ │ │ ├── LabelList.module.scss
│ │ │ │ ├── LabelList.spec.ts
│ │ │ │ ├── LabelList.tsx
│ │ │ │ └── LabelListNative.tsx
│ │ │ ├── Legend
│ │ │ │ ├── Legend.spec.ts
│ │ │ │ ├── Legend.tsx
│ │ │ │ └── LegendNative.tsx
│ │ │ ├── LineChart
│ │ │ │ ├── LineChart.md
│ │ │ │ ├── LineChart.module.scss
│ │ │ │ ├── LineChart.spec.ts
│ │ │ │ ├── LineChart.tsx
│ │ │ │ └── LineChartNative.tsx
│ │ │ ├── PieChart
│ │ │ │ ├── PieChart.md
│ │ │ │ ├── PieChart.spec.ts
│ │ │ │ ├── PieChart.tsx
│ │ │ │ ├── PieChartNative.module.scss
│ │ │ │ └── PieChartNative.tsx
│ │ │ ├── RadarChart
│ │ │ │ ├── RadarChart.md
│ │ │ │ ├── RadarChart.spec.ts
│ │ │ │ ├── RadarChart.tsx
│ │ │ │ └── RadarChartNative.tsx
│ │ │ ├── Tooltip
│ │ │ │ ├── TooltipContent.module.scss
│ │ │ │ ├── TooltipContent.spec.ts
│ │ │ │ └── TooltipContent.tsx
│ │ │ └── utils
│ │ │ ├── abstractions.ts
│ │ │ └── ChartProvider.tsx
│ │ ├── Checkbox
│ │ │ ├── Checkbox.md
│ │ │ ├── Checkbox.spec.ts
│ │ │ └── Checkbox.tsx
│ │ ├── CodeBlock
│ │ │ ├── CodeBlock.module.scss
│ │ │ ├── CodeBlock.spec.ts
│ │ │ ├── CodeBlock.tsx
│ │ │ ├── CodeBlockNative.tsx
│ │ │ └── highlight-code.ts
│ │ ├── collectedComponentMetadata.ts
│ │ ├── ColorPicker
│ │ │ ├── ColorPicker.md
│ │ │ ├── ColorPicker.module.scss
│ │ │ ├── ColorPicker.spec.ts
│ │ │ ├── ColorPicker.tsx
│ │ │ └── ColorPickerNative.tsx
│ │ ├── Column
│ │ │ ├── Column.md
│ │ │ ├── Column.tsx
│ │ │ ├── ColumnNative.tsx
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ └── TableContext.tsx
│ │ ├── component-utils.ts
│ │ ├── ComponentProvider.tsx
│ │ ├── ComponentRegistryContext.tsx
│ │ ├── container-helpers.tsx
│ │ ├── ContentSeparator
│ │ │ ├── ContentSeparator.md
│ │ │ ├── ContentSeparator.module.scss
│ │ │ ├── ContentSeparator.spec.ts
│ │ │ ├── ContentSeparator.tsx
│ │ │ └── ContentSeparatorNative.tsx
│ │ ├── DataSource
│ │ │ ├── DataSource.md
│ │ │ └── DataSource.tsx
│ │ ├── DateInput
│ │ │ ├── DateInput.md
│ │ │ ├── DateInput.module.scss
│ │ │ ├── DateInput.spec.ts
│ │ │ ├── DateInput.tsx
│ │ │ └── DateInputNative.tsx
│ │ ├── DatePicker
│ │ │ ├── DatePicker.md
│ │ │ ├── DatePicker.module.scss
│ │ │ ├── DatePicker.spec.ts
│ │ │ ├── DatePicker.tsx
│ │ │ └── DatePickerNative.tsx
│ │ ├── DropdownMenu
│ │ │ ├── DropdownMenu.md
│ │ │ ├── DropdownMenu.module.scss
│ │ │ ├── DropdownMenu.spec.ts
│ │ │ ├── DropdownMenu.tsx
│ │ │ ├── DropdownMenuNative.tsx
│ │ │ ├── MenuItem.md
│ │ │ └── SubMenuItem.md
│ │ ├── EmojiSelector
│ │ │ ├── EmojiSelector.md
│ │ │ ├── EmojiSelector.spec.ts
│ │ │ ├── EmojiSelector.tsx
│ │ │ └── EmojiSelectorNative.tsx
│ │ ├── ExpandableItem
│ │ │ ├── ExpandableItem.module.scss
│ │ │ ├── ExpandableItem.spec.ts
│ │ │ ├── ExpandableItem.tsx
│ │ │ └── ExpandableItemNative.tsx
│ │ ├── FileInput
│ │ │ ├── FileInput.md
│ │ │ ├── FileInput.module.scss
│ │ │ ├── FileInput.spec.ts
│ │ │ ├── FileInput.tsx
│ │ │ └── FileInputNative.tsx
│ │ ├── FileUploadDropZone
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FileUploadDropZone.module.scss
│ │ │ ├── FileUploadDropZone.spec.ts
│ │ │ ├── FileUploadDropZone.tsx
│ │ │ └── FileUploadDropZoneNative.tsx
│ │ ├── FlowLayout
│ │ │ ├── FlowLayout.md
│ │ │ ├── FlowLayout.module.scss
│ │ │ ├── FlowLayout.spec.ts
│ │ │ ├── FlowLayout.spec.ts-snapshots
│ │ │ │ └── Edge-cases-boxShadow-is-not-clipped-1-non-smoke-darwin.png
│ │ │ ├── FlowLayout.tsx
│ │ │ └── FlowLayoutNative.tsx
│ │ ├── Footer
│ │ │ ├── Footer.md
│ │ │ ├── Footer.module.scss
│ │ │ ├── Footer.spec.ts
│ │ │ ├── Footer.tsx
│ │ │ └── FooterNative.tsx
│ │ ├── Form
│ │ │ ├── Form.md
│ │ │ ├── Form.module.scss
│ │ │ ├── Form.spec.ts
│ │ │ ├── Form.tsx
│ │ │ ├── formActions.ts
│ │ │ ├── FormContext.ts
│ │ │ └── FormNative.tsx
│ │ ├── FormItem
│ │ │ ├── FormItem.md
│ │ │ ├── FormItem.module.scss
│ │ │ ├── FormItem.spec.ts
│ │ │ ├── FormItem.tsx
│ │ │ ├── FormItemNative.tsx
│ │ │ ├── HelperText.module.scss
│ │ │ ├── HelperText.tsx
│ │ │ ├── ItemWithLabel.tsx
│ │ │ └── Validations.ts
│ │ ├── FormSection
│ │ │ ├── FormSection.md
│ │ │ ├── FormSection.ts
│ │ │ └── FormSection.xmlui
│ │ ├── Fragment
│ │ │ ├── Fragment.spec.ts
│ │ │ └── Fragment.tsx
│ │ ├── Heading
│ │ │ ├── abstractions.ts
│ │ │ ├── H1.md
│ │ │ ├── H1.spec.ts
│ │ │ ├── H2.md
│ │ │ ├── H2.spec.ts
│ │ │ ├── H3.md
│ │ │ ├── H3.spec.ts
│ │ │ ├── H4.md
│ │ │ ├── H4.spec.ts
│ │ │ ├── H5.md
│ │ │ ├── H5.spec.ts
│ │ │ ├── H6.md
│ │ │ ├── H6.spec.ts
│ │ │ ├── Heading.md
│ │ │ ├── Heading.module.scss
│ │ │ ├── Heading.spec.ts
│ │ │ ├── Heading.tsx
│ │ │ └── HeadingNative.tsx
│ │ ├── HoverCard
│ │ │ ├── HoverCard.tsx
│ │ │ └── HovercardNative.tsx
│ │ ├── HtmlTags
│ │ │ ├── HtmlTags.module.scss
│ │ │ ├── HtmlTags.spec.ts
│ │ │ └── HtmlTags.tsx
│ │ ├── Icon
│ │ │ ├── AdmonitionDanger.tsx
│ │ │ ├── AdmonitionInfo.tsx
│ │ │ ├── AdmonitionNote.tsx
│ │ │ ├── AdmonitionTip.tsx
│ │ │ ├── AdmonitionWarning.tsx
│ │ │ ├── ApiIcon.tsx
│ │ │ ├── ArrowDropDown.module.scss
│ │ │ ├── ArrowDropDown.tsx
│ │ │ ├── ArrowDropUp.module.scss
│ │ │ ├── ArrowDropUp.tsx
│ │ │ ├── ArrowLeft.module.scss
│ │ │ ├── ArrowLeft.tsx
│ │ │ ├── ArrowRight.module.scss
│ │ │ ├── ArrowRight.tsx
│ │ │ ├── Attach.tsx
│ │ │ ├── Binding.module.scss
│ │ │ ├── Binding.tsx
│ │ │ ├── BoardIcon.tsx
│ │ │ ├── BoxIcon.tsx
│ │ │ ├── CheckIcon.tsx
│ │ │ ├── ChevronDownIcon.tsx
│ │ │ ├── ChevronLeft.tsx
│ │ │ ├── ChevronRight.tsx
│ │ │ ├── ChevronUpIcon.tsx
│ │ │ ├── CodeFileIcon.tsx
│ │ │ ├── CodeSandbox.tsx
│ │ │ ├── CompactListIcon.tsx
│ │ │ ├── ContentCopyIcon.tsx
│ │ │ ├── DarkToLightIcon.tsx
│ │ │ ├── DatabaseIcon.module.scss
│ │ │ ├── DatabaseIcon.tsx
│ │ │ ├── DocFileIcon.tsx
│ │ │ ├── DocIcon.tsx
│ │ │ ├── DotMenuHorizontalIcon.tsx
│ │ │ ├── DotMenuIcon.tsx
│ │ │ ├── EmailIcon.tsx
│ │ │ ├── EmptyFolderIcon.tsx
│ │ │ ├── ErrorIcon.tsx
│ │ │ ├── ExpressionIcon.tsx
│ │ │ ├── FillPlusCricleIcon.tsx
│ │ │ ├── FilterIcon.tsx
│ │ │ ├── FolderIcon.tsx
│ │ │ ├── GlobeIcon.tsx
│ │ │ ├── HomeIcon.tsx
│ │ │ ├── HyperLinkIcon.tsx
│ │ │ ├── Icon.md
│ │ │ ├── Icon.module.scss
│ │ │ ├── Icon.spec.ts
│ │ │ ├── Icon.tsx
│ │ │ ├── IconNative.tsx
│ │ │ ├── ImageFileIcon.tsx
│ │ │ ├── Inspect.tsx
│ │ │ ├── LightToDark.tsx
│ │ │ ├── LinkIcon.tsx
│ │ │ ├── ListIcon.tsx
│ │ │ ├── LooseListIcon.tsx
│ │ │ ├── MoonIcon.tsx
│ │ │ ├── MoreOptionsIcon.tsx
│ │ │ ├── NoSortIcon.tsx
│ │ │ ├── PDFIcon.tsx
│ │ │ ├── PenIcon.tsx
│ │ │ ├── PhoneIcon.tsx
│ │ │ ├── PhotoIcon.tsx
│ │ │ ├── PlusIcon.tsx
│ │ │ ├── SearchIcon.tsx
│ │ │ ├── ShareIcon.tsx
│ │ │ ├── SortAscendingIcon.tsx
│ │ │ ├── SortDescendingIcon.tsx
│ │ │ ├── StarsIcon.tsx
│ │ │ ├── SunIcon.tsx
│ │ │ ├── svg
│ │ │ │ ├── admonition_danger.svg
│ │ │ │ ├── admonition_info.svg
│ │ │ │ ├── admonition_note.svg
│ │ │ │ ├── admonition_tip.svg
│ │ │ │ ├── admonition_warning.svg
│ │ │ │ ├── api.svg
│ │ │ │ ├── arrow-dropdown.svg
│ │ │ │ ├── arrow-left.svg
│ │ │ │ ├── arrow-right.svg
│ │ │ │ ├── arrow-up.svg
│ │ │ │ ├── attach.svg
│ │ │ │ ├── binding.svg
│ │ │ │ ├── box.svg
│ │ │ │ ├── bulb.svg
│ │ │ │ ├── code-file.svg
│ │ │ │ ├── code-sandbox.svg
│ │ │ │ ├── dark_to_light.svg
│ │ │ │ ├── database.svg
│ │ │ │ ├── doc.svg
│ │ │ │ ├── empty-folder.svg
│ │ │ │ ├── expression.svg
│ │ │ │ ├── eye-closed.svg
│ │ │ │ ├── eye-dark.svg
│ │ │ │ ├── eye.svg
│ │ │ │ ├── file-text.svg
│ │ │ │ ├── filter.svg
│ │ │ │ ├── folder.svg
│ │ │ │ ├── img.svg
│ │ │ │ ├── inspect.svg
│ │ │ │ ├── light_to_dark.svg
│ │ │ │ ├── moon.svg
│ │ │ │ ├── pdf.svg
│ │ │ │ ├── photo.svg
│ │ │ │ ├── share.svg
│ │ │ │ ├── stars.svg
│ │ │ │ ├── sun.svg
│ │ │ │ ├── trending-down.svg
│ │ │ │ ├── trending-level.svg
│ │ │ │ ├── trending-up.svg
│ │ │ │ ├── txt.svg
│ │ │ │ ├── unknown-file.svg
│ │ │ │ ├── unlink.svg
│ │ │ │ └── xls.svg
│ │ │ ├── TableDeleteColumnIcon.tsx
│ │ │ ├── TableDeleteRowIcon.tsx
│ │ │ ├── TableInsertColumnIcon.tsx
│ │ │ ├── TableInsertRowIcon.tsx
│ │ │ ├── TrashIcon.tsx
│ │ │ ├── TrendingDownIcon.tsx
│ │ │ ├── TrendingLevelIcon.tsx
│ │ │ ├── TrendingUpIcon.tsx
│ │ │ ├── TxtIcon.tsx
│ │ │ ├── UnknownFileIcon.tsx
│ │ │ ├── UnlinkIcon.tsx
│ │ │ ├── UserIcon.tsx
│ │ │ ├── WarningIcon.tsx
│ │ │ └── XlsIcon.tsx
│ │ ├── IconProvider.tsx
│ │ ├── IconRegistryContext.tsx
│ │ ├── IFrame
│ │ │ ├── IFrame.md
│ │ │ ├── IFrame.module.scss
│ │ │ ├── IFrame.spec.ts
│ │ │ ├── IFrame.tsx
│ │ │ └── IFrameNative.tsx
│ │ ├── Image
│ │ │ ├── Image.md
│ │ │ ├── Image.module.scss
│ │ │ ├── Image.spec.ts
│ │ │ ├── Image.tsx
│ │ │ └── ImageNative.tsx
│ │ ├── Input
│ │ │ ├── index.ts
│ │ │ ├── InputAdornment.module.scss
│ │ │ ├── InputAdornment.tsx
│ │ │ ├── InputDivider.module.scss
│ │ │ ├── InputDivider.tsx
│ │ │ ├── InputLabel.module.scss
│ │ │ ├── InputLabel.tsx
│ │ │ ├── PartialInput.module.scss
│ │ │ └── PartialInput.tsx
│ │ ├── InspectButton
│ │ │ ├── InspectButton.module.scss
│ │ │ └── InspectButton.tsx
│ │ ├── Items
│ │ │ ├── Items.md
│ │ │ ├── Items.spec.ts
│ │ │ ├── Items.tsx
│ │ │ └── ItemsNative.tsx
│ │ ├── Link
│ │ │ ├── Link.md
│ │ │ ├── Link.module.scss
│ │ │ ├── Link.spec.ts
│ │ │ ├── Link.tsx
│ │ │ └── LinkNative.tsx
│ │ ├── List
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── List.md
│ │ │ ├── List.module.scss
│ │ │ ├── List.spec.ts
│ │ │ ├── List.tsx
│ │ │ └── ListNative.tsx
│ │ ├── Logo
│ │ │ ├── doc-resources
│ │ │ │ └── xmlui-logo.svg
│ │ │ ├── Logo.md
│ │ │ ├── Logo.tsx
│ │ │ └── LogoNative.tsx
│ │ ├── Markdown
│ │ │ ├── CodeText.module.scss
│ │ │ ├── CodeText.tsx
│ │ │ ├── Markdown.md
│ │ │ ├── Markdown.module.scss
│ │ │ ├── Markdown.spec.ts
│ │ │ ├── Markdown.tsx
│ │ │ ├── MarkdownNative.tsx
│ │ │ ├── parse-binding-expr.ts
│ │ │ └── utils.ts
│ │ ├── metadata-helpers.ts
│ │ ├── ModalDialog
│ │ │ ├── ConfirmationModalContextProvider.tsx
│ │ │ ├── Dialog.module.scss
│ │ │ ├── Dialog.tsx
│ │ │ ├── ModalDialog.md
│ │ │ ├── ModalDialog.module.scss
│ │ │ ├── ModalDialog.spec.ts
│ │ │ ├── ModalDialog.tsx
│ │ │ ├── ModalDialogNative.tsx
│ │ │ └── ModalVisibilityContext.tsx
│ │ ├── NavGroup
│ │ │ ├── NavGroup.md
│ │ │ ├── NavGroup.module.scss
│ │ │ ├── NavGroup.spec.ts
│ │ │ ├── NavGroup.tsx
│ │ │ ├── NavGroupContext.ts
│ │ │ └── NavGroupNative.tsx
│ │ ├── NavLink
│ │ │ ├── NavLink.md
│ │ │ ├── NavLink.module.scss
│ │ │ ├── NavLink.spec.ts
│ │ │ ├── NavLink.tsx
│ │ │ └── NavLinkNative.tsx
│ │ ├── NavPanel
│ │ │ ├── NavPanel.md
│ │ │ ├── NavPanel.module.scss
│ │ │ ├── NavPanel.spec.ts
│ │ │ ├── NavPanel.tsx
│ │ │ └── NavPanelNative.tsx
│ │ ├── NestedApp
│ │ │ ├── AppWithCodeView.module.scss
│ │ │ ├── AppWithCodeView.tsx
│ │ │ ├── AppWithCodeViewNative.tsx
│ │ │ ├── defaultProps.tsx
│ │ │ ├── logo.svg
│ │ │ ├── NestedApp.module.scss
│ │ │ ├── NestedApp.tsx
│ │ │ ├── NestedAppNative.tsx
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.tsx
│ │ │ └── utils.ts
│ │ ├── NoResult
│ │ │ ├── NoResult.md
│ │ │ ├── NoResult.module.scss
│ │ │ ├── NoResult.spec.ts
│ │ │ ├── NoResult.tsx
│ │ │ └── NoResultNative.tsx
│ │ ├── NumberBox
│ │ │ ├── numberbox-abstractions.ts
│ │ │ ├── NumberBox.md
│ │ │ ├── NumberBox.module.scss
│ │ │ ├── NumberBox.spec.ts
│ │ │ ├── NumberBox.tsx
│ │ │ └── NumberBoxNative.tsx
│ │ ├── Option
│ │ │ ├── Option.md
│ │ │ ├── Option.spec.ts
│ │ │ ├── Option.tsx
│ │ │ ├── OptionNative.tsx
│ │ │ └── OptionTypeProvider.tsx
│ │ ├── PageMetaTitle
│ │ │ ├── PageMetaTilteNative.tsx
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── PageMetaTitle.spec.ts
│ │ │ └── PageMetaTitle.tsx
│ │ ├── Pages
│ │ │ ├── Page.md
│ │ │ ├── Pages.md
│ │ │ ├── Pages.module.scss
│ │ │ ├── Pages.tsx
│ │ │ └── PagesNative.tsx
│ │ ├── Pagination
│ │ │ ├── Pagination.md
│ │ │ ├── Pagination.module.scss
│ │ │ ├── Pagination.spec.ts
│ │ │ ├── Pagination.tsx
│ │ │ └── PaginationNative.tsx
│ │ ├── PositionedContainer
│ │ │ ├── PositionedContainer.module.scss
│ │ │ ├── PositionedContainer.tsx
│ │ │ └── PositionedContainerNative.tsx
│ │ ├── ProfileMenu
│ │ │ ├── ProfileMenu.module.scss
│ │ │ └── ProfileMenu.tsx
│ │ ├── ProgressBar
│ │ │ ├── ProgressBar.md
│ │ │ ├── ProgressBar.module.scss
│ │ │ ├── ProgressBar.spec.ts
│ │ │ ├── ProgressBar.tsx
│ │ │ └── ProgressBarNative.tsx
│ │ ├── Queue
│ │ │ ├── Queue.md
│ │ │ ├── Queue.spec.ts
│ │ │ ├── Queue.tsx
│ │ │ ├── queueActions.ts
│ │ │ └── QueueNative.tsx
│ │ ├── RadioGroup
│ │ │ ├── RadioGroup.md
│ │ │ ├── RadioGroup.module.scss
│ │ │ ├── RadioGroup.spec.ts
│ │ │ ├── RadioGroup.tsx
│ │ │ ├── RadioGroupNative.tsx
│ │ │ ├── RadioItem.tsx
│ │ │ └── RadioItemNative.tsx
│ │ ├── RealTimeAdapter
│ │ │ ├── RealTimeAdapter.tsx
│ │ │ └── RealTimeAdapterNative.tsx
│ │ ├── Redirect
│ │ │ ├── Redirect.md
│ │ │ ├── Redirect.spec.ts
│ │ │ └── Redirect.tsx
│ │ ├── ResponsiveBar
│ │ │ ├── README.md
│ │ │ ├── ResponsiveBar.md
│ │ │ ├── ResponsiveBar.module.scss
│ │ │ ├── ResponsiveBar.spec.ts
│ │ │ ├── ResponsiveBar.tsx
│ │ │ └── ResponsiveBarNative.tsx
│ │ ├── Select
│ │ │ ├── HiddenOption.tsx
│ │ │ ├── OptionContext.ts
│ │ │ ├── Select.md
│ │ │ ├── Select.module.scss
│ │ │ ├── Select.spec.ts
│ │ │ ├── Select.tsx
│ │ │ ├── SelectContext.tsx
│ │ │ └── SelectNative.tsx
│ │ ├── SelectionStore
│ │ │ ├── SelectionStore.md
│ │ │ ├── SelectionStore.tsx
│ │ │ └── SelectionStoreNative.tsx
│ │ ├── Slider
│ │ │ ├── Slider.md
│ │ │ ├── Slider.module.scss
│ │ │ ├── Slider.spec.ts
│ │ │ ├── Slider.tsx
│ │ │ └── SliderNative.tsx
│ │ ├── Slot
│ │ │ ├── Slot.md
│ │ │ ├── Slot.spec.ts
│ │ │ └── Slot.ts
│ │ ├── SlotItem.tsx
│ │ ├── SpaceFiller
│ │ │ ├── SpaceFiller.md
│ │ │ ├── SpaceFiller.module.scss
│ │ │ ├── SpaceFiller.spec.ts
│ │ │ ├── SpaceFiller.tsx
│ │ │ └── SpaceFillerNative.tsx
│ │ ├── Spinner
│ │ │ ├── Spinner.md
│ │ │ ├── Spinner.module.scss
│ │ │ ├── Spinner.spec.ts
│ │ │ ├── Spinner.tsx
│ │ │ └── SpinnerNative.tsx
│ │ ├── Splitter
│ │ │ ├── HSplitter.md
│ │ │ ├── HSplitter.spec.ts
│ │ │ ├── Splitter.md
│ │ │ ├── Splitter.module.scss
│ │ │ ├── Splitter.spec.ts
│ │ │ ├── Splitter.tsx
│ │ │ ├── SplitterNative.tsx
│ │ │ ├── utils.ts
│ │ │ ├── VSplitter.md
│ │ │ └── VSplitter.spec.ts
│ │ ├── Stack
│ │ │ ├── CHStack.md
│ │ │ ├── CHStack.spec.ts
│ │ │ ├── CVStack.md
│ │ │ ├── CVStack.spec.ts
│ │ │ ├── HStack.md
│ │ │ ├── HStack.spec.ts
│ │ │ ├── Stack.md
│ │ │ ├── Stack.module.scss
│ │ │ ├── Stack.spec.ts
│ │ │ ├── Stack.tsx
│ │ │ ├── StackNative.tsx
│ │ │ ├── VStack.md
│ │ │ └── VStack.spec.ts
│ │ ├── StickyBox
│ │ │ ├── StickyBox.md
│ │ │ ├── StickyBox.module.scss
│ │ │ ├── StickyBox.tsx
│ │ │ └── StickyBoxNative.tsx
│ │ ├── Switch
│ │ │ ├── Switch.md
│ │ │ ├── Switch.spec.ts
│ │ │ └── Switch.tsx
│ │ ├── Table
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── react-table-config.d.ts
│ │ │ ├── Table.md
│ │ │ ├── Table.module.scss
│ │ │ ├── Table.spec.ts
│ │ │ ├── Table.tsx
│ │ │ ├── TableNative.tsx
│ │ │ └── useRowSelection.tsx
│ │ ├── TableOfContents
│ │ │ ├── TableOfContents.module.scss
│ │ │ ├── TableOfContents.spec.ts
│ │ │ ├── TableOfContents.tsx
│ │ │ └── TableOfContentsNative.tsx
│ │ ├── Tabs
│ │ │ ├── TabContext.tsx
│ │ │ ├── TabItem.md
│ │ │ ├── TabItem.tsx
│ │ │ ├── TabItemNative.tsx
│ │ │ ├── Tabs.md
│ │ │ ├── Tabs.module.scss
│ │ │ ├── Tabs.spec.ts
│ │ │ ├── Tabs.tsx
│ │ │ └── TabsNative.tsx
│ │ ├── Text
│ │ │ ├── Text.md
│ │ │ ├── Text.module.scss
│ │ │ ├── Text.spec.ts
│ │ │ ├── Text.tsx
│ │ │ └── TextNative.tsx
│ │ ├── TextArea
│ │ │ ├── TextArea.md
│ │ │ ├── TextArea.module.scss
│ │ │ ├── TextArea.spec.ts
│ │ │ ├── TextArea.tsx
│ │ │ ├── TextAreaNative.tsx
│ │ │ ├── TextAreaResizable.tsx
│ │ │ └── useComposedRef.ts
│ │ ├── TextBox
│ │ │ ├── TextBox.md
│ │ │ ├── TextBox.module.scss
│ │ │ ├── TextBox.spec.ts
│ │ │ ├── TextBox.tsx
│ │ │ └── TextBoxNative.tsx
│ │ ├── Theme
│ │ │ ├── NotificationToast.tsx
│ │ │ ├── Theme.md
│ │ │ ├── Theme.module.scss
│ │ │ ├── Theme.spec.ts
│ │ │ ├── Theme.tsx
│ │ │ └── ThemeNative.tsx
│ │ ├── TimeInput
│ │ │ ├── TimeInput.md
│ │ │ ├── TimeInput.module.scss
│ │ │ ├── TimeInput.spec.ts
│ │ │ ├── TimeInput.tsx
│ │ │ ├── TimeInputNative.tsx
│ │ │ └── utils.ts
│ │ ├── Timer
│ │ │ ├── Timer.md
│ │ │ ├── Timer.spec.ts
│ │ │ ├── Timer.tsx
│ │ │ └── TimerNative.tsx
│ │ ├── Toggle
│ │ │ ├── Toggle.module.scss
│ │ │ └── Toggle.tsx
│ │ ├── ToneChangerButton
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneChangerButton.spec.ts
│ │ │ └── ToneChangerButton.tsx
│ │ ├── ToneSwitch
│ │ │ ├── ToneSwitch.md
│ │ │ ├── ToneSwitch.module.scss
│ │ │ ├── ToneSwitch.spec.ts
│ │ │ ├── ToneSwitch.tsx
│ │ │ └── ToneSwitchNative.tsx
│ │ ├── Tooltip
│ │ │ ├── Tooltip.md
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.spec.ts
│ │ │ ├── Tooltip.tsx
│ │ │ └── TooltipNative.tsx
│ │ ├── Tree
│ │ │ ├── testData.ts
│ │ │ ├── Tree-dynamic.spec.ts
│ │ │ ├── Tree-icons.spec.ts
│ │ │ ├── Tree.md
│ │ │ ├── Tree.spec.ts
│ │ │ ├── TreeComponent.module.scss
│ │ │ ├── TreeComponent.tsx
│ │ │ └── TreeNative.tsx
│ │ ├── TreeDisplay
│ │ │ ├── TreeDisplay.md
│ │ │ ├── TreeDisplay.module.scss
│ │ │ ├── TreeDisplay.tsx
│ │ │ └── TreeDisplayNative.tsx
│ │ ├── ValidationSummary
│ │ │ ├── ValidationSummary.module.scss
│ │ │ └── ValidationSummary.tsx
│ │ └── VisuallyHidden.tsx
│ ├── components-core
│ │ ├── abstractions
│ │ │ ├── ComponentRenderer.ts
│ │ │ ├── LoaderRenderer.ts
│ │ │ ├── standalone.ts
│ │ │ └── treeAbstractions.ts
│ │ ├── action
│ │ │ ├── actions.ts
│ │ │ ├── APICall.tsx
│ │ │ ├── FileDownloadAction.tsx
│ │ │ ├── FileUploadAction.tsx
│ │ │ ├── NavigateAction.tsx
│ │ │ └── TimedAction.tsx
│ │ ├── ApiBoundComponent.tsx
│ │ ├── appContext
│ │ │ ├── date-functions.ts
│ │ │ ├── math-function.ts
│ │ │ └── misc-utils.ts
│ │ ├── AppContext.tsx
│ │ ├── behaviors
│ │ │ ├── Behavior.tsx
│ │ │ └── CoreBehaviors.tsx
│ │ ├── component-hooks.ts
│ │ ├── ComponentDecorator.tsx
│ │ ├── ComponentViewer.tsx
│ │ ├── CompoundComponent.tsx
│ │ ├── constants.ts
│ │ ├── DebugViewProvider.tsx
│ │ ├── descriptorHelper.ts
│ │ ├── devtools
│ │ │ ├── InspectorDialog.module.scss
│ │ │ ├── InspectorDialog.tsx
│ │ │ └── InspectorDialogVisibilityContext.tsx
│ │ ├── EngineError.ts
│ │ ├── event-handlers.ts
│ │ ├── InspectorButton.module.scss
│ │ ├── InspectorContext.tsx
│ │ ├── interception
│ │ │ ├── abstractions.ts
│ │ │ ├── ApiInterceptor.ts
│ │ │ ├── ApiInterceptorProvider.tsx
│ │ │ ├── apiInterceptorWorker.ts
│ │ │ ├── Backend.ts
│ │ │ ├── Errors.ts
│ │ │ ├── IndexedDb.ts
│ │ │ ├── initMock.ts
│ │ │ ├── InMemoryDb.ts
│ │ │ ├── ReadonlyCollection.ts
│ │ │ └── useApiInterceptorContext.tsx
│ │ ├── loader
│ │ │ ├── ApiLoader.tsx
│ │ │ ├── DataLoader.tsx
│ │ │ ├── ExternalDataLoader.tsx
│ │ │ ├── Loader.tsx
│ │ │ ├── MockLoaderRenderer.tsx
│ │ │ └── PageableLoader.tsx
│ │ ├── LoaderComponent.tsx
│ │ ├── markup-check.ts
│ │ ├── parts.ts
│ │ ├── renderers.ts
│ │ ├── rendering
│ │ │ ├── AppContent.tsx
│ │ │ ├── AppRoot.tsx
│ │ │ ├── AppWrapper.tsx
│ │ │ ├── buildProxy.ts
│ │ │ ├── collectFnVarDeps.ts
│ │ │ ├── ComponentAdapter.tsx
│ │ │ ├── ComponentWrapper.tsx
│ │ │ ├── Container.tsx
│ │ │ ├── containers.ts
│ │ │ ├── ContainerWrapper.tsx
│ │ │ ├── ErrorBoundary.module.scss
│ │ │ ├── ErrorBoundary.tsx
│ │ │ ├── InvalidComponent.module.scss
│ │ │ ├── InvalidComponent.tsx
│ │ │ ├── nodeUtils.ts
│ │ │ ├── reducer.ts
│ │ │ ├── renderChild.tsx
│ │ │ ├── StandaloneComponent.tsx
│ │ │ ├── StateContainer.tsx
│ │ │ ├── UnknownComponent.module.scss
│ │ │ ├── UnknownComponent.tsx
│ │ │ └── valueExtractor.ts
│ │ ├── reportEngineError.ts
│ │ ├── RestApiProxy.ts
│ │ ├── script-runner
│ │ │ ├── asyncProxy.ts
│ │ │ ├── AttributeValueParser.ts
│ │ │ ├── bannedFunctions.ts
│ │ │ ├── BindingTreeEvaluationContext.ts
│ │ │ ├── eval-tree-async.ts
│ │ │ ├── eval-tree-common.ts
│ │ │ ├── eval-tree-sync.ts
│ │ │ ├── ParameterParser.ts
│ │ │ ├── process-statement-async.ts
│ │ │ ├── process-statement-common.ts
│ │ │ ├── process-statement-sync.ts
│ │ │ ├── ScriptingSourceTree.ts
│ │ │ ├── simplify-expression.ts
│ │ │ ├── statement-queue.ts
│ │ │ └── visitors.ts
│ │ ├── StandaloneApp.tsx
│ │ ├── StandaloneExtensionManager.ts
│ │ ├── TableOfContentsContext.tsx
│ │ ├── theming
│ │ │ ├── _themes.scss
│ │ │ ├── component-layout-resolver.ts
│ │ │ ├── extendThemeUtils.ts
│ │ │ ├── hvar.ts
│ │ │ ├── layout-resolver.ts
│ │ │ ├── parse-layout-props.ts
│ │ │ ├── StyleContext.tsx
│ │ │ ├── StyleRegistry.ts
│ │ │ ├── ThemeContext.tsx
│ │ │ ├── ThemeProvider.tsx
│ │ │ ├── themes
│ │ │ │ ├── base-utils.ts
│ │ │ │ ├── palette.ts
│ │ │ │ ├── root.ts
│ │ │ │ ├── solid.ts
│ │ │ │ ├── theme-colors.ts
│ │ │ │ └── xmlui.ts
│ │ │ ├── themeVars.module.scss
│ │ │ ├── themeVars.ts
│ │ │ ├── transformThemeVars.ts
│ │ │ └── utils.ts
│ │ ├── utils
│ │ │ ├── actionUtils.ts
│ │ │ ├── audio-utils.ts
│ │ │ ├── base64-utils.ts
│ │ │ ├── compound-utils.ts
│ │ │ ├── css-utils.ts
│ │ │ ├── DataLoaderQueryKeyGenerator.ts
│ │ │ ├── date-utils.ts
│ │ │ ├── extractParam.ts
│ │ │ ├── hooks.tsx
│ │ │ ├── LruCache.ts
│ │ │ ├── mergeProps.ts
│ │ │ ├── misc.ts
│ │ │ ├── request-params.ts
│ │ │ ├── statementUtils.ts
│ │ │ └── treeUtils.ts
│ │ └── xmlui-parser.ts
│ ├── index-standalone.ts
│ ├── index.scss
│ ├── index.ts
│ ├── language-server
│ │ ├── server-common.ts
│ │ ├── server-web-worker.ts
│ │ ├── server.ts
│ │ ├── services
│ │ │ ├── common
│ │ │ │ ├── docs-generation.ts
│ │ │ │ ├── lsp-utils.ts
│ │ │ │ ├── metadata-utils.ts
│ │ │ │ └── syntax-node-utilities.ts
│ │ │ ├── completion.ts
│ │ │ ├── diagnostic.ts
│ │ │ ├── format.ts
│ │ │ └── hover.ts
│ │ └── xmlui-metadata-generated.js
│ ├── logging
│ │ ├── LoggerContext.tsx
│ │ ├── LoggerInitializer.tsx
│ │ ├── LoggerService.ts
│ │ └── xmlui.ts
│ ├── logo.svg
│ ├── parsers
│ │ ├── common
│ │ │ ├── GenericToken.ts
│ │ │ ├── InputStream.ts
│ │ │ └── utils.ts
│ │ ├── scripting
│ │ │ ├── code-behind-collect.ts
│ │ │ ├── Lexer.ts
│ │ │ ├── modules.ts
│ │ │ ├── Parser.ts
│ │ │ ├── ParserError.ts
│ │ │ ├── ScriptingNodeTypes.ts
│ │ │ ├── TokenTrait.ts
│ │ │ ├── TokenType.ts
│ │ │ └── tree-visitor.ts
│ │ ├── style-parser
│ │ │ ├── errors.ts
│ │ │ ├── source-tree.ts
│ │ │ ├── StyleInputStream.ts
│ │ │ ├── StyleLexer.ts
│ │ │ ├── StyleParser.ts
│ │ │ └── tokens.ts
│ │ └── xmlui-parser
│ │ ├── CharacterCodes.ts
│ │ ├── diagnostics.ts
│ │ ├── fileExtensions.ts
│ │ ├── index.ts
│ │ ├── lint.ts
│ │ ├── parser.ts
│ │ ├── ParserError.ts
│ │ ├── scanner.ts
│ │ ├── syntax-kind.ts
│ │ ├── syntax-node.ts
│ │ ├── transform.ts
│ │ ├── utils.ts
│ │ ├── xmlui-serializer.ts
│ │ └── xmlui-tree.ts
│ ├── react-app-env.d.ts
│ ├── syntax
│ │ ├── monaco
│ │ │ ├── grammar.monacoLanguage.ts
│ │ │ ├── index.ts
│ │ │ ├── xmlui-dark.ts
│ │ │ ├── xmlui-light.ts
│ │ │ └── xmluiscript.monacoLanguage.ts
│ │ └── textMate
│ │ ├── index.ts
│ │ ├── xmlui-dark.json
│ │ ├── xmlui-light.json
│ │ ├── xmlui.json
│ │ └── xmlui.tmLanguage.json
│ ├── testing
│ │ ├── assertions.ts
│ │ ├── component-test-helpers.ts
│ │ ├── ComponentDrivers.ts
│ │ ├── drivers
│ │ │ ├── DateInputDriver.ts
│ │ │ ├── index.ts
│ │ │ ├── ModalDialogDriver.ts
│ │ │ ├── NumberBoxDriver.ts
│ │ │ ├── TextBoxDriver.ts
│ │ │ ├── TimeInputDriver.ts
│ │ │ ├── TimerDriver.ts
│ │ │ └── TreeDriver.ts
│ │ ├── fixtures.ts
│ │ ├── index.ts
│ │ ├── infrastructure
│ │ │ ├── index.html
│ │ │ ├── main.tsx
│ │ │ ├── public
│ │ │ │ ├── mockServiceWorker.js
│ │ │ │ ├── resources
│ │ │ │ │ ├── bell.svg
│ │ │ │ │ ├── box.svg
│ │ │ │ │ ├── doc.svg
│ │ │ │ │ ├── eye.svg
│ │ │ │ │ ├── flower-640x480.jpg
│ │ │ │ │ ├── sun.svg
│ │ │ │ │ ├── test-image-100x100.jpg
│ │ │ │ │ └── txt.svg
│ │ │ │ └── serve.json
│ │ │ └── TestBed.tsx
│ │ └── themed-app-test-helpers.ts
│ └── vite-env.d.ts
├── tests
│ ├── components
│ │ ├── CodeBlock
│ │ │ └── hightlight-code.test.ts
│ │ ├── playground-pattern.test.ts
│ │ └── Tree
│ │ └── Tree-states.test.ts
│ ├── components-core
│ │ ├── abstractions
│ │ │ └── treeAbstractions.test.ts
│ │ ├── container
│ │ │ └── buildProxy.test.ts
│ │ ├── interception
│ │ │ ├── orderBy.test.ts
│ │ │ ├── ReadOnlyCollection.test.ts
│ │ │ └── request-param-converter.test.ts
│ │ ├── scripts-runner
│ │ │ ├── AttributeValueParser.test.ts
│ │ │ ├── eval-tree-arrow-async.test.ts
│ │ │ ├── eval-tree-arrow.test.ts
│ │ │ ├── eval-tree-func-decl-async.test.ts
│ │ │ ├── eval-tree-func-decl.test.ts
│ │ │ ├── eval-tree-pre-post.test.ts
│ │ │ ├── eval-tree-regression.test.ts
│ │ │ ├── eval-tree.test.ts
│ │ │ ├── function-proxy.test.ts
│ │ │ ├── parser-regression.test.ts
│ │ │ ├── process-event.test.ts
│ │ │ ├── process-function.test.ts
│ │ │ ├── process-implicit-context.test.ts
│ │ │ ├── process-statement-asgn.test.ts
│ │ │ ├── process-statement-destruct.test.ts
│ │ │ ├── process-statement-regs.test.ts
│ │ │ ├── process-statement-sync.test.ts
│ │ │ ├── process-statement.test.ts
│ │ │ ├── process-switch-sync.test.ts
│ │ │ ├── process-switch.test.ts
│ │ │ ├── process-try-sync.test.ts
│ │ │ ├── process-try.test.ts
│ │ │ └── test-helpers.ts
│ │ ├── test-metadata-handler.ts
│ │ ├── theming
│ │ │ ├── border-segments.test.ts
│ │ │ ├── component-layout.resolver.test.ts
│ │ │ ├── layout-property-parser.test.ts
│ │ │ ├── layout-resolver.test.ts
│ │ │ ├── layout-resolver2.test.ts
│ │ │ ├── layout-vp-override.test.ts
│ │ │ └── padding-segments.test.ts
│ │ └── utils
│ │ ├── date-utils.test.ts
│ │ ├── format-human-elapsed-time.test.ts
│ │ └── LruCache.test.ts
│ ├── language-server
│ │ ├── completion.test.ts
│ │ ├── format.test.ts
│ │ ├── hover.test.ts
│ │ └── mockData.ts
│ └── parsers
│ ├── common
│ │ └── input-stream.test.ts
│ ├── markdown
│ │ └── parse-binding-expression.test.ts
│ ├── parameter-parser.test.ts
│ ├── paremeter-parser.test.ts
│ ├── scripting
│ │ ├── eval-tree-arrow.test.ts
│ │ ├── eval-tree-pre-post.test.ts
│ │ ├── eval-tree.test.ts
│ │ ├── function-proxy.test.ts
│ │ ├── lexer-literals.test.ts
│ │ ├── lexer-misc.test.ts
│ │ ├── module-parse.test.ts
│ │ ├── parser-arrow.test.ts
│ │ ├── parser-assignments.test.ts
│ │ ├── parser-binary.test.ts
│ │ ├── parser-destructuring.test.ts
│ │ ├── parser-errors.test.ts
│ │ ├── parser-expressions.test.ts
│ │ ├── parser-function.test.ts
│ │ ├── parser-literals.test.ts
│ │ ├── parser-primary.test.ts
│ │ ├── parser-regex.test.ts
│ │ ├── parser-statements.test.ts
│ │ ├── parser-unary.test.ts
│ │ ├── process-event.test.ts
│ │ ├── process-implicit-context.test.ts
│ │ ├── process-statement-asgn.test.ts
│ │ ├── process-statement-destruct.test.ts
│ │ ├── process-statement-regs.test.ts
│ │ ├── process-statement-sync.test.ts
│ │ ├── process-statement.test.ts
│ │ ├── process-switch-sync.test.ts
│ │ ├── process-switch.test.ts
│ │ ├── process-try-sync.test.ts
│ │ ├── process-try.test.ts
│ │ ├── simplify-expression.test.ts
│ │ ├── statement-hooks.test.ts
│ │ └── test-helpers.ts
│ ├── style-parser
│ │ ├── generateHvarChain.test.ts
│ │ ├── parseHVar.test.ts
│ │ ├── parser.test.ts
│ │ └── tokens.test.ts
│ └── xmlui
│ ├── lint.test.ts
│ ├── parser.test.ts
│ ├── scanner.test.ts
│ ├── transform.attr.test.ts
│ ├── transform.circular.test.ts
│ ├── transform.element.test.ts
│ ├── transform.errors.test.ts
│ ├── transform.escape.test.ts
│ ├── transform.regression.test.ts
│ ├── transform.script.test.ts
│ ├── transform.test.ts
│ └── xmlui.ts
├── tests-e2e
│ ├── api-bound-component-regression.spec.ts
│ ├── api-call-as-extracted-component.spec.ts
│ ├── assign-to-object-or-array-regression.spec.ts
│ ├── binding-regression.spec.ts
│ ├── children-as-template-context-vars.spec.ts
│ ├── compound-component.spec.ts
│ ├── context-vars-regression.spec.ts
│ ├── data-bindings.spec.ts
│ ├── datasource-and-api-usage-in-var.spec.ts
│ ├── datasource-direct-binding.spec.ts
│ ├── datasource-onLoaded-regression.spec.ts
│ ├── modify-array-item-regression.spec.ts
│ ├── namespaces.spec.ts
│ ├── push-to-array-regression.spec.ts
│ ├── screen-breakpoints.spec.ts
│ ├── scripting.spec.ts
│ ├── state-scope-in-pages.spec.ts
│ └── state-var-scopes.spec.ts
├── tsconfig.json
├── tsdown.config.ts
├── vite.config.ts
└── vitest.config.ts
```
# Files
--------------------------------------------------------------------------------
/xmlui/src/components/AutoComplete/AutoComplete.module.scss:
--------------------------------------------------------------------------------
```scss
@use "../../components-core/theming/themes" as t;
// --- This code snippet is required to collect the theme variables used in this module
$themeVars: (
);
@function createThemeVar($componentVariable) {
$themeVars: t.appendThemeVar($themeVars, $componentVariable) !global;
@return t.getThemeVar($themeVars, $componentVariable);
}
$component: "AutoComplete";
$themeVars: t.composeBorderVars($themeVars, $component);
$themeVars: t.composePaddingVars($themeVars, $component);
$themeVars: t.composePaddingVars($themeVars, "item-#{$component}");
// Variables for default variant
$borderRadius-AutoComplete--default: createThemeVar("Input:borderRadius-#{$component}--default");
$borderColor-AutoComplete--default: createThemeVar("Input:borderColor-#{$component}--default");
$borderWidth-AutoComplete--default: createThemeVar("Input:borderWidth-#{$component}--default");
$borderStyle-AutoComplete--default: createThemeVar("Input:borderStyle-#{$component}--default");
$fontSize-AutoComplete--default: createThemeVar("Input:fontSize-#{$component}--default");
$backgroundColor-AutoComplete--default: createThemeVar("Input:backgroundColor-#{$component}--default");
$boxShadow-AutoComplete--default: createThemeVar("Input:boxShadow-#{$component}--default");
$textColor-AutoComplete--default: createThemeVar("Input:textColor-#{$component}--default");
$borderColor-AutoComplete--default--hover: createThemeVar("Input:borderColor-#{$component}--default--hover");
$backgroundColor-AutoComplete--default--hover: createThemeVar("Input:backgroundColor-#{$component}--default--hover");
$boxShadow-AutoComplete--default--hover: createThemeVar("Input:boxShadow-#{$component}--default--hover");
$textColor-AutoComplete--default--hover: createThemeVar("Input:textColor-#{$component}--default--hover");
$textColor-placeholder-AutoComplete--default: createThemeVar("Input:textColor-placeholder-#{$component}--default");
$fontSize-placeholder-AutoComplete--default: createThemeVar("Input:fontSize-placeholder-#{$component}--default");
// Variables for error variant
$borderRadius-AutoComplete--error: createThemeVar("Input:borderRadius-#{$component}--error");
$borderColor-AutoComplete--error: createThemeVar("Input:borderColor-#{$component}--error");
$borderWidth-AutoComplete--error: createThemeVar("Input:borderWidth-#{$component}--error");
$borderStyle-AutoComplete--error: createThemeVar("Input:borderStyle-#{$component}--error");
$fontSize-AutoComplete--error: createThemeVar("Input:fontSize-#{$component}--error");
$backgroundColor-AutoComplete--error: createThemeVar("Input:backgroundColor-#{$component}--error");
$boxShadow-AutoComplete--error: createThemeVar("Input:boxShadow-#{$component}--error");
$textColor-AutoComplete--error: createThemeVar("Input:textColor-#{$component}--error");
$borderColor-AutoComplete--error--hover: createThemeVar("Input:borderColor-#{$component}--error--hover");
$backgroundColor-AutoComplete--error--hover: createThemeVar("Input:backgroundColor-#{$component}--error--hover");
$boxShadow-AutoComplete--error--hover: createThemeVar("Input:boxShadow-#{$component}--error--hover");
$textColor-AutoComplete--error--hover: createThemeVar("Input:textColor-#{$component}--error--hover");
$textColor-placeholder-AutoComplete--error: createThemeVar("Input:textColor-placeholder-#{$component}--error");
$fontSize-placeholder-AutoComplete--error: createThemeVar("Input:fontSize-placeholder-#{$component}--error");
// Variables for warning variant
$borderRadius-AutoComplete--warning: createThemeVar("Input:borderRadius-#{$component}--warning");
$borderColor-AutoComplete--warning: createThemeVar("Input:borderColor-#{$component}--warning");
$borderWidth-AutoComplete--warning: createThemeVar("Input:borderWidth-#{$component}--warning");
$borderStyle-AutoComplete--warning: createThemeVar("Input:borderStyle-#{$component}--warning");
$fontSize-AutoComplete--warning: createThemeVar("Input:fontSize-#{$component}--warning");
$backgroundColor-AutoComplete--warning: createThemeVar("Input:backgroundColor-#{$component}--warning");
$boxShadow-AutoComplete--warning: createThemeVar("Input:boxShadow-#{$component}--warning");
$textColor-AutoComplete--warning: createThemeVar("Input:textColor-#{$component}--warning");
$borderColor-AutoComplete--warning--hover: createThemeVar("Input:borderColor-#{$component}--warning--hover");
$backgroundColor-AutoComplete--warning--hover: createThemeVar("Input:backgroundColor-#{$component}--warning--hover");
$boxShadow-AutoComplete--warning--hover: createThemeVar("Input:boxShadow-#{$component}--warning--hover");
$textColor-AutoComplete--warning--hover: createThemeVar("Input:textColor-#{$component}--warning--hover");
$textColor-placeholder-AutoComplete--warning: createThemeVar("Input:textColor-placeholder-#{$component}--warning");
$fontSize-placeholder-AutoComplete--warning: createThemeVar("Input:fontSize-placeholder-#{$component}--warning");
// Variables for success variant
$borderRadius-AutoComplete--success: createThemeVar("Input:borderRadius-#{$component}--success");
$borderColor-AutoComplete--success: createThemeVar("Input:borderColor-#{$component}--success");
$borderWidth-AutoComplete--success: createThemeVar("Input:borderWidth-#{$component}--success");
$borderStyle-AutoComplete--success: createThemeVar("Input:borderStyle-#{$component}--success");
$fontSize-AutoComplete--success: createThemeVar("Input:fontSize-#{$component}--success");
$backgroundColor-AutoComplete--success: createThemeVar("Input:backgroundColor-#{$component}--success");
$boxShadow-AutoComplete--success: createThemeVar("Input:boxShadow-#{$component}--success");
$textColor-AutoComplete--success: createThemeVar("Input:textColor-#{$component}--success");
$borderColor-AutoComplete--success--hover: createThemeVar("Input:borderColor-#{$component}--success--hover");
$backgroundColor-AutoComplete--success--hover: createThemeVar("Input:backgroundColor-#{$component}--success--hover");
$boxShadow-AutoComplete--success--hover: createThemeVar("Input:boxShadow-#{$component}--success--hover");
$textColor-AutoComplete--success--hover: createThemeVar("Input:textColor-#{$component}--success--hover");
$textColor-placeholder-AutoComplete--success: createThemeVar("Input:textColor-placeholder-#{$component}--success");
$fontSize-placeholder-AutoComplete--success: createThemeVar("Input:fontSize-placeholder-#{$component}--success");
// Variables for @layer section
$gap-adornment-AutoComplete: createThemeVar("Input:gap-adornment-#{$component}");
$backgroundColor-AutoComplete--disabled: createThemeVar("Input:backgroundColor-#{$component}--disabled");
$textColor-AutoComplete--disabled: createThemeVar("Input:textColor-#{$component}--disabled");
$borderColor-AutoComplete--disabled: createThemeVar("Input:borderColor-#{$component}--disabled");
$outlineWidth-AutoComplete--focus: createThemeVar("Input:outlineWidth-#{$component}--focus");
$outlineColor-AutoComplete--focus: createThemeVar("Input:outlineColor-#{$component}--focus");
$outlineStyle-AutoComplete--focus: createThemeVar("Input:outlineStyle-#{$component}--focus");
$outlineOffset-AutoComplete--focus: createThemeVar("Input:outlineOffset-#{$component}--focus");
$paddingVertical-AutoComplete-badge: createThemeVar("paddingVertical-#{$component}-badge");
$paddingHorizontal-AutoComplete-badge: createThemeVar("paddingHorizontal-#{$component}-badge");
$borderRadius-AutoComplete-badge: createThemeVar("borderRadius-#{$component}-badge");
$fontSize-AutoComplete-badge: createThemeVar("Input:fontSize-#{$component}-badge");
$backgroundColor-AutoComplete-badge: createThemeVar("Input:backgroundColor-#{$component}-badge");
$textColor-AutoComplete-badge: createThemeVar("Input:textColor-#{$component}-badge");
$backgroundColor-AutoComplete-badge--hover: createThemeVar("Input:backgroundColor-#{$component}-badge--hover");
$textColor-AutoComplete-badge--hover: createThemeVar("Input:textColor-#{$component}-badge--hover");
$backgroundColor-AutoComplete-badge--active: createThemeVar("Input:backgroundColor-#{$component}-badge--active");
$textColor-AutoComplete-badge--active: createThemeVar("Input:textColor-#{$component}-badge--active");
$textColor-placeholder-AutoComplete: createThemeVar("Input:textColor-placeholder-#{$component}");
$borderRadius-menu-AutoComplete: createThemeVar("Input:borderRadius-menu-#{$component}");
$borderWidth-menu-AutoComplete: createThemeVar("Input:borderWidth-menu-#{$component}");
$borderColor-menu-AutoComplete: createThemeVar("Input:borderColor-menu-#{$component}");
$backgroundColor-menu-AutoComplete: createThemeVar("Input:backgroundColor-menu-#{$component}");
$boxShadow-menu-AutoComplete: createThemeVar("Input:boxShadow-menu-#{$component}");
$backgroundColor-item-AutoComplete: createThemeVar("backgroundColor-item-#{$component}");
$backgroundColor-item-AutoComplete--active: createThemeVar("backgroundColor-item-#{$component}--active");
$backgroundColor-item-AutoComplete--hover: createThemeVar("backgroundColor-item-#{$component}--hover");
$textColor-item-AutoComplete--disabled: createThemeVar("textColor-item-#{$component}--disabled");
// --- CSS properties of a particular AutoComplete variant
@mixin variant($variantName) {
border-radius: createThemeVar("Input:borderRadius-#{$component}--#{$variantName}");
border-color: createThemeVar("Input:borderColor-#{$component}--#{$variantName}");
border-width: createThemeVar("Input:borderWidth-#{$component}--#{$variantName}");
border-style: createThemeVar("Input:borderStyle-#{$component}--#{$variantName}");
font-size: createThemeVar("Input:fontSize-#{$component}--#{$variantName}");
background-color: createThemeVar("Input:backgroundColor-#{$component}--#{$variantName}");
box-shadow: createThemeVar("Input:boxShadow-#{$component}--#{$variantName}");
color: createThemeVar("Input:textColor-#{$component}--#{$variantName}");
&:hover {
border-color: createThemeVar("Input:borderColor-#{$component}--#{$variantName}--hover");
background-color: createThemeVar("Input:backgroundColor-#{$component}--#{$variantName}--hover");
box-shadow: createThemeVar("Input:boxShadow-#{$component}--#{$variantName}--hover");
color: createThemeVar("Input:textColor-#{$component}--#{$variantName}--hover");
}
&::placeholder {
color: createThemeVar("Input:textColor-placeholder-#{$component}--#{$variantName}");
font-size: createThemeVar("Input:fontSize-placeholder-#{$component}--#{$variantName}");
}
}
@layer components {
.command {
width: 100%;
height: auto;
overflow: visible;
background-color: transparent;
}
.badgeListWrapper {
outline: none;
width: 100%;
gap: t.$space-1;
display: flex;
flex-direction: row;
flex-wrap: wrap;
@include t.paddingVars($themeVars, $component);
@include variant("default");
&.error {
@include variant("error");
}
&.warning {
@include variant("warning");
}
&.valid {
@include variant("success");
}
&.disabled {
cursor: not-allowed;
opacity: 0.5;
background-color: $backgroundColor-AutoComplete--disabled;
color: $textColor-AutoComplete--disabled;
border-color: $borderColor-AutoComplete--disabled;
}
&.focused {
outline-width: $outlineWidth-AutoComplete--focus;
outline-color: $outlineColor-AutoComplete--focus;
outline-style: $outlineStyle-AutoComplete--focus;
outline-offset: $outlineOffset-AutoComplete--focus;
}
}
.badgeList {
position: relative;
align-items: center;
display: flex;
flex-wrap: wrap;
gap: 0.25rem;
}
.inputWrapper {
display: flex;
align-items: center;
min-width: fit-content;
flex: 1;
gap: t.$space-1;
}
.badge {
width: fit-content;
height: fit-content;
min-width: 0;
padding: $paddingVertical-AutoComplete-badge $paddingHorizontal-AutoComplete-badge;
border-radius: $borderRadius-AutoComplete-badge;
transition:
color 0.2s,
background-color 0.2s;
user-select: none;
cursor: pointer;
display: flex;
gap: t.$space-1;
justify-content: center;
align-items: center;
font-size: $fontSize-AutoComplete-badge;
background-color: $backgroundColor-AutoComplete-badge;
color: $textColor-AutoComplete-badge;
&:hover {
background-color: $backgroundColor-AutoComplete-badge--hover;
color: $textColor-AutoComplete-badge--hover;
}
&:active {
background-color: $backgroundColor-AutoComplete-badge--active;
color: $textColor-AutoComplete-badge--active;
}
}
.commandInput {
width: 100%;
background-color: transparent;
outline: none;
&:disabled {
cursor: not-allowed;
opacity: 0.5;
}
&::placeholder {
color: $textColor-placeholder-AutoComplete;
}
&:focus-within {
outline: none;
}
}
.actions {
display: flex;
align-items: center;
flex-shrink: 0;
}
.action {
cursor: pointer;
}
.autoCompleteEmpty {
display: flex;
gap: 0.2rem;
padding: 10px 0;
justify-content: center;
align-items: center;
font-size: 14px;
width: 100%;
}
.commandList {
width: 100%;
position: absolute;
overflow: hidden;
top: t.$space-1;
z-index: 999;
outline: none;
border-radius: $borderRadius-menu-AutoComplete;
border: $borderWidth-menu-AutoComplete solid $borderColor-menu-AutoComplete;
background-color: $backgroundColor-menu-AutoComplete;
box-shadow: $boxShadow-menu-AutoComplete;
animation: fade-in 0.3s ease-in-out;
}
.autoCompleteOption {
@include t.paddingVars($themeVars, "item-#{$component}");
display: flex;
gap: t.$space-1;
align-items: center;
justify-content: space-between;
cursor: pointer;
transition: background-color 0.2s ease;
background-color: $backgroundColor-item-AutoComplete;
&[aria-selected="true"] {
background-color: $backgroundColor-item-AutoComplete--active;
}
&:hover,
&.highlighted {
background-color: $backgroundColor-item-AutoComplete--hover;
}
&[aria-disabled="true"],
&.disabledOption {
pointer-events: none;
cursor: not-allowed;
color: $textColor-item-AutoComplete--disabled;
font-style: italic;
}
}
}
// --- We export the theme variables to add them to the component renderer
:export {
themeVars: t.json-stringify($themeVars);
}
```
--------------------------------------------------------------------------------
/docs/content/components/Tabs.md:
--------------------------------------------------------------------------------
```markdown
# Tabs [#tabs]
`Tabs` enables users to switch among content panels using clickable tab headers. It provides an efficient way to present multiple related sections in a single interface area, with each tab containing distinct content defined by [TabItem](/components/TabItem) components.
**Key features:**
- **Content organization**: Efficiently displays multiple content sections in a single interface area
- **Flexible orientation**: Supports both horizontal (tabs on top) and vertical (tabs on side) layouts
- **Active tab control**: Programmatically set which tab is initially selected
- **Custom header templates**: Configurable tab appearance via `headerTemplate` property
- **Navigation methods**: Built-in methods for programmatic tab switching (`next()`, `prev()`, `setActiveTabIndex()`, `setActiveTabById()`)
- **External ID support**: Optional `id` prop for TabItems with context exposure
- **Dynamic content**: Works seamlessly with `Items` for data-driven tabs
## Using Tabs [#using-tabs]
The component accepts only [TabItem](/components/TabItem) components as children. Other child components will not be displayed. Each [TabItem](/components/TabItem) has a `label` property for the tab button text, with content provided by placing child components within the [TabItem](/components/TabItem).
```xmlui-pg copy display name="Example: using Tabs" height="200px"
<App>
<Tabs>
<TabItem label="Account">
<Text>Account</Text>
</TabItem>
<TabItem label="Stream">
<Text>Stream</Text>
</TabItem>
<TabItem label="Support">
<Text>Support</Text>
</TabItem>
</Tabs>
</App>
```
## Dynamic Tabs [#dynamic-tabs]
You can create `TabItem` children dynamically:
```xmlui-pg copy display name="Example: using Tabs with dynamic items" height="200px"
<App>
<Tabs>
<Items data="{[1, 2, 3, 4]}">
<TabItem label="Account {$item}">
<Card title="Tab Content for Account {$item}"/>
</TabItem>
</Items>
</Tabs>
</App>
```
## Properties [#properties]
### `accordionView` (default: false) [#accordionview-default-false]
When enabled, displays tabs in an accordion-like view where tab headers are stacked vertically and only the active tab's content is visible. Each tab header remains visible and clicking a header opens its content while closing others. When enabled, the orientation property is ignored.
The `accordionView` property enables an accordion-like layout where tab headers are stacked vertically and only the active tab's content is visible. All tab headers remain visible, and clicking a header opens its content while closing others.
> [!NOTE] When `accordionView` is enabled, the `orientation` property is ignored.
```xmlui-pg copy display name="Example: accordionView" /accordionView/ height="480px"
<App>
<Tabs accordionView="true">
<TabItem label="Account Information">
<Card title="Account Details">
<Text>Your account is active and in good standing.</Text>
<Text>Account ID: 12345</Text>
<Text>Member since: January 2024</Text>
</Card>
</TabItem>
<TabItem label="Billing & Payments">
<Card title="Payment Methods">
<Text>Current Plan: Professional</Text>
<Text>Next billing date: November 1, 2025</Text>
<Text>Payment method: xxxx 4242</Text>
</Card>
</TabItem>
<TabItem label="Security Settings">
<Card title="Security Options">
<Text>Two-factor authentication: Enabled</Text>
<Text>Last password change: September 15, 2025</Text>
<Text>Active sessions: 2</Text>
</Card>
</TabItem>
</Tabs>
</App>
```
The accordion view is particularly useful for mobile layouts or when you need to present expandable sections in a vertical format. Each section can be opened independently by clicking its header.
```xmlui-pg copy display name="Example: accordionView with dynamic content" /accordionView/ height="450px"
<App>
<Tabs accordionView="true">
<Items data="{[
{title: 'Overview', content: 'Dashboard and quick statistics'},
{title: 'Reports', content: 'Monthly and annual reports'},
{title: 'Analytics', content: 'User behavior and metrics'},
{title: 'Export', content: 'Download data in various formats'}
]}">
<TabItem label="{$item.title}">
<Card>
<Text>{$item.content}</Text>
</Card>
</TabItem>
</Items>
</Tabs>
</App>
```
### `activeTab` [#activetab]
This property indicates the index of the active tab. The indexing starts from 0, representing the starting (leftmost) tab. If not set, the first tab is selected by default.
### `headerTemplate` [#headertemplate]
This property declares the template for the clickable tab area.
```xmlui-pg copy {3-6} display name="Example: headerTemplate" /headerTemplate/ height="200px"
<App>
<Tabs>
<property name="headerTemplate">
<Icon name="chevronright" />
<Text color="green">Account {$header.index}</Text>
</property>
<Items data="{[
{id: 1, name: 'AcmeCorp'},
{id: 2, name: 'BetaLLC'},
{id: 3, name: 'GammaInc'}]
}">
<TabItem label="Account {$item}">
<Card title="Tab Content for Account {$item.name}"/>
</TabItem>
</Items>
</Tabs>
</App>
```
The `headerTemplate` property allows you to customize the appearance of tab headers. The template receives a `$header` context variable with the following properties:
- `id` (optional): External ID if provided to TabItem
- `index`: Zero-based index of the tab
- `label`: The tab's label text
- `isActive`: Boolean indicating if this tab is currently active
Individual tab items have an optional identifier, which is passed to the header template.
```xmlui-pg copy {3-5} display name="Example: headerTemplate" /headerTemplate/ height="200px"
<App>
<Tabs>
<property name="headerTemplate">
{$header.label}{$header.id ? ' | ID: ' + $header.id : ''}
</property>
<TabItem label="Home" id="home-tab">
Home content
</TabItem>
<TabItem label="Accounts" id="accounts-tab">
Accounts content
</TabItem>
<TabItem label="Settings">
Settings content
</TabItem>
</Tabs>
</App>
```
> [!INFO] Individual `TabItem` children can customize their [header templates](./TabItem#headertemplate), too.
### `orientation` (default: "horizontal") [#orientation-default-horizontal]
This property indicates the orientation of the component. In horizontal orientation, the tab sections are laid out on the left side of the content panel, while in vertical orientation, the buttons are at the top. Note: This property is ignored when accordionView is set to true.
Available values: `horizontal` **(default)**, `vertical`
### `tabAlignment` (default: "start") [#tabalignment-default-start]
This property controls how tabs are aligned within the tab header container in horizontal orientation. Use 'start' to align tabs to the left, 'end' to align to the right, 'center' to center the tabs, and 'stretch' to make tabs fill the full width of the header. Note: This property is ignored when orientation is set to 'vertical' or when accordionView is enabled.
Available values: `start` **(default)**, `end`, `center`, `stretch`
The `tabAlignment` property controls how tabs are aligned within the tab header container in horizontal orientation. It accepts four values: `start`, `end`, `center`, and `stretch`.
> [!NOTE] The `tabAlignment` property is ignored when `orientation` is set to `vertical` or when `accordionView` is enabled.
**Alignment: start**
Aligns tabs to the left side of the container:
```xmlui-pg copy display name="Example: tabAlignment='start'" /tabAlignment/ height="200px"
<App>
<Tabs tabAlignment="start" style="width: 100%">
<TabItem label="Home">Home content</TabItem>
<TabItem label="Profile">Profile content</TabItem>
<TabItem label="Settings">Settings content</TabItem>
</Tabs>
</App>
```
**Alignment: center**
Centers tabs within the container:
```xmlui-pg copy display name="Example: tabAlignment='center'" /tabAlignment/ height="200px"
<App>
<Tabs tabAlignment="center" style="width: 100%">
<TabItem label="Home">Home content</TabItem>
<TabItem label="Profile">Profile content</TabItem>
<TabItem label="Settings">Settings content</TabItem>
</Tabs>
</App>
```
**Alignment: end**
Aligns tabs to the right side of the container:
```xmlui-pg copy display name="Example: tabAlignment='end'" /tabAlignment/ height="200px"
<App>
<Tabs tabAlignment="end" style="width: 100%">
<TabItem label="Home">Home content</TabItem>
<TabItem label="Profile">Profile content</TabItem>
<TabItem label="Settings">Settings content</TabItem>
</Tabs>
</App>
```
**Alignment: stretch**
Makes tabs fill the full width of the container, distributing them evenly:
```xmlui-pg copy display name="Example: tabAlignment='stretch'" /tabAlignment/ height="200px"
<App>
<Tabs tabAlignment="stretch" style="width: 100%">
<TabItem label="Home">Home content</TabItem>
<TabItem label="Profile">Profile content</TabItem>
<TabItem label="Settings">Settings content</TabItem>
</Tabs>
</App>
```
## Events [#events]
### `didChange` [#didchange]
This event is triggered when value of Tabs has changed.
The event handler gets these parameters, which refer to the active tab after the change:
- `index`: The active tab index
- `id`: The identifier of the active tab (if not defined, the framework provides an auto-generated id)
- `label`: The label of the active tab
```xmlui-pg copy display name="Example: didChange" /onDidChange/ height="200px"
<App var.lastTab="(none)">
<Tabs onDidChange="
(newIndex, id, label) =>
lastTab = newIndex + ': ' + label + ' (' + id + ')'
">
<TabItem id="account" label="Account">
<Text>Account</Text>
</TabItem>
<TabItem label="Stream">
<Text>Stream</Text>
</TabItem>
<TabItem label="Support">
<Text>Support</Text>
</TabItem>
</Tabs>
<Text>Tab index changed to {lastTab}</Text>
</App>
```
## Exposed Methods [#exposed-methods]
### `next` [#next]
This method selects the next tab. If the current tab is the last one, it wraps around to the first tab.
**Signature**: `next(): void`
```xmlui-pg copy display name="Example: next()" /next/ height="250px"
<App>
<Fragment>
<Tabs id="myTabs">
<TabItem label="Tab 1">Content 1</TabItem>
<TabItem label="Tab 2">Content 2</TabItem>
<TabItem label="Tab 3">Content 3</TabItem>
</Tabs>
<Button onClick="myTabs.next()">Next Tab</Button>
</Fragment>
</App>
```
### `prev` [#prev]
This method selects the previous tab. If the current tab is the first one, it wraps around to the last tab.
**Signature**: `prev(): void`
```xmlui-pg copy display name="Example: prev()" /prev/ height="250px"
<App>
<Fragment>
<Tabs id="myTabs">
<TabItem label="Tab 1">Content 1</TabItem>
<TabItem label="Tab 2">Content 2</TabItem>
<TabItem label="Tab 3">Content 3</TabItem>
</Tabs>
<Button onClick="myTabs.prev()">Previous Tab</Button>
</Fragment>
</App>
```
### `setActiveTabById` [#setactivetabbyid]
This method sets the active tab by its ID.
**Signature**: `setActiveTabById(id: string): void`
```xmlui-pg copy display name="Example: setActiveTabById()" /setActiveTabById/ height="250px"
<App>
<Fragment>
<Tabs id="myTabs">
<TabItem label="Home" id="home">Home Content</TabItem>
<TabItem label="Settings" id="settings">Settings Content</TabItem>
<TabItem label="Help" id="help">Help Content</TabItem>
</Tabs>
<Button onClick="myTabs.setActiveTabById('settings')">
Go to Settings (by ID)
</Button>
</Fragment>
</App>
```
### `setActiveTabIndex` [#setactivetabindex]
This method sets the active tab by index (0-based).
**Signature**: `setActiveTabIndex(index: number): void`
```xmlui-pg copy display name="Example: setActiveTabIndex()" /setActiveTabIndex/ height="250px"
<App>
<Fragment>
<Tabs id="myTabs">
<TabItem label="Tab 1">Content 1</TabItem>
<TabItem label="Tab 2">Content 2</TabItem>
<TabItem label="Tab 3">Content 3</TabItem>
</Tabs>
<Button onClick="myTabs.setActiveTabIndex(2)">Go to Tab 3 (by Index)</Button>
</Fragment>
</App>
```
## Styling [#styling]
### Theme Variables [#theme-variables]
| Variable | Default Value (Light) | Default Value (Dark) |
| --- | --- | --- |
| [backgroundColor](../styles-and-themes/common-units/#color)-list-Tabs | *none* | *none* |
| [backgroundColor](../styles-and-themes/common-units/#color)-Tabs | *none* | *none* |
| [backgroundColor](../styles-and-themes/common-units/#color)-trigger-Tabs | *none* | *none* |
| [backgroundColor](../styles-and-themes/common-units/#color)-trigger-Tabs--active | *none* | *none* |
| [backgroundColor](../styles-and-themes/common-units/#color)-trigger-Tabs--hover | $color-surface-100 | $color-surface-100 |
| [border](../styles-and-themes/common-units/#border)-list-Tabs | *none* | *none* |
| [border](../styles-and-themes/common-units/#border)-trigger-Tabs | *none* | *none* |
| [borderColor](../styles-and-themes/common-units/#color)-active-Tabs | $color-primary | $color-primary |
| [borderColor](../styles-and-themes/common-units/#color)-Tabs | $borderColor | $borderColor |
| [borderRadius](../styles-and-themes/common-units/#border-rounding)-list-Tabs | *none* | *none* |
| [borderRadius](../styles-and-themes/common-units/#border-rounding)-trigger-Tabs | *none* | *none* |
| [borderStyle](../styles-and-themes/common-units/#border-style)-Tabs | solid | solid |
| [borderWidth](../styles-and-themes/common-units/#size)-Tabs | 2px | 2px |
| [padding](../styles-and-themes/common-units/#size)-trigger-Tabs | $space-4 | $space-4 |
| [paddingBottom](../styles-and-themes/common-units/#size)-trigger-Tabs | *none* | *none* |
| [paddingHorizontal](../styles-and-themes/common-units/#size)-trigger-Tabs | *none* | *none* |
| [paddingLeft](../styles-and-themes/common-units/#size)-trigger-Tabs | *none* | *none* |
| [paddingRight](../styles-and-themes/common-units/#size)-trigger-Tabs | *none* | *none* |
| [paddingTop](../styles-and-themes/common-units/#size)-trigger-Tabs | *none* | *none* |
| [paddingVertical](../styles-and-themes/common-units/#size)-trigger-Tabs | *none* | *none* |
| [textColor](../styles-and-themes/common-units/#color)-trigger-Tabs | *none* | *none* |
```
--------------------------------------------------------------------------------
/docs/public/pages/styles-and-themes/layout-props.md:
--------------------------------------------------------------------------------
```markdown
# Layout Properties [#layout-summary]
This document summarizes the layout properties you can use for UI Engine components.
## `animation`
Sets the animation to apply to the component.
## `animationDuration`
Sets the duration of the animation associated with the component.
## `background`
Sets the background [color value](/styles-and-themes/common-units#color) of a component (shortcut to `backgroundColor`).
## `backgroundColor`
Sets the background [color value](/styles-and-themes/common-units#color) of a component.
## `border`
Sets the value of the [border](/styles-and-themes/common-units#border) area; uses the same value for the left, top, right, and bottom borders.
## `borderBottom`
Sets the value of the bottom [border](/styles-and-themes/common-units#border) to the specified one.
## `borderColor`
Sets the [color value](/styles-and-themes/common-units#color) of the border; uses the same value for the left, top, right, and bottom borders.
## `borderHorizontal`
Sets the value of the horizontal [borders](/styles-and-themes/common-units#border) (left and right) to the specified one.
## `borderLeft`
Sets the value of the left [border](/styles-and-themes/common-units#border) to the specified one.
## `borderRadius`
This property rounds the corners of a component's outer border edge according to the specified [value](/styles-and-themes/common-units#border-rounding).
## `borderRadiusBottomLeft`
This property rounds the bottom-left corner of a component's outer border edge according to the specified [value](/styles-and-themes/common-units#border-rounding).
## `borderRadiusBottomRight`
This property rounds the bottom-right corner of a component's outer border edge according to the specified [value](/styles-and-themes/common-units#border-rounding).
## `borderRadiusTopLeft`
This property rounds the top-left corner of a component's outer border edge according to the specified [value](/styles-and-themes/common-units#border-rounding).
## `borderRadiusTopRight`
This property rounds the top-right corner of a component's outer border edge according to the specified [value](/styles-and-themes/common-units#border-rounding).
## `borderRight`
Sets the value of the right [border](/styles-and-themes/common-units#border) to the specified one.
## `borderStyle`
Sets the [style](/styles-and-themes/common-units#border-style) of the border; uses the same value for the left, top, right, and bottom borders.
## `borderWidth`
Sets the [width](/styles-and-themes/common-units#size) (thickness) of the border; uses the same value for the left, top, right, and bottom borders.
## `borderTop`
Sets the value of the top [border](/styles-and-themes/common-units#border) to the specified one.
## `borderVertical`
Sets the value of the vertical [borders](/styles-and-themes/common-units#border) (top and bottom) to the specified one.
## `bottom`
Sets the [bottom](/styles-and-themes/common-units#size) position of the component to the specified value.
## `boxShadow`
This property adds [shadow effects](/styles-and-themes/common-units#shadow) around a component's frame and set up one or more shadow effects.
## `canShrink`
This boolean property indicates if a component can shrink its size when its parent container is resized.
## `color`
Sets the foreground [color value](/styles-and-themes/common-units#color) of a component's text and text decorations.
## `cursor`
Sets the mouse [cursor](/styles-and-themes/common-units#cursor), if any, to show when the mouse pointer is over a particular component
## `direction`
This property sets the direction of text, table columns, and horizontal overflow. Use `rtl` for languages written from right to left (like Hebrew or Arabic), and `ltr` for those written from left to right (like English and most other languages). By default, the prop's value is `ltr`.
## `fill`
Sets the fill [color](/styles-and-themes/common-units#color) of graphical elements (such as SVG icons).
## `fontFamily`
This property specifies a prioritized list of one or more [font family](/styles-and-themes/common-units#font-family) names and/or generic family names for the selected component.
## `fontSize`
This property sets the size of the font. Changing the font [size](/styles-and-themes/common-units#size) also updates the sizes of the font size-relative length units, such as em, ex, and so forth.
## `fontWeight`
Sets the [weight (or boldness)](/styles-and-themes/common-units#font-weight) of the font. The weights available depend on the `fontFamily` that is currently set.
## `fontStyle`
This property sets whether a font should be styled with a normal, italic, or oblique face from its font family.
## `fontVariant`
This property controls the usage of alternate glyphs in a font. These alternates include things like stylistic variants (such as [small caps](/styles-and-themes/common-units#font-variant)), ligatures, and language-specific glyph variants.
## `gap`
Layout components use this property to define the [size](/styles-and-themes/common-units#size) of space separating child components.
## `height`
Specifies the [height](/styles-and-themes/common-units#size) (vertical dimension) of the component.
## `left`
Sets the [left](/styles-and-themes/common-units#size) position of the component to the specified value.
## `letterSpacing`
This property sets the horizontal [spacing](/styles-and-themes/common-units#size) behavior between text characters. This value is added to the natural spacing between characters while rendering the text. Positive values cause characters to spread farther apart, while negative values bring characters closer together.
## `lineBreak`
This property determines how [line breaking](/styles-and-themes/common-units#line-break) works for languages that use a text wrapping system other than the standard space-based approach, such as Chinese, Japanese, and Korean.
## `lineHeight`
This property sets the [height](/styles-and-themes/common-units#size) of a line box. It's commonly used to set the distance between lines of text.
## `margin`
Sets the [size](/styles-and-themes/common-units#size) of the margin area; uses the same value for the left, top, right, and bottom margins.
## `marginBottom`
Sets the [size](/styles-and-themes/common-units#size) of the bottom margin to the specified value.
## `marginHorizontal`
Sets the [size](/styles-and-themes/common-units#size) of the horizontal margins (left and right) to the specified value.
## `marginLeft`
Sets the [size](/styles-and-themes/common-units#size) of the left margin to the specified value.
## `marginRight`
Sets the [size](/styles-and-themes/common-units#size) of the right margin to the specified value.
## `marginTop`
Sets the [size](/styles-and-themes/common-units#size) of the top margin to the specified value.
## `marginVertical`
Sets the [size](/styles-and-themes/common-units#size) of the vertical margins (top and bottom) to the specified value.
## `maxHeight`
Specifies the maximum [height](/styles-and-themes/common-units#size) of an element. It prevents the current value of the height property from becoming larger than the value specified.
## `maxWidth`
Specifies the maximum [width](/styles-and-themes/common-units#size) of an element. It prevents the current value of the width property from becoming larger than the value specified.
## `minHeight`
Specifies the minimum [height](/styles-and-themes/common-units#size) of an element. It prevents the current value of the height property from becoming smaller than the value specified.
## `minWidth`
Specifies the minimum [width](/styles-and-themes/common-units#size) of an element. It prevents the current value of the width property from becoming smaller than the value specified.
## `opacity`
This property sets the opacity of an element. Opacity is the degree to which the content behind an element is hidden. The value is a number in the range 0.0 to 1.0, inclusive, or a percentage from 0% to 100%.
## `outline`
This property sets most of the outline properties in a single declaration. An outline is a line that is drawn around an element, outside the border.
## `outlineWidth`
This property sets the thickness of an element's outline. An outline is a line that is drawn around an element, outside the border.
## `outlineStyle`
This property sets the style of an element's outline. An outline is a line that is drawn around an element, outside the border.
## `outlineColor`
This property sets the [color](/styles-and-themes/common-units#color) of an element's outline.
## `overflowX`
This property defines the [overflow](/styles-and-themes/common-units#overflow) strategy when a component horizontally overflows the UI its parent provides.
## `overflowY`
This property defines the [overflow](/styles-and-themes/common-units#overflow) strategy when a component vertically overflows the UI its parent provides.
## `padding`
Sets the [size](/styles-and-themes/common-units#size) of the padding area; uses the same value for the left, top, right, and bottom paddings.
## `paddingBottom`
Sets the [size](/styles-and-themes/common-units#size) of the bottom padding to the specified value.
## `paddingHorizontal`
Sets the [size](/styles-and-themes/common-units#size) of the horizontal padding (left and right) to the specified value.
## `paddingLeft`
Sets the [size](/styles-and-themes/common-units#size) of the left padding to the specified value.
## `paddingRight`
Sets the [size](/styles-and-themes/common-units#size) of the right padding to the specified value.
## `paddingTop`
Sets the [size](/styles-and-themes/common-units#size) of the top padding to the specified value.
## `paddingVertical`
Sets the [size](/styles-and-themes/common-units#size) of the vertical paddings (top and bottom) to the specified value.
## `right`
Sets the [right](/styles-and-themes/common-units#size) position of the component to the specified value.
## `stroke`
Sets the [stroke color](/styles-and-themes/common-units#color) of graphical elements (such as SVG icons).
## `strokeWidth`
Sets the [stroke width](/styles-and-themes/common-units#size) of graphical elements (such as SVG icons).
## `textAlign`
This property sets the horizontal [alignment](/styles-and-themes/common-units#text-align) of the inline-rendered content (e.g., text) inside its block-rendered parent.
## `textAlignLast`
This property sets how the last line of a block or a line, right before a forced line break, is [aligned](/styles-and-themes/common-units#text-align).
## `textDecoration`
This property sets the appearance of [decorative lines](/styles-and-themes/common-units#text-decoration) on text.
## `textDecorationLine`
This property sets the kind of decoration that is used on text in an element, such as an underline or overline.
## `textDecorationColor`
This property sets the [color](/styles-and-themes/common-units#color) of decorations added to text by `textDecorationLine`.
## `textDecorationStyle`
This property sets the style of the lines specified by `textDecorationLine`. The style applies to all lines that are set with `textDecorationLine`.
## `textDecorationThickness`
This property sets sets the stroke thickness of the decoration line that is used on text in an element, such as a line-through, underline, or overline.
## `textIndent`
This property specifies the amount of [indentation](/styles-and-themes/common-units#text-indent) (empty space) that should be left before the first line of the text content of a block element.
## `textShadow`
This property adds [shadows](/styles-and-themes/common-units#text-shadow) to text. It accepts a comma-separated list of shadows to be applied to the text and any of its decorations.
## `textTransform`
This property specifies how to [capitalize](/styles-and-themes/common-units#text-transform) an element's text.
## `textUnderlineOffset`
This property specifies the offset distance of an underline text decoration line (applied using `textDecoration`) from its original position.
## `textWrap`
The [value](/styles-and-themes/common-units#text-wrap) of this property controls how text inside an element is wrapped.
## `top`
Sets the [top](/styles-and-themes/common-units#size) position of the component to the specified value.
## `transition`
This property is a shorthand for [transition effects](/styles-and-themes/common-units#transition) that specify the CSS property to which a transition effect should be applied, the duration and timing of the transition, and any delay.
## `transform`
This layout property lets you rotate, scale, skew, or translate an element. You can use the standard [CSS transform property](https://developer.mozilla.org/en-US/docs/Web/CSS/transform) format.
## `userSelect`
This property controls whether the [user can select](/styles-and-themes/common-units#user-select) text.
## `whiteSpace`
This property sets how white space inside an element is handled. Available values are: `normal`, `pre`, `pre-wrap`, `pre-line`, `wrap`, `collapse`, `nowrap`, and `preserve nowrap`.
## `width`
Specifies the [width](/styles-and-themes/common-units#size) (horizontal dimension) of the component.
## `wordBreak`
This property specifies how [words should break](/styles-and-themes/common-units#word-break) when reaching the end of a line. It determines whether to break lines within words or to maintain words intact.
## `wordSpacing`
This property sets the length of [white space](/styles-and-themes/common-units#word-spacing) between words and between tags. Positive values increase the space between words, while negative values bring them closer together.
## `wordWrap`
This property determines whether the browser should [break lines within words](/styles-and-themes/common-units#word-wrap) when they would otherwise overflow the container. Also known as "overflow-wrap".
## `wrapContent`
This boolean property indicates if a layout container can wrap its content into multiple lines.
## `zIndex`
This layout property sets the z-order of a positioned component and its children. Overlapping components with a larger z-index cover those with a smaller one.
## `writingMode`
This property sets whether [lines of text](/styles-and-themes/common-units#writing-mode) are laid out horizontally or vertically, as well as the direction in which blocks progress. Use this for vertical languages, such as Chinese, Japanese, and Korean.
## `zoom`
This property sets the zoom level of the view. The zoom level is a scaling factor that changes the size of the view.
```
--------------------------------------------------------------------------------
/docs/content/components/Queue.md:
--------------------------------------------------------------------------------
```markdown
# Queue [#queue]
`Queue` manages sequential processing of items in FIFO (first-in, first-out) order. It is a non-visual component but provides UI progress reporting and result display.
## Using Queue [#using-queue]
As its name suggests, the `Queue` component keeps a queue of items to process. You can add items to the queue with the `enqueueItem` (or `enqueueItems`) method. Once the queue has some items to process, the engine reads them one by one (in FIFO order) and processes an item with the `process` event handler.
Though `Queue` is a non-visual component, it can render UI for reporting progress through its `progressFeedback` property. Also, when the queue gets empty, the UI can render a result summary through the `resultFeedback` property.
The following sample demonstrates these concepts. When the user clicks the button, a new random number is queued. The sample imitates a long calculation by waiting one second within the `process` event handler and reports the progress.
A `ChangeListener` instance observes queue length changes and stores the actual length to display that in the UI.
```xmlui-pg copy {9-24} display name="Example: using Queue"
<App
var.queued="{0}"
var.queueLength="{0}"
var.processed="{0}"
var.result="{0}">
<Button
label="Add a new item to the queue"
onClick="{myQueue.enqueueItem(Math.random()); queued++; }" />
<Queue id="myQueue"
onProcess="processing =>
{
result += processing.item;
delay(1000);
processed++;
processing.onProgress(processed)
}
">
<property name="progressFeedback">
<Text value="{processed} / {queued}" />
</property>
<property name="resultFeedback">
<Text value="{result.toFixed(4)}" />
</property>
</Queue>
<ChangeListener
listenTo="{myQueue.getQueueLength()}"
onDidChange="l => queueLength = l.newValue;"/>
<Text>Items queued: {queued}</Text>
<Text>Current queue length: {queueLength}</Text>
<Text>Current result: {result.toFixed(4)}</Text>
</App>
```
Try the app by clicking the button several times. Check how the queue processes the items and displays feedback.
**Context variables available during execution:**
- `$completedItems`: A list containing the queue items that have been completed (fully processed).
- `$queuedItems`: A list containing the items waiting in the queue, icluding the completed items.
## Properties [#properties]
### `clearAfterFinish` (default: false) [#clearafterfinish-default-false]
This property indicates the completed items (successful or error) should be removed from the queue after completion.
### `progressFeedback` [#progressfeedback]
This property defines the component template of the UI that displays progress information whenever, the queue's `progressReport` function in invoked. If not set, no progress feedback is displayed.
### `resultFeedback` [#resultfeedback]
This property defines the component template of the UI that displays result information when the queue becomes empty after processing all queued items. If not set, no result feedback is displayed.
## Events [#events]
### `complete` [#complete]
The queue fires this event when the queue gets empty after processing all items. The event handler has no arguments.
The following sample displays a tick mark every time the queue is emptied:
```xmlui-pg copy {13} display name="Example: complete"
<App
var.queued="{0}"
var.queueEmptied=""
var.result="{0}">
<Button
label="Add a new item to the queue"
onClick="{myQueue.enqueueItem(Math.random()); queued++; }" />
<Queue id="myQueue"
onProcess="processing => {
result += processing.item;
delay(1000);
}"
onComplete="queueEmptied += ' ok!'" >
<property name="progressFeedback">
<Text value="Completed: {$completedItems.length} of {$queuedItems.length}"/>
</property>
<property name="resultFeedback">
<Text value="{result.toFixed(4)}" />
</property>
</Queue>
<Text>Items queued: {queued}</Text>
<Text>Current result: {result.toFixed(4)}</Text>
<Text>Queue emptied: {queueEmptied}</Text>
</App>
```
### `didProcess` [#didprocess]
This event is fired when the processing of a queued item has been successfully processed.
The parameter of the event handler is an object with these properties:
- `item`: the item to process
- `actionItemId`: The unique (internal) ID of the item being processed, as generated by the `Queue` component. You can pass this ID to some API methods (for example, to `remove`).
- `processItemContext`: A context object (initially empty) that you can use to add some context-specific information to the item. The event handlers of other events will see this information as the item being processed conveys it.
The following sample uses the `didProcess` event handler to add a tick symbol to the progress whenever an item has been processed:
```xmlui-pg copy {13} display name="Example: didProcess"
<App
var.queued="{0}"
var.progressLine=""
var.result="{0}">
<Button
label="Add a new item to the queue"
onClick="{myQueue.enqueueItem(Math.random()); queued++; }" />
<Queue id="myQueue"
onProcess="processing => {
result += processing.item;
delay(1000);
}"
onDidProcess="progressLine += ' ok!'" >
<property name="resultFeedback">
<Text value="{result.toFixed(4)}" />
</property>
</Queue>
<Text>Items queued: {queued}</Text>
<Text>Current result: {result.toFixed(4)}</Text>
<Text>Progress: {progressLine}</Text>
</App>
```
### `process` [#process]
This event is fired to process the next item in the queue. If the processing cannot proceed because of some error, raise an exception, and the queue will handle that.
The parameter of the event handler is an object with these properties:
- `item`: the item to process
- `actionItemId`: The unique (internal) ID of the item being processed, as generated by the `Queue` component. You can pass this ID to some API methods (for example, to `remove`).
- `processItemContext`: A context object (initially empty) that you can use to add some context-specific information to the item. The event handlers of other events will see this information as the item being processed conveys it.
- `reportProgress`: A function you can use to report the progress. Invoke this method with an argument that the `progressFeedback` component's template will utilize.
See the example in the [Using Queue](#using-queue) section.
### `processError` [#processerror]
This event is fired when processing an item raises an error. The event handler method receives two parameters. The first is the error raised during the processing of the item; the second is an object with these properties:
- `item`: the item to process
- `actionItemId`: The unique (internal) ID of the item being processed, as generated by the `Queue` component. You can pass this ID to some API methods (for example, to `remove`).
- `processItemContext`: A context object (initially empty) that you can use to add some context-specific information to the item. The event handlers of other events will see this information as the item being processed conveys it.
If the event handler returns false, the queue does not sign the error in the UI. With other return values (including no return value), the queue displays the error.
The following sample generates an error for every fourth item, and gives an error feedback with the `processError` event handler:
```xmlui-pg
---app copy {10-12, 17} display name="Example: processError"
<App
var.queued="{0}"
var.progressLine=""
var.result="{0}">
<Button
label="Add a new item to the queue"
onClick="{myQueue.enqueueItem(Math.random()); queued++; }" />
<Queue id="myQueue"
onProcess="processing => {
if (progressLine.length % 4 === 3) {
throw 'Item cannot be processed';
}
result += processing.item;
delay(1000);
}"
onDidProcess="progressLine += ' ok!'"
onProcessError="progressLine += ' canceled'" >
<property name="resultFeedback">
<Text value="{result.toFixed(4)}" />
</property>
</Queue>
<Text>Items queued: {queued}</Text>
<Text>Current result: {result.toFixed(4)}</Text>
<Text>Progress: {progressLine}</Text>
</App>
---desc
Click the button several times to see how processing errors are handled in the UI.
```
### `willProcess` [#willprocess]
This event is triggered to process a particular item.
This event is fired before the next item in the queue gets processed. If the event handler returns `false`, the queue skips processing that item. With other return values (including no return value), the queue continues processing the item.
The parameter of the event handler is an object with these properties:
- `item`: the item to process
- `actionItemId`: The unique (internal) ID of the item being processed, as generated by the `Queue` component. You can pass this ID to some API methods (for example, to `remove`).
- `processItemContext`: A context object (initially empty) that you can use to add some context-specific information to the item. The event handlers of other events will see this information as the item being processed conveys it.
The following sample declares a `willProcess` event handler that will skip processing (summing) items less than 0.5; the handler counts the number of skipped items.
```xmlui-pg
---app copy {9} display name="Example: willProcess"
<App
var.queued="{0}"
var.skipped="{0}"
var.result="{0}">
<Button
label="Add a new item to the queue"
onClick="{myQueue.enqueueItem(Math.random()); queued++; }" />
<Queue id="myQueue"
onWillProcess="toProcess => toProcess.item < 0.5 ? (skipped++, false) : true"
onProcess="processing => {
result += processing.item;
delay(1000);
}">
<property name="resultFeedback">
<Text value="{result.toFixed(4)}" />
</property>
</Queue>
<Text>Items queued: {queued}</Text>
<Text>Items skipped: {skipped}</Text>
<Text>Current result: {result.toFixed(4)}</Text>
</App>
---desc
Click the button several times and see how the number of skipped items increments.
```
## Exposed Methods [#exposed-methods]
### `enqueueItem` [#enqueueitem]
This method enqueues the item passed in the method parameter. The new item will be processed after the current queue items have been handled. The method retrieves the unique ID of the newly added item; this ID can be used later in other methods, such as `remove`.
**Signature**: `enqueueItem(item: any): string`
- `item`: The item to enqueue.
The following example stores and displays this item when a new item is put into the queue:
```xmlui-pg copy {5} display name="Example: enqueueItem"
<App var.queued="{0}" var.itemIds="">
<Button
label="Add a new item to the queue"
onClick="{
const itemId = myQueue.enqueueItem(Math.random());
itemIds += itemId + ', '; queued++;
}" />
<Queue id="myQueue" onProcess="processing => {}" />
<Text>Items queued: {queued}</Text>
<Text>Item IDs: {itemIds}</Text>
</App>
```
### `enqueueItems` [#enqueueitems]
This method enqueues the array of items passed in the method parameter. The new items will be processed after the current queue items have been handled. The method retrieves an array of unique IDs, one for each new item. An item ID can be used later in other methods, such as `remove`.
**Signature**: `enqueueItems(items: any[]): string[]`
- `items`: The array of items to enqueue.
### `getQueuedItems` [#getqueueditems]
You can use this method to return the items in the queue. These items contain all entries not removed from the queue yet, including pending, in-progress, and completed items.
**Signature**: `getQueuedItems(): any[]`
This method returns the items currently in the queue with their entire context. The result of this method is a list of objects with these properties:
- `item`: The queued item (as passed to the `enqueueItem` and `enqueueItems` methods)
- `actionItemId`: The unique (internal) ID of the item being processed, as generated by the `Queue` component.
- `status`: The current processing status of the item; one of the following values: `"pending"`, `"started"`, `"in-progress"`, `"completed"`, or `"error"`
- `progress`: The latest progress value reported for the item (may be undefined)
- `result`: The optional value the `process` event handler returns.
> **Note**: When all items are processed, the queue removes the items and fires the `complete` event. When the event handler runs, the queue is empty, and `getQueuedItems` returns an empty list.
### `getQueueLength` [#getqueuelength]
This method retrieves the current queue length. The queue contains only those items that are not fully processed yet.
**Signature**: `getQueueLength(): number`
### `remove` [#remove]
This method removes an item from the queue using its unique ID.
**Signature**: `remove(itemId: string): void`
- `itemId`: The unique ID of the item to remove.
The following example emulates a file-processing application. When a file is about to save (in the `process` event), the processing fails with files that deny overwrite. In such a case, the `processError` event handler asks the user to confirm the overwrite action. In case of confirmation, the queue uses the `remove` action to discard the faulty queue item and enqueues the file again with the `accept` behavior so that it won't fail next time.
```xmlui-pg copy {21} display name="Example: remove" height="240px"
<App var.queued="{0}" var.processed="" var.skipped="{0}">
<Button
label="Add a new file to the queue"
onClick="{myQueue.enqueueItem({file: ++queued, conflict: 'deny'})}" />
<Queue id="myQueue"
onProcess="processing =>
{
delay(1000);
if (processing.item.conflict === 'deny') {
throw 'Conflict';
}
processed += processing.item.file + ', ';
}
"
onProcessError="(error, processing) => {
if (error.message === 'Conflict') {
console.log(error);
const result = confirm('Do you want to overwrite?',
'File ' + processing.item.file + ' already exists',
'Overwrite');
$this.remove(processing.actionItemId);
if (result) {
$this.enqueueItems([{...processing.item, conflict: 'accept'}]);
}
return false;
}
}">
<property name="resultFeedback">
<Text value="All items processed" />
</property>
</Queue>
<Text>Items queued: {queued}</Text>
<Text>Processed: {processed}</Text>
</App>
```
## Styling [#styling]
This component does not have any styles.
```
--------------------------------------------------------------------------------
/xmlui/src/components-core/theming/layout-resolver.ts:
--------------------------------------------------------------------------------
```typescript
import type { CSSProperties } from "react";
import type { LayoutContext } from "../../abstractions/RendererDefs";
import { EMPTY_OBJECT } from "../constants";
import { isEmpty } from "lodash-es";
export const THEME_VAR_PREFIX = "xmlui";
const themeVarCapturesRegex = /(\$[a-zA-Z][a-zA-Z0-9-_]*)/g;
const booleanRegex = /^(true|false)$/;
const starSizeRegex = /^\d*\*$/;
export type ResolvedLayout = {
cssProps: Record<string, CSSProperties[keyof CSSProperties]>;
issues: Set<string>;
};
const defaultCompResult: ResolvedLayout = {
cssProps: {},
issues: new Set(),
};
export function resolveLayoutProps(
layoutProps: LayoutProps = EMPTY_OBJECT,
layoutContext?: LayoutContext,
): ResolvedLayout {
const result: ResolvedLayout = {
cssProps: {},
issues: new Set(),
};
// --- Adjust flex
if (!!getOrientation(layoutContext)) {
// --- In a container, we always use "flex-shrink: 0"
result.cssProps.flexShrink = 0;
}
// --- Dimensions
collectCss("width");
const horizontalStarSize = getHorizontalStarSize(result.cssProps.width, layoutContext);
if (horizontalStarSize !== null) {
// --- We use "flex" when width is in start-size and allow shrinking
result.cssProps.flex = horizontalStarSize;
result.cssProps.flexShrink = 1;
}
collectCss("minWidth");
collectCss("maxWidth");
collectCss("height");
const verticalStarSize = getVerticalStarSize(result.cssProps.height, layoutContext);
if (verticalStarSize !== null) {
// --- We use "flex" when width is in start-size and allow shrinking
result.cssProps.flex = verticalStarSize;
result.cssProps.flexShrink = 1;
}
collectCss("minHeight");
collectCss("maxHeight");
// --- Positions
collectCss("top");
collectCss("right");
collectCss("bottom");
collectCss("left");
// --- Paddings and gap
collectCss("gap");
collectCss("padding");
const paddingHorizontal = transformLayoutValue("paddingHorizontal");
if (paddingHorizontal) {
result.cssProps.paddingLeft = paddingHorizontal;
result.cssProps.paddingRight = paddingHorizontal;
}
collectCss("paddingRight");
collectCss("paddingLeft");
const paddingVertical = transformLayoutValue("paddingVertical");
if (paddingVertical) {
result.cssProps.paddingTop = paddingVertical;
result.cssProps.paddingBottom = paddingVertical;
}
collectCss("paddingTop");
collectCss("paddingBottom");
// --- Margins
collectCss("margin");
const marginHorizontal = transformLayoutValue("marginHorizontal");
if (marginHorizontal) {
result.cssProps.marginLeft = marginHorizontal;
result.cssProps.marginRight = marginHorizontal;
}
collectCss("marginRight");
collectCss("marginLeft");
const marginVertical = transformLayoutValue("marginVertical");
if (marginVertical) {
result.cssProps.marginTop = marginVertical;
result.cssProps.marginBottom = marginVertical;
}
collectCss("marginTop");
collectCss("marginBottom");
// --- Borders
collectCss("border");
const horizontalBorder = transformLayoutValue("borderHorizontal");
if (horizontalBorder) {
result.cssProps.borderLeft = horizontalBorder;
result.cssProps.borderRight = horizontalBorder;
}
collectCss("borderRight");
collectCss("borderLeft");
const verticalBorder = transformLayoutValue("borderVertical");
if (verticalBorder) {
result.cssProps.borderTop = verticalBorder;
result.cssProps.borderBottom = verticalBorder;
}
collectCss("borderTop");
collectCss("borderBottom");
collectCss("borderColor");
collectCss("borderStyle");
collectCss("borderWidth");
// --- Radius
collectCss("borderRadius");
collectCss("radiusTopLeft", "borderTopLeftRadius");
collectCss("radiusTopRight", "borderTopRightRadius");
collectCss("radiusBottomLeft", "borderBottomLeftRadius");
collectCss("radiusBottomRight", "borderBottomRightRadius");
// --- Typography
collectCss("color");
collectCss("fontFamily");
collectCss("fontSize");
collectCss("fontWeight");
collectCss("fontStyle");
collectCss("fontVariant");
collectCss("lineBreak");
collectCss("textDecoration");
collectCss("textDecorationLine");
collectCss("textDecorationColor");
collectCss("textDecorationStyle");
collectCss("textDecorationThickness");
collectCss("textIndent");
collectCss("textShadow");
collectCss("textUnderlineOffset");
collectCss("userSelect");
collectCss("letterSpacing");
collectCss("textTransform");
collectCss("lineHeight");
collectCss("textAlign");
collectCss("textAlignLast");
collectCss("textWrap");
collectCss("wordBreak");
collectCss("wordSpacing");
collectCss("wordWrap");
collectCss("writingMode");
// --- Other
collectCss("backgroundColor");
collectCss("background");
collectCss("boxShadow");
collectCss("direction");
collectCss("overflowX");
collectCss("overflowY");
collectCss("zIndex");
collectCss("opacity");
collectCss("zoom");
collectCss("cursor");
collectCss("whiteSpace");
collectCss("transform");
// --- Outline
collectCss("outline");
collectCss("outlineWidth");
collectCss("outlineColor");
collectCss("outlineStyle");
collectCss("outlineOffset");
// --- Content rendering
const wrapContent = transformLayoutValue("wrapContent");
if (wrapContent) {
result.cssProps.flexWrap = wrapContent === "true" ? "wrap" : "nowrap";
}
collectCss("canShrink", "flexShrink");
const canShrink = transformLayoutValue("canShrink");
if (canShrink) {
result.cssProps.flexShrink = canShrink === "true" ? 1 : 0;
}
// --- If we didn't set any props, return a referentially stable result
if (isEmpty(result.cssProps) && isEmpty(result.issues)) {
return defaultCompResult;
}
// --- Done
return result;
// --- Replaces all variable occurrences in the input string with the result of toCssVar
function transformLayoutValue(prop: string): string {
const defValue = resolveSingleValue();
if (layoutContext?.mediaSize?.sizeIndex !== undefined) {
const sizeIndex = layoutContext.mediaSize?.sizeIndex;
const xsValue = resolveSingleValue("xs");
const smValue = resolveSingleValue("sm");
const mdValue = resolveSingleValue("md");
const lgValue = resolveSingleValue("lg");
const xlValue = resolveSingleValue("xl");
const xxlValue = resolveSingleValue("xxl");
let mergedValue: string;
switch (sizeIndex) {
case 0: // xs
mergedValue = xsValue ?? smValue ?? mdValue;
break;
case 1: // sm
mergedValue = smValue ?? mdValue;
break;
case 2: // md
mergedValue = mdValue;
break;
case 3: // lg
mergedValue = lgValue;
break;
case 4: // xl
mergedValue = xlValue ?? lgValue;
break;
case 5: // xxl
mergedValue = xxlValue ?? xlValue ?? lgValue;
break;
}
return mergedValue ?? defValue;
}
return defValue;
function resolveSingleValue(sizeTag = ""): string {
const fullProp = sizeTag ? `${prop}-${sizeTag}` : prop;
let singleInput = layoutProps[fullProp];
if (singleInput == undefined) {
return;
}
if (typeof singleInput === "string") {
singleInput = singleInput.trim();
} else {
singleInput = singleInput.toString();
}
// --- Evaluate
const value = singleInput
? (singleInput as string).replace(themeVarCapturesRegex, (match: string) =>
toCssVar(match.trim()),
)
: undefined;
if (singleInput !== value) {
// --- Theme variable replaced, do not check pattern validity
return value;
}
// --- Check value validity
const propPatterns = layoutPatterns[prop];
if (!propPatterns || propPatterns.length === 0) {
return value;
}
for (const pattern of propPatterns) {
if (pattern.test(value)) {
return value;
}
}
// --- Done
result.issues.add(fullProp);
return value;
}
}
function collectCss(prop: string, propCssName = ""): void {
const value = transformLayoutValue(prop);
if (value) {
result.cssProps[propCssName || prop] = value;
}
}
// --- Checks if the specified size is a star size and the orientation is horizontal
function getHorizontalStarSize(
size: string | number,
layoutContext?: LayoutContext,
): number | null {
if (!size) return null;
const orientation = getOrientation(layoutContext);
return orientation === "horizontal" && starSizeRegex.test(size.toString())
? getStarSizeNumber(size.toString())
: null;
}
// --- Checks if the specified size is a star size and the orientation is vertical
function getVerticalStarSize(
size: string | number,
layoutContext?: LayoutContext,
): number | null {
if (!size) return null;
const orientation = getOrientation(layoutContext);
return orientation === "vertical" && starSizeRegex.test(size.toString())
? getStarSizeNumber(size.toString())
: null;
}
// --- Obtains the integer number from a string that matches the starSizeRegex.
function getStarSizeNumber(input: string): number | null {
if (starSizeRegex.test(input)) {
const numberPart = input.slice(0, -1); // Remove the trailing '*'
return numberPart === "" ? 1 : parseInt(numberPart, 10); // Default to 1 if no number is present
}
return null;
}
// --- Gets the current orientation from the layout context
function getOrientation(layoutContext?: LayoutContext): string | undefined {
if (!layoutContext) return;
let orientation = layoutContext?.type === "Stack" && layoutContext?.orientation;
return orientation?.toString();
}
}
/**
* Converts the specified themeID to a CSS var string
* @param c segment to convert
*/
export function toCssVar(c: string): string {
return `var(--${THEME_VAR_PREFIX}-${c.substring(1)})`;
}
// The properties constituting a component's layout
export type LayoutProps = {
// --- Dimensions
width?: number | string;
minWidth?: number | string;
maxWidth?: number | string;
height?: number | string;
minHeight?: number | string;
maxHeight?: number | string;
gap?: string;
// --- Positions
top?: number | string;
right?: number | string;
bottom?: number | string;
left?: number | string;
// --- Border
border?: string;
borderTop?: string;
borderRight?: string;
borderBottom?: string;
borderLeft?: string;
borderColor?: string;
borderStyle?: string;
borderWidth?: string;
borderHorizontal?: string;
borderVertical?: string;
// --- Border radius
borderRadius?: number | string;
radiusTopLeft?: number | string;
radiusTopRight?: number | string;
radiusBottomLeft?: number | string;
radiusBottomRight?: number | string;
// --- Padding
padding?: number | string;
paddingHorizontal?: number | string;
paddingVertical?: number | string;
paddingTop?: number | string;
paddingRight?: number | string;
paddingBottom?: number | string;
paddingLeft?: number | string;
// --- Margin
margin?: number | string;
marginHorizontal?: number | string;
marginVertical?: number | string;
marginTop?: number | string;
marginRight?: number | string;
marginBottom?: number | string;
marginLeft?: number | string;
// --- Other
backgroundColor?: string;
background?: string;
boxShadow?: string;
direction?: string;
overflowX?: string;
overflowY?: string;
zIndex?: number | string;
opacity?: string | number;
transform?: string;
// --- Typography
color?: string;
fontFamily?: string;
fontSize?: number | string;
fontWeight?: number | string;
fontStyle?: string;
fontVariant?: string;
lineBreak?: string;
textDecoration?: string;
textDecorationLine?: string;
textDecorationColor?: string;
textDecorationStyle?: string;
textDecorationThickness?: string;
textIndent?: number | string;
textShadow?: string;
textUnderlineOffset?: string;
userSelect?: string;
letterSpacing?: string;
textTransform?: string;
lineHeight?: string;
textAlign?: string;
textWrap?: string;
textAlignLast?: string;
wordBreak?: string;
wordSpacing?: string | number;
wordWrap?: string;
writingMode?: string;
// --- Outline
outline?: string;
outlineWidth?: string;
outlineColor?: string;
outlineStyle?: string;
outlineOffset?: string;
// --- Content rendering
wrapContent?: boolean | string;
canShrink?: boolean | string;
// --- Other
cursor?: string;
zoom?: string | number;
whiteSpace?: string;
// --- Animation
transition?: string;
};
// The properties constituting a component's layout
const layoutPatterns: Record<keyof LayoutProps, RegExp[]> = {
// --- Dimensions
width: [],
minWidth: [],
maxWidth: [],
height: [],
minHeight: [],
maxHeight: [],
gap: [],
// --- Positions
top: [],
right: [],
bottom: [],
left: [],
// --- Border
border: [],
borderTop: [],
borderRight: [],
borderBottom: [],
borderLeft: [],
borderColor: [],
borderStyle: [],
borderWidth: [],
borderHorizontal: [],
borderVertical: [],
// --- Border radius
borderRadius: [],
radiusTopLeft: [],
radiusTopRight: [],
radiusBottomLeft: [],
radiusBottomRight: [],
// --- Padding
padding: [],
paddingHorizontal: [],
paddingVertical: [],
paddingTop: [],
paddingRight: [],
paddingBottom: [],
paddingLeft: [],
// --- Margin
margin: [],
marginHorizontal: [],
marginVertical: [],
marginTop: [],
marginRight: [],
marginBottom: [],
marginLeft: [],
// --- Other
backgroundColor: [],
background: [],
boxShadow: [],
direction: [],
overflowX: [],
overflowY: [],
zIndex: [],
opacity: [],
// --- Typography
color: [],
fontFamily: [],
fontSize: [],
fontWeight: [],
fontStyle: [booleanRegex],
fontVariant: [],
lineBreak: [],
textDecoration: [],
userSelect: [],
letterSpacing: [],
textTransform: [],
lineHeight: [],
textAlign: [],
textWrap: [],
textAlignLast: [],
textIndent: [],
textShadow: [],
wordBreak: [],
wordSpacing: [],
wordWrap: [],
writingMode: [],
// --- Content rendering
wrapContent: [],
canShrink: [],
// --- Other
cursor: [],
zoom: [],
whiteSpace: [],
textDecorationLine: [],
textDecorationColor: [],
textDecorationStyle: [],
textDecorationThickness: [],
textUnderlineOffset: [],
transform: [],
// --- Outline
outline: [],
outlineWidth: [],
outlineColor: [],
outlineStyle: [],
outlineOffset: [],
// --- Animation
transition: [],
};
```
--------------------------------------------------------------------------------
/xmlui/src/components/Charts/BarChart/BarChartNative.tsx:
--------------------------------------------------------------------------------
```typescript
import {
Bar,
BarChart as RBarChart,
CartesianGrid,
XAxis,
YAxis,
ResponsiveContainer,
Tooltip,
Legend as RLegend,
} from "recharts";
import {
type CSSProperties,
type ReactNode,
useEffect,
useRef,
useState,
useCallback,
} from "react";
import { useMemo } from "react";
import ChartProvider, { useChartContextValue } from "../utils/ChartProvider";
import { TooltipContent } from "../Tooltip/TooltipContent";
import { useTheme } from "../../../components-core/theming/ThemeContext";
import classnames from "classnames";
import styles from "./BarChart.module.scss";
export type BarChartProps = {
data: any[];
layout?: "horizontal" | "vertical";
nameKey: string;
stacked?: boolean;
dataKeys?: string[];
style?: CSSProperties;
hideTickX?: boolean;
hideTickY?: boolean;
hideX?: boolean;
hideY?: boolean;
hideTooltip?: boolean;
tickFormatterX?: (value: any) => any;
tickFormatterY?: (value: any) => any;
children?: ReactNode;
showLegend?: boolean;
className?: string;
tooltipRenderer?: (tooltipData: any) => ReactNode;
};
export const defaultProps: Pick<
BarChartProps,
| "layout"
| "stacked"
| "hideTickX"
| "hideTickY"
| "hideX"
| "hideY"
| "hideTooltip"
| "tickFormatterX"
| "tickFormatterY"
| "showLegend"
> = {
layout: "vertical",
stacked: false,
hideTickX: false,
hideTickY: false,
hideX: false,
hideY: false,
hideTooltip: false,
tickFormatterX: (value) => value,
tickFormatterY: (value) => value,
showLegend: false,
};
const defaultChartParams = {
chartWidth: 800,
chartHeight: 300,
};
export function BarChart({
data = [],
layout = defaultProps.layout,
nameKey,
stacked = defaultProps.stacked,
dataKeys = [],
hideTickX = defaultProps.hideTickX,
hideTickY = defaultProps.hideTickY,
hideY = defaultProps.hideY,
hideX = defaultProps.hideX,
hideTooltip = defaultProps.hideTooltip,
tickFormatterX = defaultProps.tickFormatterX,
tickFormatterY = defaultProps.tickFormatterY,
style,
className,
children,
showLegend = defaultProps.showLegend,
tooltipRenderer,
}: BarChartProps) {
// Validate and normalize data
const validData = useMemo(() => (Array.isArray(data) ? data : []), [data]);
const { getThemeVar } = useTheme();
const colorValues = useMemo(() => {
return [
getThemeVar("color-primary-500"),
getThemeVar("color-primary-300"),
getThemeVar("color-success-500"),
getThemeVar("color-success-300"),
getThemeVar("color-warn-500"),
getThemeVar("color-warn-300"),
getThemeVar("color-danger-500"),
getThemeVar("color-danger-300"),
getThemeVar("color-info-500"),
getThemeVar("color-info-300"),
getThemeVar("color-secondary-500"),
getThemeVar("color-secondary-300"),
getThemeVar("color-primary-600"),
getThemeVar("color-primary-400"),
getThemeVar("color-success-600"),
getThemeVar("color-success-400"),
getThemeVar("color-warn-600"),
getThemeVar("color-warn-400"),
getThemeVar("color-danger-600"),
getThemeVar("color-danger-400"),
getThemeVar("color-info-600"),
getThemeVar("color-info-400"),
getThemeVar("color-secondary-600"),
getThemeVar("color-secondary-400"),
getThemeVar("color-primary-900"),
getThemeVar("color-primary-700"),
getThemeVar("color-success-900"),
getThemeVar("color-success-700"),
getThemeVar("color-warn-900"),
getThemeVar("color-warn-700"),
getThemeVar("color-danger-900"),
getThemeVar("color-danger-700"),
getThemeVar("color-info-900"),
getThemeVar("color-info-700"),
getThemeVar("color-secondary-900"),
getThemeVar("color-secondary-700"),
];
}, [getThemeVar]);
const safeTooltipRenderer = useCallback(
(props: any) => {
if (!tooltipRenderer) return <TooltipContent {...props} />;
const payloadArray: Array<{ label: string; value: any; color: string }> = [];
if (props.payload && props.payload.length > 0 && props.payload[0].payload) {
const originalPayload = props.payload[0].payload;
// Transform dataKeys into array of objects with label, value, and color
dataKeys?.forEach((dataKey, index) => {
if (dataKey in originalPayload) {
payloadArray.push({
label: dataKey,
value: originalPayload[dataKey],
color: colorValues[index] || colorValues[0],
});
}
});
}
// Extract tooltip data from Recharts props
const tooltipData = {
label: props.label,
payload: payloadArray,
active: props.active,
};
return tooltipRenderer(tooltipData);
},
[tooltipRenderer, dataKeys, colorValues],
);
const config = useMemo(() => {
return Object.assign(
{},
...dataKeys.map((key, index) => {
return {
[key]: {
label: key,
color: colorValues[index % colorValues.length],
},
};
}),
);
}, [colorValues, dataKeys]);
const chartContextValue = useChartContextValue({ dataKeys, nameKey });
const containerRef = useRef(null);
const labelsRef = useRef<HTMLDivElement>(null);
const [interval, setIntervalState] = useState(0);
const [xAxisHeight, setXAxisHeight] = useState(50);
const [yTickCount, setYTickCount] = useState(5);
const fontSize = 12;
const [chartMargin, setChartMargin] = useState({ left: 30, right: 30, top: 10, bottom: 60 });
const [tickAngle, setTickAngle] = useState(0);
const [tickAnchor, setTickAnchor] = useState<"end" | "middle">("middle");
const [miniMode, setMiniMode] = useState(false);
const [yAxisWidth, setYAxisWidth] = useState(40);
const wrapperRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const calc = () => {
const chartWidth = containerRef?.current?.offsetWidth || defaultChartParams.chartWidth;
const chartHeight = containerRef?.current?.offsetHeight || defaultChartParams.chartHeight;
const spans = labelsRef.current?.querySelectorAll("span") || [];
const yTicks = Array.from(
document.querySelectorAll(".recharts-y-axis .recharts-layer tspan"),
) as SVGGraphicsElement[];
const maxYTickWidth =
yTicks.length > 0 ? Math.max(...yTicks.map((t) => t.getBBox().width)) : 40;
// Only update if the value actually changed
// NOTE: This might cause recursive calls along with setting the state in here directly. Fix if necessary.
setYAxisWidth((prev) => {
// Add a small tolerance to prevent micro-adjustments
if (Math.abs(maxYTickWidth - prev) > 1) {
return maxYTickWidth;
}
return prev;
});
const maxWidth = Array.from(spans).reduce((mx, s) => Math.max(mx, s.offsetWidth), 50);
let angle = 0;
let anchor: "end" | "middle" = "middle";
let rad = 0;
let minTickSpacing = maxWidth + 8;
let leftMargin = Math.ceil(maxWidth / 3);
let rightMargin = Math.ceil(maxWidth / 3);
let xAxisH = Math.ceil(fontSize * 1.2);
let maxTicks = Math.max(1, Math.floor(chartWidth / minTickSpacing));
let skip = Math.max(0, Math.ceil(validData.length / maxTicks) - 1);
if (skip > 0) {
angle = -60;
anchor = "end";
rad = (Math.abs(angle) * Math.PI) / 180;
minTickSpacing = Math.ceil(maxWidth * Math.cos(rad)) + 2;
maxTicks = Math.max(1, Math.floor(chartWidth / minTickSpacing));
skip = Math.max(0, Math.ceil(validData.length / maxTicks) - 1);
leftMargin = Math.ceil((maxWidth * Math.cos(rad)) / 1.8);
rightMargin = Math.ceil((maxWidth * Math.cos(rad)) / 1.8);
xAxisH = Math.ceil(Math.abs(maxWidth * Math.sin(rad)) + Math.abs(fontSize * Math.cos(rad)));
}
setIntervalState(skip);
setTickAngle(angle);
setTickAnchor(anchor);
const xTicks = Array.from(
document.querySelectorAll(".recharts-x-axis .recharts-layer tspan"),
) as SVGGraphicsElement[];
const maxXTickHeight =
xTicks.length > 0 ? Math.max(...xTicks.map((t) => t.getBBox().height)) : fontSize;
let bottomMargin = 10;
if (layout === "vertical") {
bottomMargin = maxXTickHeight;
} else {
bottomMargin = Math.max(xAxisH, maxXTickHeight);
}
setChartMargin({ left: leftMargin, right: rightMargin, top: 10, bottom: bottomMargin });
const maxYTicks = Math.max(2, Math.floor(chartHeight / (fontSize * 3)));
setYTickCount(maxYTicks);
setXAxisHeight(Math.ceil(fontSize));
const neededHeight = 10 + xAxisHeight + 10 + 32;
const neededWidth = chartMargin.left + chartMargin.right + yAxisWidth + 32;
setMiniMode(neededHeight > chartHeight || neededWidth > chartWidth);
};
calc();
window.addEventListener("resize", calc);
return () => window.removeEventListener("resize", calc);
// See note above: leaving out yAxisWidth may stop recursive calls but is hacky
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [data, chartMargin.left, chartMargin.right, layout, validData.length, xAxisHeight]);
const [tooltipElement, setTooltipElement] = useState<HTMLElement | null>(null);
const observer = useRef<ResizeObserver>();
const [tooltipPosition, setTooltipPosition] = useState({ x: 0, y: 0 });
const [tooltipWidth, setTooltipWidth] = useState(0);
const onMouseEnter = useCallback(
(e) => {
setTooltipPosition({ x: e.x - tooltipWidth / 2, y: e.y });
},
[setTooltipPosition, tooltipWidth],
);
// Observe the size of the reference element
useEffect(() => {
observer.current?.disconnect();
if (tooltipElement) {
observer.current = new ResizeObserver((entries) => {
if (entries[0]) {
setTooltipWidth(entries[0].contentRect.width);
}
});
observer.current.observe(tooltipElement);
}
return () => {
observer.current?.disconnect();
};
}, [tooltipElement]);
// Custom tooltip renderer that captures the DOM element
const customTooltipRenderer = useCallback(
(props: any) => {
const tooltipContent = safeTooltipRenderer(props);
return (
<div
ref={(el) => {
if (el) {
setTooltipElement(el);
}
}}
>
{tooltipContent}
</div>
);
},
[safeTooltipRenderer],
);
const xAxisProps: Record<string, any> =
layout === "vertical"
? {
type: "number",
axisLine: false,
hide: miniMode || hideX,
height: miniMode || hideX ? 0 : xAxisHeight,
tick: miniMode || hideTickX ? false : { fill: "currentColor", fontSize },
tickFormatter: miniMode || hideTickX ? undefined : tickFormatterX,
domain: [0, (dataMax: number) => Math.ceil((dataMax * 1.05) / 10) * 10],
}
: {
type: "category",
dataKey: nameKey,
hide: miniMode || hideX,
height: miniMode || hideX ? 0 : xAxisHeight,
tick: miniMode || hideTickX ? false : { fill: "currentColor", fontSize },
tickFormatter: miniMode || hideTickX ? undefined : tickFormatterX,
interval: interval,
tickLine: false,
angle: tickAngle,
textAnchor: tickAnchor,
};
const yAxisProps: Record<string, any> =
layout === "vertical"
? {
type: "category",
dataKey: nameKey,
hide: miniMode || hideY,
interval: "equidistantPreserveStart",
tickLine: false,
tickFormatter: miniMode || hideTickY ? undefined : tickFormatterY,
tick: miniMode || hideTickY ? false : { fill: "currentColor", fontSize },
width: miniMode || hideY ? 0 : yAxisWidth,
}
: {
type: "number",
axisLine: false,
tick: miniMode || hideTickY ? false : { fill: "currentColor", fontSize },
hide: miniMode || hideY,
tickCount: yTickCount,
tickFormatter: miniMode || hideTickY ? undefined : tickFormatterY,
width: miniMode || hideY ? 0 : yAxisWidth,
domain: [
0,
(dataMax: number) => {
const roundedMax = Math.ceil((dataMax * 1.05) / 10) * 10;
return roundedMax;
},
],
};
return (
<ChartProvider value={chartContextValue}>
{children}
<div
ref={labelsRef}
style={{ position: "absolute", visibility: "hidden", height: 0, overflow: "hidden" }}
>
{validData
.map((d) => d[nameKey])
.map((label, idx) => (
<span key={idx} style={{ fontSize: 12, whiteSpace: "nowrap" }}>
{label}
</span>
))}
</div>
<div
className={classnames(className, styles.wrapper)}
style={{ flexGrow: 1, ...style }}
ref={wrapperRef}
>
<ResponsiveContainer
ref={containerRef}
minWidth={60}
minHeight={60}
debounce={100}
width="100%"
height="100%"
>
<RBarChart
accessibilityLayer
data={validData}
layout={layout}
margin={miniMode ? { left: 0, right: 0, top: 0, bottom: 0 } : chartMargin}
>
<CartesianGrid vertical={true} strokeDasharray="3 3" />
<XAxis {...xAxisProps} />
<YAxis {...yAxisProps} />
{!miniMode && !hideTooltip && (
<Tooltip
content={customTooltipRenderer}
wrapperStyle={{
pointerEvents: "auto",
}}
position={tooltipPosition}
/>
)}
{validData.length > 0 &&
Object.keys(config).map((key, index) => (
<Bar
key={index}
dataKey={key}
fill={config[key].color}
radius={stacked ? 0 : 8}
stackId={stacked ? "stacked" : undefined}
strokeWidth={1}
onMouseEnter={onMouseEnter}
/>
))}
{showLegend && (
<RLegend
wrapperStyle={{
bottom: 0,
left: 0,
right: 0,
margin: "0 auto",
width: "100%",
textAlign: "center",
}}
/>
)}
</RBarChart>
</ResponsiveContainer>
</div>
</ChartProvider>
);
}
```