@geomak/ui 6.25.0 → 6.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2840,6 +2840,7 @@ var MONTHS2 = [
2840
2840
  "November",
2841
2841
  "December"
2842
2842
  ];
2843
+ var MONTHS_SHORT = MONTHS2.map((m) => m.slice(0, 3));
2843
2844
  var WEEKDAYS2 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
2844
2845
  var toDate = (d) => d instanceof Date ? d : new Date(d);
2845
2846
  var startOfDay2 = (d) => new Date(d.getFullYear(), d.getMonth(), d.getDate());
@@ -2967,10 +2968,18 @@ function Scheduler({
2967
2968
  /* @__PURE__ */ jsx(IconButton, { type: "bordered", size: "sm", icon: /* @__PURE__ */ jsx(Chevron4, { dir: "left" }), title: "Previous", onClick: () => go(-1) }),
2968
2969
  /* @__PURE__ */ jsx(IconButton, { type: "bordered", size: "sm", icon: /* @__PURE__ */ jsx(Chevron4, { dir: "right" }), title: "Next", onClick: () => go(1) }),
2969
2970
  /* @__PURE__ */ jsx(Button_default, { variant: "ghost", size: "sm", content: "Today", onClick: goToday }),
2970
- /* @__PURE__ */ jsxs("h2", { className: "ml-1 min-w-[9rem] text-base font-semibold tracking-tight text-foreground", children: [
2971
- title,
2972
- loading && /* @__PURE__ */ jsx("span", { className: "ml-2 inline-flex translate-y-0.5", children: /* @__PURE__ */ jsx(Spinner2, {}) })
2973
- ] })
2971
+ /* @__PURE__ */ jsx(
2972
+ MonthYearPicker,
2973
+ {
2974
+ label: title,
2975
+ cursor,
2976
+ onPick: (d) => {
2977
+ setDir(0);
2978
+ setCursor(d);
2979
+ }
2980
+ }
2981
+ ),
2982
+ loading && /* @__PURE__ */ jsx(Spinner2, {})
2974
2983
  ] }),
2975
2984
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2976
2985
  /* @__PURE__ */ jsx(
@@ -3021,6 +3030,64 @@ function Scheduler({
3021
3030
  }
3022
3031
  );
3023
3032
  }
3033
+ function MonthYearPicker({ label, cursor, onPick }) {
3034
+ const [open, setOpen] = useState(false);
3035
+ const [viewYear, setViewYear] = useState(cursor.getFullYear());
3036
+ useEffect(() => {
3037
+ if (open) setViewYear(cursor.getFullYear());
3038
+ }, [open, cursor]);
3039
+ return /* @__PURE__ */ jsxs(Popover.Root, { open, onOpenChange: setOpen, children: [
3040
+ /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
3041
+ "button",
3042
+ {
3043
+ type: "button",
3044
+ className: "group ml-1 inline-flex items-center gap-1.5 rounded-md px-1.5 py-0.5 text-lg font-semibold tracking-tight text-foreground transition-colors hover:bg-background focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
3045
+ children: [
3046
+ label,
3047
+ /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, "aria-hidden": "true", className: "h-4 w-4 text-foreground-muted transition-transform duration-150 group-data-[state=open]:rotate-180", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 9l6 6 6-6" }) })
3048
+ ]
3049
+ }
3050
+ ) }),
3051
+ /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(
3052
+ Popover.Content,
3053
+ {
3054
+ align: "start",
3055
+ sideOffset: 8,
3056
+ className: [
3057
+ "z-[400] w-64 rounded-lg border border-border bg-surface p-3 shadow-lg",
3058
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
3059
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95"
3060
+ ].join(" "),
3061
+ children: [
3062
+ /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
3063
+ /* @__PURE__ */ jsx(IconButton, { size: "sm", type: "bordered", icon: /* @__PURE__ */ jsx(Chevron4, { dir: "left" }), title: "Previous year", onClick: () => setViewYear((y) => y - 1) }),
3064
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold tabular-nums text-foreground", children: viewYear }),
3065
+ /* @__PURE__ */ jsx(IconButton, { size: "sm", type: "bordered", icon: /* @__PURE__ */ jsx(Chevron4, { dir: "right" }), title: "Next year", onClick: () => setViewYear((y) => y + 1) })
3066
+ ] }),
3067
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1", children: MONTHS_SHORT.map((m, i) => {
3068
+ const current = i === cursor.getMonth() && viewYear === cursor.getFullYear();
3069
+ return /* @__PURE__ */ jsx(
3070
+ "button",
3071
+ {
3072
+ type: "button",
3073
+ onClick: () => {
3074
+ onPick(new Date(viewYear, i, 1));
3075
+ setOpen(false);
3076
+ },
3077
+ className: [
3078
+ "rounded-md px-2 py-1.5 text-sm transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
3079
+ current ? "bg-accent font-semibold text-accent-fg" : "text-foreground hover:bg-background"
3080
+ ].join(" "),
3081
+ children: m
3082
+ },
3083
+ m
3084
+ );
3085
+ }) })
3086
+ ]
3087
+ }
3088
+ ) })
3089
+ ] });
3090
+ }
3024
3091
  var MAX_CHIPS = 3;
