@parallelworks/ui 0.19.0 → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/dist/{chunks/memoryStore-CC91S5LP.js → ai/adapter/memoryStore.js} +2 -2
  2. package/dist/ai/adapter/mock/index.js +2 -80
  3. package/dist/ai/adapter/mock/mockAdapter.js +81 -0
  4. package/dist/ai/adapter/openai/createOpenAIStream.js +33 -0
  5. package/dist/ai/adapter/openai/errors.js +37 -0
  6. package/dist/ai/adapter/openai/index.js +5 -333
  7. package/dist/ai/adapter/openai/openaiAdapter.js +54 -0
  8. package/dist/ai/adapter/openai/responses.js +108 -0
  9. package/dist/ai/adapter/openai/sse.js +112 -0
  10. package/dist/{chunks/types-Yy0NrerF.js → ai/adapter/types.js} +1 -1
  11. package/dist/ai/agent/classifier.js +12 -0
  12. package/dist/ai/agent/diff.js +223 -0
  13. package/dist/ai/agent/diffHighlight.js +101 -0
  14. package/dist/ai/agent/permissions.js +29 -0
  15. package/dist/ai/agent/toolfmt.js +383 -0
  16. package/dist/ai/agent/transcript.js +127 -0
  17. package/dist/ai/components/AllocationSelector.js +56 -0
  18. package/dist/ai/components/AttachmentManager.js +144 -0
  19. package/dist/ai/components/AttachmentUpload.js +179 -0
  20. package/dist/ai/components/BlockedGroupBanner.js +29 -0
  21. package/dist/ai/components/BranchNavigator.js +57 -0
  22. package/dist/ai/components/ChatEmptyState.js +171 -0
  23. package/dist/ai/components/ChatInput.js +265 -0
  24. package/dist/ai/components/ChatLayout.js +15 -0
  25. package/dist/ai/components/ChatMessage.js +338 -0
  26. package/dist/ai/components/ChatMessageList.js +301 -0
  27. package/dist/ai/components/ChatSidebar.js +345 -0
  28. package/dist/ai/components/ChatThread.js +198 -0
  29. package/dist/ai/components/ComposerChrome.js +50 -0
  30. package/dist/ai/components/ComposerFrame.js +33 -0
  31. package/dist/ai/components/DragOverlay.js +20 -0
  32. package/dist/ai/components/ModelSelector.js +343 -0
  33. package/dist/ai/components/ShareDialog.js +260 -0
  34. package/dist/ai/components/SlashMenu.js +91 -0
  35. package/dist/ai/components/agent/ActivityLine.js +151 -0
  36. package/dist/ai/components/agent/AgentMessageParts.js +721 -0
  37. package/dist/ai/components/agent/PermissionPicker.js +38 -0
  38. package/dist/ai/components/attachmentKeys.js +10 -0
  39. package/dist/ai/core/ChatProvider.js +848 -0
  40. package/dist/ai/core/KeyboardShortcutsProvider.js +9 -0
  41. package/dist/ai/core/chatReducer.js +223 -0
  42. package/dist/ai/core/config.js +45 -0
  43. package/dist/ai/core/events.js +4 -0
  44. package/dist/ai/core/exportConversation.js +42 -0
  45. package/dist/ai/core/greeting.js +38 -0
  46. package/dist/ai/core/parts.js +84 -0
  47. package/dist/ai/core/useDragDrop.js +36 -0
  48. package/dist/ai/core/useKeyboardShortcuts.js +77 -0
  49. package/dist/ai/core/useSSEStream.js +98 -0
  50. package/dist/ai/index.js +43 -6644
  51. package/dist/ai/strings.js +175 -0
  52. package/dist/ai/ui/Avatar.js +35 -0
  53. package/dist/ai/ui/Dropdown.js +110 -0
  54. package/dist/ai/ui/Markdown.js +79 -0
  55. package/dist/ai/ui/Notice.js +77 -0
  56. package/dist/ai/ui/codeBreaks.js +36 -0
  57. package/dist/ai/ui/prose.js +13 -0
  58. package/dist/ai/ui/sidebar.js +148 -0
  59. package/dist/ai/utils.js +23 -0
  60. package/dist/components/AddMenu.js +46 -0
  61. package/dist/components/Avatar.js +46 -0
  62. package/dist/{chunks/BareModal-BtRiQezg.js → components/BareModal.js} +1 -1
  63. package/dist/components/Breadcrumbs.js +83 -0
  64. package/dist/components/Button.js +83 -0
  65. package/dist/components/Callout.js +23 -0
  66. package/dist/components/Card.js +31 -0
  67. package/dist/components/CollapsiblePanel.js +77 -0
  68. package/dist/{chunks/ConfirmModal-aOR4O1QE.js → components/ConfirmModal.js} +4 -9
  69. package/dist/components/CopyToClipboard.js +81 -0
  70. package/dist/{chunks/Markdown-CM-FenNE.js → components/CreateModal.js} +9 -116
  71. package/dist/components/DescriptionList.js +42 -0
  72. package/dist/components/Dropdown.js +349 -0
  73. package/dist/components/EmptyState.js +27 -0
  74. package/dist/components/Filter.js +32 -0
  75. package/dist/components/FilterPill.js +13 -0
  76. package/dist/components/IconButton.js +34 -0
  77. package/dist/{chunks/Indicator-hBSIxOPK.js → components/Indicator.js} +1 -1
  78. package/dist/components/Input.js +88 -0
  79. package/dist/components/LetterBadge.js +13 -0
  80. package/dist/components/Listbox.js +123 -0
  81. package/dist/{chunks/Loader-BXoXTZGc.js → components/Loader.js} +1 -1
  82. package/dist/components/Markdown.js +15 -0
  83. package/dist/components/MultiSelect.js +171 -0
  84. package/dist/components/Overview.js +39 -0
  85. package/dist/components/PageHeader.js +194 -0
  86. package/dist/components/Pagination.js +35 -0
  87. package/dist/{chunks/Provider-CDYurraE.js → components/Provider.js} +1 -1
  88. package/dist/{chunks/RequiredMark-DfLdYbYZ.js → components/RequiredMark.js} +1 -1
  89. package/dist/components/SectionHeader.js +11 -0
  90. package/dist/components/SettingModeOption.js +30 -0
  91. package/dist/components/SettingRow.js +35 -0
  92. package/dist/components/SettingsCard.js +31 -0
  93. package/dist/components/SettingsGroup.js +17 -0
  94. package/dist/components/Sort.js +42 -0
  95. package/dist/components/StatusBadge.js +63 -0
  96. package/dist/components/SwitchToggle.js +59 -0
  97. package/dist/{chunks/SwitchToggleSmall-FcsaYSTs.js → components/SwitchToggleSmall.js} +1 -1
  98. package/dist/{chunks/Table-DU2MW8xz.js → components/Table.js} +3 -3
  99. package/dist/components/Toggle.js +20 -0
  100. package/dist/{chunks/Tooltip-K5HJr4_p.js → components/Tooltip.js} +2 -27
  101. package/dist/{chunks/StatusBadge-C1Blx_cW.js → components/dropdownUtils.js} +2 -63
  102. package/dist/{chunks/focus-D_iZJTW1.js → components/focus.js} +1 -1
  103. package/dist/components/ghostButton.js +7 -0
  104. package/dist/components/inputClasses.js +4 -0
  105. package/dist/components/keys.js +27 -0
  106. package/dist/components/relativeTime.js +32 -0
  107. package/dist/{chunks/useCssIsDark-DHr05dG2.js → components/useCssIsDark.js} +1 -1
  108. package/dist/{chunks/duration-BOv8Phl8.js → duration.js} +1 -1
  109. package/dist/editor/Editor.js +13 -0
  110. package/dist/editor/EditorField.js +53 -0
  111. package/dist/editor/FormCodePanel.js +173 -0
  112. package/dist/{chunks/Monaco-DJ8MW-Dq.js → editor/Monaco.js} +4 -2
  113. package/dist/editor/index.js +6 -1
  114. package/dist/editor/themes.js +91 -0
  115. package/dist/editor/workers.js +29 -0
  116. package/dist/editor/yaml.js +15 -0
  117. package/dist/file-explorer/FileExplorer.js +1402 -0
  118. package/dist/file-explorer/FileExplorerContext.js +370 -0
  119. package/dist/{chunks/CodePreviewEditor-YqQBz1YL.js → file-explorer/FilePreview/CodePreviewEditor.js} +3 -2
  120. package/dist/file-explorer/FilePreview/Inline.js +45 -0
  121. package/dist/file-explorer/FilePreview/StreamedBadge.js +16 -0
  122. package/dist/file-explorer/FilePreview/Viewer.js +526 -0
  123. package/dist/file-explorer/FilePreview/index.js +266 -0
  124. package/dist/file-explorer/FilePreview/parse.js +63 -0
  125. package/dist/file-explorer/FilePreview/previewCache.js +98 -0
  126. package/dist/file-explorer/FilePreview/previewType.js +151 -0
  127. package/dist/file-explorer/FilePreview/readCappedBytes.js +196 -0
  128. package/dist/file-explorer/FilePreview/useObjectBlobUrl.js +95 -0
  129. package/dist/file-explorer/FilePreview/useObjectText.js +109 -0
  130. package/dist/file-explorer/FilePreview/usePresignedUrl.js +73 -0
  131. package/dist/file-explorer/FileRow.js +165 -0
  132. package/dist/file-explorer/FileRowsWindow.js +92 -0
  133. package/dist/file-explorer/FileTable.js +172 -0
  134. package/dist/file-explorer/FileTableHeaders.js +49 -0
  135. package/dist/file-explorer/LoadMoreRow.js +46 -0
  136. package/dist/file-explorer/TreeView.js +376 -0
  137. package/dist/file-explorer/helpers.js +537 -0
  138. package/dist/file-explorer/index.js +7 -5671
  139. package/dist/file-explorer/lib/batch.js +39 -0
  140. package/dist/file-explorer/lib/errors.js +9 -0
  141. package/dist/file-explorer/lib/paging.js +124 -0
  142. package/dist/file-explorer/lib/utils.js +322 -0
  143. package/dist/file-explorer/toasts.js +400 -0
  144. package/dist/file-explorer/treeRows.js +73 -0
  145. package/dist/file-explorer/useNearEnd.js +27 -0
  146. package/dist/form/FieldWrapper.js +54 -0
  147. package/dist/form/Fields/BooleanField.js +51 -0
  148. package/dist/form/Fields/CheckboxGroupField.js +72 -0
  149. package/dist/form/Fields/ColorField.js +33 -0
  150. package/dist/form/Fields/DropdownField.js +49 -0
  151. package/dist/form/Fields/DurationField.js +130 -0
  152. package/dist/form/Fields/LabelField.js +19 -0
  153. package/dist/form/Fields/MultiDropdownField.js +40 -0
  154. package/dist/form/Fields/NumberField.js +51 -0
  155. package/dist/form/Fields/ObjectField.js +54 -0
  156. package/dist/form/Fields/RadioField.js +49 -0
  157. package/dist/form/Fields/RangeField.js +58 -0
  158. package/dist/form/Fields/ResourceOptionIcon.js +21 -0
  159. package/dist/form/Fields/StepField.js +6 -0
  160. package/dist/form/Fields/StringField.js +37 -0
  161. package/dist/form/Fields/TextAreaField.js +31 -0
  162. package/dist/form/Fields/durationValidity.js +11 -0
  163. package/dist/form/Form.js +643 -0
  164. package/dist/form/SpecialTypes/DropdownWrapper.js +30 -0
  165. package/dist/form/SpecialTypes/FormikCustomDropdown.js +122 -0
  166. package/dist/form/SpecialTypes/FormikCustomInput.js +111 -0
  167. package/dist/form/SpecialTypes/FormikMultiSelectDropdown.js +31 -0
  168. package/dist/form/SpecialTypes/FormikNumericInput.js +60 -0
  169. package/dist/form/Wizard/WizardContainer.js +138 -0
  170. package/dist/form/Wizard/WizardNavigation.js +92 -0
  171. package/dist/form/Wizard/WizardStepContent.js +35 -0
  172. package/dist/form/Wizard/WizardStepIndicator.js +108 -0
  173. package/dist/form/Wizard/useWizardState.js +118 -0
  174. package/dist/form/Wizard/utils.js +34 -0
  175. package/dist/form/fieldContext.js +26 -0
  176. package/dist/form/fieldRegistry.js +50 -0
  177. package/dist/form/index.js +17 -2321
  178. package/dist/{chunks/FieldWrapper-Cszwg-4B.js → form/lib.js} +2 -97
  179. package/dist/form/useParsedOpts.js +62 -0
  180. package/dist/form/usePrevious.js +11 -0
  181. package/dist/form/utils/checkShowIfObject.js +14 -0
  182. package/dist/form/utils/duration.js +69 -0
  183. package/dist/form/utils/getParentValue.js +23 -0
  184. package/dist/form/utils/getPlaceholder.js +9 -0
  185. package/dist/form/utils/getValueUsingPath.js +23 -0
  186. package/dist/form/utils/secondaryField.js +22 -0
  187. package/dist/graph/AnnotationBanner.js +141 -0
  188. package/dist/graph/Collapse.js +41 -0
  189. package/dist/graph/DependencyGraph.js +1398 -0
  190. package/dist/graph/JobSummary.js +104 -0
  191. package/dist/graph/MatrixGroup.js +107 -0
  192. package/dist/graph/Reveal.js +57 -0
  193. package/dist/graph/TreeView.js +711 -0
  194. package/dist/graph/index.js +1 -2519
  195. package/dist/graph/types.js +6 -0
  196. package/dist/index.js +46 -599
  197. package/dist/list/ActionToolbar.js +184 -0
  198. package/dist/list/HoverCard.js +73 -0
  199. package/dist/list/ListPage.js +145 -0
  200. package/dist/list/ListPager.js +59 -0
  201. package/dist/list/ListTable.js +163 -0
  202. package/dist/list/ListViewControls.js +372 -0
  203. package/dist/list/RowContextMenu.js +350 -0
  204. package/dist/list/UserHoverCard.js +117 -0
  205. package/dist/list/index.js +11 -2
  206. package/dist/list/listSearch.js +137 -0
  207. package/dist/list/listView.js +210 -0
  208. package/dist/list/textEntry.js +10 -0
  209. package/dist/{chunks/logviewer-BTKuQWzw.js → logviewer/LogViewer.js} +4 -82
  210. package/dist/logviewer/index.js +2 -1
  211. package/dist/logviewer/segments.js +80 -0
  212. package/package.json +1 -1
  213. package/dist/chunks/PageHeader-0kG_iypP.js +0 -692
  214. package/dist/chunks/SwitchToggle-DShNdcao.js +0 -758
  215. package/dist/chunks/editor-Dk1rbV75.js +0 -361
  216. package/dist/chunks/list-CJm875m7.js +0 -1418
  217. /package/dist/{chunks/MarkdownImpl-CyeTVvSt.js → components/MarkdownImpl.js} +0 -0
