@omerdlw/base-framework 1.0.0 → 1.0.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.
Files changed (71) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +121 -52
  3. package/dist/hooks/index.d.ts +1 -10
  4. package/dist/hooks/index.d.ts.map +1 -1
  5. package/dist/hooks/index.js +2 -538
  6. package/dist/hooks/index.js.map +1 -1
  7. package/dist/hooks/types.d.ts +0 -53
  8. package/dist/hooks/types.d.ts.map +1 -1
  9. package/dist/hooks/use-global-event.d.ts +0 -2
  10. package/dist/hooks/use-global-event.d.ts.map +1 -1
  11. package/dist/index.js +138 -742
  12. package/dist/index.js.map +1 -1
  13. package/dist/kernel/index.js +3 -3
  14. package/dist/kernel/index.js.map +1 -1
  15. package/dist/modules/ambient/index.js.map +1 -1
  16. package/dist/modules/background/index.js +5 -5
  17. package/dist/modules/background/index.js.map +1 -1
  18. package/dist/modules/context-menu/index.js +4 -4
  19. package/dist/modules/context-menu/index.js.map +1 -1
  20. package/dist/modules/controls/index.js +3 -3
  21. package/dist/modules/controls/index.js.map +1 -1
  22. package/dist/modules/dock/cards.d.ts +1 -1
  23. package/dist/modules/dock/hooks.d.ts +1 -1
  24. package/dist/modules/dock/index.js +3 -3
  25. package/dist/modules/dock/index.js.map +1 -1
  26. package/dist/modules/index.js +34 -115
  27. package/dist/modules/index.js.map +1 -1
  28. package/dist/modules/loading/index.js +3 -3
  29. package/dist/modules/loading/index.js.map +1 -1
  30. package/dist/modules/media/index.js.map +1 -1
  31. package/dist/modules/modal/index.js +11 -95
  32. package/dist/modules/modal/index.js.map +1 -1
  33. package/dist/modules/notification/index.js +7 -5
  34. package/dist/modules/notification/index.js.map +1 -1
  35. package/dist/provider.js.map +1 -1
  36. package/dist/utils/dom.d.ts +0 -2
  37. package/dist/utils/dom.d.ts.map +1 -1
  38. package/dist/utils/index.d.ts +5 -6
  39. package/dist/utils/index.d.ts.map +1 -1
  40. package/dist/utils/index.js +19 -84
  41. package/dist/utils/index.js.map +1 -1
  42. package/dist/utils/number.d.ts +0 -1
  43. package/dist/utils/number.d.ts.map +1 -1
  44. package/dist/utils/object.d.ts +0 -2
  45. package/dist/utils/object.d.ts.map +1 -1
  46. package/dist/utils/string.d.ts +0 -3
  47. package/dist/utils/string.d.ts.map +1 -1
  48. package/dist/utils/timing.d.ts +0 -1
  49. package/dist/utils/timing.d.ts.map +1 -1
  50. package/docs/README.md +124 -0
  51. package/docs/architecture-and-rules.md +129 -0
  52. package/docs/core-engine.md +196 -0
  53. package/docs/custom-modules.md +267 -0
  54. package/docs/getting-started.md +199 -0
  55. package/docs/modules/README.md +176 -0
  56. package/docs/modules/ambient.md +150 -0
  57. package/docs/modules/background.md +195 -0
  58. package/docs/modules/context-menu.md +248 -0
  59. package/docs/modules/controls.md +159 -0
  60. package/docs/modules/dock.md +734 -0
  61. package/docs/modules/error-boundary.md +160 -0
  62. package/docs/modules/kernel.md +266 -0
  63. package/docs/modules/loading.md +157 -0
  64. package/docs/modules/media.md +196 -0
  65. package/docs/modules/modal.md +229 -0
  66. package/docs/modules/notification.md +161 -0
  67. package/docs/modules/result.md +135 -0
  68. package/docs/testing.md +160 -0
  69. package/docs/theming.md +185 -0
  70. package/package.json +3 -1
  71. package/templates/AGENTS.md +165 -0
