@open-flow/ui 0.3.1 → 0.5.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.
Files changed (65) hide show
  1. package/dist/app.d.ts +2 -1
  2. package/dist/app.js +1 -1
  3. package/dist/canvas-gestures.d.ts +15 -0
  4. package/dist/canvas-gestures.js +1 -0
  5. package/dist/connect-popover.d.ts +9 -0
  6. package/dist/connect-popover.js +1 -0
  7. package/dist/cta.d.ts +17 -0
  8. package/dist/cta.js +1 -0
  9. package/dist/dev-actions.d.ts +2 -1
  10. package/dist/dev-actions.js +1 -1
  11. package/dist/dev-actions.noop.d.ts +2 -1
  12. package/dist/dev-actions.noop.js +1 -1
  13. package/dist/floating.d.ts +35 -0
  14. package/dist/floating.js +1 -0
  15. package/dist/flow-canvas.d.ts +103 -0
  16. package/dist/flow-canvas.js +1 -0
  17. package/dist/flow-edit.d.ts +61 -0
  18. package/dist/flow-edit.js +1 -0
  19. package/dist/flow-frames.d.ts +25 -0
  20. package/dist/flow-frames.js +1 -0
  21. package/dist/flow-graph.d.ts +109 -0
  22. package/dist/flow-graph.js +1 -0
  23. package/dist/flow-layout.d.ts +30 -0
  24. package/dist/flow-layout.js +1 -0
  25. package/dist/flow-start.d.ts +9 -0
  26. package/dist/flow-start.js +1 -0
  27. package/dist/frame-view.js +1 -1
  28. package/dist/frame.d.ts +21 -1
  29. package/dist/frame.js +1 -1
  30. package/dist/index.d.ts +3 -3
  31. package/dist/index.js +1 -1
  32. package/dist/journey-acts.d.ts +19 -0
  33. package/dist/journey-acts.js +1 -0
  34. package/dist/manifest.d.ts +3 -2
  35. package/dist/manifest.js +1 -1
  36. package/dist/manifest.types.d.ts +11 -1
  37. package/dist/manifest.types.js +1 -1
  38. package/dist/mirror.d.ts +6 -1
  39. package/dist/mirror.js +1 -1
  40. package/dist/node-actions.d.ts +24 -0
  41. package/dist/node-actions.js +1 -0
  42. package/dist/node-menu.d.ts +13 -0
  43. package/dist/node-menu.js +1 -0
  44. package/dist/panels/components.js +1 -1
  45. package/dist/panels/elements.js +1 -1
  46. package/dist/panels/flow-canvas-board.d.ts +49 -0
  47. package/dist/panels/flow-canvas-board.js +1 -0
  48. package/dist/panels/flow-cards.d.ts +54 -0
  49. package/dist/panels/flow-cards.js +1 -0
  50. package/dist/panels/flows.d.ts +5 -5
  51. package/dist/panels/flows.js +1 -1
  52. package/dist/pick-highlight.d.ts +26 -0
  53. package/dist/pick-highlight.js +1 -1
  54. package/dist/pin.d.ts +34 -0
  55. package/dist/screen-frame.d.ts +11 -2
  56. package/dist/screen-frame.js +1 -1
  57. package/dist/screen-sketch.d.ts +30 -0
  58. package/dist/screen-sketch.js +1 -0
  59. package/dist/screen-toolbar.d.ts +4 -3
  60. package/dist/screen-toolbar.js +1 -1
  61. package/dist/server.d.ts +2 -1
  62. package/dist/server.js +2 -1
  63. package/dist/workbench-app.d.ts +3 -2
  64. package/dist/workbench-app.js +1 -1
  65. package/package.json +1 -1
package/dist/frame.js CHANGED
@@ -1 +1 @@
1
- "use client";import{jsx as s,jsxs as x}from"react/jsx-runtime";import{useEffect as b,useRef as p}from"react";import{cx as f}from"./cx";import{isElement as g}from"./dom-realm";import{PickBox as k}from"./pick-box";function L({label:t,meta:n,children:o,className:c}){return x("div",{className:f("overflow-hidden rounded-lg border border-zinc-300 bg-white shadow-sm","dark:border-zinc-700 dark:bg-zinc-900",c),children:[(t||n)&&x("div",{className:"flex items-center justify-between gap-3 border-b border-zinc-200 bg-zinc-50 px-3 py-1.5 text-[11px] font-medium tracking-wide text-zinc-600 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-300",children:[s("span",{className:"truncate",children:t}),n&&s("span",{className:"truncate font-mono text-[10px] text-zinc-500 dark:text-zinc-400",children:n})]}),o]})}function y({theme:t,children:n,padded:o=!0,editing:c}){return s("div",{className:f(t==="dark"&&"dark"),children:s(k,{enabled:c,className:f("bg-background text-foreground",o&&"p-6"),children:n})})}function N({src:t,title:n,width:o,height:c,theme:i,frameRef:l,onLoad:a}){const d=p(null);return b(()=>{if(i===void 0)return;const e=d.current;if(!e)return;const r=()=>{try{e.contentDocument?.documentElement.classList.toggle("dark",i==="dark")}catch{}};r(),e.addEventListener("load",r);const u=[300,1200,2500].map(m=>setTimeout(r,m));return()=>{e.removeEventListener("load",r);for(const m of u)clearTimeout(m)}},[i,t]),s("iframe",{ref:e=>{d.current=e,l?.(e)},src:t,title:n,width:o,height:c,onLoad:e=>a?.(e.currentTarget),className:"border-0 bg-white",style:{width:o,height:c}})}function j({srcdoc:t,title:n,width:o,height:c,theme:i}){const l=p(null);return b(()=>{const a=l.current;if(!a)return;const d=r=>{const u=r.target;g(u)&&u.closest("a[href]")&&r.preventDefault()},e=()=>{try{const r=a.contentDocument;if(!r)return;r.documentElement.classList.toggle("dark",i==="dark"),r.addEventListener("click",d,!0)}catch{}};return e(),a.addEventListener("load",e),()=>{a.removeEventListener("load",e);try{a.contentDocument?.removeEventListener("click",d,!0)}catch{}}},[i,t]),s("iframe",{ref:l,srcDoc:t,title:n,sandbox:"allow-same-origin","data-workbench-mirror":"",tabIndex:-1,width:o,height:c,className:"border-0 bg-white",style:{width:o,height:c}})}export{L as FrameShell,y as InlineSurface,j as MirrorFrame,N as RouteFrame};
1
+ "use client";import{jsx as m,jsxs as _}from"react/jsx-runtime";import{useContext as W,useEffect as y,useRef as C}from"react";import{CanvasGesturesContext as X,EDGE_VAR as g}from"./canvas-gestures";import{cx as z}from"./cx";import{ctaOf as Y,CTA_MAX_DEPTH as B,semanticCtaOf as G}from"./cta";import{isElement as H,readProp as $}from"./dom-realm";import{PickBox as K}from"./pick-box";import{mapPoint as F,mapRect as U}from"./pick-highlight";function nt({label:e,meta:o,children:c,className:i}){return _("div",{className:z("overflow-hidden border-zinc-300 bg-white dark:border-zinc-700 dark:bg-zinc-900",i),style:{borderWidth:`var(${g}, 1px)`,borderStyle:"solid",borderRadius:`min(calc(var(${g}, 1px) * 8), 6%)`,boxShadow:`0 calc(var(${g}, 1px) * 1) calc(var(${g}, 1px) * 2) rgb(0 0 0 / 0.05)`},children:[(e||o)&&_("div",{className:"flex items-center justify-between gap-3 border-b border-zinc-200 bg-zinc-50 px-3 py-1.5 text-[11px] font-medium tracking-wide text-zinc-600 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-300",children:[m("span",{className:"truncate",children:e}),o&&m("span",{className:"truncate font-mono text-[10px] text-zinc-500 dark:text-zinc-400",children:o})]}),c]})}function ot({theme:e,children:o,padded:c=!0,editing:i}){return m("div",{className:z(e==="dark"&&"dark"),children:m(K,{enabled:i,className:z("bg-background text-foreground",c&&"p-6"),children:o})})}function ct({src:e,title:o,width:c,height:i,theme:u,frameRef:b,onLoad:x}){const p=C(null);return y(()=>{if(u===void 0)return;const n=p.current;if(!n)return;const f=()=>{try{n.contentDocument?.documentElement.classList.toggle("dark",u==="dark")}catch{}};f(),n.addEventListener("load",f);const h=[300,1200,2500].map(a=>setTimeout(f,a));return()=>{n.removeEventListener("load",f);for(const a of h)clearTimeout(a)}},[u,e]),m("iframe",{ref:n=>{p.current=n,b?.(n)},src:e,title:o,width:c,height:i,onLoad:n=>x?.(n.currentTarget),className:"border-0 bg-white",style:{width:c,height:i}})}function I(e){return(e.tagName==="INPUT"?String($(e,"value")??""):"")||e.getAttribute("aria-label")||e.getAttribute("title")||e.textContent||""}function M(e,o,c){const i=c?e.ownerDocument.defaultView:null,u=c?e.getBoundingClientRect():null;return{tag:e.tagName.toUpperCase(),role:e.getAttribute("role")?.toLowerCase()??null,type:e.getAttribute("type")?.toLowerCase()??null,href:e.hasAttribute("href"),onclick:e.hasAttribute("onclick"),disabled:e.hasAttribute("disabled")||e.getAttribute("aria-disabled")==="true",cursor:i?i.getComputedStyle(e).cursor:"auto",name:c?I(e):"",share:u&&o>0?u.width*u.height/o:1}}function A(e){const o=C(e);return y(()=>{o.current=e},[e]),o}function at({srcdoc:e,title:o,width:c,height:i,theme:u,connect:b,onMenu:x}){const p=C(null),n=A(b),f=A(x),h=A(W(X));return y(()=>{const a=p.current;if(!a)return;const D=a.clientWidth*a.clientHeight,v=t=>{if(!H(t))return null;const r=[];for(let l=t;l&&r.length<B;l=l.parentElement)r.push(l);const s=r.map(l=>M(l,D,!1)),d=G(s);if(d)return r[s.indexOf(d)]??null;const j=r.map(l=>M(l,D,!0)),T=Y(j);return T?r[j.indexOf(T)]??null:null},k=(t,r="append")=>{const s=t.closest("a[href]"),d=I(t).trim().replace(/\s+/g," ").slice(0,80);return{wants:r,text:d,href:s?String($(s,"href")):null,rect:U(t,a)}},N=t=>{const r=t.target;H(r)&&r.closest("a[href]")&&t.preventDefault();const s=v(r);n.current?.onPick(s?k(s):null)};let E=null,L=null;const O=t=>{if(!n.current||t.target===L)return;L=t.target;const r=v(t.target);r!==E&&(E=r,n.current.onHover(r?k(r):null))},R=()=>{E=null,L=null,n.current?.onHover(null)},P=t=>{const r=n.current&&!n.current.busy?n.current:null,s=r?v(t.target):null;if(s&&r){t.preventDefault(),r.onPick(k(s,"fork"));return}const d=f.current;d&&(t.preventDefault(),d(F(t.clientX,t.clientY,a)))},S=t=>{if(!t.ctrlKey&&!t.metaKey)return;t.preventDefault();const r=F(t.clientX,t.clientY,a);h.current?.zoomAtClient(r.x,r.y,t.deltaY,t.deltaMode)},w=()=>{try{const t=a.contentDocument;if(!t)return;t.documentElement.classList.toggle("dark",u==="dark"),t.addEventListener("click",N,!0),t.addEventListener("mouseover",O,!0),t.addEventListener("mouseleave",R),t.addEventListener("wheel",S,{passive:!1}),t.addEventListener("contextmenu",P,!0)}catch(t){console.warn("[workbench] no se pudo armar el espejo",t)}};return w(),a.addEventListener("load",w),()=>{a.removeEventListener("load",w);try{const t=a.contentDocument;t?.removeEventListener("click",N,!0),t?.removeEventListener("mouseover",O,!0),t?.removeEventListener("mouseleave",R),t?.removeEventListener("wheel",S),t?.removeEventListener("contextmenu",P,!0)}catch{}}},[u,e,c,i]),m("iframe",{ref:p,srcDoc:e,title:o,sandbox:"allow-same-origin","data-workbench-mirror":"",tabIndex:-1,width:c,height:i,className:"border-0 bg-white",style:{width:c,height:i}})}export{nt as FrameShell,ot as InlineSurface,at as MirrorFrame,ct as RouteFrame};
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { byGroup, flowById, frameUrl, groupLabel, surfaceForRoute, surfaceFromPins, viewportById, workbenchUrl, MANIFEST_VERSION, } from "./manifest";
2
- export type { ComponentEntry, Flow, FlowStep, HardcodedColor, LearnedFile, Manifest, Origin, PropSample, PropSpec, Renderability, RouteEntry, RouteKind, SampleKind, SampleValue, ScanStats, Surface, SurfaceFiles, Token, TokenGroup, TokenKind, TokenUse, Viewport, ViewerConfig, Weight, } from "./manifest";
1
+ export { byGroup, flowById, tokenCount, frameUrl, groupLabel, surfaceForRoute, surfaceFromPins, viewportById, workbenchUrl, MANIFEST_VERSION, } from "./manifest";
2
+ export type { ComponentEntry, Flow, FlowStep, FlowBranch, HardcodedColor, LearnedFile, Manifest, Origin, PropSample, PropSpec, Renderability, RouteEntry, RouteKind, SampleKind, SampleValue, ScanStats, Surface, SurfaceFiles, Token, TokenGroup, TokenKind, TokenUse, Viewport, ViewerConfig, Weight, } from "./manifest";
3
3
  export { parseManifest } from "./parse-manifest";
4
4
  export type { RegistryEntry } from "./registry";
