@stackone/malachite 2.32.0 → 2.33.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"FieldMessage.js","sources":["../../src/components/FieldMessage.tsx"],"sourcesContent":["import type React from 'react';\n\nconst MESSAGE_CLASSES =\n 'text-[length:var(--malachite-font-size-small,13px)] text-left pl-2 text-[var(--malachite-destructive-foreground,rgb(196,62,62))]';\n\ninterface FieldMessageProps {\n id?: string;\n message?: string;\n /** The controls that sit their message under a helper line need the gap; `Input` does not. */\n spaced?: boolean;\n}\n\n/**\n * A field's validation message. The live region is mounted whether or not there is anything\n * to say, because a region inserted with its text already inside it is not a mutation and\n * screen readers stay silent — which would lose the first rejection, the one that matters.\n * Out of flow while empty, so a flex parent's `gap` reserves no space beside it.\n */\nexport const FieldMessage: React.FC<FieldMessageProps> = ({ id, message, spaced = false }) => (\n <div\n id={id}\n // Polite rather than assertive: the message is also the field's description via\n // aria-describedby, and an interrupting region says it a second time.\n aria-live=\"polite\"\n className={message ? `${spaced ? 'mt-1 ' : ''}${MESSAGE_CLASSES}` : 'absolute'}\n >\n {message}\n </div>\n);\n\nexport default FieldMessage;\n"],"names":["MESSAGE_CLASSES","FieldMessage","id","message","spaced","jsx"],"mappings":";AAEA,MAAMA,IACF,oIAeSC,IAA4C,CAAC,EAAE,IAAAC,GAAI,SAAAC,GAAS,QAAAC,IAAS,SAC9E,gBAAAC;AAAA,EAAC;AAAA,EAAA;AAAA,IACG,IAAAH;AAAA,IAGA,aAAU;AAAA,IACV,WAAWC,IAAU,GAAGC,IAAS,UAAU,EAAE,GAAGJ,CAAe,KAAK;AAAA,IAEnE,UAAAG;AAAA,EAAA;AACL;"}
1
+ {"version":3,"file":"FieldMessage.js","sources":["../../src/components/FieldMessage.tsx"],"sourcesContent":["import type React from 'react';\n\nconst MESSAGE_CLASSES =\n 'text-[length:var(--malachite-font-size-small,13px)] text-left pl-2 text-[var(--malachite-destructive-foreground,rgb(196,62,62))]';\n\ninterface FieldMessageProps {\n id?: string;\n message?: string;\n /** The controls that sit their message under a helper line need the gap. */\n spaced?: boolean;\n}\n\n/**\n * A field's validation message. The live region is mounted whether or not there is anything\n * to say, because a region inserted with its text already inside it is not a mutation and\n * screen readers stay silent — which would lose the first rejection, the one that matters.\n * Out of flow while empty, so a flex parent's `gap` reserves no space beside it.\n */\nexport const FieldMessage: React.FC<FieldMessageProps> = ({ id, message, spaced = false }) => (\n <div\n id={id}\n // Polite rather than assertive: the message is also the field's description via\n // aria-describedby, and an interrupting region says it a second time.\n aria-live=\"polite\"\n className={message ? `${spaced ? 'mt-1 ' : ''}${MESSAGE_CLASSES}` : 'absolute'}\n >\n {message}\n </div>\n);\n\nexport default FieldMessage;\n"],"names":["MESSAGE_CLASSES","FieldMessage","id","message","spaced","jsx"],"mappings":";AAEA,MAAMA,IACF,oIAeSC,IAA4C,CAAC,EAAE,IAAAC,GAAI,SAAAC,GAAS,QAAAC,IAAS,SAC9E,gBAAAC;AAAA,EAAC;AAAA,EAAA;AAAA,IACG,IAAAH;AAAA,IAGA,aAAU;AAAA,IACV,WAAWC,IAAU,GAAGC,IAAS,UAAU,EAAE,GAAGJ,CAAe,KAAK;AAAA,IAEnE,UAAAG;AAAA,EAAA;AACL;"}
@@ -1,4 +1,4 @@
1
- import { jsx as a, jsxs as n, Fragment as K } from "react/jsx-runtime";
1
+ import { jsx as r, jsxs as n, Fragment as K } from "react/jsx-runtime";
2
2
  import { useState as j, useEffect as xe, useRef as ge } from "react";
3
3
  import be, { useFormFieldIds as we } from "../BaseFormComponent.js";
4
4
  import { Button as Q } from "../Button.js";
