This is page 14 of 181. Use http://codebase.md/xmlui-org/xmlui/mockApiDef.js?lines=true&page={x} to view the full context. # Directory Structure ``` ├── .changeset │ ├── config.json │ └── cool-queens-look.md ├── .eslintrc.cjs ├── .github │ ├── build-checklist.png │ ├── ISSUE_TEMPLATE │ │ ├── bug_report.md │ │ └── feature_request.md │ └── workflows │ ├── deploy-blog.yml │ ├── deploy-docs-optimized.yml │ ├── deploy-docs.yml │ ├── prepare-versions.yml │ ├── release-packages.yml │ ├── run-all-tests.yml │ └── run-smoke-tests.yml ├── .gitignore ├── .prettierrc.js ├── .vscode │ ├── launch.json │ └── settings.json ├── blog │ ├── .gitignore │ ├── .gitkeep │ ├── CHANGELOG.md │ ├── extensions.ts │ ├── index.html │ ├── index.ts │ ├── package.json │ ├── public │ │ ├── blog │ │ │ ├── images │ │ │ │ ├── blog-page-component.png │ │ │ │ ├── blog-scrabble.png │ │ │ │ ├── integrated-blog-search.png │ │ │ │ └── lorem-ipsum.png │ │ │ ├── lorem-ipsum.md │ │ │ ├── newest-post.md │ │ │ ├── older-post.md │ │ │ └── welcome-to-the-xmlui-blog.md │ │ ├── mockServiceWorker.js │ │ ├── netlify.toml │ │ ├── resources │ │ │ ├── favicon.ico │ │ │ ├── files │ │ │ │ └── for-download │ │ │ │ └── xmlui │ │ │ │ └── xmlui-standalone.umd.js │ │ │ ├── github.svg │ │ │ ├── llms.txt │ │ │ ├── logo-dark.svg │ │ │ ├── logo.svg │ │ │ ├── pg-popout.svg │ │ │ └── xmlui-logo.svg │ │ ├── serve.json │ │ └── web.config │ ├── scripts │ │ ├── download-latest-xmlui.js │ │ ├── generate-rss.js │ │ ├── get-releases.js │ │ └── utils.js │ ├── src │ │ ├── components │ │ │ ├── BlogOverview.xmlui │ │ │ ├── BlogPage.xmlui │ │ │ ├── Debug.xmlui │ │ │ └── PageNotFound.xmlui │ │ ├── config.ts │ │ ├── Main.xmlui │ │ ├── Main.xmlui.xs │ │ └── themes │ │ ├── docs-theme.ts │ │ ├── earthtone.ts │ │ ├── xmlui-gray-on-default.ts │ │ ├── xmlui-green-on-default.ts │ │ └── xmlui-orange-on-default.ts │ └── tsconfig.json ├── CONTRIBUTING.md ├── docs │ ├── .gitignore │ ├── CHANGELOG.md │ ├── ComponentRefLinks.txt │ ├── content │ │ ├── _meta.json │ │ ├── components │ │ │ ├── _meta.json │ │ │ ├── _overview.md │ │ │ ├── APICall.md │ │ │ ├── App.md │ │ │ ├── AppHeader.md │ │ │ ├── AppState.md │ │ │ ├── AutoComplete.md │ │ │ ├── Avatar.md │ │ │ ├── Backdrop.md │ │ │ ├── Badge.md │ │ │ ├── BarChart.md │ │ │ ├── Bookmark.md │ │ │ ├── Breakout.md │ │ │ ├── Button.md │ │ │ ├── Card.md │ │ │ ├── Carousel.md │ │ │ ├── ChangeListener.md │ │ │ ├── Checkbox.md │ │ │ ├── CHStack.md │ │ │ ├── ColorPicker.md │ │ │ ├── Column.md │ │ │ ├── ContentSeparator.md │ │ │ ├── CVStack.md │ │ │ ├── DataSource.md │ │ │ ├── DateInput.md │ │ │ ├── DatePicker.md │ │ │ ├── DonutChart.md │ │ │ ├── DropdownMenu.md │ │ │ ├── EmojiSelector.md │ │ │ ├── ExpandableItem.md │ │ │ ├── FileInput.md │ │ │ ├── FileUploadDropZone.md │ │ │ ├── FlowLayout.md │ │ │ ├── Footer.md │ │ │ ├── Form.md │ │ │ ├── FormItem.md │ │ │ ├── FormSection.md │ │ │ ├── Fragment.md │ │ │ ├── H1.md │ │ │ ├── H2.md │ │ │ ├── H3.md │ │ │ ├── H4.md │ │ │ ├── H5.md │ │ │ ├── H6.md │ │ │ ├── Heading.md │ │ │ ├── HSplitter.md │ │ │ ├── HStack.md │ │ │ ├── Icon.md │ │ │ ├── IFrame.md │ │ │ ├── Image.md │ │ │ ├── Items.md │ │ │ ├── LabelList.md │ │ │ ├── Legend.md │ │ │ ├── LineChart.md │ │ │ ├── Link.md │ │ │ ├── List.md │ │ │ ├── Logo.md │ │ │ ├── Markdown.md │ │ │ ├── MenuItem.md │ │ │ ├── MenuSeparator.md │ │ │ ├── ModalDialog.md │ │ │ ├── NavGroup.md │ │ │ ├── NavLink.md │ │ │ ├── NavPanel.md │ │ │ ├── NoResult.md │ │ │ ├── NumberBox.md │ │ │ ├── Option.md │ │ │ ├── Page.md │ │ │ ├── PageMetaTitle.md │ │ │ ├── Pages.md │ │ │ ├── Pagination.md │ │ │ ├── PasswordInput.md │ │ │ ├── PieChart.md │ │ │ ├── ProgressBar.md │ │ │ ├── Queue.md │ │ │ ├── RadioGroup.md │ │ │ ├── RealTimeAdapter.md │ │ │ ├── Redirect.md │ │ │ ├── Select.md │ │ │ ├── Slider.md │ │ │ ├── Slot.md │ │ │ ├── SpaceFiller.md │ │ │ ├── Spinner.md │ │ │ ├── Splitter.md │ │ │ ├── Stack.md │ │ │ ├── StickyBox.md │ │ │ ├── SubMenuItem.md │ │ │ ├── Switch.md │ │ │ ├── TabItem.md │ │ │ ├── Table.md │ │ │ ├── TableOfContents.md │ │ │ ├── Tabs.md │ │ │ ├── Text.md │ │ │ ├── TextArea.md │ │ │ ├── TextBox.md │ │ │ ├── Theme.md │ │ │ ├── TimeInput.md │ │ │ ├── Timer.md │ │ │ ├── ToneChangerButton.md │ │ │ ├── ToneSwitch.md │ │ │ ├── Tooltip.md │ │ │ ├── Tree.md │ │ │ ├── VSplitter.md │ │ │ ├── VStack.md │ │ │ ├── xmlui-animations │ │ │ │ ├── _meta.json │ │ │ │ ├── _overview.md │ │ │ │ ├── Animation.md │ │ │ │ ├── FadeAnimation.md │ │ │ │ ├── FadeInAnimation.md │ │ │ │ ├── FadeOutAnimation.md │ │ │ │ ├── ScaleAnimation.md │ │ │ │ └── SlideInAnimation.md │ │ │ ├── xmlui-pdf │ │ │ │ ├── _meta.json │ │ │ │ ├── _overview.md │ │ │ │ └── Pdf.md │ │ │ ├── xmlui-spreadsheet │ │ │ │ ├── _meta.json │ │ │ │ ├── _overview.md │ │ │ │ └── Spreadsheet.md │ │ │ └── xmlui-website-blocks │ │ │ ├── _meta.json │ │ │ ├── _overview.md │ │ │ ├── Carousel.md │ │ │ ├── HelloMd.md │ │ │ ├── HeroSection.md │ │ │ └── ScrollToTop.md │ │ └── extensions │ │ ├── _meta.json │ │ ├── xmlui-animations │ │ │ ├── _meta.json │ │ │ ├── _overview.md │ │ │ ├── Animation.md │ │ │ ├── FadeAnimation.md │ │ │ ├── FadeInAnimation.md │ │ │ ├── FadeOutAnimation.md │ │ │ ├── ScaleAnimation.md │ │ │ └── SlideInAnimation.md │ │ └── xmlui-website-blocks │ │ ├── _meta.json │ │ ├── _overview.md │ │ ├── Carousel.md │ │ ├── HelloMd.md │ │ ├── HeroSection.md │ │ └── ScrollToTop.md │ ├── extensions.ts │ ├── index.html │ ├── index.ts │ ├── package.json │ ├── public │ │ ├── feed.rss │ │ ├── mockServiceWorker.js │ │ ├── pages │ │ │ ├── _meta.json │ │ │ ├── app-structure.md │ │ │ ├── build-editor-component.md │ │ │ ├── build-hello-world-component.md │ │ │ ├── components-intro.md │ │ │ ├── context-variables.md │ │ │ ├── forms.md │ │ │ ├── globals.md │ │ │ ├── glossary.md │ │ │ ├── helper-tags.md │ │ │ ├── hosted-deployment.md │ │ │ ├── howto │ │ │ │ ├── assign-a-complex-json-literal-to-a-component-variable.md │ │ │ │ ├── chain-a-refetch.md │ │ │ │ ├── debug-a-component.md │ │ │ │ ├── delay-a-datasource-until-another-datasource-is-ready.md │ │ │ │ ├── delegate-a-method.md │ │ │ │ ├── do-custom-form-validation.md │ │ │ │ ├── expose-a-method-from-a-component.md │ │ │ │ ├── filter-and-transform-data-from-an-api.md │ │ │ │ ├── group-items-in-list-by-a-property.md │ │ │ │ ├── handle-background-operations.md │ │ │ │ ├── hide-an-element-until-its-datasource-is-ready.md │ │ │ │ ├── make-a-set-of-equal-width-cards.md │ │ │ │ ├── make-a-table-responsive.md │ │ │ │ ├── modify-a-value-reported-in-a-column.md │ │ │ │ ├── paginate-a-list.md │ │ │ │ ├── pass-data-to-a-modal-dialog.md │ │ │ │ ├── react-to-button-click-not-keystrokes.md │ │ │ │ ├── set-the-initial-value-of-a-select-from-fetched-data.md │ │ │ │ ├── share-a-modaldialog-across-components.md │ │ │ │ ├── sync-selections-between-table-and-list-views.md │ │ │ │ ├── update-ui-optimistically.md │ │ │ │ ├── use-built-in-form-validation.md │ │ │ │ └── use-the-same-modaldialog-to-add-or-edit.md │ │ │ ├── howto.md │ │ │ ├── intro.md │ │ │ ├── layout.md │ │ │ ├── markup.md │ │ │ ├── mcp.md │ │ │ ├── modal-dialogs.md │ │ │ ├── news-and-reviews.md │ │ │ ├── reactive-intro.md │ │ │ ├── refactoring.md │ │ │ ├── routing-and-links.md │ │ │ ├── samples │ │ │ │ ├── color-palette.xmlui │ │ │ │ ├── color-values.xmlui │ │ │ │ ├── shadow-sizes.xmlui │ │ │ │ ├── spacing-sizes.xmlui │ │ │ │ ├── swatch.xmlui │ │ │ │ ├── theme-gallery-brief.xmlui │ │ │ │ └── theme-gallery.xmlui │ │ │ ├── scoping.md │ │ │ ├── scripting.md │ │ │ ├── styles-and-themes │ │ │ │ ├── common-units.md │ │ │ │ ├── layout-props.md │ │ │ │ ├── theme-variable-defaults.md │ │ │ │ ├── theme-variables.md │ │ │ │ └── themes.md │ │ │ ├── template-properties.md │ │ │ ├── test.md │ │ │ ├── tutorial-01.md │ │ │ ├── tutorial-02.md │ │ │ ├── tutorial-03.md │ │ │ ├── tutorial-04.md │ │ │ ├── tutorial-05.md │ │ │ ├── tutorial-06.md │ │ │ ├── tutorial-07.md │ │ │ ├── tutorial-08.md │ │ │ ├── tutorial-09.md │ │ │ ├── tutorial-10.md │ │ │ ├── tutorial-11.md │ │ │ ├── tutorial-12.md │ │ │ ├── universal-properties.md │ │ │ ├── user-defined-components.md │ │ │ ├── vscode.md │ │ │ ├── working-with-markdown.md │ │ │ ├── working-with-text.md │ │ │ ├── xmlui-animations │ │ │ │ ├── _meta.json │ │ │ │ ├── _overview.md │ │ │ │ ├── Animation.md │ │ │ │ ├── FadeAnimation.md │ │ │ │ ├── FadeInAnimation.md │ │ │ │ ├── FadeOutAnimation.md │ │ │ │ ├── ScaleAnimation.md │ │ │ │ └── SlideInAnimation.md │ │ │ ├── xmlui-charts │ │ │ │ ├── _meta.json │ │ │ │ ├── _overview.md │ │ │ │ ├── BarChart.md │ │ │ │ ├── DonutChart.md │ │ │ │ ├── LabelList.md │ │ │ │ ├── Legend.md │ │ │ │ ├── LineChart.md │ │ │ │ └── PieChart.md │ │ │ ├── xmlui-pdf │ │ │ │ ├── _meta.json │ │ │ │ ├── _overview.md │ │ │ │ └── Pdf.md │ │ │ └── xmlui-spreadsheet │ │ │ ├── _meta.json │ │ │ ├── _overview.md │ │ │ └── Spreadsheet.md │ │ ├── resources │ │ │ ├── devdocs │ │ │ │ ├── debug-proxy-object-2.png │ │ │ │ ├── debug-proxy-object.png │ │ │ │ ├── table_editor_01.png │ │ │ │ ├── table_editor_02.png │ │ │ │ ├── table_editor_03.png │ │ │ │ ├── table_editor_04.png │ │ │ │ ├── table_editor_05.png │ │ │ │ ├── table_editor_06.png │ │ │ │ ├── table_editor_07.png │ │ │ │ ├── table_editor_08.png │ │ │ │ ├── table_editor_09.png │ │ │ │ ├── table_editor_10.png │ │ │ │ ├── table_editor_11.png │ │ │ │ ├── table-editor-01.png │ │ │ │ ├── table-editor-02.png │ │ │ │ ├── table-editor-03.png │ │ │ │ ├── table-editor-04.png │ │ │ │ ├── table-editor-06.png │ │ │ │ ├── table-editor-07.png │ │ │ │ ├── table-editor-08.png │ │ │ │ ├── table-editor-09.png │ │ │ │ └── xmlui-rendering-of-tiptap-markdown.png │ │ │ ├── favicon.ico │ │ │ ├── files │ │ │ │ ├── clients.json │ │ │ │ ├── daily-revenue.json │ │ │ │ ├── dashboard-stats.json │ │ │ │ ├── demo.xmlui │ │ │ │ ├── demo.xmlui.xs │ │ │ │ ├── downloads │ │ │ │ │ └── downloads.json │ │ │ │ ├── for-download │ │ │ │ │ ├── index-with-api.html │ │ │ │ │ ├── index.html │ │ │ │ │ ├── mockApi.js │ │ │ │ │ ├── start-darwin.sh │ │ │ │ │ ├── start-linux.sh │ │ │ │ │ ├── start.bat │ │ │ │ │ └── xmlui │ │ │ │ │ └── xmlui-standalone.umd.js │ │ │ │ ├── getting-started │ │ │ │ │ ├── cl-tutorial-final.zip │ │ │ │ │ ├── cl-tutorial.zip │ │ │ │ │ ├── cl-tutorial2.zip │ │ │ │ │ ├── cl-tutorial3.zip │ │ │ │ │ ├── cl-tutorial4.zip │ │ │ │ │ ├── cl-tutorial5.zip │ │ │ │ │ ├── cl-tutorial6.zip │ │ │ │ │ ├── getting-started.zip │ │ │ │ │ ├── hello-xmlui.zip │ │ │ │ │ ├── xmlui-empty.zip │ │ │ │ │ └── xmlui-starter.zip │ │ │ │ ├── howto │ │ │ │ │ └── component-icons │ │ │ │ │ └── up-arrow.svg │ │ │ │ ├── invoices.json │ │ │ │ ├── monthly-status.json │ │ │ │ ├── news-and-reviews.json │ │ │ │ ├── products.json │ │ │ │ ├── releases.json │ │ │ │ ├── tutorials │ │ │ │ │ ├── datasource │ │ │ │ │ │ └── api.ts │ │ │ │ │ └── p2do │ │ │ │ │ ├── api.ts │ │ │ │ │ └── todo-logo.svg │ │ │ │ └── xmlui.json │ │ │ ├── github.svg │ │ │ ├── images │ │ │ │ ├── apiaction-tutorial │ │ │ │ │ ├── add-success.png │ │ │ │ │ ├── apiaction-param.png │ │ │ │ │ ├── change-completed.png │ │ │ │ │ ├── change-in-progress.png │ │ │ │ │ ├── confirm-delete.png │ │ │ │ │ ├── data-error.png │ │ │ │ │ ├── data-progress.png │ │ │ │ │ ├── data-success.png │ │ │ │ │ ├── display-1.png │ │ │ │ │ ├── item-deleted.png │ │ │ │ │ ├── item-updated.png │ │ │ │ │ ├── missing-api-key.png │ │ │ │ │ ├── new-item-added.png │ │ │ │ │ └── test-message.png │ │ │ │ ├── chat-api │ │ │ │ │ └── domain-model.svg │ │ │ │ ├── components │ │ │ │ │ ├── image │ │ │ │ │ │ └── breakfast.jpg │ │ │ │ │ ├── markdown │ │ │ │ │ │ └── colors.png │ │ │ │ │ └── modal │ │ │ │ │ ├── deep_link_dialog_1.jpg │ │ │ │ │ └── deep_link_dialog_2.jpg │ │ │ │ ├── create-apps │ │ │ │ │ ├── collapsed-vertical.png │ │ │ │ │ ├── using-forms-warning-dialog.png │ │ │ │ │ └── using-forms.png │ │ │ │ ├── datasource-tutorial │ │ │ │ │ ├── data-with-header.png │ │ │ │ │ ├── filtered-data.png │ │ │ │ │ ├── filtered-items.png │ │ │ │ │ ├── initial-page-items.png │ │ │ │ │ ├── list-items.png │ │ │ │ │ ├── next-page-items.png │ │ │ │ │ ├── no-data.png │ │ │ │ │ ├── pagination-1.jpg │ │ │ │ │ ├── pagination-1.png │ │ │ │ │ ├── polling-1.png │ │ │ │ │ ├── refetch-data.png │ │ │ │ │ ├── slow-loading.png │ │ │ │ │ ├── test-message.png │ │ │ │ │ ├── Thumbs.db │ │ │ │ │ ├── unconventional-data.png │ │ │ │ │ └── unfiltered-items.png │ │ │ │ ├── flower.jpg │ │ │ │ ├── get-started │ │ │ │ │ ├── add-new-contact.png │ │ │ │ │ ├── app-modified.png │ │ │ │ │ ├── app-start.png │ │ │ │ │ ├── app-with-boxes.png │ │ │ │ │ ├── app-with-toast.png │ │ │ │ │ ├── boilerplate-structure.png │ │ │ │ │ ├── cl-initial.png │ │ │ │ │ ├── cl-start.png │ │ │ │ │ ├── contact-counts.png │ │ │ │ │ ├── contact-dialog-title.png │ │ │ │ │ ├── contact-dialog.png │ │ │ │ │ ├── contact-menus.png │ │ │ │ │ ├── contact-predicates.png │ │ │ │ │ ├── context-menu.png │ │ │ │ │ ├── dashboard-numbers.png │ │ │ │ │ ├── default-contact-list.png │ │ │ │ │ ├── delete-contact.png │ │ │ │ │ ├── delete-task.png │ │ │ │ │ ├── detailed-template.png │ │ │ │ │ ├── edit-contact-details.png │ │ │ │ │ ├── edited-contact-saved.png │ │ │ │ │ ├── empty-sections.png │ │ │ │ │ ├── filter-completed.png │ │ │ │ │ ├── fullwidth-desktop.png │ │ │ │ │ ├── fullwidth-mobile.png │ │ │ │ │ ├── initial-table.png │ │ │ │ │ ├── items-and-badges.png │ │ │ │ │ ├── loading-message.png │ │ │ │ │ ├── new-contact-button.png │ │ │ │ │ ├── new-contact-saved.png │ │ │ │ │ ├── no-empty-sections.png │ │ │ │ │ ├── personal-todo-initial.png │ │ │ │ │ ├── piechart.png │ │ │ │ │ ├── review-today.png │ │ │ │ │ ├── rudimentary-dashboard.png │ │ │ │ │ ├── section-collapsed.png │ │ │ │ │ ├── sectioned-items.png │ │ │ │ │ ├── sections-ordered.png │ │ │ │ │ ├── spacex-list-with-links.png │ │ │ │ │ ├── spacex-list.png │ │ │ │ │ ├── start-personal-todo-1.png │ │ │ │ │ ├── submit-new-contact.png │ │ │ │ │ ├── submit-new-task.png │ │ │ │ │ ├── syntax-highlighting.png │ │ │ │ │ ├── table-with-badge.png │ │ │ │ │ ├── template-with-card.png │ │ │ │ │ ├── test-emulated-api.png │ │ │ │ │ ├── Thumbs.db │ │ │ │ │ ├── todo-logo.png │ │ │ │ │ └── xmlui-tools.png │ │ │ │ ├── HelloApp.png │ │ │ │ ├── HelloApp2.png │ │ │ │ ├── logos │ │ │ │ │ ├── xmlui1.svg │ │ │ │ │ ├── xmlui2.svg │ │ │ │ │ ├── xmlui3.svg │ │ │ │ │ ├── xmlui4.svg │ │ │ │ │ ├── xmlui5.svg │ │ │ │ │ ├── xmlui6.svg │ │ │ │ │ └── xmlui7.svg │ │ │ │ ├── pdf │ │ │ │ │ └── dummy-pdf.jpg │ │ │ │ ├── rendering-engine │ │ │ │ │ ├── AppEngine-flow.svg │ │ │ │ │ ├── Component.svg │ │ │ │ │ ├── CompoundComponent.svg │ │ │ │ │ ├── RootComponent.svg │ │ │ │ │ └── tree-with-containers.svg │ │ │ │ ├── reviewers-guide │ │ │ │ │ ├── AppEngine-flow.svg │ │ │ │ │ └── incbutton-in-action.png │ │ │ │ ├── tools │ │ │ │ │ └── boilerplate-structure.png │ │ │ │ ├── try.svg │ │ │ │ ├── tutorial │ │ │ │ │ ├── app-chat-history.png │ │ │ │ │ ├── app-content-placeholder.png │ │ │ │ │ ├── app-header-and-content.png │ │ │ │ │ ├── app-links-channel-selected.png │ │ │ │ │ ├── app-links-click.png │ │ │ │ │ ├── app-navigation.png │ │ │ │ │ ├── finished-ex01.png │ │ │ │ │ ├── finished-ex02.png │ │ │ │ │ ├── hello.png │ │ │ │ │ ├── splash-screen-advanced.png │ │ │ │ │ ├── splash-screen-after-click.png │ │ │ │ │ ├── splash-screen-centered.png │ │ │ │ │ ├── splash-screen-events.png │ │ │ │ │ ├── splash-screen-expression.png │ │ │ │ │ ├── splash-screen-reuse-after.png │ │ │ │ │ ├── splash-screen-reuse-before.png │ │ │ │ │ └── splash-screen.png │ │ │ │ └── tutorial-01.png │ │ │ ├── llms.txt │ │ │ ├── logo-dark.svg │ │ │ ├── logo.svg │ │ │ ├── pg-popout.svg │ │ │ └── xmlui-logo.svg │ │ ├── serve.json │ │ └── web.config │ ├── scripts │ │ ├── download-latest-xmlui.js │ │ ├── generate-rss.js │ │ ├── get-releases.js │ │ └── utils.js │ ├── src │ │ ├── components │ │ │ ├── BlogOverview.xmlui │ │ │ ├── BlogPage.xmlui │ │ │ ├── Boxes.xmlui │ │ │ ├── Breadcrumb.xmlui │ │ │ ├── ChangeLog.xmlui │ │ │ ├── ColorPalette.xmlui │ │ │ ├── DocumentLinks.xmlui │ │ │ ├── DocumentPage.xmlui │ │ │ ├── DocumentPageNoTOC.xmlui │ │ │ ├── Icons.xmlui │ │ │ ├── IncButton.xmlui │ │ │ ├── IncButton2.xmlui │ │ │ ├── NameValue.xmlui │ │ │ ├── PageNotFound.xmlui │ │ │ ├── PaletteItem.xmlui │ │ │ ├── Palettes.xmlui │ │ │ ├── SectionHeader.xmlui │ │ │ ├── TBD.xmlui │ │ │ ├── Test.xmlui │ │ │ ├── ThemesIntro.xmlui │ │ │ ├── ThousandThemes.xmlui │ │ │ ├── TubeStops.xmlui │ │ │ ├── TubeStops.xmlui.xs │ │ │ └── TwoColumnCode.xmlui │ │ ├── config.ts │ │ ├── Main.xmlui │ │ └── themes │ │ ├── docs-theme.ts │ │ ├── earthtone.ts │ │ ├── xmlui-gray-on-default.ts │ │ ├── xmlui-green-on-default.ts │ │ └── xmlui-orange-on-default.ts │ └── tsconfig.json ├── LICENSE ├── package-lock.json ├── package.json ├── packages │ ├── xmlui-animations │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── demo │ │ │ └── Main.xmlui │ │ ├── index.html │ │ ├── index.ts │ │ ├── meta │ │ │ └── componentsMetadata.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── Animation.tsx │ │ │ ├── AnimationNative.tsx │ │ │ ├── FadeAnimation.tsx │ │ │ ├── FadeInAnimation.tsx │ │ │ ├── FadeOutAnimation.tsx │ │ │ ├── index.tsx │ │ │ ├── ScaleAnimation.tsx │ │ │ └── SlideInAnimation.tsx │ │ └── tsconfig.json │ ├── xmlui-devtools │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── demo │ │ │ └── Main.xmlui │ │ ├── index.html │ │ ├── index.ts │ │ ├── meta │ │ │ └── componentsMetadata.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── devtools │ │ │ │ ├── DevTools.tsx │ │ │ │ ├── DevToolsNative.module.scss │ │ │ │ ├── DevToolsNative.tsx │ │ │ │ ├── ModalDialog.module.scss │ │ │ │ ├── ModalDialog.tsx │ │ │ │ ├── ModalVisibilityContext.tsx │ │ │ │ ├── Tooltip.module.scss │ │ │ │ ├── Tooltip.tsx │ │ │ │ └── utils.ts │ │ │ ├── editor │ │ │ │ └── Editor.tsx │ │ │ └── index.tsx │ │ ├── tsconfig.json │ │ └── vite.config-overrides.ts │ ├── xmlui-hello-world │ │ ├── .gitignore │ │ ├── index.ts │ │ ├── meta │ │ │ └── componentsMetadata.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── HelloWorld.module.scss │ │ │ ├── HelloWorld.tsx │ │ │ ├── HelloWorldNative.tsx │ │ │ └── index.tsx │ │ └── tsconfig.json │ ├── xmlui-os-frames │ │ ├── .gitignore │ │ ├── demo │ │ │ └── Main.xmlui │ │ ├── index.html │ │ ├── index.ts │ │ ├── meta │ │ │ └── componentsMetadata.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── index.tsx │ │ │ ├── IPhoneFrame.module.scss │ │ │ ├── IPhoneFrame.tsx │ │ │ ├── MacOSAppFrame.module.scss │ │ │ ├── MacOSAppFrame.tsx │ │ │ ├── WindowsAppFrame.module.scss │ │ │ └── WindowsAppFrame.tsx │ │ └── tsconfig.json │ ├── xmlui-pdf │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── demo │ │ │ ├── components │ │ │ │ └── Pdf.xmlui │ │ │ └── Main.xmlui │ │ ├── index.html │ │ ├── index.ts │ │ ├── meta │ │ │ └── componentsMetadata.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── index.tsx │ │ │ ├── LazyPdfNative.tsx │ │ │ ├── Pdf.module.scss │ │ │ └── Pdf.tsx │ │ └── tsconfig.json │ ├── xmlui-playground │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── demo │ │ │ └── Main.xmlui │ │ ├── index.html │ │ ├── index.ts │ │ ├── meta │ │ │ └── componentsMetadata.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── hooks │ │ │ │ ├── usePlayground.ts │ │ │ │ └── useToast.ts │ │ │ ├── index.tsx │ │ │ ├── playground │ │ │ │ ├── Box.module.scss │ │ │ │ ├── Box.tsx │ │ │ │ ├── CodeSelector.tsx │ │ │ │ ├── ConfirmationDialog.module.scss │ │ │ │ ├── ConfirmationDialog.tsx │ │ │ │ ├── Editor.tsx │ │ │ │ ├── Header.module.scss │ │ │ │ ├── Header.tsx │ │ │ │ ├── Playground.tsx │ │ │ │ ├── PlaygroundContent.module.scss │ │ │ │ ├── PlaygroundContent.tsx │ │ │ │ ├── PlaygroundNative.module.scss │ │ │ │ ├── PlaygroundNative.tsx │ │ │ │ ├── Preview.module.scss │ │ │ │ ├── Preview.tsx │ │ │ │ ├── Select.module.scss │ │ │ │ ├── StandalonePlayground.tsx │ │ │ │ ├── StandalonePlaygroundNative.module.scss │ │ │ │ ├── StandalonePlaygroundNative.tsx │ │ │ │ ├── ThemeSwitcher.module.scss │ │ │ │ ├── ThemeSwitcher.tsx │ │ │ │ ├── ToneSwitcher.tsx │ │ │ │ ├── Tooltip.module.scss │ │ │ │ ├── Tooltip.tsx │ │ │ │ └── utils.ts │ │ │ ├── providers │ │ │ │ ├── Toast.module.scss │ │ │ │ └── ToastProvider.tsx │ │ │ ├── state │ │ │ │ └── store.ts │ │ │ ├── themes │ │ │ │ └── theme.ts │ │ │ └── utils │ │ │ └── helpers.ts │ │ └── tsconfig.json │ ├── xmlui-search │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── demo │ │ │ └── Main.xmlui │ │ ├── index.html │ │ ├── index.ts │ │ ├── meta │ │ │ └── componentsMetadata.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── index.tsx │ │ │ ├── Search.module.scss │ │ │ └── Search.tsx │ │ └── tsconfig.json │ ├── xmlui-spreadsheet │ │ ├── .gitignore │ │ ├── demo │ │ │ └── Main.xmlui │ │ ├── index.html │ │ ├── index.ts │ │ ├── meta │ │ │ └── componentsMetadata.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── index.tsx │ │ │ ├── Spreadsheet.tsx │ │ │ └── SpreadsheetNative.tsx │ │ └── tsconfig.json │ └── xmlui-website-blocks │ ├── .gitignore │ ├── CHANGELOG.md │ ├── demo │ │ ├── components │ │ │ ├── HeroBackgroundBreakoutPage.xmlui │ │ │ ├── HeroBackgroundsPage.xmlui │ │ │ ├── HeroContentsPage.xmlui │ │ │ ├── HeroTextAlignPage.xmlui │ │ │ ├── HeroTextPage.xmlui │ │ │ └── HeroTonesPage.xmlui │ │ ├── Main.xmlui │ │ └── themes │ │ └── default.ts │ ├── index.html │ ├── index.ts │ ├── meta │ │ └── componentsMetadata.ts │ ├── package.json │ ├── public │ │ └── resources │ │ ├── building.jpg │ │ └── xmlui-logo.svg │ ├── src │ │ ├── Carousel │ │ │ ├── Carousel.module.scss │ │ │ ├── Carousel.tsx │ │ │ ├── CarouselContext.tsx │ │ │ └── CarouselNative.tsx │ │ ├── FancyButton │ │ │ ├── FancyButton.module.scss │ │ │ ├── FancyButton.tsx │ │ │ └── FancyButton.xmlui │ │ ├── Hello │ │ │ ├── Hello.tsx │ │ │ ├── Hello.xmlui │ │ │ └── Hello.xmlui.xs │ │ ├── HeroSection │ │ │ ├── HeroSection.module.scss │ │ │ ├── HeroSection.tsx │ │ │ └── HeroSectionNative.tsx │ │ ├── index.tsx │ │ ├── ScrollToTop │ │ │ ├── ScrollToTop.module.scss │ │ │ ├── ScrollToTop.tsx │ │ │ └── ScrollToTopNative.tsx │ │ └── vite-env.d.ts │ └── tsconfig.json ├── README.md ├── tools │ ├── codefence │ │ └── xmlui-code-fence-docs.md │ ├── create-app │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── create-app.ts │ │ ├── helpers │ │ │ ├── copy.ts │ │ │ ├── get-pkg-manager.ts │ │ │ ├── git.ts │ │ │ ├── install.ts │ │ │ ├── is-folder-empty.ts │ │ │ ├── is-writeable.ts │ │ │ ├── make-dir.ts │ │ │ └── validate-pkg.ts │ │ ├── index.ts │ │ ├── package.json │ │ ├── templates │ │ │ ├── default │ │ │ │ └── ts │ │ │ │ ├── gitignore │ │ │ │ ├── index.html │ │ │ │ ├── index.ts │ │ │ │ ├── public │ │ │ │ │ ├── mockServiceWorker.js │ │ │ │ │ ├── resources │ │ │ │ │ │ ├── favicon.ico │ │ │ │ │ │ └── xmlui-logo.svg │ │ │ │ │ └── serve.json │ │ │ │ └── src │ │ │ │ ├── components │ │ │ │ │ ├── ApiAware.xmlui │ │ │ │ │ ├── Home.xmlui │ │ │ │ │ ├── IncButton.xmlui │ │ │ │ │ └── PagePanel.xmlui │ │ │ │ ├── config.ts │ │ │ │ └── Main.xmlui │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── tsconfig.json │ ├── create-xmlui-hello-world │ │ ├── index.js │ │ └── package.json │ └── vscode │ ├── .gitignore │ ├── .vscode │ │ ├── launch.json │ │ └── tasks.json │ ├── .vscodeignore │ ├── build.sh │ ├── CHANGELOG.md │ ├── esbuild.js │ ├── eslint.config.mjs │ ├── formatter-docs.md │ ├── generate-test-sample.sh │ ├── LICENSE.md │ ├── package-lock.json │ ├── package.json │ ├── README.md │ ├── resources │ │ ├── xmlui-logo.png │ │ └── xmlui-markup-syntax-highlighting.png │ ├── src │ │ ├── extension.ts │ │ └── server.ts │ ├── syntaxes │ │ └── xmlui.tmLanguage.json │ ├── test-samples │ │ └── sample.xmlui │ ├── tsconfig.json │ └── tsconfig.tsbuildinfo ├── turbo.json └── xmlui ├── .gitignore ├── bin │ ├── bootstrap.js │ ├── build-lib.ts │ ├── build.ts │ ├── index.ts │ ├── preview.ts │ ├── start.ts │ ├── vite-xmlui-plugin.ts │ └── viteConfig.ts ├── CHANGELOG.md ├── conventions │ ├── component-qa-checklist.md │ ├── copilot-conventions.md │ ├── create-xmlui-components.md │ ├── mermaid.md │ ├── testing-conventions.md │ └── xmlui-in-a-nutshell.md ├── dev-docs │ ├── accessibility.md │ ├── build-system.md │ ├── build-xmlui.md │ ├── component-behaviors.md │ ├── containers.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 │ ├── state-management.md │ └── xmlui-repo.md ├── package.json ├── playwright.config.ts ├── scripts │ ├── coverage-only.js │ ├── e2e-test-summary.js │ ├── generate-docs │ │ ├── build-downloads-map.mjs │ │ ├── build-pages-map.mjs │ │ ├── components-config.json │ │ ├── configuration-management.mjs │ │ ├── constants.mjs │ │ ├── create-theme-files.mjs │ │ ├── DocsGenerator.mjs │ │ ├── error-handling.mjs │ │ ├── extensions-config.json │ │ ├── folders.mjs │ │ ├── generate-summary-files.mjs │ │ ├── get-docs.mjs │ │ ├── input-handler.mjs │ │ ├── logger.mjs │ │ ├── logging-standards.mjs │ │ ├── MetadataProcessor.mjs │ │ ├── pattern-utilities.mjs │ │ └── utils.mjs │ ├── get-langserver-metadata.mjs │ ├── inline-links.mjs │ └── README-e2e-summary.md ├── src │ ├── abstractions │ │ ├── _conventions.md │ │ ├── ActionDefs.ts │ │ ├── AppContextDefs.ts │ │ ├── ComponentDefs.ts │ │ ├── ContainerDefs.ts │ │ ├── ExtensionDefs.ts │ │ ├── FunctionDefs.ts │ │ ├── RendererDefs.ts │ │ ├── scripting │ │ │ ├── BlockScope.ts │ │ │ ├── Compilation.ts │ │ │ ├── LogicalThread.ts │ │ │ ├── LoopScope.ts │ │ │ ├── modules.ts │ │ │ ├── ScriptParserError.ts │ │ │ ├── Token.ts │ │ │ ├── TryScope.ts │ │ │ └── TryScopeExp.ts │ │ └── ThemingDefs.ts │ ├── components │ │ ├── _conventions.md │ │ ├── abstractions.ts │ │ ├── Accordion │ │ │ ├── Accordion.md │ │ │ ├── Accordion.module.scss │ │ │ ├── Accordion.spec.ts │ │ │ ├── Accordion.tsx │ │ │ ├── AccordionContext.tsx │ │ │ ├── AccordionItem.tsx │ │ │ ├── AccordionItemNative.tsx │ │ │ └── AccordionNative.tsx │ │ ├── Animation │ │ │ └── AnimationNative.tsx │ │ ├── APICall │ │ │ ├── APICall.md │ │ │ ├── APICall.spec.ts │ │ │ ├── APICall.tsx │ │ │ └── APICallNative.tsx │ │ ├── App │ │ │ ├── App.md │ │ │ ├── App.module.scss │ │ │ ├── App.spec.ts │ │ │ ├── App.tsx │ │ │ ├── AppLayoutContext.ts │ │ │ ├── AppNative.tsx │ │ │ ├── AppStateContext.ts │ │ │ ├── doc-resources │ │ │ │ ├── condensed-sticky.xmlui │ │ │ │ ├── condensed.xmlui │ │ │ │ ├── horizontal-sticky.xmlui │ │ │ │ ├── horizontal.xmlui │ │ │ │ ├── vertical-full-header.xmlui │ │ │ │ ├── vertical-sticky.xmlui │ │ │ │ └── vertical.xmlui │ │ │ ├── IndexerContext.ts │ │ │ ├── LinkInfoContext.ts │ │ │ ├── SearchContext.tsx │ │ │ ├── Sheet.module.scss │ │ │ └── Sheet.tsx │ │ ├── AppHeader │ │ │ ├── AppHeader.md │ │ │ ├── AppHeader.module.scss │ │ │ ├── AppHeader.spec.ts │ │ │ ├── AppHeader.tsx │ │ │ └── AppHeaderNative.tsx │ │ ├── AppState │ │ │ ├── AppState.md │ │ │ ├── AppState.spec.ts │ │ │ ├── AppState.tsx │ │ │ └── AppStateNative.tsx │ │ ├── AutoComplete │ │ │ ├── AutoComplete.md │ │ │ ├── AutoComplete.module.scss │ │ │ ├── AutoComplete.spec.ts │ │ │ ├── AutoComplete.tsx │ │ │ ├── AutoCompleteContext.tsx │ │ │ └── AutoCompleteNative.tsx │ │ ├── Avatar │ │ │ ├── Avatar.md │ │ │ ├── Avatar.module.scss │ │ │ ├── Avatar.spec.ts │ │ │ ├── Avatar.tsx │ │ │ └── AvatarNative.tsx │ │ ├── Backdrop │ │ │ ├── Backdrop.md │ │ │ ├── Backdrop.module.scss │ │ │ ├── Backdrop.spec.ts │ │ │ ├── Backdrop.tsx │ │ │ └── BackdropNative.tsx │ │ ├── Badge │ │ │ ├── Badge.md │ │ │ ├── Badge.module.scss │ │ │ ├── Badge.spec.ts │ │ │ ├── Badge.tsx │ │ │ └── BadgeNative.tsx │ │ ├── Bookmark │ │ │ ├── Bookmark.md │ │ │ ├── Bookmark.module.scss │ │ │ ├── Bookmark.spec.ts │ │ │ ├── Bookmark.tsx │ │ │ └── BookmarkNative.tsx │ │ ├── Breakout │ │ │ ├── Breakout.module.scss │ │ │ ├── Breakout.spec.ts │ │ │ ├── Breakout.tsx │ │ │ └── BreakoutNative.tsx │ │ ├── Button │ │ │ ├── Button-style.spec.ts │ │ │ ├── Button.md │ │ │ ├── Button.module.scss │ │ │ ├── Button.spec.ts │ │ │ ├── Button.tsx │ │ │ └── ButtonNative.tsx │ │ ├── Card │ │ │ ├── Card.md │ │ │ ├── Card.module.scss │ │ │ ├── Card.spec.ts │ │ │ ├── Card.tsx │ │ │ └── CardNative.tsx │ │ ├── Carousel │ │ │ ├── Carousel.md │ │ │ ├── Carousel.module.scss │ │ │ ├── Carousel.spec.ts │ │ │ ├── Carousel.tsx │ │ │ ├── CarouselContext.tsx │ │ │ ├── CarouselItem.tsx │ │ │ ├── CarouselItemNative.tsx │ │ │ └── CarouselNative.tsx │ │ ├── ChangeListener │ │ │ ├── ChangeListener.md │ │ │ ├── ChangeListener.spec.ts │ │ │ ├── ChangeListener.tsx │ │ │ └── ChangeListenerNative.tsx │ │ ├── chart-color-schemes.ts │ │ ├── Charts │ │ │ ├── AreaChart │ │ │ │ ├── AreaChart.md │ │ │ │ ├── AreaChart.spec.ts │ │ │ │ ├── AreaChart.tsx │ │ │ │ └── AreaChartNative.tsx │ │ │ ├── BarChart │ │ │ │ ├── BarChart.md │ │ │ │ ├── BarChart.module.scss │ │ │ │ ├── BarChart.spec.ts │ │ │ │ ├── BarChart.tsx │ │ │ │ └── BarChartNative.tsx │ │ │ ├── DonutChart │ │ │ │ ├── DonutChart.spec.ts │ │ │ │ └── DonutChart.tsx │ │ │ ├── LabelList │ │ │ │ ├── LabelList.spec.ts │ │ │ │ ├── LabelList.tsx │ │ │ │ ├── LabelListNative.module.scss │ │ │ │ └── LabelListNative.tsx │ │ │ ├── Legend │ │ │ │ ├── Legend.spec.ts │ │ │ │ ├── Legend.tsx │ │ │ │ └── LegendNative.tsx │ │ │ ├── LineChart │ │ │ │ ├── LineChart.md │ │ │ │ ├── LineChart.module.scss │ │ │ │ ├── LineChart.spec.ts │ │ │ │ ├── LineChart.tsx │ │ │ │ └── LineChartNative.tsx │ │ │ ├── PieChart │ │ │ │ ├── PieChart.md │ │ │ │ ├── PieChart.spec.ts │ │ │ │ ├── PieChart.tsx │ │ │ │ ├── PieChartNative.module.scss │ │ │ │ └── PieChartNative.tsx │ │ │ ├── RadarChart │ │ │ │ ├── RadarChart.md │ │ │ │ ├── RadarChart.spec.ts │ │ │ │ ├── RadarChart.tsx │ │ │ │ └── RadarChartNative.tsx │ │ │ ├── Tooltip │ │ │ │ ├── TooltipContent.module.scss │ │ │ │ ├── TooltipContent.spec.ts │ │ │ │ └── TooltipContent.tsx │ │ │ └── utils │ │ │ ├── abstractions.ts │ │ │ └── ChartProvider.tsx │ │ ├── Checkbox │ │ │ ├── Checkbox.md │ │ │ ├── Checkbox.spec.ts │ │ │ └── Checkbox.tsx │ │ ├── CodeBlock │ │ │ ├── CodeBlock.module.scss │ │ │ ├── CodeBlock.spec.ts │ │ │ ├── CodeBlock.tsx │ │ │ ├── CodeBlockNative.tsx │ │ │ └── highlight-code.ts │ │ ├── collectedComponentMetadata.ts │ │ ├── ColorPicker │ │ │ ├── ColorPicker.md │ │ │ ├── ColorPicker.module.scss │ │ │ ├── ColorPicker.spec.ts │ │ │ ├── ColorPicker.tsx │ │ │ └── ColorPickerNative.tsx │ │ ├── Column │ │ │ ├── Column.md │ │ │ ├── Column.tsx │ │ │ ├── ColumnNative.tsx │ │ │ ├── doc-resources │ │ │ │ └── list-component-data.js │ │ │ └── TableContext.tsx │ │ ├── component-utils.ts │ │ ├── ComponentProvider.tsx │ │ ├── ComponentRegistryContext.tsx │ │ ├── container-helpers.tsx │ │ ├── ContentSeparator │ │ │ ├── ContentSeparator.md │ │ │ ├── ContentSeparator.module.scss │ │ │ ├── ContentSeparator.spec.ts │ │ │ ├── ContentSeparator.tsx │ │ │ └── ContentSeparatorNative.tsx │ │ ├── DataSource │ │ │ ├── DataSource.md │ │ │ └── DataSource.tsx │ │ ├── DateInput │ │ │ ├── DateInput.md │ │ │ ├── DateInput.module.scss │ │ │ ├── DateInput.spec.ts │ │ │ ├── DateInput.tsx │ │ │ └── DateInputNative.tsx │ │ ├── DatePicker │ │ │ ├── DatePicker.md │ │ │ ├── DatePicker.module.scss │ │ │ ├── DatePicker.spec.ts │ │ │ ├── DatePicker.tsx │ │ │ └── DatePickerNative.tsx │ │ ├── DropdownMenu │ │ │ ├── DropdownMenu.md │ │ │ ├── DropdownMenu.module.scss │ │ │ ├── DropdownMenu.spec.ts │ │ │ ├── DropdownMenu.tsx │ │ │ ├── DropdownMenuNative.tsx │ │ │ ├── MenuItem.md │ │ │ └── SubMenuItem.md │ │ ├── EmojiSelector │ │ │ ├── EmojiSelector.md │ │ │ ├── EmojiSelector.spec.ts │ │ │ ├── EmojiSelector.tsx │ │ │ └── EmojiSelectorNative.tsx │ │ ├── ExpandableItem │ │ │ ├── ExpandableItem.module.scss │ │ │ ├── ExpandableItem.spec.ts │ │ │ ├── ExpandableItem.tsx │ │ │ └── ExpandableItemNative.tsx │ │ ├── FileInput │ │ │ ├── FileInput.md │ │ │ ├── FileInput.module.scss │ │ │ ├── FileInput.spec.ts │ │ │ ├── FileInput.tsx │ │ │ └── FileInputNative.tsx │ │ ├── FileUploadDropZone │ │ │ ├── FileUploadDropZone.md │ │ │ ├── FileUploadDropZone.module.scss │ │ │ ├── FileUploadDropZone.spec.ts │ │ │ ├── FileUploadDropZone.tsx │ │ │ └── FileUploadDropZoneNative.tsx │ │ ├── FlowLayout │ │ │ ├── FlowLayout.md │ │ │ ├── FlowLayout.module.scss │ │ │ ├── FlowLayout.spec.ts │ │ │ ├── FlowLayout.spec.ts-snapshots │ │ │ │ └── Edge-cases-boxShadow-is-not-clipped-1-non-smoke-darwin.png │ │ │ ├── FlowLayout.tsx │ │ │ └── FlowLayoutNative.tsx │ │ ├── Footer │ │ │ ├── Footer.md │ │ │ ├── Footer.module.scss │ │ │ ├── Footer.spec.ts │ │ │ ├── Footer.tsx │ │ │ └── FooterNative.tsx │ │ ├── Form │ │ │ ├── Form.md │ │ │ ├── Form.module.scss │ │ │ ├── Form.spec.ts │ │ │ ├── Form.tsx │ │ │ ├── formActions.ts │ │ │ ├── FormContext.ts │ │ │ └── FormNative.tsx │ │ ├── FormItem │ │ │ ├── FormItem.md │ │ │ ├── FormItem.module.scss │ │ │ ├── FormItem.spec.ts │ │ │ ├── FormItem.tsx │ │ │ ├── FormItemNative.tsx │ │ │ ├── HelperText.module.scss │ │ │ ├── HelperText.tsx │ │ │ ├── ItemWithLabel.tsx │ │ │ └── Validations.ts │ │ ├── FormSection │ │ │ ├── FormSection.md │ │ │ ├── FormSection.ts │ │ │ └── FormSection.xmlui │ │ ├── Fragment │ │ │ ├── Fragment.spec.ts │ │ │ └── Fragment.tsx │ │ ├── Heading │ │ │ ├── abstractions.ts │ │ │ ├── H1.md │ │ │ ├── H1.spec.ts │ │ │ ├── H2.md │ │ │ ├── H2.spec.ts │ │ │ ├── H3.md │ │ │ ├── H3.spec.ts │ │ │ ├── H4.md │ │ │ ├── H4.spec.ts │ │ │ ├── H5.md │ │ │ ├── H5.spec.ts │ │ │ ├── H6.md │ │ │ ├── H6.spec.ts │ │ │ ├── Heading.md │ │ │ ├── Heading.module.scss │ │ │ ├── Heading.spec.ts │ │ │ ├── Heading.tsx │ │ │ └── HeadingNative.tsx │ │ ├── HoverCard │ │ │ ├── HoverCard.tsx │ │ │ └── HovercardNative.tsx │ │ ├── HtmlTags │ │ │ ├── HtmlTags.module.scss │ │ │ ├── HtmlTags.spec.ts │ │ │ └── HtmlTags.tsx │ │ ├── Icon │ │ │ ├── AdmonitionDanger.tsx │ │ │ ├── AdmonitionInfo.tsx │ │ │ ├── AdmonitionNote.tsx │ │ │ ├── AdmonitionTip.tsx │ │ │ ├── AdmonitionWarning.tsx │ │ │ ├── ApiIcon.tsx │ │ │ ├── ArrowDropDown.module.scss │ │ │ ├── ArrowDropDown.tsx │ │ │ ├── ArrowDropUp.module.scss │ │ │ ├── ArrowDropUp.tsx │ │ │ ├── ArrowLeft.module.scss │ │ │ ├── ArrowLeft.tsx │ │ │ ├── ArrowRight.module.scss │ │ │ ├── ArrowRight.tsx │ │ │ ├── Attach.tsx │ │ │ ├── Binding.module.scss │ │ │ ├── Binding.tsx │ │ │ ├── BoardIcon.tsx │ │ │ ├── BoxIcon.tsx │ │ │ ├── CheckIcon.tsx │ │ │ ├── ChevronDownIcon.tsx │ │ │ ├── ChevronLeft.tsx │ │ │ ├── ChevronRight.tsx │ │ │ ├── ChevronUpIcon.tsx │ │ │ ├── CodeFileIcon.tsx │ │ │ ├── CodeSandbox.tsx │ │ │ ├── CompactListIcon.tsx │ │ │ ├── ContentCopyIcon.tsx │ │ │ ├── DarkToLightIcon.tsx │ │ │ ├── DatabaseIcon.module.scss │ │ │ ├── DatabaseIcon.tsx │ │ │ ├── DocFileIcon.tsx │ │ │ ├── DocIcon.tsx │ │ │ ├── DotMenuHorizontalIcon.tsx │ │ │ ├── DotMenuIcon.tsx │ │ │ ├── EmailIcon.tsx │ │ │ ├── EmptyFolderIcon.tsx │ │ │ ├── ErrorIcon.tsx │ │ │ ├── ExpressionIcon.tsx │ │ │ ├── FillPlusCricleIcon.tsx │ │ │ ├── FilterIcon.tsx │ │ │ ├── FolderIcon.tsx │ │ │ ├── GlobeIcon.tsx │ │ │ ├── HomeIcon.tsx │ │ │ ├── HyperLinkIcon.tsx │ │ │ ├── Icon.md │ │ │ ├── Icon.module.scss │ │ │ ├── Icon.spec.ts │ │ │ ├── Icon.tsx │ │ │ ├── IconNative.tsx │ │ │ ├── ImageFileIcon.tsx │ │ │ ├── Inspect.tsx │ │ │ ├── LightToDark.tsx │ │ │ ├── LinkIcon.tsx │ │ │ ├── ListIcon.tsx │ │ │ ├── LooseListIcon.tsx │ │ │ ├── MoonIcon.tsx │ │ │ ├── MoreOptionsIcon.tsx │ │ │ ├── NoSortIcon.tsx │ │ │ ├── PDFIcon.tsx │ │ │ ├── PenIcon.tsx │ │ │ ├── PhoneIcon.tsx │ │ │ ├── PhotoIcon.tsx │ │ │ ├── PlusIcon.tsx │ │ │ ├── SearchIcon.tsx │ │ │ ├── ShareIcon.tsx │ │ │ ├── SortAscendingIcon.tsx │ │ │ ├── SortDescendingIcon.tsx │ │ │ ├── StarsIcon.tsx │ │ │ ├── SunIcon.tsx │ │ │ ├── svg │ │ │ │ ├── admonition_danger.svg │ │ │ │ ├── admonition_info.svg │ │ │ │ ├── admonition_note.svg │ │ │ │ ├── admonition_tip.svg │ │ │ │ ├── admonition_warning.svg │ │ │ │ ├── api.svg │ │ │ │ ├── arrow-dropdown.svg │ │ │ │ ├── arrow-left.svg │ │ │ │ ├── arrow-right.svg │ │ │ │ ├── arrow-up.svg │ │ │ │ ├── attach.svg │ │ │ │ ├── binding.svg │ │ │ │ ├── box.svg │ │ │ │ ├── bulb.svg │ │ │ │ ├── code-file.svg │ │ │ │ ├── code-sandbox.svg │ │ │ │ ├── dark_to_light.svg │ │ │ │ ├── database.svg │ │ │ │ ├── doc.svg │ │ │ │ ├── empty-folder.svg │ │ │ │ ├── expression.svg │ │ │ │ ├── eye-closed.svg │ │ │ │ ├── eye-dark.svg │ │ │ │ ├── eye.svg │ │ │ │ ├── file-text.svg │ │ │ │ ├── filter.svg │ │ │ │ ├── folder.svg │ │ │ │ ├── img.svg │ │ │ │ ├── inspect.svg │ │ │ │ ├── light_to_dark.svg │ │ │ │ ├── moon.svg │ │ │ │ ├── pdf.svg │ │ │ │ ├── photo.svg │ │ │ │ ├── share.svg │ │ │ │ ├── stars.svg │ │ │ │ ├── sun.svg │ │ │ │ ├── trending-down.svg │ │ │ │ ├── trending-level.svg │ │ │ │ ├── trending-up.svg │ │ │ │ ├── txt.svg │ │ │ │ ├── unknown-file.svg │ │ │ │ ├── unlink.svg │ │ │ │ └── xls.svg │ │ │ ├── TableDeleteColumnIcon.tsx │ │ │ ├── TableDeleteRowIcon.tsx │ │ │ ├── TableInsertColumnIcon.tsx │ │ │ ├── TableInsertRowIcon.tsx │ │ │ ├── TrashIcon.tsx │ │ │ ├── TrendingDownIcon.tsx │ │ │ ├── TrendingLevelIcon.tsx │ │ │ ├── TrendingUpIcon.tsx │ │ │ ├── TxtIcon.tsx │ │ │ ├── UnknownFileIcon.tsx │ │ │ ├── UnlinkIcon.tsx │ │ │ ├── UserIcon.tsx │ │ │ ├── WarningIcon.tsx │ │ │ └── XlsIcon.tsx │ │ ├── IconProvider.tsx │ │ ├── IconRegistryContext.tsx │ │ ├── IFrame │ │ │ ├── IFrame.md │ │ │ ├── IFrame.module.scss │ │ │ ├── IFrame.spec.ts │ │ │ ├── IFrame.tsx │ │ │ └── IFrameNative.tsx │ │ ├── Image │ │ │ ├── Image.md │ │ │ ├── Image.module.scss │ │ │ ├── Image.spec.ts │ │ │ ├── Image.tsx │ │ │ └── ImageNative.tsx │ │ ├── Input │ │ │ ├── index.ts │ │ │ ├── InputAdornment.module.scss │ │ │ ├── InputAdornment.tsx │ │ │ ├── InputDivider.module.scss │ │ │ ├── InputDivider.tsx │ │ │ ├── InputLabel.module.scss │ │ │ ├── InputLabel.tsx │ │ │ ├── PartialInput.module.scss │ │ │ └── PartialInput.tsx │ │ ├── InspectButton │ │ │ ├── InspectButton.module.scss │ │ │ └── InspectButton.tsx │ │ ├── Items │ │ │ ├── Items.md │ │ │ ├── Items.spec.ts │ │ │ ├── Items.tsx │ │ │ └── ItemsNative.tsx │ │ ├── Link │ │ │ ├── Link.md │ │ │ ├── Link.module.scss │ │ │ ├── Link.spec.ts │ │ │ ├── Link.tsx │ │ │ └── LinkNative.tsx │ │ ├── List │ │ │ ├── doc-resources │ │ │ │ └── list-component-data.js │ │ │ ├── List.md │ │ │ ├── List.module.scss │ │ │ ├── List.spec.ts │ │ │ ├── List.tsx │ │ │ └── ListNative.tsx │ │ ├── Logo │ │ │ ├── doc-resources │ │ │ │ └── xmlui-logo.svg │ │ │ ├── Logo.md │ │ │ ├── Logo.tsx │ │ │ └── LogoNative.tsx │ │ ├── Markdown │ │ │ ├── CodeText.module.scss │ │ │ ├── CodeText.tsx │ │ │ ├── Markdown.md │ │ │ ├── Markdown.module.scss │ │ │ ├── Markdown.spec.ts │ │ │ ├── Markdown.tsx │ │ │ ├── MarkdownNative.tsx │ │ │ ├── parse-binding-expr.ts │ │ │ └── utils.ts │ │ ├── metadata-helpers.ts │ │ ├── ModalDialog │ │ │ ├── ConfirmationModalContextProvider.tsx │ │ │ ├── Dialog.module.scss │ │ │ ├── Dialog.tsx │ │ │ ├── ModalDialog.md │ │ │ ├── ModalDialog.module.scss │ │ │ ├── ModalDialog.spec.ts │ │ │ ├── ModalDialog.tsx │ │ │ ├── ModalDialogNative.tsx │ │ │ └── ModalVisibilityContext.tsx │ │ ├── NavGroup │ │ │ ├── NavGroup.md │ │ │ ├── NavGroup.module.scss │ │ │ ├── NavGroup.spec.ts │ │ │ ├── NavGroup.tsx │ │ │ ├── NavGroupContext.ts │ │ │ └── NavGroupNative.tsx │ │ ├── NavLink │ │ │ ├── NavLink.md │ │ │ ├── NavLink.module.scss │ │ │ ├── NavLink.spec.ts │ │ │ ├── NavLink.tsx │ │ │ └── NavLinkNative.tsx │ │ ├── NavPanel │ │ │ ├── NavPanel.md │ │ │ ├── NavPanel.module.scss │ │ │ ├── NavPanel.spec.ts │ │ │ ├── NavPanel.tsx │ │ │ └── NavPanelNative.tsx │ │ ├── NestedApp │ │ │ ├── AppWithCodeView.module.scss │ │ │ ├── AppWithCodeView.tsx │ │ │ ├── AppWithCodeViewNative.tsx │ │ │ ├── defaultProps.tsx │ │ │ ├── logo.svg │ │ │ ├── NestedApp.module.scss │ │ │ ├── NestedApp.tsx │ │ │ ├── NestedAppNative.tsx │ │ │ ├── Tooltip.module.scss │ │ │ ├── Tooltip.tsx │ │ │ └── utils.ts │ │ ├── NoResult │ │ │ ├── NoResult.md │ │ │ ├── NoResult.module.scss │ │ │ ├── NoResult.spec.ts │ │ │ ├── NoResult.tsx │ │ │ └── NoResultNative.tsx │ │ ├── NumberBox │ │ │ ├── numberbox-abstractions.ts │ │ │ ├── NumberBox.md │ │ │ ├── NumberBox.module.scss │ │ │ ├── NumberBox.spec.ts │ │ │ ├── NumberBox.tsx │ │ │ └── NumberBoxNative.tsx │ │ ├── Option │ │ │ ├── Option.md │ │ │ ├── Option.spec.ts │ │ │ ├── Option.tsx │ │ │ ├── OptionNative.tsx │ │ │ └── OptionTypeProvider.tsx │ │ ├── PageMetaTitle │ │ │ ├── PageMetaTilteNative.tsx │ │ │ ├── PageMetaTitle.md │ │ │ ├── PageMetaTitle.spec.ts │ │ │ └── PageMetaTitle.tsx │ │ ├── Pages │ │ │ ├── Page.md │ │ │ ├── Pages.md │ │ │ ├── Pages.module.scss │ │ │ ├── Pages.tsx │ │ │ └── PagesNative.tsx │ │ ├── Pagination │ │ │ ├── Pagination.md │ │ │ ├── Pagination.module.scss │ │ │ ├── Pagination.spec.ts │ │ │ ├── Pagination.tsx │ │ │ └── PaginationNative.tsx │ │ ├── PositionedContainer │ │ │ ├── PositionedContainer.module.scss │ │ │ ├── PositionedContainer.tsx │ │ │ └── PositionedContainerNative.tsx │ │ ├── ProfileMenu │ │ │ ├── ProfileMenu.module.scss │ │ │ └── ProfileMenu.tsx │ │ ├── ProgressBar │ │ │ ├── ProgressBar.md │ │ │ ├── ProgressBar.module.scss │ │ │ ├── ProgressBar.spec.ts │ │ │ ├── ProgressBar.tsx │ │ │ └── ProgressBarNative.tsx │ │ ├── Queue │ │ │ ├── Queue.md │ │ │ ├── Queue.spec.ts │ │ │ ├── Queue.tsx │ │ │ ├── queueActions.ts │ │ │ └── QueueNative.tsx │ │ ├── RadioGroup │ │ │ ├── RadioGroup.md │ │ │ ├── RadioGroup.module.scss │ │ │ ├── RadioGroup.spec.ts │ │ │ ├── RadioGroup.tsx │ │ │ ├── RadioGroupNative.tsx │ │ │ ├── RadioItem.tsx │ │ │ └── RadioItemNative.tsx │ │ ├── RealTimeAdapter │ │ │ ├── RealTimeAdapter.tsx │ │ │ └── RealTimeAdapterNative.tsx │ │ ├── Redirect │ │ │ ├── Redirect.md │ │ │ ├── Redirect.spec.ts │ │ │ └── Redirect.tsx │ │ ├── ResponsiveBar │ │ │ ├── README.md │ │ │ ├── ResponsiveBar.md │ │ │ ├── ResponsiveBar.module.scss │ │ │ ├── ResponsiveBar.spec.ts │ │ │ ├── ResponsiveBar.tsx │ │ │ └── ResponsiveBarNative.tsx │ │ ├── Select │ │ │ ├── HiddenOption.tsx │ │ │ ├── MultiSelectOption.tsx │ │ │ ├── OptionContext.ts │ │ │ ├── Select.md │ │ │ ├── Select.module.scss │ │ │ ├── Select.spec.ts │ │ │ ├── Select.tsx │ │ │ ├── SelectContext.tsx │ │ │ ├── SelectNative.tsx │ │ │ ├── SelectOption.tsx │ │ │ └── SimpleSelect.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 │ │ │ ├── compound-utils.ts │ │ │ ├── css-utils.ts │ │ │ ├── DataLoaderQueryKeyGenerator.ts │ │ │ ├── date-utils.ts │ │ │ ├── extractParam.ts │ │ │ ├── hooks.tsx │ │ │ ├── LruCache.ts │ │ │ ├── mergeProps.ts │ │ │ ├── misc.ts │ │ │ ├── request-params.ts │ │ │ ├── statementUtils.ts │ │ │ └── treeUtils.ts │ │ └── xmlui-parser.ts │ ├── index-standalone.ts │ ├── index.scss │ ├── index.ts │ ├── language-server │ │ ├── server-common.ts │ │ ├── server-web-worker.ts │ │ ├── server.ts │ │ ├── services │ │ │ ├── common │ │ │ │ ├── docs-generation.ts │ │ │ │ ├── lsp-utils.ts │ │ │ │ ├── metadata-utils.ts │ │ │ │ └── syntax-node-utilities.ts │ │ │ ├── completion.ts │ │ │ ├── diagnostic.ts │ │ │ ├── format.ts │ │ │ └── hover.ts │ │ └── xmlui-metadata-generated.mjs │ ├── logging │ │ ├── LoggerContext.tsx │ │ ├── LoggerInitializer.tsx │ │ ├── LoggerService.ts │ │ └── xmlui.ts │ ├── logo.svg │ ├── parsers │ │ ├── common │ │ │ ├── GenericToken.ts │ │ │ ├── InputStream.ts │ │ │ └── utils.ts │ │ ├── scripting │ │ │ ├── code-behind-collect.ts │ │ │ ├── Lexer.ts │ │ │ ├── modules.ts │ │ │ ├── Parser.ts │ │ │ ├── ParserError.ts │ │ │ ├── ScriptingNodeTypes.ts │ │ │ ├── TokenTrait.ts │ │ │ ├── TokenType.ts │ │ │ └── tree-visitor.ts │ │ ├── style-parser │ │ │ ├── errors.ts │ │ │ ├── source-tree.ts │ │ │ ├── StyleInputStream.ts │ │ │ ├── StyleLexer.ts │ │ │ ├── StyleParser.ts │ │ │ └── tokens.ts │ │ └── xmlui-parser │ │ ├── CharacterCodes.ts │ │ ├── diagnostics.ts │ │ ├── fileExtensions.ts │ │ ├── index.ts │ │ ├── lint.ts │ │ ├── parser.ts │ │ ├── ParserError.ts │ │ ├── scanner.ts │ │ ├── syntax-kind.ts │ │ ├── syntax-node.ts │ │ ├── transform.ts │ │ ├── utils.ts │ │ ├── xmlui-serializer.ts │ │ └── xmlui-tree.ts │ ├── react-app-env.d.ts │ ├── syntax │ │ ├── monaco │ │ │ ├── grammar.monacoLanguage.ts │ │ │ ├── index.ts │ │ │ ├── xmlui-dark.ts │ │ │ ├── xmlui-light.ts │ │ │ └── xmluiscript.monacoLanguage.ts │ │ └── textMate │ │ ├── index.ts │ │ ├── xmlui-dark.json │ │ ├── xmlui-light.json │ │ ├── xmlui.json │ │ └── xmlui.tmLanguage.json │ ├── testing │ │ ├── assertions.ts │ │ ├── component-test-helpers.ts │ │ ├── ComponentDrivers.ts │ │ ├── drivers │ │ │ ├── DateInputDriver.ts │ │ │ ├── ModalDialogDriver.ts │ │ │ ├── NumberBoxDriver.ts │ │ │ ├── TextBoxDriver.ts │ │ │ ├── TimeInputDriver.ts │ │ │ ├── TimerDriver.ts │ │ │ └── TreeDriver.ts │ │ ├── fixtures.ts │ │ ├── infrastructure │ │ │ ├── index.html │ │ │ ├── main.tsx │ │ │ ├── public │ │ │ │ ├── mockServiceWorker.js │ │ │ │ ├── resources │ │ │ │ │ ├── bell.svg │ │ │ │ │ ├── box.svg │ │ │ │ │ ├── doc.svg │ │ │ │ │ ├── eye.svg │ │ │ │ │ ├── flower-640x480.jpg │ │ │ │ │ ├── sun.svg │ │ │ │ │ ├── test-image-100x100.jpg │ │ │ │ │ └── txt.svg │ │ │ │ └── serve.json │ │ │ └── TestBed.tsx │ │ └── themed-app-test-helpers.ts │ └── vite-env.d.ts ├── tests │ ├── components │ │ ├── CodeBlock │ │ │ └── hightlight-code.test.ts │ │ ├── playground-pattern.test.ts │ │ └── Tree │ │ └── Tree-states.test.ts │ ├── components-core │ │ ├── abstractions │ │ │ └── treeAbstractions.test.ts │ │ ├── container │ │ │ └── buildProxy.test.ts │ │ ├── interception │ │ │ ├── orderBy.test.ts │ │ │ ├── ReadOnlyCollection.test.ts │ │ │ └── request-param-converter.test.ts │ │ ├── scripts-runner │ │ │ ├── AttributeValueParser.test.ts │ │ │ ├── eval-tree-arrow-async.test.ts │ │ │ ├── eval-tree-arrow.test.ts │ │ │ ├── eval-tree-func-decl-async.test.ts │ │ │ ├── eval-tree-func-decl.test.ts │ │ │ ├── eval-tree-pre-post.test.ts │ │ │ ├── eval-tree-regression.test.ts │ │ │ ├── eval-tree.test.ts │ │ │ ├── function-proxy.test.ts │ │ │ ├── parser-regression.test.ts │ │ │ ├── process-event.test.ts │ │ │ ├── process-function.test.ts │ │ │ ├── process-implicit-context.test.ts │ │ │ ├── process-statement-asgn.test.ts │ │ │ ├── process-statement-destruct.test.ts │ │ │ ├── process-statement-regs.test.ts │ │ │ ├── process-statement-sync.test.ts │ │ │ ├── process-statement.test.ts │ │ │ ├── process-switch-sync.test.ts │ │ │ ├── process-switch.test.ts │ │ │ ├── process-try-sync.test.ts │ │ │ ├── process-try.test.ts │ │ │ └── test-helpers.ts │ │ ├── test-metadata-handler.ts │ │ ├── theming │ │ │ ├── border-segments.test.ts │ │ │ ├── component-layout.resolver.test.ts │ │ │ ├── layout-property-parser.test.ts │ │ │ ├── layout-resolver.test.ts │ │ │ ├── layout-resolver2.test.ts │ │ │ ├── layout-vp-override.test.ts │ │ │ └── padding-segments.test.ts │ │ └── utils │ │ ├── date-utils.test.ts │ │ ├── format-human-elapsed-time.test.ts │ │ └── LruCache.test.ts │ ├── language-server │ │ ├── completion.test.ts │ │ ├── format.test.ts │ │ ├── hover.test.ts │ │ └── mockData.ts │ └── parsers │ ├── common │ │ └── input-stream.test.ts │ ├── markdown │ │ └── parse-binding-expression.test.ts │ ├── parameter-parser.test.ts │ ├── paremeter-parser.test.ts │ ├── scripting │ │ ├── eval-tree-arrow.test.ts │ │ ├── eval-tree-pre-post.test.ts │ │ ├── eval-tree.test.ts │ │ ├── function-proxy.test.ts │ │ ├── lexer-literals.test.ts │ │ ├── lexer-misc.test.ts │ │ ├── module-parse.test.ts │ │ ├── parser-arrow.test.ts │ │ ├── parser-assignments.test.ts │ │ ├── parser-binary.test.ts │ │ ├── parser-destructuring.test.ts │ │ ├── parser-errors.test.ts │ │ ├── parser-expressions.test.ts │ │ ├── parser-function.test.ts │ │ ├── parser-literals.test.ts │ │ ├── parser-primary.test.ts │ │ ├── parser-regex.test.ts │ │ ├── parser-statements.test.ts │ │ ├── parser-unary.test.ts │ │ ├── process-event.test.ts │ │ ├── process-implicit-context.test.ts │ │ ├── process-statement-asgn.test.ts │ │ ├── process-statement-destruct.test.ts │ │ ├── process-statement-regs.test.ts │ │ ├── process-statement-sync.test.ts │ │ ├── process-statement.test.ts │ │ ├── process-switch-sync.test.ts │ │ ├── process-switch.test.ts │ │ ├── process-try-sync.test.ts │ │ ├── process-try.test.ts │ │ ├── simplify-expression.test.ts │ │ ├── statement-hooks.test.ts │ │ └── test-helpers.ts │ ├── style-parser │ │ ├── generateHvarChain.test.ts │ │ ├── parseHVar.test.ts │ │ ├── parser.test.ts │ │ └── tokens.test.ts │ └── xmlui │ ├── lint.test.ts │ ├── parser.test.ts │ ├── scanner.test.ts │ ├── transform.attr.test.ts │ ├── transform.circular.test.ts │ ├── transform.element.test.ts │ ├── transform.errors.test.ts │ ├── transform.escape.test.ts │ ├── transform.regression.test.ts │ ├── transform.script.test.ts │ ├── transform.test.ts │ └── xmlui.ts ├── tests-e2e │ ├── api-bound-component-regression.spec.ts │ ├── api-call-as-extracted-component.spec.ts │ ├── assign-to-object-or-array-regression.spec.ts │ ├── binding-regression.spec.ts │ ├── children-as-template-context-vars.spec.ts │ ├── compound-component.spec.ts │ ├── context-vars-regression.spec.ts │ ├── data-bindings.spec.ts │ ├── datasource-and-api-usage-in-var.spec.ts │ ├── datasource-direct-binding.spec.ts │ ├── datasource-onLoaded-regression.spec.ts │ ├── modify-array-item-regression.spec.ts │ ├── namespaces.spec.ts │ ├── push-to-array-regression.spec.ts │ ├── screen-breakpoints.spec.ts │ ├── scripting.spec.ts │ ├── state-scope-in-pages.spec.ts │ └── state-var-scopes.spec.ts ├── tsconfig.bin.json ├── tsconfig.json ├── tsconfig.node.json ├── vite.config.ts └── vitest.config.ts ``` # Files -------------------------------------------------------------------------------- /xmlui/tests/components-core/scripts-runner/process-function.test.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { describe, expect, it } from "vitest"; 2 | 3 | import { processStatementQueueAsync } from "../../../src/components-core/script-runner/process-statement-async"; 4 | import {createEvalContext, parseStatements} from "./test-helpers"; 5 | import { processStatementQueue } from "../../../src/components-core/script-runner/process-statement-sync"; 6 | 7 | describe("Process functions (exp)", () => { 8 | it("Function async #1", async () => { 9 | // --- Arrange 10 | const source = ` 11 | let x = myFunction(1,2); 12 | function myFunction(...a) { 13 | return a[0] + a[1]; 14 | } 15 | `; 16 | const evalContext = createEvalContext({ 17 | localContext: {} 18 | }); 19 | const statements = parseStatements(source); 20 | 21 | // --- Act 22 | await processStatementQueueAsync(statements, evalContext); 23 | 24 | // --- Assert 25 | const thread = evalContext.mainThread; 26 | expect(thread!.blocks!.length).equal(1); 27 | expect(thread!.blocks![0].vars.x).equal(3); 28 | }); 29 | 30 | it("Function async #2", async () => { 31 | // --- Arrange 32 | const source = ` 33 | let x = myFunction(1, 2, 3); 34 | function myFunction(b, ...a) { 35 | return b + a[0] + a[1]; 36 | } 37 | `; 38 | const evalContext = createEvalContext({ 39 | localContext: {} 40 | }); 41 | const statements = parseStatements(source); 42 | 43 | // --- Act 44 | await processStatementQueueAsync(statements, evalContext); 45 | 46 | // --- Assert 47 | const thread = evalContext.mainThread; 48 | expect(thread!.blocks!.length).equal(1); 49 | expect(thread!.blocks![0].vars.x).equal(6); 50 | }); 51 | 52 | it("Function sync #1", () => { 53 | // --- Arrange 54 | const source = ` 55 | let x = myFunction(1,2); 56 | function myFunction(...a) { 57 | return a[0] + a[1]; 58 | } 59 | `; 60 | const evalContext = createEvalContext({ 61 | localContext: {} 62 | }); 63 | const statements = parseStatements(source); 64 | 65 | // --- Act 66 | processStatementQueue(statements, evalContext); 67 | 68 | // --- Assert 69 | const thread = evalContext.mainThread; 70 | expect(thread!.blocks!.length).equal(1); 71 | expect(thread!.blocks![0].vars.x).equal(3); 72 | }); 73 | 74 | it("Function sync #2", () => { 75 | // --- Arrange 76 | const source = ` 77 | let x = myFunction(1, 2, 3); 78 | function myFunction(b, ...a) { 79 | return b + a[0] + a[1]; 80 | } 81 | `; 82 | const evalContext = createEvalContext({ 83 | localContext: {} 84 | }); 85 | const statements = parseStatements(source); 86 | 87 | // --- Act 88 | processStatementQueue(statements, evalContext); 89 | 90 | // --- Assert 91 | const thread = evalContext.mainThread; 92 | expect(thread!.blocks!.length).equal(1); 93 | expect(thread!.blocks![0].vars.x).equal(6); 94 | }); 95 | }); 96 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/FormItem/FormItem.module.scss: -------------------------------------------------------------------------------- ```scss 1 | @use "../../components-core/theming/themes" as t; 2 | 3 | // --- This code snippet is required to collect the theme variables used in this module 4 | $themeVars: ( 5 | ); 6 | 7 | @function createThemeVar($componentVariable) { 8 | $themeVars: t.appendThemeVar($themeVars, $componentVariable) !global; 9 | @return t.getThemeVar($themeVars, $componentVariable); 10 | } 11 | 12 | // TODO: Add HelperText styles here, as HelperText React component is used only in FormItem 13 | 14 | @layer components { 15 | .container { 16 | display: flex; 17 | width: 100%; 18 | flex-direction: column; 19 | align-items: start; 20 | gap: 0.5em; 21 | 22 | &.top { 23 | flex-direction: column; 24 | align-items: start; 25 | justify-content: center; 26 | } 27 | 28 | &.end { 29 | flex-direction: row-reverse; 30 | align-items: center; 31 | justify-content: start; 32 | gap: 0.5em; 33 | } 34 | 35 | &.bottom { 36 | flex-direction: column-reverse; 37 | align-items: start; 38 | justify-content: center; 39 | } 40 | 41 | &.start { 42 | flex-direction: row; 43 | align-items: center; 44 | justify-content: start; 45 | gap: 0.5em; 46 | } 47 | 48 | &.shrinkToLabel { 49 | width: fit-content; 50 | } 51 | 52 | .inputLabel { 53 | display: flex; 54 | color: createThemeVar("textColor-FormItemLabel"); 55 | font-family: createThemeVar("fontFamily-FormItemLabel"); 56 | font-size: createThemeVar("fontSize-FormItemLabel"); 57 | font-weight: createThemeVar("fontWeight-FormItemLabel"); 58 | font-style: createThemeVar("fontStyle-FormItemLabel"); 59 | text-transform: createThemeVar("textTransform-FormItemLabel"); 60 | user-select: none; 61 | cursor: pointer; 62 | word-break: normal; 63 | white-space: nowrap; 64 | 65 | &.disabled { 66 | cursor: not-allowed; 67 | color: t.$textColor--disabled; 68 | } 69 | 70 | &.labelBreak { 71 | white-space: normal; 72 | word-break: normal; 73 | overflow-wrap: break-word; 74 | } 75 | 76 | &.required { 77 | color: createThemeVar("textColor-FormItemLabel-required"); 78 | font-size: createThemeVar("fontSize-FormItemLabel-required"); 79 | font-weight: createThemeVar("fontWeight-FormItemLabel-required"); 80 | font-style: createThemeVar("fontStyle-FormItemLabel-required"); 81 | text-transform: createThemeVar("textTransform-FormItemLabel-required"); 82 | } 83 | 84 | .requiredMark { 85 | margin-left: 0.2em; 86 | color: createThemeVar("textColor-FormItemLabel-requiredMark"); 87 | } 88 | } 89 | } 90 | 91 | .itemWithLabel { 92 | display: flex; 93 | justify-content: center; 94 | align-items: center; 95 | } 96 | } 97 | 98 | // --- We export the theme variables to add them to the component renderer 99 | :export { 100 | themeVars: t.json-stringify($themeVars); 101 | } ``` -------------------------------------------------------------------------------- /xmlui/src/components-core/DebugViewProvider.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { createContext, useContext, useState } from "react"; 2 | 3 | // --- Represents the options for the state view. 4 | type StateViewOptions = { 5 | showBoundary?: boolean; 6 | blink?: boolean; 7 | } 8 | 9 | // --- Represents a state transition. 10 | type StateTransition = { 11 | action: string; 12 | uid?: string; 13 | prevState: any; 14 | nextState: any; 15 | } 16 | 17 | // --- This type represents the shape of the debug configuration stored in the app's global properties. 18 | interface DebugConfiguration { 19 | displayStateView?: boolean; 20 | stateViewOptions?: StateViewOptions; 21 | collectStateTransitions?: boolean; 22 | } 23 | 24 | // --- Represents the context for the debug view. 25 | export interface IDebugViewContext extends DebugConfiguration { 26 | // --- Debug tools window 27 | showDebugToolsWindow: boolean; 28 | openDebugToolsWindow: () => void; 29 | closeDebugToolsWindow: () => void; 30 | 31 | // --- State view 32 | setDisplayStateView: (display: boolean) => void; 33 | 34 | // --- State transition collection 35 | stateTransitions?: StateTransition[]; 36 | startCollectingStateTransitions: () => void; 37 | stopCollectingStateTransitions: () => void; 38 | } 39 | 40 | export const DebugViewContext = createContext<IDebugViewContext | null>(null); 41 | 42 | type Props = { 43 | children: React.ReactNode; 44 | debugConfig?: DebugConfiguration; 45 | } 46 | 47 | export function DebugViewProvider({ children, debugConfig }: Props) { 48 | const [showDebugToolsWindow, setShowDebugToolsWindow] = useState(false); 49 | const [displayStateView, setDisplayStateView] = useState(!!debugConfig?.displayStateView); 50 | const [collectStateTransitions, setCollectStateTransitions] = useState(!!debugConfig?.collectStateTransitions); 51 | const [stateTransitions, setStateTransitions] = useState<StateTransition[]>([]); 52 | 53 | const openDebugToolsWindow = () => { 54 | setShowDebugToolsWindow(true); 55 | }; 56 | 57 | const closeDebugToolsWindow = () => { 58 | setShowDebugToolsWindow(false); 59 | }; 60 | 61 | const startCollectingStateTransitions = () => { 62 | setCollectStateTransitions(true); 63 | setStateTransitions([]); 64 | }; 65 | 66 | const stopCollectingStateTransitions = () => { 67 | setCollectStateTransitions(false); 68 | }; 69 | 70 | const contextValue: IDebugViewContext = { 71 | showDebugToolsWindow, 72 | openDebugToolsWindow, 73 | closeDebugToolsWindow, 74 | displayStateView, 75 | stateViewOptions: { showBoundary: true, blink: true }, 76 | setDisplayStateView, 77 | collectStateTransitions, 78 | stateTransitions, 79 | startCollectingStateTransitions, 80 | stopCollectingStateTransitions, 81 | }; 82 | 83 | return ( 84 | <DebugViewContext.Provider value={contextValue}> 85 | {children} 86 | </DebugViewContext.Provider> 87 | ); 88 | } 89 | 90 | export function useDebugView() { 91 | return useContext(DebugViewContext); 92 | } ``` -------------------------------------------------------------------------------- /xmlui/src/components-core/rendering/ErrorBoundary.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import React, { type ErrorInfo, type ReactNode } from "react"; 2 | 3 | import styles from "./ErrorBoundary.module.scss"; 4 | 5 | import type { ComponentLike } from "../../abstractions/ComponentDefs"; 6 | 7 | // --- The properties of the ErrorBoundary component 8 | interface Props { 9 | // --- Child nodes within the boundary 10 | children: ReactNode; 11 | 12 | // --- Whenever the value of this property changes, the boundary restores its "no error" state. 13 | node?: ComponentLike; 14 | 15 | // --- The location of the error 16 | location?: string; 17 | } 18 | 19 | // --- This type represents the current state of the error boundary 20 | type State = { 21 | hasError: boolean; 22 | error: Error | null; 23 | }; 24 | 25 | /** 26 | * This React component serves as an error boundary; it catches any errors within 27 | * the nested components 28 | */ 29 | export class ErrorBoundary extends React.Component<Props, State> { 30 | // --- We start with "no error" state 31 | state: State = { 32 | hasError: false, 33 | error: null, 34 | }; 35 | 36 | /** 37 | * This method implements the Error Boundaries for the React application. 38 | * It is invoked if errors occur during the rendering phase of any lifecycle 39 | * methods or children components. 40 | * 41 | * DO NOT DELETE this method! Though it is not referenced directly from the code, 42 | * it is a required part of the React component lifecycle. 43 | */ 44 | static getDerivedStateFromError(error: Error): State { 45 | // --- Update state so the next render will show the fallback UI. 46 | return { hasError: true, error }; 47 | } 48 | 49 | /** 50 | * Display any error in the console 51 | * @param error Error object 52 | * @param errorInfo Extra information about the error 53 | */ 54 | componentDidCatch(error: Error, errorInfo: ErrorInfo) { 55 | console.error("Uncaught error:", error, errorInfo, this.props.location); 56 | } 57 | 58 | /** 59 | * Whenever the `restoreOnChangeOf` property of this component instance 60 | * changes, we reset the state to "no error". 61 | * @param prevProps Previous property values 62 | * @param prevState Previous state 63 | * @param snapshot Optional snapshot (not used in this component) 64 | */ 65 | componentDidUpdate(prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) { 66 | if (prevProps.node !== this.props.node) { 67 | this.setState({ 68 | hasError: false, 69 | }); 70 | } 71 | } 72 | 73 | /** 74 | * Display an error message if an error occurred during rendering. 75 | */ 76 | render() { 77 | return this.state.hasError ? ( 78 | <div data-error-boundary className={styles.errorOverlay}> 79 | <div className={styles.title}>There was an error!</div> 80 | <div className={styles.errorItem}>{this.state.error?.message}</div> 81 | </div> 82 | ) : ( 83 | this.props.children 84 | ); 85 | } 86 | } 87 | ``` -------------------------------------------------------------------------------- /docs/content/components/Icon.md: -------------------------------------------------------------------------------- ```markdown 1 | # Icon [#icon] 2 | 3 | `Icon` displays scalable vector icons from XMLUI's built-in icon registry using simple name references. Icons are commonly used in buttons, navigation elements, and status indicators. 4 | 5 | **Key features:** 6 | - **Name-based lookup**: Reference icons by name from the built-in registry (e.g., "home", "search", "trash") 7 | - **Multiple sizes**: Choose from predefined sizes (xs, sm, md, lg) or set custom dimensions 8 | - **Fallback support**: Specify backup icons when the primary icon name doesn't exist 9 | - **Interactive**: Supports click events for creating icon buttons and clickable elements 10 | 11 | ## Properties [#properties] 12 | 13 | ### `fallback` [#fallback] 14 | 15 | This optional property provides a way to handle situations when the icon with the provided [icon name](#name) name does not exist. If the icon cannot be found, no icon is displayed. 16 | 17 | ```xmlui-pg copy display name="Example: fallback" 18 | <App> 19 | <Icon name="noicon" fallback="trash" /> 20 | </App> 21 | ``` 22 | 23 | ### `name` [#name] 24 | 25 | This string property specifies the name of the icon to display. All icons have unique, case-sensitive names identifying them. If the icon name is not set, the `fallback` value is used. 26 | 27 | The engine looks up the icon in its registry and determines which icon is associated with the name that the component will show. 28 | Nothing is displayed if the icon name is not found in the registry. 29 | 30 | ```xmlui-pg copy display name="Example: name" 31 | <App> 32 | <HStack> 33 | <Icon name="message" /> 34 | <Icon name="note" /> 35 | <Icon name="cog" /> 36 | <Icon name="start" /> 37 | <Icon name="some-non-existing-icon" /> 38 | <Icon name="some-non-existing-icon-with fallback" fallback="trash" /> 39 | </HStack> 40 | </App> 41 | ``` 42 | 43 | ### `size` [#size] 44 | 45 | This property defines the size of the `Icon`. Note that setting the `height` and/or the `width` of the component will override this property. You can use az explicit size value (e.g., 32px) or one of these predefined values: `xs`, `sm`, `md`, `lg`. 46 | 47 | Available values: `xs`, `sm`, `md`, `lg` 48 | 49 | ```xmlui-pg copy display name="Example: size" 50 | <App> 51 | <HStack> 52 | <Icon name="like" /> 53 | <Icon name="like" size="xs" /> 54 | <Icon name="like" size="sm" /> 55 | <Icon name="like" size="md" /> 56 | <Icon name="like" size="lg" /> 57 | </HStack> 58 | </App> 59 | ``` 60 | 61 | ## Events [#events] 62 | 63 | ### `click` [#click] 64 | 65 | This event is triggered when the icon is clicked. 66 | 67 | ## Exposed Methods [#exposed-methods] 68 | 69 | This component does not expose any methods. 70 | 71 | ## Styling [#styling] 72 | 73 | ### Theme Variables [#theme-variables] 74 | 75 | | Variable | Default Value (Light) | Default Value (Dark) | 76 | | --- | --- | --- | 77 | | [size](../styles-and-themes/common-units/#size)-Icon | 1.2em | 1.2em | 78 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/ColorPicker/ColorPicker.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { createComponentRenderer } from "../../components-core/renderers"; 2 | import { ColorPicker, defaultProps } from "./ColorPickerNative"; 3 | import { 4 | createMetadata, 5 | dAutoFocus, 6 | dDidChange, 7 | dEnabled, 8 | dGotFocus, 9 | dInitialValue, 10 | dLostFocus, 11 | dReadonly, 12 | dRequired, 13 | dValidationStatus, 14 | } from "../metadata-helpers"; 15 | import { parseScssVar } from "../../components-core/theming/themeVars"; 16 | import styles from "./ColorPicker.module.scss"; 17 | 18 | const COMP = "ColorPicker"; 19 | 20 | export const ColorPickerMd = createMetadata({ 21 | status: "stable", 22 | description: 23 | "`ColorPicker` enables users to choose colors by specifying RGB, HSL, or HEX values.", 24 | props: { 25 | initialValue: dInitialValue(), 26 | enabled: dEnabled(), 27 | autoFocus: dAutoFocus(), 28 | required: dRequired(), 29 | readOnly: dReadonly(), 30 | validationStatus: dValidationStatus(defaultProps.validationStatus), 31 | }, 32 | events: { 33 | didChange: dDidChange(COMP), 34 | gotFocus: dGotFocus(COMP), 35 | lostFocus: dLostFocus(COMP), 36 | }, 37 | apis: { 38 | focus: { 39 | description: `Focus the ${COMP} component.`, 40 | signature: "focus(): void", 41 | }, 42 | value: { 43 | description: `This method returns the current value of the ${COMP}.`, 44 | signature: "get value(): string", 45 | }, 46 | setValue: { 47 | description: `This method sets the current value of the ${COMP}.`, 48 | signature: "set value(value: string): void", 49 | parameters: { 50 | value: "The new value to set for the color picker.", 51 | }, 52 | }, 53 | }, 54 | themeVars: parseScssVar(styles.themeVars), 55 | }); 56 | 57 | export const colorPickerComponentRenderer = createComponentRenderer( 58 | "ColorPicker", 59 | ColorPickerMd, 60 | ({ 61 | node, 62 | extractValue, 63 | className, 64 | state, 65 | lookupEventHandler, 66 | registerComponentApi, 67 | updateState, 68 | }) => { 69 | const readOnly = extractValue.asOptionalBoolean(node.props?.readOnly, false); 70 | const enabled = extractValue.asOptionalBoolean(node.props?.enabled, true); 71 | return ( 72 | <ColorPicker 73 | validationStatus={extractValue(node.props.validationStatus)} 74 | value={state.value} 75 | initialValue={extractValue(node.props.initialValue)} 76 | updateState={updateState} 77 | onDidChange={lookupEventHandler("didChange")} 78 | onFocus={lookupEventHandler("gotFocus")} 79 | onBlur={lookupEventHandler("lostFocus")} 80 | registerComponentApi={registerComponentApi} 81 | className={className} 82 | required={extractValue.asOptionalBoolean(node.props?.required)} 83 | enabled={enabled && !readOnly} 84 | readOnly={readOnly} 85 | autoFocus={extractValue.asOptionalBoolean(node.props?.autoFocus)} 86 | /> 87 | ); 88 | }, 89 | ); 90 | ``` -------------------------------------------------------------------------------- /docs/content/components/_meta.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "_overview": "Components Overview", 3 | "APICall": "APICall", 4 | "App": "App", 5 | "AppHeader": "AppHeader", 6 | "AppState": "AppState", 7 | "AutoComplete": "AutoComplete", 8 | "Avatar": "Avatar", 9 | "Backdrop": "Backdrop", 10 | "Badge": "Badge", 11 | "BarChart": "BarChart", 12 | "Bookmark": "Bookmark", 13 | "Breakout": "Breakout", 14 | "Button": "Button", 15 | "CHStack": "CHStack", 16 | "CVStack": "CVStack", 17 | "Card": "Card", 18 | "Carousel": "Carousel", 19 | "ChangeListener": "ChangeListener", 20 | "Checkbox": "Checkbox", 21 | "ColorPicker": "ColorPicker", 22 | "Column": "Column", 23 | "ContentSeparator": "ContentSeparator", 24 | "DataSource": "DataSource", 25 | "DateInput": "DateInput", 26 | "DatePicker": "DatePicker", 27 | "DonutChart": "DonutChart", 28 | "DropdownMenu": "DropdownMenu", 29 | "EmojiSelector": "EmojiSelector", 30 | "ExpandableItem": "ExpandableItem", 31 | "FileInput": "FileInput", 32 | "FileUploadDropZone": "FileUploadDropZone", 33 | "FlowLayout": "FlowLayout", 34 | "Footer": "Footer", 35 | "Form": "Form", 36 | "FormItem": "FormItem", 37 | "FormSection": "FormSection", 38 | "Fragment": "Fragment", 39 | "H1": "H1", 40 | "H2": "H2", 41 | "H3": "H3", 42 | "H4": "H4", 43 | "H5": "H5", 44 | "H6": "H6", 45 | "HSplitter": "HSplitter", 46 | "HStack": "HStack", 47 | "Heading": "Heading", 48 | "IFrame": "IFrame", 49 | "Icon": "Icon", 50 | "Image": "Image", 51 | "Items": "Items", 52 | "LabelList": "LabelList", 53 | "Legend": "Legend", 54 | "LineChart": "LineChart", 55 | "Link": "Link", 56 | "List": "List", 57 | "Logo": "Logo", 58 | "Markdown": "Markdown", 59 | "MenuItem": "MenuItem", 60 | "MenuSeparator": "MenuSeparator", 61 | "ModalDialog": "ModalDialog", 62 | "NavGroup": "NavGroup", 63 | "NavLink": "NavLink", 64 | "NavPanel": "NavPanel", 65 | "NoResult": "NoResult", 66 | "NumberBox": "NumberBox", 67 | "Option": "Option", 68 | "Page": "Page", 69 | "PageMetaTitle": "PageMetaTitle", 70 | "Pages": "Pages", 71 | "Pagination": "Pagination", 72 | "PasswordInput": "PasswordInput", 73 | "PieChart": "PieChart", 74 | "ProgressBar": "ProgressBar", 75 | "Queue": "Queue", 76 | "RadioGroup": "RadioGroup", 77 | "RealTimeAdapter": "RealTimeAdapter", 78 | "Redirect": "Redirect", 79 | "Select": "Select", 80 | "Slider": "Slider", 81 | "Slot": "Slot", 82 | "SpaceFiller": "SpaceFiller", 83 | "Spinner": "Spinner", 84 | "Splitter": "Splitter", 85 | "Stack": "Stack", 86 | "StickyBox": "StickyBox", 87 | "SubMenuItem": "SubMenuItem", 88 | "Switch": "Switch", 89 | "TabItem": "TabItem", 90 | "Table": "Table", 91 | "TableOfContents": "TableOfContents", 92 | "Tabs": "Tabs", 93 | "Text": "Text", 94 | "TextArea": "TextArea", 95 | "TextBox": "TextBox", 96 | "Theme": "Theme", 97 | "TimeInput": "TimeInput", 98 | "Timer": "Timer", 99 | "ToneChangerButton": "ToneChangerButton", 100 | "ToneSwitch": "ToneSwitch", 101 | "Tooltip": "Tooltip", 102 | "Tree": "Tree", 103 | "VSplitter": "VSplitter", 104 | "VStack": "VStack" 105 | } ``` -------------------------------------------------------------------------------- /packages/xmlui-playground/src/playground/ThemeSwitcher.module.scss: -------------------------------------------------------------------------------- ```scss 1 | @use "xmlui/themes.scss" as themes; 2 | 3 | .button { 4 | padding: .5rem 1rem; 5 | } 6 | 7 | .RadixMenuContent { 8 | display: flex; 9 | flex-direction: column; 10 | min-width: 100px; 11 | width: fit-content; 12 | background-color: themes.$backgroundColor; 13 | border-radius: 6px; 14 | padding: 5px; 15 | box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35), 0px 10px 20px -15px rgba(22, 23, 24, 0.2); 16 | animation-duration: 400ms; 17 | animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); 18 | will-change: transform, opacity; 19 | } 20 | 21 | .RadixMenuContent[data-side='top'] { 22 | animation-name: slideDownAndFade; 23 | } 24 | 25 | .RadixMenuContent[data-side='right'] { 26 | animation-name: slideLeftAndFade; 27 | } 28 | 29 | .RadixMenuContent[data-side='bottom'] { 30 | animation-name: slideUpAndFade; 31 | } 32 | 33 | .RadixMenuContent[data-side='left'] { 34 | animation-name: slideRightAndFade; 35 | } 36 | 37 | .dark { 38 | --tw-bg-opacity: 1; 39 | background-color: rgba(38, 38, 38, var(--tw-bg-opacity)); 40 | } 41 | 42 | .RadixMenuRadioGroup { 43 | width: 100%; 44 | } 45 | 46 | .RadixMenuItem, 47 | .RadixMenuRadioItem { 48 | width: 100%; 49 | display: flex; 50 | align-items: center; 51 | justify-content: space-between; 52 | font-size: 13px; 53 | line-height: 1; 54 | border-radius: 3px; 55 | display: flex; 56 | align-items: center; 57 | height: 25px; 58 | padding: 0 5px; 59 | padding-left: 1rem; 60 | user-select: none; 61 | outline: none; 62 | } 63 | 64 | .RadixMenuItem[data-disabled], 65 | .RadixMenuRadioItem[data-disabled] { 66 | pointer-events: none; 67 | } 68 | 69 | .RadixMenuItem[data-highlighted], 70 | .RadixMenuRadioItem[data-highlighted] { 71 | background-color: rgba(243, 244, 246, var(--tw-bg-opacity)); 72 | color: rgba(51, 65, 85, var(--tw-text-opacity)); 73 | } 74 | 75 | :is(html[class~=dark] .RadixMenuRadioItem[data-highlighted], .RadixMenuItem[data-highlighted]) { 76 | background-color: hsl(var(--nextra-primary-hue) var(--nextra-primary-saturation) 94%/.05); 77 | --tw-text-opacity: 1; 78 | } 79 | 80 | .RadixMenuLabel { 81 | padding-left: 1rem; 82 | font-weight: 600; 83 | font-size: 12px; 84 | line-height: 25px; 85 | } 86 | 87 | .RadixMenuSeparator { 88 | height: 1px; 89 | --tw-text-opacity: 1; 90 | margin: 5px; 91 | } 92 | 93 | .RadixMenuItemIndicator { 94 | width: 25px; 95 | display: inline-flex; 96 | align-items: center; 97 | justify-content: center; 98 | } 99 | 100 | @keyframes slideUpAndFade { 101 | from { 102 | opacity: 0; 103 | transform: translateY(2px); 104 | } 105 | to { 106 | opacity: 1; 107 | transform: translateY(0); 108 | } 109 | } 110 | 111 | @keyframes slideRightAndFade { 112 | from { 113 | opacity: 0; 114 | transform: translateX(-2px); 115 | } 116 | to { 117 | opacity: 1; 118 | transform: translateX(0); 119 | } 120 | } 121 | 122 | @keyframes slideDownAndFade { 123 | from { 124 | opacity: 0; 125 | transform: translateY(-2px); 126 | } 127 | to { 128 | opacity: 1; 129 | transform: translateY(0); 130 | } 131 | } 132 | 133 | @keyframes slideLeftAndFade { 134 | from { 135 | opacity: 0; 136 | transform: translateX(2px); 137 | } 138 | to { 139 | opacity: 1; 140 | transform: translateX(0); 141 | } 142 | } 143 | ``` -------------------------------------------------------------------------------- /docs/public/pages/tutorial-12.md: -------------------------------------------------------------------------------- ```markdown 1 | # Settings 2 | 3 | The `Settings` component demonstrates how to manage application state that persists between sessions using [AppState](/components/AppState), [DataSource](/components/DataSource), and [APICall](/components/APICall) working together. 4 | 5 | ## State management pattern 6 | 7 | XMLUI Invoice uses a three-component pattern for persistent settings: 8 | 9 | 1. **AppState** - Holds current settings in memory for immediate UI updates 10 | 2. **DataSource** - Loads initial settings from the database on app startup 11 | 3. **APICall** - Saves settings changes back to the database when triggered 12 | 13 | ```xmlui /AppState/ /DataSource/ /APICall/ 14 | <Component name="Settings"> 15 | <DataSource url="/api/users" id="users" /> 16 | <AppState id="settings" bucket="settingsState" /> 17 | 18 | <APICall 19 | id="updateSettings" 20 | method="put" 21 | url="/api/settings" 22 | body="{settings.value}" 23 | completedNotificationMessage="Settings saved successfully" 24 | errorNotificationMessage="Failed to save settings" 25 | /> 26 | </Component> 27 | ``` 28 | 29 | ## Loading settings on startup 30 | 31 | In `Main.xmlui`, a `DataSource` loads settings from the database and populates the `AppState` when the app starts: 32 | 33 | ```xmlui /settingsLoader/ /settings.update/ 34 | <DataSource id="settingsLoader" url="/api/settings"> 35 | <event name="loaded"> 36 | settings.update({ 37 | avatar_border_radius: settingsLoader.value[0].avatar_border_radius 38 | }); 39 | delay(500); 40 | </event> 41 | </DataSource> 42 | ``` 43 | 44 | The `loaded` event fires when the database fetch completes, then calls `settings.update()` to populate the AppState with the retrieved values. 45 | 46 | ## Reactive UI updates 47 | 48 | Components throughout the app can bind directly to AppState values for immediate updates: 49 | 50 | ```xmlui /settings.value.avatar_border_radius/ 51 | <InvoiceAvatar 52 | url="{loggedInUser.avatar_url}" 53 | name="{loggedInUser.display_name}" 54 | borderRadius="{settings.value.avatar_border_radius}" 55 | /> 56 | ``` 57 | 58 | When settings change, any bound UI elements automatically re-render with the new values. 59 | 60 | ## User input and gated saves 61 | 62 | The Settings form uses a [TextBox](/components/TextBox) that updates AppState immediately, but database saves are gated behind a [Button](/components/Button): 63 | 64 | ```xmlui /onDidChange/ /onClick/ 65 | <TextBox 66 | value="{settings.value.avatar_border_radius}" 67 | onDidChange="{(value) => { 68 | if (value && settings.value) { 69 | settings.update({ 70 | avatar_border_radius: value 71 | }); 72 | } 73 | }}" 74 | /> 75 | 76 | <Button onClick="{() => updateSettings.execute()}"> 77 | Save 78 | </Button> 79 | ``` 80 | 81 | This pattern provides: 82 | 83 | - **Immediate feedback** - UI updates as the user types 84 | - **Controlled persistence** - Database only updates on explicit save 85 | - **Error handling** - Save failures don't lose the user's input 86 | ``` -------------------------------------------------------------------------------- /xmlui/src/logo.svg: -------------------------------------------------------------------------------- ``` 1 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"> 2 | <g fill="#61DAFB"> 3 | <path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/> 4 | <circle cx="420.9" cy="296.5" r="45.7"/> 5 | <path d="M520.5 78.1z"/> 6 | </g> 7 | </svg> 8 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Splitter/Splitter.md: -------------------------------------------------------------------------------- ```markdown 1 | %-DESC-START 2 | 3 | Most properties of the component focus on the primary section (e.g. sizing). 4 | 5 | See also: [HSplitter](/components/HSplitter), [VSplitter](/components/VSplitter). 6 | 7 | %-DESC-END 8 | 9 | %-PROP-START floating 10 | 11 | ```xmlui-pg copy display name="Example: floating" 12 | <App> 13 | <Splitter height="200px" floating="true"> 14 | <Stack backgroundColor="lightblue" height="100%" /> 15 | <Stack backgroundColor="darksalmon" height="100%" /> 16 | </Splitter> 17 | </App> 18 | ``` 19 | 20 | %-PROP-END 21 | 22 | %-PROP-START initialPrimarySize 23 | 24 | ```xmlui-pg copy display name="Example: initialPrimarySize" 25 | <App> 26 | <Splitter height="200px" initialPrimarySize="40%"> 27 | <Stack backgroundColor="lightblue" height="100%" /> 28 | <Stack backgroundColor="darksalmon" height="100%" /> 29 | </Splitter> 30 | </App> 31 | ``` 32 | 33 | %-PROP-END 34 | 35 | %-PROP-START maxPrimarySize 36 | 37 | ```xmlui-pg copy display name="Example: maxPrimarySize" 38 | <App> 39 | <Splitter height="200px" maxPrimarySize="80%"> 40 | <Stack backgroundColor="lightblue" height="100%" /> 41 | <Stack backgroundColor="darksalmon" height="100%" /> 42 | </Splitter> 43 | </App> 44 | ``` 45 | 46 | %-PROP-END 47 | 48 | %-PROP-START minPrimarySize 49 | 50 | ```xmlui-pg copy display name="Example: minPrimarySize" 51 | <App> 52 | <Splitter height="200px" minPrimarySize="40px"> 53 | <Stack backgroundColor="lightblue" height="100%" /> 54 | <Stack backgroundColor="darksalmon" height="100%" /> 55 | </Splitter> 56 | </App> 57 | ``` 58 | 59 | %-PROP-END 60 | 61 | %-PROP-START orientation 62 | 63 | ```xmlui-pg copy display name="Example: orientation" 64 | <App> 65 | <Splitter height="200px" orientation="horizontal"> 66 | <Stack backgroundColor="lightblue" height="100%" /> 67 | <Stack backgroundColor="darksalmon" height="100%" /> 68 | </Splitter> 69 | </App> 70 | ``` 71 | 72 | %-PROP-END 73 | 74 | %-PROP-START splitterTemplate 75 | 76 | ```xmlui-pg copy {2-4} display name="Example: splitterTemplate" 77 | <App> 78 | <Splitter height="200px"> 79 | <property name="splitterTemplate"> 80 | <ContentSeparator backgroundColor="green" height="4px" /> 81 | </property> 82 | <Stack backgroundColor="lightblue" height="100%" /> 83 | <Stack backgroundColor="darksalmon" height="100%" /> 84 | </Splitter> 85 | </App> 86 | ``` 87 | 88 | %-PROP-END 89 | 90 | %-PROP-START swapped 91 | 92 | ```xmlui-pg copy display name="Example: swapped" 93 | <App> 94 | <Splitter height="200px" swapped="true"> 95 | <Stack backgroundColor="lightblue" height="100%" /> 96 | <Stack backgroundColor="darksalmon" height="100%" /> 97 | </Splitter> 98 | </App> 99 | ``` 100 | 101 | %-PROP-END 102 | 103 | %-EVENT-START resize 104 | 105 | ```xmlui-pg copy {2} display name="Example: resize" 106 | <App height="200px" var.counter="{0}"> 107 | <Splitter onResize="counter++"> 108 | <Stack backgroundColor="lightblue" height="100%"> 109 | <Text value="Resize event called {counter} number of times" /> 110 | </Stack> 111 | <Stack backgroundColor="darksalmon" height="100%" /> 112 | </Splitter> 113 | </App> 114 | ``` 115 | 116 | %-EVENT-END 117 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Queue/queueActions.ts: -------------------------------------------------------------------------------- ```typescript 1 | export enum QueueActionKind { 2 | ACTION_ITEM_STARTED = "ACTION_ITEM_STARTED", 3 | ACTION_ITEM_PROGRESS = "ACTION_ITEM_PROGRESS", 4 | ACTION_ITEM_COMPLETED = "ACTION_ITEM_COMPLETED", 5 | CLEAR_COMPLETED_ACTION_ITEMS = "CLEAR_COMPLETED_ACTION_ITEMS", 6 | ACTION_ITEM_ERROR = "ACTION_ITEM_ERROR", 7 | ACTION_QUEUE_INITIALIZED = "ACTION_QUEUE_INITIALIZED", 8 | ACTION_ITEM_REMOVED = "ACTION_ITEM_REMOVED", 9 | } 10 | 11 | export interface QueueAction { 12 | type: QueueActionKind; 13 | // Potential improvement: Try to specify the type with more details 14 | payload: 15 | | { 16 | uid?: any; 17 | data?: any; 18 | error?: any; 19 | value?: any; 20 | } 21 | | any; 22 | } 23 | 24 | // Signs that a particular component (`uid`) has started running an action with `actionItemId`. 25 | export function actionItemStarted(actionItemId: string) { 26 | return { 27 | type: QueueActionKind.ACTION_ITEM_STARTED, 28 | payload: { 29 | actionItemId, 30 | }, 31 | }; 32 | } 33 | 34 | // Signs that a particular component (`uid`) reports progress information (`progressEvent`) 35 | // on an action with `actionItemId`. 36 | export function actionItemProgress(actionItemId: string, progressEvent: any) { 37 | return { 38 | type: QueueActionKind.ACTION_ITEM_PROGRESS, 39 | payload: { 40 | actionItemId, 41 | progressEvent, 42 | }, 43 | }; 44 | } 45 | 46 | // Signs that a particular component (`uid`) has completed an action with `actionItemId` resulting in `result`. 47 | export function actionItemCompleted(actionItemId: string, result: any) { 48 | return { 49 | type: QueueActionKind.ACTION_ITEM_COMPLETED, 50 | payload: { 51 | actionItemId, 52 | result, 53 | }, 54 | }; 55 | } 56 | 57 | // Signs that a particular component (`uid`) has removed an action with `actionItemId` from the execution queue. 58 | export function removeActionItem(actionItemId: string) { 59 | return { 60 | type: QueueActionKind.ACTION_ITEM_REMOVED, 61 | payload: { 62 | actionItemId, 63 | }, 64 | }; 65 | } 66 | 67 | // Signs that a particular component (`uid`) has cleared completed action items from its execution queue. 68 | export function clearCompletedActionItems() { 69 | return { 70 | type: QueueActionKind.CLEAR_COMPLETED_ACTION_ITEMS, 71 | payload: {}, 72 | }; 73 | } 74 | 75 | // Signs that a particular component (`uid`) received an `error` when running an action with `actionItemId`. 76 | export function actionItemError(actionItemId: string, error: any) { 77 | return { 78 | type: QueueActionKind.ACTION_ITEM_ERROR, 79 | payload: { 80 | actionItemId, 81 | error, 82 | }, 83 | }; 84 | } 85 | 86 | // Signs that a particular component (`uid`) has initialized its execution `queue` with the specified `batchId`. 87 | export function actionQueueInitialized(queue: Array<any>, batchId: string, actionItemIds: string[]) { 88 | return { 89 | type: QueueActionKind.ACTION_QUEUE_INITIALIZED, 90 | payload: { 91 | queue, 92 | actionItemIds, 93 | batchId, 94 | }, 95 | }; 96 | } 97 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/ResponsiveBar/ResponsiveBar.md: -------------------------------------------------------------------------------- ```markdown 1 | %-DESC-START 2 | 3 | **Key features:** 4 | - **Automatic overflow management**: Automatically moves items that don't fit into a dropdown menu 5 | - **Responsive design**: Adapts to container width changes in real-time 6 | - **Zero configuration**: Works out of the box with sensible defaults 7 | - **Customizable overflow icon**: Use custom icons for the overflow dropdown trigger 8 | 9 | The component monitors its container width and automatically determines which child components fit within the available space. Components that don't fit are moved into a dropdown menu accessible via a "..." trigger button. 10 | 11 | ```xmlui-pg copy display name="Example: Basic ResponsiveBar" height="200px" 12 | ---app copy display 13 | <App> 14 | <ResponsiveBar> 15 | <Button label="File" /> 16 | <Button label="Edit" /> 17 | <Button label="View" /> 18 | <Button label="Window" /> 19 | <Button label="Help" /> 20 | </ResponsiveBar> 21 | </App> 22 | ---desc 23 | Try resizing the container or browser window to see the responsive behavior: 24 | ``` 25 | 26 | %-DESC-END 27 | 28 | %-PROP-START overflowIcon 29 | 30 | You can customize the icon used for the overflow dropdown trigger: 31 | 32 | ```xmlui-pg copy display name="Example: Custom overflow icon" height="200px" 33 | <App> 34 | <ResponsiveBar overflowIcon="menu"> 35 | <Button label="Home" /> 36 | <Button label="Products" /> 37 | <Button label="Services" /> 38 | <Button label="About" /> 39 | <Button label="Contact" /> 40 | </ResponsiveBar> 41 | </App> 42 | ``` 43 | 44 | %-PROP-END 45 | 46 | %-EVENT-START click 47 | 48 | ```xmlui-pg copy display name="Example: Click event" height="200px" 49 | <App> 50 | <variable name="clickCount" value="{0}" /> 51 | <Text value="ResponsiveBar clicked {clickCount} times" /> 52 | <ResponsiveBar onClick="clickCount += 1"> 53 | <Button label="Item 1" /> 54 | <Button label="Item 2" /> 55 | <Button label="Item 3" /> 56 | </ResponsiveBar> 57 | </App> 58 | ``` 59 | 60 | %-EVENT-END 61 | 62 | ## Advanced Usage 63 | 64 | ### With Different Content Types 65 | 66 | ResponsiveBar works with any type of child components: 67 | 68 | ```xmlui-pg copy display name="Example: Mixed content" height="200px" 69 | <App> 70 | <ResponsiveBar> 71 | <Button label="New" icon="plus" /> 72 | <Button label="Open" icon="folder" /> 73 | <Text>|</Text> 74 | <Button label="Save" icon="save" /> 75 | <Button label="Print" icon="printer" /> 76 | <Text>|</Text> 77 | <Button label="Settings" icon="cog" /> 78 | </ResponsiveBar> 79 | </App> 80 | ``` 81 | 82 | ### Navigation Menu Example 83 | 84 | Perfect for responsive navigation menus: 85 | 86 | ```xmlui-pg copy display name="Example: Navigation menu" height="200px" 87 | <App> 88 | <ResponsiveBar> 89 | <Button label="Dashboard" variant="ghost" /> 90 | <Button label="Analytics" variant="ghost" /> 91 | <Button label="Reports" variant="ghost" /> 92 | <Button label="Settings" variant="ghost" /> 93 | <Button label="Users" variant="ghost" /> 94 | <Button label="Profile" variant="ghost" /> 95 | </ResponsiveBar> 96 | </App> 97 | ``` 98 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Select/SelectOption.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { forwardRef, useEffect, useMemo, useRef } from "react"; 2 | import type { Option } from "../abstractions"; 3 | import { Item, ItemIndicator, ItemText } from "@radix-ui/react-select"; 4 | import { useSelect } from "./SelectContext"; 5 | import { useOption } from "./OptionContext"; 6 | import classnames from "classnames"; 7 | import styles from "./Select.module.scss"; 8 | import Icon from "../Icon/IconNative"; 9 | 10 | export const SelectOption = forwardRef<React.ElementRef<typeof Item>, Option>( 11 | function SelectOption(option, ref) { 12 | const visibleContentRef = useRef<HTMLDivElement>(null); 13 | const { value, label, enabled = true, children, className } = option; 14 | const { value: selectedValue, optionRenderer } = useSelect(); 15 | const { onOptionRemove, onOptionAdd } = useOption(); 16 | 17 | const opt: Option = useMemo(() => { 18 | return { 19 | ...option, 20 | label: label ?? "", 21 | keywords: [label ?? ""], 22 | }; 23 | }, [option, label]); 24 | 25 | useEffect(() => { 26 | onOptionAdd(opt); 27 | return () => onOptionRemove(opt); 28 | }, [opt, onOptionAdd, onOptionRemove]); 29 | 30 | return ( 31 | <Item 32 | ref={ref} 33 | className={classnames(className, styles.selectOption)} 34 | value={value} 35 | textValue={label} 36 | disabled={!enabled} 37 | onClick={(event) => { 38 | event.stopPropagation(); 39 | }} 40 | data-state={selectedValue === value && "checked"} 41 | > 42 | {/* SelectItemText is used by SelectValue to display the selected value */} 43 | <span style={{ display: "none" }}> 44 | <ItemText>{label}</ItemText> 45 | </span> 46 | {/* Visible content in the dropdown */} 47 | {children ? ( 48 | <> 49 | <div className={styles.selectOptionContent} ref={visibleContentRef}> 50 | {children} 51 | </div> 52 | {selectedValue === value && ( 53 | <ItemIndicator className={styles.selectOptionIndicator}> 54 | <Icon name="checkmark" /> 55 | </ItemIndicator> 56 | )} 57 | </> 58 | ) : optionRenderer ? ( 59 | <div className={styles.selectOptionContent} ref={visibleContentRef}> 60 | {optionRenderer( 61 | { 62 | label, 63 | value, 64 | enabled, 65 | }, 66 | selectedValue as any, 67 | false, 68 | )} 69 | </div> 70 | ) : ( 71 | <> 72 | <div className={styles.selectOptionContent} ref={visibleContentRef}> 73 | {label} 74 | </div> 75 | {selectedValue === value && ( 76 | <ItemIndicator className={styles.selectItemIndicator}> 77 | <Icon name="checkmark" /> 78 | </ItemIndicator> 79 | )} 80 | </> 81 | )} 82 | </Item> 83 | ); 84 | }, 85 | ); 86 | ``` -------------------------------------------------------------------------------- /xmlui/bin/build-lib.ts: -------------------------------------------------------------------------------- ```typescript 1 | #!/usr/bin/env node 2 | 3 | import { build as viteBuild, defineConfig, loadEnv, type UserConfig } from "vite"; 4 | // @ts-ignore 5 | import path from "path"; 6 | import react from "@vitejs/plugin-react"; 7 | import { libInjectCss } from "vite-plugin-lib-inject-css"; 8 | import { default as ViteXmlui } from "./vite-xmlui-plugin"; 9 | 10 | export const buildLib = async ({ 11 | watchMode, 12 | mode = "production", 13 | }: { 14 | watchMode?: boolean; 15 | mode?: string; 16 | }) => { 17 | const env = loadEnv(mode, process.cwd(), ""); 18 | 19 | const umdFileName = `${env.npm_package_name}.js`; 20 | const esFileName = `${env.npm_package_name}.mjs`; 21 | 22 | let overrides: UserConfig = {}; 23 | try { 24 | const configOverrides = await import(process.cwd() + `/vite.config-overrides`); 25 | overrides = configOverrides.default || {}; 26 | } catch (e) { 27 | // console.error(e); 28 | } 29 | 30 | const config: UserConfig = { 31 | resolve: { 32 | extensions: [".js", ".ts", ".jsx", ".tsx", ".json", ".xmlui", ".xmlui.xs", ".xs"], 33 | }, 34 | esbuild: { 35 | target: "es2020", 36 | }, 37 | optimizeDeps: { 38 | esbuildOptions: { 39 | target: "es2020", 40 | }, 41 | }, 42 | define: { 43 | "process.env": { 44 | NODE_ENV: env.NODE_ENV, 45 | }, 46 | }, 47 | build: { 48 | emptyOutDir: false, 49 | outDir: "dist", 50 | watch: watchMode ? {} : undefined, 51 | sourcemap: watchMode ? "inline" : false, 52 | lib: 53 | mode === "metadata" 54 | ? { 55 | entry: [path.resolve("meta", "componentsMetadata.ts")], 56 | name: `${env.npm_package_name}-metadata`, 57 | fileName: `${env.npm_package_name}-metadata`, 58 | } 59 | : { 60 | entry: [path.resolve("src", "index.tsx")], 61 | formats: watchMode ? ["es"] : ["umd", "es"], 62 | name: env.npm_package_name, 63 | fileName: (format) => (format === "es" ? esFileName : umdFileName), 64 | }, 65 | rollupOptions: { 66 | treeshake: mode === "metadata" ? "smallest" : undefined, 67 | external: mode === "metadata" ? [] : ["react", "react-dom", "xmlui", "react/jsx-runtime"], 68 | output: { 69 | footer: (chunk) => { 70 | if (chunk.name === "index" && chunk.fileName === umdFileName) { 71 | return `if(typeof window.xmlui !== "undefined"){window.xmlui.standalone.registerExtension(window['${env.npm_package_name}'].default || window['${env.npm_package_name}']);}`; 72 | } 73 | return ""; 74 | }, 75 | globals: { 76 | react: "React", 77 | "react-dom": "ReactDOM", 78 | jsx: "react/jsx-runtime", 79 | }, 80 | }, 81 | }, 82 | }, 83 | plugins: 84 | mode === "metadata" 85 | ? [ViteXmlui({})] 86 | : [react(), ViteXmlui({}), libInjectCss(), ...(overrides.plugins || [])], 87 | }; 88 | 89 | await viteBuild(defineConfig(config)); 90 | }; 91 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/ResponsiveBar/ResponsiveBar.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import styles from "./ResponsiveBar.module.scss"; 2 | 3 | import { createComponentRenderer } from "../../components-core/renderers"; 4 | import { parseScssVar } from "../../components-core/theming/themeVars"; 5 | import { createMetadata, dClick } from "../metadata-helpers"; 6 | import { defaultResponsiveBarProps, ResponsiveBar } from "./ResponsiveBarNative"; 7 | 8 | const COMP = "ResponsiveBar"; 9 | 10 | export const ResponsiveBarMd = createMetadata({ 11 | status: "stable", 12 | description: 13 | "`ResponsiveBar` is a layout container that automatically manages child " + 14 | "component overflow by moving items that don't fit into a dropdown menu. It supports " + 15 | "both horizontal and vertical orientations and provides a space-efficient way to display " + 16 | "navigation items, toolbar buttons, or other components that need to adapt to varying " + 17 | "container dimensions while maintaining full functionality.", 18 | docFolder: COMP, 19 | props: { 20 | orientation: { 21 | description: 22 | "Layout direction of the responsive bar. In horizontal mode, items are arranged " + 23 | "left-to-right and overflow is based on container width. In vertical mode, items are " + 24 | "arranged top-to-bottom and overflow is based on container height.", 25 | valueType: "string", 26 | availableValues: ["horizontal", "vertical"], 27 | defaultValue: defaultResponsiveBarProps.orientation, 28 | }, 29 | overflowIcon: { 30 | description: 31 | "Icon to display in the dropdown trigger button when items overflow. " + 32 | "You can use component-specific icons in the format \"iconName:ResponsiveBar\".", 33 | valueType: "string", 34 | defaultValue: defaultResponsiveBarProps.overflowIcon, 35 | }, 36 | gap: { 37 | description: 38 | "Gap between child elements in pixels. Controls the spacing between items " + 39 | "in the responsive bar layout.", 40 | valueType: "number", 41 | defaultValue: defaultResponsiveBarProps.gap, 42 | }, 43 | }, 44 | events: { 45 | click: dClick(COMP), 46 | }, 47 | apis: {}, 48 | contextVars: {}, 49 | themeVars: parseScssVar(styles.themeVars), 50 | limitThemeVarsToComponent: true, 51 | defaultThemeVars: { 52 | [`backgroundColor-${COMP}`]: "transparent", 53 | [`padding-${COMP}`]: "0", 54 | [`margin-${COMP}`]: "0", 55 | }, 56 | }); 57 | 58 | export const responsiveBarComponentRenderer = createComponentRenderer( 59 | COMP, 60 | ResponsiveBarMd, 61 | ({ node, extractValue, renderChild, className, lookupEventHandler }) => { 62 | return ( 63 | <ResponsiveBar 64 | orientation={extractValue(node.props?.orientation)} 65 | overflowIcon={extractValue(node.props?.overflowIcon)} 66 | gap={extractValue(node.props?.gap)} 67 | onClick={lookupEventHandler("click")} 68 | className={className} 69 | > 70 | {renderChild(node.children)} 71 | </ResponsiveBar> 72 | ); 73 | }, 74 | ); 75 | ``` -------------------------------------------------------------------------------- /docs/CHANGELOG.md: -------------------------------------------------------------------------------- ```markdown 1 | # xmlui-docs 2 | 3 | ## 0.0.10 4 | 5 | ### Patch Changes 6 | 7 | - eb6454f: refactor: change LineChart/BarChart property names 8 | - Updated dependencies [f12a042] 9 | - Updated dependencies [8731eb8] 10 | - Updated dependencies [eb6454f] 11 | - Updated dependencies [1210852] 12 | - [email protected] 13 | 14 | ## 0.0.9 15 | 16 | ### Patch Changes 17 | 18 | - 819b563: Update fontSize and lineHeight themes and style (may break existing xmlui code) 19 | - Updated dependencies [8c76c8d] 20 | - Updated dependencies [d56c3e5] 21 | - Updated dependencies [e42d367] 22 | - Updated dependencies [f539526] 23 | - Updated dependencies [19ce234] 24 | - Updated dependencies [455b6c0] 25 | - Updated dependencies [e90dc73] 26 | - Updated dependencies [819b563] 27 | - Updated dependencies [b57dfa2] 28 | - Updated dependencies [9dd0f97] 29 | - Updated dependencies [19ce234] 30 | - Updated dependencies [898346d] 31 | - Updated dependencies [705dd04] 32 | - [email protected] 33 | 34 | ## 0.0.8 35 | 36 | ### Patch Changes 37 | 38 | - 4ad31fc: refactor: rename dataKeys/nameKey to xKeys/yKey and layout to orientation in chart components - BarChart, LineChart 39 | - Updated dependencies [879c09d] 40 | - Updated dependencies [3ad8514] 41 | - Updated dependencies [0c69245] 42 | - Updated dependencies [4ad31fc] 43 | - Updated dependencies [c99f184] 44 | - Updated dependencies [5032e4a] 45 | - Updated dependencies [2394f36] 46 | - [email protected] 47 | 48 | ## 0.0.7 49 | 50 | ### Patch Changes 51 | 52 | - 6bc9ed1: feat: support aligning cells in a Table row vertically 53 | - Updated dependencies [2e512bb] 54 | - Updated dependencies [46d1d18] 55 | - Updated dependencies [6bc9ed1] 56 | - Updated dependencies [0b1f983] 57 | - Updated dependencies [a2637f3] 58 | - Updated dependencies [eb4d592] 59 | - [email protected] 60 | 61 | ## 0.0.6 62 | 63 | ### Patch Changes 64 | 65 | - 1451a94: feat: make input padding configurable via theme variables 66 | - Updated dependencies [ff14e15] 67 | - Updated dependencies [1451a94] 68 | - [email protected] 69 | 70 | ## 0.0.5 71 | 72 | ### Patch Changes 73 | 74 | - bc95844: improve: Select and AutoComplete components 75 | - Updated dependencies [af17117] 76 | - Updated dependencies [44da3d9] 77 | - Updated dependencies [b7a6b9a] 78 | - Updated dependencies [bc95844] 79 | - Updated dependencies [52d94a2] 80 | - Updated dependencies [6629ce5] 81 | - Updated dependencies [0254471] 82 | - Updated dependencies [3318cfb] 83 | - [email protected] 84 | 85 | ## 0.0.4 86 | 87 | ### Patch Changes 88 | 89 | - c876be8: Turn docs deploy to standard routing 90 | - Updated dependencies [c876be8] 91 | - [email protected] 92 | 93 | ## 0.0.3 94 | 95 | ### Patch Changes 96 | 97 | - 69b4402: improve: docs - footer logo, FormItem - labelBreak 98 | - Updated dependencies [de8d63c] 99 | - Updated dependencies [bd6d1b4] 100 | - Updated dependencies [db5a5f4] 101 | - Updated dependencies [69b4402] 102 | - [email protected] 103 | 104 | ## 0.0.2 105 | 106 | ### Patch Changes 107 | 108 | - 3eab4a3: improve: design updates - devtools, playground, docs 109 | - Updated dependencies [3eab4a3] 110 | - Updated dependencies [411cd34] 111 | - Updated dependencies [cdf96bb] 112 | - Updated dependencies [121c55c] 113 | - Updated dependencies [f1092fe] 114 | - [email protected] 115 | - [email protected] 116 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/NavPanel/NavPanel.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import styles from "./NavPanel.module.scss"; 2 | 3 | import { createComponentRenderer } from "../../components-core/renderers"; 4 | import { parseScssVar } from "../../components-core/theming/themeVars"; 5 | import { createMetadata, dComponent } from "../metadata-helpers"; 6 | import { NavPanel, defaultProps, buildNavHierarchy } from "./NavPanelNative"; 7 | import { useMemo } from "react"; 8 | import classnames from "classnames"; 9 | 10 | const COMP = "NavPanel"; 11 | 12 | export const NavPanelMd = createMetadata({ 13 | status: "stable", 14 | description: 15 | "`NavPanel` defines the navigation structure within an App, serving as a container " + 16 | "for NavLink and NavGroup components that create your application's primary " + 17 | "navigation menu. Its appearance and behavior automatically adapt based on the " + 18 | "App's layout configuration.", 19 | props: { 20 | logoTemplate: dComponent( 21 | `This property defines the logo template to display in the navigation panel with the ` + 22 | `\`vertical\` and \`vertical-sticky\` layout.`, 23 | ), 24 | inDrawer: { 25 | description: `This property determines if the navigation panel is displayed in a drawer.`, 26 | valueType: "boolean", 27 | defaultValue: defaultProps.inDrawer, 28 | }, 29 | }, 30 | themeVars: parseScssVar(styles.themeVars), 31 | limitThemeVarsToComponent: true, 32 | defaultThemeVars: { 33 | [`horizontalAlignment-logo-${COMP}`]: "center", 34 | [`backgroundColor-${COMP}`]: "$backgroundColor", 35 | [`backgroundColor-${COMP}-horizontal`]: "$backgroundColor-AppHeader", 36 | [`border-${COMP}`]: "0px solid $borderColor", 37 | [`paddingHorizontal-${COMP}`]: "0", 38 | [`paddingVertical-logo-${COMP}`]: "$space-4", 39 | [`paddingHorizontal-logo-${COMP}`]: "$space-4", 40 | [`marginBottom-logo-${COMP}`]: "$space-4", 41 | [`boxShadow-${COMP}-vertical`]: "4px 0 4px 0 rgb(0 0 0 / 10%)", 42 | }, 43 | }); 44 | 45 | function NavPanelWithBuiltNavHierarchy({ 46 | node, 47 | renderChild, 48 | className, 49 | layoutContext, 50 | extractValue, 51 | }) { 52 | const navLinks = useMemo(() => { 53 | return buildNavHierarchy(node.children, extractValue, undefined, []); 54 | }, [extractValue, node.children]); 55 | 56 | return ( 57 | <NavPanel 58 | logoContent={renderChild(node.props.logoTemplate)} 59 | className={classnames(layoutContext?.themeClassName, className)} 60 | inDrawer={layoutContext?.inDrawer} 61 | renderChild={renderChild} 62 | navLinks={navLinks} 63 | > 64 | {renderChild(node.children)} 65 | </NavPanel> 66 | ); 67 | } 68 | 69 | export const navPanelRenderer = createComponentRenderer( 70 | COMP, 71 | NavPanelMd, 72 | ({ node, renderChild, className, layoutContext, extractValue }) => { 73 | return ( 74 | <NavPanelWithBuiltNavHierarchy 75 | node={node} 76 | renderChild={renderChild} 77 | className={className} 78 | layoutContext={layoutContext} 79 | extractValue={extractValue} 80 | /> 81 | ); 82 | }, 83 | ); 84 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/App/Sheet.module.scss: -------------------------------------------------------------------------------- ```scss 1 | @use "../../components-core/theming/themes" as t; 2 | 3 | $themeVars: (); 4 | @function createThemeVar($componentVariable) { 5 | $themeVars: t.appendThemeVar($themeVars, $componentVariable) !global; 6 | @return t.getThemeVar($themeVars, $componentVariable); 7 | } 8 | 9 | $maxWidth-Drawer: createThemeVar("maxWidth-Drawer"); 10 | 11 | //we do it with animations (instead of transitions) because: https://www.radix-ui.com/primitives/docs/guides/animation 12 | $reveal-anim-duration: 300ms; 13 | 14 | @keyframes slide-in-from-left { 15 | from { 16 | transform: translateX(-100%); 17 | opacity: 0; 18 | box-shadow: none; 19 | } 20 | to { 21 | } 22 | } 23 | 24 | @keyframes slide-out-to-left { 25 | from { 26 | } 27 | to { 28 | transform: translateX(-100%); 29 | opacity: 0; 30 | box-shadow: none; 31 | } 32 | } 33 | 34 | @keyframes blur-in { 35 | from { 36 | background-color: transparent; 37 | backdrop-filter: blur(0); 38 | } 39 | to { 40 | } 41 | } 42 | 43 | @keyframes blur-out { 44 | from { 45 | } 46 | to { 47 | backdrop-filter: blur(0); 48 | background-color: transparent; 49 | } 50 | } 51 | 52 | 53 | .overlay{ 54 | position: absolute; 55 | top: 0; 56 | right: 0; 57 | bottom: 0; 58 | left: 0; 59 | backdrop-filter: blur(4px); 60 | background-color: #{rgb}(from t.useVar(t.$backgroundColor-primary) r g b / 70%); 61 | 62 | &[data-state='open']{ 63 | animation: blur-in $reveal-anim-duration; 64 | } 65 | &[data-state='closed']{ 66 | animation: blur-out $reveal-anim-duration; 67 | } 68 | } 69 | 70 | 71 | .sheetContent{ 72 | position: absolute; 73 | gap: 1rem; 74 | background-color: t.$backgroundColor; 75 | 76 | opacity: 1; 77 | transform: translateX(0); 78 | box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); 79 | border-color: transparent; 80 | 81 | &[data-state='open']{ 82 | animation: slide-in-from-left $reveal-anim-duration; 83 | } 84 | &[data-state='closed']{ 85 | animation: slide-out-to-left $reveal-anim-duration; 86 | } 87 | 88 | &.top{ 89 | right: 0; 90 | left: 0; 91 | top: 0; 92 | border-bottom-width: 1px; 93 | } 94 | 95 | &.bottom{ 96 | right: 0; 97 | left: 0; 98 | bottom: 0; 99 | border-top-width: 1px; 100 | } 101 | 102 | &.left{ 103 | top: 0; 104 | bottom: 0; 105 | left: 0; 106 | border-right-width: 1px; 107 | width: 100%; 108 | height: 100%; 109 | max-width: $maxWidth-Drawer; 110 | } 111 | 112 | &.right{ 113 | top: 0; 114 | bottom: 0; 115 | right: 0; 116 | border-left-width: 1px; 117 | width: 100%; 118 | height: 100%; 119 | max-width: $maxWidth-Drawer; 120 | } 121 | } 122 | 123 | .close{ 124 | color: inherit; 125 | position: absolute; 126 | top: 1rem; 127 | right: 1rem; 128 | display: flex; 129 | align-items: center; 130 | justify-content: center; 131 | border-radius: t.$borderRadius; 132 | transition-property: opacity; 133 | transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 134 | transition-duration: 300ms; 135 | opacity: 0.7; 136 | padding: 0.25rem; 137 | background-color: inherit; 138 | border: 0; 139 | cursor: pointer; 140 | z-index: 2; 141 | 142 | &:hover { 143 | opacity: 1; 144 | } 145 | 146 | } 147 | 148 | // --- We export the theme variables to add them to the component renderer 149 | :export{ 150 | themeVars: t.json-stringify($themeVars) 151 | } 152 | ``` -------------------------------------------------------------------------------- /docs/content/components/TabItem.md: -------------------------------------------------------------------------------- ```markdown 1 | # TabItem [#tabitem] 2 | 3 | `TabItem` defines individual tabs within a [Tabs](/components/Tabs) component, providing both the tab header label and the content that displays when the tab is selected. As a non-visual structural component, it serves as a container that organizes content into distinct, switchable sections. 4 | 5 | **Key features:** 6 | - **Label definition**: Provides the clickable tab header text via the label property 7 | - **Content container**: Wraps any child components that display when the tab is active 8 | - **Structural organization**: Creates the relationship between tab headers and their corresponding content 9 | - **Seamless integration**: Designed exclusively for use within [Tabs](/components/Tabs) components 10 | 11 | **Usage pattern:** 12 | Always used as a direct child of [Tabs](/components/Tabs) components. The `label` property defines the tab button text, while child components placed within the TabItem provide the content that displays when the tab is selected. 13 | 14 | **Context variables available during execution:** 15 | 16 | - `$header`: This context value represents the header context with props: id (optional), index, label, isActive. 17 | 18 | ## Properties [#properties] 19 | 20 | ### `headerTemplate` [#headertemplate] 21 | 22 | This property allows the customization of the TabItem header. 23 | 24 | ```xmlui-pg copy {7-9} display name="Example: headerTemplate" /headerTemplate/ height="200px" 25 | <App> 26 | <Tabs> 27 | <TabItem label="Home"> 28 | Home content 29 | </TabItem> 30 | <TabItem label="Accounts"> 31 | <property name="headerTemplate"> 32 | <Text variant="title" color="green">Accounts</Text> 33 | </property> 34 | Accounts content 35 | </TabItem> 36 | <TabItem label="Settings"> 37 | Settings content 38 | </TabItem> 39 | </Tabs> 40 | </App> 41 | ``` 42 | 43 | > [!INFO] You can customize the [header templates](./Tabs#headertemplate) of **all** tab items, too. You can mix the `Tabs` level header templates with the `TabItem` level ones. In this case, the `TabItem` level template prevails. 44 | 45 | ### `label` [#label] 46 | 47 | This property sets the label of the component. If not set, the component will not display a label. 48 | 49 | ## Events [#events] 50 | 51 | ### `activated` [#activated] 52 | 53 | This event is triggered when the tab is activated. 54 | 55 | ```xmlui-pg copy display name="Example: activated" /onActivated/ height="200px" 56 | <App var.activationCount="{0}"> 57 | <Tabs> 58 | <TabItem label="Account" onActivated="activationCount++"> 59 | <Text>Account</Text> 60 | </TabItem> 61 | <TabItem label="Stream"> 62 | <Text>Stream</Text> 63 | </TabItem> 64 | <TabItem label="Support"> 65 | <Text>Support</Text> 66 | </TabItem> 67 | </Tabs> 68 | <Text>The Account tab has been activated {activationCount} times.</Text> 69 | </App> 70 | ``` 71 | 72 | ## Exposed Methods [#exposed-methods] 73 | 74 | This component does not expose any methods. 75 | 76 | ## Styling [#styling] 77 | 78 | This component does not have any styles. 79 | ``` -------------------------------------------------------------------------------- /xmlui/src/components-core/EngineError.ts: -------------------------------------------------------------------------------- ```typescript 1 | /** 2 | * The abstract base class of all UI engine errors 3 | */ 4 | export abstract class EngineError extends Error { 5 | protected abstract readonly errorCategory: string; 6 | protected constructor(message: string) { 7 | super(message); 8 | Object.setPrototypeOf(this, EngineError.prototype); 9 | } 10 | } 11 | 12 | /** 13 | * Extracts information from the error object received from the backend 14 | */ 15 | export class GenericBackendError extends EngineError { 16 | readonly errorCategory = "GenericBackendError"; 17 | details: any; 18 | statusCode: number | undefined; 19 | constructor(public readonly info: any, errorCode: number | undefined) { 20 | // `The backend raised an error. (reasonCode: ${info.reasonCode}, isBusiness: ${info.isBusiness}, message: ${info.message})` 21 | let message = ""; 22 | if (info?.code) { 23 | message += `[Error code: ${info.code}]\n`; 24 | } 25 | if (info?.details && typeof info.details === "string") { 26 | message += `${info.details}`; 27 | } else if(info?.message){ 28 | message += `${info.message}`; 29 | } 30 | super(message || info?.message || "Unknown error"); 31 | 32 | this.details = info; 33 | this.statusCode = errorCode; 34 | // --- Set the prototype explicitly. 35 | Object.setPrototypeOf(this, GenericBackendError.prototype); 36 | } 37 | } 38 | 39 | /** 40 | * Custom exception indicating a parser error 41 | */ 42 | export class ScriptParseError extends EngineError { 43 | readonly errorCategory = "ScriptParserError"; 44 | constructor(message: string, public readonly source?: string, public readonly position?: number) { 45 | message = `Parser Error: ${message}`; 46 | super(message); 47 | Object.setPrototypeOf(this, ScriptParseError.prototype); 48 | } 49 | } 50 | 51 | /** 52 | * Custom exception signing parsing error 53 | */ 54 | export class StatementExecutionError extends EngineError { 55 | readonly errorCategory = "StatementExecutionError"; 56 | constructor(message: string, public readonly source?: string) { 57 | super(message); 58 | Object.setPrototypeOf(this, StatementExecutionError.prototype); 59 | } 60 | } 61 | 62 | /** 63 | * Signs that we get an unexpected type instead of a component definition 64 | */ 65 | export class NotAComponentDefError extends EngineError { 66 | readonly errorCategory = "NotAComponentError"; 67 | constructor() { 68 | super("Must be a component definition, cannot use dynamic children here..."); 69 | Object.setPrototypeOf(this, NotAComponentDefError.prototype); 70 | } 71 | } 72 | 73 | /** 74 | * We throw this error when a throw statement is executed 75 | */ 76 | export class ThrowStatementError extends EngineError { 77 | readonly errorCategory = "ThrowStatementError"; 78 | readonly message: string; 79 | constructor(public readonly errorObject: any) { 80 | const message = typeof errorObject === "string" 81 | ? errorObject : errorObject?.message || "Error without message"; 82 | super(message); 83 | this.message = message; 84 | Object.setPrototypeOf(this, ThrowStatementError.prototype); 85 | } 86 | } ``` -------------------------------------------------------------------------------- /xmlui/src/language-server/services/common/docs-generation.ts: -------------------------------------------------------------------------------- ```typescript 1 | import type { ComponentMetadata, ComponentPropertyMetadata } from "../../../abstractions/ComponentDefs"; 2 | 3 | export function generateCompNameDescription(componentName: string, metadata: ComponentMetadata): string { 4 | const sections: string[] = []; 5 | 6 | // Add title and description 7 | sections.push(`# ${componentName}`); 8 | 9 | if (metadata.description) { 10 | sections.push(metadata.description); 11 | } 12 | 13 | // Add status if not stable 14 | if (metadata.status && metadata.status !== 'stable') { 15 | sections.push(`**Status:** ${metadata.status}`); 16 | } 17 | 18 | // Add Properties section if there are props 19 | if (metadata.props && Object.keys(metadata.props).length > 0) { 20 | sections.push('\n## Properties'); 21 | 22 | Object.entries(metadata.props) 23 | .filter(([_, prop]) => !(prop as any).isInternal) 24 | .forEach(([propName, prop]) => { 25 | sections.push(generateAttrDescription(propName, prop)); 26 | }); 27 | } 28 | 29 | // Add Events section if there are events 30 | if (metadata.events && Object.keys(metadata.events).length > 0) { 31 | sections.push('\n## Events'); 32 | 33 | Object.entries(metadata.events) 34 | .filter(([_, event]) => !(event as any).isInternal) 35 | .forEach(([eventName, event]) => { 36 | sections.push(`### \`${eventName}\`\n${(event as any).description}`); 37 | }); 38 | } 39 | 40 | // Add APIs section if there are APIs 41 | if (metadata.apis && Object.keys(metadata.apis).length > 0) { 42 | sections.push('\n## APIs'); 43 | 44 | Object.entries(metadata.apis) 45 | .filter(([_, api]) => !(api as any).isInternal) 46 | .forEach(([apiName, api]) => { 47 | sections.push(`### \`${apiName}\`\n${(api as any).description}`); 48 | }); 49 | } 50 | 51 | // Add Context Variables section if there are any 52 | if (metadata.contextVars && Object.keys(metadata.contextVars).length > 0) { 53 | sections.push('\n## Context Variables'); 54 | 55 | Object.entries(metadata.contextVars) 56 | .filter(([_, contextVar]) => !(contextVar as any).isInternal) 57 | .forEach(([varName, contextVar]) => { 58 | sections.push(`### \`${varName}\`\n${(contextVar as any).description}`); 59 | }); 60 | } 61 | 62 | return sections.join('\n\n'); 63 | } 64 | 65 | export function generateAttrDescription(attrName: string, attrMd: ComponentPropertyMetadata) { 66 | let propText = `\`${attrName}\``; 67 | 68 | if (attrMd.isRequired) { 69 | propText += " (required)"; 70 | } 71 | 72 | propText += ": "; 73 | 74 | if (attrMd.description) { 75 | propText += attrMd.description; 76 | } 77 | 78 | if (attrMd.defaultValue !== undefined) { 79 | propText += `\n\nDefault: \`${attrMd.defaultValue}\``; 80 | } 81 | 82 | if (attrMd.availableValues && attrMd.availableValues.length > 0) { 83 | const values = attrMd.availableValues.map(v => 84 | typeof v === 'object' ? 85 | `- \`${v.value}\`: ${v.description}` : 86 | `- \`${v}\`` 87 | ).join('\n'); 88 | propText += `\n\n**Allowed values**:\n${values}`; 89 | } 90 | 91 | return propText; 92 | } 93 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Card/Card.md: -------------------------------------------------------------------------------- ```markdown 1 | %-desc-START 2 | 3 | **Key features:** 4 | - **Pre-styled elements**: Built-in support for `title`, `subtitle`, and `avatarUrl` properties 5 | - **Flexible layout**: Choose `vertical` (default) or `horizontal` orientation 6 | - **Visual grouping**: Automatic styling with background, borders, and spacing 7 | - **Clickable areas**: Supports click events for interactive cards 8 | ## Using Card 9 | 10 | `Card` is a container; it does not have any explicit properties. 11 | You can nest the card's content into the `<Card>` tag: 12 | 13 | ```xmlui-pg copy display name="Example: using Card" 14 | <App> 15 | <Card maxWidth="200px"> 16 | <HStack verticalAlignment="center"> 17 | <Icon name="info" /> 18 | <Text value="Information" variant="strong" /> 19 | </HStack> 20 | <Text value="This is an example text" /> 21 | </Card> 22 | </App> 23 | ``` 24 | 25 | There are also prestyled properties one can make use of, detailed in the [Properties section](#properties). 26 | Prestyled elements always appear above other children. 27 | 28 | ```xmlui-pg copy display name="Example: using Card with prestyled elements" 29 | <App> 30 | <Card 31 | avatarUrl="https://i.pravatar.cc/100" 32 | title="Example Title" 33 | subtitle="Predefined subtitle" 34 | maxWidth="300px"> 35 | <HStack verticalAlignment="center"> 36 | <Icon name="info"/> 37 | This is a card 38 | </HStack> 39 | </Card> 40 | </App> 41 | ``` 42 | 43 | %-DESC-END 44 | 45 | %-PROP-START showAvatar 46 | 47 | Note that in the demo below if the `avatarUrl` is specified, `showAvatar` is automatically set to true but can still be hidden. 48 | 49 | ```xmlui-pg copy display name="Example: showAvatar" 50 | <App> 51 | <Card maxWidth="300px" avatarUrl="https://i.pravatar.cc/100" /> 52 | <Card maxWidth="300px" showAvatar="true" title="Example Card" /> 53 | <Card maxWidth="300px" showAvatar="true" /> 54 | </App> 55 | ``` 56 | 57 | %-PROP-END 58 | 59 | %-PROP-START subtitle 60 | 61 | This prop sets the prestyled subtitle. 62 | 63 | ```xmlui-pg copy display name="Example: subtitle" 64 | <App> 65 | <Card maxWidth="300px" subtitle="Example Subtitle" /> 66 | </App> 67 | ``` 68 | 69 | %-PROP-END 70 | 71 | %-PROP-START title 72 | 73 | This prop sets the prestyled title. 74 | 75 | ```xmlui-pg copy display name="Example: title" 76 | <App> 77 | <Card maxWidth="300px" title="Example Title" /> 78 | </App> 79 | ``` 80 | 81 | %-PROP-END 82 | 83 | %-PROP-START orientation 84 | 85 | ```xmlui-pg copy display name="Example: orientation" 86 | <App> 87 | <Card title="Example Title" subtitle="Example Subtitle" orientation="horizontal"> 88 | <SpaceFiller /> 89 | <Text>Text child #1</Text> 90 | <Text>Text child #2</Text> 91 | <Button label="Button Child" /> 92 | </Card> 93 | </App> 94 | ``` 95 | 96 | %-PROP-END 97 | 98 | %-EVENT-START click 99 | 100 | This event is triggered when the `Card` is clicked. 101 | 102 | ```xmlui-pg copy display name="Example: click" 103 | <App> 104 | <Card maxWidth="300px" onClick="toast('Clicked!')"> 105 | <HStack verticalAlignment="center"> 106 | <Icon name="info" /> 107 | <Text value="Information" variant="strong" /> 108 | </HStack> 109 | <Text value="This is an example text" /> 110 | </Card> 111 | </App> 112 | ``` 113 | 114 | %-EVENT-END 115 | ```