@visualli/core 0.1.5 → 0.1.6

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 (85) hide show
  1. package/dist/animations/index.cjs +146 -0
  2. package/dist/animations/index.cjs.map +1 -0
  3. package/dist/animations/index.d.cts +81 -0
  4. package/dist/animations/index.d.ts +81 -0
  5. package/dist/animations/index.js +35 -0
  6. package/dist/animations/index.js.map +1 -0
  7. package/dist/chunk-6NXADJK2.js +562 -0
  8. package/dist/chunk-6NXADJK2.js.map +1 -0
  9. package/dist/chunk-F36SMC3K.js +106 -0
  10. package/dist/chunk-F36SMC3K.js.map +1 -0
  11. package/dist/chunk-G5H3P4YZ.js +273 -0
  12. package/dist/chunk-G5H3P4YZ.js.map +1 -0
  13. package/dist/chunk-GQMFBYLK.js +81 -0
  14. package/dist/chunk-GQMFBYLK.js.map +1 -0
  15. package/dist/chunk-I75TMOE4.js +108 -0
  16. package/dist/chunk-I75TMOE4.js.map +1 -0
  17. package/dist/chunk-LDJRGT2Q.js +163 -0
  18. package/dist/chunk-LDJRGT2Q.js.map +1 -0
  19. package/dist/chunk-LI3BVD6H.js +98 -0
  20. package/dist/chunk-LI3BVD6H.js.map +1 -0
  21. package/dist/chunk-LJYSKSCE.js +95 -0
  22. package/dist/chunk-LJYSKSCE.js.map +1 -0
  23. package/dist/chunk-LNTJTDB2.js +349 -0
  24. package/dist/chunk-LNTJTDB2.js.map +1 -0
  25. package/dist/chunk-PDP5CVUL.js +139 -0
  26. package/dist/chunk-PDP5CVUL.js.map +1 -0
  27. package/dist/chunk-VLGR5PZX.js +1 -0
  28. package/dist/chunk-VLGR5PZX.js.map +1 -0
  29. package/dist/config/index.cjs +391 -0
  30. package/dist/config/index.cjs.map +1 -0
  31. package/dist/config/index.d.cts +77 -0
  32. package/dist/config/index.d.ts +77 -0
  33. package/dist/config/index.js +38 -0
  34. package/dist/config/index.js.map +1 -0
  35. package/dist/constants/index.cjs +642 -0
  36. package/dist/constants/index.cjs.map +1 -0
  37. package/dist/constants/index.d.cts +448 -0
  38. package/dist/constants/index.d.ts +448 -0
  39. package/dist/constants/index.js +183 -0
  40. package/dist/constants/index.js.map +1 -0
  41. package/dist/document-B3hnNr-F.d.cts +73 -0
  42. package/dist/document-B3hnNr-F.d.ts +73 -0
  43. package/dist/index.cjs +32 -32
  44. package/dist/index.cjs.map +1 -1
  45. package/dist/index.d.cts +15 -1044
  46. package/dist/index.d.ts +15 -1044
  47. package/dist/index.js +179 -1747
  48. package/dist/index.js.map +1 -1
  49. package/dist/layout/index.cjs +210 -0
  50. package/dist/layout/index.cjs.map +1 -0
  51. package/dist/layout/index.d.cts +80 -0
  52. package/dist/layout/index.d.ts +80 -0
  53. package/dist/layout/index.js +25 -0
  54. package/dist/layout/index.js.map +1 -0
  55. package/dist/mindmap-DWS0WZT_.d.cts +118 -0
  56. package/dist/mindmap-DWS0WZT_.d.ts +118 -0
  57. package/dist/parser/index.cjs +739 -0
  58. package/dist/parser/index.cjs.map +1 -0
  59. package/dist/parser/index.d.cts +87 -0
  60. package/dist/parser/index.d.ts +87 -0
  61. package/dist/parser/index.js +43 -0
  62. package/dist/parser/index.js.map +1 -0
  63. package/dist/performance/index.cjs +167 -0
  64. package/dist/performance/index.cjs.map +1 -0
  65. package/dist/performance/index.d.cts +40 -0
  66. package/dist/performance/index.d.ts +40 -0
  67. package/dist/performance/index.js +12 -0
  68. package/dist/performance/index.js.map +1 -0
  69. package/dist/types/index.cjs +19 -0
  70. package/dist/types/index.cjs.map +1 -0
  71. package/dist/types/index.d.cts +8 -0
  72. package/dist/types/index.d.ts +8 -0
  73. package/dist/types/index.js +2 -0
  74. package/dist/types/index.js.map +1 -0
  75. package/dist/viewport/index.cjs +131 -0
  76. package/dist/viewport/index.cjs.map +1 -0
  77. package/dist/viewport/index.d.cts +56 -0
  78. package/dist/viewport/index.d.ts +56 -0
  79. package/dist/viewport/index.js +26 -0
  80. package/dist/viewport/index.js.map +1 -0
  81. package/package.json +6 -1
  82. package/src/config/README.md +59 -0
  83. package/src/config/USAGE_EXAMPLES.md +285 -0
  84. package/src/config/index.ts +7 -0
  85. package/src/index.ts +1 -2
