@diwauhris/ui 1.5.0 → 1.7.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/lib/index.cjs CHANGED
@@ -32,6 +32,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
32
32
  //#endregion
33
33
  let react_jsx_runtime = require("react/jsx-runtime");
34
34
  let react = require("react");
35
+ react = __toESM(react, 1);
35
36
  let clsx = require("clsx");
36
37
  let tailwind_merge = require("tailwind-merge");
37
38
  let lucide_react = require("lucide-react");
@@ -46,6 +47,8 @@ _radix_ui_react_popover = __toESM(_radix_ui_react_popover, 1);
46
47
  let _radix_ui_react_tooltip = require("@radix-ui/react-tooltip");
47
48
  _radix_ui_react_tooltip = __toESM(_radix_ui_react_tooltip, 1);
48
49
  let react_router_dom = require("react-router-dom");
50
+ let d3 = require("d3");
51
+ d3 = __toESM(d3, 1);
49
52
  let sonner = require("sonner");
50
53
  //#region src/ui-library/gallery/button/Button.tsx
51
54
  var VARIANT_STYLES$1 = {
@@ -212,15 +215,15 @@ function getInitials(name) {
212
215
  return ((parts[0] ?? "").charAt(0) + (parts[parts.length - 1] ?? "").charAt(0)).toUpperCase();
213
216
  }
214
217
  var PALETTE = [
215
- "#0B2545",
218
+ "#00377B",
219
+ "#034EA2",
220
+ "#2D8ACA",
221
+ "#00ADCC",
222
+ "#00A74C",
223
+ "#B61D66",
224
+ "#F68B1F",
216
225
  "#0F4C81",
217
- "#0369A1",
218
- "#1E3A8A",
219
- "#0D9488",
220
- "#0F766E",
221
- "#B45309",
222
- "#C2410C",
223
- "#BE185D"
226
+ "#0369A1"
224
227
  ];
225
228
  function deriveColor(name) {
226
229
  if (!name) return PALETTE[0];
@@ -718,6 +721,7 @@ function RadioItem({ value, label, description, disabled: itemDisabled = false,
718
721
  const isDisabled = groupDisabled || itemDisabled;
719
722
  const isChecked = activeValue === value;
720
723
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
724
+ htmlFor: id,
721
725
  className: [
722
726
  "group flex cursor-pointer items-start gap-3",
723
727
  isDisabled ? "cursor-not-allowed opacity-50" : "",
@@ -733,7 +737,8 @@ function RadioItem({ value, label, description, disabled: itemDisabled = false,
733
737
  disabled: isDisabled,
734
738
  required,
735
739
  onChange: () => !isDisabled && select(value),
736
- className: "peer sr-only"
740
+ className: "peer sr-only",
741
+ "aria-label": typeof label === "string" ? label : void 0
737
742
  }),
738
743
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
739
744
  className: [
@@ -773,6 +778,7 @@ function Switch({ checked, onChange, label, description, disabled = false, loadi
773
778
  role: "switch",
774
779
  "aria-checked": checked,
775
780
  "aria-labelledby": labelId,
781
+ "aria-label": !label ? "Toggle" : void 0,
776
782
  "aria-disabled": !isInteractive || void 0,
777
783
  disabled: !isInteractive,
778
784
  onClick: () => isInteractive && onChange(!checked),
@@ -812,7 +818,7 @@ function Switch({ checked, onChange, label, description, disabled = false, loadi
812
818
  */
813
819
  var fieldInputClass = "w-full rounded-xl border border-slate-200 bg-slate-50 px-4 py-2.5 text-sm font-medium text-slate-900 outline-none transition placeholder:text-slate-400 focus:border-brand-blue/40 focus:ring-2 focus:ring-brand-blue/15 disabled:cursor-not-allowed disabled:opacity-60";
814
820
  var fieldInputErrorClass = "border-rose-300 focus:border-rose-400 focus:ring-rose-100";
815
- function Combobox({ value, onChange, options, placeholder, className, disabled, loading, error }) {
821
+ function Combobox({ value, onChange, options, placeholder, className, disabled, loading, error, "aria-label": ariaLabel }) {
816
822
  const [isOpen, setIsOpen] = (0, react.useState)(false);
817
823
  const [search, setSearch] = (0, react.useState)(value);
818
824
  const [highlightIndex, setHighlightIndex] = (0, react.useState)(-1);
@@ -893,6 +899,7 @@ function Combobox({ value, onChange, options, placeholder, className, disabled,
893
899
  "aria-activedescendant": highlightIndex >= 0 ? optionId(highlightIndex) : void 0,
894
900
  "aria-autocomplete": "list",
895
901
  "aria-invalid": error ? "true" : void 0,
902
+ "aria-label": ariaLabel,
896
903
  value: search,
897
904
  onChange: handleInputChange,
898
905
  onFocus: () => setIsOpen(true),
@@ -2394,12 +2401,6 @@ var radius = {
2394
2401
  * - Use gallery Button component (Phase 11 — replaces legacy inlined btn* strings)
2395
2402
  * - Use a simple inline ErrorBanner instead of importing from ui.tsx
2396
2403
  */
2397
- function ErrorBanner$1({ message }) {
2398
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2399
- className: "rounded-lg border border-rose-100 bg-rose-50 px-4 py-3 text-sm font-medium text-rose-700",
2400
- children: message
2401
- });
2402
- }
2403
2404
  function ConfirmAction({ title, message, label, description, confirmLabel = "Confirm", tone = "danger", disabled = false, onConfirm, children }) {
2404
2405
  const [open, setOpen] = (0, react.useState)(false);
2405
2406
  const [pending, setPending] = (0, react.useState)(false);
@@ -2461,7 +2462,7 @@ function ConfirmAction({ title, message, label, description, confirmLabel = "Con
2461
2462
  className: "text-sm font-medium leading-relaxed text-slate-600",
2462
2463
  children: effectiveMessage
2463
2464
  })]
2464
- }), error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorBanner$1, { message: error })]
2465
+ }), error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorBanner, { message: error })]
2465
2466
  })
2466
2467
  })] });
2467
2468
  }
@@ -2952,8 +2953,8 @@ function StepCircle({ state, number, icon }) {
2952
2953
  }
2953
2954
  function Stepper({ steps, currentStep, completedSteps = [], disabledSteps = [], orientation = "horizontal", className = "" }) {
2954
2955
  if (!(orientation === "horizontal")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2956
+ role: "group",
2955
2957
  "aria-label": "Progress",
2956
- "aria-orientation": "vertical",
2957
2958
  className: ["flex flex-col", className].filter(Boolean).join(" "),
2958
2959
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ol", {
2959
2960
  className: "flex flex-col",
@@ -3001,34 +3002,48 @@ function Stepper({ steps, currentStep, completedSteps = [], disabledSteps = [],
3001
3002
  disabled: "text-slate-300"
3002
3003
  };
3003
3004
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3005
+ role: "group",
3004
3006
  "aria-label": "Progress",
3005
- "aria-orientation": "horizontal",
3006
3007
  className: ["w-full", className].filter(Boolean).join(" "),
3007
3008
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ol", {
3008
- className: "flex items-start w-full",
3009
+ className: "grid w-full",
3010
+ style: { gridTemplateColumns: `repeat(${steps.length}, 1fr)` },
3009
3011
  children: steps.map((step, idx) => {
3010
3012
  const state = resolvedStates[idx];
3011
3013
  const isCurrent = state === "current";
3012
3014
  const isLast = idx === steps.length - 1;
3015
+ const prevState = idx > 0 ? resolvedStates[idx - 1] : null;
3013
3016
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
3014
3017
  "aria-current": isCurrent ? "step" : void 0,
3015
- className: ["flex flex-col items-center relative", isLast ? "" : "flex-1"].filter(Boolean).join(" "),
3018
+ className: "flex flex-col items-center",
3016
3019
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3017
- className: "flex items-center w-full",
3018
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3019
- className: "shrink-0 z-10",
3020
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepCircle, {
3021
- state,
3022
- number: idx + 1,
3023
- icon: step.icon
3020
+ className: "flex w-full items-center",
3021
+ children: [
3022
+ idx > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3023
+ className: `h-0.5 flex-1 ${prevState === "completed" || prevState === "current" ? "bg-brand-blue/50" : "bg-slate-200"}`,
3024
+ "aria-hidden": "true"
3025
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3026
+ className: "flex-1",
3027
+ "aria-hidden": "true"
3028
+ }),
3029
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3030
+ className: "shrink-0 z-10",
3031
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepCircle, {
3032
+ state,
3033
+ number: idx + 1,
3034
+ icon: step.icon
3035
+ })
3036
+ }),
3037
+ !isLast ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3038
+ className: `h-0.5 flex-1 ${state === "completed" ? "bg-brand-blue/50" : "bg-slate-200"}`,
3039
+ "aria-hidden": "true"
3040
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3041
+ className: "flex-1",
3042
+ "aria-hidden": "true"
3024
3043
  })
3025
- }), !isLast && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3026
- className: `h-0.5 flex-1 ${state === "completed" ? "bg-brand-blue/50" : "bg-slate-200"}`,
3027
- "aria-hidden": "true"
3028
- })]
3044
+ ]
3029
3045
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3030
- className: "mt-2 flex flex-col items-center text-center w-max max-w-[120px]",
3031
- style: { transform: isLast ? "translateX(calc(50% - 1.125rem))" : idx === 0 ? "translateX(calc(-50% + 1.125rem))" : void 0 },
3046
+ className: "mt-2 flex flex-col items-center text-center px-1",
3032
3047
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3033
3048
  className: `text-sm leading-tight ${labelColor[state]}`,
3034
3049
  children: step.label
@@ -3310,20 +3325,22 @@ function Menu({ trigger, items, ariaLabel = "Menu", align = "right" }) {
3310
3325
  focusItem(items.length - 1);
3311
3326
  }
3312
3327
  };
3328
+ const panelAlign = align === "left" ? "left-0" : "right-0";
3313
3329
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3314
3330
  className: "relative inline-block",
3315
3331
  ref: containerRef,
3316
3332
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3317
3333
  ref: triggerRef,
3318
- "aria-expanded": open,
3319
- "aria-haspopup": "menu",
3320
3334
  onClick: () => setOpen((v) => !v),
3321
3335
  className: "cursor-pointer",
3322
- children: trigger
3336
+ children: (0, react.isValidElement)(trigger) ? (0, react.cloneElement)(trigger, {
3337
+ "aria-expanded": open,
3338
+ "aria-haspopup": "menu"
3339
+ }) : trigger
3323
3340
  }), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3324
3341
  role: "menu",
3325
3342
  "aria-label": ariaLabel,
3326
- className: `absolute top-full ${align === "left" ? "left-0" : "right-0"} z-30 mt-1 min-w-[11rem] overflow-hidden rounded-xl border border-slate-200 bg-white py-1 shadow-xl`,
3343
+ className: `absolute top-full ${panelAlign} z-30 mt-1 min-w-[11rem] overflow-hidden rounded-xl border border-slate-200 bg-white py-1 shadow-xl`,
3327
3344
  children: items.map((item, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3328
3345
  ref: (node) => {
3329
3346
  itemRefs.current[index] = node;
@@ -3727,6 +3744,7 @@ function TimelineValueCard({ beforeLabel = "Previous", afterLabel = "Current", b
3727
3744
  })]
3728
3745
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3729
3746
  className: "text-sm text-slate-500 leading-snug",
3747
+ role: "group",
3730
3748
  "aria-label": `${beforeLabel} value`,
3731
3749
  children: beforeContent
3732
3750
  })]
@@ -3753,6 +3771,7 @@ function TimelineValueCard({ beforeLabel = "Previous", afterLabel = "Current", b
3753
3771
  })]
3754
3772
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3755
3773
  className: "text-sm font-semibold text-slate-800 leading-snug",
3774
+ role: "group",
3756
3775
  "aria-label": `${afterLabel} value`,
3757
3776
  children: afterContent
3758
3777
  })]
@@ -3827,6 +3846,100 @@ function EmptyState({ title, hint, icon, action, className = "" }) {
3827
3846
  });
3828
3847
  }
3829
3848
  //#endregion
3849
+ //#region src/ui-library/gallery/status-page/StatusPage.tsx
3850
+ /**
3851
+ * Named presets for the three common status states.
3852
+ * Each preset supplies code, eyebrow, title, and description.
3853
+ * Consumer always provides actions — presets never include navigation.
3854
+ *
3855
+ * Usage:
3856
+ * <StatusPage
3857
+ * {...STATUS_PAGE_PRESETS.notFound}
3858
+ * primaryAction={{ label: 'Go to Dashboard', onClick: () => navigate('/dashboard') }}
3859
+ * secondaryAction={{ label: 'Go Back', onClick: () => navigate(-1) }}
3860
+ * />
3861
+ */
3862
+ var STATUS_PAGE_PRESETS = {
3863
+ notFound: {
3864
+ code: "404",
3865
+ eyebrow: "404 — Not Found",
3866
+ title: "Page Not Found",
3867
+ description: "The page you're looking for doesn't exist or may have been moved."
3868
+ },
3869
+ forbidden: {
3870
+ code: "403",
3871
+ eyebrow: "403 — Access Restricted",
3872
+ title: "Access Restricted",
3873
+ description: "You don't have permission to view this page. Contact your system administrator if you need access."
3874
+ },
3875
+ serverError: {
3876
+ code: "500",
3877
+ eyebrow: "500 — Server Error",
3878
+ title: "Something Went Wrong",
3879
+ description: "We encountered an unexpected problem. Please try again or return to the dashboard."
3880
+ }
3881
+ };
3882
+ 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";
3883
+ 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`;
3884
+ 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`;
3885
+ function ActionButton({ action, variant }) {
3886
+ if (action.href) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
3887
+ href: action.href,
3888
+ className: variant === "primary" ? ANCHOR_PRIMARY : ANCHOR_OUTLINE,
3889
+ children: action.label
3890
+ });
3891
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
3892
+ variant,
3893
+ onClick: action.onClick,
3894
+ children: action.label
3895
+ });
3896
+ }
3897
+ function StatusPage({ eyebrow, title, description, code, icon, primaryAction, secondaryAction, className = "" }) {
3898
+ const hasActions = primaryAction || secondaryAction;
3899
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3900
+ className: `relative flex min-h-screen items-center justify-center bg-surface-page px-6 py-16 overflow-hidden ${className}`,
3901
+ children: [code ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3902
+ "aria-hidden": "true",
3903
+ className: "pointer-events-none absolute select-none font-heading font-bold text-brand-navy opacity-[0.07] text-[80px] sm:text-[120px] leading-none",
3904
+ children: code
3905
+ }) : icon ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3906
+ "aria-hidden": "true",
3907
+ className: "pointer-events-none absolute select-none text-brand-navy opacity-[0.12]",
3908
+ style: { fontSize: 0 },
3909
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3910
+ className: "block [&>svg]:h-24 [&>svg]:w-24",
3911
+ children: icon
3912
+ })
3913
+ }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3914
+ className: "relative z-10 max-w-sm w-full os-slide-up",
3915
+ children: [
3916
+ eyebrow && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3917
+ className: "mb-3 text-[11px] font-bold uppercase tracking-[0.18em] text-brand-sky",
3918
+ children: eyebrow
3919
+ }),
3920
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
3921
+ className: "font-heading text-3xl font-bold text-brand-navy leading-tight",
3922
+ children: title
3923
+ }),
3924
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3925
+ className: "mt-3 text-sm font-medium text-slate-500 leading-relaxed",
3926
+ children: description
3927
+ }),
3928
+ hasActions && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3929
+ className: "mt-8 flex flex-wrap items-center gap-3",
3930
+ children: [primaryAction && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton, {
3931
+ action: primaryAction,
3932
+ variant: "primary"
3933
+ }), secondaryAction && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton, {
3934
+ action: secondaryAction,
3935
+ variant: "outline"
3936
+ })]
3937
+ })
3938
+ ]
3939
+ })]
3940
+ });
3941
+ }
3942
+ //#endregion
3830
3943
  //#region src/ui-library/gallery/employee-card/EmployeeCard.tsx
