foldkit 0.137.0 → 0.138.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/dist/dom/dom.d.ts +13 -0
- package/dist/dom/dom.d.ts.map +1 -1
- package/dist/dom/dom.js +13 -0
- package/dist/html/index.d.ts +1 -1
- package/dist/html/index.d.ts.map +1 -1
- package/dist/render/commit.d.ts +44 -0
- package/dist/render/commit.d.ts.map +1 -0
- package/dist/render/commit.js +58 -0
- package/dist/render/render.d.ts +12 -7
- package/dist/render/render.d.ts.map +1 -1
- package/dist/render/render.js +45 -17
- package/dist/runtime/public.d.ts +1 -0
- package/dist/runtime/public.d.ts.map +1 -1
- package/dist/runtime/runtime.d.ts +20 -9
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +1013 -789
- package/dist/runtime/viewTransition.d.ts +69 -0
- package/dist/runtime/viewTransition.d.ts.map +1 -0
- package/dist/runtime/viewTransition.js +37 -0
- package/dist/test/apps/attributes.js +1 -1
- package/dist/test/apps/mountPanel.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Option } from 'effect';
|
|
2
|
+
/** Context passed to the `viewTransition` predicate before each live render.
|
|
3
|
+
*
|
|
4
|
+
* A View Transition animates between two states, so the predicate is given
|
|
5
|
+
* both. `previousModel` is the Model behind the DOM on screen, the state the
|
|
6
|
+
* browser is about to snapshot. `model` is the Model the pending render will
|
|
7
|
+
* paint. Direction is the pair: comparing the two says where the application
|
|
8
|
+
* is going and where it came from, with no route history kept in the Model.
|
|
9
|
+
*
|
|
10
|
+
* `previousModel` is always a real painted state rather than an `Option`. The
|
|
11
|
+
* predicate only runs once a Message has dirtied the Model, and the initial
|
|
12
|
+
* render completes before any Message is processed.
|
|
13
|
+
*
|
|
14
|
+
* `message` is the Message that dirtied the Model for this frame. The runtime
|
|
15
|
+
* coalesces a burst of dispatches into one render frame, so the predicate
|
|
16
|
+
* sees the last dirtying Message before the frame. */
|
|
17
|
+
export type ViewTransitionContext<Model, Message> = Readonly<{
|
|
18
|
+
previousModel: Model;
|
|
19
|
+
model: Model;
|
|
20
|
+
message: Message;
|
|
21
|
+
}>;
|
|
22
|
+
/** What the `viewTransition` predicate returns for a render. `false` renders
|
|
23
|
+
* plainly. `true` wraps the render in `document.startViewTransition`.
|
|
24
|
+
* `{ types }` additionally tags the transition so CSS can scope animations
|
|
25
|
+
* via `:active-view-transition-type(...)`. */
|
|
26
|
+
export type ViewTransitionDecision = boolean | Readonly<{
|
|
27
|
+
types: ReadonlyArray<string>;
|
|
28
|
+
}>;
|
|
29
|
+
/** Decides, per render, whether the DOM update should run inside a View
|
|
30
|
+
* Transition. The predicate is total over the Message union, so animation is
|
|
31
|
+
* opted into per Message: return `true` for the ones worth animating and
|
|
32
|
+
* `false` for everything else. */
|
|
33
|
+
export type ViewTransitionConfig<Model, Message> = (context: ViewTransitionContext<Model, Message>) => ViewTransitionDecision;
|
|
34
|
+
/** The slice of the DOM `ViewTransition` handle the runtime consumes. `ready`
|
|
35
|
+
* and `finished` are optional: the runtime only ever attaches rejection
|
|
36
|
+
* handlers to them, so a handle that omits them stays valid. */
|
|
37
|
+
export type ViewTransitionHandle = Readonly<{
|
|
38
|
+
updateCallbackDone: Promise<void>;
|
|
39
|
+
skipTransition: () => void;
|
|
40
|
+
ready?: Promise<void>;
|
|
41
|
+
finished?: Promise<void>;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* Attaches no-op rejection handlers to a transition's promises.
|
|
45
|
+
*
|
|
46
|
+
* The browser rejects `ready` whenever a transition is skipped, and skipping
|
|
47
|
+
* is routine rather than exceptional: a second navigation lands mid-animation,
|
|
48
|
+
* the document is hidden, or the runtime skips the transition itself while
|
|
49
|
+
* tearing down. The runtime never awaits any of these promises, so without a
|
|
50
|
+
* handler every skip surfaces as an unhandled rejection and lands in whatever
|
|
51
|
+
* the application wired to `window.onunhandledrejection`, turning a purely
|
|
52
|
+
* cosmetic animation into an error report.
|
|
53
|
+
*/
|
|
54
|
+
export declare const __silenceViewTransitionRejections: (handle: ViewTransitionHandle) => void;
|
|
55
|
+
/** Starts a View Transition around `update`. Injected into the render path so
|
|
56
|
+
* tests can fake the browser API. */
|
|
57
|
+
export type StartViewTransition = (update: () => void, maybeTypes: Option.Option<ReadonlyArray<string>>) => ViewTransitionHandle;
|
|
58
|
+
/** Feature-detects `document.startViewTransition`, returning `Option.none()`
|
|
59
|
+
* where the API is unavailable so the runtime falls through to plain
|
|
60
|
+
* renders. Transition types are newer than the API itself, so when the
|
|
61
|
+
* running browser only supports the callback form the types are dropped and
|
|
62
|
+
* the transition still runs untyped. */
|
|
63
|
+
export declare const __resolveStartViewTransition: () => Option.Option<StartViewTransition>;
|
|
64
|
+
/** Normalizes a `ViewTransitionDecision` into "skip" (`Option.none()`) or
|
|
65
|
+
* "transition, with these types" so the render path branches once. */
|
|
66
|
+
export declare const __decideViewTransition: <Model, Message>(decide: ViewTransitionConfig<Model, Message>, context: ViewTransitionContext<Model, Message>) => Option.Option<Readonly<{
|
|
67
|
+
maybeTypes: Option.Option<ReadonlyArray<string>>;
|
|
68
|
+
}>>;
|
|
69
|
+
//# sourceMappingURL=viewTransition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewTransition.d.ts","sourceRoot":"","sources":["../../src/runtime/viewTransition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAQ,MAAM,QAAQ,CAAA;AAE5C;;;;;;;;;;;;;;uDAcuD;AACvD,MAAM,MAAM,qBAAqB,CAAC,KAAK,EAAE,OAAO,IAAI,QAAQ,CAAC;IAC3D,aAAa,EAAE,KAAK,CAAA;IACpB,KAAK,EAAE,KAAK,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;CACjB,CAAC,CAAA;AAEF;;;+CAG+C;AAC/C,MAAM,MAAM,sBAAsB,GAC9B,OAAO,GACP,QAAQ,CAAC;IAAE,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAAA;AAE9C;;;mCAGmC;AACnC,MAAM,MAAM,oBAAoB,CAAC,KAAK,EAAE,OAAO,IAAI,CACjD,OAAO,EAAE,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC,KAC3C,sBAAsB,CAAA;AAE3B;;iEAEiE;AACjE,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C,kBAAkB,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IACjC,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CACzB,CAAC,CAAA;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iCAAiC,GAC5C,QAAQ,oBAAoB,KAC3B,IAKF,CAAA;AAED;sCACsC;AACtC,MAAM,MAAM,mBAAmB,GAAG,CAChC,MAAM,EAAE,MAAM,IAAI,EAClB,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,KAC7C,oBAAoB,CAAA;AAEzB;;;;yCAIyC;AACzC,eAAO,MAAM,4BAA4B,QACnC,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAoBpC,CAAA;AAEH;uEACuE;AACvE,eAAO,MAAM,sBAAsB,GAAI,KAAK,EAAE,OAAO,EACnD,QAAQ,oBAAoB,CAAC,KAAK,EAAE,OAAO,CAAC,EAC5C,SAAS,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC,KAC7C,MAAM,CAAC,MAAM,CACd,QAAQ,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;CAAE,CAAC,CAa7D,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Match, Option, pipe } from 'effect';
|
|
2
|
+
/**
|
|
3
|
+
* Attaches no-op rejection handlers to a transition's promises.
|
|
4
|
+
*
|
|
5
|
+
* The browser rejects `ready` whenever a transition is skipped, and skipping
|
|
6
|
+
* is routine rather than exceptional: a second navigation lands mid-animation,
|
|
7
|
+
* the document is hidden, or the runtime skips the transition itself while
|
|
8
|
+
* tearing down. The runtime never awaits any of these promises, so without a
|
|
9
|
+
* handler every skip surfaces as an unhandled rejection and lands in whatever
|
|
10
|
+
* the application wired to `window.onunhandledrejection`, turning a purely
|
|
11
|
+
* cosmetic animation into an error report.
|
|
12
|
+
*/
|
|
13
|
+
export const __silenceViewTransitionRejections = (handle) => {
|
|
14
|
+
const ignore = () => { };
|
|
15
|
+
handle.ready?.catch(ignore);
|
|
16
|
+
handle.finished?.catch(ignore);
|
|
17
|
+
handle.updateCallbackDone.catch(ignore);
|
|
18
|
+
};
|
|
19
|
+
/** Feature-detects `document.startViewTransition`, returning `Option.none()`
|
|
20
|
+
* where the API is unavailable so the runtime falls through to plain
|
|
21
|
+
* renders. Transition types are newer than the API itself, so when the
|
|
22
|
+
* running browser only supports the callback form the types are dropped and
|
|
23
|
+
* the transition still runs untyped. */
|
|
24
|
+
export const __resolveStartViewTransition = () => {
|
|
25
|
+
if (typeof document.startViewTransition !== 'function') {
|
|
26
|
+
return Option.none();
|
|
27
|
+
}
|
|
28
|
+
const isTypesSupported = typeof ViewTransition !== 'undefined' &&
|
|
29
|
+
'types' in ViewTransition.prototype;
|
|
30
|
+
return Option.some((update, maybeTypes) => pipe(maybeTypes, Option.filter(() => isTypesSupported), Option.match({
|
|
31
|
+
onNone: () => document.startViewTransition(update),
|
|
32
|
+
onSome: types => document.startViewTransition({ update, types: [...types] }),
|
|
33
|
+
})));
|
|
34
|
+
};
|
|
35
|
+
/** Normalizes a `ViewTransitionDecision` into "skip" (`Option.none()`) or
|
|
36
|
+
* "transition, with these types" so the render path branches once. */
|
|
37
|
+
export const __decideViewTransition = (decide, context) => Match.value(decide(context)).pipe(Match.withReturnType(), Match.when(false, () => Option.none()), Match.when(true, () => Option.some({ maybeTypes: Option.none() })), Match.orElse(({ types }) => Option.some({ maybeTypes: Option.some(types) })));
|
|
@@ -11,5 +11,5 @@ export const update = (model, message) => M.value(message).pipe(M.withReturnType
|
|
|
11
11
|
const TEST_ID = 'attribute-host';
|
|
12
12
|
export const testId = TEST_ID;
|
|
13
13
|
export const view = (model, h) => {
|
|
14
|
-
return h.div([h.DataAttribute('testid', TEST_ID), model.attribute]
|
|
14
|
+
return h.div([h.DataAttribute('testid', TEST_ID), model.attribute]);
|
|
15
15
|
};
|
|
@@ -88,5 +88,5 @@ export const twoPanelView = (model, h) => {
|
|
|
88
88
|
* pending Mount's args). The chosen `offset` flows through `ScrollList`'s
|
|
89
89
|
* args and is observable on the rendered Mount marker. */
|
|
90
90
|
export const scrollListView = (offset, h) => {
|
|
91
|
-
return h.div([h.Class('scroll-list')], [h.div([h.Key('list'), h.OnMount(ScrollList({ offset }))]
|
|
91
|
+
return h.div([h.Class('scroll-list')], [h.div([h.Key('list'), h.OnMount(ScrollList({ offset }))])]);
|
|
92
92
|
};
|