@@ -0,0 +1,106 @@
1
+ // src/animations/easing.ts
2
+ var easeInOutCubic = (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
3
+ var easeInOutQuart = (t) => t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2;
4
+ var easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
5
+ var easeInCubic = (t) => t * t * t;
6
+ var easeOutQuad = (t) => 1 - (1 - t) * (1 - t);
7
+ var easeInOutSine = (t) => -(Math.cos(Math.PI * t) - 1) / 2;
8
+ function createCubicBezier(x1, y1, x2, y2) {
9
+ const N = 256;
10
+ const lut = new Float64Array(N + 1);
11
+ for (let i = 0; i <= N; i++) {
12
+ const target = i / N;
13
+ let lo = 0, hi = 1;
14
+ for (let j = 0; j < 20; j++) {
15
+ const mid = (lo + hi) / 2;
16
+ const om = 1 - mid;
17
+ const x = 3 * om * om * mid * x1 + 3 * om * mid * mid * x2 + mid * mid * mid;
18
+ if (x < target) lo = mid;
19
+ else hi = mid;
20
+ }
21
+ const u = (lo + hi) / 2;
22
+ const ou = 1 - u;
23
+ lut[i] = 3 * ou * ou * u * y1 + 3 * ou * u * u * y2 + u * u * u;
24
+ }
25
+ return (t) => {
26
+ if (t <= 0) return 0;
27
+ if (t >= 1) return 1;
28
+ const s = t * N;
29
+ const i = s | 0;
30
+ return lut[i] + (lut[i + 1] - lut[i]) * (s - i);
31
+ };
32
+ }
33
+ var easeZoomTransition = createCubicBezier(0.2, 0.8, 0.2, 1);
34
+
35
+ // src/animations/constants.ts
36
+ var ANIMATION_DURATION = {
37
+ ZOOM_IN_LAYER: 500,
38
+ ZOOM_OUT_LAYER: 500,
39
+ ZOOM_GESTURE: 500,
40
+ FADE_OUT: 200,
41
+ FADE_IN: 250,
42
+ COLOR_TRANSITION: 500,
43
+ CURSOR_CHANGE: 150,
44
+ LOADING_FADE: 200
45
+ };
46
+ var ANIMATION_PHASES = {
47
+ ZOOM_IN: {
48
+ ZOOM_TO_TARGET: 500,
49
+ FADE_OUT_START: 120,
50
+ FADE_OUT: 280,
51
+ CONTENT_SWAP: 310,
52
+ FADE_IN: 200,
53
+ TOTAL: 510
54
+ },
55
+ ZOOM_OUT: {
56
+ FADE_OUT: 200,
57
+ ZOOM_BACK: 50,
58
+ FADE_IN: 250,
59
+ TOTAL: 500
60
+ }
61
+ };
62
+ var ZOOM_THRESHOLDS = {
63
+ ENTER_LAYER: 5,
64
+ EXIT_LAYER: 0.5,
65
+ GESTURE_TRIGGER: 0.8
66
+ };
67
+ var COOLDOWN = {
68
+ NAVIGATION: 1e3,
69
+ ZOOM_GESTURE: 800,
70
+ DOUBLE_CLICK: 200
71
+ };
72
+ var OPACITY = {
73
+ VISIBLE: 1,
74
+ HIDDEN: 0,
75
+ TRANSITIONING: 0.3
76
+ };
77
+ var TARGET_ZOOM = {
78
+ NORMAL: 1,
79
+ FOCUSED: 0.8,
80
+ FILL_NODE: 3,
81
+ DETAIL: 2
82
+ };
83
+ var VIEWPORT_FRAMING = {
84
+ NODE_FILL_RATIO: 0.7,
85
+ EXIT_NODE_SIZE: 0.4,
86
+ PADDING_RATIO: 0.1
87
+ };
88
+
89
+ export {
90
+ easeInOutCubic,
91
+ easeInOutQuart,
92
+ easeOutCubic,
93
+ easeInCubic,
94
+ easeOutQuad,
95
+ easeInOutSine,
96
+ createCubicBezier,
97
+ easeZoomTransition,
98
+ ANIMATION_DURATION,
99
+ ANIMATION_PHASES,
100
+ ZOOM_THRESHOLDS,
101
+ COOLDOWN,
102
+ OPACITY,
103
+ TARGET_ZOOM,
104
+ VIEWPORT_FRAMING
105
+ };
106
+ //# sourceMappingURL=chunk-F36SMC3K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/animations/easing.ts","../src/animations/constants.ts"],"sourcesContent":["// ─── Animation Easing Functions ───────────────────────────────────────────────\n//\n// Pure math easing functions for smooth, cinematic animations.\n// No DOM / RAF dependencies – usable in any runtime.\n\nexport type EasingFunction = (t: number) => number;\n\n/** Smooth cubic – slow start, fast middle, slow end. */\nexport const easeInOutCubic: EasingFunction = (t) =>\n t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;\n\n/** Smooth quartic – more dramatic than cubic. */\nexport const easeInOutQuart: EasingFunction = (t) =>\n t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2;\n\n/** Fast start, slow end. */\nexport const easeOutCubic: EasingFunction = (t) => 1 - Math.pow(1 - t, 3);\n\n/** Slow start, fast end. */\nexport const easeInCubic: EasingFunction = (t) => t * t * t;\n\n/** Gentle ease-out (quadratic). */\nexport const easeOutQuad: EasingFunction = (t) => 1 - (1 - t) * (1 - t);\n\n/** Very smooth, organic sine easing. */\nexport const easeInOutSine: EasingFunction = (t) =>\n -(Math.cos(Math.PI * t) - 1) / 2;\n\n/**\n * Create a CSS cubic-bezier easing function from four control-point values.\n *\n * Builds a 256-entry lookup table at call time (once) so subsequent evaluations\n * are a single table lookup + linear interpolation.\n */\nexport function createCubicBezier(\n x1: number, y1: number,\n x2: number, y2: number,\n): EasingFunction {\n const N = 256;\n const lut = new Float64Array(N + 1);\n\n for (let i = 0; i <= N; i++) {\n const target = i / N;\n let lo = 0, hi = 1;\n for (let j = 0; j < 20; j++) {\n const mid = (lo + hi) / 2;\n const om = 1 - mid;\n const x = 3 * om * om * mid * x1 + 3 * om * mid * mid * x2 + mid * mid * mid;\n if (x < target) lo = mid; else hi = mid;\n }\n const u = (lo + hi) / 2;\n const ou = 1 - u;\n lut[i] = 3 * ou * ou * u * y1 + 3 * ou * u * u * y2 + u * u * u;\n }\n\n return (t: number): number => {\n if (t <= 0) return 0;\n if (t >= 1) return 1;\n const s = t * N;\n const i = s | 0;\n return lut[i] + (lut[i + 1] - lut[i]) * (s - i);\n };\n}\n\n/**\n * Zoom-transition easing — matches CSS cubic-bezier(0.2, 0.8, 0.2, 1).\n * Fast start with smooth, organic settle. Used for all layer transitions.\n * Pre-computed LUT: subsequent calls are a single table lookup + linear interpolation.\n */\nexport const easeZoomTransition: EasingFunction = createCubicBezier(0.2, 0.8, 0.2, 1);\n","// ─── Animation Constants ──────────────────────────────────────────────────────\n\n// ── Timing (ms) ───────────────────────────────────────────────────────────────\n\nexport const ANIMATION_DURATION = {\n ZOOM_IN_LAYER: 500,\n ZOOM_OUT_LAYER: 500,\n ZOOM_GESTURE: 500,\n FADE_OUT: 200,\n FADE_IN: 250,\n COLOR_TRANSITION: 500,\n CURSOR_CHANGE: 150,\n LOADING_FADE: 200,\n} as const;\n\nexport const ANIMATION_PHASES = {\n ZOOM_IN: {\n ZOOM_TO_TARGET: 500,\n FADE_OUT_START: 120,\n FADE_OUT: 280,\n CONTENT_SWAP: 310,\n FADE_IN: 200,\n TOTAL: 510,\n },\n ZOOM_OUT: {\n FADE_OUT: 200,\n ZOOM_BACK: 50,\n FADE_IN: 250,\n TOTAL: 500,\n },\n} as const;\n\n// ── Zoom Thresholds ───────────────────────────────────────────────────────────\n\nexport const ZOOM_THRESHOLDS = {\n ENTER_LAYER: 5.0,\n EXIT_LAYER: 0.5,\n GESTURE_TRIGGER: 0.8,\n} as const;\n\n// ── Cooldowns (ms) ────────────────────────────────────────────────────────────\n\nexport const COOLDOWN = {\n NAVIGATION: 1000,\n ZOOM_GESTURE: 800,\n DOUBLE_CLICK: 200,\n} as const;\n\n// ── Opacity ───────────────────────────────────────────────────────────────────\n\nexport const OPACITY = {\n VISIBLE: 1.0,\n HIDDEN: 0.0,\n TRANSITIONING: 0.3,\n} as const;\n\n// ── Target Zoom Levels ────────────────────────────────────────────────────────\n\nexport const TARGET_ZOOM = {\n NORMAL: 1.0,\n FOCUSED: 0.8,\n FILL_NODE: 3.0,\n DETAIL: 2.0,\n} as const;\n\n// ── Viewport Framing ──────────────────────────────────────────────────────────\n\nexport const VIEWPORT_FRAMING = {\n NODE_FILL_RATIO: 0.7,\n EXIT_NODE_SIZE: 0.4,\n PADDING_RATIO: 0.1,\n} as const;\n"],"mappings":";AAQO,IAAM,iBAAiC,CAAC,MAC7C,IAAI,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC,IAAI;AAGnD,IAAM,iBAAiC,CAAC,MAC7C,IAAI,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC,IAAI;AAGvD,IAAM,eAA+B,CAAC,MAAM,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;AAGjE,IAAM,cAA8B,CAAC,MAAM,IAAI,IAAI;AAGnD,IAAM,cAA8B,CAAC,MAAM,KAAK,IAAI,MAAM,IAAI;AAG9D,IAAM,gBAAgC,CAAC,MAC5C,EAAE,KAAK,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK;AAQ1B,SAAS,kBACd,IAAY,IACZ,IAAY,IACI;AAChB,QAAM,IAAI;AACV,QAAM,MAAM,IAAI,aAAa,IAAI,CAAC;AAElC,WAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,UAAM,SAAS,IAAI;AACnB,QAAI,KAAK,GAAG,KAAK;AACjB,aAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,YAAM,OAAO,KAAK,MAAM;AACxB,YAAM,KAAM,IAAI;AAChB,YAAM,IAAM,IAAI,KAAK,KAAK,MAAM,KAAK,IAAI,KAAK,MAAM,MAAM,KAAK,MAAM,MAAM;AAC3E,UAAI,IAAI,OAAQ,MAAK;AAAA,UAAU,MAAK;AAAA,IACtC;AACA,UAAM,KAAM,KAAK,MAAM;AACvB,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI;AAAA,EAChE;AAEA,SAAO,CAAC,MAAsB;AAC5B,QAAI,KAAK,EAAG,QAAO;AACnB,QAAI,KAAK,EAAG,QAAO;AACnB,UAAM,IAAI,IAAI;AACd,UAAM,IAAI,IAAI;AACd,WAAO,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI;AAAA,EAC/C;AACF;AAOO,IAAM,qBAAqC,kBAAkB,KAAK,KAAK,KAAK,CAAC;;;ACjE7E,IAAM,qBAAqB;AAAA,EAChC,eAAkB;AAAA,EAClB,gBAAkB;AAAA,EAClB,cAAkB;AAAA,EAClB,UAAkB;AAAA,EAClB,SAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,eAAkB;AAAA,EAClB,cAAkB;AACpB;AAEO,IAAM,mBAAmB;AAAA,EAC9B,SAAS;AAAA,IACP,gBAAiB;AAAA,IACjB,gBAAiB;AAAA,IACjB,UAAiB;AAAA,IACjB,cAAiB;AAAA,IACjB,SAAiB;AAAA,IACjB,OAAiB;AAAA,EACnB;AAAA,EACA,UAAU;AAAA,IACR,UAAW;AAAA,IACX,WAAW;AAAA,IACX,SAAW;AAAA,IACX,OAAW;AAAA,EACb;AACF;AAIO,IAAM,kBAAkB;AAAA,EAC7B,aAAkB;AAAA,EAClB,YAAkB;AAAA,EAClB,iBAAkB;AACpB;AAIO,IAAM,WAAW;AAAA,EACtB,YAAe;AAAA,EACf,cAAe;AAAA,EACf,cAAe;AACjB;AAIO,IAAM,UAAU;AAAA,EACrB,SAAe;AAAA,EACf,QAAe;AAAA,EACf,eAAe;AACjB;AAIO,IAAM,cAAc;AAAA,EACzB,QAAY;AAAA,EACZ,SAAY;AAAA,EACZ,WAAY;AAAA,EACZ,QAAY;AACd;AAIO,IAAM,mBAAmB;AAAA,EAC9B,iBAAkB;AAAA,EAClB,gBAAkB;AAAA,EAClB,eAAkB;AACpB;","names":[]}
@@ -0,0 +1,273 @@
1
+ // src/constants/design.ts
2
+ var DS_COLORS = {
3
+ light: {
4
+ bgApp: "#F0EDE6",
5
+ bgSurface: "#FAF8F4",
6
+ bgInput: "#FFFFFF",
7
+ border: "#DDD9D0",
8
+ borderDivider: "#E8E4DC",
9
+ primary: "#1B2D4F",
10
+ primaryHover: "#243B68",
11
+ textPrimary: "#1A1A18",
12
+ textSecondary: "#6B6860",
13
+ textMuted: "#747270",
14
+ textOnPrimary: "#FAF8F4",
15
+ hoverItem: "rgba(27,45,79,0.07)",
16
+ focusRing: "rgba(27,45,79,0.40)",
17
+ btnMuted: "#8E8C88"
18
+ },
19
+ dark: {
20
+ bgApp: "#141412",
21
+ bgSurface: "#1C1C1A",
22
+ bgInput: "#262622",
23
+ border: "#333330",
24
+ borderDivider: "#2A2A28",
25
+ primary: "#BB532D",
26
+ primaryHover: "#CC6440",
27
+ textPrimary: "#F0EDE6",
28
+ textSecondary: "#B0ABA3",
29
+ textMuted: "#8E8C88",
30
+ textOnPrimary: "#FAF8F4",
31
+ hoverItem: "rgba(198,94,56,0.12)",
32
+ focusRing: "rgba(198,94,56,0.50)",
33
+ btnMuted: "#4A4845"
34
+ }
35
+ };
36
+ var DS_TYPOGRAPHY = {
37
+ fontDisplay: "'Nunito', sans-serif",
38
+ fontBody: "'Nunito Sans', sans-serif",
39
+ logo: { size: "20px", weight: 800, letterSpacing: "0.04em" },
40
+ heading: { size: "16px", weight: 700, letterSpacing: "-0.2px" },
41
+ cta: { size: "11px", weight: 800, letterSpacing: "0.12em", transform: "uppercase" },
42
+ body: { size: "13px", weight: 400 },
43
+ input: { size: "13px", weight: 300, style: "italic" },
44
+ search: { size: "12px", weight: 400 },
45
+ username: { size: "13px", weight: 600 },
46
+ avatar: { size: "11px", weight: 700 },
47
+ footer: { size: "12px", weight: 400 },
48
+ empty: { size: "11px", weight: 300, style: "italic" }
49
+ };
50
+ var DS_RADII = {
51
+ sidebar: 16,
52
+ input: 8,
53
+ cta: 7,
54
+ item: 6,
55
+ swatch: 10
56
+ };
57
+ var BRAND_COLORS = {
58
+ primary: {
59
+ 50: "#EFF6FF",
60
+ 100: "#DBEAFE",
61
+ 200: "#BFDBFE",
62
+ 300: "#93C5FD",
63
+ 400: "#60A5FA",
64
+ 500: "#3B82F6",
65
+ 600: "#2563EB",
66
+ 700: "#1D4ED8",
67
+ 800: "#1E40AF",
68
+ 900: "#1E3A8A"
69
+ },
70
+ secondary: {
71
+ 50: "#F0FDF4",
72
+ 100: "#DCFCE7",
73
+ 200: "#BBF7D0",
74
+ 300: "#86EFAC",
75
+ 400: "#4ADE80",
76
+ 500: "#10B981",
77
+ 600: "#059669",
78
+ 700: "#047857",
79
+ 800: "#065F46",
80
+ 900: "#064E3B"
81
+ },
82
+ accent: {
83
+ purple: "#8B5CF6",
84
+ cyan: "#06B6D4",
85
+ sky: "#0EA5E9",
86
+ lime: "#84CC16",
87
+ amber: "#F59E0B",
88
+ red: "#EF4444"
89
+ }
90
+ };
91
+ var LEVEL_COLORS = {
92
+ level0: BRAND_COLORS.primary[500],
93
+ level1: BRAND_COLORS.primary[400],
94
+ level2: BRAND_COLORS.primary[300],
95
+ level3: BRAND_COLORS.primary[200],
96
+ level4: BRAND_COLORS.primary[300],
97
+ level5: BRAND_COLORS.primary[400],
98
+ level6: BRAND_COLORS.primary[500],
99
+ level7: BRAND_COLORS.primary[600],
100
+ level8: BRAND_COLORS.primary[700]
101
+ };
102
+ var LEVEL_COLOR_ARRAY = [
103
+ LEVEL_COLORS.level0,
104
+ LEVEL_COLORS.level1,
105
+ LEVEL_COLORS.level2,
106
+ LEVEL_COLORS.level3,
107
+ LEVEL_COLORS.level4,
108
+ LEVEL_COLORS.level5,
109
+ LEVEL_COLORS.level6,
110
+ LEVEL_COLORS.level7,
111
+ LEVEL_COLORS.level8
112
+ ];
113
+ var PARENT_FALLBACK_COLORS = [
114
+ "#12C7D3",
115
+ "#325E8C",
116
+ "#8A70A6",
117
+ "#F54A57",
118
+ "#FF6C4D",
119
+ "#F28C16",
120
+ "#FFD347",
121
+ "#7F7F7F",
122
+ "#8D8D8D"
123
+ ];
124
+ var SEMANTIC_COLORS = {
125
+ success: BRAND_COLORS.secondary[500],
126
+ error: BRAND_COLORS.accent.red,
127
+ warning: BRAND_COLORS.accent.amber,
128
+ info: BRAND_COLORS.primary[500]
129
+ };
130
+ var THEME_COLORS = {
131
+ light: {
132
+ background: { primary: "#FAF8F4", secondary: "#F0EDE6", tertiary: "#FFFFFF" },
133
+ text: { primary: "#1A1A18", secondary: "#6B6860", tertiary: "#747270" },
134
+ border: { primary: "#DDD9D0", secondary: "#E8E4DC" }
135
+ },
136
+ dark: {
137
+ background: { primary: "#1C1C1A", secondary: "#141412", tertiary: "#262622" },
138
+ text: { primary: "#F0EDE6", secondary: "#B0ABA3", tertiary: "#8E8C88" },
139
+ border: { primary: "#333330", secondary: "#2A2A28" }
140
+ }
141
+ };
142
+ var CANVAS_COLORS = {
143
+ node: {
144
+ border: "#FFFFFF",
145
+ titleColor: "#1e1b4b",
146
+ badgeBackground: "#FFC107",
147
+ badgeStroke: "#fcd34d"
148
+ }
149
+ };
150
+ var SPACING = {
151
+ xs: 4,
152
+ sm: 8,
153
+ md: 16,
154
+ lg: 24,
155
+ xl: 32,
156
+ "2xl": 48,
157
+ "3xl": 64,
158
+ "4xl": 96
159
+ };
160
+ var LAYOUT_SPACING = {
161
+ nodeSpacing: 200,
162
+ levelSpacing: 150,
163
+ containerPadding: 20,
164
+ gridSize: 50
165
+ };
166
+ var FONTS = {
167
+ primary: "'Inter', sans-serif",
168
+ secondary: "'Poppins', sans-serif",
169
+ mono: "'Roboto Mono', monospace"
170
+ };
171
+ var FONT_SIZES = {
172
+ xs: "0.75rem",
173
+ sm: "0.875rem",
174
+ base: "1rem",
175
+ lg: "1.125rem",
176
+ xl: "1.25rem",
177
+ "2xl": "1.5rem",
178
+ "3xl": "1.875rem",
179
+ "4xl": "2.25rem"
180
+ };
181
+ function getColorForLevel(level) {
182
+ return LEVEL_COLOR_ARRAY[level % LEVEL_COLOR_ARRAY.length];
183
+ }
184
+ function darkenHexColor(hex, amount = 0.22) {
185
+ if (!hex || !hex.startsWith("#")) return hex;
186
+ let r, g, b;
187
+ if (hex.length === 4) {
188
+ r = parseInt(hex[1] + hex[1], 16);
189
+ g = parseInt(hex[2] + hex[2], 16);
190
+ b = parseInt(hex[3] + hex[3], 16);
191
+ } else if (hex.length === 7) {
192
+ r = parseInt(hex.slice(1, 3), 16);
193
+ g = parseInt(hex.slice(3, 5), 16);
194
+ b = parseInt(hex.slice(5, 7), 16);
195
+ } else {
196
+ return hex;
197
+ }
198
+ if (isNaN(r) || isNaN(g) || isNaN(b)) return hex;
199
+ const rn = r / 255, gn = g / 255, bn = b / 255;
200
+ const cmax = Math.max(rn, gn, bn), cmin = Math.min(rn, gn, bn);
201
+ const d = cmax - cmin;
202
+ const l = (cmax + cmin) / 2;
203
+ const s = d === 0 ? 0 : d / (1 - Math.abs(2 * l - 1));
204
+ let h = 0;
205
+ if (d !== 0) {
206
+ const seg = cmax === rn ? (gn - bn) / d : cmax === gn ? (bn - rn) / d + 2 : (rn - gn) / d + 4;
207
+ h = (seg * 60 + 360) % 360;
208
+ }
209
+ const newL = Math.max(0, l - amount);
210
+ const c2 = (1 - Math.abs(2 * newL - 1)) * s;
211
+ const x2 = c2 * (1 - Math.abs(h / 60 % 2 - 1));
212
+ const m2 = newL - c2 / 2;
213
+ let r1 = 0, g1 = 0, b1 = 0;
214
+ if (h < 60) {
215
+ r1 = c2;
216
+ g1 = x2;
217
+ b1 = 0;
218
+ } else if (h < 120) {
219
+ r1 = x2;
220
+ g1 = c2;
221
+ b1 = 0;
222
+ } else if (h < 180) {
223
+ r1 = 0;
224
+ g1 = c2;
225
+ b1 = x2;
226
+ } else if (h < 240) {
227
+ r1 = 0;
228
+ g1 = x2;
229
+ b1 = c2;
230
+ } else if (h < 300) {
231
+ r1 = x2;
232
+ g1 = 0;
233
+ b1 = c2;
234
+ } else {
235
+ r1 = c2;
236
+ g1 = 0;
237
+ b1 = x2;
238
+ }
239
+ const toHex = (v) => Math.round((v + m2) * 255).toString(16).padStart(2, "0");
240
+ return `#${toHex(r1)}${toHex(g1)}${toHex(b1)}`;
241
+ }
242
+ function getThemeBackground(isDark, variant = "primary") {
243
+ return isDark ? THEME_COLORS.dark.background[variant] : THEME_COLORS.light.background[variant];
244
+ }
245
+ function getThemeText(isDark, variant = "primary") {
246
+ return isDark ? THEME_COLORS.dark.text[variant] : THEME_COLORS.light.text[variant];
247
+ }
248
+ function getThemeBorder(isDark, variant = "primary") {
249
+ return isDark ? THEME_COLORS.dark.border[variant] : THEME_COLORS.light.border[variant];
250
+ }
251
+
252
+ export {
253
+ DS_COLORS,
254
+ DS_TYPOGRAPHY,
255
+ DS_RADII,
256
+ BRAND_COLORS,
257
+ LEVEL_COLORS,
258
+ LEVEL_COLOR_ARRAY,
259
+ PARENT_FALLBACK_COLORS,
260
+ SEMANTIC_COLORS,
261
+ THEME_COLORS,
262
+ CANVAS_COLORS,
263
+ SPACING,
264
+ LAYOUT_SPACING,
265
+ FONTS,
266
+ FONT_SIZES,
267
+ getColorForLevel,
268
+ darkenHexColor,
269
+ getThemeBackground,
270
+ getThemeText,
271
+ getThemeBorder
272
+ };
273
+ //# sourceMappingURL=chunk-G5H3P4YZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/constants/design.ts"],"sourcesContent":["// ─── Design System Constants ──────────────────────────────────────────────────\n//\n// Single source of truth for all color tokens, typography, spacing, and\n// visual design constants used across the SDK and consuming apps.\n//\n// ## Color Priority\n// 1. Data file values (node.color, layer.backgroundColor)\n// 2. Fall back to these constants\n\n// ── Visualli Design System v2 ─────────────────────────────────────────────────\n\nexport const DS_COLORS = {\n light: {\n bgApp: '#F0EDE6',\n bgSurface: '#FAF8F4',\n bgInput: '#FFFFFF',\n border: '#DDD9D0',\n borderDivider: '#E8E4DC',\n primary: '#1B2D4F',\n primaryHover: '#243B68',\n textPrimary: '#1A1A18',\n textSecondary: '#6B6860',\n textMuted: '#747270',\n textOnPrimary: '#FAF8F4',\n hoverItem: 'rgba(27,45,79,0.07)',\n focusRing: 'rgba(27,45,79,0.40)',\n btnMuted: '#8E8C88',\n },\n dark: {\n bgApp: '#141412',\n bgSurface: '#1C1C1A',\n bgInput: '#262622',\n border: '#333330',\n borderDivider: '#2A2A28',\n primary: '#BB532D',\n primaryHover: '#CC6440',\n textPrimary: '#F0EDE6',\n textSecondary: '#B0ABA3',\n textMuted: '#8E8C88',\n textOnPrimary: '#FAF8F4',\n hoverItem: 'rgba(198,94,56,0.12)',\n focusRing: 'rgba(198,94,56,0.50)',\n btnMuted: '#4A4845',\n },\n} as const;\n\nexport const DS_TYPOGRAPHY = {\n fontDisplay: \"'Nunito', sans-serif\",\n fontBody: \"'Nunito Sans', sans-serif\",\n logo: { size: '20px', weight: 800, letterSpacing: '0.04em' },\n heading: { size: '16px', weight: 700, letterSpacing: '-0.2px' },\n cta: { size: '11px', weight: 800, letterSpacing: '0.12em', transform: 'uppercase' as const },\n body: { size: '13px', weight: 400 },\n input: { size: '13px', weight: 300, style: 'italic' as const },\n search: { size: '12px', weight: 400 },\n username: { size: '13px', weight: 600 },\n avatar: { size: '11px', weight: 700 },\n footer: { size: '12px', weight: 400 },\n empty: { size: '11px', weight: 300, style: 'italic' as const },\n} as const;\n\nexport const DS_RADII = {\n sidebar: 16,\n input: 8,\n cta: 7,\n item: 6,\n swatch: 10,\n} as const;\n\n// ── Brand Colors ──────────────────────────────────────────────────────────────\n\nexport const BRAND_COLORS = {\n primary: {\n 50: '#EFF6FF',\n 100: '#DBEAFE',\n 200: '#BFDBFE',\n 300: '#93C5FD',\n 400: '#60A5FA',\n 500: '#3B82F6',\n 600: '#2563EB',\n 700: '#1D4ED8',\n 800: '#1E40AF',\n 900: '#1E3A8A',\n },\n secondary: {\n 50: '#F0FDF4',\n 100: '#DCFCE7',\n 200: '#BBF7D0',\n 300: '#86EFAC',\n 400: '#4ADE80',\n 500: '#10B981',\n 600: '#059669',\n 700: '#047857',\n 800: '#065F46',\n 900: '#064E3B',\n },\n accent: {\n purple: '#8B5CF6',\n cyan: '#06B6D4',\n sky: '#0EA5E9',\n lime: '#84CC16',\n amber: '#F59E0B',\n red: '#EF4444',\n },\n} as const;\n\n// ── Level Colors ──────────────────────────────────────────────────────────────\n\nexport const LEVEL_COLORS = {\n level0: BRAND_COLORS.primary[500],\n level1: BRAND_COLORS.primary[400],\n level2: BRAND_COLORS.primary[300],\n level3: BRAND_COLORS.primary[200],\n level4: BRAND_COLORS.primary[300],\n level5: BRAND_COLORS.primary[400],\n level6: BRAND_COLORS.primary[500],\n level7: BRAND_COLORS.primary[600],\n level8: BRAND_COLORS.primary[700],\n} as const;\n\nexport const LEVEL_COLOR_ARRAY = [\n LEVEL_COLORS.level0,\n LEVEL_COLORS.level1,\n LEVEL_COLORS.level2,\n LEVEL_COLORS.level3,\n LEVEL_COLORS.level4,\n LEVEL_COLORS.level5,\n LEVEL_COLORS.level6,\n LEVEL_COLORS.level7,\n LEVEL_COLORS.level8,\n] as const;\n\nexport const PARENT_FALLBACK_COLORS = [\n '#12C7D3', '#325E8C', '#8A70A6', '#F54A57', '#FF6C4D',\n '#F28C16', '#FFD347', '#7F7F7F', '#8D8D8D',\n] as const;\n\nexport const SEMANTIC_COLORS = {\n success: BRAND_COLORS.secondary[500],\n error: BRAND_COLORS.accent.red,\n warning: BRAND_COLORS.accent.amber,\n info: BRAND_COLORS.primary[500],\n} as const;\n\n// ── Theme Colors ──────────────────────────────────────────────────────────────\n\nexport const THEME_COLORS = {\n light: {\n background: { primary: '#FAF8F4', secondary: '#F0EDE6', tertiary: '#FFFFFF' },\n text: { primary: '#1A1A18', secondary: '#6B6860', tertiary: '#747270' },\n border: { primary: '#DDD9D0', secondary: '#E8E4DC' },\n },\n dark: {\n background: { primary: '#1C1C1A', secondary: '#141412', tertiary: '#262622' },\n text: { primary: '#F0EDE6', secondary: '#B0ABA3', tertiary: '#8E8C88' },\n border: { primary: '#333330', secondary: '#2A2A28' },\n },\n} as const;\n\n// ── Canvas Node Colors ────────────────────────────────────────────────────────\n\nexport const CANVAS_COLORS = {\n node: {\n border: '#FFFFFF',\n titleColor: '#1e1b4b',\n badgeBackground: '#FFC107',\n badgeStroke: '#fcd34d',\n },\n} as const;\n\n// ── Spacing ───────────────────────────────────────────────────────────────────\n\nexport const SPACING = {\n xs: 4,\n sm: 8,\n md: 16,\n lg: 24,\n xl: 32,\n '2xl': 48,\n '3xl': 64,\n '4xl': 96,\n} as const;\n\nexport const LAYOUT_SPACING = {\n nodeSpacing: 200,\n levelSpacing: 150,\n containerPadding: 20,\n gridSize: 50,\n} as const;\n\n// ── Typography ────────────────────────────────────────────────────────────────\n\nexport const FONTS = {\n primary: \"'Inter', sans-serif\",\n secondary: \"'Poppins', sans-serif\",\n mono: \"'Roboto Mono', monospace\",\n} as const;\n\nexport const FONT_SIZES = {\n xs: '0.75rem',\n sm: '0.875rem',\n base: '1rem',\n lg: '1.125rem',\n xl: '1.25rem',\n '2xl': '1.5rem',\n '3xl': '1.875rem',\n '4xl': '2.25rem',\n} as const;\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\n/** Get a level color, cycling back to level 0 for levels > 8. */\nexport function getColorForLevel(level: number): string {\n return LEVEL_COLOR_ARRAY[level % LEVEL_COLOR_ARRAY.length];\n}\n\n/**\n * Darken a hex color by reducing HSL lightness.\n * Returns a monochromatic darker version — used for border/stroke colors.\n * Falls back to the original string if parsing fails.\n */\nexport function darkenHexColor(hex: string, amount: number = 0.22): string {\n if (!hex || !hex.startsWith('#')) return hex;\n let r: number, g: number, b: number;\n if (hex.length === 4) {\n r = parseInt(hex[1] + hex[1], 16);\n g = parseInt(hex[2] + hex[2], 16);\n b = parseInt(hex[3] + hex[3], 16);\n } else if (hex.length === 7) {\n r = parseInt(hex.slice(1, 3), 16);\n g = parseInt(hex.slice(3, 5), 16);\n b = parseInt(hex.slice(5, 7), 16);\n } else {\n return hex;\n }\n if (isNaN(r) || isNaN(g) || isNaN(b)) return hex;\n const rn = r / 255, gn = g / 255, bn = b / 255;\n const cmax = Math.max(rn, gn, bn), cmin = Math.min(rn, gn, bn);\n const d = cmax - cmin;\n const l = (cmax + cmin) / 2;\n const s = d === 0 ? 0 : d / (1 - Math.abs(2 * l - 1));\n let h = 0;\n if (d !== 0) {\n const seg = cmax === rn ? (gn - bn) / d : cmax === gn ? (bn - rn) / d + 2 : (rn - gn) / d + 4;\n h = ((seg * 60) + 360) % 360;\n }\n const newL = Math.max(0, l - amount);\n const c2 = (1 - Math.abs(2 * newL - 1)) * s;\n const x2 = c2 * (1 - Math.abs(((h / 60) % 2) - 1));\n const m2 = newL - c2 / 2;\n let r1 = 0, g1 = 0, b1 = 0;\n if (h < 60) { r1 = c2; g1 = x2; b1 = 0; }\n else if (h < 120) { r1 = x2; g1 = c2; b1 = 0; }\n else if (h < 180) { r1 = 0; g1 = c2; b1 = x2; }\n else if (h < 240) { r1 = 0; g1 = x2; b1 = c2; }\n else if (h < 300) { r1 = x2; g1 = 0; b1 = c2; }\n else { r1 = c2; g1 = 0; b1 = x2; }\n const toHex = (v: number) => Math.round((v + m2) * 255).toString(16).padStart(2, '0');\n return `#${toHex(r1)}${toHex(g1)}${toHex(b1)}`;\n}\n\nexport function getThemeBackground(\n isDark: boolean,\n variant: 'primary' | 'secondary' | 'tertiary' = 'primary',\n): string {\n return isDark ? THEME_COLORS.dark.background[variant] : THEME_COLORS.light.background[variant];\n}\n\nexport function getThemeText(\n isDark: boolean,\n variant: 'primary' | 'secondary' | 'tertiary' = 'primary',\n): string {\n return isDark ? THEME_COLORS.dark.text[variant] : THEME_COLORS.light.text[variant];\n}\n\nexport function getThemeBorder(\n isDark: boolean,\n variant: 'primary' | 'secondary' = 'primary',\n): string {\n return isDark ? THEME_COLORS.dark.border[variant] : THEME_COLORS.light.border[variant];\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,81 @@
1
+ // src/layout/circularLayout.ts
2
+ function applyCircularLayout(nodes, options = {}) {
3
+ const {
4
+ radiusPercentage = 0.135,
5
+ containerWidth = 2e3,
6
+ containerHeight = 2e3,
7
+ centerX = 0,
8
+ centerY = 0
9
+ } = options;
10
+ if (nodes.length === 0) return nodes;
11
+ if (nodes.length === 1) {
12
+ nodes[0].x = centerX;
13
+ nodes[0].y = centerY;
14
+ return nodes;
15
+ }
16
+ const radius = Math.min(containerWidth, containerHeight) * radiusPercentage;
17
+ const startAngle = nodes.length === 2 ? 0 : -Math.PI / 2;
18
+ const angleStep = 2 * Math.PI / nodes.length;
19
+ for (let i = 0; i < nodes.length; i++) {
20
+ const angle = startAngle + i * angleStep;
21
+ nodes[i].x = centerX + radius * Math.cos(angle);
22
+ nodes[i].y = centerY + radius * Math.sin(angle);
23
+ }
24
+ return nodes;
25
+ }
26
+ function calculateMinimumRadius(nodeCount, nodeWidth = 200, nodePadding = 150) {
27
+ if (nodeCount <= 1) return 0;
28
+ const angleStep = 2 * Math.PI / nodeCount;
29
+ const minChordLength = nodeWidth + nodePadding;
30
+ return minChordLength / (2 * Math.sin(angleStep / 2));
31
+ }
32
+ function calculateOptimalRadiusPercentage(nodeCount, containerWidth = 2e3, containerHeight = 2e3, nodeWidth = 200, nodePadding = 120) {
33
+ const minRadius = calculateMinimumRadius(nodeCount, nodeWidth, nodePadding);
34
+ const minDimension = Math.min(containerWidth, containerHeight);
35
+ return Math.min(0.45, Math.max(0.135, minRadius / minDimension));
36
+ }
37
+
38
+ // src/layout/linearLayout.ts
39
+ function applyLinearHorizontalLayout(nodes, options = {}) {
40
+ const { nodeWidth = 200, hGap = 180, centerX = 0, centerY = 0 } = options;
41
+ if (nodes.length === 0) return nodes;
42
+ if (nodes.length === 1) {
43
+ nodes[0].x = centerX;
44
+ nodes[0].y = centerY;
45
+ return nodes;
46
+ }
47
+ const spacing = nodeWidth + hGap;
48
+ const totalWidth = (nodes.length - 1) * spacing;
49
+ const startX = centerX - totalWidth / 2;
50
+ for (let i = 0; i < nodes.length; i++) {
51
+ nodes[i].x = startX + i * spacing;
52
+ nodes[i].y = centerY;
53
+ }
54
+ return nodes;
55
+ }
56
+ function applyLinearVerticalLayout(nodes, options = {}) {
57
+ const { nodeHeight = 80, vGap = 220, centerX = 0, centerY = 0 } = options;
58
+ if (nodes.length === 0) return nodes;
59
+ if (nodes.length === 1) {
60
+ nodes[0].x = centerX;
61
+ nodes[0].y = centerY;
62
+ return nodes;
63
+ }
64
+ const spacing = nodeHeight + vGap;
65
+ const totalHeight = (nodes.length - 1) * spacing;
66
+ const startY = centerY - totalHeight / 2;
67
+ for (let i = 0; i < nodes.length; i++) {
68
+ nodes[i].x = centerX;
69
+ nodes[i].y = startY + i * spacing;
70
+ }
71
+ return nodes;
72
+ }
73
+
74
+ export {
75
+ applyCircularLayout,
76
+ calculateMinimumRadius,
77
+ calculateOptimalRadiusPercentage,
78
+ applyLinearHorizontalLayout,
79
+ applyLinearVerticalLayout
80
+ };
81
+ //# sourceMappingURL=chunk-GQMFBYLK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/layout/circularLayout.ts","../src/layout/linearLayout.ts"],"sourcesContent":["// ─── Circular Layout Algorithm ────────────────────────────────────────────────\n//\n// Positions nodes in a uniform circle with equal angular spacing.\n// PATTERN : Uniform circular distribution (polar coordinates)\n// SPACING : Equal angular intervals (2π/n)\n// ORIGIN : Configurable center (default 0, 0)\n// RADIUS : Configurable percentage of container (default 13.5%)\n\nimport type { FlatNode } from '../types/mindmap.js';\n\nexport interface CircularLayoutOptions {\n /** Radius as a fraction of the container's minimum dimension (0–1). Default: 0.135 */\n radiusPercentage?: number;\n /** Container width used to calculate absolute radius. Default: 2000 */\n containerWidth?: number;\n /** Container height used to calculate absolute radius. Default: 2000 */\n containerHeight?: number;\n /** World-space X of the circle centre. Default: 0 */\n centerX?: number;\n /** World-space Y of the circle centre. Default: 0 */\n centerY?: number;\n}\n\n/**\n * Apply circular layout to a set of nodes.\n * Mutates the `x` / `y` properties of each node and returns the same array.\n */\nexport function applyCircularLayout(\n nodes: FlatNode[],\n options: CircularLayoutOptions = {},\n): FlatNode[] {\n const {\n radiusPercentage = 0.135,\n containerWidth = 2000,\n containerHeight = 2000,\n centerX = 0,\n centerY = 0,\n } = options;\n\n if (nodes.length === 0) return nodes;\n\n if (nodes.length === 1) {\n nodes[0].x = centerX;\n nodes[0].y = centerY;\n return nodes;\n }\n\n const radius = Math.min(containerWidth, containerHeight) * radiusPercentage;\n\n // n=2 → horizontal; n≥3 → start at 12 o'clock\n const startAngle = nodes.length === 2 ? 0 : -Math.PI / 2;\n const angleStep = (2 * Math.PI) / nodes.length;\n\n for (let i = 0; i < nodes.length; i++) {\n const angle = startAngle + i * angleStep;\n nodes[i].x = centerX + radius * Math.cos(angle);\n nodes[i].y = centerY + radius * Math.sin(angle);\n }\n\n return nodes;\n}\n\n/**\n * Calculate the minimum radius needed to prevent node boxes from overlapping.\n *\n * Uses the chord-length formula: `chord = 2r · sin(θ/2)`, solved for `r`.\n */\nexport function calculateMinimumRadius(\n nodeCount: number,\n nodeWidth = 200,\n nodePadding = 150,\n): number {\n if (nodeCount <= 1) return 0;\n const angleStep = (2 * Math.PI) / nodeCount;\n const minChordLength = nodeWidth + nodePadding;\n return minChordLength / (2 * Math.sin(angleStep / 2));\n}\n\n/**\n * Calculate the optimal radius percentage for a given node count,\n * ensuring sufficient spacing for edge labels.\n *\n * @returns A value in [0.135, 0.45]\n */\nexport function calculateOptimalRadiusPercentage(\n nodeCount: number,\n containerWidth = 2000,\n containerHeight = 2000,\n nodeWidth = 200,\n nodePadding = 120,\n): number {\n const minRadius = calculateMinimumRadius(nodeCount, nodeWidth, nodePadding);\n const minDimension = Math.min(containerWidth, containerHeight);\n return Math.min(0.45, Math.max(0.135, minRadius / minDimension));\n}\n","// ─── Linear Layout Algorithms ─────────────────────────────────────────────────\n//\n// Positions nodes in a straight line without overlap, with enough gap between\n// node edges for edge-label text to render cleanly.\n//\n// linear-horizontal → left-to-right along X-axis\n// linear-vertical → top-to-bottom along Y-axis\n\nimport type { FlatNode } from '../types/mindmap.js';\n\nexport interface LinearLayoutOptions {\n /** Logical node width (px). Default: 200 */\n nodeWidth?: number;\n /** Logical node height (px). Default: 80 */\n nodeHeight?: number;\n /** Gap between node edges for horizontal layout (px). Default: 180 */\n hGap?: number;\n /** Gap between node edges for vertical layout (px). Default: 220 */\n vGap?: number;\n /** World X of the layout midpoint. Default: 0 */\n centerX?: number;\n /** World Y of the layout midpoint. Default: 0 */\n centerY?: number;\n}\n\n/**\n * Arrange nodes in a horizontal row (shared Y, varying X).\n * Row is centred on (`centerX`, `centerY`).\n */\nexport function applyLinearHorizontalLayout(\n nodes: FlatNode[],\n options: LinearLayoutOptions = {},\n): FlatNode[] {\n const { nodeWidth = 200, hGap = 180, centerX = 0, centerY = 0 } = options;\n\n if (nodes.length === 0) return nodes;\n\n if (nodes.length === 1) {\n nodes[0].x = centerX;\n nodes[0].y = centerY;\n return nodes;\n }\n\n const spacing = nodeWidth + hGap;\n const totalWidth = (nodes.length - 1) * spacing;\n const startX = centerX - totalWidth / 2;\n\n for (let i = 0; i < nodes.length; i++) {\n nodes[i].x = startX + i * spacing;\n nodes[i].y = centerY;\n }\n\n return nodes;\n}\n\n/**\n * Arrange nodes in a vertical column (shared X, varying Y).\n * Column is centred on (`centerX`, `centerY`).\n */\nexport function applyLinearVerticalLayout(\n nodes: FlatNode[],\n options: LinearLayoutOptions = {},\n): FlatNode[] {\n const { nodeHeight = 80, vGap = 220, centerX = 0, centerY = 0 } = options;\n\n if (nodes.length === 0) return nodes;\n\n if (nodes.length === 1) {\n nodes[0].x = centerX;\n nodes[0].y = centerY;\n return nodes;\n }\n\n const spacing = nodeHeight + vGap;\n const totalHeight = (nodes.length - 1) * spacing;\n const startY = centerY - totalHeight / 2;\n\n for (let i = 0; i < nodes.length; i++) {\n nodes[i].x = centerX;\n nodes[i].y = startY + i * spacing;\n }\n\n return nodes;\n}\n"],"mappings":";AA2BO,SAAS,oBACd,OACA,UAAiC,CAAC,GACtB;AACZ,QAAM;AAAA,IACJ,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,UAAU;AAAA,EACZ,IAAI;AAEJ,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,CAAC,EAAE,IAAI;AACb,UAAM,CAAC,EAAE,IAAI;AACb,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,KAAK,IAAI,gBAAgB,eAAe,IAAI;AAG3D,QAAM,aAAa,MAAM,WAAW,IAAI,IAAI,CAAC,KAAK,KAAK;AACvD,QAAM,YAAa,IAAI,KAAK,KAAM,MAAM;AAExC,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,QAAQ,aAAa,IAAI;AAC/B,UAAM,CAAC,EAAE,IAAI,UAAU,SAAS,KAAK,IAAI,KAAK;AAC9C,UAAM,CAAC,EAAE,IAAI,UAAU,SAAS,KAAK,IAAI,KAAK;AAAA,EAChD;AAEA,SAAO;AACT;AAOO,SAAS,uBACd,WACA,YAAY,KACZ,cAAc,KACN;AACR,MAAI,aAAa,EAAG,QAAO;AAC3B,QAAM,YAAa,IAAI,KAAK,KAAM;AAClC,QAAM,iBAAiB,YAAY;AACnC,SAAO,kBAAkB,IAAI,KAAK,IAAI,YAAY,CAAC;AACrD;AAQO,SAAS,iCACd,WACA,iBAAiB,KACjB,kBAAkB,KAClB,YAAY,KACZ,cAAc,KACN;AACR,QAAM,YAAY,uBAAuB,WAAW,WAAW,WAAW;AAC1E,QAAM,eAAe,KAAK,IAAI,gBAAgB,eAAe;AAC7D,SAAO,KAAK,IAAI,MAAM,KAAK,IAAI,OAAO,YAAY,YAAY,CAAC;AACjE;;;ACjEO,SAAS,4BACd,OACA,UAA+B,CAAC,GACpB;AACZ,QAAM,EAAE,YAAY,KAAK,OAAO,KAAK,UAAU,GAAG,UAAU,EAAE,IAAI;AAElE,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,CAAC,EAAE,IAAI;AACb,UAAM,CAAC,EAAE,IAAI;AACb,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,YAAY;AAC5B,QAAM,cAAc,MAAM,SAAS,KAAK;AACxC,QAAM,SAAS,UAAU,aAAa;AAEtC,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,CAAC,EAAE,IAAI,SAAS,IAAI;AAC1B,UAAM,CAAC,EAAE,IAAI;AAAA,EACf;AAEA,SAAO;AACT;AAMO,SAAS,0BACd,OACA,UAA+B,CAAC,GACpB;AACZ,QAAM,EAAE,aAAa,IAAI,OAAO,KAAK,UAAU,GAAG,UAAU,EAAE,IAAI;AAElE,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,CAAC,EAAE,IAAI;AACb,UAAM,CAAC,EAAE,IAAI;AACb,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,aAAa;AAC7B,QAAM,eAAe,MAAM,SAAS,KAAK;AACzC,QAAM,SAAS,UAAU,cAAc;AAEvC,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,CAAC,EAAE,IAAI;AACb,UAAM,CAAC,EAAE,IAAI,SAAS,IAAI;AAAA,EAC5B;AAEA,SAAO;AACT;","names":[]}
@@ -0,0 +1,108 @@
1
+ import {
2
+ FPS_TARGET,
3
+ MEMORY_TARGET_MB,
4
+ QUALITY_HIGH,
5
+ QUALITY_LOW,
6
+ QUALITY_MEDIUM
7
+ } from "./chunk-LDJRGT2Q.js";
8
+
9
+ // src/constants/renderConfig.ts
10
+ var DEFAULT_RENDER_CONFIG = {
11
+ renderMode: "canvas",
12
+ qualityLevel: "high",
13
+ cullingEnabled: false,
14
+ fpsTarget: FPS_TARGET,
15
+ memoryLimit: MEMORY_TARGET_MB
16
+ };
17
+ var SIMPLIFIED_RENDER_CONFIG = {
18
+ renderMode: "simplified",
19
+ qualityLevel: "low",
20
+ cullingEnabled: true,
21
+ fpsTarget: 30,
22
+ memoryLimit: 400
23
+ };
24
+ var QUALITY_SETTINGS = {
25
+ high: QUALITY_HIGH,
26
+ medium: QUALITY_MEDIUM,
27
+ low: QUALITY_LOW
28
+ };
29
+ var FEATURE_FLAGS = {
30
+ viewportCulling: true,
31
+ spatialIndexing: true,
32
+ shadows: true,
33
+ bezierCurves: true,
34
+ animations: true,
35
+ branchBadges: true,
36
+ autoQualityAdjustment: true,
37
+ performanceMonitoring: true,
38
+ performanceToasts: true,
39
+ debugOverlay: false,
40
+ showFPS: false,
41
+ showMemory: false,
42
+ showVisibleCount: false
43
+ };
44
+ var RENDER_MODES = {
45
+ canvas: {
46
+ name: "Canvas",
47
+ description: "Full Konva canvas rendering with all features",
48
+ features: { culling: true, shadows: true, bezierCurves: true, animations: true }
49
+ },
50
+ simplified: {
51
+ name: "Simplified",
52
+ description: "Reduced feature set for low-end devices",
53
+ features: { culling: true, shadows: false, bezierCurves: false, animations: false }
54
+ }
55
+ };
56
+ var QUALITY_LEVELS = {
57
+ high: { name: "High", description: "All visual features enabled", targetFPS: 60, features: QUALITY_HIGH },
58
+ medium: { name: "Medium", description: "Shadows disabled, other features enabled", targetFPS: 60, features: QUALITY_MEDIUM },
59
+ low: { name: "Low", description: "Minimal visual features, max performance", targetFPS: 30, features: QUALITY_LOW }
60
+ };
61
+ function getOptimalQualityLevel(currentFPS, currentQuality) {
62
+ if (currentFPS < 45 && currentQuality === "high") return "medium";
63
+ if (currentFPS < 30 && currentQuality === "medium") return "low";
64
+ if (currentFPS > 58 && currentQuality === "low") return "medium";
65
+ if (currentFPS > 58 && currentQuality === "medium") return "high";
66
+ return currentQuality;
67
+ }
68
+ function getRenderConfigForQuality(quality) {
69
+ return { qualityLevel: quality, fpsTarget: QUALITY_LEVELS[quality].targetFPS };
70
+ }
71
+ function isFeatureEnabled(featureName, config) {
72
+ if (!FEATURE_FLAGS[featureName]) return false;
73
+ const qs = QUALITY_SETTINGS[config.qualityLevel];
74
+ switch (featureName) {
75
+ case "shadows":
76
+ return qs.shadows;
77
+ case "bezierCurves":
78
+ return qs.bezierCurves;
79
+ case "animations":
80
+ return qs.animations;
81
+ default:
82
+ return FEATURE_FLAGS[featureName];
83
+ }
84
+ }
85
+ function getRecommendedRenderConfig() {
86
+ if (typeof performance === "undefined" || !performance["memory"]) {
87
+ return SIMPLIFIED_RENDER_CONFIG;
88
+ }
89
+ const memory = performance["memory"];
90
+ if (memory?.["jsHeapSizeLimit"] && memory["jsHeapSizeLimit"] < 512 * 1024 * 1024) {
91
+ return SIMPLIFIED_RENDER_CONFIG;
92
+ }
93
+ return DEFAULT_RENDER_CONFIG;
94
+ }
95
+
96
+ export {
97
+ DEFAULT_RENDER_CONFIG,
98
+ SIMPLIFIED_RENDER_CONFIG,
99
+ QUALITY_SETTINGS,
100
+ FEATURE_FLAGS,
101
+ RENDER_MODES,
102
+ QUALITY_LEVELS,
103
+ getOptimalQualityLevel,
104
+ getRenderConfigForQuality,
105
+ isFeatureEnabled,
106
+ getRecommendedRenderConfig
107
+ };
108
+ //# sourceMappingURL=chunk-I75TMOE4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/constants/renderConfig.ts"],"sourcesContent":["// ─── Render Configuration ─────────────────────────────────────────────────────\n\nimport type { RenderConfig } from '../types/mindmap.js';\nimport {\n FPS_TARGET,\n MEMORY_TARGET_MB,\n QUALITY_HIGH,\n QUALITY_MEDIUM,\n QUALITY_LOW,\n NODE_COUNT_THRESHOLDS,\n} from './performanceConstants.js';\n\n// ── Defaults ──────────────────────────────────────────────────────────────────\n\nexport const DEFAULT_RENDER_CONFIG: RenderConfig = {\n renderMode: 'canvas',\n qualityLevel: 'high',\n cullingEnabled: false,\n fpsTarget: FPS_TARGET,\n memoryLimit: MEMORY_TARGET_MB,\n};\n\nexport const SIMPLIFIED_RENDER_CONFIG: RenderConfig = {\n renderMode: 'simplified',\n qualityLevel: 'low',\n cullingEnabled: true,\n fpsTarget: 30,\n memoryLimit: 400,\n};\n\n// ── Quality Map ───────────────────────────────────────────────────────────────\n\nexport const QUALITY_SETTINGS = {\n high: QUALITY_HIGH,\n medium: QUALITY_MEDIUM,\n low: QUALITY_LOW,\n} as const;\n\n// ── Feature Flags ─────────────────────────────────────────────────────────────\n\nexport const FEATURE_FLAGS = {\n viewportCulling: true,\n spatialIndexing: true,\n shadows: true,\n bezierCurves: true,\n animations: true,\n branchBadges: true,\n autoQualityAdjustment: true,\n performanceMonitoring: true,\n performanceToasts: true,\n debugOverlay: false,\n showFPS: false,\n showMemory: false,\n showVisibleCount: false,\n} as const;\n\n// ── Render Modes ──────────────────────────────────────────────────────────────\n\nexport type RenderMode = RenderConfig['renderMode'];\nexport type QualityLevel = RenderConfig['qualityLevel'];\n\nexport const RENDER_MODES = {\n canvas: {\n name: 'Canvas',\n description: 'Full Konva canvas rendering with all features',\n features: { culling: true, shadows: true, bezierCurves: true, animations: true },\n },\n simplified: {\n name: 'Simplified',\n description: 'Reduced feature set for low-end devices',\n features: { culling: true, shadows: false, bezierCurves: false, animations: false },\n },\n} as const;\n\nexport const QUALITY_LEVELS = {\n high: { name: 'High', description: 'All visual features enabled', targetFPS: 60, features: QUALITY_HIGH },\n medium: { name: 'Medium', description: 'Shadows disabled, other features enabled', targetFPS: 60, features: QUALITY_MEDIUM },\n low: { name: 'Low', description: 'Minimal visual features, max performance', targetFPS: 30, features: QUALITY_LOW },\n} as const;\n\n// ── Auto-Adjustment Helpers ───────────────────────────────────────────────────\n\nexport function getOptimalQualityLevel(\n currentFPS: number,\n currentQuality: QualityLevel,\n): QualityLevel {\n if (currentFPS < 45 && currentQuality === 'high') return 'medium';\n if (currentFPS < 30 && currentQuality === 'medium') return 'low';\n if (currentFPS > 58 && currentQuality === 'low') return 'medium';\n if (currentFPS > 58 && currentQuality === 'medium') return 'high';\n return currentQuality;\n}\n\nexport function getRenderConfigForQuality(quality: QualityLevel): Partial<RenderConfig> {\n return { qualityLevel: quality, fpsTarget: QUALITY_LEVELS[quality].targetFPS };\n}\n\nexport function isFeatureEnabled(\n featureName: keyof typeof FEATURE_FLAGS,\n config: RenderConfig,\n): boolean {\n if (!FEATURE_FLAGS[featureName]) return false;\n\n const qs = QUALITY_SETTINGS[config.qualityLevel];\n switch (featureName) {\n case 'shadows': return qs.shadows;\n case 'bezierCurves': return qs.bezierCurves;\n case 'animations': return qs.animations;\n default: return FEATURE_FLAGS[featureName] as boolean;\n }\n}\n\n// ── Device Detection ──────────────────────────────────────────────────────────\n\n/**\n * Recommend a render config based on detected device memory (browser only).\n * Falls back to SIMPLIFIED_RENDER_CONFIG when the Performance Memory API is\n * unavailable or memory is constrained.\n */\nexport function getRecommendedRenderConfig(): RenderConfig {\n if (typeof performance === 'undefined' || !(performance as unknown as Record<string, unknown>)['memory']) {\n return SIMPLIFIED_RENDER_CONFIG;\n }\n\n const memory = (performance as unknown as Record<string, unknown>)['memory'] as Record<string, number>;\n if (memory?.['jsHeapSizeLimit'] && memory['jsHeapSizeLimit'] < 512 * 1024 * 1024) {\n return SIMPLIFIED_RENDER_CONFIG;\n }\n\n return DEFAULT_RENDER_CONFIG;\n}\n\n/** Re-export so consumers need only one import. */\nexport { NODE_COUNT_THRESHOLDS };\n"],"mappings":";;;;;;;;;AAcO,IAAM,wBAAsC;AAAA,EACjD,YAAe;AAAA,EACf,cAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,WAAe;AAAA,EACf,aAAe;AACjB;AAEO,IAAM,2BAAyC;AAAA,EACpD,YAAe;AAAA,EACf,cAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,WAAe;AAAA,EACf,aAAe;AACjB;AAIO,IAAM,mBAAmB;AAAA,EAC9B,MAAQ;AAAA,EACR,QAAQ;AAAA,EACR,KAAQ;AACV;AAIO,IAAM,gBAAgB;AAAA,EAC3B,iBAAwB;AAAA,EACxB,iBAAwB;AAAA,EACxB,SAAwB;AAAA,EACxB,cAAwB;AAAA,EACxB,YAAwB;AAAA,EACxB,cAAwB;AAAA,EACxB,uBAAwB;AAAA,EACxB,uBAAwB;AAAA,EACxB,mBAAwB;AAAA,EACxB,cAAwB;AAAA,EACxB,SAAwB;AAAA,EACxB,YAAwB;AAAA,EACxB,kBAAwB;AAC1B;AAOO,IAAM,eAAe;AAAA,EAC1B,QAAQ;AAAA,IACN,MAAa;AAAA,IACb,aAAa;AAAA,IACb,UAAa,EAAE,SAAS,MAAM,SAAS,MAAM,cAAc,MAAM,YAAY,KAAK;AAAA,EACpF;AAAA,EACA,YAAY;AAAA,IACV,MAAa;AAAA,IACb,aAAa;AAAA,IACb,UAAa,EAAE,SAAS,MAAM,SAAS,OAAO,cAAc,OAAO,YAAY,MAAM;AAAA,EACvF;AACF;AAEO,IAAM,iBAAiB;AAAA,EAC5B,MAAQ,EAAE,MAAM,QAAU,aAAa,+BAA4C,WAAW,IAAI,UAAU,aAAe;AAAA,EAC3H,QAAQ,EAAE,MAAM,UAAU,aAAa,4CAA4C,WAAW,IAAI,UAAU,eAAe;AAAA,EAC3H,KAAQ,EAAE,MAAM,OAAU,aAAa,4CAA4C,WAAW,IAAI,UAAU,YAAe;AAC7H;AAIO,SAAS,uBACd,YACA,gBACc;AACd,MAAI,aAAa,MAAM,mBAAmB,OAAU,QAAO;AAC3D,MAAI,aAAa,MAAM,mBAAmB,SAAU,QAAO;AAC3D,MAAI,aAAa,MAAM,mBAAmB,MAAU,QAAO;AAC3D,MAAI,aAAa,MAAM,mBAAmB,SAAU,QAAO;AAC3D,SAAO;AACT;AAEO,SAAS,0BAA0B,SAA8C;AACtF,SAAO,EAAE,cAAc,SAAS,WAAW,eAAe,OAAO,EAAE,UAAU;AAC/E;AAEO,SAAS,iBACd,aACA,QACS;AACT,MAAI,CAAC,cAAc,WAAW,EAAG,QAAO;AAExC,QAAM,KAAK,iBAAiB,OAAO,YAAY;AAC/C,UAAQ,aAAa;AAAA,IACnB,KAAK;AAAgB,aAAO,GAAG;AAAA,IAC/B,KAAK;AAAgB,aAAO,GAAG;AAAA,IAC/B,KAAK;AAAgB,aAAO,GAAG;AAAA,IAC/B;AAAqB,aAAO,cAAc,WAAW;AAAA,EACvD;AACF;AASO,SAAS,6BAA2C;AACzD,MAAI,OAAO,gBAAgB,eAAe,CAAE,YAAmD,QAAQ,GAAG;AACxG,WAAO;AAAA,EACT;AAEA,QAAM,SAAU,YAAmD,QAAQ;AAC3E,MAAI,SAAS,iBAAiB,KAAK,OAAO,iBAAiB,IAAI,MAAM,OAAO,MAAM;AAChF,WAAO;AAAA,EACT;AAEA,SAAO;AACT;","names":[]}