@medalsocial/meda 1.7.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/README.md +2 -1
  2. package/dist/calendar/calendar-toolbar.d.ts +2 -0
  3. package/dist/calendar/calendar-toolbar.js +22 -0
  4. package/dist/calendar/calendar.d.ts +2 -0
  5. package/dist/calendar/calendar.js +55 -0
  6. package/dist/calendar/day-view.d.ts +2 -0
  7. package/dist/calendar/day-view.js +40 -0
  8. package/dist/calendar/index.d.ts +6 -0
  9. package/dist/calendar/index.js +7 -0
  10. package/dist/calendar/internal/date.d.ts +26 -0
  11. package/dist/calendar/internal/date.js +107 -0
  12. package/dist/calendar/internal/day-cell.d.ts +15 -0
  13. package/dist/calendar/internal/day-cell.js +38 -0
  14. package/dist/calendar/internal/event-pill.d.ts +13 -0
  15. package/dist/calendar/internal/event-pill.js +30 -0
  16. package/dist/calendar/internal/time-slot.d.ts +17 -0
  17. package/dist/calendar/internal/time-slot.js +23 -0
  18. package/dist/calendar/month-view.d.ts +2 -0
  19. package/dist/calendar/month-view.js +46 -0
  20. package/dist/calendar/public.d.ts +6 -0
  21. package/dist/calendar/public.js +8 -0
  22. package/dist/calendar/types.d.ts +113 -0
  23. package/dist/calendar/types.js +15 -0
  24. package/dist/calendar/week-view.d.ts +2 -0
  25. package/dist/calendar/week-view.js +39 -0
  26. package/dist/chat/turn-card.js +10 -5
  27. package/dist/email-builder/block-error-boundary.d.ts +16 -0
  28. package/dist/email-builder/block-error-boundary.js +20 -0
  29. package/dist/email-builder/block-palette.d.ts +7 -0
  30. package/dist/email-builder/block-palette.js +22 -0
  31. package/dist/email-builder/block-registry.d.ts +15 -0
  32. package/dist/email-builder/block-registry.js +156 -0
  33. package/dist/email-builder/block-renderer.d.ts +5 -0
  34. package/dist/email-builder/block-renderer.js +40 -0
  35. package/dist/email-builder/block-renderers/button.d.ts +4 -0
  36. package/dist/email-builder/block-renderers/button.js +26 -0
  37. package/dist/email-builder/block-renderers/columns.d.ts +5 -0
  38. package/dist/email-builder/block-renderers/columns.js +27 -0
  39. package/dist/email-builder/block-renderers/divider.d.ts +4 -0
  40. package/dist/email-builder/block-renderers/divider.js +14 -0
  41. package/dist/email-builder/block-renderers/footer.d.ts +4 -0
  42. package/dist/email-builder/block-renderers/footer.js +12 -0
  43. package/dist/email-builder/block-renderers/heading.d.ts +4 -0
  44. package/dist/email-builder/block-renderers/heading.js +19 -0
  45. package/dist/email-builder/block-renderers/image.d.ts +4 -0
  46. package/dist/email-builder/block-renderers/image.js +18 -0
  47. package/dist/email-builder/block-renderers/social.d.ts +4 -0
  48. package/dist/email-builder/block-renderers/social.js +19 -0
  49. package/dist/email-builder/block-renderers/spacer.d.ts +4 -0
  50. package/dist/email-builder/block-renderers/spacer.js +5 -0
  51. package/dist/email-builder/block-renderers/text.d.ts +4 -0
  52. package/dist/email-builder/block-renderers/text.js +17 -0
  53. package/dist/email-builder/builder-canvas.d.ts +15 -0
  54. package/dist/email-builder/builder-canvas.js +26 -0
  55. package/dist/email-builder/builder-header.d.ts +9 -0
  56. package/dist/email-builder/builder-header.js +8 -0
  57. package/dist/email-builder/builder-left-tabs.d.ts +11 -0
  58. package/dist/email-builder/builder-left-tabs.js +19 -0
  59. package/dist/email-builder/email-builder.d.ts +3 -0
  60. package/dist/email-builder/email-builder.js +84 -0
  61. package/dist/email-builder/envelope-card.d.ts +7 -0
  62. package/dist/email-builder/envelope-card.js +16 -0
  63. package/dist/email-builder/floating-bar.d.ts +13 -0
  64. package/dist/email-builder/floating-bar.js +9 -0
  65. package/dist/email-builder/index.d.ts +4 -0
  66. package/dist/email-builder/index.js +12 -0
  67. package/dist/email-builder/internal/builder-state-utils.d.ts +7 -0
  68. package/dist/email-builder/internal/builder-state-utils.js +52 -0
  69. package/dist/email-builder/internal/dnd-wrapper.d.ts +10 -0
  70. package/dist/email-builder/internal/dnd-wrapper.js +9 -0
  71. package/dist/email-builder/internal/email-font-options.d.ts +5 -0
  72. package/dist/email-builder/internal/email-font-options.js +12 -0
  73. package/dist/email-builder/mobile-drawers.d.ts +10 -0
  74. package/dist/email-builder/mobile-drawers.js +7 -0
  75. package/dist/email-builder/mobile-tab-bar.d.ts +10 -0
  76. package/dist/email-builder/mobile-tab-bar.js +9 -0
  77. package/dist/email-builder/property-editors/_shared.d.ts +58 -0
  78. package/dist/email-builder/property-editors/_shared.js +52 -0
  79. package/dist/email-builder/property-editors/button-editor.d.ts +7 -0
  80. package/dist/email-builder/property-editors/button-editor.js +10 -0
  81. package/dist/email-builder/property-editors/columns-editor.d.ts +7 -0
  82. package/dist/email-builder/property-editors/columns-editor.js +15 -0
  83. package/dist/email-builder/property-editors/divider-editor.d.ts +7 -0
  84. package/dist/email-builder/property-editors/divider-editor.js +10 -0
  85. package/dist/email-builder/property-editors/footer-editor.d.ts +7 -0
  86. package/dist/email-builder/property-editors/footer-editor.js +6 -0
  87. package/dist/email-builder/property-editors/heading-editor.d.ts +7 -0
  88. package/dist/email-builder/property-editors/heading-editor.js +16 -0
  89. package/dist/email-builder/property-editors/image-editor.d.ts +8 -0
  90. package/dist/email-builder/property-editors/image-editor.js +17 -0
  91. package/dist/email-builder/property-editors/social-editor.d.ts +7 -0
  92. package/dist/email-builder/property-editors/social-editor.js +18 -0
  93. package/dist/email-builder/property-editors/spacer-editor.d.ts +7 -0
  94. package/dist/email-builder/property-editors/spacer-editor.js +6 -0
  95. package/dist/email-builder/property-editors/text-editor.d.ts +13 -0
  96. package/dist/email-builder/property-editors/text-editor.js +8 -0
  97. package/dist/email-builder/property-inspector.d.ts +11 -0
  98. package/dist/email-builder/property-inspector.js +42 -0
  99. package/dist/email-builder/public.d.ts +1 -0
  100. package/dist/email-builder/public.js +3 -0
  101. package/dist/email-builder/render-to-email-html.d.ts +11 -0
  102. package/dist/email-builder/render-to-email-html.js +219 -0
  103. package/dist/email-builder/starter-shell.d.ts +3 -0
  104. package/dist/email-builder/starter-shell.js +21 -0
  105. package/dist/email-builder/types.d.ts +182 -0
  106. package/dist/email-builder/types.js +41 -0
  107. package/dist/email-builder/view-controls.d.ts +10 -0
  108. package/dist/email-builder/view-controls.js +12 -0
  109. package/dist/index.d.ts +4 -0
  110. package/dist/index.js +4 -0
  111. package/dist/lib/format-time.js +2 -3
  112. package/dist/post-preview/index.d.ts +4 -0
  113. package/dist/post-preview/index.js +7 -0
  114. package/dist/post-preview/internal/avatar.d.ts +12 -0
  115. package/dist/post-preview/internal/avatar.js +21 -0
  116. package/dist/post-preview/internal/format-content.d.ts +12 -0
  117. package/dist/post-preview/internal/format-content.js +31 -0
  118. package/dist/post-preview/internal/platform-meta.d.ts +10 -0
  119. package/dist/post-preview/internal/platform-meta.js +18 -0
  120. package/dist/post-preview/internal/textarea.d.ts +8 -0
  121. package/dist/post-preview/internal/textarea.js +12 -0
  122. package/dist/post-preview/internal/use-swipe.d.ts +17 -0
  123. package/dist/post-preview/internal/use-swipe.js +29 -0
  124. package/dist/post-preview/platforms/bluesky.d.ts +15 -0
  125. package/dist/post-preview/platforms/bluesky.js +21 -0
  126. package/dist/post-preview/platforms/discord.d.ts +44 -0
  127. package/dist/post-preview/platforms/discord.js +32 -0
  128. package/dist/post-preview/platforms/facebook.d.ts +23 -0
  129. package/dist/post-preview/platforms/facebook.js +24 -0
  130. package/dist/post-preview/platforms/generic.d.ts +22 -0
  131. package/dist/post-preview/platforms/generic.js +28 -0
  132. package/dist/post-preview/platforms/google-business.d.ts +18 -0
  133. package/dist/post-preview/platforms/google-business.js +22 -0
  134. package/dist/post-preview/platforms/index.d.ts +24 -0
  135. package/dist/post-preview/platforms/index.js +13 -0
  136. package/dist/post-preview/platforms/instagram.d.ts +31 -0
  137. package/dist/post-preview/platforms/instagram.js +99 -0
  138. package/dist/post-preview/platforms/linkedin.d.ts +52 -0
  139. package/dist/post-preview/platforms/linkedin.js +131 -0
  140. package/dist/post-preview/platforms/telegram.d.ts +46 -0
  141. package/dist/post-preview/platforms/telegram.js +42 -0
  142. package/dist/post-preview/platforms/threads.d.ts +19 -0
  143. package/dist/post-preview/platforms/threads.js +24 -0
  144. package/dist/post-preview/platforms/tiktok.d.ts +18 -0
  145. package/dist/post-preview/platforms/tiktok.js +23 -0
  146. package/dist/post-preview/platforms/twitter.d.ts +40 -0
  147. package/dist/post-preview/platforms/twitter.js +132 -0
  148. package/dist/post-preview/platforms/youtube.d.ts +17 -0
  149. package/dist/post-preview/platforms/youtube.js +21 -0
  150. package/dist/post-preview/post-preview.d.ts +29 -0
  151. package/dist/post-preview/post-preview.js +70 -0
  152. package/dist/post-preview/public.d.ts +1 -0
  153. package/dist/post-preview/public.js +6 -0
  154. package/dist/post-preview/types.d.ts +82 -0
  155. package/dist/post-preview/types.js +1 -0
  156. package/dist/primitives/filter-rail.js +17 -2
  157. package/dist/shell/app-shell-workspace.js +1 -1
  158. package/dist/shell/context-rail.d.ts +4 -2
  159. package/dist/shell/context-rail.js +27 -19
  160. package/dist/shell/extras/shell-scrollable-content.js +2 -2
  161. package/dist/shell/extras/workbench-layout.js +24 -13
  162. package/dist/shell/index.d.ts +1 -1
  163. package/dist/shell/internal/mobile-drawers.d.ts +6 -2
  164. package/dist/shell/internal/mobile-drawers.js +10 -7
  165. package/dist/shell/right-panel.js +10 -1
  166. package/dist/shell/shell-header.js +1 -1
  167. package/dist/shell/shell-provider.js +69 -53
  168. package/dist/shell/theme-next-themes.js +2 -2
  169. package/dist/shell/theme.js +7 -1
  170. package/dist/shell/types.d.ts +4 -0
  171. package/dist/shell/use-shell-viewport.js +14 -4
  172. package/dist/timeline/lane-timeline.js +1 -1
  173. package/dist/timeline/scrub-bar.js +1 -1
  174. package/dist/timeline/timeline-tape.js +8 -5
  175. package/dist/voice/voice-orb-scene.js +4 -4
  176. package/dist/voice/voice-status-pill.js +8 -7
  177. package/dist/workflow-builder/edges/default-edge.d.ts +10 -0
  178. package/dist/workflow-builder/edges/default-edge.js +21 -0
  179. package/dist/workflow-builder/edges/index.d.ts +3 -0
  180. package/dist/workflow-builder/edges/index.js +5 -0
  181. package/dist/workflow-builder/index.d.ts +5 -0
  182. package/dist/workflow-builder/index.js +12 -0
  183. package/dist/workflow-builder/internal/trigger-icons.d.ts +4 -0
  184. package/dist/workflow-builder/internal/trigger-icons.js +43 -0
  185. package/dist/workflow-builder/internal/trigger-sentence.d.ts +14 -0
  186. package/dist/workflow-builder/internal/trigger-sentence.js +50 -0
  187. package/dist/workflow-builder/nodes/action-node.d.ts +3 -0
  188. package/dist/workflow-builder/nodes/action-node.js +7 -0
  189. package/dist/workflow-builder/nodes/base-node.d.ts +20 -0
  190. package/dist/workflow-builder/nodes/base-node.js +18 -0
  191. package/dist/workflow-builder/nodes/condition-node.d.ts +3 -0
  192. package/dist/workflow-builder/nodes/condition-node.js +11 -0
  193. package/dist/workflow-builder/nodes/delay-node.d.ts +3 -0
  194. package/dist/workflow-builder/nodes/delay-node.js +7 -0
  195. package/dist/workflow-builder/nodes/end-node.d.ts +3 -0
  196. package/dist/workflow-builder/nodes/end-node.js +7 -0
  197. package/dist/workflow-builder/nodes/index.d.ts +13 -0
  198. package/dist/workflow-builder/nodes/index.js +22 -0
  199. package/dist/workflow-builder/nodes/trigger-node.d.ts +3 -0
  200. package/dist/workflow-builder/nodes/trigger-node.js +8 -0
  201. package/dist/workflow-builder/public.d.ts +1 -0
  202. package/dist/workflow-builder/public.js +4 -0
  203. package/dist/workflow-builder/types.d.ts +140 -0
  204. package/dist/workflow-builder/types.js +18 -0
  205. package/dist/workflow-builder/workflow-builder.d.ts +10 -0
  206. package/dist/workflow-builder/workflow-builder.js +22 -0
  207. package/dist/workflow-builder/workflow-canvas.d.ts +26 -0
  208. package/dist/workflow-builder/workflow-canvas.js +25 -0
  209. package/dist/workflow-builder/workflow-card-compact.d.ts +2 -0
  210. package/dist/workflow-builder/workflow-card-compact.js +22 -0
  211. package/dist/workflow-builder/workflow-card.d.ts +2 -0
  212. package/dist/workflow-builder/workflow-card.js +44 -0
  213. package/dist/workflow-builder/workflow-header.d.ts +2 -0
  214. package/dist/workflow-builder/workflow-header.js +31 -0
  215. package/dist/workflow-builder/workflow-toolbox.d.ts +2 -0
  216. package/dist/workflow-builder/workflow-toolbox.js +19 -0
  217. package/package.json +72 -50
