@crewlethq/ui 0.45.0 → 0.47.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 (123) hide show
  1. package/README.md +28 -0
  2. package/dist/AgentHandoffPanel/index.js +6 -3
  3. package/dist/AppShell/index.js +3 -3
  4. package/dist/ArrangeList/index.js +5 -3
  5. package/dist/ArtifactBar/index.js +5 -5
  6. package/dist/AvatarPicker/index.js +6 -6
  7. package/dist/Canvas/index.js +1 -1
  8. package/dist/CanvasBoard/index.js +1 -1
  9. package/dist/CanvasToolbar/index.js +1 -1
  10. package/dist/CatalogTile/index.js +1 -1
  11. package/dist/{CatalogTile-VPSLCKJE.css → CatalogTile-26XN7L2A.css} +13 -7
  12. package/dist/CharacterCount/CharacterCount.d.ts +63 -0
  13. package/dist/CharacterCount/index.d.ts +3 -0
  14. package/dist/CharacterCount/index.js +4 -0
  15. package/dist/CharacterCount-S735DICR.css +29 -0
  16. package/dist/Checkbox/index.js +5 -2
  17. package/dist/Combobox/index.js +5 -3
  18. package/dist/CommandPalette/index.js +6 -4
  19. package/dist/CommentThread/index.js +6 -3
  20. package/dist/Composer/index.js +5 -2
  21. package/dist/ConfirmField/index.js +5 -2
  22. package/dist/DataTable/index.js +8 -6
  23. package/dist/DataView/index.js +9 -7
  24. package/dist/DateTimePicker/index.js +1 -1
  25. package/dist/DocTabsEditor/index.js +5 -4
  26. package/dist/EditingStatus/index.js +2 -1
  27. package/dist/{Editor-AMO2B54T.js → Editor-MLGK3KOG.js} +6 -4
  28. package/dist/FollowBanner/index.js +2 -2
  29. package/dist/HuePicker/index.js +5 -5
  30. package/dist/InlineEditor/InlineEditor.d.ts +86 -0
  31. package/dist/InlineEditor/index.d.ts +3 -0
  32. package/dist/InlineEditor/index.js +9 -0
  33. package/dist/InlineEditor-W55DDKML.css +72 -0
  34. package/dist/Input/FormField.d.ts +27 -1
  35. package/dist/Input/Textarea.d.ts +16 -0
  36. package/dist/Input/index.d.ts +3 -2
  37. package/dist/Input/index.js +4 -1
  38. package/dist/{Input-OQZBCRX5.css → Input-VDSV7VWJ.css} +19 -0
  39. package/dist/LinkInterstitial/index.js +3 -3
  40. package/dist/List/List.d.ts +16 -1
  41. package/dist/List/index.js +1 -1
  42. package/dist/{List-YHLIZFK4.css → List-XY445TKY.css} +31 -0
  43. package/dist/ListInput/ListInput.d.ts +87 -2
  44. package/dist/ListInput/index.d.ts +2 -2
  45. package/dist/ListInput/index.js +5 -2
  46. package/dist/{ListInput-O7LJKOIG.css → ListInput-WUP2YITQ.css} +147 -2
  47. package/dist/MarkdownEditor/index.js +5 -5
  48. package/dist/Menu/index.js +2 -2
  49. package/dist/MergeConflicts/index.js +5 -5
  50. package/dist/Modal/index.js +2 -2
  51. package/dist/PresenterView/index.js +3 -3
  52. package/dist/PrincipalPicker/index.js +6 -4
  53. package/dist/RelatedRow/index.js +2 -2
  54. package/dist/RichEditor/index.js +1 -1
  55. package/dist/SegmentedControl/index.js +4 -4
  56. package/dist/Select/index.js +1 -1
  57. package/dist/ShareDialog/index.js +3 -3
  58. package/dist/SheetColumnEditor/index.js +10 -8
  59. package/dist/SheetGrid/index.js +3 -3
  60. package/dist/SlideCompare/index.js +1 -1
  61. package/dist/SlideFilmstrip/index.js +3 -3
  62. package/dist/Switcher/index.js +5 -4
  63. package/dist/Tabs/index.js +3 -3
  64. package/dist/Text/Text.d.ts +8 -0
  65. package/dist/Text/index.js +1 -1
  66. package/dist/{Text-S3Q4O3IG.css → Text-XOCOU34C.css} +9 -0
  67. package/dist/ThemeSwitcher/index.js +5 -5
  68. package/dist/TileGrid/index.js +1 -1
  69. package/dist/{TileGrid-I6LNYD2H.css → TileGrid-UYMVVVJK.css} +30 -0
  70. package/dist/TimeWindowPicker/index.js +5 -3
  71. package/dist/TreeCanvas/index.js +1 -1
  72. package/dist/VersionCompare/index.js +5 -5
  73. package/dist/{chunk-5AHDGYKN.js → chunk-2KQR6JKE.js} +2 -2
  74. package/dist/{chunk-4DIKLY53.js → chunk-32TGEMQQ.js} +1 -1
  75. package/dist/{chunk-QOP7QYUW.js → chunk-34RMTXDZ.js} +1 -1
  76. package/dist/{chunk-Q7HLZH32.js → chunk-3QSKDZR5.js} +1 -1
  77. package/dist/{chunk-BVFMLSE3.js → chunk-5EBDOE3C.js} +1 -1
  78. package/dist/{chunk-W53CWWX3.js → chunk-627KFRON.js} +2 -2
  79. package/dist/{chunk-AGNZIT3Z.js → chunk-6EBGPCAW.js} +1 -1
  80. package/dist/{chunk-BF5WV7NM.js → chunk-6FVGSWLS.js} +1 -1
  81. package/dist/{chunk-7CXGSS7D.js → chunk-6R5BSA36.js} +1 -1
  82. package/dist/{chunk-NF6SWHQI.js → chunk-7JED2NYP.js} +2 -2
  83. package/dist/chunk-7P336RA5.js +147 -0
  84. package/dist/{chunk-GI3S6RMM.js → chunk-AS2BMY3E.js} +3 -3
  85. package/dist/{chunk-N3SHQ3VU.js → chunk-CWKWMIIJ.js} +1 -1
  86. package/dist/{chunk-KKUJSMLF.js → chunk-DY4DQ7EB.js} +1 -1
  87. package/dist/{chunk-ZI5G5RS7.js → chunk-EXRRTKWT.js} +59 -9
  88. package/dist/{chunk-EY7LACIR.js → chunk-F57N6ZJG.js} +1 -1
  89. package/dist/chunk-ICVS3U4S.js +436 -0
  90. package/dist/{chunk-KA75QPFM.js → chunk-ILFEWRLG.js} +1 -1
  91. package/dist/{chunk-JF3TJUBU.js → chunk-JWNYI7UD.js} +1 -1
  92. package/dist/{chunk-GPIRKHGS.js → chunk-LIJQT74Y.js} +1 -1
  93. package/dist/{chunk-TC7DJTXI.js → chunk-MULOZYHL.js} +2 -0
  94. package/dist/{chunk-FV6H7H5I.js → chunk-MUQJCH2Y.js} +4 -4
  95. package/dist/{chunk-ZUTUI27P.js → chunk-N4GBDK4L.js} +1 -1
  96. package/dist/{chunk-Y4GXCKOC.js → chunk-OHJ2R2X4.js} +3 -3
  97. package/dist/{chunk-OWIGEE2Y.js → chunk-OO7QJCJQ.js} +2 -2
  98. package/dist/{chunk-MVGCZ655.js → chunk-OOJTPR7N.js} +1 -1
  99. package/dist/{chunk-NNTO3TNC.js → chunk-Q6CQMS6R.js} +1 -1
  100. package/dist/{chunk-IKBK4A5O.js → chunk-QP2P6GDQ.js} +1 -1
  101. package/dist/{chunk-U44WGRFW.js → chunk-RFPCHMSX.js} +1 -1
  102. package/dist/{chunk-LSRQJDGR.js → chunk-SEPSXOGJ.js} +1 -1
  103. package/dist/{chunk-MCOC3KQA.js → chunk-SQ4JFHO7.js} +1 -1
  104. package/dist/{chunk-DL5ERIFF.js → chunk-SS4XCUUJ.js} +2 -2
  105. package/dist/{chunk-NZWX27J7.js → chunk-TDQ262TB.js} +19 -3
  106. package/dist/{chunk-5GNA4RKP.js → chunk-TGSIVB6H.js} +1 -1
  107. package/dist/{chunk-6MAQ2SVP.js → chunk-TWZEWXNW.js} +3 -3
  108. package/dist/{chunk-UO5VJHWP.js → chunk-U4HOKU6P.js} +2 -2
  109. package/dist/{chunk-X6IJ7DAX.js → chunk-VKFG4FLE.js} +2 -2
  110. package/dist/chunk-XCUUI7E7.js +62 -0
  111. package/dist/{chunk-ENHLVF6Q.js → chunk-XS2FJVMT.js} +1 -1
  112. package/dist/{chunk-FG243QHY.js → chunk-ZCIL5IHU.js} +1 -1
  113. package/dist/generated/index.d.ts +2 -0
  114. package/dist/generated/index.js +76 -74
  115. package/dist/index.js +76 -74
  116. package/dist/styles.css +362 -15
  117. package/package.json +3 -3
  118. package/dist/chunk-NMYGJJJK.js +0 -263
  119. package/dist/{chunk-6IPEPSB5.js → chunk-245IXG5P.js} +0 -0
  120. package/dist/{chunk-OED6LUWE.js → chunk-4A4QG6UC.js} +1 -1
  121. package/dist/{chunk-FYINAYAJ.js → chunk-6AKG2VLR.js} +1 -1
  122. package/dist/{chunk-E6HXFFWO.js → chunk-ISDEXIXH.js} +1 -1
  123. package/dist/{chunk-PCI7ZJ6Z.js → chunk-TMM32U7D.js} +1 -1
