@medalsocial/meda 2.0.0 → 2.2.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.
- package/dist/calendar/calendar-toolbar.d.ts +2 -0
- package/dist/calendar/calendar-toolbar.js +22 -0
- package/dist/calendar/calendar.d.ts +2 -0
- package/dist/calendar/calendar.js +55 -0
- package/dist/calendar/day-view.d.ts +2 -0
- package/dist/calendar/day-view.js +40 -0
- package/dist/calendar/index.d.ts +6 -0
- package/dist/calendar/index.js +7 -0
- package/dist/calendar/internal/date.d.ts +26 -0
- package/dist/calendar/internal/date.js +107 -0
- package/dist/calendar/internal/day-cell.d.ts +15 -0
- package/dist/calendar/internal/day-cell.js +38 -0
- package/dist/calendar/internal/event-pill.d.ts +13 -0
- package/dist/calendar/internal/event-pill.js +30 -0
- package/dist/calendar/internal/time-slot.d.ts +17 -0
- package/dist/calendar/internal/time-slot.js +23 -0
- package/dist/calendar/month-view.d.ts +2 -0
- package/dist/calendar/month-view.js +46 -0
- package/dist/calendar/public.d.ts +6 -0
- package/dist/calendar/public.js +8 -0
- package/dist/calendar/types.d.ts +113 -0
- package/dist/calendar/types.js +15 -0
- package/dist/calendar/week-view.d.ts +2 -0
- package/dist/calendar/week-view.js +39 -0
- package/dist/chat/turn-card.js +10 -5
- package/dist/email-builder/block-error-boundary.d.ts +16 -0
- package/dist/email-builder/block-error-boundary.js +21 -0
- package/dist/email-builder/block-palette.d.ts +7 -0
- package/dist/email-builder/block-palette.js +22 -0
- package/dist/email-builder/block-registry.d.ts +15 -0
- package/dist/email-builder/block-registry.js +157 -0
- package/dist/email-builder/block-renderer.d.ts +5 -0
- package/dist/email-builder/block-renderer.js +40 -0
- package/dist/email-builder/block-renderers/button.d.ts +4 -0
- package/dist/email-builder/block-renderers/button.js +26 -0
- package/dist/email-builder/block-renderers/columns.d.ts +5 -0
- package/dist/email-builder/block-renderers/columns.js +27 -0
- package/dist/email-builder/block-renderers/divider.d.ts +4 -0
- package/dist/email-builder/block-renderers/divider.js +14 -0
- package/dist/email-builder/block-renderers/footer.d.ts +4 -0
- package/dist/email-builder/block-renderers/footer.js +12 -0
- package/dist/email-builder/block-renderers/heading.d.ts +4 -0
- package/dist/email-builder/block-renderers/heading.js +19 -0
- package/dist/email-builder/block-renderers/image.d.ts +4 -0
- package/dist/email-builder/block-renderers/image.js +18 -0
- package/dist/email-builder/block-renderers/social.d.ts +4 -0
- package/dist/email-builder/block-renderers/social.js +19 -0
- package/dist/email-builder/block-renderers/spacer.d.ts +4 -0
- package/dist/email-builder/block-renderers/spacer.js +5 -0
- package/dist/email-builder/block-renderers/text.d.ts +4 -0
- package/dist/email-builder/block-renderers/text.js +17 -0
- package/dist/email-builder/builder-canvas.d.ts +15 -0
- package/dist/email-builder/builder-canvas.js +28 -0
- package/dist/email-builder/builder-header.d.ts +9 -0
- package/dist/email-builder/builder-header.js +8 -0
- package/dist/email-builder/builder-left-tabs.d.ts +11 -0
- package/dist/email-builder/builder-left-tabs.js +20 -0
- package/dist/email-builder/email-builder.d.ts +3 -0
- package/dist/email-builder/email-builder.js +94 -0
- package/dist/email-builder/envelope-card.d.ts +7 -0
- package/dist/email-builder/envelope-card.js +16 -0
- package/dist/email-builder/floating-bar.d.ts +13 -0
- package/dist/email-builder/floating-bar.js +9 -0
- package/dist/email-builder/index.d.ts +4 -0
- package/dist/email-builder/index.js +12 -0
- package/dist/email-builder/internal/builder-state-utils.d.ts +7 -0
- package/dist/email-builder/internal/builder-state-utils.js +53 -0
- package/dist/email-builder/internal/dnd-wrapper.d.ts +10 -0
- package/dist/email-builder/internal/dnd-wrapper.js +9 -0
- package/dist/email-builder/internal/email-font-options.d.ts +5 -0
- package/dist/email-builder/internal/email-font-options.js +12 -0
- package/dist/email-builder/mobile-drawers.d.ts +10 -0
- package/dist/email-builder/mobile-drawers.js +7 -0
- package/dist/email-builder/mobile-tab-bar.d.ts +10 -0
- package/dist/email-builder/mobile-tab-bar.js +9 -0
- package/dist/email-builder/property-editors/_shared.d.ts +58 -0
- package/dist/email-builder/property-editors/_shared.js +54 -0
- package/dist/email-builder/property-editors/button-editor.d.ts +7 -0
- package/dist/email-builder/property-editors/button-editor.js +10 -0
- package/dist/email-builder/property-editors/columns-editor.d.ts +7 -0
- package/dist/email-builder/property-editors/columns-editor.js +15 -0
- package/dist/email-builder/property-editors/divider-editor.d.ts +7 -0
- package/dist/email-builder/property-editors/divider-editor.js +10 -0
- package/dist/email-builder/property-editors/footer-editor.d.ts +7 -0
- package/dist/email-builder/property-editors/footer-editor.js +6 -0
- package/dist/email-builder/property-editors/heading-editor.d.ts +7 -0
- package/dist/email-builder/property-editors/heading-editor.js +16 -0
- package/dist/email-builder/property-editors/image-editor.d.ts +8 -0
- package/dist/email-builder/property-editors/image-editor.js +17 -0
- package/dist/email-builder/property-editors/social-editor.d.ts +7 -0
- package/dist/email-builder/property-editors/social-editor.js +18 -0
- package/dist/email-builder/property-editors/spacer-editor.d.ts +7 -0
- package/dist/email-builder/property-editors/spacer-editor.js +6 -0
- package/dist/email-builder/property-editors/text-editor.d.ts +13 -0
- package/dist/email-builder/property-editors/text-editor.js +8 -0
- package/dist/email-builder/property-inspector.d.ts +11 -0
- package/dist/email-builder/property-inspector.js +42 -0
- package/dist/email-builder/public.d.ts +1 -0
- package/dist/email-builder/public.js +3 -0
- package/dist/email-builder/render-to-email-html.d.ts +11 -0
- package/dist/email-builder/render-to-email-html.js +220 -0
- package/dist/email-builder/starter-shell.d.ts +3 -0
- package/dist/email-builder/starter-shell.js +21 -0
- package/dist/email-builder/types.d.ts +182 -0
- package/dist/email-builder/types.js +41 -0
- package/dist/email-builder/view-controls.d.ts +10 -0
- package/dist/email-builder/view-controls.js +12 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/lib/format-time.js +2 -3
- package/dist/marketing/index.d.ts +10 -1
- package/dist/marketing/index.js +9 -0
- package/dist/marketing/marketing-bento-card.d.ts +2 -0
- package/dist/marketing/marketing-bento-card.js +24 -0
- package/dist/marketing/marketing-bento-grid.d.ts +2 -0
- package/dist/marketing/marketing-bento-grid.js +12 -0
- package/dist/marketing/marketing-faq.d.ts +2 -0
- package/dist/marketing/marketing-faq.js +12 -0
- package/dist/marketing/marketing-footer.d.ts +2 -0
- package/dist/marketing/marketing-footer.js +5 -0
- package/dist/marketing/marketing-header-logo.d.ts +10 -0
- package/dist/marketing/marketing-header-logo.js +6 -0
- package/dist/marketing/marketing-header.d.ts +2 -0
- package/dist/marketing/marketing-header.js +26 -0
- package/dist/marketing/marketing-nav-item.d.ts +4 -0
- package/dist/marketing/marketing-nav-item.js +10 -0
- package/dist/marketing/marketing-shell.d.ts +2 -0
- package/dist/marketing/marketing-shell.js +5 -0
- package/dist/marketing/marketing-trust-bar.d.ts +2 -0
- package/dist/marketing/marketing-trust-bar.js +5 -0
- package/dist/marketing/public.d.ts +1 -1
- package/dist/marketing/types.d.ts +99 -0
- package/dist/post-preview/index.d.ts +4 -0
- package/dist/post-preview/index.js +7 -0
- package/dist/post-preview/internal/avatar.d.ts +12 -0
- package/dist/post-preview/internal/avatar.js +21 -0
- package/dist/post-preview/internal/format-content.d.ts +12 -0
- package/dist/post-preview/internal/format-content.js +32 -0
- package/dist/post-preview/internal/platform-meta.d.ts +10 -0
- package/dist/post-preview/internal/platform-meta.js +18 -0
- package/dist/post-preview/internal/textarea.d.ts +8 -0
- package/dist/post-preview/internal/textarea.js +12 -0
- package/dist/post-preview/internal/use-swipe.d.ts +17 -0
- package/dist/post-preview/internal/use-swipe.js +29 -0
- package/dist/post-preview/platforms/bluesky.d.ts +15 -0
- package/dist/post-preview/platforms/bluesky.js +21 -0
- package/dist/post-preview/platforms/discord.d.ts +44 -0
- package/dist/post-preview/platforms/discord.js +34 -0
- package/dist/post-preview/platforms/facebook.d.ts +23 -0
- package/dist/post-preview/platforms/facebook.js +26 -0
- package/dist/post-preview/platforms/generic.d.ts +22 -0
- package/dist/post-preview/platforms/generic.js +30 -0
- package/dist/post-preview/platforms/google-business.d.ts +18 -0
- package/dist/post-preview/platforms/google-business.js +24 -0
- package/dist/post-preview/platforms/index.d.ts +24 -0
- package/dist/post-preview/platforms/index.js +13 -0
- package/dist/post-preview/platforms/instagram.d.ts +31 -0
- package/dist/post-preview/platforms/instagram.js +104 -0
- package/dist/post-preview/platforms/linkedin.d.ts +52 -0
- package/dist/post-preview/platforms/linkedin.js +140 -0
- package/dist/post-preview/platforms/telegram.d.ts +46 -0
- package/dist/post-preview/platforms/telegram.js +44 -0
- package/dist/post-preview/platforms/threads.d.ts +19 -0
- package/dist/post-preview/platforms/threads.js +26 -0
- package/dist/post-preview/platforms/tiktok.d.ts +18 -0
- package/dist/post-preview/platforms/tiktok.js +25 -0
- package/dist/post-preview/platforms/twitter.d.ts +40 -0
- package/dist/post-preview/platforms/twitter.js +137 -0
- package/dist/post-preview/platforms/youtube.d.ts +17 -0
- package/dist/post-preview/platforms/youtube.js +23 -0
- package/dist/post-preview/post-preview.d.ts +29 -0
- package/dist/post-preview/post-preview.js +70 -0
- package/dist/post-preview/public.d.ts +1 -0
- package/dist/post-preview/public.js +6 -0
- package/dist/post-preview/types.d.ts +82 -0
- package/dist/post-preview/types.js +1 -0
- package/dist/primitives/filter-rail.js +17 -2
- package/dist/shell/command-palette.js +2 -0
- package/dist/shell/drag-mode-banner.js +4 -0
- package/dist/shell/extras/shell-scrollable-content.js +2 -2
- package/dist/shell/extras/workbench-layout.js +24 -13
- package/dist/shell/internal/mobile-bottom-nav.js +1 -0
- package/dist/shell/internal/mobile-drawers.js +5 -0
- package/dist/shell/rail-drop-slot.js +20 -3
- package/dist/shell/rail-drop-zones.js +2 -0
- package/dist/shell/right-panel.js +10 -1
- package/dist/shell/shell-header.js +7 -1
- package/dist/shell/theme-next-themes.js +7 -2
- package/dist/shell/theme.js +7 -1
- package/dist/shell/use-shell-viewport.js +2 -0
- package/dist/timeline/lane-timeline.js +1 -1
- package/dist/timeline/scrub-bar.js +1 -1
- package/dist/timeline/timeline-tape.js +8 -5
- package/dist/voice/voice-orb-scene.js +4 -4
- package/dist/voice/voice-status-pill.js +8 -7
- package/dist/workflow-builder/edges/default-edge.d.ts +10 -0
- package/dist/workflow-builder/edges/default-edge.js +21 -0
- package/dist/workflow-builder/edges/index.d.ts +3 -0
- package/dist/workflow-builder/edges/index.js +5 -0
- package/dist/workflow-builder/index.d.ts +5 -0
- package/dist/workflow-builder/index.js +12 -0
- package/dist/workflow-builder/internal/trigger-icons.d.ts +4 -0
- package/dist/workflow-builder/internal/trigger-icons.js +43 -0
- package/dist/workflow-builder/internal/trigger-sentence.d.ts +14 -0
- package/dist/workflow-builder/internal/trigger-sentence.js +50 -0
- package/dist/workflow-builder/nodes/action-node.d.ts +3 -0
- package/dist/workflow-builder/nodes/action-node.js +7 -0
- package/dist/workflow-builder/nodes/base-node.d.ts +20 -0
- package/dist/workflow-builder/nodes/base-node.js +18 -0
- package/dist/workflow-builder/nodes/condition-node.d.ts +3 -0
- package/dist/workflow-builder/nodes/condition-node.js +11 -0
- package/dist/workflow-builder/nodes/delay-node.d.ts +3 -0
- package/dist/workflow-builder/nodes/delay-node.js +7 -0
- package/dist/workflow-builder/nodes/end-node.d.ts +3 -0
- package/dist/workflow-builder/nodes/end-node.js +7 -0
- package/dist/workflow-builder/nodes/index.d.ts +13 -0
- package/dist/workflow-builder/nodes/index.js +22 -0
- package/dist/workflow-builder/nodes/trigger-node.d.ts +3 -0
- package/dist/workflow-builder/nodes/trigger-node.js +8 -0
- package/dist/workflow-builder/public.d.ts +1 -0
- package/dist/workflow-builder/public.js +4 -0
- package/dist/workflow-builder/types.d.ts +140 -0
- package/dist/workflow-builder/types.js +18 -0
- package/dist/workflow-builder/workflow-builder.d.ts +10 -0
- package/dist/workflow-builder/workflow-builder.js +22 -0
- package/dist/workflow-builder/workflow-canvas.d.ts +26 -0
- package/dist/workflow-builder/workflow-canvas.js +29 -0
- package/dist/workflow-builder/workflow-card-compact.d.ts +2 -0
- package/dist/workflow-builder/workflow-card-compact.js +22 -0
- package/dist/workflow-builder/workflow-card.d.ts +2 -0
- package/dist/workflow-builder/workflow-card.js +44 -0
- package/dist/workflow-builder/workflow-header.d.ts +2 -0
- package/dist/workflow-builder/workflow-header.js +32 -0
- package/dist/workflow-builder/workflow-toolbox.d.ts +2 -0
- package/dist/workflow-builder/workflow-toolbox.js +19 -0
- package/package.json +72 -50
- package/dist/styles/theme.test.ts +0 -41
|
@@ -6,6 +6,13 @@ import { EventCard } from './event-card.js';
|
|
|
6
6
|
const DEFAULT_PX_PER_SEC = 1.2;
|
|
7
7
|
const DEFAULT_FUTURE_PAD_SEC = 300;
|
|
8
8
|
const DEFAULT_PAST_SPAN_SEC = 6 * 60 * 60;
|
|
9
|
+
function getSegmentColorClass(event) {
|
|
10
|
+
if (event.isLive)
|
|
11
|
+
return 'bg-success-600 shadow-[0_0_12px_rgba(16,185,129,0.5)]';
|
|
12
|
+
if (event.kind === 'error')
|
|
13
|
+
return 'bg-destructive';
|
|
14
|
+
return 'bg-info-500 shadow-[0_0_8px_rgba(56,189,248,0.35)]';
|
|
15
|
+
}
|
|
9
16
|
/** Convert a unix-ms instant to canvas y (px). y=0 at canvas top. */
|
|
10
17
|
function instantToY(instantMs, nowMs, pxPerSec, futurePadSec) {
|
|
11
18
|
const secsAfterNow = (instantMs - nowMs) / 1000;
|
|
@@ -53,11 +60,7 @@ export function TimelineTape({ now, events, pxPerSec = DEFAULT_PX_PER_SEC, futur
|
|
|
53
60
|
const height = Math.max(2, Math.abs(endY - startY));
|
|
54
61
|
return { event: e, top, height };
|
|
55
62
|
});
|
|
56
|
-
return (_jsxs("div", { className: cn('relative ml-3.5 mr-3', className), style: { height: `${canvasHeight}px` }, "data-canvas-height": canvasHeight, children: [ticks.map((t) => t.major ? (_jsxs("div", { children: [_jsx("span", { className: "absolute left-0 w-[30px] -translate-y-[7px] text-right text-[11px] font-medium tabular-nums text-muted-foreground", style: { top: `${t.y}px` }, children: t.label }), _jsx("span", { className: "absolute h-px w-2 bg-border", style: { left: 32, top: `${t.y}px` } })] }, `maj-${t.y}`)) : (_jsx("span", { className: "absolute h-px w-1.5 bg-border/40", style: { left: 35, top: `${t.y}px` } }, `min-${t.y}`))), segments.map(({ event, top, height }) => (_jsx("span", { "aria-hidden": "true", "data-tape-segment-id": event.id, "data-tape-segment-live": String(event.isLive ?? false), className: cn('absolute w-1 rounded-sm', event.
|
|
57
|
-
? 'bg-success-600 shadow-[0_0_12px_rgba(16,185,129,0.5)]'
|
|
58
|
-
: event.kind === 'error'
|
|
59
|
-
? 'bg-destructive'
|
|
60
|
-
: 'bg-info-500 shadow-[0_0_8px_rgba(56,189,248,0.35)]'), style: { left: 44, top: `${top}px`, height: `${height}px` } }, `seg-${event.id}`))), events.map((event) => {
|
|
63
|
+
return (_jsxs("div", { className: cn('relative ml-3.5 mr-3', className), style: { height: `${canvasHeight}px` }, "data-canvas-height": canvasHeight, children: [ticks.map((t) => t.major ? (_jsxs("div", { children: [_jsx("span", { className: "absolute left-0 w-[30px] -translate-y-[7px] text-right text-[11px] font-medium tabular-nums text-muted-foreground", style: { top: `${t.y}px` }, children: t.label }), _jsx("span", { className: "absolute h-px w-2 bg-border", style: { left: 32, top: `${t.y}px` } })] }, `maj-${t.y}`)) : (_jsx("span", { className: "absolute h-px w-1.5 bg-border/40", style: { left: 35, top: `${t.y}px` } }, `min-${t.y}`))), segments.map(({ event, top, height }) => (_jsx("span", { "aria-hidden": "true", "data-tape-segment-id": event.id, "data-tape-segment-live": String(event.isLive ?? false), className: cn('absolute w-1 rounded-sm', getSegmentColorClass(event)), style: { left: 44, top: `${top}px`, height: `${height}px` } }, `seg-${event.id}`))), events.map((event) => {
|
|
61
64
|
const startY = instantToY(event.startedAt, nowMs, pxPerSec, futurePadSec);
|
|
62
65
|
const isSubEvent = event.kind === 'sub-event';
|
|
63
66
|
return (_jsx("div", { "data-event-id": event.id, className: "absolute", style: { top: `${startY}px`, left: 56, right: 0 }, children: _jsx(EventCard, { event: event, size: isSubEvent ? 'tiny' : 'default', onSelect: onSelect }) }, event.id));
|
|
@@ -23,13 +23,13 @@ const PHASE_TARGET = {
|
|
|
23
23
|
function splitmix32(seed) {
|
|
24
24
|
let a = seed;
|
|
25
25
|
return () => {
|
|
26
|
-
a = (a +
|
|
26
|
+
a = (a + 0x9e_37_79_b9) | 0;
|
|
27
27
|
let t = a ^ (a >>> 16);
|
|
28
|
-
t = Math.imul(t,
|
|
28
|
+
t = Math.imul(t, 0x21_f0_aa_ad);
|
|
29
29
|
t = t ^ (t >>> 15);
|
|
30
|
-
t = Math.imul(t,
|
|
30
|
+
t = Math.imul(t, 0x73_5a_2d_97);
|
|
31
31
|
t = t ^ (t >>> 15);
|
|
32
|
-
return (t >>> 0) /
|
|
32
|
+
return (t >>> 0) / 4_294_967_296;
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
export function Scene({ level = 0, outputLevel = 0, phase = 'idle', colors, reducedMotion = false, pressed = false, variant = 'aurora', }) {
|
|
@@ -9,13 +9,14 @@ const PHASE_LABEL = {
|
|
|
9
9
|
error: 'Error',
|
|
10
10
|
};
|
|
11
11
|
export function VoiceStatusPill({ phase, thinkingForMs, className }) {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
const TONE_MAP = {
|
|
13
|
+
listening: 'bg-primary text-primary-foreground',
|
|
14
|
+
speaking: 'bg-success text-success-foreground',
|
|
15
|
+
error: 'bg-destructive text-destructive-foreground',
|
|
16
|
+
idle: 'bg-muted text-muted-foreground',
|
|
17
|
+
thinking: 'bg-muted text-muted-foreground',
|
|
18
|
+
};
|
|
19
|
+
const tone = TONE_MAP[phase];
|
|
19
20
|
const seconds = thinkingForMs ? (thinkingForMs / 1000).toFixed(1) : null;
|
|
20
21
|
return (_jsxs("span", { role: "status", "data-phase": phase, className: cn('inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-medium', tone, className), children: [_jsx("span", { className: cn('size-1.5 rounded-full bg-current', phase === 'thinking' && 'animate-pulse') }), PHASE_LABEL[phase], phase === 'thinking' && seconds && _jsxs("span", { children: ["\u00B7 ", seconds, "s"] })] }));
|
|
21
22
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type EdgeProps } from '@xyflow/react';
|
|
2
|
+
interface DefaultEdgeData {
|
|
3
|
+
readOnly?: boolean;
|
|
4
|
+
}
|
|
5
|
+
type DefaultWorkflowEdgeProps = EdgeProps & {
|
|
6
|
+
data?: DefaultEdgeData;
|
|
7
|
+
};
|
|
8
|
+
declare function DefaultWorkflowEdgeComponent({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style, markerEnd, }: DefaultWorkflowEdgeProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare const DefaultWorkflowEdge: import("react").MemoExoticComponent<typeof DefaultWorkflowEdgeComponent>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { BaseEdge, getBezierPath } from '@xyflow/react';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
function DefaultWorkflowEdgeComponent({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style, markerEnd, }) {
|
|
6
|
+
const [edgePath] = getBezierPath({
|
|
7
|
+
sourceX,
|
|
8
|
+
sourceY,
|
|
9
|
+
sourcePosition,
|
|
10
|
+
targetX,
|
|
11
|
+
targetY,
|
|
12
|
+
targetPosition,
|
|
13
|
+
});
|
|
14
|
+
const edgeStyle = {
|
|
15
|
+
...style,
|
|
16
|
+
stroke: 'var(--color-border)',
|
|
17
|
+
strokeWidth: 2,
|
|
18
|
+
};
|
|
19
|
+
return _jsx(BaseEdge, { path: edgePath, markerEnd: markerEnd, style: edgeStyle });
|
|
20
|
+
}
|
|
21
|
+
export const DefaultWorkflowEdge = memo(DefaultWorkflowEdgeComponent);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { WorkflowBuilderLabels, WorkflowBuilderProps, WorkflowCardCompactProps, WorkflowCardProps, WorkflowEdge, WorkflowHeaderProps, WorkflowNode, WorkflowNodeData, WorkflowNodeKind, WorkflowStatus, WorkflowSummary, WorkflowToolboxItem, } from './types.js';
|
|
2
|
+
export { defaultWorkflowBuilderLabels } from './types.js';
|
|
3
|
+
export { WorkflowBuilder } from './workflow-builder.js';
|
|
4
|
+
export { WorkflowCard } from './workflow-card.js';
|
|
5
|
+
export { WorkflowCardCompact } from './workflow-card-compact.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// open/meda/src/workflow-builder/index.ts
|
|
2
|
+
//
|
|
3
|
+
// Subpath barrel for `@medalsocial/meda/workflow-builder`.
|
|
4
|
+
//
|
|
5
|
+
// Top-level `WorkflowBuilder` component plus the sibling list-row components
|
|
6
|
+
// (`WorkflowCard`, `WorkflowCardCompact`) used to render workflow summaries
|
|
7
|
+
// outside of the builder. Canvas, header, toolbox, nodes, edges, and node
|
|
8
|
+
// helpers remain internal implementation details.
|
|
9
|
+
export { defaultWorkflowBuilderLabels } from './types.js';
|
|
10
|
+
export { WorkflowBuilder } from './workflow-builder.js';
|
|
11
|
+
export { WorkflowCard } from './workflow-card.js';
|
|
12
|
+
export { WorkflowCardCompact } from './workflow-card-compact.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ComponentType, ReactNode, SVGProps } from 'react';
|
|
2
|
+
import type { WorkflowNodeKind } from '../types.js';
|
|
3
|
+
export declare function resolveWorkflowIcon(kind: WorkflowNodeKind, iconName?: string): ComponentType<SVGProps<SVGSVGElement>>;
|
|
4
|
+
export declare function renderWorkflowIcon(kind: WorkflowNodeKind, iconName?: string, className?: string): ReactNode;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { AlertCircle, Bell, Bot, Clock, Flag, GitBranch, Mail, Play, Send, Square, Webhook, Zap, } from 'lucide-react';
|
|
4
|
+
/**
|
|
5
|
+
* Resolve a Lucide icon by free-form string. Unknown values fall back to
|
|
6
|
+
* `Zap` so consumers don't have to import lucide just to set an icon.
|
|
7
|
+
*/
|
|
8
|
+
const ICON_MAP = {
|
|
9
|
+
zap: Zap,
|
|
10
|
+
webhook: Webhook,
|
|
11
|
+
clock: Clock,
|
|
12
|
+
mail: Mail,
|
|
13
|
+
bell: Bell,
|
|
14
|
+
bot: Bot,
|
|
15
|
+
send: Send,
|
|
16
|
+
flag: Flag,
|
|
17
|
+
play: Play,
|
|
18
|
+
square: Square,
|
|
19
|
+
branch: GitBranch,
|
|
20
|
+
'git-branch': GitBranch,
|
|
21
|
+
alert: AlertCircle,
|
|
22
|
+
warning: AlertCircle,
|
|
23
|
+
};
|
|
24
|
+
/** Default icons per kind; used when the node data omits `iconName`. */
|
|
25
|
+
const KIND_ICONS = {
|
|
26
|
+
trigger: Zap,
|
|
27
|
+
action: Send,
|
|
28
|
+
condition: GitBranch,
|
|
29
|
+
delay: Clock,
|
|
30
|
+
end: Flag,
|
|
31
|
+
};
|
|
32
|
+
export function resolveWorkflowIcon(kind, iconName) {
|
|
33
|
+
if (iconName) {
|
|
34
|
+
const lower = iconName.toLowerCase();
|
|
35
|
+
if (ICON_MAP[lower])
|
|
36
|
+
return ICON_MAP[lower];
|
|
37
|
+
}
|
|
38
|
+
return KIND_ICONS[kind];
|
|
39
|
+
}
|
|
40
|
+
export function renderWorkflowIcon(kind, iconName, className = 'h-5 w-5') {
|
|
41
|
+
const Icon = resolveWorkflowIcon(kind, iconName);
|
|
42
|
+
return _jsx(Icon, { className: className, "aria-hidden": true });
|
|
43
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { WorkflowNodeKind } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Returns a short human-readable description for a workflow node based on its
|
|
4
|
+
* kind. Consumers can override per-node via `data.description`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getDefaultNodeSentence(kind: WorkflowNodeKind, label?: string): string;
|
|
7
|
+
/** Tailwind class tokens per kind. Mapped to the meda token system. */
|
|
8
|
+
export declare const NODE_KIND_STYLES: Record<WorkflowNodeKind, {
|
|
9
|
+
bg: string;
|
|
10
|
+
border: string;
|
|
11
|
+
icon: string;
|
|
12
|
+
}>;
|
|
13
|
+
export declare const NODE_WIDTH = 264;
|
|
14
|
+
export declare const NODE_HEIGHT = 80;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a short human-readable description for a workflow node based on its
|
|
3
|
+
* kind. Consumers can override per-node via `data.description`.
|
|
4
|
+
*/
|
|
5
|
+
export function getDefaultNodeSentence(kind, label) {
|
|
6
|
+
switch (kind) {
|
|
7
|
+
case 'trigger':
|
|
8
|
+
return label ? `When ${label.toLowerCase()}` : 'When event occurs';
|
|
9
|
+
case 'action':
|
|
10
|
+
return label ?? 'Run action';
|
|
11
|
+
case 'condition':
|
|
12
|
+
return label ?? 'Branch on condition';
|
|
13
|
+
case 'delay':
|
|
14
|
+
return label ?? 'Wait before continuing';
|
|
15
|
+
case 'end':
|
|
16
|
+
return label ?? 'End of workflow';
|
|
17
|
+
default:
|
|
18
|
+
return label ?? '';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Tailwind class tokens per kind. Mapped to the meda token system. */
|
|
22
|
+
export const NODE_KIND_STYLES = {
|
|
23
|
+
trigger: {
|
|
24
|
+
bg: 'bg-info-50 dark:bg-info-950/40',
|
|
25
|
+
border: 'border-info-300 dark:border-info-700',
|
|
26
|
+
icon: 'text-info-600 dark:text-info-400',
|
|
27
|
+
},
|
|
28
|
+
action: {
|
|
29
|
+
bg: 'bg-success-50 dark:bg-success-950/40',
|
|
30
|
+
border: 'border-success-300 dark:border-success-700',
|
|
31
|
+
icon: 'text-success-600 dark:text-success-400',
|
|
32
|
+
},
|
|
33
|
+
condition: {
|
|
34
|
+
bg: 'bg-brand-50 dark:bg-brand-950/40',
|
|
35
|
+
border: 'border-brand-300 dark:border-brand-700',
|
|
36
|
+
icon: 'text-brand-600 dark:text-brand-400',
|
|
37
|
+
},
|
|
38
|
+
delay: {
|
|
39
|
+
bg: 'bg-warning-50 dark:bg-warning-950/40',
|
|
40
|
+
border: 'border-warning-300 dark:border-warning-700',
|
|
41
|
+
icon: 'text-warning-600 dark:text-warning-400',
|
|
42
|
+
},
|
|
43
|
+
end: {
|
|
44
|
+
bg: 'bg-neutral-50 dark:bg-neutral-900/40',
|
|
45
|
+
border: 'border-neutral-300 dark:border-neutral-600',
|
|
46
|
+
icon: 'text-neutral-600 dark:text-neutral-400',
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
export const NODE_WIDTH = 264;
|
|
50
|
+
export const NODE_HEIGHT = 80;
|
|
@@ -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 ActionNode({ data, selected }) {
|
|
6
|
+
return (_jsx(BaseWorkflowNode, { kind: "action", selected: selected, icon: renderWorkflowIcon('action', data.iconName), label: data.label || 'Action', description: data.description, warning: data.state === 'warning' ? 'Needs config' : undefined }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Position } from '@xyflow/react';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import type { WorkflowNodeKind } from '../types.js';
|
|
4
|
+
export interface BaseWorkflowNodeProps {
|
|
5
|
+
kind: WorkflowNodeKind;
|
|
6
|
+
icon: ReactNode;
|
|
7
|
+
label: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
warning?: string;
|
|
10
|
+
selected?: boolean;
|
|
11
|
+
showSourceHandle?: boolean;
|
|
12
|
+
showTargetHandle?: boolean;
|
|
13
|
+
/** Optional named handles (e.g. for condition true/false branches). */
|
|
14
|
+
sourceHandles?: Array<{
|
|
15
|
+
id: string;
|
|
16
|
+
position: Position;
|
|
17
|
+
label?: string;
|
|
18
|
+
}>;
|
|
19
|
+
}
|
|
20
|
+
export declare function BaseWorkflowNode({ kind, icon, label, description, warning, selected, showSourceHandle, showTargetHandle, sourceHandles, }: BaseWorkflowNodeProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -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,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,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,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,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,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
|
+
}
|