ajo-ui 0.1.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.
Files changed (103) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +126 -0
  3. package/dist/accordion.js +130 -0
  4. package/dist/avatar.js +54 -0
  5. package/dist/calendar.js +2 -0
  6. package/dist/carousel.js +239 -0
  7. package/dist/chart.js +790 -0
  8. package/dist/checkbox-group.js +70 -0
  9. package/dist/checkbox.js +77 -0
  10. package/dist/chunks/bar-CVafh6C1.js +99 -0
  11. package/dist/chunks/calendar-q8jZ8Cxr.js +1923 -0
  12. package/dist/chunks/collection-DtRB63U4.js +111 -0
  13. package/dist/chunks/data-table-DpkWv4y4.js +1039 -0
  14. package/dist/chunks/menu-B45IyHHC.js +704 -0
  15. package/dist/chunks/native-BJdhd9XJ.js +20 -0
  16. package/dist/chunks/popup-C8Bb3l_g.js +459 -0
  17. package/dist/chunks/popup-surface-BDCgtVU0.js +18 -0
  18. package/dist/chunks/position-D6_i_SRn.js +434 -0
  19. package/dist/chunks/virtual-list-B7hjGkjk.js +413 -0
  20. package/dist/collapsible.js +106 -0
  21. package/dist/command.js +263 -0
  22. package/dist/context-menu.js +112 -0
  23. package/dist/data-table.js +5 -0
  24. package/dist/dialog.js +207 -0
  25. package/dist/direction.js +22 -0
  26. package/dist/drawer.js +139 -0
  27. package/dist/field.js +26 -0
  28. package/dist/index.js +38 -0
  29. package/dist/input-date.js +994 -0
  30. package/dist/input-group.js +52 -0
  31. package/dist/input-otp.js +179 -0
  32. package/dist/menu.js +2 -0
  33. package/dist/menubar.js +236 -0
  34. package/dist/message-scroller.js +446 -0
  35. package/dist/navigation-menu.js +330 -0
  36. package/dist/popover.js +307 -0
  37. package/dist/progress.js +39 -0
  38. package/dist/radio-group.js +107 -0
  39. package/dist/resizable.js +172 -0
  40. package/dist/select.js +961 -0
  41. package/dist/sidebar.js +343 -0
  42. package/dist/slider.js +259 -0
  43. package/dist/switch.js +53 -0
  44. package/dist/tabs.js +182 -0
  45. package/dist/toast.js +492 -0
  46. package/dist/toggle-group.js +111 -0
  47. package/dist/toggle.js +52 -0
  48. package/dist/toolbar.js +127 -0
  49. package/dist/tooltip.js +196 -0
  50. package/dist/utils.js +104 -0
  51. package/dist/virtual-list.js +2 -0
  52. package/package.json +250 -0
  53. package/src/accordion.tsx +261 -0
  54. package/src/availability.ts +261 -0
  55. package/src/avatar.tsx +99 -0
  56. package/src/bar.ts +156 -0
  57. package/src/calendar.tsx +1441 -0
  58. package/src/carousel.tsx +424 -0
  59. package/src/chart.tsx +1194 -0
  60. package/src/checkbox-group.tsx +132 -0
  61. package/src/checkbox.tsx +130 -0
  62. package/src/collapsible.tsx +188 -0
  63. package/src/collection.ts +154 -0
  64. package/src/command.tsx +511 -0
  65. package/src/context-menu.tsx +233 -0
  66. package/src/data-table-contract.ts +143 -0
  67. package/src/data-table-model.ts +760 -0
  68. package/src/data-table.tsx +475 -0
  69. package/src/dialog.tsx +393 -0
  70. package/src/direction.tsx +45 -0
  71. package/src/drawer.tsx +251 -0
  72. package/src/field.tsx +61 -0
  73. package/src/index.ts +37 -0
  74. package/src/input-date.tsx +1539 -0
  75. package/src/input-group.tsx +142 -0
  76. package/src/input-otp.tsx +324 -0
  77. package/src/menu-cluster.ts +124 -0
  78. package/src/menu.tsx +1095 -0
  79. package/src/menubar.tsx +459 -0
  80. package/src/message-scroller.tsx +732 -0
  81. package/src/native.ts +26 -0
  82. package/src/navigation-menu.tsx +578 -0
  83. package/src/popover.tsx +519 -0
  84. package/src/popup-surface.tsx +31 -0
  85. package/src/popup.ts +569 -0
  86. package/src/position.ts +523 -0
  87. package/src/progress.tsx +70 -0
  88. package/src/radio-group.tsx +186 -0
  89. package/src/resizable.tsx +310 -0
  90. package/src/segments.ts +922 -0
  91. package/src/select.tsx +1501 -0
  92. package/src/sidebar.tsx +683 -0
  93. package/src/slider.tsx +424 -0
  94. package/src/switch.tsx +104 -0
  95. package/src/tabs.tsx +314 -0
  96. package/src/toast.tsx +923 -0
  97. package/src/toggle-group.tsx +249 -0
  98. package/src/toggle.tsx +91 -0
  99. package/src/toolbar.tsx +212 -0
  100. package/src/tooltip.tsx +359 -0
  101. package/src/utils.ts +204 -0
  102. package/src/virtual-list.tsx +205 -0
  103. package/src/virtual.ts +385 -0
