foldkit 0.162.0 → 0.163.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/README.md +4 -4
- package/dist/asyncData/asyncData.d.ts +1 -1
- package/dist/asyncData/asyncData.js +1 -1
- package/dist/devTools/store.d.ts.map +1 -1
- package/dist/devTools/store.js +16 -16
- package/dist/experimental/machine/machine.d.ts +4 -4
- package/dist/experimental/machine/machine.js +3 -3
- package/dist/experimental/server/server.d.ts +9 -6
- package/dist/experimental/server/server.d.ts.map +1 -1
- package/dist/experimental/server/server.js +3 -28
- package/dist/html/index.d.ts +31 -20
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +1 -1
- package/dist/runtime/deepFreeze.d.ts +1 -1
- package/dist/runtime/deepFreeze.js +1 -1
- package/dist/runtime/documentMetadata.d.ts.map +1 -1
- package/dist/runtime/documentMetadata.js +69 -47
- package/dist/runtime/managedResourceFibers.d.ts +1 -1
- package/dist/runtime/managedResourceFibers.d.ts.map +1 -1
- package/dist/runtime/managedResourceFibers.js +3 -2
- package/dist/runtime/subscriptionFibers.d.ts +1 -1
- package/dist/runtime/subscriptionFibers.d.ts.map +1 -1
- package/dist/runtime/subscriptionFibers.js +3 -2
- package/dist/struct/index.d.ts +4 -4
- package/dist/struct/index.d.ts.map +1 -1
- package/dist/struct/index.js +4 -4
- package/dist/struct/public.d.ts +1 -1
- package/dist/struct/public.d.ts.map +1 -1
- package/dist/struct/public.js +1 -1
- package/dist/submodel/submodel.d.ts +3 -3
- package/dist/subscription/fromEvent.d.ts +47 -33
- package/dist/subscription/fromEvent.d.ts.map +1 -1
- package/dist/subscription/fromEvent.js +30 -25
- package/dist/subscription/keyBindings.d.ts +13 -11
- package/dist/subscription/keyBindings.d.ts.map +1 -1
- package/dist/subscription/keyBindings.js +9 -7
- package/dist/subscription/public.d.ts +1 -1
- package/dist/subscription/public.d.ts.map +1 -1
- package/dist/test/apps/bubbling.js +5 -5
- package/dist/test/apps/colorPicker.js +2 -2
- package/dist/test/apps/contentEditableEditor.js +3 -3
- package/dist/test/apps/contextMenu.js +2 -2
- package/dist/test/apps/counter.d.ts.map +1 -1
- package/dist/test/apps/counter.js +8 -5
- package/dist/test/apps/crashOnRender.js +3 -3
- package/dist/test/apps/drafts.js +3 -3
- package/dist/test/apps/feedSocket.js +5 -5
- package/dist/test/apps/fileUpload.js +2 -2
- package/dist/test/apps/focusBoundary.js +3 -3
- package/dist/test/apps/formChild.js +4 -4
- package/dist/test/apps/interactions.js +7 -7
- package/dist/test/apps/keypress.js +3 -3
- package/dist/test/apps/keypressSelf.js +2 -2
- package/dist/test/apps/login.js +7 -7
- package/dist/test/apps/mountPanel.js +4 -4
- package/dist/test/apps/multiRole.js +2 -2
- package/dist/test/apps/pointer.d.ts +5 -1
- package/dist/test/apps/pointer.d.ts.map +1 -1
- package/dist/test/apps/pointer.js +16 -7
- package/dist/test/apps/resumeUpload.js +5 -5
- package/dist/test/apps/scorePanel.js +2 -2
- package/dist/test/apps/selectiveKeys.d.ts.map +1 -1
- package/dist/test/apps/selectiveKeys.js +5 -3
- package/dist/test/apps/uploads.d.ts.map +1 -1
- package/dist/test/apps/uploads.js +13 -7
- package/dist/test/query.js +5 -5
- package/dist/test/scene.d.ts +6 -2
- package/dist/test/scene.d.ts.map +1 -1
- package/dist/test/scene.js +27 -3
- package/dist/update/update.d.ts +4 -4
- package/dist/update/update.js +3 -3
- package/package.json +6 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, Option, Record, Ref, Schema, Stream, pipe, } from 'effect';
|
|
1
|
+
import { Effect, Option, PubSub, Record, Ref, Schema, Scope, Stream, pipe, } from 'effect';
|
|
2
2
|
import { measureSlowPhase, reportSlowPhase, } from './slowPhase.js';
|
|
3
3
|
/**
|
|
4
4
|
* Forks one fiber per Subscription into the runtime scope. Each fiber
|
|
@@ -18,7 +18,8 @@ export const forkSubscriptionFibers = ({ subscriptions, initModel, modelPubSub,
|
|
|
18
18
|
thresholdMs,
|
|
19
19
|
}));
|
|
20
20
|
const latestDependenciesRef = yield* Ref.make(initDependencies);
|
|
21
|
-
const
|
|
21
|
+
const modelSubscription = yield* PubSub.subscribe(modelPubSub).pipe(Effect.provideService(Scope.Scope, runtimeScope));
|
|
22
|
+
const modelChangesStream = Stream.fromSubscription(modelSubscription).pipe(
|
|
22
23
|
// NOTE: Ref.set runs upstream of Stream.changesWith on
|
|
23
24
|
// every model change, so readDependencies() returns
|
|
24
25
|
// current values even when the equivalence filter
|
package/dist/struct/index.d.ts
CHANGED
|
@@ -7,12 +7,12 @@ type StrictKeys<O, T> = T extends Record<string, any> ? Exclude<keyof T, keyof O
|
|
|
7
7
|
type Evolved<O, T> = {
|
|
8
8
|
[K in keyof O]: K extends keyof T ? T[K] extends (a: any) => infer R ? R : O[K] : O[K];
|
|
9
9
|
};
|
|
10
|
-
/** Immutably
|
|
11
|
-
export declare const
|
|
10
|
+
/** Immutably modifies fields of a struct by applying transform functions. Each transformer must return its field's existing type. Wraps Effect's `Struct.evolve` with stricter key checking. */
|
|
11
|
+
export declare const modifyFields: {
|
|
12
12
|
<O, const T extends EvolveTransform<O>>(t: StrictKeys<O, T>): (obj: O) => Evolved<O, T>;
|
|
13
13
|
<O, const T extends EvolveTransform<O>>(obj: O, t: StrictKeys<O, T>): Evolved<O, T>;
|
|
14
14
|
};
|
|
15
|
-
/** Creates a
|
|
16
|
-
export declare const
|
|
15
|
+
/** Creates a field modifier for a base shape. Use in generic helpers whose Model extends that shape. Transformers are checked against the base shape, and the returned function preserves the Model's subtype and all fields not in the transform. */
|
|
16
|
+
export declare const makeModifyFieldsFor: <Base extends Record<string, unknown>>() => <Model extends Base>(model: Model, transforms: EvolveTransform<Base>) => Model;
|
|
17
17
|
export {};
|
|
18
18
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/struct/index.ts"],"names":[],"mappings":"AAEA,KAAK,eAAe,CAAC,CAAC,IAAI,OAAO,CAAC;KAC/B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;CAClC,CAAC,CAAA;AAEF,KAAK,UAAU,CAAC,CAAC,EAAE,CAAC,IAClB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACzB,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,SAAS,KAAK,GACrC,CAAC,GACD,CAAC,GAAG;KACD,CAAC,IAAI,gBAAgB,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,EAAE,GAAG,KAAK;CACnE,GACH,KAAK,CAAA;AAEX,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI;KAClB,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,GAC7B,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,KAAK,MAAM,CAAC,GAC9B,CAAC,GACD,CAAC,CAAC,CAAC,CAAC,GACN,CAAC,CAAC,CAAC,CAAC;CACT,CAAA;AAED,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/struct/index.ts"],"names":[],"mappings":"AAEA,KAAK,eAAe,CAAC,CAAC,IAAI,OAAO,CAAC;KAC/B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;CAClC,CAAC,CAAA;AAEF,KAAK,UAAU,CAAC,CAAC,EAAE,CAAC,IAClB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACzB,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,SAAS,KAAK,GACrC,CAAC,GACD,CAAC,GAAG;KACD,CAAC,IAAI,gBAAgB,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,EAAE,GAAG,KAAK;CACnE,GACH,KAAK,CAAA;AAEX,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI;KAClB,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,GAC7B,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,KAAK,MAAM,CAAC,GAC9B,CAAC,GACD,CAAC,CAAC,CAAC,CAAC,GACN,CAAC,CAAC,CAAC,CAAC;CACT,CAAA;AAED,gMAAgM;AAChM,eAAO,MAAM,YAAY,EAAE;IACzB,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,SAAS,eAAe,CAAC,CAAC,CAAC,EACpC,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,GAClB,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC5B,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,SAAS,eAAe,CAAC,CAAC,CAAC,EACpC,GAAG,EAAE,CAAC,EACN,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,GAClB,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;CACD,CAAA;AAEjB,sPAAsP;AACtP,eAAO,MAAM,mBAAmB,GAC7B,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,QACpC,KAAK,SAAS,IAAI,SACV,KAAK,cACA,eAAe,CAAC,IAAI,CAAC,KAChC,KAE+C,CAAA"}
|
package/dist/struct/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Struct } from 'effect';
|
|
2
|
-
/** Immutably
|
|
3
|
-
export const
|
|
4
|
-
/** Creates a
|
|
5
|
-
export const
|
|
2
|
+
/** Immutably modifies fields of a struct by applying transform functions. Each transformer must return its field's existing type. Wraps Effect's `Struct.evolve` with stricter key checking. */
|
|
3
|
+
export const modifyFields = Struct.evolve;
|
|
4
|
+
/** Creates a field modifier for a base shape. Use in generic helpers whose Model extends that shape. Transformers are checked against the base shape, and the returned function preserves the Model's subtype and all fields not in the transform. */
|
|
5
|
+
export const makeModifyFieldsFor = () => (model, transforms) =>
|
|
6
6
|
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
7
7
|
Struct.evolve(model, transforms);
|
package/dist/struct/public.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { modifyFields, makeModifyFieldsFor } from './index.js';
|
|
2
2
|
//# sourceMappingURL=public.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/struct/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/struct/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA"}
|
package/dist/struct/public.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { modifyFields, makeModifyFieldsFor } from './index.js';
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Being dual, it reads two ways. Data-first sets the field and returns the
|
|
11
11
|
* model; data-last returns `(model) => model`, which slots point-free into
|
|
12
|
-
*
|
|
12
|
+
* a `modifyFields` callback:
|
|
13
13
|
*
|
|
14
14
|
* ```ts
|
|
15
15
|
* // data-first
|
|
16
16
|
* const next = Slider.reflectRange(model.priceSlider, rangeFromUrl)
|
|
17
|
-
* // data-last, point-free in
|
|
18
|
-
*
|
|
17
|
+
* // data-last, point-free in modifyFields
|
|
18
|
+
* modifyFields(model, { priceSlider: Slider.reflectRange(rangeFromUrl) })
|
|
19
19
|
* ```
|
|
20
20
|
*/
|
|
21
21
|
export type Reflect<Model, Value> = {
|
|
@@ -51,10 +51,10 @@ type PreventDefaultEventListenerOptions = Omit<AddEventListenerOptions, 'passive
|
|
|
51
51
|
* `document`.
|
|
52
52
|
*
|
|
53
53
|
* `type` is constrained to the event names the target declares, and
|
|
54
|
-
* `
|
|
54
|
+
* `mapEvent`'s parameter is the event those two resolve to. Annotating that
|
|
55
55
|
* parameter is checked against the resolved event rather than replacing it.
|
|
56
56
|
*
|
|
57
|
-
* `
|
|
57
|
+
* `mapEvent(event)` transforms each dispatched event into a Stream value. The
|
|
58
58
|
* mapper runs synchronously in the same call stack as the browser's event
|
|
59
59
|
* dispatch, so calling `event.preventDefault()` inside it takes effect,
|
|
60
60
|
* unless the listener is passive. Some browsers default wheel and touch
|
|
@@ -62,11 +62,14 @@ type PreventDefaultEventListenerOptions = Omit<AddEventListenerOptions, 'passive
|
|
|
62
62
|
* ignored. Pass `options: { passive: false }` explicitly when cancelling
|
|
63
63
|
* those events, or reach for `fromEventFilterMapPreventDefault`, which does
|
|
64
64
|
* so for you.
|
|
65
|
+
*
|
|
66
|
+
* The output type is inferred from the mapper; `Subscription.make` checks
|
|
67
|
+
* that the final Stream emits the application's Message type.
|
|
65
68
|
*/
|
|
66
|
-
export type FromEventConfig<Target extends EventTarget, Type extends EventTypeOf<Target>,
|
|
69
|
+
export type FromEventConfig<Target extends EventTarget, Type extends EventTypeOf<Target>, Output> = Readonly<{
|
|
67
70
|
target: Target | (() => Target);
|
|
68
71
|
type: Type;
|
|
69
|
-
|
|
72
|
+
mapEvent: (event: EventOf<Target, Type>) => Output;
|
|
70
73
|
options?: AddEventListenerOptions;
|
|
71
74
|
}>;
|
|
72
75
|
/**
|
|
@@ -79,10 +82,10 @@ export type FromEventConfig<Target extends EventTarget, Type extends EventTypeOf
|
|
|
79
82
|
* `document`.
|
|
80
83
|
*
|
|
81
84
|
* `type` is constrained to the event names the target declares, and
|
|
82
|
-
* `
|
|
85
|
+
* `filterMapEvent`'s parameter is the event those two resolve to. Annotating that
|
|
83
86
|
* parameter is checked against the resolved event rather than replacing it.
|
|
84
87
|
*
|
|
85
|
-
* `
|
|
88
|
+
* `filterMapEvent(event)` returns `Option.some(value)` to emit a value for the
|
|
86
89
|
* event, or `Option.none()` to ignore it. The mapper runs synchronously in the
|
|
87
90
|
* same call stack as the browser's event dispatch, so calling
|
|
88
91
|
* `event.preventDefault()` inside it takes effect, unless the listener is
|
|
@@ -90,11 +93,14 @@ export type FromEventConfig<Target extends EventTarget, Type extends EventTypeOf
|
|
|
90
93
|
* to passive, where `preventDefault()` is ignored. Pass
|
|
91
94
|
* `options: { passive: false }` explicitly when cancelling those events, or
|
|
92
95
|
* reach for `fromEventFilterMapPreventDefault`, which does so for you.
|
|
96
|
+
*
|
|
97
|
+
* The output type is inferred from the mapper; `Subscription.make` checks
|
|
98
|
+
* that the final Stream emits the application's Message type.
|
|
93
99
|
*/
|
|
94
|
-
export type FromEventFilterMapConfig<Target extends EventTarget, Type extends EventTypeOf<Target>,
|
|
100
|
+
export type FromEventFilterMapConfig<Target extends EventTarget, Type extends EventTypeOf<Target>, Output> = Readonly<{
|
|
95
101
|
target: Target | (() => Target);
|
|
96
102
|
type: Type;
|
|
97
|
-
|
|
103
|
+
filterMapEvent: (event: EventOf<Target, Type>) => Option.Option<Output>;
|
|
98
104
|
options?: AddEventListenerOptions;
|
|
99
105
|
}>;
|
|
100
106
|
/**
|
|
@@ -107,36 +113,38 @@ export type FromEventFilterMapConfig<Target extends EventTarget, Type extends Ev
|
|
|
107
113
|
* `document`.
|
|
108
114
|
*
|
|
109
115
|
* `type` is constrained to the event names the target declares, and
|
|
110
|
-
* `
|
|
116
|
+
* `filterMapEvent`'s parameter is the event those two resolve to. Annotating that
|
|
111
117
|
* parameter is checked against the resolved event rather than replacing it.
|
|
112
118
|
*
|
|
113
|
-
* `
|
|
119
|
+
* `filterMapEvent(event)` returns `Option.some(value)` to mark the dispatch
|
|
114
120
|
* handled, or `Option.none()` to leave the default behavior intact. For a
|
|
115
121
|
* handled dispatch the helper calls `event.preventDefault()` and queues the
|
|
116
|
-
*
|
|
122
|
+
* value before the listener returns; the mapper itself never calls
|
|
117
123
|
* `preventDefault()`.
|
|
118
124
|
*
|
|
119
125
|
* `options.passive` defaults to `false` so `preventDefault()` keeps working
|
|
120
126
|
* for the events browsers would otherwise register as passive. The config
|
|
121
127
|
* rejects `passive: true`; the runtime guard also throws for unchecked
|
|
122
128
|
* JavaScript inputs.
|
|
129
|
+
*
|
|
130
|
+
* The output type is inferred from the mapper; `Subscription.make` checks
|
|
131
|
+
* that the final Stream emits the application's Message type.
|
|
123
132
|
*/
|
|
124
|
-
export type FromEventFilterMapPreventDefaultConfig<Target extends EventTarget, Type extends EventTypeOf<Target>,
|
|
133
|
+
export type FromEventFilterMapPreventDefaultConfig<Target extends EventTarget, Type extends EventTypeOf<Target>, Output> = Readonly<{
|
|
125
134
|
target: Target | (() => Target);
|
|
126
135
|
type: Type;
|
|
127
|
-
|
|
136
|
+
filterMapEvent: (event: EventOf<Target, Type>) => Option.Option<Output>;
|
|
128
137
|
options?: PreventDefaultEventListenerOptions;
|
|
129
138
|
}>;
|
|
130
139
|
/**
|
|
131
|
-
* Build a Stream that emits a
|
|
140
|
+
* Build a Stream that emits a value for the dispatches of a DOM event the
|
|
132
141
|
* mapper chooses to keep, registering the listener when the Stream's scope
|
|
133
142
|
* opens and removing it when the scope closes.
|
|
134
143
|
*
|
|
135
|
-
* This is the filtered variant of `fromEvent`. Its `
|
|
136
|
-
* `Option.some(
|
|
144
|
+
* This is the filtered variant of `fromEvent`. Its `filterMapEvent` returns
|
|
145
|
+
* `Option.some(value)` to emit and `Option.none()` to ignore the event, so a
|
|
137
146
|
* single listener can react to some dispatches while passing on the rest. A
|
|
138
|
-
* mapper that never emits produces a `Stream<never
|
|
139
|
-
* a Message-producing Stream is expected.
|
|
147
|
+
* mapper that never emits produces a `Stream<never>`.
|
|
140
148
|
*
|
|
141
149
|
* Reach for this over a downstream `Stream.filterMap` whenever the decision to
|
|
142
150
|
* keep an event is paired with `event.preventDefault()`. The mapper runs
|
|
@@ -164,7 +172,9 @@ export type FromEventFilterMapPreventDefaultConfig<Target extends EventTarget, T
|
|
|
164
172
|
* `Subscription.persistent` for a listener whose lifetime spans the whole
|
|
165
173
|
* Subscriptions record, or plug it into a `Subscription.make` entry's
|
|
166
174
|
* `dependenciesToStream` (typically behind `Stream.when`) to gate it on a
|
|
167
|
-
* Model condition.
|
|
175
|
+
* Model condition. The mapper's output type is inferred (even a raw Event is
|
|
176
|
+
* accepted here); `Subscription.make` checks the final Stream against the
|
|
177
|
+
* application's Message type.
|
|
168
178
|
*
|
|
169
179
|
* @example
|
|
170
180
|
* ```typescript
|
|
@@ -178,7 +188,7 @@ export type FromEventFilterMapPreventDefaultConfig<Target extends EventTarget, T
|
|
|
178
188
|
* Subscription.fromEventFilterMap({
|
|
179
189
|
* target: window,
|
|
180
190
|
* type: 'keydown',
|
|
181
|
-
*
|
|
191
|
+
* filterMapEvent: event =>
|
|
182
192
|
* event.key === 'Escape'
|
|
183
193
|
* ? Option.some(Message.PressedEscape())
|
|
184
194
|
* : Option.none(),
|
|
@@ -190,9 +200,9 @@ export type FromEventFilterMapPreventDefaultConfig<Target extends EventTarget, T
|
|
|
190
200
|
* }))
|
|
191
201
|
* ```
|
|
192
202
|
*/
|
|
193
|
-
export declare const fromEventFilterMap: <Target extends EventTarget, Type extends EventTypeOf<Target>,
|
|
203
|
+
export declare const fromEventFilterMap: <Target extends EventTarget, Type extends EventTypeOf<Target>, Output>(config: FromEventFilterMapConfig<Target, Type, Output>) => Stream.Stream<Output>;
|
|
194
204
|
/**
|
|
195
|
-
* Build a Stream that emits a
|
|
205
|
+
* Build a Stream that emits a value for every dispatch of a DOM event,
|
|
196
206
|
* registering the listener when the Stream's scope opens and removing it when
|
|
197
207
|
* the scope closes.
|
|
198
208
|
*
|
|
@@ -212,10 +222,12 @@ export declare const fromEventFilterMap: <Target extends EventTarget, Type exten
|
|
|
212
222
|
* `Subscription.persistent` for a listener whose lifetime spans the whole
|
|
213
223
|
* Subscriptions record, or plug it into a `Subscription.make` entry's
|
|
214
224
|
* `dependenciesToStream` (typically behind `Stream.when`) to gate it on a
|
|
215
|
-
* Model condition.
|
|
225
|
+
* Model condition. The mapper's output type is inferred (even a raw Event is
|
|
226
|
+
* accepted here); `Subscription.make` checks the final Stream against the
|
|
227
|
+
* application's Message type.
|
|
216
228
|
*
|
|
217
229
|
* For a listener that reacts to only some events, reach for
|
|
218
|
-
* `fromEventFilterMap`, whose mapper returns `Option<
|
|
230
|
+
* `fromEventFilterMap`, whose mapper returns `Option<Output>`. For a
|
|
219
231
|
* listener that also cancels the default action of the events it handles,
|
|
220
232
|
* reach for `fromEventFilterMapPreventDefault`.
|
|
221
233
|
*
|
|
@@ -231,7 +243,7 @@ export declare const fromEventFilterMap: <Target extends EventTarget, Type exten
|
|
|
231
243
|
* Subscription.fromEvent({
|
|
232
244
|
* target: window,
|
|
233
245
|
* type: 'keydown',
|
|
234
|
-
*
|
|
246
|
+
* mapEvent: event => Message.PressedKey({ key: event.key }),
|
|
235
247
|
* }),
|
|
236
248
|
* Effect.sync(() => isListening),
|
|
237
249
|
* ),
|
|
@@ -240,17 +252,17 @@ export declare const fromEventFilterMap: <Target extends EventTarget, Type exten
|
|
|
240
252
|
* }))
|
|
241
253
|
* ```
|
|
242
254
|
*/
|
|
243
|
-
export declare const fromEvent: <Target extends EventTarget, Type extends EventTypeOf<Target>,
|
|
255
|
+
export declare const fromEvent: <Target extends EventTarget, Type extends EventTypeOf<Target>, Output>(config: FromEventConfig<Target, Type, Output>) => Stream.Stream<Output>;
|
|
244
256
|
/**
|
|
245
|
-
* Build a Stream that emits a
|
|
257
|
+
* Build a Stream that emits a value for the dispatches of a DOM event the
|
|
246
258
|
* mapper marks handled, calling `event.preventDefault()` on each of them,
|
|
247
259
|
* registering the listener when the Stream's scope opens and removing it when
|
|
248
260
|
* the scope closes.
|
|
249
261
|
*
|
|
250
262
|
* This is the cancelling variant of `fromEventFilterMap`, mirroring
|
|
251
|
-
* `h.OnKeyDownPreventDefault` from `foldkit/html`. Its `
|
|
252
|
-
* `Option.some(
|
|
253
|
-
* mapper, calls `event.preventDefault()`, and queues the
|
|
263
|
+
* `h.OnKeyDownPreventDefault` from `foldkit/html`. Its `filterMapEvent` returns
|
|
264
|
+
* `Option.some(value)` to mark a dispatch handled. The helper evaluates the
|
|
265
|
+
* mapper, calls `event.preventDefault()`, and queues the value before the
|
|
254
266
|
* native listener returns. `Option.none()` leaves the default behavior intact.
|
|
255
267
|
* The mapper never calls `preventDefault()` itself.
|
|
256
268
|
*
|
|
@@ -275,7 +287,9 @@ export declare const fromEvent: <Target extends EventTarget, Type extends EventT
|
|
|
275
287
|
* `Subscription.persistent` for a listener whose lifetime spans the whole
|
|
276
288
|
* Subscriptions record, or plug it into a `Subscription.make` entry's
|
|
277
289
|
* `dependenciesToStream` (typically behind `Stream.when`) to gate it on a
|
|
278
|
-
* Model condition.
|
|
290
|
+
* Model condition. The mapper's output type is inferred (even a raw Event is
|
|
291
|
+
* accepted here); `Subscription.make` checks the final Stream against the
|
|
292
|
+
* application's Message type.
|
|
279
293
|
*
|
|
280
294
|
* @example
|
|
281
295
|
* ```typescript
|
|
@@ -289,7 +303,7 @@ export declare const fromEvent: <Target extends EventTarget, Type extends EventT
|
|
|
289
303
|
* Subscription.fromEventFilterMapPreventDefault({
|
|
290
304
|
* target: window,
|
|
291
305
|
* type: 'wheel',
|
|
292
|
-
*
|
|
306
|
+
* filterMapEvent: () => Option.some(Message.SuppressedWheelScroll()),
|
|
293
307
|
* }),
|
|
294
308
|
* Effect.sync(() => isModalOpen),
|
|
295
309
|
* ),
|
|
@@ -298,6 +312,6 @@ export declare const fromEvent: <Target extends EventTarget, Type extends EventT
|
|
|
298
312
|
* }))
|
|
299
313
|
* ```
|
|
300
314
|
*/
|
|
301
|
-
export declare const fromEventFilterMapPreventDefault: <Target extends EventTarget, Type extends EventTypeOf<Target>,
|
|
315
|
+
export declare const fromEventFilterMapPreventDefault: <Target extends EventTarget, Type extends EventTypeOf<Target>, Output>(config: FromEventFilterMapPreventDefaultConfig<Target, Type, Output>) => Stream.Stream<Output>;
|
|
302
316
|
export {};
|
|
303
317
|
//# sourceMappingURL=fromEvent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fromEvent.d.ts","sourceRoot":"","sources":["../../src/subscription/fromEvent.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"fromEvent.d.ts","sourceRoot":"","sources":["../../src/subscription/fromEvent.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,9 +4,9 @@ const listen = (config) => Stream.callback(queue => Effect.acquireRelease(Effect
|
|
|
4
4
|
const target = resolveTarget(config.target);
|
|
5
5
|
const handleEvent = (event) => {
|
|
6
6
|
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
7
|
-
const
|
|
8
|
-
if (Option.isSome(
|
|
9
|
-
Queue.offerUnsafe(queue,
|
|
7
|
+
const maybeOutput = config.filterMapEvent(event);
|
|
8
|
+
if (Option.isSome(maybeOutput)) {
|
|
9
|
+
Queue.offerUnsafe(queue, maybeOutput.value);
|
|
10
10
|
}
|
|
11
11
|
};
|
|
12
12
|
target.addEventListener(config.type, handleEvent, config.options);
|
|
@@ -15,15 +15,14 @@ const listen = (config) => Stream.callback(queue => Effect.acquireRelease(Effect
|
|
|
15
15
|
target.removeEventListener(config.type, handleEvent, config.options);
|
|
16
16
|
})).pipe(Effect.flatMap(() => Effect.never)));
|
|
17
17
|
/**
|
|
18
|
-
* Build a Stream that emits a
|
|
18
|
+
* Build a Stream that emits a value for the dispatches of a DOM event the
|
|
19
19
|
* mapper chooses to keep, registering the listener when the Stream's scope
|
|
20
20
|
* opens and removing it when the scope closes.
|
|
21
21
|
*
|
|
22
|
-
* This is the filtered variant of `fromEvent`. Its `
|
|
23
|
-
* `Option.some(
|
|
22
|
+
* This is the filtered variant of `fromEvent`. Its `filterMapEvent` returns
|
|
23
|
+
* `Option.some(value)` to emit and `Option.none()` to ignore the event, so a
|
|
24
24
|
* single listener can react to some dispatches while passing on the rest. A
|
|
25
|
-
* mapper that never emits produces a `Stream<never
|
|
26
|
-
* a Message-producing Stream is expected.
|
|
25
|
+
* mapper that never emits produces a `Stream<never>`.
|
|
27
26
|
*
|
|
28
27
|
* Reach for this over a downstream `Stream.filterMap` whenever the decision to
|
|
29
28
|
* keep an event is paired with `event.preventDefault()`. The mapper runs
|
|
@@ -51,7 +50,9 @@ const listen = (config) => Stream.callback(queue => Effect.acquireRelease(Effect
|
|
|
51
50
|
* `Subscription.persistent` for a listener whose lifetime spans the whole
|
|
52
51
|
* Subscriptions record, or plug it into a `Subscription.make` entry's
|
|
53
52
|
* `dependenciesToStream` (typically behind `Stream.when`) to gate it on a
|
|
54
|
-
* Model condition.
|
|
53
|
+
* Model condition. The mapper's output type is inferred (even a raw Event is
|
|
54
|
+
* accepted here); `Subscription.make` checks the final Stream against the
|
|
55
|
+
* application's Message type.
|
|
55
56
|
*
|
|
56
57
|
* @example
|
|
57
58
|
* ```typescript
|
|
@@ -65,7 +66,7 @@ const listen = (config) => Stream.callback(queue => Effect.acquireRelease(Effect
|
|
|
65
66
|
* Subscription.fromEventFilterMap({
|
|
66
67
|
* target: window,
|
|
67
68
|
* type: 'keydown',
|
|
68
|
-
*
|
|
69
|
+
* filterMapEvent: event =>
|
|
69
70
|
* event.key === 'Escape'
|
|
70
71
|
* ? Option.some(Message.PressedEscape())
|
|
71
72
|
* : Option.none(),
|
|
@@ -79,7 +80,7 @@ const listen = (config) => Stream.callback(queue => Effect.acquireRelease(Effect
|
|
|
79
80
|
*/
|
|
80
81
|
export const fromEventFilterMap = (config) => listen(config);
|
|
81
82
|
/**
|
|
82
|
-
* Build a Stream that emits a
|
|
83
|
+
* Build a Stream that emits a value for every dispatch of a DOM event,
|
|
83
84
|
* registering the listener when the Stream's scope opens and removing it when
|
|
84
85
|
* the scope closes.
|
|
85
86
|
*
|
|
@@ -99,10 +100,12 @@ export const fromEventFilterMap = (config) => listen(config);
|
|
|
99
100
|
* `Subscription.persistent` for a listener whose lifetime spans the whole
|
|
100
101
|
* Subscriptions record, or plug it into a `Subscription.make` entry's
|
|
101
102
|
* `dependenciesToStream` (typically behind `Stream.when`) to gate it on a
|
|
102
|
-
* Model condition.
|
|
103
|
+
* Model condition. The mapper's output type is inferred (even a raw Event is
|
|
104
|
+
* accepted here); `Subscription.make` checks the final Stream against the
|
|
105
|
+
* application's Message type.
|
|
103
106
|
*
|
|
104
107
|
* For a listener that reacts to only some events, reach for
|
|
105
|
-
* `fromEventFilterMap`, whose mapper returns `Option<
|
|
108
|
+
* `fromEventFilterMap`, whose mapper returns `Option<Output>`. For a
|
|
106
109
|
* listener that also cancels the default action of the events it handles,
|
|
107
110
|
* reach for `fromEventFilterMapPreventDefault`.
|
|
108
111
|
*
|
|
@@ -118,7 +121,7 @@ export const fromEventFilterMap = (config) => listen(config);
|
|
|
118
121
|
* Subscription.fromEvent({
|
|
119
122
|
* target: window,
|
|
120
123
|
* type: 'keydown',
|
|
121
|
-
*
|
|
124
|
+
* mapEvent: event => Message.PressedKey({ key: event.key }),
|
|
122
125
|
* }),
|
|
123
126
|
* Effect.sync(() => isListening),
|
|
124
127
|
* ),
|
|
@@ -129,18 +132,18 @@ export const fromEventFilterMap = (config) => listen(config);
|
|
|
129
132
|
*/
|
|
130
133
|
export const fromEvent = (config) => listen({
|
|
131
134
|
...config,
|
|
132
|
-
|
|
135
|
+
filterMapEvent: event => Option.some(config.mapEvent(event)),
|
|
133
136
|
});
|
|
134
137
|
/**
|
|
135
|
-
* Build a Stream that emits a
|
|
138
|
+
* Build a Stream that emits a value for the dispatches of a DOM event the
|
|
136
139
|
* mapper marks handled, calling `event.preventDefault()` on each of them,
|
|
137
140
|
* registering the listener when the Stream's scope opens and removing it when
|
|
138
141
|
* the scope closes.
|
|
139
142
|
*
|
|
140
143
|
* This is the cancelling variant of `fromEventFilterMap`, mirroring
|
|
141
|
-
* `h.OnKeyDownPreventDefault` from `foldkit/html`. Its `
|
|
142
|
-
* `Option.some(
|
|
143
|
-
* mapper, calls `event.preventDefault()`, and queues the
|
|
144
|
+
* `h.OnKeyDownPreventDefault` from `foldkit/html`. Its `filterMapEvent` returns
|
|
145
|
+
* `Option.some(value)` to mark a dispatch handled. The helper evaluates the
|
|
146
|
+
* mapper, calls `event.preventDefault()`, and queues the value before the
|
|
144
147
|
* native listener returns. `Option.none()` leaves the default behavior intact.
|
|
145
148
|
* The mapper never calls `preventDefault()` itself.
|
|
146
149
|
*
|
|
@@ -165,7 +168,9 @@ export const fromEvent = (config) => listen({
|
|
|
165
168
|
* `Subscription.persistent` for a listener whose lifetime spans the whole
|
|
166
169
|
* Subscriptions record, or plug it into a `Subscription.make` entry's
|
|
167
170
|
* `dependenciesToStream` (typically behind `Stream.when`) to gate it on a
|
|
168
|
-
* Model condition.
|
|
171
|
+
* Model condition. The mapper's output type is inferred (even a raw Event is
|
|
172
|
+
* accepted here); `Subscription.make` checks the final Stream against the
|
|
173
|
+
* application's Message type.
|
|
169
174
|
*
|
|
170
175
|
* @example
|
|
171
176
|
* ```typescript
|
|
@@ -179,7 +184,7 @@ export const fromEvent = (config) => listen({
|
|
|
179
184
|
* Subscription.fromEventFilterMapPreventDefault({
|
|
180
185
|
* target: window,
|
|
181
186
|
* type: 'wheel',
|
|
182
|
-
*
|
|
187
|
+
* filterMapEvent: () => Option.some(Message.SuppressedWheelScroll()),
|
|
183
188
|
* }),
|
|
184
189
|
* Effect.sync(() => isModalOpen),
|
|
185
190
|
* ),
|
|
@@ -204,12 +209,12 @@ export const fromEventFilterMapPreventDefault = (config) => {
|
|
|
204
209
|
return fromEventFilterMap({
|
|
205
210
|
...config,
|
|
206
211
|
options: { ...options, passive: false },
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
if (Option.isSome(
|
|
212
|
+
filterMapEvent: event => {
|
|
213
|
+
const maybeOutput = config.filterMapEvent(event);
|
|
214
|
+
if (Option.isSome(maybeOutput)) {
|
|
210
215
|
event.preventDefault();
|
|
211
216
|
}
|
|
212
|
-
return
|
|
217
|
+
return maybeOutput;
|
|
213
218
|
},
|
|
214
219
|
});
|
|
215
220
|
};
|
|
@@ -3,9 +3,9 @@ import { Duration, Stream } from 'effect';
|
|
|
3
3
|
export type WhileTyping = 'Suppress' | 'Allow';
|
|
4
4
|
/** A single key press or a sequence of two or more key presses. */
|
|
5
5
|
export type KeySequence = string | Readonly<[string, string, ...Array<string>]>;
|
|
6
|
-
type BindingBase<
|
|
6
|
+
type BindingBase<Output> = Readonly<{
|
|
7
7
|
keys: KeySequence;
|
|
8
|
-
|
|
8
|
+
mapEvent: (event: KeyboardEvent) => Output;
|
|
9
9
|
isEnabled?: boolean;
|
|
10
10
|
whileTyping?: WhileTyping;
|
|
11
11
|
preventDefault?: boolean;
|
|
@@ -17,7 +17,7 @@ type BindingBase<Message> = Readonly<{
|
|
|
17
17
|
* An array describes a sequence of at least two presses, such as
|
|
18
18
|
* `['G', 'H']` or `['G', 'Shift+G']`.
|
|
19
19
|
*/
|
|
20
|
-
export type KeyBinding<
|
|
20
|
+
export type KeyBinding<Output> = BindingBase<Output> & (Readonly<{
|
|
21
21
|
keys: string;
|
|
22
22
|
whenRepeated?: 'Ignore' | 'Allow';
|
|
23
23
|
}> | Readonly<{
|
|
@@ -26,14 +26,16 @@ export type KeyBinding<Message> = BindingBase<Message> & (Readonly<{
|
|
|
26
26
|
}>);
|
|
27
27
|
type ModKey = 'Control' | 'Meta';
|
|
28
28
|
/** Configuration for the {@link keyBindings} Stream helper. */
|
|
29
|
-
export type KeyBindingsConfig<
|
|
30
|
-
bindings: ReadonlyArray<KeyBinding<
|
|
29
|
+
export type KeyBindingsConfig<Output> = Readonly<{
|
|
30
|
+
bindings: ReadonlyArray<KeyBinding<Output>>;
|
|
31
31
|
target?: EventTarget | (() => EventTarget);
|
|
32
32
|
modKey?: ModKey;
|
|
33
33
|
sequenceTimeout?: Duration.Input;
|
|
34
34
|
}>;
|
|
35
35
|
/**
|
|
36
|
-
* Build a Stream that
|
|
36
|
+
* Build a Stream that maps declarative key bindings to values. The output is
|
|
37
|
+
* inferred from each binding's `mapEvent` callback; `Subscription.make`
|
|
38
|
+
* checks that the final Stream emits the application's Message type.
|
|
37
39
|
*
|
|
38
40
|
* A string describes one key press. Modifiers are joined with `+`:
|
|
39
41
|
* `'Mod+K'`, `'Control+Shift+P'`, or `'Alt+ArrowDown'`. The supported modifiers
|
|
@@ -69,7 +71,7 @@ export type KeyBindingsConfig<Message> = Readonly<{
|
|
|
69
71
|
* or put bindings with different parent-owned lifetimes in separate child
|
|
70
72
|
* entries so `Subscription.lift` can gate them individually. If the meaning
|
|
71
73
|
* of a key depends on the Model, dispatch a factual key Message and decide
|
|
72
|
-
* what it means in update instead of reading the Model from `
|
|
74
|
+
* what it means in update instead of reading the Model from `mapEvent`.
|
|
73
75
|
*
|
|
74
76
|
* @example
|
|
75
77
|
* ```typescript
|
|
@@ -87,16 +89,16 @@ export type KeyBindingsConfig<Message> = Readonly<{
|
|
|
87
89
|
* keys: 'Escape',
|
|
88
90
|
* isEnabled: isPaletteOpen,
|
|
89
91
|
* whileTyping: 'Allow',
|
|
90
|
-
*
|
|
92
|
+
* mapEvent: () => Message.PressedEscape(),
|
|
91
93
|
* },
|
|
92
94
|
* {
|
|
93
95
|
* keys: 'Mod+K',
|
|
94
96
|
* whileTyping: 'Allow',
|
|
95
|
-
*
|
|
97
|
+
* mapEvent: () => Message.PressedSearchShortcut(),
|
|
96
98
|
* },
|
|
97
99
|
* {
|
|
98
100
|
* keys: ['G', 'L'],
|
|
99
|
-
*
|
|
101
|
+
* mapEvent: () => Message.PressedListShortcut(),
|
|
100
102
|
* },
|
|
101
103
|
* ],
|
|
102
104
|
* }),
|
|
@@ -105,6 +107,6 @@ export type KeyBindingsConfig<Message> = Readonly<{
|
|
|
105
107
|
* }))
|
|
106
108
|
* ```
|
|
107
109
|
*/
|
|
108
|
-
export declare const keyBindings: <
|
|
110
|
+
export declare const keyBindings: <Output>(config: KeyBindingsConfig<Output>) => Stream.Stream<Output>;
|
|
109
111
|
export {};
|
|
110
112
|
//# sourceMappingURL=keyBindings.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyBindings.d.ts","sourceRoot":"","sources":["../../src/subscription/keyBindings.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EAOR,MAAM,EAGP,MAAM,QAAQ,CAAA;AAEf,oFAAoF;AACpF,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,OAAO,CAAA;AAE9C,mEAAmE;AACnE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;AAE/E,KAAK,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"keyBindings.d.ts","sourceRoot":"","sources":["../../src/subscription/keyBindings.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EAOR,MAAM,EAGP,MAAM,QAAQ,CAAA;AAEf,oFAAoF;AACpF,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,OAAO,CAAA;AAE9C,mEAAmE;AACnE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;AAE/E,KAAK,WAAW,CAAC,MAAM,IAAI,QAAQ,CAAC;IAClC,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,MAAM,CAAA;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB,CAAC,CAAA;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,CAAC,MAAM,IAAI,WAAW,CAAC,MAAM,CAAC,GAClD,CACI,QAAQ,CAAC;IACP,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAA;CAClC,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IAClD,YAAY,CAAC,EAAE,KAAK,CAAA;CACrB,CAAC,CACL,CAAA;AAEH,KAAK,MAAM,GAAG,SAAS,GAAG,MAAM,CAAA;AAEhC,+DAA+D;AAC/D,MAAM,MAAM,iBAAiB,CAAC,MAAM,IAAI,QAAQ,CAAC;IAC/C,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;IAC3C,MAAM,CAAC,EAAE,WAAW,GAAG,CAAC,MAAM,WAAW,CAAC,CAAA;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,eAAe,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAA;CACjC,CAAC,CAAA;AA2sBF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0EG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,UACxB,iBAAiB,CAAC,MAAM,CAAC,KAChC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAuD,CAAA"}
|
|
@@ -109,7 +109,7 @@ const compileBinding = (binding) => {
|
|
|
109
109
|
: Array.map(binding.keys, parsePress);
|
|
110
110
|
return {
|
|
111
111
|
presses,
|
|
112
|
-
|
|
112
|
+
mapEvent: binding.mapEvent,
|
|
113
113
|
whileTyping: binding.whileTyping ?? 'Suppress',
|
|
114
114
|
preventDefault: binding.preventDefault ?? true,
|
|
115
115
|
whenRepeated: binding.whenRepeated ?? 'Ignore',
|
|
@@ -237,7 +237,7 @@ const emitBindingMessage = (context, binding, event) => {
|
|
|
237
237
|
if (binding.preventDefault) {
|
|
238
238
|
event.preventDefault();
|
|
239
239
|
}
|
|
240
|
-
context.emitMessage(binding.
|
|
240
|
+
context.emitMessage(binding.mapEvent(event));
|
|
241
241
|
};
|
|
242
242
|
const isMatchingOnePressBinding = (event, modKey, isEditable) => (binding) => !isSequence(binding) &&
|
|
243
243
|
isAllowedWhileTyping(binding, isEditable) &&
|
|
@@ -368,7 +368,9 @@ const keyBindingStream = (config) => Stream.callback(queue => {
|
|
|
368
368
|
return Effect.acquireRelease(Effect.sync(() => acquireKeyBindingListener(config, emitMessage)), listener => Effect.sync(() => releaseKeyBindingListener(listener)));
|
|
369
369
|
});
|
|
370
370
|
/**
|
|
371
|
-
* Build a Stream that
|
|
371
|
+
* Build a Stream that maps declarative key bindings to values. The output is
|
|
372
|
+
* inferred from each binding's `mapEvent` callback; `Subscription.make`
|
|
373
|
+
* checks that the final Stream emits the application's Message type.
|
|
372
374
|
*
|
|
373
375
|
* A string describes one key press. Modifiers are joined with `+`:
|
|
374
376
|
* `'Mod+K'`, `'Control+Shift+P'`, or `'Alt+ArrowDown'`. The supported modifiers
|
|
@@ -404,7 +406,7 @@ const keyBindingStream = (config) => Stream.callback(queue => {
|
|
|
404
406
|
* or put bindings with different parent-owned lifetimes in separate child
|
|
405
407
|
* entries so `Subscription.lift` can gate them individually. If the meaning
|
|
406
408
|
* of a key depends on the Model, dispatch a factual key Message and decide
|
|
407
|
-
* what it means in update instead of reading the Model from `
|
|
409
|
+
* what it means in update instead of reading the Model from `mapEvent`.
|
|
408
410
|
*
|
|
409
411
|
* @example
|
|
410
412
|
* ```typescript
|
|
@@ -422,16 +424,16 @@ const keyBindingStream = (config) => Stream.callback(queue => {
|
|
|
422
424
|
* keys: 'Escape',
|
|
423
425
|
* isEnabled: isPaletteOpen,
|
|
424
426
|
* whileTyping: 'Allow',
|
|
425
|
-
*
|
|
427
|
+
* mapEvent: () => Message.PressedEscape(),
|
|
426
428
|
* },
|
|
427
429
|
* {
|
|
428
430
|
* keys: 'Mod+K',
|
|
429
431
|
* whileTyping: 'Allow',
|
|
430
|
-
*
|
|
432
|
+
* mapEvent: () => Message.PressedSearchShortcut(),
|
|
431
433
|
* },
|
|
432
434
|
* {
|
|
433
435
|
* keys: ['G', 'L'],
|
|
434
|
-
*
|
|
436
|
+
* mapEvent: () => Message.PressedListShortcut(),
|
|
435
437
|
* },
|
|
436
438
|
* ],
|
|
437
439
|
* }),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { aggregate, lift, make, persistent } from './subscription.js';
|
|
2
|
-
export type { EntryWithoutKeepAlive, GatedDependencies, Subscription, Subscriptions, } from './subscription.js';
|
|
2
|
+
export type { EntryGates, EntryWithoutKeepAlive, GatedDependencies, Subscription, Subscriptions, } from './subscription.js';
|
|
3
3
|
export { animationFrame } from './animationFrame.js';
|
|
4
4
|
export type { AnimationFrameConfig } from './animationFrame.js';
|
|
5
5
|
export { fromEvent, fromEventFilterMap, fromEventFilterMapPreventDefault, } from './fromEvent.js';
|