@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.js
CHANGED
|
@@ -2662,21 +2662,34 @@ function FilterDropdownFooter({
|
|
|
2662
2662
|
import { useEffect as useEffect10, useState as useState11 } from "react";
|
|
2663
2663
|
import { createPortal as createPortal5 } from "react-dom";
|
|
2664
2664
|
import { jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2665
|
-
function NameListModal({
|
|
2665
|
+
function NameListModal({
|
|
2666
|
+
title,
|
|
2667
|
+
initialName,
|
|
2668
|
+
submitLabel,
|
|
2669
|
+
onCancel,
|
|
2670
|
+
onSubmit,
|
|
2671
|
+
fieldLabel = "List name",
|
|
2672
|
+
placeholder = "e.g. Q4 prospecting targets",
|
|
2673
|
+
options
|
|
2674
|
+
}) {
|
|
2666
2675
|
const [name, setName] = useState11(initialName);
|
|
2676
|
+
const [checked, setChecked] = useState11(
|
|
2677
|
+
() => Object.fromEntries((options ?? []).map((o) => [o.key, !!o.initial]))
|
|
2678
|
+
);
|
|
2679
|
+
const toggle = (key) => setChecked((c) => ({ ...c, [key]: !c[key] }));
|
|
2667
2680
|
useEffect10(() => {
|
|
2668
2681
|
const onKey = (e) => e.key === "Escape" && onCancel();
|
|
2669
2682
|
window.addEventListener("keydown", onKey);
|
|
2670
2683
|
return () => window.removeEventListener("keydown", onKey);
|
|
2671
2684
|
}, [onCancel]);
|
|
2672
2685
|
return createPortal5(
|
|
2673
|
-
//
|
|
2674
|
-
//
|
|
2675
|
-
//
|
|
2686
|
+
// bg-scrim, not a literal: design-tokens gained a scrim token in 2.5.0.
|
|
2687
|
+
// No in-data-[theme=dark] override needed any more -- the token redefines
|
|
2688
|
+
// itself under that attribute in dark.css, so one class covers both themes.
|
|
2676
2689
|
/* @__PURE__ */ jsx26(
|
|
2677
2690
|
"div",
|
|
2678
2691
|
{
|
|
2679
|
-
className: "fixed inset-0 z-70 flex items-center justify-center bg-
|
|
2692
|
+
className: "fixed inset-0 z-70 flex items-center justify-center bg-scrim px-4",
|
|
2680
2693
|
onMouseDown: (e) => e.target === e.currentTarget && onCancel(),
|
|
2681
2694
|
children: /* @__PURE__ */ jsxs24(
|
|
2682
2695
|
"div",
|
|
@@ -2688,7 +2701,7 @@ function NameListModal({ title, initialName, submitLabel, onCancel, onSubmit })
|
|
|
2688
2701
|
children: [
|
|
2689
2702
|
/* @__PURE__ */ jsx26("h2", { className: "text-[16px] font-semibold text-text-primary", children: title }),
|
|
2690
2703
|
/* @__PURE__ */ jsxs24("div", { className: "mt-4 flex flex-col gap-1.5", children: [
|
|
2691
|
-
/* @__PURE__ */ jsx26("label", { htmlFor: "account-list-name", className: "text-[12px] font-medium text-text-secondary", children:
|
|
2704
|
+
/* @__PURE__ */ jsx26("label", { htmlFor: "account-list-name", className: "text-[12px] font-medium text-text-secondary", children: fieldLabel }),
|
|
2692
2705
|
/* @__PURE__ */ jsx26(
|
|
2693
2706
|
"input",
|
|
2694
2707
|
{
|
|
@@ -2696,14 +2709,18 @@ function NameListModal({ title, initialName, submitLabel, onCancel, onSubmit })
|
|
|
2696
2709
|
autoFocus: true,
|
|
2697
2710
|
value: name,
|
|
2698
2711
|
onChange: (e) => setName(e.target.value),
|
|
2699
|
-
placeholder
|
|
2712
|
+
placeholder,
|
|
2700
2713
|
className: "h-10 rounded-control border border-border-default bg-input px-3 text-sm outline-hidden focus:border-brand-primaryAction"
|
|
2701
2714
|
}
|
|
2702
2715
|
)
|
|
2703
2716
|
] }),
|
|
2717
|
+
options && options.length > 0 && /* @__PURE__ */ jsx26("div", { className: "mt-4 flex flex-col gap-2.5", children: options.map((o) => /* @__PURE__ */ jsxs24("label", { className: "flex cursor-pointer items-center gap-2.5 text-[13px] text-text-primary", children: [
|
|
2718
|
+
/* @__PURE__ */ jsx26(CheckBox, { checked: !!checked[o.key], onChange: () => toggle(o.key), ariaLabel: o.label }),
|
|
2719
|
+
o.label
|
|
2720
|
+
] }, o.key)) }),
|
|
2704
2721
|
/* @__PURE__ */ jsxs24("div", { className: "mt-5 flex items-center justify-end gap-2", children: [
|
|
2705
2722
|
/* @__PURE__ */ jsx26(Button, { variant: "secondary", onClick: onCancel, children: "Cancel" }),
|
|
2706
|
-
/* @__PURE__ */ jsx26(Button, { disabled: !name.trim(), onClick: () => onSubmit(name.trim()), children: submitLabel })
|
|
2723
|
+
/* @__PURE__ */ jsx26(Button, { disabled: !name.trim(), onClick: () => onSubmit(name.trim(), checked), children: submitLabel })
|
|
2707
2724
|
] })
|
|
2708
2725
|
]
|
|
2709
2726
|
}
|
|
@@ -3075,6 +3092,7 @@ import { useEffect as useEffect11, useMemo as useMemo4, useRef as useRef11, useS
|
|
|
3075
3092
|
import { ChevronDown as ChevronDown10 } from "lucide-react";
|
|
3076
3093
|
import { jsx as jsx34, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3077
3094
|
var MONTH_ABBR = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
3095
|
+
var QUARTER_ABBR = ["Q1", "Q2", "Q3", "Q4"];
|
|
3078
3096
|
var PRESETS = ["Rolling 3 months", "Rolling 6 months", "Rolling 12 months"];
|
|
3079
3097
|
var startOfToday = () => {
|
|
3080
3098
|
const d = /* @__PURE__ */ new Date();
|
|
@@ -3123,6 +3141,7 @@ function MiniSelect({ value, onChange, options }) {
|
|
|
3123
3141
|
}
|
|
3124
3142
|
function DateRangePicker({
|
|
3125
3143
|
defaultValue = "Rolling 6 months",
|
|
3144
|
+
granularity = "month",
|
|
3126
3145
|
align = "left",
|
|
3127
3146
|
presets = PRESETS,
|
|
3128
3147
|
onChange,
|
|
@@ -3141,6 +3160,8 @@ function DateRangePicker({
|
|
|
3141
3160
|
const [fromYr, setFromYr] = useState12(end.getFullYear() - 1);
|
|
3142
3161
|
const [toMo, setToMo] = useState12(end.getMonth());
|
|
3143
3162
|
const [toYr, setToYr] = useState12(end.getFullYear());
|
|
3163
|
+
const [fromQ, setFromQ] = useState12(Math.floor(end.getMonth() / 3));
|
|
3164
|
+
const [toQ, setToQ] = useState12(Math.floor(end.getMonth() / 3));
|
|
3144
3165
|
useEffect11(() => {
|
|
3145
3166
|
const [s, e] = resolveRange(value, end);
|
|
3146
3167
|
onRangeChange?.(s, e);
|
|
@@ -3167,11 +3188,11 @@ function DateRangePicker({
|
|
|
3167
3188
|
onChange?.(label);
|
|
3168
3189
|
setOpen(false);
|
|
3169
3190
|
};
|
|
3170
|
-
const span = toYr * 12 + toMo - (fromYr * 12 + fromMo) + 1;
|
|
3191
|
+
const span = granularity === "year" ? toYr - fromYr + 1 : granularity === "quarter" ? toYr * 4 + toQ - (fromYr * 4 + fromQ) + 1 : toYr * 12 + toMo - (fromYr * 12 + fromMo) + 1;
|
|
3171
3192
|
const valid = span >= 1;
|
|
3172
3193
|
const applyCustom = () => {
|
|
3173
3194
|
if (!valid) return;
|
|
3174
|
-
const label = `${MONTH_ABBR[fromMo]} ${fromYr} \u2013 ${MONTH_ABBR[toMo]} ${toYr}`;
|
|
3195
|
+
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}`;
|
|
3175
3196
|
if (showFooter) setDraft(label);
|
|
3176
3197
|
else commit(label);
|
|
3177
3198
|
};
|
|
@@ -3210,14 +3231,16 @@ function DateRangePicker({
|
|
|
3210
3231
|
/* @__PURE__ */ jsxs30("label", { className: "flex items-center justify-between gap-2 text-[12px] text-text-secondary", children: [
|
|
3211
3232
|
"From",
|
|
3212
3233
|
/* @__PURE__ */ jsxs30("span", { className: "flex gap-1", children: [
|
|
3213
|
-
/* @__PURE__ */ jsx34(MiniSelect, { value: fromMo, onChange: setFromMo, options: MONTH_ABBR.map((mm, i) => ({ label: mm, value: i })) }),
|
|
3234
|
+
granularity === "month" && /* @__PURE__ */ jsx34(MiniSelect, { value: fromMo, onChange: setFromMo, options: MONTH_ABBR.map((mm, i) => ({ label: mm, value: i })) }),
|
|
3235
|
+
granularity === "quarter" && /* @__PURE__ */ jsx34(MiniSelect, { value: fromQ, onChange: setFromQ, options: QUARTER_ABBR.map((qq, i) => ({ label: qq, value: i })) }),
|
|
3214
3236
|
/* @__PURE__ */ jsx34(MiniSelect, { value: fromYr, onChange: setFromYr, options: yearOptions.map((y) => ({ label: String(y), value: y })) })
|
|
3215
3237
|
] })
|
|
3216
3238
|
] }),
|
|
3217
3239
|
/* @__PURE__ */ jsxs30("label", { className: "flex items-center justify-between gap-2 text-[12px] text-text-secondary", children: [
|
|
3218
3240
|
"To",
|
|
3219
3241
|
/* @__PURE__ */ jsxs30("span", { className: "flex gap-1", children: [
|
|
3220
|
-
/* @__PURE__ */ jsx34(MiniSelect, { value: toMo, onChange: setToMo, options: MONTH_ABBR.map((mm, i) => ({ label: mm, value: i })) }),
|
|
3242
|
+
granularity === "month" && /* @__PURE__ */ jsx34(MiniSelect, { value: toMo, onChange: setToMo, options: MONTH_ABBR.map((mm, i) => ({ label: mm, value: i })) }),
|
|
3243
|
+
granularity === "quarter" && /* @__PURE__ */ jsx34(MiniSelect, { value: toQ, onChange: setToQ, options: QUARTER_ABBR.map((qq, i) => ({ label: qq, value: i })) }),
|
|
3221
3244
|
/* @__PURE__ */ jsx34(MiniSelect, { value: toYr, onChange: setToYr, options: yearOptions.map((y) => ({ label: String(y), value: y })) })
|
|
3222
3245
|
] })
|
|
3223
3246
|
] }),
|
|
@@ -3246,6 +3269,8 @@ function MultiSelectFilter({
|
|
|
3246
3269
|
caption,
|
|
3247
3270
|
options = [],
|
|
3248
3271
|
groups,
|
|
3272
|
+
counts,
|
|
3273
|
+
variant = "box",
|
|
3249
3274
|
selected,
|
|
3250
3275
|
onChange,
|
|
3251
3276
|
allLabel = "All",
|
|
@@ -3303,14 +3328,18 @@ function MultiSelectFilter({
|
|
|
3303
3328
|
return next;
|
|
3304
3329
|
});
|
|
3305
3330
|
const toggleGroup = (g) => setDraft((cur) => {
|
|
3306
|
-
const ids = groupLeaves(g).map((c) => c.id);
|
|
3331
|
+
const ids = groupLeaves(g).map((c) => c.id).filter((id) => !counts || (counts[id] ?? 0) > 0 || cur.includes(id));
|
|
3332
|
+
if (!ids.length) return cur;
|
|
3307
3333
|
const allSel = ids.every((id) => cur.includes(id));
|
|
3308
3334
|
const next = allSel ? cur.filter((id) => !ids.includes(id)) : [.../* @__PURE__ */ new Set([...cur, ...ids])];
|
|
3309
3335
|
if (next.length < min) return cur;
|
|
3310
3336
|
return next;
|
|
3311
3337
|
});
|
|
3338
|
+
const isAvailable = (id) => !counts || (counts[id] ?? 0) > 0 || draft.includes(id);
|
|
3339
|
+
const countFor = (id) => counts?.[id] ?? 0;
|
|
3312
3340
|
const groupState = (g) => {
|
|
3313
|
-
const ids = groupLeaves(g).map((c) => c.id);
|
|
3341
|
+
const ids = groupLeaves(g).map((c) => c.id).filter(isAvailable);
|
|
3342
|
+
if (!ids.length) return "none";
|
|
3314
3343
|
const sel = ids.filter((id) => draft.includes(id)).length;
|
|
3315
3344
|
return sel === 0 ? "none" : sel === ids.length ? "all" : "some";
|
|
3316
3345
|
};
|
|
@@ -3318,10 +3347,12 @@ function MultiSelectFilter({
|
|
|
3318
3347
|
const isAll = shown.length === 0 || fullIsAll && shown.length === leafOptions.length;
|
|
3319
3348
|
const value = isAll ? allLabel : shown.length === 1 ? leafOptions.find((o) => o.id === shown[0])?.label ?? `${shown.length} selected` : `${shown.length} selected`;
|
|
3320
3349
|
const ql = q.trim().toLowerCase();
|
|
3321
|
-
const items = options.filter((o) => !ql || o.label.toLowerCase().includes(ql));
|
|
3350
|
+
const items = options.filter((o) => isAvailable(o.id) && (!ql || o.label.toLowerCase().includes(ql)));
|
|
3322
3351
|
const visibleGroups = groups ? groups.map((g) => {
|
|
3323
|
-
|
|
3324
|
-
|
|
3352
|
+
const live = g.children.filter((c) => isAvailable(c.id));
|
|
3353
|
+
if (!live.length && !isAvailable(g.id)) return null;
|
|
3354
|
+
if (!ql || g.label.toLowerCase().includes(ql)) return { ...g, children: live };
|
|
3355
|
+
const kids = live.filter((c) => c.label.toLowerCase().includes(ql));
|
|
3325
3356
|
return kids.length ? { ...g, children: kids } : null;
|
|
3326
3357
|
}).filter((g) => g !== null) : [];
|
|
3327
3358
|
return /* @__PURE__ */ jsxs31("div", { className: cn("relative", fullWidth && "w-full"), ref, children: [
|
|
@@ -3331,7 +3362,7 @@ function MultiSelectFilter({
|
|
|
3331
3362
|
type: "button",
|
|
3332
3363
|
onClick: () => open ? close() : openTray(),
|
|
3333
3364
|
"aria-expanded": open,
|
|
3334
|
-
className: cn(chipTriggerClass(), fullWidth && "w-full justify-between"),
|
|
3365
|
+
className: cn(chipTriggerClass(variant), fullWidth && "w-full justify-between"),
|
|
3335
3366
|
children: [
|
|
3336
3367
|
/* @__PURE__ */ jsx35(ChipContent, { caption, value, icon }),
|
|
3337
3368
|
/* @__PURE__ */ jsx35(
|
|
@@ -3382,7 +3413,8 @@ function MultiSelectFilter({
|
|
|
3382
3413
|
className: "flex w-full items-center gap-2.5 rounded-control px-2 py-2 text-left transition-colors hover:bg-subtle",
|
|
3383
3414
|
children: [
|
|
3384
3415
|
/* @__PURE__ */ jsx35(TriCheck, { state }),
|
|
3385
|
-
/* @__PURE__ */ jsx35("span", { className: cn("flex-1 text-[14px] text-text-primary", !plainParent && "font-semibold"), children: g.label })
|
|
3416
|
+
/* @__PURE__ */ jsx35("span", { className: cn("flex-1 text-[14px] text-text-primary", !plainParent && "font-semibold"), children: g.label }),
|
|
3417
|
+
counts && /* @__PURE__ */ jsx35(OptionCount, { n: countFor(g.id) })
|
|
3386
3418
|
]
|
|
3387
3419
|
}
|
|
3388
3420
|
),
|
|
@@ -3396,7 +3428,8 @@ function MultiSelectFilter({
|
|
|
3396
3428
|
className: "flex w-full items-center gap-2.5 rounded-control py-2 pl-9 pr-2 text-left transition-colors hover:bg-subtle",
|
|
3397
3429
|
children: [
|
|
3398
3430
|
/* @__PURE__ */ jsx35(TriCheck, { state: checked ? "all" : "none" }),
|
|
3399
|
-
/* @__PURE__ */ jsx35("span", { className: "flex-1 text-[14px] text-text-primary", children: c.label })
|
|
3431
|
+
/* @__PURE__ */ jsx35("span", { className: "flex-1 text-[14px] text-text-primary", children: c.label }),
|
|
3432
|
+
counts && /* @__PURE__ */ jsx35(OptionCount, { n: countFor(c.id) })
|
|
3400
3433
|
]
|
|
3401
3434
|
},
|
|
3402
3435
|
c.id
|
|
@@ -3422,7 +3455,8 @@ function MultiSelectFilter({
|
|
|
3422
3455
|
children: checked && /* @__PURE__ */ jsx35(Check7, { size: 13, strokeWidth: 3 })
|
|
3423
3456
|
}
|
|
3424
3457
|
),
|
|
3425
|
-
/* @__PURE__ */ jsx35("span", { className: "flex-1 text-[14px] text-text-primary", children: o.label })
|
|
3458
|
+
/* @__PURE__ */ jsx35("span", { className: "flex-1 text-[14px] text-text-primary", children: o.label }),
|
|
3459
|
+
counts && /* @__PURE__ */ jsx35(OptionCount, { n: countFor(o.id) })
|
|
3426
3460
|
]
|
|
3427
3461
|
},
|
|
3428
3462
|
o.id
|
|
@@ -3463,6 +3497,13 @@ function TriCheck({ state }) {
|
|
|
3463
3497
|
}
|
|
3464
3498
|
);
|
|
3465
3499
|
}
|
|
3500
|
+
function OptionCount({ n }) {
|
|
3501
|
+
return /* @__PURE__ */ jsxs31("span", { className: "shrink-0 text-[12px] tabular-nums text-text-tertiary", children: [
|
|
3502
|
+
"(",
|
|
3503
|
+
n.toLocaleString(),
|
|
3504
|
+
")"
|
|
3505
|
+
] });
|
|
3506
|
+
}
|
|
3466
3507
|
|
|
3467
3508
|
// src/Toggle.tsx
|
|
3468
3509
|
import { jsx as jsx36 } from "react/jsx-runtime";
|