@@ -1,5 +1,5 @@
1
1
  import { NODE_HUES, NODE_HUE_NAMES } from './chunk-AYKXMIOR.js';
2
- import { SegmentedControl } from './chunk-BF5WV7NM.js';
2
+ import { SegmentedControl } from './chunk-6FVGSWLS.js';
3
3
  import { cx } from './chunk-ODEQTPFM.js';
4
4
  import { jsx } from 'react/jsx-runtime';
5
5
 
@@ -1,4 +1,4 @@
1
- import { HuePicker } from './chunk-QOP7QYUW.js';
1
+ import { HuePicker } from './chunk-34RMTXDZ.js';
2
2
  import { Popover } from './chunk-KHJIEPZV.js';
3
3
  import { NODE_HUE_NAMES } from './chunk-AYKXMIOR.js';
4
4
  import { CharacterPicker } from './chunk-SNQRGH4A.js';
@@ -1,6 +1,6 @@
1
1
  import { Select } from './chunk-XQZ6EWOE.js';
2
2
  import { CopyButton } from './chunk-7SHAFLEX.js';
3
- import { Modal } from './chunk-FYINAYAJ.js';
3
+ import { Modal } from './chunk-6AKG2VLR.js';
4
4
  import { Callout } from './chunk-SZZRIHGT.js';
