@byfungsi/lipat 0.2.0 → 0.2.1

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/motion.js CHANGED
@@ -1,16 +1,16 @@
1
1
  import { animate } from 'motion';
2
2
 
3
3
  // ../motion/src/motion-playback.ts
4
- function entranceTransform(effect) {
4
+ function entranceTransforms(effect) {
5
5
  switch (effect) {
6
6
  case "fade":
7
- return "none";
7
+ return null;
8
8
  case "rise":
9
- return "translateY(24px)";
9
+ return { initial: "translateY(24px)", rest: "translateY(0px)" };
10
10
  case "slide":
11
- return "translateX(-32px)";
11
+ return { initial: "translateX(-32px)", rest: "translateX(0px)" };
12
12
  case "zoom":
13
- return "scale(0.95)";
13
+ return { initial: "scale(0.95)", rest: "scale(1)" };
14
14
  }
15
15
  }
16
16
  function createMotionPlayback(options = {}) {
@@ -63,19 +63,20 @@ function createMotionPlayback(options = {}) {
63
63
  target.style.transformBox = "fill-box";
64
64
  target.style.transformOrigin = "center";
65
65
  target.style.opacity = "0";
66
- target.style.transform = entranceTransform(animation.effect);
66
+ const transforms = entranceTransforms(animation.effect);
67
+ target.style.transform = transforms?.initial ?? "none";
68
+ const keyframes = transforms ? {
69
+ opacity: [0, 1],
70
+ transform: [transforms.initial, transforms.rest]
71
+ } : { opacity: [0, 1] };
67
72
  const ease = animation.easing === "linear" ? "linear" : animation.easing === "easeInOut" ? [0.77, 0, 0.175, 1] : [0.23, 1, 0.32, 1];
68
73
  running.set(
69
74
  element.id,
70
- animate(
71
- target,
72
- { opacity: 1, transform: "none" },
73
- {
74
- duration: (animation.durationMs ?? 350) / 1e3,
75
- delay: (animation.delayMs ?? 0) / 1e3,
76
- ease
77
- }
78
- )
75
+ animate(target, keyframes, {
76
+ duration: (animation.durationMs ?? 350) / 1e3,
77
+ delay: (animation.delayMs ?? 0) / 1e3,
78
+ ease
79
+ })
79
80
  );
80
81
  }
81
82
  currentStep = step;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../motion/src/motion-playback.ts"],"names":[],"mappings":"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","file":"motion.js","sourcesContent":["import { animate } from \"motion\";\nimport type { AnimationPlaybackControls } from \"motion\";\nimport type {\n EntranceAnimation,\n SlidePlaybackDriver,\n} from \"@lipat-internal/model\";\n\n/** Reduced motion follows the OS by default; an explicit policy supports kiosk/test hosts. */\nexport interface MotionPlaybackOptions {\n readonly reducedMotion?: \"user\" | \"always\" | \"never\";\n}\n\nfunction entranceTransform(effect: EntranceAnimation[\"effect\"]): string {\n switch (effect) {\n case \"fade\":\n return \"none\";\n case \"rise\":\n return \"translateY(24px)\";\n case \"slide\":\n return \"translateX(-32px)\";\n case \"zoom\":\n return \"scale(0.95)\";\n }\n}\n\n/** Optional browser animation adapter; importing it never mounts a player or reads the DOM. */\nexport function createMotionPlayback(\n options: MotionPlaybackOptions = {},\n): SlidePlaybackDriver<HTMLElement> {\n return {\n mount(surface, slide) {\n // Use direct elements, not interpolated selectors: arbitrary document IDs remain safe.\n const targets = new Map(\n [...surface.querySelectorAll<SVGElement>(\"[data-playback-id]\")].map(\n (element) =>\n [element.getAttribute(\"data-playback-id\"), element] as const,\n ),\n );\n const running = new Map<string, AnimationPlaybackControls>();\n const originals = new Map(\n [...targets.values()].map(\n (element) =>\n [\n element,\n {\n style: element.getAttribute(\"style\"),\n ariaHidden: element.getAttribute(\"aria-hidden\"),\n },\n ] as const,\n ),\n );\n const policy = options.reducedMotion ?? \"user\";\n const media =\n policy === \"user\"\n ? surface.ownerDocument.defaultView?.matchMedia?.(\n \"(prefers-reduced-motion: reduce)\",\n )\n : undefined;\n const reduced = () =>\n policy === \"always\" || (policy === \"user\" && media?.matches === true);\n let currentStep = -1;\n let destroyed = false;\n\n const stop = (id: string) => {\n running.get(id)?.cancel();\n running.delete(id);\n };\n const showStep = (step: number, settle = false) => {\n if (destroyed || !Number.isInteger(step) || step < 0) return;\n for (const element of slide.elements) {\n const target = targets.get(element.id);\n if (!target) continue;\n const at = element.step ?? 0;\n const visible = at <= step;\n const wasVisible = at <= currentStep;\n if (currentStep >= 0 && !settle && visible === wasVisible) continue;\n stop(element.id);\n target.style.visibility = visible ? \"visible\" : \"hidden\";\n target.setAttribute(\"aria-hidden\", String(!visible));\n target.style.opacity = \"1\";\n target.style.transform = \"none\";\n if (!visible || !element.animation || settle || reduced()) continue;\n const animation = element.animation;\n target.style.transformBox = \"fill-box\";\n target.style.transformOrigin = \"center\";\n // Static rotation lives on the outer SVG group; Motion owns only this inner group.\n target.style.opacity = \"0\";\n target.style.transform = entranceTransform(animation.effect);\n const ease =\n animation.easing === \"linear\"\n ? (\"linear\" as const)\n : animation.easing === \"easeInOut\"\n ? ([0.77, 0, 0.175, 1] as const)\n : ([0.23, 1, 0.32, 1] as const);\n running.set(\n element.id,\n animate(\n target,\n { opacity: 1, transform: \"none\" },\n {\n duration: (animation.durationMs ?? 350) / 1000,\n delay: (animation.delayMs ?? 0) / 1000,\n ease,\n },\n ),\n );\n }\n currentStep = step;\n };\n const onPreferenceChange = () => {\n if (reduced()) showStep(Math.max(0, currentStep), true);\n };\n media?.addEventListener(\"change\", onPreferenceChange);\n return {\n setStep: showStep,\n destroy() {\n if (destroyed) return;\n destroyed = true;\n media?.removeEventListener(\"change\", onPreferenceChange);\n for (const control of running.values()) control.cancel();\n running.clear();\n for (const [element, original] of originals) {\n if (original.style === null) element.removeAttribute(\"style\");\n else element.setAttribute(\"style\", original.style);\n if (original.ariaHidden === null)\n element.removeAttribute(\"aria-hidden\");\n else element.setAttribute(\"aria-hidden\", original.ariaHidden);\n }\n },\n };\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../../motion/src/motion-playback.ts"],"names":[],"mappings":"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","file":"motion.js","sourcesContent":["import { animate } from \"motion\";\nimport type { AnimationPlaybackControls } from \"motion\";\nimport type {\n EntranceAnimation,\n SlidePlaybackDriver,\n} from \"@lipat-internal/model\";\n\n/** Reduced motion follows the OS by default; an explicit policy supports kiosk/test hosts. */\nexport interface MotionPlaybackOptions {\n readonly reducedMotion?: \"user\" | \"always\" | \"never\";\n}\n\nfunction entranceTransforms(effect: EntranceAnimation[\"effect\"]): {\n readonly initial: string;\n readonly rest: string;\n} | null {\n switch (effect) {\n case \"fade\":\n return null;\n case \"rise\":\n return { initial: \"translateY(24px)\", rest: \"translateY(0px)\" };\n case \"slide\":\n return { initial: \"translateX(-32px)\", rest: \"translateX(0px)\" };\n case \"zoom\":\n return { initial: \"scale(0.95)\", rest: \"scale(1)\" };\n }\n}\n\n/** Optional browser animation adapter; importing it never mounts a player or reads the DOM. */\nexport function createMotionPlayback(\n options: MotionPlaybackOptions = {},\n): SlidePlaybackDriver<HTMLElement> {\n return {\n mount(surface, slide) {\n // Use direct elements, not interpolated selectors: arbitrary document IDs remain safe.\n const targets = new Map(\n [...surface.querySelectorAll<SVGElement>(\"[data-playback-id]\")].map(\n (element) =>\n [element.getAttribute(\"data-playback-id\"), element] as const,\n ),\n );\n const running = new Map<string, AnimationPlaybackControls>();\n const originals = new Map(\n [...targets.values()].map(\n (element) =>\n [\n element,\n {\n style: element.getAttribute(\"style\"),\n ariaHidden: element.getAttribute(\"aria-hidden\"),\n },\n ] as const,\n ),\n );\n const policy = options.reducedMotion ?? \"user\";\n const media =\n policy === \"user\"\n ? surface.ownerDocument.defaultView?.matchMedia?.(\n \"(prefers-reduced-motion: reduce)\",\n )\n : undefined;\n const reduced = () =>\n policy === \"always\" || (policy === \"user\" && media?.matches === true);\n let currentStep = -1;\n let destroyed = false;\n\n const stop = (id: string) => {\n running.get(id)?.cancel();\n running.delete(id);\n };\n const showStep = (step: number, settle = false) => {\n if (destroyed || !Number.isInteger(step) || step < 0) return;\n for (const element of slide.elements) {\n const target = targets.get(element.id);\n if (!target) continue;\n const at = element.step ?? 0;\n const visible = at <= step;\n const wasVisible = at <= currentStep;\n if (currentStep >= 0 && !settle && visible === wasVisible) continue;\n stop(element.id);\n target.style.visibility = visible ? \"visible\" : \"hidden\";\n target.setAttribute(\"aria-hidden\", String(!visible));\n target.style.opacity = \"1\";\n target.style.transform = \"none\";\n if (!visible || !element.animation || settle || reduced()) continue;\n const animation = element.animation;\n target.style.transformBox = \"fill-box\";\n target.style.transformOrigin = \"center\";\n // Static rotation lives on the outer SVG group; Motion owns only this inner group.\n target.style.opacity = \"0\";\n const transforms = entranceTransforms(animation.effect);\n target.style.transform = transforms?.initial ?? \"none\";\n // Explicit matching endpoints avoid Motion deriving a zero matrix from computed\n // SVG transforms when resolving \"none\". Fade owns opacity only.\n const keyframes = transforms\n ? {\n opacity: [0, 1],\n transform: [transforms.initial, transforms.rest],\n }\n : { opacity: [0, 1] };\n const ease =\n animation.easing === \"linear\"\n ? (\"linear\" as const)\n : animation.easing === \"easeInOut\"\n ? ([0.77, 0, 0.175, 1] as const)\n : ([0.23, 1, 0.32, 1] as const);\n running.set(\n element.id,\n animate(target, keyframes, {\n duration: (animation.durationMs ?? 350) / 1000,\n delay: (animation.delayMs ?? 0) / 1000,\n ease,\n }),\n );\n }\n currentStep = step;\n };\n const onPreferenceChange = () => {\n if (reduced()) showStep(Math.max(0, currentStep), true);\n };\n media?.addEventListener(\"change\", onPreferenceChange);\n return {\n setStep: showStep,\n destroy() {\n if (destroyed) return;\n destroyed = true;\n media?.removeEventListener(\"change\", onPreferenceChange);\n for (const control of running.values()) control.cancel();\n running.clear();\n for (const [element, original] of originals) {\n if (original.style === null) element.removeAttribute(\"style\");\n else element.setAttribute(\"style\", original.style);\n if (original.ariaHidden === null)\n element.removeAttribute(\"aria-hidden\");\n else element.setAttribute(\"aria-hidden\", original.ariaHidden);\n }\n },\n };\n },\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byfungsi/lipat",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Agent-friendly slide authoring, independent PPTX import/export, React views and a Rust WebAssembly core",
5
5
  "type": "module",
6
6
  "sideEffects": false,