dishui 0.0.48 → 0.0.50

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 (55) hide show
  1. package/dist/components/pro/Flow/Flow.js +419 -407
  2. package/dist/components/pro/Flow/Flow.js.map +1 -1
  3. package/dist/components/pro/Flow/archify/build.d.ts +74 -0
  4. package/dist/components/pro/Flow/archify/build.js +103 -0
  5. package/dist/components/pro/Flow/archify/build.js.map +1 -0
  6. package/dist/components/pro/Flow/archify/convert.d.ts +14 -0
  7. package/dist/components/pro/Flow/archify/convert.js +534 -0
  8. package/dist/components/pro/Flow/archify/convert.js.map +1 -0
  9. package/dist/components/pro/Flow/archify/index.d.ts +12 -0
  10. package/dist/components/pro/Flow/archify/palette.d.ts +64 -0
  11. package/dist/components/pro/Flow/archify/palette.js +112 -0
  12. package/dist/components/pro/Flow/archify/palette.js.map +1 -0
  13. package/dist/components/pro/Flow/archify/presets.d.ts +26 -0
  14. package/dist/components/pro/Flow/archify/presets.js +43 -0
  15. package/dist/components/pro/Flow/archify/presets.js.map +1 -0
  16. package/dist/components/pro/Flow/archify/spec.d.ts +283 -0
  17. package/dist/components/pro/Flow/archify/spec.js +10 -0
  18. package/dist/components/pro/Flow/archify/spec.js.map +1 -0
  19. package/dist/components/pro/Flow/constants.js +14 -0
  20. package/dist/components/pro/Flow/constants.js.map +1 -1
  21. package/dist/components/pro/Flow/hooks/useClipboard.d.ts +5 -0
  22. package/dist/components/pro/Flow/hooks/useClipboard.js +129 -73
  23. package/dist/components/pro/Flow/hooks/useClipboard.js.map +1 -1
  24. package/dist/components/pro/Flow/hooks/useFlowImportExport.d.ts +1 -0
  25. package/dist/components/pro/Flow/hooks/useFlowImportExport.js +108 -93
  26. package/dist/components/pro/Flow/hooks/useFlowImportExport.js.map +1 -1
  27. package/dist/components/pro/Flow/hooks/useKeyboardShortcuts.d.ts +1 -0
  28. package/dist/components/pro/Flow/hooks/useKeyboardShortcuts.js +7 -7
  29. package/dist/components/pro/Flow/hooks/useKeyboardShortcuts.js.map +1 -1
  30. package/dist/components/pro/Flow/index.d.ts +2 -0
  31. package/dist/components/pro/Flow/nodes/DataNodeView.d.ts +4 -1
  32. package/dist/components/pro/Flow/nodes/DataNodeView.js +127 -115
  33. package/dist/components/pro/Flow/nodes/DataNodeView.js.map +1 -1
  34. package/dist/components/pro/Flow/nodes/MediaContent.js +72 -67
  35. package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
  36. package/dist/components/pro/Flow/nodes/NodeRenderer.d.ts +5 -0
  37. package/dist/components/pro/Flow/nodes/NodeRenderer.js +216 -115
  38. package/dist/components/pro/Flow/nodes/NodeRenderer.js.map +1 -1
  39. package/dist/components/pro/Flow/panels/FlowToolbar.js +208 -169
  40. package/dist/components/pro/Flow/panels/FlowToolbar.js.map +1 -1
  41. package/dist/components/pro/Flow/panels/InspectorPanel.js +602 -369
  42. package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
  43. package/dist/components/pro/Flow/panels/ShapePalette.js +50 -39
  44. package/dist/components/pro/Flow/panels/ShapePalette.js.map +1 -1
  45. package/dist/components/pro/Flow/panels/toolbarIcons.d.ts +1 -0
  46. package/dist/components/pro/Flow/panels/toolbarIcons.js +36 -8
  47. package/dist/components/pro/Flow/panels/toolbarIcons.js.map +1 -1
  48. package/dist/components/pro/Flow/types.d.ts +30 -0
  49. package/dist/components/pro/Flow/types.js.map +1 -1
  50. package/dist/components/pro/Flow/utils/themeColor.d.ts +10 -9
  51. package/dist/components/pro/Flow/utils/themeColor.js +66 -44
  52. package/dist/components/pro/Flow/utils/themeColor.js.map +1 -1
  53. package/dist/dishui.css +1 -1
  54. package/dist/flow.js +73 -56
  55. package/package.json +18 -17
@@ -121,6 +121,14 @@ export type GradientDirection = 'to-r' | 'to-l' | 'to-b' | 'to-t' | 'to-br' | 't
121
121
  /** Group label placement */
122
122
  export type FlowGroupLabelPlacement = 'top' | 'bottom' | 'left' | 'right';
123
123
  export type FlowGroupLabelAlign = 'start' | 'center' | 'end';
124
+ /** Corner placement for a node's tag pill. */
125
+ export type FlowTagPlacement = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
126
+ /**
127
+ * Label placement for ordinary shape nodes: the center plus the eight compass
128
+ * positions around it. Non-center placements sit just outside / against the
129
+ * corresponding edge or corner and can be nudged with `labelOffsetX/Y`.
130
+ */
131
+ export type FlowTextPlacement = 'center' | 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
124
132
  export declare const FLOW_NODE_TYPES: readonly ['shapeRect', 'shapeRoundRect', 'shapeEllipse', 'shapeDiamond', 'shapeDocument', 'shapeParallelogram', 'shapeTriangle', 'shapeTrapezoid', 'shapePentagon', 'shapeHexagon', 'shapeStar', 'shapeHexagram', 'shapeRightTriangle', 'shapeCorner', 'textLabel', 'flowGroup', 'geometryGroup', 'dividerNode', 'arrowNode', 'polylineNode', 'shapeSvg', 'mediaNode', 'animAnchor'];
125
133
  export type FlowShapeType = (typeof FLOW_NODE_TYPES)[number];
126
134
  /** Custom key-value attribute on a node */
