@mt-gloss/ui 0.1.113 → 0.1.115

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.
@@ -1,538 +0,0 @@
1
- import { jsx as c, jsxs as E } from "react/jsx-runtime";
2
- import { motion as L } from "framer-motion";
3
- import { useSyncExternalStore as O, createContext as T, useContext as y, useReducer as N, useRef as C, useEffect as d, useMemo as S, useCallback as I, useLayoutEffect as _, useState as w } from "react";
4
- import { z as f } from "zod";
5
- const x = "(prefers-reduced-motion: reduce)";
6
- function b() {
7
- return typeof window > "u" || typeof window.matchMedia != "function" ? null : window.matchMedia(x);
8
- }
9
- function H(e) {
10
- const n = b();
11
- return n ? (n.addEventListener("change", e), () => {
12
- n.removeEventListener("change", e);
13
- }) : () => {
14
- };
15
- }
16
- function A() {
17
- const e = b();
18
- return e ? e.matches : !1;
19
- }
20
- function F() {
21
- return !1;
22
- }
23
- function P() {
24
- return O(H, A, F);
25
- }
26
- const R = {
27
- threshold: "Threshold",
28
- timeframe: "Timeframe",
29
- slots: "Slots",
30
- color: "Color"
31
- };
32
- function B({
33
- dimensions: e,
34
- activeTab: n,
35
- onSelect: t,
36
- reduced: r,
37
- labels: l,
38
- ariaLabel: a = "Settings dimensions"
39
- }) {
40
- const s = P(), i = r ?? s;
41
- if (e.length < 2) return null;
42
- const u = (o) => l?.[o] ?? R[o], h = (o, p) => {
43
- o.key === "ArrowRight" ? (o.preventDefault(), t(e[(p + 1) % e.length])) : o.key === "ArrowLeft" ? (o.preventDefault(), t(e[(p - 1 + e.length) % e.length])) : o.key === "Home" ? (o.preventDefault(), t(e[0])) : o.key === "End" && (o.preventDefault(), t(e[e.length - 1]));
44
- };
45
- return /* @__PURE__ */ c(
46
- "div",
47
- {
48
- role: "tablist",
49
- "aria-label": a,
50
- className: "settings-tab-strip",
51
- children: e.map((o, p) => {
52
- const g = n === o;
53
- return /* @__PURE__ */ E(
54
- "button",
55
- {
56
- role: "tab",
57
- type: "button",
58
- id: `settings-tab-${o}`,
59
- "aria-selected": g,
60
- "aria-controls": `settings-tabpanel-${o}`,
61
- tabIndex: g ? 0 : -1,
62
- className: `settings-tab-strip__tab${g ? " settings-tab-strip__tab--active" : ""}`,
63
- onClick: () => t(o),
64
- onKeyDown: (D) => h(D, p),
65
- children: [
66
- /* @__PURE__ */ c("span", { className: "settings-tab-strip__label", children: u(o) }),
67
- g && !i && /* @__PURE__ */ c(
68
- L.span,
69
- {
70
- layoutId: "settings-active-tab-indicator",
71
- "data-layout-id": "settings-active-tab-indicator",
72
- className: "settings-tab-strip__indicator",
73
- "aria-hidden": "true",
74
- transition: { type: "spring", stiffness: 380, damping: 30 }
75
- }
76
- )
77
- ]
78
- },
79
- o
80
- );
81
- })
82
- }
83
- );
84
- }
85
- B.displayName = "SettingsTabStrip";
86
- const v = T(null);
87
- function k() {
88
- const e = y(v);
89
- if (!e)
90
- throw new Error(
91
- "[panels] usePanelContext must be used inside <PanelProvider>. See @mt-gloss/ui/composites/panels."
92
- );
93
- return e;
94
- }
95
- function ie() {
96
- return y(v);
97
- }
98
- const M = f.number().min(0).max(100), U = f.number().min(7).max(90), V = f.enum(["#1d6fd8", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6"]), K = f.array(f.string().min(1)).max(3);
99
- function j(e, n) {
100
- if (e === "threshold") {
101
- const t = M.safeParse(n);
102
- return t.success ? t.data : 80;
103
- }
104
- if (e === "timeframe") {
105
- const t = U.safeParse(n);
106
- return t.success ? t.data : 30;
107
- }
108
- if (e === "accent") {
109
- const t = V.safeParse(n);
110
- return t.success ? t.data : null;
111
- }
112
- if (e === "slots") {
113
- const t = K.safeParse(n);
114
- return t.success ? t.data : [];
115
- }
116
- return n;
117
- }
118
- const q = {
119
- activePanelId: null,
120
- activeTrigger: null,
121
- bellCutoutOpen: !1,
122
- isDirty: !1,
123
- dirtySessionCount: 0,
124
- lockHint: null,
125
- bufferByCard: {},
126
- lastClose: null,
127
- pendingSideEffects: []
128
- }, m = /* @__PURE__ */ new Set(["settings"]);
129
- function z(e, n) {
130
- if (e == null || e.kind !== n.kind) return !1;
131
- switch (e.kind) {
132
- case "bell":
133
- return !0;
134
- case "card-overflow":
135
- return e.cardId === n.cardId && e.sectionIndex === n.sectionIndex && e.action === n.action;
136
- case "empty-cell":
137
- return e.sectionIndex === n.sectionIndex && e.cellPosition.row === n.cellPosition.row && e.cellPosition.col === n.cellPosition.col;
138
- case "manage-pages-action":
139
- return e.global === n.global && e.align === n.align;
140
- case "layout-action-blocked":
141
- return e.action === n.action && e.blockedCardId === n.blockedCardId && e.activeCardId === n.activeCardId;
142
- }
143
- }
144
- function Y(e, n) {
145
- switch (n.type) {
146
- case "OPEN_PANEL": {
147
- if (e.activePanelId && e.isDirty)
148
- return {
149
- ...e,
150
- pendingSideEffects: [
151
- ...e.pendingSideEffects,
152
- {
153
- type: "SET_LOCK_HINT",
154
- hint: {
155
- blockedTrigger: n.trigger,
156
- activeCardId: e.activeTrigger?.cardId ?? null,
157
- expiresAt: Date.now() + 4e3
158
- }
159
- }
160
- ]
161
- };
162
- if (e.activePanelId === n.panelId && z(e.activeTrigger, n.trigger))
163
- return e;
164
- const t = e.activePanelId != null ? [
165
- {
166
- type: "HANDOFF_CLOSE",
167
- reason: "mutex-handoff",
168
- previousPanelId: e.activePanelId
169
- }
170
- ] : [], r = n.panelId === "notification-center" && e.bellCutoutOpen;
171
- return {
172
- ...e,
173
- activePanelId: n.panelId,
174
- activeTrigger: n.trigger,
175
- isDirty: !1,
176
- dirtySessionCount: 0,
177
- // Phase 16 P2 CC-17 — fresh open starts a clean session
178
- bellCutoutOpen: r ? !1 : e.bellCutoutOpen,
179
- lastClose: null,
180
- // reset on fresh open
181
- pendingSideEffects: [...e.pendingSideEffects, ...t]
182
- };
183
- }
184
- case "CLOSE_PANEL": {
185
- if (e.activePanelId == null)
186
- return e;
187
- const t = e.activePanelId, r = e.activeTrigger?.cardId ?? null, l = r != null ? e.bufferByCard[r] : void 0, a = e.isDirty ? n.reason === "apply-button" ? r != null && l != null ? [
188
- {
189
- type: "COMMIT_BUFFER",
190
- payload: { cardId: r, delta: l }
191
- }
192
- ] : [{ type: "COMMIT_BUFFER" }] : [{ type: "DISCARD_BUFFER" }] : [], s = r != null && l != null ? (() => {
193
- const i = { ...e.bufferByCard };
194
- return delete i[r], i;
195
- })() : e.bufferByCard;
196
- return {
197
- ...e,
198
- activePanelId: null,
199
- activeTrigger: null,
200
- isDirty: !1,
201
- dirtySessionCount: 0,
202
- // Phase 16 P2 CC-17 — session ends on panel close (apply or discard)
203
- lockHint: null,
204
- // closing clears any active lockHint (dirty-buffer condition gone)
205
- bufferByCard: s,
206
- lastClose: { panelId: t, reason: n.reason },
207
- pendingSideEffects: [...e.pendingSideEffects, ...a]
208
- };
209
- }
210
- case "OPEN_BELL_CUTOUT":
211
- return e.bellCutoutOpen ? e : e.activePanelId === "notification-center" ? {
212
- ...e,
213
- activePanelId: null,
214
- activeTrigger: null,
215
- bellCutoutOpen: !0,
216
- pendingSideEffects: [
217
- ...e.pendingSideEffects,
218
- { type: "AUTO_CLOSE_NOTIF_CENTER" }
219
- ]
220
- } : { ...e, bellCutoutOpen: !0 };
221
- case "CLOSE_BELL_CUTOUT":
222
- return e.bellCutoutOpen ? { ...e, bellCutoutOpen: !1 } : e;
223
- case "SET_BUFFER_VALUE": {
224
- if (e.activePanelId == null || !m.has(e.activePanelId))
225
- return {
226
- ...e,
227
- pendingSideEffects: [
228
- ...e.pendingSideEffects,
229
- { type: "INVALID_DISPATCH", reason: "no-buffer-panel" }
230
- ]
231
- };
232
- const t = e.bufferByCard[n.cardId], r = t == null, l = j(n.key, n.value);
233
- if (!r && t.changes[n.key] === l)
234
- return e;
235
- const s = { kind: "settings", changes: {
236
- ...t?.kind === "settings" ? t.changes : {},
237
- [n.key]: l
238
- } }, i = { ...e.bufferByCard, [n.cardId]: s }, u = r ? [
239
- {
240
- type: "SCHEDULE_TIMER",
241
- ms: 0,
242
- action: { type: "BUFFER_BECOMES_DIRTY" }
243
- }
244
- ] : [];
245
- return {
246
- ...e,
247
- bufferByCard: i,
248
- pendingSideEffects: [...e.pendingSideEffects, ...u]
249
- };
250
- }
251
- case "CLEAR_BUFFER": {
252
- if (e.bufferByCard[n.cardId] == null)
253
- return e;
254
- const r = Object.keys(e.bufferByCard).length === 1, l = { ...e.bufferByCard };
255
- delete l[n.cardId];
256
- const a = r && e.isDirty ? [
257
- {
258
- type: "SCHEDULE_TIMER",
259
- ms: 0,
260
- action: { type: "BUFFER_BECOMES_CLEAN" }
261
- }
262
- ] : [];
263
- return {
264
- ...e,
265
- bufferByCard: l,
266
- pendingSideEffects: [...e.pendingSideEffects, ...a]
267
- };
268
- }
269
- case "BUFFER_BECOMES_DIRTY":
270
- return e.activePanelId == null || !m.has(e.activePanelId) ? {
271
- ...e,
272
- pendingSideEffects: [
273
- ...e.pendingSideEffects,
274
- { type: "INVALID_DISPATCH", reason: "no-buffer-panel" }
275
- ]
276
- } : e.isDirty ? e : { ...e, isDirty: !0, dirtySessionCount: e.dirtySessionCount + 1 };
277
- case "BUFFER_BECOMES_CLEAN":
278
- return e.isDirty ? { ...e, isDirty: !1, dirtySessionCount: 0 } : e;
279
- case "SET_LOCK_HINT":
280
- return {
281
- ...e,
282
- lockHint: n.hint,
283
- pendingSideEffects: [
284
- ...e.pendingSideEffects,
285
- {
286
- type: "SCHEDULE_TIMER",
287
- ms: Math.max(0, n.hint.expiresAt - Date.now()),
288
- action: { type: "CLEAR_LOCK_HINT" }
289
- }
290
- ]
291
- };
292
- case "CLEAR_LOCK_HINT":
293
- return e.lockHint == null ? e : { ...e, lockHint: null };
294
- case "DRAIN_SIDE_EFFECTS":
295
- return e.pendingSideEffects.length === 0 ? e : typeof n.count == "number" && n.count > 0 ? n.count >= e.pendingSideEffects.length ? { ...e, pendingSideEffects: [] } : {
296
- ...e,
297
- pendingSideEffects: e.pendingSideEffects.slice(n.count)
298
- } : {
299
- ...e,
300
- pendingSideEffects: []
301
- };
302
- default:
303
- return e;
304
- }
305
- }
306
- function $(e) {
307
- return e.activePanelId === "notification-center" ? "notif-center" : e.activePanelId != null && e.bellCutoutOpen ? e.isDirty ? "panel-dirty+cutout" : "panel-clean+cutout" : e.activePanelId != null ? e.isDirty ? "panel-dirty" : "panel-clean" : e.bellCutoutOpen ? "bell-cutout-only" : "idle";
308
- }
309
- function Q() {
310
- const [e, n] = N(Y, q), t = C([]), r = C(null);
311
- d(() => () => {
312
- r.current != null && (window.clearTimeout(r.current), r.current = null);
313
- }, []), d(() => {
314
- const s = e.pendingSideEffects.length;
315
- if (s !== 0) {
316
- for (const i of e.pendingSideEffects)
317
- i.type === "SCHEDULE_TIMER" ? (r.current != null && window.clearTimeout(r.current), r.current = window.setTimeout(() => {
318
- r.current = null, n(i.action);
319
- }, Math.max(0, i.ms))) : i.type === "SET_LOCK_HINT" ? n({ type: "SET_LOCK_HINT", hint: i.hint }) : i.type === "HANDOFF_CLOSE" ? t.current = [
320
- ...t.current.slice(-99),
321
- {
322
- panelId: i.previousPanelId,
323
- reason: "mutex-handoff",
324
- at: Date.now(),
325
- note: "F22: mutex-handoff synthetic close-log entry"
326
- }
327
- ] : i.type === "INVALID_DISPATCH" && process.env.NODE_ENV !== "production" && console.warn("[panels] INVALID_DISPATCH:", i.reason);
328
- n({ type: "DRAIN_SIDE_EFFECTS", count: s });
329
- }
330
- }, [e.pendingSideEffects, n]), d(() => {
331
- if (!e.lastClose) return;
332
- const s = {
333
- panelId: e.lastClose.panelId,
334
- reason: e.lastClose.reason,
335
- at: Date.now(),
336
- note: e.lastClose.reason === "nav-escape-hatch" ? "F21: backdrop-click OR page-nav escape" : void 0
337
- };
338
- t.current = [
339
- ...t.current.slice(-99),
340
- s
341
- ];
342
- }, [e.lastClose]);
343
- const l = S(
344
- () => $(e),
345
- [e.activePanelId, e.bellCutoutOpen, e.isDirty]
346
- ), a = I(() => t.current.slice(), []);
347
- return { state: e, surfaceState: l, dispatch: n, getCloseLog: a };
348
- }
349
- function oe({ children: e }) {
350
- const n = Q(), t = S(
351
- () => n,
352
- // Re-publish only when one of the four coordinator fields changes identity.
353
- // dispatch + getCloseLog are stable. state + surfaceState change on dispatch.
354
- [n.state, n.surfaceState, n.dispatch, n.getCloseLog]
355
- );
356
- return /* @__PURE__ */ c(v.Provider, { value: t, children: e });
357
- }
358
- const W = {
359
- position: "relative",
360
- pointerEvents: "auto"
361
- };
362
- function G({ children: e, onClose: n, footer: t, title: r, variant: l = "default" }) {
363
- return /* @__PURE__ */ E(
364
- "div",
365
- {
366
- "data-chrome": "panel",
367
- "data-chrome-variant": l,
368
- role: "dialog",
369
- "aria-modal": "true",
370
- className: l === "merged-stage" ? "gloss-panel-chrome gloss-panel-chrome--merged-stage" : "gloss-panel-chrome",
371
- style: W,
372
- children: [
373
- /* @__PURE__ */ E("div", { className: "gloss-panel-chrome__header", children: [
374
- r != null && /* @__PURE__ */ c("span", { className: "gloss-panel-chrome__title", children: r }),
375
- /* @__PURE__ */ c(
376
- "button",
377
- {
378
- id: "panel-close",
379
- type: "button",
380
- "aria-label": "Close panel",
381
- className: "gloss-panel-chrome__close",
382
- onClick: n,
383
- children: "×"
384
- }
385
- )
386
- ] }),
387
- /* @__PURE__ */ c("div", { className: "gloss-panel-chrome__body", children: e }),
388
- t != null && /* @__PURE__ */ c("div", { className: "gloss-panel-chrome__footer", children: t })
389
- ]
390
- }
391
- );
392
- }
393
- function J(e) {
394
- if (process.env.NODE_ENV === "production" || !e || !e.parentElement) return;
395
- const n = e.parentElement, t = window.getComputedStyle(n);
396
- t.perspective === "none" && console.warn(
397
- "[PanelMount] §2.7 violation: parent of .gloss-panel-mount has perspective:none. Rotated mount will render flat. Parent:",
398
- n
399
- ), (t.overflow === "hidden" || t.overflowY === "hidden") && console.warn(
400
- "[PanelMount] §2.9 violation: parent of .gloss-panel-mount has overflow:hidden. Rising panel will be clipped. Parent:",
401
- n
402
- );
403
- }
404
- function X({ isOpen: e, children: n }) {
405
- const t = P(), r = C(null);
406
- _(() => {
407
- J(r.current);
408
- }, []);
409
- const [l, a] = w(!1);
410
- d(() => {
411
- if (!e) {
412
- a(!1);
413
- return;
414
- }
415
- const i = requestAnimationFrame(() => a(!0));
416
- return () => cancelAnimationFrame(i);
417
- }, [e]);
418
- const s = [
419
- "gloss-panel-mount",
420
- l ? "has-panel" : "",
421
- t ? "reduced-motion" : ""
422
- ].filter(Boolean).join(" ");
423
- return /* @__PURE__ */ c(
424
- "div",
425
- {
426
- ref: r,
427
- className: s,
428
- "data-mount": "panel",
429
- "data-open": e ? "true" : "false",
430
- children: n
431
- }
432
- );
433
- }
434
- const Z = {
435
- position: "fixed",
436
- top: 0,
437
- left: 0,
438
- right: 0,
439
- height: "var(--tb-h, 60px)",
440
- perspective: "var(--panel-perspective, 1500px)",
441
- perspectiveOrigin: "center bottom",
442
- overflow: "visible",
443
- pointerEvents: "none",
444
- zIndex: 55
445
- }, ee = {
446
- position: "fixed",
447
- top: "var(--tb-h, 60px)",
448
- left: 0,
449
- right: 0,
450
- bottom: 0,
451
- zIndex: 1,
452
- // CR-03 fix: pass-through tint — scrim is visual-only and must not intercept
453
- // grid card clicks. Click-outside / scrim-dismiss is handled via the onClick
454
- // on the div below, which still fires because pointer events on the element
455
- // itself are honoured when explicitly set; using 'none' prevents the invisible
456
- // overlay from swallowing clicks on underlying controls (same class as the
457
- // panel-wrapper-covers-grid-cards bug fixed at V2FeedbackSurface).
458
- pointerEvents: "none",
459
- background: "rgba(0, 0, 0, 0.04)"
460
- };
461
- function ae({ panelComponents: e }) {
462
- const { state: n, dispatch: t, getCloseLog: r } = k(), l = n.activePanelId ? e[n.activePanelId] : null;
463
- n.activePanelId && !l && process.env.NODE_ENV !== "production" && console.error(
464
- "[panels] No panel component registered for activePanelId:",
465
- n.activePanelId
466
- ), d(() => {
467
- if (n.activePanelId == null) return;
468
- function u(h) {
469
- h.key === "Escape" && t({ type: "CLOSE_PANEL", reason: "escape-key" });
470
- }
471
- return document.addEventListener("keydown", u), () => {
472
- document.removeEventListener("keydown", u);
473
- };
474
- }, [n.activePanelId, t]);
475
- const a = C(n);
476
- _(() => {
477
- a.current = n;
478
- }), d(() => {
479
- if (process.env.NODE_ENV === "production") return;
480
- const u = window;
481
- return u.__panelsHostHandle && console.warn("[panels] multiple PanelHost/PanelHostShell instances mounted; dev handle is unreliable"), u.__panelsHostHandle = {
482
- dispatch: t,
483
- getState: () => a.current,
484
- getCloseLog: r
485
- }, () => {
486
- u.__panelsHostHandle?.dispatch === t && delete u.__panelsHostHandle;
487
- };
488
- }, [t, r]);
489
- const s = I(() => {
490
- t({ type: "CLOSE_PANEL", reason: "nav-escape-hatch" });
491
- }, [t]), i = n.activePanelId != null && l != null;
492
- return /* @__PURE__ */ E("div", { "data-panel-host": "true", style: Z, children: [
493
- i && /* @__PURE__ */ c(
494
- "div",
495
- {
496
- "data-panel-scrim": "true",
497
- style: ee,
498
- onClick: s
499
- }
500
- ),
501
- /* @__PURE__ */ c(X, { isOpen: i, children: i && /* @__PURE__ */ c(
502
- G,
503
- {
504
- isOpen: !0,
505
- onClose: () => t({ type: "CLOSE_PANEL", reason: "header-x" }),
506
- children: /* @__PURE__ */ c(l, { isOpen: !0 })
507
- }
508
- ) })
509
- ] });
510
- }
511
- const se = {
512
- "apply-button": !0,
513
- // the ONLY commit reason
514
- "cancel-button": !1,
515
- "header-x": !1,
516
- "escape-key": !1,
517
- "page-nav": !1,
518
- "mutex-handoff": !1,
519
- "ghost-anchor": !1,
520
- "viewport-collapse": !1,
521
- unmount: !1,
522
- "nav-escape-hatch": !1
523
- };
524
- export {
525
- se as C,
526
- oe as P,
527
- B as S,
528
- k as a,
529
- ae as b,
530
- G as c,
531
- Q as d,
532
- $ as e,
533
- P as f,
534
- X as g,
535
- q as i,
536
- Y as r,
537
- ie as u
538
- };