tsquare 0.12.3 → 0.13.0

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.
@@ -7675,16 +7675,16 @@ function FDEF(state) {
7675
7675
  state.ip = ip;
7676
7676
  state.funcs[fn] = prog.slice(ipBegin + 1, ip);
7677
7677
  }
7678
- function MDAP(round, state) {
7678
+ function MDAP(round2, state) {
7679
7679
  var pi = state.stack.pop();
7680
7680
  var p = state.z0[pi];
7681
7681
  var fv = state.fv;
7682
7682
  var pv = state.pv;
7683
7683
  if (exports.DEBUG) {
7684
- console.log(state.step, "MDAP[" + round + "]", pi);
7684
+ console.log(state.step, "MDAP[" + round2 + "]", pi);
7685
7685
  }
7686
7686
  var d2 = pv.distance(p, HPZero);
7687
- if (round) {
7687
+ if (round2) {
7688
7688
  d2 = state.round(d2);
7689
7689
  }
7690
7690
  fv.setRelative(p, HPZero, d2, pv);
@@ -7887,7 +7887,7 @@ function RTDG(state) {
7887
7887
  }
7888
7888
  state.round = roundToDoubleGrid;
7889
7889
  }
7890
- function MIAP(round, state) {
7890
+ function MIAP(round2, state) {
7891
7891
  var stack = state.stack;
7892
7892
  var n = stack.pop();
7893
7893
  var pi = stack.pop();
@@ -7898,7 +7898,7 @@ function MIAP(round, state) {
7898
7898
  if (exports.DEBUG) {
7899
7899
  console.log(
7900
7900
  state.step,
7901
- "MIAP[" + round + "]",
7901
+ "MIAP[" + round2 + "]",
7902
7902
  n,
7903
7903
  "(",
7904
7904
  cv,
@@ -7907,7 +7907,7 @@ function MIAP(round, state) {
7907
7907
  );
7908
7908
  }
7909
7909
  var d2 = pv.distance(p, HPZero);
7910
- if (round) {
7910
+ if (round2) {
7911
7911
  if (Math.abs(d2 - cv) < state.cvCutIn) {
7912
7912
  d2 = cv;
7913
7913
  }
@@ -20659,6 +20659,7 @@ function markRoot(root, color) {
20659
20659
  const kids = Children.toArray(node.props.children);
20660
20660
  return cloneElement(node, {}, ...kids, /* @__PURE__ */ jsx3(Marker, { color }, "__marker"));
20661
20661
  }
20662
+ var MARKS_ITSELF = /* @__PURE__ */ new Set(["Screen", "Modal", "Drawer", "Toast"]);
20662
20663
  function withMarkers(reg) {
20663
20664
  return Object.fromEntries(
20664
20665
  Object.entries(reg).map(([name, C]) => [
@@ -20666,7 +20667,7 @@ function withMarkers(reg) {
20666
20667
  (props) => {
20667
20668
  const root = C(props);
20668
20669
  const color = props.element?.props?.__mark;
20669
- return color && name !== "Screen" ? markRoot(root, color) : root;
20670
+ return color && !MARKS_ITSELF.has(name) ? markRoot(root, color) : root;
20670
20671
  }
20671
20672
  ])
20672
20673
  );
@@ -20789,6 +20790,16 @@ function BrowserBar() {
20789
20790
  }
20790
20791
  );
20791
20792
  }
20793
+ function mayOverflow(name, width) {
20794
+ let w2 = 0;
20795
+ for (const ch of name) {
20796
+ if (ch.charCodeAt(0) >= 128 || /[MWmw@%&]/.test(ch)) w2 += 16.5;
20797
+ else if (/[A-Z]/.test(ch)) w2 += 12.5;
20798
+ else if (/[ .,:;'!|il1jft()[\]{}"`-]/.test(ch)) w2 += 8.5;
20799
+ else w2 += 11;
20800
+ }
20801
+ return w2 > width;
20802
+ }
20792
20803
  function Screen({ element, children }) {
20793
20804
  const p = element.props;
20794
20805
  const s = screenSize(p);
@@ -20804,7 +20815,12 @@ function Screen({ element, children }) {
20804
20815
  else body.push(c2);
20805
20816
  }
20806
20817
  return /* @__PURE__ */ jsxs(Box, { style: { flexDirection: "column", flexShrink: 0 }, children: [
20807
- /* @__PURE__ */ jsx3(Box, { style: { height: LABEL_H, fontSize: 16, fontWeight: 600, color: theme.text }, children: p.name ?? "" }),
20818
+ mayOverflow(p.name ?? "", s.width) ? (
20819
+ // the board's layout sizes each column by its screen, so a name that may be wider than the
20820
+ // screen gets the screen's width and ends in "…" instead of widening the column. Only then:
20821
+ // the clip changes how the text is antialiased, and names that fit should render as before.
20822
+ /* @__PURE__ */ jsx3(Box, { style: { width: s.width, height: LABEL_H, fontSize: 16, fontWeight: 600, color: theme.text }, children: /* @__PURE__ */ jsx3("div", { style: { overflow: "hidden", whiteSpace: "nowrap", textOverflow: "ellipsis" }, children: p.name }) })
20823
+ ) : /* @__PURE__ */ jsx3(Box, { style: { height: LABEL_H, fontSize: 16, fontWeight: 600, color: theme.text }, children: p.name ?? "" }),
20808
20824
  /* @__PURE__ */ jsxs(
20809
20825
  Box,
20810
20826
  {
@@ -20825,19 +20841,22 @@ function Screen({ element, children }) {
20825
20841
  s.chrome && s.device === "desktop" ? /* @__PURE__ */ jsx3(BrowserBar, {}) : null,
20826
20842
  /* @__PURE__ */ jsxs(Box, { style: { position: "relative", flexGrow: 1, flexBasis: "0px", flexDirection: "column", overflow: "hidden" }, children: [
20827
20843
  top,
20828
- /* @__PURE__ */ jsx3(Box, { style: { flexGrow: 1, flexBasis: "0px", flexDirection: "column", overflow: "hidden" }, children: /* @__PURE__ */ jsx3(
20829
- Box,
20830
- {
20831
- style: {
20832
- flexGrow: 1,
20833
- flexShrink: 0,
20834
- flexDirection: "column",
20835
- padding: s.padding,
20836
- gap: p.gap ?? 14
20837
- },
20838
- children: withDir(body, "column")
20839
- }
20840
- ) }),
20844
+ /* @__PURE__ */ jsxs(Box, { style: { flexGrow: 1, flexBasis: "0px", flexDirection: "column", overflow: "hidden" }, children: [
20845
+ /* @__PURE__ */ jsx3(
20846
+ Box,
20847
+ {
20848
+ style: {
20849
+ flexGrow: 1,
20850
+ flexShrink: 0,
20851
+ flexDirection: "column",
20852
+ padding: s.padding,
20853
+ gap: p.gap ?? 14
20854
+ },
20855
+ children: withDir(body, "column")
20856
+ }
20857
+ ),
20858
+ p.__markBody ? /* @__PURE__ */ jsx3(Marker, { color: p.__markBody }) : null
20859
+ ] }),
20841
20860
  bottom,
20842
20861
  overlays.map((o2) => isValidElement(o2) ? cloneElement(o2, { aboveTabBar: bottom.length > 0 }) : o2),
20843
20862
  p.__mark ? /* @__PURE__ */ jsx3(Marker, { color: p.__mark }) : null
@@ -21103,9 +21122,9 @@ function Chart({ element, dir }) {
21103
21122
  const kind = p.kind ?? "line";
21104
21123
  const h2 = p.height ?? 180;
21105
21124
  const w2 = p.width ?? (dir === "row" ? void 0 : "100%");
21106
- const round = kind === "pie" || kind === "donut";
21125
+ const round2 = kind === "pie" || kind === "donut";
21107
21126
  const plot = (() => {
21108
- if (round) {
21127
+ if (round2) {
21109
21128
  const slice = (from, to2, fill, k) => {
21110
21129
  const a0 = from / 100 * 2 * Math.PI - Math.PI / 2, a1 = to2 / 100 * 2 * Math.PI - Math.PI / 2;
21111
21130
  const x0 = 50 + 46 * Math.cos(a0), y0 = 50 + 46 * Math.sin(a0), x1 = 50 + 46 * Math.cos(a1), y1 = 50 + 46 * Math.sin(a1);
@@ -21135,7 +21154,7 @@ function Chart({ element, dir }) {
21135
21154
  })();
21136
21155
  return /* @__PURE__ */ jsxs(Box, { style: { flexDirection: "column", gap: 10, width: w2, height: h2, flexShrink: 0, ...dir === "row" ? { flexGrow: 1, flexBasis: "0px" } : {} }, children: [
21137
21156
  p.title ? /* @__PURE__ */ jsx3(Box, { style: { fontSize: 13, fontWeight: 600, color: theme.text }, children: p.title }) : null,
21138
- /* @__PURE__ */ jsx3(Box, { style: { flexGrow: 1, borderBottom: round ? void 0 : `1.5px solid ${theme.line}`, justifyContent: round ? "center" : void 0, alignItems: round ? "center" : void 0 }, children: plot })
21157
+ /* @__PURE__ */ jsx3(Box, { style: { flexGrow: 1, borderBottom: round2 ? void 0 : `1.5px solid ${theme.line}`, justifyContent: round2 ? "center" : void 0, alignItems: round2 ? "center" : void 0 }, children: plot })
21139
21158
  ] });
21140
21159
  }
21141
21160
  function AvatarCircle({ initials, size = 40 }) {
@@ -21300,7 +21319,7 @@ function Select({ element, dir }) {
21300
21319
  ] })
21301
21320
  ] });
21302
21321
  }
21303
- function CheckMark({ checked, round = false, c: c2 = GRAY }) {
21322
+ function CheckMark({ checked, round: round2 = false, c: c2 = GRAY }) {
21304
21323
  return /* @__PURE__ */ jsx3(
21305
21324
  Box,
21306
21325
  {
@@ -21308,13 +21327,13 @@ function CheckMark({ checked, round = false, c: c2 = GRAY }) {
21308
21327
  width: 20,
21309
21328
  height: 20,
21310
21329
  flexShrink: 0,
21311
- borderRadius: round ? 10 : 5,
21312
- border: `1.5px solid ${checked && !round ? c2.accent : theme.lineStrong}`,
21313
- backgroundColor: checked && !round ? c2.accent : theme.paper,
21330
+ borderRadius: round2 ? 10 : 5,
21331
+ border: `1.5px solid ${checked && !round2 ? c2.accent : theme.lineStrong}`,
21332
+ backgroundColor: checked && !round2 ? c2.accent : theme.paper,
21314
21333
  alignItems: "center",
21315
21334
  justifyContent: "center"
21316
21335
  },
21317
- children: checked ? round ? /* @__PURE__ */ jsx3(Box, { style: { width: 10, height: 10, borderRadius: 5, backgroundColor: c2.accent } }) : /* @__PURE__ */ jsx3(IconGlyph, { name: "check", size: 14, color: c2.onAccent, strokeWidth: 3 }) : null
21336
+ children: checked ? round2 ? /* @__PURE__ */ jsx3(Box, { style: { width: 10, height: 10, borderRadius: 5, backgroundColor: c2.accent } }) : /* @__PURE__ */ jsx3(IconGlyph, { name: "check", size: 14, color: c2.onAccent, strokeWidth: 3 }) : null
21318
21337
  }
21319
21338
  );
21320
21339
  }
@@ -21454,7 +21473,7 @@ function Calendar({ element, dir, aligned, colors: c2 = GRAY }) {
21454
21473
  /* @__PURE__ */ jsx3(Box, { children: ["S", "M", "T", "W", "T", "F", "S"].map((d2, i2) => /* @__PURE__ */ jsx3(Box, { style: { width: CELL, justifyContent: "center", fontSize: 12, color: theme.muted }, children: d2 }, i2)) }),
21455
21474
  weeks.map((week, w2) => /* @__PURE__ */ jsx3(Box, { children: week.map((d2, i2) => {
21456
21475
  const end = d2 != null && (d2 === from || d2 === to2) && from > 0;
21457
- const inside = d2 != null && from > 0 && d2 > from && d2 < to2;
21476
+ const inside2 = d2 != null && from > 0 && d2 > from && d2 < to2;
21458
21477
  const band = d2 != null && from > 0 && to2 > from && d2 >= from && d2 <= to2;
21459
21478
  return /* @__PURE__ */ jsxs(Box, { style: { width: CELL, height: CELL, alignItems: "center", justifyContent: "center", position: "relative" }, children: [
21460
21479
  band ? /* @__PURE__ */ jsx3(Box, { style: { position: "absolute", top: 4, bottom: 4, left: d2 === from ? CELL / 2 : 0, right: d2 === to2 ? CELL / 2 : 0, backgroundColor: theme.fill } }) : null,
@@ -21470,7 +21489,7 @@ function Calendar({ element, dir, aligned, colors: c2 = GRAY }) {
21470
21489
  justifyContent: "center",
21471
21490
  fontSize: 14,
21472
21491
  backgroundColor: end ? c2.accent : void 0,
21473
- color: end ? c2.onAccent : inside ? theme.ink : theme.text,
21492
+ color: end ? c2.onAccent : inside2 ? theme.ink : theme.text,
21474
21493
  fontWeight: end ? 600 : 400
21475
21494
  },
21476
21495
  children: [
@@ -21692,7 +21711,8 @@ function Modal({ element, children }) {
21692
21711
  },
21693
21712
  children: [
21694
21713
  p.title ? /* @__PURE__ */ jsx3(Box, { style: { fontSize: 18, fontWeight: 600 }, children: p.title }) : null,
21695
- withDir(children, "column")
21714
+ withDir(children, "column"),
21715
+ p.__mark ? /* @__PURE__ */ jsx3(Marker, { color: p.__mark }) : null
21696
21716
  ]
21697
21717
  }
21698
21718
  ) });
@@ -21727,7 +21747,8 @@ function Drawer({ element, children }) {
21727
21747
  /* @__PURE__ */ jsx3(Box, { style: { fontSize: 18, fontWeight: 600 }, children: p.title }),
21728
21748
  /* @__PURE__ */ jsx3(IconGlyph, { name: "x", size: 22, color: theme.muted })
21729
21749
  ] }) : null,
21730
- withDir(children, "column")
21750
+ withDir(children, "column"),
21751
+ p.__mark ? /* @__PURE__ */ jsx3(Marker, { color: p.__mark }) : null
21731
21752
  ]
21732
21753
  }
21733
21754
  ) });
@@ -21740,7 +21761,8 @@ function Toast({ element, aboveTabBar }) {
21740
21761
  return /* @__PURE__ */ jsx3(Box, { style: { position: "absolute", left: 16, right: 16, justifyContent: side, ...top ? { top: 16 } : { bottom: aboveTabBar ? 92 : 24 } }, children: /* @__PURE__ */ jsxs(Box, { style: { alignItems: "center", gap: 12, padding: "12px 16px", borderRadius: 12, backgroundColor: theme.ink, color: theme.onPrimary, fontSize: 14, boxShadow: "0 6px 20px rgba(0,0,0,0.22)", maxWidth: 420 }, children: [
21741
21762
  p.icon ? /* @__PURE__ */ jsx3(IconGlyph, { name: p.icon, size: 18, color: theme.onPrimary }) : null,
21742
21763
  /* @__PURE__ */ jsx3(Box, { style: { flexShrink: 1 }, children: p.text ?? "" }),
21743
- p.action ? /* @__PURE__ */ jsx3(Box, { style: { fontWeight: 700, marginLeft: 8, flexShrink: 0 }, children: p.action }) : null
21764
+ p.action ? /* @__PURE__ */ jsx3(Box, { style: { fontWeight: 700, marginLeft: 8, flexShrink: 0 }, children: p.action }) : null,
21765
+ p.__mark ? /* @__PURE__ */ jsx3(Marker, { color: p.__mark }) : null
21744
21766
  ] }) });
21745
21767
  }
21746
21768
  function Flow() {
@@ -21817,22 +21839,23 @@ function findAnchors(spec) {
21817
21839
  return [...out, ...tips];
21818
21840
  }
21819
21841
  var MARK = (i2) => `#fe${(i2 >> 8).toString(16).padStart(2, "0")}${(i2 & 255).toString(16).padStart(2, "0")}`;
21820
- function tagForMeasuring(spec, anchors) {
21842
+ function tagForMeasuring(spec, anchors, bodies = []) {
21821
21843
  const tagged = structuredClone(spec);
21822
21844
  const colors = /* @__PURE__ */ new Map();
21823
21845
  let n = 1;
21824
- const tag = (id, field) => {
21825
- const key = field ? `${id}#field` : id;
21846
+ const tag = (id, part) => {
21847
+ const key = part ? `${id}#${part}` : id;
21826
21848
  if (colors.has(key)) return;
21827
21849
  const color = MARK(n++);
21828
21850
  colors.set(key, color);
21829
21851
  const el2 = tagged.elements[id];
21830
- el2.props = { ...el2.props ?? {}, [field ? "__markField" : "__mark"]: color };
21852
+ el2.props = { ...el2.props ?? {}, [part === "field" ? "__markField" : part === "body" ? "__markBody" : "__mark"]: color };
21831
21853
  };
21832
21854
  for (const a of anchors) {
21833
- tag(a.screen, false);
21834
- tag(a.id, a.field);
21855
+ tag(a.screen, "");
21856
+ tag(a.id, a.field ? "field" : "");
21835
21857
  }
21858
+ for (const id of bodies) tag(id, "body");
21836
21859
  return { tagged, colors };
21837
21860
  }
21838
21861
  function readMarkers(svg, colors) {
@@ -21891,35 +21914,54 @@ function tooltipSize(text2) {
21891
21914
  const lines = Math.max(1, Math.ceil(text2.length * 7.4 / 216));
21892
21915
  return { w: width, h: lines * 18 + 12 + 6 };
21893
21916
  }
21917
+ function placeOverlay(spec, a, boxes) {
21918
+ const screen = boxes[a.screen];
21919
+ const anchor = boxes[a.field ? `${a.id}#field` : a.id];
21920
+ if (!screen || !anchor) return null;
21921
+ const p = propsOf(spec.elements, a.id);
21922
+ if (a.kind === "options") {
21923
+ const options = p.options?.length ? p.options : [p.value ?? "Option 1", "Option 2", "Option 3"];
21924
+ const size2 = { w: anchor.w, h: options.length * ROW + 8 };
21925
+ return { screen, anchor, size: size2, pos: place(anchor, size2, screen, { prefer: "below", align: "start", gap: 4 }), options };
21926
+ }
21927
+ if (a.kind === "menu") {
21928
+ const items = p.menu.map((i2) => typeof i2 === "string" ? { label: i2 } : i2);
21929
+ const width = a.end ? 200 : Math.max(180, anchor.w);
21930
+ const inRightHalf = anchor.x + anchor.w / 2 > screen.x + screen.w / 2;
21931
+ const size2 = { w: width, h: items.length * ROW + 8 };
21932
+ return { screen, anchor, size: size2, pos: place(anchor, size2, screen, { prefer: "below", align: a.end || inRightHalf ? "end" : "start", gap: a.end ? -6 : 4 }), items };
21933
+ }
21934
+ if (a.kind === "calendar") {
21935
+ const date = parseDate(p.value);
21936
+ const { start, days } = monthGrid(date?.month);
21937
+ const weeks = Math.ceil((start + days) / 7);
21938
+ const size2 = { w: 296, h: 92 + weeks * 38 };
21939
+ return { screen, anchor, size: size2, pos: place(anchor, size2, screen, { prefer: "below", align: "start", gap: 4 }), date };
21940
+ }
21941
+ const size = tooltipSize(p.tooltip);
21942
+ return { screen, anchor, size, pos: place(anchor, size, screen, { prefer: "above", align: "center", gap: 4 }) };
21943
+ }
21944
+ function overlayBoxes(spec, anchors, boxes) {
21945
+ return anchors.flatMap((a) => {
21946
+ const o2 = placeOverlay(spec, a, boxes);
21947
+ return o2 ? [{ id: a.id, box: { x: o2.screen.x + o2.pos.x, y: o2.screen.y + o2.pos.y, w: o2.size.w, h: o2.size.h } }] : [];
21948
+ });
21949
+ }
21894
21950
  function overlayLayer(spec, anchors, boxes, c2, Calendar2) {
21895
21951
  const byScreen = /* @__PURE__ */ new Map();
21896
21952
  for (const a of anchors) {
21897
- const screen = boxes[a.screen];
21898
- const anchor = boxes[a.field ? `${a.id}#field` : a.id];
21899
- if (!screen || !anchor) continue;
21953
+ const o2 = placeOverlay(spec, a, boxes);
21954
+ if (!o2) continue;
21955
+ const { screen, anchor, size, pos } = o2;
21900
21956
  const p = propsOf(spec.elements, a.id);
21901
21957
  let node = null;
21902
- let pos = null;
21903
21958
  if (a.kind === "options") {
21904
- const options = p.options?.length ? p.options : [p.value ?? "Option 1", "Option 2", "Option 3"];
21905
- const size = { w: anchor.w, h: options.length * ROW + 8 };
21906
- pos = place(anchor, size, screen, { prefer: "below", align: "start", gap: 4 });
21907
- node = /* @__PURE__ */ jsx4(ListCard, { items: options.map((label) => ({ label })), width: size.w, selected: p.value, c: c2 });
21959
+ node = /* @__PURE__ */ jsx4(ListCard, { items: o2.options.map((label) => ({ label })), width: size.w, selected: p.value, c: c2 });
21908
21960
  } else if (a.kind === "menu") {
21909
- const items = p.menu.map((i2) => typeof i2 === "string" ? { label: i2 } : i2);
21910
- const width = a.end ? 200 : Math.max(180, anchor.w);
21911
- const inRightHalf = anchor.x + anchor.w / 2 > screen.x + screen.w / 2;
21912
- pos = place(anchor, { w: width, h: items.length * ROW + 8 }, screen, { prefer: "below", align: a.end || inRightHalf ? "end" : "start", gap: a.end ? -6 : 4 });
21913
- node = /* @__PURE__ */ jsx4(ListCard, { items, width, c: c2 });
21961
+ node = /* @__PURE__ */ jsx4(ListCard, { items: o2.items, width: size.w, c: c2 });
21914
21962
  } else if (a.kind === "calendar") {
21915
- const date = parseDate(p.value);
21916
- const { start, days } = monthGrid(date?.month);
21917
- const weeks = Math.ceil((start + days) / 7);
21918
- pos = place(anchor, { w: 296, h: 92 + weeks * 38 }, screen, { prefer: "below", align: "start", gap: 4 });
21919
- node = /* @__PURE__ */ jsx4("div", { style: { display: "flex", boxShadow: "0 8px 24px rgba(0,0,0,0.18)", borderRadius: 12 }, children: Calendar2({ element: { type: "Calendar", props: { month: date?.month ?? "Month", selected: date?.day } }, colors: c2 }) });
21963
+ node = /* @__PURE__ */ jsx4("div", { style: { display: "flex", boxShadow: "0 8px 24px rgba(0,0,0,0.18)", borderRadius: 12 }, children: Calendar2({ element: { type: "Calendar", props: { month: o2.date?.month ?? "Month", selected: o2.date?.day } }, colors: c2 }) });
21920
21964
  } else {
21921
- const size = tooltipSize(p.tooltip);
21922
- pos = place(anchor, size, screen, { prefer: "above", align: "center", gap: 4 });
21923
21965
  node = /* @__PURE__ */ jsx4(Tooltip, { text: p.tooltip, side: pos.side, width: size.w, arrowX: anchor.x + anchor.w / 2 - (screen.x + pos.x) });
21924
21966
  }
21925
21967
  const list = byScreen.get(a.screen) ?? [];
@@ -22061,9 +22103,7 @@ function flowColor(color, palette) {
22061
22103
  const s = String(color);
22062
22104
  return ACCENTS[s] ?? s;
22063
22105
  }
22064
- function flowLayer(spec, flows, screens, gap, palette, size) {
22065
- const shapes = [];
22066
- const labels = [];
22106
+ function layoutFlows(spec, flows, screens, gap, palette) {
22067
22107
  const placed = [];
22068
22108
  const drawn = [];
22069
22109
  const tips = flows.flatMap(({ ends: ends2 }) => {
@@ -22082,20 +22122,16 @@ function flowLayer(spec, flows, screens, gap, palette, size) {
22082
22122
  return r;
22083
22123
  });
22084
22124
  const ends = routes.flatMap((r) => [r.points[0], r.points[r.points.length - 1]]);
22085
- flows.forEach(({ key }, i2) => {
22125
+ return flows.map(({ key }, i2) => {
22086
22126
  const r = routes[i2];
22087
22127
  const p = spec.elements[key].props ?? {};
22088
- const color = flowColor(p.color, palette);
22089
22128
  const start = p.start ?? "none", end = p.end ?? "arrow";
22090
22129
  const pts = [...r.points];
22091
22130
  pts[0] = add(pts[0], DIR[r.from], INSET[start]);
22092
22131
  pts[pts.length - 1] = add(pts[pts.length - 1], DIR[r.to], INSET[end]);
22093
- const { d: d2, at } = linePath(r, pts, p.line ?? "rounded");
22094
- shapes.push(
22095
- /* @__PURE__ */ jsx5("path", { d: d2, fill: "none", stroke: color, strokeWidth: 2, strokeLinejoin: "round", strokeLinecap: "round", ...p.dashed ? { strokeDasharray: "7 6" } : {} }, `${key}-line`),
22096
- marker(start, r.points[0], DIR[r.from], color, `${key}-start`),
22097
- marker(end, r.points[r.points.length - 1], DIR[r.to], color, `${key}-end`)
22098
- );
22132
+ const line = p.line ?? "rounded";
22133
+ const { d: d2, at } = linePath(r, pts, line);
22134
+ const out = { key, route: r, points: pts, d: d2, color: flowColor(p.color, palette), start, end, line, dashed: !!p.dashed };
22099
22135
  if (p.label) {
22100
22136
  const w2 = flowLabelWidth(String(p.label));
22101
22137
  const covers = (c2) => placed.filter((q) => c2.x - w2 / 2 < q.x + q.w && q.x < c2.x + w2 / 2 && c2.y - 14 < q.y + q.h && q.y < c2.y + 14).length + ends.filter((q) => Math.abs(q.x - c2.x) < w2 / 2 + 12 && Math.abs(q.y - c2.y) < 24).length;
@@ -22105,13 +22141,58 @@ function flowLayer(spec, flows, screens, gap, palette, size) {
22105
22141
  const c2 = at(t), n = covers(c2);
22106
22142
  if (n < best) [mid, best] = [c2, n];
22107
22143
  }
22108
- const top = mid.y - 12;
22109
- placed.push({ x: mid.x - w2 / 2, y: top, w: w2, h: 24 });
22144
+ const box = { x: mid.x - w2 / 2, y: mid.y - 12, w: w2, h: 24 };
22145
+ placed.push(box);
22146
+ out.label = { text: String(p.label), ...box };
22147
+ }
22148
+ return out;
22149
+ });
22150
+ }
22151
+ function flowPolyline(f) {
22152
+ const r = f.route, pts = f.points;
22153
+ const s0 = pts[0], e0 = pts[pts.length - 1];
22154
+ let out;
22155
+ if (r.lane == null && f.line === "straight") out = [s0, e0];
22156
+ else if (r.lane == null && f.line === "curved") {
22157
+ const { at } = linePath(r, pts, f.line);
22158
+ out = Array.from({ length: 25 }, (_, i2) => at(i2 / 24));
22159
+ } else {
22160
+ const radius = f.line === "curved" ? 40 : f.line === "rounded" ? 14 : 0;
22161
+ const q = simplify(pts);
22162
+ out = [q[0]];
22163
+ for (let i2 = 1; i2 < q.length; i2++) {
22164
+ const p = q[i2];
22165
+ if (radius > 0 && i2 < q.length - 1) {
22166
+ const prev = q[i2 - 1], next = q[i2 + 1];
22167
+ const rr2 = Math.min(radius, Math.hypot(p.x - prev.x, p.y - prev.y) / 2, Math.hypot(next.x - p.x, next.y - p.y) / 2);
22168
+ const into = { x: Math.sign(p.x - prev.x), y: Math.sign(p.y - prev.y) }, outd = { x: Math.sign(next.x - p.x), y: Math.sign(next.y - p.y) };
22169
+ const a = { x: p.x - into.x * rr2, y: p.y - into.y * rr2 }, b = { x: p.x + outd.x * rr2, y: p.y + outd.y * rr2 };
22170
+ for (let k = 0; k <= 6; k++) {
22171
+ const t = k / 6;
22172
+ out.push({ x: (1 - t) ** 2 * a.x + 2 * (1 - t) * t * p.x + t ** 2 * b.x, y: (1 - t) ** 2 * a.y + 2 * (1 - t) * t * p.y + t ** 2 * b.y });
22173
+ }
22174
+ } else out.push(p);
22175
+ }
22176
+ }
22177
+ const first = r.points[0], last = r.points[r.points.length - 1];
22178
+ return [first, ...out, last].filter((p, i2, all) => i2 === 0 || Math.hypot(p.x - all[i2 - 1].x, p.y - all[i2 - 1].y) >= 0.01);
22179
+ }
22180
+ function flowLayer(layout, size) {
22181
+ const shapes = [];
22182
+ const labels = [];
22183
+ for (const f of layout) {
22184
+ const r = f.route, { key, color } = f;
22185
+ shapes.push(
22186
+ /* @__PURE__ */ jsx5("path", { d: f.d, fill: "none", stroke: color, strokeWidth: 2, strokeLinejoin: "round", strokeLinecap: "round", ...f.dashed ? { strokeDasharray: "7 6" } : {} }, `${key}-line`),
22187
+ marker(f.start, r.points[0], DIR[r.from], color, `${key}-start`),
22188
+ marker(f.end, r.points[r.points.length - 1], DIR[r.to], color, `${key}-end`)
22189
+ );
22190
+ if (f.label) {
22110
22191
  labels.push(
22111
- /* @__PURE__ */ jsx5("div", { style: { position: "absolute", left: mid.x - w2 / 2, top, width: w2, height: 24, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: 12, backgroundColor: theme.paper, border: `1.5px solid ${color}`, color, fontSize: 12, fontWeight: 600 }, children: p.label }, `${key}-label`)
22192
+ /* @__PURE__ */ jsx5("div", { style: { position: "absolute", left: f.label.x, top: f.label.y, width: f.label.w, height: 24, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: 12, backgroundColor: theme.paper, border: `1.5px solid ${color}`, color, fontSize: 12, fontWeight: 600 }, children: f.label.text }, `${key}-label`)
22112
22193
  );
22113
22194
  }
22114
- });
22195
+ }
22115
22196
  return /* @__PURE__ */ jsxs3("div", { style: { position: "absolute", top: 0, left: 0, width: size.width, height: size.height, display: "flex" }, children: [
22116
22197
  /* @__PURE__ */ jsx5("svg", { width: size.width, height: size.height, viewBox: `0 0 ${size.width} ${size.height}`, style: { position: "absolute", top: 0, left: 0 }, children: shapes }),
22117
22198
  labels
@@ -22902,10 +22983,8 @@ async function renderWireframeSvg(spec, opts = {}) {
22902
22983
  if (issues.length) throw new SpecError(issues);
22903
22984
  }
22904
22985
  const flowsOn = opts.flows !== false;
22905
- const { width, height, gap } = boardLayout(spec, { flows: opts.flows });
22906
- const board = spec.elements[spec.root];
22907
- if ((board.props ?? {}).gap == null && gap !== BOARD_GAP)
22908
- spec = { ...spec, elements: { ...spec.elements, [spec.root]: { ...board, props: { ...board.props, gap } } } };
22986
+ const { width, height } = boardLayout(spec, { flows: opts.flows });
22987
+ spec = withBoardGap(spec, opts.flows);
22909
22988
  const palette = paletteFor(spec.elements[spec.root]?.props?.accent);
22910
22989
  const registry2 = withPalette(palette);
22911
22990
  const draw = async (s, reg) => renderToSvg(s, { registry: reg, includeStandard: false, fonts: await loadFonts(), width, height });
@@ -22913,13 +22992,17 @@ async function renderWireframeSvg(spec, opts = {}) {
22913
22992
  const { anchors, boxes } = await measureAnchors(spec, flows?.measure ?? []);
22914
22993
  if (!anchors.length && !flows?.list.length) return draw(spec, registry2);
22915
22994
  const layers = [];
22916
- if (flows?.list.length) {
22917
- const resolved = flows.list.map(({ key, from, to: to2 }) => ({ key, ends: { from: flows.box(from, boxes) ?? flows.screenBox(from), to: flows.box(to2, boxes) ?? flows.screenBox(to2), fromScreen: flows.screenBox(from), toScreen: flows.screenBox(to2) } })).filter((f) => !!(f.ends.from && f.ends.to && f.ends.fromScreen && f.ends.toScreen));
22918
- layers.push(flowLayer(spec, resolved, flows.screens, flows.gap, palette, { width, height }));
22919
- }
22995
+ if (flows?.list.length) layers.push(flowLayer(layoutFlows(spec, flows.resolve(boxes), flows.screens, flows.gap, palette), { width, height }));
22920
22996
  if (anchors.length) layers.push(overlayLayer(spec, anchors, boxes, palette, registry2.Calendar));
22921
22997
  return draw(spec, withTopLayer(registry2, layers));
22922
22998
  }
22999
+ function withBoardGap(spec, flows) {
23000
+ const { gap } = boardLayout(spec, { flows });
23001
+ const board = spec.elements[spec.root];
23002
+ if ((board.props ?? {}).gap == null && gap !== BOARD_GAP)
23003
+ return { ...spec, elements: { ...spec.elements, [spec.root]: { ...board, props: { ...board.props, gap } } } };
23004
+ return spec;
23005
+ }
22923
23006
  function flowEnds(spec) {
22924
23007
  const els = spec.elements;
22925
23008
  const byId = /* @__PURE__ */ new Map();
@@ -22947,9 +23030,12 @@ function flowEnds(spec) {
22947
23030
  list,
22948
23031
  measure,
22949
23032
  screens: [...screenRects.values()],
22950
- screenBox: (key) => screenRects.get(screenOf(key) ?? ""),
22951
23033
  gap: (els[spec.root].props ?? {}).gap ?? BOARD_GAP,
22952
- box: (key, boxes) => els[key].type === "Screen" ? screenRects.get(key) : boxes[key]
23034
+ resolve(boxes) {
23035
+ const box = (key) => els[key].type === "Screen" ? screenRects.get(key) : boxes[key];
23036
+ const screenBox = (key) => screenRects.get(screenOf(key) ?? "");
23037
+ return list.map(({ key, from, to: to2 }) => ({ key, ends: { from: box(from) ?? screenBox(from), to: box(to2) ?? screenBox(to2), fromScreen: screenBox(from), toScreen: screenBox(to2) } })).filter((f) => !!(f.ends.from && f.ends.to && f.ends.fromScreen && f.ends.toScreen));
23038
+ }
22953
23039
  };
22954
23040
  }
22955
23041
  async function measureAnchors(spec, extra = []) {
@@ -22993,7 +23079,7 @@ function compileWireframe(source) {
22993
23079
  return true;
22994
23080
  });
22995
23081
  unique.sort((a, b) => a.line - b.line);
22996
- return { spec: parsed.spec, issues: unique };
23082
+ return { spec: parsed.spec, issues: unique, lines: parsed.lines };
22997
23083
  }
22998
23084
  function formatIssues(issues) {
22999
23085
  return issues.map((i2) => `line ${i2.line}: ${i2.message}`).join("\n");
@@ -23456,6 +23542,150 @@ function addStyles(doc) {
23456
23542
  doc.head.append(style);
23457
23543
  }
23458
23544
 
23545
+ // src/measure.ts
23546
+ var isFlow = (e) => e.type === "Flow";
23547
+ var COVERS_SCREEN = /* @__PURE__ */ new Set(["Modal", "Drawer"]);
23548
+ var OVERLAYS = /* @__PURE__ */ new Set(["Modal", "Drawer", "Toast"]);
23549
+ var CONTAINERS = new Set(Object.entries(componentDefinitions).filter(([, d2]) => d2.slots.length).map(([name]) => name));
23550
+ var BARS = /* @__PURE__ */ new Set(["NavBar", "TabBar"]);
23551
+ var toBox = (r) => ({ x: round(r.x), y: round(r.y), width: round(r.w), height: round(r.h) });
23552
+ var round = (n) => Math.round(n * 100) / 100;
23553
+ function clip(r, to2) {
23554
+ if (!to2) return r;
23555
+ const x3 = Math.max(r.x, to2.x), y = Math.max(r.y, to2.y);
23556
+ const w2 = Math.min(r.x + r.w, to2.x + to2.w) - x3, h2 = Math.min(r.y + r.h, to2.y + to2.h) - y;
23557
+ return w2 >= 0 && h2 >= 0 && (w2 > 0 || r.w === 0) && (h2 > 0 || r.h === 0) ? { x: x3, y, w: w2, h: h2 } : null;
23558
+ }
23559
+ async function measureElements(spec, lines, opts = {}) {
23560
+ upgradeSpec(spec);
23561
+ if (!opts.skipValidation) {
23562
+ const issues = checkSpec(spec);
23563
+ if (issues.length) throw new SpecError(issues);
23564
+ }
23565
+ const { width, height } = boardLayout(spec, { flows: opts.flows });
23566
+ spec = withBoardGap(spec, opts.flows);
23567
+ const els = spec.elements;
23568
+ const anchors = findAnchors(spec);
23569
+ const every = Object.keys(els).filter((k) => !["Board", "Screen", "Flow"].includes(els[k].type)).map((id) => ({ id, screen: id, kind: "tooltip", field: false }));
23570
+ const screens = Object.keys(els).filter((k) => els[k].type === "Screen");
23571
+ const { tagged, colors } = tagForMeasuring(spec, [...anchors, ...every], screens);
23572
+ const svg = await renderToSvg(tagged, { registry: withMarkers(withPalette(paletteFor())), includeStandard: false, fonts: await loadFonts(), width, height });
23573
+ const boxes = readMarkers(svg, colors);
23574
+ const { items } = boardLayout(spec, { flows: opts.flows });
23575
+ const laidOut = (els[spec.root].children ?? []).filter((k) => els[k]?.type === "Screen" || els[k]?.type === "Note");
23576
+ const frames = /* @__PURE__ */ new Map(), bands = /* @__PURE__ */ new Map();
23577
+ laidOut.forEach((k, i2) => {
23578
+ const it = items[i2];
23579
+ if (!it || els[k].type !== "Screen") return;
23580
+ frames.set(k, { x: it.x, y: it.y + LABEL_H, w: it.width, h: it.height - LABEL_H });
23581
+ bands.set(k, { x: it.x, y: it.y, w: it.width, h: LABEL_H });
23582
+ });
23583
+ const overlays = /* @__PURE__ */ new Map();
23584
+ for (const o2 of overlayBoxes(spec, anchors, boxes)) overlays.set(o2.id, [...overlays.get(o2.id) ?? [], o2.box]);
23585
+ const lineOf = (k) => k == null ? null : lines[k] ?? 0;
23586
+ const endLine = (k) => Math.max(lines[k] ?? 0, ...(els[k].children ?? []).filter((c2) => els[c2]).map(endLine));
23587
+ const labelOf = (k) => {
23588
+ const p = els[k].props ?? {};
23589
+ const v2 = p[PRIMARY_PROP[els[k].type] ?? ""];
23590
+ return typeof v2 === "string" ? v2 : void 0;
23591
+ };
23592
+ const out = [];
23593
+ const visit = (k, parent, screen, cut) => {
23594
+ const el2 = els[k];
23595
+ if (!el2 || el2.type === "Flow") return;
23596
+ const p = el2.props ?? {};
23597
+ const base = { line: lineOf(k), endLine: endLine(k), ...typeof p.id === "string" ? { id: p.id } : {}, type: el2.type, ...labelOf(k) != null ? { label: labelOf(k) } : {}, screenLine: lineOf(screen), parentLine: lineOf(parent) };
23598
+ let entry = null;
23599
+ if (el2.type === "Board") entry = { ...base, box: { x: 0, y: 0, width, height } };
23600
+ else if (el2.type === "Screen") {
23601
+ const frame = frames.get(k);
23602
+ if (frame) entry = { ...base, box: toBox(frame), labelBox: toBox(bands.get(k)) };
23603
+ } else {
23604
+ const r = boxes[k];
23605
+ const seen = r && clip(r, cut);
23606
+ if (seen) {
23607
+ const view = screen ? boxes[screen] ?? frames.get(screen) : void 0;
23608
+ const os3 = (overlays.get(k) ?? []).map((o2) => clip(o2, view)).filter((o2) => !!o2 && o2.w > 0 && o2.h > 0);
23609
+ entry = { ...base, box: toBox(seen), ...os3.length ? { overlays: os3.map(toBox) } : {}, ...COVERS_SCREEN.has(el2.type) ? { scrim: p.scrim ?? true } : {} };
23610
+ }
23611
+ }
23612
+ if (entry) out.push(entry);
23613
+ const inScreen = el2.type === "Screen" ? k : screen;
23614
+ const kids = el2.children ?? [];
23615
+ if (el2.type === "Screen") {
23616
+ const frame = frames.get(k) ?? null;
23617
+ const body = clip(boxes[`${k}#body`] ?? frame, frame);
23618
+ const over = (c2) => OVERLAYS.has(els[c2]?.type);
23619
+ for (const c2 of [...kids.filter((c3) => !over(c3)), ...kids.filter(over)]) visit(c2, k, k, BARS.has(els[c2]?.type) || over(c2) ? frame : body);
23620
+ } else {
23621
+ const inner = el2.type === "Drawer" && boxes[k] ? clip(boxes[k], cut) : cut;
23622
+ for (const c2 of kids) visit(c2, k, inScreen, inner);
23623
+ }
23624
+ };
23625
+ visit(spec.root, null, null, null);
23626
+ if (opts.flows !== false) {
23627
+ const flows = flowEnds(spec);
23628
+ const resolved = flows.resolve(boxes);
23629
+ const ends = new Map(flows.list.map((f) => [f.key, f]));
23630
+ layoutFlows(spec, resolved, flows.screens, flows.gap, paletteFor()).forEach((f) => {
23631
+ const p = els[f.key].props ?? {};
23632
+ const e = ends.get(f.key);
23633
+ out.push({
23634
+ line: lineOf(f.key),
23635
+ endLine: lineOf(f.key),
23636
+ type: "Flow",
23637
+ ...f.label ? { label: f.label.text } : {},
23638
+ from: String(p.from),
23639
+ to: String(p.to),
23640
+ fromLine: lineOf(e.from),
23641
+ toLine: lineOf(e.to),
23642
+ path: flowPolyline(f).map((q) => [round(q.x), round(q.y)]),
23643
+ ...f.label ? { labelBox: toBox(f.label) } : {}
23644
+ });
23645
+ });
23646
+ }
23647
+ return out;
23648
+ }
23649
+ var inside = (b, x3, y) => !!b && b.width > 0 && b.height > 0 && x3 >= b.x && x3 <= b.x + b.width && y >= b.y && y <= b.y + b.height;
23650
+ var center = (b) => [b.x + b.width / 2, b.y + b.height / 2];
23651
+ function distanceToPath(path, x3, y) {
23652
+ let best = Infinity;
23653
+ for (let i2 = 1; i2 < path.length; i2++) {
23654
+ const [ax, ay] = path[i2 - 1], [bx, by] = path[i2];
23655
+ const dx = bx - ax, dy = by - ay, len = dx * dx + dy * dy;
23656
+ const t = len ? Math.max(0, Math.min(1, ((x3 - ax) * dx + (y - ay) * dy) / len)) : 0;
23657
+ best = Math.min(best, Math.hypot(x3 - ax - t * dx, y - ay - t * dy));
23658
+ }
23659
+ return best;
23660
+ }
23661
+ var isContainer = (e) => CONTAINERS.has(e.type);
23662
+ function elementsAt(elements, x3, y, opts = {}) {
23663
+ const tolerance = opts.tolerance ?? 6;
23664
+ const order = new Map(elements.map((e, i2) => [e, i2]));
23665
+ const topFirst = (a, b) => order.get(b) - order.get(a);
23666
+ const covered = /* @__PURE__ */ new Set();
23667
+ const screens = elements.filter((e) => e.type === "Screen");
23668
+ const screenAround = (b) => screens.find((s) => inside(s.box, ...center(b)));
23669
+ for (const [i2, m2] of elements.entries()) {
23670
+ if (isFlow(m2) || !OVERLAYS.has(m2.type)) continue;
23671
+ const screen = screenAround(m2.box);
23672
+ if (!screen || !inside(m2.box, x3, y) && !(m2.scrim && inside(screen.box, x3, y))) continue;
23673
+ for (const e of elements.slice(0, i2)) if (!isFlow(e) && e.type !== "Screen" && e.type !== "Board" && screenAround(e.box) === screen) covered.add(e);
23674
+ }
23675
+ const owners = [], labels = [], leaves = [], lines = [], containers = [];
23676
+ for (const e of elements) {
23677
+ if (isFlow(e)) {
23678
+ if (inside(e.labelBox, x3, y)) labels.push(e);
23679
+ else if (distanceToPath(e.path, x3, y) <= tolerance) lines.push(e);
23680
+ } else if (e.overlays?.some((o2) => inside(o2, x3, y))) owners.push(e);
23681
+ else if (!covered.has(e) && (inside(e.box, x3, y) || inside(e.labelBox, x3, y))) (isContainer(e) ? containers : leaves).push(e);
23682
+ }
23683
+ return [owners, labels, leaves, lines, containers].flatMap((g2) => g2.sort(topFirst));
23684
+ }
23685
+ function elementsAtLine(elements, line) {
23686
+ return elements.filter((e) => e.line > 0 && e.line <= line && line <= e.endLine).sort((a, b) => b.line - a.line);
23687
+ }
23688
+
23459
23689
  // src/playground/language-data.ts
23460
23690
  function unwrap4(t) {
23461
23691
  let cur = t;
@@ -23524,11 +23754,14 @@ export {
23524
23754
  compileWireframe,
23525
23755
  componentDefinitions,
23526
23756
  decodeWireframe,
23757
+ elementsAt,
23758
+ elementsAtLine,
23527
23759
  encodeWireframe,
23528
23760
  formatIssues,
23529
23761
  printWireframeText as formatWireframe,
23530
23762
  languageData,
23531
23763
  mcpTools,
23764
+ measureElements,
23532
23765
  parseWireframeText,
23533
23766
  registry,
23534
23767
  renderAll,
@@ -6,7 +6,7 @@ import {
6
6
  componentDefinitions,
7
7
  iconNames,
8
8
  takesUniversalProps
9
- } from "./chunk-H4Y6VBEX.js";
9
+ } from "./chunk-YOZFCNSK.js";
10
10
 
11
11
  // src/playground/language-data.ts
12
12
  function unwrap(t) {