@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 +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/presence.d.ts +15 -0
- package/dist/presence.js +51 -0
- package/docs/LIBRARY.md +33 -0
- package/package.json +5 -5
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;
|
package/dist/presence.js
ADDED
|
@@ -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.
|
|
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
|
|
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
|
},
|