@geomak/ui 5.4.0 → 5.5.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.cjs +647 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +182 -1
- package/dist/index.d.ts +182 -1
- package/dist/index.js +643 -3
- package/dist/index.js.map +1 -1
- package/dist/styles.css +36 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1835,8 +1835,8 @@ function CatalogCarousel({ items, buttonText, onOpen }) {
|
|
|
1835
1835
|
)
|
|
1836
1836
|
] }) });
|
|
1837
1837
|
}
|
|
1838
|
-
function Catalog({ display = "grid", items = [], buttonText, onOpen }) {
|
|
1839
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full", children:
|
|
1838
|
+
function Catalog({ display: display2 = "grid", items = [], buttonText, onOpen }) {
|
|
1839
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full", children: display2 === "grid" ? /* @__PURE__ */ jsxRuntime.jsx(CatalogGrid, { items, buttonText, onOpen }) : /* @__PURE__ */ jsxRuntime.jsx(CatalogCarousel, { items, buttonText, onOpen }) });
|
|
1840
1840
|
}
|
|
1841
1841
|
function ContextMenu({ items, children }) {
|
|
1842
1842
|
return /* @__PURE__ */ jsxRuntime.jsxs(ContextMenuPrimitive__namespace.Root, { children: [
|
|
@@ -5036,6 +5036,646 @@ function TagsInput({
|
|
|
5036
5036
|
}
|
|
5037
5037
|
);
|
|
5038
5038
|
}
|
|
5039
|
+
var BOX_SIZE = {
|
|
5040
|
+
sm: "h-9 w-8 text-sm",
|
|
5041
|
+
md: "h-11 w-10 text-base",
|
|
5042
|
+
lg: "h-14 w-12 text-lg"
|
|
5043
|
+
};
|
|
5044
|
+
function OtpInput({
|
|
5045
|
+
length = 6,
|
|
5046
|
+
value = "",
|
|
5047
|
+
onChange,
|
|
5048
|
+
onComplete,
|
|
5049
|
+
label,
|
|
5050
|
+
htmlFor,
|
|
5051
|
+
name,
|
|
5052
|
+
mode = "numeric",
|
|
5053
|
+
masked = false,
|
|
5054
|
+
size = "md",
|
|
5055
|
+
disabled,
|
|
5056
|
+
errorMessage,
|
|
5057
|
+
required,
|
|
5058
|
+
groupAfter
|
|
5059
|
+
}) {
|
|
5060
|
+
const errorId = React8.useId();
|
|
5061
|
+
const hasError = errorMessage != null;
|
|
5062
|
+
const refs = React8.useRef([]);
|
|
5063
|
+
const chars = Array.from({ length }, (_, i) => value[i] ?? "");
|
|
5064
|
+
const pattern = mode === "numeric" ? /[0-9]/ : /[a-zA-Z0-9]/;
|
|
5065
|
+
const emit = (next) => {
|
|
5066
|
+
onChange?.(next);
|
|
5067
|
+
if (next.length === length && !next.includes(" ") && [...next].every(Boolean)) {
|
|
5068
|
+
onComplete?.(next);
|
|
5069
|
+
}
|
|
5070
|
+
};
|
|
5071
|
+
const setCharAt = (idx, char) => {
|
|
5072
|
+
const arr = chars.slice();
|
|
5073
|
+
arr[idx] = char;
|
|
5074
|
+
emit(arr.join(""));
|
|
5075
|
+
};
|
|
5076
|
+
const focusBox = (idx) => {
|
|
5077
|
+
const el = refs.current[Math.max(0, Math.min(length - 1, idx))];
|
|
5078
|
+
el?.focus();
|
|
5079
|
+
el?.select();
|
|
5080
|
+
};
|
|
5081
|
+
const onBoxChange = (idx, raw) => {
|
|
5082
|
+
const char = raw.slice(-1);
|
|
5083
|
+
if (char && !pattern.test(char)) return;
|
|
5084
|
+
setCharAt(idx, char);
|
|
5085
|
+
if (char) focusBox(idx + 1);
|
|
5086
|
+
};
|
|
5087
|
+
const onKeyDown = (idx, e) => {
|
|
5088
|
+
if (e.key === "Backspace") {
|
|
5089
|
+
if (chars[idx]) {
|
|
5090
|
+
setCharAt(idx, "");
|
|
5091
|
+
} else if (idx > 0) {
|
|
5092
|
+
setCharAt(idx - 1, "");
|
|
5093
|
+
focusBox(idx - 1);
|
|
5094
|
+
}
|
|
5095
|
+
} else if (e.key === "ArrowLeft") {
|
|
5096
|
+
e.preventDefault();
|
|
5097
|
+
focusBox(idx - 1);
|
|
5098
|
+
} else if (e.key === "ArrowRight") {
|
|
5099
|
+
e.preventDefault();
|
|
5100
|
+
focusBox(idx + 1);
|
|
5101
|
+
}
|
|
5102
|
+
};
|
|
5103
|
+
const onPaste = (e) => {
|
|
5104
|
+
e.preventDefault();
|
|
5105
|
+
const text = e.clipboardData.getData("text").trim();
|
|
5106
|
+
const valid = [...text].filter((c) => pattern.test(c)).slice(0, length);
|
|
5107
|
+
if (valid.length === 0) return;
|
|
5108
|
+
emit(valid.join(""));
|
|
5109
|
+
focusBox(valid.length);
|
|
5110
|
+
};
|
|
5111
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, htmlFor, errorId, errorMessage, required, children: /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs(React8__default.default.Fragment, { children: [
|
|
5112
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5113
|
+
"input",
|
|
5114
|
+
{
|
|
5115
|
+
ref: (el) => {
|
|
5116
|
+
refs.current[idx] = el;
|
|
5117
|
+
},
|
|
5118
|
+
id: idx === 0 ? htmlFor : void 0,
|
|
5119
|
+
name: idx === 0 ? name : void 0,
|
|
5120
|
+
value: char,
|
|
5121
|
+
disabled,
|
|
5122
|
+
inputMode: mode === "numeric" ? "numeric" : "text",
|
|
5123
|
+
autoComplete: idx === 0 ? "one-time-code" : "off",
|
|
5124
|
+
type: masked && char ? "password" : "text",
|
|
5125
|
+
maxLength: 1,
|
|
5126
|
+
"aria-label": `Digit ${idx + 1}`,
|
|
5127
|
+
"aria-invalid": hasError || void 0,
|
|
5128
|
+
"aria-describedby": hasError ? errorId : void 0,
|
|
5129
|
+
onChange: (e) => onBoxChange(idx, e.target.value),
|
|
5130
|
+
onKeyDown: (e) => onKeyDown(idx, e),
|
|
5131
|
+
onPaste,
|
|
5132
|
+
onFocus: (e) => e.target.select(),
|
|
5133
|
+
className: [
|
|
5134
|
+
BOX_SIZE[size],
|
|
5135
|
+
"text-center font-medium rounded-lg border bg-surface text-foreground",
|
|
5136
|
+
"transition-[border-color,box-shadow] duration-150",
|
|
5137
|
+
hasError ? "border-status-error" : "border-border",
|
|
5138
|
+
"hover:border-border-strong",
|
|
5139
|
+
"focus:outline-none focus:border-accent focus:ring-[3px] focus:ring-focus-ring",
|
|
5140
|
+
"disabled:bg-surface-raised disabled:text-foreground-muted disabled:cursor-not-allowed"
|
|
5141
|
+
].join(" ")
|
|
5142
|
+
}
|
|
5143
|
+
),
|
|
5144
|
+
groupAfter && (idx + 1) % groupAfter === 0 && idx < length - 1 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-2 text-center text-foreground-muted", "aria-hidden": "true", children: "\xB7" })
|
|
5145
|
+
] }, idx)) }) });
|
|
5146
|
+
}
|
|
5147
|
+
var ICON_SIZE = { sm: "w-4 h-4", md: "w-5 h-5", lg: "w-7 h-7" };
|
|
5148
|
+
var Star = (filled) => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: filled ? "currentColor" : "none", stroke: "currentColor", strokeWidth: filled ? 0 : 1.5, className: "w-full h-full", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M11.48 3.5a.56.56 0 011.04 0l2.13 4.77 5.18.5a.56.56 0 01.32.97l-3.9 3.46 1.15 5.1a.56.56 0 01-.83.6L12 16.8l-4.57 2.6a.56.56 0 01-.83-.6l1.15-5.1-3.9-3.46a.56.56 0 01.32-.97l5.18-.5L11.48 3.5z" }) });
|
|
5149
|
+
function Rating({
|
|
5150
|
+
value,
|
|
5151
|
+
defaultValue = 0,
|
|
5152
|
+
onChange,
|
|
5153
|
+
count = 5,
|
|
5154
|
+
allowHalf = false,
|
|
5155
|
+
readOnly = false,
|
|
5156
|
+
clearable = true,
|
|
5157
|
+
label,
|
|
5158
|
+
size = "md",
|
|
5159
|
+
disabled,
|
|
5160
|
+
icon = Star,
|
|
5161
|
+
errorMessage,
|
|
5162
|
+
name
|
|
5163
|
+
}) {
|
|
5164
|
+
const errorId = React8.useId();
|
|
5165
|
+
const [internal, setInternal] = React8.useState(defaultValue);
|
|
5166
|
+
const [hover, setHover] = React8.useState(null);
|
|
5167
|
+
const current = value ?? internal;
|
|
5168
|
+
const display2 = hover ?? current;
|
|
5169
|
+
const interactive = !readOnly && !disabled;
|
|
5170
|
+
const commit = (next) => {
|
|
5171
|
+
const v = clearable && next === current ? 0 : next;
|
|
5172
|
+
setInternal(v);
|
|
5173
|
+
onChange?.(v);
|
|
5174
|
+
};
|
|
5175
|
+
const onKeyDown = (e) => {
|
|
5176
|
+
if (!interactive) return;
|
|
5177
|
+
const step = allowHalf ? 0.5 : 1;
|
|
5178
|
+
if (e.key === "ArrowRight" || e.key === "ArrowUp") {
|
|
5179
|
+
e.preventDefault();
|
|
5180
|
+
commit(Math.min(count, current + step));
|
|
5181
|
+
} else if (e.key === "ArrowLeft" || e.key === "ArrowDown") {
|
|
5182
|
+
e.preventDefault();
|
|
5183
|
+
commit(Math.max(0, current - step));
|
|
5184
|
+
} else if (e.key === "Home") {
|
|
5185
|
+
e.preventDefault();
|
|
5186
|
+
commit(0);
|
|
5187
|
+
} else if (e.key === "End") {
|
|
5188
|
+
e.preventDefault();
|
|
5189
|
+
commit(count);
|
|
5190
|
+
}
|
|
5191
|
+
};
|
|
5192
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, errorId, errorMessage, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5193
|
+
"div",
|
|
5194
|
+
{
|
|
5195
|
+
role: interactive ? "slider" : "img",
|
|
5196
|
+
"aria-label": typeof label === "string" ? label : "Rating",
|
|
5197
|
+
"aria-valuenow": interactive ? current : void 0,
|
|
5198
|
+
"aria-valuemin": interactive ? 0 : void 0,
|
|
5199
|
+
"aria-valuemax": interactive ? count : void 0,
|
|
5200
|
+
"aria-valuetext": `${current} of ${count}`,
|
|
5201
|
+
tabIndex: interactive ? 0 : -1,
|
|
5202
|
+
onKeyDown,
|
|
5203
|
+
onMouseLeave: () => setHover(null),
|
|
5204
|
+
className: "inline-flex items-center gap-1 text-accent focus:outline-none focus-visible:ring-[3px] focus-visible:ring-focus-ring rounded-md w-max",
|
|
5205
|
+
children: [
|
|
5206
|
+
name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: current }),
|
|
5207
|
+
Array.from({ length: count }, (_, i) => {
|
|
5208
|
+
const starValue = i + 1;
|
|
5209
|
+
const fillFraction = Math.max(0, Math.min(1, display2 - i));
|
|
5210
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5211
|
+
"span",
|
|
5212
|
+
{
|
|
5213
|
+
className: `relative ${ICON_SIZE[size]} ${interactive ? "cursor-pointer" : ""} ${disabled ? "opacity-50" : ""}`,
|
|
5214
|
+
onMouseMove: (e) => {
|
|
5215
|
+
if (!interactive) return;
|
|
5216
|
+
if (allowHalf) {
|
|
5217
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
5218
|
+
const half = e.clientX - rect.left < rect.width / 2;
|
|
5219
|
+
setHover(i + (half ? 0.5 : 1));
|
|
5220
|
+
} else {
|
|
5221
|
+
setHover(starValue);
|
|
5222
|
+
}
|
|
5223
|
+
},
|
|
5224
|
+
onClick: (e) => {
|
|
5225
|
+
if (!interactive) return;
|
|
5226
|
+
if (allowHalf) {
|
|
5227
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
5228
|
+
const half = e.clientX - rect.left < rect.width / 2;
|
|
5229
|
+
commit(i + (half ? 0.5 : 1));
|
|
5230
|
+
} else {
|
|
5231
|
+
commit(starValue);
|
|
5232
|
+
}
|
|
5233
|
+
},
|
|
5234
|
+
children: [
|
|
5235
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 text-foreground-muted", children: icon(false) }),
|
|
5236
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5237
|
+
"span",
|
|
5238
|
+
{
|
|
5239
|
+
className: "absolute inset-0 overflow-hidden",
|
|
5240
|
+
style: { width: `${fillFraction * 100}%` },
|
|
5241
|
+
children: icon(true)
|
|
5242
|
+
}
|
|
5243
|
+
)
|
|
5244
|
+
]
|
|
5245
|
+
},
|
|
5246
|
+
i
|
|
5247
|
+
);
|
|
5248
|
+
})
|
|
5249
|
+
]
|
|
5250
|
+
}
|
|
5251
|
+
) });
|
|
5252
|
+
}
|
|
5253
|
+
var pad = (n) => n.toString().padStart(2, "0");
|
|
5254
|
+
function parse(value) {
|
|
5255
|
+
if (!value) return null;
|
|
5256
|
+
const [h, m, s] = value.split(":").map(Number);
|
|
5257
|
+
if (Number.isNaN(h) || Number.isNaN(m)) return null;
|
|
5258
|
+
return { h, m, s: Number.isNaN(s) ? 0 : s };
|
|
5259
|
+
}
|
|
5260
|
+
function display(value, use12, withSeconds) {
|
|
5261
|
+
const p = parse(value);
|
|
5262
|
+
if (!p) return "";
|
|
5263
|
+
if (use12) {
|
|
5264
|
+
const period = p.h >= 12 ? "PM" : "AM";
|
|
5265
|
+
const h12 = p.h % 12 === 0 ? 12 : p.h % 12;
|
|
5266
|
+
return `${h12}:${pad(p.m)}${withSeconds ? `:${pad(p.s)}` : ""} ${period}`;
|
|
5267
|
+
}
|
|
5268
|
+
return `${pad(p.h)}:${pad(p.m)}${withSeconds ? `:${pad(p.s)}` : ""}`;
|
|
5269
|
+
}
|
|
5270
|
+
function TimePicker({
|
|
5271
|
+
value,
|
|
5272
|
+
onChange,
|
|
5273
|
+
label,
|
|
5274
|
+
htmlFor,
|
|
5275
|
+
name,
|
|
5276
|
+
placeholder = "Select a time\u2026",
|
|
5277
|
+
layout = "vertical",
|
|
5278
|
+
size = "md",
|
|
5279
|
+
use12Hours = false,
|
|
5280
|
+
withSeconds = false,
|
|
5281
|
+
minuteStep = 1,
|
|
5282
|
+
disabled,
|
|
5283
|
+
errorMessage,
|
|
5284
|
+
required,
|
|
5285
|
+
style
|
|
5286
|
+
}) {
|
|
5287
|
+
const errorId = React8.useId();
|
|
5288
|
+
const hasError = errorMessage != null;
|
|
5289
|
+
const [open, setOpen] = React8.useState(false);
|
|
5290
|
+
const parsed = parse(value) ?? { h: 0, m: 0, s: 0 };
|
|
5291
|
+
const update = (next) => {
|
|
5292
|
+
const merged = { ...parsed, ...next };
|
|
5293
|
+
onChange?.(`${pad(merged.h)}:${pad(merged.m)}${withSeconds ? `:${pad(merged.s)}` : ""}`);
|
|
5294
|
+
};
|
|
5295
|
+
const hours = use12Hours ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 24 }, (_, i) => i);
|
|
5296
|
+
const minutes = Array.from({ length: Math.ceil(60 / minuteStep) }, (_, i) => i * minuteStep);
|
|
5297
|
+
const seconds = Array.from({ length: 60 }, (_, i) => i);
|
|
5298
|
+
const selectedHourCol = use12Hours ? parsed.h % 12 === 0 ? 12 : parsed.h % 12 : parsed.h;
|
|
5299
|
+
const period = parsed.h >= 12 ? "PM" : "AM";
|
|
5300
|
+
const setHour12 = (h12, p) => {
|
|
5301
|
+
const h24 = p === "AM" ? h12 === 12 ? 0 : h12 : h12 === 12 ? 12 : h12 + 12;
|
|
5302
|
+
update({ h: h24 });
|
|
5303
|
+
};
|
|
5304
|
+
const Column = ({ items, selected, onPick, fmt }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col overflow-y-auto max-h-48 w-14 hidden-scrollbar", role: "listbox", children: items.map((n) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5305
|
+
"button",
|
|
5306
|
+
{
|
|
5307
|
+
type: "button",
|
|
5308
|
+
role: "option",
|
|
5309
|
+
"aria-selected": selected === n,
|
|
5310
|
+
onClick: () => onPick(n),
|
|
5311
|
+
className: `py-1.5 text-sm rounded-md text-center transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${selected === n ? "bg-accent text-accent-fg" : "text-foreground hover:bg-surface-raised"}`,
|
|
5312
|
+
children: fmt ? fmt(n) : pad(n)
|
|
5313
|
+
},
|
|
5314
|
+
n
|
|
5315
|
+
)) });
|
|
5316
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Field, { label, htmlFor, errorId, errorMessage, layout, required, children: [
|
|
5317
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
|
|
5318
|
+
/* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5319
|
+
"button",
|
|
5320
|
+
{
|
|
5321
|
+
id: htmlFor,
|
|
5322
|
+
type: "button",
|
|
5323
|
+
disabled,
|
|
5324
|
+
style,
|
|
5325
|
+
"aria-invalid": hasError || void 0,
|
|
5326
|
+
"aria-describedby": hasError ? errorId : void 0,
|
|
5327
|
+
className: `flex items-center justify-between cursor-pointer select-none ${!style?.width ? "min-w-[160px]" : ""} ${fieldShell({ size, hasError, disabled })}`,
|
|
5328
|
+
children: [
|
|
5329
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-sm truncate ${value ? "" : "text-foreground-muted"}`, children: display(value, use12Hours, withSeconds) || placeholder }),
|
|
5330
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.75, className: "w-4 h-4 flex-shrink-0 text-foreground-muted ml-2", "aria-hidden": "true", children: [
|
|
5331
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "9" }),
|
|
5332
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 7v5l3 2", strokeLinecap: "round" })
|
|
5333
|
+
] })
|
|
5334
|
+
]
|
|
5335
|
+
}
|
|
5336
|
+
) }),
|
|
5337
|
+
/* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5338
|
+
Popover__namespace.Content,
|
|
5339
|
+
{
|
|
5340
|
+
align: "start",
|
|
5341
|
+
sideOffset: 4,
|
|
5342
|
+
className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-50 p-2 flex gap-1 animate-in fade-in-0 zoom-in-95",
|
|
5343
|
+
children: [
|
|
5344
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5345
|
+
Column,
|
|
5346
|
+
{
|
|
5347
|
+
items: hours,
|
|
5348
|
+
selected: selectedHourCol,
|
|
5349
|
+
onPick: (h) => use12Hours ? setHour12(h, period) : update({ h }),
|
|
5350
|
+
fmt: use12Hours ? (n) => String(n) : pad
|
|
5351
|
+
}
|
|
5352
|
+
),
|
|
5353
|
+
/* @__PURE__ */ jsxRuntime.jsx(Column, { items: minutes, selected: parsed.m, onPick: (m) => update({ m }) }),
|
|
5354
|
+
withSeconds && /* @__PURE__ */ jsxRuntime.jsx(Column, { items: seconds, selected: parsed.s, onPick: (s) => update({ s }) }),
|
|
5355
|
+
use12Hours && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-1 w-12", children: ["AM", "PM"].map((p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5356
|
+
"button",
|
|
5357
|
+
{
|
|
5358
|
+
type: "button",
|
|
5359
|
+
onClick: () => setHour12(selectedHourCol, p),
|
|
5360
|
+
className: `py-1.5 text-sm rounded-md transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${period === p ? "bg-accent text-accent-fg" : "text-foreground hover:bg-surface-raised"}`,
|
|
5361
|
+
children: p
|
|
5362
|
+
},
|
|
5363
|
+
p
|
|
5364
|
+
)) })
|
|
5365
|
+
]
|
|
5366
|
+
}
|
|
5367
|
+
) })
|
|
5368
|
+
] }),
|
|
5369
|
+
name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: value ?? "" })
|
|
5370
|
+
] });
|
|
5371
|
+
}
|
|
5372
|
+
var MONTH_NAMES2 = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
5373
|
+
var WEEKDAY = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
5374
|
+
var startOfMonth2 = (d) => new Date(d.getFullYear(), d.getMonth(), 1);
|
|
5375
|
+
var addMonths2 = (d, n) => new Date(d.getFullYear(), d.getMonth() + n, 1);
|
|
5376
|
+
var addDays2 = (d, n) => {
|
|
5377
|
+
const c = new Date(d);
|
|
5378
|
+
c.setDate(c.getDate() + n);
|
|
5379
|
+
return c;
|
|
5380
|
+
};
|
|
5381
|
+
var isSameDay2 = (a, b) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
5382
|
+
var startOfDay = (d) => new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
5383
|
+
var defaultFmt = (d) => `${d.getFullYear()}-${`${d.getMonth() + 1}`.padStart(2, "0")}-${`${d.getDate()}`.padStart(2, "0")}`;
|
|
5384
|
+
function buildGrid2(viewMonth, weekStartsOn) {
|
|
5385
|
+
const first = startOfMonth2(viewMonth);
|
|
5386
|
+
const offset = (first.getDay() - weekStartsOn + 7) % 7;
|
|
5387
|
+
const gridStart = addDays2(first, -offset);
|
|
5388
|
+
return Array.from({ length: 42 }, (_, i) => {
|
|
5389
|
+
const d = addDays2(gridStart, i);
|
|
5390
|
+
return { date: d, outside: d.getMonth() !== viewMonth.getMonth() };
|
|
5391
|
+
});
|
|
5392
|
+
}
|
|
5393
|
+
function DateRangePicker({
|
|
5394
|
+
value = { start: null, end: null },
|
|
5395
|
+
onChange,
|
|
5396
|
+
label,
|
|
5397
|
+
htmlFor,
|
|
5398
|
+
placeholder = "Select a date range\u2026",
|
|
5399
|
+
layout = "vertical",
|
|
5400
|
+
size = "md",
|
|
5401
|
+
min,
|
|
5402
|
+
max,
|
|
5403
|
+
weekStartsOn = 0,
|
|
5404
|
+
presets,
|
|
5405
|
+
format = defaultFmt,
|
|
5406
|
+
disabled,
|
|
5407
|
+
errorMessage,
|
|
5408
|
+
required,
|
|
5409
|
+
style
|
|
5410
|
+
}) {
|
|
5411
|
+
const errorId = React8.useId();
|
|
5412
|
+
const hasError = errorMessage != null;
|
|
5413
|
+
const [open, setOpen] = React8.useState(false);
|
|
5414
|
+
const [leftMonth, setLeftMonth] = React8.useState(() => startOfMonth2(value.start ?? /* @__PURE__ */ new Date()));
|
|
5415
|
+
const [pendingStart, setPendingStart] = React8.useState(null);
|
|
5416
|
+
const [hoverDate, setHoverDate] = React8.useState(null);
|
|
5417
|
+
const weekdays = React8.useMemo(
|
|
5418
|
+
() => WEEKDAY.slice(weekStartsOn).concat(WEEKDAY.slice(0, weekStartsOn)),
|
|
5419
|
+
[weekStartsOn]
|
|
5420
|
+
);
|
|
5421
|
+
const isDisabled = (d) => min && d < startOfDay(min) || max && d > startOfDay(max);
|
|
5422
|
+
const effective = pendingStart ? { start: pendingStart, end: hoverDate } : value;
|
|
5423
|
+
const inRange = (d) => {
|
|
5424
|
+
const { start, end } = effective;
|
|
5425
|
+
if (!start || !end) return false;
|
|
5426
|
+
const [a, b] = start <= end ? [start, end] : [end, start];
|
|
5427
|
+
return d >= startOfDay(a) && d <= startOfDay(b);
|
|
5428
|
+
};
|
|
5429
|
+
const onDayClick = (d) => {
|
|
5430
|
+
if (isDisabled(d)) return;
|
|
5431
|
+
if (!pendingStart) {
|
|
5432
|
+
setPendingStart(d);
|
|
5433
|
+
setHoverDate(d);
|
|
5434
|
+
onChange?.({ start: d, end: null });
|
|
5435
|
+
} else {
|
|
5436
|
+
const [start, end] = pendingStart <= d ? [pendingStart, d] : [d, pendingStart];
|
|
5437
|
+
onChange?.({ start, end });
|
|
5438
|
+
setPendingStart(null);
|
|
5439
|
+
setHoverDate(null);
|
|
5440
|
+
setOpen(false);
|
|
5441
|
+
}
|
|
5442
|
+
};
|
|
5443
|
+
const triggerText = value.start && value.end ? `${format(value.start)} \u2013 ${format(value.end)}` : value.start ? `${format(value.start)} \u2013 \u2026` : "";
|
|
5444
|
+
const renderMonth = (viewMonth) => {
|
|
5445
|
+
const cells = buildGrid2(viewMonth, weekStartsOn);
|
|
5446
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
5447
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm font-semibold text-center mb-2 select-none", children: [
|
|
5448
|
+
MONTH_NAMES2[viewMonth.getMonth()],
|
|
5449
|
+
" ",
|
|
5450
|
+
viewMonth.getFullYear()
|
|
5451
|
+
] }),
|
|
5452
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-7 gap-y-1", children: [
|
|
5453
|
+
weekdays.map((w) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[11px] font-medium text-foreground-muted uppercase text-center", children: w }, w)),
|
|
5454
|
+
cells.map(({ date, outside }) => {
|
|
5455
|
+
const dis = isDisabled(date);
|
|
5456
|
+
const isStart = effective.start && isSameDay2(date, effective.start);
|
|
5457
|
+
const isEnd = effective.end && isSameDay2(date, effective.end);
|
|
5458
|
+
const within = inRange(date) && !isStart && !isEnd;
|
|
5459
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5460
|
+
"button",
|
|
5461
|
+
{
|
|
5462
|
+
type: "button",
|
|
5463
|
+
disabled: dis,
|
|
5464
|
+
onMouseEnter: () => pendingStart && setHoverDate(date),
|
|
5465
|
+
onClick: () => onDayClick(date),
|
|
5466
|
+
className: [
|
|
5467
|
+
"h-8 text-xs font-medium transition-colors",
|
|
5468
|
+
"focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
|
|
5469
|
+
"disabled:opacity-30 disabled:cursor-not-allowed",
|
|
5470
|
+
isStart || isEnd ? "bg-accent text-accent-fg rounded-md" : within ? "bg-surface-raised text-foreground rounded-none" : outside ? "text-foreground-muted hover:bg-surface-raised rounded-md" : "text-foreground hover:bg-surface-raised rounded-md"
|
|
5471
|
+
].join(" "),
|
|
5472
|
+
children: date.getDate()
|
|
5473
|
+
},
|
|
5474
|
+
defaultFmt(date)
|
|
5475
|
+
);
|
|
5476
|
+
})
|
|
5477
|
+
] })
|
|
5478
|
+
] });
|
|
5479
|
+
};
|
|
5480
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, htmlFor, errorId, errorMessage, layout, required, children: /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => {
|
|
5481
|
+
if (!disabled) {
|
|
5482
|
+
setOpen(o);
|
|
5483
|
+
if (!o) {
|
|
5484
|
+
setPendingStart(null);
|
|
5485
|
+
setHoverDate(null);
|
|
5486
|
+
}
|
|
5487
|
+
}
|
|
5488
|
+
}, children: [
|
|
5489
|
+
/* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5490
|
+
"button",
|
|
5491
|
+
{
|
|
5492
|
+
id: htmlFor,
|
|
5493
|
+
type: "button",
|
|
5494
|
+
disabled,
|
|
5495
|
+
style,
|
|
5496
|
+
"aria-invalid": hasError || void 0,
|
|
5497
|
+
"aria-describedby": hasError ? errorId : void 0,
|
|
5498
|
+
className: `flex items-center justify-between cursor-pointer select-none ${!style?.width ? "min-w-[240px]" : ""} ${fieldShell({ size, hasError, disabled })}`,
|
|
5499
|
+
children: [
|
|
5500
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-sm truncate ${triggerText ? "" : "text-foreground-muted"}`, children: triggerText || placeholder }),
|
|
5501
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.75, className: "w-4 h-4 flex-shrink-0 text-foreground-muted ml-2", "aria-hidden": "true", children: [
|
|
5502
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "5", width: "18", height: "16", rx: "2" }),
|
|
5503
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 9h18M8 3v4M16 3v4", strokeLinecap: "round" })
|
|
5504
|
+
] })
|
|
5505
|
+
]
|
|
5506
|
+
}
|
|
5507
|
+
) }),
|
|
5508
|
+
/* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5509
|
+
Popover__namespace.Content,
|
|
5510
|
+
{
|
|
5511
|
+
align: "start",
|
|
5512
|
+
sideOffset: 4,
|
|
5513
|
+
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",
|
|
5514
|
+
children: [
|
|
5515
|
+
presets && presets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-1 pr-3 border-r border-border min-w-[120px]", children: presets.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5516
|
+
"button",
|
|
5517
|
+
{
|
|
5518
|
+
type: "button",
|
|
5519
|
+
onClick: () => {
|
|
5520
|
+
onChange?.(p.range());
|
|
5521
|
+
setOpen(false);
|
|
5522
|
+
},
|
|
5523
|
+
className: "text-left text-xs px-2 py-1.5 rounded-md text-foreground-secondary hover:bg-surface-raised hover:text-foreground transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
|
|
5524
|
+
children: p.label
|
|
5525
|
+
},
|
|
5526
|
+
p.label
|
|
5527
|
+
)) }),
|
|
5528
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4", children: [
|
|
5529
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
5530
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5531
|
+
"button",
|
|
5532
|
+
{
|
|
5533
|
+
type: "button",
|
|
5534
|
+
onClick: () => setLeftMonth(addMonths2(leftMonth, -1)),
|
|
5535
|
+
"aria-label": "Previous month",
|
|
5536
|
+
className: "absolute -top-1 left-0 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",
|
|
5537
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 19l-7-7 7-7" }) })
|
|
5538
|
+
}
|
|
5539
|
+
),
|
|
5540
|
+
renderMonth(leftMonth)
|
|
5541
|
+
] }),
|
|
5542
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
5543
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5544
|
+
"button",
|
|
5545
|
+
{
|
|
5546
|
+
type: "button",
|
|
5547
|
+
onClick: () => setLeftMonth(addMonths2(leftMonth, 1)),
|
|
5548
|
+
"aria-label": "Next month",
|
|
5549
|
+
className: "absolute -top-1 right-0 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",
|
|
5550
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) })
|
|
5551
|
+
}
|
|
5552
|
+
),
|
|
5553
|
+
renderMonth(addMonths2(leftMonth, 1))
|
|
5554
|
+
] })
|
|
5555
|
+
] })
|
|
5556
|
+
]
|
|
5557
|
+
}
|
|
5558
|
+
) })
|
|
5559
|
+
] }) });
|
|
5560
|
+
}
|
|
5561
|
+
var DEFAULT_SWATCHES = [
|
|
5562
|
+
"#0466c8",
|
|
5563
|
+
"#1e8449",
|
|
5564
|
+
"#d68910",
|
|
5565
|
+
"#c0392b",
|
|
5566
|
+
"#8e44ad",
|
|
5567
|
+
"#16a085",
|
|
5568
|
+
"#2c3e50",
|
|
5569
|
+
"#7f8c8d",
|
|
5570
|
+
"#e84393",
|
|
5571
|
+
"#00b894",
|
|
5572
|
+
"#fdcb6e",
|
|
5573
|
+
"#0a1929"
|
|
5574
|
+
];
|
|
5575
|
+
var HEX_RE = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
|
5576
|
+
function ColorPicker({
|
|
5577
|
+
value = "",
|
|
5578
|
+
onChange,
|
|
5579
|
+
label,
|
|
5580
|
+
htmlFor,
|
|
5581
|
+
name,
|
|
5582
|
+
layout = "vertical",
|
|
5583
|
+
size = "md",
|
|
5584
|
+
swatches = DEFAULT_SWATCHES,
|
|
5585
|
+
allowCustom = true,
|
|
5586
|
+
disabled,
|
|
5587
|
+
errorMessage,
|
|
5588
|
+
required,
|
|
5589
|
+
placeholder = "Pick a colour\u2026"
|
|
5590
|
+
}) {
|
|
5591
|
+
const errorId = React8.useId();
|
|
5592
|
+
const hasError = errorMessage != null;
|
|
5593
|
+
const [open, setOpen] = React8.useState(false);
|
|
5594
|
+
const [draft, setDraft] = React8.useState(value);
|
|
5595
|
+
const valid = HEX_RE.test(value);
|
|
5596
|
+
const pick = (hex) => {
|
|
5597
|
+
onChange?.(hex);
|
|
5598
|
+
setDraft(hex);
|
|
5599
|
+
};
|
|
5600
|
+
const commitDraft = (raw) => {
|
|
5601
|
+
const hex = raw.startsWith("#") ? raw : `#${raw}`;
|
|
5602
|
+
setDraft(hex);
|
|
5603
|
+
if (HEX_RE.test(hex)) onChange?.(hex);
|
|
5604
|
+
};
|
|
5605
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Field, { label, htmlFor, errorId, errorMessage, layout, required, children: [
|
|
5606
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
|
|
5607
|
+
/* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5608
|
+
"button",
|
|
5609
|
+
{
|
|
5610
|
+
id: htmlFor,
|
|
5611
|
+
type: "button",
|
|
5612
|
+
disabled,
|
|
5613
|
+
"aria-invalid": hasError || void 0,
|
|
5614
|
+
"aria-describedby": hasError ? errorId : void 0,
|
|
5615
|
+
className: `flex items-center gap-2 cursor-pointer select-none ${fieldShell({ size, hasError, disabled })}`,
|
|
5616
|
+
children: [
|
|
5617
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5618
|
+
"span",
|
|
5619
|
+
{
|
|
5620
|
+
className: "h-4 w-4 flex-shrink-0 rounded border border-border",
|
|
5621
|
+
style: { backgroundColor: valid ? value : "transparent" },
|
|
5622
|
+
"aria-hidden": "true"
|
|
5623
|
+
}
|
|
5624
|
+
),
|
|
5625
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `flex-1 text-left text-sm truncate ${valid ? "text-foreground" : "text-foreground-muted"}`, children: valid ? value.toLowerCase() : placeholder })
|
|
5626
|
+
]
|
|
5627
|
+
}
|
|
5628
|
+
) }),
|
|
5629
|
+
/* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5630
|
+
Popover__namespace.Content,
|
|
5631
|
+
{
|
|
5632
|
+
align: "start",
|
|
5633
|
+
sideOffset: 4,
|
|
5634
|
+
className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-50 p-3 w-56 animate-in fade-in-0 zoom-in-95",
|
|
5635
|
+
children: [
|
|
5636
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-6 gap-2 mb-3", children: swatches.map((sw) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5637
|
+
"button",
|
|
5638
|
+
{
|
|
5639
|
+
type: "button",
|
|
5640
|
+
onClick: () => {
|
|
5641
|
+
pick(sw);
|
|
5642
|
+
setOpen(false);
|
|
5643
|
+
},
|
|
5644
|
+
"aria-label": sw,
|
|
5645
|
+
className: `h-7 w-7 rounded-md border transition-transform hover:scale-110 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${value.toLowerCase() === sw.toLowerCase() ? "border-accent ring-2 ring-focus-ring" : "border-border"}`,
|
|
5646
|
+
style: { backgroundColor: sw }
|
|
5647
|
+
},
|
|
5648
|
+
sw
|
|
5649
|
+
)) }),
|
|
5650
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
5651
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5652
|
+
"input",
|
|
5653
|
+
{
|
|
5654
|
+
value: draft,
|
|
5655
|
+
onChange: (e) => commitDraft(e.target.value),
|
|
5656
|
+
placeholder: "#0466c8",
|
|
5657
|
+
"aria-label": "Hex colour",
|
|
5658
|
+
className: `flex-1 ${fieldShell({ size: "sm" })}`
|
|
5659
|
+
}
|
|
5660
|
+
),
|
|
5661
|
+
allowCustom && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5662
|
+
"input",
|
|
5663
|
+
{
|
|
5664
|
+
type: "color",
|
|
5665
|
+
value: valid ? value : "#000000",
|
|
5666
|
+
onChange: (e) => pick(e.target.value),
|
|
5667
|
+
"aria-label": "Custom colour",
|
|
5668
|
+
className: "h-7 w-9 rounded-md border border-border bg-surface cursor-pointer p-0.5"
|
|
5669
|
+
}
|
|
5670
|
+
)
|
|
5671
|
+
] })
|
|
5672
|
+
]
|
|
5673
|
+
}
|
|
5674
|
+
) })
|
|
5675
|
+
] }),
|
|
5676
|
+
name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: valid ? value : "" })
|
|
5677
|
+
] });
|
|
5678
|
+
}
|
|
5039
5679
|
|
|
5040
5680
|
Object.defineProperty(exports, "COLORS", {
|
|
5041
5681
|
enumerable: true,
|
|
@@ -5062,7 +5702,9 @@ exports.Catalog = Catalog;
|
|
|
5062
5702
|
exports.CatalogCarousel = CatalogCarousel;
|
|
5063
5703
|
exports.CatalogGrid = CatalogGrid;
|
|
5064
5704
|
exports.Checkbox = Checkbox;
|
|
5705
|
+
exports.ColorPicker = ColorPicker;
|
|
5065
5706
|
exports.ContextMenu = ContextMenu;
|
|
5707
|
+
exports.DateRangePicker = DateRangePicker;
|
|
5066
5708
|
exports.Drawer = Drawer;
|
|
5067
5709
|
exports.Dropdown = Dropdown;
|
|
5068
5710
|
exports.FadingBase = FadingBase;
|
|
@@ -5079,9 +5721,11 @@ exports.Modal = Modal;
|
|
|
5079
5721
|
exports.NotificationProvider = NotificationProvider;
|
|
5080
5722
|
exports.NumberInput = NumberInput;
|
|
5081
5723
|
exports.OpaqueGridCard = OpaqueGridCard;
|
|
5724
|
+
exports.OtpInput = OtpInput;
|
|
5082
5725
|
exports.Password = Password;
|
|
5083
5726
|
exports.Portal = Portal;
|
|
5084
5727
|
exports.RadioGroup = RadioGroup;
|
|
5728
|
+
exports.Rating = Rating;
|
|
5085
5729
|
exports.ScalableContainer = ScalableContainer;
|
|
5086
5730
|
exports.SearchInput = SearchInput_default;
|
|
5087
5731
|
exports.SegmentedControl = SegmentedControl;
|
|
@@ -5100,6 +5744,7 @@ exports.TextArea = TextArea;
|
|
|
5100
5744
|
exports.TextInput = TextInput;
|
|
5101
5745
|
exports.ThemeProvider = ThemeProvider;
|
|
5102
5746
|
exports.ThemeSwitch = ThemeSwitch;
|
|
5747
|
+
exports.TimePicker = TimePicker;
|
|
5103
5748
|
exports.ToggleButton = ToggleButton;
|
|
5104
5749
|
exports.Tooltip = Tooltip;
|
|
5105
5750
|
exports.TooltipProvider = TooltipProvider;
|