foldkit 0.33.6 → 0.34.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 (79) hide show
  1. package/README.md +19 -19
  2. package/dist/devtools/overlay.d.ts.map +1 -1
  3. package/dist/devtools/overlay.js +76 -33
  4. package/dist/html/index.d.ts +431 -5
  5. package/dist/html/index.d.ts.map +1 -1
  6. package/dist/html/index.js +1 -0
  7. package/dist/html/public.d.ts +1 -2
  8. package/dist/html/public.d.ts.map +1 -1
  9. package/dist/html/public.js +1 -2
  10. package/dist/task/dom.d.ts +6 -6
  11. package/dist/task/dom.js +6 -6
  12. package/dist/task/inert.d.ts +2 -2
  13. package/dist/task/inert.js +2 -2
  14. package/dist/task/scrollLock.d.ts +2 -2
  15. package/dist/task/scrollLock.js +2 -2
  16. package/dist/ui/checkbox/index.d.ts +5 -9
  17. package/dist/ui/checkbox/index.d.ts.map +1 -1
  18. package/dist/ui/checkbox/index.js +7 -10
  19. package/dist/ui/checkbox/public.d.ts +1 -1
  20. package/dist/ui/checkbox/public.d.ts.map +1 -1
  21. package/dist/ui/combobox/multi.d.ts +31 -10
  22. package/dist/ui/combobox/multi.d.ts.map +1 -1
  23. package/dist/ui/combobox/multi.js +1 -1
  24. package/dist/ui/combobox/public.d.ts +1 -1
  25. package/dist/ui/combobox/public.d.ts.map +1 -1
  26. package/dist/ui/combobox/shared.d.ts +53 -14
  27. package/dist/ui/combobox/shared.d.ts.map +1 -1
  28. package/dist/ui/combobox/shared.js +72 -28
  29. package/dist/ui/combobox/single.d.ts +31 -10
  30. package/dist/ui/combobox/single.d.ts.map +1 -1
  31. package/dist/ui/combobox/single.js +1 -1
  32. package/dist/ui/dialog/index.d.ts +14 -8
  33. package/dist/ui/dialog/index.d.ts.map +1 -1
  34. package/dist/ui/dialog/index.js +21 -12
  35. package/dist/ui/dialog/public.d.ts +1 -1
  36. package/dist/ui/dialog/public.d.ts.map +1 -1
  37. package/dist/ui/dialog/public.js +1 -1
  38. package/dist/ui/disclosure/index.d.ts +11 -8
  39. package/dist/ui/disclosure/index.d.ts.map +1 -1
  40. package/dist/ui/disclosure/index.js +20 -18
  41. package/dist/ui/disclosure/public.d.ts +1 -1
  42. package/dist/ui/disclosure/public.d.ts.map +1 -1
  43. package/dist/ui/listbox/multi.d.ts +34 -9
  44. package/dist/ui/listbox/multi.d.ts.map +1 -1
  45. package/dist/ui/listbox/multi.js +1 -1
  46. package/dist/ui/listbox/public.d.ts +1 -1
  47. package/dist/ui/listbox/public.d.ts.map +1 -1
  48. package/dist/ui/listbox/shared.d.ts +57 -13
  49. package/dist/ui/listbox/shared.d.ts.map +1 -1
  50. package/dist/ui/listbox/shared.js +77 -27
  51. package/dist/ui/listbox/single.d.ts +34 -9
  52. package/dist/ui/listbox/single.d.ts.map +1 -1
  53. package/dist/ui/listbox/single.js +1 -1
  54. package/dist/ui/menu/index.d.ts +39 -11
  55. package/dist/ui/menu/index.d.ts.map +1 -1
  56. package/dist/ui/menu/index.js +81 -32
  57. package/dist/ui/menu/public.d.ts +1 -1
  58. package/dist/ui/menu/public.d.ts.map +1 -1
  59. package/dist/ui/popover/index.d.ts +28 -12
  60. package/dist/ui/popover/index.d.ts.map +1 -1
  61. package/dist/ui/popover/index.js +50 -24
  62. package/dist/ui/popover/public.d.ts +1 -1
  63. package/dist/ui/popover/public.d.ts.map +1 -1
  64. package/dist/ui/radioGroup/index.d.ts +8 -7
  65. package/dist/ui/radioGroup/index.d.ts.map +1 -1
  66. package/dist/ui/radioGroup/index.js +12 -9
  67. package/dist/ui/radioGroup/public.d.ts +1 -1
  68. package/dist/ui/radioGroup/public.d.ts.map +1 -1
  69. package/dist/ui/switch/index.d.ts +5 -9
  70. package/dist/ui/switch/index.d.ts.map +1 -1
  71. package/dist/ui/switch/index.js +7 -10
  72. package/dist/ui/switch/public.d.ts +1 -1
  73. package/dist/ui/switch/public.d.ts.map +1 -1
  74. package/dist/ui/tabs/index.d.ts +9 -7
  75. package/dist/ui/tabs/index.d.ts.map +1 -1
  76. package/dist/ui/tabs/index.js +27 -17
  77. package/dist/ui/tabs/public.d.ts +1 -1
  78. package/dist/ui/tabs/public.d.ts.map +1 -1
  79. package/package.json +3 -3
