@omerdlw/base-framework 1.0.5 → 2.0.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.
Files changed (232) hide show
  1. package/dist/atoms/index.js +1 -103
  2. package/dist/atoms/index.js.map +1 -1
  3. package/dist/chunk-3BUP64Q6.js +105 -0
  4. package/dist/chunk-3BUP64Q6.js.map +1 -0
  5. package/dist/chunk-3MSK4XGK.js +9888 -0
  6. package/dist/chunk-3MSK4XGK.js.map +1 -0
  7. package/dist/chunk-4GMQKD6F.js +353 -0
  8. package/dist/chunk-4GMQKD6F.js.map +1 -0
  9. package/dist/chunk-65ZB4QTQ.js +888 -0
  10. package/dist/chunk-65ZB4QTQ.js.map +1 -0
  11. package/dist/chunk-6SG7V77J.js +577 -0
  12. package/dist/chunk-6SG7V77J.js.map +1 -0
  13. package/dist/chunk-7HQMXTNP.js +419 -0
  14. package/dist/chunk-7HQMXTNP.js.map +1 -0
  15. package/dist/chunk-7TAVYJ3A.js +371 -0
  16. package/dist/chunk-7TAVYJ3A.js.map +1 -0
  17. package/dist/chunk-AQ4BNXA2.js +349 -0
  18. package/dist/chunk-AQ4BNXA2.js.map +1 -0
  19. package/dist/chunk-CGHZSSFR.js +2166 -0
  20. package/dist/chunk-CGHZSSFR.js.map +1 -0
  21. package/dist/chunk-DGCQWQLZ.js +61 -0
  22. package/dist/chunk-DGCQWQLZ.js.map +1 -0
  23. package/dist/chunk-FIMPHODX.js +67 -0
  24. package/dist/chunk-FIMPHODX.js.map +1 -0
  25. package/dist/chunk-GF7TUX5I.js +1889 -0
  26. package/dist/chunk-GF7TUX5I.js.map +1 -0
  27. package/dist/chunk-JELG4JLT.js +454 -0
  28. package/dist/chunk-JELG4JLT.js.map +1 -0
  29. package/dist/chunk-K676GL7Z.js +51 -0
  30. package/dist/chunk-K676GL7Z.js.map +1 -0
  31. package/dist/chunk-KKQT46TP.js +26 -0
  32. package/dist/chunk-KKQT46TP.js.map +1 -0
  33. package/dist/chunk-QI3ALLIB.js +38 -0
  34. package/dist/chunk-QI3ALLIB.js.map +1 -0
  35. package/dist/chunk-QXR55VVS.js +1139 -0
  36. package/dist/chunk-QXR55VVS.js.map +1 -0
  37. package/dist/chunk-R2YGFJDJ.js +408 -0
  38. package/dist/chunk-R2YGFJDJ.js.map +1 -0
  39. package/dist/chunk-RFZQWLC5.js +27 -0
  40. package/dist/chunk-RFZQWLC5.js.map +1 -0
  41. package/dist/chunk-SYAVGTOX.js +521 -0
  42. package/dist/chunk-SYAVGTOX.js.map +1 -0
  43. package/dist/chunk-TV3WEF5G.js +784 -0
  44. package/dist/chunk-TV3WEF5G.js.map +1 -0
  45. package/dist/chunk-XASQT4CQ.js +280 -0
  46. package/dist/chunk-XASQT4CQ.js.map +1 -0
  47. package/dist/error/index.js +5 -682
  48. package/dist/error/index.js.map +1 -1
  49. package/dist/error/reporter.d.ts.map +1 -1
  50. package/dist/error/theme.d.ts +1 -1
  51. package/dist/error/theme.d.ts.map +1 -1
  52. package/dist/events.js +1 -7
  53. package/dist/events.js.map +1 -1
  54. package/dist/hooks/index.js +1 -358
  55. package/dist/hooks/index.js.map +1 -1
  56. package/dist/hooks/use-global-event.d.ts +1 -1
  57. package/dist/index.js +18 -20019
  58. package/dist/index.js.map +1 -1
  59. package/dist/kernel/index.js +2 -2035
  60. package/dist/kernel/index.js.map +1 -1
  61. package/dist/kernel/types.d.ts +1 -1
  62. package/dist/modules/ambient/analyze.d.ts +46 -0
  63. package/dist/modules/ambient/analyze.d.ts.map +1 -0
  64. package/dist/modules/ambient/constants.d.ts +1 -5
  65. package/dist/modules/ambient/constants.d.ts.map +1 -1
  66. package/dist/modules/ambient/context.d.ts.map +1 -1
  67. package/dist/modules/ambient/dom.d.ts +11 -12
  68. package/dist/modules/ambient/dom.d.ts.map +1 -1
  69. package/dist/modules/ambient/extractor.d.ts +12 -4
  70. package/dist/modules/ambient/extractor.d.ts.map +1 -1
  71. package/dist/modules/ambient/hooks.d.ts +1 -1
  72. package/dist/modules/ambient/hooks.d.ts.map +1 -1
  73. package/dist/modules/ambient/index.d.ts +6 -4
  74. package/dist/modules/ambient/index.d.ts.map +1 -1
  75. package/dist/modules/ambient/index.js +7 -753
  76. package/dist/modules/ambient/index.js.map +1 -1
  77. package/dist/modules/ambient/module.d.ts +1 -1
  78. package/dist/modules/ambient/module.d.ts.map +1 -1
  79. package/dist/modules/ambient/oklab.d.ts +36 -0
  80. package/dist/modules/ambient/oklab.d.ts.map +1 -0
  81. package/dist/modules/ambient/pipeline.d.ts +28 -0
  82. package/dist/modules/ambient/pipeline.d.ts.map +1 -0
  83. package/dist/modules/ambient/quantize.d.ts +22 -0
  84. package/dist/modules/ambient/quantize.d.ts.map +1 -0
  85. package/dist/modules/ambient/server/address.d.ts +8 -0
  86. package/dist/modules/ambient/server/address.d.ts.map +1 -0
  87. package/dist/modules/ambient/server/index.d.ts +53 -0
  88. package/dist/modules/ambient/server/index.d.ts.map +1 -0
  89. package/dist/modules/ambient/server/index.js +221 -0
  90. package/dist/modules/ambient/server/index.js.map +1 -0
  91. package/dist/modules/ambient/settings.d.ts +19 -0
  92. package/dist/modules/ambient/settings.d.ts.map +1 -0
  93. package/dist/modules/ambient/types.d.ts +105 -9
  94. package/dist/modules/ambient/types.d.ts.map +1 -1
  95. package/dist/modules/ambient/worker/index.d.ts +15 -0
  96. package/dist/modules/ambient/worker/index.d.ts.map +1 -0
  97. package/dist/modules/ambient/worker/index.js +114 -0
  98. package/dist/modules/ambient/worker/index.js.map +1 -0
  99. package/dist/modules/background/constants.d.ts +2 -2
  100. package/dist/modules/background/constants.d.ts.map +1 -1
  101. package/dist/modules/background/hooks.d.ts +1 -1
  102. package/dist/modules/background/index.js +6 -3078
  103. package/dist/modules/background/index.js.map +1 -1
  104. package/dist/modules/background/motion.d.ts +9 -7
  105. package/dist/modules/background/motion.d.ts.map +1 -1
  106. package/dist/modules/background/overlay.d.ts +3 -8
  107. package/dist/modules/background/overlay.d.ts.map +1 -1
  108. package/dist/modules/background/types.d.ts +16 -2
  109. package/dist/modules/background/types.d.ts.map +1 -1
  110. package/dist/modules/context-menu/constants.d.ts +2 -2
  111. package/dist/modules/context-menu/constants.d.ts.map +1 -1
  112. package/dist/modules/context-menu/hooks.d.ts +1 -1
  113. package/dist/modules/context-menu/index.js +10 -1896
  114. package/dist/modules/context-menu/index.js.map +1 -1
  115. package/dist/modules/context-menu/motion.d.ts +1 -8
  116. package/dist/modules/context-menu/motion.d.ts.map +1 -1
  117. package/dist/modules/context-menu/overlay.d.ts.map +1 -1
  118. package/dist/modules/context-menu/types.d.ts +16 -2
  119. package/dist/modules/context-menu/types.d.ts.map +1 -1
  120. package/dist/modules/controls/constants.d.ts +1 -1
  121. package/dist/modules/controls/constants.d.ts.map +1 -1
  122. package/dist/modules/controls/entries.d.ts +1 -1
  123. package/dist/modules/controls/hooks.d.ts +1 -1
  124. package/dist/modules/controls/index.js +4 -1110
  125. package/dist/modules/controls/index.js.map +1 -1
  126. package/dist/modules/controls/overlay.d.ts +1 -1
  127. package/dist/modules/controls/types.d.ts +2 -2
  128. package/dist/modules/dock/cards.d.ts +708 -24
  129. package/dist/modules/dock/cards.d.ts.map +1 -1
  130. package/dist/modules/dock/constants.d.ts +2 -2
  131. package/dist/modules/dock/constants.d.ts.map +1 -1
  132. package/dist/modules/dock/helpers.d.ts +2 -2
  133. package/dist/modules/dock/hooks.d.ts +2 -2
  134. package/dist/modules/dock/index.d.ts +1 -1
  135. package/dist/modules/dock/index.d.ts.map +1 -1
  136. package/dist/modules/dock/index.js +9 -12130
  137. package/dist/modules/dock/index.js.map +1 -1
  138. package/dist/modules/dock/module.d.ts +1 -1
  139. package/dist/modules/dock/motion.d.ts +41 -915
  140. package/dist/modules/dock/motion.d.ts.map +1 -1
  141. package/dist/modules/dock/overlay.d.ts.map +1 -1
  142. package/dist/modules/dock/runtime/dock.d.ts +1 -23
  143. package/dist/modules/dock/runtime/dock.d.ts.map +1 -1
  144. package/dist/modules/dock/styles.d.ts +4 -4
  145. package/dist/modules/dock/surface/context.d.ts.map +1 -1
  146. package/dist/modules/dock/surface/hooks.d.ts +10 -23
  147. package/dist/modules/dock/surface/hooks.d.ts.map +1 -1
  148. package/dist/modules/dock/surface/machine.d.ts +4 -3
  149. package/dist/modules/dock/surface/machine.d.ts.map +1 -1
  150. package/dist/modules/dock/surface/stack.d.ts.map +1 -1
  151. package/dist/modules/dock/types.d.ts +158 -3
  152. package/dist/modules/dock/types.d.ts.map +1 -1
  153. package/dist/modules/index.js +16 -17873
  154. package/dist/modules/index.js.map +1 -1
  155. package/dist/modules/loading/constants.d.ts +1 -1
  156. package/dist/modules/loading/constants.d.ts.map +1 -1
  157. package/dist/modules/loading/context.d.ts +1 -1
  158. package/dist/modules/loading/hooks.d.ts +1 -1
  159. package/dist/modules/loading/index.js +5 -1153
  160. package/dist/modules/loading/index.js.map +1 -1
  161. package/dist/modules/loading/types.d.ts +2 -2
  162. package/dist/modules/media/context.d.ts +1 -1
  163. package/dist/modules/media/index.js +3 -570
  164. package/dist/modules/media/index.js.map +1 -1
  165. package/dist/modules/media/types.d.ts +2 -2
  166. package/dist/modules/modal/constants.d.ts +2 -2
  167. package/dist/modules/modal/constants.d.ts.map +1 -1
  168. package/dist/modules/modal/context.d.ts +1 -1
  169. package/dist/modules/modal/hooks.d.ts +3 -3
  170. package/dist/modules/modal/index.js +8 -2355
  171. package/dist/modules/modal/index.js.map +1 -1
  172. package/dist/modules/modal/motion.d.ts +3 -8
  173. package/dist/modules/modal/motion.d.ts.map +1 -1
  174. package/dist/modules/modal/overlay.d.ts.map +1 -1
  175. package/dist/modules/modal/types.d.ts +21 -0
  176. package/dist/modules/modal/types.d.ts.map +1 -1
  177. package/dist/modules/notification/constants.d.ts +2 -2
  178. package/dist/modules/notification/constants.d.ts.map +1 -1
  179. package/dist/modules/notification/context.d.ts +1 -1
  180. package/dist/modules/notification/hooks.d.ts +1 -1
  181. package/dist/modules/notification/index.js +4 -828
  182. package/dist/modules/notification/index.js.map +1 -1
  183. package/dist/modules/notification/motion.d.ts +1 -7
  184. package/dist/modules/notification/motion.d.ts.map +1 -1
  185. package/dist/modules/notification/overlay.d.ts.map +1 -1
  186. package/dist/modules/notification/types.d.ts +9 -1
  187. package/dist/modules/notification/types.d.ts.map +1 -1
  188. package/dist/overlay-TZ6L52A5.js +9 -0
  189. package/dist/overlay-TZ6L52A5.js.map +1 -0
  190. package/dist/provider.d.ts +1 -1
  191. package/dist/provider.d.ts.map +1 -1
  192. package/dist/provider.js +6 -1968
  193. package/dist/provider.js.map +1 -1
  194. package/dist/result.js +2 -63
  195. package/dist/result.js.map +1 -1
  196. package/dist/theme.d.ts +45 -8
  197. package/dist/theme.d.ts.map +1 -1
  198. package/dist/theme.js +3 -41
  199. package/dist/theme.js.map +1 -1
  200. package/dist/tokens/index.d.ts +1 -0
  201. package/dist/tokens/index.d.ts.map +1 -1
  202. package/dist/tokens/index.js +126 -155
  203. package/dist/tokens/index.js.map +1 -1
  204. package/dist/tokens/motion-config.d.ts +44 -0
  205. package/dist/tokens/motion-config.d.ts.map +1 -0
  206. package/dist/tokens/motion.d.ts +23 -174
  207. package/dist/tokens/motion.d.ts.map +1 -1
  208. package/dist/utils/index.js +4 -82
  209. package/dist/utils/index.js.map +1 -1
  210. package/dist/utils/report.d.ts.map +1 -1
  211. package/docs/README.md +1 -0
  212. package/docs/architecture-and-rules.md +4 -3
  213. package/docs/core-engine.md +7 -10
  214. package/docs/getting-started.md +4 -2
  215. package/docs/modules/ambient.md +194 -80
  216. package/docs/modules/background.md +3 -3
  217. package/docs/modules/context-menu.md +2 -2
  218. package/docs/modules/dock.md +8 -5
  219. package/docs/modules/modal.md +2 -2
  220. package/docs/modules/notification.md +2 -2
  221. package/docs/theming.md +81 -9
  222. package/package.json +22 -5
  223. package/templates/AGENTS.md +1 -1
  224. package/templates/motion/background.ts +17 -0
  225. package/templates/motion/context-menu.ts +63 -0
  226. package/templates/motion/dock.ts +327 -0
  227. package/templates/motion/modal.ts +79 -0
  228. package/templates/motion/notification.ts +27 -0
  229. package/templates/motion/tokens.ts +47 -0
  230. package/templates/tsconfig.json +7 -0
  231. package/dist/modules/ambient/color.d.ts +0 -16
  232. package/dist/modules/ambient/color.d.ts.map +0 -1
