@class-kit/core 0.1.1 → 0.1.2

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.
package/dist/index.cjs CHANGED
@@ -348,13 +348,44 @@ class FormController {
348
348
  }
349
349
  }
350
350
 
351
+ function normalizeRows(value, fallback) {
352
+ if (typeof value !== "number" || !Number.isFinite(value))
353
+ return fallback;
354
+ return Math.max(1, Math.floor(value));
355
+ }
356
+ class ChatTextareaController {
357
+ constructor(options = {}) {
358
+ this.state = this.normalize(options);
359
+ }
360
+ getState() {
361
+ return { ...this.state };
362
+ }
363
+ setValue(value) {
364
+ this.state = this.normalize({ ...this.state, value });
365
+ return this.getState();
366
+ }
367
+ update(options = {}) {
368
+ this.state = this.normalize({ ...this.state, ...options });
369
+ return this.getState();
370
+ }
371
+ normalize(options) {
372
+ const minRows = normalizeRows(options.minRows, 1);
373
+ const maxRows = Math.max(minRows, normalizeRows(options.maxRows, 3));
374
+ return {
375
+ maxRows,
376
+ minRows,
377
+ value: String(options.value ?? ""),
378
+ };
379
+ }
380
+ }
381
+
351
382
  const builtInThemeNames = [
352
383
  "minimal",
353
- "violet",
354
- "emerald",
355
- "sky",
356
- "rose",
357
- "amber",
384
+ "business-blue",
385
+ "dark-tech",
386
+ "soft-pink",
387
+ "creative-purple",
388
+ "cartoon-3d",
358
389
  "liquid-glass",
359
390
  ];
360
391
  const defaultLocale = {
@@ -749,11 +780,11 @@ function hsvToRgb(hue, saturation, brightness) {
749
780
  };
750
781
  }