@@ -0,0 +1,18 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Handle, Position } from '@xyflow/react';
4
+ import { cn } from '../../lib/utils.js';
5
+ import { NODE_HEIGHT, NODE_KIND_STYLES, NODE_WIDTH } from '../internal/trigger-sentence.js';
6
+ const HANDLE_CLASS = '!w-[11px] !h-[11px] !bg-neutral-400 dark:!bg-neutral-500 !border-2 !border-background !rounded-full';
7
+ export function BaseWorkflowNode({ kind, icon, label, description, warning, selected, showSourceHandle = true, showTargetHandle = true, sourceHandles, }) {
8
+ const colors = NODE_KIND_STYLES[kind];
9
+ return (_jsxs("div", { "data-slot": "workflow-node", "data-kind": kind, "data-selected": selected ? '' : undefined, className: cn('cursor-default select-none rounded-lg border-2 shadow-sm transition-all', colors.bg, colors.border, selected && 'shadow-md ring-2 ring-primary ring-offset-2', !selected && 'hover:shadow-md'), style: { width: NODE_WIDTH, minHeight: NODE_HEIGHT }, children: [showTargetHandle ? (_jsx(Handle, { type: "target", position: Position.Top, className: HANDLE_CLASS })) : null, _jsxs("div", { className: "flex items-start gap-3 p-3", children: [_jsx("div", { className: cn('mt-0.5 flex-shrink-0', colors.icon), children: icon }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "select-none truncate font-medium text-foreground text-sm", children: label }), description ? (_jsx("p", { className: "mt-0.5 truncate text-muted-foreground text-xs", children: description })) : null, warning ? (_jsx("p", { className: "mt-1 inline-flex max-w-full rounded-full bg-warning-100 px-2 py-0.5 font-medium text-[10px] text-warning-800 dark:bg-warning-900/30 dark:text-warning-300", children: warning })) : null] })] }), (() => {
10
+ if (sourceHandles?.length) {
11
+ return sourceHandles.map((handle) => (_jsx(Handle, { type: "source", position: handle.position, id: handle.id, className: HANDLE_CLASS }, handle.id)));
12
+ }
13
+ if (showSourceHandle) {
14
+ return _jsx(Handle, { type: "source", position: Position.Bottom, className: HANDLE_CLASS });
15
+ }
16
+ return null;
17
+ })()] }));
18
+ }
@@ -0,0 +1,3 @@
1
+ import { type NodeProps } from '@xyflow/react';
2
+ import type { WorkflowNode } from '../types.js';
3
+ export declare function ConditionNode({ data, selected }: NodeProps<WorkflowNode>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,11 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Position } from '@xyflow/react';
4
+ import { renderWorkflowIcon } from '../internal/trigger-icons.js';
5
+ import { BaseWorkflowNode } from './base-node.js';
6
+ export function ConditionNode({ data, selected }) {
7
+ return (_jsx(BaseWorkflowNode, { kind: "condition", selected: selected, icon: renderWorkflowIcon('condition', data.iconName), label: data.label || 'Condition', description: data.description ?? 'If / else branch', sourceHandles: [
8
+ { id: 'true', position: Position.Bottom, label: 'true' },
9
+ { id: 'false', position: Position.Right, label: 'false' },
10
+ ] }));
11
+ }
@@ -0,0 +1,3 @@
1
+ import type { NodeProps } from '@xyflow/react';
2
+ import type { WorkflowNode } from '../types.js';
3
+ export declare function DelayNode({ data, selected }: NodeProps<WorkflowNode>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { renderWorkflowIcon } from '../internal/trigger-icons.js';
4
+ import { BaseWorkflowNode } from './base-node.js';
5
+ export function DelayNode({ data, selected }) {
6
+ return (_jsx(BaseWorkflowNode, { kind: "delay", selected: selected, icon: renderWorkflowIcon('delay', data.iconName), label: data.label || 'Delay', description: data.description ?? 'Wait before continuing' }));
7
+ }
@@ -0,0 +1,3 @@
1
+ import type { NodeProps } from '@xyflow/react';
2
+ import type { WorkflowNode } from '../types.js';
3
+ export declare function EndNode({ data, selected }: NodeProps<WorkflowNode>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { renderWorkflowIcon } from '../internal/trigger-icons.js';
4
+ import { BaseWorkflowNode } from './base-node.js';
5
+ export function EndNode({ data, selected }) {
6
+ return (_jsx(BaseWorkflowNode, { kind: "end", selected: selected, icon: renderWorkflowIcon('end', data.iconName), label: data.label || 'End', description: data.description ?? 'End of workflow', showSourceHandle: false }));
7
+ }
@@ -0,0 +1,13 @@
1
+ import type { NodeTypes } from '@xyflow/react';
2
+ export { ActionNode } from './action-node.js';
3
+ export type { BaseWorkflowNodeProps } from './base-node.js';
4
+ export { BaseWorkflowNode } from './base-node.js';
5
+ export { ConditionNode } from './condition-node.js';
6
+ export { DelayNode } from './delay-node.js';
7
+ export { EndNode } from './end-node.js';
8
+ export { TriggerNode } from './trigger-node.js';
9
+ /**
10
+ * Default node-type registry. Pass into `<ReactFlow nodeTypes>` or override
11
+ * via `WorkflowBuilderProps['customNodeTypes']`.
12
+ */
13
+ export declare const workflowNodeTypes: NodeTypes;
@@ -0,0 +1,22 @@
1
+ import { ActionNode } from './action-node.js';
2
+ import { ConditionNode } from './condition-node.js';
3
+ import { DelayNode } from './delay-node.js';
4
+ import { EndNode } from './end-node.js';
5
+ import { TriggerNode } from './trigger-node.js';
6
+ export { ActionNode } from './action-node.js';
7
+ export { BaseWorkflowNode } from './base-node.js';
8
+ export { ConditionNode } from './condition-node.js';
9
+ export { DelayNode } from './delay-node.js';
10
+ export { EndNode } from './end-node.js';
11
+ export { TriggerNode } from './trigger-node.js';
12
+ /**
13
+ * Default node-type registry. Pass into `<ReactFlow nodeTypes>` or override
14
+ * via `WorkflowBuilderProps['customNodeTypes']`.
15
+ */
16
+ export const workflowNodeTypes = {
17
+ trigger: TriggerNode,
18
+ action: ActionNode,
19
+ condition: ConditionNode,
20
+ delay: DelayNode,
21
+ end: EndNode,
22
+ };
@@ -0,0 +1,3 @@
1
+ import type { NodeProps } from '@xyflow/react';
2
+ import type { WorkflowNode } from '../types.js';
3
+ export declare function TriggerNode({ data, selected }: NodeProps<WorkflowNode>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,8 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { renderWorkflowIcon } from '../internal/trigger-icons.js';
4
+ import { getDefaultNodeSentence } from '../internal/trigger-sentence.js';
5
+ import { BaseWorkflowNode } from './base-node.js';
6
+ export function TriggerNode({ data, selected }) {
7
+ return (_jsx(BaseWorkflowNode, { kind: "trigger", selected: selected, icon: renderWorkflowIcon('trigger', data.iconName), label: data.label || 'Trigger', description: data.description ?? getDefaultNodeSentence('trigger', data.label), showTargetHandle: false }));
8
+ }
@@ -0,0 +1 @@
1
+ export * from './index.js';
@@ -0,0 +1,4 @@
1
+ // open/meda/src/workflow-builder/public.ts
2
+ // Re-exported from the root barrel (`@medalsocial/meda`) so consumers can
3
+ // reach workflow surfaces from either entry point.
4
+ export * from './index.js';
@@ -0,0 +1,140 @@
1
+ import type { Connection, Edge, EdgeChange, Node, NodeChange, ReactFlowProps } from '@xyflow/react';
2
+ import type { ReactNode } from 'react';
3
+ /**
4
+ * The set of canonical workflow node kinds the package ships custom renderers
5
+ * for. Consumers may also register their own node `type` values via
6
+ * `nodeTypes` / `customNodeTypes` props — these labels are what the bundled
7
+ * toolbox + node renderers cover out-of-the-box.
8
+ */
9
+ export type WorkflowNodeKind = 'trigger' | 'action' | 'condition' | 'delay' | 'end';
10
+ export interface WorkflowNodeData {
11
+ /** Visible label shown on the node body. */
12
+ label: string;
13
+ /** Canonical kind (drives icon + accent color when no custom renderer). */
14
+ kind: WorkflowNodeKind;
15
+ /** Optional secondary line shown beneath the label. */
16
+ description?: string;
17
+ /** Lucide icon name (free-form string so consumers don't need to import). */
18
+ iconName?: string;
19
+ /** Free-form configuration the consumer attaches to the node. */
20
+ config?: Record<string, unknown>;
21
+ /** Optional state — `error` shows an amber accent. */
22
+ state?: 'default' | 'warning' | 'error';
23
+ [key: string]: unknown;
24
+ }
25
+ export type WorkflowNode = Node<WorkflowNodeData>;
26
+ export type WorkflowEdge = Edge;
27
+ export interface WorkflowBuilderLabels {
28
+ /** Header bar */
29
+ saveAction: string;
30
+ publishAction: string;
31
+ pauseAction: string;
32
+ saving: string;
33
+ /** Toolbox panel */
34
+ toolboxTitle: string;
35
+ toolboxHint: string;
36
+ toolboxReadOnlyHint: string;
37
+ addTrigger: string;
38
+ addAction: string;
39
+ addCondition: string;
40
+ addDelay: string;
41
+ addEnd: string;
42
+ /** Mobile drawers */
43
+ openToolbox: string;
44
+ openInspector: string;
45
+ closeDrawer: string;
46
+ /** Empty / placeholder state */
47
+ emptyCanvas: string;
48
+ }
49
+ export declare const defaultWorkflowBuilderLabels: WorkflowBuilderLabels;
50
+ /** Status badge values for the header. */
51
+ export type WorkflowStatus = 'draft' | 'active' | 'paused';
52
+ export interface WorkflowBuilderProps {
53
+ /** Controlled nodes array. */
54
+ nodes: WorkflowNode[];
55
+ /** Controlled edges array. */
56
+ edges: WorkflowEdge[];
57
+ /** React Flow node-change handler. */
58
+ onNodesChange: (changes: NodeChange[]) => void;
59
+ /** React Flow edge-change handler. */
60
+ onEdgesChange: (changes: EdgeChange[]) => void;
61
+ /** Connection handler. */
62
+ onConnect: (connection: Connection) => void;
63
+ /** Called when a toolbox item is tapped. */
64
+ onAddNode?: (kind: WorkflowNodeKind, position?: {
65
+ x: number;
66
+ y: number;
67
+ }) => void;
68
+ /** Selection change forwarded from React Flow. */
69
+ onSelectionChange?: (selection: {
70
+ nodes: WorkflowNode[];
71
+ edges: WorkflowEdge[];
72
+ }) => void;
73
+ /** Called when a node is clicked (header / inspector trigger). */
74
+ onNodeClick?: (node: WorkflowNode) => void;
75
+ /** Whether the toolbox panel is open by default on desktop (default true). */
76
+ showToolbox?: boolean;
77
+ /** Read-only canvas — disables changes & hides edit affordances. */
78
+ readOnly?: boolean;
79
+ /** Render the header bar slot. When omitted no header is rendered. */
80
+ headerSlot?: ReactNode;
81
+ /** Optional inspector slot (renders inside the right rail / mobile drawer). */
82
+ inspectorSlot?: ReactNode;
83
+ /** Override the default node-types registry. */
84
+ customNodeTypes?: ReactFlowProps['nodeTypes'];
85
+ /** Override the default edge-types registry. */
86
+ customEdgeTypes?: ReactFlowProps['edgeTypes'];
87
+ labels?: Partial<WorkflowBuilderLabels>;
88
+ className?: string;
89
+ }
90
+ export interface WorkflowToolboxItem {
91
+ kind: WorkflowNodeKind;
92
+ label: string;
93
+ description?: string;
94
+ iconName?: string;
95
+ }
96
+ export interface WorkflowToolboxProps {
97
+ items?: WorkflowToolboxItem[];
98
+ onAddNode?: (kind: WorkflowNodeKind) => void;
99
+ readOnly?: boolean;
100
+ labels?: Partial<WorkflowBuilderLabels>;
101
+ className?: string;
102
+ }
103
+ export interface WorkflowHeaderProps {
104
+ name: string;
105
+ onNameChange?: (name: string) => void;
106
+ status?: WorkflowStatus;
107
+ onSave?: () => void;
108
+ onPublish?: () => void;
109
+ onPause?: () => void;
110
+ onBack?: () => void;
111
+ isSaving?: boolean;
112
+ readOnly?: boolean;
113
+ labels?: Partial<WorkflowBuilderLabels>;
114
+ className?: string;
115
+ }
116
+ export interface WorkflowSummary {
117
+ id: string;
118
+ name: string;
119
+ description?: string;
120
+ status: WorkflowStatus;
121
+ triggerLabel?: string;
122
+ /** Free-form metadata the card surfaces in a footer row. */
123
+ meta?: {
124
+ label: string;
125
+ value: string;
126
+ }[];
127
+ /** Avatar URL for the creator (rendered when present). */
128
+ creatorAvatarUrl?: string;
129
+ creatorName?: string;
130
+ /** Unix ms; rendered as relative time when present. */
131
+ createdAt?: number;
132
+ }
133
+ export interface WorkflowCardProps {
134
+ workflow: WorkflowSummary;
135
+ onClick?: () => void;
136
+ className?: string;
137
+ }
138
+ export interface WorkflowCardCompactProps extends WorkflowCardProps {
139
+ showStats?: boolean;
140
+ }
@@ -0,0 +1,18 @@
1
+ export const defaultWorkflowBuilderLabels = {
2
+ saveAction: 'Save',
3
+ publishAction: 'Publish',
4
+ pauseAction: 'Pause',
5
+ saving: 'Saving...',
6
+ toolboxTitle: 'Add step',
7
+ toolboxHint: 'Tap a step to add it to your workflow.',
8
+ toolboxReadOnlyHint: 'This workflow is read-only.',
9
+ addTrigger: 'Trigger',
10
+ addAction: 'Action',
11
+ addCondition: 'Condition',
12
+ addDelay: 'Delay',
13
+ addEnd: 'End',
14
+ openToolbox: 'Steps',
15
+ openInspector: 'Inspector',
16
+ closeDrawer: 'Close',
17
+ emptyCanvas: 'Add a trigger to start building your workflow.',
18
+ };
@@ -0,0 +1,10 @@
1
+ import { type WorkflowBuilderProps } from './types.js';
2
+ /**
3
+ * Top-level workflow builder surface — composes the canvas, toolbox and
4
+ * (optional) header / inspector slots into a responsive layout.
5
+ *
6
+ * Container queries adapt the layout: at narrower container widths the
7
+ * toolbox collapses behind a tab bar (mobile) and at wider widths it sits to
8
+ * the left of the canvas.
9
+ */
10
+ export declare function WorkflowBuilder({ nodes, edges, onNodesChange, onEdgesChange, onConnect, onAddNode, onSelectionChange, onNodeClick, showToolbox, readOnly, headerSlot, inspectorSlot, customNodeTypes, customEdgeTypes, labels, className, }: WorkflowBuilderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,22 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { cn } from '../lib/utils.js';
5
+ import { defaultWorkflowBuilderLabels } from './types.js';
6
+ import { WorkflowCanvas } from './workflow-canvas.js';
7
+ import { WorkflowToolbox } from './workflow-toolbox.js';
8
+ /**
9
+ * Top-level workflow builder surface — composes the canvas, toolbox and
10
+ * (optional) header / inspector slots into a responsive layout.
11
+ *
12
+ * Container queries adapt the layout: at narrower container widths the
13
+ * toolbox collapses behind a tab bar (mobile) and at wider widths it sits to
14
+ * the left of the canvas.
15
+ */
16
+ export function WorkflowBuilder({ nodes, edges, onNodesChange, onEdgesChange, onConnect, onAddNode, onSelectionChange, onNodeClick, showToolbox = true, readOnly = false, headerSlot, inspectorSlot, customNodeTypes, customEdgeTypes, labels, className, }) {
17
+ const resolvedLabels = { ...defaultWorkflowBuilderLabels, ...(labels ?? {}) };
18
+ const [mobileDrawer, setMobileDrawer] = useState(null);
19
+ return (_jsxs("div", { "data-slot": "workflow-builder", className: cn('@container/workflow relative flex h-full w-full flex-col overflow-hidden bg-background', className), children: [headerSlot, _jsxs("div", { className: "relative flex flex-1 overflow-hidden", children: [showToolbox ? (_jsx("div", { className: "hidden w-64 flex-shrink-0 @[640px]/workflow:flex", children: _jsx(WorkflowToolbox, { onAddNode: onAddNode, readOnly: readOnly, labels: resolvedLabels }) })) : null, _jsxs("div", { className: "relative flex flex-1 flex-col", children: [_jsx(WorkflowCanvas, { nodes: nodes, edges: edges, onNodesChange: onNodesChange, onEdgesChange: onEdgesChange, onConnect: onConnect, onNodeClick: onNodeClick, onSelectionChange: onSelectionChange, readOnly: readOnly, customNodeTypes: customNodeTypes, customEdgeTypes: customEdgeTypes }), nodes.length === 0 ? (_jsx("div", { "data-slot": "workflow-empty-canvas", className: "pointer-events-none absolute inset-0 flex items-center justify-center text-center", children: _jsx("p", { className: "max-w-xs rounded-md bg-background/80 px-4 py-3 text-muted-foreground text-sm shadow-sm backdrop-blur", children: resolvedLabels.emptyCanvas }) })) : null] }), inspectorSlot ? (_jsx("div", { className: "hidden w-72 flex-shrink-0 border-border border-l @[960px]/workflow:flex", children: inspectorSlot })) : null] }), showToolbox || inspectorSlot ? (_jsxs("nav", { "data-slot": "workflow-mobile-tab-bar", className: "flex border-border border-t bg-background @[640px]/workflow:hidden", "aria-label": "Workflow panels", children: [showToolbox ? (_jsx("button", { type: "button", onClick: () => setMobileDrawer((current) => (current === 'toolbox' ? null : 'toolbox')), className: "flex h-12 min-h-11 flex-1 items-center justify-center font-medium text-sm transition-colors hover:bg-accent", "aria-pressed": mobileDrawer === 'toolbox', children: resolvedLabels.openToolbox })) : null, inspectorSlot ? (_jsx("button", { type: "button", onClick: () => setMobileDrawer((current) => (current === 'inspector' ? null : 'inspector')), className: "flex h-12 min-h-11 flex-1 items-center justify-center border-border border-l font-medium text-sm transition-colors hover:bg-accent", "aria-pressed": mobileDrawer === 'inspector', children: resolvedLabels.openInspector })) : null] })) : null, mobileDrawer ? (_jsxs("div", { "data-slot": "workflow-mobile-drawer", "data-panel": mobileDrawer, className: "@[640px]/workflow:hidden absolute inset-x-0 bottom-12 max-h-[60%] overflow-hidden border-border border-t bg-background shadow-lg", children: [_jsxs("div", { className: "flex items-center justify-between border-border border-b px-4 py-2", children: [_jsx("span", { className: "font-medium text-sm", children: mobileDrawer === 'toolbox'
20
+ ? resolvedLabels.openToolbox
21
+ : resolvedLabels.openInspector }), _jsx("button", { type: "button", onClick: () => setMobileDrawer(null), className: "inline-flex h-9 min-h-9 min-w-11 items-center rounded-md px-2 text-muted-foreground text-sm transition-colors hover:bg-accent hover:text-foreground", children: resolvedLabels.closeDrawer })] }), _jsxs("div", { className: "max-h-[50vh] overflow-y-auto", children: [mobileDrawer === 'toolbox' && showToolbox ? (_jsx(WorkflowToolbox, { onAddNode: onAddNode, readOnly: readOnly, labels: resolvedLabels })) : null, mobileDrawer === 'inspector' ? inspectorSlot : null] })] })) : null] }));
22
+ }
@@ -0,0 +1,26 @@
1
+ import { type Connection, type EdgeChange, type NodeChange, type ReactFlowProps } from '@xyflow/react';
2
+ import '@xyflow/react/dist/style.css';
3
+ import type { WorkflowEdge, WorkflowNode } from './types.js';
4
+ export interface WorkflowCanvasProps {
5
+ nodes: WorkflowNode[];
6
+ edges: WorkflowEdge[];
7
+ onNodesChange: (changes: NodeChange[]) => void;
8
+ onEdgesChange: (changes: EdgeChange[]) => void;
9
+ onConnect: (connection: Connection) => void;
10
+ onNodeClick?: (node: WorkflowNode) => void;
11
+ onPaneClick?: () => void;
12
+ onSelectionChange?: (selection: {
13
+ nodes: WorkflowNode[];
14
+ edges: WorkflowEdge[];
15
+ }) => void;
16
+ readOnly?: boolean;
17
+ customNodeTypes?: ReactFlowProps['nodeTypes'];
18
+ customEdgeTypes?: ReactFlowProps['edgeTypes'];
19
+ className?: string;
20
+ }
21
+ /**
22
+ * The bare React Flow canvas, with sensible defaults wired in. No header / no
23
+ * toolbox — compose with `WorkflowBuilder` for the full surface, or use this
24
+ * alone when embedding in a custom layout.
25
+ */
26
+ export declare function WorkflowCanvas({ nodes, edges, onNodesChange, onEdgesChange, onConnect, onNodeClick, onPaneClick, onSelectionChange, readOnly, customNodeTypes, customEdgeTypes, className, }: WorkflowCanvasProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,25 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Background, BackgroundVariant, Controls, ReactFlow, } from '@xyflow/react';
4
+ import '@xyflow/react/dist/style.css';
5
+ import { useCallback } from 'react';
6
+ import { cn } from '../lib/utils.js';
7
+ import { workflowEdgeTypes } from './edges/index.js';
8
+ import { workflowNodeTypes } from './nodes/index.js';
9
+ /**
10
+ * The bare React Flow canvas, with sensible defaults wired in. No header / no
11
+ * toolbox — compose with `WorkflowBuilder` for the full surface, or use this
12
+ * alone when embedding in a custom layout.
13
+ */
14
+ export function WorkflowCanvas({ nodes, edges, onNodesChange, onEdgesChange, onConnect, onNodeClick, onPaneClick, onSelectionChange, readOnly = false, customNodeTypes, customEdgeTypes, className, }) {
15
+ const handleNodeClick = useCallback((_e, node) => {
16
+ onNodeClick?.(node);
17
+ }, [onNodeClick]);
18
+ const handleSelectionChange = useCallback((params) => {
19
+ onSelectionChange?.({
20
+ nodes: params.nodes,
21
+ edges: params.edges,
22
+ });
23
+ }, [onSelectionChange]);
24
+ return (_jsx("div", { "data-slot": "workflow-canvas", className: cn('@container relative h-full w-full bg-muted/40', className), children: _jsxs(ReactFlow, { nodes: nodes, edges: edges, onNodesChange: readOnly ? undefined : onNodesChange, onEdgesChange: readOnly ? undefined : onEdgesChange, onConnect: readOnly ? undefined : onConnect, onNodeClick: onNodeClick ? handleNodeClick : undefined, onPaneClick: onPaneClick, onSelectionChange: onSelectionChange ? handleSelectionChange : undefined, nodeTypes: customNodeTypes ?? workflowNodeTypes, edgeTypes: customEdgeTypes ?? workflowEdgeTypes, fitView: true, fitViewOptions: { padding: 0.3, maxZoom: 1.1 }, nodesDraggable: !readOnly, nodesConnectable: !readOnly, elementsSelectable: !readOnly, panOnScroll: true, proOptions: { hideAttribution: true }, children: [_jsx(Background, { variant: BackgroundVariant.Dots, gap: 20, size: 1, color: "var(--color-border)" }), _jsx(Controls, { showInteractive: false, className: "!bg-background !border-border !shadow-sm [&>button]:!bg-background [&>button]:!border-border [&>button]:!text-foreground [&>button:hover]:!bg-muted" })] }) }));
25
+ }
@@ -0,0 +1,2 @@
1
+ import type { WorkflowCardCompactProps } from './types.js';
2
+ export declare function WorkflowCardCompact({ workflow, onClick, className }: WorkflowCardCompactProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,22 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Pause, Play, Zap } from 'lucide-react';
4
+ import { cn } from '../lib/utils.js';
5
+ const STATUS_CLASSES = {
6
+ draft: 'bg-muted text-muted-foreground',
7
+ active: 'bg-success-100 text-success-700 dark:bg-success-900/30 dark:text-success-400',
8
+ paused: 'bg-warning-100 text-warning-700 dark:bg-warning-900/30 dark:text-warning-400',
9
+ };
10
+ const STATUS_ICONS = {
11
+ draft: null,
12
+ active: _jsx(Play, { className: "h-3 w-3", "aria-hidden": true }),
13
+ paused: _jsx(Pause, { className: "h-3 w-3", "aria-hidden": true }),
14
+ };
15
+ export function WorkflowCardCompact({ workflow, onClick, className }) {
16
+ return (_jsxs("div", { "data-slot": "workflow-card-compact", "data-status": workflow.status, className: cn('cursor-pointer space-y-2 rounded-md border border-border bg-card p-3 transition-colors hover:bg-accent/50', className), onClick: onClick, onKeyDown: (e) => {
17
+ if (onClick && (e.key === 'Enter' || e.key === ' ')) {
18
+ e.preventDefault();
19
+ onClick();
20
+ }
21
+ }, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, children: [_jsx("div", { className: "truncate font-medium text-foreground text-sm", children: workflow.name }), workflow.description ? (_jsx("p", { className: "line-clamp-2 text-muted-foreground text-xs", children: workflow.description })) : null, _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs("span", { className: cn('inline-flex items-center gap-1 rounded-full px-2 py-0.5 font-medium text-xs', STATUS_CLASSES[workflow.status]), children: [STATUS_ICONS[workflow.status], _jsx("span", { className: "capitalize", children: workflow.status })] }), workflow.triggerLabel ? (_jsxs("span", { className: "inline-flex items-center gap-1 text-muted-foreground text-xs", children: [_jsx(Zap, { className: "h-3 w-3", "aria-hidden": true }), workflow.triggerLabel] })) : null] })] }));
22
+ }
@@ -0,0 +1,2 @@
1
+ import type { WorkflowCardProps } from './types.js';
2
+ export declare function WorkflowCard({ workflow, onClick, className }: WorkflowCardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,44 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Pause, Play, Zap } from 'lucide-react';
4
+ import { cn } from '../lib/utils.js';
5
+ const STATUS_CLASSES = {
6
+ draft: 'bg-muted text-muted-foreground',
7
+ active: 'bg-success-100 text-success-700 dark:bg-success-900/30 dark:text-success-400',
8
+ paused: 'bg-warning-100 text-warning-700 dark:bg-warning-900/30 dark:text-warning-400',
9
+ };
10
+ function formatRelative(ts) {
11
+ const diff = Date.now() - ts;
12
+ const seconds = Math.round(diff / 1000);
13
+ if (seconds < 60)
14
+ return 'just now';
15
+ const minutes = Math.round(seconds / 60);
16
+ if (minutes < 60)
17
+ return `${minutes}m ago`;
18
+ const hours = Math.round(minutes / 60);
19
+ if (hours < 24)
20
+ return `${hours}h ago`;
21
+ const days = Math.round(hours / 24);
22
+ return `${days}d ago`;
23
+ }
24
+ function getInitials(value) {
25
+ return value
26
+ .split(' ')
27
+ .map((part) => part[0] ?? '')
28
+ .join('')
29
+ .toUpperCase()
30
+ .slice(0, 2);
31
+ }
32
+ const STATUS_ICONS = {
33
+ draft: null,
34
+ active: _jsx(Play, { className: "h-3 w-3", "aria-hidden": true }),
35
+ paused: _jsx(Pause, { className: "h-3 w-3", "aria-hidden": true }),
36
+ };
37
+ export function WorkflowCard({ workflow, onClick, className }) {
38
+ return (_jsxs("div", { "data-slot": "workflow-card", "data-status": workflow.status, className: cn('group cursor-pointer rounded-lg border border-border bg-card p-4 shadow-sm transition-all hover:shadow-md', className), onClick: onClick, onKeyDown: (e) => {
39
+ if (onClick && (e.key === 'Enter' || e.key === ' ')) {
40
+ e.preventDefault();
41
+ onClick();
42
+ }
43
+ }, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, children: [_jsx("div", { className: "mb-3 flex items-start justify-between gap-3", children: _jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [_jsx("h3", { className: "truncate font-semibold text-base text-foreground", children: workflow.name }), workflow.description ? (_jsx("p", { className: "line-clamp-2 text-muted-foreground text-sm", children: workflow.description })) : null] }) }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs("span", { className: cn('inline-flex items-center gap-1 rounded-full px-2 py-0.5 font-medium text-xs', STATUS_CLASSES[workflow.status]), children: [STATUS_ICONS[workflow.status], _jsx("span", { className: "capitalize", children: workflow.status })] }), workflow.triggerLabel ? (_jsxs("span", { className: "inline-flex items-center gap-1 text-muted-foreground text-sm", children: [_jsx(Zap, { className: "h-3.5 w-3.5", "aria-hidden": true }), workflow.triggerLabel] })) : null] }), workflow.meta?.length ? (_jsx("dl", { className: "flex flex-wrap items-center gap-x-4 gap-y-1 text-muted-foreground text-sm", children: workflow.meta.map((m) => (_jsxs("div", { className: "flex items-center gap-1", children: [_jsxs("dt", { className: "font-medium", children: [m.label, ":"] }), _jsx("dd", { className: "tabular-nums", children: m.value })] }, m.label))) })) : null, workflow.creatorName || workflow.createdAt ? (_jsxs("div", { className: "flex items-center gap-2 text-muted-foreground text-xs", children: [workflow.creatorName ? (_jsxs("span", { className: "inline-flex items-center gap-1.5", children: [workflow.creatorAvatarUrl ? (_jsx("img", { src: workflow.creatorAvatarUrl, alt: "", className: "h-5 w-5 rounded-full" })) : (_jsx("span", { className: "inline-flex h-5 w-5 items-center justify-center rounded-full bg-muted font-medium text-[10px]", children: getInitials(workflow.creatorName) })), _jsx("span", { className: "truncate", children: workflow.creatorName })] })) : null, workflow.createdAt ? _jsx("span", { children: formatRelative(workflow.createdAt) }) : null] })) : null] })] }));
44
+ }
@@ -0,0 +1,2 @@
1
+ import { type WorkflowHeaderProps } from './types.js';
2
+ export declare function WorkflowHeader({ name, onNameChange, status, onSave, onPublish, onPause, onBack, isSaving, readOnly, labels, className, }: WorkflowHeaderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,31 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { ArrowLeft, Pause, Play, Save } from 'lucide-react';
4
+ import { useRef, useState } from 'react';
5
+ import { cn } from '../lib/utils.js';
6
+ import { defaultWorkflowBuilderLabels, } from './types.js';
7
+ const STATUS_CLASSES = {
8
+ draft: 'bg-muted text-muted-foreground',
9
+ active: 'bg-success-100 text-success-700 dark:bg-success-900/30 dark:text-success-400',
10
+ paused: 'bg-warning-100 text-warning-700 dark:bg-warning-900/30 dark:text-warning-400',
11
+ };
12
+ const STATUS_TEXT = {
13
+ draft: 'Draft',
14
+ active: 'Active',
15
+ paused: 'Paused',
16
+ };
17
+ export function WorkflowHeader({ name, onNameChange, status = 'draft', onSave, onPublish, onPause, onBack, isSaving = false, readOnly = false, labels, className, }) {
18
+ const resolvedLabels = { ...defaultWorkflowBuilderLabels, ...(labels ?? {}) };
19
+ const [isEditing, setIsEditing] = useState(false);
20
+ const inputRef = useRef(null);
21
+ const handleNameClick = () => {
22
+ if (readOnly || !onNameChange)
23
+ return;
24
+ setIsEditing(true);
25
+ setTimeout(() => inputRef.current?.select(), 0);
26
+ };
27
+ return (_jsxs("header", { "data-slot": "workflow-header", className: cn('flex h-14 items-center justify-between border-border border-b bg-background px-4', className), children: [_jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [onBack ? (_jsx("button", { type: "button", onClick: onBack, "aria-label": "Back", className: "inline-flex h-11 w-11 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground", children: _jsx(ArrowLeft, { className: "h-4 w-4", "aria-hidden": true }) })) : null, isEditing && onNameChange ? (_jsx("input", { ref: inputRef, value: name, onChange: (e) => onNameChange(e.target.value), onBlur: () => setIsEditing(false), onKeyDown: (e) => {
28
+ if (e.key === 'Enter' || e.key === 'Escape')
29
+ setIsEditing(false);
30
+ }, className: "h-9 w-64 rounded-md border border-border bg-background px-2 font-semibold text-foreground text-sm" })) : (_jsx("button", { type: "button", onClick: handleNameClick, disabled: readOnly || !onNameChange, className: "rounded-md px-2 py-1 font-semibold text-foreground text-sm transition-colors hover:bg-accent disabled:cursor-default disabled:hover:bg-transparent", children: name || 'Untitled workflow' })), _jsx("span", { "data-slot": "workflow-status-badge", className: cn('inline-flex items-center rounded-full px-2 py-0.5 font-medium text-xs', STATUS_CLASSES[status]), children: STATUS_TEXT[status] })] }), !readOnly ? (_jsxs("div", { className: "flex items-center gap-2", children: [(status === 'draft' || status === 'paused') && onPublish ? (_jsxs("button", { type: "button", onClick: onPublish, className: "inline-flex h-9 min-h-9 items-center gap-1.5 rounded-md border border-border bg-background px-3 font-medium text-sm transition-colors hover:bg-accent", children: [_jsx(Play, { className: "h-3.5 w-3.5", "aria-hidden": true }), resolvedLabels.publishAction] })) : null, status === 'active' && onPause ? (_jsxs("button", { type: "button", onClick: onPause, className: "inline-flex h-9 min-h-9 items-center gap-1.5 rounded-md border border-border bg-background px-3 font-medium text-sm transition-colors hover:bg-accent", children: [_jsx(Pause, { className: "h-3.5 w-3.5", "aria-hidden": true }), resolvedLabels.pauseAction] })) : null, onSave ? (_jsxs("button", { type: "button", onClick: onSave, disabled: isSaving, className: "inline-flex h-9 min-h-9 items-center gap-1.5 rounded-md bg-primary px-3 font-medium text-primary-foreground text-sm transition-colors hover:bg-primary/90 disabled:opacity-50", children: [_jsx(Save, { className: "h-3.5 w-3.5", "aria-hidden": true }), isSaving ? resolvedLabels.saving : resolvedLabels.saveAction] })) : null] })) : null] }));
31
+ }
@@ -0,0 +1,2 @@
1
+ import { type WorkflowToolboxProps } from './types.js';
2
+ export declare function WorkflowToolbox({ items, onAddNode, readOnly, labels, className, }: WorkflowToolboxProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,19 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { cn } from '../lib/utils.js';
4
+ import { renderWorkflowIcon } from './internal/trigger-icons.js';
5
+ import { defaultWorkflowBuilderLabels, } from './types.js';
6
+ function defaultItems(labels) {
7
+ return [
8
+ { kind: 'trigger', label: labels.addTrigger, iconName: 'zap' },
9
+ { kind: 'action', label: labels.addAction, iconName: 'send' },
10
+ { kind: 'condition', label: labels.addCondition, iconName: 'git-branch' },
11
+ { kind: 'delay', label: labels.addDelay, iconName: 'clock' },
12
+ { kind: 'end', label: labels.addEnd, iconName: 'flag' },
13
+ ];
14
+ }
15
+ export function WorkflowToolbox({ items, onAddNode, readOnly = false, labels, className, }) {
16
+ const resolvedLabels = { ...defaultWorkflowBuilderLabels, ...(labels ?? {}) };
17
+ const resolvedItems = items ?? defaultItems(resolvedLabels);
18
+ return (_jsxs("aside", { "data-slot": "workflow-toolbox", className: cn('flex h-full w-full flex-col border-border border-r bg-background', className), children: [_jsx("div", { className: "border-border border-b px-4 py-3", children: _jsx("h2", { className: "font-semibold text-foreground text-sm", children: resolvedLabels.toolboxTitle }) }), _jsx("div", { className: "flex-1 overflow-y-auto px-3 py-3", children: readOnly ? (_jsx("p", { className: "px-1 py-2 text-muted-foreground text-xs", children: resolvedLabels.toolboxReadOnlyHint })) : (_jsxs(_Fragment, { children: [_jsx("p", { className: "mb-2 px-1 text-muted-foreground text-xs", children: resolvedLabels.toolboxHint }), _jsx("ul", { className: "space-y-1.5", children: resolvedItems.map((item) => (_jsx("li", { children: _jsxs("button", { type: "button", "data-slot": "workflow-toolbox-item", "data-kind": item.kind, onClick: () => onAddNode?.(item.kind), className: "flex min-h-11 w-full items-center gap-2.5 rounded-md px-2 py-2.5 text-left text-sm transition-colors hover:bg-accent/60 focus-visible:bg-accent/80 focus-visible:outline-none", children: [_jsx("span", { className: "flex-shrink-0 text-muted-foreground", children: renderWorkflowIcon(item.kind, item.iconName, 'h-4 w-4') }), _jsx("span", { className: "flex-1 font-medium", children: item.label })] }) }, item.kind))) })] })) })] }));
19
+ }