This is page 29 of 181. Use http://codebase.md/xmlui-org/xmlui?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .changeset
│ └── config.json
├── .eslintrc.cjs
├── .github
│ ├── build-checklist.png
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows
│ ├── deploy-blog.yml
│ ├── deploy-docs-optimized.yml
│ ├── deploy-docs.yml
│ ├── prepare-versions.yml
│ ├── release-packages.yml
│ ├── run-all-tests.yml
│ └── run-smoke-tests.yml
├── .gitignore
├── .prettierrc.js
├── .vscode
│ ├── launch.json
│ └── settings.json
├── blog
│ ├── .gitignore
│ ├── .gitkeep
│ ├── CHANGELOG.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── layout-changes.md
│ ├── package.json
│ ├── public
│ │ ├── blog
│ │ │ ├── images
│ │ │ │ ├── blog-page-component.png
│ │ │ │ ├── blog-scrabble.png
│ │ │ │ ├── integrated-blog-search.png
│ │ │ │ └── lorem-ipsum.png
│ │ │ ├── lorem-ipsum.md
│ │ │ ├── newest-post.md
│ │ │ ├── older-post.md
│ │ │ └── welcome-to-the-xmlui-blog.md
│ │ ├── mockServiceWorker.js
│ │ ├── resources
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ └── for-download
│ │ │ │ └── xmlui
│ │ │ │ └── xmlui-standalone.umd.js
│ │ │ ├── github.svg
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ ├── rss.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ └── PageNotFound.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── blog-theme.ts
│ └── tsconfig.json
├── CONTRIBUTING.md
├── docs
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── ComponentRefLinks.txt
│ ├── content
│ │ ├── _meta.json
│ │ ├── components
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── APICall.md
│ │ │ ├── App.md
│ │ │ ├── AppHeader.md
│ │ │ ├── AppState.md
│ │ │ ├── AutoComplete.md
│ │ │ ├── Avatar.md
│ │ │ ├── Backdrop.md
│ │ │ ├── Badge.md
│ │ │ ├── BarChart.md
│ │ │ ├── Bookmark.md
│ │ │ ├── Breakout.md
│ │ │ ├── Button.md
│ │ │ ├── Card.md
│ │ │ ├── Carousel.md
│ │ │ ├── ChangeListener.md
│ │ │ ├── Checkbox.md
│ │ │ ├── CHStack.md
│ │ │ ├── ColorPicker.md
│ │ │ ├── Column.md
│ │ │ ├── ContentSeparator.md
│ │ │ ├── CVStack.md
│ │ │ ├── DataSource.md
│ │ │ ├── DateInput.md
│ │ │ ├── DatePicker.md
│ │ │ ├── DonutChart.md
│ │ │ ├── DropdownMenu.md
│ │ │ ├── EmojiSelector.md
│ │ │ ├── ExpandableItem.md
│ │ │ ├── FileInput.md
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FlowLayout.md
│ │ │ ├── Footer.md
│ │ │ ├── Form.md
│ │ │ ├── FormItem.md
│ │ │ ├── FormSection.md
│ │ │ ├── Fragment.md
│ │ │ ├── H1.md
│ │ │ ├── H2.md
│ │ │ ├── H3.md
│ │ │ ├── H4.md
│ │ │ ├── H5.md
│ │ │ ├── H6.md
│ │ │ ├── Heading.md
│ │ │ ├── HSplitter.md
│ │ │ ├── HStack.md
│ │ │ ├── Icon.md
│ │ │ ├── IFrame.md
│ │ │ ├── Image.md
│ │ │ ├── Items.md
│ │ │ ├── LabelList.md
│ │ │ ├── Legend.md
│ │ │ ├── LineChart.md
│ │ │ ├── Link.md
│ │ │ ├── List.md
│ │ │ ├── Logo.md
│ │ │ ├── Markdown.md
│ │ │ ├── MenuItem.md
│ │ │ ├── MenuSeparator.md
│ │ │ ├── ModalDialog.md
│ │ │ ├── NavGroup.md
│ │ │ ├── NavLink.md
│ │ │ ├── NavPanel.md
│ │ │ ├── NoResult.md
│ │ │ ├── NumberBox.md
│ │ │ ├── Option.md
│ │ │ ├── Page.md
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── Pages.md
│ │ │ ├── Pagination.md
│ │ │ ├── PasswordInput.md
│ │ │ ├── PieChart.md
│ │ │ ├── ProgressBar.md
│ │ │ ├── Queue.md
│ │ │ ├── RadioGroup.md
│ │ │ ├── RealTimeAdapter.md
│ │ │ ├── Redirect.md
│ │ │ ├── Select.md
│ │ │ ├── Slider.md
│ │ │ ├── Slot.md
│ │ │ ├── SpaceFiller.md
│ │ │ ├── Spinner.md
│ │ │ ├── Splitter.md
│ │ │ ├── Stack.md
│ │ │ ├── StickyBox.md
│ │ │ ├── SubMenuItem.md
│ │ │ ├── Switch.md
│ │ │ ├── TabItem.md
│ │ │ ├── Table.md
│ │ │ ├── TableOfContents.md
│ │ │ ├── Tabs.md
│ │ │ ├── Text.md
│ │ │ ├── TextArea.md
│ │ │ ├── TextBox.md
│ │ │ ├── Theme.md
│ │ │ ├── TimeInput.md
│ │ │ ├── Timer.md
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneSwitch.md
│ │ │ ├── Tooltip.md
│ │ │ ├── Tree.md
│ │ │ ├── VSplitter.md
│ │ │ ├── VStack.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ ├── xmlui-spreadsheet
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Spreadsheet.md
│ │ │ └── xmlui-website-blocks
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Carousel.md
│ │ │ ├── HelloMd.md
│ │ │ ├── HeroSection.md
│ │ │ └── ScrollToTop.md
│ │ └── extensions
│ │ ├── _meta.json
│ │ ├── xmlui-animations
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Animation.md
│ │ │ ├── FadeAnimation.md
│ │ │ ├── FadeInAnimation.md
│ │ │ ├── FadeOutAnimation.md
│ │ │ ├── ScaleAnimation.md
│ │ │ └── SlideInAnimation.md
│ │ └── xmlui-website-blocks
│ │ ├── _meta.json
│ │ ├── _overview.md
│ │ ├── Carousel.md
│ │ ├── HelloMd.md
│ │ ├── HeroSection.md
│ │ └── ScrollToTop.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── package.json
│ ├── public
│ │ ├── feed.rss
│ │ ├── mockServiceWorker.js
│ │ ├── pages
│ │ │ ├── _meta.json
│ │ │ ├── app-structure.md
│ │ │ ├── build-editor-component.md
│ │ │ ├── build-hello-world-component.md
│ │ │ ├── components-intro.md
│ │ │ ├── context-variables.md
│ │ │ ├── forms.md
│ │ │ ├── globals.md
│ │ │ ├── glossary.md
│ │ │ ├── helper-tags.md
│ │ │ ├── hosted-deployment.md
│ │ │ ├── howto
│ │ │ │ ├── assign-a-complex-json-literal-to-a-component-variable.md
│ │ │ │ ├── chain-a-refetch.md
│ │ │ │ ├── debug-a-component.md
│ │ │ │ ├── delay-a-datasource-until-another-datasource-is-ready.md
│ │ │ │ ├── delegate-a-method.md
│ │ │ │ ├── do-custom-form-validation.md
│ │ │ │ ├── expose-a-method-from-a-component.md
│ │ │ │ ├── filter-and-transform-data-from-an-api.md
│ │ │ │ ├── group-items-in-list-by-a-property.md
│ │ │ │ ├── handle-background-operations.md
│ │ │ │ ├── hide-an-element-until-its-datasource-is-ready.md
│ │ │ │ ├── make-a-set-of-equal-width-cards.md
│ │ │ │ ├── make-a-table-responsive.md
│ │ │ │ ├── make-navpanel-width-responsive.md
│ │ │ │ ├── modify-a-value-reported-in-a-column.md
│ │ │ │ ├── paginate-a-list.md
│ │ │ │ ├── pass-data-to-a-modal-dialog.md
│ │ │ │ ├── react-to-button-click-not-keystrokes.md
│ │ │ │ ├── set-the-initial-value-of-a-select-from-fetched-data.md
│ │ │ │ ├── share-a-modaldialog-across-components.md
│ │ │ │ ├── sync-selections-between-table-and-list-views.md
│ │ │ │ ├── update-ui-optimistically.md
│ │ │ │ ├── use-built-in-form-validation.md
│ │ │ │ └── use-the-same-modaldialog-to-add-or-edit.md
│ │ │ ├── howto.md
│ │ │ ├── intro.md
│ │ │ ├── layout.md
│ │ │ ├── markup.md
│ │ │ ├── mcp.md
│ │ │ ├── modal-dialogs.md
│ │ │ ├── news-and-reviews.md
│ │ │ ├── reactive-intro.md
│ │ │ ├── refactoring.md
│ │ │ ├── routing-and-links.md
│ │ │ ├── samples
│ │ │ │ ├── color-palette.xmlui
│ │ │ │ ├── color-values.xmlui
│ │ │ │ ├── shadow-sizes.xmlui
│ │ │ │ ├── spacing-sizes.xmlui
│ │ │ │ ├── swatch.xmlui
│ │ │ │ ├── theme-gallery-brief.xmlui
│ │ │ │ └── theme-gallery.xmlui
│ │ │ ├── scoping.md
│ │ │ ├── scripting.md
│ │ │ ├── styles-and-themes
│ │ │ │ ├── common-units.md
│ │ │ │ ├── layout-props.md
│ │ │ │ ├── theme-variable-defaults.md
│ │ │ │ ├── theme-variables.md
│ │ │ │ └── themes.md
│ │ │ ├── template-properties.md
│ │ │ ├── test.md
│ │ │ ├── tutorial-01.md
│ │ │ ├── tutorial-02.md
│ │ │ ├── tutorial-03.md
│ │ │ ├── tutorial-04.md
│ │ │ ├── tutorial-05.md
│ │ │ ├── tutorial-06.md
│ │ │ ├── tutorial-07.md
│ │ │ ├── tutorial-08.md
│ │ │ ├── tutorial-09.md
│ │ │ ├── tutorial-10.md
│ │ │ ├── tutorial-11.md
│ │ │ ├── tutorial-12.md
│ │ │ ├── universal-properties.md
│ │ │ ├── user-defined-components.md
│ │ │ ├── vscode.md
│ │ │ ├── working-with-markdown.md
│ │ │ ├── working-with-text.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-charts
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── DonutChart.md
│ │ │ │ ├── LabelList.md
│ │ │ │ ├── Legend.md
│ │ │ │ ├── LineChart.md
│ │ │ │ └── PieChart.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ └── xmlui-spreadsheet
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ └── Spreadsheet.md
│ │ ├── resources
│ │ │ ├── devdocs
│ │ │ │ ├── debug-proxy-object-2.png
│ │ │ │ ├── debug-proxy-object.png
│ │ │ │ ├── table_editor_01.png
│ │ │ │ ├── table_editor_02.png
│ │ │ │ ├── table_editor_03.png
│ │ │ │ ├── table_editor_04.png
│ │ │ │ ├── table_editor_05.png
│ │ │ │ ├── table_editor_06.png
│ │ │ │ ├── table_editor_07.png
│ │ │ │ ├── table_editor_08.png
│ │ │ │ ├── table_editor_09.png
│ │ │ │ ├── table_editor_10.png
│ │ │ │ ├── table_editor_11.png
│ │ │ │ ├── table-editor-01.png
│ │ │ │ ├── table-editor-02.png
│ │ │ │ ├── table-editor-03.png
│ │ │ │ ├── table-editor-04.png
│ │ │ │ ├── table-editor-06.png
│ │ │ │ ├── table-editor-07.png
│ │ │ │ ├── table-editor-08.png
│ │ │ │ ├── table-editor-09.png
│ │ │ │ └── xmlui-rendering-of-tiptap-markdown.png
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ ├── clients.json
│ │ │ │ ├── daily-revenue.json
│ │ │ │ ├── dashboard-stats.json
│ │ │ │ ├── demo.xmlui
│ │ │ │ ├── demo.xmlui.xs
│ │ │ │ ├── downloads
│ │ │ │ │ └── downloads.json
│ │ │ │ ├── for-download
│ │ │ │ │ ├── index-with-api.html
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── mockApi.js
│ │ │ │ │ ├── start-darwin.sh
│ │ │ │ │ ├── start-linux.sh
│ │ │ │ │ ├── start.bat
│ │ │ │ │ └── xmlui
│ │ │ │ │ └── xmlui-standalone.umd.js
│ │ │ │ ├── getting-started
│ │ │ │ │ ├── cl-tutorial-final.zip
│ │ │ │ │ ├── cl-tutorial.zip
│ │ │ │ │ ├── cl-tutorial2.zip
│ │ │ │ │ ├── cl-tutorial3.zip
│ │ │ │ │ ├── cl-tutorial4.zip
│ │ │ │ │ ├── cl-tutorial5.zip
│ │ │ │ │ ├── cl-tutorial6.zip
│ │ │ │ │ ├── getting-started.zip
│ │ │ │ │ ├── hello-xmlui.zip
│ │ │ │ │ ├── xmlui-empty.zip
│ │ │ │ │ └── xmlui-starter.zip
│ │ │ │ ├── howto
│ │ │ │ │ └── component-icons
│ │ │ │ │ └── up-arrow.svg
│ │ │ │ ├── invoices.json
│ │ │ │ ├── monthly-status.json
│ │ │ │ ├── news-and-reviews.json
│ │ │ │ ├── products.json
│ │ │ │ ├── releases.json
│ │ │ │ ├── tutorials
│ │ │ │ │ ├── datasource
│ │ │ │ │ │ └── api.ts
│ │ │ │ │ └── p2do
│ │ │ │ │ ├── api.ts
│ │ │ │ │ └── todo-logo.svg
│ │ │ │ └── xmlui.json
│ │ │ ├── github.svg
│ │ │ ├── images
│ │ │ │ ├── apiaction-tutorial
│ │ │ │ │ ├── add-success.png
│ │ │ │ │ ├── apiaction-param.png
│ │ │ │ │ ├── change-completed.png
│ │ │ │ │ ├── change-in-progress.png
│ │ │ │ │ ├── confirm-delete.png
│ │ │ │ │ ├── data-error.png
│ │ │ │ │ ├── data-progress.png
│ │ │ │ │ ├── data-success.png
│ │ │ │ │ ├── display-1.png
│ │ │ │ │ ├── item-deleted.png
│ │ │ │ │ ├── item-updated.png
│ │ │ │ │ ├── missing-api-key.png
│ │ │ │ │ ├── new-item-added.png
│ │ │ │ │ └── test-message.png
│ │ │ │ ├── chat-api
│ │ │ │ │ └── domain-model.svg
│ │ │ │ ├── components
│ │ │ │ │ ├── image
│ │ │ │ │ │ └── breakfast.jpg
│ │ │ │ │ ├── markdown
│ │ │ │ │ │ └── colors.png
│ │ │ │ │ └── modal
│ │ │ │ │ ├── deep_link_dialog_1.jpg
│ │ │ │ │ └── deep_link_dialog_2.jpg
│ │ │ │ ├── create-apps
│ │ │ │ │ ├── collapsed-vertical.png
│ │ │ │ │ ├── using-forms-warning-dialog.png
│ │ │ │ │ └── using-forms.png
│ │ │ │ ├── datasource-tutorial
│ │ │ │ │ ├── data-with-header.png
│ │ │ │ │ ├── filtered-data.png
│ │ │ │ │ ├── filtered-items.png
│ │ │ │ │ ├── initial-page-items.png
│ │ │ │ │ ├── list-items.png
│ │ │ │ │ ├── next-page-items.png
│ │ │ │ │ ├── no-data.png
│ │ │ │ │ ├── pagination-1.jpg
│ │ │ │ │ ├── pagination-1.png
│ │ │ │ │ ├── polling-1.png
│ │ │ │ │ ├── refetch-data.png
│ │ │ │ │ ├── slow-loading.png
│ │ │ │ │ ├── test-message.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── unconventional-data.png
│ │ │ │ │ └── unfiltered-items.png
│ │ │ │ ├── flower.jpg
│ │ │ │ ├── get-started
│ │ │ │ │ ├── add-new-contact.png
│ │ │ │ │ ├── app-modified.png
│ │ │ │ │ ├── app-start.png
│ │ │ │ │ ├── app-with-boxes.png
│ │ │ │ │ ├── app-with-toast.png
│ │ │ │ │ ├── boilerplate-structure.png
│ │ │ │ │ ├── cl-initial.png
│ │ │ │ │ ├── cl-start.png
│ │ │ │ │ ├── contact-counts.png
│ │ │ │ │ ├── contact-dialog-title.png
│ │ │ │ │ ├── contact-dialog.png
│ │ │ │ │ ├── contact-menus.png
│ │ │ │ │ ├── contact-predicates.png
│ │ │ │ │ ├── context-menu.png
│ │ │ │ │ ├── dashboard-numbers.png
│ │ │ │ │ ├── default-contact-list.png
│ │ │ │ │ ├── delete-contact.png
│ │ │ │ │ ├── delete-task.png
│ │ │ │ │ ├── detailed-template.png
│ │ │ │ │ ├── edit-contact-details.png
│ │ │ │ │ ├── edited-contact-saved.png
│ │ │ │ │ ├── empty-sections.png
│ │ │ │ │ ├── filter-completed.png
│ │ │ │ │ ├── fullwidth-desktop.png
│ │ │ │ │ ├── fullwidth-mobile.png
│ │ │ │ │ ├── initial-table.png
│ │ │ │ │ ├── items-and-badges.png
│ │ │ │ │ ├── loading-message.png
│ │ │ │ │ ├── new-contact-button.png
│ │ │ │ │ ├── new-contact-saved.png
│ │ │ │ │ ├── no-empty-sections.png
│ │ │ │ │ ├── personal-todo-initial.png
│ │ │ │ │ ├── piechart.png
│ │ │ │ │ ├── review-today.png
│ │ │ │ │ ├── rudimentary-dashboard.png
│ │ │ │ │ ├── section-collapsed.png
│ │ │ │ │ ├── sectioned-items.png
│ │ │ │ │ ├── sections-ordered.png
│ │ │ │ │ ├── spacex-list-with-links.png
│ │ │ │ │ ├── spacex-list.png
│ │ │ │ │ ├── start-personal-todo-1.png
│ │ │ │ │ ├── submit-new-contact.png
│ │ │ │ │ ├── submit-new-task.png
│ │ │ │ │ ├── syntax-highlighting.png
│ │ │ │ │ ├── table-with-badge.png
│ │ │ │ │ ├── template-with-card.png
│ │ │ │ │ ├── test-emulated-api.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── todo-logo.png
│ │ │ │ │ └── xmlui-tools.png
│ │ │ │ ├── HelloApp.png
│ │ │ │ ├── HelloApp2.png
│ │ │ │ ├── logos
│ │ │ │ │ ├── xmlui1.svg
│ │ │ │ │ ├── xmlui2.svg
│ │ │ │ │ ├── xmlui3.svg
│ │ │ │ │ ├── xmlui4.svg
│ │ │ │ │ ├── xmlui5.svg
│ │ │ │ │ ├── xmlui6.svg
│ │ │ │ │ └── xmlui7.svg
│ │ │ │ ├── pdf
│ │ │ │ │ └── dummy-pdf.jpg
│ │ │ │ ├── rendering-engine
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ ├── Component.svg
│ │ │ │ │ ├── CompoundComponent.svg
│ │ │ │ │ ├── RootComponent.svg
│ │ │ │ │ └── tree-with-containers.svg
│ │ │ │ ├── reviewers-guide
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ └── incbutton-in-action.png
│ │ │ │ ├── tools
│ │ │ │ │ └── boilerplate-structure.png
│ │ │ │ ├── try.svg
│ │ │ │ ├── tutorial
│ │ │ │ │ ├── app-chat-history.png
│ │ │ │ │ ├── app-content-placeholder.png
│ │ │ │ │ ├── app-header-and-content.png
│ │ │ │ │ ├── app-links-channel-selected.png
│ │ │ │ │ ├── app-links-click.png
│ │ │ │ │ ├── app-navigation.png
│ │ │ │ │ ├── finished-ex01.png
│ │ │ │ │ ├── finished-ex02.png
│ │ │ │ │ ├── hello.png
│ │ │ │ │ ├── splash-screen-advanced.png
│ │ │ │ │ ├── splash-screen-after-click.png
│ │ │ │ │ ├── splash-screen-centered.png
│ │ │ │ │ ├── splash-screen-events.png
│ │ │ │ │ ├── splash-screen-expression.png
│ │ │ │ │ ├── splash-screen-reuse-after.png
│ │ │ │ │ ├── splash-screen-reuse-before.png
│ │ │ │ │ └── splash-screen.png
│ │ │ │ └── tutorial-01.png
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ ├── Boxes.xmlui
│ │ │ ├── Breadcrumb.xmlui
│ │ │ ├── ChangeLog.xmlui
│ │ │ ├── ColorPalette.xmlui
│ │ │ ├── DocumentLinks.xmlui
│ │ │ ├── DocumentPage.xmlui
│ │ │ ├── DocumentPageNoTOC.xmlui
│ │ │ ├── Icons.xmlui
│ │ │ ├── IncButton.xmlui
│ │ │ ├── IncButton2.xmlui
│ │ │ ├── NameValue.xmlui
│ │ │ ├── PageNotFound.xmlui
│ │ │ ├── PaletteItem.xmlui
│ │ │ ├── Palettes.xmlui
│ │ │ ├── SectionHeader.xmlui
│ │ │ ├── TBD.xmlui
│ │ │ ├── Test.xmlui
│ │ │ ├── ThemesIntro.xmlui
│ │ │ ├── ThousandThemes.xmlui
│ │ │ ├── TubeStops.xmlui
│ │ │ ├── TubeStops.xmlui.xs
│ │ │ └── TwoColumnCode.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ ├── docs-theme.ts
│ │ ├── earthtone.ts
│ │ ├── xmlui-gray-on-default.ts
│ │ ├── xmlui-green-on-default.ts
│ │ └── xmlui-orange-on-default.ts
│ └── tsconfig.json
├── LICENSE
├── package-lock.json
├── package.json
├── packages
│ ├── xmlui-animations
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── Animation.tsx
│ │ │ ├── AnimationNative.tsx
│ │ │ ├── FadeAnimation.tsx
│ │ │ ├── FadeInAnimation.tsx
│ │ │ ├── FadeOutAnimation.tsx
│ │ │ ├── index.tsx
│ │ │ ├── ScaleAnimation.tsx
│ │ │ └── SlideInAnimation.tsx
│ │ └── tsconfig.json
│ ├── xmlui-devtools
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── devtools
│ │ │ │ ├── DevTools.tsx
│ │ │ │ ├── DevToolsNative.module.scss
│ │ │ │ ├── DevToolsNative.tsx
│ │ │ │ ├── ModalDialog.module.scss
│ │ │ │ ├── ModalDialog.tsx
│ │ │ │ ├── ModalVisibilityContext.tsx
│ │ │ │ ├── Tooltip.module.scss
│ │ │ │ ├── Tooltip.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── editor
│ │ │ │ └── Editor.tsx
│ │ │ └── index.tsx
│ │ ├── tsconfig.json
│ │ └── vite.config-overrides.ts
│ ├── xmlui-hello-world
│ │ ├── .gitignore
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── HelloWorld.module.scss
│ │ │ ├── HelloWorld.tsx
│ │ │ ├── HelloWorldNative.tsx
│ │ │ └── index.tsx
│ │ └── tsconfig.json
│ ├── xmlui-os-frames
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── index.tsx
│ │ │ ├── IPhoneFrame.module.scss
│ │ │ ├── IPhoneFrame.tsx
│ │ │ ├── MacOSAppFrame.module.scss
│ │ │ ├── MacOSAppFrame.tsx
│ │ │ ├── WindowsAppFrame.module.scss
│ │ │ └── WindowsAppFrame.tsx
│ │ └── tsconfig.json
│ ├── xmlui-pdf
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ ├── components
│ │ │ │ └── Pdf.xmlui
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── index.tsx
│ │ │ ├── LazyPdfNative.tsx
│ │ │ ├── Pdf.module.scss
│ │ │ └── Pdf.tsx
│ │ └── tsconfig.json
│ ├── xmlui-playground
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── hooks
│ │ │ │ ├── usePlayground.ts
│ │ │ │ └── useToast.ts
│ │ │ ├── index.tsx
│ │ │ ├── playground
│ │ │ │ ├── Box.module.scss
│ │ │ │ ├── Box.tsx
│ │ │ │ ├── CodeSelector.tsx
│ │ │ │ ├── ConfirmationDialog.module.scss
│ │ │ │ ├── ConfirmationDialog.tsx
│ │ │ │ ├── Editor.tsx
│ │ │ │ ├── Header.module.scss
│ │ │ │ ├── Header.tsx
│ │ │ │ ├── Playground.tsx
│ │ │ │ ├── PlaygroundContent.module.scss
│ │ │ │ ├── PlaygroundContent.tsx
│ │ │ │ ├── PlaygroundNative.module.scss
│ │ │ │ ├── PlaygroundNative.tsx
│ │ │ │ ├── Preview.module.scss
│ │ │ │ ├── Preview.tsx
│ │ │ │ ├── Select.module.scss
│ │ │ │ ├── StandalonePlayground.tsx
│ │ │ │ ├── StandalonePlaygroundNative.module.scss
│ │ │ │ ├── StandalonePlaygroundNative.tsx
│ │ │ │ ├── ThemeSwitcher.module.scss
│ │ │ │ ├── ThemeSwitcher.tsx
│ │ │ │ ├── ToneSwitcher.tsx
│ │ │ │ ├── Tooltip.module.scss
│ │ │ │ ├── Tooltip.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── providers
│ │ │ │ ├── Toast.module.scss
│ │ │ │ └── ToastProvider.tsx
│ │ │ ├── state
│ │ │ │ └── store.ts
│ │ │ ├── themes
│ │ │ │ └── theme.ts
│ │ │ └── utils
│ │ │ └── helpers.ts
│ │ └── tsconfig.json
│ ├── xmlui-search
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── index.tsx
│ │ │ ├── Search.module.scss
│ │ │ └── Search.tsx
│ │ └── tsconfig.json
│ ├── xmlui-spreadsheet
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── index.tsx
│ │ │ ├── Spreadsheet.tsx
│ │ │ └── SpreadsheetNative.tsx
│ │ └── tsconfig.json
│ └── xmlui-website-blocks
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── demo
│ │ ├── components
│ │ │ ├── HeroBackgroundBreakoutPage.xmlui
│ │ │ ├── HeroBackgroundsPage.xmlui
│ │ │ ├── HeroContentsPage.xmlui
│ │ │ ├── HeroTextAlignPage.xmlui
│ │ │ ├── HeroTextPage.xmlui
│ │ │ └── HeroTonesPage.xmlui
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── default.ts
│ ├── index.html
│ ├── index.ts
│ ├── meta
│ │ └── componentsMetadata.ts
│ ├── package.json
│ ├── public
│ │ └── resources
│ │ ├── building.jpg
│ │ └── xmlui-logo.svg
│ ├── src
│ │ ├── Carousel
│ │ │ ├── Carousel.module.scss
│ │ │ ├── Carousel.tsx
│ │ │ ├── CarouselContext.tsx
│ │ │ └── CarouselNative.tsx
│ │ ├── FancyButton
│ │ │ ├── FancyButton.module.scss
│ │ │ ├── FancyButton.tsx
│ │ │ └── FancyButton.xmlui
│ │ ├── Hello
│ │ │ ├── Hello.tsx
│ │ │ ├── Hello.xmlui
│ │ │ └── Hello.xmlui.xs
│ │ ├── HeroSection
│ │ │ ├── HeroSection.module.scss
│ │ │ ├── HeroSection.tsx
│ │ │ └── HeroSectionNative.tsx
│ │ ├── index.tsx
│ │ ├── ScrollToTop
│ │ │ ├── ScrollToTop.module.scss
│ │ │ ├── ScrollToTop.tsx
│ │ │ └── ScrollToTopNative.tsx
│ │ └── vite-env.d.ts
│ └── tsconfig.json
├── README.md
├── tools
│ ├── codefence
│ │ └── xmlui-code-fence-docs.md
│ ├── create-app
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── create-app.ts
│ │ ├── helpers
│ │ │ ├── copy.ts
│ │ │ ├── get-pkg-manager.ts
│ │ │ ├── git.ts
│ │ │ ├── install.ts
│ │ │ ├── is-folder-empty.ts
│ │ │ ├── is-writeable.ts
│ │ │ ├── make-dir.ts
│ │ │ └── validate-pkg.ts
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── templates
│ │ │ ├── default
│ │ │ │ └── ts
│ │ │ │ ├── gitignore
│ │ │ │ ├── index.html
│ │ │ │ ├── index.ts
│ │ │ │ ├── public
│ │ │ │ │ ├── mockServiceWorker.js
│ │ │ │ │ ├── resources
│ │ │ │ │ │ ├── favicon.ico
│ │ │ │ │ │ └── xmlui-logo.svg
│ │ │ │ │ └── serve.json
│ │ │ │ └── src
│ │ │ │ ├── components
│ │ │ │ │ ├── ApiAware.xmlui
│ │ │ │ │ ├── Home.xmlui
│ │ │ │ │ ├── IncButton.xmlui
│ │ │ │ │ └── PagePanel.xmlui
│ │ │ │ ├── config.ts
│ │ │ │ └── Main.xmlui
│ │ │ ├── index.ts
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ ├── create-xmlui-hello-world
│ │ ├── index.js
│ │ └── package.json
│ └── vscode
│ ├── .gitignore
│ ├── .vscode
│ │ ├── launch.json
│ │ └── tasks.json
│ ├── .vscodeignore
│ ├── build.sh
│ ├── CHANGELOG.md
│ ├── esbuild.js
│ ├── eslint.config.mjs
│ ├── formatter-docs.md
│ ├── generate-test-sample.sh
│ ├── LICENSE.md
│ ├── package-lock.json
│ ├── package.json
│ ├── README.md
│ ├── resources
│ │ ├── xmlui-logo.png
│ │ └── xmlui-markup-syntax-highlighting.png
│ ├── src
│ │ ├── extension.ts
│ │ └── server.ts
│ ├── syntaxes
│ │ └── xmlui.tmLanguage.json
│ ├── test-samples
│ │ └── sample.xmlui
│ ├── tsconfig.json
│ └── tsconfig.tsbuildinfo
├── turbo.json
└── xmlui
├── .gitignore
├── bin
│ ├── bootstrap.js
│ ├── build-lib.ts
│ ├── build.ts
│ ├── index.ts
│ ├── preview.ts
│ ├── start.ts
│ ├── vite-xmlui-plugin.ts
│ └── viteConfig.ts
├── CHANGELOG.md
├── conventions
│ ├── component-qa-checklist.md
│ ├── copilot-conventions.md
│ ├── create-xmlui-components.md
│ ├── mermaid.md
│ ├── testing-conventions.md
│ └── xmlui-in-a-nutshell.md
├── dev-docs
│ ├── accessibility.md
│ ├── build-system.md
│ ├── build-xmlui.md
│ ├── component-behaviors.md
│ ├── components-with-options.md
│ ├── containers.md
│ ├── data-operations.md
│ ├── glossary.md
│ ├── index.md
│ ├── next
│ │ ├── component-dev-guide.md
│ │ ├── configuration-management-enhancement-summary.md
│ │ ├── documentation-scripts-refactoring-complete-summary.md
│ │ ├── documentation-scripts-refactoring-plan.md
│ │ ├── duplicate-pattern-extraction-summary.md
│ │ ├── error-handling-standardization-summary.md
│ │ ├── generating-component-reference.md
│ │ ├── index.md
│ │ ├── logging-consistency-implementation-summary.md
│ │ ├── project-build.md
│ │ ├── project-structure.md
│ │ ├── theme-context.md
│ │ ├── tiptap-design-considerations.md
│ │ ├── working-with-code.md
│ │ ├── xmlui-runtime-architecture
│ │ └── xmlui-wcag-accessibility-report.md
│ ├── react-fundamentals.md
│ ├── release-method.md
│ ├── standalone-app.md
│ ├── ud-components.md
│ └── xmlui-repo.md
├── package.json
├── playwright.config.ts
├── scripts
│ ├── coverage-only.js
│ ├── e2e-test-summary.js
│ ├── generate-docs
│ │ ├── build-downloads-map.mjs
│ │ ├── build-pages-map.mjs
│ │ ├── components-config.json
│ │ ├── configuration-management.mjs
│ │ ├── constants.mjs
│ │ ├── create-theme-files.mjs
│ │ ├── DocsGenerator.mjs
│ │ ├── error-handling.mjs
│ │ ├── extensions-config.json
│ │ ├── folders.mjs
│ │ ├── generate-summary-files.mjs
│ │ ├── get-docs.mjs
│ │ ├── input-handler.mjs
│ │ ├── logger.mjs
│ │ ├── logging-standards.mjs
│ │ ├── MetadataProcessor.mjs
│ │ ├── pattern-utilities.mjs
│ │ └── utils.mjs
│ ├── get-langserver-metadata.mjs
│ ├── inline-links.mjs
│ └── README-e2e-summary.md
├── src
│ ├── abstractions
│ │ ├── _conventions.md
│ │ ├── ActionDefs.ts
│ │ ├── AppContextDefs.ts
│ │ ├── ComponentDefs.ts
│ │ ├── ContainerDefs.ts
│ │ ├── ExtensionDefs.ts
│ │ ├── FunctionDefs.ts
│ │ ├── RendererDefs.ts
│ │ ├── scripting
│ │ │ ├── BlockScope.ts
│ │ │ ├── Compilation.ts
│ │ │ ├── LogicalThread.ts
│ │ │ ├── LoopScope.ts
│ │ │ ├── modules.ts
│ │ │ ├── ScriptParserError.ts
│ │ │ ├── Token.ts
│ │ │ ├── TryScope.ts
│ │ │ └── TryScopeExp.ts
│ │ └── ThemingDefs.ts
│ ├── components
│ │ ├── _conventions.md
│ │ ├── abstractions.ts
│ │ ├── Accordion
│ │ │ ├── Accordion.md
│ │ │ ├── Accordion.module.scss
│ │ │ ├── Accordion.spec.ts
│ │ │ ├── Accordion.tsx
│ │ │ ├── AccordionContext.tsx
│ │ │ ├── AccordionItem.tsx
│ │ │ ├── AccordionItemNative.tsx
│ │ │ └── AccordionNative.tsx
│ │ ├── Animation
│ │ │ └── AnimationNative.tsx
│ │ ├── APICall
│ │ │ ├── APICall.md
│ │ │ ├── APICall.spec.ts
│ │ │ ├── APICall.tsx
│ │ │ └── APICallNative.tsx
│ │ ├── App
│ │ │ ├── App.md
│ │ │ ├── App.module.scss
│ │ │ ├── App.spec.ts
│ │ │ ├── App.tsx
│ │ │ ├── AppLayoutContext.ts
│ │ │ ├── AppNative.tsx
│ │ │ ├── AppStateContext.ts
│ │ │ ├── doc-resources
│ │ │ │ ├── condensed-sticky.xmlui
│ │ │ │ ├── condensed.xmlui
│ │ │ │ ├── horizontal-sticky.xmlui
│ │ │ │ ├── horizontal.xmlui
│ │ │ │ ├── vertical-full-header.xmlui
│ │ │ │ ├── vertical-sticky.xmlui
│ │ │ │ └── vertical.xmlui
│ │ │ ├── IndexerContext.ts
│ │ │ ├── LinkInfoContext.ts
│ │ │ ├── SearchContext.tsx
│ │ │ ├── Sheet.module.scss
│ │ │ └── Sheet.tsx
│ │ ├── AppHeader
│ │ │ ├── AppHeader.md
│ │ │ ├── AppHeader.module.scss
│ │ │ ├── AppHeader.spec.ts
│ │ │ ├── AppHeader.tsx
│ │ │ └── AppHeaderNative.tsx
│ │ ├── AppState
│ │ │ ├── AppState.md
│ │ │ ├── AppState.spec.ts
│ │ │ ├── AppState.tsx
│ │ │ └── AppStateNative.tsx
│ │ ├── AutoComplete
│ │ │ ├── AutoComplete.md
│ │ │ ├── AutoComplete.module.scss
│ │ │ ├── AutoComplete.spec.ts
│ │ │ ├── AutoComplete.tsx
│ │ │ ├── AutoCompleteContext.tsx
│ │ │ └── AutoCompleteNative.tsx
│ │ ├── Avatar
│ │ │ ├── Avatar.md
│ │ │ ├── Avatar.module.scss
│ │ │ ├── Avatar.spec.ts
│ │ │ ├── Avatar.tsx
│ │ │ └── AvatarNative.tsx
│ │ ├── Backdrop
│ │ │ ├── Backdrop.md
│ │ │ ├── Backdrop.module.scss
│ │ │ ├── Backdrop.spec.ts
│ │ │ ├── Backdrop.tsx
│ │ │ └── BackdropNative.tsx
│ │ ├── Badge
│ │ │ ├── Badge.md
│ │ │ ├── Badge.module.scss
│ │ │ ├── Badge.spec.ts
│ │ │ ├── Badge.tsx
│ │ │ └── BadgeNative.tsx
│ │ ├── Bookmark
│ │ │ ├── Bookmark.md
│ │ │ ├── Bookmark.module.scss
│ │ │ ├── Bookmark.spec.ts
│ │ │ ├── Bookmark.tsx
│ │ │ └── BookmarkNative.tsx
│ │ ├── Breakout
│ │ │ ├── Breakout.module.scss
│ │ │ ├── Breakout.spec.ts
│ │ │ ├── Breakout.tsx
│ │ │ └── BreakoutNative.tsx
│ │ ├── Button
│ │ │ ├── Button-style.spec.ts
│ │ │ ├── Button.md
│ │ │ ├── Button.module.scss
│ │ │ ├── Button.spec.ts
│ │ │ ├── Button.tsx
│ │ │ └── ButtonNative.tsx
│ │ ├── Card
│ │ │ ├── Card.md
│ │ │ ├── Card.module.scss
│ │ │ ├── Card.spec.ts
│ │ │ ├── Card.tsx
│ │ │ └── CardNative.tsx
│ │ ├── Carousel
│ │ │ ├── Carousel.md
│ │ │ ├── Carousel.module.scss
│ │ │ ├── Carousel.spec.ts
│ │ │ ├── Carousel.tsx
│ │ │ ├── CarouselContext.tsx
│ │ │ ├── CarouselItem.tsx
│ │ │ ├── CarouselItemNative.tsx
│ │ │ └── CarouselNative.tsx
│ │ ├── ChangeListener
│ │ │ ├── ChangeListener.md
│ │ │ ├── ChangeListener.spec.ts
│ │ │ ├── ChangeListener.tsx
│ │ │ └── ChangeListenerNative.tsx
│ │ ├── chart-color-schemes.ts
│ │ ├── Charts
│ │ │ ├── AreaChart
│ │ │ │ ├── AreaChart.md
│ │ │ │ ├── AreaChart.spec.ts
│ │ │ │ ├── AreaChart.tsx
│ │ │ │ └── AreaChartNative.tsx
│ │ │ ├── BarChart
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── BarChart.module.scss
│ │ │ │ ├── BarChart.spec.ts
│ │ │ │ ├── BarChart.tsx
│ │ │ │ └── BarChartNative.tsx
│ │ │ ├── DonutChart
│ │ │ │ ├── DonutChart.spec.ts
│ │ │ │ └── DonutChart.tsx
│ │ │ ├── LabelList
│ │ │ │ ├── LabelList.spec.ts
│ │ │ │ ├── LabelList.tsx
│ │ │ │ ├── LabelListNative.module.scss
│ │ │ │ └── LabelListNative.tsx
│ │ │ ├── Legend
│ │ │ │ ├── Legend.spec.ts
│ │ │ │ ├── Legend.tsx
│ │ │ │ └── LegendNative.tsx
│ │ │ ├── LineChart
│ │ │ │ ├── LineChart.md
│ │ │ │ ├── LineChart.module.scss
│ │ │ │ ├── LineChart.spec.ts
│ │ │ │ ├── LineChart.tsx
│ │ │ │ └── LineChartNative.tsx
│ │ │ ├── PieChart
│ │ │ │ ├── PieChart.md
│ │ │ │ ├── PieChart.spec.ts
│ │ │ │ ├── PieChart.tsx
│ │ │ │ ├── PieChartNative.module.scss
│ │ │ │ └── PieChartNative.tsx
│ │ │ ├── RadarChart
│ │ │ │ ├── RadarChart.md
│ │ │ │ ├── RadarChart.spec.ts
│ │ │ │ ├── RadarChart.tsx
│ │ │ │ └── RadarChartNative.tsx
│ │ │ ├── Tooltip
│ │ │ │ ├── TooltipContent.module.scss
│ │ │ │ ├── TooltipContent.spec.ts
│ │ │ │ └── TooltipContent.tsx
│ │ │ └── utils
│ │ │ ├── abstractions.ts
│ │ │ └── ChartProvider.tsx
│ │ ├── Checkbox
│ │ │ ├── Checkbox.md
│ │ │ ├── Checkbox.spec.ts
│ │ │ └── Checkbox.tsx
│ │ ├── CodeBlock
│ │ │ ├── CodeBlock.module.scss
│ │ │ ├── CodeBlock.spec.ts
│ │ │ ├── CodeBlock.tsx
│ │ │ ├── CodeBlockNative.tsx
│ │ │ └── highlight-code.ts
│ │ ├── collectedComponentMetadata.ts
│ │ ├── ColorPicker
│ │ │ ├── ColorPicker.md
│ │ │ ├── ColorPicker.module.scss
│ │ │ ├── ColorPicker.spec.ts
│ │ │ ├── ColorPicker.tsx
│ │ │ └── ColorPickerNative.tsx
│ │ ├── Column
│ │ │ ├── Column.md
│ │ │ ├── Column.tsx
│ │ │ ├── ColumnNative.tsx
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ └── TableContext.tsx
│ │ ├── component-utils.ts
│ │ ├── ComponentProvider.tsx
│ │ ├── ComponentRegistryContext.tsx
│ │ ├── container-helpers.tsx
│ │ ├── ContentSeparator
│ │ │ ├── ContentSeparator.md
│ │ │ ├── ContentSeparator.module.scss
│ │ │ ├── ContentSeparator.spec.ts
│ │ │ ├── ContentSeparator.tsx
│ │ │ └── ContentSeparatorNative.tsx
│ │ ├── DataSource
│ │ │ ├── DataSource.md
│ │ │ └── DataSource.tsx
│ │ ├── DateInput
│ │ │ ├── DateInput.md
│ │ │ ├── DateInput.module.scss
│ │ │ ├── DateInput.spec.ts
│ │ │ ├── DateInput.tsx
│ │ │ └── DateInputNative.tsx
│ │ ├── DatePicker
│ │ │ ├── DatePicker.md
│ │ │ ├── DatePicker.module.scss
│ │ │ ├── DatePicker.spec.ts
│ │ │ ├── DatePicker.tsx
│ │ │ └── DatePickerNative.tsx
│ │ ├── DropdownMenu
│ │ │ ├── DropdownMenu.md
│ │ │ ├── DropdownMenu.module.scss
│ │ │ ├── DropdownMenu.spec.ts
│ │ │ ├── DropdownMenu.tsx
│ │ │ ├── DropdownMenuNative.tsx
│ │ │ ├── MenuItem.md
│ │ │ └── SubMenuItem.md
│ │ ├── EmojiSelector
│ │ │ ├── EmojiSelector.md
│ │ │ ├── EmojiSelector.spec.ts
│ │ │ ├── EmojiSelector.tsx
│ │ │ └── EmojiSelectorNative.tsx
│ │ ├── ExpandableItem
│ │ │ ├── ExpandableItem.module.scss
│ │ │ ├── ExpandableItem.spec.ts
│ │ │ ├── ExpandableItem.tsx
│ │ │ └── ExpandableItemNative.tsx
│ │ ├── FileInput
│ │ │ ├── FileInput.md
│ │ │ ├── FileInput.module.scss
│ │ │ ├── FileInput.spec.ts
│ │ │ ├── FileInput.tsx
│ │ │ └── FileInputNative.tsx
│ │ ├── FileUploadDropZone
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FileUploadDropZone.module.scss
│ │ │ ├── FileUploadDropZone.spec.ts
│ │ │ ├── FileUploadDropZone.tsx
│ │ │ └── FileUploadDropZoneNative.tsx
│ │ ├── FlowLayout
│ │ │ ├── FlowLayout.md
│ │ │ ├── FlowLayout.module.scss
│ │ │ ├── FlowLayout.spec.ts
│ │ │ ├── FlowLayout.spec.ts-snapshots
│ │ │ │ └── Edge-cases-boxShadow-is-not-clipped-1-non-smoke-darwin.png
│ │ │ ├── FlowLayout.tsx
│ │ │ └── FlowLayoutNative.tsx
│ │ ├── Footer
│ │ │ ├── Footer.md
│ │ │ ├── Footer.module.scss
│ │ │ ├── Footer.spec.ts
│ │ │ ├── Footer.tsx
│ │ │ └── FooterNative.tsx
│ │ ├── Form
│ │ │ ├── Form.md
│ │ │ ├── Form.module.scss
│ │ │ ├── Form.spec.ts
│ │ │ ├── Form.tsx
│ │ │ ├── formActions.ts
│ │ │ ├── FormContext.ts
│ │ │ └── FormNative.tsx
│ │ ├── FormItem
│ │ │ ├── FormItem.md
│ │ │ ├── FormItem.module.scss
│ │ │ ├── FormItem.spec.ts
│ │ │ ├── FormItem.tsx
│ │ │ ├── FormItemNative.tsx
│ │ │ ├── HelperText.module.scss
│ │ │ ├── HelperText.tsx
│ │ │ ├── ItemWithLabel.tsx
│ │ │ └── Validations.ts
│ │ ├── FormSection
│ │ │ ├── FormSection.md
│ │ │ ├── FormSection.ts
│ │ │ └── FormSection.xmlui
│ │ ├── Fragment
│ │ │ ├── Fragment.spec.ts
│ │ │ └── Fragment.tsx
│ │ ├── Heading
│ │ │ ├── abstractions.ts
│ │ │ ├── H1.md
│ │ │ ├── H1.spec.ts
│ │ │ ├── H2.md
│ │ │ ├── H2.spec.ts
│ │ │ ├── H3.md
│ │ │ ├── H3.spec.ts
│ │ │ ├── H4.md
│ │ │ ├── H4.spec.ts
│ │ │ ├── H5.md
│ │ │ ├── H5.spec.ts
│ │ │ ├── H6.md
│ │ │ ├── H6.spec.ts
│ │ │ ├── Heading.md
│ │ │ ├── Heading.module.scss
│ │ │ ├── Heading.spec.ts
│ │ │ ├── Heading.tsx
│ │ │ └── HeadingNative.tsx
│ │ ├── HoverCard
│ │ │ ├── HoverCard.tsx
│ │ │ └── HovercardNative.tsx
│ │ ├── HtmlTags
│ │ │ ├── HtmlTags.module.scss
│ │ │ ├── HtmlTags.spec.ts
│ │ │ └── HtmlTags.tsx
│ │ ├── Icon
│ │ │ ├── AdmonitionDanger.tsx
│ │ │ ├── AdmonitionInfo.tsx
│ │ │ ├── AdmonitionNote.tsx
│ │ │ ├── AdmonitionTip.tsx
│ │ │ ├── AdmonitionWarning.tsx
│ │ │ ├── ApiIcon.tsx
│ │ │ ├── ArrowDropDown.module.scss
│ │ │ ├── ArrowDropDown.tsx
│ │ │ ├── ArrowDropUp.module.scss
│ │ │ ├── ArrowDropUp.tsx
│ │ │ ├── ArrowLeft.module.scss
│ │ │ ├── ArrowLeft.tsx
│ │ │ ├── ArrowRight.module.scss
│ │ │ ├── ArrowRight.tsx
│ │ │ ├── Attach.tsx
│ │ │ ├── Binding.module.scss
│ │ │ ├── Binding.tsx
│ │ │ ├── BoardIcon.tsx
│ │ │ ├── BoxIcon.tsx
│ │ │ ├── CheckIcon.tsx
│ │ │ ├── ChevronDownIcon.tsx
│ │ │ ├── ChevronLeft.tsx
│ │ │ ├── ChevronRight.tsx
│ │ │ ├── ChevronUpIcon.tsx
│ │ │ ├── CodeFileIcon.tsx
│ │ │ ├── CodeSandbox.tsx
│ │ │ ├── CompactListIcon.tsx
│ │ │ ├── ContentCopyIcon.tsx
│ │ │ ├── DarkToLightIcon.tsx
│ │ │ ├── DatabaseIcon.module.scss
│ │ │ ├── DatabaseIcon.tsx
│ │ │ ├── DocFileIcon.tsx
│ │ │ ├── DocIcon.tsx
│ │ │ ├── DotMenuHorizontalIcon.tsx
│ │ │ ├── DotMenuIcon.tsx
│ │ │ ├── EmailIcon.tsx
│ │ │ ├── EmptyFolderIcon.tsx
│ │ │ ├── ErrorIcon.tsx
│ │ │ ├── ExpressionIcon.tsx
│ │ │ ├── FillPlusCricleIcon.tsx
│ │ │ ├── FilterIcon.tsx
│ │ │ ├── FolderIcon.tsx
│ │ │ ├── GlobeIcon.tsx
│ │ │ ├── HomeIcon.tsx
│ │ │ ├── HyperLinkIcon.tsx
│ │ │ ├── Icon.md
│ │ │ ├── Icon.module.scss
│ │ │ ├── Icon.spec.ts
│ │ │ ├── Icon.tsx
│ │ │ ├── IconNative.tsx
│ │ │ ├── ImageFileIcon.tsx
│ │ │ ├── Inspect.tsx
│ │ │ ├── LightToDark.tsx
│ │ │ ├── LinkIcon.tsx
│ │ │ ├── ListIcon.tsx
│ │ │ ├── LooseListIcon.tsx
│ │ │ ├── MoonIcon.tsx
│ │ │ ├── MoreOptionsIcon.tsx
│ │ │ ├── NoSortIcon.tsx
│ │ │ ├── PDFIcon.tsx
│ │ │ ├── PenIcon.tsx
│ │ │ ├── PhoneIcon.tsx
│ │ │ ├── PhotoIcon.tsx
│ │ │ ├── PlusIcon.tsx
│ │ │ ├── SearchIcon.tsx
│ │ │ ├── ShareIcon.tsx
│ │ │ ├── SortAscendingIcon.tsx
│ │ │ ├── SortDescendingIcon.tsx
│ │ │ ├── StarsIcon.tsx
│ │ │ ├── SunIcon.tsx
│ │ │ ├── svg
│ │ │ │ ├── admonition_danger.svg
│ │ │ │ ├── admonition_info.svg
│ │ │ │ ├── admonition_note.svg
│ │ │ │ ├── admonition_tip.svg
│ │ │ │ ├── admonition_warning.svg
│ │ │ │ ├── api.svg
│ │ │ │ ├── arrow-dropdown.svg
│ │ │ │ ├── arrow-left.svg
│ │ │ │ ├── arrow-right.svg
│ │ │ │ ├── arrow-up.svg
│ │ │ │ ├── attach.svg
│ │ │ │ ├── binding.svg
│ │ │ │ ├── box.svg
│ │ │ │ ├── bulb.svg
│ │ │ │ ├── code-file.svg
│ │ │ │ ├── code-sandbox.svg
│ │ │ │ ├── dark_to_light.svg
│ │ │ │ ├── database.svg
│ │ │ │ ├── doc.svg
│ │ │ │ ├── empty-folder.svg
│ │ │ │ ├── expression.svg
│ │ │ │ ├── eye-closed.svg
│ │ │ │ ├── eye-dark.svg
│ │ │ │ ├── eye.svg
│ │ │ │ ├── file-text.svg
│ │ │ │ ├── filter.svg
│ │ │ │ ├── folder.svg
│ │ │ │ ├── img.svg
│ │ │ │ ├── inspect.svg
│ │ │ │ ├── light_to_dark.svg
│ │ │ │ ├── moon.svg
│ │ │ │ ├── pdf.svg
│ │ │ │ ├── photo.svg
│ │ │ │ ├── share.svg
│ │ │ │ ├── stars.svg
│ │ │ │ ├── sun.svg
│ │ │ │ ├── trending-down.svg
│ │ │ │ ├── trending-level.svg
│ │ │ │ ├── trending-up.svg
│ │ │ │ ├── txt.svg
│ │ │ │ ├── unknown-file.svg
│ │ │ │ ├── unlink.svg
│ │ │ │ └── xls.svg
│ │ │ ├── TableDeleteColumnIcon.tsx
│ │ │ ├── TableDeleteRowIcon.tsx
│ │ │ ├── TableInsertColumnIcon.tsx
│ │ │ ├── TableInsertRowIcon.tsx
│ │ │ ├── TrashIcon.tsx
│ │ │ ├── TrendingDownIcon.tsx
│ │ │ ├── TrendingLevelIcon.tsx
│ │ │ ├── TrendingUpIcon.tsx
│ │ │ ├── TxtIcon.tsx
│ │ │ ├── UnknownFileIcon.tsx
│ │ │ ├── UnlinkIcon.tsx
│ │ │ ├── UserIcon.tsx
│ │ │ ├── WarningIcon.tsx
│ │ │ └── XlsIcon.tsx
│ │ ├── IconProvider.tsx
│ │ ├── IconRegistryContext.tsx
│ │ ├── IFrame
│ │ │ ├── IFrame.md
│ │ │ ├── IFrame.module.scss
│ │ │ ├── IFrame.spec.ts
│ │ │ ├── IFrame.tsx
│ │ │ └── IFrameNative.tsx
│ │ ├── Image
│ │ │ ├── Image.md
│ │ │ ├── Image.module.scss
│ │ │ ├── Image.spec.ts
│ │ │ ├── Image.tsx
│ │ │ └── ImageNative.tsx
│ │ ├── Input
│ │ │ ├── index.ts
│ │ │ ├── InputAdornment.module.scss
│ │ │ ├── InputAdornment.tsx
│ │ │ ├── InputDivider.module.scss
│ │ │ ├── InputDivider.tsx
│ │ │ ├── InputLabel.module.scss
│ │ │ ├── InputLabel.tsx
│ │ │ ├── PartialInput.module.scss
│ │ │ └── PartialInput.tsx
│ │ ├── InspectButton
│ │ │ ├── InspectButton.module.scss
│ │ │ └── InspectButton.tsx
│ │ ├── Items
│ │ │ ├── Items.md
│ │ │ ├── Items.spec.ts
│ │ │ ├── Items.tsx
│ │ │ └── ItemsNative.tsx
│ │ ├── Link
│ │ │ ├── Link.md
│ │ │ ├── Link.module.scss
│ │ │ ├── Link.spec.ts
│ │ │ ├── Link.tsx
│ │ │ └── LinkNative.tsx
│ │ ├── List
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── List.md
│ │ │ ├── List.module.scss
│ │ │ ├── List.spec.ts
│ │ │ ├── List.tsx
│ │ │ └── ListNative.tsx
│ │ ├── Logo
│ │ │ ├── doc-resources
│ │ │ │ └── xmlui-logo.svg
│ │ │ ├── Logo.md
│ │ │ ├── Logo.tsx
│ │ │ └── LogoNative.tsx
│ │ ├── Markdown
│ │ │ ├── CodeText.module.scss
│ │ │ ├── CodeText.tsx
│ │ │ ├── Markdown.md
│ │ │ ├── Markdown.module.scss
│ │ │ ├── Markdown.spec.ts
│ │ │ ├── Markdown.tsx
│ │ │ ├── MarkdownNative.tsx
│ │ │ ├── parse-binding-expr.ts
│ │ │ └── utils.ts
│ │ ├── metadata-helpers.ts
│ │ ├── ModalDialog
│ │ │ ├── ConfirmationModalContextProvider.tsx
│ │ │ ├── Dialog.module.scss
│ │ │ ├── Dialog.tsx
│ │ │ ├── ModalDialog.md
│ │ │ ├── ModalDialog.module.scss
│ │ │ ├── ModalDialog.spec.ts
│ │ │ ├── ModalDialog.tsx
│ │ │ ├── ModalDialogNative.tsx
│ │ │ └── ModalVisibilityContext.tsx
│ │ ├── NavGroup
│ │ │ ├── NavGroup.md
│ │ │ ├── NavGroup.module.scss
│ │ │ ├── NavGroup.spec.ts
│ │ │ ├── NavGroup.tsx
│ │ │ ├── NavGroupContext.ts
│ │ │ └── NavGroupNative.tsx
│ │ ├── NavLink
│ │ │ ├── NavLink.md
│ │ │ ├── NavLink.module.scss
│ │ │ ├── NavLink.spec.ts
│ │ │ ├── NavLink.tsx
│ │ │ └── NavLinkNative.tsx
│ │ ├── NavPanel
│ │ │ ├── NavPanel.md
│ │ │ ├── NavPanel.module.scss
│ │ │ ├── NavPanel.spec.ts
│ │ │ ├── NavPanel.tsx
│ │ │ └── NavPanelNative.tsx
│ │ ├── NestedApp
│ │ │ ├── AppWithCodeView.module.scss
│ │ │ ├── AppWithCodeView.tsx
│ │ │ ├── AppWithCodeViewNative.tsx
│ │ │ ├── defaultProps.tsx
│ │ │ ├── logo.svg
│ │ │ ├── NestedApp.module.scss
│ │ │ ├── NestedApp.tsx
│ │ │ ├── NestedAppNative.tsx
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.tsx
│ │ │ └── utils.ts
│ │ ├── NoResult
│ │ │ ├── NoResult.md
│ │ │ ├── NoResult.module.scss
│ │ │ ├── NoResult.spec.ts
│ │ │ ├── NoResult.tsx
│ │ │ └── NoResultNative.tsx
│ │ ├── NumberBox
│ │ │ ├── numberbox-abstractions.ts
│ │ │ ├── NumberBox.md
│ │ │ ├── NumberBox.module.scss
│ │ │ ├── NumberBox.spec.ts
│ │ │ ├── NumberBox.tsx
│ │ │ └── NumberBoxNative.tsx
│ │ ├── Option
│ │ │ ├── Option.md
│ │ │ ├── Option.spec.ts
│ │ │ ├── Option.tsx
│ │ │ ├── OptionNative.tsx
│ │ │ └── OptionTypeProvider.tsx
│ │ ├── PageMetaTitle
│ │ │ ├── PageMetaTilteNative.tsx
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── PageMetaTitle.spec.ts
│ │ │ └── PageMetaTitle.tsx
│ │ ├── Pages
│ │ │ ├── Page.md
│ │ │ ├── Pages.md
│ │ │ ├── Pages.module.scss
│ │ │ ├── Pages.tsx
│ │ │ └── PagesNative.tsx
│ │ ├── Pagination
│ │ │ ├── Pagination.md
│ │ │ ├── Pagination.module.scss
│ │ │ ├── Pagination.spec.ts
│ │ │ ├── Pagination.tsx
│ │ │ └── PaginationNative.tsx
│ │ ├── PositionedContainer
│ │ │ ├── PositionedContainer.module.scss
│ │ │ ├── PositionedContainer.tsx
│ │ │ └── PositionedContainerNative.tsx
│ │ ├── ProfileMenu
│ │ │ ├── ProfileMenu.module.scss
│ │ │ └── ProfileMenu.tsx
│ │ ├── ProgressBar
│ │ │ ├── ProgressBar.md
│ │ │ ├── ProgressBar.module.scss
│ │ │ ├── ProgressBar.spec.ts
│ │ │ ├── ProgressBar.tsx
│ │ │ └── ProgressBarNative.tsx
│ │ ├── Queue
│ │ │ ├── Queue.md
│ │ │ ├── Queue.spec.ts
│ │ │ ├── Queue.tsx
│ │ │ ├── queueActions.ts
│ │ │ └── QueueNative.tsx
│ │ ├── RadioGroup
│ │ │ ├── RadioGroup.md
│ │ │ ├── RadioGroup.module.scss
│ │ │ ├── RadioGroup.spec.ts
│ │ │ ├── RadioGroup.tsx
│ │ │ ├── RadioGroupNative.tsx
│ │ │ ├── RadioItem.tsx
│ │ │ └── RadioItemNative.tsx
│ │ ├── RealTimeAdapter
│ │ │ ├── RealTimeAdapter.tsx
│ │ │ └── RealTimeAdapterNative.tsx
│ │ ├── Redirect
│ │ │ ├── Redirect.md
│ │ │ ├── Redirect.spec.ts
│ │ │ └── Redirect.tsx
│ │ ├── ResponsiveBar
│ │ │ ├── README.md
│ │ │ ├── ResponsiveBar.md
│ │ │ ├── ResponsiveBar.module.scss
│ │ │ ├── ResponsiveBar.spec.ts
│ │ │ ├── ResponsiveBar.tsx
│ │ │ └── ResponsiveBarNative.tsx
│ │ ├── Select
│ │ │ ├── HiddenOption.tsx
│ │ │ ├── OptionContext.ts
│ │ │ ├── Select.md
│ │ │ ├── Select.module.scss
│ │ │ ├── Select.spec.ts
│ │ │ ├── Select.tsx
│ │ │ ├── SelectContext.tsx
│ │ │ └── SelectNative.tsx
│ │ ├── SelectionStore
│ │ │ ├── SelectionStore.md
│ │ │ ├── SelectionStore.tsx
│ │ │ └── SelectionStoreNative.tsx
│ │ ├── Slider
│ │ │ ├── Slider.md
│ │ │ ├── Slider.module.scss
│ │ │ ├── Slider.spec.ts
│ │ │ ├── Slider.tsx
│ │ │ └── SliderNative.tsx
│ │ ├── Slot
│ │ │ ├── Slot.md
│ │ │ ├── Slot.spec.ts
│ │ │ └── Slot.ts
│ │ ├── SlotItem.tsx
│ │ ├── SpaceFiller
│ │ │ ├── SpaceFiller.md
│ │ │ ├── SpaceFiller.module.scss
│ │ │ ├── SpaceFiller.spec.ts
│ │ │ ├── SpaceFiller.tsx
│ │ │ └── SpaceFillerNative.tsx
│ │ ├── Spinner
│ │ │ ├── Spinner.md
│ │ │ ├── Spinner.module.scss
│ │ │ ├── Spinner.spec.ts
│ │ │ ├── Spinner.tsx
│ │ │ └── SpinnerNative.tsx
│ │ ├── Splitter
│ │ │ ├── HSplitter.md
│ │ │ ├── HSplitter.spec.ts
│ │ │ ├── Splitter.md
│ │ │ ├── Splitter.module.scss
│ │ │ ├── Splitter.spec.ts
│ │ │ ├── Splitter.tsx
│ │ │ ├── SplitterNative.tsx
│ │ │ ├── utils.ts
│ │ │ ├── VSplitter.md
│ │ │ └── VSplitter.spec.ts
│ │ ├── Stack
│ │ │ ├── CHStack.md
│ │ │ ├── CHStack.spec.ts
│ │ │ ├── CVStack.md
│ │ │ ├── CVStack.spec.ts
│ │ │ ├── HStack.md
│ │ │ ├── HStack.spec.ts
│ │ │ ├── Stack.md
│ │ │ ├── Stack.module.scss
│ │ │ ├── Stack.spec.ts
│ │ │ ├── Stack.tsx
│ │ │ ├── StackNative.tsx
│ │ │ ├── VStack.md
│ │ │ └── VStack.spec.ts
│ │ ├── StickyBox
│ │ │ ├── StickyBox.md
│ │ │ ├── StickyBox.module.scss
│ │ │ ├── StickyBox.tsx
│ │ │ └── StickyBoxNative.tsx
│ │ ├── Switch
│ │ │ ├── Switch.md
│ │ │ ├── Switch.spec.ts
│ │ │ └── Switch.tsx
│ │ ├── Table
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── react-table-config.d.ts
│ │ │ ├── Table.md
│ │ │ ├── Table.module.scss
│ │ │ ├── Table.spec.ts
│ │ │ ├── Table.tsx
│ │ │ ├── TableNative.tsx
│ │ │ └── useRowSelection.tsx
│ │ ├── TableOfContents
│ │ │ ├── TableOfContents.module.scss
│ │ │ ├── TableOfContents.spec.ts
│ │ │ ├── TableOfContents.tsx
│ │ │ └── TableOfContentsNative.tsx
│ │ ├── Tabs
│ │ │ ├── TabContext.tsx
│ │ │ ├── TabItem.md
│ │ │ ├── TabItem.tsx
│ │ │ ├── TabItemNative.tsx
│ │ │ ├── Tabs.md
│ │ │ ├── Tabs.module.scss
│ │ │ ├── Tabs.spec.ts
│ │ │ ├── Tabs.tsx
│ │ │ └── TabsNative.tsx
│ │ ├── Text
│ │ │ ├── Text.md
│ │ │ ├── Text.module.scss
│ │ │ ├── Text.spec.ts
│ │ │ ├── Text.tsx
│ │ │ └── TextNative.tsx
│ │ ├── TextArea
│ │ │ ├── TextArea.md
│ │ │ ├── TextArea.module.scss
│ │ │ ├── TextArea.spec.ts
│ │ │ ├── TextArea.tsx
│ │ │ ├── TextAreaNative.tsx
│ │ │ ├── TextAreaResizable.tsx
│ │ │ └── useComposedRef.ts
│ │ ├── TextBox
│ │ │ ├── TextBox.md
│ │ │ ├── TextBox.module.scss
│ │ │ ├── TextBox.spec.ts
│ │ │ ├── TextBox.tsx
│ │ │ └── TextBoxNative.tsx
│ │ ├── Theme
│ │ │ ├── NotificationToast.tsx
│ │ │ ├── Theme.md
│ │ │ ├── Theme.module.scss
│ │ │ ├── Theme.spec.ts
│ │ │ ├── Theme.tsx
│ │ │ └── ThemeNative.tsx
│ │ ├── TimeInput
│ │ │ ├── TimeInput.md
│ │ │ ├── TimeInput.module.scss
│ │ │ ├── TimeInput.spec.ts
│ │ │ ├── TimeInput.tsx
│ │ │ ├── TimeInputNative.tsx
│ │ │ └── utils.ts
│ │ ├── Timer
│ │ │ ├── Timer.md
│ │ │ ├── Timer.spec.ts
│ │ │ ├── Timer.tsx
│ │ │ └── TimerNative.tsx
│ │ ├── Toggle
│ │ │ ├── Toggle.module.scss
│ │ │ └── Toggle.tsx
│ │ ├── ToneChangerButton
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneChangerButton.spec.ts
│ │ │ └── ToneChangerButton.tsx
│ │ ├── ToneSwitch
│ │ │ ├── ToneSwitch.md
│ │ │ ├── ToneSwitch.module.scss
│ │ │ ├── ToneSwitch.spec.ts
│ │ │ ├── ToneSwitch.tsx
│ │ │ └── ToneSwitchNative.tsx
│ │ ├── Tooltip
│ │ │ ├── Tooltip.md
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.spec.ts
│ │ │ ├── Tooltip.tsx
│ │ │ └── TooltipNative.tsx
│ │ ├── Tree
│ │ │ ├── testData.ts
│ │ │ ├── Tree-dynamic.spec.ts
│ │ │ ├── Tree-icons.spec.ts
│ │ │ ├── Tree.md
│ │ │ ├── Tree.spec.ts
│ │ │ ├── TreeComponent.module.scss
│ │ │ ├── TreeComponent.tsx
│ │ │ └── TreeNative.tsx
│ │ ├── TreeDisplay
│ │ │ ├── TreeDisplay.md
│ │ │ ├── TreeDisplay.module.scss
│ │ │ ├── TreeDisplay.tsx
│ │ │ └── TreeDisplayNative.tsx
│ │ ├── ValidationSummary
│ │ │ ├── ValidationSummary.module.scss
│ │ │ └── ValidationSummary.tsx
│ │ └── VisuallyHidden.tsx
│ ├── components-core
│ │ ├── abstractions
│ │ │ ├── ComponentRenderer.ts
│ │ │ ├── LoaderRenderer.ts
│ │ │ ├── standalone.ts
│ │ │ └── treeAbstractions.ts
│ │ ├── action
│ │ │ ├── actions.ts
│ │ │ ├── APICall.tsx
│ │ │ ├── FileDownloadAction.tsx
│ │ │ ├── FileUploadAction.tsx
│ │ │ ├── NavigateAction.tsx
│ │ │ └── TimedAction.tsx
│ │ ├── ApiBoundComponent.tsx
│ │ ├── appContext
│ │ │ ├── date-functions.ts
│ │ │ ├── math-function.ts
│ │ │ └── misc-utils.ts
│ │ ├── AppContext.tsx
│ │ ├── behaviors
│ │ │ ├── Behavior.tsx
│ │ │ └── CoreBehaviors.tsx
│ │ ├── component-hooks.ts
│ │ ├── ComponentDecorator.tsx
│ │ ├── ComponentViewer.tsx
│ │ ├── CompoundComponent.tsx
│ │ ├── constants.ts
│ │ ├── DebugViewProvider.tsx
│ │ ├── descriptorHelper.ts
│ │ ├── devtools
│ │ │ ├── InspectorDialog.module.scss
│ │ │ ├── InspectorDialog.tsx
│ │ │ └── InspectorDialogVisibilityContext.tsx
│ │ ├── EngineError.ts
│ │ ├── event-handlers.ts
│ │ ├── InspectorButton.module.scss
│ │ ├── InspectorContext.tsx
│ │ ├── interception
│ │ │ ├── abstractions.ts
│ │ │ ├── ApiInterceptor.ts
│ │ │ ├── ApiInterceptorProvider.tsx
│ │ │ ├── apiInterceptorWorker.ts
│ │ │ ├── Backend.ts
│ │ │ ├── Errors.ts
│ │ │ ├── IndexedDb.ts
│ │ │ ├── initMock.ts
│ │ │ ├── InMemoryDb.ts
│ │ │ ├── ReadonlyCollection.ts
│ │ │ └── useApiInterceptorContext.tsx
│ │ ├── loader
│ │ │ ├── ApiLoader.tsx
│ │ │ ├── DataLoader.tsx
│ │ │ ├── ExternalDataLoader.tsx
│ │ │ ├── Loader.tsx
│ │ │ ├── MockLoaderRenderer.tsx
│ │ │ └── PageableLoader.tsx
│ │ ├── LoaderComponent.tsx
│ │ ├── markup-check.ts
│ │ ├── parts.ts
│ │ ├── renderers.ts
│ │ ├── rendering
│ │ │ ├── AppContent.tsx
│ │ │ ├── AppRoot.tsx
│ │ │ ├── AppWrapper.tsx
│ │ │ ├── buildProxy.ts
│ │ │ ├── collectFnVarDeps.ts
│ │ │ ├── ComponentAdapter.tsx
│ │ │ ├── ComponentWrapper.tsx
│ │ │ ├── Container.tsx
│ │ │ ├── containers.ts
│ │ │ ├── ContainerWrapper.tsx
│ │ │ ├── ErrorBoundary.module.scss
│ │ │ ├── ErrorBoundary.tsx
│ │ │ ├── InvalidComponent.module.scss
│ │ │ ├── InvalidComponent.tsx
│ │ │ ├── nodeUtils.ts
│ │ │ ├── reducer.ts
│ │ │ ├── renderChild.tsx
│ │ │ ├── StandaloneComponent.tsx
│ │ │ ├── StateContainer.tsx
│ │ │ ├── UnknownComponent.module.scss
│ │ │ ├── UnknownComponent.tsx
│ │ │ └── valueExtractor.ts
│ │ ├── reportEngineError.ts
│ │ ├── RestApiProxy.ts
│ │ ├── script-runner
│ │ │ ├── asyncProxy.ts
│ │ │ ├── AttributeValueParser.ts
│ │ │ ├── bannedFunctions.ts
│ │ │ ├── BindingTreeEvaluationContext.ts
│ │ │ ├── eval-tree-async.ts
│ │ │ ├── eval-tree-common.ts
│ │ │ ├── eval-tree-sync.ts
│ │ │ ├── ParameterParser.ts
│ │ │ ├── process-statement-async.ts
│ │ │ ├── process-statement-common.ts
│ │ │ ├── process-statement-sync.ts
│ │ │ ├── ScriptingSourceTree.ts
│ │ │ ├── simplify-expression.ts
│ │ │ ├── statement-queue.ts
│ │ │ └── visitors.ts
│ │ ├── StandaloneApp.tsx
│ │ ├── StandaloneExtensionManager.ts
│ │ ├── TableOfContentsContext.tsx
│ │ ├── theming
│ │ │ ├── _themes.scss
│ │ │ ├── component-layout-resolver.ts
│ │ │ ├── extendThemeUtils.ts
│ │ │ ├── hvar.ts
│ │ │ ├── layout-resolver.ts
│ │ │ ├── parse-layout-props.ts
│ │ │ ├── StyleContext.tsx
│ │ │ ├── StyleRegistry.ts
│ │ │ ├── ThemeContext.tsx
│ │ │ ├── ThemeProvider.tsx
│ │ │ ├── themes
│ │ │ │ ├── base-utils.ts
│ │ │ │ ├── palette.ts
│ │ │ │ ├── root.ts
│ │ │ │ ├── solid.ts
│ │ │ │ ├── theme-colors.ts
│ │ │ │ └── xmlui.ts
│ │ │ ├── themeVars.module.scss
│ │ │ ├── themeVars.ts
│ │ │ ├── transformThemeVars.ts
│ │ │ └── utils.ts
│ │ ├── utils
│ │ │ ├── actionUtils.ts
│ │ │ ├── audio-utils.ts
│ │ │ ├── base64-utils.ts
│ │ │ ├── compound-utils.ts
│ │ │ ├── css-utils.ts
│ │ │ ├── DataLoaderQueryKeyGenerator.ts
│ │ │ ├── date-utils.ts
│ │ │ ├── extractParam.ts
│ │ │ ├── hooks.tsx
│ │ │ ├── LruCache.ts
│ │ │ ├── mergeProps.ts
│ │ │ ├── misc.ts
│ │ │ ├── request-params.ts
│ │ │ ├── statementUtils.ts
│ │ │ └── treeUtils.ts
│ │ └── xmlui-parser.ts
│ ├── index-standalone.ts
│ ├── index.scss
│ ├── index.ts
│ ├── language-server
│ │ ├── server-common.ts
│ │ ├── server-web-worker.ts
│ │ ├── server.ts
│ │ ├── services
│ │ │ ├── common
│ │ │ │ ├── docs-generation.ts
│ │ │ │ ├── lsp-utils.ts
│ │ │ │ ├── metadata-utils.ts
│ │ │ │ └── syntax-node-utilities.ts
│ │ │ ├── completion.ts
│ │ │ ├── diagnostic.ts
│ │ │ ├── format.ts
│ │ │ └── hover.ts
│ │ └── xmlui-metadata-generated.mjs
│ ├── logging
│ │ ├── LoggerContext.tsx
│ │ ├── LoggerInitializer.tsx
│ │ ├── LoggerService.ts
│ │ └── xmlui.ts
│ ├── logo.svg
│ ├── parsers
│ │ ├── common
│ │ │ ├── GenericToken.ts
│ │ │ ├── InputStream.ts
│ │ │ └── utils.ts
│ │ ├── scripting
│ │ │ ├── code-behind-collect.ts
│ │ │ ├── Lexer.ts
│ │ │ ├── modules.ts
│ │ │ ├── Parser.ts
│ │ │ ├── ParserError.ts
│ │ │ ├── ScriptingNodeTypes.ts
│ │ │ ├── TokenTrait.ts
│ │ │ ├── TokenType.ts
│ │ │ └── tree-visitor.ts
│ │ ├── style-parser
│ │ │ ├── errors.ts
│ │ │ ├── source-tree.ts
│ │ │ ├── StyleInputStream.ts
│ │ │ ├── StyleLexer.ts
│ │ │ ├── StyleParser.ts
│ │ │ └── tokens.ts
│ │ └── xmlui-parser
│ │ ├── CharacterCodes.ts
│ │ ├── diagnostics.ts
│ │ ├── fileExtensions.ts
│ │ ├── index.ts
│ │ ├── lint.ts
│ │ ├── parser.ts
│ │ ├── ParserError.ts
│ │ ├── scanner.ts
│ │ ├── syntax-kind.ts
│ │ ├── syntax-node.ts
│ │ ├── transform.ts
│ │ ├── utils.ts
│ │ ├── xmlui-serializer.ts
│ │ └── xmlui-tree.ts
│ ├── react-app-env.d.ts
│ ├── syntax
│ │ ├── monaco
│ │ │ ├── grammar.monacoLanguage.ts
│ │ │ ├── index.ts
│ │ │ ├── xmlui-dark.ts
│ │ │ ├── xmlui-light.ts
│ │ │ └── xmluiscript.monacoLanguage.ts
│ │ └── textMate
│ │ ├── index.ts
│ │ ├── xmlui-dark.json
│ │ ├── xmlui-light.json
│ │ ├── xmlui.json
│ │ └── xmlui.tmLanguage.json
│ ├── testing
│ │ ├── assertions.ts
│ │ ├── component-test-helpers.ts
│ │ ├── ComponentDrivers.ts
│ │ ├── drivers
│ │ │ ├── DateInputDriver.ts
│ │ │ ├── ModalDialogDriver.ts
│ │ │ ├── NumberBoxDriver.ts
│ │ │ ├── TextBoxDriver.ts
│ │ │ ├── TimeInputDriver.ts
│ │ │ ├── TimerDriver.ts
│ │ │ └── TreeDriver.ts
│ │ ├── fixtures.ts
│ │ ├── infrastructure
│ │ │ ├── index.html
│ │ │ ├── main.tsx
│ │ │ ├── public
│ │ │ │ ├── mockServiceWorker.js
│ │ │ │ ├── resources
│ │ │ │ │ ├── bell.svg
│ │ │ │ │ ├── box.svg
│ │ │ │ │ ├── doc.svg
│ │ │ │ │ ├── eye.svg
│ │ │ │ │ ├── flower-640x480.jpg
│ │ │ │ │ ├── sun.svg
│ │ │ │ │ ├── test-image-100x100.jpg
│ │ │ │ │ └── txt.svg
│ │ │ │ └── serve.json
│ │ │ └── TestBed.tsx
│ │ └── themed-app-test-helpers.ts
│ └── vite-env.d.ts
├── tests
│ ├── components
│ │ ├── CodeBlock
│ │ │ └── hightlight-code.test.ts
│ │ ├── playground-pattern.test.ts
│ │ └── Tree
│ │ └── Tree-states.test.ts
│ ├── components-core
│ │ ├── abstractions
│ │ │ └── treeAbstractions.test.ts
│ │ ├── container
│ │ │ └── buildProxy.test.ts
│ │ ├── interception
│ │ │ ├── orderBy.test.ts
│ │ │ ├── ReadOnlyCollection.test.ts
│ │ │ └── request-param-converter.test.ts
│ │ ├── scripts-runner
│ │ │ ├── AttributeValueParser.test.ts
│ │ │ ├── eval-tree-arrow-async.test.ts
│ │ │ ├── eval-tree-arrow.test.ts
│ │ │ ├── eval-tree-func-decl-async.test.ts
│ │ │ ├── eval-tree-func-decl.test.ts
│ │ │ ├── eval-tree-pre-post.test.ts
│ │ │ ├── eval-tree-regression.test.ts
│ │ │ ├── eval-tree.test.ts
│ │ │ ├── function-proxy.test.ts
│ │ │ ├── parser-regression.test.ts
│ │ │ ├── process-event.test.ts
│ │ │ ├── process-function.test.ts
│ │ │ ├── process-implicit-context.test.ts
│ │ │ ├── process-statement-asgn.test.ts
│ │ │ ├── process-statement-destruct.test.ts
│ │ │ ├── process-statement-regs.test.ts
│ │ │ ├── process-statement-sync.test.ts
│ │ │ ├── process-statement.test.ts
│ │ │ ├── process-switch-sync.test.ts
│ │ │ ├── process-switch.test.ts
│ │ │ ├── process-try-sync.test.ts
│ │ │ ├── process-try.test.ts
│ │ │ └── test-helpers.ts
│ │ ├── test-metadata-handler.ts
│ │ ├── theming
│ │ │ ├── border-segments.test.ts
│ │ │ ├── component-layout.resolver.test.ts
│ │ │ ├── layout-property-parser.test.ts
│ │ │ ├── layout-resolver.test.ts
│ │ │ ├── layout-resolver2.test.ts
│ │ │ ├── layout-vp-override.test.ts
│ │ │ └── padding-segments.test.ts
│ │ └── utils
│ │ ├── date-utils.test.ts
│ │ ├── format-human-elapsed-time.test.ts
│ │ └── LruCache.test.ts
│ ├── language-server
│ │ ├── completion.test.ts
│ │ ├── format.test.ts
│ │ ├── hover.test.ts
│ │ └── mockData.ts
│ └── parsers
│ ├── common
│ │ └── input-stream.test.ts
│ ├── markdown
│ │ └── parse-binding-expression.test.ts
│ ├── parameter-parser.test.ts
│ ├── paremeter-parser.test.ts
│ ├── scripting
│ │ ├── eval-tree-arrow.test.ts
│ │ ├── eval-tree-pre-post.test.ts
│ │ ├── eval-tree.test.ts
│ │ ├── function-proxy.test.ts
│ │ ├── lexer-literals.test.ts
│ │ ├── lexer-misc.test.ts
│ │ ├── module-parse.test.ts
│ │ ├── parser-arrow.test.ts
│ │ ├── parser-assignments.test.ts
│ │ ├── parser-binary.test.ts
│ │ ├── parser-destructuring.test.ts
│ │ ├── parser-errors.test.ts
│ │ ├── parser-expressions.test.ts
│ │ ├── parser-function.test.ts
│ │ ├── parser-literals.test.ts
│ │ ├── parser-primary.test.ts
│ │ ├── parser-regex.test.ts
│ │ ├── parser-statements.test.ts
│ │ ├── parser-unary.test.ts
│ │ ├── process-event.test.ts
│ │ ├── process-implicit-context.test.ts
│ │ ├── process-statement-asgn.test.ts
│ │ ├── process-statement-destruct.test.ts
│ │ ├── process-statement-regs.test.ts
│ │ ├── process-statement-sync.test.ts
│ │ ├── process-statement.test.ts
│ │ ├── process-switch-sync.test.ts
│ │ ├── process-switch.test.ts
│ │ ├── process-try-sync.test.ts
│ │ ├── process-try.test.ts
│ │ ├── simplify-expression.test.ts
│ │ ├── statement-hooks.test.ts
│ │ └── test-helpers.ts
│ ├── style-parser
│ │ ├── generateHvarChain.test.ts
│ │ ├── parseHVar.test.ts
│ │ ├── parser.test.ts
│ │ └── tokens.test.ts
│ └── xmlui
│ ├── lint.test.ts
│ ├── parser.test.ts
│ ├── scanner.test.ts
│ ├── transform.attr.test.ts
│ ├── transform.circular.test.ts
│ ├── transform.element.test.ts
│ ├── transform.errors.test.ts
│ ├── transform.escape.test.ts
│ ├── transform.regression.test.ts
│ ├── transform.script.test.ts
│ ├── transform.test.ts
│ └── xmlui.ts
├── tests-e2e
│ ├── api-bound-component-regression.spec.ts
│ ├── api-call-as-extracted-component.spec.ts
│ ├── assign-to-object-or-array-regression.spec.ts
│ ├── binding-regression.spec.ts
│ ├── children-as-template-context-vars.spec.ts
│ ├── compound-component.spec.ts
│ ├── context-vars-regression.spec.ts
│ ├── data-bindings.spec.ts
│ ├── datasource-and-api-usage-in-var.spec.ts
│ ├── datasource-direct-binding.spec.ts
│ ├── datasource-onLoaded-regression.spec.ts
│ ├── modify-array-item-regression.spec.ts
│ ├── namespaces.spec.ts
│ ├── push-to-array-regression.spec.ts
│ ├── screen-breakpoints.spec.ts
│ ├── scripting.spec.ts
│ ├── state-scope-in-pages.spec.ts
│ └── state-var-scopes.spec.ts
├── tsconfig.bin.json
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── vitest.config.ts
```
# Files
--------------------------------------------------------------------------------
/.github/workflows/release-packages.yml:
--------------------------------------------------------------------------------
```yaml
1 | name: Release Packages
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 | types:
7 | - closed
8 | branches:
9 | - main
10 |
11 | permissions:
12 | contents: write
13 | pull-requests: write
14 | id-token: write
15 |
16 | jobs:
17 | publish_and_github_release:
18 | name: Publish Stable and Create GitHub Release
19 | if: >
20 | github.event_name == 'workflow_dispatch' ||
21 | (github.event_name == 'pull_request' &&
22 | github.event.action == 'closed' &&
23 | github.event.pull_request.merged == true &&
24 | (startsWith(github.event.pull_request.title, 'Version Packages for Stable Release') || contains(github.event.pull_request.labels.*.name, 'changeset-release')))
25 | runs-on: ubuntu-latest-8-core
26 | timeout-minutes: 60
27 | env:
28 | NODE_OPTIONS: "--max-old-space-size=8192"
29 | # needs: [create_version_pr] # This is implied by the trigger conditions
30 | steps:
31 | - name: Checkout Repo
32 | uses: actions/checkout@v4
33 | with:
34 | fetch-depth: 0
35 |
36 | - name: Setup Node.js
37 | uses: actions/setup-node@v4
38 | with:
39 | node-version: 22
40 | cache: "npm"
41 | registry-url: "https://registry.npmjs.org"
42 |
43 | - name: Install dependencies
44 | run: npm ci --prefer-offline
45 |
46 | - name: Cache for Turbo
47 | uses: rharkor/[email protected]
48 |
49 | - name: Store Playwright's Version
50 | run: |
51 | PLAYWRIGHT_VERSION=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | sort | head -n 1)
52 | echo "Playwright's Version: $PLAYWRIGHT_VERSION"
53 | echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV
54 |
55 | - name: Cache Playwright Browsers for Playwright's Version
56 | id: cache-playwright-browsers
57 | uses: actions/cache@v4
58 | with:
59 | path: ~/.cache/ms-playwright
60 | key: playwright-browsers-${{ env.PLAYWRIGHT_VERSION }}
61 |
62 | - name: Install Playwright Browsers
63 | if: steps.cache-playwright-browsers.outputs.cache-hit != 'true'
64 | run: npx playwright install --with-deps
65 |
66 | - name: Create Version PR or Publish to NPM and Create GitHub Releases
67 | id: changesets_publish
68 | uses: changesets/action@v1
69 | with:
70 | publish: npm run publish-packages
71 | env:
72 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
73 | NODE_AUTH_TOKEN: ${{secrets.PUBLISH_NPM_TOKEN}}
74 |
75 | - name: Output Published Packages Info
76 | if: steps.changesets_publish.outputs.published == 'true'
77 | run: |
78 | echo "Packages published: ${{ steps.changesets_publish.outputs.publishedPackages }}"
79 |
80 | - name: Prepare standalone js file
81 | id: prepare_standalone
82 | if: steps.changesets_publish.outputs.published == 'true' && contains(fromJSON(steps.changesets_publish.outputs.publishedPackages).*.name, 'xmlui')
83 | run: |
84 | XMLUI_VERSION=$(jq -r .version xmlui/package.json)
85 | STANDALONE_FILENAME="xmlui-${XMLUI_VERSION}.js"
86 | cp xmlui/dist/standalone/xmlui-standalone.umd.js $STANDALONE_FILENAME
87 | echo "version=$XMLUI_VERSION" >> $GITHUB_OUTPUT
88 | echo "filename=$STANDALONE_FILENAME" >> $GITHUB_OUTPUT
89 |
90 | echo "prepared xmlui-standalone.umd.js for release with filename: $STANDALONE_FILENAME"
91 |
92 | - name: Upload standalone js file
93 | if: steps.prepare_standalone.outputs.filename != ''
94 | uses: softprops/action-gh-release@v1
95 | with:
96 | files: "${{ steps.prepare_standalone.outputs.filename }}"
97 | tag_name: xmlui@${{ steps.prepare_standalone.outputs.version }}
98 | fail_on_unmatched_files: true
99 |
100 | - name: Get VSCode Extension release info
101 | id: xmlui_vscode_info
102 | if: steps.changesets_publish.outputs.published == 'true'
103 | run: |
104 | XMLUI_VSCODE_VERSION=$(jq -r .version tools/vscode/package.json)
105 |
106 | XMLUI_VSCODE_TAG="xmlui-vscode@${XMLUI_VSCODE_VERSION}"
107 | echo "tag=$XMLUI_VSCODE_TAG" >> $GITHUB_OUTPUT
108 |
109 | XMLUI_VSCODE_TAG_EXISTING=$(git tag --list $XMLUI_VSCODE_TAG)
110 | TAG_EXISTS="false"
111 | if [ ! -z "$XMLUI_VSCODE_TAG_EXISTING" ]; then
112 | TAG_EXISTS="true"
113 | fi
114 | echo "tagExists=$TAG_EXISTS" >> $GITHUB_OUTPUT
115 |
116 | echo "current VSCode extension version: $XMLUI_VSCODE_VERSION"
117 | echo "release tag for VSCode extension: $XMLUI_VSCODE_TAG"
118 | echo "tag already exists: $TAG_EXISTS"
119 |
120 | - name: Build VSCode extension
121 | if: steps.changesets_publish.outputs.published == 'true' && steps.xmlui_vscode_info.outputs.tagExists == 'false'
122 | run: npm run build-vscode-extension
123 |
124 | - name: Upload VSIX to Release
125 | if: steps.changesets_publish.outputs.published == 'true' && steps.xmlui_vscode_info.outputs.tagExists == 'false'
126 | uses: softprops/action-gh-release@v1
127 | with:
128 | files: "tools/vscode/*.vsix"
129 | tag_name: ${{ steps.xmlui_vscode_info.outputs.tag }}
130 | fail_on_unmatched_files: true
131 |
132 | - name: Publish VSCode Extension to Marketplace
133 | if: steps.changesets_publish.outputs.published == 'true' && steps.xmlui_vscode_info.outputs.tagExists == 'false'
134 | run: |
135 | cd tools/vscode
136 | npx vsce publish \
137 | --packagePath *.vsix \
138 | --no-git-tag-version \
139 | --no-update-package-json \
140 | env:
141 | VSCE_PAT: ${{ secrets.VSCE_PAT }}
142 |
```
--------------------------------------------------------------------------------
/xmlui/src/components-core/interception/ApiInterceptorProvider.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import type { ReactNode } from "react";
2 | import { useCallback, useEffect, useMemo, useState } from "react";
3 | import type { SetupWorker } from "msw/browser";
4 |
5 | import type { IApiInterceptorContext } from "../../abstractions/AppContextDefs";
6 | import type { ApiInterceptorDefinition } from "../interception/abstractions";
7 | import { normalizePath } from "../utils/misc";
8 | import { ApiInterceptorContext } from "./useApiInterceptorContext";
9 | import type { ApiInterceptor } from "./ApiInterceptor";
10 |
11 | type Props = {
12 | interceptor?: ApiInterceptorDefinition;
13 | children: ReactNode;
14 | parentInterceptorContext?: IApiInterceptorContext;
15 | waitForApiInterceptor?: boolean;
16 | useHashBasedRouting?: boolean;
17 | };
18 |
19 | // This React component injects the API interceptor into the application's context
20 | export function ApiInterceptorProvider({
21 | interceptor,
22 | children,
23 | parentInterceptorContext = null,
24 | waitForApiInterceptor = false,
25 | }: Props) {
26 | const hasParentInterceptorContext = parentInterceptorContext !== null;
27 | const [initialized, setInitialized] = useState(!interceptor);
28 | const [forceInitialize, setForceInitialize] = useState(false);
29 | const [interceptorWorker, setInterceptorWorker] = useState<SetupWorker | null>(null);
30 | const [apiInstance, setApiInstance] = useState<ApiInterceptor | null>(null);
31 |
32 | const useWorker = interceptor?.useWorker ?? true;
33 |
34 | // --- Whenever the interceptor changes, update the provider accordingly
35 | let forceInitializeParent = parentInterceptorContext?.forceInitialize;
36 | let parentInterceptorWorker = parentInterceptorContext?.interceptorWorker;
37 |
38 | //// if we don't use a worker, we initialize the api instance directly
39 | useEffect(() => {
40 | if (useWorker) {
41 | return;
42 | }
43 | if (!interceptor) {
44 | return;
45 | }
46 |
47 | void (async () => {
48 | const { initMock } = await import("./initMock");
49 | const apiInstance = await initMock(interceptor);
50 | setApiInstance(apiInstance);
51 | setInitialized(true);
52 | })();
53 | }, [interceptor, useWorker]);
54 |
55 | //// if we use a worker, we initialize the worker with the api instance
56 | useEffect(() => {
57 | if (!useWorker) {
58 | return;
59 | }
60 | if (!hasParentInterceptorContext) {
61 | if (interceptor || forceInitialize) {
62 | // setInitialized(false);
63 |
64 | // --- We use "msw" to manage the API interception
65 | let interceptorWorker: SetupWorker;
66 | void (async () => {
67 | // --- Create the worker on the fly
68 | if (process.env.VITE_MOCK_ENABLED) {
69 | const [{ createApiInterceptorWorker }, { initMock }] = await Promise.all([
70 | useWorker
71 | ? import("./apiInterceptorWorker")
72 | : Promise.resolve({ createApiInterceptorWorker: () => null }),
73 | import("./initMock"),
74 | ]);
75 |
76 | if (interceptor || forceInitialize) {
77 | const apiInstance = await initMock(interceptor || {});
78 | interceptorWorker = await createApiInterceptorWorker(apiInstance);
79 | // if the apiWorker comes from the outside, we don't handle the lifecycle here
80 | const workerFileLocation = normalizePath(
81 | process.env.VITE_MOCK_WORKER_LOCATION || "mockServiceWorker.js",
82 | );
83 | await interceptorWorker.start({
84 | onUnhandledRequest: "bypass",
85 | quiet: true,
86 | serviceWorker: {
87 | url: workerFileLocation,
88 | },
89 | });
90 | setInterceptorWorker(interceptorWorker);
91 | }
92 | }
93 | setInitialized(true);
94 | })();
95 | return () => {
96 | // if the apiWorker comes from the outside, we don't handle the lifecycle here
97 | if (!parentInterceptorWorker) {
98 | interceptorWorker?.stop();
99 | }
100 | setInitialized(false);
101 | };
102 | } else {
103 | setInitialized(true);
104 | }
105 | } else {
106 | if (!interceptor) {
107 | return;
108 | }
109 | if (parentInterceptorWorker) {
110 | void (async () => {
111 | const [{ createApiInterceptorWorker }, { initMock }] = await Promise.all([
112 | import("./apiInterceptorWorker"),
113 | import("./initMock"),
114 | ]);
115 | const apiInstance = await initMock(interceptor);
116 | await createApiInterceptorWorker(apiInstance, parentInterceptorWorker);
117 | setTimeout(() => {
118 | setInitialized(true);
119 | }, 0);
120 | })();
121 | } else {
122 | forceInitializeParent?.();
123 | }
124 | }
125 | }, [
126 | useWorker,
127 | forceInitialize,
128 | hasParentInterceptorContext,
129 | interceptor,
130 | forceInitializeParent,
131 | parentInterceptorWorker,
132 | ]);
133 |
134 | const isMocked = useCallback(
135 | (url) => interceptor !== undefined && !!process.env.VITE_MOCK_ENABLED,
136 | [interceptor],
137 | );
138 |
139 | const doForceInitialize = useCallback(() => {
140 | setForceInitialize(true);
141 | }, []);
142 |
143 | const contextValue: IApiInterceptorContext = useMemo(() => {
144 | return {
145 | interceptorWorker,
146 | apiInstance,
147 | initialized: initialized,
148 | forceInitialize: doForceInitialize,
149 | isMocked: isMocked,
150 | };
151 | }, [interceptorWorker, apiInstance, initialized, doForceInitialize, isMocked]);
152 |
153 | return (
154 | <ApiInterceptorContext.Provider value={contextValue}>
155 | {waitForApiInterceptor && !initialized ? null : children}
156 | </ApiInterceptorContext.Provider>
157 | );
158 | }
159 |
```
--------------------------------------------------------------------------------
/xmlui/src/components-core/rendering/AppRoot.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { useEffect, useMemo } from "react";
2 | import { QueryClient } from "@tanstack/react-query";
3 | import { enableMapSet } from "immer";
4 |
5 | import type { ComponentLike } from "../../abstractions/ComponentDefs";
6 | import { resetErrors } from "../reportEngineError";
7 | import { ComponentProvider } from "../../components/ComponentProvider";
8 | import { DebugViewProvider } from "../DebugViewProvider";
9 | import type StandaloneExtensionManager from "../StandaloneExtensionManager";
10 | import type { AppWrapperProps } from "./AppWrapper";
11 | import { AppWrapper } from "./AppWrapper";
12 | import type { ComponentCompilation } from "../../abstractions/scripting/Compilation";
13 | import { StyleProvider } from "../theming/StyleContext";
14 |
15 | // --- We want to enable the produce method of `immer` on Map objects
16 | enableMapSet();
17 |
18 | // --- This type represents an arbitrary set of global properties (name
19 | // --- and value pairs).
20 | export type GlobalProps = Record<string, any>;
21 |
22 | // --- We use this object in the app context to represent the `QlientQuery`
23 | // --- of the react-query package.
24 | export const queryClient = new QueryClient({
25 | defaultOptions: {
26 | queries: {
27 | refetchOnWindowFocus: false,
28 | },
29 | },
30 | });
31 |
32 | /**
33 | * This component is responsible for running a pre-compiled xmlui app. It
34 | * receives the internal representation of the app markup and code (coming
35 | * from either code-behind files or inlined markup expressions) and executes
36 | * the app accordingly.
37 | */
38 | export function AppRoot({
39 | apiInterceptor,
40 | contributes,
41 | node,
42 | decorateComponentsWithTestId,
43 | debugEnabled,
44 | defaultTheme,
45 | defaultTone,
46 | resources,
47 | globalProps,
48 | standalone,
49 | trackContainerHeight,
50 | routerBaseName,
51 | previewMode,
52 | resourceMap,
53 | sources,
54 | extensionManager,
55 | children,
56 | projectCompilation,
57 | isNested = false,
58 | onInit,
59 | }: AppWrapperProps & {
60 | extensionManager?: StandaloneExtensionManager;
61 | isNested?: boolean;
62 | }) {
63 | // --- Make sure, the root node is wrapped in a `Theme` component. Also,
64 | // --- the root node must be wrapped in a `Container` component managing
65 | // --- the app's top-level state.
66 | const rootNode = useMemo(() => {
67 | const themedRoot = {
68 | type: "Theme",
69 | props: {
70 | root: true,
71 | },
72 | children: [node],
73 | };
74 | return {
75 | type: "Container",
76 | uid: "root",
77 | children: [themedRoot],
78 | uses: [],
79 | };
80 | }, [node]);
81 |
82 | if (projectCompilation) {
83 | const entryDeps = projectCompilation.entrypoint.dependencies;
84 |
85 | const transDeps = getTransitiveDependencies(entryDeps, projectCompilation.components);
86 | // console.log("projectCompilation: ", projectCompilation);
87 | // console.log("transitive dependencies of entrypoint: ", transDeps);
88 | }
89 |
90 | // --- Start with an error-free state
91 | resetErrors();
92 |
93 | // --- Add isNested to global props so it can be accessed throughout the app
94 | const enhancedGlobalProps = useMemo(() => ({
95 | ...globalProps,
96 | isNested,
97 | }), [globalProps, isNested]);
98 |
99 | // --- Render the app providing a component registry (in which the engine finds a
100 | // --- component definition by its name). Ensure the app has a context for debugging.
101 | return (
102 | <ComponentProvider contributes={contributes} extensionManager={extensionManager}>
103 | <StyleProvider>
104 | <DebugViewProvider debugConfig={globalProps?.debug}>
105 | <AppWrapper
106 | projectCompilation={projectCompilation}
107 | resourceMap={resourceMap}
108 | apiInterceptor={apiInterceptor}
109 | node={rootNode as ComponentLike}
110 | contributes={contributes}
111 | resources={resources}
112 | routerBaseName={routerBaseName}
113 | decorateComponentsWithTestId={decorateComponentsWithTestId}
114 | debugEnabled={debugEnabled}
115 | defaultTheme={defaultTheme}
116 | defaultTone={defaultTone}
117 | globalProps={enhancedGlobalProps}
118 | standalone={standalone}
119 | trackContainerHeight={trackContainerHeight}
120 | previewMode={previewMode}
121 | sources={sources}
122 | onInit={onInit}
123 | >
124 | {children}
125 | </AppWrapper>
126 | </DebugViewProvider>
127 | </StyleProvider>
128 | </ComponentProvider>
129 | );
130 | }
131 |
132 | /**
133 | *
134 | * @param directCompDepNames The direct dependencies (those are component names)
135 | * of the component for which the transitive dependencies will be returned
136 | * @param components the compilation info of all the components of the project */
137 | function getTransitiveDependencies(
138 | directCompDepNames: Set<string>,
139 | components: ComponentCompilation[],
140 | ) {
141 | const allDepsByCompName: Map<string, Set<string>> = components.reduce(
142 | function addDepsByNameToCollection(
143 | collection: Map<string, Set<string>>,
144 | { definition: { name }, dependencies },
145 | ) {
146 | return collection.set(name, dependencies);
147 | },
148 | new Map(),
149 | );
150 |
151 | const transitiveDeps = new Set<string>();
152 | populateTransitiveDeps(directCompDepNames);
153 | return transitiveDeps;
154 |
155 | function populateTransitiveDeps(directCompDepNames: Set<string>) {
156 | if (!directCompDepNames) return;
157 | for (const directDep of directCompDepNames) {
158 | if (!transitiveDeps.has(directDep)) {
159 | transitiveDeps.add(directDep);
160 | const depsOfDirectDep = allDepsByCompName.get(directDep);
161 | populateTransitiveDeps(depsOfDirectDep);
162 | }
163 | }
164 | }
165 | }
166 |
```
--------------------------------------------------------------------------------
/docs/content/components/Theme.md:
--------------------------------------------------------------------------------
```markdown
1 | # Theme [#theme]
2 |
3 | `Theme` creates styling contexts to customize the appearance of nested components without using CSS.
4 |
5 | **Key features:**
6 | - **No CSS required**: Change component appearance using theme variables instead of custom stylesheets
7 | - **Brand consistency**: Maintain design system compliance while allowing contextual variations
8 | - **Scoped styling**: Apply theme changes only to nested components without affecting the global design
9 | - **Variable overrides**: Modify colors, spacing, typography, and other design variables declaratively
10 | - **Nested contexts**: Stack multiple `Theme` components for granular control with automatic specificity rules
11 |
12 | See [this guide](/themes-intro) and [these references](/styles-and-themes/layout-props) for details.
13 |
14 | ## Using `Theme` [#using-theme]
15 |
16 | In contrast to other components, `Theme` accepts theme variables as properties.
17 | You can define specific styles for components nested in `Theme` using these theme variables.
18 |
19 | The following example specifies a dark tone for the current theme
20 | and sets several theme variables to style the `ProgressBar` component:
21 |
22 | ```xmlui-pg copy {3-8} display name="Example: using Theme"
23 | <App>
24 | <Theme
25 | tone="dark"
26 | backgroundColor-ProgressBar="cyan"
27 | color-indicator-ProgressBar="purple"
28 | thickness-ProgressBar="12px"
29 | borderRadius-indicator-ProgressBar="12px"
30 | borderRadius-Progressbar="4px"
31 | >
32 | <VStack backgroundColor="$backgroundColor-primary">
33 | <ProgressBar value="0"/>
34 | <ProgressBar value="0.2"/>
35 | <ProgressBar value="0.6"/>
36 | <ProgressBar value="1.0"/>
37 | </VStack>
38 | </Theme>
39 | </App>
40 | ```
41 |
42 | ## Properties [#properties]
43 |
44 | ### `applyIf` (default: true) [#applyif-default-true]
45 |
46 | This property controls whether the theme wrapper is applied. When true (default), the theme wraps the children. When false, children are rendered unwrapped.
47 |
48 | The `applyIf` property controls whether the theme is conditionally applied to its children. When set to `false`, the children are rendered without the theme wrapper, effectively bypassing the theme styling.
49 |
50 | ```xmlui-pg copy {2,9,16} display name="Example: applyIf"
51 | <App var.apply="{false}">
52 | <Theme backgroundColor-Button="rgb(255, 100, 100)" applyIf="true">
53 | <VStack>
54 | <H3>Theme Applied (applyIf="true"):</H3>
55 | <Button>Themed Button</Button>
56 | </VStack>
57 | </Theme>
58 | <Theme backgroundColor-Button="rgb(255, 100, 100)" applyIf="false">
59 | <VStack>
60 | <H3>Theme Not Applied (applyIf="false"):</H3>
61 | <Button>Default Button</Button>
62 | </VStack>
63 | </Theme>
64 | <Theme backgroundColor-Button="rgb(100, 192, 100)" applyIf="{apply}">
65 | <VStack>
66 | <H3>Conditional Theme (dynamic):</H3>
67 | <Button onClick="apply = !apply">
68 | {apply ? 'Themed' : 'Default'} - Click to Toggle
69 | </Button>
70 | </VStack>
71 | </Theme>
72 | </App>
73 | ```
74 |
75 | This property is particularly useful for:
76 | - **Conditional styling**: Apply themes based on user preferences, feature flags, or application state
77 | - **Theme debugging**: Temporarily disable themes during development
78 | - **Progressive enhancement**: Provide fallback styling when themes fail to load
79 | - **Dynamic theming**: Switch themes on and off based on user interactions or data conditions
80 |
81 | ### `root` (default: false) [#root-default-false]
82 |
83 | This property indicates whether the component is at the root of the application.
84 |
85 | If so, it will set a number of important settings for the app:
86 | - what favicon to use
87 | - sets up font links
88 | - specifies the base css
89 | - sets up the root for the toast notification system
90 |
91 | Otherwise, the `Theme` component will just provide the theme context to its children.
92 |
93 | ### `themeId` [#themeid]
94 |
95 | This property specifies which theme to use by setting the theme's id.
96 |
97 | ```xmlui-pg copy {2, 9, 16} display name="Example: themeId"
98 | <App>
99 | <Theme themeId="xmlui">
100 | <VStack backgroundColor="$backgroundColor-primary">
101 | <H3>Use 'xmlui' theme:</H3>
102 | <ProgressBar value="0"/>
103 | <ProgressBar value="0.6"/>
104 | </VStack>
105 | </Theme>
106 | <Theme themeId="xmlui-green">
107 | <VStack backgroundColor="$backgroundColor-primary">
108 | <H3>Use 'xmlui-green' theme:</H3>
109 | <ProgressBar value="0"/>
110 | <ProgressBar value="0.6"/>
111 | </VStack>
112 | </Theme>
113 | <Theme themeId="xmlui-red">
114 | <VStack backgroundColor="$backgroundColor-primary">
115 | <H3>Use the 'xmlui-red' theme:</H3>
116 | <ProgressBar value="0"/>
117 | <ProgressBar value="0.6"/>
118 | </VStack>
119 | </Theme>
120 | </App>
121 | ```
122 |
123 | ### `tone` (default: "light") [#tone-default-light]
124 |
125 | This property allows the setting of the current theme's tone.
126 |
127 | Available values: `light` **(default)**, `dark`
128 |
129 | ```xmlui-pg copy {2,9} display name="Example: tone"
130 | <App>
131 | <Theme tone="light">
132 | <VStack backgroundColor="$backgroundColor-primary" >
133 | <H3>Use the light tone of the base theme:</H3>
134 | <ProgressBar value="0"/>
135 | <ProgressBar value="0.6"/>
136 | </VStack>
137 | </Theme>
138 | <Theme tone="dark">
139 | <VStack backgroundColor="$backgroundColor-primary">
140 | <H3>Use the dark tone of the base theme:</H3>
141 | <ProgressBar value="0"/>
142 | <ProgressBar value="0.6"/>
143 | </VStack>
144 | </Theme>
145 | </App>
146 | ```
147 |
148 | ## Events [#events]
149 |
150 | This component does not have any events.
151 |
152 | ## Exposed Methods [#exposed-methods]
153 |
154 | This component does not expose any methods.
155 |
156 | ## Styling [#styling]
157 |
158 | The `Theme` component is a styling wrapper that influences the nested components' visual appearance. It cannot be styled.
159 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/ExpandableItem/ExpandableItemNative.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { type CSSProperties, forwardRef, type ReactNode, useCallback, useEffect, useId, useRef } from "react";
2 | import { useState } from "react";
3 | import classNames from "classnames";
4 |
5 | import styles from "./ExpandableItem.module.scss";
6 |
7 | import type { RegisterComponentApiFn } from "../../abstractions/RendererDefs";
8 | import { Icon } from "../Icon/IconNative";
9 | import { Toggle } from "../Toggle/Toggle";
10 |
11 | type ExpandableItemProps = {
12 | children?: ReactNode;
13 | summary?: ReactNode;
14 | className?: string;
15 | style?: CSSProperties;
16 | initiallyExpanded?: boolean;
17 | enabled?: boolean;
18 | iconExpanded?: string;
19 | iconCollapsed?: string;
20 | iconPosition?: "start" | "end";
21 | withSwitch?: boolean;
22 | onExpandedChange?: (isExpanded: boolean) => void;
23 | registerComponentApi?: RegisterComponentApiFn;
24 | };
25 |
26 | export const defaultExpandableItemProps: Pick<
27 | ExpandableItemProps,
28 | "initiallyExpanded" | "enabled" | "iconExpanded" | "iconCollapsed" | "iconPosition" | "withSwitch"
29 | > = {
30 | initiallyExpanded: false,
31 | enabled: true,
32 | iconExpanded: "chevrondown",
33 | iconCollapsed: "chevronright",
34 | iconPosition: "end",
35 | withSwitch: false,
36 | };
37 |
38 | export const ExpandableItem = forwardRef(function ExpandableItem(
39 | {
40 | summary,
41 | children,
42 | className,
43 | style,
44 | initiallyExpanded = defaultExpandableItemProps.initiallyExpanded,
45 | enabled = defaultExpandableItemProps.enabled,
46 | iconExpanded = defaultExpandableItemProps.iconExpanded,
47 | iconCollapsed = defaultExpandableItemProps.iconCollapsed,
48 | iconPosition = defaultExpandableItemProps.iconPosition,
49 | withSwitch = defaultExpandableItemProps.withSwitch,
50 | onExpandedChange,
51 | registerComponentApi,
52 | ...rest
53 | }: ExpandableItemProps,
54 | ref,
55 | ) {
56 | const [isOpen, setIsOpen] = useState(initiallyExpanded);
57 | const generatedId = useId();
58 | const summaryId = `${generatedId}-summary`;
59 | const contentId = `${generatedId}-content`;
60 |
61 | const toggleOpen = useCallback(() => {
62 | if (!enabled) return;
63 |
64 | const newValue = !isOpen;
65 | setIsOpen(newValue);
66 | onExpandedChange?.(newValue);
67 | }, [enabled, isOpen, onExpandedChange]);
68 |
69 | // Register component API
70 | const expand = useCallback(() => {
71 | if (!isOpen && enabled) {
72 | setIsOpen(true);
73 | onExpandedChange?.(true);
74 | }
75 | }, [enabled, isOpen, onExpandedChange]);
76 |
77 | const collapse = useCallback(() => {
78 | if (isOpen && enabled) {
79 | setIsOpen(false);
80 | onExpandedChange?.(false);
81 | }
82 | }, [enabled, isOpen, onExpandedChange]);
83 |
84 | const toggle = useCallback(() => {
85 | toggleOpen();
86 | }, [toggleOpen]);
87 |
88 | const getIsExpanded = useCallback(() => isOpen, [isOpen]);
89 |
90 | // Handle switch value change
91 | const handleSwitchChange = useCallback(
92 | (value: boolean) => {
93 | if (!enabled) return;
94 | setIsOpen(value);
95 | onExpandedChange?.(value);
96 | },
97 | [enabled, onExpandedChange],
98 | );
99 |
100 | // Register these functions with the component API using useEffect
101 | useEffect(() => {
102 | registerComponentApi?.({
103 | expand,
104 | collapse,
105 | toggle,
106 | isExpanded: getIsExpanded,
107 | });
108 | }, [registerComponentApi, expand, collapse, toggle, getIsExpanded]);
109 |
110 | // Handler for clicking on the summary when using a switch
111 | const handleSummaryClick = useCallback(() => {
112 | if (!enabled || !withSwitch) return;
113 |
114 | const newValue = !isOpen;
115 | setIsOpen(newValue);
116 | onExpandedChange?.(newValue);
117 | }, [enabled, withSwitch, isOpen, onExpandedChange]);
118 |
119 | // Handle keyboard events for accessibility
120 | const handleKeyDown = useCallback((event: React.KeyboardEvent) => {
121 | if (!enabled) return;
122 |
123 | if (event.key === 'Enter' || event.key === ' ') {
124 | event.preventDefault();
125 | if (withSwitch) {
126 | handleSwitchChange(!isOpen);
127 | } else {
128 | toggleOpen();
129 | }
130 | }
131 | }, [enabled, withSwitch, isOpen, handleSwitchChange, toggleOpen]);
132 |
133 | return (
134 | <div
135 | {...rest}
136 | className={classNames(styles.expandableItem, className, {
137 | [styles.open]: isOpen,
138 | [styles.disabled]: !enabled,
139 | [styles.withSwitch]: withSwitch,
140 | })}
141 | style={style}
142 | ref={ref as any}
143 | >
144 | <div
145 | className={classNames(styles.summary, {
146 | [styles.iconStart]: iconPosition === "start",
147 | [styles.iconEnd]: iconPosition === "end",
148 | })}
149 | onClick={enabled ? (withSwitch ? handleSummaryClick : toggleOpen) : undefined}
150 | onKeyDown={handleKeyDown}
151 | tabIndex={enabled ? 0 : undefined}
152 | role="button"
153 | aria-expanded={isOpen}
154 | aria-controls={contentId}
155 | aria-disabled={!enabled}
156 | id={summaryId}
157 | >
158 | <div className={withSwitch ? styles.switch : styles.icon} aria-hidden="true">
159 | {withSwitch ? (
160 | <Toggle
161 | variant="switch"
162 | value={isOpen}
163 | enabled={enabled}
164 | onDidChange={handleSwitchChange}
165 | />
166 | ) : (
167 | <Icon
168 | name={isOpen ? iconExpanded : iconCollapsed}
169 | fallback={isOpen ? "chevrondown" : "chevronright"}
170 | />
171 | )}
172 | </div>
173 | <div className={styles.summaryContent}>
174 | {summary}
175 | </div>
176 | </div>
177 | {isOpen && (
178 | <div
179 | className={styles.content}
180 | role="region"
181 | aria-labelledby={summaryId}
182 | id={contentId}
183 | >
184 | {children}
185 | </div>
186 | )}
187 | </div>
188 | );
189 | });
190 |
```
--------------------------------------------------------------------------------
/xmlui/tests/parsers/scripting/parser-regex.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describe, expect, it } from "vitest";
2 |
3 | import { Parser } from "../../../src/parsers/scripting/Parser";
4 | import {
5 | ConstStatement,
6 | Literal,
7 | T_CONST_STATEMENT,
8 | T_LITERAL,
9 | } from "../../../src/components-core/script-runner/ScriptingSourceTree";
10 |
11 | describe("Parser - regex literals", () => {
12 | it("null", () => {
13 | // --- Arrange
14 | const wParser = new Parser("null");
15 |
16 | // --- Act
17 | const expr = wParser.parseExpr();
18 |
19 | // --- Assert
20 | expect(expr).not.equal(null);
21 | if (!expr) return;
22 | expect(expr.type).equal(T_LITERAL);
23 | });
24 |
25 | const regExpCases = [
26 | /\w+/g,
27 | /(-?\d*\.\d\w*)|([^`~!@#%^&*()\-=+\[{\]}\\|;:'",.<>\/?\s]+)/g,
28 | /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
29 | /^\s*\*\/$/,
30 | /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
31 | /^(\t|(\ \ ))*\ \*\/\s*$/,
32 | /[=><!~?:&|+\-*\/\^%]+/,
33 | /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
34 | /\d+(_+\d+)*/,
35 | /[0-7]+(_+[0-7]+)*/,
36 | /[0-1]+(_+[0-1]+)*/,
37 | /[[0-9a-fA-F]+(_+[0-9a-fA-F]+)*/,
38 | /[(){}\[\]\$\^|\-*+?\.]/,
39 | /\\(?:[bBdDfnrstvwWn0\\\/]|@regexpctl|c[A-Z]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})/,
40 | /\d/, // Match any digit
41 | /\D/, // Match any non-digit character
42 | /\w/, // Match any word character
43 | /\W/, // Match any non-word character
44 | /\s/, // Match any whitespace character
45 | /\S/, // Match any non-whitespace character
46 | /a/, // Match a specific character
47 | /abc/, // Match a specific sequence of characters
48 | /./, // Match any character except newline
49 | /a*/, // Match zero or more occurrences of a character
50 | /a+/, // Match one or more occurrences of a character
51 | /a?/, // Match zero or one occurrence of a character
52 | /a{3}/, // Match a specific number of occurrences of a character
53 | /a{2,4}/, // Match a range of occurrences of a character
54 | /[abc]/, // Match any character in a character class
55 | /[^abc]/, // Match any character not in a character class
56 | /[a-z]/, // Match any character in a range
57 | /[^a-z]/, // Match any character not in a range
58 | /^/, // Match the start of a string
59 | /$/, // Match the end of a string
60 | /\b/, // Match the start of a word
61 | /\b\w/, // Match the end of a word
62 | /\B/, // Match a word boundary not at the start or end of a word
63 | /(abc)/, // Match a group of characters
64 | /(abc|def)/, // Match either of two patterns
65 | /.+?/, // Match any character except newline in a non-greedy way
66 | /.+/i, // Match any character except newline in a case-insensitive manner
67 | /a(?=b)/, // Match a character only if it is followed by another character
68 | /a(?!b)/, // Match a character only if it is not followed by another character
69 | /(?<=a)b/, // Match a character only if it is preceded by another character
70 | /(?<!a)b/, // Match a character only if it is not preceded by another character
71 | /\p{Sc}/u, // Match a character with a specific Unicode property
72 | /\P{Sc}/u, // Match a character without a specific Unicode property
73 | /\p{Script=Hiragana}/u, // Match a character with a specific Unicode script property
74 | /\P{Script=Hiragana}/u, // Match a character without a specific Unicode script property
75 | /\u{1F602}/u, // Match a Unicode character by its code point
76 | /\p{General_Category=Letter}/u, // Match a character with a specific Unicode property value
77 | /\P{General_Category=Letter}/u, // Match a character without a specific Unicode property value
78 | /[^abc]/i, // Match any character except those in a character class ignoring case
79 | /[^a-z]/i, // Match any character except those in a range ignoring case
80 | /\x41/, // Match a digit in hexadecimal format
81 | /\o101/, // Match a digit in octal format
82 | /\b01000001\b/, // Match a digit in binary format
83 | /\p{Dash}/u, // Match a character with a specific Unicode binary property value
84 | /\P{Dash}/u, // Match a character without a specific Unicode binary property value
85 | /\p{L}/u, // Match a character with a specific Unicode property value using shorthand
86 | /\P{L}/u, // Match a character without a specific Unicode property value using shorthand
87 | /[:digit:]/u, // Match a character with a specific Unicode property value using POSIX syntax
88 | /[^:digit:]/u, // Match a character without a specific Unicode property value using POSIX syntax
89 | ];
90 |
91 | regExpCases.forEach((regExp) => {
92 | it(`RegExp: ${regExp}`, () => {
93 | const parser = new Parser(regExp.toString());
94 | const result = parser.parseExpr()!;
95 |
96 | expect(result.type).toBe(T_LITERAL);
97 | const literal = result as Literal;
98 | expect(literal.value instanceof RegExp).equal(true);
99 | expect(literal.value).toStrictEqual(regExp);
100 | });
101 |
102 | it(`RegExp in statement: ${regExp} #1`, () => {
103 | const parser = new Parser(`const a = ${regExp};`);
104 | const result = parser.parseStatements()!;
105 |
106 | expect(result.length).toBe(1);
107 | const stmt = result[0] as ConstStatement;
108 | expect(stmt.decls[0].expr!.type).equal(T_LITERAL);
109 | const literal = stmt.decls[0].expr as Literal;
110 | expect(literal.value instanceof RegExp).equal(true);
111 | expect(literal.value).toStrictEqual(regExp);
112 | });
113 |
114 | it(`RegExp in statement: ${regExp} #2`, () => {
115 | const parser = new Parser(`const a = ''.match(${regExp}) + 120;`);
116 | const result = parser.parseStatements()!;
117 |
118 | expect(result.length).toBe(1);
119 | expect(result[0].type).toBe(T_CONST_STATEMENT);
120 | });
121 | });
122 | });
123 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Pagination/Pagination.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 | // Define theme variables
11 | $backgroundColor-Pagination: createThemeVar("backgroundColor-Pagination");
12 | $borderColor-Pagination: createThemeVar("borderColor-Pagination");
13 | $borderRadius-selector-Pagination: createThemeVar("borderRadius-selector-Pagination");
14 | $textColor-Pagination: createThemeVar("textColor-Pagination");
15 | $backgroundColor-selector-Pagination: createThemeVar("backgroundColor-selector-Pagination");
16 | $textColor-selector-Pagination: createThemeVar("textColor-selector-Pagination");
17 |
18 | @layer components {
19 | .pagination {
20 | display: grid;
21 | align-items: center;
22 | padding: createThemeVar("padding-Pagination");
23 | gap: t.$space-4;
24 |
25 | // Default 3-column layout
26 | grid-template-columns: 1fr 1fr 1fr;
27 | grid-template-areas: "a b c";
28 |
29 | // Vertical layout (3 rows)
30 | &.paginationVertical {
31 | grid-template-columns: 1fr;
32 | grid-template-rows: auto auto auto;
33 | grid-template-areas: "a" "b" "c";
34 |
35 | // 2-row layout when only start and end slots are present
36 | &:has(.startSlot):has(.endSlot):not(:has(.centerSlot)) {
37 | grid-template-rows: auto auto;
38 | grid-template-areas: "a" "c";
39 | }
40 |
41 | // 1-row layout when only one slot is present
42 | &:has(.startSlot):not(:has(.centerSlot)):not(:has(.endSlot)) {
43 | grid-template-rows: auto;
44 | grid-template-areas: "a";
45 | }
46 |
47 | &:has(.centerSlot):not(:has(.startSlot)):not(:has(.endSlot)) {
48 | grid-template-rows: auto;
49 | grid-template-areas: "b";
50 | }
51 |
52 | &:has(.endSlot):not(:has(.startSlot)):not(:has(.centerSlot)) {
53 | grid-template-rows: auto;
54 | grid-template-areas: "c";
55 | }
56 |
57 | // 2-row layout for start + center
58 | &:has(.startSlot):has(.centerSlot):not(:has(.endSlot)) {
59 | grid-template-rows: auto auto;
60 | grid-template-areas: "a" "b";
61 | }
62 |
63 | // 2-row layout for center + end
64 | &:has(.centerSlot):has(.endSlot):not(:has(.startSlot)) {
65 | grid-template-rows: auto auto;
66 | grid-template-areas: "b" "c";
67 | }
68 | }
69 |
70 | // Horizontal layout variations (keep existing)
71 | &:not(.paginationVertical) {
72 | // 2-column layout when only start and end slots are present
73 | &:has(.startSlot):has(.endSlot):not(:has(.centerSlot)) {
74 | grid-template-columns: 1fr 1fr;
75 | grid-template-areas: "a c";
76 | }
77 |
78 | // 1-column layout when only one slot is present
79 | &:has(.startSlot):not(:has(.centerSlot)):not(:has(.endSlot)) {
80 | grid-template-columns: 1fr;
81 | grid-template-areas: "a";
82 | }
83 |
84 | &:has(.centerSlot):not(:has(.startSlot)):not(:has(.endSlot)) {
85 | grid-template-columns: 1fr;
86 | grid-template-areas: "b";
87 | }
88 |
89 | &:has(.endSlot):not(:has(.startSlot)):not(:has(.centerSlot)) {
90 | grid-template-columns: 1fr;
91 | grid-template-areas: "c";
92 | }
93 |
94 | // 2-column layout for start + center
95 | &:has(.startSlot):has(.centerSlot):not(:has(.endSlot)) {
96 | grid-template-columns: 1fr 1fr;
97 | grid-template-areas: "a b";
98 | }
99 |
100 | // 2-column layout for center + end
101 | &:has(.centerSlot):has(.endSlot):not(:has(.startSlot)) {
102 | grid-template-columns: 1fr 1fr;
103 | grid-template-areas: "b c";
104 | }
105 | }
106 | }
107 |
108 | .slot {
109 | display: flex;
110 | flex-direction: row;
111 | align-items: center;
112 | gap: t.$space-6;
113 | flex-direction: row;
114 |
115 | .paginationVertical & {
116 | flex-direction: column;
117 | }
118 | }
119 |
120 | .startSlot {
121 | grid-area: a;
122 | justify-self: start;
123 |
124 | .paginationVertical & {
125 | justify-self: stretch;
126 | }
127 | }
128 |
129 | .centerSlot {
130 | grid-area: b;
131 | justify-self: center;
132 |
133 | .paginationVertical & {
134 | justify-self: stretch;
135 | }
136 | }
137 |
138 | .endSlot {
139 | grid-area: c;
140 | justify-self: end;
141 |
142 | .paginationVertical & {
143 | justify-self: stretch;
144 | }
145 | }
146 |
147 | .selectorContainer {
148 | display: flex;
149 | flex-direction: row;
150 | align-items: center;
151 | gap: t.$space-2;
152 | }
153 |
154 | .pageSizeLabel {
155 | color: $textColor-selector-Pagination;
156 | font-size: t.$fontSize-sm;
157 | }
158 |
159 | .pageSizeSelect {
160 | color: $textColor-selector-Pagination;
161 | background-color: $backgroundColor-selector-Pagination;
162 | border: 1px solid $borderColor-Pagination;
163 | border-radius: $borderRadius-selector-Pagination;
164 | padding: t.$space-1 t.$space-2;
165 | font-size: t.$fontSize-sm;
166 |
167 | .paginationVertical & {
168 | align-self: center;
169 | }
170 |
171 | &:focus {
172 | //outline: 2px solid t.$color-primary-400;
173 | outline-offset: 2px;
174 | }
175 |
176 | &:not([disabled]):hover {
177 | cursor: pointer;
178 | }
179 |
180 | &:disabled {
181 | opacity: 0.5;
182 | cursor: not-allowed;
183 | }
184 | }
185 |
186 | .buttonRow {
187 | list-style: none;
188 | padding: 0;
189 | display: flex;
190 | flex-direction: row;
191 | align-items: center;
192 | gap: createThemeVar("gap-buttonRow-Pagination");
193 |
194 | li {
195 | margin: 0;
196 | }
197 |
198 | &.paginationListVertical {
199 | flex-direction: column;
200 | }
201 | }
202 | }
203 |
204 | // --- We export the theme variables to add them to the component renderer
205 | :export {
206 | themeVars: t.json-stringify($themeVars);
207 | }
208 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Charts/BarChart/BarChart.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { BarChart, defaultProps } from "./BarChartNative";
2 | import { createComponentRenderer } from "../../../components-core/renderers";
3 | import { createMetadata } from "../../metadata-helpers";
4 | import { MemoizedItem } from "../../container-helpers";
5 |
6 | const COMP = "BarChart";
7 |
8 | export const BarChartMd = createMetadata({
9 | status: "experimental",
10 | description:
11 | "`BarChart` displays data as horizontal or vertical bars, supporting both grouped " +
12 | "and stacked layouts. It's ideal for comparing values across categories, showing " +
13 | "revenue trends, or displaying any quantitative data over time or categories.",
14 | docFolder: "Charts/BarChart",
15 | props: {
16 | data: {
17 | description:
18 | `This property is used to provide the component with data to display.` +
19 | `The data needs to be an array of objects.`,
20 | },
21 | yKeys: {
22 | description:
23 | "Specifies the key in the data objects that will be used to label the different data series.",
24 | valueType: "string",
25 | },
26 | stacked: {
27 | description:
28 | `This property determines how the bars are laid out.` +
29 | `If set to \`true\`, bars with the same category will be stacked on top of each other rather than placed side by side.`,
30 | valueType: "boolean",
31 | defaultValue: defaultProps.stacked,
32 | },
33 | orientation: {
34 | description:
35 | `This property determines the orientation of the bar chart. The \`vertical\` variant ` +
36 | `specifies the horizontal axis as the primary and lays out the bars from left to right. ` +
37 | `The \`horizontal\` variant specifies the vertical axis as the primary and has the bars ` +
38 | `spread from top to bottom.`,
39 | valueType: "string",
40 | availableValues: ["horizontal", "vertical"],
41 | defaultValue: defaultProps.layout,
42 | },
43 | xKey: {
44 | description:
45 | "This property specifies the keys in the data objects that should be used for rendering the bars." +
46 | `E.g. 'id' or 'key'.`,
47 | valueType: "string",
48 | },
49 | hideX: {
50 | description:
51 | "Determines whether the X-axis should be hidden. If set to `true`, the axis will not be rendered.",
52 | valueType: "boolean",
53 | defaultValue: defaultProps.hideX,
54 | },
55 | hideY: {
56 | description:
57 | "Determines whether the Y-axis should be hidden. If set to `true`, the axis will not be rendered.",
58 | valueType: "boolean",
59 | defaultValue: defaultProps.hideY,
60 | },
61 | hideTickX: {
62 | description:
63 | "Controls the visibility of the X-axis ticks. If set to `true`, tick labels on the X-axis will be hidden.",
64 | valueType: "boolean",
65 | defaultValue: defaultProps.hideTickX,
66 | },
67 | hideTickY: {
68 | description:
69 | "Controls the visibility of the Y-axis ticks. If set to `true`, tick labels on the Y-axis will be hidden.",
70 | valueType: "boolean",
71 | defaultValue: defaultProps.hideTickY,
72 | },
73 | tickFormatterX: {
74 | description: "A function that formats the tick labels on the X-axis. ",
75 | defaultValue: JSON.stringify(defaultProps.tickFormatterX),
76 | },
77 | tickFormatterY: {
78 | description: "A function that formats the tick labels on the Y-axis. ",
79 | defaultValue: JSON.stringify(defaultProps.tickFormatterY),
80 | },
81 | hideTooltip: {
82 | description: "Determines whether the tooltip should be hidden. If set to `true`, tooltips will not appear on hover.",
83 | valueType: "boolean",
84 | defaultValue: defaultProps.hideTooltip,
85 | },
86 | showLegend: {
87 | description: "Determines whether the legend should be displayed.",
88 | valueType: "boolean",
89 | defaultValue: defaultProps.showLegend,
90 | },
91 | tooltipTemplate: {
92 | description: "This property allows replacing the default template to display a tooltip.",
93 | },
94 | },
95 | });
96 |
97 | export const barChartComponentRenderer = createComponentRenderer(
98 | COMP,
99 | BarChartMd,
100 | ({ extractValue, node, className, lookupSyncCallback, renderChild }: any) => {
101 | return (
102 | <BarChart
103 | className={className}
104 | tickFormatterX={lookupSyncCallback(node.props?.tickFormatterX)}
105 | tickFormatterY={lookupSyncCallback(node.props?.tickFormatterY)}
106 | data={extractValue(node.props?.data)}
107 | layout={extractValue(node.props?.orientation)}
108 | nameKey={extractValue(node.props?.xKey)}
109 | dataKeys={extractValue(node.props?.yKeys)}
110 | stacked={extractValue.asOptionalBoolean(node.props?.stacked)}
111 | hideX={extractValue.asOptionalBoolean(node.props?.hideX)}
112 | hideY={extractValue.asOptionalBoolean(node.props?.hideY)}
113 | hideTickX={extractValue.asOptionalBoolean(node.props?.hideTickX)}
114 | hideTickY={extractValue.asOptionalBoolean(node.props?.hideTickY)}
115 | hideTooltip={extractValue.asOptionalBoolean(node.props?.hideTooltip)}
116 | showLegend={extractValue.asOptionalBoolean(node.props?.showLegend)}
117 | tooltipRenderer={
118 | node.props.tooltipTemplate
119 | ? (tooltipData) => {
120 | return (
121 | <MemoizedItem
122 | node={node.props.tooltipTemplate}
123 | item={tooltipData}
124 | contextVars={{
125 | $tooltip: tooltipData,
126 | }}
127 | renderChild={renderChild}
128 | />
129 | );
130 | }
131 | : undefined
132 | }
133 | >
134 | {renderChild(node.children)}
135 | </BarChart>
136 | );
137 | },
138 | );
139 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/TextArea/TextArea.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import styles from "./TextArea.module.scss";
2 |
3 | import { type PropertyValueDescription } from "../../abstractions/ComponentDefs";
4 | import { createComponentRenderer } from "../../components-core/renderers";
5 | import { parseScssVar } from "../../components-core/theming/themeVars";
6 | import {
7 | createMetadata,
8 | d,
9 | dAutoFocus,
10 | dDidChange,
11 | dEnabled,
12 | dGotFocus,
13 | dInitialValue,
14 | dLostFocus,
15 | dMaxLength,
16 | dPlaceholder,
17 | dReadonly,
18 | dRequired,
19 | dSetValueApi,
20 | dValidationStatus,
21 | } from "../metadata-helpers";
22 | import { type ResizeOptions, TextArea, defaultProps } from "./TextAreaNative";
23 |
24 | const COMP = "TextArea";
25 |
26 | export const resizeOptionsMd: PropertyValueDescription[] = [
27 | { value: "(undefined)", description: "No resizing" },
28 | { value: "horizontal", description: "Can only resize horizontally" },
29 | { value: "vertical", description: "Can only resize vertically" },
30 | { value: "both", description: "Can resize in both dimensions" },
31 | ];
32 |
33 | export const TextAreaMd = createMetadata({
34 | status: "stable",
35 | description: "`TextArea` provides a multiline text input area.",
36 | parts: {
37 | label: {
38 | description: "The label displayed for the text area.",
39 | },
40 | startAdornment: {
41 | description: "The adornment displayed at the start of the text area.",
42 | },
43 | endAdornment: {
44 | description: "The adornment displayed at the end of the text area.",
45 | },
46 | input: {
47 | description: "The text area input.",
48 | },
49 | },
50 | props: {
51 | enterSubmits: {
52 | description:
53 | "This optional boolean property indicates whether pressing the \`Enter\` key on the " +
54 | "keyboard prompts the parent \`Form\` component to submit.",
55 | valueType: "boolean",
56 | defaultValue: defaultProps.enterSubmits,
57 | },
58 | escResets: {
59 | description:
60 | `This boolean property indicates whether the ${COMP} contents should be reset when pressing ` +
61 | `the ESC key.`,
62 | valueType: "boolean",
63 | defaultValue: false,
64 | },
65 | maxRows: d(
66 | `This optional property sets the maximum number of text rows the \`${COMP}\` ` +
67 | "can grow. If not set, the number of rows is unlimited.",
68 | ),
69 | minRows: d(
70 | `This optional property sets the minimum number of text rows the \`${COMP}\` can shrink. ` +
71 | `If not set, the minimum number of rows is 1.`,
72 | ),
73 | rows: {
74 | description: `Specifies the number of rows the component initially has.`,
75 | valueType: "number",
76 | defaultValue: defaultProps.rows,
77 | },
78 | autoSize: {
79 | description:
80 | `If set to \`true\`, this boolean property enables the \`${COMP}\` to resize ` +
81 | `automatically based on the number of lines inside it.`,
82 | valueType: "boolean",
83 | defaultValue: false,
84 | },
85 | placeholder: dPlaceholder(),
86 | initialValue: dInitialValue(),
87 | maxLength: dMaxLength(),
88 | autoFocus: dAutoFocus(),
89 | required: dRequired(),
90 | readOnly: dReadonly(),
91 | enabled: dEnabled(),
92 | validationStatus: dValidationStatus(),
93 | resize: {
94 | description:
95 | `This optional property specifies in which dimensions can the \`TextArea\` ` +
96 | `be resized by the user.`,
97 | availableValues: resizeOptionsMd,
98 | },
99 | },
100 | events: {
101 | gotFocus: dGotFocus(COMP),
102 | lostFocus: dLostFocus(COMP),
103 | didChange: dDidChange(COMP),
104 | },
105 | apis: {
106 | focus: {
107 | description: `This method sets the focus on the \`${COMP}\` component.`,
108 | signature: "focus(): void",
109 | },
110 | value: {
111 | description: `You can query the component's value. If no value is set, it will retrieve \`undefined\`.`,
112 | signature: "get value(): string | undefined",
113 | },
114 | setValue: dSetValueApi(),
115 | },
116 | themeVars: parseScssVar(styles.themeVars),
117 | defaultThemeVars: {
118 | [`paddingVertical-${COMP}`]: "$space-2",
119 | [`paddingHorizontal-${COMP}`]: "$space-2",
120 | },
121 | });
122 |
123 | export const textAreaComponentRenderer = createComponentRenderer(
124 | COMP,
125 | TextAreaMd,
126 | ({
127 | node,
128 | extractValue,
129 | state,
130 | updateState,
131 | className,
132 | registerComponentApi,
133 | lookupEventHandler,
134 | }) => {
135 | return (
136 | <TextArea
137 | value={state?.value}
138 | initialValue={extractValue(node.props.initialValue)}
139 | updateState={updateState}
140 | autoFocus={extractValue.asOptionalBoolean(node.props.autoFocus)}
141 | enabled={extractValue.asOptionalBoolean(node.props.enabled)}
142 | placeholder={extractValue(node.props.placeholder)}
143 | onDidChange={lookupEventHandler("didChange")}
144 | onFocus={lookupEventHandler("gotFocus")}
145 | onBlur={lookupEventHandler("lostFocus")}
146 | readOnly={extractValue.asOptionalBoolean(node.props.readOnly)}
147 | resize={node.props.resize as ResizeOptions}
148 | enterSubmits={extractValue.asOptionalBoolean(node.props.enterSubmits)}
149 | escResets={extractValue.asOptionalBoolean(node.props.escResets)}
150 | className={className}
151 | registerComponentApi={registerComponentApi}
152 | maxRows={extractValue.asOptionalNumber(node.props.maxRows)}
153 | minRows={extractValue.asOptionalNumber(node.props.minRows)}
154 | maxLength={extractValue.asOptionalNumber(node.props.maxLength)}
155 | rows={extractValue.asOptionalNumber(node.props.rows)}
156 | autoSize={extractValue.asOptionalBoolean(node.props.autoSize)}
157 | validationStatus={extractValue(node.props.validationStatus)}
158 | required={extractValue.asOptionalBoolean(node.props.required)}
159 | />
160 | );
161 | },
162 | );
163 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/CodeBlock/CodeBlockNative.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import type React from "react";
2 | import styles from "./CodeBlock.module.scss";
3 | import { Text } from "../Text/TextNative";
4 | import {
5 | type CodeHighlighterMeta,
6 | CodeHighlighterMetaKeys,
7 | encodeToBase64,
8 | } from "./highlight-code";
9 | import { Button } from "../Button/ButtonNative";
10 | import Icon from "../Icon/IconNative";
11 | import toast from "react-hot-toast";
12 | import { visit } from "unist-util-visit";
13 | import type { Node, Parent } from "unist";
14 | import type { CSSProperties } from "react";
15 | import classnames from "classnames";
16 |
17 | type CodeBlockProps = {
18 | children?: React.ReactNode;
19 | textToCopy?: string;
20 | meta?: CodeHighlighterMeta;
21 | style?: CSSProperties;
22 | className?: string;
23 | };
24 |
25 | export const defaultProps = {
26 | // No default props needed for this component currently
27 | };
28 |
29 | export function CodeBlock({
30 | children,
31 | meta,
32 | textToCopy,
33 | style,
34 | className,
35 | ...rest
36 | }: CodeBlockProps) {
37 | // 'global-codeBlock' class is there so we could apply styles if this codeblock is used inside a splitView nested app
38 | if (!meta) {
39 | return (
40 | <div
41 | {...rest}
42 | className={classnames(className, styles.codeBlock, "global-codeBlock")}
43 | style={style}
44 | >
45 | <div className={styles.codeBlockContent}>{children}</div>
46 | </div>
47 | );
48 | }
49 | return (
50 | <div className={classnames(styles.codeBlock, "global-codeBlock")} style={style}>
51 | {meta.filename && (
52 | <div className={styles.codeBlockHeader}>
53 | <Text variant="em">{meta.filename}</Text>
54 | </div>
55 | )}
56 | <div className={styles.codeBlockContent}>
57 | {children}
58 | {meta.copy !== false && (
59 | <div className={styles.codeBlockCopyButton}>
60 | <Button
61 | variant="ghost"
62 | size="xs"
63 | className={styles.copyButton}
64 | icon={<Icon name={"copy"} aria-hidden />}
65 | onClick={() => {
66 | if (!textToCopy) return;
67 | void navigator.clipboard.writeText(textToCopy);
68 | toast.success("Code copied!");
69 | }}
70 | ></Button>
71 | </div>
72 | )}
73 | </div>
74 | </div>
75 | );
76 | }
77 |
78 | interface CodeNode extends Node {
79 | lang: string | null;
80 | meta: string | null;
81 | }
82 |
83 | export function markdownCodeBlockParser() {
84 | return function transformer(tree: Node) {
85 | visit(tree, "code", visitor);
86 | };
87 |
88 | /**
89 | * This visitor visits each node in the mdast tree and adds all meta information to the code block html element
90 | * that we use later in the Markdown component.
91 | */
92 | function visitor(node: CodeNode, _: number, parent: Parent | undefined) {
93 | const { lang, meta } = node;
94 | const nodeData = { hProperties: {} };
95 | if (lang !== null) {
96 | nodeData.hProperties["dataLanguage"] = lang;
97 | node.data = nodeData;
98 | }
99 | if (!parent) return;
100 | if (!meta) return;
101 |
102 | const params = splitter(meta)
103 | ?.filter((s) => s !== "")
104 | .map((s) => s.trim());
105 | if (!params) return;
106 | if (params.length === 0) return;
107 |
108 | const parsedMeta = params.reduce(
109 | (acc, item) => {
110 | item = item.trim();
111 | if (item === "") return acc;
112 |
113 | if (item.toLocaleLowerCase().startsWith("filename=")) {
114 | const index = item.indexOf("=");
115 | acc[CodeHighlighterMetaKeys.filename.data] = item
116 | .substring(index + 1)
117 | .replace(/"(.+)"/, "$1")
118 | .replace(/'(.+)'/, "$1");
119 | }
120 | if (item.startsWith("/") && item.endsWith("/")) {
121 | const unparsedSubstrings = acc[CodeHighlighterMetaKeys.highlightSubstrings.data];
122 | const newItemBase64 = encodeToBase64(item.substring(1, item.length - 1));
123 |
124 | if (!unparsedSubstrings) {
125 | acc[CodeHighlighterMetaKeys.highlightSubstrings.data] = newItemBase64;
126 | } else {
127 | acc[CodeHighlighterMetaKeys.highlightSubstrings.data] =
128 | `${unparsedSubstrings} ${newItemBase64}`;
129 | }
130 | }
131 | if (item.startsWith("!/") && item.endsWith("/")) {
132 | const unparsedSubstrings =
133 | acc[CodeHighlighterMetaKeys.highlightSubstringsEmphasized.data];
134 | const newItemBase64 = encodeToBase64(item.substring(2, item.length - 1));
135 |
136 | if (!unparsedSubstrings) {
137 | acc[CodeHighlighterMetaKeys.highlightSubstringsEmphasized.data] = newItemBase64;
138 | } else {
139 | acc[CodeHighlighterMetaKeys.highlightSubstringsEmphasized.data] =
140 | `${unparsedSubstrings} ${newItemBase64}`;
141 | }
142 | }
143 | if (item.startsWith("{") && item.endsWith("}")) {
144 | const unparsedRows = acc[CodeHighlighterMetaKeys.highlightRows.data];
145 | const newItem = item.substring(1, item.length - 1);
146 |
147 | if (!unparsedRows) {
148 | acc[CodeHighlighterMetaKeys.highlightRows.data] = newItem;
149 | } else {
150 | acc[CodeHighlighterMetaKeys.highlightRows.data] = `${unparsedRows}, ${newItem}`;
151 | }
152 | }
153 | if (item === "copy") {
154 | acc[CodeHighlighterMetaKeys.copy.data] = "true";
155 | }
156 | if (item === "rowNumbers") {
157 | acc[CodeHighlighterMetaKeys.rowNumbers.data] = "true";
158 | }
159 | return acc;
160 | },
161 | {} as Record<string, string>,
162 | );
163 | nodeData.hProperties = { ...nodeData.hProperties, ...parsedMeta };
164 | node.data = nodeData;
165 | }
166 |
167 | function splitter(str: string): string[] | null {
168 | return str.match(/(?:("|')[^"']*\1|\{[^{}]*\}|\/.*?\/|[^\s"'{}/])+/g);
169 | }
170 | }
171 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/AppState/AppState.md:
--------------------------------------------------------------------------------
```markdown
1 | %-DESC-START
2 |
3 | **Key advantages over variables:**
4 | - **Global accessibility**: Any component can access the state by referencing the same `bucket`
5 | - **Automatic reactivity**: UI updates automatically when state changes, no manual prop passing required
6 | - **Cross-component coordination**: Perfect for user sessions, UI preferences, loading states, and shared data
7 |
8 | ## Using AppState
9 |
10 | Variables in xmlui are a straightforward tool for managing states. However, a variable's scope is the app's main file or the particular component file in which it is declared. To access the variable's value (the stored state), you must pass its value to components wanting to leverage it.
11 |
12 | ### Storing State in Variables
13 |
14 | In the following example, the main file of the app declares a variable, `enhancedMode`, which is toggled with a checkbox:
15 |
16 | ```xmlui-pg
17 | ---app copy display filename="Main.xmlui"
18 | <App var.enhancedMode="{false}">
19 | <VStack gap="$space-4" padding="$space-4">
20 | <Checkbox
21 | label="Enhanced mode"
22 | initialValue="{enhancedMode}"
23 | onDidChange="v => enhancedMode = v" />
24 | <Component1 enhancedMode="{enhancedMode}" />
25 | <Component2 enhancedMode="{enhancedMode}" />
26 | </VStack>
27 | </App>
28 | ---desc
29 | Two components, `Component1` and `Component2`, use the value of `enhancedMode`. Because of the aforementioned scoping issue, the app must explicitly pass the variable's value to those components so that they can use it. These components utilize the value to render their UI:
30 | ---comp copy display filename="Component1.xmlui"
31 | <Component name="Component1">
32 | <H3 when="{$props.enhancedMode}">I am in enhanced mode!</H3>
33 | <Text when="{!$props.enhancedMode}">Enhanced mode turned off.</Text>
34 | </Component>
35 | ---desc
36 | When you define an `AppState`, you can set its `initialValue` property to initialize the state value.
37 | ---comp copy display filename="Component2.xmlui"
38 | <Component name="Component2">
39 | <Button enabled="{$props.enhancedMode}">Set enhanced options</Button>
40 | </Component>
41 | ---desc
42 | You can try how this app works:
43 | ```
44 |
45 | ### Storing State in AppState
46 |
47 | What if `Component1` and `Component2` had nested components using `enhancedMode`? You must also pass them to the nested components (via properties). What if you have not only one but a dozen of similar properties and a long chain of nested components? The "use a variable" pattern soon becomes a state management nightmare.
48 |
49 | If the nested components want to change the state value, you must declare events and event handlers or component APIs to manage the state. It sounds pretty tedious!
50 |
51 | This situation is where `AppState` comes into the picture. With an `AppState` instance, you can define a state object that automatically conveys between parent and nested child component chains implicitly.
52 |
53 | Let's turn the previous example into one using `AppState`! The following code shows how we change the main app file:
54 |
55 | ```xmlui-pg
56 | ---app copy display filename="Main.xmlui"
57 | <App>
58 | <AppState id="appState" initialValue="{{ enhancedMode: false }}"/>
59 | <VStack gap="$space-4" padding="$space-4">
60 | <Checkbox
61 | label="Enhanced mode"
62 | initialValue="{appState.value.enhancedMode}"
63 | onDidChange="v => appState.update({ enhancedMode: v})" />
64 | <Component1 />
65 | <Component2 />
66 | </VStack>
67 | </App>
68 | ---desc
69 | When you define an `AppState`, you can set its `initialValue` property to initialize the state value. You must give an ID to the `AppState` instance to access it and use the `value` property to get the state. You must invoke the `AppState`'s `update` method when you intend to update the state.
70 |
71 | The components may use their own `AppState` object to access the state value:
72 | ---comp copy display filename="Component1.xmlui"
73 | <Component name="Component1">
74 | <AppState id="state" />
75 | <H3 when="{state.value.enhancedMode}">I am in enhanced mode!</H3>
76 | <Text when="{!state.value.enhancedMode}">Enhanced mode turned off.</Text>
77 | </Component>
78 | ---comp copy display filename="Component2.xmlui"
79 | <Component name="Component2">
80 | <AppState id="state" />
81 | <Button enabled="{state.value.enhancedMode}">Set enhanced options</Button>
82 | </Component>
83 | ---desc
84 | The modified app works the same way as the previous one (using variables):
85 | ```
86 |
87 | ### State Buckets
88 |
89 | With the `AppState` component, you can use separate state objects. The `bucket` property of `AppState` is an identifier (using the "default" string by default). While multiple `AppState` objects use the same `bucket` property value, they refer to the same state object.
90 |
91 | If you want to run the sample with explicit state buckets (for example, with the `settings` bucket id), you should change the `AppState` declarations accordingly:
92 |
93 | ```xmlui /bucket="settings"/
94 | <!-- Main.xmlui -->
95 | <AppState id="appState" bucket="settings" initialValue="{{ enhancedMode: false }}"/>
96 |
97 | <!-- Component1 -->
98 | <AppState id="state" bucket="settings" />
99 |
100 | <!-- Component2 -->
101 | <AppState id="state" bucket="settings" />
102 | ```
103 |
104 | %-DESC-END
105 |
106 | %-API-START update
107 |
108 | If the argument is a hash object, it will be merged with the previous state value. Let's assume the previous state value was the following:
109 |
110 | ```json
111 | {
112 | "enhancedMode": false,
113 | "showHeader": true,
114 | "showFooter": true,
115 | "theme": "light"
116 | }
117 | ```
118 |
119 | Now, update the state with this call:
120 |
121 | ```js
122 | appState.update({ enhancedMode: true, theme: "dark" });
123 | ```
124 |
125 | The new state value will be:
126 |
127 | ```json
128 | {
129 | "enhancedMode": true,
130 | "showHeader": true,
131 | "showFooter": true,
132 | "theme": "dark"
133 | }
134 | ```
135 |
136 | %-API-END
137 |
```
--------------------------------------------------------------------------------
/xmlui/src/parsers/xmlui-parser/diagnostics.ts:
--------------------------------------------------------------------------------
```typescript
1 | export interface GeneralDiagnosticMessage {
2 | code: ErrCodes;
3 | category: DiagnosticCategory;
4 | message: string;
5 | }
6 |
7 | export enum DiagnosticCategory {
8 | Error = 1,
9 | Warning = 2,
10 | Information = 3,
11 | Hint = 4,
12 | }
13 |
14 | export enum ErrCodes {
15 | onlyOneElem = "U002",
16 | expTagOpen = "U003",
17 | expTagName = "U004",
18 | expCloseStart = "U005",
19 | expEndOrClose = "U006",
20 | tagNameMismatch = "U007",
21 | expEnd = "U008",
22 | expAttrName = "U009",
23 | expEq = "U010",
24 | expAttrValue = "U011",
25 | duplAttr = "U012",
26 | uppercaseAttr = "U013",
27 | expTagNameAfterNamespace = "U014",
28 | expCloseStartWithName = "U015",
29 | expAttrNameAfterNamespace = "U016",
30 | unexpectedCloseTag = "U017",
31 | expTagNameAfterCloseStart = "U019",
32 | expAttrNameBeforeEq = "U020",
33 | invalidChar = "W001",
34 | untermStr = "W002",
35 | untermComment = "W007",
36 | untermCData = "W008",
37 | untermScript = "W009",
38 | }
39 |
40 | export const DIAGS = {
41 | unexpectedCloseTag: {
42 | category: DiagnosticCategory.Error,
43 | code: ErrCodes.unexpectedCloseTag,
44 | message: "Read '</', but there's no opening tag to close.",
45 | },
46 | expCloseStartWithName: function (openTagName: string) {
47 | return {
48 | category: DiagnosticCategory.Error,
49 | code: ErrCodes.expCloseStartWithName,
50 | message: `Opened tag has no closing pair. Expected to see '</${openTagName}>'.`,
51 | };
52 | },
53 | expCloseStart: {
54 | category: DiagnosticCategory.Error,
55 | code: ErrCodes.expCloseStart,
56 | message: "A '</' token expected.",
57 | },
58 | uppercaseAttr: function (attrName: string) {
59 | return {
60 | category: DiagnosticCategory.Error,
61 | code: ErrCodes.uppercaseAttr,
62 | message: `Attribute name '${attrName}' cannot start with an uppercase letter.`,
63 | };
64 | },
65 | duplAttr: function (attrName: string) {
66 | return {
67 | category: DiagnosticCategory.Error,
68 | code: ErrCodes.duplAttr,
69 | message: `Duplicated attribute: '${attrName}'.`,
70 | };
71 | },
72 | tagNameMismatch: function (openTagName: string, closeTagName: string) {
73 | return {
74 | category: DiagnosticCategory.Error,
75 | code: ErrCodes.tagNameMismatch,
76 | message: `Opening and closing tag names should match. Opening tag has a name '${openTagName}', but the closing tag name is '${closeTagName}'.`,
77 | };
78 | },
79 | invalidChar: function (char: string) {
80 | return {
81 | category: DiagnosticCategory.Error,
82 | code: ErrCodes.invalidChar,
83 | message: `Invalid character '${char}'.`,
84 | };
85 | },
86 | expEnd: {
87 | category: DiagnosticCategory.Error,
88 | code: ErrCodes.expEnd,
89 | message: "A '>' token expected.",
90 | },
91 | expTagName: {
92 | category: DiagnosticCategory.Error,
93 | code: ErrCodes.expTagName,
94 | message: "A tag name expected.",
95 | },
96 | expAttrStr: {
97 | category: DiagnosticCategory.Error,
98 | code: ErrCodes.expAttrValue,
99 | message: `A string expected as an attribute value after '='.`,
100 | },
101 | expEq: {
102 | category: DiagnosticCategory.Error,
103 | code: ErrCodes.expEq,
104 | message: "An '=' token expected.",
105 | },
106 | expTagOpen: {
107 | category: DiagnosticCategory.Error,
108 | code: ErrCodes.expTagOpen,
109 | message: "A '<' token expected.",
110 | },
111 | expEndOrClose: {
112 | category: DiagnosticCategory.Error,
113 | code: ErrCodes.expEndOrClose,
114 | message: `A '>' or '/>' token expected.`,
115 | },
116 | expAttrName: {
117 | category: DiagnosticCategory.Error,
118 | code: ErrCodes.expAttrName,
119 | message: `An attribute name expected.`,
120 | },
121 | expAttrNameAfterNamespace: function (namespaceName: string) {
122 | return {
123 | category: DiagnosticCategory.Error,
124 | code: ErrCodes.expAttrNameAfterNamespace,
125 | message: `An attribute name expected after namespace '${namespaceName}'.`,
126 | };
127 | },
128 | expTagNameAfterNamespace: function (namespaceName: string) {
129 | return {
130 | category: DiagnosticCategory.Error,
131 | code: ErrCodes.expTagNameAfterNamespace,
132 | message: `A tag name expected after namespace '${namespaceName}'.`,
133 | };
134 | },
135 | expTagNameAfterCloseStart: {
136 | category: DiagnosticCategory.Error,
137 | code: ErrCodes.expTagNameAfterCloseStart,
138 | message: "Expected tag name after '</'.",
139 | },
140 | expAttrNameBeforeEq: {
141 | category: DiagnosticCategory.Error,
142 | code: ErrCodes.expAttrNameBeforeEq,
143 | message: "Expected attribute name before '='.",
144 | },
145 | } as const;
146 |
147 | export function diagnosticCategoryName(
148 | d: { category: DiagnosticCategory },
149 | lowerCase = true,
150 | ): string {
151 | const name = DiagnosticCategory[d.category];
152 | return lowerCase ? name.toLowerCase() : name;
153 | }
154 |
155 | export const Diag_Invalid_Character = {
156 | code: ErrCodes.invalidChar,
157 | category: DiagnosticCategory.Error,
158 | message: "Invalid character.",
159 | } as const;
160 |
161 | export const Diag_Unterminated_String_Literal = {
162 | code: ErrCodes.untermStr,
163 | category: DiagnosticCategory.Error,
164 | message: "Unterminated string literal.",
165 | } as const;
166 |
167 | export const Diag_Unterminated_Comment = {
168 | code: ErrCodes.untermComment,
169 | category: DiagnosticCategory.Error,
170 | message: "Unterminated comment",
171 | } as const;
172 |
173 | export const Diag_Unterminated_CData = {
174 | code: ErrCodes.untermCData,
175 | category: DiagnosticCategory.Error,
176 | message: "Unterminated CDATA section",
177 | } as const;
178 |
179 | export const Diag_Unterminated_Script = {
180 | code: ErrCodes.untermScript,
181 | category: DiagnosticCategory.Error,
182 | message: "Unterminated script section",
183 | } as const;
184 |
185 | export type ScannerDiagnosticMessage =
186 | | typeof Diag_Invalid_Character
187 | | typeof Diag_Unterminated_String_Literal
188 | | typeof Diag_Unterminated_Comment
189 | | typeof Diag_Unterminated_CData
190 | | typeof Diag_Unterminated_Script;
191 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/DataSource/DataSource.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { httpMethodNames } from "../abstractions";
2 | import { createMetadata, d } from "../metadata-helpers";
3 |
4 | // NOTE: Original component this is based on is the `Loader` component
5 |
6 | const COMP = "DataSource";
7 |
8 | export const DataSourceMd = createMetadata({
9 | status: "stable",
10 | description:
11 | "`DataSource` fetches and caches data from API endpoints, versus " +
12 | "[`APICall`](/components/APICall) which creates, updates or deletes data.",
13 | props: {
14 | method: {
15 | description: `Set the HTTP method.`,
16 | defaultValue: "get",
17 | availableValues: httpMethodNames,
18 | },
19 | id: {
20 | description:
21 | `Set the ID used by other components to access the retrieved data in the \`value\`` +
22 | "property of a \`DataSource\`, or status info in the \`loaded\` and \`error\` properties." +
23 | "When no `id` is set, the component cannot be used programmatically.",
24 | isRequired: true,
25 | valueType: "string",
26 | },
27 | url: {
28 | description: `Set the URL.`,
29 | isRequired: true,
30 | valueType: "string",
31 | },
32 | body: {
33 | description: `Set the optional request body. The object you pass is serialized as a JSON string.`,
34 | valueType: "any",
35 | },
36 | rawBody: {
37 | description:
38 | `Set the request body with no serialization. Use it to send a payload ` +
39 | `that has already been serialized to a JSON string.`,
40 | valueType: "string",
41 | },
42 | queryParams: {
43 | description: `Append optional key-value pairs to the URL.`,
44 | valueType: "any",
45 | },
46 | headers: {
47 | description: `Set request headers. Pass an object whose keys are header names and values are header values.`,
48 | valueType: "any",
49 | },
50 | pollIntervalInSeconds: {
51 | description:
52 | "Set the interval for periodic data fetching. If the data changes on refresh, " +
53 | "XMLUI will re-render components that refer directly or indirectly to the \`DataSource\`. " +
54 | "If not set or set to zero, the component does not poll for data.",
55 | valueType: "number",
56 | },
57 | inProgressNotificationMessage: {
58 | description:
59 | "Set the message to display when the data fetch is in progress. " +
60 | "If the property value is not set, no progress message is displayed.",
61 | valueType: "string",
62 | },
63 | completedNotificationMessage: {
64 | description:
65 | "Set the message to display when the data fetch completes." +
66 | "If the property value is not set, no completion message is displayed.",
67 | valueType: "string",
68 | },
69 | errorNotificationMessage: {
70 | description:
71 | "Set the message to display when the there is an error. " +
72 | "You can use the `$error` context value in an expression to " +
73 | "refer to the original error message.",
74 | valueType: "string",
75 | },
76 | resultSelector: {
77 | description:
78 | "Set an optional object key to extract a subset of the response data. If this " +
79 | "value is not set, the entire response body is considered the result.",
80 | valueType: "string",
81 | },
82 | transformResult: {
83 | description:
84 | "Set an optional function to perform a final transformation of the " +
85 | "response data. If this value is not set, the result is not transformed.",
86 | },
87 | prevPageSelector: {
88 | description:
89 | `When using \`${COMP}\` with paging, the response may contain information about the ` +
90 | `previous and next page. This property defines the selector that extracts the ` +
91 | `previous page information from the response deserialized to an object.`,
92 | },
93 | nextPageSelector: {
94 | description:
95 | `When using \`${COMP}\` with paging, the response may contain information about ` +
96 | `the previous and next page. This property defines the selector that extracts ` +
97 | `the next page information from the response deserialized to an object.`,
98 | },
99 | structuralSharing: {
100 | description:
101 | "This property allows structural sharing. When turned on, `DataSource` will keep " +
102 | "the original reference if nothing has changed in the data. If a subset has " +
103 | "changed, `DataSource` will keep the unchanged parts and only replace the changed " +
104 | "parts. If you do not need this behavior, set this property to `false`.",
105 | defaultValue: "true",
106 | },
107 | },
108 | events: {
109 | loaded: d(
110 | "The component triggers this event when the fetch operation has been completed " +
111 | "and the data is loaded. The event has two arguments. The first is the data " +
112 | "loaded; the second indicates if the event is a result of a refetch.",
113 | ),
114 | error: d(`This event fires when a request results in an error.`),
115 | },
116 | apis: {
117 | value: {
118 | description: `This property retrieves the data queried from the source after optional transformations.`,
119 | signature: "get value(): any",
120 | },
121 | inProgress: {
122 | description: "This property indicates if the data is being fetched.",
123 | signature: "get inProgress(): boolean",
124 | },
125 | isRefetching: {
126 | description: "This property indicates if the data is being re-fetched.",
127 | signature: "get isRefetching(): boolean",
128 | },
129 | loaded: {
130 | description: "This property indicates if the data has been loaded.",
131 | signature: "get loaded(): boolean",
132 | },
133 | refetch: {
134 | description: "This method requests the re-fetch of the data.",
135 | signature: "refetch(): void",
136 | },
137 | },
138 | });
139 |
```