This is page 38 of 181. Use http://codebase.md/xmlui-org/xmlui/mockApiDef.js?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .changeset
│ └── config.json
├── .eslintrc.cjs
├── .github
│ ├── build-checklist.png
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows
│ ├── deploy-blog.yml
│ ├── deploy-docs-optimized.yml
│ ├── deploy-docs.yml
│ ├── prepare-versions.yml
│ ├── release-packages.yml
│ ├── run-all-tests.yml
│ └── run-smoke-tests.yml
├── .gitignore
├── .prettierrc.js
├── .vscode
│ ├── launch.json
│ └── settings.json
├── blog
│ ├── .gitignore
│ ├── .gitkeep
│ ├── CHANGELOG.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── layout-changes.md
│ ├── package.json
│ ├── public
│ │ ├── blog
│ │ │ ├── images
│ │ │ │ ├── blog-page-component.png
│ │ │ │ ├── blog-scrabble.png
│ │ │ │ ├── integrated-blog-search.png
│ │ │ │ └── lorem-ipsum.png
│ │ │ ├── lorem-ipsum.md
│ │ │ ├── newest-post.md
│ │ │ ├── older-post.md
│ │ │ └── welcome-to-the-xmlui-blog.md
│ │ ├── mockServiceWorker.js
│ │ ├── resources
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ └── for-download
│ │ │ │ └── xmlui
│ │ │ │ └── xmlui-standalone.umd.js
│ │ │ ├── github.svg
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ ├── rss.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ └── PageNotFound.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── blog-theme.ts
│ └── tsconfig.json
├── CONTRIBUTING.md
├── docs
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── ComponentRefLinks.txt
│ ├── content
│ │ ├── _meta.json
│ │ ├── components
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── APICall.md
│ │ │ ├── App.md
│ │ │ ├── AppHeader.md
│ │ │ ├── AppState.md
│ │ │ ├── AutoComplete.md
│ │ │ ├── Avatar.md
│ │ │ ├── Backdrop.md
│ │ │ ├── Badge.md
│ │ │ ├── BarChart.md
│ │ │ ├── Bookmark.md
│ │ │ ├── Breakout.md
│ │ │ ├── Button.md
│ │ │ ├── Card.md
│ │ │ ├── Carousel.md
│ │ │ ├── ChangeListener.md
│ │ │ ├── Checkbox.md
│ │ │ ├── CHStack.md
│ │ │ ├── ColorPicker.md
│ │ │ ├── Column.md
│ │ │ ├── ContentSeparator.md
│ │ │ ├── CVStack.md
│ │ │ ├── DataSource.md
│ │ │ ├── DateInput.md
│ │ │ ├── DatePicker.md
│ │ │ ├── DonutChart.md
│ │ │ ├── DropdownMenu.md
│ │ │ ├── EmojiSelector.md
│ │ │ ├── ExpandableItem.md
│ │ │ ├── FileInput.md
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FlowLayout.md
│ │ │ ├── Footer.md
│ │ │ ├── Form.md
│ │ │ ├── FormItem.md
│ │ │ ├── FormSection.md
│ │ │ ├── Fragment.md
│ │ │ ├── H1.md
│ │ │ ├── H2.md
│ │ │ ├── H3.md
│ │ │ ├── H4.md
│ │ │ ├── H5.md
│ │ │ ├── H6.md
│ │ │ ├── Heading.md
│ │ │ ├── HSplitter.md
│ │ │ ├── HStack.md
│ │ │ ├── Icon.md
│ │ │ ├── IFrame.md
│ │ │ ├── Image.md
│ │ │ ├── Items.md
│ │ │ ├── LabelList.md
│ │ │ ├── Legend.md
│ │ │ ├── LineChart.md
│ │ │ ├── Link.md
│ │ │ ├── List.md
│ │ │ ├── Logo.md
│ │ │ ├── Markdown.md
│ │ │ ├── MenuItem.md
│ │ │ ├── MenuSeparator.md
│ │ │ ├── ModalDialog.md
│ │ │ ├── NavGroup.md
│ │ │ ├── NavLink.md
│ │ │ ├── NavPanel.md
│ │ │ ├── NoResult.md
│ │ │ ├── NumberBox.md
│ │ │ ├── Option.md
│ │ │ ├── Page.md
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── Pages.md
│ │ │ ├── Pagination.md
│ │ │ ├── PasswordInput.md
│ │ │ ├── PieChart.md
│ │ │ ├── ProgressBar.md
│ │ │ ├── Queue.md
│ │ │ ├── RadioGroup.md
│ │ │ ├── RealTimeAdapter.md
│ │ │ ├── Redirect.md
│ │ │ ├── Select.md
│ │ │ ├── Slider.md
│ │ │ ├── Slot.md
│ │ │ ├── SpaceFiller.md
│ │ │ ├── Spinner.md
│ │ │ ├── Splitter.md
│ │ │ ├── Stack.md
│ │ │ ├── StickyBox.md
│ │ │ ├── SubMenuItem.md
│ │ │ ├── Switch.md
│ │ │ ├── TabItem.md
│ │ │ ├── Table.md
│ │ │ ├── TableOfContents.md
│ │ │ ├── Tabs.md
│ │ │ ├── Text.md
│ │ │ ├── TextArea.md
│ │ │ ├── TextBox.md
│ │ │ ├── Theme.md
│ │ │ ├── TimeInput.md
│ │ │ ├── Timer.md
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneSwitch.md
│ │ │ ├── Tooltip.md
│ │ │ ├── Tree.md
│ │ │ ├── VSplitter.md
│ │ │ ├── VStack.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ ├── xmlui-spreadsheet
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Spreadsheet.md
│ │ │ └── xmlui-website-blocks
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Carousel.md
│ │ │ ├── HelloMd.md
│ │ │ ├── HeroSection.md
│ │ │ └── ScrollToTop.md
│ │ └── extensions
│ │ ├── _meta.json
│ │ ├── xmlui-animations
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Animation.md
│ │ │ ├── FadeAnimation.md
│ │ │ ├── FadeInAnimation.md
│ │ │ ├── FadeOutAnimation.md
│ │ │ ├── ScaleAnimation.md
│ │ │ └── SlideInAnimation.md
│ │ └── xmlui-website-blocks
│ │ ├── _meta.json
│ │ ├── _overview.md
│ │ ├── Carousel.md
│ │ ├── HelloMd.md
│ │ ├── HeroSection.md
│ │ └── ScrollToTop.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── package.json
│ ├── public
│ │ ├── feed.rss
│ │ ├── mockServiceWorker.js
│ │ ├── pages
│ │ │ ├── _meta.json
│ │ │ ├── app-structure.md
│ │ │ ├── build-editor-component.md
│ │ │ ├── build-hello-world-component.md
│ │ │ ├── components-intro.md
│ │ │ ├── context-variables.md
│ │ │ ├── forms.md
│ │ │ ├── globals.md
│ │ │ ├── glossary.md
│ │ │ ├── helper-tags.md
│ │ │ ├── hosted-deployment.md
│ │ │ ├── howto
│ │ │ │ ├── assign-a-complex-json-literal-to-a-component-variable.md
│ │ │ │ ├── chain-a-refetch.md
│ │ │ │ ├── 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
│ ├── 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
│ │ └── tsconfig.json
│ ├── 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
│ │ ├── tsconfig.json
│ │ └── 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
│ │ └── tsconfig.json
│ ├── 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
│ │ └── tsconfig.json
│ ├── 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
│ │ └── tsconfig.json
│ ├── xmlui-playground
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── hooks
│ │ │ │ ├── usePlayground.ts
│ │ │ │ └── useToast.ts
│ │ │ ├── index.tsx
│ │ │ ├── playground
│ │ │ │ ├── Box.module.scss
│ │ │ │ ├── Box.tsx
│ │ │ │ ├── CodeSelector.tsx
│ │ │ │ ├── ConfirmationDialog.module.scss
│ │ │ │ ├── ConfirmationDialog.tsx
│ │ │ │ ├── Editor.tsx
│ │ │ │ ├── Header.module.scss
│ │ │ │ ├── Header.tsx
│ │ │ │ ├── Playground.tsx
│ │ │ │ ├── PlaygroundContent.module.scss
│ │ │ │ ├── PlaygroundContent.tsx
│ │ │ │ ├── PlaygroundNative.module.scss
│ │ │ │ ├── PlaygroundNative.tsx
│ │ │ │ ├── Preview.module.scss
│ │ │ │ ├── Preview.tsx
│ │ │ │ ├── Select.module.scss
│ │ │ │ ├── StandalonePlayground.tsx
│ │ │ │ ├── StandalonePlaygroundNative.module.scss
│ │ │ │ ├── StandalonePlaygroundNative.tsx
│ │ │ │ ├── ThemeSwitcher.module.scss
│ │ │ │ ├── ThemeSwitcher.tsx
│ │ │ │ ├── ToneSwitcher.tsx
│ │ │ │ ├── Tooltip.module.scss
│ │ │ │ ├── Tooltip.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── providers
│ │ │ │ ├── Toast.module.scss
│ │ │ │ └── ToastProvider.tsx
│ │ │ ├── state
│ │ │ │ └── store.ts
│ │ │ ├── themes
│ │ │ │ └── theme.ts
│ │ │ └── utils
│ │ │ └── helpers.ts
│ │ └── tsconfig.json
│ ├── 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
│ │ └── tsconfig.json
│ ├── xmlui-spreadsheet
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── index.tsx
│ │ │ ├── Spreadsheet.tsx
│ │ │ └── SpreadsheetNative.tsx
│ │ └── tsconfig.json
│ └── 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.tsx
│ │ │ └── HeroSectionNative.tsx
│ │ ├── index.tsx
│ │ ├── ScrollToTop
│ │ │ ├── ScrollToTop.module.scss
│ │ │ ├── ScrollToTop.tsx
│ │ │ └── ScrollToTopNative.tsx
│ │ └── vite-env.d.ts
│ └── tsconfig.json
├── 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.js
│ ├── build-lib.ts
│ ├── build.ts
│ ├── index.ts
│ ├── preview.ts
│ ├── start.ts
│ ├── vite-xmlui-plugin.ts
│ └── viteConfig.ts
├── CHANGELOG.md
├── conventions
│ ├── component-qa-checklist.md
│ ├── copilot-conventions.md
│ ├── create-xmlui-components.md
│ ├── mermaid.md
│ ├── testing-conventions.md
│ └── xmlui-in-a-nutshell.md
├── dev-docs
│ ├── accessibility.md
│ ├── build-system.md
│ ├── build-xmlui.md
│ ├── component-behaviors.md
│ ├── components-with-options.md
│ ├── containers.md
│ ├── data-operations.md
│ ├── glossary.md
│ ├── index.md
│ ├── next
│ │ ├── component-dev-guide.md
│ │ ├── configuration-management-enhancement-summary.md
│ │ ├── documentation-scripts-refactoring-complete-summary.md
│ │ ├── documentation-scripts-refactoring-plan.md
│ │ ├── duplicate-pattern-extraction-summary.md
│ │ ├── error-handling-standardization-summary.md
│ │ ├── generating-component-reference.md
│ │ ├── index.md
│ │ ├── logging-consistency-implementation-summary.md
│ │ ├── project-build.md
│ │ ├── project-structure.md
│ │ ├── theme-context.md
│ │ ├── tiptap-design-considerations.md
│ │ ├── working-with-code.md
│ │ ├── xmlui-runtime-architecture
│ │ └── xmlui-wcag-accessibility-report.md
│ ├── react-fundamentals.md
│ ├── release-method.md
│ ├── standalone-app.md
│ ├── ud-components.md
│ └── xmlui-repo.md
├── package.json
├── playwright.config.ts
├── scripts
│ ├── coverage-only.js
│ ├── e2e-test-summary.js
│ ├── generate-docs
│ │ ├── build-downloads-map.mjs
│ │ ├── build-pages-map.mjs
│ │ ├── components-config.json
│ │ ├── configuration-management.mjs
│ │ ├── constants.mjs
│ │ ├── create-theme-files.mjs
│ │ ├── DocsGenerator.mjs
│ │ ├── error-handling.mjs
│ │ ├── extensions-config.json
│ │ ├── folders.mjs
│ │ ├── generate-summary-files.mjs
│ │ ├── get-docs.mjs
│ │ ├── input-handler.mjs
│ │ ├── logger.mjs
│ │ ├── logging-standards.mjs
│ │ ├── MetadataProcessor.mjs
│ │ ├── pattern-utilities.mjs
│ │ └── utils.mjs
│ ├── get-langserver-metadata.mjs
│ ├── inline-links.mjs
│ └── README-e2e-summary.md
├── src
│ ├── abstractions
│ │ ├── _conventions.md
│ │ ├── ActionDefs.ts
│ │ ├── AppContextDefs.ts
│ │ ├── ComponentDefs.ts
│ │ ├── ContainerDefs.ts
│ │ ├── ExtensionDefs.ts
│ │ ├── FunctionDefs.ts
│ │ ├── RendererDefs.ts
│ │ ├── scripting
│ │ │ ├── BlockScope.ts
│ │ │ ├── Compilation.ts
│ │ │ ├── LogicalThread.ts
│ │ │ ├── LoopScope.ts
│ │ │ ├── modules.ts
│ │ │ ├── ScriptParserError.ts
│ │ │ ├── Token.ts
│ │ │ ├── TryScope.ts
│ │ │ └── TryScopeExp.ts
│ │ └── ThemingDefs.ts
│ ├── components
│ │ ├── _conventions.md
│ │ ├── abstractions.ts
│ │ ├── Accordion
│ │ │ ├── Accordion.md
│ │ │ ├── Accordion.module.scss
│ │ │ ├── Accordion.spec.ts
│ │ │ ├── Accordion.tsx
│ │ │ ├── AccordionContext.tsx
│ │ │ ├── AccordionItem.tsx
│ │ │ ├── AccordionItemNative.tsx
│ │ │ └── AccordionNative.tsx
│ │ ├── Animation
│ │ │ └── AnimationNative.tsx
│ │ ├── APICall
│ │ │ ├── APICall.md
│ │ │ ├── APICall.spec.ts
│ │ │ ├── APICall.tsx
│ │ │ └── APICallNative.tsx
│ │ ├── App
│ │ │ ├── App.md
│ │ │ ├── App.module.scss
│ │ │ ├── App.spec.ts
│ │ │ ├── App.tsx
│ │ │ ├── AppLayoutContext.ts
│ │ │ ├── AppNative.tsx
│ │ │ ├── AppStateContext.ts
│ │ │ ├── doc-resources
│ │ │ │ ├── condensed-sticky.xmlui
│ │ │ │ ├── condensed.xmlui
│ │ │ │ ├── horizontal-sticky.xmlui
│ │ │ │ ├── horizontal.xmlui
│ │ │ │ ├── vertical-full-header.xmlui
│ │ │ │ ├── vertical-sticky.xmlui
│ │ │ │ └── vertical.xmlui
│ │ │ ├── IndexerContext.ts
│ │ │ ├── LinkInfoContext.ts
│ │ │ ├── SearchContext.tsx
│ │ │ ├── Sheet.module.scss
│ │ │ └── Sheet.tsx
│ │ ├── AppHeader
│ │ │ ├── AppHeader.md
│ │ │ ├── AppHeader.module.scss
│ │ │ ├── AppHeader.spec.ts
│ │ │ ├── AppHeader.tsx
│ │ │ └── AppHeaderNative.tsx
│ │ ├── AppState
│ │ │ ├── AppState.md
│ │ │ ├── AppState.spec.ts
│ │ │ ├── AppState.tsx
│ │ │ └── AppStateNative.tsx
│ │ ├── AutoComplete
│ │ │ ├── AutoComplete.md
│ │ │ ├── AutoComplete.module.scss
│ │ │ ├── AutoComplete.spec.ts
│ │ │ ├── AutoComplete.tsx
│ │ │ ├── AutoCompleteContext.tsx
│ │ │ └── AutoCompleteNative.tsx
│ │ ├── Avatar
│ │ │ ├── Avatar.md
│ │ │ ├── Avatar.module.scss
│ │ │ ├── Avatar.spec.ts
│ │ │ ├── Avatar.tsx
│ │ │ └── AvatarNative.tsx
│ │ ├── Backdrop
│ │ │ ├── Backdrop.md
│ │ │ ├── Backdrop.module.scss
│ │ │ ├── Backdrop.spec.ts
│ │ │ ├── Backdrop.tsx
│ │ │ └── BackdropNative.tsx
│ │ ├── Badge
│ │ │ ├── Badge.md
│ │ │ ├── Badge.module.scss
│ │ │ ├── Badge.spec.ts
│ │ │ ├── Badge.tsx
│ │ │ └── BadgeNative.tsx
│ │ ├── Bookmark
│ │ │ ├── Bookmark.md
│ │ │ ├── Bookmark.module.scss
│ │ │ ├── Bookmark.spec.ts
│ │ │ ├── Bookmark.tsx
│ │ │ └── BookmarkNative.tsx
│ │ ├── Breakout
│ │ │ ├── Breakout.module.scss
│ │ │ ├── Breakout.spec.ts
│ │ │ ├── Breakout.tsx
│ │ │ └── BreakoutNative.tsx
│ │ ├── Button
│ │ │ ├── Button-style.spec.ts
│ │ │ ├── Button.md
│ │ │ ├── Button.module.scss
│ │ │ ├── Button.spec.ts
│ │ │ ├── Button.tsx
│ │ │ └── ButtonNative.tsx
│ │ ├── Card
│ │ │ ├── Card.md
│ │ │ ├── Card.module.scss
│ │ │ ├── Card.spec.ts
│ │ │ ├── Card.tsx
│ │ │ └── CardNative.tsx
│ │ ├── Carousel
│ │ │ ├── Carousel.md
│ │ │ ├── Carousel.module.scss
│ │ │ ├── Carousel.spec.ts
│ │ │ ├── Carousel.tsx
│ │ │ ├── CarouselContext.tsx
│ │ │ ├── CarouselItem.tsx
│ │ │ ├── CarouselItemNative.tsx
│ │ │ └── CarouselNative.tsx
│ │ ├── ChangeListener
│ │ │ ├── ChangeListener.md
│ │ │ ├── ChangeListener.spec.ts
│ │ │ ├── ChangeListener.tsx
│ │ │ └── ChangeListenerNative.tsx
│ │ ├── chart-color-schemes.ts
│ │ ├── Charts
│ │ │ ├── AreaChart
│ │ │ │ ├── AreaChart.md
│ │ │ │ ├── AreaChart.spec.ts
│ │ │ │ ├── AreaChart.tsx
│ │ │ │ └── AreaChartNative.tsx
│ │ │ ├── BarChart
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── BarChart.module.scss
│ │ │ │ ├── BarChart.spec.ts
│ │ │ │ ├── BarChart.tsx
│ │ │ │ └── BarChartNative.tsx
│ │ │ ├── DonutChart
│ │ │ │ ├── DonutChart.spec.ts
│ │ │ │ └── DonutChart.tsx
│ │ │ ├── LabelList
│ │ │ │ ├── LabelList.spec.ts
│ │ │ │ ├── LabelList.tsx
│ │ │ │ ├── LabelListNative.module.scss
│ │ │ │ └── LabelListNative.tsx
│ │ │ ├── Legend
│ │ │ │ ├── Legend.spec.ts
│ │ │ │ ├── Legend.tsx
│ │ │ │ └── LegendNative.tsx
│ │ │ ├── LineChart
│ │ │ │ ├── LineChart.md
│ │ │ │ ├── LineChart.module.scss
│ │ │ │ ├── LineChart.spec.ts
│ │ │ │ ├── LineChart.tsx
│ │ │ │ └── LineChartNative.tsx
│ │ │ ├── PieChart
│ │ │ │ ├── PieChart.md
│ │ │ │ ├── PieChart.spec.ts
│ │ │ │ ├── PieChart.tsx
│ │ │ │ ├── PieChartNative.module.scss
│ │ │ │ └── PieChartNative.tsx
│ │ │ ├── RadarChart
│ │ │ │ ├── RadarChart.md
│ │ │ │ ├── RadarChart.spec.ts
│ │ │ │ ├── RadarChart.tsx
│ │ │ │ └── RadarChartNative.tsx
│ │ │ ├── Tooltip
│ │ │ │ ├── TooltipContent.module.scss
│ │ │ │ ├── TooltipContent.spec.ts
│ │ │ │ └── TooltipContent.tsx
│ │ │ └── utils
│ │ │ ├── abstractions.ts
│ │ │ └── ChartProvider.tsx
│ │ ├── Checkbox
│ │ │ ├── Checkbox.md
│ │ │ ├── Checkbox.spec.ts
│ │ │ └── Checkbox.tsx
│ │ ├── CodeBlock
│ │ │ ├── CodeBlock.module.scss
│ │ │ ├── CodeBlock.spec.ts
│ │ │ ├── CodeBlock.tsx
│ │ │ ├── CodeBlockNative.tsx
│ │ │ └── highlight-code.ts
│ │ ├── collectedComponentMetadata.ts
│ │ ├── ColorPicker
│ │ │ ├── ColorPicker.md
│ │ │ ├── ColorPicker.module.scss
│ │ │ ├── ColorPicker.spec.ts
│ │ │ ├── ColorPicker.tsx
│ │ │ └── ColorPickerNative.tsx
│ │ ├── Column
│ │ │ ├── Column.md
│ │ │ ├── Column.tsx
│ │ │ ├── ColumnNative.tsx
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ └── TableContext.tsx
│ │ ├── component-utils.ts
│ │ ├── ComponentProvider.tsx
│ │ ├── ComponentRegistryContext.tsx
│ │ ├── container-helpers.tsx
│ │ ├── ContentSeparator
│ │ │ ├── ContentSeparator.md
│ │ │ ├── ContentSeparator.module.scss
│ │ │ ├── ContentSeparator.spec.ts
│ │ │ ├── ContentSeparator.tsx
│ │ │ └── ContentSeparatorNative.tsx
│ │ ├── DataSource
│ │ │ ├── DataSource.md
│ │ │ └── DataSource.tsx
│ │ ├── DateInput
│ │ │ ├── DateInput.md
│ │ │ ├── DateInput.module.scss
│ │ │ ├── DateInput.spec.ts
│ │ │ ├── DateInput.tsx
│ │ │ └── DateInputNative.tsx
│ │ ├── DatePicker
│ │ │ ├── DatePicker.md
│ │ │ ├── DatePicker.module.scss
│ │ │ ├── DatePicker.spec.ts
│ │ │ ├── DatePicker.tsx
│ │ │ └── DatePickerNative.tsx
│ │ ├── DropdownMenu
│ │ │ ├── DropdownMenu.md
│ │ │ ├── DropdownMenu.module.scss
│ │ │ ├── DropdownMenu.spec.ts
│ │ │ ├── DropdownMenu.tsx
│ │ │ ├── DropdownMenuNative.tsx
│ │ │ ├── MenuItem.md
│ │ │ └── SubMenuItem.md
│ │ ├── EmojiSelector
│ │ │ ├── EmojiSelector.md
│ │ │ ├── EmojiSelector.spec.ts
│ │ │ ├── EmojiSelector.tsx
│ │ │ └── EmojiSelectorNative.tsx
│ │ ├── ExpandableItem
│ │ │ ├── ExpandableItem.module.scss
│ │ │ ├── ExpandableItem.spec.ts
│ │ │ ├── ExpandableItem.tsx
│ │ │ └── ExpandableItemNative.tsx
│ │ ├── FileInput
│ │ │ ├── FileInput.md
│ │ │ ├── FileInput.module.scss
│ │ │ ├── FileInput.spec.ts
│ │ │ ├── FileInput.tsx
│ │ │ └── FileInputNative.tsx
│ │ ├── FileUploadDropZone
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FileUploadDropZone.module.scss
│ │ │ ├── FileUploadDropZone.spec.ts
│ │ │ ├── FileUploadDropZone.tsx
│ │ │ └── FileUploadDropZoneNative.tsx
│ │ ├── FlowLayout
│ │ │ ├── FlowLayout.md
│ │ │ ├── FlowLayout.module.scss
│ │ │ ├── FlowLayout.spec.ts
│ │ │ ├── FlowLayout.spec.ts-snapshots
│ │ │ │ └── Edge-cases-boxShadow-is-not-clipped-1-non-smoke-darwin.png
│ │ │ ├── FlowLayout.tsx
│ │ │ └── FlowLayoutNative.tsx
│ │ ├── Footer
│ │ │ ├── Footer.md
│ │ │ ├── Footer.module.scss
│ │ │ ├── Footer.spec.ts
│ │ │ ├── Footer.tsx
│ │ │ └── FooterNative.tsx
│ │ ├── Form
│ │ │ ├── Form.md
│ │ │ ├── Form.module.scss
│ │ │ ├── Form.spec.ts
│ │ │ ├── Form.tsx
│ │ │ ├── formActions.ts
│ │ │ ├── FormContext.ts
│ │ │ └── FormNative.tsx
│ │ ├── FormItem
│ │ │ ├── FormItem.md
│ │ │ ├── FormItem.module.scss
│ │ │ ├── FormItem.spec.ts
│ │ │ ├── FormItem.tsx
│ │ │ ├── FormItemNative.tsx
│ │ │ ├── HelperText.module.scss
│ │ │ ├── HelperText.tsx
│ │ │ ├── ItemWithLabel.tsx
│ │ │ └── Validations.ts
│ │ ├── FormSection
│ │ │ ├── FormSection.md
│ │ │ ├── FormSection.ts
│ │ │ └── FormSection.xmlui
│ │ ├── Fragment
│ │ │ ├── Fragment.spec.ts
│ │ │ └── Fragment.tsx
│ │ ├── Heading
│ │ │ ├── abstractions.ts
│ │ │ ├── H1.md
│ │ │ ├── H1.spec.ts
│ │ │ ├── H2.md
│ │ │ ├── H2.spec.ts
│ │ │ ├── H3.md
│ │ │ ├── H3.spec.ts
│ │ │ ├── H4.md
│ │ │ ├── H4.spec.ts
│ │ │ ├── H5.md
│ │ │ ├── H5.spec.ts
│ │ │ ├── H6.md
│ │ │ ├── H6.spec.ts
│ │ │ ├── Heading.md
│ │ │ ├── Heading.module.scss
│ │ │ ├── Heading.spec.ts
│ │ │ ├── Heading.tsx
│ │ │ └── HeadingNative.tsx
│ │ ├── HoverCard
│ │ │ ├── HoverCard.tsx
│ │ │ └── HovercardNative.tsx
│ │ ├── HtmlTags
│ │ │ ├── HtmlTags.module.scss
│ │ │ ├── HtmlTags.spec.ts
│ │ │ └── HtmlTags.tsx
│ │ ├── Icon
│ │ │ ├── AdmonitionDanger.tsx
│ │ │ ├── AdmonitionInfo.tsx
│ │ │ ├── AdmonitionNote.tsx
│ │ │ ├── AdmonitionTip.tsx
│ │ │ ├── AdmonitionWarning.tsx
│ │ │ ├── ApiIcon.tsx
│ │ │ ├── ArrowDropDown.module.scss
│ │ │ ├── ArrowDropDown.tsx
│ │ │ ├── ArrowDropUp.module.scss
│ │ │ ├── ArrowDropUp.tsx
│ │ │ ├── ArrowLeft.module.scss
│ │ │ ├── ArrowLeft.tsx
│ │ │ ├── ArrowRight.module.scss
│ │ │ ├── ArrowRight.tsx
│ │ │ ├── Attach.tsx
│ │ │ ├── Binding.module.scss
│ │ │ ├── Binding.tsx
│ │ │ ├── BoardIcon.tsx
│ │ │ ├── BoxIcon.tsx
│ │ │ ├── CheckIcon.tsx
│ │ │ ├── ChevronDownIcon.tsx
│ │ │ ├── ChevronLeft.tsx
│ │ │ ├── ChevronRight.tsx
│ │ │ ├── ChevronUpIcon.tsx
│ │ │ ├── CodeFileIcon.tsx
│ │ │ ├── CodeSandbox.tsx
│ │ │ ├── CompactListIcon.tsx
│ │ │ ├── ContentCopyIcon.tsx
│ │ │ ├── DarkToLightIcon.tsx
│ │ │ ├── DatabaseIcon.module.scss
│ │ │ ├── DatabaseIcon.tsx
│ │ │ ├── DocFileIcon.tsx
│ │ │ ├── DocIcon.tsx
│ │ │ ├── DotMenuHorizontalIcon.tsx
│ │ │ ├── DotMenuIcon.tsx
│ │ │ ├── EmailIcon.tsx
│ │ │ ├── EmptyFolderIcon.tsx
│ │ │ ├── ErrorIcon.tsx
│ │ │ ├── ExpressionIcon.tsx
│ │ │ ├── FillPlusCricleIcon.tsx
│ │ │ ├── FilterIcon.tsx
│ │ │ ├── FolderIcon.tsx
│ │ │ ├── GlobeIcon.tsx
│ │ │ ├── HomeIcon.tsx
│ │ │ ├── HyperLinkIcon.tsx
│ │ │ ├── Icon.md
│ │ │ ├── Icon.module.scss
│ │ │ ├── Icon.spec.ts
│ │ │ ├── Icon.tsx
│ │ │ ├── IconNative.tsx
│ │ │ ├── ImageFileIcon.tsx
│ │ │ ├── Inspect.tsx
│ │ │ ├── LightToDark.tsx
│ │ │ ├── LinkIcon.tsx
│ │ │ ├── ListIcon.tsx
│ │ │ ├── LooseListIcon.tsx
│ │ │ ├── MoonIcon.tsx
│ │ │ ├── MoreOptionsIcon.tsx
│ │ │ ├── NoSortIcon.tsx
│ │ │ ├── PDFIcon.tsx
│ │ │ ├── PenIcon.tsx
│ │ │ ├── PhoneIcon.tsx
│ │ │ ├── PhotoIcon.tsx
│ │ │ ├── PlusIcon.tsx
│ │ │ ├── SearchIcon.tsx
│ │ │ ├── ShareIcon.tsx
│ │ │ ├── SortAscendingIcon.tsx
│ │ │ ├── SortDescendingIcon.tsx
│ │ │ ├── StarsIcon.tsx
│ │ │ ├── SunIcon.tsx
│ │ │ ├── svg
│ │ │ │ ├── admonition_danger.svg
│ │ │ │ ├── admonition_info.svg
│ │ │ │ ├── admonition_note.svg
│ │ │ │ ├── admonition_tip.svg
│ │ │ │ ├── admonition_warning.svg
│ │ │ │ ├── api.svg
│ │ │ │ ├── arrow-dropdown.svg
│ │ │ │ ├── arrow-left.svg
│ │ │ │ ├── arrow-right.svg
│ │ │ │ ├── arrow-up.svg
│ │ │ │ ├── attach.svg
│ │ │ │ ├── binding.svg
│ │ │ │ ├── box.svg
│ │ │ │ ├── bulb.svg
│ │ │ │ ├── code-file.svg
│ │ │ │ ├── code-sandbox.svg
│ │ │ │ ├── dark_to_light.svg
│ │ │ │ ├── database.svg
│ │ │ │ ├── doc.svg
│ │ │ │ ├── empty-folder.svg
│ │ │ │ ├── expression.svg
│ │ │ │ ├── eye-closed.svg
│ │ │ │ ├── eye-dark.svg
│ │ │ │ ├── eye.svg
│ │ │ │ ├── file-text.svg
│ │ │ │ ├── filter.svg
│ │ │ │ ├── folder.svg
│ │ │ │ ├── img.svg
│ │ │ │ ├── inspect.svg
│ │ │ │ ├── light_to_dark.svg
│ │ │ │ ├── moon.svg
│ │ │ │ ├── pdf.svg
│ │ │ │ ├── photo.svg
│ │ │ │ ├── share.svg
│ │ │ │ ├── stars.svg
│ │ │ │ ├── sun.svg
│ │ │ │ ├── trending-down.svg
│ │ │ │ ├── trending-level.svg
│ │ │ │ ├── trending-up.svg
│ │ │ │ ├── txt.svg
│ │ │ │ ├── unknown-file.svg
│ │ │ │ ├── unlink.svg
│ │ │ │ └── xls.svg
│ │ │ ├── TableDeleteColumnIcon.tsx
│ │ │ ├── TableDeleteRowIcon.tsx
│ │ │ ├── TableInsertColumnIcon.tsx
│ │ │ ├── TableInsertRowIcon.tsx
│ │ │ ├── TrashIcon.tsx
│ │ │ ├── TrendingDownIcon.tsx
│ │ │ ├── TrendingLevelIcon.tsx
│ │ │ ├── TrendingUpIcon.tsx
│ │ │ ├── TxtIcon.tsx
│ │ │ ├── UnknownFileIcon.tsx
│ │ │ ├── UnlinkIcon.tsx
│ │ │ ├── UserIcon.tsx
│ │ │ ├── WarningIcon.tsx
│ │ │ └── XlsIcon.tsx
│ │ ├── IconProvider.tsx
│ │ ├── IconRegistryContext.tsx
│ │ ├── IFrame
│ │ │ ├── IFrame.md
│ │ │ ├── IFrame.module.scss
│ │ │ ├── IFrame.spec.ts
│ │ │ ├── IFrame.tsx
│ │ │ └── IFrameNative.tsx
│ │ ├── Image
│ │ │ ├── Image.md
│ │ │ ├── Image.module.scss
│ │ │ ├── Image.spec.ts
│ │ │ ├── Image.tsx
│ │ │ └── ImageNative.tsx
│ │ ├── Input
│ │ │ ├── index.ts
│ │ │ ├── InputAdornment.module.scss
│ │ │ ├── InputAdornment.tsx
│ │ │ ├── InputDivider.module.scss
│ │ │ ├── InputDivider.tsx
│ │ │ ├── InputLabel.module.scss
│ │ │ ├── InputLabel.tsx
│ │ │ ├── PartialInput.module.scss
│ │ │ └── PartialInput.tsx
│ │ ├── InspectButton
│ │ │ ├── InspectButton.module.scss
│ │ │ └── InspectButton.tsx
│ │ ├── Items
│ │ │ ├── Items.md
│ │ │ ├── Items.spec.ts
│ │ │ ├── Items.tsx
│ │ │ └── ItemsNative.tsx
│ │ ├── Link
│ │ │ ├── Link.md
│ │ │ ├── Link.module.scss
│ │ │ ├── Link.spec.ts
│ │ │ ├── Link.tsx
│ │ │ └── LinkNative.tsx
│ │ ├── List
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── List.md
│ │ │ ├── List.module.scss
│ │ │ ├── List.spec.ts
│ │ │ ├── List.tsx
│ │ │ └── ListNative.tsx
│ │ ├── Logo
│ │ │ ├── doc-resources
│ │ │ │ └── xmlui-logo.svg
│ │ │ ├── Logo.md
│ │ │ ├── Logo.tsx
│ │ │ └── LogoNative.tsx
│ │ ├── Markdown
│ │ │ ├── CodeText.module.scss
│ │ │ ├── CodeText.tsx
│ │ │ ├── Markdown.md
│ │ │ ├── Markdown.module.scss
│ │ │ ├── Markdown.spec.ts
│ │ │ ├── Markdown.tsx
│ │ │ ├── MarkdownNative.tsx
│ │ │ ├── parse-binding-expr.ts
│ │ │ └── utils.ts
│ │ ├── metadata-helpers.ts
│ │ ├── ModalDialog
│ │ │ ├── ConfirmationModalContextProvider.tsx
│ │ │ ├── Dialog.module.scss
│ │ │ ├── Dialog.tsx
│ │ │ ├── ModalDialog.md
│ │ │ ├── ModalDialog.module.scss
│ │ │ ├── ModalDialog.spec.ts
│ │ │ ├── ModalDialog.tsx
│ │ │ ├── ModalDialogNative.tsx
│ │ │ └── ModalVisibilityContext.tsx
│ │ ├── NavGroup
│ │ │ ├── NavGroup.md
│ │ │ ├── NavGroup.module.scss
│ │ │ ├── NavGroup.spec.ts
│ │ │ ├── NavGroup.tsx
│ │ │ ├── NavGroupContext.ts
│ │ │ └── NavGroupNative.tsx
│ │ ├── NavLink
│ │ │ ├── NavLink.md
│ │ │ ├── NavLink.module.scss
│ │ │ ├── NavLink.spec.ts
│ │ │ ├── NavLink.tsx
│ │ │ └── NavLinkNative.tsx
│ │ ├── NavPanel
│ │ │ ├── NavPanel.md
│ │ │ ├── NavPanel.module.scss
│ │ │ ├── NavPanel.spec.ts
│ │ │ ├── NavPanel.tsx
│ │ │ └── NavPanelNative.tsx
│ │ ├── NestedApp
│ │ │ ├── AppWithCodeView.module.scss
│ │ │ ├── AppWithCodeView.tsx
│ │ │ ├── AppWithCodeViewNative.tsx
│ │ │ ├── defaultProps.tsx
│ │ │ ├── logo.svg
│ │ │ ├── NestedApp.module.scss
│ │ │ ├── NestedApp.tsx
│ │ │ ├── NestedAppNative.tsx
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.tsx
│ │ │ └── utils.ts
│ │ ├── NoResult
│ │ │ ├── NoResult.md
│ │ │ ├── NoResult.module.scss
│ │ │ ├── NoResult.spec.ts
│ │ │ ├── NoResult.tsx
│ │ │ └── NoResultNative.tsx
│ │ ├── NumberBox
│ │ │ ├── numberbox-abstractions.ts
│ │ │ ├── NumberBox.md
│ │ │ ├── NumberBox.module.scss
│ │ │ ├── NumberBox.spec.ts
│ │ │ ├── NumberBox.tsx
│ │ │ └── NumberBoxNative.tsx
│ │ ├── Option
│ │ │ ├── Option.md
│ │ │ ├── Option.spec.ts
│ │ │ ├── Option.tsx
│ │ │ ├── OptionNative.tsx
│ │ │ └── OptionTypeProvider.tsx
│ │ ├── PageMetaTitle
│ │ │ ├── PageMetaTilteNative.tsx
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── PageMetaTitle.spec.ts
│ │ │ └── PageMetaTitle.tsx
│ │ ├── Pages
│ │ │ ├── Page.md
│ │ │ ├── Pages.md
│ │ │ ├── Pages.module.scss
│ │ │ ├── Pages.tsx
│ │ │ └── PagesNative.tsx
│ │ ├── Pagination
│ │ │ ├── Pagination.md
│ │ │ ├── Pagination.module.scss
│ │ │ ├── Pagination.spec.ts
│ │ │ ├── Pagination.tsx
│ │ │ └── PaginationNative.tsx
│ │ ├── PositionedContainer
│ │ │ ├── PositionedContainer.module.scss
│ │ │ ├── PositionedContainer.tsx
│ │ │ └── PositionedContainerNative.tsx
│ │ ├── ProfileMenu
│ │ │ ├── ProfileMenu.module.scss
│ │ │ └── ProfileMenu.tsx
│ │ ├── ProgressBar
│ │ │ ├── ProgressBar.md
│ │ │ ├── ProgressBar.module.scss
│ │ │ ├── ProgressBar.spec.ts
│ │ │ ├── ProgressBar.tsx
│ │ │ └── ProgressBarNative.tsx
│ │ ├── Queue
│ │ │ ├── Queue.md
│ │ │ ├── Queue.spec.ts
│ │ │ ├── Queue.tsx
│ │ │ ├── queueActions.ts
│ │ │ └── QueueNative.tsx
│ │ ├── RadioGroup
│ │ │ ├── RadioGroup.md
│ │ │ ├── RadioGroup.module.scss
│ │ │ ├── RadioGroup.spec.ts
│ │ │ ├── RadioGroup.tsx
│ │ │ ├── RadioGroupNative.tsx
│ │ │ ├── RadioItem.tsx
│ │ │ └── RadioItemNative.tsx
│ │ ├── RealTimeAdapter
│ │ │ ├── RealTimeAdapter.tsx
│ │ │ └── RealTimeAdapterNative.tsx
│ │ ├── Redirect
│ │ │ ├── Redirect.md
│ │ │ ├── Redirect.spec.ts
│ │ │ └── Redirect.tsx
│ │ ├── ResponsiveBar
│ │ │ ├── README.md
│ │ │ ├── ResponsiveBar.md
│ │ │ ├── ResponsiveBar.module.scss
│ │ │ ├── ResponsiveBar.spec.ts
│ │ │ ├── ResponsiveBar.tsx
│ │ │ └── ResponsiveBarNative.tsx
│ │ ├── Select
│ │ │ ├── HiddenOption.tsx
│ │ │ ├── OptionContext.ts
│ │ │ ├── Select.md
│ │ │ ├── Select.module.scss
│ │ │ ├── Select.spec.ts
│ │ │ ├── Select.tsx
│ │ │ ├── SelectContext.tsx
│ │ │ └── SelectNative.tsx
│ │ ├── SelectionStore
│ │ │ ├── SelectionStore.md
│ │ │ ├── SelectionStore.tsx
│ │ │ └── SelectionStoreNative.tsx
│ │ ├── Slider
│ │ │ ├── Slider.md
│ │ │ ├── Slider.module.scss
│ │ │ ├── Slider.spec.ts
│ │ │ ├── Slider.tsx
│ │ │ └── SliderNative.tsx
│ │ ├── Slot
│ │ │ ├── Slot.md
│ │ │ ├── Slot.spec.ts
│ │ │ └── Slot.ts
│ │ ├── SlotItem.tsx
│ │ ├── SpaceFiller
│ │ │ ├── SpaceFiller.md
│ │ │ ├── SpaceFiller.module.scss
│ │ │ ├── SpaceFiller.spec.ts
│ │ │ ├── SpaceFiller.tsx
│ │ │ └── SpaceFillerNative.tsx
│ │ ├── Spinner
│ │ │ ├── Spinner.md
│ │ │ ├── Spinner.module.scss
│ │ │ ├── Spinner.spec.ts
│ │ │ ├── Spinner.tsx
│ │ │ └── SpinnerNative.tsx
│ │ ├── Splitter
│ │ │ ├── HSplitter.md
│ │ │ ├── HSplitter.spec.ts
│ │ │ ├── Splitter.md
│ │ │ ├── Splitter.module.scss
│ │ │ ├── Splitter.spec.ts
│ │ │ ├── Splitter.tsx
│ │ │ ├── SplitterNative.tsx
│ │ │ ├── utils.ts
│ │ │ ├── VSplitter.md
│ │ │ └── VSplitter.spec.ts
│ │ ├── Stack
│ │ │ ├── CHStack.md
│ │ │ ├── CHStack.spec.ts
│ │ │ ├── CVStack.md
│ │ │ ├── CVStack.spec.ts
│ │ │ ├── HStack.md
│ │ │ ├── HStack.spec.ts
│ │ │ ├── Stack.md
│ │ │ ├── Stack.module.scss
│ │ │ ├── Stack.spec.ts
│ │ │ ├── Stack.tsx
│ │ │ ├── StackNative.tsx
│ │ │ ├── VStack.md
│ │ │ └── VStack.spec.ts
│ │ ├── StickyBox
│ │ │ ├── StickyBox.md
│ │ │ ├── StickyBox.module.scss
│ │ │ ├── StickyBox.tsx
│ │ │ └── StickyBoxNative.tsx
│ │ ├── Switch
│ │ │ ├── Switch.md
│ │ │ ├── Switch.spec.ts
│ │ │ └── Switch.tsx
│ │ ├── Table
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── react-table-config.d.ts
│ │ │ ├── Table.md
│ │ │ ├── Table.module.scss
│ │ │ ├── Table.spec.ts
│ │ │ ├── Table.tsx
│ │ │ ├── TableNative.tsx
│ │ │ └── useRowSelection.tsx
│ │ ├── TableOfContents
│ │ │ ├── TableOfContents.module.scss
│ │ │ ├── TableOfContents.spec.ts
│ │ │ ├── TableOfContents.tsx
│ │ │ └── TableOfContentsNative.tsx
│ │ ├── Tabs
│ │ │ ├── TabContext.tsx
│ │ │ ├── TabItem.md
│ │ │ ├── TabItem.tsx
│ │ │ ├── TabItemNative.tsx
│ │ │ ├── Tabs.md
│ │ │ ├── Tabs.module.scss
│ │ │ ├── Tabs.spec.ts
│ │ │ ├── Tabs.tsx
│ │ │ └── TabsNative.tsx
│ │ ├── Text
│ │ │ ├── Text.md
│ │ │ ├── Text.module.scss
│ │ │ ├── Text.spec.ts
│ │ │ ├── Text.tsx
│ │ │ └── TextNative.tsx
│ │ ├── TextArea
│ │ │ ├── TextArea.md
│ │ │ ├── TextArea.module.scss
│ │ │ ├── TextArea.spec.ts
│ │ │ ├── TextArea.tsx
│ │ │ ├── TextAreaNative.tsx
│ │ │ ├── TextAreaResizable.tsx
│ │ │ └── useComposedRef.ts
│ │ ├── TextBox
│ │ │ ├── TextBox.md
│ │ │ ├── TextBox.module.scss
│ │ │ ├── TextBox.spec.ts
│ │ │ ├── TextBox.tsx
│ │ │ └── TextBoxNative.tsx
│ │ ├── Theme
│ │ │ ├── NotificationToast.tsx
│ │ │ ├── Theme.md
│ │ │ ├── Theme.module.scss
│ │ │ ├── Theme.spec.ts
│ │ │ ├── Theme.tsx
│ │ │ └── ThemeNative.tsx
│ │ ├── TimeInput
│ │ │ ├── TimeInput.md
│ │ │ ├── TimeInput.module.scss
│ │ │ ├── TimeInput.spec.ts
│ │ │ ├── TimeInput.tsx
│ │ │ ├── TimeInputNative.tsx
│ │ │ └── utils.ts
│ │ ├── Timer
│ │ │ ├── Timer.md
│ │ │ ├── Timer.spec.ts
│ │ │ ├── Timer.tsx
│ │ │ └── TimerNative.tsx
│ │ ├── Toggle
│ │ │ ├── Toggle.module.scss
│ │ │ └── Toggle.tsx
│ │ ├── ToneChangerButton
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneChangerButton.spec.ts
│ │ │ └── ToneChangerButton.tsx
│ │ ├── ToneSwitch
│ │ │ ├── ToneSwitch.md
│ │ │ ├── ToneSwitch.module.scss
│ │ │ ├── ToneSwitch.spec.ts
│ │ │ ├── ToneSwitch.tsx
│ │ │ └── ToneSwitchNative.tsx
│ │ ├── Tooltip
│ │ │ ├── Tooltip.md
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.spec.ts
│ │ │ ├── Tooltip.tsx
│ │ │ └── TooltipNative.tsx
│ │ ├── Tree
│ │ │ ├── testData.ts
│ │ │ ├── Tree-dynamic.spec.ts
│ │ │ ├── Tree-icons.spec.ts
│ │ │ ├── Tree.md
│ │ │ ├── Tree.spec.ts
│ │ │ ├── TreeComponent.module.scss
│ │ │ ├── TreeComponent.tsx
│ │ │ └── TreeNative.tsx
│ │ ├── TreeDisplay
│ │ │ ├── TreeDisplay.md
│ │ │ ├── TreeDisplay.module.scss
│ │ │ ├── TreeDisplay.tsx
│ │ │ └── TreeDisplayNative.tsx
│ │ ├── ValidationSummary
│ │ │ ├── ValidationSummary.module.scss
│ │ │ └── ValidationSummary.tsx
│ │ └── VisuallyHidden.tsx
│ ├── components-core
│ │ ├── abstractions
│ │ │ ├── ComponentRenderer.ts
│ │ │ ├── LoaderRenderer.ts
│ │ │ ├── standalone.ts
│ │ │ └── treeAbstractions.ts
│ │ ├── action
│ │ │ ├── actions.ts
│ │ │ ├── APICall.tsx
│ │ │ ├── FileDownloadAction.tsx
│ │ │ ├── FileUploadAction.tsx
│ │ │ ├── NavigateAction.tsx
│ │ │ └── TimedAction.tsx
│ │ ├── ApiBoundComponent.tsx
│ │ ├── appContext
│ │ │ ├── date-functions.ts
│ │ │ ├── math-function.ts
│ │ │ └── misc-utils.ts
│ │ ├── AppContext.tsx
│ │ ├── behaviors
│ │ │ ├── Behavior.tsx
│ │ │ └── CoreBehaviors.tsx
│ │ ├── component-hooks.ts
│ │ ├── ComponentDecorator.tsx
│ │ ├── ComponentViewer.tsx
│ │ ├── CompoundComponent.tsx
│ │ ├── constants.ts
│ │ ├── DebugViewProvider.tsx
│ │ ├── descriptorHelper.ts
│ │ ├── devtools
│ │ │ ├── InspectorDialog.module.scss
│ │ │ ├── InspectorDialog.tsx
│ │ │ └── InspectorDialogVisibilityContext.tsx
│ │ ├── EngineError.ts
│ │ ├── event-handlers.ts
│ │ ├── InspectorButton.module.scss
│ │ ├── InspectorContext.tsx
│ │ ├── interception
│ │ │ ├── abstractions.ts
│ │ │ ├── ApiInterceptor.ts
│ │ │ ├── ApiInterceptorProvider.tsx
│ │ │ ├── apiInterceptorWorker.ts
│ │ │ ├── Backend.ts
│ │ │ ├── Errors.ts
│ │ │ ├── IndexedDb.ts
│ │ │ ├── initMock.ts
│ │ │ ├── InMemoryDb.ts
│ │ │ ├── ReadonlyCollection.ts
│ │ │ └── useApiInterceptorContext.tsx
│ │ ├── loader
│ │ │ ├── ApiLoader.tsx
│ │ │ ├── DataLoader.tsx
│ │ │ ├── ExternalDataLoader.tsx
│ │ │ ├── Loader.tsx
│ │ │ ├── MockLoaderRenderer.tsx
│ │ │ └── PageableLoader.tsx
│ │ ├── LoaderComponent.tsx
│ │ ├── markup-check.ts
│ │ ├── parts.ts
│ │ ├── renderers.ts
│ │ ├── rendering
│ │ │ ├── AppContent.tsx
│ │ │ ├── AppRoot.tsx
│ │ │ ├── AppWrapper.tsx
│ │ │ ├── buildProxy.ts
│ │ │ ├── collectFnVarDeps.ts
│ │ │ ├── ComponentAdapter.tsx
│ │ │ ├── ComponentWrapper.tsx
│ │ │ ├── Container.tsx
│ │ │ ├── containers.ts
│ │ │ ├── ContainerWrapper.tsx
│ │ │ ├── ErrorBoundary.module.scss
│ │ │ ├── ErrorBoundary.tsx
│ │ │ ├── InvalidComponent.module.scss
│ │ │ ├── InvalidComponent.tsx
│ │ │ ├── nodeUtils.ts
│ │ │ ├── reducer.ts
│ │ │ ├── renderChild.tsx
│ │ │ ├── StandaloneComponent.tsx
│ │ │ ├── StateContainer.tsx
│ │ │ ├── UnknownComponent.module.scss
│ │ │ ├── UnknownComponent.tsx
│ │ │ └── valueExtractor.ts
│ │ ├── reportEngineError.ts
│ │ ├── RestApiProxy.ts
│ │ ├── script-runner
│ │ │ ├── asyncProxy.ts
│ │ │ ├── AttributeValueParser.ts
│ │ │ ├── bannedFunctions.ts
│ │ │ ├── BindingTreeEvaluationContext.ts
│ │ │ ├── eval-tree-async.ts
│ │ │ ├── eval-tree-common.ts
│ │ │ ├── eval-tree-sync.ts
│ │ │ ├── ParameterParser.ts
│ │ │ ├── process-statement-async.ts
│ │ │ ├── process-statement-common.ts
│ │ │ ├── process-statement-sync.ts
│ │ │ ├── ScriptingSourceTree.ts
│ │ │ ├── simplify-expression.ts
│ │ │ ├── statement-queue.ts
│ │ │ └── visitors.ts
│ │ ├── StandaloneApp.tsx
│ │ ├── StandaloneExtensionManager.ts
│ │ ├── TableOfContentsContext.tsx
│ │ ├── theming
│ │ │ ├── _themes.scss
│ │ │ ├── component-layout-resolver.ts
│ │ │ ├── extendThemeUtils.ts
│ │ │ ├── hvar.ts
│ │ │ ├── layout-resolver.ts
│ │ │ ├── parse-layout-props.ts
│ │ │ ├── StyleContext.tsx
│ │ │ ├── StyleRegistry.ts
│ │ │ ├── ThemeContext.tsx
│ │ │ ├── ThemeProvider.tsx
│ │ │ ├── themes
│ │ │ │ ├── base-utils.ts
│ │ │ │ ├── palette.ts
│ │ │ │ ├── root.ts
│ │ │ │ ├── solid.ts
│ │ │ │ ├── theme-colors.ts
│ │ │ │ └── xmlui.ts
│ │ │ ├── themeVars.module.scss
│ │ │ ├── themeVars.ts
│ │ │ ├── transformThemeVars.ts
│ │ │ └── utils.ts
│ │ ├── utils
│ │ │ ├── actionUtils.ts
│ │ │ ├── audio-utils.ts
│ │ │ ├── base64-utils.ts
│ │ │ ├── compound-utils.ts
│ │ │ ├── css-utils.ts
│ │ │ ├── DataLoaderQueryKeyGenerator.ts
│ │ │ ├── date-utils.ts
│ │ │ ├── extractParam.ts
│ │ │ ├── hooks.tsx
│ │ │ ├── LruCache.ts
│ │ │ ├── mergeProps.ts
│ │ │ ├── misc.ts
│ │ │ ├── request-params.ts
│ │ │ ├── statementUtils.ts
│ │ │ └── treeUtils.ts
│ │ └── xmlui-parser.ts
│ ├── index-standalone.ts
│ ├── index.scss
│ ├── index.ts
│ ├── language-server
│ │ ├── server-common.ts
│ │ ├── server-web-worker.ts
│ │ ├── server.ts
│ │ ├── services
│ │ │ ├── common
│ │ │ │ ├── docs-generation.ts
│ │ │ │ ├── lsp-utils.ts
│ │ │ │ ├── metadata-utils.ts
│ │ │ │ └── syntax-node-utilities.ts
│ │ │ ├── completion.ts
│ │ │ ├── diagnostic.ts
│ │ │ ├── format.ts
│ │ │ └── hover.ts
│ │ └── xmlui-metadata-generated.mjs
│ ├── 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
│ │ │ ├── ModalDialogDriver.ts
│ │ │ ├── NumberBoxDriver.ts
│ │ │ ├── TextBoxDriver.ts
│ │ │ ├── TimeInputDriver.ts
│ │ │ ├── TimerDriver.ts
│ │ │ └── TreeDriver.ts
│ │ ├── fixtures.ts
│ │ ├── infrastructure
│ │ │ ├── index.html
│ │ │ ├── main.tsx
│ │ │ ├── public
│ │ │ │ ├── mockServiceWorker.js
│ │ │ │ ├── resources
│ │ │ │ │ ├── bell.svg
│ │ │ │ │ ├── box.svg
│ │ │ │ │ ├── doc.svg
│ │ │ │ │ ├── eye.svg
│ │ │ │ │ ├── flower-640x480.jpg
│ │ │ │ │ ├── sun.svg
│ │ │ │ │ ├── test-image-100x100.jpg
│ │ │ │ │ └── txt.svg
│ │ │ │ └── serve.json
│ │ │ └── TestBed.tsx
│ │ └── themed-app-test-helpers.ts
│ └── vite-env.d.ts
├── tests
│ ├── components
│ │ ├── CodeBlock
│ │ │ └── hightlight-code.test.ts
│ │ ├── playground-pattern.test.ts
│ │ └── Tree
│ │ └── Tree-states.test.ts
│ ├── components-core
│ │ ├── abstractions
│ │ │ └── treeAbstractions.test.ts
│ │ ├── container
│ │ │ └── buildProxy.test.ts
│ │ ├── interception
│ │ │ ├── orderBy.test.ts
│ │ │ ├── ReadOnlyCollection.test.ts
│ │ │ └── request-param-converter.test.ts
│ │ ├── scripts-runner
│ │ │ ├── AttributeValueParser.test.ts
│ │ │ ├── eval-tree-arrow-async.test.ts
│ │ │ ├── eval-tree-arrow.test.ts
│ │ │ ├── eval-tree-func-decl-async.test.ts
│ │ │ ├── eval-tree-func-decl.test.ts
│ │ │ ├── eval-tree-pre-post.test.ts
│ │ │ ├── eval-tree-regression.test.ts
│ │ │ ├── eval-tree.test.ts
│ │ │ ├── function-proxy.test.ts
│ │ │ ├── parser-regression.test.ts
│ │ │ ├── process-event.test.ts
│ │ │ ├── process-function.test.ts
│ │ │ ├── process-implicit-context.test.ts
│ │ │ ├── process-statement-asgn.test.ts
│ │ │ ├── process-statement-destruct.test.ts
│ │ │ ├── process-statement-regs.test.ts
│ │ │ ├── process-statement-sync.test.ts
│ │ │ ├── process-statement.test.ts
│ │ │ ├── process-switch-sync.test.ts
│ │ │ ├── process-switch.test.ts
│ │ │ ├── process-try-sync.test.ts
│ │ │ ├── process-try.test.ts
│ │ │ └── test-helpers.ts
│ │ ├── test-metadata-handler.ts
│ │ ├── theming
│ │ │ ├── border-segments.test.ts
│ │ │ ├── component-layout.resolver.test.ts
│ │ │ ├── layout-property-parser.test.ts
│ │ │ ├── layout-resolver.test.ts
│ │ │ ├── layout-resolver2.test.ts
│ │ │ ├── layout-vp-override.test.ts
│ │ │ └── padding-segments.test.ts
│ │ └── utils
│ │ ├── date-utils.test.ts
│ │ ├── format-human-elapsed-time.test.ts
│ │ └── LruCache.test.ts
│ ├── language-server
│ │ ├── completion.test.ts
│ │ ├── format.test.ts
│ │ ├── hover.test.ts
│ │ └── mockData.ts
│ └── parsers
│ ├── common
│ │ └── input-stream.test.ts
│ ├── markdown
│ │ └── parse-binding-expression.test.ts
│ ├── parameter-parser.test.ts
│ ├── paremeter-parser.test.ts
│ ├── scripting
│ │ ├── eval-tree-arrow.test.ts
│ │ ├── eval-tree-pre-post.test.ts
│ │ ├── eval-tree.test.ts
│ │ ├── function-proxy.test.ts
│ │ ├── lexer-literals.test.ts
│ │ ├── lexer-misc.test.ts
│ │ ├── module-parse.test.ts
│ │ ├── parser-arrow.test.ts
│ │ ├── parser-assignments.test.ts
│ │ ├── parser-binary.test.ts
│ │ ├── parser-destructuring.test.ts
│ │ ├── parser-errors.test.ts
│ │ ├── parser-expressions.test.ts
│ │ ├── parser-function.test.ts
│ │ ├── parser-literals.test.ts
│ │ ├── parser-primary.test.ts
│ │ ├── parser-regex.test.ts
│ │ ├── parser-statements.test.ts
│ │ ├── parser-unary.test.ts
│ │ ├── process-event.test.ts
│ │ ├── process-implicit-context.test.ts
│ │ ├── process-statement-asgn.test.ts
│ │ ├── process-statement-destruct.test.ts
│ │ ├── process-statement-regs.test.ts
│ │ ├── process-statement-sync.test.ts
│ │ ├── process-statement.test.ts
│ │ ├── process-switch-sync.test.ts
│ │ ├── process-switch.test.ts
│ │ ├── process-try-sync.test.ts
│ │ ├── process-try.test.ts
│ │ ├── simplify-expression.test.ts
│ │ ├── statement-hooks.test.ts
│ │ └── test-helpers.ts
│ ├── style-parser
│ │ ├── generateHvarChain.test.ts
│ │ ├── parseHVar.test.ts
│ │ ├── parser.test.ts
│ │ └── tokens.test.ts
│ └── xmlui
│ ├── lint.test.ts
│ ├── parser.test.ts
│ ├── scanner.test.ts
│ ├── transform.attr.test.ts
│ ├── transform.circular.test.ts
│ ├── transform.element.test.ts
│ ├── transform.errors.test.ts
│ ├── transform.escape.test.ts
│ ├── transform.regression.test.ts
│ ├── transform.script.test.ts
│ ├── transform.test.ts
│ └── xmlui.ts
├── tests-e2e
│ ├── api-bound-component-regression.spec.ts
│ ├── api-call-as-extracted-component.spec.ts
│ ├── assign-to-object-or-array-regression.spec.ts
│ ├── binding-regression.spec.ts
│ ├── children-as-template-context-vars.spec.ts
│ ├── compound-component.spec.ts
│ ├── context-vars-regression.spec.ts
│ ├── data-bindings.spec.ts
│ ├── datasource-and-api-usage-in-var.spec.ts
│ ├── datasource-direct-binding.spec.ts
│ ├── datasource-onLoaded-regression.spec.ts
│ ├── modify-array-item-regression.spec.ts
│ ├── namespaces.spec.ts
│ ├── push-to-array-regression.spec.ts
│ ├── screen-breakpoints.spec.ts
│ ├── scripting.spec.ts
│ ├── state-scope-in-pages.spec.ts
│ └── state-var-scopes.spec.ts
├── tsconfig.bin.json
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── vitest.config.ts
```
# Files
--------------------------------------------------------------------------------
/xmlui/src/components/DatePicker/DatePicker.md:
--------------------------------------------------------------------------------
```markdown
1 | %-DESC-START
2 |
3 | **Key features:**
4 | - **Flexible modes**: Single date selection (default) or date range selection
5 | - **Format customization**: Support for various date formats (MM/dd/yyyy, yyyy-MM-dd, etc.)
6 | - **Date restrictions**: Set minimum/maximum dates and disable specific dates
7 | - **Localization options**: Configure first day of week and show week numbers
8 |
9 | %-DESC-END
10 |
11 | %-API-START setValue
12 |
13 | ```xmlui-pg copy {3, 9, 12} display name="Example: setValue" height="500px"
14 | <App>
15 | <HStack>
16 | <Button
17 | label="Set Date to 05/25/2024"
18 | onClick="picker.setValue('05/25/2024')" />
19 | <Button
20 | label="Remove Date"
21 | onClick="picker.setValue('')" />
22 | </HStack>
23 | <DatePicker inline id="picker" />
24 | </App>
25 | ```
26 |
27 | %-API-END
28 |
29 | %-PROP-START initialValue
30 |
31 | ```xmlui-pg copy display name="Example: initialValue" height="440px"
32 | <App>
33 | <DatePicker inline initialValue="05/25/2024" />
34 | </App>
35 | ```
36 |
37 | %-PROP-END
38 |
39 | %-PROP-START placeholder
40 |
41 | ```xmlui-pg copy display name="Example: placeholder" height="500px"
42 | <App>
43 | <DatePicker placeholder="This is a placeholder" />
44 | </App>
45 | ```
46 |
47 | %-PROP-END
48 |
49 | %-PROP-START enabled
50 |
51 | ```xmlui-pg copy display name="Example: enabled" height="120px"
52 | <App>
53 | <DatePicker enabled="false" />
54 | </App>
55 | ```
56 |
57 | %-PROP-END
58 |
59 | %-PROP-START validationStatus
60 |
61 | | Value | Description |
62 | | :-------- | :---------------------------------------------------- |
63 | | `valid` | Visual indicator for an input that is accepted |
64 | | `warning` | Visual indicator for an input that produced a warning |
65 | | `error` | Visual indicator for an input that produced an error |
66 |
67 | ```xmlui-pg copy display name="Example: validationStatus" height="500px"
68 | <App>
69 | <DatePicker />
70 | <DatePicker validationStatus="valid" />
71 | <DatePicker validationStatus="warning" />
72 | <DatePicker validationStatus="error" />
73 | </App>
74 | ```
75 |
76 | %-PROP-END
77 |
78 | %-PROP-START mode
79 |
80 | ```xmlui-pg copy {2-3} display name="Example: mode" height="560px"
81 | <App>
82 | <DatePicker mode="single" />
83 | <DatePicker mode="range" />
84 | </App>
85 | ```
86 |
87 | %-PROP-END
88 |
89 | %-PROP-START dateFormat
90 |
91 | Formats handle years (`y`), months (`m` or `M`), days of the month (`d`).
92 | Providing multiple placeholder letters changes the display of the date.
93 |
94 | The table below shows the available date formats:
95 |
96 | | Format | Example |
97 | | :--------- | :--------- |
98 | | MM/dd/yyyy | 05/25/2024 |
99 | | MM-dd-yyyy | 05-25-2024 |
100 | | yyyy/MM/dd | 2024/05/25 |
101 | | yyyy-MM-dd | 2024-05-25 |
102 | | dd/MM/yyyy | 25/05/2024 |
103 | | dd-MM-yyyy | 25-05-2024 |
104 | | yyyyMMdd | 20240525 |
105 | | MMddyyyy | 05252024 |
106 |
107 | ```xmlui-pg copy display name="Example: dateFormat" height="440px"
108 | <App>
109 | <DatePicker
110 | inline
111 | dateFormat="dd-MM-yyyy"
112 | initialValue="05/25/2024" />
113 | </App>
114 | ```
115 |
116 | %-PROP-END
117 |
118 | %-PROP-START showWeekNumber
119 |
120 | ```xmlui-pg copy display name="Example: showWeekNumber" height="500px"
121 | <App>
122 | <DatePicker showWeekNumber="true" />
123 | </App>
124 | ```
125 |
126 | %-PROP-END
127 |
128 | %-PROP-START weekStartsOn
129 |
130 | | Day | Number |
131 | | :-------- | :----- |
132 | | Sunday | 0 |
133 | | Monday | 1 |
134 | | Tuesday | 2 |
135 | | Wednesday | 3 |
136 | | Thursday | 4 |
137 | | Friday | 5 |
138 | | Saturday | 6 |
139 |
140 | ```xmlui-pg copy display name="Example: weekStartsOn" height="440px"
141 | <App>
142 | <DatePicker inline weekStartsOn="1" />
143 | </App>
144 | ```
145 |
146 | %-PROP-END
147 |
148 | %-PROP-START minValue
149 |
150 | ```xmlui-pg copy display name="Example: minValue" height="440px"
151 | <App>
152 | <DatePicker inline minValue="05/24/2024" />
153 | </App>
154 | ```
155 |
156 | %-PROP-END
157 |
158 | %-PROP-START maxValue
159 |
160 | ```xmlui-pg copy display name="Example: maxValue" height="440px"
161 | <App>
162 | <DatePicker inline maxValue="05/26/2024" />
163 | </App>
164 | ```
165 |
166 | %-PROP-END
167 |
168 | %-PROP-START disabledDates
169 |
170 | The `disabledDates` prop supports multiple patterns for disabling specific dates in the calendar. You can use Date objects, strings (parsed using the `dateFormat`), or complex matcher objects.
171 |
172 | **Basic patterns:**
173 |
174 | | Pattern | Description | Example |
175 | | :------ | :---------- | :------ |
176 | | Single string | Disable one specific date | `"05/25/2024"` |
177 | | Array of strings | Disable multiple specific dates | `["05/25/2024", "05/26/2024"]` |
178 | | Boolean | Disable all dates | `true` |
179 |
180 | > [!INFO] You can use the [getDate()](/globals#getdate) function to query the current date.
181 |
182 | ```xmlui-pg copy display name="Example: Disable specific dates" height="440px"
183 | <App>
184 | <DatePicker
185 | inline
186 | disabledDates="{['05/26/2024', '05/27/2024']}"
187 | initialValue="05/25/2024" />
188 | </App>
189 | ```
190 |
191 | **Advanced patterns:**
192 |
193 | | Pattern | Description | Example |
194 | | :------ | :---------- | :------ |
195 | | Date range | Disable a range of dates | `{from: "05/20/2024", to: "05/25/2024"}` |
196 | | Day of week | Disable specific weekdays (0=Sunday, 6=Saturday) | `{dayOfWeek: [0, 6]}` |
197 | | Before date | Disable all dates before a specific date | `{before: "05/25/2024"}` |
198 | | After date | Disable all dates after a specific date | `{after: "05/25/2024"}` |
199 | | Date interval | Disable dates between two dates (exclusive) | `{before: "05/30/2024", after: "05/20/2024"}` |
200 |
201 |
202 | ```xmlui-pg copy display name="Example: Disable weekends" height="440px"
203 | <App>
204 | <DatePicker inline disabledDates="{{dayOfWeek: [0, 6]}}" />
205 | </App>
206 | ```
207 |
208 | ```xmlui-pg copy display name="Example: Disable date range" height="440px"
209 | <App>
210 | <DatePicker
211 | inline
212 | disabledDates="{{from: '05/20/2024', to: '05/25/2024'}}"
213 | initialValue="05/18/2024" />
214 | </App>
215 | ```
216 |
217 | ```xmlui-pg copy display name="Example: Disable dates before today" height="440px"
218 | <App>
219 | <DatePicker
220 | inline
221 | disabledDates="{{before: getDate()}}"
222 | intialValue="{getDate()}"/>
223 | </App>
224 | ```
225 |
226 | ```xmlui-pg copy display name="Example: Disable dates today and after" height="440px"
227 | <App>
228 | <DatePicker
229 | inline
230 | disabledDates="{[getDate(), {after: getDate()}]}"
231 | intialValue="{getDate()}"/>
232 | </App>
233 | ```
234 |
235 |
236 | ```xmlui-pg copy display name="Example: Complex combination" height="440px"
237 | <App>
238 | <DatePicker
239 | inline
240 | disabledDates="{[
241 | {dayOfWeek: [0, 6]},
242 | {from: '12/24/2024', to: '12/26/2024'},
243 | '01/01/2025']}"
244 | initialValue="12/20/2024"
245 | />
246 | </App>
247 | ```
248 |
249 | %-PROP-END
250 |
251 | %-EVENT-START didChange
252 |
253 | Write in the input field and see how the `Text` underneath it is updated in parallel.
254 |
255 | ```xmlui-pg copy {2} display name="Example: didChange" height="520px"
256 | <App var.field="(none)">
257 | <Text value="{field}" />
258 | <DatePicker
259 | inline
260 | initialValue="{field}"
261 | onDidChange="(val) => field = val" />
262 | </App>
263 | ```
264 |
265 | %-EVENT-END
266 |
267 | %-EVENT-START gotFocus
268 |
269 | Clicking on the `DatePicker` in the example demo changes the label text.
270 | Note how clicking elsewhere resets the text to the original.
271 |
272 | ```xmlui-pg copy {4-5} display name="Example: gotFocus/lostFocus" height="540px"
273 | <App var.isFocused="false">
274 | <Text value="{isFocused === true
275 | ? 'DatePicker focused' : 'DatePicker lost focus'}"
276 | />
277 | <DatePicker
278 | onGotFocus="isFocused = true"
279 | onLostFocus="isFocused = false"
280 | />
281 | </App>
282 | ```
283 |
284 | %-EVENT-END
285 |
286 |
```
--------------------------------------------------------------------------------
/packages/xmlui-playground/src/playground/StandalonePlaygroundNative.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { useEffect, useId, useMemo, useReducer, useRef, useState } from "react";
2 | import {
3 | appDescriptionInitialized,
4 | contentChanged,
5 | optionsInitialized,
6 | PlaygroundContext,
7 | playgroundReducer,
8 | } from "../state/store";
9 | import { decompressData, INITIAL_PLAYGROUND_STATE } from "../utils/helpers";
10 | import { ToastProvider } from "../providers/ToastProvider";
11 | import styles from "./StandalonePlaygroundNative.module.scss";
12 | import { useToast } from "../hooks/useToast";
13 | import { ErrorBoundary, useThemes } from "xmlui";
14 | import { Header } from "./Header";
15 | import { PlaygroundContent } from "./PlaygroundContent";
16 | import { Theme } from "../themes/theme";
17 |
18 | export const StandalonePlayground = () => {
19 | const { showToast } = useToast();
20 | const id = useId();
21 | const [loading, setLoading] = useState(true);
22 | const { setActiveThemeTone } = useThemes();
23 | const [playgroundState, dispatch] = useReducer(playgroundReducer, INITIAL_PLAYGROUND_STATE);
24 | const initialized = useRef(false);
25 |
26 | const queryParams = useMemo(() => {
27 | if (typeof window !== "undefined") {
28 | return Object.fromEntries(new URLSearchParams("?app=" + window.location.hash.split("#")[2]));
29 | }
30 | return {};
31 | }, []);
32 |
33 | useEffect(() => {
34 | const getApp = async () => {
35 | try {
36 | const data = JSON.parse(await decompressData(queryParams.app as string));
37 | dispatch(appDescriptionInitialized(data.standalone));
38 | dispatch(
39 | optionsInitialized({
40 | ...playgroundState.options,
41 | ...data.options,
42 | content: "app",
43 | orientation: "horizontal",
44 | }),
45 | );
46 | setActiveThemeTone(data.options.activeTone || "light");
47 | dispatch(contentChanged(data.options.content));
48 | } catch (e) {
49 | showToast({
50 | type: "error",
51 | title: "Error",
52 | description: "The app could not be loaded",
53 | });
54 | }
55 | setLoading(false);
56 | initialized.current = true;
57 | };
58 |
59 | if (initialized.current) {
60 | return;
61 | } else {
62 | if (queryParams.app && queryParams.app !== "undefined") {
63 | getApp();
64 | } else {
65 | dispatch(
66 | appDescriptionInitialized({
67 | config: {
68 | name: "Hello World",
69 | description: "",
70 | appGlobals: {},
71 | resources: {},
72 | themes: [Theme],
73 | },
74 | components: [],
75 | app: "<App>Hello World!</App>",
76 | }),
77 | );
78 | dispatch(
79 | optionsInitialized({
80 | activeTheme: "theme",
81 | activeTone: "light",
82 | content: "app",
83 | orientation: "horizontal",
84 | id: 0,
85 | allowStandalone: true,
86 | language: "xmlui",
87 | emulatedApi: undefined,
88 | fixedTheme: false,
89 | }),
90 | );
91 | setLoading(false);
92 | initialized.current = true;
93 | }
94 | }
95 | }, [queryParams.app, showToast, setActiveThemeTone, playgroundState.options]);
96 |
97 | const playgroundContextValue = useMemo(() => {
98 | return {
99 | editorStatus: playgroundState.editorStatus,
100 | status: playgroundState.status,
101 | options: playgroundState.options,
102 | text: playgroundState.text,
103 | originalAppDescription: playgroundState.originalAppDescription,
104 | appDescription: playgroundState.appDescription,
105 | dispatch,
106 | playgroundId: id,
107 | error: playgroundState.error,
108 | };
109 | }, [
110 | playgroundState.editorStatus,
111 | playgroundState.status,
112 | playgroundState.options,
113 | playgroundState.text,
114 | playgroundState.originalAppDescription,
115 | playgroundState.appDescription,
116 | id,
117 | playgroundState.error,
118 | ]);
119 |
120 | return (
121 | <ToastProvider>
122 | <PlaygroundContext.Provider value={playgroundContextValue}>
123 | <ErrorBoundary>
124 | {loading && <AnimatedLogo />}
125 | {!loading && (
126 | <div className={styles.standalonePlayground}>
127 | {!playgroundState.options.previewMode && <Header standalone={true} />}
128 | <div style={{ flexGrow: 1, overflow: "auto" }}>
129 | <PlaygroundContent standalone={true} />
130 | </div>
131 | </div>
132 | )}
133 | </ErrorBoundary>
134 | </PlaygroundContext.Provider>
135 | </ToastProvider>
136 | );
137 | };
138 |
139 | function AnimatedLogo() {
140 | return (
141 | <div className={styles.loadingContainer}>
142 | <div className={styles.loadingText}>Loading XMLUI App...</div>
143 | <div className={styles.logoWrapper}>
144 | <svg viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg">
145 | {/* Unchanged inner paths */}
146 | <path
147 | d="M9.04674 19.3954C8.2739 19.3954 7.60226 19.2265 7.03199 18.8887C6.47443 18.5384 6.0435 18.0505 5.73938 17.425C5.43526 16.7869 5.2832 16.0362 5.2832 15.173V9.89961C5.2832 9.7745 5.32771 9.66815 5.41637 9.58059C5.50502 9.493 5.61275 9.44922 5.73938 9.44922H7.41222C7.55157 9.44922 7.6593 9.493 7.73524 9.58059C7.8239 9.66815 7.86841 9.7745 7.86841 9.89961V15.0604C7.86841 16.6117 8.55895 17.3874 9.94021 17.3874C10.5991 17.3874 11.1187 17.181 11.4988 16.7681C11.8917 16.3553 12.0881 15.786 12.0881 15.0604V9.89961C12.0881 9.7745 12.1325 9.66815 12.2211 9.58059C12.3098 9.493 12.4175 9.44922 12.5443 9.44922H14.217C14.3436 9.44922 14.4513 9.493 14.54 9.58059C14.6288 9.66815 14.6732 9.7745 14.6732 9.89961V18.7574C14.6732 18.8825 14.6288 18.9888 14.54 19.0764C14.4513 19.164 14.3436 19.2078 14.217 19.2078H12.6773C12.538 19.2078 12.4239 19.164 12.3352 19.0764C12.2591 18.9888 12.2211 18.8825 12.2211 18.7574V17.988C11.879 18.4258 11.4545 18.7699 10.9476 19.0201C10.4407 19.2703 9.80704 19.3954 9.04674 19.3954Z"
148 | fill="#3367CC"
149 | />
150 | <path
151 | d="M17.6397 19.2104C17.5129 19.2104 17.4052 19.1666 17.3165 19.079C17.2279 18.9914 17.1835 18.8851 17.1835 18.76V9.90221C17.1835 9.7771 17.2279 9.67075 17.3165 9.58319C17.4052 9.4956 17.5129 9.45182 17.6397 9.45182H19.2174C19.3567 9.45182 19.4644 9.4956 19.5404 9.58319C19.6292 9.67075 19.6736 9.7771 19.6736 9.90221V18.76C19.6736 18.8851 19.6292 18.9914 19.5404 19.079C19.4644 19.1666 19.3567 19.2104 19.2174 19.2104H17.6397ZM17.5636 7.8379C17.4243 7.8379 17.3102 7.80038 17.2215 7.72531C17.1454 7.63773 17.1074 7.52514 17.1074 7.38751V6.03633C17.1074 5.91122 17.1454 5.80487 17.2215 5.71731C17.3102 5.62972 17.4243 5.58594 17.5636 5.58594H19.2933C19.4327 5.58594 19.5467 5.62972 19.6354 5.71731C19.7242 5.80487 19.7686 5.91122 19.7686 6.03633V7.38751C19.7686 7.52514 19.7242 7.63773 19.6354 7.72531C19.5467 7.80038 19.4327 7.8379 19.2933 7.8379H17.5636Z"
152 | fill="#3367CC"
153 | />
154 |
155 | {/* ✨ MODIFIED outer path for animation */}
156 | <path
157 | className={styles.animatedLogoPath}
158 | d="M23.0215 2.81748H2.53486V23.044H23.0215V2.81748Z"
159 | fill="none"
160 | stroke="#3367CC"
161 | strokeWidth="0.75"
162 | />
163 | </svg>
164 | </div>
165 | </div>
166 | );
167 | }
168 |
```
--------------------------------------------------------------------------------
/docs/content/components/NavPanel.md:
--------------------------------------------------------------------------------
```markdown
1 | # NavPanel [#navpanel]
2 |
3 | `NavPanel` defines the navigation structure within an App, serving as a container for NavLink and NavGroup components that create your application's primary navigation menu. Its appearance and behavior automatically adapt based on the App's layout configuration.
4 |
5 | **Key features:**
6 |
7 | - **Layout adaptation**: Automatically positions navigation horizontally or vertically based on App layout
8 | - **Navigation organization**: Contains NavLink and NavGroup components to build structured menus
9 | - **Logo integration**: Supports custom logo templates in vertical layouts via logoTemplate property
10 | - **Drawer mode**: Can optionally display navigation in a collapsible drawer interface
11 | - **Theme integration**: Inherits styling from the app's theme system for consistent appearance
12 |
13 | ## Properties [#properties]
14 |
15 | ### `inDrawer` (default: false) [#indrawer-default-false]
16 |
17 | This property determines if the navigation panel is displayed in a drawer.
18 |
19 | ### `logoTemplate` [#logotemplate]
20 |
21 | This property defines the logo template to display in the navigation panel with the `vertical` and `vertical-sticky` layout.
22 |
23 | ```xmlui-pg copy {3-8} display name="Example: logoTemplate" height={250}
24 | <App layout="vertical">
25 | <NavPanel>
26 | <property name="logoTemplate">
27 | <H3>
28 | <Icon name="drive" />
29 | DriveDiag (Nav)
30 | </H3>
31 | </property>
32 | <NavLink label="Home" to="/" icon="home"/>
33 | <NavLink label="Page 1" to="/page1"/>
34 | </NavPanel>
35 | <Pages fallbackPath="/">
36 | <Page url="/">
37 | <Text value="Home" />
38 | </Page>
39 | <Page url="/page1">
40 | <Text value="Page 1" />
41 | </Page>
42 | </Pages>
43 | </App>
44 | ```
45 |
46 | ## Events [#events]
47 |
48 | This component does not have any events.
49 |
50 | ## Exposed Methods [#exposed-methods]
51 |
52 | This component does not expose any methods.
53 |
54 | ## Styling [#styling]
55 |
56 | ### Theme Variables [#theme-variables]
57 |
58 | | Variable | Default Value (Light) | Default Value (Dark) |
59 | | --- | --- | --- |
60 | | [backgroundColor](../styles-and-themes/common-units/#color)-NavPanel | $backgroundColor | $backgroundColor |
61 | | [backgroundColor](../styles-and-themes/common-units/#color)-NavPanel-horizontal | $backgroundColor-AppHeader | $backgroundColor-AppHeader |
62 | | [border](../styles-and-themes/common-units/#border)-NavPanel | 0px solid $borderColor | 0px solid $borderColor |
63 | | [borderBottom](../styles-and-themes/common-units/#border)-NavPanel | *none* | *none* |
64 | | [borderBottomColor](../styles-and-themes/common-units/#color)-NavPanel | *none* | *none* |
65 | | [borderBottomStyle](../styles-and-themes/common-units/#border-style)-NavPanel | *none* | *none* |
66 | | [borderBottomWidth](../styles-and-themes/common-units/#size)-NavPanel | *none* | *none* |
67 | | [borderColor](../styles-and-themes/common-units/#color)-NavPanel | *none* | *none* |
68 | | [borderEndEndRadius](../styles-and-themes/common-units/#border-rounding)-NavPanel | *none* | *none* |
69 | | [borderEndStartRadius](../styles-and-themes/common-units/#border-rounding)-NavPanel | *none* | *none* |
70 | | [borderHorizontal](../styles-and-themes/common-units/#border)-NavPanel | *none* | *none* |
71 | | [borderHorizontalColor](../styles-and-themes/common-units/#color)-NavPanel | *none* | *none* |
72 | | [borderHorizontalStyle](../styles-and-themes/common-units/#border-style)-NavPanel | *none* | *none* |
73 | | [borderHorizontalWidth](../styles-and-themes/common-units/#size)-NavPanel | *none* | *none* |
74 | | [borderLeft](../styles-and-themes/common-units/#border)-NavPanel | *none* | *none* |
75 | | [color](../styles-and-themes/common-units/#color)-NavPanel | *none* | *none* |
76 | | [borderLeftStyle](../styles-and-themes/common-units/#border-style)-NavPanel | *none* | *none* |
77 | | [borderLeftWidth](../styles-and-themes/common-units/#size)-NavPanel | *none* | *none* |
78 | | [borderRight](../styles-and-themes/common-units/#border)-NavPanel | *none* | *none* |
79 | | [color](../styles-and-themes/common-units/#color)-NavPanel | *none* | *none* |
80 | | [borderRightStyle](../styles-and-themes/common-units/#border-style)-NavPanel | *none* | *none* |
81 | | [borderRightWidth](../styles-and-themes/common-units/#size)-NavPanel | *none* | *none* |
82 | | [borderStartEndRadius](../styles-and-themes/common-units/#border-rounding)-NavPanel | *none* | *none* |
83 | | [borderStartStartRadius](../styles-and-themes/common-units/#border-rounding)-NavPanel | *none* | *none* |
84 | | [borderStyle](../styles-and-themes/common-units/#border-style)-NavPanel | *none* | *none* |
85 | | [borderTop](../styles-and-themes/common-units/#border)-NavPanel | *none* | *none* |
86 | | [borderTopColor](../styles-and-themes/common-units/#color)-NavPanel | *none* | *none* |
87 | | [borderTopStyle](../styles-and-themes/common-units/#border-style)-NavPanel | *none* | *none* |
88 | | [borderTopWidth](../styles-and-themes/common-units/#size)-NavPanel | *none* | *none* |
89 | | [borderHorizontal](../styles-and-themes/common-units/#border)-NavPanel | *none* | *none* |
90 | | [borderVerticalColor](../styles-and-themes/common-units/#color)-NavPanel | *none* | *none* |
91 | | [borderVerticalStyle](../styles-and-themes/common-units/#border-style)-NavPanel | *none* | *none* |
92 | | [borderVerticalWidth](../styles-and-themes/common-units/#size)-NavPanel | *none* | *none* |
93 | | [borderWidth](../styles-and-themes/common-units/#size)-NavPanel | *none* | *none* |
94 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-NavPanel | *none* | *none* |
95 | | [boxShadow](../styles-and-themes/common-units/#boxShadow)-NavPanel-vertical | 4px 0 4px 0 rgb(0 0 0 / 10%) | 4px 0 4px 0 rgb(0 0 0 / 10%) |
96 | | [horizontalAlignment](../styles-and-themes/common-units/#alignment)-logo-NavPanel | center | center |
97 | | [marginBottom](../styles-and-themes/common-units/#size)-logo-NavPanel | $space-4 | $space-4 |
98 | | [padding](../styles-and-themes/common-units/#size)-logo-NavPanel | *none* | *none* |
99 | | [padding](../styles-and-themes/common-units/#size)-NavPanel | *none* | *none* |
100 | | [paddingBottom](../styles-and-themes/common-units/#size)-logo-NavPanel | *none* | *none* |
101 | | [paddingBottom](../styles-and-themes/common-units/#size)-NavPanel | *none* | *none* |
102 | | [paddingHorizontal](../styles-and-themes/common-units/#size)-logo-NavPanel | $space-4 | $space-4 |
103 | | [paddingHorizontal](../styles-and-themes/common-units/#size)-NavPanel | 0 | 0 |
104 | | [paddingLeft](../styles-and-themes/common-units/#size)-logo-NavPanel | *none* | *none* |
105 | | [paddingLeft](../styles-and-themes/common-units/#size)-NavPanel | *none* | *none* |
106 | | [paddingRight](../styles-and-themes/common-units/#size)-logo-NavPanel | *none* | *none* |
107 | | [paddingRight](../styles-and-themes/common-units/#size)-NavPanel | *none* | *none* |
108 | | [paddingTop](../styles-and-themes/common-units/#size)-logo-NavPanel | *none* | *none* |
109 | | [paddingTop](../styles-and-themes/common-units/#size)-NavPanel | *none* | *none* |
110 | | [paddingVertical](../styles-and-themes/common-units/#size)-logo-NavPanel | $space-4 | $space-4 |
111 | | [paddingVertical](../styles-and-themes/common-units/#size)-NavPanel | *none* | *none* |
112 |
```
--------------------------------------------------------------------------------
/packages/xmlui-playground/src/utils/helpers.ts:
--------------------------------------------------------------------------------
```typescript
1 | import type { PlaygroundState } from "../state/store";
2 | import JSZip from "jszip";
3 | import { saveAs } from "file-saver";
4 | import {
5 | type ComponentDef,
6 | type CompoundComponentDef,
7 | type ThemeDefinition,
8 | XmlUiHelper,
9 | type XmlUiNode,
10 | } from "xmlui";
11 | import { decompress } from "../playground/utils";
12 | import { decodeFromBase64 } from "../../../../xmlui/src/components-core/utils/base64-utils";
13 |
14 | export function normalizePath(url?: string): string | undefined {
15 | if (!url) {
16 | return undefined;
17 | }
18 | if (url.startsWith("http://") || url.startsWith("https://")) {
19 | return url;
20 | }
21 | if (typeof window === "undefined") {
22 | return url;
23 | }
24 | // @ts-ignore
25 | const prefix = window.__PUBLIC_PATH || "";
26 | if (!prefix) {
27 | return url;
28 | }
29 | const prefixWithoutTrailingSlash = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
30 | const urlWithoutLeadingSlash = url.startsWith("/") ? url.slice(1) : url;
31 |
32 | return `${prefixWithoutTrailingSlash}/${urlWithoutLeadingSlash}`;
33 | }
34 |
35 | async function fetchWithoutCache(url: string) {
36 | return fetch(normalizePath(url) as any, {
37 | headers: {
38 | "Cache-Control": "no-cache, no-store",
39 | },
40 | });
41 | }
42 |
43 | export function serialize(component: ComponentDef | CompoundComponentDef): string {
44 | if (component) {
45 | const xh = new XmlUiHelper();
46 | try {
47 | const node = xh.transformComponentDefinition(component) as XmlUiNode;
48 | return xh.serialize(node, { prettify: true });
49 | } catch (e) {
50 | console.log(e);
51 | return "";
52 | }
53 | }
54 | return "";
55 | }
56 |
57 | export async function decompressData(source: string) {
58 | const base64 = decodeURIComponent(source);
59 | const decoded = decodeFromBase64(base64);
60 | if (!decoded) {
61 | throw new Error("Failed to decode base64 data");
62 | }
63 | const compressed = new TextEncoder().encode(decoded);
64 | return await decompress(compressed);
65 | }
66 |
67 | export const INITIAL_PLAYGROUND_STATE: PlaygroundState = {
68 | editorStatus: "idle",
69 | status: "idle",
70 | options: {
71 | orientation: "horizontal",
72 | swapped: false,
73 | content: "app",
74 | previewMode: false,
75 | id: 0,
76 | language: "xmlui",
77 | },
78 | text: "",
79 | appDescription: {
80 | config: {
81 | name: "",
82 | appGlobals: {},
83 | resources: {},
84 | themes: [],
85 | },
86 | components: [],
87 | app: "",
88 | },
89 | originalAppDescription: {
90 | config: {
91 | name: "",
92 | appGlobals: {},
93 | resources: {},
94 | themes: [],
95 | },
96 | components: [],
97 | app: "",
98 | },
99 | error: null,
100 | };
101 |
102 | function removeWhitespace(obj: any) {
103 | if (typeof obj === "string") {
104 | return obj.replace(/\s+/g, " ").trim(); // Remove extra whitespaces and newlines
105 | } else if (obj !== null && typeof obj === "object") {
106 | const newObj: any = Array.isArray(obj) ? [] : {};
107 | for (const key in obj) {
108 | newObj[key] = removeWhitespace(obj[key]);
109 | }
110 | return newObj;
111 | }
112 | return obj; // Return the value as is if not a string or object
113 | }
114 |
115 | export const handleDownloadZip = async (appDescription: any) => {
116 | const operatingSystem = getOperatingSystem();
117 |
118 | const zip = new JSZip();
119 |
120 | const xmluiFolder = zip.folder("xmlui");
121 | const xmluiStandalone = await fetchWithoutCache(
122 | "/resources/files/for-download/xmlui/xmlui-standalone.umd.js",
123 | ).then((res) => res.blob());
124 | xmluiFolder?.file("xmlui-standalone.umd.js", xmluiStandalone);
125 |
126 | zip.file("Main.xmlui", appDescription.app);
127 | zip.file("config.json", JSON.stringify(appDescription.config, null, 2));
128 |
129 | if (appDescription.components.length > 0) {
130 | const components = zip.folder("components");
131 | appDescription.components.forEach((component: { name: string; component: string }) => {
132 | components?.file(`${component.name}.xmlui`, component.component);
133 | });
134 | }
135 | if (appDescription.config.themes.length > 0) {
136 | const themes = zip.folder("themes");
137 | appDescription.config.themes.forEach((theme: ThemeDefinition) => {
138 | themes?.file(`${theme.id}.json`, JSON.stringify(theme, null, 2));
139 | });
140 | }
141 |
142 | const emulatedApi = appDescription.api;
143 | if (emulatedApi) {
144 | const indexWithApiHtml = await fetchWithoutCache(
145 | "/resources/files/for-download/index-with-api.html",
146 | ).then((res) => res.blob());
147 | zip.file("index.html", indexWithApiHtml);
148 | xmluiFolder?.file(
149 | "mockApiDef.js",
150 | `window.XMLUI_MOCK_API = ${JSON.stringify(removeWhitespace(emulatedApi), null, 2)};`,
151 | );
152 |
153 | const emulatedApiWorker = await fetchWithoutCache(
154 | "/resources/files/for-download/mockApi.js",
155 | ).then((res) => res.blob());
156 | zip.file("mockApi.js", emulatedApiWorker);
157 | } else {
158 | const indexHtml = await fetchWithoutCache("/resources/files/for-download/index.html").then(
159 | (res) => res.blob(),
160 | );
161 | zip.file("index.html", indexHtml);
162 | }
163 |
164 | const startBat = await fetchWithoutCache("/resources/files/for-download/start.bat").then((res) =>
165 | res.blob(),
166 | );
167 |
168 | if (operatingSystem === "Windows") {
169 | zip.file("start.bat", startBat);
170 | } else {
171 | let fileName = operatingSystem === "Linux" ? "start-linux.sh" : "start-darwin.sh";
172 | const startSh = await fetchWithoutCache(`/resources/files/for-download/${fileName}`).then(
173 | (res) => res.blob(),
174 | );
175 | zip.file("start.sh", startSh, {
176 | unixPermissions: "777",
177 | });
178 | }
179 |
180 | try {
181 | const content = await zip.generateAsync({
182 | type: "blob",
183 | platform: operatingSystem === "Windows" ? "DOS" : "UNIX",
184 | });
185 | saveAs(content, `${(appDescription.config.name || "xmlui-playground-app").trim()}.zip`);
186 | } catch (error) {
187 | console.error("An error occurred while generating the ZIP:", error);
188 | }
189 | };
190 |
191 | export function preprocessCode(code: string): string {
192 | // Split code by newlines
193 | const lines = code.split("\n");
194 |
195 | // Remove whitespace-only lines from the beginning and end
196 | let start = 0;
197 | while (start < lines.length && lines[start].trim() === "") {
198 | start++;
199 | }
200 |
201 | let end = lines.length - 1;
202 | while (end >= 0 && lines[end].trim() === "") {
203 | end--;
204 | }
205 |
206 | const trimmedLines = lines.slice(start, end + 1);
207 |
208 | // Calculate the minimum indentation
209 | const minIndent = Math.min(
210 | ...trimmedLines
211 | .filter((line) => line.trim() !== "") // Ignore empty lines for indentation
212 | .map((line) => line.match(/^\s*/)?.[0].length || 0), // Count leading spaces
213 | );
214 |
215 | // Remove minIndent spaces from the beginning of each line
216 | const result = trimmedLines.map((line) =>
217 | line.startsWith(" ".repeat(minIndent)) ? line.slice(minIndent) : line,
218 | );
219 |
220 | // Join lines back into a single string
221 | return result.join("\n");
222 | }
223 |
224 | function getOperatingSystem() {
225 | const userAgent = window.navigator.userAgent;
226 | const platform = window.navigator.platform;
227 |
228 | if (/Win/.test(platform)) {
229 | return "Windows";
230 | }
231 | if (/Mac/.test(platform)) {
232 | return "MacOS";
233 | }
234 | if (/Linux/.test(platform)) {
235 | return "Linux";
236 | }
237 | if (/Android/.test(userAgent)) {
238 | return "Android";
239 | }
240 | if (/iPhone|iPad|iPod/.test(userAgent)) {
241 | return "iOS";
242 | }
243 | return "Unknown OS";
244 | }
245 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Toggle/Toggle.module.scss:
--------------------------------------------------------------------------------
```scss
1 | @use "../../components-core/theming/themes" as t;
2 |
3 | // --- This code snippet is required to collect the theme variables used in this module
4 | $themeVars: ();
5 | @function createThemeVar($componentVariable) {
6 | $themeVars: t.appendThemeVar($themeVars, $componentVariable) !global;
7 | @return t.getThemeVar($themeVars, $componentVariable);
8 | }
9 |
10 | // --- CSS properties of a particular Checkbox variant
11 | @mixin checkboxVariant($variantName) {
12 | border-radius: createThemeVar("Input:borderRadius-Checkbox-#{$variantName}");
13 | border-color: createThemeVar("Input:borderColor-Checkbox-#{$variantName}");
14 | background-color: createThemeVar("Input:backgroundColor-Checkbox-#{$variantName}");
15 |
16 | &:focus-visible {
17 | outline-width: createThemeVar("Input:outlineWidth-Checkbox-#{$variantName}--focus");
18 | outline-color: createThemeVar("Input:outlineColor-Checkbox-#{$variantName}--focus");
19 | outline-style: createThemeVar("Input:outlineStyle-Checkbox-#{$variantName}--focus");
20 | outline-offset: createThemeVar("Input:outlineOffset-Checkbox-#{$variantName}--focus");
21 | }
22 | }
23 |
24 | @mixin hoverAndDisabledState($componentName) {
25 | &:hover {
26 | border-color: createThemeVar("Input:borderColor-#{$componentName}-default--hover");
27 | }
28 |
29 | &:disabled {
30 | cursor: not-allowed;
31 | background-color: createThemeVar("Input:backgroundColor-#{$componentName}--disabled");
32 | border-color: createThemeVar("Input:borderColor-#{$componentName}--disabled");
33 | }
34 | }
35 |
36 | @mixin checkedState($componentName) {
37 | &:checked {
38 | border-color: createThemeVar("Input:borderColor-checked-#{$componentName}");
39 | background-color: createThemeVar("Input:backgroundColor-checked-#{$componentName}");
40 | }
41 |
42 | &:checked:disabled {
43 | background-color: createThemeVar("Input:backgroundColor-#{$componentName}--disabled");
44 | border-color: createThemeVar("Input:borderColor-#{$componentName}--disabled");
45 | }
46 |
47 | &:checked.error {
48 | border-color: createThemeVar("Input:borderColor-checked-#{$componentName}-error");
49 | background-color: createThemeVar("Input:backgroundColor-checked-#{$componentName}-error");
50 | }
51 |
52 | &:checked.warning {
53 | border-color: createThemeVar("Input:borderColor-checked-#{$componentName}-warning");
54 | background-color: createThemeVar("Input:backgroundColor-checked-#{$componentName}-warning");
55 | }
56 |
57 | &:checked.valid {
58 | border-color: createThemeVar("Input:borderColor-checked-#{$componentName}-success");
59 | background-color: createThemeVar("Input:backgroundColor-checked-#{$componentName}-success");
60 | }
61 | }
62 |
63 | @layer components {
64 | .resetAppearance {
65 | /* Add if not using autoprefixer */
66 | -webkit-appearance: none;
67 | appearance: none;
68 | /* Not removed via appearance */
69 | margin: 0;
70 | }
71 |
72 | .label {
73 | width: 100%;
74 | }
75 |
76 | .inputContainer {
77 | z-index: -1;
78 | position: relative;
79 | opacity: 0;
80 | width: 0;
81 | height: 0;
82 | }
83 |
84 | // --------------- Checkbox ---------------
85 |
86 | .checkbox {
87 | display: grid;
88 | place-content: center;
89 | min-width: 1em;
90 | min-height: 1em;
91 | width: 1em;
92 | height: 1em;
93 | border: 2px solid transparent;
94 |
95 | &:not([readonly]) {
96 | cursor: pointer;
97 | }
98 |
99 | @include checkboxVariant("default");
100 | @include hoverAndDisabledState("Checkbox");
101 |
102 | .forceHover {
103 | border-color: createThemeVar("Input:borderColor-Checkbox-default--hover");
104 | // Don't override background-color - let the existing background rules apply
105 | }
106 |
107 | &.error {
108 | @include checkboxVariant("error");
109 | }
110 |
111 | &.warning {
112 | @include checkboxVariant("warning");
113 | }
114 |
115 | &.valid {
116 | @include checkboxVariant("success");
117 | }
118 |
119 | &::before {
120 | content: "";
121 | width: 0.5em;
122 | height: 0.5em;
123 | transform: scale(0);
124 | transition: 0.1s transform ease-out;
125 | box-shadow: inset 1em 1em createThemeVar("backgroundColor-indicator-Checkbox");
126 | transform-origin: center;
127 | clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
128 | }
129 |
130 | &:checked::before {
131 | transform: scale(1);
132 | }
133 |
134 | @include checkedState("Checkbox");
135 |
136 | &:indeterminate {
137 | background-color: createThemeVar("Input:backgroundColor-checked-Checkbox");
138 | border-color: createThemeVar("Input:borderColor-checked-Checkbox");
139 |
140 | &[readonly] {
141 | pointer-events: none;
142 | }
143 | }
144 | &:indeterminate:disabled {
145 | background-color: createThemeVar("Input:backgroundColor-Checkbox--disabled");
146 | border-color: createThemeVar("Input:borderColor-Checkbox--disabled");
147 | }
148 | &:indeterminate::before {
149 | clip-path: circle(30% at 50% 50%);
150 | transform: scale(1);
151 | }
152 | }
153 |
154 | // --------------- Switch ---------------
155 |
156 | .switch {
157 | --thumb-size: 1rem;
158 | --thumb-position: 0%;
159 | --track-size: calc(var(--thumb-size) * 3);
160 | --padding-size: 4px;
161 |
162 | cursor: pointer;
163 | flex-shrink: 0;
164 | display: grid;
165 | align-items: center;
166 | grid: [track] 1fr / [track] 1fr;
167 | background-color: createThemeVar("Input:backgroundColor-Switch");
168 |
169 | width: var(--track-size);
170 | min-height: var(--thumb-size);
171 |
172 | padding: var(--padding-size);
173 | border: 1px solid createThemeVar("Input:borderColor-Switch");
174 | border-radius: 1rem;
175 |
176 | &::before {
177 | content: "";
178 | grid-area: track;
179 | height: var(--thumb-size);
180 | width: var(--thumb-size);
181 | background: createThemeVar("backgroundColor-indicator-Switch");
182 | border-radius: 50%;
183 |
184 | transform: translateX(var(--thumb-position));
185 | transition: 0.3s transform;
186 | }
187 |
188 | &:checked {
189 | background: createThemeVar("backgroundColor-checked-Switch");
190 |
191 | &::before {
192 | background: createThemeVar("backgroundColor-indicator-checked-Switch");
193 | --thumb-position: calc(
194 | var(--track-size) - var(--thumb-size) - 2 * var(--padding-size) - 2px
195 | );
196 | }
197 | }
198 |
199 | @include hoverAndDisabledState("Switch");
200 | @include checkedState("Switch");
201 |
202 | .forceHover {
203 | border-color: createThemeVar("Input:borderColor-Switch-default--hover");
204 | // Don't override background-color - let the existing background rules apply
205 | }
206 |
207 | &:focus-visible {
208 | outline-width: createThemeVar("Input:outlineWidth-Switch--focus");
209 | outline-color: createThemeVar("Input:outlineColor-Switch--focus");
210 | outline-style: createThemeVar("Input:outlineStyle-Switch--focus");
211 | outline-offset: createThemeVar("Input:outlineOffset-Switch--focus");
212 | }
213 |
214 | &:disabled {
215 | &::before {
216 | background-color: createThemeVar("backgroundColor-Switch-indicator--disabled");
217 | }
218 | }
219 |
220 | &.error {
221 | border-color: createThemeVar("Input:borderColor-Switch-error");
222 | }
223 |
224 | &.warning {
225 | border-color: createThemeVar("Input:borderColor-Switch-warning");
226 | }
227 |
228 | &.valid {
229 | border-color: createThemeVar("Input:borderColor-Switch-success");
230 | }
231 | }
232 | }
233 |
234 | // --- We export the theme variables to add them to the component renderer
235 | :export {
236 | themeVars: t.json-stringify($themeVars);
237 | }
238 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/FileInput/FileInputNative.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import type React from "react";
2 | import { type CSSProperties, useCallback, useEffect, useId, useRef, useState } from "react";
3 | import type { DropzoneRootProps } from "react-dropzone";
4 | import * as dropzone from "react-dropzone";
5 | import * as VisuallyHidden from "@radix-ui/react-visually-hidden";
6 | import classnames from "classnames";
7 |
8 | import styles from "./FileInput.module.scss";
9 |
10 | import type { RegisterComponentApiFn, UpdateStateFn } from "../../abstractions/RendererDefs";
11 | import { noop } from "../../components-core/constants";
12 | import { useEvent } from "../../components-core/utils/misc";
13 | import type { ValidationStatus } from "../abstractions";
14 | import type { ButtonThemeColor, ButtonVariant, SizeType, IconPosition } from "../abstractions";
15 | import { Button } from "../Button/ButtonNative";
16 | import { TextBox } from "../TextBox/TextBoxNative";
17 |
18 | // https://github.com/react-dropzone/react-dropzone/issues/1259
19 | const { useDropzone } = dropzone;
20 |
21 | // ============================================================================
22 | // React FileInput component implementation
23 |
24 | type Props = {
25 | // General
26 | id?: string;
27 | enabled?: boolean;
28 | style?: CSSProperties;
29 | className?: string;
30 | // Button styles
31 | buttonLabel?: string;
32 | variant?: ButtonVariant;
33 | buttonThemeColor?: ButtonThemeColor;
34 | buttonSize?: SizeType;
35 | buttonIcon?: React.ReactNode;
36 | buttonIconPosition?: IconPosition;
37 | // Input props
38 | updateState?: UpdateStateFn;
39 | onDidChange?: (newValue: File[]) => void;
40 | onFocus?: () => void;
41 | onBlur?: () => void;
42 | registerComponentApi?: RegisterComponentApiFn;
43 | validationStatus?: ValidationStatus;
44 | autoFocus?: boolean;
45 | // Component-specific props
46 | value?: any;
47 | initialValue?: any;
48 | acceptsFileType?: string | string[];
49 | multiple?: boolean;
50 | directory?: boolean;
51 | required?: boolean;
52 | placeholder?: string;
53 | buttonPosition?: "start" | "end";
54 | };
55 |
56 | export const defaultProps: Pick<
57 | Props,
58 | | "enabled"
59 | | "buttonPosition"
60 | | "buttonLabel"
61 | | "multiple"
62 | | "directory"
63 | | "updateState"
64 | | "onDidChange"
65 | | "onFocus"
66 | | "onBlur"
67 | | "buttonThemeColor"
68 | > = {
69 | enabled: true,
70 | buttonPosition: "end",
71 | buttonLabel: "Browse",
72 | multiple: false,
73 | directory: false,
74 | buttonThemeColor: "primary",
75 | updateState: noop,
76 | onDidChange: noop,
77 | onFocus: noop,
78 | onBlur: noop,
79 | };
80 |
81 | export const FileInput = ({
82 | id,
83 | enabled = defaultProps.enabled,
84 | style,
85 | className,
86 | placeholder,
87 | buttonPosition = defaultProps.buttonPosition,
88 | buttonLabel = defaultProps.buttonLabel,
89 | buttonIcon,
90 | buttonIconPosition,
91 | variant,
92 | buttonThemeColor,
93 | buttonSize,
94 |
95 | autoFocus,
96 | validationStatus,
97 | updateState = defaultProps.updateState,
98 | onDidChange = defaultProps.onDidChange,
99 | onFocus = defaultProps.onFocus,
100 | onBlur = defaultProps.onBlur,
101 | registerComponentApi,
102 | value,
103 | initialValue,
104 | acceptsFileType,
105 | multiple = defaultProps.multiple,
106 | directory = defaultProps.directory,
107 | required,
108 | ...rest
109 | }: Props) => {
110 | const _id = useId();
111 | id = id || _id;
112 | // Don't accept any (initial) value if it is not a File array explicitly
113 | const _initialValue: File[] | undefined = isFileArray(initialValue) ? initialValue : undefined;
114 | const _value: File[] | undefined = isFileArray(value) ? value : undefined;
115 |
116 | const buttonRef = useRef<HTMLButtonElement>(null);
117 | const _acceptsFileType =
118 | typeof acceptsFileType === "string" ? acceptsFileType : acceptsFileType?.join(",");
119 |
120 | useEffect(() => {
121 | if (autoFocus) {
122 | setTimeout(() => {
123 | buttonRef.current?.focus();
124 | }, 0);
125 | }
126 | }, [autoFocus]);
127 |
128 | // --- Initialize the related field with the input's initial value
129 | useEffect(() => {
130 | updateState({ value: _initialValue }, { initial: true });
131 | }, [_initialValue, updateState]);
132 |
133 | // --- Manage obtaining and losing the focus
134 | const handleOnFocus = useCallback((e: React.FocusEvent) => {
135 | // Only fire onFocus if focus is coming from outside the component
136 | if (!e.currentTarget.contains(e.relatedTarget as Node)) {
137 | onFocus?.();
138 | }
139 | }, [onFocus]);
140 |
141 | const handleOnBlur = useCallback((e: React.FocusEvent) => {
142 | // Only fire onBlur if focus is leaving the component entirely
143 | if (!e.currentTarget.contains(e.relatedTarget as Node)) {
144 | onBlur?.();
145 | }
146 | }, [onBlur]);
147 |
148 | const focus = useCallback(() => {
149 | buttonRef.current?.focus();
150 | }, []);
151 |
152 | // --- Handle the value change events for this input
153 | const onDrop = useCallback(
154 | (acceptedFiles: File[]) => {
155 | if (!acceptedFiles.length) return;
156 | updateState({ value: acceptedFiles });
157 | onDidChange(acceptedFiles);
158 | },
159 | [updateState, onDidChange],
160 | );
161 |
162 | const { getRootProps, getInputProps, open } = useDropzone({
163 | disabled: !enabled,
164 | multiple: multiple || directory,
165 | onDrop,
166 | noClick: true,
167 | noKeyboard: true,
168 | noDragEventsBubbling: true,
169 | useFsAccessApi: directory === false,
170 | });
171 |
172 | const doOpen = useEvent(() => {
173 | open();
174 | });
175 |
176 | useEffect(() => {
177 | registerComponentApi?.({
178 | focus,
179 | open: doOpen,
180 | });
181 | }, [focus, doOpen, registerComponentApi]);
182 |
183 | // Solution source: https://stackoverflow.com/questions/1084925/input-type-file-show-only-button
184 | return (
185 | <div
186 | className={classnames(styles.container, className, {
187 | [styles.buttonStart]: buttonPosition === "start",
188 | [styles.buttonEnd]: buttonPosition === "end",
189 | })}
190 | style={style}
191 | onFocus={handleOnFocus}
192 | onBlur={handleOnBlur}
193 | tabIndex={-1}
194 | {...rest}
195 | >
196 | <button
197 | id={id}
198 | {...getRootProps({
199 | tabIndex: 0,
200 | disabled: !enabled,
201 | className: styles.textBoxWrapper,
202 | onClick: open,
203 | ref: buttonRef,
204 | type: "button",
205 | })}
206 | >
207 | <VisuallyHidden.Root>
208 | <input
209 | {...getInputProps({
210 | webkitdirectory: directory ? "true" : undefined,
211 | } as DropzoneRootProps)}
212 | accept={_acceptsFileType}
213 | />
214 | </VisuallyHidden.Root>
215 |
216 | <TextBox
217 | placeholder={placeholder}
218 | enabled={enabled}
219 | value={_value?.map((v) => v.name).join(", ") || ""}
220 | validationStatus={validationStatus}
221 | readOnly
222 | tabIndex={-1}
223 | />
224 | </button>
225 | <Button
226 | disabled={!enabled}
227 | type="button"
228 | onClick={open}
229 | icon={buttonIcon}
230 | iconPosition={buttonIconPosition}
231 | variant={variant}
232 | themeColor={buttonThemeColor}
233 | size={buttonSize}
234 | className={styles.button}
235 | autoFocus={autoFocus}
236 | >
237 | {buttonLabel}
238 | </Button>
239 | </div>
240 | );
241 | };
242 |
243 | export function isFile(value: any): value is File {
244 | return value instanceof File;
245 | }
246 |
247 | export function isFileArray(value: any): value is File[] {
248 | return Array.isArray(value) && value.every(isFile);
249 | }
250 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/DatePicker/DatePicker.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import styles from "./DatePicker.module.scss";
2 |
3 | import { createComponentRenderer } from "../../components-core/renderers";
4 | import { parseScssVar } from "../../components-core/theming/themeVars";
5 | import {
6 | createMetadata,
7 | dAutoFocus,
8 | dDidChange,
9 | dEnabled,
10 | dEndIcon,
11 | dEndText,
12 | dGotFocus,
13 | dInitialValue,
14 | dLostFocus,
15 | dPlaceholder,
16 | dReadonly,
17 | dStartIcon,
18 | dStartText,
19 | dValidationStatus,
20 | } from "../metadata-helpers";
21 | import {
22 | dateFormats,
23 | DatePicker,
24 | DatePickerModeValues,
25 | defaultProps,
26 | WeekDays,
27 | } from "./DatePickerNative";
28 |
29 | const COMP = "DatePicker";
30 |
31 | export const DatePickerMd = createMetadata({
32 | status: "experimental",
33 | description:
34 | "`DatePicker` provides an interactive calendar interface for selecting single dates " +
35 | "or date ranges, with customizable formatting and validation options. It displays " +
36 | "a text input that opens a calendar popup when clicked, offering both keyboard and " +
37 | "mouse interaction.",
38 | props: {
39 | placeholder: dPlaceholder(),
40 | initialValue: dInitialValue(),
41 | autoFocus: dAutoFocus(),
42 | readOnly: dReadonly(),
43 | enabled: dEnabled(defaultProps.enabled),
44 | validationStatus: dValidationStatus(defaultProps.validationStatus),
45 | mode: {
46 | description: "The mode of the datepicker (single or range)",
47 | valueType: "string",
48 | availableValues: DatePickerModeValues,
49 | defaultValue: defaultProps.mode,
50 | },
51 | dateFormat: {
52 | description: "The format of the date displayed in the input field",
53 | valueType: "string",
54 | defaultValue: defaultProps.dateFormat,
55 | availableValues: dateFormats,
56 | },
57 | showWeekNumber: {
58 | description: "Whether to show the week number in the calendar",
59 | valueType: "boolean",
60 | defaultValue: defaultProps.showWeekNumber,
61 | },
62 | weekStartsOn: {
63 | description: "The first day of the week. 0 is Sunday, 1 is Monday, etc.",
64 | valueType: "number",
65 | defaultValue: defaultProps.weekStartsOn,
66 | availableValues: [
67 | {
68 | value: WeekDays.Sunday,
69 | description: "Sunday",
70 | },
71 | {
72 | value: WeekDays.Monday,
73 | description: "Monday",
74 | },
75 | {
76 | value: WeekDays.Tuesday,
77 | description: "Tuesday",
78 | },
79 | {
80 | value: WeekDays.Wednesday,
81 | description: "Wednesday",
82 | },
83 | {
84 | value: WeekDays.Thursday,
85 | description: "Thursday",
86 | },
87 | {
88 | value: WeekDays.Friday,
89 | description: "Friday",
90 | },
91 | {
92 | value: WeekDays.Saturday,
93 | description: "Saturday",
94 | },
95 | ],
96 | },
97 | startDate: {
98 | description:
99 | "The earliest month to start the month navigation from (inclusive). " +
100 | "If not defined, the component allows any dates in the past. " +
101 | "Accepts the same date format as the `initialValue`." +
102 | "Example: '2023-01-01' ensures the first month to select a date from is January 2023.",
103 | valueType: "string",
104 | },
105 | endDate: {
106 | description:
107 | "The latest month to start the month navigation from (inclusive). " +
108 | "If not defined, the component allows any future dates. " +
109 | "Accepts the same date format as the `initialValue`." +
110 | "Example: '2023-12-31' ensures the last month to select a date from is December 2023.",
111 | valueType: "string",
112 | },
113 | disabledDates: {
114 | description: "An optional array of dates that are to be disabled.",
115 | valueType: "any",
116 | },
117 | inline: {
118 | description:
119 | "If set to true, the calendar is always visible and its panel is rendered as part of the layout." +
120 | " If false, the calendar is shown in a popup when the input is focused or clicked.",
121 | valueType: "boolean",
122 | defaultValue: defaultProps.inline,
123 | },
124 | startText: dStartText(),
125 | startIcon: dStartIcon(),
126 | endText: dEndText(),
127 | endIcon: dEndIcon(),
128 | },
129 | events: {
130 | didChange: dDidChange(COMP),
131 | gotFocus: dGotFocus(COMP),
132 | lostFocus: dLostFocus(COMP),
133 | },
134 | apis: {
135 | focus: {
136 | description: `Focus the ${COMP} component.`,
137 | signature: "focus(): void",
138 | },
139 | value: {
140 | description: `You can query the component's value. If no value is set, it will retrieve \`undefined\`.`,
141 | signature: "get value(): any",
142 | },
143 | setValue: {
144 | description: `This method sets the current value of the ${COMP}.`,
145 | signature: "set value(value: any): void",
146 | parameters: {
147 | value: "The new value to set for the date picker.",
148 | },
149 | },
150 | },
151 | themeVars: parseScssVar(styles.themeVars),
152 | defaultThemeVars: {
153 | [`boxShadow-menu-${COMP}`]: "$boxShadow-md",
154 | [`borderRadius-menu-${COMP}`]: "$borderRadius",
155 | [`textColor-value-${COMP}`]: "$textColor-primary",
156 | [`borderColor-selectedItem-${COMP}`]: "$color-primary-200",
157 | [`backgroundColor-menu-${COMP}`]: "$color-surface-50",
158 | [`backgroundColor-item-${COMP}--hover`]: "$color-surface-100",
159 | [`backgroundColor-item-${COMP}--active`]: "$color-surface-200",
160 | [`paddingVertical-${COMP}`]: "$space-2",
161 | [`paddingHorizontal-${COMP}`]: "$space-2",
162 | },
163 | });
164 |
165 | export const datePickerComponentRenderer = createComponentRenderer(
166 | COMP,
167 | DatePickerMd,
168 | ({
169 | node,
170 | state,
171 | updateState,
172 | extractValue,
173 | className,
174 | lookupEventHandler,
175 | registerComponentApi,
176 | }) => {
177 | return (
178 | <DatePicker
179 | className={className}
180 | mode={extractValue(node.props?.mode)}
181 | value={state?.value}
182 | initialValue={extractValue(node.props.initialValue)}
183 | enabled={extractValue.asOptionalBoolean(node.props.enabled)}
184 | placeholder={extractValue.asOptionalString(node.props.placeholder)}
185 | validationStatus={extractValue(node.props.validationStatus)}
186 | updateState={updateState}
187 | onDidChange={lookupEventHandler("didChange")}
188 | onFocus={lookupEventHandler("gotFocus")}
189 | onBlur={lookupEventHandler("lostFocus")}
190 | registerComponentApi={registerComponentApi}
191 | dateFormat={extractValue(node.props.dateFormat)}
192 | showWeekNumber={extractValue.asOptionalBoolean(node.props.showWeekNumber)}
193 | weekStartsOn={extractValue(node.props.weekStartsOn)}
194 | startDate={extractValue(node.props.startDate)}
195 | endDate={extractValue(node.props.endDate)}
196 | disabledDates={extractValue(node.props.disabledDates)}
197 | inline={extractValue.asOptionalBoolean(node.props.inline)}
198 | startText={extractValue.asOptionalString(node.props.startText)}
199 | startIcon={extractValue.asOptionalString(node.props.startIcon)}
200 | endText={extractValue.asOptionalString(node.props.endText)}
201 | endIcon={extractValue.asOptionalString(node.props.endIcon)}
202 | readOnly={extractValue.asOptionalBoolean(node.props.readOnly)}
203 | autoFocus={extractValue.asOptionalBoolean(node.props.autoFocus)}
204 | />
205 | );
206 | },
207 | );
208 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Card/Card.spec.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { getBounds, SKIP_REASON } from "../../testing/component-test-helpers";
2 | import { expect, test } from "../../testing/fixtures";
3 |
4 | // =============================================================================
5 | // BASIC FUNCTIONALITY TESTS
6 | // =============================================================================
7 |
8 | test.describe("Basic Functionality", () => {
9 | test("Card renders", async ({ initTestBed, createCardDriver }) => {
10 | await initTestBed(`<Card />`);
11 | const driver = await createCardDriver();
12 | await expect(driver.component).toBeVisible();
13 | });
14 |
15 | test("Card renders with title", async ({ initTestBed, createCardDriver }) => {
16 | await initTestBed(`<Card title="Test Title" />`);
17 | const title = (await createCardDriver()).component.getByRole("heading");
18 | await expect(title).toBeVisible();
19 | await expect(title).toHaveText("Test Title");
20 | });
21 |
22 | test("Card renders with subtitle", async ({ initTestBed, createCardDriver }) => {
23 | await initTestBed(`<Card subtitle="Test Subtitle" />`);
24 | const subtitle = (await createCardDriver()).component.locator("div").first();
25 | await expect(subtitle).toBeVisible();
26 | await expect(subtitle).toHaveText("Test Subtitle");
27 | });
28 |
29 | test("Card renders with both title and subtitle", async ({ initTestBed, createCardDriver }) => {
30 | await initTestBed(`
31 | <Card title="Test Title" subtitle="Test Subtitle">
32 | <Text value="Card content" />
33 | </Card>
34 | `);
35 | const driver = await createCardDriver();
36 | const title = driver.component.getByRole("heading");
37 | const subtitle = driver.component.getByText("Test Subtitle");
38 |
39 | await expect(title).toHaveText("Test Title");
40 | await expect(subtitle).toBeVisible();
41 | });
42 |
43 | test("displays avatar when avatarUrl is provided", async ({ initTestBed, createCardDriver }) => {
44 | await initTestBed(`<Card avatarUrl="/resources/flower-640x480.jpg" />`);
45 | const avatar = (await createCardDriver()).avatar;
46 | await expect(avatar).toBeVisible();
47 | await expect(avatar).toHaveAttribute("src", "/resources/flower-640x480.jpg");
48 | });
49 |
50 | test("clicking linkTo title navigates", async ({ page, initTestBed, createCardDriver }) => {
51 | await initTestBed(`<Card title="Clickable Title" linkTo="/test-link" />`);
52 | const titleLink = (await createCardDriver()).component.getByRole("link", {
53 | name: "Clickable Title",
54 | });
55 | await titleLink.click();
56 | await expect(page).toHaveURL(/\/test-link$/);
57 | });
58 |
59 | test("showAvatar=false hides avatar even when avatarUrl is provided", async ({
60 | initTestBed,
61 | createCardDriver,
62 | }) => {
63 | await initTestBed(`
64 | <Card avatarUrl="https://i.pravatar.cc/100" showAvatar="false" title="Test Title" />
65 | `);
66 | const driver = await createCardDriver();
67 | await expect(driver.avatar).not.toBeVisible();
68 | await expect(driver.component.getByText("Test Title")).toBeVisible();
69 | });
70 |
71 | test("showAvatar displays initials with single word title", async ({
72 | initTestBed,
73 | createCardDriver,
74 | }) => {
75 | await initTestBed(`<Card showAvatar="true" title="John" />`);
76 | await expect(
77 | (await createCardDriver()).component.getByText("J", { exact: true }),
78 | ).toBeVisible();
79 | });
80 |
81 | test("showAvatar=true with empty title displays no initials", async ({
82 | initTestBed,
83 | createCardDriver,
84 | }) => {
85 | await initTestBed(`<Card showAvatar="true" />`);
86 | const avatar = (await createCardDriver()).avatar;
87 | await expect(avatar).toHaveText(/^$/);
88 | });
89 |
90 | test("linkTo without title does not create link", async ({ initTestBed, createCardDriver }) => {
91 | await initTestBed(`
92 | <Card linkTo="/test-link">
93 | <Text value="Content" />
94 | </Card>
95 | `);
96 | const driver = await createCardDriver();
97 | await expect(driver.component.getByRole("link")).not.toBeVisible();
98 | await expect(driver.component.getByText("Content")).toBeVisible();
99 | });
100 |
101 | test("orientation horizontal displays children in row", async ({
102 | initTestBed,
103 | createTextDriver,
104 | }) => {
105 | await initTestBed(`
106 | <Card orientation="horizontal">
107 | <Text testId="text-1" value="Child 1" />
108 | <Text testId="text-2" value="Child 2" />
109 | </Card>
110 | `);
111 | const text1Driver = await createTextDriver("text-1");
112 | const text2Driver = await createTextDriver("text-2");
113 |
114 | const { right: text1Right } = await getBounds(text1Driver);
115 | const { right: text2Left } = await getBounds(text2Driver);
116 | expect(text1Right).toBeLessThan(text2Left);
117 | });
118 |
119 | test("orientation vertical displays children in column", async ({
120 | initTestBed,
121 | createTextDriver,
122 | }) => {
123 | await initTestBed(`
124 | <Card orientation="vertical">
125 | <Text testId="text-1" value="Child 1" />
126 | <Text testId="text-2" value="Child 2" />
127 | </Card>
128 | `);
129 | const text1Driver = await createTextDriver("text-1");
130 | const text2Driver = await createTextDriver("text-2");
131 |
132 | const { bottom: text1Bottom } = await getBounds(text1Driver);
133 | const { top: text2Top } = await getBounds(text2Driver);
134 | expect(text1Bottom).toBeLessThan(text2Top);
135 | });
136 | });
137 |
138 | // =============================================================================
139 | // EVENT HANDLING TESTS
140 | // =============================================================================
141 |
142 | test.describe("Event Handling", () => {
143 | test("click event is triggered when Card is clicked", async ({
144 | initTestBed,
145 | createCardDriver,
146 | }) => {
147 | const { testStateDriver } = await initTestBed(`<Card onClick="testState = true" />`);
148 | await (await createCardDriver()).click();
149 | await expect.poll(testStateDriver.testState).toEqual(true);
150 | });
151 |
152 | test("Card click does not interfere with link click", async ({
153 | page,
154 | initTestBed,
155 | createCardDriver,
156 | createTextDriver,
157 | }) => {
158 | await initTestBed(`
159 | <Card title="Title" linkTo="/test-link" onClick="testState = true">
160 | <Text testId="text-1" when="{testState}" value="visible" />
161 | </Card>
162 | `);
163 | const cardDriver = await createCardDriver();
164 | const textDriver = await createTextDriver("text-1");
165 |
166 | await cardDriver.click();
167 | await expect(textDriver.component).toHaveText("visible");
168 | await expect(page).not.toHaveURL(/\/test-link$/);
169 | });
170 |
171 | test("Link click does not interfere with Card click", async ({
172 | page,
173 | initTestBed,
174 | createCardDriver,
175 | createTextDriver,
176 | }) => {
177 | const { testStateDriver } = await initTestBed(`
178 | <Card title="Title" linkTo="/test-link" onClick="testState = true">
179 | <Text testId="text-1" when="{testState}" value="visible" />
180 | </Card>
181 | `);
182 |
183 | const textDriver = await createTextDriver("text-1");
184 | const title = (await createCardDriver()).component.getByRole("heading");
185 |
186 | await expect(textDriver.component).not.toBeVisible();
187 | await title.click();
188 | await page.waitForTimeout(200);
189 | await expect(page).toHaveURL(/\/test-link$/);
190 | await expect(textDriver.component).toBeVisible();
191 | });
192 | });
193 |
```
--------------------------------------------------------------------------------
/packages/xmlui-website-blocks/src/HeroSection/HeroSection.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import styles from "./HeroSection.module.scss";
2 |
3 | import { createComponentRenderer, createMetadata, dComponent, d, parseScssVar } from "xmlui";
4 | import { HeroSection, defaultProps } from "./HeroSectionNative";
5 |
6 | const COMP = "HeroSection";
7 |
8 | export const HeroSectionMd = createMetadata({
9 | status: "experimental",
10 | description: "HeroSection",
11 | parts: {
12 | header: {
13 | description: "The header section containing all text content and CTA button",
14 | },
15 | content: {
16 | description: "The content section containing image and children",
17 | },
18 | headingSection: {
19 | description: "The heading section containing preamble, headline, and subheadline",
20 | },
21 | preamble: {
22 | description: "The preamble text for the hero section",
23 | },
24 | headline: {
25 | description: "The headline text for the hero section",
26 | },
27 | subheadline: {
28 | description: "The subheadline text for the hero section",
29 | },
30 | mainText: {
31 | description: "The main text content for the hero section",
32 | },
33 | ctaButton: {
34 | description: "The call-to-action button for the hero section",
35 | },
36 | image: {
37 | description: "The image for the hero section",
38 | },
39 | background: {
40 | description: "The background template area of the hero section",
41 | },
42 | },
43 | props: {
44 | headerAlignment: {
45 | description: "Alignment of the header content",
46 | type: "string",
47 | defaultValue: "center",
48 | options: ["start", "center", "end"],
49 | },
50 | contentPlacement: {
51 | description: "Position of the content area relative to the header",
52 | type: "string",
53 | defaultValue: defaultProps.contentPlacement,
54 | options: ["left", "right", "bottom"],
55 | },
56 | contentAlignment: {
57 | description: "Horizontal alignment of the content within its area",
58 | type: "string",
59 | defaultValue: defaultProps.contentAlignment,
60 | options: ["start", "center", "end"],
61 | },
62 | headerWidth: {
63 | description: "Width of the header section in horizontal layouts",
64 | type: "string",
65 | defaultValue: defaultProps.headerWidth,
66 | },
67 | contentWidth: {
68 | description: "Width of the hero content (header + content sections)",
69 | type: "string",
70 | defaultValue: defaultProps.contentWidth,
71 | },
72 | gap: {
73 | description: "Gap between header and content sections",
74 | type: "string",
75 | },
76 | preamble: {
77 | description: "The preamble text for the hero section",
78 | type: "string",
79 | },
80 | headline: {
81 | description: "The headline text for the hero section",
82 | type: "string",
83 | },
84 | subheadline: {
85 | description: "The subheadline text for the hero section",
86 | type: "string",
87 | },
88 | mainText: {
89 | description: "The main text content for the hero section",
90 | type: "string",
91 | },
92 | mainTextTemplate: dComponent("The template for the text content in the hero section"),
93 | ctaButtonIcon: {
94 | description: "The icon for the call-to-action button",
95 | type: "string",
96 | },
97 | ctaButtonText: {
98 | description: "The text for the call-to-action button",
99 | type: "string",
100 | },
101 | ctaButtonTemplate: dComponent("The template for the call-to-action button"),
102 | fullWidthBackground: {
103 | description: "Whether the background should span the full width of the viewport",
104 | type: "boolean",
105 | defaultValue: defaultProps.fullWidthBackground,
106 | },
107 | image: {
108 | description: "The image for the hero section",
109 | type: "string",
110 | },
111 | imageWidth: {
112 | description: "The width of the image",
113 | type: "string",
114 | },
115 | imageHeight: {
116 | description: "The height of the image",
117 | type: "string",
118 | },
119 | backgroundTemplate: dComponent("The template for the background of the hero section"),
120 | headerTone: {
121 | description: "The tone for the header section, affecting text colors",
122 | type: "string",
123 | options: ["light", "dark", "reverse"],
124 | defaultValue: "dark",
125 | },
126 | contentTone: {
127 | description: "The tone for the content section, affecting text colors",
128 | type: "string",
129 | options: ["light", "dark", "reverse"],
130 | defaultValue: "dark",
131 | },
132 | className: d("Additional CSS class names to apply to the hero section", undefined, "string"),
133 | },
134 | events: {
135 | ctaClick: d("Triggered when the call-to-action button is clicked"),
136 | },
137 | themeVars: parseScssVar(styles.themeVars),
138 | defaultThemeVars: {
139 | [`paddingTop-${COMP}`]: "$space-12",
140 | [`paddingBottom-${COMP}`]: "$space-12",
141 | [`paddingHorizontal-${COMP}`]: "$space-12",
142 | [`fontSize-headline-${COMP}`]: "3em",
143 | [`fontWeight-headline-${COMP}`]: "$fontWeight-bold",
144 | [`lineHeight-headline-${COMP}`]: "1.4em",
145 | [`gap-headline-${COMP}`]: "$space-8",
146 | [`fontSize-subheadline-${COMP}`]: "2em",
147 | [`lineHeight-subheadline-${COMP}`]: "1.1em",
148 | [`fontWeight-subheadline-${COMP}`]: "$fontWeight-bold",
149 | [`gap-subheadline-${COMP}`]: "$space-4",
150 | [`fontSize-mainText-${COMP}`]: "1.4em",
151 | [`lineHeight-mainText-${COMP}`]: "1.1em",
152 | [`gap-mainText-${COMP}`]: "$space-4",
153 | [`textColor-preamble-${COMP}`]: "$textColor-primary",
154 | [`textColor-headline-${COMP}`]: "$textColor-primary",
155 | [`textColor-subheadline-${COMP}`]: "$textColor-primary",
156 | [`textColor-mainText-${COMP}`]: "$textColor-primary",
157 | },
158 | });
159 |
160 | export const heroSectionComponentRenderer = createComponentRenderer(
161 | COMP,
162 | HeroSectionMd,
163 | ({ node, extractValue, renderChild, lookupEventHandler, className }) => {
164 | const props = (node.props as typeof HeroSectionMd.props)!;
165 | return (
166 | <HeroSection
167 | headerAlignment={extractValue(props.headerAlignment)}
168 | contentPlacement={extractValue(props.contentPlacement)}
169 | contentAlignment={extractValue(props.contentAlignment)}
170 | headerWidth={extractValue(props.headerWidth)}
171 | contentWidth={extractValue(props.contentWidth)}
172 | headerTone={extractValue(props.headerTone)}
173 | contentTone={extractValue(props.contentTone)}
174 | gap={extractValue(props.gap)}
175 | preamble={extractValue(props.preamble)}
176 | headline={extractValue(props.headline)}
177 | subheadline={extractValue(props.subheadline)}
178 | mainText={extractValue(props.mainText)}
179 | mainTextTemplate={renderChild(props.mainTextTemplate as any)}
180 | ctaButtonIcon={extractValue(props.ctaButtonIcon)}
181 | ctaButtonText={extractValue(props.ctaButtonText)}
182 | ctaButtonTemplate={renderChild(props.ctaButtonTemplate as any)}
183 | image={extractValue(props.image)}
184 | imageWidth={extractValue(props.imageWidth)}
185 | imageHeight={extractValue(props.imageHeight)}
186 | fullWidthBackground={extractValue.asOptionalBoolean(props.fullWidthBackground)}
187 | className={extractValue(className)}
188 | onCtaClick={lookupEventHandler("ctaClick")}
189 | backgroundTemplate={renderChild(props.backgroundTemplate as any)}
190 | >
191 | {renderChild(node.children)}
192 | </HeroSection>
193 | );
194 | },
195 | );
196 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/NestedApp/AppWithCodeViewNative.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { type ReactNode, useCallback, useRef, useState } from "react";
2 | import { IndexAwareNestedApp } from "./NestedAppNative";
3 | import { Markdown } from "../Markdown/Markdown";
4 | import type { ThemeTone } from "../../abstractions/ThemingDefs";
5 | import { Button } from "../Button/ButtonNative";
6 | import styles from "./NestedApp.module.scss";
7 | import { Tooltip } from "./Tooltip";
8 | import { RxOpenInNewWindow } from "react-icons/rx";
9 | import { LiaUndoAltSolid } from "react-icons/lia";
10 | import { createQueryString, withoutTrailingSlash } from "./utils";
11 | import { useAppContext } from "../../components-core/AppContext";
12 | import classnames from "classnames";
13 | import Logo from "./logo.svg?react";
14 | import { useTheme } from "../../components-core/theming/ThemeContext";
15 |
16 | type AppWithCodeViewNativeProps = {
17 | // Markdown content to display in the left column
18 | markdown: string;
19 | // Display layout in side-by-side mode (horizontal) when true,
20 | // or stacked (vertical) when false or undefined
21 | splitView?: boolean;
22 | // Indicates that the split view should initially show the code
23 | initiallyShowCode?: boolean;
24 | // Optional URL for the playground pop-out
25 | popOutUrl?: string;
26 | api?: any;
27 | app: string;
28 | components?: any[];
29 | config?: any;
30 | activeTone?: ThemeTone;
31 | activeTheme?: string;
32 | title?: string;
33 | height?: string | number;
34 | allowPlaygroundPopup?: boolean;
35 | withFrame?: boolean;
36 | noHeader?: boolean;
37 | immediate?: boolean;
38 | withSplashScreen?: boolean;
39 | closeButton?: ReactNode;
40 | controlsWidth?: string | number;
41 | };
42 |
43 | /**
44 | * A component that displays markdown content on the left and a NestedApp on the right
45 | */
46 | export function AppWithCodeViewNative({
47 | markdown,
48 | splitView,
49 | withFrame = true,
50 | noHeader = false,
51 | initiallyShowCode = false,
52 | popOutUrl,
53 | app,
54 | api,
55 | components = [],
56 | config,
57 | activeTone,
58 | activeTheme,
59 | title,
60 | height,
61 | allowPlaygroundPopup,
62 | withSplashScreen,
63 | immediate,
64 | closeButton = null,
65 | controlsWidth,
66 | }: AppWithCodeViewNativeProps): ReactNode {
67 | const [showCode, setShowCode] = useState(initiallyShowCode);
68 | const appContext = useAppContext();
69 | const [refreshVersion, setRefreshVersion] = useState(0);
70 | const { activeTheme: currentTheme, activeThemeTone, activeThemeId } = useTheme();
71 |
72 | const safePopOutUrl = withoutTrailingSlash(
73 | popOutUrl || appContext?.appGlobals?.popOutUrl || "https://playground.xmlui.org/#/playground",
74 | );
75 | const openPlayground = useCallback(async () => {
76 | const data = {
77 | standalone: {
78 | app,
79 | components,
80 | config: {
81 | name: title,
82 | themes: [currentTheme],
83 | defaultTheme: activeTheme,
84 | },
85 | api: api,
86 | },
87 | options: {
88 | fixedTheme: false,
89 | swapped: false,
90 | previewMode: false,
91 | orientation: "horizontal",
92 | activeTheme: activeThemeId || activeTheme,
93 | activeTone: activeTone || activeThemeTone,
94 | content: "app",
95 | },
96 | };
97 | const appQueryString = await createQueryString(JSON.stringify(data));
98 | window.open(`${safePopOutUrl}/#${appQueryString}`, "_blank");
99 | }, [app, components, title, activeTheme, api, activeTone, safePopOutUrl]);
100 |
101 | if (withFrame) {
102 | return (
103 | <>
104 | {!!markdown && !splitView && <Markdown>{markdown}</Markdown>}
105 | <div className={styles.nestedAppContainer} style={{ height }}>
106 | {!noHeader && (
107 | <div className={styles.header}>
108 | {!splitView && <span className={styles.headerText}>{title}</span>}
109 | {splitView && (
110 | <>
111 | <div className={styles.wrapper} style={{ width: controlsWidth }}>
112 | <Logo className={styles.logo} />
113 | </div>
114 | <div className={styles.viewControls}>
115 | <Button
116 | onClick={() => setShowCode(true)}
117 | className={classnames(styles.splitViewButton, {
118 | [styles.show]: showCode,
119 | [styles.hide]: !showCode,
120 | })}
121 | >
122 | XML
123 | </Button>
124 | <Button
125 | onClick={() => setShowCode(false)}
126 | className={classnames(styles.splitViewButton, {
127 | [styles.show]: !showCode,
128 | [styles.hide]: showCode,
129 | })}
130 | >
131 | UI
132 | </Button>
133 | </div>
134 | </>
135 | )}
136 | <div className={styles.wrapper} style={{ width: controlsWidth }}>
137 | {allowPlaygroundPopup && (
138 | <Tooltip
139 | trigger={
140 | <button
141 | className={styles.headerButton}
142 | onClick={() => {
143 | void openPlayground();
144 | }}
145 | >
146 | <RxOpenInNewWindow />
147 | </button>
148 | }
149 | label="View and edit in new full-width window"
150 | />
151 | )}
152 | <Tooltip
153 | trigger={
154 | <button
155 | className={styles.headerButton}
156 | onClick={() => {
157 | setShowCode(false);
158 | setRefreshVersion(refreshVersion + 1);
159 | }}
160 | >
161 | <LiaUndoAltSolid />
162 | </button>
163 | }
164 | label="Reset the app"
165 | />
166 | {closeButton}
167 | </div>
168 | </div>
169 | )}
170 | <div className={styles.contentContainer}>
171 | <Markdown
172 | className={classnames(styles.splitViewMarkdown, { [styles.hidden]: !showCode })}
173 | >
174 | {markdown}
175 | </Markdown>
176 | <IndexAwareNestedApp
177 | className={classnames({ [styles.hidden]: showCode })}
178 | height="100%"
179 | app={app}
180 | api={api}
181 | components={components}
182 | config={config}
183 | activeTone={activeTone}
184 | activeTheme={activeTheme}
185 | refreshVersion={refreshVersion}
186 | withSplashScreen={withSplashScreen}
187 | immediate={immediate}
188 | />
189 | </div>
190 | </div>
191 | </>
192 | );
193 | }
194 | return (
195 | <>
196 | {!!markdown && <Markdown>{markdown}</Markdown>}
197 | <IndexAwareNestedApp
198 | height={height}
199 | app={app}
200 | api={api}
201 | components={components}
202 | config={config}
203 | activeTone={activeTone}
204 | activeTheme={activeTheme}
205 | refreshVersion={refreshVersion}
206 | withSplashScreen={withSplashScreen}
207 | immediate={immediate}
208 | />
209 | </>
210 | );
211 | }
212 |
213 | /**
214 | * Export a named default for easier imports
215 | */
216 | export default AppWithCodeViewNative;
217 |
```