package/docs/theming.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Theming System Guide — `@omerdlw/base-framework/theme`
2
2
 
3
- > **Read this first if you need to:** customize the visual design of any first-party module (`dock`, `modal`, `notification`, etc.), supply custom Tailwind styles, or understand the theme slot contract.
3
+ > **Read this first if you need to:** customize the visual design or the animation of any first-party module (`dock`, `modal`, `notification`, etc.), supply custom Tailwind styles, set your app's motion tempo, or understand the theme slot and motion contracts.
4
4
 
5
5
  ---
6
6
 
@@ -10,6 +10,8 @@
10
10
 
11
11
  Modules ship with **zero hardcoded visual Tailwind colors or aesthetic choices**. Instead, each module declares a typed **Theme Spec** defining required "slots" (e.g. `card`, `backdrop`, `header`, `item`).
12
12
 
13
+ The same holds for **animation**. Modules that animate (`dock`, `modal`, `notification`, `context-menu`, `background`) ship no durations, curves, springs or travel distances. Their spec also declares a typed **motion contract**, and your theme file supplies it next to `slots` (§5). The module keeps only the mechanics: which phase plays when, what comes from layout, and accessibility.
14
+
13
15
  If a required theme is not provided to `<ThemeProvider>`, `useTheme()` throws an informative error at mount time:
