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,233 @@
1
+ import type { IntrinsicElements, Stateful, Stateless, WithChildren } from 'ajo'
2
+ import { callHandler, listen, restore, statefulRootAttrs as rootAttrs } from 'ajo-cloves'
3
+ import {
4
+ Menu,
5
+ MenuCheckboxItem,
6
+ MenuContent,
7
+ MenuGroup,
8
+ MenuItem,
9
+ MenuLabel,
10
+ MenuRadioGroup,
11
+ MenuRadioItem,
12
+ MenuSeparator,
13
+ MenuShortcut,
14
+ MenuSub,
15
+ MenuSubContent,
16
+ MenuSubTrigger,
17
+ } from './menu'
18
+ import type {
19
+ MenuArgs,
20
+ MenuCheckboxItemArgs,
21
+ MenuContentArgs,
22
+ MenuGroupArgs,
23
+ MenuItemArgs,
24
+ MenuLabelArgs,
25
+ MenuRadioGroupArgs,
26
+ MenuRadioItemArgs,
27
+ MenuSeparatorArgs,
28
+ MenuShortcutArgs,
29
+ MenuSubArgs,
30
+ MenuSubContentArgs,
31
+ MenuSubTriggerArgs,
32
+ } from './menu'
33
+ import {
34
+ menuInvocation,
35
+ provideContextMenuComposition,
36
+ SURFACE_SELECTOR,
37
+ type ContextMenuInvoke,
38
+ } from './menu-cluster'
39
+ import { pointReference, type PositionReference } from './position'
40
+ import { type FixedArgs, type OmitArg, withSlot } from './utils'
41
+
42
+ /** Arguments for the invocation-driven ContextMenu root. */
43
+ export type ContextMenuArgs = OmitArg<MenuArgs, 'defaultOpen' | 'gap' | 'open' | 'placement'> & FixedArgs<'defaultOpen' | 'gap' | 'open' | 'placement'>
44
+ /** Arguments for the floating ContextMenu surface. */
45
+ export type ContextMenuContentArgs = MenuContentArgs
46
+ /** Arguments for an actionable ContextMenu item. */
47
+ export type ContextMenuItemArgs = MenuItemArgs
48
+ /** Arguments for a checked ContextMenu item. */
49
+ export type ContextMenuCheckboxItemArgs = MenuCheckboxItemArgs
50
+ /** Arguments for a single-value ContextMenu radio group. */
51
+ export type ContextMenuRadioGroupArgs = MenuRadioGroupArgs
52
+ /** Arguments for one ContextMenu radio option. */
53
+ export type ContextMenuRadioItemArgs = MenuRadioItemArgs
54
+ /** Arguments for a non-interactive ContextMenu label. */
55
+ export type ContextMenuLabelArgs = MenuLabelArgs
56
+ /** Arguments for a semantic ContextMenu item group. */
57
+ export type ContextMenuGroupArgs = MenuGroupArgs
58
+ /** Arguments for a ContextMenu separator. */
59
+ export type ContextMenuSeparatorArgs = MenuSeparatorArgs
60
+ /** Arguments for shortcut text displayed in a ContextMenu. */
61
+ export type ContextMenuShortcutArgs = MenuShortcutArgs
62
+ /** Arguments for a nested ContextMenu root. */
63
+ export type ContextMenuSubArgs = MenuSubArgs
64
+ /** Arguments for the item that opens a nested ContextMenu. */
65
+ export type ContextMenuSubTriggerArgs = MenuSubTriggerArgs
66
+ /** Arguments for a nested ContextMenu surface. */
67
+ export type ContextMenuSubContentArgs = MenuSubContentArgs
68
+
69
+ /** Arguments for the single region that invokes a ContextMenu. */
70
+ export type ContextMenuTriggerArgs = WithChildren<IntrinsicElements['div'] & {
71
+ /** Disable context menu activation. */
72
+ disabled?: boolean
73
+ /** Additional UnoCSS classes. */
74
+ class?: string
75
+ }>
76
+
77
+ const ContextMenuRoot: Stateful<ContextMenuArgs> = function* () {
78
+ const focus = restore(this)
79
+ let invoker: HTMLElement | null = null
80
+ let point = { x: 0, y: 0 }
81
+ let reference: PositionReference | null = null
82
+
83
+ const invoke: ContextMenuInvoke = (controller, x, y, event, source, focusIntent) => {
84
+ point.x = x
85
+ point.y = y
86
+ if (source !== invoker || !reference) {
87
+ invoker = source
88
+ point = { x, y }
89
+ reference = pointReference(source, () => point)
90
+ }
91
+ focus.capture(source)
92
+ controller(reference, source, event, focusIntent)
93
+ }
94
+
95
+ listen(this, 'contextmenu', (event: Event) => {
96
+ const target = event.target as HTMLElement | null
97
+ if (target?.closest(SURFACE_SELECTOR)) event.preventDefault()
98
+ })
99
+
100
+ for (const args of this) {
101
+ provideContextMenuComposition(invoke, focus.restore)
102
+
103
+ yield (
104
+ <Menu disabled={args.disabled} onOpenChange={args.onOpenChange}>
105
+ {args.children}
106
+ </Menu>
107
+ )
108
+ }
109
+ }
110
+
111
+ /** Root provider for a context menu. */
112
+ const ContextMenu: Stateless<ContextMenuArgs> = ({
113
+ children,
114
+ class: classes,
115
+ disabled,
116
+ onOpenChange,
117
+ ...attrs
118
+ }) => (
119
+ <ContextMenuRoot
120
+ {...rootAttrs(attrs)}
121
+ disabled={disabled}
122
+ onOpenChange={onOpenChange}
123
+ attr:class={classes}
124
+ attr:data-slot="context-menu"
125
+ >
126
+ {children}
127
+ </ContextMenuRoot>
128
+ )
129
+
130
+ /** The single region that invokes its ContextMenu by pointer or keyboard. */
131
+ const ContextMenuTrigger: Stateless<ContextMenuTriggerArgs> = ({
132
+ children,
133
+ class: classes,
134
+ disabled,
135
+ id,
136
+ ref,
137
+ tabindex,
138
+ 'set:oncontextmenu': onContextMenu,
139
+ 'set:onkeydown': onKeydown,
140
+ ...attrs
141
+ }) => {
142
+ const menu = menuInvocation()
143
+ const disabledFlag = Boolean(disabled ?? menu?.disabled)
144
+ const adoptedId = menu?.adoptTriggerId(id)
145
+
146
+ return (
147
+ <div
148
+ {...attrs}
149
+ aria-controls={menu?.contentId}
150
+ aria-disabled={disabledFlag ? 'true' : undefined}
151
+ aria-expanded={menu?.open ? 'true' : 'false'}
152
+ aria-haspopup="menu"
153
+ class={classes}
154
+ data-disabled={disabledFlag ? 'true' : undefined}
155
+ data-slot="context-menu-trigger"
156
+ data-state={menu?.open ? 'open' : 'closed'}
157
+ id={adoptedId ?? id}
158
+ ref={ref}
159
+ set:oncontextmenu={(event: MouseEvent) => {
160
+ const element = event.currentTarget as HTMLElement
161
+ callHandler(onContextMenu, event)
162
+ if (event.defaultPrevented || disabledFlag) return
163
+ event.preventDefault()
164
+ menu?.invoke(event.clientX, event.clientY, event, element, 'content')
165
+ }}
166
+ set:onkeydown={(event: KeyboardEvent) => {
167
+ const element = event.currentTarget as HTMLElement
168
+ callHandler(onKeydown, event)
169
+ if (event.defaultPrevented || disabledFlag) return
170
+ if (event.key !== 'ContextMenu' && !(event.key === 'F10' && event.shiftKey)) return
171
+ event.preventDefault()
172
+ const rect = element.getBoundingClientRect()
173
+ menu?.invoke(rect.left, rect.bottom, event, element, 'first')
174
+ }}
175
+ tabindex={disabledFlag ? undefined : tabindex ?? 0}
176
+ >
177
+ {children}
178
+ </div>
179
+ )
180
+ }
181
+
182
+ /** Popover menu content opened by a ContextMenuTrigger. */
183
+ const ContextMenuContent: Stateless<ContextMenuContentArgs> = withSlot<ContextMenuContentArgs>(MenuContent, 'context-menu-content')
184
+
185
+ /** Standard context menu action item. */
186
+ const ContextMenuItem: Stateless<ContextMenuItemArgs> = withSlot<ContextMenuItemArgs>(MenuItem, 'context-menu-item')
187
+
188
+ /** Checkable context menu item. */
189
+ const ContextMenuCheckboxItem: Stateless<ContextMenuCheckboxItemArgs> = withSlot<ContextMenuCheckboxItemArgs>(MenuCheckboxItem, 'context-menu-checkbox-item')
190
+
191
+ /** Radio group inside a context menu. */
192
+ const ContextMenuRadioGroup: Stateless<ContextMenuRadioGroupArgs> = withSlot<ContextMenuRadioGroupArgs>(MenuRadioGroup, 'context-menu-radio-group')
193
+
194
+ /** Radio item inside a context menu radio group. */
195
+ const ContextMenuRadioItem: Stateless<ContextMenuRadioItemArgs> = withSlot<ContextMenuRadioItemArgs>(MenuRadioItem, 'context-menu-radio-item')
196
+
197
+ /** Group of context menu items. */
198
+ const ContextMenuGroup: Stateless<ContextMenuGroupArgs> = withSlot<ContextMenuGroupArgs>(MenuGroup, 'context-menu-group')
199
+
200
+ /** Non-interactive label inside a context menu. */
201
+ const ContextMenuLabel: Stateless<ContextMenuLabelArgs> = withSlot<ContextMenuLabelArgs>(MenuLabel, 'context-menu-label')
202
+
203
+ /** Visual separator between context menu groups. */
204
+ const ContextMenuSeparator: Stateless<ContextMenuSeparatorArgs> = withSlot<ContextMenuSeparatorArgs>(MenuSeparator, 'context-menu-separator')
205
+
206
+ /** Right-aligned shortcut hint inside a context menu item. */
207
+ const ContextMenuShortcut: Stateless<ContextMenuShortcutArgs> = withSlot<ContextMenuShortcutArgs>(MenuShortcut, 'context-menu-shortcut')
208
+
209
+ /** Root provider for a context submenu. */
210
+ const ContextMenuSub: Stateless<ContextMenuSubArgs> = withSlot<ContextMenuSubArgs>(MenuSub, 'context-menu-sub')
211
+
212
+ /** Trigger item that opens a context submenu. */
213
+ const ContextMenuSubTrigger: Stateless<ContextMenuSubTriggerArgs> = withSlot<ContextMenuSubTriggerArgs>(MenuSubTrigger, 'context-menu-sub-trigger')
214
+
215
+ /** Content for a context submenu. */
216
+ const ContextMenuSubContent: Stateless<ContextMenuSubContentArgs> = withSlot<ContextMenuSubContentArgs>(MenuSubContent, 'context-menu-sub-content')
217
+
218
+ export {
219
+ ContextMenu,
220
+ ContextMenuCheckboxItem,
221
+ ContextMenuContent,
222
+ ContextMenuGroup,
223
+ ContextMenuItem,
224
+ ContextMenuLabel,
225
+ ContextMenuRadioGroup,
226
+ ContextMenuRadioItem,
227
+ ContextMenuSeparator,
228
+ ContextMenuShortcut,
229
+ ContextMenuSub,
230
+ ContextMenuSubContent,
231
+ ContextMenuSubTrigger,
232
+ ContextMenuTrigger,
233
+ }
@@ -0,0 +1,143 @@
1
+ import type { Children, IntrinsicElements } from 'ajo'
2
+ import type { FixedArgs, OmitArg } from './utils'
3
+
4
+ export type DataTableKey = number | string
5
+ export type DataTableData = any[] | Record<string, any>
6
+
7
+ export type DataTableScalar = boolean | number | string | null | undefined
8
+
9
+ export type DataTableCellContext = {
10
+ columnId: string
11
+ sourceIndex: number
12
+ value: unknown
13
+ }
14
+
15
+ export type DataTableFacet<T extends DataTableData> = {
16
+ label: string
17
+ options: readonly {
18
+ icon?: Children
19
+ label: string
20
+ value: string
21
+ }[]
22
+ values?: (row: T, sourceIndex: number) => string | readonly string[]
23
+ }
24
+
25
+ type DataTableColumnBase = {
26
+ /** Plain accessible name used by menus, sorting, and announcements. */
27
+ label: string
28
+ /** Visual header content. Defaults to `label`. */
29
+ header?: Children
30
+ align?: 'center' | 'left' | 'right'
31
+ defaultHidden?: boolean
32
+ hideable?: boolean
33
+ }
34
+
35
+ type DataTableValue<T extends DataTableData> =
36
+ | { id?: string; value: keyof T & string }
37
+ | { id: string; value: (row: T, sourceIndex: number) => unknown }
38
+
39
+ type DataTableValueColumn<T extends DataTableData> = DataTableColumnBase & DataTableValue<T> & {
40
+ cell?: (row: T, context: DataTableCellContext) => Children
41
+ sort?: false | ((left: T, right: T) => number)
42
+ search?: false | ((row: T, sourceIndex: number) => DataTableScalar)
43
+ facet?: DataTableFacet<T>
44
+ }
45
+
46
+ type DataTableDisplayColumn<T extends DataTableData> = DataTableColumnBase & {
47
+ id: string
48
+ value?: never
49
+ cell: (row: T, context: DataTableCellContext) => Children
50
+ sort?: false
51
+ search?: false
52
+ facet?: never
53
+ }
54
+
55
+ /** A stable Ajo column schema; TanStack implementation details stay private. */
56
+ export type DataTableColumn<T extends DataTableData> = DataTableDisplayColumn<T> | DataTableValueColumn<T>
57
+
58
+ type DataTableSelectionChange<Key extends DataTableKey> = (
59
+ keys: readonly Key[],
60
+ event?: Event,
61
+ ) => void
62
+
63
+ export type DataTableSelection<T extends DataTableData, Key extends DataTableKey = DataTableKey> = {
64
+ getRowLabel: (row: T, sourceIndex: number) => string
65
+ } & (
66
+ | {
67
+ value: readonly Key[]
68
+ defaultValue?: readonly Key[]
69
+ onValueChange: DataTableSelectionChange<Key>
70
+ }
71
+ | {
72
+ value?: undefined
73
+ defaultValue?: readonly Key[]
74
+ onValueChange?: DataTableSelectionChange<Key>
75
+ }
76
+ )
77
+
78
+ export type DataTablePagination = {
79
+ defaultSize?: number
80
+ sizes?: readonly number[]
81
+ }
82
+
83
+ export type DataTableSortName = 'ascending' | 'descending' | 'none'
84
+
85
+ export type DataTableLabels = {
86
+ columns: string
87
+ deselectPage: string
88
+ deselectResults: string
89
+ deselectRow: (rowLabel: string) => string
90
+ firstPage: string
91
+ lastPage: string
92
+ nextPage: string
93
+ page: (page: number, pages: number) => string
94
+ pagination: (tableLabel: string) => string
95
+ previousPage: string
96
+ reset: string
97
+ results: (count: number) => string
98
+ rowsPerPage: string
99
+ search: string
100
+ selectPage: string
101
+ selectResults: string
102
+ selectRow: (rowLabel: string) => string
103
+ selected: (selected: number, sourceTotal: number) => string
104
+ sort: (columnLabel: string, next: DataTableSortName) => string
105
+ toolbar: (tableLabel: string) => string
106
+ }
107
+
108
+ /** Arguments for the client-side, paginated DataTable strategy. */
109
+ export type DataTableArgs<
110
+ T extends DataTableData = Record<string, unknown>,
111
+ Key extends DataTableKey = DataTableKey,
112
+ > = OmitArg<
113
+ IntrinsicElements['div'],
114
+ 'aria-label' | 'aria-labelledby' | 'children' | 'data-slot'
115
+ > & FixedArgs<
116
+ 'aria-label'
117
+ | 'aria-labelledby'
118
+ | 'attr:aria-label'
119
+ | 'attr:aria-labelledby'
120
+ | 'attr:data-slot'
121
+ | 'children'
122
+ | 'data-slot'
123
+ | 'set:ariaLabel'
124
+ | 'set:ariaLabelledByElements'
125
+ > & {
126
+ /** Plain accessible name applied to the native table element. */
127
+ label: string
128
+ /** Immutable ordered logical collection. */
129
+ rows: readonly T[]
130
+ /** Stable unique identity across filter, sort, page, and refresh. */
131
+ getRowKey: (row: T, sourceIndex: number) => Key
132
+ /** Immutable column schema with stable IDs. */
133
+ columns: readonly DataTableColumn<T>[]
134
+ /** Opt-in global search. */
135
+ search?: { placeholder?: string }
136
+ /** Presence enables key-first row selection. */
137
+ selection?: DataTableSelection<T, Key>
138
+ /** Pagination is enabled by default; false renders every filtered row. */
139
+ pagination?: false | DataTablePagination
140
+ empty?: Children
141
+ labels?: Partial<DataTableLabels>
142
+ children?: never
143
+ }