@geomak/ui 5.0.2 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ export { colors_default as COLORS, PALETTE as palette, semanticTokens, vars } fr
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import React8, { createContext, useState, useEffect, useMemo, useCallback, useContext, useRef, useId, useLayoutEffect } from 'react';
5
5
  import { createPortal } from 'react-dom';
6
+ import * as AvatarPrimitive from '@radix-ui/react-avatar';
6
7
  import * as Dialog from '@radix-ui/react-dialog';
7
8
  import { useReducedMotion, AnimatePresence, motion } from 'framer-motion';
8
9
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
@@ -185,6 +186,417 @@ function Portal({ children, target }) {
185
186
  }, [target]);
186
187
  return resolved ? createPortal(children, resolved) : null;
187
188
  }
189
+ var SPACING_MAP = {
190
+ "none": "0",
191
+ "xs": "1",
192
+ "sm": "2",
193
+ "md": "4",
194
+ "lg": "6",
195
+ "xl": "8",
196
+ "2xl": "12"
197
+ };
198
+ var padding = (s, axis = "p") => s == null ? "" : `${axis}-${SPACING_MAP[s]}`;
199
+ var margin = (s, axis = "m") => s == null ? "" : `${axis}-${SPACING_MAP[s]}`;
200
+ var BG_MAP = {
201
+ "none": "",
202
+ "background": "bg-background",
203
+ "surface": "bg-surface",
204
+ "surface-raised": "bg-surface-raised",
205
+ "accent": "bg-accent text-accent-fg"
206
+ };
207
+ var BORDER_MAP = {
208
+ "none": "",
209
+ "border": "border border-border",
210
+ "border-strong": "border border-border-strong",
211
+ "accent": "border border-accent",
212
+ "status-error": "border border-status-error"
213
+ };
214
+ var RADIUS_MAP = {
215
+ "none": "rounded-none",
216
+ "sm": "rounded-sm",
217
+ "md": "rounded-md",
218
+ "lg": "rounded-lg",
219
+ "xl": "rounded-xl",
220
+ "2xl": "rounded-2xl",
221
+ "full": "rounded-full"
222
+ };
223
+ var SHADOW_MAP = {
224
+ "none": "",
225
+ "sm": "shadow-sm",
226
+ "md": "shadow-md",
227
+ "lg": "shadow-lg",
228
+ "xl": "shadow-xl"
229
+ };
230
+ function Box({
231
+ as,
232
+ p,
233
+ px: px2,
234
+ py,
235
+ pt,
236
+ pr,
237
+ pb,
238
+ pl,
239
+ m,
240
+ mx,
241
+ my,
242
+ mt,
243
+ mr,
244
+ mb,
245
+ ml,
246
+ background = "none",
247
+ border = "none",
248
+ radius,
249
+ shadow = "none",
250
+ width,
251
+ height,
252
+ onClick,
253
+ className = "",
254
+ style,
255
+ children
256
+ }) {
257
+ const Element = as ?? "div";
258
+ return /* @__PURE__ */ jsx(
259
+ Element,
260
+ {
261
+ onClick,
262
+ className: [
263
+ padding(p, "p"),
264
+ padding(px2, "px"),
265
+ padding(py, "py"),
266
+ padding(pt, "pt"),
267
+ padding(pr, "pr"),
268
+ padding(pb, "pb"),
269
+ padding(pl, "pl"),
270
+ margin(m, "m"),
271
+ margin(mx, "mx"),
272
+ margin(my, "my"),
273
+ margin(mt, "mt"),
274
+ margin(mr, "mr"),
275
+ margin(mb, "mb"),
276
+ margin(ml, "ml"),
277
+ BG_MAP[background],
278
+ BORDER_MAP[border],
279
+ radius ? RADIUS_MAP[radius] : "",
280
+ SHADOW_MAP[shadow],
281
+ className
282
+ ].filter(Boolean).join(" "),
283
+ style: {
284
+ width: typeof width === "number" ? `${width}px` : width,
285
+ height: typeof height === "number" ? `${height}px` : height,
286
+ ...style
287
+ },
288
+ children
289
+ }
290
+ );
291
+ }
292
+ var GAP_MAP = {
293
+ "none": "gap-0",
294
+ "xs": "gap-1",
295
+ "sm": "gap-2",
296
+ "md": "gap-4",
297
+ "lg": "gap-6",
298
+ "xl": "gap-8",
299
+ "2xl": "gap-12"
300
+ };
301
+ var DIRECTION_CLASS = {
302
+ "row": "flex-row",
303
+ "row-reverse": "flex-row-reverse",
304
+ "col": "flex-col",
305
+ "col-reverse": "flex-col-reverse"
306
+ };
307
+ var ALIGN_CLASS = {
308
+ start: "items-start",
309
+ center: "items-center",
310
+ end: "items-end",
311
+ stretch: "items-stretch",
312
+ baseline: "items-baseline"
313
+ };
314
+ var JUSTIFY_CLASS = {
315
+ start: "justify-start",
316
+ center: "justify-center",
317
+ end: "justify-end",
318
+ between: "justify-between",
319
+ around: "justify-around",
320
+ evenly: "justify-evenly"
321
+ };
322
+ var WRAP_CLASS = {
323
+ "nowrap": "flex-nowrap",
324
+ "wrap": "flex-wrap",
325
+ "wrap-reverse": "flex-wrap-reverse"
326
+ };
327
+ function Flex({
328
+ direction = "row",
329
+ align,
330
+ justify,
331
+ wrap,
332
+ gap,
333
+ inline,
334
+ className = "",
335
+ ...boxProps
336
+ }) {
337
+ return /* @__PURE__ */ jsx(
338
+ Box,
339
+ {
340
+ ...boxProps,
341
+ className: [
342
+ inline ? "inline-flex" : "flex",
343
+ DIRECTION_CLASS[direction],
344
+ align ? ALIGN_CLASS[align] : "",
345
+ justify ? JUSTIFY_CLASS[justify] : "",
346
+ wrap ? WRAP_CLASS[wrap] : "",
347
+ gap ? GAP_MAP[gap] : "",
348
+ className
349
+ ].filter(Boolean).join(" ")
350
+ }
351
+ );
352
+ }
353
+ var GAP_MAP2 = {
354
+ "none": "gap-0",
355
+ "xs": "gap-1",
356
+ "sm": "gap-2",
357
+ "md": "gap-4",
358
+ "lg": "gap-6",
359
+ "xl": "gap-8",
360
+ "2xl": "gap-12"
361
+ };
362
+ var COL_MAP = {
363
+ 1: "grid-cols-1",
364
+ 2: "grid-cols-2",
365
+ 3: "grid-cols-3",
366
+ 4: "grid-cols-4",
367
+ 5: "grid-cols-5",
368
+ 6: "grid-cols-6",
369
+ 7: "grid-cols-7",
370
+ 8: "grid-cols-8",
371
+ 9: "grid-cols-9",
372
+ 10: "grid-cols-10",
373
+ 11: "grid-cols-11",
374
+ 12: "grid-cols-12"
375
+ };
376
+ var ROW_MAP = {
377
+ 1: "grid-rows-1",
378
+ 2: "grid-rows-2",
379
+ 3: "grid-rows-3",
380
+ 4: "grid-rows-4",
381
+ 5: "grid-rows-5",
382
+ 6: "grid-rows-6"
383
+ };
384
+ var ALIGN_CLASS2 = {
385
+ start: "items-start",
386
+ center: "items-center",
387
+ end: "items-end",
388
+ stretch: "items-stretch"
389
+ };
390
+ var JUSTIFY_CLASS2 = {
391
+ start: "justify-items-start",
392
+ center: "justify-items-center",
393
+ end: "justify-items-end",
394
+ stretch: "justify-items-stretch"
395
+ };
396
+ function Grid2({
397
+ cols,
398
+ rows,
399
+ gap,
400
+ gapX,
401
+ gapY,
402
+ align,
403
+ justify,
404
+ className = "",
405
+ style,
406
+ ...boxProps
407
+ }) {
408
+ const colClass = typeof cols === "number" ? COL_MAP[cols] ?? "" : "";
409
+ const rowClass = typeof rows === "number" ? ROW_MAP[rows] ?? "" : "";
410
+ const inlineCols = typeof cols === "string" ? cols : void 0;
411
+ const inlineRows = typeof rows === "string" ? rows : void 0;
412
+ return /* @__PURE__ */ jsx(
413
+ Box,
414
+ {
415
+ ...boxProps,
416
+ className: [
417
+ "grid",
418
+ colClass,
419
+ rowClass,
420
+ gap ? GAP_MAP2[gap] : "",
421
+ gapX ? GAP_MAP2[gapX].replace("gap-", "gap-x-") : "",
422
+ gapY ? GAP_MAP2[gapY].replace("gap-", "gap-y-") : "",
423
+ align ? ALIGN_CLASS2[align] : "",
424
+ justify ? JUSTIFY_CLASS2[justify] : "",
425
+ className
426
+ ].filter(Boolean).join(" "),
427
+ style: {
428
+ gridTemplateColumns: inlineCols,
429
+ gridTemplateRows: inlineRows,
430
+ ...style
431
+ }
432
+ }
433
+ );
434
+ }
435
+ var SIZE_PX = {
436
+ xs: 20,
437
+ sm: 28,
438
+ md: 36,
439
+ lg: 48,
440
+ xl: 64
441
+ };
442
+ var TEXT_CLASS = {
443
+ xs: "text-[10px]",
444
+ sm: "text-xs",
445
+ md: "text-sm",
446
+ lg: "text-base",
447
+ xl: "text-lg"
448
+ };
449
+ var STATUS_CLASS = {
450
+ online: "bg-status-success",
451
+ offline: "bg-foreground-muted",
452
+ away: "bg-status-warning",
453
+ busy: "bg-status-error"
454
+ };
455
+ function Avatar({
456
+ src,
457
+ alt,
458
+ fallback,
459
+ size = "md",
460
+ shape = "circle",
461
+ status,
462
+ className = ""
463
+ }) {
464
+ const px2 = SIZE_PX[size];
465
+ const initialsFallback = (() => {
466
+ if (fallback) return fallback;
467
+ if (alt) {
468
+ const parts = alt.trim().split(/\s+/).slice(0, 2);
469
+ const initials = parts.map((p) => p[0]?.toUpperCase() ?? "").join("");
470
+ if (initials) return initials;
471
+ }
472
+ return /* @__PURE__ */ jsx(PersonSilhouette, {});
473
+ })();
474
+ return /* @__PURE__ */ jsxs(
475
+ "span",
476
+ {
477
+ className: `relative inline-block flex-shrink-0 ${className}`,
478
+ style: { width: px2, height: px2 },
479
+ children: [
480
+ /* @__PURE__ */ jsxs(
481
+ AvatarPrimitive.Root,
482
+ {
483
+ className: `flex w-full h-full items-center justify-center overflow-hidden bg-surface-raised text-foreground-secondary select-none ${shape === "circle" ? "rounded-full" : "rounded-md"}`,
484
+ children: [
485
+ src && /* @__PURE__ */ jsx(
486
+ AvatarPrimitive.Image,
487
+ {
488
+ src,
489
+ alt: alt ?? "",
490
+ className: "h-full w-full object-cover"
491
+ }
492
+ ),
493
+ /* @__PURE__ */ jsx(
494
+ AvatarPrimitive.Fallback,
495
+ {
496
+ delayMs: src ? 300 : 0,
497
+ className: `flex h-full w-full items-center justify-center font-semibold ${TEXT_CLASS[size]}`,
498
+ children: initialsFallback
499
+ }
500
+ )
501
+ ]
502
+ }
503
+ ),
504
+ status && /* @__PURE__ */ jsx(
505
+ "span",
506
+ {
507
+ className: `absolute bottom-0 right-0 block rounded-full ring-2 ring-background ${STATUS_CLASS[status]}`,
508
+ style: {
509
+ width: Math.max(6, Math.round(px2 / 4)),
510
+ height: Math.max(6, Math.round(px2 / 4))
511
+ },
512
+ "aria-label": `Status: ${status}`,
513
+ role: "status"
514
+ }
515
+ )
516
+ ]
517
+ }
518
+ );
519
+ }
520
+ function PersonSilhouette() {
521
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", className: "w-[60%] h-[60%]", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M12 12a4 4 0 100-8 4 4 0 000 8zM4 20a8 8 0 1116 0H4z" }) });
522
+ }
523
+ var VARIANT_CLASS = {
524
+ display: "text-3xl font-bold leading-tight tracking-tight",
525
+ h1: "text-2xl font-bold leading-tight tracking-tight",
526
+ h2: "text-xl font-semibold leading-snug tracking-tight",
527
+ h3: "text-lg font-semibold leading-snug",
528
+ h4: "text-base font-semibold leading-snug",
529
+ subtitle: "text-sm font-medium leading-snug",
530
+ body: "text-sm leading-normal",
531
+ caption: "text-xs leading-normal",
532
+ overline: "text-[10px] font-semibold leading-normal uppercase tracking-wider",
533
+ code: "text-xs leading-normal font-mono bg-surface-raised text-foreground rounded px-1 py-0.5"
534
+ };
535
+ var DEFAULT_ELEMENT = {
536
+ display: "h1",
537
+ h1: "h1",
538
+ h2: "h2",
539
+ h3: "h3",
540
+ h4: "h4",
541
+ subtitle: "p",
542
+ body: "p",
543
+ caption: "span",
544
+ overline: "span",
545
+ code: "code"
546
+ };
547
+ var COLOR_CLASS = {
548
+ "foreground": "text-foreground",
549
+ "foreground-secondary": "text-foreground-secondary",
550
+ "foreground-muted": "text-foreground-muted",
551
+ "accent": "text-accent",
552
+ "status-error": "text-status-error",
553
+ "status-warning": "text-status-warning",
554
+ "status-success": "text-status-success",
555
+ "status-info": "text-status-info",
556
+ "inherit": ""
557
+ };
558
+ var WEIGHT_CLASS = {
559
+ normal: "font-normal",
560
+ medium: "font-medium",
561
+ semibold: "font-semibold",
562
+ bold: "font-bold"
563
+ };
564
+ var ALIGN_CLASS3 = {
565
+ left: "text-left",
566
+ center: "text-center",
567
+ right: "text-right",
568
+ justify: "text-justify"
569
+ };
570
+ function Typography({
571
+ variant = "body",
572
+ as,
573
+ color = "inherit",
574
+ weight,
575
+ align,
576
+ truncate,
577
+ muted,
578
+ className = "",
579
+ style,
580
+ children
581
+ }) {
582
+ const Element = as ?? DEFAULT_ELEMENT[variant];
583
+ return /* @__PURE__ */ jsx(
584
+ Element,
585
+ {
586
+ className: [
587
+ VARIANT_CLASS[variant],
588
+ COLOR_CLASS[color],
589
+ weight ? WEIGHT_CLASS[weight] : "",
590
+ align ? ALIGN_CLASS3[align] : "",
591
+ truncate ? "truncate" : "",
592
+ muted ? "opacity-60" : "",
593
+ className
594
+ ].filter(Boolean).join(" "),
595
+ style,
596
+ children
597
+ }
598
+ );
599
+ }
188
600
  function IconButton({
189
601
  icon,
190
602
  onClick,
@@ -967,6 +1379,9 @@ function useNotification() {
967
1379
  };
968
1380
  }
969
1381
  var SIZE_MAP = {
1382
+ // xs is sized to fit beside button text (~14px) — async AutoComplete,
1383
+ // Button loading prop, inline status badges, etc.
1384
+ 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]" },
970
1385
  sm: { outer: "w-8 h-8", inner: "w-4 h-4", dot: "w-1 h-1", stroke: "border-2", text: "text-xs" },
971
1386
  md: { outer: "w-20 h-20", inner: "w-12 h-12", dot: "w-2 h-2", stroke: "border-[3px]", text: "text-2xl" },
972
1387
  lg: { outer: "w-32 h-32", inner: "w-20 h-20", dot: "w-3 h-3", stroke: "border-4", text: "text-4xl" }
@@ -1102,78 +1517,130 @@ function FadingBase({
1102
1517
  )
1103
1518
  );
1104
1519
  }