14
16
  ```
15
17
  Theme "dock" is missing. Add its theme configuration to your ThemeProvider.
@@ -33,15 +35,16 @@ import {
33
35
  } from "@omerdlw/base-framework/theme";
34
36
  ```
35
37
 
36
- ### 2.1 `defineThemeSpec<Slots>(id)`
38
+ ### 2.1 `defineThemeSpec<Slots, Motion?>(id)`
37
39
  Used by module authors to define the contract:
38
40
  ```ts
39
41
  export type DockThemeSlot = "card" | "header" | "title" | "description" | "icon" | "surface";
40
- export const dockTheme = defineThemeSpec<DockThemeSlot>("dock");
42
+ export const dockTheme = defineThemeSpec<DockThemeSlot, DockMotion>("dock");
41
43
  ```
44
+ The second type parameter is the module's motion contract. Leave it out for a module that doesn't animate (`ambient`, `controls`, `loading`, `error`).
42
45
 
43
- ### 2.2 `defineTheme(spec, { slots, styles? })`
44
- Used by application developers to implement the styling contract. TypeScript enforces that **every required slot** is provided:
46
+ ### 2.2 `defineTheme(spec, { slots, styles?, motion })`
47
+ Used by application developers to implement the styling contract. TypeScript enforces that **every required slot** is provided, and that `motion` is given exactly when the spec declares a motion contract (§5):
45
48
  ```ts
46
49
  export const dockThemeConfig = defineTheme(dockTheme, {
47
50
  slots: {
@@ -59,10 +62,10 @@ export const dockThemeConfig = defineTheme(dockTheme, {
59
62
  });
60
63
  ```
