@almadar/ui 6.52.0 → 6.53.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 (64) hide show
  1. package/dist/{EntityBindingContext-BbxrwSb9.d.ts → AwaitingSkeletonContext-Bh399p1x.d.ts} +17 -2
  2. package/dist/{Canvas3DHost-CWO0tswb.d.ts → Canvas3DHost-B-y2TNij.d.ts} +1 -1
  3. package/dist/{GameAudioProvider-_hPzjqp-.d.ts → GameAudioProvider-DyBvYP2c.d.ts} +1 -1
  4. package/dist/Typography-7QEWUTW3.js +5 -0
  5. package/dist/{UISlotRenderer-CR7SCAMR.js → UISlotRenderer-P7A4SZSK.js} +10 -10
  6. package/dist/avl/index.cjs +40157 -39958
  7. package/dist/avl/index.d.ts +5 -2
  8. package/dist/avl/index.js +34 -21
  9. package/dist/{chunk-XUSSAWKL.js → chunk-2LFBQ4IS.js} +1 -1
  10. package/dist/{chunk-QWDKMVLX.js → chunk-53VTY5CC.js} +141 -82
  11. package/dist/{chunk-MSBMVG3B.js → chunk-6O37FCX4.js} +1 -0
  12. package/dist/{chunk-WB2A6V3I.js → chunk-7KSLPY56.js} +49 -1
  13. package/dist/{chunk-BHZG4PDZ.js → chunk-7LM6I3NA.js} +629 -626
  14. package/dist/{chunk-NCNP2RKZ.js → chunk-E37BYSXY.js} +2 -2
  15. package/dist/{chunk-5GCI6C7J.js → chunk-FUQASYEW.js} +2 -2
  16. package/dist/{chunk-CLSLVFSP.js → chunk-HB4C27KU.js} +2 -2
  17. package/dist/{chunk-EERAGPBW.js → chunk-HUG25TT3.js} +32341 -33067
  18. package/dist/{chunk-TWHYH25Q.js → chunk-JRW33U35.js} +80 -80
  19. package/dist/{chunk-G4GMXYMY.js → chunk-KQXXO42S.js} +93 -171
  20. package/dist/chunk-OKWD7LPO.js +80 -0
  21. package/dist/{chunk-YHY5K2Y7.js → chunk-PEST66PN.js} +6 -0
  22. package/dist/{chunk-V5AGW2JN.js → chunk-QVXLKFUQ.js} +1 -1
  23. package/dist/chunk-UOTYAPV5.js +284 -0
  24. package/dist/{chunk-2QB2PXOO.js → chunk-VHTJRS2N.js} +3 -5
  25. package/dist/components/index.cjs +42813 -42691
  26. package/dist/components/index.d.ts +182 -319
  27. package/dist/components/index.js +621 -13
  28. package/dist/context/index.cjs +8 -3
  29. package/dist/context/index.js +3 -3
  30. package/dist/hooks/index.cjs +56 -4
  31. package/dist/hooks/index.js +7 -7
  32. package/dist/lib/drawable/three/index.cjs +49 -1
  33. package/dist/lib/drawable/three/index.d.ts +5 -5
  34. package/dist/lib/drawable/three/index.js +7 -7
  35. package/dist/lib/index.cjs +50 -1
  36. package/dist/lib/index.d.ts +2 -2
  37. package/dist/lib/index.js +6 -5
  38. package/dist/locales/index.cjs +147 -3
  39. package/dist/locales/index.js +99 -3
  40. package/dist/{paintDispatch-DHo3WhaU.d.ts → paintDispatch-_6EhJCiL.d.ts} +3 -3
  41. package/dist/providers/index.cjs +35850 -35687
  42. package/dist/providers/index.d.ts +33 -8
  43. package/dist/providers/index.js +37 -13
  44. package/dist/renderer/index.cjs +6 -0
  45. package/dist/renderer/index.d.ts +1 -1
  46. package/dist/renderer/index.js +1 -1
  47. package/dist/runtime/index.cjs +42533 -42343
  48. package/dist/runtime/index.d.ts +4 -2
  49. package/dist/runtime/index.js +12 -12
  50. package/dist/ssr/index.cjs +377 -137
  51. package/dist/ssr/index.d.cts +5 -1
  52. package/dist/ssr/index.d.ts +5 -1
  53. package/dist/ssr/index.js +313 -73
  54. package/dist/{verificationRegistry-BYD3cVhS.d.ts → verificationRegistry-CD7Xb40L.d.ts} +1 -1
  55. package/locales/ar.json +49 -1
  56. package/locales/en.json +49 -1
  57. package/locales/sl.json +49 -1
  58. package/package.json +6 -6
  59. package/tailwind-preset.cjs +23 -0
  60. package/themes/_base.css +28 -8
  61. package/themes/_contract.md +5 -0
  62. package/dist/Typography-7FRZOS2H.js +0 -5
  63. package/dist/{avl-3d-context-DLteNEwu.d.ts → avl-3d-context-MAt_NuU9.d.ts} +3 -3
  64. package/dist/{chunk-IN3BVW2Z.js → chunk-64WACXM7.js} +14 -14
@@ -1,6 +1,25 @@
1
1
  import { useEventBus } from './chunk-6EV3OEBQ.js';
