@remix-run/ui 0.1.2 → 0.3.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 +9 -7
- package/dist/animation/demos/animation.demo.d.ts +5 -0
- package/dist/animation/demos/animation.demo.js +92 -0
- package/dist/animation/demos/animation.demo.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 +50 -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/spring.demo.d.ts +6 -0
- package/dist/animation/demos/spring.demo.js +304 -0
- package/dist/animation/demos/spring.demo.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 +24 -31
- package/dist/animation/spring.js +31 -8
- package/dist/animation/spring.js.map +1 -1
- package/dist/components/accordion/accordion.d.ts +6 -6
- package/dist/components/accordion/accordion.js.map +1 -1
- package/dist/components/accordion/demos/card.demo.d.ts +1 -0
- package/dist/components/accordion/demos/card.demo.js +1 -0
- package/dist/components/accordion/demos/card.demo.js.map +1 -1
- package/dist/components/accordion/demos/multiple.demo.d.ts +1 -0
- package/dist/components/accordion/demos/multiple.demo.js +1 -0
- package/dist/components/accordion/demos/multiple.demo.js.map +1 -1
- package/dist/components/accordion/demos/overview.demo.d.ts +1 -0
- package/dist/components/accordion/demos/overview.demo.js +1 -0
- package/dist/components/accordion/demos/overview.demo.js.map +1 -1
- package/dist/components/anchor/anchor.d.ts +8 -1
- package/dist/components/anchor/anchor.js +30 -11
- package/dist/components/anchor/anchor.js.map +1 -1
- package/dist/components/breadcrumbs/{demos/basic.demo.d.ts → basic.demo.d.ts} +1 -0
- package/dist/components/breadcrumbs/{demos/basic.demo.js → basic.demo.js} +1 -0
- package/dist/components/breadcrumbs/basic.demo.js.map +1 -0
- package/dist/components/breadcrumbs/breadcrumbs.d.ts +1 -1
- package/dist/components/breadcrumbs/{demos/separator.demo.d.ts → separator.demo.d.ts} +1 -0
- package/dist/components/breadcrumbs/{demos/separator.demo.js → separator.demo.js} +1 -0
- package/dist/components/breadcrumbs/separator.demo.js.map +1 -0
- package/dist/components/button/button.d.ts +4 -4
- package/dist/components/button/button.js +3 -1
- package/dist/components/button/button.js.map +1 -1
- package/dist/components/button/demos/aliases.demo.d.ts +1 -0
- package/dist/components/button/demos/aliases.demo.js +1 -0
- package/dist/components/button/demos/aliases.demo.js.map +1 -1
- package/dist/components/button/demos/basic.demo.d.ts +1 -0
- package/dist/components/button/demos/basic.demo.js +1 -0
- package/dist/components/button/demos/basic.demo.js.map +1 -1
- package/dist/components/button/demos/states.demo.d.ts +1 -0
- package/dist/components/button/demos/states.demo.js +1 -0
- package/dist/components/button/demos/states.demo.js.map +1 -1
- package/dist/components/combobox/combobox.d.ts +10 -10
- package/dist/components/combobox/combobox.js.map +1 -1
- package/dist/components/combobox/{demos/overview.demo.d.ts → overview.demo.d.ts} +1 -0
- package/dist/components/combobox/{demos/overview.demo.js → overview.demo.js} +1 -0
- package/dist/components/combobox/overview.demo.js.map +1 -0
- package/dist/components/listbox/listbox.d.ts +3 -3
- package/dist/components/listbox/listbox.js.map +1 -1
- package/dist/components/listbox/{demos/overview.demo.d.ts → overview.demo.d.ts} +1 -0
- package/dist/components/listbox/{demos/overview.demo.js → overview.demo.js} +1 -0
- package/dist/components/listbox/overview.demo.js.map +1 -0
- package/dist/components/menu/demos/bubbling.demo.d.ts +1 -0
- package/dist/components/menu/demos/bubbling.demo.js +1 -0
- package/dist/components/menu/demos/bubbling.demo.js.map +1 -1
- package/dist/components/menu/demos/context-trigger.demo.d.ts +7 -0
- package/dist/components/menu/demos/context-trigger.demo.js +87 -0
- package/dist/components/menu/demos/context-trigger.demo.js.map +1 -0
- package/dist/components/menu/demos/overview.demo.d.ts +1 -0
- package/dist/components/menu/demos/overview.demo.js +1 -0
- package/dist/components/menu/demos/overview.demo.js.map +1 -1
- package/dist/components/menu/menu.d.ts +15 -12
- package/dist/components/menu/menu.js +55 -0
- package/dist/components/menu/menu.js.map +1 -1
- package/dist/components/popover/{demos/overview.demo.d.ts → overview.demo.d.ts} +1 -0
- package/dist/components/popover/{demos/overview.demo.js → overview.demo.js} +1 -0
- package/dist/components/popover/overview.demo.js.map +1 -0
- package/dist/components/popover/popover.d.ts +7 -7
- package/dist/components/popover/popover.js +11 -4
- package/dist/components/popover/popover.js.map +1 -1
- package/dist/components/select/{demos/deconstructed.demo.d.ts → deconstructed.demo.d.ts} +1 -0
- package/dist/components/select/{demos/deconstructed.demo.js → deconstructed.demo.js} +1 -0
- package/dist/components/select/deconstructed.demo.js.map +1 -0
- package/dist/components/select/{demos/overview.demo.d.ts → overview.demo.d.ts} +1 -0
- package/dist/components/select/{demos/overview.demo.js → overview.demo.js} +1 -0
- package/dist/components/select/overview.demo.js.map +1 -0
- package/dist/components/select/select.d.ts +10 -10
- package/dist/components/select/select.js +1 -1
- package/dist/components/select/select.js.map +1 -1
- package/dist/components/tabs/tabs.d.ts +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interactions/keydown/keydown.d.ts +1 -1
- package/dist/interactions/outside-click/outside-click-mixin.d.ts +2 -1
- package/dist/interactions/typeahead/typeahead-mixin.d.ts +3 -1
- package/dist/runtime/client-entries.d.ts +1 -2
- package/dist/runtime/client-entries.js.map +1 -1
- package/dist/runtime/component.d.ts +20 -17
- package/dist/runtime/component.js +15 -6
- package/dist/runtime/component.js.map +1 -1
- package/dist/runtime/core/attributes.d.ts +3 -1
- package/dist/runtime/core/attributes.js +19 -1
- package/dist/runtime/core/attributes.js.map +1 -1
- package/dist/runtime/core/props.js +6 -5
- package/dist/runtime/core/props.js.map +1 -1
- package/dist/runtime/demos/basic.demo.d.ts +6 -0
- package/dist/runtime/demos/basic.demo.js +16 -0
- package/dist/runtime/demos/basic.demo.js.map +1 -0
- package/dist/runtime/demos/controlled-uncontrolled-values.demo.d.ts +6 -0
- package/dist/runtime/demos/controlled-uncontrolled-values.demo.js +77 -0
- package/dist/runtime/demos/controlled-uncontrolled-values.demo.js.map +1 -0
- package/dist/runtime/demos/keyed-list.demo.d.ts +6 -0
- package/dist/runtime/demos/keyed-list.demo.js +62 -0
- package/dist/runtime/demos/keyed-list.demo.js.map +1 -0
- package/dist/runtime/demos/readme.demo.d.ts +5 -0
- package/dist/runtime/demos/readme.demo.js +396 -0
- package/dist/runtime/demos/readme.demo.js.map +1 -0
- package/dist/runtime/diff-dom.js +194 -21
- package/dist/runtime/diff-dom.js.map +1 -1
- package/dist/runtime/dom.d.ts +16 -9
- 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 +3 -4
- package/dist/runtime/jsx.js.map +1 -1
- package/dist/runtime/mixins/link-mixin.d.ts +5 -1
- package/dist/runtime/mixins/link-mixin.js.map +1 -1
- package/dist/runtime/mixins/mixin.d.ts +2 -1
- package/dist/runtime/mixins/mixin.js.map +1 -1
- package/dist/runtime/mixins/ref-mixin.d.ts +2 -1
- package/dist/runtime/mixins/ref-mixin.js.map +1 -1
- package/dist/runtime/reconcile.d.ts +1 -1
- package/dist/runtime/reconcile.js +19 -5
- package/dist/runtime/reconcile.js.map +1 -1
- package/dist/runtime/scheduler.d.ts +10 -10
- package/dist/runtime/scheduler.js +1 -1
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/svg-attributes.js +1 -0
- package/dist/runtime/svg-attributes.js.map +1 -1
- package/dist/runtime/to-vnode.js +2 -2
- package/dist/runtime/to-vnode.js.map +1 -1
- package/dist/runtime/vnode.d.ts +6 -1
- package/dist/runtime/vnode.js +4 -0
- package/dist/runtime/vnode.js.map +1 -1
- package/dist/server/stream.d.ts +2 -0
- package/dist/server/stream.js +82 -11
- package/dist/server/stream.js.map +1 -1
- package/dist/style/css-mixin.d.ts +2 -1
- package/dist/style/css-mixin.js.map +1 -1
- package/dist/style/index.d.ts +1 -1
- package/dist/style/style.js +27 -10
- package/dist/style/style.js.map +1 -1
- package/dist/style/stylesheet.d.ts +13 -13
- package/dist/style/stylesheet.js.map +1 -1
- package/dist/theme/contract.d.ts +24 -222
- package/dist/theme/contract.js +2 -2
- package/dist/theme/contract.js.map +1 -1
- package/dist/theme/glyph-contract.d.ts +1 -3
- package/dist/theme/glyph-contract.js.map +1 -1
- package/dist/theme/presets/rmx-01/index.d.ts +4 -2
- package/dist/theme/presets/rmx-01/index.js.map +1 -1
- package/dist/utils/scroll-lock.d.ts +3 -3
- package/dist/utils/scroll-lock.js.map +1 -1
- package/package.json +4 -4
- package/src/animation/README.md +7 -5
- package/src/animation/demos/animation.demo.tsx +194 -0
- 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 +65 -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/spring.demo.tsx +385 -0
- package/src/animation/demos/transition-options.tsx +24 -0
- package/src/animation/spring.ts +43 -9
- package/src/components/accordion/accordion.tsx +7 -5
- package/src/components/accordion/demos/card.demo.tsx +1 -0
- package/src/components/accordion/demos/multiple.demo.tsx +1 -0
- package/src/components/accordion/demos/overview.demo.tsx +1 -0
- package/src/components/anchor/README.md +11 -3
- package/src/components/anchor/anchor.ts +54 -13
- package/src/components/breadcrumbs/{demos/basic.demo.tsx → basic.demo.tsx} +1 -0
- package/src/components/breadcrumbs/breadcrumbs.tsx +1 -1
- package/src/components/breadcrumbs/{demos/separator.demo.tsx → separator.demo.tsx} +1 -0
- package/src/components/button/button.tsx +30 -18
- package/src/components/button/demos/aliases.demo.tsx +1 -0
- package/src/components/button/demos/basic.demo.tsx +1 -0
- package/src/components/button/demos/states.demo.tsx +1 -0
- package/src/components/combobox/README.md +1 -1
- package/src/components/combobox/combobox.tsx +30 -12
- package/src/components/combobox/{demos/overview.demo.tsx → overview.demo.tsx} +1 -0
- package/src/components/glyph/glyph.tsx +2 -2
- package/src/components/listbox/listbox.ts +88 -83
- package/src/components/listbox/{demos/overview.demo.tsx → overview.demo.tsx} +1 -0
- package/src/components/menu/README.md +26 -2
- package/src/components/menu/demos/bubbling.demo.tsx +1 -0
- package/src/components/menu/demos/context-trigger.demo.tsx +133 -0
- package/src/components/menu/demos/overview.demo.tsx +1 -0
- package/src/components/menu/menu.tsx +100 -16
- package/src/components/popover/{demos/overview.demo.tsx → overview.demo.tsx} +1 -0
- package/src/components/popover/popover.ts +101 -81
- package/src/components/select/{demos/deconstructed.demo.tsx → deconstructed.demo.tsx} +1 -0
- package/src/components/select/{demos/overview.demo.tsx → overview.demo.tsx} +1 -0
- package/src/components/select/select.tsx +27 -10
- package/src/index.ts +1 -0
- package/src/runtime/client-entries.ts +1 -5
- package/src/runtime/component.ts +37 -15
- package/src/runtime/core/attributes.ts +21 -0
- package/src/runtime/core/props.ts +6 -4
- package/src/runtime/demos/basic.demo.tsx +21 -0
- package/src/runtime/demos/controlled-uncontrolled-values.demo.tsx +177 -0
- package/src/runtime/demos/keyed-list.demo.tsx +94 -0
- package/src/runtime/demos/readme.demo.tsx +702 -0
- package/src/runtime/diff-dom.ts +270 -20
- package/src/runtime/dom.ts +16 -9
- package/src/runtime/frame.ts +218 -41
- package/src/runtime/jsx.ts +7 -11
- package/src/runtime/mixins/link-mixin.ts +88 -86
- package/src/runtime/mixins/mixin.ts +9 -1
- package/src/runtime/mixins/ref-mixin.ts +4 -5
- package/src/runtime/reconcile.ts +23 -14
- package/src/runtime/scheduler.ts +20 -20
- package/src/runtime/svg-attributes.ts +1 -0
- package/src/runtime/to-vnode.ts +2 -2
- package/src/runtime/vnode.ts +10 -0
- package/src/server/README.md +4 -2
- package/src/server/stream.ts +84 -10
- package/src/style/css-mixin.ts +6 -1
- package/src/style/index.ts +1 -2
- package/src/style/style.ts +29 -10
- package/src/style/stylesheet.ts +14 -2
- package/src/theme/contract.ts +37 -5
- package/src/theme/glyph-contract.ts +3 -1
- package/src/theme/presets/rmx-01/index.ts +4 -2
- package/src/utils/scroll-lock.ts +7 -3
- package/dist/components/breadcrumbs/demos/basic.demo.js.map +0 -1
- package/dist/components/breadcrumbs/demos/separator.demo.js.map +0 -1
- package/dist/components/combobox/demos/overview.demo.js.map +0 -1
- package/dist/components/listbox/demos/overview.demo.js.map +0 -1
- package/dist/components/popover/demos/overview.demo.js.map +0 -1
- package/dist/components/select/demos/deconstructed.demo.js.map +0 -1
- package/dist/components/select/demos/overview.demo.js.map +0 -1
|
@@ -4,7 +4,9 @@ import {
|
|
|
4
4
|
css,
|
|
5
5
|
on,
|
|
6
6
|
type CSSMixinDescriptor,
|
|
7
|
+
type ElementProps,
|
|
7
8
|
type Handle,
|
|
9
|
+
type MixinFactory,
|
|
8
10
|
type RemixNode,
|
|
9
11
|
} from '@remix-run/ui'
|
|
10
12
|
import { theme } from '../../theme/theme.ts'
|
|
@@ -149,7 +151,7 @@ export const optionStyle = itemCss
|
|
|
149
151
|
export const glyphStyle = itemGlyphCss
|
|
150
152
|
export const labelStyle = itemLabelCss
|
|
151
153
|
|
|
152
|
-
function ListboxProvider(handle: Handle<ListboxProviderProps, ListboxContext>) {
|
|
154
|
+
function ListboxProvider(handle: Handle<ListboxProviderProps, ListboxContext>): () => RemixNode {
|
|
153
155
|
let options: RegisteredOption[] = []
|
|
154
156
|
let state: State = 'idle'
|
|
155
157
|
|
|
@@ -336,49 +338,51 @@ function ListboxProvider(handle: Handle<ListboxProviderProps, ListboxContext>) {
|
|
|
336
338
|
}
|
|
337
339
|
}
|
|
338
340
|
|
|
339
|
-
const listMixin = createMixin<HTMLElement>(
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
341
|
+
const listMixin: MixinFactory<HTMLElement, [], ElementProps> = createMixin<HTMLElement>(
|
|
342
|
+
(handle) => (props) => {
|
|
343
|
+
let context = handle.context.get(ListboxProvider)
|
|
344
|
+
return [
|
|
345
|
+
attrs({
|
|
346
|
+
tabIndex: props.tabIndex ?? -1,
|
|
347
|
+
role: props.role ?? 'listbox',
|
|
348
|
+
}),
|
|
349
|
+
on('focus', () => {
|
|
350
|
+
context.scrollActiveOptionIntoView()
|
|
351
|
+
}),
|
|
352
|
+
on('keydown', (event) => {
|
|
353
|
+
switch (event.key) {
|
|
354
|
+
case 'ArrowDown':
|
|
355
|
+
event.preventDefault()
|
|
356
|
+
context.navigate('next')
|
|
357
|
+
break
|
|
358
|
+
case 'ArrowUp':
|
|
359
|
+
event.preventDefault()
|
|
360
|
+
context.navigate('previous')
|
|
361
|
+
break
|
|
362
|
+
case 'Tab':
|
|
363
|
+
event.preventDefault()
|
|
364
|
+
context.navigate('first')
|
|
365
|
+
break
|
|
366
|
+
case 'Enter':
|
|
367
|
+
case ' ':
|
|
368
|
+
event.preventDefault()
|
|
369
|
+
void context.select(context.activeValue)
|
|
370
|
+
break
|
|
371
|
+
case 'Home':
|
|
372
|
+
event.preventDefault()
|
|
373
|
+
context.navigate('first')
|
|
374
|
+
break
|
|
375
|
+
case 'End':
|
|
376
|
+
event.preventDefault()
|
|
377
|
+
context.navigate('last')
|
|
378
|
+
}
|
|
379
|
+
}),
|
|
380
|
+
hiddenTypeahead((text) => {
|
|
381
|
+
context.highlightSearchMatch(text)
|
|
382
|
+
}),
|
|
383
|
+
]
|
|
384
|
+
},
|
|
385
|
+
)
|
|
382
386
|
|
|
383
387
|
export interface ListboxOption {
|
|
384
388
|
id: string
|
|
@@ -388,50 +392,51 @@ export interface ListboxOption {
|
|
|
388
392
|
textValue?: SearchValue
|
|
389
393
|
}
|
|
390
394
|
|
|
391
|
-
const optionMixin
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
handle.queueTask((node) => {
|
|
395
|
-
optionRef = node
|
|
396
|
-
})
|
|
395
|
+
const optionMixin: MixinFactory<HTMLElement, [option: Omit<ListboxOption, 'id'>], ElementProps> =
|
|
396
|
+
createMixin<HTMLElement, [option: Omit<ListboxOption, 'id'>]>((handle) => {
|
|
397
|
+
let optionRef: HTMLElement | undefined
|
|
397
398
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
context.registerOption({
|
|
401
|
-
...option,
|
|
402
|
-
id: handle.id,
|
|
403
|
-
get hidden() {
|
|
404
|
-
return optionRef?.hidden === true
|
|
405
|
-
},
|
|
406
|
-
get node() {
|
|
407
|
-
return optionRef as HTMLElement
|
|
408
|
-
},
|
|
399
|
+
handle.queueTask((node) => {
|
|
400
|
+
optionRef = node
|
|
409
401
|
})
|
|
410
402
|
|
|
411
|
-
return
|
|
412
|
-
|
|
413
|
-
|
|
403
|
+
return (option) => {
|
|
404
|
+
let context = handle.context.get(ListboxProvider)
|
|
405
|
+
context.registerOption({
|
|
406
|
+
...option,
|
|
414
407
|
id: handle.id,
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
408
|
+
get hidden() {
|
|
409
|
+
return optionRef?.hidden === true
|
|
410
|
+
},
|
|
411
|
+
get node() {
|
|
412
|
+
return optionRef as HTMLElement
|
|
413
|
+
},
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
return [
|
|
417
|
+
attrs({
|
|
418
|
+
role: 'option',
|
|
419
|
+
id: handle.id,
|
|
420
|
+
'aria-selected': context.value === option.value ? 'true' : 'false',
|
|
421
|
+
'aria-disabled': option.disabled ? 'true' : 'false',
|
|
422
|
+
'data-highlighted': context.activeValue === option.value ? 'true' : 'false',
|
|
422
423
|
}),
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
})
|
|
424
|
+
!option.disabled && [
|
|
425
|
+
on('click', () => {
|
|
426
|
+
context.select(option.value)
|
|
427
|
+
}),
|
|
428
|
+
on('mousemove', () => {
|
|
429
|
+
if (context.activeValue === option.value) return
|
|
430
|
+
context.highlight(option.value)
|
|
431
|
+
}),
|
|
432
|
+
on('mouseleave', () => {
|
|
433
|
+
if (context.activeValue !== option.value) return
|
|
434
|
+
context.highlight(null)
|
|
435
|
+
}),
|
|
436
|
+
],
|
|
437
|
+
]
|
|
438
|
+
}
|
|
439
|
+
})
|
|
435
440
|
|
|
436
441
|
export const Context = ListboxProvider
|
|
437
442
|
export const list = listMixin
|
|
@@ -7,6 +7,7 @@ import { theme } from '@remix-run/ui/theme'
|
|
|
7
7
|
/**
|
|
8
8
|
* @name Listbox Overview
|
|
9
9
|
* @description A keyboard-navigable listbox with selection, highlighting, and an optional flash-selection animation.
|
|
10
|
+
* @layout center
|
|
10
11
|
*/
|
|
11
12
|
export default function Example(handle: Handle) {
|
|
12
13
|
let value: ListboxValue = options[0]!.value
|
|
@@ -68,6 +68,29 @@ Use `menuLabel` when the menu surface needs a different accessible label from th
|
|
|
68
68
|
</Menu>
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
Use `menu.contextTrigger()` with `menu.Context` and `MenuList` when a menu should open at the right-click location of an element.
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import * as menu from 'remix/ui/menu'
|
|
75
|
+
import { MenuItem, MenuList } from 'remix/ui/menu'
|
|
76
|
+
|
|
77
|
+
export function FileContextMenu(handle: Handle) {
|
|
78
|
+
return () => (
|
|
79
|
+
<menu.Context label="File actions">
|
|
80
|
+
<div mix={menu.contextTrigger()} tabIndex={0}>
|
|
81
|
+
File.txt
|
|
82
|
+
</div>
|
|
83
|
+
<MenuList>
|
|
84
|
+
<MenuItem name="rename">Rename</MenuItem>
|
|
85
|
+
<MenuItem name="delete">Delete</MenuItem>
|
|
86
|
+
</MenuList>
|
|
87
|
+
</menu.Context>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Attach `onMenuSelect(...)` to `MenuList` or a shared ancestor when using lower-level context menu composition.
|
|
93
|
+
|
|
71
94
|
## `menu.*`
|
|
72
95
|
|
|
73
96
|
- `Menu`: composed trigger, popover, and list component for the common menu case.
|
|
@@ -77,13 +100,14 @@ Use `menuLabel` when the menu surface needs a different accessible label from th
|
|
|
77
100
|
- `onMenuSelect(...)`: event mixin for the bubbling `MenuSelectEvent`.
|
|
78
101
|
- `MenuSelectEvent`: bubbling event class whose `item` describes the selected item.
|
|
79
102
|
- `MenuSelectItem`: selected item shape with `checked`, `id`, `label`, `name`, `type`, and `value`.
|
|
80
|
-
- `menu.Context`, `menu.trigger()`, `menu.popover()`, `menu.list()`, `menu.item(...)`, and `menu.submenuTrigger(...)`: lower-level composition primitives.
|
|
103
|
+
- `menu.Context`, `menu.trigger()`, `menu.contextTrigger()`, `menu.popover()`, `menu.list()`, `menu.item(...)`, and `menu.submenuTrigger(...)`: lower-level composition primitives.
|
|
81
104
|
- `buttonStyle`, `popoverStyle`, `listStyle`, `itemStyle`, `itemSlotStyle`, `itemLabelStyle`, `itemGlyphStyle`, and `triggerGlyphStyle`: flat style mixins used by the wrappers.
|
|
82
|
-
- `MenuProps`, `MenuItemProps`, `MenuListProps`, `MenuProviderProps`, `MenuTriggerOptions`, `MenuItemOptions`, and `SubmenuProps`: public TypeScript props and option types.
|
|
105
|
+
- `MenuProps`, `MenuItemProps`, `MenuListProps`, `MenuProviderProps`, `MenuTriggerOptions`, `MenuContextTriggerOptions`, `MenuItemOptions`, and `SubmenuProps`: public TypeScript props and option types.
|
|
83
106
|
|
|
84
107
|
## Behavior Notes
|
|
85
108
|
|
|
86
109
|
- Click opens the root menu and focuses the list; clicking the trigger again closes it and restores focus.
|
|
110
|
+
- `menu.contextTrigger()` opens the root menu from a `contextmenu` event at the pointer coordinates and supports keyboard opening with the Context Menu key or Shift+F10.
|
|
87
111
|
- `ArrowDown` opens from the trigger at the first enabled item. `ArrowUp` opens at the last enabled item. Enter and Space open the menu with focus on the list.
|
|
88
112
|
- Keyboard navigation skips disabled items and does not wrap past the first or last enabled item.
|
|
89
113
|
- `Home` and `End` move to the first and last enabled item. Enter and Space activate the highlighted item.
|
|
@@ -4,6 +4,7 @@ import { Menu, MenuItem, onMenuSelect } from '@remix-run/ui/menu'
|
|
|
4
4
|
/**
|
|
5
5
|
* @name Menu Event Bubbling
|
|
6
6
|
* @description Item-level handlers fire before the root handler, letting individual items intercept events while others bubble up.
|
|
7
|
+
* @layout center
|
|
7
8
|
*/
|
|
8
9
|
export default function Example() {
|
|
9
10
|
return () => (
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { css, type Handle } from '@remix-run/ui'
|
|
2
|
+
import * as menu from '@remix-run/ui/menu'
|
|
3
|
+
import { MenuItem, MenuList, onMenuSelect, Submenu } from '@remix-run/ui/menu'
|
|
4
|
+
import { separatorStyle } from '@remix-run/ui/separator'
|
|
5
|
+
import { theme } from '@remix-run/ui/theme'
|
|
6
|
+
|
|
7
|
+
type FileAction = 'copyPath' | 'duplicate' | 'move' | 'rename' | 'reveal' | 'trash'
|
|
8
|
+
|
|
9
|
+
const actionLabelByName: Record<FileAction, string> = {
|
|
10
|
+
copyPath: 'Copied path',
|
|
11
|
+
duplicate: 'Duplicated file',
|
|
12
|
+
move: 'Moved file',
|
|
13
|
+
rename: 'Renamed file',
|
|
14
|
+
reveal: 'Revealed in Finder',
|
|
15
|
+
trash: 'Moved to trash',
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @name Context Menu Trigger
|
|
20
|
+
* @description A lower-level menu composition that opens from right-click coordinates while keeping standard menu selection and submenu behavior.
|
|
21
|
+
* @layout center
|
|
22
|
+
*/
|
|
23
|
+
export default function Example(handle: Handle) {
|
|
24
|
+
let latestAction = 'Right-click the card.'
|
|
25
|
+
|
|
26
|
+
return () => (
|
|
27
|
+
<menu.Context label="File actions">
|
|
28
|
+
<div mix={layoutCss}>
|
|
29
|
+
<div tabIndex={0} mix={[fileCardCss, menu.contextTrigger()]}>
|
|
30
|
+
<span mix={fileIconCss}>TS</span>
|
|
31
|
+
<span mix={fileTextCss}>
|
|
32
|
+
<strong mix={fileNameCss}>context-menu.tsx</strong>
|
|
33
|
+
<span mix={fileMetaCss}>Right-click or press Shift+F10</span>
|
|
34
|
+
</span>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<p aria-live="polite" mix={statusCss}>
|
|
38
|
+
{latestAction}
|
|
39
|
+
</p>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<MenuList
|
|
43
|
+
mix={onMenuSelect((event) => {
|
|
44
|
+
latestAction =
|
|
45
|
+
actionLabelByName[event.item.name as FileAction] ?? `Selected ${event.item.label}`
|
|
46
|
+
void handle.update()
|
|
47
|
+
})}
|
|
48
|
+
>
|
|
49
|
+
<MenuItem name="rename">Rename</MenuItem>
|
|
50
|
+
<MenuItem name="duplicate">Duplicate</MenuItem>
|
|
51
|
+
<MenuItem name="copyPath">Copy path</MenuItem>
|
|
52
|
+
<hr mix={separatorStyle} />
|
|
53
|
+
<Submenu label="Move to">
|
|
54
|
+
<MenuItem name="move" value="drafts">
|
|
55
|
+
Drafts
|
|
56
|
+
</MenuItem>
|
|
57
|
+
<MenuItem name="move" value="archive">
|
|
58
|
+
Archive
|
|
59
|
+
</MenuItem>
|
|
60
|
+
</Submenu>
|
|
61
|
+
<MenuItem name="reveal">Reveal in Finder</MenuItem>
|
|
62
|
+
<hr mix={separatorStyle} />
|
|
63
|
+
<MenuItem name="trash">Move to trash</MenuItem>
|
|
64
|
+
</MenuList>
|
|
65
|
+
</menu.Context>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const layoutCss = css({
|
|
70
|
+
display: 'grid',
|
|
71
|
+
justifyItems: 'start',
|
|
72
|
+
gap: theme.space.md,
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const fileCardCss = css({
|
|
76
|
+
display: 'grid',
|
|
77
|
+
gridTemplateColumns: 'auto minmax(0, 1fr)',
|
|
78
|
+
alignItems: 'center',
|
|
79
|
+
gap: theme.space.md,
|
|
80
|
+
width: 'min(100%, 21rem)',
|
|
81
|
+
padding: theme.space.md,
|
|
82
|
+
border: `1px solid ${theme.colors.border.subtle}`,
|
|
83
|
+
borderRadius: theme.radius.lg,
|
|
84
|
+
backgroundColor: theme.surface.lvl1,
|
|
85
|
+
color: theme.colors.text.primary,
|
|
86
|
+
boxShadow: theme.shadow.xs,
|
|
87
|
+
cursor: 'context-menu',
|
|
88
|
+
userSelect: 'none',
|
|
89
|
+
'&:focus-visible': {
|
|
90
|
+
outline: `2px solid ${theme.colors.focus.ring}`,
|
|
91
|
+
outlineOffset: '2px',
|
|
92
|
+
},
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const fileIconCss = css({
|
|
96
|
+
display: 'inline-grid',
|
|
97
|
+
placeItems: 'center',
|
|
98
|
+
width: theme.control.height.lg,
|
|
99
|
+
height: theme.control.height.lg,
|
|
100
|
+
borderRadius: theme.radius.md,
|
|
101
|
+
backgroundColor: theme.colors.action.primary.background,
|
|
102
|
+
color: theme.colors.action.primary.foreground,
|
|
103
|
+
fontSize: theme.fontSize.xs,
|
|
104
|
+
fontWeight: theme.fontWeight.bold,
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
const fileTextCss = css({
|
|
108
|
+
display: 'grid',
|
|
109
|
+
gap: theme.space.px,
|
|
110
|
+
minWidth: 0,
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
const fileNameCss = css({
|
|
114
|
+
overflow: 'hidden',
|
|
115
|
+
textOverflow: 'ellipsis',
|
|
116
|
+
whiteSpace: 'nowrap',
|
|
117
|
+
fontSize: theme.fontSize.sm,
|
|
118
|
+
lineHeight: theme.lineHeight.normal,
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
const fileMetaCss = css({
|
|
122
|
+
color: theme.colors.text.secondary,
|
|
123
|
+
fontSize: theme.fontSize.xs,
|
|
124
|
+
lineHeight: theme.lineHeight.normal,
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
const statusCss = css({
|
|
128
|
+
margin: 0,
|
|
129
|
+
minHeight: theme.lineHeight.normal,
|
|
130
|
+
color: theme.colors.text.secondary,
|
|
131
|
+
fontSize: theme.fontSize.sm,
|
|
132
|
+
lineHeight: theme.lineHeight.normal,
|
|
133
|
+
})
|
|
@@ -5,6 +5,7 @@ import { separatorStyle } from '@remix-run/ui/separator'
|
|
|
5
5
|
/**
|
|
6
6
|
* @name Menu Overview
|
|
7
7
|
* @description A hierarchical menu with checkboxes, radio groups, submenus, and separators.
|
|
8
|
+
* @layout center
|
|
8
9
|
*/
|
|
9
10
|
export default function Example(handle: Handle) {
|
|
10
11
|
type Density = 'comfortable' | 'compact'
|
|
@@ -9,10 +9,11 @@ import {
|
|
|
9
9
|
type Dispatched,
|
|
10
10
|
type ElementProps,
|
|
11
11
|
type Handle,
|
|
12
|
+
type MixinFactory,
|
|
12
13
|
type Props,
|
|
13
14
|
type RemixNode,
|
|
14
15
|
} from '@remix-run/ui'
|
|
15
|
-
import { type AnchorOptions } from '../anchor/anchor.ts'
|
|
16
|
+
import { type AnchorOptions, type AnchorPoint } from '../anchor/anchor.ts'
|
|
16
17
|
import * as button from '../button/button.tsx'
|
|
17
18
|
import { Glyph } from '../glyph/glyph.tsx'
|
|
18
19
|
import * as popover from '../popover/popover.ts'
|
|
@@ -249,6 +250,8 @@ export interface MenuProviderProps {
|
|
|
249
250
|
|
|
250
251
|
export interface MenuTriggerOptions extends AnchorOptions {}
|
|
251
252
|
|
|
253
|
+
export interface MenuContextTriggerOptions extends AnchorOptions {}
|
|
254
|
+
|
|
252
255
|
export interface MenuItemOptions {
|
|
253
256
|
checked?: boolean
|
|
254
257
|
disabled?: boolean
|
|
@@ -416,7 +419,7 @@ function focusNode(node: HTMLElement | undefined) {
|
|
|
416
419
|
}
|
|
417
420
|
}
|
|
418
421
|
|
|
419
|
-
function MenuProvider(handle: Handle<MenuProviderProps, MenuContextValue>) {
|
|
422
|
+
function MenuProvider(handle: Handle<MenuProviderProps, MenuContextValue>): () => RemixNode {
|
|
420
423
|
let parent = handle.context.get(MenuProvider)
|
|
421
424
|
|
|
422
425
|
let activeId: string | null = null
|
|
@@ -957,8 +960,8 @@ function MenuProvider(handle: Handle<MenuProviderProps, MenuContextValue>) {
|
|
|
957
960
|
}
|
|
958
961
|
}
|
|
959
962
|
|
|
960
|
-
const triggerMixin
|
|
961
|
-
(handle) => {
|
|
963
|
+
const triggerMixin: MixinFactory<HTMLElement, [options?: MenuTriggerOptions], ElementProps> =
|
|
964
|
+
createMixin<HTMLElement, [options?: MenuTriggerOptions], ElementProps>((handle) => {
|
|
962
965
|
let context = handle.context.get(MenuProvider)
|
|
963
966
|
|
|
964
967
|
return (options = {}) => [
|
|
@@ -1005,10 +1008,81 @@ const triggerMixin = createMixin<HTMLElement, [options?: MenuTriggerOptions], El
|
|
|
1005
1008
|
}
|
|
1006
1009
|
}),
|
|
1007
1010
|
]
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1011
|
+
})
|
|
1012
|
+
|
|
1013
|
+
const contextTriggerMixin: MixinFactory<
|
|
1014
|
+
HTMLElement,
|
|
1015
|
+
[options?: MenuContextTriggerOptions],
|
|
1016
|
+
ElementProps
|
|
1017
|
+
> = createMixin<HTMLElement, [options?: MenuContextTriggerOptions], ElementProps>((handle) => {
|
|
1018
|
+
let context = handle.context.get(MenuProvider)
|
|
1019
|
+
let popoverContext = handle.context.get(popover.Context)
|
|
1020
|
+
let anchorPoint: AnchorPoint = { x: 0, y: 0, width: 0, height: 0 }
|
|
1021
|
+
|
|
1022
|
+
function setAnchorPoint(
|
|
1023
|
+
{ x, y, width = 0, height = 0 }: AnchorPoint,
|
|
1024
|
+
options: MenuContextTriggerOptions,
|
|
1025
|
+
) {
|
|
1026
|
+
anchorPoint.x = x
|
|
1027
|
+
anchorPoint.y = y
|
|
1028
|
+
anchorPoint.width = width
|
|
1029
|
+
anchorPoint.height = height
|
|
1030
|
+
popoverContext.anchor = {
|
|
1031
|
+
target: anchorPoint,
|
|
1032
|
+
options: {
|
|
1033
|
+
placement: 'bottom-start',
|
|
1034
|
+
...options,
|
|
1035
|
+
},
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
return (options = {}) => [
|
|
1040
|
+
attrs({
|
|
1041
|
+
id: handle.id,
|
|
1042
|
+
'aria-controls': context.listId,
|
|
1043
|
+
'aria-expanded': context.isOpen ? 'true' : 'false',
|
|
1044
|
+
'aria-haspopup': 'menu',
|
|
1045
|
+
}),
|
|
1046
|
+
ref((node: HTMLElement, signal) => {
|
|
1047
|
+
context.registerTrigger(node, handle.id)
|
|
1048
|
+
signal.addEventListener('abort', () => {
|
|
1049
|
+
context.unregisterTrigger(node)
|
|
1050
|
+
})
|
|
1051
|
+
}),
|
|
1052
|
+
on('contextmenu', (event) => {
|
|
1053
|
+
event.preventDefault()
|
|
1054
|
+
event.stopPropagation()
|
|
1055
|
+
setAnchorPoint({ x: event.clientX, y: event.clientY }, options)
|
|
1056
|
+
void context.open({ strategy: 'list' })
|
|
1057
|
+
}),
|
|
1058
|
+
on('keydown', (event) => {
|
|
1059
|
+
if (event.key !== 'ContextMenu' && !(event.shiftKey && event.key === 'F10')) {
|
|
1060
|
+
return
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
event.preventDefault()
|
|
1064
|
+
event.stopPropagation()
|
|
1065
|
+
|
|
1066
|
+
let rect = event.currentTarget.getBoundingClientRect()
|
|
1067
|
+
setAnchorPoint(
|
|
1068
|
+
{
|
|
1069
|
+
x: rect.left,
|
|
1070
|
+
y: rect.top,
|
|
1071
|
+
width: rect.width,
|
|
1072
|
+
height: rect.height,
|
|
1073
|
+
},
|
|
1074
|
+
options,
|
|
1075
|
+
)
|
|
1076
|
+
void context.open({ strategy: 'list' })
|
|
1077
|
+
}),
|
|
1078
|
+
]
|
|
1079
|
+
})
|
|
1010
1080
|
|
|
1011
|
-
const popoverMixin
|
|
1081
|
+
const popoverMixin: MixinFactory<HTMLElement, [], ElementProps> = createMixin<
|
|
1082
|
+
HTMLElement,
|
|
1083
|
+
[],
|
|
1084
|
+
ElementProps
|
|
1085
|
+
>((handle) => {
|
|
1012
1086
|
let context = handle.context.get(MenuProvider)
|
|
1013
1087
|
|
|
1014
1088
|
return () => [
|
|
@@ -1045,7 +1119,11 @@ const popoverMixin = createMixin<HTMLElement, [], ElementProps>((handle) => {
|
|
|
1045
1119
|
]
|
|
1046
1120
|
})
|
|
1047
1121
|
|
|
1048
|
-
const listMixin
|
|
1122
|
+
const listMixin: MixinFactory<HTMLElement, [], ElementProps> = createMixin<
|
|
1123
|
+
HTMLElement,
|
|
1124
|
+
[],
|
|
1125
|
+
ElementProps
|
|
1126
|
+
>((handle) => {
|
|
1049
1127
|
let context = handle.context.get(MenuProvider)
|
|
1050
1128
|
|
|
1051
1129
|
return () => [
|
|
@@ -1146,7 +1224,11 @@ const listMixin = createMixin<HTMLElement, [], ElementProps>((handle) => {
|
|
|
1146
1224
|
]
|
|
1147
1225
|
})
|
|
1148
1226
|
|
|
1149
|
-
const itemMixin
|
|
1227
|
+
const itemMixin: MixinFactory<HTMLElement, [options: MenuItemOptions], ElementProps> = createMixin<
|
|
1228
|
+
HTMLElement,
|
|
1229
|
+
[options: MenuItemOptions],
|
|
1230
|
+
ElementProps
|
|
1231
|
+
>((handle) => {
|
|
1150
1232
|
let itemRef: HTMLElement | undefined
|
|
1151
1233
|
|
|
1152
1234
|
handle.queueTask((node) => {
|
|
@@ -1226,11 +1308,11 @@ const itemMixin = createMixin<HTMLElement, [options: MenuItemOptions], ElementPr
|
|
|
1226
1308
|
}
|
|
1227
1309
|
})
|
|
1228
1310
|
|
|
1229
|
-
const submenuTriggerMixin
|
|
1311
|
+
const submenuTriggerMixin: MixinFactory<
|
|
1230
1312
|
HTMLElement,
|
|
1231
1313
|
[options: SubmenuTriggerOptions],
|
|
1232
1314
|
ElementProps
|
|
1233
|
-
>((handle) => {
|
|
1315
|
+
> = createMixin<HTMLElement, [options: SubmenuTriggerOptions], ElementProps>((handle) => {
|
|
1234
1316
|
let itemRef: HTMLElement | undefined
|
|
1235
1317
|
let openTimeoutId = 0
|
|
1236
1318
|
let aborted = false
|
|
@@ -1382,6 +1464,7 @@ type MenuListChildProps = Omit<
|
|
|
1382
1464
|
>
|
|
1383
1465
|
|
|
1384
1466
|
export const Context = MenuProvider
|
|
1467
|
+
export const contextTrigger = contextTriggerMixin
|
|
1385
1468
|
export const item = itemMixin
|
|
1386
1469
|
export const list = listMixin
|
|
1387
1470
|
export { popoverMixin as popover }
|
|
@@ -1390,6 +1473,7 @@ export const trigger = triggerMixin
|
|
|
1390
1473
|
|
|
1391
1474
|
const menu = {
|
|
1392
1475
|
Context,
|
|
1476
|
+
contextTrigger,
|
|
1393
1477
|
item,
|
|
1394
1478
|
list,
|
|
1395
1479
|
popover: popoverMixin,
|
|
@@ -1400,7 +1484,7 @@ const menu = {
|
|
|
1400
1484
|
export function onMenuSelect<target extends HTMLElement>(
|
|
1401
1485
|
handler: MenuSelectHandler<target>,
|
|
1402
1486
|
captureBoolean?: boolean,
|
|
1403
|
-
) {
|
|
1487
|
+
): ReturnType<typeof on<target, typeof MENU_SELECT_EVENT>> {
|
|
1404
1488
|
return on(MENU_SELECT_EVENT, handler, captureBoolean)
|
|
1405
1489
|
}
|
|
1406
1490
|
|
|
@@ -1425,7 +1509,7 @@ export interface SubmenuProps
|
|
|
1425
1509
|
menuLabel?: string
|
|
1426
1510
|
}
|
|
1427
1511
|
|
|
1428
|
-
export function Menu(handle: Handle<MenuProps>) {
|
|
1512
|
+
export function Menu(handle: Handle<MenuProps>): () => RemixNode {
|
|
1429
1513
|
let buttonRef: HTMLButtonElement | undefined
|
|
1430
1514
|
|
|
1431
1515
|
return () => {
|
|
@@ -1472,7 +1556,7 @@ export function Menu(handle: Handle<MenuProps>) {
|
|
|
1472
1556
|
}
|
|
1473
1557
|
}
|
|
1474
1558
|
|
|
1475
|
-
export function MenuList(handle: Handle<MenuListProps>) {
|
|
1559
|
+
export function MenuList(handle: Handle<MenuListProps>): () => RemixNode {
|
|
1476
1560
|
return () => {
|
|
1477
1561
|
let { children, mix, ...divProps } = handle.props
|
|
1478
1562
|
|
|
@@ -1486,7 +1570,7 @@ export function MenuList(handle: Handle<MenuListProps>) {
|
|
|
1486
1570
|
}
|
|
1487
1571
|
}
|
|
1488
1572
|
|
|
1489
|
-
export function MenuItem(handle: Handle<MenuItemProps>) {
|
|
1573
|
+
export function MenuItem(handle: Handle<MenuItemProps>): () => RemixNode {
|
|
1490
1574
|
return () => {
|
|
1491
1575
|
let { checked, children, disabled, label, mix, name, searchValue, type, value, ...divProps } =
|
|
1492
1576
|
handle.props
|
|
@@ -1509,7 +1593,7 @@ export function MenuItem(handle: Handle<MenuItemProps>) {
|
|
|
1509
1593
|
}
|
|
1510
1594
|
}
|
|
1511
1595
|
|
|
1512
|
-
export function Submenu(handle: Handle<SubmenuProps>) {
|
|
1596
|
+
export function Submenu(handle: Handle<SubmenuProps>): () => RemixNode {
|
|
1513
1597
|
return () => {
|
|
1514
1598
|
let { children, disabled, label, listProps, menuLabel, mix, searchValue, value, ...divProps } =
|
|
1515
1599
|
handle.props
|
|
@@ -8,6 +8,7 @@ import { theme } from '@remix-run/ui/theme'
|
|
|
8
8
|
/**
|
|
9
9
|
* @name Popover Overview
|
|
10
10
|
* @description A popover panel anchored to a trigger button, containing form controls and a close action.
|
|
11
|
+
* @layout center
|
|
11
12
|
*/
|
|
12
13
|
export default function Example(handle: Handle) {
|
|
13
14
|
let open = false
|