@assure-one/design-system 1.26.0 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +9 -0
- package/dist/index.js +144 -101
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -2705,6 +2705,15 @@ interface ProposalPackageCardProps extends Omit<React.HTMLAttributes<HTMLDivElem
|
|
|
2705
2705
|
servicesLabel?: ReactNode;
|
|
2706
2706
|
/** Service rows (`ProposalServiceRow`) or any content. */
|
|
2707
2707
|
children?: ReactNode;
|
|
2708
|
+
/**
|
|
2709
|
+
* Cap the service list's height (any CSS length, e.g. `"14rem"`). Past it the
|
|
2710
|
+
* list scrolls rather than growing, so a package with many services keeps its
|
|
2711
|
+
* select control in view instead of pushing it below the fold — and cards
|
|
2712
|
+
* sitting in a row stay the same height.
|
|
2713
|
+
*
|
|
2714
|
+
* Omit for the previous behaviour: the list grows to fit.
|
|
2715
|
+
*/
|
|
2716
|
+
servicesMaxHeight?: string;
|
|
2708
2717
|
/** Select / toggle handler — makes the card interactive. */
|
|
2709
2718
|
onSelect?: () => void;
|
|
2710
2719
|
disabled?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -10639,6 +10639,7 @@ var ProposalPackageCard = forwardRef(
|
|
|
10639
10639
|
badge,
|
|
10640
10640
|
servicesLabel = "Included services",
|
|
10641
10641
|
children,
|
|
10642
|
+
servicesMaxHeight,
|
|
10642
10643
|
onSelect,
|
|
10643
10644
|
disabled = false,
|
|
10644
10645
|
className,
|
|
@@ -10674,7 +10675,31 @@ var ProposalPackageCard = forwardRef(
|
|
|
10674
10675
|
] }),
|
|
10675
10676
|
children && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10676
10677
|
/* @__PURE__ */ jsx("div", { className: "text-fg-3 mt-4 mb-1 text-[11.5px] font-semibold tracking-wide", children: servicesLabel }),
|
|
10677
|
-
/* @__PURE__ */ jsx(
|
|
10678
|
+
/* @__PURE__ */ jsx(
|
|
10679
|
+
"div",
|
|
10680
|
+
{
|
|
10681
|
+
className: cn(
|
|
10682
|
+
servicesMaxHeight && [
|
|
10683
|
+
"min-h-0 overflow-y-auto",
|
|
10684
|
+
// pr-3 keeps the rail off the service text; -mr-1 gives that
|
|
10685
|
+
// padding back to the card so the rail still sits near its
|
|
10686
|
+
// edge rather than floating in from it.
|
|
10687
|
+
"-mr-1 pr-3",
|
|
10688
|
+
// A 2px hairline. `scrollbar-thin` is 8px, and on
|
|
10689
|
+
// Chrome-for-Windows an unstyled bar also carries stepper
|
|
10690
|
+
// arrows, which is most of what made it read as heavy.
|
|
10691
|
+
"[scrollbar-width:thin]",
|
|
10692
|
+
"[&::-webkit-scrollbar]:w-[2px]",
|
|
10693
|
+
"[&::-webkit-scrollbar-button]:hidden",
|
|
10694
|
+
"[&::-webkit-scrollbar-track]:bg-transparent",
|
|
10695
|
+
"[&::-webkit-scrollbar-thumb]:rounded-full",
|
|
10696
|
+
"[&::-webkit-scrollbar-thumb]:bg-rule-strong"
|
|
10697
|
+
]
|
|
10698
|
+
),
|
|
10699
|
+
style: servicesMaxHeight ? { maxHeight: servicesMaxHeight } : void 0,
|
|
10700
|
+
children
|
|
10701
|
+
}
|
|
10702
|
+
)
|
|
10678
10703
|
] }),
|
|
10679
10704
|
/* @__PURE__ */ jsx("div", { className: "mt-auto pt-4", children: interactive ? /* @__PURE__ */ jsx(
|
|
10680
10705
|
"button",
|
|
@@ -18249,6 +18274,8 @@ var SEARCH_THRESHOLD = 8;
|
|
|
18249
18274
|
var HOVER_OPEN_MS = 90;
|
|
18250
18275
|
var HOVER_CLOSE_MS = 220;
|
|
18251
18276
|
var FLYOUT_WIDTH = 224;
|
|
18277
|
+
var MIN_FLYOUT_HEIGHT = 120;
|
|
18278
|
+
var VIEWPORT_MARGIN = 24;
|
|
18252
18279
|
var DEFAULT_GUTTER_PX = 24;
|
|
18253
18280
|
function DisplayMenu({
|
|
18254
18281
|
sections,
|
|
@@ -18265,7 +18292,8 @@ function DisplayMenu({
|
|
|
18265
18292
|
const [openKey, setOpenKey] = useState(null);
|
|
18266
18293
|
const [flyout, setFlyout] = useState({
|
|
18267
18294
|
top: 0,
|
|
18268
|
-
side: "left"
|
|
18295
|
+
side: "left",
|
|
18296
|
+
maxHeight: 0
|
|
18269
18297
|
});
|
|
18270
18298
|
const [panelShift, setPanelShift] = useState(0);
|
|
18271
18299
|
const [rootQuery, setRootQuery] = useState("");
|
|
@@ -18289,10 +18317,14 @@ function DisplayMenu({
|
|
|
18289
18317
|
if (!panel || !row) return;
|
|
18290
18318
|
const panelRect = panel.getBoundingClientRect();
|
|
18291
18319
|
const rowRect = row.getBoundingClientRect();
|
|
18292
|
-
const maxTop = Math.max(0, window.innerHeight - panelRect.top - 24 -
|
|
18320
|
+
const maxTop = Math.max(0, window.innerHeight - panelRect.top - 24 - MIN_FLYOUT_HEIGHT);
|
|
18293
18321
|
const top = Math.min(Math.max(rowRect.top - panelRect.top - 4, 0), maxTop);
|
|
18322
|
+
const maxHeight = Math.max(
|
|
18323
|
+
MIN_FLYOUT_HEIGHT,
|
|
18324
|
+
window.innerHeight - (panelRect.top + top) - VIEWPORT_MARGIN
|
|
18325
|
+
);
|
|
18294
18326
|
const side = panelRect.left >= FLYOUT_WIDTH + 16 ? "left" : "right";
|
|
18295
|
-
setFlyout({ top, side });
|
|
18327
|
+
setFlyout({ top, side, maxHeight });
|
|
18296
18328
|
}, []);
|
|
18297
18329
|
const openSection = useCallback(
|
|
18298
18330
|
(key) => {
|
|
@@ -18423,100 +18455,108 @@ function DisplayMenu({
|
|
|
18423
18455
|
}
|
|
18424
18456
|
)
|
|
18425
18457
|
] }),
|
|
18426
|
-
/* @__PURE__ */ jsx(
|
|
18427
|
-
|
|
18428
|
-
|
|
18429
|
-
|
|
18430
|
-
|
|
18431
|
-
|
|
18432
|
-
|
|
18433
|
-
{
|
|
18434
|
-
|
|
18435
|
-
|
|
18436
|
-
"
|
|
18437
|
-
|
|
18438
|
-
|
|
18439
|
-
|
|
18440
|
-
|
|
18441
|
-
|
|
18442
|
-
|
|
18443
|
-
|
|
18444
|
-
|
|
18445
|
-
|
|
18446
|
-
|
|
18447
|
-
|
|
18448
|
-
|
|
18449
|
-
|
|
18450
|
-
className: "shrink-0 text-muted-foreground",
|
|
18451
|
-
"
|
|
18452
|
-
|
|
18453
|
-
|
|
18454
|
-
|
|
18455
|
-
|
|
18456
|
-
|
|
18457
|
-
|
|
18458
|
-
`${section2.key}:${option.key}`
|
|
18459
|
-
);
|
|
18460
|
-
}
|
|
18461
|
-
const { section } = row;
|
|
18462
|
-
const count = section.selected.size;
|
|
18463
|
-
const valueLabel = section.summary ?? (section.mode === "single" ? section.options.find((o) => section.selected.has(o.key))?.label ?? "" : "");
|
|
18464
|
-
const isOpen = section.key === openKey;
|
|
18465
|
-
return (
|
|
18466
|
-
/* Hover handlers sit on the wrapper so the cursor can cross
|
|
18467
|
-
* the gap to `section.trailing` without closing the flyout.
|
|
18468
|
-
* The wrapper is not itself a control — the button inside is,
|
|
18469
|
-
* and it carries the keyboard equivalent (ArrowRight / Enter /
|
|
18470
|
-
* Space open the same flyout). Nothing here is mouse-only. */
|
|
18471
|
-
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
18472
|
-
/* @__PURE__ */ jsxs(
|
|
18473
|
-
"div",
|
|
18474
|
-
{
|
|
18475
|
-
ref: (el) => {
|
|
18476
|
-
if (el) rowRefs.current.set(section.key, el);
|
|
18477
|
-
else rowRefs.current.delete(section.key);
|
|
18478
|
-
},
|
|
18479
|
-
className: "flex items-center gap-0.5",
|
|
18480
|
-
onMouseEnter: () => scheduleOpen(section.key),
|
|
18481
|
-
onMouseLeave: scheduleClose,
|
|
18482
|
-
children: [
|
|
18483
|
-
/* @__PURE__ */ jsxs(
|
|
18484
|
-
"button",
|
|
18485
|
-
{
|
|
18486
|
-
type: "button",
|
|
18487
|
-
role: "menuitem",
|
|
18488
|
-
"aria-haspopup": "menu",
|
|
18489
|
-
"aria-expanded": isOpen,
|
|
18490
|
-
onClick: () => openSection(section.key),
|
|
18491
|
-
onKeyDown: (e) => {
|
|
18492
|
-
if (e.key === "ArrowRight" || e.key === "Enter" || e.key === " ") {
|
|
18493
|
-
e.preventDefault();
|
|
18494
|
-
openSection(section.key);
|
|
18495
|
-
requestAnimationFrame(
|
|
18496
|
-
() => flyoutRef.current?.querySelector("input, [role='menuitemcheckbox'], [role='menuitemradio']")?.focus()
|
|
18497
|
-
);
|
|
18458
|
+
/* @__PURE__ */ jsx(
|
|
18459
|
+
"div",
|
|
18460
|
+
{
|
|
18461
|
+
role: "menu",
|
|
18462
|
+
"aria-label": triggerLabel,
|
|
18463
|
+
className: "scrollbar-thin max-h-[min(32rem,70vh)] overflow-y-auto p-1",
|
|
18464
|
+
children: rootRows.length === 0 ? /* @__PURE__ */ jsx(EmptyRow, {}) : rootRows.map((row) => {
|
|
18465
|
+
if (row.kind === "option") {
|
|
18466
|
+
const { section: section2, option } = row;
|
|
18467
|
+
const isActive = section2.selected.has(option.key);
|
|
18468
|
+
const isMulti = section2.mode === "multi";
|
|
18469
|
+
return /* @__PURE__ */ jsxs(
|
|
18470
|
+
"button",
|
|
18471
|
+
{
|
|
18472
|
+
type: "button",
|
|
18473
|
+
role: isMulti ? "menuitemcheckbox" : "menuitemradio",
|
|
18474
|
+
"aria-checked": isActive,
|
|
18475
|
+
onMouseEnter: () => {
|
|
18476
|
+
clearTimers();
|
|
18477
|
+
setOpenKey(null);
|
|
18478
|
+
},
|
|
18479
|
+
onClick: () => section2.onSelect(option.key),
|
|
18480
|
+
className: "flex w-full items-center gap-1.5 rounded-md px-2 py-1.5 text-left text-[13px] transition-colors hover:bg-muted/60 focus-visible:bg-muted/60 focus-visible:outline-none",
|
|
18481
|
+
children: [
|
|
18482
|
+
section2.icon && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", "aria-hidden": "true", children: section2.icon }),
|
|
18483
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 truncate text-muted-foreground", children: section2.label }),
|
|
18484
|
+
/* @__PURE__ */ jsx(
|
|
18485
|
+
ChevronRightIcon,
|
|
18486
|
+
{
|
|
18487
|
+
size: 12,
|
|
18488
|
+
className: "shrink-0 text-muted-foreground",
|
|
18489
|
+
"aria-hidden": "true"
|
|
18498
18490
|
}
|
|
18499
|
-
},
|
|
18500
|
-
className: cn(
|
|
18501
|
-
"flex min-w-0 flex-1 items-center gap-2 rounded-md px-2 py-1.5 text-left text-[13px] text-foreground transition-colors hover:bg-muted/60 focus-visible:bg-muted/60 focus-visible:outline-none",
|
|
18502
|
-
isOpen && "bg-muted/60"
|
|
18503
18491
|
),
|
|
18504
|
-
children:
|
|
18505
|
-
|
|
18506
|
-
|
|
18507
|
-
|
|
18508
|
-
|
|
18509
|
-
|
|
18510
|
-
|
|
18511
|
-
|
|
18512
|
-
|
|
18513
|
-
|
|
18514
|
-
|
|
18515
|
-
|
|
18516
|
-
|
|
18517
|
-
|
|
18518
|
-
|
|
18519
|
-
|
|
18492
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-foreground", children: option.label }),
|
|
18493
|
+
isActive && /* @__PURE__ */ jsx(CheckIcon, { size: 14, className: "shrink-0 text-brand" })
|
|
18494
|
+
]
|
|
18495
|
+
},
|
|
18496
|
+
`${section2.key}:${option.key}`
|
|
18497
|
+
);
|
|
18498
|
+
}
|
|
18499
|
+
const { section } = row;
|
|
18500
|
+
const count = section.selected.size;
|
|
18501
|
+
const valueLabel = section.summary ?? (section.mode === "single" ? section.options.find((o) => section.selected.has(o.key))?.label ?? "" : "");
|
|
18502
|
+
const isOpen = section.key === openKey;
|
|
18503
|
+
return (
|
|
18504
|
+
/* Hover handlers sit on the wrapper so the cursor can cross
|
|
18505
|
+
* the gap to `section.trailing` without closing the flyout.
|
|
18506
|
+
* The wrapper is not itself a control — the button inside is,
|
|
18507
|
+
* and it carries the keyboard equivalent (ArrowRight / Enter /
|
|
18508
|
+
* Space open the same flyout). Nothing here is mouse-only. */
|
|
18509
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
18510
|
+
/* @__PURE__ */ jsxs(
|
|
18511
|
+
"div",
|
|
18512
|
+
{
|
|
18513
|
+
ref: (el) => {
|
|
18514
|
+
if (el) rowRefs.current.set(section.key, el);
|
|
18515
|
+
else rowRefs.current.delete(section.key);
|
|
18516
|
+
},
|
|
18517
|
+
className: "flex items-center gap-0.5",
|
|
18518
|
+
onMouseEnter: () => scheduleOpen(section.key),
|
|
18519
|
+
onMouseLeave: scheduleClose,
|
|
18520
|
+
children: [
|
|
18521
|
+
/* @__PURE__ */ jsxs(
|
|
18522
|
+
"button",
|
|
18523
|
+
{
|
|
18524
|
+
type: "button",
|
|
18525
|
+
role: "menuitem",
|
|
18526
|
+
"aria-haspopup": "menu",
|
|
18527
|
+
"aria-expanded": isOpen,
|
|
18528
|
+
onClick: () => openSection(section.key),
|
|
18529
|
+
onKeyDown: (e) => {
|
|
18530
|
+
if (e.key === "ArrowRight" || e.key === "Enter" || e.key === " ") {
|
|
18531
|
+
e.preventDefault();
|
|
18532
|
+
openSection(section.key);
|
|
18533
|
+
requestAnimationFrame(
|
|
18534
|
+
() => flyoutRef.current?.querySelector("input, [role='menuitemcheckbox'], [role='menuitemradio']")?.focus()
|
|
18535
|
+
);
|
|
18536
|
+
}
|
|
18537
|
+
},
|
|
18538
|
+
className: cn(
|
|
18539
|
+
"flex min-w-0 flex-1 items-center gap-2 rounded-md px-2 py-1.5 text-left text-[13px] text-foreground transition-colors hover:bg-muted/60 focus-visible:bg-muted/60 focus-visible:outline-none",
|
|
18540
|
+
isOpen && "bg-muted/60"
|
|
18541
|
+
),
|
|
18542
|
+
children: [
|
|
18543
|
+
section.icon && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", "aria-hidden": "true", children: section.icon }),
|
|
18544
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: section.label }),
|
|
18545
|
+
section.mode === "multi" && count > 0 && /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full bg-brand-bg px-1.5 text-[11px] font-medium text-brand", children: count }),
|
|
18546
|
+
section.mode !== "multi" && valueLabel && /* @__PURE__ */ jsx("span", { className: "max-w-24 shrink-0 truncate text-[13px] text-muted-foreground", children: valueLabel }),
|
|
18547
|
+
/* @__PURE__ */ jsx(ChevronRightIcon, { size: 13, className: "shrink-0 text-muted-foreground" })
|
|
18548
|
+
]
|
|
18549
|
+
}
|
|
18550
|
+
),
|
|
18551
|
+
section.trailing
|
|
18552
|
+
]
|
|
18553
|
+
},
|
|
18554
|
+
section.key
|
|
18555
|
+
)
|
|
18556
|
+
);
|
|
18557
|
+
})
|
|
18558
|
+
}
|
|
18559
|
+
),
|
|
18520
18560
|
/* @__PURE__ */ jsx("div", { className: "border-t border-border p-1", children: /* @__PURE__ */ jsxs(
|
|
18521
18561
|
Button,
|
|
18522
18562
|
{
|
|
@@ -18538,9 +18578,12 @@ function DisplayMenu({
|
|
|
18538
18578
|
role: "menu",
|
|
18539
18579
|
"aria-label": activeSection.label,
|
|
18540
18580
|
tabIndex: -1,
|
|
18541
|
-
style: { top: flyout.top, width: FLYOUT_WIDTH },
|
|
18581
|
+
style: { top: flyout.top, width: FLYOUT_WIDTH, maxHeight: flyout.maxHeight },
|
|
18542
18582
|
className: cn(
|
|
18543
|
-
|
|
18583
|
+
// Column + overflow-hidden so the option list (the only flexible
|
|
18584
|
+
// part) absorbs the height cap, while the search box and Clear
|
|
18585
|
+
// footer stay pinned and fully visible.
|
|
18586
|
+
"absolute z-50 flex flex-col overflow-hidden rounded-lg border border-border bg-popover shadow-md",
|
|
18544
18587
|
// -mx-1 lets the flyout tuck against the panel so there's no
|
|
18545
18588
|
// dead gap for the cursor to fall through on the way over.
|
|
18546
18589
|
flyout.side === "left" ? "right-full -mr-1" : "left-full -ml-1"
|
|
@@ -18548,7 +18591,7 @@ function DisplayMenu({
|
|
|
18548
18591
|
onMouseEnter: clearTimers,
|
|
18549
18592
|
onMouseLeave: scheduleClose,
|
|
18550
18593
|
children: [
|
|
18551
|
-
showFlyoutSearch && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 border-b border-border px-2.5 py-1.5", children: [
|
|
18594
|
+
showFlyoutSearch && /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1.5 border-b border-border px-2.5 py-1.5", children: [
|
|
18552
18595
|
/* @__PURE__ */ jsx(SearchIcon, { size: 13, className: "shrink-0 text-muted-foreground", "aria-hidden": "true" }),
|
|
18553
18596
|
/* @__PURE__ */ jsx(
|
|
18554
18597
|
"input",
|
|
@@ -18562,7 +18605,7 @@ function DisplayMenu({
|
|
|
18562
18605
|
}
|
|
18563
18606
|
)
|
|
18564
18607
|
] }),
|
|
18565
|
-
/* @__PURE__ */ jsx("div", { className: "max-h-
|
|
18608
|
+
/* @__PURE__ */ jsx("div", { className: "scrollbar-thin min-h-0 flex-1 max-h-[min(24rem,60vh)] overflow-y-auto p-1", children: activeSection.content ? (
|
|
18566
18609
|
/* Consumer-supplied controls (date range, numeric bound).
|
|
18567
18610
|
* Rendered raw — the section owns its own labelling and
|
|
18568
18611
|
* layout; the flyout only provides the surface. */
|
|
@@ -18615,7 +18658,7 @@ function DisplayMenu({
|
|
|
18615
18658
|
option.key
|
|
18616
18659
|
);
|
|
18617
18660
|
}) }),
|
|
18618
|
-
activeSection.mode === "multi" && activeSection.selected.size > 0 && activeSection.onClear && /* @__PURE__ */ jsx("div", { className: "border-t border-border p-1", children: /* @__PURE__ */ jsxs(
|
|
18661
|
+
activeSection.mode === "multi" && activeSection.selected.size > 0 && activeSection.onClear && /* @__PURE__ */ jsx("div", { className: "shrink-0 border-t border-border p-1", children: /* @__PURE__ */ jsxs(
|
|
18619
18662
|
Button,
|
|
18620
18663
|
{
|
|
18621
18664
|
variant: "ghost",
|