This is page 44 of 186. Use http://codebase.md/xmlui-org/xmlui/xmlui-standalone.umd.js?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-optimized.yml
│ ├── deploy-blog-swa.yml
│ ├── deploy-blog.yml
│ ├── deploy-docs-optimized.yml
│ ├── deploy-docs.yml
│ ├── prepare-versions.yml
│ ├── release-packages.yml
│ ├── run-all-tests.yml
│ └── run-smoke-tests.yml
├── .gitignore
├── .prettierrc.js
├── .vscode
│ ├── launch.json
│ └── settings.json
├── blog
│ ├── .gitignore
│ ├── .gitkeep
│ ├── CHANGELOG.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── package.json
│ ├── public
│ │ ├── blog
│ │ │ ├── images
│ │ │ │ ├── an-advanced-codefence.gif
│ │ │ │ ├── an-advanced-codefence.mp4
│ │ │ │ ├── blog-page-component.png
│ │ │ │ ├── blog-scrabble.png
│ │ │ │ ├── codefence-runner.png
│ │ │ │ ├── integrated-blog-search.png
│ │ │ │ ├── lorem-ipsum.png
│ │ │ │ ├── playground-checkbox-source.png
│ │ │ │ ├── playground.png
│ │ │ │ ├── use-xmlui-mcp-to-find-a-howto.png
│ │ │ │ └── xmlui-demo-gallery.png
│ │ │ ├── introducing-xmlui.md
│ │ │ ├── lorem-ipsum.md
│ │ │ ├── newest-post.md
│ │ │ ├── older-post.md
│ │ │ ├── xmlui-playground.md
│ │ │ └── xmlui-powered-blog.md
│ │ ├── mockServiceWorker.js
│ │ ├── resources
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ └── for-download
│ │ │ │ └── xmlui
│ │ │ │ └── xmlui-standalone.umd.js
│ │ │ ├── github.svg
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ ├── rss.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ ├── staticwebapp.config.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ └── PageNotFound.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── blog-theme.ts
│ └── tsconfig.json
├── CONTRIBUTING.md
├── docs
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── ComponentRefLinks.txt
│ ├── content
│ │ ├── _meta.json
│ │ ├── components
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── APICall.md
│ │ │ ├── App.md
│ │ │ ├── AppHeader.md
│ │ │ ├── AppState.md
│ │ │ ├── AutoComplete.md
│ │ │ ├── Avatar.md
│ │ │ ├── Backdrop.md
│ │ │ ├── Badge.md
│ │ │ ├── BarChart.md
│ │ │ ├── Bookmark.md
│ │ │ ├── Breakout.md
│ │ │ ├── Button.md
│ │ │ ├── Card.md
│ │ │ ├── Carousel.md
│ │ │ ├── ChangeListener.md
│ │ │ ├── Checkbox.md
│ │ │ ├── CHStack.md
│ │ │ ├── ColorPicker.md
│ │ │ ├── Column.md
│ │ │ ├── ContentSeparator.md
│ │ │ ├── CVStack.md
│ │ │ ├── DataSource.md
│ │ │ ├── DateInput.md
│ │ │ ├── DatePicker.md
│ │ │ ├── DonutChart.md
│ │ │ ├── DropdownMenu.md
│ │ │ ├── EmojiSelector.md
│ │ │ ├── ExpandableItem.md
│ │ │ ├── FileInput.md
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FlowLayout.md
│ │ │ ├── Footer.md
│ │ │ ├── Form.md
│ │ │ ├── FormItem.md
│ │ │ ├── FormSection.md
│ │ │ ├── Fragment.md
│ │ │ ├── H1.md
│ │ │ ├── H2.md
│ │ │ ├── H3.md
│ │ │ ├── H4.md
│ │ │ ├── H5.md
│ │ │ ├── H6.md
│ │ │ ├── Heading.md
│ │ │ ├── HSplitter.md
│ │ │ ├── HStack.md
│ │ │ ├── Icon.md
│ │ │ ├── IFrame.md
│ │ │ ├── Image.md
│ │ │ ├── Items.md
│ │ │ ├── LabelList.md
│ │ │ ├── Legend.md
│ │ │ ├── LineChart.md
│ │ │ ├── Link.md
│ │ │ ├── List.md
│ │ │ ├── Logo.md
│ │ │ ├── Markdown.md
│ │ │ ├── MenuItem.md
│ │ │ ├── MenuSeparator.md
│ │ │ ├── ModalDialog.md
│ │ │ ├── NavGroup.md
│ │ │ ├── NavLink.md
│ │ │ ├── NavPanel.md
│ │ │ ├── NoResult.md
│ │ │ ├── NumberBox.md
│ │ │ ├── Option.md
│ │ │ ├── Page.md
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── Pages.md
│ │ │ ├── Pagination.md
│ │ │ ├── PasswordInput.md
│ │ │ ├── PieChart.md
│ │ │ ├── ProgressBar.md
│ │ │ ├── Queue.md
│ │ │ ├── RadioGroup.md
│ │ │ ├── RealTimeAdapter.md
│ │ │ ├── Redirect.md
│ │ │ ├── Select.md
│ │ │ ├── Slider.md
│ │ │ ├── Slot.md
│ │ │ ├── SpaceFiller.md
│ │ │ ├── Spinner.md
│ │ │ ├── Splitter.md
│ │ │ ├── Stack.md
│ │ │ ├── StickyBox.md
│ │ │ ├── SubMenuItem.md
│ │ │ ├── Switch.md
│ │ │ ├── TabItem.md
│ │ │ ├── Table.md
│ │ │ ├── TableOfContents.md
│ │ │ ├── Tabs.md
│ │ │ ├── Text.md
│ │ │ ├── TextArea.md
│ │ │ ├── TextBox.md
│ │ │ ├── Theme.md
│ │ │ ├── TimeInput.md
│ │ │ ├── Timer.md
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneSwitch.md
│ │ │ ├── Tooltip.md
│ │ │ ├── Tree.md
│ │ │ ├── VSplitter.md
│ │ │ ├── VStack.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ ├── xmlui-spreadsheet
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Spreadsheet.md
│ │ │ └── xmlui-website-blocks
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Carousel.md
│ │ │ ├── HelloMd.md
│ │ │ ├── HeroSection.md
│ │ │ └── ScrollToTop.md
│ │ └── extensions
│ │ ├── _meta.json
│ │ ├── xmlui-animations
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ ├── Animation.md
│ │ │ ├── FadeAnimation.md
│ │ │ ├── FadeInAnimation.md
│ │ │ ├── FadeOutAnimation.md
│ │ │ ├── ScaleAnimation.md
│ │ │ └── SlideInAnimation.md
│ │ └── xmlui-website-blocks
│ │ ├── _meta.json
│ │ ├── _overview.md
│ │ ├── Carousel.md
│ │ ├── FancyButton.md
│ │ ├── HeroSection.md
│ │ └── ScrollToTop.md
│ ├── extensions.ts
│ ├── index.html
│ ├── index.ts
│ ├── package.json
│ ├── public
│ │ ├── feed.rss
│ │ ├── mockServiceWorker.js
│ │ ├── pages
│ │ │ ├── _meta.json
│ │ │ ├── app-structure.md
│ │ │ ├── build-editor-component.md
│ │ │ ├── build-hello-world-component.md
│ │ │ ├── components-intro.md
│ │ │ ├── context-variables.md
│ │ │ ├── forms.md
│ │ │ ├── globals.md
│ │ │ ├── glossary.md
│ │ │ ├── helper-tags.md
│ │ │ ├── hosted-deployment.md
│ │ │ ├── howto
│ │ │ │ ├── assign-a-complex-json-literal-to-a-component-variable.md
│ │ │ │ ├── chain-a-refetch.md
│ │ │ │ ├── control-cache-invalidation.md
│ │ │ │ ├── debounce-user-input-for-api-calls.md
│ │ │ │ ├── debounce-with-changelistener.md
│ │ │ │ ├── debug-a-component.md
│ │ │ │ ├── delay-a-datasource-until-another-datasource-is-ready.md
│ │ │ │ ├── delegate-a-method.md
│ │ │ │ ├── do-custom-form-validation.md
│ │ │ │ ├── expose-a-method-from-a-component.md
│ │ │ │ ├── filter-and-transform-data-from-an-api.md
│ │ │ │ ├── group-items-in-list-by-a-property.md
│ │ │ │ ├── handle-background-operations.md
│ │ │ │ ├── hide-an-element-until-its-datasource-is-ready.md
│ │ │ │ ├── make-a-set-of-equal-width-cards.md
│ │ │ │ ├── make-a-table-responsive.md
│ │ │ │ ├── make-navpanel-width-responsive.md
│ │ │ │ ├── modify-a-value-reported-in-a-column.md
│ │ │ │ ├── paginate-a-list.md
│ │ │ │ ├── pass-data-to-a-modal-dialog.md
│ │ │ │ ├── react-to-button-click-not-keystrokes.md
│ │ │ │ ├── set-the-initial-value-of-a-select-from-fetched-data.md
│ │ │ │ ├── share-a-modaldialog-across-components.md
│ │ │ │ ├── sync-selections-between-table-and-list-views.md
│ │ │ │ ├── update-ui-optimistically.md
│ │ │ │ ├── use-built-in-form-validation.md
│ │ │ │ └── use-the-same-modaldialog-to-add-or-edit.md
│ │ │ ├── howto.md
│ │ │ ├── intro.md
│ │ │ ├── layout.md
│ │ │ ├── markup.md
│ │ │ ├── mcp.md
│ │ │ ├── modal-dialogs.md
│ │ │ ├── news-and-reviews.md
│ │ │ ├── reactive-intro.md
│ │ │ ├── refactoring.md
│ │ │ ├── routing-and-links.md
│ │ │ ├── samples
│ │ │ │ ├── color-palette.xmlui
│ │ │ │ ├── color-values.xmlui
│ │ │ │ ├── shadow-sizes.xmlui
│ │ │ │ ├── spacing-sizes.xmlui
│ │ │ │ ├── swatch.xmlui
│ │ │ │ ├── theme-gallery-brief.xmlui
│ │ │ │ └── theme-gallery.xmlui
│ │ │ ├── scoping.md
│ │ │ ├── scripting.md
│ │ │ ├── styles-and-themes
│ │ │ │ ├── common-units.md
│ │ │ │ ├── layout-props.md
│ │ │ │ ├── theme-variable-defaults.md
│ │ │ │ ├── theme-variables.md
│ │ │ │ └── themes.md
│ │ │ ├── template-properties.md
│ │ │ ├── test.md
│ │ │ ├── tutorial-01.md
│ │ │ ├── tutorial-02.md
│ │ │ ├── tutorial-03.md
│ │ │ ├── tutorial-04.md
│ │ │ ├── tutorial-05.md
│ │ │ ├── tutorial-06.md
│ │ │ ├── tutorial-07.md
│ │ │ ├── tutorial-08.md
│ │ │ ├── tutorial-09.md
│ │ │ ├── tutorial-10.md
│ │ │ ├── tutorial-11.md
│ │ │ ├── tutorial-12.md
│ │ │ ├── universal-properties.md
│ │ │ ├── user-defined-components.md
│ │ │ ├── vscode.md
│ │ │ ├── working-with-markdown.md
│ │ │ ├── working-with-text.md
│ │ │ ├── xmlui-animations
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── Animation.md
│ │ │ │ ├── FadeAnimation.md
│ │ │ │ ├── FadeInAnimation.md
│ │ │ │ ├── FadeOutAnimation.md
│ │ │ │ ├── ScaleAnimation.md
│ │ │ │ └── SlideInAnimation.md
│ │ │ ├── xmlui-charts
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── DonutChart.md
│ │ │ │ ├── LabelList.md
│ │ │ │ ├── Legend.md
│ │ │ │ ├── LineChart.md
│ │ │ │ └── PieChart.md
│ │ │ ├── xmlui-pdf
│ │ │ │ ├── _meta.json
│ │ │ │ ├── _overview.md
│ │ │ │ └── Pdf.md
│ │ │ └── xmlui-spreadsheet
│ │ │ ├── _meta.json
│ │ │ ├── _overview.md
│ │ │ └── Spreadsheet.md
│ │ ├── resources
│ │ │ ├── devdocs
│ │ │ │ ├── debug-proxy-object-2.png
│ │ │ │ ├── debug-proxy-object.png
│ │ │ │ ├── table_editor_01.png
│ │ │ │ ├── table_editor_02.png
│ │ │ │ ├── table_editor_03.png
│ │ │ │ ├── table_editor_04.png
│ │ │ │ ├── table_editor_05.png
│ │ │ │ ├── table_editor_06.png
│ │ │ │ ├── table_editor_07.png
│ │ │ │ ├── table_editor_08.png
│ │ │ │ ├── table_editor_09.png
│ │ │ │ ├── table_editor_10.png
│ │ │ │ ├── table_editor_11.png
│ │ │ │ ├── table-editor-01.png
│ │ │ │ ├── table-editor-02.png
│ │ │ │ ├── table-editor-03.png
│ │ │ │ ├── table-editor-04.png
│ │ │ │ ├── table-editor-06.png
│ │ │ │ ├── table-editor-07.png
│ │ │ │ ├── table-editor-08.png
│ │ │ │ ├── table-editor-09.png
│ │ │ │ └── xmlui-rendering-of-tiptap-markdown.png
│ │ │ ├── favicon.ico
│ │ │ ├── files
│ │ │ │ ├── clients.json
│ │ │ │ ├── daily-revenue.json
│ │ │ │ ├── dashboard-stats.json
│ │ │ │ ├── demo.xmlui
│ │ │ │ ├── demo.xmlui.xs
│ │ │ │ ├── downloads
│ │ │ │ │ └── downloads.json
│ │ │ │ ├── for-download
│ │ │ │ │ ├── index-with-api.html
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── mockApi.js
│ │ │ │ │ ├── start-darwin.sh
│ │ │ │ │ ├── start-linux.sh
│ │ │ │ │ ├── start.bat
│ │ │ │ │ └── xmlui
│ │ │ │ │ └── xmlui-standalone.umd.js
│ │ │ │ ├── getting-started
│ │ │ │ │ ├── cl-tutorial-final.zip
│ │ │ │ │ ├── cl-tutorial.zip
│ │ │ │ │ ├── cl-tutorial2.zip
│ │ │ │ │ ├── cl-tutorial3.zip
│ │ │ │ │ ├── cl-tutorial4.zip
│ │ │ │ │ ├── cl-tutorial5.zip
│ │ │ │ │ ├── cl-tutorial6.zip
│ │ │ │ │ ├── getting-started.zip
│ │ │ │ │ ├── hello-xmlui.zip
│ │ │ │ │ ├── xmlui-empty.zip
│ │ │ │ │ └── xmlui-starter.zip
│ │ │ │ ├── howto
│ │ │ │ │ └── component-icons
│ │ │ │ │ └── up-arrow.svg
│ │ │ │ ├── invoices.json
│ │ │ │ ├── monthly-status.json
│ │ │ │ ├── news-and-reviews.json
│ │ │ │ ├── products.json
│ │ │ │ ├── releases.json
│ │ │ │ ├── tutorials
│ │ │ │ │ ├── datasource
│ │ │ │ │ │ └── api.ts
│ │ │ │ │ └── p2do
│ │ │ │ │ ├── api.ts
│ │ │ │ │ └── todo-logo.svg
│ │ │ │ └── xmlui.json
│ │ │ ├── github.svg
│ │ │ ├── images
│ │ │ │ ├── apiaction-tutorial
│ │ │ │ │ ├── add-success.png
│ │ │ │ │ ├── apiaction-param.png
│ │ │ │ │ ├── change-completed.png
│ │ │ │ │ ├── change-in-progress.png
│ │ │ │ │ ├── confirm-delete.png
│ │ │ │ │ ├── data-error.png
│ │ │ │ │ ├── data-progress.png
│ │ │ │ │ ├── data-success.png
│ │ │ │ │ ├── display-1.png
│ │ │ │ │ ├── item-deleted.png
│ │ │ │ │ ├── item-updated.png
│ │ │ │ │ ├── missing-api-key.png
│ │ │ │ │ ├── new-item-added.png
│ │ │ │ │ └── test-message.png
│ │ │ │ ├── chat-api
│ │ │ │ │ └── domain-model.svg
│ │ │ │ ├── components
│ │ │ │ │ ├── image
│ │ │ │ │ │ └── breakfast.jpg
│ │ │ │ │ ├── markdown
│ │ │ │ │ │ └── colors.png
│ │ │ │ │ └── modal
│ │ │ │ │ ├── deep_link_dialog_1.jpg
│ │ │ │ │ └── deep_link_dialog_2.jpg
│ │ │ │ ├── create-apps
│ │ │ │ │ ├── collapsed-vertical.png
│ │ │ │ │ ├── using-forms-warning-dialog.png
│ │ │ │ │ └── using-forms.png
│ │ │ │ ├── datasource-tutorial
│ │ │ │ │ ├── data-with-header.png
│ │ │ │ │ ├── filtered-data.png
│ │ │ │ │ ├── filtered-items.png
│ │ │ │ │ ├── initial-page-items.png
│ │ │ │ │ ├── list-items.png
│ │ │ │ │ ├── next-page-items.png
│ │ │ │ │ ├── no-data.png
│ │ │ │ │ ├── pagination-1.jpg
│ │ │ │ │ ├── pagination-1.png
│ │ │ │ │ ├── polling-1.png
│ │ │ │ │ ├── refetch-data.png
│ │ │ │ │ ├── slow-loading.png
│ │ │ │ │ ├── test-message.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── unconventional-data.png
│ │ │ │ │ └── unfiltered-items.png
│ │ │ │ ├── flower.jpg
│ │ │ │ ├── get-started
│ │ │ │ │ ├── add-new-contact.png
│ │ │ │ │ ├── app-modified.png
│ │ │ │ │ ├── app-start.png
│ │ │ │ │ ├── app-with-boxes.png
│ │ │ │ │ ├── app-with-toast.png
│ │ │ │ │ ├── boilerplate-structure.png
│ │ │ │ │ ├── cl-initial.png
│ │ │ │ │ ├── cl-start.png
│ │ │ │ │ ├── contact-counts.png
│ │ │ │ │ ├── contact-dialog-title.png
│ │ │ │ │ ├── contact-dialog.png
│ │ │ │ │ ├── contact-menus.png
│ │ │ │ │ ├── contact-predicates.png
│ │ │ │ │ ├── context-menu.png
│ │ │ │ │ ├── dashboard-numbers.png
│ │ │ │ │ ├── default-contact-list.png
│ │ │ │ │ ├── delete-contact.png
│ │ │ │ │ ├── delete-task.png
│ │ │ │ │ ├── detailed-template.png
│ │ │ │ │ ├── edit-contact-details.png
│ │ │ │ │ ├── edited-contact-saved.png
│ │ │ │ │ ├── empty-sections.png
│ │ │ │ │ ├── filter-completed.png
│ │ │ │ │ ├── fullwidth-desktop.png
│ │ │ │ │ ├── fullwidth-mobile.png
│ │ │ │ │ ├── initial-table.png
│ │ │ │ │ ├── items-and-badges.png
│ │ │ │ │ ├── loading-message.png
│ │ │ │ │ ├── new-contact-button.png
│ │ │ │ │ ├── new-contact-saved.png
│ │ │ │ │ ├── no-empty-sections.png
│ │ │ │ │ ├── personal-todo-initial.png
│ │ │ │ │ ├── piechart.png
│ │ │ │ │ ├── review-today.png
│ │ │ │ │ ├── rudimentary-dashboard.png
│ │ │ │ │ ├── section-collapsed.png
│ │ │ │ │ ├── sectioned-items.png
│ │ │ │ │ ├── sections-ordered.png
│ │ │ │ │ ├── spacex-list-with-links.png
│ │ │ │ │ ├── spacex-list.png
│ │ │ │ │ ├── start-personal-todo-1.png
│ │ │ │ │ ├── submit-new-contact.png
│ │ │ │ │ ├── submit-new-task.png
│ │ │ │ │ ├── syntax-highlighting.png
│ │ │ │ │ ├── table-with-badge.png
│ │ │ │ │ ├── template-with-card.png
│ │ │ │ │ ├── test-emulated-api.png
│ │ │ │ │ ├── Thumbs.db
│ │ │ │ │ ├── todo-logo.png
│ │ │ │ │ └── xmlui-tools.png
│ │ │ │ ├── HelloApp.png
│ │ │ │ ├── HelloApp2.png
│ │ │ │ ├── logos
│ │ │ │ │ ├── xmlui1.svg
│ │ │ │ │ ├── xmlui2.svg
│ │ │ │ │ ├── xmlui3.svg
│ │ │ │ │ ├── xmlui4.svg
│ │ │ │ │ ├── xmlui5.svg
│ │ │ │ │ ├── xmlui6.svg
│ │ │ │ │ └── xmlui7.svg
│ │ │ │ ├── pdf
│ │ │ │ │ └── dummy-pdf.jpg
│ │ │ │ ├── rendering-engine
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ ├── Component.svg
│ │ │ │ │ ├── CompoundComponent.svg
│ │ │ │ │ ├── RootComponent.svg
│ │ │ │ │ └── tree-with-containers.svg
│ │ │ │ ├── reviewers-guide
│ │ │ │ │ ├── AppEngine-flow.svg
│ │ │ │ │ └── incbutton-in-action.png
│ │ │ │ ├── tools
│ │ │ │ │ └── boilerplate-structure.png
│ │ │ │ ├── try.svg
│ │ │ │ ├── tutorial
│ │ │ │ │ ├── app-chat-history.png
│ │ │ │ │ ├── app-content-placeholder.png
│ │ │ │ │ ├── app-header-and-content.png
│ │ │ │ │ ├── app-links-channel-selected.png
│ │ │ │ │ ├── app-links-click.png
│ │ │ │ │ ├── app-navigation.png
│ │ │ │ │ ├── finished-ex01.png
│ │ │ │ │ ├── finished-ex02.png
│ │ │ │ │ ├── hello.png
│ │ │ │ │ ├── splash-screen-advanced.png
│ │ │ │ │ ├── splash-screen-after-click.png
│ │ │ │ │ ├── splash-screen-centered.png
│ │ │ │ │ ├── splash-screen-events.png
│ │ │ │ │ ├── splash-screen-expression.png
│ │ │ │ │ ├── splash-screen-reuse-after.png
│ │ │ │ │ ├── splash-screen-reuse-before.png
│ │ │ │ │ └── splash-screen.png
│ │ │ │ └── tutorial-01.png
│ │ │ ├── llms.txt
│ │ │ ├── logo-dark.svg
│ │ │ ├── logo.svg
│ │ │ ├── pg-popout.svg
│ │ │ └── xmlui-logo.svg
│ │ ├── serve.json
│ │ └── web.config
│ ├── scripts
│ │ ├── download-latest-xmlui.js
│ │ ├── generate-rss.js
│ │ ├── get-releases.js
│ │ └── utils.js
│ ├── src
│ │ ├── components
│ │ │ ├── BlogOverview.xmlui
│ │ │ ├── BlogPage.xmlui
│ │ │ ├── Boxes.xmlui
│ │ │ ├── Breadcrumb.xmlui
│ │ │ ├── ChangeLog.xmlui
│ │ │ ├── ColorPalette.xmlui
│ │ │ ├── DocumentLinks.xmlui
│ │ │ ├── DocumentPage.xmlui
│ │ │ ├── DocumentPageNoTOC.xmlui
│ │ │ ├── Icons.xmlui
│ │ │ ├── IncButton.xmlui
│ │ │ ├── IncButton2.xmlui
│ │ │ ├── NameValue.xmlui
│ │ │ ├── PageNotFound.xmlui
│ │ │ ├── PaletteItem.xmlui
│ │ │ ├── Palettes.xmlui
│ │ │ ├── SectionHeader.xmlui
│ │ │ ├── TBD.xmlui
│ │ │ ├── Test.xmlui
│ │ │ ├── ThemesIntro.xmlui
│ │ │ ├── ThousandThemes.xmlui
│ │ │ ├── TubeStops.xmlui
│ │ │ ├── TubeStops.xmlui.xs
│ │ │ └── TwoColumnCode.xmlui
│ │ ├── config.ts
│ │ ├── Main.xmlui
│ │ └── themes
│ │ ├── docs-theme.ts
│ │ ├── earthtone.ts
│ │ ├── xmlui-gray-on-default.ts
│ │ ├── xmlui-green-on-default.ts
│ │ └── xmlui-orange-on-default.ts
│ └── tsconfig.json
├── LICENSE
├── package-lock.json
├── package.json
├── packages
│ ├── tsconfig.json
│ ├── xmlui-animations
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── Animation.tsx
│ │ ├── AnimationNative.tsx
│ │ ├── FadeAnimation.tsx
│ │ ├── FadeInAnimation.tsx
│ │ ├── FadeOutAnimation.tsx
│ │ ├── index.tsx
│ │ ├── ScaleAnimation.tsx
│ │ └── SlideInAnimation.tsx
│ ├── xmlui-devtools
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── devtools
│ │ │ │ ├── DevTools.tsx
│ │ │ │ ├── DevToolsNative.module.scss
│ │ │ │ ├── DevToolsNative.tsx
│ │ │ │ ├── ModalDialog.module.scss
│ │ │ │ ├── ModalDialog.tsx
│ │ │ │ ├── ModalVisibilityContext.tsx
│ │ │ │ ├── Tooltip.module.scss
│ │ │ │ ├── Tooltip.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── editor
│ │ │ │ └── Editor.tsx
│ │ │ └── index.tsx
│ │ └── vite.config-overrides.ts
│ ├── xmlui-hello-world
│ │ ├── .gitignore
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── HelloWorld.module.scss
│ │ ├── HelloWorld.tsx
│ │ ├── HelloWorldNative.tsx
│ │ └── index.tsx
│ ├── xmlui-os-frames
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── IPhoneFrame.module.scss
│ │ ├── IPhoneFrame.tsx
│ │ ├── MacOSAppFrame.module.scss
│ │ ├── MacOSAppFrame.tsx
│ │ ├── WindowsAppFrame.module.scss
│ │ └── WindowsAppFrame.tsx
│ ├── xmlui-pdf
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ ├── components
│ │ │ │ └── Pdf.xmlui
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── LazyPdfNative.tsx
│ │ ├── Pdf.module.scss
│ │ └── Pdf.tsx
│ ├── xmlui-playground
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── hooks
│ │ │ ├── usePlayground.ts
│ │ │ └── useToast.ts
│ │ ├── index.tsx
│ │ ├── playground
│ │ │ ├── Box.module.scss
│ │ │ ├── Box.tsx
│ │ │ ├── CodeSelector.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
│ ├── xmlui-search
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── Search.module.scss
│ │ └── Search.tsx
│ ├── xmlui-spreadsheet
│ │ ├── .gitignore
│ │ ├── demo
│ │ │ └── Main.xmlui
│ │ ├── index.html
│ │ ├── index.ts
│ │ ├── meta
│ │ │ └── componentsMetadata.ts
│ │ ├── package.json
│ │ └── src
│ │ ├── index.tsx
│ │ ├── Spreadsheet.tsx
│ │ └── SpreadsheetNative.tsx
│ └── xmlui-website-blocks
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── demo
│ │ ├── components
│ │ │ ├── HeroBackgroundBreakoutPage.xmlui
│ │ │ ├── HeroBackgroundsPage.xmlui
│ │ │ ├── HeroContentsPage.xmlui
│ │ │ ├── HeroTextAlignPage.xmlui
│ │ │ ├── HeroTextPage.xmlui
│ │ │ └── HeroTonesPage.xmlui
│ │ ├── Main.xmlui
│ │ └── themes
│ │ └── default.ts
│ ├── index.html
│ ├── index.ts
│ ├── meta
│ │ └── componentsMetadata.ts
│ ├── package.json
│ ├── public
│ │ └── resources
│ │ ├── building.jpg
│ │ └── xmlui-logo.svg
│ └── src
│ ├── Carousel
│ │ ├── Carousel.module.scss
│ │ ├── Carousel.tsx
│ │ ├── CarouselContext.tsx
│ │ └── CarouselNative.tsx
│ ├── FancyButton
│ │ ├── FancyButton.module.scss
│ │ ├── FancyButton.tsx
│ │ └── FancyButton.xmlui
│ ├── Hello
│ │ ├── Hello.tsx
│ │ ├── Hello.xmlui
│ │ └── Hello.xmlui.xs
│ ├── HeroSection
│ │ ├── HeroSection.module.scss
│ │ ├── HeroSection.spec.ts
│ │ ├── HeroSection.tsx
│ │ └── HeroSectionNative.tsx
│ ├── index.tsx
│ ├── ScrollToTop
│ │ ├── ScrollToTop.module.scss
│ │ ├── ScrollToTop.tsx
│ │ └── ScrollToTopNative.tsx
│ └── vite-env.d.ts
├── playwright.config.ts
├── README.md
├── tools
│ ├── codefence
│ │ └── xmlui-code-fence-docs.md
│ ├── create-app
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── create-app.ts
│ │ ├── helpers
│ │ │ ├── copy.ts
│ │ │ ├── get-pkg-manager.ts
│ │ │ ├── git.ts
│ │ │ ├── install.ts
│ │ │ ├── is-folder-empty.ts
│ │ │ ├── is-writeable.ts
│ │ │ ├── make-dir.ts
│ │ │ └── validate-pkg.ts
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── templates
│ │ │ ├── default
│ │ │ │ └── ts
│ │ │ │ ├── gitignore
│ │ │ │ ├── index.html
│ │ │ │ ├── index.ts
│ │ │ │ ├── public
│ │ │ │ │ ├── mockServiceWorker.js
│ │ │ │ │ ├── resources
│ │ │ │ │ │ ├── favicon.ico
│ │ │ │ │ │ └── xmlui-logo.svg
│ │ │ │ │ └── serve.json
│ │ │ │ └── src
│ │ │ │ ├── components
│ │ │ │ │ ├── ApiAware.xmlui
│ │ │ │ │ ├── Home.xmlui
│ │ │ │ │ ├── IncButton.xmlui
│ │ │ │ │ └── PagePanel.xmlui
│ │ │ │ ├── config.ts
│ │ │ │ └── Main.xmlui
│ │ │ ├── index.ts
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ ├── create-xmlui-hello-world
│ │ ├── index.js
│ │ └── package.json
│ └── vscode
│ ├── .gitignore
│ ├── .vscode
│ │ ├── launch.json
│ │ └── tasks.json
│ ├── .vscodeignore
│ ├── build.sh
│ ├── CHANGELOG.md
│ ├── esbuild.js
│ ├── eslint.config.mjs
│ ├── formatter-docs.md
│ ├── generate-test-sample.sh
│ ├── LICENSE.md
│ ├── package-lock.json
│ ├── package.json
│ ├── README.md
│ ├── resources
│ │ ├── xmlui-logo.png
│ │ └── xmlui-markup-syntax-highlighting.png
│ ├── src
│ │ ├── extension.ts
│ │ └── server.ts
│ ├── syntaxes
│ │ └── xmlui.tmLanguage.json
│ ├── test-samples
│ │ └── sample.xmlui
│ ├── tsconfig.json
│ └── tsconfig.tsbuildinfo
├── turbo.json
└── xmlui
├── .gitignore
├── bin
│ ├── bootstrap.cjs
│ ├── bootstrap.js
│ ├── build-lib.ts
│ ├── build.ts
│ ├── index.ts
│ ├── preview.ts
│ ├── start.ts
│ ├── vite-xmlui-plugin.ts
│ └── viteConfig.ts
├── CHANGELOG.md
├── conventions
│ ├── component-qa-checklist.md
│ ├── copilot-conventions.md
│ ├── create-xmlui-components.md
│ ├── mermaid.md
│ ├── testing-conventions.md
│ └── xmlui-in-a-nutshell.md
├── dev-docs
│ ├── accessibility.md
│ ├── build-system.md
│ ├── build-xmlui.md
│ ├── component-behaviors.md
│ ├── component-metadata.md
│ ├── components-with-options.md
│ ├── containers.md
│ ├── data-operations.md
│ ├── glossary.md
│ ├── index.md
│ ├── next
│ │ ├── component-dev-guide.md
│ │ ├── configuration-management-enhancement-summary.md
│ │ ├── documentation-scripts-refactoring-complete-summary.md
│ │ ├── documentation-scripts-refactoring-plan.md
│ │ ├── duplicate-pattern-extraction-summary.md
│ │ ├── error-handling-standardization-summary.md
│ │ ├── generating-component-reference.md
│ │ ├── index.md
│ │ ├── logging-consistency-implementation-summary.md
│ │ ├── project-build.md
│ │ ├── project-structure.md
│ │ ├── theme-context.md
│ │ ├── tiptap-design-considerations.md
│ │ ├── working-with-code.md
│ │ ├── xmlui-runtime-architecture
│ │ └── xmlui-wcag-accessibility-report.md
│ ├── react-fundamentals.md
│ ├── release-method.md
│ ├── standalone-app.md
│ ├── theme-variables-refactoring.md
│ ├── ud-components.md
│ └── xmlui-repo.md
├── package.json
├── scripts
│ ├── coverage-only.js
│ ├── e2e-test-summary.js
│ ├── extract-component-metadata.js
│ ├── generate-docs
│ │ ├── build-downloads-map.mjs
│ │ ├── build-pages-map.mjs
│ │ ├── components-config.json
│ │ ├── configuration-management.mjs
│ │ ├── constants.mjs
│ │ ├── create-theme-files.mjs
│ │ ├── DocsGenerator.mjs
│ │ ├── error-handling.mjs
│ │ ├── extensions-config.json
│ │ ├── folders.mjs
│ │ ├── generate-summary-files.mjs
│ │ ├── get-docs.mjs
│ │ ├── input-handler.mjs
│ │ ├── logger.mjs
│ │ ├── logging-standards.mjs
│ │ ├── MetadataProcessor.mjs
│ │ ├── pattern-utilities.mjs
│ │ └── utils.mjs
│ ├── generate-metadata-markdown.js
│ ├── get-langserver-metadata.js
│ ├── inline-links.mjs
│ └── README-e2e-summary.md
├── src
│ ├── abstractions
│ │ ├── _conventions.md
│ │ ├── ActionDefs.ts
│ │ ├── AppContextDefs.ts
│ │ ├── ComponentDefs.ts
│ │ ├── ContainerDefs.ts
│ │ ├── ExtensionDefs.ts
│ │ ├── FunctionDefs.ts
│ │ ├── RendererDefs.ts
│ │ ├── scripting
│ │ │ ├── BlockScope.ts
│ │ │ ├── Compilation.ts
│ │ │ ├── LogicalThread.ts
│ │ │ ├── LoopScope.ts
│ │ │ ├── modules.ts
│ │ │ ├── ScriptParserError.ts
│ │ │ ├── Token.ts
│ │ │ ├── TryScope.ts
│ │ │ └── TryScopeExp.ts
│ │ └── ThemingDefs.ts
│ ├── components
│ │ ├── _conventions.md
│ │ ├── abstractions.ts
│ │ ├── Accordion
│ │ │ ├── Accordion.md
│ │ │ ├── Accordion.module.scss
│ │ │ ├── Accordion.spec.ts
│ │ │ ├── Accordion.tsx
│ │ │ ├── AccordionContext.tsx
│ │ │ ├── AccordionItem.tsx
│ │ │ ├── AccordionItemNative.tsx
│ │ │ └── AccordionNative.tsx
│ │ ├── Animation
│ │ │ └── AnimationNative.tsx
│ │ ├── APICall
│ │ │ ├── APICall.md
│ │ │ ├── APICall.spec.ts
│ │ │ ├── APICall.tsx
│ │ │ └── APICallNative.tsx
│ │ ├── App
│ │ │ ├── App.md
│ │ │ ├── App.module.scss
│ │ │ ├── App.spec.ts
│ │ │ ├── App.tsx
│ │ │ ├── AppLayoutContext.ts
│ │ │ ├── AppNative.tsx
│ │ │ ├── AppStateContext.ts
│ │ │ ├── doc-resources
│ │ │ │ ├── condensed-sticky.xmlui
│ │ │ │ ├── condensed.xmlui
│ │ │ │ ├── horizontal-sticky.xmlui
│ │ │ │ ├── horizontal.xmlui
│ │ │ │ ├── vertical-full-header.xmlui
│ │ │ │ ├── vertical-sticky.xmlui
│ │ │ │ └── vertical.xmlui
│ │ │ ├── IndexerContext.ts
│ │ │ ├── LinkInfoContext.ts
│ │ │ ├── SearchContext.tsx
│ │ │ ├── Sheet.module.scss
│ │ │ └── Sheet.tsx
│ │ ├── AppHeader
│ │ │ ├── AppHeader.md
│ │ │ ├── AppHeader.module.scss
│ │ │ ├── AppHeader.spec.ts
│ │ │ ├── AppHeader.tsx
│ │ │ └── AppHeaderNative.tsx
│ │ ├── AppState
│ │ │ ├── AppState.md
│ │ │ ├── AppState.spec.ts
│ │ │ ├── AppState.tsx
│ │ │ └── AppStateNative.tsx
│ │ ├── AutoComplete
│ │ │ ├── AutoComplete.md
│ │ │ ├── AutoComplete.module.scss
│ │ │ ├── AutoComplete.spec.ts
│ │ │ ├── AutoComplete.tsx
│ │ │ ├── AutoCompleteContext.tsx
│ │ │ └── AutoCompleteNative.tsx
│ │ ├── Avatar
│ │ │ ├── Avatar.md
│ │ │ ├── Avatar.module.scss
│ │ │ ├── Avatar.spec.ts
│ │ │ ├── Avatar.tsx
│ │ │ └── AvatarNative.tsx
│ │ ├── Backdrop
│ │ │ ├── Backdrop.md
│ │ │ ├── Backdrop.module.scss
│ │ │ ├── Backdrop.spec.ts
│ │ │ ├── Backdrop.tsx
│ │ │ └── BackdropNative.tsx
│ │ ├── Badge
│ │ │ ├── Badge.md
│ │ │ ├── Badge.module.scss
│ │ │ ├── Badge.spec.ts
│ │ │ ├── Badge.tsx
│ │ │ └── BadgeNative.tsx
│ │ ├── Bookmark
│ │ │ ├── Bookmark.md
│ │ │ ├── Bookmark.module.scss
│ │ │ ├── Bookmark.spec.ts
│ │ │ ├── Bookmark.tsx
│ │ │ └── BookmarkNative.tsx
│ │ ├── Breakout
│ │ │ ├── Breakout.module.scss
│ │ │ ├── Breakout.spec.ts
│ │ │ ├── Breakout.tsx
│ │ │ └── BreakoutNative.tsx
│ │ ├── Button
│ │ │ ├── Button-style.spec.ts
│ │ │ ├── Button.md
│ │ │ ├── Button.module.scss
│ │ │ ├── Button.spec.ts
│ │ │ ├── Button.tsx
│ │ │ └── ButtonNative.tsx
│ │ ├── Card
│ │ │ ├── Card.md
│ │ │ ├── Card.module.scss
│ │ │ ├── Card.spec.ts
│ │ │ ├── Card.tsx
│ │ │ └── CardNative.tsx
│ │ ├── Carousel
│ │ │ ├── Carousel.md
│ │ │ ├── Carousel.module.scss
│ │ │ ├── Carousel.spec.ts
│ │ │ ├── Carousel.tsx
│ │ │ ├── CarouselContext.tsx
│ │ │ ├── CarouselItem.tsx
│ │ │ ├── CarouselItemNative.tsx
│ │ │ └── CarouselNative.tsx
│ │ ├── ChangeListener
│ │ │ ├── ChangeListener.md
│ │ │ ├── ChangeListener.spec.ts
│ │ │ ├── ChangeListener.tsx
│ │ │ └── ChangeListenerNative.tsx
│ │ ├── chart-color-schemes.ts
│ │ ├── Charts
│ │ │ ├── AreaChart
│ │ │ │ ├── AreaChart.md
│ │ │ │ ├── AreaChart.spec.ts
│ │ │ │ ├── AreaChart.tsx
│ │ │ │ └── AreaChartNative.tsx
│ │ │ ├── BarChart
│ │ │ │ ├── BarChart.md
│ │ │ │ ├── BarChart.module.scss
│ │ │ │ ├── BarChart.spec.ts
│ │ │ │ ├── BarChart.tsx
│ │ │ │ └── BarChartNative.tsx
│ │ │ ├── DonutChart
│ │ │ │ ├── DonutChart.spec.ts
│ │ │ │ └── DonutChart.tsx
│ │ │ ├── LabelList
│ │ │ │ ├── LabelList.module.scss
│ │ │ │ ├── LabelList.spec.ts
│ │ │ │ ├── LabelList.tsx
│ │ │ │ └── LabelListNative.tsx
│ │ │ ├── Legend
│ │ │ │ ├── Legend.spec.ts
│ │ │ │ ├── Legend.tsx
│ │ │ │ └── LegendNative.tsx
│ │ │ ├── LineChart
│ │ │ │ ├── LineChart.md
│ │ │ │ ├── LineChart.module.scss
│ │ │ │ ├── LineChart.spec.ts
│ │ │ │ ├── LineChart.tsx
│ │ │ │ └── LineChartNative.tsx
│ │ │ ├── PieChart
│ │ │ │ ├── PieChart.md
│ │ │ │ ├── PieChart.spec.ts
│ │ │ │ ├── PieChart.tsx
│ │ │ │ ├── PieChartNative.module.scss
│ │ │ │ └── PieChartNative.tsx
│ │ │ ├── RadarChart
│ │ │ │ ├── RadarChart.md
│ │ │ │ ├── RadarChart.spec.ts
│ │ │ │ ├── RadarChart.tsx
│ │ │ │ └── RadarChartNative.tsx
│ │ │ ├── Tooltip
│ │ │ │ ├── TooltipContent.module.scss
│ │ │ │ ├── TooltipContent.spec.ts
│ │ │ │ └── TooltipContent.tsx
│ │ │ └── utils
│ │ │ ├── abstractions.ts
│ │ │ └── ChartProvider.tsx
│ │ ├── Checkbox
│ │ │ ├── Checkbox.md
│ │ │ ├── Checkbox.spec.ts
│ │ │ └── Checkbox.tsx
│ │ ├── CodeBlock
│ │ │ ├── CodeBlock.module.scss
│ │ │ ├── CodeBlock.spec.ts
│ │ │ ├── CodeBlock.tsx
│ │ │ ├── CodeBlockNative.tsx
│ │ │ └── highlight-code.ts
│ │ ├── collectedComponentMetadata.ts
│ │ ├── ColorPicker
│ │ │ ├── ColorPicker.md
│ │ │ ├── ColorPicker.module.scss
│ │ │ ├── ColorPicker.spec.ts
│ │ │ ├── ColorPicker.tsx
│ │ │ └── ColorPickerNative.tsx
│ │ ├── Column
│ │ │ ├── Column.md
│ │ │ ├── Column.tsx
│ │ │ ├── ColumnNative.tsx
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ └── TableContext.tsx
│ │ ├── component-utils.ts
│ │ ├── ComponentProvider.tsx
│ │ ├── ComponentRegistryContext.tsx
│ │ ├── container-helpers.tsx
│ │ ├── ContentSeparator
│ │ │ ├── ContentSeparator.md
│ │ │ ├── ContentSeparator.module.scss
│ │ │ ├── ContentSeparator.spec.ts
│ │ │ ├── ContentSeparator.tsx
│ │ │ └── ContentSeparatorNative.tsx
│ │ ├── DataSource
│ │ │ ├── DataSource.md
│ │ │ └── DataSource.tsx
│ │ ├── DateInput
│ │ │ ├── DateInput.md
│ │ │ ├── DateInput.module.scss
│ │ │ ├── DateInput.spec.ts
│ │ │ ├── DateInput.tsx
│ │ │ └── DateInputNative.tsx
│ │ ├── DatePicker
│ │ │ ├── DatePicker.md
│ │ │ ├── DatePicker.module.scss
│ │ │ ├── DatePicker.spec.ts
│ │ │ ├── DatePicker.tsx
│ │ │ └── DatePickerNative.tsx
│ │ ├── DropdownMenu
│ │ │ ├── DropdownMenu.md
│ │ │ ├── DropdownMenu.module.scss
│ │ │ ├── DropdownMenu.spec.ts
│ │ │ ├── DropdownMenu.tsx
│ │ │ ├── DropdownMenuNative.tsx
│ │ │ ├── MenuItem.md
│ │ │ └── SubMenuItem.md
│ │ ├── EmojiSelector
│ │ │ ├── EmojiSelector.md
│ │ │ ├── EmojiSelector.spec.ts
│ │ │ ├── EmojiSelector.tsx
│ │ │ └── EmojiSelectorNative.tsx
│ │ ├── ExpandableItem
│ │ │ ├── ExpandableItem.module.scss
│ │ │ ├── ExpandableItem.spec.ts
│ │ │ ├── ExpandableItem.tsx
│ │ │ └── ExpandableItemNative.tsx
│ │ ├── FileInput
│ │ │ ├── FileInput.md
│ │ │ ├── FileInput.module.scss
│ │ │ ├── FileInput.spec.ts
│ │ │ ├── FileInput.tsx
│ │ │ └── FileInputNative.tsx
│ │ ├── FileUploadDropZone
│ │ │ ├── FileUploadDropZone.md
│ │ │ ├── FileUploadDropZone.module.scss
│ │ │ ├── FileUploadDropZone.spec.ts
│ │ │ ├── FileUploadDropZone.tsx
│ │ │ └── FileUploadDropZoneNative.tsx
│ │ ├── FlowLayout
│ │ │ ├── FlowLayout.md
│ │ │ ├── FlowLayout.module.scss
│ │ │ ├── FlowLayout.spec.ts
│ │ │ ├── FlowLayout.spec.ts-snapshots
│ │ │ │ └── Edge-cases-boxShadow-is-not-clipped-1-non-smoke-darwin.png
│ │ │ ├── FlowLayout.tsx
│ │ │ └── FlowLayoutNative.tsx
│ │ ├── Footer
│ │ │ ├── Footer.md
│ │ │ ├── Footer.module.scss
│ │ │ ├── Footer.spec.ts
│ │ │ ├── Footer.tsx
│ │ │ └── FooterNative.tsx
│ │ ├── Form
│ │ │ ├── Form.md
│ │ │ ├── Form.module.scss
│ │ │ ├── Form.spec.ts
│ │ │ ├── Form.tsx
│ │ │ ├── formActions.ts
│ │ │ ├── FormContext.ts
│ │ │ └── FormNative.tsx
│ │ ├── FormItem
│ │ │ ├── FormItem.md
│ │ │ ├── FormItem.module.scss
│ │ │ ├── FormItem.spec.ts
│ │ │ ├── FormItem.tsx
│ │ │ ├── FormItemNative.tsx
│ │ │ ├── HelperText.module.scss
│ │ │ ├── HelperText.tsx
│ │ │ ├── ItemWithLabel.tsx
│ │ │ └── Validations.ts
│ │ ├── FormSection
│ │ │ ├── FormSection.md
│ │ │ ├── FormSection.ts
│ │ │ └── FormSection.xmlui
│ │ ├── Fragment
│ │ │ ├── Fragment.spec.ts
│ │ │ └── Fragment.tsx
│ │ ├── Heading
│ │ │ ├── abstractions.ts
│ │ │ ├── H1.md
│ │ │ ├── H1.spec.ts
│ │ │ ├── H2.md
│ │ │ ├── H2.spec.ts
│ │ │ ├── H3.md
│ │ │ ├── H3.spec.ts
│ │ │ ├── H4.md
│ │ │ ├── H4.spec.ts
│ │ │ ├── H5.md
│ │ │ ├── H5.spec.ts
│ │ │ ├── H6.md
│ │ │ ├── H6.spec.ts
│ │ │ ├── Heading.md
│ │ │ ├── Heading.module.scss
│ │ │ ├── Heading.spec.ts
│ │ │ ├── Heading.tsx
│ │ │ └── HeadingNative.tsx
│ │ ├── HoverCard
│ │ │ ├── HoverCard.tsx
│ │ │ └── HovercardNative.tsx
│ │ ├── HtmlTags
│ │ │ ├── HtmlTags.module.scss
│ │ │ ├── HtmlTags.spec.ts
│ │ │ └── HtmlTags.tsx
│ │ ├── Icon
│ │ │ ├── AdmonitionDanger.tsx
│ │ │ ├── AdmonitionInfo.tsx
│ │ │ ├── AdmonitionNote.tsx
│ │ │ ├── AdmonitionTip.tsx
│ │ │ ├── AdmonitionWarning.tsx
│ │ │ ├── ApiIcon.tsx
│ │ │ ├── ArrowDropDown.module.scss
│ │ │ ├── ArrowDropDown.tsx
│ │ │ ├── ArrowDropUp.module.scss
│ │ │ ├── ArrowDropUp.tsx
│ │ │ ├── ArrowLeft.module.scss
│ │ │ ├── ArrowLeft.tsx
│ │ │ ├── ArrowRight.module.scss
│ │ │ ├── ArrowRight.tsx
│ │ │ ├── Attach.tsx
│ │ │ ├── Binding.module.scss
│ │ │ ├── Binding.tsx
│ │ │ ├── BoardIcon.tsx
│ │ │ ├── BoxIcon.tsx
│ │ │ ├── CheckIcon.tsx
│ │ │ ├── ChevronDownIcon.tsx
│ │ │ ├── ChevronLeft.tsx
│ │ │ ├── ChevronRight.tsx
│ │ │ ├── ChevronUpIcon.tsx
│ │ │ ├── CodeFileIcon.tsx
│ │ │ ├── CodeSandbox.tsx
│ │ │ ├── CompactListIcon.tsx
│ │ │ ├── ContentCopyIcon.tsx
│ │ │ ├── DarkToLightIcon.tsx
│ │ │ ├── DatabaseIcon.module.scss
│ │ │ ├── DatabaseIcon.tsx
│ │ │ ├── DocFileIcon.tsx
│ │ │ ├── DocIcon.tsx
│ │ │ ├── DotMenuHorizontalIcon.tsx
│ │ │ ├── DotMenuIcon.tsx
│ │ │ ├── EmailIcon.tsx
│ │ │ ├── EmptyFolderIcon.tsx
│ │ │ ├── ErrorIcon.tsx
│ │ │ ├── ExpressionIcon.tsx
│ │ │ ├── FillPlusCricleIcon.tsx
│ │ │ ├── FilterIcon.tsx
│ │ │ ├── FolderIcon.tsx
│ │ │ ├── GlobeIcon.tsx
│ │ │ ├── HomeIcon.tsx
│ │ │ ├── HyperLinkIcon.tsx
│ │ │ ├── Icon.md
│ │ │ ├── Icon.module.scss
│ │ │ ├── Icon.spec.ts
│ │ │ ├── Icon.tsx
│ │ │ ├── IconNative.tsx
│ │ │ ├── ImageFileIcon.tsx
│ │ │ ├── Inspect.tsx
│ │ │ ├── LightToDark.tsx
│ │ │ ├── LinkIcon.tsx
│ │ │ ├── ListIcon.tsx
│ │ │ ├── LooseListIcon.tsx
│ │ │ ├── MoonIcon.tsx
│ │ │ ├── MoreOptionsIcon.tsx
│ │ │ ├── NoSortIcon.tsx
│ │ │ ├── PDFIcon.tsx
│ │ │ ├── PenIcon.tsx
│ │ │ ├── PhoneIcon.tsx
│ │ │ ├── PhotoIcon.tsx
│ │ │ ├── PlusIcon.tsx
│ │ │ ├── SearchIcon.tsx
│ │ │ ├── ShareIcon.tsx
│ │ │ ├── SortAscendingIcon.tsx
│ │ │ ├── SortDescendingIcon.tsx
│ │ │ ├── StarsIcon.tsx
│ │ │ ├── SunIcon.tsx
│ │ │ ├── svg
│ │ │ │ ├── admonition_danger.svg
│ │ │ │ ├── admonition_info.svg
│ │ │ │ ├── admonition_note.svg
│ │ │ │ ├── admonition_tip.svg
│ │ │ │ ├── admonition_warning.svg
│ │ │ │ ├── api.svg
│ │ │ │ ├── arrow-dropdown.svg
│ │ │ │ ├── arrow-left.svg
│ │ │ │ ├── arrow-right.svg
│ │ │ │ ├── arrow-up.svg
│ │ │ │ ├── attach.svg
│ │ │ │ ├── binding.svg
│ │ │ │ ├── box.svg
│ │ │ │ ├── bulb.svg
│ │ │ │ ├── code-file.svg
│ │ │ │ ├── code-sandbox.svg
│ │ │ │ ├── dark_to_light.svg
│ │ │ │ ├── database.svg
│ │ │ │ ├── doc.svg
│ │ │ │ ├── empty-folder.svg
│ │ │ │ ├── expression.svg
│ │ │ │ ├── eye-closed.svg
│ │ │ │ ├── eye-dark.svg
│ │ │ │ ├── eye.svg
│ │ │ │ ├── file-text.svg
│ │ │ │ ├── filter.svg
│ │ │ │ ├── folder.svg
│ │ │ │ ├── img.svg
│ │ │ │ ├── inspect.svg
│ │ │ │ ├── light_to_dark.svg
│ │ │ │ ├── moon.svg
│ │ │ │ ├── pdf.svg
│ │ │ │ ├── photo.svg
│ │ │ │ ├── share.svg
│ │ │ │ ├── stars.svg
│ │ │ │ ├── sun.svg
│ │ │ │ ├── trending-down.svg
│ │ │ │ ├── trending-level.svg
│ │ │ │ ├── trending-up.svg
│ │ │ │ ├── txt.svg
│ │ │ │ ├── unknown-file.svg
│ │ │ │ ├── unlink.svg
│ │ │ │ └── xls.svg
│ │ │ ├── TableDeleteColumnIcon.tsx
│ │ │ ├── TableDeleteRowIcon.tsx
│ │ │ ├── TableInsertColumnIcon.tsx
│ │ │ ├── TableInsertRowIcon.tsx
│ │ │ ├── TrashIcon.tsx
│ │ │ ├── TrendingDownIcon.tsx
│ │ │ ├── TrendingLevelIcon.tsx
│ │ │ ├── TrendingUpIcon.tsx
│ │ │ ├── TxtIcon.tsx
│ │ │ ├── UnknownFileIcon.tsx
│ │ │ ├── UnlinkIcon.tsx
│ │ │ ├── UserIcon.tsx
│ │ │ ├── WarningIcon.tsx
│ │ │ └── XlsIcon.tsx
│ │ ├── IconProvider.tsx
│ │ ├── IconRegistryContext.tsx
│ │ ├── IFrame
│ │ │ ├── IFrame.md
│ │ │ ├── IFrame.module.scss
│ │ │ ├── IFrame.spec.ts
│ │ │ ├── IFrame.tsx
│ │ │ └── IFrameNative.tsx
│ │ ├── Image
│ │ │ ├── Image.md
│ │ │ ├── Image.module.scss
│ │ │ ├── Image.spec.ts
│ │ │ ├── Image.tsx
│ │ │ └── ImageNative.tsx
│ │ ├── Input
│ │ │ ├── index.ts
│ │ │ ├── InputAdornment.module.scss
│ │ │ ├── InputAdornment.tsx
│ │ │ ├── InputDivider.module.scss
│ │ │ ├── InputDivider.tsx
│ │ │ ├── InputLabel.module.scss
│ │ │ ├── InputLabel.tsx
│ │ │ ├── PartialInput.module.scss
│ │ │ └── PartialInput.tsx
│ │ ├── InspectButton
│ │ │ ├── InspectButton.module.scss
│ │ │ └── InspectButton.tsx
│ │ ├── Items
│ │ │ ├── Items.md
│ │ │ ├── Items.spec.ts
│ │ │ ├── Items.tsx
│ │ │ └── ItemsNative.tsx
│ │ ├── Link
│ │ │ ├── Link.md
│ │ │ ├── Link.module.scss
│ │ │ ├── Link.spec.ts
│ │ │ ├── Link.tsx
│ │ │ └── LinkNative.tsx
│ │ ├── List
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── List.md
│ │ │ ├── List.module.scss
│ │ │ ├── List.spec.ts
│ │ │ ├── List.tsx
│ │ │ └── ListNative.tsx
│ │ ├── Logo
│ │ │ ├── doc-resources
│ │ │ │ └── xmlui-logo.svg
│ │ │ ├── Logo.md
│ │ │ ├── Logo.tsx
│ │ │ └── LogoNative.tsx
│ │ ├── Markdown
│ │ │ ├── CodeText.module.scss
│ │ │ ├── CodeText.tsx
│ │ │ ├── Markdown.md
│ │ │ ├── Markdown.module.scss
│ │ │ ├── Markdown.spec.ts
│ │ │ ├── Markdown.tsx
│ │ │ ├── MarkdownNative.tsx
│ │ │ ├── parse-binding-expr.ts
│ │ │ └── utils.ts
│ │ ├── metadata-helpers.ts
│ │ ├── ModalDialog
│ │ │ ├── ConfirmationModalContextProvider.tsx
│ │ │ ├── Dialog.module.scss
│ │ │ ├── Dialog.tsx
│ │ │ ├── ModalDialog.md
│ │ │ ├── ModalDialog.module.scss
│ │ │ ├── ModalDialog.spec.ts
│ │ │ ├── ModalDialog.tsx
│ │ │ ├── ModalDialogNative.tsx
│ │ │ └── ModalVisibilityContext.tsx
│ │ ├── NavGroup
│ │ │ ├── NavGroup.md
│ │ │ ├── NavGroup.module.scss
│ │ │ ├── NavGroup.spec.ts
│ │ │ ├── NavGroup.tsx
│ │ │ ├── NavGroupContext.ts
│ │ │ └── NavGroupNative.tsx
│ │ ├── NavLink
│ │ │ ├── NavLink.md
│ │ │ ├── NavLink.module.scss
│ │ │ ├── NavLink.spec.ts
│ │ │ ├── NavLink.tsx
│ │ │ └── NavLinkNative.tsx
│ │ ├── NavPanel
│ │ │ ├── NavPanel.md
│ │ │ ├── NavPanel.module.scss
│ │ │ ├── NavPanel.spec.ts
│ │ │ ├── NavPanel.tsx
│ │ │ └── NavPanelNative.tsx
│ │ ├── NestedApp
│ │ │ ├── AppWithCodeView.module.scss
│ │ │ ├── AppWithCodeView.tsx
│ │ │ ├── AppWithCodeViewNative.tsx
│ │ │ ├── defaultProps.tsx
│ │ │ ├── logo.svg
│ │ │ ├── NestedApp.module.scss
│ │ │ ├── NestedApp.tsx
│ │ │ ├── NestedAppNative.tsx
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.tsx
│ │ │ └── utils.ts
│ │ ├── NoResult
│ │ │ ├── NoResult.md
│ │ │ ├── NoResult.module.scss
│ │ │ ├── NoResult.spec.ts
│ │ │ ├── NoResult.tsx
│ │ │ └── NoResultNative.tsx
│ │ ├── NumberBox
│ │ │ ├── numberbox-abstractions.ts
│ │ │ ├── NumberBox.md
│ │ │ ├── NumberBox.module.scss
│ │ │ ├── NumberBox.spec.ts
│ │ │ ├── NumberBox.tsx
│ │ │ └── NumberBoxNative.tsx
│ │ ├── Option
│ │ │ ├── Option.md
│ │ │ ├── Option.spec.ts
│ │ │ ├── Option.tsx
│ │ │ ├── OptionNative.tsx
│ │ │ └── OptionTypeProvider.tsx
│ │ ├── PageMetaTitle
│ │ │ ├── PageMetaTilteNative.tsx
│ │ │ ├── PageMetaTitle.md
│ │ │ ├── PageMetaTitle.spec.ts
│ │ │ └── PageMetaTitle.tsx
│ │ ├── Pages
│ │ │ ├── Page.md
│ │ │ ├── Pages.md
│ │ │ ├── Pages.module.scss
│ │ │ ├── Pages.tsx
│ │ │ └── PagesNative.tsx
│ │ ├── Pagination
│ │ │ ├── Pagination.md
│ │ │ ├── Pagination.module.scss
│ │ │ ├── Pagination.spec.ts
│ │ │ ├── Pagination.tsx
│ │ │ └── PaginationNative.tsx
│ │ ├── PositionedContainer
│ │ │ ├── PositionedContainer.module.scss
│ │ │ ├── PositionedContainer.tsx
│ │ │ └── PositionedContainerNative.tsx
│ │ ├── ProfileMenu
│ │ │ ├── ProfileMenu.module.scss
│ │ │ └── ProfileMenu.tsx
│ │ ├── ProgressBar
│ │ │ ├── ProgressBar.md
│ │ │ ├── ProgressBar.module.scss
│ │ │ ├── ProgressBar.spec.ts
│ │ │ ├── ProgressBar.tsx
│ │ │ └── ProgressBarNative.tsx
│ │ ├── Queue
│ │ │ ├── Queue.md
│ │ │ ├── Queue.spec.ts
│ │ │ ├── Queue.tsx
│ │ │ ├── queueActions.ts
│ │ │ └── QueueNative.tsx
│ │ ├── RadioGroup
│ │ │ ├── RadioGroup.md
│ │ │ ├── RadioGroup.module.scss
│ │ │ ├── RadioGroup.spec.ts
│ │ │ ├── RadioGroup.tsx
│ │ │ ├── RadioGroupNative.tsx
│ │ │ ├── RadioItem.tsx
│ │ │ └── RadioItemNative.tsx
│ │ ├── RealTimeAdapter
│ │ │ ├── RealTimeAdapter.tsx
│ │ │ └── RealTimeAdapterNative.tsx
│ │ ├── Redirect
│ │ │ ├── Redirect.md
│ │ │ ├── Redirect.spec.ts
│ │ │ └── Redirect.tsx
│ │ ├── ResponsiveBar
│ │ │ ├── README.md
│ │ │ ├── ResponsiveBar.md
│ │ │ ├── ResponsiveBar.module.scss
│ │ │ ├── ResponsiveBar.spec.ts
│ │ │ ├── ResponsiveBar.tsx
│ │ │ └── ResponsiveBarNative.tsx
│ │ ├── Select
│ │ │ ├── HiddenOption.tsx
│ │ │ ├── OptionContext.ts
│ │ │ ├── Select.md
│ │ │ ├── Select.module.scss
│ │ │ ├── Select.spec.ts
│ │ │ ├── Select.tsx
│ │ │ ├── SelectContext.tsx
│ │ │ └── SelectNative.tsx
│ │ ├── SelectionStore
│ │ │ ├── SelectionStore.md
│ │ │ ├── SelectionStore.tsx
│ │ │ └── SelectionStoreNative.tsx
│ │ ├── Slider
│ │ │ ├── Slider.md
│ │ │ ├── Slider.module.scss
│ │ │ ├── Slider.spec.ts
│ │ │ ├── Slider.tsx
│ │ │ └── SliderNative.tsx
│ │ ├── Slot
│ │ │ ├── Slot.md
│ │ │ ├── Slot.spec.ts
│ │ │ └── Slot.ts
│ │ ├── SlotItem.tsx
│ │ ├── SpaceFiller
│ │ │ ├── SpaceFiller.md
│ │ │ ├── SpaceFiller.module.scss
│ │ │ ├── SpaceFiller.spec.ts
│ │ │ ├── SpaceFiller.tsx
│ │ │ └── SpaceFillerNative.tsx
│ │ ├── Spinner
│ │ │ ├── Spinner.md
│ │ │ ├── Spinner.module.scss
│ │ │ ├── Spinner.spec.ts
│ │ │ ├── Spinner.tsx
│ │ │ └── SpinnerNative.tsx
│ │ ├── Splitter
│ │ │ ├── HSplitter.md
│ │ │ ├── HSplitter.spec.ts
│ │ │ ├── Splitter.md
│ │ │ ├── Splitter.module.scss
│ │ │ ├── Splitter.spec.ts
│ │ │ ├── Splitter.tsx
│ │ │ ├── SplitterNative.tsx
│ │ │ ├── utils.ts
│ │ │ ├── VSplitter.md
│ │ │ └── VSplitter.spec.ts
│ │ ├── Stack
│ │ │ ├── CHStack.md
│ │ │ ├── CHStack.spec.ts
│ │ │ ├── CVStack.md
│ │ │ ├── CVStack.spec.ts
│ │ │ ├── HStack.md
│ │ │ ├── HStack.spec.ts
│ │ │ ├── Stack.md
│ │ │ ├── Stack.module.scss
│ │ │ ├── Stack.spec.ts
│ │ │ ├── Stack.tsx
│ │ │ ├── StackNative.tsx
│ │ │ ├── VStack.md
│ │ │ └── VStack.spec.ts
│ │ ├── StickyBox
│ │ │ ├── StickyBox.md
│ │ │ ├── StickyBox.module.scss
│ │ │ ├── StickyBox.tsx
│ │ │ └── StickyBoxNative.tsx
│ │ ├── Switch
│ │ │ ├── Switch.md
│ │ │ ├── Switch.spec.ts
│ │ │ └── Switch.tsx
│ │ ├── Table
│ │ │ ├── doc-resources
│ │ │ │ └── list-component-data.js
│ │ │ ├── react-table-config.d.ts
│ │ │ ├── Table.md
│ │ │ ├── Table.module.scss
│ │ │ ├── Table.spec.ts
│ │ │ ├── Table.tsx
│ │ │ ├── TableNative.tsx
│ │ │ └── useRowSelection.tsx
│ │ ├── TableOfContents
│ │ │ ├── TableOfContents.module.scss
│ │ │ ├── TableOfContents.spec.ts
│ │ │ ├── TableOfContents.tsx
│ │ │ └── TableOfContentsNative.tsx
│ │ ├── Tabs
│ │ │ ├── TabContext.tsx
│ │ │ ├── TabItem.md
│ │ │ ├── TabItem.tsx
│ │ │ ├── TabItemNative.tsx
│ │ │ ├── Tabs.md
│ │ │ ├── Tabs.module.scss
│ │ │ ├── Tabs.spec.ts
│ │ │ ├── Tabs.tsx
│ │ │ └── TabsNative.tsx
│ │ ├── Text
│ │ │ ├── Text.md
│ │ │ ├── Text.module.scss
│ │ │ ├── Text.spec.ts
│ │ │ ├── Text.tsx
│ │ │ └── TextNative.tsx
│ │ ├── TextArea
│ │ │ ├── TextArea.md
│ │ │ ├── TextArea.module.scss
│ │ │ ├── TextArea.spec.ts
│ │ │ ├── TextArea.tsx
│ │ │ ├── TextAreaNative.tsx
│ │ │ ├── TextAreaResizable.tsx
│ │ │ └── useComposedRef.ts
│ │ ├── TextBox
│ │ │ ├── TextBox.md
│ │ │ ├── TextBox.module.scss
│ │ │ ├── TextBox.spec.ts
│ │ │ ├── TextBox.tsx
│ │ │ └── TextBoxNative.tsx
│ │ ├── Theme
│ │ │ ├── NotificationToast.tsx
│ │ │ ├── Theme.md
│ │ │ ├── Theme.module.scss
│ │ │ ├── Theme.spec.ts
│ │ │ ├── Theme.tsx
│ │ │ └── ThemeNative.tsx
│ │ ├── TimeInput
│ │ │ ├── TimeInput.md
│ │ │ ├── TimeInput.module.scss
│ │ │ ├── TimeInput.spec.ts
│ │ │ ├── TimeInput.tsx
│ │ │ ├── TimeInputNative.tsx
│ │ │ └── utils.ts
│ │ ├── Timer
│ │ │ ├── Timer.md
│ │ │ ├── Timer.spec.ts
│ │ │ ├── Timer.tsx
│ │ │ └── TimerNative.tsx
│ │ ├── Toggle
│ │ │ ├── Toggle.module.scss
│ │ │ └── Toggle.tsx
│ │ ├── ToneChangerButton
│ │ │ ├── ToneChangerButton.md
│ │ │ ├── ToneChangerButton.spec.ts
│ │ │ └── ToneChangerButton.tsx
│ │ ├── ToneSwitch
│ │ │ ├── ToneSwitch.md
│ │ │ ├── ToneSwitch.module.scss
│ │ │ ├── ToneSwitch.spec.ts
│ │ │ ├── ToneSwitch.tsx
│ │ │ └── ToneSwitchNative.tsx
│ │ ├── Tooltip
│ │ │ ├── Tooltip.md
│ │ │ ├── Tooltip.module.scss
│ │ │ ├── Tooltip.spec.ts
│ │ │ ├── Tooltip.tsx
│ │ │ └── TooltipNative.tsx
│ │ ├── Tree
│ │ │ ├── testData.ts
│ │ │ ├── Tree-dynamic.spec.ts
│ │ │ ├── Tree-icons.spec.ts
│ │ │ ├── Tree.md
│ │ │ ├── Tree.spec.ts
│ │ │ ├── TreeComponent.module.scss
│ │ │ ├── TreeComponent.tsx
│ │ │ └── TreeNative.tsx
│ │ ├── TreeDisplay
│ │ │ ├── TreeDisplay.md
│ │ │ ├── TreeDisplay.module.scss
│ │ │ ├── TreeDisplay.tsx
│ │ │ └── TreeDisplayNative.tsx
│ │ ├── ValidationSummary
│ │ │ ├── ValidationSummary.module.scss
│ │ │ └── ValidationSummary.tsx
│ │ └── VisuallyHidden.tsx
│ ├── components-core
│ │ ├── abstractions
│ │ │ ├── ComponentRenderer.ts
│ │ │ ├── LoaderRenderer.ts
│ │ │ ├── standalone.ts
│ │ │ └── treeAbstractions.ts
│ │ ├── action
│ │ │ ├── actions.ts
│ │ │ ├── APICall.tsx
│ │ │ ├── FileDownloadAction.tsx
│ │ │ ├── FileUploadAction.tsx
│ │ │ ├── NavigateAction.tsx
│ │ │ └── TimedAction.tsx
│ │ ├── ApiBoundComponent.tsx
│ │ ├── appContext
│ │ │ ├── date-functions.ts
│ │ │ ├── math-function.ts
│ │ │ └── misc-utils.ts
│ │ ├── AppContext.tsx
│ │ ├── behaviors
│ │ │ ├── Behavior.tsx
│ │ │ └── CoreBehaviors.tsx
│ │ ├── component-hooks.ts
│ │ ├── ComponentDecorator.tsx
│ │ ├── ComponentViewer.tsx
│ │ ├── CompoundComponent.tsx
│ │ ├── constants.ts
│ │ ├── DebugViewProvider.tsx
│ │ ├── descriptorHelper.ts
│ │ ├── devtools
│ │ │ ├── InspectorDialog.module.scss
│ │ │ ├── InspectorDialog.tsx
│ │ │ └── InspectorDialogVisibilityContext.tsx
│ │ ├── EngineError.ts
│ │ ├── event-handlers.ts
│ │ ├── InspectorButton.module.scss
│ │ ├── InspectorContext.tsx
│ │ ├── interception
│ │ │ ├── abstractions.ts
│ │ │ ├── ApiInterceptor.ts
│ │ │ ├── ApiInterceptorProvider.tsx
│ │ │ ├── apiInterceptorWorker.ts
│ │ │ ├── Backend.ts
│ │ │ ├── Errors.ts
│ │ │ ├── IndexedDb.ts
│ │ │ ├── initMock.ts
│ │ │ ├── InMemoryDb.ts
│ │ │ ├── ReadonlyCollection.ts
│ │ │ └── useApiInterceptorContext.tsx
│ │ ├── loader
│ │ │ ├── ApiLoader.tsx
│ │ │ ├── DataLoader.tsx
│ │ │ ├── ExternalDataLoader.tsx
│ │ │ ├── Loader.tsx
│ │ │ ├── MockLoaderRenderer.tsx
│ │ │ └── PageableLoader.tsx
│ │ ├── LoaderComponent.tsx
│ │ ├── markup-check.ts
│ │ ├── parts.ts
│ │ ├── renderers.ts
│ │ ├── rendering
│ │ │ ├── AppContent.tsx
│ │ │ ├── AppRoot.tsx
│ │ │ ├── AppWrapper.tsx
│ │ │ ├── buildProxy.ts
│ │ │ ├── collectFnVarDeps.ts
│ │ │ ├── ComponentAdapter.tsx
│ │ │ ├── ComponentWrapper.tsx
│ │ │ ├── Container.tsx
│ │ │ ├── containers.ts
│ │ │ ├── ContainerWrapper.tsx
│ │ │ ├── ErrorBoundary.module.scss
│ │ │ ├── ErrorBoundary.tsx
│ │ │ ├── InvalidComponent.module.scss
│ │ │ ├── InvalidComponent.tsx
│ │ │ ├── nodeUtils.ts
│ │ │ ├── reducer.ts
│ │ │ ├── renderChild.tsx
│ │ │ ├── StandaloneComponent.tsx
│ │ │ ├── StateContainer.tsx
│ │ │ ├── UnknownComponent.module.scss
│ │ │ ├── UnknownComponent.tsx
│ │ │ └── valueExtractor.ts
│ │ ├── reportEngineError.ts
│ │ ├── RestApiProxy.ts
│ │ ├── script-runner
│ │ │ ├── asyncProxy.ts
│ │ │ ├── AttributeValueParser.ts
│ │ │ ├── bannedFunctions.ts
│ │ │ ├── BindingTreeEvaluationContext.ts
│ │ │ ├── eval-tree-async.ts
│ │ │ ├── eval-tree-common.ts
│ │ │ ├── eval-tree-sync.ts
│ │ │ ├── ParameterParser.ts
│ │ │ ├── process-statement-async.ts
│ │ │ ├── process-statement-common.ts
│ │ │ ├── process-statement-sync.ts
│ │ │ ├── ScriptingSourceTree.ts
│ │ │ ├── simplify-expression.ts
│ │ │ ├── statement-queue.ts
│ │ │ └── visitors.ts
│ │ ├── StandaloneApp.tsx
│ │ ├── StandaloneExtensionManager.ts
│ │ ├── TableOfContentsContext.tsx
│ │ ├── theming
│ │ │ ├── _themes.scss
│ │ │ ├── component-layout-resolver.ts
│ │ │ ├── extendThemeUtils.ts
│ │ │ ├── hvar.ts
│ │ │ ├── layout-resolver.ts
│ │ │ ├── parse-layout-props.ts
│ │ │ ├── StyleContext.tsx
│ │ │ ├── StyleRegistry.ts
│ │ │ ├── ThemeContext.tsx
│ │ │ ├── ThemeProvider.tsx
│ │ │ ├── themes
│ │ │ │ ├── base-utils.ts
│ │ │ │ ├── palette.ts
│ │ │ │ ├── root.ts
│ │ │ │ ├── solid.ts
│ │ │ │ ├── theme-colors.ts
│ │ │ │ └── xmlui.ts
│ │ │ ├── themeVars.module.scss
│ │ │ ├── themeVars.ts
│ │ │ ├── transformThemeVars.ts
│ │ │ └── utils.ts
│ │ ├── utils
│ │ │ ├── actionUtils.ts
│ │ │ ├── audio-utils.ts
│ │ │ ├── base64-utils.ts
│ │ │ ├── compound-utils.ts
│ │ │ ├── css-utils.ts
│ │ │ ├── DataLoaderQueryKeyGenerator.ts
│ │ │ ├── date-utils.ts
│ │ │ ├── extractParam.ts
│ │ │ ├── hooks.tsx
│ │ │ ├── LruCache.ts
│ │ │ ├── mergeProps.ts
│ │ │ ├── misc.ts
│ │ │ ├── request-params.ts
│ │ │ ├── statementUtils.ts
│ │ │ └── treeUtils.ts
│ │ └── xmlui-parser.ts
│ ├── index-standalone.ts
│ ├── index.scss
│ ├── index.ts
│ ├── language-server
│ │ ├── server-common.ts
│ │ ├── server-web-worker.ts
│ │ ├── server.ts
│ │ ├── services
│ │ │ ├── common
│ │ │ │ ├── docs-generation.ts
│ │ │ │ ├── lsp-utils.ts
│ │ │ │ ├── metadata-utils.ts
│ │ │ │ └── syntax-node-utilities.ts
│ │ │ ├── completion.ts
│ │ │ ├── diagnostic.ts
│ │ │ ├── format.ts
│ │ │ └── hover.ts
│ │ └── xmlui-metadata-generated.js
│ ├── logging
│ │ ├── LoggerContext.tsx
│ │ ├── LoggerInitializer.tsx
│ │ ├── LoggerService.ts
│ │ └── xmlui.ts
│ ├── logo.svg
│ ├── parsers
│ │ ├── common
│ │ │ ├── GenericToken.ts
│ │ │ ├── InputStream.ts
│ │ │ └── utils.ts
│ │ ├── scripting
│ │ │ ├── code-behind-collect.ts
│ │ │ ├── Lexer.ts
│ │ │ ├── modules.ts
│ │ │ ├── Parser.ts
│ │ │ ├── ParserError.ts
│ │ │ ├── ScriptingNodeTypes.ts
│ │ │ ├── TokenTrait.ts
│ │ │ ├── TokenType.ts
│ │ │ └── tree-visitor.ts
│ │ ├── style-parser
│ │ │ ├── errors.ts
│ │ │ ├── source-tree.ts
│ │ │ ├── StyleInputStream.ts
│ │ │ ├── StyleLexer.ts
│ │ │ ├── StyleParser.ts
│ │ │ └── tokens.ts
│ │ └── xmlui-parser
│ │ ├── CharacterCodes.ts
│ │ ├── diagnostics.ts
│ │ ├── fileExtensions.ts
│ │ ├── index.ts
│ │ ├── lint.ts
│ │ ├── parser.ts
│ │ ├── ParserError.ts
│ │ ├── scanner.ts
│ │ ├── syntax-kind.ts
│ │ ├── syntax-node.ts
│ │ ├── transform.ts
│ │ ├── utils.ts
│ │ ├── xmlui-serializer.ts
│ │ └── xmlui-tree.ts
│ ├── react-app-env.d.ts
│ ├── syntax
│ │ ├── monaco
│ │ │ ├── grammar.monacoLanguage.ts
│ │ │ ├── index.ts
│ │ │ ├── xmlui-dark.ts
│ │ │ ├── xmlui-light.ts
│ │ │ └── xmluiscript.monacoLanguage.ts
│ │ └── textMate
│ │ ├── index.ts
│ │ ├── xmlui-dark.json
│ │ ├── xmlui-light.json
│ │ ├── xmlui.json
│ │ └── xmlui.tmLanguage.json
│ ├── testing
│ │ ├── assertions.ts
│ │ ├── component-test-helpers.ts
│ │ ├── ComponentDrivers.ts
│ │ ├── drivers
│ │ │ ├── DateInputDriver.ts
│ │ │ ├── index.ts
│ │ │ ├── ModalDialogDriver.ts
│ │ │ ├── NumberBoxDriver.ts
│ │ │ ├── TextBoxDriver.ts
│ │ │ ├── TimeInputDriver.ts
│ │ │ ├── TimerDriver.ts
│ │ │ └── TreeDriver.ts
│ │ ├── fixtures.ts
│ │ ├── index.ts
│ │ ├── infrastructure
│ │ │ ├── index.html
│ │ │ ├── main.tsx
│ │ │ ├── public
│ │ │ │ ├── mockServiceWorker.js
│ │ │ │ ├── resources
│ │ │ │ │ ├── bell.svg
│ │ │ │ │ ├── box.svg
│ │ │ │ │ ├── doc.svg
│ │ │ │ │ ├── eye.svg
│ │ │ │ │ ├── flower-640x480.jpg
│ │ │ │ │ ├── sun.svg
│ │ │ │ │ ├── test-image-100x100.jpg
│ │ │ │ │ └── txt.svg
│ │ │ │ └── serve.json
│ │ │ └── TestBed.tsx
│ │ └── themed-app-test-helpers.ts
│ └── vite-env.d.ts
├── tests
│ ├── components
│ │ ├── CodeBlock
│ │ │ └── hightlight-code.test.ts
│ │ ├── playground-pattern.test.ts
│ │ └── Tree
│ │ └── Tree-states.test.ts
│ ├── components-core
│ │ ├── abstractions
│ │ │ └── treeAbstractions.test.ts
│ │ ├── container
│ │ │ └── buildProxy.test.ts
│ │ ├── interception
│ │ │ ├── orderBy.test.ts
│ │ │ ├── ReadOnlyCollection.test.ts
│ │ │ └── request-param-converter.test.ts
│ │ ├── scripts-runner
│ │ │ ├── AttributeValueParser.test.ts
│ │ │ ├── eval-tree-arrow-async.test.ts
│ │ │ ├── eval-tree-arrow.test.ts
│ │ │ ├── eval-tree-func-decl-async.test.ts
│ │ │ ├── eval-tree-func-decl.test.ts
│ │ │ ├── eval-tree-pre-post.test.ts
│ │ │ ├── eval-tree-regression.test.ts
│ │ │ ├── eval-tree.test.ts
│ │ │ ├── function-proxy.test.ts
│ │ │ ├── parser-regression.test.ts
│ │ │ ├── process-event.test.ts
│ │ │ ├── process-function.test.ts
│ │ │ ├── process-implicit-context.test.ts
│ │ │ ├── process-statement-asgn.test.ts
│ │ │ ├── process-statement-destruct.test.ts
│ │ │ ├── process-statement-regs.test.ts
│ │ │ ├── process-statement-sync.test.ts
│ │ │ ├── process-statement.test.ts
│ │ │ ├── process-switch-sync.test.ts
│ │ │ ├── process-switch.test.ts
│ │ │ ├── process-try-sync.test.ts
│ │ │ ├── process-try.test.ts
│ │ │ └── test-helpers.ts
│ │ ├── test-metadata-handler.ts
│ │ ├── theming
│ │ │ ├── border-segments.test.ts
│ │ │ ├── component-layout.resolver.test.ts
│ │ │ ├── layout-property-parser.test.ts
│ │ │ ├── layout-resolver.test.ts
│ │ │ ├── layout-resolver2.test.ts
│ │ │ ├── layout-vp-override.test.ts
│ │ │ └── padding-segments.test.ts
│ │ └── utils
│ │ ├── date-utils.test.ts
│ │ ├── format-human-elapsed-time.test.ts
│ │ └── LruCache.test.ts
│ ├── language-server
│ │ ├── completion.test.ts
│ │ ├── format.test.ts
│ │ ├── hover.test.ts
│ │ └── mockData.ts
│ └── parsers
│ ├── common
│ │ └── input-stream.test.ts
│ ├── markdown
│ │ └── parse-binding-expression.test.ts
│ ├── parameter-parser.test.ts
│ ├── paremeter-parser.test.ts
│ ├── scripting
│ │ ├── eval-tree-arrow.test.ts
│ │ ├── eval-tree-pre-post.test.ts
│ │ ├── eval-tree.test.ts
│ │ ├── function-proxy.test.ts
│ │ ├── lexer-literals.test.ts
│ │ ├── lexer-misc.test.ts
│ │ ├── module-parse.test.ts
│ │ ├── parser-arrow.test.ts
│ │ ├── parser-assignments.test.ts
│ │ ├── parser-binary.test.ts
│ │ ├── parser-destructuring.test.ts
│ │ ├── parser-errors.test.ts
│ │ ├── parser-expressions.test.ts
│ │ ├── parser-function.test.ts
│ │ ├── parser-literals.test.ts
│ │ ├── parser-primary.test.ts
│ │ ├── parser-regex.test.ts
│ │ ├── parser-statements.test.ts
│ │ ├── parser-unary.test.ts
│ │ ├── process-event.test.ts
│ │ ├── process-implicit-context.test.ts
│ │ ├── process-statement-asgn.test.ts
│ │ ├── process-statement-destruct.test.ts
│ │ ├── process-statement-regs.test.ts
│ │ ├── process-statement-sync.test.ts
│ │ ├── process-statement.test.ts
│ │ ├── process-switch-sync.test.ts
│ │ ├── process-switch.test.ts
│ │ ├── process-try-sync.test.ts
│ │ ├── process-try.test.ts
│ │ ├── simplify-expression.test.ts
│ │ ├── statement-hooks.test.ts
│ │ └── test-helpers.ts
│ ├── style-parser
│ │ ├── generateHvarChain.test.ts
│ │ ├── parseHVar.test.ts
│ │ ├── parser.test.ts
│ │ └── tokens.test.ts
│ └── xmlui
│ ├── lint.test.ts
│ ├── parser.test.ts
│ ├── scanner.test.ts
│ ├── transform.attr.test.ts
│ ├── transform.circular.test.ts
│ ├── transform.element.test.ts
│ ├── transform.errors.test.ts
│ ├── transform.escape.test.ts
│ ├── transform.regression.test.ts
│ ├── transform.script.test.ts
│ ├── transform.test.ts
│ └── xmlui.ts
├── tests-e2e
│ ├── api-bound-component-regression.spec.ts
│ ├── api-call-as-extracted-component.spec.ts
│ ├── assign-to-object-or-array-regression.spec.ts
│ ├── binding-regression.spec.ts
│ ├── children-as-template-context-vars.spec.ts
│ ├── compound-component.spec.ts
│ ├── context-vars-regression.spec.ts
│ ├── data-bindings.spec.ts
│ ├── datasource-and-api-usage-in-var.spec.ts
│ ├── datasource-direct-binding.spec.ts
│ ├── datasource-onLoaded-regression.spec.ts
│ ├── modify-array-item-regression.spec.ts
│ ├── namespaces.spec.ts
│ ├── push-to-array-regression.spec.ts
│ ├── screen-breakpoints.spec.ts
│ ├── scripting.spec.ts
│ ├── state-scope-in-pages.spec.ts
│ └── state-var-scopes.spec.ts
├── tsconfig.bin.json
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── vitest.config.ts
```
# Files
--------------------------------------------------------------------------------
/xmlui/tests/parsers/scripting/lexer-misc.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describe, expect, it } from "vitest";
2 | import { Lexer } from "../../../src/parsers/scripting/Lexer";
3 | import { InputStream } from "../../../src/parsers/common/InputStream";
4 | import { TokenType } from "../../../src/parsers/scripting/TokenType";
5 |
6 | describe("Lexer - miscellaneous", () => {
7 | it("Empty", () => {
8 | // --- Arrange
9 | const source = "";
10 | const wLexer = new Lexer(new InputStream(source));
11 |
12 | // --- Act
13 | const next = wLexer.get();
14 |
15 | // --- Assert
16 | expect(next.type).equal(TokenType.Eof);
17 | expect(next.text).equal(source);
18 | expect(next.startPosition).equal(0);
19 | expect(next.endPosition).equal(source.length);
20 | expect(next.startLine).equal(1);
21 | expect(next.endLine).equal(1);
22 | expect(next.startColumn).equal(0);
23 | expect(next.endColumn).equal(source.length);
24 | });
25 |
26 | const miscCases = [
27 | { src: "...", exp: TokenType.Spread },
28 | { src: ";", exp: TokenType.Semicolon },
29 | { src: "/", exp: TokenType.Divide },
30 | { src: "**", exp: TokenType.Exponent },
31 | { src: "*", exp: TokenType.Multiply },
32 | { src: "%", exp: TokenType.Remainder },
33 | { src: "+", exp: TokenType.Plus },
34 | { src: "-", exp: TokenType.Minus },
35 | { src: "^", exp: TokenType.BitwiseXor },
36 | { src: "|", exp: TokenType.BitwiseOr },
37 | { src: "||", exp: TokenType.LogicalOr },
38 | { src: "&", exp: TokenType.BitwiseAnd },
39 | { src: "&&", exp: TokenType.LogicalAnd },
40 | { src: ",", exp: TokenType.Comma },
41 | { src: "(", exp: TokenType.LParent },
42 | { src: ")", exp: TokenType.RParent },
43 | { src: ":", exp: TokenType.Colon },
44 | { src: "[", exp: TokenType.LSquare },
45 | { src: "]", exp: TokenType.RSquare },
46 | { src: "?", exp: TokenType.QuestionMark },
47 | { src: "??", exp: TokenType.NullCoalesce },
48 | { src: "?.", exp: TokenType.OptionalChaining },
49 | { src: "{", exp: TokenType.LBrace },
50 | { src: "}", exp: TokenType.RBrace },
51 | { src: "=", exp: TokenType.Assignment },
52 | { src: "==", exp: TokenType.Equal },
53 | { src: "===", exp: TokenType.StrictEqual },
54 | { src: "!", exp: TokenType.LogicalNot },
55 | { src: "!=", exp: TokenType.NotEqual },
56 | { src: "!==", exp: TokenType.StrictNotEqual },
57 | { src: "<", exp: TokenType.LessThan },
58 | { src: "<=", exp: TokenType.LessThanOrEqual },
59 | { src: "<<", exp: TokenType.ShiftLeft },
60 | { src: ">", exp: TokenType.GreaterThan },
61 | { src: ">=", exp: TokenType.GreaterThanOrEqual },
62 | { src: ">>", exp: TokenType.SignedShiftRight },
63 | { src: ">>>", exp: TokenType.ShiftRight },
64 | { src: ".", exp: TokenType.Dot },
65 | { src: "thisId", exp: TokenType.Identifier },
66 | { src: "_other145$", exp: TokenType.Identifier },
67 | { src: "$loader", exp: TokenType.Identifier },
68 | { src: "Infinity", exp: TokenType.Infinity },
69 | { src: "NaN", exp: TokenType.NaN },
70 | { src: "true", exp: TokenType.True },
71 | { src: "false", exp: TokenType.False },
72 | { src: "$item", exp: TokenType.Identifier },
73 | { src: "null", exp: TokenType.Null },
74 | { src: "undefined", exp: TokenType.Undefined },
75 | { src: "in", exp: TokenType.In },
76 | { src: "+=", exp: TokenType.AddAssignment },
77 | { src: "-=", exp: TokenType.SubtractAssignment },
78 | { src: "**=", exp: TokenType.ExponentAssignment },
79 | { src: "*=", exp: TokenType.MultiplyAssignment },
80 | { src: "/=", exp: TokenType.DivideAssignment },
81 | { src: "%=", exp: TokenType.RemainderAssignment },
82 | { src: "<<=", exp: TokenType.ShiftLeftAssignment },
83 | { src: ">>=", exp: TokenType.SignedShiftRightAssignment },
84 | { src: ">>>=", exp: TokenType.ShiftRightAssignment },
85 | { src: "&=", exp: TokenType.BitwiseAndAssignment },
86 | { src: "&&=", exp: TokenType.LogicalAndAssignment },
87 | { src: "^=", exp: TokenType.BitwiseXorAssignment },
88 | { src: "|=", exp: TokenType.BitwiseOrAssignment },
89 | { src: "||=", exp: TokenType.LogicalOrAssignment },
90 | { src: "??=", exp: TokenType.NullCoalesceAssignment },
91 | { src: "=>", exp: TokenType.Arrow },
92 | { src: "++", exp: TokenType.IncOp },
93 | { src: "--", exp: TokenType.DecOp },
94 | { src: "let", exp: TokenType.Let },
95 | { src: "const", exp: TokenType.Const },
96 | { src: "var", exp: TokenType.Var },
97 | { src: "if", exp: TokenType.If },
98 | { src: "else", exp: TokenType.Else },
99 | { src: "return", exp: TokenType.Return },
100 | { src: "break", exp: TokenType.Break },
101 | { src: "continue", exp: TokenType.Continue },
102 | { src: "do", exp: TokenType.Do },
103 | { src: "while", exp: TokenType.While },
104 | { src: "for", exp: TokenType.For },
105 | { src: "of", exp: TokenType.Of },
106 | { src: "try", exp: TokenType.Try },
107 | { src: "catch", exp: TokenType.Catch },
108 | { src: "finally", exp: TokenType.Finally },
109 | { src: "throw", exp: TokenType.Throw },
110 | { src: "switch", exp: TokenType.Switch },
111 | { src: "case", exp: TokenType.Case },
112 | { src: "default", exp: TokenType.Default },
113 | { src: "delete", exp: TokenType.Delete },
114 | { src: "function", exp: TokenType.Function },
115 | { src: "as", exp: TokenType.As },
116 | ];
117 | miscCases.forEach(c => {
118 | it(`Token ${c.src} #1`, () => {
119 | const source = c.src;
120 | const wLexer = new Lexer(new InputStream(source));
121 |
122 | // --- Act
123 | const next = wLexer.get();
124 |
125 | // --- Assert
126 | expect(next.type).equal(c.exp);
127 | expect(next.text).equal(source);
128 | expect(next.startPosition).equal(0);
129 | expect(next.endPosition).equal(source.length);
130 | expect(next.startLine).equal(1);
131 | expect(next.endLine).equal(1);
132 | expect(next.startColumn).equal(0);
133 | expect(next.endColumn).equal(source.length);
134 | });
135 |
136 | it(`Token ${c.src} #2`, () => {
137 | const source = ` \t \r ${c.src}`;
138 | const wLexer = new Lexer(new InputStream(source));
139 |
140 | // --- Act
141 | const next = wLexer.get();
142 |
143 | // --- Assert
144 | expect(next.type).equal(c.exp);
145 | expect(next.text).equal(c.src);
146 | expect(next.startPosition).equal(5);
147 | expect(next.endPosition).equal(source.length);
148 | expect(next.startLine).equal(1);
149 | expect(next.endLine).equal(1);
150 | expect(next.startColumn).equal(5);
151 | expect(next.endColumn).equal(source.length);
152 | });
153 |
154 | it(`Token ${c.src} #3`, () => {
155 | const source = ` /* c */ ${c.src}`;
156 | const wLexer = new Lexer(new InputStream(source));
157 |
158 | // --- Act
159 | const next = wLexer.get();
160 |
161 | // --- Assert
162 | expect(next.type).equal(c.exp);
163 | expect(next.text).equal(c.src);
164 | expect(next.startPosition).equal(9);
165 | expect(next.endPosition).equal(source.length);
166 | expect(next.startLine).equal(1);
167 | expect(next.endLine).equal(1);
168 | expect(next.startColumn).equal(9);
169 | expect(next.endColumn).equal(source.length);
170 | });
171 |
172 | it(`Token ${c.src} #4`, () => {
173 | const source = `${c.src} \t \r `;
174 | const wLexer = new Lexer(new InputStream(source));
175 |
176 | // --- Act
177 | const next = wLexer.get();
178 |
179 | // --- Assert
180 | expect(next.type).equal(c.exp);
181 | expect(next.text).equal(c.src);
182 | expect(next.startPosition).equal(0);
183 | expect(next.endPosition).equal(c.src.length);
184 | expect(next.startLine).equal(1);
185 | expect(next.endLine).equal(1);
186 | expect(next.startColumn).equal(0);
187 | expect(next.endColumn).equal(c.src.length);
188 | });
189 |
190 | it(`Token ${c.src} #5`, () => {
191 | const source = `${c.src} // c`;
192 | const wLexer = new Lexer(new InputStream(source));
193 |
194 | // --- Act
195 | const next = wLexer.get();
196 | const trail1 = wLexer.get(true);
197 | const trail2 = wLexer.get(true);
198 | const trail3 = wLexer.get();
199 |
200 | // --- Assert
201 | expect(next.type).equal(c.exp);
202 | expect(next.text).equal(c.src);
203 | expect(next.startPosition).equal(0);
204 | expect(next.endPosition).equal(c.src.length);
205 | expect(next.startLine).equal(1);
206 | expect(next.endLine).equal(1);
207 | expect(next.startColumn).equal(0);
208 | expect(next.endColumn).equal(c.src.length);
209 | expect(trail1.type).equal(TokenType.Ws);
210 | expect(trail2.type).equal(TokenType.EolComment);
211 | expect(trail3.type).equal(TokenType.Eof);
212 | });
213 | });
214 | });
215 |
```
--------------------------------------------------------------------------------
/xmlui/tests/components-core/theming/layout-resolver2.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { describe, expect, it } from "vitest";
2 | import { resolveLayoutProps, toCssVar } from "../../../src/components-core/theming/layout-resolver";
3 |
4 | describe("Layout resolver 2", () => {
5 | const THEME_ID = "$some-theme-id_x";
6 | const THEME_ID_VALUE = toCssVar(THEME_ID);
7 | const THEME_ID2 = "$some-theme-id2";
8 | const THEME_ID2_VALUE = toCssVar(THEME_ID2);
9 | const THEME_ID3 = "$some-theme-id3";
10 | const THEME_ID3_VALUE = toCssVar(THEME_ID3);
11 | const THEME_ID4 = "$some-theme-id4";
12 | const THEME_ID4_VALUE = toCssVar(THEME_ID4);
13 |
14 | // --- Borders
15 | it("textDecoration", () => {
16 | const PROP = "textDecoration";
17 | const VALUE = "underline solid red";
18 | const result = resolveLayoutProps({ [PROP]: VALUE });
19 | expect(result.cssProps[PROP]).toBe(VALUE);
20 | expect(result.issues.has(PROP)).toBe(false);
21 | });
22 |
23 | it("textDecorationLine", () => {
24 | const PROP = "textDecorationLine";
25 | const VALUE = "overline";
26 | const result = resolveLayoutProps({ [PROP]: VALUE });
27 | expect(result.cssProps[PROP]).toBe(VALUE);
28 | expect(result.issues.has(PROP)).toBe(false);
29 | });
30 |
31 | it("textDecorationColor", () => {
32 | const PROP = "textDecorationColor";
33 | const VALUE = "blue";
34 | const result = resolveLayoutProps({ [PROP]: VALUE });
35 | expect(result.cssProps[PROP]).toBe(VALUE);
36 | expect(result.issues.has(PROP)).toBe(false);
37 | });
38 |
39 | it("textDecorationStyle", () => {
40 | const PROP = "textDecorationStyle";
41 | const VALUE = "dotted";
42 | const result = resolveLayoutProps({ [PROP]: VALUE });
43 | expect(result.cssProps[PROP]).toBe(VALUE);
44 | expect(result.issues.has(PROP)).toBe(false);
45 | });
46 |
47 | it("textDecorationThickness", () => {
48 | const PROP = "textDecorationThickness";
49 | const VALUE = "8px";
50 | const result = resolveLayoutProps({ [PROP]: VALUE });
51 | expect(result.cssProps[PROP]).toBe(VALUE);
52 | expect(result.issues.has(PROP)).toBe(false);
53 | });
54 |
55 | it("textUnderlineOffset", () => {
56 | const PROP = "textUnderlineOffset";
57 | const VALUE = "8px";
58 | const result = resolveLayoutProps({ [PROP]: VALUE });
59 | expect(result.cssProps[PROP]).toBe(VALUE);
60 | expect(result.issues.has(PROP)).toBe(false);
61 | });
62 |
63 | it("outline", () => {
64 | const PROP = "outline";
65 | const VALUE = "3px solid green";
66 | const result = resolveLayoutProps({ [PROP]: VALUE });
67 | expect(result.cssProps[PROP]).toBe(VALUE);
68 | expect(result.issues.has(PROP)).toBe(false);
69 | });
70 |
71 | it("outlineWidth", () => {
72 | const PROP = "outlineWidth";
73 | const VALUE = "3px";
74 | const result = resolveLayoutProps({ [PROP]: VALUE });
75 | expect(result.cssProps[PROP]).toBe(VALUE);
76 | expect(result.issues.has(PROP)).toBe(false);
77 | });
78 |
79 | it("outlineColor", () => {
80 | const PROP = "outlineColor";
81 | const VALUE = "green";
82 | const result = resolveLayoutProps({ [PROP]: VALUE });
83 | expect(result.cssProps[PROP]).toBe(VALUE);
84 | expect(result.issues.has(PROP)).toBe(false);
85 | });
86 |
87 | it("outlineStyle", () => {
88 | const PROP = "outlineStyle";
89 | const VALUE = "dotted";
90 | const result = resolveLayoutProps({ [PROP]: VALUE });
91 | expect(result.cssProps[PROP]).toBe(VALUE);
92 | expect(result.issues.has(PROP)).toBe(false);
93 | });
94 |
95 | it("outlineOffset", () => {
96 | const PROP = "outlineOffset";
97 | const VALUE = "5px";
98 | const result = resolveLayoutProps({ [PROP]: VALUE });
99 | expect(result.cssProps[PROP]).toBe(VALUE);
100 | expect(result.issues.has(PROP)).toBe(false);
101 | });
102 |
103 | it("borderHorizontal: 1px solid red", () => {
104 | const PROP = "borderHorizontal";
105 | const VALUE = "1px solid red";
106 | const result = resolveLayoutProps({ [PROP]: VALUE });
107 | expect(result.cssProps.borderLeft).toBe(VALUE);
108 | expect(result.cssProps.borderRight).toBe(VALUE);
109 | expect(result.issues.has(PROP)).toBe(false);
110 | });
111 |
112 | it("borderLeft overwrites borderHorizontal", () => {
113 | const PROP = "borderHorizontal";
114 | const VALUE = "1px solid red";
115 | const result = resolveLayoutProps({ [PROP]: VALUE, borderLeft: "2px solid blue" });
116 | expect(result.cssProps.borderLeft).toBe("2px solid blue");
117 | expect(result.cssProps.borderRight).toBe(VALUE);
118 | expect(result.issues.has(PROP)).toBe(false);
119 | });
120 |
121 | it("borderRight overwrites borderHorizontal", () => {
122 | const PROP = "borderHorizontal";
123 | const VALUE = "1px solid red";
124 | const result = resolveLayoutProps({ [PROP]: VALUE, borderRight: "2px solid blue" });
125 | expect(result.cssProps.borderLeft).toBe(VALUE);
126 | expect(result.cssProps.borderRight).toBe("2px solid blue");
127 | expect(result.issues.has(PROP)).toBe(false);
128 | });
129 |
130 | it("borderHorizontal (themeVar) 1", () => {
131 | const PROP = "borderHorizontal";
132 | const VALUE = THEME_ID;
133 | const result = resolveLayoutProps({ [PROP]: VALUE });
134 | expect(result.cssProps.borderLeft).toBe(THEME_ID_VALUE);
135 | expect(result.cssProps.borderRight).toBe(THEME_ID_VALUE);
136 | expect(result.issues.has(PROP)).toBe(false);
137 | });
138 |
139 | it("borderHorizontal (themeVar) 2", () => {
140 | const PROP = "borderHorizontal";
141 | const VALUE = `${THEME_ID} ${THEME_ID2}`;
142 | const result = resolveLayoutProps({ [PROP]: VALUE });
143 | expect(result.cssProps.borderLeft).toBe(`${THEME_ID_VALUE} ${THEME_ID2_VALUE}`);
144 | expect(result.cssProps.borderRight).toBe(`${THEME_ID_VALUE} ${THEME_ID2_VALUE}`);
145 | expect(result.issues.has(PROP)).toBe(false);
146 | });
147 |
148 | it("borderHorizontal (themeVar) 3", () => {
149 | const PROP = "borderHorizontal";
150 | const VALUE = `${THEME_ID} ${THEME_ID2} ${THEME_ID3}`;
151 | const result = resolveLayoutProps({ [PROP]: VALUE });
152 | expect(result.cssProps.borderLeft).toBe(`${THEME_ID_VALUE} ${THEME_ID2_VALUE} ${THEME_ID3_VALUE}`);
153 | expect(result.cssProps.borderRight).toBe(`${THEME_ID_VALUE} ${THEME_ID2_VALUE} ${THEME_ID3_VALUE}`);
154 | expect(result.issues.has(PROP)).toBe(false);
155 | });
156 |
157 | it("borderVertical: 1px solid red", () => {
158 | const PROP = "borderVertical";
159 | const VALUE = "1px solid red";
160 | const result = resolveLayoutProps({ [PROP]: VALUE });
161 | expect(result.cssProps.borderTop).toBe(VALUE);
162 | expect(result.cssProps.borderBottom).toBe(VALUE);
163 | expect(result.issues.has(PROP)).toBe(false);
164 | });
165 |
166 | it("borderVertical (themeVar) 1", () => {
167 | const PROP = "borderVertical";
168 | const VALUE = THEME_ID;
169 | const result = resolveLayoutProps({ [PROP]: VALUE });
170 | expect(result.cssProps.borderTop).toBe(THEME_ID_VALUE);
171 | expect(result.cssProps.borderBottom).toBe(THEME_ID_VALUE);
172 | expect(result.issues.has(PROP)).toBe(false);
173 | });
174 |
175 | it("borderVertical (themeVar) 2", () => {
176 | const PROP = "borderVertical";
177 | const VALUE = `${THEME_ID} ${THEME_ID2}`;
178 | const result = resolveLayoutProps({ [PROP]: VALUE });
179 | expect(result.cssProps.borderTop).toBe(`${THEME_ID_VALUE} ${THEME_ID2_VALUE}`);
180 | expect(result.cssProps.borderBottom).toBe(`${THEME_ID_VALUE} ${THEME_ID2_VALUE}`);
181 | expect(result.issues.has(PROP)).toBe(false);
182 | });
183 |
184 | it("borderVertical (themeVar) 3", () => {
185 | const PROP = "borderVertical";
186 | const VALUE = `${THEME_ID} ${THEME_ID2} ${THEME_ID3}`;
187 | const result = resolveLayoutProps({ [PROP]: VALUE });
188 | expect(result.cssProps.borderTop).toBe(`${THEME_ID_VALUE} ${THEME_ID2_VALUE} ${THEME_ID3_VALUE}`);
189 | expect(result.cssProps.borderBottom).toBe(`${THEME_ID_VALUE} ${THEME_ID2_VALUE} ${THEME_ID3_VALUE}`);
190 | expect(result.issues.has(PROP)).toBe(false);
191 | });
192 |
193 | it("borderTop overwrites borderVertical", () => {
194 | const PROP = "borderVertical";
195 | const VALUE = "1px solid red";
196 | const result = resolveLayoutProps({ [PROP]: VALUE, borderTop: "2px solid blue" });
197 | expect(result.cssProps.borderTop).toBe("2px solid blue");
198 | expect(result.cssProps.borderBottom).toBe(VALUE);
199 | expect(result.issues.has(PROP)).toBe(false);
200 | });
201 |
202 | it("borderBottom overwrites borderVertical", () => {
203 | const PROP = "borderVertical";
204 | const VALUE = "1px solid red";
205 | const result = resolveLayoutProps({ [PROP]: VALUE, borderBottom: "2px solid blue" });
206 | expect(result.cssProps.borderTop).toBe(VALUE);
207 | expect(result.cssProps.borderBottom).toBe("2px solid blue");
208 | expect(result.issues.has(PROP)).toBe(false);
209 | });
210 | });
211 |
```
--------------------------------------------------------------------------------
/xmlui/src/components-core/interception/IndexedDb.ts:
--------------------------------------------------------------------------------
```typescript
1 | import type { Table } from "dexie";
2 | import Dexie from "dexie";
3 |
4 | import { ReadOnlyCollection } from "../interception/ReadonlyCollection";
5 | import type { IDatabase, TableDescriptor } from "./abstractions";
6 |
7 | export class IndexedDb implements IDatabase {
8 | // private repository: Record<string, Array<any>>;
9 | // private maxIdsByCollections: Record<string, number> = {};
10 | private db: Dexie | null = null;
11 |
12 | [key: string]: unknown;
13 |
14 | constructor(
15 | private tables: Array<TableDescriptor> | undefined,
16 | private initialData: Record<string, any[]> | (() => Promise<Record<string, any[]>>) = {},
17 | private config?: any,
18 | ) {}
19 |
20 | private getDb() {
21 | if (this.db === null) {
22 | throw new Error("Db is not initialized yet");
23 | }
24 | return this.db;
25 | }
26 |
27 | public async initialize() {
28 | const resolvedInitialData =
29 | typeof this.initialData === "function" ? await this.initialData() : this.initialData;
30 | const schema: Record<string, string> = {};
31 | const tableNames = new Set<string>();
32 | if (this.tables) {
33 | this.tables.forEach((tableDescriptor) => {
34 | const schemaArray = [];
35 | if (tableDescriptor.pk.length === 1) {
36 | schemaArray.push(tableDescriptor.pk[0]);
37 | } else {
38 | schemaArray.push(`[${tableDescriptor.pk.join("+")}]`); //indexeddb compound index looks like this: [field+anotherfield]
39 | }
40 | if (tableDescriptor.indexes) {
41 | schemaArray.push(...tableDescriptor.indexes);
42 | }
43 | schema[tableDescriptor.name] = schemaArray.join(", ");
44 | tableNames.add(tableDescriptor.name);
45 | });
46 | } else {
47 | Object.entries(resolvedInitialData).forEach(([key]) => {
48 | schema[key] = "++id";
49 | tableNames.add(key);
50 | });
51 | }
52 |
53 | const targetVersion =
54 | this.config?.version !== undefined && typeof this.config?.version === "number"
55 | ? this.config?.version
56 | : 1;
57 |
58 | const shouldInitializeData = await this.dropDbOnVersionChange(targetVersion);
59 |
60 | this.db = this.createDbInstance();
61 | this.db.version(targetVersion).stores(schema);
62 |
63 | if (shouldInitializeData) {
64 | await Promise.all(
65 | Object.entries(resolvedInitialData).map(async ([key, value]) => {
66 | try {
67 | await this.getDb().table(key).bulkAdd(value);
68 | } catch (ignored) {
69 | console.error(ignored);
70 | }
71 | }),
72 | );
73 | }
74 |
75 | tableNames.forEach((key) => {
76 | this[`$${key}`] = createTableWrapper(this.getDb().table(key));
77 | });
78 | }
79 |
80 | private createDbInstance() {
81 | return new Dexie(this.config?.database ?? "defaultIndexDb");
82 | }
83 |
84 | private async dropDbOnVersionChange(targetVersion: number) {
85 | const tempDb = this.createDbInstance();
86 | if (!(await Dexie.exists(tempDb.name))) {
87 | return true;
88 | }
89 | await tempDb.open();
90 | if (tempDb.verno !== targetVersion) {
91 | await tempDb.delete();
92 | return true;
93 | } else {
94 | tempDb.close();
95 | return false;
96 | }
97 | }
98 |
99 | public getItems = (resourceId: string) => this.getDb().table(resourceId).toArray();
100 |
101 | public findItems = async (resourceId: string, predicate: (item: any) => Promise<boolean>) => {
102 | const ret = await this.getItems(resourceId);
103 | const results = await Promise.all(ret.map(predicate));
104 | return ret.filter((_v, index) => results[index]);
105 | };
106 |
107 | public getItem = async (resourceId: string, predicate: (item: any) => Promise<boolean>) => {
108 | const ret = await this.getItems(resourceId);
109 | const results = await Promise.all(ret.map(predicate));
110 | return ret.find((_v, index) => results[index]);
111 | };
112 |
113 | public getItemById = async (resourceId: string, id: any) => {
114 | return await this.getItem(resourceId, (item) => {
115 | return Promise.resolve(item.id + "" === id + "");
116 | });
117 | };
118 |
119 | public deleteItems = async (resourceId: string, predicate: (item: any) => Promise<boolean>) => {
120 | // this.repository[resourceId] = this.repository[resourceId]?.filter((item) => !predicate(item));
121 | };
122 |
123 | public insertItem = async (resourceId: string, item: any) => {
124 | const id = await this.getDb().table(resourceId).add(item);
125 | return this.getItemById(resourceId, id);
126 | };
127 |
128 | public updateItem = async (resourceId: string, item: any) => {
129 | await this.getDb().table(resourceId).update(item.id, item);
130 | return await this.getItemById(resourceId, item.id);
131 | };
132 |
133 | // --- This method signifies that a section of operations is executed in a transaction
134 | async transaction(actions: () => Promise<void>): Promise<void> {
135 | if (!this.db) return;
136 |
137 | const tables = this.db.tables;
138 | await this.db.transaction("rw", tables, actions);
139 | }
140 | }
141 |
142 | // Wraps an indexDb Table into an object that provides helpful methods
143 | function createTableWrapper(table: Table): any {
144 | // --- Function to retrieve the current table data
145 | const getDataFn = () => table.db.table(table.name);
146 |
147 | // --- Helper method to filter the table data
148 | const filteredData = async (predicate?: (item: any) => Promise<boolean>) => {
149 | const dataSnapshot = await table.toArray();
150 | const results = await Promise.all(dataSnapshot.map(predicate ?? (() => Promise.resolve(true))));
151 | return dataSnapshot.filter((_v, index) => results[index]);
152 | };
153 |
154 | return {
155 | native: getDataFn,
156 | insert: async (item: any) => {
157 | const id = await table.add(item);
158 | return getDataFn().get(id);
159 | },
160 | update: async (item: any) => {
161 | await table.update(item.id, item);
162 | return getDataFn().get(item.id);
163 | },
164 | save: async (item: any) => {
165 | const key = await table.put(item);
166 | return table.get(key);
167 | },
168 | deleteById: async (id: any) => {
169 | await table.delete(id);
170 | },
171 | byId: async (id: any) => {
172 | if (id === undefined || id === null) {
173 | return null;
174 | }
175 | let safeId = id;
176 | if (table.schema.primKey.src === "++id") {
177 | //it's an auto incremented id, must be a number
178 | safeId = Number(id);
179 | }
180 | return await table.get(safeId);
181 | },
182 | toArray: async () => await table.toArray(),
183 | single: async (predicate: (item: any) => Promise<boolean>) =>
184 | await new ReadOnlyCollection(await table.toArray()).single(predicate),
185 | singleOrDefault: async (predicate: (item: any) => Promise<boolean>, defValue?: any) => {
186 | return await new ReadOnlyCollection(await table.toArray()).singleOrDefault(
187 | predicate,
188 | defValue,
189 | );
190 | },
191 | where: async (predicate: (item: any) => Promise<boolean>) =>
192 | new ReadOnlyCollection(await filteredData(predicate)),
193 | whereAsArray: async (predicate: (item: any) => Promise<boolean>) =>
194 | await filteredData(predicate),
195 | orderBy: async (...mappers: any[]) =>
196 | await new ReadOnlyCollection(await table.toArray()).orderBy(...mappers),
197 | orderByAsArray: async (...mappers: any[]) =>
198 | await new ReadOnlyCollection(await table.toArray()).orderByAsArray(...mappers),
199 | groupBy: async (groupKey: (item: any) => Promise<any>) =>
200 | await new ReadOnlyCollection(await table.toArray()).groupBy(groupKey),
201 | groupByAsArray: async (groupKey: (item: any) => Promise<any>) =>
202 | await new ReadOnlyCollection(await table.toArray()).groupByAsArray(groupKey),
203 | distinct: async (distinctValue?: (item: any) => Promise<any>) =>
204 | await new ReadOnlyCollection(await table.toArray()).distinct(distinctValue),
205 | distinctAsArray: async (distinctValue?: (item: any) => Promise<any>) =>
206 | await new ReadOnlyCollection(await table.toArray()).distinctAsArray(distinctValue),
207 | maxValue: async (fieldName = "id", predicate?: (item: any) => Promise<boolean>) => {
208 | return await new ReadOnlyCollection(await table.toArray()).maxValue(fieldName, predicate);
209 | },
210 | skip: async (count: number) => {
211 | return await new ReadOnlyCollection(await table.toArray()).skip(count);
212 | },
213 | take: async (count: number) => {
214 | return await new ReadOnlyCollection(await table.toArray()).take(count);
215 | },
216 | skipTake: async (skip: number, take: number) => {
217 | return await new ReadOnlyCollection(await table.toArray()).skipTake(skip, take);
218 | },
219 | };
220 | }
221 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/IconRegistryContext.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import React, { useCallback, useContext } from "react";
2 |
3 | import type { IconRegistry } from "./IconProvider";
4 | import { useIsomorphicLayoutEffect } from "../components-core/utils/hooks";
5 |
6 | export const IconRegistryContext = React.createContext<IconRegistry | null>(null);
7 |
8 | export function useIconRegistry() {
9 | return useContext(IconRegistryContext)!;
10 | }
11 |
12 | //https://github.com/hatashiro/react-attr-converter/tree/master
13 | const svgAttributeMap: Record<string, string> = {
14 | // SVG attributes
15 | accentheight: "accentHeight",
16 | accumulate: "accumulate",
17 | additive: "additive",
18 | alignmentbaseline: "alignmentBaseline",
19 | allowreorder: "allowReorder",
20 | alphabetic: "alphabetic",
21 | amplitude: "amplitude",
22 | arabicform: "arabicForm",
23 | ascent: "ascent",
24 | attributename: "attributeName",
25 | attributetype: "attributeType",
26 | autoreverse: "autoReverse",
27 | azimuth: "azimuth",
28 | basefrequency: "baseFrequency",
29 | baseprofile: "baseProfile",
30 | baselineshift: "baselineShift",
31 | bbox: "bbox",
32 | begin: "begin",
33 | bias: "bias",
34 | by: "by",
35 | calcmode: "calcMode",
36 | capheight: "capHeight",
37 | clip: "clip",
38 | clippath: "clipPath",
39 | clippathunits: "clipPathUnits",
40 | cliprule: "clipRule",
41 | colorinterpolation: "colorInterpolation",
42 | colorinterpolationfilters: "colorInterpolationFilters",
43 | colorprofile: "colorProfile",
44 | colorrendering: "colorRendering",
45 | contentscripttype: "contentScriptType",
46 | contentstyletype: "contentStyleType",
47 | cursor: "cursor",
48 | cx: "cx",
49 | cy: "cy",
50 | d: "d",
51 | decelerate: "decelerate",
52 | descent: "descent",
53 | diffuseconstant: "diffuseConstant",
54 | direction: "direction",
55 | display: "display",
56 | divisor: "divisor",
57 | dominantbaseline: "dominantBaseline",
58 | dur: "dur",
59 | dx: "dx",
60 | dy: "dy",
61 | edgemode: "edgeMode",
62 | elevation: "elevation",
63 | enablebackground: "enableBackground",
64 | end: "end",
65 | exponent: "exponent",
66 | externalresourcesrequired: "externalResourcesRequired",
67 | fill: "fill",
68 | fillopacity: "fillOpacity",
69 | fillrule: "fillRule",
70 | filter: "filter",
71 | filterres: "filterRes",
72 | filterunits: "filterUnits",
73 | floodcolor: "floodColor",
74 | floodopacity: "floodOpacity",
75 | focusable: "focusable",
76 | fontfamily: "fontFamily",
77 | fontsize: "fontSize",
78 | fontsizeadjust: "fontSizeAdjust",
79 | fontstretch: "fontStretch",
80 | fontstyle: "fontStyle",
81 | fontvariant: "fontVariant",
82 | fontweight: "fontWeight",
83 | format: "format",
84 | from: "from",
85 | fx: "fx",
86 | fy: "fy",
87 | g1: "g1",
88 | g2: "g2",
89 | glyphname: "glyphName",
90 | glyphorientationhorizontal: "glyphOrientationHorizontal",
91 | glyphorientationvertical: "glyphOrientationVertical",
92 | glyphref: "glyphRef",
93 | gradienttransform: "gradientTransform",
94 | gradientunits: "gradientUnits",
95 | hanging: "hanging",
96 | horizadvx: "horizAdvX",
97 | horizoriginx: "horizOriginX",
98 | ideographic: "ideographic",
99 | imagerendering: "imageRendering",
100 | in: "in",
101 | in2: "in2",
102 | intercept: "intercept",
103 | k: "k",
104 | k1: "k1",
105 | k2: "k2",
106 | k3: "k3",
107 | k4: "k4",
108 | kernelmatrix: "kernelMatrix",
109 | kernelunitlength: "kernelUnitLength",
110 | kerning: "kerning",
111 | keypoints: "keyPoints",
112 | keysplines: "keySplines",
113 | keytimes: "keyTimes",
114 | lengthadjust: "lengthAdjust",
115 | letterspacing: "letterSpacing",
116 | lightingcolor: "lightingColor",
117 | limitingconeangle: "limitingConeAngle",
118 | local: "local",
119 | markerend: "markerEnd",
120 | markerheight: "markerHeight",
121 | markermid: "markerMid",
122 | markerstart: "markerStart",
123 | markerunits: "markerUnits",
124 | markerwidth: "markerWidth",
125 | mask: "mask",
126 | maskcontentunits: "maskContentUnits",
127 | maskunits: "maskUnits",
128 | mathematical: "mathematical",
129 | mode: "mode",
130 | numoctaves: "numOctaves",
131 | offset: "offset",
132 | opacity: "opacity",
133 | operator: "operator",
134 | order: "order",
135 | orient: "orient",
136 | orientation: "orientation",
137 | origin: "origin",
138 | overflow: "overflow",
139 | overlineposition: "overlinePosition",
140 | overlinethickness: "overlineThickness",
141 | paintorder: "paintOrder",
142 | panose1: "panose1",
143 | pathlength: "pathLength",
144 | patterncontentunits: "patternContentUnits",
145 | patterntransform: "patternTransform",
146 | patternunits: "patternUnits",
147 | pointerevents: "pointerEvents",
148 | points: "points",
149 | pointsatx: "pointsAtX",
150 | pointsaty: "pointsAtY",
151 | pointsatz: "pointsAtZ",
152 | preservealpha: "preserveAlpha",
153 | preserveaspectratio: "preserveAspectRatio",
154 | primitiveunits: "primitiveUnits",
155 | r: "r",
156 | radius: "radius",
157 | refx: "refX",
158 | refy: "refY",
159 | renderingintent: "renderingIntent",
160 | repeatcount: "repeatCount",
161 | repeatdur: "repeatDur",
162 | requiredextensions: "requiredExtensions",
163 | requiredfeatures: "requiredFeatures",
164 | restart: "restart",
165 | result: "result",
166 | rotate: "rotate",
167 | rx: "rx",
168 | ry: "ry",
169 | scale: "scale",
170 | seed: "seed",
171 | shaperendering: "shapeRendering",
172 | slope: "slope",
173 | spacing: "spacing",
174 | specularconstant: "specularConstant",
175 | specularexponent: "specularExponent",
176 | speed: "speed",
177 | spreadmethod: "spreadMethod",
178 | startoffset: "startOffset",
179 | stddeviation: "stdDeviation",
180 | stemh: "stemh",
181 | stemv: "stemv",
182 | stitchtiles: "stitchTiles",
183 | stopcolor: "stopColor",
184 | stopopacity: "stopOpacity",
185 | strikethroughposition: "strikethroughPosition",
186 | strikethroughthickness: "strikethroughThickness",
187 | string: "string",
188 | stroke: "stroke",
189 | strokedasharray: "strokeDasharray",
190 | strokedashoffset: "strokeDashoffset",
191 | strokelinecap: "strokeLinecap",
192 | strokelinejoin: "strokeLinejoin",
193 | strokemiterlimit: "strokeMiterlimit",
194 | strokeopacity: "strokeOpacity",
195 | strokewidth: "strokeWidth",
196 | surfacescale: "surfaceScale",
197 | systemlanguage: "systemLanguage",
198 | tablevalues: "tableValues",
199 | targetx: "targetX",
200 | targety: "targetY",
201 | textanchor: "textAnchor",
202 | textdecoration: "textDecoration",
203 | textlength: "textLength",
204 | textrendering: "textRendering",
205 | to: "to",
206 | transform: "transform",
207 | u1: "u1",
208 | u2: "u2",
209 | underlineposition: "underlinePosition",
210 | underlinethickness: "underlineThickness",
211 | unicode: "unicode",
212 | unicodebidi: "unicodeBidi",
213 | unicoderange: "unicodeRange",
214 | unitsperem: "unitsPerEm",
215 | valphabetic: "vAlphabetic",
216 | vhanging: "vHanging",
217 | videographic: "vIdeographic",
218 | vmathematical: "vMathematical",
219 | values: "values",
220 | vectoreffect: "vectorEffect",
221 | version: "version",
222 | vertadvy: "vertAdvY",
223 | vertoriginx: "vertOriginX",
224 | vertoriginy: "vertOriginY",
225 | viewbox: "viewBox",
226 | viewtarget: "viewTarget",
227 | visibility: "visibility",
228 | widths: "widths",
229 | wordspacing: "wordSpacing",
230 | writingmode: "writingMode",
231 | x: "x",
232 | x1: "x1",
233 | x2: "x2",
234 | xchannelselector: "xChannelSelector",
235 | xheight: "xHeight",
236 | xlinkactuate: "xlinkActuate",
237 | xlinkarcrole: "xlinkArcrole",
238 | xlinkhref: "xlinkHref",
239 | xlinkrole: "xlinkRole",
240 | xlinkshow: "xlinkShow",
241 | xlinktitle: "xlinkTitle",
242 | xlinktype: "xlinkType",
243 | xmlns: "xmlns",
244 | xmlnsxlink: "xmlnsXlink",
245 | xmlbase: "xmlBase",
246 | xmllang: "xmlLang",
247 | xmlspace: "xmlSpace",
248 | y: "y",
249 | y1: "y1",
250 | y2: "y2",
251 | ychannelselector: "yChannelSelector",
252 | z: "z",
253 | zoomandpan: "zoomAndPan",
254 | };
255 |
256 | const extraCharRegex = /[-:]/g;
257 |
258 | export function useCustomSvgIconRenderer(resourceUrl?: string) {
259 | const { ensureCustomSvgIcon, customSvgs } = useIconRegistry();
260 | useIsomorphicLayoutEffect(() => {
261 | if (!resourceUrl) {
262 | return;
263 | }
264 | void ensureCustomSvgIcon(resourceUrl);
265 | }, [ensureCustomSvgIcon, resourceUrl]);
266 | const customSvg = resourceUrl ? customSvgs[resourceUrl] : null;
267 |
268 | const iconRenderer = useCallback(
269 | ({ style, className }: any) => {
270 | if (!customSvg) {
271 | return null;
272 | }
273 | const { attributes, name } = customSvg;
274 | const safeAttributes: any = {};
275 | Object.entries(attributes).forEach(([key, value]) => {
276 | let safeKey = key;
277 | if (/^(data-|aria-)/.test(key)) {
278 | safeKey = key;
279 | } else {
280 | safeKey = key.replace(extraCharRegex, "").toLowerCase();
281 | }
282 |
283 | safeAttributes[svgAttributeMap[safeKey] || key] = value;
284 | });
285 | return (
286 | <svg {...safeAttributes} style={style} className={className}>
287 | <use href={`#${name}`} />
288 | </svg>
289 | );
290 | },
291 | [customSvg],
292 | );
293 |
294 | return !resourceUrl ? null : iconRenderer;
295 | }
296 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Select/Select.md:
--------------------------------------------------------------------------------
```markdown
1 | %-DESC-START
2 |
3 | **Key features:**
4 | - **Flexible selection modes**: Single selection by default, with optional multi-select capability
5 | - **Option containers**: Uses Option components to define selectable items with separate values and labels
6 | - **Search functionality**: Optional filtering to quickly find options in large lists
7 | - **Custom templates**: Configurable option display, value presentation, and empty state templates
8 | - **Dynamic options**: Supports both static [Option](/components/Option) children and dynamic lists via [Items](/components/Items).
9 |
10 | ## Using `Select`
11 |
12 | The component accepts `Option` components as children defining a particular option's label-value pair.
13 | `Option` requires a `value` property and while also having a `label` that is displayed in the list.
14 | If the `label` is not specified `value` is shown.
15 |
16 | ```xmlui-pg copy display name="Example: using Select" height="200px"
17 | <App>
18 | <Select>
19 | <Option value="opt1" label="first"/>
20 | <Option value="opt2" label="second"/>
21 | <Option value="opt3" label="third"/>
22 | </Select>
23 | </App>
24 | ```
25 |
26 | You can use `Select` with dynamic options:
27 |
28 | ```xmlui-pg copy display name="Example: using Select with dynamic options" height="200px"
29 | <App>
30 | <Select>
31 | <Items data="{['one', 'two', 'three']}" >
32 | <Option value="{$itemIndex}" label="{$item}" />
33 | </Items>
34 | </Select>
35 | </App>
36 | ```
37 |
38 | %-DESC-END
39 |
40 | %-PROP-START initialValue
41 |
42 | ```xmlui-pg copy display name="Example: initialValue" height="200px"
43 | <App>
44 | <Select initialValue="opt3">
45 | <Option value="opt1" label="first"/>
46 | <Option value="opt2" label="second"/>
47 | <Option value="opt3" label="third"/>
48 | </Select>
49 | </App>
50 | ```
51 |
52 | %-PROP-END
53 |
54 | %-PROP-START optionTemplate
55 |
56 | ```xmlui-pg copy display name="Example: optionTemplate" height="200px"
57 | <App>
58 | <Select>
59 | <property name="optionTemplate">
60 | <HStack verticalAlignment="center" gap="$space-0_5">
61 | <Icon name="info" />
62 | <Text value="{$item.label}" variant="strong" />
63 | </HStack>
64 | </property>
65 | <Option value="opt1" label="first"/>
66 | <Option value="opt2" label="second"/>
67 | <Option value="opt3" label="third"/>
68 | </Select>
69 | </App>
70 | ```
71 |
72 | %-PROP-END
73 |
74 | %-PROP-START placeholder
75 |
76 | ```xmlui-pg copy display name="Example: placeholder" height="200px"
77 | <App>
78 | <Select placeholder="Please select an item">
79 | <Option value="opt1" label="first"/>
80 | <Option value="opt2" label="second"/>
81 | <Option value="opt3" label="third"/>
82 | </Select>
83 | </App>
84 | ```
85 |
86 | %-PROP-END
87 |
88 | %-PROP-START validationStatus
89 |
90 | ```xmlui-pg copy display name="Example: validationStatus" height="280px"
91 | <App>
92 | <Select />
93 | <Select validationStatus="valid" />
94 | <Select validationStatus="warning" />
95 | <Select validationStatus="error" />
96 | </App>
97 | ```
98 |
99 | %-PROP-END
100 |
101 | %-PROP-START enabled
102 |
103 | ```xmlui-pg copy display name="Example: enabled"
104 | <App>
105 | <Select enabled="false" />
106 | </App>
107 | ```
108 |
109 | %-PROP-END
110 |
111 | %-PROP-START emptyListTemplate
112 |
113 | Click on the second field to see the custom empty list indicator.
114 |
115 | ```xmlui-pg copy {9-11} display name="Example: emptyListTemplate" height="260px"
116 | <App>
117 | <VStack>
118 | <Text value="Default:" />
119 | <Select />
120 | </VStack>
121 | <VStack>
122 | <Text value="Custom:" />
123 | <Select>
124 | <property name="emptyListTemplate">
125 | <Text variant="strong" value="Nothing to see here!" />
126 | </property>
127 | </Select>
128 | </VStack>
129 | </App>
130 | ```
131 |
132 | %-PROP-END
133 |
134 | %-PROP-START dropdownHeight
135 |
136 | ```xmlui-pg copy display name="Example: dropdownHeight" height="300px"
137 | <App>
138 | <Select dropdownHeight="180px">
139 | <Option value="opt1" label="first"/>
140 | <Option value="opt2" label="second"/>
141 | <Option value="opt3" label="third"/>
142 | <Option value="opt4" label="fourth"/>
143 | <Option value="opt5" label="fifth"/>
144 | <Option value="opt6" label="sixth"/>
145 | <Option value="opt7" label="seventh"/>
146 | <Option value="opt8" label="eighth"/>
147 | <Option value="opt9" label="ninth"/>
148 | <Option value="opt10" label="tenth"/>
149 | <Option value="opt11" label="eleventh"/>
150 | <Option value="opt12" label="twelfth"/>
151 | </Select>
152 | </App>
153 | ```
154 |
155 | %-PROP-END
156 |
157 | %-PROP-START multiSelect
158 |
159 | ```xmlui-pg copy display name="Example: multiSelect" height="300px"
160 | <App>
161 | <Select multiSelect="true" dropdownHeight="180px" >
162 | <Option value="opt1" label="first"/>
163 | <Option value="opt2" label="second"/>
164 | <Option value="opt3" label="third"/>
165 | <Option value="opt4" label="fourth"/>
166 | <Option value="opt5" label="fifth"/>
167 | <Option value="opt6" label="sixth"/>
168 | <Option value="opt7" label="seventh"/>
169 | <Option value="opt8" label="eighth"/>
170 | <Option value="opt9" label="ninth"/>
171 | <Option value="opt10" label="tenth"/>
172 | <Option value="opt11" label="eleventh"/>
173 | <Option value="opt12" label="twelfth"/>
174 | </Select>
175 | </App>
176 | ```
177 |
178 | %-PROP-END
179 |
180 | %-PROP-START optionLabelTemplate
181 |
182 | In the template definition, you can use the `$item` context property to access the particular item's `label` and `value`.
183 |
184 | ```xmlui-pg copy {3-9} display name="Example: optionLabelTemplate" height="300px"
185 | <App>
186 | <Select initialValue="{0}" placeholder="Select..." searchable>
187 | <property name="optionLabelTemplate">
188 | <HStack
189 | paddingHorizontal="$padding-tight"
190 | border="2px dotted $color-primary-500">
191 | <Text>{$item.label}</Text>
192 | </HStack>
193 | </property>
194 | <Option value="{0}" label="zero"/>
195 | <Option value="opt1" label="first"/>
196 | <Option value="opt2" label="second"/>
197 | <Option value="opt3" label="third"/>
198 | </Select>
199 | </App>
200 | ```
201 |
202 | %-PROP-END
203 |
204 | %-PROP-START valueTemplate
205 |
206 | In the template definition, you can use the `$item` context property to access the particular item's `label` and `value`. The `$itemContext` property provides a `removeItem` method to delete a value from the current selection.
207 |
208 | ```xmlui-pg copy {3-15} display name="Example: valueTemplate" height="300px"
209 | <App>
210 | <Select initialValue="{0}" placeholder="Select..." multiSelect>
211 | <property name="valueTemplate">
212 | <HStack
213 | paddingLeft="$padding-tight"
214 | border="2px dotted $color-primary-500"
215 | verticalAlignment="center">
216 | <Text>{$item.label}</Text>
217 | <Button
218 | variant="ghost"
219 | icon="close"
220 | size="xs"
221 | onClick="$itemContext.removeItem()"/>
222 | </HStack>
223 | </property>
224 | <Option value="{0}" label="zero"/>
225 | <Option value="opt1" label="first"/>
226 | <Option value="opt2" label="second"/>
227 | <Option value="opt3" label="third"/>
228 | </Select>
229 | </App>
230 | ```
231 |
232 | %-PROP-END
233 |
234 | %-EVENT-START didChange
235 |
236 | ```xmlui-pg copy display name="Example: didChange" height="260px"
237 | <App>
238 | <variable name="newValue" value="(none)" />
239 | <Text value="{newValue}" />
240 | <Select onDidChange="(newItem) => newValue = newItem">
241 | <Option value="opt1" label="first"/>
242 | <Option value="opt2" label="second"/>
243 | <Option value="opt3" label="third"/>
244 | </Select>
245 | </App>
246 | ```
247 |
248 | %-EVENT-END
249 |
250 | %-EVENT-START gotFocus
251 |
252 | ```xmlui-pg copy {5-6} display name="Example: gotFocus/lostFocus" height="260px"
253 | <App>
254 | <variable name="isFocused" value="{false}" />
255 | <Text value="Input control is focused: {isFocused}" />
256 | <Select
257 | onGotFocus="isFocused = true"
258 | onLostFocus="isFocused = false">
259 | <Option value="opt1" label="first"/>
260 | <Option value="opt2" label="second"/>
261 | <Option value="opt3" label="third"/>
262 | </Select>
263 | </App>
264 | ```
265 |
266 | %-EVENT-END
267 |
268 | %-API-START focus
269 |
270 | ```xmlui-pg copy display name="Example: focus()" height="260px"
271 | <App>
272 | <Button label="Focus Input" onClick="inputControl.focus()" />
273 | <Select id="inputControl">
274 | <Option value="opt1" label="first"/>
275 | <Option value="opt2" label="second"/>
276 | <Option value="opt3" label="third"/>
277 | </Select>
278 | </App>
279 | ```
280 |
281 | %-API-END
282 |
283 | %-API-START setValue
284 |
285 | ```xmlui-pg copy display name="Example: setValue()" height="260px"
286 | <App>
287 | <Select id="inputControl">
288 | <Option value="opt1" label="first"/>
289 | <Option value="opt2" label="second"/>
290 | <Option value="opt3" label="third"/>
291 | </Select>
292 | <HStack>
293 | <Button
294 | label="Select 2nd Item"
295 | onClick="inputControl.setValue('opt2')" />
296 | <Button
297 | label="Remove Selection"
298 | onClick="inputControl.setValue('')" />
299 | </HStack>
300 | </App>
301 | ```
302 |
303 | %-API-END
304 |
```
--------------------------------------------------------------------------------
/xmlui/src/components-core/utils/statementUtils.ts:
--------------------------------------------------------------------------------
```typescript
1 | import {
2 | T_ARROW_EXPRESSION,
3 | T_ARROW_EXPRESSION_STATEMENT,
4 | T_BLOCK_STATEMENT,
5 | T_CALCULATED_MEMBER_ACCESS_EXPRESSION,
6 | T_EMPTY_STATEMENT,
7 | T_EXPRESSION_STATEMENT,
8 | T_FUNCTION_INVOCATION_EXPRESSION,
9 | T_IDENTIFIER,
10 | T_LITERAL,
11 | T_MEMBER_ACCESS_EXPRESSION,
12 | T_RETURN_STATEMENT,
13 | type ArrowExpression,
14 | type ArrowExpressionStatement,
15 | type BlockStatement,
16 | type EmptyStatement,
17 | type Expression,
18 | type ExpressionStatement,
19 | type FunctionInvocationExpression,
20 | type Identifier,
21 | type Statement,
22 | } from "../script-runner/ScriptingSourceTree";
23 | import type { QueueInfo } from "../script-runner/statement-queue";
24 | import type { BindingTreeEvaluationContext } from "../script-runner/BindingTreeEvaluationContext";
25 | import type { LogicalThread } from "../../abstractions/scripting/LogicalThread";
26 |
27 | import { Parser } from "../../parsers/scripting/Parser";
28 | import { processStatementQueueAsync } from "../script-runner/process-statement-async";
29 | import { reportEngineError } from "../reportEngineError";
30 | import { ScriptParseError } from "../EngineError";
31 |
32 | /**
33 | * Parse the specified source code as event handler code
34 | * @param source Event handler source code
35 | */
36 | export function parseHandlerCode(source: string): Statement[] {
37 | // --- Parse the event code
38 | const wParser = new Parser(source);
39 | let parsedStatements: Statement[] | null = null;
40 | try {
41 | // --- Invoke the parser
42 | parsedStatements = wParser.parseStatements();
43 | } catch (err) {
44 | // --- Parsing error with explicit error code
45 | if (wParser.errors.length > 0) {
46 | const err = wParser.errors[0];
47 | reportEngineError(
48 | new ScriptParseError(
49 | `${err.code}(${err.line}, ${err.column}): ${wParser.errors[0].text}`,
50 | source,
51 | err.position,
52 | ),
53 | );
54 | } else {
55 | throw err;
56 | }
57 | }
58 |
59 | // --- Check for the completeness of source code parsing
60 | if (!wParser.isEof) {
61 | const tail = wParser.getTail();
62 | reportEngineError(
63 | new ScriptParseError(`Invalid tail found`, source, source.length - tail.length + 1),
64 | );
65 | }
66 |
67 | // --- Done
68 | return parsedStatements!;
69 | }
70 |
71 | /**
72 | * Optionally transform statements in an event handler to an arrow expression statement
73 | * @param stmts Statements to transform
74 | * @param evalContext Optional event arguments
75 | */
76 | export function prepareHandlerStatements(
77 | stmts: Statement[],
78 | evalContext?: BindingTreeEvaluationContext,
79 | ): Statement[] {
80 | const stmtLength = stmts?.length ?? 0;
81 | if (stmtLength === 0) {
82 | // -- Use a no-op arrow function
83 | return [
84 | {
85 | type: T_ARROW_EXPRESSION_STATEMENT,
86 | expr: {
87 | type: T_ARROW_EXPRESSION,
88 | args: [],
89 | statement: {
90 | type: T_EMPTY_STATEMENT,
91 | } as EmptyStatement,
92 | } as ArrowExpression,
93 | } as ArrowExpressionStatement,
94 | ];
95 | }
96 |
97 | if (stmtLength === 1) {
98 | const stmt = stmts[0];
99 |
100 | if (stmt.type === T_EXPRESSION_STATEMENT) {
101 | // --- Handle single expression statements
102 | if (evalContext) {
103 | // --- We have a context in which the event handler is executed
104 | if (stmt.expr.type === T_IDENTIFIER) {
105 | // --- A single identifier, it is supposed to be an arrow function
106 | // --- Use this arrow expression
107 | return [convertExpressionToFunctionInvocation(stmt.expr)];
108 | }
109 |
110 | if (isMemberExpressionChain(stmt.expr)) {
111 | // --- A single member expression chain, it is supposed to be an arrow function
112 | // --- Use this arrow expression
113 | return [convertExpressionToFunctionInvocation(stmt.expr)];
114 | }
115 | }
116 |
117 | if (stmt.expr.type === T_ARROW_EXPRESSION) {
118 | // --- A single arrow expression
119 | return [
120 | {
121 | type: T_ARROW_EXPRESSION_STATEMENT,
122 | expr: stmt.expr,
123 | } as ArrowExpressionStatement,
124 | ];
125 | }
126 |
127 | // --- A single statement, turn into an arrow expression
128 | return [
129 | {
130 | type: T_ARROW_EXPRESSION_STATEMENT,
131 | expr: {
132 | type: T_ARROW_EXPRESSION,
133 | args: [],
134 | statement: stmts[0],
135 | } as ArrowExpression,
136 | } as ArrowExpressionStatement,
137 | ];
138 | }
139 |
140 | if (stmt.type === T_RETURN_STATEMENT) {
141 | // --- A single arrow expression with a return
142 | return [
143 | {
144 | type: T_ARROW_EXPRESSION_STATEMENT,
145 | expr: {
146 | type: T_ARROW_EXPRESSION,
147 | args: [],
148 | statement: {
149 | type: T_BLOCK_STATEMENT,
150 | stmts: [stmt],
151 | } as BlockStatement,
152 | } as ArrowExpression,
153 | } as ArrowExpressionStatement,
154 | ];
155 | }
156 |
157 | if (stmt.type === T_BLOCK_STATEMENT) {
158 | // --- A single block statement?
159 | if (
160 | stmt.stmts[0].type === T_EXPRESSION_STATEMENT &&
161 | stmt.stmts[0].expr.type === T_ARROW_EXPRESSION
162 | ) {
163 | // --- A single block statement with a single arrow expression?
164 | return [
165 | {
166 | type: T_ARROW_EXPRESSION_STATEMENT,
167 | expr: stmt.stmts[0].expr,
168 | } as ArrowExpressionStatement,
169 | ];
170 | } else {
171 | // --- Consider as a body of a no-arg arrow function
172 | return [
173 | {
174 | type: T_ARROW_EXPRESSION_STATEMENT,
175 | expr: {
176 | type: T_ARROW_EXPRESSION,
177 | args: [],
178 | statement: stmts[0],
179 | } as unknown as ArrowExpression,
180 | } as ArrowExpressionStatement,
181 | ];
182 | }
183 | }
184 | }
185 |
186 | if (stmtLength > 1) {
187 | // --- Use the statements as the body of a no-arg arrow function
188 | return [
189 | {
190 | type: T_ARROW_EXPRESSION_STATEMENT,
191 | expr: {
192 | type: T_ARROW_EXPRESSION,
193 | args: [],
194 | statement: {
195 | type: T_BLOCK_STATEMENT,
196 | stmts,
197 | } as BlockStatement,
198 | } as unknown as ArrowExpression,
199 | } as ArrowExpressionStatement,
200 | ];
201 | }
202 |
203 | // --- Nothing to transform
204 | return stmts;
205 |
206 | function isMemberExpressionChain(expr: Expression): boolean {
207 | return (
208 | (expr.type === T_MEMBER_ACCESS_EXPRESSION ||
209 | (expr.type === T_CALCULATED_MEMBER_ACCESS_EXPRESSION && expr.member.type === T_LITERAL)) &&
210 | (isMemberExpressionChain(expr.obj) || expr.obj.type === T_IDENTIFIER)
211 | );
212 | }
213 |
214 | function convertExpressionToFunctionInvocation(expr: Expression): ArrowExpressionStatement {
215 | // --- A single identifier, it is supposed to be an arrow function
216 | // --- Create formal arguments
217 | const formalArgs = evalContext.eventArgs
218 | ? evalContext.eventArgs.map(
219 | (_, idx) =>
220 | ({
221 | type: T_IDENTIFIER,
222 | name: `__arg@@#__${idx}__`,
223 | }) as Identifier,
224 | )
225 | : [];
226 |
227 | // --- Add formal argument with current values
228 | if (evalContext.eventArgs) {
229 | evalContext.eventArgs.forEach((val, idx) => {
230 | evalContext.localContext[`__arg@@#__${idx}__`] = val;
231 | });
232 | }
233 |
234 | // --- Create the arrow expression
235 | const arrowExpr: ArrowExpression = {
236 | type: T_ARROW_EXPRESSION,
237 | args: formalArgs,
238 | statement: {
239 | type: T_EXPRESSION_STATEMENT,
240 | expr: {
241 | type: T_FUNCTION_INVOCATION_EXPRESSION,
242 | obj: expr,
243 | arguments: [...formalArgs],
244 | } as unknown as FunctionInvocationExpression,
245 | } as ExpressionStatement,
246 | } as ArrowExpression;
247 |
248 | // --- Use this arrow expression
249 | return {
250 | type: T_ARROW_EXPRESSION_STATEMENT,
251 | expr: arrowExpr,
252 | } as ArrowExpressionStatement;
253 | }
254 | }
255 |
256 | /**
257 | * Runs the specified event handler code
258 | * @param source Event handler source code
259 | * @param evalContext Evaluation context to use
260 | * @param thread Logical thread to use
261 | * @param onStatementCompleted Callback for statement completion
262 | */
263 | export async function runEventHandlerCode(
264 | source: string,
265 | evalContext: BindingTreeEvaluationContext,
266 | thread?: LogicalThread,
267 | ): Promise<QueueInfo> {
268 | const statements = prepareHandlerStatements(parseHandlerCode(source));
269 | return await processStatementQueueAsync(statements, evalContext, thread);
270 | }
271 |
```
--------------------------------------------------------------------------------
/xmlui/src/components-core/rendering/valueExtractor.ts:
--------------------------------------------------------------------------------
```typescript
1 | import type { MutableRefObject } from "react";
2 | import memoizeOne from "memoize-one";
3 | import { isPlainObject, isString } from "lodash-es";
4 |
5 | import type { AppContextObject } from "../../abstractions/AppContextDefs";
6 | import type { MemoedVars } from "../abstractions/ComponentRenderer";
7 | import { parseParameterString } from "../script-runner/ParameterParser";
8 | import type { ComponentApi, ContainerState } from "../rendering/ContainerWrapper";
9 | import { isPrimitive, pickFromObject, shallowCompare } from "../utils/misc";
10 | import { collectVariableDependencies } from "../script-runner/visitors";
11 | import { extractParam } from "../utils/extractParam";
12 | import { StyleParser, toCssVar } from "../../parsers/style-parser/StyleParser";
13 | import type { ValueExtractor } from "../../abstractions/RendererDefs";
14 |
15 | function parseStringArray(input: string): string[] {
16 | const trimmedInput = input.trim();
17 |
18 | if (trimmedInput.startsWith("[") && trimmedInput.endsWith("]")) {
19 | const content = trimmedInput.slice(1, -1);
20 | const items = content.split(",").map((item) => item.trim());
21 | return items.map((item) => item.replace(/^['"]|['"]$/g, ""));
22 | } else {
23 | throw new Error("Invalid array format");
24 | }
25 | }
26 |
27 | function collectParams(expression: any) {
28 | const params = [];
29 |
30 | if (typeof expression === "string") {
31 | params.push(...parseParameterString(expression));
32 | } else if (Array.isArray(expression)) {
33 | expression.forEach((exp) => {
34 | params.push(...collectParams(exp));
35 | });
36 | } else if (isPlainObject(expression)) {
37 | Object.entries(expression).forEach(([key, value]) => {
38 | params.push(...collectParams(value));
39 | });
40 | }
41 |
42 | return params;
43 | }
44 |
45 | export function asOptionalBoolean(value: any, defValue?: boolean | undefined) {
46 | if (value === undefined || value === null) return defValue;
47 |
48 | // Empty array returns false
49 | if (Array.isArray(value) && value.length === 0) {
50 | return false;
51 | }
52 |
53 | // Empty object returns false
54 | if (typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).length === 0) {
55 | return false;
56 | }
57 |
58 | if (typeof value === "number") {
59 | return value !== 0;
60 | }
61 | if (typeof value === "string") {
62 |
63 | value = value.trim().toLowerCase();
64 | if (value === "") {
65 | return false;
66 | }
67 | if (value === "true") {
68 | return true;
69 | }
70 | if (value === "false") {
71 | return false;
72 | }
73 | if (value !== "") {
74 | return true;
75 | }
76 | }
77 | if (typeof value === "boolean") {
78 | return value;
79 | }
80 | return true;
81 | }
82 |
83 | // This function represents the extractor function we pass to extractValue
84 | export function createValueExtractor(
85 | state: ContainerState,
86 | appContext: AppContextObject | undefined,
87 | referenceTrackedApi: Record<string, ComponentApi>,
88 | memoedVarsRef: MutableRefObject<MemoedVars>
89 | ): ValueExtractor {
90 | // --- Extract the parameter and retrieve as is is
91 | const extractor = (expression?: any, strict?: boolean): any => {
92 | if (!expression) {
93 | return expression;
94 | }
95 | if (isPrimitive(expression) && !isString(expression)) {
96 | return expression;
97 | }
98 |
99 | let expressionString = expression;
100 | if (typeof expression !== "string") {
101 | if (strict) {
102 | return expression;
103 | }
104 | expressionString = JSON.stringify(expression);
105 | }
106 |
107 | if (!memoedVarsRef.current.has(expressionString)) {
108 | const params = collectParams(expression);
109 | memoedVarsRef.current.set(expressionString, {
110 | getDependencies: memoizeOne((_expressionString, referenceTrackedApi) => {
111 | let ret = new Set<string>();
112 | params.forEach((param) => {
113 | if (param.type === "expression") {
114 | ret = new Set([...ret, ...collectVariableDependencies(param.value, referenceTrackedApi)]);
115 | }
116 | });
117 | return Array.from(ret);
118 | }),
119 | obtainValue: memoizeOne(
120 | (expression, state, appContext, strict, deps, appContextDeps) => {
121 | // console.log("COMP, BUST, obtain value called with", expression, state, appContext, deps, appContextDeps);
122 | return extractParam(state, expression, appContext, strict);
123 | },
124 | (
125 | [_newExpression, _newState, _newAppContext, _newStrict, newDeps, newAppContextDeps],
126 | [_lastExpression, _lastState, _lastAppContext, _lastStrict, lastDeps, lastAppContextDeps]
127 | ) => {
128 | return shallowCompare(newDeps, lastDeps) && shallowCompare(newAppContextDeps, lastAppContextDeps);
129 | }
130 | ),
131 | });
132 | }
133 | const expressionDependencies = memoedVarsRef.current
134 | .get(expressionString)!
135 | .getDependencies(expressionString, referenceTrackedApi);
136 | const depValues = pickFromObject(state, expressionDependencies);
137 | const appContextDepValues = pickFromObject(appContext, expressionDependencies);
138 | // console.log("COMP, obtain value called with", depValues, appContextDepValues, expressionDependencies);
139 | return memoedVarsRef.current.get(expressionString)!.obtainValue!(
140 | expression,
141 | state,
142 | appContext,
143 | strict,
144 | depValues,
145 | appContextDepValues
146 | );
147 | };
148 |
149 | // --- Extract a string value
150 | extractor.asString = (expression?: any) => {
151 | return extractor(expression)?.toString() ?? "";
152 | };
153 |
154 | // --- Extract an optional string value
155 | extractor.asOptionalString = <T extends string>(expression?: any, defValue?: string) => {
156 | const value = extractor(expression)?.toString();
157 | if (value === undefined || value === null) return defValue;
158 | return value as T;
159 | };
160 |
161 | extractor.asDisplayText = (expression?: any) => {
162 | let text = extractor(expression)?.toString();
163 | if (text) {
164 | let replaced = "";
165 | let spaceFound = false;
166 | for (const char of text) {
167 | if (char === " " || char === "\t") {
168 | replaced += spaceFound ? "\xa0" : " ";
169 | spaceFound = true;
170 | } else {
171 | replaced += char;
172 | spaceFound = char === "\xa0";
173 | }
174 | }
175 | text = replaced;
176 | }
177 | return text;
178 | };
179 |
180 | // ---Extract an array of strings
181 | extractor.asOptionalStringArray = (expression?: any) => {
182 | const value = extractor(expression);
183 | if (value === undefined || value === null) return [];
184 | if (typeof value === "string" && value.trim() !== "") {
185 | //console.log(parseStringArray(value));
186 | return parseStringArray(value);
187 | }
188 | if (Array.isArray(value)) {
189 | return value.map((item) => item.toString());
190 | }
191 | throw new Error(`An array of strings expected but ${typeof value} received.`);
192 | };
193 |
194 | // --- Extract a numeric value
195 | extractor.asNumber = (expression?: any) => {
196 | const value = extractor(expression);
197 | if (typeof value === "number") return value;
198 | throw new Error(`A numeric value expected but ${typeof value} received.`);
199 | };
200 |
201 | // --- Extract an optional numeric value
202 | extractor.asOptionalNumber = (expression?: any, defValue?: number) => {
203 | const value = extractor(expression);
204 | if (value === undefined || value === null) return defValue;
205 | if (typeof value === "string" && !isNaN(parseFloat(value))) {
206 | return Number(value);
207 | }
208 | if (typeof value === "number") return value;
209 | throw new Error(`A numeric value expected but ${typeof value} received.`);
210 | };
211 |
212 | // --- Extract a Boolean value
213 | extractor.asBoolean = (expression?: any) => {
214 | return !!extractor(expression);
215 | };
216 |
217 | // --- Extract an optional Boolean value
218 | extractor.asOptionalBoolean = (expression?: any, defValue?: boolean) => {
219 | return asOptionalBoolean(extractor(expression), defValue);
220 | };
221 |
222 | // --- Extract an optional size value
223 | extractor.asSize = (expression?: any) => {
224 | const value = extractor(expression);
225 | if (value === undefined || value === null) return undefined;
226 |
227 | try {
228 | const parser = new StyleParser(value);
229 | const size = parser.parseSize();
230 | if (size?.themeId) {
231 | return toCssVar(size.themeId);
232 | }
233 | return size ? `${size.value}${size.unit ?? "px"}` : undefined;
234 | } catch {
235 | return undefined;
236 | }
237 | };
238 |
239 | // --- Done.
240 | return extractor as ValueExtractor;
241 | }
242 |
```
--------------------------------------------------------------------------------
/xmlui/src/components/Carousel/Carousel.md:
--------------------------------------------------------------------------------
```markdown
1 | %-DESC-START
2 |
3 | `Carousel` displays a slideshow by cycling through elements (images, text, or custom slides) in a carousel format. It provides an interactive way to present multiple content items in a single interface area with smooth transitions and navigation controls.
4 |
5 | **Key features:**
6 | - **Multiple orientations**: Supports both horizontal and vertical scrolling
7 | - **Navigation controls**: Built-in previous/next buttons with customizable icons
8 | - **Indicators**: Visual dots showing current position and allowing direct navigation
9 | - **Autoplay functionality**: Automatic slide progression with configurable intervals
10 | - **Loop support**: Continuous cycling through slides
11 | - **Keyboard navigation**: Arrow key support for accessibility
12 | - **Exposed methods**: Programmatic control via `scrollTo()`, `scrollNext()`, `scrollPrev()`, `canScrollNext()`, `canScrollPrev()`
13 |
14 | %-DESC-END
15 |
16 | %-PROP-START autoplay
17 |
18 | This property indicates whether the carousel automatically scrolls through slides.
19 |
20 | ```xmlui-pg copy display name="Example: autoplay"
21 | <App>
22 | <Carousel autoplay autoplayInterval="2000" height="120px" loop>
23 | <CarouselItem>
24 | <Card title="Slide 1" />
25 | </CarouselItem>
26 | <CarouselItem>
27 | <Card title="Slide 2" />
28 | </CarouselItem>
29 | <CarouselItem>
30 | <Card title="Slide 3" />
31 | </CarouselItem>
32 | </Carousel>
33 | </App>
34 | ```
35 |
36 | %-PROP-END
37 |
38 | %-PROP-START controls
39 |
40 | This property indicates whether the carousel displays navigation controls (previous/next buttons).
41 |
42 | ```xmlui-pg copy display name="Example: controls"
43 | <App>
44 | <Carousel controls="true" height="120px">
45 | <CarouselItem>Slide 1 with controls</CarouselItem>
46 | <CarouselItem>Slide 2 with controls</CarouselItem>
47 | </Carousel>
48 | </App>
49 | ```
50 |
51 | %-PROP-END
52 |
53 | %-PROP-START indicators
54 |
55 | This property indicates whether the carousel displays position indicators.
56 |
57 | ```xmlui-pg copy display name="Example: indicators"
58 | <App>
59 | <Carousel indicators="true" height="120px">
60 | <CarouselItem>Slide 1 with indicators</CarouselItem>
61 | <CarouselItem>Slide 2 with indicators</CarouselItem>
62 | <CarouselItem>Slide 3 with indicators</CarouselItem>
63 | </Carousel>
64 | </App>
65 | ```
66 |
67 | %-PROP-END
68 |
69 | %-PROP-START loop
70 |
71 | This property indicates whether the carousel loops continuously from the last slide back to the first.
72 |
73 | ```xmlui-pg copy display name="Example: loop"
74 | <App>
75 | <Carousel loop="true" height="120px">
76 | <CarouselItem>
77 | <Card title="First Slide" />
78 | </CarouselItem>
79 | <CarouselItem>
80 | <Card title="Second Slide" />
81 | </CarouselItem>
82 | <CarouselItem>
83 | <Card title="Third Slide" />
84 | </CarouselItem>
85 | </Carousel>
86 | </App>
87 | ```
88 |
89 | %-PROP-END
90 |
91 | %-PROP-START orientation
92 |
93 | This property indicates the orientation of the carousel. The `horizontal` value indicates that the carousel moves horizontally, and the `vertical` value indicates that the carousel moves vertically.
94 |
95 | Available values:
96 |
97 | | Value | Description |
98 | | --- | --- |
99 | | `horizontal` | The carousel moves horizontally **(default)** |
100 | | `vertical` | The carousel moves vertically |
101 |
102 | ```xmlui-pg copy display name="Example: orientation"
103 | <App>
104 | <Carousel orientation="horizontal" height="120px">
105 | <CarouselItem>Horizontal Slide 1</CarouselItem>
106 | <CarouselItem>Horizontal Slide 2</CarouselItem>
107 | </Carousel>
108 | </App>
109 | ```
110 |
111 | %-PROP-END
112 |
113 | %-PROP-START startIndex
114 |
115 | This property indicates the index of the first slide to display when the carousel initializes.
116 |
117 | ```xmlui-pg copy display name="Example: startIndex"
118 | <App>
119 | <Carousel startIndex="2" height="120px">
120 | <CarouselItem>Slide 1</CarouselItem>
121 | <CarouselItem>Slide 2</CarouselItem>
122 | <CarouselItem>Slide 3 (starts here)</CarouselItem>
123 | <CarouselItem>Slide 4</CarouselItem>
124 | </Carousel>
125 | </App>
126 | ```
127 |
128 | %-PROP-END
129 |
130 | %-PROP-START nextIcon
131 |
132 | This property specifies the icon to display for the next control button.
133 |
134 | ```xmlui-pg copy display name="Example: custom icons"
135 | <App>
136 | <Carousel nextIcon="chevronright" prevIcon="chevronleft" height="120px">
137 | <CarouselItem>Slide 1</CarouselItem>
138 | <CarouselItem>Slide 2</CarouselItem>
139 | <CarouselItem>Slide 3</CarouselItem>
140 | </Carousel>
141 | </App>
142 | ```
143 |
144 | %-PROP-END
145 |
146 | %-PROP-START prevIcon
147 |
148 | This property specifies the icon to display for the previous control button.
149 |
150 | %-PROP-END
151 |
152 | %-PROP-START autoplayInterval
153 |
154 | This property specifies the interval between autoplay transitions in milliseconds.
155 |
156 | %-PROP-END
157 |
158 | %-PROP-START stopAutoplayOnInteraction
159 |
160 | This property indicates whether autoplay stops when the user interacts with the carousel (clicking controls, indicators, or using keyboard navigation).
161 |
162 | %-PROP-END
163 |
164 | %-PROP-START transitionDuration
165 |
166 | This property indicates the duration of the transition between slides in milliseconds.
167 |
168 | %-PROP-END
169 |
170 | %-EVENT-START displayDidChange
171 |
172 | This event is triggered when the active slide changes.
173 |
174 | The event handler receives the active slide index as a parameter.
175 |
176 | ```xmlui-pg copy display name="Example: displayDidChange"
177 | <App var.currentSlide="0">
178 | <Carousel onDisplayDidChange="(index) => currentSlide = index" height="120px">
179 | <CarouselItem>Slide 1</CarouselItem>
180 | <CarouselItem>Slide 2</CarouselItem>
181 | <CarouselItem>Slide 3</CarouselItem>
182 | </Carousel>
183 | <Text>Current slide: {currentSlide + 1}</Text>
184 | </App>
185 | ```
186 |
187 | %-EVENT-END
188 |
189 | %-STYLE-START
190 |
191 | ### Theme Variables
192 |
193 | | Variable | Default Value (Light) | Default Value (Dark) |
194 | | --- | --- | --- |
195 | | [backgroundColor](../styles-and-themes/common-units/#color)-control-Carousel | $color-primary | $color-primary |
196 | | [backgroundColor](../styles-and-themes/common-units/#color)-control-active-Carousel | $color-primary | $color-primary |
197 | | [backgroundColor](../styles-and-themes/common-units/#color)-control-disabled-Carousel | $color-surface-200 | $color-surface-200 |
198 | | [backgroundColor](../styles-and-themes/common-units/#color)-control-hover-Carousel | $color-primary | $color-primary |
199 | | [backgroundColor](../styles-and-themes/common-units/#color)-indicator-Carousel | $color-surface-200 | $color-surface-200 |
200 | | [backgroundColor](../styles-and-themes/common-units/#color)-indicator-active-Carousel | $color-primary | $color-primary |
201 | | [backgroundColor](../styles-and-themes/common-units/#color)-indicator-hover-Carousel | $color-surface-200 | $color-surface-200 |
202 | | [borderRadius](../styles-and-themes/common-units/#border-rounding)-control-Carousel | 50% | 50% |
203 | | [height](../styles-and-themes/common-units/#size)-Carousel | 100% | 100% |
204 | | [height](../styles-and-themes/common-units/#size)-control-Carousel | 36px | 36px |
205 | | [height](../styles-and-themes/common-units/#size)-indicator-Carousel | 6px | 6px |
206 | | [textColor](../styles-and-themes/common-units/#color)-control-Carousel | $textColor | $textColor |
207 | | [textColor](../styles-and-themes/common-units/#color)-control-active-Carousel | $color-primary | $color-primary |
208 | | [textColor](../styles-and-themes/common-units/#color)-control-disabled-Carousel | $textColor-disabled | $textColor-disabled |
209 | | [textColor](../styles-and-themes/common-units/#color)-control-hover-Carousel | $textColor | $textColor |
210 | | [textColor](../styles-and-themes/common-units/#color)-indicator-Carousel | $color-primary | $color-primary |
211 | | [textColor](../styles-and-themes/common-units/#color)-indicator-active-Carousel | $color-primary | $color-primary |
212 | | [textColor](../styles-and-themes/common-units/#color)-indicator-hover-Carousel | $color-primary | $color-primary |
213 | | [width](../styles-and-themes/common-units/#size)-Carousel | 100% | 100% |
214 | | [width](../styles-and-themes/common-units/#size)-control-Carousel | 36px | 36px |
215 | | [width](../styles-and-themes/common-units/#size)-indicator-Carousel | 25px | 25px |
216 |
217 | ### Navigation Controls
218 |
219 | The carousel provides built-in navigation controls that can be customized through theme variables:
220 |
221 | ```xmlui-pg copy name="Example: Custom control styling"
222 | <App>
223 | <Theme
224 | backgroundColor-control-Carousel="red"
225 | textColor-control-Carousel="white"
226 | borderRadius-control-Carousel="4px">
227 | <Carousel height="120px">
228 | <CarouselItem>Slide 1</CarouselItem>
229 | <CarouselItem>Slide 2</CarouselItem>
230 | <CarouselItem>Slide 3</CarouselItem>
231 | </Carousel>
232 | </Theme>
233 | </App>
234 | ```
235 |
236 | %-STYLE-END
237 |
```