61
64
 
62
- ### 2.3 `ThemeProvider({ themes, children })`
63
- Wraps your application or `CoreProvider` to supply the theme map:
65
+ ### 2.3 `ThemeProvider({ themes, motion?, children })`
66
+ Wraps your application or `CoreProvider` to supply the theme map and your motion tokens (§5.1):
64
67
  ```tsx
65
- <ThemeProvider themes={[dockThemeConfig, modalThemeConfig, notificationThemeConfig]}>
68
+ <ThemeProvider themes={[dockThemeConfig, modalThemeConfig, notificationThemeConfig]} motion={appMotion}>
66
69
  <CoreProvider modules={modules}>
67
70
  {children}
68
71
  </CoreProvider>
@@ -165,6 +168,8 @@ export const appThemes = [
165
168
  ];
166
169
  ```
167
170
 
171
+ Modules that animate also need their `motion` (§5): start from the framework's `templates/motion/` and add `motion: dockMotion` and so on next to each `slots`.
172
+
168
173
  Then in `src/app/providers.tsx`:
169
174
 
170
175
  ```tsx
@@ -173,13 +178,80 @@ Then in `src/app/providers.tsx`:
173
178
  import { ThemeProvider } from "@omerdlw/base-framework/theme";
174
179
  import { CoreProvider } from "@omerdlw/base-framework/provider";
175
180
  import { appThemes } from "@/config/themes";
181
+ import { motion } from "@/config/theme/motion/tokens";
176
182
  import { modules } from "@/config/modules";
177
183
 
178
184
  export function Providers({ children }: { children: React.ReactNode }) {
179
185
  return (
180
- <ThemeProvider themes={appThemes}>
186
+ <ThemeProvider themes={appThemes} motion={motion}>
181
187
  <CoreProvider modules={modules}>{children}</CoreProvider>
182
188
  </ThemeProvider>
183
189
  );
184
190
  }
185
191
  ```
192
+
193
+ ---
194
+
195
+ ## 5. Motion: Your App Owns Every Animation
196
+
197
+ Animation is part of your design, so it lives in your theme files like your slots do. The framework applies two things to whatever you write: your **tempo** and your **reduced-motion policy**.
198
+
199
+ ### 5.1 `defineMotion({ tempo?, reducedMotion?, durations?, easings?, springs? })`
200
+
201
+ ```ts
202
+ // src/config/theme/motion/tokens.ts
203
+ import { defineMotion } from "@omerdlw/base-framework/tokens";
204
+
205
+ export const motion = defineMotion({
206
+ tempo: 1, // stretches everything a module animates
207
+ reducedMotion: "user", // "user" (OS setting) | "always" | "never"
208
+ durations: { fast: 0.28, base: 0.36, slow: 0.58 },
209
+ easings: { enter: [0.25, 1, 0.5, 1], exit: [0.5, 0, 1, 1] },
210
+ springs: { press: { type: "spring", stiffness: 420, damping: 34, mass: 0.35 } },
211
+ });
212
+ ```
213
+
214
+ - `durations`, `easings` and `springs` are **your vocabulary**: name them as you like. The framework never reads them. Your module motion files use them, so changing one easing re-times every module that refers to it.
215
+ - `tempo` stretches every duration, delay, stagger and choreography timer the modules play, including the ones you wrote. Springs are retuned to take tempo× as long at the same damping ratio. Write values at tempo 1.
216
+ - Pass the result to `<ThemeProvider motion={motion}>`. App code can read it back with `useMotionTokens()`, which also returns `reduced`: whether reduced motion is in effect. A nested `ThemeProvider` without `motion` keeps the one above it.
217
+
218
+ ### 5.2 Module motion: `defineTheme(spec, { slots, motion })`
219
+
220
+ Each animating module exports its contract type. Give it a full value, the same way you give `slots`:
221
+
222
+ | Module | Spec | Contract type | What it holds |
223
+ | :--- | :--- | :--- | :--- |
224
+ | Dock | `dockTheme` | `DockMotion` | `transitions` (stack, expand, surface enter/step/exit/resize, cards, text, header swap, press, …), `variants` (fade, text crossfade, header swap/restore, controls, command bar, badge, hud, …), `deck` (elevation, compress, `peek(position)`, `exit(card)`, `tapScale`), `drag`, `skeleton`, `timings` (surface phase lengths and card staggers, in seconds) |
225
+ | Modal | `modalTheme` | `ModalMotion` | `backdrop`, `content`, `header`, `footer` variants, and `positions` (`center`, `top`, `right`, `bottom`, `left`: variants plus an optional own `transition`) |
226
+ | Notification | `notificationTheme` | `NotificationMotion` | `toast` variants and the toast's `transition` |
227
+ | Context menu | `contextMenuTheme` | `ContextMenuMotion` | `pop`, `content`, `item` variants (`item.visible` may take the row index), `itemTap`, `itemTransition` |
228
+ | Background | `backgroundTheme` | `BackgroundMotion` | `initial`, `animate`, `exit`, `transition`, `exitDurationFactor`. A page's own `background.animation` still wins field by field and follows your tempo too. |
229
+
230
+ ```ts
231
+ // src/config/theme/dock.ts
232
+ import { defineTheme } from "@omerdlw/base-framework/theme";
233
+ import { dockTheme } from "@omerdlw/base-framework/modules/dock";
234
+ import { dockMotion } from "./motion/dock";
235
+
236
+ export const dockThemeConfig = defineTheme(dockTheme, { slots: { … }, motion: dockMotion });
237
+ ```
238
+
239
+ Variant functions keep their `custom` signature (e.g. `commandBar.visible(index)`, `controlsContainer.hidden(targetY)`), and `deck.peek` / `deck.exit` receive what the dock knows from layout. Everything else about those values is yours.
240
+
241
+ If an animating module's theme has no `motion`, mounting it throws:
242
+ ```
243
+ Motion for theme "dock" is missing. Add `motion` to its defineTheme(...) next to `slots` (start from the framework's templates/motion/).
244
+ ```
245
+ `DockProvider` alone (without the dock theme) still runs: its surface phases advance immediately, since nothing is drawn.
246
+
247
+ ### 5.3 The starter: `templates/motion/`
248
+
249
+ The package ships `templates/motion/` with `tokens.ts`, `dock.ts`, `modal.ts`, `notification.ts`, `context-menu.ts` and `background.ts`. It is a complete starting point (the motion the modules carried before motion moved into apps), type-checked against the module contracts. Copy the folder into your app (e.g. `src/config/theme/motion/`) and make it yours; the framework never reads it.
250
+
251
+ ### 5.4 Reduced motion
252
+
253
+ Reduced motion is an accessibility mechanic, so the framework handles it once for every module:
254
+
255
+ - When it is in effect (`reducedMotion: "always"`, or `"user"` with the OS setting on), every module transition, including your own, collapses to `REDUCED_MOTION_TRANSITION` (0.08 s, linear, no delay). Every `timings` entry is capped at 0.08 s, so choreography doesn't hold the dock still on animations that aren't playing.
256
+ - `CoreProvider` wraps every module backdrop and overlay in `ModuleMotionConfig` (Motion's `MotionConfig` with your policy), so positional values (`width`, `height`, `x`, `scale`, …) jump instead of animating. App content outside the modules is untouched and keeps its own `MotionConfig`.
257
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omerdlw/base-framework",
3
- "version": "1.0.5",
3
+ "version": "2.0.0",
4
4
  "description": "Microkernel engine and first-party declarative UI modules for app-like Next.js products.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -82,6 +82,16 @@
82
82
  "import": "./dist/modules/ambient/index.js",
83
83
  "default": "./dist/modules/ambient/index.js"
84
84
  },
