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