foldkit 0.17.0 → 0.18.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 (48) hide show
  1. package/README.md +3 -8
  2. package/dist/fieldValidation/index.d.ts +8 -8
  3. package/dist/fieldValidation/index.d.ts.map +1 -1
  4. package/dist/fieldValidation/index.js +5 -4
  5. package/dist/html/index.d.ts +29 -1
  6. package/dist/html/index.d.ts.map +1 -1
  7. package/dist/html/index.js +23 -3
  8. package/dist/runtime/browserListeners.d.ts.map +1 -1
  9. package/dist/runtime/browserListeners.js +2 -2
  10. package/dist/runtime/runtime.d.ts +1 -1
  11. package/dist/runtime/runtime.d.ts.map +1 -1
  12. package/dist/runtime/urlRequest.d.ts +4 -4
  13. package/dist/runtime/urlRequest.d.ts.map +1 -1
  14. package/dist/runtime/urlRequest.js +3 -2
  15. package/dist/schema/index.d.ts +13 -7
  16. package/dist/schema/index.d.ts.map +1 -1
  17. package/dist/schema/index.js +13 -15
  18. package/dist/schema/public.d.ts +1 -0
  19. package/dist/schema/public.d.ts.map +1 -1
  20. package/dist/task/index.d.ts +35 -12
  21. package/dist/task/index.d.ts.map +1 -1
  22. package/dist/task/index.js +48 -11
  23. package/dist/task/public.d.ts +1 -1
  24. package/dist/task/public.d.ts.map +1 -1
  25. package/dist/task/public.js +1 -1
  26. package/dist/ui/dialog/index.d.ts +4 -4
  27. package/dist/ui/dialog/index.d.ts.map +1 -1
  28. package/dist/ui/dialog/index.js +4 -4
  29. package/dist/ui/disclosure/index.d.ts +4 -4
  30. package/dist/ui/disclosure/index.d.ts.map +1 -1
  31. package/dist/ui/disclosure/index.js +4 -4
  32. package/dist/ui/index.d.ts +1 -0
  33. package/dist/ui/index.d.ts.map +1 -1
  34. package/dist/ui/index.js +1 -0
  35. package/dist/ui/keyboard.d.ts +4 -0
  36. package/dist/ui/keyboard.d.ts.map +1 -0
  37. package/dist/ui/keyboard.js +7 -0
  38. package/dist/ui/menu/index.d.ts +136 -0
  39. package/dist/ui/menu/index.d.ts.map +1 -0
  40. package/dist/ui/menu/index.js +297 -0
  41. package/dist/ui/menu/public.d.ts +3 -0
  42. package/dist/ui/menu/public.d.ts.map +1 -0
  43. package/dist/ui/menu/public.js +1 -0
  44. package/dist/ui/tabs/index.d.ts +8 -10
  45. package/dist/ui/tabs/index.d.ts.map +1 -1
  46. package/dist/ui/tabs/index.js +11 -22
  47. package/dist/url/index.d.ts +1 -1
  48. package/package.json +10 -1
@@ -1,11 +1,11 @@
1
- import { DateTime, Effect } from 'effect';
1
+ import { DateTime, Duration, Effect } from 'effect';
2
2
  /**
3
3
  * Creates a command that gets the current UTC time and passes it to a message constructor.
4
4
  * This is similar to Elm's `Task.perform` with `Time.now`.
5
5
  *
6
6
  * @example
7
7
  * ```typescript
8
- * Task.getTime(utc => GotTime.make({ utc }))
8
+ * Task.getTime(utc => GotTime({ utc }))
9
9
  * ```
10
10
  */
11
11
  export declare const getTime: <Message>(f: (utc: DateTime.Utc) => Message) => Effect.Effect<Message>;
@@ -15,7 +15,7 @@ export declare const getTime: <Message>(f: (utc: DateTime.Utc) => Message) => Ef
15
15
  *
16
16
  * @example
17
17
  * ```typescript
18
- * Task.getTimeZone(zone => GotTimeZone.make({ zone }))
18
+ * Task.getTimeZone(zone => GotTimeZone({ zone }))
19
19
  * ```
20
20
  */
21
21
  export declare const getTimeZone: <Message>(f: (zone: DateTime.TimeZone) => Message) => Effect.Effect<Message>;
