This is page 8 of 179. Use http://codebase.md/xmlui-org/xmlui?lines=true&page={x} to view the full context. # Directory Structure ``` ├── .changeset │ ├── cold-items-taste.md │ ├── config.json │ ├── empty-spiders-dress.md │ ├── shy-windows-allow.md │ ├── sour-coins-read.md │ ├── tame-zebras-invite.md │ ├── three-ideas-invent.md │ ├── twenty-jeans-watch.md │ ├── warm-spies-melt.md │ └── whole-ways-cry.md ├── .eslintrc.cjs ├── .github │ ├── build-checklist.png │ ├── ISSUE_TEMPLATE │ │ ├── bug_report.md │ │ └── feature_request.md │ └── workflows │ ├── 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 │ │ ├── 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 │ │ │ └── PageNotFound.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 ├── 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 │ ├── actions.md │ ├── AppRoot.md │ ├── component-apis.md │ ├── component-rendering.md │ ├── component-review-checklist.md │ ├── containers.md │ ├── data-sources.md │ ├── e2e-summary.md │ ├── expression-evaluation.md │ ├── glossary.md │ ├── helper-components.md │ ├── index.md │ ├── loaders.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 │ ├── rendering-fundamentals.md │ ├── reusable-components.md │ ├── standalone-apps.md │ ├── state-management.md │ └── xmlui-extensibility.xlsx ├── 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 │ │ │ ├── BehaviorContext.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/src/components/Fragment/Fragment.spec.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { expect, test } from "../../testing/fixtures"; 2 | 3 | // ============================================================================= 4 | // BASIC FUNCTIONALITY TESTS 5 | // ============================================================================= 6 | 7 | test.describe("Basic Functionality", () => { 8 | test("parent has items", async ({ page, initTestBed }) => { 9 | const expectedChildCount = 3; 10 | const expectedChildrenDisplay = ["Item #1", "Item #2", "Item #3"]; 11 | 12 | await initTestBed(` 13 | <Stack testId="container"> 14 | <Fragment> 15 | <Text value='Item #1' /> 16 | <Text value='Item #2' /> 17 | <Text value='Item #3' /> 18 | </Fragment> 19 | </Stack>`); 20 | 21 | const children = page.locator(`[data-testid="container"] > *`); 22 | await expect(children).toHaveCount(expectedChildCount); 23 | await expect(children).toHaveText(expectedChildrenDisplay); 24 | }); 25 | 26 | test("parent style affects children", async ({ page, initTestBed }) => { 27 | const expectedFontSize = "14px"; 28 | await initTestBed(` 29 | <Stack testId="container" fontSize="${expectedFontSize}"> 30 | <Fragment> 31 | <Text value='Item #1' /> 32 | <Text value='Item #2' /> 33 | <Text value='Item #3' /> 34 | </Fragment> 35 | </Stack>`, 36 | { 37 | testThemeVars: { 38 | "font-size": "16px", 39 | }, 40 | }, 41 | ); 42 | for (const child of await page.locator(`[data-testid="container"] > *`).all()) { 43 | await expect(child).toHaveCSS("font-size", expectedFontSize); 44 | } 45 | }); 46 | }); 47 | ``` -------------------------------------------------------------------------------- /tools/create-app/create-app.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { green } from "picocolors"; 2 | import path from "path"; 3 | import { makeDir } from "./helpers/make-dir"; 4 | import { tryGitInit } from "./helpers/git"; 5 | import { isFolderEmpty } from "./helpers/is-folder-empty"; 6 | import { isWriteable } from "./helpers/is-writeable"; 7 | import type { PackageManager } from "./helpers/get-pkg-manager"; 8 | 9 | import type { TemplateType } from "./templates"; 10 | import { installTemplate } from "./templates"; 11 | 12 | export async function createApp({ 13 | appPath, 14 | packageManager, 15 | useGit 16 | }: { 17 | appPath: string; 18 | packageManager: PackageManager; 19 | useGit: boolean; 20 | }): Promise<void> { 21 | const template: TemplateType = "default"; 22 | const root = path.resolve(appPath); 23 | 24 | if (!(await isWriteable(path.dirname(root)))) { 25 | console.error("The application path is not writable, please check folder permissions and try again."); 26 | console.error("It is likely you do not have write permissions for this folder."); 27 | process.exit(1); 28 | } 29 | 30 | const appName = path.basename(root); 31 | 32 | await makeDir(root); 33 | if (!isFolderEmpty(root, appName)) { 34 | process.exit(1); 35 | } 36 | 37 | console.log(`Creating a new UI Engine app in ${green(root)}.`); 38 | console.log(); 39 | 40 | process.chdir(root); 41 | 42 | await installTemplate({ 43 | appName, 44 | root, 45 | template, 46 | packageManager, 47 | useGit 48 | }); 49 | 50 | if (useGit && tryGitInit(root)) { 51 | console.log("Initialized a git repository."); 52 | console.log(); 53 | } 54 | console.log(`${green("Success!")} Created ${appName} at ${appPath}`); 55 | 56 | console.log(); 57 | } 58 | ``` -------------------------------------------------------------------------------- /blog/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "xmlui-blog", 3 | "private": true, 4 | "version": "0.0.9", 5 | "scripts": { 6 | "start": "echo '====================================================================\nExecuting \"npm run watch-docs-content\" in the project root,\nyou get automatic content generation based on xmlui metadata!\n====================================================================\n' && xmlui start", 7 | "preview": "xmlui preview", 8 | "gen:releases": "node scripts/get-releases.js --output 'public/resources/files/releases.json'", 9 | "gen:download-latest-xmlui-release": "node scripts/download-latest-xmlui.js", 10 | "gen:rss": "node scripts/generate-rss.js", 11 | "build:docs": "xmlui build --buildMode=INLINE_ALL --withMock && npm run gen:download-latest-xmlui-release && npm run gen:rss", 12 | "build-optimized": "npx xmlui-optimizer", 13 | "release-ci-optimized": "npm run build-optimized && xmlui zip-dist --source=xmlui-optimized-output --target=ui-optimized.zip", 14 | "preview-optimized": "npx serve@latest ./xmlui-optimized-output" 15 | }, 16 | "dependencies": { 17 | "@shikijs/langs": "3.4.2", 18 | "shiki": "^3.3.0", 19 | "xmlui": "*", 20 | "xmlui-playground": "*", 21 | "xmlui-search": "*", 22 | "xmlui-hello-world": "*" 23 | }, 24 | "msw": { 25 | "workerDirectory": [ 26 | "public" 27 | ] 28 | }, 29 | "devDependencies": { 30 | "@emotion/is-prop-valid": "^1.3.1", 31 | "@octokit/rest": "^22.0.0", 32 | "remark-parse": "11.0.0", 33 | "remark-stringify": "11.0.0", 34 | "strip-markdown": "6.0.0", 35 | "unified": "11.0.5" 36 | } 37 | } 38 | ``` -------------------------------------------------------------------------------- /docs/public/pages/howto/make-a-set-of-equal-width-cards.md: -------------------------------------------------------------------------------- ```markdown 1 | # Make a set of equal-width cards 2 | 3 | ```xmlui-pg noHeader 4 | ---app 5 | <App> 6 | <Test /> 7 | </App> 8 | ---api 9 | { 10 | "apiUrl": "/api", 11 | "initialize": "$state.dashboard_stats = { 12 | \"draft_invoices\":6, 13 | \"outstanding\":3502.9, 14 | \"paid_invoices\":79, 15 | \"paid_this_year\":1745.18, 16 | \"sent_invoices\":43, 17 | \"total_clients\":30, 18 | \"total_invoices\":91 19 | }", 20 | "operations": { 21 | "get-dashboard-stats": { 22 | "url": "/dashboard_stats", 23 | "method": "get", 24 | "handler": "$state.dashboard_stats" 25 | } 26 | } 27 | } 28 | ---comp display 29 | <Component name="Test" > 30 | 31 | <DataSource id="dashboard_stats" url="/api/dashboard_stats" method="GET" /> 32 | 33 | <FlowLayout> 34 | <InfoCard 35 | width="*" <!-- use star sizing --> 36 | title="Outstanding" 37 | value="{ dashboard_stats.value.outstanding }" 38 | /> 39 | <InfoCard 40 | width="*" 41 | title="Paid This Year" 42 | value="{ dashboard_stats.value.paid_this_year }" 43 | /> 44 | <InfoCard 45 | width="*" 46 | title="Draft" 47 | value="{ dashboard_stats.value.draft_invoices }" 48 | 49 | /> 50 | <InfoCard 51 | width="*" 52 | title="Sent" 53 | value="{ dashboard_stats.value.sent_invoices }" 54 | /> 55 | </FlowLayout> 56 | 57 | </Component> 58 | ---comp display 59 | <Component name="InfoCard"> 60 | 61 | <Card width="{$props.width}" borderRadius="8px" boxShadow="$boxShadow-spread"> 62 | 63 | <Text>{$props.title}</Text> 64 | 65 | <Text fontWeight="$fontWeight-extra-bold" fontSize="larger"> 66 | { $props.value } 67 | </Text> 68 | </Card> 69 | 70 | </Component> 71 | ``` 72 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Tabs/TabContext.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { createContext, useContext, useMemo, useState } from "react"; 2 | import produce from "immer"; 3 | 4 | import { EMPTY_ARRAY } from "../../components-core/constants"; 5 | import type { Tab } from "../abstractions"; 6 | 7 | type TabItem = Tab & { innerId: string }; 8 | 9 | interface ITabContext{ 10 | register: (tabItem: TabItem) => void; 11 | unRegister: (innerId: string) => void; 12 | activeTabId: string; 13 | } 14 | export const TabContext = createContext<ITabContext>({ 15 | register: (tabItem) => {}, 16 | unRegister: (innerId: string) => {}, 17 | activeTabId: "", 18 | }); 19 | 20 | export function useTabContextValue() { 21 | const [tabItems, setTabItems] = useState<TabItem[]>(EMPTY_ARRAY); 22 | const [activeTabId, setActiveTabId] = useState<string>(""); 23 | const tabContextValue = useMemo(() => { 24 | return { 25 | register: (tabItem: TabItem) => { 26 | setTabItems( 27 | produce((draft) => { 28 | const existing = draft.findIndex((col) => col.innerId === tabItem.innerId); 29 | if (existing < 0) { 30 | draft.push(tabItem); 31 | } else { 32 | draft[existing] = tabItem; 33 | } 34 | }), 35 | ); 36 | }, 37 | unRegister: (innerId: string) => { 38 | setTabItems( 39 | produce((draft) => { 40 | return draft.filter((col) => col.innerId !== innerId); 41 | }), 42 | ); 43 | }, 44 | activeTabId, 45 | setActiveTabId, 46 | }; 47 | }, [activeTabId]); 48 | 49 | return { 50 | tabItems, 51 | tabContextValue, 52 | }; 53 | } 54 | 55 | export function useTabContext() { 56 | return useContext(TabContext); 57 | } 58 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/EmojiSelector/EmojiSelectorNative.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { forwardRef } from "react"; 2 | import type { Theme as EmojiPickerTheme } from "emoji-picker-react"; 3 | import EmojiPicker, { EmojiStyle } from "emoji-picker-react"; 4 | import type { AsyncFunction } from "../../abstractions/FunctionDefs"; 5 | import { noop } from "../../components-core/constants"; 6 | 7 | // ===================================================================================================================== 8 | // React EmojiSelector component implementation 9 | 10 | export type EmojiSelectorProps = { 11 | theme?: EmojiPickerTheme; 12 | select?: AsyncFunction; 13 | autoFocus?: boolean; 14 | }; 15 | 16 | export const defaultProps: Pick<EmojiSelectorProps, "theme" | "select" | "autoFocus"> = { 17 | theme: "light" as EmojiPickerTheme, 18 | select: noop, 19 | autoFocus: false, 20 | }; 21 | 22 | export const EmojiSelector = forwardRef<HTMLDivElement, EmojiSelectorProps>( 23 | ( 24 | { 25 | select = defaultProps.select, 26 | theme = defaultProps.theme, 27 | autoFocus = defaultProps.autoFocus, 28 | ...rest 29 | }, 30 | ref, 31 | ) => ( 32 | <div 33 | {...rest} 34 | ref={ref} 35 | style={{ display: "inline-block", width: "fit-content", height: "fit-content" }} 36 | > 37 | <EmojiPicker 38 | autoFocusSearch={autoFocus} 39 | onEmojiClick={async (emojiObject) => { 40 | await select(emojiObject.emoji); 41 | }} 42 | lazyLoadEmojis={true} 43 | theme={theme} 44 | previewConfig={{ showPreview: false }} 45 | skinTonesDisabled={true} 46 | height={360} 47 | emojiStyle={EmojiStyle.NATIVE} 48 | /> 49 | </div> 50 | ), 51 | ); 52 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/App/SearchContext.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { createContext, useContextSelector } from "use-context-selector"; 2 | import { useCallback, useMemo, useState } from "react"; 3 | import { EMPTY_OBJECT } from "../../components-core/constants"; 4 | 5 | type SearchEntry = { path: string; title: string; content: string }; 6 | 7 | type ISearchContext = { 8 | content: Record<string, SearchEntry>; 9 | storeContent: ({ path, title, content }: SearchEntry) => void; 10 | isIndexing: boolean; 11 | setIsIndexing: (isIndexing: boolean) => void; 12 | }; 13 | 14 | const SearchContext = createContext<ISearchContext | null>(null); 15 | 16 | export const SearchContextProvider = ({children})=>{ 17 | const [content, setContent] = useState<Record<string, SearchEntry>>(EMPTY_OBJECT); 18 | const [isIndexing, setIsIndexing] = useState(true); 19 | const storeContent = useCallback((entry: SearchEntry) => { 20 | setContent((prevContent) => ({ 21 | ...prevContent, 22 | [entry.path]: entry, 23 | })); 24 | }, []); 25 | 26 | const value = useMemo(()=>({ 27 | content, 28 | storeContent, 29 | isIndexing, 30 | setIsIndexing 31 | }), [content, isIndexing, storeContent]); 32 | 33 | return <SearchContext.Provider value={value}>{children}</SearchContext.Provider> 34 | }; 35 | 36 | export const useSearchContextUpdater = () => { 37 | return useContextSelector(SearchContext, (value) => value.storeContent); 38 | }; 39 | 40 | export const useSearchContextContent = () => { 41 | return useContextSelector(SearchContext, (value) => value?.content); 42 | }; 43 | 44 | export const useSearchContextSetIndexing = () => { 45 | return useContextSelector(SearchContext, (value) => value.setIsIndexing); 46 | }; 47 | 48 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/FlowLayout/FlowLayout.module.scss: -------------------------------------------------------------------------------- ```scss 1 | @use "../../components-core/theming/themes" as t; 2 | 3 | // --- This code snippet is required to collect the theme variables used in this module 4 | $themeVars: (); 5 | @function createThemeVar($componentVariable) { 6 | $themeVars: t.appendThemeVar($themeVars, $componentVariable) !global; 7 | @return t.getThemeVar($themeVars, $componentVariable); 8 | } 9 | 10 | @layer components { 11 | .outer { 12 | contain: layout; 13 | } 14 | 15 | .flowContainer { 16 | display: flex; 17 | flex-wrap: wrap; 18 | 19 | &.horizontal { 20 | flex-direction: row; 21 | 22 | .flowItem { 23 | flex-shrink: 0; 24 | 25 | & > * { 26 | width: 100% !important; //reset the wrapped content's width-like properties to their default 27 | min-width: 0 !important; 28 | max-width: none !important; 29 | } 30 | } 31 | } 32 | 33 | &.vertical { 34 | height: 100%; 35 | flex-direction: column; 36 | align-content: flex-start; 37 | 38 | .flowItem { 39 | width: auto; 40 | flex-shrink: 0; 41 | 42 | & > * { 43 | height: auto !important; 44 | min-height: 0 !important; 45 | max-height: none !important; 46 | } 47 | } 48 | } 49 | } 50 | 51 | //we use the .break class to create a new line in the flow 52 | // if there are multiple star-sized elements in a row, the break will be ignored between them 53 | .break:not(.forceBreak):has(+ .starSized) { 54 | display: none; 55 | } 56 | 57 | .break, 58 | .forceBreak { 59 | flex-basis: 100%; 60 | height: 0; 61 | } 62 | } 63 | 64 | // --- We export the theme variables to add them to the component renderer 65 | :export { 66 | themeVars: t.json-stringify($themeVars); 67 | } 68 | ``` -------------------------------------------------------------------------------- /xmlui/src/components-core/utils/DataLoaderQueryKeyGenerator.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { isEqual } from "lodash-es"; 2 | import type { Query, QueryKey } from "@tanstack/react-query"; 3 | 4 | // base on this: https://tkdodo.eu/blog/effective-react-query-keys 5 | 6 | type UrlKeyPart = string; 7 | type UrlQueryParamsPart = Record<string, any>; 8 | 9 | type DataLoaderQueryKey = [UrlKeyPart, UrlQueryParamsPart?]; 10 | 11 | export class DataLoaderQueryKeyGenerator { 12 | private readonly url: UrlKeyPart; 13 | private readonly queryParams?: UrlQueryParamsPart; 14 | private key?: DataLoaderQueryKey; 15 | 16 | constructor( 17 | url: UrlKeyPart, 18 | queryParams: UrlQueryParamsPart | undefined, 19 | apiUrl: string | undefined, 20 | body: any, 21 | rawBody: any, 22 | ) { 23 | this.url = url; 24 | this.queryParams = queryParams; 25 | this.key = [url]; 26 | if (queryParams) { 27 | this.key.push(queryParams); 28 | } 29 | if (apiUrl) { 30 | this.key.push(apiUrl); 31 | } 32 | if (body) { 33 | this.key.push(body); 34 | } 35 | if (rawBody) { 36 | this.key.push(rawBody); 37 | } 38 | } 39 | 40 | asKey() { 41 | if (!this.key) { 42 | throw new Error("no key defined"); 43 | } 44 | return this.key; 45 | } 46 | 47 | asPredicate(): { 48 | predicate: (query: Query<unknown, unknown, unknown, QueryKey>) => boolean; 49 | } { 50 | if (!this.key) { 51 | throw new Error("no key defined"); 52 | } 53 | return { 54 | predicate: (query: Query<unknown, unknown, unknown, QueryKey>) => { 55 | const queryKey = query.queryKey as DataLoaderQueryKey; 56 | return ( 57 | queryKey[0] === this.url && (!this.queryParams || isEqual(queryKey[1], this.queryParams)) 58 | ); 59 | }, 60 | }; 61 | } 62 | } 63 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/ProgressBar/ProgressBar.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import styles from "./ProgressBar.module.scss"; 2 | 3 | import { createComponentRenderer } from "../../components-core/renderers"; 4 | import { parseScssVar } from "../../components-core/theming/themeVars"; 5 | import { ProgressBar, defaultProps } from "./ProgressBarNative"; 6 | import { createMetadata } from "../metadata-helpers"; 7 | 8 | const COMP = "ProgressBar"; 9 | 10 | export const ProgressBarMd = createMetadata({ 11 | status: "stable", 12 | description: 13 | "`ProgressBar` provides a visual indicator showing the completion percentage " + 14 | "of tasks, processes, or any measurable progress. It displays as a horizontal " + 15 | "bar that fills from left to right based on the provided value between 0 " + 16 | "(empty) and 1 (complete).", 17 | props: { 18 | value: { 19 | description: `This property defines the progress value with a number between 0 and 1.`, 20 | valueType: "number", 21 | defaultValue: defaultProps.value, 22 | }, 23 | }, 24 | themeVars: parseScssVar(styles.themeVars), 25 | defaultThemeVars: { 26 | [`borderRadius-${COMP}`]: "$borderRadius", 27 | [`borderRadius-indicator-${COMP}`]: "0px", 28 | [`thickness-${COMP}`]: "$space-2", 29 | [`backgroundColor-${COMP}`]: "$color-surface-200", 30 | [`color-indicator-${COMP}`]: "$color-primary-500", 31 | }, 32 | }); 33 | 34 | export const progressBarComponentRenderer = createComponentRenderer( 35 | COMP, 36 | ProgressBarMd, 37 | ({ node, extractValue, className }) => { 38 | return ( 39 | <ProgressBar 40 | value={Math.max(0, Math.min(1, extractValue(node.props.value)))} 41 | className={className} 42 | /> 43 | ); 44 | }, 45 | ); 46 | ``` -------------------------------------------------------------------------------- /tools/vscode/src/extension.ts: -------------------------------------------------------------------------------- ```typescript 1 | import * as path from 'path'; 2 | import { ExtensionContext, } from 'vscode'; 3 | 4 | import { 5 | LanguageClient, 6 | LanguageClientOptions, 7 | ServerOptions, 8 | TransportKind 9 | } from 'vscode-languageclient/node'; 10 | 11 | let client: LanguageClient; 12 | 13 | export function activate(context: ExtensionContext) { 14 | const serverModule = getPathToLangServer(context); 15 | 16 | // If the extension is launched in debug mode then the debug server options are used 17 | // Otherwise the run options are used 18 | const serverOptions: ServerOptions = { 19 | run: { module: serverModule, transport: TransportKind.ipc }, 20 | debug: { 21 | module: serverModule, 22 | transport: TransportKind.ipc, 23 | } 24 | }; 25 | 26 | // Options to control the language client 27 | const clientOptions: LanguageClientOptions = { 28 | documentSelector: [ { language: 'xmlui' } ] 29 | }; 30 | 31 | // Create the language client and start the client. 32 | client = new LanguageClient( 33 | 'XMLUILanguageService', 34 | 'XMLUI Language Service', 35 | serverOptions, 36 | clientOptions 37 | ); 38 | 39 | // Start the client. This will also launch the server 40 | client.start(); 41 | } 42 | 43 | export function deactivate(): Thenable<void> | undefined { 44 | if (!client) { 45 | return undefined; 46 | } 47 | return client.stop(); 48 | } 49 | 50 | function getPathToLangServer(context: ExtensionContext) { 51 | const localLangServPath = null; 52 | if (!localLangServPath){ 53 | const bundledLangServPath = context.asAbsolutePath(path.join('dist', 'server.js')); 54 | console.log({ bundledLangServPath }); 55 | return bundledLangServPath; 56 | } 57 | return localLangServPath; 58 | } 59 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Charts/Tooltip/TooltipContent.module.scss: -------------------------------------------------------------------------------- ```scss 1 | @use "xmlui/themes.scss" as t; 2 | 3 | // --- This code snippet is required to collect the theme variables used in this module 4 | $themeVars: (); 5 | @function createThemeVar($componentVariable) { 6 | $themeVars: t.appendThemeVar($themeVars, $componentVariable) !global; 7 | @return t.getThemeVar($themeVars, $componentVariable); 8 | } 9 | 10 | $componentName: "TooltipContent"; 11 | 12 | @layer components { 13 | .tooltipContainer { 14 | display: grid; 15 | min-width: 8rem; 16 | align-items: start; 17 | gap: 1.5px; 18 | border-radius: 8px; 19 | background: t.$backgroundColor-secondary; 20 | padding: 0.4rem; 21 | font-size: 0.75rem; 22 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); 23 | } 24 | 25 | .gridGap { 26 | display: grid; 27 | gap: 1.5px; 28 | } 29 | 30 | .labelGrid { 31 | display: grid; 32 | gap: 1.5px; 33 | } 34 | 35 | .itemContainer { 36 | display: flex; 37 | width: 100%; 38 | flex-wrap: wrap; 39 | align-items: center; 40 | gap: 4px; 41 | } 42 | 43 | .valueContainer { 44 | display: flex; 45 | flex: 1; 46 | gap: t.$space-2; 47 | justify-content: space-between; 48 | align-items: center; 49 | } 50 | 51 | .indicator { 52 | flex-shrink: 0; 53 | border-radius: 2px; 54 | } 55 | 56 | .dot { 57 | width: 10px; 58 | height: 10px; 59 | } 60 | 61 | .line { 62 | width: 4px; 63 | } 64 | 65 | .dashed { 66 | width: 0; 67 | border: 1.5px dashed; 68 | background: transparent; 69 | } 70 | } 71 | 72 | .mutedText { 73 | color: t.$textColor-secondary; 74 | font-size: 0.75rem; 75 | } 76 | 77 | .valueText { 78 | color: t.$textColor-primary; 79 | font-weight: 500; 80 | font-size: 0.75rem; 81 | } 82 | 83 | // --- We export the theme variables to add them to the component renderer 84 | :export { 85 | themeVars: t.json-stringify($themeVars); 86 | } 87 | ``` -------------------------------------------------------------------------------- /xmlui/tests-e2e/datasource-and-api-usage-in-var.spec.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { expect, test } from "../src/testing/fixtures"; 2 | 3 | test("regression: datasource usage in compound component var", async ({ page, initTestBed }) => { 4 | await initTestBed(`<TestComp />`, { 5 | components: [ 6 | ` 7 | <Component name="TestComp"> 8 | <Fragment var.sortFiles="{(files)=> files}"> 9 | <DataSource url="/data1" id="datasource"/> 10 | <variable name="x" value="{datasource.value.listing[0].name + '_transformed'}"/> 11 | <Text testId="transformed_text" value="{x}"/> 12 | </Fragment> 13 | </Component> 14 | `, 15 | ], 16 | apiInterceptor: { 17 | operations: { 18 | "load-api-data1": { 19 | url: "/data1", 20 | method: "get", 21 | handler: `() => { return {listing: [{name: 'data1'}]}; }`, 22 | }, 23 | }, 24 | }, 25 | }); 26 | await expect(page.getByTestId("transformed_text")).toHaveText("data1_transformed"); 27 | }); 28 | 29 | test("regression: api usage in compound component var", async ({ page, initTestBed }) => { 30 | await initTestBed(`<TestComp />`, { 31 | components: [ 32 | ` 33 | <Component name="TestComp"> 34 | <Stack var.itemsInVar="{uploadQueue.getQueuedItems()}"> 35 | <Queue id="uploadQueue" clearAfterFinish="false"/> 36 | <Button onClick="uploadQueue.enqueueItems([1, 2, 3])" testId="button">add to queue</Button> 37 | <Text testId="result">{itemsInVar.map(item => item.item)}</Text> 38 | </Stack> 39 | </Component> 40 | `, 41 | ], 42 | }); 43 | await page.getByTestId("button").click(); 44 | await expect(page.getByTestId("result")).toHaveText("123"); 45 | }); 46 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Icon/svg/xls.svg: -------------------------------------------------------------------------------- ``` 1 | <svg width="22" height="28" viewBox="0 0 22 28" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path d="M21.9982 7.38281L16.0756 5.74219L14.3835 0H1.69217C0.757586 0 0 0.734508 0 1.64062V26.3594C0 27.2655 0.757586 28 1.69217 28H20.3061C21.2407 28 21.9982 27.2655 21.9982 26.3594V7.38281Z" fill="#59C36A"/> 3 | <path d="M21.9982 7.38281V26.3594C21.9982 27.2655 21.2406 28 20.306 28H11.1345V0H14.3834L16.0756 5.74219L21.9982 7.38281Z" fill="#59C36A"/> 4 | <path d="M16.0753 11.5391H5.92226C5.4546 11.5391 5.07617 11.906 5.07617 12.3594V22.2031C5.07617 22.6565 5.4546 23.0234 5.92226 23.0234H16.0753C16.543 23.0234 16.9214 22.6565 16.9214 22.2031V12.3594C16.9214 11.906 16.543 11.5391 16.0753 11.5391ZM6.76834 16.4609H10.1527V18.1016H6.76834V16.4609ZM11.8449 16.4609H15.2292V18.1016H11.8449V16.4609ZM15.2292 14.8203H11.8449V13.1797H15.2292V14.8203ZM10.1527 13.1797V14.8203H6.76834V13.1797H10.1527ZM6.76834 19.7422H10.1527V21.3828H6.76834V19.7422ZM11.8449 21.3828V19.7422H15.2292V21.3828H11.8449Z" fill="white"/> 5 | <path d="M16.0758 11.5391H11.1365V23.0234H16.0758C16.5435 23.0234 16.9219 22.6565 16.9219 22.2031V12.3594C16.9219 11.906 16.5435 11.5391 16.0758 11.5391ZM15.2297 21.3828H11.8454V19.7422H15.2297V21.3828ZM15.2297 18.1016H11.8454V16.4609H15.2297V18.1016ZM15.2297 14.8203H11.8454V13.1797H15.2297V14.8203Z" fill="white"/> 6 | <path d="M21.9995 7.38281H16.0769C15.1462 7.38281 14.3848 6.64453 14.3848 5.74219V0C14.6047 0 14.8247 0.0820312 14.977 0.246148L21.7457 6.80865C21.9149 6.95625 21.9995 7.16953 21.9995 7.38281Z" fill="#A0DEB0"/> 7 | </svg> 8 | ``` -------------------------------------------------------------------------------- /packages/xmlui-website-blocks/src/Carousel/CarouselContext.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { createContext, useContext, useMemo, useState } from "react"; 2 | import produce from "immer"; 3 | 4 | interface CarouselItem { 5 | id: string; 6 | [key: string]: any; 7 | } 8 | 9 | export const CarouselContext = createContext({ 10 | register: (column: CarouselItem) => {}, 11 | unRegister: (id: string) => {}, 12 | itemProps: {}, 13 | }); 14 | 15 | export const useCarousel = () => { 16 | const context = useContext(CarouselContext); 17 | if (!context) { 18 | throw new Error("useCarousel must be used within a Carousel"); 19 | } 20 | return context; 21 | }; 22 | 23 | export function useCarouselContextValue(isTabbed: boolean) { 24 | const [carouselItems, setCarouselItems] = useState<CarouselItem[]>([]); 25 | 26 | const carouselContextValue = useMemo(() => { 27 | return { 28 | register: (column: CarouselItem) => { 29 | setCarouselItems( 30 | produce((draft: CarouselItem[]) => { 31 | const existing = draft.findIndex((col) => col.id === column.id); 32 | if (existing < 0) { 33 | draft.push(column); 34 | } else { 35 | draft[existing] = column; 36 | } 37 | }), 38 | ); 39 | }, 40 | unRegister: (id: string) => { 41 | setCarouselItems( 42 | produce((draft) => { 43 | return draft.filter((col) => col.id !== id); 44 | }), 45 | ); 46 | }, 47 | itemProps: isTabbed 48 | ? { 49 | role: "group tabpanel", 50 | } 51 | : { 52 | role: "group", 53 | "aria-roledescription": "slide", 54 | }, 55 | }; 56 | }, [setCarouselItems, isTabbed]); 57 | 58 | return { 59 | carouselItems, 60 | carouselContextValue, 61 | }; 62 | } 63 | ``` -------------------------------------------------------------------------------- /docs/public/pages/xmlui-charts/PieChart.md: -------------------------------------------------------------------------------- ```markdown 1 | # PieChart [#piechart] 2 | 3 | >[!WARNING] 4 | > This component is in an **experimental** state; you can use it in your app. However, we may modify it, and it may even have breaking changes in the future.Represents a pie chart component. 5 | 6 | ## Properties 7 | 8 | ### `data` 9 | 10 | The data to be displayed in the chart. Needs to be an array of objects. 11 | 12 | ### `dataKeys` 13 | 14 | This property specifies the keys in the data objects that should be used for rendering the bars. 15 | 16 | ### `height` 17 | 18 | The height of the chart 19 | 20 | ### `labelListPosition (default: "inside")` 21 | 22 | The position of the label list. 23 | 24 | Available values: `top`, `left`, `right`, `bottom`, `inside` **(default)**, `outside`, `insideLeft`, `insideRight`, `insideTop`, `insideBottom`, `insideTopLeft`, `insideBottomLeft`, `insideTopRight`, `insideBottomRight`, `insideStart`, `insideEnd`, `end`, `center`, `centerTop`, `centerBottom`, `middle` 25 | 26 | ### `nameKey` 27 | 28 | Specifies the key in the data objects that will be used to label the different data series. 29 | 30 | ### `showLabel (default: true)` 31 | 32 | Toggles whether to show labels (`true`) or not (`false`). 33 | 34 | ### `showLabelList (default: false)` 35 | 36 | Whether to show labels in a list (`true`) or not (`false`). 37 | 38 | ### `width` 39 | 40 | The width of the chart 41 | 42 | ## Events 43 | 44 | This component does not have any events. 45 | 46 | ## Exposed Methods 47 | 48 | This component does not expose any methods. 49 | 50 | ## Styling 51 | 52 | ### Theme Variables 53 | 54 | | Variable | Default Value (Light) | Default Value (Dark) | 55 | | --- | --- | --- | 56 | | [textColor](../styles-and-themes/common-units/#color)-labelList-PieChart | $textColor-primary | $textColor-primary | 57 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Icon/svg/txt.svg: -------------------------------------------------------------------------------- ``` 1 | <svg width="22" height="28" viewBox="0 0 22 28" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <g clip-path="url(#clip0_1811_14941)"> 3 | <path d="M21.7881 7.38281L16.374 5.74219L14.8271 0H3.22559C2.37125 0 1.67871 0.734508 1.67871 1.64062V26.3594C1.67871 27.2655 2.37125 28 3.22559 28H20.2412C21.0956 28 21.7881 27.2655 21.7881 26.3594V7.38281Z" fill="#EDEDED"/> 4 | <path d="M21.7881 7.38281V26.3594C21.7881 27.2655 21.0955 28 20.2412 28H11.8572V0H14.8271L16.374 5.74219L21.7881 7.38281Z" fill="#EDEDED"/> 5 | <path d="M21.7881 7.38281H16.374C15.5232 7.38281 14.8271 6.64453 14.8271 5.74219V0C15.0282 0 15.2293 0.0820312 15.3685 0.246148L21.556 6.80865C21.7107 6.95625 21.7881 7.16953 21.7881 7.38281Z" fill="#BDBDBD"/> 6 | <path d="M20.5333 22.4259C20.5333 22.925 20.1483 23.3333 19.6778 23.3333H0.855556C0.385 23.3333 0 22.925 0 22.4259V13.3519C0 12.8528 0.385 12.4444 0.855556 12.4444H19.6778C20.1483 12.4444 20.5333 12.8528 20.5333 13.3519V22.4259Z" fill="#161C28"/> 7 | <path d="M4.62629 16.508V20H5.56828V16.508H6.85229V15.716H3.34229V16.508H4.62629Z" fill="white"/> 8 | <path d="M8.99625 17.756L7.50225 20H8.55825L9.51225 18.518L10.4483 20H11.5703L10.0763 17.762L11.4503 15.716H10.4183L9.54825 17.084L8.70825 15.716H7.61625L8.99625 17.756Z" fill="white"/> 9 | <path d="M13.4962 16.508V20H14.4382V16.508H15.7222V15.716H12.2122V16.508H13.4962Z" fill="white"/> 10 | </g> 11 | <defs> 12 | <clipPath id="clip0_1811_14941"> 13 | <rect width="22" height="28" fill="white"/> 14 | </clipPath> 15 | </defs> 16 | </svg> ``` -------------------------------------------------------------------------------- /docs/content/components/ToneSwitch.md: -------------------------------------------------------------------------------- ```markdown 1 | # ToneSwitch [#toneswitch] 2 | 3 | `ToneSwitch` enables the user to switch between light and dark modes using a switch control. 4 | 5 | ```xmlui-pg {4} copy display name="Example: using ToneSwitch" 6 | <App> 7 | <AppHeader> 8 | <SpaceFiller /> 9 | <ToneSwitch /> 10 | </AppHeader> 11 | <Card 12 | title="Tone Switch" 13 | subtitle="Toggle the switch to change the tone." 14 | /> 15 | </App> 16 | ``` 17 | 18 | ## Properties [#properties] 19 | 20 | ### `iconDark` (default: "moon") [#icondark-default-moon] 21 | 22 | Icon to display for dark mode 23 | 24 | ### `iconLight` (default: "sun") [#iconlight-default-sun] 25 | 26 | Icon to display for light mode 27 | 28 | ## Events [#events] 29 | 30 | This component does not have any events. 31 | 32 | ## Exposed Methods [#exposed-methods] 33 | 34 | This component does not expose any methods. 35 | 36 | ## Styling [#styling] 37 | 38 | ### Theme Variables [#theme-variables] 39 | 40 | | Variable | Default Value (Light) | Default Value (Dark) | 41 | | --- | --- | --- | 42 | | [backgroundColor](../styles-and-themes/common-units/#color)-ToneSwitch-dark | $color-primary-500 | $color-primary-500 | 43 | | [backgroundColor](../styles-and-themes/common-units/#color)-ToneSwitch-light | $color-surface-200 | $color-surface-700 | 44 | | [borderColor](../styles-and-themes/common-units/#color)-ToneSwitch | $color-surface-200 | $color-surface-600 | 45 | | [borderColor](../styles-and-themes/common-units/#color)-ToneSwitch--hover | $color-surface-300 | $color-surface-500 | 46 | | [color](../styles-and-themes/common-units/#color)-ToneSwitch-dark | $color-surface-0 | $color-surface-0 | 47 | | [color](../styles-and-themes/common-units/#color)-ToneSwitch-light | $color-text-primary | $color-text-primary | 48 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Icon/svg/admonition_warning.svg: -------------------------------------------------------------------------------- ``` 1 | <svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path d="M15.8283 6C16.5981 4.66667 18.5226 4.66667 19.2924 6L31.8498 27.75C32.6196 29.0833 31.6573 30.75 30.1177 30.75H5.00298C3.46338 30.75 2.50113 29.0833 3.27093 27.75L15.8283 6Z" fill="url(#paint0_linear_11265_27105)"/> 3 | <path d="M15.8278 6C16.5976 4.66667 18.5229 4.66667 19.2927 6L31.8493 27.75C32.595 29.0416 31.7158 30.646 30.2605 30.7451L30.1179 30.75V29.75C30.8875 29.7498 31.3687 28.9166 30.9841 28.25L18.4265 6.5C18.0657 5.87505 17.1975 5.83607 16.7731 6.38281L16.694 6.5L4.13643 28.25C3.75177 28.9166 4.23306 29.7498 5.00264 29.75V30.75L4.86006 30.7451C3.4517 30.6492 2.5826 29.1436 3.20381 27.876L3.2712 27.75L15.8278 6ZM30.1179 29.75V30.75H5.00264V29.75H30.1179Z" fill="#FFD93C"/> 4 | <path d="M18.9476 12.0938L18.7226 22.572H16.5272L16.309 12.0938H18.9476ZM17.6249 27.0938C17.2112 27.0938 16.8567 26.9392 16.5612 26.63C16.2703 26.3208 16.1249 25.944 16.1249 25.4995C16.1249 25.0648 16.2703 24.6928 16.5612 24.3836C16.8567 24.0744 17.2112 23.9198 17.6249 23.9198C18.0294 23.9198 18.3794 24.0744 18.6749 24.3836C18.9749 24.6928 19.1249 25.0648 19.1249 25.4995C19.1249 25.7942 19.0544 26.0623 18.9135 26.3039C18.7772 26.5454 18.5953 26.7387 18.3681 26.8836C18.1453 27.0237 17.8976 27.0938 17.6249 27.0938Z" fill="black"/> 5 | <defs> 6 | <linearGradient id="paint0_linear_11265_27105" x1="17.5604" y1="3" x2="17.5604" y2="40" gradientUnits="userSpaceOnUse"> 7 | <stop stop-color="#FFE980"/> 8 | <stop offset="0.932692" stop-color="#FFD93C"/> 9 | </linearGradient> 10 | </defs> 11 | </svg> 12 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Charts/LabelList/LabelList.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import styles from "./LabelListNative.module.scss"; 2 | import { defaultProps, LabelList } from "./LabelListNative"; 3 | import { LabelPositionValues } from "../utils/abstractions"; 4 | import { parseScssVar } from "../../../components-core/theming/themeVars"; 5 | import { createComponentRenderer } from "../../../components-core/renderers"; 6 | import { createMetadata } from "../../metadata-helpers"; 7 | 8 | const COMP = "LabelList"; 9 | 10 | export const LabelListMd = createMetadata({ 11 | status: "experimental", 12 | description: 13 | "`LabelList` adds custom data labels to chart components when automatic " + 14 | "labeling isn't sufficient. It's a specialized component for advanced chart " + 15 | "customization scenarios where you need precise control over label positioning " + 16 | "and appearance.", 17 | props: { 18 | key: { 19 | description: "The key that needs to be matched to the data series.", 20 | valueType: "string", 21 | }, 22 | position: { 23 | description: "The position of the label list", 24 | valueType: "string", 25 | availableValues: LabelPositionValues, 26 | defaultValue: defaultProps.position, 27 | }, 28 | }, 29 | themeVars: parseScssVar(styles.themeVars), 30 | defaultThemeVars: { 31 | "textColor-LabelList": "$textColor-primary", 32 | }, 33 | }); 34 | 35 | export const labelListComponentRenderer = createComponentRenderer( 36 | COMP, 37 | LabelListMd, 38 | ({ extractValue, node, className }: any) => { 39 | return ( 40 | <LabelList 41 | key={extractValue(node.props?.dataKey)} 42 | position={extractValue.asOptionalString(node.props?.position)} 43 | className={className} 44 | /> 45 | ); 46 | }, 47 | ); 48 | ``` -------------------------------------------------------------------------------- /docs/public/resources/files/downloads/downloads.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "engine": { 3 | "availableVersions": [ 4 | { 5 | "version": "0.9.51", 6 | "changelogs": [ 7 | "Added theme variable for setting the horizontal alignment of the logo in the NavPanel.", 8 | "Moved Drawer logo position to left.", 9 | "fix: Slider - min/max value validation", 10 | "fix: Markdown renders inline/block images correclty" 11 | ], 12 | "fileName": "xmlui-0.9.51.js", 13 | "fileSize": "3.81 MB" 14 | }, 15 | { 16 | "version": "0.9.50", 17 | "changelogs": [ 18 | "standalone usage: explicit codeBehind reference", 19 | "Make the \"marked\" Text variant have lighter background color in dark mode.", 20 | "Tweaked Search dropdown panel styles. Corrected Link component text and decoration hover and active colors" 21 | ], 22 | "fileName": "xmlui-0.9.51.js", 23 | "fileSize": "3.75 MB" 24 | }, 25 | { 26 | "version": "0.9.49", 27 | "changelogs": [ 28 | "Added new features for better user experience.", 29 | "Enhanced documentation and examples.", 30 | "Fixed issues with previous versions." 31 | ], 32 | "fileName": "xmlui-0.9.51.js", 33 | "fileSize": "3.70 MB" 34 | } 35 | ] 36 | }, 37 | "packages": [ 38 | { 39 | "name": "xmlui-search", 40 | "version": "0.1.3", 41 | "changelogs": [ 42 | "Tweaked Search dropdown panel styles. Corrected Link component text and decoration hover and active colors" 43 | ], 44 | "fileName": "xmlui-search-0.1.3.js", 45 | "fileSize": "3.70 MB" 46 | } 47 | ] 48 | } 49 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/AppHeader/AppHeader.md: -------------------------------------------------------------------------------- ```markdown 1 | %-DESC-START 2 | 3 | **Key features:** 4 | 5 | - **Logo customization**: Use `logoTemplate` to create rich logo designs beyond simple images 6 | - **Profile menu**: Add user authentication displays, settings menus, or action buttons via `profileMenuTemplate` 7 | - **Layout integration**: Automatically positioned and styled based on your App's `layout` property 8 | 9 | %-DESC-END 10 | 11 | %-PROP-START logoTemplate 12 | 13 | This property defines the template to use for the logo. 14 | With this property, you can construct your custom logo instead of using a single image. 15 | 16 | ```xmlui-pg copy display {3-8} name="Example: logoTemplate" height="170px" 17 | <App> 18 | <AppHeader> 19 | <property name="logoTemplate"> 20 | <H3> 21 | <Icon name="drive" /> 22 | DriveDiag 23 | </H3> 24 | </property> 25 | </AppHeader> 26 | <NavPanel> 27 | <NavLink label="Home" to="/" icon="home"/> 28 | <NavLink label="Page 1" to="/page1"/> 29 | </NavPanel> 30 | <Pages fallbackPath="/"> 31 | <Page url="/"> 32 | <Text value="Home" /> 33 | </Page> 34 | <Page url="/page1"> 35 | <Text value="Page 1" /> 36 | </Page> 37 | </Pages> 38 | </App> 39 | ``` 40 | 41 | %-PROP-END 42 | 43 | %-PROP-START profileMenuTemplate 44 | 45 | This property makes the profile menu slot of the `AppHeader` component customizable. 46 | It accepts component definitions. 47 | 48 | ```xmlui-pg copy display {3-9} name="Example: profileMenuTemplate" height="150px" 49 | <App> 50 | <AppHeader> 51 | <property name="profileMenuTemplate"> 52 | <DropdownMenu> 53 | <property name="triggerTemplate"> 54 | <Avatar name="Joe" size="xs" borderRadius="50%"/> 55 | </property> 56 | </DropdownMenu> 57 | </property> 58 | </AppHeader> 59 | </App> 60 | ``` 61 | 62 | %-PROP-END 63 | ``` -------------------------------------------------------------------------------- /packages/xmlui-playground/src/playground/ConfirmationDialog.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import * as AlertDialog from "@radix-ui/react-alert-dialog"; 2 | import styles from "./ConfirmationDialog.module.scss"; 3 | import classnames from "classnames"; 4 | import { useTheme } from "xmlui"; 5 | 6 | const ConfirmationDialog = ({ 7 | open, 8 | onOpenChange, 9 | title, 10 | description, 11 | onConfirm, 12 | confirmText = "Confirm", 13 | cancelText = "Cancel", 14 | }: { 15 | open: boolean; 16 | onOpenChange: (open: boolean) => void; 17 | title: string; 18 | description: string; 19 | onConfirm: () => void; 20 | confirmText?: string; 21 | cancelText?: string; 22 | }) => { 23 | const { root } = useTheme(); 24 | return ( 25 | <AlertDialog.Root open={open} onOpenChange={onOpenChange}> 26 | <AlertDialog.Portal container={root}> 27 | <AlertDialog.Overlay className={styles.Overlay} /> 28 | <AlertDialog.Content className={styles.Content}> 29 | <AlertDialog.Title className={styles.Title}>{title}</AlertDialog.Title> 30 | <AlertDialog.Description className={styles.Description}> 31 | {description} 32 | </AlertDialog.Description> 33 | <div className={styles.Actions}> 34 | <AlertDialog.Cancel asChild> 35 | <button className={classnames(styles.Button, styles.mauve)}>{cancelText}</button> 36 | </AlertDialog.Cancel> 37 | <AlertDialog.Action asChild> 38 | <button className={classnames(styles.Button, styles.red)} onClick={onConfirm}> 39 | {confirmText} 40 | </button> 41 | </AlertDialog.Action> 42 | </div> 43 | </AlertDialog.Content> 44 | </AlertDialog.Portal> 45 | </AlertDialog.Root> 46 | ); 47 | }; 48 | 49 | export default ConfirmationDialog; 50 | ``` -------------------------------------------------------------------------------- /xmlui/bin/start.ts: -------------------------------------------------------------------------------- ```typescript 1 | import type { InlineConfig } from "vite"; 2 | import { createServer } from "vite"; 3 | import { getViteConfig } from "./viteConfig"; 4 | 5 | type XmlUiStartOptions = { 6 | port?: number; 7 | withMock?: boolean; 8 | proxy?: string; 9 | }; 10 | 11 | export const start = async ({ 12 | port, 13 | withMock = true, 14 | proxy, 15 | }: XmlUiStartOptions) => { 16 | console.log("Starting with options:", { 17 | withMock, 18 | withProxy: proxy, 19 | }); 20 | 21 | let proxyDef; 22 | if (proxy) { 23 | const splitProxy = proxy.split("->"); 24 | if (splitProxy.length !== 2) { 25 | console.error("Invalid proxy definition. Example: /api->http://localhost:3000"); 26 | } else { 27 | proxyDef = { 28 | [splitProxy[0]]: { 29 | target: splitProxy[1], 30 | changeOrigin: true, 31 | }, 32 | }; 33 | } 34 | } 35 | 36 | try { 37 | let viteConfig = await getViteConfig({}); 38 | const server = await createServer({ 39 | ...viteConfig, 40 | server: { 41 | port, 42 | proxy: proxyDef, 43 | }, 44 | define: { 45 | ...viteConfig.define, 46 | "process.env.VITE_BUILD_MODE": JSON.stringify("ALL"), 47 | "process.env.VITE_DEV_MODE": true, 48 | "process.env.VITE_STANDALONE": process.env.VITE_STANDALONE, 49 | "process.env.VITE_MOCK_ENABLED": withMock, 50 | "process.env.VITE_INCLUDE_ALL_COMPONENTS": JSON.stringify("true"), 51 | "process.env.VITE_USER_COMPONENTS_Inspect": JSON.stringify("true"), 52 | }, 53 | } as InlineConfig); 54 | 55 | // server. 56 | 57 | if (!server.httpServer) { 58 | throw new Error("HTTP server not available"); 59 | } 60 | 61 | await server.listen(); 62 | server.printUrls(); 63 | } catch (e) { 64 | process.exit(1); 65 | } 66 | }; 67 | ``` -------------------------------------------------------------------------------- /tools/create-app/helpers/is-folder-empty.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { green, blue } from 'picocolors' 2 | import fs from 'fs' 3 | import path from 'path' 4 | 5 | export function isFolderEmpty(root: string, name: string): boolean { 6 | const validFiles = [ 7 | '.DS_Store', 8 | '.git', 9 | '.gitattributes', 10 | '.gitignore', 11 | '.gitlab-ci.yml', 12 | '.hg', 13 | '.hgcheck', 14 | '.hgignore', 15 | '.idea', 16 | '.npmignore', 17 | '.travis.yml', 18 | 'LICENSE', 19 | 'Thumbs.db', 20 | 'docs', 21 | 'mkdocs.yml', 22 | 'npm-debug.log', 23 | 'yarn-debug.log', 24 | 'yarn-error.log', 25 | 'yarnrc.yml', 26 | '.yarn', 27 | ] 28 | 29 | const conflicts = fs 30 | .readdirSync(root) 31 | .filter((file) => !validFiles.includes(file)) 32 | // Support IntelliJ IDEA-based editors 33 | .filter((file) => !/\.iml$/.test(file)) 34 | 35 | if (conflicts.length > 0) { 36 | console.log( 37 | `The directory ${green(name)} contains files that could conflict:` 38 | ) 39 | console.log() 40 | for (const file of conflicts) { 41 | try { 42 | const stats = fs.lstatSync(path.join(root, file)) 43 | if (stats.isDirectory()) { 44 | console.log(` ${blue(file)}/`) 45 | } else { 46 | console.log(` ${file}`) 47 | } 48 | } catch { 49 | console.log(` ${file}`) 50 | } 51 | } 52 | console.log() 53 | console.log( 54 | 'Either try using a new directory name, or remove the files listed above.' 55 | ) 56 | console.log() 57 | return false 58 | } 59 | 60 | return true 61 | } ``` -------------------------------------------------------------------------------- /xmlui/src/components-core/utils/mergeProps.ts: -------------------------------------------------------------------------------- ```typescript 1 | type AnyProps = Record<string, any>; 2 | 3 | /** 4 | * Merges child component props with rest props. 5 | * @param childProps Child component props 6 | * @param restProps Rest props 7 | * @returns 8 | * 9 | * The origin of this method is: 10 | * https://github.com/radix-ui/primitives/blob/c31c97274ff357aea99afe6c01c1c8c58b6356e0/packages/react/slot/src/Slot.tsx#L91 11 | */ 12 | export function mergeProps(childProps: AnyProps, restProps: AnyProps) { 13 | // --- All child props should override 14 | const overrideProps = { ...restProps }; 15 | 16 | for (const propName in restProps) { 17 | const childPropValue = childProps[propName]; 18 | const restPropValue = restProps[propName]; 19 | 20 | const isHandler = /^on[A-Z]/.test(propName); 21 | if (isHandler) { 22 | // --- If the handler exists on both, we compose them... 23 | if (childPropValue && restPropValue) { 24 | overrideProps[propName] = (...args: unknown[]) => { 25 | restPropValue(...args); 26 | childPropValue(...args); 27 | }; 28 | } 29 | // --- ...but if it exists only on the original, we use only this one 30 | else if (childPropValue) { 31 | overrideProps[propName] = childPropValue; 32 | } 33 | } else if (propName === "style") { 34 | // --- We merge `style` 35 | overrideProps[propName] = restPropValue ? { ...restPropValue, ...childPropValue } : childPropValue; 36 | } else if (propName === "className") { 37 | // --- We merge `className` 38 | overrideProps[propName] = restPropValue 39 | ? [restPropValue, childPropValue].filter(Boolean).join(" ") 40 | : childPropValue; 41 | } 42 | } 43 | 44 | return { ...childProps, ...overrideProps }; 45 | } 46 | ``` -------------------------------------------------------------------------------- /xmlui/src/testing/infrastructure/public/resources/txt.svg: -------------------------------------------------------------------------------- ``` 1 | <svg width="22" height="28" viewBox="0 0 22 28" fill="none" xmlns="http://www.w3.org/2000/svg" data-testid="txt-svg"> 2 | <g clip-path="url(#clip0_1811_14941)"> 3 | <path d="M21.7881 7.38281L16.374 5.74219L14.8271 0H3.22559C2.37125 0 1.67871 0.734508 1.67871 1.64062V26.3594C1.67871 27.2655 2.37125 28 3.22559 28H20.2412C21.0956 28 21.7881 27.2655 21.7881 26.3594V7.38281Z" fill="#EDEDED"/> 4 | <path d="M21.7881 7.38281V26.3594C21.7881 27.2655 21.0955 28 20.2412 28H11.8572V0H14.8271L16.374 5.74219L21.7881 7.38281Z" fill="#EDEDED"/> 5 | <path d="M21.7881 7.38281H16.374C15.5232 7.38281 14.8271 6.64453 14.8271 5.74219V0C15.0282 0 15.2293 0.0820312 15.3685 0.246148L21.556 6.80865C21.7107 6.95625 21.7881 7.16953 21.7881 7.38281Z" fill="#BDBDBD"/> 6 | <path d="M20.5333 22.4259C20.5333 22.925 20.1483 23.3333 19.6778 23.3333H0.855556C0.385 23.3333 0 22.925 0 22.4259V13.3519C0 12.8528 0.385 12.4444 0.855556 12.4444H19.6778C20.1483 12.4444 20.5333 12.8528 20.5333 13.3519V22.4259Z" fill="#161C28"/> 7 | <path d="M4.62629 16.508V20H5.56828V16.508H6.85229V15.716H3.34229V16.508H4.62629Z" fill="white"/> 8 | <path d="M8.99625 17.756L7.50225 20H8.55825L9.51225 18.518L10.4483 20H11.5703L10.0763 17.762L11.4503 15.716H10.4183L9.54825 17.084L8.70825 15.716H7.61625L8.99625 17.756Z" fill="white"/> 9 | <path d="M13.4962 16.508V20H14.4382V16.508H15.7222V15.716H12.2122V16.508H13.4962Z" fill="white"/> 10 | </g> 11 | <defs> 12 | <clipPath id="clip0_1811_14941"> 13 | <rect width="22" height="28" fill="white"/> 14 | </clipPath> 15 | </defs> 16 | </svg> 17 | ``` -------------------------------------------------------------------------------- /xmlui/tests/parsers/style-parser/generateHvarChain.test.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { describe, expect, it } from "vitest"; 2 | import { matchThemeVar } from "../../../src/components-core/theming/hvar"; 3 | 4 | describe("Generate HVar chain", () => { 5 | it("Input:backgroundColor-TextArea-default--hover", () => { 6 | const ret = matchThemeVar("Input:backgroundColor-TextArea-default--hover", [ 7 | { 8 | "backgroundColor-Input": "$yeah", 9 | "backgroundColor-TextArea-default--hover": "$something else" 10 | }, 11 | { 12 | "backgroundColor-Input--hover": "$something", 13 | } 14 | ]); 15 | 16 | const expected = { 17 | forValue: "backgroundColor-TextArea-default--hover", 18 | matchedValue: "backgroundColor-Input--hover", 19 | from: [ 20 | "backgroundColor-TextArea-default--hover", 21 | "backgroundColor-Input-default--hover", 22 | "backgroundColor-TextArea--hover", 23 | "backgroundColor-Input--hover", 24 | "backgroundColor-TextArea-default", 25 | "backgroundColor-Input-default", 26 | "backgroundColor-TextArea", 27 | "backgroundColor-Input", 28 | ], 29 | }; 30 | 31 | expect(ret).eqls(expected); 32 | }); 33 | 34 | it("backgroundColor-Button-primary-solid", () => { 35 | const ret = matchThemeVar("backgroundColor-Button-primary-solid", [{ 36 | "backgroundColor-Button-primary-solid": "$something", 37 | }]); 38 | 39 | const expected = { 40 | forValue: "backgroundColor-Button-primary-solid", 41 | matchedValue: "backgroundColor-Button-primary-solid", 42 | from: ["backgroundColor-Button-primary-solid", "backgroundColor-Button-primary", "backgroundColor-Button-solid", "backgroundColor-Button"], 43 | }; 44 | 45 | expect(ret).eqls(expected); 46 | }); 47 | }); 48 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Badge/BadgeNative.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { type CSSProperties, type ForwardedRef, forwardRef } from "react"; 2 | import classnames from "classnames"; 3 | 4 | import styles from "./Badge.module.scss"; 5 | 6 | export const badgeVariantValues = ["badge", "pill"] as const; 7 | export type BadgeVariant = (typeof badgeVariantValues)[number]; 8 | export type BadgeColors = { 9 | label: string; 10 | background: string; 11 | }; 12 | 13 | // --- Type guard for BadgeColors --- 14 | export function isBadgeColors(color: any): color is BadgeColors { 15 | return ( 16 | typeof color === "object" && 17 | color !== null && 18 | "label" in color && 19 | "background" in color && 20 | typeof color.label === "string" && 21 | typeof color.background === "string" 22 | ); 23 | } 24 | 25 | type Props = { 26 | children?: React.ReactNode; 27 | variant?: BadgeVariant; 28 | color?: string | BadgeColors; 29 | style?: CSSProperties; 30 | className?: string; 31 | }; 32 | 33 | export const defaultProps: Pick<Props, "variant"> = { 34 | variant: "badge", 35 | }; 36 | 37 | export const Badge = forwardRef(function Badge( 38 | { children, color, variant = defaultProps.variant, style, className, ...rest }: Props, 39 | forwardedRef: ForwardedRef<HTMLDivElement>, 40 | ) { 41 | return ( 42 | <div 43 | {...rest} 44 | ref={forwardedRef} 45 | className={classnames( 46 | { 47 | [styles.badge]: variant === "badge", 48 | [styles.pill]: variant === "pill", 49 | }, 50 | className, 51 | )} 52 | style={{ 53 | ...(color 54 | ? typeof color === "string" 55 | ? { backgroundColor: color } 56 | : { backgroundColor: color.background, color: color.label } 57 | : {}), 58 | ...style, 59 | }} 60 | > 61 | {children} 62 | </div> 63 | ); 64 | }); 65 | ``` -------------------------------------------------------------------------------- /xmlui/src/components-core/theming/themes/xmlui.ts: -------------------------------------------------------------------------------- ```typescript 1 | import type { ThemeDefinition } from "../../../abstractions/ThemingDefs"; 2 | import { 3 | cyanThemeColors, 4 | grayThemeColors, 5 | greenThemeColors, 6 | orangeThemeColors, 7 | purpleThemeColors, 8 | redThemeColors, 9 | } from "./theme-colors"; 10 | 11 | export const XmlUiThemeDefinition: ThemeDefinition = { 12 | id: "xmlui", 13 | resources: { 14 | // "font.inter": "https://rsms.me/inter/inter.css", 15 | }, 16 | themeVars: { 17 | "font-size": "15px", 18 | "boxShadow-Input": "$boxShadow-sm", 19 | }, 20 | tones: { 21 | light: { 22 | themeVars: { 23 | "backgroundColor-ModalDialog": "white", 24 | "backgroundColor-checked-RadioGroupOption": "$color-primary-400", 25 | } 26 | }, 27 | dark: { 28 | themeVars: { 29 | "color-error": "$color-danger-400", 30 | } 31 | } 32 | } 33 | }; 34 | 35 | export const XmlUiGreenThemeDefinition: ThemeDefinition = { 36 | id: "xmlui-green", 37 | extends: "xmlui", 38 | themeVars: { ...greenThemeColors }, 39 | }; 40 | 41 | export const XmlUiGrayThemeDefinition: ThemeDefinition = { 42 | id: "xmlui-gray", 43 | extends: "xmlui", 44 | themeVars: { ...grayThemeColors }, 45 | }; 46 | 47 | export const XmlUiOrangeThemeDefinition: ThemeDefinition = { 48 | id: "xmlui-orange", 49 | extends: "xmlui", 50 | themeVars: { ...orangeThemeColors }, 51 | }; 52 | 53 | export const XmlUiPurpleThemeDefinition: ThemeDefinition = { 54 | id: "xmlui-purple", 55 | extends: "xmlui", 56 | themeVars: { ...purpleThemeColors }, 57 | }; 58 | 59 | export const XmlUiCyanThemeDefinition: ThemeDefinition = { 60 | id: "xmlui-cyan", 61 | extends: "xmlui", 62 | themeVars: { ...cyanThemeColors }, 63 | }; 64 | 65 | export const XmlUiRedThemeDefinition: ThemeDefinition = { 66 | id: "xmlui-red", 67 | extends: "xmlui", 68 | themeVars: { ...redThemeColors }, 69 | }; 70 | ``` -------------------------------------------------------------------------------- /xmlui/src/components-core/descriptorHelper.ts: -------------------------------------------------------------------------------- ```typescript 1 | // We need these keys for extracting layout parameters 2 | export const layoutOptionKeys = [ 3 | "horizontalAlignment", 4 | "verticalAlignment", 5 | "orientation", 6 | "width", 7 | "minWidth", 8 | "maxWidth", 9 | "height", 10 | "minHeight", 11 | "maxHeight", 12 | "gap", 13 | "border", 14 | "borderTop", 15 | "borderRight", 16 | "borderBottom", 17 | "borderLeft", 18 | "borderColor", 19 | "borderStyle", 20 | "borderWidth", 21 | "borderHorizontal", 22 | "borderVertical", 23 | "borderRadius", 24 | "radiusTopLeft", 25 | "radiusTopRight", 26 | "radiusBottomLeft", 27 | "radiusBottomRight", 28 | "padding", 29 | "paddingHorizontal", 30 | "paddingVertical", 31 | "paddingTop", 32 | "paddingRight", 33 | "paddingBottom", 34 | "paddingLeft", 35 | "backgroundColor", 36 | "background", 37 | "boxShadow", 38 | "direction", 39 | "overflowX", 40 | "overflowY", 41 | "zIndex", 42 | "color", 43 | "fontFamily", 44 | "fontSize", 45 | "fontWeight", 46 | "fontStyle", 47 | "textDecoration", 48 | "wrapContent", 49 | "canShrink", 50 | "margin", 51 | "marginHorizontal", 52 | "marginVertical", 53 | "marginTop", 54 | "marginRight", 55 | "marginBottom", 56 | "marginLeft", 57 | "userSelect", 58 | "letterSpacing", 59 | "textTransform", 60 | "lineHeight", 61 | "opacity", 62 | "cursor", 63 | "textWrap", 64 | "textAlign", 65 | "textAlignLast", 66 | "top", 67 | "right", 68 | "bottom", 69 | "left", 70 | "zoom", 71 | "whiteSpace", 72 | "textDecoration", 73 | "textDecorationLine", 74 | "textDecorationColor", 75 | "textDecorationStyle", 76 | "textDecorationThickness", 77 | "textUnderlineOffset", 78 | "outline", 79 | "outlineWidth", 80 | "outlineColor", 81 | "outlineStyle", 82 | "outlineOffset", 83 | "fontVariant", 84 | "lineBreak", 85 | "textIndent", 86 | "textShadow", 87 | "wordBreak", 88 | "wordSpacing", 89 | "wordWrap", 90 | "writingMode", 91 | "transition", 92 | "transform", 93 | ]; 94 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/APICall/APICallNative.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { useEffect } from "react"; 2 | 3 | import type { RegisterComponentApiFn } from "../../abstractions/RendererDefs"; 4 | import type { ActionExecutionContext } from "../../abstractions/ActionDefs"; 5 | import { useEvent } from "../../components-core/utils/misc"; 6 | import { callApi } from "../../components-core/action/APICall"; 7 | import type { ApiActionComponent } from "../../components/APICall/APICall"; 8 | 9 | interface Props { 10 | registerComponentApi: RegisterComponentApiFn; 11 | node: ApiActionComponent; 12 | uid: symbol; 13 | } 14 | 15 | export const defaultProps = { 16 | method: "get", 17 | }; 18 | 19 | export function APICallNative({ registerComponentApi, node, uid }: Props) { 20 | // TODO pause until the apiInterceptorContext is initialized (to make sure the API calls are intercepted) 21 | const execute = useEvent( 22 | async (executionContext: ActionExecutionContext, ...eventArgs: any[]) => { 23 | const options = eventArgs[1]; 24 | return await callApi( 25 | executionContext, 26 | { 27 | ...node.props, 28 | body: node.props.body || (options?.passAsDefaultBody ? eventArgs[0] : undefined), 29 | uid: uid, 30 | params: { $param: eventArgs[0], $params: eventArgs }, 31 | onError: node.events?.error, 32 | onProgress: node.events?.progress, 33 | onBeforeRequest: node.events?.beforeRequest, 34 | onSuccess: node.events?.success, 35 | }, 36 | { 37 | resolveBindingExpressions: true, 38 | }, 39 | ); 40 | }, 41 | ); 42 | 43 | useEffect(() => { 44 | registerComponentApi({ 45 | execute: execute, 46 | _SUPPORT_IMPLICIT_CONTEXT: true, 47 | }); 48 | }, [execute, registerComponentApi]); 49 | 50 | return null; 51 | } 52 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Pages/Pages.md: -------------------------------------------------------------------------------- ```markdown 1 | %-DESC-START 2 | 3 | **Key features:** 4 | 5 | - **Route coordination**: Automatically displays the correct Page based on current URL and navigation 6 | - **Default route handling**: Sets the initial page shown when the application loads 7 | - **Client-side routing**: Manages navigation without page refreshes or server requests 8 | 9 | ### Using the Pages and Page components 10 | 11 | The `Page` component has a property called `url`. This is the route associated with the `Page's` contents. 12 | You can provide a link to this route to display a particular `Page`. 13 | Currently, all navigation is done on the clientside. 14 | No page is fetched from the server, thus the application operates as a [Single Page Application](https://developer.mozilla.org/en-US/docs/Glossary/SPA). 15 | 16 | ```xmlui-pg copy {3-4, 7, 10} display name="Example: using Pages and Page" height="170px" 17 | <App> 18 | <NavPanel> 19 | <NavLink label="Home" to="/" icon="home"/> 20 | <NavLink label="Account" to="/account" icon="user"/> 21 | </NavPanel> 22 | <Pages> 23 | <Page url="/"> 24 | <Text>Hello App!</Text> 25 | </Page> 26 | <Page url="/account"> 27 | <Text>This is the account page.</Text> 28 | </Page> 29 | </Pages> 30 | </App> 31 | ``` 32 | 33 | %-DESC-END 34 | 35 | %-PROP-START fallbackPath 36 | 37 | ```xmlui-pg copy {6-13} display name="Example: fallbackPath" height="170px" 38 | <App> 39 | <NavPanel> 40 | <NavLink label="Not Home" to="/not-home" icon="trash"/> 41 | <NavLink label="Home" to="/home" icon="home"/> 42 | </NavPanel> 43 | <Pages fallbackPath="/home"> 44 | <Page url="/not-home"> 45 | <Text>This is not home...</Text> 46 | </Page> 47 | <Page url="/home"> 48 | <Text>Hello App!</Text> 49 | </Page> 50 | </Pages> 51 | </App> 52 | ``` 53 | 54 | %-PROP-END 55 | ``` -------------------------------------------------------------------------------- /xmlui/src/parsers/style-parser/errors.ts: -------------------------------------------------------------------------------- ```typescript 1 | // The common root class of all parser error objects 2 | export class StyleParserError extends Error { 3 | constructor (message: string, public code?: string) { 4 | super(message); 5 | 6 | // --- Set the prototype explicitly. 7 | Object.setPrototypeOf(this, StyleParserError.prototype); 8 | } 9 | } 10 | 11 | export type StyleErrorCodes = 12 | | "S001" 13 | | "S002" 14 | | "S003" 15 | | "S004" 16 | | "S005" 17 | | "S006" 18 | | "S007" 19 | | "S008" 20 | | "S009" 21 | | "S010" 22 | | "S011" 23 | | "S012" 24 | | "S013" 25 | | "S014" 26 | | "S015" 27 | | "S016" 28 | | "S017" 29 | | "S018" 30 | | "S019" 31 | | "S020" 32 | | "S021"; 33 | 34 | // Error message type description 35 | type ErrorText = Record<string, string>; 36 | 37 | // The error messages of error codes 38 | export const styleErrorMessages: ErrorText = { 39 | S001: "A numeric value expected", 40 | S002: "A dimension unit expected", 41 | S003: "An alignment value expected", 42 | S004: "A border style value expected", 43 | S005: "A color value or expression expected", 44 | S006: "Unknown color function name '{0}'", 45 | S007: "'(' expected, but '{0}' received", 46 | S008: "A color channel percentage value expected between 0 and 100", 47 | S009: "A color channel value expected between 0 and 255", 48 | S010: "')' expected, but '{0}' received", 49 | S011: "An alpha channel value expected between 0.0 and 1.0", 50 | S012: "A scrolling value expected", 51 | S013: "A direction value expected", 52 | S014: "A fontFamily value expected", 53 | S015: "A fontWeight value expected", 54 | S016: "Unexpected token found", 55 | S017: "A Boolean value expected", 56 | S018: "An orientation value expected", 57 | S019: "']' expected", 58 | S020: "A user-select value expected", 59 | S021: "A text transform value expected", 60 | }; 61 | ``` -------------------------------------------------------------------------------- /xmlui/src/parsers/common/InputStream.ts: -------------------------------------------------------------------------------- ```typescript 1 | // This class represents the input stream of the binding parser 2 | export class InputStream { 3 | // --- Current stream position 4 | private _pos = 0; 5 | 6 | // --- Current line number 7 | private _line = 1; 8 | 9 | // --- Current column number 10 | private _column = 0; 11 | 12 | // Creates a stream that uses the specified source code 13 | constructor (public readonly source: string) {} 14 | 15 | // Gets the current position in the stream. Starts from 0. 16 | get position (): number { 17 | return this._pos; 18 | } 19 | 20 | // Gets the current line number. Starts from 1. 21 | get line (): number { 22 | return this._line; 23 | } 24 | 25 | // Gets the current column number. Starts from 0. 26 | get column (): number { 27 | return this._column; 28 | } 29 | 30 | // Peeks the next character in the stream. Returns null, if EOF; otherwise the current source code character 31 | peek (): string | null { 32 | return this.ahead(0); 33 | } 34 | 35 | // Looks ahead with `n` characters in the stream. Returns null, if EOF; otherwise the look-ahead character 36 | ahead (n: number = 1): string | null { 37 | return this._pos + n > this.source.length - 1 ? null : this.source[this._pos + n]; 38 | } 39 | 40 | // Gets the next character from the stream 41 | get (): string | null { 42 | // --- Check for EOF 43 | if (this._pos >= this.source.length) { 44 | return null; 45 | } 46 | 47 | // --- Get the char, and keep track of position 48 | const ch = this.source[this._pos++]; 49 | if (ch === "\n") { 50 | this._line++; 51 | this._column = 0; 52 | } else { 53 | this._column++; 54 | } 55 | return ch; 56 | } 57 | 58 | // Gets the tail of the input stream 59 | getTail (start: number): string { 60 | return this.source?.substring(start) ?? ""; 61 | } 62 | } 63 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/NestedApp/AppWithCodeView.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 | $component: "AppWithCodeView"; 13 | $background-sideBySide-AppWithCode: createThemeVar("background-sideBySide-#{$component}"); 14 | $border-sideBySide-AppWithCode: createThemeVar("border-sideBySide-#{$component}"); 15 | $padding-sideBySide-AppWithCode: createThemeVar("padding-sideBySide-#{$component}"); 16 | $margin-sideBySide-AppWithCode: createThemeVar("margin-sideBySide-#{$component}"); 17 | $gap-sideBySide-AppWithCode: createThemeVar("gap-sideBySide-#{$component}"); 18 | 19 | @layer components { 20 | .container { 21 | display: flex; 22 | /* default flexbox alignment */ 23 | justify-content: flex-start; 24 | align-items: stretch; 25 | min-height: 0; 26 | min-width: 0; 27 | gap: $gap-sideBySide-AppWithCode; 28 | background: $background-sideBySide-AppWithCode; 29 | border: $border-sideBySide-AppWithCode; 30 | padding: $padding-sideBySide-AppWithCode; 31 | margin: $margin-sideBySide-AppWithCode; 32 | } 33 | 34 | .vertical { 35 | flex-direction: column; 36 | gap: var(--stack-gap-default); 37 | min-height: 0; 38 | } 39 | 40 | .horizontal { 41 | flex-direction: row; 42 | } 43 | 44 | 45 | .column { 46 | width: 50%; 47 | display: flex; 48 | flex-direction: column; 49 | align-items: center; 50 | justify-content: center; 51 | } 52 | } 53 | 54 | 55 | 56 | // --- We export the theme variables to add them to the component renderer 57 | :export { 58 | themeVars: t.json-stringify($themeVars); 59 | } ``` -------------------------------------------------------------------------------- /xmlui/src/components-core/rendering/StandaloneComponent.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import type { ReactNode} from "react"; 2 | import { cloneElement, isValidElement, useMemo, useRef } from "react"; 3 | import type { MemoedVars } from "../abstractions/ComponentRenderer"; 4 | import { renderChild } from "./renderChild"; 5 | import { EMPTY_OBJECT, noop } from "../constants"; 6 | import type { ComponentDef } from "../../abstractions/ComponentDefs"; 7 | 8 | type RootComponentProps = { 9 | node: ComponentDef; 10 | children?: ReactNode; 11 | functions?: Record<string, any>; 12 | vars?: Record<string, any>; 13 | }; 14 | 15 | function StandaloneComponent({ node, children, functions, vars }: RootComponentProps) { 16 | const memoedVarsRef = useRef<MemoedVars>(new Map()); 17 | const rootNode = useMemo(() => { 18 | if(node.type === "Container"){ 19 | // If the node is already a Container, we can use it directly 20 | return { 21 | ...node, 22 | functions: { 23 | ...node.functions, 24 | ...functions, 25 | }, 26 | vars: { 27 | ...node.vars, 28 | ...vars, 29 | } 30 | }; 31 | } 32 | return { 33 | type: "Container", 34 | uid: "standaloneComponentRoot", 35 | children: [node], 36 | uses: [], 37 | functions, 38 | vars, 39 | }; 40 | }, [functions, node, vars]); 41 | 42 | const renderedRoot = renderChild({ 43 | node: rootNode, 44 | state: EMPTY_OBJECT, 45 | dispatch: noop, 46 | appContext: undefined, 47 | lookupAction: noop, 48 | lookupSyncCallback: noop, 49 | registerComponentApi: noop, 50 | renderChild: noop, 51 | statePartChanged: noop, 52 | cleanup: noop, 53 | memoedVarsRef, 54 | }); 55 | 56 | return !!children && isValidElement(renderedRoot) 57 | ? cloneElement(renderedRoot, null, children) 58 | : renderedRoot; 59 | } 60 | 61 | export default StandaloneComponent; 62 | ``` -------------------------------------------------------------------------------- /packages/xmlui-devtools/CHANGELOG.md: -------------------------------------------------------------------------------- ```markdown 1 | # xmlui-devtools 2 | 3 | ## 0.1.20 4 | 5 | ### Patch Changes 6 | 7 | - 819b563: Update fontSize and lineHeight themes and style (may break existing xmlui code) 8 | 9 | ## 0.1.19 10 | 11 | ### Patch Changes 12 | 13 | - cbe1ef2: Use grammar and syntax highlight files straight form the xmlui package, instead of duplicating them in every app. 14 | 15 | ## 0.1.18 16 | 17 | ### Patch Changes 18 | 19 | - 7d255a9: Changed open in new window button tooltip label for all occurrences. 20 | 21 | ## 0.1.17 22 | 23 | ### Patch Changes 24 | 25 | - 84a660d: fix: devtools - turn off stickyScroll 26 | 27 | ## 0.1.16 28 | 29 | ### Patch Changes 30 | 31 | - 9345bd4: Turn off sticky scroll 32 | 33 | ## 0.1.15 34 | 35 | ### Patch Changes 36 | 37 | - 9a3c3b6: feat: xmlui-devtools - start dialog animation from the click, use exit animation as well 38 | 39 | ## 0.1.14 40 | 41 | ### Patch Changes 42 | 43 | - 9d9d930: feat: devtools - themeVariable for setting the duration of the modal's animation 44 | 45 | ## 0.1.13 46 | 47 | ### Patch Changes 48 | 49 | - 73c2c21: wip: code inspector buttons - label change, devtools - animation update 50 | 51 | ## 0.1.12 52 | 53 | ### Patch Changes 54 | 55 | - f5b9f15: feat: xmlui-devtools - use it in a modal dialog 56 | 57 | ## 0.1.11 58 | 59 | ### Patch Changes 60 | 61 | - 2e88539: improve: add Tooltip to DevTools 62 | 63 | ## 0.1.10 64 | 65 | ### Patch Changes 66 | 67 | - 3eab4a3: improve: design updates - devtools, playground, docs 68 | 69 | ## 0.1.9 70 | 71 | ### Patch Changes 72 | 73 | - c92223c: When we launch the playground from the devtools, it now appears on a subpage instead of under the docs on a different domain. 74 | 75 | ## 0.1.8 76 | 77 | ### Patch Changes 78 | 79 | - b0ae113: testing 80 | 81 | ## 0.1.7 82 | 83 | ### Patch Changes 84 | 85 | - f15c018: another testing 86 | - f15c018: testing 87 | 88 | ## 0.1.6 89 | 90 | ### Patch Changes 91 | 92 | - 421968b: testing 93 | 94 | ## 0.1.5 95 | 96 | ### Patch Changes 97 | 98 | - 99bba69: testing 99 | 100 | ## 0.1.4 101 | 102 | ### Patch Changes 103 | 104 | - bcf162c: testing changesets 105 | ``` -------------------------------------------------------------------------------- /packages/xmlui-playground/src/providers/Toast.module.scss: -------------------------------------------------------------------------------- ```scss 1 | .ToastViewport { 2 | --viewport-padding: 25px; 3 | position: fixed; 4 | bottom: 0; 5 | right: 0; 6 | display: flex; 7 | flex-direction: column; 8 | padding: 2rem; 9 | gap: 10px; 10 | width: 390px; 11 | max-width: 100vw; 12 | margin: 0; 13 | list-style: none; 14 | z-index: 2147483647; 15 | outline: none; 16 | } 17 | 18 | .ToastClose { 19 | color: #fff; 20 | justify-self: flex-end; 21 | } 22 | 23 | .ToastRoot { 24 | background-color: rgb(23, 162, 184); 25 | border-radius: 6px; 26 | box-shadow: 0px 0.8px 2px rgba(0, 0, 0, 0.032), 0px 2.7px 6.7px rgba(0, 0, 0, 0.048), 27 | 0px 12px 30px rgba(0, 0, 0, 0.08); 28 | padding: 15px; 29 | display: grid; 30 | grid-template-areas: "title action" "description action"; 31 | grid-template-columns: auto max-content; 32 | align-items: center; 33 | } 34 | 35 | .error { 36 | background-color: rgb(220, 53, 69); 37 | } 38 | 39 | .warning { 40 | background-color: rgb(255, 193, 7); 41 | } 42 | 43 | .info { 44 | background-color: rgb(23, 162, 184); 45 | } 46 | 47 | .success { 48 | background-color: rgb(40, 167, 69); 49 | } 50 | 51 | .ToastRoot[data-state="open"] { 52 | animation: slideIn 150ms cubic-bezier(0.16, 1, 0.3, 1); 53 | } 54 | .ToastRoot[data-state="closed"] { 55 | animation: hide 100ms ease-in; 56 | } 57 | .ToastRoot[data-swipe="cancel"] { 58 | transform: translateX(0); 59 | transition: transform 200ms ease-out; 60 | } 61 | 62 | @keyframes hide { 63 | from { 64 | opacity: 1; 65 | } 66 | to { 67 | opacity: 0; 68 | } 69 | } 70 | 71 | @keyframes slideIn { 72 | from { 73 | transform: translateX(calc(100% + 2rem)); 74 | } 75 | to { 76 | transform: translateX(0); 77 | } 78 | } 79 | 80 | .ToastTitle { 81 | color: #fff; 82 | grid-area: title; 83 | margin-bottom: 5px; 84 | font-weight: 500; 85 | font-size: 15px; 86 | } 87 | 88 | .ToastDescription { 89 | color: #fff; 90 | grid-area: description; 91 | margin: 0; 92 | font-size: 13px; 93 | line-height: 1.3; 94 | } 95 | 96 | .ToastAction { 97 | grid-area: action; 98 | } 99 | ```