foldkit 0.100.0 → 0.101.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 +38 -36
- package/dist/devTools/overlay.d.ts.map +1 -1
- package/dist/devTools/overlay.js +25 -40
- package/dist/devTools/store.d.ts.map +1 -1
- package/dist/devTools/store.js +50 -49
- package/dist/runtime/runtime.d.ts +10 -10
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +3 -2
- package/dist/runtime/subscription.d.ts +139 -19
- package/dist/runtime/subscription.d.ts.map +1 -1
- package/dist/runtime/subscription.js +90 -9
- package/dist/subscription/animationFrame.d.ts +23 -26
- package/dist/subscription/animationFrame.d.ts.map +1 -1
- package/dist/subscription/animationFrame.js +17 -18
- package/dist/subscription/public.d.ts +2 -2
- package/dist/subscription/public.d.ts.map +1 -1
- package/dist/subscription/public.js +1 -1
- package/dist/test/apps/bubbling.d.ts.map +1 -1
- package/dist/test/apps/bubbling.js +7 -5
- package/dist/test/apps/counter.d.ts.map +1 -1
- package/dist/test/apps/counter.js +8 -6
- package/dist/test/apps/disabledButton.d.ts.map +1 -1
- package/dist/test/apps/disabledButton.js +32 -21
- package/dist/test/apps/fileUpload.d.ts.map +1 -1
- package/dist/test/apps/fileUpload.js +18 -16
- package/dist/test/apps/interactions.d.ts.map +1 -1
- package/dist/test/apps/interactions.js +21 -19
- package/dist/test/apps/keypress.d.ts.map +1 -1
- package/dist/test/apps/keypress.js +12 -10
- package/dist/test/apps/login.d.ts.map +1 -1
- package/dist/test/apps/login.js +38 -36
- package/dist/test/apps/logoutButton.d.ts.map +1 -1
- package/dist/test/apps/logoutButton.js +4 -2
- package/dist/test/apps/mountPanel.d.ts.map +1 -1
- package/dist/test/apps/mountPanel.js +29 -21
- package/dist/test/apps/multiRole.d.ts.map +1 -1
- package/dist/test/apps/multiRole.js +6 -4
- package/dist/test/apps/pointer.d.ts.map +1 -1
- package/dist/test/apps/pointer.js +15 -13
- package/dist/test/apps/resumeUpload.d.ts.map +1 -1
- package/dist/test/apps/resumeUpload.js +20 -15
- package/dist/ui/dragAndDrop/index.d.ts +383 -101
- package/dist/ui/dragAndDrop/index.d.ts.map +1 -1
- package/dist/ui/dragAndDrop/index.js +19 -24
- package/dist/ui/dragAndDrop/public.d.ts +1 -1
- package/dist/ui/dragAndDrop/public.d.ts.map +1 -1
- package/dist/ui/dragAndDrop/public.js +1 -1
- package/dist/ui/slider/index.d.ts +193 -87
- package/dist/ui/slider/index.d.ts.map +1 -1
- package/dist/ui/slider/index.js +12 -19
- package/dist/ui/slider/public.d.ts +1 -1
- package/dist/ui/slider/public.d.ts.map +1 -1
- package/dist/ui/slider/public.js +1 -1
- package/dist/ui/virtualList/index.d.ts +45 -39
- package/dist/ui/virtualList/index.d.ts.map +1 -1
- package/dist/ui/virtualList/index.js +5 -12
- package/dist/ui/virtualList/public.d.ts +1 -1
- package/dist/ui/virtualList/public.d.ts.map +1 -1
- package/dist/ui/virtualList/public.js +1 -1
- package/package.json +1 -1
|
@@ -1,23 +1,143 @@
|
|
|
1
|
-
import { type Equivalence,
|
|
2
|
-
type
|
|
3
|
-
|
|
4
|
-
export type Subscription<Model, Message, StreamDeps, Resources = never> = {
|
|
5
|
-
readonly modelToDependencies: (model: Model) => StreamDeps;
|
|
6
|
-
readonly equivalence?: Equivalence.Equivalence<StreamDeps>;
|
|
7
|
-
readonly dependenciesToStream: (deps: StreamDeps, readDependencies: () => StreamDeps) => Stream.Stream<ResolveMessage<Message>, never, Resources>;
|
|
1
|
+
import { type Equivalence, Schema, Stream } from 'effect';
|
|
2
|
+
type SubscriptionBrand = {
|
|
3
|
+
readonly __subscription: never;
|
|
8
4
|
};
|
|
9
|
-
type
|
|
10
|
-
readonly
|
|
11
|
-
} & Subscription<Model, Message, StreamDeps, Resources>;
|
|
12
|
-
/** A record of named subscription configurations, keyed by dependency field name. */
|
|
13
|
-
export type Subscriptions<Model, Message, SubscriptionDependencies extends Schema.Struct<any>, Resources = never> = {
|
|
14
|
-
readonly [K in keyof Schema.Schema.Type<SubscriptionDependencies>]: SubscriptionConfig<Model, Message, Schema.Schema.Type<SubscriptionDependencies>[K], Resources>;
|
|
5
|
+
type DependenciesSchema<Dependencies> = Schema.Schema<Dependencies> & {
|
|
6
|
+
readonly fields: Schema.Struct.Fields;
|
|
15
7
|
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
readonly modelToDependencies: (model: Model) =>
|
|
19
|
-
readonly
|
|
20
|
-
readonly dependenciesToStream: (
|
|
21
|
-
};
|
|
8
|
+
type EntryWithoutKeepAlive<Model, Message, Dependencies, Services> = {
|
|
9
|
+
readonly dependenciesSchema: DependenciesSchema<Dependencies>;
|
|
10
|
+
readonly modelToDependencies: (model: Model) => Dependencies;
|
|
11
|
+
readonly keepAliveEquivalence?: never;
|
|
12
|
+
readonly dependenciesToStream: (dependencies: Dependencies) => Stream.Stream<Message, never, Services>;
|
|
13
|
+
};
|
|
14
|
+
type EntryWithKeepAlive<Model, Message, Dependencies, Services> = {
|
|
15
|
+
readonly dependenciesSchema: DependenciesSchema<Dependencies>;
|
|
16
|
+
readonly modelToDependencies: (model: Model) => Dependencies;
|
|
17
|
+
readonly keepAliveEquivalence: Equivalence.Equivalence<Dependencies>;
|
|
18
|
+
readonly dependenciesToStream: (dependencies: Dependencies, readDependencies: () => Dependencies) => Stream.Stream<Message, never, Services>;
|
|
19
|
+
};
|
|
20
|
+
type Entry<Model, Message, Dependencies, Services = never> = EntryWithoutKeepAlive<Model, Message, Dependencies, Services> | EntryWithKeepAlive<Model, Message, Dependencies, Services>;
|
|
21
|
+
/**
|
|
22
|
+
* A single subscription entry produced by `Subscription.make`,
|
|
23
|
+
* `Subscription.lift`, or `Subscription.aggregate`. The brand field is
|
|
24
|
+
* `never`, so application code cannot manually construct a `Subscription`
|
|
25
|
+
* value: it must go through one of those constructors (or a helper like
|
|
26
|
+
* `Subscription.persistent` that returns an entry shape, then through
|
|
27
|
+
* `make`).
|
|
28
|
+
*
|
|
29
|
+
* Two variants by `keepAliveEquivalence` presence:
|
|
30
|
+
*
|
|
31
|
+
* - Without `keepAliveEquivalence` (the common case), every Model change recomputes
|
|
32
|
+
* the dependencies. Equivalent dependencies leave the Stream alone; any
|
|
33
|
+
* change tears it down and restarts. `dependenciesToStream` takes a single
|
|
34
|
+
* argument: the latest dependencies.
|
|
35
|
+
* - With `keepAliveEquivalence` (an escape hatch), Model changes that the
|
|
36
|
+
* equivalence treats as equal leave the Stream running, but the running
|
|
37
|
+
* Stream can still read the latest dependencies via the second
|
|
38
|
+
* `readDependencies` argument. Use this when the Stream needs mid-flight
|
|
39
|
+
* access to data that changes often but shouldn't trigger restarts
|
|
40
|
+
* (Foldkit UI's `Ui.DragAndDrop.autoScroll` reading the latest pointer
|
|
41
|
+
* `clientY` each rAF tick is the canonical example).
|
|
42
|
+
*
|
|
43
|
+
* `dependenciesSchema` must be a `Schema.Struct` so every dependency is
|
|
44
|
+
* explicitly named at the schema level.
|
|
45
|
+
*/
|
|
46
|
+
export type Subscription<Model, Message, Dependencies, Services = never> = Entry<Model, Message, Dependencies, Services> & SubscriptionBrand;
|
|
47
|
+
/** A record of named Subscriptions keyed by dependency field name. */
|
|
48
|
+
export type Subscriptions<Model, Message, Services = never> = Readonly<Record<string, Subscription<Model, Message, any, Services>>>;
|
|
49
|
+
/**
|
|
50
|
+
* Callbacks for a subscription entry without `keepAliveEquivalence`. Dependencies
|
|
51
|
+
* are inferred from the field map passed to `entry`.
|
|
52
|
+
*/
|
|
53
|
+
type EntryCallbacksWithoutKeepAlive<Model, Message, Dependencies, Services> = {
|
|
54
|
+
readonly modelToDependencies: (model: Model) => Dependencies;
|
|
55
|
+
readonly keepAliveEquivalence?: never;
|
|
56
|
+
readonly dependenciesToStream: (dependencies: Dependencies) => Stream.Stream<Message, never, Services>;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Callbacks for a subscription entry with `keepAliveEquivalence`. Dependencies
|
|
60
|
+
* are inferred from the field map passed to `entry`.
|
|
61
|
+
*/
|
|
62
|
+
type EntryCallbacksWithKeepAlive<Model, Message, Dependencies, Services> = {
|
|
63
|
+
readonly modelToDependencies: (model: Model) => Dependencies;
|
|
64
|
+
readonly keepAliveEquivalence: Equivalence.Equivalence<Dependencies>;
|
|
65
|
+
readonly dependenciesToStream: (dependencies: Dependencies, readDependencies: () => Dependencies) => Stream.Stream<Message, never, Services>;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Builds a single subscription entry from a field map and callbacks.
|
|
69
|
+
*
|
|
70
|
+
* The field map is the same shape you would pass to `S.Struct`. Reading the
|
|
71
|
+
* schema as a positional argument (rather than a property on the entry
|
|
72
|
+
* literal) lets TypeScript fully resolve the `Dependencies` type before
|
|
73
|
+
* contextually typing `modelToDependencies` and `dependenciesToStream`, so
|
|
74
|
+
* destructuring patterns like `({ maybeMapHostId })` are inferred correctly
|
|
75
|
+
* even when the field schemas use transforms (e.g. `S.Option`).
|
|
76
|
+
*
|
|
77
|
+
* Two overloads, one per `keepAliveEquivalence` presence:
|
|
78
|
+
*
|
|
79
|
+
* - Without `keepAliveEquivalence`, `dependenciesToStream` takes a single
|
|
80
|
+
* `dependencies` argument.
|
|
81
|
+
* - With `keepAliveEquivalence`, `dependenciesToStream` also receives a
|
|
82
|
+
* `readDependencies` thunk for accessing the latest value while the Stream
|
|
83
|
+
* stays running across Model changes the equivalence accepts as equal.
|
|
84
|
+
*/
|
|
85
|
+
export type EntryBuilder<Model, Message, Services> = <const Fields extends Schema.Struct.Fields, Callbacks extends EntryCallbacksWithoutKeepAlive<Model, Message, Schema.Struct.Type<Fields>, Services> | EntryCallbacksWithKeepAlive<Model, Message, Schema.Struct.Type<Fields>, Services>>(fields: Fields, callbacks: Callbacks) => Callbacks extends {
|
|
86
|
+
readonly keepAliveEquivalence: Equivalence.Equivalence<any>;
|
|
87
|
+
} ? EntryWithKeepAlive<Model, Message, Schema.Struct.Type<Fields>, Services> : EntryWithoutKeepAlive<Model, Message, Schema.Struct.Type<Fields>, Services>;
|
|
88
|
+
/**
|
|
89
|
+
* Declares a Subscriptions record. The Model, Message, and optional Services
|
|
90
|
+
* generics are provided up front; the entries record follows, built from
|
|
91
|
+
* calls to the `entry` builder passed into the inner function.
|
|
92
|
+
*
|
|
93
|
+
* Reach for `Subscription.aggregate` to combine multiple records, and
|
|
94
|
+
* `Subscription.lift` to translate a child Submodel's record into a parent
|
|
95
|
+
* context.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* Subscription.make<Model, Message>()(entry => ({
|
|
100
|
+
* tick: entry(
|
|
101
|
+
* { isRunning: S.Boolean },
|
|
102
|
+
* {
|
|
103
|
+
* modelToDependencies: model => ({ isRunning: model.isRunning }),
|
|
104
|
+
* dependenciesToStream: ({ isRunning }) =>
|
|
105
|
+
* Stream.when(..., Effect.sync(() => isRunning)),
|
|
106
|
+
* },
|
|
107
|
+
* ),
|
|
108
|
+
* }))
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export declare const make: <Model, Message, Services = never>() => <Entries extends Readonly<Record<string, Entry<Model, Message, any, Services>>>>(build: (entry: EntryBuilder<Model, Message, Services>) => Entries) => { readonly [K in keyof Entries]: Entries[K] & SubscriptionBrand; };
|
|
112
|
+
/**
|
|
113
|
+
* Combines multiple Subscriptions records into one. Throws on duplicate
|
|
114
|
+
* keys so a misconfigured aggregate fails loudly at startup rather than
|
|
115
|
+
* silently overriding.
|
|
116
|
+
*/
|
|
117
|
+
export declare const aggregate: <Model, Message, Services = never>() => (...records: ReadonlyArray<Subscriptions<Model, Message, Services>>) => Subscriptions<Model, Message, Services>;
|
|
118
|
+
/**
|
|
119
|
+
* Wraps a Stream as a Subscription entry whose lifecycle is independent of
|
|
120
|
+
* the Model. The Stream runs for the lifetime of the Subscriptions record;
|
|
121
|
+
* no Model change tears it down or restarts it. Use for any Stream whose
|
|
122
|
+
* work doesn't depend on Model state, such as system theme listeners,
|
|
123
|
+
* viewport width observers, or route-independent timers.
|
|
124
|
+
*
|
|
125
|
+
* Returns an entry shape, not a branded Subscription. Pass it into `make`
|
|
126
|
+
* as an entry value.
|
|
127
|
+
*/
|
|
128
|
+
export declare const persistent: <Message, Services = never>(stream: Stream.Stream<Message, never, Services>) => EntryWithoutKeepAlive<unknown, Message, Record<string, never>, Services>;
|
|
129
|
+
type ChildModelOf<ChildSubscriptions> = ChildSubscriptions[keyof ChildSubscriptions] extends Subscription<infer ChildModel, any, any, any> ? ChildModel : never;
|
|
130
|
+
type ChildMessageOf<ChildSubscriptions> = ChildSubscriptions[keyof ChildSubscriptions] extends Subscription<any, infer ChildMessage, any, any> ? ChildMessage : never;
|
|
131
|
+
/**
|
|
132
|
+
* Lifts a record of child Subscriptions into a parent's Model and Message
|
|
133
|
+
* context, applying a Model accessor and a Message wrapper uniformly to
|
|
134
|
+
* every entry. Per-entry dependency types, schemas, and `keepAliveEquivalence`
|
|
135
|
+
* settings are preserved; each lifted entry's variant (with or without
|
|
136
|
+
* `readDependencies`) matches its source entry's.
|
|
137
|
+
*/
|
|
138
|
+
export declare const lift: <Subscriptions extends Readonly<Record<string, Subscription<any, any, any, any>>>>(subscriptions: Subscriptions) => <ParentModel, ParentMessage>(config: {
|
|
139
|
+
readonly toChildModel: (parentModel: ParentModel) => ChildModelOf<Subscriptions>;
|
|
140
|
+
readonly toParentMessage: (message: ChildMessageOf<Subscriptions>) => ParentMessage;
|
|
141
|
+
}) => { readonly [K in keyof Subscriptions]: Subscriptions[K] extends Subscription<any, any, infer Dependencies, infer Services> ? Subscription<ParentModel, ParentMessage, Dependencies, Services> : never; };
|
|
22
142
|
export {};
|
|
23
143
|
//# sourceMappingURL=subscription.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../src/runtime/subscription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAU,
|
|
1
|
+
{"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../src/runtime/subscription.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,92 @@
|
|
|
1
|
-
import { Record } from 'effect';
|
|
2
|
-
/**
|
|
3
|
-
|
|
1
|
+
import { Record, Schema, Stream } from 'effect';
|
|
2
|
+
/**
|
|
3
|
+
* Declares a Subscriptions record. The Model, Message, and optional Services
|
|
4
|
+
* generics are provided up front; the entries record follows, built from
|
|
5
|
+
* calls to the `entry` builder passed into the inner function.
|
|
6
|
+
*
|
|
7
|
+
* Reach for `Subscription.aggregate` to combine multiple records, and
|
|
8
|
+
* `Subscription.lift` to translate a child Submodel's record into a parent
|
|
9
|
+
* context.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* Subscription.make<Model, Message>()(entry => ({
|
|
14
|
+
* tick: entry(
|
|
15
|
+
* { isRunning: S.Boolean },
|
|
16
|
+
* {
|
|
17
|
+
* modelToDependencies: model => ({ isRunning: model.isRunning }),
|
|
18
|
+
* dependenciesToStream: ({ isRunning }) =>
|
|
19
|
+
* Stream.when(..., Effect.sync(() => isRunning)),
|
|
20
|
+
* },
|
|
21
|
+
* ),
|
|
22
|
+
* }))
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export const make = () => (build) => {
|
|
26
|
+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
27
|
+
const entryBuilder = ((fields, callbacks) => ({
|
|
28
|
+
dependenciesSchema: Schema.Struct(fields),
|
|
29
|
+
...callbacks,
|
|
30
|
+
}));
|
|
31
|
+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
32
|
+
return build(entryBuilder);
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Combines multiple Subscriptions records into one. Throws on duplicate
|
|
36
|
+
* keys so a misconfigured aggregate fails loudly at startup rather than
|
|
37
|
+
* silently overriding.
|
|
38
|
+
*/
|
|
39
|
+
export const aggregate = () => (...records) => {
|
|
40
|
+
const result = {};
|
|
41
|
+
for (const record of records) {
|
|
42
|
+
for (const key of Object.keys(record)) {
|
|
43
|
+
if (key in result) {
|
|
44
|
+
throw new Error(`Subscription.aggregate: duplicate key "${key}" across records`);
|
|
45
|
+
}
|
|
46
|
+
result[key] = record[key];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Wraps a Stream as a Subscription entry whose lifecycle is independent of
|
|
53
|
+
* the Model. The Stream runs for the lifetime of the Subscriptions record;
|
|
54
|
+
* no Model change tears it down or restarts it. Use for any Stream whose
|
|
55
|
+
* work doesn't depend on Model state, such as system theme listeners,
|
|
56
|
+
* viewport width observers, or route-independent timers.
|
|
57
|
+
*
|
|
58
|
+
* Returns an entry shape, not a branded Subscription. Pass it into `make`
|
|
59
|
+
* as an entry value.
|
|
60
|
+
*/
|
|
61
|
+
export const persistent = (stream) => ({
|
|
62
|
+
dependenciesSchema: Schema.Struct({}),
|
|
63
|
+
modelToDependencies: () => ({}),
|
|
64
|
+
dependenciesToStream: () => stream,
|
|
65
|
+
});
|
|
66
|
+
/**
|
|
67
|
+
* Lifts a record of child Subscriptions into a parent's Model and Message
|
|
68
|
+
* context, applying a Model accessor and a Message wrapper uniformly to
|
|
69
|
+
* every entry. Per-entry dependency types, schemas, and `keepAliveEquivalence`
|
|
70
|
+
* settings are preserved; each lifted entry's variant (with or without
|
|
71
|
+
* `readDependencies`) matches its source entry's.
|
|
72
|
+
*/
|
|
73
|
+
export const lift = (subscriptions) => (config) =>
|
|
4
74
|
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
|
5
|
-
Record.map(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
75
|
+
Record.map(subscriptions, subscription => {
|
|
76
|
+
const modelToDependencies = (parentModel) => subscription.modelToDependencies(config.toChildModel(parentModel));
|
|
77
|
+
const wrapStream = (stream) => Stream.map(stream, config.toParentMessage);
|
|
78
|
+
if (subscription.keepAliveEquivalence !== undefined) {
|
|
79
|
+
return {
|
|
80
|
+
dependenciesSchema: subscription.dependenciesSchema,
|
|
81
|
+
modelToDependencies,
|
|
82
|
+
keepAliveEquivalence: subscription.keepAliveEquivalence,
|
|
83
|
+
dependenciesToStream: (dependencies, readDependencies) => wrapStream(subscription.dependenciesToStream(dependencies, readDependencies)),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
dependenciesSchema: subscription.dependenciesSchema,
|
|
88
|
+
modelToDependencies,
|
|
89
|
+
dependenciesToStream: (dependencies) => wrapStream(subscription.dependenciesToStream(dependencies)),
|
|
90
|
+
};
|
|
91
|
+
});
|
|
11
92
|
/* eslint-enable @typescript-eslint/consistent-type-assertions */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Stream } from 'effect';
|
|
1
|
+
import { Schema as S, Stream } from 'effect';
|
|
2
2
|
/**
|
|
3
3
|
* Configuration for the `animationFrame` Subscription helper.
|
|
4
4
|
*
|
|
@@ -13,41 +13,38 @@ export type AnimationFrameConfig<Model, Message> = Readonly<{
|
|
|
13
13
|
toMessage: (deltaTime: number) => Message;
|
|
14
14
|
}>;
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
* `{ modelToDependencies, dependenciesToStream }` form expected by
|
|
18
|
-
* `Subscription.makeSubscriptions` field configs.
|
|
19
|
-
*/
|
|
20
|
-
export type AnimationFrameSubscription<Model, Message> = Readonly<{
|
|
21
|
-
modelToDependencies: (model: Model) => boolean;
|
|
22
|
-
dependenciesToStream: (isActive: boolean) => Stream.Stream<Message>;
|
|
23
|
-
}>;
|
|
24
|
-
/**
|
|
25
|
-
* Build a Subscription field config that emits a Message on every
|
|
16
|
+
* Build a Subscription that emits a Message on every
|
|
26
17
|
* `requestAnimationFrame` tick, with the inter-frame delta in milliseconds.
|
|
27
18
|
*
|
|
28
|
-
* Pair with `S.Boolean` in the `SubscriptionDependencies` schema:
|
|
29
|
-
*
|
|
30
19
|
* @example
|
|
31
20
|
* ```typescript
|
|
32
|
-
* const
|
|
33
|
-
* frame: S.Boolean,
|
|
34
|
-
* })
|
|
35
|
-
*
|
|
36
|
-
* const subscriptions = Subscription.makeSubscriptions(SubscriptionDependencies)<
|
|
37
|
-
* Model,
|
|
38
|
-
* Message
|
|
39
|
-
* >({
|
|
21
|
+
* const subscriptions = Subscription.make<Model, Message>()(_entry => ({
|
|
40
22
|
* frame: Subscription.animationFrame({
|
|
41
23
|
* isActive: model => model.isPlaying,
|
|
42
24
|
* toMessage: deltaTime => Tick({ deltaTime }),
|
|
43
25
|
* }),
|
|
44
|
-
* })
|
|
26
|
+
* }))
|
|
45
27
|
* ```
|
|
46
28
|
*
|
|
47
29
|
* The browser pauses `requestAnimationFrame` when the tab is hidden, so
|
|
48
|
-
* `deltaTime` may spike on the first frame after the
|
|
49
|
-
*
|
|
50
|
-
*
|
|
30
|
+
* `deltaTime` may spike to several seconds on the first frame after the
|
|
31
|
+
* tab regains focus. If your `update` function multiplies `deltaTime`
|
|
32
|
+
* against motion or physics, cap it to a reasonable maximum (32ms is
|
|
33
|
+
* typical) before using it. Otherwise a multi-second `deltaTime` can send
|
|
34
|
+
* moving objects flying across the screen in one frame.
|
|
35
|
+
*
|
|
36
|
+
* Returns an entry shape, not a branded Subscription. Pass it into
|
|
37
|
+
* `Subscription.make` as an entry value.
|
|
51
38
|
*/
|
|
52
|
-
export declare const animationFrame: <Model, Message>(config: AnimationFrameConfig<Model, Message>) =>
|
|
39
|
+
export declare const animationFrame: <Model, Message>(config: AnimationFrameConfig<Model, Message>) => {
|
|
40
|
+
dependenciesSchema: S.Struct<{
|
|
41
|
+
readonly isActive: S.Boolean;
|
|
42
|
+
}>;
|
|
43
|
+
modelToDependencies: (model: Model) => {
|
|
44
|
+
isActive: boolean;
|
|
45
|
+
};
|
|
46
|
+
dependenciesToStream: ({ isActive }: {
|
|
47
|
+
readonly isActive: boolean;
|
|
48
|
+
}) => Stream.Stream<Message, never, never>;
|
|
49
|
+
};
|
|
53
50
|
//# sourceMappingURL=animationFrame.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"animationFrame.d.ts","sourceRoot":"","sources":["../../src/subscription/animationFrame.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,MAAM,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"animationFrame.d.ts","sourceRoot":"","sources":["../../src/subscription/animationFrame.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,MAAM,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE3D;;;;;;;;GAQG;AACH,MAAM,MAAM,oBAAoB,CAAC,KAAK,EAAE,OAAO,IAAI,QAAQ,CAAC;IAC1D,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAA;IACnC,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAA;CAC1C,CAAC,CAAA;AA2BF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,EAAE,OAAO,EAC3C,QAAQ,oBAAoB,CAAC,KAAK,EAAE,OAAO,CAAC;;;;iCAGf,KAAK;;;yCAGG;QAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;KAAE;CAKnE,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, Queue, Stream } from 'effect';
|
|
1
|
+
import { Effect, Queue, Schema as S, Stream } from 'effect';
|
|
2
2
|
const makeAnimationFrameStream = (toMessage) => Stream.callback(queue => Effect.acquireRelease(Effect.sync(() => {
|
|
3
3
|
const state = {
|
|
4
4
|
frameId: 0,
|
|
@@ -14,34 +14,33 @@ const makeAnimationFrameStream = (toMessage) => Stream.callback(queue => Effect.
|
|
|
14
14
|
return state;
|
|
15
15
|
}), state => Effect.sync(() => cancelAnimationFrame(state.frameId))).pipe(Effect.flatMap(() => Effect.never)));
|
|
16
16
|
/**
|
|
17
|
-
* Build a Subscription
|
|
17
|
+
* Build a Subscription that emits a Message on every
|
|
18
18
|
* `requestAnimationFrame` tick, with the inter-frame delta in milliseconds.
|
|
19
19
|
*
|
|
20
|
-
* Pair with `S.Boolean` in the `SubscriptionDependencies` schema:
|
|
21
|
-
*
|
|
22
20
|
* @example
|
|
23
21
|
* ```typescript
|
|
24
|
-
* const
|
|
25
|
-
* frame: S.Boolean,
|
|
26
|
-
* })
|
|
27
|
-
*
|
|
28
|
-
* const subscriptions = Subscription.makeSubscriptions(SubscriptionDependencies)<
|
|
29
|
-
* Model,
|
|
30
|
-
* Message
|
|
31
|
-
* >({
|
|
22
|
+
* const subscriptions = Subscription.make<Model, Message>()(_entry => ({
|
|
32
23
|
* frame: Subscription.animationFrame({
|
|
33
24
|
* isActive: model => model.isPlaying,
|
|
34
25
|
* toMessage: deltaTime => Tick({ deltaTime }),
|
|
35
26
|
* }),
|
|
36
|
-
* })
|
|
27
|
+
* }))
|
|
37
28
|
* ```
|
|
38
29
|
*
|
|
39
30
|
* The browser pauses `requestAnimationFrame` when the tab is hidden, so
|
|
40
|
-
* `deltaTime` may spike on the first frame after the
|
|
41
|
-
*
|
|
42
|
-
*
|
|
31
|
+
* `deltaTime` may spike to several seconds on the first frame after the
|
|
32
|
+
* tab regains focus. If your `update` function multiplies `deltaTime`
|
|
33
|
+
* against motion or physics, cap it to a reasonable maximum (32ms is
|
|
34
|
+
* typical) before using it. Otherwise a multi-second `deltaTime` can send
|
|
35
|
+
* moving objects flying across the screen in one frame.
|
|
36
|
+
*
|
|
37
|
+
* Returns an entry shape, not a branded Subscription. Pass it into
|
|
38
|
+
* `Subscription.make` as an entry value.
|
|
43
39
|
*/
|
|
44
40
|
export const animationFrame = (config) => ({
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
dependenciesSchema: S.Struct({ isActive: S.Boolean }),
|
|
42
|
+
modelToDependencies: (model) => ({
|
|
43
|
+
isActive: config.isActive(model),
|
|
44
|
+
}),
|
|
45
|
+
dependenciesToStream: ({ isActive }) => Stream.when(makeAnimationFrameStream(config.toMessage), Effect.sync(() => isActive)),
|
|
47
46
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { aggregate, lift, make, persistent } from '../runtime/subscription.js';
|
|
2
2
|
export type { Subscription, Subscriptions } from '../runtime/subscription.js';
|
|
3
3
|
export { animationFrame } from './animationFrame.js';
|
|
4
|
-
export type { AnimationFrameConfig
|
|
4
|
+
export type { AnimationFrameConfig } from './animationFrame.js';
|
|
5
5
|
//# sourceMappingURL=public.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/subscription/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/subscription/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAE9E,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAE7E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { aggregate, lift, make, persistent } from '../runtime/subscription.js';
|
|
2
2
|
export { animationFrame } from './animationFrame.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bubbling.d.ts","sourceRoot":"","sources":["../../../src/test/apps/bubbling.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEhD,OAAO,EAAE,KAAK,IAAI,EAAQ,MAAM,qBAAqB,CAAA;AAKrD,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AACF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAOrC,QAAA,MAAM,OAAO,sLAAsD,CAAA;AACnE,KAAK,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIlC,eAAO,MAAM,YAAY,EAAE,KAG1B,CAAA;AAID,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,CAUrC,CAAA;
|
|
1
|
+
{"version":3,"file":"bubbling.d.ts","sourceRoot":"","sources":["../../../src/test/apps/bubbling.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEhD,OAAO,EAAE,KAAK,IAAI,EAAQ,MAAM,qBAAqB,CAAA;AAKrD,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AACF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAOrC,QAAA,MAAM,OAAO,sLAAsD,CAAA;AACnE,KAAK,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIlC,eAAO,MAAM,YAAY,EAAE,KAG1B,CAAA;AAID,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,CAUrC,CAAA;AAIH,eAAO,MAAM,IAAI,GAAI,OAAO,KAAK,KAAG,IAgBnC,CAAA"}
|
|
@@ -24,8 +24,10 @@ export const update = (model, message) => M.value(message).pipe(M.withReturnType
|
|
|
24
24
|
],
|
|
25
25
|
}));
|
|
26
26
|
// VIEW
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
h.div([
|
|
30
|
-
|
|
31
|
-
])
|
|
27
|
+
export const view = (model) => {
|
|
28
|
+
const h = html();
|
|
29
|
+
return h.div([], [
|
|
30
|
+
h.div([h.Role('option'), h.OnClick(ClickedContainer())], [h.span([], [`clicks=${model.clicks}`])]),
|
|
31
|
+
h.div([h.Role('listitem'), h.OnDoubleClick(DoubleClickedContainer())], [h.span([], [`dbl=${model.doubleClicks}`])]),
|
|
32
|
+
]);
|
|
33
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"counter.d.ts","sourceRoot":"","sources":["../../../src/test/apps/counter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAc,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAExD,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAA;AACjD,OAAO,EAAE,KAAK,IAAI,EAAQ,MAAM,qBAAqB,CAAA;AAKrD,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AACF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,eAAO,MAAM,gBAAgB,8EAAwB,CAAA;AACrD,eAAO,MAAM,gBAAgB,8EAAwB,CAAA;AACrD,eAAO,MAAM,YAAY,0EAAoB,CAAA;AAC7C,eAAO,MAAM,gBAAgB;;EAA0C,CAAA;AACvE,eAAO,MAAM,mBAAmB,iFAA2B,CAAA;AAC3D,eAAO,MAAM,qBAAqB,mFAA6B,CAAA;AAC/D,eAAO,MAAM,mBAAmB,iFAA2B,CAAA;AAC3D,eAAO,MAAM,mBAAmB;;EAAgD,CAAA;AAChF,eAAO,MAAM,gBAAgB;;EAA6C,CAAA;AAE1E,eAAO,MAAM,OAAO;;;;;;IAUlB,CAAA;AACF,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,eAAO,MAAM,UAAU;;;iBAIgC,CAAA;AAEvD,eAAO,MAAM,cAAc;;;;;iBAKyC,CAAA;AAIpE,eAAO,MAAM,YAAY,EAAE,KAA6B,CAAA;AAIxD,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAiCxD,CAAA;
|
|
1
|
+
{"version":3,"file":"counter.d.ts","sourceRoot":"","sources":["../../../src/test/apps/counter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAc,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAExD,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAA;AACjD,OAAO,EAAE,KAAK,IAAI,EAAQ,MAAM,qBAAqB,CAAA;AAKrD,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AACF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,eAAO,MAAM,gBAAgB,8EAAwB,CAAA;AACrD,eAAO,MAAM,gBAAgB,8EAAwB,CAAA;AACrD,eAAO,MAAM,YAAY,0EAAoB,CAAA;AAC7C,eAAO,MAAM,gBAAgB;;EAA0C,CAAA;AACvE,eAAO,MAAM,mBAAmB,iFAA2B,CAAA;AAC3D,eAAO,MAAM,qBAAqB,mFAA6B,CAAA;AAC/D,eAAO,MAAM,mBAAmB,iFAA2B,CAAA;AAC3D,eAAO,MAAM,mBAAmB;;EAAgD,CAAA;AAChF,eAAO,MAAM,gBAAgB;;EAA6C,CAAA;AAE1E,eAAO,MAAM,OAAO;;;;;;IAUlB,CAAA;AACF,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,eAAO,MAAM,UAAU;;;iBAIgC,CAAA;AAEvD,eAAO,MAAM,cAAc;;;;;iBAKyC,CAAA;AAIpE,eAAO,MAAM,YAAY,EAAE,KAA6B,CAAA;AAIxD,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAiCxD,CAAA;AAIH,eAAO,MAAM,IAAI,GAAI,OAAO,KAAK,KAAG,IAiBnC,CAAA"}
|
|
@@ -63,9 +63,11 @@ export const update = (model, message) => M.value(message).pipe(M.withReturnType
|
|
|
63
63
|
FailedFetchCount: () => [model, []],
|
|
64
64
|
}));
|
|
65
65
|
// VIEW
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
h.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
])
|
|
66
|
+
export const view = (model) => {
|
|
67
|
+
const h = html();
|
|
68
|
+
return h.div([], [
|
|
69
|
+
h.span([h.Role('status')], [`count: ${model.count}`]),
|
|
70
|
+
h.button([h.OnClick(StartedThreeFetches()), h.Role('button')], ['Start three fetches']),
|
|
71
|
+
h.button([h.OnClick(StartedTwoFetchesById()), h.Role('button')], ['Start two fetches by id']),
|
|
72
|
+
]);
|
|
73
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"disabledButton.d.ts","sourceRoot":"","sources":["../../../src/test/apps/disabledButton.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAExD,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAA;AACjD,OAAO,EAAE,KAAK,IAAI,EAAQ,MAAM,qBAAqB,CAAA;AAMrD,eAAO,MAAM,KAAK;;;;;;;;;;;;;EAGhB,CAAA;AACF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,eAAO,MAAM,aAAa,2EAAqB,CAAA;AAC/C,eAAO,MAAM,aAAa,2EAAqB,CAAA;AAC/C,eAAO,MAAM,gBAAgB;;;;EAE3B,CAAA;AAEF,eAAO,MAAM,OAAO;;;;IAA4D,CAAA;AAChF,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,eAAO,MAAM,YAAY,EAAE,KAG1B,CAAA;AAID,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAyBxD,CAAA;
|
|
1
|
+
{"version":3,"file":"disabledButton.d.ts","sourceRoot":"","sources":["../../../src/test/apps/disabledButton.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAExD,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAA;AACjD,OAAO,EAAE,KAAK,IAAI,EAAQ,MAAM,qBAAqB,CAAA;AAMrD,eAAO,MAAM,KAAK;;;;;;;;;;;;;EAGhB,CAAA;AACF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,eAAO,MAAM,aAAa,2EAAqB,CAAA;AAC/C,eAAO,MAAM,aAAa,2EAAqB,CAAA;AAC/C,eAAO,MAAM,gBAAgB;;;;EAE3B,CAAA;AAEF,eAAO,MAAM,OAAO;;;;IAA4D,CAAA;AAChF,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,eAAO,MAAM,YAAY,EAAE,KAG1B,CAAA;AAID,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAyBxD,CAAA;AAgBH,sCAAsC;AACtC,eAAO,MAAM,IAAI,GAAI,OAAO,KAAK,KAAG,IAUnC,CAAA;AAED,8DAA8D;AAC9D,eAAO,MAAM,cAAc,GAAI,OAAO,KAAK,KAAG,IAe7C,CAAA;AAKD,eAAO,MAAM,kBAAkB,GAAI,OAAO,KAAK,KAAG,IAejD,CAAA"}
|
|
@@ -33,28 +33,39 @@ export const update = (model, message) => M.value(message).pipe(M.withReturnType
|
|
|
33
33
|
},
|
|
34
34
|
}));
|
|
35
35
|
// VIEW
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
h.
|
|
39
|
-
|
|
40
|
-
]
|
|
36
|
+
const submitButton = (isEnabled) => {
|
|
37
|
+
const h = html();
|
|
38
|
+
return h.button([
|
|
39
|
+
h.Class('submit'),
|
|
40
|
+
...(isEnabled ? [h.OnClick(ClickedSubmit())] : [h.Disabled(true)]),
|
|
41
|
+
], ['Submit']);
|
|
42
|
+
};
|
|
41
43
|
/** Plain view — no dialog wrapper. */
|
|
42
|
-
export const view = (model) =>
|
|
43
|
-
h
|
|
44
|
-
|
|
45
|
-
])
|
|
44
|
+
export const view = (model) => {
|
|
45
|
+
const h = html();
|
|
46
|
+
return h.div([], [
|
|
47
|
+
h.button([h.OnClick(ClickedToggle())], ['Toggle']),
|
|
48
|
+
submitButton(model.isEnabled),
|
|
49
|
+
]);
|
|
50
|
+
};
|
|
46
51
|
/** View with submit button inside a dialog's panelContent. */
|
|
47
|
-
export const viewWithDialog = (model) =>
|
|
48
|
-
h
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
export const viewWithDialog = (model) => {
|
|
53
|
+
const h = html();
|
|
54
|
+
return h.div([], [
|
|
55
|
+
h.button([h.OnClick(ClickedToggle())], ['Toggle']),
|
|
56
|
+
Dialog.view({
|
|
57
|
+
model: model.dialog,
|
|
58
|
+
toParentMessage: (dialogMessage) => GotDialogMessage({ message: dialogMessage }),
|
|
59
|
+
panelContent: submitButton(model.isEnabled),
|
|
60
|
+
}),
|
|
61
|
+
]);
|
|
62
|
+
};
|
|
55
63
|
/** View using Dialog.lazy with panelContent passed dynamically. */
|
|
56
64
|
const lazyDialogView = Dialog.lazy({});
|
|
57
|
-
export const viewWithLazyDialog = (model) =>
|
|
58
|
-
h
|
|
59
|
-
|
|
60
|
-
])
|
|
65
|
+
export const viewWithLazyDialog = (model) => {
|
|
66
|
+
const h = html();
|
|
67
|
+
return h.div([], [
|
|
68
|
+
h.button([h.OnClick(ClickedToggle())], ['Toggle']),
|
|
69
|
+
lazyDialogView(model.dialog, (dialogMessage) => GotDialogMessage({ message: dialogMessage }), submitButton(model.isEnabled)),
|
|
70
|
+
]);
|
|
71
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileUpload.d.ts","sourceRoot":"","sources":["../../../src/test/apps/fileUpload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEhD,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAE,KAAK,IAAI,EAAQ,MAAM,qBAAqB,CAAA;AAKrD,MAAM,MAAM,KAAK,GAAG,QAAQ,CAAC;IAC3B,aAAa,EAAE,aAAa,CAAC,IAAI,CAAC,CAAA;CACnC,CAAC,CAAA;AAEF,eAAO,MAAM,YAAY,EAAE,KAA6B,CAAA;AAIxD,eAAO,MAAM,aAAa;;EAA+C,CAAA;AAEzE,eAAO,MAAM,OAAO;;IAA2B,CAAA;AAC/C,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,CAMrC,CAAA;
|
|
1
|
+
{"version":3,"file":"fileUpload.d.ts","sourceRoot":"","sources":["../../../src/test/apps/fileUpload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEhD,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAE,KAAK,IAAI,EAAQ,MAAM,qBAAqB,CAAA;AAKrD,MAAM,MAAM,KAAK,GAAG,QAAQ,CAAC;IAC3B,aAAa,EAAE,aAAa,CAAC,IAAI,CAAC,CAAA;CACnC,CAAC,CAAA;AAEF,eAAO,MAAM,YAAY,EAAE,KAA6B,CAAA;AAIxD,eAAO,MAAM,aAAa;;EAA+C,CAAA;AAEzE,eAAO,MAAM,OAAO;;IAA2B,CAAA;AAC/C,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,CAMrC,CAAA;AAIH,eAAO,MAAM,IAAI,GAAI,OAAO,KAAK,KAAG,IA8BnC,CAAA"}
|
|
@@ -11,19 +11,21 @@ export const update = (model, message) => M.value(message).pipe(M.withReturnType
|
|
|
11
11
|
ReceivedFiles: ({ files }) => [{ ...model, receivedFiles: files }, []],
|
|
12
12
|
}));
|
|
13
13
|
// VIEW
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
h.
|
|
17
|
-
h.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
h.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
])
|
|
14
|
+
export const view = (model) => {
|
|
15
|
+
const h = html();
|
|
16
|
+
return h.div([], [
|
|
17
|
+
h.input([
|
|
18
|
+
h.Key('file-input'),
|
|
19
|
+
h.AriaLabel('resume'),
|
|
20
|
+
h.Type('file'),
|
|
21
|
+
h.OnFileChange(files => ReceivedFiles({ files })),
|
|
22
|
+
]),
|
|
23
|
+
h.div([
|
|
24
|
+
h.Key('drop-zone'),
|
|
25
|
+
h.AriaLabel('attachments'),
|
|
26
|
+
h.OnDropFiles(files => ReceivedFiles({ files })),
|
|
27
|
+
], ['Drop files here']),
|
|
28
|
+
h.div([h.Key('received-count')], [`count=${String(model.receivedFiles.length)}`]),
|
|
29
|
+
h.div([h.Key('received-names')], [`names=${model.receivedFiles.map(file => file.name).join(',')}`]),
|
|
30
|
+
]);
|
|
31
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactions.d.ts","sourceRoot":"","sources":["../../../src/test/apps/interactions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEhD,OAAO,EAAE,KAAK,IAAI,EAAQ,MAAM,qBAAqB,CAAA;AAKrD,eAAO,MAAM,KAAK;;;;;;EAMhB,CAAA;AACF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,eAAO,MAAM,aAAa,2EAAqB,CAAA;AAC/C,eAAO,MAAM,mBAAmB,iFAA2B,CAAA;AAC3D,eAAO,MAAM,aAAa,2EAAqB,CAAA;AAC/C,eAAO,MAAM,YAAY,0EAAoB,CAAA;AAC7C,eAAO,MAAM,YAAY,0EAAoB,CAAA;AAC7C,eAAO,MAAM,aAAa;;EAA0C,CAAA;AAEpE,eAAO,MAAM,OAAO;;IAOlB,CAAA;AACF,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAA;AAID,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,CAcrC,CAAA;
|
|
1
|
+
{"version":3,"file":"interactions.d.ts","sourceRoot":"","sources":["../../../src/test/apps/interactions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEhD,OAAO,EAAE,KAAK,IAAI,EAAQ,MAAM,qBAAqB,CAAA;AAKrD,eAAO,MAAM,KAAK;;;;;;EAMhB,CAAA;AACF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,eAAO,MAAM,aAAa,2EAAqB,CAAA;AAC/C,eAAO,MAAM,mBAAmB,iFAA2B,CAAA;AAC3D,eAAO,MAAM,aAAa,2EAAqB,CAAA;AAC/C,eAAO,MAAM,YAAY,0EAAoB,CAAA;AAC7C,eAAO,MAAM,YAAY,0EAAoB,CAAA;AAC7C,eAAO,MAAM,aAAa;;EAA0C,CAAA;AAEpE,eAAO,MAAM,OAAO;;IAOlB,CAAA;AACF,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAA;AAID,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,CAcrC,CAAA;AAIH,eAAO,MAAM,IAAI,GAAI,OAAO,KAAK,KAAG,IA8BnC,CAAA"}
|