3831
3944
  function EmployeeCard({ name, role, avatarSrc, status, meta, actions, className = "" }) {
3832
3945
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
@@ -3918,11 +4031,11 @@ function EmployeeCard({ name, role, avatarSrc, status, meta, actions, className
3918
4031
  * onSelect={setSelected}
3919
4032
  * />
3920
4033
  */
3921
- function flattenVisible(items, expanded) {
4034
+ function flattenVisible$1(items, expanded) {
3922
4035
  const result = [];
3923
4036
  for (const item of items) {
3924
4037
  result.push(item);
3925
- if (item.children && expanded.has(item.id)) result.push(...flattenVisible(item.children, expanded));
4038
+ if (item.children && expanded.has(item.id)) result.push(...flattenVisible$1(item.children, expanded));
3926
4039
  }
3927
4040
  return result;
3928
4041
  }
@@ -4012,7 +4125,7 @@ function TreeView({ items, selectedId, onSelect, "aria-label": ariaLabel, classN
4012
4125
  onSelect?.(id);
4013
4126
  }, [onSelect]);
4014
4127
  const handleKeyDown = (e) => {
4015
- const visible = flattenVisible(items, expanded);
4128
+ const visible = flattenVisible$1(items, expanded);
4016
4129
  if (visible.length === 0) return;
4017
4130
  const currentId = selectedId ?? visible[0]?.id;
4018
4131
  const currentIdx = visible.findIndex((v) => v.id === currentId);
@@ -4361,67 +4474,154 @@ function Calendar({ value, defaultValue, onChange, minDate, maxDate, className =
4361
4474
  }
4362
4475
  //#endregion
4363
4476
  //#region src/ui-library/gallery/charts/Charts.tsx
4364
- function BarChart({ data, height = 160, barColor = "#6366f1", "aria-label": ariaLabel, className = "" }) {
4477
+ /**
4478
+ * Charts — Design System Components
4479
+ *
4480
+ * Lightweight SVG-native chart primitives. No charting library dependency.
4481
+ * Suitable for simple analytics/KPI displays.
4482
+ *
4483
+ * Components:
4484
+ * BarChart — vertical bar chart
4485
+ * LineChart — line/area chart (SVG path)
4486
+ * CHART_PALETTE — shared default color sequence for multi-series charts
4487
+ *
4488
+ * Visual language (applied as defaults, no new props):
4489
+ * - BarChart: top-only rounded corners, subtle same-hue gradient fill,
4490
+ * baseline rule, value labels inside SVG above bars, comfortable gaps
4491
+ * - LineChart: gradient area fill fading to transparent, strokeWidth 2,
4492
+ * white-ring dots only when ≤ 12 data points, no horizontal distortion
4493
+ *
4494
+ * Accessibility:
4495
+ * - role="img" on every SVG with aria-label describing the chart
4496
+ * - Each bar/point has aria-label with label and value
4497
+ * - Decorative elements are aria-hidden
4498
+ */
4499
+ /**
4500
+ * Default color sequence for multi-series / per-item charts.
4501
+ * Built on the brand's blue-sky hue family with a single warm accent.
4502
+ * Import this directly when constructing per-item color arrays:
4503
+ *
4504
+ * import { CHART_PALETTE } from '@diwauhris/ui';
4505
+ * const data = items.map((item, i) => ({ ...item, color: CHART_PALETTE[i % CHART_PALETTE.length] }));
4506
+ */
4507
+ var CHART_PALETTE = [
4508
+ "#034EA2",
4509
+ "#2D8ACA",
4510
+ "#4F6FBF",
4511
+ "#0E7490",
4512
+ "#B45309"
4513
+ ];
4514
+ function BarChart({ data, height = 160, barColor = "#034EA2", "aria-label": ariaLabel, className = "" }) {
4515
+ const uid = (0, react.useId)().replace(/:/g, "");
4365
4516
  const max = Math.max(...data.map((d) => d.value), 1);
4366
- const w = 100 / data.length;
4367
- const gap = .4;
4517
+ const n = data.length;
4518
+ const W = Math.max(n * 50, 200);
4519
+ const w = W / n;
4520
+ const gap = w * .2;
4368
4521
  const bw = w - gap * 2;
4369
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4370
- className: `space-y-2 ${className}`,
4371
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
4522
+ const bottomPad = 24;
4523
+ const labelGap = 4;
4524
+ const chartH = height - bottomPad;
4525
+ const baselineY = chartH;
4526
+ const isDefaultBarColor = barColor === "#034EA2";
4527
+ const fillColors = data.map((d, i) => d.color ?? (isDefaultBarColor ? CHART_PALETTE[i % CHART_PALETTE.length] ?? barColor : barColor));
4528
+ const distinctColors = Array.from(new Set(fillColors));
4529
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4530
+ className,
4531
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
4372
4532
  role: "img",
4373
4533
  "aria-label": ariaLabel,
4374
- viewBox: `0 0 100 ${height}`,
4534
+ viewBox: `0 0 ${W} ${height}`,
4375
4535
  preserveAspectRatio: "none",
4376
4536
  className: "w-full",
4377
4537
  style: { height },
4378
- children: [data.map((d, i) => {
4379
- const barH = d.value / max * (height - 24);
4380
- const x = i * w + gap;
4381
- const y = height - 20 - barH;
4382
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", {
4383
- "aria-label": `${d.label}: ${d.value}`,
4384
- role: "img",
4385
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
4386
- x,
4387
- y,
4388
- width: bw,
4389
- height: barH,
4390
- rx: "2",
4391
- fill: d.color ?? barColor,
4392
- opacity: .9
4393
- })
4394
- }, d.label);
4395
- }), data.map((d, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
4396
- x: i * w + w / 2,
4397
- y: height - 4,
4398
- textAnchor: "middle",
4399
- className: "fill-slate-500",
4400
- style: {
4401
- fontSize: "6px",
4402
- fontFamily: "inherit"
4403
- },
4404
- "aria-hidden": "true",
4405
- children: d.label
4406
- }, `lbl-${d.label}`))]
4407
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4408
- className: "flex justify-around",
4409
- children: data.map((d) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4410
- className: "text-[10px] font-bold text-slate-600",
4411
- children: d.value
4412
- }, d.label))
4413
- })]
4538
+ children: [
4539
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: distinctColors.map((color) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("linearGradient", {
4540
+ id: `${uid}-bg-${color.replace("#", "")}`,
4541
+ x1: "0",
4542
+ y1: "0",
4543
+ x2: "0",
4544
+ y2: height - bottomPad,
4545
+ gradientUnits: "userSpaceOnUse",
4546
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("stop", {
4547
+ offset: "0%",
4548
+ stopColor: color,
4549
+ stopOpacity: 1
4550
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("stop", {
4551
+ offset: "100%",
4552
+ stopColor: color,
4553
+ stopOpacity: .7
4554
+ })]
4555
+ }, color)) }),
4556
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
4557
+ x1: 0,
4558
+ y1: baselineY,
4559
+ x2: W,
4560
+ y2: baselineY,
4561
+ stroke: "#e2e8f0",
4562
+ strokeWidth: .5,
4563
+ "aria-hidden": "true"
4564
+ }),
4565
+ data.map((d, i) => {
4566
+ const fillColor = fillColors[i];
4567
+ const gradId = `${uid}-bg-${fillColor.replace("#", "")}`;
4568
+ const barH = d.value / max * (chartH - 16);
4569
+ const x = i * w + gap;
4570
+ const barY = chartH - barH;
4571
+ const rx = Math.min(3, barH * .4);
4572
+ const barPath = barH < 1 ? "" : [
4573
+ `M ${x + rx},${barY}`,
4574
+ `Q ${x},${barY} ${x},${barY + rx}`,
4575
+ `L ${x},${barY + barH}`,
4576
+ `L ${x + bw},${barY + barH}`,
4577
+ `L ${x + bw},${barY + rx}`,
4578
+ `Q ${x + bw},${barY} ${x + bw - rx},${barY}`,
4579
+ "Z"
4580
+ ].join(" ");
4581
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
4582
+ "aria-label": `${d.label}: ${d.value}`,
4583
+ role: "img",
4584
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
4585
+ d: barPath,
4586
+ fill: `url(#${gradId})`
4587
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
4588
+ x: x + bw / 2,
4589
+ y: barY - labelGap,
4590
+ textAnchor: "middle",
4591
+ fontSize: 7,
4592
+ fill: "#64748b",
4593
+ fontWeight: "600",
4594
+ fontFamily: "inherit",
4595
+ "aria-hidden": "true",
4596
+ children: d.value
4597
+ })]
4598
+ }, d.label);
4599
+ }),
4600
+ data.map((d, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
4601
+ x: i * w + w / 2,
4602
+ y: height - 4,
4603
+ textAnchor: "middle",
4604
+ fontSize: 7,
4605
+ fill: "#94a3b8",
4606
+ fontWeight: "600",
4607
+ fontFamily: "inherit",
4608
+ "aria-hidden": "true",
4609
+ children: d.label
4610
+ }, `lbl-${d.label}`))
4611
+ ]
4612
+ })
4414
4613
  });
4415
4614
  }
4416
- function LineChart({ data, height = 120, lineColor = "#6366f1", filled = true, "aria-label": ariaLabel, className = "" }) {
4615
+ function LineChart({ data, height = 120, lineColor = "#034EA2", filled = true, "aria-label": ariaLabel, className = "" }) {
4616
+ const uid = (0, react.useId)().replace(/:/g, "");
4417
4617
  const max = Math.max(...data.map((d) => d.value), 1);
4418
4618
  const n = data.length;
4419
4619
  if (n < 2) return null;
4420
- const pad = 8;
4421
- const W = 100;
4620
+ const W = 300;
4422
4621
  const H = height;
4423
- const px = (i) => pad + i / (n - 1) * 84;
4424
- const py = (v) => pad + (max - v) / max * (H - 16);
4622
+ const pad = Math.round(H * .07);
4623
+ const px = (i) => pad + i / (n - 1) * (W - pad * 2);
4624
+ const py = (v) => pad + (max - v) / max * (H - pad * 2);
4425
4625
  const points = data.map((d, i) => ({
4426
4626
  x: px(i),
4427
4627
  y: py(d.value),
@@ -4430,38 +4630,314 @@ function LineChart({ data, height = 120, lineColor = "#6366f1", filled = true, "
4430
4630
  }));
4431
4631
  const linePath = points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x},${p.y}`).join(" ");
4432
4632
  const areaPath = `${linePath} L${points[n - 1].x},${H - pad} L${points[0].x},${H - pad} Z`;
4633
+ const showDots = n <= 12;
4433
4634
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
4434
4635
  role: "img",
4435
4636
  "aria-label": ariaLabel,
4436
4637
  viewBox: `0 0 ${W} ${H}`,
4437
- preserveAspectRatio: "none",
4438
4638
  className: `w-full ${className}`,
4439
4639
  style: { height },
4440
4640
  children: [
4641
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: filled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("linearGradient", {
4642
+ id: `${uid}-lc-fill`,
4643
+ x1: "0",
4644
+ y1: "0",
4645
+ x2: "0",
4646
+ y2: "1",
4647
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("stop", {
4648
+ offset: "0%",
4649
+ stopColor: lineColor,
4650
+ stopOpacity: .2
4651
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("stop", {
4652
+ offset: "100%",
4653
+ stopColor: lineColor,
4654
+ stopOpacity: 0
4655
+ })]
4656
+ }) }),
4441
4657
  filled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
4442
4658
  d: areaPath,
4443
- fill: lineColor,
4444
- fillOpacity: .1
4659
+ fill: `url(#${uid}-lc-fill)`,
4660
+ "aria-hidden": "true"
4445
4661
  }),
4446
4662
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
4447
4663
  d: linePath,
4448
4664
  fill: "none",
4449
4665
  stroke: lineColor,
4450
- strokeWidth: "1.5",
4666
+ strokeWidth: 2,
4451
4667
  strokeLinejoin: "round",
4452
- strokeLinecap: "round"
4668
+ strokeLinecap: "round",
4669
+ "aria-hidden": "true"
4453
4670
  }),
4454
- points.map((p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
4671
+ showDots && points.map((p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
4455
4672
  cx: p.x,
4456
4673
  cy: p.y,
4457
- r: 2,
4674
+ r: 2.5,
4458
4675
  fill: lineColor,
4676
+ stroke: "white",
4677
+ strokeWidth: 1.5,
4678
+ role: "img",
4459
4679
  "aria-label": `${p.label}: ${p.value}`
4460
4680
  }, p.label))
4461
4681
  ]
4462
4682
  });
4463
4683
  }
4464
4684
  //#endregion
