@mirror-physics/fractal-ui 0.2.0-next.83 → 0.2.0-next.85
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/column-editor.css.map +1 -1
- package/dist/index.cjs +27 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +81 -12
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +32 -14
- package/dist/index.js.map +1 -1
- package/dist/tokens.css +3 -2
- package/package.json +1 -1
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,
|
|
@@ -1496,8 +1497,12 @@ function Dropdown({
|
|
|
1496
1497
|
}) {
|
|
1497
1498
|
const [query, setQuery] = React11.useState("");
|
|
1498
1499
|
const searchRef = React11.useRef(null);
|
|
1500
|
+
const searchContainerRef = React11.useRef(null);
|
|
1501
|
+
const optionsRef = React11.useRef(null);
|
|
1502
|
+
const [optionsScrolled, setOptionsScrolled] = React11.useState(false);
|
|
1499
1503
|
const accessibleLabel = triggerLabel ?? fieldLabel ?? "Options";
|
|
1500
1504
|
const size = controlSize ?? sizeAlias;
|
|
1505
|
+
const canClear = clearable && !disabled && (multiple ? selectedValues.length > 0 && Boolean(onSelectionChange) : Boolean(selectedValue) && Boolean(onSelect));
|
|
1501
1506
|
const [open, setOpen] = React11.useState(false);
|
|
1502
1507
|
React11.useEffect(() => {
|
|
1503
1508
|
if (!open) setQuery("");
|
|
@@ -1526,12 +1531,17 @@ function Dropdown({
|
|
|
1526
1531
|
return renderableItems.slice(index + 1, nextHeader < 0 ? void 0 : nextHeader).some((next) => matching.has(next.value));
|
|
1527
1532
|
});
|
|
1528
1533
|
const selectableItems = visibleItems.filter((i) => i.kind !== "header");
|
|
1529
|
-
const selected = items.find((i) => i.value === selectedValue && i.kind !== "header") ?? selectableItems[0] ?? visibleItems[0];
|
|
1534
|
+
const selected = items.find((i) => i.value === selectedValue && i.kind !== "header") ?? (fieldLabel && !selectedValue && !multiple ? void 0 : selectableItems[0] ?? visibleItems[0]);
|
|
1530
1535
|
const ChevronIcon = direction === "up" ? ChevronUp : direction === "left" ? ChevronLeft : direction === "right" ? ChevronRight2 : ChevronDown;
|
|
1531
1536
|
useEscapeDismiss(100, () => {
|
|
1532
1537
|
setOpen(false);
|
|
1533
1538
|
triggerRef.current?.focus();
|
|
1534
1539
|
}, open);
|
|
1540
|
+
React11.useLayoutEffect(() => {
|
|
1541
|
+
if (!open) return;
|
|
1542
|
+
if (optionsRef.current) optionsRef.current.scrollTop = 0;
|
|
1543
|
+
setOptionsScrolled(false);
|
|
1544
|
+
}, [open, query]);
|
|
1535
1545
|
React11.useLayoutEffect(() => {
|
|
1536
1546
|
const root = rootRef.current;
|
|
1537
1547
|
const trigger = triggerRef.current;
|
|
@@ -1569,7 +1579,7 @@ function Dropdown({
|
|
|
1569
1579
|
panel.style.maxWidth = `${availableWidth}px`;
|
|
1570
1580
|
panel.style.minWidth = `${Math.min(triggerRect.width, availableWidth)}px`;
|
|
1571
1581
|
const panelRect = panel.getBoundingClientRect();
|
|
1572
|
-
const desiredHeight = Math.min(heightLimit,
|
|
1582
|
+
const desiredHeight = Math.min(heightLimit, (optionsRef.current?.scrollHeight ?? 0) + (searchContainerRef.current?.offsetHeight ?? 0) + parseFloat(getComputedStyle(panel).paddingTop) + parseFloat(getComputedStyle(panel).paddingBottom) + panel.offsetHeight - panel.clientHeight);
|
|
1573
1583
|
const position = positionDropdown(triggerRect, { width: panelRect.width, height: desiredHeight }, bounds, direction, align);
|
|
1574
1584
|
const nextStyle = {
|
|
1575
1585
|
left: position.left - rootRect.left - root.clientLeft + root.scrollLeft,
|
|
@@ -1594,6 +1604,7 @@ function Dropdown({
|
|
|
1594
1604
|
const resize = new ResizeObserver(updatePosition);
|
|
1595
1605
|
resize.observe(root);
|
|
1596
1606
|
resize.observe(panel);
|
|
1607
|
+
if (optionsRef.current) resize.observe(optionsRef.current);
|
|
1597
1608
|
for (let ancestor = root.parentElement; ancestor; ancestor = ancestor.parentElement) {
|
|
1598
1609
|
resize.observe(ancestor);
|
|
1599
1610
|
}
|
|
@@ -1620,7 +1631,7 @@ function Dropdown({
|
|
|
1620
1631
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1621
1632
|
}, [open]);
|
|
1622
1633
|
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: [
|
|
1634
|
+
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
1635
|
/* @__PURE__ */ jsxs17(
|
|
1625
1636
|
"button",
|
|
1626
1637
|
{
|
|
@@ -1665,6 +1676,13 @@ function Dropdown({
|
|
|
1665
1676
|
]
|
|
1666
1677
|
}
|
|
1667
1678
|
),
|
|
1679
|
+
canClear && /* @__PURE__ */ jsx19("button", { type: "button", className: "fractal-dropdown-clear", "aria-label": `Clear ${accessibleLabel}`, onClick: () => {
|
|
1680
|
+
if (multiple) onSelectionChange?.([]);
|
|
1681
|
+
else onSelect?.("");
|
|
1682
|
+
setOpen(false);
|
|
1683
|
+
setQuery("");
|
|
1684
|
+
triggerRef.current?.focus();
|
|
1685
|
+
}, children: /* @__PURE__ */ jsx19(Close2, { "aria-hidden": "true" }) }),
|
|
1668
1686
|
fieldLabel ? /* @__PURE__ */ jsx19("label", { className: "fractal-floating-field__label", htmlFor: triggerId ?? `${menuId}-trigger`, children: fieldLabel }) : null,
|
|
1669
1687
|
open && /* @__PURE__ */ jsxs17(
|
|
1670
1688
|
"div",
|
|
@@ -1686,11 +1704,11 @@ function Dropdown({
|
|
|
1686
1704
|
className: cn("fractal-dropdown-panel", `fractal-dropdown-panel--${size}`, panelClassName),
|
|
1687
1705
|
style: panelStyle,
|
|
1688
1706
|
children: [
|
|
1689
|
-
searchable && /* @__PURE__ */ jsxs17("div", { className: "fractal-dropdown-search", children: [
|
|
1707
|
+
searchable && /* @__PURE__ */ jsx19("div", { ref: searchContainerRef, className: "fractal-dropdown-search-container", "data-scrolled": optionsScrolled, children: /* @__PURE__ */ jsxs17("div", { className: "fractal-dropdown-search", children: [
|
|
1690
1708
|
/* @__PURE__ */ jsx19(MagnifyingGlass2, { "aria-hidden": "true" }),
|
|
1691
1709
|
/* @__PURE__ */ jsx19("input", { ref: searchRef, type: "search", "aria-label": searchPlaceholder, placeholder: searchPlaceholder, value: query, onChange: (event) => setQuery(event.target.value) })
|
|
1692
|
-
] }),
|
|
1693
|
-
/* @__PURE__ */ jsxs17("div", { role: "listbox", id: `${menuId}-options`, "aria-label": accessibleLabel, "aria-multiselectable": multiple || void 0, children: [
|
|
1710
|
+
] }) }),
|
|
1711
|
+
/* @__PURE__ */ jsxs17("div", { ref: optionsRef, className: "fractal-dropdown-options", onScroll: (event) => setOptionsScrolled(event.currentTarget.scrollTop > 0), role: "listbox", id: `${menuId}-options`, "aria-label": accessibleLabel, "aria-multiselectable": multiple || void 0, children: [
|
|
1694
1712
|
label != null && /* @__PURE__ */ jsx19("div", { className: "fractal-dropdown-label", children: label }),
|
|
1695
1713
|
visibleItems.map((item, index) => {
|
|
1696
1714
|
const topDivider = item.border === "top" ? /* @__PURE__ */ jsx19("div", { className: "fractal-dropdown-separator" }) : null;
|
|
@@ -1730,9 +1748,9 @@ function Dropdown({
|
|
|
1730
1748
|
),
|
|
1731
1749
|
bottomDivider
|
|
1732
1750
|
] }, item.value);
|
|
1733
|
-
})
|
|
1734
|
-
|
|
1735
|
-
|
|
1751
|
+
}),
|
|
1752
|
+
!selectableItems.length && /* @__PURE__ */ jsx19("p", { role: "status", className: "fractal-dropdown-label", children: emptyMessage })
|
|
1753
|
+
] })
|
|
1736
1754
|
]
|
|
1737
1755
|
}
|
|
1738
1756
|
)
|
|
@@ -2695,7 +2713,7 @@ SidebarFooter.displayName = "SidebarFooter";
|
|
|
2695
2713
|
// src/components/SidePanel/SidePanel.tsx
|
|
2696
2714
|
import * as React16 from "react";
|
|
2697
2715
|
import { createPortal as createPortal4 } from "react-dom";
|
|
2698
|
-
import { Close as
|
|
2716
|
+
import { Close as Close3 } from "@mirror-physics/fractal-icons";
|
|
2699
2717
|
import { jsx as jsx31, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2700
2718
|
function SidePanel({ open, onClose, title, description, children, footer, size = "md", loading = false, loadingLabel = "Loading", className }) {
|
|
2701
2719
|
useEscapeDismiss(80, onClose, open);
|
|
@@ -2746,7 +2764,7 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
|
|
|
2746
2764
|
typeof title === "string" ? /* @__PURE__ */ jsx31("h2", { className: "fractal-side-panel__title", children: title }) : /* @__PURE__ */ jsx31("div", { className: "fractal-side-panel__title", children: title }),
|
|
2747
2765
|
description && /* @__PURE__ */ jsx31("p", { className: "fractal-side-panel__description", children: description })
|
|
2748
2766
|
] }),
|
|
2749
|
-
/* @__PURE__ */ jsx31("button", { type: "button", className: "fractal-side-panel__close", "aria-label": "Close panel", onClick: onClose, children: /* @__PURE__ */ jsx31(
|
|
2767
|
+
/* @__PURE__ */ jsx31("button", { type: "button", className: "fractal-side-panel__close", "aria-label": "Close panel", onClick: onClose, children: /* @__PURE__ */ jsx31(Close3, { size: 18 }) })
|
|
2750
2768
|
] }),
|
|
2751
2769
|
/* @__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
2770
|
footer && /* @__PURE__ */ jsx31("footer", { className: "fractal-side-panel__footer", "data-scroll-divider": scrollEdges.below, children: footer })
|
|
@@ -2806,7 +2824,7 @@ TextButton.displayName = "TextButton";
|
|
|
2806
2824
|
|
|
2807
2825
|
// src/components/FileDropzone/FileDropzone.tsx
|
|
2808
2826
|
import * as React19 from "react";
|
|
2809
|
-
import { Close as
|
|
2827
|
+
import { Close as Close4, FileArrowUp } from "@mirror-physics/fractal-icons";
|
|
2810
2828
|
import { jsx as jsx34, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2811
2829
|
function FileDropzone({
|
|
2812
2830
|
files,
|
|
@@ -2886,7 +2904,7 @@ function FileDropzone({
|
|
|
2886
2904
|
"aria-label": `Remove ${file.name}`,
|
|
2887
2905
|
disabled,
|
|
2888
2906
|
onClick: () => onFilesChange(files.filter((_, fileIndex) => fileIndex !== index)),
|
|
2889
|
-
children: /* @__PURE__ */ jsx34(
|
|
2907
|
+
children: /* @__PURE__ */ jsx34(Close4, { "aria-hidden": "true", size: 14 })
|
|
2890
2908
|
}
|
|
2891
2909
|
)
|
|
2892
2910
|
] }, `${file.name}-${file.size}-${index}`)) })
|