foldkit 0.59.0 → 0.61.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 (80) hide show
  1. package/dist/calendar/arithmetic.d.ts +140 -0
  2. package/dist/calendar/arithmetic.d.ts.map +1 -0
  3. package/dist/calendar/arithmetic.js +169 -0
  4. package/dist/calendar/calendarDate.d.ts +162 -0
  5. package/dist/calendar/calendarDate.d.ts.map +1 -0
  6. package/dist/calendar/calendarDate.js +196 -0
  7. package/dist/calendar/comparison.d.ts +163 -0
  8. package/dist/calendar/comparison.d.ts.map +1 -0
  9. package/dist/calendar/comparison.js +134 -0
  10. package/dist/calendar/index.d.ts +7 -0
  11. package/dist/calendar/index.d.ts.map +1 -0
  12. package/dist/calendar/index.js +6 -0
  13. package/dist/calendar/info.d.ts +76 -0
  14. package/dist/calendar/info.d.ts.map +1 -0
  15. package/dist/calendar/info.js +125 -0
  16. package/dist/calendar/locale.d.ts +71 -0
  17. package/dist/calendar/locale.d.ts.map +1 -0
  18. package/dist/calendar/locale.js +171 -0
  19. package/dist/calendar/public.d.ts +2 -0
  20. package/dist/calendar/public.d.ts.map +1 -0
  21. package/dist/calendar/public.js +1 -0
  22. package/dist/calendar/today.d.ts +41 -0
  23. package/dist/calendar/today.d.ts.map +1 -0
  24. package/dist/calendar/today.js +33 -0
  25. package/dist/html/index.d.ts +3 -3
  26. package/dist/html/index.d.ts.map +1 -1
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +1 -0
  30. package/dist/test/apps/disabledButton.d.ts +2 -2
  31. package/dist/ui/calendar/index.d.ts +242 -0
  32. package/dist/ui/calendar/index.d.ts.map +1 -0
  33. package/dist/ui/calendar/index.js +515 -0
  34. package/dist/ui/calendar/public.d.ts +3 -0
  35. package/dist/ui/calendar/public.d.ts.map +1 -0
  36. package/dist/ui/calendar/public.js +1 -0
  37. package/dist/ui/combobox/multi.d.ts +7 -4
  38. package/dist/ui/combobox/multi.d.ts.map +1 -1
  39. package/dist/ui/combobox/multi.js +3 -1
  40. package/dist/ui/combobox/multiPublic.d.ts +1 -1
  41. package/dist/ui/combobox/multiPublic.d.ts.map +1 -1
  42. package/dist/ui/combobox/multiPublic.js +1 -1
  43. package/dist/ui/combobox/public.d.ts +1 -1
  44. package/dist/ui/combobox/public.d.ts.map +1 -1
  45. package/dist/ui/combobox/public.js +1 -1
  46. package/dist/ui/combobox/shared.d.ts +3 -3
  47. package/dist/ui/combobox/shared.js +3 -3
  48. package/dist/ui/combobox/single.d.ts +8 -4
  49. package/dist/ui/combobox/single.d.ts.map +1 -1
  50. package/dist/ui/combobox/single.js +4 -1
  51. package/dist/ui/dialog/index.d.ts +1 -1
  52. package/dist/ui/dialog/index.js +2 -2
  53. package/dist/ui/dragAndDrop/index.d.ts +1 -1
  54. package/dist/ui/index.d.ts +1 -0
  55. package/dist/ui/index.d.ts.map +1 -1
  56. package/dist/ui/index.js +1 -0
  57. package/dist/ui/listbox/multi.d.ts +7 -4
  58. package/dist/ui/listbox/multi.d.ts.map +1 -1
  59. package/dist/ui/listbox/multi.js +3 -1
  60. package/dist/ui/listbox/multiPublic.d.ts +1 -1
  61. package/dist/ui/listbox/multiPublic.d.ts.map +1 -1
  62. package/dist/ui/listbox/multiPublic.js +1 -1
  63. package/dist/ui/listbox/shared.d.ts +3 -3
  64. package/dist/ui/listbox/shared.js +2 -2
  65. package/dist/ui/listbox/single.d.ts +1 -1
  66. package/dist/ui/menu/index.d.ts +2 -2
  67. package/dist/ui/menu/index.js +2 -2
  68. package/dist/ui/popover/index.d.ts +2 -2
  69. package/dist/ui/popover/index.js +2 -2
  70. package/dist/ui/transition/index.d.ts +2 -2
  71. package/dist/ui/transition/index.d.ts.map +1 -1
  72. package/dist/ui/transition/index.js +2 -2
  73. package/dist/ui/transition/public.d.ts +1 -1
  74. package/dist/ui/transition/public.d.ts.map +1 -1
  75. package/dist/ui/transition/public.js +1 -1
  76. package/dist/ui/transition/schema.d.ts +3 -3
  77. package/dist/ui/transition/schema.d.ts.map +1 -1
  78. package/dist/ui/transition/schema.js +2 -2
  79. package/dist/ui/transition/update.js +1 -1
  80. package/package.json +9 -1