@@ -0,0 +1,643 @@
1
+ import { useStrings, useWorkflowEngine } from "../components/Provider.js";
2
+ import { AngleRightIcon, TrashIcon } from "../icons.js";
3
+ import { TooltipInfo } from "../components/Tooltip.js";
4
+ import { UncontrolledCollapsiblePanel } from "../components/CollapsiblePanel.js";
5
+ import CustomListbox from "../components/Listbox.js";
6
+ import Loader from "../components/Loader.js";
7
+ import SectionHeader from "../components/SectionHeader.js";
8
+ import { Table } from "../components/Table.js";
9
+ import { useFieldControlProps, useFieldRequired } from "./fieldContext.js";
10
+ import { resolvedFlag } from "./lib.js";
11
+ import { FieldRegistryContext, Registry } from "./fieldRegistry.js";
12
+ import { useParsedOpts } from "./useParsedOpts.js";
13
+ import { usePrevious } from "./usePrevious.js";
14
+ import { getValueUsingPath } from "./utils/getValueUsingPath.js";
15
+ import { getParentValue } from "./utils/getParentValue.js";
16
+ import { parseWizardConfig } from "./Wizard/utils.js";
17
+ import { WizardContainer } from "./Wizard/WizardContainer.js";
18
+ import cx from "classnames";
19
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
20
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
21
+ import deepEqual from "fast-deep-equal";
22
+ import { Form, Formik, useField, useFormikContext } from "formik";
23
+ //#region src/form/Form.tsx
24
+ function asSchemaField(value) {
25
+ return value && typeof value === "object" ? value : null;
26
+ }
27
+ function asRecord(value) {
28
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
29
+ }
30
+ function flagValue(value, fallback) {
31
+ return value && (typeof value === "string" || typeof value === "boolean") ? value : fallback;
32
+ }
33
+ /** Applies `$meta` overrides for `labelPosition` / `spaceCompact`. */
34
+ function resolveMetaOverrides(options, labelPosition, spaceCompact) {
35
+ const meta = options?.["$meta"];
36
+ return {
37
+ labelPosition: meta?.labelPosition ?? labelPosition,
38
+ spaceCompact: meta?.spaceCompact ?? spaceCompact
39
+ };
40
+ }
41
+ /** Cheap signature of every list's length; gates the expensive collect walk. */
42
+ function listLengthsSignature(options, values = {}, prefix = "") {
43
+ if (!options || typeof options !== "object") return "";
44
+ const parts = [];
45
+ for (const [fieldName, rawField] of Object.entries(options)) {
46
+ const field = asSchemaField(rawField);
47
+ if (fieldName === "$meta" || !field) continue;
48
+ const fullName = prefix ? `${prefix}${fieldName}` : fieldName;
49
+ if (field.type === "list") {
50
+ const items = values?.[fieldName];
51
+ const len = Array.isArray(items) ? items.length : 0;
52
+ parts.push(`${fullName}:${len}`);
53
+ const template = field.template || field.options;
54
+ if (template && Array.isArray(items)) for (let i = 0; i < items.length; i++) parts.push(listLengthsSignature(template, asRecord(items[i]), `${fullName}[${i}].`));
55
+ } else if (field.type === "group") {
56
+ const groupItems = field.items || field.options;
57
+ if (groupItems) parts.push(listLengthsSignature(groupItems, values, prefix));
58
+ } else if (field.type === "object") {
59
+ const groupItems = field.items || field.options;
60
+ if (groupItems) {
61
+ const nestedValues = asRecord(values?.[fieldName]);
62
+ parts.push(listLengthsSignature(groupItems, nestedValues, `${fullName}.`));
63
+ }
64
+ }
65
+ }
66
+ return parts.join("|");
67
+ }
68
+ /** Collects every field with a `default` for the form-level sync to track. */
69
+ function collectFieldsWithDefaults(options, values = {}, prefix = "") {
70
+ const result = [];
71
+ if (!options || typeof options !== "object") return result;
72
+ for (const [fieldName, rawField] of Object.entries(options)) {
73
+ const field = asSchemaField(rawField);
74
+ if (!field) continue;
75
+ if (fieldName === "$meta") continue;
76
+ const fullName = prefix ? `${prefix}${fieldName}` : fieldName;
77
+ if (field.type === "group") {
78
+ const groupItems = field.items || field.options;
79
+ if (groupItems) result.push(...collectFieldsWithDefaults(groupItems, values, prefix));
80
+ continue;
81
+ }
82
+ if (field.type === "object") {
83
+ const groupItems = field.items || field.options;
84
+ if (groupItems) {
85
+ const nestedValues = asRecord(values?.[fieldName]);
86
+ result.push(...collectFieldsWithDefaults(groupItems, nestedValues, `${fullName}.`));
87
+ }
88
+ continue;
89
+ }
90
+ if (field.type === "list") {
91
+ const listTemplate = field.template || field.options;
92
+ const listValues = values?.[fieldName];
93
+ if (listTemplate && Array.isArray(listValues)) for (let i = 0; i < listValues.length; i++) {
94
+ const itemValues = asRecord(listValues[i]);
95
+ result.push(...collectFieldsWithDefaults(listTemplate, itemValues, `${fullName}[${i}].`));
96
+ }
97
+ continue;
98
+ }
99
+ if (resolvedFlag(field.hidden) === true && field.ignore !== void 0 && resolvedFlag(field.ignore) !== false) continue;
100
+ if (field.default !== void 0) result.push({
101
+ name: fullName,
102
+ defaultValue: field.default,
103
+ ...field.secondaryField ? { hasSecondary: true } : {}
104
+ });
105
+ }
106
+ return result;
107
+ }
108
+ function defaultReferencesField(defaultValue, fieldPath) {
109
+ if (typeof defaultValue !== "string" || !defaultValue.includes("${{")) return false;
110
+ const escaped = fieldPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
111
+ return new RegExp(`\\binputs\\.${escaped}(?![\\w.[-])`).test(defaultValue);
112
+ }
113
+ function findSelfReferencingFieldNames(schema, values = {}) {
114
+ return collectFieldsWithDefaults(schema, values).filter(({ name, defaultValue }) => defaultReferencesField(defaultValue, name)).map(({ name }) => name);
115
+ }
116
+ /** Resolves schema defaults into form values as dependencies change. Store-agnostic so the Formik
117
+ * form and hosts with their own store share one implementation. */
118
+ function useDynamicDefaultsSync({ options, values, setValue, isTouched }) {
119
+ const engine = useWorkflowEngine();
120
+ const listSig = useMemo(() => listLengthsSignature(options, values), [options, values]);
121
+ const fieldsWithDefaults = useMemo(() => collectFieldsWithDefaults(options, values).map((f) => {
122
+ if (typeof f.defaultValue !== "string" || !f.defaultValue.includes("${{")) return f;
123
+ const lastRowIndex = [...f.name.matchAll(/\[(\d+)\]/g)].at(-1)?.[1];
124
+ const index = lastRowIndex === void 0 ? -1 : Number(lastRowIndex);
125
+ const parsed = engine.evaluate({
126
+ inputs: values,
127
+ obj: { v: f.defaultValue },
128
+ orgVars: {},
129
+ index
130
+ });
131
+ const resolved = parsed && typeof parsed === "object" && "v" in parsed ? parsed.v : f.defaultValue;
132
+ return {
133
+ ...f,
134
+ defaultValue: resolved
135
+ };
136
+ }), [options, listSig]);
137
+ const prevDefaultsRef = useRef(/* @__PURE__ */ new Map());
138
+ const synthTouchedRef = useRef(/* @__PURE__ */ new Set());
139
+ const prevListLensRef = useRef(/* @__PURE__ */ new Map());
140
+ const fieldsWithDefaultsRef = useRef(null);
141
+ if (!deepEqual(fieldsWithDefaultsRef.current, fieldsWithDefaults)) {
142
+ fieldsWithDefaultsRef.current = fieldsWithDefaults;
143
+ const currentNames = new Set(fieldsWithDefaults.map((f) => f.name));
144
+ for (const name of prevDefaultsRef.current.keys()) if (!currentNames.has(name)) {
145
+ prevDefaultsRef.current.delete(name);
146
+ synthTouchedRef.current.delete(name);
147
+ }
148
+ const listLens = /* @__PURE__ */ new Map();
149
+ for (const part of listSig.split("|")) {
150
+ const sep = part.lastIndexOf(":");
151
+ if (sep > 0) listLens.set(part.slice(0, sep), Number(part.slice(sep + 1)));
152
+ }
153
+ for (const [list, prevLen] of prevListLensRef.current) {
154
+ const nowLen = listLens.get(list);
155
+ if (nowLen !== void 0 && nowLen < prevLen) {
156
+ for (const name of [...prevDefaultsRef.current.keys()]) if (name.startsWith(`${list}[`)) prevDefaultsRef.current.delete(name);
157
+ for (const name of [...synthTouchedRef.current]) if (name.startsWith(`${list}[`)) synthTouchedRef.current.delete(name);
158
+ }
159
+ }
160
+ prevListLensRef.current = listLens;
161
+ for (const { name, defaultValue, hasSecondary } of fieldsWithDefaults) {
162
+ if (hasSecondary) continue;
163
+ if (synthTouchedRef.current.has(name)) continue;
164
+ if (isTouched(name)) continue;
165
+ if (typeof defaultValue === "string" && defaultValue.includes("${{")) continue;
166
+ const wasSeen = prevDefaultsRef.current.has(name);
167
+ const serializedDefault = JSON.stringify(defaultValue ?? null);
168
+ const prevDefault = prevDefaultsRef.current.get(name);
169
+ prevDefaultsRef.current.set(name, serializedDefault);
170
+ if (!wasSeen) {
171
+ const rawValue = getValueUsingPath(values, name);
172
+ const currVal = JSON.stringify(rawValue);
173
+ const trimmedValue = typeof rawValue === "string" ? rawValue.trim() : "";
174
+ const unresolvedValue = trimmedValue.startsWith("${{") && trimmedValue.endsWith("}}");
175
+ if (!unresolvedValue && currVal !== void 0 && currVal !== serializedDefault) {
176
+ synthTouchedRef.current.add(name);
177
+ continue;
178
+ }
179
+ if (!unresolvedValue) continue;
180
+ }
181
+ if (prevDefault === serializedDefault) continue;
182
+ if (defaultValue === null || defaultValue === void 0) continue;
183
+ if (JSON.stringify(getValueUsingPath(values, name)) !== serializedDefault) setValue(name, defaultValue);
184
+ }
185
+ }
186
+ }
187
+ function DynamicDefaultsSync({ options }) {
188
+ const { setFieldValue, getFieldMeta, values } = useFormikContext();
189
+ useDynamicDefaultsSync({
190
+ options,
191
+ values,
192
+ setValue: setFieldValue,
193
+ isTouched: (name) => getFieldMeta(name).touched
194
+ });
195
+ return null;
196
+ }
197
+ function GroupHeader({ children, open, setOpen, title }) {
198
+ return /* @__PURE__ */ jsxs(SectionHeader, {
199
+ className: "flex items-center justify-between pb-1 mb-2 border-b",
200
+ children: [/* @__PURE__ */ jsxs("button", {
201
+ type: "button",
202
+ "aria-expanded": open,
203
+ className: cx("w-full flex items-center text-left transform ease-in transition cursor-pointer"),
204
+ onClick: () => setOpen((open) => !open),
205
+ children: [/* @__PURE__ */ jsx(AngleRightIcon, { className: cx(open && "transform rotate-90 ", "px-1 text-[1.25rem] transition ease-in ") }), /* @__PURE__ */ jsx("span", { children: title })]
206
+ }), children]
207
+ });
208
+ }
209
+ function deleteFieldByPath(obj, path) {
210
+ if (!path) return;
211
+ const parts = path.replaceAll("[", ".").replaceAll("]", "").split(".");
212
+ const fieldToRemove = parts.pop();
213
+ if (!fieldToRemove) {
214
+ console.error("Invalid path");
215
+ return;
216
+ }
217
+ const parent = parts.reduce((acc, curr) => {
218
+ if (acc && typeof acc === "object") return acc[curr];
219
+ return {};
220
+ }, obj);
221
+ if (parent && typeof parent === "object" && Object.hasOwn(parent, fieldToRemove)) delete parent[fieldToRemove];
222
+ }
223
+ function getClosestParentIndex(parentPath) {
224
+ for (let i = parentPath.length - 1; i >= 0; i--) if (parentPath[i] === "]") {
225
+ let j = i - 1;
226
+ while (j >= 0 && parentPath[j] !== "[") j--;
227
+ return parseInt(parentPath.slice(j + 1, i));
228
+ }
229
+ }
230
+ function MultiSelectionDropdown({ name, label = "", invalid = false, options: initialOptions = [], setFormDirty, onChange, parentValue }) {
231
+ const [field] = useField(name);
232
+ const required = useFieldRequired();
233
+ const controlProps = useFieldControlProps();
234
+ const { setFieldValue } = useFormikContext();
235
+ const options = useMemo(() => {
236
+ return initialOptions.map((option) => {
237
+ const op = typeof option === "string" ? {
238
+ label: option,
239
+ value: option,
240
+ selected: false
241
+ } : { ...option };
242
+ if (field.value?.includes(op.value)) op.selected = true;
243
+ return op;
244
+ });
245
+ }, [initialOptions, field.value]);
246
+ const handleOptionSelected = (selectedValue) => {
247
+ let selected = [];
248
+ if (field.value) selected = [...field.value];
249
+ selected.push(selectedValue);
250
+ setFieldValue(name, selected);
251
+ if (onChange) onChange(options);
252
+ setFormDirty(true);
253
+ };
254
+ const t = useStrings().common;
255
+ const handleRemoveOption = (key) => {
256
+ const selected = [...field.value.filter((item) => item !== key)];
257
+ setFieldValue(name, selected);
258
+ if (onChange) onChange(options);
259
+ setFormDirty(true);
260
+ };
261
+ const prevParent = usePrevious(parentValue);
262
+ useEffect(() => {
263
+ if (prevParent && parentValue && prevParent !== parentValue) setFieldValue(name, []);
264
+ }, [
265
+ parentValue,
266
+ prevParent,
267
+ name,
268
+ setFieldValue
269
+ ]);
270
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(CustomListbox, {
271
+ ...controlProps,
272
+ options,
273
+ required,
274
+ type: label.toLowerCase(),
275
+ handleOptionSelected,
276
+ className: "mb-3",
277
+ invalid,
278
+ closeOnSelect: false
279
+ }), /* @__PURE__ */ jsx(Table, { children: field.value && field.value.length > 0 ? options.filter((option) => option.selected).map((option) => {
280
+ return /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx(Table.Item, {
281
+ className: "w-full",
282
+ children: option?.label
283
+ }), /* @__PURE__ */ jsx(Table.Item, { children: /* @__PURE__ */ jsx("button", {
284
+ type: "button",
285
+ "aria-label": t.remove,
286
+ className: "inline-flex bg-transparent p-0 cursor-pointer",
287
+ onClick: () => handleRemoveOption(option.value),
288
+ children: /* @__PURE__ */ jsx(TrashIcon, { className: "link mr-4" })
289
+ }) })] }, String(option.value));
290
+ }) : /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs(Table.Item, { children: [
291
+ "No ",
292
+ label !== "" ? label.toLowerCase() : "options",
293
+ " selected"
294
+ ] }) }) })] });
295
+ }
296
+ var InputField = React.memo(function InputField({ label, field, setFormDirty, onChange, disabled = false, labelPosition = "left", missingFields = [], computeOn, spaceCompact = false, workflowForm = false, setFieldValue, setFieldTouched, values, currentValue }) {
297
+ const prevField = useRef(field);
298
+ const fieldObj = useMemo(() => {
299
+ if (deepEqual(prevField.current, field)) return prevField.current;
300
+ prevField.current = field;
301
+ return { ...field };
302
+ }, [field]);
303
+ const tooltipComponent = useMemo(() => {
304
+ if (!fieldObj.tooltip) return null;
305
+ return /* @__PURE__ */ jsx(TooltipInfo, {
306
+ className: "pr-2",
307
+ place: "top",
308
+ text: typeof fieldObj.tooltip === "string" ? fieldObj.tooltip.replace(/\r/g, "") : fieldObj.tooltip.filter(Boolean).join("\n")
309
+ });
310
+ }, [fieldObj.tooltip]);
311
+ const missing = missingFields.includes(fieldObj.name ?? "");
312
+ return /* @__PURE__ */ jsx(Registry, {
313
+ field: fieldObj,
314
+ label,
315
+ labelPosition,
316
+ missing,
317
+ missingFields,
318
+ values,
319
+ setFormDirty,
320
+ onChange,
321
+ disabled,
322
+ computeOn,
323
+ spaceCompact,
324
+ tooltipComponent,
325
+ workflowForm,
326
+ setFieldTouched,
327
+ setFieldValue,
328
+ currentValue
329
+ });
330
+ }, (prev, next) => {
331
+ if (!deepEqual(prev.field, next.field)) return false;
332
+ for (const key of Object.keys(prev)) {
333
+ if (key === "field" || key === "values") continue;
334
+ if (prev[key] !== next[key]) return false;
335
+ }
336
+ return true;
337
+ });
338
+ function FormikStateBridge({ onChange }) {
339
+ const { values } = useFormikContext();
340
+ const prevEmitted = useRef(null);
341
+ useEffect(() => {
342
+ const { editorKeyPostfix: _, ...next } = values;
343
+ if (prevEmitted.current !== null && prevEmitted.current !== void 0 && deepEqual(prevEmitted.current, next)) return;
344
+ prevEmitted.current = next;
345
+ onChange(next);
346
+ }, [values, onChange]);
347
+ return null;
348
+ }
349
+ function DirtyStateBridge({ setFormDirty }) {
350
+ const { dirty } = useFormikContext();
351
+ useEffect(() => {
352
+ setFormDirty(dirty);
353
+ }, [dirty, setFormDirty]);
354
+ return null;
355
+ }
356
+ /** Three-tier cache: no expressions → raw pass-through; input-dep expressions → re-parse on dep change; org-var/path expressions → parse once. */
357
+ function useFieldParse(optionsField, values, arrayIndex) {
358
+ const engine = useWorkflowEngine();
359
+ const c = useRef({
360
+ lastOptField: null,
361
+ convertedField: null,
362
+ inputDeps: /* @__PURE__ */ new Set(),
363
+ hasExpressions: false,
364
+ lastRelevant: {},
365
+ lastIndex: void 0,
366
+ result: null
367
+ }).current;
368
+ if (optionsField !== c.lastOptField) {
369
+ c.lastOptField = optionsField;
370
+ c.convertedField = engine.convertInputs(asRecord(optionsField));
371
+ const { inputDeps, hasExpressions } = engine.inputDependencies(c.convertedField);
372
+ c.inputDeps = inputDeps;
373
+ c.hasExpressions = hasExpressions;
374
+ c.result = null;
375
+ }
376
+ if (!c.hasExpressions) return optionsField;
377
+ if (c.inputDeps.size === 0) {
378
+ if (c.result !== null) return c.result;
379
+ }
380
+ if (c.result !== null) {
381
+ let changed = arrayIndex !== c.lastIndex;
382
+ if (!changed) {
383
+ for (const key of c.inputDeps) if (!deepEqual(values[key], c.lastRelevant[key])) {
384
+ changed = true;
385
+ break;
386
+ }
387
+ }
388
+ if (!changed) return c.result;
389
+ }
390
+ c.result = engine.evaluate({
391
+ inputs: values,
392
+ obj: c.convertedField,
393
+ orgVars: {},
394
+ index: arrayIndex
395
+ });
396
+ c.lastIndex = arrayIndex;
397
+ c.lastRelevant = {};
398
+ for (const key of c.inputDeps) c.lastRelevant[key] = values[key];
399
+ return c.result;
400
+ }
401
+ var FormField = React.memo(function FormField({ id, optionsField, fieldName, values, setFormDirty, setFieldValue, setFieldTouched, parentInfo, labelPosition = "left", missingFields = [], spaceCompact = false, workflowForm = false }) {
402
+ const parsedField = useFieldParse(optionsField, values, parentInfo?.arrayIndex);
403
+ const field = asSchemaField(parentInfo ? parsedField : optionsField);
404
+ if (field === null) return null;
405
+ const fieldNamePrefix = parentInfo?.fieldNamePrefix || "";
406
+ const fieldObj = {
407
+ ...field,
408
+ label: field.label || fieldName.charAt(0).toUpperCase() + fieldName.slice(1),
409
+ name: fieldNamePrefix + fieldName,
410
+ optional: resolvedFlag(field.optional) ?? field.default !== void 0
411
+ };
412
+ if (!fieldObj["name"] || fieldName === "v3") return null;
413
+ if (field.hidden === true || !field.type) {
414
+ if (resolvedFlag(field.ignore) && !workflowForm) deleteFieldByPath(values, fieldObj["name"]);
415
+ return null;
416
+ }
417
+ if (!field.type && field.options) fieldObj["type"] = "dropdown";
418
+ let onChange;
419
+ if (field.one_must_be_true && parentInfo?.onChange) {
420
+ const parentOnChange = parentInfo.onChange;
421
+ const parentArrayIndex = parentInfo.arrayIndex ?? 0;
422
+ const fieldOptions = fieldObj["options"];
423
+ onChange = (val) => parentOnChange(fieldName, parentArrayIndex, flagValue(fieldOptions?.["offOption"], false), flagValue(fieldOptions?.["onOption"], true), val);
424
+ }
425
+ if (field.show_if !== void 0 || field.show_if_not !== void 0) {
426
+ let index;
427
+ if (parentInfo) {
428
+ if (!parentInfo?.arrayIndex) index = getClosestParentIndex(parentInfo.fieldNamePrefix);
429
+ else index = parentInfo.arrayIndex;
430
+ }
431
+ let shouldShowField = true;
432
+ if (field.show_if !== void 0) shouldShowField = !!getParentValue(index, field.show_if, values, "", field);
433
+ if (shouldShowField && field.show_if_not !== void 0) shouldShowField = !getParentValue(index, field.show_if_not, values, "", field);
434
+ if (!shouldShowField) {
435
+ if (!workflowForm) deleteFieldByPath(values, fieldObj["name"]);
436
+ return null;
437
+ }
438
+ }
439
+ if (field.depends_on) {
440
+ if (parentInfo?.arrayIndex !== void 0) fieldObj["depends_on"] = field.depends_on.replace("[index]", `[${parentInfo.arrayIndex}]`);
441
+ }
442
+ if (field.enable_if && field.disabled === false) {
443
+ if (typeof field.enable_if === "string") {
444
+ let path = field.enable_if;
445
+ if (parentInfo?.arrayIndex !== void 0) path = field.enable_if.replace("[index]", `[${parentInfo.arrayIndex}]`);
446
+ if (getValueUsingPath(values, path) === false) fieldObj["disabled"] = true;
447
+ }
448
+ }
449
+ if (field.type === "group") {
450
+ const hideHeader = field.noCollapse;
451
+ const HeaderElement = hideHeader ? React.Fragment : UncontrolledCollapsiblePanel;
452
+ const meta = resolveMetaOverrides(field.options, labelPosition, spaceCompact);
453
+ return /* @__PURE__ */ jsx("div", {
454
+ className: "flex flex-col w-full",
455
+ children: /* @__PURE__ */ jsx(HeaderElement, {
456
+ ...!hideHeader && {
457
+ title: (open, setOpen) => /* @__PURE__ */ jsx(GroupHeader, {
458
+ open,
459
+ setOpen,
460
+ title: field.label
461
+ }),
462
+ initialState: field.collapsed !== void 0 ? !field.collapsed : true
463
+ },
464
+ children: /* @__PURE__ */ jsx("div", {
465
+ className: "w-full",
466
+ children: /* @__PURE__ */ jsx(FieldsFromOptions, {
467
+ options: field.options ?? {},
468
+ setFormDirty,
469
+ setFieldValue,
470
+ setFieldTouched,
471
+ values,
472
+ parentInfo,
473
+ workflowForm,
474
+ labelPosition: meta.labelPosition,
475
+ spaceCompact: meta.spaceCompact,
476
+ missingFields
477
+ })
478
+ })
479
+ })
480
+ }, fieldObj["name"]);
481
+ }
482
+ if (typeof field.type === "object" && field.depends_on) {
483
+ const parentValue = getValueUsingPath(values, field.depends_on);
484
+ const resolvedType = field.type[String(parentValue)];
485
+ if (!resolvedType) return null;
486
+ fieldObj["type"] = resolvedType;
487
+ }
488
+ if (field.type === "range" && field.depends_on) {
489
+ const parentValue = getValueUsingPath(values, field.depends_on);
490
+ const { min, max } = field;
491
+ if (typeof min === "object" && typeof max === "object") {
492
+ fieldObj["min"] = min[String(parentValue)];
493
+ fieldObj["max"] = max[String(parentValue)];
494
+ }
495
+ }
496
+ if (field.resetOnChange) {
497
+ const parentValue = getValueUsingPath(values, field.resetOnChange);
498
+ const prevParentValue = field.prevParentValue;
499
+ if (prevParentValue !== void 0 && prevParentValue !== parentValue) deleteFieldByPath(values, fieldObj["name"]);
500
+ field.prevParentValue = parentValue;
501
+ }
502
+ if (field.secondaryField) {
503
+ if (Array.isArray(field.secondaryField)) fieldObj["secondaryField"] = field.secondaryField.map((secondaryField) => fieldNamePrefix + secondaryField);
504
+ else fieldObj["secondaryField"] = fieldNamePrefix + field.secondaryField;
505
+ }
506
+ return /* @__PURE__ */ jsx("div", {
507
+ className: cx("flex w-full", labelPosition === "left" ? "mb-[15px]" : "mb-[5px]"),
508
+ children: /* @__PURE__ */ jsx(InputField, {
509
+ field: fieldObj,
510
+ label: fieldObj["label"],
511
+ setFormDirty,
512
+ setFieldValue,
513
+ setFieldTouched,
514
+ values,
515
+ currentValue: getValueUsingPath(values, fieldObj["name"]),
516
+ onChange,
517
+ disabled: Boolean(fieldObj["disabled"]),
518
+ computeOn: parentInfo?.computeOn || fieldObj["computeOn"],
519
+ labelPosition,
520
+ missingFields,
521
+ spaceCompact,
522
+ workflowForm
523
+ })
524
+ }, `field-${id}`);
525
+ }, (prev, next) => {
526
+ if (!deepEqual(prev.optionsField, next.optionsField)) return false;
527
+ if (prev.values !== next.values) return false;
528
+ if (!deepEqual(prev.parentInfo, next.parentInfo)) return false;
529
+ if (!deepEqual(prev.missingFields, next.missingFields)) return false;
530
+ if (prev.labelPosition !== next.labelPosition) return false;
531
+ if (prev.spaceCompact !== next.spaceCompact) return false;
532
+ if (prev.workflowForm !== next.workflowForm) return false;
533
+ return true;
534
+ });
535
+ function FieldsFromOptions({ options = {}, values, setFormDirty, setFieldValue, setFieldTouched, parentInfo, labelPosition = "left", missingFields = [], spaceCompact = false, workflowForm = false }) {
536
+ return Object.keys(options).map((fieldName, idx) => /* @__PURE__ */ jsx(FormField, {
537
+ id: idx,
538
+ optionsField: options[fieldName],
539
+ fieldName,
540
+ values,
541
+ setFormDirty,
542
+ setFieldValue,
543
+ setFieldTouched,
544
+ parentInfo,
545
+ labelPosition,
546
+ missingFields,
547
+ spaceCompact,
548
+ workflowForm
549
+ }, fieldName));
550
+ }
551
+ var noop = () => {};
552
+ function DynamicFormContent({ options, setValues, setFormDirty, labelPosition, missingFields, spaceCompact, organizationVariables, remoteVars, workflowForm, onSubmit, submitLabel, values, contextKey }) {
553
+ const { setFieldValue, setFieldTouched } = useFormikContext();
554
+ const opts = useParsedOpts(options, values, organizationVariables, void 0, void 0, remoteVars);
555
+ const handleChange = useCallback((state) => {
556
+ if (setValues) setValues(state);
557
+ }, [setValues]);
558
+ const wizardConfig = parseWizardConfig(opts);
559
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
560
+ /* @__PURE__ */ jsx(DirtyStateBridge, { setFormDirty }),
561
+ /* @__PURE__ */ jsx(FormikStateBridge, { onChange: handleChange }),
562
+ /* @__PURE__ */ jsx(DynamicDefaultsSync, { options: opts }, contextKey ?? ""),
563
+ wizardConfig !== null && wizardConfig ? /* @__PURE__ */ jsx(WizardContainer, {
564
+ wizardConfig,
565
+ values,
566
+ onChange: handleChange,
567
+ onSubmit,
568
+ className: "w-full",
569
+ ...resolveMetaOverrides(options, labelPosition, spaceCompact),
570
+ missingFields,
571
+ workflowForm,
572
+ setFieldValue,
573
+ setFieldTouched
574
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(FieldsFromOptions, {
575
+ ...resolveMetaOverrides(options, labelPosition, spaceCompact),
576
+ options: opts,
577
+ values,
578
+ setFormDirty,
579
+ setFieldValue,
580
+ setFieldTouched,
581
+ missingFields,
582
+ workflowForm
583
+ }), onSubmit !== void 0 && !workflowForm && /* @__PURE__ */ jsx("div", {
584
+ className: "mt-4",
585
+ children: /* @__PURE__ */ jsx("input", {
586
+ type: "submit",
587
+ className: "btn btn-info",
588
+ value: submitLabel
589
+ })
590
+ })] })
591
+ ] });
592
+ }
593
+ var NO_FIELDS = {};
594
+ function DynamicForm({ formJSONs: options = {}, reinitialize = false, initialValues, setValues, setFormDirty = noop, formikRef, labelPosition = "left", missingFields = [], spaceCompact = false, organizationVariables, remoteVars, needsOrganizationVariables = false, onSubmit = void 0, submitLabel = "Submit", className = "w-full", workflowForm = false, contextKey, skipValueParse = false, fields = NO_FIELDS }) {
595
+ const engine = useWorkflowEngine();
596
+ const [parseReady, setParseReady] = useState(() => engine.isReady());
597
+ useEffect(() => {
598
+ engine.init();
599
+ return engine.onReady(setParseReady);
600
+ }, [engine]);
601
+ if (!parseReady) return /* @__PURE__ */ jsx(Loader, {});
602
+ const parsedInitVals = skipValueParse ? initialValues : initialValues && engine.evaluate({
603
+ inputs: initialValues,
604
+ obj: initialValues,
605
+ orgVars: organizationVariables,
606
+ remoteVars
607
+ });
608
+ return /* @__PURE__ */ jsx(FieldRegistryContext.Provider, {
609
+ value: fields,
610
+ children: /* @__PURE__ */ jsx("div", {
611
+ className,
612
+ children: (!needsOrganizationVariables || organizationVariables) && initialValues && /* @__PURE__ */ jsx(Formik, {
613
+ enableReinitialize: reinitialize,
614
+ initialValues: parsedInitVals,
615
+ onSubmit: onSubmit ?? (() => {}),
616
+ onReset: () => {
617
+ setFormDirty(false);
618
+ },
619
+ ...formikRef ? { innerRef: formikRef } : {},
620
+ children: ({ values }) => /* @__PURE__ */ jsx(Form, {
621
+ className: "w-full text-[13px]",
622
+ children: /* @__PURE__ */ jsx(DynamicFormContent, {
623
+ values,
624
+ options,
625
+ setValues,
626
+ setFormDirty,
627
+ labelPosition,
628
+ missingFields,
629
+ spaceCompact,
630
+ organizationVariables,
631
+ remoteVars,
632
+ workflowForm,
633
+ onSubmit,
634
+ submitLabel,
635
+ contextKey
636
+ })
637
+ })
638
+ })
639
+ })
640
+ });
641
+ }
642
+ //#endregion
643
+ export { DynamicDefaultsSync, DynamicForm, FieldsFromOptions, GroupHeader, MultiSelectionDropdown, collectFieldsWithDefaults, defaultReferencesField, findSelfReferencingFieldNames, listLengthsSignature, resolveMetaOverrides, useDynamicDefaultsSync };
@@ -0,0 +1,30 @@
1
+ import FormikCustomDropdown_default from "./FormikCustomDropdown.js";
2
+ import { getPlaceholder } from "../utils/getPlaceholder.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/form/SpecialTypes/DropdownWrapper.tsx
5
+ function DropdownWrapper({ options, onChange, fieldObj, setFormDirty, invalid = false, loading = false, disabled = void 0, allowCustomValue = void 0, currentValue, setFieldValue, setFieldTouched }) {
6
+ return /* @__PURE__ */ jsx(FormikCustomDropdown_default, {
7
+ invalid,
8
+ className: "w-full",
9
+ onChange,
10
+ loading,
11
+ setFormDirty,
12
+ options,
13
+ disabled: disabled ?? Boolean(fieldObj.disabled),
14
+ placeholder: getPlaceholder(fieldObj.placeholder, typeof fieldObj.default === "string" ? fieldObj.default : void 0),
15
+ name: fieldObj.name ?? "",
16
+ ariaLabel: fieldObj.label,
17
+ parentValue: fieldObj.parentValue,
18
+ secondaryField: fieldObj.secondaryField,
19
+ resetOnChange: fieldObj.resetOnChange,
20
+ value: fieldObj.value,
21
+ autoselect: fieldObj.autoselect === void 0 ? void 0 : Boolean(fieldObj.autoselect),
22
+ allowCustomValue: allowCustomValue ?? fieldObj.allowCustomValue,
23
+ customValueLabel: fieldObj.customValueLabel,
24
+ currentValue,
25
+ setFieldValue,
26
+ setFieldTouched
27
+ });
28
+ }
29
+ //#endregion
30
+ export { DropdownWrapper as default };