85
+ "./ambient/server": {
86
+ "types": "./dist/modules/ambient/server/index.d.ts",
87
+ "import": "./dist/modules/ambient/server/index.js",
88
+ "default": "./dist/modules/ambient/server/index.js"
89
+ },
90
+ "./ambient/worker": {
91
+ "types": "./dist/modules/ambient/worker/index.d.ts",
92
+ "import": "./dist/modules/ambient/worker/index.js",
93
+ "default": "./dist/modules/ambient/worker/index.js"
94
+ },
85
95
  "./background": {
86
96
  "types": "./dist/modules/background/index.d.ts",
87
97
  "import": "./dist/modules/background/index.js",
@@ -126,12 +136,13 @@
126
136
  "LICENSE"
127
137
  ],
128
138
  "scripts": {
129
- "build": "rm -rf dist && ./node_modules/.bin/tsup && ./node_modules/.bin/tsc --emitDeclarationOnly --outDir dist",
130
- "prepublishOnly": "npm run build",
139
+ "build": "rm -rf dist && ./node_modules/.bin/tsup && ./node_modules/.bin/tsc --emitDeclarationOnly --outDir dist && node scripts/rewrite-dts-aliases.mjs",
140
+ "prepublishOnly": "npm run build && npm run test:dist",
131
141
  "dev": "./node_modules/.bin/tsup --watch",
132
- "type-check": "./node_modules/.bin/tsc --noEmit",
142
+ "type-check": "./node_modules/.bin/tsc --noEmit && ./node_modules/.bin/tsc -p templates",
133
143
  "check:architecture": "node scripts/check-architecture.mjs",
134
144
  "test": "node --import ./tests/support/register.mjs --test 'tests/**/*.test.ts'",
145
+ "test:dist": "node --import ./tests/support/register.mjs --test 'tests/bundle/*.smoke.ts'",
135
146
  "pack": "npm run build && npm pack",
136
147
  "clean": "rm -rf dist *.tgz"
137
148
  },
@@ -139,7 +150,13 @@
139
150
  "motion": "^12.0.0 || ^13.0.0",
140
151
  "next": ">=15.0.0",
141
152
  "react": ">=19.0.0",
142
- "react-dom": ">=19.0.0"
153
+ "react-dom": ">=19.0.0",
154
+ "sharp": "^0.35.0"
155
+ },
156
+ "peerDependenciesMeta": {
157
+ "sharp": {
158
+ "optional": true
159
+ }
143
160
  },