2
- import { createContext, useRef, useCallback, useState, useSyncExternalStore, useContext, useEffect, useMemo } from 'react';
2
+ import { createContext, useCallback, useSyncExternalStore, useRef, useState, useContext, useEffect, useMemo } from 'react';
3
3
 
4
+ function useMediaQuery(query) {
5
+ const subscribe = useCallback(
6
+ (onChange) => {
7
+ if (!hasMatchMedia()) return () => void 0;
8
+ const mql = window.matchMedia(query);
9
+ mql.addEventListener("change", onChange);
10
+ return () => mql.removeEventListener("change", onChange);
11
+ },
12
+ [query]
13
+ );
14
+ return useSyncExternalStore(
15
+ subscribe,
16
+ () => hasMatchMedia() && window.matchMedia(query).matches,
17
+ () => false
18
+ );
19
+ }
20
+ function hasMatchMedia() {
21
+ return typeof window !== "undefined" && typeof window.matchMedia === "function";
22
+ }
4
23
  var counts = /* @__PURE__ */ new Map();
5
24
  var keyListeners = /* @__PURE__ */ new Map();
6
25
  var seq = 0;
@@ -147,25 +166,6 @@ function useInfiniteScroll(onLoadMore, options = {}) {
147
166
  }, [rootMargin]);
148
167
  return { sentinelRef };
149
168
  }
150
- function useMediaQuery(query) {
151
- const subscribe = useCallback(
152
- (onChange) => {
153
- if (!hasMatchMedia()) return () => void 0;
154
- const mql = window.matchMedia(query);
155
- mql.addEventListener("change", onChange);
156
- return () => mql.removeEventListener("change", onChange);
157
- },
158
- [query]
159
- );
160
- return useSyncExternalStore(
161
- subscribe,
162
- () => hasMatchMedia() && window.matchMedia(query).matches,
163
- () => false
164
- );
165
- }
166
- function hasMatchMedia() {
167
- return typeof window !== "undefined" && typeof window.matchMedia === "function";
168
- }
169
169
 
170
170
  // hooks/usePrefersReducedMotion.ts
171
171
  function usePrefersReducedMotion() {
@@ -549,6 +549,66 @@ function parseQueryBinding(binding) {
549
549
  field: parts.length > 1 ? parts.slice(1).join(".") : void 0
550
550
  };
551
551
  }
552
+ function usePullToRefresh(onRefresh, options = {}) {
553
+ const { threshold = 60, maxPull = 120 } = options;
554
+ const [pullDistance, setPullDistance] = useState(0);
555
+ const [isPulling, setIsPulling] = useState(false);
556
+ const [isRefreshing, setIsRefreshing] = useState(false);
557
+ const startY = useRef(0);
558
+ const scrollTopRef = useRef(0);
559
+ const onTouchStart = useCallback((e) => {
560
+ const container = e.currentTarget;
561
+ scrollTopRef.current = container.scrollTop;
562
+ if (scrollTopRef.current <= 0) {
563
+ startY.current = e.touches[0].clientY;
564
+ setIsPulling(true);
565
+ }
566
+ }, []);
567
+ const onTouchMove = useCallback((e) => {
568
+ if (!isPulling || isRefreshing) return;
569
+ const container = e.currentTarget;
570
+ if (container.scrollTop > 0) {
571
+ setPullDistance(0);
572
+ return;
573
+ }
574
+ const dy = e.touches[0].clientY - startY.current;
575
+ if (dy > 0) {
576
+ const distance = Math.min(dy * 0.5, maxPull);
577
+ setPullDistance(distance);
578
+ }
579
+ }, [isPulling, isRefreshing, maxPull]);
580
+ const onTouchEnd = useCallback(() => {
581
+ if (!isPulling) return;
582
+ setIsPulling(false);
583
+ if (pullDistance >= threshold && !isRefreshing) {
584
+ setIsRefreshing(true);
585
+ setPullDistance(threshold);
586
+ onRefresh();
587
+ } else {
588
+ setPullDistance(0);
589
+ }
590
+ }, [isPulling, pullDistance, threshold, isRefreshing, onRefresh]);
591
+ const endRefresh = useCallback(() => {
592
+ setIsRefreshing(false);
593
+ setPullDistance(0);
594
+ }, []);
595
+ const containerProps = {
596
+ onTouchStart,
597
+ onTouchMove,
598
+ onTouchEnd,
599
+ style: {
600
+ transform: pullDistance > 0 ? `translateY(${pullDistance}px)` : void 0,
601
+ transition: isPulling ? "none" : "transform 300ms ease-out"
602
+ }
603
+ };
604
+ return {
605
+ pullDistance,
606
+ isPulling,
607
+ isRefreshing,
608
+ containerProps,
609
+ endRefresh
610
+ };
611
+ }
552
612
  function useDragReorder(initialItems, onReorder) {
553
613
  const [items, setItems] = useState(initialItems);
554
614
  const [dragIndex, setDragIndex] = useState(-1);
@@ -617,65 +677,5 @@ function useDragReorder(initialItems, onReorder) {
617
677
  getItemProps
618
678
  };
619
679
  }
