@octanejs/aria 0.0.4 → 0.0.5

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 (93) hide show
  1. package/package.json +7 -5
  2. package/src/autocomplete/useAutocomplete.ts +656 -0
  3. package/src/collections/BaseCollection.ts +374 -0
  4. package/src/collections/CollectionBuilder.ts +343 -0
  5. package/src/collections/Document.ts +451 -0
  6. package/src/collections/Hidden.ts +84 -0
  7. package/src/collections/useCachedChildren.ts +103 -0
  8. package/src/components/Autocomplete.ts +124 -0
  9. package/src/components/Breadcrumbs.ts +170 -0
  10. package/src/components/Button.ts +209 -0
  11. package/src/components/Checkbox.ts +593 -0
  12. package/src/components/Collection.ts +301 -0
  13. package/src/components/ComboBox.ts +477 -0
  14. package/src/components/Dialog.ts +195 -0
  15. package/src/components/Disclosure.ts +322 -0
  16. package/src/components/DragAndDrop.ts +177 -0
  17. package/src/components/FieldError.ts +79 -0
  18. package/src/components/Form.ts +65 -0
  19. package/src/components/GridList.ts +1099 -0
  20. package/src/components/Group.ts +146 -0
  21. package/src/components/Header.ts +32 -0
  22. package/src/components/Heading.ts +45 -0
  23. package/src/components/Input.ts +139 -0
  24. package/src/components/Keyboard.ts +23 -0
  25. package/src/components/Label.ts +30 -0
  26. package/src/components/Link.ts +137 -0
  27. package/src/components/ListBox.ts +886 -0
  28. package/src/components/Menu.ts +685 -0
  29. package/src/components/Meter.ts +100 -0
  30. package/src/components/Modal.ts +352 -0
  31. package/src/components/NumberField.ts +221 -0
  32. package/src/components/OverlayArrow.ts +117 -0
  33. package/src/components/Popover.ts +385 -0
  34. package/src/components/ProgressBar.ts +112 -0
  35. package/src/components/RadioGroup.ts +542 -0
  36. package/src/components/SearchField.ts +208 -0
  37. package/src/components/Select.ts +505 -0
  38. package/src/components/SelectionIndicator.ts +52 -0
  39. package/src/components/Separator.ts +97 -0
  40. package/src/components/SharedElementTransition.ts +209 -0
  41. package/src/components/Slider.ts +472 -0
  42. package/src/components/Switch.ts +449 -0
  43. package/src/components/Tabs.ts +675 -0
  44. package/src/components/TagGroup.ts +443 -0
  45. package/src/components/Text.ts +27 -0
  46. package/src/components/TextArea.ts +92 -0
  47. package/src/components/TextField.ts +200 -0
  48. package/src/components/ToggleButton.ts +147 -0
  49. package/src/components/ToggleButtonGroup.ts +106 -0
  50. package/src/components/Toolbar.ts +74 -0
  51. package/src/components/Tooltip.ts +249 -0
  52. package/src/components/index.ts +302 -0
  53. package/src/components/useDragAndDrop.ts +164 -0
  54. package/src/components/utils.ts +521 -0
  55. package/src/intl/autocomplete/ar-AE.json +3 -0
  56. package/src/intl/autocomplete/bg-BG.json +3 -0
  57. package/src/intl/autocomplete/cs-CZ.json +3 -0
  58. package/src/intl/autocomplete/da-DK.json +3 -0
  59. package/src/intl/autocomplete/de-DE.json +3 -0
  60. package/src/intl/autocomplete/el-GR.json +3 -0
  61. package/src/intl/autocomplete/en-US.json +3 -0
  62. package/src/intl/autocomplete/es-ES.json +3 -0
  63. package/src/intl/autocomplete/et-EE.json +3 -0
  64. package/src/intl/autocomplete/fi-FI.json +3 -0
  65. package/src/intl/autocomplete/fr-FR.json +3 -0
  66. package/src/intl/autocomplete/he-IL.json +3 -0
  67. package/src/intl/autocomplete/hr-HR.json +3 -0
  68. package/src/intl/autocomplete/hu-HU.json +3 -0
  69. package/src/intl/autocomplete/index.ts +75 -0
  70. package/src/intl/autocomplete/it-IT.json +3 -0
  71. package/src/intl/autocomplete/ja-JP.json +3 -0
  72. package/src/intl/autocomplete/ko-KR.json +3 -0
  73. package/src/intl/autocomplete/lt-LT.json +3 -0
  74. package/src/intl/autocomplete/lv-LV.json +3 -0
  75. package/src/intl/autocomplete/nb-NO.json +3 -0
  76. package/src/intl/autocomplete/nl-NL.json +3 -0
  77. package/src/intl/autocomplete/pl-PL.json +3 -0
  78. package/src/intl/autocomplete/pt-BR.json +3 -0
  79. package/src/intl/autocomplete/pt-PT.json +3 -0
  80. package/src/intl/autocomplete/ro-RO.json +3 -0
  81. package/src/intl/autocomplete/ru-RU.json +3 -0
  82. package/src/intl/autocomplete/sk-SK.json +3 -0
  83. package/src/intl/autocomplete/sl-SI.json +3 -0
  84. package/src/intl/autocomplete/sr-SP.json +3 -0
  85. package/src/intl/autocomplete/sv-SE.json +3 -0
  86. package/src/intl/autocomplete/tr-TR.json +3 -0
  87. package/src/intl/autocomplete/uk-UA.json +3 -0
  88. package/src/intl/autocomplete/zh-CN.json +3 -0
  89. package/src/intl/autocomplete/zh-TW.json +3 -0
  90. package/src/stately/autocomplete/useAutocompleteState.ts +85 -0
  91. package/src/utils/animation.ts +149 -0
  92. package/src/utils/useLoadMoreSentinel.ts +78 -0
  93. package/src/utils/useViewportSize.ts +123 -0
