@harborclient/sdk 0.6.2 → 0.6.4

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 (69) hide show
  1. package/dist/components/BusyIndicator/index.d.ts +3 -2
  2. package/dist/components/BusyIndicator/index.d.ts.map +1 -1
  3. package/dist/components/BusyIndicator/index.js +11 -3
  4. package/dist/components/Button/index.d.ts +23 -8
  5. package/dist/components/Button/index.d.ts.map +1 -1
  6. package/dist/components/Button/index.js +11 -9
  7. package/dist/components/CodeEditor/index.d.ts +9 -1
  8. package/dist/components/CodeEditor/index.d.ts.map +1 -1
  9. package/dist/components/CodeEditor/index.js +186 -62
  10. package/dist/components/FieldError/index.d.ts.map +1 -1
  11. package/dist/components/FieldError/index.js +1 -1
  12. package/dist/components/FooterButton/index.js +2 -2
  13. package/dist/components/FormDataEditor/index.d.ts.map +1 -1
  14. package/dist/components/FormDataEditor/index.js +2 -2
  15. package/dist/components/FormGroup/index.d.ts +6 -1
  16. package/dist/components/FormGroup/index.d.ts.map +1 -1
  17. package/dist/components/FormGroup/index.js +25 -31
  18. package/dist/components/KeyValueEditor/index.d.ts.map +1 -1
  19. package/dist/components/KeyValueEditor/index.js +3 -3
  20. package/dist/components/Modal/ModalFormLayout.d.ts.map +1 -1
  21. package/dist/components/Modal/ModalFormLayout.js +2 -1
  22. package/dist/components/Modal/ModalHeader.d.ts +5 -1
  23. package/dist/components/Modal/ModalHeader.d.ts.map +1 -1
  24. package/dist/components/Modal/ModalHeader.js +2 -2
  25. package/dist/components/Modal/index.d.ts.map +1 -1
  26. package/dist/components/Modal/index.js +4 -2
  27. package/dist/components/OverlayCloseButton/index.d.ts.map +1 -1
  28. package/dist/components/OverlayCloseButton/index.js +1 -2
  29. package/dist/components/Resizable/Resizable.d.ts.map +1 -1
  30. package/dist/components/Resizable/Resizable.js +1 -1
  31. package/dist/components/Resizable/ResizeHandle.js +2 -2
  32. package/dist/components/ResourceList/index.d.ts +11 -1
  33. package/dist/components/ResourceList/index.d.ts.map +1 -1
  34. package/dist/components/ResourceList/index.js +4 -2
  35. package/dist/components/RowActionsMenu/index.d.ts.map +1 -1
  36. package/dist/components/RowActionsMenu/index.js +150 -11
  37. package/dist/components/SegmentedTabs/index.d.ts.map +1 -1
  38. package/dist/components/SegmentedTabs/index.js +2 -2
  39. package/dist/components/TabCloseButton/index.d.ts +1 -1
  40. package/dist/components/TabCloseButton/index.js +2 -2
  41. package/dist/components/VariableInput/index.d.ts.map +1 -1
  42. package/dist/components/VariableInput/index.js +84 -10
  43. package/dist/components/VariableTable/index.d.ts.map +1 -1
  44. package/dist/components/VariableTable/index.js +1 -1
  45. package/dist/components/classes.d.ts +1 -1
  46. package/dist/components/classes.d.ts.map +1 -1
  47. package/dist/components/classes.js +3 -3
  48. package/dist/components/enhanceControl.d.ts +28 -0
  49. package/dist/components/enhanceControl.d.ts.map +1 -0
  50. package/dist/components/enhanceControl.js +84 -0
  51. package/dist/components/enhanceControl.test.d.ts +2 -0
  52. package/dist/components/enhanceControl.test.d.ts.map +1 -0
  53. package/dist/components/enhanceControl.test.js +83 -0
  54. package/dist/components/useDialogFocus.d.ts +3 -2
  55. package/dist/components/useDialogFocus.d.ts.map +1 -1
  56. package/dist/components/useDialogFocus.js +61 -4
  57. package/dist/components/utils.d.ts +25 -0
  58. package/dist/components/utils.d.ts.map +1 -1
  59. package/dist/components/utils.js +24 -0
  60. package/dist/components/utils.test.js +18 -1
  61. package/dist/types.d.ts.map +1 -1
  62. package/dist/variables/index.d.ts +1 -1
  63. package/dist/variables/index.d.ts.map +1 -1
  64. package/dist/variables/index.js +1 -1
  65. package/dist/variables/tokens.d.ts +31 -0
  66. package/dist/variables/tokens.d.ts.map +1 -1
  67. package/dist/variables/tokens.js +38 -1
  68. package/dist/variables/tokens.test.js +46 -1
  69. package/package.json +2 -1
