@beehexa/vueflow-tokens 2611.6.1 → 2611.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,47 +24,110 @@ host/dimension changes. The factory uses VueFlow 1's real `fitViewOnInit` option
24
24
 
25
25
  ## Public contracts
26
26
 
27
- - `createVueFlowTheme({ dark?, locale? })`: scoped source variables, real VueFlow
28
- viewport settings, background and minimap bindings.
29
- - `NodeType`, `NODE_DIMENSIONS`, `GRID_SPACING`, `TASK_DATA_LAYOUT`: source-backed
30
- fixed geometry shared by renderers and graph layout. Do not recreate these tables.
31
- - `getFlowNodeStyles(type, { hovered?, selected?, selfDependency? })`: typed custom
32
- node body/content/icon/label/connector styles, without decorative motion or gradients.
33
- - `getNodeColorPalette(category)`: CSS-backed paired category roles, live across
34
- theme switches. Categories are task, dependency, transformation, validation,
35
- pushStep, decision, loop and grouped; they identify kinds, never execution status.
36
- - `getNodeColor(type)`, `getEdgeColorPalette(category)`, `styleTargetEdge(edge, nodes)`:
37
- source-backed directed edge identity; target stroke and marker remain paired.
27
+ - `createVueFlowTheme({ dark?, locale?, nodeTone? })`: scoped source variables, real VueFlow
28
+ viewport settings, background and minimap bindings. `nodeTone(node)` picks each MiniMap
29
+ node's tone (`blue`, VueFlow's default-node colour, when omitted).
30
+ - `FLOW_TONES` / `FlowTone`: the generic colour tones `blue`, `red`, `green`, `crimson`,
31
+ `yellow`, `teal`, `magenta` and `purple`. Each tone reads one existing foundation
32
+ `flow.category.*` role set (foundation names unchanged); the package gives a tone no
33
+ meaning, and the consumer owns which of its concepts takes which tone. Tones identify
34
+ kinds, never execution status.
35
+ - `getFlowTonePalette(tone)`: CSS-backed paired tone roles, live across theme switches.
36
+ - `getFlowToneStyles(tone, part?)`: custom content role binding; `foreground` (default)
37
+ sets tone text, `border` sets border colour and `background` sets the tone surface.
38
+ - `getFlowNodeStyles({ tone, width, height, shape? }, { hovered?, selected?, dashed? })`:
39
+ typed custom node body/content/icon/label/logo styles over consumer-owned geometry,
40
+ without decorative motion or gradients. `shape: 'circle'` rounds the body fully.
41
+ - `styleTargetEdge(edge, nodes, toneOf?)`: directed edge identity from the target node's
42
+ tone (`blue` when omitted); target stroke and marker remain paired.
38
43
  - `FLOW_EDGE`, `FLOW_ICON`: numeric source values at VueFlow/icon API boundaries.
39
- - `getFlowCategoryStyles(type, part?)`: custom semantic content role binding;
40
- `foreground` (default) sets category text, `border` sets border colour and
41
- `background` sets the category surface.
42
- - `getFlowIconStyles(type, { size?, color?, disabled? })`: category-border glyphs
44
+ - `getFlowIconStyles(toneOrRole, { size?, color?, disabled? })`: tone-border glyphs
43
45
  or separate `status-success|warning|error|info|loading` / `control-expand|collapse|help`
44
- icon roles. Edge icon keys use `edge-dependency|edge-transformation`.
45
- Sizes accept `small|medium|large` or a numeric API size; explicit colours must
46
- already be source-resolved semantic roles.
47
- - `getFlowEdgeStyles(category, suppliedStyle?)`: SVG width, non-scaling stroke,
48
- no-fill and static relation dashes. The supplied directed target stroke wins
49
- over category fallback, preserving stroke/arrow identity.
50
- - Public option, category, dimension, node-state, style and theme interfaces are emitted
46
+ icon roles. Sizes accept `small|medium|large` or a numeric API size; explicit colours
47
+ must already be source-resolved semantic roles.
48
+ - `getFlowEdgeStyles(tone, suppliedStyle?)`: SVG width, non-scaling stroke and no fill.
49
+ A supplied directed target stroke wins over the tone fallback, and a supplied static
50
+ dash is kept; the consumer owns what a dash means.
51
+ - Public option, tone, node-look, node-state, style and theme interfaces are emitted
51
52
  in `dist/index.d.ts`; CSS has a typed `./css` export.
52
53
 
53
54
  Use public source typography/content markers and graph presentation factories in
54
- custom semantic content. Keep category labels and icons, selected outline, separate
55
- keyboard focus and readable error messages. Do not append hexadecimal alpha suffixes
56
- to CSS variables. Do not animate idle graph nodes, rotate category icons, add
57
- glass/gradients, or override core controls in each consumer.
55
+ custom content. Keep kind labels and icons, selected outline, separate keyboard focus
56
+ and readable error messages. Do not append hexadecimal alpha suffixes to CSS
57
+ variables. Do not animate idle graph nodes, rotate kind icons, add glass/gradients,
58
+ or override core controls in each consumer.
58
59
  Preserve graph IDs, stored coordinates and relationship direction on theme changes.
59
60
  Exports must capture the current graph surface/font rather than force white/system fonts.
60
61
 