@@ -136,11 +144,33 @@ export interface FlowNodeData {
136
144
  strokeWidth: number;
137
145
  color: string;
138
146
  fontSize: number;
147
+ /**
148
+ * Optional secondary line rendered under the bold title, in a muted color.
149
+ * Used by imported Archify diagrams to reproduce the two-line card look
150
+ * (e.g. "API Gateway" / "public :443").
151
+ */
152
+ sublabel?: string;
153
+ /** Muted color for `sublabel`; falls back to a dimmed label color. */
154
+ sublabelColor?: string;
155
+ /**
156
+ * Optional short pill rendered in a corner of the node (e.g. a tag such as
157
+ * "SEV-1/2" or a lifecycle step number). Cosmetic only.
158
+ */
159
+ tag?: string;
160
+ /** Tag pill text/border color. Falls back to the node stroke color. */
161
+ tagColor?: string;
162
+ /** Which corner the tag pill sits in. Defaults to `top-right`. */
163
+ tagPlacement?: FlowTagPlacement;
139
164
  /**
140
165
  * Label/font color. When unset, falls back to `color` (legacy behavior where
141
166
  * a single color drove both the label and the SVG icon tint).
142
167
  */
143
168
  labelColor?: string;
169
+ /**
170
+ * Label placement for ordinary shape nodes (9-way). When unset the label is
171
+ * centered. Fine-tune with `labelOffsetX` / `labelOffsetY`.
172
+ */
173
+ textPlacement?: FlowTextPlacement;
144
174
  borderStyle?: FlowBorderStyle;
145
175
  rotation?: number;
146
176
  flipX?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../../../src/components/pro/Flow/types.ts"],"sourcesContent":["/** Arrow marker type for edges and lines */\nexport type FlowEdgeMarkerKind = 'none' | 'arrow' | 'arrowclosed';\n\n/** Label placement for SVG icon stamps. */\nexport type FlowIconLabelPlacement = 'top' | 'middle' | 'bottom' | 'left' | 'right';\n\n/** Media stamp kinds rendered via DOM overlay. */\nexport type FlowMediaKind = 'markdown' | 'html' | 'mermaid' | 'math' | 'image' | 'model3d' | 'ai' | 'data';\n\nexport type FlowModelFormat = 'stl' | 'obj' | '3mf';\n\n/** Logical type of a Data-node column, driving parsing/aggregation/axis scales. */\nexport type FlowDataColumnType = 'string' | 'number' | 'date' | 'boolean';\n\n/** A single column definition for a Data node. */\nexport interface FlowDataColumn {\n /** Object key used in each row record. */\n key: string;\n /** Display label; falls back to `key` when unset. */\n label?: string;\n /** Value type; numeric columns can be aggregated and used as chart measures. */\n type: FlowDataColumnType;\n}\n\n/** Which surface the Data node renders: a (pivotable) table or a chart. */\nexport type FlowDataView = 'table' | 'chart';\n\n/** Supported chart renderings for a Data node. */\nexport type FlowDataChartType =\n | 'bar'\n | 'barHorizontal'\n | 'line'\n | 'area'\n | 'scatter'\n | 'pie';\n\n/** Chart-view configuration for a Data node. */\nexport interface FlowDataChartConfig {\n type: FlowDataChartType;\n /** Category / X axis field (dimension). */\n xField?: string;\n /** One or more numeric measure fields drawn as series. */\n yFields?: string[];\n /** Per-series color overrides, keyed by measure field key (cartesian charts). */\n seriesColors?: Record<string, string>;\n /** Slice color palette for pie charts. Defaults to the built-in palette. */\n palette?: string[];\n}\n\n/** Aggregation used by the pivot table view. */\nexport type FlowDataAggFn = 'sum' | 'avg' | 'count' | 'min' | 'max';\n\n/** Pivot configuration panel placement. */\nexport type FlowDataPivotPanelPlacement = 'top' | 'bottom' | 'left' | 'right';\n\n/** Pivot-view configuration for a Data node table. */\nexport interface FlowDataPivotConfig {\n enabled: boolean;\n rowFields: string[];\n colFields: string[];\n values: Array<{ field: string; aggFn: FlowDataAggFn }>;\n /** Where the pivot config panel renders. Defaults to 'top'. */\n panelPlacement?: FlowDataPivotPanelPlacement;\n}\n\n/**\n * Persisted state for a Data node (`mediaKind: 'data'`). Holds the parsed\n * columns/rows plus how they should be visualized. Serialized with the document.\n */\nexport interface FlowDataConfig {\n columns: FlowDataColumn[];\n rows: Array<Record<string, unknown>>;\n /** Active rendering surface. Defaults to 'table'. */\n view: FlowDataView;\n /** Chart configuration (used when `view === 'chart'`). */\n chart?: FlowDataChartConfig;\n /** Pivot configuration (used when `view === 'table'`). */\n pivot?: FlowDataPivotConfig;\n /** Original uploaded file name, when imported. */\n sourceName?: string;\n}\n\n/** AI media node configuration (persisted subset). */\nexport interface FlowAIConfig {\n /** API endpoint (OpenAI-compatible chat completions or Anthropic messages). */\n gateway: string;\n protocol: 'openai' | 'anthropic';\n model: string;\n /** API key. Persisted in the document; treat exported JSON as sensitive. */\n apiKey?: string;\n systemPrompt?: string;\n /** Extra request headers. */\n headers?: Record<string, string>;\n}\n\n/** Line style */\nexport type FlowEdgeLineStyle = 'solid' | 'dashed' | 'dotted' | 'dynamic';\n\n/** Dash density for dashed/dotted lines */\nexport type FlowEdgeDashDensity = 'sparse' | 'medium' | 'dense';\n\n/** Bezier control points for simplebezier edge segments (canvas coordinates) */\nexport interface FlowBezierControl {\n c1x: number;\n c1y: number;\n c2x: number;\n c2y: number;\n}\n\n/** Persisted edge styling on edge.data */\nexport interface FlowEdgeData {\n strokeColor?: string;\n strokeWidth?: number;\n lineStyle?: FlowEdgeLineStyle;\n dashDensity?: FlowEdgeDashDensity;\n markerStart?: FlowEdgeMarkerKind;\n markerEnd?: FlowEdgeMarkerKind;\n labelText?: string;\n labelFontSize?: number;\n labelFontFamily?: string;\n /** Play a source-to-target traveling gradient while in presentation mode. */\n animated?: boolean;\n /** Waypoints; absolute canvas coords unless waypointGroupId set */\n waypoints?: Array<{ x: number; y: number }>;\n waypointGroupId?: string;\n /**\n * Per-segment bezier controls for simplebezier type;\n * null entries use default computed controls.\n */\n bezierControls?: Array<FlowBezierControl | null> | null;\n}\n\n/** Edge type names */\nexport type FlowEdgeTypeName =\n | 'smoothstep'\n | 'step'\n | 'straight'\n | 'simplebezier';\n\n/** Border line style */\nexport type FlowBorderStyle = 'none' | 'solid' | 'dashed' | 'dotted' | 'dynamic';\n\n/** Gradient direction */\nexport type GradientDirection =\n | 'to-r'\n | 'to-l'\n | 'to-b'\n | 'to-t'\n | 'to-br'\n | 'to-tl'\n | 'to-tr'\n | 'to-bl';\n\n/** Group label placement */\nexport type FlowGroupLabelPlacement = 'top' | 'bottom' | 'left' | 'right';\nexport type FlowGroupLabelAlign = 'start' | 'center' | 'end';\n\nexport const FLOW_NODE_TYPES = [\n 'shapeRect',\n 'shapeRoundRect',\n 'shapeEllipse',\n 'shapeDiamond',\n 'shapeDocument',\n 'shapeParallelogram',\n 'shapeTriangle',\n 'shapeTrapezoid',\n 'shapePentagon',\n 'shapeHexagon',\n 'shapeStar',\n 'shapeHexagram',\n 'shapeRightTriangle',\n 'shapeCorner',\n 'textLabel',\n 'flowGroup',\n 'geometryGroup',\n 'dividerNode',\n 'arrowNode',\n 'polylineNode',\n 'shapeSvg',\n 'mediaNode',\n 'animAnchor',\n] as const;\n\nexport type FlowShapeType = (typeof FLOW_NODE_TYPES)[number];\n\n/** Custom key-value attribute on a node */\nexport interface FlowNodeAttribute {\n key: string;\n value: string;\n}\n\n/** Data stored on each flow node */\nexport interface FlowNodeData {\n label: string;\n fill: string;\n stroke: string;\n strokeWidth: number;\n color: string;\n fontSize: number;\n /**\n * Label/font color. When unset, falls back to `color` (legacy behavior where\n * a single color drove both the label and the SVG icon tint).\n */\n labelColor?: string;\n borderStyle?: FlowBorderStyle;\n rotation?: number;\n flipX?: boolean;\n flipY?: boolean;\n fillGradientTo?: string;\n fillGradientDirection?: GradientDirection;\n attributes?: FlowNodeAttribute[];\n childCanvasId?: string;\n isGroup?: boolean;\n groupBorderStyle?: FlowBorderStyle;\n groupLabelPlacement?: FlowGroupLabelPlacement;\n groupLabelAlign?: FlowGroupLabelAlign;\n groupLabelFill?: string;\n groupLabelRotation?: 0 | 90 | 180 | 270;\n groupLabelBgMode?: 'text' | 'full';\n dividerOrientation?: 'horizontal' | 'vertical';\n arrowDouble?: boolean;\n arrowBent?: boolean;\n arrowBendX?: number;\n arrowBendY?: number;\n polylineWaypoints?: Array<{ x: number; y: number }>;\n /** SVG stamp icon id (for type 'shapeSvg'). */\n svgId?: string;\n /** Whether the SVG stamp draws a bordered box around the icon. */\n iconBox?: boolean;\n /** Label placement for SVG stamps. Left/right use top-to-bottom vertical text. */\n labelPlacement?: FlowIconLabelPlacement;\n /** Horizontal offset from the resolved icon label position, in canvas units. */\n labelOffsetX?: number;\n /** Vertical offset from the resolved icon label position, in canvas units. */\n labelOffsetY?: number;\n /** Media node kind (for type 'mediaNode'). */\n mediaKind?: FlowMediaKind;\n /** Source content or URL for the media node. */\n mediaContent?: string;\n /** Explicit model format for 3D media nodes. */\n modelFormat?: FlowModelFormat;\n /** AI media node configuration (serializable subset; secrets are runtime-only). */\n aiConfig?: FlowAIConfig;\n /** Data node configuration (for type 'mediaNode' with mediaKind 'data'). */\n dataConfig?: FlowDataConfig;\n /**\n * Stable creation index for `animAnchor` nodes, used to order slides. The\n * displayed sequence badge is derived from this ordering, so deleting an\n * anchor renumbers the rest automatically.\n */\n animIndex?: number;\n /** Marks nodes managed by Mindmap mode. */\n isMindMapNode?: boolean;\n /** Logical parent used by Mindmap auto-layout (separate from visual groups). */\n mindMapParentId?: string;\n}\n\n/** A flow node */\nexport interface FlowNode {\n id: string;\n type: FlowShapeType;\n position: { x: number; y: number };\n width: number;\n height: number;\n data: FlowNodeData;\n parentId?: string;\n zIndex?: number;\n}\n\n/** A flow edge (connection between nodes) */\nexport interface FlowEdge {\n id: string;\n source: string;\n target: string;\n sourceHandle?: string;\n targetHandle?: string;\n type: FlowEdgeTypeName;\n data: FlowEdgeData;\n}\n\n/** Independent line types */\nexport type FlowLineType = 'freehand' | 'straight' | 'polyline' | 'arrow';\n\n/** An independent line not attached to nodes */\nexport interface FlowLine {\n id: string;\n type: FlowLineType;\n points: Array<{ x: number; y: number }>;\n strokeColor: string;\n strokeWidth: number;\n lineStyle: FlowEdgeLineStyle;\n dashDensity?: FlowEdgeDashDensity;\n markerStart?: FlowEdgeMarkerKind;\n markerEnd?: FlowEdgeMarkerKind;\n closed?: boolean;\n zIndex?: number;\n parentId?: string;\n}\n\n/** Single canvas layer data */\nexport interface FlowCanvasData {\n nodes: FlowNode[];\n edges: FlowEdge[];\n lines: FlowLine[];\n}\n\n/** Multi-canvas document; root canvas id is 'root' */\nexport interface FlowDocument {\n canvases: Record<string, FlowCanvasData>;\n stack: string[];\n /** Project title, shown in the editable title bar and used as export filename. */\n title?: string;\n}\n\n/** Active tool modes */\nexport type FlowToolMode =\n | 'select'\n | 'pan'\n | 'connect'\n | 'freehand'\n | 'line'\n | 'polyline'\n | 'arrow';\n\n/** Viewport transform state */\nexport interface ViewportState {\n x: number;\n y: number;\n zoom: number;\n}\n\n/** Selection state */\nexport interface SelectionState {\n nodeIds: Set<string>;\n edgeIds: Set<string>;\n lineIds: Set<string>;\n}\n\n/** Props for the Flow component */\nexport interface FlowProps {\n /** Initial document; if not provided, starts with empty doc */\n initialDocument?: FlowDocument;\n /** Callback when document changes */\n onChange?: (doc: FlowDocument) => void;\n /** Width of the component (defaults to 100%) */\n width?: number | string;\n /** Height of the component (defaults to 100%) */\n height?: number | string;\n /** Whether the flow is read-only */\n readOnly?: boolean;\n /** Leave the current document from the built-in toolbar. */\n onBack?: () => void;\n /** Export the current canvas as PNG from the built-in toolbar. */\n onExportPNG?: () => void | Promise<void>;\n /** Publish or configure sharing from the built-in toolbar. */\n onPublish?: () => void;\n /** Show minimap */\n showMiniMap?: boolean;\n /** Show grid */\n showGrid?: boolean;\n /** Grid size in pixels */\n gridSize?: number;\n /** CSS class for outer container */\n className?: string;\n /**\n * Show the AI assistant panel (right side) that turns a text description or\n * an uploaded image into a flow document. Defaults to true.\n */\n showAI?: boolean;\n /**\n * Show the AI model configuration form inside the AI panel (gateway /\n * protocol / model / api key). When false, the config is hidden and the\n * caller is expected to supply `aiConfig`. Defaults to true.\n */\n showAIConfig?: boolean;\n /** Initial / preset AI model configuration for the AI panel. */\n aiConfig?: FlowAIConfig;\n}\n"],"mappings":"AA6JA,IAAa,IAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF"}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../../src/components/pro/Flow/types.ts"],"sourcesContent":["/** Arrow marker type for edges and lines */\nexport type FlowEdgeMarkerKind = 'none' | 'arrow' | 'arrowclosed';\n\n/** Label placement for SVG icon stamps. */\nexport type FlowIconLabelPlacement = 'top' | 'middle' | 'bottom' | 'left' | 'right';\n\n/** Media stamp kinds rendered via DOM overlay. */\nexport type FlowMediaKind = 'markdown' | 'html' | 'mermaid' | 'math' | 'image' | 'model3d' | 'ai' | 'data';\n\nexport type FlowModelFormat = 'stl' | 'obj' | '3mf';\n\n/** Logical type of a Data-node column, driving parsing/aggregation/axis scales. */\nexport type FlowDataColumnType = 'string' | 'number' | 'date' | 'boolean';\n\n/** A single column definition for a Data node. */\nexport interface FlowDataColumn {\n /** Object key used in each row record. */\n key: string;\n /** Display label; falls back to `key` when unset. */\n label?: string;\n /** Value type; numeric columns can be aggregated and used as chart measures. */\n type: FlowDataColumnType;\n}\n\n/** Which surface the Data node renders: a (pivotable) table or a chart. */\nexport type FlowDataView = 'table' | 'chart';\n\n/** Supported chart renderings for a Data node. */\nexport type FlowDataChartType =\n | 'bar'\n | 'barHorizontal'\n | 'line'\n | 'area'\n | 'scatter'\n | 'pie';\n\n/** Chart-view configuration for a Data node. */\nexport interface FlowDataChartConfig {\n type: FlowDataChartType;\n /** Category / X axis field (dimension). */\n xField?: string;\n /** One or more numeric measure fields drawn as series. */\n yFields?: string[];\n /** Per-series color overrides, keyed by measure field key (cartesian charts). */\n seriesColors?: Record<string, string>;\n /** Slice color palette for pie charts. Defaults to the built-in palette. */\n palette?: string[];\n}\n\n/** Aggregation used by the pivot table view. */\nexport type FlowDataAggFn = 'sum' | 'avg' | 'count' | 'min' | 'max';\n\n/** Pivot configuration panel placement. */\nexport type FlowDataPivotPanelPlacement = 'top' | 'bottom' | 'left' | 'right';\n\n/** Pivot-view configuration for a Data node table. */\nexport interface FlowDataPivotConfig {\n enabled: boolean;\n rowFields: string[];\n colFields: string[];\n values: Array<{ field: string; aggFn: FlowDataAggFn }>;\n /** Where the pivot config panel renders. Defaults to 'top'. */\n panelPlacement?: FlowDataPivotPanelPlacement;\n}\n\n/**\n * Persisted state for a Data node (`mediaKind: 'data'`). Holds the parsed\n * columns/rows plus how they should be visualized. Serialized with the document.\n */\nexport interface FlowDataConfig {\n columns: FlowDataColumn[];\n rows: Array<Record<string, unknown>>;\n /** Active rendering surface. Defaults to 'table'. */\n view: FlowDataView;\n /** Chart configuration (used when `view === 'chart'`). */\n chart?: FlowDataChartConfig;\n /** Pivot configuration (used when `view === 'table'`). */\n pivot?: FlowDataPivotConfig;\n /** Original uploaded file name, when imported. */\n sourceName?: string;\n}\n\n/** AI media node configuration (persisted subset). */\nexport interface FlowAIConfig {\n /** API endpoint (OpenAI-compatible chat completions or Anthropic messages). */\n gateway: string;\n protocol: 'openai' | 'anthropic';\n model: string;\n /** API key. Persisted in the document; treat exported JSON as sensitive. */\n apiKey?: string;\n systemPrompt?: string;\n /** Extra request headers. */\n headers?: Record<string, string>;\n}\n\n/** Line style */\nexport type FlowEdgeLineStyle = 'solid' | 'dashed' | 'dotted' | 'dynamic';\n\n/** Dash density for dashed/dotted lines */\nexport type FlowEdgeDashDensity = 'sparse' | 'medium' | 'dense';\n\n/** Bezier control points for simplebezier edge segments (canvas coordinates) */\nexport interface FlowBezierControl {\n c1x: number;\n c1y: number;\n c2x: number;\n c2y: number;\n}\n\n/** Persisted edge styling on edge.data */\nexport interface FlowEdgeData {\n strokeColor?: string;\n strokeWidth?: number;\n lineStyle?: FlowEdgeLineStyle;\n dashDensity?: FlowEdgeDashDensity;\n markerStart?: FlowEdgeMarkerKind;\n markerEnd?: FlowEdgeMarkerKind;\n labelText?: string;\n labelFontSize?: number;\n labelFontFamily?: string;\n /** Play a source-to-target traveling gradient while in presentation mode. */\n animated?: boolean;\n /** Waypoints; absolute canvas coords unless waypointGroupId set */\n waypoints?: Array<{ x: number; y: number }>;\n waypointGroupId?: string;\n /**\n * Per-segment bezier controls for simplebezier type;\n * null entries use default computed controls.\n */\n bezierControls?: Array<FlowBezierControl | null> | null;\n}\n\n/** Edge type names */\nexport type FlowEdgeTypeName =\n | 'smoothstep'\n | 'step'\n | 'straight'\n | 'simplebezier';\n\n/** Border line style */\nexport type FlowBorderStyle = 'none' | 'solid' | 'dashed' | 'dotted' | 'dynamic';\n\n/** Gradient direction */\nexport type GradientDirection =\n | 'to-r'\n | 'to-l'\n | 'to-b'\n | 'to-t'\n | 'to-br'\n | 'to-tl'\n | 'to-tr'\n | 'to-bl';\n\n/** Group label placement */\nexport type FlowGroupLabelPlacement = 'top' | 'bottom' | 'left' | 'right';\nexport type FlowGroupLabelAlign = 'start' | 'center' | 'end';\n\n/** Corner placement for a node's tag pill. */\nexport type FlowTagPlacement = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n\n/**\n * Label placement for ordinary shape nodes: the center plus the eight compass\n * positions around it. Non-center placements sit just outside / against the\n * corresponding edge or corner and can be nudged with `labelOffsetX/Y`.\n */\nexport type FlowTextPlacement =\n | 'center'\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'top-left'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-right';\n\nexport const FLOW_NODE_TYPES = [\n 'shapeRect',\n 'shapeRoundRect',\n 'shapeEllipse',\n 'shapeDiamond',\n 'shapeDocument',\n 'shapeParallelogram',\n 'shapeTriangle',\n 'shapeTrapezoid',\n 'shapePentagon',\n 'shapeHexagon',\n 'shapeStar',\n 'shapeHexagram',\n 'shapeRightTriangle',\n 'shapeCorner',\n 'textLabel',\n 'flowGroup',\n 'geometryGroup',\n 'dividerNode',\n 'arrowNode',\n 'polylineNode',\n 'shapeSvg',\n 'mediaNode',\n 'animAnchor',\n] as const;\n\nexport type FlowShapeType = (typeof FLOW_NODE_TYPES)[number];\n\n/** Custom key-value attribute on a node */\nexport interface FlowNodeAttribute {\n key: string;\n value: string;\n}\n\n/** Data stored on each flow node */\nexport interface FlowNodeData {\n label: string;\n fill: string;\n stroke: string;\n strokeWidth: number;\n color: string;\n fontSize: number;\n /**\n * Optional secondary line rendered under the bold title, in a muted color.\n * Used by imported Archify diagrams to reproduce the two-line card look\n * (e.g. \"API Gateway\" / \"public :443\").\n */\n sublabel?: string;\n /** Muted color for `sublabel`; falls back to a dimmed label color. */\n sublabelColor?: string;\n /**\n * Optional short pill rendered in a corner of the node (e.g. a tag such as\n * \"SEV-1/2\" or a lifecycle step number). Cosmetic only.\n */\n tag?: string;\n /** Tag pill text/border color. Falls back to the node stroke color. */\n tagColor?: string;\n /** Which corner the tag pill sits in. Defaults to `top-right`. */\n tagPlacement?: FlowTagPlacement;\n /**\n * Label/font color. When unset, falls back to `color` (legacy behavior where\n * a single color drove both the label and the SVG icon tint).\n */\n labelColor?: string;\n /**\n * Label placement for ordinary shape nodes (9-way). When unset the label is\n * centered. Fine-tune with `labelOffsetX` / `labelOffsetY`.\n */\n textPlacement?: FlowTextPlacement;\n borderStyle?: FlowBorderStyle;\n rotation?: number;\n flipX?: boolean;\n flipY?: boolean;\n fillGradientTo?: string;\n fillGradientDirection?: GradientDirection;\n attributes?: FlowNodeAttribute[];\n childCanvasId?: string;\n isGroup?: boolean;\n groupBorderStyle?: FlowBorderStyle;\n groupLabelPlacement?: FlowGroupLabelPlacement;\n groupLabelAlign?: FlowGroupLabelAlign;\n groupLabelFill?: string;\n groupLabelRotation?: 0 | 90 | 180 | 270;\n groupLabelBgMode?: 'text' | 'full';\n dividerOrientation?: 'horizontal' | 'vertical';\n arrowDouble?: boolean;\n arrowBent?: boolean;\n arrowBendX?: number;\n arrowBendY?: number;\n polylineWaypoints?: Array<{ x: number; y: number }>;\n /** SVG stamp icon id (for type 'shapeSvg'). */\n svgId?: string;\n /** Whether the SVG stamp draws a bordered box around the icon. */\n iconBox?: boolean;\n /** Label placement for SVG stamps. Left/right use top-to-bottom vertical text. */\n labelPlacement?: FlowIconLabelPlacement;\n /** Horizontal offset from the resolved icon label position, in canvas units. */\n labelOffsetX?: number;\n /** Vertical offset from the resolved icon label position, in canvas units. */\n labelOffsetY?: number;\n /** Media node kind (for type 'mediaNode'). */\n mediaKind?: FlowMediaKind;\n /** Source content or URL for the media node. */\n mediaContent?: string;\n /** Explicit model format for 3D media nodes. */\n modelFormat?: FlowModelFormat;\n /** AI media node configuration (serializable subset; secrets are runtime-only). */\n aiConfig?: FlowAIConfig;\n /** Data node configuration (for type 'mediaNode' with mediaKind 'data'). */\n dataConfig?: FlowDataConfig;\n /**\n * Stable creation index for `animAnchor` nodes, used to order slides. The\n * displayed sequence badge is derived from this ordering, so deleting an\n * anchor renumbers the rest automatically.\n */\n animIndex?: number;\n /** Marks nodes managed by Mindmap mode. */\n isMindMapNode?: boolean;\n /** Logical parent used by Mindmap auto-layout (separate from visual groups). */\n mindMapParentId?: string;\n}\n\n/** A flow node */\nexport interface FlowNode {\n id: string;\n type: FlowShapeType;\n position: { x: number; y: number };\n width: number;\n height: number;\n data: FlowNodeData;\n parentId?: string;\n zIndex?: number;\n}\n\n/** A flow edge (connection between nodes) */\nexport interface FlowEdge {\n id: string;\n source: string;\n target: string;\n sourceHandle?: string;\n targetHandle?: string;\n type: FlowEdgeTypeName;\n data: FlowEdgeData;\n}\n\n/** Independent line types */\nexport type FlowLineType = 'freehand' | 'straight' | 'polyline' | 'arrow';\n\n/** An independent line not attached to nodes */\nexport interface FlowLine {\n id: string;\n type: FlowLineType;\n points: Array<{ x: number; y: number }>;\n strokeColor: string;\n strokeWidth: number;\n lineStyle: FlowEdgeLineStyle;\n dashDensity?: FlowEdgeDashDensity;\n markerStart?: FlowEdgeMarkerKind;\n markerEnd?: FlowEdgeMarkerKind;\n closed?: boolean;\n zIndex?: number;\n parentId?: string;\n}\n\n/** Single canvas layer data */\nexport interface FlowCanvasData {\n nodes: FlowNode[];\n edges: FlowEdge[];\n lines: FlowLine[];\n}\n\n/** Multi-canvas document; root canvas id is 'root' */\nexport interface FlowDocument {\n canvases: Record<string, FlowCanvasData>;\n stack: string[];\n /** Project title, shown in the editable title bar and used as export filename. */\n title?: string;\n}\n\n/** Active tool modes */\nexport type FlowToolMode =\n | 'select'\n | 'pan'\n | 'connect'\n | 'freehand'\n | 'line'\n | 'polyline'\n | 'arrow';\n\n/** Viewport transform state */\nexport interface ViewportState {\n x: number;\n y: number;\n zoom: number;\n}\n\n/** Selection state */\nexport interface SelectionState {\n nodeIds: Set<string>;\n edgeIds: Set<string>;\n lineIds: Set<string>;\n}\n\n/** Props for the Flow component */\nexport interface FlowProps {\n /** Initial document; if not provided, starts with empty doc */\n initialDocument?: FlowDocument;\n /** Callback when document changes */\n onChange?: (doc: FlowDocument) => void;\n /** Width of the component (defaults to 100%) */\n width?: number | string;\n /** Height of the component (defaults to 100%) */\n height?: number | string;\n /** Whether the flow is read-only */\n readOnly?: boolean;\n /** Leave the current document from the built-in toolbar. */\n onBack?: () => void;\n /** Export the current canvas as PNG from the built-in toolbar. */\n onExportPNG?: () => void | Promise<void>;\n /** Publish or configure sharing from the built-in toolbar. */\n onPublish?: () => void;\n /** Show minimap */\n showMiniMap?: boolean;\n /** Show grid */\n showGrid?: boolean;\n /** Grid size in pixels */\n gridSize?: number;\n /** CSS class for outer container */\n className?: string;\n /**\n * Show the AI assistant panel (right side) that turns a text description or\n * an uploaded image into a flow document. Defaults to true.\n */\n showAI?: boolean;\n /**\n * Show the AI model configuration form inside the AI panel (gateway /\n * protocol / model / api key). When false, the config is hidden and the\n * caller is expected to supply `aiConfig`. Defaults to true.\n */\n showAIConfig?: boolean;\n /** Initial / preset AI model configuration for the AI panel. */\n aiConfig?: FlowAIConfig;\n}\n"],"mappings":"AAgLA,IAAa,IAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF"}