@@ -0,0 +1,459 @@
1
+ import type { IntrinsicElements, Stateful, Stateless, WithChildren } from 'ajo'
2
+ import { callHandler, callRef, id, listen, statefulRootAttrs as rootAttrs } from 'ajo-cloves'
3
+ import { context } from 'ajo/context'
4
+ import { bar } from './bar'
5
+ import type { ReservedPositionArg } from './position'
6
+ import type { FixedArgs, OmitArg, PopupPosition } from './utils'
7
+ import {
8
+ Menu,
9
+ MenuCheckboxItem,
10
+ MenuContent,
11
+ MenuGroup,
12
+ MenuItem,
13
+ MenuLabel,
14
+ MenuRadioGroup,
15
+ MenuRadioItem,
16
+ MenuSeparator,
17
+ MenuShortcut,
18
+ MenuSub,
19
+ MenuSubContent,
20
+ MenuSubTrigger,
21
+ MenuTrigger,
22
+ } from './menu'
23
+ import type {
24
+ MenuCheckboxItemArgs,
25
+ MenuContentArgs,
26
+ MenuGroupArgs,
27
+ MenuItemArgs,
28
+ MenuLabelArgs,
29
+ MenuRadioGroupArgs,
30
+ MenuRadioItemArgs,
31
+ MenuSeparatorArgs,
32
+ MenuShortcutArgs,
33
+ MenuSubContentArgs,
34
+ MenuSubArgs,
35
+ MenuSubTriggerArgs,
36
+ MenuTriggerArgs,
37
+ } from './menu'
38
+ import { provideMenubarComposition } from './menu-cluster'
39
+ import { text, withSlot } from './utils'
40
+ export type { PopupPlacement, PopupPosition } from './utils'
41
+
42
+ /** Arguments for a horizontal Menubar and its controlled open menu. */
43
+ export type MenubarArgs = WithChildren<OmitArg<IntrinsicElements['div'], 'onchange' | ReservedPositionArg> & PopupPosition & {
44
+ /** Controlled open top-level menu value. */
45
+ value?: string
46
+ /** Initial open top-level menu value for uncontrolled usage. */
47
+ defaultValue?: string
48
+ /** Disable every menubar trigger and menu item. */
49
+ disabled?: boolean
50
+ /** Wrap arrow-key navigation at the ends. */
51
+ loop?: boolean
52
+ /** Called whenever the open top-level menu changes. Empty string means closed. */
53
+ onValueChange?: (value: string, event?: Event) => void
54
+ /** Additional UnoCSS classes. */
55
+ class?: string
56
+ }> & FixedArgs<'onchange' | ReservedPositionArg>
57
+
58
+ /** Arguments for one value-bearing top-level menu in a Menubar. */
59
+ export type MenubarMenuArgs = WithChildren<OmitArg<IntrinsicElements['div'], 'gap' | 'placement' | ReservedPositionArg> & {
60
+ /** Top-level menu value used by controlled Menubar state. */
61
+ value?: string
62
+ /** Disable this top-level menu. */
63
+ disabled?: boolean
64
+ /** Additional UnoCSS classes. */
65
+ class?: string
66
+ }> & FixedArgs<'gap' | 'placement' | ReservedPositionArg>
67
+
68
+ /** Arguments for the trigger of a top-level Menubar menu. */
69
+ export type MenubarTriggerArgs = WithChildren<MenuTriggerArgs & {
70
+ /** Plain-text label used for menubar typeahead. */
71
+ textValue?: string
72
+ }>
73
+
74
+ /** Arguments for positioned content belonging to a top-level Menubar menu. */
75
+ export type MenubarContentArgs = MenuContentArgs
76
+
77
+ /** Arguments for a standard actionable Menubar item. */
78
+ export type MenubarItemArgs = MenuItemArgs
79
+ /** Arguments for a checkable Menubar item. */
80
+ export type MenubarCheckboxItemArgs = MenuCheckboxItemArgs
81
+ /** Arguments for a single-selection group inside a Menubar menu. */
82
+ export type MenubarRadioGroupArgs = MenuRadioGroupArgs
83
+ /** Arguments for one value-bearing Menubar radio item. */
84
+ export type MenubarRadioItemArgs = MenuRadioItemArgs
85
+ /** Arguments for a non-interactive label inside a Menubar menu. */
86
+ export type MenubarLabelArgs = MenuLabelArgs
87
+ /** Arguments for a semantic group of Menubar items. */
88
+ export type MenubarGroupArgs = MenuGroupArgs
89
+ /** Arguments for a visual separator between Menubar groups. */
90
+ export type MenubarSeparatorArgs = MenuSeparatorArgs
91
+ /** Arguments for a shortcut hint beside a Menubar item. */
92
+ export type MenubarShortcutArgs = MenuShortcutArgs
93
+ /** Arguments for a nested Menubar submenu provider. */
94
+ export type MenubarSubArgs = MenuSubArgs
95
+ /** Arguments for the item that opens a nested Menubar submenu. */
96
+ export type MenubarSubTriggerArgs = MenuSubTriggerArgs
97
+ /** Arguments for positioned content belonging to a Menubar submenu. */
98
+ export type MenubarSubContentArgs = MenuSubContentArgs
99
+
100
+ type MenubarContextValue = {
101
+ ackFocus: (value: string) => boolean
102
+ close: (event?: Event) => void
103
+ disabled: boolean
104
+ focus: (value: string, event?: Event) => void
105
+ follow: (value: string, event?: Event) => void
106
+ gap: PopupPosition['gap']
107
+ isTabbable: (value: string) => boolean
108
+ open: (value: string, event?: Event) => void
109
+ placement: PopupPosition['placement']
110
+ register: (value: string, element: HTMLButtonElement | null) => void
111
+ value: string
112
+ }
113
+
114
+ type MenubarMenuContextValue = {
115
+ disabled: boolean
116
+ value: string
117
+ }
118
+
119
+ const MenubarContext = context<MenubarContextValue | null>(null)
120
+ const MenubarMenuContext = context<MenubarMenuContextValue | null>(null)
121
+
122
+ const order = (root: HTMLElement) =>
123
+ Array.from(root.querySelectorAll<HTMLButtonElement>('[data-menubar-trigger="true"]'))
124
+ .filter(trigger =>
125
+ !trigger.disabled
126
+ && trigger.offsetParent !== null
127
+ && trigger.closest('[data-slot="menubar"]') === root)
128
+
129
+ const MenubarRoot: Stateful<MenubarArgs> = function* ({ defaultValue, value }) {
130
+ const triggers = new Map<string, HTMLButtonElement>()
131
+ let disabled = false
132
+ let entering = false
133
+ let loop = true
134
+ let onValueChange: MenubarArgs['onValueChange']
135
+ let pendingFocus = ''
136
+ let queued = false
137
+
138
+ const state = bar(this, {
139
+ triggers: () => order(this),
140
+ initialValue: String(value ?? defaultValue ?? ''),
141
+ disabled: () => disabled,
142
+ loop: () => loop,
143
+ onValueChange: (next, event) => onValueChange?.(next, event),
144
+ })
145
+
146
+ // Trigger mount/unmount changes the tab-stop row after the render that
147
+ // caused it; the microtask queue coalesces the follow-up pass (ajo render
148
+ // semantics: refs run during render, no reentrant render).
149
+ const rerender = () => {
150
+ if (queued) return
151
+ queued = true
152
+ queueMicrotask(() => {
153
+ queued = false
154
+ this.next()
155
+ })
156
+ }
157
+
158
+ const register = (itemValue: string, element: HTMLButtonElement | null) => {
159
+ if (element) {
160
+ if (triggers.get(itemValue) === element) return
161
+ triggers.set(itemValue, element)
162
+ rerender()
163
+ } else if (triggers.delete(itemValue)) {
164
+ // Tab-stop repair falls back to DOM order through the row query.
165
+ if (state.focused === itemValue) state.adopt('')
166
+ rerender()
167
+ }
168
+ }
169
+
170
+ const close = (event?: Event) => {
171
+ pendingFocus = ''
172
+ state.close(event)
173
+ }
174
+
175
+ const focus = (next: string, event?: Event) => {
176
+ if (!entering) pendingFocus = ''
177
+ state.focus(next, event)
178
+ }
179
+
180
+ const follow = (next: string, event?: Event) => {
181
+ if (!entering) pendingFocus = ''
182
+ state.follow(next, event)
183
+ }
184
+
185
+ const open = (next: string, event?: Event) => {
186
+ pendingFocus = ''
187
+ state.setValue(next, event)
188
+ }
189
+
190
+ const enter = (next: string, event: Event) => {
191
+ pendingFocus = next
192
+ entering = true
193
+ try {
194
+ state.follow(next, event)
195
+ } finally {
196
+ entering = false
197
+ }
198
+ }
199
+
200
+ const ackFocus = (next: string) => {
201
+ if (!next || pendingFocus !== next) return false
202
+ pendingFocus = ''
203
+ return true
204
+ }
205
+
206
+ listen(this, 'keydown', (event: KeyboardEvent) => {
207
+ if (event.defaultPrevented) return
208
+ const target = event.target as HTMLElement | null
209
+ if (target?.closest('[data-slot="menubar"]') !== this) return
210
+
211
+ if (event.key === 'Tab') {
212
+ // Tab leaves the bar (from a trigger or from inside an open menu):
213
+ // close and let focus proceed.
214
+ close(event)
215
+ return
216
+ }
217
+
218
+ if (target?.closest('[data-menubar-trigger="true"]')) {
219
+ if (event.key === 'Escape') pendingFocus = ''
220
+ const transfer = Boolean(pendingFocus)
221
+ if (transfer) entering = true
222
+ try {
223
+ if (state.handle(event) && transfer) pendingFocus = state.value
224
+ } finally {
225
+ if (transfer) entering = false
226
+ }
227
+ return
228
+ }
229
+
230
+ // ArrowLeft/Right from inside an open menu move to the adjacent
231
+ // top-level menu with its first item focused (APG). Submenu-owned
232
+ // arrows stay with the submenu machinery: ArrowRight enters a submenu
233
+ // from its trigger, ArrowLeft closes one from inside.
234
+ if (state.value && (event.key === 'ArrowLeft' || event.key === 'ArrowRight') && target?.closest('[data-menu-content="true"]')) {
235
+ if (event.key === 'ArrowRight' && target.closest('[data-menu-sub-trigger="true"]')) return
236
+ if (target.closest('[data-menu-sub-content="true"]')) return
237
+ const row = order(this)
238
+ const index = row.findIndex(trigger => trigger.dataset.value === state.value)
239
+ if (index < 0) return
240
+ const step = event.key === 'ArrowRight' ? 1 : -1
241
+ const next = row[index + step] ?? (loop ? row[(index + step + row.length) % row.length] : undefined)
242
+ if (!next || next === row[index]) return
243
+ event.preventDefault()
244
+ enter(next.dataset.value ?? '', event)
245
+ }
246
+ })
247
+
248
+ for (const args of this) {
249
+ disabled = Boolean(args.disabled)
250
+ loop = args.loop !== false
251
+ onValueChange = args.onValueChange
252
+ state.sync(args.value != null ? String(args.value ?? '') : undefined)
253
+
254
+ MenubarContext({
255
+ ackFocus,
256
+ close,
257
+ disabled,
258
+ focus,
259
+ follow,
260
+ gap: args.gap,
261
+ isTabbable: state.isTabbable,
262
+ open,
263
+ placement: args.placement,
264
+ register,
265
+ value: state.value,
266
+ })
267
+
268
+ yield <>{args.children}</>
269
+ }
270
+ }
271
+
272
+
273
+ /** Persistent horizontal menu bar. */
274
+ const Menubar: Stateless<MenubarArgs> = ({
275
+ children,
276
+ class: classes,
277
+ defaultValue,
278
+ disabled,
279
+ gap,
280
+ loop,
281
+ onValueChange,
282
+ placement,
283
+ value,
284
+ ...attrs
285
+ }) => (
286
+ <MenubarRoot
287
+ {...rootAttrs(attrs)}
288
+ defaultValue={defaultValue}
289
+ disabled={disabled}
290
+ gap={gap}
291
+ loop={loop}
292
+ onValueChange={onValueChange}
293
+ placement={placement}
294
+ value={value}
295
+ attr:aria-orientation="horizontal"
296
+ attr:class={classes}
297
+ attr:data-slot="menubar"
298
+ attr:role="menubar"
299
+ >
300
+ {children}
301
+ </MenubarRoot>
302
+ )
303
+
304
+ const MenubarMenuRoot: Stateful<MenubarMenuArgs> = function* ({ value }) {
305
+ const fallback = id('menubar-menu')
306
+ let bar: MenubarContextValue | null = null
307
+ let itemValue = String(value ?? fallback)
308
+ const ackFocus = () => bar?.ackFocus(itemValue) ?? false
309
+
310
+ for (const args of this) {
311
+ bar = MenubarContext()
312
+ itemValue = String(args.value ?? value ?? fallback)
313
+ const disabled = Boolean(args.disabled ?? bar?.disabled)
314
+
315
+ MenubarMenuContext({ disabled, value: itemValue })
316
+ if (bar) provideMenubarComposition(ackFocus)
317
+
318
+ yield (
319
+ // Without a Menubar ancestor the menu degrades to a standalone
320
+ // uncontrolled Menu instead of a permanently-closed one.
321
+ <Menu
322
+ disabled={disabled}
323
+ gap={bar?.gap}
324
+ onOpenChange={(open, event) => open ? bar?.open(itemValue, event) : bar?.close(event)}
325
+ open={bar ? bar.value === itemValue : undefined}
326
+ placement={bar?.placement}
327
+ >
328
+ {args.children}
329
+ </Menu>
330
+ )
331
+ }
332
+ }
333
+
334
+
335
+ /** Top-level Menubar menu. */
336
+ const MenubarMenu: Stateless<MenubarMenuArgs> = ({
337
+ children,
338
+ class: classes,
339
+ disabled,
340
+ value,
341
+ ...attrs
342
+ }) => (
343
+ <MenubarMenuRoot
344
+ {...rootAttrs(attrs)}
345
+ disabled={disabled}
346
+ value={value}
347
+ attr:class={classes}
348
+ attr:data-slot="menubar-menu"
349
+ >
350
+ {children}
351
+ </MenubarMenuRoot>
352
+ )
353
+
354
+ /** Top-level trigger inside a Menubar. */
355
+ const MenubarTrigger: Stateless<MenubarTriggerArgs> = ({
356
+ children,
357
+ class: classes,
358
+ disabled,
359
+ ref,
360
+ textValue,
361
+ 'set:onfocus': onFocus,
362
+ 'set:onmouseenter': onMouseEnter,
363
+ ...attrs
364
+ }) => {
365
+ const bar = MenubarContext()
366
+ const menu = MenubarMenuContext()
367
+ const itemValue = menu?.value ?? ''
368
+ const disabledFlag = Boolean(disabled ?? menu?.disabled ?? bar?.disabled)
369
+ const label = textValue ?? text(children)
370
+ const reference = (element: HTMLButtonElement | null) => {
371
+ if (itemValue) bar?.register(itemValue, element)
372
+ callRef(ref, element)
373
+ }
374
+
375
+ return (
376
+ <MenuTrigger
377
+ {...attrs}
378
+ class={classes}
379
+ data-label={bar ? label : undefined}
380
+ data-menubar-trigger={bar ? 'true' : undefined}
381
+ data-slot="menubar-trigger"
382
+ data-value={bar ? itemValue : undefined}
383
+ disabled={disabledFlag}
384
+ ref={reference}
385
+ role={bar ? 'menuitem' : undefined}
386
+ set:onfocus={(event: FocusEvent) => {
387
+ callHandler(onFocus, event)
388
+ if (event.defaultPrevented || disabledFlag) return
389
+ // Single follow path: roving/typeahead only focus, this follows.
390
+ bar?.focus(itemValue, event)
391
+ }}
392
+ set:onmouseenter={(event: MouseEvent) => {
393
+ callHandler(onMouseEnter, event)
394
+ if (event.defaultPrevented || disabledFlag) return
395
+ bar?.follow(itemValue, event)
396
+ }}
397
+ tabindex={bar ? (bar.isTabbable(itemValue) ? 0 : -1) : undefined}
398
+ >
399
+ {children}
400
+ </MenuTrigger>
401
+ )
402
+ }
403
+
404
+ /** Popover content for a top-level Menubar menu. */
405
+ const MenubarContent: Stateless<MenubarContentArgs> = withSlot<MenubarContentArgs>(
406
+ MenuContent,
407
+ 'menubar-content',
408
+ )
409
+
410
+ /** Standard menubar action item. */
411
+ const MenubarItem: Stateless<MenubarItemArgs> = withSlot<MenubarItemArgs>(MenuItem, 'menubar-item')
412
+
413
+ /** Checkable menubar item. */
414
+ const MenubarCheckboxItem: Stateless<MenubarCheckboxItemArgs> = withSlot<MenubarCheckboxItemArgs>(MenuCheckboxItem, 'menubar-checkbox-item')
415
+
416
+ /** Radio group inside a menubar menu. */
417
+ const MenubarRadioGroup: Stateless<MenubarRadioGroupArgs> = withSlot<MenubarRadioGroupArgs>(MenuRadioGroup, 'menubar-radio-group')
418
+
419
+ /** Radio item inside a menubar radio group. */
420
+ const MenubarRadioItem: Stateless<MenubarRadioItemArgs> = withSlot<MenubarRadioItemArgs>(MenuRadioItem, 'menubar-radio-item')
421
+
422
+ /** Group of menubar items. */
423
+ const MenubarGroup: Stateless<MenubarGroupArgs> = withSlot<MenubarGroupArgs>(MenuGroup, 'menubar-group')
424
+
425
+ /** Non-interactive label inside a menubar menu. */
426
+ const MenubarLabel: Stateless<MenubarLabelArgs> = withSlot<MenubarLabelArgs>(MenuLabel, 'menubar-label')
427
+
428
+ /** Visual separator between menubar groups. */
429
+ const MenubarSeparator: Stateless<MenubarSeparatorArgs> = withSlot<MenubarSeparatorArgs>(MenuSeparator, 'menubar-separator')
430
+
431
+ /** Right-aligned shortcut hint inside a menubar item. */
432
+ const MenubarShortcut: Stateless<MenubarShortcutArgs> = withSlot<MenubarShortcutArgs>(MenuShortcut, 'menubar-shortcut')
433
+
434
+ /** Root provider for a menubar submenu. */
435
+ const MenubarSub: Stateless<MenubarSubArgs> = withSlot<MenubarSubArgs>(MenuSub, 'menubar-sub')
436
+
437
+ /** Trigger item that opens a menubar submenu. */
438
+ const MenubarSubTrigger: Stateless<MenubarSubTriggerArgs> = withSlot<MenubarSubTriggerArgs>(MenuSubTrigger, 'menubar-sub-trigger')
439
+
440
+ /** Content for a menubar submenu. */
441
+ const MenubarSubContent: Stateless<MenubarSubContentArgs> = withSlot<MenubarSubContentArgs>(MenuSubContent, 'menubar-sub-content')
442
+
443
+ export {
444
+ Menubar,
445
+ MenubarCheckboxItem,
446
+ MenubarContent,
447
+ MenubarGroup,
448
+ MenubarItem,
449
+ MenubarLabel,
450
+ MenubarMenu,
451
+ MenubarRadioGroup,
452
+ MenubarRadioItem,
453
+ MenubarSeparator,
454
+ MenubarShortcut,
455
+ MenubarSub,
456
+ MenubarSubContent,
457
+ MenubarSubTrigger,
458
+ MenubarTrigger,
459
+ }