620
- function usePullToRefresh(onRefresh, options = {}) {
621
- const { threshold = 60, maxPull = 120 } = options;
622
- const [pullDistance, setPullDistance] = useState(0);
623
- const [isPulling, setIsPulling] = useState(false);
624
- const [isRefreshing, setIsRefreshing] = useState(false);
625
- const startY = useRef(0);
626
- const scrollTopRef = useRef(0);
627
- const onTouchStart = useCallback((e) => {
628
- const container = e.currentTarget;
629
- scrollTopRef.current = container.scrollTop;
630
- if (scrollTopRef.current <= 0) {
631
- startY.current = e.touches[0].clientY;
632
- setIsPulling(true);
633
- }
634
- }, []);
635
- const onTouchMove = useCallback((e) => {
636
- if (!isPulling || isRefreshing) return;
637
- const container = e.currentTarget;
638
- if (container.scrollTop > 0) {
639
- setPullDistance(0);
640
- return;
641
- }
642
- const dy = e.touches[0].clientY - startY.current;
643
- if (dy > 0) {
644
- const distance = Math.min(dy * 0.5, maxPull);
645
- setPullDistance(distance);
646
- }
647
- }, [isPulling, isRefreshing, maxPull]);
648
- const onTouchEnd = useCallback(() => {
649
- if (!isPulling) return;
650
- setIsPulling(false);
651
- if (pullDistance >= threshold && !isRefreshing) {
652
- setIsRefreshing(true);
653
- setPullDistance(threshold);
654
- onRefresh();
655
- } else {
656
- setPullDistance(0);
657
- }
658
- }, [isPulling, pullDistance, threshold, isRefreshing, onRefresh]);
659
- const endRefresh = useCallback(() => {
660
- setIsRefreshing(false);
661
- setPullDistance(0);
662
- }, []);
663
- const containerProps = {
664
- onTouchStart,
665
- onTouchMove,
666
- onTouchEnd,
667
- style: {
668
- transform: pullDistance > 0 ? `translateY(${pullDistance}px)` : void 0,
669
- transition: isPulling ? "none" : "transform 300ms ease-out"
670
- }
671
- };
672
- return {
673
- pullDistance,
674
- isPulling,
675
- isRefreshing,
676
- containerProps,
677
- endRefresh
678
- };
679
- }
680
680
 
681
681
  export { ALMADAR_DND_MIME, PendingScopeContext, beginPending, endPending, parseQueryBinding, useAuthContext, useCanvasGestures, useDragReorder, useDraggable, useDropZone, useInfiniteScroll, useLongPress, useMediaQuery, usePendingAction, usePendingRows, usePendingScopeValue, usePrefersReducedMotion, usePullToRefresh, useQuerySingleton, useScopeHasPending, useSwipeGesture };
@@ -1,4 +1,4 @@
1
- import { domPassthrough, cn } from './chunk-IN3BVW2Z.js';
1
+ import { domPassthrough, cn } from './chunk-64WACXM7.js';
2
2
  import { useState, useRef, useCallback, useLayoutEffect, useEffect, useSyncExternalStore } from 'react';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
  import { ENTER_DELAY_STEPS, ENTER_ANIMATIONS, isFileValue } from '@almadar/core';
@@ -7,6 +7,86 @@ import { perfStore, pushPerfEntry } from '@almadar/runtime/ui';
7
7
  export { PERF_NAMESPACE, clearPerf, perfEnd, perfGauge, perfStart, perfTime, perfTimeAsync } from '@almadar/runtime/ui';
8
8
  import { createLogger, isLogLevelEnabled } from '@almadar/logger';
9
9
 
