@neo4j-ndl/react 4.22.0 → 4.23.3

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 (197) hide show
  1. package/lib/cjs/_common/form-control/FormFieldLabel.js +52 -0
  2. package/lib/cjs/_common/form-control/FormFieldLabel.js.map +1 -0
  3. package/lib/cjs/_common/form-control/FormFieldMessage.js +72 -0
  4. package/lib/cjs/_common/form-control/FormFieldMessage.js.map +1 -0
  5. package/lib/cjs/_common/form-control/form-control-types.js +23 -0
  6. package/lib/cjs/_common/form-control/form-control-types.js.map +1 -0
  7. package/lib/cjs/_common/form-control/index.js +39 -0
  8. package/lib/cjs/_common/form-control/index.js.map +1 -0
  9. package/lib/cjs/_common/form-control/use-form-field.js +76 -0
  10. package/lib/cjs/_common/form-control/use-form-field.js.map +1 -0
  11. package/lib/cjs/_common/form-control/use-inline-field-label.js +76 -0
  12. package/lib/cjs/_common/form-control/use-inline-field-label.js.map +1 -0
  13. package/lib/cjs/checkbox/Checkbox.js +9 -21
  14. package/lib/cjs/checkbox/Checkbox.js.map +1 -1
  15. package/lib/cjs/combobox/Combobox.js +75 -53
  16. package/lib/cjs/combobox/Combobox.js.map +1 -1
  17. package/lib/cjs/combobox/combobox-types.js.map +1 -1
  18. package/lib/cjs/date-picker/DatePicker.js.map +1 -1
  19. package/lib/cjs/icons/generated/custom/FloppyDiskArrowTopRight.js +30 -0
  20. package/lib/cjs/icons/generated/custom/FloppyDiskArrowTopRight.js.map +1 -0
  21. package/lib/cjs/icons/generated/custom/OpenQueryTab.js +1 -0
  22. package/lib/cjs/icons/generated/custom/OpenQueryTab.js.map +1 -1
  23. package/lib/cjs/icons/generated/custom/index.js +5 -3
  24. package/lib/cjs/icons/generated/custom/index.js.map +1 -1
  25. package/lib/cjs/next/tree-view/TreeView.js +16 -1
  26. package/lib/cjs/next/tree-view/TreeView.js.map +1 -1
  27. package/lib/cjs/radio/Radio.js +12 -22
  28. package/lib/cjs/radio/Radio.js.map +1 -1
  29. package/lib/cjs/select/Select.js +14 -5
  30. package/lib/cjs/select/Select.js.map +1 -1
  31. package/lib/cjs/select/types.js.map +1 -1
  32. package/lib/cjs/switch/Switch.js +9 -21
  33. package/lib/cjs/switch/Switch.js.map +1 -1
  34. package/lib/cjs/text-area/TextArea.js +8 -21
  35. package/lib/cjs/text-area/TextArea.js.map +1 -1
  36. package/lib/cjs/text-input/TextInput.js +15 -38
  37. package/lib/cjs/text-input/TextInput.js.map +1 -1
  38. package/lib/cjs/text-input/stories/text-input-sizes.story.js +1 -1
  39. package/lib/cjs/text-input/stories/text-input-sizes.story.js.map +1 -1
  40. package/lib/cjs/time-picker/TimePicker.js +13 -7
  41. package/lib/cjs/time-picker/TimePicker.js.map +1 -1
  42. package/lib/cjs/timezone-picker/TimeZonePicker.js +13 -7
  43. package/lib/cjs/timezone-picker/TimeZonePicker.js.map +1 -1
  44. package/lib/esm/_common/form-control/FormFieldLabel.js +45 -0
  45. package/lib/esm/_common/form-control/FormFieldLabel.js.map +1 -0
  46. package/lib/esm/_common/form-control/FormFieldMessage.js +65 -0
  47. package/lib/esm/_common/form-control/FormFieldMessage.js.map +1 -0
  48. package/lib/esm/_common/form-control/form-control-types.js +22 -0
  49. package/lib/esm/_common/form-control/form-control-types.js.map +1 -0
  50. package/lib/esm/_common/form-control/index.js +32 -0
  51. package/lib/esm/_common/form-control/index.js.map +1 -0
  52. package/lib/esm/_common/form-control/use-form-field.js +72 -0
  53. package/lib/esm/_common/form-control/use-form-field.js.map +1 -0
  54. package/lib/esm/_common/form-control/use-inline-field-label.js +69 -0
  55. package/lib/esm/_common/form-control/use-inline-field-label.js.map +1 -0
  56. package/lib/esm/checkbox/Checkbox.js +10 -22
  57. package/lib/esm/checkbox/Checkbox.js.map +1 -1
  58. package/lib/esm/combobox/Combobox.js +76 -54
  59. package/lib/esm/combobox/Combobox.js.map +1 -1
  60. package/lib/esm/combobox/combobox-types.js.map +1 -1
  61. package/lib/esm/date-picker/DatePicker.js.map +1 -1
  62. package/lib/esm/icons/generated/custom/FloppyDiskArrowTopRight.js +28 -0
  63. package/lib/esm/icons/generated/custom/FloppyDiskArrowTopRight.js.map +1 -0
  64. package/lib/esm/icons/generated/custom/OpenQueryTab.js +1 -0
  65. package/lib/esm/icons/generated/custom/OpenQueryTab.js.map +1 -1
  66. package/lib/esm/icons/generated/custom/index.js +1 -0
  67. package/lib/esm/icons/generated/custom/index.js.map +1 -1
  68. package/lib/esm/next/tree-view/TreeView.js +16 -1
  69. package/lib/esm/next/tree-view/TreeView.js.map +1 -1
  70. package/lib/esm/radio/Radio.js +12 -22
  71. package/lib/esm/radio/Radio.js.map +1 -1
  72. package/lib/esm/select/Select.js +14 -5
  73. package/lib/esm/select/Select.js.map +1 -1
  74. package/lib/esm/select/types.js.map +1 -1
  75. package/lib/esm/switch/Switch.js +10 -22
  76. package/lib/esm/switch/Switch.js.map +1 -1
  77. package/lib/esm/text-area/TextArea.js +9 -22
  78. package/lib/esm/text-area/TextArea.js.map +1 -1
  79. package/lib/esm/text-input/TextInput.js +15 -38
  80. package/lib/esm/text-input/TextInput.js.map +1 -1
  81. package/lib/esm/text-input/stories/text-input-sizes.story.js +1 -1
  82. package/lib/esm/text-input/stories/text-input-sizes.story.js.map +1 -1
  83. package/lib/esm/time-picker/TimePicker.js +13 -7
  84. package/lib/esm/time-picker/TimePicker.js.map +1 -1
  85. package/lib/esm/timezone-picker/TimeZonePicker.js +13 -7
  86. package/lib/esm/timezone-picker/TimeZonePicker.js.map +1 -1
  87. package/lib/types/_common/form-control/FormFieldLabel.d.ts +58 -0
  88. package/lib/types/_common/form-control/FormFieldLabel.d.ts.map +1 -0
  89. package/lib/types/_common/form-control/FormFieldMessage.d.ts +46 -0
  90. package/lib/types/_common/form-control/FormFieldMessage.d.ts.map +1 -0
  91. package/lib/types/_common/form-control/form-control-types.d.ts +92 -0
  92. package/lib/types/_common/form-control/form-control-types.d.ts.map +1 -0
  93. package/lib/types/_common/form-control/index.d.ts +33 -0
  94. package/lib/types/_common/form-control/index.d.ts.map +1 -0
  95. package/lib/types/_common/form-control/use-form-field.d.ts +53 -0
  96. package/lib/types/_common/form-control/use-form-field.d.ts.map +1 -0
  97. package/lib/types/_common/form-control/use-inline-field-label.d.ts +69 -0
  98. package/lib/types/_common/form-control/use-inline-field-label.d.ts.map +1 -0
  99. package/lib/types/checkbox/Checkbox.d.ts.map +1 -1
  100. package/lib/types/combobox/Combobox.d.ts.map +1 -1
  101. package/lib/types/combobox/combobox-types.d.ts +6 -5
  102. package/lib/types/combobox/combobox-types.d.ts.map +1 -1
  103. package/lib/types/icons/generated/custom/FloppyDiskArrowTopRight.d.ts +29 -0
  104. package/lib/types/icons/generated/custom/FloppyDiskArrowTopRight.d.ts.map +1 -0
  105. package/lib/types/icons/generated/custom/OpenQueryTab.d.ts +1 -0
  106. package/lib/types/icons/generated/custom/OpenQueryTab.d.ts.map +1 -1
  107. package/lib/types/icons/generated/custom/index.d.ts +1 -0
  108. package/lib/types/icons/generated/custom/index.d.ts.map +1 -1
  109. package/lib/types/next/tree-view/TreeView.d.ts.map +1 -1
  110. package/lib/types/radio/Radio.d.ts.map +1 -1
  111. package/lib/types/select/Select.d.ts.map +1 -1
  112. package/lib/types/select/types.d.ts.map +1 -1
  113. package/lib/types/switch/Switch.d.ts.map +1 -1
  114. package/lib/types/text-area/TextArea.d.ts.map +1 -1
  115. package/lib/types/text-input/TextInput.d.ts.map +1 -1
  116. package/lib/types/text-input/stories/text-input-sizes.story.d.ts.map +1 -1
  117. package/lib/types/time-picker/TimePicker.d.ts +3 -1
  118. package/lib/types/time-picker/TimePicker.d.ts.map +1 -1
  119. package/lib/types/timezone-picker/TimeZonePicker.d.ts +4 -1
  120. package/lib/types/timezone-picker/TimeZonePicker.d.ts.map +1 -1
  121. package/package.json +3 -3
  122. package/skills/ndl-react/SKILL.md +7 -2
  123. package/skills/ndl-react/components/accordion.md +2 -0
  124. package/skills/ndl-react/components/ai/code-preview.md +4 -0
  125. package/skills/ndl-react/components/ai/file-tag.md +2 -0
  126. package/skills/ndl-react/components/ai/image-tag.md +2 -0
  127. package/skills/ndl-react/components/ai/more-files.md +2 -0
  128. package/skills/ndl-react/components/ai/presence.md +2 -0
  129. package/skills/ndl-react/components/ai/preview.md +2 -0
  130. package/skills/ndl-react/components/ai/prompt.md +2 -0
  131. package/skills/ndl-react/components/ai/reasoning.md +2 -0
  132. package/skills/ndl-react/components/ai/response.md +2 -0
  133. package/skills/ndl-react/components/ai/suggestion.md +2 -0
  134. package/skills/ndl-react/components/ai/thinking.md +2 -0
  135. package/skills/ndl-react/components/ai/tool-call.md +2 -0
  136. package/skills/ndl-react/components/ai/user-bubble.md +2 -0
  137. package/skills/ndl-react/components/avatar.md +2 -0
  138. package/skills/ndl-react/components/banner.md +2 -0
  139. package/skills/ndl-react/components/box.md +2 -0
  140. package/skills/ndl-react/components/breadcrumbs.md +2 -0
  141. package/skills/ndl-react/components/checkbox.md +2 -0
  142. package/skills/ndl-react/components/clean-icon-button.md +2 -0
  143. package/skills/ndl-react/components/clipboard-button.md +2 -0
  144. package/skills/ndl-react/components/code-block.md +2 -0
  145. package/skills/ndl-react/components/code.md +2 -0
  146. package/skills/ndl-react/components/color-picker.md +34 -32
  147. package/skills/ndl-react/components/combobox.md +5 -3
  148. package/skills/ndl-react/components/conditional-wrap.md +2 -0
  149. package/skills/ndl-react/components/data-grid.md +2 -0
  150. package/skills/ndl-react/components/date-picker.md +2 -0
  151. package/skills/ndl-react/components/dialog.md +2 -0
  152. package/skills/ndl-react/components/dismissible-tag.md +2 -0
  153. package/skills/ndl-react/components/divider.md +2 -0
  154. package/skills/ndl-react/components/drawer.md +2 -0
  155. package/skills/ndl-react/components/dropdown-button.md +2 -0
  156. package/skills/ndl-react/components/dropzone.md +7 -5
  157. package/skills/ndl-react/components/filled-button.md +2 -0
  158. package/skills/ndl-react/components/flex.md +2 -0
  159. package/skills/ndl-react/components/graph-label.md +2 -0
  160. package/skills/ndl-react/components/icon-button-array.md +2 -0
  161. package/skills/ndl-react/components/icon-button.md +2 -0
  162. package/skills/ndl-react/components/inline-edit.md +2 -0
  163. package/skills/ndl-react/components/kbd.md +2 -0
  164. package/skills/ndl-react/components/loading-bar.md +2 -0
  165. package/skills/ndl-react/components/loading-spinner.md +2 -0
  166. package/skills/ndl-react/components/logo.md +2 -0
  167. package/skills/ndl-react/components/menu.md +2 -0
  168. package/skills/ndl-react/components/modal.md +2 -0
  169. package/skills/ndl-react/components/next/tree-view.md +90 -2
  170. package/skills/ndl-react/components/outlined-button.md +2 -0
  171. package/skills/ndl-react/components/popover.md +2 -0
  172. package/skills/ndl-react/components/progress-bar.md +2 -0
  173. package/skills/ndl-react/components/radio.md +2 -0
  174. package/skills/ndl-react/components/read-only-tag.md +2 -0
  175. package/skills/ndl-react/components/segmented-control.md +2 -0
  176. package/skills/ndl-react/components/select-icon-button.md +2 -0
  177. package/skills/ndl-react/components/select.md +4 -0
  178. package/skills/ndl-react/components/selectable-tag.md +2 -0
  179. package/skills/ndl-react/components/side-navigation.md +2 -0
  180. package/skills/ndl-react/components/skeleton.md +2 -0
  181. package/skills/ndl-react/components/slider.md +2 -0
  182. package/skills/ndl-react/components/spotlight.md +2 -0
  183. package/skills/ndl-react/components/status-indicator.md +2 -0
  184. package/skills/ndl-react/components/status-label.md +2 -0
  185. package/skills/ndl-react/components/switch.md +2 -0
  186. package/skills/ndl-react/components/tabs.md +2 -0
  187. package/skills/ndl-react/components/tag.md +4 -0
  188. package/skills/ndl-react/components/text-area.md +2 -0
  189. package/skills/ndl-react/components/text-button.md +2 -0
  190. package/skills/ndl-react/components/text-input.md +8 -0
  191. package/skills/ndl-react/components/text-link.md +2 -0
  192. package/skills/ndl-react/components/time-picker.md +3 -0
  193. package/skills/ndl-react/components/timezone-picker.md +3 -0
  194. package/skills/ndl-react/components/tooltip.md +2 -0
  195. package/skills/ndl-react/components/tree-view.md +2 -0
  196. package/skills/ndl-react/components/typography.md +2 -0
  197. package/skills/ndl-react/components/wizard.md +2 -0