751
782
  class ColorPickerController {
752
- constructor(value = "#7c3aed") {
783
+ constructor(value = "#1d2129") {
753
784
  this.state = this.parse(value);
754
785
  }
755
786
  parse(value) {
756
- const parsed = parseRgb(value) ?? parseHex(value) ?? parseHex("#7c3aed");
787
+ const parsed = parseRgb(value) ?? parseHex(value) ?? parseHex("#1d2129");
757
788
  const hsv = rgbToHsv(parsed.red, parsed.green, parsed.blue);
758
789
  const rgba = formatRgba(parsed.red, parsed.green, parsed.blue, parsed.alpha);
759
790
  return { ...parsed, ...hsv, contrastColor: getContrastColor(parsed.red, parsed.green, parsed.blue, parsed.alpha), rgba, value: rgba };
@@ -1074,7 +1105,7 @@ const DEFAULT_TOLERANCE = 6;
1074
1105
  function finiteNumber(value, fallback) {
1075
1106
  return Number.isFinite(value) ? Number(value) : fallback;
1076
1107
  }
1077
- function clamp$c(value, min, max) {
1108
+ function clamp$d(value, min, max) {
1078
1109
  return Math.min(max, Math.max(min, value));
1079
1110
  }
1080
1111
  class SlideCaptchaController {
@@ -1127,10 +1158,10 @@ class SlideCaptchaController {
1127
1158
  this.offsetY = this.value && this.moveAxis === "xy" ? this.targetY - this.originY : 0;
1128
1159
  }
1129
1160
  else {
1130
- this.offsetX = clamp$c(this.offsetX, 0, this.getMaxOffset());
1161
+ this.offsetX = clamp$d(this.offsetX, 0, this.getMaxOffset());
1131
1162
  this.offsetY =
1132
1163
  this.moveAxis === "xy"
1133
- ? clamp$c(this.offsetY, this.getMinOffsetY(), this.getMaxOffsetY())
1164
+ ? clamp$d(this.offsetY, this.getMinOffsetY(), this.getMaxOffsetY())
1134
1165
  : 0;
1135
1166
  }
1136
1167
  return this.getState();
@@ -1144,10 +1175,10 @@ class SlideCaptchaController {
1144
1175
  move(offsetX, offsetY = 0) {
1145
1176
  if (this.value)
1146
1177
  return this.getState();
1147
- this.offsetX = clamp$c(finiteNumber(offsetX, 0), 0, this.getMaxOffset());
1178
+ this.offsetX = clamp$d(finiteNumber(offsetX, 0), 0, this.getMaxOffset());
1148
1179
  this.offsetY =
1149
1180
  this.moveAxis === "xy"
1150
- ? clamp$c(finiteNumber(offsetY, 0), this.getMinOffsetY(), this.getMaxOffsetY())
1181
+ ? clamp$d(finiteNumber(offsetY, 0), this.getMinOffsetY(), this.getMaxOffsetY())
1151
1182
  : 0;
1152
1183
  this.status = "dragging";
1153
1184
  return this.getState();
@@ -1205,13 +1236,13 @@ class SlideCaptchaController {
1205
1236
  return Math.max(this.getMinOffsetY(), this.height - this.pieceHeight - this.originY);
1206
1237
  }
1207
1238
  normalizeOriginY(value) {
1208
- return clamp$c(finiteNumber(value, 0), 0, Math.max(0, this.height - this.pieceHeight));
1239
+ return clamp$d(finiteNumber(value, 0), 0, Math.max(0, this.height - this.pieceHeight));
1209
1240
  }
1210
1241
  normalizeTargetX(value) {
1211
- return clamp$c(finiteNumber(value, this.width * 0.62), 0, this.getMaxOffset());
1242
+ return clamp$d(finiteNumber(value, this.width * 0.62), 0, this.getMaxOffset());
1212
1243
  }
1213
1244
  normalizeTargetY(value) {
1214
- return clamp$c(finiteNumber(value, this.originY), 0, Math.max(0, this.height - this.pieceHeight));
1245
+ return clamp$d(finiteNumber(value, this.originY), 0, Math.max(0, this.height - this.pieceHeight));
1215
1246
  }
1216
1247
  }
1217
1248
 
@@ -1316,7 +1347,7 @@ class ModalController {
1316
1347
  }
1317
1348
  }
1318
1349
 
1319
- function clamp$b(value, min, max) {
1350
+ function clamp$c(value, min, max) {
1320
1351
  return Math.min(max, Math.max(min, value));
1321
1352
  }
1322
1353
  class FloatingBallController {
@@ -1391,8 +1422,8 @@ class FloatingBallController {
1391
1422
  }
1392
1423
  clampToViewport(position, viewport, size) {
1393
1424
  return {
1394
- x: clamp$b(position.x, this.gap, Math.max(this.gap, viewport.width - size.width - this.gap)),
1395
- y: clamp$b(position.y, this.gap, Math.max(this.gap, viewport.height - size.height - this.gap))
1425
+ x: clamp$c(position.x, this.gap, Math.max(this.gap, viewport.width - size.width - this.gap)),
1426
+ y: clamp$c(position.y, this.gap, Math.max(this.gap, viewport.height - size.height - this.gap))
1396
1427
  };
1397
1428
  }
1398
1429
  }
@@ -1529,10 +1560,11 @@ function createId() {
1529
1560
  return `toast-${Date.now()}-${Math.random().toString(16).slice(2)}`;
1530
1561
  }
1531
1562
  class ToastManager {
1532
- constructor() {
1563
+ constructor(options = {}) {
1533
1564
  this.emitter = new StateEmitter();
1534
1565
  this.timers = new Map();
1535
1566
  this.items = [];
1567
+ this.maxVisible = normalizeMaxVisible(options.maxVisible);
1536
1568
  }
1537
1569
  getToasts() {
1538
1570
  return [...this.items];
@@ -1546,7 +1578,7 @@ class ToastManager {
1546
1578
  duration: options.duration ?? 3000,
1547
1579
  position: options.position ?? "top-right",
1548
1580
  };
1549
- this.items = [toast, ...this.items.filter((item) => item.id !== toast.id)];
1581
+ this.items = this.limitByPosition([...this.items.filter((item) => item.id !== toast.id), toast], toast.position, normalizeMaxVisible(options.maxVisible ?? this.maxVisible));
1550
1582
  this.scheduleDismiss(toast);
1551
1583
  this.notify();
1552
1584
  return toast.id;
@@ -1580,6 +1612,26 @@ class ToastManager {
1580
1612
  notify() {
1581
1613
  this.emitter.emit(this.getToasts());
1582
1614
  }
1615
+ limitByPosition(items, position, maxVisible) {
1616
+ const positionItems = items.filter((item) => item.position === position);
1617
+ if (positionItems.length <= maxVisible)
1618
+ return items;
1619
+ const overflowIds = new Set(positionItems
1620
+ .slice(0, Math.max(0, positionItems.length - maxVisible))
1621
+ .map((item) => item.id));
1622
+ overflowIds.forEach((id) => {
1623
+ const timer = this.timers.get(id);
1624
+ if (timer)
1625
+ clearTimeout(timer);
1626
+ this.timers.delete(id);
1627
+ });
1628
+ return items.filter((item) => !overflowIds.has(item.id));
1629
+ }
1630
+ }
1631
+ function normalizeMaxVisible(maxVisible) {
1632
+ if (typeof maxVisible !== "number" || !Number.isFinite(maxVisible))
1633
+ return 3;
1634
+ return Math.max(1, Math.min(6, Math.floor(maxVisible)));
1583
1635
  }
1584
1636
 
1585
1637
  function getSafeTooltipPlacement(triggerRect, tooltipRect, preferred, viewportWidth = window.innerWidth, viewportHeight = window.innerHeight, margin = 8) {
@@ -1703,6 +1755,124 @@ class PaginationController {
1703
1755
  }
1704
1756
  }
1705
1757
 
1758
+ function normalizeItems$2(items = [], level = 0) {
1759
+ return items
1760
+ .filter((item) => item &&
1761
+ String(item.key || "").trim() &&
1762
+ String(item.label || "").trim())
1763
+ .map((item) => ({
1764
+ children: normalizeItems$2(item.children ?? [], level + 1),
1765
+ disabled: Boolean(item.disabled),
1766
+ expanded: false,
1767
+ icon: item.icon,
1768
+ isActive: false,
1769
+ key: String(item.key),
1770
+ label: String(item.label),
1771
+ level,
1772
+ }));
1773
+ }
1774
+ function collectParentKeys(items, activeKey, parents = []) {
1775
+ for (const item of items) {
1776
+ if (item.key === activeKey)
1777
+ return parents;
1778
+ const matched = collectParentKeys(item.children, activeKey, [
1779
+ ...parents,
1780
+ item.key,
1781
+ ]);
1782
+ if (matched.length > 0)
1783
+ return matched;
1784
+ }
1785
+ return [];
1786
+ }
1787
+ function markItems(items, activeKey, expandedKeys) {
1788
+ return items.map((item) => ({
1789
+ ...item,
1790
+ children: markItems(item.children, activeKey, expandedKeys),
1791
+ expanded: expandedKeys.has(item.key),
1792
+ isActive: item.key === activeKey,
1793
+ }));
1794
+ }
1795
+ function hasItem(items, key) {
1796
+ if (!key)
1797
+ return false;
1798
+ for (const item of items) {
1799
+ if (item.key === key)
1800
+ return true;
1801
+ if (hasItem(item.children, key))
1802
+ return true;
1803
+ }
1804
+ return false;
1805
+ }
1806
+ class MenuController {
1807
+ constructor(options = {}) {
1808
+ this.items = normalizeItems$2(options.items);
1809
+ this.activeKey = hasItem(this.items, options.activeKey)
1810
+ ? options.activeKey
1811
+ : undefined;
1812
+ this.collapsed = Boolean(options.collapsed);
1813
+ this.expandedKeys = new Set(options.defaultExpandedKeys?.map(String) ?? []);
1814
+ collectParentKeys(this.items, this.activeKey).forEach((key) => this.expandedKeys.add(key));
1815
+ }
1816
+ activate(key) {
1817
+ const item = this.findItem(key);
1818
+ if (!item || item.disabled)
1819
+ return this.getState();
1820
+ this.activeKey = key;
1821
+ collectParentKeys(this.items, key).forEach((parentKey) => this.expandedKeys.add(parentKey));
1822
+ return this.getState();
1823
+ }
1824
+ findItem(key, items = this.items) {
1825
+ for (const item of items) {
1826
+ if (item.key === key)
1827
+ return item;
1828
+ const matched = this.findItem(key, item.children);
1829
+ if (matched)
1830
+ return matched;
1831
+ }
1832
+ return undefined;
1833
+ }
1834
+ getState() {
1835
+ return {
1836
+ activeKey: this.activeKey,
1837
+ collapsed: this.collapsed,
1838
+ expandedKeys: [...this.expandedKeys],
1839
+ items: markItems(this.items, this.activeKey, this.expandedKeys),
1840
+ };
1841
+ }
1842
+ setCollapsed(collapsed) {
1843
+ this.collapsed = Boolean(collapsed);
1844
+ return this.getState();
1845
+ }
1846
+ toggleCollapsed() {
1847
+ this.collapsed = !this.collapsed;
1848
+ return this.getState();
1849
+ }
1850
+ toggleExpanded(key) {
1851
+ const item = this.findItem(key);
1852
+ if (!item || item.disabled || item.children.length === 0)
1853
+ return this.getState();
1854
+ if (this.expandedKeys.has(key))
1855
+ this.expandedKeys.delete(key);
1856
+ else
1857
+ this.expandedKeys.add(key);
1858
+ return this.getState();
1859
+ }
1860
+ update(options = {}) {
1861
+ if (options.items)
1862
+ this.items = normalizeItems$2(options.items);
1863
+ if (options.activeKey !== undefined)
1864
+ this.activeKey = options.activeKey;
1865
+ if (!hasItem(this.items, this.activeKey))
1866
+ this.activeKey = undefined;
1867
+ if (options.collapsed !== undefined)
1868
+ this.collapsed = Boolean(options.collapsed);
1869
+ if (options.defaultExpandedKeys)
1870
+ this.expandedKeys = new Set(options.defaultExpandedKeys.map(String));
1871
+ collectParentKeys(this.items, this.activeKey).forEach((key) => this.expandedKeys.add(key));
1872
+ return this.getState();
1873
+ }
1874
+ }
1875
+
1706
1876
  class BadgeController {
1707
1877
  constructor(options = {}) {
1708
1878
  this.state = this.normalize(options);
@@ -1760,20 +1930,20 @@ const DEFAULT_NODE_WIDTH = 160;
1760
1930
  const DEFAULT_NODE_HEIGHT = 64;
1761
1931
  const DEFAULT_GAP_X = 220;
1762
1932
  const MIN_NODE_GAP_Y = 4;
1763
- function clamp$a(value, min, max) {
1933
+ function clamp$b(value, min, max) {
1764
1934
  return Math.min(max, Math.max(min, value));
1765
1935
  }
1766
- function finiteOr$3(value, fallback) {
1936
+ function finiteOr$5(value, fallback) {
1767
1937
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
1768
1938
  }
1769
1939
  function estimateNodeWidth(node) {
1770
1940
  if (node.width !== undefined)
1771
- return clamp$a(finiteOr$3(node.width, DEFAULT_NODE_WIDTH), MIN_NODE_WIDTH, MAX_NODE_WIDTH);
1941
+ return clamp$b(finiteOr$5(node.width, DEFAULT_NODE_WIDTH), MIN_NODE_WIDTH, MAX_NODE_WIDTH);
1772
1942
  const title = String(node.title || " ");
1773
1943
  const contentLines = String(node.content ?? "").split(/\r?\n/);
1774
1944
  const longestContentLine = contentLines.reduce((max, line) => Math.max(max, line.length), 0);
1775
1945
  const longestLine = Math.max(title.length, longestContentLine);
1776
- return clamp$a(Math.ceil(longestLine * 7.2 + 24), MIN_NODE_WIDTH, MAX_NODE_WIDTH);
1946
+ return clamp$b(Math.ceil(longestLine * 7.2 + 24), MIN_NODE_WIDTH, MAX_NODE_WIDTH);
1777
1947
  }
1778
1948
  function estimateNodeHeight(node) {
1779
1949
  const width = estimateNodeWidth(node);
@@ -1800,12 +1970,12 @@ function createDefaultNodes() {
1800
1970
  }
1801
1971
  function normalizeViewport(viewport) {
1802
1972
  return {
1803
- x: finiteOr$3(viewport?.x, 0),
1804
- y: finiteOr$3(viewport?.y, 0),
1805
- zoom: clamp$a(finiteOr$3(viewport?.zoom, 1), 0.35, 2.4)
1973
+ x: finiteOr$5(viewport?.x, 0),
1974
+ y: finiteOr$5(viewport?.y, 0),
1975
+ zoom: clamp$b(finiteOr$5(viewport?.zoom, 1), 0.35, 2.4)
1806
1976
  };
1807
1977
  }
1808
- function normalizeMode(mode) {
1978
+ function normalizeMode$1(mode) {
1809
1979
  return mode === "mind" ? "mind" : "document";
1810
1980
  }
1811
1981
  function cloneNode(node) {
@@ -1872,7 +2042,7 @@ function getRootId(nodes, rootId) {
1872
2042
  class CanvasEditorController {
1873
2043
  constructor(options = {}) {
1874
2044
  this.idSeed = 0;
1875
- this.mode = normalizeMode(options.mode);
2045
+ this.mode = normalizeMode$1(options.mode);
1876
2046
  this.nodes = normalizeNodes(options.nodes);
1877
2047
  this.rootId = getRootId(this.nodes, options.rootId);
1878
2048
  this.viewport = normalizeViewport(options.viewport);
@@ -1881,7 +2051,7 @@ class CanvasEditorController {
1881
2051
  }
1882
2052
  updateOptions(options = {}) {
1883
2053
  if (options.mode)
1884
- this.mode = normalizeMode(options.mode);
2054
+ this.mode = normalizeMode$1(options.mode);
1885
2055
  if (options.nodes) {
1886
2056
  this.nodes = normalizeNodes(options.nodes);
1887
2057
  this.rootId = getRootId(this.nodes, options.rootId ?? this.rootId);
@@ -1898,7 +2068,7 @@ class CanvasEditorController {
1898
2068
  return this.getState();
1899
2069
  }
1900
2070
  setMode(mode) {
1901
- this.mode = normalizeMode(mode);
2071
+ this.mode = normalizeMode$1(mode);
1902
2072
  return this.getState();
1903
2073
  }
1904
2074
  select(id) {
@@ -1932,7 +2102,7 @@ class CanvasEditorController {
1932
2102
  ...(input.x !== undefined ? { x: input.x } : {}),
1933
2103
  ...(input.y !== undefined ? { y: input.y } : {})
1934
2104
  };
1935
- nextNode.height = finiteOr$3(input.height, estimateNodeHeight(nextNode));
2105
+ nextNode.height = finiteOr$5(input.height, estimateNodeHeight(nextNode));
1936
2106
  this.nodes = this.nodes
1937
2107
  .map((node) => node.id === parentId ? { ...node, children: [...(node.children ?? []), id] } : node)
1938
2108
  .concat(nextNode);
@@ -1970,8 +2140,8 @@ class CanvasEditorController {
1970
2140
  this.nodes = this.nodes.map((node) => node.id === input.id
1971
2141
  ? {
1972
2142
  ...node,
1973
- x: finiteOr$3(node.x, 0) + input.deltaX / zoom,
1974
- y: finiteOr$3(node.y, 0) + input.deltaY / zoom
2143
+ x: finiteOr$5(node.x, 0) + input.deltaX / zoom,
2144
+ y: finiteOr$5(node.y, 0) + input.deltaY / zoom
1975
2145
  }
1976
2146
  : node);
1977
2147
  return this.getState();
@@ -1991,7 +2161,7 @@ class CanvasEditorController {
1991
2161
  return this.getState();
1992
2162
  this.viewport = {
1993
2163
  ...this.viewport,
1994
- zoom: clamp$a(this.viewport.zoom + delta, 0.35, 2.4)
2164
+ zoom: clamp$b(this.viewport.zoom + delta, 0.35, 2.4)
1995
2165
  };
1996
2166
  return this.getState();
1997
2167
  }
@@ -2039,7 +2209,7 @@ class CanvasEditorController {
2039
2209
  depthById.set(id, depth);
2040
2210
  const children = (node.children ?? []).filter((childId) => nodeMap.has(childId));
2041
2211
  const width = estimateNodeWidth(node);
2042
- const height = Math.max(finiteOr$3(node.height, DEFAULT_NODE_HEIGHT), estimateNodeHeight({ ...node, width }));
2212
+ const height = Math.max(finiteOr$5(node.height, DEFAULT_NODE_HEIGHT), estimateNodeHeight({ ...node, width }));
2043
2213
  const startY = offsetY;
2044
2214
  let nextY = offsetY;
2045
2215
  children.forEach((childId, index) => {
@@ -2047,7 +2217,7 @@ class CanvasEditorController {
2047
2217
  });
2048
2218
  const endY = children.length > 0 ? nextY - MIN_NODE_GAP_Y : startY;
2049
2219
  const fallbackY = children.length > 0 ? (startY + endY) / 2 : startY;
2050
- const y = finiteOr$3(node.y, children.length > 0 ? fallbackY - height / 2 : siblingIndex === 0 && depth === 0 ? 0 : offsetY);
2220
+ const y = finiteOr$5(node.y, children.length > 0 ? fallbackY - height / 2 : siblingIndex === 0 && depth === 0 ? 0 : offsetY);
2051
2221
  result.push({
2052
2222
  ...node,
2053
2223
  height,
@@ -2062,13 +2232,13 @@ class CanvasEditorController {
2062
2232
  if (!visited.has(node.id)) {
2063
2233
  depthById.set(node.id, 0);
2064
2234
  const width = estimateNodeWidth(node);
2065
- const height = Math.max(finiteOr$3(node.height, DEFAULT_NODE_HEIGHT), estimateNodeHeight({ ...node, width }));
2235
+ const height = Math.max(finiteOr$5(node.height, DEFAULT_NODE_HEIGHT), estimateNodeHeight({ ...node, width }));
2066
2236
  result.push({
2067
2237
  ...node,
2068
2238
  height,
2069
2239
  width,
2070
2240
  x: 0,
2071
- y: finiteOr$3(node.y, result.length * (height + MIN_NODE_GAP_Y))
2241
+ y: finiteOr$5(node.y, result.length * (height + MIN_NODE_GAP_Y))
2072
2242
  });
2073
2243
  }
2074
2244
  });
@@ -2085,12 +2255,12 @@ class CanvasEditorController {
2085
2255
  });
2086
2256
  groups.forEach((group) => {
2087
2257
  group
2088
- .sort((a, b) => finiteOr$3(a.y, 0) - finiteOr$3(b.y, 0))
2258
+ .sort((a, b) => finiteOr$5(a.y, 0) - finiteOr$5(b.y, 0))
2089
2259
  .reduce((nextY, node) => {
2090
- const currentY = finiteOr$3(node.y, nextY);
2260
+ const currentY = finiteOr$5(node.y, nextY);
2091
2261
  const y = Math.max(currentY, nextY);
2092
2262
  node.y = y;
2093
- return y + finiteOr$3(node.height, DEFAULT_NODE_HEIGHT) + MIN_NODE_GAP_Y;
2263
+ return y + finiteOr$5(node.height, DEFAULT_NODE_HEIGHT) + MIN_NODE_GAP_Y;
2094
2264
  }, Number.NEGATIVE_INFINITY);
2095
2265
  });
2096
2266
  return nextNodes;
@@ -2103,10 +2273,10 @@ class CanvasEditorController {
2103
2273
  const child = nodeMap.get(childId);
2104
2274
  if (!child)
2105
2275
  return;
2106
- const fromX = finiteOr$3(node.x, 0) + finiteOr$3(node.width, DEFAULT_NODE_WIDTH);
2107
- const fromY = finiteOr$3(node.y, 0) + finiteOr$3(node.height, DEFAULT_NODE_HEIGHT) / 2;
2108
- const toX = finiteOr$3(child.x, 0);
2109
- const toY = finiteOr$3(child.y, 0) + finiteOr$3(child.height, DEFAULT_NODE_HEIGHT) / 2;
2276
+ const fromX = finiteOr$5(node.x, 0) + finiteOr$5(node.width, DEFAULT_NODE_WIDTH);
2277
+ const fromY = finiteOr$5(node.y, 0) + finiteOr$5(node.height, DEFAULT_NODE_HEIGHT) / 2;
2278
+ const toX = finiteOr$5(child.x, 0);
2279
+ const toY = finiteOr$5(child.y, 0) + finiteOr$5(child.height, DEFAULT_NODE_HEIGHT) / 2;
2110
2280
  const curve = Math.max(48, Math.abs(toX - fromX) * 0.45);
2111
2281
  links.push({
2112
2282
  d: `M ${fromX} ${fromY} C ${fromX + curve} ${fromY}, ${toX - curve} ${toY}, ${toX} ${toY}`,
@@ -2119,17 +2289,17 @@ class CanvasEditorController {
2119
2289
  }
2120
2290
  }
2121
2291
 
2122
- function finiteOr$2(value, fallback) {
2292
+ function finiteOr$4(value, fallback) {
2123
2293
  return Number.isFinite(value) ? Number(value) : fallback;
2124
2294
  }
2125
- function clamp$9(value, min, max) {
2295
+ function clamp$a(value, min, max) {
2126
2296
  return Math.min(max, Math.max(min, value));
2127
2297
  }
2128
2298
  function normalizeDpr(value) {
2129
- return clamp$9(finiteOr$2(value, 1), 1, 4);
2299
+ return clamp$a(finiteOr$4(value, 1), 1, 4);
2130
2300
  }
2131
2301
  function roundedRect(ctx, x, y, width, height, radius = 0) {
2132
- const r = clamp$9(radius, 0, Math.min(width, height) / 2);
2302
+ const r = clamp$a(radius, 0, Math.min(width, height) / 2);
2133
2303
  ctx.beginPath();
2134
2304
  ctx.moveTo(x + r, y);
2135
2305
  ctx.lineTo(x + width - r, y);
@@ -2145,7 +2315,7 @@ function roundedRect(ctx, x, y, width, height, radius = 0) {
2145
2315
  function createFont(layer) {
2146
2316
  const style = layer.fontStyle ?? "normal";
2147
2317
  const weight = layer.fontWeight ?? 500;
2148
- const size = finiteOr$2(layer.fontSize, 16);
2318
+ const size = finiteOr$4(layer.fontSize, 16);
2149
2319
  const family = layer.fontFamily ?? "Inter, system-ui, -apple-system, BlinkMacSystemFont, sans-serif";
2150
2320
  return `${style} ${weight} ${size}px ${family}`;
2151
2321
  }
@@ -2197,9 +2367,9 @@ class CanvasImageController {
2197
2367
  return {
2198
2368
  background: this.options.background ?? "transparent",
2199
2369
  dpr: normalizeDpr(this.options.dpr),
2200
- height: Math.max(1, finiteOr$2(this.options.height, 1)),
2370
+ height: Math.max(1, finiteOr$4(this.options.height, 1)),
2201
2371
  layerCount: this.options.layers?.length ?? 0,
2202
- width: Math.max(1, finiteOr$2(this.options.width, 1))
2372
+ width: Math.max(1, finiteOr$4(this.options.width, 1))
2203
2373
  };
2204
2374
  }
2205
2375
  async draw(canvas) {
@@ -2224,7 +2394,7 @@ class CanvasImageController {
2224
2394
  }
2225
2395
  async drawLayer(ctx, layer) {
2226
2396
  ctx.save();
2227
- ctx.globalAlpha = clamp$9(layer.opacity ?? 1, 0, 1);
2397
+ ctx.globalAlpha = clamp$a(layer.opacity ?? 1, 0, 1);
2228
2398
  if (layer.rotate) {
2229
2399
  ctx.translate(layer.x, layer.y);
2230
2400
  ctx.rotate((layer.rotate * Math.PI) / 180);
@@ -2247,7 +2417,7 @@ class CanvasImageController {
2247
2417
  ctx.fillStyle = layer.color ?? "#111827";
2248
2418
  ctx.textAlign = layer.textAlign ?? "left";
2249
2419
  ctx.textBaseline = layer.textBaseline ?? "top";
2250
- const lineHeight = finiteOr$2(layer.lineHeight, finiteOr$2(layer.fontSize, 16) * 1.4);
2420
+ const lineHeight = finiteOr$4(layer.lineHeight, finiteOr$4(layer.fontSize, 16) * 1.4);
2251
2421
  const lines = layer.wrap && layer.maxWidth
2252
2422
  ? wrapText(ctx, layer.text, layer.maxWidth, layer.maxLines)
2253
2423
  : layer.text.split("\n").slice(0, layer.maxLines ?? Number.MAX_SAFE_INTEGER);
@@ -2615,7 +2785,7 @@ function normalizeStepAnimationDuration(duration) {
2615
2785
  return DEFAULT_STEP_ANIMATION_DURATION;
2616
2786
  return Math.max(0, Math.floor(duration));
2617
2787
  }
2618
- function normalizeItems(items) {
2788
+ function normalizeItems$1(items) {
2619
2789
  return items
2620
2790
  .map((item, index) => {
2621
2791
  if (typeof item === "object" && item !== null) {
@@ -2636,7 +2806,7 @@ function normalizeItems(items) {
2636
2806
  }
2637
2807
  class MarqueeController {
2638
2808
  constructor(items = [], options = {}) {
2639
- this.items = normalizeItems(items);
2809
+ this.items = normalizeItems$1(items);
2640
2810
  this.direction = normalizeDirection$1(options.direction);
2641
2811
  this.duration = normalizeDuration$1(options.duration);
2642
2812
  this.gap = normalizeGap(options.gap);
@@ -2648,7 +2818,7 @@ class MarqueeController {
2648
2818
  this.verticalMode = normalizeVerticalMode(options.verticalMode);
2649
2819
  }
2650
2820
  update(items, options = {}) {
2651
- this.items = normalizeItems(items);
2821
+ this.items = normalizeItems$1(items);
2652
2822
  this.direction = normalizeDirection$1(options.direction ?? this.direction);
2653
2823
  this.duration = normalizeDuration$1(options.duration ?? this.duration);
2654
2824
  this.gap = normalizeGap(options.gap ?? this.gap);
@@ -2679,23 +2849,23 @@ class MarqueeController {
2679
2849
  }
2680
2850
  }
2681
2851
 
2682
- function clamp$8(value, min, max) {
2852
+ function clamp$9(value, min, max) {
2683
2853
  return Math.min(max, Math.max(min, value));
2684
2854
  }
2685
- function finiteOr$1(value, fallback) {
2855
+ function finiteOr$3(value, fallback) {
2686
2856
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
2687
2857
  }
2688
2858
  function normalizeOptions$2(options = {}) {
2689
2859
  return {
2690
2860
  disabled: options.disabled ?? false,
2691
- enterTransitionDuration: clamp$8(finiteOr$1(options.enterTransitionDuration, 180), 0, 600),
2861
+ enterTransitionDuration: clamp$9(finiteOr$3(options.enterTransitionDuration, 180), 0, 600),
2692
2862
  glare: options.glare ?? true,
2693
- maxTilt: clamp$8(finiteOr$1(options.maxTilt, 12), 0, 45),
2694
- moveTransitionDuration: clamp$8(finiteOr$1(options.moveTransitionDuration, 80), 0, 300),
2695
- perspective: clamp$8(finiteOr$1(options.perspective, 900), 240, 2400),
2696
- scale: clamp$8(finiteOr$1(options.scale, 1.02), 1, 1.18),
2863
+ maxTilt: clamp$9(finiteOr$3(options.maxTilt, 12), 0, 45),
2864
+ moveTransitionDuration: clamp$9(finiteOr$3(options.moveTransitionDuration, 80), 0, 300),
2865
+ perspective: clamp$9(finiteOr$3(options.perspective, 900), 240, 2400),
2866
+ scale: clamp$9(finiteOr$3(options.scale, 1.02), 1, 1.18),
2697
2867
  transitionEasing: options.transitionEasing ?? "cubic-bezier(0.2, 0.8, 0.2, 1)",
2698
- transitionDuration: clamp$8(finiteOr$1(options.transitionDuration, 180), 0, 1200)
2868
+ transitionDuration: clamp$9(finiteOr$3(options.transitionDuration, 180), 0, 1200)
2699
2869
  };
2700
2870
  }
2701
2871
  function createTransform(rotateX, rotateY, scale, perspective) {
@@ -2710,18 +2880,18 @@ class TiltCardController {
2710
2880
  return this.reset();
2711
2881
  }
2712
2882
  move(input) {
2713
- const width = Math.max(1, finiteOr$1(input.width, 1));
2714
- const height = Math.max(1, finiteOr$1(input.height, 1));
2883
+ const width = Math.max(1, finiteOr$3(input.width, 1));
2884
+ const height = Math.max(1, finiteOr$3(input.height, 1));
2715
2885
  if (this.options.disabled) {
2716
2886
  return this.reset();
2717
2887
  }
2718
- const x = clamp$8(input.pointerX / width, 0, 1);
2719
- const y = clamp$8(input.pointerY / height, 0, 1);
2888
+ const x = clamp$9(input.pointerX / width, 0, 1);
2889
+ const y = clamp$9(input.pointerY / height, 0, 1);
2720
2890
  const rotateY = (x - 0.5) * this.options.maxTilt * 2;
2721
2891
  const rotateX = (0.5 - y) * this.options.maxTilt * 2;
2722
2892
  return {
2723
2893
  glare: this.options.glare,
2724
- glareOpacity: this.options.glare ? clamp$8(Math.abs(x - 0.5) + Math.abs(y - 0.5), 0.16, 0.58) : 0,
2894
+ glareOpacity: this.options.glare ? clamp$9(Math.abs(x - 0.5) + Math.abs(y - 0.5), 0.16, 0.58) : 0,
2725
2895
  glareX: x * 100,
2726
2896
  glareY: y * 100,
2727
2897
  isActive: true,
@@ -2753,20 +2923,20 @@ class TiltCardController {
2753
2923
  }
2754
2924
  }
2755
2925
 
2756
- function finiteOr(value, fallback) {
2926
+ function finiteOr$2(value, fallback) {
2757
2927
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
2758
2928
  }
2759
- function clamp$7(value, min, max) {
2929
+ function clamp$8(value, min, max) {
2760
2930
  return Math.min(max, Math.max(min, value));
2761
2931
  }
2762
2932
  function normalizeOptions$1(options = {}) {
2763
2933
  return {
2764
2934
  cursor: options.cursor ?? true,
2765
- delay: clamp$7(finiteOr(options.delay, 0), 0, 60000),
2935
+ delay: clamp$8(finiteOr$2(options.delay, 0), 0, 60000),
2766
2936
  disabled: options.disabled ?? false,
2767
2937
  loading: options.loading ?? false,
2768
2938
  loop: options.loop ?? false,
2769
- speed: clamp$7(finiteOr(options.speed, 36), 1, 5000),
2939
+ speed: clamp$8(finiteOr$2(options.speed, 36), 1, 5000),
2770
2940
  startOnMount: options.startOnMount ?? true,
2771
2941
  text: options.text ?? ""
2772
2942
  };
@@ -2790,7 +2960,7 @@ class TypewriterTextController {
2790
2960
  this.running = this.options.startOnMount && this.options.text.length > 0;
2791
2961
  }
2792
2962
  else {
2793
- this.index = clamp$7(this.index, 0, this.options.text.length);
2963
+ this.index = clamp$8(this.index, 0, this.options.text.length);
2794
2964
  if (this.index >= this.options.text.length)
2795
2965
  this.running = false;
2796
2966
  }
@@ -2850,7 +3020,7 @@ class TypewriterTextController {
2850
3020
  }
2851
3021
  }
2852
3022
 
2853
- const defaultColors = ["#7c3aed", "#ec4899", "#22d3ee"];
3023
+ const defaultColors = ["#722ed1", "#d64d8c", "#36bffb"];
2854
3024
  const cssColorPattern$1 = /^(#|rgb\(|rgba\(|hsl\(|hsla\(|color\(|color-mix\(|var\(|[a-zA-Z])/;
2855
3025
  function normalizeColors$1(colors) {
2856
3026
  const next = (colors ?? [])
@@ -2914,15 +3084,15 @@ const presetSet = new Set([
2914
3084
  ]);
2915
3085
  const toneSet = new Set(["accent", "cool", "danger", "neutral", "success", "warm"]);
2916
3086
  const toneColors = {
2917
- accent: ["#7c3aed", "#ec4899", "#22d3ee"],
2918
- cool: ["#0ea5e9", "#22d3ee", "#14b8a6"],
3087
+ accent: ["#722ed1", "#d64d8c", "#36bffb"],
3088
+ cool: ["#007aff", "#36bffb", "#00b42a"],
2919
3089
  danger: ["#ef4444", "#f97316", "#facc15"],
2920
3090
  neutral: ["#334155", "#94a3b8", "#e2e8f0"],
2921
3091
  success: ["#16a34a", "#22c55e", "#84cc16"],
2922
3092
  warm: ["#f59e0b", "#f97316", "#fb7185"]
2923
3093
  };
2924
3094
  const cssColorPattern = /^(#|rgb\(|rgba\(|hsl\(|hsla\(|color\(|color-mix\(|var\(|[a-zA-Z])/;
2925
- function clamp$6(value, min, max) {
3095
+ function clamp$7(value, min, max) {
2926
3096
  return Math.min(max, Math.max(min, value));
2927
3097
  }
2928
3098
  function normalizePreset(preset) {
@@ -2944,7 +3114,7 @@ function normalizeColors(colors, tone) {
2944
3114
  return next.length >= 2 ? next : [...toneColors[tone]];
2945
3115
  }
2946
3116
  function normalizeIntensity(intensity) {
2947
- return clamp$6(Number.isFinite(intensity) ? Number(intensity) : 0.72, 0, 1);
3117
+ return clamp$7(Number.isFinite(intensity) ? Number(intensity) : 0.72, 0, 1);
2948
3118
  }
2949
3119
  class DesignEffectController {
2950
3120
  constructor(options = {}) {
@@ -2990,13 +3160,13 @@ class DesignEffectController {
2990
3160
  }
2991
3161
  }
2992
3162
 
2993
- function clamp$5(value, min, max) {
3163
+ function clamp$6(value, min, max) {
2994
3164
  return Math.min(max, Math.max(min, value));
2995
3165
  }
2996
3166
  class SwiperController {
2997
3167
  constructor(options) {
2998
3168
  this.count = Math.max(0, Math.floor(options.count));
2999
- this.current = clamp$5(Math.floor(options.current ?? 0), 0, Math.max(0, this.count - 1));
3169
+ this.current = clamp$6(Math.floor(options.current ?? 0), 0, Math.max(0, this.count - 1));
3000
3170
  this.loop = options.loop ?? false;
3001
3171
  this.threshold = Math.max(1, options.threshold ?? 48);
3002
3172
  }
@@ -3008,9 +3178,9 @@ class SwiperController {
3008
3178
  if (options.threshold !== undefined)
3009
3179
  this.threshold = Math.max(1, options.threshold);
3010
3180
  if (options.current !== undefined)
3011
- this.current = clamp$5(Math.floor(options.current), 0, Math.max(0, this.count - 1));
3181
+ this.current = clamp$6(Math.floor(options.current), 0, Math.max(0, this.count - 1));
3012
3182
  else
3013
- this.current = clamp$5(this.current, 0, Math.max(0, this.count - 1));
3183
+ this.current = clamp$6(this.current, 0, Math.max(0, this.count - 1));
3014
3184
  return this.getState();
3015
3185
  }
3016
3186
  next() {
@@ -3031,7 +3201,7 @@ class SwiperController {
3031
3201
  return deltaX < 0 || velocityX < -360 ? this.next() : this.previous();
3032
3202
  }
3033
3203
  setCurrent(index) {
3034
- this.current = clamp$5(index, 0, Math.max(0, this.count - 1));
3204
+ this.current = clamp$6(index, 0, Math.max(0, this.count - 1));
3035
3205
  return this.getState();
3036
3206
  }
3037
3207
  getState() {
@@ -3043,25 +3213,25 @@ class SwiperController {
3043
3213
  }
3044
3214
  }
3045
3215
 
3046
- function clamp$4(value, min, max) {
3216
+ function clamp$5(value, min, max) {
3047
3217
  return Math.min(max, Math.max(min, value));
3048
3218
  }
3049
3219
  class ImagePreviewController {
3050
3220
  constructor(items = [], activeIndex = 0, open = false) {
3051
3221
  this.loading = false;
3052
3222
  this.items = items.filter((item) => item.src);
3053
- this.activeIndex = clamp$4(activeIndex, 0, Math.max(0, this.items.length - 1));
3223
+ this.activeIndex = clamp$5(activeIndex, 0, Math.max(0, this.items.length - 1));
3054
3224
  this.openState = open;
3055
3225
  }
3056
3226
  updateItems(items, activeIndex = this.activeIndex) {
3057
3227
  this.items = items.filter((item) => item.src);
3058
- this.activeIndex = clamp$4(activeIndex, 0, Math.max(0, this.items.length - 1));
3228
+ this.activeIndex = clamp$5(activeIndex, 0, Math.max(0, this.items.length - 1));
3059
3229
  this.loading = false;
3060
3230
  return this.getState();
3061
3231
  }
3062
3232
  open(index = this.activeIndex) {
3063
3233
  this.openState = true;
3064
- this.activeIndex = clamp$4(index, 0, Math.max(0, this.items.length - 1));
3234
+ this.activeIndex = clamp$5(index, 0, Math.max(0, this.items.length - 1));
3065
3235
  return this.getState();
3066
3236
  }
3067
3237
  close() {
@@ -3081,7 +3251,7 @@ class ImagePreviewController {
3081
3251
  return this.getState();
3082
3252
  }
3083
3253
  setActiveIndex(index) {
3084
- this.activeIndex = clamp$4(index, 0, Math.max(0, this.items.length - 1));
3254
+ this.activeIndex = clamp$5(index, 0, Math.max(0, this.items.length - 1));
3085
3255
  this.loading = true;
3086
3256
  return this.getState();
3087
3257
  }
@@ -3226,7 +3396,7 @@ const WORD_EXTENSIONS = new Set(["doc", "docx", "rtf"]);
3226
3396
  const EXCEL_EXTENSIONS = new Set(["csv", "xls", "xlsx"]);
3227
3397
  const PPT_EXTENSIONS = new Set(["ppt", "pptx"]);
3228
3398
  const DEFAULT_OFFICE_VIEWER = "https://view.officeapps.live.com/op/embed.aspx?src=";
3229
- function clamp$3(value, min, max) {
3399
+ function clamp$4(value, min, max) {
3230
3400
  return Math.min(max, Math.max(min, value));
3231
3401
  }
3232
3402
  function getExtension(value) {
@@ -3290,7 +3460,7 @@ class FilePreviewController {
3290
3460
  const fileName = inferFileName(this.options.src, this.options.fileName);
3291
3461
  const type = this.options.type && this.options.type !== "unknown" ? this.options.type : inferType(this.options.src, fileName);
3292
3462
  const pageCount = this.options.pageCount && this.options.pageCount > 0 ? Math.floor(this.options.pageCount) : undefined;
3293
- const currentPage = clamp$3(Math.floor(this.options.currentPage ?? 1), 1, pageCount ?? Number.MAX_SAFE_INTEGER);
3463
+ const currentPage = clamp$4(Math.floor(this.options.currentPage ?? 1), 1, pageCount ?? Number.MAX_SAFE_INTEGER);
3294
3464
  const mode = type === "pdf" ? "pdf" : type === "word" || type === "excel" || type === "ppt" ? "office" : "unsupported";
3295
3465
  const previewUrl = mode === "pdf"
3296
3466
  ? buildPdfUrl(this.options.src, currentPage)
@@ -3310,7 +3480,7 @@ class FilePreviewController {
3310
3480
  }
3311
3481
  }
3312
3482
 
3313
- function clamp$2(value, min, max) {
3483
+ function clamp$3(value, min, max) {
3314
3484
  return Math.min(max, Math.max(min, value));
3315
3485
  }
3316
3486
  class ProgressController {
@@ -3340,7 +3510,7 @@ class ProgressController {
3340
3510
  return this.getState();
3341
3511
  }
3342
3512
  valueFromRatio(ratio) {
3343
- return this.setValue(this.min + clamp$2(ratio, 0, 1) * (this.max - this.min));
3513
+ return this.setValue(this.min + clamp$3(ratio, 0, 1) * (this.max - this.min));
3344
3514
  }
3345
3515
  valueFromClientX(clientX, rect, thumbWidth = 0) {
3346
3516
  if (rect.width <= 0)
@@ -3361,7 +3531,7 @@ class ProgressController {
3361
3531
  };
3362
3532
  }
3363
3533
  normalizeValue(value) {
3364
- const clamped = clamp$2(Number.isFinite(value) ? value : this.min, this.min, this.max);
3534
+ const clamped = clamp$3(Number.isFinite(value) ? value : this.min, this.min, this.max);
3365
3535
  if (this.step <= 0)
3366
3536
  return clamped;
3367
3537
  const precision = Math.max(0, String(this.step).split(".")[1]?.length ?? 0);
@@ -3369,20 +3539,20 @@ class ProgressController {
3369
3539
  }
3370
3540
  }
3371
3541
 
3372
- function clamp$1(value, min, max) {
3542
+ function clamp$2(value, min, max) {
3373
3543
  return Math.min(max, Math.max(min, value));
3374
3544
  }
3375
3545
  function normalizeLineWidth(value) {
3376
- return clamp$1(Number.isFinite(value ?? NaN) ? Number(value) : 3, 0.5, 24);
3546
+ return clamp$2(Number.isFinite(value ?? NaN) ? Number(value) : 3, 0.5, 24);
3377
3547
  }
3378
3548
  function normalizePoint(x, y, size, pressure = 0.5) {
3379
3549
  const width = Math.max(1, size.width);
3380
3550
  const height = Math.max(1, size.height);
3381
3551
  return {
3382
- pressure: clamp$1(Number.isFinite(pressure) ? pressure : 0.5, 0, 1),
3552
+ pressure: clamp$2(Number.isFinite(pressure) ? pressure : 0.5, 0, 1),
3383
3553
  time: Date.now(),
3384
- x: clamp$1(x / width, 0, 1),
3385
- y: clamp$1(y / height, 0, 1)
3554
+ x: clamp$2(x / width, 0, 1),
3555
+ y: clamp$2(y / height, 0, 1)
3386
3556
  };
3387
3557
  }
3388
3558
  class SignatureController {
@@ -3447,10 +3617,10 @@ class SignatureController {
3447
3617
  color: stroke.color,
3448
3618
  lineWidth: normalizeLineWidth(stroke.lineWidth),
3449
3619
  points: stroke.points.map((point) => ({
3450
- pressure: clamp$1(point.pressure, 0, 1),
3620
+ pressure: clamp$2(point.pressure, 0, 1),
3451
3621
  time: point.time,
3452
- x: clamp$1(point.x, 0, 1),
3453
- y: clamp$1(point.y, 0, 1)
3622
+ x: clamp$2(point.x, 0, 1),
3623
+ y: clamp$2(point.y, 0, 1)
3454
3624
  }))
3455
3625
  }));
3456
3626
  this.isDrawing = false;
@@ -3474,6 +3644,305 @@ class SignatureController {
3474
3644
  }
3475
3645
  }
3476
3646
 
3647
+ function normalizePlacement(placement) {
3648
+ return placement === "top" ||
3649
+ placement === "right" ||
3650
+ placement === "bottom" ||
3651
+ placement === "left" ||
3652
+ placement === "auto"
3653
+ ? placement
3654
+ : "auto";
3655
+ }
3656
+ function finiteOr$1(value, fallback) {
3657
+ return Number.isFinite(value) ? value : fallback;
3658
+ }
3659
+ class CodePreviewController {
3660
+ constructor(options = {}) {
3661
+ this.state = {
3662
+ code: options.code ?? "",
3663
+ copied: false,
3664
+ expanded: Boolean(options.defaultExpanded),
3665
+ language: options.language ?? "Vue / TSX",
3666
+ placement: normalizePlacement(options.placement),
3667
+ resolvedPlacement: "bottom",
3668
+ title: options.title ?? "示例源码",
3669
+ };
3670
+ }
3671
+ close() {
3672
+ this.state.expanded = false;
3673
+ this.state.copied = false;
3674
+ return this.getState();
3675
+ }
3676
+ copied() {
3677
+ this.state.copied = true;
3678
+ return this.getState();
3679
+ }
3680
+ resetCopied() {
3681
+ this.state.copied = false;
3682
+ return this.getState();
3683
+ }
3684
+ getState() {
3685
+ return { ...this.state };
3686
+ }
3687
+ resolvePlacement(input) {
3688
+ if (this.state.placement !== "auto") {
3689
+ this.state.resolvedPlacement = this.state.placement;
3690
+ return this.getState();
3691
+ }
3692
+ const viewportHeight = Math.max(0, finiteOr$1(input.viewportHeight, 0));
3693
+ const viewportWidth = Math.max(0, finiteOr$1(input.viewportWidth ?? 0, 0));
3694
+ const anchorBottom = Math.max(0, finiteOr$1(input.anchorBottom, 0));
3695
+ const anchorLeft = Math.max(0, finiteOr$1(input.anchorLeft ?? 0, 0));
3696
+ const anchorRight = Math.max(0, finiteOr$1(input.anchorRight ?? 0, 0));
3697
+ const anchorTop = Math.max(0, finiteOr$1(input.anchorTop, 0));
3698
+ const panelHeight = Math.max(0, finiteOr$1(input.panelHeight, 0));
3699
+ const panelWidth = Math.max(0, finiteOr$1(input.panelWidth ?? 0, 0));
3700
+ const candidates = [
3701
+ {
3702
+ placement: "bottom",
3703
+ size: panelHeight,
3704
+ space: Math.max(0, viewportHeight - anchorBottom),
3705
+ },
3706
+ { placement: "top", size: panelHeight, space: anchorTop },
3707
+ {
3708
+ placement: "right",
3709
+ size: panelWidth,
3710
+ space: Math.max(0, viewportWidth - anchorRight),
3711
+ },
3712
+ { placement: "left", size: panelWidth, space: anchorLeft },
3713
+ ];
3714
+ const fitting = candidates.find(({ size, space }) => space >= size + 10);
3715
+ this.state.resolvedPlacement =
3716
+ fitting?.placement ??
3717
+ candidates.reduce((best, item) => (item.space > best.space ? item : best))
3718
+ .placement;
3719
+ return this.getState();
3720
+ }
3721
+ toggle() {
3722
+ this.state.expanded = !this.state.expanded;
3723
+ if (!this.state.expanded)
3724
+ this.state.copied = false;
3725
+ return this.getState();
3726
+ }
3727
+ update(options = {}) {
3728
+ if (options.code !== undefined)
3729
+ this.state.code = options.code;
3730
+ if (options.language !== undefined)
3731
+ this.state.language = options.language;
3732
+ if (options.placement !== undefined)
3733
+ this.state.placement = normalizePlacement(options.placement);
3734
+ if (options.title !== undefined)
3735
+ this.state.title = options.title;
3736
+ return this.getState();
3737
+ }
3738
+ }
3739
+
3740
+ function finiteOr(value, fallback) {
3741
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
3742
+ }
3743
+ function normalizeMode(mode) {
3744
+ return mode === "auto" || mode === "grid" || mode === "flip" ? mode : "auto";
3745
+ }
3746
+ class HeightTransitionController {
3747
+ constructor(options = {}) {
3748
+ this.state = this.resolve(options);
3749
+ }
3750
+ getState() {
3751
+ return { ...this.state };
3752
+ }
3753
+ update(options = {}) {
3754
+ this.state = this.resolve({ ...this.state, ...options });
3755
+ return this.getState();
3756
+ }
3757
+ resolve(options) {
3758
+ return {
3759
+ duration: Math.max(0, Math.min(1200, finiteOr(options.duration, 220))),
3760
+ easing: options.easing || "cubic-bezier(0.22, 1, 0.36, 1)",
3761
+ expanded: Boolean(options.expanded),
3762
+ mode: normalizeMode(options.mode),
3763
+ };
3764
+ }
3765
+ }
3766
+
3767
+ const defaultItems = [
3768
+ { id: "docs", label: "Docs", tone: "primary" },
3769
+ { id: "api", label: "API", tone: "neutral" },
3770
+ { id: "theme", label: "Theme", tone: "accent" },
3771
+ { id: "react", label: "React", tone: "cool" },
3772
+ { id: "vue", label: "Vue", tone: "success" },
3773
+ { id: "core", label: "Core", tone: "warm" },
3774
+ ];
3775
+ function clamp$1(value, min, max) {
3776
+ return Math.min(max, Math.max(min, value));
3777
+ }
3778
+ function normalizeCssSize(value, fallback) {
3779
+ if (typeof value === "number" && Number.isFinite(value))
3780
+ return `${Math.max(0, value)}px`;
3781
+ const next = String(value ?? fallback).trim();
3782
+ return next.length > 0 ? next : fallback;
3783
+ }
3784
+ function normalizeNumber(value, fallback, min, max) {
3785
+ return clamp$1(Number.isFinite(value) ? Number(value) : fallback, min, max);
3786
+ }
3787
+ function normalizeItems(items) {
3788
+ const source = items && items.length > 0 ? items : defaultItems;
3789
+ return source
3790
+ .map((item, index) => {
3791
+ const id = String(item.id || `orbital-${index}`).trim() || `orbital-${index}`;
3792
+ const label = String(item.label ?? item.content ?? id).trim() || id;
3793
+ return {
3794
+ content: String(item.content ?? label),
3795
+ id,
3796
+ label,
3797
+ tone: String(item.tone ?? "neutral"),
3798
+ };
3799
+ })
3800
+ .slice(0, 24);
3801
+ }
3802
+ function round(value) {
3803
+ return value.toFixed(3).replace(/\.?0+$/, "");
3804
+ }
3805
+ function point(x, y) {
3806
+ return {
3807
+ x: clamp$1(x, 0, 1),
3808
+ y: clamp$1(y, 0, 1),
3809
+ };
3810
+ }
3811
+ function jitter(index, salt, range = 0.16) {
3812
+ const raw = ((index * 37 + salt * 17) % 100) / 100;
3813
+ return (raw - 0.5) * range;
3814
+ }
3815
+ function createMotionRoute(index, total, spread) {
3816
+ const laneBase = total <= 1 ? 0.5 : index / Math.max(1, total - 1);
3817
+ const lane = clamp$1(0.08 + laneBase * 0.84 + jitter(index, 1, 0.12), 0, 1);
3818
+ const inverseLane = 1 - lane;
3819
+ const loose = clamp$1(spread, 0.32, 1.12);
3820
+ const bend = 0.18 * loose;
3821
+ switch (index % 6) {
3822
+ case 0:
3823
+ return [
3824
+ point(0, lane),
3825
+ point(0.42, lane + bend),
3826
+ point(1, lane - bend),
3827
+ point(0.16, inverseLane),
3828
+ ];
3829
+ case 1:
3830
+ return [
3831
+ point(lane, 0),
3832
+ point(lane + bend, 0.38),
3833
+ point(lane - bend, 1),
3834
+ point(inverseLane, 0.22),
3835
+ ];
3836
+ case 2:
3837
+ return [
3838
+ point(1, inverseLane),
3839
+ point(0.58, inverseLane - bend),
3840
+ point(0, inverseLane + bend),
3841
+ point(0.84, lane),
3842
+ ];
3843
+ case 3:
3844
+ return [
3845
+ point(inverseLane, 1),
3846
+ point(inverseLane - bend, 0.62),
3847
+ point(inverseLane + bend, 0),
3848
+ point(lane, 0.78),
3849
+ ];
3850
+ case 4:
3851
+ return [
3852
+ point(0.06, 0.08 + lane * 0.4),
3853
+ point(0.52 + jitter(index, 3), 0.24 + inverseLane * 0.36),
3854
+ point(0.94, 0.92 - lane * 0.42),
3855
+ point(0.28 + inverseLane * 0.36, 0.84),
3856
+ ];
3857
+ default:
3858
+ return [
3859
+ point(0.94, 0.08 + inverseLane * 0.38),
3860
+ point(0.46 + jitter(index, 5), 0.28 + lane * 0.34),
3861
+ point(0.06, 0.88 - inverseLane * 0.42),
3862
+ point(0.72 - lane * 0.34, 0.16),
3863
+ ];
3864
+ }
3865
+ }
3866
+ function createItemState(item, index, total, duration, spread, depth, cycleDuration) {
3867
+ const [start, mid, end, alt] = createMotionRoute(index, total, spread);
3868
+ const itemDuration = duration * (0.92 + ((index * 37) % 19) / 100);
3869
+ const delay = -((index * 997) % Math.max(1, Math.floor(itemDuration)));
3870
+ const presenceDelay = -((index * 1207) % Math.max(1, cycleDuration));
3871
+ const scale = 0.88 + depth * 0.1 + ((index * 29) % 9) / 100;
3872
+ return {
3873
+ content: item.content ?? item.label ?? item.id,
3874
+ id: item.id,
3875
+ index,
3876
+ label: item.label ?? item.id,
3877
+ styleVars: {
3878
+ "--cc-orbital-item-delay": `${delay}ms`,
3879
+ "--cc-orbital-item-duration": `${Math.round(itemDuration)}ms`,
3880
+ "--cc-orbital-item-alt-x": round(alt.x),
3881
+ "--cc-orbital-item-alt-y": round(alt.y),
3882
+ "--cc-orbital-item-end-x": round(end.x),
3883
+ "--cc-orbital-item-end-y": round(end.y),
3884
+ "--cc-orbital-item-mid-x": round(mid.x),
3885
+ "--cc-orbital-item-mid-y": round(mid.y),
3886
+ "--cc-orbital-item-presence-delay": `${presenceDelay}ms`,
3887
+ "--cc-orbital-item-scale": round(scale),
3888
+ "--cc-orbital-item-start-x": round(start.x),
3889
+ "--cc-orbital-item-start-y": round(start.y),
3890
+ },
3891
+ tone: item.tone ?? "neutral",
3892
+ };
3893
+ }
3894
+ class OrbitalSphereController {
3895
+ constructor(options = {}) {
3896
+ this.state = this.normalize(options);
3897
+ }
3898
+ getState() {
3899
+ return {
3900
+ ...this.state,
3901
+ items: this.state.items.map((item) => ({
3902
+ ...item,
3903
+ styleVars: { ...item.styleVars },
3904
+ })),
3905
+ styleVars: { ...this.state.styleVars },
3906
+ };
3907
+ }
3908
+ update(options = {}) {
3909
+ this.state = this.normalize(options);
3910
+ return this.getState();
3911
+ }
3912
+ normalize(options) {
3913
+ const animated = options.animated ?? true;
3914
+ const cycleDuration = normalizeNumber(options.cycleDuration, 12000, 10000, 60000);
3915
+ const depth = normalizeNumber(options.depth, 0.72, 0, 1.4);
3916
+ const duration = normalizeNumber(options.duration, 9000, 1200, 60000);
3917
+ const itemSize = normalizeNumber(options.itemSize, 72, 36, 160);
3918
+ const radius = normalizeCssSize(options.radius, "50%");
3919
+ const size = normalizeCssSize(options.size, "360px");
3920
+ const spread = normalizeNumber(options.spread, 0.86, 0.32, 1.12);
3921
+ const sourceItems = normalizeItems(options.items);
3922
+ const visibleCount = Math.round(normalizeNumber(options.visibleCount, 10, 2, 24));
3923
+ return {
3924
+ animated,
3925
+ cycleDuration,
3926
+ depth,
3927
+ disabled: options.disabled ?? false,
3928
+ duration,
3929
+ itemSize,
3930
+ items: sourceItems.map((item, index) => createItemState(item, index, sourceItems.length, duration, spread, depth, cycleDuration)),
3931
+ radius,
3932
+ size,
3933
+ spread,
3934
+ styleVars: {
3935
+ "--cc-orbital-sphere-cycle-duration": `${Math.round(cycleDuration)}ms`,
3936
+ "--cc-orbital-sphere-duration": `${Math.round(duration)}ms`,
3937
+ "--cc-orbital-sphere-item-size": `${Math.round(itemSize)}px`,
3938
+ "--cc-orbital-sphere-radius": radius,
3939
+ "--cc-orbital-sphere-size": size,
3940
+ },
3941
+ visibleCount,
3942
+ };
3943
+ }
3944
+ }
3945
+
3477
3946
  const DEFAULT_MIN_WIDTH = 32;
3478
3947
  const DEFAULT_MAX_WIDTH = 1000;
3479
3948
  function normalizeMinWidth(width) {
@@ -4629,7 +5098,9 @@ exports.BreadcrumbController = BreadcrumbController;
4629
5098
  exports.CalendarController = CalendarController;
4630
5099
  exports.CanvasEditorController = CanvasEditorController;
4631
5100
  exports.CanvasImageController = CanvasImageController;
5101
+ exports.ChatTextareaController = ChatTextareaController;
4632
5102
  exports.ChatVirtualListController = ChatVirtualListController;
5103
+ exports.CodePreviewController = CodePreviewController;
4633
5104
  exports.ColorPickerController = ColorPickerController;
4634
5105
  exports.ComicReaderController = ComicReaderController;
4635
5106
  exports.CountdownController = CountdownController;
@@ -4645,14 +5116,17 @@ exports.FloatingBallController = FloatingBallController;
4645
5116
  exports.FormController = FormController;
4646
5117
  exports.GestureController = GestureController;
4647
5118
  exports.GradientTextController = GradientTextController;
5119
+ exports.HeightTransitionController = HeightTransitionController;
4648
5120
  exports.ImagePreviewController = ImagePreviewController;
4649
5121
  exports.LazyImageController = LazyImageController;
4650
5122
  exports.LiveRoomController = LiveRoomController;
4651
5123
  exports.MarqueeController = MarqueeController;
4652
5124
  exports.MasonryVirtualListController = MasonryVirtualListController;
5125
+ exports.MenuController = MenuController;
4653
5126
  exports.ModalController = ModalController;
4654
5127
  exports.MultiColumnPickerController = MultiColumnPickerController;
4655
5128
  exports.NovelReaderController = NovelReaderController;
5129
+ exports.OrbitalSphereController = OrbitalSphereController;
4656
5130
  exports.PaginationController = PaginationController;
4657
5131
  exports.PasswordInputController = PasswordInputController;
4658
5132
  exports.PopupController = PopupController;