@@ -9,8 +9,9 @@ export interface Props {
9
9
  * Global busy overlay: top progress bar, corner spinner, and wait cursor.
10
10
  * Delayed show avoids flashing on fast operations; min-visible avoids flicker.
11
11
  *
12
- * Requires host styles for `body.app-busy` (wait cursor) and `.busy-progress-bar`
13
- * (progress animation); HarborClient defines these in `styles.css`.
12
+ * Sets `body.app-busy` and `aria-busy="true"` while visible. Requires host styles
13
+ * for `body.app-busy` (wait cursor) and `.busy-progress-bar` (progress animation);
14
+ * HarborClient defines these in `styles.css`.
14
15
  */
15
16
  export declare function BusyIndicator({ isBusy }: Props): JSX.Element | null;
16
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/BusyIndicator/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAMjC,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CA2FnE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/BusyIndicator/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAMjC,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAiGnE"}
@@ -7,8 +7,9 @@ const MIN_VISIBLE_MS = 300;
7
7
  * Global busy overlay: top progress bar, corner spinner, and wait cursor.
8
8
  * Delayed show avoids flashing on fast operations; min-visible avoids flicker.
9
9
  *
10
- * Requires host styles for `body.app-busy` (wait cursor) and `.busy-progress-bar`
11
- * (progress animation); HarborClient defines these in `styles.css`.
10
+ * Sets `body.app-busy` and `aria-busy="true"` while visible. Requires host styles
11
+ * for `body.app-busy` (wait cursor) and `.busy-progress-bar` (progress animation);
12
+ * HarborClient defines these in `styles.css`.
12
13
  */
13
14
  export function BusyIndicator({ isBusy }) {
14
15
  const [visible, setVisible] = useState(false);
@@ -63,12 +64,19 @@ export function BusyIndicator({ isBusy }) {
63
64
  };
64
65
  }, []);
65
66
  /**
66
- * Toggles the document wait cursor while the overlay is visible.
67
+ * Toggles the document wait cursor and `aria-busy` while the overlay is visible.
67
68
  */
68
69
  useEffect(() => {
69
70
  document.body.classList.toggle('app-busy', visible);
71
+ if (visible) {
72
+ document.body.setAttribute('aria-busy', 'true');
73
+ }
74
+ else {
75
+ document.body.removeAttribute('aria-busy');
76
+ }
70
77
  return () => {
71
78
  document.body.classList.remove('app-busy');
79
+ document.body.removeAttribute('aria-busy');
72
80
  };
73
81
  }, [visible]);
74
82
  if (!visible) {
@@ -1,18 +1,31 @@
1
- import type { ButtonHTMLAttributes, JSX } from 'react';
1
+ import type { ButtonHTMLAttributes, JSX, RefObject } from 'react';
2
2
  /**
3
3
  * Visual style for a macOS-style button.
4
4
  */
5
5
  export type ButtonVariant = 'primary' | 'secondary' | 'primaryDanger' | 'secondaryDanger' | 'toolbar' | 'icon' | 'iconDanger';
6
- interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
7
- /**
8
- * Visual style preset. Defaults to primary accent fill.
9
- */
10
- variant?: ButtonVariant;
6
+ type IconButtonVariant = 'icon' | 'iconDanger';
7
+ type AccessibleName = {
8
+ 'aria-label': string;
9
+ 'aria-labelledby'?: undefined;
10
+ } | {
11
+ 'aria-labelledby': string;
12
+ 'aria-label'?: undefined;
13
+ };
14
+ type BaseProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'aria-label' | 'aria-labelledby'> & {
11
15
  /**
12
16
  * Additional Tailwind classes merged after the variant preset.
13
17
  */
14
18
  className?: string;
15
- }
19
+ /**
20
+ * Ref forwarded to the underlying native button element.
21
+ */
22
+ innerRef?: RefObject<HTMLButtonElement | null>;
23
+ };
24
+ export type ButtonProps = (BaseProps & {
25
+ variant: IconButtonVariant;
26
+ } & AccessibleName) | (BaseProps & {
27
+ variant?: Exclude<ButtonVariant, IconButtonVariant>;
28
+ });
16
29
  /**
17
30
  * macOS-style button with shared variant presets for primary actions, secondary
18
31
  * actions, toolbar controls, and icon-only controls.
@@ -20,10 +33,12 @@ interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
20
33
  * Defaults to `type="button"` so clicks do not accidentally submit a parent form.
21
34
  * Pass `type="submit"` explicitly when submit behavior is intended.
22
35
  *
36
+ * Icon variants (`icon`, `iconDanger`) require `aria-label` or `aria-labelledby`.
37
+ *
23
38
  * @param variant - Visual preset; defaults to `primary`.
24
39
  * @param className - Extra classes appended after the variant classes.
25
40
  * @param type - Native button type; defaults to `button`.
26
41
  */
27
- export declare function Button({ variant, className, type, ...props }: Props): JSX.Element;
42
+ export declare function Button({ variant, className, type, innerRef, ...props }: ButtonProps): JSX.Element;
28
43
  export {};