@@ -0,0 +1,472 @@
1
+ // Ported from react-aria-components (source: .react-spectrum/packages/react-aria-components/src/Slider.tsx).
2
+ // octane adaptations: `.tsx` → `.ts`, JSX → `createElement`; NO forwardRef — the forwarded ref
3
+ // is `props.ref`, passed into `useContextProps` explicitly and re-applied as the merged object
4
+ // ref (SliderThumb has no context and reads `props.ref` directly); the plain-`.ts` components
5
+ // use the S()/subSlot component-slot convention; `clamp` comes from the binding's stately
6
+ // utils port; React's HTMLAttributes/OutputHTMLAttributes prop bags → structural records.
7
+ // The thumb's hidden `<input type="range">` keeps upstream's native wiring (position math
8
+ // reads track rects, which are inert in jsdom — tests assert aria/data-* wiring, not pixels).
9
+ import type { HoverEvents, Orientation, RefObject } from '@react-types/shared';
10
+ import { createContext, createElement, useContext, useRef } from 'octane';
11
+
12
+ import { useFocusRing } from '../focus/useFocusRing';
13
+ import { useNumberFormatter } from '../i18n/useNumberFormatter';
14
+ import { useHover } from '../interactions/useHover';
15
+ import { S, subSlot } from '../internal';
16
+ import { type AriaSliderProps, useSlider } from '../slider/useSlider';
17
+ import { type AriaSliderThumbProps, useSliderThumb } from '../slider/useSliderThumb';
18
+ import { type SliderState, useSliderState } from '../stately/slider/useSliderState';
19
+ import { clamp } from '../stately/utils/number';
20
+ import { filterDOMProps } from '../utils/filterDOMProps';
21
+ import { mergeProps } from '../utils/mergeProps';
22
+ import { VisuallyHidden } from '../visually-hidden/VisuallyHidden';
23
+ import { LabelContext } from './Label';
24
+ import {
25
+ type ClassNameOrFunction,
26
+ type ContextValue,
27
+ dom,
28
+ Provider,
29
+ type RenderProps,
30
+ type SlotProps,
31
+ useContextProps,
32
+ useRenderProps,
33
+ useSlot,
34
+ useSlottedContext,
35
+ } from './utils';
36
+
37
+ // octane adaptations: structural bags (upstream's React attribute/handler types).
38
+ type GlobalDOMAttributes = Record<string, any>;
39
+ type HTMLAttributes = Record<string, any>;
40
+ type OutputHTMLAttributes = Record<string, any>;
41
+
42
+ export interface SliderProps<T = number | number[]>
43
+ extends
44
+ Omit<AriaSliderProps<T>, 'label'>,
45
+ RenderProps<SliderRenderProps>,
46
+ SlotProps,
47
+ GlobalDOMAttributes {
48
+ /**
49
+ * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the
50
+ * element. A function may be provided to compute the class based on component state.
51
+ *
52
+ * @default 'react-aria-Slider'
53
+ */
54
+ className?: ClassNameOrFunction<SliderRenderProps>;
55
+ /**
56
+ * The display format of the value label.
57
+ */
58
+ formatOptions?: Intl.NumberFormatOptions;
59
+ }
60
+
61
+ export const SliderContext = createContext<ContextValue<SliderProps, HTMLDivElement>>(null);
62
+ export const SliderStateContext = createContext<SliderState | null>(null);
63
+ export const SliderTrackContext =
64
+ createContext<ContextValue<SliderTrackContextValue, HTMLDivElement>>(null);
65
+ export const SliderFillContext = createContext<ContextValue<SliderFillProps, HTMLDivElement>>(null);
66
+ export const SliderOutputContext =
67
+ createContext<ContextValue<SliderOutputContextValue, HTMLOutputElement>>(null);
68
+
69
+ export interface SliderRenderProps {
70
+ /**
71
+ * The orientation of the slider.
72
+ *
73
+ * @selector [data-orientation="horizontal | vertical"]
74
+ */
75
+ orientation: Orientation;
76
+ /**
77
+ * Whether the slider is disabled.
78
+ *
79
+ * @selector [data-disabled]
80
+ */
81
+ isDisabled: boolean;
82
+ /**
83
+ * State of the slider.
84
+ */
85
+ state: SliderState;
86
+ }
87
+
88
+ /**
89
+ * A slider allows a user to select one or more values within a range.
90
+ */
91
+ export function Slider<T extends number | number[]>(props: SliderProps<T>): any {
92
+ const slot = S('Slider');
93
+ let ref: any;
94
+ [props, ref] = useContextProps(props, props.ref, SliderContext, subSlot(slot, 'ctx'));
95
+ let trackRef = useRef<HTMLDivElement | null>(null, subSlot(slot, 'track'));
96
+ let numberFormatter = useNumberFormatter(props.formatOptions, subSlot(slot, 'formatter'));
97
+ let state = useSliderState({ ...props, numberFormatter }, subSlot(slot, 'state'));
98
+ let [labelRef, label] = useSlot(
99
+ !props['aria-label'] && !props['aria-labelledby'],
100
+ subSlot(slot, 'labelSlot'),
101
+ );
102
+ let { groupProps, trackProps, labelProps, outputProps } = useSlider(
103
+ { ...props, label },
104
+ state,
105
+ trackRef,
106
+ subSlot(slot, 'slider'),
107
+ );
108
+
109
+ let renderProps = useRenderProps(
110
+ {
111
+ ...props,
112
+ values: {
113
+ orientation: state.orientation,
114
+ isDisabled: state.isDisabled,
115
+ state,
116
+ },
117
+ defaultClassName: 'react-aria-Slider',
118
+ },
119
+ subSlot(slot, 'render'),
120
+ );
121
+
122
+ let DOMProps = filterDOMProps(props, { global: true });
123
+ delete DOMProps.id;
124
+
125
+ return createElement(Provider, {
126
+ values: [
127
+ [SliderStateContext, state],
128
+ [SliderTrackContext, { ...trackProps, ref: trackRef }],
129
+ [SliderOutputContext, outputProps],
130
+ [LabelContext, { ...labelProps, ref: labelRef }],
131
+ ] as any,
132
+ children: createElement(dom.div, {
133
+ ...mergeProps(DOMProps, renderProps, groupProps),
134
+ ref,
135
+ slot: props.slot || undefined,
136
+ 'data-orientation': state.orientation,
137
+ 'data-disabled': state.isDisabled || undefined,
138
+ }),
139
+ });
140
+ }
141
+
142
+ export interface SliderOutputProps
143
+ extends RenderProps<SliderRenderProps, 'output'>, GlobalDOMAttributes {
144
+ /**
145
+ * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the
146
+ * element. A function may be provided to compute the class based on component state.
147
+ *
148
+ * @default 'react-aria-SliderOutput'
149
+ */
150
+ className?: ClassNameOrFunction<SliderRenderProps>;
151
+ }
152
+ interface SliderOutputContextValue
153
+ extends Omit<OutputHTMLAttributes, 'children' | 'className' | 'style'>, SliderOutputProps {}
154
+
155
+ /**
156
+ * A slider output displays the current value of a slider as text.
157
+ */
158
+ export function SliderOutput(props: SliderOutputProps): any {
159
+ const slot = S('SliderOutput');
160
+ let ref: any;
161
+ [props, ref] = useContextProps(props, props.ref, SliderOutputContext, subSlot(slot, 'ctx'));
162
+ let { children, style, className, render, ...otherProps } = props;
163
+ let state = useContext(SliderStateContext)!;
164
+ let renderProps = useRenderProps(
165
+ {
166
+ className,
167
+ style,
168
+ children,
169
+ render,
170
+ defaultChildren: state.getFormattedValue(),
171
+ defaultClassName: 'react-aria-SliderOutput',
172
+ values: {
173
+ orientation: state.orientation,
174
+ isDisabled: state.isDisabled,
175
+ state,
176
+ },
177
+ },
178
+ subSlot(slot, 'render'),
179
+ );
180
+
181
+ return createElement(dom.output, {
182
+ ...otherProps,
183
+ ...renderProps,
184
+ ref,
185
+ 'data-orientation': state.orientation || undefined,
186
+ 'data-disabled': state.isDisabled || undefined,
187
+ });
188
+ }
189
+
190
+ export interface SliderTrackRenderProps extends SliderRenderProps {
191
+ /**
192
+ * Whether the slider track is currently hovered with a mouse.
193
+ *
194
+ * @selector [data-hovered]
195
+ */
196
+ isHovered: boolean;
197
+ }
198
+
199
+ export interface SliderTrackProps
200
+ extends HoverEvents, RenderProps<SliderTrackRenderProps>, GlobalDOMAttributes {
201
+ /**
202
+ * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the
203
+ * element. A function may be provided to compute the class based on component state.
204
+ *
205
+ * @default 'react-aria-SliderTrack'
206
+ */
207
+ className?: ClassNameOrFunction<SliderTrackRenderProps>;
208
+ }
209
+ interface SliderTrackContextValue
210
+ extends Omit<HTMLAttributes, 'children' | 'className' | 'style'>, SliderTrackProps {}
211
+
212
+ /**
213
+ * A slider track is a container for one or more slider thumbs.
214
+ */
215
+ export function SliderTrack(props: SliderTrackProps): any {
216
+ const slot = S('SliderTrack');
217
+ let ref: any;
218
+ [props, ref] = useContextProps(props, props.ref, SliderTrackContext, subSlot(slot, 'ctx'));
219
+ let state = useContext(SliderStateContext)!;
220
+ let { onHoverStart, onHoverEnd, onHoverChange, ...otherProps } = props;
221
+ let { hoverProps, isHovered } = useHover(
222
+ { onHoverStart, onHoverEnd, onHoverChange },
223
+ subSlot(slot, 'hover'),
224
+ );
225
+ let renderProps = useRenderProps(
226
+ {
227
+ ...props,
228
+ defaultClassName: 'react-aria-SliderTrack',
229
+ values: {
230
+ orientation: state.orientation,
231
+ isDisabled: state.isDisabled,
232
+ isHovered,
233
+ state,
234
+ },
235
+ },
236
+ subSlot(slot, 'render'),
237
+ );
238
+
239
+ return createElement(dom.div, {
240
+ ...mergeProps(otherProps, hoverProps),
241
+ ...renderProps,
242
+ ref,
243
+ 'data-hovered': isHovered || undefined,
244
+ 'data-orientation': state.orientation || undefined,
245
+ 'data-disabled': state.isDisabled || undefined,
246
+ });
247
+ }
248
+
249
+ export interface SliderThumbRenderProps {
250
+ /**
251
+ * State of the slider.
252
+ */
253
+ state: SliderState;
254
+ /**
255
+ * Whether this thumb is currently being dragged.
256
+ *
257
+ * @selector [data-dragging]
258
+ */
259
+ isDragging: boolean;
260
+ /**
261
+ * Whether the thumb is currently hovered with a mouse.
262
+ *
263
+ * @selector [data-hovered]
264
+ */
265
+ isHovered: boolean;
266
+ /**
267
+ * Whether the thumb is currently focused.
268
+ *
269
+ * @selector [data-focused]
270
+ */
271
+ isFocused: boolean;
272
+ /**
273
+ * Whether the thumb is keyboard focused.
274
+ *
275
+ * @selector [data-focus-visible]
276
+ */
277
+ isFocusVisible: boolean;
278
+ /**
279
+ * Whether the thumb is disabled.
280
+ *
281
+ * @selector [data-disabled]
282
+ */
283
+ isDisabled: boolean;
284
+ }
285
+
286
+ export interface SliderThumbProps
287
+ extends
288
+ Omit<AriaSliderThumbProps, 'label' | 'validationState'>,
289
+ HoverEvents,
290
+ RenderProps<SliderThumbRenderProps>,
291
+ GlobalDOMAttributes {
292
+ /**
293
+ * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the
294
+ * element. A function may be provided to compute the class based on component state.
295
+ *
296
+ * @default 'react-aria-SliderThumb'
297
+ */
298
+ className?: ClassNameOrFunction<SliderThumbRenderProps>;
299
+ /**
300
+ * A ref for the HTML input element.
301
+ */
302
+ inputRef?: RefObject<HTMLInputElement | null>;
303
+ }
304
+
305
+ /**
306
+ * A slider thumb represents an individual value that the user can adjust within a slider track.
307
+ */
308
+ export function SliderThumb(props: SliderThumbProps): any {
309
+ const slot = S('SliderThumb');
310
+ // No thumb context upstream — the forwarded ref is read straight off props.
311
+ let ref = (props as any).ref;
312
+ let { inputRef: userInputRef = null } = props;
313
+ let state = useContext(SliderStateContext)!;
314
+ let { ref: trackRef } = useSlottedContext(SliderTrackContext)!;
315
+ let { index = 0 } = props;
316
+ let defaultInputRef = useRef<HTMLInputElement | null>(null, subSlot(slot, 'input'));
317
+ let inputRef = userInputRef || defaultInputRef;
318
+ let [labelRef, label] = useSlot(
319
+ !props['aria-label'] && !props['aria-labelledby'],
320
+ subSlot(slot, 'labelSlot'),
321
+ );
322
+ let { thumbProps, inputProps, labelProps, isDragging, isFocused, isDisabled } = useSliderThumb(
323
+ {
324
+ ...props,
325
+ index,
326
+ trackRef: trackRef as RefObject<HTMLDivElement | null>,
327
+ inputRef,
328
+ label,
329
+ },
330
+ state,
331
+ subSlot(slot, 'thumb'),
332
+ );
333
+
334
+ let { focusProps, isFocusVisible } = useFocusRing(undefined, subSlot(slot, 'focusRing'));
335
+ let { hoverProps, isHovered } = useHover(props, subSlot(slot, 'hover'));
336
+
337
+ let renderProps = useRenderProps(
338
+ {
339
+ ...props,
340
+ defaultClassName: 'react-aria-SliderThumb',
341
+ values: {
342
+ state,
343
+ isHovered,
344
+ isDragging,
345
+ isFocused,
346
+ isFocusVisible,
347
+ isDisabled,
348
+ },
349
+ },
350
+ subSlot(slot, 'render'),
351
+ );
352
+
353
+ let DOMProps = filterDOMProps(props, { global: true });
354
+ delete DOMProps.id;
355
+
356
+ return createElement(dom.div, {
357
+ ...mergeProps(DOMProps, thumbProps, hoverProps),
358
+ ...renderProps,
359
+ ref,
360
+ style: { ...thumbProps.style, ...renderProps.style },
361
+ 'data-hovered': isHovered || undefined,
362
+ 'data-dragging': isDragging || undefined,
363
+ 'data-focused': isFocused || undefined,
364
+ 'data-focus-visible': isFocusVisible || undefined,
365
+ 'data-disabled': isDisabled || undefined,
366
+ // octane adaptation: keys keep the two-item child array (hidden input +
367
+ // provider-wrapped children) reconciling stably (upstream renders JSX siblings).
368
+ children: [
369
+ createElement(VisuallyHidden, {
370
+ key: 'input',
371
+ children: createElement('input', {
372
+ ref: inputRef,
373
+ ...mergeProps(inputProps, focusProps),
374
+ }),
375
+ }),
376
+ createElement(Provider, {
377
+ key: 'children',
378
+ values: [[LabelContext, { ...labelProps, ref: labelRef }]] as any,
379
+ children: renderProps.children,
380
+ }),
381
+ ],
382
+ });
383
+ }
384
+
385
+ export interface SliderFillRenderProps extends SliderRenderProps {
386
+ /**
387
+ * Whether the slider fill is currently hovered with a mouse.
388
+ *
389
+ * @selector [data-hovered]
390
+ */
391
+ isHovered: boolean;
392
+ }
393
+
394
+ export interface SliderFillProps
395
+ extends HoverEvents, RenderProps<SliderFillRenderProps>, GlobalDOMAttributes {
396
+ /**
397
+ * The offset from which to start the fill.
398
+ *
399
+ * @default 0
400
+ */
401
+ offset?: number;
402
+ /**
403
+ * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the
404
+ * element. A function may be provided to compute the class based on component state.
405
+ *
406
+ * @default 'react-aria-SliderFill'
407
+ */
408
+ className?: ClassNameOrFunction<SliderFillRenderProps>;
409
+ }
410
+
411
+ /**
412
+ * Displays the selected range.
413
+ */
414
+ export function SliderFill(props: SliderFillProps): any {
415
+ const slot = S('SliderFill');
416
+ let ref: any;
417
+ [props, ref] = useContextProps(props, props.ref, SliderFillContext, subSlot(slot, 'ctx'));
418
+ let state = useContext(SliderStateContext)!;
419
+ let { onHoverStart, onHoverEnd, onHoverChange, ...otherProps } = props;
420
+ let { hoverProps, isHovered } = useHover(
421
+ { onHoverStart, onHoverEnd, onHoverChange },
422
+ subSlot(slot, 'hover'),
423
+ );
424
+
425
+ let offset =
426
+ props.offset != null
427
+ ? clamp(props.offset, state.getThumbMinValue(0), state.getThumbMaxValue(0))
428
+ : state.getThumbMinValue(0);
429
+ let start =
430
+ state.values.length > 1 ? state.getThumbPercent(0) * 100 : state.getValuePercent(offset) * 100;
431
+ let end = state.values.length > 0 ? state.getThumbPercent(state.values.length - 1) * 100 : 0;
432
+ let startPercent = Math.min(start, end);
433
+ let endPercent = Math.max(start, end);
434
+ let sizePercent = Math.max(0, endPercent - startPercent);
435
+
436
+ let renderProps = useRenderProps(
437
+ {
438
+ ...props,
439
+ defaultClassName: 'react-aria-SliderFill',
440
+ defaultStyle:
441
+ state.orientation === 'vertical'
442
+ ? {
443
+ position: 'absolute',
444
+ bottom: `${startPercent}%`,
445
+ height: `${sizePercent}%`,
446
+ width: '100%',
447
+ }
448
+ : {
449
+ position: 'absolute',
450
+ insetInlineStart: `${startPercent}%`,
451
+ width: `${sizePercent}%`,
452
+ height: '100%',
453
+ },
454
+ values: {
455
+ orientation: state.orientation,
456
+ isDisabled: state.isDisabled,
457
+ isHovered,
458
+ state,
459
+ },
460
+ },
461
+ subSlot(slot, 'render'),
462
+ );
463
+
464
+ return createElement(dom.div, {
465
+ ...mergeProps(otherProps, hoverProps),
466
+ ...renderProps,
467
+ ref,
468
+ 'data-hovered': isHovered || undefined,
469
+ 'data-orientation': state.orientation || undefined,
470
+ 'data-disabled': state.isDisabled || undefined,
471
+ });
472
+ }