@gtkx/animated 1.2.2
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 +172 -0
- package/dist/animated.d.ts +20 -0
- package/dist/animated.d.ts.map +1 -0
- package/dist/animated.js +44 -0
- package/dist/animated.js.map +1 -0
- package/dist/apply-animated-values.d.ts +4 -0
- package/dist/apply-animated-values.d.ts.map +1 -0
- package/dist/apply-animated-values.js +84 -0
- package/dist/apply-animated-values.js.map +1 -0
- package/dist/bootstrap.d.ts +2 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +11 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/reduced-motion.d.ts +13 -0
- package/dist/reduced-motion.d.ts.map +1 -0
- package/dist/reduced-motion.js +59 -0
- package/dist/reduced-motion.js.map +1 -0
- package/dist/request-frame.d.ts +4 -0
- package/dist/request-frame.d.ts.map +1 -0
- package/dist/request-frame.js +155 -0
- package/dist/request-frame.js.map +1 -0
- package/dist/types.d.ts +38 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/with-animated.d.ts +6 -0
- package/dist/with-animated.d.ts.map +1 -0
- package/dist/with-animated.js +181 -0
- package/dist/with-animated.js.map +1 -0
- package/package.json +78 -0
- package/src/animated.ts +62 -0
- package/src/apply-animated-values.ts +116 -0
- package/src/bootstrap.ts +12 -0
- package/src/index.ts +110 -0
- package/src/reduced-motion.ts +82 -0
- package/src/request-frame.ts +214 -0
- package/src/types.ts +64 -0
- package/src/with-animated.tsx +254 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import * as GLib from "@gtkx/gi/glib";
|
|
2
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
3
|
+
const FALLBACK_FRAME_MS = 16;
|
|
4
|
+
const MIN_FRAME_MS = 1;
|
|
5
|
+
const STALL_MS = 250;
|
|
6
|
+
const STALL_COOLDOWN_MS = 1000;
|
|
7
|
+
const scheduler = {
|
|
8
|
+
callbacks: [],
|
|
9
|
+
driver: null,
|
|
10
|
+
fallbackTimer: null,
|
|
11
|
+
flushedAt: 0,
|
|
12
|
+
isTicking: false,
|
|
13
|
+
stalledUntil: new WeakMap(),
|
|
14
|
+
ticks: 0,
|
|
15
|
+
};
|
|
16
|
+
const isSuspended = (widget) => widget instanceof Gtk.Window && widget.isSuspended();
|
|
17
|
+
const hasClock = (widget) => widget.getMapped() && widget.getFrameClock() !== null && !isSuspended(widget);
|
|
18
|
+
const isCoolingDown = (widget) => {
|
|
19
|
+
const until = scheduler.stalledUntil.get(widget);
|
|
20
|
+
if (until === undefined) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (performance.now() < until) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
scheduler.stalledUntil.delete(widget);
|
|
27
|
+
return false;
|
|
28
|
+
};
|
|
29
|
+
const findDriverWidget = () => {
|
|
30
|
+
const candidates = Gtk.Window.listToplevels().filter((widget) => hasClock(widget));
|
|
31
|
+
return candidates.find((widget) => !scheduler.stalledUntil.has(widget)) ??
|
|
32
|
+
candidates.find((widget) => !isCoolingDown(widget)) ??
|
|
33
|
+
null;
|
|
34
|
+
};
|
|
35
|
+
const flush = () => {
|
|
36
|
+
const pending = scheduler.callbacks;
|
|
37
|
+
scheduler.callbacks = [];
|
|
38
|
+
scheduler.isTicking = true;
|
|
39
|
+
scheduler.flushedAt = performance.now();
|
|
40
|
+
try {
|
|
41
|
+
for (const callback of pending) {
|
|
42
|
+
callback();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
scheduler.isTicking = false;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const armStallSource = () => GLib.timeoutAdd(GLib.PRIORITY_DEFAULT_IDLE, STALL_MS, shouldRepeatStallCheck);
|
|
50
|
+
const cancelStallSource = (driver) => {
|
|
51
|
+
if (driver.stallSource === 0) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
GLib.Source.remove(driver.stallSource);
|
|
55
|
+
driver.stallSource = 0;
|
|
56
|
+
};
|
|
57
|
+
const finishDriver = (driver) => {
|
|
58
|
+
cancelStallSource(driver);
|
|
59
|
+
driver.widget.off("unmap", onDriverUnmapped);
|
|
60
|
+
scheduler.driver = null;
|
|
61
|
+
};
|
|
62
|
+
const releaseDriver = (driver) => {
|
|
63
|
+
finishDriver(driver);
|
|
64
|
+
driver.widget.removeTickCallback(driver.tickId);
|
|
65
|
+
};
|
|
66
|
+
const flushThenArm = () => {
|
|
67
|
+
try {
|
|
68
|
+
flush();
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
arm();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const shouldContinueTicking = (driver) => {
|
|
75
|
+
if (scheduler.driver !== driver) {
|
|
76
|
+
arm();
|
|
77
|
+
return GLib.SOURCE_REMOVE;
|
|
78
|
+
}
|
|
79
|
+
if (scheduler.callbacks.length === 0) {
|
|
80
|
+
finishDriver(driver);
|
|
81
|
+
return GLib.SOURCE_REMOVE;
|
|
82
|
+
}
|
|
83
|
+
driver.stallSource = armStallSource();
|
|
84
|
+
return GLib.SOURCE_CONTINUE;
|
|
85
|
+
};
|
|
86
|
+
const shouldKeepTicking = () => {
|
|
87
|
+
const { driver } = scheduler;
|
|
88
|
+
if (driver === null) {
|
|
89
|
+
return GLib.SOURCE_REMOVE;
|
|
90
|
+
}
|
|
91
|
+
if (performance.now() - scheduler.flushedAt < MIN_FRAME_MS) {
|
|
92
|
+
return GLib.SOURCE_CONTINUE;
|
|
93
|
+
}
|
|
94
|
+
cancelStallSource(driver);
|
|
95
|
+
scheduler.ticks += 1;
|
|
96
|
+
scheduler.stalledUntil.delete(driver.widget);
|
|
97
|
+
try {
|
|
98
|
+
flush();
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
finishDriver(driver);
|
|
102
|
+
arm();
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
return shouldContinueTicking(driver);
|
|
106
|
+
};
|
|
107
|
+
const onFallbackFrame = () => {
|
|
108
|
+
scheduler.fallbackTimer = null;
|
|
109
|
+
flushThenArm();
|
|
110
|
+
};
|
|
111
|
+
const armDriver = (widget) => {
|
|
112
|
+
const tickId = widget.addTickCallback(shouldKeepTicking);
|
|
113
|
+
scheduler.driver = { widget, tickId, stallSource: armStallSource() };
|
|
114
|
+
widget.on("unmap", onDriverUnmapped);
|
|
115
|
+
};
|
|
116
|
+
function shouldRepeatStallCheck() {
|
|
117
|
+
const { driver } = scheduler;
|
|
118
|
+
if (driver !== null) {
|
|
119
|
+
driver.stallSource = 0;
|
|
120
|
+
releaseDriver(driver);
|
|
121
|
+
scheduler.stalledUntil.set(driver.widget, performance.now() + STALL_COOLDOWN_MS);
|
|
122
|
+
flushThenArm();
|
|
123
|
+
}
|
|
124
|
+
return GLib.SOURCE_REMOVE;
|
|
125
|
+
}
|
|
126
|
+
function onDriverUnmapped() {
|
|
127
|
+
const { driver } = scheduler;
|
|
128
|
+
if (driver === null) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
scheduler.stalledUntil.delete(driver.widget);
|
|
132
|
+
releaseDriver(driver);
|
|
133
|
+
if (!scheduler.isTicking) {
|
|
134
|
+
arm();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function arm() {
|
|
138
|
+
if (scheduler.callbacks.length === 0 || scheduler.driver !== null || scheduler.fallbackTimer !== null) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const widget = findDriverWidget();
|
|
142
|
+
if (widget === null) {
|
|
143
|
+
scheduler.fallbackTimer = setTimeout(onFallbackFrame, FALLBACK_FRAME_MS);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
armDriver(widget);
|
|
147
|
+
}
|
|
148
|
+
const requestFrame = (callback) => {
|
|
149
|
+
scheduler.callbacks.push(callback);
|
|
150
|
+
if (!scheduler.isTicking) {
|
|
151
|
+
arm();
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
export { requestFrame };
|
|
155
|
+
//# sourceMappingURL=request-frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-frame.js","sourceRoot":"","sources":["../src/request-frame.ts"],"names":[],"mappings":"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","sourcesContent":["import * as GLib from \"@gtkx/gi/glib\";\nimport * as Gtk from \"@gtkx/gi/gtk\";\n\ntype FrameCallback = () => void;\ntype Timer = ReturnType<typeof setTimeout>;\ntype Driver = { widget: Gtk.Widget; tickId: number; stallSource: number };\n\ntype Scheduler = {\n callbacks: FrameCallback[];\n driver: Driver | null;\n fallbackTimer: Timer | null;\n flushedAt: number;\n isTicking: boolean;\n stalledUntil: WeakMap<Gtk.Widget, number>;\n ticks: number;\n};\n\nconst FALLBACK_FRAME_MS = 16;\nconst MIN_FRAME_MS = 1;\nconst STALL_MS = 250;\nconst STALL_COOLDOWN_MS = 1000;\n\nconst scheduler: Scheduler = {\n callbacks: [],\n driver: null,\n fallbackTimer: null,\n flushedAt: 0,\n isTicking: false,\n stalledUntil: new WeakMap(),\n ticks: 0,\n};\n\nconst isSuspended = (widget: Gtk.Widget): boolean => widget instanceof Gtk.Window && widget.isSuspended();\n\nconst hasClock = (widget: Gtk.Widget): boolean =>\n widget.getMapped() && widget.getFrameClock() !== null && !isSuspended(widget);\n\nconst isCoolingDown = (widget: Gtk.Widget): boolean => {\n const until = scheduler.stalledUntil.get(widget);\n\n if (until === undefined) {\n return false;\n }\n\n if (performance.now() < until) {\n return true;\n }\n\n scheduler.stalledUntil.delete(widget);\n\n return false;\n};\n\nconst findDriverWidget = (): Gtk.Widget | null => {\n const candidates = Gtk.Window.listToplevels().filter((widget) => hasClock(widget));\n\n return candidates.find((widget) => !scheduler.stalledUntil.has(widget)) ??\n candidates.find((widget) => !isCoolingDown(widget)) ??\n null;\n};\n\nconst flush = (): void => {\n const pending = scheduler.callbacks;\n scheduler.callbacks = [];\n scheduler.isTicking = true;\n scheduler.flushedAt = performance.now();\n\n try {\n for (const callback of pending) {\n callback();\n }\n } finally {\n scheduler.isTicking = false;\n }\n};\n\nconst armStallSource = (): number => GLib.timeoutAdd(GLib.PRIORITY_DEFAULT_IDLE, STALL_MS, shouldRepeatStallCheck);\n\nconst cancelStallSource = (driver: Driver): void => {\n if (driver.stallSource === 0) {\n return;\n }\n\n GLib.Source.remove(driver.stallSource);\n driver.stallSource = 0;\n};\n\nconst finishDriver = (driver: Driver): void => {\n cancelStallSource(driver);\n driver.widget.off(\"unmap\", onDriverUnmapped);\n scheduler.driver = null;\n};\n\nconst releaseDriver = (driver: Driver): void => {\n finishDriver(driver);\n driver.widget.removeTickCallback(driver.tickId);\n};\n\nconst flushThenArm = (): void => {\n try {\n flush();\n } finally {\n arm();\n }\n};\n\nconst shouldContinueTicking = (driver: Driver): boolean => {\n if (scheduler.driver !== driver) {\n arm();\n\n return GLib.SOURCE_REMOVE;\n }\n\n if (scheduler.callbacks.length === 0) {\n finishDriver(driver);\n\n return GLib.SOURCE_REMOVE;\n }\n\n driver.stallSource = armStallSource();\n\n return GLib.SOURCE_CONTINUE;\n};\n\nconst shouldKeepTicking = (): boolean => {\n const { driver } = scheduler;\n\n if (driver === null) {\n return GLib.SOURCE_REMOVE;\n }\n\n if (performance.now() - scheduler.flushedAt < MIN_FRAME_MS) {\n return GLib.SOURCE_CONTINUE;\n }\n\n cancelStallSource(driver);\n scheduler.ticks += 1;\n scheduler.stalledUntil.delete(driver.widget);\n\n try {\n flush();\n } catch (error) {\n finishDriver(driver);\n arm();\n throw error;\n }\n\n return shouldContinueTicking(driver);\n};\n\nconst onFallbackFrame = (): void => {\n scheduler.fallbackTimer = null;\n flushThenArm();\n};\n\nconst armDriver = (widget: Gtk.Widget): void => {\n const tickId = widget.addTickCallback(shouldKeepTicking);\n scheduler.driver = { widget, tickId, stallSource: armStallSource() };\n widget.on(\"unmap\", onDriverUnmapped);\n};\n\nfunction shouldRepeatStallCheck(): boolean {\n const { driver } = scheduler;\n\n if (driver !== null) {\n driver.stallSource = 0;\n releaseDriver(driver);\n scheduler.stalledUntil.set(driver.widget, performance.now() + STALL_COOLDOWN_MS);\n flushThenArm();\n }\n\n return GLib.SOURCE_REMOVE;\n}\n\nfunction onDriverUnmapped(): void {\n const { driver } = scheduler;\n\n if (driver === null) {\n return;\n }\n\n scheduler.stalledUntil.delete(driver.widget);\n releaseDriver(driver);\n\n if (!scheduler.isTicking) {\n arm();\n }\n}\n\nfunction arm(): void {\n if (scheduler.callbacks.length === 0 || scheduler.driver !== null || scheduler.fallbackTimer !== null) {\n return;\n }\n\n const widget = findDriverWidget();\n\n if (widget === null) {\n scheduler.fallbackTimer = setTimeout(onFallbackFrame, FALLBACK_FRAME_MS);\n\n return;\n }\n\n armDriver(widget);\n}\n\nconst requestFrame = (callback: FrameCallback): void => {\n scheduler.callbacks.push(callback);\n\n if (!scheduler.isTicking) {\n arm();\n }\n};\n\nexport { requestFrame };\n"]}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
+
import type * as elements from "@gtkx/jsx";
|
|
3
|
+
import type { FluidValue } from "@react-spring/shared";
|
|
4
|
+
import type { ComponentPropsWithRef, ElementType, FunctionComponent, Ref } from "react";
|
|
5
|
+
/** An array-valued prop whose items may each be a spring or an interpolation, such as mixed text children. */
|
|
6
|
+
type AnimatedItems<T> = [Exclude<Extract<T, Iterable<unknown>>, string>] extends [never] ? never : Exclude<Extract<T, Iterable<unknown>>, string> extends Iterable<infer Item> ? Iterable<AnimatedProp<Item>> : never;
|
|
7
|
+
/** A prop value that an animated component also accepts as a spring or an interpolation. */
|
|
8
|
+
type AnimatedProp<T> = T | FluidValue<Exclude<T, undefined>> | AnimatedItems<Exclude<T, undefined>>;
|
|
9
|
+
/**
|
|
10
|
+
* A `style` object whose declarations may each be a spring or an interpolation, nested blocks
|
|
11
|
+
* included, so the object a spring hook returns can be handed to `style` as it is.
|
|
12
|
+
*/
|
|
13
|
+
type AnimatedStyle<T> = {
|
|
14
|
+
[K in keyof T]: T[K] extends string | number | undefined | null ? AnimatedProp<T[K]> : AnimatedProp<T[K]> | AnimatedStyle<NonNullable<T[K]>>;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The props of an animated component: every prop of the wrapped component, each also accepting a
|
|
18
|
+
* {@link FluidValue} such as a `SpringValue` or an `Interpolation`, while `ref` and `key` keep
|
|
19
|
+
* their original types.
|
|
20
|
+
*/
|
|
21
|
+
type AnimatedProps<Props extends object> = {
|
|
22
|
+
[P in keyof Props]: P extends "key" | "ref" ? Props[P] : P extends "style" ? AnimatedProp<Props[P]> | AnimatedStyle<NonNullable<Props[P]>> : AnimatedProp<Props[P]>;
|
|
23
|
+
};
|
|
24
|
+
/** A component returned by {@link animated}: the wrapped component with animated props. */
|
|
25
|
+
type AnimatedComponent<T extends Exclude<ElementType, string>> = FunctionComponent<AnimatedProps<ComponentPropsWithRef<T>>>;
|
|
26
|
+
/**
|
|
27
|
+
* The widget components of the generated `@gtkx/jsx` store, keyed by element name, each wrapped as
|
|
28
|
+
* an {@link AnimatedComponent}. Only components whose `ref` exposes a `Gtk.Widget` subclass are
|
|
29
|
+
* included, so `animated.GtkLabel` is available while non-widget elements such as `GtkAdjustment`
|
|
30
|
+
* are wrapped explicitly through the `animated(...)` call instead.
|
|
31
|
+
*/
|
|
32
|
+
type AnimatedElements = {
|
|
33
|
+
readonly [K in keyof typeof elements as (typeof elements)[K] extends Exclude<ElementType, string> ? ComponentPropsWithRef<(typeof elements)[K]> extends {
|
|
34
|
+
ref?: Ref<infer Instance> | undefined;
|
|
35
|
+
} ? [NonNullable<Instance>] extends [never] ? never : NonNullable<Instance> extends Gtk.Widget ? K : never : never : never]: (typeof elements)[K] extends Exclude<ElementType, string> ? AnimatedComponent<(typeof elements)[K]> : never;
|
|
36
|
+
};
|
|
37
|
+
export type { AnimatedComponent, AnimatedElements, AnimatedItems, AnimatedProp, AnimatedProps, AnimatedStyle };
|
|
38
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,GAAG,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,KAAK,QAAQ,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAExF,8GAA8G;AAC9G,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAClF,KAAK,GACL,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,QAAQ,CAAC,MAAM,IAAI,CAAC,GACvE,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAC5B,KAAK,CAAC;AAEhB,4FAA4F;AAC5F,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;AAEpG;;;GAGG;AACH,KAAK,aAAa,CAAC,CAAC,IAAI;KACnB,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,GACzD,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAClB,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC9D,CAAC;AAEF;;;;GAIG;AACH,KAAK,aAAa,CAAC,KAAK,SAAS,MAAM,IAAI;KACtC,CAAC,IAAI,MAAM,KAAK,GAAG,CAAC,SAAS,KAAK,GAAG,KAAK,GACrC,KAAK,CAAC,CAAC,CAAC,GACR,CAAC,SAAS,OAAO,GACb,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAC7D,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;CACnC,CAAC;AAEF,2FAA2F;AAC3F,KAAK,iBAAiB,CAAC,CAAC,SAAS,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,iBAAiB,CAC9E,aAAa,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAC1C,CAAC;AAEF;;;;;GAKG;AACH,KAAK,gBAAgB,GAAG;IACpB,QAAQ,EAAE,CAAC,IAAI,MAAM,OAAO,QAAQ,IAAI,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,GAC3F,qBAAqB,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,GAAG,CAAC,EAAE,GAAG,CAAC,MAAM,QAAQ,CAAC,GAAG,SAAS,CAAA;KAAE,GACzF,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC/B,KAAK,GACL,WAAW,CAAC,QAAQ,CAAC,SAAS,GAAG,CAAC,MAAM,GACpC,CAAC,GACD,KAAK,GACjB,KAAK,GACT,KAAK,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,GACjE,iBAAiB,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GACvC,KAAK;CACd,CAAC;AAEF,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type * as Gtk from \"@gtkx/gi/gtk\";\nimport type * as elements from \"@gtkx/jsx\";\nimport type { FluidValue } from \"@react-spring/shared\";\nimport type { ComponentPropsWithRef, ElementType, FunctionComponent, Ref } from \"react\";\n\n/** An array-valued prop whose items may each be a spring or an interpolation, such as mixed text children. */\ntype AnimatedItems<T> = [Exclude<Extract<T, Iterable<unknown>>, string>] extends [never]\n ? never\n : Exclude<Extract<T, Iterable<unknown>>, string> extends Iterable<infer Item>\n ? Iterable<AnimatedProp<Item>>\n : never;\n\n/** A prop value that an animated component also accepts as a spring or an interpolation. */\ntype AnimatedProp<T> = T | FluidValue<Exclude<T, undefined>> | AnimatedItems<Exclude<T, undefined>>;\n\n/**\n * A `style` object whose declarations may each be a spring or an interpolation, nested blocks\n * included, so the object a spring hook returns can be handed to `style` as it is.\n */\ntype AnimatedStyle<T> = {\n [K in keyof T]: T[K] extends string | number | undefined | null\n ? AnimatedProp<T[K]>\n : AnimatedProp<T[K]> | AnimatedStyle<NonNullable<T[K]>>;\n};\n\n/**\n * The props of an animated component: every prop of the wrapped component, each also accepting a\n * {@link FluidValue} such as a `SpringValue` or an `Interpolation`, while `ref` and `key` keep\n * their original types.\n */\ntype AnimatedProps<Props extends object> = {\n [P in keyof Props]: P extends \"key\" | \"ref\"\n ? Props[P]\n : P extends \"style\"\n ? AnimatedProp<Props[P]> | AnimatedStyle<NonNullable<Props[P]>>\n : AnimatedProp<Props[P]>;\n};\n\n/** A component returned by {@link animated}: the wrapped component with animated props. */\ntype AnimatedComponent<T extends Exclude<ElementType, string>> = FunctionComponent<\n AnimatedProps<ComponentPropsWithRef<T>>\n>;\n\n/**\n * The widget components of the generated `@gtkx/jsx` store, keyed by element name, each wrapped as\n * an {@link AnimatedComponent}. Only components whose `ref` exposes a `Gtk.Widget` subclass are\n * included, so `animated.GtkLabel` is available while non-widget elements such as `GtkAdjustment`\n * are wrapped explicitly through the `animated(...)` call instead.\n */\ntype AnimatedElements = {\n readonly [K in keyof typeof elements as (typeof elements)[K] extends Exclude<ElementType, string>\n ? ComponentPropsWithRef<(typeof elements)[K]> extends { ref?: Ref<infer Instance> | undefined }\n ? [NonNullable<Instance>] extends [never]\n ? never\n : NonNullable<Instance> extends Gtk.Widget\n ? K\n : never\n : never\n : never]: (typeof elements)[K] extends Exclude<ElementType, string>\n ? AnimatedComponent<(typeof elements)[K]>\n : never;\n};\n\nexport type { AnimatedComponent, AnimatedElements, AnimatedItems, AnimatedProp, AnimatedProps, AnimatedStyle };\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ElementType } from "react";
|
|
2
|
+
import type { AnimatedComponent } from "./types.js";
|
|
3
|
+
type Wrappable = Exclude<ElementType, string>;
|
|
4
|
+
declare function withAnimated<T extends Wrappable>(component: T): AnimatedComponent<T>;
|
|
5
|
+
export { withAnimated };
|
|
6
|
+
//# sourceMappingURL=with-animated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-animated.d.ts","sourceRoot":"","sources":["../src/with-animated.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAE,KAAK,WAAW,EAAqE,MAAM,OAAO,CAAC;AAC5G,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAKpD,KAAK,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AA+M9C,iBAAS,YAAY,CAAC,CAAC,SAAS,SAAS,EAAE,SAAS,EAAE,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAS7E;AAmBD,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMergedRef } from "@gtkx/react/internal";
|
|
3
|
+
import { addFluidObserver, getFluidValue, hasFluidValue, raf, removeFluidObserver, useForceUpdate, } from "@react-spring/shared";
|
|
4
|
+
import { useLayoutEffect, useRef } from "react";
|
|
5
|
+
import { didApplyAnimatedValues } from "./apply-animated-values.js";
|
|
6
|
+
import { trackReducedMotion } from "./reduced-motion.js";
|
|
7
|
+
const STYLE_PROP = "style";
|
|
8
|
+
const cache = new WeakMap();
|
|
9
|
+
const getDisplayName = (component) => {
|
|
10
|
+
const { displayName, name } = component;
|
|
11
|
+
if (typeof displayName === "string" && displayName !== "") {
|
|
12
|
+
return displayName;
|
|
13
|
+
}
|
|
14
|
+
return typeof name === "string" && name !== "" ? name : "Anonymous";
|
|
15
|
+
};
|
|
16
|
+
const isFluidProp = (value) => hasFluidValue(value) || isFluidArray(value);
|
|
17
|
+
const isBlock = (value) => typeof value === "object" && value !== null && Object.getPrototypeOf(value) === Object.prototype;
|
|
18
|
+
function isFluidArray(value) {
|
|
19
|
+
return Array.isArray(value) && value.some((item) => isFluidProp(item));
|
|
20
|
+
}
|
|
21
|
+
function isFluidStyle(value) {
|
|
22
|
+
return isBlock(value) && Object.values(value).some((item) => hasFluidValue(item) || isFluidStyle(item));
|
|
23
|
+
}
|
|
24
|
+
function resolveStyle(style) {
|
|
25
|
+
const resolved = {};
|
|
26
|
+
for (const name in style) {
|
|
27
|
+
const value = style[name];
|
|
28
|
+
const next = isFluidStyle(value) ? resolveStyle(value) : getFluidValue(value);
|
|
29
|
+
resolved[name] = next;
|
|
30
|
+
}
|
|
31
|
+
return resolved;
|
|
32
|
+
}
|
|
33
|
+
function resolveValue(value) {
|
|
34
|
+
return isFluidArray(value) ? value.map((item) => resolveValue(item)) : getFluidValue(value);
|
|
35
|
+
}
|
|
36
|
+
const isFluidNamed = (name, value) => isFluidProp(value) || (name === STYLE_PROP && isFluidStyle(value));
|
|
37
|
+
const resolveNamed = (name, value) => name === STYLE_PROP && isFluidStyle(value) ? resolveStyle(value) : resolveValue(value);
|
|
38
|
+
const resolveProps = (props, isAnimatedOnly) => {
|
|
39
|
+
const resolved = {};
|
|
40
|
+
for (const name in props) {
|
|
41
|
+
const value = props[name];
|
|
42
|
+
if (isFluidNamed(name, value)) {
|
|
43
|
+
resolved[name] = resolveNamed(name, value);
|
|
44
|
+
}
|
|
45
|
+
else if (!isAnimatedOnly) {
|
|
46
|
+
resolved[name] = value;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return resolved;
|
|
50
|
+
};
|
|
51
|
+
function collectEach(items, dependencies) {
|
|
52
|
+
for (const item of items) {
|
|
53
|
+
collectDependencies(item, dependencies);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function collectDependencies(value, dependencies) {
|
|
57
|
+
if (hasFluidValue(value)) {
|
|
58
|
+
dependencies.add(value);
|
|
59
|
+
}
|
|
60
|
+
else if (isFluidArray(value)) {
|
|
61
|
+
collectEach(value, dependencies);
|
|
62
|
+
}
|
|
63
|
+
else if (isFluidStyle(value)) {
|
|
64
|
+
collectEach(Object.values(value), dependencies);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const collectNamed = (name, value, dependencies) => {
|
|
68
|
+
if (isFluidNamed(name, value)) {
|
|
69
|
+
collectDependencies(value, dependencies);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const getDependencies = (props) => {
|
|
73
|
+
const dependencies = new Set();
|
|
74
|
+
for (const name in props) {
|
|
75
|
+
collectNamed(name, props[name], dependencies);
|
|
76
|
+
}
|
|
77
|
+
return dependencies;
|
|
78
|
+
};
|
|
79
|
+
const getFluidNames = (props) => {
|
|
80
|
+
const names = new Set();
|
|
81
|
+
for (const name in props) {
|
|
82
|
+
if (isFluidNamed(name, props[name])) {
|
|
83
|
+
names.add(name);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return names;
|
|
87
|
+
};
|
|
88
|
+
const observe = (observer) => {
|
|
89
|
+
for (const dependency of observer.dependencies) {
|
|
90
|
+
addFluidObserver(dependency, observer);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const unobserve = (observer) => {
|
|
94
|
+
for (const dependency of observer.dependencies) {
|
|
95
|
+
removeFluidObserver(dependency, observer);
|
|
96
|
+
}
|
|
97
|
+
raf.cancel(observer.update);
|
|
98
|
+
};
|
|
99
|
+
const useObserver = (observer) => {
|
|
100
|
+
const observerRef = useRef(null);
|
|
101
|
+
useLayoutEffect(() => {
|
|
102
|
+
observerRef.current = observer;
|
|
103
|
+
observe(observer);
|
|
104
|
+
return () => {
|
|
105
|
+
if (observerRef.current === null) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
unobserve(observerRef.current);
|
|
109
|
+
observerRef.current = null;
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
const collectStaticReplacements = (props, previous, current, values) => {
|
|
114
|
+
for (const name of previous) {
|
|
115
|
+
const value = props[name];
|
|
116
|
+
if (value !== undefined && !current.has(name)) {
|
|
117
|
+
values[name] = value;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const useCommitSync = (instanceRef, props) => {
|
|
122
|
+
const fluidNamesRef = useRef(new Set());
|
|
123
|
+
useLayoutEffect(() => {
|
|
124
|
+
const previous = fluidNamesRef.current;
|
|
125
|
+
const current = getFluidNames(props);
|
|
126
|
+
fluidNamesRef.current = current;
|
|
127
|
+
trackReducedMotion();
|
|
128
|
+
const instance = instanceRef.current;
|
|
129
|
+
if (instance === null) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const values = resolveProps(props, true);
|
|
133
|
+
collectStaticReplacements(props, previous, current, values);
|
|
134
|
+
didApplyAnimatedValues(instance, values);
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
const useAnimatedUpdate = (instanceRef, props) => {
|
|
138
|
+
const forceUpdate = useForceUpdate();
|
|
139
|
+
return () => {
|
|
140
|
+
const instance = instanceRef.current;
|
|
141
|
+
const isApplied = instance !== null && didApplyAnimatedValues(instance, resolveProps(props, true));
|
|
142
|
+
if (!isApplied) {
|
|
143
|
+
forceUpdate();
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
const createAnimatedComponent = (Component) => {
|
|
148
|
+
const Animated = ({ ref: givenRef, ...props }) => {
|
|
149
|
+
const instanceRef = useRef(null);
|
|
150
|
+
const ref = useMergedRef(givenRef, instanceRef);
|
|
151
|
+
const update = useAnimatedUpdate(instanceRef, props);
|
|
152
|
+
useObserver(new PropsObserver(update, getDependencies(props)));
|
|
153
|
+
useCommitSync(instanceRef, props);
|
|
154
|
+
return _jsx(Component, { ...resolveProps(props, false), ref: ref });
|
|
155
|
+
};
|
|
156
|
+
Animated.displayName = `Animated(${getDisplayName(Component)})`;
|
|
157
|
+
return Animated;
|
|
158
|
+
};
|
|
159
|
+
function withAnimated(component) {
|
|
160
|
+
let cached = cache.get(component);
|
|
161
|
+
if (cached === undefined) {
|
|
162
|
+
cached = createAnimatedComponent(component);
|
|
163
|
+
cache.set(component, cached);
|
|
164
|
+
}
|
|
165
|
+
return cached;
|
|
166
|
+
}
|
|
167
|
+
class PropsObserver {
|
|
168
|
+
update;
|
|
169
|
+
dependencies;
|
|
170
|
+
constructor(update, dependencies) {
|
|
171
|
+
this.update = update;
|
|
172
|
+
this.dependencies = dependencies;
|
|
173
|
+
}
|
|
174
|
+
eventObserved(event) {
|
|
175
|
+
if (event.type === "change") {
|
|
176
|
+
raf.write(this.update);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
export { withAnimated };
|
|
181
|
+
//# sourceMappingURL=with-animated.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-animated.js","sourceRoot":"","sources":["../src/with-animated.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EACH,gBAAgB,EAGhB,aAAa,EACb,aAAa,EACb,GAAG,EACH,mBAAmB,EACnB,cAAc,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAA8D,eAAe,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE5G,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAMzD,MAAM,UAAU,GAAG,OAAO,CAAC;AAC3B,MAAM,KAAK,GAAkD,IAAI,OAAO,EAAE,CAAC;AAE3E,MAAM,cAAc,GAAG,CAAC,SAAoB,EAAU,EAAE;IACpD,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,SAAsD,CAAC;IAErF,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,KAAK,EAAE,EAAE,CAAC;QACxD,OAAO,WAAW,CAAC;IACvB,CAAC;IAED,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC;AACxE,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,KAAc,EAAW,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC;AAE7F,MAAM,OAAO,GAAG,CAAC,KAAc,EAAmB,EAAE,CAChD,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,SAAS,CAAC;AAErG,SAAS,YAAY,CAAC,KAAc;IAChC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAChC,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5G,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IAC/B,MAAM,QAAQ,GAAW,EAAE,CAAC;IAE5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,KAAK,GAAY,KAAK,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,IAAI,GAAY,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACvF,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAChC,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AAChG,CAAC;AAED,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,KAAc,EAAW,EAAE,CAC3D,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;AAEvE,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,KAAc,EAAW,EAAE,CAC3D,IAAI,KAAK,UAAU,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;AAE3F,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,cAAuB,EAAU,EAAE;IACpE,MAAM,QAAQ,GAAW,EAAE,CAAC;IAE5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,KAAK,GAAY,KAAK,CAAC,IAAI,CAAC,CAAC;QAEnC,IAAI,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;YAC5B,QAAQ,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC/C,CAAC;aAAM,IAAI,CAAC,cAAc,EAAE,CAAC;YACzB,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QAC3B,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC,CAAC;AAEF,SAAS,WAAW,CAAC,KAAgB,EAAE,YAA6B;IAChE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,mBAAmB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC5C,CAAC;AACL,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc,EAAE,YAA6B;IACtE,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;SAAM,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,WAAW,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IACrC,CAAC;SAAM,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC;IACpD,CAAC;AACL,CAAC;AAED,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,KAAc,EAAE,YAA6B,EAAQ,EAAE;IACvF,IAAI,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;QAC5B,mBAAmB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IAC7C,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,KAAa,EAAmB,EAAE;IACvD,MAAM,YAAY,GAAoB,IAAI,GAAG,EAAE,CAAC;IAEhD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,YAAY,CAAC;AACxB,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,KAAa,EAAe,EAAE;IACjD,MAAM,KAAK,GAAgB,IAAI,GAAG,EAAE,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YAClC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,OAAO,GAAG,CAAC,QAAuB,EAAQ,EAAE;IAC9C,KAAK,MAAM,UAAU,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;QAC7C,gBAAgB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC3C,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,CAAC,QAAuB,EAAQ,EAAE;IAChD,KAAK,MAAM,UAAU,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;QAC7C,mBAAmB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAED,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,QAAuB,EAAQ,EAAE;IAClD,MAAM,WAAW,GAAgB,MAAM,CAAuB,IAAI,CAAC,CAAC;IAEpE,eAAe,CAAC,GAAG,EAAE;QACjB,WAAW,CAAC,OAAO,GAAG,QAAQ,CAAC;QAC/B,OAAO,CAAC,QAAQ,CAAC,CAAC;QAElB,OAAO,GAAG,EAAE;YACR,IAAI,WAAW,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;gBAC/B,OAAO;YACX,CAAC;YAED,SAAS,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YAC/B,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;QAC/B,CAAC,CAAC;IACN,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,MAAM,yBAAyB,GAAG,CAC9B,KAAa,EACb,QAAqB,EACrB,OAAoB,EACpB,MAAc,EACV,EAAE;IACN,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAY,KAAK,CAAC,IAAI,CAAC,CAAC;QAEnC,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5C,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QACzB,CAAC;IACL,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,WAAqC,EAAE,KAAa,EAAQ,EAAE;IACjF,MAAM,aAAa,GAAG,MAAM,CAAc,IAAI,GAAG,EAAE,CAAC,CAAC;IAErD,eAAe,CAAC,GAAG,EAAE;QACjB,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC;QACvC,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QACrC,aAAa,CAAC,OAAO,GAAG,OAAO,CAAC;QAChC,kBAAkB,EAAE,CAAC;QACrB,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC;QAErC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACpB,OAAO;QACX,CAAC;QAED,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACzC,yBAAyB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAC5D,sBAAsB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,WAAqC,EAAE,KAAa,EAAgB,EAAE;IAC7F,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,OAAO,GAAG,EAAE;QACR,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC;QACrC,MAAM,SAAS,GAAG,QAAQ,KAAK,IAAI,IAAI,sBAAsB,CAAC,QAAQ,EAAE,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QAEnG,IAAI,CAAC,SAAS,EAAE,CAAC;YACb,WAAW,EAAE,CAAC;QAClB,CAAC;IACL,CAAC,CAAC;AACN,CAAC,CAAC;AAEF,MAAM,uBAAuB,GAAG,CAAC,SAAoB,EAAgC,EAAE;IACnF,MAAM,QAAQ,GAAG,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAiB,EAAa,EAAE;QACvE,MAAM,WAAW,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;QAChD,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,iBAAiB,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QACrD,WAAW,CAAC,IAAI,aAAa,CAAC,MAAM,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/D,aAAa,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAElC,OAAO,KAAC,SAAS,OAAK,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,GAAG,EAAE,GAAG,GAAI,CAAC;IACnE,CAAC,CAAC;IAEF,QAAQ,CAAC,WAAW,GAAG,YAAY,cAAc,CAAC,SAAS,CAAC,GAAG,CAAC;IAEhE,OAAO,QAAwC,CAAC;AACpD,CAAC,CAAC;AAEF,SAAS,YAAY,CAAsB,SAAY;IACnD,IAAI,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAElC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;QAC5C,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,MAA8B,CAAC;AAC1C,CAAC;AAED,MAAM,aAAa;IACN,MAAM,CAAa;IAEnB,YAAY,CAAkB;IAEvC,YAAY,MAAkB,EAAE,YAA6B;QACzD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACrC,CAAC;IAED,aAAa,CAAC,KAAiB;QAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC1B,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;IACL,CAAC;CACJ;AAED,OAAO,EAAE,YAAY,EAAE,CAAC","sourcesContent":["import type { Lookup } from \"@react-spring/types\";\nimport { useMergedRef } from \"@gtkx/react/internal\";\nimport {\n addFluidObserver,\n type FluidEvent,\n type FluidValue,\n getFluidValue,\n hasFluidValue,\n raf,\n removeFluidObserver,\n useForceUpdate,\n} from \"@react-spring/shared\";\nimport { type ElementType, type ReactNode, type Ref, type RefObject, useLayoutEffect, useRef } from \"react\";\nimport type { AnimatedComponent } from \"./types.js\";\nimport { didApplyAnimatedValues } from \"./apply-animated-values.js\";\nimport { trackReducedMotion } from \"./reduced-motion.js\";\n\ntype AnimatedInput = { ref?: Ref<object> | undefined; [key: string]: unknown };\ntype Wrappable = Exclude<ElementType, string>;\ntype ObserverRef = { current: PropsObserver | null };\n\nconst STYLE_PROP = \"style\";\nconst cache: WeakMap<object, AnimatedComponent<Wrappable>> = new WeakMap();\n\nconst getDisplayName = (component: Wrappable): string => {\n const { displayName, name } = component as { displayName?: unknown; name?: unknown };\n\n if (typeof displayName === \"string\" && displayName !== \"\") {\n return displayName;\n }\n\n return typeof name === \"string\" && name !== \"\" ? name : \"Anonymous\";\n};\n\nconst isFluidProp = (value: unknown): boolean => hasFluidValue(value) || isFluidArray(value);\n\nconst isBlock = (value: unknown): value is Lookup =>\n typeof value === \"object\" && value !== null && Object.getPrototypeOf(value) === Object.prototype;\n\nfunction isFluidArray(value: unknown): value is unknown[] {\n return Array.isArray(value) && value.some((item) => isFluidProp(item));\n}\n\nfunction isFluidStyle(value: unknown): value is Lookup {\n return isBlock(value) && Object.values(value).some((item) => hasFluidValue(item) || isFluidStyle(item));\n}\n\nfunction resolveStyle(style: Lookup): Lookup {\n const resolved: Lookup = {};\n\n for (const name in style) {\n const value: unknown = style[name];\n const next: unknown = isFluidStyle(value) ? resolveStyle(value) : getFluidValue(value);\n resolved[name] = next;\n }\n\n return resolved;\n}\n\nfunction resolveValue(value: unknown): unknown {\n return isFluidArray(value) ? value.map((item) => resolveValue(item)) : getFluidValue(value);\n}\n\nconst isFluidNamed = (name: string, value: unknown): boolean =>\n isFluidProp(value) || (name === STYLE_PROP && isFluidStyle(value));\n\nconst resolveNamed = (name: string, value: unknown): unknown =>\n name === STYLE_PROP && isFluidStyle(value) ? resolveStyle(value) : resolveValue(value);\n\nconst resolveProps = (props: Lookup, isAnimatedOnly: boolean): Lookup => {\n const resolved: Lookup = {};\n\n for (const name in props) {\n const value: unknown = props[name];\n\n if (isFluidNamed(name, value)) {\n resolved[name] = resolveNamed(name, value);\n } else if (!isAnimatedOnly) {\n resolved[name] = value;\n }\n }\n\n return resolved;\n};\n\nfunction collectEach(items: unknown[], dependencies: Set<FluidValue>): void {\n for (const item of items) {\n collectDependencies(item, dependencies);\n }\n}\n\nfunction collectDependencies(value: unknown, dependencies: Set<FluidValue>): void {\n if (hasFluidValue(value)) {\n dependencies.add(value);\n } else if (isFluidArray(value)) {\n collectEach(value, dependencies);\n } else if (isFluidStyle(value)) {\n collectEach(Object.values(value), dependencies);\n }\n}\n\nconst collectNamed = (name: string, value: unknown, dependencies: Set<FluidValue>): void => {\n if (isFluidNamed(name, value)) {\n collectDependencies(value, dependencies);\n }\n};\n\nconst getDependencies = (props: Lookup): Set<FluidValue> => {\n const dependencies: Set<FluidValue> = new Set();\n\n for (const name in props) {\n collectNamed(name, props[name], dependencies);\n }\n\n return dependencies;\n};\n\nconst getFluidNames = (props: Lookup): Set<string> => {\n const names: Set<string> = new Set();\n\n for (const name in props) {\n if (isFluidNamed(name, props[name])) {\n names.add(name);\n }\n }\n\n return names;\n};\n\nconst observe = (observer: PropsObserver): void => {\n for (const dependency of observer.dependencies) {\n addFluidObserver(dependency, observer);\n }\n};\n\nconst unobserve = (observer: PropsObserver): void => {\n for (const dependency of observer.dependencies) {\n removeFluidObserver(dependency, observer);\n }\n\n raf.cancel(observer.update);\n};\n\nconst useObserver = (observer: PropsObserver): void => {\n const observerRef: ObserverRef = useRef<PropsObserver | null>(null);\n\n useLayoutEffect(() => {\n observerRef.current = observer;\n observe(observer);\n\n return () => {\n if (observerRef.current === null) {\n return;\n }\n\n unobserve(observerRef.current);\n observerRef.current = null;\n };\n });\n};\n\nconst collectStaticReplacements = (\n props: Lookup,\n previous: Set<string>,\n current: Set<string>,\n values: Lookup,\n): void => {\n for (const name of previous) {\n const value: unknown = props[name];\n\n if (value !== undefined && !current.has(name)) {\n values[name] = value;\n }\n }\n};\n\nconst useCommitSync = (instanceRef: RefObject<object | null>, props: Lookup): void => {\n const fluidNamesRef = useRef<Set<string>>(new Set());\n\n useLayoutEffect(() => {\n const previous = fluidNamesRef.current;\n const current = getFluidNames(props);\n fluidNamesRef.current = current;\n trackReducedMotion();\n const instance = instanceRef.current;\n\n if (instance === null) {\n return;\n }\n\n const values = resolveProps(props, true);\n collectStaticReplacements(props, previous, current, values);\n didApplyAnimatedValues(instance, values);\n });\n};\n\nconst useAnimatedUpdate = (instanceRef: RefObject<object | null>, props: Lookup): (() => void) => {\n const forceUpdate = useForceUpdate();\n\n return () => {\n const instance = instanceRef.current;\n const isApplied = instance !== null && didApplyAnimatedValues(instance, resolveProps(props, true));\n\n if (!isApplied) {\n forceUpdate();\n }\n };\n};\n\nconst createAnimatedComponent = (Component: Wrappable): AnimatedComponent<Wrappable> => {\n const Animated = ({ ref: givenRef, ...props }: AnimatedInput): ReactNode => {\n const instanceRef = useRef<object | null>(null);\n const ref = useMergedRef(givenRef, instanceRef);\n const update = useAnimatedUpdate(instanceRef, props);\n useObserver(new PropsObserver(update, getDependencies(props)));\n useCommitSync(instanceRef, props);\n\n return <Component {...resolveProps(props, false)} ref={ref} />;\n };\n\n Animated.displayName = `Animated(${getDisplayName(Component)})`;\n\n return Animated as AnimatedComponent<Wrappable>;\n};\n\nfunction withAnimated<T extends Wrappable>(component: T): AnimatedComponent<T> {\n let cached = cache.get(component);\n\n if (cached === undefined) {\n cached = createAnimatedComponent(component);\n cache.set(component, cached);\n }\n\n return cached as AnimatedComponent<T>;\n}\n\nclass PropsObserver {\n readonly update: () => void;\n\n readonly dependencies: Set<FluidValue>;\n\n constructor(update: () => void, dependencies: Set<FluidValue>) {\n this.update = update;\n this.dependencies = dependencies;\n }\n\n eventObserved(event: FluidEvent): void {\n if (event.type === \"change\") {\n raf.write(this.update);\n }\n }\n}\n\nexport { withAnimated };\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gtkx/animated",
|
|
3
|
+
"version": "1.2.2",
|
|
4
|
+
"description": "React Spring animations for GTKX: animated widget components driven by the GTK frame clock",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"gtkx",
|
|
7
|
+
"gtk",
|
|
8
|
+
"gtk4",
|
|
9
|
+
"react",
|
|
10
|
+
"react-spring",
|
|
11
|
+
"animation",
|
|
12
|
+
"spring",
|
|
13
|
+
"linux",
|
|
14
|
+
"desktop"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://gtkx.dev",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/gtkx-org/gtkx/issues"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/gtkx-org/gtkx.git",
|
|
23
|
+
"directory": "packages/animated"
|
|
24
|
+
},
|
|
25
|
+
"license": "MPL-2.0",
|
|
26
|
+
"author": "Eugenio Depalo <eugeniodepalo@gmail.com>",
|
|
27
|
+
"type": "module",
|
|
28
|
+
"exports": {
|
|
29
|
+
"./package.json": "./package.json",
|
|
30
|
+
".": {
|
|
31
|
+
"source": "./src/index.ts",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"default": "./dist/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"sideEffects": [
|
|
37
|
+
"./src/index.ts",
|
|
38
|
+
"./dist/index.js",
|
|
39
|
+
"./src/bootstrap.ts",
|
|
40
|
+
"./dist/bootstrap.js"
|
|
41
|
+
],
|
|
42
|
+
"files": [
|
|
43
|
+
"dist",
|
|
44
|
+
"src"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"release": "tsx ../../scripts/release-package.ts"
|
|
48
|
+
},
|
|
49
|
+
"nx": {
|
|
50
|
+
"targets": {
|
|
51
|
+
"lint": {
|
|
52
|
+
"options": {
|
|
53
|
+
"cwd": ".",
|
|
54
|
+
"command": "eslint {projectRoot}"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=24"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"@gtkx/react": "workspace:*",
|
|
64
|
+
"@gtkx/runtime": "workspace:*",
|
|
65
|
+
"@react-spring/core": "^10.1.2",
|
|
66
|
+
"@react-spring/shared": "^10.1.2",
|
|
67
|
+
"@react-spring/types": "^10.1.2"
|
|
68
|
+
},
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"react": "^19.2"
|
|
71
|
+
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"@gtkx/config": "workspace:*",
|
|
74
|
+
"@gtkx/testing": "workspace:*",
|
|
75
|
+
"@gtkx/vitest": "workspace:*",
|
|
76
|
+
"vitest": "catalog:"
|
|
77
|
+
}
|
|
78
|
+
}
|
package/src/animated.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ElementType } from "react";
|
|
2
|
+
import * as elements from "@gtkx/jsx";
|
|
3
|
+
import type { AnimatedComponent, AnimatedElements } from "./types.js";
|
|
4
|
+
import { withAnimated } from "./with-animated.js";
|
|
5
|
+
|
|
6
|
+
type Wrappable = Exclude<ElementType, string>;
|
|
7
|
+
/**
|
|
8
|
+
* The `animated` entrypoint: callable to wrap any component, and exposing every generated widget
|
|
9
|
+
* component as a property, so `animated.GtkLabel` is the animated form of `GtkLabel`.
|
|
10
|
+
*/
|
|
11
|
+
type Animated = (<T extends Exclude<ElementType, string>>(component: T) => AnimatedComponent<T>) & AnimatedElements;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Wraps a component so that its props accept springs and interpolations: `animated(GtkLabel)` is
|
|
15
|
+
* `GtkLabel` with every prop also taking a `SpringValue` or an `Interpolation`. Animated values are
|
|
16
|
+
* written to the widget on each frame without a React render. The wrapper of a given component is
|
|
17
|
+
* created once and reused, so repeated lookups render the same component.
|
|
18
|
+
*
|
|
19
|
+
* Every widget component of the generated `@gtkx/jsx` store is also available as a property:
|
|
20
|
+
* `animated.GtkLabel` is `animated(GtkLabel)` without the import. Elements whose `ref` does not
|
|
21
|
+
* expose a `Gtk.Widget` subclass, such as `GtkAdjustment`, are wrapped through the call form.
|
|
22
|
+
*/
|
|
23
|
+
const animated: Animated = new Proxy(wrapComponent, {
|
|
24
|
+
get(target, property, receiver): unknown {
|
|
25
|
+
const component = componentFor(property);
|
|
26
|
+
|
|
27
|
+
return component === null ? Reflect.get(target, property, receiver) : withAnimated(component);
|
|
28
|
+
},
|
|
29
|
+
getOwnPropertyDescriptor(target, property): PropertyDescriptor | undefined {
|
|
30
|
+
const component = componentFor(property);
|
|
31
|
+
|
|
32
|
+
if (component === null) {
|
|
33
|
+
return Reflect.getOwnPropertyDescriptor(target, property);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return { configurable: true, enumerable: true, writable: false, value: withAnimated(component) };
|
|
37
|
+
},
|
|
38
|
+
has(target, property): boolean {
|
|
39
|
+
return componentFor(property) !== null || Reflect.has(target, property);
|
|
40
|
+
},
|
|
41
|
+
ownKeys(target): (string | symbol)[] {
|
|
42
|
+
const names = Object.keys(elements).filter((name) => componentFor(name) !== null);
|
|
43
|
+
|
|
44
|
+
return [...new Set([...Reflect.ownKeys(target), ...names])];
|
|
45
|
+
},
|
|
46
|
+
}) as Animated;
|
|
47
|
+
|
|
48
|
+
function componentFor(property: string | symbol): Wrappable | null {
|
|
49
|
+
const value: unknown = Reflect.get(elements, property);
|
|
50
|
+
|
|
51
|
+
return isComponent(value) ? value : null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isComponent(value: unknown): value is Wrappable {
|
|
55
|
+
return typeof value === "function";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function wrapComponent<T extends Wrappable>(component: T): AnimatedComponent<T> {
|
|
59
|
+
return withAnimated(component);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { animated, type Animated };
|