5
5
  import { PrincipalAvatar } from './chunk-CI3VPIJN.js';
6
6
  import { useHeadingLevel, headingTag } from './chunk-PQADV6P6.js';
@@ -1,6 +1,6 @@
1
1
  import { useReorder } from './chunk-XJ2QEBMM.js';
2
- import { Input } from './chunk-ZI5G5RS7.js';
3
- import { Menu } from './chunk-PCI7ZJ6Z.js';
2
+ import { Input } from './chunk-EXRRTKWT.js';
3
+ import { Menu } from './chunk-TMM32U7D.js';
4
4
  import { IconButton } from './chunk-LACA4JGC.js';
5
5
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
6
6
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,7 +1,7 @@
1
1
  import { PrincipalAvatar } from './chunk-CI3VPIJN.js';
2
2
  import { toInstant, RelativeTime, formatExact, toISO } from './chunk-3CZ7XAVY.js';
3
3
  import { Document } from './chunk-PWG3VHRQ.js';
4
- import { Composer } from './chunk-7CXGSS7D.js';
4
+ import { Composer } from './chunk-6R5BSA36.js';
5
5
  import { Count } from './chunk-BHHIIK3M.js';
6
6
  import { useHeadingLevel, headingTag } from './chunk-PQADV6P6.js';
7
7
  import { Button } from './chunk-OG6CL3EB.js';
@@ -1,4 +1,4 @@
1
- import { tabId } from './chunk-KA75QPFM.js';
1
+ import { tabId } from './chunk-ILFEWRLG.js';
2
2
  import { useRoving, tabStop } from './chunk-EGMQURBR.js';
