@harborclient/sdk 0.4.6 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/dist/components/AsyncListState/index.d.ts +85 -0
  2. package/dist/components/AsyncListState/index.d.ts.map +1 -0
  3. package/dist/components/AsyncListState/index.js +51 -0
  4. package/dist/components/BackButton/index.d.ts +32 -0
  5. package/dist/components/BackButton/index.d.ts.map +1 -0
  6. package/dist/components/BackButton/index.js +19 -0
  7. package/dist/components/Badge/index.d.ts +29 -0
  8. package/dist/components/Badge/index.d.ts.map +1 -0
  9. package/dist/components/Badge/index.js +32 -0
  10. package/dist/components/BusyIndicator/index.d.ts +16 -0
  11. package/dist/components/BusyIndicator/index.d.ts.map +1 -0
  12. package/dist/components/BusyIndicator/index.js +78 -0
  13. package/dist/components/Button/index.d.ts +29 -0
  14. package/dist/components/Button/index.d.ts.map +1 -0
  15. package/dist/components/Button/index.js +25 -0
  16. package/dist/components/CodeEditor/config.d.ts +51 -0
  17. package/dist/components/CodeEditor/config.d.ts.map +1 -0
  18. package/dist/components/CodeEditor/config.js +64 -0
  19. package/dist/components/CodeEditor/index.d.ts +77 -0
  20. package/dist/components/CodeEditor/index.d.ts.map +1 -0
  21. package/dist/components/CodeEditor/index.js +319 -0
  22. package/dist/components/CodeEditor/themes.d.ts +19 -0
  23. package/dist/components/CodeEditor/themes.d.ts.map +1 -0
  24. package/dist/components/CodeEditor/themes.js +37 -0
  25. package/dist/components/EmptyState/index.d.ts +26 -0
  26. package/dist/components/EmptyState/index.d.ts.map +1 -0
  27. package/dist/components/EmptyState/index.js +25 -0
  28. package/dist/components/FaIcon/index.d.ts +22 -0
  29. package/dist/components/FaIcon/index.d.ts.map +1 -0
  30. package/dist/components/FaIcon/index.js +13 -0
  31. package/dist/components/FieldError/index.d.ts +39 -0
  32. package/dist/components/FieldError/index.d.ts.map +1 -0
  33. package/dist/components/FieldError/index.js +34 -0
  34. package/dist/components/FooterButton/index.d.ts +30 -0
  35. package/dist/components/FooterButton/index.d.ts.map +1 -0
  36. package/dist/components/FooterButton/index.js +19 -0
  37. package/dist/components/FooterIcon/index.d.ts +32 -0
  38. package/dist/components/FooterIcon/index.d.ts.map +1 -0
  39. package/dist/components/FooterIcon/index.js +21 -0
  40. package/dist/components/FormDataEditor/index.d.ts +31 -0
  41. package/dist/components/FormDataEditor/index.d.ts.map +1 -0
  42. package/dist/components/FormDataEditor/index.js +109 -0
  43. package/dist/components/FormGroup/index.d.ts +75 -0
  44. package/dist/components/FormGroup/index.d.ts.map +1 -0
  45. package/dist/components/FormGroup/index.js +95 -0
  46. package/dist/components/KeyValueEditor/index.d.ts +35 -0
  47. package/dist/components/KeyValueEditor/index.d.ts.map +1 -0
  48. package/dist/components/KeyValueEditor/index.js +40 -0
  49. package/dist/components/MethodSelect/index.d.ts +20 -0
  50. package/dist/components/MethodSelect/index.d.ts.map +1 -0
  51. package/dist/components/MethodSelect/index.js +9 -0
  52. package/dist/components/Modal/ModalFooter.d.ts +25 -0
  53. package/dist/components/Modal/ModalFooter.d.ts.map +1 -0
  54. package/dist/components/Modal/ModalFooter.js +13 -0
  55. package/dist/components/Modal/ModalFormLayout.d.ts +31 -0
  56. package/dist/components/Modal/ModalFormLayout.d.ts.map +1 -0
  57. package/dist/components/Modal/ModalFormLayout.js +14 -0
  58. package/dist/components/Modal/ModalHeader.d.ts +34 -0
  59. package/dist/components/Modal/ModalHeader.d.ts.map +1 -0
  60. package/dist/components/Modal/ModalHeader.js +11 -0
  61. package/dist/components/Modal/index.d.ts +59 -0
  62. package/dist/components/Modal/index.d.ts.map +1 -0
  63. package/dist/components/Modal/index.js +37 -0
  64. package/dist/components/OverlayCloseButton/index.d.ts +25 -0
  65. package/dist/components/OverlayCloseButton/index.d.ts.map +1 -0
  66. package/dist/components/OverlayCloseButton/index.js +16 -0
  67. package/dist/components/OverlayPage/index.d.ts +40 -0
  68. package/dist/components/OverlayPage/index.d.ts.map +1 -0
  69. package/dist/components/OverlayPage/index.js +18 -0
  70. package/dist/components/PageHeader/index.d.ts +31 -0
  71. package/dist/components/PageHeader/index.d.ts.map +1 -0
  72. package/dist/components/PageHeader/index.js +12 -0
  73. package/dist/components/PanelCloseButton/index.d.ts +30 -0
  74. package/dist/components/PanelCloseButton/index.d.ts.map +1 -0
  75. package/dist/components/PanelCloseButton/index.js +17 -0
  76. package/dist/components/Resizable/Resizable.d.ts +48 -0
  77. package/dist/components/Resizable/Resizable.d.ts.map +1 -0
  78. package/dist/components/Resizable/Resizable.js +32 -0
  79. package/dist/components/Resizable/ResizeHandle.d.ts +41 -0
  80. package/dist/components/Resizable/ResizeHandle.d.ts.map +1 -0
  81. package/dist/components/Resizable/ResizeHandle.js +17 -0
  82. package/dist/components/Resizable/footerPanelUtils.d.ts +25 -0
  83. package/dist/components/Resizable/footerPanelUtils.d.ts.map +1 -0
  84. package/dist/components/Resizable/footerPanelUtils.js +59 -0
  85. package/dist/components/Resizable/index.d.ts +4 -0
  86. package/dist/components/Resizable/index.d.ts.map +1 -0
  87. package/dist/components/Resizable/index.js +3 -0
  88. package/dist/components/Resizable/useResizable.d.ts +42 -0
  89. package/dist/components/Resizable/useResizable.d.ts.map +1 -0
  90. package/dist/components/Resizable/useResizable.js +151 -0
  91. package/dist/components/ResourceList/index.d.ts +73 -0
  92. package/dist/components/ResourceList/index.d.ts.map +1 -0
  93. package/dist/components/ResourceList/index.js +44 -0
  94. package/dist/components/RowActionsMenu/index.d.ts +33 -0
  95. package/dist/components/RowActionsMenu/index.d.ts.map +1 -0
  96. package/dist/components/RowActionsMenu/index.js +54 -0
  97. package/dist/components/SegmentedTabs/index.d.ts +107 -0
  98. package/dist/components/SegmentedTabs/index.d.ts.map +1 -0
  99. package/dist/components/SegmentedTabs/index.js +111 -0
  100. package/dist/components/Spinner/index.d.ts +26 -0
  101. package/dist/components/Spinner/index.d.ts.map +1 -0
  102. package/dist/components/Spinner/index.js +22 -0
  103. package/dist/components/StatusMessage/index.d.ts +29 -0
  104. package/dist/components/StatusMessage/index.d.ts.map +1 -0
  105. package/dist/components/StatusMessage/index.js +13 -0
  106. package/dist/components/TabCloseButton/index.d.ts +25 -0
  107. package/dist/components/TabCloseButton/index.d.ts.map +1 -0
  108. package/dist/components/TabCloseButton/index.js +13 -0
  109. package/dist/components/VariableInput/index.d.ts +58 -0
  110. package/dist/components/VariableInput/index.d.ts.map +1 -0
  111. package/dist/components/VariableInput/index.js +90 -0
  112. package/dist/components/VariableTable/index.d.ts +22 -0
  113. package/dist/components/VariableTable/index.d.ts.map +1 -0
  114. package/dist/components/VariableTable/index.js +43 -0
  115. package/dist/components/classes.d.ts +11 -0
  116. package/dist/components/classes.d.ts.map +1 -0
  117. package/dist/components/classes.js +14 -0
  118. package/dist/components/forms/Input.d.ts +22 -0
  119. package/dist/components/forms/Input.d.ts.map +1 -0
  120. package/dist/components/forms/Input.js +9 -0
  121. package/dist/components/forms/Select.d.ts +24 -0
  122. package/dist/components/forms/Select.d.ts.map +1 -0
  123. package/dist/components/forms/Select.js +10 -0
  124. package/dist/components/forms/Textarea.d.ts +22 -0
  125. package/dist/components/forms/Textarea.d.ts.map +1 -0
  126. package/dist/components/forms/Textarea.js +8 -0
  127. package/dist/components/forms/classes.d.ts +24 -0
  128. package/dist/components/forms/classes.d.ts.map +1 -0
  129. package/dist/components/forms/classes.js +32 -0
  130. package/dist/components/forms/index.d.ts +5 -0
  131. package/dist/components/forms/index.d.ts.map +1 -0
  132. package/dist/components/forms/index.js +4 -0
  133. package/dist/components/index.d.ts +51 -0
  134. package/dist/components/index.d.ts.map +1 -0
  135. package/dist/components/index.js +37 -0
  136. package/dist/components/rowActionsMenuHelpers.d.ts +13 -0
  137. package/dist/components/rowActionsMenuHelpers.d.ts.map +1 -0
  138. package/dist/components/rowActionsMenuHelpers.js +29 -0
  139. package/dist/components/useDialogFocus.d.ts +16 -0
  140. package/dist/components/useDialogFocus.d.ts.map +1 -0
  141. package/dist/components/useDialogFocus.js +81 -0
  142. package/dist/components/utils.d.ts +29 -0
  143. package/dist/components/utils.d.ts.map +1 -0
  144. package/dist/components/utils.js +89 -0
  145. package/dist/components/utils.test.d.ts +2 -0
  146. package/dist/components/utils.test.d.ts.map +1 -0
  147. package/dist/components/utils.test.js +27 -0
  148. package/dist/http/substitute.d.ts.map +1 -1
  149. package/dist/http/substitute.js +9 -3
  150. package/dist/http/substitute.test.js +8 -0
  151. package/dist/main.d.ts +1 -1
  152. package/dist/main.d.ts.map +1 -1
  153. package/dist/runtime/react.d.ts +16 -1
  154. package/dist/runtime/react.js +40 -0
  155. package/dist/types.d.ts +100 -0
  156. package/dist/types.d.ts.map +1 -1
  157. package/dist/ui/codeEditorSettings.d.ts +29 -0
  158. package/dist/ui/codeEditorSettings.d.ts.map +1 -0
  159. package/dist/ui/codeEditorSettings.js +52 -0
  160. package/dist/ui/index.d.ts +1 -0
  161. package/dist/ui/index.d.ts.map +1 -1
  162. package/dist/ui/index.js +1 -0
  163. package/dist/variables/dynamic.d.ts +49 -0
  164. package/dist/variables/dynamic.d.ts.map +1 -0
  165. package/dist/variables/dynamic.js +735 -0
  166. package/dist/variables/dynamic.test.d.ts +2 -0
  167. package/dist/variables/dynamic.test.d.ts.map +1 -0
  168. package/dist/variables/dynamic.test.js +60 -0
  169. package/dist/variables/index.d.ts +3 -0
  170. package/dist/variables/index.d.ts.map +1 -0
  171. package/dist/variables/index.js +2 -0
  172. package/dist/variables/tokens.d.ts +44 -0
  173. package/dist/variables/tokens.d.ts.map +1 -0
  174. package/dist/variables/tokens.js +76 -0
  175. package/dist/variables/tokens.test.d.ts +2 -0
  176. package/dist/variables/tokens.test.d.ts.map +1 -0
  177. package/dist/variables/tokens.test.js +115 -0
  178. package/package.json +75 -14
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "@harborclient/sdk/jsx-runtime";
2
+ import { FaIcon } from '../FaIcon/index.js';
3
+ /**
4
+ * Square icon toggle styles for footer sidebar buttons.
5
+ *
6
+ * @param active - Whether the associated sidebar is currently visible.
7
+ */
8
+ function footerIconButton(active) {
9
+ return active
10
+ ? 'inline-flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-md border-none bg-surface text-text shadow-sm app-no-drag'
11
+ : 'inline-flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-md border-none bg-transparent text-muted hover:bg-selection hover:text-text app-no-drag';
12
+ }
13
+ /**
14
+ * Icon-only toggle button for the window footer bar, used to show or hide
15
+ * sidebars and similar panels.
16
+ */
17
+ export function FooterIcon({ icon, active, onClick, label, className }) {
18
+ const accessibleLabel = active ? `Hide ${label}` : `Show ${label}`;
19
+ const classes = className ? `${footerIconButton(active)} ${className}` : footerIconButton(active);
20
+ return (_jsx("button", { type: "button", className: classes, onClick: onClick, "aria-pressed": active, "aria-label": accessibleLabel, title: accessibleLabel, children: _jsx(FaIcon, { icon: icon, className: "h-4 w-4" }) }));
21
+ }
@@ -0,0 +1,31 @@
1
+ import type { JSX } from 'react';
2
+ import type { FormDataPart, Variable } from '../../types.js';
3
+ export interface Props {
4
+ /**
5
+ * Editable multipart form rows.
6
+ */
7
+ parts: FormDataPart[];
8
+ /**
9
+ * Called when rows are added, updated, or removed.
10
+ *
11
+ * @param parts - Updated part list.
12
+ */
13
+ onChange: (parts: FormDataPart[]) => void;
14
+ /**
15
+ * Collection-scoped variables for value highlighting and tooltips.
16
+ */
17
+ variables: Variable[];
18
+ /**
19
+ * Opens the host file picker and returns selected absolute paths.
20
+ */
21
+ onSelectFiles: () => Promise<string[]>;
22
+ /**
23
+ * Opens collection settings to edit a hovered variable.
24
+ */
25
+ onEditVariable?: () => void;
26
+ }
27
+ /**
28
+ * Editable table of multipart form parts with text and file field types.
29
+ */
30
+ export declare function FormDataEditor({ parts, onChange, variables, onSelectFiles, onEditVariable }: Props): JSX.Element;
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FormDataEditor/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAoB,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAM/E,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,KAAK,EAAE,YAAY,EAAE,CAAC;IAEtB;;;;OAIG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAE1C;;OAEG;IACH,SAAS,EAAE,QAAQ,EAAE,CAAC;IAEtB;;OAEG;IACH,aAAa,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEvC;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAqCD;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,QAAQ,EACR,SAAS,EACT,aAAa,EACb,cAAc,EACf,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAqLrB"}
@@ -0,0 +1,109 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
+ import { faXmark } from '@fortawesome/free-solid-svg-icons';
3
+ import { useMemo } from '@harborclient/sdk/react';
4
+ import { Button } from '../Button/index.js';
5
+ import { FaIcon } from '../FaIcon/index.js';
6
+ import { Input, Select, fieldFrame } from '../forms/index.js';
7
+ import { VariableInput } from '../VariableInput/index.js';
8
+ const thClass = 'border-r border-b border-separator px-1.5 py-1 text-left text-[14px] font-medium uppercase tracking-wide text-muted last:border-r-0';
9
+ const tdClass = 'border-r border-b border-separator p-1.5 align-top last:border-r-0';
10
+ /**
11
+ * Returns a blank multipart form part with enabled set to true.
12
+ */
13
+ function emptyFormPart() {
14
+ return { key: '', value: '', enabled: true, type: 'text', files: [] };
15
+ }
16
+ /**
17
+ * Returns the file name portion of an absolute path.
18
+ *
19
+ * @param filePath - Absolute file path.
20
+ */
21
+ function fileBasename(filePath) {
22
+ const normalized = filePath.replace(/\\/g, '/');
23
+ const lastSlash = normalized.lastIndexOf('/');
24
+ return lastSlash >= 0 ? normalized.slice(lastSlash + 1) : normalized;
25
+ }
26
+ /**
27
+ * Ensures at least one row exists and appends a trailing blank row when needed.
28
+ *
29
+ * @param parts - Current form parts.
30
+ * @returns Rows safe to render in the editor.
31
+ */
32
+ function withTrailingRow(parts) {
33
+ if (parts.length === 0) {
34
+ return [emptyFormPart()];
35
+ }
36
+ return parts;
37
+ }
38
+ /**
39
+ * Editable table of multipart form parts with text and file field types.
40
+ */
41
+ export function FormDataEditor({ parts, onChange, variables, onSelectFiles, onEditVariable }) {
42
+ /**
43
+ * Ensures at least one row exists for rendering, including a trailing blank row.
44
+ */
45
+ const rows = useMemo(() => withTrailingRow(parts), [parts]);
46
+ /**
47
+ * Updates a single row by index, auto-appending a blank row when the last key is filled.
48
+ *
49
+ * @param index - Row index to update.
50
+ * @param patch - Partial fields to merge into the row.
51
+ */
52
+ const updateRow = (index, patch) => {
53
+ const next = rows.map((row, i) => (i === index ? { ...row, ...patch } : row));
54
+ const isLast = index === rows.length - 1;
55
+ if (isLast && next[index].key.trim() !== '') {
56
+ next.push(emptyFormPart());
57
+ }
58
+ onChange(next);
59
+ };
60
+ /**
61
+ * Removes a row, keeping at least one empty row.
62
+ *
63
+ * @param index - Row index to remove.
64
+ */
65
+ const removeRow = (index) => {
66
+ if (rows.length === 1) {
67
+ onChange([emptyFormPart()]);
68
+ return;
69
+ }
70
+ onChange(rows.filter((_, i) => i !== index));
71
+ };
72
+ /**
73
+ * Opens the host file picker and merges selected paths into a file row.
74
+ *
75
+ * @param index - Row index to attach files to.
76
+ */
77
+ const chooseFiles = async (index) => {
78
+ const selected = await onSelectFiles();
79
+ if (selected.length === 0) {
80
+ return;
81
+ }
82
+ const currentFiles = rows[index]?.files ?? [];
83
+ const merged = [...currentFiles];
84
+ for (const filePath of selected) {
85
+ if (!merged.includes(filePath)) {
86
+ merged.push(filePath);
87
+ }
88
+ }
89
+ updateRow(index, { type: 'file', files: merged, value: '' });
90
+ };
91
+ /**
92
+ * Removes one file path from a file row.
93
+ *
94
+ * @param index - Row index containing the file.
95
+ * @param filePath - Absolute path to remove.
96
+ */
97
+ const removeFile = (index, filePath) => {
98
+ const currentFiles = rows[index]?.files ?? [];
99
+ updateRow(index, { files: currentFiles.filter((file) => file !== filePath) });
100
+ };
101
+ return (_jsx("div", { className: "overflow-hidden rounded-md border border-separator", children: _jsxs("table", { className: "w-full border-collapse", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { className: `${thClass} w-6 p-0` }), _jsx("th", { className: thClass, children: "Key" }), _jsx("th", { className: `${thClass} w-24`, children: "Type" }), _jsx("th", { className: thClass, children: "Value" }), _jsx("th", { className: `${thClass} w-7 p-0` })] }) }), _jsx("tbody", { className: "[&_tr:last-child_td]:border-b-0", children: rows.map((row, index) => (_jsxs("tr", { className: "group", children: [_jsx("td", { className: `${tdClass} w-6 p-1 text-center`, children: _jsx(Input, { type: "checkbox", className: "app-no-drag", checked: row.enabled, onChange: (e) => updateRow(index, { enabled: e.target.checked }), "aria-label": `Enable row ${index + 1}`, title: "Enable" }) }), _jsx("td", { className: tdClass, children: _jsx(Input, { type: "text", className: "w-full", value: row.key, placeholder: "field", "aria-label": `Key, row ${index + 1}`, onChange: (e) => updateRow(index, { key: e.target.value }) }) }), _jsx("td", { className: tdClass, children: _jsxs(Select, { className: "w-full", value: row.type, "aria-label": `Type, row ${index + 1}`, onChange: (e) => {
102
+ const type = e.target.value;
103
+ updateRow(index, {
104
+ type,
105
+ value: type === 'text' ? row.value : '',
106
+ files: type === 'file' ? row.files : []
107
+ });
108
+ }, children: [_jsx("option", { value: "text", children: "Text" }), _jsx("option", { value: "file", children: "File" })] }) }), _jsx("td", { className: tdClass, children: row.type === 'text' ? (_jsx(VariableInput, { wrapperClassName: `${fieldFrame} w-full`, className: "app-no-drag", value: row.value, onChange: (value) => updateRow(index, { value }), variables: variables, placeholder: "value", "aria-label": `Value, row ${index + 1}`, onEditVariable: onEditVariable })) : (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Button, { type: "button", variant: "secondary", className: "self-start px-2 py-0.5 text-[14px]", onClick: () => void chooseFiles(index), children: "Choose files" }), row.files.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-1", children: row.files.map((filePath) => (_jsxs("span", { className: "inline-flex max-w-full items-center gap-1 rounded-md border border-separator bg-control px-1.5 py-0.5 text-[14px] text-text", title: filePath, children: [_jsx("span", { className: "truncate", children: fileBasename(filePath) }), _jsx("button", { type: "button", className: "inline-flex h-4 w-4 shrink-0 cursor-pointer items-center justify-center rounded border-none bg-transparent text-muted hover:bg-selection hover:text-text app-no-drag", onClick: () => removeFile(index, filePath), title: "Remove file", children: _jsx(FaIcon, { icon: faXmark, className: "h-3 w-3" }) })] }, filePath))) }))] })) }), _jsx("td", { className: `${tdClass} w-7 p-1 text-center`, children: _jsx(Button, { type: "button", variant: "iconDanger", onClick: () => removeRow(index), title: "Remove", children: _jsx(FaIcon, { icon: faXmark, className: "h-3.5 w-3.5" }) }) })] }, index))) })] }) }));
109
+ }
@@ -0,0 +1,75 @@
1
+ import type { JSX, ReactNode } from 'react';
2
+ /**
3
+ * Layout preset for label and control placement within a form group.
4
+ */
5
+ export type FormGroupLayout = 'stacked' | 'checkbox' | 'inline' | 'radio' | 'checkboxAdjacent' | 'associated';
6
+ /**
7
+ * Label color tone for form group headings.
8
+ */
9
+ export type FormGroupLabelTone = 'default' | 'muted';
10
+ interface Props {
11
+ /**
12
+ * Visible label text, or screen-reader-only text when `srOnly` is set.
13
+ */
14
+ label: ReactNode;
15
+ /**
16
+ * Form control(s) rendered inside or beside the label. Omitted for `associated` layout.
17
+ */
18
+ children?: ReactNode;
19
+ /**
20
+ * Associates the label with a control via `htmlFor`.
21
+ */
22
+ htmlFor?: string;
23
+ /**
24
+ * Muted helper text rendered below the control (stacked layout only).
25
+ */
26
+ description?: ReactNode;
27
+ /**
28
+ * Validation error rendered below the control with linked `aria-describedby`.
29
+ */
30
+ error?: ReactNode;
31
+ /**
32
+ * Explicit id for the error element; defaults to `${htmlFor}-error` when `htmlFor` is set.
33
+ */
34
+ errorId?: string;
35
+ /**
36
+ * Label and control placement. Defaults to stacked (label above control).
37
+ */
38
+ layout?: FormGroupLayout;
39
+ /**
40
+ * Label color style. Defaults to prominent `text-text`.
41
+ */
42
+ labelTone?: FormGroupLabelTone;
43
+ /**
44
+ * Hides the label visually while keeping it available to screen readers.
45
+ */
46
+ srOnly?: boolean;
47
+ /**
48
+ * Additional Tailwind classes on the outer wrapper.
49
+ */
50
+ className?: string;
51
+ /**
52
+ * Extra classes on the label element (associated and checkboxAdjacent layouts).
53
+ */
54
+ labelClassName?: string;
55
+ }
56
+ /**
57
+ * Reusable form field wrapper that pairs a label with one or more controls.
58
+ * Supports stacked fields, checkboxes, inline rows, radio options, and
59
+ * adjacent checkbox rows used in list pickers.
60
+ *
61
+ * @param label - Field label text.
62
+ * @param children - Input, select, or composite control content.
63
+ * @param htmlFor - ID of the primary associated control.
64
+ * @param description - Optional helper text below the control.
65
+ * @param error - Optional validation error below the control.
66
+ * @param errorId - Explicit error element id for `aria-describedby`.
67
+ * @param layout - Label/control placement preset.
68
+ * @param labelTone - Label color style.
69
+ * @param srOnly - Hide label visually for screen-reader-only labels.
70
+ * @param className - Extra classes on the outer wrapper.
71
+ * @param labelClassName - Extra classes on the label element.
72
+ */
73
+ export declare function FormGroup({ label, children, htmlFor, description, error, errorId, layout, labelTone, srOnly, className, labelClassName }: Props): JSX.Element;
74
+ export {};
75
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FormGroup/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAG5C;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,UAAU,GACV,QAAQ,GACR,OAAO,GACP,kBAAkB,GAClB,YAAY,CAAC;AAEjB;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAAC;AAErD,UAAU,KAAK;IACb;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IAExB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IAEzB;;OAEG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAE/B;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAkDD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,QAAQ,EACR,OAAO,EACP,WAAW,EACX,KAAK,EACL,OAAO,EACP,MAAkB,EAClB,SAAqB,EACrB,MAAc,EACd,SAAS,EACT,cAAc,EACf,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAkFrB"}
@@ -0,0 +1,95 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
+ import { cloneElement, isValidElement } from '@harborclient/sdk/react';
3
+ import { FieldError } from '../FieldError/index.js';
4
+ /**
5
+ * Returns Tailwind classes for the label text based on tone and visibility.
6
+ *
7
+ * @param tone - Label color preset.
8
+ * @param srOnly - Whether the label is visually hidden.
9
+ * @param inline - Whether the label sits beside the control in a row.
10
+ * @returns Class string for the label element.
11
+ */
12
+ function labelClasses(tone, srOnly, inline) {
13
+ const base = 'text-[14px]';
14
+ const visibility = srOnly ? 'sr-only' : '';
15
+ if (inline) {
16
+ const color = tone === 'muted' ? 'shrink-0 text-muted' : 'shrink-0 font-medium text-text';
17
+ return `${base} ${color} ${visibility}`.trim();
18
+ }
19
+ const color = tone === 'muted' ? 'text-muted' : 'font-medium text-text';
20
+ return `${base} ${color} ${visibility}`.trim();
21
+ }
22
+ /**
23
+ * Merges accessibility attributes onto a single control when a field error is present.
24
+ *
25
+ * @param child - Form control element to enhance.
26
+ * @param describedBy - Id of the error element for `aria-describedby`.
27
+ * @returns The original node or a cloned element with invalid/describedby props.
28
+ */
29
+ function enhanceControl(child, describedBy) {
30
+ if (!describedBy ||
31
+ !isValidElement(child)) {
32
+ return child;
33
+ }
34
+ const existingDescribedBy = typeof child.props['aria-describedby'] === 'string'
35
+ ? child.props['aria-describedby']
36
+ : undefined;
37
+ const mergedDescribedBy = existingDescribedBy
38
+ ? `${existingDescribedBy} ${describedBy}`
39
+ : describedBy;
40
+ return cloneElement(child, {
41
+ 'aria-invalid': true,
42
+ 'aria-describedby': mergedDescribedBy
43
+ });
44
+ }
45
+ /**
46
+ * Reusable form field wrapper that pairs a label with one or more controls.
47
+ * Supports stacked fields, checkboxes, inline rows, radio options, and
48
+ * adjacent checkbox rows used in list pickers.
49
+ *
50
+ * @param label - Field label text.
51
+ * @param children - Input, select, or composite control content.
52
+ * @param htmlFor - ID of the primary associated control.
53
+ * @param description - Optional helper text below the control.
54
+ * @param error - Optional validation error below the control.
55
+ * @param errorId - Explicit error element id for `aria-describedby`.
56
+ * @param layout - Label/control placement preset.
57
+ * @param labelTone - Label color style.
58
+ * @param srOnly - Hide label visually for screen-reader-only labels.
59
+ * @param className - Extra classes on the outer wrapper.
60
+ * @param labelClassName - Extra classes on the label element.
61
+ */
62
+ export function FormGroup({ label, children, htmlFor, description, error, errorId, layout = 'stacked', labelTone = 'default', srOnly = false, className, labelClassName }) {
63
+ const extra = className ?? '';
64
+ if (layout === 'associated') {
65
+ const associatedClasses = labelClassName ?? 'text-[14px] text-text';
66
+ return (_jsx("label", { htmlFor: htmlFor, className: associatedClasses, children: label }));
67
+ }
68
+ if (layout === 'checkboxAdjacent') {
69
+ const wrapperClasses = extra ? `flex items-start gap-2 ${extra}` : 'flex items-start gap-2';
70
+ const adjacentLabelClasses = labelClassName ?? 'min-w-0 flex-1 text-[14px] text-text';
71
+ return (_jsxs("div", { className: wrapperClasses, children: [children, _jsx("label", { htmlFor: htmlFor, className: adjacentLabelClasses, children: label })] }));
72
+ }
73
+ if (layout === 'radio') {
74
+ const wrapperClasses = extra
75
+ ? `inline-flex cursor-pointer items-center gap-1.5 text-[14px] text-text app-no-drag ${extra}`
76
+ : 'inline-flex cursor-pointer items-center gap-1.5 text-[14px] text-text app-no-drag';
77
+ return (_jsxs("label", { htmlFor: htmlFor, className: wrapperClasses, children: [children, label] }));
78
+ }
79
+ if (layout === 'checkbox') {
80
+ const wrapperClasses = extra ? `flex items-center gap-2 ${extra}` : 'flex items-center gap-2';
81
+ return (_jsxs("label", { htmlFor: htmlFor, className: wrapperClasses, children: [children, _jsx("span", { className: labelClasses(labelTone, srOnly, false), children: label })] }));
82
+ }
83
+ if (layout === 'inline') {
84
+ const wrapperClasses = extra
85
+ ? `flex min-w-0 flex-1 items-center gap-2 ${extra}`
86
+ : 'flex min-w-0 flex-1 items-center gap-2';
87
+ return (_jsxs("label", { htmlFor: htmlFor, className: wrapperClasses, children: [_jsx("span", { className: labelClasses(labelTone, srOnly, true), children: label }), children] }));
88
+ }
89
+ const resolvedErrorId = error != null && error !== ''
90
+ ? (errorId ?? (htmlFor ? `${htmlFor}-error` : undefined))
91
+ : undefined;
92
+ const control = enhanceControl(children, resolvedErrorId);
93
+ const wrapperClasses = extra ? `flex flex-col gap-1 ${extra}` : 'flex flex-col gap-1';
94
+ return (_jsxs("div", { className: wrapperClasses, children: [_jsxs("label", { htmlFor: htmlFor, className: "flex flex-col gap-1", children: [_jsx("span", { className: labelClasses(labelTone, srOnly, false), children: label }), control, description != null && description !== '' ? (_jsx("p", { className: "m-0 text-[14px] text-muted", children: description })) : null] }), resolvedErrorId ? (_jsx(FieldError, { id: resolvedErrorId, spacing: "field", children: error })) : null] }));
95
+ }
@@ -0,0 +1,35 @@
1
+ import type { JSX } from 'react';
2
+ import type { KeyValue, Variable } from '../../types.js';
3
+ export interface Props {
4
+ /**
5
+ * Editable key-value rows.
6
+ */
7
+ rows: KeyValue[];
8
+ /**
9
+ * Called when rows are added, updated, or removed.
10
+ *
11
+ * @param rows - Updated row list.
12
+ */
13
+ onChange: (rows: KeyValue[]) => void;
14
+ /**
15
+ * Placeholder text for the key column.
16
+ */
17
+ placeholderKey?: string;
18
+ /**
19
+ * Placeholder text for the value column.
20
+ */
21
+ placeholderValue?: string;
22
+ /**
23
+ * Collection-scoped variables for value highlighting and tooltips.
24
+ */
25
+ variables: Variable[];
26
+ /**
27
+ * Opens collection settings to edit a hovered variable.
28
+ */
29
+ onEditVariable?: () => void;
30
+ }
31
+ /**
32
+ * Editable table of key-value rows with enable toggles for headers and params.
33
+ */
34
+ export declare function KeyValueEditor({ rows, onChange, placeholderKey, placeholderValue, variables, onEditVariable }: Props): JSX.Element;
35
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/KeyValueEditor/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAMzD,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,IAAI,EAAE,QAAQ,EAAE,CAAC;IAEjB;;;;OAIG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;IAErC;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,SAAS,EAAE,QAAQ,EAAE,CAAC;IAEtB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,QAAQ,EACR,cAAsB,EACtB,gBAA0B,EAC1B,SAAS,EACT,cAAc,EACf,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CA2FrB"}
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
+ import { faXmark } from '@fortawesome/free-solid-svg-icons';
3
+ import { Button } from '../Button/index.js';
4
+ import { FaIcon } from '../FaIcon/index.js';
5
+ import { Input, fieldFrame } from '../forms/index.js';
6
+ import { VariableInput } from '../VariableInput/index.js';
7
+ const thClass = 'border-r border-b border-separator px-1.5 py-1 text-left text-[14px] font-medium uppercase tracking-wide text-muted last:border-r-0';
8
+ const tdClass = 'border-r border-b border-separator p-1.5 last:border-r-0';
9
+ /**
10
+ * Editable table of key-value rows with enable toggles for headers and params.
11
+ */
12
+ export function KeyValueEditor({ rows, onChange, placeholderKey = 'Key', placeholderValue = 'Value', variables, onEditVariable }) {
13
+ /**
14
+ * Updates a single row by index.
15
+ *
16
+ * @param index - Row index to update.
17
+ * @param patch - Partial fields to merge into the row.
18
+ */
19
+ const updateRow = (index, patch) => {
20
+ const next = rows.map((row, i) => (i === index ? { ...row, ...patch } : row));
21
+ const isLast = index === rows.length - 1;
22
+ if (isLast && next[index].key.trim() !== '') {
23
+ next.push({ key: '', value: '', enabled: true });
24
+ }
25
+ onChange(next);
26
+ };
27
+ /**
28
+ * Removes a row, keeping at least one empty row.
29
+ *
30
+ * @param index - Row index to remove.
31
+ */
32
+ const removeRow = (index) => {
33
+ if (rows.length === 1) {
34
+ onChange([{ key: '', value: '', enabled: true }]);
35
+ return;
36
+ }
37
+ onChange(rows.filter((_, i) => i !== index));
38
+ };
39
+ return (_jsx("div", { className: "overflow-hidden rounded-md border border-separator", children: _jsxs("table", { className: "w-full border-collapse", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { className: `${thClass} w-6 p-0` }), _jsx("th", { className: thClass, children: "Key" }), _jsx("th", { className: thClass, children: "Value" }), _jsx("th", { className: `${thClass} w-7 p-0` })] }) }), _jsx("tbody", { className: "[&_tr:last-child_td]:border-b-0", children: rows.map((row, index) => (_jsxs("tr", { className: "group", children: [_jsx("td", { className: `${tdClass} w-6 p-1 text-center`, children: _jsx(Input, { type: "checkbox", className: "app-no-drag", checked: row.enabled, onChange: (e) => updateRow(index, { enabled: e.target.checked }), "aria-label": `Enable row ${index + 1}`, title: "Enable" }) }), _jsx("td", { className: tdClass, children: _jsx(Input, { type: "text", className: "w-full", value: row.key, placeholder: placeholderKey, "aria-label": `Key, row ${index + 1}`, onChange: (e) => updateRow(index, { key: e.target.value }) }) }), _jsx("td", { className: tdClass, children: _jsx(VariableInput, { wrapperClassName: `${fieldFrame} w-full`, className: "app-no-drag", value: row.value, onChange: (value) => updateRow(index, { value }), variables: variables, placeholder: placeholderValue, "aria-label": `Value, row ${index + 1}`, onEditVariable: onEditVariable }) }), _jsx("td", { className: `${tdClass} w-7 p-1 text-center`, children: _jsx(Button, { type: "button", variant: "iconDanger", onClick: () => removeRow(index), title: "Remove", children: _jsx(FaIcon, { icon: faXmark, className: "h-3.5 w-3.5" }) }) })] }, index))) })] }) }));
40
+ }
@@ -0,0 +1,20 @@
1
+ import type { JSX } from 'react';
2
+ import type { HttpMethod } from '../../types.js';
3
+ interface Props {
4
+ /**
5
+ * Currently selected HTTP method.
6
+ */
7
+ value: HttpMethod;
8
+ /**
9
+ * Called when the user picks a different method.
10
+ *
11
+ * @param method - Newly selected HTTP method.
12
+ */
13
+ onChange: (method: HttpMethod) => void;
14
+ }
15
+ /**
16
+ * Dropdown for selecting an HTTP request method.
17
+ */
18
+ export declare function MethodSelect({ value, onChange }: Props): JSX.Element;
19
+ export {};
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/MethodSelect/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAKjD,UAAU,KAAK;IACb;;OAEG;IACH,KAAK,EAAE,UAAU,CAAC;IAElB;;;;OAIG;IACH,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;CACxC;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAgBpE"}
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx } from "@harborclient/sdk/jsx-runtime";
2
+ import { Select } from '../forms/index.js';
3
+ const METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'];
4
+ /**
5
+ * Dropdown for selecting an HTTP request method.
6
+ */
7
+ export function MethodSelect({ value, onChange }) {
8
+ return (_jsx(Select, { variant: "plain", className: "w-[100px] shrink-0 cursor-pointer appearance-none border-none bg-transparent px-2 py-1 text-[14px] font-semibold app-no-drag", value: value, "aria-label": "HTTP method", onChange: (e) => onChange(e.target.value), children: METHODS.map((method) => (_jsx("option", { value: method, children: method }, method))) }));
9
+ }
@@ -0,0 +1,25 @@
1
+ import type { JSX, ReactNode } from 'react';
2
+ interface Props {
3
+ /**
4
+ * Action buttons rendered in a right-aligned row.
5
+ */
6
+ children: ReactNode;
7
+ /**
8
+ * When true, adds top margin before the action row (common in modal bodies).
9
+ */
10
+ spaced?: boolean;
11
+ /**
12
+ * Additional Tailwind classes merged onto the footer row.
13
+ */
14
+ className?: string;
15
+ }
16
+ /**
17
+ * Right-aligned action button row for modal bodies and overlay footers.
18
+ *
19
+ * @param children - Cancel, confirm, and other action controls.
20
+ * @param spaced - Whether to add `mt-4` above the button row.
21
+ * @param className - Extra classes appended after the layout preset.
22
+ */
23
+ export declare function ModalFooter({ children, spaced, className }: Props): JSX.Element;
24
+ export {};
25
+ //# sourceMappingURL=ModalFooter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ModalFooter.d.ts","sourceRoot":"","sources":["../../../src/components/Modal/ModalFooter.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5C,UAAU,KAAK;IACb;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,MAAc,EAAE,SAAS,EAAE,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAKvF"}
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx } from "@harborclient/sdk/jsx-runtime";
2
+ /**
3
+ * Right-aligned action button row for modal bodies and overlay footers.
4
+ *
5
+ * @param children - Cancel, confirm, and other action controls.
6
+ * @param spaced - Whether to add `mt-4` above the button row.
7
+ * @param className - Extra classes appended after the layout preset.
8
+ */
9
+ export function ModalFooter({ children, spaced = false, className }) {
10
+ const base = spaced ? 'mt-4 flex justify-end gap-2' : 'flex justify-end gap-2';
11
+ const classes = className ? `${base} ${className}` : base;
12
+ return _jsx("div", { className: classes, children: children });
13
+ }
@@ -0,0 +1,31 @@
1
+ import type { JSX, ReactNode } from 'react';
2
+ interface Props {
3
+ /**
4
+ * Primary modal body content such as form fields or descriptive text.
5
+ */
6
+ children: ReactNode;
7
+ /**
8
+ * Optional error message rendered above the action row.
9
+ */
10
+ error?: ReactNode;
11
+ /**
12
+ * Action buttons; wrapped in {@link ModalFooter} when provided.
13
+ */
14
+ actions?: ReactNode;
15
+ /**
16
+ * When true, adds top margin on the action footer row.
17
+ */
18
+ actionsSpaced?: boolean;
19
+ }
20
+ /**
21
+ * Stacks modal body content, an optional error block, and a trailing action footer
22
+ * using the shared spacing conventions used across Team Hub and settings dialogs.
23
+ *
24
+ * @param children - Main modal content.
25
+ * @param error - Optional inline error rendered before actions.
26
+ * @param actions - Footer buttons wrapped by {@link ModalFooter}.
27
+ * @param actionsSpaced - Whether the footer row receives `mt-4`.
28
+ */
29
+ export declare function ModalFormLayout({ children, error, actions, actionsSpaced }: Props): JSX.Element;
30
+ export {};
31
+ //# sourceMappingURL=ModalFormLayout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ModalFormLayout.d.ts","sourceRoot":"","sources":["../../../src/components/Modal/ModalFormLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAG5C,UAAU,KAAK;IACb;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,KAAK,EACL,OAAO,EACP,aAAoB,EACrB,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAQrB"}
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
+ import { ModalFooter } from './ModalFooter.js';
3
+ /**
4
+ * Stacks modal body content, an optional error block, and a trailing action footer
5
+ * using the shared spacing conventions used across Team Hub and settings dialogs.
6
+ *
7
+ * @param children - Main modal content.
8
+ * @param error - Optional inline error rendered before actions.
9
+ * @param actions - Footer buttons wrapped by {@link ModalFooter}.
10
+ * @param actionsSpaced - Whether the footer row receives `mt-4`.
11
+ */
12
+ export function ModalFormLayout({ children, error, actions, actionsSpaced = true }) {
13
+ return (_jsxs(_Fragment, { children: [children, error, actions ? _jsx(ModalFooter, { spaced: actionsSpaced, children: actions }) : null] }));
14
+ }
@@ -0,0 +1,34 @@
1
+ import type { JSX, ReactNode } from 'react';
2
+ interface Props {
3
+ /**
4
+ * Id referenced by the dialog's `aria-labelledby`.
5
+ */
6
+ titleId: string;
7
+ /**
8
+ * Dialog heading rendered in the header row.
9
+ */
10
+ title: ReactNode;
11
+ /**
12
+ * Optional muted summary shown below the title.
13
+ */
14
+ description?: ReactNode;
15
+ /**
16
+ * Extra action controls rendered before the Close button.
17
+ */
18
+ headerActions?: ReactNode;
19
+ /**
20
+ * When true, the header Close button is disabled.
21
+ */
22
+ closeDisabled?: boolean;
23
+ /**
24
+ * Closes the dialog from the header Close button.
25
+ */
26
+ onClose: () => void;
27
+ }
28
+ /**
29
+ * Modal header row with a bordered bottom edge, title block on the left,
30
+ * optional actions, and a close icon on the right.
31
+ */
32
+ export declare function ModalHeader({ titleId, title, description, headerActions, closeDisabled, onClose }: Props): JSX.Element;
33
+ export {};
34
+ //# sourceMappingURL=ModalHeader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ModalHeader.d.ts","sourceRoot":"","sources":["../../../src/components/Modal/ModalHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAK5C,UAAU,KAAK;IACb;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IAExB;;OAEG;IACH,aAAa,CAAC,EAAE,SAAS,CAAC;IAE1B;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,KAAK,EACL,WAAW,EACX,aAAa,EACb,aAAqB,EACrB,OAAO,EACR,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CA2BrB"}
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
+ import { faXmark } from '@fortawesome/free-solid-svg-icons';
3
+ import { Button } from '../Button/index.js';
4
+ import { FaIcon } from '../FaIcon/index.js';
5
+ /**
6
+ * Modal header row with a bordered bottom edge, title block on the left,
7
+ * optional actions, and a close icon on the right.
8
+ */
9
+ export function ModalHeader({ titleId, title, description, headerActions, closeDisabled = false, onClose }) {
10
+ return (_jsxs("div", { className: "flex flex-wrap items-center gap-2 border-b border-separator px-4 py-4", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("h2", { id: titleId, className: "m-0 flex flex-wrap items-center gap-2 text-[17px] font-semibold text-text", children: title }), description ? _jsx("p", { className: "m-0 mt-1 text-[14px] text-muted", children: description }) : null] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [headerActions, _jsx(Button, { type: "button", variant: "icon", className: "shrink-0 opacity-100", "aria-label": "Close", disabled: closeDisabled, onClick: onClose, children: _jsx(FaIcon, { icon: faXmark, className: "h-4 w-4" }) })] })] }));
11
+ }