@@ -74,8 +74,20 @@ export const MovedPointerOverItem = m('MovedPointerOverItem', {
74
74
  export const RequestedItemClick = m('RequestedItemClick', {
75
75
  index: S.Number,
76
76
  });
77
- /** Placeholder message used when no action is needed. */
78
- export const NoOp = m('NoOp');
77
+ /** Sent when the scroll lock command completes. */
78
+ export const CompletedScrollLock = m('CompletedScrollLock');
79
+ /** Sent when the scroll unlock command completes. */
80
+ export const CompletedScrollUnlock = m('CompletedScrollUnlock');
81
+ /** Sent when the inert-others command completes. */
82
+ export const CompletedInertSetup = m('CompletedInertSetup');
83
+ /** Sent when the restore-inert command completes. */
84
+ export const CompletedInertTeardown = m('CompletedInertTeardown');
85
+ /** Sent when the focus-input command completes. */
86
+ export const CompletedInputFocus = m('CompletedInputFocus');
87
+ /** Sent when the scroll-into-view command completes after keyboard activation. */
88
+ export const CompletedScrollIntoView = m('CompletedScrollIntoView');
89
+ /** Sent when the programmatic item click command completes. */
90
+ export const CompletedItemClick = m('CompletedItemClick');
79
91
  /** Sent internally when a double-rAF completes, advancing the transition to its animating phase. */
80
92
  export const AdvancedTransitionFrame = m('AdvancedTransitionFrame');
81
93
  /** Sent internally when all CSS transitions on the items container have completed. */
@@ -89,7 +101,7 @@ export const UpdatedInputValue = m('UpdatedInputValue', {
89
101
  /** Sent when the optional toggle button is clicked. */
90
102
  export const PressedToggleButton = m('PressedToggleButton');
91
103
  /** Union of all messages the combobox component can produce. */
92
- export const Message = S.Union(Opened, Closed, ClosedByTab, ActivatedItem, DeactivatedItem, SelectedItem, MovedPointerOverItem, RequestedItemClick, NoOp, AdvancedTransitionFrame, EndedTransition, DetectedInputMovement, UpdatedInputValue, PressedToggleButton);
104
+ export const Message = S.Union(Opened, Closed, ClosedByTab, ActivatedItem, DeactivatedItem, SelectedItem, MovedPointerOverItem, RequestedItemClick, CompletedScrollLock, CompletedScrollUnlock, CompletedInertSetup, CompletedInertTeardown, CompletedInputFocus, CompletedScrollIntoView, CompletedItemClick, AdvancedTransitionFrame, EndedTransition, DetectedInputMovement, UpdatedInputValue, PressedToggleButton);
93
105
  // SELECTORS
94
106
  export const inputSelector = (id) => `#${id}-input`;
95
107
  export const inputWrapperSelector = (id) => `#${id}-input-wrapper`;
@@ -111,14 +123,14 @@ export const makeUpdate = (handlers) => {
111
123
  const withUpdateReturn = M.withReturnType();
112
124
  return (model, message) => {
113
125
  const maybeNextFrame = OptionExt.when(model.isAnimated, Task.nextFrame.pipe(Effect.as(AdvancedTransitionFrame())));
114
- const maybeLockScroll = OptionExt.when(model.isModal, Task.lockScroll.pipe(Effect.as(NoOp())));
115
- const maybeUnlockScroll = OptionExt.when(model.isModal, Task.unlockScroll.pipe(Effect.as(NoOp())));
126
+ const maybeLockScroll = OptionExt.when(model.isModal, Task.lockScroll.pipe(Effect.as(CompletedScrollLock())));
127
+ const maybeUnlockScroll = OptionExt.when(model.isModal, Task.unlockScroll.pipe(Effect.as(CompletedScrollUnlock())));
116
128
  const maybeInertOthers = OptionExt.when(model.isModal, Task.inertOthers(model.id, [
117
129
  inputWrapperSelector(model.id),
118
130
  itemsSelector(model.id),
119
- ]).pipe(Effect.as(NoOp())));
120
- const maybeRestoreInert = OptionExt.when(model.isModal, Task.restoreInert(model.id).pipe(Effect.as(NoOp())));
121
- const focusInput = Task.focus(inputSelector(model.id)).pipe(Effect.ignore, Effect.as(NoOp()));
131
+ ]).pipe(Effect.as(CompletedInertSetup())));
132
+ const maybeRestoreInert = OptionExt.when(model.isModal, Task.restoreInert(model.id).pipe(Effect.as(CompletedInertTeardown())));
133
+ const focusInput = Task.focus(inputSelector(model.id)).pipe(Effect.ignore, Effect.as(CompletedInputFocus()));
122
134
  return M.value(message).pipe(withUpdateReturn, M.tagsExhaustive({
123
135
  Opened: ({ maybeActiveItemIndex }) => {
124
136
  const nextModel = constrainedEvo(model, {
@@ -165,7 +177,7 @@ export const makeUpdate = (handlers) => {
165
177
  nextModel,
166
178
  activationTrigger === 'Keyboard'
167
179
  ? [
168
- Task.scrollIntoView(itemSelector(model.id, index)).pipe(Effect.ignore, Effect.as(NoOp())),
180
+ Task.scrollIntoView(itemSelector(model.id, index)).pipe(Effect.ignore, Effect.as(CompletedScrollIntoView())),
169
181
  ]
170
182
  : [],
171
183
  ];
@@ -201,7 +213,7 @@ export const makeUpdate = (handlers) => {
201
213
  RequestedItemClick: ({ index }) => [
202
214
  model,
203
215
  [
204
- Task.clickElement(itemSelector(model.id, index)).pipe(Effect.ignore, Effect.as(NoOp())),
216
+ Task.clickElement(itemSelector(model.id, index)).pipe(Effect.ignore, Effect.as(CompletedItemClick())),
205
217
  ],
206
218
  ],
207
219
  UpdatedInputValue: ({ value }) => {
@@ -282,14 +294,20 @@ export const makeUpdate = (handlers) => {
282
294
  }),
283
295
  [],
284
296
  ]), M.orElse(() => [model, []])),
285
- NoOp: () => [model, []],
297
+ CompletedScrollLock: () => [model, []],
298
+ CompletedScrollUnlock: () => [model, []],
299
+ CompletedInertSetup: () => [model, []],
300
+ CompletedInertTeardown: () => [model, []],
301
+ CompletedInputFocus: () => [model, []],
302
+ CompletedScrollIntoView: () => [model, []],
303
+ CompletedItemClick: () => [model, []],
286
304
  }));
287
305
  };
288
306
  };
289
307
  /** Creates a combobox view function from variant-specific behavior. Shared rendering logic (input, items, transitions, keyboard navigation) is handled internally; only selection display varies by variant. */
290
308
  export const makeView = (behavior) => (config) => {
291
- const { div, input, AriaActiveDescendant, AriaControls, AriaDisabled, AriaExpanded, AriaInvalid, AriaLabelledBy, AriaMultiSelectable, AriaSelected, Attribute, Autocomplete, Class, DataAttribute, Id, Name, OnBlur, OnClick, OnDestroy, OnFocus, OnInput, OnInsert, OnKeyDownPreventDefault, OnPointerLeave, OnPointerMove, Role, Style, Tabindex, Type, Value, keyed, } = html();
292
- const { model: { id, isOpen, immediate, transitionState, maybeActiveItemIndex }, toMessage, items, itemToConfig, itemToValue, itemToDisplayText, isItemDisabled, inputClassName, inputPlaceholder, itemsClassName, itemsScrollClassName, backdropClassName, className, inputWrapperClassName, buttonContent, buttonClassName, formName, isDisabled, isInvalid, openOnFocus, itemGroupKey, groupToHeading, groupClassName, separatorClassName, anchor, } = config;
309
+ const { div, input, AriaActiveDescendant, AriaControls, AriaDisabled, AriaExpanded, AriaInvalid, AriaLabelledBy, AriaMultiSelectable, AriaSelected, Attribute, Autocomplete, Class, DataAttribute, Id, Name, OnBlur, OnClick, OnDestroy, OnFocus, OnInput, OnInsert, OnKeyDownPreventDefault, OnPointerLeave, OnPointerMove, Placeholder, Role, Style, Tabindex, Type, Value, keyed, } = html();
310
+ const { model: { id, isOpen, immediate, transitionState, maybeActiveItemIndex }, toMessage, items, itemToConfig, itemToValue, itemToDisplayText, isItemDisabled, inputClassName, inputAttributes = [], inputPlaceholder, inputWrapperClassName, inputWrapperAttributes = [], itemsClassName, itemsAttributes = [], itemsScrollClassName, itemsScrollAttributes = [], backdropClassName, backdropAttributes = [], className, attributes = [], buttonContent, buttonClassName, buttonAttributes = [], formName, isDisabled, isInvalid, openOnFocus, itemGroupKey, groupToHeading, groupClassName, groupAttributes = [], separatorClassName, separatorAttributes = [], anchor, } = config;
293
311
  const isLeaving = transitionState === 'LeaveStart' || transitionState === 'LeaveAnimating';
294
312
  const isVisible = isOpen || isLeaving;
295
313
  const transitionAttributes = M.value(transitionState).pipe(M.when('EnterStart', () => [
@@ -373,10 +391,9 @@ export const makeView = (behavior) => (config) => {
373
391
  onNone: () => [],
374
392
  onSome: index => [AriaActiveDescendant(itemId(id, index))],
375
393
  });
376
- const inputAttributes = [
394
+ const resolvedInputAttributes = [
377
395
  Id(`${id}-input`),
378
396
  Role('combobox'),
379
- Class(inputClassName),
380
397
  AriaExpanded(isVisible),
381
398
  AriaControls(`${id}-items`),
382
399
  Attribute('aria-autocomplete', 'list'),
@@ -384,7 +401,7 @@ export const makeView = (behavior) => (config) => {
384
401
  Autocomplete('off'),
385
402
  Value(config.model.inputValue),
386
403
  ...maybeActiveDescendant,
387
- ...(inputPlaceholder ? [Attribute('placeholder', inputPlaceholder)] : []),
404
+ ...(inputPlaceholder ? [Placeholder(inputPlaceholder)] : []),
388
405
  ...(isDisabled
389
406
  ? [AriaDisabled(true), DataAttribute('disabled', '')]
390
407
  : [
@@ -410,6 +427,8 @@ export const makeView = (behavior) => (config) => {
410
427
  }),
411
428
  ]
412
429
  : []),
430
+ ...(inputClassName ? [Class(inputClassName)] : []),
431
+ ...inputAttributes,
413
432
  ];
414
433
  const hooks = anchor
415
434
  ? anchorHooks({
@@ -434,9 +453,10 @@ export const makeView = (behavior) => (config) => {
434
453
  ...(behavior.ariaMultiSelectable ? [AriaMultiSelectable(true)] : []),
435
454
  AriaLabelledBy(`${id}-input`),
436
455
  Tabindex(-1),
437
- Class(itemsClassName),
438
456
  ...anchorAttributes,
439
457
  ...transitionAttributes,
458
+ ...(itemsClassName ? [Class(itemsClassName)] : []),
459
+ ...itemsAttributes,
440
460
  ];
441
461
  const comboboxItems = Array.map(items, (item, index) => {
442
462
  const isActiveItem = Option.exists(maybeActiveItemIndex, activeIndex => activeIndex === index);
@@ -452,7 +472,6 @@ export const makeView = (behavior) => (config) => {
452
472
  Id(itemId(id, index)),
453
473
  Role('option'),
454
474
  AriaSelected(isSelectedItem),
455
- Class(itemConfig.className),
456
475
  ...(isActiveItem ? [DataAttribute('active', '')] : []),
457
476
  ...(isSelectedItem ? [DataAttribute('selected', '')] : []),
458
477
  ...(isDisabledItem
@@ -472,6 +491,7 @@ export const makeView = (behavior) => (config) => {
472
491
  OnPointerLeave(pointerType => OptionExt.when(pointerType !== 'touch', toMessage(DeactivatedItem()))),
473
492
  ]
474
493
  : []),
494
+ ...(itemConfig.className ? [Class(itemConfig.className)] : []),
475
495
  ], [itemConfig.content]);
476
496
  });
477
497
  const renderGroupedItems = () => {
@@ -488,7 +508,11 @@ export const makeView = (behavior) => (config) => {
488
508
  const headingElement = Option.match(maybeHeading, {
489
509
  onNone: () => [],
490
510
  onSome: heading => [
491
- keyed('div')(headingId, [Id(headingId), Role('presentation'), Class(heading.className)], [heading.content]),
511
+ keyed('div')(headingId, [
512
+ Id(headingId),
513
+ Role('presentation'),
514
+ ...(heading.className ? [Class(heading.className)] : []),
515
+ ], [heading.content]),
492
516
  ],
493
517
  });
494
518
  const groupContent = [...headingElement, ...segment.items];
@@ -496,37 +520,51 @@ export const makeView = (behavior) => (config) => {
496
520
  Role('group'),
497
521
  ...(Option.isSome(maybeHeading) ? [AriaLabelledBy(headingId)] : []),
498
522
  ...(groupClassName ? [Class(groupClassName)] : []),
523
+ ...groupAttributes,
499
524
  ], groupContent);
500
- const separator = segmentIndex > 0 && separatorClassName
525
+ const separator = segmentIndex > 0 &&
526
+ (separatorClassName ||
527
+ Array.isNonEmptyReadonlyArray(separatorAttributes))
501
528
  ? [
502
- keyed('div')(`${id}-separator-${segmentIndex}`, [Role('separator'), Class(separatorClassName)], []),
529
+ keyed('div')(`${id}-separator-${segmentIndex}`, [
530
+ Role('separator'),
531
+ ...(separatorClassName ? [Class(separatorClassName)] : []),
532
+ ...separatorAttributes,
533
+ ], []),
503
534
  ]
504
535
  : [];
505
536
  return [...separator, groupElement];
506
537
  });
507
538
  };
508
539
  const backdrop = keyed('div')(`${id}-backdrop`, [
509
- Class(backdropClassName),
510
540
  ...(isLeaving ? [] : [OnClick(toMessage(Closed()))]),
541
+ ...(backdropClassName ? [Class(backdropClassName)] : []),
542
+ ...backdropAttributes,
511
543
  ], []);
512
544
  const renderedItems = renderGroupedItems();
513
- const scrollableItems = itemsScrollClassName
514
- ? [div([Class(itemsScrollClassName)], renderedItems)]
545
+ const scrollableItems = itemsScrollClassName ||
546
+ Array.isNonEmptyReadonlyArray(itemsScrollAttributes)
547
+ ? [
548
+ div([
549
+ ...(itemsScrollClassName ? [Class(itemsScrollClassName)] : []),
550
+ ...itemsScrollAttributes,
551
+ ], renderedItems),
552
+ ]
515
553
  : renderedItems;
516
554
  const visibleContent = [
517
555
  backdrop,
518
556
  keyed('div')(`${id}-items-container`, itemsContainerAttributes, scrollableItems),
519
557
  ];
520
- const inputWrapperAttributes = [
558
+ const resolvedInputWrapperAttributes = [
521
559
  Id(`${id}-input-wrapper`),
522
560
  ...(inputWrapperClassName ? [Class(inputWrapperClassName)] : []),
561
+ ...inputWrapperAttributes,
523
562
  ];
524
- const toggleButton = buttonContent && buttonClassName
563
+ const toggleButton = buttonContent
525
564
  ? [
526
565
  keyed('button')(`${id}-button`, [
527
566
  Id(`${id}-button`),
528
567
  Type('button'),
529
- Class(buttonClassName),
530
568
  Tabindex(-1),
531
569
  AriaControls(`${id}-items`),
532
570
  AriaExpanded(isVisible),
@@ -535,6 +573,8 @@ export const makeView = (behavior) => (config) => {
535
573
  ? [AriaDisabled(true), DataAttribute('disabled', '')]
536
574
  : [OnClick(toMessage(PressedToggleButton()))]),
537
575
  OnInsert(preventBlurOnPointerDown),
576
+ ...(buttonClassName ? [Class(buttonClassName)] : []),
577
+ ...buttonAttributes,
538
578
  ], [buttonContent]),
539
579
  ]
540
580
  : [];
@@ -550,12 +590,16 @@ export const makeView = (behavior) => (config) => {
550
590
  : [];
551
591
  const wrapperAttributes = [
552
592
  ...(className ? [Class(className)] : []),
593
+ ...attributes,
553
594
  ...(isVisible ? [DataAttribute('open', '')] : []),
554
595
  ...(isDisabled ? [DataAttribute('disabled', '')] : []),
555
596
  ...(isInvalid ? [DataAttribute('invalid', '')] : []),
556
597
  ];
557
598
  return div(wrapperAttributes, [
558
- div(inputWrapperAttributes, [input(inputAttributes), ...toggleButton]),
599
+ div(resolvedInputWrapperAttributes, [
600
+ input(resolvedInputAttributes),
601
+ ...toggleButton,
602
+ ]),
559
603
  ...(isVisible && Array.isNonEmptyReadonlyArray(items)
560
604
  ? visibleContent
561
605
  : []),
@@ -1,5 +1,5 @@
1
1
  import { Option, Schema as S } from 'effect';
2
- import type { Html } from '../../html';
2
+ import { type Html } from '../../html';
3
3
  import { type BaseInitConfig, type BaseViewConfig } from './shared';
4
4
  /** Schema for the single-select combobox component's state, tracking open/closed status, active item, input value, selected item, and display text. */
5
5
  export declare const Model: S.extend<S.Struct<{
@@ -70,8 +70,6 @@ export declare const update: (model: {
70
70
  readonly maybeSelectedItem: Option.Option<string>;
71
71
  readonly maybeSelectedDisplayText: Option.Option<string>;
72
72
  }, readonly import("../../command").Command<{
73
- readonly _tag: "NoOp";
74
- } | {
75
73
  readonly _tag: "Opened";
76
74
  readonly maybeActiveItemIndex: Option.Option<number>;
77
75
  } | {
@@ -100,6 +98,20 @@ export declare const update: (model: {
100
98
  } | {
101
99
  readonly _tag: "RequestedItemClick";
102
100
  readonly index: number;
101
+ } | {
102
+ readonly _tag: "CompletedScrollLock";
103
+ } | {
104
+ readonly _tag: "CompletedScrollUnlock";
105
+ } | {
106
+ readonly _tag: "CompletedInertSetup";
107
+ } | {
108
+ readonly _tag: "CompletedInertTeardown";
109
+ } | {
110
+ readonly _tag: "CompletedInputFocus";
111
+ } | {
112
+ readonly _tag: "CompletedScrollIntoView";
113
+ } | {
114
+ readonly _tag: "CompletedItemClick";
103
115
  } | {
104
116
  readonly _tag: "AdvancedTransitionFrame";
105
117
  } | {
@@ -136,28 +148,35 @@ export declare const view: <Message, Item extends string>(config: Readonly<{
136
148
  readonly maybeSelectedItem: Option.Option<string>;
137
149
  readonly maybeSelectedDisplayText: Option.Option<string>;
138
150
  };
139
- toMessage: (message: import("./shared").Opened | import("./shared").Closed | import("./shared").ClosedByTab | import("./shared").ActivatedItem | import("./shared").DeactivatedItem | import("./shared").SelectedItem | import("./shared").MovedPointerOverItem | import("./shared").RequestedItemClick | import("./shared").UpdatedInputValue | import("./shared").PressedToggleButton | import("./shared").NoOp) => Message;
151
+ toMessage: (message: import("./shared").Opened | import("./shared").Closed | import("./shared").ClosedByTab | import("./shared").ActivatedItem | import("./shared").DeactivatedItem | import("./shared").SelectedItem | import("./shared").MovedPointerOverItem | import("./shared").RequestedItemClick | import("./shared").UpdatedInputValue | import("./shared").PressedToggleButton | import("./shared").CompletedScrollLock | import("./shared").CompletedScrollUnlock | import("./shared").CompletedInertSetup | import("./shared").CompletedInertTeardown | import("./shared").CompletedInputFocus | import("./shared").CompletedScrollIntoView | import("./shared").CompletedItemClick) => Message;
140
152
  items: readonly Item[];
141
153
  itemToConfig: (item: Item, context: Readonly<{
142
154
  isActive: boolean;
143
155
  isDisabled: boolean;
144
156
  isSelected: boolean;
145
157
  }>) => Readonly<{
146
- className: string;
158
+ className?: string;
147
159
  content: Html;
148
160
  }>;
149
161
  itemToValue: (item: Item, index: number) => string;
150
162
  itemToDisplayText: (item: Item, index: number) => string;
151
163
  isItemDisabled?: (item: Item, index: number) => boolean;
152
- inputClassName: string;
164
+ inputClassName?: string;
165
+ inputAttributes?: readonly import("../../html").Attribute<Message>[];
153
166
  inputPlaceholder?: string;
154
- itemsClassName: string;
167
+ inputWrapperClassName?: string;
168
+ inputWrapperAttributes?: readonly import("../../html").Attribute<Message>[];
169
+ itemsClassName?: string;
170
+ itemsAttributes?: readonly import("../../html").Attribute<Message>[];
155
171
  itemsScrollClassName?: string;
156
- backdropClassName: string;
172
+ itemsScrollAttributes?: readonly import("../../html").Attribute<Message>[];
173
+ backdropClassName?: string;
174
+ backdropAttributes?: readonly import("../../html").Attribute<Message>[];
157
175
  className?: string;
158
- inputWrapperClassName?: string;
176
+ attributes?: readonly import("../../html").Attribute<Message>[];
159
177
  buttonContent?: Html;
160
178
  buttonClassName?: string;
179
+ buttonAttributes?: readonly import("../../html").Attribute<Message>[];
161
180
  formName?: string;
162
181
  isDisabled?: boolean;
163
182
  isInvalid?: boolean;
@@ -165,10 +184,12 @@ export declare const view: <Message, Item extends string>(config: Readonly<{
165
184
  itemGroupKey?: (item: Item, index: number) => string;
166
185
  groupToHeading?: (groupKey: string) => Readonly<{
167
186
  content: Html;
168
- className: string;
187
+ className?: string;
169
188
  }> | undefined;
170
189
  groupClassName?: string;
190
+ groupAttributes?: readonly import("../../html").Attribute<Message>[];
171
191
  separatorClassName?: string;
192
+ separatorAttributes?: readonly import("../../html").Attribute<Message>[];
172
193
  anchor?: Readonly<{
173
194
  placement?: import("@floating-ui/dom").Placement;
174
195
  gap?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"single.d.ts","sourceRoot":"","sources":["../../../src/ui/combobox/single.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,IAAI,CAAC,EAAQ,MAAM,QAAQ,CAAA;AAEzD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAGtC,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,cAAc,EAKpB,MAAM,UAAU,CAAA;AAIjB,uJAAuJ;AACvJ,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;GAOjB,CAAA;AAED,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,8RAA8R;AAC9R,MAAM,MAAM,UAAU,GAAG,cAAc,GACrC,QAAQ,CAAC;IACP,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAC,CAAA;AAEJ,4IAA4I;AAC5I,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAMxC,CAAA;AAIF,uIAAuI;AACvI,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqDjB,CAAA;AAIF,wEAAwE;AACxE,MAAM,MAAM,UAAU,CAAC,OAAO,EAAE,IAAI,SAAS,MAAM,IAAI,cAAc,CACnE,OAAO,EACP,IAAI,EACJ,KAAK,CACN,CAAA;AAED,0IAA0I;AAC1I,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAOf,CAAA;AAEF;6EAC6E;AAC7E,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,IAAI,SAAS,MAAM,EAC/C,cAAc,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC,KACnE,CAAC,CACF,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,WAAW,CAAC,KACzD,IAAI,CAgBR,CAAA"}
1
+ {"version":3,"file":"single.d.ts","sourceRoot":"","sources":["../../../src/ui/combobox/single.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,IAAI,CAAC,EAAQ,MAAM,QAAQ,CAAA;AAEzD,OAAO,EAAE,KAAK,IAAI,EAAc,MAAM,YAAY,CAAA;AAElD,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,cAAc,EAKpB,MAAM,UAAU,CAAA;AAIjB,uJAAuJ;AACvJ,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;GAOjB,CAAA;AAED,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,8RAA8R;AAC9R,MAAM,MAAM,UAAU,GAAG,cAAc,GACrC,QAAQ,CAAC;IACP,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAC,CAAA;AAEJ,4IAA4I;AAC5I,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAMxC,CAAA;AAIF,uIAAuI;AACvI,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqDjB,CAAA;AAIF,wEAAwE;AACxE,MAAM,MAAM,UAAU,CAAC,OAAO,EAAE,IAAI,SAAS,MAAM,IAAI,cAAc,CACnE,OAAO,EACP,IAAI,EACJ,KAAK,CACN,CAAA;AAED,0IAA0I;AAC1I,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAOf,CAAA;AAEF;6EAC6E;AAC7E,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,IAAI,SAAS,MAAM,EAC/C,cAAc,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC,KACnE,CAAC,CACF,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,WAAW,CAAC,KACzD,IAAI,CAgBR,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { Array, Option, Schema as S, pipe } from 'effect';
2
- import { createLazy } from '../../html/lazy';
2
+ import { createLazy } from '../../html';
3
3
  import { evo } from '../../struct';
4
4
  import { BaseModel, baseInit, closedBaseModel, makeUpdate, makeView, } from './shared';
5
5
  // MODEL
@@ -1,6 +1,6 @@
1
1
  import { Schema as S } from 'effect';
2
2
  import type { Command } from '../../command';
3
- import type { Html } from '../../html';
3
+ import { type Attribute, type Html } from '../../html';
4
4
  /** Schema for the dialog component's state, tracking its unique ID, open/closed status, animation support, and transition phase. */
5
5
  export declare const Model: S.Struct<{
6
6
  id: typeof S.String;
@@ -13,17 +13,20 @@ export type Model = typeof Model.Type;
13
13
  export declare const Opened: import("../../schema").CallableTaggedStruct<"Opened", {}>;
14
14
  /** Sent when the dialog should close (Escape key, backdrop click, or programmatic). Triggers the closeModal command. */
15
15
  export declare const Closed: import("../../schema").CallableTaggedStruct<"Closed", {}>;
16
- /** Placeholder message used when no action is needed, such as after a showModal or closeModal command completes. */
17
- export declare const NoOp: import("../../schema").CallableTaggedStruct<"NoOp", {}>;
16
+ /** Sent when the show-dialog command completes (scroll lock + showModal). */
17
+ export declare const CompletedDialogShow: import("../../schema").CallableTaggedStruct<"CompletedDialogShow", {}>;
18
+ /** Sent when the close-dialog command completes (closeModal + scroll unlock). */
19
+ export declare const CompletedDialogClose: import("../../schema").CallableTaggedStruct<"CompletedDialogClose", {}>;
18
20
  /** Sent internally when a double-rAF completes, advancing the transition to its animating phase. */
19
21
  export declare const AdvancedTransitionFrame: import("../../schema").CallableTaggedStruct<"AdvancedTransitionFrame", {}>;
20
22
  /** Sent internally when all CSS transitions on the dialog panel have completed. */
21
23
  export declare const EndedTransition: import("../../schema").CallableTaggedStruct<"EndedTransition", {}>;
22
24
  /** Union of all messages the dialog component can produce. */
23
- export declare const Message: S.Union<[import("../../schema").CallableTaggedStruct<"Opened", {}>, import("../../schema").CallableTaggedStruct<"Closed", {}>, import("../../schema").CallableTaggedStruct<"NoOp", {}>, import("../../schema").CallableTaggedStruct<"AdvancedTransitionFrame", {}>, import("../../schema").CallableTaggedStruct<"EndedTransition", {}>]>;
25
+ export declare const Message: S.Union<[import("../../schema").CallableTaggedStruct<"Opened", {}>, import("../../schema").CallableTaggedStruct<"Closed", {}>, import("../../schema").CallableTaggedStruct<"CompletedDialogShow", {}>, import("../../schema").CallableTaggedStruct<"CompletedDialogClose", {}>, import("../../schema").CallableTaggedStruct<"AdvancedTransitionFrame", {}>, import("../../schema").CallableTaggedStruct<"EndedTransition", {}>]>;
24
26
  export type Opened = typeof Opened.Type;
25
27
  export type Closed = typeof Closed.Type;
26
- export type NoOp = typeof NoOp.Type;
28
+ export type CompletedDialogShow = typeof CompletedDialogShow.Type;
29
+ export type CompletedDialogClose = typeof CompletedDialogClose.Type;
27
30
  export type Message = typeof Message.Type;
28
31
  /** Configuration for creating a dialog model with `init`. `isAnimated` enables CSS transition coordination (default `false`). */
29
32
  export type InitConfig = Readonly<{
@@ -43,11 +46,14 @@ export declare const descriptionId: (model: Model) => string;
43
46
  /** Configuration for rendering a dialog with `view`. */
44
47
  export type ViewConfig<Message> = Readonly<{
45
48
  model: Model;
46
- toMessage: (message: Closed | NoOp) => Message;
49
+ toMessage: (message: Closed | CompletedDialogShow | CompletedDialogClose) => Message;
47
50
  panelContent: Html;
48
- panelClassName: string;
49
- backdropClassName: string;
51
+ panelClassName?: string;
52
+ panelAttributes?: ReadonlyArray<Attribute<Message>>;
53
+ backdropClassName?: string;
54
+ backdropAttributes?: ReadonlyArray<Attribute<Message>>;
50
55
  className?: string;
56
+ attributes?: ReadonlyArray<Attribute<Message>>;
51
57
  }>;
52
58
  /** Renders a headless dialog component backed by the native `<dialog>` element with `showModal()`. */
53
59
  export declare const view: <Message>(config: ViewConfig<Message>) => Html;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/dialog/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqC,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEvE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAG5C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAStC,oIAAoI;AACpI,eAAO,MAAM,KAAK;;;;;EAKhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,wEAAwE;AACxE,eAAO,MAAM,MAAM,2DAAc,CAAA;AACjC,wHAAwH;AACxH,eAAO,MAAM,MAAM,2DAAc,CAAA;AACjC,oHAAoH;AACpH,eAAO,MAAM,IAAI,yDAAY,CAAA;AAC7B,oGAAoG;AACpG,eAAO,MAAM,uBAAuB,4EAA+B,CAAA;AACnE,mFAAmF;AACnF,eAAO,MAAM,eAAe,oEAAuB,CAAA;AAEnD,8DAA8D;AAC9D,eAAO,MAAM,OAAO,0UAMnB,CAAA;AAED,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAA;AAEnC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,iIAAiI;AACjI,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAC,CAAA;AAEF,0FAA0F;AAC1F,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAKxC,CAAA;AAOF,KAAK,YAAY,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;AAG5D,0EAA0E;AAC1E,eAAO,MAAM,MAAM,GAAI,OAAO,KAAK,EAAE,SAAS,OAAO,KAAG,YAwGvD,CAAA;AAID,iGAAiG;AACjG,eAAO,MAAM,OAAO,GAAI,OAAO,KAAK,KAAG,MAA6B,CAAA;AAEpE,wGAAwG;AACxG,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,KAAG,MAAmC,CAAA;AAEhF,wDAAwD;AACxD,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAA;IAC9C,YAAY,EAAE,IAAI,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAC,CAAA;AAEF,sGAAsG;AACtG,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,QAAQ,UAAU,CAAC,OAAO,CAAC,KAAG,IAqF3D,CAAA;AAED;6EAC6E;AAC7E,eAAO,MAAM,IAAI,GAAI,OAAO,EAC1B,cAAc,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC,KAC7D,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,KAAK,IAAI,CAgBtE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/dialog/index.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  import { Array, Effect, Match as M, Option, Schema as S } from 'effect';
2
2
  import { OptionExt } from '../../effectExtensions';
3
- import { html } from '../../html';
4
- import { createLazy } from '../../html/lazy';
3
+ import { createLazy, html } from '../../html';
5
4
  import { m } from '../../message';
6
5
  import { evo } from '../../struct';
7
6
  import * as Task from '../../task';
@@ -19,14 +18,16 @@ export const Model = S.Struct({
19
18
  export const Opened = m('Opened');
20
19
  /** Sent when the dialog should close (Escape key, backdrop click, or programmatic). Triggers the closeModal command. */
21
20
  export const Closed = m('Closed');
22
- /** Placeholder message used when no action is needed, such as after a showModal or closeModal command completes. */
23
- export const NoOp = m('NoOp');
21
+ /** Sent when the show-dialog command completes (scroll lock + showModal). */
22
+ export const CompletedDialogShow = m('CompletedDialogShow');
23
+ /** Sent when the close-dialog command completes (closeModal + scroll unlock). */
24
+ export const CompletedDialogClose = m('CompletedDialogClose');
24
25
  /** Sent internally when a double-rAF completes, advancing the transition to its animating phase. */
25
26
  export const AdvancedTransitionFrame = m('AdvancedTransitionFrame');
26
27
  /** Sent internally when all CSS transitions on the dialog panel have completed. */
27
28
  export const EndedTransition = m('EndedTransition');
28
29
  /** Union of all messages the dialog component can produce. */
29
- export const Message = S.Union(Opened, Closed, NoOp, AdvancedTransitionFrame, EndedTransition);
30
+ export const Message = S.Union(Opened, Closed, CompletedDialogShow, CompletedDialogClose, AdvancedTransitionFrame, EndedTransition);
30
31
  /** Creates an initial dialog model from a config. Defaults to closed and non-animated. */
31
32
  export const init = (config) => ({
32
33
  id: config.id,
@@ -43,7 +44,7 @@ export const update = (model, message) => {
43
44
  const maybeNextFrame = OptionExt.when(model.isAnimated, Task.nextFrame.pipe(Effect.as(AdvancedTransitionFrame())));
44
45
  return M.value(message).pipe(withUpdateReturn, M.tagsExhaustive({
45
46
  Opened: () => {
46
- const maybeShow = Option.liftPredicate(Task.lockScroll.pipe(Effect.andThen(() => Task.showModal(dialogSelector(model.id))), Effect.ignore, Effect.as(NoOp())), () => !model.isOpen);
47
+ const maybeShow = Option.liftPredicate(Task.lockScroll.pipe(Effect.andThen(() => Task.showModal(dialogSelector(model.id))), Effect.ignore, Effect.as(CompletedDialogShow())), () => !model.isOpen);
47
48
  return [
48
49
  evo(model, {
49
50
  isOpen: () => true,
@@ -67,7 +68,7 @@ export const update = (model, message) => {
67
68
  Option.toArray(maybeNextFrame),
68
69
  ];
69
70
  }
70
- const maybeClose = Option.liftPredicate(Task.closeModal(dialogSelector(model.id)).pipe(Effect.andThen(() => Task.unlockScroll), Effect.ignore, Effect.as(NoOp())), () => model.isOpen);
71
+ const maybeClose = Option.liftPredicate(Task.closeModal(dialogSelector(model.id)).pipe(Effect.andThen(() => Task.unlockScroll), Effect.ignore, Effect.as(CompletedDialogClose())), () => model.isOpen);
71
72
  return [evo(model, { isOpen: () => false }), Option.toArray(maybeClose)];
72
73
  },
73
74
  AdvancedTransitionFrame: () => M.value(model.transitionState).pipe(withUpdateReturn, M.when('EnterStart', () => [
@@ -87,10 +88,11 @@ export const update = (model, message) => {
87
88
  ]), M.when('LeaveAnimating', () => [
88
89
  evo(model, { transitionState: () => 'Idle' }),
89
90
  [
90
- Task.closeModal(dialogSelector(model.id)).pipe(Effect.andThen(() => Task.unlockScroll), Effect.ignore, Effect.as(NoOp())),
91
+ Task.closeModal(dialogSelector(model.id)).pipe(Effect.andThen(() => Task.unlockScroll), Effect.ignore, Effect.as(CompletedDialogClose())),
91
92
  ],
92
93
  ]), M.orElse(() => [model, []])),
93
- NoOp: () => [model, []],
94
+ CompletedDialogShow: () => [model, []],
95
+ CompletedDialogClose: () => [model, []],
94
96
  }));
95
97
  };
96
98
  // VIEW
@@ -101,7 +103,7 @@ export const descriptionId = (model) => `${model.id}-description`;
101
103
  /** Renders a headless dialog component backed by the native `<dialog>` element with `showModal()`. */
102
104
  export const view = (config) => {
103
105
  const { AriaDescribedBy, AriaLabelledBy, Class, DataAttribute, Id, OnCancel, OnClick, Style, keyed, } = html();
104
- const { model: { id, isOpen, transitionState }, toMessage, panelContent, panelClassName, backdropClassName, className, } = config;
106
+ const { model: { id, isOpen, transitionState }, toMessage, panelContent, panelClassName, panelAttributes = [], backdropClassName, backdropAttributes = [], className, attributes = [], } = config;
105
107
  const isLeaving = transitionState === 'LeaveStart' || transitionState === 'LeaveAnimating';
106
108
  const isVisible = isOpen || isLeaving;
107
109
  const transitionAttributes = M.value(transitionState).pipe(M.when('EnterStart', () => [
@@ -134,13 +136,20 @@ export const view = (config) => {
134
136
  }),
135
137
  ...(isVisible ? [DataAttribute('open', '')] : []),
136
138
  ...(className ? [Class(className)] : []),
139
+ ...attributes,
137
140
  ];
138
141
  const backdrop = keyed('div')(`${id}-backdrop`, [
139
- Class(backdropClassName),
140
142
  ...transitionAttributes,
141
143
  ...(isLeaving ? [] : [OnClick(toMessage(Closed()))]),
144
+ ...(backdropClassName ? [Class(backdropClassName)] : []),
145
+ ...backdropAttributes,
142
146
  ], []);
143
- const panel = keyed('div')(`${id}-panel`, [Id(`${id}-panel`), Class(panelClassName), ...transitionAttributes], [panelContent]);
147
+ const panel = keyed('div')(`${id}-panel`, [
148
+ Id(`${id}-panel`),
149
+ ...transitionAttributes,
150
+ ...(panelClassName ? [Class(panelClassName)] : []),
151
+ ...panelAttributes,
152
+ ], [panelContent]);
144
153
  const content = isVisible ? [backdrop, panel] : [];
145
154
  return keyed('dialog')(id, dialogAttributes, content);
146
155
  };
@@ -1,3 +1,3 @@
1
- export { init, update, view, lazy, titleId, descriptionId, Model, Message, Opened, Closed, NoOp, AdvancedTransitionFrame, EndedTransition, } from './index';
1
+ export { init, update, view, lazy, titleId, descriptionId, Model, Message, Opened, Closed, CompletedDialogShow, CompletedDialogClose, AdvancedTransitionFrame, EndedTransition, } from './index';
2
2
  export type { InitConfig, ViewConfig } from './index';
3
3
  //# sourceMappingURL=public.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/dialog/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,aAAa,EACb,KAAK,EACL,OAAO,EACP,MAAM,EACN,MAAM,EACN,IAAI,EACJ,uBAAuB,EACvB,eAAe,GAChB,MAAM,SAAS,CAAA;AAEhB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/dialog/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,aAAa,EACb,KAAK,EACL,OAAO,EACP,MAAM,EACN,MAAM,EACN,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,eAAe,GAChB,MAAM,SAAS,CAAA;AAEhB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA"}
@@ -1 +1 @@
1
- export { init, update, view, lazy, titleId, descriptionId, Model, Message, Opened, Closed, NoOp, AdvancedTransitionFrame, EndedTransition, } from './index';
1
+ export { init, update, view, lazy, titleId, descriptionId, Model, Message, Opened, Closed, CompletedDialogShow, CompletedDialogClose, AdvancedTransitionFrame, EndedTransition, } from './index';
@@ -1,6 +1,6 @@
1
1
  import { Schema as S } from 'effect';
2
2
  import type { Command } from '../../command';
3
- import type { Html, TagName } from '../../html';
3
+ import { type Attribute, type Html, type TagName } from '../../html';
4
4
  /** Schema for the disclosure component's state, tracking its unique ID and open/closed status. */
5
5
  export declare const Model: S.Struct<{
6
6
  id: typeof S.String;
@@ -11,13 +11,13 @@ export type Model = typeof Model.Type;
11
11
  export declare const Toggled: import("../../schema").CallableTaggedStruct<"Toggled", {}>;
12
12
  /** Sent to explicitly close the disclosure, regardless of its current state. */
13
13
  export declare const Closed: import("../../schema").CallableTaggedStruct<"Closed", {}>;
14
- /** Placeholder message used when no action is needed, such as after a focus command completes. */
15
- export declare const NoOp: import("../../schema").CallableTaggedStruct<"NoOp", {}>;
14
+ /** Sent when the focus-button command completes after closing. */
15
+ export declare const CompletedButtonFocus: import("../../schema").CallableTaggedStruct<"CompletedButtonFocus", {}>;
16
16
  /** Union of all messages the disclosure component can produce. */
17
- export declare const Message: S.Union<[import("../../schema").CallableTaggedStruct<"Toggled", {}>, import("../../schema").CallableTaggedStruct<"Closed", {}>, import("../../schema").CallableTaggedStruct<"NoOp", {}>]>;
17
+ export declare const Message: S.Union<[import("../../schema").CallableTaggedStruct<"Toggled", {}>, import("../../schema").CallableTaggedStruct<"Closed", {}>, import("../../schema").CallableTaggedStruct<"CompletedButtonFocus", {}>]>;
18
18
  export type Toggled = typeof Toggled.Type;
19
19
  export type Closed = typeof Closed.Type;
20
- export type NoOp = typeof NoOp.Type;
20
+ export type CompletedButtonFocus = typeof CompletedButtonFocus.Type;
21
21
  export type Message = typeof Message.Type;
22
22
  /** Configuration for creating a disclosure model with `init`. */
23
23
  export type InitConfig = Readonly<{
@@ -31,16 +31,19 @@ export declare const update: (model: Model, message: Message) => [Model, Readonl
31
31
  /** Configuration for rendering a disclosure with `view`. */
32
32
  export type ViewConfig<Message> = Readonly<{
33
33
  model: Model;
34
- toMessage: (message: Toggled | Closed | NoOp) => Message;
35
- buttonClassName: string;
34
+ toMessage: (message: Toggled | Closed | CompletedButtonFocus) => Message;
35
+ buttonClassName?: string;
36
+ buttonAttributes?: ReadonlyArray<Attribute<Message>>;
36
37
  buttonContent: Html;
37
- panelClassName: string;
38
+ panelClassName?: string;
39
+ panelAttributes?: ReadonlyArray<Attribute<Message>>;
38
40
  panelContent: Html;
39
41
  isDisabled?: boolean;
40
42
  persistPanel?: boolean;
41
43
  buttonElement?: TagName;
42
44
  panelElement?: TagName;
43
45
  className?: string;
46
+ attributes?: ReadonlyArray<Attribute<Message>>;
44
47
  }>;
45
48
  /** Renders a headless disclosure component with accessible ARIA attributes and keyboard support. */
46
49
  export declare const view: <Message>(config: ViewConfig<Message>) => Html;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/disclosure/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAE5C,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAQ/C,kGAAkG;AAClG,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,iFAAiF;AACjF,eAAO,MAAM,OAAO,4DAAe,CAAA;AACnC,gFAAgF;AAChF,eAAO,MAAM,MAAM,2DAAc,CAAA;AACjC,kGAAkG;AAClG,eAAO,MAAM,IAAI,yDAAY,CAAA;AAE7B,kEAAkE;AAClE,eAAO,MAAM,OAAO,2LAAiC,CAAA;AAErD,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AACzC,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAA;AAEnC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,iEAAiE;AACjE,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAC,CAAA;AAEF,6EAA6E;AAC7E,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAGxC,CAAA;AAUF,8EAA8E;AAC9E,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CA+BvC,CAAA;AAIH,4DAA4D;AAC5D,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,KAAK,OAAO,CAAA;IACxD,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,IAAI,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;IACtB,YAAY,EAAE,IAAI,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAC,CAAA;AAEF,oGAAoG;AACpG,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,QAAQ,UAAU,CAAC,OAAO,CAAC,KAAG,IAwF3D,CAAA;AAED;6EAC6E;AAC7E,eAAO,MAAM,IAAI,GAAI,OAAO,EAC1B,cAAc,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC,KAC7D,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,KAAK,IAAI,CAgBtE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/disclosure/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EACL,KAAK,SAAS,EACd,KAAK,IAAI,EACT,KAAK,OAAO,EAGb,MAAM,YAAY,CAAA;AAOnB,kGAAkG;AAClG,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,iFAAiF;AACjF,eAAO,MAAM,OAAO,4DAAe,CAAA;AACnC,gFAAgF;AAChF,eAAO,MAAM,MAAM,2DAAc,CAAA;AACjC,kEAAkE;AAClE,eAAO,MAAM,oBAAoB,yEAA4B,CAAA;AAE7D,kEAAkE;AAClE,eAAO,MAAM,OAAO,2MAAiD,CAAA;AAErE,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AACzC,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,oBAAoB,GAAG,OAAO,oBAAoB,CAAC,IAAI,CAAA;AAEnE,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,iEAAiE;AACjE,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAC,CAAA;AAEF,6EAA6E;AAC7E,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAGxC,CAAA;AAUF,8EAA8E;AAC9E,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CA+BvC,CAAA;AAIH,4DAA4D;AAC5D,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,oBAAoB,KAAK,OAAO,CAAA;IACxE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,gBAAgB,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;IACpD,aAAa,EAAE,IAAI,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,eAAe,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;IACnD,YAAY,EAAE,IAAI,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;CAC/C,CAAC,CAAA;AAEF,oGAAoG;AACpG,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,QAAQ,UAAU,CAAC,OAAO,CAAC,KAAG,IAgG3D,CAAA;AAED;6EAC6E;AAC7E,eAAO,MAAM,IAAI,GAAI,OAAO,EAC1B,cAAc,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC,KAC7D,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,KAAK,IAAI,CAgBtE,CAAA"}