4685
+ //#region src/ui-library/gallery/charts/AreaChart.tsx
4686
+ /**
4687
+ * AreaChart — Design System Component
4688
+ *
4689
+ * SVG area/line chart with gradient fill, explicit Y-axis ticks, optional
4690
+ * threshold line, point annotations, highlight regions, and multi-series support.
4691
+ * No external charting library — native SVG only.
4692
+ *
4693
+ * Gradient IDs are scoped per instance via useId() to avoid SVG ID collisions
4694
+ * when multiple charts appear on the same page.
4695
+ *
4696
+ * Usage:
4697
+ * <AreaChart
4698
+ * data={monthlyData}
4699
+ * series={{ dataKey: 'value', color: '#6366f1', fillOpacity: { top: 0.22, bottom: 0.01 } }}
4700
+ * yTicks={[0, 25, 50, 75, 100]}
4701
+ * yTickFormat={(v) => `${v}%`}
4702
+ * annotations={[{ dataIndex: 5, label: 'Peak', radius: 5, color: '#ef4444' }]}
4703
+ * height={170}
4704
+ * />
4705
+ *
4706
+ * Accessibility:
4707
+ * - role="img" on the SVG with aria-label
4708
+ * - Each dot has aria-label with label and value
4709
+ * - Decorative elements are aria-hidden
4710
+ */
4711
+ function resolveOpacity(op) {
4712
+ if (op === void 0) return {
4713
+ top: .15,
4714
+ bottom: 0
4715
+ };
4716
+ if (typeof op === "number") return {
4717
+ top: op,
4718
+ bottom: op
4719
+ };
4720
+ return op;
4721
+ }
4722
+ function AreaChart({ data, series, yTicks, yTickFormat, showDots = true, threshold, annotations = [], highlightRegion, height = 170, "aria-label": ariaLabel = "Area chart", className = "" }) {
4723
+ const uid = (0, react.useId)().replace(/:/g, "");
4724
+ const seriesArr = Array.isArray(series) ? series : [series];
4725
+ const primary = seriesArr[0];
4726
+ const W = 560;
4727
+ const pl = 52;
4728
+ const pt = 14;
4729
+ const pb = 30;
4730
+ const cW = 492;
4731
+ const cH = height - pt - pb;
4732
+ const n = data.length;
4733
+ const yTicksSafe = yTicks && yTicks.length > 0 ? yTicks : void 0;
4734
+ const minY = yTicksSafe ? Math.min(...yTicksSafe) : 0;
4735
+ const maxY = yTicksSafe ? Math.max(...yTicksSafe) : Math.max(...seriesArr.flatMap((s) => data.map((d) => Number(d[s.dataKey] ?? 0))), 1);
4736
+ const cx = (i) => pl + i / Math.max(n - 1, 1) * cW;
4737
+ const cy = (v) => pt + (1 - (v - minY) / (maxY - minY)) * cH;
4738
+ const paths = seriesArr.map((s) => {
4739
+ const vals = data.map((d) => Number(d[s.dataKey] ?? 0));
4740
+ const line = "M" + vals.map((v, i) => `${cx(i)},${cy(v)}`).join("L");
4741
+ return {
4742
+ line,
4743
+ area: `${line}L${cx(n - 1)},${height - pb}L${cx(0)},${height - pb}Z`,
4744
+ vals
4745
+ };
4746
+ });
4747
+ const annotatedIdx = new Set(annotations.map((a) => a.dataIndex));
4748
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
4749
+ role: "img",
4750
+ "aria-label": ariaLabel,
4751
+ viewBox: `0 0 ${W} ${height}`,
4752
+ className: `w-full ${className}`,
4753
+ style: { height },
4754
+ children: [
4755
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: seriesArr.map((s, si) => {
4756
+ const op = resolveOpacity(s.fillOpacity);
4757
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("linearGradient", {
4758
+ id: `${uid}-g${si}`,
4759
+ x1: "0",
4760
+ y1: "0",
4761
+ x2: "0",
4762
+ y2: "1",
4763
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("stop", {
4764
+ offset: "0%",
4765
+ stopColor: s.color,
4766
+ stopOpacity: op.top
4767
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("stop", {
4768
+ offset: "100%",
4769
+ stopColor: s.color,
4770
+ stopOpacity: op.bottom
4771
+ })]
4772
+ }, si);
4773
+ }) }),
4774
+ highlightRegion && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
4775
+ "aria-hidden": "true",
4776
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
4777
+ x: cx(highlightRegion.startIndex),
4778
+ y: pt,
4779
+ width: cx(highlightRegion.endIndex) - cx(highlightRegion.startIndex),
4780
+ height: cH,
4781
+ fill: highlightRegion.color ?? "#eef0ff",
4782
+ rx: 3,
4783
+ opacity: .7
4784
+ }), highlightRegion.label && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
4785
+ x: (cx(highlightRegion.startIndex) + cx(highlightRegion.endIndex)) / 2,
4786
+ y: 23,
4787
+ textAnchor: "middle",
4788
+ fontSize: 7.5,
4789
+ fill: "#a5b4fc",
4790
+ children: highlightRegion.label
4791
+ })]
4792
+ }),
4793
+ yTicks?.map((v) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
4794
+ "aria-hidden": "true",
4795
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
4796
+ x1: pl,
4797
+ y1: cy(v),
4798
+ x2: 544,
4799
+ y2: cy(v),
4800
+ stroke: "#f1f5f9",
4801
+ strokeWidth: 1
4802
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
4803
+ x: 46,
4804
+ y: cy(v) + 4,
4805
+ textAnchor: "end",
4806
+ fontSize: 9,
4807
+ fill: "#94a3b8",
4808
+ children: yTickFormat ? yTickFormat(v) : String(v)
4809
+ })]
4810
+ }, v)),
4811
+ threshold && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
4812
+ x1: pl,
4813
+ y1: cy(threshold.value),
4814
+ x2: 544,
4815
+ y2: cy(threshold.value),
4816
+ stroke: threshold.color ?? "#f59e0b",
4817
+ strokeWidth: 1,
4818
+ strokeDasharray: threshold.strokeStyle === "solid" ? void 0 : "4,2",
4819
+ "aria-hidden": "true"
4820
+ }),
4821
+ seriesArr.map((s, si) => {
4822
+ const op = resolveOpacity(s.fillOpacity);
4823
+ if (op.top === 0 && op.bottom === 0) return null;
4824
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
4825
+ d: paths[si].area,
4826
+ fill: `url(#${uid}-g${si})`,
4827
+ "aria-hidden": "true"
4828
+ }, `area-${si}`);
4829
+ }),
4830
+ seriesArr.map((s, si) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
4831
+ d: paths[si].line,
4832
+ fill: "none",
4833
+ stroke: s.color,
4834
+ strokeWidth: si === 0 ? 2.5 : 1.5,
4835
+ strokeLinecap: "round",
4836
+ strokeLinejoin: "round",
4837
+ strokeDasharray: s.strokeStyle === "dashed" ? "4,2" : void 0,
4838
+ "aria-hidden": "true"
4839
+ }, `line-${si}`)),
4840
+ showDots && paths[0].vals.map((v, i) => {
4841
+ if (annotatedIdx.has(i)) return null;
4842
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
4843
+ cx: cx(i),
4844
+ cy: cy(v),
4845
+ r: 3.5,
4846
+ fill: primary.color,
4847
+ stroke: "white",
4848
+ strokeWidth: 2,
4849
+ "aria-label": `${data[i].label}: ${v}`
4850
+ }, `dot-${i}`);
4851
+ }),
4852
+ data.map((d, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
4853
+ x: cx(i),
4854
+ y: height - 4,
4855
+ textAnchor: "middle",
4856
+ fontSize: 9,
4857
+ fill: "#94a3b8",
4858
+ "aria-hidden": "true",
4859
+ children: d.label
4860
+ }, `x-${i}`)),
4861
+ annotations.map((ann) => {
4862
+ const v = Number(data[ann.dataIndex]?.[primary.dataKey] ?? 0);
4863
+ const x = cx(ann.dataIndex);
4864
+ const y = cy(v);
4865
+ const r = ann.radius ?? 4;
4866
+ const col = ann.color ?? primary.color;
4867
+ const ly = ann.labelPosition === "below" ? y + r + 10 : Math.max(22, y - r - 5);
4868
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
4869
+ "aria-label": `${data[ann.dataIndex].label}: ${ann.label}`,
4870
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
4871
+ cx: x,
4872
+ cy: y,
4873
+ r,
4874
+ fill: col,
4875
+ stroke: "white",
4876
+ strokeWidth: 2
4877
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
4878
+ x,
4879
+ y: ly,
4880
+ textAnchor: "middle",
4881
+ fontSize: 8,
4882
+ fill: col,
4883
+ fontWeight: "bold",
4884
+ children: ann.label
4885
+ })]
4886
+ }, `ann-${ann.dataIndex}`);
4887
+ })
4888
+ ]
4889
+ });
4890
+ }
4891
+ //#endregion
4892
+ //#region src/ui-library/gallery/charts/BarList.tsx
4893
+ function BarList({ items, valueFormat, totalLabel, barHeight = "h-2", staggerDelay = 70, className = "" }) {
4894
+ const maxValue = Math.max(...items.map((item) => item.value), 1);
4895
+ const total = items.reduce((sum, item) => sum + item.value, 0);
4896
+ const fmt = valueFormat ?? ((v) => String(v));
4897
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4898
+ role: "list",
4899
+ "aria-label": "Bar list",
4900
+ className: `space-y-3 pt-1 ${className}`,
4901
+ children: [items.map((item, i) => {
4902
+ const pct = item.value / maxValue * 100;
4903
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4904
+ role: "listitem",
4905
+ "aria-label": `${item.label}: ${fmt(item.value)}`,
4906
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4907
+ className: "flex justify-between items-baseline mb-1",
4908
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4909
+ className: "text-xs font-bold text-slate-700",
4910
+ children: item.label
4911
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4912
+ className: "text-xs text-slate-400 font-medium",
4913
+ children: fmt(item.value)
4914
+ })]
4915
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4916
+ className: `${barHeight} w-full bg-slate-100/60 rounded-full overflow-hidden`,
4917
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4918
+ className: `${barHeight} rounded-full os-bar-in`,
4919
+ style: {
4920
+ width: `${pct}%`,
4921
+ backgroundColor: item.color,
4922
+ animationDelay: `${i * staggerDelay}ms`
4923
+ },
4924
+ "aria-hidden": "true"
4925
+ })
4926
+ })]
4927
+ }, item.label);
4928
+ }), totalLabel !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4929
+ className: "pt-2 border-t border-slate-50 flex justify-between items-center",
4930
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4931
+ className: "text-[10px] font-bold text-slate-400 uppercase tracking-widest",
4932
+ children: totalLabel
4933
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4934
+ className: "text-sm font-bold text-slate-700",
4935
+ children: total
4936
+ })]
4937
+ })]
4938
+ });
4939
+ }
4940
+ //#endregion
4465
4941
  //#region src/ui-library/gallery/heatmap/Heatmap.tsx