29
44
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Button/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAEvD;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,WAAW,GACX,eAAe,GACf,iBAAiB,GACjB,SAAS,GACT,MAAM,GACN,YAAY,CAAC;AAkBjB,UAAU,KAAM,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IAC7D;;OAEG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,EACrB,OAAmB,EACnB,SAAS,EACT,IAAe,EACf,GAAG,KAAK,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAGrB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Button/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,WAAW,GACX,eAAe,GACf,iBAAiB,GACjB,SAAS,GACT,MAAM,GACN,YAAY,CAAC;AAEjB,KAAK,iBAAiB,GAAG,MAAM,GAAG,YAAY,CAAC;AAE/C,KAAK,cAAc,GACf;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,SAAS,CAAA;CAAE,GACvD;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AAE5D,KAAK,SAAS,GAAG,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,YAAY,GAAG,iBAAiB,CAAC,GAAG;IACjG;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB,CAAC,SAAS,GAAG;IAAE,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAAG,cAAc,CAAC,GAC7D,CAAC,SAAS,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAA;CAAE,CAAC,CAAC;AAkB1E;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,EACrB,OAAmB,EACnB,SAAS,EACT,IAAe,EACf,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,WAAW,GAAG,GAAG,CAAC,OAAO,CAG3B"}
@@ -1,12 +1,12 @@
1
1
  import { jsx as _jsx } from "@harborclient/sdk/jsx-runtime";
2
2
  const VARIANT_CLASSES = {
3
- primary: 'cursor-pointer rounded-md border border-transparent bg-accent px-3 py-1 text-[15px] font-medium text-white shadow-sm hover:brightness-110 disabled:cursor-not-allowed disabled:opacity-50 app-no-drag',
4
- secondary: 'cursor-pointer rounded-md border border-separator bg-control px-3 py-1 text-[15px] text-text shadow-sm hover:bg-selection disabled:cursor-not-allowed disabled:opacity-50 app-no-drag',
5
- primaryDanger: 'cursor-pointer rounded-md border border-transparent bg-danger px-3 py-1 text-[15px] font-medium text-white shadow-sm hover:brightness-110 disabled:cursor-not-allowed disabled:opacity-50 app-no-drag',
6
- secondaryDanger: 'cursor-pointer rounded-md border border-separator bg-control px-3 py-1 text-[15px] text-danger shadow-sm hover:bg-danger/15 disabled:cursor-not-allowed disabled:opacity-50 app-no-drag',
7
- toolbar: 'cursor-pointer rounded-md border-none bg-transparent px-2 py-1 text-[15px] hover:bg-selection app-no-drag',
8
- icon: 'inline-flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center rounded-md border-none bg-transparent text-muted opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 focus:opacity-100 focus-visible:opacity-100 hover:bg-selection hover:text-text app-no-drag',
9
- iconDanger: 'inline-flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center rounded-md border-none bg-transparent text-muted opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 focus:opacity-100 focus-visible:opacity-100 hover:bg-danger/15 hover:text-danger app-no-drag'
3
+ primary: 'inline-flex min-h-[34px] cursor-pointer items-center justify-center rounded-md border border-transparent bg-accent px-3 py-1 text-[15px] font-medium text-white shadow-sm hover:brightness-110 disabled:cursor-not-allowed disabled:opacity-50 app-no-drag',
4
+ secondary: 'inline-flex min-h-[34px] cursor-pointer items-center justify-center rounded-md border border-separator bg-control px-3 py-1 text-[15px] text-text shadow-sm hover:bg-selection disabled:cursor-not-allowed disabled:opacity-50 app-no-drag',
5
+ primaryDanger: 'inline-flex min-h-[34px] cursor-pointer items-center justify-center rounded-md border border-transparent bg-danger px-3 py-1 text-[15px] font-medium text-white shadow-sm hover:brightness-110 disabled:cursor-not-allowed disabled:opacity-50 app-no-drag',
6
+ secondaryDanger: 'inline-flex min-h-[34px] cursor-pointer items-center justify-center rounded-md border border-separator bg-control px-3 py-1 text-[15px] text-danger shadow-sm hover:bg-danger/15 disabled:cursor-not-allowed disabled:opacity-50 app-no-drag',
7
+ toolbar: 'inline-flex min-h-[34px] cursor-pointer items-center rounded-md border-none bg-transparent px-2 py-1 text-[15px] hover:bg-selection app-no-drag',
8
+ icon: 'inline-flex size-[30px] 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',
9
+ iconDanger: 'inline-flex size-[30px] shrink-0 cursor-pointer items-center justify-center rounded-md border-none bg-transparent text-muted hover:bg-danger/15 hover:text-danger app-no-drag'
10
10
  };
11
11
  /**
12
12
  * macOS-style button with shared variant presets for primary actions, secondary
@@ -15,11 +15,13 @@ const VARIANT_CLASSES = {
15
15
  * Defaults to `type="button"` so clicks do not accidentally submit a parent form.
16
16
  * Pass `type="submit"` explicitly when submit behavior is intended.
17
17
  *
18
+ * Icon variants (`icon`, `iconDanger`) require `aria-label` or `aria-labelledby`.
19
+ *
18
20
  * @param variant - Visual preset; defaults to `primary`.
19
21
  * @param className - Extra classes appended after the variant classes.
20
22
  * @param type - Native button type; defaults to `button`.
21
23
  */
