@diwauhris/ui 1.6.0 → 1.7.1
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/lib/assets/ui.css +53 -4
- package/lib/index.cjs +396 -53
- package/lib/index.mjs +392 -54
- package/lib/types/ui-library/gallery/column-manager/ColumnManager.d.ts +66 -0
- package/lib/types/ui-library/gallery/pagination/Pagination.d.ts +17 -1
- package/lib/types/ui-library/gallery/status-dot/MaskedValue.d.ts +54 -0
- package/lib/types/ui-library/gallery/status-page/StatusPage.d.ts +112 -0
- package/lib/types/ui-library/gallery/validation-summary/ValidationSummary.d.ts +23 -1
- package/lib/types/ui-library/index.d.ts +6 -0
- package/package.json +1 -1
package/lib/assets/ui.css
CHANGED
|
@@ -482,6 +482,11 @@
|
|
|
482
482
|
margin: auto;
|
|
483
483
|
}
|
|
484
484
|
|
|
485
|
+
.-mx-5 {
|
|
486
|
+
margin-left: -1.25rem;
|
|
487
|
+
margin-right: -1.25rem;
|
|
488
|
+
}
|
|
489
|
+
|
|
485
490
|
.mx-1 {
|
|
486
491
|
margin-left: 0.25rem;
|
|
487
492
|
margin-right: 0.25rem;
|
|
@@ -510,6 +515,10 @@
|
|
|
510
515
|
margin-top: -0.125rem;
|
|
511
516
|
}
|
|
512
517
|
|
|
518
|
+
.-mt-4 {
|
|
519
|
+
margin-top: -1rem;
|
|
520
|
+
}
|
|
521
|
+
|
|
513
522
|
.mb-0\.5 {
|
|
514
523
|
margin-bottom: 0.125rem;
|
|
515
524
|
}
|
|
@@ -610,10 +619,6 @@
|
|
|
610
619
|
margin-top: 2.5rem;
|
|
611
620
|
}
|
|
612
621
|
|
|
613
|
-
.mt-12 {
|
|
614
|
-
margin-top: 3rem;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
622
|
.mt-2 {
|
|
618
623
|
margin-top: 0.5rem;
|
|
619
624
|
}
|
|
@@ -3310,6 +3315,10 @@
|
|
|
3310
3315
|
line-height: 1;
|
|
3311
3316
|
}
|
|
3312
3317
|
|
|
3318
|
+
.text-\[100px\] {
|
|
3319
|
+
font-size: 100px;
|
|
3320
|
+
}
|
|
3321
|
+
|
|
3313
3322
|
.text-\[10px\] {
|
|
3314
3323
|
font-size: 10px;
|
|
3315
3324
|
}
|
|
@@ -3350,6 +3359,10 @@
|
|
|
3350
3359
|
font-size: 7px;
|
|
3351
3360
|
}
|
|
3352
3361
|
|
|
3362
|
+
.text-\[80px\] {
|
|
3363
|
+
font-size: 80px;
|
|
3364
|
+
}
|
|
3365
|
+
|
|
3353
3366
|
.text-\[8px\] {
|
|
3354
3367
|
font-size: 8px;
|
|
3355
3368
|
}
|
|
@@ -3798,6 +3811,14 @@
|
|
|
3798
3811
|
text-decoration-line: line-through;
|
|
3799
3812
|
}
|
|
3800
3813
|
|
|
3814
|
+
.decoration-amber-500\/60 {
|
|
3815
|
+
text-decoration-color: rgb(245 158 11 / 0.6);
|
|
3816
|
+
}
|
|
3817
|
+
|
|
3818
|
+
.underline-offset-2 {
|
|
3819
|
+
text-underline-offset: 2px;
|
|
3820
|
+
}
|
|
3821
|
+
|
|
3801
3822
|
.antialiased {
|
|
3802
3823
|
-webkit-font-smoothing: antialiased;
|
|
3803
3824
|
-moz-osx-font-smoothing: grayscale;
|
|
@@ -3813,6 +3834,10 @@
|
|
|
3813
3834
|
color: rgb(148 163 184 / var(--tw-placeholder-opacity, 1));
|
|
3814
3835
|
}
|
|
3815
3836
|
|
|
3837
|
+
.accent-brand-blue {
|
|
3838
|
+
accent-color: #034EA2;
|
|
3839
|
+
}
|
|
3840
|
+
|
|
3816
3841
|
.opacity-0 {
|
|
3817
3842
|
opacity: 0;
|
|
3818
3843
|
}
|
|
@@ -3853,6 +3878,14 @@
|
|
|
3853
3878
|
opacity: 0.8;
|
|
3854
3879
|
}
|
|
3855
3880
|
|
|
3881
|
+
.opacity-\[0\.07\] {
|
|
3882
|
+
opacity: 0.07;
|
|
3883
|
+
}
|
|
3884
|
+
|
|
3885
|
+
.opacity-\[0\.12\] {
|
|
3886
|
+
opacity: 0.12;
|
|
3887
|
+
}
|
|
3888
|
+
|
|
3856
3889
|
.shadow {
|
|
3857
3890
|
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
|
3858
3891
|
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
|
|
@@ -4673,6 +4706,9 @@ body {
|
|
|
4673
4706
|
.hover\:underline:hover {
|
|
4674
4707
|
text-decoration-line: underline;
|
|
4675
4708
|
}
|
|
4709
|
+
.hover\:decoration-amber-700:hover {
|
|
4710
|
+
text-decoration-color: #b45309;
|
|
4711
|
+
}
|
|
4676
4712
|
.hover\:opacity-100:hover {
|
|
4677
4713
|
opacity: 1;
|
|
4678
4714
|
}
|
|
@@ -4784,6 +4820,10 @@ body {
|
|
|
4784
4820
|
--tw-ring-opacity: 1;
|
|
4785
4821
|
--tw-ring-color: rgb(253 230 138 / var(--tw-ring-opacity, 1));
|
|
4786
4822
|
}
|
|
4823
|
+
.focus-visible\:ring-amber-600:focus-visible {
|
|
4824
|
+
--tw-ring-opacity: 1;
|
|
4825
|
+
--tw-ring-color: rgb(217 119 6 / var(--tw-ring-opacity, 1));
|
|
4826
|
+
}
|
|
4787
4827
|
.focus-visible\:ring-brand-blue\/15:focus-visible {
|
|
4788
4828
|
--tw-ring-color: rgb(3 78 162 / 0.15);
|
|
4789
4829
|
}
|
|
@@ -5052,6 +5092,9 @@ body {
|
|
|
5052
5092
|
padding-left: 2rem;
|
|
5053
5093
|
padding-right: 2rem;
|
|
5054
5094
|
}
|
|
5095
|
+
.sm\:text-\[120px\] {
|
|
5096
|
+
font-size: 120px;
|
|
5097
|
+
}
|
|
5055
5098
|
}
|
|
5056
5099
|
@media (min-width: 768px) {
|
|
5057
5100
|
.md\:relative {
|
|
@@ -5180,3 +5223,9 @@ body {
|
|
|
5180
5223
|
grid-template-columns: 340px minmax(0,1fr);
|
|
5181
5224
|
}
|
|
5182
5225
|
}
|
|
5226
|
+
.\[\&\>svg\]\:h-24>svg {
|
|
5227
|
+
height: 6rem;
|
|
5228
|
+
}
|
|
5229
|
+
.\[\&\>svg\]\:w-24>svg {
|
|
5230
|
+
width: 6rem;
|
|
5231
|
+
}
|
package/lib/index.cjs
CHANGED
|
@@ -1475,7 +1475,17 @@ function SegmentedControl({ options, defaultValue, value: controlledValue, onVal
|
|
|
1475
1475
|
}
|
|
1476
1476
|
//#endregion
|
|
1477
1477
|
//#region src/ui-library/gallery/validation-summary/ValidationSummary.tsx
|
|
1478
|
-
function
|
|
1478
|
+
function scrollToField(domId) {
|
|
1479
|
+
const el = document.getElementById(domId);
|
|
1480
|
+
if (!el) return;
|
|
1481
|
+
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1482
|
+
el.scrollIntoView({
|
|
1483
|
+
behavior: prefersReducedMotion ? "auto" : "smooth",
|
|
1484
|
+
block: "center"
|
|
1485
|
+
});
|
|
1486
|
+
(el.querySelector("input,select,textarea,[tabindex]") ?? el).focus();
|
|
1487
|
+
}
|
|
1488
|
+
function ValidationSummary({ issues, heading = "Review these fields before saving", fieldIds, fieldLabels, className = "" }) {
|
|
1479
1489
|
if (issues.length === 0) return null;
|
|
1480
1490
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1481
1491
|
role: "alert",
|
|
@@ -1485,14 +1495,24 @@ function ValidationSummary({ issues, heading = "Review these fields before savin
|
|
|
1485
1495
|
children: heading
|
|
1486
1496
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
1487
1497
|
className: "mt-2 list-disc space-y-1 pl-5",
|
|
1488
|
-
children: issues.map((issue) =>
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1498
|
+
children: issues.map((issue) => {
|
|
1499
|
+
const displayLabel = fieldLabels?.[issue.field] ?? issue.field;
|
|
1500
|
+
const domId = fieldIds?.[issue.field];
|
|
1501
|
+
const label = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1502
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1503
|
+
className: "font-semibold",
|
|
1504
|
+
children: [displayLabel, ":"]
|
|
1505
|
+
}),
|
|
1506
|
+
" ",
|
|
1507
|
+
issue.message
|
|
1508
|
+
] });
|
|
1509
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: domId ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1510
|
+
type: "button",
|
|
1511
|
+
onClick: () => scrollToField(domId),
|
|
1512
|
+
className: "underline decoration-amber-500/60 underline-offset-2 hover:decoration-amber-700 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-amber-600 rounded text-left",
|
|
1513
|
+
children: label
|
|
1514
|
+
}) : label }, `${issue.field}:${issue.message}`);
|
|
1515
|
+
})
|
|
1496
1516
|
})]
|
|
1497
1517
|
});
|
|
1498
1518
|
}
|
|
@@ -2879,53 +2899,72 @@ function getPageNumbers(current, total) {
|
|
|
2879
2899
|
pages.push(total);
|
|
2880
2900
|
return pages;
|
|
2881
2901
|
}
|
|
2882
|
-
function Pagination({ page, totalPages, onPageChange, ariaLabel = "Pagination" }) {
|
|
2883
|
-
if (totalPages <= 1) return null;
|
|
2902
|
+
function Pagination({ page, totalPages, onPageChange, ariaLabel = "Pagination", totalItems, pageSize, itemLabel = "items" }) {
|
|
2903
|
+
if (totalPages <= 1 && !totalItems) return null;
|
|
2904
|
+
const showRecordCount = typeof totalItems === "number" && typeof pageSize === "number";
|
|
2905
|
+
const rangeStart = showRecordCount ? (page - 1) * pageSize + 1 : null;
|
|
2906
|
+
const rangeEnd = showRecordCount ? Math.min(page * pageSize, totalItems) : null;
|
|
2884
2907
|
const pageNumbers = getPageNumbers(page, totalPages);
|
|
2885
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
2886
|
-
"
|
|
2887
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.
|
|
2888
|
-
|
|
2889
|
-
|
|
2908
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2909
|
+
className: "flex flex-col items-center gap-1.5",
|
|
2910
|
+
children: [totalPages > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("nav", {
|
|
2911
|
+
"aria-label": ariaLabel,
|
|
2912
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ol", {
|
|
2913
|
+
className: "list-none flex items-center gap-1",
|
|
2914
|
+
role: "list",
|
|
2915
|
+
children: [
|
|
2916
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2917
|
+
type: "button",
|
|
2918
|
+
onClick: () => onPageChange(page - 1),
|
|
2919
|
+
disabled: page <= 1,
|
|
2920
|
+
"aria-label": "Previous page",
|
|
2921
|
+
className: "flex h-9 w-9 items-center justify-center rounded-md border border-slate-200 bg-white text-slate-500 transition hover:border-slate-300 hover:text-slate-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30 disabled:cursor-not-allowed disabled:opacity-40",
|
|
2922
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronLeft, {
|
|
2923
|
+
size: 16,
|
|
2924
|
+
"aria-hidden": "true"
|
|
2925
|
+
})
|
|
2926
|
+
}) }),
|
|
2927
|
+
pageNumbers.map((n, idx) => n === "ellipsis" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
2928
|
+
"aria-hidden": "true",
|
|
2929
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2930
|
+
className: "flex h-9 w-9 items-center justify-center text-xs font-bold text-slate-300",
|
|
2931
|
+
children: "…"
|
|
2932
|
+
})
|
|
2933
|
+
}, `ellipsis-${idx}`) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2934
|
+
type: "button",
|
|
2935
|
+
onClick: () => onPageChange(n),
|
|
2936
|
+
"aria-label": `Page ${n}`,
|
|
2937
|
+
"aria-current": n === page ? "page" : void 0,
|
|
2938
|
+
className: ["flex h-9 w-9 items-center justify-center rounded-md text-xs font-bold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30", n === page ? "bg-brand-blue text-white shadow-md shadow-brand-blue/20" : "border border-slate-200 bg-white text-slate-500 hover:border-slate-300 hover:text-slate-800"].filter(Boolean).join(" "),
|
|
2939
|
+
children: n
|
|
2940
|
+
}) }, n)),
|
|
2941
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2942
|
+
type: "button",
|
|
2943
|
+
onClick: () => onPageChange(page + 1),
|
|
2944
|
+
disabled: page >= totalPages,
|
|
2945
|
+
"aria-label": "Next page",
|
|
2946
|
+
className: "flex h-9 w-9 items-center justify-center rounded-md border border-slate-200 bg-white text-slate-500 transition hover:border-slate-300 hover:text-slate-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30 disabled:cursor-not-allowed disabled:opacity-40",
|
|
2947
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, {
|
|
2948
|
+
size: 16,
|
|
2949
|
+
"aria-hidden": "true"
|
|
2950
|
+
})
|
|
2951
|
+
}) })
|
|
2952
|
+
]
|
|
2953
|
+
})
|
|
2954
|
+
}), showRecordCount && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
2955
|
+
className: "text-[11px] font-bold tabular-nums text-slate-400",
|
|
2956
|
+
"aria-live": "polite",
|
|
2890
2957
|
children: [
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
"aria-hidden": "true"
|
|
2900
|
-
})
|
|
2901
|
-
}) }),
|
|
2902
|
-
pageNumbers.map((n, idx) => n === "ellipsis" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
2903
|
-
"aria-hidden": "true",
|
|
2904
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2905
|
-
className: "flex h-9 w-9 items-center justify-center text-xs font-bold text-slate-300",
|
|
2906
|
-
children: "…"
|
|
2907
|
-
})
|
|
2908
|
-
}, `ellipsis-${idx}`) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2909
|
-
type: "button",
|
|
2910
|
-
onClick: () => onPageChange(n),
|
|
2911
|
-
"aria-label": `Page ${n}`,
|
|
2912
|
-
"aria-current": n === page ? "page" : void 0,
|
|
2913
|
-
className: ["flex h-9 w-9 items-center justify-center rounded-md text-xs font-bold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30", n === page ? "bg-brand-blue text-white shadow-md shadow-brand-blue/20" : "border border-slate-200 bg-white text-slate-500 hover:border-slate-300 hover:text-slate-800"].filter(Boolean).join(" "),
|
|
2914
|
-
children: n
|
|
2915
|
-
}) }, n)),
|
|
2916
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2917
|
-
type: "button",
|
|
2918
|
-
onClick: () => onPageChange(page + 1),
|
|
2919
|
-
disabled: page >= totalPages,
|
|
2920
|
-
"aria-label": "Next page",
|
|
2921
|
-
className: "flex h-9 w-9 items-center justify-center rounded-md border border-slate-200 bg-white text-slate-500 transition hover:border-slate-300 hover:text-slate-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30 disabled:cursor-not-allowed disabled:opacity-40",
|
|
2922
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, {
|
|
2923
|
-
size: 16,
|
|
2924
|
-
"aria-hidden": "true"
|
|
2925
|
-
})
|
|
2926
|
-
}) })
|
|
2958
|
+
"Showing ",
|
|
2959
|
+
rangeStart,
|
|
2960
|
+
"–",
|
|
2961
|
+
rangeEnd,
|
|
2962
|
+
" of ",
|
|
2963
|
+
totalItems,
|
|
2964
|
+
" ",
|
|
2965
|
+
itemLabel
|
|
2927
2966
|
]
|
|
2928
|
-
})
|
|
2967
|
+
})]
|
|
2929
2968
|
});
|
|
2930
2969
|
}
|
|
2931
2970
|
//#endregion
|
|
@@ -3846,6 +3885,100 @@ function EmptyState({ title, hint, icon, action, className = "" }) {
|
|
|
3846
3885
|
});
|
|
3847
3886
|
}
|
|
3848
3887
|
//#endregion
|
|
3888
|
+
//#region src/ui-library/gallery/status-page/StatusPage.tsx
|
|
3889
|
+
/**
|
|
3890
|
+
* Named presets for the three common status states.
|
|
3891
|
+
* Each preset supplies code, eyebrow, title, and description.
|
|
3892
|
+
* Consumer always provides actions — presets never include navigation.
|
|
3893
|
+
*
|
|
3894
|
+
* Usage:
|
|
3895
|
+
* <StatusPage
|
|
3896
|
+
* {...STATUS_PAGE_PRESETS.notFound}
|
|
3897
|
+
* primaryAction={{ label: 'Go to Dashboard', onClick: () => navigate('/dashboard') }}
|
|
3898
|
+
* secondaryAction={{ label: 'Go Back', onClick: () => navigate(-1) }}
|
|
3899
|
+
* />
|
|
3900
|
+
*/
|
|
3901
|
+
var STATUS_PAGE_PRESETS = {
|
|
3902
|
+
notFound: {
|
|
3903
|
+
code: "404",
|
|
3904
|
+
eyebrow: "404 — Not Found",
|
|
3905
|
+
title: "Page Not Found",
|
|
3906
|
+
description: "The page you're looking for doesn't exist or may have been moved."
|
|
3907
|
+
},
|
|
3908
|
+
forbidden: {
|
|
3909
|
+
code: "403",
|
|
3910
|
+
eyebrow: "403 — Access Restricted",
|
|
3911
|
+
title: "Access Restricted",
|
|
3912
|
+
description: "You don't have permission to view this page. Contact your system administrator if you need access."
|
|
3913
|
+
},
|
|
3914
|
+
serverError: {
|
|
3915
|
+
code: "500",
|
|
3916
|
+
eyebrow: "500 — Server Error",
|
|
3917
|
+
title: "Something Went Wrong",
|
|
3918
|
+
description: "We encountered an unexpected problem. Please try again or return to the dashboard."
|
|
3919
|
+
}
|
|
3920
|
+
};
|
|
3921
|
+
var BASE_ANCHOR = "inline-flex items-center justify-center transition-all duration-150 ease-out active:scale-[.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 select-none h-10 gap-2 rounded-md px-4 text-sm";
|
|
3922
|
+
var ANCHOR_PRIMARY = `${BASE_ANCHOR} font-bold bg-brand-blue text-white shadow-lg shadow-brand-blue/25 hover:bg-brand-navy hover:shadow-xl hover:shadow-brand-blue/30 focus-visible:ring-brand-blue/30`;
|
|
3923
|
+
var ANCHOR_OUTLINE = `${BASE_ANCHOR} font-semibold border border-slate-300 bg-white text-slate-700 shadow-sm hover:border-brand-blue/40 hover:bg-blue-50/40 hover:text-brand-blue focus-visible:ring-brand-blue/20`;
|
|
3924
|
+
function ActionButton({ action, variant }) {
|
|
3925
|
+
if (action.href) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
3926
|
+
href: action.href,
|
|
3927
|
+
className: variant === "primary" ? ANCHOR_PRIMARY : ANCHOR_OUTLINE,
|
|
3928
|
+
children: action.label
|
|
3929
|
+
});
|
|
3930
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
3931
|
+
variant,
|
|
3932
|
+
onClick: action.onClick,
|
|
3933
|
+
children: action.label
|
|
3934
|
+
});
|
|
3935
|
+
}
|
|
3936
|
+
function StatusPage({ eyebrow, title, description, code, icon, primaryAction, secondaryAction, className = "" }) {
|
|
3937
|
+
const hasActions = primaryAction || secondaryAction;
|
|
3938
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3939
|
+
className: `relative flex min-h-screen items-center justify-center bg-surface-page px-6 py-16 overflow-hidden ${className}`,
|
|
3940
|
+
children: [code ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3941
|
+
"aria-hidden": "true",
|
|
3942
|
+
className: "pointer-events-none absolute select-none font-heading font-bold text-brand-navy opacity-[0.07] text-[80px] sm:text-[120px] leading-none",
|
|
3943
|
+
children: code
|
|
3944
|
+
}) : icon ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3945
|
+
"aria-hidden": "true",
|
|
3946
|
+
className: "pointer-events-none absolute select-none text-brand-navy opacity-[0.12]",
|
|
3947
|
+
style: { fontSize: 0 },
|
|
3948
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3949
|
+
className: "block [&>svg]:h-24 [&>svg]:w-24",
|
|
3950
|
+
children: icon
|
|
3951
|
+
})
|
|
3952
|
+
}) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3953
|
+
className: "relative z-10 max-w-sm w-full os-slide-up",
|
|
3954
|
+
children: [
|
|
3955
|
+
eyebrow && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3956
|
+
className: "mb-3 text-[11px] font-bold uppercase tracking-[0.18em] text-brand-sky",
|
|
3957
|
+
children: eyebrow
|
|
3958
|
+
}),
|
|
3959
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
3960
|
+
className: "font-heading text-3xl font-bold text-brand-navy leading-tight",
|
|
3961
|
+
children: title
|
|
3962
|
+
}),
|
|
3963
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3964
|
+
className: "mt-3 text-sm font-medium text-slate-500 leading-relaxed",
|
|
3965
|
+
children: description
|
|
3966
|
+
}),
|
|
3967
|
+
hasActions && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3968
|
+
className: "mt-8 flex flex-wrap items-center gap-3",
|
|
3969
|
+
children: [primaryAction && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton, {
|
|
3970
|
+
action: primaryAction,
|
|
3971
|
+
variant: "primary"
|
|
3972
|
+
}), secondaryAction && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton, {
|
|
3973
|
+
action: secondaryAction,
|
|
3974
|
+
variant: "outline"
|
|
3975
|
+
})]
|
|
3976
|
+
})
|
|
3977
|
+
]
|
|
3978
|
+
})]
|
|
3979
|
+
});
|
|
3980
|
+
}
|
|
3981
|
+
//#endregion
|
|
3849
3982
|
//#region src/ui-library/gallery/employee-card/EmployeeCard.tsx
|
|
3850
3983
|
function EmployeeCard({ name, role, avatarSrc, status, meta, actions, className = "" }) {
|
|
3851
3984
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
@@ -7434,6 +7567,211 @@ function StatusDot({ status, label, className = "" }) {
|
|
|
7434
7567
|
});
|
|
7435
7568
|
}
|
|
7436
7569
|
//#endregion
|
|
7570
|
+
//#region src/ui-library/gallery/column-manager/ColumnManager.tsx
|
|
7571
|
+
/**
|
|
7572
|
+
* ColumnManager — Design System Component
|
|
7573
|
+
*
|
|
7574
|
+
* A dropdown panel for managing table column visibility and order.
|
|
7575
|
+
* Provides checkboxes to show/hide individual columns and up/down
|
|
7576
|
+
* buttons to reorder them. Includes a reset action.
|
|
7577
|
+
*
|
|
7578
|
+
* Purely presentational — all state is owned by the caller.
|
|
7579
|
+
*
|
|
7580
|
+
* Usage:
|
|
7581
|
+
* const [hidden, setHidden] = useState<string[]>([]);
|
|
7582
|
+
* const [order, setOrder] = useState<string[] | null>(null);
|
|
7583
|
+
*
|
|
7584
|
+
* <ColumnManager
|
|
7585
|
+
* columns={[{ key: 'name', label: 'Name' }, { key: 'dept', label: 'Department' }]}
|
|
7586
|
+
* hiddenColumnKeys={hidden}
|
|
7587
|
+
* columnOrder={order}
|
|
7588
|
+
* onHiddenColumnKeysChange={setHidden}
|
|
7589
|
+
* onColumnOrderChange={setOrder}
|
|
7590
|
+
* onReset={() => { setHidden([]); setOrder(null); }}
|
|
7591
|
+
* />
|
|
7592
|
+
*
|
|
7593
|
+
* Accessibility:
|
|
7594
|
+
* - Trigger button has aria-expanded and aria-controls.
|
|
7595
|
+
* - Panel has role="region" and aria-label.
|
|
7596
|
+
* - Each checkbox is labelled via htmlFor + id.
|
|
7597
|
+
* - Reorder buttons have descriptive aria-labels.
|
|
7598
|
+
* - Panel closes on Escape, focus returns to the trigger.
|
|
7599
|
+
*/
|
|
7600
|
+
/**
|
|
7601
|
+
* Apply a stored column order to the runtime column array.
|
|
7602
|
+
*
|
|
7603
|
+
* Rules:
|
|
7604
|
+
* - Keys in `order` that don't exist in `columns` are silently ignored
|
|
7605
|
+
* (forward compatibility when columns are removed).
|
|
7606
|
+
* - Columns not present in `order` are appended at the end in their
|
|
7607
|
+
* original relative order (forward compatibility when columns are added).
|
|
7608
|
+
* - When `order` is null the original array is returned unchanged.
|
|
7609
|
+
*/
|
|
7610
|
+
function applyColumnOrder(columns, order) {
|
|
7611
|
+
if (!order) return columns;
|
|
7612
|
+
const byKey = new Map(columns.map((c) => [c.key, c]));
|
|
7613
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7614
|
+
const result = [];
|
|
7615
|
+
for (const key of order) {
|
|
7616
|
+
const col = byKey.get(key);
|
|
7617
|
+
if (col) {
|
|
7618
|
+
result.push(col);
|
|
7619
|
+
seen.add(key);
|
|
7620
|
+
}
|
|
7621
|
+
}
|
|
7622
|
+
for (const col of columns) if (!seen.has(col.key)) result.push(col);
|
|
7623
|
+
return result;
|
|
7624
|
+
}
|
|
7625
|
+
function ColumnManager({ columns, hiddenColumnKeys, columnOrder, onHiddenColumnKeysChange, onColumnOrderChange, onReset, triggerLabel = "Columns" }) {
|
|
7626
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
7627
|
+
const triggerRef = (0, react.useRef)(null);
|
|
7628
|
+
const panelRef = (0, react.useRef)(null);
|
|
7629
|
+
const panelId = "cm-panel";
|
|
7630
|
+
const orderedColumns = applyColumnOrder(columns, columnOrder);
|
|
7631
|
+
const hiddenSet = new Set(hiddenColumnKeys);
|
|
7632
|
+
const hiddenCount = hiddenColumnKeys.length;
|
|
7633
|
+
(0, react.useEffect)(() => {
|
|
7634
|
+
if (!open) return;
|
|
7635
|
+
const handlePointerDown = (e) => {
|
|
7636
|
+
if (triggerRef.current?.contains(e.target) || panelRef.current?.contains(e.target)) return;
|
|
7637
|
+
setOpen(false);
|
|
7638
|
+
};
|
|
7639
|
+
document.addEventListener("pointerdown", handlePointerDown);
|
|
7640
|
+
return () => document.removeEventListener("pointerdown", handlePointerDown);
|
|
7641
|
+
}, [open]);
|
|
7642
|
+
(0, react.useEffect)(() => {
|
|
7643
|
+
if (!open) return;
|
|
7644
|
+
const handleKeyDown = (e) => {
|
|
7645
|
+
if (e.key === "Escape") {
|
|
7646
|
+
setOpen(false);
|
|
7647
|
+
triggerRef.current?.focus();
|
|
7648
|
+
}
|
|
7649
|
+
};
|
|
7650
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
7651
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
7652
|
+
}, [open]);
|
|
7653
|
+
function toggleColumn(key) {
|
|
7654
|
+
onHiddenColumnKeysChange(hiddenSet.has(key) ? hiddenColumnKeys.filter((k) => k !== key) : [...hiddenColumnKeys, key]);
|
|
7655
|
+
}
|
|
7656
|
+
function moveUp(index) {
|
|
7657
|
+
if (index === 0) return;
|
|
7658
|
+
const next = [...orderedColumns];
|
|
7659
|
+
[next[index - 1], next[index]] = [next[index], next[index - 1]];
|
|
7660
|
+
onColumnOrderChange(next.map((c) => c.key));
|
|
7661
|
+
}
|
|
7662
|
+
function moveDown(index) {
|
|
7663
|
+
if (index === orderedColumns.length - 1) return;
|
|
7664
|
+
const next = [...orderedColumns];
|
|
7665
|
+
[next[index], next[index + 1]] = [next[index + 1], next[index]];
|
|
7666
|
+
onColumnOrderChange(next.map((c) => c.key));
|
|
7667
|
+
}
|
|
7668
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7669
|
+
className: "relative inline-block",
|
|
7670
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
7671
|
+
ref: triggerRef,
|
|
7672
|
+
type: "button",
|
|
7673
|
+
"aria-expanded": open,
|
|
7674
|
+
"aria-controls": open ? panelId : void 0,
|
|
7675
|
+
onClick: () => setOpen((v) => !v),
|
|
7676
|
+
className: "inline-flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-2 text-xs font-bold text-slate-600 shadow-sm transition hover:border-slate-300 hover:bg-slate-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30",
|
|
7677
|
+
children: [
|
|
7678
|
+
triggerLabel,
|
|
7679
|
+
hiddenCount > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7680
|
+
className: "rounded-full bg-brand-blue/10 px-1.5 py-0.5 font-bold text-brand-blue",
|
|
7681
|
+
children: [hiddenCount, " hidden"]
|
|
7682
|
+
}),
|
|
7683
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronDown, {
|
|
7684
|
+
size: 13,
|
|
7685
|
+
className: `transition-transform ${open ? "rotate-180" : ""}`,
|
|
7686
|
+
"aria-hidden": "true"
|
|
7687
|
+
})
|
|
7688
|
+
]
|
|
7689
|
+
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7690
|
+
id: panelId,
|
|
7691
|
+
ref: panelRef,
|
|
7692
|
+
role: "region",
|
|
7693
|
+
"aria-label": "Manage columns",
|
|
7694
|
+
className: "absolute right-0 top-full z-30 mt-1 flex w-64 flex-col overflow-hidden rounded-xl border border-slate-200 bg-white shadow-xl",
|
|
7695
|
+
style: { maxHeight: 400 },
|
|
7696
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7697
|
+
className: "flex shrink-0 items-center justify-between border-b border-slate-100 px-4 py-2.5",
|
|
7698
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7699
|
+
className: "text-xs font-bold text-slate-700",
|
|
7700
|
+
children: "Columns"
|
|
7701
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7702
|
+
type: "button",
|
|
7703
|
+
onClick: () => {
|
|
7704
|
+
onReset();
|
|
7705
|
+
setOpen(false);
|
|
7706
|
+
},
|
|
7707
|
+
className: "rounded-md px-2 py-1 text-[11px] font-bold text-slate-400 hover:bg-slate-100 hover:text-slate-700 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-brand-blue/30 transition",
|
|
7708
|
+
children: "Reset"
|
|
7709
|
+
})]
|
|
7710
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
7711
|
+
className: "overflow-y-auto",
|
|
7712
|
+
role: "list",
|
|
7713
|
+
children: orderedColumns.map((col, idx) => {
|
|
7714
|
+
const visible = !hiddenSet.has(col.key);
|
|
7715
|
+
const checkboxId = `cm-col-${col.key}`;
|
|
7716
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
7717
|
+
className: "flex items-center gap-2 border-b border-slate-50 px-3 py-2 last:border-0",
|
|
7718
|
+
children: [
|
|
7719
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
7720
|
+
type: "checkbox",
|
|
7721
|
+
id: checkboxId,
|
|
7722
|
+
checked: visible,
|
|
7723
|
+
onChange: () => toggleColumn(col.key),
|
|
7724
|
+
className: "h-3.5 w-3.5 rounded accent-brand-blue focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-brand-blue/30"
|
|
7725
|
+
}),
|
|
7726
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
7727
|
+
htmlFor: checkboxId,
|
|
7728
|
+
className: `flex-1 cursor-pointer text-xs font-medium ${visible ? "text-slate-700" : "text-slate-400"}`,
|
|
7729
|
+
children: col.label
|
|
7730
|
+
}),
|
|
7731
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7732
|
+
className: "flex shrink-0 gap-0.5",
|
|
7733
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7734
|
+
type: "button",
|
|
7735
|
+
"aria-label": `Move ${col.label} up`,
|
|
7736
|
+
disabled: idx === 0,
|
|
7737
|
+
onClick: () => moveUp(idx),
|
|
7738
|
+
className: "rounded p-1 text-slate-300 hover:bg-slate-100 hover:text-slate-600 disabled:cursor-not-allowed disabled:opacity-30 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-brand-blue/30 transition",
|
|
7739
|
+
children: "▲"
|
|
7740
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7741
|
+
type: "button",
|
|
7742
|
+
"aria-label": `Move ${col.label} down`,
|
|
7743
|
+
disabled: idx === orderedColumns.length - 1,
|
|
7744
|
+
onClick: () => moveDown(idx),
|
|
7745
|
+
className: "rounded p-1 text-slate-300 hover:bg-slate-100 hover:text-slate-600 disabled:cursor-not-allowed disabled:opacity-30 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-brand-blue/30 transition",
|
|
7746
|
+
children: "▼"
|
|
7747
|
+
})]
|
|
7748
|
+
})
|
|
7749
|
+
]
|
|
7750
|
+
}, col.key);
|
|
7751
|
+
})
|
|
7752
|
+
})]
|
|
7753
|
+
})]
|
|
7754
|
+
});
|
|
7755
|
+
}
|
|
7756
|
+
//#endregion
|
|
7757
|
+
//#region src/ui-library/gallery/status-dot/MaskedValue.tsx
|
|
7758
|
+
function MaskedValue({ value, masked, maskText = "••••• •••••", maskLabel = "Value restricted", className = "" }) {
|
|
7759
|
+
if (!masked) return className ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7760
|
+
className,
|
|
7761
|
+
children: value
|
|
7762
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: value });
|
|
7763
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7764
|
+
"aria-label": maskLabel,
|
|
7765
|
+
title: maskLabel,
|
|
7766
|
+
className: [
|
|
7767
|
+
"inline-flex select-none items-center rounded-md bg-slate-100 px-2 py-0.5",
|
|
7768
|
+
"font-mono text-xs font-medium text-slate-400 tracking-wider",
|
|
7769
|
+
className
|
|
7770
|
+
].filter(Boolean).join(" "),
|
|
7771
|
+
children: maskText
|
|
7772
|
+
});
|
|
7773
|
+
}
|
|
7774
|
+
//#endregion
|
|
7437
7775
|
//#region src/ui-library/gallery/status-actions/statusActions.ts
|
|
7438
7776
|
/**
|
|
7439
7777
|
* statusActions — Gallery-native lifecycle transition utilities.
|
|
@@ -7638,6 +7976,7 @@ exports.CardContent = CardContent;
|
|
|
7638
7976
|
exports.CardFooter = CardFooter;
|
|
7639
7977
|
exports.CardHeader = CardHeader;
|
|
7640
7978
|
exports.Checkbox = Checkbox;
|
|
7979
|
+
exports.ColumnManager = ColumnManager;
|
|
7641
7980
|
exports.Combobox = Combobox;
|
|
7642
7981
|
exports.CommandPalette = CommandPalette;
|
|
7643
7982
|
exports.ConfirmAction = ConfirmAction;
|
|
@@ -7665,6 +8004,7 @@ exports.Input = Input;
|
|
|
7665
8004
|
exports.IsoCubeBlock = IsoCubeBlock;
|
|
7666
8005
|
exports.Kanban = Kanban;
|
|
7667
8006
|
exports.LineChart = LineChart;
|
|
8007
|
+
exports.MaskedValue = MaskedValue;
|
|
7668
8008
|
exports.Menu = Menu;
|
|
7669
8009
|
exports.Modal = Modal;
|
|
7670
8010
|
exports.OrgChart = OrgChart;
|
|
@@ -7682,6 +8022,7 @@ exports.Progress = Progress;
|
|
|
7682
8022
|
exports.RadioGroup = RadioGroup;
|
|
7683
8023
|
exports.RadioItem = RadioItem;
|
|
7684
8024
|
exports.ReportTemplate = ReportTemplate;
|
|
8025
|
+
exports.STATUS_PAGE_PRESETS = STATUS_PAGE_PRESETS;
|
|
7685
8026
|
exports.Section = Section;
|
|
7686
8027
|
exports.SegmentedControl = SegmentedControl;
|
|
7687
8028
|
exports.Select = Select;
|
|
@@ -7698,6 +8039,7 @@ exports.Spinner = Spinner;
|
|
|
7698
8039
|
exports.Statistic = Statistic;
|
|
7699
8040
|
exports.StatusBadge = StatusBadge;
|
|
7700
8041
|
exports.StatusDot = StatusDot;
|
|
8042
|
+
exports.StatusPage = StatusPage;
|
|
7701
8043
|
exports.Stepper = Stepper;
|
|
7702
8044
|
exports.Switch = Switch;
|
|
7703
8045
|
exports.Tab = Tab;
|
|
@@ -7722,6 +8064,7 @@ exports.Toolbar = Toolbar;
|
|
|
7722
8064
|
exports.Tooltip = Tooltip;
|
|
7723
8065
|
exports.TreeView = TreeView;
|
|
7724
8066
|
exports.ValidationSummary = ValidationSummary;
|
|
8067
|
+
exports.applyColumnOrder = applyColumnOrder;
|
|
7725
8068
|
Object.defineProperty(exports, "colors", {
|
|
7726
8069
|
enumerable: true,
|
|
7727
8070
|
get: function() {
|