This is page 6 of 177. Use http://codebase.md/xmlui-org/xmlui/mockApiDef.js?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 │ ├── twenty-jeans-watch.md │ └── warm-spies-melt.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 │ │ │ ├── OptionContext.ts │ │ │ ├── Select.md │ │ │ ├── Select.module.scss │ │ │ ├── Select.spec.ts │ │ │ ├── Select.tsx │ │ │ ├── SelectContext.tsx │ │ │ └── SelectNative.tsx │ │ ├── SelectionStore │ │ │ ├── SelectionStore.md │ │ │ ├── SelectionStore.tsx │ │ │ └── SelectionStoreNative.tsx │ │ ├── Slider │ │ │ ├── Slider.md │ │ │ ├── Slider.module.scss │ │ │ ├── Slider.spec.ts │ │ │ ├── Slider.tsx │ │ │ └── SliderNative.tsx │ │ ├── Slot │ │ │ ├── Slot.md │ │ │ ├── Slot.spec.ts │ │ │ └── Slot.ts │ │ ├── SlotItem.tsx │ │ ├── SpaceFiller │ │ │ ├── SpaceFiller.md │ │ │ ├── SpaceFiller.module.scss │ │ │ ├── SpaceFiller.spec.ts │ │ │ ├── SpaceFiller.tsx │ │ │ └── SpaceFillerNative.tsx │ │ ├── Spinner │ │ │ ├── Spinner.md │ │ │ ├── Spinner.module.scss │ │ │ ├── Spinner.spec.ts │ │ │ ├── Spinner.tsx │ │ │ └── SpinnerNative.tsx │ │ ├── Splitter │ │ │ ├── HSplitter.md │ │ │ ├── HSplitter.spec.ts │ │ │ ├── Splitter.md │ │ │ ├── Splitter.module.scss │ │ │ ├── Splitter.spec.ts │ │ │ ├── Splitter.tsx │ │ │ ├── SplitterNative.tsx │ │ │ ├── utils.ts │ │ │ ├── VSplitter.md │ │ │ └── VSplitter.spec.ts │ │ ├── Stack │ │ │ ├── CHStack.md │ │ │ ├── CHStack.spec.ts │ │ │ ├── CVStack.md │ │ │ ├── CVStack.spec.ts │ │ │ ├── HStack.md │ │ │ ├── HStack.spec.ts │ │ │ ├── Stack.md │ │ │ ├── Stack.module.scss │ │ │ ├── Stack.spec.ts │ │ │ ├── Stack.tsx │ │ │ ├── StackNative.tsx │ │ │ ├── VStack.md │ │ │ └── VStack.spec.ts │ │ ├── StickyBox │ │ │ ├── StickyBox.md │ │ │ ├── StickyBox.module.scss │ │ │ ├── StickyBox.tsx │ │ │ └── StickyBoxNative.tsx │ │ ├── Switch │ │ │ ├── Switch.md │ │ │ ├── Switch.spec.ts │ │ │ └── Switch.tsx │ │ ├── Table │ │ │ ├── doc-resources │ │ │ │ └── list-component-data.js │ │ │ ├── react-table-config.d.ts │ │ │ ├── Table.md │ │ │ ├── Table.module.scss │ │ │ ├── Table.spec.ts │ │ │ ├── Table.tsx │ │ │ ├── TableNative.tsx │ │ │ └── useRowSelection.tsx │ │ ├── TableOfContents │ │ │ ├── TableOfContents.module.scss │ │ │ ├── TableOfContents.spec.ts │ │ │ ├── TableOfContents.tsx │ │ │ └── TableOfContentsNative.tsx │ │ ├── Tabs │ │ │ ├── TabContext.tsx │ │ │ ├── TabItem.md │ │ │ ├── TabItem.tsx │ │ │ ├── TabItemNative.tsx │ │ │ ├── Tabs.md │ │ │ ├── Tabs.module.scss │ │ │ ├── Tabs.spec.ts │ │ │ ├── Tabs.tsx │ │ │ └── TabsNative.tsx │ │ ├── Text │ │ │ ├── Text.md │ │ │ ├── Text.module.scss │ │ │ ├── Text.spec.ts │ │ │ ├── Text.tsx │ │ │ └── TextNative.tsx │ │ ├── TextArea │ │ │ ├── TextArea.md │ │ │ ├── TextArea.module.scss │ │ │ ├── TextArea.spec.ts │ │ │ ├── TextArea.tsx │ │ │ ├── TextAreaNative.tsx │ │ │ ├── TextAreaResizable.tsx │ │ │ └── useComposedRef.ts │ │ ├── TextBox │ │ │ ├── TextBox.md │ │ │ ├── TextBox.module.scss │ │ │ ├── TextBox.spec.ts │ │ │ ├── TextBox.tsx │ │ │ └── TextBoxNative.tsx │ │ ├── Theme │ │ │ ├── NotificationToast.tsx │ │ │ ├── Theme.md │ │ │ ├── Theme.module.scss │ │ │ ├── Theme.spec.ts │ │ │ ├── Theme.tsx │ │ │ └── ThemeNative.tsx │ │ ├── TimeInput │ │ │ ├── TimeInput.md │ │ │ ├── TimeInput.module.scss │ │ │ ├── TimeInput.spec.ts │ │ │ ├── TimeInput.tsx │ │ │ ├── TimeInputNative.tsx │ │ │ └── utils.ts │ │ ├── Timer │ │ │ ├── Timer.md │ │ │ ├── Timer.spec.ts │ │ │ ├── Timer.tsx │ │ │ └── TimerNative.tsx │ │ ├── Toggle │ │ │ ├── Toggle.module.scss │ │ │ └── Toggle.tsx │ │ ├── ToneChangerButton │ │ │ ├── ToneChangerButton.md │ │ │ ├── ToneChangerButton.spec.ts │ │ │ └── ToneChangerButton.tsx │ │ ├── ToneSwitch │ │ │ ├── ToneSwitch.md │ │ │ ├── ToneSwitch.module.scss │ │ │ ├── ToneSwitch.spec.ts │ │ │ ├── ToneSwitch.tsx │ │ │ └── ToneSwitchNative.tsx │ │ ├── Tooltip │ │ │ ├── Tooltip.md │ │ │ ├── Tooltip.module.scss │ │ │ ├── Tooltip.spec.ts │ │ │ ├── Tooltip.tsx │ │ │ └── TooltipNative.tsx │ │ ├── Tree │ │ │ ├── testData.ts │ │ │ ├── Tree-dynamic.spec.ts │ │ │ ├── Tree-icons.spec.ts │ │ │ ├── Tree.md │ │ │ ├── Tree.spec.ts │ │ │ ├── TreeComponent.module.scss │ │ │ ├── TreeComponent.tsx │ │ │ └── TreeNative.tsx │ │ ├── TreeDisplay │ │ │ ├── TreeDisplay.md │ │ │ ├── TreeDisplay.module.scss │ │ │ ├── TreeDisplay.tsx │ │ │ └── TreeDisplayNative.tsx │ │ ├── ValidationSummary │ │ │ ├── ValidationSummary.module.scss │ │ │ └── ValidationSummary.tsx │ │ └── VisuallyHidden.tsx │ ├── components-core │ │ ├── abstractions │ │ │ ├── ComponentRenderer.ts │ │ │ ├── LoaderRenderer.ts │ │ │ ├── standalone.ts │ │ │ └── treeAbstractions.ts │ │ ├── action │ │ │ ├── actions.ts │ │ │ ├── APICall.tsx │ │ │ ├── FileDownloadAction.tsx │ │ │ ├── FileUploadAction.tsx │ │ │ ├── NavigateAction.tsx │ │ │ └── TimedAction.tsx │ │ ├── ApiBoundComponent.tsx │ │ ├── appContext │ │ │ ├── date-functions.ts │ │ │ ├── math-function.ts │ │ │ └── misc-utils.ts │ │ ├── AppContext.tsx │ │ ├── behaviors │ │ │ ├── Behavior.tsx │ │ │ ├── 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/Icon/svg/expression.svg: -------------------------------------------------------------------------------- ``` 1 | <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path d="M21 16.0019V8.00186C20.9996 7.65113 20.9071 7.30667 20.7315 7.00302C20.556 6.69937 20.3037 6.44722 20 6.27186L13 2.27186C12.696 2.09632 12.3511 2.00391 12 2.00391C11.6489 2.00391 11.304 2.09632 11 2.27186L4 6.27186C3.69626 6.44722 3.44398 6.69937 3.26846 7.00302C3.09294 7.30667 3.00036 7.65113 3 8.00186V16.0019C3.00036 16.3526 3.09294 16.697 3.26846 17.0007C3.44398 17.3043 3.69626 17.5565 4 17.7319L11 21.7319C11.304 21.9074 11.6489 21.9998 12 21.9998C12.3511 21.9998 12.696 21.9074 13 21.7319L20 17.7319C20.3037 17.5565 20.556 17.3043 20.7315 17.0007C20.9071 16.697 20.9996 16.3526 21 16.0019Z" 3 | stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> 4 | <path d="M3.26953 6.96094L11.9995 12.0109L20.7295 6.96094" stroke="currentColor" stroke-width="1.5" 5 | stroke-linecap="round" stroke-linejoin="round"/> 6 | <path d="M12 22.08V12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> 7 | </svg> ``` -------------------------------------------------------------------------------- /xmlui/src/abstractions/scripting/LogicalThread.ts: -------------------------------------------------------------------------------- ```typescript 1 | import type { BlockScope } from "./BlockScope"; 2 | import type { LoopScope } from "./LoopScope"; 3 | import type { TryScope } from "./TryScopeExp"; 4 | import type { Expression } from "../../components-core/script-runner/ScriptingSourceTree"; 5 | 6 | // Result of evaluating a binding expression 7 | export type ValueResult = { 8 | value: any; 9 | valueScope?: any; 10 | valueIndex?: number | string; 11 | }; 12 | 13 | // Represents a logical thread instance 14 | export type LogicalThread = { 15 | // --- Parent thread 16 | parent?: LogicalThread; 17 | 18 | // --- Child threads forked directly from this thread 19 | childThreads: LogicalThread[]; 20 | 21 | // --- Optional cache for expression values 22 | valueCache?: Map<Expression, ValueResult>; 23 | 24 | // --- Available closures 25 | closures?: BlockScope[]; 26 | 27 | // --- Scopes for block-level variables 28 | blocks?: BlockScope[]; 29 | 30 | // --- Scopes for loops in progress 31 | loops?: LoopScope[]; 32 | 33 | // --- Scopes for try blocks in progress 34 | tryBlocks?: TryScope[]; 35 | 36 | // --- The value of the break label to use for the forthcoming loop 37 | breakLabelValue?: number; 38 | 39 | // --- Optional return value of the thread 40 | returnValue?: any; 41 | }; 42 | ``` -------------------------------------------------------------------------------- /xmlui/src/components-core/behaviors/Behavior.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import type { ReactNode } from "react"; 2 | 3 | import type { RendererContext } from "../../abstractions/RendererDefs"; 4 | import type { ComponentDef, ComponentMetadata } from "../../abstractions/ComponentDefs"; 5 | 6 | /** 7 | * Defines the shape of a component behavior that can wrap a component with 8 | * additional functionality. 9 | */ 10 | export interface Behavior { 11 | /** 12 | * The name of the behavior (e.g., "tooltip", "animation"). 13 | */ 14 | name: string; 15 | 16 | /** 17 | * A function that determines if the behavior should be applied based on the 18 | * component's context and props. 19 | * @param node The component definition. 20 | * @param metadata The metadata of the component. 21 | * @returns True if the behavior can be attached, otherwise false. 22 | */ 23 | canAttach: (node: ComponentDef, metadata: ComponentMetadata) => boolean; 24 | 25 | /** 26 | * A function that attaches the behavior to the component's React node. 27 | * @param context The renderer context of the component. 28 | * @param node The React node to attach. 29 | * @returns The attached React node. 30 | */ 31 | attach: (context: RendererContext<any>, node: ReactNode) => ReactNode; 32 | } 33 | ``` -------------------------------------------------------------------------------- /xmlui/src/parsers/style-parser/source-tree.ts: -------------------------------------------------------------------------------- ```typescript 1 | // The root type of all source tree nodes 2 | export interface BaseNode { 3 | type: StyleNode["type"]; 4 | startPosition: number; 5 | endPosition: number; 6 | themeId?: ThemeIdDescriptor; 7 | } 8 | 9 | export type DefaultValueDescriptor = (string | ThemeIdDescriptor)[]; 10 | 11 | export type ThemeIdDescriptor = { 12 | id: string; 13 | defaultValue?: DefaultValueDescriptor; 14 | }; 15 | 16 | export interface SizeNode extends BaseNode { 17 | type: "Size"; 18 | value: number; 19 | unit: string; 20 | extSize?: string; 21 | } 22 | 23 | export interface BooleanNode extends BaseNode { 24 | type: "Boolean"; 25 | value: boolean; 26 | } 27 | 28 | export interface BorderStyleNode extends BaseNode { 29 | type: "BorderStyle"; 30 | value: string; 31 | } 32 | 33 | export interface BorderNode extends BaseNode { 34 | type: "Border"; 35 | widthValue?: number; 36 | widthUnit?: string; 37 | color?: string | number; 38 | styleValue?: string; 39 | themeId1?: ThemeIdDescriptor; 40 | themeId2?: ThemeIdDescriptor; 41 | themeId3?: ThemeIdDescriptor; 42 | } 43 | 44 | export interface ColorNode extends BaseNode { 45 | type: "Color"; 46 | colorId?: string; 47 | value: string | number; 48 | } 49 | 50 | export type StyleNode = SizeNode | BooleanNode | BorderStyleNode | BorderNode | ColorNode; 51 | ``` -------------------------------------------------------------------------------- /xmlui/tests/components-core/scripts-runner/eval-tree-regression.test.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { describe, expect, it } from "vitest"; 2 | 3 | import { evalBindingExpression } from "../../../src/components-core/script-runner/eval-tree-sync"; 4 | import {createEvalContext} from "./test-helpers"; 5 | import { Parser } from "../../../src/parsers/scripting/Parser"; 6 | import { evalBindingAsync } from "../../../src/components-core/script-runner/eval-tree-async"; 7 | 8 | describe("Evaluate arrow expressions (exp)", () => { 9 | it("concat #1", () => { 10 | // --- Arrange 11 | const source = "[].concat([])"; 12 | const context = createEvalContext({}); 13 | 14 | // --- Act 15 | const value = evalBindingExpression(source, context); 16 | 17 | // --- Arrange 18 | expect(value).toStrictEqual([]); 19 | }); 20 | 21 | it("concat (async) #1", async () => { 22 | // --- Arrange 23 | const source = "[].concat([])"; 24 | const context = createEvalContext({}); 25 | 26 | // --- Act 27 | const wParser = new Parser(source); 28 | const expr = wParser.parseExpr(); 29 | expect(expr).not.equal(null); 30 | if (!expr) return; 31 | const value = await evalBindingAsync(expr, context, context.mainThread); 32 | 33 | // --- Arrange 34 | expect(value).toStrictEqual([]); 35 | }); 36 | }); 37 | 38 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/RadioGroup/RadioItem.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { createComponentRenderer } from "../../components-core/renderers"; 2 | import { createMetadata, dDidChange } from "../metadata-helpers"; 3 | import { RadioItem, defaultProps } from "./RadioItemNative"; 4 | 5 | const COMP = "RadioItem"; 6 | 7 | export const RadioItemMd = createMetadata({ 8 | status: "experimental", 9 | description: `The \`${COMP}\` component is a radio button that is part of a group of radio buttons.`, 10 | props: { 11 | checked: { 12 | description: "This property specifies whether the radio button is checked.", 13 | defaultValue: defaultProps.checked, 14 | }, 15 | value: { 16 | description: "This property specifies the value of the radio button.", 17 | defaultValue: defaultProps.value, 18 | }, 19 | }, 20 | events: { 21 | didChange: dDidChange(COMP), 22 | }, 23 | }); 24 | 25 | export const radioItemComponentRenderer = createComponentRenderer( 26 | COMP, 27 | RadioItemMd, 28 | ({ node, extractValue, lookupEventHandler }) => { 29 | return ( 30 | <RadioItem 31 | checked={extractValue(node.props.checked)} 32 | value={extractValue(node.props.value)} 33 | onDidChange={lookupEventHandler("didChange")} 34 | /> 35 | ); 36 | }, 37 | ); 38 | ``` -------------------------------------------------------------------------------- /docs/public/pages/xmlui-charts/DonutChart.md: -------------------------------------------------------------------------------- ```markdown 1 | # DonutChart [#donutchart] 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 derivative of the pie chart that is a donut chart. 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 | ### `innerRadius (default: 60)` 17 | 18 | Sets the inner radius of the donut chart. 19 | 20 | ### `nameKey` 21 | 22 | Specifies the key in the data objects that will be used to label the different data series. 23 | 24 | ### `showLabel (default: true)` 25 | 26 | Toggles whether to show labels (`true`) or not (`false`). 27 | 28 | ### `showLabelList (default: false)` 29 | 30 | Whether to show labels in a list (`true`) or not (`false`). 31 | 32 | ### `showLegend (default: false)` 33 | 34 | Whether to show a legend (`true`) or not (`false`). 35 | 36 | ## Events 37 | 38 | This component does not have any events. 39 | 40 | ## Exposed Methods 41 | 42 | This component does not expose any methods. 43 | 44 | ## Styling 45 | 46 | This component does not have any styles. 47 | ``` -------------------------------------------------------------------------------- /.github/workflows/prepare-versions.yml: -------------------------------------------------------------------------------- ```yaml 1 | name: Prepare versions for release 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | permissions: 7 | contents: write 8 | pull-requests: write 9 | id-token: write 10 | 11 | jobs: 12 | create_version_pr: 13 | name: Create Stable Version PR 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout Repo 17 | uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Setup Node.js 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: 22 25 | cache: 'npm' 26 | 27 | - name: Install Dependencies 28 | run: npm ci --prefer-offline 29 | 30 | - name: Create Version PR 31 | id: changesets_pr 32 | uses: changesets/action@v1 33 | with: 34 | # Command to run for versioning. 35 | version: npm run changeset:version 36 | commit: 'chore: version packages for stable release' 37 | title: 'Version Packages for Stable Release' 38 | env: 39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | 41 | - name: Output Changeset PR URL 42 | if: steps.changesets_pr.outputs.pullRequestUrl 43 | run: | 44 | echo "Version PR created: ${{ steps.changesets_pr.outputs.pullRequestUrl }}" ``` -------------------------------------------------------------------------------- /.github/workflows/deploy-docs.yml: -------------------------------------------------------------------------------- ```yaml 1 | name: Deploy docs 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | max_releases: 7 | description: "Maximum number of releases to include in docs" 8 | type: number 9 | required: false 10 | default: 10 11 | 12 | jobs: 13 | build-and-deploy: 14 | runs-on: ubuntu-latest 15 | env: 16 | NODE_OPTIONS: "--max-old-space-size=8192" 17 | TURBO_UI: "false" 18 | steps: 19 | - uses: actions/checkout@v4 20 | - uses: actions/setup-node@v4 21 | with: 22 | node-version: 22 23 | cache: "npm" 24 | registry-url: https://registry.npmjs.org/ 25 | 26 | - name: Cache for Turbo 27 | uses: rharkor/[email protected] 28 | 29 | - run: npm ci --prefer-offline 30 | 31 | - run: npm run build-docs 32 | env: 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | DOCS_XMLUI_MAX_RELEASES_LENGTH: ${{ github.event.inputs.max_releases }} 35 | 36 | - name: "Run Azure webapp deploy action using publish profile credentials" 37 | uses: azure/webapps-deploy@v2 38 | with: 39 | package: "docs/dist/ui.zip" 40 | app-name: xmlui-docs 41 | publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_XMLUI_DOCS }} 42 | ``` -------------------------------------------------------------------------------- /xmlui/src/components-core/interception/InMemoryDb.ts: -------------------------------------------------------------------------------- ```typescript 1 | import type { IDatabase, TableDescriptor } from "./abstractions"; 2 | 3 | export class InMemoryDb implements IDatabase { 4 | [key: string]: unknown; 5 | 6 | constructor( 7 | private tables: Array<TableDescriptor> | undefined, 8 | private initialData: Record<string, any[]> | (() => Promise<Record<string, any[]>>) = {}, 9 | private config?: any, 10 | ) {} 11 | 12 | getItems(collectionName: string): Promise<any[]> { 13 | throw new Error("Method not implemented."); 14 | } 15 | getItem(collectionName: string, predicate: (item: any) => Promise<boolean>): Promise<any> { 16 | throw new Error("Method not implemented."); 17 | } 18 | getItemById(collectionName: string, id: any): Promise<any> { 19 | throw new Error("Method not implemented."); 20 | } 21 | deleteItems(collectionName: string, predicate: (item: any) => Promise<boolean>): Promise<void> { 22 | throw new Error("Method not implemented."); 23 | } 24 | insertItem(collectionName: string, item: any): Promise<any> { 25 | throw new Error("Method not implemented."); 26 | } 27 | updateItem(collectionName: string, item: any): Promise<any> { 28 | throw new Error("Method not implemented."); 29 | } 30 | 31 | public async initialize() {} 32 | } 33 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/TreeDisplay/TreeDisplay.md: -------------------------------------------------------------------------------- ```markdown 1 | %-DESC-START 2 | 3 | ```xmlui-pg copy display name="Example: using TreeDisplay" 4 | <App> 5 | <TreeDisplay content="components 6 | ClientDetails.xmlui 7 | Clients.xmlui 8 | MonthlyRevenue.xmlui 9 | WeeklyRevenue.xmlui" /> 10 | </App> 11 | ``` 12 | 13 | ```xmlui-pg copy display name="Example: using TreeDisplay with deeper hierarchy" 14 | <App> 15 | <TreeDisplay> 16 | components 17 | frontend 18 | pages 19 | home.xmlui 20 | about.xmlui 21 | contact.xmlui 22 | components 23 | Header.xmlui 24 | Footer.xmlui 25 | backend 26 | api 27 | users.js 28 | products.js 29 | </TreeDisplay> 30 | </App> 31 | ``` 32 | 33 | ```xmlui-pg copy display name="Example: file structure with custom theme color" 34 | <App> 35 | <TreeDisplay 36 | content="project 37 | src 38 | components 39 | TreeDisplay.tsx 40 | utils 41 | helpers.ts 42 | package.json"> 43 | <property name="style"> 44 | { 45 | "--color-connect-TreeDisplay": "var(--accentColor)" 46 | } 47 | </property> 48 | </TreeDisplay> 49 | </App> 50 | ``` 51 | 52 | **Note:** TreeDisplay interprets indentation (spaces at the beginning of lines) to determine the hierarchy level. Each indentation level represents a level in the tree structure. The component uses SVG lines to create clean, modern connecting lines between tree nodes. 53 | 54 | %-DESC-END 55 | ``` -------------------------------------------------------------------------------- /docs/content/components/Page.md: -------------------------------------------------------------------------------- ```markdown 1 | # Page [#page] 2 | 3 | `Page` defines route endpoints within an application, mapping specific URL patterns to content that displays when users navigate to those routes. Each Page represents a distinct view or screen in your single-page application's routing system. 4 | 5 | **Key features:** 6 | - **Navigation**: Activated by [NavLink](/components/NavLink) or programmatic navigation (`Actions.navigate()`) 7 | - **Content container**: Wraps any XMLUI components to define what displays for each route 8 | - **URL pattern matching**: Maps exact URLs or dynamic patterns with parameters to specific content 9 | - **Route parameters**: Supports dynamic URL segments (e.g., `/user/:id`) accessible via `$routeParams` 10 | - **Query parameter access**: Retrieves URL query parameters through `$queryParams` context variable 11 | 12 | ## Properties [#properties] 13 | 14 | ### `url` [#url] 15 | 16 | The URL of the route associated with the content. If not set, the page is not available. 17 | 18 | ## Events [#events] 19 | 20 | This component does not have any events. 21 | 22 | ## Exposed Methods [#exposed-methods] 23 | 24 | This component does not expose any methods. 25 | 26 | ## Styling [#styling] 27 | 28 | This component does not have any styles. 29 | ``` -------------------------------------------------------------------------------- /docs/public/pages/xmlui-charts/_overview.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Xmlui Charts Package 2 | 3 | The `Charts` package contains components that display data in a graphical way.All chart components use the same set of properties to receive data.All chart components accept a `LabelLst` component as a child to parametrize display labels.All chart components also accept a `Legend` component as a child to display the legend. 4 | 5 | ## Package Components 6 | 7 | | Component | Description | Status | 8 | | :---: | --- | :---: | 9 | | [BarChart](./xmlui-charts/BarChart) | The `BarChart` component represents a bar chart.Accepts a `LabelLst` component as a child to parametrize display labels. | experimental | 10 | | [DonutChart](./xmlui-charts/DonutChart) | Represents a derivative of the pie chart that is a donut chart. | experimental | 11 | | [LabelList](./xmlui-charts/LabelList) | Label list component for a chart component. | experimental | 12 | | [Legend](./xmlui-charts/Legend) | Legend component to be displayed in a chart component. | experimental | 13 | | [LineChart](./xmlui-charts/LineChart) | Represents a line chart component. | experimental | 14 | | [PieChart](./xmlui-charts/PieChart) | Represents a pie chart component. | experimental | 15 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Icon/svg/binding.svg: -------------------------------------------------------------------------------- ``` 1 | <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path d="M10 13C10.4295 13.5741 10.9774 14.0491 11.6066 14.3929C12.2357 14.7367 12.9315 14.9411 13.6467 14.9923C14.3618 15.0435 15.0796 14.9403 15.7513 14.6897C16.4231 14.4392 17.0331 14.047 17.54 13.54L20.54 10.54C21.4508 9.59695 21.9548 8.33394 21.9434 7.02296C21.932 5.71198 21.4061 4.45791 20.4791 3.53087C19.5521 2.60383 18.298 2.07799 16.987 2.0666C15.676 2.0552 14.413 2.55918 13.47 3.46997L11.75 5.17997" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> 3 | <path d="M14.0002 11.0012C13.5707 10.4271 13.0228 9.95202 12.3936 9.60826C11.7645 9.2645 11.0687 9.06009 10.3535 9.00887C9.63841 8.95765 8.92061 9.06083 8.24885 9.31142C7.5771 9.56201 6.96709 9.95413 6.4602 10.4612L3.4602 13.4612C2.54941 14.4042 2.04544 15.6672 2.05683 16.9782C2.06822 18.2892 2.59407 19.5433 3.52111 20.4703C4.44815 21.3973 5.70221 21.9232 7.01319 21.9346C8.32418 21.946 9.58719 21.442 10.5302 20.5312L12.2402 18.8212" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> 4 | </svg> 5 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Charts/Legend/LegendNative.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import * as RechartsPrimitive from "recharts"; 2 | import { useLegend } from "../utils/ChartProvider"; 3 | import { useEffect, useMemo } from "react"; 4 | import type { 5 | HorizontalAlignmentType, 6 | VerticalAlignmentType, 7 | } from "recharts/types/component/DefaultLegendContent"; 8 | 9 | const RLegend = RechartsPrimitive.Legend; 10 | 11 | type Props = { 12 | verticalAlign?: VerticalAlignmentType; 13 | align?: HorizontalAlignmentType; 14 | }; 15 | 16 | export const verticalAlignmentValues: readonly VerticalAlignmentType[] = [ 17 | "top", 18 | "bottom", 19 | "middle", 20 | ] as const; 21 | export const horizontalAlignmentValues: readonly HorizontalAlignmentType[] = [ 22 | "left", 23 | "right", 24 | "center", 25 | ] as const; 26 | 27 | export const defaultProps: Pick<Props, "verticalAlign" | "align"> = { 28 | verticalAlign: "bottom", 29 | align: "center", 30 | }; 31 | 32 | export const Legend = ({ 33 | verticalAlign = defaultProps.verticalAlign, 34 | align = defaultProps.align, 35 | }: Props) => { 36 | const { setLegend } = useLegend(); 37 | 38 | const content = useMemo( 39 | () => <RLegend align={align} verticalAlign={verticalAlign} />, 40 | [align, verticalAlign], 41 | ); 42 | 43 | useEffect(() => { 44 | setLegend(content); 45 | }, [content, setLegend]); 46 | 47 | return null; 48 | }; 49 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Icon/svg/photo.svg: -------------------------------------------------------------------------------- ``` 1 | <svg viewBox="0 0 22 28" fill="none" xmlns="http://www.w3.org/2000/svg"> <g clip-path="url(#clip0_1960_14734)"> <path d="M22.2271 7.38281L16.304 5.74219L14.6117 0H1.91936C0.984697 0 0.227051 0.734508 0.227051 1.64062V26.3594C0.227051 27.2655 0.984697 28 1.91936 28H20.5347C21.4694 28 22.2271 27.2655 22.2271 26.3594V7.38281Z" fill="#F2F2F2"/> <path d="M22.2271 7.38281V26.3594C22.2271 27.2655 21.4695 28 20.5348 28H11.3625V0H14.6117L16.304 5.74219L22.2271 7.38281Z" fill="#F2F2F2"/> <path d="M22.227 7.38281H16.3039C15.3731 7.38281 14.6116 6.64453 14.6116 5.74219V0C14.8316 0 15.0516 0.0820312 15.2038 0.246148L21.9731 6.80865C22.1423 6.95625 22.227 7.16953 22.227 7.38281Z" fill="#E1E1E1"/> <path d="M9 17L14.1962 21.5H3.80385L9 17Z" fill="#8BDC6F"/> <path d="M13 14L18.1963 21.5H7.80396L13 14Z" fill="#8BDC6F"/> <circle cx="7" cy="11" r="2" fill="#EFC942"/> </g> <defs> <clipPath id="clip0_1960_14734"> <rect width="22" height="28" fill="white"/> </clipPath> </defs></svg> ``` -------------------------------------------------------------------------------- /docs/content/components/xmlui-animations/FadeAnimation.md: -------------------------------------------------------------------------------- ```markdown 1 | # FadeAnimation [#fadeanimation] 2 | 3 | The `FadeAnimation` component represents an animation that fades the content with adjustable opacity values. 4 | 5 | ## Properties 6 | 7 | ### `animateWhenInView` 8 | 9 | Indicates whether the animation should start when the component is in view 10 | 11 | ### `delay` (default: 0) 12 | 13 | The delay before the animation starts in milliseconds 14 | 15 | ### `duration` 16 | 17 | The duration of the animation in milliseconds 18 | 19 | ### `from` (default: 0) 20 | 21 | Sets the initial opacity of the content.If the `to` property is not set, the initial opacity set here will be used as the final opacity. 22 | 23 | ### `loop` (default: false) 24 | 25 | Indicates whether the animation should loop 26 | 27 | ### `reverse` (default: false) 28 | 29 | Indicates whether the animation should run in reverse 30 | 31 | ### `to` (default: 1) 32 | 33 | Sets the final opacity of the content.If the `from` property is not set, the initial opacity set here will be used as the final opacity. 34 | 35 | ## Events 36 | 37 | ### `started` 38 | 39 | Event fired when the animation starts 40 | 41 | ### `stopped` 42 | 43 | Event fired when the animation stops 44 | 45 | ## Exposed Methods 46 | 47 | ### `start` 48 | 49 | Starts the animation 50 | 51 | ### `stop` 52 | 53 | Stops the animation 54 | 55 | ## Styling 56 | 57 | This component does not have any styles. 58 | ``` -------------------------------------------------------------------------------- /docs/content/extensions/xmlui-animations/FadeAnimation.md: -------------------------------------------------------------------------------- ```markdown 1 | # FadeAnimation [#fadeanimation] 2 | 3 | The `FadeAnimation` component represents an animation that fades the content with adjustable opacity values. 4 | 5 | ## Properties 6 | 7 | ### `animateWhenInView` 8 | 9 | Indicates whether the animation should start when the component is in view 10 | 11 | ### `delay` (default: 0) 12 | 13 | The delay before the animation starts in milliseconds 14 | 15 | ### `duration` 16 | 17 | The duration of the animation in milliseconds 18 | 19 | ### `from` (default: 0) 20 | 21 | Sets the initial opacity of the content.If the `to` property is not set, the initial opacity set here will be used as the final opacity. 22 | 23 | ### `loop` (default: false) 24 | 25 | Indicates whether the animation should loop 26 | 27 | ### `reverse` (default: false) 28 | 29 | Indicates whether the animation should run in reverse 30 | 31 | ### `to` (default: 1) 32 | 33 | Sets the final opacity of the content.If the `from` property is not set, the initial opacity set here will be used as the final opacity. 34 | 35 | ## Events 36 | 37 | ### `started` 38 | 39 | Event fired when the animation starts 40 | 41 | ### `stopped` 42 | 43 | Event fired when the animation stops 44 | 45 | ## Exposed Methods 46 | 47 | ### `start` 48 | 49 | Starts the animation 50 | 51 | ### `stop` 52 | 53 | Stops the animation 54 | 55 | ## Styling 56 | 57 | This component does not have any styles. 58 | ``` -------------------------------------------------------------------------------- /docs/public/pages/howto/delegate-a-method.md: -------------------------------------------------------------------------------- ```markdown 1 | # Delegate a method 2 | 3 | Use `method.` attributes to directly delegate to internal component methods: 4 | 5 | ```xmlui-pg height="350px" 6 | ---app display 7 | <App> 8 | <H3>Method Delegation Example</H3> 9 | 10 | <Button 11 | label="Open Modal" 12 | onClick="myModal.openDialog()" /> 13 | 14 | <MyModalWrapper id="myModal" title="Hello World!" /> 15 | </App> 16 | 17 | ---comp display 18 | <Component 19 | name="MyModalWrapper" 20 | method.openDialog="internalModal.open()" 21 | method.close="internalModal.close()"> 22 | 23 | <ModalDialog 24 | id="internalModal" 25 | title="{$props.title}" 26 | maxWidth="400px"> 27 | <VStack> 28 | <Text>This uses method.openDialog="internalModal.open()"</Text> 29 | <Text>Direct delegation - no custom logic needed</Text> 30 | 31 | <Button 32 | label="Close" 33 | onClick="internalModal.close()" /> 34 | </VStack> 35 | </ModalDialog> 36 | </Component> 37 | ``` 38 | 39 | **Use delegation when**: You want to expose internal methods directly without adding custom logic. 40 | 41 | **Pros**: Simple, no JavaScript needed, clean syntax 42 | 43 | **Cons**: No custom logic, just passes through calls 44 | 45 | **See also**: [Expose a method from a component](/howto/expose-a-method-from-a-component) for adding custom logic to methods. ``` -------------------------------------------------------------------------------- /docs/public/pages/mcp.md: -------------------------------------------------------------------------------- ```markdown 1 | # xmlui-mcp: Model Context Protocol server for XMLUI 2 | 3 | The Model Context Procotol (MCP) enables AI agents to use third-party tools. If you are using an agent like Claude or Cursor, you can equip them with a set of XMLUI-specific tools so they can: 4 | 5 | - list available XMLUI components 6 | - review documentation for a component 7 | - search XMLUI source code and apps 8 | - list and search XMLUI How To docs 9 | - help you build your own XMLUI app 10 | 11 | The xmlui-mcp tookit is available [here](https://github.com/xmlui-org/xmlui-mcp). To use it, clone that repo and also the [XMLUI repo](https://github.com/xmlui-org/xmlui) to create this layout. 12 | 13 | ```xmlui-tree 14 | <root> 15 | xmlui 16 | xmlui-mcp 17 | ``` 18 | 19 | This is an example of a conversation with Claude in which it uses some of the xmlui-mcp tools. 20 | 21 | <img width="737" alt="image" src="https://github.com/user-attachments/assets/1f87519c-1338-4eca-a730-9f2e0c1a64a9" /> 22 | 23 | <img width="788" alt="image" src="https://github.com/user-attachments/assets/4793a475-46d1-418e-ad6a-0760af53ddca" /> 24 | 25 | See the [README](https://github.com/xmlui-org/xmlui-mcp?tab=readme-ov-file#configure) for details on configuring and using the MCP toolkit. 26 | 27 | 28 | 29 | 30 | 31 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Icon/svg/attach.svg: -------------------------------------------------------------------------------- ``` 1 | <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16px" height="16px" viewBox="0 0 16 16" version="1.1"> 2 | <g id="surface1"> 3 | <path stroke="none" fill-rule="nonzero" fill-opacity="1" d="M 9.886719 5.171875 L 6.113281 8.941406 C 5.855469 9.203125 5.855469 9.625 6.113281 9.886719 C 6.375 10.144531 6.796875 10.144531 7.058594 9.886719 L 10.828125 6.113281 C 11.609375 5.332031 11.609375 4.066406 10.828125 3.285156 C 10.046875 2.503906 8.78125 2.503906 8 3.285156 L 4.230469 7.058594 C 2.925781 8.359375 2.925781 10.46875 4.230469 11.769531 C 5.53125 13.074219 7.640625 13.074219 8.941406 11.769531 L 12.714844 8 L 13.65625 8.941406 L 9.886719 12.714844 C 8.0625 14.535156 5.109375 14.535156 3.285156 12.714844 C 1.464844 10.890625 1.464844 7.9375 3.285156 6.113281 L 7.058594 2.34375 C 8.359375 1.042969 10.46875 1.042969 11.769531 2.34375 C 13.074219 3.644531 13.074219 5.753906 11.769531 7.058594 L 8 10.828125 C 7.21875 11.609375 5.953125 11.609375 5.171875 10.828125 C 4.390625 10.046875 4.390625 8.78125 5.171875 8 L 8.941406 4.230469 Z M 9.886719 5.171875 "/> 4 | </g> 5 | </svg> 6 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/ChangeListener/ChangeListenerNative.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { useEffect, useMemo } from "react"; 2 | import { isEqual, throttle } from "lodash-es"; 3 | import { usePrevious } from "../../components-core/utils/hooks"; 4 | 5 | // ===================================================================================================================== 6 | // React ChangeListener component implementation 7 | 8 | type Props = { 9 | listenTo: any; 10 | onChange?: (newValue: any) => void; 11 | throttleWaitInMs?: number; 12 | }; 13 | 14 | export const defaultProps: Pick<Props, "throttleWaitInMs"> = { 15 | throttleWaitInMs: 0, 16 | }; 17 | 18 | export function ChangeListener({ listenTo, onChange, throttleWaitInMs = defaultProps.throttleWaitInMs }: Props) { 19 | const prevValue = usePrevious(listenTo); 20 | 21 | const throttledOnChange = useMemo(() => { 22 | if (throttleWaitInMs !== 0 && onChange) { 23 | return throttle(onChange, throttleWaitInMs, { 24 | leading: true, 25 | }); 26 | } 27 | return onChange; 28 | }, [onChange, throttleWaitInMs]); 29 | 30 | useEffect(() => { 31 | if (throttledOnChange && !isEqual(prevValue, listenTo)) { 32 | throttledOnChange?.({ 33 | prevValue, 34 | newValue: listenTo, 35 | }); 36 | } 37 | }, [listenTo, throttledOnChange, prevValue]); 38 | return null; 39 | } 40 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Charts/LabelList/LabelListNative.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import styles from "./LabelListNative.module.scss"; 2 | import type { LabelPosition } from "recharts/types/component/Label"; 3 | import type { CSSProperties } from "react"; 4 | import { useEffect, useMemo } from "react"; 5 | import { LabelList as RLabelList } from "recharts"; 6 | import { useChart, useLabelList } from "../utils/ChartProvider"; 7 | import classnames from "classnames"; 8 | 9 | type Props = { 10 | position: LabelPosition; 11 | nameKey?: string; 12 | style?: CSSProperties; 13 | className?: string; 14 | }; 15 | 16 | export const defaultProps: Pick<Props, "position"> = { 17 | position: "inside", 18 | }; 19 | 20 | export const LabelList = ({ position = defaultProps.position, nameKey: key, style, className }: Props) => { 21 | const { nameKey } = useChart(); 22 | const { setLabelList } = useLabelList(); 23 | 24 | const content = useMemo( 25 | () => ( 26 | <RLabelList 27 | key={"labelList"} 28 | position={position} 29 | className={classnames(styles.labelList, className)} 30 | dataKey={key || nameKey} 31 | stroke="none" 32 | style={style} 33 | /> 34 | ), 35 | [key, nameKey, position, style, className], 36 | ); 37 | 38 | useEffect(() => { 39 | setLabelList(content); 40 | }, [content, setLabelList]); 41 | 42 | return null; 43 | }; 44 | ``` -------------------------------------------------------------------------------- /packages/xmlui-playground/CHANGELOG.md: -------------------------------------------------------------------------------- ```markdown 1 | # xmlui-playground 2 | 3 | ## 0.1.10 4 | 5 | ### Patch Changes 6 | 7 | - 39e5d67: refactor: xmlui-playground 8 | 9 | ## 0.1.9 10 | 11 | ### Patch Changes 12 | 13 | - b390690: improve: xmlui-playground - toast message on share 14 | 15 | ## 0.1.8 16 | 17 | ### Patch Changes 18 | 19 | - 8f03ada: feat: show a helloworld app in the playground if no other content loads; add share button to the header 20 | 21 | ## 0.1.7 22 | 23 | ### Patch Changes 24 | 25 | - 79c1d8a: fix: allow the playground to use the same tone as its source 26 | 27 | ## 0.1.6 28 | 29 | ### Patch Changes 30 | 31 | - 7d255a9: Changed open in new window button tooltip label for all occurrences. 32 | - Updated dependencies [7d255a9] 33 | - [email protected] 34 | 35 | ## 0.1.5 36 | 37 | ### Patch Changes 38 | 39 | - 2a461d8: NestedApp works with ApiInterceptor 40 | - Updated dependencies [f5b9f15] 41 | - [email protected] 42 | 43 | ## 0.1.4 44 | 45 | ### Patch Changes 46 | 47 | - 2e88539: improve: add Tooltip to DevTools 48 | - Updated dependencies [2e88539] 49 | - [email protected] 50 | 51 | ## 0.1.3 52 | 53 | ### Patch Changes 54 | 55 | - 3eab4a3: improve: design updates - devtools, playground, docs 56 | - Updated dependencies [3eab4a3] 57 | - [email protected] 58 | 59 | ## 0.1.2 60 | 61 | ### Patch Changes 62 | 63 | - bae8280: rework preview component 64 | 65 | ## 0.1.1 66 | 67 | ### Patch Changes 68 | 69 | - 4019d82: xmlui-playground, new exports from xmlui 70 | ``` -------------------------------------------------------------------------------- /docs/content/components/LabelList.md: -------------------------------------------------------------------------------- ```markdown 1 | # LabelList [#labellist] 2 | 3 | `LabelList` adds custom data labels to chart components when automatic labeling isn't sufficient. It's a specialized component for advanced chart customization scenarios where you need precise control over label positioning and appearance. 4 | 5 | ## Properties [#properties] 6 | 7 | ### `key` [#key] 8 | 9 | The key that needs to be matched to the data series. 10 | 11 | ### `position` (default: "inside") [#position-default-inside] 12 | 13 | The position of the label list 14 | 15 | Available values: `top`, `left`, `right`, `bottom`, `inside` **(default)**, `outside`, `insideLeft`, `insideRight`, `insideTop`, `insideBottom`, `insideTopLeft`, `insideBottomLeft`, `insideTopRight`, `insideBottomRight`, `insideStart`, `insideEnd`, `end`, `center`, `centerTop`, `centerBottom`, `middle` 16 | 17 | ## Events [#events] 18 | 19 | This component does not have any events. 20 | 21 | ## Exposed Methods [#exposed-methods] 22 | 23 | This component does not expose any methods. 24 | 25 | ## Styling [#styling] 26 | 27 | ### Theme Variables [#theme-variables] 28 | 29 | | Variable | Default Value (Light) | Default Value (Dark) | 30 | | --- | --- | --- | 31 | | [textColor](../styles-and-themes/common-units/#color)-LabelList | $textColor-primary | $textColor-primary | 32 | ``` -------------------------------------------------------------------------------- /xmlui/src/parsers/style-parser/StyleInputStream.ts: -------------------------------------------------------------------------------- ```typescript 1 | // This class represents the input stream of the layout parser 2 | export class StyleInputStream { 3 | // --- Current stream position 4 | private _pos = 0; 5 | 6 | // Creates a stream that uses the specified source code 7 | constructor (public readonly source: string) {} 8 | 9 | // Gets the current position in the stream. Starts from 0. 10 | get position (): number { 11 | return this._pos; 12 | } 13 | 14 | // Peeks the next character in the stream. Returns null, if EOF; otherwise the current source code character 15 | peek (): string | null { 16 | return this.ahead(0); 17 | } 18 | 19 | // Looks ahead with `n` characters in the stream. Returns null, if EOF; otherwise the look-ahead character 20 | ahead (n: number = 1): string | null { 21 | return this._pos + n > this.source.length - 1 ? null : this.source[this._pos + n]; 22 | } 23 | 24 | // Gets the next character from the stream 25 | get (): string | null { 26 | // --- Check for EOF 27 | if (this._pos >= this.source.length) { 28 | return null; 29 | } 30 | 31 | // --- Get the char, and keep track of position 32 | return this.source[this._pos++]; 33 | } 34 | 35 | // Gets the tail of the input stream 36 | getTail (start: number): string { 37 | return this.source?.substring(start) ?? ""; 38 | } 39 | } 40 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Spinner/Spinner.md: -------------------------------------------------------------------------------- ```markdown 1 | %-DESC-START 2 | 3 | While it is visible, the action is yet to be completed; on completion, the UI logic may opt to remove the component. 4 | 5 | ## Using the `Spinner` 6 | 7 | ```xmlui-pg copy display name="Example: using Spinner" 8 | <App> 9 | <Spinner /> 10 | </App> 11 | ``` 12 | 13 | >[!INFO] 14 | > `Spinner` ignores the `width`, `minWidth`, `maxWidth`, `height`, `minHeight`, and `maxHeight` properties. If you want to change its size, use the `size-Spinner` theme variable (see details is the [Styling](#styling) section). 15 | 16 | %-DESC-END 17 | 18 | %-PROP-START delay 19 | 20 | Use the buttons to toggle between the two `Spinners`. 21 | 22 | ```xmlui-pg copy {8-9} display name="Example: delay" 23 | <App> 24 | <variable name="noDelay" value="{true}" /> 25 | <variable name="yesDelay" value="{false}" /> 26 | <HStack gap="$space-0_5"> 27 | <Button label="No delay" onClick="noDelay = true; yesDelay = false;" /> 28 | <Button label="1000 ms delay" onClick="noDelay = false; yesDelay = true;" /> 29 | </HStack> 30 | <Spinner when="{noDelay}" delay="0" /> 31 | <Spinner when="{yesDelay}" delay="1000" /> 32 | </App> 33 | ``` 34 | 35 | %-PROP-END 36 | 37 | %-PROP-START fullScreen 38 | 39 | ```xmlui-pg copy display name="Example: fullScreen" height="200px" 40 | <App> 41 | <Spinner fullScreen="true" /> 42 | </App> 43 | ``` 44 | 45 | %-PROP-END 46 | ``` -------------------------------------------------------------------------------- /docs/public/pages/howto/modify-a-value-reported-in-a-column.md: -------------------------------------------------------------------------------- ```markdown 1 | # Modify a value reported in a Column 2 | 3 | ```xmlui-pg noHeader 4 | ---app 5 | <App> 6 | <Test /> 7 | </App> 8 | ---comp display 9 | <Component name="Test"> 10 | <DataSource 11 | id="invoices_with_badges" 12 | url="/resources/files/invoices.json" 13 | transformResult="{data => data.slice(0,5)}" 14 | /> 15 | <Table data="{invoices_with_badges}"> 16 | <Column bindTo="invoice_number" /> <!-- empty tag for bound column --> 17 | <Column bindTo="client" /> 18 | <Column bindTo="issue_date" /> 19 | <Column bindTo="due_date" /> 20 | <Column bindTo="paid_date" /> 21 | <Column header="total"> 22 | ${$item.total} <!-- unbound column, prepend $ to the $item value --> 23 | </Column> 24 | <Column header="status"> 25 | <StatusBadge status="{$item.status}" /> <!-- embed component, pass value --> 26 | </Column> 27 | </Table> 28 | </Component> 29 | ---comp display 30 | <Component 31 | name="StatusBadge" 32 | var.statusColors="{{ 33 | draft: { background: '#f59e0b', label: 'white' }, 34 | sent: { background: '#3b82f6', label: 'white' }, 35 | paid: { background: '#10b981', label: 'white' } 36 | }}" 37 | > 38 | <Badge 39 | value="{$props.status}" 40 | colorMap="{statusColors}" 41 | variant="pill" 42 | /> 43 | </Component> 44 | ``` 45 | ``` -------------------------------------------------------------------------------- /docs/public/resources/images/logos/xmlui5.svg: -------------------------------------------------------------------------------- ``` 1 | <svg width="75" height="32" viewBox="0 0 75 32" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <rect x="46" y="2" width="29" height="21" fill="#DA020F"/> 3 | <path d="M7.93731 13.2963L12.4267 20H9.21133L6.11729 14.9646L3.02326 20H0L4.40849 13.1345L0.283114 6.69363H3.39737L6.25885 11.4863L9.06977 6.69363H12.1132L7.93731 13.2963ZM26.6878 13.7007C26.6878 13.276 26.6878 12.939 26.6878 12.6896C26.6945 12.4334 26.7417 11.3987 26.8294 9.58544H26.7485L23.3107 20H20.7323L17.527 9.56522H17.4461C17.5607 11.756 17.618 13.1716 17.618 13.8119V20H15.1003V6.69363H18.9325L22.0872 16.8655H22.1377L25.4745 6.69363H29.3167V20H26.6878V13.7007ZM41.8888 20H33.6785V6.69363H36.4995V17.6744H41.8888V20Z" fill="black"/> 4 | <path d="M59.585 6.69363H62.406V15.3084C62.4195 16.7846 61.9241 17.971 60.9197 18.8675C59.9153 19.7641 58.5705 20.2022 56.8853 20.182C55.1664 20.182 53.8351 19.7438 52.8914 18.8675C51.9544 17.9845 51.4859 16.7846 51.4859 15.2679V6.69363H54.2968V14.8433C54.2968 15.8814 54.5024 16.6363 54.9136 17.1082C55.3315 17.58 56.0056 17.816 56.9358 17.816C57.8728 17.816 58.5469 17.5767 58.9581 17.0981C59.376 16.6195 59.585 15.8611 59.585 14.8231V6.69363ZM69.48 20H66.6589V6.69363H69.48V20Z" fill="white"/> 5 | </svg> 6 | ``` -------------------------------------------------------------------------------- /xmlui/tests/components-core/scripts-runner/test-helpers.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Expression, Statement } from "../../../src/components-core/script-runner/ScriptingSourceTree"; 2 | import { BindingTreeEvaluationContext } from "../../../src/components-core/script-runner/BindingTreeEvaluationContext"; 3 | import { Parser } from "../../../src/parsers/scripting/Parser"; 4 | 5 | export function createEvalContext (parts: Partial<BindingTreeEvaluationContext>): BindingTreeEvaluationContext { 6 | return { 7 | ...{ 8 | mainThread: { 9 | childThreads: [], 10 | blocks: [{ vars: {} }], 11 | loops: [], 12 | breakLabelValue: -1 13 | } 14 | }, 15 | ...parts 16 | }; 17 | } 18 | 19 | export function parseStatements (source: string): Statement[] { 20 | const wParser = new Parser(source); 21 | const tree = wParser.parseStatements(); 22 | if (tree === null) { 23 | // --- This should happen only there were errors during the parse phase 24 | throw new Error("Source code parsing failed"); 25 | } 26 | return tree; 27 | } 28 | 29 | export function parseExpression (source: string): Expression { 30 | const wParser = new Parser(source); 31 | const tree = wParser.parseExpr(); 32 | if (tree === null) { 33 | // --- This should happen only there were errors during the parse phase 34 | throw new Error("Source code parsing failed"); 35 | } 36 | return tree; 37 | } 38 | ``` -------------------------------------------------------------------------------- /tools/create-app/helpers/copy.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { async as glob } from "fast-glob"; 2 | import path from "path"; 3 | import fs from "fs"; 4 | 5 | interface CopyOption { 6 | cwd?: string; 7 | rename?: (basename: string) => string; 8 | parents?: boolean; 9 | } 10 | 11 | const identity = (x: string) => x; 12 | 13 | export const copy = async ( 14 | src: string | string[], 15 | dest: string, 16 | { cwd, rename = identity, parents = true }: CopyOption = {} 17 | ) => { 18 | const source = typeof src === "string" ? [src] : src; 19 | 20 | if (source.length === 0 || !dest) { 21 | throw new TypeError("`src` and `dest` are required"); 22 | } 23 | 24 | const sourceFiles = await glob(source, { 25 | cwd, 26 | dot: true, 27 | absolute: false, 28 | stats: false, 29 | }); 30 | 31 | const destRelativeToCwd = cwd ? path.resolve(cwd, dest) : dest; 32 | 33 | return Promise.all( 34 | sourceFiles.map(async (p) => { 35 | const dirname = path.dirname(p); 36 | const basename = rename(path.basename(p)); 37 | 38 | const from = cwd ? path.resolve(cwd, p) : p; 39 | const to = parents ? path.join(destRelativeToCwd, dirname, basename) : path.join(destRelativeToCwd, basename); 40 | 41 | // Ensure the destination directory exists 42 | await fs.promises.mkdir(path.dirname(to), { recursive: true }); 43 | 44 | return fs.promises.copyFile(from, to); 45 | }) 46 | ); 47 | }; 48 | ``` -------------------------------------------------------------------------------- /docs/public/pages/howto/expose-a-method-from-a-component.md: -------------------------------------------------------------------------------- ```markdown 1 | # Expose a method from a component 2 | 3 | Use the `<method>` element to create custom methods with JavaScript logic: 4 | 5 | ```xmlui-pg height="350px" 6 | ---app display 7 | <App> 8 | <H3>Custom Method Example</H3> 9 | 10 | <Button 11 | label="Open Modal" 12 | onClick="myModal.openDialog()" /> 13 | 14 | <MyModalWrapper id="myModal" title="Hello World!" /> 15 | </App> 16 | ---comp display 17 | <Component name="MyModalWrapper"> 18 | <ModalDialog id="internalModal" title="{$props.title}" maxWidth="400px"> 19 | <VStack gap="$space-3" padding="$space-4"> 20 | <Text>This uses a custom method with JavaScript logic</Text> 21 | <Text>Check the console for the log message</Text> 22 | 23 | <Button 24 | label="Close" 25 | onClick="internalModal.close()" /> 26 | </VStack> 27 | </ModalDialog> 28 | 29 | <method name="openDialog"> 30 | console.log('Custom method called - opening modal'); 31 | internalModal.open(); 32 | </method> 33 | </Component> 34 | ``` 35 | 36 | **Use custom methods when**: You need to add logging, validation, or other logic before/after calling internal methods. 37 | 38 | **Pros**: Full JavaScript control, can add custom logic 39 | 40 | **Cons**: More complex, requires JavaScript knowledge 41 | 42 | **See also**: [Delegate a method](/howto/delegate-a-method) for a simpler approach without custom logic. ``` -------------------------------------------------------------------------------- /xmlui/src/components/Footer/FooterNative.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import type { ForwardedRef, ReactNode } from "react"; 2 | import type React from "react"; 3 | import { forwardRef } from "react"; 4 | import classnames from "classnames"; 5 | 6 | import styles from "./Footer.module.scss"; 7 | 8 | import { useAppLayoutContext } from "../App/AppLayoutContext"; 9 | 10 | // ===================================================================================================================== 11 | // React Footer component implementation 12 | 13 | export const defaultProps = { 14 | // No default props needed currently, but adding object for consistency 15 | }; 16 | 17 | export const Footer = forwardRef(function Footer( 18 | { 19 | children, 20 | style, 21 | className, 22 | ...rest 23 | }: { 24 | children: ReactNode; 25 | style?: React.CSSProperties; 26 | className?: string; 27 | }, 28 | forwardedRef: ForwardedRef<HTMLDivElement>, 29 | ) { 30 | const { layout } = useAppLayoutContext() || {}; 31 | const canRestrictContentWidth = layout !== "vertical-full-header"; 32 | return ( 33 | <div {...rest} className={styles.outerWrapper} ref={forwardedRef} style={style} role="contentinfo"> 34 | <div 35 | className={classnames(styles.wrapper, className, { 36 | [styles.full]: !canRestrictContentWidth, 37 | })} 38 | > 39 | {children} 40 | </div> 41 | </div> 42 | ); 43 | }); 44 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/EmojiSelector/EmojiSelector.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { createComponentRenderer } from "../../components-core/renderers"; 2 | import { useTheme } from "../../components-core/theming/ThemeContext"; 3 | import { createMetadata, d, dAutoFocus } from "../metadata-helpers"; 4 | import { EmojiSelector } from "./EmojiSelectorNative"; 5 | import { defaultProps } from "./EmojiSelectorNative"; 6 | 7 | const COMP = "EmojiSelector"; 8 | 9 | export const EmojiSelectorMd = createMetadata({ 10 | status: "experimental", 11 | description: 12 | "`EmojiSelector` enables users to browse, search and select emojis from " + 13 | "their system's native emoji set.", 14 | props: { 15 | autoFocus: { 16 | ...dAutoFocus(), 17 | defaultValue: defaultProps.autoFocus, 18 | }, 19 | }, 20 | events: { 21 | select: d(`This event is fired when the user selects an emoticon from this component.`), 22 | }, 23 | }); 24 | 25 | export const emojiSelectorRenderer = createComponentRenderer( 26 | COMP, 27 | EmojiSelectorMd, 28 | ({ node, lookupEventHandler, extractValue }) => { 29 | const onActionSelect = lookupEventHandler("select"); 30 | const theme = useTheme(); 31 | 32 | return ( 33 | <EmojiSelector 34 | select={onActionSelect} 35 | theme={theme.activeThemeTone as any} 36 | autoFocus={extractValue.asOptionalBoolean(node.props.autoFocus)} 37 | /> 38 | ); 39 | }, 40 | ); 41 | ``` -------------------------------------------------------------------------------- /docs/public/pages/xmlui-animations/_overview.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Xmlui Animations Package 2 | 3 | This package contains components that deal with different sorts of animations. 4 | These components can wrap other components and provide different sorts of animations that run when the child component visibility changes. 5 | 6 | ## Package Components 7 | 8 | | Component | Description | Status | 9 | | :---: | --- | :---: | 10 | | [Animation](./xmlui-animations/Animation) | | experimental | 11 | | [FadeAnimation](./xmlui-animations/FadeAnimation) | The `FadeAnimation` component represents an animation that fades the content with adjustable opacity values. | experimental | 12 | | [FadeInAnimation](./xmlui-animations/FadeInAnimation) | The `FadeInAnimation` component represents an animation that fades in the content. | experimental | 13 | | [FadeOutAnimation](./xmlui-animations/FadeOutAnimation) | The `FadeOutAnimation` component represents an animation that fades out the content. | experimental | 14 | | [ScaleAnimation](./xmlui-animations/ScaleAnimation) | The `ScaleAnimation` component represents an animation that scales the content. | experimental | 15 | | [SlideInAnimation](./xmlui-animations/SlideInAnimation) | The `SlideInAnimation` component represents an animation that slides in the content from the left. | experimental | 16 | ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "xmlui-root", 3 | "version": "1.0.0", 4 | "description": "Root folder of XMLUI", 5 | "private": true, 6 | "workspaces": [ 7 | "./xmlui", 8 | "./docs", 9 | "./blog", 10 | "./tools/create-app", 11 | "./tools/vscode", 12 | "./packages/*" 13 | ], 14 | "devDependencies": { 15 | "@changesets/cli": "^2.29.4", 16 | "@typescript-eslint/eslint-plugin": "^8.15.0", 17 | "turbo": "^2.5.6" 18 | }, 19 | "packageManager": "[email protected]", 20 | "scripts": { 21 | "changeset:add": "changeset add", 22 | "changeset:version": "changeset version", 23 | "changeset:publish": "changeset publish", 24 | "build-xmlui": "turbo run build:xmlui-all", 25 | "build-vscode-extension": "turbo run xmlui-vscode#build:vsix", 26 | "test-xmlui:ci": "CI=true npm run test-xmlui", 27 | "test-xmlui:ci-win": "set CI=true && npm run test-xmlui", 28 | "test-xmlui": "turbo run build:xmlui-all test:xmlui-all", 29 | "test-xmlui-smoke": "turbo run build:xmlui-all test:xmlui-smoke", 30 | "publish-packages": "turbo run build:xmlui-all test:xmlui-all && npm run changeset:publish", 31 | "build-extensions": "turbo run build:extension", 32 | "build-docs": "turbo run build:docs", 33 | "watch-docs-content": "turbo watch generate-docs-summaries", 34 | "generate-docs": "turbo run generate-docs" 35 | } 36 | } 37 | ``` -------------------------------------------------------------------------------- /docs/public/resources/images/logos/xmlui1.svg: -------------------------------------------------------------------------------- ``` 1 | <svg width="65" height="24" viewBox="0 0 65 24" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path d="M4.14773 4.45455L7.08097 9.41193H7.1946L10.142 4.45455H13.6151L9.17614 11.7273L13.7145 19H10.1776L7.1946 14.0355H7.08097L4.09801 19H0.575284L5.12784 11.7273L0.660511 4.45455H4.14773ZM15.5611 4.45455H19.3537L23.3594 14.2273H23.5298L27.5355 4.45455H31.3281V19H28.3452V9.53267H28.2244L24.4602 18.929H22.429L18.6648 9.49716H18.544V19H15.5611V4.45455ZM33.8619 19V4.45455H36.9371V16.4645H43.1729V19H33.8619Z" fill="#143566"/> 3 | <path d="M54.1939 4.45455H57.2692V13.9006C57.2692 14.9612 57.0159 15.8892 56.5092 16.6847C56.0073 17.4801 55.3042 18.1004 54.3999 18.5455C53.4955 18.9858 52.442 19.206 51.2393 19.206C50.032 19.206 48.9761 18.9858 48.0717 18.5455C47.1674 18.1004 46.4643 17.4801 45.9624 16.6847C45.4605 15.8892 45.2095 14.9612 45.2095 13.9006V4.45455H48.2848V13.6378C48.2848 14.1918 48.4055 14.6842 48.647 15.1151C48.8932 15.5459 49.2389 15.8845 49.6839 16.1307C50.129 16.3769 50.6475 16.5 51.2393 16.5C51.8359 16.5 52.3544 16.3769 52.7947 16.1307C53.2398 15.8845 53.5831 15.5459 53.8246 15.1151C54.0708 14.6842 54.1939 14.1918 54.1939 13.6378V4.45455ZM62.8746 4.45455V19H59.7994V4.45455H62.8746Z" fill="#DA020F"/> 4 | </svg> 5 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/StickyBox/StickyBox.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import styles from "./StickyBox.module.scss"; 2 | 3 | import { createComponentRenderer } from "../../components-core/renderers"; 4 | import { parseScssVar } from "../../components-core/theming/themeVars"; 5 | import { StickyBox, defaultProps } from "./StickyBoxNative"; 6 | import { createMetadata } from "../metadata-helpers"; 7 | 8 | const COMP = "StickyBox"; 9 | 10 | export const StickyBoxMd = createMetadata({ 11 | status: "stable", 12 | description: 13 | "`StickyBox` remains fixed at the top or bottom of the screen as the user scrolls.", 14 | props: { 15 | to: { 16 | description: 17 | "This property determines whether the StickyBox should be anchored to " + 18 | "the \`top\` or \`bottom\`.", 19 | availableValues: ["top", "bottom"], 20 | valueType: "string", 21 | defaultValue: defaultProps.to, 22 | }, 23 | }, 24 | themeVars: parseScssVar(styles.themeVars), 25 | defaultThemeVars: { 26 | [`backgroundColor-${COMP}`]: "$backgroundColor", 27 | }, 28 | }); 29 | 30 | export const stickyBoxComponentRenderer = createComponentRenderer( 31 | COMP, 32 | StickyBoxMd, 33 | ({ node, renderChild, extractValue, className }) => { 34 | return ( 35 | <StickyBox uid={node.uid} className={className} to={extractValue(node.props?.to)}> 36 | {renderChild(node.children)} 37 | </StickyBox> 38 | ); 39 | }, 40 | ); 41 | ``` -------------------------------------------------------------------------------- /xmlui/tests/parsers/scripting/test-helpers.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { BindingTreeEvaluationContext } from "../../../src/components-core/script-runner/BindingTreeEvaluationContext"; 2 | import { Parser } from "../../../src/parsers/scripting/Parser"; 3 | import {Expression, Statement} from "../../../src/components-core/script-runner/ScriptingSourceTree"; 4 | 5 | export function createEvalContext (parts: Partial<BindingTreeEvaluationContext>): BindingTreeEvaluationContext { 6 | return { 7 | ...{ 8 | mainThread: { 9 | childThreads: [], 10 | blocks: [{ vars: {} }], 11 | loops: [], 12 | breakLabelValue: -1 13 | }, 14 | valueCache: new Map(), 15 | }, 16 | ...parts 17 | }; 18 | } 19 | 20 | export function parseStatements (source: string): Statement[] { 21 | const wParser = new Parser(source); 22 | const tree = wParser.parseStatements(); 23 | if (tree === null) { 24 | // --- This should happen only there were errors during the parse phase 25 | throw new Error("Source code parsing failed"); 26 | } 27 | return tree; 28 | } 29 | 30 | export function parseExpression (source: string): Expression { 31 | const wParser = new Parser(source); 32 | const tree = wParser.parseExpr(); 33 | if (tree === null) { 34 | // --- This should happen only there were errors during the parse phase 35 | throw new Error("Source code parsing failed"); 36 | } 37 | return tree; 38 | } 39 | ``` -------------------------------------------------------------------------------- /packages/xmlui-pdf/src/Pdf.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { forwardRef, useState } from "react"; 2 | import styles from "./Pdf.module.scss"; 3 | import { Document, Page, pdfjs } from "react-pdf"; 4 | import workerUrl from "pdfjs-dist/build/pdf.worker.min.mjs?url"; 5 | import "react-pdf/dist/Page/TextLayer.css"; 6 | import "react-pdf/dist/Page/AnnotationLayer.css"; 7 | // 8 | pdfjs.GlobalWorkerOptions.workerSrc = workerUrl; 9 | 10 | // ===================================================================================================================== 11 | // React Pdf component implementation 12 | 13 | interface Props { 14 | src?: string; 15 | data?: any; // Binary data for PDF content 16 | } 17 | 18 | const Pdf = forwardRef(({ src, data }: Props, ref) => { 19 | const [numPages, setNumPages] = useState<number | null>(null); 20 | 21 | function onLoadSuccess({ numPages }: { numPages: number }) { 22 | setNumPages(numPages); 23 | } 24 | 25 | // Use data if provided, otherwise use src 26 | const fileSource = data || src; 27 | 28 | return ( 29 | <Document 30 | file={fileSource} 31 | onLoadSuccess={onLoadSuccess} 32 | className={styles.document} 33 | inputRef={ref as any} 34 | > 35 | {Array.from(new Array(numPages), (_, index) => ( 36 | <Page key={index + 1} pageNumber={index + 1} loading="" className={styles.page} /> 37 | ))} 38 | </Document> 39 | ); 40 | }); 41 | 42 | export default Pdf; 43 | ``` -------------------------------------------------------------------------------- /xmlui/src/components-core/script-runner/bannedFunctions.ts: -------------------------------------------------------------------------------- ```typescript 1 | /** 2 | * Checks if the specified function object is banned from running. 3 | * @param func Function to check 4 | * @return Information about the banned state, including a helper text 5 | */ 6 | export function isBannedFunction(func: any): BannedFunctionResult { 7 | if (func === undefined) { 8 | return { banned: false }; 9 | } 10 | const bannedInfo = bannedFunctions.find((f) => f.func === func); 11 | return bannedInfo 12 | ? { banned: true, func: bannedInfo.func, help: bannedInfo.help } 13 | : { banned: false }; 14 | } 15 | 16 | /** 17 | * List of global functions we do not allow to call 18 | */ 19 | const bannedFunctions: BannedFunctionInfo[] = [ 20 | { func: globalThis.cancelAnimationFrame }, 21 | { func: globalThis.cancelIdleCallback }, 22 | { func: globalThis.clearInterval }, 23 | { func: globalThis.clearImmediate }, 24 | { func: globalThis.clearTimeout }, 25 | { func: globalThis.eval }, 26 | { func: globalThis.queueMicrotask }, 27 | { func: globalThis.requestAnimationFrame }, 28 | { func: globalThis.requestIdleCallback }, 29 | { func: globalThis.setImmediate }, 30 | { func: globalThis.setInterval }, 31 | { func: globalThis.setTimeout, help: "Use 'delay'" }, 32 | ]; 33 | 34 | type BannedFunctionInfo = { 35 | func?: (...args: any[]) => any; 36 | help?: string; 37 | }; 38 | 39 | type BannedFunctionResult = BannedFunctionInfo & { 40 | banned: boolean; 41 | }; 42 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Avatar/Avatar.md: -------------------------------------------------------------------------------- ```markdown 1 | %-DESC-START 2 | 3 | **Key features:** 4 | - **Automatic fallback**: Shows initials when no image URL is provided or image fails to load 5 | - **Multiple sizes**: From `xs` (extra small) to `lg` (large) to fit different contexts 6 | - **Clickable**: Supports click events for profile actions, modals, or navigation 7 | - **Accessible**: Automatically generates appropriate alt text from the name 8 | 9 | %-DESC-END 10 | 11 | %-PROP-START name 12 | 13 | ```xmlui-pg copy display name="Example: name" 14 | <App> 15 | <Avatar name="John, Doe" /> 16 | </App> 17 | ``` 18 | %-PROP-END 19 | 20 | %-PROP-START size 21 | 22 | ```xmlui-pg copy display name="Example: size" 23 | <App> 24 | <HStack> 25 | <Avatar name="Dorothy Ellen Fuller" /> 26 | <Avatar name="Xavier Schiller" size="xs" /> 27 | <Avatar name="Sebastien Moore" size="sm" /> 28 | <Avatar name="Molly Dough" size="md" /> 29 | <Avatar name="Lynn Gilbert" size="lg" /> 30 | </HStack> 31 | </App> 32 | ``` 33 | 34 | %-PROP-END 35 | 36 | %-PROP-START url 37 | 38 | ```xmlui-pg copy display name="Example: url" 39 | <App> 40 | <Avatar url="https://i.pravatar.cc/100" size="md" /> 41 | </App> 42 | ``` 43 | 44 | %-PROP-END 45 | 46 | %-EVENT-START click 47 | 48 | ```xmlui-pg copy display name="Example: click" 49 | <App> 50 | <HStack verticalAlignment="center"> 51 | <Avatar name="Molly Dough" size="md" onClick="toast('Avatar clicked')" /> 52 | Click the avatar! 53 | </HStack> 54 | </App> 55 | ``` 56 | 57 | %-EVENT-END 58 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/chart-color-schemes.ts: -------------------------------------------------------------------------------- ```typescript 1 | const colorSchemes: any = { 2 | "set3": "set3", 3 | "tableau10": "tableau10", 4 | "brown_blueGreen": "brown_blueGreen", 5 | "purpleRed_green": "purpleRed_green", 6 | "pink_yellowGreen": "pink_yellowGreen", 7 | "purple_orange": "purple_orange", 8 | "red_blue": "red_blue", 9 | "red_grey": "red_grey", 10 | "red_yellow_blue": "red_yellow_blue", 11 | "red_yellow_green": "red_yellow_green", 12 | "spectral": "spectral", 13 | "blues": "blues", 14 | "greens": "greens", 15 | "greys": "greys", 16 | "oranges": "oranges", 17 | "purples": "purples", 18 | "reds": "reds", 19 | "blue_green": "blue_green", 20 | "blue_purple": "blue_purple", 21 | "green_blue": "green_blue", 22 | "orange_red": "orange_red", 23 | "purple_blue_green": "purple_blue_green", 24 | "purple_blue": "purple_blue", 25 | "purple_red": "purple_red", 26 | "red_purple": "red_purple", 27 | "yellow_green_blue": "yellow_green_blue", 28 | "yellow_green": "yellow_green", 29 | "yellow_orange_brown": "yellow_orange_brown", 30 | "yellow_orange_red": "yellow_orange_red", 31 | "nivo": "nivo", 32 | "category10": "category10", 33 | "accent": "accent", 34 | "dark2": "dark2", 35 | "paired": "paired", 36 | "pastel1": "pastel1", 37 | "pastel2": "pastel2", 38 | "set1": "set1", 39 | "set2": "set2" 40 | }; 41 | 42 | export default colorSchemes; 43 | ``` -------------------------------------------------------------------------------- /docs/public/pages/xmlui-charts/LineChart.md: -------------------------------------------------------------------------------- ```markdown 1 | # LineChart [#linechart] 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 line chart component. 5 | 6 | ## Properties 7 | 8 | ### `data` 9 | 10 | The data to be displayed in the line chart.It needs to be an array of objects, where each object represents a data point. 11 | 12 | ### `dataKeys` 13 | 14 | This property specifies the keys in the data objects that should be used for rendering the lines. 15 | 16 | ### `hideTooltip (default: false)` 17 | 18 | Determines whether the tooltip should be hidden.If set to (`true`), no tooltip will be shown when hovering over data points. 19 | 20 | ### `hideX (default: false)` 21 | 22 | Determines whether the X-axis should be hidden. If set to (`true`), the axis will not be displayed. 23 | 24 | ### `nameKey` 25 | 26 | The key in the data objects used for labeling different data series. 27 | 28 | ### `showLegend (default: false)` 29 | 30 | Determines whether the legend should be displayed. 31 | 32 | ### `tickFormatter` 33 | 34 | A function that formats the axis tick labels. It receives a tick value and returns a formatted string. 35 | 36 | ## Events 37 | 38 | This component does not have any events. 39 | 40 | ## Exposed Methods 41 | 42 | This component does not expose any methods. 43 | 44 | ## Styling 45 | 46 | This component does not have any styles. 47 | ``` -------------------------------------------------------------------------------- /docs/public/pages/howto/debug-a-component.md: -------------------------------------------------------------------------------- ```markdown 1 | # Debug a component 2 | 3 | ```xmlui-pg noHeader 4 | ---app 5 | <App> 6 | <Test /> 7 | </App> 8 | ---api 9 | { 10 | "apiUrl": "/api", 11 | "initialize": "$state.user_data = { 12 | id: 42, 13 | name: 'John Doe', 14 | preferences: { theme: 'dark', notifications: true }, 15 | recentItems: ['item1', 'item2', 'item3'] 16 | }", 17 | "operations": { 18 | "get_user_data": { 19 | "url": "/user_data", 20 | "method": "get", 21 | "handler": "console.log('API called:', $state.user_data); return $state.user_data" 22 | } 23 | } 24 | } 25 | ---comp display 26 | <Component name="Test" 27 | var.counter = "{1}" 28 | > 29 | 30 | <DataSource 31 | id="userData" 32 | url="/api/user_data" 33 | /> 34 | 35 | <script> 36 | // can customize here 37 | function debug(msg, data) { 38 | console.log(msg, data) 39 | }; 40 | </script> 41 | 42 | <Text>Method 1: JSON.stringify with preserveLinebreaks</Text> 43 | 44 | <Text preserveLinebreaks="true"> 45 | {JSON.stringify(userData.value, null, 2)} 46 | </Text> 47 | 48 | <Text>Method 2: Console.log in handler</Text> 49 | 50 | <Button 51 | label="Log to console" 52 | onClick="console.log(userData);console.log(userData.value)" 53 | /> 54 | 55 | <Text>Method 3: Use Fragment and custom debug function to watch changes</Text> 56 | 57 | <Fragment when="{debug('counter', counter)}" /> 58 | 59 | <Button 60 | label="Update counter" 61 | onClick="{counter++}" 62 | /> 63 | 64 | </Component> 65 | ``` 66 | ``` -------------------------------------------------------------------------------- /docs/public/pages/howto/group-items-in-list-by-a-property.md: -------------------------------------------------------------------------------- ```markdown 1 | # Group items in List by a property 2 | 3 | ```xmlui-pg noHeader 4 | ---app 5 | <App> 6 | <Test /> 7 | </App> 8 | ---api display 9 | { 10 | "apiUrl": "/api", 11 | "initialize": "$state.people_groupby = [ 12 | { id: 1, name: 'Alice', active: true, group: 'A' }, 13 | { id: 2, name: 'Bob', active: false, group: 'B' }, 14 | { id: 3, name: 'Carol', active: true, group: 'A' }, 15 | { id: 4, name: 'Dave', active: true, group: 'B' } 16 | ]", 17 | "operations": { 18 | "get-people-groupby": { 19 | "url": "/people_groupby", 20 | "method": "get", 21 | "handler": "return { status: 'ok', data: { items: $state.people_groupby } }" 22 | } 23 | } 24 | } 25 | ---comp display 26 | <Component name="Test"> 27 | 28 | <!-- 29 | { 30 | items: 31 | [ 32 | { id: 1, name: 'Alice', active: true, group: 'A' }, 33 | { id: 2, name: 'Bob', active: false, group: 'B' }, 34 | { id: 3, name: 'Carol', active: true, group: 'A' }, 35 | { id: 4, name: 'Dave', active: true, group: 'B' } 36 | ] 37 | } 38 | --> 39 | 40 | <DataSource 41 | id="allPeopleGroupBy" 42 | url="/api/people_groupby" 43 | resultSelector="data.items" 44 | /> 45 | <List data="{allPeopleGroupBy}" groupBy="group"> 46 | <property name="groupHeaderTemplate"> 47 | <Text variant="subtitle">Group {$group.key}</Text> 48 | </property> 49 | <Text>{$item.name}</Text> 50 | </List> 51 | </Component> 52 | ``` 53 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/ProgressBar/ProgressBar.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 | $backgroundColor-ProgressBar: createThemeVar("backgroundColor-ProgressBar"); 11 | $color-indicator-ProgressBar: createThemeVar("color-indicator-ProgressBar"); 12 | $borderRadius-ProgressBar: createThemeVar("borderRadius-ProgressBar"); 13 | $borderRadius-indicator-ProgressBar: createThemeVar("borderRadius-indicator-ProgressBar"); 14 | $thickness-ProgressBar: createThemeVar("thickness-ProgressBar"); 15 | 16 | @layer components { 17 | .wrapper { 18 | width: 100%; 19 | background-color: $backgroundColor-ProgressBar; 20 | border-radius: $borderRadius-ProgressBar; 21 | overflow: hidden; 22 | position: relative; 23 | height: $thickness-ProgressBar; 24 | } 25 | 26 | .bar { 27 | position: absolute; 28 | background-color: $color-indicator-ProgressBar; 29 | border-radius: $borderRadius-indicator-ProgressBar; 30 | left: 0; 31 | top: 0; 32 | bottom: 0; 33 | } 34 | } 35 | 36 | // --- We export the theme variables to add them to the component renderer 37 | :export { 38 | themeVars: t.json-stringify($themeVars); 39 | } 40 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Tabs/TabItemNative.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import type { ForwardedRef } from "react"; 2 | import { forwardRef, useEffect, useId } from "react"; 3 | import { Content } from "@radix-ui/react-tabs"; 4 | 5 | import styles from "../Tabs/Tabs.module.scss"; 6 | 7 | import type { Tab } from "../abstractions"; 8 | import { useTabContext } from "./TabContext"; 9 | 10 | export const TabItemComponent = forwardRef(function TabItemComponent( 11 | { children, label, headerRenderer, style, id, activated, ...rest }: Tab, 12 | forwardedRef: ForwardedRef<HTMLDivElement>, 13 | ) { 14 | const innerId = useId(); 15 | const { register, unRegister, activeTabId } = useTabContext(); 16 | 17 | useEffect(() => { 18 | register({ 19 | label, 20 | headerRenderer, 21 | innerId, 22 | id, // Store the external id (can be undefined) 23 | }); 24 | }, [innerId, id, label, headerRenderer, register]); 25 | 26 | useEffect(() => { 27 | return () => { 28 | unRegister(innerId); 29 | }; 30 | }, [innerId, unRegister]); 31 | 32 | useEffect(() => { 33 | if (activeTabId === innerId && activated) { 34 | activated(); 35 | } 36 | }, [activeTabId, innerId, activated]); 37 | 38 | if (activeTabId !== innerId) return null; 39 | 40 | return ( 41 | <Content 42 | {...rest} 43 | key={innerId} 44 | value={innerId} 45 | className={styles.tabsContent} 46 | ref={forwardedRef} 47 | style={style} 48 | > 49 | {children} 50 | </Content> 51 | ); 52 | }); 53 | ``` -------------------------------------------------------------------------------- /tools/vscode/esbuild.js: -------------------------------------------------------------------------------- ```javascript 1 | const esbuild = require("esbuild"); 2 | 3 | const production = process.argv.includes("--production"); 4 | const watch = process.argv.includes("--watch"); 5 | 6 | async function main() { 7 | const ctx = await esbuild.context({ 8 | entryPoints: ["src/extension.ts", "src/server.ts"], 9 | bundle: true, 10 | format: "cjs", 11 | minify: production, 12 | sourcemap: !production, 13 | sourcesContent: false, 14 | platform: "node", 15 | outdir: "dist", 16 | external: ["vscode"], 17 | logLevel: "warning", 18 | plugins: [ 19 | /* add to the end of plugins array */ 20 | esbuildProblemMatcherPlugin, 21 | ], 22 | }); 23 | if (watch) { 24 | await ctx.watch(); 25 | } else { 26 | await ctx.rebuild(); 27 | await ctx.dispose(); 28 | } 29 | } 30 | 31 | /** 32 | * @type {import('esbuild').Plugin} 33 | */ 34 | const esbuildProblemMatcherPlugin = { 35 | name: "esbuild-problem-matcher", 36 | 37 | setup(build) { 38 | build.onStart(() => { 39 | console.log("[watch] build started"); 40 | }); 41 | build.onEnd((result) => { 42 | result.errors.forEach(({ text, location }) => { 43 | console.error(`✘ [ERROR] ${text}`); 44 | if (location == null) return; 45 | console.error(` ${location.file}:${location.line}:${location.column}:`); 46 | }); 47 | console.log("[watch] build finished"); 48 | }); 49 | }, 50 | }; 51 | 52 | main().catch((e) => { 53 | console.error(e); 54 | process.exit(1); 55 | }); 56 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/FormItem/HelperText.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import type { CSSProperties } from "react"; 2 | import classnames from "classnames"; 3 | 4 | import styles from "./HelperText.module.scss"; 5 | 6 | import type { ValidationStatus } from "../abstractions"; 7 | import { WarningIcon } from "../Icon/WarningIcon"; 8 | import { ErrorIcon } from "../Icon/ErrorIcon"; 9 | 10 | // ===================================================================================================================== 11 | // React HelperText component implementation 12 | 13 | type Props = { 14 | text?: string; 15 | status?: ValidationStatus; 16 | style?: CSSProperties 17 | }; 18 | 19 | export const HelperText = ({ text = "", status, style }: Props) => { 20 | const renderStatusIcon = () => { 21 | if (status === "warning") { 22 | return <WarningIcon color="var(--xmlui-color-warning)" />; 23 | } else if (status === "error") { 24 | return <ErrorIcon color="var(--xmlui-color-error)" />; 25 | } 26 | }; 27 | 28 | return ( 29 | <div 30 | data-validation-status={status} 31 | style={style} 32 | className={classnames(styles.helper, { 33 | [styles.valid]: status === "valid", 34 | [styles.warning]: status === "warning", 35 | [styles.error]: status === "error", 36 | })} 37 | > 38 | {status && <div style={{ flexShrink: 0 }}>{renderStatusIcon()}</div>} 39 | {text && <div className={styles.helperText}>{text}</div>} 40 | </div> 41 | ); 42 | }; 43 | ``` -------------------------------------------------------------------------------- /xmlui/src/components/Redirect/Redirect.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import type { To } from "react-router-dom"; 2 | import { Navigate } from "@remix-run/react"; 3 | 4 | import { createComponentRenderer } from "../../components-core/renderers"; 5 | import { createUrlWithQueryParams } from "../component-utils"; 6 | import { createMetadata } from "../metadata-helpers"; 7 | 8 | const COMP = "Redirect"; 9 | 10 | export const defaultProps = { 11 | to: "", 12 | }; 13 | 14 | export const RedirectMd = createMetadata({ 15 | status: "stable", 16 | description: 17 | "`Redirect` immediately redirects the browser to the URL in its `to` property when " + 18 | "it gets visible (its `when` property gets `true`). It works only within " + 19 | "[App](/components/App), not externally.", 20 | props: { 21 | replace: { 22 | description: `This boolean property indicates whether the redirect should replace the current history entry or create a new one.`, 23 | defaultValue: false, 24 | }, 25 | to: { 26 | description: `This property defines the URL to which this component is about to redirect requests.`, 27 | defaultValue: defaultProps.to, 28 | }, 29 | }, 30 | }); 31 | 32 | export const redirectRenderer = createComponentRenderer( 33 | COMP, 34 | RedirectMd, 35 | ({ node, extractValue }) => { 36 | return <Navigate to={createUrlWithQueryParams(extractValue(node.props.to)) as To} replace={extractValue.asOptionalBoolean(node.props.replace)} />; 37 | }, 38 | ); 39 | ``` -------------------------------------------------------------------------------- /xmlui/src/components-core/rendering/InvalidComponent.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import type React from "react"; 2 | 3 | import styles from "./InvalidComponent.module.scss"; 4 | 5 | import type { ComponentDef } from "../../abstractions/ComponentDefs"; 6 | import { EMPTY_ARRAY } from "../constants"; 7 | 8 | // --- Represents the properties of InvalidComponent 9 | type Props = { 10 | // -- Errors found while validating component prperties 11 | errors?: string[]; 12 | 13 | // -- The definition of the component validated 14 | node: ComponentDef; 15 | 16 | // --- Component children to render with the error message 17 | children?: React.ReactNode; 18 | }; 19 | 20 | /** 21 | * This component displays run time errors found while the rendering engine 22 | * runs. If it finds an issue that hinders regular operation, it renders this 23 | * component instead of the faulty one. 24 | */ 25 | function InvalidComponent({ errors = EMPTY_ARRAY, node, children }: Props) { 26 | return ( 27 | <> 28 | <div className={styles.errorOverlay}> 29 | <div className={styles.title}> 30 | <span> 31 | <b>{node.type}</b> component problems: 32 | </span> 33 | </div> 34 | <ul className={styles.errorItems}> 35 | {errors.map((error: string, i) => ( 36 | <li className={styles.errorItem} key={i}> 37 | {error} 38 | </li> 39 | ))} 40 | </ul> 41 | </div> 42 | {children} 43 | </> 44 | ); 45 | } 46 | 47 | export default InvalidComponent; 48 | ```