3025
3092
  function MonthView({
3026
3093
  cursor,
@@ -3045,7 +3112,9 @@ function MonthView({
3045
3112
  className: [
3046
3113
  "group flex min-h-[5rem] flex-col gap-1 border-b border-r border-border p-1.5 text-left transition-colors",
3047
3114
  "[&:nth-child(7n)]:border-r-0 focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-accent",
3048
- inMonth ? "bg-surface hover:bg-surface-raised" : "bg-background/40"
3115
+ // surface===surface-raised in light mode, so hover lifts toward the
3116
+ // cool chart-mist background instead (a visible, on-brand tint).
3117
+ inMonth ? "bg-surface hover:bg-background" : "bg-background hover:bg-surface"
3049
3118
  ].join(" "),
3050
3119
  children: [
3051
3120
  /* @__PURE__ */ jsx(
@@ -3102,6 +3171,8 @@ function WeekView({
3102
3171
  onSelectEvent
3103
3172
  }) {
3104
3173
  const days = useMemo(() => getWeekDays(cursor, weekStartsOn), [cursor, weekStartsOn]);
3174
+ const labels = useMemo(() => weekdayLabels(weekStartsOn), [weekStartsOn]);
3175
+ const dow = (d) => labels[(d.getDay() - weekStartsOn + 7) % 7];
3105
3176
  const [startHour, endHour] = dayHours;
3106
3177
  const hours = useMemo(
3107
3178
  () => Array.from({ length: endHour - startHour }, (_, i) => startHour + i),
@@ -3113,7 +3184,7 @@ function WeekView({
3113
3184
  /* @__PURE__ */ jsxs("div", { className: "grid border-b border-border", style: { gridTemplateColumns: `3.5rem repeat(7, 1fr)` }, children: [
3114
3185
  /* @__PURE__ */ jsx("div", { className: "border-r border-border" }),
3115
3186
  days.map((d) => /* @__PURE__ */ jsxs("div", { className: "border-r border-border px-1 py-1.5 text-center last:border-r-0", children: [
3116
- /* @__PURE__ */ jsx("div", { className: "text-[11px] font-medium uppercase tracking-wide text-foreground-muted", children: weekdayLabels(weekStartsOn)[(d.getDay() - weekStartsOn + 7) % 7] }),
3187
+ /* @__PURE__ */ jsx("div", { className: "text-[11px] font-medium uppercase tracking-wide text-foreground-muted", children: dow(d) }),
3117
3188
  /* @__PURE__ */ jsx("div", { className: ["mx-auto mt-0.5 flex h-6 w-6 items-center justify-center rounded-full text-xs tabular-nums", isToday(d) ? "bg-accent font-semibold text-accent-fg" : "text-foreground"].join(" "), children: d.getDate() })
3118
3189
  ] }, d.getTime()))
3119
3190
  ] }),
@@ -3126,9 +3197,9 @@ function WeekView({
3126
3197
  "button",
3127
3198
  {
3128
3199
  type: "button",
3129
- "aria-label": `${weekdayLabels(weekStartsOn)[(day.getDay() - weekStartsOn + 7) % 7]} ${day.getDate()} ${hourLabel(h)}`,
3200
+ "aria-label": `${dow(day)} ${day.getDate()} ${hourLabel(h)}`,
3130
3201
  onClick: () => onSelectSlot?.(new Date(day.getFullYear(), day.getMonth(), day.getDate(), h)),
3131
- className: "absolute left-0 right-0 border-b border-border/60 hover:bg-surface-raised/60 focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-accent",
3202
+ className: "absolute left-0 right-0 border-b border-border hover:bg-background focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-accent",
3132
3203
  style: { top: i * hourHeight, height: hourHeight }
3133
3204
  },
3134
3205
  h
@@ -3147,11 +3218,16 @@ function WeekView({
3147
3218
  onSelectEvent?.(e);
3148
3219
  },
3149
3220
  title: `${e.title} \xB7 ${timeLabel(e.start)}\u2013${timeLabel(e.end)}`,
3150
- className: "absolute left-0.5 right-0.5 overflow-hidden rounded-md border-l-2 px-1.5 py-0.5 text-left text-[11px] leading-tight text-foreground shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
3151
- style: { top: Math.max(0, top), height, borderLeftColor: color, backgroundColor: `color-mix(in oklab, ${color} 16%, var(--color-surface))` },
3221
+ className: "absolute left-0.5 right-0.5 overflow-hidden rounded-md border px-1.5 py-0.5 text-left text-[11px] leading-tight text-foreground shadow-sm transition-shadow hover:shadow-md focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
3222
+ style: {
3223
+ top: Math.max(0, top),
3224
+ height,
3225
+ backgroundColor: `color-mix(in oklab, ${color} 14%, var(--color-surface))`,
3226
+ borderColor: `color-mix(in oklab, ${color} 40%, var(--color-surface))`
3227
+ },
3152
3228
  children: [
3153
3229
  /* @__PURE__ */ jsx("div", { className: "truncate font-medium", children: e.title }),
3154
- /* @__PURE__ */ jsx("div", { className: "truncate text-foreground-muted", children: timeLabel(e.start) })
3230
+ /* @__PURE__ */ jsx("div", { className: "truncate", style: { color }, children: timeLabel(e.start) })
3155
3231
  ]
3156
3232
  },
3157
3233
  e.id
@@ -5653,48 +5729,45 @@ function Pagination({
5653
5729
  if (next) setPerPageKey(next.key);
5654
5730
  }
5655
5731
  }, [serverSide, options.perPage, picker]);
5656
- const navBtn = (icon, disabled, onClick) => /* @__PURE__ */ jsx(IconButton, { disabled, onClick, icon });
5657
- const chevronRight = /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-5 w-5", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
5658
- const doubleChevronRight = /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-5 w-5", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13 5l7 7-7 7M5 5l7 7-7 7" }) });
5659
- return /* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center justify-end pt-2", children: [
5660
- navBtn(
5661
- /* @__PURE__ */ jsx("span", { className: "rotate-180 inline-flex", children: doubleChevronRight }),
5662
- activePage === 0,
5663
- () => onPageChange(0)
5664
- ),
5665
- navBtn(
5666
- /* @__PURE__ */ jsx("span", { className: "rotate-180 inline-flex", children: chevronRight }),
5667
- activePage === 0,
5668
- () => activePage > 0 && onPageChange(activePage - 1)
5669
- ),
5670
- /* @__PURE__ */ jsx("span", { className: "bg-surface-raised rounded-lg ml-2 mr-2 shadow-sm p-2 w-10 text-center select-none text-foreground", children: activePage + 1 }),
5671
- navBtn(
5672
- chevronRight,
5673
- activePage === maxPage,
5674
- () => activePage < maxPage && onPageChange(activePage + 1)
5675
- ),
5676
- navBtn(
5677
- doubleChevronRight,
5678
- activePage === maxPage,
5679
- () => onPageChange(maxPage)
5680
- ),
5681
- options.withPicker && /* @__PURE__ */ jsx(
5682
- Dropdown,
5683
- {
5684
- style: { width: 80, position: "relative", bottom: 4 },
5685
- hasSearch: false,
5686
- items: picker,
5687
- isMultiselect: false,
5688
- value: displayPerPageKey,
5689
- onChange: ({ target: { value } }) => {
5690
- if (Array.isArray(value)) return;
5691
- const numKey = typeof value === "number" ? value : Number(value);
5692
- if (!serverSide) setPerPageKey(numKey);
5693
- const opt = picker.find((o) => o.key === numKey);
5694
- onPerPageChange(opt?.label ?? opt?.value ?? numKey);
5732
+ const navBtn = (icon, disabled, onClick, title) => /* @__PURE__ */ jsx(IconButton, { type: "bordered", size: "sm", disabled, onClick, icon, title });
5733
+ const chevronRight = /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
5734
+ const doubleChevronRight = /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13 5l7 7-7 7M5 5l7 7-7 7" }) });
5735
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-end gap-x-4 gap-y-3 pt-3", children: [
5736
+ options.withPicker && /* @__PURE__ */ jsxs("div", { className: "mr-auto flex items-center gap-2", children: [
5737
+ /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap text-xs text-foreground-muted", children: "Rows per page" }),
5738
+ /* @__PURE__ */ jsx(
5739
+ Dropdown,
5740
+ {
5741
+ size: "sm",
5742
+ style: { width: 76 },
5743
+ hasSearch: false,
5744
+ items: picker,
5745
+ isMultiselect: false,
5746
+ value: displayPerPageKey,
5747
+ onChange: ({ target: { value } }) => {
5748
+ if (Array.isArray(value)) return;
5749
+ const numKey = typeof value === "number" ? value : Number(value);
5750
+ if (!serverSide) setPerPageKey(numKey);
5751
+ const opt = picker.find((o) => o.key === numKey);
5752
+ onPerPageChange(opt?.label ?? opt?.value ?? numKey);
5753
+ }
5695
5754
  }
5696
- }
5697
- )
5755
+ )
5756
+ ] }),
5757
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
5758
+ navBtn(/* @__PURE__ */ jsx("span", { className: "inline-flex rotate-180", children: doubleChevronRight }), activePage === 0, () => onPageChange(0), "First page"),
5759
+ navBtn(/* @__PURE__ */ jsx("span", { className: "inline-flex rotate-180", children: chevronRight }), activePage === 0, () => activePage > 0 && onPageChange(activePage - 1), "Previous page"),
5760
+ /* @__PURE__ */ jsxs("span", { className: "px-2 text-sm tabular-nums text-foreground-secondary select-none", children: [
5761
+ activePage + 1,
5762
+ " ",
5763
+ /* @__PURE__ */ jsxs("span", { className: "text-foreground-muted", children: [
5764
+ "/ ",
5765
+ maxPage + 1
5766
+ ] })
5767
+ ] }),
5768
+ navBtn(chevronRight, activePage === maxPage, () => activePage < maxPage && onPageChange(activePage + 1), "Next page"),
5769
+ navBtn(doubleChevronRight, activePage === maxPage, () => onPageChange(maxPage), "Last page")
5770
+ ] })
5698
5771
  ] });
5699
5772
  }
