@foldkit/ui 0.112.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 (201) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/anchor.d.ts +38 -0
  4. package/dist/anchor.d.ts.map +1 -0
  5. package/dist/anchor.js +142 -0
  6. package/dist/animation/index.d.ts +49 -0
  7. package/dist/animation/index.d.ts.map +1 -0
  8. package/dist/animation/index.js +75 -0
  9. package/dist/animation/public.d.ts +3 -0
  10. package/dist/animation/public.d.ts.map +1 -0
  11. package/dist/animation/public.js +1 -0
  12. package/dist/animation/schema.d.ts +43 -0
  13. package/dist/animation/schema.d.ts.map +1 -0
  14. package/dist/animation/schema.js +41 -0
  15. package/dist/animation/update.d.ts +24 -0
  16. package/dist/animation/update.d.ts.map +1 -0
  17. package/dist/animation/update.js +67 -0
  18. package/dist/button/index.d.ts +17 -0
  19. package/dist/button/index.d.ts.map +1 -0
  20. package/dist/button/index.js +22 -0
  21. package/dist/button/public.d.ts +3 -0
  22. package/dist/button/public.d.ts.map +1 -0
  23. package/dist/button/public.js +1 -0
  24. package/dist/calendar/index.d.ts +462 -0
  25. package/dist/calendar/index.d.ts.map +1 -0
  26. package/dist/calendar/index.js +825 -0
  27. package/dist/calendar/public.d.ts +3 -0
  28. package/dist/calendar/public.d.ts.map +1 -0
  29. package/dist/calendar/public.js +1 -0
  30. package/dist/checkbox/index.d.ts +119 -0
  31. package/dist/checkbox/index.d.ts.map +1 -0
  32. package/dist/checkbox/index.js +111 -0
  33. package/dist/checkbox/public.d.ts +3 -0
  34. package/dist/checkbox/public.d.ts.map +1 -0
  35. package/dist/checkbox/public.js +1 -0
  36. package/dist/combobox/multi.d.ts +183 -0
  37. package/dist/combobox/multi.d.ts.map +1 -0
  38. package/dist/combobox/multi.js +81 -0
  39. package/dist/combobox/multiPublic.d.ts +3 -0
  40. package/dist/combobox/multiPublic.d.ts.map +1 -0
  41. package/dist/combobox/multiPublic.js +1 -0
  42. package/dist/combobox/public.d.ts +7 -0
  43. package/dist/combobox/public.d.ts.map +1 -0
  44. package/dist/combobox/public.js +3 -0
  45. package/dist/combobox/shared.d.ts +423 -0
  46. package/dist/combobox/shared.d.ts.map +1 -0
  47. package/dist/combobox/shared.js +708 -0
  48. package/dist/combobox/single.d.ts +198 -0
  49. package/dist/combobox/single.d.ts.map +1 -0
  50. package/dist/combobox/single.js +106 -0
  51. package/dist/datePicker/index.d.ts +457 -0
  52. package/dist/datePicker/index.d.ts.map +1 -0
  53. package/dist/datePicker/index.js +318 -0
  54. package/dist/datePicker/public.d.ts +3 -0
  55. package/dist/datePicker/public.d.ts.map +1 -0
  56. package/dist/datePicker/public.js +1 -0
  57. package/dist/dialog/index.d.ts +160 -0
  58. package/dist/dialog/index.d.ts.map +1 -0
  59. package/dist/dialog/index.js +211 -0
  60. package/dist/dialog/public.d.ts +3 -0
  61. package/dist/dialog/public.d.ts.map +1 -0
  62. package/dist/dialog/public.js +1 -0
  63. package/dist/disclosure/index.d.ts +110 -0
  64. package/dist/disclosure/index.d.ts.map +1 -0
  65. package/dist/disclosure/index.js +111 -0
  66. package/dist/disclosure/public.d.ts +3 -0
  67. package/dist/disclosure/public.d.ts.map +1 -0
  68. package/dist/disclosure/public.js +1 -0
  69. package/dist/dragAndDrop/index.d.ts +540 -0
  70. package/dist/dragAndDrop/index.d.ts.map +1 -0
  71. package/dist/dragAndDrop/index.js +535 -0
  72. package/dist/dragAndDrop/public.d.ts +3 -0
  73. package/dist/dragAndDrop/public.d.ts.map +1 -0
  74. package/dist/dragAndDrop/public.js +1 -0
  75. package/dist/fieldset/index.d.ts +21 -0
  76. package/dist/fieldset/index.d.ts.map +1 -0
  77. package/dist/fieldset/index.js +25 -0
  78. package/dist/fieldset/public.d.ts +3 -0
  79. package/dist/fieldset/public.d.ts.map +1 -0
  80. package/dist/fieldset/public.js +1 -0
  81. package/dist/fileDrop/index.d.ts +109 -0
  82. package/dist/fileDrop/index.d.ts.map +1 -0
  83. package/dist/fileDrop/index.js +127 -0
  84. package/dist/fileDrop/public.d.ts +3 -0
  85. package/dist/fileDrop/public.d.ts.map +1 -0
  86. package/dist/fileDrop/public.js +1 -0
  87. package/dist/group.d.ts +8 -0
  88. package/dist/group.d.ts.map +1 -0
  89. package/dist/group.js +13 -0
  90. package/dist/index.d.ts +25 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +24 -0
  93. package/dist/input/index.d.ts +26 -0
  94. package/dist/input/index.d.ts.map +1 -0
  95. package/dist/input/index.js +43 -0
  96. package/dist/input/public.d.ts +3 -0
  97. package/dist/input/public.d.ts.map +1 -0
  98. package/dist/input/public.js +1 -0
  99. package/dist/internal/optionExtensions.d.ts +6 -0
  100. package/dist/internal/optionExtensions.d.ts.map +1 -0
  101. package/dist/internal/optionExtensions.js +2 -0
  102. package/dist/keyboard.d.ts +6 -0
  103. package/dist/keyboard.d.ts.map +1 -0
  104. package/dist/keyboard.js +9 -0
  105. package/dist/listbox/multi.d.ts +189 -0
  106. package/dist/listbox/multi.d.ts.map +1 -0
  107. package/dist/listbox/multi.js +65 -0
  108. package/dist/listbox/multiPublic.d.ts +3 -0
  109. package/dist/listbox/multiPublic.d.ts.map +1 -0
  110. package/dist/listbox/multiPublic.js +1 -0
  111. package/dist/listbox/public.d.ts +7 -0
  112. package/dist/listbox/public.d.ts.map +1 -0
  113. package/dist/listbox/public.js +3 -0
  114. package/dist/listbox/shared.d.ts +432 -0
  115. package/dist/listbox/shared.d.ts.map +1 -0
  116. package/dist/listbox/shared.js +670 -0
  117. package/dist/listbox/single.d.ts +207 -0
  118. package/dist/listbox/single.d.ts.map +1 -0
  119. package/dist/listbox/single.js +73 -0
  120. package/dist/menu/index.d.ts +368 -0
  121. package/dist/menu/index.d.ts.map +1 -0
  122. package/dist/menu/index.js +682 -0
  123. package/dist/menu/public.d.ts +4 -0
  124. package/dist/menu/public.d.ts.map +1 -0
  125. package/dist/menu/public.js +1 -0
  126. package/dist/popover/index.d.ts +267 -0
  127. package/dist/popover/index.d.ts.map +1 -0
  128. package/dist/popover/index.js +346 -0
  129. package/dist/popover/public.d.ts +4 -0
  130. package/dist/popover/public.d.ts.map +1 -0
  131. package/dist/popover/public.js +1 -0
  132. package/dist/radioGroup/index.d.ts +169 -0
  133. package/dist/radioGroup/index.d.ts.map +1 -0
  134. package/dist/radioGroup/index.js +197 -0
  135. package/dist/radioGroup/public.d.ts +3 -0
  136. package/dist/radioGroup/public.d.ts.map +1 -0
  137. package/dist/radioGroup/public.js +1 -0
  138. package/dist/select/index.d.ts +24 -0
  139. package/dist/select/index.d.ts.map +1 -0
  140. package/dist/select/index.js +40 -0
  141. package/dist/select/public.d.ts +3 -0
  142. package/dist/select/public.d.ts.map +1 -0
  143. package/dist/select/public.js +1 -0
  144. package/dist/slider/index.d.ts +318 -0
  145. package/dist/slider/index.d.ts.map +1 -0
  146. package/dist/slider/index.js +337 -0
  147. package/dist/slider/public.d.ts +3 -0
  148. package/dist/slider/public.d.ts.map +1 -0
  149. package/dist/slider/public.js +1 -0
  150. package/dist/switch/index.d.ts +99 -0
  151. package/dist/switch/index.d.ts.map +1 -0
  152. package/dist/switch/index.js +107 -0
  153. package/dist/switch/public.d.ts +3 -0
  154. package/dist/switch/public.d.ts.map +1 -0
  155. package/dist/switch/public.js +1 -0
  156. package/dist/tabs/index.d.ts +155 -0
  157. package/dist/tabs/index.d.ts.map +1 -0
  158. package/dist/tabs/index.js +185 -0
  159. package/dist/tabs/public.d.ts +3 -0
  160. package/dist/tabs/public.d.ts.map +1 -0
  161. package/dist/tabs/public.js +1 -0
  162. package/dist/test/apps/disabledButton.d.ts +38 -0
  163. package/dist/test/apps/disabledButton.d.ts.map +1 -0
  164. package/dist/test/apps/disabledButton.js +71 -0
  165. package/dist/textarea/index.d.ts +26 -0
  166. package/dist/textarea/index.d.ts.map +1 -0
  167. package/dist/textarea/index.js +44 -0
  168. package/dist/textarea/public.d.ts +3 -0
  169. package/dist/textarea/public.d.ts.map +1 -0
  170. package/dist/textarea/public.js +1 -0
  171. package/dist/toast/index.d.ts +608 -0
  172. package/dist/toast/index.d.ts.map +1 -0
  173. package/dist/toast/index.js +146 -0
  174. package/dist/toast/public.d.ts +4 -0
  175. package/dist/toast/public.d.ts.map +1 -0
  176. package/dist/toast/public.js +1 -0
  177. package/dist/toast/schema.d.ts +154 -0
  178. package/dist/toast/schema.d.ts.map +1 -0
  179. package/dist/toast/schema.js +93 -0
  180. package/dist/toast/update.d.ts +510 -0
  181. package/dist/toast/update.d.ts.map +1 -0
  182. package/dist/toast/update.js +225 -0
  183. package/dist/tooltip/index.d.ts +170 -0
  184. package/dist/tooltip/index.d.ts.map +1 -0
  185. package/dist/tooltip/index.js +253 -0
  186. package/dist/tooltip/public.d.ts +4 -0
  187. package/dist/tooltip/public.d.ts.map +1 -0
  188. package/dist/tooltip/public.js +1 -0
  189. package/dist/typeahead.d.ts +4 -0
  190. package/dist/typeahead.d.ts.map +1 -0
  191. package/dist/typeahead.js +14 -0
  192. package/dist/virtualList/index.d.ts +203 -0
  193. package/dist/virtualList/index.d.ts.map +1 -0
  194. package/dist/virtualList/index.js +392 -0
  195. package/dist/virtualList/public.d.ts +3 -0
  196. package/dist/virtualList/public.d.ts.map +1 -0
  197. package/dist/virtualList/public.js +1 -0
  198. package/dist/vitest-setup.d.ts +2 -0
  199. package/dist/vitest-setup.d.ts.map +1 -0
  200. package/dist/vitest-setup.js +2 -0
  201. package/package.json +161 -0
