@ykurilov/agent-chat-skin-tandem 0.69.0 → 0.69.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @ykurilov/agent-chat-skin-tandem
2
2
 
3
+ ## 0.69.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 857777b: Ряд значков шагов в Тандеме — по настоящей ширине строки, «+N» всегда помещается, не вылезает за край узкой колонки; модели заголовков раздумий уходит не больше 1200 знаков раздумья (начало и конец) — длинный заголовок вдвое дешевле.
8
+ - @ykurilov/agent-chat-flows@0.69.1
9
+ - @ykurilov/agent-chat-mcp@0.69.1
10
+ - @ykurilov/agent-chat-messengers@0.69.1
11
+ - @ykurilov/agent-chat-sandbox@0.69.1
12
+ - @ykurilov/agent-chat-skills@0.69.1
13
+ - @ykurilov/agent-chat-react@0.69.1
14
+
3
15
  ## 0.69.0
4
16
 
5
17
  ### Minor Changes
package/dist/index.js CHANGED
@@ -2778,7 +2778,7 @@ function StatusMark2({ status }) {
2778
2778
  import { Button as Button29, cn as cn13 } from "@tandem/ui";
2779
2779
  import { useChatLabels as useChatLabels43 } from "@ykurilov/agent-chat-react";
2780
2780
  import { ChevronDown as ChevronDown6 } from "lucide-react";
2781
- import { useId as useId13 } from "react";
2781
+ import { useId as useId13, useLayoutEffect as useLayoutEffect4, useRef as useRef12, useState as useState8 } from "react";
2782
2782
 
2783
2783
  // src/step-icon.tsx
2784
2784
  import { cn as cn12 } from "@tandem/ui";
@@ -2810,9 +2810,50 @@ function TandemStepIcon({ icon, className }) {
2810
2810
 
2811
2811
  // src/work-steps.tsx
2812
2812
  import { jsx as jsx52, jsxs as jsxs42 } from "react/jsx-runtime";
2813
+ var GAP_PX = 4;
2814
+ function visibleStepIcons(available, total, plusWidthOf, iconPx = 14) {
2815
+ const iconsWidth = (count) => count * iconPx + Math.max(0, count - 1) * GAP_PX;
2816
+ if (iconsWidth(total) <= available) return total;
2817
+ for (let count = total - 1; count > 0; count--) if (iconsWidth(count) + GAP_PX + plusWidthOf(total - count) <= available) return count;
2818
+ return plusWidthOf(total) <= available ? 0 : null;
2819
+ }
2820
+ function useIconRowSpace() {
2821
+ const lineRef = useRef12(null);
2822
+ const rowRef = useRef12(null);
2823
+ const [measured, setMeasured] = useState8(null);
2824
+ useLayoutEffect4(() => {
2825
+ const line = lineRef.current;
2826
+ if (!line || typeof ResizeObserver === "undefined") return;
2827
+ const measure = () => {
2828
+ const button = line.firstElementChild;
2829
+ const row = rowRef.current;
2830
+ if (!button || !row || line.clientWidth === 0) return;
2831
+ const rest = button.getBoundingClientRect().width - row.getBoundingClientRect().width;
2832
+ const icon = row.querySelector("svg")?.getBoundingClientRect().width;
2833
+ const more = row.querySelector("[data-step-icons-more]");
2834
+ const moreText = more?.textContent ?? "";
2835
+ setMeasured((previous) => {
2836
+ const next = {
2837
+ space: Math.max(0, line.clientWidth - rest - 4),
2838
+ iconPx: icon || previous?.iconPx || 16,
2839
+ // Знак «+N» с запасом в 1 px: «+N» всегда влезает.
2840
+ charPx: more && moreText ? more.getBoundingClientRect().width / moreText.length + 1 : previous?.charPx ?? 8
2841
+ };
2842
+ return previous && previous.space === next.space && previous.iconPx === next.iconPx && previous.charPx === next.charPx ? previous : next;
2843
+ });
2844
+ };
2845
+ measure();
2846
+ const observer = new ResizeObserver(measure);
2847
+ observer.observe(line);
2848
+ if (rowRef.current) observer.observe(rowRef.current);
2849
+ return () => observer.disconnect();
2850
+ }, []);
2851
+ return { lineRef, rowRef, measured };
2852
+ }
2813
2853
  function TandemWorkSteps(view) {
2814
2854
  const labels = useChatLabels43();
2815
2855
  const listId = useId13();
2856
+ const { lineRef, rowRef, measured } = useIconRowSpace();
2816
2857
  if (view.state === "live") {
2817
2858
  return /* @__PURE__ */ jsxs42("div", { "data-work-live": true, className: "mb-2 flex h-7 min-w-0 items-center gap-2 last:mb-0 text-xs font-medium text-[var(--foreground-muted)] not-first:mt-3", children: [
2818
2859
  view.icon ? /* @__PURE__ */ jsx52(TandemStepIcon, { icon: view.icon, className: "text-[var(--action)] motion-safe:animate-pulse" }) : /* @__PURE__ */ jsx52("span", { "aria-hidden": "true", className: "size-1.5 shrink-0 rounded-full bg-[var(--action)] motion-safe:animate-pulse" }),
@@ -2822,7 +2863,11 @@ function TandemWorkSteps(view) {
2822
2863
  }
2823
2864
  const { steps, count, open, onOpenChange, items, icons = [], moreIcons = 0 } = view;
2824
2865
  const list = items ?? steps.map((step) => ({ ...step, icon: void 0 }));
2825
- return /* @__PURE__ */ jsxs42("div", { className: "mb-2 not-first:mt-3", children: [
2866
+ const total = icons.length + moreIcons;
2867
+ const fitting = measured && visibleStepIcons(measured.space, total, (count2) => labels.workView.moreSteps(count2).length * measured.charPx, measured.iconPx);
2868
+ const shown = measured === null ? icons.length : fitting === null ? 0 : Math.min(icons.length, fitting);
2869
+ const hidden = fitting === null && measured !== null ? 0 : total - shown;
2870
+ return /* @__PURE__ */ jsxs42("div", { ref: lineRef, className: "mb-2 min-w-0 not-first:mt-3", children: [
2826
2871
  /* @__PURE__ */ jsxs42(
2827
2872
  Button29,
2828
2873
  {
@@ -2834,9 +2879,9 @@ function TandemWorkSteps(view) {
2834
2879
  className: "-ml-2 h-7 max-w-full min-w-0 gap-1 px-2 text-xs font-medium text-[var(--foreground-muted)]",
2835
2880
  children: [
2836
2881
  /* @__PURE__ */ jsx52("span", { className: "shrink-0", children: labels.workView.stepsDone(count) }),
2837
- icons.length > 0 && /* @__PURE__ */ jsxs42("span", { "data-step-icons": true, "aria-hidden": "true", className: "ml-1 flex min-w-0 items-center gap-1 overflow-hidden text-[var(--foreground-subtle)]", children: [
2838
- icons.map((icon, index) => /* @__PURE__ */ jsx52(TandemStepIcon, { icon }, index)),
2839
- moreIcons > 0 && /* @__PURE__ */ jsx52("span", { className: "shrink-0 tabular-nums", children: labels.workView.moreSteps(moreIcons) })
2882
+ icons.length > 0 && /* @__PURE__ */ jsxs42("span", { ref: rowRef, "data-step-icons": true, "aria-hidden": "true", className: "ml-1 flex min-w-0 items-center gap-1 overflow-hidden text-[var(--foreground-subtle)]", children: [
2883
+ icons.slice(0, shown).map((icon, index) => /* @__PURE__ */ jsx52(TandemStepIcon, { icon }, index)),
2884
+ hidden > 0 && /* @__PURE__ */ jsx52("span", { "data-step-icons-more": true, className: "shrink-0 tabular-nums", children: labels.workView.moreSteps(hidden) })
2840
2885
  ] }),
2841
2886
  /* @__PURE__ */ jsx52(ChevronDown6, { "aria-hidden": "true", className: cn13("size-3.5 shrink-0 transition-transform duration-[var(--motion-fast)]", open && "rotate-180") })
2842
2887
  ]