5700
5773
  function Table({
@@ -8422,7 +8495,7 @@ function OtpInput({
8422
8495
  emit(valid.join(""));
8423
8496
  focusBox(valid.length);
8424
8497
  };
8425
- return /* @__PURE__ */ jsx(Field, { className, label, htmlFor, errorId, errorMessage, required, layout, helperText, children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", role: "group", "aria-label": typeof label === "string" ? label : "One-time code", children: chars.map((char, idx) => /* @__PURE__ */ jsxs(React29.Fragment, { children: [
8498
+ return /* @__PURE__ */ jsx(Field, { className, label, htmlFor, errorId, errorMessage, required, layout, helperText, children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2", role: "group", "aria-label": typeof label === "string" ? label : "One-time code", children: chars.map((char, idx) => /* @__PURE__ */ jsxs(React29.Fragment, { children: [
8426
8499
  /* @__PURE__ */ jsx(
8427
8500
  "input",
8428
8501
  {
@@ -8833,9 +8906,9 @@ function DateRangePicker({
8833
8906
  {
8834
8907
  align: "start",
8835
8908
  sideOffset: 4,
8836
- className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-50 p-3 flex gap-3 animate-in fade-in-0 zoom-in-95",
8909
+ className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-50 p-3 flex flex-col gap-3 sm:flex-row max-w-[calc(100vw-1rem)] max-h-[calc(100vh-2rem)] overflow-auto animate-in fade-in-0 zoom-in-95",
8837
8910
  children: [
8838
- presets && presets.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1 pr-3 border-r border-border min-w-[120px]", children: presets.map((p) => /* @__PURE__ */ jsx(
8911
+ presets && presets.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1 min-w-[120px] sm:pr-3 sm:border-r sm:border-border", children: presets.map((p) => /* @__PURE__ */ jsx(
8839
8912
  "button",
8840
8913
  {
8841
8914
  type: "button",
@@ -8848,7 +8921,7 @@ function DateRangePicker({
8848
8921
  },
8849
8922
  p.label
8850
8923
  )) }),
8851
- /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
8924
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 sm:flex-row", children: [
8852
8925
  /* @__PURE__ */ jsxs("div", { className: "relative", children: [
8853
8926
  /* @__PURE__ */ jsx(
8854
8927
  "button",