@@ -0,0 +1,225 @@
1
+ import { Array, Duration, Effect, Match as M, Number, Option, Schema as S, } from 'effect';
2
+ import * as Command from 'foldkit/command';
3
+ import { evo } from 'foldkit/struct';
4
+ import { Hid as AnimationHid, Showed as AnimationShowed, init as animationInit, } from '../animation/schema.js';
5
+ import { defaultLeaveCommand as animationDefaultLeaveCommand, update as animationUpdate, } from '../animation/update.js';
6
+ import * as OptionExt from '../internal/optionExtensions.js';
7
+ import { DEFAULT_DURATION, Dismissed, DismissedAll, ElapsedDuration, GotAnimationMessage, makeAdded, makeDismissedToast, makeEntry, makeMessage, makeModel, makeOutMessage, } from './schema.js';
8
+ /** Schedules an auto-dismiss timer for an entry. The result Message carries a
9
+ * version so stale timers (from hover or manual dismiss) are discarded in
10
+ * the update function. Static. The Command definition doesn't depend on
11
+ * payload. */
12
+ export const DismissAfter = Command.define('DismissAfter', {
13
+ entryId: S.String,
14
+ version: S.Number,
15
+ duration: S.DurationFromMillis,
16
+ }, ElapsedDuration)(({ entryId, version, duration }) => Effect.sleep(duration).pipe(Effect.as(ElapsedDuration({ entryId, version }))));
17
+ const DEFAULT_VARIANT = 'Info';
18
+ /** Factory that binds Toast's runtime (update fn, helpers, commands) to a
19
+ * specific payload schema. Called by `make` in index.ts; inner helpers close
20
+ * over the payload-specific Entry / Model / Added types so generics don't
21
+ * have to propagate through every helper signature.
22
+ *
23
+ * @internal Consumers should use `Toast.make(PayloadSchema)`. This is
24
+ * only exported so `index.ts` can wire the view into the bound runtime. */
25
+ export const makeRuntime = (payloadSchema) => {
26
+ const EntrySchema = makeEntry(payloadSchema);
27
+ const ModelSchema = makeModel(payloadSchema);
28
+ const MessageSchema = makeMessage(payloadSchema);
29
+ const OutMessageSchema = makeOutMessage(payloadSchema);
30
+ const Added = makeAdded(payloadSchema);
31
+ const DismissedToast = makeDismissedToast(payloadSchema);
32
+ const withUpdateReturn = M.withReturnType();
33
+ const updateEntry = (model, entryId, f) => evo(model, {
34
+ entries: Array.map(entry => (entry.id === entryId ? f(entry) : entry)),
35
+ });
36
+ const removeEntry = (model, entryId) => evo(model, {
37
+ entries: Array.filter(({ id }) => id !== entryId),
38
+ });
39
+ const isEntryLeaving = (entry) => {
40
+ const { transitionState } = entry.animation;
41
+ return (transitionState === 'LeaveStart' || transitionState === 'LeaveAnimating');
42
+ };
43
+ const scheduleDismiss = (entryId, version, duration) => DismissAfter({ entryId, version, duration });
44
+ const rescheduleDismissCommands = (entry) => {
45
+ if (isEntryLeaving(entry) || entry.isHovered) {
46
+ return [];
47
+ }
48
+ else {
49
+ return Option.match(entry.maybeDuration, {
50
+ onNone: () => [],
51
+ onSome: duration => [
52
+ scheduleDismiss(entry.id, entry.pendingDismissVersion, duration),
53
+ ],
54
+ });
55
+ }
56
+ };
57
+ const delegateToEntryAnimation = (model, entryId, animationMessage) => {
58
+ const maybeEntry = Array.findFirst(model.entries, ({ id }) => id === entryId);
59
+ return Option.match(maybeEntry, {
60
+ onNone: () => [model, [], Option.none()],
61
+ onSome: entry => {
62
+ const [nextAnimation, animationCommands, maybeOutMessage] = animationUpdate(entry.animation, animationMessage);
63
+ const toMessage = (message) => GotAnimationMessage({ entryId, message });
64
+ const mappedCommands = Command.mapMessages(animationCommands, toMessage);
65
+ const nextEntry = evo(entry, {
66
+ animation: () => nextAnimation,
67
+ });
68
+ return Option.match(maybeOutMessage, {
69
+ onNone: () => [
70
+ updateEntry(model, entryId, () => nextEntry),
71
+ mappedCommands,
72
+ Option.none(),
73
+ ],
74
+ onSome: M.type().pipe(withUpdateReturn, M.tagsExhaustive({
75
+ StartedLeaveAnimating: () => [
76
+ updateEntry(model, entryId, () => nextEntry),
77
+ [
78
+ ...mappedCommands,
79
+ Command.mapMessage(animationDefaultLeaveCommand(nextAnimation), toMessage),
80
+ ],
81
+ Option.none(),
82
+ ],
83
+ TransitionedOut: () => [
84
+ removeEntry(model, entryId),
85
+ mappedCommands,
86
+ Option.some(DismissedToast({ payload: entry.payload })),
87
+ ],
88
+ })),
89
+ });
90
+ },
91
+ });
92
+ };
93
+ const createEntry = (model, input) => {
94
+ const entryId = `${model.id}-entry-${model.nextEntryKey}`;
95
+ const duration = input.duration === undefined
96
+ ? model.defaultDuration
97
+ : Duration.fromInputUnsafe(input.duration);
98
+ const maybeDuration = OptionExt.when(!input.sticky, duration);
99
+ return {
100
+ id: entryId,
101
+ variant: input.variant ?? DEFAULT_VARIANT,
102
+ animation: animationInit({ id: entryId, isShowing: false }),
103
+ maybeDuration,
104
+ pendingDismissVersion: 0,
105
+ isHovered: false,
106
+ payload: input.payload,
107
+ };
108
+ };
109
+ /** Creates an initial toast container model from a config. Starts empty. */
110
+ const init = (config) => ({
111
+ id: config.id,
112
+ defaultDuration: config.defaultDuration === undefined
113
+ ? DEFAULT_DURATION
114
+ : Duration.fromInputUnsafe(config.defaultDuration),
115
+ entries: [],
116
+ nextEntryKey: 0,
117
+ });
118
+ /** Processes a toast message and returns the next model, commands, and
119
+ * an optional `DismissedToast` OutMessage emitted once an entry has
120
+ * finished its leave animation. */
121
+ const update = (model, message) => M.value(message).pipe(withUpdateReturn, M.tagsExhaustive({
122
+ Added: ({ entry }) => {
123
+ const modelWithEntry = evo(model, {
124
+ entries: entries => Array.append(entries, entry),
125
+ nextEntryKey: Number.increment,
126
+ });
127
+ const [modelAfterShow, showCommands] = delegateToEntryAnimation(modelWithEntry, entry.id, AnimationShowed());
128
+ const postShowEntry = Array.findFirst(modelAfterShow.entries, ({ id }) => id === entry.id);
129
+ const dismissCommands = Option.match(postShowEntry, {
130
+ onNone: () => [],
131
+ onSome: rescheduleDismissCommands,
132
+ });
133
+ return [
134
+ modelAfterShow,
135
+ [...showCommands, ...dismissCommands],
136
+ Option.none(),
137
+ ];
138
+ },
139
+ Dismissed: ({ entryId }) => {
140
+ const maybeEntry = Array.findFirst(model.entries, ({ id }) => id === entryId);
141
+ return Option.match(maybeEntry, {
142
+ onNone: () => [model, [], Option.none()],
143
+ onSome: entry => {
144
+ if (isEntryLeaving(entry)) {
145
+ return [model, [], Option.none()];
146
+ }
147
+ else {
148
+ return delegateToEntryAnimation(model, entryId, AnimationHid());
149
+ }
150
+ },
151
+ });
152
+ },
153
+ DismissedAll: () => Array.reduce(model.entries, [model, [], Option.none()], ([currentModel, currentCommands, currentOut], entry) => {
154
+ if (isEntryLeaving(entry)) {
155
+ return [currentModel, currentCommands, currentOut];
156
+ }
157
+ const [nextModel, nextCommands] = delegateToEntryAnimation(currentModel, entry.id, AnimationHid());
158
+ return [
159
+ nextModel,
160
+ [...currentCommands, ...nextCommands],
161
+ currentOut,
162
+ ];
163
+ }),
164
+ ElapsedDuration: ({ entryId, version }) => {
165
+ const maybeEntry = Array.findFirst(model.entries, ({ id }) => id === entryId);
166
+ return Option.match(maybeEntry, {
167
+ onNone: () => [model, [], Option.none()],
168
+ onSome: entry => {
169
+ const isStale = version !== entry.pendingDismissVersion;
170
+ if (isStale || isEntryLeaving(entry)) {
171
+ return [model, [], Option.none()];
172
+ }
173
+ else {
174
+ return delegateToEntryAnimation(model, entryId, AnimationHid());
175
+ }
176
+ },
177
+ });
178
+ },
179
+ HoveredEntry: ({ entryId }) => [
180
+ updateEntry(model, entryId, entry => evo(entry, {
181
+ isHovered: () => true,
182
+ pendingDismissVersion: Number.increment,
183
+ })),
184
+ [],
185
+ Option.none(),
186
+ ],
187
+ LeftEntry: ({ entryId }) => {
188
+ const maybeEntry = Array.findFirst(model.entries, ({ id }) => id === entryId);
189
+ return Option.match(maybeEntry, {
190
+ onNone: () => [model, [], Option.none()],
191
+ onSome: entry => {
192
+ const nextEntry = evo(entry, {
193
+ isHovered: () => false,
194
+ pendingDismissVersion: Number.increment,
195
+ });
196
+ return [
197
+ updateEntry(model, entryId, () => nextEntry),
198
+ rescheduleDismissCommands(nextEntry),
199
+ Option.none(),
200
+ ];
201
+ },
202
+ });
203
+ },
204
+ GotAnimationMessage: ({ entryId, message: animationMessage }) => delegateToEntryAnimation(model, entryId, animationMessage),
205
+ }));
206
+ /** Adds a new toast entry. */
207
+ const show = (model, input) => update(model, Added({ entry: createEntry(model, input) }));
208
+ /** Begins dismissing a specific entry. */
209
+ const dismiss = (model, entryId) => update(model, Dismissed({ entryId }));
210
+ /** Begins dismissing every currently-visible entry. */
211
+ const dismissAll = (model) => update(model, DismissedAll());
212
+ return {
213
+ Entry: EntrySchema,
214
+ Model: ModelSchema,
215
+ Message: MessageSchema,
216
+ OutMessage: OutMessageSchema,
217
+ Added,
218
+ DismissedToast,
219
+ init,
220
+ update,
221
+ show,
222
+ dismiss,
223
+ dismissAll,
224
+ };
225
+ };
@@ -0,0 +1,170 @@
1
+ import { Duration, Effect, Option, Schema as S } from 'effect';
2
+ import * as Command from 'foldkit/command';
3
+ import { type ChildAttribute, type Html } from 'foldkit/html';
4
+ import * as Mount from 'foldkit/mount';
5
+ import { type Reflect } from 'foldkit/submodel';
6
+ import { AnchorConfig } from '../anchor.js';
7
+ /** Schema for the tooltip component's state. `isOpen` is visibility; `isHovered` tracks pointer on trigger; `isFocused` tracks tooltip-affirming focus on the trigger (focus arriving without a preceding mouse press, like keyboard, touch, or pen; mouse-click-induced focus is excluded since it doesn't affirm the user wants the tooltip visible); `isDismissed` suppresses re-opening after the user dismissed the tooltip (via Escape or left-click) until they disengage (leave or blur). `showDelay` is the hover-to-show duration. `maybeLastPointerType` records the most recent pointer type that pressed the trigger, so a mouse-click-induced focus can be distinguished from other focus. */
8
+ export declare const Model: S.Struct<{
9
+ readonly id: S.String;
10
+ readonly isOpen: S.Boolean;
11
+ readonly isHovered: S.Boolean;
12
+ readonly isFocused: S.Boolean;
13
+ readonly isDismissed: S.Boolean;
14
+ readonly showDelay: S.DurationFromMillis;
15
+ readonly pendingShowVersion: S.Number;
16
+ readonly maybeLastPointerType: S.Option<S.String>;
17
+ }>;
18
+ export type Model = typeof Model.Type;
19
+ /** Sent when the pointer enters the tooltip trigger. */
20
+ export declare const EnteredTrigger: import("foldkit/schema").CallableTaggedStruct<"EnteredTrigger", {}>;
21
+ /** Sent when the pointer leaves the tooltip trigger. */
22
+ export declare const LeftTrigger: import("foldkit/schema").CallableTaggedStruct<"LeftTrigger", {}>;
23
+ /** Sent when focus enters the trigger. */
24
+ export declare const FocusedTrigger: import("foldkit/schema").CallableTaggedStruct<"FocusedTrigger", {}>;
25
+ /** Sent when focus leaves the trigger. */
26
+ export declare const BlurredTrigger: import("foldkit/schema").CallableTaggedStruct<"BlurredTrigger", {}>;
27
+ /** Sent when Escape is pressed while the tooltip is visible. */
28
+ export declare const PressedEscape: import("foldkit/schema").CallableTaggedStruct<"PressedEscape", {}>;
29
+ /** Sent when a pointer presses the trigger. */
30
+ export declare const PressedPointerOnTrigger: import("foldkit/schema").CallableTaggedStruct<"PressedPointerOnTrigger", {
31
+ pointerType: S.String;
32
+ button: S.Number;
33
+ }>;
34
+ /** Sent when the show-delay timer fires. */
35
+ export declare const ElapsedShowDelay: import("foldkit/schema").CallableTaggedStruct<"ElapsedShowDelay", {
36
+ version: S.Number;
37
+ }>;
38
+ /** Sent when the tooltip panel mounts and Floating UI has positioned it. */
39
+ export declare const CompletedAnchorTooltip: import("foldkit/schema").CallableTaggedStruct<"CompletedAnchorTooltip", {}>;
40
+ /** Union of all messages the tooltip component can produce. */
41
+ export declare const Message: S.Union<[
42
+ typeof EnteredTrigger,
43
+ typeof LeftTrigger,
44
+ typeof FocusedTrigger,
45
+ typeof BlurredTrigger,
46
+ typeof PressedEscape,
47
+ typeof PressedPointerOnTrigger,
48
+ typeof ElapsedShowDelay,
49
+ typeof CompletedAnchorTooltip
50
+ ]>;
51
+ export type EnteredTrigger = typeof EnteredTrigger.Type;
52
+ export type LeftTrigger = typeof LeftTrigger.Type;
53
+ export type FocusedTrigger = typeof FocusedTrigger.Type;
54
+ export type BlurredTrigger = typeof BlurredTrigger.Type;
55
+ export type PressedEscape = typeof PressedEscape.Type;
56
+ export type PressedPointerOnTrigger = typeof PressedPointerOnTrigger.Type;
57
+ export type Message = typeof Message.Type;
58
+ /** Emitted once the tooltip transitions to visible (`isOpen` becomes true).
59
+ * Consumers typically use this for analytics, instrumentation, or to
60
+ * coordinate with other transient UI. */
61
+ export declare const Shown: import("foldkit/schema").CallableTaggedStruct<"Shown", {}>;
62
+ /** Emitted once the tooltip transitions to hidden (`isOpen` becomes false). */
63
+ export declare const Hidden: import("foldkit/schema").CallableTaggedStruct<"Hidden", {}>;
64
+ /** Union of out-messages the tooltip component can produce. */
65
+ export declare const OutMessage: S.Union<readonly [import("foldkit/schema").CallableTaggedStruct<"Shown", {}>, import("foldkit/schema").CallableTaggedStruct<"Hidden", {}>]>;
66
+ export type Shown = typeof Shown.Type;
67
+ export type Hidden = typeof Hidden.Type;
68
+ export type OutMessage = typeof OutMessage.Type;
69
+ /** Configuration for creating a tooltip model with `init`. */
70
+ export type InitConfig = Readonly<{
71
+ id: string;
72
+ showDelay?: Duration.Input;
73
+ }>;
74
+ /** Creates an initial tooltip model from a config. Defaults to hidden. */
75
+ export declare const init: (config: InitConfig) => Model;
76
+ /** Waits for the tooltip's show delay before emitting `ElapsedShowDelay`. */
77
+ export declare const ShowAfterDelay: Command.CommandDefinitionWithArgs<"ShowAfterDelay", {
78
+ delay: S.DurationFromMillis;
79
+ version: S.Number;
80
+ }, Effect.Effect<{
81
+ readonly _tag: "ElapsedShowDelay";
82
+ readonly version: number;
83
+ }, never, never>>;
84
+ /** The anchor-positioning Mount this Tooltip renders on its panel. */
85
+ export declare const AnchorTooltip: Mount.MountDefinitionWithArgs<"AnchorTooltip", {
86
+ buttonId: S.String;
87
+ anchor: S.Struct<{
88
+ readonly placement: S.optional<S.Literals<readonly ["top", "right", "bottom", "left", "top-start", "top-end", "right-start", "right-end", "bottom-start", "bottom-end", "left-start", "left-end"]>>;
89
+ readonly gap: S.optional<S.Number>;
90
+ readonly offset: S.optional<S.Number>;
91
+ readonly padding: S.optional<S.Number>;
92
+ readonly portal: S.optional<S.Boolean>;
93
+ }>;
94
+ }, {
95
+ readonly _tag: "CompletedAnchorTooltip";
96
+ }>;
97
+ type UpdateReturn = readonly [
98
+ Model,
99
+ ReadonlyArray<Command.Command<Message>>,
100
+ Option.Option<OutMessage>
101
+ ];
102
+ /** Processes a tooltip message and returns the next model, commands, and
103
+ * an optional OutMessage. `Shown`/`Hidden` fire only on `isOpen`
104
+ * transitions, so consumers don't get spurious events for messages that
105
+ * only update hover/focus/delay state without changing visibility. */
106
+ export declare const update: (model: Model, message: Message) => UpdateReturn;
107
+ /** Reflects an externally-sourced hover show-delay onto the model without
108
+ * emitting an OutMessage. Use to mirror an external config value (a user
109
+ * preference, a restored setting) onto the tooltip. */
110
+ export declare const reflectShowDelay: Reflect<Model, Duration.Input>;
111
+ /** Render-time payload published to the consumer's `toView`.
112
+ *
113
+ * - `trigger`: attribute bundle for the trigger element. Carries the
114
+ * hover/focus/keyboard handlers + ARIA `aria-describedby` linking to
115
+ * the panel.
116
+ * - `panel`: attribute bundle for the panel element. Carries the
117
+ * `role="tooltip"`, the anchor Mount that positions the panel via
118
+ * Floating UI, and a `data-open` attribute when visible.
119
+ * - `isVisible`: derived state. The consumer decides whether to render
120
+ * the panel conditionally on this. */
121
+ export type RenderInfo = Readonly<{
122
+ trigger: ReadonlyArray<ChildAttribute>;
123
+ panel: ReadonlyArray<ChildAttribute>;
124
+ isVisible: boolean;
125
+ }>;
126
+ /** Per-render view inputs passed to `view` via `h.submodel`'s `viewInputs` field. */
127
+ export type ViewInputs = Readonly<{
128
+ anchor: AnchorConfig;
129
+ toView: (render: RenderInfo) => Html;
130
+ isDisabled?: boolean;
131
+ }>;
132
+ /** Renders a headless tooltip with an anchored non-interactive panel.
133
+ * Shows on hover (after delay) or focus (from keyboard, touch, or pen;
134
+ * mouse-click focus is excluded); hides on leave, blur, Escape, or
135
+ * left-click of the trigger. */
136
+ export declare const view: import("foldkit/submodel").View<{
137
+ readonly id: string;
138
+ readonly isOpen: boolean;
139
+ readonly isHovered: boolean;
140
+ readonly isFocused: boolean;
141
+ readonly isDismissed: boolean;
142
+ readonly showDelay: Duration.Duration;
143
+ readonly pendingShowVersion: number;
144
+ readonly maybeLastPointerType: Option.Option<string>;
145
+ }, {
146
+ readonly _tag: "EnteredTrigger";
147
+ } | {
148
+ readonly _tag: "LeftTrigger";
149
+ } | {
150
+ readonly _tag: "FocusedTrigger";
151
+ } | {
152
+ readonly _tag: "BlurredTrigger";
153
+ } | {
154
+ readonly _tag: "PressedEscape";
155
+ } | {
156
+ readonly _tag: "PressedPointerOnTrigger";
157
+ readonly pointerType: string;
158
+ readonly button: number;
159
+ } | {
160
+ readonly _tag: "ElapsedShowDelay";
161
+ readonly version: number;
162
+ } | {
163
+ readonly _tag: "CompletedAnchorTooltip";
164
+ }, Readonly<{
165
+ anchor: AnchorConfig;
166
+ toView: (render: RenderInfo) => Html;
167
+ isDisabled?: boolean;
168
+ }>>;
169
+ export {};
170
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tooltip/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,253 @@
1
+ import { Duration, Effect, Equal, Function, Match as M, Number, Option, Schema as S, } from 'effect';
2
+ import * as Command from 'foldkit/command';
3
+ import { childAttributes, html, } from 'foldkit/html';
4
+ import { m } from 'foldkit/message';
5
+ import * as Mount from 'foldkit/mount';
6
+ import { evo } from 'foldkit/struct';
7
+ import { defineView } from 'foldkit/submodel';
8
+ import { AnchorConfig, anchorSetup } from '../anchor.js';
9
+ import * as OptionExt from '../internal/optionExtensions.js';
10
+ // MODEL
11
+ /** Schema for the tooltip component's state. `isOpen` is visibility; `isHovered` tracks pointer on trigger; `isFocused` tracks tooltip-affirming focus on the trigger (focus arriving without a preceding mouse press, like keyboard, touch, or pen; mouse-click-induced focus is excluded since it doesn't affirm the user wants the tooltip visible); `isDismissed` suppresses re-opening after the user dismissed the tooltip (via Escape or left-click) until they disengage (leave or blur). `showDelay` is the hover-to-show duration. `maybeLastPointerType` records the most recent pointer type that pressed the trigger, so a mouse-click-induced focus can be distinguished from other focus. */
12
+ export const Model = S.Struct({
13
+ id: S.String,
14
+ isOpen: S.Boolean,
15
+ isHovered: S.Boolean,
16
+ isFocused: S.Boolean,
17
+ isDismissed: S.Boolean,
18
+ showDelay: S.DurationFromMillis,
19
+ pendingShowVersion: S.Number,
20
+ maybeLastPointerType: S.Option(S.String),
21
+ });
22
+ // MESSAGE
23
+ /** Sent when the pointer enters the tooltip trigger. */
24
+ export const EnteredTrigger = m('EnteredTrigger');
25
+ /** Sent when the pointer leaves the tooltip trigger. */
26
+ export const LeftTrigger = m('LeftTrigger');
27
+ /** Sent when focus enters the trigger. */
28
+ export const FocusedTrigger = m('FocusedTrigger');
29
+ /** Sent when focus leaves the trigger. */
30
+ export const BlurredTrigger = m('BlurredTrigger');
31
+ /** Sent when Escape is pressed while the tooltip is visible. */
32
+ export const PressedEscape = m('PressedEscape');
33
+ /** Sent when a pointer presses the trigger. */
34
+ export const PressedPointerOnTrigger = m('PressedPointerOnTrigger', {
35
+ pointerType: S.String,
36
+ button: S.Number,
37
+ });
38
+ /** Sent when the show-delay timer fires. */
39
+ export const ElapsedShowDelay = m('ElapsedShowDelay', {
40
+ version: S.Number,
41
+ });
42
+ /** Sent when the tooltip panel mounts and Floating UI has positioned it. */
43
+ export const CompletedAnchorTooltip = m('CompletedAnchorTooltip');
44
+ /** Union of all messages the tooltip component can produce. */
45
+ export const Message = S.Union([
46
+ EnteredTrigger,
47
+ LeftTrigger,
48
+ FocusedTrigger,
49
+ BlurredTrigger,
50
+ PressedEscape,
51
+ PressedPointerOnTrigger,
52
+ ElapsedShowDelay,
53
+ CompletedAnchorTooltip,
54
+ ]);
55
+ // OUT MESSAGE
56
+ /** Emitted once the tooltip transitions to visible (`isOpen` becomes true).
57
+ * Consumers typically use this for analytics, instrumentation, or to
58
+ * coordinate with other transient UI. */
59
+ export const Shown = m('Shown');
60
+ /** Emitted once the tooltip transitions to hidden (`isOpen` becomes false). */
61
+ export const Hidden = m('Hidden');
62
+ /** Union of out-messages the tooltip component can produce. */
63
+ export const OutMessage = S.Union([Shown, Hidden]);
64
+ // INIT
65
+ const DEFAULT_SHOW_DELAY = Duration.millis(500);
66
+ const LEFT_MOUSE_BUTTON = 0;
67
+ /** Creates an initial tooltip model from a config. Defaults to hidden. */
68
+ export const init = (config) => ({
69
+ id: config.id,
70
+ isOpen: false,
71
+ isHovered: false,
72
+ isFocused: false,
73
+ isDismissed: false,
74
+ showDelay: config.showDelay === undefined
75
+ ? DEFAULT_SHOW_DELAY
76
+ : Duration.fromInputUnsafe(config.showDelay),
77
+ pendingShowVersion: 0,
78
+ maybeLastPointerType: Option.none(),
79
+ });
80
+ const withUpdateReturn = M.withReturnType();
81
+ /** Waits for the tooltip's show delay before emitting `ElapsedShowDelay`. */
82
+ export const ShowAfterDelay = Command.define('ShowAfterDelay', { delay: S.DurationFromMillis, version: S.Number }, ElapsedShowDelay)(({ delay, version }) => Effect.sleep(delay).pipe(Effect.as(ElapsedShowDelay({ version }))));
83
+ /** The anchor-positioning Mount this Tooltip renders on its panel. */
84
+ export const AnchorTooltip = Mount.define('AnchorTooltip', { buttonId: S.String, anchor: AnchorConfig }, CompletedAnchorTooltip)(({ buttonId, anchor }) => element => Effect.gen(function* () {
85
+ yield* Effect.acquireRelease(Effect.sync(() => anchorSetup({
86
+ buttonId,
87
+ anchor,
88
+ interceptTab: false,
89
+ })(element)), cleanup => Effect.sync(cleanup));
90
+ return CompletedAnchorTooltip();
91
+ }));
92
+ const computeUpdate = (model, message) => M.value(message).pipe(withUpdateReturn, M.tagsExhaustive({
93
+ EnteredTrigger: () => {
94
+ if (model.isOpen || model.isDismissed) {
95
+ return [evo(model, { isHovered: () => true }), []];
96
+ }
97
+ const nextVersion = Number.increment(model.pendingShowVersion);
98
+ return [
99
+ evo(model, {
100
+ isHovered: () => true,
101
+ pendingShowVersion: () => nextVersion,
102
+ }),
103
+ [ShowAfterDelay({ delay: model.showDelay, version: nextVersion })],
104
+ ];
105
+ },
106
+ LeftTrigger: () => [
107
+ evo(model, {
108
+ isHovered: () => false,
109
+ isOpen: () => model.isFocused && model.isOpen,
110
+ isDismissed: () => false,
111
+ pendingShowVersion: Number.increment,
112
+ }),
113
+ [],
114
+ ],
115
+ FocusedTrigger: () => {
116
+ const isFromMousePress = Option.exists(model.maybeLastPointerType, Equal.equals('mouse'));
117
+ if (isFromMousePress) {
118
+ return [
119
+ evo(model, {
120
+ maybeLastPointerType: () => Option.none(),
121
+ }),
122
+ [],
123
+ ];
124
+ }
125
+ if (model.isDismissed) {
126
+ return [
127
+ evo(model, {
128
+ isFocused: () => true,
129
+ maybeLastPointerType: () => Option.none(),
130
+ }),
131
+ [],
132
+ ];
133
+ }
134
+ return [
135
+ evo(model, {
136
+ isFocused: () => true,
137
+ isOpen: () => true,
138
+ pendingShowVersion: Number.increment,
139
+ }),
140
+ [],
141
+ ];
142
+ },
143
+ BlurredTrigger: () => [
144
+ evo(model, {
145
+ isFocused: () => false,
146
+ isOpen: () => model.isHovered && model.isOpen,
147
+ isDismissed: () => false,
148
+ pendingShowVersion: Number.increment,
149
+ maybeLastPointerType: () => Option.none(),
150
+ }),
151
+ [],
152
+ ],
153
+ PressedEscape: () => [
154
+ evo(model, {
155
+ isOpen: () => false,
156
+ isDismissed: () => true,
157
+ pendingShowVersion: Number.increment,
158
+ }),
159
+ [],
160
+ ],
161
+ PressedPointerOnTrigger: ({ pointerType, button }) => {
162
+ const isLeftClickOnOpen = button === LEFT_MOUSE_BUTTON && model.isOpen;
163
+ if (isLeftClickOnOpen) {
164
+ return [
165
+ evo(model, {
166
+ maybeLastPointerType: () => Option.some(pointerType),
167
+ isOpen: () => false,
168
+ isFocused: () => false,
169
+ isDismissed: () => true,
170
+ pendingShowVersion: Number.increment,
171
+ }),
172
+ [],
173
+ ];
174
+ }
175
+ return [
176
+ evo(model, {
177
+ maybeLastPointerType: () => Option.some(pointerType),
178
+ }),
179
+ [],
180
+ ];
181
+ },
182
+ ElapsedShowDelay: ({ version }) => {
183
+ if (version !== model.pendingShowVersion) {
184
+ return [model, []];
185
+ }
186
+ if (!model.isHovered) {
187
+ return [model, []];
188
+ }
189
+ return [evo(model, { isOpen: () => true }), []];
190
+ },
191
+ CompletedAnchorTooltip: () => [model, []],
192
+ }));
193
+ /** Processes a tooltip message and returns the next model, commands, and
194
+ * an optional OutMessage. `Shown`/`Hidden` fire only on `isOpen`
195
+ * transitions, so consumers don't get spurious events for messages that
196
+ * only update hover/focus/delay state without changing visibility. */
197
+ export const update = (model, message) => {
198
+ const [nextModel, commands] = computeUpdate(model, message);
199
+ const maybeOutMessage = !model.isOpen && nextModel.isOpen
200
+ ? Option.some(Shown())
201
+ : model.isOpen && !nextModel.isOpen
202
+ ? Option.some(Hidden())
203
+ : Option.none();
204
+ return [nextModel, commands, maybeOutMessage];
205
+ };
206
+ /** Reflects an externally-sourced hover show-delay onto the model without
207
+ * emitting an OutMessage. Use to mirror an external config value (a user
208
+ * preference, a restored setting) onto the tooltip. */
209
+ export const reflectShowDelay = Function.dual(2, (model, showDelay) => evo(model, { showDelay: () => Duration.fromInputUnsafe(showDelay) }));
210
+ /** Renders a headless tooltip with an anchored non-interactive panel.
211
+ * Shows on hover (after delay) or focus (from keyboard, touch, or pen;
212
+ * mouse-click focus is excluded); hides on leave, blur, Escape, or
213
+ * left-click of the trigger. */
214
+ export const view = defineView((model, viewInputs) => {
215
+ const h = html();
216
+ const { id, isOpen } = model;
217
+ const { anchor, toView, isDisabled } = viewInputs;
218
+ const handleTriggerKeyDown = (key) => M.value(key).pipe(M.when('Escape', () => OptionExt.when(isOpen, PressedEscape())), M.orElse(() => Option.none()));
219
+ const handleTriggerPointerDown = (pointerType, button) => Option.some(PressedPointerOnTrigger({ pointerType, button }));
220
+ const triggerAttributes = [
221
+ h.Id(`${id}-trigger`),
222
+ h.Type('button'),
223
+ h.AriaDescribedBy(`${id}-panel`),
224
+ ...(isOpen ? [h.DataAttribute('open', '')] : []),
225
+ ...(isDisabled
226
+ ? [h.AriaDisabled(true), h.DataAttribute('disabled', '')]
227
+ : [
228
+ h.OnMouseEnter(EnteredTrigger()),
229
+ h.OnMouseLeave(LeftTrigger()),
230
+ h.OnFocus(FocusedTrigger()),
231
+ h.OnBlur(BlurredTrigger()),
232
+ h.OnKeyDownPreventDefault(handleTriggerKeyDown),
233
+ h.OnPointerDown(handleTriggerPointerDown),
234
+ ]),
235
+ ];
236
+ const panelAttributes = [
237
+ h.Id(`${id}-panel`),
238
+ h.Role('tooltip'),
239
+ h.Style({
240
+ position: 'absolute',
241
+ margin: '0',
242
+ visibility: 'hidden',
243
+ pointerEvents: 'none',
244
+ }),
245
+ h.OnMount(AnchorTooltip({ buttonId: `${id}-trigger`, anchor })),
246
+ ...(isOpen ? [h.DataAttribute('open', '')] : []),
247
+ ];
248
+ return toView({
249
+ trigger: childAttributes(triggerAttributes),
250
+ panel: childAttributes(panelAttributes),
251
+ isVisible: isOpen,
252
+ });
253
+ });
@@ -0,0 +1,4 @@
1
+ export { init, update, view, reflectShowDelay, Model, Message, OutMessage, Shown, Hidden, EnteredTrigger, LeftTrigger, FocusedTrigger, BlurredTrigger, PressedEscape, PressedPointerOnTrigger, ElapsedShowDelay, ShowAfterDelay, CompletedAnchorTooltip, AnchorTooltip, } from './index.js';
2
+ export type { InitConfig, ViewInputs, RenderInfo } from './index.js';
3
+ export type { AnchorConfig } from '../anchor.js';
4
+ //# sourceMappingURL=public.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/tooltip/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,gBAAgB,EAChB,KAAK,EACL,OAAO,EACP,UAAU,EACV,KAAK,EACL,MAAM,EACN,cAAc,EACd,WAAW,EACX,cAAc,EACd,cAAc,EACd,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EAChB,cAAc,EACd,sBAAsB,EACtB,aAAa,GACd,MAAM,YAAY,CAAA;AAEnB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEpE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA"}
@@ -0,0 +1 @@
1
+ export { init, update, view, reflectShowDelay, Model, Message, OutMessage, Shown, Hidden, EnteredTrigger, LeftTrigger, FocusedTrigger, BlurredTrigger, PressedEscape, PressedPointerOnTrigger, ElapsedShowDelay, ShowAfterDelay, CompletedAnchorTooltip, AnchorTooltip, } from './index.js';
@@ -0,0 +1,4 @@
1
+ import { Option } from 'effect';
2
+ /** Finds the first enabled item whose search text starts with the query, searching forward from the active item and wrapping around. On a fresh search, starts after the active item; on a refinement, includes the active item. */
3
+ export declare const resolveTypeaheadMatch: <Item>(items: ReadonlyArray<Item>, query: string, maybeActiveItemIndex: Option.Option<number>, isDisabled: (index: number) => boolean, itemToSearchText: (item: Item, index: number) => string, isRefinement: boolean) => Option.Option<number>;
4
+ //# sourceMappingURL=typeahead.d.ts.map