@dragunio/fe-libs 0.1.3 → 0.1.5

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.
package/dist/index.mjs CHANGED
@@ -1,3 +1,27 @@
1
+ import {
2
+ ChevronDownIcon,
3
+ CloseIcon,
4
+ PlusIcon,
5
+ SearchIcon,
6
+ arrow_left,
7
+ check_square_fill,
8
+ chevron_down,
9
+ chevron_left,
10
+ chevron_right,
11
+ chevron_up,
12
+ copy,
13
+ key,
14
+ lock,
15
+ lock_unlocked,
16
+ log_out,
17
+ minus_square,
18
+ plus,
19
+ plus_square,
20
+ search,
21
+ trash,
22
+ x_close
23
+ } from "./chunk-3TCR34LS.mjs";
24
+
1
25
  // packages/button/src/index.tsx
2
26
  import { forwardRef } from "react";
3
27
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -64,32 +88,6 @@ var Button = forwardRef(
64
88
  );
65
89
  Button.displayName = "Button";
66
90
 
67
- // packages/icons/src/index.tsx
68
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
69
- var iconProps = ({ size, ...props }) => ({
70
- width: size ?? 20,
71
- height: size ?? 20,
72
- fill: "none",
73
- viewBox: "0 0 24 24",
74
- "aria-hidden": true,
75
- ...props
76
- });
77
- function PlusIcon(props) {
78
- return /* @__PURE__ */ jsx2("svg", { ...iconProps(props), children: /* @__PURE__ */ jsx2("path", { d: "M12 5v14M5 12h14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) });
79
- }
80
- function ChevronDownIcon(props) {
81
- return /* @__PURE__ */ jsx2("svg", { ...iconProps(props), children: /* @__PURE__ */ jsx2("path", { d: "m6 9 6 6 6-6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) });
82
- }
83
- function CloseIcon(props) {
84
- return /* @__PURE__ */ jsx2("svg", { ...iconProps(props), children: /* @__PURE__ */ jsx2("path", { d: "m6 6 12 12M18 6 6 18", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) });
85
- }
86
- function SearchIcon(props) {
87
- return /* @__PURE__ */ jsxs2("svg", { ...iconProps(props), children: [
88
- /* @__PURE__ */ jsx2("circle", { cx: "11", cy: "11", r: "6.5", stroke: "currentColor", strokeWidth: "2" }),
89
- /* @__PURE__ */ jsx2("path", { d: "m16 16 4 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
90
- ] });
91
- }
92
-
93
91
  // packages/table/src/index.tsx
94
92
  import {
95
93
  createContext,
@@ -104,7 +102,7 @@ import {
104
102
 
105
103
  // packages/pagination/src/index.tsx
106
104
  import { useMemo, useState } from "react";
107
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
105
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
108
106
  var clamp = (value, min, max) => Math.min(Math.max(value, min), max);
109
107
  var range = (start, end) => Array.from({ length: Math.max(0, end - start + 1) }, (_, index) => start + index);
110
108
  function getItems(totalPages, page, siblingCount, boundaryCount) {
@@ -147,9 +145,9 @@ function Pagination({
147
145
  if (page === void 0) setUncontrolledPage(resolvedPage);
148
146
  if (resolvedPage !== currentPage) onPageChange?.(resolvedPage);
149
147
  };
150
- return /* @__PURE__ */ jsxs3("nav", { className: ["fe-pagination", className].filter(Boolean).join(" "), "aria-label": "Pagination", ...props, children: [
151
- /* @__PURE__ */ jsx3(Button, { className: "fe-pagination__button fe-pagination__button--control", hierarchy: "secondary-gray", size: "40", iconOnly: true, icon: "\u2039", "aria-label": previousLabel, disabled: disabled || currentPage === 1, onClick: () => selectPage(currentPage - 1) }),
152
- items.map((item, index) => item === "start-ellipsis" || item === "end-ellipsis" ? /* @__PURE__ */ jsx3("span", { className: "fe-pagination__ellipsis", "aria-hidden": "true", children: "\u2026" }, `${item}-${index}`) : /* @__PURE__ */ jsx3(
148
+ return /* @__PURE__ */ jsxs2("nav", { className: ["fe-pagination", className].filter(Boolean).join(" "), "aria-label": "Pagination", ...props, children: [
149
+ /* @__PURE__ */ jsx2(Button, { className: "fe-pagination__button fe-pagination__button--control", hierarchy: "secondary-gray", size: "40", iconOnly: true, icon: "\u2039", "aria-label": previousLabel, disabled: disabled || currentPage === 1, onClick: () => selectPage(currentPage - 1) }),
150
+ items.map((item, index) => item === "start-ellipsis" || item === "end-ellipsis" ? /* @__PURE__ */ jsx2("span", { className: "fe-pagination__ellipsis", "aria-hidden": "true", children: "\u2026" }, `${item}-${index}`) : /* @__PURE__ */ jsx2(
153
151
  Button,
154
152
  {
155
153
  className: "fe-pagination__button",
@@ -163,12 +161,12 @@ function Pagination({
163
161
  },
164
162
  item
165
163
  )),
166
- /* @__PURE__ */ jsx3(Button, { className: "fe-pagination__button fe-pagination__button--control", hierarchy: "secondary-gray", size: "40", iconOnly: true, icon: "\u203A", "aria-label": nextLabel, disabled: disabled || currentPage === safeTotalPages, onClick: () => selectPage(currentPage + 1) })
164
+ /* @__PURE__ */ jsx2(Button, { className: "fe-pagination__button fe-pagination__button--control", hierarchy: "secondary-gray", size: "40", iconOnly: true, icon: "\u203A", "aria-label": nextLabel, disabled: disabled || currentPage === safeTotalPages, onClick: () => selectPage(currentPage + 1) })
167
165
  ] });
168
166
  }
169
167
 
170
168
  // packages/table/src/index.tsx
171
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
169
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
172
170
  var TableContext = createContext({ striped: false });
173
171
  var MIN_COLUMN_WIDTH = 96;
174
172
  var MAX_COLUMN_WIDTH = 1200;
@@ -268,14 +266,14 @@ function DataTable({
268
266
  if (nextPage !== currentPage) onPageChange?.(nextPage);
269
267
  };
270
268
  const resolvedPaginationPosition = paginationPosition === "middle-bottom" ? "bottom-center" : paginationPosition;
271
- const paginationControl = shouldPaginate && totalPages > 1 ? /* @__PURE__ */ jsx4("div", { className: `fe-table__pagination fe-table__pagination--${resolvedPaginationPosition}`, children: /* @__PURE__ */ jsx4(Pagination, { page: currentPage, totalPages, onPageChange: changePage }) }) : null;
272
- return /* @__PURE__ */ jsxs4("div", { className: "fe-table", "data-resizing": isResizing || void 0, children: [
269
+ const paginationControl = shouldPaginate && totalPages > 1 ? /* @__PURE__ */ jsx3("div", { className: `fe-table__pagination fe-table__pagination--${resolvedPaginationPosition}`, children: /* @__PURE__ */ jsx3(Pagination, { page: currentPage, totalPages, onPageChange: changePage }) }) : null;
270
+ return /* @__PURE__ */ jsxs3("div", { className: "fe-table", "data-resizing": isResizing || void 0, children: [
273
271
  resolvedPaginationPosition === "top-right" && paginationControl,
274
- /* @__PURE__ */ jsxs4("table", { className: ["fe-table__table", className].filter(Boolean).join(" "), "data-fe-table": true, "data-striped": striped || void 0, ...props, children: [
275
- /* @__PURE__ */ jsx4("colgroup", { children: sizes2.map((size, index) => /* @__PURE__ */ jsx4("col", { style: { width: `${size}px` } }, index)) }),
276
- /* @__PURE__ */ jsx4("thead", { children: /* @__PURE__ */ jsx4("tr", { children: Array.from({ length: columnCount }, (_, columnIndex) => /* @__PURE__ */ jsxs4("th", { scope: "col", children: [
277
- /* @__PURE__ */ jsx4("span", { className: "fe-table__header-content", children: headers[columnIndex] ?? `Column ${columnIndex + 1}` }),
278
- /* @__PURE__ */ jsx4(
272
+ /* @__PURE__ */ jsxs3("table", { className: ["fe-table__table", className].filter(Boolean).join(" "), "data-fe-table": true, "data-striped": striped || void 0, ...props, children: [
273
+ /* @__PURE__ */ jsx3("colgroup", { children: sizes2.map((size, index) => /* @__PURE__ */ jsx3("col", { style: { width: `${size}px` } }, index)) }),
274
+ /* @__PURE__ */ jsx3("thead", { children: /* @__PURE__ */ jsx3("tr", { children: Array.from({ length: columnCount }, (_, columnIndex) => /* @__PURE__ */ jsxs3("th", { scope: "col", children: [
275
+ /* @__PURE__ */ jsx3("span", { className: "fe-table__header-content", children: headers[columnIndex] ?? `Column ${columnIndex + 1}` }),
276
+ /* @__PURE__ */ jsx3(
279
277
  "span",
280
278
  {
281
279
  className: "fe-table__resize-handle",
@@ -299,7 +297,7 @@ function DataTable({
299
297
  }
300
298
  )
301
299
  ] }, columnIndex)) }) }),
302
- /* @__PURE__ */ jsx4("tbody", { children: pagedData.map((row, rowIndex) => /* @__PURE__ */ jsx4("tr", { children: Array.from({ length: columnCount }, (_, columnIndex) => /* @__PURE__ */ jsx4("td", { children: row[columnIndex] }, columnIndex)) }, shouldPaginate ? (currentPage - 1) * safePageSize + rowIndex : rowIndex)) })
300
+ /* @__PURE__ */ jsx3("tbody", { children: pagedData.map((row, rowIndex) => /* @__PURE__ */ jsx3("tr", { children: Array.from({ length: columnCount }, (_, columnIndex) => /* @__PURE__ */ jsx3("td", { children: row[columnIndex] }, columnIndex)) }, shouldPaginate ? (currentPage - 1) * safePageSize + rowIndex : rowIndex)) })
303
301
  ] }),
304
302
  resolvedPaginationPosition !== "top-right" && paginationControl
305
303
  ] });
@@ -317,42 +315,42 @@ function Table({
317
315
  paginationPosition,
318
316
  ...props
319
317
  }) {
320
- if (headers || data) return /* @__PURE__ */ jsx4(DataTable, { headers: headers ?? [], data: data ?? [], striped: striped ?? true, pagination, pageSize, page, defaultPage, onPageChange, paginationPosition, ...props });
321
- return /* @__PURE__ */ jsx4(TableContext.Provider, { value: { striped: striped ?? false }, children: /* @__PURE__ */ jsx4("table", { "data-fe-table": true, "data-striped": striped || void 0, ...props, children }) });
318
+ if (headers || data) return /* @__PURE__ */ jsx3(DataTable, { headers: headers ?? [], data: data ?? [], striped: striped ?? true, pagination, pageSize, page, defaultPage, onPageChange, paginationPosition, ...props });
319
+ return /* @__PURE__ */ jsx3(TableContext.Provider, { value: { striped: striped ?? false }, children: /* @__PURE__ */ jsx3("table", { "data-fe-table": true, "data-striped": striped || void 0, ...props, children }) });
322
320
  }
323
321
  function TableHead(props) {
324
- return /* @__PURE__ */ jsx4("thead", { ...props });
322
+ return /* @__PURE__ */ jsx3("thead", { ...props });
325
323
  }
326
324
  function TableBody(props) {
327
- return /* @__PURE__ */ jsx4("tbody", { ...props });
325
+ return /* @__PURE__ */ jsx3("tbody", { ...props });
328
326
  }
329
327
  function TableRow({ children, ...props }) {
330
328
  const { striped } = useContext(TableContext);
331
- return /* @__PURE__ */ jsx4("tr", { "data-striped": striped || void 0, ...props, children });
329
+ return /* @__PURE__ */ jsx3("tr", { "data-striped": striped || void 0, ...props, children });
332
330
  }
333
331
  function TableCell({ children, ...props }) {
334
- return /* @__PURE__ */ jsx4("td", { ...props, children });
332
+ return /* @__PURE__ */ jsx3("td", { ...props, children });
335
333
  }
336
334
  function TableHeader({ children, ...props }) {
337
- return /* @__PURE__ */ jsx4("th", { scope: "col", ...props, children });
335
+ return /* @__PURE__ */ jsx3("th", { scope: "col", ...props, children });
338
336
  }
339
337
  function TableCaption(props) {
340
- return /* @__PURE__ */ jsx4("caption", { ...props });
338
+ return /* @__PURE__ */ jsx3("caption", { ...props });
341
339
  }
342
340
 
343
341
  // packages/toggle/src/index.tsx
344
342
  import { forwardRef as forwardRef2 } from "react";
345
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
343
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
346
344
  var Toggle = forwardRef2(function Toggle2({ color = "#16a34a", label, className, style, id, ...props }, ref) {
347
345
  const classes = ["fe-toggle", className].filter(Boolean).join(" ");
348
346
  const toggleStyle = {
349
347
  "--fe-toggle-color": color,
350
348
  ...style
351
349
  };
352
- return /* @__PURE__ */ jsxs5("label", { className: classes, style: toggleStyle, children: [
353
- /* @__PURE__ */ jsx5("input", { ref, id, className: "fe-toggle__input", type: "checkbox", role: "switch", ...props }),
354
- /* @__PURE__ */ jsx5("span", { className: "fe-toggle__control", "aria-hidden": "true" }),
355
- label && /* @__PURE__ */ jsx5("span", { className: "fe-toggle__label", children: label })
350
+ return /* @__PURE__ */ jsxs4("label", { className: classes, style: toggleStyle, children: [
351
+ /* @__PURE__ */ jsx4("input", { ref, id, className: "fe-toggle__input", type: "checkbox", role: "switch", ...props }),
352
+ /* @__PURE__ */ jsx4("span", { className: "fe-toggle__control", "aria-hidden": "true" }),
353
+ label && /* @__PURE__ */ jsx4("span", { className: "fe-toggle__label", children: label })
356
354
  ] });
357
355
  });
358
356
  Toggle.displayName = "Toggle";
@@ -360,7 +358,7 @@ Toggle.displayName = "Toggle";
360
358
  // packages/drawer/src/index.tsx
361
359
  import { useEffect as useEffect2 } from "react";
362
360
  import { createPortal } from "react-dom";
363
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
361
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
364
362
  function Drawer({ open, onClose, title, footer, side = "right", width = 400, fullScreen = false, children, closeOnBackdropClick = true, className, style, ...props }) {
365
363
  useEffect2(() => {
366
364
  if (!open) return;
@@ -372,26 +370,47 @@ function Drawer({ open, onClose, title, footer, side = "right", width = 400, ful
372
370
  }, [onClose, open]);
373
371
  if (!open || typeof document === "undefined") return null;
374
372
  const panelStyle = !fullScreen && (side === "left" || side === "right") ? { ...style, width: typeof width === "number" ? `${width}px` : width } : style;
375
- return createPortal(/* @__PURE__ */ jsx6("div", { className: "fe-drawer-backdrop", role: "presentation", onMouseDown: (event) => {
373
+ return createPortal(/* @__PURE__ */ jsx5("div", { className: "fe-drawer-backdrop", role: "presentation", onMouseDown: (event) => {
376
374
  if (event.target === event.currentTarget && closeOnBackdropClick) onClose();
377
- }, children: /* @__PURE__ */ jsxs6("aside", { className: ["fe-drawer", `fe-drawer--${side}`, fullScreen && "fe-drawer--full-screen", className].filter(Boolean).join(" "), style: panelStyle, role: "dialog", "aria-modal": "true", "aria-label": typeof title === "string" ? title : "Drawer", ...props, children: [
378
- /* @__PURE__ */ jsxs6("header", { className: "fe-drawer__header", children: [
379
- title && /* @__PURE__ */ jsx6("h2", { children: title }),
380
- /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Close drawer", onClick: onClose, children: "\xD7" })
375
+ }, children: /* @__PURE__ */ jsxs5("aside", { className: ["fe-drawer", `fe-drawer--${side}`, fullScreen && "fe-drawer--full-screen", className].filter(Boolean).join(" "), style: panelStyle, role: "dialog", "aria-modal": "true", "aria-label": typeof title === "string" ? title : "Drawer", ...props, children: [
376
+ /* @__PURE__ */ jsxs5("header", { className: "fe-drawer__header", children: [
377
+ title && /* @__PURE__ */ jsx5("h2", { children: title }),
378
+ /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Close drawer", onClick: onClose, children: "\xD7" })
381
379
  ] }),
382
- /* @__PURE__ */ jsx6("div", { className: "fe-drawer__body", children }),
383
- footer && /* @__PURE__ */ jsx6("footer", { className: "fe-drawer__footer", children: footer })
380
+ /* @__PURE__ */ jsx5("div", { className: "fe-drawer__body", children }),
381
+ footer && /* @__PURE__ */ jsx5("footer", { className: "fe-drawer__footer", children: footer })
384
382
  ] }) }), document.body);
385
383
  }
386
384
 
387
- // packages/form-controls/src/index.tsx
388
- import {
389
- forwardRef as forwardRef3,
390
- useEffect as useEffect3,
391
- useId,
392
- useRef as useRef2,
393
- useState as useState3
394
- } from "react";
385
+ // packages/form-controls/src/controls/TextInput/text-input.tsx
386
+ import { forwardRef as forwardRef3, useId as useId2, useState as useState4 } from "react";
387
+
388
+ // packages/tooltip/src/index.tsx
389
+ import { cloneElement, useId, useState as useState3 } from "react";
390
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
391
+ function Tooltip({ content, children, placement = "top", disabled, className, ...props }) {
392
+ const [visible, setVisible] = useState3(false);
393
+ const id = useId();
394
+ const trigger = cloneElement(children, { "aria-describedby": visible ? id : void 0, onMouseEnter: (event) => {
395
+ children.props.onMouseEnter?.(event);
396
+ setVisible(true);
397
+ }, onMouseLeave: (event) => {
398
+ children.props.onMouseLeave?.(event);
399
+ setVisible(false);
400
+ }, onFocus: (event) => {
401
+ children.props.onFocus?.(event);
402
+ setVisible(true);
403
+ }, onBlur: (event) => {
404
+ children.props.onBlur?.(event);
405
+ setVisible(false);
406
+ } });
407
+ return /* @__PURE__ */ jsxs6("span", { className: ["fe-tooltip", `fe-tooltip--${placement}`, className].filter(Boolean).join(" "), ...props, children: [
408
+ trigger,
409
+ visible && !disabled && /* @__PURE__ */ jsx6("span", { id, role: "tooltip", className: "fe-tooltip__content", children: content })
410
+ ] });
411
+ }
412
+
413
+ // packages/form-controls/src/controls/Field/field.tsx
395
414
  import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
396
415
  function getFieldError(error, errorMessage) {
397
416
  if (errorMessage !== void 0 && errorMessage !== null) return errorMessage;
@@ -401,161 +420,655 @@ function getFieldError(error, errorMessage) {
401
420
  function getDescribedBy(existing, messageId2) {
402
421
  return [existing, messageId2].filter(Boolean).join(" ") || void 0;
403
422
  }
404
- var TextInput = forwardRef3(function TextInput2({ value, defaultValue = "", onChange, onValueChange, label, helperText, error, errorMessage, clearable = false, onClear, clearLabel = "Clear input", className, disabled, readOnly, id, "aria-describedby": ariaDescribedBy, "aria-labelledby": ariaLabelledBy, ...props }, ref) {
405
- const generatedId = useId();
406
- const inputId = id ?? `${generatedId}-input`;
407
- const labelId = `${generatedId}-label`;
408
- const messageId2 = `${generatedId}-message`;
409
- const controlled = value !== void 0;
410
- const [internalValue, setInternalValue] = useState3(defaultValue);
411
- const currentValue = controlled ? value : internalValue;
412
- const fieldError = getFieldError(error, errorMessage);
413
- const hasError = fieldError !== void 0 && fieldError !== false && fieldError !== null;
414
- const displayedMessage = hasError ? fieldError : helperText;
415
- const describedBy = getDescribedBy(ariaDescribedBy, displayedMessage ? messageId2 : void 0);
416
- const clear = () => {
417
- if (!controlled) setInternalValue("");
418
- onValueChange?.("");
419
- onClear?.();
420
- };
421
- const labelledBy = getDescribedBy(ariaLabelledBy, label ? labelId : void 0);
422
- return /* @__PURE__ */ jsxs7("label", { className: ["fe-text-input", hasError && "fe-text-input--error", className].filter(Boolean).join(" "), children: [
423
- label && /* @__PURE__ */ jsx7("span", { id: labelId, className: "fe-text-input__label", children: label }),
424
- /* @__PURE__ */ jsxs7("span", { className: "fe-text-input__control", children: [
425
- /* @__PURE__ */ jsx7("input", { ref, id: inputId, value: currentValue, disabled, readOnly, "aria-invalid": hasError || void 0, "aria-labelledby": labelledBy, "aria-describedby": describedBy, onChange: (event) => {
426
- if (!controlled) setInternalValue(event.target.value);
427
- onValueChange?.(event.target.value);
428
- onChange?.(event);
429
- }, ...props }),
430
- clearable && currentValue && !disabled && !readOnly && /* @__PURE__ */ jsx7(Button, { hierarchy: "tertiary-gray", size: "24", iconOnly: true, icon: /* @__PURE__ */ jsx7(CloseIcon, { size: 14 }), "aria-label": clearLabel, onClick: clear, className: "fe-text-input__clear" })
431
- ] }),
432
- displayedMessage && /* @__PURE__ */ jsx7("span", { id: messageId2, className: hasError ? "fe-text-input__error" : "fe-text-input__helper", children: displayedMessage })
423
+ function FieldLabel({
424
+ id,
425
+ label,
426
+ description,
427
+ descriptionDisplay,
428
+ isRequired = false
429
+ }) {
430
+ if (!label) return null;
431
+ return /* @__PURE__ */ jsxs7("span", { className: "fe-field__label", children: [
432
+ /* @__PURE__ */ jsx7("span", { id, children: label }),
433
+ isRequired && /* @__PURE__ */ jsx7("span", { className: "fe-field__required", "aria-hidden": "true", children: "*" }),
434
+ description && descriptionDisplay === "tooltip" && /* @__PURE__ */ jsx7(Tooltip, { content: description, children: /* @__PURE__ */ jsx7(
435
+ "span",
436
+ {
437
+ className: "fe-field__info",
438
+ tabIndex: 0,
439
+ role: "img",
440
+ "aria-label": "More information",
441
+ children: "i"
442
+ }
443
+ ) })
433
444
  ] });
434
- });
445
+ }
446
+ function FieldMessage({
447
+ id,
448
+ error,
449
+ description,
450
+ descriptionDisplay
451
+ }) {
452
+ if (error !== void 0 && error !== false && error !== null)
453
+ return /* @__PURE__ */ jsx7(
454
+ "span",
455
+ {
456
+ id,
457
+ className: "fe-field__message fe-field__message--error",
458
+ role: "alert",
459
+ children: error
460
+ }
461
+ );
462
+ if (description && descriptionDisplay === "inline")
463
+ return /* @__PURE__ */ jsx7("span", { id, className: "fe-field__message", children: description });
464
+ return null;
465
+ }
466
+
467
+ // packages/form-controls/src/controls/TextInput/text-input.tsx
468
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
469
+ var TextInput = forwardRef3(
470
+ function TextInput2({
471
+ value,
472
+ defaultValue = "",
473
+ onChange,
474
+ onValueChange,
475
+ label,
476
+ description,
477
+ descriptionDisplay = "inline",
478
+ helperText,
479
+ error,
480
+ errorMessage,
481
+ clearable = false,
482
+ onClear,
483
+ clearLabel = "Clear input",
484
+ className,
485
+ disabled,
486
+ readOnly,
487
+ id,
488
+ prefix,
489
+ suffix,
490
+ Prefix,
491
+ Suffix,
492
+ isRequired = false,
493
+ placeholder,
494
+ required,
495
+ "aria-describedby": ariaDescribedBy,
496
+ "aria-labelledby": ariaLabelledBy,
497
+ ...props
498
+ }, ref) {
499
+ const generatedId = useId2();
500
+ const inputId = id ?? generatedId + "-input";
501
+ const labelId = generatedId + "-label";
502
+ const messageId2 = generatedId + "-message";
503
+ const controlled = value !== void 0;
504
+ const [internalValue, setInternalValue] = useState4(defaultValue);
505
+ const currentValue = controlled ? value : internalValue;
506
+ const fieldError = getFieldError(error, errorMessage);
507
+ const hasError = fieldError !== void 0 && fieldError !== false && fieldError !== null;
508
+ const resolvedDescription = description ?? helperText;
509
+ const hasMessage = hasError || resolvedDescription && descriptionDisplay === "inline";
510
+ const describedBy = getDescribedBy(
511
+ ariaDescribedBy,
512
+ hasMessage ? messageId2 : void 0
513
+ );
514
+ const resolvedPrefix = prefix ?? Prefix;
515
+ const resolvedSuffix = suffix ?? Suffix;
516
+ const labelledBy = getDescribedBy(
517
+ ariaLabelledBy,
518
+ label ? labelId : void 0
519
+ );
520
+ const clear = () => {
521
+ if (!controlled) setInternalValue("");
522
+ onValueChange?.("");
523
+ onClear?.();
524
+ };
525
+ return /* @__PURE__ */ jsxs8(
526
+ "div",
527
+ {
528
+ className: [
529
+ "fe-text-input",
530
+ hasError && "fe-text-input--error",
531
+ className
532
+ ].filter(Boolean).join(" "),
533
+ children: [
534
+ /* @__PURE__ */ jsx8(
535
+ FieldLabel,
536
+ {
537
+ id: labelId,
538
+ label,
539
+ description: resolvedDescription,
540
+ descriptionDisplay,
541
+ isRequired
542
+ }
543
+ ),
544
+ /* @__PURE__ */ jsxs8("span", { className: "fe-text-input__control", children: [
545
+ resolvedPrefix && /* @__PURE__ */ jsx8("span", { className: "fe-text-input__prefix", children: resolvedPrefix }),
546
+ /* @__PURE__ */ jsxs8("span", { className: "fe-text-input__input-wrap", children: [
547
+ /* @__PURE__ */ jsx8(
548
+ "input",
549
+ {
550
+ ref,
551
+ id: inputId,
552
+ value: currentValue,
553
+ placeholder,
554
+ required: isRequired || required,
555
+ disabled,
556
+ readOnly,
557
+ "aria-invalid": hasError || void 0,
558
+ "aria-required": isRequired || void 0,
559
+ "aria-labelledby": labelledBy,
560
+ "aria-describedby": describedBy,
561
+ onChange: (event) => {
562
+ if (!controlled) setInternalValue(event.target.value);
563
+ onValueChange?.(event.target.value);
564
+ onChange?.(event);
565
+ },
566
+ ...props
567
+ }
568
+ ),
569
+ isRequired && placeholder && !currentValue && /* @__PURE__ */ jsxs8("span", { className: "fe-text-input__placeholder", "aria-hidden": "true", children: [
570
+ /* @__PURE__ */ jsx8("span", { children: placeholder }),
571
+ /* @__PURE__ */ jsx8("span", { className: "fe-field__required", children: "*" })
572
+ ] })
573
+ ] }),
574
+ resolvedSuffix && /* @__PURE__ */ jsx8("span", { className: "fe-text-input__suffix", children: resolvedSuffix }),
575
+ clearable && currentValue && !disabled && !readOnly && /* @__PURE__ */ jsx8(
576
+ Button,
577
+ {
578
+ hierarchy: "tertiary-gray",
579
+ size: "24",
580
+ iconOnly: true,
581
+ icon: /* @__PURE__ */ jsx8(CloseIcon, { size: 14 }),
582
+ "aria-label": clearLabel,
583
+ onClick: clear,
584
+ className: "fe-text-input__clear"
585
+ }
586
+ )
587
+ ] }),
588
+ /* @__PURE__ */ jsx8(
589
+ FieldMessage,
590
+ {
591
+ id: messageId2,
592
+ error: fieldError,
593
+ description: resolvedDescription,
594
+ descriptionDisplay
595
+ }
596
+ )
597
+ ]
598
+ }
599
+ );
600
+ }
601
+ );
435
602
  TextInput.displayName = "TextInput";
436
- var TextArea = forwardRef3(function TextArea2({ value, defaultValue = "", onChange, onValueChange, label, helperText, error, errorMessage, clearable = false, onClear, clearLabel = "Clear text area", className, disabled, readOnly, id, "aria-describedby": ariaDescribedBy, "aria-labelledby": ariaLabelledBy, ...props }, ref) {
437
- const generatedId = useId();
438
- const inputId = id ?? `${generatedId}-input`;
439
- const labelId = `${generatedId}-label`;
440
- const messageId2 = `${generatedId}-message`;
441
- const controlled = value !== void 0;
442
- const [internalValue, setInternalValue] = useState3(defaultValue);
443
- const currentValue = controlled ? value : internalValue;
444
- const fieldError = getFieldError(error, errorMessage);
445
- const hasError = fieldError !== void 0 && fieldError !== false && fieldError !== null;
446
- const displayedMessage = hasError ? fieldError : helperText;
447
- const describedBy = getDescribedBy(ariaDescribedBy, displayedMessage ? messageId2 : void 0);
448
- const clear = () => {
449
- if (!controlled) setInternalValue("");
450
- onValueChange?.("");
451
- onClear?.();
452
- };
453
- const labelledBy = getDescribedBy(ariaLabelledBy, label ? labelId : void 0);
454
- return /* @__PURE__ */ jsxs7("label", { className: ["fe-text-area", hasError && "fe-text-area--error", className].filter(Boolean).join(" "), children: [
455
- label && /* @__PURE__ */ jsx7("span", { id: labelId, className: "fe-text-area__label", children: label }),
456
- /* @__PURE__ */ jsxs7("span", { className: "fe-text-area__control", children: [
457
- /* @__PURE__ */ jsx7("textarea", { ref, id: inputId, value: currentValue, disabled, readOnly, "aria-invalid": hasError || void 0, "aria-labelledby": labelledBy, "aria-describedby": describedBy, onChange: (event) => {
458
- if (!controlled) setInternalValue(event.target.value);
459
- onValueChange?.(event.target.value);
460
- onChange?.(event);
461
- }, ...props }),
462
- clearable && currentValue && !disabled && !readOnly && /* @__PURE__ */ jsx7(Button, { hierarchy: "tertiary-gray", size: "24", iconOnly: true, icon: /* @__PURE__ */ jsx7(CloseIcon, { size: 14 }), "aria-label": clearLabel, onClick: clear, className: "fe-text-area__clear" })
463
- ] }),
464
- displayedMessage && /* @__PURE__ */ jsx7("span", { id: messageId2, className: hasError ? "fe-text-area__error" : "fe-text-area__helper", children: displayedMessage })
465
- ] });
466
- });
603
+
604
+ // packages/form-controls/src/controls/TextArea/text-area.tsx
605
+ import { forwardRef as forwardRef4, useId as useId3, useState as useState5 } from "react";
606
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
607
+ var TextArea = forwardRef4(
608
+ function TextArea2({
609
+ value,
610
+ defaultValue = "",
611
+ onChange,
612
+ onValueChange,
613
+ label,
614
+ description,
615
+ descriptionDisplay = "inline",
616
+ helperText,
617
+ error,
618
+ errorMessage,
619
+ clearable = false,
620
+ onClear,
621
+ clearLabel = "Clear text area",
622
+ className,
623
+ disabled,
624
+ readOnly,
625
+ id,
626
+ isRequired = false,
627
+ placeholder,
628
+ required,
629
+ "aria-describedby": ariaDescribedBy,
630
+ "aria-labelledby": ariaLabelledBy,
631
+ ...props
632
+ }, ref) {
633
+ const generatedId = useId3();
634
+ const inputId = id ?? generatedId + "-input";
635
+ const labelId = generatedId + "-label";
636
+ const messageId2 = generatedId + "-message";
637
+ const controlled = value !== void 0;
638
+ const [internalValue, setInternalValue] = useState5(defaultValue);
639
+ const currentValue = controlled ? value : internalValue;
640
+ const fieldError = getFieldError(error, errorMessage);
641
+ const hasError = fieldError !== void 0 && fieldError !== false && fieldError !== null;
642
+ const resolvedDescription = description ?? helperText;
643
+ const hasMessage = hasError || resolvedDescription && descriptionDisplay === "inline";
644
+ const describedBy = getDescribedBy(
645
+ ariaDescribedBy,
646
+ hasMessage ? messageId2 : void 0
647
+ );
648
+ const labelledBy = getDescribedBy(
649
+ ariaLabelledBy,
650
+ label ? labelId : void 0
651
+ );
652
+ const clear = () => {
653
+ if (!controlled) setInternalValue("");
654
+ onValueChange?.("");
655
+ onClear?.();
656
+ };
657
+ return /* @__PURE__ */ jsxs9(
658
+ "div",
659
+ {
660
+ className: [
661
+ "fe-text-area",
662
+ hasError && "fe-text-area--error",
663
+ className
664
+ ].filter(Boolean).join(" "),
665
+ children: [
666
+ /* @__PURE__ */ jsx9(
667
+ FieldLabel,
668
+ {
669
+ id: labelId,
670
+ label,
671
+ description: resolvedDescription,
672
+ descriptionDisplay,
673
+ isRequired
674
+ }
675
+ ),
676
+ /* @__PURE__ */ jsxs9("span", { className: "fe-text-area__control", children: [
677
+ /* @__PURE__ */ jsx9(
678
+ "textarea",
679
+ {
680
+ ref,
681
+ id: inputId,
682
+ value: currentValue,
683
+ placeholder,
684
+ required: isRequired || required,
685
+ disabled,
686
+ readOnly,
687
+ "aria-invalid": hasError || void 0,
688
+ "aria-required": isRequired || void 0,
689
+ "aria-labelledby": labelledBy,
690
+ "aria-describedby": describedBy,
691
+ onChange: (event) => {
692
+ if (!controlled) setInternalValue(event.target.value);
693
+ onValueChange?.(event.target.value);
694
+ onChange?.(event);
695
+ },
696
+ ...props
697
+ }
698
+ ),
699
+ isRequired && placeholder && !currentValue && /* @__PURE__ */ jsxs9("span", { className: "fe-text-area__placeholder", "aria-hidden": "true", children: [
700
+ /* @__PURE__ */ jsx9("span", { children: placeholder }),
701
+ /* @__PURE__ */ jsx9("span", { className: "fe-field__required", children: "*" })
702
+ ] }),
703
+ clearable && currentValue && !disabled && !readOnly && /* @__PURE__ */ jsx9(
704
+ Button,
705
+ {
706
+ hierarchy: "tertiary-gray",
707
+ size: "24",
708
+ iconOnly: true,
709
+ icon: /* @__PURE__ */ jsx9(CloseIcon, { size: 14 }),
710
+ "aria-label": clearLabel,
711
+ onClick: clear,
712
+ className: "fe-text-area__clear"
713
+ }
714
+ )
715
+ ] }),
716
+ /* @__PURE__ */ jsx9(
717
+ FieldMessage,
718
+ {
719
+ id: messageId2,
720
+ error: fieldError,
721
+ description: resolvedDescription,
722
+ descriptionDisplay
723
+ }
724
+ )
725
+ ]
726
+ }
727
+ );
728
+ }
729
+ );
467
730
  TextArea.displayName = "TextArea";
468
- var Selection = forwardRef3(function Selection2({ className, label, helperText, error, options, placeholder = "Select an option", size = "medium", id, value, defaultValue, onChange, multiple = false, searchable = false, tag = false, clearable = false, disabled = false, name, onKeyDown, ...props }, ref) {
469
- const generatedId = useId();
470
- const listboxId = id ?? generatedId;
471
- const isControlled = value !== void 0;
472
- const [internalValue, setInternalValue] = useState3(defaultValue ?? (multiple ? [] : ""));
473
- const selectedValue = isControlled ? value : internalValue;
474
- const selectedValues = Array.isArray(selectedValue) ? selectedValue : selectedValue === "" || selectedValue === null || selectedValue === void 0 ? [] : [selectedValue];
475
- const selectedOptions = options.filter((option) => selectedValues.some((item) => String(item) === String(option.value)));
476
- const [open, setOpen] = useState3(false);
477
- const [query, setQuery] = useState3("");
478
- const [activeIndex, setActiveIndex] = useState3(0);
479
- const rootRef = useRef2(null);
480
- useEffect3(() => {
481
- const close = (event) => {
482
- if (!rootRef.current?.contains(event.target)) setOpen(false);
731
+
732
+ // packages/form-controls/src/controls/Selection/selection.tsx
733
+ import {
734
+ forwardRef as forwardRef5,
735
+ useEffect as useEffect3,
736
+ useId as useId4,
737
+ useLayoutEffect,
738
+ useRef as useRef2,
739
+ useState as useState6
740
+ } from "react";
741
+ import { createPortal as createPortal2 } from "react-dom";
742
+ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
743
+ var Selection = forwardRef5(
744
+ function Selection2({
745
+ className,
746
+ label,
747
+ isRequired = false,
748
+ description,
749
+ descriptionDisplay = "inline",
750
+ helperText,
751
+ error,
752
+ errorMessage,
753
+ options,
754
+ placeholder = "Select an option",
755
+ size = "medium",
756
+ id,
757
+ value,
758
+ defaultValue,
759
+ onChange,
760
+ multiple = false,
761
+ searchable = false,
762
+ tag = false,
763
+ clearable = false,
764
+ disabled = false,
765
+ name,
766
+ onKeyDown,
767
+ "aria-label": ariaLabel,
768
+ "aria-describedby": ariaDescribedBy,
769
+ "aria-labelledby": ariaLabelledBy,
770
+ ...props
771
+ }, ref) {
772
+ const generatedId = useId4();
773
+ const triggerId = id ?? generatedId + "-trigger";
774
+ const listboxId = triggerId + "-listbox";
775
+ const labelId = generatedId + "-label";
776
+ const messageId2 = generatedId + "-message";
777
+ const fieldError = getFieldError(error, errorMessage);
778
+ const hasError = fieldError !== void 0 && fieldError !== false && fieldError !== null;
779
+ const resolvedDescription = description ?? helperText;
780
+ const hasMessage = hasError || resolvedDescription && descriptionDisplay === "inline";
781
+ const describedBy = getDescribedBy(
782
+ ariaDescribedBy,
783
+ hasMessage ? messageId2 : void 0
784
+ );
785
+ const labelledBy = getDescribedBy(
786
+ ariaLabelledBy,
787
+ label ? labelId : void 0
788
+ );
789
+ const isControlled = value !== void 0;
790
+ const [internalValue, setInternalValue] = useState6(
791
+ defaultValue ?? (multiple ? [] : "")
792
+ );
793
+ const selectedValue = isControlled ? value : internalValue;
794
+ const selectedValues = Array.isArray(selectedValue) ? selectedValue : selectedValue === "" || selectedValue === null || selectedValue === void 0 ? [] : [selectedValue];
795
+ const selectedOptions = options.filter(
796
+ (option) => selectedValues.some((item) => String(item) === String(option.value))
797
+ );
798
+ const [open, setOpen] = useState6(false);
799
+ const [query, setQuery] = useState6("");
800
+ const [activeIndex, setActiveIndex] = useState6(0);
801
+ const rootRef = useRef2(null);
802
+ const menuRef = useRef2(null);
803
+ const [menuPosition, setMenuPosition] = useState6(null);
804
+ useEffect3(() => {
805
+ const close = (event) => {
806
+ const target = event.target;
807
+ if (!rootRef.current?.contains(target) && !menuRef.current?.contains(target))
808
+ setOpen(false);
809
+ };
810
+ document.addEventListener("mousedown", close);
811
+ return () => document.removeEventListener("mousedown", close);
812
+ }, []);
813
+ useLayoutEffect(() => {
814
+ if (!open) return;
815
+ const updateMenuPosition = () => {
816
+ const rect = rootRef.current?.getBoundingClientRect();
817
+ if (rect)
818
+ setMenuPosition({
819
+ top: rect.bottom + 7,
820
+ left: rect.left,
821
+ width: rect.width
822
+ });
823
+ };
824
+ updateMenuPosition();
825
+ window.addEventListener("resize", updateMenuPosition);
826
+ document.addEventListener("scroll", updateMenuPosition, true);
827
+ return () => {
828
+ window.removeEventListener("resize", updateMenuPosition);
829
+ document.removeEventListener("scroll", updateMenuPosition, true);
830
+ };
831
+ }, [open]);
832
+ const filteredOptions = options.filter(
833
+ (option) => !query || (option.searchText ?? (typeof option.label === "string" ? option.label : String(option.value))).toLowerCase().includes(query.toLowerCase())
834
+ );
835
+ const commit = (next) => {
836
+ if (!isControlled) setInternalValue(next);
837
+ const selected = options.filter(
838
+ (option) => (Array.isArray(next) ? next : [next]).some(
839
+ (item) => String(item) === String(option.value)
840
+ )
841
+ );
842
+ onChange?.(next, multiple ? selected : selected[0]);
483
843
  };
484
- document.addEventListener("mousedown", close);
485
- return () => document.removeEventListener("mousedown", close);
486
- }, []);
487
- const filteredOptions = options.filter((option) => !query || (option.searchText ?? (typeof option.label === "string" ? option.label : String(option.value))).toLowerCase().includes(query.toLowerCase()));
488
- const commit = (next) => {
489
- if (!isControlled) setInternalValue(next);
490
- const selected = options.filter((option) => (Array.isArray(next) ? next : [next]).some((item) => String(item) === String(option.value)));
491
- onChange?.(next, multiple ? selected : selected[0]);
492
- };
493
- const choose = (option) => {
494
- if (option.disabled) return;
495
- const isSelected = selectedValues.some((item) => String(item) === String(option.value));
496
- if (multiple) commit(isSelected ? selectedValues.filter((item) => String(item) !== String(option.value)) : [...selectedValues, option.value]);
497
- else {
498
- commit(option.value);
499
- setOpen(false);
844
+ const choose = (option) => {
845
+ if (option.disabled) return;
846
+ const isSelected = selectedValues.some(
847
+ (item) => String(item) === String(option.value)
848
+ );
849
+ if (multiple)
850
+ commit(
851
+ isSelected ? selectedValues.filter(
852
+ (item) => String(item) !== String(option.value)
853
+ ) : [...selectedValues, option.value]
854
+ );
855
+ else {
856
+ commit(option.value);
857
+ setOpen(false);
858
+ setQuery("");
859
+ }
860
+ };
861
+ const clear = () => {
862
+ commit(multiple ? [] : "");
500
863
  setQuery("");
501
- }
502
- };
503
- const clear = () => {
504
- commit(multiple ? [] : "");
505
- setQuery("");
506
- };
507
- const displayLabel = selectedOptions.length ? selectedOptions.map((option) => option.label) : null;
508
- const onTriggerKeyDown = (event) => {
509
- onKeyDown?.(event);
510
- if (disabled) return;
511
- if (event.key === "ArrowDown" || event.key === "ArrowUp") {
512
- event.preventDefault();
513
- setOpen(true);
514
- setActiveIndex((current) => Math.max(0, Math.min(filteredOptions.length - 1, current + (event.key === "ArrowDown" ? 1 : -1))));
515
- }
516
- if (event.key === "Enter" || event.key === " ") {
517
- event.preventDefault();
518
- if (!open) setOpen(true);
519
- else if (filteredOptions[activeIndex]) choose(filteredOptions[activeIndex]);
520
- }
521
- if (event.key === "Escape") setOpen(false);
522
- };
523
- return /* @__PURE__ */ jsxs7("div", { ref, className: ["fe-selection", `fe-selection--${size}`, open && "fe-selection--open", clearable && selectedOptions.length > 0 && "fe-selection--clearable", error && "fe-selection--error", disabled && "fe-selection--disabled", className].filter(Boolean).join(" "), ...props, children: [
524
- label && /* @__PURE__ */ jsx7("span", { className: "fe-selection__label", children: label }),
525
- /* @__PURE__ */ jsxs7("div", { ref: rootRef, className: "fe-selection__control", children: [
526
- name && selectedValues.map((item) => /* @__PURE__ */ jsx7("input", { type: "hidden", name: multiple ? `${name}[]` : name, value: item }, String(item))),
527
- /* @__PURE__ */ jsxs7("button", { type: "button", className: "fe-selection__trigger", disabled, "aria-invalid": error || void 0, "aria-haspopup": "listbox", "aria-expanded": open, "aria-controls": listboxId, onClick: () => setOpen((current) => !current), onKeyDown: onTriggerKeyDown, children: [
528
- /* @__PURE__ */ jsx7("span", { className: ["fe-selection__value", !selectedOptions.length && "is-placeholder", tag && selectedOptions.length > 1 && "is-tags"].filter(Boolean).join(" "), children: displayLabel ? tag && multiple ? selectedOptions.map((option) => /* @__PURE__ */ jsxs7("span", { className: "fe-selection__tag", children: [
529
- option.label,
530
- /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\xD7" })
531
- ] }, String(option.value))) : displayLabel.map((item, index) => /* @__PURE__ */ jsxs7("span", { children: [
532
- item,
533
- index < displayLabel.length - 1 ? ", " : ""
534
- ] }, index)) : placeholder }),
535
- /* @__PURE__ */ jsx7("span", { className: "fe-selection__actions", children: /* @__PURE__ */ jsx7("span", { className: "fe-selection__chevron", "aria-hidden": "true" }) })
536
- ] }),
537
- clearable && selectedOptions.length > 0 && /* @__PURE__ */ jsx7("button", { type: "button", className: "fe-selection__clear", "aria-label": "Clear selection", onClick: clear }),
538
- open && /* @__PURE__ */ jsxs7("div", { id: listboxId, className: "fe-selection__menu", role: "listbox", "aria-multiselectable": multiple || void 0, children: [
539
- searchable && /* @__PURE__ */ jsxs7("div", { className: "fe-selection__search", children: [
540
- /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\u2315" }),
541
- /* @__PURE__ */ jsx7("input", { autoFocus: true, value: query, onChange: (event) => {
542
- setQuery(event.target.value);
543
- setActiveIndex(0);
544
- }, placeholder: "Search\u2026", "aria-label": "Search options" })
545
- ] }),
546
- /* @__PURE__ */ jsx7("div", { className: "fe-selection__options", children: filteredOptions.length ? filteredOptions.map((option, index) => {
547
- const isSelected = selectedValues.some((item) => String(item) === String(option.value));
548
- return /* @__PURE__ */ jsxs7("button", { type: "button", className: [isSelected && "is-selected", index === activeIndex && "is-active"].filter(Boolean).join(" "), role: "option", "aria-selected": isSelected, disabled: option.disabled, onMouseMove: () => setActiveIndex(index), onClick: () => choose(option), children: [
549
- /* @__PURE__ */ jsx7("span", { children: option.label }),
550
- isSelected && /* @__PURE__ */ jsx7("span", { className: "fe-selection__check", "aria-hidden": "true", children: "\u2713" })
551
- ] }, String(option.value));
552
- }) : /* @__PURE__ */ jsx7("p", { className: "fe-selection__empty", children: "No matching options" }) })
553
- ] })
554
- ] }),
555
- helperText && /* @__PURE__ */ jsx7("span", { className: "fe-selection__helper", children: helperText })
556
- ] });
557
- });
864
+ };
865
+ const displayLabel = selectedOptions.length ? selectedOptions.map((option) => option.label) : null;
866
+ const onTriggerKeyDown = (event) => {
867
+ onKeyDown?.(event);
868
+ if (disabled) return;
869
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
870
+ event.preventDefault();
871
+ setOpen(true);
872
+ setActiveIndex(
873
+ (current) => Math.max(
874
+ 0,
875
+ Math.min(
876
+ filteredOptions.length - 1,
877
+ current + (event.key === "ArrowDown" ? 1 : -1)
878
+ )
879
+ )
880
+ );
881
+ }
882
+ if (event.key === "Enter" || event.key === " ") {
883
+ event.preventDefault();
884
+ if (!open) setOpen(true);
885
+ else if (filteredOptions[activeIndex])
886
+ choose(filteredOptions[activeIndex]);
887
+ }
888
+ if (event.key === "Escape") setOpen(false);
889
+ };
890
+ return /* @__PURE__ */ jsxs10(
891
+ "div",
892
+ {
893
+ ref,
894
+ className: [
895
+ "fe-selection",
896
+ "fe-selection--" + size,
897
+ open && "fe-selection--open",
898
+ clearable && selectedOptions.length > 0 && "fe-selection--clearable",
899
+ hasError && "fe-selection--error",
900
+ disabled && "fe-selection--disabled",
901
+ className
902
+ ].filter(Boolean).join(" "),
903
+ ...props,
904
+ children: [
905
+ /* @__PURE__ */ jsx10(
906
+ FieldLabel,
907
+ {
908
+ id: labelId,
909
+ label,
910
+ description: resolvedDescription,
911
+ descriptionDisplay,
912
+ isRequired
913
+ }
914
+ ),
915
+ /* @__PURE__ */ jsxs10("div", { ref: rootRef, className: "fe-selection__control", children: [
916
+ name && selectedValues.map((item) => /* @__PURE__ */ jsx10(
917
+ "input",
918
+ {
919
+ type: "hidden",
920
+ name: multiple ? name + "[]" : name,
921
+ value: item
922
+ },
923
+ String(item)
924
+ )),
925
+ /* @__PURE__ */ jsxs10(
926
+ "button",
927
+ {
928
+ id: triggerId,
929
+ type: "button",
930
+ className: "fe-selection__trigger",
931
+ disabled,
932
+ "aria-label": ariaLabel,
933
+ "aria-invalid": hasError || void 0,
934
+ "aria-required": isRequired || void 0,
935
+ "aria-labelledby": labelledBy,
936
+ "aria-describedby": describedBy,
937
+ "aria-haspopup": "listbox",
938
+ "aria-expanded": open,
939
+ "aria-controls": listboxId,
940
+ onClick: () => setOpen((current) => !current),
941
+ onKeyDown: onTriggerKeyDown,
942
+ children: [
943
+ /* @__PURE__ */ jsx10(
944
+ "span",
945
+ {
946
+ className: [
947
+ "fe-selection__value",
948
+ !selectedOptions.length && "is-placeholder",
949
+ tag && selectedOptions.length > 1 && "is-tags"
950
+ ].filter(Boolean).join(" "),
951
+ children: displayLabel ? tag && multiple ? selectedOptions.map((option) => /* @__PURE__ */ jsxs10(
952
+ "span",
953
+ {
954
+ className: "fe-selection__tag",
955
+ children: [
956
+ option.label,
957
+ /* @__PURE__ */ jsx10("span", { "aria-hidden": "true", children: "\xD7" })
958
+ ]
959
+ },
960
+ String(option.value)
961
+ )) : displayLabel.map((item, index) => /* @__PURE__ */ jsxs10("span", { children: [
962
+ item,
963
+ index < displayLabel.length - 1 ? ", " : ""
964
+ ] }, index)) : /* @__PURE__ */ jsxs10(Fragment2, { children: [
965
+ /* @__PURE__ */ jsx10("span", { children: placeholder }),
966
+ isRequired && /* @__PURE__ */ jsx10("span", { className: "fe-field__required", "aria-hidden": "true", children: "*" })
967
+ ] })
968
+ }
969
+ ),
970
+ /* @__PURE__ */ jsx10("span", { className: "fe-selection__actions", children: /* @__PURE__ */ jsx10("span", { className: "fe-selection__chevron", "aria-hidden": "true" }) })
971
+ ]
972
+ }
973
+ ),
974
+ clearable && selectedOptions.length > 0 && !disabled && /* @__PURE__ */ jsx10(
975
+ "button",
976
+ {
977
+ type: "button",
978
+ className: "fe-selection__clear",
979
+ "aria-label": "Clear selection",
980
+ onClick: clear
981
+ }
982
+ ),
983
+ open && menuPosition && createPortal2(
984
+ /* @__PURE__ */ jsxs10(
985
+ "div",
986
+ {
987
+ ref: menuRef,
988
+ id: listboxId,
989
+ className: "fe-selection__menu",
990
+ style: {
991
+ position: "fixed",
992
+ top: menuPosition.top,
993
+ left: menuPosition.left,
994
+ width: menuPosition.width
995
+ },
996
+ role: "listbox",
997
+ "aria-multiselectable": multiple || void 0,
998
+ children: [
999
+ searchable && /* @__PURE__ */ jsxs10("div", { className: "fe-selection__search", children: [
1000
+ /* @__PURE__ */ jsx10("span", { "aria-hidden": "true", children: "\u2315" }),
1001
+ /* @__PURE__ */ jsx10(
1002
+ "input",
1003
+ {
1004
+ autoFocus: true,
1005
+ value: query,
1006
+ onChange: (event) => {
1007
+ setQuery(event.target.value);
1008
+ setActiveIndex(0);
1009
+ },
1010
+ placeholder: "Search\u2026",
1011
+ "aria-label": "Search options"
1012
+ }
1013
+ )
1014
+ ] }),
1015
+ /* @__PURE__ */ jsx10("div", { className: "fe-selection__options", children: filteredOptions.length ? filteredOptions.map((option, index) => {
1016
+ const isSelected = selectedValues.some(
1017
+ (item) => String(item) === String(option.value)
1018
+ );
1019
+ return /* @__PURE__ */ jsxs10(
1020
+ "button",
1021
+ {
1022
+ type: "button",
1023
+ className: [
1024
+ isSelected && "is-selected",
1025
+ index === activeIndex && "is-active"
1026
+ ].filter(Boolean).join(" "),
1027
+ role: "option",
1028
+ "aria-selected": isSelected,
1029
+ disabled: option.disabled,
1030
+ onMouseMove: () => setActiveIndex(index),
1031
+ onClick: () => choose(option),
1032
+ children: [
1033
+ /* @__PURE__ */ jsx10("span", { children: option.label }),
1034
+ isSelected && /* @__PURE__ */ jsx10(
1035
+ "span",
1036
+ {
1037
+ className: "fe-selection__check",
1038
+ "aria-hidden": "true",
1039
+ children: "\u2713"
1040
+ }
1041
+ )
1042
+ ]
1043
+ },
1044
+ String(option.value)
1045
+ );
1046
+ }) : /* @__PURE__ */ jsx10("p", { className: "fe-selection__empty", children: "No matching options" }) })
1047
+ ]
1048
+ }
1049
+ ),
1050
+ document.body
1051
+ )
1052
+ ] }),
1053
+ /* @__PURE__ */ jsx10(
1054
+ FieldMessage,
1055
+ {
1056
+ id: messageId2,
1057
+ error: fieldError,
1058
+ description: resolvedDescription,
1059
+ descriptionDisplay
1060
+ }
1061
+ )
1062
+ ]
1063
+ }
1064
+ );
1065
+ }
1066
+ );
558
1067
  Selection.displayName = "Selection";
1068
+
1069
+ // packages/form-controls/src/controls/NumberInput/number-input.tsx
1070
+ import { forwardRef as forwardRef6, useEffect as useEffect4, useId as useId5, useState as useState7 } from "react";
1071
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
559
1072
  function formatNumber(value, decimals = 2, thousandSeparator = ",", decimalSeparator = ".") {
560
1073
  return new Intl.NumberFormat("en-US", {
561
1074
  minimumFractionDigits: 0,
@@ -564,7 +1077,7 @@ function formatNumber(value, decimals = 2, thousandSeparator = ",", decimalSepar
564
1077
  }).format(value).replace(/,/g, thousandSeparator).replace(/\./g, decimalSeparator);
565
1078
  }
566
1079
  function escapeRegExp(value) {
567
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1080
+ return value.replace(/[.*+?^$\x7B\x7D()|[\]\\]/g, "\\$&");
568
1081
  }
569
1082
  function groupInteger(value, separator) {
570
1083
  return value.replace(/\B(?=(\d{3})+(?!\d))/g, separator);
@@ -573,7 +1086,10 @@ function normalizeNumberInput(raw, options) {
573
1086
  const { allowDecimal, decimalSeparator, thousandSeparator, min, max } = options;
574
1087
  const decimals = Math.max(0, options.decimals);
575
1088
  const negative = raw.trimStart().startsWith("-") && (min === void 0 || min < 0);
576
- const decimalExpression = new RegExp(`[^0-9${allowDecimal ? escapeRegExp(decimalSeparator) : ""}]`, "g");
1089
+ const decimalExpression = new RegExp(
1090
+ "[^0-9" + (allowDecimal ? escapeRegExp(decimalSeparator) : "") + "]",
1091
+ "g"
1092
+ );
577
1093
  const cleaned = raw.replace(decimalExpression, "");
578
1094
  const decimalIndex = allowDecimal ? cleaned.indexOf(decimalSeparator) : -1;
579
1095
  const hasDecimal = decimalIndex >= 0;
@@ -581,64 +1097,227 @@ function normalizeNumberInput(raw, options) {
581
1097
  const rawFraction = hasDecimal ? cleaned.slice(decimalIndex + decimalSeparator.length).replace(new RegExp(escapeRegExp(decimalSeparator), "g"), "") : "";
582
1098
  const integer = rawInteger.replace(/^0+(?=\d)/, "") || (rawInteger ? "0" : "");
583
1099
  const fraction = rawFraction.slice(0, decimals);
584
- if (!integer && !fraction) return { display: negative ? "-" : "", value: null };
585
- const numericValue = Number(`${negative ? "-" : ""}${integer || "0"}${hasDecimal ? `.${fraction || "0"}` : ""}`);
1100
+ if (!integer && !fraction)
1101
+ return { display: negative ? "-" : "", value: null };
1102
+ const numericValue = Number(
1103
+ (negative ? "-" : "") + (integer || "0") + (hasDecimal ? "." + (fraction || "0") : "")
1104
+ );
586
1105
  if (!Number.isFinite(numericValue)) return { display: "", value: null };
587
1106
  const lowerBound = min === void 0 ? numericValue : Math.max(numericValue, min);
588
1107
  const value = max === void 0 ? lowerBound : Math.min(lowerBound, max);
589
- if (value !== numericValue) return { display: formatNumber(value, decimals, thousandSeparator, decimalSeparator), value };
590
- return { display: `${negative ? "-" : ""}${groupInteger(integer || "0", thousandSeparator)}${hasDecimal ? `${decimalSeparator}${fraction}` : ""}`, value };
591
- }
592
- var NumberInput = forwardRef3(function NumberInput2({ value, defaultValue = null, onValueChange, allowDecimal = true, decimals = 2, min, max, decimalSeparator = ".", thousandSeparator = ",", label, helperText, error, errorMessage, className, onBlur, onFocus, "aria-describedby": ariaDescribedBy, ...props }, ref) {
593
- const generatedId = useId();
594
- const messageId2 = `${generatedId}-message`;
595
- const isControlled = value !== void 0;
596
- const [internalValue, setInternalValue] = useState3(defaultValue);
597
- const [focused, setFocused] = useState3(false);
598
- const actualValue = isControlled ? value ?? null : internalValue;
599
- const [text, setText] = useState3(actualValue === null ? "" : formatNumber(actualValue, decimals, thousandSeparator, decimalSeparator));
600
- const fieldError = getFieldError(error, errorMessage);
601
- const hasError = fieldError !== void 0 && fieldError !== false && fieldError !== null;
602
- const displayedMessage = hasError ? fieldError : helperText;
603
- const describedBy = getDescribedBy(ariaDescribedBy, displayedMessage ? messageId2 : void 0);
604
- useEffect3(() => {
605
- if (!focused) setText(actualValue === null ? "" : formatNumber(actualValue, decimals, thousandSeparator, decimalSeparator));
606
- }, [actualValue, decimalSeparator, decimals, focused, thousandSeparator]);
607
- const updateValue = (nextText) => {
608
- const next = normalizeNumberInput(nextText, { allowDecimal, decimals, decimalSeparator, thousandSeparator, min, max });
609
- setText(next.display);
610
- const nextValue = next.value;
611
- if (!isControlled) setInternalValue(nextValue);
612
- onValueChange?.(nextValue);
1108
+ if (value !== numericValue)
1109
+ return {
1110
+ display: formatNumber(
1111
+ value,
1112
+ decimals,
1113
+ thousandSeparator,
1114
+ decimalSeparator
1115
+ ),
1116
+ value
1117
+ };
1118
+ return {
1119
+ display: (negative ? "-" : "") + groupInteger(integer || "0", thousandSeparator) + (hasDecimal ? decimalSeparator + fraction : ""),
1120
+ value
613
1121
  };
614
- return /* @__PURE__ */ jsxs7("label", { className: ["fe-number-input", hasError && "fe-number-input--error", className].filter(Boolean).join(" "), children: [
615
- label && /* @__PURE__ */ jsx7("span", { className: "fe-number-input__label", children: label }),
616
- /* @__PURE__ */ jsx7("input", { ref, inputMode: allowDecimal ? "decimal" : "numeric", value: text, onFocus: (event) => {
617
- setFocused(true);
618
- onFocus?.(event);
619
- }, onChange: (event) => updateValue(event.target.value), onBlur: (event) => {
620
- setFocused(false);
621
- onBlur?.(event);
622
- }, ...props, "aria-invalid": hasError || void 0, "aria-describedby": describedBy }),
623
- displayedMessage && /* @__PURE__ */ jsx7("span", { id: messageId2, className: hasError ? "fe-number-input__error" : "fe-number-input__helper", children: displayedMessage })
624
- ] });
625
- });
1122
+ }
1123
+ var NumberInput = forwardRef6(
1124
+ function NumberInput2({
1125
+ value,
1126
+ defaultValue = null,
1127
+ onValueChange,
1128
+ allowDecimal = true,
1129
+ decimals = 2,
1130
+ min,
1131
+ max,
1132
+ decimalSeparator = ".",
1133
+ thousandSeparator = ",",
1134
+ label,
1135
+ description,
1136
+ descriptionDisplay = "inline",
1137
+ helperText,
1138
+ error,
1139
+ errorMessage,
1140
+ isRequired = false,
1141
+ className,
1142
+ onBlur,
1143
+ onFocus,
1144
+ placeholder,
1145
+ required,
1146
+ endAdornment,
1147
+ "aria-describedby": ariaDescribedBy,
1148
+ "aria-labelledby": ariaLabelledBy,
1149
+ ...props
1150
+ }, ref) {
1151
+ const generatedId = useId5();
1152
+ const messageId2 = generatedId + "-message";
1153
+ const isControlled = value !== void 0;
1154
+ const [internalValue, setInternalValue] = useState7(defaultValue);
1155
+ const [focused, setFocused] = useState7(false);
1156
+ const actualValue = isControlled ? value ?? null : internalValue;
1157
+ const [text, setText] = useState7(
1158
+ actualValue === null ? "" : formatNumber(
1159
+ actualValue,
1160
+ decimals,
1161
+ thousandSeparator,
1162
+ decimalSeparator
1163
+ )
1164
+ );
1165
+ const fieldError = getFieldError(error, errorMessage);
1166
+ const hasError = fieldError !== void 0 && fieldError !== false && fieldError !== null;
1167
+ const labelId = generatedId + "-label";
1168
+ const resolvedDescription = description ?? helperText;
1169
+ const hasMessage = hasError || resolvedDescription && descriptionDisplay === "inline";
1170
+ const describedBy = getDescribedBy(
1171
+ ariaDescribedBy,
1172
+ hasMessage ? messageId2 : void 0
1173
+ );
1174
+ const labelledBy = getDescribedBy(
1175
+ ariaLabelledBy,
1176
+ label ? labelId : void 0
1177
+ );
1178
+ useEffect4(() => {
1179
+ if (!focused)
1180
+ setText(
1181
+ actualValue === null ? "" : formatNumber(
1182
+ actualValue,
1183
+ decimals,
1184
+ thousandSeparator,
1185
+ decimalSeparator
1186
+ )
1187
+ );
1188
+ }, [actualValue, decimalSeparator, decimals, focused, thousandSeparator]);
1189
+ const updateValue = (nextText) => {
1190
+ const next = normalizeNumberInput(nextText, {
1191
+ allowDecimal,
1192
+ decimals,
1193
+ decimalSeparator,
1194
+ thousandSeparator,
1195
+ min,
1196
+ max
1197
+ });
1198
+ setText(next.display);
1199
+ if (!isControlled) setInternalValue(next.value);
1200
+ onValueChange?.(next.value);
1201
+ };
1202
+ return /* @__PURE__ */ jsxs11(
1203
+ "label",
1204
+ {
1205
+ className: [
1206
+ "fe-number-input",
1207
+ hasError && "fe-number-input--error",
1208
+ className
1209
+ ].filter(Boolean).join(" "),
1210
+ children: [
1211
+ /* @__PURE__ */ jsx11(
1212
+ FieldLabel,
1213
+ {
1214
+ id: labelId,
1215
+ label,
1216
+ description: resolvedDescription,
1217
+ descriptionDisplay,
1218
+ isRequired
1219
+ }
1220
+ ),
1221
+ /* @__PURE__ */ jsxs11("span", { className: "fe-number-input__control", children: [
1222
+ /* @__PURE__ */ jsx11(
1223
+ "input",
1224
+ {
1225
+ ref,
1226
+ inputMode: allowDecimal ? "decimal" : "numeric",
1227
+ value: text,
1228
+ placeholder,
1229
+ required: isRequired || required,
1230
+ onFocus: (event) => {
1231
+ setFocused(true);
1232
+ onFocus?.(event);
1233
+ },
1234
+ onChange: (event) => updateValue(event.target.value),
1235
+ onBlur: (event) => {
1236
+ setFocused(false);
1237
+ onBlur?.(event);
1238
+ },
1239
+ ...props,
1240
+ "aria-invalid": hasError || void 0,
1241
+ "aria-required": isRequired || void 0,
1242
+ "aria-labelledby": labelledBy,
1243
+ "aria-describedby": describedBy
1244
+ }
1245
+ ),
1246
+ isRequired && placeholder && !text && /* @__PURE__ */ jsxs11("span", { className: "fe-number-input__placeholder", "aria-hidden": "true", children: [
1247
+ /* @__PURE__ */ jsx11("span", { children: placeholder }),
1248
+ /* @__PURE__ */ jsx11("span", { className: "fe-field__required", children: "*" })
1249
+ ] }),
1250
+ endAdornment
1251
+ ] }),
1252
+ /* @__PURE__ */ jsx11(
1253
+ FieldMessage,
1254
+ {
1255
+ id: messageId2,
1256
+ error: fieldError,
1257
+ description: resolvedDescription,
1258
+ descriptionDisplay
1259
+ }
1260
+ )
1261
+ ]
1262
+ }
1263
+ );
1264
+ }
1265
+ );
626
1266
  NumberInput.displayName = "NumberInput";
627
- function CurrencyInput({ suffix = "VND", currencies, currency, defaultCurrency, onCurrencyChange, className, ...props }) {
628
- const [internalCurrency, setInternalCurrency] = useState3(defaultCurrency ?? currencies?.[0]?.code ?? "");
1267
+
1268
+ // packages/form-controls/src/controls/CurrencyInput/currency-input.tsx
1269
+ import { useState as useState8 } from "react";
1270
+ import { jsx as jsx12 } from "react/jsx-runtime";
1271
+ function CurrencyInput({
1272
+ suffix = "VND",
1273
+ currencies,
1274
+ currency,
1275
+ defaultCurrency,
1276
+ onCurrencyChange,
1277
+ className,
1278
+ disabled,
1279
+ ...props
1280
+ }) {
1281
+ const [internalCurrency, setInternalCurrency] = useState8(
1282
+ defaultCurrency ?? currencies?.[0]?.code ?? ""
1283
+ );
629
1284
  const selectedCurrency = currency ?? internalCurrency;
630
1285
  const current = currencies?.find((item) => item.code === selectedCurrency);
631
1286
  const currencySuffix = current?.suffix ?? current?.code ?? suffix;
632
- return /* @__PURE__ */ jsxs7("div", { className: ["fe-currency-input", className].filter(Boolean).join(" "), children: [
633
- /* @__PURE__ */ jsx7(NumberInput, { ...props, className: "fe-currency-input__number" }),
634
- currencies?.length ? /* @__PURE__ */ jsx7("select", { className: "fe-currency-input__currency", "aria-label": "Currency", value: selectedCurrency, onChange: (event) => {
635
- const next = currencies.find((item) => item.code === event.target.value);
636
- if (!next) return;
637
- if (currency === void 0) setInternalCurrency(next.code);
638
- onCurrencyChange?.(next);
639
- }, children: currencies.map((item) => /* @__PURE__ */ jsx7("option", { value: item.code, children: item.label ?? item.code }, item.code)) }) : /* @__PURE__ */ jsx7("span", { className: "fe-currency-input__suffix", children: currencySuffix })
640
- ] });
1287
+ const endAdornment = currencies?.length ? /* @__PURE__ */ jsx12(
1288
+ Selection,
1289
+ {
1290
+ className: "fe-currency-input__currency",
1291
+ "aria-label": "Currency",
1292
+ options: currencies.map((item) => ({
1293
+ label: item.label ?? item.code,
1294
+ value: item.code
1295
+ })),
1296
+ disabled,
1297
+ value: selectedCurrency,
1298
+ size: "small",
1299
+ onChange: (value) => {
1300
+ const next = currencies.find((item) => item.code === String(value));
1301
+ if (!next) return;
1302
+ if (currency === void 0) setInternalCurrency(next.code);
1303
+ onCurrencyChange?.(next);
1304
+ }
1305
+ }
1306
+ ) : /* @__PURE__ */ jsx12("span", { className: "fe-currency-input__suffix", children: currencySuffix });
1307
+ return /* @__PURE__ */ jsx12(
1308
+ NumberInput,
1309
+ {
1310
+ ...props,
1311
+ disabled,
1312
+ className: ["fe-currency-input", className].filter(Boolean).join(" "),
1313
+ endAdornment
1314
+ }
1315
+ );
641
1316
  }
1317
+
1318
+ // packages/form-controls/src/controls/DateTimePicker/date-time-picker.tsx
1319
+ import { useEffect as useEffect5, useId as useId6, useRef as useRef3, useState as useState9 } from "react";
1320
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
642
1321
  var pad = (value) => String(value).padStart(2, "0");
643
1322
  function formatDate(date, format) {
644
1323
  return format.replace(/yyyy/g, String(date.getFullYear())).replace(/MM/g, pad(date.getMonth() + 1)).replace(/dd/g, pad(date.getDate())).replace(/HH/g, pad(date.getHours())).replace(/mm/g, pad(date.getMinutes()));
@@ -656,24 +1335,66 @@ function mergeDateTime(day, time) {
656
1335
  return next;
657
1336
  }
658
1337
  function DateTimePicker(props) {
659
- const { label, format = "dd/MM/yyyy HH:mm", disabled, placeholder, locale = "en-US", className, mode = "single" } = props;
1338
+ const {
1339
+ label,
1340
+ description,
1341
+ descriptionDisplay = "inline",
1342
+ helperText,
1343
+ error,
1344
+ errorMessage,
1345
+ isRequired = false,
1346
+ format = "dd/MM/yyyy HH:mm",
1347
+ disabled,
1348
+ placeholder,
1349
+ locale = "en-US",
1350
+ className,
1351
+ mode = "single",
1352
+ id,
1353
+ "aria-describedby": ariaDescribedBy,
1354
+ "aria-labelledby": ariaLabelledBy
1355
+ } = props;
1356
+ const generatedId = useId6();
1357
+ const triggerId = id ?? generatedId + "-trigger";
1358
+ const labelId = generatedId + "-label";
1359
+ const messageId2 = generatedId + "-message";
1360
+ const fieldError = getFieldError(error, errorMessage);
1361
+ const hasError = fieldError !== void 0 && fieldError !== false && fieldError !== null;
1362
+ const resolvedDescription = description ?? helperText;
1363
+ const hasMessage = hasError || resolvedDescription && descriptionDisplay === "inline";
1364
+ const describedBy = getDescribedBy(
1365
+ ariaDescribedBy,
1366
+ hasMessage ? messageId2 : void 0
1367
+ );
1368
+ const labelledBy = getDescribedBy(
1369
+ ariaLabelledBy,
1370
+ label ? labelId : void 0
1371
+ );
660
1372
  const isRange = mode === "range";
661
1373
  const controlled = props.value !== void 0;
662
- const [singleInternal, setSingleInternal] = useState3((!isRange ? props.defaultValue : null) ?? null);
663
- const [rangeInternal, setRangeInternal] = useState3((isRange ? props.defaultValue : void 0) ?? [null, null]);
1374
+ const [singleInternal, setSingleInternal] = useState9(
1375
+ (!isRange ? props.defaultValue : null) ?? null
1376
+ );
1377
+ const [rangeInternal, setRangeInternal] = useState9(
1378
+ (isRange ? props.defaultValue : void 0) ?? [null, null]
1379
+ );
664
1380
  const singleValue = !isRange ? props.value ?? singleInternal : null;
665
1381
  const rangeValue = isRange ? props.value ?? rangeInternal : [null, null];
666
- const [open, setOpen] = useState3(false);
667
- const [month, setMonth] = useState3(() => new Date((isRange ? rangeValue[0] : singleValue) ?? /* @__PURE__ */ new Date()));
668
- const [editingEnd, setEditingEnd] = useState3(false);
669
- const rootRef = useRef2(null);
670
- useEffect3(() => {
1382
+ const [open, setOpen] = useState9(false);
1383
+ const [month, setMonth] = useState9(
1384
+ () => new Date((isRange ? rangeValue[0] : singleValue) ?? /* @__PURE__ */ new Date())
1385
+ );
1386
+ const [editingEnd, setEditingEnd] = useState9(false);
1387
+ const rootRef = useRef3(null);
1388
+ useEffect5(() => {
671
1389
  const onPointerDown = (event) => {
672
1390
  if (!rootRef.current?.contains(event.target)) setOpen(false);
673
1391
  };
674
1392
  document.addEventListener("mousedown", onPointerDown);
675
1393
  return () => document.removeEventListener("mousedown", onPointerDown);
676
1394
  }, []);
1395
+ useEffect5(() => {
1396
+ if (disabled) setOpen(false);
1397
+ }, [disabled]);
677
1398
  const setSingle = (next) => {
678
1399
  if (!controlled) setSingleInternal(next);
679
1400
  props.onChange?.(next);
@@ -684,13 +1405,24 @@ function DateTimePicker(props) {
684
1405
  };
685
1406
  const selectDay = (day) => {
686
1407
  if (!isRange) {
687
- setSingle(mergeDateTime(day, singleValue ? `${pad(singleValue.getHours())}:${pad(singleValue.getMinutes())}` : "00:00"));
1408
+ setSingle(
1409
+ mergeDateTime(
1410
+ day,
1411
+ singleValue ? pad(singleValue.getHours()) + ":" + pad(singleValue.getMinutes()) : "00:00"
1412
+ )
1413
+ );
688
1414
  setOpen(false);
689
1415
  return;
690
1416
  }
691
1417
  const [start, end] = rangeValue;
692
1418
  if (!start || end || editingEnd) {
693
- setRange([mergeDateTime(day, start ? `${pad(start.getHours())}:${pad(start.getMinutes())}` : "00:00"), null]);
1419
+ setRange([
1420
+ mergeDateTime(
1421
+ day,
1422
+ start ? pad(start.getHours()) + ":" + pad(start.getMinutes()) : "00:00"
1423
+ ),
1424
+ null
1425
+ ]);
694
1426
  setEditingEnd(false);
695
1427
  return;
696
1428
  }
@@ -698,97 +1430,200 @@ function DateTimePicker(props) {
698
1430
  setRange(nextEnd < start ? [nextEnd, start] : [start, nextEnd]);
699
1431
  setEditingEnd(false);
700
1432
  };
701
- const shownValue = isRange ? [rangeValue[0] && formatDate(rangeValue[0], format), rangeValue[1] && formatDate(rangeValue[1], format)].filter(Boolean).join(" \u2014 ") : singleValue && formatDate(singleValue, format);
1433
+ const shownValue = isRange ? [
1434
+ rangeValue[0] && formatDate(rangeValue[0], format),
1435
+ rangeValue[1] && formatDate(rangeValue[1], format)
1436
+ ].filter(Boolean).join(" \u2014 ") : singleValue && formatDate(singleValue, format);
702
1437
  const firstDay = new Date(month.getFullYear(), month.getMonth(), 1);
703
1438
  const offset = (firstDay.getDay() + 6) % 7;
704
- const days = Array.from({ length: 42 }, (_, index) => new Date(month.getFullYear(), month.getMonth(), index - offset + 1));
1439
+ const days = Array.from(
1440
+ { length: 42 },
1441
+ (_, index) => new Date(month.getFullYear(), month.getMonth(), index - offset + 1)
1442
+ );
705
1443
  const selectedForTime = isRange ? editingEnd ? rangeValue[1] : rangeValue[0] : singleValue;
706
1444
  const setTime = (time) => {
707
1445
  if (!selectedForTime) return;
708
1446
  const next = mergeDateTime(selectedForTime, time);
709
- if (isRange) setRange(editingEnd ? [rangeValue[0], next] : [next, rangeValue[1]]);
1447
+ if (isRange)
1448
+ setRange(editingEnd ? [rangeValue[0], next] : [next, rangeValue[1]]);
710
1449
  else setSingle(next);
711
1450
  };
712
- return /* @__PURE__ */ jsxs7("div", { ref: rootRef, className: ["fe-datetime-picker", className].filter(Boolean).join(" "), children: [
713
- label && /* @__PURE__ */ jsx7("span", { className: "fe-datetime-picker__label", children: label }),
714
- /* @__PURE__ */ jsxs7("button", { type: "button", className: "fe-datetime-picker__trigger", disabled, "aria-expanded": open, onClick: () => setOpen((current) => !current), children: [
715
- /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\u25F7" }),
716
- /* @__PURE__ */ jsx7("span", { children: shownValue || placeholder || (isRange ? "Select date range" : "Select date and time") })
717
- ] }),
718
- open && /* @__PURE__ */ jsxs7("div", { className: "fe-datetime-picker__popper", role: "dialog", "aria-label": "Date and time picker", children: [
719
- /* @__PURE__ */ jsxs7("div", { className: "fe-datetime-picker__month", children: [
720
- /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "Previous month", onClick: () => setMonth((current) => new Date(current.getFullYear(), current.getMonth() - 1, 1)), children: "\u2039" }),
721
- /* @__PURE__ */ jsx7("strong", { children: month.toLocaleDateString(locale, { month: "long", year: "numeric" }) }),
722
- /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "Next month", onClick: () => setMonth((current) => new Date(current.getFullYear(), current.getMonth() + 1, 1)), children: "\u203A" })
723
- ] }),
724
- /* @__PURE__ */ jsx7("div", { className: "fe-datetime-picker__weekdays", children: ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"].map((day) => /* @__PURE__ */ jsx7("span", { children: day }, day)) }),
725
- /* @__PURE__ */ jsx7("div", { className: "fe-datetime-picker__days", children: days.map((day) => {
726
- const inMonth = day.getMonth() === month.getMonth();
727
- const selected = isRange ? sameDay(day, rangeValue[0]) || sameDay(day, rangeValue[1]) : sameDay(day, singleValue);
728
- const inRange = isRange && rangeValue[0] && rangeValue[1] && day > startOfDay(rangeValue[0]) && day < startOfDay(rangeValue[1]);
729
- return /* @__PURE__ */ jsx7("button", { type: "button", className: [!inMonth && "is-other-month", selected && "is-selected", inRange && "is-in-range"].filter(Boolean).join(" "), onClick: () => selectDay(day), children: day.getDate() }, day.toISOString());
730
- }) }),
731
- isRange && /* @__PURE__ */ jsxs7("div", { className: "fe-datetime-picker__range-tabs", children: [
732
- /* @__PURE__ */ jsx7("button", { type: "button", className: !editingEnd ? "is-active" : "", onClick: () => setEditingEnd(false), children: "Start" }),
733
- /* @__PURE__ */ jsx7("button", { type: "button", className: editingEnd ? "is-active" : "", onClick: () => setEditingEnd(true), children: "End" })
734
- ] }),
735
- /* @__PURE__ */ jsxs7("label", { className: "fe-datetime-picker__time", children: [
736
- "Time",
737
- /* @__PURE__ */ jsx7("input", { type: "time", value: selectedForTime ? `${pad(selectedForTime.getHours())}:${pad(selectedForTime.getMinutes())}` : "00:00", onChange: (event) => setTime(event.target.value), disabled: !selectedForTime })
738
- ] })
739
- ] })
740
- ] });
741
- }
742
-
743
- // packages/tooltip/src/index.tsx
744
- import { cloneElement, useId as useId2, useState as useState4 } from "react";
745
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
746
- function Tooltip({ content, children, placement = "top", disabled, className, ...props }) {
747
- const [visible, setVisible] = useState4(false);
748
- const id = useId2();
749
- const trigger = cloneElement(children, { "aria-describedby": visible ? id : void 0, onMouseEnter: (event) => {
750
- children.props.onMouseEnter?.(event);
751
- setVisible(true);
752
- }, onMouseLeave: (event) => {
753
- children.props.onMouseLeave?.(event);
754
- setVisible(false);
755
- }, onFocus: (event) => {
756
- children.props.onFocus?.(event);
757
- setVisible(true);
758
- }, onBlur: (event) => {
759
- children.props.onBlur?.(event);
760
- setVisible(false);
761
- } });
762
- return /* @__PURE__ */ jsxs8("span", { className: ["fe-tooltip", `fe-tooltip--${placement}`, className].filter(Boolean).join(" "), ...props, children: [
763
- trigger,
764
- visible && !disabled && /* @__PURE__ */ jsx8("span", { id, role: "tooltip", className: "fe-tooltip__content", children: content })
765
- ] });
1451
+ return /* @__PURE__ */ jsxs12(
1452
+ "div",
1453
+ {
1454
+ ref: rootRef,
1455
+ className: [
1456
+ "fe-datetime-picker",
1457
+ hasError && "fe-datetime-picker--error",
1458
+ className
1459
+ ].filter(Boolean).join(" "),
1460
+ children: [
1461
+ /* @__PURE__ */ jsx13(
1462
+ FieldLabel,
1463
+ {
1464
+ id: labelId,
1465
+ label,
1466
+ description: resolvedDescription,
1467
+ descriptionDisplay,
1468
+ isRequired
1469
+ }
1470
+ ),
1471
+ /* @__PURE__ */ jsxs12(
1472
+ "button",
1473
+ {
1474
+ id: triggerId,
1475
+ type: "button",
1476
+ className: "fe-datetime-picker__trigger",
1477
+ disabled,
1478
+ "aria-invalid": hasError || void 0,
1479
+ "aria-required": isRequired || void 0,
1480
+ "aria-labelledby": labelledBy,
1481
+ "aria-describedby": describedBy,
1482
+ "aria-expanded": open,
1483
+ onClick: () => setOpen((current) => !current),
1484
+ children: [
1485
+ /* @__PURE__ */ jsx13("span", { "aria-hidden": "true", children: "\u25F7" }),
1486
+ /* @__PURE__ */ jsxs12(
1487
+ "span",
1488
+ {
1489
+ className: !shownValue && placeholder ? "fe-datetime-picker__value is-placeholder" : "fe-datetime-picker__value",
1490
+ children: [
1491
+ shownValue || placeholder || (isRange ? "Select date range" : "Select date and time"),
1492
+ isRequired && placeholder && !shownValue && /* @__PURE__ */ jsx13("span", { className: "fe-field__required", "aria-hidden": "true", children: "*" })
1493
+ ]
1494
+ }
1495
+ )
1496
+ ]
1497
+ }
1498
+ ),
1499
+ open && /* @__PURE__ */ jsxs12(
1500
+ "div",
1501
+ {
1502
+ className: "fe-datetime-picker__popper",
1503
+ role: "dialog",
1504
+ "aria-label": "Date and time picker",
1505
+ children: [
1506
+ /* @__PURE__ */ jsxs12("div", { className: "fe-datetime-picker__month", children: [
1507
+ /* @__PURE__ */ jsx13(
1508
+ "button",
1509
+ {
1510
+ type: "button",
1511
+ "aria-label": "Previous month",
1512
+ onClick: () => setMonth(
1513
+ (current) => new Date(current.getFullYear(), current.getMonth() - 1, 1)
1514
+ ),
1515
+ children: "\u2039"
1516
+ }
1517
+ ),
1518
+ /* @__PURE__ */ jsx13("strong", { children: month.toLocaleDateString(locale, {
1519
+ month: "long",
1520
+ year: "numeric"
1521
+ }) }),
1522
+ /* @__PURE__ */ jsx13(
1523
+ "button",
1524
+ {
1525
+ type: "button",
1526
+ "aria-label": "Next month",
1527
+ onClick: () => setMonth(
1528
+ (current) => new Date(current.getFullYear(), current.getMonth() + 1, 1)
1529
+ ),
1530
+ children: "\u203A"
1531
+ }
1532
+ )
1533
+ ] }),
1534
+ /* @__PURE__ */ jsx13("div", { className: "fe-datetime-picker__weekdays", children: ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"].map((day) => /* @__PURE__ */ jsx13("span", { children: day }, day)) }),
1535
+ /* @__PURE__ */ jsx13("div", { className: "fe-datetime-picker__days", children: days.map((day) => {
1536
+ const inMonth = day.getMonth() === month.getMonth();
1537
+ const selected = isRange ? sameDay(day, rangeValue[0]) || sameDay(day, rangeValue[1]) : sameDay(day, singleValue);
1538
+ const inRange = isRange && rangeValue[0] && rangeValue[1] && day > startOfDay(rangeValue[0]) && day < startOfDay(rangeValue[1]);
1539
+ return /* @__PURE__ */ jsx13(
1540
+ "button",
1541
+ {
1542
+ type: "button",
1543
+ className: [
1544
+ !inMonth && "is-other-month",
1545
+ selected && "is-selected",
1546
+ inRange && "is-in-range"
1547
+ ].filter(Boolean).join(" "),
1548
+ onClick: () => selectDay(day),
1549
+ children: day.getDate()
1550
+ },
1551
+ day.toISOString()
1552
+ );
1553
+ }) }),
1554
+ isRange && /* @__PURE__ */ jsxs12("div", { className: "fe-datetime-picker__range-tabs", children: [
1555
+ /* @__PURE__ */ jsx13(
1556
+ "button",
1557
+ {
1558
+ type: "button",
1559
+ className: !editingEnd ? "is-active" : "",
1560
+ onClick: () => setEditingEnd(false),
1561
+ children: "Start"
1562
+ }
1563
+ ),
1564
+ /* @__PURE__ */ jsx13(
1565
+ "button",
1566
+ {
1567
+ type: "button",
1568
+ className: editingEnd ? "is-active" : "",
1569
+ onClick: () => setEditingEnd(true),
1570
+ children: "End"
1571
+ }
1572
+ )
1573
+ ] }),
1574
+ /* @__PURE__ */ jsxs12("label", { className: "fe-datetime-picker__time", children: [
1575
+ "Time",
1576
+ /* @__PURE__ */ jsx13(
1577
+ "input",
1578
+ {
1579
+ type: "time",
1580
+ value: selectedForTime ? pad(selectedForTime.getHours()) + ":" + pad(selectedForTime.getMinutes()) : "00:00",
1581
+ onChange: (event) => setTime(event.target.value),
1582
+ disabled: !selectedForTime
1583
+ }
1584
+ )
1585
+ ] })
1586
+ ]
1587
+ }
1588
+ ),
1589
+ /* @__PURE__ */ jsx13(
1590
+ FieldMessage,
1591
+ {
1592
+ id: messageId2,
1593
+ error: fieldError,
1594
+ description: resolvedDescription,
1595
+ descriptionDisplay
1596
+ }
1597
+ )
1598
+ ]
1599
+ }
1600
+ );
766
1601
  }
767
1602
 
768
1603
  // packages/expandable-section/src/index.tsx
769
- import { useId as useId3, useState as useState5 } from "react";
770
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1604
+ import { useId as useId7, useState as useState10 } from "react";
1605
+ import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
771
1606
  function ExpandableSection({ title, children, expanded, defaultExpanded = false, onExpandedChange, disabled, className, ...props }) {
772
- const [internalExpanded, setInternalExpanded] = useState5(defaultExpanded);
1607
+ const [internalExpanded, setInternalExpanded] = useState10(defaultExpanded);
773
1608
  const isExpanded = expanded ?? internalExpanded;
774
- const id = useId3();
1609
+ const id = useId7();
775
1610
  const toggle = () => {
776
1611
  if (disabled) return;
777
1612
  const next = !isExpanded;
778
1613
  if (expanded === void 0) setInternalExpanded(next);
779
1614
  onExpandedChange?.(next);
780
1615
  };
781
- return /* @__PURE__ */ jsxs9("section", { className: ["fe-expandable-section", isExpanded && "fe-expandable-section--expanded", disabled && "fe-expandable-section--disabled", className].filter(Boolean).join(" "), ...props, children: [
782
- /* @__PURE__ */ jsxs9("button", { className: "fe-expandable-section__trigger", type: "button", "aria-expanded": isExpanded, "aria-controls": id, disabled, onClick: toggle, children: [
783
- /* @__PURE__ */ jsx9("span", { children: title }),
784
- /* @__PURE__ */ jsx9("span", { className: "fe-expandable-section__chevron", "aria-hidden": "true" })
1616
+ return /* @__PURE__ */ jsxs13("section", { className: ["fe-expandable-section", isExpanded && "fe-expandable-section--expanded", disabled && "fe-expandable-section--disabled", className].filter(Boolean).join(" "), ...props, children: [
1617
+ /* @__PURE__ */ jsxs13("button", { className: "fe-expandable-section__trigger", type: "button", "aria-expanded": isExpanded, "aria-controls": id, disabled, onClick: toggle, children: [
1618
+ /* @__PURE__ */ jsx14("span", { children: title }),
1619
+ /* @__PURE__ */ jsx14("span", { className: "fe-expandable-section__chevron", "aria-hidden": "true" })
785
1620
  ] }),
786
- /* @__PURE__ */ jsx9("div", { id, className: "fe-expandable-section__content", "aria-hidden": !isExpanded, children: /* @__PURE__ */ jsx9("div", { className: "fe-expandable-section__content-inner", children }) })
1621
+ /* @__PURE__ */ jsx14("div", { id, className: "fe-expandable-section__content", "aria-hidden": !isExpanded, children: /* @__PURE__ */ jsx14("div", { className: "fe-expandable-section__content-inner", children }) })
787
1622
  ] });
788
1623
  }
789
1624
 
790
1625
  // packages/loading/src/index.tsx
791
- import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1626
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
792
1627
  var sizes = {
793
1628
  small: "16px",
794
1629
  medium: "24px",
@@ -801,15 +1636,15 @@ function Loading({ size = "medium", color = "#2878f0", label, className, style,
801
1636
  "--fe-loading-color": color,
802
1637
  ...style
803
1638
  };
804
- return /* @__PURE__ */ jsxs10("span", { className: ["fe-loading", className].filter(Boolean).join(" "), style: loadingStyle, role: "status", ...props, children: [
805
- /* @__PURE__ */ jsx10("span", { className: "fe-loading__spinner", "aria-hidden": "true" }),
806
- label && /* @__PURE__ */ jsx10("span", { className: "fe-loading__label", children: label }),
807
- !label && /* @__PURE__ */ jsx10("span", { className: "fe-loading__sr-only", children: "Loading" })
1639
+ return /* @__PURE__ */ jsxs14("span", { className: ["fe-loading", className].filter(Boolean).join(" "), style: loadingStyle, role: "status", ...props, children: [
1640
+ /* @__PURE__ */ jsx15("span", { className: "fe-loading__spinner", "aria-hidden": "true" }),
1641
+ label && /* @__PURE__ */ jsx15("span", { className: "fe-loading__label", children: label }),
1642
+ !label && /* @__PURE__ */ jsx15("span", { className: "fe-loading__sr-only", children: "Loading" })
808
1643
  ] });
809
1644
  }
810
1645
 
811
1646
  // packages/skeleton/src/index.tsx
812
- import { Fragment as Fragment2, jsx as jsx11 } from "react/jsx-runtime";
1647
+ import { Fragment as Fragment3, jsx as jsx16 } from "react/jsx-runtime";
813
1648
  var pixels = (value) => typeof value === "number" ? `${value}px` : value;
814
1649
  function SkeletonBase({ variant = "box", shape, width, height, count = 1, animated = true, className, style, ...props }) {
815
1650
  const resolvedVariant = shape ?? variant;
@@ -820,7 +1655,7 @@ function SkeletonBase({ variant = "box", shape, width, height, count = 1, animat
820
1655
  "--fe-skeleton-height": resolvedHeight,
821
1656
  ...style
822
1657
  };
823
- return /* @__PURE__ */ jsx11(Fragment2, { children: Array.from({ length: Math.max(1, count) }, (_, index) => /* @__PURE__ */ jsx11(
1658
+ return /* @__PURE__ */ jsx16(Fragment3, { children: Array.from({ length: Math.max(1, count) }, (_, index) => /* @__PURE__ */ jsx16(
824
1659
  "div",
825
1660
  {
826
1661
  className: ["fe-skeleton", `fe-skeleton--${resolvedVariant}`, animated && "fe-skeleton--animated", className].filter(Boolean).join(" "),
@@ -832,16 +1667,16 @@ function SkeletonBase({ variant = "box", shape, width, height, count = 1, animat
832
1667
  )) });
833
1668
  }
834
1669
  function SkeletonCircle({ size = 40, ...props }) {
835
- return /* @__PURE__ */ jsx11(SkeletonBase, { variant: "circle", width: size, height: size, ...props });
1670
+ return /* @__PURE__ */ jsx16(SkeletonBase, { variant: "circle", width: size, height: size, ...props });
836
1671
  }
837
1672
  function SkeletonSquare({ size = 80, ...props }) {
838
- return /* @__PURE__ */ jsx11(SkeletonBase, { variant: "box", width: size, height: size, ...props });
1673
+ return /* @__PURE__ */ jsx16(SkeletonBase, { variant: "box", width: size, height: size, ...props });
839
1674
  }
840
1675
  function SkeletonBox({ width = "100%", height = 80, ...props }) {
841
- return /* @__PURE__ */ jsx11(SkeletonBase, { variant: "box", width, height, ...props });
1676
+ return /* @__PURE__ */ jsx16(SkeletonBase, { variant: "box", width, height, ...props });
842
1677
  }
843
1678
  function SkeletonLine({ width = "100%", height = 12, ...props }) {
844
- return /* @__PURE__ */ jsx11(SkeletonBase, { variant: "line", width, height, ...props });
1679
+ return /* @__PURE__ */ jsx16(SkeletonBase, { variant: "line", width, height, ...props });
845
1680
  }
846
1681
  var Skeleton = Object.assign(SkeletonBase, {
847
1682
  Circle: SkeletonCircle,
@@ -851,9 +1686,9 @@ var Skeleton = Object.assign(SkeletonBase, {
851
1686
  });
852
1687
 
853
1688
  // packages/modal/src/index.tsx
854
- import { useEffect as useEffect4, useId as useId4, useRef as useRef3 } from "react";
855
- import { createPortal as createPortal2 } from "react-dom";
856
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1689
+ import { useEffect as useEffect6, useId as useId8, useRef as useRef4 } from "react";
1690
+ import { createPortal as createPortal3 } from "react-dom";
1691
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
857
1692
  function Modal({
858
1693
  open,
859
1694
  onClose,
@@ -869,9 +1704,9 @@ function Modal({
869
1704
  className,
870
1705
  ...props
871
1706
  }) {
872
- const titleId = useId4();
873
- const panelRef = useRef3(null);
874
- useEffect4(() => {
1707
+ const titleId = useId8();
1708
+ const panelRef = useRef4(null);
1709
+ useEffect6(() => {
875
1710
  if (!open) return;
876
1711
  const onKeyDown = (event) => {
877
1712
  if (event.key === "Escape") onClose();
@@ -882,10 +1717,10 @@ function Modal({
882
1717
  }, [onClose, open]);
883
1718
  if (!open || typeof document === "undefined") return null;
884
1719
  const hasFooter = footer || actions.length > 0;
885
- return createPortal2(
886
- /* @__PURE__ */ jsx12("div", { className: "fe-modal-backdrop", role: "presentation", onMouseDown: (event) => {
1720
+ return createPortal3(
1721
+ /* @__PURE__ */ jsx17("div", { className: "fe-modal-backdrop", role: "presentation", onMouseDown: (event) => {
887
1722
  if (event.target === event.currentTarget && closeOnBackdropClick) onClose();
888
- }, children: /* @__PURE__ */ jsxs11(
1723
+ }, children: /* @__PURE__ */ jsxs15(
889
1724
  "div",
890
1725
  {
891
1726
  ref: panelRef,
@@ -897,17 +1732,17 @@ function Modal({
897
1732
  tabIndex: -1,
898
1733
  ...props,
899
1734
  children: [
900
- (title || description || closeButton) && /* @__PURE__ */ jsxs11("header", { className: "fe-modal__header", children: [
901
- /* @__PURE__ */ jsxs11("div", { className: "fe-modal__heading", children: [
902
- title && /* @__PURE__ */ jsx12("h2", { id: titleId, children: title }),
903
- description && /* @__PURE__ */ jsx12("p", { children: description })
1735
+ (title || description || closeButton) && /* @__PURE__ */ jsxs15("header", { className: "fe-modal__header", children: [
1736
+ /* @__PURE__ */ jsxs15("div", { className: "fe-modal__heading", children: [
1737
+ title && /* @__PURE__ */ jsx17("h2", { id: titleId, children: title }),
1738
+ description && /* @__PURE__ */ jsx17("p", { children: description })
904
1739
  ] }),
905
- closeButton && /* @__PURE__ */ jsx12(Button, { hierarchy: "tertiary-gray", size: "32", iconOnly: true, icon: /* @__PURE__ */ jsx12(CloseIcon, {}), "aria-label": closeLabel, onClick: onClose })
1740
+ closeButton && /* @__PURE__ */ jsx17(Button, { hierarchy: "tertiary-gray", size: "32", iconOnly: true, icon: /* @__PURE__ */ jsx17(CloseIcon, {}), "aria-label": closeLabel, onClick: onClose })
906
1741
  ] }),
907
- /* @__PURE__ */ jsx12("div", { className: "fe-modal__body", children }),
908
- hasFooter && /* @__PURE__ */ jsxs11("footer", { className: "fe-modal__footer", children: [
909
- footer && /* @__PURE__ */ jsx12("div", { className: "fe-modal__footer-content", children: footer }),
910
- actions.length > 0 && /* @__PURE__ */ jsx12("div", { className: "fe-modal__actions", children: actions.map(({ label, ...action }, index) => /* @__PURE__ */ jsx12(Button, { ...action, children: label }, index)) })
1742
+ /* @__PURE__ */ jsx17("div", { className: "fe-modal__body", children }),
1743
+ hasFooter && /* @__PURE__ */ jsxs15("footer", { className: "fe-modal__footer", children: [
1744
+ footer && /* @__PURE__ */ jsx17("div", { className: "fe-modal__footer-content", children: footer }),
1745
+ actions.length > 0 && /* @__PURE__ */ jsx17("div", { className: "fe-modal__actions", children: actions.map(({ label, ...action }, index) => /* @__PURE__ */ jsx17(Button, { ...action, children: label }, index)) })
911
1746
  ] })
912
1747
  ]
913
1748
  }
@@ -917,7 +1752,7 @@ function Modal({
917
1752
  }
918
1753
 
919
1754
  // packages/progress/src/index.tsx
920
- import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
1755
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
921
1756
  function ProgressBar({ value, max = 100, label, showValue = true, size = "medium", color = "#2878f0", className, style, "aria-label": ariaLabel, ...props }) {
922
1757
  const indeterminate = value === null || value === void 0;
923
1758
  const percentage = indeterminate ? 0 : Math.min(100, Math.max(0, Number(value) / Math.max(1, max) * 100));
@@ -927,17 +1762,17 @@ function ProgressBar({ value, max = 100, label, showValue = true, size = "medium
927
1762
  ...style
928
1763
  };
929
1764
  const visibleValue = `${Math.round(percentage)}%`;
930
- return /* @__PURE__ */ jsxs12("div", { className: ["fe-progress", `fe-progress--${size}`, indeterminate && "fe-progress--indeterminate", className].filter(Boolean).join(" "), style: progressStyle, ...props, children: [
931
- (label || !indeterminate && showValue) && /* @__PURE__ */ jsxs12("div", { className: "fe-progress__meta", children: [
932
- label && /* @__PURE__ */ jsx13("span", { className: "fe-progress__label", children: label }),
933
- !indeterminate && showValue && /* @__PURE__ */ jsx13("output", { className: "fe-progress__value", children: visibleValue })
1765
+ return /* @__PURE__ */ jsxs16("div", { className: ["fe-progress", `fe-progress--${size}`, indeterminate && "fe-progress--indeterminate", className].filter(Boolean).join(" "), style: progressStyle, ...props, children: [
1766
+ (label || !indeterminate && showValue) && /* @__PURE__ */ jsxs16("div", { className: "fe-progress__meta", children: [
1767
+ label && /* @__PURE__ */ jsx18("span", { className: "fe-progress__label", children: label }),
1768
+ !indeterminate && showValue && /* @__PURE__ */ jsx18("output", { className: "fe-progress__value", children: visibleValue })
934
1769
  ] }),
935
- /* @__PURE__ */ jsx13("div", { className: "fe-progress__track", role: "progressbar", "aria-label": ariaLabel ?? (typeof label === "string" ? label : "Progress"), "aria-valuemin": indeterminate ? void 0 : 0, "aria-valuemax": indeterminate ? void 0 : max, "aria-valuenow": indeterminate ? void 0 : Number(value), "aria-valuetext": indeterminate ? "Loading" : visibleValue, children: /* @__PURE__ */ jsx13("span", { className: "fe-progress__indicator" }) })
1770
+ /* @__PURE__ */ jsx18("div", { className: "fe-progress__track", role: "progressbar", "aria-label": ariaLabel ?? (typeof label === "string" ? label : "Progress"), "aria-valuemin": indeterminate ? void 0 : 0, "aria-valuemax": indeterminate ? void 0 : max, "aria-valuenow": indeterminate ? void 0 : Number(value), "aria-valuetext": indeterminate ? "Loading" : visibleValue, children: /* @__PURE__ */ jsx18("span", { className: "fe-progress__indicator" }) })
936
1771
  ] });
937
1772
  }
938
1773
 
939
1774
  // packages/chip/src/index.tsx
940
- import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1775
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
941
1776
  var statuses = ["default", "info", "success", "warning", "error", "neutral", "pending", "processing"];
942
1777
  function Chip({ children, status = "default", color, variant = "subtle", dot = false, onRemove, removeLabel = "Remove", className, style, ...props }) {
943
1778
  const usesCustomColor = Boolean(color);
@@ -946,16 +1781,16 @@ function Chip({ children, status = "default", color, variant = "subtle", dot = f
946
1781
  ...style
947
1782
  };
948
1783
  const resolvedStatus = statuses.includes(status) ? status : "default";
949
- return /* @__PURE__ */ jsxs13("span", { className: ["fe-chip", `fe-chip--${variant}`, `fe-chip--${usesCustomColor ? "custom" : resolvedStatus}`, className].filter(Boolean).join(" "), style: chipStyle, ...props, children: [
950
- dot && /* @__PURE__ */ jsx14("span", { className: "fe-chip__dot", "aria-hidden": "true" }),
951
- /* @__PURE__ */ jsx14("span", { className: "fe-chip__content", children }),
952
- onRemove && /* @__PURE__ */ jsx14(Button, { hierarchy: "tertiary-gray", size: "24", iconOnly: true, icon: /* @__PURE__ */ jsx14(CloseIcon, { size: 14 }), "aria-label": removeLabel, onClick: onRemove, className: "fe-chip__remove" })
1784
+ return /* @__PURE__ */ jsxs17("span", { className: ["fe-chip", `fe-chip--${variant}`, `fe-chip--${usesCustomColor ? "custom" : resolvedStatus}`, className].filter(Boolean).join(" "), style: chipStyle, ...props, children: [
1785
+ dot && /* @__PURE__ */ jsx19("span", { className: "fe-chip__dot", "aria-hidden": "true" }),
1786
+ /* @__PURE__ */ jsx19("span", { className: "fe-chip__content", children }),
1787
+ onRemove && /* @__PURE__ */ jsx19(Button, { hierarchy: "tertiary-gray", size: "24", iconOnly: true, icon: /* @__PURE__ */ jsx19(CloseIcon, { size: 14 }), "aria-label": removeLabel, onClick: onRemove, className: "fe-chip__remove" })
953
1788
  ] });
954
1789
  }
955
1790
 
956
1791
  // packages/message/src/index.tsx
957
- import { useEffect as useEffect5, useState as useState6 } from "react";
958
- import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
1792
+ import { useEffect as useEffect7, useState as useState11 } from "react";
1793
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
959
1794
  var messageId = 0;
960
1795
  var entries = [];
961
1796
  var listeners = /* @__PURE__ */ new Set();
@@ -988,22 +1823,22 @@ var message = {
988
1823
  };
989
1824
  var icons = { success: "\u2713", info: "i", warning: "!", error: "\xD7" };
990
1825
  function Message({ maxCount = 4, closeLabel = "Close notification", className, ...props }) {
991
- const [visibleEntries, setVisibleEntries] = useState6(entries);
992
- useEffect5(() => {
1826
+ const [visibleEntries, setVisibleEntries] = useState11(entries);
1827
+ useEffect7(() => {
993
1828
  const listener = (nextEntries) => setVisibleEntries(nextEntries);
994
1829
  listeners.add(listener);
995
1830
  return () => {
996
1831
  listeners.delete(listener);
997
1832
  };
998
1833
  }, []);
999
- return /* @__PURE__ */ jsx15("div", { className: ["fe-message-viewport", className].filter(Boolean).join(" "), "aria-live": "polite", ...props, children: visibleEntries.slice(-Math.max(1, maxCount)).map((entry) => /* @__PURE__ */ jsxs14("div", { className: `fe-message fe-message--${entry.severity ?? "info"}`, role: entry.severity === "error" ? "alert" : "status", children: [
1000
- /* @__PURE__ */ jsx15("span", { className: "fe-message__icon", "aria-hidden": "true", children: icons[entry.severity ?? "info"] }),
1001
- /* @__PURE__ */ jsxs14("div", { className: "fe-message__body", children: [
1002
- entry.title && /* @__PURE__ */ jsx15("strong", { className: "fe-message__title", children: entry.title }),
1003
- /* @__PURE__ */ jsx15("div", { className: "fe-message__content", children: entry.content })
1834
+ return /* @__PURE__ */ jsx20("div", { className: ["fe-message-viewport", className].filter(Boolean).join(" "), "aria-live": "polite", ...props, children: visibleEntries.slice(-Math.max(1, maxCount)).map((entry) => /* @__PURE__ */ jsxs18("div", { className: `fe-message fe-message--${entry.severity ?? "info"}`, role: entry.severity === "error" ? "alert" : "status", children: [
1835
+ /* @__PURE__ */ jsx20("span", { className: "fe-message__icon", "aria-hidden": "true", children: icons[entry.severity ?? "info"] }),
1836
+ /* @__PURE__ */ jsxs18("div", { className: "fe-message__body", children: [
1837
+ entry.title && /* @__PURE__ */ jsx20("strong", { className: "fe-message__title", children: entry.title }),
1838
+ /* @__PURE__ */ jsx20("div", { className: "fe-message__content", children: entry.content })
1004
1839
  ] }),
1005
- entry.action && /* @__PURE__ */ jsx15("span", { className: "fe-message__action", children: entry.action }),
1006
- /* @__PURE__ */ jsx15(Button, { className: "fe-message__close", hierarchy: "tertiary-gray", size: "24", iconOnly: true, icon: "\xD7", "aria-label": closeLabel, onClick: () => dismiss(entry.id) })
1840
+ entry.action && /* @__PURE__ */ jsx20("span", { className: "fe-message__action", children: entry.action }),
1841
+ /* @__PURE__ */ jsx20(Button, { className: "fe-message__close", hierarchy: "tertiary-gray", size: "24", iconOnly: true, icon: "\xD7", "aria-label": closeLabel, onClick: () => dismiss(entry.id) })
1007
1842
  ] }, entry.id)) });
1008
1843
  }
1009
1844
  ((Message2) => {
@@ -1017,8 +1852,8 @@ function Message({ maxCount = 4, closeLabel = "Close notification", className, .
1017
1852
  })(Message || (Message = {}));
1018
1853
 
1019
1854
  // packages/snackbar/src/index.tsx
1020
- import { useEffect as useEffect6 } from "react";
1021
- import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
1855
+ import { useEffect as useEffect8 } from "react";
1856
+ import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
1022
1857
  function Snackbar({
1023
1858
  open,
1024
1859
  message: message2,
@@ -1032,12 +1867,12 @@ function Snackbar({
1032
1867
  }) {
1033
1868
  const vertical = anchorOrigin.vertical ?? "bottom";
1034
1869
  const horizontal = anchorOrigin.horizontal ?? "center";
1035
- useEffect6(() => {
1870
+ useEffect8(() => {
1036
1871
  if (!open || autoHideDuration === null) return void 0;
1037
1872
  const timer = window.setTimeout(() => onClose?.("timeout"), autoHideDuration);
1038
1873
  return () => window.clearTimeout(timer);
1039
1874
  }, [open, autoHideDuration, onClose]);
1040
- useEffect6(() => {
1875
+ useEffect8(() => {
1041
1876
  if (!open) return void 0;
1042
1877
  const onKeyDown = (event) => {
1043
1878
  if (event.key === "Escape") onClose?.("escapeKeyDown");
@@ -1046,10 +1881,10 @@ function Snackbar({
1046
1881
  return () => window.removeEventListener("keydown", onKeyDown);
1047
1882
  }, [open, onClose]);
1048
1883
  if (!open) return null;
1049
- return /* @__PURE__ */ jsx16("div", { className: ["fe-snackbar", `fe-snackbar--${vertical}`, `fe-snackbar--${horizontal}`, className].filter(Boolean).join(" "), ...props, children: /* @__PURE__ */ jsxs15("div", { className: "fe-snackbar__content", role: "status", "aria-live": "polite", children: [
1050
- /* @__PURE__ */ jsx16("span", { className: "fe-snackbar__message", children: message2 }),
1051
- action && /* @__PURE__ */ jsx16("span", { className: "fe-snackbar__action", children: action }),
1052
- onClose && /* @__PURE__ */ jsx16(Button, { className: "fe-snackbar__close", hierarchy: "tertiary-gray", size: "24", iconOnly: true, icon: "\xD7", "aria-label": closeLabel, onClick: () => onClose("closeButton") })
1884
+ return /* @__PURE__ */ jsx21("div", { className: ["fe-snackbar", `fe-snackbar--${vertical}`, `fe-snackbar--${horizontal}`, className].filter(Boolean).join(" "), ...props, children: /* @__PURE__ */ jsxs19("div", { className: "fe-snackbar__content", role: "status", "aria-live": "polite", children: [
1885
+ /* @__PURE__ */ jsx21("span", { className: "fe-snackbar__message", children: message2 }),
1886
+ action && /* @__PURE__ */ jsx21("span", { className: "fe-snackbar__action", children: action }),
1887
+ onClose && /* @__PURE__ */ jsx21(Button, { className: "fe-snackbar__close", hierarchy: "tertiary-gray", size: "24", iconOnly: true, icon: "\xD7", "aria-label": closeLabel, onClick: () => onClose("closeButton") })
1053
1888
  ] }) });
1054
1889
  }
1055
1890
  export {
@@ -1087,7 +1922,24 @@ export {
1087
1922
  TextInput,
1088
1923
  Toggle,
1089
1924
  Tooltip,
1925
+ arrow_left,
1926
+ check_square_fill,
1927
+ chevron_down,
1928
+ chevron_left,
1929
+ chevron_right,
1930
+ chevron_up,
1931
+ copy,
1090
1932
  formatNumber,
1091
1933
  getIconSize,
1092
- message
1934
+ key,
1935
+ lock,
1936
+ lock_unlocked,
1937
+ log_out,
1938
+ message,
1939
+ minus_square,
1940
+ plus,
1941
+ plus_square,
1942
+ search,
1943
+ trash,
1944
+ x_close
1093
1945
  };