@justanarthur/modo-ui 0.5.0 → 0.6.0-canary.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/DESIGN.md +608 -0
- package/README.md +61 -39
- package/blocks/sidebar-app/examples.mdx +33 -0
- package/blocks/sidebar-app/index.tsx +218 -0
- package/blocks/sidebar-app/inset-topbar.tsx +25 -0
- package/blocks/sidebar-app/menu-grid.ts +26 -0
- package/blocks/sidebar-app/nav-data.ts +36 -0
- package/blocks/sidebar-app/search-field.tsx +48 -0
- package/blocks/sidebar-app/user-footer.tsx +67 -0
- package/blocks/sidebar-app/workspace-header.tsx +129 -0
- package/components/AI/input-message/examples.mdx +124 -0
- package/components/AI/input-message/file-thumbnail.tsx +173 -0
- package/components/AI/input-message/index.tsx +1383 -0
- package/components/AI/thinking-indicator/examples.mdx +27 -0
- package/components/AI/thinking-indicator/index.tsx +210 -0
- package/components/accordion/examples.mdx +148 -0
- package/components/accordion/index.tsx +1034 -0
- package/components/avatar/examples.mdx +95 -0
- package/components/avatar/index.tsx +129 -0
- package/components/badge/change-demo.tsx +29 -0
- package/components/badge/examples.mdx +120 -0
- package/components/badge/index.tsx +225 -0
- package/components/badge/variants.ts +73 -0
- package/components/button/examples.mdx +164 -0
- package/components/button/index.tsx +416 -0
- package/components/button/loading-demo.tsx +25 -0
- package/components/button/variants.ts +166 -0
- package/components/card/examples.mdx +212 -0
- package/components/card/index.tsx +1037 -0
- package/components/copy/examples.mdx +87 -0
- package/components/copy/index.tsx +482 -0
- package/components/inputs/checkbox/examples.mdx +83 -0
- package/components/inputs/checkbox/index.tsx +611 -0
- package/components/inputs/checkbox/select-all-demo.tsx +48 -0
- package/components/inputs/color-picker/examples.mdx +72 -0
- package/components/inputs/color-picker/index.tsx +1955 -0
- package/components/inputs/color-picker/variants.ts +401 -0
- package/components/inputs/combobox/examples.mdx +273 -0
- package/components/inputs/combobox/index.tsx +1436 -0
- package/components/inputs/combobox/remote-demo.tsx +101 -0
- package/components/inputs/date-time/calendar/examples.mdx +34 -0
- package/components/inputs/date-time/calendar/index.tsx +351 -0
- package/components/inputs/date-time/calendar/use-month-window.ts +163 -0
- package/components/inputs/date-time/date-picker/examples.mdx +166 -0
- package/components/inputs/date-time/date-picker/index.tsx +385 -0
- package/components/inputs/date-time/date-picker/masked-date-input.tsx +336 -0
- package/components/inputs/date-time/date-range-picker/examples.mdx +29 -0
- package/components/inputs/date-time/date-range-picker/index.tsx +217 -0
- package/components/inputs/date-time/duration-picker/examples.mdx +16 -0
- package/components/inputs/date-time/duration-picker/index.tsx +189 -0
- package/components/inputs/date-time/month-picker/examples.mdx +16 -0
- package/components/inputs/date-time/month-picker/index.tsx +190 -0
- package/components/inputs/date-time/picker-shell.tsx +395 -0
- package/components/inputs/date-time/time-columns.tsx +91 -0
- package/components/inputs/date-time/time-picker/examples.mdx +26 -0
- package/components/inputs/date-time/time-picker/index.tsx +166 -0
- package/components/inputs/field/examples.mdx +113 -0
- package/components/inputs/field/index.tsx +267 -0
- package/components/inputs/file-dropzone/examples.mdx +73 -0
- package/components/inputs/file-dropzone/file-row.tsx +201 -0
- package/components/inputs/file-dropzone/index.tsx +296 -0
- package/components/inputs/file-dropzone/upload-demo.tsx +67 -0
- package/components/inputs/file-dropzone/variants.ts +94 -0
- package/components/inputs/input/examples.mdx +135 -0
- package/components/inputs/input/index.tsx +494 -0
- package/components/inputs/input/password-demo.tsx +30 -0
- package/components/inputs/label/examples.mdx +67 -0
- package/components/inputs/label/index.tsx +85 -0
- package/components/inputs/number-input/examples.mdx +56 -0
- package/components/inputs/number-input/index.tsx +214 -0
- package/components/inputs/radio/examples.mdx +77 -0
- package/components/inputs/radio/index.tsx +636 -0
- package/components/inputs/search/examples.mdx +74 -0
- package/components/inputs/search/index.tsx +333 -0
- package/components/inputs/select/examples.mdx +218 -0
- package/components/inputs/select/index.tsx +862 -0
- package/components/inputs/select/variants.ts +32 -0
- package/components/inputs/slider/examples.mdx +127 -0
- package/components/inputs/slider/index.tsx +1725 -0
- package/components/inputs/switch/examples.mdx +94 -0
- package/components/inputs/switch/index.tsx +504 -0
- package/components/inputs/textarea/examples.mdx +88 -0
- package/components/inputs/textarea/index.tsx +161 -0
- package/components/navigation/navigation-menu/examples.mdx +109 -0
- package/components/navigation/navigation-menu/index.tsx +613 -0
- package/components/navigation/pagination/examples.mdx +64 -0
- package/components/navigation/pagination/index.tsx +395 -0
- package/components/navigation/sidebar/examples.mdx +319 -0
- package/components/navigation/sidebar/index.tsx +453 -0
- package/components/navigation/sidebar/sidebar-core.tsx +1408 -0
- package/components/navigation/sidebar/sidebar-menu.tsx +1495 -0
- package/components/navigation/sidebar/sidebar.css +74 -0
- package/components/navigation/sidebar/variants.ts +55 -0
- package/components/navigation/tabs/examples.mdx +89 -0
- package/components/navigation/tabs/index.tsx +494 -0
- package/components/navigation/tabs-subtle/examples.mdx +49 -0
- package/components/navigation/tabs-subtle/index.tsx +512 -0
- package/components/overlays/alert-dialog/examples.mdx +123 -0
- package/components/overlays/alert-dialog/index.tsx +258 -0
- package/components/overlays/alert-dialog/pending-demo.tsx +36 -0
- package/components/overlays/command/examples.mdx +113 -0
- package/components/overlays/command/index.tsx +416 -0
- package/components/overlays/context-menu/examples.mdx +56 -0
- package/components/overlays/context-menu/index.tsx +279 -0
- package/components/overlays/dialog/examples.mdx +144 -0
- package/components/overlays/dialog/index.tsx +366 -0
- package/components/overlays/dropdown/dropdown-search.tsx +395 -0
- package/components/overlays/dropdown/examples.mdx +294 -0
- package/components/overlays/dropdown/index.tsx +1168 -0
- package/components/overlays/dropdown/menu-item.tsx +464 -0
- package/components/overlays/dropdown/menu-parts.tsx +660 -0
- package/components/overlays/popover/anchored-demo.tsx +59 -0
- package/components/overlays/popover/examples.mdx +180 -0
- package/components/overlays/popover/index.tsx +315 -0
- package/components/overlays/preview-card/examples.mdx +61 -0
- package/components/overlays/preview-card/index.tsx +204 -0
- package/components/overlays/sheet/examples.mdx +89 -0
- package/components/overlays/sheet/index.tsx +247 -0
- package/components/overlays/toast/examples.mdx +68 -0
- package/components/overlays/toast/global-demo.tsx +72 -0
- package/components/overlays/toast/index.tsx +474 -0
- package/components/overlays/toast/manager.ts +193 -0
- package/components/overlays/tooltip/examples.mdx +106 -0
- package/components/overlays/tooltip/index.tsx +519 -0
- package/components/progress/examples.mdx +59 -0
- package/components/progress/index.tsx +174 -0
- package/components/progress/progress.css +49 -0
- package/components/progress/step-demo.tsx +27 -0
- package/components/table/examples.mdx +184 -0
- package/components/table/index.tsx +510 -0
- package/components/table/sort-demo.tsx +61 -0
- package/dist/base.css +100 -0
- package/dist/blocks/sidebar-app/index.js +39 -26
- package/dist/components/AI/input-message/index.js +22 -16
- package/dist/components/AI/thinking-indicator/index.js +9 -6
- package/dist/components/accordion/index.js +16 -13
- package/dist/components/avatar/index.d.ts +46 -0
- package/dist/components/avatar/index.js +18 -0
- package/dist/components/badge/index.d.ts +18 -11
- package/dist/components/badge/index.js +11 -7
- package/dist/components/badge/variants.d.ts +33 -0
- package/dist/components/badge/variants.js +10 -0
- package/dist/components/button/index.d.ts +53 -17
- package/dist/components/button/index.js +10 -6
- package/dist/components/button/variants.d.ts +39 -0
- package/dist/components/button/variants.js +8 -0
- package/dist/components/card/index.d.ts +16 -3
- package/dist/components/card/index.js +16 -11
- package/dist/components/copy/index.js +13 -9
- package/dist/components/inputs/checkbox/index.d.ts +28 -9
- package/dist/components/inputs/checkbox/index.js +17 -13
- package/dist/components/inputs/color-picker/index.d.ts +13 -13
- package/dist/components/inputs/color-picker/index.js +25 -18
- package/dist/components/inputs/color-picker/variants.d.ts +61 -0
- package/dist/components/inputs/color-picker/variants.js +28 -0
- package/dist/components/inputs/combobox/index.d.ts +60 -17
- package/dist/components/inputs/combobox/index.js +26 -18
- package/dist/components/inputs/date-time/calendar/index.js +14 -11
- package/dist/components/inputs/date-time/date-picker/index.d.ts +53 -11
- package/dist/components/inputs/date-time/date-picker/index.js +33 -25
- package/dist/components/inputs/date-time/date-range-picker/index.d.ts +3 -3
- package/dist/components/inputs/date-time/date-range-picker/index.js +32 -24
- package/dist/components/inputs/date-time/duration-picker/index.d.ts +3 -3
- package/dist/components/inputs/date-time/duration-picker/index.js +32 -24
- package/dist/components/inputs/date-time/month-picker/index.d.ts +3 -3
- package/dist/components/inputs/date-time/month-picker/index.js +31 -23
- package/dist/components/inputs/date-time/time-picker/index.d.ts +3 -3
- package/dist/components/inputs/date-time/time-picker/index.js +32 -24
- package/dist/components/inputs/field/index.d.ts +116 -0
- package/dist/components/inputs/field/index.js +28 -0
- package/dist/components/inputs/file-dropzone/index.d.ts +165 -0
- package/dist/components/inputs/file-dropzone/index.js +32 -0
- package/dist/components/inputs/file-dropzone/variants.d.ts +35 -0
- package/dist/components/inputs/file-dropzone/variants.js +12 -0
- package/dist/components/inputs/input/index.d.ts +95 -13
- package/dist/components/inputs/input/index.js +17 -9
- package/dist/components/inputs/label/index.d.ts +32 -0
- package/dist/components/inputs/label/index.js +11 -0
- package/dist/components/inputs/number-input/index.d.ts +84 -0
- package/dist/components/inputs/number-input/index.js +20 -0
- package/dist/components/inputs/radio/index.d.ts +20 -5
- package/dist/components/inputs/radio/index.js +15 -12
- package/dist/components/inputs/search/index.js +25 -18
- package/dist/components/inputs/select/index.d.ts +41 -11
- package/dist/components/inputs/select/index.js +27 -14
- package/dist/components/inputs/select/variants.d.ts +5 -0
- package/dist/components/inputs/select/variants.js +6 -0
- package/dist/components/inputs/slider/index.js +7 -5
- package/dist/components/inputs/switch/index.d.ts +8 -2
- package/dist/components/inputs/switch/index.js +14 -12
- package/dist/components/inputs/textarea/index.d.ts +4 -0
- package/dist/components/inputs/textarea/index.js +8 -6
- package/dist/components/navigation/navigation-menu/index.d.ts +114 -0
- package/dist/components/navigation/navigation-menu/index.js +40 -0
- package/dist/components/navigation/pagination/index.d.ts +73 -0
- package/dist/components/navigation/pagination/index.js +39 -0
- package/dist/components/navigation/sidebar/index.d.ts +44 -21
- package/dist/components/navigation/sidebar/index.js +41 -31
- package/dist/components/navigation/sidebar/variants.d.ts +25 -0
- package/dist/components/navigation/sidebar/variants.js +28 -0
- package/dist/components/navigation/tabs/index.d.ts +8 -2
- package/dist/components/navigation/tabs/index.js +14 -10
- package/dist/components/navigation/tabs-subtle/index.js +12 -10
- package/dist/components/overlays/alert-dialog/index.d.ts +121 -15
- package/dist/components/overlays/alert-dialog/index.js +22 -13
- package/dist/components/overlays/command/index.js +24 -17
- package/dist/components/overlays/context-menu/index.d.ts +33 -17
- package/dist/components/overlays/context-menu/index.js +27 -18
- package/dist/components/overlays/dialog/index.js +17 -12
- package/dist/components/overlays/dropdown/index.d.ts +257 -31
- package/dist/components/overlays/dropdown/index.js +42 -17
- package/dist/components/overlays/popover/index.d.ts +31 -9
- package/dist/components/overlays/popover/index.js +12 -9
- package/dist/components/overlays/preview-card/index.js +11 -8
- package/dist/components/overlays/sheet/index.js +18 -13
- package/dist/components/overlays/toast/index.d.ts +123 -47
- package/dist/components/overlays/toast/index.js +18 -10
- package/dist/components/overlays/tooltip/index.d.ts +113 -21
- package/dist/components/overlays/tooltip/index.js +15 -6
- package/dist/components/progress/index.d.ts +56 -0
- package/dist/components/progress/index.js +15 -0
- package/dist/components/table/index.d.ts +63 -8
- package/dist/components/table/index.js +19 -9
- package/dist/index.d.ts +2201 -736
- package/dist/index.js +223 -82
- package/dist/lib/date-locale.d.ts +14 -0
- package/dist/lib/date-locale.js +16 -0
- package/dist/lib/field-classes.d.ts +144 -0
- package/dist/lib/field-classes.js +40 -0
- package/dist/lib/field-variants.d.ts +47 -0
- package/dist/lib/field-variants.js +26 -0
- package/dist/lib/fluid-hover-highlight.d.ts +112 -0
- package/dist/lib/fluid-hover-highlight.js +17 -0
- package/dist/lib/focus-ring.d.ts +18 -0
- package/dist/lib/focus-ring.js +10 -0
- package/dist/lib/goo-indicator.d.ts +46 -0
- package/dist/lib/goo-indicator.js +14 -0
- package/dist/lib/icon-context.d.ts +30 -0
- package/dist/lib/icon-context.js +12 -0
- package/dist/lib/inert.d.ts +9 -0
- package/dist/lib/inert.js +8 -0
- package/dist/lib/morph-layers.d.ts +93 -0
- package/dist/lib/morph-layers.js +13 -0
- package/dist/lib/morph-part.d.ts +21 -0
- package/dist/lib/morph-part.js +12 -0
- package/dist/lib/popup.d.ts +20 -0
- package/dist/lib/popup.js +12 -0
- package/dist/lib/reduced-motion.d.ts +9 -0
- package/dist/lib/reduced-motion.js +6 -0
- package/dist/lib/row-index.d.ts +10 -0
- package/dist/lib/row-index.js +8 -0
- package/dist/lib/row-order.d.ts +28 -0
- package/dist/lib/row-order.js +10 -0
- package/dist/lib/scroll-column.d.ts +27 -0
- package/dist/lib/scroll-column.js +18 -0
- package/dist/lib/shape-context.d.ts +30 -0
- package/dist/lib/shape-context.js +12 -0
- package/dist/lib/size-context.d.ts +94 -0
- package/dist/lib/size-context.js +20 -0
- package/dist/lib/size-scale.d.ts +79 -0
- package/dist/lib/size-scale.js +8 -0
- package/dist/lib/slot.d.ts +12 -0
- package/dist/lib/slot.js +6 -0
- package/dist/lib/springs.d.ts +44 -0
- package/dist/lib/springs.js +8 -0
- package/dist/lib/surface-classes.d.ts +19 -0
- package/dist/lib/surface-classes.js +10 -0
- package/dist/lib/surface-context.d.ts +9 -0
- package/dist/lib/surface-context.js +8 -0
- package/dist/lib/use-controllable-state.d.ts +2 -0
- package/dist/lib/use-controllable-state.js +6 -0
- package/dist/lib/use-fluid-hover.d.ts +138 -0
- package/dist/lib/use-fluid-hover.js +14 -0
- package/dist/lib/use-is-mobile.d.ts +2 -0
- package/dist/lib/use-is-mobile.js +6 -0
- package/dist/lib/use-keyboard-nav-gate.d.ts +20 -0
- package/dist/lib/use-keyboard-nav-gate.js +7 -0
- package/dist/lib/use-merge-split.d.ts +47 -0
- package/dist/lib/use-merge-split.js +15 -0
- package/dist/lib/use-morph.d.ts +101 -0
- package/dist/lib/use-morph.js +20 -0
- package/dist/lib/use-touch-primary.d.ts +2 -0
- package/dist/lib/use-touch-primary.js +6 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.js +6 -0
- package/dist/preset.d.ts +17 -0
- package/dist/preset.js +22 -2
- package/dist/primitives/code/index.js +7 -5
- package/dist/primitives/craft/index.js +9 -6
- package/dist/primitives/fluid-hover/index.js +9 -8
- package/dist/primitives/morph/index.js +15 -10
- package/dist/primitives/motion/index.js +10 -8
- package/dist/primitives/scroll-area/index.js +4 -3
- package/dist/primitives/separator/index.d.ts +25 -0
- package/dist/primitives/separator/index.js +9 -0
- package/dist/primitives/sizes/index.js +6 -4
- package/dist/primitives/skeleton/index.d.ts +35 -0
- package/dist/primitives/skeleton/index.js +12 -0
- package/dist/primitives/surface/index.js +6 -4
- package/dist/shared/{components-3mkepka5.js → components-0jmqhx2k.js} +28 -25
- package/dist/shared/components-124epb7f.js +53 -0
- package/dist/shared/{components-gz8zf3ec.js → components-1k0wv53d.js} +15 -43
- package/dist/shared/components-26snnbs9.js +322 -0
- package/dist/shared/{components-2dxkv6zm.js → components-2c0qcfx4.js} +8 -7
- package/dist/shared/{components-473g814w.js → components-2mt9te6d.js} +243 -137
- package/dist/shared/{components-hawvy2qz.js → components-2z48g4fp.js} +9 -30
- package/dist/shared/components-34txk9rj.js +35 -0
- package/dist/shared/components-3h92d94m.js +23 -0
- package/dist/shared/{components-zfnmn5d4.js → components-3sp623ae.js} +36 -31
- package/dist/shared/{components-jwst3vtj.js → components-3wxkjgqn.js} +186 -76
- package/dist/shared/{components-s2bz1xpk.js → components-49bsynbw.js} +8 -5
- package/dist/shared/components-4bwsd46w.js +71 -0
- package/dist/shared/components-4n4f5m3e.js +297 -0
- package/dist/shared/{components-0q0sqfh4.js → components-4y816hwp.js} +27 -49
- package/dist/shared/components-52ngsgca.js +399 -0
- package/dist/shared/{components-y9y0g8er.js → components-52r5763g.js} +22 -19
- package/dist/shared/components-559tf7yb.js +28 -0
- package/dist/shared/components-5mkga9hj.js +440 -0
- package/dist/shared/{components-kwa6mrf9.js → components-5s0nfqvw.js} +14 -9
- package/dist/shared/{components-dk0gjr5a.js → components-60atskhp.js} +19 -18
- package/dist/shared/{components-rr7a6ja9.js → components-658b26nb.js} +21 -18
- package/dist/shared/{components-xxvdw7k1.js → components-65vwfjs6.js} +37 -34
- package/dist/shared/{components-frw34b65.js → components-6j2fh74k.js} +114 -123
- package/dist/shared/components-6zg1yft7.js +167 -0
- package/dist/shared/components-6zng858q.js +53 -0
- package/dist/shared/components-72w4ge68.js +64 -0
- package/dist/shared/{components-cv16mryv.js → components-78x40gee.js} +13 -7
- package/dist/shared/{components-b2wyq2cq.js → components-7d4r7hh1.js} +39 -57
- package/dist/shared/components-7ntvvegr.js +316 -0
- package/dist/shared/components-8nwsqjn8.js +34 -0
- package/dist/shared/{components-5xc2j8jz.js → components-8tt3xbb5.js} +19 -18
- package/dist/shared/{components-vc7vq5nz.js → components-9as3rf68.js} +6 -3
- package/dist/shared/components-9mys9jna.js +255 -0
- package/dist/shared/components-adkarj8n.js +35 -0
- package/dist/shared/{components-b3c5et5b.js → components-ae9fncz4.js} +32 -31
- package/dist/shared/{components-hqeq3w9q.js → components-awra5sff.js} +24 -16
- package/dist/shared/components-b1e239g3.js +28 -0
- package/dist/shared/{components-q5xj5c16.js → components-b1f2bjf1.js} +9 -8
- package/dist/shared/{components-qmmjx1qw.js → components-bn42vq6d.js} +71 -72
- package/dist/shared/components-c96g82th.js +1444 -0
- package/dist/shared/components-c9yr4ed1.js +44 -0
- package/dist/shared/components-d3shbwqq.js +95 -0
- package/dist/shared/{components-jjw69c4c.js → components-dcc02hs2.js} +7 -4
- package/dist/shared/{components-men63rwj.js → components-de99ykt7.js} +3 -2
- package/dist/shared/components-dhgk6mbt.js +16 -0
- package/dist/shared/components-drxrtnp2.js +25 -0
- package/dist/shared/{components-6p8tfcd6.js → components-ds9fqat9.js} +21 -18
- package/dist/shared/{components-mjthm1kf.js → components-egy4tyjt.js} +11 -8
- package/dist/shared/components-f0xfpkhh.js +82 -0
- package/dist/shared/components-f7h57m6t.js +59 -0
- package/dist/shared/{components-d6xtjht3.js → components-fjkpbg6n.js} +33 -30
- package/dist/shared/{components-gc5vtq2f.js → components-gh0qeey3.js} +63 -29
- package/dist/shared/{components-39jq9va1.js → components-gvbapfen.js} +29 -24
- package/dist/shared/{components-5vgpnxgy.js → components-gzesg7hy.js} +19 -16
- package/dist/shared/components-h6p86be3.js +19 -0
- package/dist/shared/components-h83az0bz.js +33 -0
- package/dist/shared/components-jjrj6ymn.js +104 -0
- package/dist/shared/{components-wvp1m52g.js → components-jp5v0m0f.js} +15 -14
- package/dist/shared/{components-zrkzcayz.js → components-jqpefjsn.js} +54 -6
- package/dist/shared/{components-1z6tdadk.js → components-k74j4hwh.js} +20 -17
- package/dist/shared/components-kswxnm3h.js +24 -0
- package/dist/shared/{components-jbbmdr74.js → components-mkkbbgb7.js} +36 -17
- package/dist/shared/{components-pbmqctfa.js → components-mpw667rb.js} +169 -65
- package/dist/shared/{components-s5ngg32c.js → components-paa08427.js} +121 -47
- package/dist/shared/{components-vfbhxf5r.js → components-pd42emw3.js} +6 -5
- package/dist/shared/{components-hw9yk32z.js → components-pmfszv7a.js} +35 -23
- package/dist/shared/{components-chacnk61.js → components-pw06rbxq.js} +19 -19
- package/dist/shared/components-q03cktx8.js +246 -0
- package/dist/shared/{components-kvr7f9hy.js → components-qdm3yh26.js} +19 -10
- package/dist/shared/{components-27nnvrwe.js → components-qs4rkqsj.js} +15 -14
- package/dist/shared/{components-s083f38z.js → components-r6gbmkew.js} +22 -21
- package/dist/shared/{components-ta7shw28.js → components-r8eqs7gz.js} +4 -4
- package/dist/shared/{components-sn1rxx1d.js → components-rm02h9nt.js} +12 -11
- package/dist/shared/{components-c6s6b43g.js → components-rrbpmfx4.js} +3 -2
- package/dist/shared/{components-n7mjr357.js → components-tz1fv35x.js} +3 -2
- package/dist/shared/components-tz4gaf1v.js +23 -0
- package/dist/shared/{components-zx6b6yby.js → components-vf45j12c.js} +4 -18
- package/dist/shared/{components-3ky44908.js → components-vfjc9jzz.js} +2 -3
- package/dist/shared/{components-39vmfq9s.js → components-vsa625vk.js} +21 -20
- package/dist/shared/components-wawnmkph.js +500 -0
- package/dist/shared/components-wktrrb4m.js +38 -0
- package/dist/shared/{components-8snj490h.js → components-wwd363me.js} +78 -32
- package/dist/shared/{components-5pnw8183.js → components-xcwvgcrd.js} +23 -22
- package/dist/shared/components-xdqmt6ed.js +20 -0
- package/dist/shared/{components-h2ajmhwn.js → components-y1w3a6wx.js} +107 -35
- package/dist/shared/{components-ar66gnt0.js → components-y6578b8h.js} +37 -34
- package/dist/shared/{components-59efxjd9.js → components-yhgq0qxx.js} +13 -12
- package/dist/shared/{components-jthe1pwb.js → components-yz84gpkq.js} +101 -404
- package/dist/shared/components-z3v0n0de.js +11 -0
- package/dist/shared/{components-7r3etddy.js → components-z9n19fyk.js} +19 -54
- package/dist/shared/components-zbvjzh1p.js +141 -0
- package/dist/styles.css +241 -16
- package/dist/tailwind.css +13 -0
- package/dist/tokens.css +34 -0
- package/index.ts +60 -0
- package/lib/date-locale.ts +50 -0
- package/lib/field-classes.ts +115 -0
- package/lib/field-variants.ts +117 -0
- package/lib/fluid-hover-highlight.tsx +139 -0
- package/lib/focus-ring.tsx +46 -0
- package/lib/goo-indicator.tsx +261 -0
- package/lib/icon-context.tsx +310 -0
- package/lib/inert.ts +22 -0
- package/lib/morph-layers.tsx +102 -0
- package/lib/morph-part.tsx +49 -0
- package/lib/popup.ts +52 -0
- package/lib/reduced-motion.ts +19 -0
- package/lib/row-index.tsx +29 -0
- package/lib/row-order.tsx +115 -0
- package/lib/scroll-column.tsx +244 -0
- package/lib/shape-context.tsx +124 -0
- package/lib/size-context.tsx +66 -0
- package/lib/size-scale.ts +115 -0
- package/lib/slot.ts +25 -0
- package/lib/springs.ts +62 -0
- package/lib/surface-classes.ts +58 -0
- package/lib/surface-context.tsx +21 -0
- package/lib/use-controllable-state.ts +44 -0
- package/lib/use-fluid-hover.ts +541 -0
- package/lib/use-is-mobile.ts +25 -0
- package/lib/use-keyboard-nav-gate.ts +45 -0
- package/lib/use-merge-split.tsx +209 -0
- package/lib/use-morph.ts +557 -0
- package/lib/use-touch-primary.tsx +43 -0
- package/lib/utils.ts +37 -0
- package/package.json +177 -4
- package/preset.ts +196 -0
- package/primitives/code/examples.mdx +27 -0
- package/primitives/code/index.tsx +80 -0
- package/primitives/craft/demos.tsx +173 -0
- package/primitives/craft/examples.mdx +138 -0
- package/primitives/craft/index.tsx +76 -0
- package/primitives/fluid-hover/examples.mdx +84 -0
- package/primitives/fluid-hover/index.tsx +316 -0
- package/primitives/morph/examples.mdx +135 -0
- package/primitives/morph/index.tsx +192 -0
- package/primitives/motion/examples.mdx +100 -0
- package/primitives/motion/index.tsx +160 -0
- package/primitives/scroll-area/examples.mdx +58 -0
- package/primitives/scroll-area/index.tsx +200 -0
- package/primitives/separator/examples.mdx +30 -0
- package/primitives/separator/index.tsx +53 -0
- package/primitives/sizes/examples.mdx +167 -0
- package/primitives/sizes/index.tsx +89 -0
- package/primitives/skeleton/examples.mdx +51 -0
- package/primitives/skeleton/index.tsx +72 -0
- package/primitives/skeleton/skeleton.css +15 -0
- package/primitives/surface/examples.mdx +173 -0
- package/primitives/surface/index.tsx +109 -0
- package/primitives/surface/surface.css +176 -0
- package/dist/shared/components-0sn7ypjw.js +0 -61
- package/dist/shared/components-1434p1mh.js +0 -123
- package/dist/shared/components-a86dytt0.js +0 -986
- package/dist/shared/components-gf5s6ap9.js +0 -42
- package/dist/shared/components-hyq23phv.js +0 -310
- package/dist/shared/components-ng72k97e.js +0 -128
- package/dist/shared/components-raknhppb.js +0 -64
- package/dist/shared/components-vynjtrk6.js +0 -19
- package/dist/shared/components-wy9jpqny.js +0 -146
- /package/dist/shared/{components-1v7rxytx.js → components-3ey0hzpb.js} +0 -0
- /package/dist/shared/{components-ezxhrmer.js → components-jcnjay5g.js} +0 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Local addition (not part of Fluid Functionalism): the liquid indicator, the
|
|
3
|
+
* morph style for everything that travels between items: a tab's active pill,
|
|
4
|
+
* a switch thumb, the fluid hover highlight and merged selection backgrounds.
|
|
5
|
+
* When the indicator leaves a rect it leaves a blob behind. The blob lingers
|
|
6
|
+
* for a third of the spring, then follows to the back of the new rect,
|
|
7
|
+
* shrinking, while the indicator springs on: the goo melts the two into one
|
|
8
|
+
* stretched drop that lets go, or, on a long move, a drop and a droplet that
|
|
9
|
+
* catches up. The filter runs only while a blob is alive; at rest nothing is
|
|
10
|
+
* filtered.
|
|
11
|
+
*
|
|
12
|
+
* The goo is the morph engine's (`GOO_MATRIX` and `GOO_BLUR_RATIO` in
|
|
13
|
+
* `lib/use-morph.ts`, after beUI's gooey popover and Sileo, notices
|
|
14
|
+
* LICENSE.beui and LICENSE.sileo). `GooFilter` lays the source over the
|
|
15
|
+
* thresholded blur, which only works for opaque fills: `bg-hover` and
|
|
16
|
+
* `bg-active` are a few percent alpha, under the threshold. `GooLayer`
|
|
17
|
+
* thresholds the shapes' coverage instead and fills the result with their own
|
|
18
|
+
* token, read from their fill class, so translucent and opaque fills melt
|
|
19
|
+
* alike.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { animate, motion, type Transition, useMotionValue, type ValueAnimationTransition } from 'motion/react'
|
|
23
|
+
import { type ReactNode, useId, useLayoutEffect, useRef, useState } from 'react'
|
|
24
|
+
import { useReduceMotion } from './reduced-motion'
|
|
25
|
+
import { spring } from './springs'
|
|
26
|
+
import type { ItemRect } from './use-fluid-hover'
|
|
27
|
+
import { GOO_BLUR_RATIO, GOO_MATRIX } from './use-morph'
|
|
28
|
+
import { cn } from './utils'
|
|
29
|
+
|
|
30
|
+
// Any coverage counts as solid before the blur, so a 4%-alpha fill melts like an opaque one.
|
|
31
|
+
const COVERAGE = '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0'
|
|
32
|
+
// The share of its cross size a retracting blob keeps: it thins into a neck instead of a point.
|
|
33
|
+
const NECK = 0.5
|
|
34
|
+
|
|
35
|
+
function union(a: ItemRect | null, b: ItemRect): ItemRect {
|
|
36
|
+
if (!a) return b
|
|
37
|
+
const left = Math.min(a.left, b.left)
|
|
38
|
+
const top = Math.min(a.top, b.top)
|
|
39
|
+
return {
|
|
40
|
+
left,
|
|
41
|
+
top,
|
|
42
|
+
width: Math.max(a.left + a.width, b.left + b.width) - left,
|
|
43
|
+
height: Math.max(a.top + a.height, b.top + b.height) - top,
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function pad(rect: ItemRect, by: number): ItemRect {
|
|
48
|
+
return { left: rect.left - by, top: rect.top - by, width: rect.width + by * 2, height: rect.height + by * 2 }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function center(rect: ItemRect) {
|
|
52
|
+
return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** A move worth a blob: the center travels more than half the indicator's size, not a resize in place. */
|
|
56
|
+
function travels(from: ItemRect, to: ItemRect) {
|
|
57
|
+
const a = center(from)
|
|
58
|
+
const b = center(to)
|
|
59
|
+
return (
|
|
60
|
+
Math.abs(b.x - a.x) > Math.min(from.width, to.width) / 2 ||
|
|
61
|
+
Math.abs(b.y - a.y) > Math.min(from.height, to.height) / 2
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Where the blob left at `from` goes: the back edge of `to` on each axis that
|
|
67
|
+
* moved, so it follows the indicator and is absorbed, and a neck on the other.
|
|
68
|
+
*/
|
|
69
|
+
function retract(from: ItemRect, to: ItemRect): ItemRect {
|
|
70
|
+
const axis = (start: number, size: number, toStart: number, toSize: number) => {
|
|
71
|
+
const delta = toStart + toSize / 2 - (start + size / 2)
|
|
72
|
+
if (Math.abs(delta) < 1) return [start + (size * (1 - NECK)) / 2, size * NECK] as const
|
|
73
|
+
return [delta > 0 ? toStart : toStart + toSize, 0] as const
|
|
74
|
+
}
|
|
75
|
+
const [left, width] = axis(from.left, from.width, to.left, to.width)
|
|
76
|
+
const [top, height] = axis(from.top, from.height, to.top, to.height)
|
|
77
|
+
return { left, top, width, height }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function toTarget(rect: ItemRect) {
|
|
81
|
+
return { x: rect.left, y: rect.top, width: rect.width, height: rect.height }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function blurOf(el: Element, rect: ItemRect) {
|
|
85
|
+
const r = Number.parseFloat(getComputedStyle(el).borderTopLeftRadius) || 0
|
|
86
|
+
return Math.min(r, rect.width / 2, rect.height / 2) * GOO_BLUR_RATIO
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface GooLayerProps {
|
|
90
|
+
/** Filter on: the shapes melt into one. Off at rest. */
|
|
91
|
+
active: boolean
|
|
92
|
+
/** Blur in px: the shapes' radius times `GOO_BLUR_RATIO`. */
|
|
93
|
+
blur: number
|
|
94
|
+
/** The layer's box in the container's coordinates, covering every shape; padded for the blur here. */
|
|
95
|
+
box: ItemRect | null
|
|
96
|
+
/** The shapes' classes (a bg token, a radius): the melted result is filled with their background. */
|
|
97
|
+
fill: string
|
|
98
|
+
/** The shapes, positioned in the container's coordinates. */
|
|
99
|
+
children?: ReactNode
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** A box of shapes that melt into one while `active`. The filter's region follows the box, so keep it tight. */
|
|
103
|
+
export function GooLayer({ active, blur, box, fill, children }: GooLayerProps) {
|
|
104
|
+
const id = `goo-${useId().replace(/:/g, '')}`
|
|
105
|
+
const flood = useRef<SVGFEFloodElement>(null)
|
|
106
|
+
const probe = useRef<HTMLDivElement>(null)
|
|
107
|
+
const layer = box ? pad(box, blur * 3) : { left: 0, top: 0, width: 0, height: 0 }
|
|
108
|
+
|
|
109
|
+
// Resolved each time the goo starts, so it follows the scheme.
|
|
110
|
+
useLayoutEffect(() => {
|
|
111
|
+
if (!active || !probe.current) return
|
|
112
|
+
flood.current?.setAttribute('flood-color', getComputedStyle(probe.current).backgroundColor)
|
|
113
|
+
}, [active])
|
|
114
|
+
|
|
115
|
+
return (
|
|
116
|
+
<>
|
|
117
|
+
<svg aria-hidden className="absolute size-0">
|
|
118
|
+
<filter id={id} x="-50%" y="-50%" width="200%" height="200%" colorInterpolationFilters="sRGB">
|
|
119
|
+
<feColorMatrix in="SourceGraphic" values={COVERAGE} result="coverage" />
|
|
120
|
+
<feGaussianBlur in="coverage" stdDeviation={blur} result="blur" />
|
|
121
|
+
<feColorMatrix in="blur" values={GOO_MATRIX} result="goo" />
|
|
122
|
+
<feFlood ref={flood} />
|
|
123
|
+
<feComposite in2="goo" operator="in" />
|
|
124
|
+
</filter>
|
|
125
|
+
</svg>
|
|
126
|
+
<div
|
|
127
|
+
aria-hidden
|
|
128
|
+
className="pointer-events-none absolute"
|
|
129
|
+
// Geometry is the shapes' own; the filter is the effect itself, melting their token fill.
|
|
130
|
+
style={{ ...layer, filter: active ? `url(#${id})` : undefined }}
|
|
131
|
+
>
|
|
132
|
+
{/* Zero-sized, so it paints nothing: it carries the fill token for the flood and maps the shapes back to the container's coordinates. */}
|
|
133
|
+
<div ref={probe} className={cn(fill, 'absolute')} style={{ left: -layer.left, top: -layer.top }}>
|
|
134
|
+
{children}
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
</>
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
interface Trail {
|
|
142
|
+
id: number
|
|
143
|
+
from: ItemRect
|
|
144
|
+
to: ItemRect
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
interface GooIndicatorProps {
|
|
148
|
+
/** The rect to sit on, in the container's coordinates (as `useFluidHover` measures them). */
|
|
149
|
+
rect: ItemRect
|
|
150
|
+
/** Where it first appears; it then travels to `rect`. Defaults to `rect`. */
|
|
151
|
+
from?: ItemRect | null
|
|
152
|
+
/** Fill and radius classes: a bg token and the shape's radius. */
|
|
153
|
+
className?: string
|
|
154
|
+
/** Shadow class. While it melts, the shapes are drawn again beneath the goo with it, since the filter flattens shadows. */
|
|
155
|
+
shadow?: string
|
|
156
|
+
/** The travel: a spring tier. `false` snaps (a reflow, reduced motion). Defaults to `spring.moderate`. */
|
|
157
|
+
transition?: Transition | false
|
|
158
|
+
/** Opacity of the whole indicator, faded on `spring.fast`. Defaults to `1`. */
|
|
159
|
+
opacity?: number
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* An indicator that travels between items with a liquid neck. Render it in the
|
|
164
|
+
* items' `relative` container, beneath them: the items' text stays above it,
|
|
165
|
+
* unfiltered.
|
|
166
|
+
*/
|
|
167
|
+
export function GooIndicator({
|
|
168
|
+
rect,
|
|
169
|
+
from,
|
|
170
|
+
className,
|
|
171
|
+
shadow,
|
|
172
|
+
transition = spring.moderate,
|
|
173
|
+
opacity = 1,
|
|
174
|
+
}: GooIndicatorProps) {
|
|
175
|
+
const reduced = useReduceMotion()
|
|
176
|
+
const start = from ?? rect
|
|
177
|
+
const x = useMotionValue(start.left)
|
|
178
|
+
const y = useMotionValue(start.top)
|
|
179
|
+
const width = useMotionValue(start.width)
|
|
180
|
+
const height = useMotionValue(start.height)
|
|
181
|
+
const lead = useRef<HTMLDivElement>(null)
|
|
182
|
+
const [trails, setTrails] = useState<Trail[]>([])
|
|
183
|
+
const [blur, setBlur] = useState(0)
|
|
184
|
+
const ids = useRef(0)
|
|
185
|
+
const travel = transition === false || reduced ? false : transition
|
|
186
|
+
const travelRef = useRef(travel)
|
|
187
|
+
travelRef.current = travel
|
|
188
|
+
const read = () => ({ left: x.get(), top: y.get(), width: width.get(), height: height.get() })
|
|
189
|
+
|
|
190
|
+
// Only a new rect moves it: the transition is often an inline object.
|
|
191
|
+
useLayoutEffect(() => {
|
|
192
|
+
const move = travelRef.current as ValueAnimationTransition<number> | false
|
|
193
|
+
const current = read()
|
|
194
|
+
if (!move) {
|
|
195
|
+
x.jump(rect.left)
|
|
196
|
+
y.jump(rect.top)
|
|
197
|
+
width.jump(rect.width)
|
|
198
|
+
height.jump(rect.height)
|
|
199
|
+
return
|
|
200
|
+
}
|
|
201
|
+
const goo = lead.current && travels(current, rect) ? blurOf(lead.current, current) : 0
|
|
202
|
+
// Square shapes have no radius to melt with.
|
|
203
|
+
if (goo >= 1) {
|
|
204
|
+
setBlur(goo)
|
|
205
|
+
setTrails(list => [...list, { id: ++ids.current, from: current, to: retract(current, rect) }])
|
|
206
|
+
}
|
|
207
|
+
animate(x, rect.left, move)
|
|
208
|
+
animate(y, rect.top, move)
|
|
209
|
+
animate(width, rect.width, move)
|
|
210
|
+
animate(height, rect.height, move)
|
|
211
|
+
}, [rect.left, rect.top, rect.width, rect.height])
|
|
212
|
+
|
|
213
|
+
const melting = trails.length > 0
|
|
214
|
+
const linger = travel ? { ...travel, delay: (travel.duration ?? 0) / 3 } : undefined
|
|
215
|
+
const shape = cn('pointer-events-none absolute top-0 left-0', className)
|
|
216
|
+
const box = trails.reduce<ItemRect>((all, trail) => union(all, trail.from), union(read(), rect))
|
|
217
|
+
const drop = (trail: Trail) => setTrails(list => list.filter(t => t.id !== trail.id))
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
<motion.div
|
|
221
|
+
aria-hidden
|
|
222
|
+
className="pointer-events-none absolute top-0 left-0"
|
|
223
|
+
initial={false}
|
|
224
|
+
animate={{ opacity }}
|
|
225
|
+
transition={{ duration: spring.fast.duration }}
|
|
226
|
+
>
|
|
227
|
+
{shadow && (
|
|
228
|
+
<>
|
|
229
|
+
{/* Fading as it shrinks: the goo lets a sliver vanish, a crisp shadow would not. */}
|
|
230
|
+
{trails.map(trail => (
|
|
231
|
+
<motion.div
|
|
232
|
+
key={trail.id}
|
|
233
|
+
className={cn(shape, shadow)}
|
|
234
|
+
initial={{ ...toTarget(trail.from), opacity: 1 }}
|
|
235
|
+
animate={{ ...toTarget(trail.to), opacity: 0 }}
|
|
236
|
+
transition={linger}
|
|
237
|
+
/>
|
|
238
|
+
))}
|
|
239
|
+
<motion.div className={cn(shape, shadow, !melting && 'invisible')} style={{ x, y, width, height }} />
|
|
240
|
+
</>
|
|
241
|
+
)}
|
|
242
|
+
<GooLayer active={melting} blur={blur} box={box} fill={className ?? ''}>
|
|
243
|
+
{trails.map(trail => (
|
|
244
|
+
<motion.div
|
|
245
|
+
key={trail.id}
|
|
246
|
+
className={shape}
|
|
247
|
+
initial={toTarget(trail.from)}
|
|
248
|
+
animate={toTarget(trail.to)}
|
|
249
|
+
transition={linger}
|
|
250
|
+
onAnimationComplete={() => drop(trail)}
|
|
251
|
+
/>
|
|
252
|
+
))}
|
|
253
|
+
{/* At rest it wears its own shadow; melting, a shadow would count as coverage and swell the goo. */}
|
|
254
|
+
<motion.div ref={lead} className={cn(shape, !melting && shadow)} style={{ x, y, width, height }} />
|
|
255
|
+
</GooLayer>
|
|
256
|
+
</motion.div>
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export type { GooIndicatorProps, GooLayerProps }
|
|
261
|
+
export { union }
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Vendored from Fluid Functionalism — `registry/default/lib/icon-context.tsx` at
|
|
3
|
+
* github.com/mickadesign/fluid-functionalism@b3587bdbd83fc66c2a6aae3817ffb856cb09260b
|
|
4
|
+
* (fluidfunctionalism.com). MIT License © 2026 Micka Touillaud — see
|
|
5
|
+
* LICENSE.fluid-functionalism in this package.
|
|
6
|
+
*
|
|
7
|
+
* Local modifications:
|
|
8
|
+
* - `"use client"` directive dropped (no RSC here).
|
|
9
|
+
* - lucide-react v1 + React 18 types: `IconComponentProps.size` /
|
|
10
|
+
* `strokeWidth` widened to `number | string` (lucide icons' propTypes
|
|
11
|
+
* accept both, and @types/react 18 compares propTypes).
|
|
12
|
+
* - `panel-left-dashed` / `panel-right-dashed`: the sidebar trigger's glyph
|
|
13
|
+
* while the sidebar opens on hover.
|
|
14
|
+
* - Names for the @utegsk/ui layer (pagination, sorting, status, password
|
|
15
|
+
* reveal, file dropzone, indeterminate): `chevron-left`, `chevron-up`, `chevrons-left`, `chevrons-right`, `arrow-up-down`, `circle-alert`, `triangle-alert`, `circle-check`, `info`, `circle-question-mark`, `trash`, `eye`, `eye-off`, `timer`, `arrow-right-from-line`, `arrow-right-to-line`, `funnel-x`, `flag`, `loader-circle`, `minus`, `upload`, `file`.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
ArrowDown,
|
|
20
|
+
ArrowLeft,
|
|
21
|
+
ArrowRight,
|
|
22
|
+
ArrowRightFromLine,
|
|
23
|
+
ArrowRightToLine,
|
|
24
|
+
ArrowUp,
|
|
25
|
+
ArrowUpDown,
|
|
26
|
+
Bell,
|
|
27
|
+
Brain,
|
|
28
|
+
Calendar,
|
|
29
|
+
Check,
|
|
30
|
+
ChevronDown,
|
|
31
|
+
ChevronLeft,
|
|
32
|
+
ChevronRight,
|
|
33
|
+
ChevronsLeft,
|
|
34
|
+
ChevronsRight,
|
|
35
|
+
ChevronsUpDown,
|
|
36
|
+
ChevronUp,
|
|
37
|
+
Circle,
|
|
38
|
+
CircleAlert,
|
|
39
|
+
CircleCheck,
|
|
40
|
+
CircleQuestionMark,
|
|
41
|
+
Clock,
|
|
42
|
+
Copy,
|
|
43
|
+
CornerDownLeft,
|
|
44
|
+
CornerDownRight,
|
|
45
|
+
Dot,
|
|
46
|
+
Ellipsis,
|
|
47
|
+
EllipsisVertical,
|
|
48
|
+
Eye,
|
|
49
|
+
EyeOff,
|
|
50
|
+
File,
|
|
51
|
+
Flag,
|
|
52
|
+
Folder,
|
|
53
|
+
FunnelX,
|
|
54
|
+
Globe,
|
|
55
|
+
Heart,
|
|
56
|
+
Home,
|
|
57
|
+
ImageIcon,
|
|
58
|
+
Inbox,
|
|
59
|
+
Info,
|
|
60
|
+
Lightbulb,
|
|
61
|
+
Link,
|
|
62
|
+
Loader,
|
|
63
|
+
LoaderCircle,
|
|
64
|
+
Lock,
|
|
65
|
+
Mail,
|
|
66
|
+
Menu,
|
|
67
|
+
MessageCircle,
|
|
68
|
+
Minus,
|
|
69
|
+
Monitor,
|
|
70
|
+
Moon,
|
|
71
|
+
Paintbrush,
|
|
72
|
+
Palette,
|
|
73
|
+
PanelLeft,
|
|
74
|
+
PanelLeftDashed,
|
|
75
|
+
PanelRight,
|
|
76
|
+
PanelRightDashed,
|
|
77
|
+
Pause,
|
|
78
|
+
Pencil,
|
|
79
|
+
Pipette,
|
|
80
|
+
Play,
|
|
81
|
+
Plus,
|
|
82
|
+
RectangleHorizontal,
|
|
83
|
+
Rocket,
|
|
84
|
+
RotateCcw,
|
|
85
|
+
Scaling,
|
|
86
|
+
Search,
|
|
87
|
+
Settings,
|
|
88
|
+
Shield,
|
|
89
|
+
SkipForward,
|
|
90
|
+
SlidersHorizontal,
|
|
91
|
+
SquareLibrary,
|
|
92
|
+
Star,
|
|
93
|
+
Sun,
|
|
94
|
+
Timer,
|
|
95
|
+
Trash2,
|
|
96
|
+
TriangleAlert,
|
|
97
|
+
Upload,
|
|
98
|
+
User,
|
|
99
|
+
Users,
|
|
100
|
+
X,
|
|
101
|
+
} from 'lucide-react'
|
|
102
|
+
import { type ComponentType, createContext, type ReactNode, useContext, useMemo } from 'react'
|
|
103
|
+
|
|
104
|
+
export interface IconComponentProps {
|
|
105
|
+
size?: number | string
|
|
106
|
+
strokeWidth?: number | string
|
|
107
|
+
className?: string
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export type IconComponent = ComponentType<IconComponentProps>
|
|
111
|
+
|
|
112
|
+
export type IconName =
|
|
113
|
+
| 'chevron-right'
|
|
114
|
+
| 'chevron-down'
|
|
115
|
+
| 'x'
|
|
116
|
+
| 'copy'
|
|
117
|
+
| 'menu'
|
|
118
|
+
| 'dot'
|
|
119
|
+
| 'monitor'
|
|
120
|
+
| 'sun'
|
|
121
|
+
| 'moon'
|
|
122
|
+
| 'rectangle-horizontal'
|
|
123
|
+
| 'circle'
|
|
124
|
+
| 'square-library'
|
|
125
|
+
| 'clock'
|
|
126
|
+
| 'star'
|
|
127
|
+
| 'settings'
|
|
128
|
+
| 'plus'
|
|
129
|
+
| 'arrow-left'
|
|
130
|
+
| 'arrow-right'
|
|
131
|
+
| 'arrow-up'
|
|
132
|
+
| 'arrow-down'
|
|
133
|
+
| 'search'
|
|
134
|
+
| 'loader'
|
|
135
|
+
| 'users'
|
|
136
|
+
| 'lock'
|
|
137
|
+
| 'mail'
|
|
138
|
+
| 'bell'
|
|
139
|
+
| 'shield'
|
|
140
|
+
| 'palette'
|
|
141
|
+
| 'lightbulb'
|
|
142
|
+
| 'rocket'
|
|
143
|
+
| 'heart'
|
|
144
|
+
| 'paintbrush'
|
|
145
|
+
| 'brain'
|
|
146
|
+
| 'globe'
|
|
147
|
+
| 'user'
|
|
148
|
+
| 'image'
|
|
149
|
+
| 'link'
|
|
150
|
+
| 'check'
|
|
151
|
+
| 'rotate-ccw'
|
|
152
|
+
| 'play'
|
|
153
|
+
| 'pause'
|
|
154
|
+
| 'pipette'
|
|
155
|
+
| 'home'
|
|
156
|
+
| 'message-circle'
|
|
157
|
+
| 'inbox'
|
|
158
|
+
| 'pencil'
|
|
159
|
+
| 'scaling'
|
|
160
|
+
| 'skip-forward'
|
|
161
|
+
| 'corner-down-right'
|
|
162
|
+
| 'corner-down-left'
|
|
163
|
+
| 'panel-left'
|
|
164
|
+
| 'panel-left-dashed'
|
|
165
|
+
| 'panel-right'
|
|
166
|
+
| 'panel-right-dashed'
|
|
167
|
+
| 'chevrons-up-down'
|
|
168
|
+
| 'more-horizontal'
|
|
169
|
+
| 'more-vertical'
|
|
170
|
+
| 'calendar'
|
|
171
|
+
| 'folder'
|
|
172
|
+
| 'sliders-horizontal'
|
|
173
|
+
| 'chevron-left'
|
|
174
|
+
| 'chevron-up'
|
|
175
|
+
| 'chevrons-left'
|
|
176
|
+
| 'chevrons-right'
|
|
177
|
+
| 'arrow-up-down'
|
|
178
|
+
| 'circle-alert'
|
|
179
|
+
| 'triangle-alert'
|
|
180
|
+
| 'circle-check'
|
|
181
|
+
| 'info'
|
|
182
|
+
| 'circle-question-mark'
|
|
183
|
+
| 'trash'
|
|
184
|
+
| 'eye'
|
|
185
|
+
| 'eye-off'
|
|
186
|
+
| 'timer'
|
|
187
|
+
| 'arrow-right-from-line'
|
|
188
|
+
| 'arrow-right-to-line'
|
|
189
|
+
| 'funnel-x'
|
|
190
|
+
| 'flag'
|
|
191
|
+
| 'loader-circle'
|
|
192
|
+
| 'minus'
|
|
193
|
+
| 'upload'
|
|
194
|
+
| 'file'
|
|
195
|
+
|
|
196
|
+
export const defaultIcons: Record<IconName, IconComponent> = {
|
|
197
|
+
'chevron-left': ChevronLeft,
|
|
198
|
+
'chevron-up': ChevronUp,
|
|
199
|
+
'chevrons-left': ChevronsLeft,
|
|
200
|
+
'chevrons-right': ChevronsRight,
|
|
201
|
+
'arrow-up-down': ArrowUpDown,
|
|
202
|
+
'circle-alert': CircleAlert,
|
|
203
|
+
'triangle-alert': TriangleAlert,
|
|
204
|
+
'circle-check': CircleCheck,
|
|
205
|
+
info: Info,
|
|
206
|
+
'circle-question-mark': CircleQuestionMark,
|
|
207
|
+
trash: Trash2,
|
|
208
|
+
eye: Eye,
|
|
209
|
+
'eye-off': EyeOff,
|
|
210
|
+
timer: Timer,
|
|
211
|
+
'arrow-right-from-line': ArrowRightFromLine,
|
|
212
|
+
'arrow-right-to-line': ArrowRightToLine,
|
|
213
|
+
'funnel-x': FunnelX,
|
|
214
|
+
flag: Flag,
|
|
215
|
+
'loader-circle': LoaderCircle,
|
|
216
|
+
minus: Minus,
|
|
217
|
+
upload: Upload,
|
|
218
|
+
file: File,
|
|
219
|
+
'chevron-right': ChevronRight,
|
|
220
|
+
'chevron-down': ChevronDown,
|
|
221
|
+
pipette: Pipette,
|
|
222
|
+
x: X,
|
|
223
|
+
copy: Copy,
|
|
224
|
+
menu: Menu,
|
|
225
|
+
dot: Dot,
|
|
226
|
+
monitor: Monitor,
|
|
227
|
+
sun: Sun,
|
|
228
|
+
moon: Moon,
|
|
229
|
+
'rectangle-horizontal': RectangleHorizontal,
|
|
230
|
+
circle: Circle,
|
|
231
|
+
'square-library': SquareLibrary,
|
|
232
|
+
clock: Clock,
|
|
233
|
+
star: Star,
|
|
234
|
+
settings: Settings,
|
|
235
|
+
plus: Plus,
|
|
236
|
+
'arrow-left': ArrowLeft,
|
|
237
|
+
'arrow-right': ArrowRight,
|
|
238
|
+
'arrow-up': ArrowUp,
|
|
239
|
+
'arrow-down': ArrowDown,
|
|
240
|
+
search: Search,
|
|
241
|
+
loader: Loader,
|
|
242
|
+
users: Users,
|
|
243
|
+
lock: Lock,
|
|
244
|
+
mail: Mail,
|
|
245
|
+
bell: Bell,
|
|
246
|
+
shield: Shield,
|
|
247
|
+
palette: Palette,
|
|
248
|
+
lightbulb: Lightbulb,
|
|
249
|
+
rocket: Rocket,
|
|
250
|
+
heart: Heart,
|
|
251
|
+
paintbrush: Paintbrush,
|
|
252
|
+
brain: Brain,
|
|
253
|
+
globe: Globe,
|
|
254
|
+
user: User,
|
|
255
|
+
image: ImageIcon,
|
|
256
|
+
link: Link,
|
|
257
|
+
check: Check,
|
|
258
|
+
'rotate-ccw': RotateCcw,
|
|
259
|
+
play: Play,
|
|
260
|
+
pause: Pause,
|
|
261
|
+
home: Home,
|
|
262
|
+
'message-circle': MessageCircle,
|
|
263
|
+
inbox: Inbox,
|
|
264
|
+
pencil: Pencil,
|
|
265
|
+
scaling: Scaling,
|
|
266
|
+
'skip-forward': SkipForward,
|
|
267
|
+
'corner-down-right': CornerDownRight,
|
|
268
|
+
'corner-down-left': CornerDownLeft,
|
|
269
|
+
'panel-left': PanelLeft,
|
|
270
|
+
'panel-left-dashed': PanelLeftDashed,
|
|
271
|
+
'panel-right': PanelRight,
|
|
272
|
+
'panel-right-dashed': PanelRightDashed,
|
|
273
|
+
'chevrons-up-down': ChevronsUpDown,
|
|
274
|
+
'more-horizontal': Ellipsis,
|
|
275
|
+
'more-vertical': EllipsisVertical,
|
|
276
|
+
calendar: Calendar,
|
|
277
|
+
folder: Folder,
|
|
278
|
+
'sliders-horizontal': SlidersHorizontal,
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const IconContext = createContext<Record<IconName, IconComponent> | null>(null)
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Returns a single icon component for the given name.
|
|
285
|
+
* Falls back to the default (Lucide) set if no provider is present.
|
|
286
|
+
*/
|
|
287
|
+
function useIcon(name: IconName): IconComponent {
|
|
288
|
+
const icons = useContext(IconContext)
|
|
289
|
+
return (icons ?? defaultIcons)[name]
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Returns the full icon map.
|
|
294
|
+
* Falls back to the default (Lucide) set if no provider is present.
|
|
295
|
+
*/
|
|
296
|
+
function useIcons(): Record<IconName, IconComponent> {
|
|
297
|
+
const icons = useContext(IconContext)
|
|
298
|
+
return icons ?? defaultIcons
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Swap some or all icons for components from another library.
|
|
303
|
+
* Names left out of `icons` keep their default (Lucide) component.
|
|
304
|
+
*/
|
|
305
|
+
function IconProvider({ children, icons }: { children: ReactNode; icons?: Partial<Record<IconName, IconComponent>> }) {
|
|
306
|
+
const value = useMemo(() => ({ ...defaultIcons, ...icons }), [icons])
|
|
307
|
+
return <IconContext.Provider value={value}>{children}</IconContext.Provider>
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export { IconProvider, useIcon, useIcons }
|
package/lib/inert.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Local addition (not part of Fluid Functionalism): `inert` that holds on
|
|
3
|
+
* React 18 and 19. React 18 has no `inert` prop and passes it through as an
|
|
4
|
+
* unknown attribute, so it needs a string (`''`); React 19 reads it as a
|
|
5
|
+
* boolean prop and drops `''`. `inertProps` picks the value per React major;
|
|
6
|
+
* `markInert` sets the attribute from a ref, outside React, for an element
|
|
7
|
+
* that is always inert.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { version } from 'react'
|
|
11
|
+
|
|
12
|
+
const INERT = (Number.parseInt(version, 10) >= 19 ? true : '') as unknown as boolean
|
|
13
|
+
|
|
14
|
+
/** Spread onto an element to make it inert while `on`. */
|
|
15
|
+
export function inertProps(on: boolean) {
|
|
16
|
+
return on ? { inert: INERT } : {}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** A ref callback that makes its element inert for good. */
|
|
20
|
+
export function markInert(el: HTMLElement | null) {
|
|
21
|
+
el?.setAttribute('inert', '')
|
|
22
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Local addition (not part of Fluid Functionalism): the one renderer behind
|
|
3
|
+
* every morphing overlay, driven by `lib/use-morph.ts`. It goes inside the
|
|
4
|
+
* Base UI popup, which stays transparent and at its final size:
|
|
5
|
+
*
|
|
6
|
+
* - shapes: while goo or morph runs, the growing surface, cut around the
|
|
7
|
+
* source so the source stays visible. For goo, an SVG goo filter melts it
|
|
8
|
+
* with a copy of the source into one shape with a liquid neck. The filter
|
|
9
|
+
* (blur, alpha threshold, composite on top) is beUI's gooey popover
|
|
10
|
+
* (github.com/starc007/ui-components `components/motion/popover.tsx` @
|
|
11
|
+
* de52f337e520e7ee37749b36eb1c32df86137bcb — MIT © 2026 Saurabh Chauhan,
|
|
12
|
+
* notice: LICENSE.beui), the same one Sileo's toast uses
|
|
13
|
+
* (github.com/hiaaryan/sileo `src/sileo.tsx` @
|
|
14
|
+
* 9793f844349983e140cf33cebbb8f51626d41407 — MIT, notice: LICENSE.sileo).
|
|
15
|
+
* - surface: the background and, above it, the shadow (so a dark scheme's
|
|
16
|
+
* inset highlight lands on top, as on one `Elevated` element). Two layers
|
|
17
|
+
* so the shadow can fade in while the goo neck is still attached.
|
|
18
|
+
* - content: in normal flow at its final place, revealed by a clip from the
|
|
19
|
+
* same rect.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { ReactNode, Ref } from 'react'
|
|
23
|
+
import { MorphPartInOverlay } from './morph-part'
|
|
24
|
+
import { GOO_MATRIX, type Morph } from './use-morph'
|
|
25
|
+
import { cn } from './utils'
|
|
26
|
+
|
|
27
|
+
interface MorphSurfaceProps {
|
|
28
|
+
/** The engine, from `useMorph`. */
|
|
29
|
+
morph: Morph
|
|
30
|
+
/** Background class of the surface: `SURFACE_BG[level]`, or `bg-foreground` for an inverted tooltip. */
|
|
31
|
+
bg?: string
|
|
32
|
+
/** Shadow class (`SURFACE_SHADOW[level]`); leave out for a flat surface. */
|
|
33
|
+
shadow?: string
|
|
34
|
+
/** Radius class the surface rests at (the shape context's `container`, `bg`, …). */
|
|
35
|
+
radius: string
|
|
36
|
+
/** Classes for the content wrapper: padding, width. */
|
|
37
|
+
className?: string
|
|
38
|
+
/** The overlay's content. */
|
|
39
|
+
children?: ReactNode
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface GooFilterProps {
|
|
43
|
+
id: string
|
|
44
|
+
/** Blur radius; leave out when `blurRef` sets it per morph. */
|
|
45
|
+
blur?: number
|
|
46
|
+
blurRef?: Ref<SVGFEGaussianBlurElement>
|
|
47
|
+
/** Outlines the melted shape with the surface shadow's 1px ring (`--shadow-color`), so a surface the color of the page still shows its neck; the ref's `flood-opacity` fades it. */
|
|
48
|
+
outlineRef?: Ref<SVGFEFloodElement>
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The goo filter: blur, threshold the alpha back into solid shapes, then lay the crisp original on top. */
|
|
52
|
+
export function GooFilter({ id, blur, blurRef, outlineRef }: GooFilterProps) {
|
|
53
|
+
return (
|
|
54
|
+
<svg aria-hidden className="absolute size-0">
|
|
55
|
+
<filter id={id} x="-50%" y="-50%" width="200%" height="200%" colorInterpolationFilters="sRGB">
|
|
56
|
+
<feGaussianBlur ref={blurRef} in="SourceGraphic" stdDeviation={blur} result="blur" />
|
|
57
|
+
<feColorMatrix in="blur" mode="matrix" values={GOO_MATRIX} result="goo" />
|
|
58
|
+
<feComposite in="SourceGraphic" in2="goo" operator="atop" result="body" />
|
|
59
|
+
{outlineRef && (
|
|
60
|
+
<>
|
|
61
|
+
<feMorphology in="goo" operator="dilate" radius={1} result="grown" />
|
|
62
|
+
<feFlood ref={outlineRef} className="[flood-color:var(--shadow-color)]" />
|
|
63
|
+
<feComposite in2="grown" operator="in" result="outline" />
|
|
64
|
+
<feMerge>
|
|
65
|
+
<feMergeNode in="outline" />
|
|
66
|
+
<feMergeNode in="body" />
|
|
67
|
+
</feMerge>
|
|
68
|
+
</>
|
|
69
|
+
)}
|
|
70
|
+
</filter>
|
|
71
|
+
</svg>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function MorphSurface({ morph, bg, shadow, radius, className, children }: MorphSurfaceProps) {
|
|
76
|
+
const { refs, gooId, effect } = morph
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<>
|
|
80
|
+
{effect === 'goo' && <GooFilter id={gooId} blurRef={refs.blur} outlineRef={refs.outline} />}
|
|
81
|
+
{(effect === 'goo' || effect === 'morph') && (
|
|
82
|
+
// The filter is the effect itself, not a visual value: it melts the shapes' own token background.
|
|
83
|
+
<div
|
|
84
|
+
ref={refs.shapes}
|
|
85
|
+
aria-hidden
|
|
86
|
+
className="pointer-events-none absolute hidden"
|
|
87
|
+
style={effect === 'goo' ? { filter: `url(#${gooId})` } : undefined}
|
|
88
|
+
>
|
|
89
|
+
{effect === 'goo' && <div ref={refs.copy} className={cn('absolute', bg)} />}
|
|
90
|
+
<div ref={refs.shape} className={cn('absolute', bg)} />
|
|
91
|
+
</div>
|
|
92
|
+
)}
|
|
93
|
+
<div ref={refs.bg} aria-hidden className={cn('pointer-events-none absolute inset-0', bg, radius)} />
|
|
94
|
+
{shadow && (
|
|
95
|
+
<div ref={refs.shadow} aria-hidden className={cn('pointer-events-none absolute inset-0', shadow, radius)} />
|
|
96
|
+
)}
|
|
97
|
+
<div ref={refs.content} className={cn('relative', className)}>
|
|
98
|
+
<MorphPartInOverlay.Provider value={true}>{children}</MorphPartInOverlay.Provider>
|
|
99
|
+
</div>
|
|
100
|
+
</>
|
|
101
|
+
)
|
|
102
|
+
}
|