@remix-run/ui 0.2.0 → 0.4.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 +50 -164
- package/dist/accordion/index.d.ts +46 -0
- package/dist/accordion/index.js +142 -0
- package/dist/accordion/index.js.map +1 -0
- package/dist/accordion/primitives.d.ts +104 -0
- package/dist/accordion/primitives.js +312 -0
- package/dist/accordion/primitives.js.map +1 -0
- package/dist/{components/anchor/anchor.d.ts → anchor/index.d.ts} +8 -1
- package/dist/{components/anchor/anchor.js → anchor/index.js} +31 -12
- package/dist/anchor/index.js.map +1 -0
- package/dist/animation/demos/aspect-ratio.d.ts +2 -0
- package/dist/animation/demos/aspect-ratio.js +69 -0
- package/dist/animation/demos/aspect-ratio.js.map +1 -0
- package/dist/animation/demos/bouncy-switch.d.ts +2 -0
- package/dist/animation/demos/bouncy-switch.js +36 -0
- package/dist/animation/demos/bouncy-switch.js.map +1 -0
- package/dist/animation/demos/color-interpolation.d.ts +1 -0
- package/dist/animation/demos/color-interpolation.js +53 -0
- package/dist/animation/demos/color-interpolation.js.map +1 -0
- package/dist/animation/demos/cube.d.ts +2 -0
- package/dist/animation/demos/cube.js +86 -0
- package/dist/animation/demos/cube.js.map +1 -0
- package/dist/animation/demos/default-animate.d.ts +2 -0
- package/dist/animation/demos/default-animate.js +89 -0
- package/dist/animation/demos/default-animate.js.map +1 -0
- package/dist/animation/demos/drag-release.d.ts +24 -0
- package/dist/animation/demos/drag-release.js +96 -0
- package/dist/animation/demos/drag-release.js.map +1 -0
- package/dist/animation/demos/enter.d.ts +1 -0
- package/dist/animation/demos/enter.js +19 -0
- package/dist/animation/demos/enter.js.map +1 -0
- package/dist/animation/demos/exit.d.ts +2 -0
- package/dist/animation/demos/exit.js +58 -0
- package/dist/animation/demos/exit.js.map +1 -0
- package/dist/animation/demos/flip-toggle.d.ts +2 -0
- package/dist/animation/demos/flip-toggle.js +37 -0
- package/dist/animation/demos/flip-toggle.js.map +1 -0
- package/dist/animation/demos/hold-to-confirm.d.ts +13 -0
- package/dist/animation/demos/hold-to-confirm.js +211 -0
- package/dist/animation/demos/hold-to-confirm.js.map +1 -0
- package/dist/animation/demos/html-content.d.ts +2 -0
- package/dist/animation/demos/html-content.js +30 -0
- package/dist/animation/demos/html-content.js.map +1 -0
- package/dist/animation/demos/interruptible-keyframes.d.ts +1 -0
- package/dist/animation/demos/interruptible-keyframes.js +48 -0
- package/dist/animation/demos/interruptible-keyframes.js.map +1 -0
- package/dist/animation/demos/keyframes.d.ts +1 -0
- package/dist/animation/demos/keyframes.js +24 -0
- package/dist/animation/demos/keyframes.js.map +1 -0
- package/dist/animation/demos/material-ripple.d.ts +2 -0
- package/dist/animation/demos/material-ripple.js +127 -0
- package/dist/animation/demos/material-ripple.js.map +1 -0
- package/dist/animation/demos/mixin-presence-list.d.ts +2 -0
- package/dist/animation/demos/mixin-presence-list.js +88 -0
- package/dist/animation/demos/mixin-presence-list.js.map +1 -0
- package/dist/animation/demos/mixin-reclaim.d.ts +2 -0
- package/dist/animation/demos/mixin-reclaim.js +90 -0
- package/dist/animation/demos/mixin-reclaim.js.map +1 -0
- package/dist/animation/demos/multi-state-badge.d.ts +2 -0
- package/dist/animation/demos/multi-state-badge.js +231 -0
- package/dist/animation/demos/multi-state-badge.js.map +1 -0
- package/dist/animation/demos/press.d.ts +2 -0
- package/dist/animation/demos/press.js +63 -0
- package/dist/animation/demos/press.js.map +1 -0
- package/dist/animation/demos/reordering.d.ts +2 -0
- package/dist/animation/demos/reordering.js +53 -0
- package/dist/animation/demos/reordering.js.map +1 -0
- package/dist/animation/demos/rolling-square.d.ts +2 -0
- package/dist/animation/demos/rolling-square.js +42 -0
- package/dist/animation/demos/rolling-square.js.map +1 -0
- package/dist/animation/demos/rotate.d.ts +1 -0
- package/dist/animation/demos/rotate.js +18 -0
- package/dist/animation/demos/rotate.js.map +1 -0
- package/dist/animation/demos/shared-layout.d.ts +2 -0
- package/dist/animation/demos/shared-layout.js +114 -0
- package/dist/animation/demos/shared-layout.js.map +1 -0
- package/dist/animation/demos/transition-options.d.ts +1 -0
- package/dist/animation/demos/transition-options.js +21 -0
- package/dist/animation/demos/transition-options.js.map +1 -0
- package/dist/animation/spring.d.ts +22 -0
- package/dist/animation/spring.js +22 -0
- package/dist/animation/spring.js.map +1 -1
- package/dist/{components/breadcrumbs/breadcrumbs.js → breadcrumbs/index.js} +19 -19
- package/dist/breadcrumbs/index.js.map +1 -0
- package/dist/button/index.d.ts +15 -0
- package/dist/button/index.js +128 -0
- package/dist/button/index.js.map +1 -0
- package/dist/checkbox/index.d.ts +14 -0
- package/dist/checkbox/index.js +125 -0
- package/dist/checkbox/index.js.map +1 -0
- package/dist/combobox/index.d.ts +21 -0
- package/dist/combobox/index.js +58 -0
- package/dist/combobox/index.js.map +1 -0
- package/dist/{components/combobox/combobox.d.ts → combobox/primitives.d.ts} +3 -7
- package/dist/{components/combobox/combobox.js → combobox/primitives.js} +8 -61
- package/dist/combobox/primitives.js.map +1 -0
- package/dist/input/index.d.ts +13 -0
- package/dist/input/index.js +121 -0
- package/dist/input/index.js.map +1 -0
- package/dist/listbox/flash-attribute.js.map +1 -0
- package/dist/{components/listbox/listbox.d.ts → listbox/index.d.ts} +2 -6
- package/dist/{components/listbox/listbox.js → listbox/index.js} +4 -82
- package/dist/listbox/index.js.map +1 -0
- package/dist/menu/hover-aim.js.map +1 -0
- package/dist/menu/index.d.ts +42 -0
- package/dist/menu/index.js +250 -0
- package/dist/menu/index.js.map +1 -0
- package/dist/{components/menu/menu.d.ts → menu/primitives.d.ts} +6 -32
- package/dist/{components/menu/menu.js → menu/primitives.js} +117 -279
- package/dist/menu/primitives.js.map +1 -0
- package/dist/{components/popover/popover.d.ts → popover/index.d.ts} +3 -5
- package/dist/{components/popover/popover.js → popover/index.js} +15 -51
- package/dist/popover/index.js.map +1 -0
- package/dist/{interactions/outside-click/outside-click-mixin.js → popover/outside-click.js} +1 -1
- package/dist/popover/outside-click.js.map +1 -0
- package/dist/popover/scroll-lock.d.ts +1 -0
- package/dist/{utils → popover}/scroll-lock.js +0 -18
- package/dist/popover/scroll-lock.js.map +1 -0
- package/dist/radio/index.d.ts +12 -0
- package/dist/radio/index.js +77 -0
- package/dist/radio/index.js.map +1 -0
- package/dist/runtime/client-entries.d.ts +1 -2
- package/dist/runtime/client-entries.js.map +1 -1
- package/dist/runtime/component.d.ts +2 -2
- package/dist/runtime/component.js +1 -1
- package/dist/runtime/component.js.map +1 -1
- package/dist/runtime/diff-dom.js +194 -21
- package/dist/runtime/diff-dom.js.map +1 -1
- package/dist/runtime/frame.d.ts +7 -0
- package/dist/runtime/frame.js +176 -41
- package/dist/runtime/frame.js.map +1 -1
- package/dist/runtime/jsx.d.ts +2 -3
- package/dist/runtime/jsx.js.map +1 -1
- package/dist/runtime/reconcile.js +11 -5
- package/dist/runtime/reconcile.js.map +1 -1
- package/dist/runtime/vdom.js +3 -0
- package/dist/runtime/vdom.js.map +1 -1
- package/dist/select/index.d.ts +19 -0
- package/dist/select/index.js +95 -0
- package/dist/select/index.js.map +1 -0
- package/dist/select/keydown.js.map +1 -0
- package/dist/{components/select/select.d.ts → select/primitives.d.ts} +4 -6
- package/dist/{components/select/select.js → select/primitives.js} +12 -64
- package/dist/select/primitives.js.map +1 -0
- package/dist/server/stream.js +5 -4
- package/dist/server/stream.js.map +1 -1
- package/dist/shared/focus-styles.d.ts +1 -0
- package/dist/shared/focus-styles.js +2 -0
- package/dist/shared/focus-styles.js.map +1 -0
- package/dist/shared/icons.d.ts +9 -0
- package/dist/shared/icons.js +42 -0
- package/dist/shared/icons.js.map +1 -0
- package/dist/shared/listbox-popover-styles.d.ts +6 -0
- package/dist/shared/listbox-popover-styles.js +137 -0
- package/dist/shared/listbox-popover-styles.js.map +1 -0
- package/dist/shared/style-values.d.ts +78 -0
- package/dist/{theme/presets/rmx-01/index.js → shared/style-values.js} +3 -34
- package/dist/shared/style-values.js.map +1 -0
- package/dist/{interactions/typeahead/typeahead-mixin.js → shared/typeahead.js} +1 -1
- package/dist/shared/typeahead.js.map +1 -0
- package/dist/shared/wait-for-css-transition.js.map +1 -0
- package/dist/shared/wait.js.map +1 -0
- package/dist/style/style.js +27 -10
- package/dist/style/style.js.map +1 -1
- package/dist/tabs/index.d.ts +32 -0
- package/dist/tabs/index.js +157 -0
- package/dist/tabs/index.js.map +1 -0
- package/dist/tabs/primitives.d.ts +57 -0
- package/dist/tabs/primitives.js +238 -0
- package/dist/tabs/primitives.js.map +1 -0
- package/dist/toggle/index.d.ts +9 -0
- package/dist/toggle/index.js +108 -0
- package/dist/toggle/index.js.map +1 -0
- package/dist/toggle/primitives.d.ts +29 -0
- package/dist/toggle/primitives.js +127 -0
- package/dist/toggle/primitives.js.map +1 -0
- package/package.json +74 -45
- package/src/{components/accordion → accordion}/README.md +50 -14
- package/src/accordion/index.tsx +285 -0
- package/src/accordion/primitives.tsx +512 -0
- package/src/{components/anchor → anchor}/README.md +48 -5
- package/src/{components/anchor/anchor.ts → anchor/index.ts} +53 -12
- package/src/animation/demos/aspect-ratio.tsx +120 -0
- package/src/animation/demos/bouncy-switch.tsx +47 -0
- package/src/animation/demos/color-interpolation.tsx +73 -0
- package/src/animation/demos/cube.tsx +116 -0
- package/src/animation/demos/default-animate.tsx +129 -0
- package/src/animation/demos/drag-release.ts +118 -0
- package/src/animation/demos/enter.tsx +22 -0
- package/src/animation/demos/exit.tsx +79 -0
- package/src/animation/demos/flip-toggle.tsx +46 -0
- package/src/animation/demos/hold-to-confirm.tsx +317 -0
- package/src/animation/demos/html-content.tsx +41 -0
- package/src/animation/demos/interruptible-keyframes.tsx +62 -0
- package/src/animation/demos/keyframes.tsx +29 -0
- package/src/animation/demos/material-ripple.tsx +158 -0
- package/src/animation/demos/mixin-presence-list.tsx +121 -0
- package/src/animation/demos/mixin-reclaim.tsx +125 -0
- package/src/animation/demos/multi-state-badge.tsx +426 -0
- package/src/animation/demos/press.tsx +67 -0
- package/src/animation/demos/reordering.tsx +68 -0
- package/src/animation/demos/rolling-square.tsx +57 -0
- package/src/animation/demos/rotate.tsx +21 -0
- package/src/animation/demos/shared-layout.tsx +211 -0
- package/src/animation/demos/transition-options.tsx +24 -0
- package/src/animation/spring.ts +22 -0
- package/src/{components/breadcrumbs → breadcrumbs}/README.md +4 -4
- package/src/{components/breadcrumbs/breadcrumbs.tsx → breadcrumbs/index.tsx} +18 -18
- package/src/button/README.md +44 -0
- package/src/button/index.ts +168 -0
- package/src/checkbox/README.md +59 -0
- package/src/checkbox/index.ts +162 -0
- package/src/{components/combobox → combobox}/README.md +58 -9
- package/src/combobox/index.tsx +112 -0
- package/src/{components/combobox/combobox.tsx → combobox/primitives.tsx} +5 -91
- package/src/input/README.md +52 -0
- package/src/input/index.ts +147 -0
- package/src/{components/listbox → listbox}/README.md +9 -41
- package/src/{components/listbox/listbox.ts → listbox/index.ts} +2 -87
- package/src/menu/README.md +161 -0
- package/src/menu/index.tsx +354 -0
- package/src/{components/menu/menu.tsx → menu/primitives.tsx} +117 -359
- package/src/{components/popover → popover}/README.md +20 -39
- package/src/{components/popover/popover.ts → popover/index.ts} +16 -61
- package/src/{utils → popover}/scroll-lock.ts +0 -28
- package/src/radio/README.md +53 -0
- package/src/radio/index.ts +100 -0
- package/src/runtime/client-entries.ts +1 -5
- package/src/runtime/component.ts +3 -3
- package/src/runtime/demos/readme.demo.tsx +704 -0
- package/src/runtime/diff-dom.ts +270 -20
- package/src/runtime/frame.ts +218 -41
- package/src/runtime/jsx.ts +6 -10
- package/src/runtime/reconcile.ts +11 -5
- package/src/runtime/vdom.ts +3 -0
- package/src/{components/select → select}/README.md +29 -19
- package/src/select/index.tsx +159 -0
- package/src/{components/select/select.tsx → select/primitives.tsx} +11 -99
- package/src/server/stream.ts +10 -5
- package/src/shared/focus-styles.ts +2 -0
- package/src/shared/icons.tsx +62 -0
- package/src/shared/listbox-popover-styles.ts +146 -0
- package/src/shared/style-values.ts +165 -0
- package/src/style/style.ts +29 -10
- package/src/tabs/README.md +141 -0
- package/src/tabs/index.tsx +244 -0
- package/src/tabs/primitives.ts +365 -0
- package/src/toggle/README.md +56 -0
- package/src/toggle/index.tsx +134 -0
- package/src/toggle/primitives.ts +192 -0
- package/dist/components/accordion/accordion.d.ts +0 -92
- package/dist/components/accordion/accordion.js +0 -335
- package/dist/components/accordion/accordion.js.map +0 -1
- package/dist/components/accordion/demos/card.demo.d.ts +0 -6
- package/dist/components/accordion/demos/card.demo.js +0 -58
- package/dist/components/accordion/demos/card.demo.js.map +0 -1
- package/dist/components/accordion/demos/multiple.demo.d.ts +0 -6
- package/dist/components/accordion/demos/multiple.demo.js +0 -19
- package/dist/components/accordion/demos/multiple.demo.js.map +0 -1
- package/dist/components/accordion/demos/overview.demo.d.ts +0 -6
- package/dist/components/accordion/demos/overview.demo.js +0 -19
- package/dist/components/accordion/demos/overview.demo.js.map +0 -1
- package/dist/components/anchor/anchor.js.map +0 -1
- package/dist/components/breadcrumbs/breadcrumbs.js.map +0 -1
- package/dist/components/breadcrumbs/demos/basic.demo.d.ts +0 -5
- package/dist/components/breadcrumbs/demos/basic.demo.js +0 -14
- package/dist/components/breadcrumbs/demos/basic.demo.js.map +0 -1
- package/dist/components/breadcrumbs/demos/separator.demo.d.ts +0 -5
- package/dist/components/breadcrumbs/demos/separator.demo.js +0 -14
- package/dist/components/breadcrumbs/demos/separator.demo.js.map +0 -1
- package/dist/components/button/button.d.ts +0 -105
- package/dist/components/button/button.js +0 -207
- package/dist/components/button/button.js.map +0 -1
- package/dist/components/button/demos/aliases.demo.d.ts +0 -6
- package/dist/components/button/demos/aliases.demo.js +0 -18
- package/dist/components/button/demos/aliases.demo.js.map +0 -1
- package/dist/components/button/demos/basic.demo.d.ts +0 -6
- package/dist/components/button/demos/basic.demo.js +0 -19
- package/dist/components/button/demos/basic.demo.js.map +0 -1
- package/dist/components/button/demos/states.demo.d.ts +0 -6
- package/dist/components/button/demos/states.demo.js +0 -29
- package/dist/components/button/demos/states.demo.js.map +0 -1
- package/dist/components/combobox/combobox.js.map +0 -1
- package/dist/components/combobox/demos/overview.demo.d.ts +0 -6
- package/dist/components/combobox/demos/overview.demo.js +0 -153
- package/dist/components/combobox/demos/overview.demo.js.map +0 -1
- package/dist/components/glyph/glyph.d.ts +0 -14
- package/dist/components/glyph/glyph.js +0 -65
- package/dist/components/glyph/glyph.js.map +0 -1
- package/dist/components/listbox/demos/overview.demo.d.ts +0 -6
- package/dist/components/listbox/demos/overview.demo.js +0 -64
- package/dist/components/listbox/demos/overview.demo.js.map +0 -1
- package/dist/components/listbox/listbox.js.map +0 -1
- package/dist/components/menu/demos/bubbling.demo.d.ts +0 -5
- package/dist/components/menu/demos/bubbling.demo.js +0 -15
- package/dist/components/menu/demos/bubbling.demo.js.map +0 -1
- package/dist/components/menu/demos/overview.demo.d.ts +0 -6
- package/dist/components/menu/demos/overview.demo.js +0 -32
- package/dist/components/menu/demos/overview.demo.js.map +0 -1
- package/dist/components/menu/hover-aim.js.map +0 -1
- package/dist/components/menu/menu.js.map +0 -1
- package/dist/components/popover/demos/overview.demo.d.ts +0 -6
- package/dist/components/popover/demos/overview.demo.js +0 -64
- package/dist/components/popover/demos/overview.demo.js.map +0 -1
- package/dist/components/popover/popover.js.map +0 -1
- package/dist/components/select/demos/deconstructed.demo.d.ts +0 -6
- package/dist/components/select/demos/deconstructed.demo.js +0 -53
- package/dist/components/select/demos/deconstructed.demo.js.map +0 -1
- package/dist/components/select/demos/overview.demo.d.ts +0 -5
- package/dist/components/select/demos/overview.demo.js +0 -27
- package/dist/components/select/demos/overview.demo.js.map +0 -1
- package/dist/components/select/select.js.map +0 -1
- package/dist/components/separator/separator.d.ts +0 -2
- package/dist/components/separator/separator.js +0 -15
- package/dist/components/separator/separator.js.map +0 -1
- package/dist/components/tabs/tabs.d.ts +0 -78
- package/dist/components/tabs/tabs.js +0 -339
- package/dist/components/tabs/tabs.js.map +0 -1
- package/dist/interactions/keydown/keydown.js.map +0 -1
- package/dist/interactions/outside-click/outside-click-mixin.js.map +0 -1
- package/dist/interactions/typeahead/typeahead-mixin.js.map +0 -1
- package/dist/theme/contract.d.ts +0 -61
- package/dist/theme/contract.js +0 -131
- package/dist/theme/contract.js.map +0 -1
- package/dist/theme/glyph-contract.d.ts +0 -11
- package/dist/theme/glyph-contract.js +0 -34
- package/dist/theme/glyph-contract.js.map +0 -1
- package/dist/theme/presets/rmx-01/glyphs.d.ts +0 -2
- package/dist/theme/presets/rmx-01/glyphs.js +0 -252
- package/dist/theme/presets/rmx-01/glyphs.js.map +0 -1
- package/dist/theme/presets/rmx-01/index.d.ts +0 -4
- package/dist/theme/presets/rmx-01/index.js.map +0 -1
- package/dist/theme/runtime.d.ts +0 -2
- package/dist/theme/runtime.js +0 -84
- package/dist/theme/runtime.js.map +0 -1
- package/dist/theme/theme.d.ts +0 -6
- package/dist/theme/theme.js +0 -5
- package/dist/theme/theme.js.map +0 -1
- package/dist/utils/flash-attribute.js.map +0 -1
- package/dist/utils/scroll-lock.d.ts +0 -3
- package/dist/utils/scroll-lock.js.map +0 -1
- package/dist/utils/wait-for-css-transition.js.map +0 -1
- package/dist/utils/wait.js.map +0 -1
- package/src/components/accordion/accordion.tsx +0 -565
- package/src/components/accordion/demos/card.demo.tsx +0 -113
- package/src/components/accordion/demos/multiple.demo.tsx +0 -56
- package/src/components/accordion/demos/overview.demo.tsx +0 -56
- package/src/components/breadcrumbs/demos/basic.demo.tsx +0 -17
- package/src/components/breadcrumbs/demos/separator.demo.tsx +0 -18
- package/src/components/button/README.md +0 -44
- package/src/components/button/button.tsx +0 -286
- package/src/components/button/demos/aliases.demo.tsx +0 -27
- package/src/components/button/demos/basic.demo.tsx +0 -30
- package/src/components/button/demos/states.demo.tsx +0 -52
- package/src/components/combobox/demos/overview.demo.tsx +0 -199
- package/src/components/glyph/README.md +0 -72
- package/src/components/glyph/glyph.tsx +0 -110
- package/src/components/listbox/demos/overview.demo.tsx +0 -101
- package/src/components/menu/README.md +0 -96
- package/src/components/menu/demos/bubbling.demo.tsx +0 -34
- package/src/components/menu/demos/overview.demo.tsx +0 -76
- package/src/components/popover/demos/overview.demo.tsx +0 -143
- package/src/components/select/demos/deconstructed.demo.tsx +0 -95
- package/src/components/select/demos/overview.demo.tsx +0 -51
- package/src/components/separator/separator.ts +0 -19
- package/src/components/tabs/README.md +0 -105
- package/src/components/tabs/tabs.tsx +0 -504
- package/src/theme/README.md +0 -103
- package/src/theme/contract.ts +0 -215
- package/src/theme/glyph-contract.ts +0 -59
- package/src/theme/presets/rmx-01/glyphs.tsx +0 -308
- package/src/theme/presets/rmx-01/index.ts +0 -123
- package/src/theme/runtime.ts +0 -119
- package/src/theme/theme.ts +0 -15
- package/src/utils/scroll-lock/README.md +0 -33
- /package/dist/{components/breadcrumbs/breadcrumbs.d.ts → breadcrumbs/index.d.ts} +0 -0
- /package/dist/{utils → listbox}/flash-attribute.d.ts +0 -0
- /package/dist/{utils → listbox}/flash-attribute.js +0 -0
- /package/dist/{components/menu → menu}/hover-aim.d.ts +0 -0
- /package/dist/{components/menu → menu}/hover-aim.js +0 -0
- /package/dist/{interactions/outside-click/outside-click-mixin.d.ts → popover/outside-click.d.ts} +0 -0
- /package/dist/{interactions/keydown → select}/keydown.d.ts +0 -0
- /package/dist/{interactions/keydown → select}/keydown.js +0 -0
- /package/dist/{interactions/typeahead/typeahead-mixin.d.ts → shared/typeahead.d.ts} +0 -0
- /package/dist/{utils → shared}/wait-for-css-transition.d.ts +0 -0
- /package/dist/{utils → shared}/wait-for-css-transition.js +0 -0
- /package/dist/{utils → shared}/wait.d.ts +0 -0
- /package/dist/{utils → shared}/wait.js +0 -0
- /package/src/{utils → listbox}/flash-attribute.ts +0 -0
- /package/src/{components/menu → menu}/hover-aim.ts +0 -0
- /package/src/{interactions/outside-click/outside-click-mixin.ts → popover/outside-click.ts} +0 -0
- /package/src/{interactions/keydown → select}/keydown.ts +0 -0
- /package/src/{interactions/typeahead/typeahead-mixin.ts → shared/typeahead.ts} +0 -0
- /package/src/{utils → shared}/wait-for-css-transition.ts +0 -0
- /package/src/{utils → shared}/wait.ts +0 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { createMixin, css } from '@remix-run/ui'
|
|
2
|
+
import type { CSSMixinDescriptor, ElementProps, MixinDescriptor } from '@remix-run/ui'
|
|
3
|
+
import { renderMixinElement } from '../runtime/mixins/mixin.ts'
|
|
4
|
+
|
|
5
|
+
export type ButtonSize = 'md' | 'lg'
|
|
6
|
+
export type ButtonTone = 'neutral' | 'primary' | 'ghost'
|
|
7
|
+
|
|
8
|
+
export interface ButtonOptions {
|
|
9
|
+
size?: ButtonSize
|
|
10
|
+
tone?: ButtonTone
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type ButtonMixin = readonly [
|
|
14
|
+
MixinDescriptor<Element, [], ElementProps>,
|
|
15
|
+
CSSMixinDescriptor,
|
|
16
|
+
CSSMixinDescriptor,
|
|
17
|
+
CSSMixinDescriptor,
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
const buttonDefaultAttrs = createMixin<Element, [], ElementProps>((handle, hostType) => (props) => {
|
|
21
|
+
if (hostType !== 'button' || props.type !== undefined) {
|
|
22
|
+
return handle.element
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return renderMixinElement(handle.element, {
|
|
26
|
+
...props,
|
|
27
|
+
type: 'button',
|
|
28
|
+
})
|
|
29
|
+
})()
|
|
30
|
+
|
|
31
|
+
const baseStyle: CSSMixinDescriptor = css({
|
|
32
|
+
'--rmx-button-shadow': '0 0 0 0 rgba(0, 0, 0, 0)',
|
|
33
|
+
'--rmx-button-focus-shadow':
|
|
34
|
+
'0 0 0 1px #3573F6, var(--rmx-button-shadow), 0 0 0 4px rgba(53, 115, 246, 0.1), 0 6px 32px 4px rgba(53, 115, 246, 0.08), inset 0 0 8px 1px rgba(53, 115, 246, 0.05)',
|
|
35
|
+
appearance: 'none',
|
|
36
|
+
margin: 0,
|
|
37
|
+
boxSizing: 'border-box',
|
|
38
|
+
cursor: 'revert',
|
|
39
|
+
display: 'inline-flex',
|
|
40
|
+
alignItems: 'center',
|
|
41
|
+
justifyContent: 'center',
|
|
42
|
+
flexDirection: 'row',
|
|
43
|
+
gap: '4px',
|
|
44
|
+
paddingBlock: 0,
|
|
45
|
+
width: 'max-content',
|
|
46
|
+
maxWidth: '100%',
|
|
47
|
+
borderRadius: '999px',
|
|
48
|
+
fontFamily: '"Inter Variable", Inter, ui-sans-serif, system-ui, sans-serif',
|
|
49
|
+
fontStyle: 'normal',
|
|
50
|
+
fontWeight: 500,
|
|
51
|
+
fontFeatureSettings: '"cv01" on, "ss01" on',
|
|
52
|
+
letterSpacing: 0,
|
|
53
|
+
whiteSpace: 'nowrap',
|
|
54
|
+
textDecoration: 'none',
|
|
55
|
+
userSelect: 'none',
|
|
56
|
+
WebkitUserSelect: 'none',
|
|
57
|
+
verticalAlign: 'top',
|
|
58
|
+
boxShadow: 'var(--rmx-button-shadow)',
|
|
59
|
+
'&:focus-visible': {
|
|
60
|
+
outline: 0,
|
|
61
|
+
boxShadow: 'var(--rmx-button-focus-shadow)',
|
|
62
|
+
},
|
|
63
|
+
'&:disabled, &[aria-disabled="true"]': {
|
|
64
|
+
cursor: 'not-allowed',
|
|
65
|
+
opacity: 0.55,
|
|
66
|
+
},
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const mediumStyle: CSSMixinDescriptor = css({
|
|
70
|
+
height: '26px',
|
|
71
|
+
minHeight: '26px',
|
|
72
|
+
paddingInline: '12px',
|
|
73
|
+
fontSize: '12px',
|
|
74
|
+
lineHeight: '17px',
|
|
75
|
+
'--rmx-button-neutral-shadow-alpha': '0.03',
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
const largeStyle: CSSMixinDescriptor = css({
|
|
79
|
+
height: '30px',
|
|
80
|
+
minHeight: '30px',
|
|
81
|
+
paddingInline: '12px',
|
|
82
|
+
fontSize: '13px',
|
|
83
|
+
lineHeight: '20px',
|
|
84
|
+
'--rmx-button-neutral-shadow-alpha': '0.04',
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
const neutralStyle: CSSMixinDescriptor = css({
|
|
88
|
+
background: '#FCFCFC',
|
|
89
|
+
border: '1px solid rgba(0, 0, 0, 0.08)',
|
|
90
|
+
'--rmx-button-shadow':
|
|
91
|
+
'0 -2px 0 -2px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(255, 255, 255, 0.75), 0 1px 0 #FFFFFF, 0 2px 4px -1px rgb(0 0 0 / var(--rmx-button-neutral-shadow-alpha)), inset 0 2px 0 #FFFFFF, inset 0 -1px 0 rgba(0, 0, 0, 0.05)',
|
|
92
|
+
color: '#101010',
|
|
93
|
+
textShadow: '0 1px 0 #FFFFFF',
|
|
94
|
+
'&:hover:not(:disabled):not([aria-disabled="true"])': {
|
|
95
|
+
background: '#FFFFFF',
|
|
96
|
+
borderColor: 'rgba(0, 0, 0, 0.1)',
|
|
97
|
+
'--rmx-button-shadow':
|
|
98
|
+
'0 -2px 0 -2px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(255, 255, 255, 0.8), 0 1px 0 #FFFFFF, 0 3px 6px -2px rgb(0 0 0 / calc(var(--rmx-button-neutral-shadow-alpha) + 0.03)), inset 0 2px 0 #FFFFFF, inset 0 -1px 0 rgba(0, 0, 0, 0.05)',
|
|
99
|
+
},
|
|
100
|
+
'&:active:not(:disabled):not([aria-disabled="true"]), &[aria-pressed="true"]:not(:disabled):not([aria-disabled="true"])':
|
|
101
|
+
{
|
|
102
|
+
background: '#F7F7F7',
|
|
103
|
+
borderColor: 'rgba(0, 0, 0, 0.12)',
|
|
104
|
+
'--rmx-button-shadow':
|
|
105
|
+
'0 0 0 1px rgba(255, 255, 255, 0.65), inset 0 1px 2px rgba(0, 0, 0, 0.08), inset 0 -1px 0 rgba(255, 255, 255, 0.8)',
|
|
106
|
+
textShadow: 'none',
|
|
107
|
+
},
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
const primaryStyle: CSSMixinDescriptor = css({
|
|
111
|
+
background:
|
|
112
|
+
'radial-gradient(50% 50% at 50% 0%, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 100%), radial-gradient(49.59% 37.11% at 50.41% 101.56%, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0) 66.46%), #101010',
|
|
113
|
+
border: 0,
|
|
114
|
+
'--rmx-button-shadow':
|
|
115
|
+
'0 16px 16px -8px rgba(0, 0, 0, 0.1), 0 8px 8px -4px rgba(0, 0, 0, 0.1), 0 4px 4px -2px rgba(0, 0, 0, 0.1), 0 2px 2px -1px rgba(0, 0, 0, 0.1), inset 0 0 4px 2px #101010, inset 0 0 4px 2px rgba(255, 255, 255, 0.1), inset 0 0 12px -6px rgba(255, 255, 255, 0.75)',
|
|
116
|
+
color: '#FFFFFF',
|
|
117
|
+
textShadow: '0 1px 1px #000000',
|
|
118
|
+
'&:hover:not(:disabled):not([aria-disabled="true"])': {
|
|
119
|
+
background:
|
|
120
|
+
'radial-gradient(50% 50% at 50% 0%, rgba(255, 255, 255, 0.24) 0%, rgba(255, 255, 255, 0) 100%), radial-gradient(49.59% 37.11% at 50.41% 101.56%, rgba(255, 255, 255, 0.18) 0%, rgba(255, 255, 255, 0) 66.46%), #171717',
|
|
121
|
+
'--rmx-button-shadow':
|
|
122
|
+
'0 18px 18px -10px rgba(0, 0, 0, 0.14), 0 8px 8px -4px rgba(0, 0, 0, 0.12), 0 4px 4px -2px rgba(0, 0, 0, 0.1), 0 2px 2px -1px rgba(0, 0, 0, 0.1), inset 0 0 4px 2px #101010, inset 0 0 4px 2px rgba(255, 255, 255, 0.13), inset 0 0 12px -6px rgba(255, 255, 255, 0.85)',
|
|
123
|
+
},
|
|
124
|
+
'&:active:not(:disabled):not([aria-disabled="true"]), &[aria-pressed="true"]:not(:disabled):not([aria-disabled="true"])':
|
|
125
|
+
{
|
|
126
|
+
background:
|
|
127
|
+
'radial-gradient(50% 50% at 50% 0%, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0) 100%), radial-gradient(49.59% 37.11% at 50.41% 101.56%, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0) 66.46%), #080808',
|
|
128
|
+
'--rmx-button-shadow':
|
|
129
|
+
'0 2px 2px -1px rgba(0, 0, 0, 0.14), inset 0 0 4px 2px #050505, inset 0 1px 2px rgba(0, 0, 0, 0.45), inset 0 0 10px -6px rgba(255, 255, 255, 0.55)',
|
|
130
|
+
textShadow: '0 1px 1px #000000',
|
|
131
|
+
},
|
|
132
|
+
'&:active:not(:disabled):not([aria-disabled="true"])': {
|
|
133
|
+
transform: 'translateY(1px)',
|
|
134
|
+
},
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
const ghostStyle: CSSMixinDescriptor = css({
|
|
138
|
+
background: 'transparent',
|
|
139
|
+
border: '1px solid transparent',
|
|
140
|
+
'--rmx-button-shadow': '0 0 0 0 rgba(0, 0, 0, 0)',
|
|
141
|
+
color: '#101010',
|
|
142
|
+
textShadow: 'none',
|
|
143
|
+
'&:hover:not(:disabled):not([aria-disabled="true"])': {
|
|
144
|
+
background: 'rgba(16, 16, 16, 0.05)',
|
|
145
|
+
},
|
|
146
|
+
'&:active:not(:disabled):not([aria-disabled="true"]), &[aria-pressed="true"]:not(:disabled):not([aria-disabled="true"])':
|
|
147
|
+
{
|
|
148
|
+
background: 'rgba(16, 16, 16, 0.08)',
|
|
149
|
+
},
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
const sizeStyles = {
|
|
153
|
+
md: mediumStyle,
|
|
154
|
+
lg: largeStyle,
|
|
155
|
+
} as const satisfies Record<ButtonSize, CSSMixinDescriptor>
|
|
156
|
+
|
|
157
|
+
const toneStyles = {
|
|
158
|
+
neutral: neutralStyle,
|
|
159
|
+
primary: primaryStyle,
|
|
160
|
+
ghost: ghostStyle,
|
|
161
|
+
} as const satisfies Record<ButtonTone, CSSMixinDescriptor>
|
|
162
|
+
|
|
163
|
+
export function button(options: ButtonOptions = {}): ButtonMixin {
|
|
164
|
+
let { size = 'md', tone = 'neutral' } = options
|
|
165
|
+
return [buttonDefaultAttrs, baseStyle, sizeStyles[size], toneStyles[tone]]
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export default button
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# checkbox
|
|
2
|
+
|
|
3
|
+
`checkbox` is a style mixin for native checkbox inputs. It only owns checkbox visuals, an optional visual state, and the default `type="checkbox"` behavior for native `<input>` hosts.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import checkbox from 'remix/ui/checkbox'
|
|
9
|
+
|
|
10
|
+
function VisibilityToggle() {
|
|
11
|
+
return () => (
|
|
12
|
+
<label>
|
|
13
|
+
<input defaultChecked mix={checkbox()} name="visibility" value="archived" />
|
|
14
|
+
Show archived items
|
|
15
|
+
</label>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Use `size: 'lg'` when the surrounding UI needs a larger visual control:
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
<input mix={checkbox({ size: 'lg' })} />
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For mixed state, app code owns the checkbox state and the native `indeterminate` property:
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import checkbox from 'remix/ui/checkbox'
|
|
30
|
+
|
|
31
|
+
function PermissionParent() {
|
|
32
|
+
let state: 'checked' | 'mixed' | 'unchecked' = 'mixed'
|
|
33
|
+
|
|
34
|
+
return () => (
|
|
35
|
+
<input
|
|
36
|
+
checked={state === 'checked'}
|
|
37
|
+
indeterminate={state === 'mixed'}
|
|
38
|
+
mix={checkbox({ state })}
|
|
39
|
+
/>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## `remix/ui/checkbox`
|
|
45
|
+
|
|
46
|
+
- `checkbox(options)`: style mixin for native checkbox inputs or checkbox-like hosts.
|
|
47
|
+
- `CheckboxOptions`: accepts `size` and `state`.
|
|
48
|
+
- `CheckboxSize`: `'md'` or `'lg'`. Defaults to `'md'`.
|
|
49
|
+
- `CheckboxState`: `'checked'`, `'mixed'`, or `'unchecked'`.
|
|
50
|
+
|
|
51
|
+
## Behavior Notes
|
|
52
|
+
|
|
53
|
+
- `checkbox()` returns a mixin descriptor, so it composes with other mixins in the host element's `mix` prop.
|
|
54
|
+
- Native `<input>` hosts receive `type="checkbox"` unless an explicit `type` is provided.
|
|
55
|
+
- Native input state is browser-owned through `checked`, `defaultChecked`, and user interaction.
|
|
56
|
+
- The optional `state` option adds `aria-checked` and `data-state` for app-owned mixed state or custom hosts.
|
|
57
|
+
- Checked styles apply through `:checked`, `aria-checked="true"`, or `data-state="checked"`.
|
|
58
|
+
- Mixed styles apply through `:indeterminate`, `indeterminate`, `aria-checked="mixed"`, or `data-state="mixed"`.
|
|
59
|
+
- Disabled hosts use the shared disabled treatment through `disabled` or `aria-disabled="true"`.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { createMixin, css } from '@remix-run/ui'
|
|
2
|
+
import type { CSSMixinDescriptor, ElementProps, MixinDescriptor } from '@remix-run/ui'
|
|
3
|
+
import { renderMixinElement } from '../runtime/mixins/mixin.ts'
|
|
4
|
+
import { controlFocusShadow } from '../shared/focus-styles.ts'
|
|
5
|
+
|
|
6
|
+
export type CheckboxSize = 'md' | 'lg'
|
|
7
|
+
export type CheckboxState = 'checked' | 'mixed' | 'unchecked'
|
|
8
|
+
|
|
9
|
+
export interface CheckboxOptions {
|
|
10
|
+
size?: CheckboxSize
|
|
11
|
+
state?: CheckboxState
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type CheckboxMixin = readonly [
|
|
15
|
+
MixinDescriptor<Element, [state?: CheckboxState], ElementProps>,
|
|
16
|
+
CSSMixinDescriptor,
|
|
17
|
+
CSSMixinDescriptor,
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
const checkedSelector = '&:checked, &[aria-checked="true"], &[data-state="checked"]'
|
|
21
|
+
const mixedSelector =
|
|
22
|
+
'&:indeterminate, &[indeterminate], &[aria-checked="mixed"], &[data-state="mixed"]'
|
|
23
|
+
const checkedMarkSelector =
|
|
24
|
+
'&:checked::before, &[aria-checked="true"]::before, &[data-state="checked"]::before'
|
|
25
|
+
const mixedMarkSelector =
|
|
26
|
+
'&:indeterminate::before, &[indeterminate]::before, &[aria-checked="mixed"]::before, &[data-state="mixed"]::before'
|
|
27
|
+
const enabledSelector = ':not(:disabled):not([aria-disabled="true"])'
|
|
28
|
+
const checkedActiveSelector =
|
|
29
|
+
'&:checked:active:not(:disabled):not([aria-disabled="true"]), &[aria-checked="true"]:active:not(:disabled):not([aria-disabled="true"]), &[data-state="checked"]:active:not(:disabled):not([aria-disabled="true"])'
|
|
30
|
+
const mixedActiveSelector =
|
|
31
|
+
'&:indeterminate:active:not(:disabled):not([aria-disabled="true"]), &[indeterminate]:active:not(:disabled):not([aria-disabled="true"]), &[aria-checked="mixed"]:active:not(:disabled):not([aria-disabled="true"]), &[data-state="mixed"]:active:not(:disabled):not([aria-disabled="true"])'
|
|
32
|
+
const checkIconUrl =
|
|
33
|
+
"url(\"data:image/svg+xml,%3Csvg width='12' height='12' viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg filter='url(%23filter0_d_2_2264)'%3E%3Cpath d='M2.75 5.76562L5.10156 8.25L9.23438 1.75' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M2.75 5.76562L5.10156 8.25L9.23438 1.75' stroke='url(%23paint0_linear_2_2264)' stroke-opacity='0.1' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/g%3E%3Cdefs%3E%3Cfilter id='filter0_d_2_2264' x='0' y='0' width='11.9845' height='12' filterUnits='userSpaceOnUse' color-interpolation-filters='sRGB'%3E%3CfeFlood flood-opacity='0' result='BackgroundImageFix'/%3E%3CfeColorMatrix in='SourceAlpha' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0' result='hardAlpha'/%3E%3CfeOffset dy='1'/%3E%3CfeGaussianBlur stdDeviation='1'/%3E%3CfeComposite in2='hardAlpha' operator='out'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.4 0'/%3E%3CfeBlend mode='overlay' in2='BackgroundImageFix' result='effect1_dropShadow_2_2264'/%3E%3CfeBlend mode='normal' in='SourceGraphic' in2='effect1_dropShadow_2_2264' result='shape'/%3E%3C/filter%3E%3ClinearGradient id='paint0_linear_2_2264' x1='5.99219' y1='1.75' x2='5.99219' y2='8.25' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0.25' stop-color='%233573F6' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='%233573F6'/%3E%3C/linearGradient%3E%3C/defs%3E%3C/svg%3E\")"
|
|
34
|
+
|
|
35
|
+
const checkboxAriaChecked = {
|
|
36
|
+
checked: 'true',
|
|
37
|
+
mixed: 'mixed',
|
|
38
|
+
unchecked: 'false',
|
|
39
|
+
} as const satisfies Record<CheckboxState, 'true' | 'mixed' | 'false'>
|
|
40
|
+
|
|
41
|
+
const checkboxDefaultAttrs = createMixin<Element, [state?: CheckboxState], ElementProps>(
|
|
42
|
+
(handle, hostType) => (state, props) => {
|
|
43
|
+
let stateProps =
|
|
44
|
+
state === undefined
|
|
45
|
+
? props
|
|
46
|
+
: {
|
|
47
|
+
...props,
|
|
48
|
+
'aria-checked': props['aria-checked'] ?? checkboxAriaChecked[state],
|
|
49
|
+
'data-state': props['data-state'] ?? state,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (hostType !== 'input' || stateProps.type !== undefined) {
|
|
53
|
+
return state === undefined ? handle.element : renderMixinElement(handle.element, stateProps)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return renderMixinElement(handle.element, {
|
|
57
|
+
...stateProps,
|
|
58
|
+
type: 'checkbox',
|
|
59
|
+
})
|
|
60
|
+
},
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
const baseStyle: CSSMixinDescriptor = css({
|
|
64
|
+
appearance: 'none',
|
|
65
|
+
WebkitAppearance: 'none',
|
|
66
|
+
margin: 0,
|
|
67
|
+
boxSizing: 'border-box',
|
|
68
|
+
position: 'relative',
|
|
69
|
+
display: 'inline-grid',
|
|
70
|
+
placeItems: 'center',
|
|
71
|
+
width: 'var(--rmx-checkbox-size)',
|
|
72
|
+
height: 'var(--rmx-checkbox-size)',
|
|
73
|
+
minWidth: 'var(--rmx-checkbox-size)',
|
|
74
|
+
minHeight: 'var(--rmx-checkbox-size)',
|
|
75
|
+
padding: 0,
|
|
76
|
+
border: 0,
|
|
77
|
+
borderRadius: 'var(--rmx-checkbox-radius)',
|
|
78
|
+
background: '#FFFFFF',
|
|
79
|
+
boxShadow:
|
|
80
|
+
'0 2px 2px -1px rgba(0, 0, 0, 0.05), 0 3px 4px -1.5px rgba(0, 0, 0, 0.05), 0 4px 8px -2px rgba(0, 0, 0, 0.05), 0 5px 16px -2.5px rgba(0, 0, 0, 0.05), 0 0 0 1px rgba(0, 0, 0, 0.12)',
|
|
81
|
+
color: '#FFFFFF',
|
|
82
|
+
verticalAlign: 'middle',
|
|
83
|
+
flex: 'none',
|
|
84
|
+
'&::before': {
|
|
85
|
+
content: '""',
|
|
86
|
+
position: 'absolute',
|
|
87
|
+
opacity: 0,
|
|
88
|
+
pointerEvents: 'none',
|
|
89
|
+
},
|
|
90
|
+
'&:disabled, &[aria-disabled="true"]': {
|
|
91
|
+
opacity: 0.55,
|
|
92
|
+
},
|
|
93
|
+
[`${checkedSelector}, ${mixedSelector}`]: {
|
|
94
|
+
background:
|
|
95
|
+
'linear-gradient(180deg, rgba(0, 0, 0, 0) 24.52%, rgba(0, 0, 0, 0.1) 100%), #3573F6',
|
|
96
|
+
backgroundBlendMode: 'overlay, normal',
|
|
97
|
+
borderRadius: 'var(--rmx-checkbox-active-radius)',
|
|
98
|
+
boxShadow:
|
|
99
|
+
'0 1px 1px -0.5px rgba(9, 68, 190, 0.12), 0 2px 2px -1px rgba(9, 68, 190, 0.12), 0 4px 4px -2px rgba(9, 68, 190, 0.12), 0 8px 8px -4px rgba(9, 68, 190, 0.12), 0 2px 8px rgba(53, 115, 246, 0.4), inset 0 0 3px 1px rgba(0, 0, 0, 0.1)',
|
|
100
|
+
},
|
|
101
|
+
[checkedMarkSelector]: {
|
|
102
|
+
opacity: 1,
|
|
103
|
+
left: '50%',
|
|
104
|
+
top: '50%',
|
|
105
|
+
width: 'var(--rmx-checkbox-check-size)',
|
|
106
|
+
height: 'var(--rmx-checkbox-check-size)',
|
|
107
|
+
background: `${checkIconUrl} center / contain no-repeat`,
|
|
108
|
+
transform: 'translate(-50%, calc(-50% + var(--rmx-checkbox-check-y)))',
|
|
109
|
+
},
|
|
110
|
+
[mixedMarkSelector]: {
|
|
111
|
+
opacity: 1,
|
|
112
|
+
left: '50%',
|
|
113
|
+
top: '50%',
|
|
114
|
+
width: 'var(--rmx-checkbox-mixed-width)',
|
|
115
|
+
height: 'var(--rmx-checkbox-mixed-height)',
|
|
116
|
+
border: 0,
|
|
117
|
+
borderRadius: '999px',
|
|
118
|
+
background: 'currentColor',
|
|
119
|
+
filter: 'drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4))',
|
|
120
|
+
transform: 'translate(-50%, -50%)',
|
|
121
|
+
},
|
|
122
|
+
[`&:active${enabledSelector}`]: {
|
|
123
|
+
boxShadow:
|
|
124
|
+
'0 1px 1px -0.5px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.14), inset 0 1px 2px rgba(0, 0, 0, 0.08)',
|
|
125
|
+
},
|
|
126
|
+
[`${checkedActiveSelector}, ${mixedActiveSelector}`]: {
|
|
127
|
+
boxShadow:
|
|
128
|
+
'0 1px 1px -0.5px rgba(9, 68, 190, 0.1), 0 2px 2px -1px rgba(9, 68, 190, 0.1), 0 4px 4px -2px rgba(9, 68, 190, 0.1), 0 6px 8px -4px rgba(9, 68, 190, 0.1), 0 2px 6px rgba(53, 115, 246, 0.32), inset 0 1px 2px rgba(0, 0, 0, 0.3), inset 0 0 3px 1px rgba(0, 0, 0, 0.12)',
|
|
129
|
+
},
|
|
130
|
+
'&:focus-visible': {
|
|
131
|
+
outline: 0,
|
|
132
|
+
boxShadow: controlFocusShadow,
|
|
133
|
+
},
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
const sizeStyles = {
|
|
137
|
+
md: css({
|
|
138
|
+
'--rmx-checkbox-size': '16px',
|
|
139
|
+
'--rmx-checkbox-radius': '4px',
|
|
140
|
+
'--rmx-checkbox-active-radius': '5px',
|
|
141
|
+
'--rmx-checkbox-check-size': '12px',
|
|
142
|
+
'--rmx-checkbox-check-y': '1px',
|
|
143
|
+
'--rmx-checkbox-mixed-width': '7px',
|
|
144
|
+
'--rmx-checkbox-mixed-height': '2px',
|
|
145
|
+
}),
|
|
146
|
+
lg: css({
|
|
147
|
+
'--rmx-checkbox-size': '20px',
|
|
148
|
+
'--rmx-checkbox-radius': '5px',
|
|
149
|
+
'--rmx-checkbox-active-radius': '6px',
|
|
150
|
+
'--rmx-checkbox-check-size': '15px',
|
|
151
|
+
'--rmx-checkbox-check-y': '1.25px',
|
|
152
|
+
'--rmx-checkbox-mixed-width': '9px',
|
|
153
|
+
'--rmx-checkbox-mixed-height': '2.25px',
|
|
154
|
+
}),
|
|
155
|
+
} as const satisfies Record<CheckboxSize, CSSMixinDescriptor>
|
|
156
|
+
|
|
157
|
+
export function checkbox(options: CheckboxOptions = {}): CheckboxMixin {
|
|
158
|
+
let { size = 'md', state } = options
|
|
159
|
+
return [checkboxDefaultAttrs(state), baseStyle, sizeStyles[size]]
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export default checkbox
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# combobox
|
|
2
2
|
|
|
3
|
-
`Combobox` is the input-first popup value picker for `remix/ui`.
|
|
3
|
+
`Combobox` is the input-first popup value picker for `remix/ui/combobox`.
|
|
4
4
|
|
|
5
5
|
Use it when the user should type draft text, filter a popup list, and still commit one stable form value. If you just need a button-triggered picker, use `Select` instead.
|
|
6
6
|
|
|
7
|
-
## Usage
|
|
7
|
+
## Component Usage
|
|
8
8
|
|
|
9
9
|
```tsx
|
|
10
10
|
import { css, type Handle } from 'remix/ui'
|
|
11
|
-
import { Combobox, ComboboxOption
|
|
11
|
+
import { Combobox, ComboboxOption } from 'remix/ui/combobox'
|
|
12
|
+
import { onComboboxChange } from 'remix/ui/combobox/primitives'
|
|
12
13
|
|
|
13
14
|
let airports = [
|
|
14
15
|
{
|
|
@@ -58,7 +59,39 @@ let root = css({
|
|
|
58
59
|
})
|
|
59
60
|
```
|
|
60
61
|
|
|
61
|
-
##
|
|
62
|
+
## Primitive Usage
|
|
63
|
+
|
|
64
|
+
Use the lower-level primitives when app code owns the input, popover, list, and option markup:
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import * as combobox from 'remix/ui/combobox/primitives'
|
|
68
|
+
import { inputStyle, listStyle, optionStyle, popoverStyle } from './combobox.styles'
|
|
69
|
+
|
|
70
|
+
let frameworks = [
|
|
71
|
+
{ label: 'Remix', searchValue: ['remix', 'rmx'], value: 'remix' },
|
|
72
|
+
{ label: 'React Router', value: 'react-router' },
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
export function PrimitiveCombobox() {
|
|
76
|
+
return (
|
|
77
|
+
<combobox.Context name="framework">
|
|
78
|
+
<input mix={[inputStyle, combobox.input()]} placeholder="Search frameworks" />
|
|
79
|
+
<div mix={[popoverStyle, combobox.popover()]}>
|
|
80
|
+
<div mix={[listStyle, combobox.list()]}>
|
|
81
|
+
{frameworks.map((option) => (
|
|
82
|
+
<div key={option.value} mix={[optionStyle, combobox.option(option)]}>
|
|
83
|
+
{option.label}
|
|
84
|
+
</div>
|
|
85
|
+
))}
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
<input mix={combobox.hiddenInput()} />
|
|
89
|
+
</combobox.Context>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## `remix/ui/combobox`
|
|
62
95
|
|
|
63
96
|
### `Combobox`
|
|
64
97
|
|
|
@@ -66,7 +99,7 @@ The convenience component.
|
|
|
66
99
|
|
|
67
100
|
- Renders the text input, popover surface, listbox root, and hidden form input.
|
|
68
101
|
- Dispatches a bubbled custom event that `onComboboxChange(...)` listens for when the committed value changes.
|
|
69
|
-
- Accepts `defaultValue`, `disabled`, `inputId`, `name`, and `
|
|
102
|
+
- Accepts `children`, `defaultValue`, `disabled`, `inputId`, `name`, `placeholder`, and root `div` props.
|
|
70
103
|
|
|
71
104
|
### `ComboboxOption`
|
|
72
105
|
|
|
@@ -74,21 +107,31 @@ The default option row for `Combobox`.
|
|
|
74
107
|
|
|
75
108
|
- Uses the shared listbox option visuals.
|
|
76
109
|
- Accepts `label`, `value`, optional `searchValue`, and optional `disabled`.
|
|
110
|
+
- Renders `children` when provided, otherwise renders `label`.
|
|
77
111
|
- `searchValue` can be a string or string array for aliases like airport codes, abbreviations, or alternate labels.
|
|
78
112
|
|
|
113
|
+
### Style and Prop Exports
|
|
114
|
+
|
|
115
|
+
- `inputStyle`: default combobox input style.
|
|
116
|
+
- `popoverStyle`: default combobox popover behavior style.
|
|
117
|
+
- `ComboboxProps` and `ComboboxOptionProps`: public TypeScript props for the composed APIs.
|
|
118
|
+
|
|
119
|
+
## `remix/ui/combobox/primitives`
|
|
120
|
+
|
|
79
121
|
### `onComboboxChange(...)`
|
|
80
122
|
|
|
81
|
-
The listener mixin for bubbled committed-value changes.
|
|
123
|
+
The listener mixin from `remix/ui/combobox/primitives` for bubbled committed-value changes.
|
|
82
124
|
|
|
83
125
|
The event object includes:
|
|
84
126
|
|
|
85
127
|
- `event.value`: the committed value or `null`
|
|
86
128
|
- `event.label`: the committed option label or `null`
|
|
87
129
|
- `event.optionId`: the generated option id or `null`
|
|
130
|
+
- `ComboboxChangeEvent`: the event class dispatched for committed value changes.
|
|
88
131
|
|
|
89
132
|
### `combobox.Context`
|
|
90
133
|
|
|
91
|
-
The lower-level coordinator for custom combobox composition.
|
|
134
|
+
The lower-level coordinator from `remix/ui/combobox/primitives` for custom combobox composition.
|
|
92
135
|
|
|
93
136
|
It wraps the shared `popover` and `listbox` contexts and owns the draft text, committed value, popup state, and selection timing.
|
|
94
137
|
|
|
@@ -106,7 +149,7 @@ Turns the host into the combobox popover surface.
|
|
|
106
149
|
|
|
107
150
|
- Uses the shared popover primitive.
|
|
108
151
|
- Keeps anchor clicks inside the session so the input stays interactive while open.
|
|
109
|
-
- Applies the combobox open/close reason contract used by `
|
|
152
|
+
- Applies the combobox open/close reason contract used by `popoverStyle`.
|
|
110
153
|
|
|
111
154
|
### `combobox.list()`
|
|
112
155
|
|
|
@@ -126,6 +169,12 @@ Mirrors the committed value into a hidden input for forms.
|
|
|
126
169
|
|
|
127
170
|
Apply it to an `<input type="hidden" />` inside the same `combobox.Context`.
|
|
128
171
|
|
|
172
|
+
### Primitive Types
|
|
173
|
+
|
|
174
|
+
- `ComboboxOpenStrategy`: initial active-option strategy when the popup opens.
|
|
175
|
+
- `ComboboxHandle`: imperative ref for reading or updating the combobox value and draft label.
|
|
176
|
+
- `ComboboxContextProps`, `ComboboxProps`, `ComboboxOptionOptions`, and `ComboboxOptionProps`: primitive prop and option types for custom composition.
|
|
177
|
+
|
|
129
178
|
## Behavior Notes
|
|
130
179
|
|
|
131
180
|
- Typing opens the popup in hint mode when there are matches.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { createElement, css } from '@remix-run/ui'
|
|
2
|
+
import type { CSSMixinDescriptor, Handle, Props, RemixNode } from '@remix-run/ui'
|
|
3
|
+
|
|
4
|
+
import * as combobox from '@remix-run/ui/combobox/primitives'
|
|
5
|
+
import type { SearchValue } from '../shared/typeahead.ts'
|
|
6
|
+
import { CheckIcon } from '../shared/icons.tsx'
|
|
7
|
+
import {
|
|
8
|
+
listboxIndicatorStyle,
|
|
9
|
+
listboxLabelStyle,
|
|
10
|
+
listboxListStyle,
|
|
11
|
+
listboxOptionStyle,
|
|
12
|
+
popoverSurfaceStyle,
|
|
13
|
+
} from '../shared/listbox-popover-styles.ts'
|
|
14
|
+
import { componentStyleValues as styles } from '../shared/style-values.ts'
|
|
15
|
+
|
|
16
|
+
export interface ComboboxProps extends Omit<Props<'div'>, 'children'> {
|
|
17
|
+
children?: RemixNode
|
|
18
|
+
defaultValue?: string | null
|
|
19
|
+
disabled?: boolean
|
|
20
|
+
inputId?: string
|
|
21
|
+
name?: string
|
|
22
|
+
placeholder?: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ComboboxOptionProps extends Omit<Props<'div'>, 'children'> {
|
|
26
|
+
children?: RemixNode
|
|
27
|
+
disabled?: boolean
|
|
28
|
+
label: string
|
|
29
|
+
searchValue?: SearchValue
|
|
30
|
+
value: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const comboboxPopoverCss: CSSMixinDescriptor = css({
|
|
34
|
+
opacity: 0,
|
|
35
|
+
'&:popover-open': {
|
|
36
|
+
opacity: 1,
|
|
37
|
+
},
|
|
38
|
+
'&:not(:popover-open)': {
|
|
39
|
+
pointerEvents: 'none',
|
|
40
|
+
},
|
|
41
|
+
'&[data-show-reason="nav"]:not(:popover-open)': {
|
|
42
|
+
transition: 'opacity 180ms ease-in, overlay 180ms ease-in, display 180ms ease-in',
|
|
43
|
+
transitionBehavior: 'allow-discrete',
|
|
44
|
+
},
|
|
45
|
+
'&[data-show-reason="hint"]:not(:popover-open)': {
|
|
46
|
+
transition: 'none',
|
|
47
|
+
transitionBehavior: 'normal',
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const comboboxInputCss: CSSMixinDescriptor = css({
|
|
52
|
+
minHeight: styles.control.height.sm,
|
|
53
|
+
width: '100%',
|
|
54
|
+
paddingInline: styles.space.sm,
|
|
55
|
+
border: `0.5px solid ${styles.colors.border.default}`,
|
|
56
|
+
borderRadius: styles.radius.md,
|
|
57
|
+
backgroundColor: styles.surface.lvl0,
|
|
58
|
+
color: styles.colors.text.primary,
|
|
59
|
+
fontFamily: styles.fontFamily.sans,
|
|
60
|
+
fontSize: styles.fontSize.sm,
|
|
61
|
+
lineHeight: styles.lineHeight.normal,
|
|
62
|
+
boxShadow: 'inset 0 1px 0 rgb(255 255 255 / 0.7)',
|
|
63
|
+
'&:focus-visible': {
|
|
64
|
+
outline: `2px solid ${styles.colors.focus.ring}`,
|
|
65
|
+
outlineOffset: styles.space.none,
|
|
66
|
+
},
|
|
67
|
+
'&[data-surface-visible="true"][aria-activedescendant]:focus-visible': {
|
|
68
|
+
outline: 'none',
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
export const inputStyle = comboboxInputCss
|
|
73
|
+
export const popoverStyle = comboboxPopoverCss
|
|
74
|
+
|
|
75
|
+
export function Combobox(handle: Handle<ComboboxProps>): () => RemixNode {
|
|
76
|
+
return () => {
|
|
77
|
+
let { children, defaultValue, disabled, inputId, name, placeholder, ...divProps } = handle.props
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<combobox.Context defaultValue={defaultValue} disabled={disabled} name={name}>
|
|
81
|
+
<div {...divProps}>
|
|
82
|
+
<input
|
|
83
|
+
defaultValue={defaultValue ?? undefined}
|
|
84
|
+
id={inputId}
|
|
85
|
+
mix={[inputStyle, combobox.input()]}
|
|
86
|
+
placeholder={placeholder}
|
|
87
|
+
/>
|
|
88
|
+
<div mix={[popoverSurfaceStyle, popoverStyle, combobox.popover()]}>
|
|
89
|
+
<div mix={[listboxListStyle, combobox.list()]}>{children}</div>
|
|
90
|
+
</div>
|
|
91
|
+
{name && <input mix={combobox.hiddenInput()} />}
|
|
92
|
+
</div>
|
|
93
|
+
</combobox.Context>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function ComboboxOption(handle: Handle<ComboboxOptionProps>): () => RemixNode {
|
|
99
|
+
return () => {
|
|
100
|
+
let { children, disabled, label, mix, searchValue, value, ...divProps } = handle.props
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<div
|
|
104
|
+
{...divProps}
|
|
105
|
+
mix={[listboxOptionStyle, combobox.option({ disabled, label, searchValue, value }), mix]}
|
|
106
|
+
>
|
|
107
|
+
<CheckIcon mix={listboxIndicatorStyle} />
|
|
108
|
+
<span mix={listboxLabelStyle}>{children ?? label}</span>
|
|
109
|
+
</div>
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
}
|