@geomak/ui 5.0.2 → 5.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -999,6 +999,9 @@ function useNotification() {
999
999
  };
1000
1000
  }
1001
1001
  var SIZE_MAP = {
1002
+ // xs is sized to fit beside button text (~14px) — async AutoComplete,
1003
+ // Button loading prop, inline status badges, etc.
1004
+ xs: { outer: "w-3.5 h-3.5", inner: "w-1.5 h-1.5", dot: "w-0.5 h-0.5", stroke: "border-[1.5px]", text: "text-[10px]" },
1002
1005
  sm: { outer: "w-8 h-8", inner: "w-4 h-4", dot: "w-1 h-1", stroke: "border-2", text: "text-xs" },
1003
1006
  md: { outer: "w-20 h-20", inner: "w-12 h-12", dot: "w-2 h-2", stroke: "border-[3px]", text: "text-2xl" },
1004
1007
  lg: { outer: "w-32 h-32", inner: "w-20 h-20", dot: "w-3 h-3", stroke: "border-4", text: "text-4xl" }
@@ -1159,53 +1162,82 @@ function List2({ items, onItemClick, activeKey }) {
1159
1162
  )
1160
1163
  )) });
1161
1164
  }
1165
+ var TOGGLE_POSITION_CLASS = {
1166
+ "top-left": "top-2 left-2",
1167
+ "top-right": "top-2 right-2",
1168
+ "bottom-left": "bottom-2 left-2",
1169
+ "bottom-right": "bottom-2 right-2"
1170
+ };
1162
1171
  function ScalableContainer({
1163
- width,
1164
- height,
1172
+ width = "100%",
1173
+ height = "auto",
1165
1174
  children,
1166
- assignClassOnClick
1175
+ assignClassOnClick,
1176
+ expandIcon,
1177
+ collapseIcon,
1178
+ togglePosition = "top-right"
1167
1179
  }) {
1168
1180
  const containerRef = React8.useRef(null);
1169
1181
  const [isScaled, setScaled] = React8.useState(false);
1170
- const [wrapperClass, setWrapperClass] = React8.useState("");
1171
- const onClick = () => {
1182
+ const reduced = framerMotion.useReducedMotion();
1183
+ const onToggle = () => {
1172
1184
  const next = !isScaled;
1173
1185
  setScaled(next);
1174
- setTimeout(() => {
1175
- containerRef.current?.scrollIntoView({ behavior: "smooth" });
1176
- if (assignClassOnClick) {
1177
- setWrapperClass(next ? assignClassOnClick : "");
1178
- }
1179
- }, 200);
1186
+ requestAnimationFrame(() => containerRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" }));
1180
1187
  };
1188
+ const wrapperClass = isScaled ? assignClassOnClick : void 0;
1181
1189
  return /* @__PURE__ */ jsxRuntime.jsxs(
1182
- "div",
1190
+ framerMotion.motion.div,
1183
1191
  {
1184
1192
  ref: containerRef,
1185
- style: {
1193
+ layout: true,
1194
+ animate: {
1186
1195
  width: isScaled ? "100%" : width,
1187
1196
  height: isScaled ? "100%" : height
1188
1197
  },
1189
- className: "rounded-lg bg-surface-raised flex flex-col transition-all duration-300 origin-center",
1198
+ transition: reduced ? { duration: 0 } : {
1199
+ width: { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] },
1200
+ height: { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] },
1201
+ layout: { duration: 0.32, ease: [0.16, 1, 0.3, 1] }
1202
+ },
1203
+ className: [
1204
+ "relative rounded-lg overflow-hidden",
1205
+ // OS-window aesthetic: subtle elevation at rest, lifted shadow
1206
+ // when expanded. No background colour change.
1207
+ isScaled ? "shadow-2xl" : "shadow-md",
1208
+ "transition-shadow duration-300"
1209
+ ].join(" "),
1190
1210
  children: [
1191
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 w-max", children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { placement: "right", title: isScaled ? "Collapse" : "Expand", children: /* @__PURE__ */ jsxRuntime.jsx(
1192
- IconButton,
1211
+ /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { placement: "bottom", title: isScaled ? "Collapse" : "Expand", children: /* @__PURE__ */ jsxRuntime.jsx(
1212
+ "button",
1193
1213
  {
1194
- onClick,
1195
- icon: isScaled ? (
1196
- /* Collapse (arrows-pointing-in) */
1197
- /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "w-5 h-5", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M3.22 3.22a.75.75 0 011.06 0l3.97 3.97V4.5a.75.75 0 011.5 0V9a.75.75 0 01-.75.75H4.5a.75.75 0 010-1.5h2.69L3.22 4.28a.75.75 0 010-1.06zm17.56 0a.75.75 0 010 1.06l-3.97 3.97h2.69a.75.75 0 010 1.5H15a.75.75 0 01-.75-.75V4.5a.75.75 0 011.5 0v2.69l3.97-3.97a.75.75 0 011.06 0zM3.75 15a.75.75 0 01.75-.75H9a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-2.69l-3.97 3.97a.75.75 0 01-1.06-1.06l3.97-3.97H4.5a.75.75 0 01-.75-.75zm10.5 0a.75.75 0 01.75-.75h4.5a.75.75 0 01.75.75 .75.75 0 01-.75.75h-2.69l3.97 3.97a.75.75 0 11-1.06 1.06l-3.97-3.97v2.69a.75.75 0 01-1.5 0V15z", clipRule: "evenodd" }) })
1198
- ) : (
1199
- /* Expand (arrows-pointing-out) */
1200
- /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "w-5 h-5", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M15 3a.75.75 0 01.75-.75h5.25A.75.75 0 0121 3v5.25a.75.75 0 01-1.5 0V4.81l-5.72 5.72a.75.75 0 11-1.06-1.06L18.19 3.75H15.75A.75.75 0 0115 3zM3 15a.75.75 0 01.75-.75h2.44l5.72-5.72a.75.75 0 111.06 1.06l-5.72 5.72v2.44a.75.75 0 01-1.5 0V15.75A.75.75 0 013 15zm0-11.25A.75.75 0 013.75 3h5.25a.75.75 0 010 1.5H4.81l5.72 5.72a.75.75 0 11-1.06 1.06L3.75 5.56V8.25a.75.75 0 01-1.5 0V3.75A.75.75 0 013 3zm18 12a.75.75 0 01-.75.75h-5.25a.75.75 0 010-1.5h2.44l-5.72-5.72a.75.75 0 111.06-1.06l5.72 5.72v-2.44a.75.75 0 011.5 0V15z", clipRule: "evenodd" }) })
1201
- )
1214
+ type: "button",
1215
+ onClick: onToggle,
1216
+ "aria-label": isScaled ? "Collapse container" : "Expand container",
1217
+ "aria-expanded": isScaled,
1218
+ className: [
1219
+ "absolute z-10",
1220
+ TOGGLE_POSITION_CLASS[togglePosition],
1221
+ "w-7 h-7 inline-flex items-center justify-center",
1222
+ "rounded-md bg-surface/80 backdrop-blur-sm border border-border",
1223
+ "text-foreground-secondary hover:text-foreground hover:bg-surface",
1224
+ "shadow-sm transition-colors duration-150",
1225
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
1226
+ ].join(" "),
1227
+ children: isScaled ? collapseIcon ?? /* @__PURE__ */ jsxRuntime.jsx(CollapseIcon, {}) : expandIcon ?? /* @__PURE__ */ jsxRuntime.jsx(ExpandIcon, {})
1202
1228
  }
1203
- ) }) }),
1229
+ ) }),
1204
1230
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrapperClass, children })
1205
1231
  ]