22
- export function Button({ variant = 'primary', className, type = 'button', ...props }) {
24
+ export function Button({ variant = 'primary', className, type = 'button', innerRef, ...props }) {
23
25
  const classes = className ? `${VARIANT_CLASSES[variant]} ${className}` : VARIANT_CLASSES[variant];
24
- return _jsx("button", { type: type, className: classes, ...props });
26
+ return _jsx("button", { ref: innerRef, type: type, className: classes, ...props });
25
27
  }
@@ -66,6 +66,14 @@ export interface Props {
66
66
  * Id of the element that labels this editor when using `aria-labelledby`.
67
67
  */
68
68
  'aria-labelledby'?: string;
69
+ /**
70
+ * When true, marks the editor as failing validation for assistive technologies.
71
+ */
72
+ 'aria-invalid'?: boolean | 'true' | 'false';
73
+ /**
74
+ * Ids of elements describing the editor, merged with variable tooltip ids when active.
75
+ */
76
+ 'aria-describedby'?: string;
69
77
  }
70
78
  /**
71
79
  * CodeMirror wrapper for editable request bodies and read-only response views.
@@ -73,5 +81,5 @@ export interface Props {
73
81
  * Styling relies on host CSS variables (`--mac-*`, `--font-mono`) and the `.app-no-drag`
74
82
  * class defined in HarborClient `styles.css`.
75
83
  */
76
- export declare function CodeEditor({ value, onChange, language, readOnly, placeholder, minHeight, className, variables, onEditVariable, completionSource, themeOverride, setupOverride, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy }: Props): JSX.Element;
84
+ export declare function CodeEditor({ value, onChange, language, readOnly, placeholder, minHeight, className, variables, onEditVariable, completionSource, themeOverride, setupOverride, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy }: Props): JSX.Element;
77
85
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/CodeEditor/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAiBjF,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AASjF,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAExD,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,GAAG,OAAO,CAAC;AAE1E,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEnC;;OAEG;IACH,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAE9B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IAEvB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAE5B;;OAEG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAEpC;;OAEG;IACH,aAAa,CAAC,EAAE,eAAe,CAAC;IAEhC;;OAEG;IACH,aAAa,CAAC,EAAE,eAAe,CAAC;IAEhC;;OAEG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AA0MD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,QAAiB,EACjB,QAAgB,EAChB,WAAW,EACX,SAAmB,EACnB,SAAc,EACd,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,EAAE,EACF,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EAClC,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CA8HrB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/CodeEditor/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAwBjF,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAKjF,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAExD,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,GAAG,OAAO,CAAC;AAE1E,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEnC;;OAEG;IACH,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAE9B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IAEvB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAE5B;;OAEG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAEpC;;OAEG;IACH,aAAa,CAAC,EAAE,eAAe,CAAC;IAEhC;;OAEG;IACH,aAAa,CAAC,EAAE,eAAe,CAAC;IAEhC;;OAEG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IAE5C;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AA4UD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,QAAiB,EACjB,QAAgB,EAChB,WAAW,EACX,SAAmB,EACnB,SAAc,EACd,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,EAAE,EACF,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACpC,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CA2LrB"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx } from "@harborclient/sdk/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
2
  import { autocompletion } from '@codemirror/autocomplete';
3
3
  import { javascript } from '@codemirror/lang-javascript';
4
4
  import { json } from '@codemirror/lang-json';
@@ -7,8 +7,8 @@ import { shell } from '@codemirror/legacy-modes/mode/shell';
7
7
  import { Decoration, EditorView, MatchDecorator, ViewPlugin, hoverTooltip } from '@codemirror/view';
8
8
  import CodeMirrorImport from '@uiw/react-codemirror';
9
9
  import { tags } from '@lezer/highlight';
10
- import { useEffect, useMemo, useState, createElement } from '@harborclient/sdk/react';
11
- import { getDynamicVariableDescription, resolveVariable, VARIABLE_NAME_CHARS } from '../../variables/index.js';
10
+ import { useEffect, useId, useMemo, useRef, useState, createElement } from '@harborclient/sdk/react';
11
+ import { getVariableTooltipContent, VARIABLE_NAME_CHARS } from '../../variables/index.js';
12
12
  import { useCodeEditorConfig } from './config.js';
13
13
  import { getCodeEditorThemeExtension } from './themes.js';
14
14
  export { CODE_EDITOR_THEME_OPTIONS } from './themes.js';
@@ -140,6 +140,137 @@ const variableHighlighter = ViewPlugin.fromClass(class {
140
140
  this.decorations = variableMatcher.updateDeco(update, this.decorations);
141
141
  }
142
142
  }, { decorations: (v) => v.decorations });
