@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.
- package/README.md +2 -1
- 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 +20 -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 +156 -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 +26 -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 +19 -0
- package/dist/email-builder/email-builder.d.ts +3 -0
- package/dist/email-builder/email-builder.js +84 -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 +52 -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 +52 -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 +219 -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/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 +31 -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 +32 -0
- package/dist/post-preview/platforms/facebook.d.ts +23 -0
- package/dist/post-preview/platforms/facebook.js +24 -0
- package/dist/post-preview/platforms/generic.d.ts +22 -0
- package/dist/post-preview/platforms/generic.js +28 -0
- package/dist/post-preview/platforms/google-business.d.ts +18 -0
- package/dist/post-preview/platforms/google-business.js +22 -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 +99 -0
- package/dist/post-preview/platforms/linkedin.d.ts +52 -0
- package/dist/post-preview/platforms/linkedin.js +131 -0
- package/dist/post-preview/platforms/telegram.d.ts +46 -0
- package/dist/post-preview/platforms/telegram.js +42 -0
- package/dist/post-preview/platforms/threads.d.ts +19 -0
- package/dist/post-preview/platforms/threads.js +24 -0
- package/dist/post-preview/platforms/tiktok.d.ts +18 -0
- package/dist/post-preview/platforms/tiktok.js +23 -0
- package/dist/post-preview/platforms/twitter.d.ts +40 -0
- package/dist/post-preview/platforms/twitter.js +132 -0
- package/dist/post-preview/platforms/youtube.d.ts +17 -0
- package/dist/post-preview/platforms/youtube.js +21 -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/app-shell-workspace.js +1 -1
- package/dist/shell/context-rail.d.ts +4 -2
- package/dist/shell/context-rail.js +27 -19
- package/dist/shell/extras/shell-scrollable-content.js +2 -2
- package/dist/shell/extras/workbench-layout.js +24 -13
- package/dist/shell/index.d.ts +1 -1
- package/dist/shell/internal/mobile-drawers.d.ts +6 -2
- package/dist/shell/internal/mobile-drawers.js +10 -7
- package/dist/shell/right-panel.js +10 -1
- package/dist/shell/shell-header.js +1 -1
- package/dist/shell/shell-provider.js +69 -53
- package/dist/shell/theme-next-themes.js +2 -2
- package/dist/shell/theme.js +7 -1
- package/dist/shell/types.d.ts +4 -0
- package/dist/shell/use-shell-viewport.js +14 -4
- 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 +25 -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 +31 -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
|
@@ -11,7 +11,7 @@ import { useTheme } from '../theme.js';
|
|
|
11
11
|
* any custom-content drawers. Mount once near the AppShell root; drawers
|
|
12
12
|
* open/close via `ctx.mobileDrawer.open` provider state.
|
|
13
13
|
*/
|
|
14
|
-
export function MobileDrawers({ menuItems = [], menuActiveId, menuRenderLink, workspaceMenuItems, workspaceMenuFooter, module, moduleAppId, panelViews = [], defaultView, customContent = {}, }) {
|
|
14
|
+
export function MobileDrawers({ menuItems = [], menuActiveId, menuRenderLink, workspaceMenuItems, workspaceMenuFooter, module, moduleAppId, moduleHeader, moduleScroll, panelViews = [], defaultView, customContent = {}, }) {
|
|
15
15
|
const ctx = useMedaShell();
|
|
16
16
|
const open = ctx.mobileDrawer.open;
|
|
17
17
|
const setOpen = ctx.mobileDrawer.setOpen;
|
|
@@ -24,7 +24,7 @@ export function MobileDrawers({ menuItems = [], menuActiveId, menuRenderLink, wo
|
|
|
24
24
|
workspaceId: ctx.workspace.id,
|
|
25
25
|
appId: moduleAppId ?? ctx.activeAppId,
|
|
26
26
|
};
|
|
27
|
-
return (_jsxs(_Fragment, { children: [_jsx(MenuDrawer, { open: open === 'menu-drawer', onClose: close, items: menuItems, activeId: menuActiveId, renderLink: menuRenderLink, workspaceItems: workspaceMenuItems, workspaceFooter: workspaceMenuFooter }), _jsx(ModuleDrawer, { open: open === 'module-drawer', onClose: close, module: module, renderCtx: moduleRenderCtx }), _jsx(PanelsDrawer, { open: open === 'panels-drawer', onClose: close, panelViews: panelViews, defaultView: defaultView, renderCtx: renderCtx }), _jsx(AiDrawer, { open: open === 'ai-drawer', onClose: close, panelViews: panelViews, renderCtx: renderCtx }), Object.entries(customContent).map(([id, renderFn]) => (_jsx(Drawer, { open: open === id, onOpenChange: (o) => !o && close(), direction: "bottom", children: _jsx(DrawerContent, { children: renderFn(close) }) }, id)))] }));
|
|
27
|
+
return (_jsxs(_Fragment, { children: [_jsx(MenuDrawer, { open: open === 'menu-drawer', onClose: close, items: menuItems, activeId: menuActiveId, renderLink: menuRenderLink, workspaceItems: workspaceMenuItems, workspaceFooter: workspaceMenuFooter }), _jsx(ModuleDrawer, { open: open === 'module-drawer', onClose: close, module: module, renderCtx: moduleRenderCtx, header: moduleHeader, scroll: moduleScroll }), _jsx(PanelsDrawer, { open: open === 'panels-drawer', onClose: close, panelViews: panelViews, defaultView: defaultView, renderCtx: renderCtx }), _jsx(AiDrawer, { open: open === 'ai-drawer', onClose: close, panelViews: panelViews, renderCtx: renderCtx }), Object.entries(customContent).map(([id, renderFn]) => (_jsx(Drawer, { open: open === id, onOpenChange: (o) => !o && close(), direction: "bottom", children: _jsx(DrawerContent, { children: renderFn(close) }) }, id)))] }));
|
|
28
28
|
}
|
|
29
29
|
// ---------------------------------------------------------------------------
|
|
30
30
|
// Internal sub-drawers
|
|
@@ -110,14 +110,17 @@ function MobileThemeMenuItem({ onClose }) {
|
|
|
110
110
|
onClose();
|
|
111
111
|
}, children: [_jsx(Icon, { size: 18, "aria-hidden": "true" }), _jsx("span", { children: THEME_LABEL[theme] })] }));
|
|
112
112
|
}
|
|
113
|
-
function ModuleDrawer({ open, onClose, module, renderCtx, }) {
|
|
113
|
+
function ModuleDrawer({ open, onClose, module, renderCtx, header = 'auto', scroll = 'auto', }) {
|
|
114
114
|
const items = module?.items ?? [];
|
|
115
115
|
if (!module || (items.length === 0 && !module.render))
|
|
116
116
|
return null;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
const hasRender = typeof module.render === 'function';
|
|
118
|
+
const showHeader = header === 'visible' || (header === 'auto' && items.length > 0 && !hasRender);
|
|
119
|
+
const title = (_jsxs(_Fragment, { children: [_jsx(DrawerTitle, { className: showHeader ? undefined : 'sr-only', children: module.label }), module.description && (_jsx(DrawerDescription, { className: showHeader ? 'text-muted-foreground text-xs' : 'sr-only', children: module.description }))] }));
|
|
120
|
+
return (_jsx(Drawer, { open: open, onOpenChange: (o) => !o && onClose(), direction: "left", children: _jsxs(DrawerContent, { children: [showHeader ? _jsx(DrawerHeader, { children: title }) : title, _jsxs("div", { "data-meda-context-rail-scroll-area": "", className: cn('min-h-0 flex-1', scroll === 'auto' ? 'overflow-y-auto overflow-x-hidden' : 'overflow-hidden'), children: [items.length > 0 && (_jsx("nav", { className: "flex flex-col gap-0.5 p-2", children: items.map((item) => {
|
|
121
|
+
const Icon = item.icon;
|
|
122
|
+
return (_jsxs("a", { href: item.to, onClick: onClose, className: "flex items-center gap-2 rounded-md px-3 py-2 text-sm text-muted-foreground hover:bg-accent hover:text-foreground", children: [_jsx(Icon, { size: 16, "aria-hidden": "true" }), _jsx("span", { children: item.label })] }, item.id));
|
|
123
|
+
}) })), module.render?.(renderCtx)] })] }) }));
|
|
121
124
|
}
|
|
122
125
|
function PanelsDrawer({ open, onClose, panelViews, defaultView, renderCtx, }) {
|
|
123
126
|
const ctx = useMedaShell();
|
|
@@ -123,7 +123,16 @@ export function RightPanel({ panelViews = EMPTY_PANEL_VIEWS, defaultView, modes
|
|
|
123
123
|
// Z-index escalation: fullscreen covers header + rails
|
|
124
124
|
const zIndexClass = mode === 'fullscreen' ? 'z-[var(--z-shell-fullscreen)]' : 'z-[var(--z-shell-panel)]';
|
|
125
125
|
const activePanelView = resolvedPanelViews.find((v) => v.id === activeView);
|
|
126
|
-
|
|
126
|
+
let cycleAriaLabel;
|
|
127
|
+
if (mode === 'panel') {
|
|
128
|
+
cycleAriaLabel = 'Expand panel';
|
|
129
|
+
}
|
|
130
|
+
else if (mode === 'expanded') {
|
|
131
|
+
cycleAriaLabel = 'Maximize panel';
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
cycleAriaLabel = 'Restore panel';
|
|
135
|
+
}
|
|
127
136
|
const handleResize = (w) => setDisplayWidth(w);
|
|
128
137
|
const handleCommit = (w) => {
|
|
129
138
|
setDisplayWidth(null);
|
|
@@ -83,7 +83,7 @@ export function AppTabs({ renderLink } = {}) {
|
|
|
83
83
|
},
|
|
84
84
|
}) }, app.id));
|
|
85
85
|
}
|
|
86
|
-
return (_jsx("button", { type: "button", "aria-current": isActive ? 'page' : undefined, onClick: handleClick, onMouseEnter: () =>
|
|
86
|
+
return (_jsx("button", { type: "button", "aria-current": isActive ? 'page' : undefined, onClick: handleClick, onMouseEnter: () => undefined, className: className, children: children }, app.id));
|
|
87
87
|
}) }));
|
|
88
88
|
}
|
|
89
89
|
// ---------------------------------------------------------------------------
|
|
@@ -107,63 +107,79 @@ export function MedaShellProvider(props) {
|
|
|
107
107
|
storage,
|
|
108
108
|
});
|
|
109
109
|
const isMobile = useShellViewport() === 'mobile';
|
|
110
|
+
const setPanelMode = useCallback((mode) => setLayoutState((prev) => ({
|
|
111
|
+
...prev,
|
|
112
|
+
rightPanel: { ...prev.rightPanel, mode },
|
|
113
|
+
})), [setLayoutState]);
|
|
114
|
+
const setPanelActiveView = useCallback((activeView) => setLayoutState((prev) => ({
|
|
115
|
+
...prev,
|
|
116
|
+
rightPanel: { ...prev.rightPanel, activeView },
|
|
117
|
+
})), [setLayoutState]);
|
|
118
|
+
const setPanelWidth = useCallback((width) => setLayoutState((prev) => ({
|
|
119
|
+
...prev,
|
|
120
|
+
rightPanel: { ...prev.rightPanel, width },
|
|
121
|
+
})), [setLayoutState]);
|
|
122
|
+
const openPanel = useCallback(() => {
|
|
123
|
+
if (isMobile)
|
|
124
|
+
setMobileDrawerOpen('panels-drawer');
|
|
125
|
+
setLayoutState((prev) => ({
|
|
126
|
+
...prev,
|
|
127
|
+
rightPanel: {
|
|
128
|
+
...prev.rightPanel,
|
|
129
|
+
mode: prev.rightPanel.mode === 'closed' ? 'panel' : prev.rightPanel.mode,
|
|
130
|
+
},
|
|
131
|
+
}));
|
|
132
|
+
}, [isMobile, setLayoutState]);
|
|
133
|
+
const closePanel = useCallback(() => {
|
|
134
|
+
if (isMobile)
|
|
135
|
+
setMobileDrawerOpen((open) => (open === 'panels-drawer' ? null : open));
|
|
136
|
+
setLayoutState((prev) => ({
|
|
137
|
+
...prev,
|
|
138
|
+
rightPanel: { ...prev.rightPanel, mode: 'closed' },
|
|
139
|
+
}));
|
|
140
|
+
}, [isMobile, setLayoutState]);
|
|
141
|
+
const togglePanel = useCallback(() => {
|
|
142
|
+
if (isMobile) {
|
|
143
|
+
setMobileDrawerOpen((open) => (open === 'panels-drawer' ? null : 'panels-drawer'));
|
|
144
|
+
}
|
|
145
|
+
setLayoutState((prev) => ({
|
|
146
|
+
...prev,
|
|
147
|
+
rightPanel: {
|
|
148
|
+
...prev.rightPanel,
|
|
149
|
+
mode: prev.rightPanel.mode === 'closed' ? 'panel' : 'closed',
|
|
150
|
+
},
|
|
151
|
+
}));
|
|
152
|
+
}, [isMobile, setLayoutState]);
|
|
153
|
+
const focusPanel = useCallback((viewId) => setLayoutState((prev) => {
|
|
154
|
+
const nextMode = prev.rightPanel.mode === 'closed' ? 'panel' : prev.rightPanel.mode;
|
|
155
|
+
return {
|
|
156
|
+
...prev,
|
|
157
|
+
rightPanel: { ...prev.rightPanel, mode: nextMode, activeView: viewId },
|
|
158
|
+
};
|
|
159
|
+
}), [setLayoutState]);
|
|
110
160
|
const panel = useMemo(() => ({
|
|
111
161
|
mode: layoutState.rightPanel.mode,
|
|
112
162
|
activeView: layoutState.rightPanel.activeView,
|
|
113
163
|
width: layoutState.rightPanel.width,
|
|
114
|
-
setMode:
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
mode: prev.rightPanel.mode === 'closed' ? 'panel' : prev.rightPanel.mode,
|
|
134
|
-
},
|
|
135
|
-
}));
|
|
136
|
-
},
|
|
137
|
-
close: () => {
|
|
138
|
-
if (isMobile)
|
|
139
|
-
setMobileDrawerOpen((open) => (open === 'panels-drawer' ? null : open));
|
|
140
|
-
setLayoutState((prev) => ({
|
|
141
|
-
...prev,
|
|
142
|
-
rightPanel: { ...prev.rightPanel, mode: 'closed' },
|
|
143
|
-
}));
|
|
144
|
-
},
|
|
145
|
-
toggle: () => {
|
|
146
|
-
if (isMobile) {
|
|
147
|
-
setMobileDrawerOpen((open) => (open === 'panels-drawer' ? null : 'panels-drawer'));
|
|
148
|
-
}
|
|
149
|
-
setLayoutState((prev) => ({
|
|
150
|
-
...prev,
|
|
151
|
-
rightPanel: {
|
|
152
|
-
...prev.rightPanel,
|
|
153
|
-
mode: prev.rightPanel.mode === 'closed' ? 'panel' : 'closed',
|
|
154
|
-
},
|
|
155
|
-
}));
|
|
156
|
-
},
|
|
157
|
-
// focus(viewId) — opens panel + switches to view in one call.
|
|
158
|
-
// Only flips closed → panel; preserves expanded / fullscreen modes.
|
|
159
|
-
focus: (viewId) => setLayoutState((prev) => {
|
|
160
|
-
const nextMode = prev.rightPanel.mode === 'closed' ? 'panel' : prev.rightPanel.mode;
|
|
161
|
-
return {
|
|
162
|
-
...prev,
|
|
163
|
-
rightPanel: { ...prev.rightPanel, mode: nextMode, activeView: viewId },
|
|
164
|
-
};
|
|
165
|
-
}),
|
|
166
|
-
}), [isMobile, layoutState, setLayoutState]);
|
|
164
|
+
setMode: setPanelMode,
|
|
165
|
+
setActiveView: setPanelActiveView,
|
|
166
|
+
setWidth: setPanelWidth,
|
|
167
|
+
open: openPanel,
|
|
168
|
+
close: closePanel,
|
|
169
|
+
toggle: togglePanel,
|
|
170
|
+
focus: focusPanel,
|
|
171
|
+
}), [
|
|
172
|
+
layoutState.rightPanel.mode,
|
|
173
|
+
layoutState.rightPanel.activeView,
|
|
174
|
+
layoutState.rightPanel.width,
|
|
175
|
+
setPanelMode,
|
|
176
|
+
setPanelActiveView,
|
|
177
|
+
setPanelWidth,
|
|
178
|
+
openPanel,
|
|
179
|
+
closePanel,
|
|
180
|
+
togglePanel,
|
|
181
|
+
focusPanel,
|
|
182
|
+
]);
|
|
167
183
|
const contextRail = useMemo(() => ({
|
|
168
184
|
width: layoutState.contextRail.width,
|
|
169
185
|
collapsed: layoutState.contextRail.collapsed,
|
|
@@ -46,7 +46,7 @@ function getClientThemeSnapshot() {
|
|
|
46
46
|
}
|
|
47
47
|
function subscribeToSystemTheme(mql, listener) {
|
|
48
48
|
if (!mql)
|
|
49
|
-
return () =>
|
|
49
|
+
return () => undefined;
|
|
50
50
|
if (typeof mql.addEventListener === 'function') {
|
|
51
51
|
mql.addEventListener('change', listener);
|
|
52
52
|
return () => mql.removeEventListener('change', listener);
|
|
@@ -55,7 +55,7 @@ function subscribeToSystemTheme(mql, listener) {
|
|
|
55
55
|
mql.addListener(listener);
|
|
56
56
|
return () => mql.removeListener?.(listener);
|
|
57
57
|
}
|
|
58
|
-
return () =>
|
|
58
|
+
return () => undefined;
|
|
59
59
|
}
|
|
60
60
|
export function NextThemesAdapter({ children }) {
|
|
61
61
|
const [theme, setThemeState] = useState('system');
|
package/dist/shell/theme.js
CHANGED
|
@@ -31,7 +31,13 @@ export function DefaultThemeProvider({ children }) {
|
|
|
31
31
|
useEffect(() => {
|
|
32
32
|
const mq = window.matchMedia('(prefers-color-scheme: dark)');
|
|
33
33
|
const apply = () => {
|
|
34
|
-
|
|
34
|
+
let resolved;
|
|
35
|
+
if (theme !== 'system') {
|
|
36
|
+
resolved = theme;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
resolved = mq.matches ? 'dark' : 'light';
|
|
40
|
+
}
|
|
35
41
|
setResolvedTheme(resolved);
|
|
36
42
|
document.documentElement.classList.toggle('dark', resolved === 'dark');
|
|
37
43
|
};
|
package/dist/shell/types.d.ts
CHANGED
|
@@ -50,6 +50,8 @@ export interface PanelView {
|
|
|
50
50
|
export type PanelMode = 'closed' | 'panel' | 'expanded' | 'fullscreen';
|
|
51
51
|
export type ShellMainLayout = 'workspace' | 'centered' | 'fullbleed';
|
|
52
52
|
export type ShellViewport = 'mobile' | 'tablet' | 'desktop' | 'wide' | 'ultrawide';
|
|
53
|
+
export type ContextRailHeader = 'auto' | 'visible' | 'hidden';
|
|
54
|
+
export type ContextRailScroll = 'auto' | 'none';
|
|
53
55
|
export interface MobileBottomNavItem {
|
|
54
56
|
id: string;
|
|
55
57
|
label: string | (() => string);
|
|
@@ -103,6 +105,8 @@ export interface AppShellContextRailConfig {
|
|
|
103
105
|
appId: string;
|
|
104
106
|
module: ContextModule;
|
|
105
107
|
activeItemId?: string;
|
|
108
|
+
header?: ContextRailHeader;
|
|
109
|
+
scroll?: ContextRailScroll;
|
|
106
110
|
}
|
|
107
111
|
/** RightPanel configuration for `<AppShell variant="workspace">`. */
|
|
108
112
|
export interface AppShellRightPanelConfig {
|
|
@@ -7,11 +7,18 @@ const BREAKPOINTS = {
|
|
|
7
7
|
wide: '(min-width: 1280px) and (max-width: 1535px)',
|
|
8
8
|
ultrawide: '(min-width: 1536px)',
|
|
9
9
|
};
|
|
10
|
-
function
|
|
10
|
+
function getMatchMedia() {
|
|
11
11
|
if (typeof window === 'undefined')
|
|
12
|
+
return null;
|
|
13
|
+
if (typeof window.matchMedia !== 'function')
|
|
14
|
+
return null;
|
|
15
|
+
return window.matchMedia.bind(window);
|
|
16
|
+
}
|
|
17
|
+
function detectViewport(matchMedia = getMatchMedia()) {
|
|
18
|
+
if (!matchMedia)
|
|
12
19
|
return 'desktop';
|
|
13
20
|
for (const [band, query] of Object.entries(BREAKPOINTS)) {
|
|
14
|
-
if (
|
|
21
|
+
if (matchMedia(query).matches)
|
|
15
22
|
return band;
|
|
16
23
|
}
|
|
17
24
|
return 'desktop';
|
|
@@ -21,9 +28,12 @@ export function useShellViewport() {
|
|
|
21
28
|
// client's first paint — actual band resolves in the post-mount effect.
|
|
22
29
|
const [viewport, setViewport] = useState('desktop');
|
|
23
30
|
useEffect(() => {
|
|
24
|
-
|
|
31
|
+
const matchMedia = getMatchMedia();
|
|
32
|
+
setViewport(detectViewport(matchMedia));
|
|
33
|
+
if (!matchMedia)
|
|
34
|
+
return;
|
|
25
35
|
const cleanups = Object.entries(BREAKPOINTS).map(([band, query]) => {
|
|
26
|
-
const mql =
|
|
36
|
+
const mql = matchMedia(query);
|
|
27
37
|
const onChange = () => {
|
|
28
38
|
if (mql.matches)
|
|
29
39
|
setViewport(band);
|
|
@@ -65,7 +65,7 @@ function formatTime(d) {
|
|
|
65
65
|
}
|
|
66
66
|
function buildTicks(start, end, range) {
|
|
67
67
|
const span = end.getTime() - start.getTime();
|
|
68
|
-
const tickCount = range === '
|
|
68
|
+
const tickCount = range === '24h' ? 8 : 7;
|
|
69
69
|
const out = [];
|
|
70
70
|
for (let i = 0; i <= tickCount; i++) {
|
|
71
71
|
const t = new Date(start.getTime() + (span * i) / tickCount);
|
|
@@ -34,7 +34,7 @@ export function ScrubBar({ durationMs, positionMs, isLive = false, marks, onSeek
|
|
|
34
34
|
onSeek(Math.min(durationMs, positionMs + step));
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
|
-
return (_jsxs("div", { className: cn('rounded-2xl border border-border bg-card p-3.5', className), children: [_jsxs("div", { className: "mb-2.5 flex items-center justify-between", children: [_jsx("span", { className: "text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Timeline \u00B7 this call" }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsxs("span", { className: "px-1.5 text-[11px] tabular-nums text-muted-foreground", children: [formatDuration(positionMs), isLive ? ' / live' : ` / ${formatDuration(durationMs)}`] }), onSkipBack && (_jsx(TransportBtn, { label: "Skip back", onClick: onSkipBack, children: _jsx(SkipBack, { className: "size-3.5" }) })), showPlayPause && (_jsx(TransportBtn, { label: isPlayingValue ? 'Pause' : 'Play', variant: "primary", onClick: onPlayPause ?? (() =>
|
|
37
|
+
return (_jsxs("div", { className: cn('rounded-2xl border border-border bg-card p-3.5', className), children: [_jsxs("div", { className: "mb-2.5 flex items-center justify-between", children: [_jsx("span", { className: "text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Timeline \u00B7 this call" }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsxs("span", { className: "px-1.5 text-[11px] tabular-nums text-muted-foreground", children: [formatDuration(positionMs), isLive ? ' / live' : ` / ${formatDuration(durationMs)}`] }), onSkipBack && (_jsx(TransportBtn, { label: "Skip back", onClick: onSkipBack, children: _jsx(SkipBack, { className: "size-3.5" }) })), showPlayPause && (_jsx(TransportBtn, { label: isPlayingValue ? 'Pause' : 'Play', variant: "primary", onClick: onPlayPause ?? (() => undefined), children: isPlayingValue ? _jsx(Pause, { className: "size-3.5" }) : _jsx(Play, { className: "size-3.5" }) })), onSkipForward && (_jsx(TransportBtn, { label: "Skip forward", onClick: onSkipForward, children: _jsx(SkipForward, { className: "size-3.5" }) }))] })] }), _jsxs("div", { ref: trackRef, role: "slider", "aria-label": "Conversation position", "aria-valuemin": 0, "aria-valuemax": durationMs, "aria-valuenow": positionMs, onClick: handleSeek, onKeyDown: handleKeyDown, tabIndex: 0, className: "relative h-8 cursor-pointer overflow-hidden rounded-md bg-muted focus:outline-none focus:ring-2 focus:ring-primary/50", children: [_jsx("span", { "aria-hidden": "true", className: "absolute inset-y-0 left-0 bg-primary/10", style: { width: `${fillPct}%` } }), marks.map((m) => (_jsx("span", { "data-mark-kind": m.kind, title: m.label ?? m.kind, className: cn('absolute inset-y-1 w-0.5 rounded-sm', KIND_COLOR[m.kind]), style: { left: `${m.positionPct}%` } }, m.id))), _jsx("span", { "aria-hidden": "true", "data-chromatic": "ignore", className: "absolute -inset-y-0.5 w-0.5 bg-foreground", style: { left: `${fillPct}%` } })] }), _jsxs("div", { className: "flex justify-between pt-2 text-[10px] tabular-nums text-muted-foreground", children: [_jsx("span", { children: "0:00" }), _jsx("span", { children: isLive ? 'now' : formatDuration(durationMs) })] })] }));
|
|
38
38
|
}
|
|
39
39
|
function TransportBtn({ label, onClick, variant, children, }) {
|
|
40
40
|
return (_jsx("button", { type: "button", "aria-label": label, onClick: onClick, className: cn('inline-flex size-6 items-center justify-center rounded', variant === 'primary'
|
|
@@ -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;
|