1105
- function List2({ items, onItemClick, activeKey }) {
1106
- return /* @__PURE__ */ jsx("div", { role: "listbox", children: items.map((item) => (
1107
- // tabIndex + Enter/Space onKeyDown makes each option
1108
- // keyboard-activatable. Previously the items were only mouse-
1109
- // clickable — keyboard-only users couldn't select anything.
1110
- /* @__PURE__ */ jsx(
1520
+ var DENSITY_PADDING = {
1521
+ "compact": "py-1.5 px-2",
1522
+ "comfortable": "py-2.5 px-3",
1523
+ "spacious": "py-3.5 px-4"
1524
+ };
1525
+ function List2({
1526
+ items,
1527
+ onItemClick,
1528
+ activeKey,
1529
+ density = "comfortable"
1530
+ }) {
1531
+ return /* @__PURE__ */ jsx("div", { role: "listbox", className: "flex flex-col", children: items.map((item) => {
1532
+ const isActive = activeKey === item.key;
1533
+ const isDisabled = !!item.disabled;
1534
+ return /* @__PURE__ */ jsxs(
1111
1535
  "div",
1112
1536
  {
1113
1537
  role: "option",
1114
- "aria-selected": activeKey === item.key,
1115
- tabIndex: 0,
1116
- className: `hover:bg-surface-raised cursor-pointer p-3 border-b border-border transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${activeKey === item.key ? "bg-surface-raised text-foreground" : "text-foreground-secondary"}`,
1117
- onClick: () => onItemClick(item),
1538
+ "aria-selected": isActive,
1539
+ "aria-disabled": isDisabled || void 0,
1540
+ tabIndex: isDisabled ? -1 : 0,
1541
+ onClick: () => !isDisabled && onItemClick(item),
1118
1542
  onKeyDown: (e) => {
1543
+ if (isDisabled) return;
1119
1544
  if (e.key === "Enter" || e.key === " ") {
1120
1545
  e.preventDefault();
1121
1546
  onItemClick(item);
1122
1547
  }
1123
1548
  },
1124
- children: item.label
1549
+ className: [
1550
+ "flex items-center gap-3 cursor-pointer border-b border-border transition-colors duration-150",
1551
+ DENSITY_PADDING[density],
1552
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-inset",
1553
+ isDisabled ? "opacity-50 cursor-not-allowed" : isActive ? "bg-surface-raised text-foreground" : "text-foreground-secondary hover:bg-surface-raised hover:text-foreground"
1554
+ ].join(" "),
1555
+ children: [
1556
+ item.avatar && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: item.avatar }),
1557
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
1558
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-foreground truncate", children: item.label }),
1559
+ item.description && /* @__PURE__ */ jsx("div", { className: "text-xs text-foreground-secondary mt-0.5 truncate", children: item.description })
1560
+ ] }),
1561
+ item.trailing && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-foreground-muted", children: item.trailing })
1562
+ ]
1125
1563
  },
1126
1564
  item.key
1127
- )
1128
- )) });
1565
+ );
1566
+ }) });
1129
1567
  }