143
+ /**
144
+ * Finds the {{variable}} token at a document position, if any.
145
+ *
146
+ * @param doc - CodeMirror document.
147
+ * @param pos - Character position in the document.
148
+ * @returns Variable key and token range, or null when not inside a token.
149
+ */
150
+ function findVariableAtPos(doc, pos) {
151
+ const line = doc.lineAt(pos);
152
+ const pattern = new RegExp(`\\{\\{\\s*([${VARIABLE_NAME_CHARS}]+)\\s*\\}\\}`, 'g');
153
+ for (const match of line.text.matchAll(pattern)) {
154
+ const start = line.from + (match.index ?? 0);
155
+ const end = start + match[0].length;
156
+ if (pos < start || pos > end)
157
+ continue;
158
+ return { key: match[1], start, end };
159
+ }
160
+ return null;
161
+ }
162
+ /**
163
+ * Builds DOM content for a variable tooltip.
164
+ *
165
+ * @param key - Variable name from the token.
166
+ * @param variables - Collection-scoped variables for resolution.
167
+ * @param onEditVariable - Optional callback to open collection settings.
168
+ */
169
+ function buildVariableTooltipDom(key, variables, onEditVariable) {
170
+ const content = getVariableTooltipContent(key, variables);
171
+ const dom = document.createElement('div');
172
+ dom.className = 'cm-variable-tooltip';
173
+ const valueEl = document.createElement('div');
174
+ valueEl.textContent = content.text;
175
+ if (content.muted) {
176
+ valueEl.className = 'cm-variable-tooltip-muted';
177
+ }
178
+ dom.appendChild(valueEl);
179
+ if (onEditVariable) {
180
+ const btn = document.createElement('button');
181
+ btn.type = 'button';
182
+ btn.textContent = 'Edit value';
183
+ btn.className = 'cm-variable-tooltip-edit';
184
+ btn.setAttribute('aria-label', `Edit value for ${key}`);
185
+ btn.addEventListener('mousedown', (e) => {
186
+ e.preventDefault();
187
+ onEditVariable();
188
+ });
189
+ dom.appendChild(btn);
190
+ }
191
+ return dom;
192
+ }
193
+ /**
194
+ * Joins non-empty element ids into a space-separated `aria-describedby` value.
195
+ *
196
+ * @param ids - Candidate element ids.
197
+ * @returns Merged id string, or undefined when no ids are provided.
198
+ */
199
+ function mergeDescribedBy(...ids) {
200
+ const merged = ids.filter((id) => id != null && id !== '');
201
+ return merged.length > 0 ? merged.join(' ') : undefined;
202
+ }
203
+ /**
204
+ * Sets or clears `aria-describedby` on the CodeMirror content element.
205
+ *
206
+ * @param content - Editable `.cm-content` element.
207
+ * @param getValidationDescribedBy - Returns validation/helper ids from props.
208
+ * @param tooltipId - Optional variable tooltip id to include while visible.
209
+ */
210
+ function setContentDescribedBy(content, getValidationDescribedBy, tooltipId) {
211
+ if (!content)
212
+ return;
213
+ const describedBy = mergeDescribedBy(getValidationDescribedBy(), tooltipId);
214
+ if (describedBy) {
215
+ content.setAttribute('aria-describedby', describedBy);
216
+ }
217
+ else {
218
+ content.removeAttribute('aria-describedby');
219
+ }
220
+ }
221
+ /**
222
+ * Shows a keyboard-driven tooltip when the caret moves inside a {{variable}} token.
223
+ *
224
+ * @param tooltipId - Stable id referenced by `aria-describedby`.
225
+ * @param onTooltipChange - Callback invoked when tooltip visibility or position changes.
226
+ * @param getValidationDescribedBy - Returns validation/helper ids from editor props.
227
+ */
228
+ function variableSelectionTooltip(tooltipId, onTooltipChange, getValidationDescribedBy) {
229
+ return EditorView.updateListener.of((update) => {
230
+ if (!update.selectionSet && !update.docChanged)
231
+ return;
232
+ const content = update.view.dom.querySelector('.cm-content');
233
+ const pos = update.state.selection.main.head;
234
+ const match = findVariableAtPos(update.state.doc, pos);
235
+ if (!match) {
236
+ onTooltipChange(null);
237
+ setContentDescribedBy(content, getValidationDescribedBy);
238
+ return;
239
+ }
240
+ const coords = update.view.coordsAtPos(match.start);
241
+ if (!coords) {
242
+ onTooltipChange(null);
243
+ setContentDescribedBy(content, getValidationDescribedBy);
244
+ return;
245
+ }
246
+ onTooltipChange({
247
+ key: match.key,
248
+ top: coords.top,
249
+ left: coords.left + (coords.right - coords.left) / 2
250
+ });
251
+ setContentDescribedBy(content, getValidationDescribedBy, tooltipId);
252
+ });
253
+ }
254
+ /**
255
+ * Dismisses the keyboard tooltip when Escape is pressed.
256
+ *
257
+ * @param isOpen - Returns whether the keyboard tooltip is currently visible.
258
+ * @param onDismiss - Called to hide the keyboard tooltip.
259
+ * @param getValidationDescribedBy - Returns validation/helper ids from editor props.
260
+ */
261
+ function variableTooltipEscapeHandler(isOpen, onDismiss, getValidationDescribedBy) {
262
+ return EditorView.domEventHandlers({
263
+ keydown(event, view) {
264
+ if (event.key === 'Escape' && isOpen()) {
265
+ event.preventDefault();
266
+ onDismiss(view);
267
+ setContentDescribedBy(view.dom.querySelector('.cm-content'), getValidationDescribedBy);
268
+ return true;
269
+ }
270
+ return false;
271
+ }
272
+ });
273
+ }
143
274
  /**
144
275
  * Builds a hover tooltip extension for {{variable}} tokens.
145
276
  *
@@ -148,51 +279,17 @@ const variableHighlighter = ViewPlugin.fromClass(class {
148
279
  */