@@ -26,8 +26,8 @@ const J = {
26
26
  small: "rounded-[var(--malachite-radius-10,10px)]",
27
27
  medium: "rounded-xl",
28
28
  large: "rounded-[var(--malachite-radius-xxl,14px)]"
29
- }, $e = (r, e) => {
30
- switch (r) {
29
+ }, $e = (a, e) => {
30
+ switch (a) {
31
31
  case "ghost":
32
32
  return {
33
33
  wrapper: [
@@ -50,7 +50,7 @@ const J = {
50
50
  };
51
51
  }
52
52
  }, Je = ({
53
- label: r,
53
+ label: a,
54
54
  hint: e,
55
55
  tooltip: i,
56
56
  placeholder: x,
@@ -67,34 +67,34 @@ const J = {
67
67
  variant: F = "default",
68
68
  defaultValue: $,
69
69
  disabled: u,
70
- prefixValue: Z,
71
- prefixSecondaryValue: _,
70
+ prefixValue: M,
71
+ prefixSecondaryValue: T,
72
72
  ellipsis: O = !1,
73
- formControl: D,
73
+ formControl: Z,
74
74
  buttons: v,
75
- onCopyClick: M,
75
+ onCopyClick: _,
76
76
  showCopyButton: ee,
77
77
  onChange: b,
78
- value: ae,
78
+ value: re,
79
79
  onBlur: w,
80
80
  helperText: f,
81
81
  showPasswordToggle: I = !0,
82
- id: re,
82
+ id: ae,
83
83
  "aria-label": te,
84
84
  "aria-labelledby": ie,
85
85
  "aria-describedby": le
86
86
  }) => {
87
- const { controlId: P, labelId: se, descriptionId: A, hintId: G, helperTextId: y } = we({
88
- id: re,
89
- label: r,
87
+ const { controlId: D, labelId: se, descriptionId: P, hintId: A, helperTextId: y } = we({
88
+ id: ae,
89
+ label: a,
90
90
  description: R,
91
91
  hint: e,
92
92
  helperText: !0
93
- }), [C, oe] = j(!1), [de, ce] = j($ || ""), [N, H] = j(!1);
93
+ }), [C, oe] = j(!1), [de, ce] = j($ || ""), [N, G] = j(!1);
94
94
  xe(() => {
95
95
  if (N) {
96
96
  const t = setTimeout(() => {
97
- H(!1);
97
+ G(!1);
98
98
  }, 1e3);
99
99
  return () => clearTimeout(t);
100
100
  }
@@ -102,18 +102,18 @@ const J = {
102
102
  const ne = (t) => (l) => {
103
103
  const c = l.target.value;
104
104
  ce(c), b == null || b(c), t == null || t(c);
105
- }, T = ge(void 0), B = (t) => Se({
105
+ }, H = ge(void 0), B = (t) => Se({
106
106
  component: "Input",
107
107
  name: s,
108
- value: ae,
108
+ value: re,
109
109
  formValue: t,
110
110
  defaultValue: $,
111
- bound: !!D,
111
+ bound: !!Z,
112
112
  uncontrolledValue: de
113
- }), L = M ? () => {
114
- const t = B(T.current);
115
- t && (navigator.clipboard.writeText(t), H(!0), M());
116
- } : void 0, me = o === "password" ? C ? "text" : "password" : o, he = m || Z || _, pe = J[d], ue = (t) => {
113
+ }), L = _ ? () => {
114
+ const t = B(H.current);
115
+ t && (navigator.clipboard.writeText(t), G(!0), _());
116
+ } : void 0, me = o === "password" ? C ? "text" : "password" : o, he = m || M || T, pe = J[d], ue = (t) => {
117
117
  const l = $e(F, t);
118
118
  return [
119
119
  "relative",
@@ -127,46 +127,53 @@ const J = {
127
127
  J[d]
128
128
  ].filter(Boolean).join(" ");
129
129
  };
130
- return /* @__PURE__ */ a(
130
+ return /* @__PURE__ */ r(
131
131
  be,
132
132
  {
133
- label: r,
133
+ label: a,
134
134
  hint: e,
135
135
  tooltip: i,
136
136
  name: s,
137
137
  required: h,
138
138
  requiredIndicator: g,
139
139
  loading: Y,
140
- formControl: D,
140
+ formControl: Z,
141
141
  description: R,
142
- controlId: P,
142
+ controlId: D,
143
143
  labelId: se,
144
- descriptionId: A,
145
- hintId: G,
146
- loadingComponent: /* @__PURE__ */ a(ze, { heightClass: pe, helperText: !!f }),
144
+ descriptionId: P,
145
+ hintId: A,
146
+ loadingComponent: /* @__PURE__ */ r(
147
+ ze,
148
+ {
149
+ heightClass: pe,
150
+ helperText: !!f,
151
+ helperTextMarginTop: !0
152
+ }
153
+ ),
147
154
  children: ({ error: t, message: l, onFieldChange: c, onFieldBlur: k, value: U }) => {
148
- T.current = U;
155
+ H.current = U;
149
156
  const E = B(U), W = ee ?? !!(L && u && E), z = p ?? t, S = p === !1 ? void 0 : l, X = z && !S, ve = X || W || (v == null ? void 0 : v.length) || o === "password" && I, q = `${y}-error`, fe = [
157
+ P,
150
158
  A,
151
- G,
152
159
  f ? y : void 0,
153
160
  S ? q : void 0,
154
161
  le
155
162
  ].filter(Boolean).join(" ") || void 0;
156
163
  return /* @__PURE__ */ n(K, { children: [
157
164
  /* @__PURE__ */ n("div", { className: ue(z), children: [
158
- he && /* @__PURE__ */ a("div", { className: "flex items-center pl-3 pr-1 flex-shrink-0 pointer-events-none", children: /* @__PURE__ */ a(
159
- Ze,
165
+ he && /* @__PURE__ */ r("div", { className: "flex items-center pl-3 pr-1 flex-shrink-0 pointer-events-none", children: /* @__PURE__ */ r(
166
+ Me,
160
167
  {
161
- prefixValue: Z,
162
- prefixSecondaryValue: _,
168
+ prefixValue: M,
169
+ prefixSecondaryValue: T,
163
170
  icon: m
164
171
  }
165
172
  ) }),
166
- /* @__PURE__ */ a(
173
+ /* @__PURE__ */ r(
167
174
  "input",
168
175
  {
169
- id: P,
176
+ id: D,
170
177
  type: me,
171
178
  placeholder: x,
172
179
  value: E,
@@ -191,8 +198,8 @@ const J = {
191
198
  {
192
199
  className: `flex items-center pl-1 flex-shrink-0 ${o === "password" && I ? "pr-0" : "pr-3"}`,
193
200
  children: [
194
- /* @__PURE__ */ a(
195
- _e,
201
+ /* @__PURE__ */ r(
202
+ Te,
196
203
  {
197
204
  error: X,
198
205
  defaultValue: E,
@@ -205,30 +212,30 @@ const J = {
205
212
  onTogglePassword: () => oe(!C)
206
213
  }
207
214
  ),
208
- /* @__PURE__ */ a(De, { buttons: v })
215
+ /* @__PURE__ */ r(Ze, { buttons: v })
209
216
  ]
210
217
  }
211
218
  )
212
219
  ] }),
213
- f && /* @__PURE__ */ a(
220
+ f && /* @__PURE__ */ r(
214
221
  "div",
215
222
  {
216
223
  id: y,
217
- className: "text-[length:var(--malachite-font-size-small,13px)] text-left pl-2 text-[var(--malachite-text-dimmed,rgb(161,161,161))]",
224
+ className: "mt-1 text-[length:var(--malachite-font-size-small,13px)] text-left pl-2 text-[var(--malachite-text-dimmed,rgb(161,161,161))]",
218
225
  children: f
219
226
  }
220
227
  ),
221
- /* @__PURE__ */ a(Ee, { id: q, message: S })
228
+ /* @__PURE__ */ r(Ee, { id: q, message: S, spaced: !0 })
222
229
  ] });
223
230
  }
224
231
  }
225
232
  );
226
- }, Ze = ({ prefixValue: r, prefixSecondaryValue: e, icon: i }) => /* @__PURE__ */ n("div", { className: "flex items-center gap-1", children: [
227
- i && /* @__PURE__ */ a("span", { className: "flex items-center justify-center text-[var(--malachite-text-dimmed)] w-4 h-4 flex-shrink-0", children: i }),
228
- r && /* @__PURE__ */ a("span", { className: "text-[length:var(--malachite-font-size-medium,14px)] leading-[1.4] text-[var(--malachite-text-dimmed)] whitespace-nowrap", children: r }),
229
- e && /* @__PURE__ */ a("span", { className: "text-[length:var(--malachite-font-size-medium,14px)] leading-[1.4] text-[var(--malachite-text-dimmed)] whitespace-nowrap", children: e })
230
- ] }), _e = ({
231
- error: r,
233
+ }, Me = ({ prefixValue: a, prefixSecondaryValue: e, icon: i }) => /* @__PURE__ */ n("div", { className: "flex items-center gap-1", children: [
234
+ i && /* @__PURE__ */ r("span", { className: "flex items-center justify-center text-[var(--malachite-text-dimmed)] w-4 h-4 flex-shrink-0", children: i }),
235
+ a && /* @__PURE__ */ r("span", { className: "text-[length:var(--malachite-font-size-medium,14px)] leading-[1.4] text-[var(--malachite-text-dimmed)] whitespace-nowrap", children: a }),
236
+ e && /* @__PURE__ */ r("span", { className: "text-[length:var(--malachite-font-size-medium,14px)] leading-[1.4] text-[var(--malachite-text-dimmed)] whitespace-nowrap", children: e })
237
+ ] }), Te = ({
238
+ error: a,
232
239
  defaultValue: e,
233
240
  onCopyClick: i,
234
241
  showCopyButton: x = !1,
@@ -238,14 +245,14 @@ const J = {
238
245
  showPasswordToggle: g = !0,
239
246
  onTogglePassword: p
240
247
  }) => /* @__PURE__ */ n("div", { className: "flex items-center gap-1", children: [
241
- r && // Decorative: the rejection is carried by the message beneath the field, so
248
+ a && // Decorative: the rejection is carried by the message beneath the field, so
242
249
  // announcing an unnamed icon here would only repeat it as "info".
243
- /* @__PURE__ */ a(
250
+ /* @__PURE__ */ r(
244
251
  "div",
245
252
  {
246
253
  "aria-hidden": "true",
247
254
  className: "flex items-center justify-center w-5 h-5 flex-shrink-0",
248
- children: /* @__PURE__ */ a(
255
+ children: /* @__PURE__ */ r(
249
256
  ke,
250
257
  {
251
258
  size: 16,
@@ -254,35 +261,35 @@ const J = {
254
261
  )
255
262
  }
256
263
  ),
257
- x && i && e && /* @__PURE__ */ a(
264
+ x && i && e && /* @__PURE__ */ r(
258
265
  "button",
259
266
  {
260
267
  onClick: i,
261
268
  type: "button",
262
269
  className: "flex items-center justify-center w-5 h-5 hover:bg-[var(--malachite-primary-border)] rounded transition-colors flex-shrink-0 cursor-pointer",
263
- children: m ? /* @__PURE__ */ a(
270
+ children: m ? /* @__PURE__ */ r(
264
271
  Ie,
265
272
  {
266
273
  size: 16,
267
274
  style: { color: "var(--malachite-success-foreground)" }
268
275
  }
269
- ) : /* @__PURE__ */ a(ye, { size: 16 })
276
+ ) : /* @__PURE__ */ r(ye, { size: 16 })
270
277
  }
271
278
  ),
272
- s === "password" && g && /* @__PURE__ */ a(Q, { variant: "no-style", onClick: p, type: "button", size: "small", children: h ? /* @__PURE__ */ a(
279
+ s === "password" && g && /* @__PURE__ */ r(Q, { variant: "no-style", onClick: p, type: "button", size: "small", children: h ? /* @__PURE__ */ r(
273
280
  Ce,
274
281
  {
275
282
  size: 16,
276
283
  style: { color: "var(--malachite-text-dimmed)" }
277
284
  }
278
- ) : /* @__PURE__ */ a(
285
+ ) : /* @__PURE__ */ r(
279
286
  Ne,
280
287
  {
281
288
  size: 16,
282
289
  style: { color: "var(--malachite-text-dimmed)" }
283
290
  }
284
291
  ) })
285
- ] }), De = ({ buttons: r }) => r != null && r.length ? /* @__PURE__ */ a(K, { children: r.map((e) => /* @__PURE__ */ a(
292
+ ] }), Ze = ({ buttons: a }) => a != null && a.length ? /* @__PURE__ */ r(K, { children: a.map((e) => /* @__PURE__ */ r(
286
293
  Q,
287
294
  {
288
295
  variant: e.variant || (e.danger ? "destructive" : "outline"),
@@ -1 +1 @@
1
- {"version":3,"file":"Input.js","sources":["../../../src/components/Input/Input.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport type { Control, FieldPath, FieldValues } from 'react-hook-form';\nimport BaseFormComponent, { type RequiredIndicator, useFormFieldIds } from '../BaseFormComponent';\nimport { Button } from '../Button';\nimport CheckCircleFilled from '../CustomIcons/CheckCircleFilled';\nimport CopyIcon from '../CustomIcons/CopyIcon';\nimport EyeClosedIcon from '../CustomIcons/EyeClosedIcon';\nimport EyeIcon from '../CustomIcons/EyeIcon';\nimport InfoIcon from '../CustomIcons/InfoIcon';\nimport FieldMessage from '../FieldMessage';\nimport LoadingInput from '../LoadingInput';\nimport { paintedFieldValue } from '../devWarning';\nimport type { ButtonDefinition, InputSize, InputType, InputVariant } from './types';\n\ninterface InputProps {\n label?: string;\n hint?: string;\n tooltip?: string;\n placeholder?: string;\n icon?: React.ReactNode;\n readOnly?: boolean;\n name: FieldPath<FieldValues> | string;\n type?: InputType;\n description?: string;\n size?: InputSize;\n variant?: InputVariant;\n required?: boolean;\n requiredIndicator?: RequiredIndicator;\n error?: boolean;\n loading?: boolean;\n defaultValue?: string;\n disabled?: boolean;\n prefixValue?: string;\n prefixSecondaryValue?: string;\n ellipsis?: boolean;\n formControl?: Control<FieldValues, unknown>;\n buttons?: ButtonDefinition[];\n onCopyClick?: () => void;\n showCopyButton?: boolean;\n onChange?: (value: string) => void;\n /** Controlled value, for a source of truth outside the form (URL, app state). */\n value?: string;\n onBlur?: () => void;\n helperText?: string;\n showPasswordToggle?: boolean;\n id?: string;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n 'aria-describedby'?: string;\n}\n\n// Figma specs one Input, at 42px / px-16 / 15px / radius 14 — the large tier. The smaller\n// tiers have no Input master, so they follow Search, which shares the field chrome.\nconst SIZE_HEIGHT: Record<InputSize, string> = {\n small: 'h-[var(--malachite-control-height-small,28px)]',\n medium: 'h-[var(--malachite-control-height-medium,32px)]',\n large: 'h-[var(--malachite-control-height-large,42px)]',\n};\n\nconst SIZE_TEXT: Record<InputSize, string> = {\n small: 'text-[length:var(--malachite-font-size-small,13px)]',\n medium: 'text-[length:var(--malachite-font-size-small,13px)]',\n large: 'text-[length:var(--malachite-font-size-15,15px)] leading-[1.4]',\n};\n\nconst SIZE_PADDING: Record<InputSize, string> = {\n small: 'px-[10px]',\n medium: 'px-[10px]',\n large: 'px-[16px]',\n};\n\nconst SIZE_RADIUS: Record<InputSize, string> = {\n small: 'rounded-[var(--malachite-radius-10,10px)]',\n medium: 'rounded-xl',\n large: 'rounded-[var(--malachite-radius-xxl,14px)]',\n};\n\nconst getVariantClasses = (\n variant: InputVariant,\n error?: boolean,\n): {\n wrapper: string[];\n shadow: string;\n borderRadius: string;\n} => {\n switch (variant) {\n case 'ghost':\n return {\n wrapper: [\n error\n ? 'border-0 border-b border-solid border-[var(--malachite-destructive-border)]'\n : '',\n error\n ? 'focus-within:border-[var(--malachite-destructive-border-hover)] hover:border-[var(--malachite-destructive-border-hover)]'\n : '',\n ],\n shadow: 'shadow-none',\n borderRadius: 'rounded-none',\n };\n case 'default':\n default:\n return {\n wrapper: [\n 'border border-solid',\n error\n ? 'border-[var(--malachite-destructive-border)]'\n : 'border-[var(--malachite-card-border)]',\n error\n ? 'focus-within:border-[var(--malachite-destructive-border-hover)] hover:border-[var(--malachite-destructive-border-hover)]'\n : 'focus-within:border-[var(--malachite-control-border-hover)] hover:border-[var(--malachite-control-border-hover)]',\n ],\n shadow: error ? 'shadow-error' : 'shadow-default',\n borderRadius: '',\n };\n }\n};\n\nconst Input: React.FC<InputProps> = ({\n label,\n hint,\n tooltip,\n placeholder,\n icon,\n name,\n required,\n requiredIndicator,\n error,\n description,\n loading = false,\n readOnly = false,\n type = 'text',\n size = 'large',\n variant = 'default',\n defaultValue,\n disabled,\n prefixValue,\n prefixSecondaryValue,\n ellipsis = false,\n formControl,\n buttons,\n onCopyClick,\n showCopyButton,\n onChange,\n value,\n onBlur,\n helperText,\n showPasswordToggle = true,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n}) => {\n const { controlId, labelId, descriptionId, hintId, helperTextId } = useFormFieldIds({\n id,\n label,\n description,\n hint,\n helperText: true,\n });\n const [showPassword, setShowPassword] = useState(false);\n const [inputValue, setInputValue] = useState(defaultValue || '');\n const [copied, setCopied] = useState(false);\n\n useEffect(() => {\n if (copied) {\n const timer = setTimeout(() => {\n setCopied(false);\n }, 1000);\n return () => clearTimeout(timer);\n }\n }, [copied]);\n\n const handleChange =\n (reportToForm?: (value: unknown) => void) => (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n setInputValue(newValue);\n onChange?.(newValue);\n reportToForm?.(newValue);\n };\n\n const formValueRef = useRef<unknown>(undefined);\n const paintedValue = (formValue: unknown): string =>\n paintedFieldValue({\n component: 'Input',\n name,\n value,\n formValue,\n defaultValue,\n bound: !!formControl,\n uncontrolledValue: inputValue,\n });\n\n const handleCopyClick = onCopyClick\n ? () => {\n const copyValue = paintedValue(formValueRef.current);\n if (copyValue) {\n navigator.clipboard.writeText(copyValue);\n setCopied(true);\n onCopyClick();\n }\n }\n : undefined;\n\n const actualInputType = type === 'password' ? (showPassword ? 'text' : 'password') : type;\n\n const hasPrefix = icon || prefixValue || prefixSecondaryValue;\n\n // The skeleton stands in for the field, so it reads the same height the wrapper does.\n const heightClass = SIZE_HEIGHT[size];\n\n const buildWrapperClasses = (isError: boolean): string => {\n const variantStyles = getVariantClasses(variant, isError);\n\n return [\n 'relative',\n 'flex items-center',\n 'w-full',\n variantStyles.borderRadius || SIZE_RADIUS[size],\n disabled\n ? 'bg-[var(--malachite-card-dimmed-background)]'\n : 'bg-[var(--malachite-card-background)]',\n 'transition-colors duration-200 ease-in-out',\n variantStyles.shadow,\n ...(disabled ? [] : variantStyles.wrapper),\n SIZE_HEIGHT[size],\n ]\n .filter(Boolean)\n .join(' ');\n };\n\n return (\n <BaseFormComponent\n label={label}\n hint={hint}\n tooltip={tooltip}\n name={name}\n required={required}\n requiredIndicator={requiredIndicator}\n loading={loading}\n formControl={formControl}\n description={description}\n controlId={controlId}\n labelId={labelId}\n descriptionId={descriptionId}\n hintId={hintId}\n loadingComponent={<LoadingInput heightClass={heightClass} helperText={!!helperText} />}\n >\n {({ error: fieldError, message, onFieldChange, onFieldBlur, value: formValue }) => {\n formValueRef.current = formValue;\n const displayValue = paintedValue(formValue);\n const shouldShowCopyButton =\n showCopyButton ?? !!(handleCopyClick && disabled && displayValue);\n const isError = error ?? fieldError;\n // `error={false}` opts out of the resolver entirely, message included: a\n // screen that has dealt with the rejection its own way would otherwise keep\n // reporting it in destructive text and through `aria-describedby`.\n // The message is its own line rather than a replacement for the helper text:\n // a field that explains where to find its value still has to say why what was\n // typed was rejected, and dropping one for the other left the field marked red\n // with nothing anywhere saying what was wrong.\n const errorMessage = error === false ? undefined : message;\n // The icon is the only signal a consumer-forced `error` has; beside a message it\n // is duplication, and it crowds the suffix next to a reveal or copy control.\n const showErrorIcon = isError && !errorMessage;\n const hasSuffix =\n showErrorIcon ||\n shouldShowCopyButton ||\n buttons?.length ||\n (type === 'password' && showPasswordToggle);\n const errorMessageId = `${helperTextId}-error`;\n const describedBy =\n [\n descriptionId,\n hintId,\n helperText ? helperTextId : undefined,\n errorMessage ? errorMessageId : undefined,\n ariaDescribedBy,\n ]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return (\n <>\n <div className={buildWrapperClasses(isError)}>\n {hasPrefix && (\n <div className=\"flex items-center pl-3 pr-1 flex-shrink-0 pointer-events-none\">\n <CompositeIcon\n prefixValue={prefixValue}\n prefixSecondaryValue={prefixSecondaryValue}\n icon={icon}\n />\n </div>\n )}\n\n <input\n id={controlId}\n type={actualInputType}\n placeholder={placeholder}\n value={displayValue}\n onChange={handleChange(onFieldChange)}\n onBlur={() => {\n onBlur?.();\n onFieldBlur?.();\n }}\n disabled={disabled || readOnly}\n readOnly={readOnly}\n autoComplete=\"off\"\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-invalid={isError || undefined}\n aria-required={required || undefined}\n aria-describedby={describedBy}\n className={`flex-1 bg-transparent border-none outline-none text-[var(--malachite-text-primary)] placeholder:text-[var(--malachite-text-placeholder)] disabled:text-[var(--malachite-text-primary)] disabled:cursor-not-allowed ${SIZE_TEXT[size]} ${SIZE_PADDING[size]} ${ellipsis ? 'min-w-0 truncate' : ''}`}\n name={name}\n />\n\n {hasSuffix && (\n <div\n className={`flex items-center pl-1 flex-shrink-0 ${type === 'password' && showPasswordToggle ? 'pr-0' : 'pr-3'}`}\n >\n <Suffix\n error={showErrorIcon}\n defaultValue={displayValue}\n onCopyClick={handleCopyClick}\n showCopyButton={shouldShowCopyButton}\n copied={copied}\n type={type}\n showPassword={showPassword}\n showPasswordToggle={showPasswordToggle}\n onTogglePassword={() => setShowPassword(!showPassword)}\n />\n <InputButtons buttons={buttons} />\n </div>\n )}\n </div>\n {helperText && (\n <div\n id={helperTextId}\n className=\"text-[length:var(--malachite-font-size-small,13px)] text-left pl-2 text-[var(--malachite-text-dimmed,rgb(161,161,161))]\"\n >\n {helperText}\n </div>\n )}\n <FieldMessage id={errorMessageId} message={errorMessage} />\n </>\n );\n }}\n </BaseFormComponent>\n );\n};\n\nconst CompositeIcon: React.FC<{\n prefixValue?: string;\n prefixSecondaryValue?: string;\n icon?: React.ReactNode;\n}> = ({ prefixValue, prefixSecondaryValue, icon }) => {\n return (\n <div className=\"flex items-center gap-1\">\n {icon && (\n <span className=\"flex items-center justify-center text-[var(--malachite-text-dimmed)] w-4 h-4 flex-shrink-0\">\n {icon}\n </span>\n )}\n {prefixValue && (\n <span className=\"text-[length:var(--malachite-font-size-medium,14px)] leading-[1.4] text-[var(--malachite-text-dimmed)] whitespace-nowrap\">\n {prefixValue}\n </span>\n )}\n {prefixSecondaryValue && (\n <span className=\"text-[length:var(--malachite-font-size-medium,14px)] leading-[1.4] text-[var(--malachite-text-dimmed)] whitespace-nowrap\">\n {prefixSecondaryValue}\n </span>\n )}\n </div>\n );\n};\n\nconst Suffix: React.FC<{\n error?: boolean;\n defaultValue?: string;\n onCopyClick?: () => void;\n showCopyButton?: boolean;\n copied?: boolean;\n type?: InputType;\n showPassword?: boolean;\n showPasswordToggle?: boolean;\n onTogglePassword?: () => void;\n}> = ({\n error,\n defaultValue,\n onCopyClick,\n showCopyButton = false,\n copied = false,\n type,\n showPassword,\n showPasswordToggle = true,\n onTogglePassword,\n}) => {\n return (\n <div className=\"flex items-center gap-1\">\n {error && (\n // Decorative: the rejection is carried by the message beneath the field, so\n // announcing an unnamed icon here would only repeat it as \"info\".\n <div\n aria-hidden=\"true\"\n className=\"flex items-center justify-center w-5 h-5 flex-shrink-0\"\n >\n <InfoIcon\n size={16}\n className=\"text-[var(--malachite-destructive-foreground,rgb(196,62,62))]\"\n />\n </div>\n )}\n {showCopyButton && onCopyClick && defaultValue && (\n <button\n onClick={onCopyClick}\n type=\"button\"\n className=\"flex items-center justify-center w-5 h-5 hover:bg-[var(--malachite-primary-border)] rounded transition-colors flex-shrink-0 cursor-pointer\"\n >\n {copied ? (\n <CheckCircleFilled\n size={16}\n style={{ color: 'var(--malachite-success-foreground)' }}\n />\n ) : (\n <CopyIcon size={16} />\n )}\n </button>\n )}\n {type === 'password' && showPasswordToggle && (\n <Button variant=\"no-style\" onClick={onTogglePassword} type=\"button\" size=\"small\">\n {showPassword ? (\n <EyeClosedIcon\n size={16}\n style={{ color: 'var(--malachite-text-dimmed)' }}\n />\n ) : (\n <EyeIcon\n size={16}\n style={{ color: 'var(--malachite-text-dimmed)' }}\n />\n )}\n </Button>\n )}\n </div>\n );\n};\n\nconst InputButtons: React.FC<{\n buttons?: ButtonDefinition[];\n}> = ({ buttons }) => {\n if (!buttons?.length) {\n return null;\n }\n\n return (\n <>\n {buttons.map((button) => (\n <Button\n key={button.label}\n variant={button.variant || (button.danger ? 'destructive' : 'outline')}\n size={button.size || 'small'}\n disabled={button.disabled}\n icon={button.icon}\n tooltip={button.tooltip}\n onClick={button.onClick}\n className=\"ml-1\"\n >\n {button.label}\n </Button>\n ))}\n </>\n );\n};\n\nexport default Input;\n"],"names":["SIZE_HEIGHT","SIZE_TEXT","SIZE_PADDING","SIZE_RADIUS","getVariantClasses","variant","error","Input","label","hint","tooltip","placeholder","icon","name","required","requiredIndicator","description","loading","readOnly","type","size","defaultValue","disabled","prefixValue","prefixSecondaryValue","ellipsis","formControl","buttons","onCopyClick","showCopyButton","onChange","value","onBlur","helperText","showPasswordToggle","id","ariaLabel","ariaLabelledBy","ariaDescribedBy","controlId","labelId","descriptionId","hintId","helperTextId","useFormFieldIds","showPassword","setShowPassword","useState","inputValue","setInputValue","copied","setCopied","useEffect","timer","handleChange","reportToForm","e","newValue","formValueRef","useRef","paintedValue","formValue","paintedFieldValue","handleCopyClick","copyValue","actualInputType","hasPrefix","heightClass","buildWrapperClasses","isError","variantStyles","jsx","BaseFormComponent","LoadingInput","fieldError","message","onFieldChange","onFieldBlur","displayValue","shouldShowCopyButton","errorMessage","showErrorIcon","hasSuffix","errorMessageId","describedBy","jsxs","Fragment","CompositeIcon","Suffix","InputButtons","FieldMessage","onTogglePassword","InfoIcon","CheckCircleFilled","CopyIcon","Button","EyeClosedIcon","EyeIcon","button"],"mappings":";;;;;;;;;;;;AAqDA,MAAMA,IAAyC;AAAA,EAC3C,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AACX,GAEMC,KAAuC;AAAA,EACzC,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AACX,GAEMC,KAA0C;AAAA,EAC5C,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AACX,GAEMC,KAAyC;AAAA,EAC3C,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AACX,GAEMC,KAAoB,CACtBC,GACAC,MAKC;AACD,UAAQD,GAAA;AAAA,IACJ,KAAK;AACD,aAAO;AAAA,QACH,SAAS;AAAA,UACLC,IACM,iFACA;AAAA,UACNA,IACM,6HACA;AAAA,QAAA;AAAA,QAEV,QAAQ;AAAA,QACR,cAAc;AAAA,MAAA;AAAA,IAEtB,KAAK;AAAA,IACL;AACI,aAAO;AAAA,QACH,SAAS;AAAA,UACL;AAAA,UACAA,IACM,iDACA;AAAA,UACNA,IACM,6HACA;AAAA,QAAA;AAAA,QAEV,QAAQA,IAAQ,iBAAiB;AAAA,QACjC,cAAc;AAAA,MAAA;AAAA,EAClB;AAEZ,GAEMC,KAA8B,CAAC;AAAA,EACjC,OAAAC;AAAA,EACA,MAAAC;AAAA,EACA,SAAAC;AAAA,EACA,aAAAC;AAAA,EACA,MAAAC;AAAA,EACA,MAAAC;AAAA,EACA,UAAAC;AAAA,EACA,mBAAAC;AAAA,EACA,OAAAT;AAAA,EACA,aAAAU;AAAA,EACA,SAAAC,IAAU;AAAA,EACV,UAAAC,IAAW;AAAA,EACX,MAAAC,IAAO;AAAA,EACP,MAAAC,IAAO;AAAA,EACP,SAAAf,IAAU;AAAA,EACV,cAAAgB;AAAA,EACA,UAAAC;AAAA,EACA,aAAAC;AAAA,EACA,sBAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,aAAAC;AAAA,EACA,SAAAC;AAAA,EACA,aAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,UAAAC;AAAA,EACA,OAAAC;AAAA,EACA,QAAAC;AAAA,EACA,YAAAC;AAAA,EACA,oBAAAC,IAAqB;AAAA,EACrB,IAAAC;AAAA,EACA,cAAcC;AAAA,EACd,mBAAmBC;AAAA,EACnB,oBAAoBC;AACxB,MAAM;AACF,QAAM,EAAE,WAAAC,GAAW,SAAAC,IAAS,eAAAC,GAAe,QAAAC,GAAQ,cAAAC,EAAA,IAAiBC,GAAgB;AAAA,IAChF,IAAAT;AAAA,IACA,OAAA3B;AAAA,IACA,aAAAQ;AAAA,IACA,MAAAP;AAAA,IACA,YAAY;AAAA,EAAA,CACf,GACK,CAACoC,GAAcC,EAAe,IAAIC,EAAS,EAAK,GAChD,CAACC,IAAYC,EAAa,IAAIF,EAAS1B,KAAgB,EAAE,GACzD,CAAC6B,GAAQC,CAAS,IAAIJ,EAAS,EAAK;AAE1C,EAAAK,GAAU,MAAM;AACZ,QAAIF,GAAQ;AACR,YAAMG,IAAQ,WAAW,MAAM;AAC3B,QAAAF,EAAU,EAAK;AAAA,MACnB,GAAG,GAAI;AACP,aAAO,MAAM,aAAaE,CAAK;AAAA,IACnC;AAAA,EACJ,GAAG,CAACH,CAAM,CAAC;AAEX,QAAMI,KACF,CAACC,MAA4C,CAACC,MAA2C;AACrF,UAAMC,IAAWD,EAAE,OAAO;AAC1B,IAAAP,GAAcQ,CAAQ,GACtB3B,KAAA,QAAAA,EAAW2B,IACXF,KAAA,QAAAA,EAAeE;AAAA,EACnB,GAEEC,IAAeC,GAAgB,MAAS,GACxCC,IAAe,CAACC,MAClBC,GAAkB;AAAA,IACd,WAAW;AAAA,IACX,MAAAjD;AAAA,IACA,OAAAkB;AAAA,IACA,WAAA8B;AAAA,IACA,cAAAxC;AAAA,IACA,OAAO,CAAC,CAACK;AAAA,IACT,mBAAmBsB;AAAA,EAAA,CACtB,GAECe,IAAkBnC,IAClB,MAAM;AACF,UAAMoC,IAAYJ,EAAaF,EAAa,OAAO;AACnD,IAAIM,MACA,UAAU,UAAU,UAAUA,CAAS,GACvCb,EAAU,EAAI,GACdvB,EAAA;AAAA,EAER,IACA,QAEAqC,KAAkB9C,MAAS,aAAc0B,IAAe,SAAS,aAAc1B,GAE/E+C,KAAYtD,KAAQW,KAAeC,GAGnC2C,KAAcnE,EAAYoB,CAAI,GAE9BgD,KAAsB,CAACC,MAA6B;AACtD,UAAMC,IAAgBlE,GAAkBC,GAASgE,CAAO;AAExD,WAAO;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACAC,EAAc,gBAAgBnE,GAAYiB,CAAI;AAAA,MAC9CE,IACM,iDACA;AAAA,MACN;AAAA,MACAgD,EAAc;AAAA,MACd,GAAIhD,IAAW,KAAKgD,EAAc;AAAA,MAClCtE,EAAYoB,CAAI;AAAA,IAAA,EAEf,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,EACjB;AAEA,SACI,gBAAAmD;AAAA,IAACC;AAAA,IAAA;AAAA,MACG,OAAAhE;AAAA,MACA,MAAAC;AAAA,MACA,SAAAC;AAAA,MACA,MAAAG;AAAA,MACA,UAAAC;AAAA,MACA,mBAAAC;AAAA,MACA,SAAAE;AAAA,MACA,aAAAS;AAAA,MACA,aAAAV;AAAA,MACA,WAAAuB;AAAA,MACA,SAAAC;AAAA,MACA,eAAAC;AAAA,MACA,QAAAC;AAAA,MACA,kBAAkB,gBAAA6B,EAACE,IAAA,EAAa,aAAAN,IAA0B,YAAY,CAAC,CAAClC,GAAY;AAAA,MAEnF,UAAA,CAAC,EAAE,OAAOyC,GAAY,SAAAC,GAAS,eAAAC,GAAe,aAAAC,GAAa,OAAOhB,QAAgB;AAC/E,QAAAH,EAAa,UAAUG;AACvB,cAAMiB,IAAelB,EAAaC,CAAS,GACrCkB,IACFlD,MAAkB,CAAC,EAAEkC,KAAmBzC,KAAYwD,IAClDT,IAAU/D,KAASoE,GAQnBM,IAAe1E,MAAU,KAAQ,SAAYqE,GAG7CM,IAAgBZ,KAAW,CAACW,GAC5BE,KACFD,KACAF,MACApD,KAAA,gBAAAA,EAAS,WACRR,MAAS,cAAce,GACtBiD,IAAiB,GAAGxC,CAAY,UAChCyC,KACF;AAAA,UACI3C;AAAA,UACAC;AAAA,UACAT,IAAaU,IAAe;AAAA,UAC5BqC,IAAeG,IAAiB;AAAA,UAChC7C;AAAA,QAAA,EAEC,OAAO,OAAO,EACd,KAAK,GAAG,KAAK;AAEtB,eACI,gBAAA+C,EAAAC,GAAA,EACI,UAAA;AAAA,UAAA,gBAAAD,EAAC,OAAA,EAAI,WAAWjB,GAAoBC,CAAO,GACtC,UAAA;AAAA,YAAAH,MACG,gBAAAK,EAAC,OAAA,EAAI,WAAU,iEACX,UAAA,gBAAAA;AAAA,cAACgB;AAAA,cAAA;AAAA,gBACG,aAAAhE;AAAA,gBACA,sBAAAC;AAAA,gBACA,MAAAZ;AAAA,cAAA;AAAA,YAAA,GAER;AAAA,YAGJ,gBAAA2D;AAAA,cAAC;AAAA,cAAA;AAAA,gBACG,IAAIhC;AAAA,gBACJ,MAAM0B;AAAA,gBACN,aAAAtD;AAAA,gBACA,OAAOmE;AAAA,gBACP,UAAUxB,GAAasB,CAAa;AAAA,gBACpC,QAAQ,MAAM;AACV,kBAAA5C,KAAA,QAAAA,KACA6C,KAAA,QAAAA;AAAA,gBACJ;AAAA,gBACA,UAAUvD,KAAYJ;AAAA,gBACtB,UAAAA;AAAA,gBACA,cAAa;AAAA,gBACb,cAAYkB;AAAA,gBACZ,mBAAiBC;AAAA,gBACjB,gBAAcgC,KAAW;AAAA,gBACzB,iBAAevD,KAAY;AAAA,gBAC3B,oBAAkBsE;AAAA,gBAClB,WAAW,sNAAsNnF,GAAUmB,CAAI,CAAC,IAAIlB,GAAakB,CAAI,CAAC,IAAIK,IAAW,qBAAqB,EAAE;AAAA,gBAC5S,MAAAZ;AAAA,cAAA;AAAA,YAAA;AAAA,YAGHqE,MACG,gBAAAG;AAAA,cAAC;AAAA,cAAA;AAAA,gBACG,WAAW,wCAAwClE,MAAS,cAAce,IAAqB,SAAS,MAAM;AAAA,gBAE9G,UAAA;AAAA,kBAAA,gBAAAqC;AAAA,oBAACiB;AAAA,oBAAA;AAAA,sBACG,OAAOP;AAAA,sBACP,cAAcH;AAAA,sBACd,aAAaf;AAAA,sBACb,gBAAgBgB;AAAA,sBAChB,QAAA7B;AAAA,sBACA,MAAA/B;AAAA,sBACA,cAAA0B;AAAA,sBACA,oBAAAX;AAAA,sBACA,kBAAkB,MAAMY,GAAgB,CAACD,CAAY;AAAA,oBAAA;AAAA,kBAAA;AAAA,kBAEzD,gBAAA0B,EAACkB,MAAa,SAAA9D,EAAA,CAAkB;AAAA,gBAAA;AAAA,cAAA;AAAA,YAAA;AAAA,UACpC,GAER;AAAA,UACCM,KACG,gBAAAsC;AAAA,YAAC;AAAA,YAAA;AAAA,cACG,IAAI5B;AAAA,cACJ,WAAU;AAAA,cAET,UAAAV;AAAA,YAAA;AAAA,UAAA;AAAA,UAGT,gBAAAsC,EAACmB,IAAA,EAAa,IAAIP,GAAgB,SAASH,EAAA,CAAc;AAAA,QAAA,GAC7D;AAAA,MAER;AAAA,IAAA;AAAA,EAAA;AAGZ,GAEMO,KAID,CAAC,EAAE,aAAAhE,GAAa,sBAAAC,GAAsB,MAAAZ,QAEnC,gBAAAyE,EAAC,OAAA,EAAI,WAAU,2BACV,UAAA;AAAA,EAAAzE,KACG,gBAAA2D,EAAC,QAAA,EAAK,WAAU,8FACX,UAAA3D,GACL;AAAA,EAEHW,KACG,gBAAAgD,EAAC,QAAA,EAAK,WAAU,4HACX,UAAAhD,GACL;AAAA,EAEHC,KACG,gBAAA+C,EAAC,QAAA,EAAK,WAAU,4HACX,UAAA/C,EAAA,CACL;AAAA,GAER,GAIFgE,KAUD,CAAC;AAAA,EACF,OAAAlF;AAAA,EACA,cAAAe;AAAA,EACA,aAAAO;AAAA,EACA,gBAAAC,IAAiB;AAAA,EACjB,QAAAqB,IAAS;AAAA,EACT,MAAA/B;AAAA,EACA,cAAA0B;AAAA,EACA,oBAAAX,IAAqB;AAAA,EACrB,kBAAAyD;AACJ,MAEQ,gBAAAN,EAAC,OAAA,EAAI,WAAU,2BACV,UAAA;AAAA,EAAA/E;AAAA;AAAA,EAGG,gBAAAiE;AAAA,IAAC;AAAA,IAAA;AAAA,MACG,eAAY;AAAA,MACZ,WAAU;AAAA,MAEV,UAAA,gBAAAA;AAAA,QAACqB;AAAA,QAAA;AAAA,UACG,MAAM;AAAA,UACN,WAAU;AAAA,QAAA;AAAA,MAAA;AAAA,IACd;AAAA,EAAA;AAAA,EAGP/D,KAAkBD,KAAeP,KAC9B,gBAAAkD;AAAA,IAAC;AAAA,IAAA;AAAA,MACG,SAAS3C;AAAA,MACT,MAAK;AAAA,MACL,WAAU;AAAA,MAET,UAAAsB,IACG,gBAAAqB;AAAA,QAACsB;AAAA,QAAA;AAAA,UACG,MAAM;AAAA,UACN,OAAO,EAAE,OAAO,sCAAA;AAAA,QAAsC;AAAA,MAAA,IAG1D,gBAAAtB,EAACuB,IAAA,EAAS,MAAM,GAAA,CAAI;AAAA,IAAA;AAAA,EAAA;AAAA,EAI/B3E,MAAS,cAAce,KACpB,gBAAAqC,EAACwB,GAAA,EAAO,SAAQ,YAAW,SAASJ,GAAkB,MAAK,UAAS,MAAK,SACpE,UAAA9C,IACG,gBAAA0B;AAAA,IAACyB;AAAA,IAAA;AAAA,MACG,MAAM;AAAA,MACN,OAAO,EAAE,OAAO,+BAAA;AAAA,IAA+B;AAAA,EAAA,IAGnD,gBAAAzB;AAAA,IAAC0B;AAAA,IAAA;AAAA,MACG,MAAM;AAAA,MACN,OAAO,EAAE,OAAO,+BAAA;AAAA,IAA+B;AAAA,EAAA,EACnD,CAER;AAAA,GAER,GAIFR,KAED,CAAC,EAAE,SAAA9D,QACCA,KAAA,QAAAA,EAAS,SAKV,gBAAA4C,EAAAe,GAAA,EACK,UAAA3D,EAAQ,IAAI,CAACuE,MACV,gBAAA3B;AAAA,EAACwB;AAAA,EAAA;AAAA,IAEG,SAASG,EAAO,YAAYA,EAAO,SAAS,gBAAgB;AAAA,IAC5D,MAAMA,EAAO,QAAQ;AAAA,IACrB,UAAUA,EAAO;AAAA,IACjB,MAAMA,EAAO;AAAA,IACb,SAASA,EAAO;AAAA,IAChB,SAASA,EAAO;AAAA,IAChB,WAAU;AAAA,IAET,UAAAA,EAAO;AAAA,EAAA;AAAA,EATHA,EAAO;AAAA,CAWnB,GACL,IAnBO;"}
1
+ {"version":3,"file":"Input.js","sources":["../../../src/components/Input/Input.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport type { Control, FieldPath, FieldValues } from 'react-hook-form';\nimport BaseFormComponent, { type RequiredIndicator, useFormFieldIds } from '../BaseFormComponent';\nimport { Button } from '../Button';\nimport CheckCircleFilled from '../CustomIcons/CheckCircleFilled';\nimport CopyIcon from '../CustomIcons/CopyIcon';\nimport EyeClosedIcon from '../CustomIcons/EyeClosedIcon';\nimport EyeIcon from '../CustomIcons/EyeIcon';\nimport InfoIcon from '../CustomIcons/InfoIcon';\nimport FieldMessage from '../FieldMessage';\nimport LoadingInput from '../LoadingInput';\nimport { paintedFieldValue } from '../devWarning';\nimport type { ButtonDefinition, InputSize, InputType, InputVariant } from './types';\n\ninterface InputProps {\n label?: string;\n hint?: string;\n tooltip?: string;\n placeholder?: string;\n icon?: React.ReactNode;\n readOnly?: boolean;\n name: FieldPath<FieldValues> | string;\n type?: InputType;\n description?: string;\n size?: InputSize;\n variant?: InputVariant;\n required?: boolean;\n requiredIndicator?: RequiredIndicator;\n error?: boolean;\n loading?: boolean;\n defaultValue?: string;\n disabled?: boolean;\n prefixValue?: string;\n prefixSecondaryValue?: string;\n ellipsis?: boolean;\n formControl?: Control<FieldValues, unknown>;\n buttons?: ButtonDefinition[];\n onCopyClick?: () => void;\n showCopyButton?: boolean;\n onChange?: (value: string) => void;\n /** Controlled value, for a source of truth outside the form (URL, app state). */\n value?: string;\n onBlur?: () => void;\n helperText?: React.ReactNode;\n showPasswordToggle?: boolean;\n id?: string;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n 'aria-describedby'?: string;\n}\n\n// Figma specs one Input, at 42px / px-16 / 15px / radius 14 — the large tier. The smaller\n// tiers have no Input master, so they follow Search, which shares the field chrome.\nconst SIZE_HEIGHT: Record<InputSize, string> = {\n small: 'h-[var(--malachite-control-height-small,28px)]',\n medium: 'h-[var(--malachite-control-height-medium,32px)]',\n large: 'h-[var(--malachite-control-height-large,42px)]',\n};\n\nconst SIZE_TEXT: Record<InputSize, string> = {\n small: 'text-[length:var(--malachite-font-size-small,13px)]',\n medium: 'text-[length:var(--malachite-font-size-small,13px)]',\n large: 'text-[length:var(--malachite-font-size-15,15px)] leading-[1.4]',\n};\n\nconst SIZE_PADDING: Record<InputSize, string> = {\n small: 'px-[10px]',\n medium: 'px-[10px]',\n large: 'px-[16px]',\n};\n\nconst SIZE_RADIUS: Record<InputSize, string> = {\n small: 'rounded-[var(--malachite-radius-10,10px)]',\n medium: 'rounded-xl',\n large: 'rounded-[var(--malachite-radius-xxl,14px)]',\n};\n\nconst getVariantClasses = (\n variant: InputVariant,\n error?: boolean,\n): {\n wrapper: string[];\n shadow: string;\n borderRadius: string;\n} => {\n switch (variant) {\n case 'ghost':\n return {\n wrapper: [\n error\n ? 'border-0 border-b border-solid border-[var(--malachite-destructive-border)]'\n : '',\n error\n ? 'focus-within:border-[var(--malachite-destructive-border-hover)] hover:border-[var(--malachite-destructive-border-hover)]'\n : '',\n ],\n shadow: 'shadow-none',\n borderRadius: 'rounded-none',\n };\n case 'default':\n default:\n return {\n wrapper: [\n 'border border-solid',\n error\n ? 'border-[var(--malachite-destructive-border)]'\n : 'border-[var(--malachite-card-border)]',\n error\n ? 'focus-within:border-[var(--malachite-destructive-border-hover)] hover:border-[var(--malachite-destructive-border-hover)]'\n : 'focus-within:border-[var(--malachite-control-border-hover)] hover:border-[var(--malachite-control-border-hover)]',\n ],\n shadow: error ? 'shadow-error' : 'shadow-default',\n borderRadius: '',\n };\n }\n};\n\nconst Input: React.FC<InputProps> = ({\n label,\n hint,\n tooltip,\n placeholder,\n icon,\n name,\n required,\n requiredIndicator,\n error,\n description,\n loading = false,\n readOnly = false,\n type = 'text',\n size = 'large',\n variant = 'default',\n defaultValue,\n disabled,\n prefixValue,\n prefixSecondaryValue,\n ellipsis = false,\n formControl,\n buttons,\n onCopyClick,\n showCopyButton,\n onChange,\n value,\n onBlur,\n helperText,\n showPasswordToggle = true,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n}) => {\n const { controlId, labelId, descriptionId, hintId, helperTextId } = useFormFieldIds({\n id,\n label,\n description,\n hint,\n helperText: true,\n });\n const [showPassword, setShowPassword] = useState(false);\n const [inputValue, setInputValue] = useState(defaultValue || '');\n const [copied, setCopied] = useState(false);\n\n useEffect(() => {\n if (copied) {\n const timer = setTimeout(() => {\n setCopied(false);\n }, 1000);\n return () => clearTimeout(timer);\n }\n }, [copied]);\n\n const handleChange =\n (reportToForm?: (value: unknown) => void) => (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n setInputValue(newValue);\n onChange?.(newValue);\n reportToForm?.(newValue);\n };\n\n const formValueRef = useRef<unknown>(undefined);\n const paintedValue = (formValue: unknown): string =>\n paintedFieldValue({\n component: 'Input',\n name,\n value,\n formValue,\n defaultValue,\n bound: !!formControl,\n uncontrolledValue: inputValue,\n });\n\n const handleCopyClick = onCopyClick\n ? () => {\n const copyValue = paintedValue(formValueRef.current);\n if (copyValue) {\n navigator.clipboard.writeText(copyValue);\n setCopied(true);\n onCopyClick();\n }\n }\n : undefined;\n\n const actualInputType = type === 'password' ? (showPassword ? 'text' : 'password') : type;\n\n const hasPrefix = icon || prefixValue || prefixSecondaryValue;\n\n // The skeleton stands in for the field, so it reads the same height the wrapper does.\n const heightClass = SIZE_HEIGHT[size];\n\n const buildWrapperClasses = (isError: boolean): string => {\n const variantStyles = getVariantClasses(variant, isError);\n\n return [\n 'relative',\n 'flex items-center',\n 'w-full',\n variantStyles.borderRadius || SIZE_RADIUS[size],\n disabled\n ? 'bg-[var(--malachite-card-dimmed-background)]'\n : 'bg-[var(--malachite-card-background)]',\n 'transition-colors duration-200 ease-in-out',\n variantStyles.shadow,\n ...(disabled ? [] : variantStyles.wrapper),\n SIZE_HEIGHT[size],\n ]\n .filter(Boolean)\n .join(' ');\n };\n\n return (\n <BaseFormComponent\n label={label}\n hint={hint}\n tooltip={tooltip}\n name={name}\n required={required}\n requiredIndicator={requiredIndicator}\n loading={loading}\n formControl={formControl}\n description={description}\n controlId={controlId}\n labelId={labelId}\n descriptionId={descriptionId}\n hintId={hintId}\n loadingComponent={\n <LoadingInput\n heightClass={heightClass}\n helperText={!!helperText}\n helperTextMarginTop\n />\n }\n >\n {({ error: fieldError, message, onFieldChange, onFieldBlur, value: formValue }) => {\n formValueRef.current = formValue;\n const displayValue = paintedValue(formValue);\n const shouldShowCopyButton =\n showCopyButton ?? !!(handleCopyClick && disabled && displayValue);\n const isError = error ?? fieldError;\n // `error={false}` opts out of the resolver entirely, message included: a\n // screen that has dealt with the rejection its own way would otherwise keep\n // reporting it in destructive text and through `aria-describedby`.\n // The message is its own line rather than a replacement for the helper text:\n // a field that explains where to find its value still has to say why what was\n // typed was rejected, and dropping one for the other left the field marked red\n // with nothing anywhere saying what was wrong.\n const errorMessage = error === false ? undefined : message;\n // The icon is the only signal a consumer-forced `error` has; beside a message it\n // is duplication, and it crowds the suffix next to a reveal or copy control.\n const showErrorIcon = isError && !errorMessage;\n const hasSuffix =\n showErrorIcon ||\n shouldShowCopyButton ||\n buttons?.length ||\n (type === 'password' && showPasswordToggle);\n const errorMessageId = `${helperTextId}-error`;\n const describedBy =\n [\n descriptionId,\n hintId,\n helperText ? helperTextId : undefined,\n errorMessage ? errorMessageId : undefined,\n ariaDescribedBy,\n ]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return (\n <>\n <div className={buildWrapperClasses(isError)}>\n {hasPrefix && (\n <div className=\"flex items-center pl-3 pr-1 flex-shrink-0 pointer-events-none\">\n <CompositeIcon\n prefixValue={prefixValue}\n prefixSecondaryValue={prefixSecondaryValue}\n icon={icon}\n />\n </div>\n )}\n\n <input\n id={controlId}\n type={actualInputType}\n placeholder={placeholder}\n value={displayValue}\n onChange={handleChange(onFieldChange)}\n onBlur={() => {\n onBlur?.();\n onFieldBlur?.();\n }}\n disabled={disabled || readOnly}\n readOnly={readOnly}\n autoComplete=\"off\"\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-invalid={isError || undefined}\n aria-required={required || undefined}\n aria-describedby={describedBy}\n className={`flex-1 bg-transparent border-none outline-none text-[var(--malachite-text-primary)] placeholder:text-[var(--malachite-text-placeholder)] disabled:text-[var(--malachite-text-primary)] disabled:cursor-not-allowed ${SIZE_TEXT[size]} ${SIZE_PADDING[size]} ${ellipsis ? 'min-w-0 truncate' : ''}`}\n name={name}\n />\n\n {hasSuffix && (\n <div\n className={`flex items-center pl-1 flex-shrink-0 ${type === 'password' && showPasswordToggle ? 'pr-0' : 'pr-3'}`}\n >\n <Suffix\n error={showErrorIcon}\n defaultValue={displayValue}\n onCopyClick={handleCopyClick}\n showCopyButton={shouldShowCopyButton}\n copied={copied}\n type={type}\n showPassword={showPassword}\n showPasswordToggle={showPasswordToggle}\n onTogglePassword={() => setShowPassword(!showPassword)}\n />\n <InputButtons buttons={buttons} />\n </div>\n )}\n </div>\n {helperText && (\n <div\n id={helperTextId}\n className=\"mt-1 text-[length:var(--malachite-font-size-small,13px)] text-left pl-2 text-[var(--malachite-text-dimmed,rgb(161,161,161))]\"\n >\n {helperText}\n </div>\n )}\n <FieldMessage id={errorMessageId} message={errorMessage} spaced />\n </>\n );\n }}\n </BaseFormComponent>\n );\n};\n\nconst CompositeIcon: React.FC<{\n prefixValue?: string;\n prefixSecondaryValue?: string;\n icon?: React.ReactNode;\n}> = ({ prefixValue, prefixSecondaryValue, icon }) => {\n return (\n <div className=\"flex items-center gap-1\">\n {icon && (\n <span className=\"flex items-center justify-center text-[var(--malachite-text-dimmed)] w-4 h-4 flex-shrink-0\">\n {icon}\n </span>\n )}\n {prefixValue && (\n <span className=\"text-[length:var(--malachite-font-size-medium,14px)] leading-[1.4] text-[var(--malachite-text-dimmed)] whitespace-nowrap\">\n {prefixValue}\n </span>\n )}\n {prefixSecondaryValue && (\n <span className=\"text-[length:var(--malachite-font-size-medium,14px)] leading-[1.4] text-[var(--malachite-text-dimmed)] whitespace-nowrap\">\n {prefixSecondaryValue}\n </span>\n )}\n </div>\n );\n};\n\nconst Suffix: React.FC<{\n error?: boolean;\n defaultValue?: string;\n onCopyClick?: () => void;\n showCopyButton?: boolean;\n copied?: boolean;\n type?: InputType;\n showPassword?: boolean;\n showPasswordToggle?: boolean;\n onTogglePassword?: () => void;\n}> = ({\n error,\n defaultValue,\n onCopyClick,\n showCopyButton = false,\n copied = false,\n type,\n showPassword,\n showPasswordToggle = true,\n onTogglePassword,\n}) => {\n return (\n <div className=\"flex items-center gap-1\">\n {error && (\n // Decorative: the rejection is carried by the message beneath the field, so\n // announcing an unnamed icon here would only repeat it as \"info\".\n <div\n aria-hidden=\"true\"\n className=\"flex items-center justify-center w-5 h-5 flex-shrink-0\"\n >\n <InfoIcon\n size={16}\n className=\"text-[var(--malachite-destructive-foreground,rgb(196,62,62))]\"\n />\n </div>\n )}\n {showCopyButton && onCopyClick && defaultValue && (\n <button\n onClick={onCopyClick}\n type=\"button\"\n className=\"flex items-center justify-center w-5 h-5 hover:bg-[var(--malachite-primary-border)] rounded transition-colors flex-shrink-0 cursor-pointer\"\n >\n {copied ? (\n <CheckCircleFilled\n size={16}\n style={{ color: 'var(--malachite-success-foreground)' }}\n />\n ) : (\n <CopyIcon size={16} />\n )}\n </button>\n )}\n {type === 'password' && showPasswordToggle && (\n <Button variant=\"no-style\" onClick={onTogglePassword} type=\"button\" size=\"small\">\n {showPassword ? (\n <EyeClosedIcon\n size={16}\n style={{ color: 'var(--malachite-text-dimmed)' }}\n />\n ) : (\n <EyeIcon\n size={16}\n style={{ color: 'var(--malachite-text-dimmed)' }}\n />\n )}\n </Button>\n )}\n </div>\n );\n};\n\nconst InputButtons: React.FC<{\n buttons?: ButtonDefinition[];\n}> = ({ buttons }) => {\n if (!buttons?.length) {\n return null;\n }\n\n return (\n <>\n {buttons.map((button) => (\n <Button\n key={button.label}\n variant={button.variant || (button.danger ? 'destructive' : 'outline')}\n size={button.size || 'small'}\n disabled={button.disabled}\n icon={button.icon}\n tooltip={button.tooltip}\n onClick={button.onClick}\n className=\"ml-1\"\n >\n {button.label}\n </Button>\n ))}\n </>\n );\n};\n\nexport default Input;\n"],"names":["SIZE_HEIGHT","SIZE_TEXT","SIZE_PADDING","SIZE_RADIUS","getVariantClasses","variant","error","Input","label","hint","tooltip","placeholder","icon","name","required","requiredIndicator","description","loading","readOnly","type","size","defaultValue","disabled","prefixValue","prefixSecondaryValue","ellipsis","formControl","buttons","onCopyClick","showCopyButton","onChange","value","onBlur","helperText","showPasswordToggle","id","ariaLabel","ariaLabelledBy","ariaDescribedBy","controlId","labelId","descriptionId","hintId","helperTextId","useFormFieldIds","showPassword","setShowPassword","useState","inputValue","setInputValue","copied","setCopied","useEffect","timer","handleChange","reportToForm","e","newValue","formValueRef","useRef","paintedValue","formValue","paintedFieldValue","handleCopyClick","copyValue","actualInputType","hasPrefix","heightClass","buildWrapperClasses","isError","variantStyles","jsx","BaseFormComponent","LoadingInput","fieldError","message","onFieldChange","onFieldBlur","displayValue","shouldShowCopyButton","errorMessage","showErrorIcon","hasSuffix","errorMessageId","describedBy","jsxs","Fragment","CompositeIcon","Suffix","InputButtons","FieldMessage","onTogglePassword","InfoIcon","CheckCircleFilled","CopyIcon","Button","EyeClosedIcon","EyeIcon","button"],"mappings":"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"}
@@ -29,7 +29,7 @@ const T = (r) => String(r.value) === "" ? r.label : `${r.value} ${r.label}`, b =
29
29
  a.current !== null && (cancelAnimationFrame(a.current), a.current = null), t.current && (clearTimeout(t.current), t.current = null);
30
30
  };
31
31
  }, [r]);
32
- const y = N === "sticky", u = d !== void 0 && d !== "", x = `sticky bottom-0 z-30${f ? " pt-4 pb-6" : ""}`, $ = /* @__PURE__ */ n("div", { className: k, style: { boxShadow: g }, children: [
32
+ const y = N === "sticky", u = d !== void 0 && d !== "", x = `sticky bottom-0 z-30 mt-auto${f ? " pt-4 pb-6" : ""}`, $ = /* @__PURE__ */ n("div", { className: k, style: { boxShadow: g }, children: [
33
33
  i.length > 0 && /* @__PURE__ */ l(
34
34
  "p",
35
35
  {
@@ -1 +1 @@
1
- {"version":3,"file":"SelectionBar.js","sources":["../../src/components/SelectionBar.tsx"],"sourcesContent":["import React, { Fragment, useEffect, useRef, useState } from 'react';\nimport {\n PILL_BUTTON_BASE,\n PILL_BUTTON_CLASS,\n PILL_DIVIDER,\n PILL_MUTED_TEXT,\n PILL_NOTICE_SHADOW,\n PILL_NOTICE_SLEEVE,\n PILL_NOTICE_TEXT,\n PILL_SHADOW,\n PILL_SHEET_CSS,\n PILL_SHEET_ID,\n PILL_SURFACE,\n PILL_TRACK_CLASS,\n PILL_TRANSITION_MS,\n type SelectionBarCount,\n type SelectionBarEmphasis,\n} from './selectionBarChrome';\nimport { useAdoptedStyleSheet } from './useAdoptedStyleSheet';\n\nexport type { SelectionBarCount, SelectionBarEmphasis };\n\nexport interface SelectionBarAction {\n label: string;\n onClick: () => void;\n /** 'primary' commits the pending change; 'secondary' (the default) is a filled chip;\n * 'quiet' is unfilled and takes a wash on hover. */\n emphasis?: SelectionBarEmphasis;\n icon?: React.ReactNode;\n iconPosition?: 'start' | 'end';\n disabled?: boolean;\n /** Renders a separator glyph before this action. */\n dividerBefore?: boolean;\n}\n\nexport interface SelectionBarProps {\n /** Drives the mount: the bar animates in on true and animates out on false. */\n open: boolean;\n counts: SelectionBarCount[];\n actions: SelectionBarAction[];\n /** 'sticky' keeps the bar in view while its container scrolls; render it as the last child\n * of that content, with no `overflow: hidden` on any ancestor. */\n placement?: 'sticky' | 'inline';\n /**\n * Wraps the bar in a warning sleeve carrying this message, for state the bar is\n * reporting rather than an action it offers — e.g. that the selection is unsaved.\n * It leads the announcement. An empty string renders no sleeve.\n */\n notice?: string;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n className?: string;\n}\n\n/** A count reads as one phrase; an empty `value` carries a bare message instead. */\nconst countText = (count: SelectionBarCount): string =>\n String(count.value) === '' ? count.label : `${count.value} ${count.label}`;\n\nconst summarise = (counts: SelectionBarCount[]): string => counts.map(countText).join(', ');\n\n/** A notice is the reason the bar is up, so it leads the announcement. */\nconst announcement = (notice: string | undefined, counts: SelectionBarCount[]): string =>\n notice === undefined || notice === ''\n ? summarise(counts)\n : `${notice} ${summarise(counts)}`.trim();\n\n/**\n * A bar reporting a pending, not-yet-written selection and the actions that resolve it. Every\n * action destroys the button just pressed, so an `onClick` that ends the pending state must\n * also move focus.\n */\nexport const SelectionBar: React.FC<SelectionBarProps> = ({\n open,\n counts,\n actions,\n placement = 'sticky',\n notice,\n 'aria-label': ariaLabel = 'Pending changes',\n 'aria-labelledby': ariaLabelledBy,\n className = '',\n}) => {\n const trackRef = useRef<HTMLDivElement>(null);\n const [isMounted, setIsMounted] = useState(open);\n const [isVisible, setIsVisible] = useState(open);\n const frameRef = useRef<number | null>(null);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useAdoptedStyleSheet(trackRef, PILL_SHEET_CSS, PILL_SHEET_ID);\n\n useEffect(() => {\n if (open) {\n setIsMounted(true);\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n frameRef.current = requestAnimationFrame(() => {\n frameRef.current = null;\n setIsVisible(true);\n });\n } else {\n // The browser refuses `aria-hidden` on a subtree still holding focus, so a caller\n // that forgets to move it would trap the keyboard here.\n const active = document.activeElement;\n if (active instanceof HTMLElement && trackRef.current?.contains(active)) {\n active.blur();\n }\n setIsVisible(false);\n timerRef.current = setTimeout(() => {\n timerRef.current = null;\n setIsMounted(false);\n }, PILL_TRANSITION_MS);\n }\n return () => {\n if (frameRef.current !== null) {\n cancelAnimationFrame(frameRef.current);\n frameRef.current = null;\n }\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n };\n }, [open]);\n\n const isSticky = placement === 'sticky';\n const hasNotice = notice !== undefined && notice !== '';\n const stickyClass = `sticky bottom-0 z-30${isMounted ? ' pt-4 pb-6' : ''}`;\n\n const pill = (\n <div className={PILL_SURFACE} style={{ boxShadow: PILL_SHADOW }}>\n {counts.length > 0 && (\n <p\n aria-hidden=\"true\"\n className=\"m-0 flex items-center gap-2 text-[13px] leading-[1.6] tracking-[0.13px]\"\n >\n {counts.map((count, index) => (\n <Fragment key={count.label}>\n {index > 0 && <span className={PILL_MUTED_TEXT}>•</span>}\n <span>{countText(count)}</span>\n </Fragment>\n ))}\n </p>\n )}\n {actions.map((action) => (\n <Fragment key={action.label}>\n {action.dividerBefore && (\n <span aria-hidden=\"true\" className={`${PILL_DIVIDER} ${PILL_MUTED_TEXT}`}>\n |\n </span>\n )}\n <button\n type=\"button\"\n disabled={action.disabled}\n tabIndex={isVisible ? undefined : -1}\n onClick={action.onClick}\n className={`${PILL_BUTTON_BASE} ${PILL_BUTTON_CLASS}--${action.emphasis ?? 'secondary'}`}\n >\n {action.icon && action.iconPosition !== 'end' && (\n <span aria-hidden=\"true\" className=\"flex items-center\">\n {action.icon}\n </span>\n )}\n {action.label}\n {action.icon && action.iconPosition === 'end' && (\n <span aria-hidden=\"true\" className=\"flex items-center\">\n {action.icon}\n </span>\n )}\n </button>\n </Fragment>\n ))}\n </div>\n );\n\n return (\n // The live region has to exist BEFORE its text changes or the first announcement is dropped.\n <div\n ref={trackRef}\n className={`${PILL_TRACK_CLASS} pointer-events-none flex w-full justify-center ${isSticky ? stickyClass : 'relative'} ${className}`.trim()}\n style={{ opacity: isVisible ? 1 : 0 }}\n >\n <p className=\"sr-only\" role=\"status\">\n {isVisible ? announcement(notice, counts) : ''}\n </p>\n {isMounted && (\n <div\n role=\"group\"\n aria-label={ariaLabelledBy ? undefined : ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-hidden={isVisible ? undefined : true}\n className={isVisible ? 'pointer-events-auto' : undefined}\n >\n {/* Keep the wrapper stable: changing the pill's parent remounts it and drops focus\n from the action that raised the notice. */}\n <div\n className={hasNotice ? PILL_NOTICE_SLEEVE : undefined}\n style={hasNotice ? { boxShadow: PILL_NOTICE_SHADOW } : undefined}\n >\n {hasNotice && (\n <p aria-hidden=\"true\" className={PILL_NOTICE_TEXT}>\n {notice}\n </p>\n )}\n {pill}\n </div>\n </div>\n )}\n </div>\n );\n};\n\nexport default SelectionBar;\n"],"names":["countText","count","summarise","counts","announcement","notice","SelectionBar","open","actions","placement","ariaLabel","ariaLabelledBy","className","trackRef","useRef","isMounted","setIsMounted","useState","isVisible","setIsVisible","frameRef","timerRef","useAdoptedStyleSheet","PILL_SHEET_CSS","PILL_SHEET_ID","useEffect","active","_a","PILL_TRANSITION_MS","isSticky","hasNotice","stickyClass","pill","PILL_SURFACE","PILL_SHADOW","jsx","index","Fragment","PILL_MUTED_TEXT","action","PILL_DIVIDER","jsxs","PILL_BUTTON_BASE","PILL_BUTTON_CLASS","PILL_TRACK_CLASS","PILL_NOTICE_SLEEVE","PILL_NOTICE_SHADOW","PILL_NOTICE_TEXT"],"mappings":"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"}
1
+ {"version":3,"file":"SelectionBar.js","sources":["../../src/components/SelectionBar.tsx"],"sourcesContent":["import React, { Fragment, useEffect, useRef, useState } from 'react';\nimport {\n PILL_BUTTON_BASE,\n PILL_BUTTON_CLASS,\n PILL_DIVIDER,\n PILL_MUTED_TEXT,\n PILL_NOTICE_SHADOW,\n PILL_NOTICE_SLEEVE,\n PILL_NOTICE_TEXT,\n PILL_SHADOW,\n PILL_SHEET_CSS,\n PILL_SHEET_ID,\n PILL_SURFACE,\n PILL_TRACK_CLASS,\n PILL_TRANSITION_MS,\n type SelectionBarCount,\n type SelectionBarEmphasis,\n} from './selectionBarChrome';\nimport { useAdoptedStyleSheet } from './useAdoptedStyleSheet';\n\nexport type { SelectionBarCount, SelectionBarEmphasis };\n\nexport interface SelectionBarAction {\n label: string;\n onClick: () => void;\n /** 'primary' commits the pending change; 'secondary' (the default) is a filled chip;\n * 'quiet' is unfilled and takes a wash on hover. */\n emphasis?: SelectionBarEmphasis;\n icon?: React.ReactNode;\n iconPosition?: 'start' | 'end';\n disabled?: boolean;\n /** Renders a separator glyph before this action. */\n dividerBefore?: boolean;\n}\n\nexport interface SelectionBarProps {\n /** Drives the mount: the bar animates in on true and animates out on false. */\n open: boolean;\n counts: SelectionBarCount[];\n actions: SelectionBarAction[];\n /** 'sticky' keeps the bar in view while its container scrolls; render it as the last child\n * of that content, with no `overflow: hidden` on any ancestor. */\n placement?: 'sticky' | 'inline';\n /**\n * Wraps the bar in a warning sleeve carrying this message, for state the bar is\n * reporting rather than an action it offers — e.g. that the selection is unsaved.\n * It leads the announcement. An empty string renders no sleeve.\n */\n notice?: string;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n className?: string;\n}\n\n/** A count reads as one phrase; an empty `value` carries a bare message instead. */\nconst countText = (count: SelectionBarCount): string =>\n String(count.value) === '' ? count.label : `${count.value} ${count.label}`;\n\nconst summarise = (counts: SelectionBarCount[]): string => counts.map(countText).join(', ');\n\n/** A notice is the reason the bar is up, so it leads the announcement. */\nconst announcement = (notice: string | undefined, counts: SelectionBarCount[]): string =>\n notice === undefined || notice === ''\n ? summarise(counts)\n : `${notice} ${summarise(counts)}`.trim();\n\n/**\n * A bar reporting a pending, not-yet-written selection and the actions that resolve it. Every\n * action destroys the button just pressed, so an `onClick` that ends the pending state must\n * also move focus.\n */\nexport const SelectionBar: React.FC<SelectionBarProps> = ({\n open,\n counts,\n actions,\n placement = 'sticky',\n notice,\n 'aria-label': ariaLabel = 'Pending changes',\n 'aria-labelledby': ariaLabelledBy,\n className = '',\n}) => {\n const trackRef = useRef<HTMLDivElement>(null);\n const [isMounted, setIsMounted] = useState(open);\n const [isVisible, setIsVisible] = useState(open);\n const frameRef = useRef<number | null>(null);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useAdoptedStyleSheet(trackRef, PILL_SHEET_CSS, PILL_SHEET_ID);\n\n useEffect(() => {\n if (open) {\n setIsMounted(true);\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n frameRef.current = requestAnimationFrame(() => {\n frameRef.current = null;\n setIsVisible(true);\n });\n } else {\n // The browser refuses `aria-hidden` on a subtree still holding focus, so a caller\n // that forgets to move it would trap the keyboard here.\n const active = document.activeElement;\n if (active instanceof HTMLElement && trackRef.current?.contains(active)) {\n active.blur();\n }\n setIsVisible(false);\n timerRef.current = setTimeout(() => {\n timerRef.current = null;\n setIsMounted(false);\n }, PILL_TRANSITION_MS);\n }\n return () => {\n if (frameRef.current !== null) {\n cancelAnimationFrame(frameRef.current);\n frameRef.current = null;\n }\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n };\n }, [open]);\n\n const isSticky = placement === 'sticky';\n const hasNotice = notice !== undefined && notice !== '';\n const stickyClass = `sticky bottom-0 z-30 mt-auto${isMounted ? ' pt-4 pb-6' : ''}`;\n\n const pill = (\n <div className={PILL_SURFACE} style={{ boxShadow: PILL_SHADOW }}>\n {counts.length > 0 && (\n <p\n aria-hidden=\"true\"\n className=\"m-0 flex items-center gap-2 text-[13px] leading-[1.6] tracking-[0.13px]\"\n >\n {counts.map((count, index) => (\n <Fragment key={count.label}>\n {index > 0 && <span className={PILL_MUTED_TEXT}>•</span>}\n <span>{countText(count)}</span>\n </Fragment>\n ))}\n </p>\n )}\n {actions.map((action) => (\n <Fragment key={action.label}>\n {action.dividerBefore && (\n <span aria-hidden=\"true\" className={`${PILL_DIVIDER} ${PILL_MUTED_TEXT}`}>\n |\n </span>\n )}\n <button\n type=\"button\"\n disabled={action.disabled}\n tabIndex={isVisible ? undefined : -1}\n onClick={action.onClick}\n className={`${PILL_BUTTON_BASE} ${PILL_BUTTON_CLASS}--${action.emphasis ?? 'secondary'}`}\n >\n {action.icon && action.iconPosition !== 'end' && (\n <span aria-hidden=\"true\" className=\"flex items-center\">\n {action.icon}\n </span>\n )}\n {action.label}\n {action.icon && action.iconPosition === 'end' && (\n <span aria-hidden=\"true\" className=\"flex items-center\">\n {action.icon}\n </span>\n )}\n </button>\n </Fragment>\n ))}\n </div>\n );\n\n return (\n // The live region has to exist BEFORE its text changes or the first announcement is dropped.\n <div\n ref={trackRef}\n className={`${PILL_TRACK_CLASS} pointer-events-none flex w-full justify-center ${isSticky ? stickyClass : 'relative'} ${className}`.trim()}\n style={{ opacity: isVisible ? 1 : 0 }}\n >\n <p className=\"sr-only\" role=\"status\">\n {isVisible ? announcement(notice, counts) : ''}\n </p>\n {isMounted && (\n <div\n role=\"group\"\n aria-label={ariaLabelledBy ? undefined : ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-hidden={isVisible ? undefined : true}\n className={isVisible ? 'pointer-events-auto' : undefined}\n >\n {/* Keep the wrapper stable: changing the pill's parent remounts it and drops focus\n from the action that raised the notice. */}\n <div\n className={hasNotice ? PILL_NOTICE_SLEEVE : undefined}\n style={hasNotice ? { boxShadow: PILL_NOTICE_SHADOW } : undefined}\n >\n {hasNotice && (\n <p aria-hidden=\"true\" className={PILL_NOTICE_TEXT}>\n {notice}\n </p>\n )}\n {pill}\n </div>\n </div>\n )}\n </div>\n );\n};\n\nexport default SelectionBar;\n"],"names":["countText","count","summarise","counts","announcement","notice","SelectionBar","open","actions","placement","ariaLabel","ariaLabelledBy","className","trackRef","useRef","isMounted","setIsMounted","useState","isVisible","setIsVisible","frameRef","timerRef","useAdoptedStyleSheet","PILL_SHEET_CSS","PILL_SHEET_ID","useEffect","active","_a","PILL_TRANSITION_MS","isSticky","hasNotice","stickyClass","pill","PILL_SURFACE","PILL_SHADOW","jsx","index","Fragment","PILL_MUTED_TEXT","action","PILL_DIVIDER","jsxs","PILL_BUTTON_BASE","PILL_BUTTON_CLASS","PILL_TRACK_CLASS","PILL_NOTICE_SLEEVE","PILL_NOTICE_SHADOW","PILL_NOTICE_TEXT"],"mappings":"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"}