5
- export type { NewTicketInput, Pin, RuntimeError, TicketSummary } from "./pin";
5
+ export type { FlowBody, FlowBranchInput, FlowStepInput, NewTicketInput, Pin, RuntimeError, SaveFlowInput, SaveFlowResult, TicketSummary, } from "./pin";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{byGroup as e,flowById as f,frameUrl as a,groupLabel as p,surfaceForRoute as s,surfaceFromPins as t,viewportById as u,workbenchUrl as l,MANIFEST_VERSION as m}from"./manifest";import{parseManifest as b}from"./parse-manifest";export{m as MANIFEST_VERSION,e as byGroup,f as flowById,a as frameUrl,p as groupLabel,b as parseManifest,s as surfaceForRoute,t as surfaceFromPins,u as viewportById,l as workbenchUrl};
1
+ import{byGroup as e,flowById as f,tokenCount as t,frameUrl as a,groupLabel as p,surfaceForRoute as u,surfaceFromPins as n,viewportById as s,workbenchUrl as l,MANIFEST_VERSION as m}from"./manifest";import{parseManifest as b}from"./parse-manifest";export{m as MANIFEST_VERSION,e as byGroup,f as flowById,a as frameUrl,p as groupLabel,b as parseManifest,u as surfaceForRoute,n as surfaceFromPins,t as tokenCount,s as viewportById,l as workbenchUrl};
@@ -0,0 +1,19 @@
1
+ export interface JourneyAct {
2
+ kind: "append" | "fork";
3
+ verb: string;
4
+ button: string;
5
+ menu: string;
6
+ chip: string | null;
7
+ hint: string;
8
+ title: string;
9
+ }
10
+ export declare const APPEND: JourneyAct;
11
+ export declare const FORK: JourneyAct;
12
+ export declare const ONLY_FROM_TRUNK = "Una rama sale siempre de un paso del tronco.";
13
+ export declare const ONLY_AT_THE_END = "S\u00F3lo se a\u00F1ade al final de una fila; desde el medio, se ramifica.";
14
+ export declare const AT_CAP = "El recorrido ya tiene todas las pantallas que caben.";
15
+ export declare const HAS_BRANCHES = "Este paso tiene ramas; qu\u00EDtalas primero.";
16
+ export declare const EN_CURSO = "Hay una escritura en curso.";
17
+ export declare const CLICK = "clic";
18
+ export declare const RIGHT_CLICK = "clic derecho";
19
+ export declare const NOWHERE = "aqu\u00ED no se puede a\u00F1adir";
@@ -0,0 +1 @@
1
+ const a={kind:"append",verb:"seguir",button:"Seguir aqu\xED",menu:"Seguir aqu\xED",chip:null,hint:"la nueva pantalla sigue a \xE9sta",title:"A\xF1ade una pantalla despu\xE9s de \xE9sta."},e={kind:"fork",verb:"ramificar",button:"Nueva rama",menu:"Nueva rama desde aqu\xED",chip:"+ rama",hint:"la nueva pantalla empieza una rama desde \xE9sta",title:"Empieza una rama desde este paso."},t="Una rama sale siempre de un paso del tronco.",n="S\xF3lo se a\xF1ade al final de una fila; desde el medio, se ramifica.",r="El recorrido ya tiene todas las pantallas que caben.",s="Este paso tiene ramas; qu\xEDtalas primero.",o="Hay una escritura en curso.",i="clic",u="clic derecho",p="aqu\xED no se puede a\xF1adir";export{a as APPEND,r as AT_CAP,i as CLICK,o as EN_CURSO,e as FORK,s as HAS_BRANCHES,p as NOWHERE,n as ONLY_AT_THE_END,t as ONLY_FROM_TRUNK,u as RIGHT_CLICK};
@@ -1,5 +1,5 @@
1
- import type { ComponentEntry, Flow, Viewport, ViewerConfig } from "./manifest.types";
2
- export type { ComponentEntry, Flow, FlowStep, HardcodedColor, LearnedFile, Manifest, Origin, PropSample, PropSpec, Renderability, RouteEntry, RouteKind, SampleKind, SampleValue, ScanStats, Surface, SurfaceFiles, Token, TokenGroup, TokenKind, TokenUse, Viewport, ViewerConfig, Weight, } from "./manifest.types";
1
+ import type { ComponentEntry, Flow, TokenGroup, Viewport, ViewerConfig } from "./manifest.types";
2
+ export type { ComponentEntry, Flow, FlowStep, FlowBranch, HardcodedColor, LearnedFile, Manifest, Origin, PropSample, PropSpec, Renderability, RouteEntry, RouteKind, SampleKind, SampleValue, ScanStats, Surface, SurfaceFiles, Token, TokenGroup, TokenKind, TokenUse, Viewport, ViewerConfig, Weight, } from "./manifest.types";
3
3
  export { MANIFEST_VERSION } from "./manifest.types";
4
4
  export declare function groupLabel(config: ViewerConfig, group: string): string;
5
5
  export declare function viewportById(config: ViewerConfig, id: string | undefined): Viewport;
@@ -16,4 +16,5 @@ export declare function surfaceForRoute(routes: ReadonlyArray<{
16
16
  dynamic: boolean;
17
17
  }>, pathname: string): string | null;
18
18
  export declare function frameUrl(config: ViewerConfig, params: Record<string, string>): string;
19
+ export declare function tokenCount(groups: TokenGroup[]): number;
19
20
  export declare function flowById(flows: Flow[], id: string | undefined): Flow | undefined;
package/dist/manifest.js CHANGED
@@ -1 +1 @@
1
- import{MANIFEST_VERSION as h}from"./manifest.types";function s(e,t){return e.groupLabels[t]??t}function u(e,t){const r=e.viewports.find(n=>n.id===t),o=e.viewports[0];if(r)return r;if(o)return o;throw new Error("El manifiesto no declara ning\xFAn viewport.")}function f(e,t,r){const o=e.mountPath.replace(/\/+$/,""),n=t?`${o}/${t}`:o;return r?`${n}?${r.toString()}`:n}function c(e){const t=new Map;for(const r of e){const o=t.get(r.group);o?o.push(r):t.set(r.group,[r])}return[...t.entries()]}function p(e,t){const r=new Map;for(const n of e){const i=n.node?.surface;i&&r.set(i,(r.get(i)??0)+1)}let o=null;for(const[n,i]of r)(o===null||i>(r.get(o)??0))&&(o=n);return o??t}function a(e,t){const r=e.find(n=>n.path===t);return r?r.surface:e.filter(n=>n.dynamic).map(n=>({route:n,stem:n.path.split(/[:*]/)[0]??""})).filter(({stem:n})=>n.length>1&&t.startsWith(n)).sort((n,i)=>i.stem.length-n.stem.length)[0]?.route.surface??null}function l(e,t){return f(e,"",new URLSearchParams({view:"frame",...t}))}function d(e,t){return e.find(r=>r.id===t)??e[0]}export{h as MANIFEST_VERSION,c as byGroup,d as flowById,l as frameUrl,s as groupLabel,a as surfaceForRoute,p as surfaceFromPins,u as viewportById,f as workbenchUrl};
1
+ import{MANIFEST_VERSION as w}from"./manifest.types";function f(e,t){return e.groupLabels[t]??t}function s(e,t){const n=e.viewports.find(r=>r.id===t),o=e.viewports[0];if(n)return n;if(o)return o;throw new Error("El manifiesto no declara ning\xFAn viewport.")}function u(e,t,n){const o=e.mountPath.replace(/\/+$/,""),r=t?`${o}/${t}`:o;return n?`${r}?${n.toString()}`:r}function c(e){const t=new Map;for(const n of e){const o=t.get(n.group);o?o.push(n):t.set(n.group,[n])}return[...t.entries()]}function p(e,t){const n=new Map;for(const r of e){const i=r.node?.surface;i&&n.set(i,(n.get(i)??0)+1)}let o=null;for(const[r,i]of n)(o===null||i>(n.get(o)??0))&&(o=r);return o??t}function a(e,t){const n=e.find(r=>r.path===t);return n?n.surface:e.filter(r=>r.dynamic).map(r=>({route:r,stem:r.path.split(/[:*]/)[0]??""})).filter(({stem:r})=>r.length>1&&t.startsWith(r)).sort((r,i)=>i.stem.length-r.stem.length)[0]?.route.surface??null}function l(e,t){return u(e,"",new URLSearchParams({view:"frame",...t}))}function d(e){return e.reduce((t,n)=>t+n.tokens.length,0)}function x(e,t){return e.find(n=>n.id===t)??e[0]}export{w as MANIFEST_VERSION,c as byGroup,x as flowById,l as frameUrl,f as groupLabel,a as surfaceForRoute,p as surfaceFromPins,d as tokenCount,s as viewportById,u as workbenchUrl};
@@ -13,6 +13,7 @@ export type ViewerConfig = {
13
13
  [key in string]: string;
14
14
  };
15
15
  viewports: Array<Viewport>;
16
+ maxFlowSteps: number;
16
17
  };
17
18
  export type TokenKind = "color" | "value";