62
+ Native `.bh-workflow-canvas` consumers may opt into the `WorkflowEdge.tone` values
63
+ `blue`, `red` and `green`. The companion binds `--wf-edge-tone-<tone>` to the existing
64
+ foundation border roles `--bh-flow-category-task-border`, `-dependency-border` and
65
+ `-transformation-border` (foundation names unchanged), with solid, short-dash (`2 4`) and
66
+ dash-dot (`9 3 2 3`) cues through `--wf-edge-tone-<tone>-dash`. Tone is categorical,
67
+ independent of failure; native stroke/arrowhead, interaction states and jump swatches
68
+ share it. The consumer maps its own relation kinds onto these tones. PNG export reuses
69
+ the native exporter's DOM/stylesheet serialization, with no tone-specific path.
70
+ Omitting tone retains existing native styling. Do not add consumer edge renderers.
71
+
72
+ Possible, context and toned-failure edges keep tone ink and dash in every state;
73
+ their cues are native shapes, never new dashes or opacity. `certainty: 'possible'`
74
+ draws a hollow source-end diamond (BPMN conditional flow). `context: true` draws an
75
+ open arrowhead and the thinner resting stroke `--wf-edge-context-width`, a package-owned
76
+ variable bound to the foundation `border.width.default`. A toned failure keeps its
77
+ tone dash and adds the Lucide `CircleX` mark in `color.icon.danger`
78
+ (`--wf-edge-failure-icon`) beside the label; an untoned failure keeps the failure dash.
79
+ Pass the localized group name as `familyLabel` for `{family} jump to {target}` names,
80
+ and localize the whole name/numbering through the viewer's `texts.jumps` (`WorkflowJumpTexts`).
81
+
82
+ `NodeLook.sizing: 'content'` opts ordinary native cards into intrinsic width:
83
+ minimum `diagram.card.width`, maximum twice that source role. The native theme owns
84
+ only that width rule; this companion owns the roles
85
+ `--wf-node-content-min-width` / `--wf-node-content-max-width` and the presentation
86
+ recipe (title/kind wrap, growing head, logos bounded without hiding any), with no
87
+ declaration duplicated in the native theme. Other cards retain their existing
88
+ fixed sizing; stadium, diamond and ellipse cards ignore the opt-in.
89
+ Native measurement/router and endpoint spreading are unchanged. Light/dark,
90
+ long title/many-logo, interaction and exported-PNG acceptance remains manual.
91
+
92
+ Native group frames (`WorkflowNode.group`, the built-in `wf-group` node) take the
93
+ package-owned `--wf-group-*` variables, each bound to an existing foundation role:
94
+ border `color.border`, border width `border.width.default`, radius `radius.card`, fill
95
+ `color.surface.subtle`, nested fill `color.background.neutral`, padding `space.stack`
96
+ and header gap `space.150`; high contrast draws the border in text ink. No flow-specific
97
+ foundation token backs them. The native layout reads padding and header gap from the
98
+ canvas, so both stay plain lengths.
99
+ Diamond and ellipse titles and kind captions wrap at word boundaries and are never
100
+ truncated (no `overflow-wrap: anywhere`, no ellipsis); only a single word wider than the
101
+ content box breaks. Other cards may still break a long unbroken title anywhere. Frame
102
+ look, toggle and exported-PNG acceptance remain manual.
103
+
104
+ The native Shift + drag selection box takes `--wf-selection-*` from the same selection
105
+ recipe as `.bh-vue-flow .vue-flow__selection`: transparent (no fill, so swept cards stay visible), a
106
+ dashed `border.width.selected` border in `color.border.focus`, in both themes. Its look remains
107
+ manual acceptance.
108
+
109
+ The native find box (`WorkflowFind`, the viewer's `/` search) takes `--wf-find-*` and the
110
+ shared `--wf-list-*` roles: an overlay (`color.surface.overlay`, `elevation.shadow.overlay`,
111
+ `radius.overlay`, no border) with a `color.border` divider under the field. Field and empty
112
+ state `font.body.default` (placeholder `color.text.subtlest`, empty state `color.text.subtle`);
113
+ rows `font.label.default`, `space.075` / `space.item.x` padding, `size.control.default` minimum
114
+ height (`size.target.touch` on coarse pointers and below 768px), `radius.item`; the kind label
115
+ `font.body.small` in `color.text.subtle`; an unnamed node's id `font.code.default`. Names wrap at
116
+ word boundaries, never truncated. Row states: hover `color.surface.overlay.hover`; the
117
+ keyboard-active row `color.surface.overlay.selected` plus the `border.width.selected` /
118
+ `color.border.selected` start bar; that row hovered `color.surface.overlay.selected.hover`.
119
+ Focus is the field ring (`--wf-focus-outline`) around the box. The canvas previews the pointed
120
+ row's node with its hover state and outer ring, without changing selection, trace or viewport.
121
+ The `--wf-list-*` roles also paint the native jump list and dock menu rows. Look and contrast
122
+ in both themes remain manual acceptance.
123
+
61
124
  Ordinary nodes, MiniMap cards and outer Controls/dock frames use `radius.100`
62
125
  (8px). Individual compact control Buttons and menu items retain `radius.050` (4px);
63
126
  floating zoom-menu surfaces use `radius.overlay` (8px), independently of those items.
64
127
  MiniMap fills clip; Controls retain exposed focus rings. Native legend popovers
65
128
  keep `radius.100`, while the native keyboard-shortcuts Dialog uses `radius.150`
66
- (12px), independently of its control Buttons. Connector logos retain nested
67
- `radius.075` (6px). Decision/loop nodes and graph handles keep their circular
129
+ (12px), independently of its control Buttons. Node logos retain nested
130
+ `radius.075` (6px). Circular nodes and graph handles keep their circular
68
131
  geometry; `FLOW_EDGE.radius` remains edge-path geometry. Consumer-owned inspector
69
132
  Cards use `radius.100`; dialogs/drawers use `radius.150`.
70
133
 
@@ -77,18 +140,18 @@ same host for the existing user accessibility settings (1.125em node text;
77
140
  1.6 line-height / 0.02em letter-spacing). These are opt-in adaptations, not new
78
141
  default typography. `bh-flow-icon[data-bh-loading="true"]` animates only an
79
142
  actual loading glyph and respects reduced motion.
80
- `bh-flow-category-mark[data-bh-category="<FlowCategory>"]` is a labelled 6px
81
- circular relationship marker in the category's border role, never a status dot.
143
+ `bh-flow-tone-mark[data-bh-tone="<FlowTone>"]` is a labelled 6px circular
144
+ relationship marker in the tone's border role (`blue` when unset), never a status dot.
82
145
 
83
- For a native category Tag, bind the cached immutable result of
84
- `getFlowCategoryBadgeStyles(type)` to its public `style` prop and omit its
85
- `color` prop. This pairs category foreground, background and border; a frame/edge
86
- stroke from `getNodeColor(type)` is not a filled badge background. Both themes'
146
+ For a native kind Tag, bind the cached immutable result of
147
+ `getFlowToneBadgeStyles(tone)` to its public `style` prop and omit its `color` prop.
148
+ This pairs tone foreground, background and border; a frame/edge stroke from
149
+ `getFlowTonePalette(tone).border` is not a filled badge background. Both themes'
87
150
  small-text pairs are checked at WCAG AA 4.5:1 and demonstrated with real native
88
- Tags in the Ant Design Vue family. Category labels are not execution status.
151
+ Tags in the Ant Design Vue family. Tones are not execution status.
89
152
 
90
- Resting handles use the neutral icon role, not keyboard-focus color. TaskFlow-style
91
- graph fullscreen uses an isolated local stacking context at `z-index.modal` (400), allowing
153
+ Resting handles use the neutral icon role, not keyboard-focus color. Graph
154
+ fullscreen uses an isolated local stacking context at `z-index.modal` (400), allowing
92
155
  global inspectors above it. Child chrome may use private z10/z15 within that context,
93
156
  not global1001/1002. Editor takeovers use the same `z-index.modal` layer.
94
157
 
@@ -97,10 +160,10 @@ not global1001/1002. Editor takeovers use the same `z-index.modal` layer.
97
160
  The shared `build-runtime-packages.mjs` compiles strict NodeNext source and checks generated
98
161
  output. Actual packed-consumer checks exercise exports/CSS with strict TypeScript and
99
162
  `skipLibCheck` at the upstream vendor-declaration boundary. Source version `0.0.0`
100
- stays private; only the authorized runner stamps real package/internal dependency versions.
163
+ stays private; only the authorized runner stamps real versions for this package and its internal requirements.
101
164
 
102
165
  Full authored guidance lives in `src/content/tools/vueflow.mdx` and ships through
103
166
  `@beehexa/design-rules`. Verify real light/dark and English/Vietnamese surfaces,
104
- contrast, all fixed dimensions, long labels, selection/focus/error, target-coloured
167
+ contrast, consumer-owned dimensions, long labels, selection/focus/error, target-coloured
105
168
  markers, controls/minimap, zoom/snap/fit, expanded/cyclic graphs, fullscreen/ESC and PNG
106
169
  export. Typed configuration is not visual or accessibility proof.
package/dist/index.d.ts CHANGED
@@ -1,61 +1,25 @@
1
1
  import type { CSSProperties } from 'vue';
2
2
  import { type FlowProps, type Node, type Edge, type Styles } from '@vue-flow/core';
3
+ /**
4
+ * Generic colour tones. Each tone reads one existing foundation `flow.category.<key>` role set;
5
+ * the foundation keys keep their names and the package gives a tone no domain meaning. The
6
+ * consumer decides which of its own concepts takes which tone.
7
+ */
8
+ export declare const FLOW_TONES: readonly ["blue", "red", "green", "crimson", "yellow", "teal", "magenta", "purple"];
9
+ export type FlowTone = typeof FLOW_TONES[number];
3
10
  export interface VueFlowThemeOptions {
4
11
  dark?: boolean;
5
12
  locale?: 'en' | 'vi';
13
+ /** Tone of a MiniMap node; `blue` when omitted. */
14
+ nodeTone?: (node: Node) => FlowTone;
6
15
  }
7
- export type FlowCategory = 'task' | 'dependency' | 'transformation' | 'validation' | 'pushStep' | 'decision' | 'loop' | 'grouped';
8
- export type FlowEdgeCategory = 'dependency' | 'transformation' | 'dataFlow' | 'conditional';
9
- export interface FlowNodePalette {
16
+ export interface FlowTonePalette {
10
17
  primary: string;
11
18
  text: string;
12
19
  background: string;
13
20
  border: string;
14
21
  hover: string;
15
- connector: {
16
- bg: string;
17
- border: string;
18
- logoBorder: string;
19
- };
20
- }
21
- export declare enum NodeType {
22
- MAIN_TASK = "task",
23
- TASK_DEPENDENCY = "task_dependency",
24
- TASK_TRANSFORMATION = "task_transformation",
25
- TASK_DATA = "task_data",
26
- TRANSFORMATION_GROUP = "transformationGroup",
27
- VALIDATION_GROUP = "validationGroup",
28
- PUSH_STEPS_GROUP = "pushStepsGroup",
29
- TRANSFORMATION = "transformation",
30
- VALIDATION = "validation",
31
- PUSH_STEP = "push_step",
32
- DECISION = "decision",
33
- LOOP = "loop",
34
- PROFILE = "profile"
35
- }
36
- export interface FlowDimensions {
37
- width: number;
38
- height: number;
39
22
  }
40
- export declare const NODE_DIMENSIONS: Record<NodeType, FlowDimensions>;
41
- export declare const GRID_SPACING: {
42
- readonly HORIZONTAL: number;
43
- readonly VERTICAL: number;
44
- readonly TASK_DATA_X_GAP: number;
45
- readonly GROUP_Y_OFFSET: number;
46
- };
47
- export declare const TASK_DATA_LAYOUT: {
48
- readonly VALIDATION_NODE_Y_GAP: number;
49
- readonly TRANSFORMATION_NODE_Y_GAP: number;
50
- readonly PUSH_STEP_NODE_Y_GAP: number;
51
- readonly PUSH_STEP_NODE_X_GAP: number;
52
- readonly PUSH_STEP_BRANCH_X_GAP: number;
53
- readonly EXPANDED_GROUP_X: number;
54
- readonly EXPANDED_GROUP_Y_START: number;
55
- readonly TREE_LEVEL_Y_GAP: number;
56
- readonly TREE_SIBLING_X_GAP: number;
57
- readonly TREE_MIN_WIDTH: number;
58
- };
59
23
  export declare const FLOW_EDGE: {
60
24
  readonly width: number;
61
25
  readonly marker: number;
@@ -68,24 +32,25 @@ export declare const FLOW_ICON: {
68
32
  readonly large: number;
69
33
  };
70
34
  /** CSS bindings stay reactive to the source theme/locale without rebuilding a graph. */
71
- export declare function getNodeColorPalette(category: FlowCategory): FlowNodePalette;
72
- export declare function getEdgeColorPalette(category: FlowEdgeCategory): FlowNodePalette;
73
- /** Unknown/custom node types retain the task category, matching VueFlow's default node. */
74
- export declare function getNodeColor(type: string): string;
75
- export type FlowCategoryPart = 'foreground' | 'border' | 'background';
76
- /** Apply a category role to custom semantic content without a consumer-owned recipe. */
77
- export declare function getFlowCategoryStyles(type: string, part?: FlowCategoryPart): CSSProperties;
78
- /** Paired native Tag paint; a category stroke is not an on-bold background. */
79
- export declare function getFlowCategoryBadgeStyles(type: string): Readonly<CSSProperties>;
35
+ export declare function getFlowTonePalette(tone: FlowTone): FlowTonePalette;
36
+ export type FlowTonePart = 'foreground' | 'border' | 'background';
37
+ /** Apply a tone role to custom content without a consumer-owned recipe. */
38
+ export declare function getFlowToneStyles(tone: FlowTone, part?: FlowTonePart): CSSProperties;
39
+ /** Paired native Tag paint; a tone stroke is not an on-bold background. */
40
+ export declare function getFlowToneBadgeStyles(tone: FlowTone): Readonly<CSSProperties>;
80
41
  export interface FlowIconOptions {
81
42
  size?: keyof typeof FLOW_ICON | number;
82
43
  color?: string;
83
44
  disabled?: boolean;
84
45
  }
85
- /** Category glyphs and operational/status glyphs retain distinct source roles. */
86
- export declare function getFlowIconStyles(type: string, options?: FlowIconOptions): CSSProperties;
87
- /** Directed target stroke wins over category fallback; dashes communicate relation kind. */
88
- export declare function getFlowEdgeStyles(category: FlowEdgeCategory, suppliedStyle?: CSSProperties): Styles;
46
+ export type FlowIconRole = 'status-success' | 'status-warning' | 'status-error' | 'status-info' | 'status-loading' | 'control-expand' | 'control-collapse' | 'control-help';
47
+ /** Tone glyphs take the tone's border role; status/control glyphs keep their own source roles. */
48
+ export declare function getFlowIconStyles(role: FlowIconRole | FlowTone, options?: FlowIconOptions): CSSProperties;
49
+ /**
50
+ * SVG presentation recipe for a custom edge path. A supplied directed target stroke wins over
51
+ * the tone fallback; a supplied static dash is kept (the consumer owns what a dash means).
52
+ */
53
+ export declare function getFlowEdgeStyles(tone: FlowTone, suppliedStyle?: CSSProperties): Styles;
89
54
  export declare const FLOW_VIEWPORT: {
90
55
  minZoom: number;
91
56
  maxZoom: number;
@@ -109,12 +74,23 @@ export interface VueFlowTheme {
109
74
  }
110
75
  /** Apply to the actual VueFlow host; import the CSS companion after upstream styles. */
111
76
  export declare function createVueFlowTheme(options?: VueFlowThemeOptions): VueFlowTheme;
112
- /** Preserve target identity for both the visible stroke and arrow marker. */
113
- export declare function styleTargetEdge(edge: Edge, nodes: readonly Node[]): Edge;
77
+ /**
78
+ * Preserve target identity for both the visible stroke and arrow marker. `toneOf` resolves the
79
+ * target node's tone (`blue` when omitted, or when the target is missing).
80
+ */
81
+ export declare function styleTargetEdge(edge: Edge, nodes: readonly Node[], toneOf?: (node: Node) => FlowTone): Edge;
82
+ /** A custom node body: its tone and the consumer-owned fixed geometry. */
83
+ export interface FlowNodeLook {
84
+ tone: FlowTone;
85
+ width: number;
86
+ height: number;
87
+ /** `circle` rounds the body fully; `rectangle` (default) uses `radius.100`. */
88
+ shape?: 'rectangle' | 'circle';
89
+ }
114
90
  export interface FlowNodeState {
115
91
  hovered?: boolean;
116
92
  selected?: boolean;
117
- selfDependency?: boolean;
93
+ dashed?: boolean;
118
94
  }
119
95
  export interface FlowNodeStyles {
120
96
  container: Styles;
@@ -123,11 +99,9 @@ export interface FlowNodeStyles {
123
99
  label: CSSProperties;
124
100
  text: CSSProperties;
125
101
  loadingIcon: CSSProperties;
126
- connectorLogo: CSSProperties;
127
- connectorFlow: CSSProperties;
128
- connectorArrow: CSSProperties;
102
+ logo: CSSProperties;
129
103
  }
130
- /** Custom content and layout share fixed source geometry, not viewport-dependent sizing. */
131
- export declare function getFlowNodeStyles(type: NodeType, state?: FlowNodeState): FlowNodeStyles;
104
+ /** Custom content and layout share fixed consumer geometry, not viewport-dependent sizing. */
105
+ export declare function getFlowNodeStyles(look: FlowNodeLook, state?: FlowNodeState): FlowNodeStyles;
132
106
  /** Minimal detail removes costly decoration, never semantic contrast or graph data. */
133
107
  export declare function getFlowDetailStyles(level: 'minimal' | 'basic' | 'detailed', suppliedStyle: Styles): Styles;
package/dist/index.js CHANGED
@@ -1,46 +1,23 @@
1
1
  import { tokens } from '@beehexa/design-tokens';
2
2
  import { MarkerType } from '@vue-flow/core';
3
- export var NodeType;
4
- (function (NodeType) {
5
- NodeType["MAIN_TASK"] = "task";
6
- NodeType["TASK_DEPENDENCY"] = "task_dependency";
7
- NodeType["TASK_TRANSFORMATION"] = "task_transformation";
8
- NodeType["TASK_DATA"] = "task_data";
9
- NodeType["TRANSFORMATION_GROUP"] = "transformationGroup";
10
- NodeType["VALIDATION_GROUP"] = "validationGroup";
11
- NodeType["PUSH_STEPS_GROUP"] = "pushStepsGroup";
12
- NodeType["TRANSFORMATION"] = "transformation";
13
- NodeType["VALIDATION"] = "validation";
14
- NodeType["PUSH_STEP"] = "push_step";
15
- NodeType["DECISION"] = "decision";
16
- NodeType["LOOP"] = "loop";
17
- NodeType["PROFILE"] = "profile";
18
- })(NodeType || (NodeType = {}));
3
+ /**
4
+ * Generic colour tones. Each tone reads one existing foundation `flow.category.<key>` role set;
5
+ * the foundation keys keep their names and the package gives a tone no domain meaning. The
6
+ * consumer decides which of its own concepts takes which tone.
7
+ */
8
+ export const FLOW_TONES = ['blue', 'red', 'green', 'crimson', 'yellow', 'teal', 'magenta', 'purple'];
9
+ /** Tone → existing foundation role set (unchanged foundation names). */
10
+ const toneRoles = {
11
+ blue: 'flow.category.task', red: 'flow.category.dependency', green: 'flow.category.transformation',
12
+ crimson: 'flow.category.validation', yellow: 'flow.category.pushStep', teal: 'flow.category.decision',
13
+ magenta: 'flow.category.loop', purple: 'flow.category.grouped'
14
+ };
15
+ /** VueFlow's default node colour; the fallback tone wherever the consumer supplies none. */
16
+ const DEFAULT_TONE = 'blue';
19
17
  const numberToken = (name) => {
20
18
  const value = tokens.light[name];
21
19
  return Number.parseFloat(value) * (value.endsWith('rem') ? 16 : 1);
22
20
  };
23
- export const NODE_DIMENSIONS = Object.fromEntries(Object.values(NodeType).map(type => [type, {
24
- width: numberToken(`flow.geometry.${type}.width`),
25
- height: numberToken(`flow.geometry.${type}.height`)
26
- }]));
27
- export const GRID_SPACING = {
28
- HORIZONTAL: numberToken('flow.grid.HORIZONTAL'), VERTICAL: numberToken('flow.grid.VERTICAL'),
29
- TASK_DATA_X_GAP: numberToken('flow.grid.TASK_DATA_X_GAP'),
30
- GROUP_Y_OFFSET: numberToken('flow.grid.GROUP_Y_OFFSET')
31
- };
32
- export const TASK_DATA_LAYOUT = {
33
- VALIDATION_NODE_Y_GAP: numberToken('flow.layout.VALIDATION_NODE_Y_GAP'),
34
- TRANSFORMATION_NODE_Y_GAP: numberToken('flow.layout.TRANSFORMATION_NODE_Y_GAP'),
35
- PUSH_STEP_NODE_Y_GAP: numberToken('flow.layout.PUSH_STEP_NODE_Y_GAP'),
36
- PUSH_STEP_NODE_X_GAP: numberToken('flow.layout.PUSH_STEP_NODE_X_GAP'),
37
- PUSH_STEP_BRANCH_X_GAP: numberToken('flow.layout.PUSH_STEP_BRANCH_X_GAP'),
38
- EXPANDED_GROUP_X: numberToken('flow.layout.EXPANDED_GROUP_X'),
39
- EXPANDED_GROUP_Y_START: numberToken('flow.layout.EXPANDED_GROUP_Y_START'),
40
- TREE_LEVEL_Y_GAP: numberToken('flow.layout.TREE_LEVEL_Y_GAP'),
41
- TREE_SIBLING_X_GAP: numberToken('flow.layout.TREE_SIBLING_X_GAP'),
42
- TREE_MIN_WIDTH: numberToken('flow.layout.TREE_MIN_WIDTH')
43
- };
44
21
  export const FLOW_EDGE = {
45
22
  width: numberToken('flow.edge.width'), marker: numberToken('flow.edge.marker'),
46
23
  radius: numberToken('flow.edge.radius'), handle: numberToken('flow.edge.handle')
@@ -49,51 +26,32 @@ export const FLOW_ICON = {
49
26
  small: numberToken('size.icon.default'), medium: numberToken('size.icon.medium'),
50
27
  large: numberToken('size.icon.large')
51
28
  };
52
- const nodeCategories = {
53
- task: 'task', task_data: 'task', profile: 'task', dependency: 'dependency', task_dependency: 'dependency',
54
- task_transformation: 'transformation', transformation: 'transformation',
55
- transformationGroup: 'transformation', validation: 'validation',
56
- validationGroup: 'validation', push_step: 'pushStep', pushStep: 'pushStep',
57
- pushStepsGroup: 'pushStep', decision: 'decision', loop: 'loop', grouped: 'grouped'
58
- };
59
29
  const variable = (name) => `var(--bh-${name.replaceAll('.', '-')})`;
60
- const palettes = Object.fromEntries([
61
- 'task', 'dependency', 'transformation', 'validation', 'pushStep', 'decision', 'loop', 'grouped'
62
- ].map(category => {
63
- const role = (part) => variable(`flow.category.${category}.${part}`);
64
- return [category, {
30
+ const palettes = Object.fromEntries(FLOW_TONES.map(tone => {
31
+ const role = (part) => variable(`${toneRoles[tone]}.${part}`);
32
+ return [tone, {
65
33
  primary: role('border'), text: role('foreground'), background: role('background'),
66
- border: role('border'), hover: role('hover'),
67
- connector: { bg: role('background'), border: role('border'), logoBorder: role('border') }
34
+ border: role('border'), hover: role('hover')
68
35
  }];
69
36
  }));
70
37
  /** CSS bindings stay reactive to the source theme/locale without rebuilding a graph. */
71
- export function getNodeColorPalette(category) {
72
- return palettes[category];
38
+ export function getFlowTonePalette(tone) {
39
+ return palettes[tone];
73
40
  }
74
- export function getEdgeColorPalette(category) {
75
- return palettes[category === 'dataFlow' ? 'pushStep' :
76
- category === 'conditional' ? 'decision' : category];
77
- }
78
- /** Unknown/custom node types retain the task category, matching VueFlow's default node. */
79
- export function getNodeColor(type) {
80
- return palettes[nodeCategories[type] ?? 'task'].border;
81
- }
82
- /** Apply a category role to custom semantic content without a consumer-owned recipe. */
83
- export function getFlowCategoryStyles(type, part = 'foreground') {
84
- const palette = palettes[nodeCategories[type] ?? 'task'];
41
+ /** Apply a tone role to custom content without a consumer-owned recipe. */
42
+ export function getFlowToneStyles(tone, part = 'foreground') {
43
+ const palette = palettes[tone];
85
44
  if (part === 'border')
86
45
  return { borderColor: palette.border };
87
46
  if (part === 'background')
88
47
  return { backgroundColor: palette.background };
89
48
  return { color: palette.text };
90
49
  }
91
- const categoryBadgeStyles = {};
92
- /** Paired native Tag paint; a category stroke is not an on-bold background. */
93
- export function getFlowCategoryBadgeStyles(type) {
94
- const category = nodeCategories[type] ?? 'task';
95
- const palette = palettes[category];
96
- return categoryBadgeStyles[category] ??= Object.freeze({
50
+ const toneBadgeStyles = {};
51
+ /** Paired native Tag paint; a tone stroke is not an on-bold background. */
52
+ export function getFlowToneBadgeStyles(tone) {
53
+ const palette = palettes[tone];
54
+ return toneBadgeStyles[tone] ??= Object.freeze({
97
55
  color: palette.text,
98
56
  backgroundColor: palette.background,
99
57
  borderColor: palette.border
@@ -105,25 +63,24 @@ const iconRoles = {
105
63
  'status-loading': 'color.icon.info', 'control-expand': 'color.icon',
106
64
  'control-collapse': 'color.icon', 'control-help': 'color.icon'
107
65
  };
108
- /** Category glyphs and operational/status glyphs retain distinct source roles. */
109
- export function getFlowIconStyles(type, options = {}) {
66
+ /** Tone glyphs take the tone's border role; status/control glyphs keep their own source roles. */
67
+ export function getFlowIconStyles(role, options = {}) {
110
68
  const size = options.size ?? 'medium';
111
- const category = type.startsWith('edge-') ? type.slice(5) : type;
112
69
  return {
113
70
  fontSize: `${typeof size === 'number' ? size : FLOW_ICON[size]}px`,
114
71
  color: options.disabled ? variable('color.icon.disabled') :
115
- options.color ?? (iconRoles[type] ? variable(iconRoles[type]) : getNodeColor(category)),
72
+ options.color ?? (role in iconRoles ? variable(iconRoles[role]) : palettes[role].border),
116
73
  display: 'inline-flex', alignItems: 'center', justifyContent: 'center'
117
74
  };
118
75
  }
119
- const edgeDashes = {
120
- dependency: undefined, transformation: '5,5', conditional: '2,2', dataFlow: '8,3,2,3'
121
- };
122
- /** Directed target stroke wins over category fallback; dashes communicate relation kind. */
123
- export function getFlowEdgeStyles(category, suppliedStyle) {
76
+ /**
77
+ * SVG presentation recipe for a custom edge path. A supplied directed target stroke wins over
78
+ * the tone fallback; a supplied static dash is kept (the consumer owns what a dash means).
79
+ */
80
+ export function getFlowEdgeStyles(tone, suppliedStyle) {
124
81
  return {
125
- stroke: suppliedStyle?.stroke ?? getEdgeColorPalette(category).primary,
126
- strokeWidth: FLOW_EDGE.width, strokeDasharray: edgeDashes[category],
82
+ stroke: suppliedStyle?.stroke ?? palettes[tone].border,
83
+ strokeWidth: FLOW_EDGE.width, strokeDasharray: suppliedStyle?.strokeDasharray,
127
84
  fill: 'none', vectorEffect: 'non-scaling-stroke'
128
85
  };
129
86
  }
@@ -135,6 +92,7 @@ export const FLOW_VIEWPORT = {
135
92
  export function createVueFlowTheme(options = {}) {
136
93
  const mode = { ...tokens.light, ...(options.dark ? tokens.dark : {}) };
137
94
  const typography = options.locale === 'vi' ? { ...mode, ...tokens.vi } : mode;
95
+ const nodeTone = options.nodeTone ?? (() => DEFAULT_TONE);
138
96
  return {
139
97
  class: 'bh-vue-flow',
140
98
  style: {
@@ -149,16 +107,19 @@ export function createVueFlowTheme(options = {}) {
149
107
  },
150
108
  flowOptions: { ...FLOW_VIEWPORT, snapGrid: [...FLOW_VIEWPORT.snapGrid] },
151
109
  minimap: {
152
- nodeColor: node => getNodeColor(node.type ?? 'task'),
110
+ nodeColor: node => palettes[nodeTone(node)].border,
153
111
  maskColor: variable('color.surface.scrim'), nodeStrokeColor: variable('color.border.bold')
154
112
  },
155
113
  background: { patternColor: variable('color.border'), bgColor: mode['color.surface.page'] }
156
114
  };
157
115
  }
158
- /** Preserve target identity for both the visible stroke and arrow marker. */
159
- export function styleTargetEdge(edge, nodes) {
116
+ /**
117
+ * Preserve target identity for both the visible stroke and arrow marker. `toneOf` resolves the
118
+ * target node's tone (`blue` when omitted, or when the target is missing).
119
+ */
120
+ export function styleTargetEdge(edge, nodes, toneOf = () => DEFAULT_TONE) {
160
121
  const target = nodes.find(node => node.id === edge.target);
161
- const stroke = getNodeColor(target?.type || target?.data?.nodeType || 'task');
122
+ const stroke = palettes[target ? toneOf(target) : DEFAULT_TONE].border;
162
123
  return {
163
124
  ...edge, animated: false,
164
125
  style: { ...(typeof edge.style === 'object' ? edge.style : {}), stroke },
@@ -170,11 +131,9 @@ export function styleTargetEdge(edge, nodes) {
170
131
  }
171
132
  };
172
133
  }
173
- /** Custom content and layout share fixed source geometry, not viewport-dependent sizing. */
174
- export function getFlowNodeStyles(type, state = {}) {
175
- const dimensions = NODE_DIMENSIONS[type];
176
- const palette = palettes[nodeCategories[type] ?? 'task'];
177
- const round = type === NodeType.LOOP || type === NodeType.DECISION;
134
+ /** Custom content and layout share fixed consumer geometry, not viewport-dependent sizing. */
135
+ export function getFlowNodeStyles(look, state = {}) {
136
+ const palette = palettes[look.tone];
178
137
  const label = {
179
138
  font: variable('font.label.default'), color: palette.text, textAlign: 'center',
180
139
  overflowWrap: 'anywhere', width: '100%'
@@ -185,12 +144,12 @@ export function getFlowNodeStyles(type, state = {}) {
185
144
  };
186
145
  return {
187
146
  container: {
188
- width: `${dimensions.width}px`, height: `${dimensions.height}px`,
147
+ width: `${look.width}px`, height: `${look.height}px`,
189
148
  boxSizing: 'border-box', display: 'flex', flexDirection: 'column',
190
149
  alignItems: 'center', justifyContent: 'center', cursor: 'pointer',
191
150
  border: `${variable('border.width.selected')} solid ${palette.border}`,
192
- borderStyle: state.selfDependency ? 'dashed' : 'solid',
193
- borderRadius: round ? '50%' : variable('radius.100'),
151
+ borderStyle: state.dashed ? 'dashed' : 'solid',
152
+ borderRadius: look.shape === 'circle' ? '50%' : variable('radius.100'),
194
153
  background: state.hovered ? palette.hover : palette.background,
195
154
  color: palette.text, font: variable('font.body.default'),
196
155
  outline: state.selected ? `${variable('border.width.selected')} solid ${variable('color.border.selected')}` : undefined,
@@ -202,9 +161,7 @@ export function getFlowNodeStyles(type, state = {}) {
202
161
  padding: variable('space.150'), gap: variable('space.050')
203
162
  },
204
163
  icon, label, text: label, loadingIcon: icon,
205
- connectorLogo: { borderRadius: variable('radius.075'), objectFit: 'contain' },
206
- connectorFlow: { display: 'flex', alignItems: 'center', gap: variable('space.100') },
207
- connectorArrow: { color: palette.primary, font: variable('font.label.default') }
164
+ logo: { borderRadius: variable('radius.075'), objectFit: 'contain' }
208
165
  };
209
166
  }
210
167
  /** Minimal detail removes costly decoration, never semantic contrast or graph data. */
package/dist/styles.css CHANGED
@@ -71,7 +71,8 @@
71
71
  .bh-vue-flow .vue-flow__edge-textbg { fill: var(--bh-color-surface); }
72
72
  .bh-vue-flow .vue-flow__selection,
73
73
  .bh-vue-flow .vue-flow__nodesselection-rect {
74
- background: var(--bh-color-background-selected);
74
+ /* Transparent: the swept cards stay visible through the box; only the dashed focus border marks it. */
75
+ background: transparent;
75
76
  border: var(--bh-border-width-selected) dashed var(--bh-color-border-focus);
76
77
  }
77
78
  .bh-vue-flow .vue-flow__controls {
@@ -155,8 +156,9 @@
155
156
  .bh-flow-icon[data-bh-loading='true'] { animation: none; }
156
157
  }
157
158
 
158
- /* Labelled relationship markers identify categories, never operational status. */
159
- .bh-flow-category-mark {
159
+ /* Labelled relationship markers identify a colour tone, never operational status. Tones map
160
+ onto the existing foundation `flow.category.*` border roles (see FlowTone in index.ts). */
161
+ .bh-flow-tone-mark {
160
162
  display: inline-block;
161
163
  flex: none;
162
164
  width: var(--bh-space-075);
@@ -164,13 +166,13 @@
164
166
  border-radius: 50%;
165
167
  background: var(--bh-flow-category-task-border);
166
168
  }
167
- .bh-flow-category-mark[data-bh-category='dependency'] { background: var(--bh-flow-category-dependency-border); }
168
- .bh-flow-category-mark[data-bh-category='transformation'] { background: var(--bh-flow-category-transformation-border); }
169
- .bh-flow-category-mark[data-bh-category='validation'] { background: var(--bh-flow-category-validation-border); }
170
- .bh-flow-category-mark[data-bh-category='pushStep'] { background: var(--bh-flow-category-pushStep-border); }
171
- .bh-flow-category-mark[data-bh-category='decision'] { background: var(--bh-flow-category-decision-border); }
172
- .bh-flow-category-mark[data-bh-category='loop'] { background: var(--bh-flow-category-loop-border); }
173
- .bh-flow-category-mark[data-bh-category='grouped'] { background: var(--bh-flow-category-grouped-border); }
169
+ .bh-flow-tone-mark[data-bh-tone='red'] { background: var(--bh-flow-category-dependency-border); }
170
+ .bh-flow-tone-mark[data-bh-tone='green'] { background: var(--bh-flow-category-transformation-border); }
171
+ .bh-flow-tone-mark[data-bh-tone='crimson'] { background: var(--bh-flow-category-validation-border); }
172
+ .bh-flow-tone-mark[data-bh-tone='yellow'] { background: var(--bh-flow-category-pushStep-border); }
173
+ .bh-flow-tone-mark[data-bh-tone='teal'] { background: var(--bh-flow-category-decision-border); }
174
+ .bh-flow-tone-mark[data-bh-tone='magenta'] { background: var(--bh-flow-category-loop-border); }
175
+ .bh-flow-tone-mark[data-bh-tone='purple'] { background: var(--bh-flow-category-grouped-border); }
174
176
 
175
177
  /* Native workflow-canvas theme variables are its public styling API. Scope the host
176
178
  protocol here; never change application-wide primary/text variables. */
@@ -200,6 +202,19 @@
200
202
  --wf-edge: var(--bh-diagram-edge);
201
203
  --wf-edge-active: var(--bh-diagram-selection-ring);
202
204
  --wf-edge-failure: var(--bh-diagram-fail-stroke);
205
+ /* Possible/context/toned-failure cues are shapes, never new dashes or opacity: context is a thinner resting
206
+ stroke (with the native open arrowhead); a toned failure keeps its tone dash and adds a circle-x mark.
207
+ Package-owned variable: it reads the foundation border width, no flow-specific token. */
208
+ --wf-edge-context-width: var(--bh-border-width-default);
209
+ --wf-edge-failure-icon: var(--bh-color-icon-danger);
210
+ /* Generic colour tones for `WorkflowEdge.tone`, mapped onto the existing foundation category border roles.
211
+ Tones are categorical, never execution/failure states; each keeps its static non-colour dash cue. */
212
+ --wf-edge-tone-blue: var(--bh-flow-category-task-border);
213
+ --wf-edge-tone-blue-dash: none;
214
+ --wf-edge-tone-red: var(--bh-flow-category-dependency-border);
215
+ --wf-edge-tone-red-dash: 2 4;
216
+ --wf-edge-tone-green: var(--bh-flow-category-transformation-border);
217
+ --wf-edge-tone-green-dash: 9 3 2 3;
203
218
  --wf-label-bg: var(--bh-diagram-edge-label-bg);
204
219
  --wf-label-fg: var(--bh-diagram-edge-label-text);
205
220
  --wf-label-border: var(--bh-color-border);
@@ -210,6 +225,8 @@
210
225
  --wf-dock-height: calc(var(--bh-size-control-default) + var(--bh-space-100) + 2 * var(--bh-border-width-default));
211
226
  --wf-chrome-radius: var(--bh-radius-050);
212
227
  --wf-node-width: var(--bh-diagram-card-width);
228
+ --wf-node-content-min-width: var(--bh-diagram-card-width);
229
+ --wf-node-content-max-width: calc(2 * var(--bh-diagram-card-width));
213
230
  --wf-node-bg: var(--bh-diagram-node-fill);
214
231
  --wf-node-fg: var(--bh-diagram-node-title);
215
232
  --wf-node-muted: var(--bh-diagram-node-desc);
@@ -227,6 +244,19 @@
227
244
  --wf-tone-fg: var(--bh-diagram-tile-glyph);
228
245
  --wf-node-kind-bg: var(--bh-diagram-node-fill);
229
246
  --wf-node-kind-fg: var(--bh-diagram-node-desc);
247
+ /* Group frames (the native `wf-group` node). Package-owned variables over foundation roles; the native layout
248
+ reads padding and header gap from here, so both stay plain lengths. */
249
+ --wf-group-border: var(--bh-color-border);
250
+ --wf-group-border-width: var(--bh-border-width-default);
251
+ --wf-group-radius: var(--bh-radius-card);
252
+ --wf-group-bg: var(--bh-color-surface-subtle);
253
+ --wf-group-nested-bg: var(--bh-color-background-neutral);
254
+ --wf-group-padding: var(--bh-space-stack);
255
+ --wf-group-header-gap: var(--bh-space-150);
256
+ /* The Shift + drag selection box: the same recipe as `.bh-vue-flow .vue-flow__selection` (transparent, dashed). */
257
+ --wf-selection-bg: transparent;
258
+ --wf-selection-border: var(--bh-color-border-focus);
259
+ --wf-selection-border-width: var(--bh-border-width-selected);
230
260
  }
231
261
  /* Opt-in graph contrast uses theme-resolved semantic ink, not a fixed light-mode
232
262
  palette. Preserve selection/failure colours and native edge/arrow pairing. */
@@ -241,6 +271,7 @@
241
271
  --wf-node-muted: var(--bh-color-text);
242
272
  --wf-node-kind-fg: var(--bh-color-text);
243
273
  --wf-tone-fg: var(--bh-color-text);
274
+ --wf-group-border: var(--bh-color-text);
244
275
  }
245
276
  /* Execution belongs to the node outline/content; the independent outer ring
246
277
  continues to carry selection, hover and keyboard focus. */
@@ -292,9 +323,21 @@
292
323
  .bh-workflow-canvas .wf-node.wf-node--shape-stadium { width: max-content; }
293
324
  .bh-workflow-canvas .wf-node__title {
294
325
  white-space: normal;
295
- overflow-wrap: anywhere;
296
326
  font: var(--bh-font-heading-xsmall);
297
327
  }
328
+ /* A card may break a long unbroken title anywhere. A diamond or ellipse wraps its title and its kind caption at word
329
+ boundaries and never truncates them: its side padding follows its width, so a mid-word break reads as two words and
330
+ an ellipsis hides the node's own name. Only a single word wider than the whole content box breaks. */
331
+ .bh-workflow-canvas .wf-node:not(.wf-node--shape-diamond, .wf-node--shape-ellipse) .wf-node__title {
332
+ overflow-wrap: anywhere;
333
+ }
334
+ .bh-workflow-canvas :is(.wf-node--shape-diamond, .wf-node--shape-ellipse) :is(.wf-node__title, .wf-node__kind) {
335
+ max-width: 100%;
336
+ white-space: normal;
337
+ overflow: visible;
338
+ overflow-wrap: break-word;
339
+ text-overflow: clip;
340
+ }
298
341
  .bh-workflow-canvas .wf-node__head { height: auto; }
299
342
  .bh-workflow-canvas .wf-node__subtitle {
300
343
  font: var(--bh-font-body-default);
@@ -310,6 +353,18 @@
310
353
  width: auto;
311
354
  flex: none;
312
355
  }
356
+ /* Opt-in ordinary-card recipe. The native theme owns the content width mechanism within the
357
+ `--wf-node-content-*` roles bound above; the head and logo flex are global rules here. Title/kind
358
+ wrap and the logo bound keep long titles and every logo readable. */
359
+ .bh-workflow-canvas .wf-node[data-sizing='content']:not(.wf-node--shape-diamond, .wf-node--shape-ellipse)
360
+ :is(.wf-node__title, .wf-node__kind) {
361
+ white-space: normal;
362
+ overflow: visible;
363
+ overflow-wrap: anywhere;
364
+ }
365
+ .bh-workflow-canvas .wf-node[data-sizing='content'] .wf-node__logos > img {
366
+ max-width: 100%;
367
+ }
313
368
  .bh-workflow-canvas .wf-node__execution > svg,
314
369
  .bh-workflow-canvas .wf-node__indicators svg {
315
370
  width: auto;
@@ -359,11 +414,57 @@
359
414
  width: auto;
360
415
  height: var(--bh-size-icon-default);
361
416
  }
417
+ /* Native find box (WorkflowFind, the viewer's `/` search). It is an overlay holding a
418
+ search field and result rows: surface.overlay with elevation.shadow.overlay and
419
+ radius.overlay, no border (overlays are set apart by surface and shadow), a
420
+ color.border divider under the field. Rows take the overlay item states one step
421
+ apart: hover surface.overlay.hover; the keyboard-active row (aria-selected)
422
+ surface.overlay.selected plus the border.selected start bar as its non-colour cue;
423
+ that row hovered surface.overlay.selected.hover. Text keeps color.text in every
424
+ state. The shared --wf-list-* roles also paint the jump list and dock menu rows. */
425
+ .bh-workflow-canvas .wf-canvas {
426
+ --wf-list-bg: var(--bh-color-surface-overlay);
427
+ --wf-list-fg: var(--bh-color-text);
428
+ --wf-list-muted: var(--bh-color-text-subtle);
429
+ --wf-list-border: var(--bh-color-border);
430
+ --wf-list-hover: var(--bh-color-surface-overlay-hover);
431
+ --wf-list-active: var(--bh-color-surface-overlay-selected);
432
+ --wf-list-active-hover: var(--bh-color-surface-overlay-selected-hover);
433
+ --wf-list-indicator: var(--bh-color-border-selected);
434
+ --wf-list-indicator-width: var(--bh-border-width-selected);
435
+ --wf-list-failure: var(--bh-color-text-danger);
436
+ --wf-find-border-width: 0;
437
+ --wf-find-radius: var(--bh-radius-overlay);
438
+ --wf-find-input-padding: var(--bh-space-075) var(--bh-space-control-x);
439
+ --wf-find-placeholder: var(--bh-color-text-subtlest);
440
+ --wf-find-list-padding: var(--bh-space-overlay);
441
+ --wf-find-option-padding: var(--bh-space-075) var(--bh-space-item-x);
442
+ --wf-find-option-min-height: var(--bh-size-control-default);
443
+ --wf-find-option-radius: var(--bh-radius-item);
444
+ --wf-find-empty-padding: var(--bh-space-075) var(--bh-space-control-x);
445
+ }
446
+ /* Search field and empty state body.default, result name label.default, the id of a
447
+ node without a name code.default, the kind label body.small in color.text.subtle
448
+ (--wf-list-muted). Names wrap at word boundaries and are never truncated. Focus is
449
+ the field's ring around the whole box (the companion's --wf-focus-outline). */
450
+ .bh-workflow-canvas .wf-find {
451
+ font: var(--bh-font-body-default);
452
+ }
453
+ .bh-workflow-canvas .wf-find__text {
454
+ font: var(--bh-font-label-default);
455
+ }
456
+ .bh-workflow-canvas .wf-find__id {
457
+ font: var(--bh-font-code-default);
458
+ }
459
+ .bh-workflow-canvas .wf-find__detail {
460
+ font: var(--bh-font-body-small);
461
+ }
362
462
  @media (pointer: coarse), (width < 768px) {
363
463
  .bh-workflow-canvas {
364
464
  --wf-control-height: var(--bh-size-target-touch);
365
465
  }
366
466
  .bh-workflow-canvas .wf-canvas {
367
467
  --wf-dock-height: calc(var(--bh-size-target-touch) + var(--bh-space-100) + 2 * var(--bh-border-width-default));
468
+ --wf-find-option-min-height: var(--bh-size-target-touch);
368
469
  }
369
470
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@beehexa/vueflow-tokens",
3
- "version": "2611.6.1",
4
- "description": "Source-backed Beehexa theme, semantic categories and geometry for VueFlow 1",
3
+ "version": "2611.8.1",
4
+ "description": "Source-backed Beehexa theme and generic colour tones for VueFlow 1",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/beehexacorp/beehexa.design.git",
@@ -29,7 +29,7 @@
29
29
  "./package.json": "./package.json"
30
30
  },
31
31
  "dependencies": {
32
- "@beehexa/design-tokens": "2611.6.1"
32
+ "@beehexa/design-tokens": "2611.8.1"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "@vue-flow/core": "^1.0.0",