@@ -25,7 +25,7 @@ export declare const getTimeZone: <Message>(f: (zone: DateTime.TimeZone) => Mess
25
25
  *
26
26
  * @example
27
27
  * ```typescript
28
- * Task.getZonedTime(zoned => GotTime.make({ zoned }))
28
+ * Task.getZonedTime(zoned => GotTime({ zoned }))
29
29
  * ```
30
30
  */
31
31
  export declare const getZonedTime: <Message>(f: (zoned: DateTime.Zoned) => Message) => Effect.Effect<Message>;
@@ -35,52 +35,75 @@ export declare const getZonedTime: <Message>(f: (zoned: DateTime.Zoned) => Messa
35
35
  *
36
36
  * @example
37
37
  * ```typescript
38
- * Task.getZonedTimeIn('America/New_York', zoned => GotNYTime.make({ zoned }))
38
+ * Task.getZonedTimeIn('America/New_York', zoned => GotNYTime({ zoned }))
39
39
  * ```
40
40
  */
41
41
  export declare const getZonedTimeIn: <Message>(zoneId: string, f: (zoned: DateTime.Zoned) => Message) => Effect.Effect<Message, string>;
42
42
  /**
43
43
  * Creates a command that focuses an element by selector and passes the result to a message constructor.
44
- * Returns true if the element was found and focused, false otherwise.
44
+ * Passes true if the element was found and focused, false otherwise.
45
45
  * Uses requestAnimationFrame to ensure the DOM tree is updated and nodes exist before attempting to focus.
46
46
  * This follows the same approach as Elm's Browser.Dom.focus.
47
47
  *
48
48
  * @example
49
49
  * ```typescript
50
- * Task.focus('#email-input', success => InputFocused.make({ success }))
50
+ * Task.focus('#email-input', success => InputFocused({ success }))
51
51
  * ```
52
52
  */
53
53
  export declare const focus: <Message>(selector: string, f: (success: boolean) => Message) => Effect.Effect<Message>;
54
54
  /**
55
55
  * Creates a command that opens a dialog element as a modal using `showModal()`.
56
- * Returns true if the element was found and opened, false otherwise.
56
+ * Passes true if the element was found and opened, false otherwise.
57
57
  * Uses requestAnimationFrame to ensure the DOM tree is updated and nodes exist before attempting to show.
58
58
  *
59
59
  * @example
60
60
  * ```typescript
61
- * Task.showModal('#my-dialog', success => ModalOpened.make({ success }))
61
+ * Task.showModal('#my-dialog', success => ModalOpened({ success }))
62
62
  * ```
63
63
  */
64
64
  export declare const showModal: <Message>(selector: string, f: (success: boolean) => Message) => Effect.Effect<Message>;
65
65
  /**
66
66
  * Creates a command that closes a dialog element using `.close()`.
67
- * Returns true if the element was found and closed, false otherwise.
67
+ * Passes true if the element was found and closed, false otherwise.
68
68
  * Uses requestAnimationFrame to ensure the DOM tree is updated and nodes exist before attempting to close.
69
69
  *
70
70
  * @example
71
71
  * ```typescript
72
- * Task.closeModal('#my-dialog', success => ModalClosed.make({ success }))
72
+ * Task.closeModal('#my-dialog', success => ModalClosed({ success }))
73
73
  * ```
74
74
  */
75
75
  export declare const closeModal: <Message>(selector: string, f: (success: boolean) => Message) => Effect.Effect<Message>;
76
+ /**
77
+ * Creates a command that resolves to a message after a delay.
78
+ * Useful for debouncing, such as clearing a typeahead search query.
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * Task.delay(350, () => SearchCleared({ version: model.searchVersion }))
83
+ * Task.delay(Duration.seconds(1), () => TimedOut())
84
+ * ```
85
+ */
86
+ export declare const delay: <Message>(duration: Duration.DurationInput, f: () => Message) => Effect.Effect<Message>;
76
87
  /**
77
88
  * Creates a command that generates a random integer between min (inclusive) and max (exclusive)
78
89
  * and passes it to a message constructor.
79
90
  *
80
91
  * @example
81
92
  * ```typescript
82
- * Task.randomInt(0, 100, value => GotRandom.make({ value }))
93
+ * Task.randomInt(0, 100, value => GotRandom({ value }))
94
+ * ```
95
+ */
96
+ /**
97
+ * Creates a command that scrolls an element into view by selector and passes the result to a message constructor.
98
+ * Passes true if the element was found and scrolled, false otherwise.
99
+ * Uses requestAnimationFrame to ensure the DOM tree is updated and nodes exist before attempting to scroll.
100
+ * Uses `{ block: 'nearest' }` to avoid unnecessary scrolling when the element is already visible.
101
+ *
102
+ * @example
103
+ * ```typescript
104
+ * Task.scrollIntoView('#active-item', success => ItemScrolled({ success }))
83
105
  * ```
84
106
  */
107
+ export declare const scrollIntoView: <Message>(selector: string, f: (success: boolean) => Message) => Effect.Effect<Message>;
85
108
  export declare const randomInt: <Message>(min: number, max: number, f: (value: number) => Message) => Effect.Effect<Message>;
86
109
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/task/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAA;AAEjD;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,GAAI,OAAO,EAC7B,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,KAAK,OAAO,KAChC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAgC,CAAA;AAExD;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,EACjC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,KAAK,OAAO,KACtC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAmD,CAAA;AAE3E;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,EAClC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,KAAK,OAAO,KACpC,MAAM,CAAC,MAAM,CAAC,OAAO,CAMpB,CAAA;AAEJ;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,EACpC,QAAQ,MAAM,EACd,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,KAAK,OAAO,KACpC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAS5B,CAAA;AAEJ;;;;;;;;;;GAUG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,EAC3B,UAAU,MAAM,EAChB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,KAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,CAWpB,CAAA;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO,EAC/B,UAAU,MAAM,EAChB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,KAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,CAWpB,CAAA;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,GAAI,OAAO,EAChC,UAAU,MAAM,EAChB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,KAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,CAWpB,CAAA;AAEJ;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO,EAC/B,KAAK,MAAM,EACX,KAAK,MAAM,EACX,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,KAC5B,MAAM,CAAC,MAAM,CAAC,OAAO,CAC6C,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/task/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAA;AAE3D;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,GAAI,OAAO,EAC7B,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,KAAK,OAAO,KAChC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAgC,CAAA;AAExD;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,EACjC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,KAAK,OAAO,KACtC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAmD,CAAA;AAE3E;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,EAClC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,KAAK,OAAO,KACpC,MAAM,CAAC,MAAM,CAAC,OAAO,CAMpB,CAAA;AAEJ;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,EACpC,QAAQ,MAAM,EACd,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,KAAK,OAAO,KACpC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAS5B,CAAA;AAEJ;;;;;;;;;;GAUG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,EAC3B,UAAU,MAAM,EAChB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,KAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,CAWpB,CAAA;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO,EAC/B,UAAU,MAAM,EAChB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,KAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,CAWpB,CAAA;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,GAAI,OAAO,EAChC,UAAU,MAAM,EAChB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,KAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,CAWpB,CAAA;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,EAC3B,UAAU,QAAQ,CAAC,aAAa,EAChC,GAAG,MAAM,OAAO,KACf,MAAM,CAAC,MAAM,CAAC,OAAO,CAIpB,CAAA;AAEJ;;;;;;;;GAQG;AACH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,EACpC,UAAU,MAAM,EAChB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,KAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,CAWpB,CAAA;AAEJ,eAAO,MAAM,SAAS,GAAI,OAAO,EAC/B,KAAK,MAAM,EACX,KAAK,MAAM,EACX,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,KAC5B,MAAM,CAAC,MAAM,CAAC,OAAO,CAC6C,CAAA"}
@@ -5,7 +5,7 @@ import { DateTime, Effect, Option } from 'effect';
5
5
  *
6
6
  * @example
7
7
  * ```typescript
8
- * Task.getTime(utc => GotTime.make({ utc }))
8
+ * Task.getTime(utc => GotTime({ utc }))
9
9
  * ```
10
10
  */
11
11
  export const getTime = (f) => Effect.map(DateTime.now, f);
@@ -15,7 +15,7 @@ export const getTime = (f) => Effect.map(DateTime.now, f);
15
15
  *
16
16
  * @example
17
17
  * ```typescript
18
- * Task.getTimeZone(zone => GotTimeZone.make({ zone }))
18
+ * Task.getTimeZone(zone => GotTimeZone({ zone }))
19
19
  * ```
20
20
  */
21
21
  export const getTimeZone = (f) => Effect.sync(() => f(DateTime.zoneMakeLocal()));
@@ -25,7 +25,7 @@ export const getTimeZone = (f) => Effect.sync(() => f(DateTime.zoneMakeLocal()))
25
25
  *
26
26
  * @example
27
27
  * ```typescript
28
- * Task.getZonedTime(zoned => GotTime.make({ zoned }))
28
+ * Task.getZonedTime(zoned => GotTime({ zoned }))
29
29
  * ```
30
30
  */
31
31
  export const getZonedTime = (f) => Effect.gen(function* () {
@@ -40,7 +40,7 @@ export const getZonedTime = (f) => Effect.gen(function* () {
40
40
  *
41
41
  * @example
42
42
  * ```typescript
43
- * Task.getZonedTimeIn('America/New_York', zoned => GotNYTime.make({ zoned }))
43
+ * Task.getZonedTimeIn('America/New_York', zoned => GotNYTime({ zoned }))
44
44
  * ```
45
45
  */
46
46
  export const getZonedTimeIn = (zoneId, f) => Effect.gen(function* () {
@@ -54,13 +54,13 @@ export const getZonedTimeIn = (zoneId, f) => Effect.gen(function* () {
54
54
  });
55
55
  /**
56
56
  * Creates a command that focuses an element by selector and passes the result to a message constructor.
57
- * Returns true if the element was found and focused, false otherwise.
57
+ * Passes true if the element was found and focused, false otherwise.
58
58
  * Uses requestAnimationFrame to ensure the DOM tree is updated and nodes exist before attempting to focus.
59
59
  * This follows the same approach as Elm's Browser.Dom.focus.
60
60
  *
61
61
  * @example
62
62
  * ```typescript
63
- * Task.focus('#email-input', success => InputFocused.make({ success }))
63
+ * Task.focus('#email-input', success => InputFocused({ success }))
64
64
  * ```
65
65
  */
66
66
  export const focus = (selector, f) => Effect.async((resume) => {
@@ -77,12 +77,12 @@ export const focus = (selector, f) => Effect.async((resume) => {
77
77
  });
78
78
  /**
79
79
  * Creates a command that opens a dialog element as a modal using `showModal()`.
80
- * Returns true if the element was found and opened, false otherwise.
80
+ * Passes true if the element was found and opened, false otherwise.
81
81
  * Uses requestAnimationFrame to ensure the DOM tree is updated and nodes exist before attempting to show.
82
82
  *
83
83
  * @example
84
84
  * ```typescript
85
- * Task.showModal('#my-dialog', success => ModalOpened.make({ success }))
85
+ * Task.showModal('#my-dialog', success => ModalOpened({ success }))
86
86
  * ```
87
87
  */
88
88
  export const showModal = (selector, f) => Effect.async((resume) => {
@@ -99,12 +99,12 @@ export const showModal = (selector, f) => Effect.async((resume) => {
99
99
  });
100
100
  /**
101
101
  * Creates a command that closes a dialog element using `.close()`.
102
- * Returns true if the element was found and closed, false otherwise.
102
+ * Passes true if the element was found and closed, false otherwise.
103
103
  * Uses requestAnimationFrame to ensure the DOM tree is updated and nodes exist before attempting to close.
104
104
  *
105
105
  * @example
106
106
  * ```typescript
107
- * Task.closeModal('#my-dialog', success => ModalClosed.make({ success }))
107
+ * Task.closeModal('#my-dialog', success => ModalClosed({ success }))
108
108
  * ```
109
109
  */
110
110
  export const closeModal = (selector, f) => Effect.async((resume) => {
@@ -119,13 +119,50 @@ export const closeModal = (selector, f) => Effect.async((resume) => {
119
119
  }
120
120
  });
121
121
  });
122
+ /**
123
+ * Creates a command that resolves to a message after a delay.
124
+ * Useful for debouncing, such as clearing a typeahead search query.
125
+ *
126
+ * @example
127
+ * ```typescript
128
+ * Task.delay(350, () => SearchCleared({ version: model.searchVersion }))
129
+ * Task.delay(Duration.seconds(1), () => TimedOut())
130
+ * ```
131
+ */
132
+ export const delay = (duration, f) => Effect.gen(function* () {
133
+ yield* Effect.sleep(duration);
134
+ return f();
135
+ });
122
136
  /**
123
137
  * Creates a command that generates a random integer between min (inclusive) and max (exclusive)
124
138
  * and passes it to a message constructor.
125
139
  *
126
140
  * @example
127
141
  * ```typescript
128
- * Task.randomInt(0, 100, value => GotRandom.make({ value }))
142
+ * Task.randomInt(0, 100, value => GotRandom({ value }))
129
143
  * ```
130
144
  */
145
+ /**
146
+ * Creates a command that scrolls an element into view by selector and passes the result to a message constructor.
147
+ * Passes true if the element was found and scrolled, false otherwise.
148
+ * Uses requestAnimationFrame to ensure the DOM tree is updated and nodes exist before attempting to scroll.
149
+ * Uses `{ block: 'nearest' }` to avoid unnecessary scrolling when the element is already visible.
150
+ *
151
+ * @example
152
+ * ```typescript
153
+ * Task.scrollIntoView('#active-item', success => ItemScrolled({ success }))
154
+ * ```
155
+ */
156
+ export const scrollIntoView = (selector, f) => Effect.async((resume) => {
157
+ requestAnimationFrame(() => {
158
+ const element = document.querySelector(selector);
159
+ if (element instanceof HTMLElement) {
160
+ element.scrollIntoView({ block: 'nearest' });
161
+ resume(Effect.succeed(f(true)));
162
+ }
163
+ else {
164
+ resume(Effect.succeed(f(false)));
165
+ }
166
+ });
167
+ });
131
168
  export const randomInt = (min, max, f) => Effect.sync(() => f(Math.floor(Math.random() * (max - min)) + min));
@@ -1,2 +1,2 @@
1
- export { getTime, getTimeZone, getZonedTime, getZonedTimeIn, focus, randomInt, } from './index';
1
+ export { getTime, getTimeZone, getZonedTime, getZonedTimeIn, focus, showModal, closeModal, delay, scrollIntoView, randomInt, } from './index';
2
2
  //# sourceMappingURL=public.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/task/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,WAAW,EACX,YAAY,EACZ,cAAc,EACd,KAAK,EACL,SAAS,GACV,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/task/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,WAAW,EACX,YAAY,EACZ,cAAc,EACd,KAAK,EACL,SAAS,EACT,UAAU,EACV,KAAK,EACL,cAAc,EACd,SAAS,GACV,MAAM,SAAS,CAAA"}
@@ -1 +1 @@
1
- export { getTime, getTimeZone, getZonedTime, getZonedTimeIn, focus, randomInt, } from './index';
1
+ export { getTime, getTimeZone, getZonedTime, getZonedTimeIn, focus, showModal, closeModal, delay, scrollIntoView, randomInt, } from './index';
@@ -8,13 +8,13 @@ export declare const Model: S.Struct<{
8
8
  }>;
9
9
  export type Model = typeof Model.Type;
10
10
  /** Sent when the dialog should open. Triggers the showModal command. */
11
- export declare const Opened: S.TaggedStruct<"Opened", {}>;
11
+ export declare const Opened: import("../../schema").CallableTaggedStruct<"Opened", {}>;
12
12
  /** Sent when the dialog should close (Escape key, backdrop click, or programmatic). Triggers the closeModal command. */
13
- export declare const Closed: S.TaggedStruct<"Closed", {}>;
13
+ export declare const Closed: import("../../schema").CallableTaggedStruct<"Closed", {}>;
14
14
  /** Placeholder message used when no action is needed, such as after a showModal or closeModal command completes. */
15
- export declare const NoOp: S.TaggedStruct<"NoOp", {}>;
15
+ export declare const NoOp: import("../../schema").CallableTaggedStruct<"NoOp", {}>;
16
16
  /** Union of all messages the dialog component can produce. */
17
- export declare const Message: S.Union<[S.TaggedStruct<"Opened", {}>, S.TaggedStruct<"Closed", {}>, S.TaggedStruct<"NoOp", {}>]>;
17
+ export declare const Message: S.Union<[import("../../schema").CallableTaggedStruct<"Opened", {}>, import("../../schema").CallableTaggedStruct<"Closed", {}>, import("../../schema").CallableTaggedStruct<"NoOp", {}>]>;
18
18
  export type Opened = typeof Opened.Type;
19
19
  export type Closed = typeof Closed.Type;
20
20
  export type NoOp = typeof NoOp.Type;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/dialog/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAGxD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAOpD,8FAA8F;AAC9F,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,wEAAwE;AACxE,eAAO,MAAM,MAAM,8BAAe,CAAA;AAClC,wHAAwH;AACxH,eAAO,MAAM,MAAM,8BAAe,CAAA;AAClC,oHAAoH;AACpH,eAAO,MAAM,IAAI,4BAAa,CAAA;AAE9B,8DAA8D;AAC9D,eAAO,MAAM,OAAO,mGAAgC,CAAA;AAEpD,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAA;AAEnC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,6DAA6D;AAC7D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAC,CAAA;AAEF,yEAAyE;AACzE,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAGxC,CAAA;AAMF,0EAA0E;AAC1E,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CA4BvC,CAAA;AAIH,iGAAiG;AACjG,eAAO,MAAM,OAAO,GAAI,OAAO,KAAK,KAAG,MAA6B,CAAA;AAEpE,wGAAwG;AACxG,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,KAAG,MAAmC,CAAA;AAEhF,wDAAwD;AACxD,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAA;IAC9C,YAAY,EAAE,IAAI,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAC,CAAA;AAEF,sGAAsG;AACtG,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,QAAQ,UAAU,CAAC,OAAO,CAAC,KAAG,IA6C3D,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/dialog/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAGxD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAOpD,8FAA8F;AAC9F,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,wEAAwE;AACxE,eAAO,MAAM,MAAM,2DAAe,CAAA;AAClC,wHAAwH;AACxH,eAAO,MAAM,MAAM,2DAAe,CAAA;AAClC,oHAAoH;AACpH,eAAO,MAAM,IAAI,yDAAa,CAAA;AAE9B,8DAA8D;AAC9D,eAAO,MAAM,OAAO,0LAAgC,CAAA;AAEpD,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAA;AAEnC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,6DAA6D;AAC7D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAC,CAAA;AAEF,yEAAyE;AACzE,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAGxC,CAAA;AAMF,0EAA0E;AAC1E,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CA4BvC,CAAA;AAIH,iGAAiG;AACjG,eAAO,MAAM,OAAO,GAAI,OAAO,KAAK,KAAG,MAA6B,CAAA;AAEpE,wGAAwG;AACxG,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,KAAG,MAAmC,CAAA;AAEhF,wDAAwD;AACxD,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAA;IAC9C,YAAY,EAAE,IAAI,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAC,CAAA;AAEF,sGAAsG;AACtG,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,QAAQ,UAAU,CAAC,OAAO,CAAC,KAAG,IA6C3D,CAAA"}
@@ -28,14 +28,14 @@ const dialogSelector = (id) => `#${id}`;
28
28
  /** Processes a dialog message and returns the next model and commands. */
29
29
  export const update = (model, message) => M.value(message).pipe(M.withReturnType(), M.tagsExhaustive({
30
30
  Opened: () => {
31
- const maybeShowCommand = Option.liftPredicate(Task.showModal(dialogSelector(model.id), () => NoOp.make()), () => !model.isOpen);
31
+ const maybeShowCommand = Option.liftPredicate(Task.showModal(dialogSelector(model.id), () => NoOp()), () => !model.isOpen);
32
32
  return [
33
33
  evo(model, { isOpen: () => true }),
34
34
  Option.toArray(maybeShowCommand),
35
35
  ];
36
36
  },
37
37
  Closed: () => {
38
- const maybeCloseCommand = Option.liftPredicate(Task.closeModal(dialogSelector(model.id), () => NoOp.make()), () => model.isOpen);
38
+ const maybeCloseCommand = Option.liftPredicate(Task.closeModal(dialogSelector(model.id), () => NoOp()), () => model.isOpen);
39
39
  return [
40
40
  evo(model, { isOpen: () => false }),
41
41
  Option.toArray(maybeCloseCommand),
@@ -56,11 +56,11 @@ export const view = (config) => {
56
56
  Id(id),
57
57
  AriaLabelledBy(`${id}-title`),
58
58
  AriaDescribedBy(`${id}-description`),
59
- OnCancel(toMessage(Closed.make())),
59
+ OnCancel(toMessage(Closed())),
60
60
  ...(isOpen ? [DataAttribute('open', '')] : []),
61
61
  ...(className ? [Class(className)] : []),
62
62
  ];
63
- const backdrop = keyed('div')(`${id}-backdrop`, [Class(backdropClassName), OnClick(toMessage(Closed.make()))], []);
63
+ const backdrop = keyed('div')(`${id}-backdrop`, [Class(backdropClassName), OnClick(toMessage(Closed()))], []);
64
64
  const panel = keyed('div')(`${id}-panel`, [Class(panelClassName)], [panelContent]);
65
65
  const content = isOpen ? [backdrop, panel] : [];
66
66
  return keyed('dialog')(id, dialogAttributes, content);
@@ -8,13 +8,13 @@ export declare const Model: S.Struct<{
8
8
  }>;
9
9
  export type Model = typeof Model.Type;
10
10
  /** Sent when the disclosure button is clicked. Toggles the open/closed state. */
11
- export declare const Toggled: S.TaggedStruct<"Toggled", {}>;
11
+ export declare const Toggled: import("../../schema").CallableTaggedStruct<"Toggled", {}>;
12
12
  /** Sent to explicitly close the disclosure, regardless of its current state. */
13
- export declare const Closed: S.TaggedStruct<"Closed", {}>;
13
+ export declare const Closed: import("../../schema").CallableTaggedStruct<"Closed", {}>;
14
14
  /** Placeholder message used when no action is needed, such as after a focus command completes. */
15
- export declare const NoOp: S.TaggedStruct<"NoOp", {}>;
15
+ export declare const NoOp: import("../../schema").CallableTaggedStruct<"NoOp", {}>;
16
16
  /** Union of all messages the disclosure component can produce. */
17
- export declare const Message: S.Union<[S.TaggedStruct<"Toggled", {}>, S.TaggedStruct<"Closed", {}>, S.TaggedStruct<"NoOp", {}>]>;
17
+ export declare const Message: S.Union<[import("../../schema").CallableTaggedStruct<"Toggled", {}>, import("../../schema").CallableTaggedStruct<"Closed", {}>, import("../../schema").CallableTaggedStruct<"NoOp", {}>]>;
18
18
  export type Toggled = typeof Toggled.Type;
19
19
  export type Closed = typeof Closed.Type;
20
20
  export type NoOp = typeof NoOp.Type;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/disclosure/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAGxD,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAOpD,kGAAkG;AAClG,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,iFAAiF;AACjF,eAAO,MAAM,OAAO,+BAAgB,CAAA;AACpC,gFAAgF;AAChF,eAAO,MAAM,MAAM,8BAAe,CAAA;AAClC,kGAAkG;AAClG,eAAO,MAAM,IAAI,4BAAa,CAAA;AAE9B,kEAAkE;AAClE,eAAO,MAAM,OAAO,oGAAiC,CAAA;AAErD,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AACzC,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAA;AAEnC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,iEAAiE;AACjE,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAC,CAAA;AAEF,6EAA6E;AAC7E,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAGxC,CAAA;AAQF,8EAA8E;AAC9E,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CA4BvC,CAAA;AAIH,4DAA4D;AAC5D,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,KAAK,OAAO,CAAA;IACxD,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,IAAI,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;IACtB,YAAY,EAAE,IAAI,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAC,CAAA;AAEF,oGAAoG;AACpG,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,QAAQ,UAAU,CAAC,OAAO,CAAC,KAAG,IAyF3D,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/disclosure/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAGxD,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAOpD,kGAAkG;AAClG,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,iFAAiF;AACjF,eAAO,MAAM,OAAO,4DAAgB,CAAA;AACpC,gFAAgF;AAChF,eAAO,MAAM,MAAM,2DAAe,CAAA;AAClC,kGAAkG;AAClG,eAAO,MAAM,IAAI,yDAAa,CAAA;AAE9B,kEAAkE;AAClE,eAAO,MAAM,OAAO,2LAAiC,CAAA;AAErD,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AACzC,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAA;AAEnC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,iEAAiE;AACjE,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAC,CAAA;AAEF,6EAA6E;AAC7E,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAGxC,CAAA;AAQF,8EAA8E;AAC9E,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CA4BvC,CAAA;AAIH,4DAA4D;AAC5D,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,KAAK,OAAO,CAAA;IACxD,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,IAAI,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;IACtB,YAAY,EAAE,IAAI,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAC,CAAA;AAEF,oGAAoG;AACpG,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,QAAQ,UAAU,CAAC,OAAO,CAAC,KAAG,IAyF3D,CAAA"}
@@ -29,14 +29,14 @@ const panelId = (id) => `${id}-panel`;
29
29
  /** Processes a disclosure message and returns the next model and commands. */
30
30
  export const update = (model, message) => M.value(message).pipe(M.withReturnType(), M.tagsExhaustive({
31
31
  Toggled: () => {
32
- const maybeFocusCommand = Option.liftPredicate(Task.focus(`#${buttonId(model.id)}`, () => NoOp.make()), () => model.isOpen);
32
+ const maybeFocusCommand = Option.liftPredicate(Task.focus(`#${buttonId(model.id)}`, () => NoOp()), () => model.isOpen);
33
33
  return [
34
34
  evo(model, { isOpen: () => !model.isOpen }),
35
35
  Option.toArray(maybeFocusCommand),
36
36
  ];
37
37
  },
38
38
  Closed: () => {
39
- const maybeFocusCommand = Option.liftPredicate(Task.focus(`#${buttonId(model.id)}`, () => NoOp.make()), () => model.isOpen);
39
+ const maybeFocusCommand = Option.liftPredicate(Task.focus(`#${buttonId(model.id)}`, () => NoOp()), () => model.isOpen);
40
40
  return [
41
41
  evo(model, { isOpen: () => false }),
42
42
  Option.toArray(maybeFocusCommand),
@@ -51,7 +51,7 @@ export const view = (config) => {
51
51
  const isNativeButton = buttonElement === 'button';
52
52
  const handleKeyDown = (key) =>
53
53
  /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
54
- M.value(key).pipe(M.whenOr('Enter', ' ', () => toMessage(Toggled.make())), M.orElse(() => toMessage(NoOp.make())));
54
+ M.value(key).pipe(M.whenOr('Enter', ' ', () => toMessage(Toggled())), M.orElse(() => toMessage(NoOp())));
55
55
  const disabledAttributes = [
56
56
  Disabled(true),
57
57
  AriaDisabled(true),
@@ -60,7 +60,7 @@ export const view = (config) => {
60
60
  const interactionAttributes = isDisabled
61
61
  ? disabledAttributes
62
62
  : [
63
- OnClick(toMessage(Toggled.make())),
63
+ OnClick(toMessage(Toggled())),
64
64
  ...(!isNativeButton ? [OnKeyDown(handleKeyDown)] : []),
65
65
  ];
66
66
  const buttonAttributes = [
@@ -1,4 +1,5 @@
1
1
  export * as Dialog from './dialog/public';
2
2
  export * as Disclosure from './disclosure/public';
3
+ export * as Menu from './menu/public';
3
4
  export * as Tabs from './tabs/public';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;AACzC,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,IAAI,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;AACzC,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,IAAI,MAAM,eAAe,CAAA;AACrC,OAAO,KAAK,IAAI,MAAM,eAAe,CAAA"}
package/dist/ui/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * as Dialog from './dialog/public';
2
2
  export * as Disclosure from './disclosure/public';
3
+ export * as Menu from './menu/public';
3
4
  export * as Tabs from './tabs/public';
@@ -0,0 +1,4 @@
1
+ export declare const wrapIndex: (index: number, length: number) => number;
2
+ export declare const findFirstEnabledIndex: (itemCount: number, focusedIndex: number, isDisabled: (index: number) => boolean) => (startIndex: number, direction: 1 | -1) => number;
3
+ export declare const keyToIndex: (nextKey: string, previousKey: string, itemCount: number, focusedIndex: number, isDisabled: (index: number) => boolean) => ((key: string) => number);
4
+ //# sourceMappingURL=keyboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../src/ui/keyboard.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS,GAAI,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAG,MACpB,CAAA;AAEtC,eAAO,MAAM,qBAAqB,GAE9B,WAAW,MAAM,EACjB,cAAc,MAAM,EACpB,YAAY,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,MAEvC,YAAY,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,KAAG,MAQtC,CAAA;AAEL,eAAO,MAAM,UAAU,GACrB,SAAS,MAAM,EACf,aAAa,MAAM,EACnB,WAAW,MAAM,EACjB,cAAc,MAAM,EACpB,YAAY,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,KACrC,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAW1B,CAAA"}
@@ -0,0 +1,7 @@
1
+ import { Array, Match as M, Option, Predicate, pipe } from 'effect';
2
+ export const wrapIndex = (index, length) => ((index % length) + length) % length;
3
+ export const findFirstEnabledIndex = (itemCount, focusedIndex, isDisabled) => (startIndex, direction) => pipe(itemCount, Array.makeBy((step) => wrapIndex(startIndex + step * direction, itemCount)), Array.findFirst(Predicate.not(isDisabled)), Option.getOrElse(() => focusedIndex));
4
+ export const keyToIndex = (nextKey, previousKey, itemCount, focusedIndex, isDisabled) => {
5
+ const find = findFirstEnabledIndex(itemCount, focusedIndex, isDisabled);
6
+ return (key) => M.value(key).pipe(M.when(nextKey, () => find(focusedIndex + 1, 1)), M.when(previousKey, () => find(focusedIndex - 1, -1)), M.whenOr('Home', 'PageUp', () => find(0, 1)), M.whenOr('End', 'PageDown', () => find(itemCount - 1, -1)), M.orElse(() => focusedIndex));
7
+ };
@@ -0,0 +1,136 @@
1
+ import { Option, Schema as S } from 'effect';
2
+ import type { Html } from '../../html';
3
+ import type { Command } from '../../runtime/runtime';
4
+ /** Schema for the activation trigger — whether the user interacted via mouse or keyboard. */
5
+ export declare const ActivationTrigger: S.Literal<["Pointer", "Keyboard"]>;
6
+ export type ActivationTrigger = typeof ActivationTrigger.Type;
7
+ /** Schema for the menu component's state, tracking open/closed status, active item, activation trigger, and typeahead search. */
8
+ export declare const Model: S.Struct<{
9
+ id: typeof S.String;
10
+ isOpen: typeof S.Boolean;
11
+ maybeActiveItemIndex: S.OptionFromSelf<typeof S.Number>;
12
+ activationTrigger: S.Literal<["Pointer", "Keyboard"]>;
13
+ searchQuery: typeof S.String;
14
+ searchVersion: typeof S.Number;
15
+ maybeLastPointerPosition: S.OptionFromSelf<S.Struct<{
16
+ screenX: typeof S.Number;
17
+ screenY: typeof S.Number;
18
+ }>>;
19
+ }>;
20
+ export type Model = typeof Model.Type;
21
+ /** Sent when the menu opens via button click or keyboard. Contains an optional initial active item index — None for pointer, Some for keyboard. */
22
+ export declare const Opened: import("../../schema").CallableTaggedStruct<"Opened", {
23
+ maybeActiveItemIndex: S.OptionFromSelf<typeof S.Number>;
24
+ }>;
25
+ /** Sent when the menu closes via Escape key or backdrop click. */
26
+ export declare const Closed: import("../../schema").CallableTaggedStruct<"Closed", {}>;
27
+ /** Sent when focus leaves the menu items container via Tab key. */
28
+ export declare const ClosedByTab: import("../../schema").CallableTaggedStruct<"ClosedByTab", {}>;
29
+ /** Sent when an item is highlighted via arrow keys or mouse hover. Includes activation trigger. */
30
+ export declare const ItemActivated: import("../../schema").CallableTaggedStruct<"ItemActivated", {
31
+ index: typeof S.Number;
32
+ activationTrigger: S.Literal<["Pointer", "Keyboard"]>;
33
+ }>;
34
+ /** Sent when the mouse leaves an enabled item. */
35
+ export declare const ItemDeactivated: import("../../schema").CallableTaggedStruct<"ItemDeactivated", {}>;
36
+ /** Sent when an item is selected via Enter, Space, or click. */
37
+ export declare const ItemSelected: import("../../schema").CallableTaggedStruct<"ItemSelected", {
38
+ index: typeof S.Number;
39
+ }>;
40
+ /** Sent when a printable character is typed for typeahead search. */
41
+ export declare const Searched: import("../../schema").CallableTaggedStruct<"Searched", {
42
+ key: typeof S.String;
43
+ maybeTargetIndex: S.OptionFromSelf<typeof S.Number>;
44
+ }>;
45
+ /** Sent after the search debounce period to clear the accumulated query. */
46
+ export declare const SearchCleared: import("../../schema").CallableTaggedStruct<"SearchCleared", {
47
+ version: typeof S.Number;
48
+ }>;
49
+ /** Sent when the pointer moves over a menu item, carrying screen coordinates for tracked-pointer comparison. */
50
+ export declare const PointerMovedOverItem: import("../../schema").CallableTaggedStruct<"PointerMovedOverItem", {
51
+ index: typeof S.Number;
52
+ screenX: typeof S.Number;
53
+ screenY: typeof S.Number;
54
+ }>;
55
+ /** Placeholder message used when no action is needed. */
56
+ export declare const NoOp: import("../../schema").CallableTaggedStruct<"NoOp", {}>;
57
+ /** Union of all messages the menu component can produce. */
58
+ export declare const Message: S.Union<[import("../../schema").CallableTaggedStruct<"Opened", {
59
+ maybeActiveItemIndex: S.OptionFromSelf<typeof S.Number>;
60
+ }>, import("../../schema").CallableTaggedStruct<"Closed", {}>, import("../../schema").CallableTaggedStruct<"ClosedByTab", {}>, import("../../schema").CallableTaggedStruct<"ItemActivated", {
61
+ index: typeof S.Number;
62
+ activationTrigger: S.Literal<["Pointer", "Keyboard"]>;
63
+ }>, import("../../schema").CallableTaggedStruct<"ItemDeactivated", {}>, import("../../schema").CallableTaggedStruct<"ItemSelected", {
64
+ index: typeof S.Number;
65
+ }>, import("../../schema").CallableTaggedStruct<"PointerMovedOverItem", {
66
+ index: typeof S.Number;
67
+ screenX: typeof S.Number;
68
+ screenY: typeof S.Number;
69
+ }>, import("../../schema").CallableTaggedStruct<"Searched", {
70
+ key: typeof S.String;
71
+ maybeTargetIndex: S.OptionFromSelf<typeof S.Number>;
72
+ }>, import("../../schema").CallableTaggedStruct<"SearchCleared", {
73
+ version: typeof S.Number;
74
+ }>, import("../../schema").CallableTaggedStruct<"NoOp", {}>]>;
75
+ export type Opened = typeof Opened.Type;
76
+ export type Closed = typeof Closed.Type;
77
+ export type ClosedByTab = typeof ClosedByTab.Type;
78
+ export type ItemActivated = typeof ItemActivated.Type;
79
+ export type ItemDeactivated = typeof ItemDeactivated.Type;
80
+ export type ItemSelected = typeof ItemSelected.Type;
81
+ export type PointerMovedOverItem = typeof PointerMovedOverItem.Type;
82
+ export type Searched = typeof Searched.Type;
83
+ export type SearchCleared = typeof SearchCleared.Type;
84
+ export type NoOp = typeof NoOp.Type;
85
+ export type Message = typeof Message.Type;
86
+ /** Configuration for creating a menu model with `init`. */
87
+ export type InitConfig = Readonly<{
88
+ id: string;
89
+ }>;
90
+ /** Creates an initial menu model from a config. Defaults to closed with no active item. */
91
+ export declare const init: (config: InitConfig) => Model;
92
+ /** Processes a menu message and returns the next model and commands. */
93
+ export declare const update: (model: Model, message: Message) => [Model, ReadonlyArray<Command<Message>>];
94
+ /** Configuration for an individual menu item's appearance. */
95
+ export type ItemConfig = Readonly<{
96
+ className: string;
97
+ content: Html;
98
+ }>;
99
+ /** Configuration for a group heading rendered above a group of items. */
100
+ export type GroupHeading = Readonly<{
101
+ content: Html;
102
+ className: string;
103
+ }>;
104
+ /** Configuration for rendering a menu with `view`. */
105
+ export type ViewConfig<Message, Item extends string> = Readonly<{
106
+ model: Model;
107
+ toMessage: (message: Opened | Closed | ClosedByTab | ItemActivated | ItemDeactivated | ItemSelected | PointerMovedOverItem | Searched) => Message;
108
+ items: ReadonlyArray<Item>;
109
+ itemToConfig: (item: Item, context: Readonly<{
110
+ isActive: boolean;
111
+ isDisabled: boolean;
112
+ }>) => ItemConfig;
113
+ isItemDisabled?: (item: Item, index: number) => boolean;
114
+ itemToSearchText?: (item: Item, index: number) => string;
115
+ isButtonDisabled?: boolean;
116
+ buttonContent: Html;
117
+ buttonClassName: string;
118
+ itemsClassName: string;
119
+ backdropClassName: string;
120
+ className?: string;
121
+ itemGroupKey?: (item: Item, index: number) => string;
122
+ groupToHeading?: (groupKey: string) => GroupHeading | undefined;
123
+ groupClassName?: string;
124
+ separatorClassName?: string;
125
+ }>;
126
+ type Segment<A> = Readonly<{
127
+ key: string;
128
+ items: ReadonlyArray<A>;
129
+ }>;
130
+ export declare const groupContiguous: <A>(items: ReadonlyArray<A>, toKey: (item: A, index: number) => string) => ReadonlyArray<Segment<A>>;
131
+ /** 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. */
132
+ export declare const resolveTypeaheadMatch: <Item extends string>(items: ReadonlyArray<Item>, query: string, maybeActiveItemIndex: Option.Option<number>, isDisabled: (index: number) => boolean, itemToSearchText: (item: Item, index: number) => string, isRefinement: boolean) => Option.Option<number>;
133
+ /** Renders a headless menu with typeahead search, keyboard navigation, and aria-activedescendant focus management. */
134
+ export declare const view: <Message, Item extends string>(config: ViewConfig<Message, Item>) => Html;
135
+ export {};
136
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/menu/index.ts"],"names":[],"mappings":"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"}