@flytedan/flytebot-design-system 0.11.4 → 0.11.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1354,8 +1354,9 @@ interface EntityRowMetric {
1354
1354
  icon?: string;
1355
1355
  /** Fixed cell width in px. Same value on the same column of every row is what makes
1356
1356
  * the strip a real aligned column rather than text that happens to sit near text.
1357
- * On a narrow screen (≤768px) cells size to their figure instead, so a phone-width row
1358
- * shows every figure rather than clipping whole columns off its end. */
1357
+ * It is the width a cell takes when the strip has room for every column at its width;
1358
+ * in a strip too narrow for that, cells shrink toward their own figure first, so a
1359
+ * narrow row loses alignment before it loses a figure. */
1359
1360
  width?: number;
1360
1361
  tone?: "default" | "muted" | "danger";
1361
1362
  }
@@ -2558,9 +2559,9 @@ declare function SaturationDistribution({ campuses, floorBand, floorScore, onSel
2558
2559
 
2559
2560
  /**
2560
2561
  * Realized media mix against the strategic target, one row per channel.
2561
- * Realized is a solid brand bar, target a neutral tick on the same row, and the
2562
- * gap is labelled directly on the bar — the gap is the story, so it never hides
2563
- * in a legend.
2562
+ * Realized is a solid tone bar, target a striped marker on the same row, and the
2563
+ * realized share is labelled directly beside them — the gap is the story, so it
2564
+ * never hides in a legend.
2564
2565
  */
2565
2566
  interface MixGapRow {
2566
2567
  channel: string;
package/dist/index.d.ts CHANGED
@@ -1354,8 +1354,9 @@ interface EntityRowMetric {
1354
1354
  icon?: string;
1355
1355
  /** Fixed cell width in px. Same value on the same column of every row is what makes
1356
1356
  * the strip a real aligned column rather than text that happens to sit near text.
1357
- * On a narrow screen (≤768px) cells size to their figure instead, so a phone-width row
1358
- * shows every figure rather than clipping whole columns off its end. */
1357
+ * It is the width a cell takes when the strip has room for every column at its width;
1358
+ * in a strip too narrow for that, cells shrink toward their own figure first, so a
1359
+ * narrow row loses alignment before it loses a figure. */
1359
1360
  width?: number;
1360
1361
  tone?: "default" | "muted" | "danger";
1361
1362
  }
@@ -2558,9 +2559,9 @@ declare function SaturationDistribution({ campuses, floorBand, floorScore, onSel
2558
2559
 
2559
2560
  /**
2560
2561
  * Realized media mix against the strategic target, one row per channel.
2561
- * Realized is a solid brand bar, target a neutral tick on the same row, and the
2562
- * gap is labelled directly on the bar — the gap is the story, so it never hides
2563
- * in a legend.
2562
+ * Realized is a solid tone bar, target a striped marker on the same row, and the
2563
+ * realized share is labelled directly beside them — the gap is the story, so it
2564
+ * never hides in a legend.
2564
2565
  */
2565
2566
  interface MixGapRow {
2566
2567
  channel: string;
package/dist/index.js CHANGED
@@ -2833,16 +2833,13 @@ function EntityRowMetrics({ metrics, className = "", style }) {
2833
2833
  return /* @__PURE__ */ jsx39("span", { className: ["fd-erow-metrics", className].filter(Boolean).join(" "), style, children: metrics.map((m, i) => {
2834
2834
  const key = m.id || m.label || i;
2835
2835
  const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
2836
- const cellStyle = { "--erow-metric-w": (m.width || ENTITY_ROW_METRIC_WIDTH) + "px", color: METRIC_TONE_COLOR[m.tone || "default"] };
2836
+ const tone = { color: METRIC_TONE_COLOR[m.tone || "default"] };
2837
2837
  const content = /* @__PURE__ */ jsxs35(React17.Fragment, { children: [
2838
2838
  m.icon ? /* @__PURE__ */ jsx39("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
2839
2839
  /* @__PURE__ */ jsx39("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
2840
2840
  /* @__PURE__ */ jsx39("span", { className: "fd-sr", children: " " + m.label })
2841
2841
  ] });
2842
- if (m.tooltip == null) {
2843
- return /* @__PURE__ */ jsx39("span", { className: className2, style: cellStyle, title: m.label, children: content }, key);
2844
- }
2845
- return /* @__PURE__ */ jsx39(Tooltip, { label: m.tooltip, children: /* @__PURE__ */ jsx39("button", { type: "button", className: className2, style: cellStyle, children: content }) }, key);
2842
+ return /* @__PURE__ */ jsx39("span", { className: "fd-erow-cell", style: { "--erow-metric-w": (m.width || ENTITY_ROW_METRIC_WIDTH) + "px" }, children: m.tooltip == null ? /* @__PURE__ */ jsx39("span", { className: className2, style: tone, title: m.label, children: content }) : /* @__PURE__ */ jsx39(Tooltip, { label: m.tooltip, children: /* @__PURE__ */ jsx39("button", { type: "button", className: className2, style: tone, children: content }) }) }, key);
2846
2843
  }) });
2847
2844
  }
2848
2845
  function EntityRow({
@@ -3198,8 +3195,10 @@ function TransferList({
3198
3195
  );
3199
3196
  };
3200
3197
  return /* @__PURE__ */ jsxs38("div", { className: ["fd-tlist", className].filter(Boolean).join(" "), children: [
3201
- renderSide("left", left, "right"),
3202
- renderSide("right", right, "left"),
3198
+ /* @__PURE__ */ jsxs38("div", { className: "fd-tlist-panes", children: [
3199
+ renderSide("left", left, "right"),
3200
+ renderSide("right", right, "left")
3201
+ ] }),
3203
3202
  drag ? createPortal4(
3204
3203
  /* @__PURE__ */ jsx43(
3205
3204
  "div",
@@ -8107,11 +8106,24 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
8107
8106
  // src/components/planner/MixGap.tsx
8108
8107
  import * as React37 from "react";
8109
8108
  import { Fragment as Fragment18, jsx as jsx66, jsxs as jsxs61 } from "react/jsx-runtime";
8109
+ var MIX_GAP_LAYOUT = {
8110
+ trackHeight: 30,
8111
+ barHeight: 20,
8112
+ targetWidth: 6,
8113
+ labelGap: 6,
8114
+ labelGutter: 50
8115
+ };
8116
+ var MIX_GAP_TARGET_STRIPE = "repeating-linear-gradient(135deg, var(--n-600) 0 2px, var(--n-300) 2px 4px)";
8117
+ function mixGapOffset(value, max) {
8118
+ return `calc((100% - ${MIX_GAP_LAYOUT.labelGutter}px) * ${value / max})`;
8119
+ }
8110
8120
  function MixGap({ rows = [], loading = false, className = "" }) {
8111
8121
  const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
8112
8122
  const [hover, setHover] = React37.useState(null);
8113
8123
  const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
8114
8124
  const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
8125
+ const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
8126
+ const barTop = (trackHeight - barHeight) / 2;
8115
8127
  return /* @__PURE__ */ jsxs61("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
8116
8128
  /* @__PURE__ */ jsxs61("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
8117
8129
  [["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ jsxs61("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
@@ -8119,7 +8131,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
8119
8131
  l
8120
8132
  ] }, l)),
8121
8133
  /* @__PURE__ */ jsxs61("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
8122
- /* @__PURE__ */ jsx66("span", { style: { width: 3, height: 14, background: "var(--n-500)" } }),
8134
+ /* @__PURE__ */ jsx66("span", { "data-mixgap-legend-target": "", style: { width: targetWidth, height: 16, borderRadius: 1, background: MIX_GAP_TARGET_STRIPE } }),
8123
8135
  "Target"
8124
8136
  ] })
8125
8137
  ] }),
@@ -8127,6 +8139,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
8127
8139
  const gap = r.realized - r.target;
8128
8140
  const tone = toneOf(gap);
8129
8141
  const tip = "Realized " + r.realized + "% vs " + r.target + "% target" + (gap < -1 ? " \xB7 " + Math.abs(gap).toFixed(0) + " pts short" : gap > 1 ? " \xB7 " + gap.toFixed(0) + " pts over" : " \xB7 on target") + (r.note ? " \u2014 " + r.note : "");
8142
+ const labelLeft = r.realized > r.target ? `calc(${mixGapOffset(r.realized, max)} + ${labelGap}px)` : `calc(${mixGapOffset(r.target, max)} + ${targetWidth / 2 + labelGap}px)`;
8130
8143
  return /* @__PURE__ */ jsxs61(
8131
8144
  "div",
8132
8145
  {
@@ -8136,14 +8149,14 @@ function MixGap({ rows = [], loading = false, className = "" }) {
8136
8149
  onMouseLeave: () => setHover(null),
8137
8150
  children: [
8138
8151
  /* @__PURE__ */ jsx66("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ jsx66(ChannelTag, { channel: r.channel, size: "sm" }) }),
8139
- /* @__PURE__ */ jsx66("span", { style: { position: "relative", flex: 1, height: 22, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx66("span", { className: "fd-skel", style: { position: "absolute", inset: "5px 0", borderRadius: 3 } }) : /* @__PURE__ */ jsxs61(Fragment18, { children: [
8140
- /* @__PURE__ */ jsx66("span", { style: { position: "absolute", left: 0, top: 5, height: 12, width: r.realized / max * 100 + "%", background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
8141
- /* @__PURE__ */ jsx66("span", { style: { position: "absolute", left: r.target / max * 100 + "%", top: 0, width: 3, height: 22, background: "var(--n-500)", borderRadius: 1 } }),
8142
- /* @__PURE__ */ jsxs61("span", { className: "fd-num", style: { position: "absolute", right: Math.max(r.realized, r.target) / max > 0.82 ? 0 : "auto", left: Math.max(r.realized, r.target) / max > 0.82 ? "auto" : "calc(" + Math.max(r.realized, r.target) / max * 100 + "% + 10px)", top: 2, fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap", background: Math.max(r.realized, r.target) / max > 0.82 ? "var(--surface)" : "none", paddingLeft: 3 }, children: [
8152
+ /* @__PURE__ */ jsx66("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx66("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ jsxs61(Fragment18, { children: [
8153
+ /* @__PURE__ */ jsx66("span", { "data-mixgap-bar": "", style: { position: "absolute", left: 0, top: barTop, height: barHeight, width: mixGapOffset(r.realized, max), background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
8154
+ /* @__PURE__ */ jsx66("span", { "data-mixgap-target": "", style: { position: "absolute", left: `calc(${mixGapOffset(r.target, max)} - ${targetWidth / 2}px)`, top: 0, width: targetWidth, height: trackHeight, background: MIX_GAP_TARGET_STRIPE, borderRadius: 1 } }),
8155
+ /* @__PURE__ */ jsxs61("span", { "data-mixgap-label": "", className: "fd-num", style: { position: "absolute", left: labelLeft, top: "50%", transform: "translateY(-50%)", fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap" }, children: [
8143
8156
  r.realized,
8144
8157
  "%"
8145
8158
  ] }),
8146
- hover === r.channel ? /* @__PURE__ */ jsx66("span", { className: "fd-tooltip", role: "tooltip", style: { position: "absolute", left: 0, right: "auto", bottom: 26, maxWidth: "min(340px, 100%)", whiteSpace: "normal", textAlign: "left", width: "max-content" }, children: tip }) : null
8159
+ hover === r.channel ? /* @__PURE__ */ jsx66("span", { className: "fd-tooltip", role: "tooltip", style: { position: "absolute", left: 0, right: "auto", bottom: trackHeight + 4, maxWidth: "min(340px, 100%)", whiteSpace: "normal", textAlign: "left", width: "max-content" }, children: tip }) : null
8147
8160
  ] }) })
8148
8161
  ]
8149
8162
  },