@parallelworks/ui 0.37.0 → 0.38.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/ai/components/ChatSidebar.js +7 -4
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/index.js +2 -2
- package/dist/ai/ui/sidebar.d.ts +6 -0
- package/dist/ai/ui/sidebar.js +15 -1
- package/dist/form/FieldWrapper.js +1 -0
- package/dist/form/Form.js +64 -23
- package/dist/form/Wizard/WizardContainer.js +66 -6
- package/dist/form/Wizard/WizardStepContent.js +23 -10
- package/dist/form/Wizard/wizardPages.d.ts +12 -0
- package/dist/form/Wizard/wizardPages.js +5 -0
- package/dist/form/formEditing.d.ts +25 -0
- package/dist/form/formEditing.js +20 -0
- package/dist/graph/InputDialog.js +1568 -54
- package/dist/graph/InputsEditor.d.ts +12 -0
- package/dist/graph/InputsEditor.js +1594 -0
- package/dist/graph/ShortcutsButton.js +56 -0
- package/dist/graph/SuggestionInput.js +29 -0
- package/dist/graph/editorApi.js +8 -0
- package/dist/graph/editorChrome.js +75 -0
- package/dist/graph/editorFields.js +394 -0
- package/dist/graph/editorPrimitives.js +95 -4
- package/dist/graph/editorStrings.js +9 -1
- package/dist/graph/fieldProblems.js +77 -0
- package/dist/graph/index.d.ts +1 -0
- package/dist/graph/index.js +2 -1
- package/dist/graph/inputLayout.js +337 -0
- package/dist/graph/inputPages.d.ts +33 -0
- package/dist/graph/inputPages.js +186 -0
- package/dist/graph/inputRefs.js +196 -0
- package/dist/graph/inputRows.d.ts +43 -0
- package/dist/graph/inputRows.js +65 -0
- package/dist/graph/settingsViews.js +62 -0
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -2,18 +2,19 @@ import { FaRegFileImage } from "../../icons/fa/FaRegFileImage.js";
|
|
|
2
2
|
import { FaSearch } from "../../icons/fa/FaSearch.js";
|
|
3
3
|
import { FaUsers } from "../../icons/fa/FaUsers.js";
|
|
4
4
|
import { TbEdit } from "../../icons/tb/TbEdit.js";
|
|
5
|
+
import { useRelativeTime } from "../../components/relativeTime.js";
|
|
5
6
|
import { useChatConfig } from "../core/config.js";
|
|
6
7
|
import { useChat } from "../core/ChatProvider.js";
|
|
7
8
|
import { ManageProvidersLink } from "./ComposerChrome.js";
|
|
8
9
|
import { FOCUS_SIDEBAR_SEARCH_EVENT } from "../core/events.js";
|
|
9
|
-
import { SidebarPlaceholder, SidebarRow } from "../ui/sidebar.js";
|
|
10
|
+
import { SidebarPlaceholder, SidebarRow, SidebarRowTitle } from "../ui/sidebar.js";
|
|
10
11
|
import { ConversationSidebar } from "../ui/ConversationSidebar.js";
|
|
11
12
|
import { groupConversationsByDate, useConversationActions } from "./conversationActions.js";
|
|
12
13
|
import cx from "classnames";
|
|
13
14
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
14
15
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
15
16
|
//#region src/ai/components/ChatSidebar.tsx
|
|
16
|
-
function ConversationRow({ conv, isCurrent, menuItems, openMenu, onOpen }) {
|
|
17
|
+
function ConversationRow({ conv, isCurrent, updated, menuItems, openMenu, onOpen }) {
|
|
17
18
|
const { LinkComponent, strings } = useChatConfig();
|
|
18
19
|
const t = strings.sidebar;
|
|
19
20
|
return /* @__PURE__ */ jsx(SidebarRow, {
|
|
@@ -30,8 +31,8 @@ function ConversationRow({ conv, isCurrent, menuItems, openMenu, onOpen }) {
|
|
|
30
31
|
children: [conv.isOwner === false && /* @__PURE__ */ jsx(FaUsers, {
|
|
31
32
|
className: "h-3 w-3 shrink-0 theme-muted-text",
|
|
32
33
|
title: t.sharedWithYou
|
|
33
|
-
}), /* @__PURE__ */ jsx(
|
|
34
|
-
|
|
34
|
+
}), /* @__PURE__ */ jsx(SidebarRowTitle, {
|
|
35
|
+
time: updated,
|
|
35
36
|
children: conv.title || t.untitled
|
|
36
37
|
})]
|
|
37
38
|
})
|
|
@@ -43,6 +44,7 @@ function ChatSidebar({ actions = true, top }) {
|
|
|
43
44
|
const { adapter, navigation, activeConversationId, conversations, sidebar, sidebarPresentation, drawerOpen, setSidebar, setDrawerOpen, toggleSidebar, isLoading, loadConversations, clearCurrentConversation } = useChat();
|
|
44
45
|
const attachmentsAvailable = !!adapter.attachments;
|
|
45
46
|
const { menuItems, openMenu, overlays } = useConversationActions();
|
|
47
|
+
const { compact } = useRelativeTime();
|
|
46
48
|
const drawer = sidebarPresentation === "drawer";
|
|
47
49
|
const sidebarCollapsed = !drawer && sidebar !== "expanded";
|
|
48
50
|
const closeDrawer = () => setDrawerOpen(false);
|
|
@@ -106,6 +108,7 @@ function ChatSidebar({ actions = true, top }) {
|
|
|
106
108
|
renderRow: (conv) => /* @__PURE__ */ jsx(ConversationRow, {
|
|
107
109
|
conv,
|
|
108
110
|
isCurrent: activeConversationId === conv.id,
|
|
111
|
+
updated: compact(conv.updatedAt ?? conv.createdAt),
|
|
109
112
|
menuItems: menuItems(conv),
|
|
110
113
|
openMenu,
|
|
111
114
|
onOpen: closeDrawer
|
package/dist/ai/index.d.ts
CHANGED
|
@@ -43,5 +43,5 @@ export * from './types.js';
|
|
|
43
43
|
export { ConversationSidebar, type ConversationSidebarGroup, useResizableSidebarWidth, } from './ui/ConversationSidebar.js';
|
|
44
44
|
export { type DropdownOption, default as Dropdown } from './ui/Dropdown.js';
|
|
45
45
|
export { NoticeBar, NoticeCard, type NoticeTone, OutputCard } from './ui/Notice.js';
|
|
46
|
-
export { RenameDialog, type RowDialogStrings, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarToggle, useRowDialogs, } from './ui/sidebar.js';
|
|
46
|
+
export { RenameDialog, type RowDialogStrings, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, useRowDialogs, } from './ui/sidebar.js';
|
|
47
47
|
export { formatFileSize, isMac, isOrgModel } from './utils.js';
|
package/dist/ai/index.js
CHANGED
|
@@ -37,7 +37,7 @@ import ChatEmptyState from "./components/ChatEmptyState.js";
|
|
|
37
37
|
import { FOCUS_SIDEBAR_SEARCH_EVENT } from "./core/events.js";
|
|
38
38
|
import { useKeyboardShortcuts } from "./core/useKeyboardShortcuts.js";
|
|
39
39
|
import { KeyboardShortcutsProvider } from "./core/KeyboardShortcutsProvider.js";
|
|
40
|
-
import { RenameDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarToggle, useRowDialogs } from "./ui/sidebar.js";
|
|
40
|
+
import { RenameDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, useRowDialogs } from "./ui/sidebar.js";
|
|
41
41
|
import { ConversationSidebar, useResizableSidebarWidth } from "./ui/ConversationSidebar.js";
|
|
42
42
|
import ShareDialog, { ShareButton } from "./components/ShareDialog.js";
|
|
43
43
|
import { groupConversationsByDate, useConversationActions } from "./components/conversationActions.js";
|
|
@@ -46,4 +46,4 @@ import ChatLayout, { CHAT_COLUMN_SCOPE, ConversationLayout, DRAWER_BELOW_PX } fr
|
|
|
46
46
|
import ChatMessage_default from "./components/ChatMessage.js";
|
|
47
47
|
import ChatMessageList from "./components/ChatMessageList.js";
|
|
48
48
|
import ChatThread from "./components/ChatThread.js";
|
|
49
|
-
export { AGENT_COLOR_NAMES, ActivityLine, AgentMessageParts, AllocationSelector, ApprovalBlock, AttachmentManager, AttachmentUpload, BlockedGroupBanner, BranchNavigator, CHAT_COLUMN_SCOPE, ChatAdapterError, ChatEmptyState, ChatInput, ChatLayout, ChatMessageList, ChatMessage_default as ChatMessageView, ChatProvider, ChatSidebar, ChatStage, ChatThread, ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ConversationLayout, ConversationSidebar, DEFAULT_PERMISSION_MODE, DRAWER_BELOW_PX, DragOverlay, Dropdown, FOCUS_SIDEBAR_SEARCH_EVENT, INTERRUPTED_NOTICE, KeyboardShortcutsProvider, MAX_EDIT_DIFF_LINES, MAX_WRITE_DIFF_LINES, ManageProvidersLink, ModelSelector, NAMED_PERMISSION_MODES, NoticeBar, NoticeCard, OutputCard, PermissionPicker, ProviderIssueBanner, RenameDialog, ShareButton, ShareDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarToggle, agentColorHex, agentTypeLabel, applyPartDelta, askQuestionFromArgs, bashExitCode, chatReducer, clampPermissionMode, classifyPseudoUserMessage, clip, compactCount, computeEditDiff, computeWriteRows, defaultChatStrings, durationToAbsHumanDuration, editSummary, finalizeParts, firstNonEmptyLine, formatElapsed, formatFileSize, fullToolArgs, getGreeting, getProviderKeyFromModelId, groupConversationsByDate, hiddenTranscriptTool, initialState, interruptionNotice, isEditDiffTool, isGroupableTool, isMac, isNamedPermissionMode, isOrgModel, languageForPath, lineDelta, parseEditArgs, parseSubagentNotice, pasteInlineMaxBytes, permissionModesUpTo, planFromArgs, plural, providerIssueFor, resolveChatConfig, resultFailed, rollupSentence, sanitizeLabel, sanitizePanelText, slashMatches, subagentDeliveryLine, summarizeToolArgs, taskCallFromArgs, thinkingHeading, tokenizeDiffLines, toolHeaderFor, toolSummary, useChat, useChatConfig, useConversationActions, useDragDrop, useKeyboardShortcuts, useResizableSidebarWidth, useRowDialogs, wordEmphasisRanges };
|
|
49
|
+
export { AGENT_COLOR_NAMES, ActivityLine, AgentMessageParts, AllocationSelector, ApprovalBlock, AttachmentManager, AttachmentUpload, BlockedGroupBanner, BranchNavigator, CHAT_COLUMN_SCOPE, ChatAdapterError, ChatEmptyState, ChatInput, ChatLayout, ChatMessageList, ChatMessage_default as ChatMessageView, ChatProvider, ChatSidebar, ChatStage, ChatThread, ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ConversationLayout, ConversationSidebar, DEFAULT_PERMISSION_MODE, DRAWER_BELOW_PX, DragOverlay, Dropdown, FOCUS_SIDEBAR_SEARCH_EVENT, INTERRUPTED_NOTICE, KeyboardShortcutsProvider, MAX_EDIT_DIFF_LINES, MAX_WRITE_DIFF_LINES, ManageProvidersLink, ModelSelector, NAMED_PERMISSION_MODES, NoticeBar, NoticeCard, OutputCard, PermissionPicker, ProviderIssueBanner, RenameDialog, ShareButton, ShareDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, agentColorHex, agentTypeLabel, applyPartDelta, askQuestionFromArgs, bashExitCode, chatReducer, clampPermissionMode, classifyPseudoUserMessage, clip, compactCount, computeEditDiff, computeWriteRows, defaultChatStrings, durationToAbsHumanDuration, editSummary, finalizeParts, firstNonEmptyLine, formatElapsed, formatFileSize, fullToolArgs, getGreeting, getProviderKeyFromModelId, groupConversationsByDate, hiddenTranscriptTool, initialState, interruptionNotice, isEditDiffTool, isGroupableTool, isMac, isNamedPermissionMode, isOrgModel, languageForPath, lineDelta, parseEditArgs, parseSubagentNotice, pasteInlineMaxBytes, permissionModesUpTo, planFromArgs, plural, providerIssueFor, resolveChatConfig, resultFailed, rollupSentence, sanitizeLabel, sanitizePanelText, slashMatches, subagentDeliveryLine, summarizeToolArgs, taskCallFromArgs, thinkingHeading, tokenizeDiffLines, toolHeaderFor, toolSummary, useChat, useChatConfig, useConversationActions, useDragDrop, useKeyboardShortcuts, useResizableSidebarWidth, useRowDialogs, wordEmphasisRanges };
|
package/dist/ai/ui/sidebar.d.ts
CHANGED
|
@@ -43,6 +43,12 @@ export declare function SidebarPlaceholder({ children, testId, }: {
|
|
|
43
43
|
children: ReactNode;
|
|
44
44
|
testId?: string | undefined;
|
|
45
45
|
}): import("react").JSX.Element;
|
|
46
|
+
/** A row's first line, the same in every list: what it is, and when it last
|
|
47
|
+
* moved, abbreviated, on the right. */
|
|
48
|
+
export declare function SidebarRowTitle({ children, time, }: {
|
|
49
|
+
children: ReactNode;
|
|
50
|
+
time?: string | undefined;
|
|
51
|
+
}): import("react").JSX.Element;
|
|
46
52
|
/** One entry in the list: the row highlights while it is the open one or
|
|
47
53
|
* while its menu is up, and the menu opens from its button or a right-click. */
|
|
48
54
|
export declare function SidebarRow({ selected, menuItems, openMenu, className, children, }: {
|
package/dist/ai/ui/sidebar.js
CHANGED
|
@@ -85,6 +85,20 @@ function SidebarPlaceholder({ children, testId }) {
|
|
|
85
85
|
children
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
|
+
/** A row's first line, the same in every list: what it is, and when it last
|
|
89
|
+
* moved, abbreviated, on the right. */
|
|
90
|
+
function SidebarRowTitle({ children, time }) {
|
|
91
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
92
|
+
className: "flex min-w-0 flex-1 items-baseline gap-2",
|
|
93
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
94
|
+
className: "min-w-0 flex-1 truncate text-sm theme-text",
|
|
95
|
+
children
|
|
96
|
+
}), time && /* @__PURE__ */ jsx("span", {
|
|
97
|
+
className: "min-w-8 shrink-0 text-[11px] tabular-nums theme-muted-text",
|
|
98
|
+
children: time
|
|
99
|
+
})]
|
|
100
|
+
});
|
|
101
|
+
}
|
|
88
102
|
/** One entry in the list: the row highlights while it is the open one or
|
|
89
103
|
* while its menu is up, and the menu opens from its button or a right-click. */
|
|
90
104
|
function SidebarRow({ selected, menuItems, openMenu, className, children }) {
|
|
@@ -191,4 +205,4 @@ function useRowDialogs({ strings, nameOf, onDelete, onRename }) {
|
|
|
191
205
|
};
|
|
192
206
|
}
|
|
193
207
|
//#endregion
|
|
194
|
-
export { RenameDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarToggle, useRowDialogs };
|
|
208
|
+
export { RenameDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, useRowDialogs };
|
|
@@ -27,6 +27,7 @@ function FieldWrapper({ label, tooltipComponent, description, labelPosition = "l
|
|
|
27
27
|
children: [/* @__PURE__ */ jsxs("label", {
|
|
28
28
|
htmlFor: id,
|
|
29
29
|
id: labelId,
|
|
30
|
+
"data-field-label": true,
|
|
30
31
|
className: cx("relative", labelPosition === "left" ? "form-label" : "form-label-top", spaceCompact && "form-label-compact"),
|
|
31
32
|
children: [
|
|
32
33
|
label,
|
package/dist/form/Form.js
CHANGED
|
@@ -14,6 +14,7 @@ import { FormLayout, LayoutCSSContext } from "./FormLayout.js";
|
|
|
14
14
|
import { useFieldControlProps, useFieldRequired } from "./fieldContext.js";
|
|
15
15
|
import { getValueUsingPath } from "./utils/getValueUsingPath.js";
|
|
16
16
|
import { FieldRegistryContext, Registry } from "./fieldRegistry.js";
|
|
17
|
+
import { EditingScope, useFormEditing } from "./formEditing.js";
|
|
17
18
|
import { useParsedOpts } from "./useParsedOpts.js";
|
|
18
19
|
import { usePrevious } from "./usePrevious.js";
|
|
19
20
|
import { getParentValue } from "./utils/getParentValue.js";
|
|
@@ -209,6 +210,7 @@ function GroupHeader({ children, open, setOpen, title }) {
|
|
|
209
210
|
children: [/* @__PURE__ */ jsxs("button", {
|
|
210
211
|
type: "button",
|
|
211
212
|
"aria-expanded": open,
|
|
213
|
+
"data-field-label": true,
|
|
212
214
|
className: "w-full flex items-center text-left transform ease-in transition cursor-pointer",
|
|
213
215
|
onClick: () => setOpen((open) => !open),
|
|
214
216
|
children: [/* @__PURE__ */ jsx(FaAngleRight, { className: cx(open && "transform rotate-90 ", "px-1 text-[1.25rem] transition ease-in ") }), /* @__PURE__ */ jsx("span", { children: title })]
|
|
@@ -393,6 +395,8 @@ function useFieldParse(optionsField, values, arrayIndex) {
|
|
|
393
395
|
}
|
|
394
396
|
var FormField = React.memo(function FormField({ optionsField, fieldName, values, setFormDirty, setFieldValue, setFieldTouched, parentInfo, labelPosition = "left", missingFields = [], spaceCompact = false, workflowForm = false }) {
|
|
395
397
|
const parsedField = useFieldParse(optionsField, values, parentInfo?.arrayIndex);
|
|
398
|
+
const editing = useFormEditing();
|
|
399
|
+
const path = editing ? [...editing.parent, fieldName] : null;
|
|
396
400
|
const field = asSchemaField(parentInfo ? parsedField : optionsField);
|
|
397
401
|
if (field === null) return null;
|
|
398
402
|
const fieldNamePrefix = parentInfo?.fieldNamePrefix || "";
|
|
@@ -405,7 +409,11 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
|
|
|
405
409
|
if (!fieldObj.name || fieldName === "v3") return null;
|
|
406
410
|
if (field.hidden === true || !field.type) {
|
|
407
411
|
if (resolvedFlag(field.ignore) && !workflowForm) deleteFieldByPath(values, fieldObj.name);
|
|
408
|
-
return
|
|
412
|
+
return editing && path && fieldName !== "$meta" ? /* @__PURE__ */ jsx(editing.Row, {
|
|
413
|
+
path,
|
|
414
|
+
instance: fieldObj.name,
|
|
415
|
+
hidden: true
|
|
416
|
+
}) : null;
|
|
409
417
|
}
|
|
410
418
|
let onChange;
|
|
411
419
|
if (field.one_must_be_true && parentInfo?.onChange) {
|
|
@@ -421,7 +429,11 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
|
|
|
421
429
|
if (shouldShowField && field.show_if_not !== void 0) shouldShowField = !getParentValue(index, field.show_if_not, values, field);
|
|
422
430
|
if (!shouldShowField) {
|
|
423
431
|
if (!workflowForm) deleteFieldByPath(values, fieldObj.name);
|
|
424
|
-
return
|
|
432
|
+
return editing && path ? /* @__PURE__ */ jsx(editing.Row, {
|
|
433
|
+
path,
|
|
434
|
+
instance: fieldObj.name,
|
|
435
|
+
hidden: true
|
|
436
|
+
}) : null;
|
|
425
437
|
}
|
|
426
438
|
}
|
|
427
439
|
if (field.depends_on && parentInfo?.arrayIndex !== void 0) fieldObj.depends_on = field.depends_on.replace("[index]", `[${parentInfo.arrayIndex}]`);
|
|
@@ -436,7 +448,7 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
|
|
|
436
448
|
const hideHeader = field.noCollapse;
|
|
437
449
|
const HeaderElement = hideHeader ? React.Fragment : UncontrolledCollapsiblePanel;
|
|
438
450
|
const meta = resolveMetaOverrides(field.options, labelPosition, spaceCompact);
|
|
439
|
-
|
|
451
|
+
const group = /* @__PURE__ */ jsx("div", {
|
|
440
452
|
className: "flex flex-col w-full",
|
|
441
453
|
children: /* @__PURE__ */ jsx(HeaderElement, {
|
|
442
454
|
...!hideHeader && {
|
|
@@ -449,21 +461,30 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
|
|
|
449
461
|
},
|
|
450
462
|
children: /* @__PURE__ */ jsx("div", {
|
|
451
463
|
className: "w-full",
|
|
452
|
-
children: /* @__PURE__ */ jsx(
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
464
|
+
children: /* @__PURE__ */ jsx(EditingScope, {
|
|
465
|
+
editing,
|
|
466
|
+
path,
|
|
467
|
+
children: /* @__PURE__ */ jsx(FieldsFromOptions, {
|
|
468
|
+
options: field.options ?? {},
|
|
469
|
+
setFormDirty,
|
|
470
|
+
setFieldValue,
|
|
471
|
+
setFieldTouched,
|
|
472
|
+
values,
|
|
473
|
+
parentInfo,
|
|
474
|
+
workflowForm,
|
|
475
|
+
labelPosition: meta.labelPosition,
|
|
476
|
+
spaceCompact: meta.spaceCompact,
|
|
477
|
+
missingFields
|
|
478
|
+
})
|
|
463
479
|
})
|
|
464
480
|
})
|
|
465
481
|
})
|
|
466
482
|
});
|
|
483
|
+
return editing && path ? /* @__PURE__ */ jsx(editing.Row, {
|
|
484
|
+
path,
|
|
485
|
+
instance: fieldObj.name,
|
|
486
|
+
children: group
|
|
487
|
+
}) : group;
|
|
467
488
|
}
|
|
468
489
|
if (typeof field.type === "object" && field.depends_on) {
|
|
469
490
|
const parentValue = getValueUsingPath(values, field.depends_on);
|
|
@@ -489,7 +510,7 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
|
|
|
489
510
|
if (Array.isArray(field.secondaryField)) fieldObj.secondaryField = field.secondaryField.map((secondaryField) => fieldNamePrefix + secondaryField);
|
|
490
511
|
else fieldObj.secondaryField = fieldNamePrefix + field.secondaryField;
|
|
491
512
|
}
|
|
492
|
-
|
|
513
|
+
const input = /* @__PURE__ */ jsx("div", {
|
|
493
514
|
className: cx("flex w-full", labelPosition === "left" ? "mb-[15px]" : "mb-[5px]"),
|
|
494
515
|
children: /* @__PURE__ */ jsx(InputField, {
|
|
495
516
|
field: fieldObj,
|
|
@@ -508,6 +529,17 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
|
|
|
508
529
|
workflowForm
|
|
509
530
|
})
|
|
510
531
|
});
|
|
532
|
+
if (!editing || !path) return input;
|
|
533
|
+
const holds = fieldObj.type === "object" || fieldObj.type === "list";
|
|
534
|
+
return /* @__PURE__ */ jsx(editing.Row, {
|
|
535
|
+
path,
|
|
536
|
+
instance: fieldObj.name,
|
|
537
|
+
children: /* @__PURE__ */ jsx(EditingScope, {
|
|
538
|
+
editing,
|
|
539
|
+
path: holds ? path : null,
|
|
540
|
+
children: input
|
|
541
|
+
})
|
|
542
|
+
});
|
|
511
543
|
}, (prev, next) => {
|
|
512
544
|
if (!deepEqual(prev.optionsField, next.optionsField)) return false;
|
|
513
545
|
if (prev.values !== next.values) return false;
|
|
@@ -519,6 +551,7 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
|
|
|
519
551
|
return true;
|
|
520
552
|
});
|
|
521
553
|
function FieldsFromOptions({ options = {}, values, setFormDirty, setFieldValue, setFieldTouched, parentInfo, labelPosition = "left", missingFields = [], spaceCompact = false, workflowForm = false }) {
|
|
554
|
+
const editing = useFormEditing();
|
|
522
555
|
const chosen = useChosenLabelPosition(options);
|
|
523
556
|
const wizard = parseWizardConfig(options);
|
|
524
557
|
if (wizard) return /* @__PURE__ */ jsx(ChosenLabelPosition.Provider, {
|
|
@@ -556,22 +589,27 @@ function FieldsFromOptions({ options = {}, values, setFormDirty, setFieldValue,
|
|
|
556
589
|
spaceCompact,
|
|
557
590
|
workflowForm
|
|
558
591
|
}, fieldName);
|
|
592
|
+
const add = editing ? /* @__PURE__ */ jsx(editing.Add, { parent: editing.parent }) : null;
|
|
559
593
|
const layout = resolveFormLayout(asRecord(options["$meta"])["layout"], names.filter((name) => !name.startsWith("$") && asSchemaField(options[name])));
|
|
560
594
|
if (layout.layout) return /* @__PURE__ */ jsx(ChosenLabelPosition.Provider, {
|
|
561
595
|
value: chosen,
|
|
562
596
|
children: /* @__PURE__ */ jsxs("div", {
|
|
563
597
|
className: "flex min-w-0 flex-col gap-4",
|
|
564
|
-
children: [
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
598
|
+
children: [
|
|
599
|
+
/* @__PURE__ */ jsx(FormLayout, {
|
|
600
|
+
layout: layout.layout,
|
|
601
|
+
renderField: (name) => fieldOf(name, true)
|
|
602
|
+
}),
|
|
603
|
+
layout.remaining.map((name) => fieldOf(name, true)),
|
|
604
|
+
add
|
|
605
|
+
]
|
|
568
606
|
})
|
|
569
607
|
});
|
|
570
608
|
return /* @__PURE__ */ jsx(ChosenLabelPosition.Provider, {
|
|
571
609
|
value: chosen,
|
|
572
|
-
children: flows ? /* @__PURE__ */
|
|
610
|
+
children: flows ? /* @__PURE__ */ jsxs("div", {
|
|
573
611
|
className: "@container/inputs -mx-2 flex flex-wrap items-start",
|
|
574
|
-
children: columns.map((column) => {
|
|
612
|
+
children: [columns.map((column) => {
|
|
575
613
|
const width = inputWidth(asRecord(options[column.head])["width"]);
|
|
576
614
|
return /* @__PURE__ */ jsx("div", {
|
|
577
615
|
"data-input-cell": true,
|
|
@@ -587,8 +625,11 @@ function FieldsFromOptions({ options = {}, values, setFormDirty, setFieldValue,
|
|
|
587
625
|
}, name);
|
|
588
626
|
})
|
|
589
627
|
}, column.head);
|
|
590
|
-
})
|
|
591
|
-
|
|
628
|
+
}), add && /* @__PURE__ */ jsx("div", {
|
|
629
|
+
className: "order-2 w-full px-2",
|
|
630
|
+
children: add
|
|
631
|
+
})]
|
|
632
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [names.map((name) => fieldOf(name, void 0)), add] })
|
|
592
633
|
});
|
|
593
634
|
}
|
|
594
635
|
var noop = () => {};
|
|
@@ -2,16 +2,21 @@ import { useStrings, useWorkflowEngine } from "../../components/Provider.js";
|
|
|
2
2
|
import { copyBounds, stepText } from "./utils.js";
|
|
3
3
|
import { initializeValues } from "../lib.js";
|
|
4
4
|
import { getValueUsingPath } from "../utils/getValueUsingPath.js";
|
|
5
|
+
import { useFormEditing } from "../formEditing.js";
|
|
5
6
|
import { useWizardState } from "./useWizardState.js";
|
|
6
7
|
import { WizardNavigation } from "./WizardNavigation.js";
|
|
7
8
|
import { WizardStepContent } from "./WizardStepContent.js";
|
|
8
9
|
import { WizardStepIndicator } from "./WizardStepIndicator.js";
|
|
9
|
-
import {
|
|
10
|
+
import { WizardPagesContext } from "./wizardPages.js";
|
|
11
|
+
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
10
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
13
|
import { useFormikContext } from "formik";
|
|
12
14
|
//#region src/form/Wizard/WizardContainer.tsx
|
|
13
15
|
function WizardContainer({ wizardConfig, values, onChange, onSubmit, className = "", labelPosition = "left", missingFields = [], spaceCompact = false, workflowForm = false, nested = false, fieldNamePrefix = "", setFieldValue, setFieldTouched }) {
|
|
14
16
|
const { validateForm, setTouched, touched, initialValues } = useFormikContext();
|
|
17
|
+
const editing = useFormEditing();
|
|
18
|
+
const pages = useContext(WizardPagesContext);
|
|
19
|
+
const [ownPage, setOwnPage] = useState(0);
|
|
15
20
|
const { form: strings } = useStrings();
|
|
16
21
|
const engine = useWorkflowEngine();
|
|
17
22
|
const { config, steps, stepOrder } = wizardConfig;
|
|
@@ -197,19 +202,39 @@ function WizardContainer({ wizardConfig, values, onChange, onSubmit, className =
|
|
|
197
202
|
touched,
|
|
198
203
|
onSubmit
|
|
199
204
|
]);
|
|
205
|
+
const last = Math.max(shown.order.length - 1, 0);
|
|
206
|
+
const wizardKey = editing ? JSON.stringify(editing.parent) : "";
|
|
207
|
+
const editIndex = Math.min(Math.max(pages ? pages.page(wizardKey) : ownPage, 0), last);
|
|
208
|
+
const turn = (to) => {
|
|
209
|
+
const next = Math.max(to, 0);
|
|
210
|
+
if (pages) pages.setPage(wizardKey, next);
|
|
211
|
+
else setOwnPage(next);
|
|
212
|
+
};
|
|
213
|
+
const drawn = shown.order.length;
|
|
214
|
+
const setCount = pages?.setCount;
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
setCount?.(wizardKey, drawn);
|
|
217
|
+
}, [
|
|
218
|
+
setCount,
|
|
219
|
+
wizardKey,
|
|
220
|
+
drawn
|
|
221
|
+
]);
|
|
200
222
|
const shownBefore = useRef(shown.order);
|
|
201
223
|
useEffect(() => {
|
|
202
224
|
shownBefore.current = shown.order;
|
|
203
225
|
});
|
|
204
|
-
const
|
|
226
|
+
const runKey = shown.byKey[currentStep] ? currentStep : nearestPage(currentStep, shown.order, shownBefore.current);
|
|
205
227
|
useEffect(() => {
|
|
206
|
-
if (
|
|
228
|
+
if (!editing && runKey && runKey !== currentStep) showStep(runKey);
|
|
207
229
|
}, [
|
|
208
|
-
|
|
230
|
+
editing,
|
|
231
|
+
runKey,
|
|
209
232
|
currentStep,
|
|
210
233
|
showStep
|
|
211
234
|
]);
|
|
235
|
+
const pageKey = editing ? shown.order[editIndex] ?? "" : runKey;
|
|
212
236
|
const page = shown.byKey[pageKey];
|
|
237
|
+
const show = (key, index) => editing ? turn(index) : showStep(key);
|
|
213
238
|
const copiesOf = (step) => {
|
|
214
239
|
const rows = getValueUsingPath(values, `${fieldNamePrefix}${step}`);
|
|
215
240
|
return Array.isArray(rows) ? rows : [];
|
|
@@ -220,13 +245,15 @@ function WizardContainer({ wizardConfig, values, onChange, onSubmit, className =
|
|
|
220
245
|
const kept = Array.from({ length: shownPage.count ?? rows.length }, (_, i) => rows[i] ?? initializeValues(options, {}) ?? {});
|
|
221
246
|
const aside = setAside.current[`${fieldNamePrefix}${shownPage.step}`] ?? [];
|
|
222
247
|
setFieldValue(`${fieldNamePrefix}${shownPage.step}`, [...kept, takeAside(aside, kept.length) ?? initializeValues(options, {}) ?? {}]);
|
|
223
|
-
|
|
248
|
+
const at = shown.order.indexOf(pageKey) + (shownPage.copy === void 0 ? 0 : 1);
|
|
249
|
+
show(`${shownPage.step}[${kept.length}]`, at);
|
|
224
250
|
};
|
|
225
251
|
const removeCopy = (shownPage) => {
|
|
226
252
|
const copy = shownPage.copy ?? 0;
|
|
227
253
|
const rows = copiesOf(shownPage.step).filter((_, i) => i !== copy);
|
|
228
254
|
setFieldValue(`${fieldNamePrefix}${shownPage.step}`, rows);
|
|
229
|
-
|
|
255
|
+
const at = shown.order.indexOf(pageKey) - (copy > 0 ? 1 : 0);
|
|
256
|
+
show(rows.length > 0 ? `${shownPage.step}[${Math.max(copy - 1, 0)}]` : shownPage.step, at);
|
|
230
257
|
};
|
|
231
258
|
const rawTitle = page ? steps[page.step]?.title : void 0;
|
|
232
259
|
const titledPerCopy = Array.isArray(rawTitle) || typeof rawTitle === "string" && rawTitle.includes("${{");
|
|
@@ -264,6 +291,39 @@ function WizardContainer({ wizardConfig, values, onChange, onSubmit, className =
|
|
|
264
291
|
setFieldTouched
|
|
265
292
|
}), copies]
|
|
266
293
|
}) : null;
|
|
294
|
+
if (editing) return /* @__PURE__ */ jsxs("div", {
|
|
295
|
+
className,
|
|
296
|
+
children: [
|
|
297
|
+
navigation.showSteps !== false && /* @__PURE__ */ jsx(WizardStepIndicator, {
|
|
298
|
+
stepOrder: shown.order,
|
|
299
|
+
currentStep: pageKey,
|
|
300
|
+
steps: configs,
|
|
301
|
+
visitedSteps: new Set(shown.order),
|
|
302
|
+
invalidSteps: /* @__PURE__ */ new Set(),
|
|
303
|
+
onStepClick: (key) => {
|
|
304
|
+
turn(shown.order.indexOf(key));
|
|
305
|
+
return true;
|
|
306
|
+
},
|
|
307
|
+
allowJump: true,
|
|
308
|
+
hideStepNumbers: navigation.hideStepNumbers
|
|
309
|
+
}),
|
|
310
|
+
content,
|
|
311
|
+
/* @__PURE__ */ jsx(WizardNavigation, {
|
|
312
|
+
isLastStep: editIndex === last,
|
|
313
|
+
canGoBack: editIndex > 0,
|
|
314
|
+
isCurrentStepValid: true,
|
|
315
|
+
nextLabel: page?.config.nextLabel,
|
|
316
|
+
prevLabel: page?.config.prevLabel,
|
|
317
|
+
submitLabel: config.submitLabel || "Execute",
|
|
318
|
+
onNext: async () => {
|
|
319
|
+
turn(editIndex + 1);
|
|
320
|
+
return true;
|
|
321
|
+
},
|
|
322
|
+
onPrevious: () => turn(editIndex - 1),
|
|
323
|
+
onSubmit: nested ? void 0 : async () => {}
|
|
324
|
+
})
|
|
325
|
+
]
|
|
326
|
+
});
|
|
267
327
|
return /* @__PURE__ */ jsxs("div", {
|
|
268
328
|
className,
|
|
269
329
|
children: [
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { stepText } from "./utils.js";
|
|
2
|
+
import { EditingScope, useFormEditing } from "../formEditing.js";
|
|
2
3
|
import { FieldsFromOptions } from "../Form.js";
|
|
3
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
5
|
//#region src/form/Wizard/WizardStepContent.tsx
|
|
5
6
|
function WizardStepContent({ currentStep, stepConfig, flatten = true, values, setFormDirty, setFieldValue, setFieldTouched, fieldNamePrefix = "", copy, ...fieldsProps }) {
|
|
7
|
+
const editing = useFormEditing();
|
|
6
8
|
if (!stepConfig.options) return null;
|
|
9
|
+
const path = editing ? [...editing.parent, currentStep] : null;
|
|
7
10
|
const parentInfo = copy !== void 0 ? {
|
|
8
11
|
parentName: currentStep,
|
|
9
12
|
fieldNamePrefix: `${fieldNamePrefix}${currentStep}[${copy}].`,
|
|
@@ -15,7 +18,7 @@ function WizardStepContent({ currentStep, stepConfig, flatten = true, values, se
|
|
|
15
18
|
parentName: fieldNamePrefix.slice(0, -1),
|
|
16
19
|
fieldNamePrefix
|
|
17
20
|
} : void 0;
|
|
18
|
-
|
|
21
|
+
const content = /* @__PURE__ */ jsxs("div", {
|
|
19
22
|
className: "mb-4 w-full",
|
|
20
23
|
children: [
|
|
21
24
|
stepText(stepConfig.title) && /* @__PURE__ */ jsx("h2", {
|
|
@@ -28,17 +31,27 @@ function WizardStepContent({ currentStep, stepConfig, flatten = true, values, se
|
|
|
28
31
|
style: { color: "var(--theme-muted-text-color)" },
|
|
29
32
|
children: stepText(stepConfig.description)
|
|
30
33
|
}),
|
|
31
|
-
/* @__PURE__ */ jsx(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
/* @__PURE__ */ jsx(EditingScope, {
|
|
35
|
+
editing,
|
|
36
|
+
path,
|
|
37
|
+
children: /* @__PURE__ */ jsx(FieldsFromOptions, {
|
|
38
|
+
options: stepConfig.options,
|
|
39
|
+
values,
|
|
40
|
+
setFormDirty,
|
|
41
|
+
setFieldValue,
|
|
42
|
+
setFieldTouched,
|
|
43
|
+
...parentInfo ? { parentInfo } : {},
|
|
44
|
+
...fieldsProps
|
|
45
|
+
}, copy === void 0 ? currentStep : `${currentStep}[${copy}]`)
|
|
46
|
+
})
|
|
40
47
|
]
|
|
41
48
|
});
|
|
49
|
+
const instance = `${fieldNamePrefix}${currentStep}${copy === void 0 ? "" : `[${copy}]`}`;
|
|
50
|
+
return editing && path ? /* @__PURE__ */ jsx(editing.Row, {
|
|
51
|
+
path,
|
|
52
|
+
instance,
|
|
53
|
+
children: content
|
|
54
|
+
}) : content;
|
|
42
55
|
}
|
|
43
56
|
//#endregion
|
|
44
57
|
export { WizardStepContent };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The page each wizard of a form being edited shows, keyed by its list's path as JSON (`[]` for the
|
|
3
|
+
* form's own), so the editor can turn its pages as well as the wizard's own controls.
|
|
4
|
+
*/
|
|
5
|
+
export interface WizardPages {
|
|
6
|
+
page: (wizard: string) => number;
|
|
7
|
+
setPage: (wizard: string, index: number) => void;
|
|
8
|
+
/** How many pages the wizard draws, a repeated page's copies included, once it has drawn. */
|
|
9
|
+
count: (wizard: string) => number | undefined;
|
|
10
|
+
setCount: (wizard: string, count: number) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare const WizardPagesContext: import("react").Context<WizardPages | null>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ComponentType, type ReactNode } from 'react';
|
|
2
|
+
/** Editing controls a form builder wraps around rendered fields. */
|
|
3
|
+
export interface FormEditing {
|
|
4
|
+
/** Input path of the fields being rendered; empty at the top level. */
|
|
5
|
+
parent: string[];
|
|
6
|
+
Row: ComponentType<{
|
|
7
|
+
path: string[];
|
|
8
|
+
/** The field isn't drawn, such as one marked hidden. */
|
|
9
|
+
hidden?: boolean;
|
|
10
|
+
/** The field's name in the form's values, which tells one input's copies in a list's rows apart. */
|
|
11
|
+
instance?: string;
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
}>;
|
|
14
|
+
Add: ComponentType<{
|
|
15
|
+
parent: string[];
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
export declare const FormEditingContext: import("react").Context<FormEditing | null>;
|
|
19
|
+
export declare function useFormEditing(): FormEditing | null;
|
|
20
|
+
/** Fields rendered inside `children` belong to the input at `path`. */
|
|
21
|
+
export declare function EditingScope({ editing, path, children, }: {
|
|
22
|
+
editing: FormEditing | null;
|
|
23
|
+
path: string[] | null;
|
|
24
|
+
children: ReactNode;
|
|
25
|
+
}): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/form/formEditing.tsx
|
|
4
|
+
var FormEditingContext = createContext(null);
|
|
5
|
+
function useFormEditing() {
|
|
6
|
+
return useContext(FormEditingContext);
|
|
7
|
+
}
|
|
8
|
+
/** Fields rendered inside `children` belong to the input at `path`. */
|
|
9
|
+
function EditingScope({ editing, path, children }) {
|
|
10
|
+
if (!editing) return children;
|
|
11
|
+
return /* @__PURE__ */ jsx(FormEditingContext.Provider, {
|
|
12
|
+
value: path ? {
|
|
13
|
+
...editing,
|
|
14
|
+
parent: path
|
|
15
|
+
} : null,
|
|
16
|
+
children
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { EditingScope, FormEditingContext, useFormEditing };
|