@@ -0,0 +1,515 @@
1
+ import { Array, Effect, Match as M, Option, Schema as S, pipe } from 'effect';
2
+ import * as Calendar from '../../calendar';
3
+ import * as Command from '../../command';
4
+ import { OptionExt } from '../../effectExtensions';
5
+ import { createLazy, html } from '../../html';
6
+ import { m } from '../../message';
7
+ import { evo } from '../../struct';
8
+ import * as Task from '../../task';
9
+ // MODEL
10
+ /** Schema for the calendar component's state. Tracks the visible month/year,
11
+ * the keyboard-focused and user-selected dates, and the configuration that
12
+ * governs navigation (locale, min/max, disabled days). */
13
+ export const Model = S.Struct({
14
+ id: S.String,
15
+ today: Calendar.CalendarDate,
16
+ viewYear: S.Int,
17
+ viewMonth: S.Int.pipe(S.between(1, 12)),
18
+ maybeFocusedDate: S.OptionFromSelf(Calendar.CalendarDate),
19
+ maybeSelectedDate: S.OptionFromSelf(Calendar.CalendarDate),
20
+ isGridFocused: S.Boolean,
21
+ locale: Calendar.LocaleConfig,
22
+ maybeMinDate: S.OptionFromSelf(Calendar.CalendarDate),
23
+ maybeMaxDate: S.OptionFromSelf(Calendar.CalendarDate),
24
+ disabledDaysOfWeek: S.Array(Calendar.DayOfWeek),
25
+ disabledDates: S.Array(Calendar.CalendarDate),
26
+ });
27
+ // MESSAGE
28
+ /** Sent when the user clicks a day cell in the grid. */
29
+ export const ClickedDay = m('ClickedDay', { date: Calendar.CalendarDate });
30
+ /** Sent when the user presses a key on the grid container. The update maps
31
+ * the key to a navigation or selection action. */
32
+ export const PressedKeyOnGrid = m('PressedKeyOnGrid', {
33
+ key: S.String,
34
+ isShift: S.Boolean,
35
+ });
36
+ /** Sent when the user clicks the previous-month navigation button. */
37
+ export const ClickedPreviousMonthButton = m('ClickedPreviousMonthButton');
38
+ /** Sent when the user clicks the next-month navigation button. */
39
+ export const ClickedNextMonthButton = m('ClickedNextMonthButton');
40
+ /** Sent when the user picks a month from the month dropdown. */
41
+ export const SelectedMonthFromDropdown = m('SelectedMonthFromDropdown', {
42
+ month: S.Int,
43
+ });
44
+ /** Sent when the user picks a year from the year dropdown. */
45
+ export const SelectedYearFromDropdown = m('SelectedYearFromDropdown', {
46
+ year: S.Int,
47
+ });
48
+ /** Sent when the grid container receives DOM focus. */
49
+ export const FocusedGrid = m('FocusedGrid');
50
+ /** Sent when the grid container loses DOM focus. */
51
+ export const BlurredGrid = m('BlurredGrid');
52
+ /** Sent when a long-lived session's "today" reference should be refreshed. */
53
+ export const RefreshedToday = m('RefreshedToday', {
54
+ today: Calendar.CalendarDate,
55
+ });
56
+ /** Sent when a FocusGrid command completes. */
57
+ export const CompletedFocusGrid = m('CompletedFocusGrid');
58
+ /** Union of all messages the calendar component can produce. */
59
+ export const Message = S.Union(ClickedDay, PressedKeyOnGrid, ClickedPreviousMonthButton, ClickedNextMonthButton, SelectedMonthFromDropdown, SelectedYearFromDropdown, FocusedGrid, BlurredGrid, RefreshedToday, CompletedFocusGrid);
60
+ // OUT MESSAGE
61
+ /** Emitted when the visible month changes due to navigation. Consumers of an
62
+ * inline calendar may use this to load month-scoped data (holidays, events).
63
+ *
64
+ * Date selection does NOT use OutMessage — consumers subscribe via the
65
+ * `onSelectedDate` callback in `ViewConfig`, matching the Listbox/Popover
66
+ * controlled-component pattern. Use `Calendar.selectDate(model, date)` to
67
+ * write back when handling the callback. */
68
+ export const ChangedViewMonth = m('ChangedViewMonth', {
69
+ year: S.Int,
70
+ month: S.Int,
71
+ });
72
+ /** The calendar's OutMessage. Only one variant — `ChangedViewMonth` — which
73
+ * fires when navigation shifts the visible month. Date selection goes through
74
+ * the `onSelectedDate` ViewConfig callback, not OutMessage. */
75
+ export const OutMessage = ChangedViewMonth;
76
+ /** Creates an initial calendar model. The view month defaults to the month
77
+ * of the initial selected date, or today if no date is pre-selected. */
78
+ export const init = (config) => {
79
+ const initialFocus = Option.getOrElse(config.maybeInitialSelectedDate ?? Option.none(), () => config.today);
80
+ return {
81
+ id: config.id,
82
+ today: config.today,
83
+ viewYear: initialFocus.year,
84
+ viewMonth: initialFocus.month,
85
+ maybeFocusedDate: Option.some(initialFocus),
86
+ maybeSelectedDate: config.maybeInitialSelectedDate ?? Option.none(),
87
+ isGridFocused: false,
88
+ locale: config.locale ?? Calendar.defaultEnglishLocale,
89
+ maybeMinDate: config.maybeMinDate ?? Option.none(),
90
+ maybeMaxDate: config.maybeMaxDate ?? Option.none(),
91
+ disabledDaysOfWeek: config.disabledDaysOfWeek ?? [],
92
+ disabledDates: config.disabledDates ?? [],
93
+ };
94
+ };
95
+ const withUpdateReturn = M.withReturnType();
96
+ const gridId = (modelId) => `${modelId}-grid`;
97
+ const gridSelector = (modelId) => `#${gridId(modelId)}`;
98
+ /** Focuses the calendar grid container. */
99
+ export const FocusGrid = Command.define('FocusGrid', CompletedFocusGrid);
100
+ /** Builds a command that focuses the calendar grid container. Parent
101
+ * components like DatePicker dispatch this after opening to hand focus to
102
+ * the grid's keyboard layer. */
103
+ export const focusGrid = (modelId) => FocusGrid(Task.focus(gridSelector(modelId)).pipe(Effect.ignore, Effect.as(CompletedFocusGrid())));
104
+ /** Programmatically selects a date on the calendar, committing it as the
105
+ * chosen value and moving the cursor onto it. Use this in controlled-mode
106
+ * handlers (when the view's `onSelectedDate` callback is provided) to write
107
+ * the selection back to the calendar's internal state.
108
+ *
109
+ * Equivalent to dispatching `ClickedDay({ date })` through `update`. */
110
+ export const selectDate = (model, date) => update(model, ClickedDay({ date }));
111
+ const DAY_SKIP_CAP = 31;
112
+ const MONTH_SKIP_CAP = 12;
113
+ const isDateDisabled = (model, date) => {
114
+ const belowMin = Option.exists(model.maybeMinDate, min => Calendar.isBefore(date, min));
115
+ if (belowMin) {
116
+ return true;
117
+ }
118
+ const aboveMax = Option.exists(model.maybeMaxDate, max => Calendar.isAfter(date, max));
119
+ if (aboveMax) {
120
+ return true;
121
+ }
122
+ if (model.disabledDaysOfWeek.includes(Calendar.dayOfWeek(date))) {
123
+ return true;
124
+ }
125
+ if (model.disabledDates.some(Calendar.isEqual(date))) {
126
+ return true;
127
+ }
128
+ return false;
129
+ };
130
+ /** Walks from `start` in `direction`, returning the first non-disabled date
131
+ * within `cap` steps. Falls back to `start` if every candidate is disabled. */
132
+ const skipDisabled = (model, start, direction, cap) => pipe(cap, Array.makeBy(step => Calendar.addDays(start, step * direction)), Array.findFirst(date => !isDateDisabled(model, date)), Option.getOrElse(() => start));
133
+ const clampToRange = (model, candidate) => {
134
+ const afterMin = Option.match(model.maybeMinDate, {
135
+ onNone: () => candidate,
136
+ onSome: min => Calendar.max(candidate, min),
137
+ });
138
+ return Option.match(model.maybeMaxDate, {
139
+ onNone: () => afterMin,
140
+ onSome: max => Calendar.min(afterMin, max),
141
+ });
142
+ };
143
+ /** Resolves a navigation key press to the next focused date candidate,
144
+ * along with the direction and search cap for disabled-date skipping. */
145
+ const resolveNavigationKey = (key, isShift, focused, firstDayOfWeek) => M.value(key).pipe(M.withReturnType(), M.when('ArrowLeft', () => [
146
+ Calendar.addDays(focused, -1),
147
+ -1,
148
+ DAY_SKIP_CAP,
149
+ ]), M.when('ArrowRight', () => [Calendar.addDays(focused, 1), 1, DAY_SKIP_CAP]), M.when('ArrowUp', () => [Calendar.addDays(focused, -7), -1, DAY_SKIP_CAP]), M.when('ArrowDown', () => [Calendar.addDays(focused, 7), 1, DAY_SKIP_CAP]), M.when('Home', () => [
150
+ Calendar.startOfWeek(focused, firstDayOfWeek),
151
+ -1,
152
+ DAY_SKIP_CAP,
153
+ ]), M.when('End', () => [
154
+ Calendar.endOfWeek(focused, firstDayOfWeek),
155
+ 1,
156
+ DAY_SKIP_CAP,
157
+ ]), M.when('PageUp', () => [
158
+ isShift
159
+ ? Calendar.addYears(focused, -1)
160
+ : Calendar.addMonths(focused, -1),
161
+ -1,
162
+ MONTH_SKIP_CAP,
163
+ ]), M.when('PageDown', () => [
164
+ isShift ? Calendar.addYears(focused, 1) : Calendar.addMonths(focused, 1),
165
+ 1,
166
+ MONTH_SKIP_CAP,
167
+ ]), M.option);
168
+ const isCommitKey = (key) => key === 'Enter' || key === ' ';
169
+ const currentOrFallbackFocus = (model) => Option.getOrElse(model.maybeFocusedDate, () => Calendar.make(model.viewYear, model.viewMonth, 1));
170
+ /** Applies a date selection to the model: commits the selection, moves the
171
+ * cursor onto the date, and syncs the view month if the selection crosses a
172
+ * month boundary. Emits `ChangedViewMonth` only when the commit crosses a
173
+ * month boundary. */
174
+ const commitSelection = (model, date) => {
175
+ const crossedMonth = date.year !== model.viewYear || date.month !== model.viewMonth;
176
+ const nextModel = evo(model, {
177
+ maybeSelectedDate: () => Option.some(date),
178
+ maybeFocusedDate: () => Option.some(date),
179
+ viewYear: () => date.year,
180
+ viewMonth: () => date.month,
181
+ });
182
+ const maybeOutMessage = OptionExt.when(crossedMonth, ChangedViewMonth({ year: date.year, month: date.month }));
183
+ return [nextModel, maybeOutMessage];
184
+ };
185
+ /** Applies a focus move to the model, clamping to the allowed range and
186
+ * skipping disabled dates. Emits `ChangedViewMonth` if the move crossed a
187
+ * month boundary. */
188
+ const applyFocusMove = (model, candidate, direction, cap) => {
189
+ const clamped = clampToRange(model, candidate);
190
+ const nextFocus = skipDisabled(model, clamped, direction, cap);
191
+ const crossedMonth = nextFocus.year !== model.viewYear || nextFocus.month !== model.viewMonth;
192
+ const nextModel = evo(model, {
193
+ maybeFocusedDate: () => Option.some(nextFocus),
194
+ viewYear: () => nextFocus.year,
195
+ viewMonth: () => nextFocus.month,
196
+ });
197
+ const maybeOutMessage = OptionExt.when(crossedMonth, ChangedViewMonth({ year: nextFocus.year, month: nextFocus.month }));
198
+ return [nextModel, maybeOutMessage];
199
+ };
200
+ /** Computes the focused-date cursor for a view-month change. Preserves the
201
+ * current day-of-month (clamping to the new month's length when needed),
202
+ * then runs the candidate through min/max clamping and disabled-date skipping
203
+ * so the cursor always lands on a real, navigable cell. */
204
+ const moveFocusForViewChange = (model, year, month, direction) => {
205
+ const currentDay = Option.match(model.maybeFocusedDate, {
206
+ onNone: () => 1,
207
+ onSome: focused => focused.day,
208
+ });
209
+ const dayInNewMonth = Math.min(currentDay, Calendar.daysInMonth(year, month));
210
+ const candidate = Calendar.make(year, month, dayInNewMonth);
211
+ const clamped = clampToRange(model, candidate);
212
+ return skipDisabled(model, clamped, direction, DAY_SKIP_CAP);
213
+ };
214
+ const applyViewMonthChange = (model, year, month, direction) => {
215
+ if (year === model.viewYear && month === model.viewMonth) {
216
+ return [model, [], Option.none()];
217
+ }
218
+ const nextFocus = moveFocusForViewChange(model, year, month, direction);
219
+ const nextModel = evo(model, {
220
+ viewYear: () => year,
221
+ viewMonth: () => month,
222
+ maybeFocusedDate: () => Option.some(nextFocus),
223
+ });
224
+ return [nextModel, [], Option.some(ChangedViewMonth({ year, month }))];
225
+ };
226
+ /** Direction the user moved when jumping to a new view month via dropdown.
227
+ * Used by `skipDisabled` so a forward jump skips forward through disabled
228
+ * dates and a backward jump skips backward. */
229
+ const dropdownDirection = (model, year, month) => {
230
+ const next = Calendar.make(year, month, 1);
231
+ const current = Calendar.make(model.viewYear, model.viewMonth, 1);
232
+ return Calendar.isAfter(next, current) ? 1 : -1;
233
+ };
234
+ /** Processes a calendar message and returns the next model, commands, and
235
+ * optional OutMessage. */
236
+ export const update = (model, message) => M.value(message).pipe(withUpdateReturn, M.tagsExhaustive({
237
+ ClickedDay: ({ date }) => {
238
+ if (isDateDisabled(model, date)) {
239
+ return [model, [], Option.none()];
240
+ }
241
+ const [nextModel, maybeOutMessage] = commitSelection(model, date);
242
+ return [nextModel, [], maybeOutMessage];
243
+ },
244
+ PressedKeyOnGrid: ({ key, isShift }) => {
245
+ const focused = currentOrFallbackFocus(model);
246
+ if (isCommitKey(key)) {
247
+ if (isDateDisabled(model, focused)) {
248
+ return [model, [], Option.none()];
249
+ }
250
+ const [nextModel, maybeOutMessage] = commitSelection(model, focused);
251
+ return [nextModel, [], maybeOutMessage];
252
+ }
253
+ return Option.match(resolveNavigationKey(key, isShift, focused, model.locale.firstDayOfWeek), {
254
+ onNone: () => [model, [], Option.none()],
255
+ onSome: ([candidate, direction, cap]) => {
256
+ const [nextModel, maybeOutMessage] = applyFocusMove(model, candidate, direction, cap);
257
+ return [nextModel, [], maybeOutMessage];
258
+ },
259
+ });
260
+ },
261
+ ClickedPreviousMonthButton: () => {
262
+ const next = Calendar.subtractMonths(Calendar.make(model.viewYear, model.viewMonth, 1), 1);
263
+ return applyViewMonthChange(model, next.year, next.month, -1);
264
+ },
265
+ ClickedNextMonthButton: () => {
266
+ const next = Calendar.addMonths(Calendar.make(model.viewYear, model.viewMonth, 1), 1);
267
+ return applyViewMonthChange(model, next.year, next.month, 1);
268
+ },
269
+ SelectedMonthFromDropdown: ({ month }) => applyViewMonthChange(model, model.viewYear, month, dropdownDirection(model, model.viewYear, month)),
270
+ SelectedYearFromDropdown: ({ year }) => applyViewMonthChange(model, year, model.viewMonth, dropdownDirection(model, year, model.viewMonth)),
271
+ FocusedGrid: () => [
272
+ evo(model, { isGridFocused: () => true }),
273
+ [],
274
+ Option.none(),
275
+ ],
276
+ BlurredGrid: () => [
277
+ evo(model, { isGridFocused: () => false }),
278
+ [],
279
+ Option.none(),
280
+ ],
281
+ RefreshedToday: ({ today }) => [
282
+ evo(model, { today: () => today }),
283
+ [],
284
+ Option.none(),
285
+ ],
286
+ CompletedFocusGrid: () => [model, [], Option.none()],
287
+ }));
288
+ // VIEW
289
+ const headingId = (modelId) => `${modelId}-heading`;
290
+ const cellId = (modelId, date) => `${modelId}-cell-${date.year}-${date.month}-${date.day}`;
291
+ const DAY_NAMES_SUNDAY_FIRST = [
292
+ 'Sunday',
293
+ 'Monday',
294
+ 'Tuesday',
295
+ 'Wednesday',
296
+ 'Thursday',
297
+ 'Friday',
298
+ 'Saturday',
299
+ ];
300
+ const DAY_OF_WEEK_INDEX = {
301
+ Sunday: 0,
302
+ Monday: 1,
303
+ Tuesday: 2,
304
+ Wednesday: 3,
305
+ Thursday: 4,
306
+ Friday: 5,
307
+ Saturday: 6,
308
+ };
309
+ /** Rotates the Sunday-first day-name array so that `firstDayOfWeek` becomes
310
+ * the first entry. Used to build column headers in locale-appropriate order. */
311
+ const rotateDayNames = (names, firstDayOfWeek) => {
312
+ const [front, back] = Array.splitAt(names, DAY_OF_WEEK_INDEX[firstDayOfWeek]);
313
+ return [...back, ...front];
314
+ };
315
+ const WEEKS_IN_GRID = 6;
316
+ const DAYS_IN_WEEK = 7;
317
+ /** Builds the 6×7 grid of dates that a calendar view renders for a given
318
+ * month. The grid always has 6 rows to keep height stable across months.
319
+ * Returns the 2D grid alongside the starting date (top-left cell) so
320
+ * callers can derive per-week positions without recomputing. */
321
+ const buildGrid = (viewYear, viewMonth, firstDayOfWeek) => {
322
+ const firstOfMonth = Calendar.make(viewYear, viewMonth, 1);
323
+ const gridStart = Calendar.startOfWeek(firstOfMonth, firstDayOfWeek);
324
+ const weeks = Array.makeBy(WEEKS_IN_GRID, weekIndex => Array.makeBy(DAYS_IN_WEEK, dayIndex => Calendar.addDays(gridStart, weekIndex * DAYS_IN_WEEK + dayIndex)));
325
+ return { gridStart, weeks };
326
+ };
327
+ const YEAR_RANGE_LOOKAHEAD = 10;
328
+ const YEAR_RANGE_LOOKBEHIND = 100;
329
+ /** Computes the inclusive year range the year dropdown should expose,
330
+ * derived from min/max constraints if set, else a sensible default window
331
+ * around today. */
332
+ const resolveYearRange = (model) => {
333
+ const defaultStart = model.today.year - YEAR_RANGE_LOOKBEHIND;
334
+ const defaultEnd = model.today.year + YEAR_RANGE_LOOKAHEAD;
335
+ const start = Option.match(model.maybeMinDate, {
336
+ onNone: () => defaultStart,
337
+ onSome: min => min.year,
338
+ });
339
+ const end = Option.match(model.maybeMaxDate, {
340
+ onNone: () => defaultEnd,
341
+ onSome: max => max.year,
342
+ });
343
+ return [start, end];
344
+ };
345
+ const NAV_KEYS = new Set([
346
+ 'ArrowLeft',
347
+ 'ArrowRight',
348
+ 'ArrowUp',
349
+ 'ArrowDown',
350
+ 'Home',
351
+ 'End',
352
+ 'PageUp',
353
+ 'PageDown',
354
+ 'Enter',
355
+ ' ',
356
+ ]);
357
+ /** Renders an accessible calendar grid. Builds ARIA attribute groups (grid,
358
+ * row, gridcell, column header) plus the derived month grid, then delegates
359
+ * layout to the consumer's `toView` callback. */
360
+ export const view = (config) => {
361
+ const { AriaActiveDescendant, AriaColcount, AriaColindex, AriaDisabled, AriaLabel, AriaRowcount, AriaRowindex, AriaSelected, DataAttribute, Id, OnBlur, OnChange, OnClick, OnFocus, OnKeyDownPreventDefault, Role, Tabindex, Type, } = html();
362
+ const { model, toParentMessage, toView, onSelectedDate } = config;
363
+ const { id, viewYear, viewMonth, maybeFocusedDate, maybeSelectedDate, today, locale, isGridFocused, } = model;
364
+ /** Returns the parent message to dispatch when the user commits a date. In
365
+ * controlled mode (when `onSelectedDate` is provided), dispatches the
366
+ * callback directly. In uncontrolled mode, routes through the internal
367
+ * `ClickedDay` message so the calendar's own update manages selection. */
368
+ const dispatchSelectedDate = (date) => onSelectedDate !== undefined
369
+ ? onSelectedDate(date)
370
+ : toParentMessage(ClickedDay({ date }));
371
+ const previousMonthLabel = config.previousMonthLabel ?? 'Previous month';
372
+ const nextMonthLabel = config.nextMonthLabel ?? 'Next month';
373
+ const monthSelectLabel = config.monthSelectLabel ?? 'Select month';
374
+ const yearSelectLabel = config.yearSelectLabel ?? 'Select year';
375
+ const headingText = `${locale.monthNames[viewMonth - 1]} ${viewYear}`;
376
+ const monthOptions = locale.monthNames.map((label, index) => ({
377
+ value: index + 1,
378
+ label,
379
+ }));
380
+ const [yearRangeStart, yearRangeEnd] = resolveYearRange(model);
381
+ const yearOptions = Array.makeBy(Math.max(0, yearRangeEnd - yearRangeStart + 1), index => yearRangeStart + index);
382
+ const rotatedDayNames = rotateDayNames(DAY_NAMES_SUNDAY_FIRST, locale.firstDayOfWeek);
383
+ const rotatedShortDayNames = rotateDayNames(locale.shortDayNames, locale.firstDayOfWeek);
384
+ const { gridStart, weeks: weeksDates } = buildGrid(viewYear, viewMonth, locale.firstDayOfWeek);
385
+ const rootAttributes = [Id(id)];
386
+ const previousMonthButtonAttributes = [
387
+ Type('button'),
388
+ AriaLabel(previousMonthLabel),
389
+ OnClick(toParentMessage(ClickedPreviousMonthButton())),
390
+ ];
391
+ const nextMonthButtonAttributes = [
392
+ Type('button'),
393
+ AriaLabel(nextMonthLabel),
394
+ OnClick(toParentMessage(ClickedNextMonthButton())),
395
+ ];
396
+ const monthSelectAttributes = [
397
+ AriaLabel(monthSelectLabel),
398
+ OnChange(value => toParentMessage(SelectedMonthFromDropdown({ month: Number(value) }))),
399
+ ];
400
+ const yearSelectAttributes = [
401
+ AriaLabel(yearSelectLabel),
402
+ OnChange(value => toParentMessage(SelectedYearFromDropdown({ year: Number(value) }))),
403
+ ];
404
+ const handleKeyDown = (key, modifiers) => {
405
+ if (!NAV_KEYS.has(key)) {
406
+ return Option.none();
407
+ }
408
+ if (isCommitKey(key) && onSelectedDate !== undefined) {
409
+ return pipe(maybeFocusedDate, Option.filter(date => !isDateDisabled(model, date)), Option.map(onSelectedDate));
410
+ }
411
+ return Option.some(toParentMessage(PressedKeyOnGrid({ key, isShift: modifiers.shiftKey })));
412
+ };
413
+ const activeDescendantAttributes = pipe(maybeFocusedDate, Option.map(date => AriaActiveDescendant(cellId(id, date))), Option.toArray);
414
+ const gridAttributes = [
415
+ Id(gridId(id)),
416
+ Role('grid'),
417
+ AriaLabel(`Calendar, ${headingText}`),
418
+ AriaRowcount(WEEKS_IN_GRID + 1),
419
+ AriaColcount(DAYS_IN_WEEK),
420
+ Tabindex(0),
421
+ OnFocus(toParentMessage(FocusedGrid())),
422
+ OnBlur(toParentMessage(BlurredGrid())),
423
+ OnKeyDownPreventDefault(handleKeyDown),
424
+ ...activeDescendantAttributes,
425
+ ];
426
+ const headerRowAttributes = [
427
+ Role('row'),
428
+ AriaRowindex(1),
429
+ ];
430
+ const columnHeaders = Array.zipWith(rotatedShortDayNames, rotatedDayNames, (name, fullName) => ({
431
+ name,
432
+ fullName,
433
+ })).map(({ name, fullName }, columnIndex) => ({
434
+ name,
435
+ attributes: [
436
+ Role('columnheader'),
437
+ AriaLabel(fullName),
438
+ AriaColindex(columnIndex + 1),
439
+ ],
440
+ }));
441
+ const buildDayCell = (date, columnIndex) => {
442
+ const isSelected = Option.exists(maybeSelectedDate, Calendar.isEqual(date));
443
+ const isFocused = Option.exists(maybeFocusedDate, Calendar.isEqual(date));
444
+ const isToday = Calendar.isEqual(today, date);
445
+ const isInViewMonth = date.month === viewMonth && date.year === viewYear;
446
+ const isDisabled = isDateDisabled(model, date);
447
+ const stateDataAttributes = Array.getSomes([
448
+ OptionExt.when(isToday, DataAttribute('today', '')),
449
+ OptionExt.when(isSelected, DataAttribute('selected', '')),
450
+ OptionExt.when(isFocused && isGridFocused, DataAttribute('focused', '')),
451
+ OptionExt.when(!isInViewMonth, DataAttribute('outside-month', '')),
452
+ OptionExt.when(isDisabled, DataAttribute('disabled', '')),
453
+ ]);
454
+ const cellAttributes = [
455
+ Id(cellId(id, date)),
456
+ Role('gridcell'),
457
+ AriaSelected(isSelected),
458
+ AriaColindex(columnIndex + 1),
459
+ ...stateDataAttributes,
460
+ ];
461
+ const buttonAttributes = [
462
+ Type('button'),
463
+ Tabindex(-1),
464
+ AriaLabel(Calendar.formatAriaLabel(date, locale)),
465
+ AriaDisabled(isDisabled),
466
+ ...(isDisabled ? [] : [OnClick(dispatchSelectedDate(date))]),
467
+ ];
468
+ return {
469
+ date,
470
+ label: String(date.day),
471
+ cellAttributes,
472
+ buttonAttributes,
473
+ isSelected,
474
+ isFocused: isFocused && isGridFocused,
475
+ isToday,
476
+ isInViewMonth,
477
+ isDisabled,
478
+ };
479
+ };
480
+ const weeks = weeksDates.map((weekDates, weekIndex) => {
481
+ const weekStart = Calendar.addDays(gridStart, weekIndex * DAYS_IN_WEEK);
482
+ return {
483
+ attributes: [
484
+ Role('row'),
485
+ AriaRowindex(weekIndex + 2),
486
+ AriaLabel(`Week of ${Calendar.formatLong(weekStart, locale)}`),
487
+ ],
488
+ cells: weekDates.map(buildDayCell),
489
+ };
490
+ });
491
+ return toView({
492
+ root: rootAttributes,
493
+ previousMonthButton: previousMonthButtonAttributes,
494
+ nextMonthButton: nextMonthButtonAttributes,
495
+ heading: { id: headingId(id), text: headingText },
496
+ monthSelect: monthSelectAttributes,
497
+ monthOptions,
498
+ yearSelect: yearSelectAttributes,
499
+ yearOptions,
500
+ grid: gridAttributes,
501
+ headerRow: headerRowAttributes,
502
+ columnHeaders,
503
+ weeks,
504
+ });
505
+ };
506
+ /** Creates a memoized calendar view. Static config is captured in a closure;
507
+ * only `model` and `toParentMessage` are compared per render via `createLazy`. */
508
+ export const lazy = (staticConfig) => {
509
+ const lazyView = createLazy();
510
+ return (model, toParentMessage) => lazyView((currentModel, currentToMessage) => view({
511
+ ...staticConfig,
512
+ model: currentModel,
513
+ toParentMessage: currentToMessage,
514
+ }), [model, toParentMessage]);
515
+ };
@@ -0,0 +1,3 @@
1
+ export { init, update, view, lazy, focusGrid, selectDate, Model, Message, OutMessage, ChangedViewMonth, ClickedDay, PressedKeyOnGrid, ClickedPreviousMonthButton, ClickedNextMonthButton, SelectedMonthFromDropdown, SelectedYearFromDropdown, FocusedGrid, BlurredGrid, RefreshedToday, CompletedFocusGrid, FocusGrid, } from './index';
2
+ export type { InitConfig, ViewConfig, CalendarAttributes, DayCell, ColumnHeader, Week, } from './index';
3
+ //# sourceMappingURL=public.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/calendar/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,UAAU,EACV,KAAK,EACL,OAAO,EACP,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,sBAAsB,EACtB,yBAAyB,EACzB,wBAAwB,EACxB,WAAW,EACX,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,SAAS,GACV,MAAM,SAAS,CAAA;AAEhB,YAAY,EACV,UAAU,EACV,UAAU,EACV,kBAAkB,EAClB,OAAO,EACP,YAAY,EACZ,IAAI,GACL,MAAM,SAAS,CAAA"}
@@ -0,0 +1 @@
1
+ export { init, update, view, lazy, focusGrid, selectDate, Model, Message, OutMessage, ChangedViewMonth, ClickedDay, PressedKeyOnGrid, ClickedPreviousMonthButton, ClickedNextMonthButton, SelectedMonthFromDropdown, SelectedYearFromDropdown, FocusedGrid, BlurredGrid, RefreshedToday, CompletedFocusGrid, FocusGrid, } from './index';
@@ -1,6 +1,7 @@
1
1
  import { Schema as S } from 'effect';
