@exegia/corpora-ui 3.0.0 → 4.0.0
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/README.md +20 -0
- package/dist-lib/autocomplete-DzjspdKa.js +151 -0
- package/dist-lib/base-CiR7nLAD.js +37 -0
- package/dist-lib/breadcrumb-DtFOhTfs.js +83 -0
- package/dist-lib/button-DDBbG_zF.js +143 -0
- package/dist-lib/button.js +3 -0
- package/dist-lib/calendar-Dyut8HPa.js +62 -0
- package/dist-lib/card.js +150 -0
- package/dist-lib/checkbox-group-B0BPFc-K.js +12 -0
- package/dist-lib/combobox-BwfmU1S_.js +267 -0
- package/dist-lib/components/atoms/text/default.d.ts +2 -1143
- package/dist-lib/components/blocks/shell/index.d.ts +1 -0
- package/dist-lib/components/blocks/sidebar-primitives/content.d.ts +2 -0
- package/dist-lib/components/blocks/sidebar-primitives/context.d.ts +2 -0
- package/dist-lib/components/blocks/sidebar-primitives/footer.d.ts +2 -0
- package/dist-lib/components/blocks/sidebar-primitives/group-action.d.ts +3 -0
- package/dist-lib/components/blocks/sidebar-primitives/group-content.d.ts +2 -0
- package/dist-lib/components/blocks/sidebar-primitives/group-label.d.ts +3 -0
- package/dist-lib/components/blocks/sidebar-primitives/group.d.ts +2 -0
- package/dist-lib/components/blocks/sidebar-primitives/header.d.ts +2 -0
- package/dist-lib/components/blocks/sidebar-primitives/index.d.ts +26 -0
- package/dist-lib/components/blocks/sidebar-primitives/input.d.ts +3 -0
- package/dist-lib/components/blocks/sidebar-primitives/inset.d.ts +2 -0
- package/dist-lib/components/blocks/sidebar-primitives/menu-action.d.ts +5 -0
- package/dist-lib/components/blocks/sidebar-primitives/menu-badge.d.ts +2 -0
- package/dist-lib/components/blocks/sidebar-primitives/menu-button.d.ts +9 -0
- package/dist-lib/components/blocks/sidebar-primitives/menu-item.d.ts +2 -0
- package/dist-lib/components/blocks/sidebar-primitives/menu-skeleton.d.ts +4 -0
- package/dist-lib/components/blocks/sidebar-primitives/menu-sub-button.d.ts +6 -0
- package/dist-lib/components/blocks/sidebar-primitives/menu-sub-item.d.ts +2 -0
- package/dist-lib/components/blocks/sidebar-primitives/menu-sub.d.ts +2 -0
- package/dist-lib/components/blocks/sidebar-primitives/menu.d.ts +2 -0
- package/dist-lib/components/blocks/sidebar-primitives/provider.d.ts +3 -0
- package/dist-lib/components/blocks/sidebar-primitives/rail.d.ts +2 -0
- package/dist-lib/components/blocks/sidebar-primitives/separator.d.ts +3 -0
- package/dist-lib/components/blocks/sidebar-primitives/sidebar-atom.d.ts +32 -0
- package/dist-lib/components/blocks/sidebar-primitives/sidebar.d.ts +6 -0
- package/dist-lib/components/blocks/sidebar-primitives/trigger.d.ts +3 -0
- package/dist-lib/components/blocks/sidebar-primitives/types.d.ts +26 -0
- package/dist-lib/components/blocks/sidebar-primitives/use-mobile.d.ts +1 -0
- package/dist-lib/components/blocks/sidebar-primitives/use-sidebar.d.ts +4 -0
- package/dist-lib/components/blocks/sidebar-primitives/utils.d.ts +10 -0
- package/dist-lib/components/ui/alert.d.ts +1 -1
- package/dist-lib/components/ui/badge.d.ts +2 -2
- package/dist-lib/components/ui/breadcrumb/base.d.ts +2 -0
- package/dist-lib/components/ui/breadcrumb/ellipsis.d.ts +2 -0
- package/dist-lib/components/ui/breadcrumb/index.d.ts +7 -0
- package/dist-lib/components/ui/breadcrumb/item.d.ts +2 -0
- package/dist-lib/components/ui/breadcrumb/link.d.ts +3 -0
- package/dist-lib/components/ui/breadcrumb/list.d.ts +2 -0
- package/dist-lib/components/ui/breadcrumb/page.d.ts +2 -0
- package/dist-lib/components/ui/breadcrumb/separator.d.ts +2 -0
- package/dist-lib/components/ui/button.d.ts +2 -2
- package/dist-lib/components/ui/calendar/base.d.ts +3 -0
- package/dist-lib/components/ui/calendar/index.d.ts +1 -0
- package/dist-lib/components/ui/calendar/utils.d.ts +1 -0
- package/dist-lib/components/ui/checkbox-group/base.d.ts +3 -0
- package/dist-lib/components/ui/checkbox-group/index.d.ts +2 -0
- package/dist-lib/components/ui/combobox/chip-remove.d.ts +3 -0
- package/dist-lib/components/ui/combobox/chip.d.ts +5 -0
- package/dist-lib/components/ui/combobox/chips-input.d.ts +6 -0
- package/dist-lib/components/ui/combobox/chips.d.ts +5 -0
- package/dist-lib/components/ui/combobox/clear.d.ts +3 -0
- package/dist-lib/components/ui/combobox/collection.d.ts +3 -0
- package/dist-lib/components/ui/combobox/context.d.ts +5 -0
- package/dist-lib/components/ui/combobox/empty.d.ts +3 -0
- package/dist-lib/components/ui/combobox/group-label.d.ts +3 -0
- package/dist-lib/components/ui/combobox/group.d.ts +3 -0
- package/dist-lib/components/ui/combobox/index.d.ts +22 -0
- package/dist-lib/components/ui/combobox/input.d.ts +11 -0
- package/dist-lib/components/ui/combobox/item.d.ts +3 -0
- package/dist-lib/components/ui/combobox/list.d.ts +3 -0
- package/dist-lib/components/ui/combobox/popup.d.ts +10 -0
- package/dist-lib/components/ui/combobox/root.d.ts +3 -0
- package/dist-lib/components/ui/combobox/row.d.ts +3 -0
- package/dist-lib/components/ui/combobox/separator.d.ts +3 -0
- package/dist-lib/components/ui/combobox/status.d.ts +3 -0
- package/dist-lib/components/ui/combobox/trigger.d.ts +3 -0
- package/dist-lib/components/ui/combobox/utils.d.ts +2 -0
- package/dist-lib/components/ui/combobox/value.d.ts +3 -0
- package/dist-lib/components/ui/dialog/backdrop.d.ts +3 -0
- package/dist-lib/components/ui/dialog/close.d.ts +3 -0
- package/dist-lib/components/ui/dialog/description.d.ts +3 -0
- package/dist-lib/components/ui/dialog/footer.d.ts +5 -0
- package/dist-lib/components/ui/dialog/header.d.ts +3 -0
- package/dist-lib/components/ui/dialog/index.d.ts +16 -0
- package/dist-lib/components/ui/dialog/panel.d.ts +5 -0
- package/dist-lib/components/ui/dialog/popup.d.ts +8 -0
- package/dist-lib/components/ui/dialog/title.d.ts +3 -0
- package/dist-lib/components/ui/dialog/trigger.d.ts +3 -0
- package/dist-lib/components/ui/dialog/utils.d.ts +4 -0
- package/dist-lib/components/ui/dialog/viewport.d.ts +3 -0
- package/dist-lib/components/ui/drawer/backdrop.d.ts +3 -0
- package/dist-lib/components/ui/drawer/bar.d.ts +6 -0
- package/dist-lib/components/ui/drawer/close.d.ts +3 -0
- package/dist-lib/components/ui/drawer/content.d.ts +3 -0
- package/dist-lib/components/ui/drawer/context.d.ts +5 -0
- package/dist-lib/components/ui/drawer/description.d.ts +3 -0
- package/dist-lib/components/ui/drawer/footer.d.ts +6 -0
- package/dist-lib/components/ui/drawer/header.d.ts +5 -0
- package/dist-lib/components/ui/drawer/index.d.ts +26 -0
- package/dist-lib/components/ui/drawer/menu-checkbox-item.d.ts +6 -0
- package/dist-lib/components/ui/drawer/menu-group-label.d.ts +3 -0
- package/dist-lib/components/ui/drawer/menu-group.d.ts +3 -0
- package/dist-lib/components/ui/drawer/menu-item.d.ts +5 -0
- package/dist-lib/components/ui/drawer/menu-radio-group.d.ts +3 -0
- package/dist-lib/components/ui/drawer/menu-radio-item.d.ts +6 -0
- package/dist-lib/components/ui/drawer/menu-separator.d.ts +3 -0
- package/dist-lib/components/ui/drawer/menu-trigger.d.ts +3 -0
- package/dist-lib/components/ui/drawer/menu.d.ts +3 -0
- package/dist-lib/components/ui/drawer/panel.d.ts +7 -0
- package/dist-lib/components/ui/drawer/popup.d.ts +10 -0
- package/dist-lib/components/ui/drawer/portal.d.ts +3 -0
- package/dist-lib/components/ui/drawer/root.d.ts +6 -0
- package/dist-lib/components/ui/drawer/swipe-area.d.ts +6 -0
- package/dist-lib/components/ui/drawer/title.d.ts +3 -0
- package/dist-lib/components/ui/drawer/trigger.d.ts +3 -0
- package/dist-lib/components/ui/drawer/types.d.ts +1 -0
- package/dist-lib/components/ui/drawer/utils.d.ts +4 -0
- package/dist-lib/components/ui/drawer/viewport.d.ts +7 -0
- package/dist-lib/components/ui/empty/base.d.ts +2 -0
- package/dist-lib/components/ui/empty/content.d.ts +2 -0
- package/dist-lib/components/ui/empty/description.d.ts +2 -0
- package/dist-lib/components/ui/empty/header.d.ts +2 -0
- package/dist-lib/components/ui/empty/index.d.ts +6 -0
- package/dist-lib/components/ui/empty/media.d.ts +4 -0
- package/dist-lib/components/ui/empty/title.d.ts +2 -0
- package/dist-lib/components/ui/empty/utils.d.ts +3 -0
- package/dist-lib/components/ui/fieldset/base.d.ts +3 -0
- package/dist-lib/components/ui/fieldset/index.d.ts +3 -0
- package/dist-lib/components/ui/fieldset/legend.d.ts +3 -0
- package/dist-lib/components/ui/form/base.d.ts +3 -0
- package/dist-lib/components/ui/form/index.d.ts +2 -0
- package/dist-lib/components/ui/glasscn/lazy-glass-surface.d.ts +6 -0
- package/dist-lib/components/ui/meter/base.d.ts +3 -0
- package/dist-lib/components/ui/meter/index.d.ts +6 -0
- package/dist-lib/components/ui/meter/indicator.d.ts +3 -0
- package/dist-lib/components/ui/meter/label.d.ts +3 -0
- package/dist-lib/components/ui/meter/track.d.ts +3 -0
- package/dist-lib/components/ui/meter/value.d.ts +3 -0
- package/dist-lib/components/ui/modal.d.ts +10 -0
- package/dist-lib/components/ui/number-field/base.d.ts +5 -0
- package/dist-lib/components/ui/number-field/context.d.ts +4 -0
- package/dist-lib/components/ui/number-field/cursor-grow-icon.d.ts +2 -0
- package/dist-lib/components/ui/number-field/decrement.d.ts +3 -0
- package/dist-lib/components/ui/number-field/group.d.ts +3 -0
- package/dist-lib/components/ui/number-field/increment.d.ts +3 -0
- package/dist-lib/components/ui/number-field/index.d.ts +9 -0
- package/dist-lib/components/ui/number-field/input.d.ts +3 -0
- package/dist-lib/components/ui/number-field/scrub-area.d.ts +5 -0
- package/dist-lib/components/ui/overlays.d.ts +4 -0
- package/dist-lib/components/ui/pagination/base.d.ts +2 -0
- package/dist-lib/components/ui/pagination/content.d.ts +2 -0
- package/dist-lib/components/ui/pagination/ellipsis.d.ts +2 -0
- package/dist-lib/components/ui/pagination/index.d.ts +8 -0
- package/dist-lib/components/ui/pagination/item.d.ts +2 -0
- package/dist-lib/components/ui/pagination/link.d.ts +3 -0
- package/dist-lib/components/ui/pagination/next.d.ts +3 -0
- package/dist-lib/components/ui/pagination/previous.d.ts +3 -0
- package/dist-lib/components/ui/pagination/types.d.ts +7 -0
- package/dist-lib/components/ui/preview-card.d.ts +2 -1
- package/dist-lib/components/ui/progress/base.d.ts +3 -0
- package/dist-lib/components/ui/progress/index.d.ts +6 -0
- package/dist-lib/components/ui/progress/indicator.d.ts +3 -0
- package/dist-lib/components/ui/progress/label.d.ts +3 -0
- package/dist-lib/components/ui/progress/track.d.ts +3 -0
- package/dist-lib/components/ui/progress/value.d.ts +3 -0
- package/dist-lib/components/ui/radio-group/base.d.ts +3 -0
- package/dist-lib/components/ui/radio-group/index.d.ts +5 -0
- package/dist-lib/components/ui/radio-group/radio.d.ts +3 -0
- package/dist-lib/components/ui/select.d.ts +1 -1
- package/dist-lib/components/ui/sheet-parts/backdrop.d.ts +2 -0
- package/dist-lib/components/ui/sheet-parts/overlay.d.ts +2 -0
- package/dist-lib/components/ui/sheet-parts/panel.d.ts +5 -0
- package/dist-lib/components/ui/sheet-parts/popup.d.ts +10 -0
- package/dist-lib/components/ui/sheet-parts/portal.d.ts +2 -0
- package/dist-lib/components/ui/sheet-parts/viewport.d.ts +6 -0
- package/dist-lib/components/ui/sheet.d.ts +19 -9
- package/dist-lib/components/ui/slider/base.d.ts +3 -0
- package/dist-lib/components/ui/slider/index.d.ts +3 -0
- package/dist-lib/components/ui/slider/value.d.ts +3 -0
- package/dist-lib/components/ui/table/base.d.ts +3 -0
- package/dist-lib/components/ui/table/body.d.ts +2 -0
- package/dist-lib/components/ui/table/caption.d.ts +2 -0
- package/dist-lib/components/ui/table/cell.d.ts +2 -0
- package/dist-lib/components/ui/table/footer.d.ts +2 -0
- package/dist-lib/components/ui/table/head.d.ts +2 -0
- package/dist-lib/components/ui/table/header.d.ts +2 -0
- package/dist-lib/components/ui/table/index.d.ts +10 -0
- package/dist-lib/components/ui/table/row.d.ts +2 -0
- package/dist-lib/components/ui/table/types.d.ts +7 -0
- package/dist-lib/components/ui/toast.d.ts +2 -0
- package/dist-lib/components/ui/toggle/base.d.ts +5 -0
- package/dist-lib/components/ui/toggle/index.d.ts +3 -0
- package/dist-lib/components/ui/toggle/utils.d.ts +4 -0
- package/dist-lib/components/ui/toggle-group/base.d.ts +5 -0
- package/dist-lib/components/ui/toggle-group/context.d.ts +4 -0
- package/dist-lib/components/ui/toggle-group/index.d.ts +5 -0
- package/dist-lib/components/ui/toggle-group/item.d.ts +5 -0
- package/dist-lib/components/ui/toggle-group/separator.d.ts +5 -0
- package/dist-lib/dialog-BF9rLVsx.js +135 -0
- package/dist-lib/drawer-DuQtc_IN.js +350 -0
- package/dist-lib/ease-C9At8rnB.js +120 -0
- package/dist-lib/empty-CUO4MoHd.js +87 -0
- package/dist-lib/exegia-provider-CDYMDsSW.js +126 -0
- package/dist-lib/fieldset-C3YDowBt.js +22 -0
- package/dist-lib/form-DdxBnCxo.js +12 -0
- package/dist-lib/index.css +3 -0
- package/dist-lib/index.d.ts +4 -0
- package/dist-lib/index.js +6649 -10344
- package/dist-lib/input.js +28 -0
- package/dist-lib/label.js +19 -0
- package/dist-lib/lib/segmented-control.d.ts +1 -1
- package/dist-lib/lib/state/exegia-provider.d.ts +17 -8
- package/dist-lib/lib/state/index.d.ts +2 -0
- package/dist-lib/lib/state/portal-context.d.ts +5 -0
- package/dist-lib/lib/state/sound-loading.d.ts +4 -0
- package/dist-lib/liquid-glass-BrmOha12.js +50 -0
- package/dist-lib/meter-B5i2cf7m.js +49 -0
- package/dist-lib/modal-BSBLNZfo.js +24 -0
- package/dist-lib/number-field-D5p-WTn_.js +97 -0
- package/dist-lib/overlays.js +5 -0
- package/dist-lib/pagination-CPOVfufE.js +94 -0
- package/dist-lib/popover-BKYgU_p3.js +62 -0
- package/dist-lib/portal-context-oIZFl3NP.js +9 -0
- package/dist-lib/progress-ByAk9CV5.js +50 -0
- package/dist-lib/radio-group-CMwDkKFE.js +27 -0
- package/dist-lib/rolldown-runtime-Dy4uBu1J.js +11 -0
- package/dist-lib/scaffold-DjS8eLk9.js +925 -0
- package/dist-lib/scaffold.js +2 -0
- package/dist-lib/scroll-area-BNcHlmRX.js +39 -0
- package/dist-lib/separator-D7T-98IV.js +14 -0
- package/dist-lib/sheet-BAYosIsg.js +148 -0
- package/dist-lib/sheet-D4fmEZW5.js +22 -0
- package/dist-lib/shell-WTIa9_ul.js +722 -0
- package/dist-lib/shell.js +2 -0
- package/dist-lib/sidebar-1j5RYZ2t.js +529 -0
- package/dist-lib/skeleton-CwqQoMiY.js +12 -0
- package/dist-lib/slider-_1H30BMt.js +48 -0
- package/dist-lib/sound-knGH4lj-.js +19 -0
- package/dist-lib/spinner-cwaneGYM.js +14 -0
- package/dist-lib/state.js +2 -0
- package/dist-lib/table-D43_yedE.js +87 -0
- package/dist-lib/tabs-CwWnKxRI.js +66 -0
- package/dist-lib/textarea-CxycYTkF.js +27 -0
- package/dist-lib/toast-BLwJEhKU.js +151 -0
- package/dist-lib/toggle-group-BzDvDKL0.js +55 -0
- package/dist-lib/tooltip-aPB3pyrl.js +39 -0
- package/dist-lib/ui/accordion.d.ts +1 -0
- package/dist-lib/ui/accordion.js +45 -0
- package/dist-lib/ui/alert-dialog.d.ts +1 -0
- package/dist-lib/ui/alert-dialog.js +74 -0
- package/dist-lib/ui/alert.d.ts +1 -0
- package/dist-lib/ui/alert.js +45 -0
- package/dist-lib/ui/autocomplete.d.ts +1 -0
- package/dist-lib/ui/autocomplete.js +2 -0
- package/dist-lib/ui/avatar.d.ts +2 -0
- package/dist-lib/ui/avatar.js +50 -0
- package/dist-lib/ui/badge.d.ts +2 -0
- package/dist-lib/ui/badge.js +72 -0
- package/dist-lib/ui/breadcrumb.d.ts +1 -0
- package/dist-lib/ui/breadcrumb.js +2 -0
- package/dist-lib/ui/button.d.ts +2 -0
- package/dist-lib/ui/button.js +2 -0
- package/dist-lib/ui/calendar.d.ts +1 -0
- package/dist-lib/ui/calendar.js +2 -0
- package/dist-lib/ui/card.d.ts +1 -0
- package/dist-lib/ui/card.js +2 -0
- package/dist-lib/ui/checkbox-group.d.ts +1 -0
- package/dist-lib/ui/checkbox-group.js +2 -0
- package/dist-lib/ui/checkbox.d.ts +1 -0
- package/dist-lib/ui/checkbox.js +51 -0
- package/dist-lib/ui/collapsible.d.ts +1 -0
- package/dist-lib/ui/collapsible.js +26 -0
- package/dist-lib/ui/combobox.d.ts +1 -0
- package/dist-lib/ui/combobox.js +2 -0
- package/dist-lib/ui/command.d.ts +1 -0
- package/dist-lib/ui/command.js +125 -0
- package/dist-lib/ui/context-menu.d.ts +1 -0
- package/dist-lib/ui/context-menu.js +178 -0
- package/dist-lib/ui/dialog.d.ts +1 -0
- package/dist-lib/ui/dialog.js +2 -0
- package/dist-lib/ui/drawer.d.ts +1 -0
- package/dist-lib/ui/drawer.js +2 -0
- package/dist-lib/ui/empty.d.ts +1 -0
- package/dist-lib/ui/empty.js +2 -0
- package/dist-lib/ui/field.d.ts +1 -0
- package/dist-lib/ui/field.js +42 -0
- package/dist-lib/ui/fieldset.d.ts +1 -0
- package/dist-lib/ui/fieldset.js +2 -0
- package/dist-lib/ui/form.d.ts +1 -0
- package/dist-lib/ui/form.js +2 -0
- package/dist-lib/ui/frame.d.ts +1 -0
- package/dist-lib/ui/frame.js +47 -0
- package/dist-lib/ui/group.d.ts +1 -0
- package/dist-lib/ui/group.js +44 -0
- package/dist-lib/ui/index.d.ts +55 -0
- package/dist-lib/ui/index.js +497 -0
- package/dist-lib/ui/input-group.d.ts +1 -0
- package/dist-lib/ui/input-group.js +59 -0
- package/dist-lib/ui/input.d.ts +2 -0
- package/dist-lib/ui/input.js +2 -0
- package/dist-lib/ui/kbd.d.ts +1 -0
- package/dist-lib/ui/kbd.js +19 -0
- package/dist-lib/ui/label.d.ts +1 -0
- package/dist-lib/ui/label.js +2 -0
- package/dist-lib/ui/menu.d.ts +1 -0
- package/dist-lib/ui/menu.js +178 -0
- package/dist-lib/ui/meter.d.ts +1 -0
- package/dist-lib/ui/meter.js +2 -0
- package/dist-lib/ui/number-field.d.ts +1 -0
- package/dist-lib/ui/number-field.js +2 -0
- package/dist-lib/ui/otp-field.d.ts +1 -0
- package/dist-lib/ui/otp-field.js +36 -0
- package/dist-lib/ui/pagination.d.ts +1 -0
- package/dist-lib/ui/pagination.js +2 -0
- package/dist-lib/ui/popover.d.ts +1 -0
- package/dist-lib/ui/popover.js +2 -0
- package/dist-lib/ui/preview-card.d.ts +1 -0
- package/dist-lib/ui/preview-card.js +35 -0
- package/dist-lib/ui/progress.d.ts +1 -0
- package/dist-lib/ui/progress.js +2 -0
- package/dist-lib/ui/radio-group.d.ts +1 -0
- package/dist-lib/ui/radio-group.js +2 -0
- package/dist-lib/ui/scroll-area.d.ts +1 -0
- package/dist-lib/ui/scroll-area.js +2 -0
- package/dist-lib/ui/select.d.ts +2 -0
- package/dist-lib/ui/select.js +145 -0
- package/dist-lib/ui/separator.d.ts +2 -0
- package/dist-lib/ui/separator.js +3 -0
- package/dist-lib/ui/sheet.d.ts +1 -0
- package/dist-lib/ui/sheet.js +3 -0
- package/dist-lib/ui/sidebar.d.ts +1 -0
- package/dist-lib/ui/sidebar.js +2 -0
- package/dist-lib/ui/skeleton.d.ts +1 -0
- package/dist-lib/ui/skeleton.js +2 -0
- package/dist-lib/ui/slider.d.ts +1 -0
- package/dist-lib/ui/slider.js +2 -0
- package/dist-lib/ui/spinner.d.ts +1 -0
- package/dist-lib/ui/spinner.js +2 -0
- package/dist-lib/ui/switch.d.ts +1 -0
- package/dist-lib/ui/switch.js +17 -0
- package/dist-lib/ui/table.d.ts +1 -0
- package/dist-lib/ui/table.js +2 -0
- package/dist-lib/ui/tabs.d.ts +1 -0
- package/dist-lib/ui/tabs.js +2 -0
- package/dist-lib/ui/textarea.d.ts +2 -0
- package/dist-lib/ui/textarea.js +2 -0
- package/dist-lib/ui/toast.d.ts +1 -0
- package/dist-lib/ui/toast.js +2 -0
- package/dist-lib/ui/toggle-group.d.ts +1 -0
- package/dist-lib/ui/toggle-group.js +2 -0
- package/dist-lib/ui/toggle.d.ts +1 -0
- package/dist-lib/ui/toggle.js +3 -0
- package/dist-lib/ui/toolbar.d.ts +1 -0
- package/dist-lib/ui/toolbar.js +48 -0
- package/dist-lib/ui/tooltip.d.ts +1 -0
- package/dist-lib/ui/tooltip.js +2 -0
- package/dist-lib/utils-BO0qfoA6.js +61 -0
- package/package.json +285 -23
- package/dist-lib/components/atoms/_layout.d.ts +0 -4
- package/dist-lib/components/atoms/bubble/__tests__/bubble.test.d.ts +0 -1
- package/dist-lib/components/atoms/bubble/__tests__/reference.test.d.ts +0 -1
- package/dist-lib/components/atoms/text/__tests__/text.test.d.ts +0 -1
- package/dist-lib/components/atoms/text-selection/__tests__/click-popover.test.d.ts +0 -1
- package/dist-lib/components/atoms/text-selection/__tests__/text-selection.test.d.ts +0 -1
- package/dist-lib/components/blocks/auth/__tests__/auth-flow-block.test.d.ts +0 -1
- package/dist-lib/components/blocks/auth/__tests__/auth-state-atom.test.d.ts +0 -1
- package/dist-lib/components/blocks/auth/__tests__/linked-accounts-block.test.d.ts +0 -1
- package/dist-lib/components/blocks/auth/__tests__/onboarding-block.test.d.ts +0 -1
- package/dist-lib/components/blocks/auth/__tests__/passkey-manager-block.test.d.ts +0 -1
- package/dist-lib/components/blocks/auth/__tests__/passkey-sign-in-block.test.d.ts +0 -1
- package/dist-lib/components/blocks/auth/__tests__/signup-block.test.d.ts +0 -1
- package/dist-lib/components/blocks/auth/__tests__/update-password-block.test.d.ts +0 -1
- package/dist-lib/components/blocks/chat/__tests__/ai-panel.test.d.ts +0 -1
- package/dist-lib/components/blocks/profile/__tests__/profile-card-block.test.d.ts +0 -1
- package/dist-lib/components/blocks/scaffold/__tests__/scaffold-atom.test.d.ts +0 -1
- package/dist-lib/components/blocks/scaffold/__tests__/scaffold.test.d.ts +0 -1
- package/dist-lib/components/blocks/shell/__tests__/shell-fit-atom.test.d.ts +0 -1
- package/dist-lib/components/blocks/shell/__tests__/shell-layout.test.d.ts +0 -1
- package/dist-lib/components/blocks/shell/__tests__/shell-metrics.test.d.ts +0 -1
- package/dist-lib/components/blocks/sidebar/__tests__/ai-sidebar-atom.test.d.ts +0 -1
- package/dist-lib/components/blocks/sidebar/__tests__/ai-sidebar.test.d.ts +0 -1
- package/dist-lib/components/blocks/sidebar/__tests__/use-ai-sidebar.test.d.ts +0 -1
- package/dist-lib/components/composed/__tests__/logo.test.d.ts +0 -1
- package/dist-lib/components/composed/action-bar/__tests__/action-bar.test.d.ts +0 -1
- package/dist-lib/components/composed/ai/__tests__/ai.test.d.ts +0 -1
- package/dist-lib/components/composed/chat/__tests__/attachment.test.d.ts +0 -1
- package/dist-lib/components/composed/chat/__tests__/beautiful-ui.test.d.ts +0 -1
- package/dist-lib/components/composed/chat/__tests__/chart.test.d.ts +0 -1
- package/dist-lib/components/composed/chat/__tests__/code-block.test.d.ts +0 -1
- package/dist-lib/components/composed/chat/__tests__/composer-attachments.test.d.ts +0 -1
- package/dist-lib/components/composed/chat/__tests__/composer.test.d.ts +0 -1
- package/dist-lib/components/composed/chat/__tests__/flowchart.test.d.ts +0 -1
- package/dist-lib/components/composed/chat/__tests__/glass-material.test.d.ts +0 -1
- package/dist-lib/components/composed/chat/__tests__/markdown.test.d.ts +0 -1
- package/dist-lib/components/composed/chat/__tests__/menu-command.test.d.ts +0 -1
- package/dist-lib/components/composed/chat/__tests__/recommendation.test.d.ts +0 -1
- package/dist-lib/components/composed/tree/__tests__/tree-atom.test.d.ts +0 -1
- package/dist-lib/components/composed/tree/__tests__/tree.test.d.ts +0 -1
- package/dist-lib/components/composed/tree/__tests__/use-tree.test.d.ts +0 -1
- package/dist-lib/components/composed/user/__tests__/message.test.d.ts +0 -1
- package/dist-lib/components/composed/verse/__tests__/verse.test.d.ts +0 -1
- package/dist-lib/components/docs/atoms-gallery.d.ts +0 -12
- package/dist-lib/components/docs/block-demo-stage.d.ts +0 -7
- package/dist-lib/components/docs/blocks-gallery.d.ts +0 -2
- package/dist-lib/components/docs/browser.d.ts +0 -10
- package/dist-lib/components/docs/code-block.d.ts +0 -4
- package/dist-lib/components/docs/components-gallery.d.ts +0 -2
- package/dist-lib/components/docs/demo-controls.d.ts +0 -21
- package/dist-lib/components/docs/hero.d.ts +0 -5
- package/dist-lib/components/docs/mermaid.d.ts +0 -3
- package/dist-lib/components/icons/__tests__/icons.test.d.ts +0 -1
- package/dist-lib/components/stories/attachment.story.d.ts +0 -11
- package/dist-lib/components/stories/auth-flow-block.story.d.ts +0 -2
- package/dist-lib/components/stories/avatar.story.d.ts +0 -6
- package/dist-lib/components/stories/base.story.d.ts +0 -6
- package/dist-lib/components/stories/bubble.story.d.ts +0 -6
- package/dist-lib/components/stories/button.story.d.ts +0 -9
- package/dist-lib/components/stories/card.story.d.ts +0 -8
- package/dist-lib/components/stories/chart.story.d.ts +0 -71
- package/dist-lib/components/stories/checkbox.story.d.ts +0 -6
- package/dist-lib/components/stories/code-auth-block.story.d.ts +0 -2
- package/dist-lib/components/stories/code-block.story.d.ts +0 -12
- package/dist-lib/components/stories/composed-password-input.story.d.ts +0 -6
- package/dist-lib/components/stories/context-cards.story.d.ts +0 -3
- package/dist-lib/components/stories/emoji-action-bar.story.d.ts +0 -3
- package/dist-lib/components/stories/field.story.d.ts +0 -6
- package/dist-lib/components/stories/file-icons.story.d.ts +0 -5
- package/dist-lib/components/stories/filter-table.story.d.ts +0 -21
- package/dist-lib/components/stories/flowchart.story.d.ts +0 -3
- package/dist-lib/components/stories/forgot-password-block.story.d.ts +0 -2
- package/dist-lib/components/stories/frame.story.d.ts +0 -8
- package/dist-lib/components/stories/index.d.ts +0 -54
- package/dist-lib/components/stories/input-group.story.d.ts +0 -6
- package/dist-lib/components/stories/input.story.d.ts +0 -8
- package/dist-lib/components/stories/insight-cards.story.d.ts +0 -74
- package/dist-lib/components/stories/label.story.d.ts +0 -8
- package/dist-lib/components/stories/linked-accounts-block.story.d.ts +0 -2
- package/dist-lib/components/stories/login-block.story.d.ts +0 -2
- package/dist-lib/components/stories/logo.story.d.ts +0 -3
- package/dist-lib/components/stories/markdown.story.d.ts +0 -7
- package/dist-lib/components/stories/menu-command.story.d.ts +0 -13
- package/dist-lib/components/stories/onboarding-block.story.d.ts +0 -2
- package/dist-lib/components/stories/otp-field.story.d.ts +0 -8
- package/dist-lib/components/stories/passkey-manager-block.story.d.ts +0 -2
- package/dist-lib/components/stories/passkey-sign-in-block.story.d.ts +0 -2
- package/dist-lib/components/stories/password-input.story.d.ts +0 -9
- package/dist-lib/components/stories/profile-card-block.story.d.ts +0 -6
- package/dist-lib/components/stories/recommendation-card.story.d.ts +0 -3
- package/dist-lib/components/stories/records-table.story.d.ts +0 -23
- package/dist-lib/components/stories/reference.story.d.ts +0 -9
- package/dist-lib/components/stories/research-answer.story.d.ts +0 -10
- package/dist-lib/components/stories/scaffold-root.story.d.ts +0 -6
- package/dist-lib/components/stories/separator.story.d.ts +0 -6
- package/dist-lib/components/stories/shell-layout.story.d.ts +0 -2
- package/dist-lib/components/stories/signup-block.story.d.ts +0 -2
- package/dist-lib/components/stories/social-providers.story.d.ts +0 -3
- package/dist-lib/components/stories/streaming-text.story.d.ts +0 -3
- package/dist-lib/components/stories/text.story.d.ts +0 -8
- package/dist-lib/components/stories/textarea.story.d.ts +0 -6
- package/dist-lib/components/stories/tree.story.d.ts +0 -4
- package/dist-lib/components/stories/update-password-block.story.d.ts +0 -2
- package/dist-lib/components/stories/user.story.d.ts +0 -8
- package/dist-lib/components/stories/verse.story.d.ts +0 -6
- package/dist-lib/components/ui/chat/__tests__/segmented-toggle.test.d.ts +0 -1
- package/dist-lib/index.js.map +0 -1
- package/dist-lib/lib/state/__tests__/sound.test.d.ts +0 -1
- package/dist-lib/lib/utils.test.d.ts +0 -1
- package/src/assets/css/base.css +0 -62
- package/src/assets/css/chat.css +0 -229
- package/src/assets/css/shadows.css +0 -157
- package/src/assets/css/theme.css +0 -321
- package/src/components/AGENTS.md +0 -0
- package/src/components/atoms/_layout.tsx +0 -9
- package/src/components/atoms/avatar/base.tsx +0 -70
- package/src/components/atoms/avatar/index.ts +0 -10
- package/src/components/atoms/avatar/types.ts +0 -24
- package/src/components/atoms/avatar/utils.ts +0 -54
- package/src/components/atoms/avatar/verified.tsx +0 -16
- package/src/components/atoms/background/index.ts +0 -8
- package/src/components/atoms/background/texture.tsx +0 -29
- package/src/components/atoms/background/type.ts +0 -10
- package/src/components/atoms/background/utils.ts +0 -13
- package/src/components/atoms/bubble/__tests__/bubble.test.tsx +0 -193
- package/src/components/atoms/bubble/__tests__/reference.test.tsx +0 -25
- package/src/components/atoms/bubble/actions.tsx +0 -28
- package/src/components/atoms/bubble/context.ts +0 -11
- package/src/components/atoms/bubble/default.tsx +0 -46
- package/src/components/atoms/bubble/header.tsx +0 -36
- package/src/components/atoms/bubble/index.ts +0 -37
- package/src/components/atoms/bubble/message.tsx +0 -32
- package/src/components/atoms/bubble/reactions.tsx +0 -191
- package/src/components/atoms/bubble/types.ts +0 -82
- package/src/components/atoms/bubble/utils.ts +0 -46
- package/src/components/atoms/chip.tsx +0 -61
- package/src/components/atoms/field.tsx +0 -43
- package/src/components/atoms/index.ts +0 -26
- package/src/components/atoms/loader.tsx +0 -33
- package/src/components/atoms/reference.tsx +0 -41
- package/src/components/atoms/text/__tests__/text.test.tsx +0 -47
- package/src/components/atoms/text/default.tsx +0 -59
- package/src/components/atoms/text/heading.tsx +0 -58
- package/src/components/atoms/text/index.ts +0 -28
- package/src/components/atoms/text/label.tsx +0 -16
- package/src/components/atoms/text/paragraph.tsx +0 -55
- package/src/components/atoms/text/span.tsx +0 -14
- package/src/components/atoms/text/types.ts +0 -41
- package/src/components/atoms/text/utils.ts +0 -16
- package/src/components/atoms/text-selection/__tests__/click-popover.test.tsx +0 -61
- package/src/components/atoms/text-selection/__tests__/text-selection.test.tsx +0 -90
- package/src/components/atoms/text-selection/click-popover.tsx +0 -62
- package/src/components/atoms/text-selection/index.ts +0 -30
- package/src/components/atoms/text-selection/popover.tsx +0 -103
- package/src/components/atoms/text-selection/selection-atom.ts +0 -51
- package/src/components/atoms/text-selection/selection.tsx +0 -56
- package/src/components/atoms/text-selection/types.ts +0 -125
- package/src/components/atoms/text-selection/use-selection.ts +0 -84
- package/src/components/atoms/types.ts +0 -46
- package/src/components/blocks/.gitkeep +0 -0
- package/src/components/blocks/auth/__tests__/auth-flow-block.test.tsx +0 -183
- package/src/components/blocks/auth/__tests__/auth-state-atom.test.tsx +0 -247
- package/src/components/blocks/auth/__tests__/linked-accounts-block.test.tsx +0 -128
- package/src/components/blocks/auth/__tests__/onboarding-block.test.tsx +0 -183
- package/src/components/blocks/auth/__tests__/passkey-manager-block.test.tsx +0 -131
- package/src/components/blocks/auth/__tests__/passkey-sign-in-block.test.tsx +0 -59
- package/src/components/blocks/auth/__tests__/signup-block.test.tsx +0 -176
- package/src/components/blocks/auth/__tests__/update-password-block.test.tsx +0 -95
- package/src/components/blocks/auth/auth-flow-atom.ts +0 -238
- package/src/components/blocks/auth/auth-flow-block.tsx +0 -211
- package/src/components/blocks/auth/auth-session-atom.ts +0 -82
- package/src/components/blocks/auth/auth-shell.tsx +0 -265
- package/src/components/blocks/auth/auth-state.ts +0 -40
- package/src/components/blocks/auth/code-auth-block.tsx +0 -176
- package/src/components/blocks/auth/forgot-password-block.tsx +0 -112
- package/src/components/blocks/auth/linked-accounts-block.tsx +0 -203
- package/src/components/blocks/auth/login-block.tsx +0 -217
- package/src/components/blocks/auth/onboarding/profile-step.tsx +0 -216
- package/src/components/blocks/auth/onboarding-block.tsx +0 -183
- package/src/components/blocks/auth/passkey-manager-block.tsx +0 -316
- package/src/components/blocks/auth/passkey-sign-in-block.tsx +0 -67
- package/src/components/blocks/auth/signup-block.tsx +0 -256
- package/src/components/blocks/auth/type.ts +0 -436
- package/src/components/blocks/auth/update-password-block.tsx +0 -139
- package/src/components/blocks/auth/use-auth-state.ts +0 -127
- package/src/components/blocks/chat/__tests__/ai-panel.test.tsx +0 -65
- package/src/components/blocks/chat/banners.tsx +0 -61
- package/src/components/blocks/chat/base.tsx +0 -84
- package/src/components/blocks/chat/header.tsx +0 -60
- package/src/components/blocks/chat/index.ts +0 -37
- package/src/components/blocks/chat/recommendation-stack.tsx +0 -41
- package/src/components/blocks/chat/shared.tsx +0 -27
- package/src/components/blocks/chat/suggested-prompts.tsx +0 -45
- package/src/components/blocks/chat/type.ts +0 -96
- package/src/components/blocks/chat/version-history-record.tsx +0 -37
- package/src/components/blocks/layout.ts +0 -35
- package/src/components/blocks/profile/__tests__/profile-card-block.test.tsx +0 -362
- package/src/components/blocks/profile/index.ts +0 -28
- package/src/components/blocks/profile/profile-card-atom.ts +0 -247
- package/src/components/blocks/profile/profile-card-block.tsx +0 -369
- package/src/components/blocks/profile/type.ts +0 -93
- package/src/components/blocks/profile/use-profile-card-state.ts +0 -67
- package/src/components/blocks/profile/use-profile-card.ts +0 -132
- package/src/components/blocks/scaffold/__tests__/scaffold-atom.test.tsx +0 -236
- package/src/components/blocks/scaffold/__tests__/scaffold.test.tsx +0 -524
- package/src/components/blocks/scaffold/constants.ts +0 -39
- package/src/components/blocks/scaffold/index.ts +0 -60
- package/src/components/blocks/scaffold/panel-close-button.tsx +0 -36
- package/src/components/blocks/scaffold/panel-menu-button.tsx +0 -221
- package/src/components/blocks/scaffold/scaffold-actions.tsx +0 -92
- package/src/components/blocks/scaffold/scaffold-atom.ts +0 -427
- package/src/components/blocks/scaffold/scaffold-canvas.tsx +0 -162
- package/src/components/blocks/scaffold/scaffold-context.ts +0 -20
- package/src/components/blocks/scaffold/scaffold-inspector.tsx +0 -137
- package/src/components/blocks/scaffold/scaffold-main.tsx +0 -28
- package/src/components/blocks/scaffold/scaffold-panel.tsx +0 -186
- package/src/components/blocks/scaffold/scaffold-root.tsx +0 -120
- package/src/components/blocks/scaffold/scaffold-sidebar.tsx +0 -31
- package/src/components/blocks/scaffold/scaffold-sub-panel.tsx +0 -122
- package/src/components/blocks/scaffold/scaffold-tab.tsx +0 -108
- package/src/components/blocks/scaffold/type.ts +0 -264
- package/src/components/blocks/scaffold/use-scaffold-state.ts +0 -85
- package/src/components/blocks/scaffold/use-scaffold.ts +0 -59
- package/src/components/blocks/scaffold/utils.ts +0 -112
- package/src/components/blocks/shell/__tests__/shell-fit-atom.test.tsx +0 -362
- package/src/components/blocks/shell/__tests__/shell-layout.test.tsx +0 -596
- package/src/components/blocks/shell/__tests__/shell-metrics.test.ts +0 -154
- package/src/components/blocks/shell/animated-panel-inset.tsx +0 -27
- package/src/components/blocks/shell/animated-panel-provider.tsx +0 -269
- package/src/components/blocks/shell/animated-panel-trigger.tsx +0 -51
- package/src/components/blocks/shell/animated-panel.tsx +0 -180
- package/src/components/blocks/shell/index.ts +0 -30
- package/src/components/blocks/shell/shell-fit-atom.ts +0 -246
- package/src/components/blocks/shell/shell-layout.tsx +0 -139
- package/src/components/blocks/shell/shell-metrics.ts +0 -133
- package/src/components/blocks/shell/shell-panel-atom.ts +0 -74
- package/src/components/blocks/shell/type.ts +0 -361
- package/src/components/blocks/shell/use-shell-fit-state.ts +0 -49
- package/src/components/blocks/shell/use-shell-fit.ts +0 -153
- package/src/components/blocks/shell/use-shell-panels.ts +0 -126
- package/src/components/blocks/shell/utils.ts +0 -187
- package/src/components/blocks/sidebar/__tests__/ai-sidebar-atom.test.tsx +0 -325
- package/src/components/blocks/sidebar/__tests__/ai-sidebar.test.tsx +0 -93
- package/src/components/blocks/sidebar/__tests__/use-ai-sidebar.test.tsx +0 -310
- package/src/components/blocks/sidebar/ai-sidebar-atom.ts +0 -698
- package/src/components/blocks/sidebar/ai-sidebar.tsx +0 -150
- package/src/components/blocks/sidebar/index.ts +0 -67
- package/src/components/blocks/sidebar/marquee-label.tsx +0 -59
- package/src/components/blocks/sidebar/sidebar-context.ts +0 -15
- package/src/components/blocks/sidebar/sidebar-icon.tsx +0 -14
- package/src/components/blocks/sidebar/sidebar-row.tsx +0 -378
- package/src/components/blocks/sidebar/type.ts +0 -294
- package/src/components/blocks/sidebar/use-ai-sidebar-state.ts +0 -123
- package/src/components/blocks/sidebar/use-ai-sidebar.ts +0 -619
- package/src/components/blocks/sidebar/utils.ts +0 -170
- package/src/components/blocks/types.ts +0 -6
- package/src/components/composed/.gitkeep +0 -0
- package/src/components/composed/__tests__/logo.test.tsx +0 -60
- package/src/components/composed/action-bar/__tests__/action-bar.test.tsx +0 -125
- package/src/components/composed/action-bar/action.tsx +0 -77
- package/src/components/composed/action-bar/emojis.tsx +0 -97
- package/src/components/composed/action-bar/index.ts +0 -24
- package/src/components/composed/action-bar/toolbar.tsx +0 -66
- package/src/components/composed/action-bar/types.ts +0 -58
- package/src/components/composed/action-bar/utils.ts +0 -140
- package/src/components/composed/ai/__tests__/ai.test.tsx +0 -66
- package/src/components/composed/ai/avatar.tsx +0 -19
- package/src/components/composed/ai/index.ts +0 -36
- package/src/components/composed/ai/message.tsx +0 -49
- package/src/components/composed/ai/research-answer.tsx +0 -157
- package/src/components/composed/ai/shared.tsx +0 -94
- package/src/components/composed/ai/streaming-text.tsx +0 -94
- package/src/components/composed/ai/suggested-prompt.tsx +0 -183
- package/src/components/composed/ai/types.ts +0 -81
- package/src/components/composed/chat/__tests__/attachment.test.tsx +0 -218
- package/src/components/composed/chat/__tests__/beautiful-ui.test.tsx +0 -57
- package/src/components/composed/chat/__tests__/chart.test.tsx +0 -316
- package/src/components/composed/chat/__tests__/code-block.test.tsx +0 -12
- package/src/components/composed/chat/__tests__/composer-attachments.test.tsx +0 -101
- package/src/components/composed/chat/__tests__/composer.test.tsx +0 -248
- package/src/components/composed/chat/__tests__/flowchart.test.tsx +0 -145
- package/src/components/composed/chat/__tests__/glass-material.test.tsx +0 -54
- package/src/components/composed/chat/__tests__/markdown.test.tsx +0 -25
- package/src/components/composed/chat/__tests__/menu-command.test.tsx +0 -35
- package/src/components/composed/chat/__tests__/recommendation.test.tsx +0 -43
- package/src/components/composed/chat/actions.tsx +0 -81
- package/src/components/composed/chat/attachment-file.ts +0 -82
- package/src/components/composed/chat/attachment.tsx +0 -498
- package/src/components/composed/chat/chart/chart-atom.ts +0 -55
- package/src/components/composed/chat/chart/chart-context.ts +0 -9
- package/src/components/composed/chat/chart/chart-legend.tsx +0 -75
- package/src/components/composed/chat/chart/chart-plot.tsx +0 -233
- package/src/components/composed/chat/chart/chart-root.tsx +0 -229
- package/src/components/composed/chat/chart/chart-tooltip.tsx +0 -74
- package/src/components/composed/chat/chart/constants.ts +0 -8
- package/src/components/composed/chat/chart/evilcharts/README.md +0 -8
- package/src/components/composed/chat/chart/evilcharts/echarts-area-chart.tsx +0 -2358
- package/src/components/composed/chat/chart/evilcharts/echarts-bar-chart.tsx +0 -2261
- package/src/components/composed/chat/chart/evilcharts/echarts-brush.tsx +0 -233
- package/src/components/composed/chat/chart/evilcharts/echarts-chart.tsx +0 -214
- package/src/components/composed/chat/chart/evilcharts/echarts-dot.tsx +0 -111
- package/src/components/composed/chat/chart/evilcharts/echarts-legend.tsx +0 -131
- package/src/components/composed/chat/chart/evilcharts/echarts-line-chart.tsx +0 -2112
- package/src/components/composed/chat/chart/evilcharts/echarts-pie-chart.tsx +0 -1235
- package/src/components/composed/chat/chart/evilcharts/echarts-tooltip.tsx +0 -125
- package/src/components/composed/chat/chart/index.ts +0 -13
- package/src/components/composed/chat/chart/type.ts +0 -88
- package/src/components/composed/chat/chart/use-chart-state.ts +0 -22
- package/src/components/composed/chat/chart/use-chart.ts +0 -70
- package/src/components/composed/chat/chart/utils.ts +0 -47
- package/src/components/composed/chat/chart.tsx +0 -3
- package/src/components/composed/chat/code-block.tsx +0 -123
- package/src/components/composed/chat/composer/add-button.tsx +0 -29
- package/src/components/composed/chat/composer/base.tsx +0 -573
- package/src/components/composed/chat/composer/command-menu.tsx +0 -47
- package/src/components/composed/chat/composer/hooks.ts +0 -29
- package/src/components/composed/chat/composer/index.ts +0 -19
- package/src/components/composed/chat/composer/send-button.tsx +0 -36
- package/src/components/composed/chat/composer/suggestions.tsx +0 -115
- package/src/components/composed/chat/composer/use-dictation.ts +0 -123
- package/src/components/composed/chat/composer/utils.ts +0 -74
- package/src/components/composed/chat/context-cards.tsx +0 -63
- package/src/components/composed/chat/filter-table.tsx +0 -119
- package/src/components/composed/chat/flowchart/chart-node.tsx +0 -162
- package/src/components/composed/chat/flowchart/connector.tsx +0 -32
- package/src/components/composed/chat/flowchart/constant.ts +0 -26
- package/src/components/composed/chat/flowchart/default.tsx +0 -230
- package/src/components/composed/chat/flowchart/edge-toolbar.tsx +0 -73
- package/src/components/composed/chat/flowchart/hooks.tsx +0 -347
- package/src/components/composed/chat/flowchart/index.ts +0 -14
- package/src/components/composed/chat/flowchart/step-body.tsx +0 -82
- package/src/components/composed/chat/flowchart/types.ts +0 -89
- package/src/components/composed/chat/flowchart/utils.ts +0 -78
- package/src/components/composed/chat/hint.tsx +0 -59
- package/src/components/composed/chat/index.ts +0 -92
- package/src/components/composed/chat/insight-cards.tsx +0 -199
- package/src/components/composed/chat/markdown-atom.ts +0 -15
- package/src/components/composed/chat/markdown.tsx +0 -213
- package/src/components/composed/chat/recommendation/checkbox.tsx +0 -122
- package/src/components/composed/chat/recommendation/constant.ts +0 -54
- package/src/components/composed/chat/recommendation/default.tsx +0 -25
- package/src/components/composed/chat/recommendation/group.tsx +0 -36
- package/src/components/composed/chat/recommendation/index.ts +0 -17
- package/src/components/composed/chat/recommendation/item.tsx +0 -215
- package/src/components/composed/chat/recommendation/types.ts +0 -76
- package/src/components/composed/chat/records-table.tsx +0 -130
- package/src/components/composed/chat/type.ts +0 -157
- package/src/components/composed/logo.tsx +0 -171
- package/src/components/composed/password-input.tsx +0 -179
- package/src/components/composed/reader/applied-mark.tsx +0 -32
- package/src/components/composed/reader/apply-toast.tsx +0 -49
- package/src/components/composed/reader/index.ts +0 -10
- package/src/components/composed/reader/selection-highlight.tsx +0 -26
- package/src/components/composed/reader/selection-popover.tsx +0 -149
- package/src/components/composed/reader/type.ts +0 -48
- package/src/components/composed/social-providers.tsx +0 -154
- package/src/components/composed/tree/CLAUDE.md +0 -145
- package/src/components/composed/tree/__tests__/tree-atom.test.tsx +0 -217
- package/src/components/composed/tree/__tests__/tree.test.tsx +0 -522
- package/src/components/composed/tree/__tests__/use-tree.test.tsx +0 -333
- package/src/components/composed/tree/constants.ts +0 -55
- package/src/components/composed/tree/index.ts +0 -51
- package/src/components/composed/tree/tree-atom.ts +0 -590
- package/src/components/composed/tree/tree-context.ts +0 -13
- package/src/components/composed/tree/tree-node.tsx +0 -496
- package/src/components/composed/tree/tree.tsx +0 -233
- package/src/components/composed/tree/type.ts +0 -322
- package/src/components/composed/tree/use-tree-dnd.ts +0 -179
- package/src/components/composed/tree/use-tree-state.ts +0 -105
- package/src/components/composed/tree/use-tree.ts +0 -311
- package/src/components/composed/tree/utils.ts +0 -172
- package/src/components/composed/types.ts +0 -9
- package/src/components/composed/user/__tests__/message.test.tsx +0 -79
- package/src/components/composed/user/index.ts +0 -14
- package/src/components/composed/user/info.tsx +0 -56
- package/src/components/composed/user/message.tsx +0 -36
- package/src/components/composed/user/pill.tsx +0 -20
- package/src/components/composed/user/types.ts +0 -47
- package/src/components/composed/user/utils.ts +0 -0
- package/src/components/composed/verse/__tests__/verse.test.tsx +0 -57
- package/src/components/composed/verse/index.ts +0 -2
- package/src/components/composed/verse/types.ts +0 -24
- package/src/components/composed/verse/verse.tsx +0 -100
- package/src/components/docs/atoms-gallery.tsx +0 -286
- package/src/components/docs/block-demo-stage.tsx +0 -38
- package/src/components/docs/blocks-gallery.tsx +0 -224
- package/src/components/docs/browser.tsx +0 -87
- package/src/components/docs/code-block.tsx +0 -10
- package/src/components/docs/components-gallery.tsx +0 -182
- package/src/components/docs/demo-controls.tsx +0 -142
- package/src/components/docs/hero.tsx +0 -197
- package/src/components/docs/mermaid.tsx +0 -55
- package/src/components/icons/README.md +0 -91
- package/src/components/icons/__tests__/icons.test.tsx +0 -58
- package/src/components/icons/file-badge-cfm.tsx +0 -615
- package/src/components/icons/file-badge-corpus.tsx +0 -604
- package/src/components/icons/file-badge-pdf.tsx +0 -570
- package/src/components/icons/file-badge-tei.tsx +0 -524
- package/src/components/icons/file-badge-tf.tsx +0 -620
- package/src/components/icons/file-badge-txt.tsx +0 -607
- package/src/components/icons/file-badge-xml.tsx +0 -576
- package/src/components/icons/file-wordmark-cfm.tsx +0 -424
- package/src/components/icons/file-wordmark-corpus.tsx +0 -454
- package/src/components/icons/file-wordmark-pdf.tsx +0 -470
- package/src/components/icons/file-wordmark-tei.tsx +0 -424
- package/src/components/icons/file-wordmark-tf.tsx +0 -406
- package/src/components/icons/file-wordmark-txt.tsx +0 -421
- package/src/components/icons/file-wordmark-xml.tsx +0 -424
- package/src/components/icons/index.ts +0 -16
- package/src/components/icons/types.ts +0 -8
- package/src/components/motion/index.ts +0 -0
- package/src/components/motion/overflow-actions.tsx +0 -376
- package/src/components/motion/popover-morph.tsx +0 -292
- package/src/components/motion/popover-position.ts +0 -86
- package/src/components/motion/shared-layout-bg.tsx +0 -151
- package/src/components/stories/attachment.story.tsx +0 -40
- package/src/components/stories/auth-flow-block.story.tsx +0 -17
- package/src/components/stories/avatar.story.tsx +0 -33
- package/src/components/stories/base.story.tsx +0 -70
- package/src/components/stories/bubble.story.tsx +0 -61
- package/src/components/stories/button.story.tsx +0 -32
- package/src/components/stories/card.story.tsx +0 -36
- package/src/components/stories/chart.story.tsx +0 -69
- package/src/components/stories/checkbox.story.tsx +0 -30
- package/src/components/stories/code-auth-block.story.tsx +0 -20
- package/src/components/stories/code-block.story.tsx +0 -35
- package/src/components/stories/composed-password-input.story.tsx +0 -41
- package/src/components/stories/context-cards.story.tsx +0 -30
- package/src/components/stories/emoji-action-bar.story.tsx +0 -20
- package/src/components/stories/field.story.tsx +0 -32
- package/src/components/stories/file-icons.story.tsx +0 -20
- package/src/components/stories/filter-table.story.tsx +0 -63
- package/src/components/stories/flowchart.story.tsx +0 -25
- package/src/components/stories/forgot-password-block.story.tsx +0 -14
- package/src/components/stories/frame.story.tsx +0 -32
- package/src/components/stories/index.ts +0 -57
- package/src/components/stories/input-group.story.tsx +0 -27
- package/src/components/stories/input.story.tsx +0 -42
- package/src/components/stories/insight-cards.story.tsx +0 -67
- package/src/components/stories/label.story.tsx +0 -32
- package/src/components/stories/linked-accounts-block.story.tsx +0 -23
- package/src/components/stories/login-block.story.tsx +0 -18
- package/src/components/stories/logo.story.tsx +0 -21
- package/src/components/stories/markdown.story.tsx +0 -31
- package/src/components/stories/menu-command.story.tsx +0 -43
- package/src/components/stories/onboarding-block.story.tsx +0 -14
- package/src/components/stories/otp-field.story.tsx +0 -35
- package/src/components/stories/passkey-manager-block.story.tsx +0 -18
- package/src/components/stories/passkey-sign-in-block.story.tsx +0 -15
- package/src/components/stories/password-input.story.tsx +0 -35
- package/src/components/stories/profile-card-block.story.tsx +0 -29
- package/src/components/stories/recommendation-card.story.tsx +0 -37
- package/src/components/stories/records-table.story.tsx +0 -52
- package/src/components/stories/reference.story.tsx +0 -33
- package/src/components/stories/research-answer.story.tsx +0 -32
- package/src/components/stories/scaffold-root.story.tsx +0 -47
- package/src/components/stories/separator.story.tsx +0 -37
- package/src/components/stories/shell-layout.story.tsx +0 -19
- package/src/components/stories/signup-block.story.tsx +0 -18
- package/src/components/stories/social-providers.story.tsx +0 -26
- package/src/components/stories/streaming-text.story.tsx +0 -25
- package/src/components/stories/text.story.tsx +0 -31
- package/src/components/stories/textarea.story.tsx +0 -34
- package/src/components/stories/tree.story.tsx +0 -31
- package/src/components/stories/update-password-block.story.tsx +0 -14
- package/src/components/stories/user.story.tsx +0 -32
- package/src/components/stories/verse.story.tsx +0 -42
- package/src/components/theme-provider.tsx +0 -230
- package/src/components/types.ts +0 -106
- package/src/components/ui/accordion.tsx +0 -68
- package/src/components/ui/alert-dialog.tsx +0 -167
- package/src/components/ui/alert.tsx +0 -84
- package/src/components/ui/autocomplete.tsx +0 -303
- package/src/components/ui/avatar.tsx +0 -109
- package/src/components/ui/badge.tsx +0 -101
- package/src/components/ui/button-group.tsx +0 -88
- package/src/components/ui/button.tsx +0 -192
- package/src/components/ui/card.tsx +0 -253
- package/src/components/ui/chat/__tests__/segmented-toggle.test.tsx +0 -27
- package/src/components/ui/chat/avatar-handle.tsx +0 -30
- package/src/components/ui/chat/badges.tsx +0 -85
- package/src/components/ui/chat/buttons.tsx +0 -94
- package/src/components/ui/chat/chips.tsx +0 -106
- package/src/components/ui/chat/dot.tsx +0 -81
- package/src/components/ui/chat/icon-button.tsx +0 -43
- package/src/components/ui/chat/icon-tile.tsx +0 -33
- package/src/components/ui/chat/index.ts +0 -12
- package/src/components/ui/chat/inline-source.tsx +0 -94
- package/src/components/ui/chat/segmented-toggle.tsx +0 -99
- package/src/components/ui/chat/tag.tsx +0 -61
- package/src/components/ui/chat/thumbnail.tsx +0 -31
- package/src/components/ui/chat/waveform.tsx +0 -30
- package/src/components/ui/checkbox.tsx +0 -83
- package/src/components/ui/collapsible.tsx +0 -42
- package/src/components/ui/command.tsx +0 -263
- package/src/components/ui/context-menu.tsx +0 -342
- package/src/components/ui/emoji-picker.tsx +0 -161
- package/src/components/ui/field.tsx +0 -89
- package/src/components/ui/frame.tsx +0 -87
- package/src/components/ui/glasscn/glass-button-group.tsx +0 -34
- package/src/components/ui/glasscn/glass-button.tsx +0 -25
- package/src/components/ui/glasscn/glass-container.tsx +0 -94
- package/src/components/ui/glasscn/glass-separator.tsx +0 -39
- package/src/components/ui/glasscn/liquid-glass.tsx +0 -59
- package/src/components/ui/group.tsx +0 -92
- package/src/components/ui/input-group.tsx +0 -105
- package/src/components/ui/input.tsx +0 -70
- package/src/components/ui/kbd.tsx +0 -32
- package/src/components/ui/label.tsx +0 -36
- package/src/components/ui/menu-command.tsx +0 -156
- package/src/components/ui/menu.tsx +0 -352
- package/src/components/ui/otp-field.tsx +0 -88
- package/src/components/ui/popover-glass.tsx +0 -158
- package/src/components/ui/popover.tsx +0 -120
- package/src/components/ui/preview-card.tsx +0 -61
- package/src/components/ui/scroll-area.tsx +0 -80
- package/src/components/ui/select.tsx +0 -257
- package/src/components/ui/separator.tsx +0 -23
- package/src/components/ui/sheet.tsx +0 -135
- package/src/components/ui/skeleton.tsx +0 -18
- package/src/components/ui/spinner.tsx +0 -17
- package/src/components/ui/switch.tsx +0 -30
- package/src/components/ui/tabs.tsx +0 -120
- package/src/components/ui/textarea.tsx +0 -58
- package/src/components/ui/toast.tsx +0 -325
- package/src/components/ui/toolbar.tsx +0 -92
- package/src/components/ui/tooltip.tsx +0 -67
- package/src/index.css +0 -10
- package/src/index.ts +0 -102
- package/src/lib/attachment-content.ts +0 -28
- package/src/lib/auth-accent.ts +0 -49
- package/src/lib/ease.ts +0 -90
- package/src/lib/glass-variants.ts +0 -22
- package/src/lib/hooks/use-hover-capable.ts +0 -23
- package/src/lib/hooks/use-mobile.ts +0 -21
- package/src/lib/keyed-atom.ts +0 -60
- package/src/lib/segmented-control.ts +0 -42
- package/src/lib/sound.ts +0 -39
- package/src/lib/specular.ts +0 -10
- package/src/lib/state/__tests__/sound.test.tsx +0 -53
- package/src/lib/state/exegia-provider.tsx +0 -83
- package/src/lib/state/index.ts +0 -4
- package/src/lib/state/store.ts +0 -19
- package/src/lib/use-motion-panel.ts +0 -78
- package/src/lib/utils.test.ts +0 -22
- package/src/lib/utils.ts +0 -100
- package/src/specular.js +0 -4
- /package/{src/components/composed/chat/composer → dist-lib}/BEAUTIFUL-UI-LICENSE.txt +0 -0
- /package/{src/components/composed/chat/chart/evilcharts/LICENSE → dist-lib/EVILCHARTS-LICENSE.txt} +0 -0
|
@@ -1,1235 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
resolveTooltipPosition,
|
|
5
|
-
roundnessClass,
|
|
6
|
-
tooltipIndicatorHtml,
|
|
7
|
-
tooltipRow,
|
|
8
|
-
tooltipVariantClass,
|
|
9
|
-
type TooltipPosition,
|
|
10
|
-
type TooltipRoundness,
|
|
11
|
-
type TooltipVariant,
|
|
12
|
-
} from "./echarts-tooltip";
|
|
13
|
-
import {
|
|
14
|
-
DEFAULT_ECHARTS_RENDERER,
|
|
15
|
-
buildChartCss,
|
|
16
|
-
getColorsCount,
|
|
17
|
-
resolveColors,
|
|
18
|
-
withAlpha,
|
|
19
|
-
type ChartConfig,
|
|
20
|
-
type EChartsRenderer,
|
|
21
|
-
type ResolvedColors,
|
|
22
|
-
} from "./echarts-chart";
|
|
23
|
-
import {
|
|
24
|
-
Children,
|
|
25
|
-
isValidElement,
|
|
26
|
-
useCallback,
|
|
27
|
-
useEffect,
|
|
28
|
-
useId,
|
|
29
|
-
useMemo,
|
|
30
|
-
useRef,
|
|
31
|
-
useState,
|
|
32
|
-
type CSSProperties,
|
|
33
|
-
type FC,
|
|
34
|
-
type ReactNode,
|
|
35
|
-
} from "react";
|
|
36
|
-
import { TooltipComponent, type TooltipComponentOption } from "echarts/components";
|
|
37
|
-
import { LegendOverlay, type LegendVariant } from "./echarts-legend";
|
|
38
|
-
import { PieChart, type PieSeriesOption } from "echarts/charts";
|
|
39
|
-
import { motion, useReducedMotion } from "motion/react";
|
|
40
|
-
import type { ComposeOption } from "echarts/core";
|
|
41
|
-
import * as echarts from "echarts/core";
|
|
42
|
-
|
|
43
|
-
// Re-export the shared types that were previously declared inline here, so
|
|
44
|
-
// existing consumers/examples keep importing them from the chart module.
|
|
45
|
-
export type {
|
|
46
|
-
ChartConfig,
|
|
47
|
-
EChartsRenderer,
|
|
48
|
-
LegendVariant,
|
|
49
|
-
TooltipPosition,
|
|
50
|
-
TooltipRoundness,
|
|
51
|
-
TooltipVariant,
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
// Modular registration keeps the bundle lean — only the pieces this chart needs.
|
|
55
|
-
// A pie has no coordinate system, so there is no GridComponent and no axes; the
|
|
56
|
-
// tooltip is item-triggered. Never register GraphicComponent: the loading shimmer
|
|
57
|
-
// and selection dim are per-sector itemStyle updates, not graphic overlays.
|
|
58
|
-
echarts.use([PieChart, TooltipComponent]);
|
|
59
|
-
|
|
60
|
-
type EChartsInstance = ReturnType<typeof echarts.init>;
|
|
61
|
-
|
|
62
|
-
// The exact option surface this chart uses — a pie series plus the tooltip
|
|
63
|
-
// component. Narrower than echarts' full EChartsOption, so a misspelled key fails
|
|
64
|
-
// the compile instead of silently reaching setOption.
|
|
65
|
-
type EChartsOption = ComposeOption<PieSeriesOption | TooltipComponentOption>;
|
|
66
|
-
|
|
67
|
-
// Sector paint — structurally assignable to a pie datum's itemStyle. `color`
|
|
68
|
-
// accepts the same solid-or-gradient value sectorPaint returns, and the optional
|
|
69
|
-
// border fields carry the constant-width gap / overlap separator.
|
|
70
|
-
type PieItemStyle = {
|
|
71
|
-
color: string | echarts.graphic.LinearGradient;
|
|
72
|
-
opacity: number;
|
|
73
|
-
borderRadius: number;
|
|
74
|
-
borderColor?: string;
|
|
75
|
-
borderWidth?: number;
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
79
|
-
// Constants
|
|
80
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
81
|
-
|
|
82
|
-
const REVEAL_DURATION = 1000; // intro draw-in length, in milliseconds (ECharts' default)
|
|
83
|
-
// NOTE: the intro is ECharts' RAW default pie entrance (`animationType: "expansion"`
|
|
84
|
-
// — sectors sweep out from the start angle). We only gate whether it plays; we do
|
|
85
|
-
// not customize its easing, matching the area chart's "raw default" policy.
|
|
86
|
-
const LOADING_ANIMATION_DURATION = 2000; // shimmer loop, in milliseconds
|
|
87
|
-
const LOADING_SECTORS = 5; // skeleton sector count — Recharts twin uses 5 equal sectors
|
|
88
|
-
|
|
89
|
-
const DEFAULT_INNER_RADIUS: number | string = 0;
|
|
90
|
-
const DEFAULT_OUTER_RADIUS: number | string = "80%";
|
|
91
|
-
const DEFAULT_CORNER_RADIUS = 0;
|
|
92
|
-
const DEFAULT_PADDING_ANGLE = 0;
|
|
93
|
-
const DEFAULT_START_ANGLE = 0;
|
|
94
|
-
const DEFAULT_END_ANGLE = 360;
|
|
95
|
-
|
|
96
|
-
const FALLBACK_COLOR = "rgba(120, 120, 120, 1)";
|
|
97
|
-
|
|
98
|
-
// Overlapping sectors (negative paddingAngle) get a background-colored border to
|
|
99
|
-
// separate the petals — the canvas analogue of the Recharts twin's
|
|
100
|
-
// `stroke="var(--background)" strokeWidth={5}`.
|
|
101
|
-
const OVERLAP_BORDER_WIDTH = 5;
|
|
102
|
-
|
|
103
|
-
// Selecting a sector pops it radially OUTWARD from the center — the offset-slice
|
|
104
|
-
// look from the official ECharts pie-pattern example. This is the pixel distance
|
|
105
|
-
// the chosen sector translates along its own bisector; deselecting returns it.
|
|
106
|
-
const SELECTED_OFFSET = 12;
|
|
107
|
-
|
|
108
|
-
// The selected sector stays fully opaque; the others recede to this dimmed
|
|
109
|
-
// opacity. Tuned to ~half the former 0.3 so the selected sector reads with more
|
|
110
|
-
// contrast against the dimmed ones — the analogue of the area chart's dim-fill
|
|
111
|
-
// halving (its dimmed fill went 0.2 → 0.1 while the selected state stays full).
|
|
112
|
-
const DIMMED_OPACITY = 0.15;
|
|
113
|
-
|
|
114
|
-
// Positive gaps between sectors are drawn as a CONSTANT-WIDTH background-colored
|
|
115
|
-
// border (px), NOT an angular padAngle. An angular pad tapers to a wedge toward
|
|
116
|
-
// the center; a border keeps every gap parallel-edged all the way from the rim to
|
|
117
|
-
// the center. The px width tracks the requested `paddingAngle` for familiar sizing.
|
|
118
|
-
function gapBorderWidth(paddingAngle: number): number {
|
|
119
|
-
return Math.max(paddingAngle, 0);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Resolves each sector's separator border. Negative paddingAngle keeps the
|
|
123
|
-
// overlapping-petal look (a real angular overlap plus a wide separator); positive
|
|
124
|
-
// paddingAngle becomes a constant-width gap; zero draws no border at all.
|
|
125
|
-
function sectorBorder(
|
|
126
|
-
paddingAngle: number,
|
|
127
|
-
background: string,
|
|
128
|
-
): { borderColor: string; borderWidth: number } | null {
|
|
129
|
-
if (paddingAngle < 0) return { borderColor: background, borderWidth: OVERLAP_BORDER_WIDTH };
|
|
130
|
-
const width = gapBorderWidth(paddingAngle);
|
|
131
|
-
if (width > 0) return { borderColor: background, borderWidth: width };
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Loading shimmer opacities (× the foreground token's own alpha). A sine-feathered
|
|
136
|
-
// window sweeps around the ring, brightening each sector from base → peak as it
|
|
137
|
-
// passes — the angular twin of the area chart's swept clip window, and a match for
|
|
138
|
-
// the Recharts twin's staggered sector pulse.
|
|
139
|
-
const LOADING_BASE_OPACITY = 0.15; // resting sector fill, × foreground alpha
|
|
140
|
-
const LOADING_PEAK_OPACITY = 0.5; // fill inside the sweep window, × foreground alpha
|
|
141
|
-
const LOADING_SHIMMER_BAND = 0.28; // window half-width, fraction of the ring (0..1)
|
|
142
|
-
const LOADING_SHIMMER_FEATHER = 0.22; // sine-eased edge softening of the window
|
|
143
|
-
|
|
144
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
145
|
-
// Public types
|
|
146
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
147
|
-
|
|
148
|
-
// The pie has a single fill style — a per-sector color gradient. Kept as a named
|
|
149
|
-
// union for API parity with the Recharts twin (and room to grow).
|
|
150
|
-
export type PieVariant = "gradient";
|
|
151
|
-
// Where sector labels sit: "inside" draws value text on the sector (the default),
|
|
152
|
-
// "outside" moves the sector's name past the rim with a leader line, matching the
|
|
153
|
-
// classic ECharts pie (echarts.apache.org/examples/en/editor.html?c=pie-simple).
|
|
154
|
-
export type LabelPosition = "inside" | "outside";
|
|
155
|
-
// TooltipVariant, TooltipRoundness, TooltipPosition, LegendVariant, and ChartConfig
|
|
156
|
-
// now live in the shared ./echarts/* modules and are imported +
|
|
157
|
-
// re-exported at the top of this file.
|
|
158
|
-
export type BackgroundVariant =
|
|
159
|
-
| "dots"
|
|
160
|
-
| "grid"
|
|
161
|
-
| "cross-hatch"
|
|
162
|
-
| "diagonal-lines"
|
|
163
|
-
| "plus"
|
|
164
|
-
| "falling-triangles"
|
|
165
|
-
| "4-pointed-star"
|
|
166
|
-
| "tiny-checkers"
|
|
167
|
-
| "overlapping-circles"
|
|
168
|
-
| "wiggle-lines"
|
|
169
|
-
| "bubbles";
|
|
170
|
-
|
|
171
|
-
export interface EChartsPieChartProps<TData extends Record<string, unknown>> {
|
|
172
|
-
data: TData[]; // rows rendered by the chart — one sector each
|
|
173
|
-
config: ChartConfig; // sector colors + labels, keyed by the sector name
|
|
174
|
-
dataKey: keyof TData & string; // key holding each sector's numeric value
|
|
175
|
-
nameKey: keyof TData & string; // key holding each sector's name
|
|
176
|
-
className?: string; // extra classes for the chart container
|
|
177
|
-
renderer?: EChartsRenderer; // rendering engine — canvas by default, or SVG
|
|
178
|
-
// Master switch for the intro draw-in. Not present on the Recharts twin (which
|
|
179
|
-
// hardcodes its animation); added here as the ECharts off-switch, mirroring the
|
|
180
|
-
// ECharts area chart's `animation` prop. OS reduce-motion also disables it.
|
|
181
|
-
animation?: boolean;
|
|
182
|
-
defaultSelectedSector?: string | null; // sector selected on first render
|
|
183
|
-
selectedSector?: string | null; // controlled selection — overrides internal state when set
|
|
184
|
-
onSelectionChange?: (selection: { dataKey: string; value: number } | null) => void; // fires when the selected sector changes
|
|
185
|
-
isLoading?: boolean; // shows the animated loading skeleton
|
|
186
|
-
chartOptions?: Record<string, unknown>; // escape hatch merged over the built ECharts option
|
|
187
|
-
children?: ReactNode; // declarative config — <Pie>, <Tooltip>, <Legend>, <Background>
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
191
|
-
// Composible parts — DECLARATIVE CONFIG. Every part renders `null`; the root
|
|
192
|
-
// walks `children` by reference (child.type === Pie, …) to collect its props.
|
|
193
|
-
// Presence semantics mirror the Recharts twin: omit a child and that part does
|
|
194
|
-
// not render. These are never mounted into the tree — they only carry props.
|
|
195
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
196
|
-
|
|
197
|
-
export interface PieProps {
|
|
198
|
-
variant?: PieVariant; // fill style for the pie's sectors
|
|
199
|
-
innerRadius?: number | string; // inner radius — set above 0 for a donut
|
|
200
|
-
outerRadius?: number | string; // outer radius of the pie
|
|
201
|
-
cornerRadius?: number; // border-radius of each sector in pixels
|
|
202
|
-
paddingAngle?: number; // gap between sectors in degrees — negative overlaps them
|
|
203
|
-
startAngle?: number; // angle the pie starts drawing from
|
|
204
|
-
endAngle?: number; // angle the pie stops drawing at
|
|
205
|
-
isClickable?: boolean; // lets sectors be selected by clicking them — the selected sector pops outward
|
|
206
|
-
children?: ReactNode; // optional <Label> composition for sector labels
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* The pie series. Declares its own shape (radii, angles, corner rounding,
|
|
211
|
-
* padding) and clickability. Renders nothing — the root reads these props to
|
|
212
|
-
* build the ECharts pie. When clickable, the selected sector pops radially
|
|
213
|
-
* outward. Compose a <Label> inside it to draw labels on each sector.
|
|
214
|
-
*/
|
|
215
|
-
const Pie: FC<PieProps> = () => null;
|
|
216
|
-
|
|
217
|
-
export interface LabelProps {
|
|
218
|
-
dataKey?: string; // data key for the label text — defaults to the pie's value key
|
|
219
|
-
position?: LabelPosition; // "inside" (value on the sector) or "outside" (name past the rim, with a leader line)
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/** Declares per-sector labels for the enclosing <Pie>. Renders nothing. */
|
|
223
|
-
const Label: FC<LabelProps> = () => null;
|
|
224
|
-
|
|
225
|
-
export interface TooltipProps {
|
|
226
|
-
variant?: TooltipVariant; // visual style of the tooltip surface
|
|
227
|
-
roundness?: TooltipRoundness; // border-radius of the tooltip
|
|
228
|
-
defaultIndex?: number; // sector index shown by default with no hover
|
|
229
|
-
position?: TooltipPosition; // "variable" follows the pointer (default); "fixed" pins the tooltip near the top and tracks the pointer's X
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/** Presence enables the hover tooltip. Renders nothing. */
|
|
233
|
-
const Tooltip: FC<TooltipProps> = () => null;
|
|
234
|
-
|
|
235
|
-
export interface LegendProps {
|
|
236
|
-
variant?: LegendVariant; // visual style of the legend indicators
|
|
237
|
-
align?: "left" | "center" | "right"; // horizontal placement
|
|
238
|
-
verticalAlign?: "top" | "middle" | "bottom"; // vertical placement
|
|
239
|
-
isClickable?: boolean; // lets each entry toggle selection of its sector
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/** Presence enables the HTML legend overlay. Renders nothing. */
|
|
243
|
-
const Legend: FC<LegendProps> = () => null;
|
|
244
|
-
|
|
245
|
-
export interface BackgroundProps {
|
|
246
|
-
variant?: BackgroundVariant; // background pattern style
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/** Presence draws a decorative SVG pattern behind the pie. Renders nothing. */
|
|
250
|
-
const Background: FC<BackgroundProps> = () => null;
|
|
251
|
-
|
|
252
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
253
|
-
// Children collection — walk the declarative config into plain objects the
|
|
254
|
-
// option builder consumes. <Label> is read from the <Pie>'s own children; a
|
|
255
|
-
// missing <Label> means sector labels do not render.
|
|
256
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
257
|
-
|
|
258
|
-
type PieSlot = {
|
|
259
|
-
variant: PieVariant;
|
|
260
|
-
innerRadius: number | string;
|
|
261
|
-
outerRadius: number | string;
|
|
262
|
-
cornerRadius: number;
|
|
263
|
-
paddingAngle: number;
|
|
264
|
-
startAngle: number;
|
|
265
|
-
endAngle: number;
|
|
266
|
-
isClickable: boolean;
|
|
267
|
-
labelDataKey: string | null; // null when no <Label> child is present
|
|
268
|
-
labelPosition: LabelPosition; // where the <Label> sits — only meaningful when labelDataKey !== null
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
type TooltipSlot = {
|
|
272
|
-
present: boolean;
|
|
273
|
-
variant: TooltipVariant;
|
|
274
|
-
roundness: TooltipRoundness;
|
|
275
|
-
defaultIndex?: number;
|
|
276
|
-
position: TooltipPosition;
|
|
277
|
-
};
|
|
278
|
-
type LegendSlot = {
|
|
279
|
-
present: boolean;
|
|
280
|
-
variant: LegendVariant;
|
|
281
|
-
align: "left" | "center" | "right";
|
|
282
|
-
verticalAlign: "top" | "middle" | "bottom";
|
|
283
|
-
isClickable: boolean;
|
|
284
|
-
};
|
|
285
|
-
type BackgroundSlot = { present: boolean; variant: BackgroundVariant };
|
|
286
|
-
|
|
287
|
-
type CollectedConfig = {
|
|
288
|
-
pie: PieSlot | null;
|
|
289
|
-
tooltip: TooltipSlot;
|
|
290
|
-
legend: LegendSlot;
|
|
291
|
-
background: BackgroundSlot;
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
function collectConfig(children: ReactNode): CollectedConfig {
|
|
295
|
-
let pie: PieSlot | null = null;
|
|
296
|
-
let tooltip: TooltipSlot = {
|
|
297
|
-
present: false,
|
|
298
|
-
variant: "default",
|
|
299
|
-
roundness: "lg",
|
|
300
|
-
position: "variable",
|
|
301
|
-
};
|
|
302
|
-
// Pie legend defaults differ from the area chart's: centered along the bottom.
|
|
303
|
-
let legend: LegendSlot = {
|
|
304
|
-
present: false,
|
|
305
|
-
variant: "rounded-square",
|
|
306
|
-
align: "center",
|
|
307
|
-
verticalAlign: "bottom",
|
|
308
|
-
isClickable: false,
|
|
309
|
-
};
|
|
310
|
-
let background: BackgroundSlot = { present: false, variant: "dots" };
|
|
311
|
-
|
|
312
|
-
Children.forEach(children, (child) => {
|
|
313
|
-
if (!isValidElement(child)) return;
|
|
314
|
-
const type = child.type;
|
|
315
|
-
|
|
316
|
-
if (type === Pie) {
|
|
317
|
-
const props = child.props as PieProps;
|
|
318
|
-
// A <Label> child (if any) declares per-sector labels.
|
|
319
|
-
let labelDataKey: string | null = null;
|
|
320
|
-
let labelPosition: LabelPosition = "inside";
|
|
321
|
-
Children.forEach(props.children, (labelChild) => {
|
|
322
|
-
if (!isValidElement(labelChild) || labelChild.type !== Label) return;
|
|
323
|
-
const labelProps = labelChild.props as LabelProps;
|
|
324
|
-
labelDataKey = labelProps.dataKey ?? "";
|
|
325
|
-
labelPosition = labelProps.position ?? "inside";
|
|
326
|
-
});
|
|
327
|
-
pie = {
|
|
328
|
-
variant: props.variant ?? "gradient",
|
|
329
|
-
innerRadius: props.innerRadius ?? DEFAULT_INNER_RADIUS,
|
|
330
|
-
outerRadius: props.outerRadius ?? DEFAULT_OUTER_RADIUS,
|
|
331
|
-
cornerRadius: props.cornerRadius ?? DEFAULT_CORNER_RADIUS,
|
|
332
|
-
paddingAngle: props.paddingAngle ?? DEFAULT_PADDING_ANGLE,
|
|
333
|
-
startAngle: props.startAngle ?? DEFAULT_START_ANGLE,
|
|
334
|
-
endAngle: props.endAngle ?? DEFAULT_END_ANGLE,
|
|
335
|
-
isClickable: props.isClickable ?? false,
|
|
336
|
-
labelDataKey,
|
|
337
|
-
labelPosition,
|
|
338
|
-
};
|
|
339
|
-
} else if (type === Tooltip) {
|
|
340
|
-
const props = child.props as TooltipProps;
|
|
341
|
-
tooltip = {
|
|
342
|
-
present: true,
|
|
343
|
-
variant: props.variant ?? "default",
|
|
344
|
-
roundness: props.roundness ?? "lg",
|
|
345
|
-
defaultIndex: props.defaultIndex,
|
|
346
|
-
position: props.position ?? "variable",
|
|
347
|
-
};
|
|
348
|
-
} else if (type === Legend) {
|
|
349
|
-
const props = child.props as LegendProps;
|
|
350
|
-
legend = {
|
|
351
|
-
present: true,
|
|
352
|
-
variant: props.variant ?? "rounded-square",
|
|
353
|
-
align: props.align ?? "center",
|
|
354
|
-
verticalAlign: props.verticalAlign ?? "bottom",
|
|
355
|
-
isClickable: props.isClickable ?? false,
|
|
356
|
-
};
|
|
357
|
-
} else if (type === Background) {
|
|
358
|
-
const props = child.props as BackgroundProps;
|
|
359
|
-
background = { present: true, variant: props.variant ?? "dots" };
|
|
360
|
-
}
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
return { pie, tooltip, legend, background };
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// Color plumbing (ChartConfig, getColorsCount, buildChartCss, withAlpha,
|
|
367
|
-
// ResolvedColors, resolveColors) now lives in ./echarts-chart and is
|
|
368
|
-
// imported at the top of this file. The pie keeps its own DIAGONAL sectorPaint
|
|
369
|
-
// below (the shared seriesPaint is a horizontal gradient).
|
|
370
|
-
|
|
371
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
372
|
-
// Sector fill
|
|
373
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
374
|
-
|
|
375
|
-
// Per-sector fill: a solid color for a single-color config, else a diagonal
|
|
376
|
-
// top-left → bottom-right gradient across the sector's own bounding box. This
|
|
377
|
-
// mirrors the Recharts twin's `RadialColorGradient` (a `linearGradient` with
|
|
378
|
-
// x1/y1 = 0 and x2/y2 = 1). ECharts gradients are bbox-relative by default —
|
|
379
|
-
// exactly what a per-sector gradient wants — so no `global` override is needed.
|
|
380
|
-
function sectorPaint(slots: string[]): string | echarts.graphic.LinearGradient {
|
|
381
|
-
if (slots.length <= 1) return slots[0] ?? FALLBACK_COLOR;
|
|
382
|
-
const stops = slots.map((color, i) => ({ offset: i / (slots.length - 1), color }));
|
|
383
|
-
return new echarts.graphic.LinearGradient(0, 0, 1, 1, stops);
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
387
|
-
// Loading skeleton helpers
|
|
388
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
389
|
-
|
|
390
|
-
// Per-sector shimmer alpha: a sine-feathered window centered on `center` (both
|
|
391
|
-
// values are ring fractions in [0, 1)). Sectors inside the window read at
|
|
392
|
-
// `LOADING_PEAK_OPACITY`, outside at `LOADING_BASE_OPACITY`, with a sine falloff
|
|
393
|
-
// across the feather so the sweep edge isn't a hard cut. Distance wraps around
|
|
394
|
-
// the ring — the highlight travels continuously, like the Recharts twin's pulse.
|
|
395
|
-
function loadingSectorAlpha(pos: number, center: number): number {
|
|
396
|
-
const raw = Math.abs(pos - center);
|
|
397
|
-
const dist = Math.min(raw, 1 - raw); // shortest way around the ring
|
|
398
|
-
const half = LOADING_SHIMMER_BAND;
|
|
399
|
-
const feather = LOADING_SHIMMER_FEATHER;
|
|
400
|
-
|
|
401
|
-
if (dist >= half) return LOADING_BASE_OPACITY;
|
|
402
|
-
if (dist <= half - feather) return LOADING_PEAK_OPACITY;
|
|
403
|
-
// Sine-eased ramp — a linear one still reads as a hard cut.
|
|
404
|
-
const t = 1 - (dist - (half - feather)) / feather;
|
|
405
|
-
const eased = Math.sin((t * Math.PI) / 2);
|
|
406
|
-
return LOADING_BASE_OPACITY + (LOADING_PEAK_OPACITY - LOADING_BASE_OPACITY) * eased;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
// Tooltip styling (roundnessClass, tooltipVariantClass, tooltipRow,
|
|
410
|
-
// tooltipIndicatorHtml) and the legend overlay (LegendOverlay + its indicators)
|
|
411
|
-
// now live in ./echarts/{tooltip,legend} and are imported at the top
|
|
412
|
-
// of this file.
|
|
413
|
-
|
|
414
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
415
|
-
// Background overlay (SVG) — the Recharts twin renders its decorative pattern in
|
|
416
|
-
// SVG, so we render the SAME SVG patterns as a layer BEHIND the transparent
|
|
417
|
-
// ECharts canvas. Copied verbatim from the repo's <ChartBackground> so this file
|
|
418
|
-
// depends on nothing outside `react`, `echarts`, and `motion`. The Tailwind
|
|
419
|
-
// `text-border` classes resolve in the DOM; the blur-masked rect fades the edges.
|
|
420
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
421
|
-
|
|
422
|
-
type PatternProps = { id: string };
|
|
423
|
-
|
|
424
|
-
const BACKGROUND_PATTERNS: Record<BackgroundVariant, FC<PatternProps>> = {
|
|
425
|
-
dots: ({ id }) => (
|
|
426
|
-
<pattern id={id} x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
|
|
427
|
-
<circle className="text-border" cx="2" cy="2" r="1" fill="currentColor" />
|
|
428
|
-
</pattern>
|
|
429
|
-
),
|
|
430
|
-
grid: ({ id }) => (
|
|
431
|
-
<pattern id={id} x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
|
|
432
|
-
<path
|
|
433
|
-
className="text-border"
|
|
434
|
-
d="M 20 0 L 0 0 0 20"
|
|
435
|
-
fill="none"
|
|
436
|
-
stroke="currentColor"
|
|
437
|
-
strokeWidth="0.5"
|
|
438
|
-
/>
|
|
439
|
-
</pattern>
|
|
440
|
-
),
|
|
441
|
-
"cross-hatch": ({ id }) => (
|
|
442
|
-
<pattern id={id} x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
|
|
443
|
-
<path
|
|
444
|
-
className="text-border/60 dark:text-border/50"
|
|
445
|
-
d="M 0 0 L 20 20 M 20 0 L 0 20"
|
|
446
|
-
fill="none"
|
|
447
|
-
stroke="currentColor"
|
|
448
|
-
strokeWidth="0.5"
|
|
449
|
-
/>
|
|
450
|
-
</pattern>
|
|
451
|
-
),
|
|
452
|
-
"diagonal-lines": ({ id }) => (
|
|
453
|
-
<pattern
|
|
454
|
-
id={id}
|
|
455
|
-
x="0"
|
|
456
|
-
y="0"
|
|
457
|
-
width="6"
|
|
458
|
-
height="6"
|
|
459
|
-
patternUnits="userSpaceOnUse"
|
|
460
|
-
patternTransform="rotate(45)"
|
|
461
|
-
>
|
|
462
|
-
<line
|
|
463
|
-
className="text-border"
|
|
464
|
-
x1="0"
|
|
465
|
-
y1="0"
|
|
466
|
-
x2="0"
|
|
467
|
-
y2="6"
|
|
468
|
-
stroke="currentColor"
|
|
469
|
-
strokeWidth="0.5"
|
|
470
|
-
/>
|
|
471
|
-
</pattern>
|
|
472
|
-
),
|
|
473
|
-
plus: ({ id }) => (
|
|
474
|
-
<pattern id={id} x="0" y="0" width="16" height="16" patternUnits="userSpaceOnUse">
|
|
475
|
-
<path
|
|
476
|
-
className="text-border"
|
|
477
|
-
d="M 8 4 L 8 12 M 4 8 L 12 8"
|
|
478
|
-
fill="none"
|
|
479
|
-
stroke="currentColor"
|
|
480
|
-
strokeWidth="0.5"
|
|
481
|
-
strokeLinecap="round"
|
|
482
|
-
/>
|
|
483
|
-
</pattern>
|
|
484
|
-
),
|
|
485
|
-
"falling-triangles": ({ id }) => (
|
|
486
|
-
<pattern id={id} x="0" y="0" width="18" height="36" patternUnits="userSpaceOnUse">
|
|
487
|
-
<path
|
|
488
|
-
className="text-border"
|
|
489
|
-
d="M2 6h12L8 18 2 6zm18 36h12l-6 12-6-12z"
|
|
490
|
-
transform="scale(0.5)"
|
|
491
|
-
fill="currentColor"
|
|
492
|
-
fillOpacity="0.4"
|
|
493
|
-
/>
|
|
494
|
-
</pattern>
|
|
495
|
-
),
|
|
496
|
-
"4-pointed-star": ({ id }) => (
|
|
497
|
-
<pattern id={id} x="0" y="0" width="16" height="16" patternUnits="userSpaceOnUse">
|
|
498
|
-
<polygon
|
|
499
|
-
className="text-border"
|
|
500
|
-
fillRule="evenodd"
|
|
501
|
-
points="5 3 8 4 5 5 4 8 3 5 0 4 3 3 4 0 5 3"
|
|
502
|
-
fill="currentColor"
|
|
503
|
-
fillOpacity="0.4"
|
|
504
|
-
/>
|
|
505
|
-
</pattern>
|
|
506
|
-
),
|
|
507
|
-
"tiny-checkers": ({ id }) => (
|
|
508
|
-
<pattern id={id} x="0" y="0" width="8" height="8" patternUnits="userSpaceOnUse">
|
|
509
|
-
<path
|
|
510
|
-
className="text-border"
|
|
511
|
-
fillRule="evenodd"
|
|
512
|
-
d="M0 0h4v4H0V0zm4 4h4v4H4V4z"
|
|
513
|
-
fill="currentColor"
|
|
514
|
-
fillOpacity="0.2"
|
|
515
|
-
/>
|
|
516
|
-
</pattern>
|
|
517
|
-
),
|
|
518
|
-
"overlapping-circles": ({ id }) => (
|
|
519
|
-
<pattern id={id} x="0" y="0" width="40" height="40" patternUnits="userSpaceOnUse">
|
|
520
|
-
<path
|
|
521
|
-
className="text-border"
|
|
522
|
-
fillRule="evenodd"
|
|
523
|
-
d="M25 25c0-2.762 2.238-5 5-5s5 2.238 5 5-2.238 5-5 5c0 2.762-2.238 5-5 5s-5-2.238-5-5 2.238-5 5-5zM5 5c0-2.762 2.238-5 5-5s5 2.238 5 5-2.238 5-5 5c0 2.762-2.238 5-5 5S0 12.762 0 10s2.238-5 5-5zm5 4c2.209 0 4-1.791 4-4s-1.791-4-4-4-4 1.791-4 4 1.791 4 4 4zm20 20c2.209 0 4-1.791 4-4s-1.791-4-4-4-4 1.791-4 4 1.791 4 4 4z"
|
|
524
|
-
fill="currentColor"
|
|
525
|
-
fillOpacity="0.4"
|
|
526
|
-
/>
|
|
527
|
-
</pattern>
|
|
528
|
-
),
|
|
529
|
-
"wiggle-lines": ({ id }) => (
|
|
530
|
-
<pattern
|
|
531
|
-
id={id}
|
|
532
|
-
x="0"
|
|
533
|
-
y="0"
|
|
534
|
-
width="52"
|
|
535
|
-
height="26"
|
|
536
|
-
patternUnits="userSpaceOnUse"
|
|
537
|
-
patternTransform="scale(0.6)"
|
|
538
|
-
>
|
|
539
|
-
<path
|
|
540
|
-
className="text-border"
|
|
541
|
-
d="M10 10c0-2.21-1.79-4-4-4-3.314 0-6-2.686-6-6h2c0 2.21 1.79 4 4 4 3.314 0 6 2.686 6 6 0 2.21 1.79 4 4 4 3.314 0 6 2.686 6 6 0 2.21 1.79 4 4 4 3.314 0 6 2.686 6 6 0 2.21 1.79 4 4 4v2c-3.314 0-6-2.686-6-6 0-2.21-1.79-4-4-4-3.314 0-6-2.686-6-6zm25.464-1.95l8.486 8.486-1.414 1.414-8.486-8.486 1.414-1.414z"
|
|
542
|
-
fill="currentColor"
|
|
543
|
-
fillOpacity="0.4"
|
|
544
|
-
/>
|
|
545
|
-
</pattern>
|
|
546
|
-
),
|
|
547
|
-
bubbles: ({ id }) => (
|
|
548
|
-
<pattern
|
|
549
|
-
id={id}
|
|
550
|
-
x="0"
|
|
551
|
-
y="0"
|
|
552
|
-
width="100"
|
|
553
|
-
height="100"
|
|
554
|
-
patternUnits="userSpaceOnUse"
|
|
555
|
-
patternTransform="scale(0.6667)"
|
|
556
|
-
>
|
|
557
|
-
<path
|
|
558
|
-
className="text-border"
|
|
559
|
-
d="M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm48 25c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm-43-7c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm63 31c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 90c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm56-76c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM12 86c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm28-65c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm23-11c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-6 60c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm29 22c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM32 63c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm57-13c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-9-21c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM60 91c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM35 41c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM12 60c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z"
|
|
560
|
-
fill="currentColor"
|
|
561
|
-
fillOpacity="0.4"
|
|
562
|
-
fillRule="evenodd"
|
|
563
|
-
/>
|
|
564
|
-
</pattern>
|
|
565
|
-
),
|
|
566
|
-
};
|
|
567
|
-
|
|
568
|
-
function BackgroundLayer({ variant }: { variant: BackgroundVariant }) {
|
|
569
|
-
const baseId = useId().replace(/:/g, "");
|
|
570
|
-
const patternId = `${baseId}-bg-${variant}`;
|
|
571
|
-
const maskId = `${baseId}-bg-edge-fade`;
|
|
572
|
-
const filterId = `${baseId}-bg-blur`;
|
|
573
|
-
const PatternComponent = BACKGROUND_PATTERNS[variant];
|
|
574
|
-
|
|
575
|
-
return (
|
|
576
|
-
<svg
|
|
577
|
-
className="pointer-events-none absolute inset-0 h-full w-full"
|
|
578
|
-
aria-hidden
|
|
579
|
-
preserveAspectRatio="none"
|
|
580
|
-
>
|
|
581
|
-
<defs>
|
|
582
|
-
<PatternComponent id={patternId} />
|
|
583
|
-
{/* Gaussian blur for a soft edge fade — a slightly inset white rect blurred
|
|
584
|
-
into a mask leaves smooth transparent edges. */}
|
|
585
|
-
<filter id={filterId}>
|
|
586
|
-
<feGaussianBlur stdDeviation="25" />
|
|
587
|
-
</filter>
|
|
588
|
-
<mask id={maskId} maskUnits="userSpaceOnUse">
|
|
589
|
-
<rect x="8%" y="20%" width="85%" height="60%" fill="white" filter={`url(#${filterId})`} />
|
|
590
|
-
</mask>
|
|
591
|
-
</defs>
|
|
592
|
-
<rect width="100%" height="100%" fill={`url(#${patternId})`} mask={`url(#${maskId})`} />
|
|
593
|
-
</svg>
|
|
594
|
-
);
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
598
|
-
// Option builders — pure functions from a snapshot context to ECharts option
|
|
599
|
-
// fragments. The component reads its refs ONCE per build into this context;
|
|
600
|
-
// nothing below touches React state or the chart instance.
|
|
601
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
602
|
-
|
|
603
|
-
type OptionBuildContext = {
|
|
604
|
-
data: Record<string, unknown>[];
|
|
605
|
-
config: ChartConfig;
|
|
606
|
-
nameKey: string;
|
|
607
|
-
dataKey: string;
|
|
608
|
-
pie: PieSlot | null;
|
|
609
|
-
selectedSector: string | null;
|
|
610
|
-
tooltipSlot: TooltipSlot;
|
|
611
|
-
legendSlot: LegendSlot;
|
|
612
|
-
isLoading: boolean;
|
|
613
|
-
resolved: ResolvedColors;
|
|
614
|
-
};
|
|
615
|
-
|
|
616
|
-
// The pie's vertical centre reserves room for the HTML legend overlay: a legend
|
|
617
|
-
// along the bottom nudges the pie up, one along the top nudges it down. Kept as a
|
|
618
|
-
// percentage so it tracks the container size (the legend is fixed-height text).
|
|
619
|
-
function pieCenterY(legendSlot: LegendSlot): string {
|
|
620
|
-
if (!legendSlot.present) return "50%";
|
|
621
|
-
if (legendSlot.verticalAlign === "bottom") return "45%";
|
|
622
|
-
if (legendSlot.verticalAlign === "top") return "55%";
|
|
623
|
-
return "50%";
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
// Tooltip HTML builder, closed over the build context. The pie tooltip is
|
|
627
|
-
// item-triggered, so each hover surfaces exactly one sector — its indicator,
|
|
628
|
-
// label, and value, matching ChartTooltipContent with `hideLabel` (no header).
|
|
629
|
-
function createTooltipFormatter(ctx: OptionBuildContext) {
|
|
630
|
-
const { config, selectedSector, tooltipSlot } = ctx;
|
|
631
|
-
|
|
632
|
-
return (params: unknown): string => {
|
|
633
|
-
const p = (Array.isArray(params) ? params[0] : params) as {
|
|
634
|
-
name?: string;
|
|
635
|
-
value?: number | string;
|
|
636
|
-
seriesId?: string;
|
|
637
|
-
} | null;
|
|
638
|
-
// The loading skeleton is a `__`-prefixed series and never surfaces a tooltip.
|
|
639
|
-
if (!p || String(p.seriesId ?? "").startsWith("__")) return "";
|
|
640
|
-
|
|
641
|
-
const name = String(p.name ?? "");
|
|
642
|
-
const item = config[name];
|
|
643
|
-
const colorsCount = item ? getColorsCount(item) : 1;
|
|
644
|
-
const labelText = typeof item?.label === "string" ? item.label : name;
|
|
645
|
-
const value = typeof p.value === "number" ? p.value.toLocaleString() : String(p.value ?? "");
|
|
646
|
-
const dimmed = selectedSector != null && selectedSector !== name ? " opacity-30" : "";
|
|
647
|
-
|
|
648
|
-
// The row shape matches the area chart's indicator + label + value, so it
|
|
649
|
-
// reuses the shared tooltipRow/tooltipIndicatorHtml. The pie tooltip is
|
|
650
|
-
// item-triggered with NO header (hideLabel), so it keeps its own no-header
|
|
651
|
-
// shell — built from the shared roundnessClass/tooltipVariantClass — rather
|
|
652
|
-
// than the header-carrying tooltipShell.
|
|
653
|
-
const row = tooltipRow({
|
|
654
|
-
indicatorHtml: tooltipIndicatorHtml(name, colorsCount),
|
|
655
|
-
labelText,
|
|
656
|
-
valueText: value,
|
|
657
|
-
dimmed,
|
|
658
|
-
});
|
|
659
|
-
|
|
660
|
-
return `<div class="grid min-w-32 items-start gap-1.5 border border-border/50 px-2.5 py-1.5 text-xs shadow-xl ${roundnessClass[tooltipSlot.roundness]} ${tooltipVariantClass[tooltipSlot.variant]}">
|
|
661
|
-
<div class="grid gap-1.5">${row}</div>
|
|
662
|
-
</div>`;
|
|
663
|
-
};
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
function buildTooltipOption(ctx: OptionBuildContext): TooltipComponentOption {
|
|
667
|
-
const { tooltipSlot, isLoading } = ctx;
|
|
668
|
-
// The pie tooltip is item-triggered (no axis, no cursor line), so it can't use
|
|
669
|
-
// the shared tooltipBaseOption (which is trigger:"axis" with an axisPointer).
|
|
670
|
-
// It keeps its own item-tooltip fields and wires the position prop directly
|
|
671
|
-
// through the shared resolveTooltipPosition — "variable" → undefined (default
|
|
672
|
-
// follow-the-pointer behavior), "fixed" → pinned near the top, tracking X.
|
|
673
|
-
return {
|
|
674
|
-
show: tooltipSlot.present && !isLoading,
|
|
675
|
-
trigger: "item",
|
|
676
|
-
confine: true,
|
|
677
|
-
backgroundColor: "transparent",
|
|
678
|
-
borderWidth: 0,
|
|
679
|
-
padding: 0,
|
|
680
|
-
extraCssText: "box-shadow:none;",
|
|
681
|
-
displayTransition: false,
|
|
682
|
-
position: resolveTooltipPosition(tooltipSlot.position),
|
|
683
|
-
formatter: createTooltipFormatter(ctx),
|
|
684
|
-
};
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// The pie series. Each row becomes a sector whose fill is its own color gradient,
|
|
688
|
-
// dimmed when another sector is selected, and separated from its neighbors by a
|
|
689
|
-
// constant-width background border (see sectorBorder). The selected sector pops
|
|
690
|
-
// radially outward via ECharts' native select state (selectedOffset).
|
|
691
|
-
function buildPieSeries(ctx: OptionBuildContext): PieSeriesOption[] {
|
|
692
|
-
const { data, config, nameKey, dataKey, pie, selectedSector, legendSlot, resolved } = ctx;
|
|
693
|
-
if (!pie) return [];
|
|
694
|
-
const { tokens } = resolved;
|
|
695
|
-
const hasSelection = selectedSector !== null;
|
|
696
|
-
// Selection (dim + pop-out) is only meaningful on a clickable pie.
|
|
697
|
-
const border = sectorBorder(pie.paddingAngle, tokens.background);
|
|
698
|
-
|
|
699
|
-
const sectors = data.map((row) => {
|
|
700
|
-
const name = String(row[nameKey]);
|
|
701
|
-
const slots = resolved.series[name] ?? [FALLBACK_COLOR];
|
|
702
|
-
// Only a clickable pie dims — a static one never has a selection to dim from.
|
|
703
|
-
const isSelected = pie.isClickable && selectedSector === name;
|
|
704
|
-
const isDimmed = pie.isClickable && hasSelection && selectedSector !== name;
|
|
705
|
-
|
|
706
|
-
const itemStyle: PieItemStyle = {
|
|
707
|
-
color: sectorPaint(slots),
|
|
708
|
-
opacity: isDimmed ? DIMMED_OPACITY : 1,
|
|
709
|
-
borderRadius: pie.cornerRadius,
|
|
710
|
-
};
|
|
711
|
-
// Constant-width background gap (positive paddingAngle) or overlap separator
|
|
712
|
-
// (negative). Parallel-edged from rim to center — no wedge-shaped taper.
|
|
713
|
-
if (border) {
|
|
714
|
-
itemStyle.borderColor = border.borderColor;
|
|
715
|
-
itemStyle.borderWidth = border.borderWidth;
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
// The `selected` flag drives the native offset — React selection is the single
|
|
719
|
-
// source of truth, re-applied on every notMerge push so it survives rebuilds.
|
|
720
|
-
return { name, value: Number(row[dataKey]) || 0, itemStyle, selected: isSelected };
|
|
721
|
-
});
|
|
722
|
-
|
|
723
|
-
const showLabel = pie.labelDataKey !== null;
|
|
724
|
-
const isOutside = pie.labelPosition === "outside";
|
|
725
|
-
// An explicit <Label dataKey> always wins. Otherwise inside labels show the
|
|
726
|
-
// sector's value (Recharts parity) and outside labels show the sector's name/
|
|
727
|
-
// config label — matching the classic ECharts pie-simple outer labels.
|
|
728
|
-
const explicitKey = pie.labelDataKey ? pie.labelDataKey : null;
|
|
729
|
-
const labelFormatter = (labelParams: { dataIndex: number; name?: string; value?: unknown }) => {
|
|
730
|
-
if (explicitKey) return String(data[labelParams.dataIndex]?.[explicitKey] ?? "");
|
|
731
|
-
if (isOutside) {
|
|
732
|
-
const item = config[String(labelParams.name ?? "")];
|
|
733
|
-
return typeof item?.label === "string" ? item.label : String(labelParams.name ?? "");
|
|
734
|
-
}
|
|
735
|
-
return String(data[labelParams.dataIndex]?.[dataKey] ?? labelParams.value ?? "");
|
|
736
|
-
};
|
|
737
|
-
|
|
738
|
-
const label = {
|
|
739
|
-
show: showLabel,
|
|
740
|
-
// Inner value labels sit on the colored sector (background-colored text);
|
|
741
|
-
// outer name labels sit past the rim in muted-foreground with a leader.
|
|
742
|
-
position: (isOutside ? "outside" : "inner") as "outside" | "inner",
|
|
743
|
-
color: isOutside ? tokens.mutedForeground : tokens.background,
|
|
744
|
-
fontSize: 12,
|
|
745
|
-
fontWeight: 500,
|
|
746
|
-
formatter: labelFormatter,
|
|
747
|
-
};
|
|
748
|
-
|
|
749
|
-
return [
|
|
750
|
-
{
|
|
751
|
-
id: "pie",
|
|
752
|
-
type: "pie",
|
|
753
|
-
center: ["50%", pieCenterY(legendSlot)],
|
|
754
|
-
radius: [pie.innerRadius, pie.outerRadius],
|
|
755
|
-
startAngle: pie.startAngle,
|
|
756
|
-
endAngle: pie.endAngle,
|
|
757
|
-
// Recharts sweeps counterclockwise from 3 o'clock; ECharts angles share that
|
|
758
|
-
// orientation, so `clockwise: false` reproduces the twin's sector order.
|
|
759
|
-
clockwise: false,
|
|
760
|
-
// Only a NEGATIVE paddingAngle reaches padAngle (petal overlap). Positive
|
|
761
|
-
// gaps are drawn as constant-width borders instead — an angular pad would
|
|
762
|
-
// taper to a wedge toward the center.
|
|
763
|
-
padAngle: Math.min(pie.paddingAngle, 0),
|
|
764
|
-
cursor: pie.isClickable ? "pointer" : "default",
|
|
765
|
-
// No hover scale on ANY variant — hovering only surfaces the tooltip. The
|
|
766
|
-
// pop-out below is the sole selection affordance, never a hover effect.
|
|
767
|
-
emphasis: { scale: false },
|
|
768
|
-
// Native select state: the chosen sector translates SELECTED_OFFSET px along
|
|
769
|
-
// its bisector, away from the center (the offset-slice pie-pattern look).
|
|
770
|
-
// Driven by each datum's `selected` flag; deselecting returns it.
|
|
771
|
-
selectedMode: pie.isClickable ? "single" : false,
|
|
772
|
-
selectedOffset: SELECTED_OFFSET,
|
|
773
|
-
// Neutralize any default select styling — the selected sector keeps its
|
|
774
|
-
// normal paint (inherited via state merge) and only its position moves.
|
|
775
|
-
select: { itemStyle: {} },
|
|
776
|
-
label,
|
|
777
|
-
labelLine: isOutside
|
|
778
|
-
? {
|
|
779
|
-
show: true,
|
|
780
|
-
length: 14,
|
|
781
|
-
length2: 14,
|
|
782
|
-
smooth: false,
|
|
783
|
-
// Leader lines drawn in a muted token, matching the docs aesthetic.
|
|
784
|
-
lineStyle: { color: withAlpha(tokens.mutedForeground, 0.45), width: 1 },
|
|
785
|
-
}
|
|
786
|
-
: { show: false },
|
|
787
|
-
data: sectors,
|
|
788
|
-
},
|
|
789
|
-
];
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
// Loading skeleton — ONE gray ring of equal sectors regardless of the real data
|
|
793
|
-
// (Recharts parity), swept by the shimmer rAF. Respects the pie's shape so a
|
|
794
|
-
// donut skeleton stays a donut. The per-sector color is a placeholder; the rAF
|
|
795
|
-
// loop retints each sector every frame.
|
|
796
|
-
function buildLoadingOption(ctx: OptionBuildContext): EChartsOption {
|
|
797
|
-
const { pie, legendSlot, resolved } = ctx;
|
|
798
|
-
const { tokens } = resolved;
|
|
799
|
-
|
|
800
|
-
const innerRadius = pie?.innerRadius ?? DEFAULT_INNER_RADIUS;
|
|
801
|
-
const outerRadius = pie?.outerRadius ?? DEFAULT_OUTER_RADIUS;
|
|
802
|
-
const cornerRadius = pie?.cornerRadius ?? DEFAULT_CORNER_RADIUS;
|
|
803
|
-
const paddingAngle = pie?.paddingAngle ?? DEFAULT_PADDING_ANGLE;
|
|
804
|
-
const startAngle = pie?.startAngle ?? DEFAULT_START_ANGLE;
|
|
805
|
-
const endAngle = pie?.endAngle ?? DEFAULT_END_ANGLE;
|
|
806
|
-
|
|
807
|
-
const border = sectorBorder(paddingAngle, tokens.background);
|
|
808
|
-
const sectors = Array.from({ length: LOADING_SECTORS }, (_, i) => {
|
|
809
|
-
const itemStyle: PieItemStyle = {
|
|
810
|
-
color: withAlpha(tokens.foreground, LOADING_BASE_OPACITY),
|
|
811
|
-
opacity: 1,
|
|
812
|
-
borderRadius: cornerRadius,
|
|
813
|
-
};
|
|
814
|
-
// Same constant-width gap / overlap separator as the real pie.
|
|
815
|
-
if (border) {
|
|
816
|
-
itemStyle.borderColor = border.borderColor;
|
|
817
|
-
itemStyle.borderWidth = border.borderWidth;
|
|
818
|
-
}
|
|
819
|
-
return { name: `__loading-${i}`, value: 1, itemStyle };
|
|
820
|
-
});
|
|
821
|
-
|
|
822
|
-
return {
|
|
823
|
-
animation: false,
|
|
824
|
-
tooltip: { show: false },
|
|
825
|
-
series: [
|
|
826
|
-
{
|
|
827
|
-
id: "__loading",
|
|
828
|
-
type: "pie",
|
|
829
|
-
center: ["50%", pieCenterY(legendSlot)],
|
|
830
|
-
radius: [innerRadius, outerRadius],
|
|
831
|
-
startAngle,
|
|
832
|
-
endAngle,
|
|
833
|
-
clockwise: false,
|
|
834
|
-
padAngle: Math.min(paddingAngle, 0),
|
|
835
|
-
silent: true,
|
|
836
|
-
emphasis: { scale: false },
|
|
837
|
-
label: { show: false },
|
|
838
|
-
labelLine: { show: false },
|
|
839
|
-
data: sectors,
|
|
840
|
-
},
|
|
841
|
-
],
|
|
842
|
-
};
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
846
|
-
// Live imperative state — everything the ECharts event handlers and rAF loops
|
|
847
|
-
// read or write OUTSIDE the React render cycle, grouped in one ref-stable object
|
|
848
|
-
// so the whole imperative surface is visible at a glance. None of it is render
|
|
849
|
-
// output, which is exactly why it is not React state.
|
|
850
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
851
|
-
|
|
852
|
-
type LiveState = {
|
|
853
|
-
resolved: ResolvedColors | null; // colors read off the live DOM — feeds builds and rAF loops
|
|
854
|
-
hasRevealed: boolean; // the intro draw-in already played on this chart instance
|
|
855
|
-
// Latest callbacks/flags for the imperative ECharts click handler.
|
|
856
|
-
handlers: {
|
|
857
|
-
isClickable: boolean;
|
|
858
|
-
selectedSector: string | null;
|
|
859
|
-
selectSector: (name: string | null) => void;
|
|
860
|
-
};
|
|
861
|
-
// Update-style re-push for paths that bypass React entirely (theme flips) —
|
|
862
|
-
// set by the sync effect.
|
|
863
|
-
repush: () => void;
|
|
864
|
-
};
|
|
865
|
-
|
|
866
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
867
|
-
// Component
|
|
868
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
869
|
-
|
|
870
|
-
/**
|
|
871
|
-
* Apache ECharts port of the EvilCharts pie chart, exposing a compound-as-config
|
|
872
|
-
* API so its JSX reads identically to the Recharts twin. The root owns the data,
|
|
873
|
-
* config, selection state, loading skeleton, and intro reveal; every visual part —
|
|
874
|
-
* `<Pie>`, `<Tooltip>`, `<Legend>`, `<Background>` — is composed as a declarative
|
|
875
|
-
* child that renders nothing. The root walks those children by reference and
|
|
876
|
-
* drives a single imperative ECharts instance. Fully self-contained: its only
|
|
877
|
-
* dependencies are `react`, `echarts`, and `motion`.
|
|
878
|
-
*/
|
|
879
|
-
export function EChartsPieChart<TData extends Record<string, unknown>>({
|
|
880
|
-
data,
|
|
881
|
-
config,
|
|
882
|
-
dataKey,
|
|
883
|
-
nameKey,
|
|
884
|
-
className,
|
|
885
|
-
renderer = DEFAULT_ECHARTS_RENDERER,
|
|
886
|
-
animation = true,
|
|
887
|
-
defaultSelectedSector = null,
|
|
888
|
-
selectedSector: selectedSectorProp,
|
|
889
|
-
onSelectionChange,
|
|
890
|
-
isLoading = false,
|
|
891
|
-
chartOptions,
|
|
892
|
-
children,
|
|
893
|
-
}: EChartsPieChartProps<TData>) {
|
|
894
|
-
const rawId = useId();
|
|
895
|
-
const chartId = `chart-${rawId.replace(/:/g, "")}`;
|
|
896
|
-
|
|
897
|
-
const containerRef = useRef<HTMLDivElement>(null);
|
|
898
|
-
const mountRef = useRef<HTMLDivElement>(null);
|
|
899
|
-
const echartsRef = useRef<EChartsInstance | null>(null);
|
|
900
|
-
|
|
901
|
-
// The single imperative surface (see LiveState). `resolved` lives here rather
|
|
902
|
-
// than in state: as state it would force an extra render pass and an effect
|
|
903
|
-
// whose only job is to trigger the option push. The object identity is stable
|
|
904
|
-
// for the component's lifetime.
|
|
905
|
-
const live = useRef<LiveState>({
|
|
906
|
-
resolved: null,
|
|
907
|
-
hasRevealed: false,
|
|
908
|
-
handlers: {
|
|
909
|
-
isClickable: false,
|
|
910
|
-
selectedSector: defaultSelectedSector,
|
|
911
|
-
selectSector: () => {},
|
|
912
|
-
},
|
|
913
|
-
repush: () => {},
|
|
914
|
-
}).current;
|
|
915
|
-
|
|
916
|
-
const shouldReduceMotion = useReducedMotion();
|
|
917
|
-
|
|
918
|
-
// Selection is controlled when the `selectedSector` prop is provided; otherwise
|
|
919
|
-
// the internal state (seeded by defaultSelectedSector) drives it.
|
|
920
|
-
const [internalSelectedSector, setSelectedSector] = useState<string | null>(
|
|
921
|
-
defaultSelectedSector,
|
|
922
|
-
);
|
|
923
|
-
const selectedSector =
|
|
924
|
-
selectedSectorProp !== undefined ? selectedSectorProp : internalSelectedSector;
|
|
925
|
-
|
|
926
|
-
// ── Declarative config, collected from children by reference ─────────────────
|
|
927
|
-
const collected = useMemo(() => collectConfig(children), [children]);
|
|
928
|
-
const { pie, tooltip: tooltipSlot, legend: legendSlot, background: backgroundSlot } = collected;
|
|
929
|
-
|
|
930
|
-
// Sector names in data order — the keys color resolution, the legend, and the
|
|
931
|
-
// click handler all agree on. Config is keyed by these same names.
|
|
932
|
-
const sectorKeys = useMemo(
|
|
933
|
-
() => data.map((row) => String(row[nameKey as string])),
|
|
934
|
-
[data, nameKey],
|
|
935
|
-
);
|
|
936
|
-
|
|
937
|
-
const css = useMemo(() => buildChartCss(chartId, config), [chartId, config]);
|
|
938
|
-
|
|
939
|
-
// Sets selection state and notifies the parent with the sector's value.
|
|
940
|
-
const selectSector = useCallback(
|
|
941
|
-
(name: string | null) => {
|
|
942
|
-
setSelectedSector(name);
|
|
943
|
-
if (name === null) {
|
|
944
|
-
onSelectionChange?.(null);
|
|
945
|
-
return;
|
|
946
|
-
}
|
|
947
|
-
const item = data.find((row) => String(row[nameKey as string]) === name);
|
|
948
|
-
onSelectionChange?.(
|
|
949
|
-
item ? { dataKey: name, value: Number(item[dataKey as string]) || 0 } : null,
|
|
950
|
-
);
|
|
951
|
-
},
|
|
952
|
-
[data, dataKey, nameKey, onSelectionChange],
|
|
953
|
-
);
|
|
954
|
-
|
|
955
|
-
// Refresh the click handler's snapshot of the latest callbacks/flags every render.
|
|
956
|
-
live.handlers = {
|
|
957
|
-
isClickable: pie?.isClickable ?? false,
|
|
958
|
-
selectedSector,
|
|
959
|
-
selectSector,
|
|
960
|
-
};
|
|
961
|
-
|
|
962
|
-
// ── Option builder ───────────────────────────────────────────────────────────
|
|
963
|
-
// Thin orchestrator over the pure builders above: snapshot the resolved colors
|
|
964
|
-
// into an OptionBuildContext, then assemble.
|
|
965
|
-
const buildOption = useCallback((): EChartsOption => {
|
|
966
|
-
const resolved = live.resolved;
|
|
967
|
-
if (!resolved) return {};
|
|
968
|
-
|
|
969
|
-
const ctx: OptionBuildContext = {
|
|
970
|
-
data,
|
|
971
|
-
config,
|
|
972
|
-
nameKey: nameKey as string,
|
|
973
|
-
dataKey: dataKey as string,
|
|
974
|
-
pie,
|
|
975
|
-
selectedSector,
|
|
976
|
-
tooltipSlot,
|
|
977
|
-
legendSlot,
|
|
978
|
-
isLoading,
|
|
979
|
-
resolved,
|
|
980
|
-
};
|
|
981
|
-
|
|
982
|
-
if (isLoading) return buildLoadingOption(ctx);
|
|
983
|
-
|
|
984
|
-
return {
|
|
985
|
-
animation: false,
|
|
986
|
-
tooltip: buildTooltipOption(ctx),
|
|
987
|
-
series: buildPieSeries(ctx),
|
|
988
|
-
};
|
|
989
|
-
}, [
|
|
990
|
-
live,
|
|
991
|
-
data,
|
|
992
|
-
config,
|
|
993
|
-
nameKey,
|
|
994
|
-
dataKey,
|
|
995
|
-
pie,
|
|
996
|
-
selectedSector,
|
|
997
|
-
tooltipSlot,
|
|
998
|
-
legendSlot,
|
|
999
|
-
isLoading,
|
|
1000
|
-
]);
|
|
1001
|
-
|
|
1002
|
-
// ── Init + resize + theme observer (per renderer instance) ───────────────────
|
|
1003
|
-
useEffect(() => {
|
|
1004
|
-
const mount = mountRef.current;
|
|
1005
|
-
const container = containerRef.current;
|
|
1006
|
-
if (!mount || !container) return;
|
|
1007
|
-
|
|
1008
|
-
const chart = echarts.init(mount, null, { renderer });
|
|
1009
|
-
echartsRef.current = chart;
|
|
1010
|
-
|
|
1011
|
-
const resizeObserver = new ResizeObserver(() => {
|
|
1012
|
-
// Observers always fire once right after observe(). Repushing on that no-op
|
|
1013
|
-
// fire would land one frame into the intro and stomp the reveal — only
|
|
1014
|
-
// react when the renderer size actually changed. The pie has no
|
|
1015
|
-
// renderer-sized textures, so a plain resize() (which re-lays the
|
|
1016
|
-
// percentage geometry) is all a size change needs.
|
|
1017
|
-
if (mount.clientWidth === chart.getWidth() && mount.clientHeight === chart.getHeight()) {
|
|
1018
|
-
return;
|
|
1019
|
-
}
|
|
1020
|
-
chart.resize();
|
|
1021
|
-
});
|
|
1022
|
-
resizeObserver.observe(mount);
|
|
1023
|
-
|
|
1024
|
-
// Light/dark flips change no React state — re-resolve and push directly.
|
|
1025
|
-
const themeObserver = new MutationObserver(() => {
|
|
1026
|
-
live.repush();
|
|
1027
|
-
});
|
|
1028
|
-
themeObserver.observe(document.documentElement, {
|
|
1029
|
-
attributes: true,
|
|
1030
|
-
attributeFilter: ["class"],
|
|
1031
|
-
});
|
|
1032
|
-
|
|
1033
|
-
chart.on("click", (params) => {
|
|
1034
|
-
const { isClickable, selectedSector: selected, selectSector: select } = live.handlers;
|
|
1035
|
-
if (!isClickable) return;
|
|
1036
|
-
const p = params as { name?: string; seriesId?: string };
|
|
1037
|
-
// Ignore the loading skeleton's `__`-prefixed series.
|
|
1038
|
-
if (String(p.seriesId ?? "").startsWith("__")) return;
|
|
1039
|
-
const name = p.name;
|
|
1040
|
-
if (typeof name !== "string") return;
|
|
1041
|
-
// Clicking the selected sector clears the selection, otherwise selects it.
|
|
1042
|
-
select(selected === name ? null : name);
|
|
1043
|
-
});
|
|
1044
|
-
|
|
1045
|
-
return () => {
|
|
1046
|
-
resizeObserver.disconnect();
|
|
1047
|
-
themeObserver.disconnect();
|
|
1048
|
-
chart.dispose();
|
|
1049
|
-
echartsRef.current = null;
|
|
1050
|
-
// The reveal guard belongs to the chart instance it guarded. Without this
|
|
1051
|
-
// reset, StrictMode's dev-only mount→unmount→remount plays the entrance on
|
|
1052
|
-
// the throwaway instance and the surviving one renders without it.
|
|
1053
|
-
live.hasRevealed = false;
|
|
1054
|
-
};
|
|
1055
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1056
|
-
}, [renderer]);
|
|
1057
|
-
|
|
1058
|
-
// ── Sync ECharts with props/theme/selection — resolve, build, push ────────────
|
|
1059
|
-
useEffect(() => {
|
|
1060
|
-
const chart = echartsRef.current;
|
|
1061
|
-
const container = containerRef.current;
|
|
1062
|
-
if (!chart || !container) return;
|
|
1063
|
-
|
|
1064
|
-
// Colors come from the <style> committed just before this effect ran — read
|
|
1065
|
-
// them here, right before the push, rather than round-tripping through state.
|
|
1066
|
-
live.resolved = resolveColors(container, config, sectorKeys);
|
|
1067
|
-
|
|
1068
|
-
const push = (withEntrance: boolean) => {
|
|
1069
|
-
const option = buildOption();
|
|
1070
|
-
const merged = chartOptions ? { ...option, ...chartOptions } : option;
|
|
1071
|
-
Object.assign(merged, {
|
|
1072
|
-
animation: withEntrance,
|
|
1073
|
-
animationDuration: REVEAL_DURATION,
|
|
1074
|
-
animationDurationUpdate: 0,
|
|
1075
|
-
});
|
|
1076
|
-
// chartOptions is an untyped escape hatch — the spread erases the option's
|
|
1077
|
-
// shape, so re-assert it. The only cast in the file.
|
|
1078
|
-
chart.setOption(merged as EChartsOption, { notMerge: true });
|
|
1079
|
-
};
|
|
1080
|
-
|
|
1081
|
-
// Intro reveal — ECharts' native pie expansion, enabled only for the first
|
|
1082
|
-
// real render. Every later push (selection, theme) applies instantly, since
|
|
1083
|
-
// notMerge would otherwise replay the entrance on each. A loading cycle
|
|
1084
|
-
// re-arms it: the Recharts twin remounts its sectors after loading and
|
|
1085
|
-
// replays the intro, so data → loading → data draws in again here too.
|
|
1086
|
-
if (isLoading) live.hasRevealed = false;
|
|
1087
|
-
const shouldReveal = !live.hasRevealed && !isLoading;
|
|
1088
|
-
if (shouldReveal) live.hasRevealed = true;
|
|
1089
|
-
const revealEnabled = animation && shouldReveal && !shouldReduceMotion;
|
|
1090
|
-
push(revealEnabled);
|
|
1091
|
-
|
|
1092
|
-
// Theme flips re-enter here without touching React: re-read the tokens (the
|
|
1093
|
-
// .dark class changed) and push an update-style option.
|
|
1094
|
-
live.repush = () => {
|
|
1095
|
-
live.resolved = resolveColors(container, config, sectorKeys);
|
|
1096
|
-
push(false);
|
|
1097
|
-
};
|
|
1098
|
-
}, [
|
|
1099
|
-
live,
|
|
1100
|
-
buildOption,
|
|
1101
|
-
chartOptions,
|
|
1102
|
-
isLoading,
|
|
1103
|
-
animation,
|
|
1104
|
-
shouldReduceMotion,
|
|
1105
|
-
config,
|
|
1106
|
-
renderer,
|
|
1107
|
-
sectorKeys,
|
|
1108
|
-
]);
|
|
1109
|
-
|
|
1110
|
-
// ── Default tooltip index — show a sector's tooltip with no hover ─────────────
|
|
1111
|
-
useEffect(() => {
|
|
1112
|
-
const chart = echartsRef.current;
|
|
1113
|
-
if (!chart || isLoading || !tooltipSlot.present || tooltipSlot.defaultIndex == null) return;
|
|
1114
|
-
// Dispatch after paint so the sector geometry exists to anchor the tooltip.
|
|
1115
|
-
const raf = requestAnimationFrame(() => {
|
|
1116
|
-
chart.dispatchAction({
|
|
1117
|
-
type: "showTip",
|
|
1118
|
-
seriesIndex: 0,
|
|
1119
|
-
dataIndex: tooltipSlot.defaultIndex,
|
|
1120
|
-
});
|
|
1121
|
-
});
|
|
1122
|
-
return () => cancelAnimationFrame(raf);
|
|
1123
|
-
}, [isLoading, tooltipSlot.present, tooltipSlot.defaultIndex, renderer]);
|
|
1124
|
-
|
|
1125
|
-
// ── Loading shimmer — rAF sweeps a bright window around the ring ──────────────
|
|
1126
|
-
useEffect(() => {
|
|
1127
|
-
const chart = echartsRef.current;
|
|
1128
|
-
if (!chart || !isLoading) return;
|
|
1129
|
-
|
|
1130
|
-
const cornerRadius = pie?.cornerRadius ?? DEFAULT_CORNER_RADIUS;
|
|
1131
|
-
const paddingAngle = pie?.paddingAngle ?? DEFAULT_PADDING_ANGLE;
|
|
1132
|
-
|
|
1133
|
-
let raf = 0;
|
|
1134
|
-
const start = performance.now();
|
|
1135
|
-
const tick = (now: number) => {
|
|
1136
|
-
const phase = ((((now - start) / LOADING_ANIMATION_DURATION) % 1) + 1) % 1;
|
|
1137
|
-
// Read tokens per frame, so a theme flip mid-loading retints the shimmer.
|
|
1138
|
-
const foreground = live.resolved?.tokens.foreground ?? FALLBACK_COLOR;
|
|
1139
|
-
const background = live.resolved?.tokens.background ?? FALLBACK_COLOR;
|
|
1140
|
-
|
|
1141
|
-
// Rebuild the full itemStyle for each sector — setOption replaces a series'
|
|
1142
|
-
// data array wholesale, so a partial datum would drop the border/rounding.
|
|
1143
|
-
const border = sectorBorder(paddingAngle, background);
|
|
1144
|
-
const sectors = Array.from({ length: LOADING_SECTORS }, (_, i) => {
|
|
1145
|
-
const pos = (i + 0.5) / LOADING_SECTORS;
|
|
1146
|
-
const itemStyle: PieItemStyle = {
|
|
1147
|
-
color: withAlpha(foreground, loadingSectorAlpha(pos, phase)),
|
|
1148
|
-
opacity: 1,
|
|
1149
|
-
borderRadius: cornerRadius,
|
|
1150
|
-
};
|
|
1151
|
-
if (border) {
|
|
1152
|
-
itemStyle.borderColor = border.borderColor;
|
|
1153
|
-
itemStyle.borderWidth = border.borderWidth;
|
|
1154
|
-
}
|
|
1155
|
-
return { value: 1, itemStyle };
|
|
1156
|
-
});
|
|
1157
|
-
|
|
1158
|
-
chart.setOption(
|
|
1159
|
-
{ series: [{ id: "__loading", data: sectors }] },
|
|
1160
|
-
{ silent: true, lazyUpdate: true },
|
|
1161
|
-
);
|
|
1162
|
-
raf = requestAnimationFrame(tick);
|
|
1163
|
-
};
|
|
1164
|
-
raf = requestAnimationFrame(tick);
|
|
1165
|
-
return () => cancelAnimationFrame(raf);
|
|
1166
|
-
}, [live, isLoading, pie, renderer]);
|
|
1167
|
-
|
|
1168
|
-
// ── Legend overlay position ──────────────────────────────────────────────────
|
|
1169
|
-
const legendStyle: CSSProperties = {
|
|
1170
|
-
position: "absolute",
|
|
1171
|
-
left: 16,
|
|
1172
|
-
right: 16,
|
|
1173
|
-
pointerEvents: "auto",
|
|
1174
|
-
...(legendSlot.verticalAlign === "top"
|
|
1175
|
-
? { top: 12 }
|
|
1176
|
-
: legendSlot.verticalAlign === "bottom"
|
|
1177
|
-
? { bottom: 12 }
|
|
1178
|
-
: { top: "50%", transform: "translateY(-50%)" }),
|
|
1179
|
-
};
|
|
1180
|
-
|
|
1181
|
-
return (
|
|
1182
|
-
<div
|
|
1183
|
-
ref={containerRef}
|
|
1184
|
-
data-chart={chartId}
|
|
1185
|
-
className={`relative flex flex-col text-xs ${className ?? ""}`}
|
|
1186
|
-
>
|
|
1187
|
-
<style dangerouslySetInnerHTML={{ __html: css }} />
|
|
1188
|
-
|
|
1189
|
-
<div className="relative min-h-0 w-full flex-1">
|
|
1190
|
-
{backgroundSlot.present && !isLoading && (
|
|
1191
|
-
<BackgroundLayer variant={backgroundSlot.variant} />
|
|
1192
|
-
)}
|
|
1193
|
-
<div ref={mountRef} className="relative h-full min-h-0 w-full" />
|
|
1194
|
-
</div>
|
|
1195
|
-
|
|
1196
|
-
{legendSlot.present && !isLoading && (
|
|
1197
|
-
<LegendOverlay
|
|
1198
|
-
seriesKeys={sectorKeys}
|
|
1199
|
-
config={config}
|
|
1200
|
-
variant={legendSlot.variant}
|
|
1201
|
-
align={legendSlot.align}
|
|
1202
|
-
verticalAlign={legendSlot.verticalAlign}
|
|
1203
|
-
selectedKey={selectedSector}
|
|
1204
|
-
hoveredKey={null}
|
|
1205
|
-
isClickable={legendSlot.isClickable}
|
|
1206
|
-
onToggle={(key) => selectSector(selectedSector === key ? null : key)}
|
|
1207
|
-
style={legendStyle}
|
|
1208
|
-
/>
|
|
1209
|
-
)}
|
|
1210
|
-
|
|
1211
|
-
{isLoading && (
|
|
1212
|
-
<div className="pointer-events-none absolute inset-0 z-20 flex items-center justify-center">
|
|
1213
|
-
<motion.div
|
|
1214
|
-
initial={shouldReduceMotion ? false : { opacity: 0, scale: 0.92 }}
|
|
1215
|
-
animate={{ opacity: 1, scale: 1 }}
|
|
1216
|
-
transition={{ duration: 0.25, ease: "easeOut" }}
|
|
1217
|
-
className="text-primary bg-background flex items-center justify-center gap-2 rounded-md border px-2 py-0.5 text-sm"
|
|
1218
|
-
>
|
|
1219
|
-
<div className="border-border border-t-primary h-3 w-3 animate-spin rounded-full border" />
|
|
1220
|
-
<span>Loading</span>
|
|
1221
|
-
</motion.div>
|
|
1222
|
-
</div>
|
|
1223
|
-
)}
|
|
1224
|
-
</div>
|
|
1225
|
-
);
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
// Compound API: every part hangs off the root as a static member, so a consumer
|
|
1229
|
-
// writes <EChartsPieChart.Pie/>, <EChartsPieChart.Tooltip/>, … from a single
|
|
1230
|
-
// import — no colliding named marker exports when several charts share one file.
|
|
1231
|
-
EChartsPieChart.Pie = Pie;
|
|
1232
|
-
EChartsPieChart.Label = Label;
|
|
1233
|
-
EChartsPieChart.Tooltip = Tooltip;
|
|
1234
|
-
EChartsPieChart.Legend = Legend;
|
|
1235
|
-
EChartsPieChart.Background = Background;
|