@@ -3,15 +3,16 @@
3
3
  * `var(--color-base-100)` that may use `oklch(...)`) into a concrete sRGB color
4
4
  * for the WebGL canvas.
5
5
  *
6
- * PixiJS needs a numeric/hex color and cannot read CSS variables. We resolve in
7
- * two steps:
8
- * 1. A hidden probe element inherits the themed scope; setting its `color` to
9
- * the requested value and reading `getComputedStyle().color` resolves the
10
- * CSS variable. Note modern browsers return this in the value's ORIGINAL
11
- * color space (e.g. `oklch(...)`), NOT `rgb(...)`.
12
- * 2. Rasterize that resolved string onto a 1x1 canvas and read the pixel back,
13
- * which always yields concrete sRGB bytes regardless of the source color
14
- * space. This is what keeps the Flow canvas in sync with any DishUI theme.
6
+ * PixiJS needs a numeric/hex color and cannot read CSS variables. Resolution:
7
+ * 1. A hidden probe element inherits the themed scope. Its `color` is set to
8
+ * `color-mix(in srgb, <value> 100%, transparent)`, which forces the
9
+ * browser to convert the color into the sRGB space at computed-value
10
+ * time. `getComputedStyle` then serializes it as a plain `rgb(...)` or
11
+ * `color(srgb ...)` string.
12
+ * 2. That string is parsed directly (no canvas). Canvas rasterization is
13
+ * only a last resort: some engines silently reject CSS Color 4 functions
14
+ * (`oklch()`, `lab()`, `color()`) in `fillStyle`, which previously turned
15
+ * every probed theme color black.
15
16
  */
