foldkit 0.26.0 → 0.28.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/dist/route/parser.d.ts +11 -14
  2. package/dist/route/parser.d.ts.map +1 -1
  3. package/dist/route/parser.js +44 -48
  4. package/dist/ui/combobox/multi.d.ts +178 -0
  5. package/dist/ui/combobox/multi.d.ts.map +1 -0
  6. package/dist/ui/combobox/multi.js +53 -0
  7. package/dist/ui/combobox/multiPublic.d.ts +3 -0
  8. package/dist/ui/combobox/multiPublic.d.ts.map +1 -0
  9. package/dist/ui/combobox/multiPublic.js +1 -0
  10. package/dist/ui/combobox/public.d.ts +8 -0
  11. package/dist/ui/combobox/public.d.ts.map +1 -0
  12. package/dist/ui/combobox/public.js +4 -0
  13. package/dist/ui/combobox/shared.d.ts +236 -0
  14. package/dist/ui/combobox/shared.d.ts.map +1 -0
  15. package/dist/ui/combobox/shared.js +560 -0
  16. package/dist/ui/combobox/single.d.ts +183 -0
  17. package/dist/ui/combobox/single.d.ts.map +1 -0
  18. package/dist/ui/combobox/single.js +73 -0
  19. package/dist/ui/dialog/index.d.ts +3 -0
  20. package/dist/ui/dialog/index.d.ts.map +1 -1
  21. package/dist/ui/dialog/index.js +11 -0
  22. package/dist/ui/dialog/public.d.ts +1 -1
  23. package/dist/ui/dialog/public.d.ts.map +1 -1
  24. package/dist/ui/dialog/public.js +1 -1
  25. package/dist/ui/disclosure/index.d.ts +3 -0
  26. package/dist/ui/disclosure/index.d.ts.map +1 -1
  27. package/dist/ui/disclosure/index.js +11 -0
  28. package/dist/ui/disclosure/public.d.ts +1 -1
  29. package/dist/ui/disclosure/public.d.ts.map +1 -1
  30. package/dist/ui/disclosure/public.js +1 -1
  31. package/dist/ui/index.d.ts +2 -0
  32. package/dist/ui/index.d.ts.map +1 -1
  33. package/dist/ui/index.js +2 -0
  34. package/dist/ui/listbox/multi.d.ts +26 -21
  35. package/dist/ui/listbox/multi.d.ts.map +1 -1
  36. package/dist/ui/listbox/multi.js +11 -0
  37. package/dist/ui/listbox/multiPublic.d.ts +1 -1
  38. package/dist/ui/listbox/multiPublic.d.ts.map +1 -1
  39. package/dist/ui/listbox/multiPublic.js +1 -1
  40. package/dist/ui/listbox/public.d.ts +1 -1
  41. package/dist/ui/listbox/public.d.ts.map +1 -1
  42. package/dist/ui/listbox/public.js +1 -1
  43. package/dist/ui/listbox/shared.d.ts +9 -8
  44. package/dist/ui/listbox/shared.d.ts.map +1 -1
  45. package/dist/ui/listbox/shared.js +10 -3
  46. package/dist/ui/listbox/single.d.ts +26 -21
  47. package/dist/ui/listbox/single.d.ts.map +1 -1
  48. package/dist/ui/listbox/single.js +11 -0
  49. package/dist/ui/menu/index.d.ts +4 -0
  50. package/dist/ui/menu/index.d.ts.map +1 -1
  51. package/dist/ui/menu/index.js +21 -3
  52. package/dist/ui/menu/public.d.ts +1 -1
  53. package/dist/ui/menu/public.d.ts.map +1 -1
  54. package/dist/ui/menu/public.js +1 -1
  55. package/dist/ui/popover/index.d.ts +3 -0
  56. package/dist/ui/popover/index.d.ts.map +1 -1
  57. package/dist/ui/popover/index.js +11 -0
  58. package/dist/ui/popover/public.d.ts +1 -1
  59. package/dist/ui/popover/public.d.ts.map +1 -1
  60. package/dist/ui/popover/public.js +1 -1
  61. package/dist/ui/radioGroup/index.d.ts +72 -0
  62. package/dist/ui/radioGroup/index.d.ts.map +1 -0
  63. package/dist/ui/radioGroup/index.js +147 -0
  64. package/dist/ui/radioGroup/public.d.ts +3 -0
  65. package/dist/ui/radioGroup/public.d.ts.map +1 -0
  66. package/dist/ui/radioGroup/public.js +1 -0
  67. package/dist/ui/switch/index.d.ts +3 -0
  68. package/dist/ui/switch/index.d.ts.map +1 -1
  69. package/dist/ui/switch/index.js +11 -0
  70. package/dist/ui/switch/public.d.ts +1 -1
  71. package/dist/ui/switch/public.d.ts.map +1 -1
  72. package/dist/ui/switch/public.js +1 -1
  73. package/dist/ui/tabs/index.d.ts +3 -0
  74. package/dist/ui/tabs/index.d.ts.map +1 -1
  75. package/dist/ui/tabs/index.js +11 -0
  76. package/dist/ui/tabs/public.d.ts +1 -1
  77. package/dist/ui/tabs/public.d.ts.map +1 -1
  78. package/dist/ui/tabs/public.js +1 -1
  79. package/package.json +10 -2