149
280
  function variableTooltip(variables, onEditVariable) {
150
281
  return hoverTooltip((view, pos) => {
151
- const line = view.state.doc.lineAt(pos);
152
- const pattern = new RegExp(`\\{\\{\\s*([${VARIABLE_NAME_CHARS}]+)\\s*\\}\\}`, 'g');
153
- for (const match of line.text.matchAll(pattern)) {
154
- const start = line.from + (match.index ?? 0);
155
- const end = start + match[0].length;
156
- if (pos < start || pos > end)
157
- continue;
158
- const key = match[1];
159
- const value = resolveVariable(key, variables);
160
- const dynamicDescription = getDynamicVariableDescription(key);
161
- return {
162
- pos: start,
163
- end,
164
- above: true,
165
- create() {
166
- const dom = document.createElement('div');
167
- dom.className = 'cm-variable-tooltip';
168
- const valueEl = document.createElement('div');
169
- if (value !== undefined) {
170
- valueEl.textContent = value;
171
- }
172
- else if (dynamicDescription) {
173
- valueEl.textContent = `Dynamic: ${dynamicDescription}`;
174
- }
175
- else {
176
- valueEl.textContent = 'Not defined';
177
- valueEl.className = 'cm-variable-tooltip-muted';
178
- }
179
- dom.appendChild(valueEl);
180
- if (onEditVariable) {
181
- const btn = document.createElement('button');
182
- btn.type = 'button';
183
- btn.textContent = 'Edit value';
184
- btn.className = 'cm-variable-tooltip-edit';
185
- btn.addEventListener('mousedown', (e) => {
186
- e.preventDefault();
187
- onEditVariable();
188
- });
189
- dom.appendChild(btn);
190
- }
191
- return { dom };
192
- }
193
- };
194
- }
195
- return null;
282
+ const match = findVariableAtPos(view.state.doc, pos);
283
+ if (!match)
284
+ return null;
285
+ return {
286
+ pos: match.start,
287
+ end: match.end,
288
+ above: true,
289
+ create() {
290
+ return { dom: buildVariableTooltipDom(match.key, variables, onEditVariable) };
291
+ }
292
+ };
196
293
  });
197
294
  }
198
295
  /**
@@ -201,11 +298,20 @@ function variableTooltip(variables, onEditVariable) {
201
298
  * Styling relies on host CSS variables (`--mac-*`, `--font-mono`) and the `.app-no-drag`
202
299
  * class defined in HarborClient `styles.css`.
203
300
  */