4466
4942
  /**
4467
4943
  * Heatmap — Design System Component
@@ -4480,31 +4956,31 @@ function LineChart({ data, height = 120, lineColor = "#6366f1", filled = true, "
4480
4956
  var SCALES = {
4481
4957
  blue: { cells: [
4482
4958
  "bg-slate-100",
4483
- "bg-brand-sky/20",
4484
- "bg-brand-sky/40",
4485
- "bg-brand-sky/70",
4486
- "bg-brand-sky"
4959
+ "bg-sky-200",
4960
+ "bg-sky-400",
4961
+ "bg-blue-600",
4962
+ "bg-[#00377B]"
4487
4963
  ] },
4488
4964
  navy: { cells: [
4489
4965
  "bg-slate-100",
4490
- "bg-brand-navy/15",
4491
- "bg-brand-navy/35",
4492
- "bg-brand-navy/65",
4493
- "bg-brand-navy"
4966
+ "bg-slate-300",
4967
+ "bg-slate-500",
4968
+ "bg-slate-700",
4969
+ "bg-slate-900"
4494
4970
  ] },
4495
4971
  teal: { cells: [
4496
4972
  "bg-slate-100",
4497
- "bg-cyan-100",
4498
- "bg-cyan-300",
4499
- "bg-cyan-500",
4500
- "bg-cyan-700"
4973
+ "bg-cyan-200",
4974
+ "bg-cyan-400",
4975
+ "bg-cyan-600",
4976
+ "bg-cyan-800"
4501
4977
  ] },
4502
4978
  orange: { cells: [
4503
4979
  "bg-slate-100",
4504
- "bg-orange-100",
4505
- "bg-orange-300",
4980
+ "bg-orange-200",
4506
4981
  "bg-orange-400",
4507
- "bg-orange-600"
4982
+ "bg-orange-500",
4983
+ "bg-orange-700"
4508
4984
  ] }
4509
4985
  };
4510
4986
  var MONTHS = [
@@ -4645,6 +5121,2250 @@ function Heatmap({ data, scale = "blue", showLegend = true, showMonthLabels = tr
4645
5121
  });
4646
5122
  }
4647
5123
  //#endregion
5124
+ //#region src/ui-library/gallery/org-chart/OrgChart.tsx
5125
+ /**
5126
+ * OrgChart — Design System Component
5127
+ *
5128
+ * A D3-powered SVG organization chart matching the UHRIS Company Structure
5129
+ * diagram mode. Renders a top-down tree with rectangular nodes and
5130
+ * stepped orthogonal connectors.
5131
+ *
5132
+ * Technology: D3 v7 (d3.hierarchy + d3.tree layout + d3.zoom)
5133
+ * Already a production dependency — no new packages introduced.
5134
+ *
5135
+ * Visual design (sourced from CompanyStructurePage diagram mode):
5136
+ * Nodes:
5137
+ * - 250 × 84 px rounded rectangles (rx=14)
5138
+ * - Root (depth 0): dark navy fill (#0f172a), white text
5139
+ * - Children: white fill (#fff), slate border (#e2e8f0)
5140
+ * - drop-shadow: 0 6px 12px rgba(15,23,42,0.08)
5141
+ * - Name: 13px, font-weight 800, centered
5142
+ * - Description: 11px, font-weight 600, #64748b / #cbd5e1 (root)
5143
+ * - Selected: indigo border overlay ring
5144
+ * Connectors:
5145
+ * - Stepped orthogonal path: M→V→H→V
5146
+ * - Stroke: #cbd5e1, stroke-width 1.5
5147
+ * Canvas:
5148
+ * - Viewport sized to container; fit-to-view on render
5149
+ * - Zoom: scaleExtent [0.05, 1.8]
5150
+ * - Pan: mouse/touch drag
5151
+ * - Layout: nodeSize [280, 185] — horizontal × vertical spacing
5152
+ * Controls:
5153
+ * - ZoomIn, Reset, ZoomOut buttons (top-right overlay panel)
5154
+ *
5155
+ * Accessibility:
5156
+ * - SVG has role="img" + aria-label
5157
+ * - Zoom controls have aria-label
5158
+ * - Keyboard: Tab to control buttons; diagram itself is navigated visually
5159
+ * - Note: full ARIA tree semantics are not possible in an SVG diagram;
5160
+ * use OrgUnitTree for a fully keyboard-accessible list-based alternative
5161
+ *
5162
+ * Usage:
5163
+ * <OrgChart
5164
+ * nodes={orgNodes}
5165
+ * selectedId={selectedId}
5166
+ * onSelect={setSelectedId}
5167
+ * aria-label="Company organization chart"
5168
+ * />
5169
+ */
5170
+ function buildD3Tree(nodes) {
5171
+ function convert(node, depth) {
5172
+ return {
5173
+ id: node.id,
5174
+ name: node.label,
5175
+ description: node.description ?? "",
5176
+ isRoot: depth === 0,
5177
+ isSyntheticRoot: false,
5178
+ originalId: node.id,
5179
+ children: node.children?.map((c) => convert(c, depth + 1))
5180
+ };
5181
+ }
5182
+ if (nodes.length === 1) return convert(nodes[0], 0);
5183
+ return {
5184
+ id: "__synthetic_root__",
5185
+ name: "",
5186
+ description: "",
5187
+ isRoot: true,
5188
+ isSyntheticRoot: true,
5189
+ originalId: "__synthetic_root__",
5190
+ children: nodes.map((n) => convert(n, 0))
5191
+ };
5192
+ }
5193
+ function OrgChart({ nodes, selectedId, onSelect, height = "75vh", "aria-label": ariaLabel = "Organization chart", className = "" }) {
5194
+ const svgRef = (0, react.useRef)(null);
5195
+ const zoomRef = (0, react.useRef)(null);
5196
+ const initialTransformRef = (0, react.useRef)(null);
5197
+ const treeBoundsRef = (0, react.useRef)(null);
5198
+ const uid = (0, react.useId)().replace(/:/g, "");
5199
+ const fitToView = () => {
5200
+ if (!svgRef.current || !zoomRef.current || !treeBoundsRef.current) return;
5201
+ const { width: W, height: H } = svgRef.current.getBoundingClientRect();
5202
+ if (W === 0 || H === 0) return;
5203
+ const { minX, maxX, minY, maxY } = treeBoundsRef.current;
5204
+ const contentLeft = minX - 125;
5205
+ const contentRight = maxX + 125;
5206
+ const contentTop = minY - 42;
5207
+ const contentBottom = maxY + 42;
5208
+ const contentWidth = contentRight - contentLeft;
5209
+ const contentHeight = contentBottom - contentTop;
5210
+ const scaleX = (W - 80) / Math.max(1, contentWidth);
5211
+ const scaleY = (H - 80) / Math.max(1, contentHeight);
5212
+ const scale = Math.max(.05, Math.min(1.8, scaleX, scaleY));
5213
+ const contentCenterX = (contentLeft + contentRight) / 2;
5214
+ const contentCenterY = (contentTop + contentBottom) / 2;
5215
+ const tx = W / 2 - contentCenterX * scale;
5216
+ const ty = H / 2 - contentCenterY * scale;
5217
+ const t = d3.zoomIdentity.translate(tx, ty).scale(scale);
5218
+ initialTransformRef.current = t;
5219
+ d3.select(svgRef.current).call(zoomRef.current.transform, t);
5220
+ };
5221
+ (0, react.useEffect)(() => {
5222
+ if (!svgRef.current || nodes.length === 0) return;
5223
+ const svg = d3.select(svgRef.current);
5224
+ svg.selectAll("*").remove();
5225
+ const treeData = buildD3Tree(nodes);
5226
+ const root = d3.hierarchy(treeData);
5227
+ d3.tree().nodeSize([280, 185])(root);
5228
+ const descendants = root.descendants();
5229
+ treeBoundsRef.current = {
5230
+ minX: d3.min(descendants, (d) => d.x) ?? 0,
5231
+ maxX: d3.max(descendants, (d) => d.x) ?? 0,
5232
+ minY: d3.min(descendants, (d) => d.y) ?? 0,
5233
+ maxY: d3.max(descendants, (d) => d.y) ?? 0
5234
+ };
5235
+ const g = svg.append("g");
5236
+ const zoom = d3.zoom().scaleExtent([.05, 1.8]).on("zoom", (e) => g.attr("transform", e.transform.toString()));
5237
+ zoomRef.current = zoom;
5238
+ svg.call(zoom);
5239
+ g.selectAll("path").data(root.links().filter((l) => !l.source.data.isSyntheticRoot)).join("path").attr("fill", "none").attr("stroke", "#cbd5e1").attr("stroke-width", 1.5).attr("d", (link) => {
5240
+ const sx = link.source.x ?? 0;
5241
+ const sy = link.source.y ?? 0;
5242
+ const tx = link.target.x ?? 0;
5243
+ const ty = link.target.y ?? 0;
5244
+ return `M${sx},${sy}V${(sy + ty) / 2}H${tx}V${ty}`;
5245
+ });
5246
+ const node = g.selectAll("g.node").data(root.descendants().filter((d) => !d.data.isSyntheticRoot)).join("g").attr("class", "node").attr("transform", (d) => `translate(${d.x},${d.y})`).style("cursor", (d) => d.data.originalId !== "__synthetic_root__" ? "pointer" : "default").on("click", (_e, d) => {
5247
+ if (d.data.isSyntheticRoot) return;
5248
+ onSelect?.(d.data.originalId);
5249
+ });
5250
+ node.append("rect").attr("x", -125).attr("y", -42).attr("width", 250).attr("height", 84).attr("rx", 14).attr("fill", (d) => d.data.isRoot ? "#0f172a" : "#fff").attr("stroke", (d) => {
5251
+ if (selectedId && d.data.originalId === selectedId) return "#6366f1";
5252
+ return d.data.isRoot ? "#0f172a" : "#e2e8f0";
5253
+ }).attr("stroke-width", (d) => selectedId && d.data.originalId === selectedId ? 2.5 : 1).attr("filter", "drop-shadow(0 6px 12px rgba(15,23,42,0.08))");
5254
+ node.append("text").attr("text-anchor", "middle").attr("y", -8).attr("font-size", 13).attr("font-weight", 800).attr("fill", (d) => d.data.isRoot ? "#fff" : "#0f172a").text((d) => d.data.name);
5255
+ node.append("text").attr("text-anchor", "middle").attr("y", 16).attr("font-size", 11).attr("font-weight", 600).attr("fill", (d) => d.data.isRoot ? "#cbd5e1" : "#64748b").text((d) => d.data.description);
5256
+ if (selectedId) node.filter((d) => d.data.originalId === selectedId).append("rect").attr("x", -128).attr("y", -45).attr("width", 256).attr("height", 90).attr("rx", 16).attr("fill", "none").attr("stroke", "#6366f1").attr("stroke-width", 2.5).attr("opacity", .6);
5257
+ requestAnimationFrame(() => {
5258
+ fitToView();
5259
+ });
5260
+ }, [
5261
+ nodes,
5262
+ selectedId,
5263
+ onSelect
5264
+ ]);
5265
+ (0, react.useEffect)(() => {
5266
+ const el = svgRef.current;
5267
+ if (!el) return;
5268
+ const ro = new ResizeObserver(() => {
5269
+ fitToView();
5270
+ });
5271
+ ro.observe(el);
5272
+ return () => ro.disconnect();
5273
+ }, []);
5274
+ const zoomBy = (factor) => {
5275
+ if (!svgRef.current || !zoomRef.current) return;
5276
+ d3.select(svgRef.current).transition().duration(250).call(zoomRef.current.scaleBy, factor);
5277
+ };
5278
+ const resetZoom = () => {
5279
+ fitToView();
5280
+ };
5281
+ const controlBtnClass = [
5282
+ "appearance-none border-0 bg-none font-[inherit]",
5283
+ "flex items-center justify-center rounded-lg p-2",
5284
+ "text-slate-400 transition hover:bg-slate-100 hover:text-slate-700",
5285
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30"
5286
+ ].join(" ");
5287
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5288
+ className: `relative w-full overflow-hidden bg-slate-50/50 ${className}`,
5289
+ style: { height },
5290
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5291
+ className: "absolute right-4 top-4 z-10 flex flex-col gap-2 rounded-lg border border-slate-100 bg-white p-2 shadow-md",
5292
+ children: [
5293
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5294
+ type: "button",
5295
+ className: controlBtnClass,
5296
+ onClick: () => zoomBy(1.2),
5297
+ "aria-label": "Zoom in",
5298
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ZoomIn, {
5299
+ size: 16,
5300
+ "aria-hidden": "true"
5301
+ })
5302
+ }),
5303
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5304
+ type: "button",
5305
+ className: controlBtnClass,
5306
+ onClick: resetZoom,
5307
+ "aria-label": "Reset zoom",
5308
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.RotateCcw, {
5309
+ size: 16,
5310
+ "aria-hidden": "true"
5311
+ })
5312
+ }),
5313
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5314
+ type: "button",
5315
+ className: controlBtnClass,
5316
+ onClick: () => zoomBy(.8),
5317
+ "aria-label": "Zoom out",
5318
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ZoomOut, {
5319
+ size: 16,
5320
+ "aria-hidden": "true"
5321
+ })
5322
+ })
5323
+ ]
5324
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
5325
+ ref: svgRef,
5326
+ id: uid,
5327
+ width: "100%",
5328
+ height: "100%",
5329
+ className: "block touch-none",
5330
+ role: "img",
5331
+ "aria-label": ariaLabel
5332
+ })]
5333
+ });
5334
+ }
5335
+ //#endregion
5336
+ //#region src/ui-library/gallery/org-unit-tree/OrgUnitTree.tsx
5337
+ /**
5338
+ * OrgUnitTree — Design System Component
5339
+ *
5340
+ * A card-based hierarchical organization tree matching the UHRIS
5341
+ * Company Structure list-mode visual design. Purely presentational —
5342
+ * no API calls, no domain logic, no permissions.
5343
+ *
5344
+ * Visual design (sourced from CompanyStructurePage StructureDesigner):
5345
+ * - Root node: dark navy (bg-slate-900) card with light text
5346
+ * - Child nodes: white bordered cards with blue hover accent
5347
+ * - Connector: left border (border-l border-slate-200) + indentation
5348
+ * - Icon badge: rounded-xl colored square containing the icon
5349
+ * - Actions: hover-reveal slot (opacity-0 → group-hover:opacity-100)
5350
+ * - Meta: right-aligned, hidden on narrow screens
5351
+ *
5352
+ * Accessibility (WAI-ARIA Tree pattern, RFC 1.2):
5353
+ * - role="tree" on root list
5354
+ * - role="treeitem" + aria-expanded + aria-selected + aria-level + aria-disabled
5355
+ * - role="group" on nested lists
5356
+ * - Keyboard: ArrowDown/Up/Left/Right/Home/End/Enter/Space
5357
+ * - Roving tabIndex: only focused item has tabIndex=0
5358
+ *
5359
+ * Usage:
5360
+ * <OrgUnitTree
5361
+ * nodes={orgNodes}
5362
+ * onSelect={(id) => navigate(`/org/${id}`)}
5363
+ * aria-label="Company structure"
5364
+ * />
5365
+ */
5366
+ function flattenVisible(nodes, expanded) {
5367
+ const result = [];
5368
+ for (const node of nodes) {
5369
+ result.push(node);
5370
+ if (node.children?.length && expanded.has(node.id)) result.push(...flattenVisible(node.children, expanded));
5371
+ }
5372
+ return result;
5373
+ }
5374
+ function findParentId(nodes, targetId) {
5375
+ for (const node of nodes) {
5376
+ if (node.children?.some((c) => c.id === targetId)) return node.id;
5377
+ if (node.children) {
5378
+ const found = findParentId(node.children, targetId);
5379
+ if (found !== null) return found;
5380
+ }
5381
+ }
5382
+ return null;
5383
+ }
5384
+ function OrgUnitTree({ nodes, selectedId, onSelect, defaultExpandedIds, expandedIds: controlledExpandedIds, onExpandedChange, "aria-label": ariaLabel, className = "" }) {
5385
+ const baseId = (0, react.useId)().replace(/:/g, "");
5386
+ const treeRef = (0, react.useRef)(null);
5387
+ const [internalExpanded, setInternalExpanded] = (0, react.useState)(() => {
5388
+ if (defaultExpandedIds) return new Set(defaultExpandedIds);
5389
+ return new Set(nodes.map((n) => n.id));
5390
+ });
5391
+ const expanded = controlledExpandedIds ? new Set(controlledExpandedIds) : internalExpanded;
5392
+ const setExpanded = (0, react.useCallback)((next) => {
5393
+ if (!controlledExpandedIds) setInternalExpanded(next);
5394
+ onExpandedChange?.(Array.from(next));
5395
+ }, [controlledExpandedIds, onExpandedChange]);
5396
+ const [focusedId, setFocusedId] = (0, react.useState)(() => {
5397
+ return flattenVisible(nodes, new Set(nodes.map((n) => n.id))).find((n) => !n.disabled)?.id ?? null;
5398
+ });
5399
+ const toggleExpand = (0, react.useCallback)((id) => {
5400
+ const next = new Set(expanded);
5401
+ if (next.has(id)) next.delete(id);
5402
+ else next.add(id);
5403
+ setExpanded(next);
5404
+ }, [expanded, setExpanded]);
5405
+ const handleSelect = (0, react.useCallback)((id) => {
5406
+ setFocusedId(id);
5407
+ onSelect?.(id);
5408
+ }, [onSelect]);
5409
+ const handleKeyDown = (e) => {
5410
+ const visible = flattenVisible(nodes, expanded).filter((n) => !n.disabled);
5411
+ if (visible.length === 0) return;
5412
+ const focusEl = (id) => {
5413
+ setFocusedId(id);
5414
+ document.getElementById(`${baseId}-${id}`)?.focus();
5415
+ };
5416
+ const currentIdx = focusedId ? visible.findIndex((n) => n.id === focusedId) : -1;
5417
+ const current = focusedId ? visible.find((n) => n.id === focusedId) : null;
5418
+ switch (e.key) {
5419
+ case "ArrowDown": {
5420
+ e.preventDefault();
5421
+ const next = visible[currentIdx + 1];
5422
+ if (next) focusEl(next.id);
5423
+ break;
5424
+ }
5425
+ case "ArrowUp": {
5426
+ e.preventDefault();
5427
+ const prev = visible[currentIdx - 1];
5428
+ if (prev) focusEl(prev.id);
5429
+ break;
5430
+ }
5431
+ case "ArrowRight":
5432
+ e.preventDefault();
5433
+ if (!current) break;
5434
+ if (current.children?.length && !expanded.has(current.id)) {
5435
+ const next = new Set(expanded);
5436
+ next.add(current.id);
5437
+ setExpanded(next);
5438
+ } else if (current.children?.length && expanded.has(current.id)) {
5439
+ const firstChild = visible.find((n, i) => i > currentIdx && n.id === current.children[0]?.id);
5440
+ if (firstChild) focusEl(firstChild.id);
5441
+ }
5442
+ break;
5443
+ case "ArrowLeft":
5444
+ e.preventDefault();
5445
+ if (!current) break;
5446
+ if (current.children?.length && expanded.has(current.id)) {
5447
+ const next = new Set(expanded);
5448
+ next.delete(current.id);
5449
+ setExpanded(next);
5450
+ } else {
5451
+ const parentId = findParentId(nodes, current.id);
5452
+ if (parentId) focusEl(parentId);
5453
+ }
5454
+ break;
5455
+ case "Home":
5456
+ e.preventDefault();
5457
+ if (visible[0]) focusEl(visible[0].id);
5458
+ break;
5459
+ case "End": {
5460
+ e.preventDefault();
5461
+ const last = visible[visible.length - 1];
5462
+ if (last) focusEl(last.id);
5463
+ break;
5464
+ }
5465
+ case "Enter":
5466
+ case " ":
5467
+ e.preventDefault();
5468
+ if (current) {
5469
+ handleSelect(current.id);
5470
+ if (current.children?.length) toggleExpand(current.id);
5471
+ }
5472
+ }
5473
+ };
5474
+ const nodeRefs = (0, react.useRef)(/* @__PURE__ */ new Map());
5475
+ function renderNodes(branch, depth) {
5476
+ return branch.map((node) => {
5477
+ const isExpanded = expanded.has(node.id);
5478
+ const isRoot = depth === 1;
5479
+ const hasChildren = Boolean(node.children?.length);
5480
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
5481
+ ref: (el) => {
5482
+ if (el) nodeRefs.current.set(node.id, el);
5483
+ else nodeRefs.current.delete(node.id);
5484
+ },
5485
+ id: `${baseId}-${node.id}`,
5486
+ role: "treeitem",
5487
+ "aria-expanded": hasChildren ? isExpanded : void 0,
5488
+ "aria-selected": selectedId === node.id,
5489
+ "aria-disabled": node.disabled || void 0,
5490
+ "aria-level": depth,
5491
+ tabIndex: focusedId === node.id ? 0 : -1,
5492
+ onFocus: () => setFocusedId(node.id),
5493
+ className: "outline-none",
5494
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5495
+ className: ["group mb-2 flex items-center gap-3 rounded-xl border px-3 py-3 transition select-none", isRoot ? "border-slate-900 bg-slate-900 text-slate-300 shadow-md" : selectedId === node.id ? "border-brand-blue/40 bg-blue-50 shadow-sm" : node.disabled ? "border-slate-100 bg-slate-50 opacity-50 cursor-not-allowed" : "border-slate-200 bg-white hover:border-blue-300 hover:shadow-sm cursor-pointer"].filter(Boolean).join(" "),
5496
+ onClick: () => {
5497
+ if (node.disabled) return;
5498
+ if (hasChildren) toggleExpand(node.id);
5499
+ handleSelect(node.id);
5500
+ },
5501
+ children: [
5502
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5503
+ type: "button",
5504
+ "aria-label": isExpanded ? `Collapse ${node.label}` : `Expand ${node.label}`,
5505
+ tabIndex: -1,
5506
+ disabled: !hasChildren,
5507
+ onClick: (e) => {
5508
+ e.stopPropagation();
5509
+ if (hasChildren) toggleExpand(node.id);
5510
+ },
5511
+ className: [
5512
+ "flex items-center justify-center rounded p-1 shrink-0 transition",
5513
+ !hasChildren && "invisible",
5514
+ isRoot ? "hover:bg-slate-700" : "hover:bg-slate-100"
5515
+ ].filter(Boolean).join(" "),
5516
+ children: isExpanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronDown, {
5517
+ size: 16,
5518
+ "aria-hidden": "true"
5519
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, {
5520
+ size: 16,
5521
+ "aria-hidden": "true"
5522
+ })
5523
+ }),
5524
+ node.icon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5525
+ className: isRoot ? "flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-slate-800 text-slate-200" : "flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-blue-50 text-blue-600",
5526
+ "aria-hidden": "true",
5527
+ children: node.icon
5528
+ }),
5529
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5530
+ className: "min-w-0 flex-1",
5531
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5532
+ className: ["flex flex-wrap items-center gap-2 text-sm font-bold", isRoot ? "text-white" : selectedId === node.id ? "text-brand-blue" : "text-slate-900"].filter(Boolean).join(" "),
5533
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5534
+ className: "truncate",
5535
+ children: node.label
5536
+ }), node.badge && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: node.badge })]
5537
+ }), node.description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5538
+ className: `mt-0.5 truncate text-xs font-medium ${isRoot ? "text-slate-400" : "text-slate-500"}`,
5539
+ children: node.description
5540
+ })]
5541
+ }),
5542
+ node.meta && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5543
+ className: `hidden md:flex items-center gap-3 text-xs ${isRoot ? "text-slate-300" : "text-slate-500"}`,
5544
+ children: node.meta
5545
+ }),
5546
+ node.actions && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5547
+ className: "flex items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100",
5548
+ onClick: (e) => e.stopPropagation(),
5549
+ children: node.actions
5550
+ })
5551
+ ]
5552
+ }), hasChildren && isExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
5553
+ role: "group",
5554
+ className: "ml-6 border-l border-slate-200 pl-4",
5555
+ children: renderNodes(node.children, depth + 1)
5556
+ })]
5557
+ }, node.id);
5558
+ });
5559
+ }
5560
+ if (nodes.length === 0) return null;
5561
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
5562
+ ref: treeRef,
5563
+ role: "tree",
5564
+ "aria-label": ariaLabel,
5565
+ onKeyDown: handleKeyDown,
5566
+ className: `w-full outline-none ${className}`,
5567
+ children: renderNodes(nodes, 1)
5568
+ });
5569
+ }
5570
+ //#endregion
5571
+ //#region src/ui-library/gallery/template-samples/templates/PafTemplate.tsx
5572
+ var fmt = new Intl.DateTimeFormat("en-US", {
5573
+ month: "short",
5574
+ day: "2-digit",
5575
+ year: "numeric"
5576
+ });
5577
+ var fmtDate = (v) => {
5578
+ if (!v?.trim()) return "";
5579
+ const n = /^\d{4}-\d{2}-\d{2}$/.test(v.trim()) ? `${v.trim()}T00:00:00` : v.trim();
5580
+ const d = new Date(n);
5581
+ return isNaN(d.getTime()) ? v : fmt.format(d);
5582
+ };
5583
+ var STANDARD_LABELS = [
5584
+ "Basic Salary",
5585
+ "Cola",
5586
+ "Trasa",
5587
+ "Trarep",
5588
+ "Communication",
5589
+ "Car",
5590
+ "Motor",
5591
+ "Others"
5592
+ ];
5593
+ function PafTemplate({ data }) {
5594
+ const allComponents = STANDARD_LABELS.map((label) => {
5595
+ const found = data.salaryComponents?.find((c) => c.label.toLowerCase() === label.toLowerCase());
5596
+ if (found) return found;
5597
+ if (label === "Basic Salary") return {
5598
+ label,
5599
+ from: data.from.basicSalary,
5600
+ to: data.to.basicSalary
5601
+ };
5602
+ return {
5603
+ label,
5604
+ from: "",
5605
+ to: ""
5606
+ };
5607
+ });
5608
+ const shownComponents = allComponents.filter((c) => {
5609
+ if (c.label === "Basic Salary") return true;
5610
+ const hasFrom = c.from && parseFloat(c.from.replace(/,/g, "")) !== 0;
5611
+ const hasTo = c.to && parseFloat(c.to.replace(/,/g, "")) !== 0;
5612
+ return hasFrom || hasTo;
5613
+ });
5614
+ const paddingRows = Array.from({ length: Math.max(0, 7 - shownComponents.length) });
5615
+ const calcTotal = (type) => {
5616
+ const t = allComponents.reduce((acc, c) => {
5617
+ const v = parseFloat((type === "from" ? c.from : c.to).replace(/,/g, ""));
5618
+ return acc + (isNaN(v) ? 0 : v);
5619
+ }, 0);
5620
+ return t === 0 ? "" : t.toLocaleString("en-US", {
5621
+ minimumFractionDigits: 2,
5622
+ maximumFractionDigits: 2
5623
+ });
5624
+ };
5625
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5626
+ className: "bg-white text-black font-sans",
5627
+ style: {
5628
+ width: "816px",
5629
+ minHeight: "1056px",
5630
+ padding: "60px 50px",
5631
+ boxSizing: "border-box"
5632
+ },
5633
+ children: [
5634
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
5635
+ className: "text-center italic font-bold text-2xl tracking-widest mb-8 uppercase",
5636
+ children: "Personnel Action Form"
5637
+ }),
5638
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5639
+ className: "mb-6",
5640
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
5641
+ className: "text-sm font-bold italic border-b border-black mb-2 uppercase tracking-tight",
5642
+ children: "Employee Data"
5643
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5644
+ className: "grid grid-cols-12 gap-x-4",
5645
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5646
+ className: "col-span-8 space-y-2",
5647
+ children: [{
5648
+ label: "Employee ID:",
5649
+ value: data.employee.idNo
5650
+ }, {
5651
+ label: "Employee Name:",
5652
+ value: data.employee.name.toUpperCase()
5653
+ }].map((r, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5654
+ className: "flex items-center",
5655
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5656
+ className: "w-32 text-[11px] font-bold italic",
5657
+ children: r.label
5658
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5659
+ className: "flex-1 border border-black px-2 py-0.5 text-[12px] min-h-[24px] font-semibold",
5660
+ children: r.value
5661
+ })]
5662
+ }, i))
5663
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5664
+ className: "col-span-4 space-y-2",
5665
+ children: [{
5666
+ label: "Date Hired:",
5667
+ value: fmtDate(data.employee.dateHired) || "Jan 01, 2024"
5668
+ }, {
5669
+ label: "Date Prepared:",
5670
+ value: fmtDate(data.date)
5671
+ }].map((r, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5672
+ className: "flex items-center",
5673
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5674
+ className: "w-24 text-[11px] font-bold italic",
5675
+ children: r.label
5676
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5677
+ className: "flex-1 border border-black px-2 py-0.5 text-[12px] min-h-[24px] text-center",
5678
+ children: r.value
5679
+ })]
5680
+ }, i))
5681
+ })]
5682
+ })]
5683
+ }),
5684
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5685
+ className: "mb-6",
5686
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
5687
+ className: "text-sm font-bold italic border-b border-black mb-2 uppercase tracking-tight",
5688
+ children: "Position/Salary Change Details"
5689
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
5690
+ className: "w-full border-collapse",
5691
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
5692
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
5693
+ className: "w-[124px]",
5694
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5695
+ className: "sr-only",
5696
+ children: "Field"
5697
+ })
5698
+ }),
5699
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
5700
+ className: "text-[12px] italic font-bold text-center pb-1",
5701
+ children: "FROM"
5702
+ }),
5703
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
5704
+ className: "text-[12px] italic font-bold text-center pb-1",
5705
+ children: "TO"
5706
+ })
5707
+ ] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tbody", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
5708
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5709
+ className: "text-[10px] italic font-bold py-1",
5710
+ children: "Pay Template"
5711
+ }),
5712
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5713
+ className: "border border-black p-1 text-[11px] font-bold w-[300px]",
5714
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5715
+ className: "px-1 min-h-[16px]",
5716
+ children: data.fromTemplate || "—"
5717
+ })
5718
+ }),
5719
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5720
+ className: "border border-black p-1 text-[11px] font-bold w-[300px]",
5721
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5722
+ className: "px-1 min-h-[16px]",
5723
+ children: data.toTemplate || "—"
5724
+ })
5725
+ })
5726
+ ] }), [
5727
+ {
5728
+ label: "Rank",
5729
+ from: data.from.rank,
5730
+ to: data.to.rank
5731
+ },
5732
+ {
5733
+ label: "Employment Status",
5734
+ from: data.from.status,
5735
+ to: data.to.status
5736
+ },
5737
+ {
5738
+ label: "Position",
5739
+ from: data.from.position,
5740
+ to: data.to.position
5741
+ },
5742
+ {
5743
+ label: "Department",
5744
+ from: data.from.department,
5745
+ to: data.to.department
5746
+ },
5747
+ {
5748
+ label: "Supervisor",
5749
+ from: data.from.supervisor,
5750
+ to: data.to.supervisor
5751
+ },
5752
+ {
5753
+ label: "Department Head",
5754
+ from: data.from.departmentHead,
5755
+ to: data.to.departmentHead
5756
+ },
5757
+ {
5758
+ label: "Company",
5759
+ from: data.from.company,
5760
+ to: data.to.company
5761
+ }
5762
+ ].map((row, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
5763
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5764
+ className: "text-[10px] italic font-bold py-1",
5765
+ children: row.label
5766
+ }),
5767
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5768
+ className: "border border-black p-1 text-[11px] w-[300px]",
5769
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5770
+ className: "px-1 min-h-[16px]",
5771
+ children: row.from
5772
+ })
5773
+ }),
5774
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5775
+ className: "border border-black p-1 text-[11px] w-[300px]",
5776
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5777
+ className: "px-1 min-h-[16px]",
5778
+ children: row.to
5779
+ })
5780
+ })
5781
+ ] }, i))] })]
5782
+ })]
5783
+ }),
5784
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5785
+ className: "mb-6",
5786
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
5787
+ className: "text-sm font-bold italic border-b border-black mb-2 uppercase tracking-tight",
5788
+ children: "Reason for Adjustment"
5789
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5790
+ className: "flex mb-2",
5791
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5792
+ className: "flex-1",
5793
+ children: [
5794
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5795
+ className: "flex items-center mb-1",
5796
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5797
+ className: "text-[10px] italic font-bold w-32",
5798
+ children: "Date of Effectivity:"
5799
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5800
+ className: "text-[11px] font-bold",
5801
+ children: fmtDate(data.effectiveDate)
5802
+ })]
5803
+ }),
5804
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5805
+ className: "text-[10px] italic font-bold mb-1",
5806
+ children: "Reason for Adjustment:"
5807
+ }),
5808
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5809
+ className: "flex items-start ml-4",
5810
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5811
+ className: "text-[10px] italic mt-1",
5812
+ children: "Others"
5813
+ })
5814
+ })
5815
+ ]
5816
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5817
+ className: "w-[450px]",
5818
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
5819
+ className: "w-full border-collapse",
5820
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
5821
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
5822
+ className: "w-1/3",
5823
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5824
+ className: "sr-only",
5825
+ children: "Component"
5826
+ })
5827
+ }),
5828
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
5829
+ className: "text-[11px] italic font-bold text-center border-x border-t border-black py-1",
5830
+ children: "FROM"
5831
+ }),
5832
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
5833
+ className: "text-[11px] italic font-bold text-center border-r border-t border-black py-1",
5834
+ children: "TO"
5835
+ })
5836
+ ] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tbody", {
5837
+ className: "border-b border-black",
5838
+ children: [
5839
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
5840
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5841
+ className: "text-[10px] italic pr-4 text-right font-bold uppercase",
5842
+ children: "Template"
5843
+ }),
5844
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5845
+ className: "border-x border-black px-2 py-0.5 text-[9px] text-center font-bold",
5846
+ children: data.fromTemplate || "—"
5847
+ }),
5848
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5849
+ className: "border-r border-black px-2 py-0.5 text-[9px] text-center font-bold",
5850
+ children: data.toTemplate || "—"
5851
+ })
5852
+ ] }),
5853
+ shownComponents.map((c, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
5854
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5855
+ className: "text-[10px] italic pr-4 text-right font-bold",
5856
+ children: c.label
5857
+ }),
5858
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5859
+ className: "border-x border-black px-2 py-0.5 text-[11px] text-right min-h-[18px]",
5860
+ children: c.from && parseFloat(c.from.replace(/,/g, "")) !== 0 ? c.from : ""
5861
+ }),
5862
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5863
+ className: "border-r border-black px-2 py-0.5 text-[11px] text-right min-h-[18px]",
5864
+ children: c.to && parseFloat(c.to.replace(/,/g, "")) !== 0 ? c.to : ""
5865
+ })
5866
+ ] }, i)),
5867
+ paddingRows.map((_, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
5868
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5869
+ className: "text-[10px] py-1",
5870
+ children: "\xA0"
5871
+ }),
5872
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5873
+ className: "border-x border-black",
5874
+ children: "\xA0"
5875
+ }),
5876
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5877
+ className: "border-r border-black",
5878
+ children: "\xA0"
5879
+ })
5880
+ ] }, `p-${i}`)),
5881
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", {
5882
+ className: "border-t border-black",
5883
+ children: [
5884
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5885
+ className: "text-[10px] italic pr-4 text-right font-bold uppercase py-1",
5886
+ children: "Total"
5887
+ }),
5888
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5889
+ className: "border-x border-black px-2 py-1 text-[11px] text-right font-bold",
5890
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5891
+ className: "border-b-4 border-double border-black pb-0.5",
5892
+ children: calcTotal("from")
5893
+ })
5894
+ }),
5895
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
5896
+ className: "border-r border-black px-2 py-1 text-[11px] text-right font-bold",
5897
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5898
+ className: "border-b-4 border-double border-black pb-0.5",
5899
+ children: calcTotal("to")
5900
+ })
5901
+ })
5902
+ ]
5903
+ })
5904
+ ]
5905
+ })]
5906
+ })
5907
+ })]
5908
+ })]
5909
+ }),
5910
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5911
+ className: "mb-8",
5912
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
5913
+ className: "text-sm font-bold italic border-b border-black mb-2 uppercase tracking-tight",
5914
+ children: "Reason for Change"
5915
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5916
+ className: "border border-black p-2 min-h-[60px] text-[11px] break-words whitespace-pre-wrap",
5917
+ children: data.reason
5918
+ })]
5919
+ }),
5920
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5921
+ className: "mt-10",
5922
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
5923
+ className: "text-sm font-bold italic border-b border-black mb-4 uppercase tracking-tight",
5924
+ children: "Authorized Signatories"
5925
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5926
+ className: "grid grid-cols-3 gap-6 mb-8",
5927
+ children: [
5928
+ {
5929
+ heading: "Prepared By",
5930
+ name: data.preparedBy,
5931
+ title: data.preparedByTitle || "HRMD Supervisor"
5932
+ },
5933
+ {
5934
+ heading: "Verified By",
5935
+ name: data.approvedBy || "VP of HRMD",
5936
+ title: data.approvedByTitle || "Vice President for HRMD"
5937
+ },
5938
+ {
5939
+ heading: "Conforme",
5940
+ name: data.employee.name,
5941
+ title: "Employee"
5942
+ }
5943
+ ].map((sig, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5944
+ className: "flex flex-col",
5945
+ children: [
5946
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
5947
+ className: "text-[11px] italic font-bold mb-3",
5948
+ children: sig.heading
5949
+ }),
5950
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-b border-black min-h-[48px] mb-1" }),
5951
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5952
+ className: "text-center",
5953
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5954
+ className: "text-[10px] font-bold uppercase",
5955
+ children: sig.name
5956
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5957
+ className: "text-[9px] font-bold text-slate-400",
5958
+ children: sig.title
5959
+ })]
5960
+ })
5961
+ ]
5962
+ }, i))
5963
+ })]
5964
+ }),
5965
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5966
+ className: "mt-6 border-t-2 border-dashed border-black pt-2 opacity-30 text-center",
5967
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5968
+ className: "text-[7px] font-black uppercase tracking-[0.2em] italic",
5969
+ children: "Authorized Document — DIWA HRIS"
5970
+ })
5971
+ })
5972
+ ]
5973
+ });
5974
+ }
5975
+ //#endregion
5976
+ //#region src/ui-library/gallery/page-sample/IsoCubeBlock.tsx
5977
+ function IsoCubeBlock({ boxWidth = 80, className = "" }) {
5978
+ const BW = boxWidth;
5979
+ const IH = BW * .575;
5980
+ const SH = BW * .525;
5981
+ const TOP_C = "#F3F3F5";
5982
+ const LEFT_C = "#7D739B";
5983
+ const RIGHT_C = "#9B92B8";
5984
+ function Box({ cx, cy }) {
5985
+ const hw = BW / 2;
5986
+ const A = `${cx + hw},${cy - IH}`;
5987
+ const B = `${cx + BW},${cy - IH / 2}`;
5988
+ const C = `${cx + hw},${cy}`;
5989
+ const D = `${cx},${cy - IH / 2}`;
5990
+ const E = `${cx + hw},${cy + SH}`;
5991
+ const F = `${cx},${cy - IH / 2 + SH}`;
5992
+ const G = `${cx + BW},${cy - IH / 2 + SH}`;
5993
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", { children: [
5994
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("polygon", {
5995
+ points: `${A} ${B} ${C} ${D}`,
5996
+ fill: TOP_C
5997
+ }),
5998
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("polygon", {
5999
+ points: `${D} ${C} ${E} ${F}`,
6000
+ fill: LEFT_C
6001
+ }),
6002
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("polygon", {
6003
+ points: `${B} ${C} ${E} ${G}`,
6004
+ fill: RIGHT_C
6005
+ })
6006
+ ] });
6007
+ }
6008
+ const COLS = 4;
6009
+ const ROWS = 4;
6010
+ const SVG_W = BW * 6;
6011
+ const SVG_H = BW * 4.75;
6012
+ const rowDY = -(IH / 2 + SH);
6013
+ const baseX = SVG_W - BW / 2;
6014
+ const baseY = SVG_H;
6015
+ const boxes = [];
6016
+ for (let row = 0; row < ROWS; row++) for (let col = 0; col < COLS; col++) {
6017
+ const cx = baseX - col * BW + row * (BW / 2);
6018
+ const cy = baseY + row * rowDY;
6019
+ boxes.push({
6020
+ cx,
6021
+ cy,
6022
+ key: `${row}-${col}`
6023
+ });
6024
+ }
6025
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
6026
+ "aria-hidden": "true",
6027
+ className: `pointer-events-none absolute bottom-0 right-0 ${className}`,
6028
+ width: SVG_W,
6029
+ height: SVG_H,
6030
+ viewBox: `0 0 ${SVG_W} ${SVG_H}`,
6031
+ style: { zIndex: 0 },
6032
+ overflow: "visible",
6033
+ children: [...boxes].sort((a, b) => {
6034
+ const [ar, ac] = a.key.split("-").map(Number);
6035
+ const [br, bc] = b.key.split("-").map(Number);
6036
+ if (ar !== br) return (br ?? 0) - (ar ?? 0);
6037
+ return (bc ?? 0) - (ac ?? 0);
6038
+ }).map(({ cx, cy, key }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Box, {
6039
+ cx,
6040
+ cy
6041
+ }, key))
6042
+ });
6043
+ }
6044
+ //#endregion
6045
+ //#region src/ui-library/gallery/template-samples/templates/PayslipTemplate.tsx
6046
+ var DEDUCTIONS = [
6047
+ {
6048
+ label: "W-Tax",
6049
+ amount: 117.59,
6050
+ remainingBalance: void 0,
6051
+ base: void 0
6052
+ },
6053
+ {
6054
+ label: "Pag-Ibig",
6055
+ amount: 100,
6056
+ remainingBalance: void 0,
6057
+ base: void 0
6058
+ },
6059
+ {
6060
+ label: "HMO Premium",
6061
+ amount: 229.99,
6062
+ remainingBalance: void 0,
6063
+ base: 5059.84
6064
+ },
6065
+ {
6066
+ label: "Insurance",
6067
+ amount: 19.44,
6068
+ remainingBalance: void 0,
6069
+ base: 427.62
6070
+ },
6071
+ {
6072
+ label: "COOP Share",
6073
+ amount: 300,
6074
+ remainingBalance: 4500,
6075
+ base: void 0
6076
+ },
6077
+ {
6078
+ label: "Salary Loan",
6079
+ amount: 1250,
6080
+ remainingBalance: 12500,
6081
+ base: void 0
6082
+ }
6083
+ ];
6084
+ var ATTENDANCE_LOGS = [
6085
+ {
6086
+ in: "07:00",
6087
+ out: "16:00"
6088
+ },
6089
+ {
6090
+ in: "07:15",
6091
+ out: "16:00"
6092
+ },
6093
+ {
6094
+ in: "Reg. Hol",
6095
+ out: "Reg. Hol"
6096
+ },
6097
+ {
6098
+ in: "Sp. Hol",
6099
+ out: "Sp. Hol"
6100
+ },
6101
+ {
6102
+ in: "-",
6103
+ out: "-"
6104
+ },
6105
+ {
6106
+ in: "-",
6107
+ out: "-"
6108
+ },
6109
+ {
6110
+ in: "07:00",
6111
+ out: "16:00"
6112
+ },
6113
+ {
6114
+ in: "VL w/pay",
6115
+ out: "VL w/pay"
6116
+ },
6117
+ {
6118
+ in: "SL w/pay",
6119
+ out: "SL w/pay"
6120
+ },
6121
+ {
6122
+ in: "07:00",
6123
+ out: "12:00 (VL)"
6124
+ },
6125
+ {
6126
+ in: "07:00",
6127
+ out: "13:00 (SL)"
6128
+ },
6129
+ {
6130
+ in: "07:00 (RH)",
6131
+ out: "16:00"
6132
+ },
6133
+ {
6134
+ in: "-",
6135
+ out: "-"
6136
+ },
6137
+ {
6138
+ in: "07:00",
6139
+ out: "16:00"
6140
+ },
6141
+ {
6142
+ in: "07:00",
6143
+ out: "16:00"
6144
+ },
6145
+ {
6146
+ in: "07:00",
6147
+ out: "16:00"
6148
+ }
6149
+ ];
6150
+ var WHOLE_DAY_TYPES = /* @__PURE__ */ new Set([
6151
+ "Reg. Hol",
6152
+ "Sp. Hol",
6153
+ "VL w/pay",
6154
+ "VL wo/pay",
6155
+ "SL w/pay",
6156
+ "SL wo/pay"
6157
+ ]);
6158
+ var fc = (n) => n.toLocaleString(void 0, {
6159
+ minimumFractionDigits: 2,
6160
+ maximumFractionDigits: 2
6161
+ });
6162
+ var fr = (n) => n.toLocaleString(void 0, {
6163
+ minimumFractionDigits: 2,
6164
+ maximumFractionDigits: 6
6165
+ });
6166
+ function AttendanceTable({ logs }) {
6167
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
6168
+ className: "flex-1 w-full text-center",
6169
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", {
6170
+ className: "border-b border-black",
6171
+ children: [
6172
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
6173
+ className: "font-black text-[8px]",
6174
+ children: "Date"
6175
+ }),
6176
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
6177
+ className: "font-black text-[8px]",
6178
+ children: "IN"
6179
+ }),
6180
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
6181
+ className: "font-black text-[8px]",
6182
+ children: "OUT"
6183
+ })
6184
+ ]
6185
+ }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: logs.map((log, i) => {
6186
+ const isWholeDay = WHOLE_DAY_TYPES.has(log.in) && log.in === log.out;
6187
+ const isAbsence = log.in === "-" && log.out === "-";
6188
+ const isTiny = log.in.includes("(") || log.out.includes("(");
6189
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6190
+ className: "font-bold text-[8px]",
6191
+ children: log.date
6192
+ }), isWholeDay ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6193
+ colSpan: 2,
6194
+ className: "text-center font-bold text-[5px] tracking-tight uppercase border-b border-black/10",
6195
+ children: log.in
6196
+ }) : isAbsence ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6197
+ className: "text-[6px]",
6198
+ children: "—"
6199
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6200
+ className: "text-[6px]",
6201
+ children: "—"
6202
+ })] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6203
+ className: isTiny ? "text-[5px]" : "text-[8px]",
6204
+ children: log.in
6205
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6206
+ className: isTiny ? "text-[5px]" : "text-[8px]",
6207
+ children: log.out
6208
+ })] })] }, i);
6209
+ }) })]
6210
+ });
6211
+ }
6212
+ function PayslipTemplate({ data }) {
6213
+ const rates = data.rates ?? {
6214
+ hourly: 107.9713,
6215
+ daily: 863.77,
6216
+ monthly: 22601.9
6217
+ };
6218
+ const taxCode = data.taxCode ?? "S";
6219
+ const taxableGross = data.taxableGross ?? (data.netPay ? data.netPay * 1.1 : 22601.9);
6220
+ const nonTaxableGross = data.nonTaxableGross ?? 0;
6221
+ const totalGross = taxableGross + nonTaxableGross;
6222
+ const totalDeductions = DEDUCTIONS.reduce((s, d) => s + d.amount, 0);
6223
+ const finalNet = totalGross - totalDeductions;
6224
+ const buildLogs = () => {
6225
+ const period = data.payPeriod;
6226
+ return ATTENDANCE_LOGS.map((log, idx) => {
6227
+ let date = String(16 + idx).padStart(2, "0");
6228
+ if (period && period.includes("-")) {
6229
+ const monthMap = {
6230
+ Jan: 0,
6231
+ Feb: 1,
6232
+ Mar: 2,
6233
+ Apr: 3,
6234
+ May: 4,
6235
+ Jun: 5,
6236
+ Jul: 6,
6237
+ Aug: 7,
6238
+ Sep: 8,
6239
+ Oct: 9,
6240
+ Nov: 10,
6241
+ Dec: 11
6242
+ };
6243
+ const parts = period.split(" ");
6244
+ const startMonth = monthMap[parts[0]] ?? 0;
6245
+ const startDay = parseInt(parts[1]) || 1;
6246
+ const year = parseInt(period.match(/\d{4}$/)?.[0] ?? String((/* @__PURE__ */ new Date()).getFullYear()));
6247
+ const d = new Date(year, startMonth, startDay + idx);
6248
+ date = `${String(d.getMonth() + 1).padStart(2, "0")}/${String(d.getDate()).padStart(2, "0")}`;
6249
+ }
6250
+ return {
6251
+ ...log,
6252
+ date
6253
+ };
6254
+ });
6255
+ };
6256
+ const logs = buildLogs();
6257
+ const leftLogs = logs.slice(0, 8);
6258
+ const rightLogs = logs.slice(8, 16);
6259
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6260
+ className: "bg-white text-[#1a1a1a] p-8 font-mono text-[10px] max-w-[900px] mx-auto leading-tight",
6261
+ children: [
6262
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6263
+ className: "grid grid-cols-12 gap-0 mb-2 items-start h-[70px]",
6264
+ children: [
6265
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6266
+ className: "col-span-4 translate-y-2",
6267
+ children: [
6268
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
6269
+ className: "text-lg font-black tracking-tight leading-none mb-2",
6270
+ children: "DIWA HRIS PAYSLIP"
6271
+ }),
6272
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
6273
+ className: "font-bold flex gap-1 text-[9px]",
6274
+ children: ["Period: ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6275
+ className: "font-normal",
6276
+ children: data.payPeriod || "No Period Selected"
6277
+ })]
6278
+ }),
6279
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
6280
+ className: "font-bold flex gap-1 text-[8px]",
6281
+ children: ["Printed: ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6282
+ className: "font-normal",
6283
+ children: (/* @__PURE__ */ new Date()).toLocaleDateString()
6284
+ })]
6285
+ })
6286
+ ]
6287
+ }),
6288
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6289
+ className: "col-span-4 border border-black p-1.5 mt-2 mb-1 relative z-10",
6290
+ children: [
6291
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6292
+ className: "flex gap-2 mb-0.5 border-b border-black pb-0.5",
6293
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6294
+ className: "font-black border-r border-black pr-2",
6295
+ children: data.id
6296
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6297
+ className: "font-black tracking-tight",
6298
+ children: data.name.toUpperCase()
6299
+ })]
6300
+ }),
6301
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6302
+ className: "font-bold text-[9px] border-b border-black pb-0.5 mb-0.5",
6303
+ children: data.role
6304
+ }),
6305
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6306
+ className: "font-bold text-[9px]",
6307
+ children: data.department
6308
+ })
6309
+ ]
6310
+ }),
6311
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6312
+ className: "col-span-4 text-[9px] pl-8 text-right pr-2 mt-4 space-y-0",
6313
+ children: [
6314
+ ["Hourly :", fr(rates.hourly)],
6315
+ ["Daily :", fr(rates.daily)],
6316
+ ["Monthly :", fr(rates.monthly)],
6317
+ ["Tax Code :", taxCode]
6318
+ ].map(([k, v]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6319
+ className: "grid grid-cols-2",
6320
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6321
+ className: "text-left font-bold",
6322
+ children: k
6323
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6324
+ className: "font-bold",
6325
+ children: v
6326
+ })]
6327
+ }, k))
6328
+ })
6329
+ ]
6330
+ }),
6331
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6332
+ className: "grid grid-cols-12 border-t border-black min-h-[160px]",
6333
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6334
+ className: "col-span-8 grid grid-cols-2 border-r border-black min-h-[160px]",
6335
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6336
+ className: "border-r border-black p-1 flex flex-col h-full",
6337
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6338
+ className: "flex-1",
6339
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6340
+ className: "font-black border-b border-black mb-1 p-0.5 flex justify-between",
6341
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "EARNINGS:" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6342
+ className: "flex gap-8 text-[7px] pr-2 items-center",
6343
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "UNIT" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "AMOUNT" })]
6344
+ })]
6345
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6346
+ className: "space-y-0.5",
6347
+ children: [
6348
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6349
+ className: "grid grid-cols-12 gap-1 px-1",
6350
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6351
+ className: "col-span-7",
6352
+ children: "Basic Salary"
6353
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6354
+ className: "col-span-5 text-right",
6355
+ children: fc(taxableGross)
6356
+ })]
6357
+ }),
6358
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6359
+ className: "grid grid-cols-12 gap-1 px-1",
6360
+ children: [
6361
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6362
+ className: "col-span-6",
6363
+ children: "Holiday Pay"
6364
+ }),
6365
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6366
+ className: "col-span-2 text-right",
6367
+ children: "1.00"
6368
+ }),
6369
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6370
+ className: "col-span-4 text-right",
6371
+ children: "863.77"
6372
+ })
6373
+ ]
6374
+ }),
6375
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6376
+ className: "grid grid-cols-12 gap-1 px-1 italic",
6377
+ children: [
6378
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6379
+ className: "col-span-6",
6380
+ children: "Absences"
6381
+ }),
6382
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6383
+ className: "col-span-2 text-right",
6384
+ children: "1.00"
6385
+ }),
6386
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6387
+ className: "col-span-4 text-right",
6388
+ children: [
6389
+ "(",
6390
+ fc(863.77),
6391
+ ")"
6392
+ ]
6393
+ })
6394
+ ]
6395
+ })
6396
+ ]
6397
+ })]
6398
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6399
+ className: "pt-2 border-t border-dotted border-black space-y-0.5",
6400
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6401
+ className: "grid grid-cols-12 gap-1 px-1",
6402
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6403
+ className: "col-span-8 font-bold",
6404
+ children: ["Gross ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6405
+ className: "font-normal",
6406
+ children: "(taxable)"
6407
+ })]
6408
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6409
+ className: "col-span-4 text-right",
6410
+ children: fc(taxableGross)
6411
+ })]
6412
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6413
+ className: "grid grid-cols-12 gap-1 px-1",
6414
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6415
+ className: "col-span-8 font-bold",
6416
+ children: ["Gross ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6417
+ className: "font-normal",
6418
+ children: "(nontaxable)"
6419
+ })]
6420
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6421
+ className: "col-span-4 text-right",
6422
+ children: fc(nonTaxableGross)
6423
+ })]
6424
+ })]
6425
+ })]
6426
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6427
+ className: "p-1",
6428
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6429
+ className: "font-black border-b border-black mb-1 p-0.5 flex justify-between",
6430
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "DEDUCTIONS:" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6431
+ className: "flex gap-4 text-[7px] pr-2 items-center",
6432
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6433
+ className: "w-16 text-center",
6434
+ children: "REM. BAL"
6435
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6436
+ className: "w-12 text-right",
6437
+ children: "AMOUNT"
6438
+ })]
6439
+ })]
6440
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6441
+ className: "space-y-0.5",
6442
+ children: DEDUCTIONS.map((d, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6443
+ className: "grid grid-cols-12 gap-1 px-1",
6444
+ children: [
6445
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6446
+ className: "col-span-5",
6447
+ children: d.label
6448
+ }),
6449
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6450
+ className: "col-span-3 text-center text-[8px] text-slate-500",
6451
+ children: d.remainingBalance ? fc(d.remainingBalance) : d.base ? fc(d.base) : ""
6452
+ }),
6453
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6454
+ className: "col-span-4 text-right",
6455
+ children: fc(d.amount)
6456
+ })
6457
+ ]
6458
+ }, i))
6459
+ })]
6460
+ })]
6461
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6462
+ className: "col-span-4 p-1 text-[8px]",
6463
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6464
+ className: "flex gap-4",
6465
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AttendanceTable, { logs: leftLogs }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AttendanceTable, { logs: rightLogs })]
6466
+ })
6467
+ })]
6468
+ }),
6469
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6470
+ className: "border-t border-black mb-1",
6471
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6472
+ className: "grid grid-cols-12",
6473
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6474
+ className: "col-span-8 border-r border-black",
6475
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6476
+ className: "grid grid-cols-2 bg-slate-100 py-1.5 border-y border-black font-black uppercase tracking-tight",
6477
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6478
+ className: "grid grid-cols-12 px-2 border-r border-black",
6479
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6480
+ className: "col-span-7",
6481
+ children: "Total Gross"
6482
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6483
+ className: "col-span-5 text-right",
6484
+ children: fc(totalGross)
6485
+ })]
6486
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6487
+ className: "grid grid-cols-12 px-2",
6488
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6489
+ className: "col-span-8 text-right pr-4",
6490
+ children: "Total Deductions:"
6491
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6492
+ className: "col-span-4 text-right",
6493
+ children: fc(totalDeductions)
6494
+ })]
6495
+ })]
6496
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6497
+ className: "p-1 px-2 flex gap-4 items-center h-8",
6498
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6499
+ className: "text-[11px] font-black uppercase",
6500
+ children: "Net Pay:"
6501
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6502
+ className: "text-[16px] font-black pl-4",
6503
+ children: fc(finalNet)
6504
+ })]
6505
+ })]
6506
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6507
+ className: "col-span-4 p-1 px-2",
6508
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6509
+ className: "grid grid-cols-2 border border-black text-center mb-2",
6510
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6511
+ className: "border-r border-black p-0.5",
6512
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6513
+ className: "border-b border-black font-bold uppercase text-[7px] mb-0.5",
6514
+ children: "YTD Gross"
6515
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6516
+ className: "font-black text-[12px]",
6517
+ children: fc(data.ytd?.gross ?? taxableGross)
6518
+ })]
6519
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6520
+ className: "p-0.5",
6521
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6522
+ className: "border-b border-black font-bold uppercase text-[7px] mb-0.5",
6523
+ children: "YTD Tax"
6524
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6525
+ className: "font-black text-[12px]",
6526
+ children: fc(data.ytd?.tax ?? totalDeductions * .1)
6527
+ })]
6528
+ })]
6529
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6530
+ className: "flex justify-between text-[8px] font-bold uppercase px-1 pb-0.5 pt-1",
6531
+ children: [
6532
+ ["VL", data.leaveBalances?.vacation.remaining ?? 10],
6533
+ ["SL", data.leaveBalances?.sick.remaining ?? 14],
6534
+ ["PL", data.leaveBalances?.personal?.remaining ?? 0]
6535
+ ].map(([k, v]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6536
+ className: "flex gap-1",
6537
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [k, " Bal:"] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6538
+ className: "font-normal",
6539
+ children: String(v)
6540
+ })]
6541
+ }, String(k)))
6542
+ })]
6543
+ })]
6544
+ })
6545
+ }),
6546
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6547
+ className: "mt-4 border-t-2 border-dashed border-black pt-2 opacity-30 text-center",
6548
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6549
+ className: "text-[7px] font-black uppercase tracking-[0.2em] italic",
6550
+ children: "Authorized Document — DIWA HRIS Fin-Audit System"
6551
+ })
6552
+ })
6553
+ ]
6554
+ });
6555
+ }
6556
+ //#endregion
6557
+ //#region src/ui-library/gallery/template-samples/templates/ReportTemplate.tsx
6558
+ var MOCK_ROWS = [
6559
+ {
6560
+ id: "DL-0001",
6561
+ name: "Maria Santos",
6562
+ dept: "Finance",
6563
+ position: "Senior Accountant",
6564
+ status: "Regular",
6565
+ dateHired: "Jan 15, 2021",
6566
+ rate: "25,000.00"
6567
+ },
6568
+ {
6569
+ id: "DL-0002",
6570
+ name: "Jose Reyes",
6571
+ dept: "IT",
6572
+ position: "IT Infrastructure Lead",
6573
+ status: "Regular",
6574
+ dateHired: "Mar 08, 2020",
6575
+ rate: "38,000.00"
6576
+ },
6577
+ {
6578
+ id: "DL-0003",
6579
+ name: "Ana Dela Cruz",
6580
+ dept: "HR",
6581
+ position: "HR Business Partner",
6582
+ status: "Regular",
6583
+ dateHired: "Jun 01, 2019",
6584
+ rate: "32,000.00"
6585
+ },
6586
+ {
6587
+ id: "DL-0004",
6588
+ name: "Carlo Mendoza",
6589
+ dept: "Operations",
6590
+ position: "Operations Manager",
6591
+ status: "Regular",
6592
+ dateHired: "Sep 22, 2022",
6593
+ rate: "45,000.00"
6594
+ },
6595
+ {
6596
+ id: "DL-0005",
6597
+ name: "Liza Bautista",
6598
+ dept: "Legal",
6599
+ position: "Legal Counsel",
6600
+ status: "Probationary",
6601
+ dateHired: "Feb 10, 2024",
6602
+ rate: "28,000.00"
6603
+ },
6604
+ {
6605
+ id: "DL-0006",
6606
+ name: "Mark Villanueva",
6607
+ dept: "Academic",
6608
+ position: "Academic Coordinator",
6609
+ status: "Regular",
6610
+ dateHired: "Nov 03, 2023",
6611
+ rate: "22,000.00"
6612
+ },
6613
+ {
6614
+ id: "DL-0007",
6615
+ name: "Rosa Castillo",
6616
+ dept: "Finance",
6617
+ position: "Bookkeeper",
6618
+ status: "Regular",
6619
+ dateHired: "Apr 14, 2018",
6620
+ rate: "20,000.00"
6621
+ },
6622
+ {
6623
+ id: "DL-0008",
6624
+ name: "Noel Ramos",
6625
+ dept: "IT",
6626
+ position: "Systems Analyst",
6627
+ status: "Regular",
6628
+ dateHired: "Jul 30, 2021",
6629
+ rate: "30,000.00"
6630
+ },
6631
+ {
6632
+ id: "DL-0009",
6633
+ name: "Cynthia Torres",
6634
+ dept: "HR",
6635
+ position: "Recruitment Officer",
6636
+ status: "Regular",
6637
+ dateHired: "Dec 05, 2022",
6638
+ rate: "24,000.00"
6639
+ },
6640
+ {
6641
+ id: "DL-0010",
6642
+ name: "Ramon Aquino",
6643
+ dept: "Operations",
6644
+ position: "Logistics Coordinator",
6645
+ status: "Probationary",
6646
+ dateHired: "Aug 18, 2024",
6647
+ rate: "19,500.00"
6648
+ },
6649
+ {
6650
+ id: "DL-0011",
6651
+ name: "Elena Fuentes",
6652
+ dept: "Academic",
6653
+ position: "Faculty Member",
6654
+ status: "Regular",
6655
+ dateHired: "Jun 12, 2017",
6656
+ rate: "27,000.00"
6657
+ },
6658
+ {
6659
+ id: "DL-0012",
6660
+ name: "Dennis Lacerna",
6661
+ dept: "Finance",
6662
+ position: "Payroll Officer",
6663
+ status: "Regular",
6664
+ dateHired: "Oct 01, 2020",
6665
+ rate: "23,500.00"
6666
+ }
6667
+ ];
6668
+ var HEADERS = [
6669
+ "#",
6670
+ "Employee ID",
6671
+ "Full Name",
6672
+ "Department",
6673
+ "Position",
6674
+ "Status",
6675
+ "Date Hired",
6676
+ "Monthly Rate"
6677
+ ];
6678
+ function ReportTemplate({ data }) {
6679
+ const today = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
6680
+ month: "long",
6681
+ day: "numeric",
6682
+ year: "numeric"
6683
+ });
6684
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6685
+ className: "bg-white text-black font-sans",
6686
+ style: {
6687
+ width: "816px",
6688
+ minHeight: "1056px",
6689
+ padding: "48px 50px",
6690
+ boxSizing: "border-box"
6691
+ },
6692
+ children: [
6693
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6694
+ className: "flex justify-between items-start mb-6 border-b-2 border-black pb-4",
6695
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
6696
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6697
+ className: "text-[9px] text-slate-500 uppercase tracking-widest mb-1 font-bold",
6698
+ children: data.company || "DIWA Learning Systems, Inc."
6699
+ }),
6700
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
6701
+ className: "text-[20px] font-black uppercase tracking-tight leading-tight",
6702
+ children: data.title || "Employee Masterlist Report"
6703
+ }),
6704
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6705
+ className: "text-[11px] text-slate-500 mt-0.5 italic",
6706
+ children: data.subtitle || "All Active Employees — Direct Labor"
6707
+ })
6708
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6709
+ className: "text-right text-[9px] space-y-0.5",
6710
+ children: [
6711
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
6712
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6713
+ className: "font-bold",
6714
+ children: "As of:"
6715
+ }),
6716
+ " ",
6717
+ data.asOf || today
6718
+ ] }),
6719
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
6720
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6721
+ className: "font-bold",
6722
+ children: "Date Printed:"
6723
+ }),
6724
+ " ",
6725
+ today
6726
+ ] }),
6727
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6728
+ className: "font-bold",
6729
+ children: "Page:"
6730
+ }), " 1 of 1"] }),
6731
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
6732
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6733
+ className: "font-bold",
6734
+ children: "Prepared by:"
6735
+ }),
6736
+ " ",
6737
+ data.preparedBy || "System"
6738
+ ] })
6739
+ ]
6740
+ })]
6741
+ }),
6742
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6743
+ className: "flex gap-6 mb-5 text-[10px]",
6744
+ children: [
6745
+ ["Total Employees", String(MOCK_ROWS.length)],
6746
+ ["Regular", String(MOCK_ROWS.filter((r) => r.status === "Regular").length)],
6747
+ ["Probationary", String(MOCK_ROWS.filter((r) => r.status === "Probationary").length)],
6748
+ ["Departments", "5"]
6749
+ ].map(([label, value]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6750
+ className: "border border-black px-3 py-1.5 text-center min-w-[80px]",
6751
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6752
+ className: "font-black text-[16px]",
6753
+ children: value
6754
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6755
+ className: "text-[8px] text-slate-500 font-bold uppercase tracking-tight",
6756
+ children: label
6757
+ })]
6758
+ }, label))
6759
+ }),
6760
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
6761
+ className: "w-full border-collapse text-[9px]",
6762
+ children: [
6763
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", {
6764
+ className: "bg-[#00377B] text-white",
6765
+ children: HEADERS.map((h) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
6766
+ className: "border border-[#00377B] px-2 py-1.5 text-left font-bold uppercase tracking-wide text-[8px]",
6767
+ children: h
6768
+ }, h))
6769
+ }) }),
6770
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: MOCK_ROWS.map((row, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", {
6771
+ className: i % 2 === 0 ? "bg-white" : "bg-slate-50",
6772
+ children: [
6773
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6774
+ className: "border border-slate-200 px-2 py-1 text-slate-400",
6775
+ children: i + 1
6776
+ }),
6777
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6778
+ className: "border border-slate-200 px-2 py-1 font-mono font-bold",
6779
+ children: row.id
6780
+ }),
6781
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6782
+ className: "border border-slate-200 px-2 py-1 font-bold uppercase",
6783
+ children: row.name
6784
+ }),
6785
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6786
+ className: "border border-slate-200 px-2 py-1",
6787
+ children: row.dept
6788
+ }),
6789
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6790
+ className: "border border-slate-200 px-2 py-1",
6791
+ children: row.position
6792
+ }),
6793
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6794
+ className: "border border-slate-200 px-2 py-1",
6795
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6796
+ className: ["inline-flex items-center rounded px-1.5 py-0.5 text-[8px] font-bold uppercase tracking-tight", row.status === "Regular" ? "bg-emerald-50 text-emerald-700" : "bg-amber-50 text-amber-700"].join(" "),
6797
+ children: row.status
6798
+ })
6799
+ }),
6800
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6801
+ className: "border border-slate-200 px-2 py-1",
6802
+ children: row.dateHired
6803
+ }),
6804
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6805
+ className: "border border-slate-200 px-2 py-1 text-right font-mono",
6806
+ children: row.rate
6807
+ })
6808
+ ]
6809
+ }, row.id)) }),
6810
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tfoot", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", {
6811
+ className: "bg-slate-100 font-black border-t-2 border-black",
6812
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6813
+ colSpan: 7,
6814
+ className: "border border-slate-300 px-2 py-1.5 text-right uppercase text-[8px] tracking-widest",
6815
+ children: "Total Monthly Cost:"
6816
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
6817
+ className: "border border-slate-300 px-2 py-1.5 text-right font-mono",
6818
+ children: MOCK_ROWS.reduce((s, r) => s + parseFloat(r.rate.replace(/,/g, "")), 0).toLocaleString("en-US", { minimumFractionDigits: 2 })
6819
+ })]
6820
+ }) })
6821
+ ]
6822
+ }),
6823
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6824
+ className: "mt-8 flex justify-between items-end text-[9px]",
6825
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
6826
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-b border-black w-48 mb-1" }),
6827
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6828
+ className: "font-bold",
6829
+ children: ["Prepared by: ", data.preparedBy || "HRIS System"]
6830
+ }),
6831
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6832
+ className: "text-slate-400",
6833
+ children: "Human Resources Management Division"
6834
+ })
6835
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6836
+ className: "text-right",
6837
+ children: [
6838
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-b border-black w-48 mb-1 ml-auto" }),
6839
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6840
+ className: "font-bold",
6841
+ children: "Noted by: ___________________________"
6842
+ }),
6843
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6844
+ className: "text-slate-400",
6845
+ children: "HR Director / VP Operations"
6846
+ })
6847
+ ]
6848
+ })]
6849
+ }),
6850
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6851
+ className: "mt-6 border-t border-dashed border-black/40 pt-2 text-center opacity-40",
6852
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6853
+ className: "text-[7px] font-black uppercase tracking-[0.2em] italic",
6854
+ children: "System-Generated Report — DIWA HRIS — Confidential"
6855
+ })
6856
+ })
6857
+ ]
6858
+ });
6859
+ }
6860
+ //#endregion
6861
+ //#region src/ui-library/gallery/template-samples/templates/TimekeepingTemplate.tsx
6862
+ /**
6863
+ * TimekeepingTemplate — self-contained preview component
6864
+ *
6865
+ * Ported from unified-hris/components/TimekeepingFileTemplate.tsx.
6866
+ * No context deps. All data is mock + prop-driven.
6867
+ */
6868
+ var RECORDS = [
6869
+ {
6870
+ dateIn: "16-Jan-25",
6871
+ day: "Thu",
6872
+ shift: 1,
6873
+ timeIn: "7:00 am",
6874
+ dateOut: "16-Jan-25",
6875
+ timeOut: "4:00 pm",
6876
+ hours: "8.00",
6877
+ actual: "9.00",
6878
+ late: "-",
6879
+ utime: "-",
6880
+ ot: "-",
6881
+ nd2: "-",
6882
+ rem: "-"
6883
+ },
6884
+ {
6885
+ dateIn: "17-Jan-25",
6886
+ day: "Fri",
6887
+ shift: 1,
6888
+ timeIn: "7:15 am",
6889
+ dateOut: "17-Jan-25",
6890
+ timeOut: "4:00 pm",
6891
+ hours: "8.00",
6892
+ actual: "9.00",
6893
+ late: "15",
6894
+ utime: "-",
6895
+ ot: "-",
6896
+ nd2: "-",
6897
+ rem: "-"
6898
+ },
6899
+ {
6900
+ dateIn: "18-Jan-25",
6901
+ day: "Sat",
6902
+ shift: 1,
6903
+ timeIn: "-",
6904
+ dateOut: "-",
6905
+ timeOut: "-",
6906
+ hours: "-",
6907
+ actual: "-",
6908
+ late: "-",
6909
+ utime: "-",
6910
+ ot: "-",
6911
+ nd2: "-",
6912
+ rem: "-"
6913
+ },
6914
+ {
6915
+ dateIn: "19-Jan-25",
6916
+ day: "Sun",
6917
+ shift: 1,
6918
+ timeIn: "-",
6919
+ dateOut: "-",
6920
+ timeOut: "-",
6921
+ hours: "-",
6922
+ actual: "-",
6923
+ late: "-",
6924
+ utime: "-",
6925
+ ot: "-",
6926
+ nd2: "-",
6927
+ rem: "-"
6928
+ },
6929
+ {
6930
+ dateIn: "20-Jan-25",
6931
+ day: "Mon",
6932
+ shift: 1,
6933
+ timeIn: "7:00 am",
6934
+ dateOut: "20-Jan-25",
6935
+ timeOut: "4:00 pm",
6936
+ hours: "8.00",
6937
+ actual: "9.00",
6938
+ late: "-",
6939
+ utime: "-",
6940
+ ot: "-",
6941
+ nd2: "-",
6942
+ rem: "-"
6943
+ },
6944
+ {
6945
+ dateIn: "21-Jan-25",
6946
+ day: "Tue",
6947
+ shift: 1,
6948
+ timeIn: "7:00 am",
6949
+ dateOut: "21-Jan-25",
6950
+ timeOut: "4:00 pm",
6951
+ hours: "8.00",
6952
+ actual: "9.00",
6953
+ late: "-",
6954
+ utime: "-",
6955
+ ot: "-",
6956
+ nd2: "-",
6957
+ rem: "-"
6958
+ },
6959
+ {
6960
+ dateIn: "22-Jan-25",
6961
+ day: "Wed",
6962
+ shift: 1,
6963
+ timeIn: "7:00 am",
6964
+ dateOut: "22-Jan-25",
6965
+ timeOut: "4:00 pm",
6966
+ hours: "8.00",
6967
+ actual: "9.00",
6968
+ late: "-",
6969
+ utime: "-",
6970
+ ot: "-",
6971
+ nd2: "-",
6972
+ rem: "-"
6973
+ },
6974
+ {
6975
+ dateIn: "23-Jan-25",
6976
+ day: "Thu",
6977
+ shift: 1,
6978
+ timeIn: "7:00 am",
6979
+ dateOut: "23-Jan-25",
6980
+ timeOut: "4:00 pm",
6981
+ hours: "8.00",
6982
+ actual: "9.00",
6983
+ late: "-",
6984
+ utime: "-",
6985
+ ot: "-",
6986
+ nd2: "-",
6987
+ rem: "-"
6988
+ },
6989
+ {
6990
+ dateIn: "24-Jan-25",
6991
+ day: "Fri",
6992
+ shift: 1,
6993
+ timeIn: "7:00 am",
6994
+ dateOut: "24-Jan-25",
6995
+ timeOut: "4:00 pm",
6996
+ hours: "8.00",
6997
+ actual: "9.00",
6998
+ late: "-",
6999
+ utime: "-",
7000
+ ot: "-",
7001
+ nd2: "-",
7002
+ rem: "-"
7003
+ },
7004
+ {
7005
+ dateIn: "25-Jan-25",
7006
+ day: "Sat",
7007
+ shift: 1,
7008
+ timeIn: "-",
7009
+ dateOut: "-",
7010
+ timeOut: "-",
7011
+ hours: "-",
7012
+ actual: "-",
7013
+ late: "-",
7014
+ utime: "-",
7015
+ ot: "-",
7016
+ nd2: "-",
7017
+ rem: "-"
7018
+ },
7019
+ {
7020
+ dateIn: "26-Jan-25",
7021
+ day: "Sun",
7022
+ shift: 1,
7023
+ timeIn: "-",
7024
+ dateOut: "-",
7025
+ timeOut: "-",
7026
+ hours: "-",
7027
+ actual: "-",
7028
+ late: "-",
7029
+ utime: "-",
7030
+ ot: "-",
7031
+ nd2: "-",
7032
+ rem: "-"
7033
+ },
7034
+ {
7035
+ dateIn: "27-Jan-25",
7036
+ day: "Mon",
7037
+ shift: 1,
7038
+ timeIn: "7:00 am",
7039
+ dateOut: "27-Jan-25",
7040
+ timeOut: "4:00 pm",
7041
+ hours: "8.00",
7042
+ actual: "9.00",
7043
+ late: "-",
7044
+ utime: "-",
7045
+ ot: "-",
7046
+ nd2: "-",
7047
+ rem: "-"
7048
+ },
7049
+ {
7050
+ dateIn: "28-Jan-25",
7051
+ day: "Tue",
7052
+ shift: 1,
7053
+ timeIn: "7:00 am",
7054
+ dateOut: "28-Jan-25",
7055
+ timeOut: "4:00 pm",
7056
+ hours: "8.00",
7057
+ actual: "9.00",
7058
+ late: "-",
7059
+ utime: "-",
7060
+ ot: "-",
7061
+ nd2: "-",
7062
+ rem: "-"
7063
+ },
7064
+ {
7065
+ dateIn: "29-Jan-25",
7066
+ day: "Wed",
7067
+ shift: 1,
7068
+ timeIn: "-",
7069
+ dateOut: "-",
7070
+ timeOut: "-",
7071
+ hours: "-",
7072
+ actual: "-",
7073
+ late: "-",
7074
+ utime: "-",
7075
+ ot: "-",
7076
+ nd2: "-",
7077
+ rem: "Sp. Hol"
7078
+ },
7079
+ {
7080
+ dateIn: "30-Jan-25",
7081
+ day: "Thu",
7082
+ shift: 1,
7083
+ timeIn: "7:00 am",
7084
+ dateOut: "30-Jan-25",
7085
+ timeOut: "4:00 pm",
7086
+ hours: "8.00",
7087
+ actual: "9.00",
7088
+ late: "-",
7089
+ utime: "-",
7090
+ ot: "-",
7091
+ nd2: "-",
7092
+ rem: "-"
7093
+ },
7094
+ {
7095
+ dateIn: "31-Jan-25",
7096
+ day: "Fri",
7097
+ shift: 1,
7098
+ timeIn: "7:00 am",
7099
+ dateOut: "31-Jan-25",
7100
+ timeOut: "4:00 pm",
7101
+ hours: "8.00",
7102
+ actual: "9.00",
7103
+ late: "-",
7104
+ utime: "-",
7105
+ ot: "-",
7106
+ nd2: "-",
7107
+ rem: "-"
7108
+ }
7109
+ ];
7110
+ var OT_SUMMARY = [
7111
+ "OT 0.30",
7112
+ "OT 1.00",
7113
+ "OT 1.25",
7114
+ "OT 1.30",
7115
+ "OT 1.69",
7116
+ "OT 1.50",
7117
+ "OT 1.95",
7118
+ "OT 2.00",
7119
+ "OT 2.69",
7120
+ "OT 3.38"
7121
+ ];
7122
+ function TimekeepingTemplate({ data }) {
7123
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7124
+ className: "w-[297mm] min-h-[210mm] bg-white text-black font-sans text-[10px] leading-tight p-10 mx-auto",
7125
+ children: [
7126
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7127
+ className: "flex justify-between items-start mb-4",
7128
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
7129
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7130
+ className: "mb-2 text-[10px]",
7131
+ children: ["DatePrinted: \xA0 ", (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
7132
+ month: "2-digit",
7133
+ day: "2-digit",
7134
+ year: "numeric"
7135
+ })]
7136
+ }),
7137
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
7138
+ className: "text-xl font-bold uppercase tracking-tight",
7139
+ children: "DIWA HRIS — TimeSheet"
7140
+ }),
7141
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7142
+ className: "mt-4 flex gap-8",
7143
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7144
+ className: "flex gap-2",
7145
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7146
+ className: "w-16",
7147
+ children: "Emp. ID:"
7148
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7149
+ className: "font-bold",
7150
+ children: data.employee.empId || "DL250814-002"
7151
+ })]
7152
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7153
+ className: "flex gap-2",
7154
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7155
+ className: "w-16",
7156
+ children: "Name:"
7157
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7158
+ className: "font-bold uppercase",
7159
+ children: data.employee.name
7160
+ })]
7161
+ })] })
7162
+ })
7163
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7164
+ className: "text-right",
7165
+ children: [
7166
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7167
+ className: "mb-1",
7168
+ children: "Page 1 of 1"
7169
+ }),
7170
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7171
+ className: "font-bold text-sm mb-2",
7172
+ children: data.period || "01/16/2025 – 01/31/2025"
7173
+ }),
7174
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7175
+ className: "grid grid-cols-[80px_1fr] gap-x-2 text-left",
7176
+ children: [
7177
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Shift:" }),
7178
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7179
+ className: "font-bold",
7180
+ children: "1"
7181
+ }),
7182
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Position:" }),
7183
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7184
+ className: "font-bold",
7185
+ children: data.employee.role
7186
+ }),
7187
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Department:" }),
7188
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7189
+ className: "font-bold",
7190
+ children: data.employee.department
7191
+ }),
7192
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Imm. Superior:" }),
7193
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7194
+ className: "font-bold",
7195
+ children: data.employee.supervisor || "ACGarcia"
7196
+ })
7197
+ ]
7198
+ })
7199
+ ]
7200
+ })]
7201
+ }),
7202
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7203
+ className: "border-t border-b border-black mb-1",
7204
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
7205
+ className: "w-full text-center border-collapse",
7206
+ children: [
7207
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", {
7208
+ className: "border-b border-black",
7209
+ children: [
7210
+ "DateIn",
7211
+ "Day",
7212
+ "Shift",
7213
+ "TimeIn",
7214
+ "DateOut",
7215
+ "TimeOut",
7216
+ "Hours",
7217
+ "Actual",
7218
+ "Late",
7219
+ "Utime",
7220
+ "OT",
7221
+ "ND2",
7222
+ "Rem."
7223
+ ].map((h) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
7224
+ className: "py-1 text-[9px]",
7225
+ children: h
7226
+ }, h))
7227
+ }) }),
7228
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: RECORDS.map((r, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", {
7229
+ className: "h-4",
7230
+ children: [
7231
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: r.dateIn }),
7232
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: r.day }),
7233
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: r.shift }),
7234
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: r.timeIn }),
7235
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: r.dateOut }),
7236
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: r.timeOut }),
7237
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: r.hours }),
7238
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: r.actual }),
7239
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: r.late }),
7240
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: r.utime }),
7241
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: r.ot }),
7242
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: r.nd2 }),
7243
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: r.rem })
7244
+ ]
7245
+ }, i)) }),
7246
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tfoot", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", {
7247
+ className: "border-t border-black font-bold",
7248
+ children: [
7249
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
7250
+ colSpan: 6,
7251
+ className: "text-left py-1 pl-2",
7252
+ children: "Totals: ( 11 WorkDays )"
7253
+ }),
7254
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: "88.00" }),
7255
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: "99.00" }),
7256
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: "0.00" }),
7257
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: "0.00" }),
7258
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: "0.00" }),
7259
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: "0.00" }),
7260
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {})
7261
+ ]
7262
+ }) })
7263
+ ]
7264
+ })
7265
+ }),
7266
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7267
+ className: "flex justify-end mb-6 font-bold text-[10px]",
7268
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7269
+ className: "text-right w-[120px]",
7270
+ children: [
7271
+ "Employment Status:",
7272
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}),
7273
+ "Regular",
7274
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}),
7275
+ "Monthly",
7276
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}),
7277
+ "Rest Day: Sunday"
7278
+ ]
7279
+ })
7280
+ }),
7281
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7282
+ className: "text-center mb-10 px-12",
7283
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7284
+ className: "mb-1",
7285
+ children: "I hereby certify that the above records are true and correct. Any"
7286
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: "unauthorized overtime will not be paid by the management." })]
7287
+ }),
7288
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7289
+ className: "flex justify-between px-16 mb-10",
7290
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7291
+ className: "text-center w-48",
7292
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-b border-black mb-1" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: "Employee Signature" })]
7293
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7294
+ className: "text-center w-48",
7295
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-b border-black mb-1" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: "Immediate Superior" })]
7296
+ })]
7297
+ }),
7298
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7299
+ className: "text-center mb-2",
7300
+ children: "For HRD use only, please do not tamper with."
7301
+ }),
7302
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7303
+ className: "border-t border-black pt-2 flex justify-between items-start mb-6",
7304
+ children: [
7305
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7306
+ className: "grid grid-cols-[90px_60px] gap-y-0.5",
7307
+ children: [
7308
+ ["Days Worked:", "11.00"],
7309
+ ["Hours Worked:", "88.00"],
7310
+ ["Absences:", "1.00"],
7311
+ ["", ""],
7312
+ ["Tardiness:", "0.00"],
7313
+ ["Reg. ND1", "0.00"],
7314
+ ["Reg. ND2", "0.00"],
7315
+ ["Holiday", "1.00"],
7316
+ ["", ""],
7317
+ ["Undertime:", "0.00"]
7318
+ ].map(([k, v], i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.default.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: k }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7319
+ className: "text-right",
7320
+ children: v
7321
+ })] }, i))
7322
+ }),
7323
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7324
+ className: "w-1/3",
7325
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7326
+ className: "flex border-b border-black pb-0.5 mb-1",
7327
+ children: [
7328
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7329
+ className: "underline mr-auto",
7330
+ children: "Summary:"
7331
+ }),
7332
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7333
+ className: "w-10 text-center underline",
7334
+ children: "10%"
7335
+ }),
7336
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7337
+ className: "w-10 text-center underline",
7338
+ children: "15%"
7339
+ })
7340
+ ]
7341
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7342
+ className: "grid grid-cols-1 gap-y-0.5 pl-2",
7343
+ children: OT_SUMMARY.map((ot) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: ot }, ot))
7344
+ })]
7345
+ }),
7346
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7347
+ className: "grid grid-cols-[90px_30px] gap-y-0.5 text-right",
7348
+ children: [
7349
+ ["VL Bal :", "10"],
7350
+ ["SL Bal :", "14"],
7351
+ ["VL w/ Pay :", "0"],
7352
+ ["VL w/o Pay :", "0"],
7353
+ ["Prev.VL w/ Pay :", "0"],
7354
+ ["SL w/ Pay :", "0"],
7355
+ ["SL w/o Pay :", "0"],
7356
+ ["PL Taken :", "0"],
7357
+ ["BL Taken :", "0"],
7358
+ ["Meal Allow. :", "0"]
7359
+ ].map(([k, v], i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.default.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: k }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: v })] }, i))
7360
+ })
7361
+ ]
7362
+ }),
7363
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-t border-black/50 border-dashed pt-2" })
7364
+ ]
7365
+ });
7366
+ }
7367
+ //#endregion
4648
7368
  //#region src/ui-library/gallery/stat-card/Statistic.tsx