@@ -0,0 +1,147 @@
1
+ import { Array, Effect, Match as M, Option, Predicate, Schema as S, String, pipe, } from 'effect';
2
+ import { html } from '../../html';
3
+ import { createLazy } from '../../html/lazy';
4
+ import { m } from '../../message';
5
+ import { evo } from '../../struct';
6
+ import * as Task from '../../task';
7
+ import { keyToIndex } from '../keyboard';
8
+ // MODEL
9
+ /** Controls the radio group layout direction and which arrow keys navigate between options. */
10
+ export const Orientation = S.Literal('Horizontal', 'Vertical');
11
+ /** Schema for the radio group component's state, tracking the selected value and orientation. */
12
+ export const Model = S.Struct({
13
+ id: S.String,
14
+ selectedValue: S.OptionFromSelf(S.String),
15
+ orientation: Orientation,
16
+ });
17
+ // MESSAGE
18
+ /** Sent when a radio option is selected via click or keyboard navigation. */
19
+ export const SelectedOption = m('SelectedOption', {
20
+ value: S.String,
21
+ index: S.Number,
22
+ });
23
+ /** Placeholder message used when no action is needed. */
24
+ export const NoOp = m('NoOp');
25
+ /** Union of all messages the radio group component can produce. */
26
+ export const Message = S.Union(SelectedOption, NoOp);
27
+ /** Creates an initial radio group model from a config. Defaults to no selection and vertical orientation. */
28
+ export const init = (config) => ({
29
+ id: config.id,
30
+ selectedValue: Option.fromNullable(config.selectedValue),
31
+ orientation: config.orientation ?? 'Vertical',
32
+ });
33
+ // UPDATE
34
+ const optionId = (id, index) => `${id}-option-${index}`;
35
+ /** Processes a radio group message and returns the next model and commands. */
36
+ export const update = (model, message) => M.value(message).pipe(M.withReturnType(), M.tagsExhaustive({
37
+ SelectedOption: ({ value, index }) => {
38
+ const selector = `#${optionId(model.id, index)}`;
39
+ return [
40
+ evo(model, { selectedValue: () => Option.some(value) }),
41
+ [Task.focus(selector).pipe(Effect.ignore, Effect.as(NoOp()))],
42
+ ];
43
+ },
44
+ NoOp: () => [model, []],
45
+ }));
46
+ const labelId = (id, index) => `${id}-option-${index}-label`;
47
+ const descriptionId = (id, index) => `${id}-option-${index}-description`;
48
+ /** Renders an accessible radio group by building ARIA attribute groups and delegating layout to the consumer's `optionToConfig` callback. */
49
+ export const view = (config) => {
50
+ const { div, input, AriaChecked, AriaDescribedBy, AriaDisabled, AriaLabelledBy, AriaOrientation, Class, DataAttribute, Id, Name, OnClick, OnKeyDownPreventDefault, Role, Tabindex, Type, Value, } = html();
51
+ const { model, model: { id, selectedValue }, toMessage, options, optionToConfig, isOptionDisabled: isOptionDisabledFn, orientation = model.orientation, className, name, isDisabled: isGroupDisabled = false, } = config;
52
+ const isDisabled = (index) => {
53
+ if (isGroupDisabled) {
54
+ return true;
55
+ }
56
+ if (!isOptionDisabledFn) {
57
+ return false;
58
+ }
59
+ return pipe(options, Array.get(index), Option.exists(option => isOptionDisabledFn(option, index)));
60
+ };
61
+ const selectedIndex = Option.flatMap(selectedValue, value => Array.findFirstIndex(options, option => optionToConfig(option, {
62
+ isSelected: false,
63
+ isActive: false,
64
+ isDisabled: false,
65
+ }).value === value));
66
+ const focusedIndex = pipe(selectedIndex, Option.getOrElse(() => pipe(options.length, Array.makeBy(index => index), Array.findFirst(Predicate.not(isDisabled)), Option.getOrElse(() => 0))));
67
+ const { nextKey, previousKey } = M.value(orientation).pipe(M.when('Horizontal', () => ({
68
+ nextKey: 'ArrowRight',
69
+ previousKey: 'ArrowLeft',
70
+ })), M.when('Vertical', () => ({
71
+ nextKey: 'ArrowDown',
72
+ previousKey: 'ArrowUp',
73
+ })), M.exhaustive);
74
+ const optionValues = Array.map(options, (option, index) => optionToConfig(option, {
75
+ isSelected: Option.exists(selectedIndex, selectedIdx => selectedIdx === index),
76
+ isActive: index === focusedIndex,
77
+ isDisabled: isDisabled(index),
78
+ }).value);
79
+ const resolveKeyIndex = keyToIndex(nextKey, previousKey, options.length, focusedIndex, isDisabled);
80
+ const handleKeyDown = (currentIndex) => (key) => M.value(key).pipe(M.whenOr(nextKey, previousKey, 'Home', 'End', 'PageUp', 'PageDown', () => {
81
+ const nextIndex = resolveKeyIndex(key);
82
+ return pipe(optionValues, Array.get(nextIndex), Option.map(value => toMessage(SelectedOption({ value, index: nextIndex }))));
83
+ }), M.when(' ', () => pipe(optionValues, Array.get(currentIndex), Option.map(value => toMessage(SelectedOption({ value, index: currentIndex }))))), M.orElse(() => Option.none()));
84
+ const renderedOptions = Array.map(options, (option, index) => {
85
+ const isSelected = Option.exists(selectedIndex, selectedIdx => selectedIdx === index);
86
+ const isFocusable = index === focusedIndex;
87
+ const isOptionDisabled = isDisabled(index);
88
+ const optionConfig = optionToConfig(option, {
89
+ isSelected,
90
+ isActive: isFocusable,
91
+ isDisabled: isOptionDisabled,
92
+ });
93
+ const checkedAttributes = isSelected ? [DataAttribute('checked', '')] : [];
94
+ const activeAttributes = isFocusable ? [DataAttribute('active', '')] : [];
95
+ const disabledAttributes = isOptionDisabled
96
+ ? [AriaDisabled(true), DataAttribute('disabled', '')]
97
+ : [];
98
+ const optionAttributes = [
99
+ Id(optionId(id, index)),
100
+ Role('radio'),
101
+ AriaChecked(isSelected),
102
+ AriaLabelledBy(labelId(id, index)),
103
+ AriaDescribedBy(descriptionId(id, index)),
104
+ Tabindex(isFocusable ? 0 : -1),
105
+ ...checkedAttributes,
106
+ ...activeAttributes,
107
+ ...disabledAttributes,
108
+ ...(isOptionDisabled
109
+ ? []
110
+ : [
111
+ OnClick(toMessage(SelectedOption({ value: optionConfig.value, index }))),
112
+ OnKeyDownPreventDefault(handleKeyDown(index)),
113
+ ]),
114
+ ];
115
+ const labelAttributes = [
116
+ Id(labelId(id, index)),
117
+ ];
118
+ const descriptionAttributes = [
119
+ Id(descriptionId(id, index)),
120
+ ];
121
+ return optionConfig.content({
122
+ option: optionAttributes,
123
+ label: labelAttributes,
124
+ description: descriptionAttributes,
125
+ });
126
+ });
127
+ const hiddenInputs = pipe(name, Option.fromNullable, Option.flatMap(inputName => pipe(selectedValue, Option.map(value => input([Type('hidden'), Name(inputName), Value(value)])))), Option.match({
128
+ onNone: () => [],
129
+ onSome: hiddenInput => [hiddenInput],
130
+ }));
131
+ const groupAttributes = [
132
+ Role('radiogroup'),
133
+ AriaOrientation(String.toLowerCase(orientation)),
134
+ ...(className ? [Class(className)] : []),
135
+ ];
136
+ return div(groupAttributes, [...renderedOptions, ...hiddenInputs]);
137
+ };
138
+ /** Creates a memoized radio group view. Static config is captured in a closure;
139
+ * only `model` and `toMessage` are compared per render via `createLazy`. */
140
+ export const lazy = (staticConfig) => {
141
+ const lazyView = createLazy();
142
+ return (model, toMessage) => lazyView((currentModel, currentToMessage) => view({
143
+ ...staticConfig,
144
+ model: currentModel,
145
+ toMessage: currentToMessage,
146
+ }), [model, toMessage]);
147
+ };
@@ -0,0 +1,3 @@
1
+ export { init, update, view, lazy, Model, Message } from './index';
2
+ export type { SelectedOption, NoOp, Orientation, InitConfig, ViewConfig, OptionAttributes, OptionConfig, } from './index';
3
+ //# sourceMappingURL=public.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/radioGroup/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAElE,YAAY,EACV,cAAc,EACd,IAAI,EACJ,WAAW,EACX,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,YAAY,GACb,MAAM,SAAS,CAAA"}
@@ -0,0 +1 @@
1
+ export { init, update, view, lazy, Model, Message } from './index';
@@ -44,4 +44,7 @@ export type ViewConfig<Message> = Readonly<{
44
44
  }>;