3
3
  import { Count } from './chunk-BHHIIK3M.js';
4
4
  import { HIT_AREA_CLASS } from './chunk-2YTOOH3A.js';
@@ -1,4 +1,4 @@
1
- import { Textarea } from './chunk-ZI5G5RS7.js';
1
+ import { Textarea } from './chunk-EXRRTKWT.js';
2
2
  import { Kbd } from './chunk-SMBKXWML.js';
3
3
  import { cx } from './chunk-ODEQTPFM.js';
4
4
  import './Composer-TXULCPPV.css';
@@ -1,9 +1,9 @@
1
- import { Modal } from './chunk-FYINAYAJ.js';
1
+ import { Modal } from './chunk-6AKG2VLR.js';
2
2
  import { useListbox, useOptionKeys } from './chunk-7KHM2FZH.js';
3
3
  import { Popover } from './chunk-KHJIEPZV.js';
4
4
  import { KeyChip, highlightMatch } from './chunk-FYTIJM2T.js';
5
5
  import { Skeleton } from './chunk-TEUQWOWZ.js';
6
- import { Input } from './chunk-ZI5G5RS7.js';
6
+ import { Input } from './chunk-EXRRTKWT.js';
7
7
  import { announce } from './chunk-RSAQOKH3.js';
8
8
  import { useMediaMatch } from './chunk-RTPQDNW3.js';
9
9
  import { focusables, isComposing } from './chunk-H5XTJ7GJ.js';