2
+ import type * as Command from '../../command';
2
3
  import { type Html } from '../../html';
3
- import { type BaseInitConfig, type BaseViewConfig } from './shared';
4
+ import { type BaseInitConfig, type BaseViewConfig, type Message, SelectedItem } from './shared';
4
5
  /** Schema for the multi-select combobox component's state, tracking open/closed status, active item, input value, and selected items. */
5
6
  export declare const Model: S.extend<S.Struct<{
6
7
  id: typeof S.String;
@@ -55,7 +56,7 @@ export declare const update: (model: {
55
56
  readonly inputValue: string;
56
57
  } & {
57
58
  readonly selectedItems: readonly string[];
58
- }, message: import("./shared").Message) => readonly [{
59
+ }, message: Message) => readonly [{
59
60
  readonly id: string;
60
61
  readonly isOpen: boolean;
61
62
  readonly isAnimated: boolean;
@@ -127,7 +128,7 @@ export declare const update: (model: {
127
128
  readonly message: {
128
129
  readonly _tag: "Showed";
129
130
  } | {
130
- readonly _tag: "Hidden";
131
+ readonly _tag: "Hid";
131
132
  } | {
132
133
  readonly _tag: "AdvancedTransitionFrame";
133
134
  } | {
@@ -140,6 +141,8 @@ export declare const update: (model: {
140
141
  readonly _tag: "PressedToggleButton";
141
142
  }, never, never>;
142
143
  }>[]];
144
+ /** Programmatically toggles an item in the multi-select combobox. Use this in domain-event handlers when the combobox uses `onSelectedItem`. */
145
+ export declare const selectItem: (model: Model, item: string) => readonly [Model, ReadonlyArray<Command.Command<Message>>];
143
146
  /** Configuration for rendering a multi-select combobox with `view`. */
144
147
  export type ViewConfig<Message, Item extends string> = BaseViewConfig<Message, Item, Model>;
145
148
  /** Renders a headless multi-select combobox with keyboard navigation, selection tracking, and aria-activedescendant focus management. */
@@ -167,7 +170,7 @@ export declare const view: <Message, Item extends string>(config: Readonly<{
167
170
  } & {
168
171
  readonly selectedItems: readonly string[];
169
172
  };
170
- toParentMessage: (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) => Message;
173
+ toParentMessage: (message: import("./shared").Opened | import("./shared").Closed | import("./shared").ClosedByTab | import("./shared").ActivatedItem | import("./shared").DeactivatedItem | SelectedItem | import("./shared").MovedPointerOverItem | import("./shared").RequestedItemClick | import("./shared").UpdatedInputValue | import("./shared").PressedToggleButton) => Message;
171
174
  onSelectedItem?: (value: string) => Message;
172
175
  items: readonly Item[];
173
176
  itemToConfig: (item: Item, context: Readonly<{
@@ -1 +1 @@
1
- {"version":3,"file":"multi.d.ts","sourceRoot":"","sources":["../../../src/ui/combobox/multi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAE3C,OAAO,EAAE,KAAK,IAAI,EAAc,MAAM,YAAY,CAAA;AAElD,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,cAAc,EAKpB,MAAM,UAAU,CAAA;AAIjB,yIAAyI;AACzI,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;GAEjB,CAAA;AAED,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,8RAA8R;AAC9R,MAAM,MAAM,UAAU,GAAG,cAAc,GACrC,QAAQ,CAAC;IACP,aAAa,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACtC,CAAC,CAAA;AAEJ,2IAA2I;AAC3I,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAGxC,CAAA;AAcF,yJAAyJ;AACzJ,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAwBjB,CAAA;AAIF,uEAAuE;AACvE,MAAM,MAAM,UAAU,CAAC,OAAO,EAAE,IAAI,SAAS,MAAM,IAAI,cAAc,CACnE,OAAO,EACP,IAAI,EACJ,KAAK,CACN,CAAA;AAED,yIAAyI;AACzI,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAIf,CAAA;AAEF;mFACmF;AACnF,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,IAAI,SAAS,MAAM,EAC/C,cAAc,IAAI,CAChB,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,EACzB,OAAO,GAAG,iBAAiB,GAAG,gBAAgB,CAC/C,KACA,CAAC,CACF,KAAK,EAAE,KAAK,EACZ,eAAe,EAAE,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,iBAAiB,CAAC,KACrE,IAAI,CAoBR,CAAA"}
1
+ {"version":3,"file":"multi.d.ts","sourceRoot":"","sources":["../../../src/ui/combobox/multi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAE3C,OAAO,KAAK,KAAK,OAAO,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,KAAK,IAAI,EAAc,MAAM,YAAY,CAAA;AAElD,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,cAAc,EACnB,KAAK,OAAO,EACZ,YAAY,EAKb,MAAM,UAAU,CAAA;AAIjB,yIAAyI;AACzI,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;GAEjB,CAAA;AAED,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,8RAA8R;AAC9R,MAAM,MAAM,UAAU,GAAG,cAAc,GACrC,QAAQ,CAAC;IACP,aAAa,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACtC,CAAC,CAAA;AAEJ,2IAA2I;AAC3I,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAGxC,CAAA;AAcF,yJAAyJ;AACzJ,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAwBjB,CAAA;AAEF,gJAAgJ;AAChJ,eAAO,MAAM,UAAU,GACrB,OAAO,KAAK,EACZ,MAAM,MAAM,KACX,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CACD,CAAA;AAI1D,uEAAuE;AACvE,MAAM,MAAM,UAAU,CAAC,OAAO,EAAE,IAAI,SAAS,MAAM,IAAI,cAAc,CACnE,OAAO,EACP,IAAI,EACJ,KAAK,CACN,CAAA;AAED,yIAAyI;AACzI,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAIf,CAAA;AAEF;mFACmF;AACnF,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,IAAI,SAAS,MAAM,EAC/C,cAAc,IAAI,CAChB,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,EACzB,OAAO,GAAG,iBAAiB,GAAG,gBAAgB,CAC/C,KACA,CAAC,CACF,KAAK,EAAE,KAAK,EACZ,eAAe,EAAE,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,iBAAiB,CAAC,KACrE,IAAI,CAoBR,CAAA"}
@@ -1,7 +1,7 @@
1
1
  import { Array, Schema as S } from 'effect';
2
2
  import { createLazy } from '../../html';
3
3
  import { evo } from '../../struct';
4
- import { BaseModel, baseInit, closedBaseModel, makeUpdate, makeView, } from './shared';
4
+ import { BaseModel, SelectedItem, baseInit, closedBaseModel, makeUpdate, makeView, } from './shared';
5
5
  // MODEL
6
6
  /** Schema for the multi-select combobox component's state, tracking open/closed status, active item, input value, and selected items. */
7
7
  export const Model = BaseModel.pipe(S.extend(S.Struct({ selectedItems: S.Array(S.String) })));
@@ -36,6 +36,8 @@ export const update = makeUpdate({
36
36
  selectedItems: () => toggleItem(model.selectedItems, item),
37
37
  }),
38
38
  });
39
+ /** Programmatically toggles an item in the multi-select combobox. Use this in domain-event handlers when the combobox uses `onSelectedItem`. */
40
+ export const selectItem = (model, item) => update(model, SelectedItem({ item, displayText: item }));
39
41
  /** Renders a headless multi-select combobox with keyboard navigation, selection tracking, and aria-activedescendant focus management. */
40
42
  export const view = makeView({
41
43
  isItemSelected: (model, itemValue) => Array.contains(model.selectedItems, itemValue),
@@ -1,3 +1,3 @@
1
- export { init, update, view, lazy, Model } from './multi';
1
+ export { init, update, selectItem, view, lazy, Model } from './multi';
2
2
  export type { InitConfig, ViewConfig } from './multi';
3
3
  //# sourceMappingURL=multiPublic.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"multiPublic.d.ts","sourceRoot":"","sources":["../../../src/ui/combobox/multiPublic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AACzD,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"multiPublic.d.ts","sourceRoot":"","sources":["../../../src/ui/combobox/multiPublic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AACrE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA"}
@@ -1 +1 @@
1
- export { init, update, view, lazy, Model } from './multi';
1
+ export { init, update, selectItem, view, lazy, Model } from './multi';
@@ -1,4 +1,4 @@
1
- export { init, update, view, lazy, Model } from './single';
1
+ export { init, update, selectItem, view, lazy, Model } from './single';
2
2
  export { Message, SelectedItem, CompletedLockScroll, CompletedUnlockScroll, CompletedSetupInert, CompletedTeardownInert, CompletedFocusInput, CompletedScrollIntoView, CompletedClickItem, GotTransitionMessage, LockScroll, UnlockScroll, InertOthers, RestoreInert, FocusInput, ScrollIntoView, ClickItem, DetectMovementOrTransitionEnd, } from './shared';
3
3
  export type { ActivationTrigger, Opened, Closed, ClosedByTab, ActivatedItem, DeactivatedItem, MovedPointerOverItem, RequestedItemClick, UpdatedInputValue, PressedToggleButton, ItemConfig, GroupHeading, } from './shared';
4
4
  export type { InitConfig, ViewConfig } from './single';
@@ -1 +1 @@
1
- {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/combobox/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AAE1D,OAAO,EACL,OAAO,EACP,YAAY,EACZ,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,EAClB,oBAAoB,EACpB,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,UAAU,EACV,cAAc,EACd,SAAS,EACT,6BAA6B,GAC9B,MAAM,UAAU,CAAA;AAEjB,YAAY,EACV,iBAAiB,EACjB,MAAM,EACN,MAAM,EACN,WAAW,EACX,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,UAAU,EACV,YAAY,GACb,MAAM,UAAU,CAAA;AAEjB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAEtD,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAE7C,OAAO,KAAK,KAAK,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/combobox/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AAEtE,OAAO,EACL,OAAO,EACP,YAAY,EACZ,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,EAClB,oBAAoB,EACpB,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,UAAU,EACV,cAAc,EACd,SAAS,EACT,6BAA6B,GAC9B,MAAM,UAAU,CAAA;AAEjB,YAAY,EACV,iBAAiB,EACjB,MAAM,EACN,MAAM,EACN,WAAW,EACX,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,UAAU,EACV,YAAY,GACb,MAAM,UAAU,CAAA;AAEjB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAEtD,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAE7C,OAAO,KAAK,KAAK,MAAM,eAAe,CAAA"}
@@ -1,3 +1,3 @@
1
- export { init, update, view, lazy, Model } from './single';
1
+ export { init, update, selectItem, view, lazy, Model } from './single';
2
2
  export { Message, SelectedItem, CompletedLockScroll, CompletedUnlockScroll, CompletedSetupInert, CompletedTeardownInert, CompletedFocusInput, CompletedScrollIntoView, CompletedClickItem, GotTransitionMessage, LockScroll, UnlockScroll, InertOthers, RestoreInert, FocusInput, ScrollIntoView, ClickItem, DetectMovementOrTransitionEnd, } from './shared';
3
3
  export * as Multi from './multiPublic';