@mediaradar/design-components 0.9.0 → 0.11.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.cjs +62 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +171 -10
- package/dist/index.d.ts +171 -10
- package/dist/index.js +62 -21
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -2736,21 +2736,34 @@ function FilterDropdownFooter({
|
|
|
2736
2736
|
var import_react14 = require("react");
|
|
2737
2737
|
var import_react_dom5 = require("react-dom");
|
|
2738
2738
|
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
2739
|
-
function NameListModal({
|
|
2739
|
+
function NameListModal({
|
|
2740
|
+
title,
|
|
2741
|
+
initialName,
|
|
2742
|
+
submitLabel,
|
|
2743
|
+
onCancel,
|
|
2744
|
+
onSubmit,
|
|
2745
|
+
fieldLabel = "List name",
|
|
2746
|
+
placeholder = "e.g. Q4 prospecting targets",
|
|
2747
|
+
options
|
|
2748
|
+
}) {
|
|
2740
2749
|
const [name, setName] = (0, import_react14.useState)(initialName);
|
|
2750
|
+
const [checked, setChecked] = (0, import_react14.useState)(
|
|
2751
|
+
() => Object.fromEntries((options ?? []).map((o) => [o.key, !!o.initial]))
|
|
2752
|
+
);
|
|
2753
|
+
const toggle = (key) => setChecked((c) => ({ ...c, [key]: !c[key] }));
|
|
2741
2754
|
(0, import_react14.useEffect)(() => {
|
|
2742
2755
|
const onKey = (e) => e.key === "Escape" && onCancel();
|
|
2743
2756
|
window.addEventListener("keydown", onKey);
|
|
2744
2757
|
return () => window.removeEventListener("keydown", onKey);
|
|
2745
2758
|
}, [onCancel]);
|
|
2746
2759
|
return (0, import_react_dom5.createPortal)(
|
|
2747
|
-
//
|
|
2748
|
-
//
|
|
2749
|
-
//
|
|
2760
|
+
// bg-scrim, not a literal: design-tokens gained a scrim token in 2.5.0.
|
|
2761
|
+
// No in-data-[theme=dark] override needed any more -- the token redefines
|
|
2762
|
+
// itself under that attribute in dark.css, so one class covers both themes.
|
|
2750
2763
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2751
2764
|
"div",
|
|
2752
2765
|
{
|
|
2753
|
-
className: "fixed inset-0 z-70 flex items-center justify-center bg-
|
|
2766
|
+
className: "fixed inset-0 z-70 flex items-center justify-center bg-scrim px-4",
|
|
2754
2767
|
onMouseDown: (e) => e.target === e.currentTarget && onCancel(),
|
|
2755
2768
|
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
2756
2769
|
"div",
|
|
@@ -2762,7 +2775,7 @@ function NameListModal({ title, initialName, submitLabel, onCancel, onSubmit })
|
|
|
2762
2775
|
children: [
|
|
2763
2776
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h2", { className: "text-[16px] font-semibold text-text-primary", children: title }),
|
|
2764
2777
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "mt-4 flex flex-col gap-1.5", children: [
|
|
2765
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("label", { htmlFor: "account-list-name", className: "text-[12px] font-medium text-text-secondary", children:
|
|
2778
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("label", { htmlFor: "account-list-name", className: "text-[12px] font-medium text-text-secondary", children: fieldLabel }),
|
|
2766
2779
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2767
2780
|
"input",
|
|
2768
2781
|
{
|
|
@@ -2770,14 +2783,18 @@ function NameListModal({ title, initialName, submitLabel, onCancel, onSubmit })
|
|
|
2770
2783
|
autoFocus: true,
|
|
2771
2784
|
value: name,
|
|
2772
2785
|
onChange: (e) => setName(e.target.value),
|
|
2773
|
-
placeholder
|
|
2786
|
+
placeholder,
|
|
2774
2787
|
className: "h-10 rounded-control border border-border-default bg-input px-3 text-sm outline-hidden focus:border-brand-primaryAction"
|
|
2775
2788
|
}
|
|
2776
2789
|
)
|
|
2777
2790
|
] }),
|
|
2791
|
+
options && options.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "mt-4 flex flex-col gap-2.5", children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("label", { className: "flex cursor-pointer items-center gap-2.5 text-[13px] text-text-primary", children: [
|
|
2792
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(CheckBox, { checked: !!checked[o.key], onChange: () => toggle(o.key), ariaLabel: o.label }),
|
|
2793
|
+
o.label
|
|
2794
|
+
] }, o.key)) }),
|
|
2778
2795
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "mt-5 flex items-center justify-end gap-2", children: [
|
|
2779
2796
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Button, { variant: "secondary", onClick: onCancel, children: "Cancel" }),
|
|
2780
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Button, { disabled: !name.trim(), onClick: () => onSubmit(name.trim()), children: submitLabel })
|
|
2797
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Button, { disabled: !name.trim(), onClick: () => onSubmit(name.trim(), checked), children: submitLabel })
|
|
2781
2798
|
] })
|
|
2782
2799
|
]
|
|
2783
2800
|
}
|
|
@@ -3149,6 +3166,7 @@ var import_react15 = require("react");
|
|
|
3149
3166
|
var import_lucide_react20 = require("lucide-react");
|
|
3150
3167
|
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
3151
3168
|
var MONTH_ABBR = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
3169
|
+
var QUARTER_ABBR = ["Q1", "Q2", "Q3", "Q4"];
|
|
3152
3170
|
var PRESETS = ["Rolling 3 months", "Rolling 6 months", "Rolling 12 months"];
|
|
3153
3171
|
var startOfToday = () => {
|
|
3154
3172
|
const d = /* @__PURE__ */ new Date();
|
|
@@ -3197,6 +3215,7 @@ function MiniSelect({ value, onChange, options }) {
|
|
|
3197
3215
|
}
|
|
3198
3216
|
function DateRangePicker({
|
|
3199
3217
|
defaultValue = "Rolling 6 months",
|
|
3218
|
+
granularity = "month",
|
|
3200
3219
|
align = "left",
|
|
3201
3220
|
presets = PRESETS,
|
|
3202
3221
|
onChange,
|
|
@@ -3215,6 +3234,8 @@ function DateRangePicker({
|
|
|
3215
3234
|
const [fromYr, setFromYr] = (0, import_react15.useState)(end.getFullYear() - 1);
|
|
3216
3235
|
const [toMo, setToMo] = (0, import_react15.useState)(end.getMonth());
|
|
3217
3236
|
const [toYr, setToYr] = (0, import_react15.useState)(end.getFullYear());
|
|
3237
|
+
const [fromQ, setFromQ] = (0, import_react15.useState)(Math.floor(end.getMonth() / 3));
|
|
3238
|
+
const [toQ, setToQ] = (0, import_react15.useState)(Math.floor(end.getMonth() / 3));
|
|
3218
3239
|
(0, import_react15.useEffect)(() => {
|
|
3219
3240
|
const [s, e] = resolveRange(value, end);
|
|
3220
3241
|
onRangeChange?.(s, e);
|
|
@@ -3241,11 +3262,11 @@ function DateRangePicker({
|
|
|
3241
3262
|
onChange?.(label);
|
|
3242
3263
|
setOpen(false);
|
|
3243
3264
|
};
|
|
3244
|
-
const span = toYr * 12 + toMo - (fromYr * 12 + fromMo) + 1;
|
|
3265
|
+
const span = granularity === "year" ? toYr - fromYr + 1 : granularity === "quarter" ? toYr * 4 + toQ - (fromYr * 4 + fromQ) + 1 : toYr * 12 + toMo - (fromYr * 12 + fromMo) + 1;
|
|
3245
3266
|
const valid = span >= 1;
|
|
3246
3267
|
const applyCustom = () => {
|
|
3247
3268
|
if (!valid) return;
|
|
3248
|
-
const label = `${MONTH_ABBR[fromMo]} ${fromYr} \u2013 ${MONTH_ABBR[toMo]} ${toYr}`;
|
|
3269
|
+
const label = granularity === "year" ? `${fromYr} \u2013 ${toYr}` : granularity === "quarter" ? `${QUARTER_ABBR[fromQ]} ${fromYr} \u2013 ${QUARTER_ABBR[toQ]} ${toYr}` : `${MONTH_ABBR[fromMo]} ${fromYr} \u2013 ${MONTH_ABBR[toMo]} ${toYr}`;
|
|
3249
3270
|
if (showFooter) setDraft(label);
|
|
3250
3271
|
else commit(label);
|
|
3251
3272
|
};
|
|
@@ -3284,14 +3305,16 @@ function DateRangePicker({
|
|
|
3284
3305
|
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("label", { className: "flex items-center justify-between gap-2 text-[12px] text-text-secondary", children: [
|
|
3285
3306
|
"From",
|
|
3286
3307
|
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "flex gap-1", children: [
|
|
3287
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MiniSelect, { value: fromMo, onChange: setFromMo, options: MONTH_ABBR.map((mm, i) => ({ label: mm, value: i })) }),
|
|
3308
|
+
granularity === "month" && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MiniSelect, { value: fromMo, onChange: setFromMo, options: MONTH_ABBR.map((mm, i) => ({ label: mm, value: i })) }),
|
|
3309
|
+
granularity === "quarter" && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MiniSelect, { value: fromQ, onChange: setFromQ, options: QUARTER_ABBR.map((qq, i) => ({ label: qq, value: i })) }),
|
|
3288
3310
|
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MiniSelect, { value: fromYr, onChange: setFromYr, options: yearOptions.map((y) => ({ label: String(y), value: y })) })
|
|
3289
3311
|
] })
|
|
3290
3312
|
] }),
|
|
3291
3313
|
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("label", { className: "flex items-center justify-between gap-2 text-[12px] text-text-secondary", children: [
|
|
3292
3314
|
"To",
|
|
3293
3315
|
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "flex gap-1", children: [
|
|
3294
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MiniSelect, { value: toMo, onChange: setToMo, options: MONTH_ABBR.map((mm, i) => ({ label: mm, value: i })) }),
|
|
3316
|
+
granularity === "month" && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MiniSelect, { value: toMo, onChange: setToMo, options: MONTH_ABBR.map((mm, i) => ({ label: mm, value: i })) }),
|
|
3317
|
+
granularity === "quarter" && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MiniSelect, { value: toQ, onChange: setToQ, options: QUARTER_ABBR.map((qq, i) => ({ label: qq, value: i })) }),
|
|
3295
3318
|
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MiniSelect, { value: toYr, onChange: setToYr, options: yearOptions.map((y) => ({ label: String(y), value: y })) })
|
|
3296
3319
|
] })
|
|
3297
3320
|
] }),
|
|
@@ -3320,6 +3343,8 @@ function MultiSelectFilter({
|
|
|
3320
3343
|
caption,
|
|
3321
3344
|
options = [],
|
|
3322
3345
|
groups,
|
|
3346
|
+
counts,
|
|
3347
|
+
variant = "box",
|
|
3323
3348
|
selected,
|
|
3324
3349
|
onChange,
|
|
3325
3350
|
allLabel = "All",
|
|
@@ -3377,14 +3402,18 @@ function MultiSelectFilter({
|
|
|
3377
3402
|
return next;
|
|
3378
3403
|
});
|
|
3379
3404
|
const toggleGroup = (g) => setDraft((cur) => {
|
|
3380
|
-
const ids = groupLeaves(g).map((c) => c.id);
|
|
3405
|
+
const ids = groupLeaves(g).map((c) => c.id).filter((id) => !counts || (counts[id] ?? 0) > 0 || cur.includes(id));
|
|
3406
|
+
if (!ids.length) return cur;
|
|
3381
3407
|
const allSel = ids.every((id) => cur.includes(id));
|
|
3382
3408
|
const next = allSel ? cur.filter((id) => !ids.includes(id)) : [.../* @__PURE__ */ new Set([...cur, ...ids])];
|
|
3383
3409
|
if (next.length < min) return cur;
|
|
3384
3410
|
return next;
|
|
3385
3411
|
});
|
|
3412
|
+
const isAvailable = (id) => !counts || (counts[id] ?? 0) > 0 || draft.includes(id);
|
|
3413
|
+
const countFor = (id) => counts?.[id] ?? 0;
|
|
3386
3414
|
const groupState = (g) => {
|
|
3387
|
-
const ids = groupLeaves(g).map((c) => c.id);
|
|
3415
|
+
const ids = groupLeaves(g).map((c) => c.id).filter(isAvailable);
|
|
3416
|
+
if (!ids.length) return "none";
|
|
3388
3417
|
const sel = ids.filter((id) => draft.includes(id)).length;
|
|
3389
3418
|
return sel === 0 ? "none" : sel === ids.length ? "all" : "some";
|
|
3390
3419
|
};
|
|
@@ -3392,10 +3421,12 @@ function MultiSelectFilter({
|
|
|
3392
3421
|
const isAll = shown.length === 0 || fullIsAll && shown.length === leafOptions.length;
|
|
3393
3422
|
const value = isAll ? allLabel : shown.length === 1 ? leafOptions.find((o) => o.id === shown[0])?.label ?? `${shown.length} selected` : `${shown.length} selected`;
|
|
3394
3423
|
const ql = q.trim().toLowerCase();
|
|
3395
|
-
const items = options.filter((o) => !ql || o.label.toLowerCase().includes(ql));
|
|
3424
|
+
const items = options.filter((o) => isAvailable(o.id) && (!ql || o.label.toLowerCase().includes(ql)));
|
|
3396
3425
|
const visibleGroups = groups ? groups.map((g) => {
|
|
3397
|
-
|
|
3398
|
-
|
|
3426
|
+
const live = g.children.filter((c) => isAvailable(c.id));
|
|
3427
|
+
if (!live.length && !isAvailable(g.id)) return null;
|
|
3428
|
+
if (!ql || g.label.toLowerCase().includes(ql)) return { ...g, children: live };
|
|
3429
|
+
const kids = live.filter((c) => c.label.toLowerCase().includes(ql));
|
|
3399
3430
|
return kids.length ? { ...g, children: kids } : null;
|
|
3400
3431
|
}).filter((g) => g !== null) : [];
|
|
3401
3432
|
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: cn("relative", fullWidth && "w-full"), ref, children: [
|
|
@@ -3405,7 +3436,7 @@ function MultiSelectFilter({
|
|
|
3405
3436
|
type: "button",
|
|
3406
3437
|
onClick: () => open ? close() : openTray(),
|
|
3407
3438
|
"aria-expanded": open,
|
|
3408
|
-
className: cn(chipTriggerClass(), fullWidth && "w-full justify-between"),
|
|
3439
|
+
className: cn(chipTriggerClass(variant), fullWidth && "w-full justify-between"),
|
|
3409
3440
|
children: [
|
|
3410
3441
|
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ChipContent, { caption, value, icon }),
|
|
3411
3442
|
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
@@ -3456,7 +3487,8 @@ function MultiSelectFilter({
|
|
|
3456
3487
|
className: "flex w-full items-center gap-2.5 rounded-control px-2 py-2 text-left transition-colors hover:bg-subtle",
|
|
3457
3488
|
children: [
|
|
3458
3489
|
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TriCheck, { state }),
|
|
3459
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: cn("flex-1 text-[14px] text-text-primary", !plainParent && "font-semibold"), children: g.label })
|
|
3490
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: cn("flex-1 text-[14px] text-text-primary", !plainParent && "font-semibold"), children: g.label }),
|
|
3491
|
+
counts && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(OptionCount, { n: countFor(g.id) })
|
|
3460
3492
|
]
|
|
3461
3493
|
}
|
|
3462
3494
|
),
|
|
@@ -3470,7 +3502,8 @@ function MultiSelectFilter({
|
|
|
3470
3502
|
className: "flex w-full items-center gap-2.5 rounded-control py-2 pl-9 pr-2 text-left transition-colors hover:bg-subtle",
|
|
3471
3503
|
children: [
|
|
3472
3504
|
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TriCheck, { state: checked ? "all" : "none" }),
|
|
3473
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "flex-1 text-[14px] text-text-primary", children: c.label })
|
|
3505
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "flex-1 text-[14px] text-text-primary", children: c.label }),
|
|
3506
|
+
counts && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(OptionCount, { n: countFor(c.id) })
|
|
3474
3507
|
]
|
|
3475
3508
|
},
|
|
3476
3509
|
c.id
|
|
@@ -3496,7 +3529,8 @@ function MultiSelectFilter({
|
|
|
3496
3529
|
children: checked && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react21.Check, { size: 13, strokeWidth: 3 })
|
|
3497
3530
|
}
|
|
3498
3531
|
),
|
|
3499
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "flex-1 text-[14px] text-text-primary", children: o.label })
|
|
3532
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "flex-1 text-[14px] text-text-primary", children: o.label }),
|
|
3533
|
+
counts && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(OptionCount, { n: countFor(o.id) })
|
|
3500
3534
|
]
|
|
3501
3535
|
},
|
|
3502
3536
|
o.id
|
|
@@ -3537,6 +3571,13 @@ function TriCheck({ state }) {
|
|
|
3537
3571
|
}
|
|
3538
3572
|
);
|
|
3539
3573
|
}
|
|
3574
|
+
function OptionCount({ n }) {
|
|
3575
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "shrink-0 text-[12px] tabular-nums text-text-tertiary", children: [
|
|
3576
|
+
"(",
|
|
3577
|
+
n.toLocaleString(),
|
|
3578
|
+
")"
|
|
3579
|
+
] });
|
|
3580
|
+
}
|
|
3540
3581
|
|
|
3541
3582
|
// src/Toggle.tsx
|
|
3542
3583
|
var import_jsx_runtime36 = require("react/jsx-runtime");
|