18
19
  export type Token = {
@@ -71,17 +72,26 @@ export type Origin = "config" | "spider";
71
72
  export type FlowStep = {
72
73
  label: string;
73
74
  route: string;
75
+ via: string | null;
74
76
  viewport: string;
75
77
  note: string | null;
78
+ notice: string | null;
76
79
  spec: string | null;
77
80
  exists: boolean;
78
81
  };
82
+ export type FlowBranch = {
83
+ id: string;
84
+ label: string;
85
+ from: number;
86
+ steps: Array<FlowStep>;
87
+ };
79
88
  export type Flow = {
80
89
  id: string;
81
90
  title: string;
82
91
  description: string | null;
83
92
  origin: Origin;
84
93
  steps: Array<FlowStep>;
94
+ branches: Array<FlowBranch>;
85
95
  };
86
96
  export type LearnedFile = {
87
97
  file: string;
@@ -166,4 +176,4 @@ export type OverlayManifest = {
166
176
  routes: Array<OverlayRoute>;
167
177
  surfaces: Array<OverlaySurface>;
168
178
  };
169
- export declare const MANIFEST_VERSION = 1;
179
+ export declare const MANIFEST_VERSION = 3;
@@ -1 +1 @@
1
- const o=1;export{o as MANIFEST_VERSION};
1
+ const o=3;export{o as MANIFEST_VERSION};
package/dist/mirror.d.ts CHANGED
@@ -1,7 +1,12 @@
1
+ import { type Sketch } from "./screen-sketch";
1
2
  export declare const QUIET_MS = 500;
2
3
  export declare const CAPTURE_MAX_MS = 8000;
3
4
  export declare const CAPTURE_TOTAL_MS = 30000;
4
5
  export declare const MIRROR_MAX_BYTES = 2000000;
5
6
  export declare function serializeMirror(doc: Document, route: string, origin: string): string;
6
7
  export declare function whenQuiet(doc: Document, quietMs?: number, maxMs?: number): Promise<"quiet" | "restless">;
7
- export declare function captureMirror(frame: HTMLIFrameElement, route: string): Promise<string | null>;
8
+ export interface Capture {
9
+ srcdoc: string;
10
+ sketch: Sketch | null;
11
+ }
12
+ export declare function captureMirror(frame: HTMLIFrameElement, route: string): Promise<Capture | null>;
package/dist/mirror.js CHANGED
@@ -1 +1 @@
1
- "use client";const f=500,T=8e3,h=3e4,d=2e6;function a(t,s,c){const o=t.documentElement;if(!o)throw new Error("documento sin ra\xEDz");const e=o.cloneNode(!0);for(const n of Array.from(e.querySelectorAll("script, noscript, base")))n.remove();for(const n of[e,...Array.from(e.querySelectorAll("*"))])for(const l of Array.from(n.attributes))l.name.toLowerCase().startsWith("on")&&n.removeAttribute(l.name);const r=t.createElement("base");r.setAttribute("href",new URL(s,c).href);const i=e.querySelector("head");return i?i.insertBefore(r,i.firstChild):e.insertBefore(r,e.firstChild),`${t.doctype?`<!DOCTYPE ${t.doctype.name}>`:"<!DOCTYPE html>"}${e.outerHTML}`}function m(t,s=500,c=8e3){return new Promise(o=>{let e,r;const i=new MutationObserver(()=>{clearTimeout(e),e=setTimeout(()=>u("quiet"),s)}),u=l=>{i.disconnect(),clearTimeout(e),clearTimeout(r),o(l)},n=t.documentElement;if(!n){o("restless");return}i.observe(n,{childList:!0,subtree:!0,attributes:!0,characterData:!0}),e=setTimeout(()=>u("quiet"),s),r=setTimeout(()=>u("restless"),c)})}async function p(t,s){try{const c=t.contentDocument;if(!c||await m(c)==="restless")return null;const o=t.contentDocument;if(!o)return null;const e=t.contentWindow?.location.pathname??s,r=a(o,e,window.location.origin);return r.length>2e6?null:r}catch{return null}}export{T as CAPTURE_MAX_MS,h as CAPTURE_TOTAL_MS,d as MIRROR_MAX_BYTES,f as QUIET_MS,p as captureMirror,a as serializeMirror,m as whenQuiet};
1
+ "use client";import{readSketch as a}from"./screen-sketch";const h=500,d=8e3,w=3e4,m=2e6;function f(t,c,s){const r=t.documentElement;if(!r)throw new Error("documento sin ra\xEDz");const e=r.cloneNode(!0);for(const i of Array.from(e.querySelectorAll("script, noscript, base")))i.remove();for(const i of[e,...Array.from(e.querySelectorAll("*"))])for(const l of Array.from(i.attributes))l.name.toLowerCase().startsWith("on")&&i.removeAttribute(l.name);const o=t.createElement("base");o.setAttribute("href",new URL(c,s).href);const n=e.querySelector("head");return n?n.insertBefore(o,n.firstChild):e.insertBefore(o,e.firstChild),`${t.doctype?`<!DOCTYPE ${t.doctype.name}>`:"<!DOCTYPE html>"}${e.outerHTML}`}function p(t,c=h,s=d){return new Promise(r=>{let e,o;const n=new MutationObserver(()=>{clearTimeout(e),e=setTimeout(()=>u("quiet"),c)}),u=l=>{n.disconnect(),clearTimeout(e),clearTimeout(o),r(l)},i=t.documentElement;if(!i){r("restless");return}n.observe(i,{childList:!0,subtree:!0,attributes:!0,characterData:!0}),e=setTimeout(()=>u("quiet"),c),o=setTimeout(()=>u("restless"),s)})}async function y(t,c){try{const s=t.contentDocument;if(!s||await p(s)==="restless")return null;const r=t.contentDocument;if(!r)return null;const e=t.contentWindow?.location.pathname??c,o=f(r,e,window.location.origin);if(o.length>m)return null;let n=null;try{n=a(r,{width:t.contentWindow?.innerWidth??t.clientWidth,height:t.contentWindow?.innerHeight??t.clientHeight})}catch{}return{srcdoc:o,sketch:n}}catch{return null}}export{d as CAPTURE_MAX_MS,w as CAPTURE_TOTAL_MS,m as MIRROR_MAX_BYTES,h as QUIET_MS,y as captureMirror,f as serializeMirror,p as whenQuiet};
@@ -0,0 +1,24 @@
1
+ export type NodeActionId = "demote" | "activate" | "refresh" | "append" | "fork" | "remove";
2
+ export interface NodeAction {
3
+ id: NodeActionId;
4
+ label: string;
5
+ chip: string | null;
6
+ title: string;
7
+ blocked: string | null;
8
+ edits: boolean;
9
+ }
10
+ export type NodeFrame = "live" | "mirrored" | "restless" | "unbuilt" | "loading";
11
+ export interface NodeSituation {
12
+ frame: NodeFrame;
13
+ lane: "trunk" | "branch";
14
+ isLast: boolean;
15
+ isForkPoint: boolean;
16
+ removable: boolean;
17
+ canEdit: boolean;
18
+ atCap: boolean;
19
+ }
20
+ export interface NodeMenuContents {
21
+ actions: NodeAction[];
22
+ note: string | null;
23
+ }
24
+ export declare function nodeActions(at: NodeSituation): NodeMenuContents;
@@ -0,0 +1 @@
1
+ import{journeyMoves as n}from"./flow-edit";import{APPEND as s,FORK as p,HAS_BRANCHES as o}from"./journey-acts";function d(e){const l=[];if(e.frame==="live"?l.push({id:"demote",label:"Volver a espejo",chip:"Volver a espejo",title:"Congela la p\xE1gina en un espejo est\xE1tico y libera el documento vivo.",blocked:null,edits:!1}):e.frame==="mirrored"?l.push({id:"activate",label:"Activar la p\xE1gina",chip:"Activar",title:"Monta la p\xE1gina real para interactuar con ella.",blocked:null,edits:!1},{id:"refresh",label:"Actualizar el espejo",chip:"Actualizar",title:"Vuelve a cargar la ruta y captura un espejo nuevo.",blocked:null,edits:!1}):e.frame==="restless"&&l.push({id:"refresh",label:"Reintentar el espejo",chip:"Reintentar espejo",title:"La p\xE1gina no termin\xF3 de asentarse; vuelve a intentarlo.",blocked:null,edits:!1}),!e.canEdit)return{actions:l,note:null};const i=n(e,e.atCap),t=(a,r)=>l.push({id:r,label:a.menu,chip:a.chip,title:a.title,blocked:null,edits:!0});return i.append&&t(s,"append"),i.fork&&t(p,"fork"),e.isLast&&e.removable&&l.push({id:"remove",label:"Quitar la pantalla",chip:"quitar",title:e.isForkPoint?o:"Quita esta pantalla del recorrido.",blocked:e.isForkPoint?o:null,edits:!0}),{actions:l,note:i.why}}export{d as nodeActions};
@@ -0,0 +1,13 @@
1
+ import type { NodeAction } from "./node-actions";
2
+ export declare function NodeMenu({ title, at, actions, note, busy, onRun, onClose, }: {
3
+ title: string;
4
+ at: {
5
+ top: number;
6
+ left: number;
7
+ };
8
+ actions: readonly NodeAction[];
9
+ note: string | null;
10
+ busy: boolean;
11
+ onRun: (action: NodeAction) => void;
12
+ onClose: () => void;
13
+ }): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ "use client";import{jsx as i,jsxs as m}from"react/jsx-runtime";import{useEffect as w,useRef as N}from"react";import{cx as E}from"./cx";import{useFloating as A}from"./floating";import{EN_CURSO as b}from"./journey-acts";function I({title:d,at:a,actions:c,note:f,busy:h,onRun:k,onClose:u}){const p=N(null),l=(e,r)=>{const t=Array.from(o.current?.querySelectorAll('[role="menuitem"]')??[]);if(t.length===0)return;e.preventDefault();const n=t.findIndex(z=>z===document.activeElement),y=r==="first"?0:r==="last"?t.length-1:(n+r+t.length)%t.length;t[y]?.focus()},g={top:a.top,left:a.left,width:0,height:0},{ref:o,placed:s,style:x}=A(g,u);return w(()=>{s&&(p.current??o.current)?.focus()},[s]),m("div",{ref:o,role:"menu",tabIndex:-1,"aria-label":`Acciones de ${d}`,onKeyDown:e=>{e.key==="Escape"?u():e.key==="ArrowDown"?l(e,1):e.key==="ArrowUp"?l(e,-1):e.key==="Home"?l(e,"first"):e.key==="End"&&l(e,"last")},className:"fixed z-[2147483050] w-52 rounded-md border border-zinc-200 bg-white p-1 shadow-lg dark:border-zinc-700 dark:bg-zinc-900",style:s?x:{...x,visibility:"hidden"},children:[i("p",{role:"presentation",className:"truncate px-1.5 pt-1 pb-1.5 text-[11px] font-medium text-zinc-500 dark:text-zinc-400",children:d}),c.length===0?i("p",{role:"presentation",className:"px-1.5 pb-1 text-[11px] text-zinc-500 dark:text-zinc-400",children:"Nada que hacer aqu\xED todav\xEDa."}):c.map((e,r)=>{const t=e.edits&&h,n=e.blocked!==null||t;return m("button",{ref:r===0?p:void 0,type:"button",role:"menuitem","aria-disabled":n||void 0,"aria-label":t?`${e.label} \u2014 ${b}`:void 0,title:t?b:e.title,onClick:()=>{n||k(e)},className:E("block w-full rounded px-1.5 py-1 text-left text-[12px] text-zinc-700 dark:text-zinc-200",n?"opacity-40":"hover:bg-zinc-100 dark:hover:bg-zinc-800"),children:[e.label,e.blocked&&i("span",{className:"mt-0.5 block text-[10px] leading-snug text-amber-700 dark:text-amber-300",children:e.blocked})]},e.id)}),f&&i("p",{role:"presentation",className:"px-1.5 pt-1 pb-0.5 text-[10px] leading-snug text-zinc-500 dark:text-zinc-400",children:f})]})}export{I as NodeMenu};
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as s}from"react/jsx-runtime";import{useCallback as F,useRef as D,useState as d}from"react";import{ComponentPreview as H,ComponentScenarios as G,VariantScenarios as J,VerdictBadge as K}from"../component-preview";import{useManifest as Q}from"../config-context";import{useInspect as W}from"../edit-mode";import{InlineSurface as X,RouteFrame as T}from"../frame";import{frameUrl as Y,viewportById as E}from"../manifest";import{FRAME_CHROME as ee,ScreenFrame as j,useScale as te}from"../screen-frame";import{AUTO as I,ScreenToolbar as ie}from"../screen-toolbar";import{indexRegistry as ne}from"../registry";function ae({src:t,title:m,viewport:o,scale:c,editing:x,onLoaded:u}){const[g,b]=d(!1);return e(j,{viewport:o,scale:c,label:m,editing:x,children:g?e(T,{src:t,title:m,width:o.width,height:o.height,onLoad:u}):s("div",{className:"flex flex-col items-center justify-center gap-6 bg-zinc-50 dark:bg-zinc-900",style:{width:o.width,height:o.height},children:[e("p",{className:"max-w-lg px-10 text-center text-2xl leading-relaxed text-zinc-400 dark:text-zinc-500",children:"Cada vista es un iframe de la p\xE1gina aislada; se cargan al pedirlas para no multiplicar cargas del servidor."}),e("button",{type:"button",onClick:()=>b(!0),className:"rounded-xl border border-zinc-300 px-8 py-4 text-2xl font-medium text-zinc-600 hover:bg-zinc-100 dark:border-zinc-700 dark:text-zinc-300 dark:hover:bg-zinc-800",children:"Cargar esta vista"})]})})}function ge({entry:t,registry:m,componentIndex:o,editing:c,onPin:x,onHover:u,onToggleEdit:g,pinCount:b,onOpenRequest:V,showChrome:L,initialViewport:M,initialZoom:O,initialTheme:_}){const l=Q().config,[h,A]=d(M??I),[z,B]=d(O??"fit"),[p,q]=d(_??"light"),R=D(null),v=ne(m).get(t.id),f=h===I,a=f?null:E(l,h),{ref:P,scale:S}=te(z,a?.width??0,ee),k=p==="split"?["light","dark"]:[p],[U,Z]=d(0),y=F(()=>Z(i=>i+1),[]);W(c,F(()=>R.current,[]),o,{onPin:x,onHover:u},`${t.id}:${h}:${z}:${p}:${U}`);const w=(i,n)=>Y(l,{component:t.id,viewport:a?.id??l.viewports[0]?.id??"",theme:i,...n?{scenario:n}:{}}),N=(i,n,r)=>s("section",{className:"mb-8",children:[s("header",{className:"mb-2 flex items-baseline gap-3",children:[e("h3",{className:"text-sm font-semibold text-zinc-900 dark:text-zinc-100",children:i}),n&&e("p",{className:"text-[11px] text-zinc-500 dark:text-zinc-400",children:n})]}),r]}),$=(i,n,r)=>f?e(X,{theme:i,editing:c,children:n}):r?e(ae,{src:w(i,r),title:`${t.name} \xB7 ${r}`,viewport:a??E(l,void 0),scale:S,editing:c,onLoaded:y}):e(j,{viewport:a??E(l,void 0),scale:S,label:t.name,editing:c,children:e(T,{src:w(i),title:`${t.name} \xB7 ${a?.label??""}`,width:a?.width??0,height:a?.height??0},`${i}-${a?.id}`)});return s("div",{className:"flex h-full flex-col",children:[L&&e(ie,{viewport:h,onViewport:A,zoom:z,onZoom:B,theme:p,onTheme:q,zoomEnabled:!f,hint:f?"En Auto se dibuja en l\xEDnea: r\xE1pido, pero los breakpoints de Tailwind responden al ancho de la ventana, no al del cuadro.":`Dentro de un iframe a ${a?.width}px reales, as\xED que los breakpoints son de verdad.`,editing:c,onToggleEdit:g,pinCount:b,onOpenRequest:V,isolatedBase:{tab:"componentes",component:t.id}}),s("div",{ref:P,className:"min-h-0 flex-1 overflow-auto bg-zinc-50 p-6 dark:bg-zinc-950",children:[s("header",{className:"mb-5 max-w-2xl",children:[s("div",{className:"flex items-center gap-2",children:[e("h2",{className:"text-lg font-semibold text-zinc-900 dark:text-zinc-100",children:t.name}),e(K,{verdict:t.verdict})]}),e("p",{className:"mt-1 font-mono text-[11px] text-zinc-500 dark:text-zinc-400",children:t.file}),t.surface&&s("p",{className:"mt-1 text-[11px] text-zinc-500 dark:text-zinc-400",children:["Superficie: ",e("span",{className:"font-medium",children:t.surface})]})]}),e("div",{ref:R,className:"space-y-8",children:k.map(i=>s("div",{children:[k.length>1&&e("p",{className:"mb-2 text-[11px] font-medium uppercase tracking-wider text-zinc-500",children:i==="light"?"Claro":"Oscuro"}),N("Vista principal",void 0,$(i,e(H,{entry:t,registry:v}))),e(J,{entry:t,registry:v,render:(n,r,C)=>N(n,r,$(i,C,n))}),e(G,{entry:t,registry:v,render:(n,r,C)=>N(n,r,$(i,C,n))})]},i))}),e("a",{href:w(k[0]??"light"),target:"_blank",rel:"noreferrer",className:"text-[11px] text-zinc-500 underline underline-offset-2 hover:text-zinc-900 dark:hover:text-zinc-100",children:"abrir aislado \u2197"})]})]})}export{ge as ComponentsPanel};
1
+ "use client";import{jsx as e,jsxs as s}from"react/jsx-runtime";import{useCallback as j,useRef as D,useState as d}from"react";import{ComponentPreview as G,ComponentScenarios as H,VariantScenarios as J,VerdictBadge as K}from"../component-preview";import{useManifest as Q}from"../config-context";import{useInspect as W}from"../edit-mode";import{InlineSurface as X,RouteFrame as F}from"../frame";import{frameUrl as Y,viewportById as S}from"../manifest";import{rowExtent as ee,ScreenFrame as R,useScale as te}from"../screen-frame";import{AUTO as I,ScreenToolbar as ie}from"../screen-toolbar";import{indexRegistry as ne}from"../registry";function ae({src:t,title:m,viewport:o,scale:c,editing:x,onLoaded:u}){const[g,b]=d(!1);return e(R,{viewport:o,scale:c,label:m,editing:x,children:g?e(F,{src:t,title:m,width:o.width,height:o.height,onLoad:u}):s("div",{className:"flex flex-col items-center justify-center gap-6 bg-zinc-50 dark:bg-zinc-900",style:{width:o.width,height:o.height},children:[e("p",{className:"max-w-lg px-10 text-center text-2xl leading-relaxed text-zinc-400 dark:text-zinc-500",children:"Cada vista es un iframe de la p\xE1gina aislada; se cargan al pedirlas para no multiplicar cargas del servidor."}),e("button",{type:"button",onClick:()=>b(!0),className:"rounded-xl border border-zinc-300 px-8 py-4 text-2xl font-medium text-zinc-600 hover:bg-zinc-100 dark:border-zinc-700 dark:text-zinc-300 dark:hover:bg-zinc-800",children:"Cargar esta vista"})]})})}function ge({entry:t,registry:m,componentIndex:o,editing:c,onPin:x,onHover:u,onToggleEdit:g,pinCount:b,onOpenRequest:V,showChrome:L,initialViewport:B,initialZoom:O,initialTheme:_}){const l=Q().config,[h,q]=d(B??I),[z,A]=d(O??"fit"),[p,M]=d(_??"light"),E=D(null),v=ne(m).get(t.id),f=h===I,a=f?null:S(l,h),{ref:P,scale:T}=te(z,[ee([a?.width??0])]),k=p==="split"?["light","dark"]:[p],[U,Z]=d(0),y=j(()=>Z(i=>i+1),[]);W(c,j(()=>E.current,[]),o,{onPin:x,onHover:u},`${t.id}:${h}:${z}:${p}:${U}`);const w=(i,n)=>Y(l,{component:t.id,viewport:a?.id??l.viewports[0]?.id??"",theme:i,...n?{scenario:n}:{}}),N=(i,n,r)=>s("section",{className:"mb-8",children:[s("header",{className:"mb-2 flex items-baseline gap-3",children:[e("h3",{className:"text-sm font-semibold text-zinc-900 dark:text-zinc-100",children:i}),n&&e("p",{className:"text-[11px] text-zinc-500 dark:text-zinc-400",children:n})]}),r]}),$=(i,n,r)=>f?e(X,{theme:i,editing:c,children:n}):r?e(ae,{src:w(i,r),title:`${t.name} \xB7 ${r}`,viewport:a??S(l,void 0),scale:T,editing:c,onLoaded:y}):e(R,{viewport:a??S(l,void 0),scale:T,label:t.name,editing:c,children:e(F,{src:w(i),title:`${t.name} \xB7 ${a?.label??""}`,width:a?.width??0,height:a?.height??0},`${i}-${a?.id}`)});return s("div",{className:"flex h-full flex-col",children:[L&&e(ie,{viewport:h,onViewport:q,zoom:z,onZoom:A,theme:p,onTheme:M,zoomEnabled:!f,hint:f?"En Auto se dibuja en l\xEDnea: r\xE1pido, pero los breakpoints de Tailwind responden al ancho de la ventana, no al del cuadro.":`Dentro de un iframe a ${a?.width}px reales, as\xED que los breakpoints son de verdad.`,editing:c,onToggleEdit:g,pinCount:b,onOpenRequest:V,isolatedBase:{tab:"componentes",component:t.id}}),s("div",{ref:P,className:"min-h-0 flex-1 overflow-auto bg-zinc-50 p-6 dark:bg-zinc-950",children:[s("header",{className:"mb-5 max-w-2xl",children:[s("div",{className:"flex items-center gap-2",children:[e("h2",{className:"text-lg font-semibold text-zinc-900 dark:text-zinc-100",children:t.name}),e(K,{verdict:t.verdict})]}),e("p",{className:"mt-1 font-mono text-[11px] text-zinc-500 dark:text-zinc-400",children:t.file}),t.surface&&s("p",{className:"mt-1 text-[11px] text-zinc-500 dark:text-zinc-400",children:["Superficie: ",e("span",{className:"font-medium",children:t.surface})]})]}),e("div",{ref:E,className:"space-y-8",children:k.map(i=>s("div",{children:[k.length>1&&e("p",{className:"mb-2 text-[11px] font-medium uppercase tracking-wider text-zinc-500",children:i==="light"?"Claro":"Oscuro"}),N("Vista principal",void 0,$(i,e(G,{entry:t,registry:v}))),e(J,{entry:t,registry:v,render:(n,r,C)=>N(n,r,$(i,C,n))}),e(H,{entry:t,registry:v,render:(n,r,C)=>N(n,r,$(i,C,n))})]},i))}),e("a",{href:w(k[0]??"light"),target:"_blank",rel:"noreferrer",className:"text-[11px] text-zinc-500 underline underline-offset-2 hover:text-zinc-900 dark:hover:text-zinc-100",children:"abrir aislado \u2197"})]})]})}export{ge as ComponentsPanel};
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as n,Fragment as x}from"react/jsx-runtime";import{useState as p}from"react";import{useManifest as b}from"../config-context";import{cx as u}from"../cx";function d({value:t}){return t?e("span",{className:"inline-block h-6 w-10 rounded border border-zinc-300 dark:border-zinc-600",style:{background:t},title:t}):e("span",{className:"inline-block h-6 w-10 rounded border border-dashed border-zinc-300 dark:border-zinc-600",title:"Sin declarar en este tema"})}function f({token:t}){const a=t.light===null||t.dark===null;return n("tr",{className:"border-b border-zinc-100 last:border-0 dark:border-zinc-800",children:[n("td",{className:"py-1.5 pr-4 align-middle",children:[e("code",{className:"font-mono text-[11px] text-zinc-700 dark:text-zinc-300",children:t.name}),a&&e("span",{className:"ml-2 rounded bg-amber-100 px-1 py-0.5 text-[10px] text-amber-900 dark:bg-amber-950 dark:text-amber-200",title:"Declarado en un solo tema",children:"falta un tema"}),t.note&&e("p",{className:"mt-0.5 text-[11px] text-zinc-500 dark:text-zinc-400",children:t.note})]}),t.kind==="color"?n(x,{children:[e("td",{className:"py-1.5 pr-3",children:e(d,{value:t.light})}),e("td",{className:"py-1.5 pr-3",children:e(d,{value:t.dark})})]}):e("td",{colSpan:2,className:"py-1.5 pr-3",children:e("code",{className:"font-mono text-[11px] text-zinc-500 dark:text-zinc-400",children:t.light??t.dark})})]})}function k({group:t}){return n("section",{id:`token-${t.id}`,className:"mb-8",children:[n("h3",{className:"mb-2 text-sm font-semibold text-zinc-900 dark:text-zinc-100",children:[t.label,e("span",{className:"ml-2 text-[11px] font-normal text-zinc-400",children:t.tokens.length})]}),n("table",{className:"w-full max-w-3xl border-collapse text-left",children:[e("thead",{children:n("tr",{className:"text-[10px] uppercase tracking-wider text-zinc-400",children:[e("th",{className:"pb-1 font-medium",children:"Token"}),e("th",{className:"pb-1 font-medium",children:"Claro"}),e("th",{className:"pb-1 font-medium",children:"Oscuro"})]})}),e("tbody",{children:t.tokens.map(a=>e(f,{token:a},a.name))})]})]})}function y(){const{tokens:t,config:a,stats:l}=b(),[o,m]=p(""),s=o.trim().toLowerCase(),i=s?t.map(r=>({...r,tokens:r.tokens.filter(c=>c.name.toLowerCase().includes(s))})).filter(r=>r.tokens.length>0):t,h=i.reduce((r,c)=>r+c.tokens.length,0);return n("div",{className:"flex h-full flex-col",children:[n("div",{className:"flex flex-wrap items-center gap-3 border-b border-zinc-200 bg-white px-6 py-2 dark:border-zinc-700 dark:bg-zinc-900",children:[e("input",{value:o,onChange:r=>m(r.target.value),placeholder:"Filtrar tokens\u2026",className:"w-56 rounded-md border border-zinc-300 px-2 py-1 text-[12px] text-zinc-800 placeholder:text-zinc-400 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-100"}),n("span",{className:"text-[11px] text-zinc-500 dark:text-zinc-400",children:[h," tokens \xB7 ",a.title]})]}),e("div",{className:u("min-h-0 flex-1 overflow-auto bg-zinc-50 p-6 dark:bg-zinc-950"),children:t.length===0?l.missingStylesheet?n("p",{className:"max-w-lg text-sm text-zinc-600 dark:text-zinc-400",children:["El escaneo no encontr\xF3 la hoja de estilos"," ",e("code",{className:"font-mono",children:l.missingStylesheet}),", as\xED que no hay tokens que mostrar. Apunta ",e("code",{children:"themeSource"})," en",e("code",{className:"mx-1 font-mono",children:"workbench.config.json"})," al archivo con el bloque"," ",e("code",{children:"@theme"})," o ",e("code",{children:":root"}),"."]}):n("p",{className:"max-w-lg text-sm text-zinc-600 dark:text-zinc-400",children:["No se encontr\xF3 ning\xFAn token. Revisa ",e("code",{children:"themeSource"})," en",e("code",{className:"mx-1 font-mono",children:"workbench.config.json"}),": debe apuntar a la hoja de estilos con el bloque ",e("code",{children:"@theme"})," o ",e("code",{children:":root"}),"."]}):i.map(r=>e(k,{group:r},r.id))})]})}export{y as ElementsPanel};
1
+ "use client";import{jsx as e,jsxs as n,Fragment as x}from"react/jsx-runtime";import{useState as p}from"react";import{useManifest as b}from"../config-context";import{cx as u}from"../cx";import{tokenCount as f}from"../manifest";function s({value:t}){return t?e("span",{className:"inline-block h-6 w-10 rounded border border-zinc-300 dark:border-zinc-600",style:{background:t},title:t}):e("span",{className:"inline-block h-6 w-10 rounded border border-dashed border-zinc-300 dark:border-zinc-600",title:"Sin declarar en este tema"})}function k({token:t}){const a=t.light===null||t.dark===null;return n("tr",{className:"border-b border-zinc-100 last:border-0 dark:border-zinc-800",children:[n("td",{className:"py-1.5 pr-4 align-middle",children:[e("code",{className:"font-mono text-[11px] text-zinc-700 dark:text-zinc-300",children:t.name}),a&&e("span",{className:"ml-2 rounded bg-amber-100 px-1 py-0.5 text-[10px] text-amber-900 dark:bg-amber-950 dark:text-amber-200",title:"Declarado en un solo tema",children:"falta un tema"}),t.note&&e("p",{className:"mt-0.5 text-[11px] text-zinc-500 dark:text-zinc-400",children:t.note})]}),t.kind==="color"?n(x,{children:[e("td",{className:"py-1.5 pr-3",children:e(s,{value:t.light})}),e("td",{className:"py-1.5 pr-3",children:e(s,{value:t.dark})})]}):e("td",{colSpan:2,className:"py-1.5 pr-3",children:e("code",{className:"font-mono text-[11px] text-zinc-500 dark:text-zinc-400",children:t.light??t.dark})})]})}function z({group:t}){return n("section",{id:`token-${t.id}`,className:"mb-8",children:[n("h3",{className:"mb-2 text-sm font-semibold text-zinc-900 dark:text-zinc-100",children:[t.label,e("span",{className:"ml-2 text-[11px] font-normal text-zinc-400",children:t.tokens.length})]}),n("table",{className:"w-full max-w-3xl border-collapse text-left",children:[e("thead",{children:n("tr",{className:"text-[10px] uppercase tracking-wider text-zinc-400",children:[e("th",{className:"pb-1 font-medium",children:"Token"}),e("th",{className:"pb-1 font-medium",children:"Claro"}),e("th",{className:"pb-1 font-medium",children:"Oscuro"})]})}),e("tbody",{children:t.tokens.map(a=>e(k,{token:a},a.name))})]})]})}function v(){const{tokens:t,config:a,stats:c}=b(),[l,d]=p(""),o=l.trim().toLowerCase(),i=o?t.map(r=>({...r,tokens:r.tokens.filter(h=>h.name.toLowerCase().includes(o))})).filter(r=>r.tokens.length>0):t,m=f(i);return n("div",{className:"flex h-full flex-col",children:[n("div",{className:"flex flex-wrap items-center gap-3 border-b border-zinc-200 bg-white px-6 py-2 dark:border-zinc-700 dark:bg-zinc-900",children:[e("input",{value:l,onChange:r=>d(r.target.value),placeholder:"Filtrar tokens\u2026",className:"w-56 rounded-md border border-zinc-300 px-2 py-1 text-[12px] text-zinc-800 placeholder:text-zinc-400 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-100"}),n("span",{className:"text-[11px] text-zinc-500 dark:text-zinc-400",children:[m," tokens \xB7 ",a.title]})]}),e("div",{className:u("min-h-0 flex-1 overflow-auto bg-zinc-50 p-6 dark:bg-zinc-950"),children:t.length===0?c.missingStylesheet?n("p",{className:"max-w-lg text-sm text-zinc-600 dark:text-zinc-400",children:["El escaneo no encontr\xF3 la hoja de estilos"," ",e("code",{className:"font-mono",children:c.missingStylesheet}),", as\xED que no hay tokens que mostrar. Apunta ",e("code",{children:"themeSource"})," en",e("code",{className:"mx-1 font-mono",children:"workbench.config.json"})," al archivo con el bloque"," ",e("code",{children:"@theme"})," o ",e("code",{children:":root"}),"."]}):n("p",{className:"max-w-lg text-sm text-zinc-600 dark:text-zinc-400",children:["No se encontr\xF3 ning\xFAn token. Revisa ",e("code",{children:"themeSource"})," en",e("code",{className:"mx-1 font-mono",children:"workbench.config.json"}),": debe apuntar a la hoja de estilos con el bloque ",e("code",{children:"@theme"})," o ",e("code",{children:":root"}),"."]}):i.map(r=>e(z,{group:r},r.id))})]})}export{v as ElementsPanel};
@@ -0,0 +1,49 @@
1
+ import { type CanvasDetail } from "../canvas-gestures";
2
+ import { type CanvasViewport } from "../flow-canvas";
3
+ import { laneRefOf, type ComposerTarget } from "../flow-edit";
4
+ import { type Frames } from "../flow-frames";
5
+ import { type Lane, type StepNode } from "../flow-layout";
6
+ import { type MirrorPick } from "../frame";
7
+ import type { Flow, Viewport } from "../manifest.types";
8
+ import { type CardDraft, type CardStatus } from "./flow-cards";
9
+ export interface BoardComposer {
10
+ card: {
11
+ at: ComposerTarget;
12
+ draft: CardDraft;
13
+ status: CardStatus;
14
+ } | null;
15
+ cardViewport: Viewport | null;
16
+ routesList: string;
17
+ busy: boolean;
18
+ onDraft: (changes: Partial<CardDraft>) => void;
19
+ onSubmit: () => void;
20
+ onCancelCard: () => void;
21
+ onGhost: (lane: ReturnType<typeof laneRefOf>, after: number, flat: number, anchorRoute: string) => void;
22
+ onFork: (position: number, flat: number, anchorRoute: string) => void;
23
+ onRemove: (lane: ReturnType<typeof laneRefOf>) => void;
24
+ connect: boolean;
25
+ onPick: (node: StepNode, pick: MirrorPick | null) => void;
26
+ onHoverPick: (node: StepNode, pick: MirrorPick | null) => void;
27
+ }
28
+ export declare function CanvasBoard({ flow, lanes, themes, nonce, editing, frames, active, fitKey, shape, onCapture, onActivate, onRefresh, onDemote, registerLiveFrame, composer, onViewportChange, onDetailChange, }: {
29
+ flow: Flow;
30
+ lanes: Lane[];
31
+ themes: Array<"light" | "dark">;
32
+ nonce: number;
33
+ editing: boolean;
34
+ frames: Frames;
35
+ active: {
36
+ key: string;
37
+ slot: number;
38
+ } | null;
39
+ fitKey: string;
40
+ shape: string;
41
+ onCapture: (key: string, ticket: number, frame: HTMLIFrameElement) => void;
42
+ onActivate: (key: string, slot: number) => void;
43
+ onRefresh: (key: string) => void;
44
+ onDemote: () => void;
45
+ registerLiveFrame: (key: string, slot: number, frame: HTMLIFrameElement | null) => void;
46
+ composer: BoardComposer | null;
47
+ onViewportChange: (viewport: CanvasViewport) => void;
48
+ onDetailChange: (detail: CanvasDetail) => void;
49
+ }): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ "use client";import{Fragment as S,jsx as a,jsxs as h}from"react/jsx-runtime";import{useCallback as Pe,useContext as oe,useEffect as X,useMemo as F,useRef as se,useState as ce}from"react";import{CanvasDetailContext as de}from"../canvas-gestures";import{useManifest as Te}from"../config-context";import{CanvasChrome as j,FlowCanvas as _e}from"../flow-canvas";import{cx as P}from"../cx";import{atCap as Be,forkResolvesTo as Ye,isForkPoint as Ge,laneRefOf as V,refKey as ue}from"../flow-edit";import{frameOf as T}from"../flow-frames";import{cardBoxOf as me,forkCardKey as he,graphOf as He,layoutGraph as Xe,projectEdges as Ve,tailKeyOf as fe}from"../flow-graph";import{laneKey as xe,locateNode as qe}from"../flow-layout";import{MirrorFrame as Ie,RouteFrame as Ue}from"../frame";import{frameUrl as Je}from"../manifest";import{ScreenFrame as pe}from"../screen-frame";import{NodeMenu as Qe}from"../node-menu";import{AT_CAP as We,EN_CURSO as Ze}from"../journey-acts";import{nodeActions as be}from"../node-actions";import{CHIP as ke}from"../screen-toolbar";import{GhostChip as et,NewScreenCard as tt,SketchCard as nt,SpecCard as rt,Stage as at,TailPlaceholder as it}from"./flow-cards";function q({children:f,always:k=!1}){return oe(de)==="near"||k?a(S,{children:f}):null}function lt({far:f,near:k}){return a(S,{children:oe(de)==="far"?f:k})}function ot(f){return new Date(f).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}const st=200,I=[{box:"border-zinc-950/10 bg-zinc-950/[0.03] dark:border-white/10 dark:bg-white/[0.03]",text:"text-zinc-500 dark:text-zinc-400"},{box:"border-sky-500/25 bg-sky-500/[0.04]",text:"text-sky-700 dark:text-sky-300"},{box:"border-violet-500/25 bg-violet-500/[0.08] dark:bg-violet-500/[0.08]",text:"text-violet-700 dark:text-violet-300"},{box:"border-emerald-500/25 bg-emerald-500/[0.04] dark:bg-emerald-500/[0.08]",text:"text-emerald-700 dark:text-emerald-300"}];function Et({flow:f,lanes:k,themes:_,nonce:U,editing:ge,frames:M,active:x,fitKey:ye,shape:O,onCapture:we,onActivate:ve,onRefresh:Ce,onDemote:Ne,registerLiveFrame:ze,composer:l,onViewportChange:$e,onDetailChange:Ee}){const{config:J}=Te(),B=Be(f,J.maxFlowSteps),c=l?.card??null,g=l?.cardViewport??null,[y,K]=ce(null),Se=(e,r)=>{const i=T(M,e);return x!==null&&x.key===e.key&&x.slot===r?"live":i.kind==="mirrored"?"mirrored":i.kind==="restless"?"restless":i.kind==="unbuilt"?"unbuilt":"loading"},Q=(e,r,i,t)=>({frame:Se(r,t),lane:e.kind,isLast:i===e.nodes.length-1,isForkPoint:e.kind==="trunk"&&Ge(f,i),removable:e.kind==="branch"||e.nodes.length>1,canEdit:l!==null,atCap:B}),w=y&&qe(k,y.key),z=w?.lane.nodes[w.position]??null,Y=y&&w&&z?be(Q(w.lane,z,w.position,y.slot)):null;X(()=>{K(e=>e===null?e:null)},[O,U]);const W=(e,r,i)=>{l?.onPick(e,null),K({at:i,key:e.key,slot:r})},Z=(e,r)=>{const{lane:i,node:t,position:o,slot:n}=r;if(e.blocked===null&&!(e.edits&&l&&(l.busy||l.card!==null)))switch(e.id){case"demote":Ne();break;case"activate":ve(t.key,n);break;case"refresh":Ce(t.key);break;case"append":l?.onGhost(V(i),o,t.flat,t.step.route);break;case"fork":l?.onFork(o,t.flat,t.step.route);break;case"remove":l?.onRemove(V(i));break}},ee=l!==null,A=F(()=>{if(!ee)return;const e=new Map;return c&&!c.at.fork&&g&&e.set(ue(c.at.lane),me(g)),{tail:e,forkCard:c?.at.fork&&g?{fork:c.at.flat,...me(g),label:c.draft.branchLabel.trim()||"nueva rama"}:null}},[ee,k,c,g]),{graph:R,positions:$,bands:D,bbox:v}=F(()=>{const e=He(k,A);return{graph:e,...Xe(e)}},[k,A]),je=F(()=>{const e=new Map;let r=0;for(const i of D)i.laneKey!==xe(null)&&(e.set(i.laneKey,1+r%(I.length-1)),r+=1);return e},[D]),Oe=F(()=>Ve(R,$),[R,$]),[Ke,te]=ce(null),ne=se(0),L=Pe(e=>{ne.current+=1,te({key:`${e}:0`,tick:ne.current})},[]),G=c?c.at.fork?he(c.at.flat):fe(ue(c.at.lane)):null;X(()=>{G?L(G):te(null)},[G,L]);const re=se(null);X(()=>{const e=re.current;if(re.current=O,e===null||e===O)return;const r=new Set(e.split("|")),i=new Set(O.split("|")),t=[...i].filter(n=>n&&!r.has(n)),o=[...r].filter(n=>n&&!i.has(n));t.length===1&&o.length===0&&t[0]&&L(t[0])},[O,L]);const Ae=(e,r,i)=>{const{step:t,viewport:o}=e,n=T(M,e),m=x!==null&&x.key===e.key&&x.slot===r,d=n.kind==="capturing"?n.ticket:null,p=d!==null&&r===0,b=m||n.kind==="restless"&&r===0||p;return h(S,{children:[t.via&&h("span",{className:"sr-only",children:["V\xEDa \xAB",t.via,"\xBB"]}),a(pe,{viewport:o,scale:1,bare:!0,editing:ge&&n.kind!=="unbuilt",children:b?a(Ue,{src:t.route,title:`${f.title} \xB7 ${t.label}`,width:o.width,height:o.height,theme:i,frameRef:s=>ze(e.key,r,s),onLoad:p&&d!==null?s=>we(e.key,d,s):void 0},U):a(lt,{far:a(nt,{viewport:o,theme:i,sketch:n.kind==="mirrored"?n.sketch:null,tone:n.kind==="unbuilt"?"unbuilt":"mirror"}),near:n.kind==="unbuilt"?a(rt,{step:t,viewport:o,theme:i}):n.kind==="mirrored"?a(Ie,{srcdoc:n.srcdoc,title:`${f.title} \xB7 ${t.label} (espejo)`,width:o.width,height:o.height,theme:i,connect:l?.connect?{busy:l.busy||l.card!==null,onPick:s=>l.onPick(e,s),onHover:s=>l.onHoverPick(e,s)}:void 0,onMenu:s=>W(e,r,s)}):a(at,{viewport:o,theme:i,className:"flex items-center justify-center",children:a("p",{className:"max-w-lg px-10 text-center text-2xl leading-relaxed text-zinc-400 dark:text-zinc-500",children:n.kind==="capturing"?"Cargando la ruta real\u2026":n.kind==="restless"?"Sin espejo \u2014 el paso sigue en vivo en el tablero claro.":"En cola \u2014 cada paso se carga una sola vez y queda como espejo."})})})})]})},Fe=(e,r,i,t,o)=>{const{step:n,viewport:m}=r,d=T(M,r),p=x!==null&&x.key===r.key&&x.slot===t,b=d.kind==="capturing"&&t===0,s=be(Q(e,r,i,t)).actions.filter(u=>u.chip!==null);return h(S,{children:[a(j,{anchor:"bottom left",clamp:!0,style:{bottom:"100%"},children:h("p",{title:`${r.number}. ${n.label} \xB7 ${n.route}`,className:P("flex items-baseline gap-1.5 overflow-hidden whitespace-nowrap pb-1 text-[11px] font-medium",d.kind==="unbuilt"?"text-amber-700 dark:text-amber-300":p?"text-emerald-600 dark:text-emerald-400":"text-zinc-600 dark:text-zinc-300"),children:[h("span",{className:"shrink-0 truncate",children:[r.number,". ",n.label]}),a(q,{children:h("span",{className:"min-w-0 truncate font-mono text-[10px] text-zinc-500 dark:text-zinc-400",children:[n.route," \xB7 ",m.label," ",m.width,"\xD7",m.height]})})]})}),a(q,{always:p||d.kind==="restless"||b,children:h(j,{clamp:!0,style:{top:"100%"},children:[(p||d.kind==="mirrored"||d.kind==="restless"||d.kind==="unbuilt"||b)&&h("div",{className:"mt-2 flex flex-wrap items-center gap-2",children:[d.kind==="unbuilt"?a("span",{className:"text-[11px] text-amber-700 dark:text-amber-300",title:"La ruta no existe todav\xEDa; el cuadro muestra la especificaci\xF3n. Se vuelve un espejo real en el siguiente `workbench scan` despu\xE9s de que la p\xE1gina aterrice.",children:"Sin p\xE1gina todav\xEDa"}):p?a("span",{className:"text-[11px] font-medium text-emerald-600 dark:text-emerald-400",children:"En vivo"}):d.kind==="mirrored"?h("span",{className:"text-[11px] text-zinc-500 dark:text-zinc-400",title:"Espejo est\xE1tico de la p\xE1gina real \u2014 sin peticiones al servidor.",children:["Espejo \xB7 ",ot(d.capturedAt)]}):d.kind==="restless"?a("span",{className:"text-[11px] text-amber-700 dark:text-amber-300",title:"La p\xE1gina no termin\xF3 de asentarse, as\xED que el cuadro sigue en vivo.",children:"En vivo \u2014 sin espejo"}):a("span",{className:"text-[11px] text-zinc-500 dark:text-zinc-400",children:"Cargando\u2026"}),s.map(u=>{const N=u.edits&&l!==null&&(l.busy||l.card!==null),E=u.blocked??(N?Ze:null);return E!==null?a("button",{type:"button",className:P(ke,"opacity-40"),"aria-disabled":"true","aria-label":`${u.chip} \u2014 ${E}`,onClick:()=>{},title:E,children:u.chip},u.id):a("button",{type:"button",className:ke,onClick:()=>Z(u,{lane:e,node:r,position:i,slot:t}),title:u.title,children:u.chip},u.id)})]}),h("div",{className:"mt-2 flex items-start justify-between gap-2",children:[h("div",{className:"flex min-w-0 flex-col gap-1",children:[n.note&&a("p",{className:"text-[11px] leading-snug text-zinc-500 dark:text-zinc-400",children:n.note}),n.notice&&a("p",{className:"text-[11px] leading-snug text-amber-700 dark:text-amber-300",children:n.notice})]}),a("span",{className:"ml-auto flex shrink-0 items-center gap-2",children:d.kind!=="unbuilt"?h(S,{children:[h("a",{href:n.route,target:"_blank",rel:"noreferrer",className:"font-mono text-[11px] text-zinc-500 underline underline-offset-2 hover:text-zinc-900 dark:hover:text-zinc-100",children:[n.route," \u2197"]}),a("a",{href:Je(J,{route:n.route,viewport:m.id,theme:o}),target:"_blank",rel:"noreferrer",className:"text-[11px] text-zinc-500 underline underline-offset-2 hover:text-zinc-900 dark:hover:text-zinc-100",children:"aislado \u2197"})]}):a("span",{className:"font-mono text-[11px] text-zinc-400 dark:text-zinc-500",children:n.route})})]})]})})]})},ae=(e,r,i)=>!c||!g||!l?null:a(pe,{viewport:g,scale:1,bare:!0,children:e===0?a(tt,{viewport:g,theme:r,fork:i,routesList:l.routesList,draft:c.draft,status:c.status,onDraft:l.onDraft,onSubmit:l.onSubmit,onCancel:l.onCancelCard}):a(it,{viewport:g,theme:r,writing:c.status==="writing"})}),H=F(()=>new Map(R.nodes.map(e=>[e.key,e])),[R]),Me=_.length>1,ie=v.maxY-Math.min(v.minY,0)+st,C=[],le=[];for(const[e,r]of _.entries()){const i=e*ie;Me&&C.push({key:`theme:${e}`,x:v.minX,y:v.minY+i,width:400,height:1,behind:!0,element:null,chrome:a(j,{anchor:"bottom left",style:{bottom:"100%"},children:a("p",{className:"text-[11px] font-medium uppercase tracking-wider text-zinc-500 dark:text-zinc-400",children:r==="light"?"Claro":"Oscuro"})})});for(const t of D){const o=I[je.get(t.laneKey)??0]??I[0];C.push({key:`section:${t.laneKey}:${e}`,x:t.section.x,y:t.section.y+i,width:t.section.width,height:t.section.height,behind:!0,element:a("div",{className:P("h-full w-full rounded-2xl border",o.box)}),chrome:a(j,{anchor:"bottom left",clamp:!0,style:{bottom:"100%",left:4},children:a("p",{title:t.label??"Tronco",className:P("truncate whitespace-nowrap pb-1 text-[11px] font-medium",o.text),children:t.label??"Tronco"})})})}for(const t of k){const o=xe(t.kind==="trunk"?null:t.id);for(const[b,s]of t.nodes.entries()){const u=$.get(s.key),N=H.get(s.key);if(!u||!N)continue;const E=T(M,s);C.push({key:`${s.key}:${e}`,x:u.x,y:u.y+i,width:N.box.width,height:N.box.height,alwaysRender:E.kind==="capturing"||E.kind==="restless"||x?.key===s.key&&x.slot===e,element:Ae(s,e,r),onContextMenu:Le=>W(s,e,Le),chromeLabel:`${s.number}. ${s.step.label} \xB7 ${s.step.route}`,chrome:Fe(t,s,b,e,r)})}const n=A?.tail.get(o),m=t.nodes[t.nodes.length-1],d=fe(o),p=n?$.get(d):void 0;if(n&&p&&l)C.push({key:`${d}:${e}`,x:p.x,y:p.y+i,width:n.width,height:n.height,alwaysRender:!0,element:ae(e,r,!1)});else if(l){const b=D.find(N=>N.laneKey===o),s=m?$.get(m.key):b&&{x:b.x,y:b.y},u=m?H.get(m.key):void 0;s&&C.push({key:`add:${o}:${e}`,x:s.x+(u?.box.width??0),y:s.y+i,width:1,height:u?.box.height??1,element:null,chrome:a(q,{children:a(j,{anchor:"bottom left",style:{top:"50%",left:12},children:a(et,{label:"+ A\xF1adir pantalla",disabled:l.busy||l.card!==null||B,reason:B?We:void 0,onOpen:()=>l.onGhost(V(t),t.nodes.length-1,m?.flat??0,m?.step.route??"")})})})})}}if(A?.forkCard&&c){const t=he(A.forkCard.fork),o=$.get(t),n=H.get(t);if(o&&n){const m=Ye(f,f.steps[c.at.after]?.route??"")!==c.at.after;C.push({key:`${t}:${e}`,x:o.x,y:o.y+i,width:n.box.width,height:n.box.height,alwaysRender:!0,element:ae(e,r,!0),chrome:m?a(j,{anchor:"bottom left",style:{bottom:"100%"},children:a("p",{className:"max-w-[26rem] text-[11px] leading-snug text-amber-700 dark:text-amber-300",children:"El tronco repite esta ruta; el motor dibuja la rama desde su primera aparici\xF3n."})}):void 0})}}for(const t of Oe)le.push({...t,id:`${t.id}:${e}`,from:{x:t.from.x,y:t.from.y+i},to:{x:t.to.x,y:t.to.y+i},...t.waypoints?{waypoints:t.waypoints.map(o=>({x:o.x,y:o.y+i}))}:{}})}const Re={minX:v.minX,minY:v.minY,maxX:v.maxX,maxY:v.maxY+(_.length-1)*ie},De=a(_e,{nodes:C,edges:le,bbox:Re,fitKey:ye,reveal:Ke,onViewportChange:e=>{K(r=>r===null?r:null),$e(e)},onDetailChange:Ee,label:`Lienzo del recorrido ${f.title}`,className:"bg-zinc-50 [--wb-canvas-bg:#fafafa] dark:bg-zinc-950 dark:[--wb-canvas-bg:#09090b]"});return h(S,{children:[De,y&&w&&z&&Y&&a(Qe,{title:`${z.number}. ${z.step.label}`,at:{top:y.at.y,left:y.at.x},actions:Y.actions,note:Y.note,busy:l!==null&&(l.busy||l.card!==null),onRun:e=>{K(null),Z(e,{lane:w.lane,node:z,position:w.position,slot:y.slot})},onClose:()=>K(null)})]})}export{Et as CanvasBoard};
@@ -0,0 +1,54 @@
1
+ import { type ReactNode } from "react";
2
+ import type { FlowStep, Viewport } from "../manifest.types";
3
+ import type { Sketch } from "../screen-sketch";
4
+ export declare function Stage({ viewport, theme, className, children, }: {
5
+ viewport: Viewport;
6
+ theme: "light" | "dark";
7
+ className?: string;
8
+ children: ReactNode;
9
+ }): import("react").JSX.Element;
10
+ export declare function SketchCard({ sketch, viewport, theme, tone, }: {
11
+ sketch: Sketch | null;
12
+ viewport: Viewport;
13
+ theme: "light" | "dark";
14
+ tone: "mirror" | "unbuilt";
15
+ }): import("react").JSX.Element;
16
+ export declare function SpecCard({ step, viewport, theme, }: {
17
+ step: FlowStep;
18
+ viewport: Viewport;
19
+ theme: "light" | "dark";
20
+ }): import("react").JSX.Element;
21
+ export interface CardDraft {
22
+ route: string;
23
+ label: string;
24
+ spec: string;
25
+ via: string;
26
+ branchLabel: string;
27
+ }
28
+ export type CardStatus = "editing" | "writing" | {
29
+ error: string;
30
+ } | {
31
+ written: string | null;
32
+ };
33
+ export declare function NewScreenCard({ viewport, theme, fork, routesList, draft, status, onDraft, onSubmit, onCancel, }: {
34
+ viewport: Viewport;
35
+ theme: "light" | "dark";
36
+ fork: boolean;
37
+ routesList: string;
38
+ draft: CardDraft;
39
+ status: CardStatus;
40
+ onDraft: (changes: Partial<CardDraft>) => void;
41
+ onSubmit: () => void;
42
+ onCancel: () => void;
43
+ }): import("react").JSX.Element;
44
+ export declare function TailPlaceholder({ viewport, theme, writing, }: {
45
+ viewport: Viewport;
46
+ theme: "light" | "dark";
47
+ writing: boolean;
48
+ }): import("react").JSX.Element;
49
+ export declare function GhostChip({ label, disabled, reason, onOpen, }: {
50
+ label: string;
51
+ disabled: boolean;
52
+ reason?: string;
53
+ onOpen: () => void;
54
+ }): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ "use client";import{jsx as e,jsxs as n}from"react/jsx-runtime";import"react";import{cx as b}from"../cx";function x({viewport:a,theme:l,className:t,children:d}){return e("div",{className:b(l==="dark"&&"dark","bg-zinc-50 dark:bg-zinc-900",t),style:{width:a.width,height:a.height},children:d})}function w({sketch:a,viewport:l,theme:t,tone:d}){return n(x,{viewport:l,theme:t,className:"relative overflow-hidden bg-white dark:bg-zinc-900",children:[d==="unbuilt"&&e("div",{className:"absolute inset-x-0 top-0 bg-amber-400",style:{height:l.height*.012}}),a&&a.boxes.length>0?e("svg",{"aria-hidden":!0,viewBox:"0 0 100 100",preserveAspectRatio:"none",className:"h-full w-full",style:{padding:l.width*.04},children:a.boxes.map((r,c)=>e("rect",{x:r.x*100,y:r.y*100,width:r.w*100,height:r.h*100,rx:.6,className:r.kind==="text"?"fill-zinc-400/70 dark:fill-zinc-500/70":r.kind==="media"?"fill-zinc-300 dark:fill-zinc-700":"fill-zinc-200/60 dark:fill-zinc-800/60"},c))}):e("div",{className:"flex h-full w-full items-center justify-center",children:e("p",{className:"text-zinc-300 dark:text-zinc-600",style:{fontSize:l.width*.06},children:d==="unbuilt"?"Por construir":"Sin vista previa"})})]})}function y({step:a,viewport:l,theme:t}){return n(x,{viewport:l,theme:t,className:"flex flex-col gap-6 p-12 text-zinc-700 dark:text-zinc-200",children:[n("div",{className:"flex flex-wrap items-center gap-x-4 gap-y-2",children:[e("span",{className:"rounded-md border border-dashed border-amber-500 px-3 py-1 text-xl font-medium uppercase tracking-wider text-amber-700 dark:text-amber-300",children:"Por construir"}),e("span",{className:"break-all font-mono text-2xl text-zinc-500 dark:text-zinc-400",children:a.route})]}),e("h3",{className:"text-5xl font-semibold leading-tight text-zinc-900 dark:text-zinc-100",children:a.label}),e("p",{className:"max-w-3xl text-3xl leading-relaxed",children:a.spec??"Sin especificaci\xF3n todav\xEDa. A\xF1\xE1dela con la tarjeta al crear la pantalla, o con `spec` en workbench.config.json, para que este cuadro diga qu\xE9 debe hacer la pantalla."})]})}const m="mt-2 w-full rounded-md border border-zinc-300 bg-white px-4 py-3 text-3xl text-zinc-900 disabled:opacity-60 dark:border-zinc-600 dark:bg-zinc-800 dark:text-zinc-100",p="text-2xl font-medium uppercase tracking-wider text-zinc-400";function v({viewport:a,theme:l,fork:t,routesList:d,draft:r,status:c,onDraft:o,onSubmit:g,onCancel:u}){const h=typeof c=="object"&&"written"in c,s=c==="writing"||h,k=r.route.trim().length>0&&(!t||r.branchLabel.trim().length>0);return n(x,{viewport:a,theme:l,className:"flex flex-col gap-6 overflow-hidden p-12 text-zinc-700 dark:text-zinc-200",children:[n("div",{className:"flex flex-wrap items-center gap-x-4 gap-y-2",children:[e("span",{className:"rounded-md border border-dashed border-sky-500 px-3 py-1 text-xl font-medium uppercase tracking-wider text-sky-700 dark:text-sky-300",children:t?"Nueva rama":"Nueva pantalla"}),r.via.trim()&&n("span",{className:"text-2xl text-zinc-500 dark:text-zinc-400",children:["v\xEDa \xAB",r.via.trim(),"\xBB"]})]}),n("form",{className:"flex min-h-0 flex-1 flex-col gap-5",onSubmit:i=>{i.preventDefault(),g()},onKeyDown:i=>{i.key==="Escape"&&(i.stopPropagation(),u())},children:[t&&n("label",{className:"block",children:[e("span",{className:p,children:"Nombre de la rama"}),e("input",{value:r.branchLabel,onChange:i=>o({branchLabel:i.target.value}),placeholder:"Tier 2",disabled:s,className:m})]}),n("label",{className:"block",children:[e("span",{className:p,children:"Ruta"}),e("input",{value:r.route,onChange:i=>o({route:i.target.value}),list:d,placeholder:"/pantalla",autoFocus:!0,disabled:s,className:b(m,"font-mono")})]}),n("label",{className:"block",children:[e("span",{className:p,children:"Nombre"}),e("input",{value:r.label,onChange:i=>o({label:i.target.value}),placeholder:"Qu\xE9 pantalla es",disabled:s,className:m})]}),n("label",{className:"block",children:[e("span",{className:p,children:"Qu\xE9 debe hacer"}),e("textarea",{value:r.spec,onChange:i=>o({spec:i.target.value}),rows:4,placeholder:"Se muestra en el tablero mientras la p\xE1gina no exista.",disabled:s,className:b(m,"resize-none")})]}),typeof c=="object"&&"error"in c&&e("p",{role:"alert",className:"text-2xl leading-snug text-red-700 dark:text-red-300",children:c.error}),h&&e("p",{role:"status",className:"text-2xl text-emerald-700 dark:text-emerald-300",children:c.written??"Escrito \xB7 esperando el mapa\u2026"}),n("div",{className:"mt-auto flex items-center gap-4",children:[e("button",{type:"submit",disabled:s||!k,className:"rounded-md bg-zinc-900 px-6 py-3 text-2xl font-medium text-white disabled:opacity-40 dark:bg-zinc-100 dark:text-zinc-900",children:c==="writing"?"Escribiendo\u2026":"A\xF1adir"}),e("button",{type:"button",onClick:u,disabled:c==="writing",className:"rounded-md border border-zinc-300 px-6 py-3 text-2xl text-zinc-700 disabled:opacity-40 dark:border-zinc-600 dark:text-zinc-200",children:h?"Cerrar":"Cancelar"})]})]})]})}function C({viewport:a,theme:l,writing:t}){return e(x,{viewport:a,theme:l,className:"flex items-center justify-center",children:e("p",{className:"max-w-lg px-10 text-center text-2xl leading-relaxed text-zinc-400 dark:text-zinc-500",children:t?"Escribiendo\u2026":"Pantalla nueva \u2014 se edita en el tablero claro."})})}function j({label:a,disabled:l,reason:t,onOpen:d}){return e("button",{type:"button",onClick:d,disabled:l,title:t,"aria-label":t?`${a} \u2014 ${t}`:void 0,className:"whitespace-nowrap rounded-md border border-dashed border-zinc-400 bg-white/80 px-2 py-1 text-[11px] font-medium text-zinc-500 backdrop-blur hover:border-sky-400 hover:text-sky-600 disabled:opacity-40 dark:border-zinc-600 dark:bg-zinc-900/80 dark:text-zinc-400 dark:hover:border-sky-500 dark:hover:text-sky-400",children:a})}export{j as GhostChip,v as NewScreenCard,w as SketchCard,y as SpecCard,x as Stage,C as TailPlaceholder};
@@ -1,10 +1,9 @@
1
1
  import type { ComponentIndex } from "../hover-inspect";