@@ -0,0 +1,159 @@
1
+ # Controls — `@omerdlw/base-framework/modules/controls`
2
+
3
+ > **Read this first if you need to:** put small floating buttons on the left and right of the dock (mute, play/pause, back to top…), per page, without any layout code.
4
+
5
+ ## 1. At a glance
6
+
7
+ | | |
8
+ | :----------------- | :------------------------------------------------------------------------------------------------------------------------------------- |
9
+ | **Import** | `import { useControls, defineControls, … } from "@omerdlw/base-framework/modules/controls"` |
10
+ | **Module id** | `controls` (`controlsModule`, in `defaultModules`) |
11
+ | **Renders** | `Controls` overlay: two rails (`<aside>`) portalled to `document.body`, **only on viewports ≥ 640 px** (theme) |
12
+ | **Registry type** | `controls` — key policy `named` (`<path>::<id>`), lifecycle `immediate`, entries validated |
13
+ | **Page slice** | `usePage({ controls })` → `page.modules.controls.set(...)` |
14
+ | **Peers (`uses`)** | none. It finds the dock through the DOM, not through imports. |
15
+ | **DOM contract** | reads `#dock-card-stack` (or the element marked `data-controls-anchor="true"`); hides when the stack has `data-controls-hidden="true"` |
16
+ | **Theme** | `controlsTheme` slots in `src/config/controls.module.theme.ts` |
17
+ | **Tests** | `tests/modules/controls.test.ts` |
18
+
19
+ ## 2. Mental model
20
+
21
+ The module has **no state of its own**. Pages register control entries in the registry; the overlay (1) filters entries for the **current pathname**, (2) pairs a left and a right entry per `order`, (3) measures the dock's rectangle and (4) places each rail so it hugs the dock and stays inside the viewport.
22
+
23
+ ```
24
+ ┌──────── dock ────────┐
25
+ [left] │ │ [right]
26
+ rail ▶ └───────────────────────┘ ◀ rail (rails are bottom-aligned with the dock and
27
+ stacked upward: lowest `order` nearest the dock) expose `--controls-height` = half the dock height)
28
+ ```
29
+
30
+ > **Rows come in pairs.** A row exists per `order` value and is rendered only if it has **both** a left and a right entry. A page that registers only a left control shows **nothing**. This keeps the two rails visually symmetric around the dock.
31
+
32
+ ## 3. Quick start
33
+
34
+ ```tsx
35
+ usePage({
36
+ controls: {
37
+ left: <MuteButton />,
38
+ right: <BackToTop />,
39
+ },
40
+ });
41
+ ```
42
+
43
+ ```tsx
44
+ // Reusable pair; slots can be a node, a component, or a render function of props
45
+ const PlayerControls = defineControls({
46
+ id: "player",
47
+ order: 1,
48
+ left: MuteButton,
49
+ right: PlaybackRate,
50
+ defaultProps: { size: "sm" },
51
+ });
52
+
53
+ function Player() {
54
+ PlayerControls.use({ size: "md" }); // registers for the current path and returns the layout
55
+ return …;
56
+ }
57
+ ```
58
+
59
+ ```tsx
60
+ // Several rows, explicit entries
61
+ usePage({
62
+ controls: [
63
+ { id: "mute", side: "left", order: 0, content: <MuteButton /> },
64
+ { id: "top", side: "right", order: 0, content: <BackToTop /> },
65
+ { id: "loop", side: "left", order: 1, content: <LoopButton /> },
66
+ { id: "speed", side: "right", order: 1, content: <SpeedButton /> },
67
+ ],
68
+ });
69
+ ```
70
+
71
+ ## 4. Public API
72
+
73
+ | Export | Kind | Description |
74
+ | :------------------------------------------------------------------------------------------------------------------------------------------ | :-------- | :------------------------------------------------------------------------------------------------------------------------------------- |
75
+ | `controlsModule` | module | `defineModule` definition. |
76
+ | `Controls` | component | The overlay (rails). Mounted by the host; renders nothing without a dock, before measurement, while hidden, or with no left entries. |
77
+ | `useControls(config?, options?)` | hook | Registers controls for a path and returns the live `ControlsLayout \| null`. |
78
+ | `useControlsLayout()` | hook | Just the layout (rail geometry), measured from the dock; `null` until measurable. |
79
+ | `useControlsRegistration(config, options?)` | hook | Register only (what `usePage` does). |
80
+ | `defineControls(def)` | builder | `defineControls({ id?, order?, path?, left?, right?, defaultProps? }).use(props?, options?)`. |
81
+ | `CONTROLS_EDGE_INSET` (4), `CONTROLS_DOCK_GAP` (8), `CONTROLS_DOCK_ELEMENT_ID` (`"dock-card-stack"`), `CONTROL_SIDE_NAMES`, `controlsTheme` | constants | |
82
+ | Types | | `ControlEntry`, `ControlSide`, `ControlSlot`, `ControlsLayout`, `ControlsPageConfig`, `DefineControlsOptions`, `ControlsUseOptions`, … |
83
+
84
+ ### 4.1 Config shapes
85
+
86
+ `usePage({ controls })` and `useControls(config)` accept:
87
+
88
+ | Shape | Meaning |
89
+ | :--------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------ |
90
+ | `{ left?, right?, id?, order?, path?, registry? }` | Slot form. Each present side becomes an entry `{ id: "<id>-<side>", side, order, content }`. `id` defaults to `"controls"`, `order` to `0`. |
91
+ | `ControlEntry` `{ id, side, content, order, path? }` | One explicit entry. |
92
+ | `ControlEntry[]` | Several entries. |
93
+ | `null` | Removes the page's controls. |
94
+
95
+ `useControls` additionally takes the **definition** form (`defineControls` options): `left` / `right` may be a node, a component, or a function of `defaultProps`, resolved before registration.
96
+
97
+ `options` (second argument): `RegistryMetadata & { enabled?, path? }`. `path` overrides the pathname the entries belong to (default: the definition's `path`, else the current pathname).
98
+
99
+ ### 4.2 Entry rules (validated)
100
+
101
+ | Field | Rule |
102
+ | :-------- | :------------------------------------------------------------------------------------------------------- |
103
+ | `id` | Non-empty string. |
104
+ | `side` | `"left"` or `"right"`. |
105
+ | `content` | A renderable value (element, string, number, array of those). `null` / `false` entries are skipped. |
106
+ | `order` | A finite number. **Always set it for explicit entries** (the slot form defaults it to `0`). |
107
+ | `path` | The pathname the entry belongs to (set automatically by `usePage`). Entries for other paths are ignored. |
108
+
109
+ Within one `(order, side)` cell, if several entries compete the one with the **lexicographically smallest `id`** wins. Rows are sorted by ascending `order` and the stack is `flex-col-reverse`, so **lower `order` sits closest to the dock**.
110
+
111
+ ### 4.3 `ControlsLayout`
112
+
113
+ `{ bottom, height, left: { maxWidth, right }, right: { left, maxWidth }, isHidden? }` in CSS pixels. `height` is half the dock's height (exposed to the stack as `--controls-height`), `maxWidth` is the free space between the dock and the viewport edge (inset 4 px, gap 8 px).
114
+
115
+ ## 5. Behaviour
116
+
117
+ - **Measurement.** The anchor is `[data-controls-anchor="true"]` if present, otherwise `#dock-card-stack`. A `ResizeObserver` follows its size; a `MutationObserver` follows attribute changes and (re)creation of the dock; `resize` is also listened to. Updates are skipped when the layout is equal.
118
+ - **Hiding.** When the dock sets `data-controls-hidden="true"` (it does while the stack is expanded or a surface is open) the rails are not rendered.
119
+ - **Responsive.** The starter theme gives the rail `hidden sm:block`: below 640 px there are no rails. Change the theme slot, not the module, to alter that.
120
+ - **A rail is not rendered** if it has no entries, or if its computed height or width is `0`.
121
+ - **Accessibility.** Each rail is an `<aside>` labelled "Left page controls" / "Right page controls".
122
+ - **Pointer events.** The starter theme disables pointer events on the rail and re-enables them on the stack, so empty space never blocks the page.
123
+
124
+ ## 6. Theming
125
+
126
+ No classes or colors in the module apart from the measured position. Slots in `controlsTheme`: `rail` (fixed container) and `stack` (the column; reads `data-side="left|right"`), plus optional per-slot `styles` (the starter theme puts `Z_INDEX.DOCK` on `rail`). The module has no `motion.ts`; animate your own buttons with the shared motion tokens ([Rule 4](../architecture-and-rules.md)).
127
+
128
+ ## 7. Recipes and gotchas
129
+
130
+ | I want to… | Do this |
131
+ | :----------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- |
132
+ | A single control on one side | Not supported alone: add a matching entry (even a spacer element) on the other side with the same `order`. |
133
+ | Different controls per page | Call `usePage({ controls })` on each page; entries are tied to the pathname and removed immediately when the page unmounts. |
134
+ | Controls only while a component is mounted | `useControls({ left, right })` inside it. |
135
+ | Move the anchor | Put `data-controls-anchor="true"` on the element the rails should hug. |
136
+ | Show controls on phones | Override `rail` in the theme (remove `hidden sm:block`). |
137
+
138
+ - A pair is `left` + `right` **with the same `order`**; a lone entry is silently dropped.
139
+ - Entries registered for another `path` never show on this page, even when registered by a layout.
140
+ - `useControls` returns a layout object, not JSX: rendering is done by the overlay.
141
+
142
+ ## 8. File map
143
+
144
+ | File | Responsibility |
145
+ | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
146
+ | `index.ts` | Public barrel. |
147
+ | `types.ts` | Entries, slots, layout, definition and page-config contracts, theme slots. |
148
+ | `constants.ts` | Edge inset, dock gap, dock element id, side names, `controlsTheme`. |
149
+ | `utils.ts` | `resolveControlsPairs` (path filter, pairing, ordering), `getControlsLayout` (geometry), `areLayoutsEqual`, `validateControlEntry`, `normalizePageControls`. |
150
+ | `hooks.ts` | `useControlsLayout` (measurement + observers), `useControls`, `useControlsRegistration`, slot resolution, `useControlsModel`. |
151
+ | `overlay.tsx` | `Controls` and the side rail renderer. |
152
+ | `module.tsx` | `controlsModule`, page API (`set`), `defineControls`, kernel type augmentation. |
153
+
154
+ No `provider.tsx` or `motion.ts`: the module is stateless and does not animate ([README](./README.md#42-why-some-optional-slots-are-absent)).
155
+
156
+ ## 9. Dependencies
157
+
158
+ - **Uses:** `@omerdlw/base-framework/kernel` (`defineModule`, `useModuleRegistration`, `useRegistryEntries`), `@omerdlw/base-framework/utils`, `@omerdlw/base-framework/theme`, `next/navigation`. It knows the dock **only** through the DOM id `dock-card-stack` (and its `data-controls-hidden` attribute).
159
+ - **Used by:** `src/core/provider.tsx` (installs it) and `page.modules.controls`.