16
17
  /** Resolve a CSS color to a 0xRRGGBB number (for PixiJS). */
17
18
  export declare function cssColorToNumber(host: HTMLElement | null, cssValue: string, fallback: number): number;
@@ -1,12 +1,12 @@
1
- var o = null;
2
- function m() {
3
- if (o) return o;
1
+ var l = null;
2
+ function d() {
3
+ if (l) return l;
4
4
  if (typeof document > "u") return null;
5
5
  const e = document.createElement("canvas");
6
- return e.width = 1, e.height = 1, o = e.getContext("2d", { willReadFrequently: !0 }), o;
6
+ return e.width = 1, e.height = 1, l = e.getContext("2d", { willReadFrequently: !0 }), l;
7
7
  }
8
8
  function v(e) {
9
- const r = m();
9
+ const r = d();
10
10
  if (!r) return null;
11
11
  try {
12
12
  r.clearRect(0, 0, 1, 1), r.fillStyle = "#000000", r.fillStyle = e, r.fillRect(0, 0, 1, 1);
@@ -20,34 +20,56 @@ function v(e) {
20
20
  return null;
21
21
  }
22
22
  }
23
- function c(e, r) {
23
+ function o(e) {
24
+ return Math.max(0, Math.min(255, Math.round(e)));
25
+ }
26
+ function h(e) {
27
+ const r = /^rgba?\(\s*([\d.eE+-]+)[\s,]+([\d.eE+-]+)[\s,]+([\d.eE+-]+)/.exec(e);
28
+ if (r) return [
29
+ o(+r[1]),
30
+ o(+r[2]),
31
+ o(+r[3])
32
+ ];
33
+ const t = /^color\(\s*srgb\s+([\d.eE+-]+)\s+([\d.eE+-]+)\s+([\d.eE+-]+)/i.exec(e);
34
+ return t ? [
35
+ o(+t[1] * 255),
36
+ o(+t[2] * 255),
37
+ o(+t[3] * 255)
38
+ ] : null;
39
+ }
40
+ var p = typeof CSS < "u" && typeof CSS.supports == "function" && CSS.supports("color", "color-mix(in srgb, red, blue)");
41
+ function i(e, r) {
24
42
  if (typeof document > "u") return null;
25
43
  try {
26
44
  const t = document.createElement("span");
27
- t.style.position = "absolute", t.style.width = "0", t.style.height = "0", t.style.overflow = "hidden", t.style.pointerEvents = "none", t.style.color = r, (e ?? document.body).appendChild(t);
28
- const n = getComputedStyle(t).color;
29
- return t.remove(), v(n);
45
+ t.style.position = "absolute", t.style.width = "0", t.style.height = "0", t.style.overflow = "hidden", t.style.pointerEvents = "none", (e ?? document.body).appendChild(t);
46
+ const n = /^var\(\s*(--[\w-]+)\s*\)$/.exec(r);
47
+ if (n && !getComputedStyle(t).getPropertyValue(n[1]).trim())
48
+ return t.remove(), null;
49
+ t.style.color = p ? `color-mix(in srgb, ${r} 100%, transparent)` : r;
50
+ const a = getComputedStyle(t).color;
51
+ return t.remove(), h(a) ?? v(a);
30
52
  } catch {
31
53
  return null;
32
54
  }
33
55
  }
34
- function s(e, r, t) {
35
- const n = c(e, r);
56
+ function u(e, r, t) {
57
+ const n = i(e, r);
36
58
  return n ? n[0] << 16 | n[1] << 8 | n[2] : t;
37
59
  }
38
- function a(e, r, t) {
39
- const n = c(e, r);
40
- return n ? "#" + n.map((b) => b.toString(16).padStart(2, "0")).join("") : t;
60
+ function s(e, r, t) {
61
+ const n = i(e, r);
62
+ return n ? "#" + n.map((a) => a.toString(16).padStart(2, "0")).join("") : t;
41
63
  }
42
- function h(e) {
64
+ function g(e) {
43
65
  return {
44
- background: s(e, "var(--color-base-200)", 16316922),
45
- gridDot: s(e, "var(--color-base-content)", 13751771),
46
- nodeFill: a(e, "var(--color-base-100)", "#ffffff"),
47
- nodeText: a(e, "var(--color-base-content)", "#111827")
66
+ background: u(e, "var(--color-base-200)", 16316922),
67
+ gridDot: u(e, "var(--color-base-content)", 13751771),
68
+ nodeFill: s(e, "var(--color-base-100)", "#ffffff"),
69
+ nodeText: s(e, "var(--color-base-content)", "#111827")
48
70
  };
49
71
  }
50
- var d = "theme:", l = [
72
+ var y = "theme:", c = [
51
73
  {
52
74
  token: "theme:base-100",
53
75
  cssVar: "var(--color-base-100)",
@@ -108,16 +130,16 @@ var d = "theme:", l = [
108
130
  cssVar: "var(--color-error)",
109
131
  label: "Error"
110
132
  }
111
- ], u = new Map(l.map((e) => [e.token, e.cssVar])), p = new Map(l.map((e) => [e.token, e.label])), y = {
133
+ ], f = new Map(c.map((e) => [e.token, e.cssVar])), C = new Map(c.map((e) => [e.token, e.label])), S = {
112
134
  fill: "theme:base-100",
113
135
  stroke: "theme:base-content",
114
136
  text: "theme:base-content",
115
137
  line: "theme:base-content"
116
138
  };
117
- function g(e) {
118
- return u.get(e);
139
+ function E(e) {
140
+ return f.get(e);
119
141
  }
120
- var C = [
142
+ var T = [
121
143
  {
122
144
  value: "#000000",
123
145
  label: "黑"
@@ -159,32 +181,32 @@ var C = [
159
181
  label: "粉"
160
182
  }
161
183
  ];
162
- function i(e) {
184
+ function b(e) {
163
185
  return typeof e == "string" && e.startsWith("theme:");
164
186
  }
165
- var f = /* @__PURE__ */ new Map();
166
- function T(e) {
167
- for (const { token: r, cssVar: t } of l) f.set(r, a(e, t, "#000000"));
187
+ var m = /* @__PURE__ */ new Map();
188
+ function k(e) {
189
+ for (const { token: r, cssVar: t } of c) m.set(r, s(e, t, "#000000"));
168
190
  }
169
- function k(e, r = "#000000") {
170
- return e ? i(e) ? f.get(e) ?? r : e : r;
191
+ function O(e, r = "#000000") {
192
+ return e ? b(e) ? m.get(e) ?? r : e : r;
171
193
  }
172
- function E(e, r = "#000000") {
173
- return e ? i(e) ? u.get(e) ?? r : e : r;
194
+ function V(e, r = "#000000") {
195
+ return e ? b(e) ? f.get(e) ?? r : e : r;
174
196
  }
175
197
  export {
176
- C as COMMON_COLORS,
177
- d as THEME_COLOR_PREFIX,
178
- l as THEME_COLOR_TOKENS,
179
- y as THEME_SYNC_TOKEN,
180
- a as cssColorToHexString,
181
- s as cssColorToNumber,
182
- i as isThemeToken,
183
- T as refreshThemePalette,
184
- h as resolveFlowThemeColors,
185
- k as resolveThemeColor,
186
- E as resolveThemeColorCss,
187
- g as themeTokenCssVar
198
+ T as COMMON_COLORS,
199
+ y as THEME_COLOR_PREFIX,
200
+ c as THEME_COLOR_TOKENS,
201
+ S as THEME_SYNC_TOKEN,
202
+ s as cssColorToHexString,
203
+ u as cssColorToNumber,
204
+ b as isThemeToken,
205
+ k as refreshThemePalette,
206
+ g as resolveFlowThemeColors,
207
+ O as resolveThemeColor,
208
+ V as resolveThemeColorCss,
209
+ E as themeTokenCssVar
188
210
  };
189
211
 
190
212
  //# sourceMappingURL=themeColor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"themeColor.js","names":[],"sources":["../../../../../src/components/pro/Flow/utils/themeColor.ts"],"sourcesContent":["/**\n * Resolve a CSS color value (including theme custom properties like\n * `var(--color-base-100)` that may use `oklch(...)`) into a concrete sRGB color\n * for the WebGL canvas.\n *\n * PixiJS needs a numeric/hex color and cannot read CSS variables. We resolve in\n * two steps:\n * 1. A hidden probe element inherits the themed scope; setting its `color` to\n * the requested value and reading `getComputedStyle().color` resolves the\n * CSS variable. Note modern browsers return this in the value's ORIGINAL\n * color space (e.g. `oklch(...)`), NOT `rgb(...)`.\n * 2. Rasterize that resolved string onto a 1x1 canvas and read the pixel back,\n * which always yields concrete sRGB bytes regardless of the source color\n * space. This is what keeps the Flow canvas in sync with any DishUI theme.\n */\n\nlet _rasterCtx: CanvasRenderingContext2D | null = null;\nfunction getRasterCtx(): CanvasRenderingContext2D | null {\n if (_rasterCtx) return _rasterCtx;\n if (typeof document === 'undefined') return null;\n const canvas = document.createElement('canvas');\n canvas.width = 1;\n canvas.height = 1;\n _rasterCtx = canvas.getContext('2d', { willReadFrequently: true });\n return _rasterCtx;\n}\n\n/** Rasterize any CSS color string to concrete sRGB bytes. */\nfunction rasterizeColor(cssColor: string): [number, number, number] | null {\n const ctx = getRasterCtx();\n if (!ctx) return null;\n try {\n ctx.clearRect(0, 0, 1, 1);\n ctx.fillStyle = '#000000';\n ctx.fillStyle = cssColor; // ignored if the browser can't parse it\n ctx.fillRect(0, 0, 1, 1);\n const { data } = ctx.getImageData(0, 0, 1, 1);\n return [data[0], data[1], data[2]];\n } catch {\n return null;\n }\n}\n\nfunction parseRgb(host: HTMLElement | null, cssValue: string): [number, number, number] | null {\n if (typeof document === 'undefined') return null;\n try {\n const probe = document.createElement('span');\n // Keep out of layout without `display:none` so `color` still resolves.\n probe.style.position = 'absolute';\n probe.style.width = '0';\n probe.style.height = '0';\n probe.style.overflow = 'hidden';\n probe.style.pointerEvents = 'none';\n probe.style.color = cssValue;\n (host ?? document.body).appendChild(probe);\n const resolved = getComputedStyle(probe).color;\n probe.remove();\n // `resolved` may be `oklch(...)`, `color(...)`, `rgb(...)`, etc. Rasterize\n // it to get concrete sRGB bytes rather than guessing at the components.\n return rasterizeColor(resolved);\n } catch {\n return null;\n }\n}\n\n/** Resolve a CSS color to a 0xRRGGBB number (for PixiJS). */\nexport function cssColorToNumber(host: HTMLElement | null, cssValue: string, fallback: number): number {\n const rgb = parseRgb(host, cssValue);\n if (!rgb) return fallback;\n return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];\n}\n\n/** Resolve a CSS color to a `#rrggbb` string (for persisted node data). */\nexport function cssColorToHexString(host: HTMLElement | null, cssValue: string, fallback: string): string {\n const rgb = parseRgb(host, cssValue);\n if (!rgb) return fallback;\n return '#' + rgb.map((c) => c.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * The colors the Flow canvas derives from the active theme:\n * - `background`: the canvas backdrop, follows the theme's muted background.\n * - `gridDot`: grid dots, derived from the theme foreground color.\n * - `nodeFill`: default fill for new shapes, follows the theme base background.\n */\nexport interface FlowThemeColors {\n background: number;\n gridDot: number;\n nodeFill: string;\n nodeText: string;\n}\n\nexport function resolveFlowThemeColors(host: HTMLElement | null): FlowThemeColors {\n return {\n background: cssColorToNumber(host, 'var(--color-base-200)', 0xf8f9fa),\n gridDot: cssColorToNumber(host, 'var(--color-base-content)', 0xd1d5db),\n nodeFill: cssColorToHexString(host, 'var(--color-base-100)', '#ffffff'),\n nodeText: cssColorToHexString(host, 'var(--color-base-content)', '#111827'),\n };\n}\n\n/* ============================================================================\n * Theme color tokens\n *\n * Node/edge colors may be stored either as a literal color (`#rrggbb`,\n * `transparent`, …) or as a THEME TOKEN of the form `theme:<name>` (e.g.\n * `theme:base-100`). Theme tokens are resolved to the live theme color at\n * render time, so shapes that use them re-color automatically whenever the\n * DishUI theme changes. These tokens are the default colors for new shapes.\n * ========================================================================== */\n\nexport const THEME_COLOR_PREFIX = 'theme:';\n\n/** A selectable theme color, shown as a swatch in the inspector. */\nexport interface ThemeColorToken {\n /** Stored value, e.g. `theme:base-100`. */\n token: string;\n /** CSS custom property backing the token. */\n cssVar: string;\n /** Short label for the inspector tooltip. */\n label: string;\n}\n\n/** The theme colors offered as presets/defaults for Flow color fields. */\nexport const THEME_COLOR_TOKENS: ThemeColorToken[] = [\n { token: 'theme:base-100', cssVar: 'var(--color-base-100)', label: 'Base 100' },\n { token: 'theme:base-200', cssVar: 'var(--color-base-200)', label: 'Base 200' },\n { token: 'theme:base-300', cssVar: 'var(--color-base-300)', label: 'Base 300' },\n { token: 'theme:base-content', cssVar: 'var(--color-base-content)', label: 'Base Content' },\n { token: 'theme:primary', cssVar: 'var(--color-primary)', label: 'Primary' },\n { token: 'theme:secondary', cssVar: 'var(--color-secondary)', label: 'Secondary' },\n { token: 'theme:accent', cssVar: 'var(--color-accent)', label: 'Accent' },\n { token: 'theme:neutral', cssVar: 'var(--color-neutral)', label: 'Neutral' },\n { token: 'theme:info', cssVar: 'var(--color-info)', label: 'Info' },\n { token: 'theme:success', cssVar: 'var(--color-success)', label: 'Success' },\n { token: 'theme:warning', cssVar: 'var(--color-warning)', label: 'Warning' },\n { token: 'theme:error', cssVar: 'var(--color-error)', label: 'Error' },\n];\n\nconst TOKEN_TO_CSSVAR = new Map(THEME_COLOR_TOKENS.map((t) => [t.token, t.cssVar]));\nconst TOKEN_TO_LABEL = new Map(THEME_COLOR_TOKENS.map((t) => [t.token, t.label]));\n\n/**\n * The \"follow theme\" default token for each color field type. Each field syncs\n * to a theme role so shapes stay legible against the canvas:\n * - `fill` -> theme background (base-100)\n * - `stroke` -> theme font color (base-content) — a visible outline\n * - `text` -> theme font color (base-content)\n * - `line` -> theme font color (base-content) — lines/edges\n */\nexport type ThemeColorFieldKind = 'fill' | 'stroke' | 'text' | 'line';\n\nexport const THEME_SYNC_TOKEN: Record<ThemeColorFieldKind, string> = {\n fill: 'theme:base-100',\n stroke: 'theme:base-content',\n text: 'theme:base-content',\n line: 'theme:base-content',\n};\n\n/** The CSS var backing a given theme token (for live-updating DOM swatches). */\nexport function themeTokenCssVar(token: string): string | undefined {\n return TOKEN_TO_CSSVAR.get(token);\n}\n\n/** Human label for a theme token (for tooltips). */\nexport function themeTokenLabel(token: string): string | undefined {\n return TOKEN_TO_LABEL.get(token);\n}\n\n/**\n * Common named colors offered after the theme-sync swatch: a compact rainbow\n * plus black/white. Order follows 黑白赤橙黄绿青蓝紫粉 (black, white, red,\n * orange, yellow, green, cyan, blue, purple, pink).\n */\nexport interface NamedColor {\n value: string;\n /** Chinese label shown on hover. */\n label: string;\n}\n\nexport const COMMON_COLORS: NamedColor[] = [\n { value: '#000000', label: '黑' },\n { value: '#ffffff', label: '白' },\n { value: '#ef4444', label: '赤' },\n { value: '#f97316', label: '橙' },\n { value: '#eab308', label: '黄' },\n { value: '#22c55e', label: '绿' },\n { value: '#06b6d4', label: '青' },\n { value: '#3b82f6', label: '蓝' },\n { value: '#8b5cf6', label: '紫' },\n { value: '#ec4899', label: '粉' },\n];\n\n/** True when `value` is a `theme:*` token. */\nexport function isThemeToken(value: string | undefined | null): value is string {\n return typeof value === 'string' && value.startsWith(THEME_COLOR_PREFIX);\n}\n\n// Module-level cache of the currently resolved token -> `#rrggbb` mapping. The\n// render loop resolves tokens against this cache (cheap, synchronous) instead\n// of probing the DOM every frame. `refreshThemePalette` rebuilds it whenever\n// the theme changes.\nconst _palette = new Map<string, string>();\n\n/**\n * Re-resolve every theme token against the given host's themed scope and cache\n * the results. Call on init and whenever the active theme changes.\n */\nexport function refreshThemePalette(host: HTMLElement | null): void {\n for (const { token, cssVar } of THEME_COLOR_TOKENS) {\n _palette.set(token, cssColorToHexString(host, cssVar, '#000000'));\n }\n}\n\n/**\n * Resolve a stored color value to a concrete `#rrggbb`/literal color. Theme\n * tokens are looked up in the cached palette; anything else is returned as-is.\n */\nexport function resolveThemeColor(value: string | undefined | null, fallback = '#000000'): string {\n if (!value) return fallback;\n if (isThemeToken(value)) return _palette.get(value) ?? fallback;\n return value;\n}\n\n/**\n * Resolve a stored color to a value usable directly in the DOM. Theme tokens\n * map to their CSS variable so the browser tracks theme changes natively.\n */\nexport function resolveThemeColorCss(value: string | undefined | null, fallback = '#000000'): string {\n if (!value) return fallback;\n if (isThemeToken(value)) return TOKEN_TO_CSSVAR.get(value) ?? fallback;\n return value;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"themeColor.js","names":[],"sources":["../../../../../src/components/pro/Flow/utils/themeColor.ts"],"sourcesContent":["/**\n * Resolve a CSS color value (including theme custom properties like\n * `var(--color-base-100)` that may use `oklch(...)`) into a concrete sRGB color\n * for the WebGL canvas.\n *\n * PixiJS needs a numeric/hex color and cannot read CSS variables. Resolution:\n * 1. A hidden probe element inherits the themed scope. Its `color` is set to\n * `color-mix(in srgb, <value> 100%, transparent)`, which forces the\n * browser to convert the color into the sRGB space at computed-value\n * time. `getComputedStyle` then serializes it as a plain `rgb(...)` or\n * `color(srgb ...)` string.\n * 2. That string is parsed directly (no canvas). Canvas rasterization is\n * only a last resort: some engines silently reject CSS Color 4 functions\n * (`oklch()`, `lab()`, `color()`) in `fillStyle`, which previously turned\n * every probed theme color black.\n */\n\nlet _rasterCtx: CanvasRenderingContext2D | null = null;\nfunction getRasterCtx(): CanvasRenderingContext2D | null {\n if (_rasterCtx) return _rasterCtx;\n if (typeof document === 'undefined') return null;\n const canvas = document.createElement('canvas');\n canvas.width = 1;\n canvas.height = 1;\n _rasterCtx = canvas.getContext('2d', { willReadFrequently: true });\n return _rasterCtx;\n}\n\n/** Rasterize any CSS color string to concrete sRGB bytes. */\nfunction rasterizeColor(cssColor: string): [number, number, number] | null {\n const ctx = getRasterCtx();\n if (!ctx) return null;\n try {\n ctx.clearRect(0, 0, 1, 1);\n ctx.fillStyle = '#000000';\n ctx.fillStyle = cssColor; // ignored if the browser can't parse it\n ctx.fillRect(0, 0, 1, 1);\n const { data } = ctx.getImageData(0, 0, 1, 1);\n return [data[0], data[1], data[2]];\n } catch {\n return null;\n }\n}\n\nfunction byte(v: number): number {\n return Math.max(0, Math.min(255, Math.round(v)));\n}\n\n/**\n * Parse the sRGB strings a browser serializes a computed color to when the\n * color was forced into the sRGB space: `rgb(...)` / `rgba(...)` (0-255\n * channels) or `color(srgb r g b / a)` (0-1 float channels).\n */\nfunction parseSrgbString(value: string): [number, number, number] | null {\n const rgb = /^rgba?\\(\\s*([\\d.eE+-]+)[\\s,]+([\\d.eE+-]+)[\\s,]+([\\d.eE+-]+)/.exec(value);\n if (rgb) return [byte(+rgb[1]), byte(+rgb[2]), byte(+rgb[3])];\n const fn = /^color\\(\\s*srgb\\s+([\\d.eE+-]+)\\s+([\\d.eE+-]+)\\s+([\\d.eE+-]+)/i.exec(value);\n if (fn) return [byte(+fn[1] * 255), byte(+fn[2] * 255), byte(+fn[3] * 255)];\n return null;\n}\n\n/** Whether the browser computes color-mix() (used to force sRGB output). */\nconst SUPPORTS_COLOR_MIX =\n typeof CSS !== 'undefined' &&\n typeof CSS.supports === 'function' &&\n CSS.supports('color', 'color-mix(in srgb, red, blue)');\n\nfunction parseRgb(host: HTMLElement | null, cssValue: string): [number, number, number] | null {\n if (typeof document === 'undefined') return null;\n try {\n const probe = document.createElement('span');\n // Keep out of layout without `display:none` so `color` still resolves.\n probe.style.position = 'absolute';\n probe.style.width = '0';\n probe.style.height = '0';\n probe.style.overflow = 'hidden';\n probe.style.pointerEvents = 'none';\n (host ?? document.body).appendChild(probe);\n // Bail out when the requested custom property is undefined in this scope:\n // var() would invalidate the declaration and the probe would report its\n // inherited text color instead of the theme color.\n const varMatch = /^var\\(\\s*(--[\\w-]+)\\s*\\)$/.exec(cssValue);\n if (varMatch && !getComputedStyle(probe).getPropertyValue(varMatch[1]).trim()) {\n probe.remove();\n return null;\n }\n // Force the resolved color into the sRGB space at computed-value time, so\n // the serialized result is a plain rgb()/color(srgb) string we can parse\n // ourselves. Do NOT rasterize oklch()/lab() via canvas fillStyle here:\n // some engines (e.g. WebKit) silently reject CSS Color 4 functions in\n // canvas, which used to turn every probed theme color black.\n probe.style.color = SUPPORTS_COLOR_MIX\n ? `color-mix(in srgb, ${cssValue} 100%, transparent)`\n : cssValue;\n const resolved = getComputedStyle(probe).color;\n probe.remove();\n return parseSrgbString(resolved) ?? rasterizeColor(resolved);\n } catch {\n return null;\n }\n}\n\n/** Resolve a CSS color to a 0xRRGGBB number (for PixiJS). */\nexport function cssColorToNumber(host: HTMLElement | null, cssValue: string, fallback: number): number {\n const rgb = parseRgb(host, cssValue);\n if (!rgb) return fallback;\n return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];\n}\n\n/** Resolve a CSS color to a `#rrggbb` string (for persisted node data). */\nexport function cssColorToHexString(host: HTMLElement | null, cssValue: string, fallback: string): string {\n const rgb = parseRgb(host, cssValue);\n if (!rgb) return fallback;\n return '#' + rgb.map((c) => c.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * The colors the Flow canvas derives from the active theme:\n * - `background`: the canvas backdrop, follows the theme's muted background.\n * - `gridDot`: grid dots, derived from the theme foreground color.\n * - `nodeFill`: default fill for new shapes, follows the theme base background.\n */\nexport interface FlowThemeColors {\n background: number;\n gridDot: number;\n nodeFill: string;\n nodeText: string;\n}\n\nexport function resolveFlowThemeColors(host: HTMLElement | null): FlowThemeColors {\n return {\n background: cssColorToNumber(host, 'var(--color-base-200)', 0xf8f9fa),\n gridDot: cssColorToNumber(host, 'var(--color-base-content)', 0xd1d5db),\n nodeFill: cssColorToHexString(host, 'var(--color-base-100)', '#ffffff'),\n nodeText: cssColorToHexString(host, 'var(--color-base-content)', '#111827'),\n };\n}\n\n/* ============================================================================\n * Theme color tokens\n *\n * Node/edge colors may be stored either as a literal color (`#rrggbb`,\n * `transparent`, …) or as a THEME TOKEN of the form `theme:<name>` (e.g.\n * `theme:base-100`). Theme tokens are resolved to the live theme color at\n * render time, so shapes that use them re-color automatically whenever the\n * DishUI theme changes. These tokens are the default colors for new shapes.\n * ========================================================================== */\n\nexport const THEME_COLOR_PREFIX = 'theme:';\n\n/** A selectable theme color, shown as a swatch in the inspector. */\nexport interface ThemeColorToken {\n /** Stored value, e.g. `theme:base-100`. */\n token: string;\n /** CSS custom property backing the token. */\n cssVar: string;\n /** Short label for the inspector tooltip. */\n label: string;\n}\n\n/** The theme colors offered as presets/defaults for Flow color fields. */\nexport const THEME_COLOR_TOKENS: ThemeColorToken[] = [\n { token: 'theme:base-100', cssVar: 'var(--color-base-100)', label: 'Base 100' },\n { token: 'theme:base-200', cssVar: 'var(--color-base-200)', label: 'Base 200' },\n { token: 'theme:base-300', cssVar: 'var(--color-base-300)', label: 'Base 300' },\n { token: 'theme:base-content', cssVar: 'var(--color-base-content)', label: 'Base Content' },\n { token: 'theme:primary', cssVar: 'var(--color-primary)', label: 'Primary' },\n { token: 'theme:secondary', cssVar: 'var(--color-secondary)', label: 'Secondary' },\n { token: 'theme:accent', cssVar: 'var(--color-accent)', label: 'Accent' },\n { token: 'theme:neutral', cssVar: 'var(--color-neutral)', label: 'Neutral' },\n { token: 'theme:info', cssVar: 'var(--color-info)', label: 'Info' },\n { token: 'theme:success', cssVar: 'var(--color-success)', label: 'Success' },\n { token: 'theme:warning', cssVar: 'var(--color-warning)', label: 'Warning' },\n { token: 'theme:error', cssVar: 'var(--color-error)', label: 'Error' },\n];\n\nconst TOKEN_TO_CSSVAR = new Map(THEME_COLOR_TOKENS.map((t) => [t.token, t.cssVar]));\nconst TOKEN_TO_LABEL = new Map(THEME_COLOR_TOKENS.map((t) => [t.token, t.label]));\n\n/**\n * The \"follow theme\" default token for each color field type. Each field syncs\n * to a theme role so shapes stay legible against the canvas:\n * - `fill` -> theme background (base-100)\n * - `stroke` -> theme font color (base-content) — a visible outline\n * - `text` -> theme font color (base-content)\n * - `line` -> theme font color (base-content) — lines/edges\n */\nexport type ThemeColorFieldKind = 'fill' | 'stroke' | 'text' | 'line';\n\nexport const THEME_SYNC_TOKEN: Record<ThemeColorFieldKind, string> = {\n fill: 'theme:base-100',\n stroke: 'theme:base-content',\n text: 'theme:base-content',\n line: 'theme:base-content',\n};\n\n/** The CSS var backing a given theme token (for live-updating DOM swatches). */\nexport function themeTokenCssVar(token: string): string | undefined {\n return TOKEN_TO_CSSVAR.get(token);\n}\n\n/** Human label for a theme token (for tooltips). */\nexport function themeTokenLabel(token: string): string | undefined {\n return TOKEN_TO_LABEL.get(token);\n}\n\n/**\n * Common named colors offered after the theme-sync swatch: a compact rainbow\n * plus black/white. Order follows 黑白赤橙黄绿青蓝紫粉 (black, white, red,\n * orange, yellow, green, cyan, blue, purple, pink).\n */\nexport interface NamedColor {\n value: string;\n /** Chinese label shown on hover. */\n label: string;\n}\n\nexport const COMMON_COLORS: NamedColor[] = [\n { value: '#000000', label: '黑' },\n { value: '#ffffff', label: '白' },\n { value: '#ef4444', label: '赤' },\n { value: '#f97316', label: '橙' },\n { value: '#eab308', label: '黄' },\n { value: '#22c55e', label: '绿' },\n { value: '#06b6d4', label: '青' },\n { value: '#3b82f6', label: '蓝' },\n { value: '#8b5cf6', label: '紫' },\n { value: '#ec4899', label: '粉' },\n];\n\n/** True when `value` is a `theme:*` token. */\nexport function isThemeToken(value: string | undefined | null): value is string {\n return typeof value === 'string' && value.startsWith(THEME_COLOR_PREFIX);\n}\n\n// Module-level cache of the currently resolved token -> `#rrggbb` mapping. The\n// render loop resolves tokens against this cache (cheap, synchronous) instead\n// of probing the DOM every frame. `refreshThemePalette` rebuilds it whenever\n// the theme changes.\nconst _palette = new Map<string, string>();\n\n/**\n * Re-resolve every theme token against the given host's themed scope and cache\n * the results. Call on init and whenever the active theme changes.\n */\nexport function refreshThemePalette(host: HTMLElement | null): void {\n for (const { token, cssVar } of THEME_COLOR_TOKENS) {\n _palette.set(token, cssColorToHexString(host, cssVar, '#000000'));\n }\n}\n\n/**\n * Resolve a stored color value to a concrete `#rrggbb`/literal color. Theme\n * tokens are looked up in the cached palette; anything else is returned as-is.\n */\nexport function resolveThemeColor(value: string | undefined | null, fallback = '#000000'): string {\n if (!value) return fallback;\n if (isThemeToken(value)) return _palette.get(value) ?? fallback;\n return value;\n}\n\n/**\n * Resolve a stored color to a value usable directly in the DOM. Theme tokens\n * map to their CSS variable so the browser tracks theme changes natively.\n */\nexport function resolveThemeColorCss(value: string | undefined | null, fallback = '#000000'): string {\n if (!value) return fallback;\n if (isThemeToken(value)) return TOKEN_TO_CSSVAR.get(value) ?? fallback;\n return value;\n}\n"],"mappings":"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"}