@@ -0,0 +1,147 @@
1
+ import { EditingStatus } from './chunk-MULOZYHL.js';
2
+ import { Kbd } from './chunk-SMBKXWML.js';
3
+ import { Button } from './chunk-OG6CL3EB.js';
4
+ import { isComposing } from './chunk-H5XTJ7GJ.js';
5
+ import { cx } from './chunk-ODEQTPFM.js';
6
+ import './InlineEditor-W55DDKML.css';
7
+ import { useRef, useLayoutEffect } from 'react';
8
+ import { jsxs, jsx } from 'react/jsx-runtime';
9
+
10
+ var INLINE_EDITOR_LABELS = {
11
+ save: "Save",
12
+ cancel: "Cancel",
13
+ unchanged: "Nothing has changed yet.",
14
+ invalid: "Fix the highlighted field first.",
15
+ saving: "Saving. Wait for it to finish.",
16
+ shortcut: "to save"
17
+ };
18
+ function firstField(root) {
19
+ return root.querySelector(
20
+ 'textarea:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), [contenteditable="true"]'
21
+ );
22
+ }
23
+ function InlineEditor({
24
+ label,
25
+ children,
26
+ onSave,
27
+ onCancel,
28
+ dirty,
29
+ saving = false,
30
+ invalid = false,
31
+ error,
32
+ notice,
33
+ focusOnMount = true,
34
+ shortcutHint = true,
35
+ secondaryActions,
36
+ labels: overrides,
37
+ className,
38
+ onKeyDown,
39
+ ...rest
40
+ }) {
41
+ const labels = { ...INLINE_EDITOR_LABELS, ...overrides };
42
+ const form = useRef(null);
43
+ const focusAtMount = useRef(focusOnMount);
44
+ useLayoutEffect(() => {
45
+ if (!focusAtMount.current || !form.current) return;
46
+ const field = firstField(form.current);
47
+ if (!field) return;
48
+ field.focus();
49
+ if (field instanceof HTMLTextAreaElement || field instanceof HTMLInputElement) {
50
+ const end = field.value.length;
51
+ try {
52
+ field.setSelectionRange(end, end);
53
+ } catch {
54
+ }
55
+ }
56
+ }, []);
57
+ const blocked = saving ? labels.saving : invalid ? labels.invalid : !dirty ? labels.unchanged : null;
58
+ const save = () => {
59
+ if (blocked === null) onSave();
60
+ };
61
+ const submit = (event) => {
62
+ event.preventDefault();
63
+ save();
64
+ };
65
+ const keys = (event) => {
66
+ onKeyDown?.(event);
67
+ if (event.defaultPrevented || isComposing(event)) return;
68
+ if (event.key === "Escape") {
69
+ event.preventDefault();
70
+ if (!saving) onCancel();
71
+ return;
72
+ }
73
+ if (event.key !== "Enter") return;
74
+ if ((event.metaKey || event.ctrlKey) && !event.altKey) {
75
+ event.preventDefault();
76
+ save();
77
+ return;
78
+ }
79
+ if (event.target instanceof HTMLInputElement) event.preventDefault();
80
+ };
81
+ return (
82
+ /*
83
+ * THE FORM LISTENS FOR ITS TWO KEYS, as React's own handler rather than a
84
+ * native one, because React's runs after every handler inside it: that is
85
+ * what lets an open menu's Escape close the menu and stop there. A
86
+ * native listener on the form would hear the key first, before anything
87
+ * inside had the chance to claim it.
88
+ */
89
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- see above
90
+ /* @__PURE__ */ jsxs(
91
+ "form",
92
+ {
93
+ ...rest,
94
+ ref: form,
95
+ "aria-label": label,
96
+ "aria-busy": saving || void 0,
97
+ noValidate: true,
98
+ className: cx("crewlet-inline-editor", className),
99
+ onSubmit: submit,
100
+ onKeyDown: keys,
101
+ children: [
102
+ /* @__PURE__ */ jsx("div", { className: "crewlet-inline-editor__fields", children }),
103
+ notice ? /* @__PURE__ */ jsx("div", { className: "crewlet-inline-editor__notice", children: notice }) : null,
104
+ error ? /* @__PURE__ */ jsx("div", { className: "crewlet-inline-editor__error", role: "alert", children: error }) : null,
105
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-inline-editor__bar", children: [
106
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-inline-editor__start", children: [
107
+ /* @__PURE__ */ jsx(EditingStatus, { dirty, saving, labels: labels.status }),
108
+ secondaryActions
109
+ ] }),
110
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-inline-editor__end", children: [
111
+ shortcutHint ? /* @__PURE__ */ jsxs("span", { className: "crewlet-inline-editor__hint", children: [
112
+ /* @__PURE__ */ jsx(Kbd, { keys: ["Mod", "Enter"], subtle: true }),
113
+ " ",
114
+ labels.shortcut
115
+ ] }) : null,
116
+ /* @__PURE__ */ jsx(
117
+ Button,
118
+ {
119
+ size: "small",
120
+ variant: "ghost",
121
+ ...saving ? { disabledReason: labels.saving } : {},
122
+ onClick: () => {
123
+ if (!saving) onCancel();
124
+ },
125
+ children: labels.cancel
126
+ }
127
+ ),
128
+ /* @__PURE__ */ jsx(
129
+ Button,
130
+ {
131
+ size: "small",
132
+ variant: "primary",
133
+ type: "submit",
134
+ loading: saving,
135
+ ...blocked !== null && !saving ? { disabledReason: blocked } : {},
136
+ children: labels.save
137
+ }
138
+ )
139
+ ] })
140
+ ] })
141
+ ]
142
+ }
143
+ )
144
+ );
145
+ }
146
+
147
+ export { INLINE_EDITOR_LABELS, InlineEditor };
@@ -1,9 +1,9 @@
1
1
  import { useClipboard } from './chunk-STJ7QBC3.js';
2
- import { Modal } from './chunk-FYINAYAJ.js';
3
- import { Checkbox } from './chunk-EY7LACIR.js';
2
+ import { Modal } from './chunk-6AKG2VLR.js';
3
+ import { Checkbox } from './chunk-F57N6ZJG.js';
4
4
  import { EmptyValue } from './chunk-EUCC37WY.js';
5
5
  import { useCardHeaderSlot } from './chunk-AV2DXAEL.js';
6
- import { Menu } from './chunk-PCI7ZJ6Z.js';
6
+ import { Menu } from './chunk-TMM32U7D.js';
7
7
  import { Button } from './chunk-OG6CL3EB.js';
8
8
  import { IconButton } from './chunk-LACA4JGC.js';
9
9
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
@@ -1,7 +1,7 @@
1
1
  import { Timeline } from './chunk-AUQPBL4O.js';
2
2
  import { Section } from './chunk-JQ7IFSF6.js';
3
3
  import { Disclosure } from './chunk-OGXHZHRX.js';
4
- import { Composer } from './chunk-7CXGSS7D.js';
4
+ import { Composer } from './chunk-6R5BSA36.js';
5
5
  import { ArtifactPanel } from './chunk-NBDN5JZV.js';
6
6
  import { Button } from './chunk-OG6CL3EB.js';
