This is page 57 of 145. Use http://codebase.md/xmlui-org/xmlui/xmlui/mockApiDef.js?lines=false&page={x} to view the full context.
# Directory Structure
```
├── .changeset
│ └── config.json
├── .eslintrc.cjs
├── .github
│ ├── build-checklist.png
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows
│ ├── deploy-blog-optimized.yml
│ ├── deploy-blog-swa.yml
│ ├── deploy-blog.yml
│ ├── deploy-docs-optimized.yml
│ ├── deploy-docs-swa.yml
│ ├── deploy-docs.yml
│ ├── prepare-versions.yml
│ ├── release-packages.yml
│ ├── run-all-tests.yml
│ └── run-smoke-tests.yml
├── .gitignore
├── .prettierrc.js
├── .vscode
│ ├── launch.json
│ └── settings.json
├── blog
│ ├── .gitignore
│ ├── .gitkeep
│ ├── CHANGELOG.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── package.json
│ ├── public
│ │ ├── blog
│ │ │ ├── images
│ │ │ │ ├── an-advanced-codefence.gif
│ │ │ │ ├── an-advanced-codefence.mp4
│ │ │ │ ├── blog-page-component.png
│ │ │ │ ├── blog-scrabble.png
│ │ │ │ ├── codefence-runner.png
│ │ │ │ ├── integrated-blog-search.png
│ │ │ │ ├── lorem-ipsum.png
│ │ │ │ ├── playground-checkbox-source.png
│ │ │ │ ├── playground.png
│ │ │ │ ├── use-xmlui-mcp-to-find-a-howto.png
│ │ │ │ └── xmlui-demo-gallery.png
│ │ │ ├── introducing-xmlui.md
│ │ │ ├── lorem-ipsum.md
│ │ │ ├── newest-post.md
│ │ │ ├── older-post.md
│ │ │ ├── xmlui-playground.md
│ │ │ └── xmlui-powered-blog.md
│ │ ├── mockServiceWorker.js
│ │ ├── resources
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ └── for-download
│ │ │ │ └── xmlui
│ │ │ │ └── xmlui-standalone.umd.js
│ │ │ ├── github.svg
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ ├── rss.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ ├── staticwebapp.config.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ └── PageNotFound.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── blog-theme.ts
│ └── tsconfig.json
├── CONTRIBUTING.md
├── docs
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── ComponentRefLinks.txt
│ ├── content
│ │ ├── _meta.json
│ │ ├── components
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── APICall.md
│ │ │ ├── App.md
│ │ │ ├── AppHeader.md
│ │ │ ├── AppState.md
│ │ │ ├── AutoComplete.md
│ │ │ ├── Avatar.md
│ │ │ ├── Backdrop.md
│ │ │ ├── Badge.md
│ │ │ ├── BarChart.md
│ │ │ ├── Bookmark.md
│ │ │ ├── Breakout.md
│ │ │ ├── Button.md
│ │ │ ├── Card.md
│ │ │ ├── Carousel.md
│ │ │ ├── ChangeListener.md
│ │ │ ├── Checkbox.md
│ │ │ ├── CHStack.md
│ │ │ ├── ColorPicker.md
│ │ │ ├── Column.md
│ │ │ ├── ContentSeparator.md
│ │ │ ├── CVStack.md
│ │ │ ├── DataSource.md
│ │ │ ├── DateInput.md
│ │ │ ├── DatePicker.md
│ │ │ ├── DonutChart.md
│ │ │ ├── DropdownMenu.md
│ │ │ ├── EmojiSelector.md
│ │ │ ├── ExpandableItem.md
│ │ │ ├── FileInput.md
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FlowLayout.md
│ │ │ ├── Footer.md
│ │ │ ├── Form.md
│ │ │ ├── FormItem.md
│ │ │ ├── FormSection.md
│ │ │ ├── Fragment.md
│ │ │ ├── H1.md
│ │ │ ├── H2.md
│ │ │ ├── H3.md
│ │ │ ├── H4.md
│ │ │ ├── H5.md
│ │ │ ├── H6.md
│ │ │ ├── Heading.md
│ │ │ ├── HSplitter.md
│ │ │ ├── HStack.md
│ │ │ ├── Icon.md
│ │ │ ├── IFrame.md
│ │ │ ├── Image.md
│ │ │ ├── Items.md
│ │ │ ├── LabelList.md
│ │ │ ├── Legend.md
│ │ │ ├── LineChart.md
│ │ │ ├── Link.md
│ │ │ ├── List.md
│ │ │ ├── Logo.md
│ │ │ ├── Markdown.md
│ │ │ ├── MenuItem.md
│ │ │ ├── MenuSeparator.md
│ │ │ ├── ModalDialog.md
│ │ │ ├── NavGroup.md
│ │ │ ├── NavLink.md
│ │ │ ├── NavPanel.md
│ │ │ ├── NoResult.md
│ │ │ ├── NumberBox.md
│ │ │ ├── Option.md
│ │ │ ├── Page.md
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── Pages.md
│ │ │ ├── Pagination.md
│ │ │ ├── PasswordInput.md
│ │ │ ├── PieChart.md
│ │ │ ├── ProgressBar.md
│ │ │ ├── Queue.md
│ │ │ ├── RadioGroup.md
│ │ │ ├── RealTimeAdapter.md
│ │ │ ├── Redirect.md
│ │ │ ├── Select.md
│ │ │ ├── Slider.md
│ │ │ ├── Slot.md
│ │ │ ├── SpaceFiller.md
│ │ │ ├── Spinner.md
│ │ │ ├── Splitter.md
│ │ │ ├── Stack.md
│ │ │ ├── StickyBox.md
│ │ │ ├── SubMenuItem.md
│ │ │ ├── Switch.md
│ │ │ ├── TabItem.md
│ │ │ ├── Table.md
│ │ │ ├── TableOfContents.md
│ │ │ ├── Tabs.md
│ │ │ ├── Text.md
│ │ │ ├── TextArea.md
│ │ │ ├── TextBox.md
│ │ │ ├── Theme.md
│ │ │ ├── TimeInput.md
│ │ │ ├── Timer.md
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneSwitch.md
│ │ │ ├── Tooltip.md
│ │ │ ├── Tree.md
│ │ │ ├── VSplitter.md
│ │ │ ├── VStack.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ ├── xmlui-spreadsheet
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Spreadsheet.md
│ │ │ └── xmlui-website-blocks
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Carousel.md
│ │ │ ├── HelloMd.md
│ │ │ ├── HeroSection.md
│ │ │ └── ScrollToTop.md
│ │ └── extensions
│ │ ├── _meta.json
│ │ ├── xmlui-animations
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Animation.md
│ │ │ ├── FadeAnimation.md
│ │ │ ├── FadeInAnimation.md
│ │ │ ├── FadeOutAnimation.md
│ │ │ ├── ScaleAnimation.md
│ │ │ └── SlideInAnimation.md
│ │ └── xmlui-website-blocks
│ │ ├── _meta.json
│ │ ├── _overview.md
│ │ ├── Carousel.md
│ │ ├── HelloMd.md
│ │ ├── HeroSection.md
│ │ └── ScrollToTop.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── package.json
│ ├── public
│ │ ├── feed.rss
│ │ ├── mockServiceWorker.js
│ │ ├── pages
│ │ │ ├── _meta.json
│ │ │ ├── app-structure.md
│ │ │ ├── build-editor-component.md
│ │ │ ├── build-hello-world-component.md
│ │ │ ├── components-intro.md
│ │ │ ├── context-variables.md
│ │ │ ├── forms.md
│ │ │ ├── globals.md
│ │ │ ├── glossary.md
│ │ │ ├── helper-tags.md
│ │ │ ├── hosted-deployment.md
│ │ │ ├── howto
│ │ │ │ ├── assign-a-complex-json-literal-to-a-component-variable.md
│ │ │ │ ├── chain-a-refetch.md
│ │ │ │ ├── control-cache-invalidation.md
│ │ │ │ ├── debounce-user-input-for-api-calls.md
│ │ │ │ ├── debounce-with-changelistener.md
│ │ │ │ ├── debug-a-component.md
│ │ │ │ ├── delay-a-datasource-until-another-datasource-is-ready.md
│ │ │ │ ├── delegate-a-method.md
│ │ │ │ ├── do-custom-form-validation.md
│ │ │ │ ├── expose-a-method-from-a-component.md
│ │ │ │ ├── filter-and-transform-data-from-an-api.md
│ │ │ │ ├── group-items-in-list-by-a-property.md
│ │ │ │ ├── handle-background-operations.md
│ │ │ │ ├── hide-an-element-until-its-datasource-is-ready.md
│ │ │ │ ├── make-a-set-of-equal-width-cards.md
│ │ │ │ ├── make-a-table-responsive.md
│ │ │ │ ├── make-navpanel-width-responsive.md
│ │ │ │ ├── modify-a-value-reported-in-a-column.md
│ │ │ │ ├── paginate-a-list.md
│ │ │ │ ├── pass-data-to-a-modal-dialog.md
│ │ │ │ ├── react-to-button-click-not-keystrokes.md
│ │ │ │ ├── set-the-initial-value-of-a-select-from-fetched-data.md
│ │ │ │ ├── share-a-modaldialog-across-components.md
│ │ │ │ ├── sync-selections-between-table-and-list-views.md
│ │ │ │ ├── update-ui-optimistically.md
│ │ │ │ ├── use-built-in-form-validation.md
│ │ │ │ └── use-the-same-modaldialog-to-add-or-edit.md
│ │ │ ├── howto.md
│ │ │ ├── intro.md
│ │ │ ├── layout.md
│ │ │ ├── markup.md
│ │ │ ├── mcp.md
│ │ │ ├── modal-dialogs.md
│ │ │ ├── news-and-reviews.md
│ │ │ ├── reactive-intro.md
│ │ │ ├── refactoring.md
│ │ │ ├── routing-and-links.md
│ │ │ ├── samples
│ │ │ │ ├── color-palette.xmlui
│ │ │ │ ├── color-values.xmlui
│ │ │ │ ├── shadow-sizes.xmlui
│ │ │ │ ├── spacing-sizes.xmlui
│ │ │ │ ├── swatch.xmlui
│ │ │ │ ├── theme-gallery-brief.xmlui
│ │ │ │ └── theme-gallery.xmlui
│ │ │ ├── scoping.md
│ │ │ ├── scripting.md
│ │ │ ├── styles-and-themes
│ │ │ │ ├── common-units.md
│ │ │ │ ├── layout-props.md
│ │ │ │ ├── theme-variable-defaults.md
│ │ │ │ ├── theme-variables.md
│ │ │ │ └── themes.md
│ │ │ ├── template-properties.md
│ │ │ ├── test.md
│ │ │ ├── tutorial-01.md
│ │ │ ├── tutorial-02.md
│ │ │ ├── tutorial-03.md
│ │ │ ├── tutorial-04.md
│ │ │ ├── tutorial-05.md
│ │ │ ├── tutorial-06.md
│ │ │ ├── tutorial-07.md
│ │ │ ├── tutorial-08.md
│ │ │ ├── tutorial-09.md
│ │ │ ├── tutorial-10.md
│ │ │ ├── tutorial-11.md
│ │ │ ├── tutorial-12.md
│ │ │ ├── universal-properties.md
│ │ │ ├── user-defined-components.md
│ │ │ ├── vscode.md
│ │ │ ├── working-with-markdown.md
│ │ │ ├── working-with-text.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-charts
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── DonutChart.md
│ │ │ │ ├── LabelList.md
│ │ │ │ ├── Legend.md
│ │ │ │ ├── LineChart.md
│ │ │ │ └── PieChart.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ └── xmlui-spreadsheet
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ └── Spreadsheet.md
│ │ ├── resources
│ │ │ ├── devdocs
│ │ │ │ ├── debug-proxy-object-2.png
│ │ │ │ ├── debug-proxy-object.png
│ │ │ │ ├── table_editor_01.png
│ │ │ │ ├── table_editor_02.png
│ │ │ │ ├── table_editor_03.png
│ │ │ │ ├── table_editor_04.png
│ │ │ │ ├── table_editor_05.png
│ │ │ │ ├── table_editor_06.png
│ │ │ │ ├── table_editor_07.png
│ │ │ │ ├── table_editor_08.png
│ │ │ │ ├── table_editor_09.png
│ │ │ │ ├── table_editor_10.png
│ │ │ │ ├── table_editor_11.png
│ │ │ │ ├── table-editor-01.png
│ │ │ │ ├── table-editor-02.png
│ │ │ │ ├── table-editor-03.png
│ │ │ │ ├── table-editor-04.png
│ │ │ │ ├── table-editor-06.png
│ │ │ │ ├── table-editor-07.png
│ │ │ │ ├── table-editor-08.png
│ │ │ │ ├── table-editor-09.png
│ │ │ │ └── xmlui-rendering-of-tiptap-markdown.png
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ ├── clients.json
│ │ │ │ ├── daily-revenue.json
│ │ │ │ ├── dashboard-stats.json
│ │ │ │ ├── demo.xmlui
│ │ │ │ ├── demo.xmlui.xs
│ │ │ │ ├── downloads
│ │ │ │ │ └── downloads.json
│ │ │ │ ├── for-download
│ │ │ │ │ ├── index-with-api.html
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── mockApi.js
│ │ │ │ │ ├── start-darwin.sh
│ │ │ │ │ ├── start-linux.sh
│ │ │ │ │ ├── start.bat
│ │ │ │ │ └── xmlui
│ │ │ │ │ └── xmlui-standalone.umd.js
│ │ │ │ ├── getting-started
│ │ │ │ │ ├── cl-tutorial-final.zip
│ │ │ │ │ ├── cl-tutorial.zip
│ │ │ │ │ ├── cl-tutorial2.zip
│ │ │ │ │ ├── cl-tutorial3.zip
│ │ │ │ │ ├── cl-tutorial4.zip
│ │ │ │ │ ├── cl-tutorial5.zip
│ │ │ │ │ ├── cl-tutorial6.zip
│ │ │ │ │ ├── getting-started.zip
│ │ │ │ │ ├── hello-xmlui.zip
│ │ │ │ │ ├── xmlui-empty.zip
│ │ │ │ │ └── xmlui-starter.zip
│ │ │ │ ├── howto
│ │ │ │ │ └── component-icons
│ │ │ │ │ └── up-arrow.svg
│ │ │ │ ├── invoices.json
│ │ │ │ ├── monthly-status.json
│ │ │ │ ├── news-and-reviews.json
│ │ │ │ ├── products.json
│ │ │ │ ├── releases.json
│ │ │ │ ├── tutorials
│ │ │ │ │ ├── datasource
│ │ │ │ │ │ └── api.ts
│ │ │ │ │ └── p2do
│ │ │ │ │ ├── api.ts
│ │ │ │ │ └── todo-logo.svg
│ │ │ │ └── xmlui.json
│ │ │ ├── github.svg
│ │ │ ├── images
│ │ │ │ ├── apiaction-tutorial
│ │ │ │ │ ├── add-success.png
│ │ │ │ │ ├── apiaction-param.png
│ │ │ │ │ ├── change-completed.png
│ │ │ │ │ ├── change-in-progress.png
│ │ │ │ │ ├── confirm-delete.png
│ │ │ │ │ ├── data-error.png
│ │ │ │ │ ├── data-progress.png
│ │ │ │ │ ├── data-success.png
│ │ │ │ │ ├── display-1.png
│ │ │ │ │ ├── item-deleted.png
│ │ │ │ │ ├── item-updated.png
│ │ │ │ │ ├── missing-api-key.png
│ │ │ │ │ ├── new-item-added.png
│ │ │ │ │ └── test-message.png
│ │ │ │ ├── chat-api
│ │ │ │ │ └── domain-model.svg
│ │ │ │ ├── components
│ │ │ │ │ ├── image
│ │ │ │ │ │ └── breakfast.jpg
│ │ │ │ │ ├── markdown
│ │ │ │ │ │ └── colors.png
│ │ │ │ │ └── modal
│ │ │ │ │ ├── deep_link_dialog_1.jpg
│ │ │ │ │ └── deep_link_dialog_2.jpg
│ │ │ │ ├── create-apps
│ │ │ │ │ ├── collapsed-vertical.png
│ │ │ │ │ ├── using-forms-warning-dialog.png
│ │ │ │ │ └── using-forms.png
│ │ │ │ ├── datasource-tutorial
│ │ │ │ │ ├── data-with-header.png
│ │ │ │ │ ├── filtered-data.png
│ │ │ │ │ ├── filtered-items.png
│ │ │ │ │ ├── initial-page-items.png
│ │ │ │ │ ├── list-items.png
│ │ │ │ │ ├── next-page-items.png
│ │ │ │ │ ├── no-data.png
│ │ │ │ │ ├── pagination-1.jpg
│ │ │ │ │ ├── pagination-1.png
│ │ │ │ │ ├── polling-1.png
│ │ │ │ │ ├── refetch-data.png
│ │ │ │ │ ├── slow-loading.png
│ │ │ │ │ ├── test-message.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── unconventional-data.png
│ │ │ │ │ └── unfiltered-items.png
│ │ │ │ ├── flower.jpg
│ │ │ │ ├── get-started
│ │ │ │ │ ├── add-new-contact.png
│ │ │ │ │ ├── app-modified.png
│ │ │ │ │ ├── app-start.png
│ │ │ │ │ ├── app-with-boxes.png
│ │ │ │ │ ├── app-with-toast.png
│ │ │ │ │ ├── boilerplate-structure.png
│ │ │ │ │ ├── cl-initial.png
│ │ │ │ │ ├── cl-start.png
│ │ │ │ │ ├── contact-counts.png
│ │ │ │ │ ├── contact-dialog-title.png
│ │ │ │ │ ├── contact-dialog.png
│ │ │ │ │ ├── contact-menus.png
│ │ │ │ │ ├── contact-predicates.png
│ │ │ │ │ ├── context-menu.png
│ │ │ │ │ ├── dashboard-numbers.png
│ │ │ │ │ ├── default-contact-list.png
│ │ │ │ │ ├── delete-contact.png
│ │ │ │ │ ├── delete-task.png
│ │ │ │ │ ├── detailed-template.png
│ │ │ │ │ ├── edit-contact-details.png
│ │ │ │ │ ├── edited-contact-saved.png
│ │ │ │ │ ├── empty-sections.png
│ │ │ │ │ ├── filter-completed.png
│ │ │ │ │ ├── fullwidth-desktop.png
│ │ │ │ │ ├── fullwidth-mobile.png
│ │ │ │ │ ├── initial-table.png
│ │ │ │ │ ├── items-and-badges.png
│ │ │ │ │ ├── loading-message.png
│ │ │ │ │ ├── new-contact-button.png
│ │ │ │ │ ├── new-contact-saved.png
│ │ │ │ │ ├── no-empty-sections.png
│ │ │ │ │ ├── personal-todo-initial.png
│ │ │ │ │ ├── piechart.png
│ │ │ │ │ ├── review-today.png
│ │ │ │ │ ├── rudimentary-dashboard.png
│ │ │ │ │ ├── section-collapsed.png
│ │ │ │ │ ├── sectioned-items.png
│ │ │ │ │ ├── sections-ordered.png
│ │ │ │ │ ├── spacex-list-with-links.png
│ │ │ │ │ ├── spacex-list.png
│ │ │ │ │ ├── start-personal-todo-1.png
│ │ │ │ │ ├── submit-new-contact.png
│ │ │ │ │ ├── submit-new-task.png
│ │ │ │ │ ├── syntax-highlighting.png
│ │ │ │ │ ├── table-with-badge.png
│ │ │ │ │ ├── template-with-card.png
│ │ │ │ │ ├── test-emulated-api.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── todo-logo.png
│ │ │ │ │ └── xmlui-tools.png
│ │ │ │ ├── HelloApp.png
│ │ │ │ ├── HelloApp2.png
│ │ │ │ ├── logos
│ │ │ │ │ ├── xmlui1.svg
│ │ │ │ │ ├── xmlui2.svg
│ │ │ │ │ ├── xmlui3.svg
│ │ │ │ │ ├── xmlui4.svg
│ │ │ │ │ ├── xmlui5.svg
│ │ │ │ │ ├── xmlui6.svg
│ │ │ │ │ └── xmlui7.svg
│ │ │ │ ├── pdf
│ │ │ │ │ └── dummy-pdf.jpg
│ │ │ │ ├── rendering-engine
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ ├── Component.svg
│ │ │ │ │ ├── CompoundComponent.svg
│ │ │ │ │ ├── RootComponent.svg
│ │ │ │ │ └── tree-with-containers.svg
│ │ │ │ ├── reviewers-guide
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ └── incbutton-in-action.png
│ │ │ │ ├── tools
│ │ │ │ │ └── boilerplate-structure.png
│ │ │ │ ├── try.svg
│ │ │ │ ├── tutorial
│ │ │ │ │ ├── app-chat-history.png
│ │ │ │ │ ├── app-content-placeholder.png
│ │ │ │ │ ├── app-header-and-content.png
│ │ │ │ │ ├── app-links-channel-selected.png
│ │ │ │ │ ├── app-links-click.png
│ │ │ │ │ ├── app-navigation.png
│ │ │ │ │ ├── finished-ex01.png
│ │ │ │ │ ├── finished-ex02.png
│ │ │ │ │ ├── hello.png
│ │ │ │ │ ├── splash-screen-advanced.png
│ │ │ │ │ ├── splash-screen-after-click.png
│ │ │ │ │ ├── splash-screen-centered.png
│ │ │ │ │ ├── splash-screen-events.png
│ │ │ │ │ ├── splash-screen-expression.png
│ │ │ │ │ ├── splash-screen-reuse-after.png
│ │ │ │ │ ├── splash-screen-reuse-before.png
│ │ │ │ │ └── splash-screen.png
│ │ │ │ └── tutorial-01.png
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ ├── staticwebapp.config.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ ├── Boxes.xmlui
│ │ │ ├── Breadcrumb.xmlui
│ │ │ ├── ChangeLog.xmlui
│ │ │ ├── ColorPalette.xmlui
│ │ │ ├── DocumentLinks.xmlui
│ │ │ ├── DocumentPage.xmlui
│ │ │ ├── DocumentPageNoTOC.xmlui
│ │ │ ├── Icons.xmlui
│ │ │ ├── IncButton.xmlui
│ │ │ ├── IncButton2.xmlui
│ │ │ ├── NameValue.xmlui
│ │ │ ├── PageNotFound.xmlui
│ │ │ ├── PaletteItem.xmlui
│ │ │ ├── Palettes.xmlui
│ │ │ ├── SectionHeader.xmlui
│ │ │ ├── TBD.xmlui
│ │ │ ├── Test.xmlui
│ │ │ ├── ThemesIntro.xmlui
│ │ │ ├── ThousandThemes.xmlui
│ │ │ ├── TubeStops.xmlui
│ │ │ ├── TubeStops.xmlui.xs
│ │ │ └── TwoColumnCode.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ ├── docs-theme.ts
│ │ ├── earthtone.ts
│ │ ├── xmlui-gray-on-default.ts
│ │ ├── xmlui-green-on-default.ts
│ │ └── xmlui-orange-on-default.ts
│ └── tsconfig.json
├── LICENSE
├── package-lock.json
├── package.json
├── packages
│ ├── tsconfig.json
│ ├── xmlui-animations
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── Animation.tsx
│ │ ├── AnimationNative.tsx
│ │ ├── FadeAnimation.tsx
│ │ ├── FadeInAnimation.tsx
│ │ ├── FadeOutAnimation.tsx
│ │ ├── index.tsx
│ │ ├── ScaleAnimation.tsx
│ │ └── SlideInAnimation.tsx
│ ├── xmlui-devtools
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── devtools
│ │ │ │ ├── DevTools.tsx
│ │ │ │ ├── DevToolsNative.module.scss
│ │ │ │ ├── DevToolsNative.tsx
│ │ │ │ ├── ModalDialog.module.scss
│ │ │ │ ├── ModalDialog.tsx
│ │ │ │ ├── ModalVisibilityContext.tsx
│ │ │ │ ├── Tooltip.module.scss
│ │ │ │ ├── Tooltip.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── editor
│ │ │ │ └── Editor.tsx
│ │ │ └── index.tsx
│ │ └── vite.config-overrides.ts
│ ├── xmlui-hello-world
│ │ ├── .gitignore
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── HelloWorld.module.scss
│ │ ├── HelloWorld.tsx
│ │ ├── HelloWorldNative.tsx
│ │ └── index.tsx
│ ├── xmlui-os-frames
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── IPhoneFrame.module.scss
│ │ ├── IPhoneFrame.tsx
│ │ ├── MacOSAppFrame.module.scss
│ │ ├── MacOSAppFrame.tsx
│ │ ├── WindowsAppFrame.module.scss
│ │ └── WindowsAppFrame.tsx
│ ├── xmlui-pdf
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ ├── components
│ │ │ │ └── Pdf.xmlui
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── LazyPdfNative.tsx
│ │ ├── Pdf.module.scss
│ │ └── Pdf.tsx
│ ├── xmlui-playground
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── hooks
│ │ │ ├── usePlayground.ts
│ │ │ └── useToast.ts
│ │ ├── index.tsx
│ │ ├── playground
│ │ │ ├── Box.module.scss
│ │ │ ├── Box.tsx
│ │ │ ├── CodeSelector.module.scss
│ │ │ ├── CodeSelector.tsx
│ │ │ ├── ConfirmationDialog.module.scss
│ │ │ ├── ConfirmationDialog.tsx
│ │ │ ├── Editor.tsx
│ │ │ ├── Header.module.scss
│ │ │ ├── Header.tsx
│ │ │ ├── Playground.tsx
│ │ │ ├── PlaygroundContent.module.scss
│ │ │ ├── PlaygroundContent.tsx
│ │ │ ├── PlaygroundNative.module.scss
│ │ │ ├── PlaygroundNative.tsx
│ │ │ ├── Preview.tsx
│ │ │ ├── StandalonePlayground.tsx
│ │ │ ├── StandalonePlaygroundNative.module.scss
│ │ │ ├── StandalonePlaygroundNative.tsx
│ │ │ ├── ThemeSwitcher.module.scss
│ │ │ ├── ThemeSwitcher.tsx
│ │ │ └── utils.ts
│ │ ├── providers
│ │ │ ├── Toast.module.scss
│ │ │ └── ToastProvider.tsx
│ │ ├── state
│ │ │ └── store.ts
│ │ ├── themes
│ │ │ └── theme.ts
│ │ └── utils
│ │ └── helpers.ts
│ ├── xmlui-search
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── Search.module.scss
│ │ └── Search.tsx
│ ├── xmlui-spreadsheet
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── Spreadsheet.tsx
│ │ └── SpreadsheetNative.tsx
│ └── xmlui-website-blocks
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── demo
│ │ ├── components
│ │ │ ├── HeroBackgroundBreakoutPage.xmlui
│ │ │ ├── HeroBackgroundsPage.xmlui
│ │ │ ├── HeroContentsPage.xmlui
│ │ │ ├── HeroTextAlignPage.xmlui
│ │ │ ├── HeroTextPage.xmlui
│ │ │ └── HeroTonesPage.xmlui
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── default.ts
│ ├── index.html
│ ├── index.ts
│ ├── meta
│ │ └── componentsMetadata.ts
│ ├── package.json
│ ├── public
│ │ └── resources
│ │ ├── building.jpg
│ │ └── xmlui-logo.svg
│ └── src
│ ├── Carousel
│ │ ├── Carousel.module.scss
│ │ ├── Carousel.tsx
│ │ ├── CarouselContext.tsx
│ │ └── CarouselNative.tsx
│ ├── FancyButton
│ │ ├── FancyButton.module.scss
│ │ ├── FancyButton.tsx
│ │ └── FancyButton.xmlui
│ ├── Hello
│ │ ├── Hello.tsx
│ │ ├── Hello.xmlui
│ │ └── Hello.xmlui.xs
│ ├── HeroSection
│ │ ├── HeroSection.module.scss
│ │ ├── HeroSection.spec.ts
│ │ ├── HeroSection.tsx
│ │ └── HeroSectionNative.tsx
│ ├── index.tsx
│ ├── ScrollToTop
│ │ ├── ScrollToTop.module.scss
│ │ ├── ScrollToTop.tsx
│ │ └── ScrollToTopNative.tsx
│ └── vite-env.d.ts
├── playwright.config.ts
├── README.md
├── tools
│ ├── codefence
│ │ └── xmlui-code-fence-docs.md
│ ├── create-app
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── create-app.ts
│ │ ├── helpers
│ │ │ ├── copy.ts
│ │ │ ├── get-pkg-manager.ts
│ │ │ ├── git.ts
│ │ │ ├── install.ts
│ │ │ ├── is-folder-empty.ts
│ │ │ ├── is-writeable.ts
│ │ │ ├── make-dir.ts
│ │ │ └── validate-pkg.ts
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── templates
│ │ │ ├── default
│ │ │ │ └── ts
│ │ │ │ ├── gitignore
│ │ │ │ ├── index.html
│ │ │ │ ├── index.ts
│ │ │ │ ├── public
│ │ │ │ │ ├── mockServiceWorker.js
│ │ │ │ │ ├── resources
│ │ │ │ │ │ ├── favicon.ico
│ │ │ │ │ │ └── xmlui-logo.svg
│ │ │ │ │ └── serve.json
│ │ │ │ └── src
│ │ │ │ ├── components
│ │ │ │ │ ├── ApiAware.xmlui
│ │ │ │ │ ├── Home.xmlui
│ │ │ │ │ ├── IncButton.xmlui
│ │ │ │ │ └── PagePanel.xmlui
│ │ │ │ ├── config.ts
│ │ │ │ └── Main.xmlui
│ │ │ ├── index.ts
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ ├── create-xmlui-hello-world
│ │ ├── index.js
│ │ └── package.json
│ └── vscode
│ ├── .gitignore
│ ├── .vscode
│ │ ├── launch.json
│ │ └── tasks.json
│ ├── .vscodeignore
│ ├── build.sh
│ ├── CHANGELOG.md
│ ├── esbuild.js
│ ├── eslint.config.mjs
│ ├── formatter-docs.md
│ ├── generate-test-sample.sh
│ ├── LICENSE.md
│ ├── package-lock.json
│ ├── package.json
│ ├── README.md
│ ├── resources
│ │ ├── xmlui-logo.png
│ │ └── xmlui-markup-syntax-highlighting.png
│ ├── src
│ │ ├── extension.ts
│ │ └── server.ts
│ ├── syntaxes
│ │ └── xmlui.tmLanguage.json
│ ├── test-samples
│ │ └── sample.xmlui
│ ├── tsconfig.json
│ └── tsconfig.tsbuildinfo
├── turbo.json
└── xmlui
├── .gitignore
├── bin
│ ├── bootstrap.cjs
│ ├── bootstrap.js
│ ├── build-lib.ts
│ ├── build.ts
│ ├── index.ts
│ ├── preview.ts
│ ├── start.ts
│ ├── vite-xmlui-plugin.ts
│ └── viteConfig.ts
├── CHANGELOG.md
├── conventions
│ ├── component-qa-checklist.md
│ ├── copilot-conventions.md
│ ├── create-xmlui-components.md
│ ├── mermaid.md
│ ├── testing-conventions.md
│ └── xmlui-in-a-nutshell.md
├── dev-docs
│ ├── accessibility.md
│ ├── build-system.md
│ ├── build-xmlui.md
│ ├── component-behaviors.md
│ ├── component-metadata.md
│ ├── components-with-options.md
│ ├── containers.md
│ ├── data-operations.md
│ ├── glossary.md
│ ├── index.md
│ ├── next
│ │ ├── component-dev-guide.md
│ │ ├── configuration-management-enhancement-summary.md
│ │ ├── documentation-scripts-refactoring-complete-summary.md
│ │ ├── documentation-scripts-refactoring-plan.md
│ │ ├── duplicate-pattern-extraction-summary.md
│ │ ├── error-handling-standardization-summary.md
│ │ ├── generating-component-reference.md
│ │ ├── index.md
│ │ ├── logging-consistency-implementation-summary.md
│ │ ├── project-build.md
│ │ ├── project-structure.md
│ │ ├── theme-context.md
│ │ ├── tiptap-design-considerations.md
│ │ ├── working-with-code.md
│ │ ├── xmlui-runtime-architecture
│ │ └── xmlui-wcag-accessibility-report.md
│ ├── react-fundamentals.md
│ ├── release-method.md
│ ├── standalone-app.md
│ ├── theme-variables-refactoring.md
│ ├── ud-components.md
│ └── xmlui-repo.md
├── package.json
├── scripts
│ ├── coverage-only.js
│ ├── e2e-test-summary.js
│ ├── extract-component-metadata.js
│ ├── generate-docs
│ │ ├── build-downloads-map.mjs
│ │ ├── build-pages-map.mjs
│ │ ├── components-config.json
│ │ ├── configuration-management.mjs
│ │ ├── constants.mjs
│ │ ├── create-theme-files.mjs
│ │ ├── DocsGenerator.mjs
│ │ ├── error-handling.mjs
│ │ ├── extensions-config.json
│ │ ├── folders.mjs
│ │ ├── generate-summary-files.mjs
│ │ ├── get-docs.mjs
│ │ ├── input-handler.mjs
│ │ ├── logger.mjs
│ │ ├── logging-standards.mjs
│ │ ├── MetadataProcessor.mjs
│ │ ├── pattern-utilities.mjs
│ │ └── utils.mjs
│ ├── generate-metadata-markdown.js
│ ├── get-langserver-metadata.js
│ ├── inline-links.mjs
│ └── README-e2e-summary.md
├── src
│ ├── abstractions
│ │ ├── _conventions.md
│ │ ├── ActionDefs.ts
│ │ ├── AppContextDefs.ts
│ │ ├── ComponentDefs.ts
│ │ ├── ContainerDefs.ts
│ │ ├── ExtensionDefs.ts
│ │ ├── FunctionDefs.ts
│ │ ├── RendererDefs.ts
│ │ ├── scripting
│ │ │ ├── BlockScope.ts
│ │ │ ├── Compilation.ts
│ │ │ ├── LogicalThread.ts
│ │ │ ├── LoopScope.ts
│ │ │ ├── modules.ts
│ │ │ ├── ScriptParserError.ts
│ │ │ ├── Token.ts
│ │ │ ├── TryScope.ts
│ │ │ └── TryScopeExp.ts
│ │ └── ThemingDefs.ts
│ ├── components
│ │ ├── _conventions.md
│ │ ├── abstractions.ts
│ │ ├── Accordion
│ │ │ ├── Accordion.md
│ │ │ ├── Accordion.module.scss
│ │ │ ├── Accordion.spec.ts
│ │ │ ├── Accordion.tsx
│ │ │ ├── AccordionContext.tsx
│ │ │ ├── AccordionItem.tsx
│ │ │ ├── AccordionItemNative.tsx
│ │ │ └── AccordionNative.tsx
│ │ ├── Animation
│ │ │ └── AnimationNative.tsx
│ │ ├── APICall
│ │ │ ├── APICall.md
│ │ │ ├── APICall.spec.ts
│ │ │ ├── APICall.tsx
│ │ │ └── APICallNative.tsx
│ │ ├── App
│ │ │ ├── App.md
│ │ │ ├── App.module.scss
│ │ │ ├── App.spec.ts
│ │ │ ├── App.tsx
│ │ │ ├── AppLayoutContext.ts
│ │ │ ├── AppNative.tsx
│ │ │ ├── AppStateContext.ts
│ │ │ ├── doc-resources
│ │ │ │ ├── condensed-sticky.xmlui
│ │ │ │ ├── condensed.xmlui
│ │ │ │ ├── horizontal-sticky.xmlui
│ │ │ │ ├── horizontal.xmlui
│ │ │ │ ├── vertical-full-header.xmlui
│ │ │ │ ├── vertical-sticky.xmlui
│ │ │ │ └── vertical.xmlui
│ │ │ ├── IndexerContext.ts
│ │ │ ├── LinkInfoContext.ts
│ │ │ ├── SearchContext.tsx
│ │ │ ├── Sheet.module.scss
│ │ │ └── Sheet.tsx
│ │ ├── AppHeader
│ │ │ ├── AppHeader.md
│ │ │ ├── AppHeader.module.scss
│ │ │ ├── AppHeader.spec.ts
│ │ │ ├── AppHeader.tsx
│ │ │ └── AppHeaderNative.tsx
│ │ ├── AppState
│ │ │ ├── AppState.md
│ │ │ ├── AppState.spec.ts
│ │ │ ├── AppState.tsx
│ │ │ └── AppStateNative.tsx
│ │ ├── AutoComplete
│ │ │ ├── AutoComplete.md
│ │ │ ├── AutoComplete.module.scss
│ │ │ ├── AutoComplete.spec.ts
│ │ │ ├── AutoComplete.tsx
│ │ │ ├── AutoCompleteContext.tsx
│ │ │ └── AutoCompleteNative.tsx
│ │ ├── Avatar
│ │ │ ├── Avatar.md
│ │ │ ├── Avatar.module.scss
│ │ │ ├── Avatar.spec.ts
│ │ │ ├── Avatar.tsx
│ │ │ └── AvatarNative.tsx
│ │ ├── Backdrop
│ │ │ ├── Backdrop.md
│ │ │ ├── Backdrop.module.scss
│ │ │ ├── Backdrop.spec.ts
│ │ │ ├── Backdrop.tsx
│ │ │ └── BackdropNative.tsx
│ │ ├── Badge
│ │ │ ├── Badge.md
│ │ │ ├── Badge.module.scss
│ │ │ ├── Badge.spec.ts
│ │ │ ├── Badge.tsx
│ │ │ └── BadgeNative.tsx
│ │ ├── Bookmark
│ │ │ ├── Bookmark.md
│ │ │ ├── Bookmark.module.scss
│ │ │ ├── Bookmark.spec.ts
│ │ │ ├── Bookmark.tsx
│ │ │ └── BookmarkNative.tsx
│ │ ├── Breakout
│ │ │ ├── Breakout.module.scss
│ │ │ ├── Breakout.spec.ts
│ │ │ ├── Breakout.tsx
│ │ │ └── BreakoutNative.tsx
│ │ ├── Button
│ │ │ ├── Button-style.spec.ts
│ │ │ ├── Button.md
│ │ │ ├── Button.module.scss
│ │ │ ├── Button.spec.ts
│ │ │ ├── Button.tsx
│ │ │ └── ButtonNative.tsx
│ │ ├── Card
│ │ │ ├── Card.md
│ │ │ ├── Card.module.scss
│ │ │ ├── Card.spec.ts
│ │ │ ├── Card.tsx
│ │ │ └── CardNative.tsx
│ │ ├── Carousel
│ │ │ ├── Carousel.md
│ │ │ ├── Carousel.module.scss
│ │ │ ├── Carousel.spec.ts
│ │ │ ├── Carousel.tsx
│ │ │ ├── CarouselContext.tsx
│ │ │ ├── CarouselItem.tsx
│ │ │ ├── CarouselItemNative.tsx
│ │ │ └── CarouselNative.tsx
│ │ ├── ChangeListener
│ │ │ ├── ChangeListener.md
│ │ │ ├── ChangeListener.spec.ts
│ │ │ ├── ChangeListener.tsx
│ │ │ └── ChangeListenerNative.tsx
│ │ ├── chart-color-schemes.ts
│ │ ├── Charts
│ │ │ ├── AreaChart
│ │ │ │ ├── AreaChart.md
│ │ │ │ ├── AreaChart.spec.ts
│ │ │ │ ├── AreaChart.tsx
│ │ │ │ └── AreaChartNative.tsx
│ │ │ ├── BarChart
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── BarChart.module.scss
│ │ │ │ ├── BarChart.spec.ts
│ │ │ │ ├── BarChart.tsx
│ │ │ │ └── BarChartNative.tsx
│ │ │ ├── DonutChart
│ │ │ │ ├── DonutChart.spec.ts
│ │ │ │ └── DonutChart.tsx
│ │ │ ├── LabelList
│ │ │ │ ├── LabelList.module.scss
│ │ │ │ ├── LabelList.spec.ts
│ │ │ │ ├── LabelList.tsx
│ │ │ │ └── LabelListNative.tsx
│ │ │ ├── Legend
│ │ │ │ ├── Legend.spec.ts
│ │ │ │ ├── Legend.tsx
│ │ │ │ └── LegendNative.tsx
│ │ │ ├── LineChart
│ │ │ │ ├── LineChart.md
│ │ │ │ ├── LineChart.module.scss
│ │ │ │ ├── LineChart.spec.ts
│ │ │ │ ├── LineChart.tsx
│ │ │ │ └── LineChartNative.tsx
│ │ │ ├── PieChart
│ │ │ │ ├── PieChart.md
│ │ │ │ ├── PieChart.spec.ts
│ │ │ │ ├── PieChart.tsx
│ │ │ │ ├── PieChartNative.module.scss
│ │ │ │ └── PieChartNative.tsx
│ │ │ ├── RadarChart
│ │ │ │ ├── RadarChart.md
│ │ │ │ ├── RadarChart.spec.ts
│ │ │ │ ├── RadarChart.tsx
│ │ │ │ └── RadarChartNative.tsx
│ │ │ ├── Tooltip
│ │ │ │ ├── TooltipContent.module.scss
│ │ │ │ ├── TooltipContent.spec.ts
│ │ │ │ └── TooltipContent.tsx
│ │ │ └── utils
│ │ │ ├── abstractions.ts
│ │ │ └── ChartProvider.tsx
│ │ ├── Checkbox
│ │ │ ├── Checkbox.md
│ │ │ ├── Checkbox.spec.ts
│ │ │ └── Checkbox.tsx
│ │ ├── CodeBlock
│ │ │ ├── CodeBlock.module.scss
│ │ │ ├── CodeBlock.spec.ts
│ │ │ ├── CodeBlock.tsx
│ │ │ ├── CodeBlockNative.tsx
│ │ │ └── highlight-code.ts
│ │ ├── collectedComponentMetadata.ts
│ │ ├── ColorPicker
│ │ │ ├── ColorPicker.md
│ │ │ ├── ColorPicker.module.scss
│ │ │ ├── ColorPicker.spec.ts
│ │ │ ├── ColorPicker.tsx
│ │ │ └── ColorPickerNative.tsx
│ │ ├── Column
│ │ │ ├── Column.md
│ │ │ ├── Column.tsx
│ │ │ ├── ColumnNative.tsx
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ └── TableContext.tsx
│ │ ├── component-utils.ts
│ │ ├── ComponentProvider.tsx
│ │ ├── ComponentRegistryContext.tsx
│ │ ├── container-helpers.tsx
│ │ ├── ContentSeparator
│ │ │ ├── ContentSeparator.md
│ │ │ ├── ContentSeparator.module.scss
│ │ │ ├── ContentSeparator.spec.ts
│ │ │ ├── ContentSeparator.tsx
│ │ │ ├── ContentSeparatorNative.tsx
│ │ │ └── test-padding.xmlui
│ │ ├── DataSource
│ │ │ ├── DataSource.md
│ │ │ └── DataSource.tsx
│ │ ├── DateInput
│ │ │ ├── DateInput.md
│ │ │ ├── DateInput.module.scss
│ │ │ ├── DateInput.spec.ts
│ │ │ ├── DateInput.tsx
│ │ │ └── DateInputNative.tsx
│ │ ├── DatePicker
│ │ │ ├── DatePicker.md
│ │ │ ├── DatePicker.module.scss
│ │ │ ├── DatePicker.spec.ts
│ │ │ ├── DatePicker.tsx
│ │ │ └── DatePickerNative.tsx
│ │ ├── DropdownMenu
│ │ │ ├── DropdownMenu.md
│ │ │ ├── DropdownMenu.module.scss
│ │ │ ├── DropdownMenu.spec.ts
│ │ │ ├── DropdownMenu.tsx
│ │ │ ├── DropdownMenuNative.tsx
│ │ │ ├── MenuItem.md
│ │ │ └── SubMenuItem.md
│ │ ├── EmojiSelector
│ │ │ ├── EmojiSelector.md
│ │ │ ├── EmojiSelector.spec.ts
│ │ │ ├── EmojiSelector.tsx
│ │ │ └── EmojiSelectorNative.tsx
│ │ ├── ExpandableItem
│ │ │ ├── ExpandableItem.module.scss
│ │ │ ├── ExpandableItem.spec.ts
│ │ │ ├── ExpandableItem.tsx
│ │ │ └── ExpandableItemNative.tsx
│ │ ├── FileInput
│ │ │ ├── FileInput.md
│ │ │ ├── FileInput.module.scss
│ │ │ ├── FileInput.spec.ts
│ │ │ ├── FileInput.tsx
│ │ │ └── FileInputNative.tsx
│ │ ├── FileUploadDropZone
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FileUploadDropZone.module.scss
│ │ │ ├── FileUploadDropZone.spec.ts
│ │ │ ├── FileUploadDropZone.tsx
│ │ │ └── FileUploadDropZoneNative.tsx
│ │ ├── FlowLayout
│ │ │ ├── FlowLayout.md
│ │ │ ├── FlowLayout.module.scss
│ │ │ ├── FlowLayout.spec.ts
│ │ │ ├── FlowLayout.spec.ts-snapshots
│ │ │ │ └── Edge-cases-boxShadow-is-not-clipped-1-non-smoke-darwin.png
│ │ │ ├── FlowLayout.tsx
│ │ │ └── FlowLayoutNative.tsx
│ │ ├── Footer
│ │ │ ├── Footer.md
│ │ │ ├── Footer.module.scss
│ │ │ ├── Footer.spec.ts
│ │ │ ├── Footer.tsx
│ │ │ └── FooterNative.tsx
│ │ ├── Form
│ │ │ ├── Form.md
│ │ │ ├── Form.module.scss
│ │ │ ├── Form.spec.ts
│ │ │ ├── Form.tsx
│ │ │ ├── formActions.ts
│ │ │ ├── FormContext.ts
│ │ │ └── FormNative.tsx
│ │ ├── FormItem
│ │ │ ├── FormItem.md
│ │ │ ├── FormItem.module.scss
│ │ │ ├── FormItem.spec.ts
│ │ │ ├── FormItem.tsx
│ │ │ ├── FormItemNative.tsx
│ │ │ ├── HelperText.module.scss
│ │ │ ├── HelperText.tsx
│ │ │ ├── ItemWithLabel.tsx
│ │ │ └── Validations.ts
│ │ ├── FormSection
│ │ │ ├── FormSection.md
│ │ │ ├── FormSection.ts
│ │ │ └── FormSection.xmlui
│ │ ├── Fragment
│ │ │ ├── Fragment.spec.ts
│ │ │ └── Fragment.tsx
│ │ ├── Heading
│ │ │ ├── abstractions.ts
│ │ │ ├── H1.md
│ │ │ ├── H1.spec.ts
│ │ │ ├── H2.md
│ │ │ ├── H2.spec.ts
│ │ │ ├── H3.md
│ │ │ ├── H3.spec.ts
│ │ │ ├── H4.md
│ │ │ ├── H4.spec.ts
│ │ │ ├── H5.md
│ │ │ ├── H5.spec.ts
│ │ │ ├── H6.md
│ │ │ ├── H6.spec.ts
│ │ │ ├── Heading.md
│ │ │ ├── Heading.module.scss
│ │ │ ├── Heading.spec.ts
│ │ │ ├── Heading.tsx
│ │ │ └── HeadingNative.tsx
│ │ ├── HoverCard
│ │ │ ├── HoverCard.tsx
│ │ │ └── HovercardNative.tsx
│ │ ├── HtmlTags
│ │ │ ├── HtmlTags.module.scss
│ │ │ ├── HtmlTags.spec.ts
│ │ │ └── HtmlTags.tsx
│ │ ├── Icon
│ │ │ ├── AdmonitionDanger.tsx
│ │ │ ├── AdmonitionInfo.tsx
│ │ │ ├── AdmonitionNote.tsx
│ │ │ ├── AdmonitionTip.tsx
│ │ │ ├── AdmonitionWarning.tsx
│ │ │ ├── ApiIcon.tsx
│ │ │ ├── ArrowDropDown.module.scss
│ │ │ ├── ArrowDropDown.tsx
│ │ │ ├── ArrowDropUp.module.scss
│ │ │ ├── ArrowDropUp.tsx
│ │ │ ├── ArrowLeft.module.scss
│ │ │ ├── ArrowLeft.tsx
│ │ │ ├── ArrowRight.module.scss
│ │ │ ├── ArrowRight.tsx
│ │ │ ├── Attach.tsx
│ │ │ ├── Binding.module.scss
│ │ │ ├── Binding.tsx
│ │ │ ├── BoardIcon.tsx
│ │ │ ├── BoxIcon.tsx
│ │ │ ├── CheckIcon.tsx
│ │ │ ├── ChevronDownIcon.tsx
│ │ │ ├── ChevronLeft.tsx
│ │ │ ├── ChevronRight.tsx
│ │ │ ├── ChevronUpIcon.tsx
│ │ │ ├── CodeFileIcon.tsx
│ │ │ ├── CodeSandbox.tsx
│ │ │ ├── CompactListIcon.tsx
│ │ │ ├── ContentCopyIcon.tsx
│ │ │ ├── DarkToLightIcon.tsx
│ │ │ ├── DatabaseIcon.module.scss
│ │ │ ├── DatabaseIcon.tsx
│ │ │ ├── DocFileIcon.tsx
│ │ │ ├── DocIcon.tsx
│ │ │ ├── DotMenuHorizontalIcon.tsx
│ │ │ ├── DotMenuIcon.tsx
│ │ │ ├── EmailIcon.tsx
│ │ │ ├── EmptyFolderIcon.tsx
│ │ │ ├── ErrorIcon.tsx
│ │ │ ├── ExpressionIcon.tsx
│ │ │ ├── FillPlusCricleIcon.tsx
│ │ │ ├── FilterIcon.tsx
│ │ │ ├── FolderIcon.tsx
│ │ │ ├── GlobeIcon.tsx
│ │ │ ├── HomeIcon.tsx
│ │ │ ├── HyperLinkIcon.tsx
│ │ │ ├── Icon.md
│ │ │ ├── Icon.module.scss
│ │ │ ├── Icon.spec.ts
│ │ │ ├── Icon.tsx
│ │ │ ├── IconNative.tsx
│ │ │ ├── ImageFileIcon.tsx
│ │ │ ├── Inspect.tsx
│ │ │ ├── LightToDark.tsx
│ │ │ ├── LinkIcon.tsx
│ │ │ ├── ListIcon.tsx
│ │ │ ├── LooseListIcon.tsx
│ │ │ ├── MoonIcon.tsx
│ │ │ ├── MoreOptionsIcon.tsx
│ │ │ ├── NoSortIcon.tsx
│ │ │ ├── PDFIcon.tsx
│ │ │ ├── PenIcon.tsx
│ │ │ ├── PhoneIcon.tsx
│ │ │ ├── PhotoIcon.tsx
│ │ │ ├── PlusIcon.tsx
│ │ │ ├── SearchIcon.tsx
│ │ │ ├── ShareIcon.tsx
│ │ │ ├── SortAscendingIcon.tsx
│ │ │ ├── SortDescendingIcon.tsx
│ │ │ ├── StarsIcon.tsx
│ │ │ ├── SunIcon.tsx
│ │ │ ├── svg
│ │ │ │ ├── admonition_danger.svg
│ │ │ │ ├── admonition_info.svg
│ │ │ │ ├── admonition_note.svg
│ │ │ │ ├── admonition_tip.svg
│ │ │ │ ├── admonition_warning.svg
│ │ │ │ ├── api.svg
│ │ │ │ ├── arrow-dropdown.svg
│ │ │ │ ├── arrow-left.svg
│ │ │ │ ├── arrow-right.svg
│ │ │ │ ├── arrow-up.svg
│ │ │ │ ├── attach.svg
│ │ │ │ ├── binding.svg
│ │ │ │ ├── box.svg
│ │ │ │ ├── bulb.svg
│ │ │ │ ├── code-file.svg
│ │ │ │ ├── code-sandbox.svg
│ │ │ │ ├── dark_to_light.svg
│ │ │ │ ├── database.svg
│ │ │ │ ├── doc.svg
│ │ │ │ ├── empty-folder.svg
│ │ │ │ ├── expression.svg
│ │ │ │ ├── eye-closed.svg
│ │ │ │ ├── eye-dark.svg
│ │ │ │ ├── eye.svg
│ │ │ │ ├── file-text.svg
│ │ │ │ ├── filter.svg
│ │ │ │ ├── folder.svg
│ │ │ │ ├── img.svg
│ │ │ │ ├── inspect.svg
│ │ │ │ ├── light_to_dark.svg
│ │ │ │ ├── moon.svg
│ │ │ │ ├── pdf.svg
│ │ │ │ ├── photo.svg
│ │ │ │ ├── share.svg
│ │ │ │ ├── stars.svg
│ │ │ │ ├── sun.svg
│ │ │ │ ├── trending-down.svg
│ │ │ │ ├── trending-level.svg
│ │ │ │ ├── trending-up.svg
│ │ │ │ ├── txt.svg
│ │ │ │ ├── unknown-file.svg
│ │ │ │ ├── unlink.svg
│ │ │ │ └── xls.svg
│ │ │ ├── TableDeleteColumnIcon.tsx
│ │ │ ├── TableDeleteRowIcon.tsx
│ │ │ ├── TableInsertColumnIcon.tsx
│ │ │ ├── TableInsertRowIcon.tsx
│ │ │ ├── TrashIcon.tsx
│ │ │ ├── TrendingDownIcon.tsx
│ │ │ ├── TrendingLevelIcon.tsx
│ │ │ ├── TrendingUpIcon.tsx
│ │ │ ├── TxtIcon.tsx
│ │ │ ├── UnknownFileIcon.tsx
│ │ │ ├── UnlinkIcon.tsx
│ │ │ ├── UserIcon.tsx
│ │ │ ├── WarningIcon.tsx
│ │ │ └── XlsIcon.tsx
│ │ ├── IconProvider.tsx
│ │ ├── IconRegistryContext.tsx
│ │ ├── IFrame
│ │ │ ├── IFrame.md
│ │ │ ├── IFrame.module.scss
│ │ │ ├── IFrame.spec.ts
│ │ │ ├── IFrame.tsx
│ │ │ └── IFrameNative.tsx
│ │ ├── Image
│ │ │ ├── Image.md
│ │ │ ├── Image.module.scss
│ │ │ ├── Image.spec.ts
│ │ │ ├── Image.tsx
│ │ │ └── ImageNative.tsx
│ │ ├── Input
│ │ │ ├── index.ts
│ │ │ ├── InputAdornment.module.scss
│ │ │ ├── InputAdornment.tsx
│ │ │ ├── InputDivider.module.scss
│ │ │ ├── InputDivider.tsx
│ │ │ ├── InputLabel.module.scss
│ │ │ ├── InputLabel.tsx
│ │ │ ├── PartialInput.module.scss
│ │ │ └── PartialInput.tsx
│ │ ├── InspectButton
│ │ │ ├── InspectButton.module.scss
│ │ │ └── InspectButton.tsx
│ │ ├── Items
│ │ │ ├── Items.md
│ │ │ ├── Items.spec.ts
│ │ │ ├── Items.tsx
│ │ │ └── ItemsNative.tsx
│ │ ├── Link
│ │ │ ├── Link.md
│ │ │ ├── Link.module.scss
│ │ │ ├── Link.spec.ts
│ │ │ ├── Link.tsx
│ │ │ └── LinkNative.tsx
│ │ ├── List
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── List.md
│ │ │ ├── List.module.scss
│ │ │ ├── List.spec.ts
│ │ │ ├── List.tsx
│ │ │ └── ListNative.tsx
│ │ ├── Logo
│ │ │ ├── doc-resources
│ │ │ │ └── xmlui-logo.svg
│ │ │ ├── Logo.md
│ │ │ ├── Logo.tsx
│ │ │ └── LogoNative.tsx
│ │ ├── Markdown
│ │ │ ├── CodeText.module.scss
│ │ │ ├── CodeText.tsx
│ │ │ ├── Markdown.md
│ │ │ ├── Markdown.module.scss
│ │ │ ├── Markdown.spec.ts
│ │ │ ├── Markdown.tsx
│ │ │ ├── MarkdownNative.tsx
│ │ │ ├── parse-binding-expr.ts
│ │ │ └── utils.ts
│ │ ├── metadata-helpers.ts
│ │ ├── ModalDialog
│ │ │ ├── ConfirmationModalContextProvider.tsx
│ │ │ ├── Dialog.module.scss
│ │ │ ├── Dialog.tsx
│ │ │ ├── ModalDialog.md
│ │ │ ├── ModalDialog.module.scss
│ │ │ ├── ModalDialog.spec.ts
│ │ │ ├── ModalDialog.tsx
│ │ │ ├── ModalDialogNative.tsx
│ │ │ └── ModalVisibilityContext.tsx
│ │ ├── NavGroup
│ │ │ ├── NavGroup.md
│ │ │ ├── NavGroup.module.scss
│ │ │ ├── NavGroup.spec.ts
│ │ │ ├── NavGroup.tsx
│ │ │ ├── NavGroupContext.ts
│ │ │ └── NavGroupNative.tsx
│ │ ├── NavLink
│ │ │ ├── NavLink.md
│ │ │ ├── NavLink.module.scss
│ │ │ ├── NavLink.spec.ts
│ │ │ ├── NavLink.tsx
│ │ │ └── NavLinkNative.tsx
│ │ ├── NavPanel
│ │ │ ├── NavPanel.md
│ │ │ ├── NavPanel.module.scss
│ │ │ ├── NavPanel.spec.ts
│ │ │ ├── NavPanel.tsx
│ │ │ └── NavPanelNative.tsx
│ │ ├── NestedApp
│ │ │ ├── AppWithCodeView.module.scss
│ │ │ ├── AppWithCodeView.tsx
│ │ │ ├── AppWithCodeViewNative.tsx
│ │ │ ├── defaultProps.tsx
│ │ │ ├── logo.svg
│ │ │ ├── NestedApp.module.scss
│ │ │ ├── NestedApp.tsx
│ │ │ ├── NestedAppNative.tsx
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.tsx
│ │ │ └── utils.ts
│ │ ├── NoResult
│ │ │ ├── NoResult.md
│ │ │ ├── NoResult.module.scss
│ │ │ ├── NoResult.spec.ts
│ │ │ ├── NoResult.tsx
│ │ │ └── NoResultNative.tsx
│ │ ├── NumberBox
│ │ │ ├── numberbox-abstractions.ts
│ │ │ ├── NumberBox.md
│ │ │ ├── NumberBox.module.scss
│ │ │ ├── NumberBox.spec.ts
│ │ │ ├── NumberBox.tsx
│ │ │ └── NumberBoxNative.tsx
│ │ ├── Option
│ │ │ ├── Option.md
│ │ │ ├── Option.spec.ts
│ │ │ ├── Option.tsx
│ │ │ ├── OptionNative.tsx
│ │ │ └── OptionTypeProvider.tsx
│ │ ├── PageMetaTitle
│ │ │ ├── PageMetaTilteNative.tsx
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── PageMetaTitle.spec.ts
│ │ │ └── PageMetaTitle.tsx
│ │ ├── Pages
│ │ │ ├── Page.md
│ │ │ ├── Pages.md
│ │ │ ├── Pages.module.scss
│ │ │ ├── Pages.tsx
│ │ │ └── PagesNative.tsx
│ │ ├── Pagination
│ │ │ ├── Pagination.md
│ │ │ ├── Pagination.module.scss
│ │ │ ├── Pagination.spec.ts
│ │ │ ├── Pagination.tsx
│ │ │ └── PaginationNative.tsx
│ │ ├── PositionedContainer
│ │ │ ├── PositionedContainer.module.scss
│ │ │ ├── PositionedContainer.tsx
│ │ │ └── PositionedContainerNative.tsx
│ │ ├── ProfileMenu
│ │ │ ├── ProfileMenu.module.scss
│ │ │ └── ProfileMenu.tsx
│ │ ├── ProgressBar
│ │ │ ├── ProgressBar.md
│ │ │ ├── ProgressBar.module.scss
│ │ │ ├── ProgressBar.spec.ts
│ │ │ ├── ProgressBar.tsx
│ │ │ └── ProgressBarNative.tsx
│ │ ├── Queue
│ │ │ ├── Queue.md
│ │ │ ├── Queue.spec.ts
│ │ │ ├── Queue.tsx
│ │ │ ├── queueActions.ts
│ │ │ └── QueueNative.tsx
│ │ ├── RadioGroup
│ │ │ ├── RadioGroup.md
│ │ │ ├── RadioGroup.module.scss
│ │ │ ├── RadioGroup.spec.ts
│ │ │ ├── RadioGroup.tsx
│ │ │ ├── RadioGroupNative.tsx
│ │ │ ├── RadioItem.tsx
│ │ │ └── RadioItemNative.tsx
│ │ ├── RealTimeAdapter
│ │ │ ├── RealTimeAdapter.tsx
│ │ │ └── RealTimeAdapterNative.tsx
│ │ ├── Redirect
│ │ │ ├── Redirect.md
│ │ │ ├── Redirect.spec.ts
│ │ │ └── Redirect.tsx
│ │ ├── ResponsiveBar
│ │ │ ├── README.md
│ │ │ ├── ResponsiveBar.md
│ │ │ ├── ResponsiveBar.module.scss
│ │ │ ├── ResponsiveBar.spec.ts
│ │ │ ├── ResponsiveBar.tsx
│ │ │ └── ResponsiveBarNative.tsx
│ │ ├── Select
│ │ │ ├── HiddenOption.tsx
│ │ │ ├── OptionContext.ts
│ │ │ ├── Select.md
│ │ │ ├── Select.module.scss
│ │ │ ├── Select.spec.ts
│ │ │ ├── Select.tsx
│ │ │ ├── SelectContext.tsx
│ │ │ └── SelectNative.tsx
│ │ ├── SelectionStore
│ │ │ ├── SelectionStore.md
│ │ │ ├── SelectionStore.tsx
│ │ │ └── SelectionStoreNative.tsx
│ │ ├── Slider
│ │ │ ├── Slider.md
│ │ │ ├── Slider.module.scss
│ │ │ ├── Slider.spec.ts
│ │ │ ├── Slider.tsx
│ │ │ └── SliderNative.tsx
│ │ ├── Slot
│ │ │ ├── Slot.md
│ │ │ ├── Slot.spec.ts
│ │ │ └── Slot.ts
│ │ ├── SlotItem.tsx
│ │ ├── SpaceFiller
│ │ │ ├── SpaceFiller.md
│ │ │ ├── SpaceFiller.module.scss
│ │ │ ├── SpaceFiller.spec.ts
│ │ │ ├── SpaceFiller.tsx
│ │ │ └── SpaceFillerNative.tsx
│ │ ├── Spinner
│ │ │ ├── Spinner.md
│ │ │ ├── Spinner.module.scss
│ │ │ ├── Spinner.spec.ts
│ │ │ ├── Spinner.tsx
│ │ │ └── SpinnerNative.tsx
│ │ ├── Splitter
│ │ │ ├── HSplitter.md
│ │ │ ├── HSplitter.spec.ts
│ │ │ ├── Splitter.md
│ │ │ ├── Splitter.module.scss
│ │ │ ├── Splitter.spec.ts
│ │ │ ├── Splitter.tsx
│ │ │ ├── SplitterNative.tsx
│ │ │ ├── utils.ts
│ │ │ ├── VSplitter.md
│ │ │ └── VSplitter.spec.ts
│ │ ├── Stack
│ │ │ ├── CHStack.md
│ │ │ ├── CHStack.spec.ts
│ │ │ ├── CVStack.md
│ │ │ ├── CVStack.spec.ts
│ │ │ ├── HStack.md
│ │ │ ├── HStack.spec.ts
│ │ │ ├── Stack.md
│ │ │ ├── Stack.module.scss
│ │ │ ├── Stack.spec.ts
│ │ │ ├── Stack.tsx
│ │ │ ├── StackNative.tsx
│ │ │ ├── VStack.md
│ │ │ └── VStack.spec.ts
│ │ ├── StickyBox
│ │ │ ├── StickyBox.md
│ │ │ ├── StickyBox.module.scss
│ │ │ ├── StickyBox.tsx
│ │ │ └── StickyBoxNative.tsx
│ │ ├── Switch
│ │ │ ├── Switch.md
│ │ │ ├── Switch.spec.ts
│ │ │ └── Switch.tsx
│ │ ├── Table
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── react-table-config.d.ts
│ │ │ ├── Table.md
│ │ │ ├── Table.module.scss
│ │ │ ├── Table.spec.ts
│ │ │ ├── Table.tsx
│ │ │ ├── TableNative.tsx
│ │ │ └── useRowSelection.tsx
│ │ ├── TableOfContents
│ │ │ ├── TableOfContents.module.scss
│ │ │ ├── TableOfContents.spec.ts
│ │ │ ├── TableOfContents.tsx
│ │ │ └── TableOfContentsNative.tsx
│ │ ├── Tabs
│ │ │ ├── TabContext.tsx
│ │ │ ├── TabItem.md
│ │ │ ├── TabItem.tsx
│ │ │ ├── TabItemNative.tsx
│ │ │ ├── Tabs.md
│ │ │ ├── Tabs.module.scss
│ │ │ ├── Tabs.spec.ts
│ │ │ ├── Tabs.tsx
│ │ │ └── TabsNative.tsx
│ │ ├── Text
│ │ │ ├── Text.md
│ │ │ ├── Text.module.scss
│ │ │ ├── Text.spec.ts
│ │ │ ├── Text.tsx
│ │ │ └── TextNative.tsx
│ │ ├── TextArea
│ │ │ ├── TextArea.md
│ │ │ ├── TextArea.module.scss
│ │ │ ├── TextArea.spec.ts
│ │ │ ├── TextArea.tsx
│ │ │ ├── TextAreaNative.tsx
│ │ │ ├── TextAreaResizable.tsx
│ │ │ └── useComposedRef.ts
│ │ ├── TextBox
│ │ │ ├── TextBox.md
│ │ │ ├── TextBox.module.scss
│ │ │ ├── TextBox.spec.ts
│ │ │ ├── TextBox.tsx
│ │ │ └── TextBoxNative.tsx
│ │ ├── Theme
│ │ │ ├── NotificationToast.tsx
│ │ │ ├── Theme.md
│ │ │ ├── Theme.module.scss
│ │ │ ├── Theme.spec.ts
│ │ │ ├── Theme.tsx
│ │ │ └── ThemeNative.tsx
│ │ ├── TimeInput
│ │ │ ├── TimeInput.md
│ │ │ ├── TimeInput.module.scss
│ │ │ ├── TimeInput.spec.ts
│ │ │ ├── TimeInput.tsx
│ │ │ ├── TimeInputNative.tsx
│ │ │ └── utils.ts
│ │ ├── Timer
│ │ │ ├── Timer.md
│ │ │ ├── Timer.spec.ts
│ │ │ ├── Timer.tsx
│ │ │ └── TimerNative.tsx
│ │ ├── Toggle
│ │ │ ├── Toggle.module.scss
│ │ │ └── Toggle.tsx
│ │ ├── ToneChangerButton
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneChangerButton.spec.ts
│ │ │ └── ToneChangerButton.tsx
│ │ ├── ToneSwitch
│ │ │ ├── ToneSwitch.md
│ │ │ ├── ToneSwitch.module.scss
│ │ │ ├── ToneSwitch.spec.ts
│ │ │ ├── ToneSwitch.tsx
│ │ │ └── ToneSwitchNative.tsx
│ │ ├── Tooltip
│ │ │ ├── Tooltip.md
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.spec.ts
│ │ │ ├── Tooltip.tsx
│ │ │ └── TooltipNative.tsx
│ │ ├── Tree
│ │ │ ├── testData.ts
│ │ │ ├── Tree-dynamic.spec.ts
│ │ │ ├── Tree-icons.spec.ts
│ │ │ ├── Tree.md
│ │ │ ├── Tree.spec.ts
│ │ │ ├── TreeComponent.module.scss
│ │ │ ├── TreeComponent.tsx
│ │ │ └── TreeNative.tsx
│ │ ├── TreeDisplay
│ │ │ ├── TreeDisplay.md
│ │ │ ├── TreeDisplay.module.scss
│ │ │ ├── TreeDisplay.tsx
│ │ │ └── TreeDisplayNative.tsx
│ │ ├── ValidationSummary
│ │ │ ├── ValidationSummary.module.scss
│ │ │ └── ValidationSummary.tsx
│ │ └── VisuallyHidden.tsx
│ ├── components-core
│ │ ├── abstractions
│ │ │ ├── ComponentRenderer.ts
│ │ │ ├── LoaderRenderer.ts
│ │ │ ├── standalone.ts
│ │ │ └── treeAbstractions.ts
│ │ ├── action
│ │ │ ├── actions.ts
│ │ │ ├── APICall.tsx
│ │ │ ├── FileDownloadAction.tsx
│ │ │ ├── FileUploadAction.tsx
│ │ │ ├── NavigateAction.tsx
│ │ │ └── TimedAction.tsx
│ │ ├── ApiBoundComponent.tsx
│ │ ├── appContext
│ │ │ ├── date-functions.ts
│ │ │ ├── math-function.ts
│ │ │ └── misc-utils.ts
│ │ ├── AppContext.tsx
│ │ ├── behaviors
│ │ │ ├── Behavior.tsx
│ │ │ └── CoreBehaviors.tsx
│ │ ├── component-hooks.ts
│ │ ├── ComponentDecorator.tsx
│ │ ├── ComponentViewer.tsx
│ │ ├── CompoundComponent.tsx
│ │ ├── constants.ts
│ │ ├── DebugViewProvider.tsx
│ │ ├── descriptorHelper.ts
│ │ ├── devtools
│ │ │ ├── InspectorDialog.module.scss
│ │ │ ├── InspectorDialog.tsx
│ │ │ └── InspectorDialogVisibilityContext.tsx
│ │ ├── EngineError.ts
│ │ ├── event-handlers.ts
│ │ ├── InspectorButton.module.scss
│ │ ├── InspectorContext.tsx
│ │ ├── interception
│ │ │ ├── abstractions.ts
│ │ │ ├── ApiInterceptor.ts
│ │ │ ├── ApiInterceptorProvider.tsx
│ │ │ ├── apiInterceptorWorker.ts
│ │ │ ├── Backend.ts
│ │ │ ├── Errors.ts
│ │ │ ├── IndexedDb.ts
│ │ │ ├── initMock.ts
│ │ │ ├── InMemoryDb.ts
│ │ │ ├── ReadonlyCollection.ts
│ │ │ └── useApiInterceptorContext.tsx
│ │ ├── loader
│ │ │ ├── ApiLoader.tsx
│ │ │ ├── DataLoader.tsx
│ │ │ ├── ExternalDataLoader.tsx
│ │ │ ├── Loader.tsx
│ │ │ ├── MockLoaderRenderer.tsx
│ │ │ └── PageableLoader.tsx
│ │ ├── LoaderComponent.tsx
│ │ ├── markup-check.ts
│ │ ├── parts.ts
│ │ ├── renderers.ts
│ │ ├── rendering
│ │ │ ├── AppContent.tsx
│ │ │ ├── AppRoot.tsx
│ │ │ ├── AppWrapper.tsx
│ │ │ ├── buildProxy.ts
│ │ │ ├── collectFnVarDeps.ts
│ │ │ ├── ComponentAdapter.tsx
│ │ │ ├── ComponentWrapper.tsx
│ │ │ ├── Container.tsx
│ │ │ ├── containers.ts
│ │ │ ├── ContainerWrapper.tsx
│ │ │ ├── ErrorBoundary.module.scss
│ │ │ ├── ErrorBoundary.tsx
│ │ │ ├── InvalidComponent.module.scss
│ │ │ ├── InvalidComponent.tsx
│ │ │ ├── nodeUtils.ts
│ │ │ ├── reducer.ts
│ │ │ ├── renderChild.tsx
│ │ │ ├── StandaloneComponent.tsx
│ │ │ ├── StateContainer.tsx
│ │ │ ├── UnknownComponent.module.scss
│ │ │ ├── UnknownComponent.tsx
│ │ │ └── valueExtractor.ts
│ │ ├── reportEngineError.ts
│ │ ├── RestApiProxy.ts
│ │ ├── script-runner
│ │ │ ├── asyncProxy.ts
│ │ │ ├── AttributeValueParser.ts
│ │ │ ├── bannedFunctions.ts
│ │ │ ├── BindingTreeEvaluationContext.ts
│ │ │ ├── eval-tree-async.ts
│ │ │ ├── eval-tree-common.ts
│ │ │ ├── eval-tree-sync.ts
│ │ │ ├── ParameterParser.ts
│ │ │ ├── process-statement-async.ts
│ │ │ ├── process-statement-common.ts
│ │ │ ├── process-statement-sync.ts
│ │ │ ├── ScriptingSourceTree.ts
│ │ │ ├── simplify-expression.ts
│ │ │ ├── statement-queue.ts
│ │ │ └── visitors.ts
│ │ ├── StandaloneApp.tsx
│ │ ├── StandaloneExtensionManager.ts
│ │ ├── TableOfContentsContext.tsx
│ │ ├── theming
│ │ │ ├── _themes.scss
│ │ │ ├── component-layout-resolver.ts
│ │ │ ├── extendThemeUtils.ts
│ │ │ ├── hvar.ts
│ │ │ ├── layout-resolver.ts
│ │ │ ├── parse-layout-props.ts
│ │ │ ├── StyleContext.tsx
│ │ │ ├── StyleRegistry.ts
│ │ │ ├── ThemeContext.tsx
│ │ │ ├── ThemeProvider.tsx
│ │ │ ├── themes
│ │ │ │ ├── base-utils.ts
│ │ │ │ ├── palette.ts
│ │ │ │ ├── root.ts
│ │ │ │ ├── solid.ts
│ │ │ │ ├── theme-colors.ts
│ │ │ │ └── xmlui.ts
│ │ │ ├── themeVars.module.scss
│ │ │ ├── themeVars.ts
│ │ │ ├── transformThemeVars.ts
│ │ │ └── utils.ts
│ │ ├── utils
│ │ │ ├── actionUtils.ts
│ │ │ ├── audio-utils.ts
│ │ │ ├── base64-utils.ts
│ │ │ ├── compound-utils.ts
│ │ │ ├── css-utils.ts
│ │ │ ├── DataLoaderQueryKeyGenerator.ts
│ │ │ ├── date-utils.ts
│ │ │ ├── extractParam.ts
│ │ │ ├── hooks.tsx
│ │ │ ├── LruCache.ts
│ │ │ ├── mergeProps.ts
│ │ │ ├── misc.ts
│ │ │ ├── request-params.ts
│ │ │ ├── statementUtils.ts
│ │ │ └── treeUtils.ts
│ │ └── xmlui-parser.ts
│ ├── index-standalone.ts
│ ├── index.scss
│ ├── index.ts
│ ├── language-server
│ │ ├── server-common.ts
│ │ ├── server-web-worker.ts
│ │ ├── server.ts
│ │ ├── services
│ │ │ ├── common
│ │ │ │ ├── docs-generation.ts
│ │ │ │ ├── lsp-utils.ts
│ │ │ │ ├── metadata-utils.ts
│ │ │ │ └── syntax-node-utilities.ts
│ │ │ ├── completion.ts
│ │ │ ├── diagnostic.ts
│ │ │ ├── format.ts
│ │ │ └── hover.ts
│ │ └── xmlui-metadata-generated.js
│ ├── logging
│ │ ├── LoggerContext.tsx
│ │ ├── LoggerInitializer.tsx
│ │ ├── LoggerService.ts
│ │ └── xmlui.ts
│ ├── logo.svg
│ ├── parsers
│ │ ├── common
│ │ │ ├── GenericToken.ts
│ │ │ ├── InputStream.ts
│ │ │ └── utils.ts
│ │ ├── scripting
│ │ │ ├── code-behind-collect.ts
│ │ │ ├── Lexer.ts
│ │ │ ├── modules.ts
│ │ │ ├── Parser.ts
│ │ │ ├── ParserError.ts
│ │ │ ├── ScriptingNodeTypes.ts
│ │ │ ├── TokenTrait.ts
│ │ │ ├── TokenType.ts
│ │ │ └── tree-visitor.ts
│ │ ├── style-parser
│ │ │ ├── errors.ts
│ │ │ ├── source-tree.ts
│ │ │ ├── StyleInputStream.ts
│ │ │ ├── StyleLexer.ts
│ │ │ ├── StyleParser.ts
│ │ │ └── tokens.ts
│ │ └── xmlui-parser
│ │ ├── CharacterCodes.ts
│ │ ├── diagnostics.ts
│ │ ├── fileExtensions.ts
│ │ ├── index.ts
│ │ ├── lint.ts
│ │ ├── parser.ts
│ │ ├── ParserError.ts
│ │ ├── scanner.ts
│ │ ├── syntax-kind.ts
│ │ ├── syntax-node.ts
│ │ ├── transform.ts
│ │ ├── utils.ts
│ │ ├── xmlui-serializer.ts
│ │ └── xmlui-tree.ts
│ ├── react-app-env.d.ts
│ ├── syntax
│ │ ├── monaco
│ │ │ ├── grammar.monacoLanguage.ts
│ │ │ ├── index.ts
│ │ │ ├── xmlui-dark.ts
│ │ │ ├── xmlui-light.ts
│ │ │ └── xmluiscript.monacoLanguage.ts
│ │ └── textMate
│ │ ├── index.ts
│ │ ├── xmlui-dark.json
│ │ ├── xmlui-light.json
│ │ ├── xmlui.json
│ │ └── xmlui.tmLanguage.json
│ ├── testing
│ │ ├── assertions.ts
│ │ ├── component-test-helpers.ts
│ │ ├── ComponentDrivers.ts
│ │ ├── drivers
│ │ │ ├── DateInputDriver.ts
│ │ │ ├── index.ts
│ │ │ ├── ModalDialogDriver.ts
│ │ │ ├── NumberBoxDriver.ts
│ │ │ ├── TextBoxDriver.ts
│ │ │ ├── TimeInputDriver.ts
│ │ │ ├── TimerDriver.ts
│ │ │ └── TreeDriver.ts
│ │ ├── fixtures.ts
│ │ ├── index.ts
│ │ ├── infrastructure
│ │ │ ├── index.html
│ │ │ ├── main.tsx
│ │ │ ├── public
│ │ │ │ ├── mockServiceWorker.js
│ │ │ │ ├── resources
│ │ │ │ │ ├── bell.svg
│ │ │ │ │ ├── box.svg
│ │ │ │ │ ├── doc.svg
│ │ │ │ │ ├── eye.svg
│ │ │ │ │ ├── flower-640x480.jpg
│ │ │ │ │ ├── sun.svg
│ │ │ │ │ ├── test-image-100x100.jpg
│ │ │ │ │ └── txt.svg
│ │ │ │ └── serve.json
│ │ │ └── TestBed.tsx
│ │ └── themed-app-test-helpers.ts
│ └── vite-env.d.ts
├── tests
│ ├── components
│ │ ├── CodeBlock
│ │ │ └── hightlight-code.test.ts
│ │ ├── playground-pattern.test.ts
│ │ └── Tree
│ │ └── Tree-states.test.ts
│ ├── components-core
│ │ ├── abstractions
│ │ │ └── treeAbstractions.test.ts
│ │ ├── container
│ │ │ └── buildProxy.test.ts
│ │ ├── interception
│ │ │ ├── orderBy.test.ts
│ │ │ ├── ReadOnlyCollection.test.ts
│ │ │ └── request-param-converter.test.ts
│ │ ├── scripts-runner
│ │ │ ├── AttributeValueParser.test.ts
│ │ │ ├── eval-tree-arrow-async.test.ts
│ │ │ ├── eval-tree-arrow.test.ts
│ │ │ ├── eval-tree-func-decl-async.test.ts
│ │ │ ├── eval-tree-func-decl.test.ts
│ │ │ ├── eval-tree-pre-post.test.ts
│ │ │ ├── eval-tree-regression.test.ts
│ │ │ ├── eval-tree.test.ts
│ │ │ ├── function-proxy.test.ts
│ │ │ ├── parser-regression.test.ts
│ │ │ ├── process-event.test.ts
│ │ │ ├── process-function.test.ts
│ │ │ ├── process-implicit-context.test.ts
│ │ │ ├── process-statement-asgn.test.ts
│ │ │ ├── process-statement-destruct.test.ts
│ │ │ ├── process-statement-regs.test.ts
│ │ │ ├── process-statement-sync.test.ts
│ │ │ ├── process-statement.test.ts
│ │ │ ├── process-switch-sync.test.ts
│ │ │ ├── process-switch.test.ts
│ │ │ ├── process-try-sync.test.ts
│ │ │ ├── process-try.test.ts
│ │ │ └── test-helpers.ts
│ │ ├── test-metadata-handler.ts
│ │ ├── theming
│ │ │ ├── border-segments.test.ts
│ │ │ ├── component-layout.resolver.test.ts
│ │ │ ├── layout-property-parser.test.ts
│ │ │ ├── layout-resolver.test.ts
│ │ │ ├── layout-resolver2.test.ts
│ │ │ ├── layout-vp-override.test.ts
│ │ │ └── padding-segments.test.ts
│ │ └── utils
│ │ ├── date-utils.test.ts
│ │ ├── format-human-elapsed-time.test.ts
│ │ └── LruCache.test.ts
│ ├── language-server
│ │ ├── completion.test.ts
│ │ ├── format.test.ts
│ │ ├── hover.test.ts
│ │ └── mockData.ts
│ └── parsers
│ ├── common
│ │ └── input-stream.test.ts
│ ├── markdown
│ │ └── parse-binding-expression.test.ts
│ ├── parameter-parser.test.ts
│ ├── paremeter-parser.test.ts
│ ├── scripting
│ │ ├── eval-tree-arrow.test.ts
│ │ ├── eval-tree-pre-post.test.ts
│ │ ├── eval-tree.test.ts
│ │ ├── function-proxy.test.ts
│ │ ├── lexer-literals.test.ts
│ │ ├── lexer-misc.test.ts
│ │ ├── module-parse.test.ts
│ │ ├── parser-arrow.test.ts
│ │ ├── parser-assignments.test.ts
│ │ ├── parser-binary.test.ts
│ │ ├── parser-destructuring.test.ts
│ │ ├── parser-errors.test.ts
│ │ ├── parser-expressions.test.ts
│ │ ├── parser-function.test.ts
│ │ ├── parser-literals.test.ts
│ │ ├── parser-primary.test.ts
│ │ ├── parser-regex.test.ts
│ │ ├── parser-statements.test.ts
│ │ ├── parser-unary.test.ts
│ │ ├── process-event.test.ts
│ │ ├── process-implicit-context.test.ts
│ │ ├── process-statement-asgn.test.ts
│ │ ├── process-statement-destruct.test.ts
│ │ ├── process-statement-regs.test.ts
│ │ ├── process-statement-sync.test.ts
│ │ ├── process-statement.test.ts
│ │ ├── process-switch-sync.test.ts
│ │ ├── process-switch.test.ts
│ │ ├── process-try-sync.test.ts
│ │ ├── process-try.test.ts
│ │ ├── simplify-expression.test.ts
│ │ ├── statement-hooks.test.ts
│ │ └── test-helpers.ts
│ ├── style-parser
│ │ ├── generateHvarChain.test.ts
│ │ ├── parseHVar.test.ts
│ │ ├── parser.test.ts
│ │ └── tokens.test.ts
│ └── xmlui
│ ├── lint.test.ts
│ ├── parser.test.ts
│ ├── scanner.test.ts
│ ├── transform.attr.test.ts
│ ├── transform.circular.test.ts
│ ├── transform.element.test.ts
│ ├── transform.errors.test.ts
│ ├── transform.escape.test.ts
│ ├── transform.regression.test.ts
│ ├── transform.script.test.ts
│ ├── transform.test.ts
│ └── xmlui.ts
├── tests-e2e
│ ├── api-bound-component-regression.spec.ts
│ ├── api-call-as-extracted-component.spec.ts
│ ├── assign-to-object-or-array-regression.spec.ts
│ ├── binding-regression.spec.ts
│ ├── children-as-template-context-vars.spec.ts
│ ├── compound-component.spec.ts
│ ├── context-vars-regression.spec.ts
│ ├── data-bindings.spec.ts
│ ├── datasource-and-api-usage-in-var.spec.ts
│ ├── datasource-direct-binding.spec.ts
│ ├── datasource-onLoaded-regression.spec.ts
│ ├── modify-array-item-regression.spec.ts
│ ├── namespaces.spec.ts
│ ├── push-to-array-regression.spec.ts
│ ├── screen-breakpoints.spec.ts
│ ├── scripting.spec.ts
│ ├── state-scope-in-pages.spec.ts
│ └── state-var-scopes.spec.ts
├── tsconfig.json
├── tsdown.config.ts
├── vite.config.ts
└── vitest.config.ts
```
# Files
--------------------------------------------------------------------------------
/xmlui/dev-docs/build-xmlui.md:
--------------------------------------------------------------------------------
```markdown
# Building the XMLUI Core Package
This document explains how the XMLUI framework package itself is built using Vite. This is relevant for XMLUI framework contributors who need to understand the internal build process.
> **Note:** For building XMLUI applications or extensions, see [XMLUI Build System](./build-system.md). For repository structure and Turborepo orchestration, see [XMLUI Repository Structure](./xmlui-repo.md).
## Table of Contents
1. [Overview](#overview)
2. [Build Modes](#build-modes)
3. [Library Build (lib)](#library-build-lib)
4. [Standalone Build](#standalone-build)
5. [Metadata Build](#metadata-build)
6. [Build Process Flow](#build-process-flow)
7. [Vite Configuration](#vite-configuration)
8. [Development vs Production](#development-vs-production)
9. [Build Performance](#build-performance)
10. [Troubleshooting](#troubleshooting)
## Overview
The XMLUI framework package is built using **Vite** with multiple build modes. The build configuration is defined in `xmlui/vite.config.ts` and supports three distinct modes.
**Build System:**
- **Build Tool:** Vite 5.x with Rollup
- **Configuration:** `xmlui/vite.config.ts`
- **Package Manager:** npm with clean-package for publishing
- **Task Orchestration:** Turborepo (see [XMLUI Repository Structure](./xmlui-repo.md))
**Quick Build Commands:**
```bash
# From workspace root
npm run build-xmlui # Build entire XMLUI core package
# From xmlui/ directory
npm run build:bin # Build CLI tools using tsdown
npm run build:xmlui # Build library mode
npm run build:xmlui-standalone # Build UMD bundle
npm run build:xmlui-metadata # Extract component metadata
```
> **Note:** For comprehensive information about the monorepo structure, Turborepo orchestration, and cross-package builds, see [XMLUI Repository Structure](./xmlui-repo.md).
## Build Modes
| Mode | Entry Point | Output Format | Purpose |
| -------------- | ----------------------------- | -------------------- | ------------------------ |
| **lib** | Multiple entries | ES Modules (.js) | npm package distribution |
| **standalone** | index-standalone.ts | UMD bundle (.umd.js) | Buildless CDN deployment |
| **metadata** | collectedComponentMetadata.ts | ES Module | Documentation/LSP |
## Library Build (lib)
The default build mode creates the npm package with multiple entry points for different framework features.
### Command
```bash
npm run build:xmlui
# Executes: vite build --mode lib
```
### Entry Points
The library build creates multiple entry points:
```typescript
{
xmlui: "src/index.ts", // Main framework export
"xmlui-parser": "src/parsers/xmlui-parser/index.ts", // Parser standalone
"language-server": "src/language-server/server.ts", // Node.js LSP
"language-server-web-worker": "src/language-server/server-web-worker.ts", // Browser LSP
"syntax-monaco": "src/syntax/monaco/index.ts", // Monaco editor syntax
"syntax-textmate": "src/syntax/textMate/index.ts" // TextMate grammar
}
```
### Vite Plugins
- `@vitejs/plugin-react` - React JSX and Fast Refresh support
- `vite-plugin-svgr` - SVG to React component transformation
- `vite-plugin-yaml` - YAML file import support
- `vite-xmlui-plugin` - Transforms .xmlui and .xmlui.xs files
- `vite-plugin-lib-inject-css` - Injects CSS into JS bundles
- `vite-plugin-dts` - Generates TypeScript declaration files with rollup type bundling
- `rollup-plugin-copy` - Copies SCSS source files to dist
### Build Configuration
```typescript
{
outDir: "dist/lib",
formats: ["es"], // ES modules only
minify: "terser", // Terser minification
treeshake: undefined, // Standard tree-shaking
rollupOptions: {
external: [
// All dependencies marked as external (not bundled)
...Object.keys(packageJson.dependencies),
"react/jsx-runtime"
]
}
}
```
### SCSS Handling
The build process copies all non-module SCSS files while preserving directory structure:
```
src/components/button/Button.scss
→ dist/lib/scss/components/button/Button.scss
```
This is implemented via `rollup-plugin-copy`:
```typescript
copy({
hook: "writeBundle",
targets: [
{
src: ["src/**/*.scss", "!src/**/*.module.scss"],
dest: "dist/lib/scss",
rename: (name, extension, fullPath) => {
// Remove 'src/' prefix to preserve structure
return fullPath.replace("src/", "");
},
},
],
});
```
### Output Structure
```
dist/lib/
├── xmlui.js # Main framework bundle
├── xmlui.d.ts # Bundled type definitions
├── xmlui-parser.js # Parser bundle
├── language-server.js # LSP server bundle
├── language-server-web-worker.js # Browser LSP bundle
├── syntax-monaco.js # Monaco syntax bundle
├── syntax-textmate.js # TextMate syntax bundle
├── *.css # Extracted component styles
└── scss/ # Source SCSS files
└── (mirrors src/ structure)
```
### NPM Package Exports
After `clean-package` transforms package.json during publish:
```json
{
"main": "./dist/standalone/xmlui-standalone.umd.js",
"module": "./dist/lib/xmlui.js",
"types": "./dist/lib/xmlui.d.ts",
"exports": {
".": {
"import": "./dist/lib/xmlui.js",
"require": "./dist/standalone/xmlui-standalone.umd.js"
},
"./language-server": {
"import": "./dist/lib/language-server.js",
"require": "./dist/lib/language-server.js"
},
"./language-server-web-worker": {
"import": "./dist/lib/language-server-web-worker.js",
"require": "./dist/lib/language-server-web-worker.js"
},
"./parser": {
"import": "./dist/lib/xmlui-parser.js",
"require": "./dist/lib/xmlui-parser.js"
},
"./*.css": {
"import": "./dist/lib/*.css",
"require": "./dist/lib/*.css"
},
"./index.scss": {
"import": "./dist/lib/scss/index.scss",
"require": "./dist/lib/scss/index.scss"
},
"./themes.scss": {
"import": "./dist/lib/scss/components-core/theming/_themes.scss",
"require": "./dist/lib/scss/components-core/theming/_themes.scss"
},
"./vite-xmlui-plugin": {
"import": "./dist/lib/vite-xmlui-plugin/index.js",
"require": "./dist/lib/vite-xmlui-plugin/index.js"
},
"./syntax/monaco": {
"import": "./dist/lib/syntax-monaco.js",
"require": "./dist/lib/syntax-monaco.js"
},
"./syntax/textmate": {
"import": "./dist/lib/syntax-textmate.js",
"require": "./dist/lib/syntax-textmate.js"
},
"./testing": {
"import": "./dist/lib/testing.js",
"require": "./dist/lib/testing.js"
}
}
}
```
## Standalone Build
Creates a self-contained UMD bundle for buildless deployment via CDN.
### Command
```bash
npm run build:xmlui-standalone
# Executes: vite build --mode standalone
```
### Purpose
Creates a self-contained UMD bundle that includes all dependencies for buildless deployment via CDN or static hosting.
### Entry Point
```typescript
entry: "src/index-standalone.ts";
```
### Build Configuration
```typescript
{
outDir: "dist/standalone",
name: "xmlui", // Global variable name
formats: ["umd"], // Universal Module Definition
minify: "terser",
rollupOptions: {
external: [], // Bundle ALL dependencies
output: {
globals: { // Map externals to globals
react: "React",
"react-dom": "ReactDOM"
}
}
}
}
```
### Environment Variables
```typescript
define: {
"process.env": {
NODE_ENV: env.NODE_ENV,
VITE_MOCK_ENABLED: true,
VITE_MOCK_WORKER_LOCATION: "mockApi.js",
VITE_USED_COMPONENTS_XmluiCodeHightlighter: "false",
VITE_USED_COMPONENTS_Tree: "false",
VITE_USED_COMPONENTS_TableEditor: "false",
VITE_XMLUI_VERSION: `${version} (built ${date})`
}
}
```
### Output
```
dist/standalone/
└── xmlui-standalone.umd.js # ~2MB self-contained bundle
```
### Usage
```html
<!DOCTYPE html>
<html>
<head>
<title>Buildless XMLUI App</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/xmlui@latest/dist/standalone/xmlui-standalone.umd.js"></script>
</body>
</html>
```
## Metadata Build
Extracts component metadata for documentation generation and language server support.
### Command
```bash
npm run build:xmlui-metadata
# Executes: vite build --mode metadata
```
### Purpose
Extracts component metadata for:
- Documentation generation
- Language server autocomplete
- Component explorer tools
- API reference generation
### Entry Point
```typescript
entry: "src/components/collectedComponentMetadata.ts";
```
### Build Configuration
```typescript
{
outDir: "dist/metadata",
name: "xmlui-metadata",
treeshake: "smallest", // Aggressive tree-shaking
rollupOptions: {
external: [...dependencies]
}
}
```
### Vite Plugins
Only uses `vite-xmlui-plugin` to process component files without React/SVGR overhead.
### Output
```
dist/metadata/
└── xmlui-metadata.js # Component metadata bundle
```
### Metadata Workflow
```bash
# 1. Extract metadata
npm run build:xmlui-metadata
# 2. Generate documentation from metadata
npm run generate-docs
# 3. Create summary files
npm run generate-docs-summaries
# 4. Export theme files
npm run export-themes
```
## Build Process Flow
### Complete Build Sequence
**Using Turborepo (recommended):**
```bash
# From workspace root - builds everything
npm run build-xmlui
# Executes: turbo run build:xmlui-all
```
This internally runs in order:
1. `build:bin` - Compile CLI tools
2. `build:xmlui-metadata` - Extract component metadata
3. `build:xmlui` - Build library mode
4. `build:xmlui-standalone` - Build UMD bundle
5. `build:extension` - Build extension packages
> **Note:** For detailed task dependencies and Turborepo orchestration, see [XMLUI Repository Structure](./xmlui-repo.md).
**Manual build sequence** (from xmlui/ directory):
```bash
# 1. Build CLI tools
npm run build:bin
# Compiles TypeScript in bin/ folder using tsdown (see tsdown.config.ts)
# Output: dist/bin/
# 2. Build library for npm
npm run build:xmlui
# Vite build with mode=lib
# Output: dist/lib/
# 3. Build standalone runtime
npm run build:xmlui-standalone
# Vite build with mode=standalone
# Output: dist/standalone/
# 4. Extract metadata
npm run build:xmlui-metadata
# Vite build with mode=metadata
# Output: dist/metadata/
# 5. Publish to npm
npm publish
# clean-package transforms package.json
# Publishes dist/ folder contents
```
### Package Transformation
The `clean-package` tool transforms package.json during publish:
**Before publish (development):**
```json
{
"main": "./src/index.ts",
"bin": {
"xmlui": "./bin/bootstrap.js"
}
}
```
**After publish (production):**
```json
{
"main": "./dist/lib/xmlui.js",
"bin": {
"xmlui": "dist/bin/index.js"
}
}
```
> **Note on CLI Development:**
> In the development environment, the `xmlui` command points to `bin/bootstrap.js`. This file uses `tsx` to execute the CLI's TypeScript source (`bin/index.ts`) on-the-fly. This allows for rapid development of the CLI without requiring a separate build step for every change.
>
> For production, `clean-package` replaces the `bin` entry to point to the compiled `dist/bin/index.js`, ensuring the published package does not rely on `tsx`.
## Vite Configuration
### Target and Optimization
```typescript
{
esbuild: {
target: "es2020"
},
optimizeDeps: {
esbuildOptions: {
target: "es2020"
}
}
}
```
### Module Resolution
```typescript
{
resolve: {
alias: {
lodash: "lodash-es"; // Use ES modules version
}
}
}
```
### Build Optimization Features
- **Terser minification** - Production code minification
- **Tree-shaking** - Removes unused code
- **Code splitting** - Multiple entry points
- **CSS extraction** - Via lib-inject-css plugin
- **Type bundling** - Via dts plugin with rollupTypes
- **SCSS preservation** - Copies source files to dist
### Browser Targets
```json
{
"browserslist": {
"production": [">0.2%", "not dead", "not op_mini all"],
"development": ["last 1 chrome version", "last 1 firefox version", "last 1 safari version"]
}
}
```
## Development vs Production
### Development Workflow
```bash
# Terminal 1: Watch mode for library
npm run build:bin
xmlui build-lib --watch
# Terminal 2: Dev server for test app
cd src/testing/infrastructure
xmlui start
# Or use test bed
npm run start-test-bed
```
### Production Build
```bash
# Complete build pipeline
npm run build:bin
npm run build:xmlui
npm run build:xmlui-standalone
npm run build:xmlui-metadata
# Verify outputs
ls -la dist/lib/
ls -la dist/standalone/
ls -la dist/metadata/
# Test locally before publishing
npm pack
npm install xmlui-0.10.19.tgz
```
### Testing Builds
```bash
# Unit tests
npm run test:unit
# E2E tests (smoke)
npm run test:e2e-smoke
# E2E tests (full)
npm run test:e2e-non-smoke
# Interactive E2E
npm run test:e2e-ui
# Test summary
npm run test:e2e-summary
```
## Build Performance
### Build Times (approximate)
**Individual builds:**
- **Library build:** ~30-60 seconds
- **Standalone build:** ~60-90 seconds (includes all dependencies)
- **Metadata build:** ~10-20 seconds (minimal processing)
- **CLI tools build:** ~5-10 seconds
**Full pipeline:**
- **build:xmlui-all:** ~2-3 minutes (first run)
> **Note:** For Turborepo caching benefits and incremental build times, see [XMLUI Repository Structure](./xmlui-repo.md).
### Output Sizes
- **Library bundle (xmlui.mjs):** ~400KB (minified, no deps)
- **Standalone bundle:** ~2MB (includes React, all deps)
- **CSS files:** ~100KB total
- **Type definitions:** ~200KB
- **SCSS sources:** ~50KB
### Optimization Strategies
1. **External dependencies** - Library mode doesn't bundle deps
2. **Code splitting** - Multiple entry points reduce initial load
3. **Tree-shaking** - Removes unused code
4. **Minification** - Terser for production builds
5. **CSS injection** - Styles bundled with JS for convenience
## Troubleshooting
### Clear Build Cache
```bash
# From workspace root - clear all build artifacts
rm -rf xmlui/dist/
rm -rf packages/*/dist/
rm -rf docs/dist/
rm -rf blog/dist/
# Clear Vite cache
rm -rf xmlui/node_modules/.vite/
rm -rf packages/*/node_modules/.vite/
# Clear Turbo cache
rm -rf node_modules/.cache/turbo/
# Or use turbo command
turbo run build:xmlui-all --force
# Rebuild everything
npm run build-xmlui
```
### Verify Build Output
```bash
# From workspace root
cd xmlui
# Check all entry points
ls -la dist/lib/*.js
# Verify TypeScript declarations
ls -la dist/lib/*.d.ts
# Check SCSS copy
find dist/lib/scss -name "*.scss"
# Verify standalone bundle
ls -lh dist/standalone/xmlui-standalone.umd.js
# Check metadata
ls -la dist/metadata/
```
### Debug Build Issues
```bash
# Verbose Vite output
DEBUG=vite:* npm run build:xmlui
# Analyze bundle size
npx vite-bundle-visualizer
# Check for dependency issues
npm ls
# Verify TypeScript compilation
cd xmlui
npx tsc --noEmit
```
> **Note:** For Turborepo debugging commands, see [XMLUI Repository Structure](./xmlui-repo.md).
### Common Issues
**Issue: Missing .d.ts files**
```bash
# Ensure vite-plugin-dts is installed
cd xmlui
npm install --save-dev vite-plugin-dts
# Check tsconfig.json includes src/
npm run build:xmlui
```
**Issue: SCSS files not copied**
```bash
# Verify rollup-plugin-copy configuration
# Check that src/**/*.scss exists
cd xmlui
find src -name "*.scss" | head -10
```
**Issue: Type conflicts**
```bash
# Clear type cache
rm -rf node_modules/.cache/typescript/
# Rebuild types
cd xmlui
npm run build:xmlui
```
### Performance Issues
**Slow initial builds:**
- Ensure dependencies are installed: `npm install`
- Check disk I/O: Build on SSD if possible
- Increase Node.js memory: `NODE_OPTIONS=--max-old-space-size=4096`
> **Note:** For workspace-level issues, Turborepo troubleshooting, and cache problems, see [XMLUI Repository Structure](./xmlui-repo.md).
## See Also
- [XMLUI Repository Structure](./xmlui-repo.md) - Monorepo architecture and Turborepo orchestration
- [XMLUI Build System](./build-system.md) - Application and extension builds
- [Standalone Rendering Architecture](./standalone-app.md) - Runtime architecture
- [Container-Based State Management](./containers.md) - State system
```
--------------------------------------------------------------------------------
/xmlui/src/components/ToneChangerButton/ToneChangerButton.spec.ts:
--------------------------------------------------------------------------------
```typescript
import { expect, test } from "../../testing/fixtures";
// =============================================================================
// BASIC FUNCTIONALITY TESTS
// =============================================================================
test.describe("Basic Functionality", () => {
test("renders with default props", async ({ initTestBed, page }) => {
await initTestBed(`<ToneChangerButton />`);
await expect(page.getByRole("button")).toBeVisible();
});
test("displays light-to-dark icon in light mode", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
// Verify we're in light mode
await expect(page.getByTestId("theme-state")).toHaveText("light");
const button = page.getByRole("button");
await expect(button).toBeVisible();
// Check that the icon exists within the button
const icon = button.locator("svg, img, [data-testid*='icon']").first();
await expect(icon).toBeVisible();
});
test("displays dark-to-light icon in dark mode", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
// Switch to dark mode first
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
// Verify the icon changes (should be different from light mode)
const icon = button.locator("svg, img, [data-testid*='icon']").first();
await expect(icon).toBeVisible();
});
test("switches from light to dark mode when clicked", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
// Initially in light mode
await expect(page.getByTestId("theme-state")).toHaveText("light");
// Click to switch to dark mode
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
});
test("switches from dark to light mode when clicked", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
// Switch to dark mode first
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
// Click again to switch back to light mode
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("light");
});
test("toggles between modes multiple times", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
// Initial state: light
await expect(page.getByTestId("theme-state")).toHaveText("light");
// First toggle: light -> dark
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
// Second toggle: dark -> light
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("light");
// Third toggle: light -> dark
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
});
// =============================================================================
// CLICK EVENT TESTS
// =============================================================================
test.describe("click event", () => {
test("fires click event with 'dark' when switching to dark mode", async ({ initTestBed, page }) => {
const { testStateDriver } = await initTestBed(`
<App>
<ToneChangerButton onClick="arg => testState = arg" />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
// Initially in light mode
await expect(page.getByTestId("theme-state")).toHaveText("light");
// Click to switch to dark mode
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
await expect.poll(testStateDriver.testState).toEqual("dark");
});
test("fires click event with 'light' when switching to light mode", async ({ initTestBed, page }) => {
const { testStateDriver } = await initTestBed(`
<App>
<ToneChangerButton onClick="arg => testState = arg" />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
// Switch to dark mode first
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
// Click again to switch to light mode
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("light");
await expect.poll(testStateDriver.testState).toEqual("light");
});
test("fires click event on each toggle", async ({ initTestBed, page }) => {
// TODO: Investigate why the onClick event handler is not being called
const { testStateDriver } = await initTestBed(`
<App>
<ToneChangerButton onClick="testState = testState == null ? 1 : testState + 1" />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
// First click
await button.click();
await expect.poll(testStateDriver.testState).toEqual(1);
// Second click
await button.click();
await expect.poll(testStateDriver.testState).toEqual(2);
// Third click
await button.click();
await expect.poll(testStateDriver.testState).toEqual(3);
});
});
// =============================================================================
// ICON PROPERTY TESTS
// =============================================================================
test.describe("icon properties", () => {
test("uses custom lightToDarkIcon", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton lightToDarkIcon="custom-light-icon" />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
// Verify we're in light mode and icon is visible
await expect(page.getByTestId("theme-state")).toHaveText("light");
const button = page.getByRole("button");
const icon = button.locator("svg, img, [data-testid*='icon']").first();
await expect(icon).toBeVisible();
});
test("uses custom darkToLightIcon", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton darkToLightIcon="custom-dark-icon" />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
// Switch to dark mode to see dark-to-light icon
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
const icon = button.locator("svg, img, [data-testid*='icon']").first();
await expect(icon).toBeVisible();
});
test("handles null lightToDarkIcon gracefully", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton lightToDarkIcon="{null}" />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
// Should still render and be functional
await expect(page.getByTestId("theme-state")).toHaveText("light");
const button = page.getByRole("button");
await expect(button).toBeVisible();
// Should still be able to toggle
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
});
test("handles null darkToLightIcon gracefully", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton darkToLightIcon="{null}" />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
// Switch to dark mode
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
// Should still render and be functional
await expect(button).toBeVisible();
// Should still be able to toggle back
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("light");
});
test("handles undefined icon properties gracefully", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton lightToDarkIcon="{undefined}" darkToLightIcon="{undefined}" />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
await expect(button).toBeVisible();
// Should still function for toggling
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("light");
});
test("handles non-string icon properties", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton lightToDarkIcon="{123}" darkToLightIcon="{true}" />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
await expect(button).toBeVisible();
// Should still function for toggling despite invalid icon values
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
});
test("handles very long unicode characters in icon names", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton lightToDarkIcon="👨👩👧👦🌟✨" darkToLightIcon="中文图标名称" />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
await expect(button).toBeVisible();
// Should still function despite unusual icon names
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
});
});
});
// =============================================================================
// ACCESSIBILITY TESTS
// =============================================================================
test.describe("Accessibility", () => {
test("has button role", async ({ initTestBed, page }) => {
await initTestBed(`<ToneChangerButton />`);
const button = page.getByRole("button");
await expect(button).toBeVisible();
});
test("is keyboard accessible with Enter key", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
await button.focus();
await expect(button).toBeFocused();
// Initially in light mode
await expect(page.getByTestId("theme-state")).toHaveText("light");
// Press Enter to toggle
await page.keyboard.press("Enter");
await expect(page.getByTestId("theme-state")).toHaveText("dark");
});
test("is keyboard accessible with Space key", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
await button.focus();
await expect(button).toBeFocused();
// Initially in light mode
await expect(page.getByTestId("theme-state")).toHaveText("light");
// Press Space to toggle
await page.keyboard.press("Space");
await expect(page.getByTestId("theme-state")).toHaveText("dark");
});
test("maintains focus during interactions", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
await button.focus();
await button.click();
// Focus should be maintained after click
await expect(button).toBeFocused();
});
test("is focusable via Tab navigation", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<Button>Before</Button>
<ToneChangerButton />
<Button>After</Button>
</App>
`);
// Focus the first button
await page.getByRole("button", { name: "Before" }).focus();
// Tab to ToneChangerButton
await page.keyboard.press("Tab");
const toneButton = page.getByRole("button").nth(1); // ToneChangerButton is the second button
await expect(toneButton).toBeFocused();
// Tab to the next button
await page.keyboard.press("Tab");
await expect(page.getByRole("button", { name: "After" })).toBeFocused();
});
test("has appropriate ARIA attributes", async ({ initTestBed, page }) => {
await initTestBed(`<ToneChangerButton />`);
const button = page.getByRole("button");
// Should be focusable (not disabled)
await expect(button).not.toBeDisabled();
// Should have role button (implicit from getByRole test above)
await expect(button).toBeVisible();
});
});
// =============================================================================
// OTHER EDGE CASE TESTS
// =============================================================================
test.describe("Other Edge Cases", () => {
test("handles no props gracefully", async ({ initTestBed, page }) => {
await initTestBed(`<ToneChangerButton/>`);
const button = page.getByRole("button");
await expect(button).toBeVisible();
});
test("works within different container components", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<Card>
<ToneChangerButton />
</Card>
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
await expect(button).toBeVisible();
// Should still function normally
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
});
test("maintains state consistency across multiple instances", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton testId="button1" />
<ToneChangerButton testId="button2" />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button1 = page.getByTestId("button1");
const button2 = page.getByTestId("button2");
// Initially in light mode
await expect(page.getByTestId("theme-state")).toHaveText("light");
// Click first button to switch to dark
await button1.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
// Click second button to switch back to light
await button2.click();
await expect(page.getByTestId("theme-state")).toHaveText("light");
});
test("handles rapid successive clicks", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
// Perform rapid clicks
await button.click();
await button.click();
await button.click();
await button.click();
// Should end up in light mode (even number of clicks)
await expect(page.getByTestId("theme-state")).toHaveText("light");
});
test("handles empty string icon properties", async ({ initTestBed, page }) => {
await initTestBed(`
<App>
<ToneChangerButton lightToDarkIcon="" darkToLightIcon="" />
<Text testId="theme-state">{activeThemeTone}</Text>
</App>
`);
const button = page.getByRole("button");
await expect(button).toBeVisible();
// Should still function despite empty icon names
await button.click();
await expect(page.getByTestId("theme-state")).toHaveText("dark");
});
});
```
--------------------------------------------------------------------------------
/xmlui/dev-docs/next/working-with-code.md:
--------------------------------------------------------------------------------
```markdown
# Working with the Code
This document describes the most common development tasks and workflows for contributing to the XMLUI project, including adding features, fixing bugs, and maintaining code quality.
## Development Workflow
### 1. Fetch and Sync Main Branch
Before starting any new work, ensure you have the latest changes from the main repository:
#### Command Line
```bash
# Switch to main branch
git checkout main
# Fetch latest changes from upstream
git fetch origin
# Sync your local main with upstream
git pull origin main
# Clean up any local changes (if needed)
git clean -fd
```
#### VS Code
1. **Open Source Control panel** (Ctrl/Cmd + Shift + G)
2. **Switch to main branch**: Click current branch name in status bar → select "main"
3. **Fetch changes**: Click "..." in Source Control → "Fetch"
4. **Pull changes**: Click "..." → "Pull" (or use Ctrl/Cmd + Shift + P → "Git: Pull")
5. **Clean workspace**: Terminal → `git clean -fd` (if needed)
#### IntelliJ IDEA / WebStorm
1. **Switch to main branch**: Bottom right corner → click branch name → "Checkout" → "main"
2. **Fetch and pull**: VCS menu → "Git" → "Fetch" then "Pull..."
- Or use toolbar Git icon → "Pull"
- Or keyboard shortcut: Ctrl/Cmd + T
3. **Clean workspace**: Terminal tool window → `git clean -fd` (if needed)
### 2. Create Your Working Branch
Create a new branch using the naming convention `<your-github-name>/<feature-or-fix-name>`:
#### Command Line
```bash
# Create and switch to new branch
git checkout -b johndoe/add-animation-components
# Examples of good branch names:
git checkout -b johndoe/fix-search-performance
git checkout -b maryjane/update-pdf-export
git checkout -b alexsmith/improve-error-handling
```
#### VS Code
1. **Create new branch**: Click branch name in status bar → "Create new branch..."
2. **Enter branch name**: Type `johndoe/add-animation-components`
3. **Switch to branch**: Branch is automatically checked out after creation
#### IntelliJ IDEA / WebStorm
1. **Create new branch**: Bottom right corner → click branch name → "New Branch"
2. **Enter branch name**: Type `johndoe/add-animation-components`
3. **Create and checkout**: Click "Create" (automatically switches to new branch)
**Branch naming guidelines:**
- Use your GitHub username as prefix
- Use descriptive names for the feature/fix
- Use kebab-case (lowercase with hyphens)
- Keep names concise but clear
### 3. Implement Your Feature or Fix
#### Development Setup
Ensure your development environment is ready:
```bash
# Install dependencies (if not done already)
npm install
```
#### Making Changes
**For Core Framework Changes:**
```bash
# Work in the core framework
cd xmlui/src/
# Make your changes to components, parsers, etc.
# Edit files in: components/, abstractions/, parsers/, etc.
```
**For Extension Package Changes:**
```bash
# Work in specific extension
cd packages/xmlui-animations/src/
# Make your changes
# Each package has its own src/ directory
```
**For Documentation Changes:**
```bash
# Work in documentation
cd docs/src/
# Update documentation content
# Edit Main.xmlui, components/, content/, etc.
```
### 4. Regular Testing
Test your changes regularly during development:
#### Command Line
```bash
# Run unit tests
cd xmlui
npm run test:unit
# Run end-to-end smoke tests (quick)
npm run test:e2e-smoke
# Run full test suite (slower)
npm run test:e2e
# Test specific package
cd packages/xmlui-animations
npm test
```
#### VS Code
1. **Open integrated terminal**: Ctrl/Cmd + ` (backtick)
2. **Run tests via terminal**: Use same npm commands as above
3. **Use Test Explorer** (if available):
- Install Jest or other test extensions
- View → Test Explorer
- Run tests from sidebar
4. **NPM Scripts panel**: Explorer → NPM Scripts → click test scripts
#### IntelliJ IDEA / WebStorm
1. **Use built-in terminal**: Alt/Opt + F12 → run npm commands
2. **NPM tool window**: View → Tool Windows → NPM → double-click test scripts
3. **Run configurations**:
- Run → Edit Configurations → "+" → NPM
- Set script: "test:unit", "test:e2e-smoke", etc.
- Save and run with Ctrl/Cmd + R
4. **Test runner integration**: Right-click test files → "Run" (for Jest/Vitest)
**Manual Testing:**
- Use the documentation site to test your changes visually
- Test in different browsers if making UI changes
- Verify your changes work with different configurations
### 5. Update Documentation
If your changes affect user-facing functionality:
**Component Documentation:**
```bash
# Update component examples in docs
cd docs/content/components/
# Edit relevant .md files
```
**API Documentation:**
```bash
# Update API documentation
cd docs/content/api/
# Add or update API descriptions
```
**Developer Documentation:**
```bash
# Update developer guides if needed
cd xmlui/dev-docs/next/
# Edit relevant .md files
```
**Code Comments:**
- Add JSDoc comments for new functions/components
- Update existing comments if behavior changes
- Include usage examples in complex functions
### 6. Add Changesets
Document your changes using changesets for proper versioning:
#### Command Line
```bash
# Add a changeset
npm run changeset:add
# Follow the interactive prompts:
# 1. Select which packages your change affects
# 2. Choose change type: patch (bug fix), minor (feature), major (breaking)
# 3. Write a clear description of your change
```
#### VS Code
1. **Open integrated terminal**: Ctrl/Cmd + `
2. **Run changeset command**: `npm run changeset:add`
3. **Use terminal prompts**: Navigate with arrow keys, select with space, enter to continue
4. **Alternative - NPM Scripts**: Explorer → NPM Scripts → "changeset:add"
#### IntelliJ IDEA / WebStorm
1. **Open terminal**: Alt/Opt + F12
2. **Run changeset command**: `npm run changeset:add`
3. **Use interactive prompts**: Follow terminal instructions
4. **Alternative - NPM tool**: View → Tool Windows → NPM → double-click "changeset:add"
**Changeset Guidelines:**
- **Patch**: Bug fixes, small improvements
- **Minor**: New features, new components
- **Major**: Breaking changes, API changes
**Example changeset descriptions:**
```markdown
Add new animation components for smooth transitions
Fix search performance issue with large datasets
Update PDF export to support custom page sizes
```
### 7. Final Testing
Before creating a pull request, run comprehensive tests from the **root folder**:
#### Command Line
```bash
# Run complete test suite (development mode)
npm run test-xmlui
# OR run complete test suite (CI mode - faster, production-like)
npm run test-xmlui:ci
# Verify changesets
npm run changeset:version
```
**Test Command Differences:**
- **`test-xmlui`**: Full test suite with development optimizations and detailed output
- **`test-xmlui:ci`**: Same tests but with `CI=true` environment variable for:
- Faster execution (no watch mode)
- Production-like environment
- Better suited for automated testing
- Less verbose output
#### VS Code
1. **Open terminal**: Ctrl/Cmd + `
2. **Navigate to root**: Ensure you're in the root folder (not in subpackages)
3. **Run test commands**: Use same npm commands as above
4. **Use NPM Scripts panel**:
- Explorer → NPM Scripts (root level)
- Click "test-xmlui" or "test-xmlui:ci"
5. **Tasks**: Ctrl/Cmd + Shift + P → "Tasks: Run Task" → select test tasks
#### IntelliJ IDEA / WebStorm
1. **Navigate to root**: Ensure project root is selected in Project tool window
2. **NPM tool window**: View → Tool Windows → NPM (shows root package.json scripts)
3. **Run scripts**: Double-click "test-xmlui" or "test-xmlui:ci"
4. **Terminal alternative**: Alt/Opt + F12 → run npm commands from root
5. **Run configurations**:
- Create NPM run configs for frequently used commands
- Run → Edit Configurations → "+" → NPM
- Set Package: (root package.json)
**Pre-commit Checklist:**
- [ ] All tests pass
- [ ] Documentation updated
- [ ] Changesets added
- [ ] Code formatted properly
- [ ] No console errors in development
### 8. Create and Merge Pull Request
#### Commit Your Changes
#### Command Line
```bash
# Stage your changes
git add .
# Commit with descriptive message
git commit -m "Add animation components with spring physics
- Implement bounce, fade, and slide animations
- Add comprehensive test coverage
- Update documentation with examples
- Add changeset for minor version bump"
# Push to your branch
git push origin johndoe/add-animation-components
```
#### VS Code
1. **Stage changes**: Source Control panel (Ctrl/Cmd + Shift + G) → "+" next to files or "Stage All Changes"
2. **Write commit message**: Enter message in text box at top
3. **Commit**: Click "✓ Commit" button or Ctrl/Cmd + Enter
4. **Push**: Click "..." → "Push" or sync icon in status bar
#### IntelliJ IDEA / WebStorm
1. **Open commit window**: Ctrl/Cmd + K or VCS → "Commit"
2. **Select files**: Check files to include in commit
3. **Write commit message**: Enter in message field
4. **Commit**: Click "Commit" button
5. **Push**: VCS → "Git" → "Push" or Ctrl/Cmd + Shift + K
#### Create Pull Request
1. **Go to GitHub** and create a pull request from your branch
2. **Use descriptive title**: Same as your commit message headline
3. **Fill out PR template** with:
- Description of changes
- Testing performed
- Screenshots (if UI changes)
- Breaking changes (if any)
#### Pull Request Review
- **Respond to feedback** promptly
- **Make requested changes** in new commits
- **Update tests** if reviewers suggest improvements
- **Rebase if needed** to keep history clean
#### Merge Process
Once approved:
#### Command Line
```bash
# Sync with main before merging (if needed)
git checkout main
git pull origin main
git checkout johndoe/add-animation-components
git rebase main
# Push updated branch
git push origin johndoe/add-animation-components --force-with-lease
```
#### VS Code
1. **Switch to main**: Click branch name → "main"
2. **Pull latest**: Source Control → "..." → "Pull"
3. **Switch back to feature branch**: Click branch → "johndoe/add-animation-components"
4. **Rebase** (if needed): Source Control → "..." → "Branch" → "Rebase Branch..."
5. **Push**: Source Control → "..." → "Push" → "Push (Force with Lease)" if rebased
#### IntelliJ IDEA / WebStorm
1. **Switch to main**: Bottom right → "main"
2. **Pull latest**: VCS → "Git" → "Pull" or Ctrl/Cmd + T
3. **Switch to feature branch**: Bottom right → "johndoe/add-animation-components"
4. **Rebase** (if needed): VCS → "Git" → "Rebase..." → select "main"
5. **Push**: VCS → "Git" → "Push" → check "Force with lease" if rebased
- **Merge via GitHub** using "Squash and merge" (preferred)
- **Delete branch** after merging
- **Clean up locally**:
#### Command Line
```bash
git checkout main
git pull origin main
git branch -d johndoe/add-animation-components
```
#### VS Code
1. **Switch to main**: Click branch name → "main"
2. **Pull latest**: Source Control → "..." → "Pull"
3. **Delete branch**: Click branch name → find old branch → click "🗑️" delete icon
#### IntelliJ IDEA / WebStorm
1. **Switch to main**: Bottom right → "main"
2. **Pull latest**: Ctrl/Cmd + T
3. **Delete branch**: Bottom right → find old branch → "Delete"
## Common Development Tasks
### Adding a New Component
1. **Create component** in appropriate package (`packages/xmlui-*/src/`)
2. **Add tests** in same package
3. **Export component** from package index
4. **Add documentation** with examples
5. **Add changeset** (minor version)
### Fixing a Bug
1. **Write test** that reproduces the bug
2. **Fix the issue** while ensuring test passes
3. **Verify fix** doesn't break existing functionality
4. **Add changeset** (patch version)
### Updating Dependencies
1. **Update package.json** files
2. **Test thoroughly** for breaking changes
3. **Update documentation** if APIs changed
4. **Add changeset** (patch or minor depending on impact)
### Performance Improvements
1. **Benchmark current performance**
2. **Implement improvements**
3. **Verify performance gains**
4. **Add performance tests** if possible
5. **Document improvements**
This workflow ensures code quality, proper testing, and coordinated releases across the entire XMLUI monorepo.
## Using Development Branch in XMLUI Apps
When developing new features or fixing bugs in the XMLUI framework, you often need to test your changes in a real application before releasing a new version. This section describes how to link your local XMLUI development repository directly to your application, allowing you to test framework modifications immediately without publishing packages.
### Why Use Local Development Linking
- **Instant Testing**: Test your XMLUI framework changes in real applications without waiting for releases
- **Faster Development**: Iterate quickly on framework features while seeing immediate results in your app
- **Bug Verification**: Confirm that bug fixes work correctly in actual use cases
- **Feature Validation**: Ensure new framework features integrate properly with existing applications
### Setting Up npm Link
To use the current development branch of XMLUI (main or your feature/fix branch) in your application, you need to create an npm link from your local XMLUI repository to your app.
> **Note**: npm link creates symbolic links between packages, allowing you to use a local development version of a package instead of the published version from the npm registry. When you run `npm link` in a package directory, it creates a global symbolic link to that package. Then, when you run `npm link <package-name>` in another project, it creates a local symbolic link from your project's `node_modules` to the global link.
>
> This approach bypasses the normal npm installation process and directly connects your application to your local development code. Any changes you make to the linked package (after building) will be immediately available to your application, enabling rapid development and testing cycles.
#### Step 1: Create the Link in XMLUI Repository
Navigate to the XMLUI core framework directory and create a global npm link:
```bash
# Navigate to the XMLUI core framework
cd /path/to/xmlui-repo/xmlui
# Create a global npm link for the xmlui package
npm link
```
**IDE Tip**: In VS Code or IntelliJ IDEA/WebStorm, you can right-click on the `xmlui` folder in the project explorer and select "Open in Terminal" (VS Code) or "Open Terminal Here" (IntelliJ/WebStorm) to open a terminal directly in the xmlui directory, eliminating the need for the `cd` command.
**Example XMLUI Application package.json**:
```json
{
"name": "my-xmlui-app",
"private": true,
"version": "0.0.1",
"scripts": {
"start": "xmlui start",
"build": "xmlui build",
"preview": "xmlui preview",
"build-prod": "npm run build -- --prod",
"release-ci": "npm run build-prod && xmlui zip-dist",
"release-prod": "npm run build-prod && xmlui zip-dist"
},
"dependencies": {
"xmlui": "*"
}
}
```
#### Step 2: Link in Your Application
Your application's package.json should reference the XMLUI framework like in this sample:
```json
{
"name": "my-xmlui-app",
"private": true,
"version": "0.0.1",
"scripts": {
"start": "xmlui start",
"build": "xmlui build",
"preview": "xmlui preview",
"build-prod": "npm run build -- --prod",
"release-ci": "npm run build-prod && xmlui zip-dist",
"release-prod": "npm run build-prod && xmlui zip-dist"
},
"dependencies": {
"xmlui": "*"
}
}
```
In your XMLUI application directory, link to your local development version:
```bash
# Navigate to your XMLUI application
cd /path/to/your-xmlui-app
# Link to your local XMLUI development version
npm link xmlui
```
> **Important**: If you modify the dependencies in your application's package.json and run `npm install`, you'll need to run `npm link xmlui` again to restore the link to your local development version.
> **Note**: In some cases (it's an npm feature or bug), you may need to use `npm link xmlui react react-dom`. If running the app after `npm link xmlui` gives an error about react or react-dom, this is the resolution.
#### Step 3: Test Your Application
Your application now uses your local XMLUI development version. The Vite development server automatically uses the freshest framework code without requiring a build step:
```bash
# In your application directory
npm start
# Your app now runs with your local XMLUI modifications
# Vite ensures you're using the latest framework code for fast iteration
```
> **Note**: Sometimes Vite hot module reloading may face situations when reloading your app after an XMLUI change does not work as expected (because the reloading did not detect the effect of changes correctly). In this case, stop the running app and start again with `npm start`.
```
--------------------------------------------------------------------------------
/xmlui/src/components/DatePicker/DatePickerNative.tsx:
--------------------------------------------------------------------------------
```typescript
import { type CSSProperties, type ForwardedRef, useRef } from "react";
import { forwardRef, useCallback, useEffect, useMemo, useState } from "react";
import type { DateRange, Matcher } from "react-day-picker";
import { DayPicker } from "react-day-picker";
import { format, parse, isValid, parseISO } from "date-fns";
import classnames from "classnames";
import styles from "./DatePicker.module.scss";
import type { RegisterComponentApiFn, UpdateStateFn } from "../../abstractions/RendererDefs";
import { useTheme } from "../../components-core/theming/ThemeContext";
import { noop } from "../../components-core/constants";
import { useEvent } from "../../components-core/utils/misc";
import type { ValidationStatus } from "../abstractions";
import { Adornment } from "../Input/InputAdornment";
import { Popover, PopoverContent, PopoverPortal, PopoverTrigger } from "@radix-ui/react-popover";
import Icon from "../Icon/IconNative";
import { composeRefs } from "@radix-ui/react-compose-refs";
export const DatePickerModeValues = ["single", "range"] as const;
type DatePickerMode = (typeof DatePickerModeValues)[number];
// Extended matcher types that support string dates in addition to Date objects
type StringDateRange = {
from: string | Date;
to?: string | Date;
};
type StringDateBefore = {
before: string | Date;
};
type StringDateAfter = {
after: string | Date;
};
type StringDateInterval = {
before: string | Date;
after: string | Date;
};
type DayOfWeekMatcher = {
dayOfWeek: number | number[];
};
type ExtendedMatcher =
| boolean
| string
| Date
| (string | Date)[]
| StringDateRange
| StringDateBefore
| StringDateAfter
| StringDateInterval
| DayOfWeekMatcher
| ((date: Date) => boolean)
| ExtendedMatcher[];
type Props = {
id?: string;
initialValue?: string | { from: string; to: string };
value?: string | { from: string; to: string };
mode?: DatePickerMode;
enabled?: boolean;
placeholder?: string;
updateState?: UpdateStateFn;
style?: CSSProperties;
className?: string;
onDidChange?: (newValue: string | { from: string; to: string }) => void;
onFocus?: () => void;
onBlur?: () => void;
validationStatus?: ValidationStatus;
registerComponentApi?: RegisterComponentApiFn;
dateFormat?: DateFormat;
showWeekNumber?: boolean;
weekStartsOn?: WeekDays;
startDate?: string;
endDate?: string;
disabledDates?: ExtendedMatcher;
inline?: boolean;
startText?: string;
startIcon?: string;
endText?: string;
endIcon?: string;
label?: string;
labelPosition?: string;
labelWidth?: string;
labelBreak?: boolean;
inProgress?: boolean;
inProgressNotificationMessage?: string;
readOnly?: boolean;
required?: boolean;
autoFocus?: boolean;
};
export const enum WeekDays {
Sunday = 0,
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday = 6,
}
export const dateFormats = [
"MM/dd/yyyy",
"MM-dd-yyyy",
"yyyy/MM/dd",
"yyyy-MM-dd",
"dd/MM/yyyy",
"dd-MM-yyyy",
"yyyyMMdd",
"MMddyyyy",
] as const;
type DateFormat = (typeof dateFormats)[number];
export const defaultProps: Pick<
Props,
| "mode"
| "validationStatus"
| "enabled"
| "inline"
| "dateFormat"
| "showWeekNumber"
| "weekStartsOn"
| "disabledDates"
> = {
mode: "single",
validationStatus: "none",
enabled: true,
inline: false,
dateFormat: "MM/dd/yyyy",
showWeekNumber: false,
weekStartsOn: WeekDays.Sunday,
disabledDates: undefined as ExtendedMatcher | undefined,
};
const Chevron = ({ ...props }) => {
const { orientation = "left" } = props;
if (orientation === "up") {
return <Icon name={"chevronup"} size={"sm"} />;
} else if (orientation === "down") {
return <Icon name={"chevrondown"} size={"sm"} />;
} else if (orientation === "left") {
return <Icon name={"chevronleft"} size={"lg"} />;
} else if (orientation === "right") {
return <Icon name={"chevronright"} size={"lg"} />;
}
};
export const DatePicker = forwardRef(function DatePicker(
{
id,
initialValue,
value,
mode = defaultProps.mode,
enabled = defaultProps.enabled,
placeholder,
updateState = noop,
validationStatus = defaultProps.validationStatus,
onDidChange = noop,
onFocus = noop,
onBlur = noop,
dateFormat = defaultProps.dateFormat,
showWeekNumber = defaultProps.showWeekNumber,
weekStartsOn = defaultProps.weekStartsOn,
startDate,
endDate,
disabledDates = defaultProps.disabledDates,
style,
className,
registerComponentApi,
inline = defaultProps.inline,
startText,
startIcon,
endText,
endIcon,
label,
labelPosition,
labelWidth,
labelBreak,
readOnly = false,
required,
autoFocus = false,
...rest
}: Props,
forwardedRef: ForwardedRef<HTMLDivElement>,
) {
const _weekStartsOn = weekStartsOn >= 0 && weekStartsOn <= 6 ? weekStartsOn : WeekDays.Sunday;
const [_, setIsMenuFocused] = useState(false);
const [referenceElement, setReferenceElement] = useState<HTMLElement | null>(null);
const [inlineMonth, setInlineMonth] = useState<Date | undefined>();
const inputRef = useRef<HTMLInputElement>(null);
const ref = forwardedRef ? composeRefs(forwardedRef, inputRef) : inputRef;
const selected: any = useMemo(() => {
if (mode === "single" && typeof value === "string") {
return parseISODate(value) || parseDate(value);
} else if (mode === "range" && typeof value === "object") {
return {
from: parseISODate(value?.from) || parseDate(value?.from),
to: parseISODate(value?.to) || parseDate(value?.to),
};
}
return undefined;
}, [value, mode]);
useEffect(() => {
if (!dateFormats.includes(dateFormat)) {
throw new Error(
`Invalid dateFormat: ${dateFormat}. Supported formats are: ${dateFormats.join(", ")}`,
);
}
}, [dateFormat]);
const _startDate = useMemo(() => {
return startDate ? parse(startDate, dateFormat, new Date()) : undefined;
}, [startDate, dateFormat]);
const _endDate = useMemo(() => {
return endDate ? parse(endDate, dateFormat, new Date()) : undefined;
}, [endDate, dateFormat]);
const defaultMonth = useMemo(() => {
if (mode === "single" && selected) {
return selected;
} else if (mode === "range" && selected && typeof selected === "object" && selected.from) {
return selected.from;
}
return undefined;
}, [selected, mode]);
const disabled = useMemo(() => {
if (!disabledDates) {
return undefined;
}
const convertStringToDate = (dateValue: string | Date): Date | undefined => {
if (dateValue instanceof Date) {
return dateValue;
}
if (typeof dateValue === "string") {
// Try to parse as ISO date first
const isoDate = parseISODate(dateValue);
if (isoDate) {
return isoDate;
}
// Parse using the specified dateFormat
const parsedDate = parse(dateValue, dateFormat, new Date());
if (isValid(parsedDate)) {
return parsedDate;
}
}
return undefined;
};
const convertMatcher = (matcher: ExtendedMatcher): Matcher | undefined => {
// Handle boolean - disable all dates
if (typeof matcher === "boolean") {
return matcher;
}
// Handle function matcher - pass through as is
if (typeof matcher === "function") {
return matcher;
}
// Handle single Date or string
if (matcher instanceof Date || typeof matcher === "string") {
const convertedDate = convertStringToDate(matcher);
return convertedDate || undefined;
}
// Handle array of mixed matchers (combines multiple disable patterns)
if (Array.isArray(matcher)) {
const convertedMatchers: any[] = [];
for (const item of matcher) {
if (
typeof item === "object" &&
item !== null &&
!Array.isArray(item) &&
!(item instanceof Date)
) {
// Handle nested matcher objects in array (e.g., {dayOfWeek: [0,6]}, {from: date, to: date})
const nestedResult = convertMatcher(item);
if (nestedResult) {
convertedMatchers.push(nestedResult);
}
} else if (item instanceof Date || typeof item === "string") {
// Handle individual dates in the array
const convertedDate = convertStringToDate(item);
if (convertedDate) {
convertedMatchers.push(convertedDate);
}
}
}
// Return array of all matchers to combine their effects
return convertedMatchers.length > 0 ? (convertedMatchers as Matcher) : undefined;
}
// Handle object matchers (DateRange, DateBefore, DateAfter, DateInterval, DayOfWeek)
if (typeof matcher === "object" && matcher !== null) {
// Handle DateRange: { from: Date, to?: Date }
if ("from" in matcher) {
const fromDate = convertStringToDate(matcher.from);
const toDate = matcher.to ? convertStringToDate(matcher.to) : undefined;
if (fromDate) {
return { from: fromDate, to: toDate };
}
}
// Handle DateBefore: { before: Date }
if ("before" in matcher && !("after" in matcher)) {
const beforeDate = convertStringToDate(matcher.before);
if (beforeDate) {
return { before: beforeDate };
}
}
// Handle DateAfter: { after: Date }
if ("after" in matcher && !("before" in matcher)) {
const afterDate = convertStringToDate(matcher.after);
if (afterDate) {
return { after: afterDate };
}
}
// Handle DateInterval: { before: Date, after: Date }
if ("before" in matcher && "after" in matcher) {
const beforeDate = convertStringToDate(matcher.before);
const afterDate = convertStringToDate(matcher.after);
if (beforeDate && afterDate) {
return { before: beforeDate, after: afterDate };
}
}
// Handle DayOfWeek: { dayOfWeek: number | number[] }
if ("dayOfWeek" in matcher) {
return { dayOfWeek: matcher.dayOfWeek };
}
}
return undefined;
};
return convertMatcher(disabledDates);
}, [disabledDates, dateFormat]);
const [open, setOpen] = useState(false);
const { root } = useTheme();
const handleOnMenuFocus = () => {
setIsMenuFocused(true);
};
const handleOnMenuBlur = () => {
setIsMenuFocused(false);
};
// Register component API for external interactions
const focus = useCallback(() => {
referenceElement?.focus();
}, [referenceElement]);
const setValue = useEvent((newValue: string) => {
updateState({ value: newValue });
});
useEffect(() => {
registerComponentApi?.({
focus,
setValue,
});
}, [focus, registerComponentApi, setValue]);
// useEffect(() => {
// if (!isButtonFocused && !isMenuFocused) {
// onBlur?.();
// }
// if (isButtonFocused || isMenuFocused) {
// onFocus?.();
// }
// }, [isButtonFocused, isMenuFocused, onFocus, onBlur]);
useEffect(() => {
updateState({ value: initialValue }, { initial: true });
}, [initialValue, updateState]);
// Update inline month when selected value changes
useEffect(() => {
if (inline) {
if (mode === "single" && selected) {
setInlineMonth(selected);
} else if (mode === "range" && selected && typeof selected === "object" && selected.from) {
setInlineMonth(selected.from);
} else if (!selected) {
// Reset to defaultMonth logic when no selection
setInlineMonth(defaultMonth);
}
}
}, [selected, mode, inline, defaultMonth]);
const handleSelect = useCallback(
(dateOrRange?: Date | DateRange) => {
if (readOnly) {
return;
}
if (!dateOrRange) {
updateState({ value: undefined });
onDidChange("");
} else if (mode === "single") {
const date = dateOrRange as Date;
const formattedDate = format(date, dateFormat);
updateState({ value: formattedDate });
onDidChange(formattedDate);
} else {
const range = dateOrRange as DateRange;
const formattedRange = {
from: range.from ? format(range.from, dateFormat) : "",
to: range.to ? format(range.to, dateFormat) : "",
};
updateState({ value: formattedRange });
onDidChange(formattedRange);
}
if (mode === "single") {
setOpen(false);
}
},
[onDidChange, updateState, mode, dateFormat, readOnly],
);
return inline ? (
<div
ref={ref}
{...rest}
style={style}
className={classnames(styles.inlinePickerMenu, className)}
tabIndex={0}
>
<DayPicker
id={id}
required={undefined}
captionLayout="dropdown"
fixedWeeks
startMonth={_startDate}
endMonth={_endDate}
month={inlineMonth}
onMonthChange={setInlineMonth}
disabled={disabled}
weekStartsOn={_weekStartsOn}
showWeekNumber={showWeekNumber}
showOutsideDays
classNames={styles}
mode={mode === "single" ? "single" : "range"}
selected={selected}
onSelect={handleSelect}
autoFocus={autoFocus}
numberOfMonths={mode === "range" ? 2 : 1}
components={{
Chevron,
}}
/>
</div>
) : (
<Popover open={open} onOpenChange={setOpen} modal={false}>
<PopoverTrigger
id={id}
ref={composeRefs(setReferenceElement, ref)}
aria-haspopup={true}
disabled={!enabled}
style={style}
aria-expanded={open}
className={classnames(
className,
styles.datePicker,
{
[styles.disabled]: !enabled,
[styles.error]: validationStatus === "error",
[styles.warning]: validationStatus === "warning",
[styles.valid]: validationStatus === "valid",
},
className,
)}
autoFocus={autoFocus}
onFocus={onFocus}
onBlur={onBlur}
>
<Adornment text={startText} iconName={startIcon} className={styles.adornment} />
<div className={styles.datePickerValue}>
{mode === "single" && selected ? (
<>{format(selected, dateFormat)}</>
) : mode === "range" && typeof selected === "object" && selected.from ? (
selected.to ? (
<>
{format(selected.from, dateFormat)} - {format(selected.to, dateFormat)}
</>
) : (
<>{format(selected.from, dateFormat)}</>
)
) : placeholder ? (
<span className={styles.placeholder} placeholder={placeholder}>
{placeholder}
</span>
) : (
<span> </span>
)}
</div>
<Adornment text={endText} iconName={endIcon} className={styles.adornment} />
</PopoverTrigger>
<PopoverPortal container={root}>
<PopoverContent
role="menu"
align={"start"}
sideOffset={5}
className={styles.datePickerMenu}
onFocus={handleOnMenuFocus}
onBlur={handleOnMenuBlur}
onInteractOutside={handleOnMenuBlur}
>
<DayPicker
required={undefined}
animate
fixedWeeks
autoFocus={autoFocus}
classNames={styles}
captionLayout="dropdown"
startMonth={_startDate}
endMonth={_endDate}
defaultMonth={defaultMonth}
disabled={disabled}
weekStartsOn={_weekStartsOn}
showWeekNumber={showWeekNumber}
showOutsideDays
mode={mode === "single" ? "single" : "range"}
selected={selected}
onSelect={handleSelect}
numberOfMonths={mode === "range" ? 2 : 1}
components={{
Chevron,
}}
/>
</PopoverContent>
</PopoverPortal>
</Popover>
);
});
const isoRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/;
const parseISODate = (dateString?: string) => {
if (dateString && isoRegex.test(dateString)) {
const parsedDate = parseISO(dateString);
if (isValid(parsedDate)) {
return parsedDate;
}
}
return undefined;
};
const parseDate = (dateString?: string) => {
if (dateString) {
for (const format of dateFormats) {
const parsedDate = parse(dateString, format, new Date());
if (isValid(parsedDate)) {
return parsedDate;
}
}
}
return undefined;
};
```
--------------------------------------------------------------------------------
/docs/content/components/App.md:
--------------------------------------------------------------------------------
```markdown
# App [#app]
The `App` component is the root container that defines your application's overall structure and layout. It provides a complete UI framework with built-in navigation, header, footer, and content areas that work together seamlessly.
**Essential features:**
- **Layout templates**: Choose from 7 predefined layouts (horizontal, vertical, condensed, etc.) with sticky navigation options
- **Routing**: Built-in page routing via the [Pages](/components/Pages) component
## Properties [#properties]
### `autoDetectTone` (default: false) [#autodetecttone-default-false]
This boolean property enables automatic detection of the system theme preference. When set to true and no defaultTone is specified, the app will automatically use "light" or "dark" tone based on the user's system theme setting. The app will also respond to changes in the system theme preference.
### `defaultTheme` [#defaulttheme]
This property sets the app's default theme.
### `defaultTone` [#defaulttone]
This property sets the app's default tone ("light" or "dark").
Available values: `light`, `dark`
### `layout` [#layout]
This property sets the layout template of the app. This setting determines the position and size of the app parts (such as header, navigation bar, footer, etc.) and the app's scroll behavior.
Available values:
| Value | Description |
| --- | --- |
| `vertical` | This layout puts the navigation bar on the left side and displays its items vertically. The main content is aligned to the right (including the header and the footer), and its content is a single scroll container; every part of it moves as you scroll the page. This layout does not display the logo in the app header. |
| `vertical-sticky` | Similar to `vertical`, the header and the navigation bar dock to the top of the main content's viewport, while the footer sticks to the bottom. This layout does not display the logo in the app header. |
| `vertical-full-header` | Similar to `vertical-sticky`. However, the header and the navigation bar dock to the top of the app's window, while the footer sticks to the bottom. |
| `condensed` | Similar to `horizontal`. However, the header and the navigation bar are in a single header block. (default) |
| `condensed-sticky` | However, the header and the navigation bar are in a single header block. |
| `horizontal` | This layout stacks the layout sections in a single column in this order: header, navigation bar, main content, and footer. The application is a single scroll container; every part moves as you scroll the page. |
| `horizontal-sticky` | Similar to `horizontal`, the header and the navigation bar dock to the top of the viewport, while the footer sticks to the bottom. |
| `desktop` | This layout stretches the app to fill the entire browser viewport with zero padding and margins. The header (if present) docks to the top, the footer (if present) docks to the bottom, and the main content stretches to fill the remaining vertical and horizontal space. |
Here are a few samples demonstrating the usage of the `layout` property. All samples use this markup, except the value of `App`'s layout and a few marked code snippets:
```xmlui
<App layout="(specific layout value)">
<!-- AppHeader omitted for "vertical" and "vertical-sticky" -->
<AppHeader>
<property name="logoTemplate">
<Heading level="h3" value="Example App"/>
</property>
</AppHeader>
<NavPanel>
<NavLink label="Home" to="/" icon="home"/>
<NavLink label="Page 1" to="/page1"/>
<NavLink label="Page 2" to="/page2"/>
</NavPanel>
<Pages fallbackPath="/">
<Page url="/">
<List data="https://api.spacexdata.com/v3/history">
<property name="itemTemplate">
<Card title="{$item.title}" subtitle="{$item.details}"/>
</property>
</List>
</Page>
<Page url="/page1">
<Text value="Page 1" />
</Page>
<Page url="/page2">
<Text value="Page 2" />
</Page>
</Pages>
<Footer>Powered by XMLUI</Footer>
</App>
```
#### `horizontal` [#horizontal]
```xmlui-pg copy name="Example: 'horizontal' layout" height="350px"
<App layout="horizontal">
<AppHeader>
<property name="logoTemplate">
<Heading level="h3" value="Example App"/>
</property>
</AppHeader>
<NavPanel>
<NavLink label="Home" to="/" icon="home"/>
<NavLink label="Page 1" to="/page1"/>
<NavLink label="Page 2" to="/page2"/>
</NavPanel>
<Pages fallbackPath="/">
<Page url="/">
<List data="https://api.spacexdata.com/v3/history">
<property name="itemTemplate">
<Card title="{$item.title}" subtitle="{$item.details}"/>
</property>
</List>
</Page>
<Page url="/page1">
<Text value="Page 1" />
</Page>
<Page url="/page2">
<Text value="Page 2" />
</Page>
</Pages>
<Footer>Powered by XMLUI</Footer>
</App>
```
#### `horizontal-sticky` [#horizontal-sticky]
```xmlui-pg copy name="Example: 'horizontal-sticky' layout" height="350px"
<App layout="horizontal-sticky">
<AppHeader>
<property name="logoTemplate">
<Heading level="h3" value="Example App"/>
</property>
</AppHeader>
<NavPanel>
<NavLink label="Home" to="/" icon="home"/>
<NavLink label="Page 1" to="/page1"/>
<NavLink label="Page 2" to="/page2"/>
</NavPanel>
<Pages fallbackPath="/">
<Page url="/">
<List data="https://api.spacexdata.com/v3/history">
<property name="itemTemplate">
<Card title="{$item.title}" subtitle="{$item.details}"/>
</property>
</List>
</Page>
<Page url="/page1">
<Text value="Page 1" />
</Page>
<Page url="/page2">
<Text value="Page 2" />
</Page>
</Pages>
<Footer>Powered by XMLUI</Footer>
</App>
```
#### `condensed` [#condensed]
```xmlui-pg copy name="Example: 'condensed' layout" height="350px"
<App layout="condensed">
<property name="logoTemplate">
<Heading level="h3" value="Example App"/>
</property>
<NavPanel>
<NavLink label="Home" to="/" icon="home"/>
<NavLink label="Page 1" to="/page1"/>
<NavLink label="Page 2" to="/page2"/>
</NavPanel>
<Pages fallbackPath="/">
<Page url="/">
<List data="https://api.spacexdata.com/v3/history">
<property name="itemTemplate">
<Card title="{$item.title}" subtitle="{$item.details}"/>
</property>
</List>
</Page>
<Page url="/page1">
<Text value="Page 1" />
</Page>
<Page url="/page2">
<Text value="Page 2" />
</Page>
</Pages>
<Footer>Powered by XMLUI</Footer>
</App>
```
#### `condensed-sticky` [#condensed-sticky]
```xmlui-pg copy name="Example: 'condensed-sticky' layout" height="350px"
<App layout="condensed-sticky">
<property name="logoTemplate">
<Heading level="h3" value="Example App"/>
</property>
<NavPanel>
<NavLink label="Home" to="/" icon="home"/>
<NavLink label="Page 1" to="/page1"/>
<NavLink label="Page 2" to="/page2"/>
</NavPanel>
<Pages fallbackPath="/">
<Page url="/">
<List data="https://api.spacexdata.com/v3/history">
<property name="itemTemplate">
<Card title="{$item.title}" subtitle="{$item.details}"/>
</property>
</List>
</Page>
<Page url="/page1">
<Text value="Page 1" />
</Page>
<Page url="/page2">
<Text value="Page 2" />
</Page>
</Pages>
<Footer>Powered by XMLUI</Footer>
</App>
```
#### `vertical` [#vertical]
```xmlui-pg copy name="Example: 'vertical' layout" height="300px"
<App layout="vertical">
<property name="logoTemplate">
<Heading level="h3" value="Example App"/>
</property>
<NavPanel>
<NavLink label="Home" to="/" icon="home"/>
<NavLink label="Page 1" to="/page1"/>
<NavLink label="Page 2" to="/page2"/>
</NavPanel>
<Pages fallbackPath="/">
<Page url="/">
<List data="https://api.spacexdata.com/v3/history">
<property name="itemTemplate">
<Card title="{$item.title}" subtitle="{$item.details}"/>
</property>
</List>
</Page>
<Page url="/page1">
<Text value="Page 1" />
</Page>
<Page url="/page2">
<Text value="Page 2" />
</Page>
</Pages>
<Footer>Powered by XMLUI</Footer>
</App>
```
#### `vertical-sticky` [#vertical-sticky]
```xmlui-pg copy name="Example: 'vertical-sticky' layout" height="300px"
<App layout="vertical-sticky">
<property name="logoTemplate">
<Heading level="h3" value="Example App"/>
</property>
<NavPanel>
<NavLink label="Home" to="/" icon="home"/>
<NavLink label="Page 1" to="/page1"/>
<NavLink label="Page 2" to="/page2"/>
</NavPanel>
<Pages fallbackPath="/">
<Page url="/">
<List data="https://api.spacexdata.com/v3/history">
<property name="itemTemplate">
<Card title="{$item.title}" subtitle="{$item.details}"/>
</property>
</List>
</Page>
<Page url="/page1">
<Text value="Page 1" />
</Page>
<Page url="/page2">
<Text value="Page 2" />
</Page>
</Pages>
<Footer>Powered by XMLUI</Footer>
</App>
```
#### `vertical-full-header` [#vertical-full-header]
```xmlui-pg copy name="Example: 'vertical-full-header' layout" height="300px"
<App layout="vertical-full-header">
<AppHeader>
<property name="logoTemplate">
<Heading level="h3" value="Example App"/>
</property>
</AppHeader>
<NavPanel>
<NavLink label="Home" to="/" icon="home"/>
<NavLink label="Page 1" to="/page1"/>
<NavLink label="Page 2" to="/page2"/>
</NavPanel>
<Pages fallbackPath="/">
<Page url="/">
<List data="https://api.spacexdata.com/v3/history">
<property name="itemTemplate">
<Card title="{$item.title}" subtitle="{$item.details}"/>
</property>
</List>
</Page>
<Page url="/page1">
<Text value="Page 1" />
</Page>
<Page url="/page2">
<Text value="Page 2" />
</Page>
</Pages>
<Footer>Powered by XMLUI</Footer>
</App>
```
#### `desktop` [#desktop]
```xmlui-pg copy name="Example: 'desktop' layout" height="300px"
<App layout="desktop">
<AppHeader>
<property name="logoTemplate">
<Heading level="h3" value="Example App"/>
</property>
</AppHeader>
<Pages fallbackPath="/">
<Page url="/">
<List data="https://api.spacexdata.com/v3/history">
<property name="itemTemplate">
<Card title="{$item.title}" subtitle="{$item.details}"/>
</property>
</List>
</Page>
<Page url="/page1">
<Text value="Page 1" />
</Page>
<Page url="/page2">
<Text value="Page 2" />
</Page>
</Pages>
<Footer>Powered by XMLUI</Footer>
</App>
```
The `desktop` layout is designed for full-screen desktop applications. It stretches the app to fill the entire browser viewport with zero padding and margins. The header (if present) docks to the top, the footer (if present) docks to the bottom, and the main content area stretches to fill all remaining vertical and horizontal space. This layout ignores all max-width constraints and scrollbar gutter settings to ensure edge-to-edge display.
### `loggedInUser` [#loggedinuser]
Stores information about the currently logged-in user. By not defining this property, you can indicate that no user is logged in.
Stores information about the currently logged in user.
Currently, there is no restriction on what the user data must look like.
```xmlui-pg copy display name="Example: loggedInUser" height="180px"
<App loggedInUser="{{ name: 'Joe', token: '1234' }}">
<NavPanel>
<NavLink label="Home" to="/" icon="home"/>
</NavPanel>
<Pages fallbackPath="/">
<Page url="/">
<Text value="User name: {loggedInUser.name}" />
<Text value="User token: {loggedInUser.token}" />
</Page>
</Pages>
</App>
```
### `logo` [#logo]
Optional logo path
### `logo-dark` [#logo-dark]
Optional logo path in dark tone
### `logo-light` [#logo-light]
Optional logo path in light tone
### `logoTemplate` [#logotemplate]
Optional template of the app logo
### `name` [#name]
Optional application name (visible in the browser tab). When you do not define this property, the tab name falls back to the one defined in the app's configuration. If the name is not configured, "XMLUI App" is displayed in the tab.
### `noScrollbarGutters` (default: false) [#noscrollbargutters-default-false]
This boolean property specifies whether the scrollbar gutters should be hidden.
### `scrollWholePage` (default: true) [#scrollwholepage-default-true]
This boolean property specifies whether the whole page should scroll (`true`) or just the content area (`false`). The default value is `true`.
This boolean property specifies whether the whole page should scroll (true) or just the content area (false).
The default value is `true`.
```xmlui-pg copy display name="Example: scrollWholePage" height="150px"
<App scrollWholePage="false">
<NavPanel>
<NavLink label="Home" to="/" icon="home"/>
</NavPanel>
<Pages fallbackPath="/">
<Page url="/">
<Text>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</Text>
</Page>
</Pages>
</App>
```
## Events [#events]
### `messageReceived` [#messagereceived]
This event fires when the `App` component receives a message from another window or iframe via the window.postMessage API.
The event handler method has two parameters. The first is the message sent; the second is the entire native event object.
```xmlui-pg copy display name="Example: messageReceived" /onMessageReceived/ /window.postMessage/
<App
var.message = "<none>"
onMessageReceived="(msg, ev) => {
message = JSON.stringify(msg);
console.log('Message event received:', ev);
}">
<Button label="Send a message"
onClick="window.postMessage({type: 'message', messages:'Here you are!'})" />
<Text>Message received: {message}</Text>
</App>
```
### `ready` [#ready]
This event fires when the `App` component finishes rendering on the page.
This event fires when the `App` component finishes rendering on the page.
Use it as `onReady` when inlining it on the component.
```xmlui-pg copy display name="Example: ready"
<App onReady="isAppReady = true">
<variable name="isAppReady" value="{false}"/>
<Text value="{isAppReady ? 'App is ready' : 'Sadly, App is not ready'}" />
</App>
```
## Exposed Methods [#exposed-methods]
This component does not expose any methods.
## Styling [#styling]
### Theme Variables [#theme-variables]
| Variable | Default Value (Light) | Default Value (Dark) |
| --- | --- | --- |
| [backgroundColor](../styles-and-themes/common-units/#color)-AppHeader | *none* | *none* |
| [backgroundColor](../styles-and-themes/common-units/#color)-content-App | $backgroundColor | $backgroundColor |
| [backgroundColor](../styles-and-themes/common-units/#color)-navPanel-App | $backgroundColor | $backgroundColor |
| [borderBottom](../styles-and-themes/common-units/#border)-AppHeader | *none* | *none* |
| [borderLeft](../styles-and-themes/common-units/#border)-content-App | *none* | *none* |
| [boxShadow](../styles-and-themes/common-units/#boxShadow)-header-App | none | none |
| [boxShadow](../styles-and-themes/common-units/#boxShadow)-navPanel-App | none | none |
| [maxWidth](../styles-and-themes/common-units/#size)-App | $maxWidth-content | $maxWidth-content |
| [maxWidth-content](../styles-and-themes/common-units/#size)-App | $maxWidth-content | $maxWidth-content |
| [width](../styles-and-themes/common-units/#size)-navPanel-App | $space-64 | $space-64 |
### Variable Explanations [#variable-explanations]
| Theme Variable | Description |
| --- | --- |
| **`maxWidth-content-App`** | This theme variable defines the maximum width of the main content. If the main content is broader, the engine adds margins to keep the expected maximum size. |
| **`boxShadow‑header‑App`** | This theme variable sets the shadow of the app's header section. |
| **`boxShadow‑navPanel‑App`** | This theme variable sets the shadow of the app's navigation panel section (visible only in vertical layouts). |
| **`width‑navPanel‑App`** | This theme variable sets the width of the navigation panel when the app is displayed with one of the vertical layouts. |
```