@mirror-physics/fractal-ui 0.2.0-next.83 → 0.2.0-next.84

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.d.cts CHANGED
@@ -304,6 +304,8 @@ interface DropdownProps {
304
304
  triggerLabel?: string;
305
305
  /** Floating field title. Empty selectedValue is the unfilled state. */
306
306
  fieldLabel?: string;
307
+ /** Show a clear action; defaults to true for floating fields. */
308
+ clearable?: boolean;
307
309
  direction?: 'up' | 'down' | 'left' | 'right';
308
310
  /** Preferred alignment; shifted as needed to stay inside visible bounds. */
309
311
  align?: 'left' | 'right';
@@ -331,7 +333,7 @@ interface DropdownProps {
331
333
  closeOnSelect?: boolean;
332
334
  disabled?: boolean;
333
335
  }
334
- declare function Dropdown({ items, selectedValue, onSelect, multiple, selectedValues, onSelectionChange, searchable, searchPlaceholder, emptyMessage, triggerLabel, fieldLabel, direction, align, maxHeight, collisionPadding, triggerOrientation, triggerContent, label, iconOnly, noChevron, size: sizeAlias, controlSize, triggerId, triggerVariant, className, triggerClassName, panelClassName, closeOnSelect, disabled, }: DropdownProps): React.JSX.Element | null;
336
+ declare function Dropdown({ items, selectedValue, onSelect, multiple, selectedValues, onSelectionChange, searchable, searchPlaceholder, emptyMessage, triggerLabel, fieldLabel, clearable, direction, align, maxHeight, collisionPadding, triggerOrientation, triggerContent, label, iconOnly, noChevron, size: sizeAlias, controlSize, triggerId, triggerVariant, className, triggerClassName, panelClassName, closeOnSelect, disabled, }: DropdownProps): React.JSX.Element | null;
335
337
 
336
338
  type LinkTheme = 'default' | 'muted' | 'accent';
337
339
  type LinkSize = 'sm' | 'md' | 'lg';
package/dist/index.d.ts CHANGED
@@ -304,6 +304,8 @@ interface DropdownProps {
304
304
  triggerLabel?: string;
305
305
  /** Floating field title. Empty selectedValue is the unfilled state. */
306
306
  fieldLabel?: string;
307
+ /** Show a clear action; defaults to true for floating fields. */
308
+ clearable?: boolean;
307
309
  direction?: 'up' | 'down' | 'left' | 'right';
308
310
  /** Preferred alignment; shifted as needed to stay inside visible bounds. */
309
311
  align?: 'left' | 'right';
@@ -331,7 +333,7 @@ interface DropdownProps {
331
333
  closeOnSelect?: boolean;
332
334
  disabled?: boolean;
333
335
  }
334
- declare function Dropdown({ items, selectedValue, onSelect, multiple, selectedValues, onSelectionChange, searchable, searchPlaceholder, emptyMessage, triggerLabel, fieldLabel, direction, align, maxHeight, collisionPadding, triggerOrientation, triggerContent, label, iconOnly, noChevron, size: sizeAlias, controlSize, triggerId, triggerVariant, className, triggerClassName, panelClassName, closeOnSelect, disabled, }: DropdownProps): React.JSX.Element | null;
336
+ declare function Dropdown({ items, selectedValue, onSelect, multiple, selectedValues, onSelectionChange, searchable, searchPlaceholder, emptyMessage, triggerLabel, fieldLabel, clearable, direction, align, maxHeight, collisionPadding, triggerOrientation, triggerContent, label, iconOnly, noChevron, size: sizeAlias, controlSize, triggerId, triggerVariant, className, triggerClassName, panelClassName, closeOnSelect, disabled, }: DropdownProps): React.JSX.Element | null;
335
337
 
336
338
  type LinkTheme = 'default' | 'muted' | 'accent';
337
339
  type LinkSize = 'sm' | 'md' | 'lg';
package/dist/index.js CHANGED
@@ -1424,7 +1424,7 @@ function DataTable({ columns, data, emptyMessage, header, size = "md", className
1424
1424
 
1425
1425
  // src/components/Dropdown/Dropdown.tsx
1426
1426
  import * as React11 from "react";
1427
- import { Check as Check2, MagnifyingGlass as MagnifyingGlass2, ChevronDown, ChevronLeft, ChevronRight as ChevronRight2, ChevronUp } from "@mirror-physics/fractal-icons";
1427
+ import { Close as Close2, Check as Check2, MagnifyingGlass as MagnifyingGlass2, ChevronDown, ChevronLeft, ChevronRight as ChevronRight2, ChevronUp } from "@mirror-physics/fractal-icons";
1428
1428
 
1429
1429
  // src/components/Dropdown/position.ts
1430
1430
  function positionDropdown(trigger, panel, bounds, direction, align) {
@@ -1475,6 +1475,7 @@ function Dropdown({
1475
1475
  emptyMessage = "No matching options.",
1476
1476
  triggerLabel,
1477
1477
  fieldLabel,
1478
+ clearable = Boolean(fieldLabel),
1478
1479
  direction = "down",
1479
1480
  align = "left",
1480
1481
  maxHeight = 320,
@@ -1498,6 +1499,7 @@ function Dropdown({
1498
1499
  const searchRef = React11.useRef(null);
1499
1500
  const accessibleLabel = triggerLabel ?? fieldLabel ?? "Options";
1500
1501
  const size = controlSize ?? sizeAlias;
1502
+ const canClear = clearable && !disabled && (multiple ? selectedValues.length > 0 && Boolean(onSelectionChange) : Boolean(selectedValue) && Boolean(onSelect));
1501
1503
  const [open, setOpen] = React11.useState(false);
1502
1504
  React11.useEffect(() => {
1503
1505
  if (!open) setQuery("");
@@ -1526,7 +1528,7 @@ function Dropdown({
1526
1528
  return renderableItems.slice(index + 1, nextHeader < 0 ? void 0 : nextHeader).some((next) => matching.has(next.value));
1527
1529
  });
1528
1530
  const selectableItems = visibleItems.filter((i) => i.kind !== "header");
1529
- const selected = items.find((i) => i.value === selectedValue && i.kind !== "header") ?? selectableItems[0] ?? visibleItems[0];
1531
+ const selected = items.find((i) => i.value === selectedValue && i.kind !== "header") ?? (fieldLabel && !selectedValue && !multiple ? void 0 : selectableItems[0] ?? visibleItems[0]);
1530
1532
  const ChevronIcon = direction === "up" ? ChevronUp : direction === "left" ? ChevronLeft : direction === "right" ? ChevronRight2 : ChevronDown;
1531
1533
  useEscapeDismiss(100, () => {
1532
1534
  setOpen(false);
@@ -1620,7 +1622,7 @@ function Dropdown({
1620
1622
  return () => document.removeEventListener("mousedown", handleClickOutside);
1621
1623
  }, [open]);
1622
1624
  if (renderableItems.length === 0) return null;
1623
- return /* @__PURE__ */ jsxs17("div", { ref: rootRef, "data-control-size": size, "data-filled": multiple ? selectedValues.length > 0 : Boolean(selectedValue), "data-open": open, className: cn("fractal-dropdown", fieldLabel && "fractal-floating-field fractal-floating-field--dropdown", className), children: [
1625
+ return /* @__PURE__ */ jsxs17("div", { ref: rootRef, "data-control-size": size, "data-filled": multiple ? selectedValues.length > 0 : Boolean(selectedValue), "data-open": open, "data-clearable": canClear || void 0, className: cn("fractal-dropdown", fieldLabel && "fractal-floating-field fractal-floating-field--dropdown", className), children: [
1624
1626
  /* @__PURE__ */ jsxs17(
1625
1627
  "button",
1626
1628
  {
@@ -1665,6 +1667,13 @@ function Dropdown({
1665
1667
  ]
1666
1668
  }
1667
1669
  ),
1670
+ canClear && /* @__PURE__ */ jsx19("button", { type: "button", className: "fractal-dropdown-clear", "aria-label": `Clear ${accessibleLabel}`, onClick: () => {
1671
+ if (multiple) onSelectionChange?.([]);
1672
+ else onSelect?.("");
1673
+ setOpen(false);
1674
+ setQuery("");
1675
+ triggerRef.current?.focus();
1676
+ }, children: /* @__PURE__ */ jsx19(Close2, { "aria-hidden": "true" }) }),
1668
1677
  fieldLabel ? /* @__PURE__ */ jsx19("label", { className: "fractal-floating-field__label", htmlFor: triggerId ?? `${menuId}-trigger`, children: fieldLabel }) : null,
1669
1678
  open && /* @__PURE__ */ jsxs17(
1670
1679
  "div",
@@ -2695,7 +2704,7 @@ SidebarFooter.displayName = "SidebarFooter";
2695
2704
  // src/components/SidePanel/SidePanel.tsx
2696
2705
  import * as React16 from "react";
2697
2706
  import { createPortal as createPortal4 } from "react-dom";
2698
- import { Close as Close2 } from "@mirror-physics/fractal-icons";
2707
+ import { Close as Close3 } from "@mirror-physics/fractal-icons";
2699
2708
  import { jsx as jsx31, jsxs as jsxs26 } from "react/jsx-runtime";
2700
2709
  function SidePanel({ open, onClose, title, description, children, footer, size = "md", loading = false, loadingLabel = "Loading", className }) {
2701
2710
  useEscapeDismiss(80, onClose, open);
@@ -2746,7 +2755,7 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
2746
2755
  typeof title === "string" ? /* @__PURE__ */ jsx31("h2", { className: "fractal-side-panel__title", children: title }) : /* @__PURE__ */ jsx31("div", { className: "fractal-side-panel__title", children: title }),
2747
2756
  description && /* @__PURE__ */ jsx31("p", { className: "fractal-side-panel__description", children: description })
2748
2757
  ] }),
2749
- /* @__PURE__ */ jsx31("button", { type: "button", className: "fractal-side-panel__close", "aria-label": "Close panel", onClick: onClose, children: /* @__PURE__ */ jsx31(Close2, { size: 18 }) })
2758
+ /* @__PURE__ */ jsx31("button", { type: "button", className: "fractal-side-panel__close", "aria-label": "Close panel", onClick: onClose, children: /* @__PURE__ */ jsx31(Close3, { size: 18 }) })
2750
2759
  ] }),
2751
2760
  /* @__PURE__ */ jsx31("div", { ref: bodyRef, "aria-busy": loading || void 0, className: cn("fractal-side-panel__body", loading && "fractal-side-panel__body--loading"), children: loading ? /* @__PURE__ */ jsx31(UILoader, { label: loadingLabel }) : children }),
2752
2761
  footer && /* @__PURE__ */ jsx31("footer", { className: "fractal-side-panel__footer", "data-scroll-divider": scrollEdges.below, children: footer })
@@ -2806,7 +2815,7 @@ TextButton.displayName = "TextButton";
2806
2815
 
2807
2816
  // src/components/FileDropzone/FileDropzone.tsx
2808
2817
  import * as React19 from "react";
2809
- import { Close as Close3, FileArrowUp } from "@mirror-physics/fractal-icons";
2818
+ import { Close as Close4, FileArrowUp } from "@mirror-physics/fractal-icons";
2810
2819
  import { jsx as jsx34, jsxs as jsxs29 } from "react/jsx-runtime";
2811
2820
  function FileDropzone({
2812
2821
  files,
@@ -2886,7 +2895,7 @@ function FileDropzone({
2886
2895
  "aria-label": `Remove ${file.name}`,
2887
2896
  disabled,
2888
2897
  onClick: () => onFilesChange(files.filter((_, fileIndex) => fileIndex !== index)),
2889
- children: /* @__PURE__ */ jsx34(Close3, { "aria-hidden": "true", size: 14 })
2898
+ children: /* @__PURE__ */ jsx34(Close4, { "aria-hidden": "true", size: 14 })
2890
2899
  }
2891
2900
  )
2892
2901
  ] }, `${file.name}-${file.size}-${index}`)) })