10
+ // lib/jazari/svg-paths.ts
11
+ function gearTeethPath(cx, cy, innerRadius, outerRadius, numTeeth) {
12
+ const parts = [];
13
+ const angleStep = Math.PI * 2 / numTeeth;
14
+ const halfTooth = angleStep * 0.25;
15
+ for (let i = 0; i < numTeeth; i++) {
16
+ const baseAngle = i * angleStep;
17
+ const x0 = cx + innerRadius * Math.cos(baseAngle - halfTooth);
18
+ const y0 = cy + innerRadius * Math.sin(baseAngle - halfTooth);
19
+ const x1 = cx + outerRadius * Math.cos(baseAngle - halfTooth * 0.4);
20
+ const y1 = cy + outerRadius * Math.sin(baseAngle - halfTooth * 0.4);
21
+ const x2 = cx + outerRadius * Math.cos(baseAngle + halfTooth * 0.4);
22
+ const y2 = cy + outerRadius * Math.sin(baseAngle + halfTooth * 0.4);
23
+ const x3 = cx + innerRadius * Math.cos(baseAngle + halfTooth);
24
+ const y3 = cy + innerRadius * Math.sin(baseAngle + halfTooth);
25
+ if (i === 0) {
26
+ parts.push(`M ${x0.toFixed(1)} ${y0.toFixed(1)}`);
27
+ } else {
28
+ parts.push(`L ${x0.toFixed(1)} ${y0.toFixed(1)}`);
29
+ }
30
+ parts.push(`L ${x1.toFixed(1)} ${y1.toFixed(1)}`);
31
+ parts.push(`L ${x2.toFixed(1)} ${y2.toFixed(1)}`);
32
+ parts.push(`L ${x3.toFixed(1)} ${y3.toFixed(1)}`);
33
+ }
34
+ parts.push("Z");
35
+ return parts.join(" ");
36
+ }
37
+ function lockIconPath(cx, cy, size) {
38
+ const bodyW = size * 0.7;
39
+ const bodyH = size * 0.5;
40
+ const bodyX = cx - bodyW / 2;
41
+ const bodyY = cy - bodyH / 4;
42
+ const body = `M ${bodyX.toFixed(1)} ${bodyY.toFixed(1)} h ${bodyW.toFixed(1)} v ${bodyH.toFixed(1)} h ${(-bodyW).toFixed(1)} Z`;
43
+ const shR = size * 0.28;
44
+ const shY = bodyY;
45
+ const shackle = `M ${(cx - shR).toFixed(1)} ${shY.toFixed(1)} A ${shR.toFixed(1)} ${(shR * 1.2).toFixed(1)} 0 1 1 ${(cx + shR).toFixed(1)} ${shY.toFixed(1)}`;
46
+ const kR = size * 0.08;
47
+ const kY = bodyY + bodyH * 0.35;
48
+ const keyhole = `M ${cx.toFixed(1)} ${(kY - kR).toFixed(1)} a ${kR.toFixed(1)} ${kR.toFixed(1)} 0 1 1 0 ${(kR * 2).toFixed(1)} a ${kR.toFixed(1)} ${kR.toFixed(1)} 0 1 1 0 ${(-kR * 2).toFixed(1)} Z`;
49
+ return `${body} ${shackle} ${keyhole}`;
50
+ }
51
+ function brainIconPath(cx, cy, size) {
52
+ const s = size / 2;
53
+ return [
54
+ `M ${cx.toFixed(1)} ${(cy - s).toFixed(1)}`,
55
+ `C ${(cx - s * 1.2).toFixed(1)} ${(cy - s).toFixed(1)}, ${(cx - s * 1.3).toFixed(1)} ${(cy + s * 0.3).toFixed(1)}, ${cx.toFixed(1)} ${(cy + s).toFixed(1)}`,
56
+ `C ${(cx + s * 1.3).toFixed(1)} ${(cy + s * 0.3).toFixed(1)}, ${(cx + s * 1.2).toFixed(1)} ${(cy - s).toFixed(1)}, ${cx.toFixed(1)} ${(cy - s).toFixed(1)}`,
57
+ "Z",
58
+ // Dividing line
59
+ `M ${cx.toFixed(1)} ${(cy - s * 0.8).toFixed(1)}`,
60
+ `C ${(cx - s * 0.2).toFixed(1)} ${(cy - s * 0.2).toFixed(1)}, ${(cx + s * 0.2).toFixed(1)} ${(cy + s * 0.2).toFixed(1)}, ${cx.toFixed(1)} ${(cy + s * 0.8).toFixed(1)}`
61
+ ].join(" ");
62
+ }
63
+ function pipeIconPath(cx, cy, size) {
64
+ const w = size * 0.6;
65
+ const h = size * 0.3;
66
+ const flangeW = size * 0.8;
67
+ const flangeH = size * 0.1;
68
+ const tube = `M ${(cx - w / 2).toFixed(1)} ${(cy - h / 2).toFixed(1)} h ${w.toFixed(1)} v ${h.toFixed(1)} h ${(-w).toFixed(1)} Z`;
69
+ const lf = `M ${(cx - flangeW / 2).toFixed(1)} ${(cy - h / 2 - flangeH).toFixed(1)} h ${flangeH.toFixed(1)} v ${(h + flangeH * 2).toFixed(1)} h ${(-flangeH).toFixed(1)} Z`;
70
+ const rf = `M ${(cx + flangeW / 2 - flangeH).toFixed(1)} ${(cy - h / 2 - flangeH).toFixed(1)} h ${flangeH.toFixed(1)} v ${(h + flangeH * 2).toFixed(1)} h ${(-flangeH).toFixed(1)} Z`;
71
+ return `${tube} ${lf} ${rf}`;
72
+ }
73
+ function eightPointedStarPath(cx, cy, outerR, innerR) {
74
+ const points = [];
75
+ const numPoints = 8;
76
+ const angleStep = Math.PI / numPoints;
77
+ for (let i = 0; i < numPoints * 2; i++) {
78
+ const angle = i * angleStep - Math.PI / 2;
79
+ const r = i % 2 === 0 ? outerR : innerR;
80
+ const x = cx + r * Math.cos(angle);
81
+ const y = cy + r * Math.sin(angle);
82
+ points.push(`${i === 0 ? "M" : "L"} ${x.toFixed(1)} ${y.toFixed(1)}`);
83
+ }
84
+ points.push("Z");
85
+ return points.join(" ");
86
+ }
87
+ function arrowheadPath(size) {
88
+ return `M 0 0 L ${size} ${size / 2} L 0 ${size} Z`;
89
+ }
10
90
  var SAFE_EXIT_MS = 1e3;
11
91
  var motionEnabledCache = null;
12
92
  function isMotionEnabled() {
@@ -98,98 +178,6 @@ function useSlotEnterRestart(ref, contentKey, active) {
98
178
  el.classList.add(ENTER_SLOT_CLASS);
99
179
  }, [contentKey, active, ref]);
100
180
  }
