@espressif/dashboard-ui-components 1.10.0 → 1.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +75 -0
- package/dist/_vendor/@radix-ui/primitive/dist/index.js +9 -0
- package/dist/_vendor/@radix-ui/react-checkbox/dist/index.js +185 -0
- package/dist/_vendor/@radix-ui/react-compose-refs/dist/index.js +28 -0
- package/dist/_vendor/@radix-ui/react-context/dist/index.js +68 -0
- package/dist/_vendor/@radix-ui/react-presence/dist/index.js +127 -0
- package/dist/_vendor/@radix-ui/react-primitive/dist/index.js +42 -0
- package/dist/_vendor/@radix-ui/react-use-controllable-state/dist/index.js +55 -0
- package/dist/_vendor/@radix-ui/react-use-layout-effect/dist/index.js +5 -0
- package/dist/_vendor/@radix-ui/react-use-previous/dist/index.js +17 -0
- package/dist/_vendor/@radix-ui/react-use-size/dist/index.js +39 -0
- package/dist/_vendor/lottie-react/build/index.es.js +537 -0
- package/dist/_vendor/lottie-web/build/player/lottie.js +14149 -0
- package/dist/_virtual/_rolldown/runtime.js +24 -0
- package/dist/assets/illustrations/bulb-cloud-drawing.js +4 -0
- package/dist/assets/illustrations/rm-dashboard-update.js +4 -0
- package/dist/assets/illustrations/rm-data-download.js +4 -0
- package/dist/assets/logos/espressif/espressif-no-text.js +4 -0
- package/dist/assets/logos/espressif/espressif-with-text-dm.js +4 -0
- package/dist/assets/logos/espressif/espressif-with-text.js +4 -0
- package/dist/assets/logos/insights/insights-no-text.js +4 -0
- package/dist/assets/logos/insights/insights-with-text-dm.js +4 -0
- package/dist/assets/logos/insights/insights-with-text.js +4 -0
- package/dist/assets/logos/launchpad/launchpad-no-text-dm.js +4 -0
- package/dist/assets/logos/launchpad/launchpad-no-text.js +4 -0
- package/dist/assets/logos/launchpad/launchpad-with-text-dm.js +4 -0
- package/dist/assets/logos/launchpad/launchpad-with-text.js +4 -0
- package/dist/assets/logos/private-agents/private-agents-no-text.js +4 -0
- package/dist/assets/logos/private-agents/private-agents-with-text-dm.js +4 -0
- package/dist/assets/logos/private-agents/private-agents-with-text.js +4 -0
- package/dist/assets/logos/rainmaker/rainmaker-no-text.js +4 -0
- package/dist/assets/logos/rainmaker/rainmaker-with-text-dm.js +4 -0
- package/dist/assets/logos/rainmaker/rainmaker-with-text.js +4 -0
- package/dist/assets/logos/rainmaker-classic/rainmaker-classic-no-text-dm.js +4 -0
- package/dist/assets/logos/rainmaker-classic/rainmaker-classic-no-text.js +4 -0
- package/dist/assets/logos/rainmaker-classic/rainmaker-classic-with-text-dm.js +4 -0
- package/dist/assets/logos/rainmaker-classic/rainmaker-classic-with-text.js +4 -0
- package/dist/assets/logos/rainmaker-neo/rainmaker-neo-no-text.js +4 -0
- package/dist/assets/logos/rainmaker-neo/rainmaker-neo-with-text-dm.js +4 -0
- package/dist/assets/logos/rainmaker-neo/rainmaker-neo-with-text.js +4 -0
- package/dist/assets/logos/ui-components/ui-components-no-text.js +4 -0
- package/dist/assets/logos/ui-components/ui-components-with-text-dm.js +4 -0
- package/dist/assets/logos/ui-components/ui-components-with-text.js +4 -0
- package/dist/assets/logos/zerocode/zerocode-no-text.js +4 -0
- package/dist/assets/logos/zerocode/zerocode-with-text-dm.js +4 -0
- package/dist/assets/logos/zerocode/zerocode-with-text.js +4 -0
- package/dist/assets/logos/zerocode-ai/zerocode-ai-no-text.js +4 -0
- package/dist/assets/logos/zerocode-ai/zerocode-ai-with-text-dm.js +4 -0
- package/dist/assets/logos/zerocode-ai/zerocode-ai-with-text.js +4 -0
- package/dist/common/animated-rainmaker-logo/animated-rainmaker-logo.constants.js +18 -0
- package/dist/common/animated-rainmaker-logo/animated-rainmaker-logo.js +24 -0
- package/dist/common/animated-rainmaker-logo/rainmaker-c-logo.js +50 -0
- package/dist/common/animated-rainmaker-logo/use-animated-rainmaker-logo-animation.js +85 -0
- package/dist/common/app-logo/app-logo.js +59 -0
- package/dist/common/app-logo/logo-config.js +297 -0
- package/dist/common/copyright-card/copyright-card.js +39 -0
- package/dist/common/footer-card/footer-card.js +22 -0
- package/dist/common/index.js +8 -8
- package/dist/common/my-account-menu/my-account-menu.js +32 -0
- package/dist/common/page-loader/page-loader.js +21 -0
- package/dist/common/profile-card/profile-card.js +26 -0
- package/dist/components/accordion/accordion.js +52 -0
- package/dist/components/advanced-search-box/advanced-search-box.js +106 -0
- package/dist/components/alert/alert.js +85 -0
- package/dist/components/animated-containers/pop-collection-item.js +28 -0
- package/dist/components/async-multi-select/async-multi-select.js +199 -0
- package/dist/components/avatar/avatar.js +41 -0
- package/dist/components/button/button.js +191 -0
- package/dist/components/button/flash-button.js +110 -0
- package/dist/components/button/invert-button.js +13 -0
- package/dist/components/calendar/calendar.js +105 -0
- package/dist/components/cards/animated-card/animated-card-animations.js +57 -0
- package/dist/components/cards/animated-card/animated-card.js +42 -0
- package/dist/components/cards/basic-details-card.js +46 -0
- package/dist/components/cards/collapsible-card.js +48 -0
- package/dist/components/cards/no-data-card/no-data-card.js +30 -0
- package/dist/components/cards/section-card.js +265 -0
- package/dist/components/cards/simple-card.js +24 -0
- package/dist/components/carousel/carousel.js +158 -0
- package/dist/components/chart/area-chart.js +135 -0
- package/dist/components/chart/bar-chart.js +151 -0
- package/dist/components/chart/chart-colors.js +85 -0
- package/dist/components/chart/chart-series-data.js +53 -0
- package/dist/components/chart/chart.js +147 -0
- package/dist/components/chart/chart.types.js +7 -0
- package/dist/components/chart/composed-chart.js +182 -0
- package/dist/components/chart/donut-chart.js +177 -0
- package/dist/components/chart/line-chart.js +137 -0
- package/dist/components/chart/treemap-chart.js +294 -0
- package/dist/components/circular-progress/circular-progress.js +125 -0
- package/dist/components/code-editor/code-editor.js +235 -0
- package/dist/components/code-editor/code-editor.utils.js +122 -0
- package/dist/components/code-editor/use-code-editor-keys.js +79 -0
- package/dist/components/code-editor/use-highlighted-html.js +102 -0
- package/dist/components/confirmation-dialog/confirmation-dialog.js +72 -0
- package/dist/components/content-container/content-container.js +20 -0
- package/dist/components/copiable-text/copiable-text.js +46 -0
- package/dist/components/data-table/data-table.js +186 -0
- package/dist/components/data-table/responsive-columns.js +65 -0
- package/dist/components/data-table/row-actions.js +27 -0
- package/dist/components/data-table/sticky-columns.js +71 -0
- package/dist/components/data-table/table-body.js +57 -0
- package/dist/components/data-table/table-header.js +21 -0
- package/dist/components/date-picker/date-picker.js +95 -0
- package/dist/components/date-range-picker/date-range-picker.js +301 -0
- package/dist/components/date-range-picker/presets.js +174 -0
- package/dist/components/date-time-picker/date-time-picker.js +144 -0
- package/dist/components/date-time-picker/date-time-picker.utils.js +32 -0
- package/dist/components/device-icon/device-icon.config.js +194 -0
- package/dist/components/device-icon/device-icon.js +17 -0
- package/dist/components/device-icon/icons/air-conditioner.js +22 -0
- package/dist/components/device-icon/icons/blind.js +24 -0
- package/dist/components/device-icon/icons/dimmer.js +14 -0
- package/dist/components/device-icon/icons/extension-board.js +42 -0
- package/dist/components/device-icon/icons/fan.js +14 -0
- package/dist/components/device-icon/icons/knob.js +14 -0
- package/dist/components/device-icon/icons/led-strip.js +22 -0
- package/dist/components/device-icon/icons/light.js +14 -0
- package/dist/components/device-icon/icons/refrigerator.js +18 -0
- package/dist/components/device-icon/icons/retro-switch.js +18 -0
- package/dist/components/device-icon/icons/router.js +20 -0
- package/dist/components/device-icon/icons/sensor.js +20 -0
- package/dist/components/device-icon/icons/socket.js +19 -0
- package/dist/components/device-icon/icons/switch.js +19 -0
- package/dist/components/device-icon/icons/thermostat.js +21 -0
- package/dist/components/device-icon/icons/washing-machine.js +22 -0
- package/dist/components/device-icon/match-device.js +61 -0
- package/dist/components/dynamic-list/dynamic-list.js +445 -0
- package/dist/components/error-display/full-size-error/full-size-error.js +20 -0
- package/dist/components/error-display/inline-error/inline-error.js +12 -0
- package/dist/components/file-input/file-input.js +318 -0
- package/dist/components/file-upload/file-upload.js +317 -0
- package/dist/components/filters-bar/filters-bar.js +36 -0
- package/dist/components/fullscreen-dialog/fullscreen-dialog.js +68 -0
- package/dist/components/icon-avatar/icon-avatar.js +130 -0
- package/dist/components/icon-text-action-card/icon-text-action-card.js +190 -0
- package/dist/components/illustration/illustration-registry.js +37 -0
- package/dist/components/illustration/illustration-variants.js +21 -0
- package/dist/components/illustration/illustration.js +68 -0
- package/dist/components/index.d.ts +0 -20
- package/dist/components/index.js +134 -6
- package/dist/components/key-value-manager/key-value-manager-add-popover.js +126 -0
- package/dist/components/key-value-manager/key-value-manager-field.js +47 -0
- package/dist/components/key-value-manager/key-value-manager-table.js +188 -0
- package/dist/components/key-value-manager/key-value-manager.js +111 -0
- package/dist/components/key-value-manager/key-value-manager.props.js +28 -0
- package/dist/components/key-value-manager/key-value-manager.utils.js +21 -0
- package/dist/components/link/link.js +67 -0
- package/dist/components/list/dropdown-list-item.js +60 -0
- package/dist/components/list/list-item.utils.js +76 -0
- package/dist/components/list/list.js +49 -0
- package/dist/components/list/list.props.js +27 -0
- package/dist/components/list/standard-list-item.js +66 -0
- package/dist/components/list-details/list-details-item-button.js +46 -0
- package/dist/components/list-details/list-details-item-dropdown.js +112 -0
- package/dist/components/list-details/list-details-item-strip.js +125 -0
- package/dist/components/list-details/list-details.js +148 -0
- package/dist/components/lottie-animation-container/lottie-animation-container.js +31 -0
- package/dist/components/lottie-animations/animation-data/access-denied.js +3980 -0
- package/dist/components/lottie-animations/animation-data/active.js +825 -0
- package/dist/components/lottie-animations/animation-data/bar-chart.js +610 -0
- package/dist/components/lottie-animations/animation-data/chart-loading.js +5368 -0
- package/dist/components/lottie-animations/animation-data/cloud-download.js +1660 -0
- package/dist/components/lottie-animations/animation-data/cloud-sync.js +932 -0
- package/dist/components/lottie-animations/animation-data/coud-upload.js +7060 -0
- package/dist/components/lottie-animations/animation-data/cross-throb.js +1506 -0
- package/dist/components/lottie-animations/animation-data/dashboard-loading.js +14330 -0
- package/dist/components/lottie-animations/animation-data/error-spread-out.js +5567 -0
- package/dist/components/lottie-animations/animation-data/error.js +1211 -0
- package/dist/components/lottie-animations/animation-data/green-success.js +14826 -0
- package/dist/components/lottie-animations/animation-data/inactive.js +723 -0
- package/dist/components/lottie-animations/animation-data/light.js +2678 -0
- package/dist/components/lottie-animations/animation-data/lock.js +900 -0
- package/dist/components/lottie-animations/animation-data/lock2.js +1686 -0
- package/dist/components/lottie-animations/animation-data/locked.js +641 -0
- package/dist/components/lottie-animations/animation-data/search-error.js +954 -0
- package/dist/components/lottie-animations/animation-data/security.js +4121 -0
- package/dist/components/lottie-animations/animation-data/success.js +404 -0
- package/dist/components/lottie-animations/animation-data/verification-in-progress.js +10138 -0
- package/dist/components/lottie-animations/animation-data/warning.js +843 -0
- package/dist/components/lottie-animations/verification-in-progress/verification-in-progress.js +19 -0
- package/dist/components/markdown-content/markdown-content.components.js +114 -0
- package/dist/components/markdown-content/markdown-content.js +39 -0
- package/dist/components/menu/menu.js +19 -0
- package/dist/components/monospace-content/monospace-content.js +80 -0
- package/dist/components/nav-bar/nav-bar-details-panel.js +51 -0
- package/dist/components/nav-bar/nav-bar-mobile-menu.js +105 -0
- package/dist/components/nav-bar/nav-bar.js +449 -0
- package/dist/components/nav-bar/use-nav-bar-overflow.js +74 -0
- package/dist/components/nav-bar/use-nav-bar-scroll.js +42 -0
- package/dist/components/overflow-badge-list/overflow-badge-list.js +58 -0
- package/dist/components/page-container/page-container-skeleton.js +72 -0
- package/dist/components/page-container/page-container.js +93 -0
- package/dist/components/pagination/pagination.js +96 -0
- package/dist/components/pagination/pagination.props.js +16 -0
- package/dist/components/progress-bar/progress-bar.js +106 -0
- package/dist/components/radio-group/radio-group.js +41 -0
- package/dist/components/requirement-list/requirement-list.js +83 -0
- package/dist/components/scrollable-sections/scrollable-sections.js +270 -0
- package/dist/components/search-box/search-box.js +54 -0
- package/dist/components/search-field-shell.js +24 -0
- package/dist/components/selectable-card-list/checkbox-card-list.js +85 -0
- package/dist/components/selectable-card-list/radio-card-list.js +99 -0
- package/dist/components/selectable-card-list/selectable-card-list-shared.js +135 -0
- package/dist/components/selectable-card-list/selectable-card-list.js +34 -0
- package/dist/components/sidebar/sidebar.js +344 -0
- package/dist/components/sidebar/types.js +6 -0
- package/dist/components/simple-clickable-card/simple-clickable-card-shared.js +309 -0
- package/dist/components/simple-clickable-card/simple-clickable-card.js +106 -0
- package/dist/components/simple-info-card/simple-info-card.js +154 -0
- package/dist/components/simple-list/simple-list.js +146 -0
- package/dist/components/simple-paginated-list/simple-paginated-list.js +178 -0
- package/dist/components/simplified-date/simplified-date.js +56 -0
- package/dist/components/skeletons/table-skeleton.js +16 -0
- package/dist/components/spinner/spinner.js +25 -0
- package/dist/components/stat-card/stat-card.js +206 -0
- package/dist/components/status-badge/status-badge.js +108 -0
- package/dist/components/status-card-list/status-card-list.js +282 -0
- package/dist/components/tag/tag.js +144 -0
- package/dist/components/tag-input/tag-input.js +161 -0
- package/dist/components/text-effects/glitch-effect/glitch-text.js +115 -0
- package/dist/components/text-effects/gradient-text/gradient-text.js +32 -0
- package/dist/components/text-effects/highlight-text/highlight-text.js +35 -0
- package/dist/components/text-effects/parse-text-markup.js +53 -0
- package/dist/components/text-effects/shimmer-text/shimmer-text.js +67 -0
- package/dist/components/time-picker/time-picker.js +23 -0
- package/dist/components/toast/toast.js +126 -0
- package/dist/components/togglable-items-list/togglable-items-list.js +28 -0
- package/dist/components/tooltip/tooltip.js +21 -0
- package/dist/components/transfer-list/transfer-list.js +413 -0
- package/dist/components/truncated-line-with-tooltip/truncated-line-with-tooltip.js +61 -0
- package/dist/components/typography/typography-variants.js +41 -0
- package/dist/components/typography/typography.js +15 -0
- package/dist/components/user-type-badge/user-type-badge.js +40 -0
- package/dist/components/user-type-badge/user-type-badge.registry.js +17 -0
- package/dist/components/vertical-stepper/vertical-stepper.js +171 -0
- package/dist/core/alert.js +33 -0
- package/dist/core/animate-ui/components/animate/code-header.js +30 -0
- package/dist/core/animate-ui/components/animate/code.js +35 -0
- package/dist/core/animate-ui/components/animate/tabs.js +188 -0
- package/dist/core/animate-ui/components/animate/tooltip.js +39 -0
- package/dist/core/animate-ui/components/base/preview-card.js +29 -0
- package/dist/core/animate-ui/components/base/progress.js +32 -0
- package/dist/core/animate-ui/components/base/radio.js +24 -0
- package/dist/core/animate-ui/components/buttons/copy.js +95 -0
- package/dist/core/animate-ui/components/radix/accordion.js +36 -0
- package/dist/core/animate-ui/components/radix/dialog.js +60 -0
- package/dist/core/animate-ui/components/radix/dropdown-menu.js +129 -0
- package/dist/core/animate-ui/components/radix/sheet.js +110 -0
- package/dist/core/animate-ui/components/radix/sidebar.js +416 -0
- package/dist/core/animate-ui/components/radix/switch.js +34 -0
- package/dist/core/animate-ui/components/radix/toggle-group.js +115 -0
- package/dist/core/animate-ui/components/radix/toggle.js +24 -0
- package/dist/core/animate-ui/primitives/animate/code-block.js +131 -0
- package/dist/core/animate-ui/primitives/animate/escape-html.js +7 -0
- package/dist/core/animate-ui/primitives/animate/shiki-highlighter.js +64 -0
- package/dist/core/animate-ui/primitives/animate/slot.js +39 -0
- package/dist/core/animate-ui/primitives/animate/tabs.js +202 -0
- package/dist/core/animate-ui/primitives/animate/tooltip.js +351 -0
- package/dist/core/animate-ui/primitives/base/preview-card.js +107 -0
- package/dist/core/animate-ui/primitives/base/progress.js +60 -0
- package/dist/core/animate-ui/primitives/base/radio.js +83 -0
- package/dist/core/animate-ui/primitives/buttons/button.js +16 -0
- package/dist/core/animate-ui/primitives/effects/highlight.js +407 -0
- package/dist/core/animate-ui/primitives/radix/accordion.js +76 -0
- package/dist/core/animate-ui/primitives/radix/dialog.js +136 -0
- package/dist/core/animate-ui/primitives/radix/dropdown-menu.js +305 -0
- package/dist/core/animate-ui/primitives/radix/sheet.js +165 -0
- package/dist/core/animate-ui/primitives/radix/switch.js +86 -0
- package/dist/core/animate-ui/primitives/radix/toggle-group.js +100 -0
- package/dist/core/animate-ui/primitives/texts/counting-number.js +75 -0
- package/dist/core/avatar.js +32 -0
- package/dist/core/badge.js +27 -0
- package/dist/core/breadcrumb.js +62 -0
- package/dist/core/button/button.js +43 -0
- package/dist/core/button/craft-button.js +78 -0
- package/dist/core/button-group.js +38 -0
- package/dist/core/button.js +40 -0
- package/dist/core/card.js +42 -0
- package/dist/core/carousel/carousel.js +149 -0
- package/dist/core/checkbox/motion-checkbox.js +103 -0
- package/dist/core/collapsible.js +54 -0
- package/dist/core/combobox/combobox.js +85 -0
- package/dist/core/command.js +61 -0
- package/dist/core/field-end-icons.js +36 -0
- package/dist/core/field-label-row.js +33 -0
- package/dist/core/form.js +92 -0
- package/dist/core/hooks/use-controlled-state.js +27 -0
- package/dist/core/hooks/use-data-state.js +39 -0
- package/dist/core/hooks/use-is-in-view.js +18 -0
- package/dist/core/hooks/use-mobile.js +19 -0
- package/dist/core/hooks/use-reveal-on-scroll-up.js +141 -0
- package/dist/core/hooks/use-scroll-overflow.js +50 -0
- package/dist/core/index.js +18 -52
- package/dist/core/input/input-password.js +30 -0
- package/dist/core/input/input.js +147 -0
- package/dist/core/input-otp/input-otp.js +183 -0
- package/dist/core/label.js +15 -0
- package/dist/core/popover.js +31 -0
- package/dist/core/scroll-area.js +42 -0
- package/dist/core/select.js +121 -0
- package/dist/core/separator.js +40 -0
- package/dist/core/skeleton.js +11 -0
- package/dist/core/table.js +59 -0
- package/dist/core/textarea/textarea.js +97 -0
- package/dist/core/utils/get-strict-context.js +18 -0
- package/dist/index.js +148 -9
- package/dist/layouts/entry-layout/entry-layout-bg.js +4 -0
- package/dist/layouts/entry-layout/entry-layout.js +52 -0
- package/dist/layouts/index.js +7 -6
- package/dist/layouts/workspace-layout/account-menu/account-menu.js +108 -0
- package/dist/layouts/workspace-layout/breadcrumbs/derive-breadcrumbs.js +37 -0
- package/dist/layouts/workspace-layout/breadcrumbs/workspace-breadcrumbs.js +22 -0
- package/dist/layouts/workspace-layout/footer/footer.js +15 -0
- package/dist/layouts/workspace-layout/header/header.js +54 -0
- package/dist/layouts/workspace-layout/workspace-layout.js +157 -0
- package/dist/tailwind-preset.js +3 -4
- package/dist/utils/cn.js +8 -0
- package/dist/utils/color.js +72 -0
- package/dist/utils/index.js +3 -2
- package/dist/utils/path-match.js +17 -0
- package/dist/utils/silver-shine.js +63 -0
- package/dist/utils/variant-gradient-underlay.js +45 -0
- package/dist/utils/variant.js +426 -0
- package/package.json +7 -4
- package/dist/chunk-2GDYZAKR.js +0 -505
- package/dist/chunk-ALCWXFUC.js +0 -733
- package/dist/chunk-CDHBLANU.js +0 -59
- package/dist/chunk-LUESSJAF.js +0 -70068
- package/dist/chunk-TMORRNEB.js +0 -323
- package/dist/chunk-TRTQSARU.js +0 -31
- package/dist/chunk-VU4CZ76T.js +0 -43
- package/dist/chunk-XNLCVHBC.js +0 -364
- package/dist/chunk-Z4776NRY.js +0 -4347
- package/src/assets/illustrations/add-to-group.svg +0 -32
- package/src/assets/illustrations/chip.svg +0 -51
- package/src/assets/illustrations/create-new-group.svg +0 -27
- package/src/assets/illustrations/new-ota.svg +0 -61
- package/src/assets/illustrations/secured-key.svg +0 -48
- /package/dist/assets/{entry-layout-bg-JPI7GJ42.webp → entry-layout-bg-DUM0UhT3.webp} +0 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { cn } from "../../utils/cn.js";
|
|
2
|
+
import { isPresetColor } from "../../utils/color.js";
|
|
3
|
+
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "./chart.js";
|
|
4
|
+
import { buildSeriesChartConfig } from "./chart-colors.js";
|
|
5
|
+
import * as React$1 from "react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { Treemap } from "recharts";
|
|
8
|
+
//#region src/components/chart/treemap-chart.tsx
|
|
9
|
+
var GRADIENT_TOP_OPACITY = 1;
|
|
10
|
+
var GRADIENT_BOTTOM_OPACITY = .82;
|
|
11
|
+
var TILE_RADIUS = 4;
|
|
12
|
+
var TILE_GUTTER = 2;
|
|
13
|
+
var LABEL_MIN_WIDTH = 60;
|
|
14
|
+
var LABEL_MIN_HEIGHT = 28;
|
|
15
|
+
var VALUE_MIN_WIDTH = 80;
|
|
16
|
+
var VALUE_MIN_HEIGHT = 44;
|
|
17
|
+
var DEFAULT_TREEMAP_ANIMATION_DURATION_MS = 300;
|
|
18
|
+
var DEFAULT_TREEMAP_ANIMATION_EASING = "ease-out";
|
|
19
|
+
var DEFAULT_LABEL_STYLE = {
|
|
20
|
+
color: "var(--color-foreground)",
|
|
21
|
+
outline: "none",
|
|
22
|
+
outlineWidth: 0,
|
|
23
|
+
fontSize: 12,
|
|
24
|
+
fontWeight: 600,
|
|
25
|
+
valueFontSize: 11,
|
|
26
|
+
valueFontWeight: 500
|
|
27
|
+
};
|
|
28
|
+
function defaultValueFormatter(value) {
|
|
29
|
+
return value.toLocaleString();
|
|
30
|
+
}
|
|
31
|
+
function deriveConfig(data, explicitConfig) {
|
|
32
|
+
if (explicitConfig) return explicitConfig;
|
|
33
|
+
const keys = Array.from(new Set(data.map((d) => d.key)));
|
|
34
|
+
const labels = {};
|
|
35
|
+
for (const d of data) if (typeof d.label === "string") labels[d.key] = d.label;
|
|
36
|
+
return buildSeriesChartConfig(keys, { labels });
|
|
37
|
+
}
|
|
38
|
+
function resolveConfigColor(config, key) {
|
|
39
|
+
const item = config[key];
|
|
40
|
+
if (!item) return void 0;
|
|
41
|
+
if ("color" in item && item.color) return item.color;
|
|
42
|
+
if ("theme" in item && item.theme) return item.theme.light ?? item.theme.dark;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Strip characters that aren't valid in CSS custom property names or in
|
|
46
|
+
* `url(#...)` SVG fragment refs. Keys like `/v1/login2` would otherwise
|
|
47
|
+
* produce broken `var(--color-/v1/login2)` declarations or unparseable
|
|
48
|
+
* gradient IDs, leaving tiles with no fill (i.e. black).
|
|
49
|
+
*/
|
|
50
|
+
function sanitizeId(key) {
|
|
51
|
+
return key.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Resolve a `Color` (preset token or arbitrary CSS color string) to a CSS
|
|
55
|
+
* color string usable in SVG `fill` / `stop-color` / `color-mix()`.
|
|
56
|
+
*/
|
|
57
|
+
function resolveBaseColor(color) {
|
|
58
|
+
if (isPresetColor(color)) return `var(--color-${color})`;
|
|
59
|
+
return color;
|
|
60
|
+
}
|
|
61
|
+
var RAMP_MIN_PCT = 25;
|
|
62
|
+
var RAMP_MAX_PCT = 85;
|
|
63
|
+
/**
|
|
64
|
+
* Build a monochrome ramp by mixing the base color with the active page
|
|
65
|
+
* background in `srgb`. Largest tile (i = 0) gets `RAMP_MAX_PCT` base;
|
|
66
|
+
* smallest (i = total - 1) gets `RAMP_MIN_PCT` base + the rest background.
|
|
67
|
+
*
|
|
68
|
+
* The ceiling is intentionally below 100% so the saturated end never punches
|
|
69
|
+
* out — important for tokens like dark-mode `--color-primary` (#7cd9ff)
|
|
70
|
+
* which would otherwise read as neon. Because the mix endpoint is
|
|
71
|
+
* `var(--color-background)`, the ramp auto-flips between light and dark
|
|
72
|
+
* themes: the saturated end stays bold, the faded end always blends.
|
|
73
|
+
*/
|
|
74
|
+
function shadeForIndex(base, index, total) {
|
|
75
|
+
if (total <= 1) return `color-mix(in srgb, ${base} ${RAMP_MAX_PCT}%, var(--color-background))`;
|
|
76
|
+
const t = index / (total - 1);
|
|
77
|
+
return `color-mix(in srgb, ${base} ${Math.round(RAMP_MAX_PCT - t * (RAMP_MAX_PCT - RAMP_MIN_PCT))}%, var(--color-background))`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Pick a text color that reads against the corresponding ramp shade without
|
|
81
|
+
* a stroke halo. For tiles in the saturated half (large values, more base
|
|
82
|
+
* color) we use `var(--color-background)`, which is the natural inverse of
|
|
83
|
+
* `var(--color-foreground)` in both light and dark themes — i.e. light text
|
|
84
|
+
* on saturated dark-blue in light mode, dark text on bright cyan in dark
|
|
85
|
+
* mode. For tiles in the faded half (small values, more background) we use
|
|
86
|
+
* `var(--color-foreground)` directly since the tile already approaches the
|
|
87
|
+
* surface. Returns `undefined` when there's only one tile so the caller can
|
|
88
|
+
* fall back to the explicit/default label color.
|
|
89
|
+
*/
|
|
90
|
+
function pickAutoTextColor(index, total) {
|
|
91
|
+
if (total <= 1) return "var(--color-background)";
|
|
92
|
+
return index / (total - 1) < .5 ? "var(--color-background)" : "var(--color-foreground)";
|
|
93
|
+
}
|
|
94
|
+
function TreemapTile(props) {
|
|
95
|
+
const { x = 0, y = 0, width = 0, height = 0, depth = 0, name, value, label, gradientScope, gradient, valueFormatter, colorByKey, textColorByKey, autoTextColor, labelStyle } = props;
|
|
96
|
+
if (depth === 0 || width <= 0 || height <= 0) return null;
|
|
97
|
+
const tileKey = name ?? "";
|
|
98
|
+
const resolvedColor = colorByKey.get(tileKey) ?? "var(--color-muted)";
|
|
99
|
+
const fill = gradient ? `url(#treemap-grad-${gradientScope}-${sanitizeId(tileKey)})` : resolvedColor;
|
|
100
|
+
const textFill = autoTextColor && textColorByKey.has(tileKey) ? textColorByKey.get(tileKey) : labelStyle.color;
|
|
101
|
+
const insetX = x + TILE_GUTTER / 2;
|
|
102
|
+
const insetY = y + TILE_GUTTER / 2;
|
|
103
|
+
const insetW = Math.max(0, width - TILE_GUTTER);
|
|
104
|
+
const insetH = Math.max(0, height - TILE_GUTTER);
|
|
105
|
+
const showLabel = insetW >= LABEL_MIN_WIDTH && insetH >= LABEL_MIN_HEIGHT;
|
|
106
|
+
const showValue = insetW >= VALUE_MIN_WIDTH && insetH >= VALUE_MIN_HEIGHT;
|
|
107
|
+
const labelText = typeof label === "string" && label.length > 0 ? label : tileKey;
|
|
108
|
+
const charWidth = Math.max(5, labelStyle.fontSize * .58);
|
|
109
|
+
const maxChars = Math.max(3, Math.floor((insetW - 16) / charWidth));
|
|
110
|
+
const displayLabel = labelText.length > maxChars ? `${labelText.slice(0, Math.max(1, maxChars - 1))}\u2026` : labelText;
|
|
111
|
+
const textOutlineStyle = labelStyle.outline !== "none" && labelStyle.outlineWidth > 0 ? {
|
|
112
|
+
paintOrder: "stroke",
|
|
113
|
+
stroke: labelStyle.outline,
|
|
114
|
+
strokeWidth: labelStyle.outlineWidth,
|
|
115
|
+
strokeLinejoin: "round"
|
|
116
|
+
} : {};
|
|
117
|
+
const labelY = insetY + Math.max(14, labelStyle.fontSize + 6);
|
|
118
|
+
const valueY = labelY + Math.max(12, labelStyle.valueFontSize + 5);
|
|
119
|
+
return /* @__PURE__ */ jsxs("g", {
|
|
120
|
+
className: "esp-treemap-tile",
|
|
121
|
+
children: [
|
|
122
|
+
/* @__PURE__ */ jsx("rect", {
|
|
123
|
+
x: insetX,
|
|
124
|
+
y: insetY,
|
|
125
|
+
width: insetW,
|
|
126
|
+
height: insetH,
|
|
127
|
+
rx: TILE_RADIUS,
|
|
128
|
+
ry: TILE_RADIUS,
|
|
129
|
+
fill,
|
|
130
|
+
className: "transition-opacity duration-150 hover:opacity-90"
|
|
131
|
+
}),
|
|
132
|
+
showLabel && /* @__PURE__ */ jsx("text", {
|
|
133
|
+
x: insetX + 10,
|
|
134
|
+
y: labelY,
|
|
135
|
+
fill: textFill,
|
|
136
|
+
fontSize: labelStyle.fontSize,
|
|
137
|
+
fontWeight: labelStyle.fontWeight,
|
|
138
|
+
style: {
|
|
139
|
+
...textOutlineStyle,
|
|
140
|
+
pointerEvents: "none"
|
|
141
|
+
},
|
|
142
|
+
children: displayLabel
|
|
143
|
+
}),
|
|
144
|
+
showValue && typeof value === "number" && /* @__PURE__ */ jsx("text", {
|
|
145
|
+
x: insetX + 10,
|
|
146
|
+
y: valueY,
|
|
147
|
+
fill: textFill,
|
|
148
|
+
fontSize: labelStyle.valueFontSize,
|
|
149
|
+
fontWeight: labelStyle.valueFontWeight,
|
|
150
|
+
opacity: .95,
|
|
151
|
+
style: {
|
|
152
|
+
...textOutlineStyle,
|
|
153
|
+
fontVariantNumeric: "tabular-nums",
|
|
154
|
+
pointerEvents: "none"
|
|
155
|
+
},
|
|
156
|
+
children: valueFormatter(value)
|
|
157
|
+
})
|
|
158
|
+
]
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
function TreemapLegend({ config, order, colorByKey }) {
|
|
162
|
+
const seen = /* @__PURE__ */ new Set();
|
|
163
|
+
const items = order.filter((k) => {
|
|
164
|
+
if (seen.has(k)) return false;
|
|
165
|
+
seen.add(k);
|
|
166
|
+
return k in config;
|
|
167
|
+
}).map((k) => ({
|
|
168
|
+
key: k,
|
|
169
|
+
entry: config[k]
|
|
170
|
+
}));
|
|
171
|
+
if (items.length === 0) return null;
|
|
172
|
+
return /* @__PURE__ */ jsx("div", {
|
|
173
|
+
className: "flex flex-wrap items-center justify-start gap-x-4 gap-y-2 pt-3 text-sm",
|
|
174
|
+
children: items.map(({ key, entry }) => {
|
|
175
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
176
|
+
className: "flex items-center gap-1.5",
|
|
177
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
178
|
+
className: "h-3 w-3 shrink-0 rounded-sm",
|
|
179
|
+
style: { backgroundColor: colorByKey.get(key) ?? resolveConfigColor(config, key) }
|
|
180
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
181
|
+
className: "font-normal text-foreground",
|
|
182
|
+
children: entry.label ?? key
|
|
183
|
+
})]
|
|
184
|
+
}, key);
|
|
185
|
+
})
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
var TreemapChart = React$1.forwardRef(function TreemapChart({ data, config: explicitConfig, color, maxDataPoints, showTooltip = true, showLegend = false, gradient = true, aspectRatio = 4 / 3, valueFormatter = defaultValueFormatter, labelStyle, className, isAnimationActive = true, animationDuration = DEFAULT_TREEMAP_ANIMATION_DURATION_MS, animationEasing = DEFAULT_TREEMAP_ANIMATION_EASING, animationBegin = 0, isUpdateAnimationActive }, ref) {
|
|
189
|
+
const resolvedUpdateAnimationActive = isUpdateAnimationActive ?? isAnimationActive;
|
|
190
|
+
const gradientScope = React$1.useId().replace(/:/g, "");
|
|
191
|
+
const resolvedLabelStyle = React$1.useMemo(() => ({
|
|
192
|
+
...DEFAULT_LABEL_STYLE,
|
|
193
|
+
...labelStyle
|
|
194
|
+
}), [labelStyle]);
|
|
195
|
+
const sortedData = React$1.useMemo(() => {
|
|
196
|
+
const sorted = [...data].sort((a, b) => b.value - a.value);
|
|
197
|
+
if (typeof maxDataPoints === "number" && maxDataPoints > 0) return sorted.slice(0, maxDataPoints);
|
|
198
|
+
return sorted;
|
|
199
|
+
}, [data, maxDataPoints]);
|
|
200
|
+
const config = React$1.useMemo(() => deriveConfig(sortedData, explicitConfig), [sortedData, explicitConfig]);
|
|
201
|
+
const uniqueKeys = React$1.useMemo(() => Array.from(new Set(sortedData.map((d) => d.key))), [sortedData]);
|
|
202
|
+
const colorByKey = React$1.useMemo(() => {
|
|
203
|
+
const map = /* @__PURE__ */ new Map();
|
|
204
|
+
if (typeof color === "string" && color.length > 0) {
|
|
205
|
+
const base = resolveBaseColor(color);
|
|
206
|
+
sortedData.forEach((d, i) => {
|
|
207
|
+
if (!map.has(d.key)) map.set(d.key, shadeForIndex(base, i, sortedData.length));
|
|
208
|
+
});
|
|
209
|
+
} else for (const k of uniqueKeys) map.set(k, resolveConfigColor(config, k) ?? "var(--color-muted)");
|
|
210
|
+
return map;
|
|
211
|
+
}, [
|
|
212
|
+
config,
|
|
213
|
+
uniqueKeys,
|
|
214
|
+
color,
|
|
215
|
+
sortedData
|
|
216
|
+
]);
|
|
217
|
+
const textColorByKey = React$1.useMemo(() => {
|
|
218
|
+
const map = /* @__PURE__ */ new Map();
|
|
219
|
+
if (typeof color === "string" && color.length > 0) sortedData.forEach((d, i) => {
|
|
220
|
+
if (!map.has(d.key)) map.set(d.key, pickAutoTextColor(i, sortedData.length));
|
|
221
|
+
});
|
|
222
|
+
return map;
|
|
223
|
+
}, [color, sortedData]);
|
|
224
|
+
const autoTextColor = labelStyle?.color === void 0;
|
|
225
|
+
const treemapData = React$1.useMemo(() => sortedData.map((d) => ({
|
|
226
|
+
...d,
|
|
227
|
+
name: d.key,
|
|
228
|
+
fill: colorByKey.get(d.key)
|
|
229
|
+
})), [sortedData, colorByKey]);
|
|
230
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
231
|
+
ref,
|
|
232
|
+
className: cn("flex w-full flex-col", className),
|
|
233
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
234
|
+
className: "relative min-h-0 flex-1",
|
|
235
|
+
children: /* @__PURE__ */ jsx(ChartContainer, {
|
|
236
|
+
config,
|
|
237
|
+
className: "h-full w-full",
|
|
238
|
+
children: /* @__PURE__ */ jsxs(Treemap, {
|
|
239
|
+
data: treemapData,
|
|
240
|
+
dataKey: "value",
|
|
241
|
+
nameKey: "key",
|
|
242
|
+
aspectRatio,
|
|
243
|
+
stroke: "transparent",
|
|
244
|
+
isAnimationActive,
|
|
245
|
+
isUpdateAnimationActive: resolvedUpdateAnimationActive,
|
|
246
|
+
animationBegin,
|
|
247
|
+
animationDuration,
|
|
248
|
+
animationEasing,
|
|
249
|
+
content: /* @__PURE__ */ jsx(TreemapTile, {
|
|
250
|
+
gradientScope,
|
|
251
|
+
gradient,
|
|
252
|
+
valueFormatter,
|
|
253
|
+
colorByKey,
|
|
254
|
+
textColorByKey,
|
|
255
|
+
autoTextColor,
|
|
256
|
+
labelStyle: resolvedLabelStyle
|
|
257
|
+
}),
|
|
258
|
+
children: [gradient && /* @__PURE__ */ jsx("defs", { children: uniqueKeys.map((key) => {
|
|
259
|
+
const stopColor = colorByKey.get(key) ?? "var(--color-muted)";
|
|
260
|
+
return /* @__PURE__ */ jsxs("linearGradient", {
|
|
261
|
+
id: `treemap-grad-${gradientScope}-${sanitizeId(key)}`,
|
|
262
|
+
x1: "0",
|
|
263
|
+
y1: "0",
|
|
264
|
+
x2: "0",
|
|
265
|
+
y2: "1",
|
|
266
|
+
children: [/* @__PURE__ */ jsx("stop", {
|
|
267
|
+
offset: "0%",
|
|
268
|
+
stopColor,
|
|
269
|
+
stopOpacity: GRADIENT_TOP_OPACITY
|
|
270
|
+
}), /* @__PURE__ */ jsx("stop", {
|
|
271
|
+
offset: "100%",
|
|
272
|
+
stopColor,
|
|
273
|
+
stopOpacity: GRADIENT_BOTTOM_OPACITY
|
|
274
|
+
})]
|
|
275
|
+
}, key);
|
|
276
|
+
}) }), showTooltip && /* @__PURE__ */ jsx(ChartTooltip, {
|
|
277
|
+
cursor: false,
|
|
278
|
+
content: /* @__PURE__ */ jsx(ChartTooltipContent, {
|
|
279
|
+
hideLabel: true,
|
|
280
|
+
nameKey: "key"
|
|
281
|
+
})
|
|
282
|
+
})]
|
|
283
|
+
})
|
|
284
|
+
})
|
|
285
|
+
}), showLegend && /* @__PURE__ */ jsx(TreemapLegend, {
|
|
286
|
+
config,
|
|
287
|
+
order: uniqueKeys,
|
|
288
|
+
colorByKey
|
|
289
|
+
})]
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
TreemapChart.displayName = "TreemapChart";
|
|
293
|
+
//#endregion
|
|
294
|
+
export { TreemapChart };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { cn } from "../../utils/cn.js";
|
|
2
|
+
import { isPresetColor, resolveColor } from "../../utils/color.js";
|
|
3
|
+
import * as React$1 from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/circular-progress/circular-progress.tsx
|
|
6
|
+
var VIEW_CENTER = 50;
|
|
7
|
+
var DEFAULT_SIZE_PX = 36;
|
|
8
|
+
var MIN_SIZE_PX = 16;
|
|
9
|
+
var MAX_SIZE_PX = 512;
|
|
10
|
+
/** Ring thickness as a fraction of `size` (matches previous default at 36px). */
|
|
11
|
+
var STROKE_TO_SIZE = 4 / 36;
|
|
12
|
+
/** Share of inner diameter used for label cap height so "100.0%" fits. */
|
|
13
|
+
var LABEL_TO_INNER_DIAMETER = .24;
|
|
14
|
+
var presetTrackClassMap = {
|
|
15
|
+
primary: "text-primary/20",
|
|
16
|
+
secondary: "text-secondary/20",
|
|
17
|
+
error: "text-error/20",
|
|
18
|
+
info: "text-info/20",
|
|
19
|
+
success: "text-success/20",
|
|
20
|
+
warning: "text-warning/20",
|
|
21
|
+
disabled: "text-disabled/20",
|
|
22
|
+
gray: "text-gray/20",
|
|
23
|
+
mist: "text-mist-border"
|
|
24
|
+
};
|
|
25
|
+
var presetProgressClassMap = {
|
|
26
|
+
primary: "text-primary",
|
|
27
|
+
secondary: "text-secondary",
|
|
28
|
+
error: "text-error",
|
|
29
|
+
info: "text-info",
|
|
30
|
+
success: "text-success",
|
|
31
|
+
warning: "text-warning",
|
|
32
|
+
disabled: "text-disabled",
|
|
33
|
+
gray: "text-gray",
|
|
34
|
+
mist: "text-mist-foreground"
|
|
35
|
+
};
|
|
36
|
+
function clampSizePx(size) {
|
|
37
|
+
if (!Number.isFinite(size)) return DEFAULT_SIZE_PX;
|
|
38
|
+
return Math.min(MAX_SIZE_PX, Math.max(MIN_SIZE_PX, size));
|
|
39
|
+
}
|
|
40
|
+
function strokeWidthPx(sizePx) {
|
|
41
|
+
return sizePx * STROKE_TO_SIZE;
|
|
42
|
+
}
|
|
43
|
+
/** Stroke width in viewBox 0–100 units (constant ratio for all sizes). */
|
|
44
|
+
var STROKE_WIDTH_VIEWBOX = STROKE_TO_SIZE * 100;
|
|
45
|
+
function labelFontSizePx(sizePx) {
|
|
46
|
+
const stroke = strokeWidthPx(sizePx);
|
|
47
|
+
const px = Math.max(0, sizePx - 2 * stroke) * LABEL_TO_INNER_DIAMETER;
|
|
48
|
+
return Math.max(5, Math.min(72, Math.round(px)));
|
|
49
|
+
}
|
|
50
|
+
function clampProgress(value) {
|
|
51
|
+
return Math.min(100, Math.max(0, value));
|
|
52
|
+
}
|
|
53
|
+
function truncateOneDecimal(value) {
|
|
54
|
+
return Math.trunc(value * 10) / 10;
|
|
55
|
+
}
|
|
56
|
+
function strokeResolvedStyle(color, opacity) {
|
|
57
|
+
if (isPresetColor(color)) return void 0;
|
|
58
|
+
return { stroke: opacity === "muted" ? `color-mix(in srgb, ${color} 20%, transparent)` : color };
|
|
59
|
+
}
|
|
60
|
+
var labelTypographyClass = "whitespace-nowrap text-center leading-none font-semibold tracking-tight tabular-nums";
|
|
61
|
+
var CircularProgress = React$1.forwardRef(function CircularProgress({ value, showPercentage = false, color = "primary", size = DEFAULT_SIZE_PX, className, style, ...props }, ref) {
|
|
62
|
+
const boxSize = clampSizePx(size);
|
|
63
|
+
const displayValue = truncateOneDecimal(clampProgress(value));
|
|
64
|
+
const strokeWidth = STROKE_WIDTH_VIEWBOX;
|
|
65
|
+
const r = VIEW_CENTER - strokeWidth / 2;
|
|
66
|
+
const circumference = 2 * Math.PI * r;
|
|
67
|
+
const dashOffset = circumference * (1 - displayValue / 100);
|
|
68
|
+
const fontSizePx = labelFontSizePx(boxSize);
|
|
69
|
+
const presetTrackClass = isPresetColor(color) ? presetTrackClassMap[color] : void 0;
|
|
70
|
+
const presetProgressClass = isPresetColor(color) ? presetProgressClassMap[color] : void 0;
|
|
71
|
+
const trackExtraStyle = strokeResolvedStyle(color, "muted");
|
|
72
|
+
const progressResolved = !isPresetColor(color) ? resolveColor(color, "text") : null;
|
|
73
|
+
const progressExtraStyle = progressResolved?.style != null ? { stroke: progressResolved.style.color } : void 0;
|
|
74
|
+
const labelColorStyle = !isPresetColor(color) && progressResolved?.style?.color != null ? { color: progressResolved.style.color } : void 0;
|
|
75
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
76
|
+
ref,
|
|
77
|
+
role: "progressbar",
|
|
78
|
+
"aria-valuemin": 0,
|
|
79
|
+
"aria-valuemax": 100,
|
|
80
|
+
"aria-valuenow": displayValue,
|
|
81
|
+
className: cn("relative inline-flex shrink-0 items-center justify-center", className),
|
|
82
|
+
style: {
|
|
83
|
+
...style,
|
|
84
|
+
width: boxSize,
|
|
85
|
+
height: boxSize
|
|
86
|
+
},
|
|
87
|
+
...props,
|
|
88
|
+
children: [/* @__PURE__ */ jsx("svg", {
|
|
89
|
+
className: "size-full",
|
|
90
|
+
viewBox: "0 0 100 100",
|
|
91
|
+
"aria-hidden": true,
|
|
92
|
+
children: /* @__PURE__ */ jsxs("g", {
|
|
93
|
+
transform: `rotate(-90 ${VIEW_CENTER} ${VIEW_CENTER})`,
|
|
94
|
+
children: [/* @__PURE__ */ jsx("circle", {
|
|
95
|
+
className: cn("fill-none", presetTrackClass != null && cn("stroke-current", presetTrackClass)),
|
|
96
|
+
style: trackExtraStyle,
|
|
97
|
+
cx: VIEW_CENTER,
|
|
98
|
+
cy: VIEW_CENTER,
|
|
99
|
+
r,
|
|
100
|
+
strokeWidth
|
|
101
|
+
}), /* @__PURE__ */ jsx("circle", {
|
|
102
|
+
className: cn("fill-none", presetProgressClass != null && cn("stroke-current", presetProgressClass)),
|
|
103
|
+
style: progressExtraStyle,
|
|
104
|
+
cx: VIEW_CENTER,
|
|
105
|
+
cy: VIEW_CENTER,
|
|
106
|
+
r,
|
|
107
|
+
strokeWidth,
|
|
108
|
+
strokeLinecap: "round",
|
|
109
|
+
strokeDasharray: circumference,
|
|
110
|
+
strokeDashoffset: dashOffset
|
|
111
|
+
})]
|
|
112
|
+
})
|
|
113
|
+
}), showPercentage ? /* @__PURE__ */ jsxs("span", {
|
|
114
|
+
className: cn("pointer-events-none absolute inset-0 flex min-h-0 min-w-0 items-center justify-center", presetProgressClass, labelTypographyClass),
|
|
115
|
+
style: {
|
|
116
|
+
fontSize: fontSizePx,
|
|
117
|
+
...labelColorStyle
|
|
118
|
+
},
|
|
119
|
+
children: [displayValue.toFixed(1), "%"]
|
|
120
|
+
}) : null]
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
CircularProgress.displayName = "CircularProgress";
|
|
124
|
+
//#endregion
|
|
125
|
+
export { CircularProgress };
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../../utils/cn.js";
|
|
3
|
+
import { buttonVariants } from "../../core/animate-ui/components/buttons/copy.js";
|
|
4
|
+
import { FieldLabelRow, fieldHintClassName } from "../../core/field-label-row.js";
|
|
5
|
+
import { CodeHeader } from "../../core/animate-ui/components/animate/code-header.js";
|
|
6
|
+
import { getBuiltInFormatter } from "./code-editor.utils.js";
|
|
7
|
+
import { applyEdit, useCodeEditorKeys } from "./use-code-editor-keys.js";
|
|
8
|
+
import { DEFAULT_CODE_EDITOR_THEMES, useHighlightedHtml } from "./use-highlighted-html.js";
|
|
9
|
+
import * as React$1 from "react";
|
|
10
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
import { Braces } from "lucide-react";
|
|
12
|
+
//#region src/components/code-editor/code-editor.tsx
|
|
13
|
+
/**
|
|
14
|
+
* Metrics every layer shares. The textarea and the highlighted text sit in
|
|
15
|
+
* the same grid cell, so any difference in font, size, spacing, padding or
|
|
16
|
+
* wrapping shows up as a caret that drifts from the characters. Ligatures are
|
|
17
|
+
* off because Shiki's token spans break them in the highlight layer but not
|
|
18
|
+
* in the textarea. 16px below `md` stops iOS Safari zooming on focus.
|
|
19
|
+
*/
|
|
20
|
+
var layerClassName = "col-start-1 row-start-1 m-0 box-border border-0 p-4 font-mono text-[16px] leading-normal tracking-normal [font-variant-ligatures:none] md:text-[13px]";
|
|
21
|
+
/** Highlight layer: Shiki's `<pre>` / `<code>` take their metrics from the layer. */
|
|
22
|
+
var highlightClassName = "[&_pre]:m-0 [&_pre]:p-0 [&_pre]:!bg-transparent [&_pre]:[font:inherit] [&_pre]:[white-space:inherit] [&_pre]:[overflow-wrap:inherit] [&_code]:[font:inherit]";
|
|
23
|
+
/**
|
|
24
|
+
* Reports assignments to `textarea.value` that fire no `input` event, such as
|
|
25
|
+
* react-hook-form's `register` writing default values, `setValue` and
|
|
26
|
+
* `reset`, and a native form reset. An uncontrolled editor needs them to
|
|
27
|
+
* keep its highlight layer in sync. The wrapper chains to whatever `value`
|
|
28
|
+
* descriptor is present (React's own value tracker), so React still sees
|
|
29
|
+
* every change.
|
|
30
|
+
*/
|
|
31
|
+
function observeValueWrites(node, onWrite) {
|
|
32
|
+
const own = Object.getOwnPropertyDescriptor(node, "value");
|
|
33
|
+
const base = own ?? Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value");
|
|
34
|
+
if (!base?.get || !base.set || own && !own.configurable) return () => {};
|
|
35
|
+
const { get, set } = base;
|
|
36
|
+
Object.defineProperty(node, "value", {
|
|
37
|
+
configurable: true,
|
|
38
|
+
enumerable: base.enumerable,
|
|
39
|
+
get() {
|
|
40
|
+
return get.call(this);
|
|
41
|
+
},
|
|
42
|
+
set(next) {
|
|
43
|
+
set.call(this, next);
|
|
44
|
+
onWrite(get.call(this));
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
const form = node.form;
|
|
48
|
+
const handleReset = () => setTimeout(() => onWrite(node.value));
|
|
49
|
+
form?.addEventListener("reset", handleReset);
|
|
50
|
+
return () => {
|
|
51
|
+
form?.removeEventListener("reset", handleReset);
|
|
52
|
+
if (own) Object.defineProperty(node, "value", own);
|
|
53
|
+
else delete node.value;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/** True for header content worth a header row; `""`, `false` and `null` render nothing. */
|
|
57
|
+
function hasContent(node) {
|
|
58
|
+
return node != null && node !== false && node !== "";
|
|
59
|
+
}
|
|
60
|
+
function toCssSize(size) {
|
|
61
|
+
return typeof size === "number" ? `${size}px` : size;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Editable, syntax-highlighted code input. Looks like `Code` (same header,
|
|
65
|
+
* copy button and Shiki themes) and behaves like `Textarea` in a form:
|
|
66
|
+
* controlled or uncontrolled, native `onChange`, ref to the `<textarea>`.
|
|
67
|
+
*
|
|
68
|
+
* Tab indents, Shift+Tab outdents, Enter keeps the indentation. Press Esc,
|
|
69
|
+
* then Tab, to move focus out of the editor. For JSON (or with a custom
|
|
70
|
+
* `formatter`) the header has a Format button next to Copy.
|
|
71
|
+
*/
|
|
72
|
+
var CodeEditor = React$1.forwardRef(({ className, style, lang = "json", theme = "light", themes = DEFAULT_CODE_EDITOR_THEMES, hideHeader = false, fileName, icon, copyButton = true, formatButton, formatter, onFormatError, formatLabel = "Format", copyLabel, headerActions, label, required, hintContent, error, errorContent, minHeight, maxHeight, wrap = false, tabSize = 2, maxHighlightLength = 1e4, id, value, defaultValue, onChange, onKeyDown, onBlur, onScroll, disabled, readOnly, "aria-describedby": ariaDescribedBy, ...textareaProps }, forwardedRef) => {
|
|
73
|
+
const autoId = React$1.useId();
|
|
74
|
+
const textareaId = id || autoId;
|
|
75
|
+
const errorId = `${textareaId}-error`;
|
|
76
|
+
const hasError = error || !!errorContent;
|
|
77
|
+
const isControlled = value !== void 0;
|
|
78
|
+
const [innerValue, setInnerValue] = React$1.useState(() => defaultValue == null ? "" : String(defaultValue));
|
|
79
|
+
const currentValue = isControlled ? String(value ?? "") : innerValue;
|
|
80
|
+
const html = useHighlightedHtml(currentValue, {
|
|
81
|
+
lang,
|
|
82
|
+
theme,
|
|
83
|
+
themes,
|
|
84
|
+
maxHighlightLength
|
|
85
|
+
});
|
|
86
|
+
const keys = useCodeEditorKeys({
|
|
87
|
+
tabSize,
|
|
88
|
+
onKeyDown,
|
|
89
|
+
onBlur
|
|
90
|
+
});
|
|
91
|
+
const textareaRef = React$1.useRef(null);
|
|
92
|
+
const stopObservingRef = React$1.useRef(void 0);
|
|
93
|
+
const setTextareaRef = React$1.useCallback((node) => {
|
|
94
|
+
textareaRef.current = node;
|
|
95
|
+
stopObservingRef.current?.();
|
|
96
|
+
stopObservingRef.current = void 0;
|
|
97
|
+
if (node && !isControlled) {
|
|
98
|
+
stopObservingRef.current = observeValueWrites(node, setInnerValue);
|
|
99
|
+
setInnerValue(node.value);
|
|
100
|
+
}
|
|
101
|
+
if (typeof forwardedRef === "function") forwardedRef(node);
|
|
102
|
+
else if (forwardedRef) forwardedRef.current = node;
|
|
103
|
+
}, [forwardedRef, isControlled]);
|
|
104
|
+
const handleChange = (event) => {
|
|
105
|
+
if (!isControlled) setInnerValue(event.target.value);
|
|
106
|
+
onChange?.(event);
|
|
107
|
+
};
|
|
108
|
+
const handleScroll = (event) => {
|
|
109
|
+
const el = event.currentTarget;
|
|
110
|
+
if (el.scrollTop !== 0) el.scrollTop = 0;
|
|
111
|
+
if (el.scrollLeft !== 0) el.scrollLeft = 0;
|
|
112
|
+
onScroll?.(event);
|
|
113
|
+
};
|
|
114
|
+
const builtInFormatter = getBuiltInFormatter(lang);
|
|
115
|
+
const format = formatter ?? (builtInFormatter && ((v) => builtInFormatter(v, tabSize)));
|
|
116
|
+
const showFormatButton = formatButton !== false && format !== void 0;
|
|
117
|
+
const handleFormat = () => {
|
|
118
|
+
const el = textareaRef.current;
|
|
119
|
+
if (!el || !format) return;
|
|
120
|
+
let formatted;
|
|
121
|
+
try {
|
|
122
|
+
formatted = format(el.value);
|
|
123
|
+
} catch (formatError) {
|
|
124
|
+
onFormatError?.(formatError);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
applyEdit(el, {
|
|
128
|
+
start: 0,
|
|
129
|
+
end: el.value.length,
|
|
130
|
+
text: formatted,
|
|
131
|
+
selectionStart: 0,
|
|
132
|
+
selectionEnd: 0
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
const describedBy = [ariaDescribedBy, errorContent ? errorId : void 0].filter(Boolean).join(" ") || void 0;
|
|
136
|
+
const wrapClassName = wrap ? "whitespace-pre-wrap [overflow-wrap:anywhere]" : "whitespace-pre [overflow-wrap:normal]";
|
|
137
|
+
const showHeader = !hideHeader && (hasContent(fileName) || copyButton || showFormatButton || hasContent(headerActions));
|
|
138
|
+
const actions = hasContent(headerActions) || showFormatButton ? /* @__PURE__ */ jsxs(Fragment$1, { children: [headerActions, showFormatButton && /* @__PURE__ */ jsx("button", {
|
|
139
|
+
type: "button",
|
|
140
|
+
"data-slot": "code-editor-format",
|
|
141
|
+
"aria-label": formatLabel,
|
|
142
|
+
title: formatLabel,
|
|
143
|
+
disabled: disabled || readOnly || currentValue.trim() === "",
|
|
144
|
+
onClick: handleFormat,
|
|
145
|
+
className: cn(buttonVariants({
|
|
146
|
+
variant: "ghost",
|
|
147
|
+
size: "sm"
|
|
148
|
+
}), "w-auto h-auto p-2"),
|
|
149
|
+
children: /* @__PURE__ */ jsx(Braces, {})
|
|
150
|
+
})] }) : void 0;
|
|
151
|
+
const editor = /* @__PURE__ */ jsxs("div", {
|
|
152
|
+
"data-slot": "code-editor",
|
|
153
|
+
"data-disabled": disabled ? "" : void 0,
|
|
154
|
+
className: cn("relative flex flex-col overflow-hidden rounded-lg border bg-background ring-offset-background transition-[box-shadow,border-color] duration-200 ease-in-out", "has-[textarea:focus-visible]:ring-2 has-[textarea:focus-visible]:ring-ring has-[textarea:focus-visible]:ring-offset-2", hasError && "border-destructive has-[textarea:focus-visible]:ring-destructive", className),
|
|
155
|
+
style,
|
|
156
|
+
children: [showHeader && /* @__PURE__ */ jsx(CodeHeader, {
|
|
157
|
+
icon,
|
|
158
|
+
fileName,
|
|
159
|
+
actions,
|
|
160
|
+
copyContent: copyButton ? currentValue : void 0,
|
|
161
|
+
copyLabel
|
|
162
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
163
|
+
className: cn("relative min-h-0 flex-1 overflow-auto bg-accent/10", disabled && "cursor-not-allowed opacity-50"),
|
|
164
|
+
style: { maxHeight: toCssSize(maxHeight) },
|
|
165
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
166
|
+
className: cn("grid", wrap ? "w-full grid-cols-[minmax(0,1fr)]" : "w-max min-w-full"),
|
|
167
|
+
style: {
|
|
168
|
+
minHeight: toCssSize(minHeight),
|
|
169
|
+
tabSize
|
|
170
|
+
},
|
|
171
|
+
children: [
|
|
172
|
+
/* @__PURE__ */ jsxs("div", {
|
|
173
|
+
"aria-hidden": true,
|
|
174
|
+
className: cn(layerClassName, wrapClassName, "invisible"),
|
|
175
|
+
children: [currentValue, ""]
|
|
176
|
+
}),
|
|
177
|
+
/* @__PURE__ */ jsx("div", {
|
|
178
|
+
"aria-hidden": true,
|
|
179
|
+
className: cn(layerClassName, wrapClassName, highlightClassName, "pointer-events-none"),
|
|
180
|
+
dangerouslySetInnerHTML: { __html: html }
|
|
181
|
+
}),
|
|
182
|
+
/* @__PURE__ */ jsx("textarea", {
|
|
183
|
+
id: textareaId,
|
|
184
|
+
ref: setTextareaRef,
|
|
185
|
+
value,
|
|
186
|
+
defaultValue,
|
|
187
|
+
disabled,
|
|
188
|
+
readOnly,
|
|
189
|
+
required,
|
|
190
|
+
wrap: wrap ? "soft" : "off",
|
|
191
|
+
spellCheck: false,
|
|
192
|
+
autoCapitalize: "off",
|
|
193
|
+
autoComplete: "off",
|
|
194
|
+
autoCorrect: "off",
|
|
195
|
+
translate: "no",
|
|
196
|
+
"data-gramm": "false",
|
|
197
|
+
"aria-invalid": hasError || void 0,
|
|
198
|
+
"aria-describedby": describedBy,
|
|
199
|
+
...textareaProps,
|
|
200
|
+
onChange: handleChange,
|
|
201
|
+
onKeyDown: keys.onKeyDown,
|
|
202
|
+
onBlur: keys.onBlur,
|
|
203
|
+
onScroll: handleScroll,
|
|
204
|
+
style: { tabSize },
|
|
205
|
+
className: cn(layerClassName, wrapClassName, "relative z-10 h-full w-full resize-none overflow-hidden bg-transparent text-transparent caret-foreground outline-none [-webkit-text-fill-color:transparent]", "placeholder:text-muted-foreground placeholder:[-webkit-text-fill-color:var(--color-muted-foreground)] selection:bg-primary/20", "disabled:cursor-not-allowed read-only:cursor-default")
|
|
206
|
+
})
|
|
207
|
+
]
|
|
208
|
+
})
|
|
209
|
+
})]
|
|
210
|
+
});
|
|
211
|
+
if (label == null && hintContent == null && errorContent == null) return editor;
|
|
212
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
213
|
+
className: "space-y-2 flex-1",
|
|
214
|
+
children: [
|
|
215
|
+
label != null ? /* @__PURE__ */ jsx(FieldLabelRow, {
|
|
216
|
+
htmlFor: textareaId,
|
|
217
|
+
label,
|
|
218
|
+
required,
|
|
219
|
+
hintContent
|
|
220
|
+
}) : hintContent != null && /* @__PURE__ */ jsx("span", {
|
|
221
|
+
className: fieldHintClassName,
|
|
222
|
+
children: hintContent
|
|
223
|
+
}),
|
|
224
|
+
editor,
|
|
225
|
+
errorContent != null && /* @__PURE__ */ jsx("div", {
|
|
226
|
+
id: errorId,
|
|
227
|
+
className: "text-sm text-destructive",
|
|
228
|
+
children: errorContent
|
|
229
|
+
})
|
|
230
|
+
]
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
CodeEditor.displayName = "CodeEditor";
|
|
234
|
+
//#endregion
|
|
235
|
+
export { CodeEditor };
|