@tobiasoberpaul/mdk 0.1.1 → 0.2.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 CHANGED
@@ -25,4 +25,6 @@ Your component manages layout, visibility, focus and accessibility. MDK handles
25
25
 
26
26
  The library includes Grow, Extract, Morph, Slide and Content transitions. See the [library guide](https://github.com/TOberpaul/animations/blob/main/docs/LIBRARY.md) for the API, CSS tokens and integration patterns.
27
27
 
28
+ Coding assistants can access the MDK reference and integration examples through the public MCP server. See the [MCP setup](https://github.com/TOberpaul/animations/blob/main/docs/AI_INTEGRATION.md#hosted-mcp).
29
+
28
30
  Licensed under [MIT](LICENSE).
package/dist/index.d.ts CHANGED
@@ -28,3 +28,5 @@ export type { MotionPlacement, MotionPositionOptions } from './position.js';
28
28
  export { captureMotionLayout, animateMotionLayout } from './layout.js';
29
29
  export { bindScrollMotion } from './scroll.js';
30
30
  export type { ScrollMotionOptions } from './scroll.js';
31
+ export { createPresenceMotion } from './presence.js';
32
+ export type { PresenceMotion, PresenceMotionOptions } from './presence.js';
package/dist/index.js CHANGED
@@ -13,3 +13,4 @@ export { bindMotionInteractions, createInteractiveMotion } from './interactions.
13
13
  export { positionMotion } from './position.js';
14
14
  export { captureMotionLayout, animateMotionLayout } from './layout.js';
15
15
  export { bindScrollMotion } from './scroll.js';
16
+ export { createPresenceMotion } from './presence.js';
@@ -0,0 +1,15 @@
1
+ import type { MotionState, Options, Transition } from './core/lifecycle.js';
2
+ export interface PresenceMotionOptions extends Pick<Options, 'initiallyOpen'> {
3
+ /** Create a fresh MDK transition using the lifecycle options supplied by the adapter. */
4
+ createTransition(lifecycle: Pick<Options, 'initiallyOpen' | 'onStateChange'>): Transition;
5
+ /** Supply only if the integration can synchronously show and hide the surface.
6
+ * Without this callback, call setOpen(true) after the host has shown the surface. */
7
+ setPresent?(present: boolean): void;
8
+ }
9
+ export interface PresenceMotion {
10
+ readonly state: MotionState;
11
+ setOpen(open: boolean): void;
12
+ destroy(): void;
13
+ }
14
+ /** Drive MDK from a component's existing open/close signals. */
15
+ export declare function createPresenceMotion(options: PresenceMotionOptions): PresenceMotion;
@@ -0,0 +1,51 @@
1
+ /** Drive MDK from a component's existing open/close signals. */
2
+ export function createPresenceMotion(options) {
3
+ const { createTransition, setPresent } = options;
4
+ let open = options.initiallyOpen ?? false;
5
+ let destroyed = false;
6
+ let controller;
7
+ if (setPresent) {
8
+ controller = createTransition({
9
+ initiallyOpen: open,
10
+ onStateChange(state) {
11
+ if (state === 'opening')
12
+ setPresent(true);
13
+ if (state === 'closed')
14
+ setPresent(false);
15
+ }
16
+ });
17
+ }
18
+ return {
19
+ get state() {
20
+ if (destroyed)
21
+ return 'destroyed';
22
+ return controller?.state ?? (open ? 'open' : 'closed');
23
+ },
24
+ setOpen(next) {
25
+ if (destroyed || next === open)
26
+ return;
27
+ open = next;
28
+ if (next) {
29
+ controller ?? (controller = createTransition({ initiallyOpen: false }));
30
+ controller.open();
31
+ }
32
+ else if (setPresent) {
33
+ controller?.close();
34
+ }
35
+ else {
36
+ // The host already owns visibility. Release visual styles for the next entry.
37
+ controller?.destroy();
38
+ controller = undefined;
39
+ }
40
+ },
41
+ destroy() {
42
+ if (destroyed)
43
+ return;
44
+ destroyed = true;
45
+ const pendingExit = controller?.state === 'closing';
46
+ controller?.destroy();
47
+ if (pendingExit)
48
+ setPresent?.(false);
49
+ }
50
+ };
51
+ }
package/docs/LIBRARY.md CHANGED
@@ -77,6 +77,39 @@ Use your design system's real dialog, drawer, popover, toast or card instead of
77
77
  this minimal surface. Native dialogs require their component integration to
78
78
  call `showModal()` / close at the appropriate lifecycle points.
79
79
 
80
+ ## Animate an existing component
81
+
82
+ Use `createPresenceMotion` when a popover, drawer or menu already owns its
83
+ interaction. Forward its existing open and close signals to `setOpen`. The
84
+ adapter uses the selected MDK controller for animation. The integration keeps
85
+ its existing positioning, focus, keyboard and dismissal behavior.
86
+
87
+ ```ts
88
+ import { createGrowTransition, createPresenceMotion } from '@tobiasoberpaul/mdk';
89
+ import '@tobiasoberpaul/mdk/motion.css';
90
+
91
+ const motion = createPresenceMotion({
92
+ initiallyOpen: !surface.hidden,
93
+ createTransition: lifecycle => createGrowTransition({ content: surface, ...lifecycle }),
94
+ setPresent: present => { surface.hidden = !present; },
95
+ });
96
+
97
+ // Forward the component's existing open/close requests to motion.setOpen(open).
98
+ // On cleanup, unsubscribe from the component and call motion.destroy().
99
+ ```
100
+
101
+ With `setPresent`, the adapter shows the surface synchronously before measurement
102
+ and hides it after the exit settles. Use the component's supported presence
103
+ mechanism in this callback. The same surface must remain mounted through exit.
104
+ Keep requested open state separate from visual presence so a new open request
105
+ can reverse an in-progress exit.
106
+
107
+ If the host hides itself immediately, omit `setPresent`. Call `setOpen(true)`
108
+ after the host has made its surface visible and positioned it, then call
109
+ `setOpen(false)` when it hides. This mode plays entry and releases the effect
110
+ on close. It requires a reliable signal from the host integration. Disable any
111
+ competing host animation on the same surface.
112
+
80
113
  ## Public behavior factories
81
114
 
82
115
  | Factory | Behavior | Required additions to shared options |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tobiasoberpaul/mdk",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -18,7 +18,7 @@
18
18
  "build:examples": "node scripts/build-db-react.mjs && node scripts/build-shadcn.mjs",
19
19
  "build:shadcn": "node scripts/build-shadcn.mjs",
20
20
  "analytics": "node context-starter/analytics/serve.mjs . --codex-history",
21
- "dev": "npm run build && npm run build:examples && node scripts/serve.mjs",
21
+ "dev": "npm run build:site && node scripts/serve.mjs",
22
22
  "test": "npm run build && npm run build:examples && playwright test",
23
23
  "build:site": "npm run build && npm run build:examples && node scripts/build-site.mjs",
24
24
  "mcp": "node ai/mcp-server.mjs",
@@ -30,6 +30,7 @@
30
30
  "@db-ux/core-foundations": "6.2.0",
31
31
  "@db-ux/db-theme": "7.2.0",
32
32
  "@db-ux/react-core-components": "6.2.0",
33
+ "@mdx-js/esbuild": "3.1.1",
33
34
  "@playwright/test": "1.48.2",
34
35
  "@radix-ui/react-dialog": "1.3.1",
35
36
  "@radix-ui/react-dropdown-menu": "2.2.1",
@@ -44,12 +45,12 @@
44
45
  "clsx": "2.1.1",
45
46
  "esbuild": "0.21.5",
46
47
  "lucide-react": "1.66.0",
48
+ "picomatch": "4.0.7",
47
49
  "react": "19.2.0",
48
50
  "react-dom": "19.2.0",
49
51
  "tailwind-merge": "2.6.0",
50
52
  "tailwindcss": "3.4.17",
51
- "typescript": "5.7.3",
52
- "picomatch": "4.0.7"
53
+ "typescript": "5.7.3"
53
54
  },
54
55
  "description": "Framework-independent, reversible UI motion with CSS tokens and the Web Animations API.",
55
56
  "main": "./dist/index.js",
@@ -74,7 +75,6 @@
74
75
  "sideEffects": [
75
76
  "**/*.css"
76
77
  ],
77
-
78
78
  "publishConfig": {
79
79
  "access": "public"
80
80
  },