204
- export function CodeEditor({ value, onChange, language = 'text', readOnly = false, placeholder, minHeight = '144px', className = '', variables, onEditVariable, completionSource, themeOverride, setupOverride, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy }) {
301
+ export function CodeEditor({ value, onChange, language = 'text', readOnly = false, placeholder, minHeight = '144px', className = '', variables, onEditVariable, completionSource, themeOverride, setupOverride, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy }) {
205
302
  const config = useCodeEditorConfig();
206
303
  const resolvedTheme = themeOverride ?? config.theme;
207
304
  const resolvedSetup = setupOverride ?? (readOnly ? null : config.setup);
208
305
  const [isDark, setIsDark] = useState(() => window.matchMedia('(prefers-color-scheme: dark)').matches);
306
+ const [selectionTooltip, setSelectionTooltip] = useState(null);
307
+ const selectionTooltipRef = useRef(selectionTooltip);
308
+ selectionTooltipRef.current = selectionTooltip;
309
+ const setSelectionTooltipRef = useRef(setSelectionTooltip);
310
+ setSelectionTooltipRef.current = setSelectionTooltip;
311
+ const ariaDescribedByRef = useRef(ariaDescribedBy);
312
+ ariaDescribedByRef.current = ariaDescribedBy;
313
+ const tooltipId = useId();
314
+ const getValidationDescribedBy = () => ariaDescribedByRef.current;
209
315
  /**
210
316
  * Tracks system dark mode so syntax highlighting matches the active theme.
211
317
  */
@@ -243,7 +349,11 @@ export function CodeEditor({ value, onChange, language = 'text', readOnly = fals
243
349
  next.push(StreamLanguage.define(shell));
244
350
  }
245
351
  if (variables) {
246
- next.push(variableHighlighter, variableTooltip(variables, onEditVariable));
352
+ next.push(variableHighlighter, variableTooltip(variables, onEditVariable), variableSelectionTooltip(tooltipId, (state) => {
353
+ setSelectionTooltipRef.current(state);
354
+ }, getValidationDescribedBy), variableTooltipEscapeHandler(() => selectionTooltipRef.current != null, () => {
355
+ setSelectionTooltipRef.current(null);
356
+ }, getValidationDescribedBy));
247
357
  }
248
358
  const contentAttrs = {};
249
359
  if (id)
@@ -252,6 +362,10 @@ export function CodeEditor({ value, onChange, language = 'text', readOnly = fals
252
362
  contentAttrs['aria-label'] = ariaLabel;
253
363
  if (ariaLabelledBy)
254
364
  contentAttrs['aria-labelledby'] = ariaLabelledBy;
365
+ if (ariaInvalid != null)
366
+ contentAttrs['aria-invalid'] = String(ariaInvalid);
367
+ if (ariaDescribedBy)
368
+ contentAttrs['aria-describedby'] = ariaDescribedBy;
255
369
  if (Object.keys(contentAttrs).length > 0) {
256
370
  next.push(EditorView.contentAttributes.of(contentAttrs));
257
371
  }
@@ -265,7 +379,10 @@ export function CodeEditor({ value, onChange, language = 'text', readOnly = fals
265
379
  completionSource,
266
380
  id,
267
381
  ariaLabel,
268
- ariaLabelledBy
382
+ ariaLabelledBy,
383
+ ariaInvalid,
384
+ ariaDescribedBy,
385
+ tooltipId
269
386
  ]);
270
387
  /**
271
388
  * Resolves CodeMirror basicSetup from persisted settings or read-only defaults.
@@ -305,15 +422,22 @@ export function CodeEditor({ value, onChange, language = 'text', readOnly = fals
305
422
  const wrapperClassName = readOnly
306
423
  ? `overflow-hidden rounded-md bg-control shadow-[inset_0_0.5px_1px_rgba(0,0,0,0.06)] app-no-drag ${className}`
307
424
  : `min-h-36 resize-y overflow-hidden rounded-md border border-separator bg-control shadow-[inset_0_0.5px_1px_rgba(0,0,0,0.06)] focus-within:shadow-[0_0_0_3px_color-mix(in_srgb,var(--mac-accent)_35%,transparent),inset_0_0.5px_1px_rgba(0,0,0,0.06)] app-no-drag ${className}`;
308
- return (_jsx("div", { className: wrapperClassName, children: createElement(CodeMirrorImport, {
309
- value,
310
- onChange: readOnly ? undefined : onChange,
311
- extensions,
312
- theme: 'none',
313
- editable: !readOnly,
314
- readOnly,
315
- placeholder,
316
- minHeight,
317
- basicSetup
318
- }) }));
425
+ const selectionTooltipContent = selectionTooltip
426
+ ? getVariableTooltipContent(selectionTooltip.key, variables ?? [])
427
+ : null;
428
+ return (_jsxs("div", { className: wrapperClassName, children: [createElement(CodeMirrorImport, {
429
+ value,
430
+ onChange: readOnly ? undefined : onChange,
431
+ extensions,
432
+ theme: 'none',
433
+ editable: !readOnly,
434
+ readOnly,
435
+ placeholder,
436
+ minHeight,
437
+ basicSetup
438
+ }), selectionTooltip && selectionTooltipContent && variables ? (_jsxs("div", { id: tooltipId, role: "tooltip", className: "pointer-events-auto fixed z-50 flex max-w-sm -translate-x-1/2 -translate-y-full flex-col gap-1.5 rounded-md border border-separator bg-surface px-3 py-2 text-[14px] text-text shadow-md app-no-drag", style: { top: selectionTooltip.top - 4, left: selectionTooltip.left }, children: [_jsx("span", { className: selectionTooltipContent.muted ? 'text-muted' : undefined, children: selectionTooltipContent.text }), onEditVariable ? (_jsx("button", { type: "button", className: "self-start text-[14px] text-accent hover:underline", "aria-label": `Edit value for ${selectionTooltip.key}`, onMouseDown: (event) => {
439
+ event.preventDefault();
440
+ onEditVariable();
441
+ setSelectionTooltip(null);
442
+ }, children: "Edit value" })) : null] })) : null] }));
319
443
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FieldError/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5C;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;AAE9D,UAAU,KAAK;IACb;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;OAEG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAE5B;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAoBD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,EAAE,EACF,OAAiB,EACjB,SAAiB,EACjB,SAAS,EACV,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAW5B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FieldError/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5C;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;AAE9D,UAAU,KAAK;IACb;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;OAEG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAE5B;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAoBD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,EAAE,EACF,OAAiB,EACjB,SAAgB,EAChB,SAAS,EACV,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAW5B"}
@@ -25,7 +25,7 @@ function spacingClasses(spacing) {
25
25
  * @param roleAlert - Whether to set `role="alert"`.
26
26
  * @param className - Extra classes appended after the preset.
27
27
  */
28
- export function FieldError({ children, id, spacing = 'field', roleAlert = false, className }) {
28
+ export function FieldError({ children, id, spacing = 'field', roleAlert = true, className }) {
29
29
  if (children == null || children === '')
30
30
  return null;
31
31
  const base = `${spacingClasses(spacing)} text-[14px] text-danger`;
@@ -6,8 +6,8 @@ import { jsx as _jsx } from "@harborclient/sdk/jsx-runtime";
6
6
  */
7
7
  function footerSegment(active) {
8
8
  return active
9
- ? 'cursor-pointer rounded-[5px] border-none bg-surface px-2 py-0.5 text-[14px] text-text shadow-sm app-no-drag'
10
- : 'cursor-pointer rounded-[5px] border-none bg-transparent px-2 py-0.5 text-[14px] text-muted hover:text-text app-no-drag';
9
+ ? 'cursor-pointer rounded-[2.5px] border-none bg-surface px-2 py-0.5 text-[14px] text-text shadow-sm app-no-drag'
10
+ : 'cursor-pointer rounded-[2.5px] border-none bg-transparent px-2 py-0.5 text-[14px] text-muted hover:text-text app-no-drag';
11
11
  }
12
12
  /**
13
13
  * Text segment toggle button for the window footer bar, used to open and close
@@ -1 +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"}
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,CAgMrB"}
@@ -98,12 +98,12 @@ export function FormDataEditor({ parts, onChange, variables, onSelectFiles, onEd
98
98
  const currentFiles = rows[index]?.files ?? [];
99
99
  updateRow(index, { files: currentFiles.filter((file) => file !== filePath) });
100
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) => {
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", { scope: "col", className: `${thClass} w-6 p-0`, children: _jsx("span", { className: "sr-only", children: "Enable" }) }), _jsx("th", { scope: "col", className: thClass, children: "Key" }), _jsx("th", { scope: "col", className: `${thClass} w-24`, children: "Type" }), _jsx("th", { scope: "col", 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", { 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
102
  const type = e.target.value;
103
103
  updateRow(index, {
104
104
  type,
105
105
  value: type === 'text' ? row.value : '',
106
106
  files: type === 'file' ? row.files : []
107
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))) })] }) }));
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, "aria-label": 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 ${fileBasename(filePath)}`, "aria-label": `Remove file ${fileBasename(filePath)}`, 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", "aria-label": `Remove row ${index + 1}`, children: _jsx(FaIcon, { icon: faXmark, className: "h-3.5 w-3.5" }) }) })] }, index))) })] }) }));
109
109
  }
@@ -32,6 +32,10 @@ interface Props {
32
32
  * Explicit id for the error element; defaults to `${htmlFor}-error` when `htmlFor` is set.
33
33
  */
34
34
  errorId?: string;
35
+ /**
36
+ * Explicit id for the description element; defaults to `${htmlFor}-description` when `htmlFor` is set.
37
+ */
38
+ descriptionId?: string;
35
39
  /**
36
40
  * Label and control placement. Defaults to stacked (label above control).
37
41
  */
@@ -64,12 +68,13 @@ interface Props {
64
68
  * @param description - Optional helper text below the control.
65
69
  * @param error - Optional validation error below the control.
66
70
  * @param errorId - Explicit error element id for `aria-describedby`.
71
+ * @param descriptionId - Explicit description element id for `aria-describedby`.
67
72
  * @param layout - Label/control placement preset.
68
73
  * @param labelTone - Label color style.
69
74
  * @param srOnly - Hide label visually for screen-reader-only labels.
70
75
  * @param className - Extra classes on the outer wrapper.
71
76
  * @param labelClassName - Extra classes on the label element.
72
77
  */
73
- export declare function FormGroup({ label, children, htmlFor, description, error, errorId, layout, labelTone, srOnly, className, labelClassName }: Props): JSX.Element;
78
+ export declare function FormGroup({ label, children, htmlFor, description, error, errorId, descriptionId, layout, labelTone, srOnly, className, labelClassName }: Props): JSX.Element;
74
79
  export {};
75
80
  //# sourceMappingURL=index.d.ts.map
@@ -1 +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"}
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;AAI5C;;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,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;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;AAqBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,QAAQ,EACR,OAAO,EACP,WAAW,EACX,KAAK,EACL,OAAO,EACP,aAAa,EACb,MAAkB,EAClB,SAAqB,EACrB,MAAc,EACd,SAAS,EACT,cAAc,EACf,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAsGrB"}