@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.
- package/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/anchor.d.ts +38 -0
- package/dist/anchor.d.ts.map +1 -0
- package/dist/anchor.js +142 -0
- package/dist/animation/index.d.ts +49 -0
- package/dist/animation/index.d.ts.map +1 -0
- package/dist/animation/index.js +75 -0
- package/dist/animation/public.d.ts +3 -0
- package/dist/animation/public.d.ts.map +1 -0
- package/dist/animation/public.js +1 -0
- package/dist/animation/schema.d.ts +43 -0
- package/dist/animation/schema.d.ts.map +1 -0
- package/dist/animation/schema.js +41 -0
- package/dist/animation/update.d.ts +24 -0
- package/dist/animation/update.d.ts.map +1 -0
- package/dist/animation/update.js +67 -0
- package/dist/button/index.d.ts +17 -0
- package/dist/button/index.d.ts.map +1 -0
- package/dist/button/index.js +22 -0
- package/dist/button/public.d.ts +3 -0
- package/dist/button/public.d.ts.map +1 -0
- package/dist/button/public.js +1 -0
- package/dist/calendar/index.d.ts +462 -0
- package/dist/calendar/index.d.ts.map +1 -0
- package/dist/calendar/index.js +825 -0
- package/dist/calendar/public.d.ts +3 -0
- package/dist/calendar/public.d.ts.map +1 -0
- package/dist/calendar/public.js +1 -0
- package/dist/checkbox/index.d.ts +119 -0
- package/dist/checkbox/index.d.ts.map +1 -0
- package/dist/checkbox/index.js +111 -0
- package/dist/checkbox/public.d.ts +3 -0
- package/dist/checkbox/public.d.ts.map +1 -0
- package/dist/checkbox/public.js +1 -0
- package/dist/combobox/multi.d.ts +183 -0
- package/dist/combobox/multi.d.ts.map +1 -0
- package/dist/combobox/multi.js +81 -0
- package/dist/combobox/multiPublic.d.ts +3 -0
- package/dist/combobox/multiPublic.d.ts.map +1 -0
- package/dist/combobox/multiPublic.js +1 -0
- package/dist/combobox/public.d.ts +7 -0
- package/dist/combobox/public.d.ts.map +1 -0
- package/dist/combobox/public.js +3 -0
- package/dist/combobox/shared.d.ts +423 -0
- package/dist/combobox/shared.d.ts.map +1 -0
- package/dist/combobox/shared.js +708 -0
- package/dist/combobox/single.d.ts +198 -0
- package/dist/combobox/single.d.ts.map +1 -0
- package/dist/combobox/single.js +106 -0
- package/dist/datePicker/index.d.ts +457 -0
- package/dist/datePicker/index.d.ts.map +1 -0
- package/dist/datePicker/index.js +318 -0
- package/dist/datePicker/public.d.ts +3 -0
- package/dist/datePicker/public.d.ts.map +1 -0
- package/dist/datePicker/public.js +1 -0
- package/dist/dialog/index.d.ts +160 -0
- package/dist/dialog/index.d.ts.map +1 -0
- package/dist/dialog/index.js +211 -0
- package/dist/dialog/public.d.ts +3 -0
- package/dist/dialog/public.d.ts.map +1 -0
- package/dist/dialog/public.js +1 -0
- package/dist/disclosure/index.d.ts +110 -0
- package/dist/disclosure/index.d.ts.map +1 -0
- package/dist/disclosure/index.js +111 -0
- package/dist/disclosure/public.d.ts +3 -0
- package/dist/disclosure/public.d.ts.map +1 -0
- package/dist/disclosure/public.js +1 -0
- package/dist/dragAndDrop/index.d.ts +540 -0
- package/dist/dragAndDrop/index.d.ts.map +1 -0
- package/dist/dragAndDrop/index.js +535 -0
- package/dist/dragAndDrop/public.d.ts +3 -0
- package/dist/dragAndDrop/public.d.ts.map +1 -0
- package/dist/dragAndDrop/public.js +1 -0
- package/dist/fieldset/index.d.ts +21 -0
- package/dist/fieldset/index.d.ts.map +1 -0
- package/dist/fieldset/index.js +25 -0
- package/dist/fieldset/public.d.ts +3 -0
- package/dist/fieldset/public.d.ts.map +1 -0
- package/dist/fieldset/public.js +1 -0
- package/dist/fileDrop/index.d.ts +109 -0
- package/dist/fileDrop/index.d.ts.map +1 -0
- package/dist/fileDrop/index.js +127 -0
- package/dist/fileDrop/public.d.ts +3 -0
- package/dist/fileDrop/public.d.ts.map +1 -0
- package/dist/fileDrop/public.js +1 -0
- package/dist/group.d.ts +8 -0
- package/dist/group.d.ts.map +1 -0
- package/dist/group.js +13 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/input/index.d.ts +26 -0
- package/dist/input/index.d.ts.map +1 -0
- package/dist/input/index.js +43 -0
- package/dist/input/public.d.ts +3 -0
- package/dist/input/public.d.ts.map +1 -0
- package/dist/input/public.js +1 -0
- package/dist/internal/optionExtensions.d.ts +6 -0
- package/dist/internal/optionExtensions.d.ts.map +1 -0
- package/dist/internal/optionExtensions.js +2 -0
- package/dist/keyboard.d.ts +6 -0
- package/dist/keyboard.d.ts.map +1 -0
- package/dist/keyboard.js +9 -0
- package/dist/listbox/multi.d.ts +189 -0
- package/dist/listbox/multi.d.ts.map +1 -0
- package/dist/listbox/multi.js +65 -0
- package/dist/listbox/multiPublic.d.ts +3 -0
- package/dist/listbox/multiPublic.d.ts.map +1 -0
- package/dist/listbox/multiPublic.js +1 -0
- package/dist/listbox/public.d.ts +7 -0
- package/dist/listbox/public.d.ts.map +1 -0
- package/dist/listbox/public.js +3 -0
- package/dist/listbox/shared.d.ts +432 -0
- package/dist/listbox/shared.d.ts.map +1 -0
- package/dist/listbox/shared.js +670 -0
- package/dist/listbox/single.d.ts +207 -0
- package/dist/listbox/single.d.ts.map +1 -0
- package/dist/listbox/single.js +73 -0
- package/dist/menu/index.d.ts +368 -0
- package/dist/menu/index.d.ts.map +1 -0
- package/dist/menu/index.js +682 -0
- package/dist/menu/public.d.ts +4 -0
- package/dist/menu/public.d.ts.map +1 -0
- package/dist/menu/public.js +1 -0
- package/dist/popover/index.d.ts +267 -0
- package/dist/popover/index.d.ts.map +1 -0
- package/dist/popover/index.js +346 -0
- package/dist/popover/public.d.ts +4 -0
- package/dist/popover/public.d.ts.map +1 -0
- package/dist/popover/public.js +1 -0
- package/dist/radioGroup/index.d.ts +169 -0
- package/dist/radioGroup/index.d.ts.map +1 -0
- package/dist/radioGroup/index.js +197 -0
- package/dist/radioGroup/public.d.ts +3 -0
- package/dist/radioGroup/public.d.ts.map +1 -0
- package/dist/radioGroup/public.js +1 -0
- package/dist/select/index.d.ts +24 -0
- package/dist/select/index.d.ts.map +1 -0
- package/dist/select/index.js +40 -0
- package/dist/select/public.d.ts +3 -0
- package/dist/select/public.d.ts.map +1 -0
- package/dist/select/public.js +1 -0
- package/dist/slider/index.d.ts +318 -0
- package/dist/slider/index.d.ts.map +1 -0
- package/dist/slider/index.js +337 -0
- package/dist/slider/public.d.ts +3 -0
- package/dist/slider/public.d.ts.map +1 -0
- package/dist/slider/public.js +1 -0
- package/dist/switch/index.d.ts +99 -0
- package/dist/switch/index.d.ts.map +1 -0
- package/dist/switch/index.js +107 -0
- package/dist/switch/public.d.ts +3 -0
- package/dist/switch/public.d.ts.map +1 -0
- package/dist/switch/public.js +1 -0
- package/dist/tabs/index.d.ts +155 -0
- package/dist/tabs/index.d.ts.map +1 -0
- package/dist/tabs/index.js +185 -0
- package/dist/tabs/public.d.ts +3 -0
- package/dist/tabs/public.d.ts.map +1 -0
- package/dist/tabs/public.js +1 -0
- package/dist/test/apps/disabledButton.d.ts +38 -0
- package/dist/test/apps/disabledButton.d.ts.map +1 -0
- package/dist/test/apps/disabledButton.js +71 -0
- package/dist/textarea/index.d.ts +26 -0
- package/dist/textarea/index.d.ts.map +1 -0
- package/dist/textarea/index.js +44 -0
- package/dist/textarea/public.d.ts +3 -0
- package/dist/textarea/public.d.ts.map +1 -0
- package/dist/textarea/public.js +1 -0
- package/dist/toast/index.d.ts +608 -0
- package/dist/toast/index.d.ts.map +1 -0
- package/dist/toast/index.js +146 -0
- package/dist/toast/public.d.ts +4 -0
- package/dist/toast/public.d.ts.map +1 -0
- package/dist/toast/public.js +1 -0
- package/dist/toast/schema.d.ts +154 -0
- package/dist/toast/schema.d.ts.map +1 -0
- package/dist/toast/schema.js +93 -0
- package/dist/toast/update.d.ts +510 -0
- package/dist/toast/update.d.ts.map +1 -0
- package/dist/toast/update.js +225 -0
- package/dist/tooltip/index.d.ts +170 -0
- package/dist/tooltip/index.d.ts.map +1 -0
- package/dist/tooltip/index.js +253 -0
- package/dist/tooltip/public.d.ts +4 -0
- package/dist/tooltip/public.d.ts.map +1 -0
- package/dist/tooltip/public.js +1 -0
- package/dist/typeahead.d.ts +4 -0
- package/dist/typeahead.d.ts.map +1 -0
- package/dist/typeahead.js +14 -0
- package/dist/virtualList/index.d.ts +203 -0
- package/dist/virtualList/index.d.ts.map +1 -0
- package/dist/virtualList/index.js +392 -0
- package/dist/virtualList/public.d.ts +3 -0
- package/dist/virtualList/public.d.ts.map +1 -0
- package/dist/virtualList/public.js +1 -0
- package/dist/vitest-setup.d.ts +2 -0
- package/dist/vitest-setup.d.ts.map +1 -0
- package/dist/vitest-setup.js +2 -0
- package/package.json +161 -0
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { init, update, view, selectDate, reflectSelectedDate, reflectMinDate, reflectMaxDate, reflectDisabledDates, reflectDisabledDaysOfWeek, dropToDays, Model, ViewMode, Message, OutMessage, ChangedViewMonth, SelectedDate, ClickedDay, PressedKeyOnGrid, ClickedPreviousMonthButton, ClickedNextMonthButton, ClickedHeading, SelectedMonth, SelectedYear, PagedYears, FocusedGrid, BlurredGrid, RefreshedToday, CompletedFocusGrid, FocusGrid, } from './index.js';
|
|
2
|
+
export type { InitConfig, ViewInputs, CalendarAttributes, DaysModeAttributes, MonthsModeAttributes, YearsModeAttributes, DayCell, ColumnHeader, Week, MonthCell, YearCell, } from './index.js';
|
|
3
|
+
//# sourceMappingURL=public.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/calendar/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,UAAU,EACV,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,oBAAoB,EACpB,yBAAyB,EACzB,UAAU,EACV,KAAK,EACL,QAAQ,EACR,OAAO,EACP,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,sBAAsB,EACtB,cAAc,EACd,aAAa,EACb,YAAY,EACZ,UAAU,EACV,WAAW,EACX,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,SAAS,GACV,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,UAAU,EACV,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,OAAO,EACP,YAAY,EACZ,IAAI,EACJ,SAAS,EACT,QAAQ,GACT,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { init, update, view, selectDate, reflectSelectedDate, reflectMinDate, reflectMaxDate, reflectDisabledDates, reflectDisabledDaysOfWeek, dropToDays, Model, ViewMode, Message, OutMessage, ChangedViewMonth, SelectedDate, ClickedDay, PressedKeyOnGrid, ClickedPreviousMonthButton, ClickedNextMonthButton, ClickedHeading, SelectedMonth, SelectedYear, PagedYears, FocusedGrid, BlurredGrid, RefreshedToday, CompletedFocusGrid, FocusGrid, } from './index.js';
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Option, Schema as S } from 'effect';
|
|
2
|
+
import type { Command } from 'foldkit/command';
|
|
3
|
+
import { type ChildAttribute, type Html } from 'foldkit/html';
|
|
4
|
+
import { type Reflect } from 'foldkit/submodel';
|
|
5
|
+
/** Schema for the checkbox component's state, tracking the checked status. */
|
|
6
|
+
export declare const Model: S.Struct<{
|
|
7
|
+
readonly id: S.String;
|
|
8
|
+
readonly isChecked: S.Boolean;
|
|
9
|
+
}>;
|
|
10
|
+
export type Model = typeof Model.Type;
|
|
11
|
+
/** Sent when the user toggles the checkbox via click or Space key. */
|
|
12
|
+
export declare const Toggled: import("foldkit/schema").CallableTaggedStruct<"Toggled", {}>;
|
|
13
|
+
/** Sent to set the checked state to a specific value. Use this for
|
|
14
|
+
* programmatic state assignment (e.g. a "select all" handler that forces
|
|
15
|
+
* all child checkboxes to the same state) where `Toggled`'s flip semantics
|
|
16
|
+
* would not reliably reach the desired state. */
|
|
17
|
+
export declare const SetChecked: import("foldkit/schema").CallableTaggedStruct<"SetChecked", {
|
|
18
|
+
isChecked: S.Boolean;
|
|
19
|
+
}>;
|
|
20
|
+
/** Schema for all messages the checkbox component can produce. */
|
|
21
|
+
export declare const Message: S.Union<readonly [import("foldkit/schema").CallableTaggedStruct<"Toggled", {}>, import("foldkit/schema").CallableTaggedStruct<"SetChecked", {
|
|
22
|
+
isChecked: S.Boolean;
|
|
23
|
+
}>]>;
|
|
24
|
+
export type Toggled = typeof Toggled.Type;
|
|
25
|
+
export type SetChecked = typeof SetChecked.Type;
|
|
26
|
+
export type Message = typeof Message.Type;
|
|
27
|
+
/** Sent to the parent each time the checkbox toggles. Carries the new
|
|
28
|
+
* checked state. Consumers pattern-match this in their `GotCheckboxMessage`
|
|
29
|
+
* handler to lift the toggle into a domain Message (e.g., persisting the
|
|
30
|
+
* flag, dispatching a save command). */
|
|
31
|
+
export declare const ToggledChecked: import("foldkit/schema").CallableTaggedStruct<"ToggledChecked", {
|
|
32
|
+
isChecked: S.Boolean;
|
|
33
|
+
}>;
|
|
34
|
+
/** Union of out-messages the checkbox component can produce. Surfaced as
|
|
35
|
+
* the third element of `update`'s return tuple and pattern-matched by
|
|
36
|
+
* the parent. */
|
|
37
|
+
export declare const OutMessage: S.Union<readonly [import("foldkit/schema").CallableTaggedStruct<"ToggledChecked", {
|
|
38
|
+
isChecked: S.Boolean;
|
|
39
|
+
}>]>;
|
|
40
|
+
export type ToggledChecked = typeof ToggledChecked.Type;
|
|
41
|
+
export type OutMessage = typeof OutMessage.Type;
|
|
42
|
+
/** Configuration for creating a checkbox model with `init`. */
|
|
43
|
+
export type InitConfig = Readonly<{
|
|
44
|
+
id: string;
|
|
45
|
+
isChecked?: boolean;
|
|
46
|
+
}>;
|
|
47
|
+
/** Creates an initial checkbox model from a config. Defaults to unchecked. */
|
|
48
|
+
export declare const init: (config: InitConfig) => Model;
|
|
49
|
+
/** Processes a checkbox message and returns the next model, commands,
|
|
50
|
+
* and a `ToggledChecked` OutMessage carrying the new checked state. */
|
|
51
|
+
export declare const update: (model: Model, message: Message) => readonly [Model, ReadonlyArray<Command<Message>>, Option.Option<OutMessage>];
|
|
52
|
+
/** Programmatically sets the checked state. Emits a `ToggledChecked`
|
|
53
|
+
* OutMessage just like a user-initiated toggle. Use this in domain-event
|
|
54
|
+
* handlers where you need to force a specific state (e.g. "select all"). */
|
|
55
|
+
export declare const setChecked: (model: Model, isChecked: boolean) => readonly [Model, ReadonlyArray<Command<Message>>, Option.Option<OutMessage>];
|
|
56
|
+
/** Reflects an externally-sourced checked state onto the model without
|
|
57
|
+
* emitting an OutMessage. Use this to mirror external truth (saved
|
|
58
|
+
* settings, a server value) onto the checkbox without triggering the
|
|
59
|
+
* downstream reaction a user toggle would cause. Contrast with
|
|
60
|
+
* `setChecked`, which emits `ToggledChecked` so the parent reacts to a
|
|
61
|
+
* programmatic assignment the same way it reacts to a user toggle. Returns
|
|
62
|
+
* the model directly because it produces no commands and no OutMessage. */
|
|
63
|
+
export declare const reflectChecked: Reflect<Model, boolean>;
|
|
64
|
+
/** Attribute groups the checkbox component provides to the consumer's
|
|
65
|
+
* `toView` callback. Each group is a `ReadonlyArray<ChildAttribute>`:
|
|
66
|
+
* attributes published from inside Checkbox's own boundary that the
|
|
67
|
+
* consumer can spread directly into its own element attribute arrays:
|
|
68
|
+
*
|
|
69
|
+
* ```ts
|
|
70
|
+
* toView: attributes =>
|
|
71
|
+
* h.div(
|
|
72
|
+
* [...attributes.checkbox, h.Class('my-class'), h.OnClick(MyOwnMsg())],
|
|
73
|
+
* [...],
|
|
74
|
+
* )
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* Checkbox's own `OnClick(Toggled())` handlers (carried inside
|
|
78
|
+
* `attributes.checkbox` etc.) dispatch `Toggled` through Checkbox's
|
|
79
|
+
* boundary wrap at event-fire time. The consumer's own
|
|
80
|
+
* `OnClick(MyOwnMsg())` lives in the parent's boundary and dispatches
|
|
81
|
+
* unwrapped. The two routes are tracked separately by the runtime; the
|
|
82
|
+
* consumer never has to think about which boundary an attribute belongs
|
|
83
|
+
* to. */
|
|
84
|
+
export type CheckboxAttributes = Readonly<{
|
|
85
|
+
checkbox: ReadonlyArray<ChildAttribute>;
|
|
86
|
+
label: ReadonlyArray<ChildAttribute>;
|
|
87
|
+
description: ReadonlyArray<ChildAttribute>;
|
|
88
|
+
hiddenInput: ReadonlyArray<ChildAttribute>;
|
|
89
|
+
}>;
|
|
90
|
+
/** Per-render view inputs passed to `view` via `h.submodel`'s `viewInputs` field.
|
|
91
|
+
* Slot content (`toView`) and behavioral flags live here; the parent
|
|
92
|
+
* declares them at the embed site rather than threading them through the
|
|
93
|
+
* Submodel as a generic-parameterized callback. */
|
|
94
|
+
export type ViewInputs = Readonly<{
|
|
95
|
+
toView: (attributes: CheckboxAttributes) => Html;
|
|
96
|
+
isDisabled?: boolean;
|
|
97
|
+
isIndeterminate?: boolean;
|
|
98
|
+
name?: string;
|
|
99
|
+
value?: string;
|
|
100
|
+
}>;
|
|
101
|
+
/** Renders an accessible checkbox by building ARIA attribute groups and
|
|
102
|
+
* delegating layout to the consumer's `toView` callback. Embedded via
|
|
103
|
+
* `h.submodel`. */
|
|
104
|
+
export declare const view: import("foldkit/submodel").View<{
|
|
105
|
+
readonly id: string;
|
|
106
|
+
readonly isChecked: boolean;
|
|
107
|
+
}, {
|
|
108
|
+
readonly _tag: "Toggled";
|
|
109
|
+
} | {
|
|
110
|
+
readonly _tag: "SetChecked";
|
|
111
|
+
readonly isChecked: boolean;
|
|
112
|
+
}, Readonly<{
|
|
113
|
+
toView: (attributes: CheckboxAttributes) => Html;
|
|
114
|
+
isDisabled?: boolean;
|
|
115
|
+
isIndeterminate?: boolean;
|
|
116
|
+
name?: string;
|
|
117
|
+
value?: string;
|
|
118
|
+
}>>;
|
|
119
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/checkbox/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Function, Match as M, Option, Schema as S } from 'effect';
|
|
2
|
+
import { childAttributes, html, } from 'foldkit/html';
|
|
3
|
+
import { m } from 'foldkit/message';
|
|
4
|
+
import { evo } from 'foldkit/struct';
|
|
5
|
+
import { defineView } from 'foldkit/submodel';
|
|
6
|
+
// MODEL
|
|
7
|
+
/** Schema for the checkbox component's state, tracking the checked status. */
|
|
8
|
+
export const Model = S.Struct({
|
|
9
|
+
id: S.String,
|
|
10
|
+
isChecked: S.Boolean,
|
|
11
|
+
});
|
|
12
|
+
// MESSAGE
|
|
13
|
+
/** Sent when the user toggles the checkbox via click or Space key. */
|
|
14
|
+
export const Toggled = m('Toggled');
|
|
15
|
+
/** Sent to set the checked state to a specific value. Use this for
|
|
16
|
+
* programmatic state assignment (e.g. a "select all" handler that forces
|
|
17
|
+
* all child checkboxes to the same state) where `Toggled`'s flip semantics
|
|
18
|
+
* would not reliably reach the desired state. */
|
|
19
|
+
export const SetChecked = m('SetChecked', { isChecked: S.Boolean });
|
|
20
|
+
/** Schema for all messages the checkbox component can produce. */
|
|
21
|
+
export const Message = S.Union([Toggled, SetChecked]);
|
|
22
|
+
// OUT MESSAGE
|
|
23
|
+
/** Sent to the parent each time the checkbox toggles. Carries the new
|
|
24
|
+
* checked state. Consumers pattern-match this in their `GotCheckboxMessage`
|
|
25
|
+
* handler to lift the toggle into a domain Message (e.g., persisting the
|
|
26
|
+
* flag, dispatching a save command). */
|
|
27
|
+
export const ToggledChecked = m('ToggledChecked', { isChecked: S.Boolean });
|
|
28
|
+
/** Union of out-messages the checkbox component can produce. Surfaced as
|
|
29
|
+
* the third element of `update`'s return tuple and pattern-matched by
|
|
30
|
+
* the parent. */
|
|
31
|
+
export const OutMessage = S.Union([ToggledChecked]);
|
|
32
|
+
/** Creates an initial checkbox model from a config. Defaults to unchecked. */
|
|
33
|
+
export const init = (config) => ({
|
|
34
|
+
id: config.id,
|
|
35
|
+
isChecked: config.isChecked ?? false,
|
|
36
|
+
});
|
|
37
|
+
// UPDATE
|
|
38
|
+
/** Processes a checkbox message and returns the next model, commands,
|
|
39
|
+
* and a `ToggledChecked` OutMessage carrying the new checked state. */
|
|
40
|
+
export const update = (model, message) => M.value(message).pipe(M.withReturnType(), M.tagsExhaustive({
|
|
41
|
+
Toggled: () => {
|
|
42
|
+
const nextIsChecked = !model.isChecked;
|
|
43
|
+
return [
|
|
44
|
+
evo(model, { isChecked: () => nextIsChecked }),
|
|
45
|
+
[],
|
|
46
|
+
Option.some(ToggledChecked({ isChecked: nextIsChecked })),
|
|
47
|
+
];
|
|
48
|
+
},
|
|
49
|
+
SetChecked: ({ isChecked }) => [
|
|
50
|
+
evo(model, { isChecked: () => isChecked }),
|
|
51
|
+
[],
|
|
52
|
+
Option.some(ToggledChecked({ isChecked })),
|
|
53
|
+
],
|
|
54
|
+
}));
|
|
55
|
+
/** Programmatically sets the checked state. Emits a `ToggledChecked`
|
|
56
|
+
* OutMessage just like a user-initiated toggle. Use this in domain-event
|
|
57
|
+
* handlers where you need to force a specific state (e.g. "select all"). */
|
|
58
|
+
export const setChecked = (model, isChecked) => update(model, SetChecked({ isChecked }));
|
|
59
|
+
/** Reflects an externally-sourced checked state onto the model without
|
|
60
|
+
* emitting an OutMessage. Use this to mirror external truth (saved
|
|
61
|
+
* settings, a server value) onto the checkbox without triggering the
|
|
62
|
+
* downstream reaction a user toggle would cause. Contrast with
|
|
63
|
+
* `setChecked`, which emits `ToggledChecked` so the parent reacts to a
|
|
64
|
+
* programmatic assignment the same way it reacts to a user toggle. Returns
|
|
65
|
+
* the model directly because it produces no commands and no OutMessage. */
|
|
66
|
+
export const reflectChecked = Function.dual(2, (model, isChecked) => evo(model, { isChecked: () => isChecked }));
|
|
67
|
+
const labelId = (id) => `${id}-label`;
|
|
68
|
+
const descriptionId = (id) => `${id}-description`;
|
|
69
|
+
/** Renders an accessible checkbox by building ARIA attribute groups and
|
|
70
|
+
* delegating layout to the consumer's `toView` callback. Embedded via
|
|
71
|
+
* `h.submodel`. */
|
|
72
|
+
export const view = defineView((model, viewInputs) => {
|
|
73
|
+
const h = html();
|
|
74
|
+
const { id, isChecked } = model;
|
|
75
|
+
const { isDisabled = false, isIndeterminate = false, name, value: formValue = 'on', } = viewInputs;
|
|
76
|
+
const handleKeyUp = (key) => M.value(key).pipe(M.when(' ', () => Option.some(Toggled())), M.orElse(() => Option.none()));
|
|
77
|
+
const stateAttributes = isIndeterminate
|
|
78
|
+
? [h.DataAttribute('indeterminate', '')]
|
|
79
|
+
: isChecked
|
|
80
|
+
? [h.DataAttribute('checked', '')]
|
|
81
|
+
: [];
|
|
82
|
+
const disabledAttributes = isDisabled
|
|
83
|
+
? [h.AriaDisabled(true), h.DataAttribute('disabled', '')]
|
|
84
|
+
: [];
|
|
85
|
+
const checkboxAttributes = [
|
|
86
|
+
h.Role('checkbox'),
|
|
87
|
+
h.AriaChecked(isIndeterminate ? 'mixed' : isChecked),
|
|
88
|
+
h.AriaLabelledBy(labelId(id)),
|
|
89
|
+
h.AriaDescribedBy(descriptionId(id)),
|
|
90
|
+
h.Tabindex(0),
|
|
91
|
+
...stateAttributes,
|
|
92
|
+
...disabledAttributes,
|
|
93
|
+
...(isDisabled
|
|
94
|
+
? []
|
|
95
|
+
: [h.OnClick(Toggled()), h.OnKeyUpPreventDefault(handleKeyUp)]),
|
|
96
|
+
];
|
|
97
|
+
const labelAttributes = [
|
|
98
|
+
h.Id(labelId(id)),
|
|
99
|
+
...(isDisabled ? [] : [h.OnClick(Toggled())]),
|
|
100
|
+
];
|
|
101
|
+
const descriptionAttributes = [h.Id(descriptionId(id))];
|
|
102
|
+
const hiddenInputAttributes = name
|
|
103
|
+
? [h.Type('hidden'), h.Name(name), h.Value(isChecked ? formValue : '')]
|
|
104
|
+
: [];
|
|
105
|
+
return viewInputs.toView({
|
|
106
|
+
checkbox: childAttributes(checkboxAttributes),
|
|
107
|
+
label: childAttributes(labelAttributes),
|
|
108
|
+
description: childAttributes(descriptionAttributes),
|
|
109
|
+
hiddenInput: childAttributes(hiddenInputAttributes),
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/checkbox/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,MAAM,EACN,UAAU,EACV,cAAc,EACd,IAAI,EACJ,KAAK,EACL,OAAO,EACP,UAAU,EACV,UAAU,EACV,cAAc,GACf,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,OAAO,EACP,UAAU,EACV,UAAU,EACV,kBAAkB,GACnB,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { init, update, setChecked, reflectChecked, view, Model, Message, OutMessage, SetChecked, ToggledChecked, } from './index.js';
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { Option, Schema as S } from 'effect';
|
|
2
|
+
import type * as Command from 'foldkit/command';
|
|
3
|
+
import type { Reflect, View as SubmodelView } from 'foldkit/submodel';
|
|
4
|
+
import { type BaseInitConfig, type BaseViewInputs, type Message, type OutMessage } from './shared.js';
|
|
5
|
+
/** Schema for the multi-select combobox component's state, tracking open/closed status, active item, input value, and selected items. */
|
|
6
|
+
export declare const Model: S.Struct<{
|
|
7
|
+
readonly selectedItems: S.$Array<S.String>;
|
|
8
|
+
readonly id: S.String;
|
|
9
|
+
readonly isOpen: S.Boolean;
|
|
10
|
+
readonly isAnimated: S.Boolean;
|
|
11
|
+
readonly isModal: S.Boolean;
|
|
12
|
+
readonly nullable: S.Boolean;
|
|
13
|
+
readonly immediate: S.Boolean;
|
|
14
|
+
readonly selectInputOnFocus: S.Boolean;
|
|
15
|
+
readonly animation: S.Struct<{
|
|
16
|
+
readonly id: S.String;
|
|
17
|
+
readonly isShowing: S.Boolean;
|
|
18
|
+
readonly transitionState: S.Literals<readonly ["Idle", "EnterStart", "EnterAnimating", "LeaveStart", "LeaveAnimating"]>;
|
|
19
|
+
}>;
|
|
20
|
+
readonly maybeActiveItemIndex: S.Option<S.Number>;
|
|
21
|
+
readonly activationTrigger: S.Literals<readonly ["Pointer", "Keyboard"]>;
|
|
22
|
+
readonly inputValue: S.String;
|
|
23
|
+
readonly maybeLastPointerPosition: S.Option<S.Struct<{
|
|
24
|
+
readonly screenX: S.Number;
|
|
25
|
+
readonly screenY: S.Number;
|
|
26
|
+
}>>;
|
|
27
|
+
}>;
|
|
28
|
+
export type Model = typeof Model.Type;
|
|
29
|
+
/** Configuration for creating a multi-select combobox model with `init`. `isAnimated` enables CSS transition coordination (default `false`). `isModal` locks page scroll and inerts other elements when open (default `false`). `selectedItems` sets the initial selection (default `[]`). */
|
|
30
|
+
export type InitConfig = BaseInitConfig & Readonly<{
|
|
31
|
+
selectedItems?: ReadonlyArray<string>;
|
|
32
|
+
}>;
|
|
33
|
+
/** Creates an initial multi-select combobox model from a config. Defaults to closed with no active item, empty input, and no selection. */
|
|
34
|
+
export declare const init: (config: InitConfig) => Model;
|
|
35
|
+
/** Processes a combobox message and returns the next model and commands. Stays open on selection and toggles item membership (multi-select behavior). */
|
|
36
|
+
export declare const update: (model: {
|
|
37
|
+
readonly selectedItems: readonly string[];
|
|
38
|
+
readonly id: string;
|
|
39
|
+
readonly isOpen: boolean;
|
|
40
|
+
readonly isAnimated: boolean;
|
|
41
|
+
readonly isModal: boolean;
|
|
42
|
+
readonly nullable: boolean;
|
|
43
|
+
readonly immediate: boolean;
|
|
44
|
+
readonly selectInputOnFocus: boolean;
|
|
45
|
+
readonly animation: {
|
|
46
|
+
readonly id: string;
|
|
47
|
+
readonly isShowing: boolean;
|
|
48
|
+
readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
|
|
49
|
+
};
|
|
50
|
+
readonly maybeActiveItemIndex: Option.Option<number>;
|
|
51
|
+
readonly activationTrigger: "Pointer" | "Keyboard";
|
|
52
|
+
readonly inputValue: string;
|
|
53
|
+
readonly maybeLastPointerPosition: Option.Option<{
|
|
54
|
+
readonly screenX: number;
|
|
55
|
+
readonly screenY: number;
|
|
56
|
+
}>;
|
|
57
|
+
}, message: Message) => readonly [{
|
|
58
|
+
readonly selectedItems: readonly string[];
|
|
59
|
+
readonly id: string;
|
|
60
|
+
readonly isOpen: boolean;
|
|
61
|
+
readonly isAnimated: boolean;
|
|
62
|
+
readonly isModal: boolean;
|
|
63
|
+
readonly nullable: boolean;
|
|
64
|
+
readonly immediate: boolean;
|
|
65
|
+
readonly selectInputOnFocus: boolean;
|
|
66
|
+
readonly animation: {
|
|
67
|
+
readonly id: string;
|
|
68
|
+
readonly isShowing: boolean;
|
|
69
|
+
readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
|
|
70
|
+
};
|
|
71
|
+
readonly maybeActiveItemIndex: Option.Option<number>;
|
|
72
|
+
readonly activationTrigger: "Pointer" | "Keyboard";
|
|
73
|
+
readonly inputValue: string;
|
|
74
|
+
readonly maybeLastPointerPosition: Option.Option<{
|
|
75
|
+
readonly screenX: number;
|
|
76
|
+
readonly screenY: number;
|
|
77
|
+
}>;
|
|
78
|
+
}, readonly Readonly<{
|
|
79
|
+
name: string;
|
|
80
|
+
args?: Record<string, unknown>;
|
|
81
|
+
effect: import("effect/Effect").Effect<{
|
|
82
|
+
readonly _tag: "CompletedLockScroll";
|
|
83
|
+
} | {
|
|
84
|
+
readonly _tag: "CompletedUnlockScroll";
|
|
85
|
+
} | {
|
|
86
|
+
readonly _tag: "CompletedInertOthers";
|
|
87
|
+
} | {
|
|
88
|
+
readonly _tag: "CompletedRestoreInert";
|
|
89
|
+
} | {
|
|
90
|
+
readonly _tag: "Closed";
|
|
91
|
+
} | {
|
|
92
|
+
readonly _tag: "Opened";
|
|
93
|
+
readonly maybeActiveItemIndex: Option.Option<number>;
|
|
94
|
+
} | {
|
|
95
|
+
readonly _tag: "BlurredInput";
|
|
96
|
+
} | {
|
|
97
|
+
readonly _tag: "ActivatedItem";
|
|
98
|
+
readonly index: number;
|
|
99
|
+
readonly activationTrigger: "Pointer" | "Keyboard";
|
|
100
|
+
readonly maybeImmediateSelection: Option.Option<{
|
|
101
|
+
readonly item: string;
|
|
102
|
+
readonly displayText: string;
|
|
103
|
+
}>;
|
|
104
|
+
} | {
|
|
105
|
+
readonly _tag: "DeactivatedItem";
|
|
106
|
+
} | {
|
|
107
|
+
readonly _tag: "SelectedItem";
|
|
108
|
+
readonly item: string;
|
|
109
|
+
readonly displayText: string;
|
|
110
|
+
} | {
|
|
111
|
+
readonly _tag: "MovedPointerOverItem";
|
|
112
|
+
readonly index: number;
|
|
113
|
+
readonly screenX: number;
|
|
114
|
+
readonly screenY: number;
|
|
115
|
+
} | {
|
|
116
|
+
readonly _tag: "RequestedItemClick";
|
|
117
|
+
readonly index: number;
|
|
118
|
+
} | {
|
|
119
|
+
readonly _tag: "CompletedFocusInput";
|
|
120
|
+
} | {
|
|
121
|
+
readonly _tag: "CompletedScrollIntoView";
|
|
122
|
+
} | {
|
|
123
|
+
readonly _tag: "CompletedClickItem";
|
|
124
|
+
} | {
|
|
125
|
+
readonly _tag: "CompletedAnchorCombobox";
|
|
126
|
+
} | {
|
|
127
|
+
readonly _tag: "CompletedAttachComboboxPreventBlur";
|
|
128
|
+
} | {
|
|
129
|
+
readonly _tag: "CompletedAttachComboboxSelectOnFocus";
|
|
130
|
+
} | {
|
|
131
|
+
readonly _tag: "CompletedPortalComboboxBackdrop";
|
|
132
|
+
} | {
|
|
133
|
+
readonly _tag: "GotAnimationMessage";
|
|
134
|
+
readonly message: {
|
|
135
|
+
readonly _tag: "Showed";
|
|
136
|
+
} | {
|
|
137
|
+
readonly _tag: "Hid";
|
|
138
|
+
} | {
|
|
139
|
+
readonly _tag: "AdvancedAnimationFrame";
|
|
140
|
+
} | {
|
|
141
|
+
readonly _tag: "EndedAnimation";
|
|
142
|
+
};
|
|
143
|
+
} | {
|
|
144
|
+
readonly _tag: "UpdatedInputValue";
|
|
145
|
+
readonly value: string;
|
|
146
|
+
} | {
|
|
147
|
+
readonly _tag: "PressedToggleButton";
|
|
148
|
+
}, never, never>;
|
|
149
|
+
}>[], Option.Option<Readonly<{
|
|
150
|
+
readonly _tag: "Selected";
|
|
151
|
+
readonly value: string;
|
|
152
|
+
readonly wasAdded: boolean;
|
|
153
|
+
}>>];
|
|
154
|
+
type UpdateReturn = ReturnType<typeof update>;
|
|
155
|
+
/** Programmatically opens the combobox, updating the model and returning
|
|
156
|
+
* focus and modal commands. Use this in domain-event handlers to open the combobox. */
|
|
157
|
+
export declare const open: (model: Model) => UpdateReturn;
|
|
158
|
+
/** Programmatically closes the combobox, updating the model and returning
|
|
159
|
+
* focus and modal commands. Use this in domain-event handlers to close the combobox. */
|
|
160
|
+
export declare const close: (model: Model) => UpdateReturn;
|
|
161
|
+
/** Programmatically toggles an item in the multi-select combobox. Emits `Selected({ value, wasAdded })`. */
|
|
162
|
+
export declare const selectItem: (model: Model, item: string) => UpdateReturn;
|
|
163
|
+
/** Reflects an externally-sourced selection set onto the model without
|
|
164
|
+
* emitting an OutMessage or running selection side effects. Use this to
|
|
165
|
+
* mirror external truth (URL parameters, restored storage, a server push)
|
|
166
|
+
* onto the combobox's selected items. Contrast with `selectItem`, which
|
|
167
|
+
* toggles a single item as a user *choice* and emits `Selected`. Returns
|
|
168
|
+
* the model directly because it produces no commands and no OutMessage. */
|
|
169
|
+
export declare const reflectSelectedItems: Reflect<Model, ReadonlyArray<string>>;
|
|
170
|
+
/** Per-render view inputs passed to the view via `h.submodel`'s `viewInputs` field. */
|
|
171
|
+
export type ViewInputs<Item extends string> = BaseViewInputs<Item>;
|
|
172
|
+
/** Pairs the multi-select combobox's `view` and `update` (and programmatic
|
|
173
|
+
* helpers) behind a single Item-typed entry point. */
|
|
174
|
+
export declare const create: <Item extends string = string>() => Readonly<{
|
|
175
|
+
view: SubmodelView<Model, Message, BaseViewInputs<Item>>;
|
|
176
|
+
update: (model: Model, message: Message) => readonly [Model, ReadonlyArray<Command.Command<Message>>, Option.Option<OutMessage<Item>>];
|
|
177
|
+
selectItem: (model: Model, item: Item) => readonly [Model, ReadonlyArray<Command.Command<Message>>, Option.Option<OutMessage<Item>>];
|
|
178
|
+
open: (model: Model) => readonly [Model, ReadonlyArray<Command.Command<Message>>, Option.Option<OutMessage<Item>>];
|
|
179
|
+
close: (model: Model) => readonly [Model, ReadonlyArray<Command.Command<Message>>, Option.Option<OutMessage<Item>>];
|
|
180
|
+
reflectSelectedItems: Reflect<Model, ReadonlyArray<Item>>;
|
|
181
|
+
}>;
|
|
182
|
+
export {};
|
|
183
|
+
//# sourceMappingURL=multi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi.d.ts","sourceRoot":"","sources":["../../src/combobox/multi.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Array, Function, Option, Schema as S } from 'effect';
|
|
2
|
+
import { evo } from 'foldkit/struct';
|
|
3
|
+
import { BaseModel, Closed, Opened, SelectedItem, Selected as SharedSelected, baseInit, closedBaseModel, makeUpdate, makeView, } from './shared.js';
|
|
4
|
+
// MODEL
|
|
5
|
+
/** Schema for the multi-select combobox component's state, tracking open/closed status, active item, input value, and selected items. */
|
|
6
|
+
export const Model = S.Struct({
|
|
7
|
+
...BaseModel.fields,
|
|
8
|
+
selectedItems: S.Array(S.String),
|
|
9
|
+
});
|
|
10
|
+
/** Creates an initial multi-select combobox model from a config. Defaults to closed with no active item, empty input, and no selection. */
|
|
11
|
+
export const init = (config) => ({
|
|
12
|
+
...baseInit(config),
|
|
13
|
+
selectedItems: config.selectedItems ?? [],
|
|
14
|
+
});
|
|
15
|
+
// UPDATE
|
|
16
|
+
const toggleItem = (selectedItems, item) => Array.contains(selectedItems, item)
|
|
17
|
+
? Array.filter(selectedItems, selected => selected !== item)
|
|
18
|
+
: Array.append(selectedItems, item);
|
|
19
|
+
const emptySelection = [];
|
|
20
|
+
/** Processes a combobox message and returns the next model and commands. Stays open on selection and toggles item membership (multi-select behavior). */
|
|
21
|
+
export const update = makeUpdate({
|
|
22
|
+
handleClose: model => {
|
|
23
|
+
if (model.nullable && model.inputValue === '') {
|
|
24
|
+
return evo(closedBaseModel(model), {
|
|
25
|
+
selectedItems: () => emptySelection,
|
|
26
|
+
inputValue: () => '',
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return evo(closedBaseModel(model), {
|
|
30
|
+
inputValue: () => '',
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
handleSelectedItem: (model, item) => {
|
|
34
|
+
const wasAdded = !Array.contains(model.selectedItems, item);
|
|
35
|
+
const nextSelectedItems = wasAdded
|
|
36
|
+
? Array.append(model.selectedItems, item)
|
|
37
|
+
: Array.filter(model.selectedItems, selected => selected !== item);
|
|
38
|
+
return [
|
|
39
|
+
evo(model, { selectedItems: () => nextSelectedItems }),
|
|
40
|
+
[],
|
|
41
|
+
Option.some(SharedSelected({ value: item, wasAdded })),
|
|
42
|
+
];
|
|
43
|
+
},
|
|
44
|
+
handleImmediateActivation: (model, item) => evo(model, {
|
|
45
|
+
selectedItems: () => toggleItem(model.selectedItems, item),
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
/** Programmatically opens the combobox, updating the model and returning
|
|
49
|
+
* focus and modal commands. Use this in domain-event handlers to open the combobox. */
|
|
50
|
+
export const open = (model) => update(model, Opened({ maybeActiveItemIndex: Option.none() }));
|
|
51
|
+
/** Programmatically closes the combobox, updating the model and returning
|
|
52
|
+
* focus and modal commands. Use this in domain-event handlers to close the combobox. */
|
|
53
|
+
export const close = (model) => update(model, Closed());
|
|
54
|
+
/** Programmatically toggles an item in the multi-select combobox. Emits `Selected({ value, wasAdded })`. */
|
|
55
|
+
export const selectItem = (model, item) => update(model, SelectedItem({ item, displayText: item }));
|
|
56
|
+
/** Reflects an externally-sourced selection set onto the model without
|
|
57
|
+
* emitting an OutMessage or running selection side effects. Use this to
|
|
58
|
+
* mirror external truth (URL parameters, restored storage, a server push)
|
|
59
|
+
* onto the combobox's selected items. Contrast with `selectItem`, which
|
|
60
|
+
* toggles a single item as a user *choice* and emits `Selected`. Returns
|
|
61
|
+
* the model directly because it produces no commands and no OutMessage. */
|
|
62
|
+
export const reflectSelectedItems = Function.dual(2, (model, items) => evo(model, { selectedItems: () => items }));
|
|
63
|
+
const internalView = makeView({
|
|
64
|
+
isItemSelected: (model, itemValue) => Array.contains(model.selectedItems, itemValue),
|
|
65
|
+
ariaMultiSelectable: true,
|
|
66
|
+
});
|
|
67
|
+
/** Pairs the multi-select combobox's `view` and `update` (and programmatic
|
|
68
|
+
* helpers) behind a single Item-typed entry point. */
|
|
69
|
+
export const create = () => {
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
71
|
+
const typedUpdate = update;
|
|
72
|
+
return {
|
|
73
|
+
view: internalView(),
|
|
74
|
+
update: typedUpdate,
|
|
75
|
+
selectItem: (model, item) => typedUpdate(model, SelectedItem({ item, displayText: item })),
|
|
76
|
+
open: model => typedUpdate(model, Opened({ maybeActiveItemIndex: Option.none() })),
|
|
77
|
+
close: model => typedUpdate(model, Closed()),
|
|
78
|
+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
79
|
+
reflectSelectedItems: reflectSelectedItems,
|
|
80
|
+
};
|
|
81
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multiPublic.d.ts","sourceRoot":"","sources":["../../src/combobox/multiPublic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAChD,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { init, create, Model } from './multi.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { init, create, Model } from './single.js';
|
|
2
|
+
export { Message, OutMessage, Selected, SelectedItem, CompletedLockScroll, CompletedUnlockScroll, CompletedInertOthers, CompletedRestoreInert, CompletedFocusInput, CompletedScrollIntoView, CompletedClickItem, CompletedAnchorCombobox, CompletedAttachComboboxPreventBlur, CompletedAttachComboboxSelectOnFocus, CompletedPortalComboboxBackdrop, AnchorCombobox, AttachComboboxPreventBlur, AttachComboboxSelectOnFocus, PortalComboboxBackdrop, GotAnimationMessage, LockScroll, UnlockScroll, InertOthers, RestoreInert, FocusInput, ScrollIntoView, ClickItem, DetectMovementOrAnimationEnd, } from './shared.js';
|
|
3
|
+
export type { ActivationTrigger, Opened, Closed, BlurredInput, ActivatedItem, DeactivatedItem, MovedPointerOverItem, RequestedItemClick, UpdatedInputValue, PressedToggleButton, ItemConfig, GroupHeading, } from './shared.js';
|
|
4
|
+
export type { InitConfig, ViewInputs } from './single.js';
|
|
5
|
+
export type { AnchorConfig } from '../anchor.js';
|
|
6
|
+
export * as Multi from './multiPublic.js';
|
|
7
|
+
//# sourceMappingURL=public.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/combobox/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEjD,OAAO,EACL,OAAO,EACP,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,EAClB,uBAAuB,EACvB,kCAAkC,EAClC,oCAAoC,EACpC,+BAA+B,EAC/B,cAAc,EACd,yBAAyB,EACzB,2BAA2B,EAC3B,sBAAsB,EACtB,mBAAmB,EACnB,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,UAAU,EACV,cAAc,EACd,SAAS,EACT,4BAA4B,GAC7B,MAAM,aAAa,CAAA;AAEpB,YAAY,EACV,iBAAiB,EACjB,MAAM,EACN,MAAM,EACN,YAAY,EACZ,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,UAAU,EACV,YAAY,GACb,MAAM,aAAa,CAAA;AAEpB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAEzD,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { init, create, Model } from './single.js';
|
|
2
|
+
export { Message, OutMessage, Selected, SelectedItem, CompletedLockScroll, CompletedUnlockScroll, CompletedInertOthers, CompletedRestoreInert, CompletedFocusInput, CompletedScrollIntoView, CompletedClickItem, CompletedAnchorCombobox, CompletedAttachComboboxPreventBlur, CompletedAttachComboboxSelectOnFocus, CompletedPortalComboboxBackdrop, AnchorCombobox, AttachComboboxPreventBlur, AttachComboboxSelectOnFocus, PortalComboboxBackdrop, GotAnimationMessage, LockScroll, UnlockScroll, InertOthers, RestoreInert, FocusInput, ScrollIntoView, ClickItem, DetectMovementOrAnimationEnd, } from './shared.js';
|
|
3
|
+
export * as Multi from './multiPublic.js';
|