1568
+ var TOGGLE_POSITION_CLASS = {
1569
+ "top-left": "top-2 left-2",
1570
+ "top-right": "top-2 right-2",
1571
+ "bottom-left": "bottom-2 left-2",
1572
+ "bottom-right": "bottom-2 right-2"
1573
+ };
1130
1574
  function ScalableContainer({
1131
- width,
1132
- height,
1575
+ width = "100%",
1576
+ height = "auto",
1133
1577
  children,
1134
- assignClassOnClick
1578
+ assignClassOnClick,
1579
+ expandIcon,
1580
+ collapseIcon,
1581
+ togglePosition = "top-right"
1135
1582
  }) {
1136
1583
  const containerRef = useRef(null);
1137
1584
  const [isScaled, setScaled] = useState(false);
1138
- const [wrapperClass, setWrapperClass] = useState("");
1139
- const onClick = () => {
1585
+ const reduced = useReducedMotion();
1586
+ const onToggle = () => {
1140
1587
  const next = !isScaled;
1141
1588
  setScaled(next);
1142
- setTimeout(() => {
1143
- containerRef.current?.scrollIntoView({ behavior: "smooth" });
1144
- if (assignClassOnClick) {
1145
- setWrapperClass(next ? assignClassOnClick : "");
1146
- }
1147
- }, 200);
1589
+ requestAnimationFrame(() => containerRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" }));
1148
1590
  };
1591
+ const wrapperClass = isScaled ? assignClassOnClick : void 0;
1149
1592
  return /* @__PURE__ */ jsxs(
1150
- "div",
1593
+ motion.div,
1151
1594
  {
1152
1595
  ref: containerRef,
1153
- style: {
1596
+ layout: true,
1597
+ animate: {
1154
1598
  width: isScaled ? "100%" : width,
1155
1599
  height: isScaled ? "100%" : height
1156
1600
  },
1157
- className: "rounded-lg bg-surface-raised flex flex-col transition-all duration-300 origin-center",
1601
+ transition: reduced ? { duration: 0 } : {
1602
+ width: { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] },
1603
+ height: { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] },
1604
+ layout: { duration: 0.32, ease: [0.16, 1, 0.3, 1] }
1605
+ },
1606
+ className: [
1607
+ "relative rounded-lg overflow-hidden",
1608
+ // OS-window aesthetic: subtle elevation at rest, lifted shadow
1609
+ // when expanded. No background colour change.
1610
+ isScaled ? "shadow-2xl" : "shadow-md",
1611
+ "transition-shadow duration-300"
1612
+ ].join(" "),
1158
1613
  children: [
1159
- /* @__PURE__ */ jsx("div", { className: "p-2 w-max", children: /* @__PURE__ */ jsx(Tooltip, { placement: "right", title: isScaled ? "Collapse" : "Expand", children: /* @__PURE__ */ jsx(
1160
- IconButton,
1614
+ /* @__PURE__ */ jsx(Tooltip, { placement: "bottom", title: isScaled ? "Collapse" : "Expand", children: /* @__PURE__ */ jsx(
1615
+ "button",
1161
1616
  {
1162
- onClick,
1163
- icon: isScaled ? (
1164
- /* Collapse (arrows-pointing-in) */
1165
- /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "w-5 h-5", children: /* @__PURE__ */ 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" }) })
1166
- ) : (
1167
- /* Expand (arrows-pointing-out) */
1168
- /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "w-5 h-5", children: /* @__PURE__ */ 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" }) })
1169
- )
1617
+ type: "button",
1618
+ onClick: onToggle,
1619
+ "aria-label": isScaled ? "Collapse container" : "Expand container",
1620
+ "aria-expanded": isScaled,
1621
+ className: [
1622
+ "absolute z-10",
1623
+ TOGGLE_POSITION_CLASS[togglePosition],
1624
+ "w-7 h-7 inline-flex items-center justify-center",
1625
+ "rounded-md bg-surface/80 backdrop-blur-sm border border-border",
1626
+ "text-foreground-secondary hover:text-foreground hover:bg-surface",
1627
+ "shadow-sm transition-colors duration-150",
1628
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
1629
+ ].join(" "),
1630
+ children: isScaled ? collapseIcon ?? /* @__PURE__ */ jsx(CollapseIcon, {}) : expandIcon ?? /* @__PURE__ */ jsx(ExpandIcon, {})
1170
1631
  }
1171
- ) }) }),
1632
+ ) }),
1172
1633
  /* @__PURE__ */ jsx("div", { className: wrapperClass, children })
1173
1634
  ]
1174
1635
  }
1175
1636
  );
1176
1637
  }
1638
+ function CollapseIcon() {
1639
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 9L4 4M9 9V4M9 9H4M15 9L20 4M15 9V4M15 9H20M9 15L4 20M9 15V20M9 15H4M15 15L20 20M15 15V20M15 15H20" }) });
1640
+ }
1641
+ function ExpandIcon() {
1642
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 8V4h4M20 8V4h-4M4 16v4h4M20 16v4h-4" }) });
1643
+ }
1177
1644
  function GridCard({ item, buttonText = "Open Application", onOpen }) {
1178
1645
  return /* @__PURE__ */ 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: [
1179
1646
  /* @__PURE__ */ jsx("div", { className: "text-prussian-blue dark:text-white text-lg font-bold text-center h-1/4", children: /* @__PURE__ */ jsx("h2", { children: item.title }) }),
@@ -1334,49 +1801,6 @@ function CatalogCarousel({ items, buttonText, onOpen }) {
1334
1801
  function Catalog({ display = "grid", items = [], buttonText, onOpen }) {
1335
1802
  return /* @__PURE__ */ jsx("div", { className: "w-full h-full", children: display === "grid" ? /* @__PURE__ */ jsx(CatalogGrid, { items, buttonText, onOpen }) : /* @__PURE__ */ jsx(CatalogCarousel, { items, buttonText, onOpen }) });
1336
1803
  }
1337
- function MenuBarItem({ icon, isActive, title, onClick }) {
1338
- return /* @__PURE__ */ jsx(Tooltip, { title, placement: "right", children: /* @__PURE__ */ jsx(
1339
- "div",
1340
- {
1341
- role: "button",
1342
- "aria-label": title,
1343
- "aria-current": isActive ? "page" : void 0,
1344
- 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`,
1345
- onClick,
1346
- tabIndex: 0,
1347
- onKeyDown: (e) => {
1348
- if (e.key === "Enter" || e.key === " ") {
1349
- e.preventDefault();
1350
- onClick?.();
1351
- }
1352
- },
1353
- children: icon
1354
- }
1355
- ) });
1356
- }
1357
- function MenuBar({ items }) {
1358
- return (
1359
- // `calculated-height` was an orphaned CSS class. Replaced with `h-full`
1360
- // so the MenuBar fills whatever vertical space its parent gives it.
1361
- /* @__PURE__ */ jsx(
1362
- "nav",
1363
- {
1364
- "aria-label": "Main navigation",
1365
- 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",
1366
- children: items.map((item) => /* @__PURE__ */ jsx(
1367
- MenuBarItem,
1368
- {
1369
- icon: item.icon,
1370
- title: item.title,
1371
- isActive: item.isActive,
1372
- onClick: item.onClick
1373
- },
1374
- item.key
1375
- ))
1376
- }
1377
- )
1378
- );
1379
- }
1380
1804
  function ContextMenu({ items, children }) {
1381
1805
  return /* @__PURE__ */ jsxs(ContextMenuPrimitive.Root, { children: [
1382
1806
  /* @__PURE__ */ jsx(ContextMenuPrimitive.Trigger, { asChild: true, children }),
@@ -1578,21 +2002,50 @@ function Wizard({
1578
2002
  const handlePrev = () => {
1579
2003
  if (activeIndex > 0) setActiveIndex((i) => i - 1);
1580
2004
  };
2005
+ const SPOT_PAD = 6;
1581
2006
  const highlightStyle = bbox ? {
1582
- left: bbox.left - 4,
1583
- top: bbox.top - 4,
1584
- width: bbox.width + 8,
1585
- height: bbox.height + 8
2007
+ left: bbox.left - SPOT_PAD,
2008
+ top: bbox.top - SPOT_PAD,
2009
+ width: bbox.width + SPOT_PAD * 2,
2010
+ height: bbox.height + SPOT_PAD * 2
2011
+ } : { display: "none" };
2012
+ const backdropTop = bbox ? { left: 0, top: 0, right: 0, height: Math.max(0, bbox.top - SPOT_PAD) } : { display: "none" };
2013
+ const backdropBottom = bbox ? { left: 0, top: bbox.bottom + SPOT_PAD, right: 0, bottom: 0 } : { display: "none" };
2014
+ const backdropLeft = bbox ? {
2015
+ left: 0,
2016
+ top: bbox.top - SPOT_PAD,
2017
+ width: Math.max(0, bbox.left - SPOT_PAD),
2018
+ height: bbox.height + SPOT_PAD * 2
2019
+ } : { display: "none" };
2020
+ const backdropRight = bbox ? {
2021
+ left: bbox.right + SPOT_PAD,
2022
+ top: bbox.top - SPOT_PAD,
2023
+ right: 0,
2024
+ height: bbox.height + SPOT_PAD * 2
1586
2025
  } : { display: "none" };
1587
2026
  const tooltipStyle = bbox ? tooltipStyleFor(bbox, step?.placement) : { display: "none" };
1588
2027
  const isLast = activeIndex === steps.length - 1;
1589
2028
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1590
2029
  children,
1591
2030
  /* @__PURE__ */ jsx(AnimatePresence, { children: open && step && /* @__PURE__ */ jsxs(Portal, { children: [
2031
+ ["top", "bottom", "left", "right"].map((side) => /* @__PURE__ */ jsx(
2032
+ motion.div,
2033
+ {
2034
+ className: "fixed z-[7000000] bg-foreground/40 backdrop-blur-[2px] pointer-events-auto",
2035
+ style: side === "top" ? backdropTop : side === "bottom" ? backdropBottom : side === "left" ? backdropLeft : backdropRight,
2036
+ initial: { opacity: 0 },
2037
+ animate: { opacity: 1 },
2038
+ exit: { opacity: 0 },
2039
+ transition: { duration: reduced ? 0 : 0.18, ease: "easeOut" },
2040
+ "aria-hidden": "true"
2041
+ },
2042
+ side
2043
+ )),
1592
2044
  /* @__PURE__ */ jsx(
1593
2045
  motion.div,
1594
2046
  {
1595
- className: "fixed inset-0 z-[7000000] bg-foreground/40 backdrop-blur-[1px] pointer-events-auto",
2047
+ className: "fixed z-[7000001] pointer-events-auto",
2048
+ style: highlightStyle,
1596
2049
  initial: { opacity: 0 },
1597
2050
  animate: { opacity: 1 },
1598
2051
  exit: { opacity: 0 },
@@ -1603,7 +2056,7 @@ function Wizard({
1603
2056
  /* @__PURE__ */ jsx(
1604
2057
  motion.div,
1605
2058
  {
1606
- className: "fixed z-[7000001] pointer-events-none rounded-md ring-2 ring-accent ring-offset-2 ring-offset-background",
2059
+ className: "fixed z-[7000002] pointer-events-none rounded-md ring-2 ring-accent",
1607
2060
  style: highlightStyle,
1608
2061
  initial: { opacity: 0, scale: 1.08 },
1609
2062
  animate: { opacity: 1, scale: 1 },
@@ -1624,7 +2077,7 @@ function Wizard({
1624
2077
  "aria-modal": "true",
1625
2078
  "aria-labelledby": step.title ? tooltipTitleId : void 0,
1626
2079
  "aria-describedby": tooltipBodyId,
1627
- className: "fixed z-[7000002] rounded-lg bg-surface text-foreground border border-border shadow-xl p-4 pointer-events-auto",
2080
+ className: "fixed z-[7000003] rounded-lg bg-surface text-foreground border border-border shadow-xl p-4 pointer-events-auto",
1628
2081
  style: tooltipStyle,
1629
2082
  initial: { opacity: 0, scale: 0.96, y: 6 },
1630
2083
  animate: { opacity: 1, scale: 1, y: 0 },
@@ -1698,7 +2151,7 @@ var SearchInput = React8.forwardRef(function SearchInput2({
1698
2151
  style: style ?? {},
1699
2152
  children: [
1700
2153
  label && /* @__PURE__ */ jsx("label", { className: "text-sm font-medium ml-1 max-content text-foreground", htmlFor, children: label }),
1701
- /* @__PURE__ */ 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: [
2154
+ /* @__PURE__ */ 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: [
1702
2155
  /* @__PURE__ */ jsx(
1703
2156
  "input",
1704
2157
  {
@@ -1745,7 +2198,8 @@ function Dropdown({
1745
2198
  htmlFor,
1746
2199
  items = [],
1747
2200
  labelStyle = {},
1748
- placeholder
2201
+ placeholder,
2202
+ showSelectedCount = false
1749
2203
  }) {
1750
2204
  const [open, setOpen] = useState(false);
1751
2205
  const [selectedItems, setSelectedItems] = useState([]);
@@ -1808,7 +2262,7 @@ function Dropdown({
1808
2262
  "aria-invalid": hasError || void 0,
1809
2263
  "aria-describedby": hasError ? errorId : void 0,
1810
2264
  style,
1811
- 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" : ""}`,
2265
+ 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" : ""}`,
1812
2266
  tabIndex: disabled ? -1 : 0,
1813
2267
  onKeyDown: (e) => {
1814
2268
  if (disabled) return;
@@ -1831,7 +2285,7 @@ function Dropdown({
1831
2285
  },
1832
2286
  String(val)
1833
2287
  )),
1834
- value.length > 1 && /* @__PURE__ */ jsx(DropdownPill, { value: `+${value.length - 1} more` })
2288
+ showSelectedCount && value.length > 1 && /* @__PURE__ */ jsx(DropdownPill, { value: `+${value.length - 1} more` })
1835
2289
  ] }) : /* @__PURE__ */ jsx(DropdownPill, { value: innerItems.find((it) => it.key === value)?.label })
1836
2290
  }
1837
2291
  ),
@@ -2630,10 +3084,13 @@ function ThemeProvider({
2630
3084
  ] });
2631
3085
  }
2632
3086
  var SHIMMER = [
2633
- "animate-shimmer rounded-sm",
2634
- "bg-[length:400%_100%]",
2635
- "bg-gradient-to-r",
2636
- "from-border via-border-strong/40 to-border"
3087
+ "relative overflow-hidden rounded-sm bg-surface-raised",
3088
+ 'before:absolute before:inset-0 before:content-[""]',
3089
+ "before:bg-gradient-to-r before:from-transparent before:via-white/30 before:to-transparent",
3090
+ "before:animate-[shimmer_1.6s_linear_infinite]",
3091
+ // Respect prefers-reduced-motion — the resting bg-surface-raised is still
3092
+ // a perfectly legible placeholder for users who have animations off.
3093
+ "motion-reduce:before:hidden"
2637
3094
  ].join(" ");
2638
3095
  function SkeletonBox({ width, height = 16, radius, className = "", style }) {
2639
3096
  return /* @__PURE__ */ jsx(
@@ -2771,7 +3228,7 @@ function TextInput({
2771
3228
  id: htmlFor,
2772
3229
  "aria-invalid": hasError || void 0,
2773
3230
  "aria-describedby": hasError ? errorId : void 0,
2774
- 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`,
3231
+ 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`,
2775
3232
  style: inputStyle ?? {},
2776
3233
  placeholder: placeholder ?? ""
2777
3234
  }
@@ -2847,7 +3304,7 @@ function NumberInput({
2847
3304
  "div",
2848
3305
  {
2849
3306
  style,
2850
- 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`,
3307
+ 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`,
2851
3308
  children: [
2852
3309
  /* @__PURE__ */ jsx(
2853
3310
  "input",
@@ -2947,7 +3404,7 @@ function Password({
2947
3404
  id: htmlFor,
2948
3405
  "aria-invalid": hasError || void 0,
2949
3406
  "aria-describedby": hasError ? errorId : void 0,
2950
- 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`,
3407
+ 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`,
2951
3408
  style: inputStyle ?? {},
2952
3409
  placeholder: placeholder ?? ""
2953
3410
  }
@@ -3114,7 +3571,7 @@ function AutoComplete({
3114
3571
  children: [
3115
3572
  label && /* @__PURE__ */ jsx("label", { className: "text-sm font-medium ml-1 max-content text-foreground", children: label }),
3116
3573
  /* @__PURE__ */ jsxs(Popover.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
3117
- /* @__PURE__ */ jsx(Popover.Anchor, { asChild: true, children: /* @__PURE__ */ 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: [
3574
+ /* @__PURE__ */ jsx(Popover.Anchor, { asChild: true, children: /* @__PURE__ */ 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: [
3118
3575
  /* @__PURE__ */ jsx(
3119
3576
  "input",
3120
3577
  {
@@ -3315,7 +3772,7 @@ function TreeSelect({
3315
3772
  "aria-invalid": hasError || void 0,
3316
3773
  "aria-describedby": hasError ? errorId : void 0,
3317
3774
  disabled,
3318
- 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]" : ""}`,
3775
+ 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]" : ""}`,
3319
3776
  children: [
3320
3777
  /* @__PURE__ */ jsx("span", { className: "text-sm truncate text-left", children: selectedNode ? selectedNode.label : /* @__PURE__ */ jsx("span", { className: "text-foreground-muted", children: placeholder }) }),
3321
3778
  /* @__PURE__ */ 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__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) })
@@ -3608,12 +4065,14 @@ function DatePicker({
3608
4065
  const [open, setOpen] = useState(false);
3609
4066
  const [viewMonth, setViewMonth] = useState(() => startOfMonth(value ?? /* @__PURE__ */ new Date()));
3610
4067
  const [focusDate, setFocusDate] = useState(() => value ?? /* @__PURE__ */ new Date());
4068
+ const [view, setView] = useState("days");
3611
4069
  const gridRef = useRef(null);
3612
4070
  useEffect(() => {
3613
4071
  if (!open) return;
3614
4072
  const target = value ?? /* @__PURE__ */ new Date();
3615
4073
  setViewMonth(startOfMonth(target));
3616
4074
  setFocusDate(target);
4075
+ setView("days");
3617
4076
  }, [open, value]);
3618
4077
  useEffect(() => {
3619
4078
  if (!open) return;
@@ -3702,7 +4161,7 @@ function DatePicker({
3702
4161
  "aria-describedby": hasError ? errorId : void 0,
3703
4162
  "aria-haspopup": "dialog",
3704
4163
  "aria-expanded": open,
3705
- 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]" : ""}`,
4164
+ 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]" : ""}`,
3706
4165
  children: [
3707
4166
  /* @__PURE__ */ jsx("span", { className: `text-sm truncate ${displayValue ? "" : "text-foreground-muted"}`, children: displayValue || placeholder }),
3708
4167
  /* @__PURE__ */ jsx(CalendarIcon, {})
@@ -3724,29 +4183,89 @@ function DatePicker({
3724
4183
  "button",
3725
4184
  {
3726
4185
  type: "button",
3727
- onClick: () => setViewMonth(addMonths(viewMonth, -1)),
3728
- "aria-label": "Previous month",
4186
+ onClick: () => {
4187
+ if (view === "days") setViewMonth(addMonths(viewMonth, -1));
4188
+ else if (view === "months") setViewMonth(new Date(viewMonth.getFullYear() - 1, viewMonth.getMonth(), 1));
4189
+ else setViewMonth(new Date(viewMonth.getFullYear() - 10, viewMonth.getMonth(), 1));
4190
+ },
4191
+ "aria-label": view === "days" ? "Previous month" : view === "months" ? "Previous year" : "Previous decade",
3729
4192
  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",
3730
4193
  children: /* @__PURE__ */ jsx(ChevronLeft, {})
3731
4194
  }
3732
4195
  ),
3733
- /* @__PURE__ */ jsxs("div", { className: "text-sm font-semibold select-none", children: [
3734
- MONTH_NAMES[viewMonth.getMonth()],
3735
- " ",
3736
- viewMonth.getFullYear()
3737
- ] }),
4196
+ /* @__PURE__ */ jsxs(
4197
+ "button",
4198
+ {
4199
+ type: "button",
4200
+ onClick: () => {
4201
+ if (view === "days") setView("months");
4202
+ else if (view === "months") setView("years");
4203
+ },
4204
+ disabled: view === "years",
4205
+ "aria-label": "Change view",
4206
+ 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",
4207
+ children: [
4208
+ view === "days" && `${MONTH_NAMES[viewMonth.getMonth()]} ${viewMonth.getFullYear()}`,
4209
+ view === "months" && `${viewMonth.getFullYear()}`,
4210
+ view === "years" && (() => {
4211
+ const decadeStart = Math.floor(viewMonth.getFullYear() / 10) * 10;
4212
+ return `${decadeStart} \u2013 ${decadeStart + 11}`;
4213
+ })()
4214
+ ]
4215
+ }
4216
+ ),
3738
4217
  /* @__PURE__ */ jsx(
3739
4218
  "button",
3740
4219
  {
3741
4220
  type: "button",
3742
- onClick: () => setViewMonth(addMonths(viewMonth, 1)),
3743
- "aria-label": "Next month",
4221
+ onClick: () => {
4222
+ if (view === "days") setViewMonth(addMonths(viewMonth, 1));
4223
+ else if (view === "months") setViewMonth(new Date(viewMonth.getFullYear() + 1, viewMonth.getMonth(), 1));
4224
+ else setViewMonth(new Date(viewMonth.getFullYear() + 10, viewMonth.getMonth(), 1));
4225
+ },
4226
+ "aria-label": view === "days" ? "Next month" : view === "months" ? "Next year" : "Next decade",
3744
4227
  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",
3745
4228
  children: /* @__PURE__ */ jsx(ChevronRight3, {})
3746
4229
  }
3747
4230
  )
3748
4231
  ] }),
3749
- /* @__PURE__ */ jsxs(
4232
+ view === "months" && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1 min-w-[224px]", children: MONTH_NAMES.map((name, idx) => {
4233
+ const isCurrent = value && value.getFullYear() === viewMonth.getFullYear() && value.getMonth() === idx;
4234
+ return /* @__PURE__ */ jsx(
4235
+ "button",
4236
+ {
4237
+ type: "button",
4238
+ onClick: () => {
4239
+ setViewMonth(new Date(viewMonth.getFullYear(), idx, 1));
4240
+ setView("days");
4241
+ },
4242
+ 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"}`,
4243
+ children: name.slice(0, 3)
4244
+ },
4245
+ name
4246
+ );
4247
+ }) }),
4248
+ view === "years" && (() => {
4249
+ const decadeStart = Math.floor(viewMonth.getFullYear() / 10) * 10;
4250
+ const years = Array.from({ length: 12 }, (_, i) => decadeStart + i);
4251
+ return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1 min-w-[224px]", children: years.map((y) => {
4252
+ const isCurrent = value?.getFullYear() === y;
4253
+ return /* @__PURE__ */ jsx(
4254
+ "button",
4255
+ {
4256
+ type: "button",
4257
+ onClick: () => {
4258
+ setViewMonth(new Date(y, viewMonth.getMonth(), 1));
4259
+ setView("months");
4260
+ },
4261
+ 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"}`,
4262
+ children: y
4263
+ },
4264
+ y
4265
+ );
4266
+ }) });
4267
+ })(),
4268
+ view === "days" && /* @__PURE__ */ jsxs(
3750
4269
  "table",
3751
4270
  {
3752
4271
  ref: gridRef,
@@ -3828,6 +4347,6 @@ function ChevronRight3() {
3828
4347
  return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
3829
4348
  }
3830
4349
 
3831
- export { AppShell, AutoComplete, Button, Catalog, CatalogCarousel, CatalogGrid, Checkbox, ContextMenu, Drawer, Dropdown, DropdownPill, FadingBase, FileInput, GridCard, icons_default as Icon, IconButton, List2 as List, LoadingSpinner, MenuBar, MenuBarItem, Modal, NotificationProvider, NumberInput, OpaqueGridCard, Password, Portal, ScalableContainer, SearchInput_default as SearchInput, Sidebar, SkeletonBox, SkeletonCard, SkeletonCircle, SkeletonText, Switch, Table, Tabs, DatePicker as Temporal, TextInput, ThemeProvider, ThemeSwitch, ToggleButton, Tooltip, TooltipProvider, TopBar, Tree, TreeSelect, Wizard, useNotification };
4350
+ export { AppShell, AutoComplete, Avatar, Box, Button, Catalog, CatalogCarousel, CatalogGrid, Checkbox, ContextMenu, Drawer, Dropdown, FadingBase, FileInput, Flex, Grid2 as Grid, GridCard, icons_default as Icon, IconButton, List2 as List, LoadingSpinner, Modal, NotificationProvider, NumberInput, OpaqueGridCard, Password, Portal, ScalableContainer, SearchInput_default as SearchInput, Sidebar, SkeletonBox, SkeletonCard, SkeletonCircle, SkeletonText, Switch, Table, Tabs, DatePicker as Temporal, TextInput, ThemeProvider, ThemeSwitch, ToggleButton, Tooltip, TooltipProvider, TopBar, Tree, TreeSelect, Typography, Wizard, useNotification };
3832
4351
  //# sourceMappingURL=index.js.map
3833
4352
  //# sourceMappingURL=index.js.map