7
7
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,5 +1,5 @@
1
1
  import { InlineCode } from './chunk-5CLW2CXT.js';
2
- import { ConfirmModal } from './chunk-FYINAYAJ.js';
2
+ import { ConfirmModal } from './chunk-6AKG2VLR.js';
3
3
  import { Callout } from './chunk-SZZRIHGT.js';
4
4
  import './LinkInterstitial-ET4MSVSV.css';
5
5
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -1,9 +1,13 @@
1
+ import { characterCountState, CharacterCount } from './chunk-XCUUI7E7.js';
1
2
  import { useHeadingLevel, headingTag, HeadingLevelProvider, nextHeadingLevel } from './chunk-PQADV6P6.js';
3
+ import { announce } from './chunk-RSAQOKH3.js';
4
+ import { isComposing } from './chunk-H5XTJ7GJ.js';
2
5
  import { IconButton } from './chunk-LACA4JGC.js';
3
6
  import { useFocusModality } from './chunk-NUZHC6MM.js';
4
7
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
5
8
  import { cx } from './chunk-ODEQTPFM.js';
6
- import './Input-OQZBCRX5.css';
9
+ import './Input-VDSV7VWJ.css';
10
+ import './VisuallyHidden-L552H7OA.css';
7
11
  import { forwardRef, useRef, useState, useImperativeHandle, useEffect, useId } from 'react';
8
12
  import { XGlyph } from '@crewlethq/icons/glyphs';
9
13
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -81,7 +85,24 @@ function InputAffix({ text, id, sentence }) {
81
85
  /* @__PURE__ */ jsx(VisuallyHidden, { id, children: sentence ?? `Begins with ${text}` })
82
86
  ] });
83
87
  }