101
- function usePerfBuffer() {
102
- return useSyncExternalStore(perfStore.subscribe, perfStore.getSnapshot, perfStore.getSnapshot);
103
- }
104
- var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
105
- pushPerfEntry({
106
- name: `profiler:${id}:${phase}`,
107
- durationMs: actualDuration,
108
- ts: commitTime,
109
- detail: { baseDuration }
110
- });
111
- };
112
-
113
- // lib/jazari/svg-paths.ts
114
- function gearTeethPath(cx, cy, innerRadius, outerRadius, numTeeth) {
115
- const parts = [];
116
- const angleStep = Math.PI * 2 / numTeeth;
117
- const halfTooth = angleStep * 0.25;
118
- for (let i = 0; i < numTeeth; i++) {
119
- const baseAngle = i * angleStep;
120
- const x0 = cx + innerRadius * Math.cos(baseAngle - halfTooth);
121
- const y0 = cy + innerRadius * Math.sin(baseAngle - halfTooth);
122
- const x1 = cx + outerRadius * Math.cos(baseAngle - halfTooth * 0.4);
123
- const y1 = cy + outerRadius * Math.sin(baseAngle - halfTooth * 0.4);
124
- const x2 = cx + outerRadius * Math.cos(baseAngle + halfTooth * 0.4);
125
- const y2 = cy + outerRadius * Math.sin(baseAngle + halfTooth * 0.4);
126
- const x3 = cx + innerRadius * Math.cos(baseAngle + halfTooth);
127
- const y3 = cy + innerRadius * Math.sin(baseAngle + halfTooth);
128
- if (i === 0) {
129
- parts.push(`M ${x0.toFixed(1)} ${y0.toFixed(1)}`);
130
- } else {
131
- parts.push(`L ${x0.toFixed(1)} ${y0.toFixed(1)}`);
132
- }
133
- parts.push(`L ${x1.toFixed(1)} ${y1.toFixed(1)}`);
134
- parts.push(`L ${x2.toFixed(1)} ${y2.toFixed(1)}`);
135
- parts.push(`L ${x3.toFixed(1)} ${y3.toFixed(1)}`);
136
- }
137
- parts.push("Z");
138
- return parts.join(" ");
139
- }
140
- function lockIconPath(cx, cy, size) {
141
- const bodyW = size * 0.7;
142
- const bodyH = size * 0.5;
143
- const bodyX = cx - bodyW / 2;
144
- const bodyY = cy - bodyH / 4;
145
- const body = `M ${bodyX.toFixed(1)} ${bodyY.toFixed(1)} h ${bodyW.toFixed(1)} v ${bodyH.toFixed(1)} h ${(-bodyW).toFixed(1)} Z`;
146
- const shR = size * 0.28;
147
- const shY = bodyY;
148
- const shackle = `M ${(cx - shR).toFixed(1)} ${shY.toFixed(1)} A ${shR.toFixed(1)} ${(shR * 1.2).toFixed(1)} 0 1 1 ${(cx + shR).toFixed(1)} ${shY.toFixed(1)}`;
149
- const kR = size * 0.08;
150
- const kY = bodyY + bodyH * 0.35;
151
- const keyhole = `M ${cx.toFixed(1)} ${(kY - kR).toFixed(1)} a ${kR.toFixed(1)} ${kR.toFixed(1)} 0 1 1 0 ${(kR * 2).toFixed(1)} a ${kR.toFixed(1)} ${kR.toFixed(1)} 0 1 1 0 ${(-kR * 2).toFixed(1)} Z`;
152
- return `${body} ${shackle} ${keyhole}`;
153
- }
154
- function brainIconPath(cx, cy, size) {
155
- const s = size / 2;
156
- return [
157
- `M ${cx.toFixed(1)} ${(cy - s).toFixed(1)}`,
158
- `C ${(cx - s * 1.2).toFixed(1)} ${(cy - s).toFixed(1)}, ${(cx - s * 1.3).toFixed(1)} ${(cy + s * 0.3).toFixed(1)}, ${cx.toFixed(1)} ${(cy + s).toFixed(1)}`,
159
- `C ${(cx + s * 1.3).toFixed(1)} ${(cy + s * 0.3).toFixed(1)}, ${(cx + s * 1.2).toFixed(1)} ${(cy - s).toFixed(1)}, ${cx.toFixed(1)} ${(cy - s).toFixed(1)}`,
160
- "Z",
161
- // Dividing line
162
- `M ${cx.toFixed(1)} ${(cy - s * 0.8).toFixed(1)}`,
163
- `C ${(cx - s * 0.2).toFixed(1)} ${(cy - s * 0.2).toFixed(1)}, ${(cx + s * 0.2).toFixed(1)} ${(cy + s * 0.2).toFixed(1)}, ${cx.toFixed(1)} ${(cy + s * 0.8).toFixed(1)}`
164
- ].join(" ");
165
- }
166
- function pipeIconPath(cx, cy, size) {
167
- const w = size * 0.6;
168
- const h = size * 0.3;
169
- const flangeW = size * 0.8;
170
- const flangeH = size * 0.1;
171
- const tube = `M ${(cx - w / 2).toFixed(1)} ${(cy - h / 2).toFixed(1)} h ${w.toFixed(1)} v ${h.toFixed(1)} h ${(-w).toFixed(1)} Z`;
172
- const lf = `M ${(cx - flangeW / 2).toFixed(1)} ${(cy - h / 2 - flangeH).toFixed(1)} h ${flangeH.toFixed(1)} v ${(h + flangeH * 2).toFixed(1)} h ${(-flangeH).toFixed(1)} Z`;
173
- const rf = `M ${(cx + flangeW / 2 - flangeH).toFixed(1)} ${(cy - h / 2 - flangeH).toFixed(1)} h ${flangeH.toFixed(1)} v ${(h + flangeH * 2).toFixed(1)} h ${(-flangeH).toFixed(1)} Z`;
174
- return `${tube} ${lf} ${rf}`;
175
- }
176
- function eightPointedStarPath(cx, cy, outerR, innerR) {
177
- const points = [];
178
- const numPoints = 8;
179
- const angleStep = Math.PI / numPoints;
180
- for (let i = 0; i < numPoints * 2; i++) {
181
- const angle = i * angleStep - Math.PI / 2;
182
- const r = i % 2 === 0 ? outerR : innerR;
183
- const x = cx + r * Math.cos(angle);
184
- const y = cy + r * Math.sin(angle);
185
- points.push(`${i === 0 ? "M" : "L"} ${x.toFixed(1)} ${y.toFixed(1)}`);
186
- }
187
- points.push("Z");
188
- return points.join(" ");
189
- }
190
- function arrowheadPath(size) {
191
- return `M 0 0 L ${size} ${size / 2} L 0 ${size} Z`;
192
- }
193
181
 
