@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
@@ -1,1113 +1,7 @@
1
1
  "use client";
2
- import { createContext, isValidElement, createElement, useState, useEffect, useMemo, Fragment, useSyncExternalStore, use, useId, useCallback, useContext, useRef, useLayoutEffect, cloneElement, Children } from 'react';
3
- import { createPortal } from 'react-dom';
4
- import { usePathname } from 'next/navigation';
5
- import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
6
-
7
- // src/kernel/constants.ts
8
- var DEFAULT_SOURCE = "dynamic";
9
- var REGISTRY_SOURCES = Object.freeze({
10
- STATIC: "static",
11
- DYNAMIC: "dynamic",
12
- USER: "user"
13
- });
14
- var REGISTRY_LIFECYCLES = Object.freeze({
15
- IMMEDIATE: "immediate",
16
- GRACEFUL: "graceful",
17
- PERSISTENT: "persistent",
18
- ROUTE: "route"
19
- });
20
- var REGISTRY_VALIDATION_MODES = Object.freeze({
21
- WARN: "warn",
22
- STRICT: "strict"
23
- });
24
- var REGISTRY_METADATA_KEYS = Object.freeze([
25
- "cleanup",
26
- "cleanupDelayMs",
27
- "instanceId",
28
- "lifecycle",
29
- "priority",
30
- "source",
31
- "scope",
32
- "validation"
33
- ]);
34
- Object.freeze({
35
- [REGISTRY_SOURCES.STATIC]: 100,
36
- [REGISTRY_SOURCES.DYNAMIC]: 200,
37
- [REGISTRY_SOURCES.USER]: 300
38
- });
39
- Object.freeze({
40
- [REGISTRY_SOURCES.STATIC]: 10,
41
- [REGISTRY_SOURCES.DYNAMIC]: 20,
42
- [REGISTRY_SOURCES.USER]: 30
43
- });
44
- var REGISTRY_LIFECYCLE_VALUES = new Set(
45
- Object.values(REGISTRY_LIFECYCLES)
46
- );
47
- var REGISTRY_METADATA_KEY_SET = new Set(
48
- REGISTRY_METADATA_KEYS
49
- );
50
- var REGISTRY_SCOPE_KINDS = Object.freeze({
51
- APP: "app",
52
- SESSION: "session",
53
- ROUTE: "route",
54
- INSTANCE: "instance",
55
- WORKSPACE: "workspace"
56
- });
57
- REGISTRY_SCOPE_KINDS.APP;
58
- function getOrCreateGlobalContext(name, defaultValue) {
59
- const sym = /* @__PURE__ */ Symbol.for(`@omerdlw/base-framework/context/${name}`);
60
- const store = globalThis;
61
- if (!store[sym]) {
62
- store[sym] = createContext(defaultValue);
63
- }
64
- return store[sym];
65
- }
66
-
67
- // src/utils/string.ts
68
- function trimToNull(value) {
69
- if (value === null || value === void 0) return null;
70
- const trimmed = String(value).trim();
71
- return trimmed.length > 0 ? trimmed : null;
72
- }
73
-
74
- // src/utils/dom.ts
75
- var isBrowser = typeof window !== "undefined";
76
-
77
- // src/utils/number.ts
78
- function clamp(value, min, max) {
79
- const num = Number(value);
80
- const finite = Number.isFinite(num) ? num : min;
81
- return Math.min(Math.max(finite, min), max);
82
- }
83
- function toFiniteNumber(value, fallback = 0) {
84
- const parsed = Number(value);
85
- return Number.isFinite(parsed) ? parsed : fallback;
86
- }
87
-
88
- // src/utils/object.ts
89
- function isObject(value) {
90
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
91
- }
92
- function isPlainObject(value) {
93
- if (!isObject(value)) return false;
94
- const proto = Object.getPrototypeOf(value);
95
- return proto === Object.prototype || proto === null;
96
- }
97
- function report(scope, error, level = "error") {
98
- if (process.env.NODE_ENV === "production" && typeof window !== "undefined") {
99
- return;
100
- }
101
- console[level](`[${scope}]`, error);
102
- }
103
-
104
- // src/utils/store.ts
105
- function freezeStoreSnapshot(state) {
106
- if (process.env.NODE_ENV === "production" || !state || typeof state !== "object") {
107
- return state;
108
- }
109
- const seen = /* @__PURE__ */ new WeakSet();
110
- const freeze = (value) => {
111
- if (seen.has(value) || Object.isFrozen(value)) return;
112
- seen.add(value);
113
- const prototype = Object.getPrototypeOf(value);
114
- if (Array.isArray(value) || prototype === Object.prototype || prototype === null) {
115
- for (const key of Reflect.ownKeys(value)) {
116
- const descriptor = Object.getOwnPropertyDescriptor(value, key);
117
- if (descriptor && "value" in descriptor && descriptor.value !== null) {
118
- if (typeof descriptor.value === "object") freeze(descriptor.value);
119
- }
120
- }
121
- }
122
- Object.freeze(value);
123
- };
124
- freeze(state);
125
- return state;
126
- }
127
- function createStore(initialState, { freezeSnapshots = true } = {}) {
128
- const listeners = /* @__PURE__ */ new Set();
129
- const prepare = freezeSnapshots ? freezeStoreSnapshot : (state) => state;
130
- let snapshot = prepare(initialState);
131
- const publish = (nextStateOrUpdater) => {
132
- const nextState = typeof nextStateOrUpdater === "function" ? nextStateOrUpdater(snapshot) : nextStateOrUpdater;
133
- if (Object.is(snapshot, nextState)) return false;
134
- snapshot = prepare(nextState);
135
- for (const listener of listeners) {
136
- try {
137
- listener();
138
- } catch (error) {
139
- report("CoreStore subscriber", error, "warn");
140
- }
141
- }
142
- return true;
143
- };
144
- const setState = (updater) => {
145
- if (typeof updater === "function") {
146
- return publish(updater);
147
- }
148
- if (snapshot && typeof snapshot === "object" && updater && typeof updater === "object") {
149
- return publish({ ...snapshot, ...updater });
150
- }
151
- return publish(updater);
152
- };
153
- return Object.freeze({
154
- getSnapshot() {
155
- return snapshot;
156
- },
157
- publish,
158
- setState,
159
- subscribe(listener) {
160
- if (typeof listener !== "function") return () => {
161
- };
162
- listeners.add(listener);
163
- return () => listeners.delete(listener);
164
- }
165
- });
166
- }
167
-
168
- // src/kernel/utils.ts
169
- function parseFiniteNumber(value) {
170
- const parsed = Number(value);
171
- return Number.isFinite(parsed) ? parsed : null;
172
- }
173
- function getValidString(value, fallback = null) {
174
- return trimToNull(value) ?? fallback;
175
- }
176
-
177
- // src/kernel/schema.ts
178
- function resolveLifecycle(metadata, fallback) {
179
- const lifecycle = metadata?.lifecycle ?? metadata?.cleanup;
180
- return lifecycle && REGISTRY_LIFECYCLE_VALUES.has(lifecycle) ? lifecycle : fallback;
181
- }
182
- function validateRegistryMetadata(metadata) {
183
- if (metadata === void 0 || metadata === null)
184
- return { issues: [], valid: true };
185
- if (!isObject(metadata))
186
- return { issues: ["registry metadata must be an object"], valid: false };
187
- const issues = [];
188
- Object.keys(metadata).forEach((key) => {
189
- if (!REGISTRY_METADATA_KEY_SET.has(key))
190
- issues.push(`unknown registry metadata field: ${key}`);
191
- });
192
- if (metadata.source !== void 0 && !getValidString(metadata.source))
193
- issues.push("source must be a non-empty string");
194
- if (metadata.instanceId !== void 0 && !getValidString(metadata.instanceId))
195
- issues.push("instanceId must be a non-empty string");
196
- if (metadata.scope !== void 0 && !getValidString(metadata.scope))
197
- issues.push("scope must be a non-empty string");
198
- if (metadata.priority !== void 0 && parseFiniteNumber(metadata.priority) === null)
199
- issues.push("priority must be a finite number");
200
- if (metadata.cleanupDelayMs !== void 0) {
201
- const delay = parseFiniteNumber(metadata.cleanupDelayMs);
202
- if (delay === null || delay < 0)
203
- issues.push("cleanupDelayMs must be a non-negative finite number");
204
- }
205
- const lifecycle = metadata.lifecycle ?? metadata.cleanup;
206
- if (lifecycle !== void 0 && !REGISTRY_LIFECYCLE_VALUES.has(String(lifecycle))) {
207
- issues.push(
208
- `lifecycle must be one of: ${[...REGISTRY_LIFECYCLE_VALUES].join(", ")}`
209
- );
210
- }
211
- if (metadata.validation !== void 0 && !Object.values(REGISTRY_VALIDATION_MODES).includes(
212
- metadata.validation
213
- )) {
214
- issues.push(
215
- `validation must be one of: ${Object.values(REGISTRY_VALIDATION_MODES).join(", ")}`
216
- );
217
- }
218
- return { issues, valid: issues.length === 0 };
219
- }
220
- function normalizeRegistryMetadata(metadata, {
221
- defaultCleanupDelayMs = null,
222
- defaultLifecycle = null,
223
- defaultSource = DEFAULT_SOURCE
224
- } = {}) {
225
- const registryMeta = isObject(metadata) ? metadata : {};
226
- const normalizedDefaultDelay = parseFiniteNumber(defaultCleanupDelayMs);
227
- const fallbackCleanupDelayMs = normalizedDefaultDelay !== null && normalizedDefaultDelay >= 0 ? normalizedDefaultDelay : null;
228
- const fallbackLifecycle = defaultLifecycle && REGISTRY_LIFECYCLE_VALUES.has(defaultLifecycle) ? defaultLifecycle : null;
229
- const source = getValidString(registryMeta.source) || getValidString(defaultSource, DEFAULT_SOURCE) || DEFAULT_SOURCE;
230
- const scope = getValidString(registryMeta.scope);
231
- const priority = parseFiniteNumber(registryMeta.priority);
232
- const lifecycle = resolveLifecycle(registryMeta, fallbackLifecycle);
233
- const validation = isValidationMode(registryMeta.validation) ? registryMeta.validation : null;
234
- const cleanupDelayCandidate = parseFiniteNumber(registryMeta.cleanupDelayMs);
235
- let cleanupDelayMs = cleanupDelayCandidate !== null && cleanupDelayCandidate >= 0 ? cleanupDelayCandidate : fallbackCleanupDelayMs;
236
- if (lifecycle === REGISTRY_LIFECYCLES.IMMEDIATE) {
237
- cleanupDelayMs = 0;
238
- } else if ((lifecycle === REGISTRY_LIFECYCLES.GRACEFUL || lifecycle === REGISTRY_LIFECYCLES.ROUTE) && cleanupDelayMs === null) {
239
- cleanupDelayMs = fallbackCleanupDelayMs;
240
- }
241
- return {
242
- cleanupDelayMs,
243
- lifecycle,
244
- priority,
245
- registerOptions: {
246
- ...priority !== null && { priority },
247
- ...validation === REGISTRY_VALIDATION_MODES.STRICT && { validation },
248
- ...scope && { scope }
249
- },
250
- source,
251
- ...scope && { scope },
252
- ...validation && { validation }
253
- };
254
- }
255
- function isValidationMode(value) {
256
- return Object.values(REGISTRY_VALIDATION_MODES).includes(value);
257
- }
258
- function pickRegistryMetadata(options) {
259
- if (!isObject(options)) return {};
260
- return Object.fromEntries(
261
- REGISTRY_METADATA_KEYS.filter((key) => options[key] !== void 0).map(
262
- (key) => [key, options[key]]
263
- )
264
- );
265
- }
266
- function useRequiredContext(context, hookName, providerName) {
267
- const value = use(context);
268
- if (value === null) {
269
- throw new Error(`${hookName} must be used within ${providerName}`);
270
- }
271
- return value;
272
- }
273
- var useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : useEffect;
274
- var RegistryContext = getOrCreateGlobalContext(
275
- "RegistryContext",
276
- null
277
- );
278
- function useRegistryActions() {
279
- return useRequiredContext(
280
- RegistryContext,
281
- "useRegistryActions",
282
- "RegistryProvider"
283
- ).actions;
284
- }
285
- function useRegistrySubscription() {
286
- return useRequiredContext(
287
- RegistryContext,
288
- "useRegistrySubscription",
289
- "RegistryProvider"
290
- ).subscription;
291
- }
292
- function useRegistryEntries(type) {
293
- const { getEntriesSnapshot, subscribe } = useRegistrySubscription();
294
- const subscribeToType = useCallback(
295
- (listener) => subscribe(type, null, listener),
296
- [subscribe, type]
297
- );
298
- const getEntries = useCallback(
299
- () => getEntriesSnapshot(type),
300
- [getEntriesSnapshot, type]
301
- );
302
- return useSyncExternalStore(subscribeToType, getEntries, getEntries);
303
- }
304
- var EMPTY_MODULES = Object.freeze([]);
305
- var ModuleHostContext = getOrCreateGlobalContext("ModuleHostContext", null);
306
- function selectModuleSlice(coreModule, config) {
307
- const slice = coreModule.page?.select ? coreModule.page.select(config) : config[coreModule.id];
308
- return slice ?? null;
309
- }
310
- function createModulePayload(modules, config, metadata = {}) {
311
- const payload = {};
312
- let hasSlices = false;
313
- for (const coreModule of modules) {
314
- if (!coreModule.page?.entries) continue;
315
- const slice = selectModuleSlice(coreModule, config);
316
- if (slice === null) continue;
317
- payload[coreModule.id] = slice;
318
- hasSlices = true;
319
- }
320
- if (!hasSlices) return null;
321
- return {
322
- ...payload,
323
- registry: {
324
- ...metadata,
325
- ...isObject(config.registry) ? config.registry : {}
326
- }
327
- };
328
- }
329
- function useInstalledModules() {
330
- return use(ModuleHostContext)?.modules ?? EMPTY_MODULES;
331
- }
332
-
333
- // src/kernel/handlers.ts
334
- function isPersistentLifecycle(lifecycle) {
335
- return lifecycle === REGISTRY_LIFECYCLES.PERSISTENT;
336
- }
337
- function runRegistrationBatch(context, executor) {
338
- return typeof context.batch === "function" ? context.batch(executor) : executor(context);
339
- }
340
- function createEntryCleanupKey(type, key, source, instanceId, scope) {
341
- return JSON.stringify([
342
- "entry",
343
- type,
344
- key,
345
- scope ?? null,
346
- source,
347
- instanceId
348
- ]);
349
- }
350
- function getCleanupScope(context) {
351
- return context?.cleanupScope || /* @__PURE__ */ new Map();
352
- }
353
- function clearCleanupTimer(scope, cleanupKey) {
354
- const lifecycle = scope.get(cleanupKey);
355
- if (!lifecycle) return;
356
- lifecycle.cancelled = true;
357
- if (lifecycle.timerId !== null) clearTimeout(lifecycle.timerId);
358
- scope.delete(cleanupKey);
359
- }
360
- function scheduleCleanup(scope, cleanupKey, callback, delayMs) {
361
- clearCleanupTimer(scope, cleanupKey);
362
- const lifecycle = {
363
- cancelled: false,
364
- timerId: null
365
- };
366
- lifecycle.timerId = setTimeout(() => {
367
- if (lifecycle.cancelled || scope.get(cleanupKey) !== lifecycle) return;
368
- scope.delete(cleanupKey);
369
- callback();
370
- }, delayMs);
371
- scope.set(cleanupKey, lifecycle);
372
- }
373
- function collectModuleRegistrations(coreModule, slice, pageMetadata, context) {
374
- const definition = coreModule.registry;
375
- const toEntries = coreModule.page?.entries;
376
- if (!definition || !toEntries || slice == null || slice === false) return [];
377
- const type = coreModule.id;
378
- const items = Array.isArray(slice) ? slice : [slice];
379
- const registrations = [];
380
- for (const item of items) {
381
- if (item == null || item === false) continue;
382
- const itemMetadata = isObject(item) && isObject(item.registry) ? item.registry : {};
383
- const metadata = { ...pageMetadata, ...itemMetadata };
384
- if (metadata.validation === "strict" && !validateRegistryMetadata(metadata).valid) {
385
- continue;
386
- }
387
- const payload = isObject(item) ? Object.fromEntries(
388
- Object.entries(item).filter(([key]) => key !== "registry")
389
- ) : item;
390
- const { cleanupDelayMs, lifecycle, registerOptions, scope, source } = normalizeRegistryMetadata(metadata, {
391
- defaultCleanupDelayMs: definition.cleanupDelayMs ?? null,
392
- defaultLifecycle: definition.lifecycle,
393
- defaultSource: DEFAULT_SOURCE
394
- });
395
- for (const { key, value } of toEntries(payload, context) ?? []) {
396
- const validation = definition.validate?.(value);
397
- if (validation && !validation.valid) {
398
- report(`Registry ${type} config is invalid`, validation.issues, "warn");
399
- continue;
400
- }
401
- registrations.push({
402
- cleanupDelayMs,
403
- cleanupKey: createEntryCleanupKey(
404
- type,
405
- key,
406
- source,
407
- context.instanceId,
408
- scope
409
- ),
410
- key,
411
- lifecycle,
412
- registerOptions,
413
- scope,
414
- source,
415
- type,
416
- value
417
- });
418
- }
419
- }
420
- return registrations;
421
- }
422
- var NO_CLEANUP = () => {
423
- };
424
- function applyRegistryConfig(config, context) {
425
- const modules = context.modules ?? [];
426
- if (!config || modules.length === 0) return NO_CLEANUP;
427
- const pageMetadata = isObject(config.registry) ? config.registry : {};
428
- const slices = config;
429
- const registrations = modules.flatMap((coreModule) => {
430
- try {
431
- return collectModuleRegistrations(
432
- coreModule,
433
- slices[coreModule.id],
434
- pageMetadata,
435
- context
436
- );
437
- } catch (error) {
438
- report(`Registry apply (${coreModule.id})`, error);
439
- return [];
440
- }
441
- });
442
- if (registrations.length === 0) return NO_CLEANUP;
443
- const cleanupScope = getCleanupScope(context);
444
- const owner = (registration) => ({
445
- instanceId: context.instanceId,
446
- scope: registration.scope,
447
- source: registration.source
448
- });
449
- runRegistrationBatch(context, (queue) => {
450
- registrations.forEach(
451
- ({ cleanupKey, key, registerOptions, source, type, value }) => {
452
- clearCleanupTimer(cleanupScope, cleanupKey);
453
- queue.register(type, key, value, source, registerOptions);
454
- }
455
- );
456
- });
457
- return () => {
458
- const immediate = [];
459
- registrations.forEach((registration) => {
460
- if (isPersistentLifecycle(registration.lifecycle)) return;
461
- const { cleanupDelayMs, cleanupKey, key, type } = registration;
462
- if (typeof cleanupDelayMs === "number" && cleanupDelayMs > 0) {
463
- scheduleCleanup(
464
- cleanupScope,
465
- cleanupKey,
466
- () => context.unregister(type, key, owner(registration)),
467
- cleanupDelayMs
468
- );
469
- } else {
470
- immediate.push(registration);
471
- }
472
- });
473
- if (immediate.length === 0) return;
474
- runRegistrationBatch(context, (queue) => {
475
- immediate.forEach(
476
- (registration) => queue.unregister(
477
- registration.type,
478
- registration.key,
479
- owner(registration)
480
- )
481
- );
482
- });
483
- };
484
- }
485
-
486
- // src/kernel/hooks.ts
487
- function withInstanceId(instanceId, sourceOrOptions, optionsArg) {
488
- if (typeof sourceOrOptions === "string") {
489
- return {
490
- optionsArg: { ...isObject(optionsArg) ? optionsArg : {}, instanceId },
491
- sourceOrOptions
492
- };
493
- }
494
- if (isObject(sourceOrOptions)) {
495
- return {
496
- optionsArg,
497
- sourceOrOptions: { ...sourceOrOptions, instanceId }
498
- };
499
- }
500
- return {
501
- optionsArg: void 0,
502
- sourceOrOptions: {
503
- ...isObject(optionsArg) ? optionsArg : {},
504
- instanceId
505
- }
506
- };
507
- }
508
- function withInstanceIdForUnregister(instanceId, sourceOrOptions) {
509
- if (typeof sourceOrOptions === "string") {
510
- return { instanceId, source: sourceOrOptions };
511
- }
512
- if (isObject(sourceOrOptions)) {
513
- return { ...sourceOrOptions, instanceId };
514
- }
515
- return { instanceId };
516
- }
517
- function resolveRegisterArgsWithInstance(instanceId, sourceOrOptions, optionsArg) {
518
- const input = withInstanceId(instanceId, sourceOrOptions, optionsArg);
519
- return [input.sourceOrOptions, input.optionsArg];
520
- }
521
- var MAX_STABILIZATION_DEPTH = 64;
522
- function createStableFunctionEntry(fn) {
523
- const entry = {
524
- current: fn,
525
- stable(...args) {
526
- return entry.current?.apply(this, args);
527
- }
528
- };
529
- return entry;
530
- }
531
- function isDirectRegistryComponentPath(path, componentSlices) {
532
- const match = /^config\.([^.[]+)\.[^.[]+$/.exec(path);
533
- return Boolean(match && componentSlices.has(match[1]));
534
- }
535
- function isReactNodeLike(value) {
536
- return value === null || value === void 0 || typeof value === "boolean" || typeof value === "string" || typeof value === "number" || isValidElement(value);
537
- }
538
- function isStabilizableObject(value) {
539
- return typeof value === "object" && value !== null && !Array.isArray(value) && !isValidElement(value);
540
- }
541
- function hasSameObjectKeys(previousValue, nextValue) {
542
- if (!isStabilizableObject(previousValue) || !isStabilizableObject(nextValue)) {
543
- return false;
544
- }
545
- const previousKeys = Object.keys(previousValue);
546
- const nextKeys = Object.keys(nextValue);
547
- if (previousKeys.length !== nextKeys.length) return false;
548
- return nextKeys.every(
549
- (key) => Object.prototype.hasOwnProperty.call(previousValue, key)
550
- );
551
- }
552
- function stabilizeRegistryValue(value, path, scope, previousValue, seen = /* @__PURE__ */ new WeakSet(), depth = 0) {
553
- if (depth > MAX_STABILIZATION_DEPTH) return value;
554
- if (typeof value === "function") {
555
- const isComponent = value.name && /^[A-Z]/.test(value.name);
556
- if (isComponent || isDirectRegistryComponentPath(path, scope.componentSlices)) {
557
- return value;
558
- }
559
- scope.usedPaths.add(path);
560
- let entry = scope.functionEntries.get(path);
561
- if (!entry) {
562
- entry = createStableFunctionEntry(value);
563
- scope.functionEntries.set(path, entry);
564
- } else {
565
- entry.current = value;
566
- }
567
- return entry.stable;
568
- }
569
- if (value && typeof value === "object") {
570
- if (seen.has(value)) return value;
571
- seen.add(value);
572
- }
573
- if (isValidElement(value)) {
574
- const nextProps = stabilizeRegistryValue(
575
- value.props,
576
- `${path}.props`,
577
- scope,
578
- isValidElement(previousValue) ? previousValue.props : void 0,
579
- seen,
580
- depth + 1
581
- );
582
- if (isValidElement(previousValue) && previousValue.type === value.type && previousValue.key === value.key && previousValue.props === nextProps) {
583
- return previousValue;
584
- }
585
- return cloneElement(value, nextProps);
586
- }
587
- if (Array.isArray(value)) {
588
- const nextValue = value.every(isReactNodeLike) ? Children.toArray(value) : value;
589
- const previousArray = Array.isArray(previousValue) ? previousValue : null;
590
- let hasChanged2 = !previousArray || previousArray.length !== nextValue.length;
591
- const stabilizedValue2 = nextValue.map((item, index) => {
592
- const nextItem = stabilizeRegistryValue(
593
- item,
594
- `${path}[${index}]`,
595
- scope,
596
- previousArray?.[index],
597
- seen,
598
- depth + 1
599
- );
600
- if (!previousArray || nextItem !== previousArray[index]) {
601
- hasChanged2 = true;
602
- }
603
- return nextItem;
604
- });
605
- return !hasChanged2 ? previousArray : stabilizedValue2;
606
- }
607
- if (typeof value !== "object" || value === null) {
608
- return value;
609
- }
610
- const source = value;
611
- const previousRecord = previousValue;
612
- const stabilizedValue = {};
613
- const canReusePrevious = hasSameObjectKeys(previousValue, value);
614
- let hasChanged = !canReusePrevious;
615
- Object.keys(source).forEach((key) => {
616
- const nextValue = stabilizeRegistryValue(
617
- source[key],
618
- `${path}.${key}`,
619
- scope,
620
- previousRecord?.[key],
621
- seen,
622
- depth + 1
623
- );
624
- stabilizedValue[key] = nextValue;
625
- if (!canReusePrevious || nextValue !== previousRecord?.[key]) {
626
- hasChanged = true;
627
- }
628
- });
629
- return !hasChanged ? previousValue : stabilizedValue;
630
- }
631
- function useAppliedRegistryConfig(payload, context, componentSlices) {
632
- const functionEntriesRef = useRef(/* @__PURE__ */ new Map());
633
- const appliedRef = useRef(null);
634
- useIsomorphicLayoutEffect(() => {
635
- const previous = appliedRef.current;
636
- if (previous && previous.payload === payload && previous.context === context) {
637
- return;
638
- }
639
- const functionEntries = functionEntriesRef.current;
640
- const usedPaths = /* @__PURE__ */ new Set();
641
- const config = stabilizeRegistryValue(
642
- payload,
643
- "config",
644
- { componentSlices, functionEntries, usedPaths },
645
- previous?.config
646
- );
647
- functionEntries.forEach((_entry, path) => {
648
- if (!usedPaths.has(path)) functionEntries.delete(path);
649
- });
650
- if (previous && previous.config === config && previous.context === context) {
651
- previous.payload = payload;
652
- return;
653
- }
654
- previous?.cleanup();
655
- appliedRef.current = {
656
- cleanup: applyRegistryConfig(config, context),
657
- config,
658
- context,
659
- payload
660
- };
661
- });
662
- useIsomorphicLayoutEffect(
663
- () => () => {
664
- appliedRef.current?.cleanup();
665
- appliedRef.current = null;
666
- },
667
- []
668
- );
669
- }
670
- function createRegistryApplyContext(actions, {
671
- cleanupScope = /* @__PURE__ */ new Map(),
672
- instanceId,
673
- modules = [],
674
- pathname
675
- }) {
676
- const stamp = (queue) => ({
677
- register: (type, key, item, sourceOrOptions, optionsArg) => queue.register(
678
- type,
679
- key,
680
- item,
681
- ...resolveRegisterArgsWithInstance(
682
- instanceId,
683
- sourceOrOptions,
684
- optionsArg
685
- )
686
- ),
687
- unregister: (type, key, sourceOrOptions) => queue.unregister(
688
- type,
689
- key,
690
- withInstanceIdForUnregister(instanceId, sourceOrOptions)
691
- )
692
- });
693
- return {
694
- ...stamp(actions),
695
- batch: (executor) => typeof executor === "function" ? actions.batch((queue) => executor(stamp(queue))) : 0,
696
- cleanupScope,
697
- instanceId,
698
- modules,
699
- pathname
700
- };
701
- }
702
- function useRegistry(config, metadata) {
703
- const { batch, register, unregister } = useRegistryActions();
704
- const pathname = usePathname();
705
- const modules = useInstalledModules();
706
- const instanceId = `registry-instance-${useId()}`;
707
- const [cleanupScope] = useState(
708
- () => /* @__PURE__ */ new Map()
709
- );
710
- const context = useMemo(
711
- () => createRegistryApplyContext(
712
- { batch, register, unregister },
713
- {
714
- cleanupScope,
715
- instanceId,
716
- modules,
717
- pathname
718
- }
719
- ),
720
- [batch, cleanupScope, instanceId, modules, pathname, register, unregister]
721
- );
722
- const payload = useMemo(
723
- () => config ? createModulePayload(modules, config, metadata) : null,
724
- [config, metadata, modules]
725
- );
726
- const componentSlices = useMemo(
727
- () => new Set(
728
- modules.filter(
729
- (coreModule) => coreModule.registry?.valueKind === "component"
730
- ).map((coreModule) => coreModule.id)
731
- ),
732
- [modules]
733
- );
734
- useAppliedRegistryConfig(payload, context, componentSlices);
735
- }
736
- function defineModule(coreModule) {
737
- return Object.freeze({ ...coreModule });
738
- }
739
- createStore(void 0);
740
-
741
- // src/kernel/adapters.ts
742
- function useModuleRegistration(id, value, options) {
743
- const coreModule = useInstalledModules().find(
744
- (candidate) => candidate.id === id
745
- );
746
- const config = coreModule && options?.enabled !== false && value != null ? { [id]: value } : null;
747
- useRegistry(config, pickRegistryMetadata(options));
748
- }
749
- function defineThemeSpec(id) {
750
- return Object.freeze({ id });
751
- }
752
- var EMPTY = /* @__PURE__ */ new Map();
753
- var ThemeContext = getOrCreateGlobalContext("ThemeContext", EMPTY);
754
- function useTheme(spec) {
755
- const config = useContext(ThemeContext).get(spec.id);
756
- if (!config) {
757
- throw new Error(
758
- `Theme "${spec.id}" is missing. Ensure its theme configuration is provided to <ThemeProvider themes={[...]}> (e.g. in src/config/ or your theme setup).`
759
- );
760
- }
761
- return {
762
- slots: config.slots,
763
- styles: config.styles ?? {}
764
- };
765
- }
766
-
767
- // src/modules/controls/constants.ts
768
- var CONTROLS_EDGE_INSET = 4;
769
- var CONTROLS_DOCK_GAP = 8;
770
- var CONTROLS_DOCK_ELEMENT_ID = "dock-card-stack";
771
- var CONTROL_SIDE_NAMES = Object.freeze(["left", "right"]);
772
- var controlsTheme = defineThemeSpec("controls");
773
- function isControlSide(value) {
774
- return CONTROL_SIDE_NAMES.includes(value);
775
- }
776
- function hasContent(content) {
777
- return content !== void 0 && content !== null && content !== false;
778
- }
779
- function isRenderable(value) {
780
- if (value === null || value === void 0 || ["boolean", "number", "string"].includes(typeof value) || isValidElement(value)) {
781
- return true;
782
- }
783
- return Array.isArray(value) && value.every(isRenderable);
784
- }
785
- function validateControlEntry(entry) {
786
- if (!isPlainObject(entry)) {
787
- return { issues: ["control must be a plain object"], valid: false };
788
- }
789
- const issues = [];
790
- if (!trimToNull(entry.id)) {
791
- issues.push("control id must be a non-empty string");
792
- }
793
- if (!isControlSide(entry.side)) {
794
- issues.push("control side must be left or right");
795
- }
796
- if (!hasContent(entry.content) || !isRenderable(entry.content)) {
797
- issues.push("control content must be renderable");
798
- }
799
- if (!Number.isFinite(Number(entry.order))) {
800
- issues.push("control order must be a finite number");
801
- }
802
- return { issues, valid: issues.length === 0 };
803
- }
804
- function resolveSlot(slot, props) {
805
- if (slot == null || slot === false) return null;
806
- if (isValidElement(slot)) return slot;
807
- if (typeof slot === "function") return createElement(slot, props);
808
- return slot;
809
- }
810
- function normalizePageControls(controls) {
811
- if (!controls) return null;
812
- if (Array.isArray(controls)) return controls;
813
- if ("side" in controls) return [controls];
814
- const { id = "controls", order = 0, path, registry } = controls;
815
- return CONTROL_SIDE_NAMES.flatMap((side) => {
816
- const content = controls[side];
817
- if (!hasContent(content)) return [];
818
- return [
819
- {
820
- ...registry ? { registry } : {},
821
- content,
822
- id: `${id}-${side}`,
823
- order,
824
- ...path ? { path } : {},
825
- side
826
- }
827
- ];
828
- });
829
- }
830
- function resolveControlsPairs(entries, pathname) {
831
- const rows = /* @__PURE__ */ new Map();
832
- for (const entry of Array.isArray(entries) ? entries : Object.values(entries || {})) {
833
- if (entry?.path !== pathname || !isControlSide(entry.side) || !hasContent(entry.content)) {
834
- continue;
835
- }
836
- const order = toFiniteNumber(entry.order);
837
- const row = rows.get(order) ?? {};
838
- rows.set(order, row);
839
- const current = row[entry.side];
840
- if (!current || String(entry.id).localeCompare(String(current.id)) < 0) {
841
- row[entry.side] = { content: entry.content, id: entry.id };
842
- }
843
- }
844
- const pairs = [...rows].sort(([a], [b]) => a - b).map(([, row]) => row).filter(
845
- (row) => Boolean(row.left && row.right)
846
- );
847
- return {
848
- left: pairs.map((row) => row.left),
849
- right: pairs.map((row) => row.right)
850
- };
851
- }
852
-
853
- // src/modules/controls/layout.ts
854
- function getControlsLayout(dockRect, viewport) {
855
- const { height, width } = viewport;
856
- if (!dockRect || width <= 0 || height <= 0) return null;
857
- const inset = CONTROLS_EDGE_INSET;
858
- const gap = CONTROLS_DOCK_GAP;
859
- const dockLeft = clamp(dockRect.left, 0, width);
860
- const dockRight = clamp(dockRect.right, dockLeft, width);
861
- const dockBottom = clamp(dockRect.bottom, 0, height);
862
- return {
863
- bottom: Math.max(0, height - dockBottom),
864
- height: Math.max(0, dockRect.height) / 2,
865
- left: {
866
- maxWidth: Math.max(0, dockLeft - inset * 2 - gap),
867
- right: Math.max(inset, width - dockLeft + gap)
868
- },
869
- right: {
870
- left: Math.min(width - inset, dockRight + gap),
871
- maxWidth: Math.max(0, width - dockRight - inset * 2 - gap)
872
- }
873
- };
874
- }
875
- function areLayoutsEqual(a, b) {
876
- if (a === b) return true;
877
- if (!a || !b) return false;
878
- return a.bottom === b.bottom && a.height === b.height && a.isHidden === b.isHidden && a.left.maxWidth === b.left.maxWidth && a.left.right === b.left.right && a.right.left === b.right.left && a.right.maxWidth === b.right.maxWidth;
879
- }
880
- function getDockStackElement() {
881
- return document.getElementById(CONTROLS_DOCK_ELEMENT_ID);
882
- }
883
- function getDockElement() {
884
- return document.querySelector('[data-controls-anchor="true"]') ?? getDockStackElement();
885
- }
886
- function measureLayout() {
887
- const dockElement = getDockElement();
888
- if (!dockElement) return null;
889
- const layout = getControlsLayout(dockElement.getBoundingClientRect(), {
890
- height: window.innerHeight,
891
- width: window.innerWidth
892
- });
893
- return layout && {
894
- ...layout,
895
- isHidden: getDockStackElement()?.dataset.controlsHidden === "true"
896
- };
897
- }
898
-
899
- // src/modules/controls/hooks.ts
900
- function useControlsLayout() {
901
- const [layout, setLayout] = useState(null);
902
- useEffect(() => {
903
- let observed;
904
- let resizeObserver;
905
- const update = () => {
906
- const next = measureLayout();
907
- setLayout((prev) => areLayoutsEqual(prev, next) ? prev : next);
908
- };
909
- const observe = () => {
910
- const dockElement = getDockElement();
911
- if (dockElement !== observed) {
912
- observed = dockElement;
913
- resizeObserver?.disconnect();
914
- mutationObserver.disconnect();
915
- if (dockElement) {
916
- if (typeof ResizeObserver !== "undefined") {
917
- resizeObserver = new ResizeObserver(update);
918
- resizeObserver.observe(dockElement);
919
- }
920
- mutationObserver.observe(dockElement, {
921
- attributes: true,
922
- attributeFilter: ["data-controls-anchor", "data-controls-hidden"]
923
- });
924
- if (dockElement.parentElement) {
925
- mutationObserver.observe(dockElement.parentElement, {
926
- childList: true
927
- });
928
- }
929
- } else {
930
- mutationObserver.observe(document.body, {
931
- childList: true,
932
- subtree: true
933
- });
934
- }
935
- }
936
- update();
937
- };
938
- const mutationObserver = new MutationObserver(observe);
939
- observe();
940
- window.addEventListener("resize", update);
941
- return () => {
942
- mutationObserver.disconnect();
943
- resizeObserver?.disconnect();
944
- window.removeEventListener("resize", update);
945
- };
946
- }, []);
947
- return layout;
948
- }
949
- function useControlsRegistration(config, options) {
950
- useModuleRegistration("controls", config, options);
951
- }
952
- function useControls(config, options) {
953
- const pathname = usePathname();
954
- const definitionPath = config && "path" in config ? config.path : void 0;
955
- const path = options?.path || definitionPath || pathname;
956
- const entries = useMemo(() => {
957
- if (!config) return null;
958
- if (Array.isArray(config) || "side" in config) return config;
959
- const { defaultProps = {}, left, right, ...page } = config;
960
- const resolved = normalizePageControls({
961
- ...page,
962
- left: resolveSlot(left, defaultProps),
963
- path,
964
- right: resolveSlot(right, defaultProps)
965
- });
966
- return resolved?.length ? resolved : null;
967
- }, [config, path]);
968
- useControlsRegistration(entries, options);
969
- return useControlsLayout();
970
- }
971
- var emptySubscribe = () => () => {
972
- };
973
- function useControlsModel() {
974
- const portalTarget = useSyncExternalStore(
975
- emptySubscribe,
976
- () => typeof document !== "undefined" ? document.body : null,
977
- () => null
978
- );
979
- const layout = useControlsLayout();
980
- const pathname = usePathname();
981
- const entries = useRegistryEntries("controls");
982
- const { left, right } = useMemo(
983
- () => resolveControlsPairs(entries, pathname),
984
- [entries, pathname]
985
- );
986
- const theme = useTheme(controlsTheme);
987
- return { portalTarget, layout, left, right, theme };
988
- }
989
- function ControlsSide({
990
- controls,
991
- geometry,
992
- side,
993
- theme
994
- }) {
995
- if (controls.length === 0 || !geometry.height || !geometry.maxWidth) {
996
- return null;
997
- }
998
- const positionStyle = side === "left" ? {
999
- bottom: geometry.bottom,
1000
- maxWidth: geometry.maxWidth,
1001
- right: geometry.right
1002
- } : {
1003
- bottom: geometry.bottom,
1004
- left: geometry.left,
1005
- maxWidth: geometry.maxWidth
1006
- };
1007
- return /* @__PURE__ */ jsx(
1008
- "aside",
1009
- {
1010
- "aria-label": `${side === "left" ? "Left" : "Right"} page controls`,
1011
- className: theme.slots.rail,
1012
- style: { ...theme.styles.rail, ...positionStyle },
1013
- children: /* @__PURE__ */ jsx(
1014
- "div",
1015
- {
1016
- "data-side": side,
1017
- className: theme.slots.stack,
1018
- style: {
1019
- ...theme.styles.stack,
1020
- "--controls-height": `${geometry.height}px`
1021
- },
1022
- children: controls.map(({ content, id }, index) => /* @__PURE__ */ jsx(Fragment, { children: content }, id || index))
1023
- }
1024
- )
1025
- }
1026
- );
1027
- }
1028
- function Controls() {
1029
- const { portalTarget, layout, left, right, theme } = useControlsModel();
1030
- if (!portalTarget || !layout || layout.isHidden || left.length === 0) {
1031
- return null;
1032
- }
1033
- return createPortal(
1034
- /* @__PURE__ */ jsxs(Fragment$1, { children: [
1035
- /* @__PURE__ */ jsx(
1036
- ControlsSide,
1037
- {
1038
- controls: left,
1039
- geometry: {
1040
- ...layout.left,
1041
- bottom: layout.bottom,
1042
- height: layout.height
1043
- },
1044
- side: "left",
1045
- theme
1046
- }
1047
- ),
1048
- /* @__PURE__ */ jsx(
1049
- ControlsSide,
1050
- {
1051
- controls: right,
1052
- geometry: {
1053
- ...layout.right,
1054
- bottom: layout.bottom,
1055
- height: layout.height
1056
- },
1057
- side: "right",
1058
- theme
1059
- }
1060
- )
1061
- ] }),
1062
- portalTarget
1063
- );
1064
- }
1065
- function selectPageControls(config) {
1066
- return normalizePageControls(config.controls);
1067
- }
1068
- function useControlsPage(_slice, page) {
1069
- return useMemo(
1070
- () => ({
1071
- set: (controls) => page.set({ controls })
1072
- }),
1073
- [page]
1074
- );
1075
- }
1076
- function defineControls(definition = {}) {
1077
- const { id = "controls", order = 0 } = definition;
1078
- return Object.freeze({
1079
- config: definition,
1080
- id,
1081
- order,
1082
- use: function useDefinedControls(props = {}, options = {}) {
1083
- return useControls(
1084
- {
1085
- ...definition,
1086
- defaultProps: { ...definition.defaultProps, ...props }
1087
- },
1088
- options
1089
- );
1090
- }
1091
- });
1092
- }
1093
- var controlsModule = defineModule({
1094
- id: "controls",
1095
- Overlay: Controls,
1096
- registry: {
1097
- keyPolicy: "named",
1098
- lifecycle: "immediate",
1099
- validate: validateControlEntry
1100
- },
1101
- page: {
1102
- select: selectPageControls,
1103
- entries: (entry, { pathname }) => {
1104
- const path = pathname || "/";
1105
- return [{ key: `${path}::${entry.id}`, value: { ...entry, path } }];
1106
- },
1107
- use: useControlsPage
1108
- }
1109
- });
1110
-
1111
- export { CONTROLS_DOCK_ELEMENT_ID, CONTROLS_DOCK_GAP, CONTROLS_EDGE_INSET, CONTROL_SIDE_NAMES, Controls, ControlsSide, areLayoutsEqual, controlsModule, controlsTheme, defineControls, getControlsLayout, getDockElement, getDockStackElement, hasContent, isControlSide, measureLayout, normalizePageControls, resolveControlsPairs, resolveSlot, useControls, useControlsLayout, useControlsRegistration, validateControlEntry };
2
+ export { CONTROLS_DOCK_ELEMENT_ID, CONTROLS_DOCK_GAP, CONTROLS_EDGE_INSET, CONTROL_SIDE_NAMES, Controls, ControlsSide, areLayoutsEqual, controlsModule, controlsTheme, defineControls, getControlsLayout, getDockElement, getDockStackElement, hasContent, isControlSide, measureLayout, normalizePageControls, resolveControlsPairs, resolveSlot, useControls, useControlsLayout, useControlsRegistration, validateControlEntry } from '../../chunk-4GMQKD6F.js';
3
+ import '../../chunk-7TAVYJ3A.js';
4
+ import '../../chunk-GF7TUX5I.js';
5
+ import '../../chunk-TV3WEF5G.js';
1112
6
  //# sourceMappingURL=index.js.map
1113
7
  //# sourceMappingURL=index.js.map