@@ -40,6 +40,7 @@ const react_1 = require("@floating-ui/react");
40
40
  const react_virtual_1 = require("@tanstack/react-virtual");
41
41
  const classnames_1 = __importDefault(require("classnames"));
42
42
  const react_2 = require("react");
43
+ const form_control_1 = require("../_common/form-control");
43
44
  const use_semi_controlled_state_1 = require("../_common/use-semi-controlled-state");
44
45
  const utils_1 = require("../_common/utils");
45
46
  const checkbox_1 = require("../checkbox");
@@ -108,9 +109,6 @@ const Combobox = ({ label, name, formId, autoComplete, triggerRef, hasVisuallyHi
108
109
  const listboxId = `${baseId}-listbox`;
109
110
  const panelId = `${baseId}-panel`;
110
111
  const triggerId = `${baseId}-trigger`;
111
- const labelId = `${baseId}-label`;
112
- const helpTextId = `${baseId}-help-text`;
113
- const errorTextId = `${baseId}-error-text`;
114
112
  const initialValue = (0, combobox_utils_1.getInitialValue)(value, defaultValue, isMulti);
115
113
  const [selectedValue, setSelectedValue, resetSelectedValue] = (0, use_semi_controlled_state_1.useSemicontrolledState)({
116
114
  isControlled: value !== undefined,
@@ -144,7 +142,6 @@ const Combobox = ({ label, name, formId, autoComplete, triggerRef, hasVisuallyHi
144
142
  isPortaled,
145
143
  onOpenChange: setIsPanelOpen,
146
144
  });
147
- const hasCustomTrigger = renderTrigger !== undefined;
148
145
  const builtInTriggerRef = (0, react_1.useMergeRefs)([internalTriggerRef, triggerRef]);
149
146
  const customTriggerRef = (0, react_1.useMergeRefs)([
150
147
  refs.setReference,
@@ -468,13 +465,22 @@ const Combobox = ({ label, name, formId, autoComplete, triggerRef, hasVisuallyHi
468
465
  ? actionRows.map((row) => getOptionId(row)).join(' ')
469
466
  : undefined;
470
467
  const isDialogPanel = isSearchable;
471
- // An error replaces the help text, so only one message is ever rendered and
472
- // only that one is described.
473
- const displayedErrorText = errorText !== null && errorText !== void 0 ? errorText : nativeValidationMessage;
474
- const hasError = Boolean(displayedErrorText);
475
- const hasHelpText = Boolean(helpText) && !hasError;
476
- const messageId = hasError ? errorTextId : helpTextId;
477
- const describedById = hasError || hasHelpText ? messageId : undefined;
468
+ // The shared form field resolves the ids and which message is displayed -
469
+ // an error always replaces the help text. A native validation failure
470
+ // reported by the hidden form control acts as the error while no errorText
471
+ // is set.
472
+ const { field: formField, controlProps: fieldControlProps } = (0, form_control_1.useFormField)({
473
+ baseId,
474
+ controlId: triggerId,
475
+ errorText: errorText !== null && errorText !== void 0 ? errorText : nativeValidationMessage,
476
+ hasRequiredIndicator,
477
+ hasVisuallyHiddenLabel,
478
+ helpText,
479
+ isRequired,
480
+ label,
481
+ });
482
+ const hasError = formField.hasError;
483
+ const labelId = formField.labelId;
478
484
  const triggerAria = {
479
485
  'aria-activedescendant': isPanelOpen && !isSearchable ? activeOptionId : undefined,
480
486
  'aria-controls': getTriggerControlsId({
@@ -484,11 +490,11 @@ const Combobox = ({ label, name, formId, autoComplete, triggerRef, hasVisuallyHi
484
490
  listboxId,
485
491
  panelId,
486
492
  }),
487
- 'aria-describedby': describedById,
493
+ 'aria-describedby': fieldControlProps['aria-describedby'],
488
494
  'aria-disabled': isDisabled ? true : undefined,
489
495
  'aria-expanded': isPanelOpen,
490
496
  'aria-haspopup': isDialogPanel ? 'dialog' : 'listbox',
491
- 'aria-invalid': hasError ? true : undefined,
497
+ 'aria-invalid': fieldControlProps['aria-invalid'],
492
498
  'aria-required': isRequired ? true : undefined,
493
499
  // The label points at the trigger through `htmlFor`, so clicking it moves
494
500
  // focus to the trigger.
@@ -508,13 +514,13 @@ const Combobox = ({ label, name, formId, autoComplete, triggerRef, hasVisuallyHi
508
514
  // is referenced, keeping "Optional" out of the accessible name.
509
515
  'aria-labelledby': labelId, ref: builtInTriggerRef });
510
516
  const field = {
511
- errorText: displayedErrorText,
512
- errorTextId,
517
+ errorText: formField.errorText,
518
+ errorTextId: formField.errorTextId,
513
519
  hasError,
514
520
  hasRequiredIndicator,
515
521
  hasVisuallyHiddenLabel,
516
522
  helpText,
517
- helpTextId,
523
+ helpTextId: formField.helpTextId,
518
524
  isRequired,
519
525
  label,
520
526
  labelId,
@@ -569,20 +575,27 @@ const Combobox = ({ label, name, formId, autoComplete, triggerRef, hasVisuallyHi
569
575
  id: listboxId,
570
576
  role: 'listbox',
571
577
  }), { className: "ndl-combobox-actions", children: [(0, jsx_runtime_1.jsx)(divider_1.Divider, { className: "ndl-combobox-action-divider", htmlAttributes: { 'aria-hidden': true } }), actionRows.map((row, index) => ((0, jsx_runtime_1.jsxs)(react_2.Fragment, { children: [index > 0 && (0, combobox_utils_1.getAction)(row).hasDivider === true && ((0, jsx_runtime_1.jsx)(divider_1.Divider, { className: "ndl-combobox-action-divider", htmlAttributes: { 'aria-hidden': true } })), renderAction(row)] }, row.value)))] })))] })));
572
- return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ ref: ref, style: style, className: (0, classnames_1.default)('ndl-combobox', {
578
+ const formControl = name !== undefined && ((0, jsx_runtime_1.jsx)(ComboboxFormControl, { ref: internalTriggerRef, name: name, form: formId, autoComplete: autoComplete, options: formOptions, selectedOptions: selectedOptions, resetSelectedOptions: resetSelectedOptions, isMulti: isMulti, isDisabled: isDisabled, isRequired: isRequired, isSelectionControlled: value !== undefined, onValueChange: setSelectedValue, onInvalid: setNativeValidationMessage, onReset: resetFromForm }));
579
+ const floatingPanel = context.open && ((0, jsx_runtime_1.jsx)(conditional_wrap_1.ConditionalWrap, { shouldWrap: isPanelPortaled, wrap: (wrapChildren) => ((0, jsx_runtime_1.jsx)(react_1.FloatingPortal, { root: portalTarget, children: wrapChildren })), children: (0, jsx_runtime_1.jsx)(react_1.FloatingFocusManager, { context: context, modal: false,
580
+ // A select-only combobox keeps DOM focus on the trigger and speaks
581
+ // through aria-activedescendant, so nothing inside is focused.
582
+ initialFocus: isSearchable ? searchInputRef : -1, returnFocus: internalTriggerRef, children: panel }) }));
583
+ // No root element around a custom trigger, so the trigger is a real child of
584
+ // whatever holds the combobox and sibling-based selectors there match it.
585
+ // The form control goes after the trigger to keep it out of leading
586
+ // positional slots.
587
+ if (renderTrigger !== undefined) {
588
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [renderTrigger(triggerProps, triggerState), formControl, floatingPanel] }));
589
+ }
590
+ return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ ref: ref, style: style, className: (0, classnames_1.default)('ndl-combobox ndl-combobox-field', {
573
591
  'ndl-clean': isClean,
574
- 'ndl-combobox-custom-trigger': hasCustomTrigger,
575
- 'ndl-combobox-field': !hasCustomTrigger,
576
592
  'ndl-disabled': isDisabled,
577
593
  'ndl-fluid': isFluid,
578
594
  'ndl-has-error': hasError,
579
595
  'ndl-large': size === 'large',
580
596
  'ndl-medium': size === 'medium',
581
597
  'ndl-small': size === 'small',
582
- }, className) }, htmlAttributes, { children: [name !== undefined && ((0, jsx_runtime_1.jsx)(ComboboxFormControl, { ref: internalTriggerRef, name: name, form: formId, autoComplete: autoComplete, options: formOptions, selectedOptions: selectedOptions, resetSelectedOptions: resetSelectedOptions, isMulti: isMulti, isDisabled: isDisabled, isRequired: isRequired, isSelectionControlled: value !== undefined, onValueChange: setSelectedValue, onInvalid: setNativeValidationMessage, onReset: resetFromForm })), renderTrigger === undefined ? ((0, jsx_runtime_1.jsx)(Control, { triggerProps: builtInTriggerProps, state: triggerState, field: field, placeholder: placeholder, isClearable: isClearable, isClean: isClean, size: size, maxRows: isMulti ? maxRows : undefined, components: components, referenceProps: getReferenceProps(), referenceRef: refs.setReference })) : (renderTrigger(triggerProps, triggerState)), context.open && ((0, jsx_runtime_1.jsx)(conditional_wrap_1.ConditionalWrap, { shouldWrap: isPanelPortaled, wrap: (wrapChildren) => ((0, jsx_runtime_1.jsx)(react_1.FloatingPortal, { root: portalTarget, children: wrapChildren })), children: (0, jsx_runtime_1.jsx)(react_1.FloatingFocusManager, { context: context, modal: false,
583
- // A select-only combobox keeps DOM focus on the trigger and speaks
584
- // through aria-activedescendant, so nothing inside is focused.
585
- initialFocus: isSearchable ? searchInputRef : -1, returnFocus: internalTriggerRef, children: panel }) }))] })));
598
+ }, className) }, htmlAttributes, { children: [formControl, (0, jsx_runtime_1.jsx)(Control, { triggerProps: builtInTriggerProps, state: triggerState, field: field, placeholder: placeholder, isClearable: isClearable, isClean: isClean, size: size, maxRows: isMulti ? maxRows : undefined, components: components, referenceProps: getReferenceProps(), referenceRef: refs.setReference }), floatingPanel] })));
586
599
  };