144
161
  "dependencies": {
145
162
  "@iconify-icon/react": "3.0.3",
@@ -10,7 +10,7 @@
10
10
  - **Engine:** Next.js 16 (App Router), React 19
11
11
  - **Core Framework:** `@omerdlw/base-framework` (Microkernel & Declarative UI Modules)
12
12
  - **Styling:** Tailwind CSS v4 (`@theme`, OKLCH semantic color tokens, `.center`, `.skeleton-block`)
13
- - **Motion:** Motion (v13) with hardware GPU acceleration (`translate3d`, `scale`)
13
+ - **Motion:** Motion (v13) with hardware GPU acceleration (`translate3d`, `scale`). Framework modules ship no animation of their own: the dock, modal, toast, context-menu and background motion lives in this app's theme files (`motion` next to `slots`), with tempo and vocabulary from `defineMotion`. Change module animation there, never in the framework.
14
14
  - **Icons:** `@iconify-icon/react` via `<Icon icon="solar:..." />`
15
15
 
16
16
  ---
@@ -0,0 +1,17 @@
1
+ import type { BackgroundMotion } from "@omerdlw/base-framework/modules/background";
2
+ import { motion } from "./tokens";
3
+
4
+ const { durations, easings } = motion;
5
+
6
+ // defineTheme(backgroundTheme, { slots, motion: backgroundMotion })
7
+ // A page can still pass its own `background.animation`; it wins field by field.
8
+ export const backgroundMotion: BackgroundMotion = {
9
+ initial: { opacity: 0 },
10
+ animate: { opacity: 1 },
11
+ exit: {
12
+ opacity: 0,
13
+ transition: { duration: durations.slow, ease: easings.exit },
14
+ },
15
+ transition: { delay: 0, duration: durations.slow, ease: easings.enter },
16
+ exitDurationFactor: 0.6,
17
+ };
@@ -0,0 +1,63 @@
1
+ import type { ContextMenuMotion } from "@omerdlw/base-framework/modules/context-menu";
2
+ import { motion } from "./tokens";
3
+
4
+ const { durations, easings, springs } = motion;
5
+
6
+ // Rows come in one after another, a short step apart, after the menu opens.
7
+ const rowDelay = (index: unknown) =>
8
+ 0.04 + Math.min(Math.max(Number(index) || 0, 0) * 0.042, 0.21);
9
+
10
+ const leave = { duration: durations.micro, ease: easings.exit };
11
+
12
+ // defineTheme(contextMenuTheme, { slots, motion: contextMenuMotion })
13
+ export const contextMenuMotion: ContextMenuMotion = {
14
+ pop: {
15
+ hidden: {
16
+ opacity: 0,
17
+ transform: "translate3d(0px, 0px, 0) scale(0.96)",
18
+ transformOrigin: "top left",
19
+ },
20
+ visible: {
21
+ opacity: 1,
22
+ transform: "translate3d(0px, 0px, 0) scale(1)",
23
+ transformOrigin: "top left",
24
+ transition: { duration: durations.fast, ease: easings.emphasized },
25
+ },
26
+ exit: {
27
+ opacity: 0,
28
+ transform: "translate3d(0px, 0px, 0) scale(0.98)",
29
+ transformOrigin: "top left",
30
+ transition: leave,
31
+ },
32
+ },
33
+ content: {
34
+ hidden: { opacity: 0 },
35
+ visible: {
36
+ opacity: 1,
37
+ transition: { duration: durations.fast, ease: easings.weighted, delay: 0.04 },
38
+ },
39
+ exit: { opacity: 0, transition: leave },
40
+ },
41
+ item: {
42
+ hidden: {
43
+ opacity: 0,
44
+ transform: "translate3d(0px, 4px, 0) scale(0.992)",
45
+ },
46
+ visible: (index: unknown = 0) => ({
47
+ opacity: 1,
48
+ transform: "translate3d(0px, 0px, 0) scale(1)",
49
+ transition: {
50
+ duration: durations.fast,
51
+ ease: easings.emphasized,
52
+ delay: rowDelay(index),
53
+ },
54
+ }),
55
+ exit: {
56
+ opacity: 0,
57
+ transform: "translate3d(0px, -3px, 0) scale(0.994)",
58
+ transition: leave,
59
+ },
60
+ },
61
+ itemTap: { transform: "translate3d(0px, 0px, 0) scale(0.97)" },
62
+ itemTransition: springs.tap,
63
+ };
@@ -0,0 +1,327 @@
1
+ import type { DockMotion } from "@omerdlw/base-framework/modules/dock";
2
+ import {
3
+ chip,
4
+ contentSwap,
5
+ contentSwapTransitions,
6
+ gpuTransform,
7
+ overlaySurface,
8
+ press,
9
+ staggerDelay,
10
+ surfaceResizeTransition,
11
+ } from "@omerdlw/base-framework/tokens";
12
+ import { motion, tween } from "./tokens";
13
+
14
+ const { durations, easings, springs } = motion;
15
+
16
+ // Dock-only lengths, next to the shared scale.
17
+ const HEADER = 0.32;
18
+ const ACTION_DISMISS = 0.32;
19
+ const COLLAPSE = 0.52;
20
+
21
+ // A surface opening: the inline action leaves (overlapping the growth a
22
+ // little), the deck compresses for a beat, then the body grows in. Closing
23
+ // runs the other way and the card header comes back last.
24
+ const SURFACE = {
25
+ anticipation: 0.24,
26
+ bodyEnter: 0.86,
27
+ bodyEnterDelay: 0.1,
28
+ // The header's return: 0.36s in all, of which 0.08s is waiting.
29
+ headerRestore: 0.36,
30
+ headerRevealDelay: 0.08,
31
+ headerReveal: 0.28,
32
+ };
33
+
34
+ const swap = (duration: number, enterEase: typeof easings.enter) =>
35
+ contentSwapTransitions({
36
+ duration,
37
+ exitDuration: durations.fast,
38
+ enterEase,
39
+ exitEase: easings.exit,
40
+ });
41
+
42
+ const headerSwap = swap(HEADER, easings.enter);
43
+ const controlSwap = swap(durations.base, easings.enter);
44
+ const textSwap = swap(durations.base, easings.emphasized);
45
+
46
+ const expand = tween(durations.cinematic, easings.weighted);
47
+ const card = tween(COLLAPSE, easings.enter);
48
+ const cardCollapse = tween(durations.base, easings.exit);
49
+
50
+ const surfaceBody = overlaySurface({
51
+ travel: 14,
52
+ exitTravel: 14,
53
+ enterScale: 0.985,
54
+ exitScale: 0.985,
55
+ duration: SURFACE.bodyEnter - SURFACE.bodyEnterDelay,
56
+ exitDuration: SURFACE.anticipation,
57
+ enterEase: easings.weighted,
58
+ exitEase: easings.weighted,
59
+ });
60
+
61
+ const pressRole = press({ tapScale: 0.97, spring: springs.press });
62
+
63
+ const extensionsEnter = tween(durations.moderate, easings.emphasized);
64
+ const extensionsExit = tween(durations.base, easings.exit);
65
+
66
+ // The STANDARD tier: a crossfade that travels a little under half of 18px.
67
+ const crossfade = {
68
+ distance: Math.round(18 * 0.42),
69
+ duration: durations.moderate,
70
+ scale: 1 - 0.018,
71
+ };
72
+
73
+ const controlsSlot = (enter: object, exit: object) => ({
74
+ hidden: { opacity: 0, scale: 0.96, width: 0, marginRight: -2 },
75
+ visible: { opacity: 1, scale: 1, width: "auto", marginRight: 0, transition: enter },
76
+ exit: { opacity: 0, scale: 0.96, width: 0, marginRight: -2, transition: exit },
77
+ });
78
+
79
+ // defineTheme(dockTheme, { slots, motion: dockMotion })
80
+ export const dockMotion: DockMotion = {
81
+ transitions: {
82
+ stack: tween(COLLAPSE, easings.enter),
83
+ expand,
84
+ surfaceResize: (distancePx) => {
85
+ const resize = surfaceResizeTransition(distancePx, {
86
+ base: 0.5,
87
+ min: 0.4,
88
+ max: durations.cinematic,
89
+ ease: easings.weighted,
90
+ });
91
+ return { ...resize, height: resize, width: resize };
92
+ },
93
+ surfaceArrival: tween(durations.cinematic, easings.overshoot),
94
+ anticipation: tween(SURFACE.anticipation, easings.weighted),
95
+ surfaceEnter: { ...surfaceBody.visible.transition, delay: SURFACE.bodyEnterDelay },
96
+ surfaceStep: swap(durations.base, easings.enter).enter,
97
+ surfaceExit: surfaceBody.exit.transition,
98
+ card,
99
+ cardExpanded: springs.deck,
100
+ cardPeek: tween(durations.fast, easings.enter),
101
+ fade: tween(durations.moderate, easings.emphasized),
102
+ text: textSwap.enter,
103
+ headerSwap: headerSwap.enter,
104
+ actionDismiss: tween(ACTION_DISMISS, easings.exit),
105
+ icon: tween(durations.fast, easings.enter),
106
+ badge: springs.badge,
107
+ hud: tween(durations.moderate, easings.emphasized),
108
+ press: pressRole.transition,
109
+ scrubberTooltip: tween(durations.fast, easings.emphasized),
110
+ scrubberFollow: springs.tooltip,
111
+ mediaVolume: { duration: durations.fast, ease: easings.enter },
112
+ },
113
+ variants: {
114
+ fade: {
115
+ hidden: { opacity: 0, transform: gpuTransform(6, 0.99) },
116
+ visible: { opacity: 1, transform: gpuTransform(0), transition: textSwap.enter },
117
+ exit: { opacity: 0, transform: gpuTransform(-4, 0.99), transition: textSwap.exit },
118
+ },
119
+ textCrossfade: {
120
+ hidden: { opacity: 0, transform: gpuTransform(crossfade.distance, crossfade.scale) },
121
+ visible: {
122
+ opacity: 1,
123
+ transform: gpuTransform(0),
124
+ transition: { duration: crossfade.duration, ease: easings.enter },
125
+ },
126
+ exit: {
127
+ opacity: 0,
128
+ transform: gpuTransform(crossfade.distance, crossfade.scale),
129
+ transition: {
130
+ duration: Math.min(crossfade.duration * 0.7, durations.moderate),
131
+ ease: easings.exit,
132
+ },
133
+ },
134
+ },
135
+ description: (opacity = 0.7) => ({
136
+ hidden: { opacity: 0, transform: gpuTransform(4, 0.99) },
137
+ visible: {
138
+ opacity,
139
+ transform: gpuTransform(0),
140
+ transition: { duration: durations.base, ease: easings.emphasized },
141
+ },
142
+ exit: {
143
+ opacity: 0,
144
+ transform: gpuTransform(-3, 0.99),
145
+ transition: { duration: durations.fast, ease: easings.exit },
146
+ },
147
+ }),
148
+ headerSwap: contentSwap({
149
+ travel: 4,
150
+ exitTravel: 4,
151
+ enterScale: 0.99,
152
+ exitScale: 0.99,
153
+ duration: HEADER,
154
+ exitDuration: durations.fast,
155
+ enterEase: easings.enter,
156
+ exitEase: easings.exit,
157
+ }),
158
+ headerRestore: {
159
+ hidden: { opacity: 0, transform: gpuTransform(-4, 0.99) },
160
+ visible: {
161
+ opacity: 1,
162
+ transform: gpuTransform(0),
163
+ transition: {
164
+ type: "tween",
165
+ duration: SURFACE.headerReveal,
166
+ delay: SURFACE.headerRevealDelay,
167
+ ease: easings.enter,
168
+ },
169
+ },
170
+ exit: { opacity: 0, transform: gpuTransform(4, 0.99), transition: textSwap.exit },
171
+ },
172
+ extensionShelf: {
173
+ hidden: { opacity: 0, transform: gpuTransform(5, 0.99) },
174
+ visible: { opacity: 1, transform: gpuTransform(0, 1), transition: extensionsEnter },
175
+ exit: { opacity: 0, transform: gpuTransform(-4, 0.99), transition: extensionsExit },
176
+ },
177
+ actionDismiss: {
178
+ hidden: { opacity: 0, transform: gpuTransform(6, 0.99) },
179
+ visible: {
180
+ opacity: 1,
181
+ transform: gpuTransform(0),
182
+ transition: { duration: durations.fast, ease: easings.enter },
183
+ },
184
+ exit: {
185
+ opacity: 0,
186
+ transform: gpuTransform(-5, 0.99),
187
+ transition: { duration: ACTION_DISMISS, ease: easings.exit },
188
+ },
189
+ },
190
+ commandBar: {
191
+ hidden: { opacity: 0, transform: "translate3d(5px, 0, 0) scale(0.97)" },
192
+ visible: (index: unknown = 0) => ({
193
+ opacity: 1,
194
+ transform: "translate3d(0px, 0, 0) scale(1)",
195
+ transition: {
196
+ duration: durations.base,
197
+ delay: staggerDelay(Number(index) || 0, { base: 0.02, cap: 0.12 }),
198
+ ease: easings.enter,
199
+ },
200
+ }),
201
+ exit: {
202
+ opacity: 0,
203
+ transform: "translate3d(4px, 0, 0) scale(0.98)",
204
+ transition: { duration: durations.fast, ease: easings.exit },
205
+ },
206
+ },
207
+ icon: {
208
+ hidden: { opacity: 0, transform: gpuTransform(0, 0.92) },
209
+ visible: {
210
+ opacity: 1,
211
+ transform: gpuTransform(0, 1),
212
+ transition: { duration: durations.fast, ease: easings.enter },
213
+ },
214
+ exit: {
215
+ opacity: 0,
216
+ transform: gpuTransform(0, 0.92),
217
+ transition: { duration: durations.fast, ease: easings.exit },
218
+ },
219
+ },
220
+ badge: {
221
+ hidden: { opacity: 0, transform: gpuTransform(0, 0.88) },
222
+ visible: { opacity: 1, transform: gpuTransform(0) },
223
+ exit: { opacity: 0, transform: gpuTransform(0, 0.9) },
224
+ },
225
+ hud: {
226
+ hidden: { opacity: 0, transform: gpuTransform(4, 0.99) },
227
+ visible: {
228
+ opacity: 1,
229
+ transform: gpuTransform(0),
230
+ transition: tween(durations.moderate, easings.emphasized),
231
+ },
232
+ exit: { opacity: 0, transform: gpuTransform(3, 0.99), transition: textSwap.exit },
233
+ },
234
+ scrubberTooltip: {
235
+ hidden: { opacity: 0, transform: gpuTransform(4, 0.98) },
236
+ visible: { opacity: 1, transform: gpuTransform(0) },
237
+ exit: { opacity: 0, transform: gpuTransform(3, 0.99) },
238
+ },
239
+ breadcrumbs: {
240
+ hidden: { opacity: 0, transform: gpuTransform(-5, 0.985) },
241
+ visible: { opacity: 1, transform: gpuTransform(0), transition: expand },
242
+ exit: { opacity: 0, transform: gpuTransform(-3, 0.99), transition: card },
243
+ },
244
+ backdrop: {
245
+ hidden: { opacity: 0 },
246
+ visible: { opacity: 1 },
247
+ exit: { opacity: 0 },
248
+ },
249
+ surfaceBody,
250
+ controlsContainer: {
251
+ hidden: (targetY: unknown = 0) => ({
252
+ opacity: 0,
253
+ transform: gpuTransform((Number(targetY) || 0) + 6, 0.97),
254
+ transition: controlSwap.exit,
255
+ }),
256
+ visible: (targetY: unknown = 0) => ({
257
+ opacity: 1,
258
+ transform: gpuTransform(Number(targetY) || 0, 1),
259
+ transition: controlSwap.enter,
260
+ }),
261
+ exit: (targetY: unknown = 0) => ({
262
+ opacity: 0,
263
+ transform: gpuTransform((Number(targetY) || 0) + 6, 0.97),
264
+ transition: controlSwap.exit,
265
+ }),
266
+ },
267
+ controlsAction: controlsSlot(controlSwap.enter, controlSwap.exit),
268
+ controlsBack: controlsSlot(controlSwap.enter, controlSwap.exit),
269
+ controlsClose: chip({
270
+ duration: durations.base,
271
+ exitDuration: durations.fast,
272
+ enterEase: easings.enter,
273
+ exitEase: easings.exit,
274
+ }),
275
+ press: pressRole.variants,
276
+ mediaVolumeThumb: { idle: { scale: 1 }, dragging: { scale: 1.18 } },
277
+ cardContent: {
278
+ hidden: { opacity: 0, transform: gpuTransform(18 * 0.35, 1 - 0.008) },
279
+ visible: { opacity: 1, transform: gpuTransform(0, 1) },
280
+ },
281
+ },
282
+ deck: {
283
+ elevation: {
284
+ rest: "0px 12px 32px 0px rgba(0,0,0,0.35), 0px 2px 8px 0px rgba(0,0,0,0.25)",
285
+ elevated:
286
+ "0px 32px 80px 0px rgba(0,0,0,0.55), 0px 8px 24px 0px rgba(0,0,0,0.35)",
287
+ },
288
+ compress: { open: 0.94, close: 0.96 },
289
+ // Cards further back lift a little further and grow a little less.
290
+ peek: (position) => {
291
+ const progress = Math.min(position / 3, 1);
292
+ return {
293
+ lift: position * (4 * (0.85 + progress * 0.35)),
294
+ scale: 1 + 0.008 * (1 - progress * 0.25),
295
+ };
296
+ },
297
+ exit: ({ y, scale, position }) => ({
298
+ opacity: 0,
299
+ transform: gpuTransform(
300
+ y,
301
+ scale === null ? 0.98 - Math.min(position * 0.008, 0.024) : scale * 0.98,
302
+ ),
303
+ transition: { ...cardCollapse },
304
+ }),
305
+ tapScale: 0.97,
306
+ },
307
+ drag: {
308
+ elastic: { top: 0.05, bottom: 0.5 },
309
+ range: [0, 180],
310
+ opacity: [1, 0.75],
311
+ scale: [1, 0.96],
312
+ },
313
+ skeleton: "animate-pulse motion-reduce:animate-none",
314
+ timings: {
315
+ // The action's 0.32s dismissal, overlapped 0.22s by the growth.
316
+ dismissAction: 0.1,
317
+ anticipation: 0.07,
318
+ expandBody: SURFACE.bodyEnter,
319
+ // The body's 0.76s exit plus 0.1s for the deck to settle.
320
+ collapseBody: 0.86,
321
+ restoreHeader: SURFACE.headerRestore,
322
+ expandStagger: 0.055,
323
+ expandStaggerCap: 0.16,
324
+ peekStagger: 0.016,
325
+ peekStaggerCap: 0.064,
326
+ },
327
+ };