2
2
  import type { Flow } from "../manifest.types";
3
- import type { PickTarget } from "../pick-highlight";
4
- import type { Pin } from "../pin";
5
- import { type Zoom } from "../screen-frame";
3
+ import { type PickTarget } from "../pick-highlight";
4
+ import type { Pin, SaveFlowInput, SaveFlowResult } from "../pin";
6
5
  import { type ThemeMode } from "../screen-toolbar";
7
- export declare function FlowsPanel({ flow, componentIndex, editing, onPin, onHover, onToggleEdit, pinCount, onOpenRequest, showChrome, initialViewport, initialZoom, initialTheme, }: {
6
+ export declare function FlowsPanel({ flow, componentIndex, editing, onPin, onHover, onToggleEdit, pinCount, onOpenRequest, showChrome, initialViewport, initialTheme, routes, onSaveFlow, }: {
8
7
  flow: Flow;
9
8
  componentIndex: ComponentIndex;
10
9
  editing: boolean;
@@ -15,6 +14,7 @@ export declare function FlowsPanel({ flow, componentIndex, editing, onPin, onHov
15
14
  onOpenRequest: () => void;
16
15
  showChrome: boolean;
17
16
  initialViewport?: string;
18
- initialZoom?: Zoom;
19
17
  initialTheme?: ThemeMode;
18
+ routes?: string[];
19
+ onSaveFlow?: (input: SaveFlowInput) => Promise<SaveFlowResult>;
20
20
  }): import("react").JSX.Element;
@@ -1 +1 @@
1
- "use client";import{jsx as t,Fragment as V,jsxs as c}from"react/jsx-runtime";import{Fragment as ue,useCallback as b,useEffect as W,useRef as Z,useState as v}from"react";import{useManifest as Y}from"../config-context";import{useInspect as me}from"../edit-mode";import{MirrorFrame as pe,RouteFrame as he}from"../frame";import{frameUrl as ge,viewportById as ee}from"../manifest";import{CAPTURE_TOTAL_MS as xe,captureMirror as fe,serializeMirror as ke}from"../mirror";import{FRAME_CHROME as be,ScreenFrame as ve,STEP_GUTTER as ze,useScale as Ne}from"../screen-frame";import{AUTO as G,CHIP as T,ScreenToolbar as $e}from"../screen-toolbar";const M={kind:"queued"};function je(n){return new Date(n).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function Ee({flow:n,steps:F,scale:p,theme:z,nonce:D,editing:q,slot:h,frames:_,active:N,onCapture:S,onActivate:L,onRefresh:R,onDemote:A,registerLiveFrame:x}){const{config:$}=Y();return t("div",{children:t("ol",{className:"flex items-start gap-4",children:F.map(({step:l,viewport:i},d)=>{const o=_[d]??M,j=N!==null&&N.step===d&&N.slot===h,m=o.kind==="capturing"&&h===0,U=j||o.kind==="restless"&&h===0||m;return c(ue,{children:[c("li",{className:"shrink-0",children:[t(ve,{viewport:i,scale:p,label:`${d+1}. ${l.label}`,editing:q,children:U?t(he,{src:l.route,title:`${n.title} \xB7 ${l.label}`,width:i.width,height:i.height,theme:z,frameRef:f=>x(d,h,f),onLoad:m?f=>S(d,f):void 0},D):o.kind==="mirrored"?t(pe,{srcdoc:o.srcdoc,title:`${n.title} \xB7 ${l.label} (espejo)`,width:i.width,height:i.height,theme:z}):t("div",{className:"flex items-center justify-center bg-zinc-50 dark:bg-zinc-900",style:{width:i.width,height:i.height},children:t("p",{className:"max-w-lg px-10 text-center text-2xl leading-relaxed text-zinc-400 dark:text-zinc-500",children:o.kind==="capturing"?"Cargando la ruta real\u2026":o.kind==="restless"?"Sin espejo \u2014 el paso sigue en vivo en el tablero claro.":"En cola \u2014 cada paso se carga una sola vez y queda como espejo."})})}),(j||o.kind==="mirrored"||o.kind==="restless"||m)&&t("div",{className:"mt-2 flex flex-wrap items-center gap-2",style:{width:Math.floor(i.width*p)},children:j?c(V,{children:[t("span",{className:"text-[11px] font-medium text-emerald-600 dark:text-emerald-400",children:"En vivo"}),t("button",{type:"button",className:T,onClick:A,children:"Volver a espejo"})]}):o.kind==="mirrored"?c(V,{children:[c("span",{className:"text-[11px] text-zinc-500 dark:text-zinc-400",title:"Espejo est\xE1tico de la p\xE1gina real \u2014 sin peticiones al servidor.",children:["Espejo \xB7 ",je(o.capturedAt)]}),t("button",{type:"button",className:T,onClick:()=>L(d,h),title:"Monta la p\xE1gina real para interactuar con ella.",children:"Activar"}),t("button",{type:"button",className:T,onClick:()=>R(d),title:"Vuelve a cargar la ruta y captura un espejo nuevo.",children:"Actualizar"})]}):o.kind==="restless"?c(V,{children:[t("span",{className:"text-[11px] text-amber-600 dark:text-amber-400",title:"La p\xE1gina no termin\xF3 de asentarse, as\xED que el cuadro sigue en vivo.",children:"En vivo \u2014 sin espejo"}),t("button",{type:"button",className:T,onClick:()=>R(d),children:"Reintentar espejo"})]}):t("span",{className:"text-[11px] text-zinc-500 dark:text-zinc-400",children:"Cargando\u2026"})}),c("div",{className:"mt-2 flex items-start justify-between gap-2",style:{width:Math.floor(i.width*p)},children:[l.note&&t("p",{className:"text-[11px] leading-snug text-zinc-500 dark:text-zinc-400",children:l.note}),c("span",{className:"ml-auto flex shrink-0 items-center gap-2",children:[c("a",{href:l.route,target:"_blank",rel:"noreferrer",className:"font-mono text-[11px] text-zinc-500 underline underline-offset-2 hover:text-zinc-900 dark:hover:text-zinc-100",children:[l.route," \u2197"]}),t("a",{href:ge($,{route:l.route,viewport:i.id,theme:z}),target:"_blank",rel:"noreferrer",className:"text-[11px] text-zinc-500 underline underline-offset-2 hover:text-zinc-900 dark:hover:text-zinc-100",children:"aislado \u2197"})]})]})]}),d<F.length-1&&t("li",{"aria-hidden":!0,className:"shrink-0 self-center text-xl text-zinc-400 dark:text-zinc-600",children:"\u2192"})]},`${n.id}-${d}-${l.route}`)})})})}function qe({flow:n,componentIndex:F,editing:p,onPin:z,onHover:D,onToggleEdit:q,pinCount:h,onOpenRequest:_,showChrome:N,initialViewport:S,initialZoom:L,initialTheme:R}){const{config:A,stats:x}=Y(),[$,l]=v(0),[i,d]=v(S??G),[o,j]=v(L??"fit"),[m,U]=v(R??"light"),f=Z(null),[g,k]=v(()=>n.steps.map(()=>M)),[u,H]=v(null),I=Z(new Map);W(()=>{k(n.steps.map(()=>M)),H(null)},[$]);const Q=Z(1);W(()=>{g.some(e=>e.kind==="capturing")||g.some(e=>e.kind==="queued")&&k(e=>{if(e.some(a=>a.kind==="capturing"))return e;const r=e.findIndex(a=>a.kind==="queued");if(r===-1)return e;const s=Q.current;return Q.current+=1,e.map((a,w)=>w===r?{kind:"capturing",ticket:s}:a)})},[g]);const E=g.findIndex(e=>e.kind==="capturing"),J=E===-1?null:g[E],O=J?.kind==="capturing"?J.ticket:null;W(()=>{if(E===-1||O===null)return;const e=setTimeout(()=>{k(r=>r.map((s,a)=>a===E&&s.kind==="capturing"&&s.ticket===O?{kind:"restless"}:s))},xe);return()=>clearTimeout(e)},[E,O]);const te=b((e,r)=>{const s=n.steps[e]?.route;s&&fe(r,s).then(a=>{k(w=>w.map((C,P)=>P!==e||C.kind!=="capturing"?C:a?{kind:"mirrored",srcdoc:a,capturedAt:Date.now()}:{kind:"restless"}))}).catch(()=>{})},[n]),B=b(()=>{if(!u)return;const e=I.current.get(`${u.slot}:${u.step}`),r=n.steps[u.step]?.route;if(e&&r)try{const s=e.contentDocument;if(s){const a=e.contentWindow?.location.pathname??r,w=ke(s,a,window.location.origin),C=Date.now(),P=u.step;k(oe=>oe.map((le,de)=>de===P?{kind:"mirrored",srcdoc:w,capturedAt:C}:le))}}catch{}H(null)},[u,n]),ne=b((e,r)=>{B(),H({step:e,slot:r})},[B]),re=b(e=>{k(r=>r.map((s,a)=>a===e?M:s))},[]),ae=b((e,r,s)=>{const a=`${r}:${e}`;s?I.current.set(a,s):I.current.delete(a)},[]),K=i===G?null:ee(A,i),y=n.steps.map(e=>({step:e,viewport:K??ee(A,e.viewport)})),ie=y.reduce((e,{viewport:r})=>e+r.width,0),{ref:se,scale:ce}=Ne(o,ie,y.length*be+Math.max(0,y.length-1)*ze),X=m==="split"?["light","dark"]:[m];return me(p,b(()=>f.current,[]),F,{onPin:z,onHover:D},`${n.id}:${$}:${i}:${o}:${m}:${g.map(e=>e.kind.charAt(0)).join("")}:${u?`${u.slot}.${u.step}`:"-"}`),c("div",{className:"flex h-full flex-col",children:[N&&t($e,{viewport:i,onViewport:d,zoom:o,onZoom:j,theme:m,onTheme:U,actions:t("button",{type:"button",onClick:()=>l(e=>e+1),className:T,children:"Recargar cuadros"}),hint:i===G?"Rutas reales, cargadas de una en una y congeladas como espejos; activa un paso para interactuar. Las pantallas con sesi\xF3n requieren haber iniciado sesi\xF3n aqu\xED.":`Rutas reales, los ${y.length} pasos a ${K?.width}px, congeladas como espejos.`,editing:p,onToggleEdit:q,pinCount:h,onOpenRequest:_,isolatedBase:{tab:"flujos",flow:n.id}}),c("div",{ref:se,className:"min-h-0 flex-1 overflow-auto bg-zinc-50 p-6 dark:bg-zinc-950",children:[c("header",{className:"mb-5 max-w-2xl",children:[c("div",{className:"flex items-center gap-2",children:[t("h2",{className:"text-lg font-semibold text-zinc-900 dark:text-zinc-100",children:n.title}),n.origin==="spider"&&t("span",{className:"rounded bg-zinc-100 px-1.5 py-0.5 text-[10px] font-medium text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300",title:"Descubierto siguiendo los enlaces reales de la app. Declara el recorrido en workbench.config.json para darle nombre y notas.",children:"descubierto"})]}),n.description&&t("p",{className:"mt-1 text-sm text-zinc-600 dark:text-zinc-400",children:n.description}),x.untraceableHrefs>0&&c("p",{className:"mt-1 text-[11px] text-zinc-500 dark:text-zinc-400",children:[x.untraceableHrefs," enlaces con destino calculado no se pudieron rastrear, as\xED que puede faltar alg\xFAn paso."]}),x.droppedFlows>0&&c("p",{className:"mt-1 text-[11px] text-zinc-500 dark:text-zinc-400",children:[x.droppedFlows," recorridos adicionales encontrados y no mostrados; declara los que importen en workbench.config.json."]})]}),t("div",{ref:f,children:t("div",{className:"space-y-8",children:X.map((e,r)=>c("div",{children:[X.length>1&&t("p",{className:"mb-2 text-[11px] font-medium uppercase tracking-wider text-zinc-500",children:e==="light"?"Claro":"Oscuro"}),t(Ee,{flow:n,steps:y,scale:ce,theme:e,nonce:$,editing:p,slot:r,frames:g,active:u,onCapture:te,onActivate:ne,onRefresh:re,onDemote:B,registerLiveFrame:ae})]},r===0?"a":"b"))})})]})]})}export{qe as FlowsPanel};
1
+ "use client";import{jsx as i,jsxs as y}from"react/jsx-runtime";import{useCallback as z,useEffect as C,useMemo as He,useRef as _,useState as m}from"react";import{useManifest as Se}from"../config-context";import{ConnectPopover as Ie}from"../connect-popover";import{useInspect as qe}from"../edit-mode";import{actionFor as Me,connectGestures as Pe,appendStep as _e,atCap as Be,bodyOf as Q,connectIntent as Ve,forkFrom as We,hasStepAt as Ue,laneRefOf as Ke,removeLast as Ge,routeOfHref as Ye,stepInputOf as Je}from"../flow-edit";import{frameOf as se,NO_FRAMES as ie,nextCapture as ce,prune as Qe,withFrame as O}from"../flow-frames";import{EN_CURSO as Xe}from"../journey-acts";import{layOut as Ze,locateNode as et}from"../flow-layout";import{viewportById as B}from"../manifest";import{CAPTURE_TOTAL_MS as tt,captureMirror as nt,serializeMirror as rt}from"../mirror";import{Outline as ot}from"../pick-highlight";import{readSketch as at}from"../screen-sketch";import{AUTO as X,CHIP as st,ScreenToolbar as it}from"../screen-toolbar";import"./flow-cards";import{CanvasBoard as ct}from"./flow-canvas-board";const le={route:"",label:"",spec:"",via:"",branchLabel:""},ue="workbench-flow-routes";function Nt({flow:o,componentIndex:de,editing:b,onPin:pe,onHover:me,onToggleEdit:fe,pinCount:he,onOpenRequest:ke,showChrome:be,initialViewport:xe,initialTheme:ge,routes:ve,onSaveFlow:A}){const{config:$,stats:D}=Se(),[L,ye]=m(0),[N,ze]=m(xe??X),[H,Ce]=m(ge??"light"),[$e,Ne]=m("near"),Z=_(null),V=_(null),S=N===X?null:B($,N),I=B($,void 0).id,{lanes:ee,nodes:c}=He(()=>Ze(o,e=>S??B($,e)),[o,S,$]),[T,x]=m(ie),[u,q]=m(null),W=_(new Map);C(()=>{x(ie),q(null)},[L]);const U=c.map(e=>e.key).join("|");C(()=>{x(e=>Qe(e,c)),q(e=>e&&c.some(t=>t.key===e.key)?e:null)},[U]);const te=_(1);C(()=>{const e=ce(T,c);e!==null&&x(t=>{if(ce(t,c)!==e)return t;const n=te.current;return te.current+=1,O(t,e,{kind:"capturing",ticket:n})})},[T,c]);let M=null,P=null;for(const e of c){const t=se(T,e);if(t.kind==="capturing"){M=e.key,P=t.ticket;break}}C(()=>{if(M===null||P===null)return;const e=M,t=P,n=setTimeout(()=>{x(r=>{const s=r.get(e);return s?.kind==="capturing"&&s.ticket===t?O(r,e,{kind:"restless"}):r})},tt);return()=>clearTimeout(n)},[M,P]);const Re=z((e,t,n)=>{const r=c.find(s=>s.key===e)?.step.route;r&&nt(n,r).then(s=>{x(p=>{const a=p.get(e);return a?.kind!=="capturing"||a.ticket!==t?p:O(p,e,s?{kind:"mirrored",srcdoc:s.srcdoc,sketch:s.sketch,capturedAt:Date.now()}:{kind:"restless"})})}).catch(()=>{})},[c]),K=z(()=>{if(!u)return;const e=W.current.get(`${u.slot}:${u.key}`),t=c.find(n=>n.key===u.key)?.step.route;if(e&&t)try{const n=e.contentDocument;if(n){const r=e.contentWindow?.location.pathname??t,s=rt(n,r,window.location.origin);let p=null;try{p=at(n,{width:e.contentWindow?.innerWidth??e.clientWidth,height:e.contentWindow?.innerHeight??e.clientHeight})}catch{}const a=Date.now(),h=u.key;x(Le=>O(Le,h,{kind:"mirrored",srcdoc:s,sketch:p,capturedAt:a}))}}catch{}q(null)},[u,c]),we=z((e,t)=>{K(),q({key:e,slot:t})},[K]),je=z(e=>{x(t=>O(t,e,{kind:"queued"}))},[]),Fe=z((e,t,n)=>{const r=`${t}:${e}`;n?W.current.set(r,n):W.current.delete(r)},[]),G=!!A,[l,d]=m(null),[E,R]=m(null),[k,f]=m(null),[g,w]=m(null),Y=l!==null&&typeof l.status=="object"&&"written"in l.status&&l.status.written===null&&Ue(o,l.at,l.draft.route.trim());C(()=>{Y&&d(null)},[Y]);const j=l&&!Y?l:null,Ae=j?S??c.find(e=>e.flat===j.at.flat)?.viewport??B($,void 0):null,J=j?.status==="writing"||E!==null&&E.error===null;C(()=>{b&&(f(null),w(null))},[b]),C(()=>{f(null),w(null),R(e=>e&&e.error===null?null:e)},[U,L]);const Te=z(()=>{f(e=>e===null?e:null),w(e=>e===null?e:null),V.current?.open&&(V.current.open=!1)},[]),ne=(e,t)=>{const n=re(e.key);if(!n)return null;const r=Ye(t.href,window.location.origin);return{loc:n,route:r,intent:Ve(o,{lane:n.kind,position:n.position,isLast:n.isLast},r,Be(o,$.maxFlowSteps))}},re=e=>{const t=et(ee,e);return t&&{ref:Ke(t.lane),kind:t.lane.kind,...t}},Ee=async()=>{if(!l||!A||l.status==="writing")return;const{at:e,draft:t}=l,n=e.lane.kind==="trunk"?o.steps[e.after]:o.branches[e.lane.index]?.id===e.lane.id?o.branches[e.lane.index]?.steps[e.after]:void 0;if(!n||n.route!==e.anchorRoute){d(a=>a&&{...a,status:{error:"El recorrido cambi\xF3 debajo de la tarjeta; ci\xE9rrala y vuelve a a\xF1adir la pantalla."}});return}const r=n.viewport,s=Je(t,r===I?"":r),p=e.fork?We(Q(o,I),n.route,t.branchLabel.trim(),s):_e(Q(o,I),e.lane,s);d(a=>a&&{...a,status:"writing"});try{const a=await A({...p,id:o.id});d(h=>h&&{...h,status:a.ok?{written:a.note??null}:{error:a.error??"Fall\xF3 la escritura."}})}catch(a){d(h=>h&&{...h,status:{error:a instanceof Error?a.message:"Fall\xF3 la escritura."}})}},Oe=G?{card:j,cardViewport:Ae,routesList:ue,busy:J,onDraft:e=>d(t=>t&&{...t,status:"editing",draft:{...t.draft,...e}}),onSubmit:()=>{Ee()},onCancelCard:()=>d(null),onGhost:(e,t,n,r)=>{f(null),d({at:{lane:e,after:t,anchorRoute:r,fork:!1,flat:n},draft:le,status:"editing"})},onFork:(e,t,n)=>{f(null),d({at:{lane:{kind:"trunk"},after:e,anchorRoute:n,fork:!0,flat:t},draft:le,status:"editing"})},onRemove:e=>{if(!A)return;const t=e.kind==="trunk"?e:(()=>{const n=o.branches.findIndex(r=>r.id===e.id);return n===-1?null:{kind:"branch",index:n,id:e.id}})();if(!t){R({error:"El recorrido cambi\xF3; esa fila ya no existe."});return}R({error:null}),A({...Ge(Q(o,I),t),id:o.id}).then(n=>{n.ok?n.note&&R({error:n.note}):R({error:n.error??"Fall\xF3 la escritura."})}).catch(n=>R({error:n instanceof Error?n.message:"Fall\xF3 la escritura."}))},connect:!b,onPick:(e,t)=>{if(!t){f(null);return}if(J||j!==null)return;const n=ne(e,t);if(!n)return;const r=Me(n.intent,t.wants);if(t.wants==="fork"&&r?.kind==="fork"){w(null),oe(e,n.loc,t,n.route,r);return}f({node:e,pick:t,route:n.route,intent:n.intent}),w(null)},onHoverPick:(e,t)=>{const n=t?ne(e,t):null;w(t&&n?{pick:t,route:n.route,intent:n.intent,parked:J||j!==null}:null)}}:null,oe=(e,t,n,r,s)=>{const p={route:r??"",label:n.text,spec:"",via:n.text,branchLabel:o.branches.some(h=>h.label===n.text)?"":n.text},a=s.kind==="fork"?{lane:{kind:"trunk"},after:t.position,anchorRoute:e.step.route,fork:!0,flat:e.flat}:{lane:t.ref,after:t.position,anchorRoute:e.step.route,fork:!1,flat:e.flat};d({at:a,draft:p,status:"editing"})},De=e=>{if(!k)return;const{node:t,pick:n,route:r}=k,s=re(t.key);f(null),s&&oe(t,s,n,r,e)},ae=H==="split"?["light","dark"]:[H];qe(b,z(()=>Z.current,[]),de,{onPin:pe,onHover:me},`${o.id}:${L}:${N}:${H}:${$e}:${c.map(e=>se(T,e).kind.charAt(0)).join("")}:${u?`${u.slot}.${u.key}`:"-"}`);const F=c.filter(e=>!e.step.exists).length,v=[F>0&&`${F} ${F===1?"paso por construir":"pasos por construir"} \u2014 se muestran sus especificaciones; se vuelven espejos reales cuando sus p\xE1ginas aterricen.`,D.untraceableHrefs>0&&`${D.untraceableHrefs} enlaces con destino calculado no se pudieron rastrear, as\xED que puede faltar alg\xFAn paso.`,D.droppedFlows>0&&`${D.droppedFlows} recorridos adicionales encontrados y no mostrados; declara los que importen en workbench.config.json.`,o.steps.some(e=>e.notice)&&"Este recorrido se muestra recortado; abre un paso para ver por qu\xE9."].filter(e=>typeof e=="string");return y("div",{className:"flex h-full flex-col",children:[be&&i(it,{viewport:N,onViewport:ze,zoomDisabledReason:"El lienzo tiene su propio zoom, abajo a la izquierda.",theme:H,onTheme:Ce,actions:i("button",{type:"button",onClick:()=>ye(e=>e+1),className:st,children:"Recargar cuadros"}),hint:N===X?"Rutas reales, cargadas de una en una y congeladas como espejos; activa un paso para interactuar. Arrastra el fondo para moverte; Ctrl/\u2318 + rueda para acercar; con el lienzo enfocado, flechas para moverte, + y \u2212 para el zoom, 0 para ajustar.":`Rutas reales, los ${c.length-F} pasos a ${S?.width}px, congeladas como espejos${F>0?`; ${F} por construir`:""}. Arrastra el fondo para moverte; Ctrl/\u2318 + rueda para acercar; con el lienzo enfocado, flechas para moverte, + y \u2212 para el zoom, 0 para ajustar.`,editing:b,onToggleEdit:fe,pinCount:he,onOpenRequest:ke,isolatedBase:{tab:"flujos",flow:o.id}}),y("div",{className:"flex items-center gap-2 border-b border-zinc-200 bg-zinc-50 px-6 py-2 dark:border-zinc-800 dark:bg-zinc-950",children:[i("h2",{className:"shrink-0 text-sm font-semibold text-zinc-900 dark:text-zinc-100",children:o.title}),o.origin==="spider"&&i("span",{className:"shrink-0 rounded bg-zinc-100 px-1.5 py-0.5 text-[10px] font-medium text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300",title:"Descubierto siguiendo los enlaces reales de la app. A\xF1\xE1dele una pantalla y queda declarado en workbench.config.json con este mismo id.",children:"descubierto"}),o.branches.length>0&&y("span",{className:"shrink-0 rounded bg-zinc-100 px-1.5 py-0.5 text-[10px] font-medium text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300",children:[o.branches.length," ",o.branches.length===1?"rama":"ramas"]}),y("details",{ref:V,className:"group relative min-w-0 flex-1",children:[y("summary",{className:"cursor-pointer list-none truncate text-[11px] text-zinc-500 marker:content-none [&::-webkit-details-marker]:hidden dark:text-zinc-400",children:[i("span",{className:"underline decoration-dotted underline-offset-2",children:v.length>0?v[0]:o.description??"Sobre este recorrido"}),v.length>1&&y("span",{className:"ml-1 rounded bg-amber-100 px-1 text-[10px] font-medium text-amber-800 dark:bg-amber-900/40 dark:text-amber-200",children:["+",v.length-1,i("span",{className:"sr-only",children:" avisos m\xE1s"})]})]}),y("div",{className:"absolute z-20 mt-1 max-w-2xl rounded-md border border-zinc-200 bg-white p-3 shadow-lg dark:border-zinc-700 dark:bg-zinc-900",children:[o.description&&i("p",{className:"text-sm text-zinc-600 dark:text-zinc-400",children:o.description}),v.map(e=>i("p",{className:"mt-1 text-[11px] text-zinc-500 dark:text-zinc-400",children:e},e)),G&&i("p",{className:"mt-1 text-[11px] text-zinc-500 dark:text-zinc-400",children:"Haz clic en un bot\xF3n o enlace de un espejo para a\xF1adir la pantalla a la que lleva; cada fila termina en \xAB+ A\xF1adir pantalla\xBB."})]})]}),v.length>0&&i("ul",{className:"sr-only",children:v.map(e=>i("li",{children:e},e))}),E?.error&&i("p",{role:"alert",className:"min-w-0 flex-1 truncate text-[11px] text-red-700 dark:text-red-300",title:E.error,children:E.error}),G&&i("datalist",{id:ue,children:(ve??[]).map(e=>i("option",{value:e},e))})]}),i("div",{ref:Z,tabIndex:-1,className:"min-h-0 flex-1",children:i(ct,{flow:o,lanes:ee,themes:ae,nonce:L,editing:b,frames:T,active:u,fitKey:`${N}:${ae.length}`,shape:U,onCapture:Re,onActivate:we,onRefresh:je,onDemote:K,registerLiveFrame:Fe,composer:Oe,onViewportChange:Te,onDetailChange:Ne})}),g&&!k&&!b&&i(ot,{rect:g.pick.rect,tone:"sky",label:`\xAB${g.pick.text||"control"}\xBB${g.route?` \u2192 ${g.route}`:""}`,hint:g.parked?Xe:Pe(g.intent)}),k&&i(Ie,{pick:k.pick,route:k.route,intent:k.intent,onConfirm:De,onCancel:()=>f(e=>e===k?null:e)})]})}export{Nt as FlowsPanel};
@@ -14,7 +14,33 @@ export declare function mapRect(element: Element, frame: HTMLIFrameElement | nul
14
14
  width: number;
15
15
  height: number;
16
16
  };
17
+ export declare function mapPoint(x: number, y: number, frame: HTMLIFrameElement): {
18
+ x: number;
19
+ y: number;
20
+ };
17
21
  export declare function describeNode(node: ResolvedNode): string;
22
+ declare const TONES: {
23
+ readonly amber: {
24
+ readonly border: "border-amber-400";
25
+ readonly tag: "bg-amber-400 text-amber-950";
26
+ };
27
+ readonly sky: {
28
+ readonly border: "border-sky-400";
29
+ readonly tag: "bg-sky-400 text-sky-950";
30
+ };
31
+ };
32
+ export declare function Outline({ rect, label, hint, tone, }: {
33
+ rect: {
34
+ top: number;
35
+ left: number;
36
+ width: number;
37
+ height: number;
38
+ };
39
+ label: string;
40
+ hint?: string;
41
+ tone?: keyof typeof TONES;
42
+ }): import("react").JSX.Element;
18
43
  export declare function PickHighlight({ target }: {
19
44
  target: PickTarget | null;
20
45
  }): import("react").JSX.Element | null;
46
+ export {};
@@ -1 +1 @@
1
- "use client";import{jsx as c,jsxs as a}from"react/jsx-runtime";import{SCALE_ATTR as p}from"./screen-frame";const r=20;function u(e,o){const t=e.getBoundingClientRect();if(!o)return{top:t.top,left:t.left,width:t.width,height:t.height};const n=o.closest(`[${p}]`)?.getAttribute(p),s=Number(n),i=Number.isFinite(s)&&s>0?s:1,l=o.getBoundingClientRect();return{top:l.top+t.top*i,left:l.left+t.left*i,width:t.width*i,height:t.height*i}}function h(e){const o=e.component??`<${e.tag}>`,t=e.component&&e.file?e.file.split("/").pop():null;return[o,t,e.surface].filter(Boolean).join(" \xB7 ")}function m({target:e}){if(!e)return null;const{rect:o,node:t}=e,n=o.top>r+4;return a("div",{"aria-hidden":!0,className:"pointer-events-none fixed z-[2147483000]",style:{top:o.top,left:o.left,width:o.width,height:o.height},children:[c("div",{className:"absolute inset-0 border border-amber-400"}),c("span",{className:"absolute left-0 whitespace-nowrap rounded-sm bg-amber-400 px-1.5 py-0.5 font-mono text-[10px] leading-none text-amber-950 shadow-sm",style:n?{top:-r}:{bottom:-r},children:h(t)})]})}export{m as PickHighlight,h as describeNode,u as mapRect};
1
+ "use client";import{jsx as r,jsxs as l}from"react/jsx-runtime";import{ZOOM_ATTR as a}from"./canvas-gestures";import{cx as c}from"./cx";import{SCALE_ATTR as p}from"./screen-frame";const d=25,u=44;function i(t,n){const e=t.closest(`[${n}]`)?.getAttribute(n),o=Number(e);return Number.isFinite(o)&&o>0?o:1}function y(t,n){const e=t.getBoundingClientRect();if(!n)return{top:e.top,left:e.left,width:e.width,height:e.height};const o=i(n,p)*i(n,a),s=n.getBoundingClientRect();return{top:s.top+e.top*o,left:s.left+e.left*o,width:e.width*o,height:e.height*o}}function N(t,n,e){const o=i(e,p)*i(e,a),s=e.getBoundingClientRect();return{x:s.left+t*o,y:s.top+n*o}}function f(t){const n=t.component??`<${t.tag}>`,e=t.component&&t.file?t.file.split("/").pop():null;return[n,e,t.surface].filter(Boolean).join(" \xB7 ")}const m={amber:{border:"border-amber-400",tag:"bg-amber-400 text-amber-950"},sky:{border:"border-sky-400",tag:"bg-sky-400 text-sky-950"}};function h({rect:t,label:n,hint:e,tone:o="amber"}){const s=t.top>(e?u:d);return l("div",{"aria-hidden":!0,className:"pointer-events-none fixed z-[2147483000]",style:{top:t.top,left:t.left,width:t.width,height:t.height},children:[r("div",{className:c("absolute inset-0 border",m[o].border)}),l("span",{className:c("absolute left-0 rounded-sm px-1.5 text-[10px] shadow-sm",e?"flex max-w-[22rem] flex-col py-1 leading-[1.45]":"whitespace-nowrap py-0.5 leading-none",m[o].tag),style:s?{bottom:"100%",marginBottom:3}:{top:"100%",marginTop:3},children:[r("span",{className:c("font-mono",e&&"truncate"),children:n}),e&&r("span",{className:"truncate font-sans opacity-70",children:e})]})]})}function R({target:t}){return t?r(h,{rect:t.rect,label:f(t.node)}):null}export{h as Outline,R as PickHighlight,f as describeNode,N as mapPoint,y as mapRect};
package/dist/pin.d.ts CHANGED
@@ -37,3 +37,37 @@ export interface TicketSummary {
37
37
  misses: number;
38
38
  file: string;
39
39
  }
40
+ export interface FlowStepInput {
41
+ route: string;
42
+ label?: string;
43
+ via?: string;
44
+ viewport?: string;
45
+ note?: string;
46
+ spec?: string;
47
+ }
48
+ export interface FlowBranchInput {
49
+ id?: string;
50
+ label: string;
51
+ from: string;
52
+ steps: FlowStepInput[];
53
+ }
54
+ export interface FlowBody {
55
+ title: string;
56
+ description: string;
57
+ intent: string;
58
+ acceptance: string;
59
+ steps: FlowStepInput[];
60
+ branches: FlowBranchInput[];
61
+ }
62
+ export type SaveFlowInput = FlowBody & {
63
+ id: string | null;
64
+ };
65
+ export interface SaveFlowResult {
66
+ ok: boolean;
67
+ flowId?: string;
68
+ ticketId?: string | null;
69
+ file?: string | null;
70
+ created?: boolean;
71
+ note?: string;
72
+ error?: string;
73
+ }