84
- var Textarea = forwardRef(function Textarea2({ error = false, autoResize = false, trailing, className = "", value, disabled, ...rest }, ref) {
88
+ var LINE_BREAK = /[\r\n\v\f\u0085\u2028\u2029]/;
89
+ var LINE_BREAKS = /[ \t]*(?:\r\n|[\r\n\v\f\u0085\u2028\u2029])+[ \t]*/g;
90
+ function foldLineBreaks(text) {
91
+ return text.replace(LINE_BREAKS, " ");
92
+ }
93
+ var Textarea = forwardRef(function Textarea2({
94
+ error = false,
95
+ autoResize = false,
96
+ trailing,
97
+ singleLine = false,
98
+ foldedMessage = "Line breaks were replaced with spaces: this field holds one line.",
99
+ className = "",
100
+ value,
101
+ disabled,
102
+ onChange,
103
+ onKeyDown,
104
+ ...rest
105
+ }, ref) {
85
106
  useFocusModality();
86
107
  const localRef = useRef(null);
87
108
  useImperativeHandle(ref, () => localRef.current);
@@ -104,6 +125,22 @@ var Textarea = forwardRef(function Textarea2({ error = false, autoResize = false
104
125
  resize?.disconnect();
105
126
  };
106
127
  }, [autoResize, value]);
128
+ const keys = (event) => {
129
+ onKeyDown?.(event);
130
+ if (!singleLine || event.defaultPrevented || event.key !== "Enter") return;
131
+ if (event.ctrlKey || event.metaKey || isComposing(event)) return;
132
+ event.preventDefault();
133
+ };
134
+ const change = (event) => {
135
+ const el = event.target;
136
+ if (singleLine && LINE_BREAK.test(el.value)) {
137
+ const caret = foldLineBreaks(el.value.slice(0, el.selectionStart ?? el.value.length)).length;
138
+ el.value = foldLineBreaks(el.value);
139
+ el.setSelectionRange(caret, caret);
140
+ announce(foldedMessage);
141
+ }
142
+ onChange?.(event);
143
+ };
107
144
  const control = /* @__PURE__ */ jsx(
108
145
  "textarea",
109
146
  {
@@ -118,7 +155,10 @@ var Textarea = forwardRef(function Textarea2({ error = false, autoResize = false
118
155
  value,
119
156
  disabled,
120
157
  "aria-invalid": error || void 0,
121
- ...rest
158
+ "aria-multiline": singleLine ? false : void 0,
159
+ ...rest,
160
+ onChange: change,
161
+ onKeyDown: keys
122
162
  }
123
163
  );
124
164
  if (!trailing) return control;
@@ -167,7 +207,9 @@ var FormField = ({
167
207
  helper,
168
208
  helperOnFocus = false,
169
209
  error,
210
+ limit,
170
211
  labelAction,
212
+ hideLabel = false,
171
213
  as = "div",
172
214
  describedBy,
173
215
  htmlFor,
@@ -179,22 +221,29 @@ var FormField = ({
179
221
  const id = htmlFor ?? autoId;
180
222
  const helperId = helper ? `${id}-helper` : void 0;
181
223
  const errorId = error ? `${id}-error` : void 0;
224
+ const countId = limit ? `${id}-count` : void 0;
225
+ const over = limit !== void 0 && characterCountState(limit.length, limit.max) === "over";
182
226
  const extra = describedBy === void 0 ? [] : typeof describedBy === "string" ? [describedBy] : [...describedBy];
183
- const described = [...extra, helperId, errorId].filter(Boolean).join(" ");
227
+ const described = [...extra, helperId, countId, errorId].filter(Boolean).join(" ");
228
+ const invalid = Boolean(error) || over;
184
229
  const field = {
185
230
  id,
186
231
  describedBy: described || void 0,
187
- invalid: Boolean(error),
232
+ invalid,
188
233
  required
189
234
  };
235
+ const help = helper ? /* @__PURE__ */ jsx("div", { id: helperId, className: "crewlet-form-field__helper", children: helper }) : null;
190
236
  const body = /* @__PURE__ */ jsxs(Fragment, { children: [
191
237
  typeof children === "function" ? children(field) : children,
192
- helper ? /* @__PURE__ */ jsx("div", { id: helperId, className: "crewlet-form-field__helper", children: helper }) : null,
238
+ limit ? /* @__PURE__ */ jsxs("div", { className: "crewlet-form-field__meta", children: [
239
+ help ?? /* @__PURE__ */ jsx("span", { className: "crewlet-form-field__meta-spacer" }),
240
+ /* @__PURE__ */ jsx(CharacterCount, { id: countId, length: limit.length, max: limit.max, labels: limit.labels })
241
+ ] }) : help,
193
242
  error ? /* @__PURE__ */ jsx("div", { id: errorId, className: "crewlet-form-field__error", role: "alert", children: error }) : null
194
243
  ] });
195
244
  const classes = cx(
196
245
  "crewlet-form-field",
197
- Boolean(error) && "is-error",
246
+ invalid && "is-error",
198
247
  helperOnFocus && helper ? "crewlet-form-field--helper-on-focus" : null,
199
248
  className
200
249
  );
@@ -206,7 +255,7 @@ var FormField = ({
206
255
  * the group itself and read when a reader enters it.
207
256
  */
208
257
  /* @__PURE__ */ jsxs("fieldset", { ...rest, "aria-describedby": field.describedBy, className: classes, children: [
209
- label !== void 0 ? /* @__PURE__ */ jsx("legend", { className: "crewlet-form-field__legend", children: /* @__PURE__ */ jsx(
258
+ label !== void 0 ? /* @__PURE__ */ jsx("legend", { className: cx("crewlet-form-field__legend", hideLabel && "crewlet-visually-hidden"), children: /* @__PURE__ */ jsx(
210
259
  Label,
211
260
  {
212
261
  as: "span",
@@ -230,6 +279,7 @@ var FormField = ({
230
279
  optional,
231
280
  requiredNews,
232
281
  action: labelAction,
282
+ className: hideLabel ? "crewlet-visually-hidden" : void 0,
233
283
  children: label
234
284
  }
235
285
  ) : null,
@@ -291,4 +341,4 @@ function ReadOnlyField({
291
341
  ] });
292
342
  }
293
343
 
294
- export { FormField, FormRow, FormSection, Input, InputAffix, Label, ReadOnlyField, Textarea };
344
+ export { FormField, FormRow, FormSection, Input, InputAffix, Label, ReadOnlyField, Textarea, foldLineBreaks };
@@ -1,4 +1,4 @@
1
- import { FormField } from './chunk-ZI5G5RS7.js';
1
+ import { FormField } from './chunk-EXRRTKWT.js';
2
2
  import { cx } from './chunk-ODEQTPFM.js';
3
3
  import './Checkbox-ALWG3WV2.css';
4
4
  import { forwardRef, useId, useRef, useCallback, useEffect } from 'react';