1206
1232
  }
1207
1233
  );
1208
1234
  }
1235
+ function CollapseIcon() {
1236
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 9L4 4M9 9V4M9 9H4M15 9L20 4M15 9V4M15 9H20M9 15L4 20M9 15V20M9 15H4M15 15L20 20M15 15V20M15 15H20" }) });
1237
+ }
1238
+ function ExpandIcon() {
1239
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 8V4h4M20 8V4h-4M4 16v4h4M20 16v4h-4" }) });
1240
+ }
1209
1241
  function GridCard({ item, buttonText = "Open Application", onOpen }) {
1210
1242
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col w-[200px] h-[250px] rounded-lg bg-ice dark:bg-independence items-center justify-between p-2 shadow-2xl", children: [
1211
1243
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-prussian-blue dark:text-white text-lg font-bold text-center h-1/4", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { children: item.title }) }),
@@ -1366,49 +1398,6 @@ function CatalogCarousel({ items, buttonText, onOpen }) {
1366
1398
  function Catalog({ display = "grid", items = [], buttonText, onOpen }) {
1367
1399
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full", children: display === "grid" ? /* @__PURE__ */ jsxRuntime.jsx(CatalogGrid, { items, buttonText, onOpen }) : /* @__PURE__ */ jsxRuntime.jsx(CatalogCarousel, { items, buttonText, onOpen }) });
1368
1400
  }
1369
- function MenuBarItem({ icon, isActive, title, onClick }) {
1370
- return /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { title, placement: "right", children: /* @__PURE__ */ jsxRuntime.jsx(
1371
- "div",
1372
- {
1373
- role: "button",
1374
- "aria-label": title,
1375
- "aria-current": isActive ? "page" : void 0,
1376
- className: `transition duration-300 hover:bg-accent hover:text-accent-fg ${isActive ? "bg-accent text-accent-fg" : "text-foreground-secondary"} rounded-lg p-2 cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-accent`,
1377
- onClick,
1378
- tabIndex: 0,
1379
- onKeyDown: (e) => {
1380
- if (e.key === "Enter" || e.key === " ") {
1381
- e.preventDefault();
1382
- onClick?.();
1383
- }
1384
- },
1385
- children: icon
1386
- }
1387
- ) });
1388
- }
1389
- function MenuBar({ items }) {
1390
- return (
1391
- // `calculated-height` was an orphaned CSS class. Replaced with `h-full`
1392
- // so the MenuBar fills whatever vertical space its parent gives it.
1393
- /* @__PURE__ */ jsxRuntime.jsx(
1394
- "nav",
1395
- {
1396
- "aria-label": "Main navigation",
1397
- className: "w-16 h-full bg-surface-raised rounded-tr-lg rounded-br-lg flex flex-col gap-2 items-center p-2 z-50",
1398
- children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
1399
- MenuBarItem,
1400
- {
1401
- icon: item.icon,
1402
- title: item.title,
1403
- isActive: item.isActive,
1404
- onClick: item.onClick
1405
- },
1406
- item.key
1407
- ))
1408
- }
1409
- )
1410
- );
1411
- }
1412
1401
  function ContextMenu({ items, children }) {
1413
1402
  return /* @__PURE__ */ jsxRuntime.jsxs(ContextMenuPrimitive__namespace.Root, { children: [
1414
1403
  /* @__PURE__ */ jsxRuntime.jsx(ContextMenuPrimitive__namespace.Trigger, { asChild: true, children }),
@@ -1730,7 +1719,7 @@ var SearchInput = React8__default.default.forwardRef(function SearchInput2({
1730
1719
  style: style ?? {},
1731
1720
  children: [
1732
1721
  label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium ml-1 max-content text-foreground", htmlFor, children: label }),
1733
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-surface text-foreground flex items-center gap-1 rounded-lg border border-border pr-2 focus-within:ring-2 focus-within:ring-accent transition-colors", children: [
1722
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-surface text-foreground flex items-center gap-1 rounded-lg border border-border pr-2 focus-within:border-transparent focus-within:ring-2 focus-within:ring-accent transition-colors", children: [
1734
1723
  /* @__PURE__ */ jsxRuntime.jsx(
1735
1724
  "input",
1736
1725
  {
@@ -1777,7 +1766,8 @@ function Dropdown({
1777
1766
  htmlFor,
1778
1767
  items = [],
1779
1768
  labelStyle = {},
1780
- placeholder
1769
+ placeholder,
1770
+ showSelectedCount = false
1781
1771
  }) {
1782
1772
  const [open, setOpen] = React8.useState(false);
1783
1773
  const [selectedItems, setSelectedItems] = React8.useState([]);
@@ -1840,7 +1830,7 @@ function Dropdown({
1840
1830
  "aria-invalid": hasError || void 0,
1841
1831
  "aria-describedby": hasError ? errorId : void 0,
1842
1832
  style,
1843
- className: `flex items-center justify-between relative h-9 rounded-lg border border-border cursor-pointer select-none focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${disabled ? "cursor-not-allowed bg-surface-raised text-foreground-muted" : "bg-surface text-foreground"} ${hasError ? "border-status-error" : ""}`,
1833
+ className: `flex items-center justify-between relative h-9 rounded-lg border border-border cursor-pointer select-none focus:outline-none focus-visible:border-transparent focus-visible:ring-2 focus-visible:ring-accent ${disabled ? "cursor-not-allowed bg-surface-raised text-foreground-muted" : "bg-surface text-foreground"} ${hasError ? "border-status-error" : ""}`,
1844
1834
  tabIndex: disabled ? -1 : 0,
1845
1835
  onKeyDown: (e) => {
1846
1836
  if (disabled) return;
@@ -1863,7 +1853,7 @@ function Dropdown({
1863
1853
  },
1864
1854
  String(val)
1865
1855
  )),
1866
- value.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(DropdownPill, { value: `+${value.length - 1} more` })
1856
+ showSelectedCount && value.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(DropdownPill, { value: `+${value.length - 1} more` })
1867
1857
  ] }) : /* @__PURE__ */ jsxRuntime.jsx(DropdownPill, { value: innerItems.find((it) => it.key === value)?.label })
1868
1858
  }
1869
1859
  ),
@@ -2662,10 +2652,13 @@ function ThemeProvider({
2662
2652
  ] });
2663
2653
  }
2664
2654
  var SHIMMER = [
2665
- "animate-shimmer rounded-sm",
2666
- "bg-[length:400%_100%]",
2667
- "bg-gradient-to-r",
2668
- "from-border via-border-strong/40 to-border"
2655
+ "relative overflow-hidden rounded-sm bg-surface-raised",
2656
+ 'before:absolute before:inset-0 before:content-[""]',
2657
+ "before:bg-gradient-to-r before:from-transparent before:via-white/30 before:to-transparent",
2658
+ "before:animate-[shimmer_1.6s_linear_infinite]",
2659
+ // Respect prefers-reduced-motion — the resting bg-surface-raised is still
2660
+ // a perfectly legible placeholder for users who have animations off.
2661
+ "motion-reduce:before:hidden"
2669
2662
  ].join(" ");
2670
2663
  function SkeletonBox({ width, height = 16, radius, className = "", style }) {
2671
2664
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -2803,7 +2796,7 @@ function TextInput({
2803
2796
  id: htmlFor,
2804
2797
  "aria-invalid": hasError || void 0,
2805
2798
  "aria-describedby": hasError ? errorId : void 0,
2806
- className: `${hasError ? "border border-status-error" : "border border-border"} bg-surface text-foreground p-2 h-9 w-60 mt-1 rounded-lg disabled:bg-surface-raised disabled:text-foreground-muted disabled:cursor-not-allowed focus:outline-none focus-visible:ring-2 focus-visible:ring-accent transition-colors`,
2799
+ className: `${hasError ? "border border-status-error" : "border border-border"} bg-surface text-foreground p-2 h-9 w-60 mt-1 rounded-lg disabled:bg-surface-raised disabled:text-foreground-muted disabled:cursor-not-allowed focus:outline-none focus:border-transparent focus:ring-2 focus:ring-accent transition-colors`,
2807
2800
  style: inputStyle ?? {},
2808
2801
  placeholder: placeholder ?? ""
2809
2802
  }
@@ -2879,7 +2872,7 @@ function NumberInput({
2879
2872
  "div",
2880
2873
  {
2881
2874
  style,
2882
- className: `flex items-center rounded-lg border overflow-hidden ${hasError ? "border-status-error" : "border-border"} ${disabled ? "bg-surface-raised text-foreground-muted cursor-not-allowed" : "bg-surface text-foreground"} focus-within:ring-2 focus-within:ring-accent transition-colors`,
2875
+ className: `flex items-center rounded-lg border overflow-hidden ${hasError ? "border-status-error" : "border-border"} ${disabled ? "bg-surface-raised text-foreground-muted cursor-not-allowed" : "bg-surface text-foreground"} focus-within:border-transparent focus-within:ring-2 focus-within:ring-accent transition-colors`,
2883
2876
  children: [
2884
2877
  /* @__PURE__ */ jsxRuntime.jsx(
2885
2878
  "input",
@@ -2979,7 +2972,7 @@ function Password({
2979
2972
  id: htmlFor,
2980
2973
  "aria-invalid": hasError || void 0,
2981
2974
  "aria-describedby": hasError ? errorId : void 0,
2982
- className: `${hasError ? "border border-status-error" : "border border-border"} bg-surface text-foreground p-2 h-9 w-52 mt-1 rounded-lg disabled:bg-surface-raised disabled:text-foreground-muted disabled:cursor-not-allowed focus:outline-none focus-visible:ring-2 focus-visible:ring-accent transition-colors`,
2975
+ className: `${hasError ? "border border-status-error" : "border border-border"} bg-surface text-foreground p-2 h-9 w-52 mt-1 rounded-lg disabled:bg-surface-raised disabled:text-foreground-muted disabled:cursor-not-allowed focus:outline-none focus:border-transparent focus:ring-2 focus:ring-accent transition-colors`,
2983
2976
  style: inputStyle ?? {},
2984
2977
  placeholder: placeholder ?? ""
2985
2978
  }
@@ -3146,7 +3139,7 @@ function AutoComplete({
3146
3139
  children: [
3147
3140
  label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium ml-1 max-content text-foreground", children: label }),
3148
3141
  /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
3149
- /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-surface text-foreground flex items-center gap-1 rounded-lg border border-border pr-2 focus-within:ring-2 focus-within:ring-accent transition-colors", children: [
3142
+ /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-surface text-foreground flex items-center gap-1 rounded-lg border border-border pr-2 focus-within:border-transparent focus-within:ring-2 focus-within:ring-accent transition-colors", children: [
3150
3143
  /* @__PURE__ */ jsxRuntime.jsx(
3151
3144
  "input",
3152
3145
  {
@@ -3347,7 +3340,7 @@ function TreeSelect({
3347
3340
  "aria-invalid": hasError || void 0,
3348
3341
  "aria-describedby": hasError ? errorId : void 0,
3349
3342
  disabled,
3350
- className: `flex items-center justify-between h-9 rounded-lg border ${hasError ? "border-status-error" : "border-border"} px-3 cursor-pointer select-none focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${disabled ? "cursor-not-allowed bg-surface-raised text-foreground-muted" : "bg-surface text-foreground"} ${!style?.width ? "min-w-[240px]" : ""}`,
3343
+ className: `flex items-center justify-between h-9 rounded-lg border ${hasError ? "border-status-error" : "border-border"} px-3 cursor-pointer select-none focus:outline-none focus-visible:border-transparent focus-visible:ring-2 focus-visible:ring-accent ${disabled ? "cursor-not-allowed bg-surface-raised text-foreground-muted" : "bg-surface text-foreground"} ${!style?.width ? "min-w-[240px]" : ""}`,
3351
3344
  children: [
3352
3345
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm truncate text-left", children: selectedNode ? selectedNode.label : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground-muted", children: placeholder }) }),
3353
3346
  /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: `h-4 w-4 flex-shrink-0 transition-transform duration-200 ${open ? "rotate-180" : ""}`, "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) })
@@ -3640,12 +3633,14 @@ function DatePicker({
3640
3633
  const [open, setOpen] = React8.useState(false);
3641
3634
  const [viewMonth, setViewMonth] = React8.useState(() => startOfMonth(value ?? /* @__PURE__ */ new Date()));
3642
3635
  const [focusDate, setFocusDate] = React8.useState(() => value ?? /* @__PURE__ */ new Date());
3636
+ const [view, setView] = React8.useState("days");
3643
3637
  const gridRef = React8.useRef(null);
3644
3638
  React8.useEffect(() => {
3645
3639
  if (!open) return;
3646
3640
  const target = value ?? /* @__PURE__ */ new Date();
3647
3641
  setViewMonth(startOfMonth(target));
3648
3642
  setFocusDate(target);
3643
+ setView("days");
3649
3644
  }, [open, value]);
3650
3645
  React8.useEffect(() => {
3651
3646
  if (!open) return;
@@ -3734,7 +3729,7 @@ function DatePicker({
3734
3729
  "aria-describedby": hasError ? errorId : void 0,
3735
3730
  "aria-haspopup": "dialog",
3736
3731
  "aria-expanded": open,
3737
- className: `flex items-center justify-between h-9 rounded-lg border px-3 cursor-pointer select-none focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${hasError ? "border-status-error" : "border-border"} ${disabled ? "cursor-not-allowed bg-surface-raised text-foreground-muted" : "bg-surface text-foreground"} ${!style?.width ? "min-w-[200px]" : ""}`,
3732
+ className: `flex items-center justify-between h-9 rounded-lg border px-3 cursor-pointer select-none focus:outline-none focus-visible:border-transparent focus-visible:ring-2 focus-visible:ring-accent ${hasError ? "border-status-error" : "border-border"} ${disabled ? "cursor-not-allowed bg-surface-raised text-foreground-muted" : "bg-surface text-foreground"} ${!style?.width ? "min-w-[200px]" : ""}`,
3738
3733
  children: [
3739
3734
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-sm truncate ${displayValue ? "" : "text-foreground-muted"}`, children: displayValue || placeholder }),
3740
3735
  /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, {})
@@ -3756,29 +3751,89 @@ function DatePicker({
3756
3751
  "button",
3757
3752
  {
3758
3753
  type: "button",
3759
- onClick: () => setViewMonth(addMonths(viewMonth, -1)),
3760
- "aria-label": "Previous month",
3754
+ onClick: () => {
3755
+ if (view === "days") setViewMonth(addMonths(viewMonth, -1));
3756
+ else if (view === "months") setViewMonth(new Date(viewMonth.getFullYear() - 1, viewMonth.getMonth(), 1));
3757
+ else setViewMonth(new Date(viewMonth.getFullYear() - 10, viewMonth.getMonth(), 1));
3758
+ },
3759
+ "aria-label": view === "days" ? "Previous month" : view === "months" ? "Previous year" : "Previous decade",
3761
3760
  className: "w-7 h-7 inline-flex items-center justify-center rounded-md hover:bg-surface-raised focus:outline-none focus-visible:ring-2 focus-visible:ring-accent transition-colors",
3762
3761
  children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeft, {})
3763
3762
  }
3764
3763
  ),
3765
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm font-semibold select-none", children: [
3766
- MONTH_NAMES[viewMonth.getMonth()],
3767
- " ",
3768
- viewMonth.getFullYear()
3769
- ] }),
3764
+ /* @__PURE__ */ jsxRuntime.jsxs(
3765
+ "button",
3766
+ {
3767
+ type: "button",
3768
+ onClick: () => {
3769
+ if (view === "days") setView("months");
3770
+ else if (view === "months") setView("years");
3771
+ },
3772
+ disabled: view === "years",
3773
+ "aria-label": "Change view",
3774
+ className: "text-sm font-semibold select-none rounded-md px-2 py-0.5 hover:bg-surface-raised focus:outline-none focus-visible:ring-2 focus-visible:ring-accent transition-colors disabled:cursor-default disabled:hover:bg-transparent",
3775
+ children: [
3776
+ view === "days" && `${MONTH_NAMES[viewMonth.getMonth()]} ${viewMonth.getFullYear()}`,
3777
+ view === "months" && `${viewMonth.getFullYear()}`,
3778
+ view === "years" && (() => {
3779
+ const decadeStart = Math.floor(viewMonth.getFullYear() / 10) * 10;
3780
+ return `${decadeStart} \u2013 ${decadeStart + 11}`;
3781
+ })()
3782
+ ]
3783
+ }
3784
+ ),
3770
3785
  /* @__PURE__ */ jsxRuntime.jsx(
3771
3786
  "button",
3772
3787
  {
3773
3788
  type: "button",
3774
- onClick: () => setViewMonth(addMonths(viewMonth, 1)),
3775
- "aria-label": "Next month",
3789
+ onClick: () => {
3790
+ if (view === "days") setViewMonth(addMonths(viewMonth, 1));
3791
+ else if (view === "months") setViewMonth(new Date(viewMonth.getFullYear() + 1, viewMonth.getMonth(), 1));
3792
+ else setViewMonth(new Date(viewMonth.getFullYear() + 10, viewMonth.getMonth(), 1));
3793
+ },
3794
+ "aria-label": view === "days" ? "Next month" : view === "months" ? "Next year" : "Next decade",
3776
3795
  className: "w-7 h-7 inline-flex items-center justify-center rounded-md hover:bg-surface-raised focus:outline-none focus-visible:ring-2 focus-visible:ring-accent transition-colors",
3777
3796
  children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRight3, {})
3778
3797
  }
3779
3798
  )
3780
3799
  ] }),
3781
- /* @__PURE__ */ jsxRuntime.jsxs(
3800
+ view === "months" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-1 min-w-[224px]", children: MONTH_NAMES.map((name, idx) => {
3801
+ const isCurrent = value && value.getFullYear() === viewMonth.getFullYear() && value.getMonth() === idx;
3802
+ return /* @__PURE__ */ jsxRuntime.jsx(
3803
+ "button",
3804
+ {
3805
+ type: "button",
3806
+ onClick: () => {
3807
+ setViewMonth(new Date(viewMonth.getFullYear(), idx, 1));
3808
+ setView("days");
3809
+ },
3810
+ className: `px-2 py-2 rounded-md text-xs font-medium transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${isCurrent ? "bg-accent text-accent-fg" : "text-foreground hover:bg-surface-raised"}`,
3811
+ children: name.slice(0, 3)
3812
+ },
3813
+ name
3814
+ );
3815
+ }) }),
3816
+ view === "years" && (() => {
3817
+ const decadeStart = Math.floor(viewMonth.getFullYear() / 10) * 10;
3818
+ const years = Array.from({ length: 12 }, (_, i) => decadeStart + i);
3819
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-1 min-w-[224px]", children: years.map((y) => {
3820
+ const isCurrent = value?.getFullYear() === y;
3821
+ return /* @__PURE__ */ jsxRuntime.jsx(
3822
+ "button",
3823
+ {
3824
+ type: "button",
3825
+ onClick: () => {
3826
+ setViewMonth(new Date(y, viewMonth.getMonth(), 1));
3827
+ setView("months");
3828
+ },
3829
+ className: `px-2 py-2 rounded-md text-xs font-medium transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${isCurrent ? "bg-accent text-accent-fg" : "text-foreground hover:bg-surface-raised"}`,
3830
+ children: y
3831
+ },
3832
+ y
3833
+ );
3834
+ }) });
3835
+ })(),
3836
+ view === "days" && /* @__PURE__ */ jsxRuntime.jsxs(
3782
3837
  "table",
3783
3838
  {
3784
3839
  ref: gridRef,
@@ -3886,7 +3941,6 @@ exports.Checkbox = Checkbox;
3886
3941
  exports.ContextMenu = ContextMenu;
3887
3942
  exports.Drawer = Drawer;
3888
3943
  exports.Dropdown = Dropdown;
3889
- exports.DropdownPill = DropdownPill;
3890
3944
  exports.FadingBase = FadingBase;
3891
3945
  exports.FileInput = FileInput;
3892
3946
  exports.GridCard = GridCard;
@@ -3894,8 +3948,6 @@ exports.Icon = icons_default;
3894
3948
  exports.IconButton = IconButton;
3895
3949
  exports.List = List2;
3896
3950
  exports.LoadingSpinner = LoadingSpinner;
3897
- exports.MenuBar = MenuBar;
3898
- exports.MenuBarItem = MenuBarItem;
3899
3951
  exports.Modal = Modal;
3900
3952
  exports.NotificationProvider = NotificationProvider;
3901
3953
  exports.NumberInput = NumberInput;