4649
7369
  /**
4650
7370
  * Statistic — Design System Component
@@ -4773,12 +7493,12 @@ var DOT_STYLES = {
4773
7493
  shadow: "0 0 0 3px rgba(239,68,68,0.18)"
4774
7494
  },
4775
7495
  inactive: {
4776
- bg: "#f59e0b",
4777
- shadow: "0 0 0 3px rgba(245,158,11,0.18)"
7496
+ bg: "#b45309",
7497
+ shadow: "0 0 0 3px rgba(180,83,9,0.18)"
4778
7498
  },
4779
7499
  pending: {
4780
- bg: "#eab308",
4781
- shadow: "0 0 0 3px rgba(234,179,8,0.18)"
7500
+ bg: "#0284c7",
7501
+ shadow: "0 0 0 3px rgba(2,132,199,0.18)"
4782
7502
  }
4783
7503
  };
4784
7504
  function StatusDot({ status, label, className = "" }) {
@@ -4998,11 +7718,14 @@ exports.AccordionTrigger = AccordionTrigger;
4998
7718
  exports.ActivityFeed = ActivityFeed;
4999
7719
  exports.Alert = Alert;
5000
7720
  exports.ApprovalTimeline = ApprovalTimeline;
7721
+ exports.AreaChart = AreaChart;
5001
7722
  exports.Avatar = Avatar;
5002
7723
  exports.Badge = Badge;
5003
7724
  exports.BarChart = BarChart;
7725
+ exports.BarList = BarList;
5004
7726
  exports.Breadcrumb = Breadcrumb;
5005
7727
  exports.Button = Button;
7728
+ exports.CHART_PALETTE = CHART_PALETTE;
5006
7729
  exports.Calendar = Calendar;
5007
7730
  exports.Card = Card;
5008
7731
  exports.CardContent = CardContent;
@@ -5033,13 +7756,18 @@ exports.FilterChip = FilterChip;
5033
7756
  exports.Heatmap = Heatmap;
5034
7757
  exports.IconButton = IconButton;
5035
7758
  exports.Input = Input;
7759
+ exports.IsoCubeBlock = IsoCubeBlock;
5036
7760
  exports.Kanban = Kanban;
5037
7761
  exports.LineChart = LineChart;
5038
7762
  exports.Menu = Menu;
5039
7763
  exports.Modal = Modal;
7764
+ exports.OrgChart = OrgChart;
7765
+ exports.OrgUnitTree = OrgUnitTree;
5040
7766
  exports.OtpInput = OtpInput;
7767
+ exports.PafTemplate = PafTemplate;
5041
7768
  exports.PageHeader = PageHeader;
5042
7769
  exports.Pagination = Pagination;
7770
+ exports.PayslipTemplate = PayslipTemplate;
5043
7771
  exports.PermissionMatrix = PermissionMatrix;
5044
7772
  exports.Popover = Popover;
5045
7773
  exports.PopoverContent = PopoverContent;
@@ -5047,6 +7775,8 @@ exports.PopoverTrigger = PopoverTrigger;
5047
7775
  exports.Progress = Progress;
5048
7776
  exports.RadioGroup = RadioGroup;
5049
7777
  exports.RadioItem = RadioItem;
7778
+ exports.ReportTemplate = ReportTemplate;
7779
+ exports.STATUS_PAGE_PRESETS = STATUS_PAGE_PRESETS;
5050
7780
  exports.Section = Section;
5051
7781
  exports.SegmentedControl = SegmentedControl;
5052
7782
  exports.Select = Select;
@@ -5063,6 +7793,7 @@ exports.Spinner = Spinner;
5063
7793
  exports.Statistic = Statistic;
5064
7794
  exports.StatusBadge = StatusBadge;
5065
7795
  exports.StatusDot = StatusDot;
7796
+ exports.StatusPage = StatusPage;
5066
7797
  exports.Stepper = Stepper;
5067
7798
  exports.Switch = Switch;
5068
7799
  exports.Tab = Tab;
@@ -5071,6 +7802,7 @@ exports.TabPanel = TabPanel;
5071
7802
  exports.TabPanels = TabPanels;
5072
7803
  exports.Tabs = Tabs;
5073
7804
  exports.Textarea = Textarea;
7805
+ exports.TimekeepingTemplate = TimekeepingTemplate;
5074
7806
  exports.Timeline = Timeline;
5075
7807
  exports.TimelineEmptyState = TimelineEmptyState;
5076
7808
  exports.TimelineFooter = TimelineFooter;