45
45
  /** Renders an accessible switch toggle by building ARIA attribute groups and delegating layout to the consumer's `toView` callback. */
46
46
  export declare const view: <Message>(config: ViewConfig<Message>) => Html;
47
+ /** Creates a memoized switch view. Static config is captured in a closure;
48
+ * only `model` and `toMessage` are compared per render via `createLazy`. */
49
+ export declare const lazy: <Message>(staticConfig: Omit<ViewConfig<Message>, "model" | "toMessage">) => ((model: Model, toMessage: ViewConfig<Message>["toMessage"]) => Html);
47
50
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/switch/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAExD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAMtC,qFAAqF;AACrF,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,oEAAoE;AACpE,eAAO,MAAM,OAAO,4DAAe,CAAA;AACnC,yDAAyD;AACzD,eAAO,MAAM,IAAI,yDAAY,CAAA;AAE7B,8DAA8D;AAC9D,eAAO,MAAM,OAAO,gIAAyB,CAAA;AAE7C,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AACzC,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAA;AAEnC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,6DAA6D;AAC7D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAC,CAAA;AAEF,4EAA4E;AAC5E,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAGxC,CAAA;AAIF,0EAA0E;AAC1E,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAOvC,CAAA;AAIH,0FAA0F;AAC1F,MAAM,MAAM,gBAAgB,CAAC,OAAO,IAAI,QAAQ,CAAC;IAC/C,MAAM,EAAE,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;IACzC,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;IACxC,WAAW,EAAE,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;IAC9C,WAAW,EAAE,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;CAC/C,CAAC,CAAA;AAEF,wDAAwD;AACxD,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,KAAK,OAAO,CAAA;IAC/C,MAAM,EAAE,CAAC,UAAU,EAAE,gBAAgB,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;IACvD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAC,CAAA;AAKF,uIAAuI;AACvI,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,QAAQ,UAAU,CAAC,OAAO,CAAC,KAAG,IAmE3D,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/switch/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAExD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAOtC,qFAAqF;AACrF,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,oEAAoE;AACpE,eAAO,MAAM,OAAO,4DAAe,CAAA;AACnC,yDAAyD;AACzD,eAAO,MAAM,IAAI,yDAAY,CAAA;AAE7B,8DAA8D;AAC9D,eAAO,MAAM,OAAO,gIAAyB,CAAA;AAE7C,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AACzC,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAA;AAEnC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,6DAA6D;AAC7D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAC,CAAA;AAEF,4EAA4E;AAC5E,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAGxC,CAAA;AAIF,0EAA0E;AAC1E,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAOvC,CAAA;AAIH,0FAA0F;AAC1F,MAAM,MAAM,gBAAgB,CAAC,OAAO,IAAI,QAAQ,CAAC;IAC/C,MAAM,EAAE,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;IACzC,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;IACxC,WAAW,EAAE,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;IAC9C,WAAW,EAAE,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;CAC/C,CAAC,CAAA;AAEF,wDAAwD;AACxD,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,KAAK,OAAO,CAAA;IAC/C,MAAM,EAAE,CAAC,UAAU,EAAE,gBAAgB,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;IACvD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAC,CAAA;AAKF,uIAAuI;AACvI,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,QAAQ,UAAU,CAAC,OAAO,CAAC,KAAG,IAmE3D,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,5 +1,6 @@
1
1
  import { Match as M, Option, Schema as S } from 'effect';