587
600
  exports.Combobox = Combobox;
588
601
  const getTriggerControlsId = ({ isPanelOpen, isDialogPanel, hasRows, panelId, listboxId, }) => {
@@ -602,6 +615,42 @@ const getSelectedOptions = (value) => {
602
615
  }
603
616
  return value === null ? [] : [value];
604
617
  };
618
+ /**
619
+ * The public `ComboboxFieldState` keeps its own shape - a custom trigger
620
+ * renders from it - so the built-in field parts map it onto the shared form
621
+ * field state (`_common/form-control`) instead of taking it directly.
622
+ */
623
+ const toFormFieldState = (field) => {
624
+ const hasHelpText = Boolean(field.helpText) && !field.hasError;
625
+ return {
626
+ controlId: field.triggerId,
627
+ errorText: field.errorText,
628
+ errorTextId: field.errorTextId,
629
+ hasError: field.hasError,
630
+ hasRequiredIndicator: field.hasRequiredIndicator,
631
+ hasVisuallyHiddenLabel: field.hasVisuallyHiddenLabel,
632
+ helpText: field.helpText,
633
+ helpTextId: field.helpTextId,
634
+ isRequired: field.isRequired,
635
+ label: field.label,
636
+ labelId: field.labelId,
637
+ message: field.hasError
638
+ ? field.errorText
639
+ : hasHelpText
640
+ ? field.helpText
641
+ : undefined,
642
+ messageId: field.hasError
643
+ ? field.errorTextId
644
+ : hasHelpText
645
+ ? field.helpTextId
646
+ : undefined,
647
+ messageSeverity: field.hasError
648
+ ? 'error'
649
+ : hasHelpText
650
+ ? 'help'
651
+ : undefined,
652
+ };
653
+ };
605
654
  /**
606
655
  * A native select mirrors the custom control for submission, autofill,
607
656
  * constraint validation, and reset. It is hidden from assistive technology
@@ -698,6 +747,7 @@ const Control = ({ triggerProps, state, field, placeholder, isClearable, isClean
698
747
  const { isOpen, isMulti, isDisabled, selectedOptions, clear, remove } = state;
699
748
  const { MultiValue, SingleValue } = components;
700
749
  const { ref: triggerRef } = triggerProps, triggerAria = __rest(triggerProps, ["ref"]);
750
+ const sharedField = toFormFieldState(field);
701
751
  const hasValue = selectedOptions.length > 0;
702
752
  const singleValueOption = isMulti ? undefined : selectedOptions[0];
703
753
  // Selected values are shown as tags, so the trigger renders nothing and is
@@ -807,7 +857,7 @@ const Control = ({ triggerProps, state, field, placeholder, isClearable, isClean
807
857
  return (
808
858
  // A fragment, so the label, the control, and the message are rows of the
809
859
  // combobox itself. A custom trigger replaces all three.
810
- (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(FieldLabel, { field: field, size: size, onLabelClick: handleLabelClick }), (0, jsx_runtime_1.jsxs)("div", Object.assign({ ref: referenceRef, className: (0, classnames_1.default)('ndl-combobox-control', {
860
+ (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(form_control_1.FormFieldLabel, { field: sharedField, size: size, onLabelClick: handleLabelClick }), (0, jsx_runtime_1.jsxs)("div", Object.assign({ ref: referenceRef, className: (0, classnames_1.default)('ndl-combobox-control', {
811
861
  'ndl-clean': isClean,
812
862
  'ndl-disabled': isDisabled,
813
863
  'ndl-has-error': field.hasError,
@@ -853,35 +903,7 @@ const Control = ({ triggerProps, state, field, placeholder, isClearable, isClean
853
903
  // Select.
854
904
  (0, jsx_runtime_1.jsxs)("div", { className: "ndl-combobox-clear", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "ndl-combobox-clear-button", "aria-label": "Clear selection", onKeyDown: handleAuxiliaryActionKeyDown, onClick: handleClear, children: (0, jsx_runtime_1.jsx)(heroIcons_1.XMarkIconOutline, {}) }), (0, jsx_runtime_1.jsx)("div", { className: "ndl-combobox-divider" })] })), (0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('ndl-combobox-dropdown-indicator', {
855
905
  'ndl-open': isOpen,
856
- }), children: (0, jsx_runtime_1.jsx)(heroIcons_1.ChevronDownIconOutline, { "aria-hidden": "true", className: "ndl-combobox-icon" }) })] })] })), (0, jsx_runtime_1.jsx)(FieldMessage, { field: field, size: size })] }));
857
- };
858
- /**
859
- * The trigger is a button with `role="combobox"`, which takes its accessible
860
- * name from the author rather than from its content, so the label is referenced
861
- * through `aria-labelledby` instead of wrapping the control in a `<label>`.
862
- * The label is still a `<label>` associated through `htmlFor`, and clicking it
863
- * moves focus to the trigger, as with a native select. It deliberately does
864
- * not open the panel, which is also what a native select label leaves alone.
865
- */
866
- const FieldLabel = ({ field, size, onLabelClick }) => {
867
- const { label, labelId, triggerId, hasVisuallyHiddenLabel, hasRequiredIndicator, isRequired, } = field;
868
- const variant = size === 'large' ? 'body-large' : 'body-medium';
869
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)('ndl-combobox-label-row', {
870
- 'ndl-visually-hidden': hasVisuallyHiddenLabel,
871
- }), children: [(0, jsx_runtime_1.jsx)(typography_1.Typography, { as: "label", variant: variant, className: "ndl-combobox-label", htmlAttributes: {
872
- htmlFor: triggerId,
873
- id: labelId,
874
- onClick: onLabelClick,
875
- }, children: label }), hasRequiredIndicator && ((0, jsx_runtime_1.jsx)(typography_1.Typography, { variant: variant, className: "ndl-combobox-label-indicator", children: isRequired ? 'Required' : 'Optional' }))] }));
876
- };
877
- /**
878
- * Rendered whether or not there is a message, so the live region is in the
879
- * document before the text arrives and a validation error is announced.
880
- */
881
- const FieldMessage = ({ field, size }) => {
882
- const { errorText, hasError, helpText, helpTextId, errorTextId } = field;
883
- const variant = size === 'large' ? 'body-medium' : 'body-small';
884
- return ((0, jsx_runtime_1.jsxs)("div", { className: "ndl-combobox-message", "aria-live": "polite", children: [hasError && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "ndl-error-icon", children: (0, jsx_runtime_1.jsx)(heroIcons_1.ExclamationCircleIconSolid, {}) }), (0, jsx_runtime_1.jsx)(typography_1.Typography, { variant: variant, className: "ndl-error-text", htmlAttributes: { id: errorTextId }, children: errorText })] })), !hasError && Boolean(helpText) && ((0, jsx_runtime_1.jsx)(typography_1.Typography, { variant: variant, htmlAttributes: { id: helpTextId }, children: helpText }))] }));
906
+ }), children: (0, jsx_runtime_1.jsx)(heroIcons_1.ChevronDownIconOutline, { "aria-hidden": "true", className: "ndl-combobox-icon" }) })] })] })), (0, jsx_runtime_1.jsx)(form_control_1.FormFieldMessage, { field: sharedField, size: size })] }));
885
907
  };
886
908
  const Panel = (_a) => {
887
909
  var { children, ref, id, ariaLabel, isDialog, className, style } = _a, restProps = __rest(_a, ["children", "ref", "id", "ariaLabel", "isDialog", "className", "style"]);