194
182
  // lib/editorMotions.ts
195
183
  var EDITOR_MOTIONS = [
@@ -673,6 +661,17 @@ function middleSnake(a, aLo, aHi, b, bLo, bHi) {
673
661
  }
674
662
  throw new Error("computeLineDiff: no middle snake \u2014 unreachable for differing texts");
675
663
  }
664
+ function usePerfBuffer() {
665
+ return useSyncExternalStore(perfStore.subscribe, perfStore.getSnapshot, perfStore.getSnapshot);
666
+ }
667
+ var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
668
+ pushPerfEntry({
669
+ name: `profiler:${id}:${phase}`,
670
+ durationMs: actualDuration,
671
+ ts: commitTime,
672
+ detail: { baseDuration }
673
+ });
674
+ };
676
675
 
677
676
  // lib/lessonSegmentUtils.ts
678
677
  function parseMarkdownWithCodeBlocks(content) {
@@ -860,83 +859,6 @@ function toLogMetaValue(v) {
860
859
  return String(v);
861
860
  }
862
861
 
863
- // lib/parseLessonSegments.ts
864
- function extractTagContent(content, tagName) {
865
- const closedTagRegex = new RegExp(`<${tagName}>([\\s\\S]*?)<\\/${tagName}>`, "i");
866
- const closedMatch = content.match(closedTagRegex);
867
- if (closedMatch) {
868
- return { content: closedMatch[1].trim(), fullMatch: closedMatch[0] };
869
- }
870
- const unclosedTagRegex = new RegExp(
871
- `<${tagName}>([\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$)`,
872
- "i"
873
- );
874
- const unclosedMatch = content.match(unclosedTagRegex);
875
- if (unclosedMatch) {
876
- return { content: unclosedMatch[1].trim(), fullMatch: unclosedMatch[0] };
877
- }
878
- return null;
879
- }
880
- function parseLessonSegments(lesson) {
881
- if (!lesson) return [];
882
- let content = lesson.replace(/<prq>[\s\S]*?<\/prq>/gi, "").trim();
883
- const segments = [];
884
- const activateResult = extractTagContent(content, "activate");
885
- if (activateResult) {
886
- segments.push({ type: "activate", question: activateResult.content });
887
- content = content.replace(activateResult.fullMatch, "").trim();
888
- }
889
- const connectResult = extractTagContent(content, "connect");
890
- if (connectResult) {
891
- segments.push({ type: "connect", content: connectResult.content });
892
- content = content.replace(connectResult.fullMatch, "").trim();
893
- }
894
- const tagRegex = new RegExp(
895
- '(?<reflect><reflect>(?<reflectClosed>[\\s\\S]*?)<\\/reflect>)|(?<reflectUnclosed><reflect>(?<reflectOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<bloom><bloom\\s+level="(?<bloomLevel>remember|understand|apply|analyze|evaluate|create)">(?<bloomClosed>[\\s\\S]*?)<\\/bloom>)|(?<bloomUnclosed><bloom\\s+level="(?<bloomLevelUn>remember|understand|apply|analyze|evaluate|create)">(?<bloomOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<quiz><question>(?<quizQuestion>[\\s\\S]*?)<\\/question>\\s*<answer>(?<quizAnswer>[\\s\\S]*?)<\\/answer>)|(?<visualize><visualize\\s+type="(?<vizType>algorithms|math|physics|biology|chemistry|probability)"\\s+description="(?<vizDesc>[^"]*?)"\\s*\\/?>)',
896
- "gi"
897
- );
898
- let lastIndex = 0;
899
- let match;
900
- while ((match = tagRegex.exec(content)) !== null) {
901
- const before = content.slice(lastIndex, match.index);
902
- if (before.trim()) {
903
- segments.push(...parseMarkdownWithCodeBlocks(before));
904
- }
905
- const g = match.groups ?? {};
906
- if (g.reflect || g.reflectUnclosed) {
907
- const prompt = (g.reflectClosed ?? g.reflectOpen ?? "").trim();
908
- if (prompt) segments.push({ type: "reflect", prompt });
909
- } else if (g.bloom || g.bloomUnclosed) {
910
- const level = g.bloomLevel ?? g.bloomLevelUn;
911
- const bloomContent = g.bloomClosed ?? g.bloomOpen ?? "";
912
- if (level && bloomContent) {
913
- const qMatch = bloomContent.match(/<question>([\s\S]*?)<\/question>/i);
914
- const aMatch = bloomContent.match(/<answer>([\s\S]*?)<\/answer>/i);
915
- if (qMatch && aMatch) {
916
- segments.push({ type: "bloom", level, question: qMatch[1].trim(), answer: aMatch[1].trim() });
917
- } else if (qMatch) {
918
- segments.push({ type: "bloom", level, question: qMatch[1].trim(), answer: "(Answer not provided)" });
919
- } else {
920
- const clean = bloomContent.replace(/^\*\*Question\s*\d*:?\*\*\s*/i, "").replace(/^\*\*Q\d*:?\*\*\s*/i, "").trim();
921
- if (clean) segments.push({ type: "bloom", level, question: clean, answer: "(See answers section below)" });
922
- }
923
- }
924
- } else if (g.quiz) {
925
- segments.push({ type: "quiz", question: g.quizQuestion.trim(), answer: g.quizAnswer.trim() });
926
- } else if (g.visualize) {
927
- segments.push({
928
- type: "visualization",
929
- visualizationType: g.vizType,
930
- description: g.vizDesc ?? ""
931
- });
932
- }
933
- lastIndex = tagRegex.lastIndex;
934
- }
935
- const remaining = content.slice(lastIndex);
936
- if (remaining.trim()) segments.push(...parseMarkdownWithCodeBlocks(remaining));
937
- return segments;
938
- }
939
-
940
862
  // lib/traitRegistry.ts
941
863
  var traits = /* @__PURE__ */ new Map();
942
864
  var listeners = /* @__PURE__ */ new Set();
@@ -1196,4 +1118,4 @@ function initDebugShortcut() {
1196
1118
  return () => window.removeEventListener("keydown", handleKeyDown);
1197
1119
  }
1198
1120
 
1199
- export { EDITOR_MOTIONS, EDITOR_OPERATORS, ENTER_SLOT_CLASS, INDENT_UNIT, MAX_ENTER_DELAY, Presence, applyMotion, applyOperator, arrowheadPath, asEnterAnimation, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, computeLineDiff, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, enterClassName, gearTeethPath, getAllTicks, getAllTraits, getDebugEvents, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getRecentEvents, getRecentGuardEvaluations, getTick, getTrait, initDebugShortcut, isDebugEnabled, isDebugEnabled2, isEditorMotion, isEditorOperator, isMotionEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, motionRange, onDebugToggle, parseContentSegments, parseLessonSegments, parseMarkdownWithCodeBlocks, parseMarkdownWithCodeBlocks2, pipeIconPath, profilerOnRender, recordGuardEvaluation, registerTick, registerTrait, resolveImageUrl, setDebugEnabled, setEntityProvider, setTickActive, slotPlaysDefaultEnter, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, toggleDebug, unregisterTick, unregisterTrait, updateGuardResult, updateTickExecution, updateTraitState, usePerfBuffer, usePresence, useSlotEnterRestart };
1121
+ export { EDITOR_MOTIONS, EDITOR_OPERATORS, ENTER_SLOT_CLASS, INDENT_UNIT, MAX_ENTER_DELAY, Presence, applyMotion, applyOperator, arrowheadPath, asEnterAnimation, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, computeLineDiff, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, enterClassName, gearTeethPath, getAllTicks, getAllTraits, getDebugEvents, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getRecentEvents, getRecentGuardEvaluations, getTick, getTrait, initDebugShortcut, isDebugEnabled, isDebugEnabled2, isEditorMotion, isEditorOperator, isMotionEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, motionRange, onDebugToggle, parseContentSegments, parseMarkdownWithCodeBlocks, parseMarkdownWithCodeBlocks2, pipeIconPath, profilerOnRender, recordGuardEvaluation, registerTick, registerTrait, resolveImageUrl, setDebugEnabled, setEntityProvider, setTickActive, slotPlaysDefaultEnter, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, toggleDebug, unregisterTick, unregisterTrait, updateGuardResult, updateTickExecution, updateTraitState, usePerfBuffer, usePresence, useSlotEnterRestart };
@@ -0,0 +1,80 @@
1
+ import { parseMarkdownWithCodeBlocks } from './chunk-KQXXO42S.js';
2
+
3
+ // lib/parseLessonSegments.ts
4
+ function extractTagContent(content, tagName) {
5
+ const closedTagRegex = new RegExp(`<${tagName}>([\\s\\S]*?)<\\/${tagName}>`, "i");
6
+ const closedMatch = content.match(closedTagRegex);
7
+ if (closedMatch) {
8
+ return { content: closedMatch[1].trim(), fullMatch: closedMatch[0] };
9
+ }
10
+ const unclosedTagRegex = new RegExp(
11
+ `<${tagName}>([\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$)`,
12
+ "i"
13
+ );
14
+ const unclosedMatch = content.match(unclosedTagRegex);
15
+ if (unclosedMatch) {
16
+ return { content: unclosedMatch[1].trim(), fullMatch: unclosedMatch[0] };
17
+ }
18
+ return null;
19
+ }
20
+ function parseLessonSegments(lesson) {
21
+ if (!lesson) return [];
22
+ let content = lesson.replace(/<prq>[\s\S]*?<\/prq>/gi, "").trim();
23
+ const segments = [];
24
+ const activateResult = extractTagContent(content, "activate");
25
+ if (activateResult) {
26
+ segments.push({ type: "activate", question: activateResult.content });
27
+ content = content.replace(activateResult.fullMatch, "").trim();
28
+ }
29
+ const connectResult = extractTagContent(content, "connect");
30
+ if (connectResult) {
31
+ segments.push({ type: "connect", content: connectResult.content });
32
+ content = content.replace(connectResult.fullMatch, "").trim();
33
+ }
34
+ const tagRegex = new RegExp(
35
+ '(?<reflect><reflect>(?<reflectClosed>[\\s\\S]*?)<\\/reflect>)|(?<reflectUnclosed><reflect>(?<reflectOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<bloom><bloom\\s+level="(?<bloomLevel>remember|understand|apply|analyze|evaluate|create)">(?<bloomClosed>[\\s\\S]*?)<\\/bloom>)|(?<bloomUnclosed><bloom\\s+level="(?<bloomLevelUn>remember|understand|apply|analyze|evaluate|create)">(?<bloomOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<quiz><question>(?<quizQuestion>[\\s\\S]*?)<\\/question>\\s*<answer>(?<quizAnswer>[\\s\\S]*?)<\\/answer>)|(?<visualize><visualize\\s+type="(?<vizType>algorithms|math|physics|biology|chemistry|probability)"\\s+description="(?<vizDesc>[^"]*?)"\\s*\\/?>)',
36
+ "gi"
37
+ );
38
+ let lastIndex = 0;
39
+ let match;
40
+ while ((match = tagRegex.exec(content)) !== null) {
41
+ const before = content.slice(lastIndex, match.index);
42
+ if (before.trim()) {
43
+ segments.push(...parseMarkdownWithCodeBlocks(before));
44
+ }
45
+ const g = match.groups ?? {};
46
+ if (g.reflect || g.reflectUnclosed) {
47
+ const prompt = (g.reflectClosed ?? g.reflectOpen ?? "").trim();
48
+ if (prompt) segments.push({ type: "reflect", prompt });
49
+ } else if (g.bloom || g.bloomUnclosed) {
50
+ const level = g.bloomLevel ?? g.bloomLevelUn;
51
+ const bloomContent = g.bloomClosed ?? g.bloomOpen ?? "";
52
+ if (level && bloomContent) {
53
+ const qMatch = bloomContent.match(/<question>([\s\S]*?)<\/question>/i);
54
+ const aMatch = bloomContent.match(/<answer>([\s\S]*?)<\/answer>/i);
55
+ if (qMatch && aMatch) {
56
+ segments.push({ type: "bloom", level, question: qMatch[1].trim(), answer: aMatch[1].trim() });
57
+ } else if (qMatch) {
58
+ segments.push({ type: "bloom", level, question: qMatch[1].trim(), answer: "(Answer not provided)" });
59
+ } else {
60
+ const clean = bloomContent.replace(/^\*\*Question\s*\d*:?\*\*\s*/i, "").replace(/^\*\*Q\d*:?\*\*\s*/i, "").trim();
61
+ if (clean) segments.push({ type: "bloom", level, question: clean, answer: "(See answers section below)" });
62
+ }
63
+ }
64
+ } else if (g.quiz) {
65
+ segments.push({ type: "quiz", question: g.quizQuestion.trim(), answer: g.quizAnswer.trim() });
66
+ } else if (g.visualize) {
67
+ segments.push({
68
+ type: "visualization",
69
+ visualizationType: g.vizType,
70
+ description: g.vizDesc ?? ""
71
+ });
72
+ }
73
+ lastIndex = tagRegex.lastIndex;
74
+ }
75
+ const remaining = content.slice(lastIndex);
76
+ if (remaining.trim()) segments.push(...parseMarkdownWithCodeBlocks(remaining));
77
+ return segments;
78
+ }
79
+
80
+ export { parseLessonSegments };
@@ -11,6 +11,12 @@ var SLOT_DEFINITIONS = {
11
11
  name: "sidebar",
12
12
  type: "inline"
13
13
  },
14
+ dock: {
15
+ name: "dock",
16
+ type: "portal",
17
+ portalTarget: "body",
18
+ zIndex: 850
19
+ },
14
20
  // -------------------------------------------------------------------------
15
21
  // Portal Slots - Render to document.body via React Portal
16
22
  // -------------------------------------------------------------------------
@@ -1,4 +1,4 @@
1
- import { en_default } from './chunk-WB2A6V3I.js';
1
+ import { en_default } from './chunk-7KSLPY56.js';
2
2
 
3
3
  // lib/format.ts
4
4
  var { $meta: _meta, ...coreMessages } = en_default;