2
2
  import { html } from '../../html';
3
+ import { createLazy } from '../../html/lazy';
3
4
  import { m } from '../../message';
4
5
  import { evo } from '../../struct';
5
6
  // MODEL
@@ -64,3 +65,13 @@ export const view = (config) => {
64
65
  hiddenInput: hiddenInputAttributes,
65
66
  });
66
67
  };
68
+ /** Creates a memoized switch view. Static config is captured in a closure;
69
+ * only `model` and `toMessage` are compared per render via `createLazy`. */
70
+ export const lazy = (staticConfig) => {
71
+ const lazyView = createLazy();
72
+ return (model, toMessage) => lazyView((currentModel, currentToMessage) => view({
73
+ ...staticConfig,
74
+ model: currentModel,
75
+ toMessage: currentToMessage,
76
+ }), [model, toMessage]);
77
+ };
@@ -1,3 +1,3 @@
1
- export { init, update, view, Model, Message } from './index';
1
+ export { init, update, view, lazy, Model, Message } from './index';
2
2
  export type { Toggled, NoOp, InitConfig, ViewConfig, SwitchAttributes, } from './index';
3
3
  //# sourceMappingURL=public.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/switch/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAE5D,YAAY,EACV,OAAO,EACP,IAAI,EACJ,UAAU,EACV,UAAU,EACV,gBAAgB,GACjB,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/switch/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAElE,YAAY,EACV,OAAO,EACP,IAAI,EACJ,UAAU,EACV,UAAU,EACV,gBAAgB,GACjB,MAAM,SAAS,CAAA"}
