@remix-run/ui 0.3.0 → 0.5.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 +116 -157
- 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.js → anchor/index.js} +1 -1
- package/dist/anchor/index.js.map +1 -0
- package/dist/animation/animate-layout-mixin.js +1 -1
- package/dist/animation/animate-layout-mixin.js.map +1 -1
- package/dist/animation/animate-mixins.js +2 -2
- package/dist/animation/animate-mixins.js.map +1 -1
- package/dist/animation/demos/color-interpolation.js +1 -1
- package/dist/animation/demos/color-interpolation.js.map +1 -1
- package/dist/animation/demos/drag-release.d.ts +1 -1
- package/dist/animation/demos/hold-to-confirm.d.ts +3 -3
- package/dist/animation/demos/material-ripple.js +1 -3
- package/dist/animation/demos/material-ripple.js.map +1 -1
- package/dist/animation/demos/reordering.js +9 -6
- package/dist/animation/demos/reordering.js.map +1 -1
- package/dist/animation/index.js +4 -4
- 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 +127 -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} +4 -8
- package/dist/{components/combobox/combobox.js → combobox/primitives.js} +8 -61
- package/dist/combobox/primitives.js.map +1 -0
- package/dist/dev/refresh.d.ts +1 -0
- package/dist/dev/refresh.js +2 -0
- package/dist/dev/refresh.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +14 -14
- 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/jsx-runtime.js +2 -2
- 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} +4 -33
- package/dist/{components/menu/menu.js → menu/primitives.js} +98 -315
- package/dist/menu/primitives.js.map +1 -0
- package/dist/{components/popover/popover.d.ts → popover/index.d.ts} +2 -4
- package/dist/{components/popover/popover.js → popover/index.js} +5 -48
- 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-entry-boundary.d.ts +14 -0
- package/dist/runtime/client-entry-boundary.js +29 -0
- package/dist/runtime/client-entry-boundary.js.map +1 -0
- package/dist/runtime/component.d.ts +19 -4
- package/dist/runtime/component.js +39 -9
- package/dist/runtime/component.js.map +1 -1
- package/dist/runtime/core/attributes.js +36 -3
- package/dist/runtime/core/attributes.js.map +1 -1
- package/dist/runtime/core/children.d.ts +2 -0
- package/dist/runtime/core/children.js +26 -2
- package/dist/runtime/core/children.js.map +1 -1
- package/dist/runtime/core/props.js +2 -2
- package/dist/runtime/core/vnode.d.ts +3 -3
- package/dist/runtime/core/vnode.js +22 -1
- package/dist/runtime/core/vnode.js.map +1 -1
- package/dist/runtime/create-element.d.ts +2 -2
- package/dist/runtime/create-element.js +3 -2
- package/dist/runtime/create-element.js.map +1 -1
- package/dist/runtime/diff-dom.js +294 -219
- package/dist/runtime/diff-dom.js.map +1 -1
- package/dist/runtime/diff-props.js +3 -3
- package/dist/runtime/dom.d.ts +12 -0
- package/dist/runtime/element-function.d.ts +3 -0
- package/dist/runtime/element-function.js +2 -0
- package/dist/runtime/element-function.js.map +1 -0
- package/dist/runtime/form-navigation.d.ts +25 -0
- package/dist/runtime/form-navigation.js +132 -0
- package/dist/runtime/form-navigation.js.map +1 -0
- package/dist/runtime/frame-resolution.d.ts +5 -0
- package/dist/runtime/frame-resolution.js +10 -0
- package/dist/runtime/frame-resolution.js.map +1 -0
- package/dist/runtime/frame.d.ts +58 -15
- package/dist/runtime/frame.js +367 -114
- package/dist/runtime/frame.js.map +1 -1
- package/dist/runtime/jsx.d.ts +1 -1
- package/dist/runtime/jsx.js +1 -1
- package/dist/runtime/jsx.js.map +1 -1
- package/dist/runtime/key.d.ts +1 -0
- package/dist/runtime/key.js +2 -0
- package/dist/runtime/key.js.map +1 -0
- package/dist/runtime/mixins/attrs-mixin.js +2 -2
- package/dist/runtime/mixins/link-mixin.js +4 -3
- package/dist/runtime/mixins/link-mixin.js.map +1 -1
- package/dist/runtime/mixins/mixin.d.ts +15 -10
- package/dist/runtime/mixins/mixin.js +4 -4
- package/dist/runtime/mixins/mixin.js.map +1 -1
- package/dist/runtime/mixins/on-mixin.js +1 -1
- package/dist/runtime/mixins/ref-mixin.js +1 -1
- package/dist/runtime/navigation.d.ts +4 -1
- package/dist/runtime/navigation.js +157 -32
- package/dist/runtime/navigation.js.map +1 -1
- package/dist/runtime/reconcile.d.ts +11 -10
- package/dist/runtime/reconcile.js +557 -423
- package/dist/runtime/reconcile.js.map +1 -1
- package/dist/runtime/refresh.d.ts +28 -0
- package/dist/runtime/refresh.js +31 -0
- package/dist/runtime/refresh.js.map +1 -0
- package/dist/runtime/render.js +1 -1
- package/dist/runtime/render.js.map +1 -1
- package/dist/runtime/run.d.ts +3 -1
- package/dist/runtime/run.js +15 -7
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/scheduler.js +8 -16
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/to-vnode.d.ts +2 -2
- package/dist/runtime/to-vnode.js +68 -20
- package/dist/runtime/to-vnode.js.map +1 -1
- package/dist/runtime/vdom.d.ts +4 -2
- package/dist/runtime/vdom.js +89 -41
- package/dist/runtime/vdom.js.map +1 -1
- package/dist/runtime/vnode.d.ts +138 -67
- package/dist/runtime/vnode.js +17 -12
- package/dist/runtime/vnode.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} +5 -7
- package/dist/{components/select/select.js → select/primitives.js} +11 -63
- package/dist/select/primitives.js.map +1 -0
- package/dist/server/stream.js +22 -29
- 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/shared/style-values.js +88 -0
- 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/css-mixin.js +3 -3
- package/dist/style/index.js +2 -2
- package/dist/style/style.js +25 -6
- package/dist/style/style.js.map +1 -1
- package/dist/style/stylesheet.d.ts +0 -1
- package/dist/style/stylesheet.js +13 -54
- package/dist/style/stylesheet.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/test.js +1 -1
- 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 +81 -49
- 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 +37 -2
- package/src/animation/animate-mixins.ts +3 -3
- package/src/animation/demos/color-interpolation.tsx +1 -1
- package/src/animation/demos/reordering.tsx +9 -6
- 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 +164 -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/dev/refresh.ts +1 -0
- package/src/index.ts +1 -1
- 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/{components/menu → menu}/README.md +55 -14
- package/src/menu/index.tsx +354 -0
- package/src/{components/menu/menu.tsx → menu/primitives.tsx} +99 -413
- package/src/{components/popover → popover}/README.md +20 -39
- package/src/{components/popover/popover.ts → popover/index.ts} +3 -57
- package/src/{utils → popover}/scroll-lock.ts +0 -28
- package/src/radio/README.md +53 -0
- package/src/radio/index.ts +101 -0
- package/src/runtime/client-entry-boundary.ts +54 -0
- package/src/runtime/component.ts +65 -16
- package/src/runtime/core/attributes.ts +35 -1
- package/src/runtime/core/children.ts +24 -2
- package/src/runtime/core/vnode.ts +25 -4
- package/src/runtime/create-element.ts +6 -5
- package/src/runtime/demos/readme.demo.tsx +20 -18
- package/src/runtime/diff-dom.ts +358 -243
- package/src/runtime/dom.ts +331 -214
- package/src/runtime/element-function.ts +1 -0
- package/src/runtime/event-listeners.ts +1 -1
- package/src/runtime/form-navigation.ts +184 -0
- package/src/runtime/frame-resolution.ts +13 -0
- package/src/runtime/frame.ts +482 -124
- package/src/runtime/jsx.ts +3 -5
- package/src/runtime/key.ts +1 -0
- package/src/runtime/mixins/link-mixin.ts +1 -0
- package/src/runtime/mixins/mixin.ts +21 -18
- package/src/runtime/navigation.ts +204 -30
- package/src/runtime/reconcile.ts +769 -760
- package/src/runtime/refresh.ts +46 -0
- package/src/runtime/run.ts +12 -2
- package/src/runtime/scheduler.ts +9 -29
- package/src/runtime/to-vnode.ts +85 -23
- package/src/runtime/vdom.ts +91 -69
- package/src/runtime/vnode.ts +192 -88
- 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} +10 -98
- package/src/server/stream.ts +25 -31
- 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 +25 -6
- package/src/style/stylesheet.ts +32 -57
- package/src/tabs/README.md +141 -0
- package/src/tabs/index.tsx +245 -0
- package/src/tabs/primitives.ts +365 -0
- package/src/test/README.md +151 -60
- package/src/toggle/README.md +56 -0
- package/src/toggle/index.tsx +136 -0
- package/src/toggle/primitives.ts +192 -0
- package/dist/animation/demos/animation.demo.d.ts +0 -5
- package/dist/animation/demos/animation.demo.js +0 -92
- package/dist/animation/demos/animation.demo.js.map +0 -1
- package/dist/animation/demos/spring.demo.d.ts +0 -6
- package/dist/animation/demos/spring.demo.js +0 -304
- package/dist/animation/demos/spring.demo.js.map +0 -1
- 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 -7
- package/dist/components/accordion/demos/card.demo.js +0 -59
- package/dist/components/accordion/demos/card.demo.js.map +0 -1
- package/dist/components/accordion/demos/multiple.demo.d.ts +0 -7
- package/dist/components/accordion/demos/multiple.demo.js +0 -20
- package/dist/components/accordion/demos/multiple.demo.js.map +0 -1
- package/dist/components/accordion/demos/overview.demo.d.ts +0 -7
- package/dist/components/accordion/demos/overview.demo.js +0 -20
- package/dist/components/accordion/demos/overview.demo.js.map +0 -1
- package/dist/components/anchor/anchor.js.map +0 -1
- package/dist/components/breadcrumbs/basic.demo.d.ts +0 -6
- package/dist/components/breadcrumbs/basic.demo.js +0 -15
- package/dist/components/breadcrumbs/basic.demo.js.map +0 -1
- package/dist/components/breadcrumbs/breadcrumbs.js.map +0 -1
- package/dist/components/breadcrumbs/separator.demo.d.ts +0 -6
- package/dist/components/breadcrumbs/separator.demo.js +0 -15
- package/dist/components/breadcrumbs/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 -7
- package/dist/components/button/demos/aliases.demo.js +0 -19
- package/dist/components/button/demos/aliases.demo.js.map +0 -1
- package/dist/components/button/demos/basic.demo.d.ts +0 -7
- package/dist/components/button/demos/basic.demo.js +0 -20
- package/dist/components/button/demos/basic.demo.js.map +0 -1
- package/dist/components/button/demos/states.demo.d.ts +0 -7
- package/dist/components/button/demos/states.demo.js +0 -30
- package/dist/components/button/demos/states.demo.js.map +0 -1
- package/dist/components/combobox/combobox.js.map +0 -1
- package/dist/components/combobox/overview.demo.d.ts +0 -7
- package/dist/components/combobox/overview.demo.js +0 -154
- package/dist/components/combobox/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/listbox.js.map +0 -1
- package/dist/components/listbox/overview.demo.d.ts +0 -7
- package/dist/components/listbox/overview.demo.js +0 -65
- package/dist/components/listbox/overview.demo.js.map +0 -1
- package/dist/components/menu/demos/bubbling.demo.d.ts +0 -6
- package/dist/components/menu/demos/bubbling.demo.js +0 -16
- package/dist/components/menu/demos/bubbling.demo.js.map +0 -1
- package/dist/components/menu/demos/context-trigger.demo.d.ts +0 -7
- package/dist/components/menu/demos/context-trigger.demo.js +0 -87
- package/dist/components/menu/demos/context-trigger.demo.js.map +0 -1
- package/dist/components/menu/demos/overview.demo.d.ts +0 -7
- package/dist/components/menu/demos/overview.demo.js +0 -33
- 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/overview.demo.d.ts +0 -7
- package/dist/components/popover/overview.demo.js +0 -65
- package/dist/components/popover/overview.demo.js.map +0 -1
- package/dist/components/popover/popover.js.map +0 -1
- package/dist/components/select/deconstructed.demo.d.ts +0 -7
- package/dist/components/select/deconstructed.demo.js +0 -54
- package/dist/components/select/deconstructed.demo.js.map +0 -1
- package/dist/components/select/overview.demo.d.ts +0 -6
- package/dist/components/select/overview.demo.js +0 -28
- package/dist/components/select/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/runtime/demos/basic.demo.d.ts +0 -6
- package/dist/runtime/demos/basic.demo.js +0 -16
- package/dist/runtime/demos/basic.demo.js.map +0 -1
- package/dist/runtime/demos/controlled-uncontrolled-values.demo.d.ts +0 -6
- package/dist/runtime/demos/controlled-uncontrolled-values.demo.js +0 -77
- package/dist/runtime/demos/controlled-uncontrolled-values.demo.js.map +0 -1
- package/dist/runtime/demos/keyed-list.demo.d.ts +0 -6
- package/dist/runtime/demos/keyed-list.demo.js +0 -62
- package/dist/runtime/demos/keyed-list.demo.js.map +0 -1
- package/dist/runtime/demos/readme.demo.d.ts +0 -5
- package/dist/runtime/demos/readme.demo.js +0 -396
- package/dist/runtime/demos/readme.demo.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 +0 -119
- 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/animation/demos/animation.demo.tsx +0 -194
- package/src/animation/demos/spring.demo.tsx +0 -385
- package/src/components/accordion/accordion.tsx +0 -565
- package/src/components/accordion/demos/card.demo.tsx +0 -114
- package/src/components/accordion/demos/multiple.demo.tsx +0 -57
- package/src/components/accordion/demos/overview.demo.tsx +0 -57
- package/src/components/breadcrumbs/basic.demo.tsx +0 -18
- package/src/components/breadcrumbs/separator.demo.tsx +0 -19
- 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 -28
- package/src/components/button/demos/basic.demo.tsx +0 -31
- package/src/components/button/demos/states.demo.tsx +0 -53
- package/src/components/combobox/overview.demo.tsx +0 -200
- package/src/components/glyph/README.md +0 -72
- package/src/components/glyph/glyph.tsx +0 -110
- package/src/components/listbox/overview.demo.tsx +0 -102
- package/src/components/menu/demos/bubbling.demo.tsx +0 -35
- package/src/components/menu/demos/context-trigger.demo.tsx +0 -133
- package/src/components/menu/demos/overview.demo.tsx +0 -77
- package/src/components/popover/overview.demo.tsx +0 -144
- package/src/components/select/deconstructed.demo.tsx +0 -96
- package/src/components/select/overview.demo.tsx +0 -52
- 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/runtime/demos/basic.demo.tsx +0 -21
- package/src/runtime/demos/controlled-uncontrolled-values.demo.tsx +0 -177
- package/src/runtime/demos/keyed-list.demo.tsx +0 -94
- 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/anchor/anchor.d.ts → anchor/index.d.ts} +0 -0
- /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/{components/anchor/anchor.ts → anchor/index.ts} +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
|
@@ -1,22 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
attrs,
|
|
3
3
|
createMixin,
|
|
4
|
-
css,
|
|
5
4
|
on,
|
|
6
|
-
type CSSMixinDescriptor,
|
|
7
5
|
type ElementProps,
|
|
8
6
|
type Handle,
|
|
9
7
|
type MixinFactory,
|
|
10
8
|
type RemixNode,
|
|
11
9
|
} from '@remix-run/ui'
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
type AnchorTarget,
|
|
16
|
-
} from '../anchor/anchor.ts'
|
|
17
|
-
import { onOutsideClick } from '../../interactions/outside-click/outside-click-mixin.ts'
|
|
18
|
-
import { theme } from '../../theme/theme.ts'
|
|
19
|
-
import { lockScroll } from '../../utils/scroll-lock.ts'
|
|
10
|
+
import { anchor as positionAnchor, type AnchorOptions, type AnchorTarget } from '../anchor/index.ts'
|
|
11
|
+
import { onOutsideClick } from './outside-click.ts'
|
|
12
|
+
import { lockScroll } from './scroll-lock.ts'
|
|
20
13
|
|
|
21
14
|
export interface PopoverContext {
|
|
22
15
|
hideFocusTarget: HTMLElement | null
|
|
@@ -34,53 +27,6 @@ interface AnchorRef {
|
|
|
34
27
|
options: AnchorOptions
|
|
35
28
|
}
|
|
36
29
|
|
|
37
|
-
const popupViewportClampMaxHeight = '50dvh'
|
|
38
|
-
|
|
39
|
-
const popoverSurfaceTransitionCss: CSSMixinDescriptor = css({
|
|
40
|
-
opacity: 0,
|
|
41
|
-
'&:popover-open': {
|
|
42
|
-
opacity: 1,
|
|
43
|
-
},
|
|
44
|
-
'&:not(:popover-open)': {
|
|
45
|
-
pointerEvents: 'none',
|
|
46
|
-
transition: 'opacity 180ms ease-in, overlay 180ms ease-in, display 180ms ease-in',
|
|
47
|
-
transitionBehavior: 'allow-discrete',
|
|
48
|
-
},
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
const popoverContentCss: CSSMixinDescriptor = css({
|
|
52
|
-
flex: '1 1 auto',
|
|
53
|
-
minHeight: 0,
|
|
54
|
-
padding: theme.space.xs,
|
|
55
|
-
overflow: 'auto',
|
|
56
|
-
overscrollBehavior: 'contain',
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
const popoverSurfaceCss: CSSMixinDescriptor = css({
|
|
60
|
-
position: 'fixed',
|
|
61
|
-
inset: 'auto',
|
|
62
|
-
margin: 0,
|
|
63
|
-
padding: theme.space.none,
|
|
64
|
-
display: 'flex',
|
|
65
|
-
flexDirection: 'column',
|
|
66
|
-
minHeight: 0,
|
|
67
|
-
minWidth: '12rem',
|
|
68
|
-
maxWidth: `min(24rem, calc(100vw - (${theme.space.lg} * 2)))`,
|
|
69
|
-
maxHeight: popupViewportClampMaxHeight,
|
|
70
|
-
border: `1px solid ${theme.colors.border.subtle}`,
|
|
71
|
-
borderRadius: theme.radius.lg,
|
|
72
|
-
backgroundColor: theme.surface.lvl0,
|
|
73
|
-
color: theme.colors.text.primary,
|
|
74
|
-
overflow: 'hidden',
|
|
75
|
-
boxShadow: `${theme.shadow.xs}, ${theme.shadow.md}`,
|
|
76
|
-
'&::backdrop': {
|
|
77
|
-
background: 'transparent',
|
|
78
|
-
},
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
export const contentStyle = popoverContentCss
|
|
82
|
-
export const surfaceStyle = [popoverSurfaceCss, popoverSurfaceTransitionCss] as const
|
|
83
|
-
|
|
84
30
|
function PopoverProvider(handle: Handle<PopoverProps, PopoverContext>): () => RemixNode {
|
|
85
31
|
handle.context.set({
|
|
86
32
|
hideFocusTarget: null,
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { createMixin, on, type ElementProps, type MixinFactory } from '@remix-run/ui'
|
|
2
|
-
|
|
3
1
|
type ScrollLockState = {
|
|
4
2
|
count: number
|
|
5
3
|
documentOverflow: string
|
|
@@ -73,29 +71,3 @@ export function lockScroll(targetDocument: Document | undefined = globalThis.doc
|
|
|
73
71
|
view.scrollTo(currentState.scrollX, currentState.scrollY)
|
|
74
72
|
}
|
|
75
73
|
}
|
|
76
|
-
|
|
77
|
-
export const lockScrollOnToggle: MixinFactory<HTMLElement, [], ElementProps> = createMixin<
|
|
78
|
-
HTMLElement,
|
|
79
|
-
[],
|
|
80
|
-
ElementProps
|
|
81
|
-
>((handle) => {
|
|
82
|
-
let unlockScroll = () => {}
|
|
83
|
-
|
|
84
|
-
handle.signal.addEventListener('abort', () => {
|
|
85
|
-
unlockScroll()
|
|
86
|
-
unlockScroll = () => {}
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
return () => [
|
|
90
|
-
on('beforetoggle', (event) => {
|
|
91
|
-
unlockScroll()
|
|
92
|
-
unlockScroll = () => {}
|
|
93
|
-
|
|
94
|
-
if (event.newState !== 'open') {
|
|
95
|
-
return
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
unlockScroll = lockScroll((event.currentTarget as HTMLElement).ownerDocument)
|
|
99
|
-
}),
|
|
100
|
-
]
|
|
101
|
-
})
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# radio
|
|
2
|
+
|
|
3
|
+
`radio` is a style mixin for native radio inputs. It only owns radio visuals and the default `type="radio"` behavior for native `<input>` hosts.
|
|
4
|
+
|
|
5
|
+
## Primitive Usage
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import radio from 'remix/ui/radio'
|
|
9
|
+
|
|
10
|
+
function ShippingSpeed() {
|
|
11
|
+
return () => (
|
|
12
|
+
<fieldset>
|
|
13
|
+
<label>
|
|
14
|
+
<input defaultChecked mix={radio()} name="shipping-speed" value="standard" />
|
|
15
|
+
Standard
|
|
16
|
+
</label>
|
|
17
|
+
<label>
|
|
18
|
+
<input mix={radio({ size: 'lg' })} name="shipping-speed" value="express" />
|
|
19
|
+
Express
|
|
20
|
+
</label>
|
|
21
|
+
</fieldset>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Compose app-owned styles around the primitive when a radio option needs local layout:
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import radio from 'remix/ui/radio'
|
|
30
|
+
import { optionStyle } from './shipping.styles'
|
|
31
|
+
|
|
32
|
+
function ShippingOption() {
|
|
33
|
+
return () => (
|
|
34
|
+
<label mix={optionStyle}>
|
|
35
|
+
<input mix={radio()} name="shipping-speed" value="overnight" />
|
|
36
|
+
Overnight
|
|
37
|
+
</label>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## `remix/ui/radio`
|
|
43
|
+
|
|
44
|
+
- `radio(options)`: style mixin for native radio inputs or radio-like hosts.
|
|
45
|
+
- `RadioOptions`: accepts `size`.
|
|
46
|
+
- `RadioSize`: `'md'` or `'lg'`. Defaults to `'md'`.
|
|
47
|
+
|
|
48
|
+
## Behavior Notes
|
|
49
|
+
|
|
50
|
+
- `radio()` returns a mixin descriptor, so it composes with other mixins in the host element's `mix` prop.
|
|
51
|
+
- Native `<input>` hosts receive `type="radio"` unless an explicit `type` is provided.
|
|
52
|
+
- Radio state is native browser behavior. The mixin also styles `aria-checked="true"` and `data-state="checked"` for custom hosts.
|
|
53
|
+
- Disabled hosts use the shared disabled treatment through `disabled` or `aria-disabled="true"`.
|
|
@@ -0,0 +1,101 @@
|
|
|
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 RadioSize = 'md' | 'lg'
|
|
7
|
+
|
|
8
|
+
export interface RadioOptions {
|
|
9
|
+
size?: RadioSize
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type RadioMixin = readonly [
|
|
13
|
+
MixinDescriptor<Element, [], ElementProps>,
|
|
14
|
+
CSSMixinDescriptor,
|
|
15
|
+
CSSMixinDescriptor,
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
const checkedSelector = '&:checked, &[aria-checked="true"], &[data-state="checked"]'
|
|
19
|
+
const checkedMarkSelector =
|
|
20
|
+
'&:checked::before, &[aria-checked="true"]::before, &[data-state="checked"]::before'
|
|
21
|
+
|
|
22
|
+
const radioDefaultAttrs = createMixin<Element, [], ElementProps>((handle, hostType) => (props) => {
|
|
23
|
+
if (hostType !== 'input' || props.type !== undefined) {
|
|
24
|
+
return handle.element
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return renderMixinElement(handle.element, {
|
|
28
|
+
...props,
|
|
29
|
+
type: 'radio',
|
|
30
|
+
})
|
|
31
|
+
})()
|
|
32
|
+
|
|
33
|
+
const baseStyle: CSSMixinDescriptor = css({
|
|
34
|
+
appearance: 'none',
|
|
35
|
+
WebkitAppearance: 'none',
|
|
36
|
+
margin: 0,
|
|
37
|
+
boxSizing: 'border-box',
|
|
38
|
+
position: 'relative',
|
|
39
|
+
display: 'inline-grid',
|
|
40
|
+
placeItems: 'center',
|
|
41
|
+
width: 'var(--rmx-radio-size)',
|
|
42
|
+
height: 'var(--rmx-radio-size)',
|
|
43
|
+
minWidth: 'var(--rmx-radio-size)',
|
|
44
|
+
minHeight: 'var(--rmx-radio-size)',
|
|
45
|
+
padding: 0,
|
|
46
|
+
border: '1px solid light-dark(rgba(0, 0, 0, 0.12), rgba(255, 255, 255, 0.2))',
|
|
47
|
+
borderRadius: '9999px',
|
|
48
|
+
background: 'light-dark(#FFFFFF, #1a1a1a)',
|
|
49
|
+
boxShadow: 'inset 0 1px 1px rgba(0, 0, 0, 0.06), inset 0 2px 2px rgba(0, 0, 0, 0.06)',
|
|
50
|
+
verticalAlign: 'middle',
|
|
51
|
+
flex: 'none',
|
|
52
|
+
'&::before': {
|
|
53
|
+
content: '""',
|
|
54
|
+
width: 'var(--rmx-radio-mark-size)',
|
|
55
|
+
height: 'var(--rmx-radio-mark-size)',
|
|
56
|
+
borderRadius: '99px',
|
|
57
|
+
background:
|
|
58
|
+
'linear-gradient(180deg, rgba(53, 115, 246, 0) 25%, rgba(53, 115, 246, 0.15) 100%), light-dark(#FFFFFF, #f5f9ff)',
|
|
59
|
+
boxShadow:
|
|
60
|
+
'0 1px 1px -0.5px #0944BE, 0 2px 2px -1px #0944BE, 0 4px 4px -2px #0944BE, 0 0 1px 1px light-dark(rgba(0, 0, 0, 0.25), rgba(255, 255, 255, 0.28)), inset 0 0 2px 1px light-dark(#FFFFFF, rgba(255, 255, 255, 0.5))',
|
|
61
|
+
opacity: 0,
|
|
62
|
+
pointerEvents: 'none',
|
|
63
|
+
},
|
|
64
|
+
'&:disabled, &[aria-disabled="true"]': {
|
|
65
|
+
opacity: 0.55,
|
|
66
|
+
},
|
|
67
|
+
[checkedSelector]: {
|
|
68
|
+
border: 0,
|
|
69
|
+
borderRadius: '99px',
|
|
70
|
+
background:
|
|
71
|
+
'linear-gradient(180deg, light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.16)) 0%, rgba(0, 0, 0, 0) 75.48%), light-dark(#3573F6, #6eaaff)',
|
|
72
|
+
backgroundBlendMode: 'overlay, normal',
|
|
73
|
+
boxShadow:
|
|
74
|
+
'0 1px 0 rgba(255, 255, 255, 0.6), 0 0 16px rgba(53, 115, 246, 0.25), inset 0 0 3px 1px rgba(0, 0, 0, 0.1)',
|
|
75
|
+
},
|
|
76
|
+
[checkedMarkSelector]: {
|
|
77
|
+
opacity: 1,
|
|
78
|
+
},
|
|
79
|
+
'&:focus-visible': {
|
|
80
|
+
outline: 0,
|
|
81
|
+
boxShadow: controlFocusShadow,
|
|
82
|
+
},
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
const sizeStyles = {
|
|
86
|
+
md: css({
|
|
87
|
+
'--rmx-radio-size': '16px',
|
|
88
|
+
'--rmx-radio-mark-size': '8px',
|
|
89
|
+
}),
|
|
90
|
+
lg: css({
|
|
91
|
+
'--rmx-radio-size': '20px',
|
|
92
|
+
'--rmx-radio-mark-size': '10px',
|
|
93
|
+
}),
|
|
94
|
+
} as const satisfies Record<RadioSize, CSSMixinDescriptor>
|
|
95
|
+
|
|
96
|
+
export function radio(options: RadioOptions = {}): RadioMixin {
|
|
97
|
+
let { size = 'md' } = options
|
|
98
|
+
return [radioDefaultAttrs, baseStyle, sizeStyles[size]]
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export default radio
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { VirtualRoot } from './vdom.ts'
|
|
2
|
+
|
|
3
|
+
export type ClientEntryIdentity = {
|
|
4
|
+
moduleUrl: string
|
|
5
|
+
exportName: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
type ClientEntryRoot = Pick<VirtualRoot, 'dispose' | 'render'>
|
|
9
|
+
|
|
10
|
+
export type ClientEntryBoundaryOwner = {
|
|
11
|
+
identity: ClientEntryIdentity
|
|
12
|
+
root: ClientEntryRoot
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const CLIENT_ENTRY_BOUNDARY_OWNER = Symbol('ClientEntryBoundaryOwner')
|
|
16
|
+
|
|
17
|
+
type ClientEntryBoundaryMarker = Comment & {
|
|
18
|
+
[CLIENT_ENTRY_BOUNDARY_OWNER]?: ClientEntryBoundaryOwner
|
|
19
|
+
$rmx?: ClientEntryRoot
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function getClientEntryBoundaryOwner(marker: Comment): ClientEntryBoundaryOwner | undefined {
|
|
23
|
+
return (marker as ClientEntryBoundaryMarker)[CLIENT_ENTRY_BOUNDARY_OWNER]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function setClientEntryBoundaryOwner(
|
|
27
|
+
marker: Comment,
|
|
28
|
+
identity: ClientEntryIdentity,
|
|
29
|
+
root: ClientEntryRoot,
|
|
30
|
+
): ClientEntryBoundaryOwner {
|
|
31
|
+
let owner = { identity, root }
|
|
32
|
+
Object.defineProperties(marker, {
|
|
33
|
+
[CLIENT_ENTRY_BOUNDARY_OWNER]: {
|
|
34
|
+
configurable: true,
|
|
35
|
+
value: owner,
|
|
36
|
+
},
|
|
37
|
+
$rmx: {
|
|
38
|
+
configurable: true,
|
|
39
|
+
value: root,
|
|
40
|
+
},
|
|
41
|
+
})
|
|
42
|
+
return owner
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function disposeClientEntryBoundary(marker: Comment): boolean {
|
|
46
|
+
let boundaryMarker = marker as ClientEntryBoundaryMarker
|
|
47
|
+
let owner = boundaryMarker[CLIENT_ENTRY_BOUNDARY_OWNER]
|
|
48
|
+
if (!owner) return false
|
|
49
|
+
|
|
50
|
+
delete boundaryMarker[CLIENT_ENTRY_BOUNDARY_OWNER]
|
|
51
|
+
delete boundaryMarker.$rmx
|
|
52
|
+
owner.root.dispose()
|
|
53
|
+
return true
|
|
54
|
+
}
|
package/src/runtime/component.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ElementProps, ElementType, RemixNode, Renderable } from './jsx.ts'
|
|
2
|
+
import type { ElementFunction } from './element-function.ts'
|
|
3
|
+
import type { Key } from './key.ts'
|
|
2
4
|
import { TypedEventTarget } from './typed-event-target.ts'
|
|
3
5
|
|
|
4
6
|
/**
|
|
@@ -138,6 +140,14 @@ export interface Context<C> {
|
|
|
138
140
|
*/
|
|
139
141
|
export type FrameContent = ReadableStream<Uint8Array> | string | RemixNode
|
|
140
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Value returned by a browser frame resolver.
|
|
145
|
+
*
|
|
146
|
+
* A response body is rendered as frame content. When `fetch()` followed a redirect, the response's
|
|
147
|
+
* final URL updates the frame source and browser URL for a top-frame navigation.
|
|
148
|
+
*/
|
|
149
|
+
export type FrameResolution = FrameContent | Response
|
|
150
|
+
|
|
141
151
|
/**
|
|
142
152
|
* Events emitted by frame handles during reloads.
|
|
143
153
|
*/
|
|
@@ -208,18 +218,26 @@ export interface BuiltinElements {
|
|
|
208
218
|
/**
|
|
209
219
|
* Key type used to stabilize host elements and components during reconciliation.
|
|
210
220
|
*/
|
|
211
|
-
export type Key
|
|
221
|
+
export type { Key } from './key.ts'
|
|
212
222
|
|
|
213
223
|
type ComponentConfig = {
|
|
214
224
|
id: string
|
|
215
|
-
type:
|
|
225
|
+
type: ElementFunction
|
|
216
226
|
frame: FrameHandle
|
|
217
|
-
getContext: (type:
|
|
227
|
+
getContext: (type: ElementFunction) => unknown
|
|
218
228
|
getFrameByName: (name: string) => FrameHandle | undefined
|
|
219
229
|
getTopFrame?: () => FrameHandle | undefined
|
|
220
230
|
signal?: AbortSignal
|
|
221
231
|
}
|
|
222
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Minimal structural view of the scheduler used for handle.update() so this
|
|
235
|
+
* module doesn't depend on the reconciler.
|
|
236
|
+
*/
|
|
237
|
+
export interface UpdateQueue {
|
|
238
|
+
enqueue(vnode: object, domParent: ParentNode): void
|
|
239
|
+
}
|
|
240
|
+
|
|
223
241
|
/**
|
|
224
242
|
* Runtime handle returned by {@link createComponent}.
|
|
225
243
|
*/
|
|
@@ -227,7 +245,7 @@ export interface ComponentHandle<C = NoContext> {
|
|
|
227
245
|
frame: FrameHandle
|
|
228
246
|
render(nextProps: ElementProps): [RemixNode, Array<() => void>]
|
|
229
247
|
remove(): Array<() => void>
|
|
230
|
-
setScheduleUpdate(
|
|
248
|
+
setScheduleUpdate(queue: UpdateQueue, vnode: object, domParent: ParentNode): void
|
|
231
249
|
getContextValue(): C | undefined
|
|
232
250
|
isRemoved(): boolean
|
|
233
251
|
}
|
|
@@ -249,12 +267,22 @@ class ComponentRuntime<C = NoContext> implements ComponentHandle<C> {
|
|
|
249
267
|
#connectedController: AbortController | undefined
|
|
250
268
|
#contextValue: C | undefined
|
|
251
269
|
#handle: Handle<ElementProps, C>
|
|
252
|
-
#props = {}
|
|
270
|
+
#props: ElementProps = {}
|
|
253
271
|
#renderController: AbortController | undefined
|
|
254
272
|
#renderFn: RenderFn | undefined
|
|
255
273
|
#removed = false
|
|
256
|
-
|
|
257
|
-
|
|
274
|
+
// The schedule target is stored as fields (updated each render) rather than
|
|
275
|
+
// a closure so re-renders don't allocate a new function per component.
|
|
276
|
+
#updateQueue: UpdateQueue | undefined
|
|
277
|
+
#updateVNode: object | undefined
|
|
278
|
+
#updateDomParent: ParentNode | undefined
|
|
279
|
+
#scheduleUpdate = (): void => {
|
|
280
|
+
let queue = this.#updateQueue
|
|
281
|
+
if (!queue) throw new Error('scheduleUpdate not implemented')
|
|
282
|
+
let vnode = this.#updateVNode
|
|
283
|
+
let domParent = this.#updateDomParent
|
|
284
|
+
if (!vnode || !domParent) throw new Error('scheduleUpdate target not initialized')
|
|
285
|
+
queue.enqueue(vnode, domParent)
|
|
258
286
|
}
|
|
259
287
|
#tasks: Task[] = []
|
|
260
288
|
|
|
@@ -276,14 +304,15 @@ class ComponentRuntime<C = NoContext> implements ComponentHandle<C> {
|
|
|
276
304
|
let renderFn = this.#renderFn
|
|
277
305
|
|
|
278
306
|
if (renderFn === undefined) {
|
|
279
|
-
let
|
|
307
|
+
let initialize = this.#config.type as unknown as (handle: Handle<ElementProps, C>) => unknown
|
|
308
|
+
let result = initialize(this.#handle)
|
|
280
309
|
|
|
281
|
-
if (
|
|
310
|
+
if (!isRenderFn(result)) {
|
|
282
311
|
let name = this.#config.type.name || 'Anonymous'
|
|
283
312
|
throw new Error(`${name} must return a render function, received ${typeof result}`)
|
|
284
313
|
}
|
|
285
314
|
|
|
286
|
-
renderFn = result
|
|
315
|
+
renderFn = result
|
|
287
316
|
this.#renderFn = renderFn
|
|
288
317
|
}
|
|
289
318
|
|
|
@@ -291,15 +320,18 @@ class ComponentRuntime<C = NoContext> implements ComponentHandle<C> {
|
|
|
291
320
|
}
|
|
292
321
|
|
|
293
322
|
remove = (): Array<() => void> => {
|
|
294
|
-
if (this.#removed) return
|
|
323
|
+
if (this.#removed) return EMPTY_TASKS
|
|
295
324
|
this.#removed = true
|
|
296
325
|
this.#connectedController?.abort()
|
|
297
326
|
this.#abortRenderSignal()
|
|
298
|
-
|
|
327
|
+
if (this.#tasks.length === 0) return EMPTY_TASKS
|
|
328
|
+
return this.#dequeueTasks((sharedAbortedSignal ??= AbortSignal.abort()))
|
|
299
329
|
}
|
|
300
330
|
|
|
301
|
-
setScheduleUpdate = (
|
|
302
|
-
this.#
|
|
331
|
+
setScheduleUpdate = (queue: UpdateQueue, vnode: object, domParent: ParentNode): void => {
|
|
332
|
+
this.#updateQueue = queue
|
|
333
|
+
this.#updateVNode = vnode
|
|
334
|
+
this.#updateDomParent = domParent
|
|
303
335
|
}
|
|
304
336
|
|
|
305
337
|
getContextValue = (): C | undefined => this.#contextValue
|
|
@@ -312,7 +344,8 @@ class ComponentRuntime<C = NoContext> implements ComponentHandle<C> {
|
|
|
312
344
|
set: (value: C) => {
|
|
313
345
|
this.#contextValue = value
|
|
314
346
|
},
|
|
315
|
-
get: (type: ElementType | symbol) =>
|
|
347
|
+
get: (type: ElementType | symbol) =>
|
|
348
|
+
isElementFunction(type) ? this.#config.getContext(type) : undefined,
|
|
316
349
|
}
|
|
317
350
|
|
|
318
351
|
return {
|
|
@@ -358,6 +391,8 @@ class ComponentRuntime<C = NoContext> implements ComponentHandle<C> {
|
|
|
358
391
|
}
|
|
359
392
|
|
|
360
393
|
#dequeueTasks(signal?: AbortSignal): Array<() => void> {
|
|
394
|
+
if (this.#tasks.length === 0) return EMPTY_TASKS
|
|
395
|
+
|
|
361
396
|
let needsSignal = signal === undefined && this.#tasks.some((task) => task.length >= 1)
|
|
362
397
|
|
|
363
398
|
if (needsSignal) {
|
|
@@ -365,11 +400,25 @@ class ComponentRuntime<C = NoContext> implements ComponentHandle<C> {
|
|
|
365
400
|
}
|
|
366
401
|
|
|
367
402
|
signal ??= this.#renderController?.signal
|
|
403
|
+
signal ??= sharedAbortedSignal ??= AbortSignal.abort()
|
|
368
404
|
let tasks = this.#tasks.splice(0, this.#tasks.length)
|
|
369
|
-
return tasks.map((task) => () => task(signal
|
|
405
|
+
return tasks.map((task) => () => task(signal))
|
|
370
406
|
}
|
|
371
407
|
}
|
|
372
408
|
|
|
409
|
+
function isRenderFn(value: unknown): value is RenderFn {
|
|
410
|
+
return typeof value === 'function'
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function isElementFunction(value: unknown): value is ElementFunction {
|
|
414
|
+
return typeof value === 'function'
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Shared empty result and aborted signal so the common no-task removal path
|
|
418
|
+
// (large subtree teardowns dispose many components at once) allocates nothing.
|
|
419
|
+
const EMPTY_TASKS: Array<() => void> = []
|
|
420
|
+
let sharedAbortedSignal: AbortSignal | undefined
|
|
421
|
+
|
|
373
422
|
function syncProps(target: ElementProps, next: ElementProps): void {
|
|
374
423
|
for (let key in target) {
|
|
375
424
|
if (!(key in next)) {
|
|
@@ -62,10 +62,31 @@ export function canUseProperty(
|
|
|
62
62
|
return name in element
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
// Prop names repeat constantly across elements and renders; cache the
|
|
66
|
+
// normalized results so the string work and object allocation happen once
|
|
67
|
+
// per distinct name. Entries are shared — callers must not mutate them.
|
|
68
|
+
const NORMALIZATION_CACHE_LIMIT = 256
|
|
69
|
+
const htmlAttributeNameCache = new Map<string, { ns?: string; attr: string }>()
|
|
70
|
+
const svgAttributeNameCache = new Map<string, { ns?: string; attr: string }>()
|
|
71
|
+
|
|
65
72
|
export function normalizeAttributeName(
|
|
66
73
|
name: string,
|
|
67
74
|
isSvg: boolean,
|
|
68
75
|
): { ns?: string; attr: string } {
|
|
76
|
+
let cache = isSvg ? svgAttributeNameCache : htmlAttributeNameCache
|
|
77
|
+
let cached = cache.get(name)
|
|
78
|
+
if (cached === undefined) {
|
|
79
|
+
cached = computeAttributeName(name, isSvg)
|
|
80
|
+
if (cache.size >= NORMALIZATION_CACHE_LIMIT) {
|
|
81
|
+
let oldest = cache.keys().next()
|
|
82
|
+
if (!oldest.done) cache.delete(oldest.value)
|
|
83
|
+
}
|
|
84
|
+
cache.set(name, cached)
|
|
85
|
+
}
|
|
86
|
+
return cached
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function computeAttributeName(name: string, isSvg: boolean): { ns?: string; attr: string } {
|
|
69
90
|
if (name.startsWith('aria-') || name.startsWith('data-')) return { attr: name }
|
|
70
91
|
|
|
71
92
|
if (name === 'className') return { attr: 'class' }
|
|
@@ -113,6 +134,19 @@ export function getMergedClassName(props: ElementProps): string | undefined {
|
|
|
113
134
|
return merged || undefined
|
|
114
135
|
}
|
|
115
136
|
|
|
137
|
+
// Style/attribute names come from a small recurring set, so cache conversions
|
|
138
|
+
// instead of running a regex per property per element per render.
|
|
139
|
+
const kebabCaseCache = new Map<string, string>()
|
|
140
|
+
|
|
116
141
|
export function toKebabCase(value: string): string {
|
|
117
|
-
|
|
142
|
+
let cached = kebabCaseCache.get(value)
|
|
143
|
+
if (cached === undefined) {
|
|
144
|
+
cached = value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`)
|
|
145
|
+
if (kebabCaseCache.size >= NORMALIZATION_CACHE_LIMIT) {
|
|
146
|
+
let oldest = kebabCaseCache.keys().next()
|
|
147
|
+
if (!oldest.done) kebabCaseCache.delete(oldest.value)
|
|
148
|
+
}
|
|
149
|
+
kebabCaseCache.set(value, cached)
|
|
150
|
+
}
|
|
151
|
+
return cached
|
|
118
152
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { RemixNode } from '../jsx.ts'
|
|
2
|
+
import { invariant } from '../invariant.ts'
|
|
3
|
+
import { isRemixElement } from './vnode.ts'
|
|
2
4
|
|
|
3
5
|
export type EmptyChild = boolean | null | undefined
|
|
4
6
|
export type PrimitiveChild = string | number | bigint
|
|
@@ -13,8 +15,8 @@ export function isPrimitiveChild(value: RemixNode): value is PrimitiveChild {
|
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export function normalizeChildren(children: readonly RemixNode[]): RemixNode[] {
|
|
16
|
-
for (let
|
|
17
|
-
if (Array.isArray(
|
|
18
|
+
for (let i = 0; i < children.length; i++) {
|
|
19
|
+
if (Array.isArray(children[i])) {
|
|
18
20
|
return (children as unknown[]).flat(Infinity) as RemixNode[]
|
|
19
21
|
}
|
|
20
22
|
}
|
|
@@ -22,6 +24,26 @@ export function normalizeChildren(children: readonly RemixNode[]): RemixNode[] {
|
|
|
22
24
|
return children as RemixNode[]
|
|
23
25
|
}
|
|
24
26
|
|
|
27
|
+
export function assertRemixNodes(values: readonly unknown[]): asserts values is RemixNode[] {
|
|
28
|
+
for (let value of values) {
|
|
29
|
+
invariant(isRemixNode(value), 'Invalid child node')
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function isRemixNode(value: unknown): value is RemixNode {
|
|
34
|
+
if (value == null) return true
|
|
35
|
+
let type = typeof value
|
|
36
|
+
if (type === 'string' || type === 'number' || type === 'bigint' || type === 'boolean') {
|
|
37
|
+
return true
|
|
38
|
+
}
|
|
39
|
+
if (isRemixElement(value)) return true
|
|
40
|
+
if (!Array.isArray(value)) return false
|
|
41
|
+
for (let child of value) {
|
|
42
|
+
if (!isRemixNode(child)) return false
|
|
43
|
+
}
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
|
|
25
47
|
export function packChildren(children: readonly RemixNode[]): RemixNode | undefined {
|
|
26
48
|
if (children.length === 0) {
|
|
27
49
|
return undefined
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { ElementProps, ElementType, RemixElement
|
|
1
|
+
import type { ElementProps, ElementType, RemixElement } from '../jsx.ts'
|
|
2
2
|
|
|
3
3
|
export function createRemixElement(
|
|
4
4
|
type: ElementType,
|
|
5
5
|
props: ElementProps | null | undefined,
|
|
6
|
-
key?:
|
|
6
|
+
key?: any,
|
|
7
7
|
): RemixElement {
|
|
8
8
|
return {
|
|
9
9
|
$rmx: true,
|
|
@@ -13,19 +13,40 @@ export function createRemixElement(
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export function isRemixElement(node:
|
|
17
|
-
|
|
16
|
+
export function isRemixElement(node: unknown): node is RemixElement {
|
|
17
|
+
if (typeof node !== 'object' || node === null) return false
|
|
18
|
+
let type = Reflect.get(node, 'type')
|
|
19
|
+
let props = Reflect.get(node, 'props')
|
|
20
|
+
return (
|
|
21
|
+
Reflect.get(node, '$rmx') === true &&
|
|
22
|
+
(typeof type === 'string' || typeof type === 'function') &&
|
|
23
|
+
typeof props === 'object' &&
|
|
24
|
+
props !== null
|
|
25
|
+
)
|
|
18
26
|
}
|
|
19
27
|
|
|
20
28
|
function normalizeElementProps(props: ElementProps | null | undefined): ElementProps {
|
|
21
29
|
if (!props) return {}
|
|
22
30
|
if (!('mix' in props)) return props
|
|
23
31
|
|
|
32
|
+
// Fast path: `mix={[a, b]}` with flat, truthy entries is already normalized.
|
|
33
|
+
// Skipping the copy avoids two prop-object spreads per element per render.
|
|
34
|
+
if (isNormalizedMix(props.mix)) return props
|
|
35
|
+
|
|
24
36
|
let { mix, ...rest } = props
|
|
25
37
|
let normalizedMix = normalizeMixValue(mix)
|
|
26
38
|
return normalizedMix === undefined ? rest : { ...rest, mix: normalizedMix }
|
|
27
39
|
}
|
|
28
40
|
|
|
41
|
+
function isNormalizedMix(mix: unknown): boolean {
|
|
42
|
+
if (!Array.isArray(mix) || mix.length === 0) return false
|
|
43
|
+
for (let i = 0; i < mix.length; i++) {
|
|
44
|
+
let item = mix[i]
|
|
45
|
+
if (!item || Array.isArray(item)) return false
|
|
46
|
+
}
|
|
47
|
+
return true
|
|
48
|
+
}
|
|
49
|
+
|
|
29
50
|
function normalizeMixValue(mix: unknown): unknown[] | undefined {
|
|
30
51
|
if (!mix) return undefined
|
|
31
52
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx } from './jsx.ts'
|
|
2
|
-
import type { ElementType, RemixElement } from './jsx.ts'
|
|
3
|
-
import { normalizeChildren } from './core/children.ts'
|
|
2
|
+
import type { ElementProps, ElementType, RemixElement } from './jsx.ts'
|
|
3
|
+
import { assertRemixNodes, normalizeChildren } from './core/children.ts'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Creates a Remix virtual element from a JSX-like call signature.
|
|
@@ -12,8 +12,8 @@ import { normalizeChildren } from './core/children.ts'
|
|
|
12
12
|
*/
|
|
13
13
|
export function createElement(
|
|
14
14
|
type: ElementType,
|
|
15
|
-
props?:
|
|
16
|
-
...children:
|
|
15
|
+
props?: ElementProps,
|
|
16
|
+
...children: unknown[]
|
|
17
17
|
): RemixElement {
|
|
18
18
|
let nextProps = { ...(props ?? {}) }
|
|
19
19
|
if (isMixinElementType(type)) {
|
|
@@ -21,6 +21,7 @@ export function createElement(
|
|
|
21
21
|
console.error(new Error('mixin elements must not receive children'))
|
|
22
22
|
}
|
|
23
23
|
} else {
|
|
24
|
+
assertRemixNodes(children)
|
|
24
25
|
nextProps.children = normalizeChildren(children)
|
|
25
26
|
}
|
|
26
27
|
|
|
@@ -34,6 +35,6 @@ export function createElement(
|
|
|
34
35
|
|
|
35
36
|
function isMixinElementType(
|
|
36
37
|
type: ElementType,
|
|
37
|
-
): type is
|
|
38
|
+
): type is ElementType & { __rmxMixinElementType: string } {
|
|
38
39
|
return typeof type === 'function' && '__rmxMixinElementType' in type
|
|
39
40
|
}
|