@@ -1 +1 @@
1
- export { init, update, view, Model, Message } from './index';
1
+ export { init, update, view, lazy, Model, Message } from './index';
@@ -72,4 +72,7 @@ export type ViewConfig<Message, Tab extends string> = Readonly<{
72
72
  }>;
73
73
  /** Renders a headless tab group with accessible ARIA roles, roving tabindex, and keyboard navigation. */
74
74
  export declare const view: <Message, Tab extends string>(config: ViewConfig<Message, Tab>) => Html;
75
+ /** Creates a memoized tabs view. Static config is captured in a closure;
76
+ * only `model` and `toMessage` are compared per render via `createLazy`. */
77
+ export declare const lazy: <Message, Tab extends string>(staticConfig: Omit<ViewConfig<Message, Tab>, "model" | "toMessage">) => ((model: Model, toMessage: ViewConfig<Message, Tab>["toMessage"]) => Html);
75
78
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/tabs/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/tabs/index.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { Array, Effect, Match as M, Option, Schema as S, String, pipe, } from 'effect';
2
2
  import { html } from '../../html';
3
+ import { createLazy } from '../../html/lazy';
3
4
  import { m } from '../../message';
4
5
  import { evo } from '../../struct';
5
6
  import * as Task from '../../task';
@@ -136,3 +137,13 @@ export const view = (config) => {
136
137
  ...tabPanels,
137
138
  ]);
138
139
  };
140
+ /** Creates a memoized tabs view. Static config is captured in a closure;
141
+ * only `model` and `toMessage` are compared per render via `createLazy`. */
142
+ export const lazy = (staticConfig) => {
143
+ const lazyView = createLazy();
144
+ return (model, toMessage) => lazyView((currentModel, currentToMessage) => view({
145
+ ...staticConfig,
146
+ model: currentModel,
147
+ toMessage: currentToMessage,
148
+ }), [model, toMessage]);
149
+ };
@@ -1,3 +1,3 @@
1
- export { init, update, view, Model, Message } from './index';
1
+ export { init, update, view, lazy, Model, Message } from './index';
2
2
  export type { Orientation, ActivationMode, TabSelected, TabFocused, NoOp, InitConfig, ViewConfig, TabConfig, } from './index';
3
3
  //# sourceMappingURL=public.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/tabs/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAE5D,YAAY,EACV,WAAW,EACX,cAAc,EACd,WAAW,EACX,UAAU,EACV,IAAI,EACJ,UAAU,EACV,UAAU,EACV,SAAS,GACV,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/tabs/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAElE,YAAY,EACV,WAAW,EACX,cAAc,EACd,WAAW,EACX,UAAU,EACV,IAAI,EACJ,UAAU,EACV,UAAU,EACV,SAAS,GACV,MAAM,SAAS,CAAA"}
@@ -1 +1 @@
1
- export { init, update, view, Model, Message } from './index';
1
+ export { init, update, view, lazy, Model, Message } from './index';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foldkit",
3
- "version": "0.26.0",
3
+ "version": "0.28.0",
4
4
  "description": "Elm-inspired UI framework powered by Effect",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -75,6 +75,10 @@
75
75
  "types": "./dist/ui/listbox/public.d.ts",
76
76
  "import": "./dist/ui/listbox/public.js"
77
77
  },
78
+ "./ui/combobox": {
79
+ "types": "./dist/ui/combobox/public.d.ts",
80
+ "import": "./dist/ui/combobox/public.js"
81
+ },
78
82
  "./ui/menu": {
79
83
  "types": "./dist/ui/menu/public.d.ts",
80
84
  "import": "./dist/ui/menu/public.js"
@@ -83,6 +87,10 @@
83
87
  "types": "./dist/ui/popover/public.d.ts",
84
88
  "import": "./dist/ui/popover/public.js"
85
89
  },
90
+ "./ui/radioGroup": {
91
+ "types": "./dist/ui/radioGroup/public.d.ts",
92
+ "import": "./dist/ui/radioGroup/public.js"
93
+ },
86
94
  "./ui/switch": {
87
95
  "types": "./dist/ui/switch/public.d.ts",
88
96
  "import": "./dist/ui/switch/public.js"
@@ -106,7 +114,7 @@
106
114
  "devDependencies": {
107
115
  "@effect/platform-browser": "^0.74.0",
108
116
  "@effect/vitest": "^0.27.0",
109
- "effect": "^3.19.15",
117
+ "effect": "^3.19.19",
110
118
  "happy-dom": "^18.0.1",
111
119
  "typescript": "^5.9.3",
112
120
  "vitest": "^3.2.4"