klun-ui 0.4.1 → 0.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.
@@ -232,6 +232,8 @@ var enUS = {
232
232
  carousel: { previous: "Previous", next: "Next", goToSlide: "Go to slide {n}" },
233
233
  input: { clear: "Clear" },
234
234
  notification: { close: "Close" },
235
+ select: { placeholder: "Select" },
236
+ counterInput: { decrease: "Decrease", increase: "Increase" },
235
237
  form: {
236
238
  required: "This field is required",
237
239
  empty: "Cannot be empty",
@@ -262,7 +264,9 @@ var enUS = {
262
264
  previous: "Previous",
263
265
  next: "Next",
264
266
  pageRange: "{from}\u2013{to} of {total}",
265
- perPage: "{size} / page"
267
+ perPage: "{size} / page",
268
+ selectRow: "Select row",
269
+ selectAll: "Select all rows"
266
270
  }
267
271
  };
268
272
  var zhCN = {
@@ -326,6 +330,8 @@ var zhCN = {
326
330
  carousel: { previous: "\u4E0A\u4E00\u9875", next: "\u4E0B\u4E00\u9875", goToSlide: "\u8DF3\u8F6C\u5230\u7B2C {n} \u5F20" },
327
331
  input: { clear: "\u6E05\u9664" },
328
332
  notification: { close: "\u5173\u95ED" },
333
+ select: { placeholder: "\u8BF7\u9009\u62E9" },
334
+ counterInput: { decrease: "\u51CF\u5C11", increase: "\u589E\u52A0" },
329
335
  form: {
330
336
  required: "\u6B64\u5B57\u6BB5\u4E3A\u5FC5\u586B\u9879",
331
337
  empty: "\u4E0D\u80FD\u4E3A\u7A7A",
@@ -356,7 +362,9 @@ var zhCN = {
356
362
  previous: "\u4E0A\u4E00\u9875",
357
363
  next: "\u4E0B\u4E00\u9875",
358
364
  pageRange: "{from}\u2013{to} \u5171 {total}",
359
- perPage: "{size} / \u9875"
365
+ perPage: "{size} / \u9875",
366
+ selectRow: "\u9009\u62E9\u672C\u884C",
367
+ selectAll: "\u5168\u9009"
360
368
  }
361
369
  };
362
370
  var zhTW = {
@@ -420,6 +428,8 @@ var zhTW = {
420
428
  carousel: { previous: "\u4E0A\u4E00\u9801", next: "\u4E0B\u4E00\u9801", goToSlide: "\u8DF3\u81F3\u7B2C {n} \u5F35" },
421
429
  input: { clear: "\u6E05\u9664" },
422
430
  notification: { close: "\u95DC\u9589" },
431
+ select: { placeholder: "\u8ACB\u9078\u64C7" },
432
+ counterInput: { decrease: "\u6E1B\u5C11", increase: "\u589E\u52A0" },
423
433
  form: {
424
434
  required: "\u6B64\u6B04\u4F4D\u70BA\u5FC5\u586B",
425
435
  empty: "\u4E0D\u80FD\u70BA\u7A7A",
@@ -450,7 +460,9 @@ var zhTW = {
450
460
  previous: "\u4E0A\u4E00\u9801",
451
461
  next: "\u4E0B\u4E00\u9801",
452
462
  pageRange: "{from}\u2013{to} \u5171 {total}",
453
- perPage: "{size} / \u9801"
463
+ perPage: "{size} / \u9801",
464
+ selectRow: "\u9078\u64C7\u672C\u884C",
465
+ selectAll: "\u5168\u9078"
454
466
  }
455
467
  };
456
468
  var jaJP = {
@@ -2233,6 +2245,275 @@ var CopyButton = react.forwardRef(
2233
2245
  }
2234
2246
  );
2235
2247
  CopyButton.displayName = "CopyButton";
2248
+ var Toggle = react.forwardRef(function Toggle2({
2249
+ variant = "default",
2250
+ size = "medium",
2251
+ pressed,
2252
+ defaultPressed = false,
2253
+ onPressedChange,
2254
+ className,
2255
+ onClick,
2256
+ disabled,
2257
+ ...props
2258
+ }, ref) {
2259
+ const [internal, setInternal] = react.useState(defaultPressed);
2260
+ const controlled = pressed !== void 0;
2261
+ const isPressed = controlled ? pressed : internal;
2262
+ return /* @__PURE__ */ jsxRuntime.jsx(
2263
+ "button",
2264
+ {
2265
+ ref,
2266
+ type: "button",
2267
+ className: chunkTPGAXYFU_cjs.cx(
2268
+ "klun-toggle",
2269
+ `klun-toggle--${variant}`,
2270
+ `klun-toggle--${size}`,
2271
+ className
2272
+ ),
2273
+ "aria-pressed": isPressed,
2274
+ disabled,
2275
+ onClick: (event) => {
2276
+ if (!controlled) setInternal(!isPressed);
2277
+ onPressedChange?.(!isPressed);
2278
+ onClick?.(event);
2279
+ },
2280
+ ...props
2281
+ }
2282
+ );
2283
+ });
2284
+ Toggle.displayName = "Toggle";
2285
+ function localTodayIso() {
2286
+ const now = /* @__PURE__ */ new Date();
2287
+ return [now.getFullYear(), now.getMonth() + 1, now.getDate()].map((part, i) => String(part).padStart(i === 0 ? 4 : 2, "0")).join("-");
2288
+ }
2289
+ function addDaysIso(iso, days) {
2290
+ const [y, m, d] = iso.split("-").map(Number);
2291
+ const dt = new Date(Date.UTC(y ?? 1970, (m ?? 1) - 1, (d ?? 1) + days));
2292
+ return [dt.getUTCFullYear(), dt.getUTCMonth() + 1, dt.getUTCDate()].map((part, i) => String(part).padStart(i === 0 ? 4 : 2, "0")).join("-");
2293
+ }
2294
+ function weekStartIso(iso) {
2295
+ const [y, m, d] = iso.split("-").map(Number);
2296
+ const dt = new Date(Date.UTC(y ?? 1970, (m ?? 1) - 1, d ?? 1));
2297
+ const mondayOffset = (dt.getUTCDay() + 6) % 7;
2298
+ return addDaysIso(iso, -mondayOffset);
2299
+ }
2300
+ var WEEKDAY_ANCHOR = Date.UTC(2026, 0, 5);
2301
+ var LABELED_WEEKDAY_INDICES = /* @__PURE__ */ new Set([0, 2, 4]);
2302
+ function buildHeatmapGrid(data, options = {}) {
2303
+ const { weeks = 26, today = localTodayIso(), locale = "en-US" } = options;
2304
+ const lastWeekStart = weekStartIso(today);
2305
+ const startDate = addDaysIso(lastWeekStart, -((weeks - 1) * 7));
2306
+ const todayIndex = (weeks - 1) * 7 + (() => {
2307
+ const [y, m, d] = today.split("-").map(Number);
2308
+ const dt = new Date(Date.UTC(y ?? 1970, (m ?? 1) - 1, d ?? 1));
2309
+ return (dt.getUTCDay() + 6) % 7;
2310
+ })();
2311
+ const all = [];
2312
+ for (let i = 0; i <= todayIndex; i++) {
2313
+ const date = addDaysIso(startDate, i);
2314
+ all.push({
2315
+ date,
2316
+ dayOfWeek: i % 7,
2317
+ week: Math.floor(i / 7),
2318
+ value: data?.[date] ?? 0,
2319
+ level: 0
2320
+ });
2321
+ }
2322
+ const nonZero = all.filter((c) => c.value > 0).map((c) => c.value).sort((a, b) => a - b);
2323
+ for (const cell of all) {
2324
+ if (cell.value <= 0) continue;
2325
+ if (nonZero.length <= 1) {
2326
+ cell.level = 4;
2327
+ continue;
2328
+ }
2329
+ const p = nonZero.indexOf(cell.value) / (nonZero.length - 1);
2330
+ cell.level = p <= 0.25 ? 1 : p <= 0.5 ? 2 : p <= 0.75 ? 3 : 4;
2331
+ }
2332
+ const months = [];
2333
+ let lastMonth = -1;
2334
+ for (const c of all) {
2335
+ const [y, m] = c.date.split("-").map(Number);
2336
+ const dt = new Date(Date.UTC(y ?? 1970, (m ?? 1) - 1, 1));
2337
+ const month = dt.getUTCMonth();
2338
+ if (month !== lastMonth && c.dayOfWeek === 0) {
2339
+ months.push({
2340
+ label: dt.toLocaleString(locale, { month: "short", timeZone: "UTC" }),
2341
+ week: c.week
2342
+ });
2343
+ lastMonth = month;
2344
+ }
2345
+ }
2346
+ const weekdayFmt = new Intl.DateTimeFormat(locale, { weekday: "short", timeZone: "UTC" });
2347
+ const weekdayLabels = Array.from(
2348
+ { length: 7 },
2349
+ (_, i) => weekdayFmt.format(new Date(WEEKDAY_ANCHOR + i * 864e5))
2350
+ );
2351
+ return { cells: all, months, weekdayLabels, windowDays: all.length };
2352
+ }
2353
+ function summarizeHeatmap(data, options = {}) {
2354
+ const { cells } = buildHeatmapGrid(data, options);
2355
+ let total = 0;
2356
+ let busiest = null;
2357
+ const sums = [0, 0, 0, 0, 0, 0, 0];
2358
+ const counts = [0, 0, 0, 0, 0, 0, 0];
2359
+ for (const c of cells) {
2360
+ total += c.value;
2361
+ sums[c.dayOfWeek] = (sums[c.dayOfWeek] ?? 0) + c.value;
2362
+ counts[c.dayOfWeek] = (counts[c.dayOfWeek] ?? 0) + 1;
2363
+ if (c.value > 0 && (!busiest || c.value > busiest.value)) {
2364
+ busiest = { date: c.date, value: c.value };
2365
+ }
2366
+ }
2367
+ if (total === 0) busiest = null;
2368
+ return {
2369
+ total,
2370
+ busiest,
2371
+ dailyAverage: cells.length > 0 ? total / cells.length : 0,
2372
+ weekdayAverages: sums.map((s, i) => (counts[i] ?? 0) > 0 ? s / (counts[i] ?? 1) : 0)
2373
+ };
2374
+ }
2375
+ var CELL_GAP = 3;
2376
+ var LABEL_WIDTH = 28;
2377
+ var HEADER_HEIGHT = 14;
2378
+ function levelFill(color, level) {
2379
+ if (level === 0) return "var(--klun-bg-soft-200)";
2380
+ const mix = ["25%", "50%", "75%", "100%"][level - 1] ?? "100%";
2381
+ return `color-mix(in oklab, ${color} ${mix}, transparent)`;
2382
+ }
2383
+ var ActivityHeatmap = react.forwardRef(
2384
+ function ActivityHeatmap2({
2385
+ data,
2386
+ weeks = 26,
2387
+ today,
2388
+ cellSize = 16,
2389
+ color = "var(--klun-primary-base)",
2390
+ formatValue = String,
2391
+ locale = "en-US",
2392
+ legendLabels = ["Less", "More"],
2393
+ className,
2394
+ style
2395
+ }, ref) {
2396
+ const { cells, months, weekdayLabels, windowDays } = react.useMemo(
2397
+ () => buildHeatmapGrid(data, { weeks, today, locale }),
2398
+ [data, weeks, today, locale]
2399
+ );
2400
+ const step = cellSize + CELL_GAP;
2401
+ const svgWidth = LABEL_WIDTH + weeks * step;
2402
+ const svgHeight = HEADER_HEIGHT + 7 * step;
2403
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-activity-heatmap", className), style, children: [
2404
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-activity-heatmap__scroll", children: /* @__PURE__ */ jsxRuntime.jsxs(
2405
+ "svg",
2406
+ {
2407
+ className: "klun-activity-heatmap__svg",
2408
+ width: svgWidth,
2409
+ height: svgHeight,
2410
+ role: "img",
2411
+ "aria-label": `Activity heatmap over ${windowDays} days`,
2412
+ children: [
2413
+ months.map((month) => /* @__PURE__ */ jsxRuntime.jsx(
2414
+ "text",
2415
+ {
2416
+ className: "klun-activity-heatmap__label",
2417
+ x: LABEL_WIDTH + month.week * step,
2418
+ y: 10,
2419
+ fontSize: 9,
2420
+ children: month.label
2421
+ },
2422
+ `${month.label}-${month.week}`
2423
+ )),
2424
+ weekdayLabels.map(
2425
+ (label, i) => LABELED_WEEKDAY_INDICES.has(i) ? /* @__PURE__ */ jsxRuntime.jsx(
2426
+ "text",
2427
+ {
2428
+ className: "klun-activity-heatmap__label",
2429
+ x: 0,
2430
+ y: HEADER_HEIGHT + i * step + cellSize - 1,
2431
+ fontSize: 9,
2432
+ children: label
2433
+ },
2434
+ i
2435
+ ) : null
2436
+ ),
2437
+ cells.map((cell) => /* @__PURE__ */ jsxRuntime.jsx(
2438
+ "rect",
2439
+ {
2440
+ className: "klun-activity-heatmap__cell",
2441
+ x: LABEL_WIDTH + cell.week * step,
2442
+ y: HEADER_HEIGHT + cell.dayOfWeek * step,
2443
+ width: cellSize,
2444
+ height: cellSize,
2445
+ rx: 3,
2446
+ fill: levelFill(color, cell.level),
2447
+ "data-level": cell.level,
2448
+ children: /* @__PURE__ */ jsxRuntime.jsxs("title", { children: [
2449
+ cell.date,
2450
+ ": ",
2451
+ cell.value > 0 ? formatValue(cell.value) : "No activity"
2452
+ ] })
2453
+ },
2454
+ cell.date
2455
+ ))
2456
+ ]
2457
+ }
2458
+ ) }),
2459
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-activity-heatmap__legend", children: [
2460
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: legendLabels[0] }),
2461
+ [0, 1, 2, 3, 4].map((level) => /* @__PURE__ */ jsxRuntime.jsx(
2462
+ "span",
2463
+ {
2464
+ className: "klun-activity-heatmap__swatch",
2465
+ style: { background: levelFill(color, level) }
2466
+ },
2467
+ level
2468
+ )),
2469
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: legendLabels[1] })
2470
+ ] })
2471
+ ] });
2472
+ }
2473
+ );
2474
+ var EMOJI_PREFIX = "emoji:";
2475
+ function parseAvatarEmoji(value) {
2476
+ if (!value?.startsWith(EMOJI_PREFIX)) return null;
2477
+ const emoji = value.slice(EMOJI_PREFIX.length).trim();
2478
+ return emoji || null;
2479
+ }
2480
+ function formatAvatarEmoji(emoji) {
2481
+ return EMOJI_PREFIX + emoji.trim();
2482
+ }
2483
+ var KIND_ICON = {
2484
+ agent: "ri-robot-2-line",
2485
+ squad: "ri-group-line",
2486
+ system: "ri-cpu-line"
2487
+ };
2488
+ var ActorAvatar = react.forwardRef(
2489
+ function ActorAvatar2({ name, initials, src, emoji, kind = "member", size = "24", className, ...props }, ref) {
2490
+ const [imgError, setImgError] = react.useState(false);
2491
+ react.useEffect(() => {
2492
+ setImgError(false);
2493
+ }, [src]);
2494
+ const resolvedEmoji = emoji ?? parseAvatarEmoji(src);
2495
+ return /* @__PURE__ */ jsxRuntime.jsx(
2496
+ "span",
2497
+ {
2498
+ ref,
2499
+ role: "img",
2500
+ "aria-label": name,
2501
+ className: chunkTPGAXYFU_cjs.cx("klun-actor-avatar", `klun-actor-avatar--${size}`, className),
2502
+ ...props,
2503
+ children: resolvedEmoji ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-actor-avatar__emoji", children: resolvedEmoji }) : src && !imgError ? /* @__PURE__ */ jsxRuntime.jsx(
2504
+ "img",
2505
+ {
2506
+ className: "klun-actor-avatar__img",
2507
+ src,
2508
+ alt: "",
2509
+ onError: () => setImgError(true)
2510
+ }
2511
+ ) : kind !== "member" ? /* @__PURE__ */ jsxRuntime.jsx("i", { className: chunkTPGAXYFU_cjs.cx("klun-actor-avatar__icon", KIND_ICON[kind]), "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-actor-avatar__initials", children: initials })
2512
+ }
2513
+ );
2514
+ }
2515
+ );
2516
+ ActorAvatar.displayName = "ActorAvatar";
2236
2517
  var Avatar = react.forwardRef(function Avatar2({ size = "40", src, alt = "", initials, color = "gray", status, icon, className, ...props }, ref) {
2237
2518
  return /* @__PURE__ */ jsxRuntime.jsxs(
2238
2519
  "span",
@@ -2902,7 +3183,7 @@ var Skeleton = react.forwardRef(function Skeleton2({ width = "100%", height = 16
2902
3183
  );
2903
3184
  });
2904
3185
  Skeleton.displayName = "Skeleton";
2905
- var KIND_ICON = {
3186
+ var KIND_ICON2 = {
2906
3187
  artifact: "ri-price-tag-3-line",
2907
3188
  pr: "ri-git-pull-request-line",
2908
3189
  commit: "ri-git-commit-line",
@@ -2957,7 +3238,7 @@ var CrossRefBadge = react.forwardRef(
2957
3238
  document.addEventListener("keydown", onKey);
2958
3239
  return () => document.removeEventListener("keydown", onKey);
2959
3240
  }, [open, close]);
2960
- const iconCls = KIND_ICON[kind];
3241
+ const iconCls = KIND_ICON2[kind];
2961
3242
  const chipColor = color ?? KIND_COLOR[kind];
2962
3243
  const inner = /* @__PURE__ */ jsxRuntime.jsxs(Chip, { color: chipColor, className: "klun-xref__chip", children: [
2963
3244
  /* @__PURE__ */ jsxRuntime.jsx("i", { className: chunkTPGAXYFU_cjs.cx("klun-xref__icon", iconCls), "aria-hidden": true }),
@@ -3347,6 +3628,98 @@ var DiffViewer = react.forwardRef(function DiffViewer2({
3347
3628
  );
3348
3629
  });
3349
3630
  DiffViewer.displayName = "DiffViewer";
3631
+ var ItemGroup = react.forwardRef(
3632
+ function ItemGroup2({ className, ...props }, ref) {
3633
+ return /* @__PURE__ */ jsxRuntime.jsx(
3634
+ "div",
3635
+ {
3636
+ ref,
3637
+ role: "list",
3638
+ className: chunkTPGAXYFU_cjs.cx("klun-item-group", className),
3639
+ ...props
3640
+ }
3641
+ );
3642
+ }
3643
+ );
3644
+ ItemGroup.displayName = "ItemGroup";
3645
+ var Item = react.forwardRef(function Item2({ variant = "default", size = "default", className, ...props }, ref) {
3646
+ return /* @__PURE__ */ jsxRuntime.jsx(
3647
+ "div",
3648
+ {
3649
+ ref,
3650
+ "data-variant": variant,
3651
+ "data-size": size,
3652
+ className: chunkTPGAXYFU_cjs.cx("klun-item", `klun-item--${variant}`, `klun-item--${size}`, className),
3653
+ ...props
3654
+ }
3655
+ );
3656
+ });
3657
+ Item.displayName = "Item";
3658
+ var ItemSeparator = react.forwardRef(
3659
+ function ItemSeparator2({ className, ...props }, ref) {
3660
+ return /* @__PURE__ */ jsxRuntime.jsx(
3661
+ "div",
3662
+ {
3663
+ ref,
3664
+ role: "separator",
3665
+ "aria-orientation": "horizontal",
3666
+ className: chunkTPGAXYFU_cjs.cx("klun-item-separator", className),
3667
+ ...props
3668
+ }
3669
+ );
3670
+ }
3671
+ );
3672
+ ItemSeparator.displayName = "ItemSeparator";
3673
+ var ItemMedia = react.forwardRef(
3674
+ function ItemMedia2({ variant = "default", className, ...props }, ref) {
3675
+ return /* @__PURE__ */ jsxRuntime.jsx(
3676
+ "div",
3677
+ {
3678
+ ref,
3679
+ "data-variant": variant,
3680
+ className: chunkTPGAXYFU_cjs.cx("klun-item__media", className),
3681
+ ...props
3682
+ }
3683
+ );
3684
+ }
3685
+ );
3686
+ ItemMedia.displayName = "ItemMedia";
3687
+ var ItemContent = react.forwardRef(
3688
+ function ItemContent2({ className, ...props }, ref) {
3689
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-item__content", className), ...props });
3690
+ }
3691
+ );
3692
+ ItemContent.displayName = "ItemContent";
3693
+ var ItemTitle = react.forwardRef(
3694
+ function ItemTitle2({ className, ...props }, ref) {
3695
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-item__title", className), ...props });
3696
+ }
3697
+ );
3698
+ ItemTitle.displayName = "ItemTitle";
3699
+ var ItemDescription = react.forwardRef(
3700
+ function ItemDescription2({ className, ...props }, ref) {
3701
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-item__description", className), ...props });
3702
+ }
3703
+ );
3704
+ ItemDescription.displayName = "ItemDescription";
3705
+ var ItemActions = react.forwardRef(
3706
+ function ItemActions2({ className, ...props }, ref) {
3707
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-item__actions", className), ...props });
3708
+ }
3709
+ );
3710
+ ItemActions.displayName = "ItemActions";
3711
+ var ItemHeader = react.forwardRef(
3712
+ function ItemHeader2({ className, ...props }, ref) {
3713
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-item__header", className), ...props });
3714
+ }
3715
+ );
3716
+ ItemHeader.displayName = "ItemHeader";
3717
+ var ItemFooter = react.forwardRef(
3718
+ function ItemFooter2({ className, ...props }, ref) {
3719
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-item__footer", className), ...props });
3720
+ }
3721
+ );
3722
+ ItemFooter.displayName = "ItemFooter";
3350
3723
  function draggedCenterY(active, delta) {
3351
3724
  const translated = active.rect.current.translated;
3352
3725
  if (translated) return translated.top + translated.height / 2;
@@ -3531,72 +3904,6 @@ function KanbanCardView({
3531
3904
  }
3532
3905
  );
3533
3906
  }
3534
- function VirtualTable({
3535
- rows = [],
3536
- columns = [],
3537
- rowHeight = 40,
3538
- height = 420,
3539
- getRowId,
3540
- onRowClick,
3541
- overscan = 8,
3542
- zebra = true,
3543
- empty,
3544
- className,
3545
- style,
3546
- ...props
3547
- }) {
3548
- const [scrollTop, setScrollTop] = react.useState(0);
3549
- const total = rows.length;
3550
- const template = react.useMemo(
3551
- () => columns.map((c) => c.width ? `${c.width}px` : "minmax(0, 1fr)").join(" "),
3552
- [columns]
3553
- );
3554
- const bodyHeight = Math.max(0, height - 36);
3555
- const start = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
3556
- const end = Math.min(total, Math.ceil((scrollTop + bodyHeight) / rowHeight) + overscan);
3557
- const slice = rows.slice(start, end);
3558
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: void 0, className: chunkTPGAXYFU_cjs.cx("klun-vtable", className), style: { ...style, height }, ...props, children: [
3559
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-vtable__head", style: { gridTemplateColumns: template }, children: columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkTPGAXYFU_cjs.cx("klun-vtable__th", c.align && `klun-vtable__th--${c.align}`), children: c.header }, c.key)) }),
3560
- /* @__PURE__ */ jsxRuntime.jsx(
3561
- "div",
3562
- {
3563
- className: "klun-vtable__body",
3564
- onScroll: (e) => setScrollTop(e.target.scrollTop),
3565
- style: { maxHeight: bodyHeight },
3566
- children: total === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-vtable__empty", children: empty ?? "No rows" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3567
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: start * rowHeight } }),
3568
- slice.map((row, i) => {
3569
- const index = start + i;
3570
- const id = getRowId?.(row, index) ?? index;
3571
- return /* @__PURE__ */ jsxRuntime.jsx(
3572
- "div",
3573
- {
3574
- role: onRowClick ? "button" : void 0,
3575
- tabIndex: onRowClick ? 0 : void 0,
3576
- onClick: () => onRowClick?.(row, index),
3577
- className: chunkTPGAXYFU_cjs.cx(
3578
- "klun-vtable__row",
3579
- zebra && index % 2 === 1 && "klun-vtable__row--zebra",
3580
- onRowClick && "klun-vtable__row--clickable"
3581
- ),
3582
- style: { gridTemplateColumns: template, height: rowHeight },
3583
- children: columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkTPGAXYFU_cjs.cx("klun-vtable__td", c.align && `klun-vtable__td--${c.align}`), children: c.render ? c.render(row, index) : String(row[c.key] ?? "") }, c.key))
3584
- },
3585
- id
3586
- );
3587
- }),
3588
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: Math.max(0, (total - end) * rowHeight) } })
3589
- ] })
3590
- }
3591
- ),
3592
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-vtable__foot", children: [
3593
- total.toLocaleString("en-US"),
3594
- " rows \xB7 rendering ",
3595
- slice.length
3596
- ] })
3597
- ] });
3598
- }
3599
- VirtualTable.displayName = "VirtualTable";
3600
3907
  var Kbd = react.forwardRef(function Kbd2({ className, children, ...props }, ref) {
3601
3908
  return /* @__PURE__ */ jsxRuntime.jsx("kbd", { ref, className: chunkTPGAXYFU_cjs.cx("klun-kbd", className), ...props, children });
3602
3909
  });
@@ -3757,8 +4064,91 @@ var ListItem = react.forwardRef(
3757
4064
  }
3758
4065
  );
3759
4066
  ListItem.displayName = "ListItem";
4067
+ var ListGrid = react.forwardRef(function ListGrid2({ columns, className, style, ...props }, ref) {
4068
+ return /* @__PURE__ */ jsxRuntime.jsx(
4069
+ "div",
4070
+ {
4071
+ ref,
4072
+ role: "table",
4073
+ className: chunkTPGAXYFU_cjs.cx("klun-list-grid", className),
4074
+ style: { gridTemplateColumns: columns, ...style },
4075
+ ...props
4076
+ }
4077
+ );
4078
+ });
4079
+ ListGrid.displayName = "ListGrid";
4080
+ var ListGridHeader = react.forwardRef(
4081
+ function ListGridHeader2({ className, children, ...props }, ref) {
4082
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, role: "row", className: chunkTPGAXYFU_cjs.cx("klun-list-grid__header", className), ...props, children: [
4083
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true" }),
4084
+ children,
4085
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true" })
4086
+ ] });
4087
+ }
4088
+ );
4089
+ ListGridHeader.displayName = "ListGridHeader";
4090
+ var ListGridBody = react.forwardRef(
4091
+ function ListGridBody2({ className, ...props }, ref) {
4092
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, role: "rowgroup", className: chunkTPGAXYFU_cjs.cx("klun-list-grid__body", className), ...props });
4093
+ }
4094
+ );
4095
+ ListGridBody.displayName = "ListGridBody";
4096
+ var ListGridHeaderCell = react.forwardRef(
4097
+ function ListGridHeaderCell2({ sorted = false, onSort, align = "left", className, children, ...props }, ref) {
4098
+ return /* @__PURE__ */ jsxRuntime.jsx(
4099
+ "div",
4100
+ {
4101
+ ref,
4102
+ role: "columnheader",
4103
+ "data-sorted": sorted ? "" : void 0,
4104
+ "data-align": align === "right" ? "right" : void 0,
4105
+ "aria-sort": sorted === "asc" ? "ascending" : sorted === "desc" ? "descending" : void 0,
4106
+ className: chunkTPGAXYFU_cjs.cx("klun-list-grid__header-cell", className),
4107
+ ...props,
4108
+ children: onSort ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "klun-list-grid__sort", onClick: onSort, children: [
4109
+ children,
4110
+ /* @__PURE__ */ jsxRuntime.jsx(
4111
+ "i",
4112
+ {
4113
+ "aria-hidden": "true",
4114
+ className: chunkTPGAXYFU_cjs.cx(
4115
+ "klun-list-grid__sort-icon",
4116
+ sorted === "asc" ? "ri-arrow-up-s-line" : "ri-arrow-down-s-line"
4117
+ )
4118
+ }
4119
+ )
4120
+ ] }) : children
4121
+ }
4122
+ );
4123
+ }
4124
+ );
4125
+ ListGridHeaderCell.displayName = "ListGridHeaderCell";
4126
+ var ListGridRow = react.forwardRef(
4127
+ function ListGridRow2({ className, children, ...props }, ref) {
4128
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, role: "row", className: chunkTPGAXYFU_cjs.cx("klun-list-grid__row", className), ...props, children: [
4129
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true" }),
4130
+ children,
4131
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true" })
4132
+ ] });
4133
+ }
4134
+ );
4135
+ ListGridRow.displayName = "ListGridRow";
4136
+ var ListGridCell = react.forwardRef(
4137
+ function ListGridCell2({ className, ...props }, ref) {
4138
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, role: "cell", className: chunkTPGAXYFU_cjs.cx("klun-list-grid__cell", className), ...props });
4139
+ }
4140
+ );
4141
+ ListGridCell.displayName = "ListGridCell";
4142
+ var LIST_GRID_BOTTOM_CLEARANCE = 64;
3760
4143
  var k = 0;
3761
4144
  var wikiResolve;
4145
+ function safeUrl(value, image = false) {
4146
+ const normalized = value.replace(/[\u0000-\u0020]/g, "");
4147
+ const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(normalized)?.[1].toLowerCase();
4148
+ if (!scheme || ["http", "https", ...image ? ["blob"] : ["mailto", "tel"]].includes(scheme)) return value;
4149
+ if (image && /^data:image\/(png|jpeg|gif|webp|svg\+xml)[;,]/i.test(normalized)) return value;
4150
+ return void 0;
4151
+ }
3762
4152
  function inline(text) {
3763
4153
  const patterns = [
3764
4154
  // [[wiki link]] / [[target|label]] — resolved via the wikiLink prop; falls
@@ -3770,20 +4160,20 @@ function inline(text) {
3770
4160
  const r = wikiResolve?.(target);
3771
4161
  const resolved = typeof r === "string" ? { href: r, label: void 0 } : r || null;
3772
4162
  const label = m[2]?.trim() || resolved?.label || target;
3773
- return resolved ? /* @__PURE__ */ jsxRuntime.jsx("a", { className: "klun-md-wikilink", href: resolved.href, children: label }, k++) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-md-wikilink klun-md-wikilink--broken", children: label }, k++);
4163
+ return resolved && safeUrl(resolved.href) ? /* @__PURE__ */ jsxRuntime.jsx("a", { className: "klun-md-wikilink", href: safeUrl(resolved.href), children: label }, k++) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-md-wikilink klun-md-wikilink--broken", children: label }, k++);
3774
4164
  }
3775
4165
  },
3776
4166
  { re: /`([^`]+)`/, node: (m) => /* @__PURE__ */ jsxRuntime.jsx("code", { className: "klun-md-code", children: m[1] }, k++) },
3777
4167
  // image before link (`![alt](url)` starts with `!` + link syntax). url allows
3778
4168
  // http(s) and data: URIs (base64 has no `)`), so pasted screenshots embed inline.
3779
- { re: /!\[([^\]]*)\]\(([^)]+)\)/, node: (m) => /* @__PURE__ */ jsxRuntime.jsx("img", { className: "klun-md-img", src: m[2], alt: m[1] }, k++) },
4169
+ { re: /!\[([^\]]*)\]\(([^)]+)\)/, node: (m) => /* @__PURE__ */ jsxRuntime.jsx("img", { className: "klun-md-img", src: safeUrl(m[2], true), alt: m[1] }, k++) },
3780
4170
  { re: /\*\*([^*]+)\*\*/, node: (m) => /* @__PURE__ */ jsxRuntime.jsx("strong", { children: inline(m[1]) }, k++) },
3781
4171
  { re: /~~([^~]+)~~/, node: (m) => /* @__PURE__ */ jsxRuntime.jsx("del", { children: inline(m[1]) }, k++) },
3782
4172
  { re: /\*([^*]+)\*/, node: (m) => /* @__PURE__ */ jsxRuntime.jsx("em", { children: inline(m[1]) }, k++) },
3783
4173
  { re: /<u>([\s\S]*?)<\/u>/, node: (m) => /* @__PURE__ */ jsxRuntime.jsx("u", { children: inline(m[1]) }, k++) },
3784
4174
  {
3785
4175
  re: /\[([^\]]+)\]\(([^)]+)\)/,
3786
- node: (m) => /* @__PURE__ */ jsxRuntime.jsx("a", { href: m[2], target: "_blank", rel: "noreferrer", children: m[1] }, k++)
4176
+ node: (m) => /* @__PURE__ */ jsxRuntime.jsx("a", { href: safeUrl(m[2]), target: "_blank", rel: "noreferrer", children: m[1] }, k++)
3787
4177
  },
3788
4178
  // bare autolink: a plain http(s) URL becomes a link. Runs after the
3789
4179
  // [text](url)/image patterns — those start at an earlier index (the `[`/`!`)
@@ -3984,36 +4374,888 @@ var Money = react.forwardRef(function Money2({
3984
4374
  );
3985
4375
  });
3986
4376
  Money.displayName = "Money";
3987
- var Rating = react.forwardRef(function Rating2({ value = 0, max = 5, onChange, readOnly = false, size = 20, className, ...props }, ref) {
3988
- const { rating } = useLocale();
3989
- const [hover, setHover] = react.useState(0);
3990
- const active = hover || value;
3991
- return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-rating", className), ...props, children: Array.from({ length: max }, (_, i) => i + 1).map((i) => /* @__PURE__ */ jsxRuntime.jsx(
3992
- "button",
4377
+ var DIGITS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
4378
+ function Digit({ value }) {
4379
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-number-flow__digit", children: /* @__PURE__ */ jsxRuntime.jsx(
4380
+ "span",
3993
4381
  {
3994
- type: "button",
3995
- className: "klun-rating__star",
3996
- disabled: readOnly,
3997
- "data-active": i <= active ? "" : void 0,
3998
- onMouseEnter: () => !readOnly && setHover(i),
3999
- onMouseLeave: () => !readOnly && setHover(0),
4000
- onClick: () => !readOnly && onChange?.(i),
4001
- "aria-label": fmt(rating.star, { count: i }),
4002
- children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2l2.9 6.1 6.6.9-4.8 4.6 1.2 6.6L12 17.8 5.9 20.8l1.2-6.6L2.3 9l6.6-.9L12 2z" }) })
4003
- },
4004
- i
4005
- )) });
4006
- });
4007
- Rating.displayName = "Rating";
4008
- var StatCard = react.forwardRef(function StatCard2({ label, value, delta, trend = "up", icon, tint = "feature", className, ...props }, ref) {
4009
- const up = trend === "up";
4010
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-stat-card", `klun-stat-card--${tint}`, className), ...props, children: [
4011
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-stat-card__head", children: [
4012
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-stat-card__icon", children: icon }),
4013
- delta != null ? /* @__PURE__ */ jsxRuntime.jsxs(
4014
- "span",
4015
- {
4016
- className: chunkTPGAXYFU_cjs.cx(
4382
+ className: "klun-number-flow__track",
4383
+ style: { transform: `translateY(${-value}em)` },
4384
+ children: DIGITS.map((d) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-number-flow__num", children: d }, d))
4385
+ }
4386
+ ) });
4387
+ }
4388
+ var NumberFlow = react.forwardRef(
4389
+ function NumberFlow2({ value, locales: locales2, format, prefix, suffix, label, className, ...props }, ref) {
4390
+ const text = new Intl.NumberFormat(locales2, {
4391
+ minimumFractionDigits: format?.minimumFractionDigits,
4392
+ maximumFractionDigits: format?.maximumFractionDigits,
4393
+ useGrouping: format?.useGrouping
4394
+ }).format(value);
4395
+ const chars = [...text];
4396
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4397
+ "span",
4398
+ {
4399
+ ref,
4400
+ className: chunkTPGAXYFU_cjs.cx("klun-number-flow", className),
4401
+ "aria-label": label ?? text,
4402
+ ...props,
4403
+ children: [
4404
+ prefix != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-number-flow__affix", children: prefix }),
4405
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-number-flow__visual", "aria-hidden": "true", children: chars.map(
4406
+ (ch, i) => ch >= "0" && ch <= "9" ? /* @__PURE__ */ jsxRuntime.jsx(Digit, { value: Number(ch) }, chars.length - i) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-number-flow__char", children: ch }, chars.length - i)
4407
+ ) }),
4408
+ suffix != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-number-flow__affix", children: suffix })
4409
+ ]
4410
+ }
4411
+ );
4412
+ }
4413
+ );
4414
+ NumberFlow.displayName = "NumberFlow";
4415
+ var CurrencyNumberFlow = react.forwardRef(
4416
+ function CurrencyNumberFlow2({ value, prefix = "$", fractionThreshold = 100, locales: locales2, label, ...props }, ref) {
4417
+ const fractionDigits = Math.abs(value) >= fractionThreshold ? 0 : 2;
4418
+ const format = {
4419
+ minimumFractionDigits: fractionDigits,
4420
+ maximumFractionDigits: fractionDigits,
4421
+ useGrouping: false
4422
+ };
4423
+ const formatted = new Intl.NumberFormat(locales2, format).format(value);
4424
+ return /* @__PURE__ */ jsxRuntime.jsx(
4425
+ NumberFlow,
4426
+ {
4427
+ ref,
4428
+ value,
4429
+ locales: locales2,
4430
+ prefix,
4431
+ format,
4432
+ label: label ?? `${prefix}${formatted}`,
4433
+ ...props
4434
+ }
4435
+ );
4436
+ }
4437
+ );
4438
+ CurrencyNumberFlow.displayName = "CurrencyNumberFlow";
4439
+ var COMPACT_UNITS = [
4440
+ { divisor: 1, upperSuffix: void 0, lowerSuffix: void 0 },
4441
+ { divisor: 1e3, upperSuffix: "K", lowerSuffix: "k" },
4442
+ { divisor: 1e6, upperSuffix: "M", lowerSuffix: "m" },
4443
+ { divisor: 1e9, upperSuffix: "B", lowerSuffix: "b" },
4444
+ { divisor: 1e12, upperSuffix: "T", lowerSuffix: "t" }
4445
+ ];
4446
+ var CompactNumberFlow = react.forwardRef(
4447
+ function CompactNumberFlow2({ value, suffixCase = "upper", locales: locales2, label, ...props }, ref) {
4448
+ const magnitude = Math.abs(value);
4449
+ let unitIndex = 0;
4450
+ for (let i = COMPACT_UNITS.length - 1; i >= 0; i--) {
4451
+ if (magnitude >= COMPACT_UNITS[i].divisor) {
4452
+ unitIndex = i;
4453
+ break;
4454
+ }
4455
+ }
4456
+ let unit = COMPACT_UNITS[unitIndex];
4457
+ let scaledValue = value / unit.divisor;
4458
+ if (Math.abs(Number(scaledValue.toFixed(1))) >= 1e3 && unitIndex < COMPACT_UNITS.length - 1) {
4459
+ unit = COMPACT_UNITS[unitIndex + 1];
4460
+ scaledValue = value / unit.divisor;
4461
+ }
4462
+ const roundedValue = Number(scaledValue.toFixed(1));
4463
+ const fractionDigits = unit.divisor > 1 && !Number.isInteger(roundedValue) ? 1 : 0;
4464
+ const suffix = suffixCase === "upper" ? unit.upperSuffix : unit.lowerSuffix;
4465
+ const format = {
4466
+ minimumFractionDigits: fractionDigits,
4467
+ maximumFractionDigits: fractionDigits,
4468
+ useGrouping: unit.divisor === 1
4469
+ };
4470
+ const formatted = new Intl.NumberFormat(locales2, format).format(scaledValue);
4471
+ return /* @__PURE__ */ jsxRuntime.jsx(
4472
+ NumberFlow,
4473
+ {
4474
+ ref,
4475
+ value: scaledValue,
4476
+ locales: locales2,
4477
+ suffix,
4478
+ format,
4479
+ label: label ?? `${formatted}${suffix ?? ""}`,
4480
+ ...props
4481
+ }
4482
+ );
4483
+ }
4484
+ );
4485
+ CompactNumberFlow.displayName = "CompactNumberFlow";
4486
+ var CappedNumberFlow = react.forwardRef(
4487
+ function CappedNumberFlow2({ value, max = 99, label, ...props }, ref) {
4488
+ const cappedValue = Math.min(Math.max(value, 0), max);
4489
+ return /* @__PURE__ */ jsxRuntime.jsx(
4490
+ NumberFlow,
4491
+ {
4492
+ ref,
4493
+ value: cappedValue,
4494
+ suffix: value > max ? "+" : void 0,
4495
+ format: { maximumFractionDigits: 0, useGrouping: false },
4496
+ label: label ?? String(value),
4497
+ ...props
4498
+ }
4499
+ );
4500
+ }
4501
+ );
4502
+ CappedNumberFlow.displayName = "CappedNumberFlow";
4503
+ var Rating = react.forwardRef(function Rating2({ value = 0, max = 5, onChange, readOnly = false, size = 20, className, ...props }, ref) {
4504
+ const { rating } = useLocale();
4505
+ const [hover, setHover] = react.useState(0);
4506
+ const active = hover || value;
4507
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-rating", className), ...props, children: Array.from({ length: max }, (_, i) => i + 1).map((i) => /* @__PURE__ */ jsxRuntime.jsx(
4508
+ "button",
4509
+ {
4510
+ type: "button",
4511
+ className: "klun-rating__star",
4512
+ disabled: readOnly,
4513
+ "data-active": i <= active ? "" : void 0,
4514
+ onMouseEnter: () => !readOnly && setHover(i),
4515
+ onMouseLeave: () => !readOnly && setHover(0),
4516
+ onClick: () => !readOnly && onChange?.(i),
4517
+ "aria-label": fmt(rating.star, { count: i }),
4518
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2l2.9 6.1 6.6.9-4.8 4.6 1.2 6.6L12 17.8 5.9 20.8l1.2-6.6L2.3 9l6.6-.9L12 2z" }) })
4519
+ },
4520
+ i
4521
+ )) });
4522
+ });
4523
+ Rating.displayName = "Rating";
4524
+ var Popover = react.forwardRef(function Popover2({ trigger, children, align = "left", width = 280, className, ...props }, ref) {
4525
+ const [open, setOpen] = react.useState(false);
4526
+ const wrapRef = react.useRef(null);
4527
+ const panelRef = react.useRef(null);
4528
+ const portal = typeof document !== "undefined";
4529
+ const [pos, setPos] = react.useState(null);
4530
+ react.useEffect(() => {
4531
+ if (!open) return;
4532
+ const h = (e) => {
4533
+ const t = e.target;
4534
+ if (wrapRef.current?.contains(t)) return;
4535
+ if (panelRef.current?.contains(t)) return;
4536
+ setOpen(false);
4537
+ };
4538
+ document.addEventListener("mousedown", h);
4539
+ return () => document.removeEventListener("mousedown", h);
4540
+ }, [open]);
4541
+ react.useLayoutEffect(() => {
4542
+ if (!open || !portal) return;
4543
+ const anchor = wrapRef.current;
4544
+ const panel2 = panelRef.current;
4545
+ if (!anchor || !panel2) return;
4546
+ const place2 = () => {
4547
+ const a = anchor.getBoundingClientRect();
4548
+ const gap = 8;
4549
+ const margin = 8;
4550
+ const pw = panel2.offsetWidth || width;
4551
+ const ph = panel2.offsetHeight;
4552
+ const below = window.innerHeight - a.bottom;
4553
+ const openUp = below < ph + gap && a.top > below;
4554
+ const top = openUp ? Math.max(margin, a.top - gap - ph) : Math.min(a.bottom + gap, window.innerHeight - margin - ph);
4555
+ let left = align === "right" ? a.right - pw : a.left;
4556
+ if (left + pw > window.innerWidth - margin) left = window.innerWidth - margin - pw;
4557
+ if (left < margin) left = margin;
4558
+ setPos({ left, top });
4559
+ };
4560
+ place2();
4561
+ window.addEventListener("scroll", place2, true);
4562
+ window.addEventListener("resize", place2);
4563
+ return () => {
4564
+ window.removeEventListener("scroll", place2, true);
4565
+ window.removeEventListener("resize", place2);
4566
+ };
4567
+ }, [open, portal, align, width]);
4568
+ react.useEffect(() => {
4569
+ if (!open) setPos(null);
4570
+ }, [open]);
4571
+ const setRefs = (node) => {
4572
+ wrapRef.current = node;
4573
+ if (typeof ref === "function") ref(node);
4574
+ else if (ref) ref.current = node;
4575
+ };
4576
+ const content = typeof children === "function" ? children(() => setOpen(false)) : children;
4577
+ const portalStyle = {
4578
+ position: "fixed",
4579
+ left: pos?.left ?? 0,
4580
+ top: pos?.top ?? 0,
4581
+ width,
4582
+ zIndex: 1150,
4583
+ // keep hidden until measured to avoid a flash at the top-left corner
4584
+ visibility: pos ? "visible" : "hidden"
4585
+ };
4586
+ const panel = open ? /* @__PURE__ */ jsxRuntime.jsx(
4587
+ "div",
4588
+ {
4589
+ ref: panelRef,
4590
+ role: "dialog",
4591
+ className: chunkTPGAXYFU_cjs.cx(
4592
+ "klun-popover__panel",
4593
+ // in-flow fallback keeps the legacy left/right anchoring classes
4594
+ !portal && `klun-popover__panel--${align}`
4595
+ ),
4596
+ style: portal ? portalStyle : { width },
4597
+ children: content
4598
+ }
4599
+ ) : null;
4600
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { ref: setRefs, className: chunkTPGAXYFU_cjs.cx("klun-popover", className), ...props, children: [
4601
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-popover__trigger", onClick: () => setOpen((o) => !o), children: trigger }),
4602
+ portal ? panel && reactDom.createPortal(panel, document.body) : panel
4603
+ ] });
4604
+ });
4605
+ Popover.displayName = "Popover";
4606
+
4607
+ // src/components/forms/emoji-data.ts
4608
+ var EMOJI_GROUPS = [
4609
+ {
4610
+ id: "people",
4611
+ label: "Smileys & people",
4612
+ emojis: [
4613
+ { emoji: "\u{1F600}", name: "Grinning Face", keywords: ["smile", "happy", "joy", ":D"] },
4614
+ { emoji: "\u{1F603}", name: "Grinning Face with Big Eyes", keywords: ["smiley", "happy", "joy", "haha"] },
4615
+ { emoji: "\u{1F604}", name: "Grinning Face with Smiling Eyes", keywords: ["smile", "happy", "joy", "funny"] },
4616
+ { emoji: "\u{1F601}", name: "Beaming Face with Smiling Eyes", keywords: ["grin", "happy", "smile", "joy"] },
4617
+ { emoji: "\u{1F606}", name: "Grinning Squinting Face", keywords: ["laughing", "satisfied", "happy", "joy"] },
4618
+ { emoji: "\u{1F605}", name: "Grinning Face with Sweat", keywords: ["smile", "hot", "happy", "laugh"] },
4619
+ { emoji: "\u{1F923}", name: "Rolling on the Floor Laughing", keywords: ["face", "lol", "haha", "rofl"] },
4620
+ { emoji: "\u{1F602}", name: "Face with Tears of Joy", keywords: ["cry", "weep", "happy", "happytears"] },
4621
+ { emoji: "\u{1F642}", name: "Slightly Smiling Face", keywords: ["smile"] },
4622
+ { emoji: "\u{1F643}", name: "Upside-Down Face", keywords: ["upside", "down", "flipped", "silly"] },
4623
+ { emoji: "\u{1FAE0}", name: "Melting Face", keywords: ["hot", "heat"] },
4624
+ { emoji: "\u{1F609}", name: "Winking Face", keywords: ["wink", "happy", "mischievous", "secret"] },
4625
+ { emoji: "\u{1F60A}", name: "Smiling Face with Smiling Eyes", keywords: ["blush", "smile", "happy", "flushed"] },
4626
+ { emoji: "\u{1F607}", name: "Smiling Face with Halo", keywords: ["innocent", "angel", "heaven"] },
4627
+ { emoji: "\u{1F970}", name: "Smiling Face with Hearts", keywords: ["3", "love", "like", "affection"] },
4628
+ { emoji: "\u{1F60D}", name: "Smiling Face with Heart-Eyes", keywords: ["heart", "eyes", "love", "like"] },
4629
+ { emoji: "\u{1F929}", name: "Star-Struck", keywords: ["star", "struck", "grinning", "face"] },
4630
+ { emoji: "\u{1F618}", name: "Face Blowing a Kiss", keywords: ["kissing", "heart", "love", "like"] },
4631
+ { emoji: "\u{1F617}", name: "Kissing Face", keywords: ["love", "like", "3", "valentines"] },
4632
+ { emoji: "\u263A\uFE0F", name: "Smiling Face", keywords: ["relaxed", "blush", "massage", "happiness"] },
4633
+ { emoji: "\u{1F61A}", name: "Kissing Face with Closed Eyes", keywords: ["love", "like", "affection", "valentines"] },
4634
+ { emoji: "\u{1F619}", name: "Kissing Face with Smiling Eyes", keywords: ["affection", "valentines", "infatuation", "kiss"] },
4635
+ { emoji: "\u{1F972}", name: "Smiling Face with Tear", keywords: ["sad", "cry", "pretend"] },
4636
+ { emoji: "\u{1F60B}", name: "Face Savoring Food", keywords: ["yum", "happy", "joy", "tongue"] },
4637
+ { emoji: "\u{1F61B}", name: "Face with Tongue", keywords: ["stuck", "out", "prank", "childish"] },
4638
+ { emoji: "\u{1F61C}", name: "Winking Face with Tongue", keywords: ["stuck", "out", "eye", "prank"] },
4639
+ { emoji: "\u{1F92A}", name: "Zany Face", keywords: ["grinning", "with", "one", "large"] },
4640
+ { emoji: "\u{1F61D}", name: "Squinting Face with Tongue", keywords: ["stuck", "out", "closed", "eyes"] },
4641
+ { emoji: "\u{1F911}", name: "Money-Mouth Face", keywords: ["money", "mouth", "rich", "dollar"] },
4642
+ { emoji: "\u{1F917}", name: "Hugging Face", keywords: ["smile", "hug"] },
4643
+ { emoji: "\u{1F92D}", name: "Face with Hand over Mouth", keywords: ["smiling", "eyes", "and", "covering"] },
4644
+ { emoji: "\u{1FAE2}", name: "Face with Open Eyes and Hand over Mouth", keywords: ["silence", "secret", "shock", "surprise"] },
4645
+ { emoji: "\u{1FAE3}", name: "Face with Peeking Eye", keywords: ["scared", "frightening", "embarrassing", "shy"] },
4646
+ { emoji: "\u{1F92B}", name: "Shushing Face", keywords: ["with", "finger", "covering", "closed"] },
4647
+ { emoji: "\u{1F914}", name: "Thinking Face", keywords: ["hmmm", "think", "consider"] },
4648
+ { emoji: "\u{1FAE1}", name: "Saluting Face", keywords: ["respect", "salute"] },
4649
+ { emoji: "\u{1F910}", name: "Zipper-Mouth Face", keywords: ["zipper", "mouth", "sealed", "secret"] },
4650
+ { emoji: "\u{1F928}", name: "Face with Raised Eyebrow", keywords: ["one", "distrust", "scepticism", "disapproval"] },
4651
+ { emoji: "\u{1F610}", name: "Neutral Face", keywords: ["indifference", "meh", ":", ""] },
4652
+ { emoji: "\u{1F611}", name: "Expressionless Face", keywords: ["indifferent", "-", "", "meh"] },
4653
+ { emoji: "\u{1F636}", name: "Face Without Mouth", keywords: ["no", "hellokitty"] },
4654
+ { emoji: "\u{1FAE5}", name: "Dotted Line Face", keywords: ["invisible", "lonely", "isolation", "depression"] },
4655
+ { emoji: "\u{1F636}\u200D\u{1F32B}\uFE0F", name: "Face in Clouds", keywords: ["shower", "steam", "dream"] },
4656
+ { emoji: "\u{1F60F}", name: "Smirking Face", keywords: ["smirk", "smile", "mean", "prank"] },
4657
+ { emoji: "\u{1F612}", name: "Unamused Face", keywords: ["indifference", "bored", "straight", "serious"] },
4658
+ { emoji: "\u{1F644}", name: "Face with Rolling Eyes", keywords: ["eyeroll", "frustrated"] },
4659
+ { emoji: "\u{1F62C}", name: "Grimacing Face", keywords: ["grimace", "teeth"] },
4660
+ { emoji: "\u{1F62E}\u200D\u{1F4A8}", name: "Face Exhaling", keywords: ["relieve", "relief", "tired", "sigh"] },
4661
+ { emoji: "\u{1F925}", name: "Lying Face", keywords: ["lie", "pinocchio"] },
4662
+ { emoji: "\u{1FAE8}", name: "Shaking Face", keywords: ["dizzy", "shock", "blurry", "earthquake"] },
4663
+ { emoji: "\u{1F60C}", name: "Relieved Face", keywords: ["relaxed", "phew", "massage", "happiness"] },
4664
+ { emoji: "\u{1F614}", name: "Pensive Face", keywords: ["sad", "depressed", "upset"] },
4665
+ { emoji: "\u{1F62A}", name: "Sleepy Face", keywords: ["tired", "rest", "nap"] },
4666
+ { emoji: "\u{1F924}", name: "Drooling Face", keywords: [] },
4667
+ { emoji: "\u{1F634}", name: "Sleeping Face", keywords: ["tired", "sleepy", "night", "zzz"] },
4668
+ { emoji: "\u{1F637}", name: "Face with Medical Mask", keywords: ["sick", "ill", "disease", "covid"] },
4669
+ { emoji: "\u{1F912}", name: "Face with Thermometer", keywords: ["sick", "temperature", "cold", "fever"] },
4670
+ { emoji: "\u{1F915}", name: "Face with Head-Bandage", keywords: ["head", "bandage", "injured", "clumsy"] },
4671
+ { emoji: "\u{1F922}", name: "Nauseated Face", keywords: ["vomit", "gross", "green", "sick"] },
4672
+ { emoji: "\u{1F92E}", name: "Face Vomiting", keywords: ["with", "open", "mouth", "sick"] },
4673
+ { emoji: "\u{1F927}", name: "Sneezing Face", keywords: ["gesundheit", "sneeze", "sick", "allergy"] },
4674
+ { emoji: "\u{1F975}", name: "Hot Face", keywords: ["feverish", "heat", "red", "sweating"] },
4675
+ { emoji: "\u{1F976}", name: "Cold Face", keywords: ["blue", "freezing", "frozen", "frostbite"] },
4676
+ { emoji: "\u{1F974}", name: "Woozy Face", keywords: ["dizzy", "intoxicated", "tipsy", "wavy"] }
4677
+ ]
4678
+ },
4679
+ {
4680
+ id: "nature",
4681
+ label: "Animals & nature",
4682
+ emojis: [
4683
+ { emoji: "\u{1F435}", name: "Monkey Face", keywords: ["animal", "nature", "circus"] },
4684
+ { emoji: "\u{1F412}", name: "Monkey", keywords: ["animal", "nature", "banana", "circus"] },
4685
+ { emoji: "\u{1F98D}", name: "Gorilla", keywords: ["animal", "nature", "circus"] },
4686
+ { emoji: "\u{1F9A7}", name: "Orangutan", keywords: ["animal"] },
4687
+ { emoji: "\u{1F436}", name: "Dog Face", keywords: ["animal", "friend", "nature", "woof"] },
4688
+ { emoji: "\u{1F415}", name: "Dog", keywords: ["dog2", "animal", "nature", "friend"] },
4689
+ { emoji: "\u{1F9AE}", name: "Guide Dog", keywords: ["animal", "blind"] },
4690
+ { emoji: "\u{1F415}\u200D\u{1F9BA}", name: "Service Dog", keywords: ["blind", "animal"] },
4691
+ { emoji: "\u{1F429}", name: "Poodle", keywords: ["dog", "animal", "101", "nature"] },
4692
+ { emoji: "\u{1F43A}", name: "Wolf", keywords: ["animal", "nature", "wild"] },
4693
+ { emoji: "\u{1F98A}", name: "Fox", keywords: ["face", "animal", "nature"] },
4694
+ { emoji: "\u{1F99D}", name: "Raccoon", keywords: ["animal", "nature"] },
4695
+ { emoji: "\u{1F431}", name: "Cat Face", keywords: ["animal", "meow", "nature", "pet"] },
4696
+ { emoji: "\u{1F408}", name: "Cat", keywords: ["cat2", "animal", "meow", "pet"] },
4697
+ { emoji: "\u{1F408}\u200D\u2B1B", name: "Black Cat", keywords: ["superstition", "luck"] },
4698
+ { emoji: "\u{1F981}", name: "Lion", keywords: ["face", "animal", "nature"] },
4699
+ { emoji: "\u{1F42F}", name: "Tiger Face", keywords: ["animal", "cat", "danger", "wild"] },
4700
+ { emoji: "\u{1F405}", name: "Tiger", keywords: ["tiger2", "animal", "nature", "roar"] },
4701
+ { emoji: "\u{1F406}", name: "Leopard", keywords: ["animal", "nature"] },
4702
+ { emoji: "\u{1F434}", name: "Horse Face", keywords: ["animal", "brown", "nature"] },
4703
+ { emoji: "\u{1FACE}", name: "Moose", keywords: ["shrek", "canada", "sweden", "sven"] },
4704
+ { emoji: "\u{1FACF}", name: "Donkey", keywords: ["eeyore", "mule"] },
4705
+ { emoji: "\u{1F40E}", name: "Horse", keywords: ["racehorse", "animal", "gamble", "luck"] },
4706
+ { emoji: "\u{1F984}", name: "Unicorn", keywords: ["face", "animal", "nature", "mystical"] },
4707
+ { emoji: "\u{1F993}", name: "Zebra", keywords: ["face", "animal", "nature", "stripes"] },
4708
+ { emoji: "\u{1F98C}", name: "Deer", keywords: ["animal", "nature", "horns", "venison"] },
4709
+ { emoji: "\u{1F9AC}", name: "Bison", keywords: ["ox"] },
4710
+ { emoji: "\u{1F42E}", name: "Cow Face", keywords: ["beef", "ox", "animal", "nature"] },
4711
+ { emoji: "\u{1F402}", name: "Ox", keywords: ["animal", "cow", "beef"] },
4712
+ { emoji: "\u{1F403}", name: "Water Buffalo", keywords: ["animal", "nature", "ox", "cow"] },
4713
+ { emoji: "\u{1F404}", name: "Cow", keywords: ["cow2", "beef", "ox", "animal"] },
4714
+ { emoji: "\u{1F437}", name: "Pig Face", keywords: ["animal", "oink", "nature"] },
4715
+ { emoji: "\u{1F416}", name: "Pig", keywords: ["pig2", "animal", "nature"] },
4716
+ { emoji: "\u{1F417}", name: "Boar", keywords: ["animal", "nature"] },
4717
+ { emoji: "\u{1F43D}", name: "Pig Nose", keywords: ["animal", "oink"] },
4718
+ { emoji: "\u{1F40F}", name: "Ram", keywords: ["animal", "sheep", "nature"] },
4719
+ { emoji: "\u{1F411}", name: "Ewe", keywords: ["sheep", "animal", "nature", "wool"] },
4720
+ { emoji: "\u{1F410}", name: "Goat", keywords: ["animal", "nature"] },
4721
+ { emoji: "\u{1F42A}", name: "Camel", keywords: ["dromedary", "animal", "hot", "desert"] },
4722
+ { emoji: "\u{1F42B}", name: "Bactrian Camel", keywords: ["two", "hump", "animal", "nature"] }
4723
+ ]
4724
+ },
4725
+ {
4726
+ id: "foods",
4727
+ label: "Food & drink",
4728
+ emojis: [
4729
+ { emoji: "\u{1F347}", name: "Grapes", keywords: ["fruit", "food", "wine"] },
4730
+ { emoji: "\u{1F348}", name: "Melon", keywords: ["fruit", "nature", "food"] },
4731
+ { emoji: "\u{1F349}", name: "Watermelon", keywords: ["fruit", "food", "picnic", "summer"] },
4732
+ { emoji: "\u{1F34A}", name: "Tangerine", keywords: ["food", "fruit", "nature", "orange"] },
4733
+ { emoji: "\u{1F34B}", name: "Lemon", keywords: ["fruit", "nature"] },
4734
+ { emoji: "\u{1F34C}", name: "Banana", keywords: ["fruit", "food", "monkey"] },
4735
+ { emoji: "\u{1F34D}", name: "Pineapple", keywords: ["fruit", "nature", "food"] },
4736
+ { emoji: "\u{1F96D}", name: "Mango", keywords: ["fruit", "food", "tropical"] },
4737
+ { emoji: "\u{1F34E}", name: "Red Apple", keywords: ["fruit", "mac", "school"] },
4738
+ { emoji: "\u{1F34F}", name: "Green Apple", keywords: ["fruit", "nature"] },
4739
+ { emoji: "\u{1F350}", name: "Pear", keywords: ["fruit", "nature", "food"] },
4740
+ { emoji: "\u{1F351}", name: "Peach", keywords: ["fruit", "nature", "food"] },
4741
+ { emoji: "\u{1F352}", name: "Cherries", keywords: ["food", "fruit"] },
4742
+ { emoji: "\u{1F353}", name: "Strawberry", keywords: ["fruit", "food", "nature"] },
4743
+ { emoji: "\u{1FAD0}", name: "Blueberries", keywords: ["fruit"] },
4744
+ { emoji: "\u{1F95D}", name: "Kiwifruit", keywords: ["kiwi", "fruit", "food"] },
4745
+ { emoji: "\u{1F345}", name: "Tomato", keywords: ["fruit", "vegetable", "nature", "food"] },
4746
+ { emoji: "\u{1FAD2}", name: "Olive", keywords: ["fruit"] },
4747
+ { emoji: "\u{1F965}", name: "Coconut", keywords: ["fruit", "nature", "food", "palm"] },
4748
+ { emoji: "\u{1F951}", name: "Avocado", keywords: ["fruit", "food"] },
4749
+ { emoji: "\u{1F346}", name: "Eggplant", keywords: ["vegetable", "nature", "food", "aubergine"] },
4750
+ { emoji: "\u{1F954}", name: "Potato", keywords: ["food", "tuber", "vegatable", "starch"] },
4751
+ { emoji: "\u{1F955}", name: "Carrot", keywords: ["vegetable", "food", "orange"] },
4752
+ { emoji: "\u{1F33D}", name: "Ear of Corn", keywords: ["food", "vegetable", "plant"] },
4753
+ { emoji: "\u{1F336}\uFE0F", name: "Hot Pepper", keywords: ["food", "spicy", "chilli", "chili"] },
4754
+ { emoji: "\u{1FAD1}", name: "Bell Pepper", keywords: ["fruit", "plant"] },
4755
+ { emoji: "\u{1F952}", name: "Cucumber", keywords: ["fruit", "food", "pickle"] },
4756
+ { emoji: "\u{1F96C}", name: "Leafy Green", keywords: ["food", "vegetable", "plant", "bok"] },
4757
+ { emoji: "\u{1F966}", name: "Broccoli", keywords: ["fruit", "food", "vegetable"] },
4758
+ { emoji: "\u{1F9C4}", name: "Garlic", keywords: ["food", "spice", "cook"] },
4759
+ { emoji: "\u{1F9C5}", name: "Onion", keywords: ["cook", "food", "spice"] },
4760
+ { emoji: "\u{1F95C}", name: "Peanuts", keywords: ["food", "nut"] },
4761
+ { emoji: "\u{1FAD8}", name: "Beans", keywords: ["food"] },
4762
+ { emoji: "\u{1F330}", name: "Chestnut", keywords: ["food", "squirrel"] },
4763
+ { emoji: "\u{1FADA}", name: "Ginger Root", keywords: ["spice", "yellow", "cooking", "gingerbread"] },
4764
+ { emoji: "\u{1FADB}", name: "Pea Pod", keywords: ["cozy", "green"] },
4765
+ { emoji: "\u{1F35E}", name: "Bread", keywords: ["food", "wheat", "breakfast", "toast"] },
4766
+ { emoji: "\u{1F950}", name: "Croissant", keywords: ["food", "bread", "french"] },
4767
+ { emoji: "\u{1F956}", name: "Baguette Bread", keywords: ["food", "french", "france", "bakery"] },
4768
+ { emoji: "\u{1FAD3}", name: "Flatbread", keywords: ["flour", "food", "bakery"] }
4769
+ ]
4770
+ },
4771
+ {
4772
+ id: "activity",
4773
+ label: "Activity",
4774
+ emojis: [
4775
+ { emoji: "\u{1F383}", name: "Jack-O-Lantern", keywords: ["jack", "o", "lantern", "halloween"] },
4776
+ { emoji: "\u{1F384}", name: "Christmas Tree", keywords: ["festival", "vacation", "december", "xmas"] },
4777
+ { emoji: "\u{1F386}", name: "Fireworks", keywords: ["photo", "festival", "carnival", "congratulations"] },
4778
+ { emoji: "\u{1F387}", name: "Sparkler", keywords: ["stars", "night", "shine"] },
4779
+ { emoji: "\u{1F9E8}", name: "Firecracker", keywords: ["dynamite", "boom", "explode", "explosion"] },
4780
+ { emoji: "\u2728", name: "Sparkles", keywords: ["stars", "shine", "shiny", "cool"] },
4781
+ { emoji: "\u{1F388}", name: "Balloon", keywords: ["party", "celebration", "birthday", "circus"] },
4782
+ { emoji: "\u{1F389}", name: "Party Popper", keywords: ["tada", "congratulations", "birthday", "magic"] },
4783
+ { emoji: "\u{1F38A}", name: "Confetti Ball", keywords: ["festival", "party", "birthday", "circus"] },
4784
+ { emoji: "\u{1F38B}", name: "Tanabata Tree", keywords: ["plant", "nature", "branch", "summer"] },
4785
+ { emoji: "\u{1F38D}", name: "Pine Decoration", keywords: ["bamboo", "japanese", "plant", "nature"] },
4786
+ { emoji: "\u{1F38E}", name: "Japanese Dolls", keywords: ["toy", "kimono"] },
4787
+ { emoji: "\u{1F38F}", name: "Carp Streamer", keywords: ["flags", "fish", "japanese", "koinobori"] },
4788
+ { emoji: "\u{1F390}", name: "Wind Chime", keywords: ["nature", "ding", "spring", "bell"] },
4789
+ { emoji: "\u{1F391}", name: "Moon Viewing Ceremony", keywords: ["rice", "scene", "photo", "japan"] },
4790
+ { emoji: "\u{1F9E7}", name: "Red Envelope", keywords: ["gift"] },
4791
+ { emoji: "\u{1F380}", name: "Ribbon", keywords: ["decoration", "pink", "girl", "bowtie"] },
4792
+ { emoji: "\u{1F381}", name: "Wrapped Gift", keywords: ["present", "birthday", "christmas", "xmas"] },
4793
+ { emoji: "\u{1F397}\uFE0F", name: "Reminder Ribbon", keywords: ["sports", "cause", "support", "awareness"] },
4794
+ { emoji: "\u{1F39F}\uFE0F", name: "Admission Tickets", keywords: ["sports", "concert", "entrance"] },
4795
+ { emoji: "\u{1F3AB}", name: "Ticket", keywords: ["event", "concert", "pass"] },
4796
+ { emoji: "\u{1F396}\uFE0F", name: "Military Medal", keywords: ["award", "winning", "army"] },
4797
+ { emoji: "\u{1F3C6}", name: "Trophy", keywords: ["win", "award", "contest", "place"] },
4798
+ { emoji: "\u{1F3C5}", name: "Sports Medal", keywords: ["award", "winning"] },
4799
+ { emoji: "\u{1F947}", name: "1st Place Medal", keywords: ["first", "award", "winning"] },
4800
+ { emoji: "\u{1F948}", name: "2nd Place Medal", keywords: ["second", "award"] },
4801
+ { emoji: "\u{1F949}", name: "3rd Place Medal", keywords: ["third", "award"] },
4802
+ { emoji: "\u26BD", name: "Soccer Ball", keywords: ["sports", "football"] },
4803
+ { emoji: "\u26BE", name: "Baseball", keywords: ["sports", "balls"] },
4804
+ { emoji: "\u{1F94E}", name: "Softball", keywords: ["sports", "balls"] },
4805
+ { emoji: "\u{1F3C0}", name: "Basketball", keywords: ["sports", "balls", "NBA"] },
4806
+ { emoji: "\u{1F3D0}", name: "Volleyball", keywords: ["sports", "balls"] }
4807
+ ]
4808
+ },
4809
+ {
4810
+ id: "places",
4811
+ label: "Travel & places",
4812
+ emojis: [
4813
+ { emoji: "\u{1F30D}", name: "Earth Globe Europe-Africa", keywords: ["africa", "showing", "europe", "world"] },
4814
+ { emoji: "\u{1F30E}", name: "Earth Globe Americas", keywords: ["showing", "world", "USA", "international"] },
4815
+ { emoji: "\u{1F30F}", name: "Earth Globe Asia-Australia", keywords: ["asia", "showing", "australia", "world"] },
4816
+ { emoji: "\u{1F310}", name: "Globe with Meridians", keywords: ["earth", "international", "world", "internet"] },
4817
+ { emoji: "\u{1F5FA}\uFE0F", name: "World Map", keywords: ["location", "direction"] },
4818
+ { emoji: "\u{1F5FE}", name: "Map of Japan", keywords: ["nation", "country", "japanese", "asia"] },
4819
+ { emoji: "\u{1F9ED}", name: "Compass", keywords: ["magnetic", "navigation", "orienteering"] },
4820
+ { emoji: "\u{1F3D4}\uFE0F", name: "Snow-Capped Mountain", keywords: ["snow", "capped", "photo", "nature"] },
4821
+ { emoji: "\u26F0\uFE0F", name: "Mountain", keywords: ["photo", "nature", "environment"] },
4822
+ { emoji: "\u{1F30B}", name: "Volcano", keywords: ["photo", "nature", "disaster"] },
4823
+ { emoji: "\u{1F5FB}", name: "Mount Fuji", keywords: ["photo", "mountain", "nature", "japanese"] },
4824
+ { emoji: "\u{1F3D5}\uFE0F", name: "Camping", keywords: ["photo", "outdoors", "tent"] },
4825
+ { emoji: "\u{1F3D6}\uFE0F", name: "Beach with Umbrella", keywords: ["weather", "summer", "sunny", "sand"] },
4826
+ { emoji: "\u{1F3DC}\uFE0F", name: "Desert", keywords: ["photo", "warm", "saharah"] },
4827
+ { emoji: "\u{1F3DD}\uFE0F", name: "Desert Island", keywords: ["photo", "tropical", "mojito"] },
4828
+ { emoji: "\u{1F3DE}\uFE0F", name: "National Park", keywords: ["photo", "environment", "nature"] },
4829
+ { emoji: "\u{1F3DF}\uFE0F", name: "Stadium", keywords: ["photo", "place", "sports", "concert"] },
4830
+ { emoji: "\u{1F3DB}\uFE0F", name: "Classical Building", keywords: ["art", "culture", "history"] },
4831
+ { emoji: "\u{1F3D7}\uFE0F", name: "Building Construction", keywords: ["wip", "working", "progress"] },
4832
+ { emoji: "\u{1F9F1}", name: "Brick", keywords: ["bricks"] },
4833
+ { emoji: "\u{1FAA8}", name: "Rock", keywords: ["stone"] },
4834
+ { emoji: "\u{1FAB5}", name: "Wood", keywords: ["nature", "timber", "trunk"] },
4835
+ { emoji: "\u{1F6D6}", name: "Hut", keywords: ["house", "structure"] },
4836
+ { emoji: "\u{1F3D8}\uFE0F", name: "Houses", keywords: ["house", "buildings", "photo"] },
4837
+ { emoji: "\u{1F3DA}\uFE0F", name: "Derelict House", keywords: ["building", "abandon", "evict", "broken"] },
4838
+ { emoji: "\u{1F3E0}", name: "House", keywords: ["building", "home"] },
4839
+ { emoji: "\u{1F3E1}", name: "House with Garden", keywords: ["home", "plant", "nature"] },
4840
+ { emoji: "\u{1F3E2}", name: "Office Building", keywords: ["bureau", "work"] },
4841
+ { emoji: "\u{1F3E3}", name: "Japanese Post Office", keywords: ["building", "envelope", "communication"] },
4842
+ { emoji: "\u{1F3E4}", name: "Post Office", keywords: ["european", "building", "email"] },
4843
+ { emoji: "\u{1F3E5}", name: "Hospital", keywords: ["building", "health", "surgery", "doctor"] },
4844
+ { emoji: "\u{1F3E6}", name: "Bank", keywords: ["building", "money", "sales", "cash"] }
4845
+ ]
4846
+ },
4847
+ {
4848
+ id: "objects",
4849
+ label: "Objects",
4850
+ emojis: [
4851
+ { emoji: "\u{1F453}", name: "Glasses", keywords: ["eyeglasses", "fashion", "accessories", "eyesight"] },
4852
+ { emoji: "\u{1F576}\uFE0F", name: "Sunglasses", keywords: ["dark", "face", "cool", "accessories"] },
4853
+ { emoji: "\u{1F97D}", name: "Goggles", keywords: ["eyes", "protection", "safety"] },
4854
+ { emoji: "\u{1F97C}", name: "Lab Coat", keywords: ["doctor", "experiment", "scientist", "chemist"] },
4855
+ { emoji: "\u{1F9BA}", name: "Safety Vest", keywords: ["protection"] },
4856
+ { emoji: "\u{1F454}", name: "Necktie", keywords: ["shirt", "suitup", "formal", "fashion"] },
4857
+ { emoji: "\u{1F455}", name: "T-Shirt", keywords: ["shirt", "tshirt", "t", "fashion"] },
4858
+ { emoji: "\u{1F456}", name: "Jeans", keywords: ["fashion", "shopping"] },
4859
+ { emoji: "\u{1F9E3}", name: "Scarf", keywords: ["neck", "winter", "clothes"] },
4860
+ { emoji: "\u{1F9E4}", name: "Gloves", keywords: ["hands", "winter", "clothes"] },
4861
+ { emoji: "\u{1F9E5}", name: "Coat", keywords: ["jacket"] },
4862
+ { emoji: "\u{1F9E6}", name: "Socks", keywords: ["stockings", "clothes"] },
4863
+ { emoji: "\u{1F457}", name: "Dress", keywords: ["clothes", "fashion", "shopping"] },
4864
+ { emoji: "\u{1F458}", name: "Kimono", keywords: ["dress", "fashion", "women", "female"] },
4865
+ { emoji: "\u{1F97B}", name: "Sari", keywords: ["dress"] },
4866
+ { emoji: "\u{1FA71}", name: "One-Piece Swimsuit", keywords: ["one", "piece", "fashion"] },
4867
+ { emoji: "\u{1FA72}", name: "Briefs", keywords: ["clothing"] },
4868
+ { emoji: "\u{1FA73}", name: "Shorts", keywords: ["clothing"] },
4869
+ { emoji: "\u{1F459}", name: "Bikini", keywords: ["swimming", "female", "woman", "girl"] },
4870
+ { emoji: "\u{1F45A}", name: "Womans Clothes", keywords: ["woman", "s", "fashion", "shopping"] },
4871
+ { emoji: "\u{1FAAD}", name: "Folding Hand Fan", keywords: ["flamenco", "hot"] },
4872
+ { emoji: "\u{1F45B}", name: "Purse", keywords: ["fashion", "accessories", "money", "sales"] },
4873
+ { emoji: "\u{1F45C}", name: "Handbag", keywords: ["fashion", "accessory", "accessories", "shopping"] },
4874
+ { emoji: "\u{1F45D}", name: "Pouch", keywords: ["clutch", "bag", "accessories", "shopping"] },
4875
+ { emoji: "\u{1F6CD}\uFE0F", name: "Shopping Bags", keywords: ["mall", "buy", "purchase"] },
4876
+ { emoji: "\u{1F392}", name: "Backpack", keywords: ["school", "satchel", "student", "education"] },
4877
+ { emoji: "\u{1FA74}", name: "Thong Sandal", keywords: ["footwear", "summer"] },
4878
+ { emoji: "\u{1F45E}", name: "Mans Shoe", keywords: ["man", "s", "fashion", "male"] },
4879
+ { emoji: "\u{1F45F}", name: "Running Shoe", keywords: ["athletic", "shoes", "sports", "sneakers"] },
4880
+ { emoji: "\u{1F97E}", name: "Hiking Boot", keywords: ["backpacking", "camping"] },
4881
+ { emoji: "\u{1F97F}", name: "Flat Shoe", keywords: ["womans", "ballet", "slip", "on"] },
4882
+ { emoji: "\u{1F460}", name: "High-Heeled Shoe", keywords: ["high", "heel", "heeled", "fashion"] },
4883
+ { emoji: "\u{1F461}", name: "Womans Sandal", keywords: ["woman", "s", "shoes", "fashion"] },
4884
+ { emoji: "\u{1FA70}", name: "Ballet Shoes", keywords: ["dance"] },
4885
+ { emoji: "\u{1F462}", name: "Womans Boots", keywords: ["boot", "woman", "s", "shoes"] },
4886
+ { emoji: "\u{1FAAE}", name: "Hair Pick", keywords: ["afro", "comb"] },
4887
+ { emoji: "\u{1F451}", name: "Crown", keywords: ["king", "kod", "leader", "royalty"] },
4888
+ { emoji: "\u{1F452}", name: "Womans Hat", keywords: ["woman", "s", "fashion", "accessories"] },
4889
+ { emoji: "\u{1F3A9}", name: "Top Hat", keywords: ["tophat", "magic", "gentleman", "classy"] },
4890
+ { emoji: "\u{1F393}", name: "Graduation Cap", keywords: ["mortar", "board", "school", "college"] },
4891
+ { emoji: "\u{1F9E2}", name: "Billed Cap", keywords: ["baseball"] },
4892
+ { emoji: "\u{1FA96}", name: "Military Helmet", keywords: ["army", "protection"] },
4893
+ { emoji: "\u26D1\uFE0F", name: "Rescue Worker\u2019s Helmet", keywords: ["with", "white", "cross", "worker"] },
4894
+ { emoji: "\u{1F4FF}", name: "Prayer Beads", keywords: ["dhikr", "religious"] }
4895
+ ]
4896
+ },
4897
+ {
4898
+ id: "symbols",
4899
+ label: "Symbols",
4900
+ emojis: [
4901
+ { emoji: "\u{1F3E7}", name: "Atm Sign", keywords: ["money", "sales", "cash", "blue"] },
4902
+ { emoji: "\u{1F6AE}", name: "Litter in Bin Sign", keywords: ["put", "its", "place", "blue"] },
4903
+ { emoji: "\u{1F6B0}", name: "Potable Water", keywords: ["blue", "square", "liquid", "restroom"] },
4904
+ { emoji: "\u267F", name: "Wheelchair Symbol", keywords: ["blue", "square", "disabled", "accessibility"] },
4905
+ { emoji: "\u{1F6B9}", name: "Men\u2019s Room", keywords: ["mens", "men", "s", "toilet"] },
4906
+ { emoji: "\u{1F6BA}", name: "Women\u2019s Room", keywords: ["womens", "women", "s", "purple"] },
4907
+ { emoji: "\u{1F6BB}", name: "Restroom", keywords: ["blue", "square", "toilet", "refresh"] },
4908
+ { emoji: "\u{1F6BC}", name: "Baby Symbol", keywords: ["orange", "square", "child"] },
4909
+ { emoji: "\u{1F6BE}", name: "Water Closet", keywords: ["wc", "toilet", "restroom", "blue"] },
4910
+ { emoji: "\u{1F6C2}", name: "Passport Control", keywords: ["custom", "blue", "square"] },
4911
+ { emoji: "\u{1F6C3}", name: "Customs", keywords: ["passport", "border", "blue", "square"] },
4912
+ { emoji: "\u{1F6C4}", name: "Baggage Claim", keywords: ["blue", "square", "airport", "transport"] },
4913
+ { emoji: "\u{1F6C5}", name: "Left Luggage", keywords: ["blue", "square", "travel"] },
4914
+ { emoji: "\u26A0\uFE0F", name: "Warning", keywords: ["exclamation", "wip", "alert", "error"] },
4915
+ { emoji: "\u{1F6B8}", name: "Children Crossing", keywords: ["school", "warning", "danger", "sign"] },
4916
+ { emoji: "\u26D4", name: "No Entry", keywords: ["limit", "security", "privacy", "bad"] },
4917
+ { emoji: "\u{1F6AB}", name: "Prohibited", keywords: ["no", "entry", "sign", "forbid"] },
4918
+ { emoji: "\u{1F6B3}", name: "No Bicycles", keywords: ["cyclist", "prohibited", "circle"] },
4919
+ { emoji: "\u{1F6AD}", name: "No Smoking", keywords: ["cigarette", "blue", "square", "smell"] },
4920
+ { emoji: "\u{1F6AF}", name: "No Littering", keywords: ["do", "not", "litter", "trash"] },
4921
+ { emoji: "\u{1F6B1}", name: "Non-Potable Water", keywords: ["non", "potable", "drink", "faucet"] },
4922
+ { emoji: "\u{1F6B7}", name: "No Pedestrians", keywords: ["rules", "crossing", "walking", "circle"] },
4923
+ { emoji: "\u{1F4F5}", name: "No Mobile Phones", keywords: ["iphone", "mute", "circle"] },
4924
+ { emoji: "\u{1F51E}", name: "No One Under Eighteen", keywords: ["underage", "18", "drink", "pub"] },
4925
+ { emoji: "\u2622\uFE0F", name: "Radioactive", keywords: ["sign", "nuclear", "danger"] },
4926
+ { emoji: "\u2623\uFE0F", name: "Biohazard", keywords: ["sign", "danger"] },
4927
+ { emoji: "\u2B06\uFE0F", name: "Up Arrow", keywords: ["blue", "square", "continue", "top"] },
4928
+ { emoji: "\u2197\uFE0F", name: "Up-Right Arrow", keywords: ["upper", "right", "up", "blue"] },
4929
+ { emoji: "\u27A1\uFE0F", name: "Right Arrow", keywords: ["blue", "square", "next"] },
4930
+ { emoji: "\u2198\uFE0F", name: "South East Arrow", keywords: ["lower", "right", "down", "blue"] },
4931
+ { emoji: "\u2B07\uFE0F", name: "Down Arrow", keywords: ["blue", "square", "direction", "bottom"] },
4932
+ { emoji: "\u2199\uFE0F", name: "Down-Left Arrow", keywords: ["lower", "left", "down", "blue"] }
4933
+ ]
4934
+ },
4935
+ {
4936
+ id: "flags",
4937
+ label: "Flags",
4938
+ emojis: [
4939
+ { emoji: "\u{1F3C1}", name: "Chequered Flag", keywords: ["checkered", "contest", "finishline", "race"] },
4940
+ { emoji: "\u{1F1E8}\u{1F1F3}", name: "China Flag", keywords: ["cn", "chinese", "prc", "country"] },
4941
+ { emoji: "\u{1F38C}", name: "Crossed Flags", keywords: ["japanese", "nation", "country", "border"] },
4942
+ { emoji: "\u{1F1E9}\u{1F1EA}", name: "Germany Flag", keywords: ["de", "german", "nation", "country"] },
4943
+ { emoji: "\u{1F1EA}\u{1F1F8}", name: "Spain Flag", keywords: ["es", "nation", "country", "banner"] },
4944
+ { emoji: "\u{1F1E6}\u{1F1E8}", name: "Ascension Island Flag", keywords: ["ac"] },
4945
+ { emoji: "\u{1F1E6}\u{1F1E9}", name: "Andorra Flag", keywords: ["ad", "nation", "country", "banner"] },
4946
+ { emoji: "\u{1F1E6}\u{1F1EA}", name: "United Arab Emirates Flag", keywords: ["ae", "nation", "country", "banner"] },
4947
+ { emoji: "\u{1F1E6}\u{1F1EB}", name: "Afghanistan Flag", keywords: ["af", "nation", "country", "banner"] },
4948
+ { emoji: "\u{1F1E6}\u{1F1EC}", name: "Antigua & Barbuda Flag", keywords: ["ag", "nation", "country", "banner"] },
4949
+ { emoji: "\u{1F1E6}\u{1F1EE}", name: "Anguilla Flag", keywords: ["ai", "nation", "country", "banner"] },
4950
+ { emoji: "\u{1F1E6}\u{1F1F1}", name: "Albania Flag", keywords: ["al", "nation", "country", "banner"] }
4951
+ ]
4952
+ }
4953
+ ];
4954
+ function matches(def, query) {
4955
+ if (def.name.toLowerCase().includes(query)) return true;
4956
+ return def.keywords.some((k2) => k2.toLowerCase().includes(query));
4957
+ }
4958
+ var EmojiPicker = react.forwardRef(
4959
+ function EmojiPicker2({
4960
+ onSelect,
4961
+ groups = EMOJI_GROUPS,
4962
+ columns = 8,
4963
+ searchable = true,
4964
+ searchPlaceholder = "Search emoji",
4965
+ emptyText = "No emoji found",
4966
+ className,
4967
+ ...props
4968
+ }, ref) {
4969
+ const [query, setQuery] = react.useState("");
4970
+ const q = query.trim().toLowerCase();
4971
+ const results = react.useMemo(() => {
4972
+ if (!q) return null;
4973
+ return groups.flatMap((g) => g.emojis).filter((d) => matches(d, q));
4974
+ }, [groups, q]);
4975
+ const gridStyle = {
4976
+ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`
4977
+ };
4978
+ const cell = (def) => /* @__PURE__ */ jsxRuntime.jsx(
4979
+ "button",
4980
+ {
4981
+ type: "button",
4982
+ className: "klun-emoji-picker__cell",
4983
+ title: def.name,
4984
+ "aria-label": def.name,
4985
+ onClick: () => onSelect(def.emoji, def),
4986
+ children: def.emoji
4987
+ },
4988
+ def.emoji
4989
+ );
4990
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-emoji-picker", className), ...props, children: [
4991
+ searchable && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "klun-emoji-picker__search", children: [
4992
+ /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-search-line", "aria-hidden": "true" }),
4993
+ /* @__PURE__ */ jsxRuntime.jsx(
4994
+ "input",
4995
+ {
4996
+ value: query,
4997
+ placeholder: searchPlaceholder,
4998
+ "aria-label": searchPlaceholder,
4999
+ onChange: (e) => setQuery(e.target.value)
5000
+ }
5001
+ )
5002
+ ] }),
5003
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-emoji-picker__body", children: results ? results.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-emoji-picker__grid", style: gridStyle, children: results.map(cell) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-emoji-picker__empty", children: emptyText }) : groups.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-emoji-picker__group", children: [
5004
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-emoji-picker__group-title", children: group.label }),
5005
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-emoji-picker__grid", style: gridStyle, children: group.emojis.map(cell) })
5006
+ ] }, group.id)) })
5007
+ ] });
5008
+ }
5009
+ );
5010
+ EmojiPicker.displayName = "EmojiPicker";
5011
+ var QUICK_EMOJIS = ["\u{1F44D}", "\u{1F44C}", "\u2764\uFE0F", "\u2705", "\u{1F389}", "\u{1F615}", "\u{1F680}", "\u{1F440}"];
5012
+ var QuickEmojiPicker = react.forwardRef(
5013
+ function QuickEmojiPicker2({ onSelect, emojis = QUICK_EMOJIS, align = "left", label = "Add reaction", className }, ref) {
5014
+ return /* @__PURE__ */ jsxRuntime.jsx(
5015
+ Popover,
5016
+ {
5017
+ align,
5018
+ width: 304,
5019
+ trigger: /* @__PURE__ */ jsxRuntime.jsx(
5020
+ "button",
5021
+ {
5022
+ ref,
5023
+ type: "button",
5024
+ className: chunkTPGAXYFU_cjs.cx("klun-quick-emoji-picker", className),
5025
+ "aria-label": label,
5026
+ title: label,
5027
+ children: /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-emotion-add-line", "aria-hidden": "true" })
5028
+ }
5029
+ ),
5030
+ children: (close) => (
5031
+ // Mounted per open, so the quick/full state resets like the original.
5032
+ /* @__PURE__ */ jsxRuntime.jsx(
5033
+ QuickPanel,
5034
+ {
5035
+ emojis,
5036
+ onSelect: (emoji) => {
5037
+ onSelect(emoji);
5038
+ close();
5039
+ }
5040
+ }
5041
+ )
5042
+ )
5043
+ }
5044
+ );
5045
+ }
5046
+ );
5047
+ QuickEmojiPicker.displayName = "QuickEmojiPicker";
5048
+ function QuickPanel({
5049
+ emojis,
5050
+ onSelect
5051
+ }) {
5052
+ const [expanded, setExpanded] = react.useState(false);
5053
+ if (expanded) {
5054
+ return /* @__PURE__ */ jsxRuntime.jsx(EmojiPicker, { onSelect: (emoji) => onSelect(emoji) });
5055
+ }
5056
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-quick-emoji-picker__panel", children: [
5057
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-quick-emoji-picker__row", children: emojis.map((emoji) => /* @__PURE__ */ jsxRuntime.jsx(
5058
+ "button",
5059
+ {
5060
+ type: "button",
5061
+ className: "klun-quick-emoji-picker__cell",
5062
+ onClick: () => onSelect(emoji),
5063
+ children: emoji
5064
+ },
5065
+ emoji
5066
+ )) }),
5067
+ /* @__PURE__ */ jsxRuntime.jsx(
5068
+ "button",
5069
+ {
5070
+ type: "button",
5071
+ className: "klun-quick-emoji-picker__more",
5072
+ onClick: () => setExpanded(true),
5073
+ children: "More emojis\u2026"
5074
+ }
5075
+ )
5076
+ ] });
5077
+ }
5078
+ var GAP = 6;
5079
+ var MARGIN = 8;
5080
+ var Tooltip = react.forwardRef(function Tooltip2({ content, side = "top", delay = 200, disabled = false, children, style, className }, ref) {
5081
+ const [open, setOpen] = react.useState(false);
5082
+ const [pos, setPos] = react.useState(null);
5083
+ const timer = react.useRef(null);
5084
+ const innerRef = react.useRef(null);
5085
+ const bubbleRef = react.useRef(null);
5086
+ const show = () => {
5087
+ if (disabled || !content) return;
5088
+ if (timer.current) clearTimeout(timer.current);
5089
+ timer.current = setTimeout(() => setOpen(true), delay);
5090
+ };
5091
+ const hide = () => {
5092
+ if (timer.current) clearTimeout(timer.current);
5093
+ setOpen(false);
5094
+ };
5095
+ react.useEffect(() => () => {
5096
+ if (timer.current) clearTimeout(timer.current);
5097
+ }, []);
5098
+ react.useLayoutEffect(() => {
5099
+ if (!open) {
5100
+ setPos(null);
5101
+ return;
5102
+ }
5103
+ const place2 = () => {
5104
+ const trigger = innerRef.current;
5105
+ const bubble = bubbleRef.current;
5106
+ if (!trigger || !bubble) return;
5107
+ const tr = trigger.getBoundingClientRect();
5108
+ const bw = bubble.offsetWidth;
5109
+ const bh = bubble.offsetHeight;
5110
+ const vw = document.documentElement.clientWidth;
5111
+ const vh = document.documentElement.clientHeight;
5112
+ let top;
5113
+ let left;
5114
+ switch (side) {
5115
+ case "bottom":
5116
+ top = tr.bottom + GAP;
5117
+ left = tr.left + tr.width / 2 - bw / 2;
5118
+ break;
5119
+ case "left":
5120
+ left = tr.left - bw - GAP;
5121
+ top = tr.top + tr.height / 2 - bh / 2;
5122
+ break;
5123
+ case "right":
5124
+ left = tr.right + GAP;
5125
+ top = tr.top + tr.height / 2 - bh / 2;
5126
+ break;
5127
+ default:
5128
+ top = tr.top - bh - GAP;
5129
+ left = tr.left + tr.width / 2 - bw / 2;
5130
+ }
5131
+ left = Math.max(MARGIN, Math.min(left, vw - bw - MARGIN));
5132
+ top = Math.max(MARGIN, Math.min(top, vh - bh - MARGIN));
5133
+ setPos({ top, left });
5134
+ };
5135
+ place2();
5136
+ window.addEventListener("scroll", place2, true);
5137
+ window.addEventListener("resize", place2);
5138
+ return () => {
5139
+ window.removeEventListener("scroll", place2, true);
5140
+ window.removeEventListener("resize", place2);
5141
+ };
5142
+ }, [open, side, content]);
5143
+ const setRefs = (node) => {
5144
+ innerRef.current = node;
5145
+ if (typeof ref === "function") ref(node);
5146
+ else if (ref) ref.current = node;
5147
+ };
5148
+ const bubbleStyle = {
5149
+ ...style,
5150
+ position: "fixed",
5151
+ top: pos ? pos.top : 0,
5152
+ left: pos ? pos.left : 0,
5153
+ right: "auto",
5154
+ bottom: "auto",
5155
+ transform: "none",
5156
+ visibility: pos ? "visible" : "hidden"
5157
+ };
5158
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5159
+ "span",
5160
+ {
5161
+ ref: setRefs,
5162
+ className: chunkTPGAXYFU_cjs.cx("klun-tooltip", className),
5163
+ onMouseEnter: show,
5164
+ onMouseLeave: hide,
5165
+ onFocus: show,
5166
+ onBlur: hide,
5167
+ children: [
5168
+ children,
5169
+ open && content && typeof document !== "undefined" ? reactDom.createPortal(
5170
+ /* @__PURE__ */ jsxRuntime.jsx(
5171
+ "span",
5172
+ {
5173
+ ref: bubbleRef,
5174
+ role: "tooltip",
5175
+ className: chunkTPGAXYFU_cjs.cx("klun-tooltip__bubble", `klun-tooltip__bubble--${side}`),
5176
+ style: bubbleStyle,
5177
+ children: content
5178
+ }
5179
+ ),
5180
+ document.body
5181
+ ) : null
5182
+ ]
5183
+ }
5184
+ );
5185
+ });
5186
+ Tooltip.displayName = "Tooltip";
5187
+ function groupReactions(items2, currentActorId) {
5188
+ const map = /* @__PURE__ */ new Map();
5189
+ for (const item of items2) {
5190
+ let group = map.get(item.emoji);
5191
+ if (!group) {
5192
+ group = { emoji: item.emoji, count: 0, reacted: false, actors: [] };
5193
+ map.set(item.emoji, group);
5194
+ }
5195
+ group.count += 1;
5196
+ group.actors.push(item.actorName ?? item.actorId);
5197
+ if (item.actorId === currentActorId) group.reacted = true;
5198
+ }
5199
+ return Array.from(map.values());
5200
+ }
5201
+ var ReactionBar = react.forwardRef(
5202
+ function ReactionBar2({ reactions, onToggle, showPicker = true, pickerEmojis, className, ...props }, ref) {
5203
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-reaction-bar", className), ...props, children: [
5204
+ reactions.map((reaction) => /* @__PURE__ */ jsxRuntime.jsx(
5205
+ Tooltip,
5206
+ {
5207
+ side: "top",
5208
+ disabled: reaction.actors.length === 0,
5209
+ content: reaction.actors.join(", "),
5210
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
5211
+ "button",
5212
+ {
5213
+ type: "button",
5214
+ className: "klun-reaction",
5215
+ "data-reacted": reaction.reacted ? "" : void 0,
5216
+ "aria-pressed": reaction.reacted,
5217
+ "aria-label": `${reaction.emoji} ${reaction.count}`,
5218
+ onClick: () => onToggle?.(reaction.emoji),
5219
+ children: [
5220
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-reaction__emoji", children: reaction.emoji }),
5221
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-reaction__count", children: reaction.count })
5222
+ ]
5223
+ }
5224
+ )
5225
+ },
5226
+ reaction.emoji
5227
+ )),
5228
+ showPicker && /* @__PURE__ */ jsxRuntime.jsx(QuickEmojiPicker, { emojis: pickerEmojis, onSelect: (emoji) => onToggle?.(emoji) })
5229
+ ] });
5230
+ }
5231
+ );
5232
+ ReactionBar.displayName = "ReactionBar";
5233
+ var ShimmerText = react.forwardRef(
5234
+ function ShimmerText2({ children, active = true, className, ...props }, ref) {
5235
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5236
+ "span",
5237
+ {
5238
+ ref,
5239
+ className: chunkTPGAXYFU_cjs.cx("klun-shimmer-text", !active && "klun-shimmer-text--static", className),
5240
+ ...props,
5241
+ children: [
5242
+ children,
5243
+ active && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-shimmer-text__window", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-shimmer-text__copy", children }) })
5244
+ ]
5245
+ }
5246
+ );
5247
+ }
5248
+ );
5249
+ ShimmerText.displayName = "ShimmerText";
5250
+ var StatCard = react.forwardRef(function StatCard2({ label, value, delta, trend = "up", icon, tint = "feature", className, ...props }, ref) {
5251
+ const up = trend === "up";
5252
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-stat-card", `klun-stat-card--${tint}`, className), ...props, children: [
5253
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-stat-card__head", children: [
5254
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-stat-card__icon", children: icon }),
5255
+ delta != null ? /* @__PURE__ */ jsxRuntime.jsxs(
5256
+ "span",
5257
+ {
5258
+ className: chunkTPGAXYFU_cjs.cx(
4017
5259
  "klun-stat-card__delta",
4018
5260
  up ? "klun-stat-card__delta--up" : "klun-stat-card__delta--down"
4019
5261
  ),
@@ -4453,7 +5695,8 @@ function SortIcon({ dir }) {
4453
5695
  function Check({
4454
5696
  checked,
4455
5697
  indeterminate,
4456
- onChange
5698
+ onChange,
5699
+ label
4457
5700
  }) {
4458
5701
  const active = checked || indeterminate;
4459
5702
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -4461,6 +5704,7 @@ function Check({
4461
5704
  {
4462
5705
  type: "button",
4463
5706
  role: "checkbox",
5707
+ "aria-label": label,
4464
5708
  "aria-checked": indeterminate ? "mixed" : checked,
4465
5709
  onClick: (e) => {
4466
5710
  e.stopPropagation();
@@ -4633,7 +5877,15 @@ function TableHead({
4633
5877
  leftFixed.length && "klun-table__cell--fixed klun-table__cell--fixed-head"
4634
5878
  ),
4635
5879
  style: leftFixed.length ? { left: expandCol ? 44 : 0 } : void 0,
4636
- children: selectionType === "radio" ? null : /* @__PURE__ */ jsxRuntime.jsx(Check, { checked: allOn, indeterminate: someOn, onChange: toggleAll })
5880
+ children: selectionType === "radio" ? null : /* @__PURE__ */ jsxRuntime.jsx(
5881
+ Check,
5882
+ {
5883
+ checked: allOn,
5884
+ indeterminate: someOn,
5885
+ onChange: toggleAll,
5886
+ label: table.selectAll ?? "Select all rows"
5887
+ }
5888
+ )
4637
5889
  }
4638
5890
  ) : null,
4639
5891
  visibleColumns.map((c, ci) => {
@@ -4879,6 +6131,7 @@ function RowBase({
4879
6131
  {
4880
6132
  type: "button",
4881
6133
  role: "radio",
6134
+ "aria-label": table.selectRow ?? "Select row",
4882
6135
  "aria-checked": on,
4883
6136
  onClick: (e) => {
4884
6137
  e.stopPropagation();
@@ -4887,7 +6140,14 @@ function RowBase({
4887
6140
  className: chunkTPGAXYFU_cjs.cx("klun-table__radio", on && "klun-table__radio--on"),
4888
6141
  children: on ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-table__radio-dot" }) : null
4889
6142
  }
4890
- ) : /* @__PURE__ */ jsxRuntime.jsx(Check, { checked: on, onChange: () => onSelectRow?.(id) })
6143
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
6144
+ Check,
6145
+ {
6146
+ checked: on,
6147
+ onChange: () => onSelectRow?.(id),
6148
+ label: table.selectRow ?? "Select row"
6149
+ }
6150
+ )
4891
6151
  }
4892
6152
  ) : null,
4893
6153
  visibleColumns.map((c, ci) => {
@@ -5730,115 +6990,6 @@ var Timeline = react.forwardRef(function Timeline2({ items: items2 = [], mode =
5730
6990
  }) });
5731
6991
  });
5732
6992
  Timeline.displayName = "Timeline";
5733
- var GAP = 6;
5734
- var MARGIN = 8;
5735
- var Tooltip = react.forwardRef(function Tooltip2({ content, side = "top", delay = 200, disabled = false, children, style, className }, ref) {
5736
- const [open, setOpen] = react.useState(false);
5737
- const [pos, setPos] = react.useState(null);
5738
- const timer = react.useRef(null);
5739
- const innerRef = react.useRef(null);
5740
- const bubbleRef = react.useRef(null);
5741
- const show = () => {
5742
- if (disabled || !content) return;
5743
- if (timer.current) clearTimeout(timer.current);
5744
- timer.current = setTimeout(() => setOpen(true), delay);
5745
- };
5746
- const hide = () => {
5747
- if (timer.current) clearTimeout(timer.current);
5748
- setOpen(false);
5749
- };
5750
- react.useEffect(() => () => {
5751
- if (timer.current) clearTimeout(timer.current);
5752
- }, []);
5753
- react.useLayoutEffect(() => {
5754
- if (!open) {
5755
- setPos(null);
5756
- return;
5757
- }
5758
- const place2 = () => {
5759
- const trigger = innerRef.current;
5760
- const bubble = bubbleRef.current;
5761
- if (!trigger || !bubble) return;
5762
- const tr = trigger.getBoundingClientRect();
5763
- const bw = bubble.offsetWidth;
5764
- const bh = bubble.offsetHeight;
5765
- const vw = document.documentElement.clientWidth;
5766
- const vh = document.documentElement.clientHeight;
5767
- let top;
5768
- let left;
5769
- switch (side) {
5770
- case "bottom":
5771
- top = tr.bottom + GAP;
5772
- left = tr.left + tr.width / 2 - bw / 2;
5773
- break;
5774
- case "left":
5775
- left = tr.left - bw - GAP;
5776
- top = tr.top + tr.height / 2 - bh / 2;
5777
- break;
5778
- case "right":
5779
- left = tr.right + GAP;
5780
- top = tr.top + tr.height / 2 - bh / 2;
5781
- break;
5782
- default:
5783
- top = tr.top - bh - GAP;
5784
- left = tr.left + tr.width / 2 - bw / 2;
5785
- }
5786
- left = Math.max(MARGIN, Math.min(left, vw - bw - MARGIN));
5787
- top = Math.max(MARGIN, Math.min(top, vh - bh - MARGIN));
5788
- setPos({ top, left });
5789
- };
5790
- place2();
5791
- window.addEventListener("scroll", place2, true);
5792
- window.addEventListener("resize", place2);
5793
- return () => {
5794
- window.removeEventListener("scroll", place2, true);
5795
- window.removeEventListener("resize", place2);
5796
- };
5797
- }, [open, side, content]);
5798
- const setRefs = (node) => {
5799
- innerRef.current = node;
5800
- if (typeof ref === "function") ref(node);
5801
- else if (ref) ref.current = node;
5802
- };
5803
- const bubbleStyle = {
5804
- ...style,
5805
- position: "fixed",
5806
- top: pos ? pos.top : 0,
5807
- left: pos ? pos.left : 0,
5808
- right: "auto",
5809
- bottom: "auto",
5810
- transform: "none",
5811
- visibility: pos ? "visible" : "hidden"
5812
- };
5813
- return /* @__PURE__ */ jsxRuntime.jsxs(
5814
- "span",
5815
- {
5816
- ref: setRefs,
5817
- className: chunkTPGAXYFU_cjs.cx("klun-tooltip", className),
5818
- onMouseEnter: show,
5819
- onMouseLeave: hide,
5820
- onFocus: show,
5821
- onBlur: hide,
5822
- children: [
5823
- children,
5824
- open && content && typeof document !== "undefined" ? reactDom.createPortal(
5825
- /* @__PURE__ */ jsxRuntime.jsx(
5826
- "span",
5827
- {
5828
- ref: bubbleRef,
5829
- role: "tooltip",
5830
- className: chunkTPGAXYFU_cjs.cx("klun-tooltip__bubble", `klun-tooltip__bubble--${side}`),
5831
- style: bubbleStyle,
5832
- children: content
5833
- }
5834
- ),
5835
- document.body
5836
- ) : null
5837
- ]
5838
- }
5839
- );
5840
- });
5841
- Tooltip.displayName = "Tooltip";
5842
6993
  function flatten(nodes, level, parentExpanded, expanded, out) {
5843
6994
  for (const n of nodes) {
5844
6995
  const isExpanded = expanded.includes(n.key);
@@ -5969,6 +7120,72 @@ var Tree = react.forwardRef(function Tree2({
5969
7120
  );
5970
7121
  });
5971
7122
  Tree.displayName = "Tree";
7123
+ function VirtualTable({
7124
+ rows = [],
7125
+ columns = [],
7126
+ rowHeight = 40,
7127
+ height = 420,
7128
+ getRowId,
7129
+ onRowClick,
7130
+ overscan = 8,
7131
+ zebra = true,
7132
+ empty,
7133
+ className,
7134
+ style,
7135
+ ...props
7136
+ }) {
7137
+ const [scrollTop, setScrollTop] = react.useState(0);
7138
+ const total = rows.length;
7139
+ const template = react.useMemo(
7140
+ () => columns.map((c) => c.width ? `${c.width}px` : "minmax(0, 1fr)").join(" "),
7141
+ [columns]
7142
+ );
7143
+ const bodyHeight = Math.max(0, height - 36);
7144
+ const start = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
7145
+ const end = Math.min(total, Math.ceil((scrollTop + bodyHeight) / rowHeight) + overscan);
7146
+ const slice = rows.slice(start, end);
7147
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: void 0, className: chunkTPGAXYFU_cjs.cx("klun-vtable", className), style: { ...style, height }, ...props, children: [
7148
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-vtable__head", style: { gridTemplateColumns: template }, children: columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkTPGAXYFU_cjs.cx("klun-vtable__th", c.align && `klun-vtable__th--${c.align}`), children: c.header }, c.key)) }),
7149
+ /* @__PURE__ */ jsxRuntime.jsx(
7150
+ "div",
7151
+ {
7152
+ className: "klun-vtable__body",
7153
+ onScroll: (e) => setScrollTop(e.target.scrollTop),
7154
+ style: { maxHeight: bodyHeight },
7155
+ children: total === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-vtable__empty", children: empty ?? "No rows" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7156
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: start * rowHeight } }),
7157
+ slice.map((row, i) => {
7158
+ const index = start + i;
7159
+ const id = getRowId?.(row, index) ?? index;
7160
+ return /* @__PURE__ */ jsxRuntime.jsx(
7161
+ "div",
7162
+ {
7163
+ role: onRowClick ? "button" : void 0,
7164
+ tabIndex: onRowClick ? 0 : void 0,
7165
+ onClick: () => onRowClick?.(row, index),
7166
+ className: chunkTPGAXYFU_cjs.cx(
7167
+ "klun-vtable__row",
7168
+ zebra && index % 2 === 1 && "klun-vtable__row--zebra",
7169
+ onRowClick && "klun-vtable__row--clickable"
7170
+ ),
7171
+ style: { gridTemplateColumns: template, height: rowHeight },
7172
+ children: columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkTPGAXYFU_cjs.cx("klun-vtable__td", c.align && `klun-vtable__td--${c.align}`), children: c.render ? c.render(row, index) : String(row[c.key] ?? "") }, c.key))
7173
+ },
7174
+ id
7175
+ );
7176
+ }),
7177
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: Math.max(0, (total - end) * rowHeight) } })
7178
+ ] })
7179
+ }
7180
+ ),
7181
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-vtable__foot", children: [
7182
+ total.toLocaleString("en-US"),
7183
+ " rows \xB7 rendering ",
7184
+ slice.length
7185
+ ] })
7186
+ ] });
7187
+ }
7188
+ VirtualTable.displayName = "VirtualTable";
5972
7189
  var Accordion = react.forwardRef(function Accordion2({ items: items2 = [], defaultOpen, multiple = false, className, ...props }, ref) {
5973
7190
  const [open, setOpen] = react.useState(() => defaultOpen != null ? [defaultOpen] : []);
5974
7191
  const toggle = (id) => setOpen((cur) => {
@@ -6097,6 +7314,74 @@ var Banner = react.forwardRef(function Banner2({ status = "information", variant
6097
7314
  );
6098
7315
  });
6099
7316
  Banner.displayName = "Banner";
7317
+ var BorderBeam = react.forwardRef(
7318
+ function BorderBeam2({ className, ...props }, ref) {
7319
+ return /* @__PURE__ */ jsxRuntime.jsx(
7320
+ "span",
7321
+ {
7322
+ ref,
7323
+ "aria-hidden": "true",
7324
+ className: chunkTPGAXYFU_cjs.cx("klun-border-beam", className),
7325
+ ...props,
7326
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-border-beam__light" })
7327
+ }
7328
+ );
7329
+ }
7330
+ );
7331
+ BorderBeam.displayName = "BorderBeam";
7332
+ var RESOURCE_NOUN = {
7333
+ agent: "agent",
7334
+ skill: "skill",
7335
+ comment: "comment",
7336
+ runtime: "runtime",
7337
+ workspace: "workspace"
7338
+ };
7339
+ function getCopy(reason, noun, ownerName) {
7340
+ switch (reason) {
7341
+ case "not_authenticated":
7342
+ return `Sign in to edit this ${noun}.`;
7343
+ case "not_member":
7344
+ return `Join this workspace to edit this ${noun}.`;
7345
+ case "not_owner_role":
7346
+ return `View only \u2014 only the workspace owner can manage this ${noun}.`;
7347
+ case "not_admin_role":
7348
+ return `View only \u2014 only workspace owners and admins can manage this ${noun}.`;
7349
+ case "not_resource_owner":
7350
+ if (ownerName) {
7351
+ return `View only \u2014 only ${ownerName} and workspace admins can edit this ${noun}.`;
7352
+ }
7353
+ return `View only \u2014 only the ${noun} owner and workspace admins can edit this ${noun}.`;
7354
+ case "last_owner":
7355
+ return `A workspace must keep at least one owner \u2014 promote another member first.`;
7356
+ case "private_visibility":
7357
+ if (ownerName) {
7358
+ return `Personal ${noun} \u2014 only ${ownerName} and workspace admins can use this.`;
7359
+ }
7360
+ return `Personal ${noun} \u2014 only the owner and workspace admins can use this.`;
7361
+ case "allowed":
7362
+ case "unknown":
7363
+ return "";
7364
+ }
7365
+ }
7366
+ var CapabilityBanner = react.forwardRef(
7367
+ function CapabilityBanner2({ reason, resource, ownerName, message, className, ...props }, ref) {
7368
+ if (reason === "allowed" || reason === "unknown") return null;
7369
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7370
+ "div",
7371
+ {
7372
+ ref,
7373
+ role: "status",
7374
+ className: chunkTPGAXYFU_cjs.cx("klun-capability-banner", className),
7375
+ ...props,
7376
+ children: [
7377
+ /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-lock-line klun-capability-banner__icon", "aria-hidden": "true" }),
7378
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: message ?? getCopy(reason, RESOURCE_NOUN[resource], ownerName) })
7379
+ ]
7380
+ }
7381
+ );
7382
+ }
7383
+ );
7384
+ CapabilityBanner.displayName = "CapabilityBanner";
6100
7385
  var CircularProgress = react.forwardRef(
6101
7386
  function CircularProgress2({
6102
7387
  value = 0,
@@ -6154,14 +7439,250 @@ var CircularProgress = react.forwardRef(
6154
7439
  )
6155
7440
  ]
6156
7441
  }
6157
- ),
6158
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-circular-progress__label", children: label != null ? label : `${Math.round(pct2)}%` })
6159
- ]
7442
+ ),
7443
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-circular-progress__label", children: label != null ? label : `${Math.round(pct2)}%` })
7444
+ ]
7445
+ }
7446
+ );
7447
+ }
7448
+ );
7449
+ CircularProgress.displayName = "CircularProgress";
7450
+ var SPHERE_PATHS = [
7451
+ { from: { x: -0.28, y: 0.18 }, to: { x: 1.28, y: 0.78 } },
7452
+ { from: { x: 1.28, y: 0.82 }, to: { x: -0.28, y: 0.22 } },
7453
+ { from: { x: 0.18, y: 1.24 }, to: { x: 0.82, y: -0.24 } }
7454
+ ];
7455
+ var WAVE_SPHERE_ANCHORS = [
7456
+ { x: 0.28, y: 0.08 },
7457
+ { x: 0.76, y: 0.28 },
7458
+ { x: 0.38, y: 0.5 },
7459
+ { x: 0.78, y: 0.72 },
7460
+ { x: 0.34, y: 0.93 }
7461
+ ];
7462
+ var SPHERE_PROFILES = [
7463
+ { phase: 0, radius: 1, dot: 1, speed: 1 },
7464
+ { phase: 0.2, radius: 0.94, dot: 0.96, speed: 1 },
7465
+ { phase: 0.4, radius: 1, dot: 1, speed: 1 },
7466
+ { phase: 0.6, radius: 0.94, dot: 0.96, speed: 1 },
7467
+ { phase: 0.8, radius: 0.9, dot: 0.94, speed: 1 }
7468
+ ];
7469
+ function clamp(value, min, max) {
7470
+ return Math.min(Math.max(value, min), max);
7471
+ }
7472
+ function lerp(start, end, amount) {
7473
+ return start + (end - start) * amount;
7474
+ }
7475
+ function easeInOutSine(value) {
7476
+ return 0.5 - Math.cos(value * Math.PI) * 0.5;
7477
+ }
7478
+ function smoothstep(edge0, edge1, value) {
7479
+ const t = clamp((value - edge0) / (edge1 - edge0), 0, 1);
7480
+ return t * t * (3 - 2 * t);
7481
+ }
7482
+ function getTravelOpacity(progress) {
7483
+ const fadeIn = smoothstep(0.03, 0.24, progress);
7484
+ const fadeOut = 1 - smoothstep(0.76, 0.97, progress);
7485
+ return Math.min(fadeIn, fadeOut);
7486
+ }
7487
+ function getWaveOpacity(progress) {
7488
+ const pulse = (1 - Math.cos(progress * Math.PI * 2)) * 0.5;
7489
+ return 0.16 + Math.pow(pulse, 1.28) * 0.84;
7490
+ }
7491
+ function resolveSphereRadius(radius, windowSize) {
7492
+ if (typeof radius === "number") return radius;
7493
+ const percent = Number.parseFloat(radius);
7494
+ if (Number.isNaN(percent)) return Math.max(windowSize.w, windowSize.h);
7495
+ return Math.max(windowSize.w, windowSize.h) * (percent / 100);
7496
+ }
7497
+ function resolveColor(host, value) {
7498
+ if (value === "currentColor") return getComputedStyle(host).color;
7499
+ return value;
7500
+ }
7501
+ var DotSphere = react.forwardRef(
7502
+ function DotSphere2({
7503
+ className,
7504
+ dotGap = 20,
7505
+ motion = "travel",
7506
+ sphereCount = 3,
7507
+ sphereRadius = 200,
7508
+ dotRadiusMax = 3,
7509
+ speed = 0.18,
7510
+ bgColor = "transparent",
7511
+ dotColor = "currentColor",
7512
+ followMouse = false,
7513
+ ...props
7514
+ }, ref) {
7515
+ const innerRef = react.useRef(null);
7516
+ react.useEffect(() => {
7517
+ const canvas = innerRef.current;
7518
+ if (!canvas) return;
7519
+ const ctx = canvas.getContext("2d");
7520
+ if (!ctx) return;
7521
+ const canvasElement = canvas;
7522
+ const context = ctx;
7523
+ const resolvedBg = bgColor === "transparent" ? null : bgColor;
7524
+ const resolvedDot = resolveColor(canvasElement, dotColor);
7525
+ const prefersReducedMotion = window.matchMedia(
7526
+ "(prefers-reduced-motion: reduce)"
7527
+ ).matches;
7528
+ const state = {
7529
+ windowSize: { w: 0, h: 0 },
7530
+ circleNumber: { x: 0, y: 0 },
7531
+ posStart: { x: 0, y: 0 },
7532
+ spheres: []
7533
+ };
7534
+ state.spheres = Array.from({ length: Math.max(1, sphereCount) }, (_, index) => {
7535
+ const path = SPHERE_PATHS[index % SPHERE_PATHS.length] ?? SPHERE_PATHS[0];
7536
+ const anchor = WAVE_SPHERE_ANCHORS[index % WAVE_SPHERE_ANCHORS.length] ?? WAVE_SPHERE_ANCHORS[0];
7537
+ const profile = SPHERE_PROFILES[index % SPHERE_PROFILES.length] ?? SPHERE_PROFILES[0];
7538
+ return {
7539
+ center: { x: 0, y: 0 },
7540
+ anchor,
7541
+ from: path.from,
7542
+ to: path.to,
7543
+ progress: profile.phase,
7544
+ radius: 0,
7545
+ radiusScale: profile.radius,
7546
+ dotRadiusMax: 0,
7547
+ dotScale: profile.dot,
7548
+ speed: speed * profile.speed,
7549
+ color: resolvedDot,
7550
+ opacity: 0
7551
+ };
7552
+ });
7553
+ function setDotParams() {
7554
+ state.circleNumber = {
7555
+ x: Math.floor(state.windowSize.w / dotGap) + 2,
7556
+ y: Math.floor(state.windowSize.h / dotGap) + 1
7557
+ };
7558
+ state.posStart = {
7559
+ x: Math.round(
7560
+ (state.windowSize.w - (state.circleNumber.x - 1) * dotGap) / 2
7561
+ ),
7562
+ y: Math.round(
7563
+ (state.windowSize.h - (state.circleNumber.y - 1) * dotGap) / 2
7564
+ )
7565
+ };
7566
+ }
7567
+ function updateSpherePosition(sphere) {
7568
+ if (motion === "wave") {
7569
+ sphere.center.x = sphere.anchor.x * state.windowSize.w;
7570
+ sphere.center.y = sphere.anchor.y * state.windowSize.h;
7571
+ sphere.opacity = getWaveOpacity(sphere.progress);
7572
+ return;
7573
+ }
7574
+ const easedProgress = easeInOutSine(sphere.progress);
7575
+ sphere.center.x = lerp(sphere.from.x, sphere.to.x, easedProgress) * state.windowSize.w;
7576
+ sphere.center.y = lerp(sphere.from.y, sphere.to.y, easedProgress) * state.windowSize.h;
7577
+ sphere.opacity = getTravelOpacity(sphere.progress);
7578
+ }
7579
+ function handleResize() {
7580
+ const bounds = canvasElement.getBoundingClientRect();
7581
+ const dpr = Math.min(window.devicePixelRatio || 1, 2);
7582
+ const width = Math.max(1, Math.floor(bounds.width));
7583
+ const height = Math.max(1, Math.floor(bounds.height));
7584
+ state.windowSize = { w: width, h: height };
7585
+ canvasElement.width = Math.floor(width * dpr);
7586
+ canvasElement.height = Math.floor(height * dpr);
7587
+ context.setTransform(dpr, 0, 0, dpr, 0, 0);
7588
+ setDotParams();
7589
+ state.spheres.forEach((sphere) => {
7590
+ sphere.radius = resolveSphereRadius(sphereRadius, state.windowSize) * sphere.radiusScale;
7591
+ sphere.dotRadiusMax = dotRadiusMax * sphere.dotScale;
7592
+ updateSpherePosition(sphere);
7593
+ });
7594
+ }
7595
+ function drawDots() {
7596
+ const { w, h } = state.windowSize;
7597
+ if (resolvedBg) {
7598
+ context.beginPath();
7599
+ context.fillStyle = resolvedBg;
7600
+ context.rect(0, 0, w, h);
7601
+ context.fill();
7602
+ context.closePath();
7603
+ } else {
7604
+ context.clearRect(0, 0, w, h);
7605
+ }
7606
+ context.globalCompositeOperation = "lighter";
7607
+ state.spheres.forEach((sphere) => {
7608
+ if (sphere.opacity <= 0.01) return;
7609
+ for (let i = 0; i < state.circleNumber.x; i++) {
7610
+ for (let j = 0; j < state.circleNumber.y; j++) {
7611
+ const gapX = j % 2 === 0 ? -dotGap / 2 : 0;
7612
+ const x = state.posStart.x + gapX + i * dotGap;
7613
+ const y = state.posStart.y + j * dotGap;
7614
+ const dx = x - sphere.center.x;
7615
+ const dy = y - sphere.center.y;
7616
+ const distance = Math.sqrt(dx * dx + dy * dy);
7617
+ if (distance >= sphere.radius) continue;
7618
+ const alpha = 1 - distance / sphere.radius;
7619
+ const radius = sphere.dotRadiusMax * alpha;
7620
+ context.save();
7621
+ context.globalAlpha = alpha * sphere.opacity;
7622
+ context.beginPath();
7623
+ context.fillStyle = sphere.color;
7624
+ context.arc(x, y, radius, 0, 2 * Math.PI, false);
7625
+ context.fill();
7626
+ context.closePath();
7627
+ context.restore();
7628
+ }
7629
+ }
7630
+ });
7631
+ context.globalCompositeOperation = "source-over";
7632
+ }
7633
+ function moveSpheres(event) {
7634
+ const bounds = event ? canvasElement.getBoundingClientRect() : null;
7635
+ state.spheres.forEach((sphere, index) => {
7636
+ if (event && followMouse && index === 0 && bounds) {
7637
+ sphere.center.x = event.clientX - bounds.left;
7638
+ sphere.center.y = event.clientY - bounds.top;
7639
+ sphere.opacity = 1;
7640
+ return;
7641
+ }
7642
+ if (followMouse && index === 0) return;
7643
+ sphere.progress = (sphere.progress + sphere.speed * (motion === "wave" ? 21e-4 : 35e-4)) % 1;
7644
+ updateSpherePosition(sphere);
7645
+ });
7646
+ }
7647
+ function render() {
7648
+ if (!prefersReducedMotion) moveSpheres(null);
7649
+ drawDots();
7650
+ }
7651
+ let animationId = 0;
7652
+ function draw() {
7653
+ animationId = window.requestAnimationFrame(draw);
7654
+ render();
7655
+ }
7656
+ function handleMouseMove(event) {
7657
+ if (followMouse) moveSpheres(event);
7658
+ }
7659
+ const resizeObserver = new ResizeObserver(handleResize);
7660
+ resizeObserver.observe(canvasElement);
7661
+ handleResize();
7662
+ render();
7663
+ if (!prefersReducedMotion) draw();
7664
+ if (followMouse) window.addEventListener("mousemove", handleMouseMove);
7665
+ return () => {
7666
+ resizeObserver.disconnect();
7667
+ window.removeEventListener("mousemove", handleMouseMove);
7668
+ window.cancelAnimationFrame(animationId);
7669
+ };
7670
+ }, [dotGap, motion, sphereCount, sphereRadius, dotRadiusMax, speed, bgColor, dotColor, followMouse]);
7671
+ return /* @__PURE__ */ jsxRuntime.jsx(
7672
+ "canvas",
7673
+ {
7674
+ ref: (node) => {
7675
+ innerRef.current = node;
7676
+ if (typeof ref === "function") ref(node);
7677
+ else if (ref) ref.current = node;
7678
+ },
7679
+ className: chunkTPGAXYFU_cjs.cx("klun-dot-sphere", className),
7680
+ ...props
6160
7681
  }
6161
7682
  );
6162
7683
  }
6163
7684
  );
6164
- CircularProgress.displayName = "CircularProgress";
7685
+ DotSphere.displayName = "DotSphere";
6165
7686
  var EmptyState = react.forwardRef(function EmptyState2({ icon, title, description, action, className, ...props }, ref) {
6166
7687
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-empty-state", className), ...props, children: [
6167
7688
  icon ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-empty-state__icon", children: icon }) : null,
@@ -6284,6 +7805,33 @@ function useMessage(defaults = {}) {
6284
7805
  return [api, holder];
6285
7806
  }
6286
7807
  Message.useMessage = useMessage;
7808
+ function NavigationProgress({
7809
+ active,
7810
+ position = "fixed",
7811
+ top = 0,
7812
+ className,
7813
+ style
7814
+ }) {
7815
+ const [renderSweep, setRenderSweep] = react.useState(false);
7816
+ react.useEffect(() => {
7817
+ if (active) setRenderSweep(true);
7818
+ }, [active]);
7819
+ return /* @__PURE__ */ jsxRuntime.jsx(
7820
+ "div",
7821
+ {
7822
+ "aria-hidden": "true",
7823
+ role: "presentation",
7824
+ "data-active": active ? "true" : "false",
7825
+ "data-position": position,
7826
+ className: chunkTPGAXYFU_cjs.cx("klun-navigation-progress", className),
7827
+ style: { top, ...style },
7828
+ onTransitionEnd: (event) => {
7829
+ if (!active) setRenderSweep(false);
7830
+ },
7831
+ children: renderSweep && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-navigation-progress__sweep" })
7832
+ }
7833
+ );
7834
+ }
6287
7835
  var STATUS2 = {
6288
7836
  default: { icon: "ri-notification-3-line", c: null },
6289
7837
  information: { icon: "ri-information-fill", c: "information" },
@@ -6726,6 +8274,54 @@ function ToastRow({
6726
8274
  }
6727
8275
  );
6728
8276
  }
8277
+
8278
+ // src/components/feedback/unicode-spinner-data.ts
8279
+ var UNICODE_ANIMATIONS = {
8280
+ "braille": { interval: 80, frames: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"] },
8281
+ "braillewave": { interval: 100, frames: ["\u2801\u2802\u2804\u2840", "\u2802\u2804\u2840\u2880", "\u2804\u2840\u2880\u2820", "\u2840\u2880\u2820\u2810", "\u2880\u2820\u2810\u2808", "\u2820\u2810\u2808\u2801", "\u2810\u2808\u2801\u2802", "\u2808\u2801\u2802\u2804"] },
8282
+ "dna": { interval: 80, frames: ["\u280B\u2809\u2819\u281A", "\u2809\u2819\u281A\u2812", "\u2819\u281A\u2812\u2802", "\u281A\u2812\u2802\u2802", "\u2812\u2802\u2802\u2812", "\u2802\u2802\u2812\u2832", "\u2802\u2812\u2832\u2834", "\u2812\u2832\u2834\u2824", "\u2832\u2834\u2824\u2804", "\u2834\u2824\u2804\u280B", "\u2824\u2804\u280B\u2809", "\u2804\u280B\u2809\u2819"] },
8283
+ "scan": { interval: 70, frames: ["\u2800\u2800\u2800\u2800", "\u2847\u2800\u2800\u2800", "\u28FF\u2800\u2800\u2800", "\u28B8\u2847\u2800\u2800", "\u2800\u28FF\u2800\u2800", "\u2800\u28B8\u2847\u2800", "\u2800\u2800\u28FF\u2800", "\u2800\u2800\u28B8\u2847", "\u2800\u2800\u2800\u28FF", "\u2800\u2800\u2800\u28B8"] },
8284
+ "rain": { interval: 100, frames: ["\u2881\u2802\u2814\u2808", "\u2802\u280C\u2860\u2810", "\u2804\u2850\u2880\u2821", "\u2848\u2820\u2800\u2882", "\u2810\u2880\u2801\u2804", "\u2820\u2801\u280A\u2840", "\u2881\u2802\u2814\u2808", "\u2802\u280C\u2860\u2810", "\u2804\u2850\u2880\u2821", "\u2848\u2820\u2800\u2882", "\u2810\u2880\u2801\u2804", "\u2820\u2801\u280A\u2840"] },
8285
+ "scanline": { interval: 120, frames: ["\u2809\u2809\u2809", "\u2813\u2813\u2813", "\u2826\u2826\u2826", "\u28C4\u28C4\u28C4", "\u2826\u2826\u2826", "\u2813\u2813\u2813"] },
8286
+ "pulse": { interval: 180, frames: ["\u2800\u2836\u2800", "\u2830\u28FF\u2806", "\u28BE\u28C9\u2877", "\u28CF\u2800\u28F9", "\u2841\u2800\u2888"] },
8287
+ "snake": { interval: 80, frames: ["\u28C1\u2840", "\u28C9\u2800", "\u2849\u2801", "\u2809\u2809", "\u2808\u2819", "\u2800\u281B", "\u2810\u281A", "\u2812\u2812", "\u2816\u2802", "\u2836\u2800", "\u2826\u2804", "\u2824\u2824", "\u2820\u28A4", "\u2800\u28E4", "\u2880\u28E0", "\u28C0\u28C0"] },
8288
+ "sparkle": { interval: 150, frames: ["\u2861\u280A\u2894\u2821", "\u280A\u2870\u2861\u2858", "\u2894\u2885\u2808\u28A2", "\u2841\u2882\u2806\u284D", "\u2894\u2828\u2891\u2890", "\u2828\u2851\u2860\u280A"] },
8289
+ "cascade": { interval: 60, frames: ["\u2800\u2800\u2800\u2800", "\u2800\u2800\u2800\u2800", "\u2801\u2800\u2800\u2800", "\u280B\u2800\u2800\u2800", "\u281E\u2801\u2800\u2800", "\u2874\u280B\u2800\u2800", "\u28E0\u281E\u2801\u2800", "\u2880\u2874\u280B\u2800", "\u2800\u28E0\u281E\u2801", "\u2800\u2880\u2874\u280B", "\u2800\u2800\u28E0\u281E", "\u2800\u2800\u2880\u2874", "\u2800\u2800\u2800\u28E0", "\u2800\u2800\u2800\u2880"] },
8290
+ "columns": { interval: 60, frames: ["\u2840\u2800\u2800", "\u2844\u2800\u2800", "\u2846\u2800\u2800", "\u2847\u2800\u2800", "\u28C7\u2800\u2800", "\u28E7\u2800\u2800", "\u28F7\u2800\u2800", "\u28FF\u2800\u2800", "\u28FF\u2840\u2800", "\u28FF\u2844\u2800", "\u28FF\u2846\u2800", "\u28FF\u2847\u2800", "\u28FF\u28C7\u2800", "\u28FF\u28E7\u2800", "\u28FF\u28F7\u2800", "\u28FF\u28FF\u2800", "\u28FF\u28FF\u2840", "\u28FF\u28FF\u2844", "\u28FF\u28FF\u2846", "\u28FF\u28FF\u2847", "\u28FF\u28FF\u28C7", "\u28FF\u28FF\u28E7", "\u28FF\u28FF\u28F7", "\u28FF\u28FF\u28FF", "\u28FF\u28FF\u28FF", "\u2800\u2800\u2800"] },
8291
+ "orbit": { interval: 100, frames: ["\u2803", "\u2809", "\u2818", "\u2830", "\u28A0", "\u28C0", "\u2844", "\u2806"] },
8292
+ "breathe": { interval: 100, frames: ["\u2800", "\u2802", "\u280C", "\u2851", "\u2895", "\u289D", "\u28EB", "\u28DF", "\u28FF", "\u28DF", "\u28EB", "\u289D", "\u2895", "\u2851", "\u280C", "\u2802", "\u2800"] },
8293
+ "waverows": { interval: 90, frames: ["\u2816\u2809\u2809\u2811", "\u2860\u2816\u2809\u2809", "\u28E0\u2860\u2816\u2809", "\u28C4\u28E0\u2860\u2816", "\u2822\u28C4\u28E0\u2860", "\u2819\u2822\u28C4\u28E0", "\u2809\u2819\u2822\u28C4", "\u280A\u2809\u2819\u2822", "\u281C\u280A\u2809\u2819", "\u2864\u281C\u280A\u2809", "\u28C0\u2864\u281C\u280A", "\u28A4\u28C0\u2864\u281C", "\u2823\u28A4\u28C0\u2864", "\u2811\u2823\u28A4\u28C0", "\u2809\u2811\u2823\u28A4", "\u280B\u2809\u2811\u2823"] },
8294
+ "checkerboard": { interval: 250, frames: ["\u2895\u2895\u2895", "\u286A\u286A\u286A", "\u288A\u2814\u2861", "\u2861\u288A\u2814"] },
8295
+ "helix": { interval: 80, frames: ["\u288C\u28C9\u288E\u28C9", "\u28C9\u2871\u28C9\u2871", "\u28C9\u288E\u28C9\u288E", "\u2871\u28C9\u2871\u28C9", "\u288E\u28C9\u288E\u28C9", "\u28C9\u2871\u28C9\u2871", "\u28C9\u288E\u28C9\u288E", "\u2871\u28C9\u2871\u28C9", "\u288E\u28C9\u288E\u28C9", "\u28C9\u2871\u28C9\u2871", "\u28C9\u288E\u28C9\u288E", "\u2871\u28C9\u2871\u28C9", "\u288E\u28C9\u288E\u28C9", "\u28C9\u2871\u28C9\u2871", "\u28C9\u288E\u28C9\u288E", "\u2871\u28C9\u2871\u28C9"] },
8296
+ "fillsweep": { interval: 100, frames: ["\u28C0\u28C0", "\u28E4\u28E4", "\u28F6\u28F6", "\u28FF\u28FF", "\u28FF\u28FF", "\u28FF\u28FF", "\u28F6\u28F6", "\u28E4\u28E4", "\u28C0\u28C0", "\u2800\u2800", "\u2800\u2800"] },
8297
+ "diagswipe": { interval: 60, frames: ["\u2801\u2800", "\u280B\u2800", "\u281F\u2801", "\u287F\u280B", "\u28FF\u281F", "\u28FF\u287F", "\u28FF\u28FF", "\u28FF\u28FF", "\u28FE\u28FF", "\u28F4\u28FF", "\u28E0\u28FE", "\u2880\u28F4", "\u2800\u28E0", "\u2800\u2880", "\u2800\u2800", "\u2800\u2800"] }
8298
+ };
8299
+ var UnicodeSpinner = react.forwardRef(
8300
+ function UnicodeSpinner2({ name = "braille", paused = false, className, ...props }, ref) {
8301
+ const spec = UNICODE_ANIMATIONS[name];
8302
+ const [frame, setFrame] = react.useState(0);
8303
+ react.useEffect(() => {
8304
+ if (paused) return;
8305
+ setFrame(0);
8306
+ const timer = setInterval(
8307
+ () => setFrame((f) => (f + 1) % spec.frames.length),
8308
+ spec.interval
8309
+ );
8310
+ return () => clearInterval(timer);
8311
+ }, [name, paused, spec]);
8312
+ return /* @__PURE__ */ jsxRuntime.jsx(
8313
+ "span",
8314
+ {
8315
+ ref,
8316
+ className: chunkTPGAXYFU_cjs.cx("klun-unicode-spinner", className),
8317
+ "aria-hidden": "true",
8318
+ ...props,
8319
+ children: spec.frames[frame]
8320
+ }
8321
+ );
8322
+ }
8323
+ );
8324
+ UnicodeSpinner.displayName = "UnicodeSpinner";
6729
8325
  var AutoComplete = react.forwardRef(
6730
8326
  function AutoComplete2({
6731
8327
  options = [],
@@ -7812,6 +9408,69 @@ var CompactSelectForInput = react.forwardRef(function CompactSelectForInput2({
7812
9408
  );
7813
9409
  });
7814
9410
  CompactSelectForInput.displayName = "CompactSelectForInput";
9411
+ var CounterInput = react.forwardRef(function CounterInput2({
9412
+ value = 0,
9413
+ min = -Infinity,
9414
+ max = Infinity,
9415
+ step = 1,
9416
+ size: sizeProp,
9417
+ onChange,
9418
+ disabled = false,
9419
+ suffix,
9420
+ className,
9421
+ ...props
9422
+ }, ref) {
9423
+ const size = useSize(sizeProp);
9424
+ const { counterInput } = useLocale();
9425
+ const decreaseLabel = counterInput?.decrease ?? "Decrease";
9426
+ const increaseLabel = counterInput?.increase ?? "Increase";
9427
+ const set = (next) => {
9428
+ const v = Math.max(min, Math.min(max, next));
9429
+ if (v !== value) onChange?.(v);
9430
+ };
9431
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9432
+ "div",
9433
+ {
9434
+ ref,
9435
+ className: chunkTPGAXYFU_cjs.cx(
9436
+ "klun-counter-input",
9437
+ `klun-counter-input--${size}`,
9438
+ disabled && "klun-counter-input--disabled",
9439
+ className
9440
+ ),
9441
+ ...props,
9442
+ children: [
9443
+ /* @__PURE__ */ jsxRuntime.jsx(
9444
+ "button",
9445
+ {
9446
+ type: "button",
9447
+ className: "klun-counter-input__step",
9448
+ "aria-label": decreaseLabel,
9449
+ disabled: disabled || value <= min,
9450
+ onClick: () => set(value - step),
9451
+ children: /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-subtract-line" })
9452
+ }
9453
+ ),
9454
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "klun-counter-input__value", children: [
9455
+ value,
9456
+ suffix ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-counter-input__suffix", children: suffix }) : null
9457
+ ] }),
9458
+ /* @__PURE__ */ jsxRuntime.jsx(
9459
+ "button",
9460
+ {
9461
+ type: "button",
9462
+ className: "klun-counter-input__step",
9463
+ "aria-label": increaseLabel,
9464
+ disabled: disabled || value >= max,
9465
+ onClick: () => set(value + step),
9466
+ children: /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-add-line" })
9467
+ }
9468
+ )
9469
+ ]
9470
+ }
9471
+ );
9472
+ });
9473
+ CounterInput.displayName = "CounterInput";
7815
9474
  var CRON_PRESETS = [
7816
9475
  { label: "Every 5 minutes", value: "*/5 * * * *" },
7817
9476
  { label: "Every 15 minutes", value: "*/15 * * * *" },
@@ -7955,64 +9614,6 @@ var CronEditor = react.forwardRef(function CronEditor2({
7955
9614
  );
7956
9615
  });
7957
9616
  CronEditor.displayName = "CronEditor";
7958
- var CounterInput = react.forwardRef(function CounterInput2({
7959
- value = 0,
7960
- min = -Infinity,
7961
- max = Infinity,
7962
- step = 1,
7963
- size: sizeProp,
7964
- onChange,
7965
- disabled = false,
7966
- suffix,
7967
- className,
7968
- ...props
7969
- }, ref) {
7970
- const size = useSize(sizeProp);
7971
- const set = (next) => {
7972
- const v = Math.max(min, Math.min(max, next));
7973
- if (v !== value) onChange?.(v);
7974
- };
7975
- return /* @__PURE__ */ jsxRuntime.jsxs(
7976
- "div",
7977
- {
7978
- ref,
7979
- className: chunkTPGAXYFU_cjs.cx(
7980
- "klun-counter-input",
7981
- `klun-counter-input--${size}`,
7982
- disabled && "klun-counter-input--disabled",
7983
- className
7984
- ),
7985
- ...props,
7986
- children: [
7987
- /* @__PURE__ */ jsxRuntime.jsx(
7988
- "button",
7989
- {
7990
- type: "button",
7991
- className: "klun-counter-input__step",
7992
- disabled: disabled || value <= min,
7993
- onClick: () => set(value - step),
7994
- children: /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-subtract-line" })
7995
- }
7996
- ),
7997
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "klun-counter-input__value", children: [
7998
- value,
7999
- suffix ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-counter-input__suffix", children: suffix }) : null
8000
- ] }),
8001
- /* @__PURE__ */ jsxRuntime.jsx(
8002
- "button",
8003
- {
8004
- type: "button",
8005
- className: "klun-counter-input__step",
8006
- disabled: disabled || value >= max,
8007
- onClick: () => set(value + step),
8008
- children: /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-add-line" })
8009
- }
8010
- )
8011
- ]
8012
- }
8013
- );
8014
- });
8015
- CounterInput.displayName = "CounterInput";
8016
9617
  var Input = react.forwardRef(function Input2({
8017
9618
  size: sizeProp,
8018
9619
  leadingIcon,
@@ -8088,107 +9689,25 @@ var Input = react.forwardRef(function Input2({
8088
9689
  }
8089
9690
  ),
8090
9691
  showClear ? /* @__PURE__ */ jsxRuntime.jsx(
8091
- "button",
8092
- {
8093
- type: "button",
8094
- className: "klun-input__clear",
8095
- onClick: clear,
8096
- "aria-label": input.clear,
8097
- children: /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-close-circle-fill" })
8098
- }
8099
- ) : null,
8100
- trailingNode,
8101
- loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-input__spinner", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "klun-input__spinner-svg", width: 18, height: 18, viewBox: "0 0 20 20", fill: "none", children: [
8102
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "10", cy: "10", r: "7", stroke: "currentColor", strokeOpacity: "0.25", strokeWidth: "2.5" }),
8103
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "10", cy: "10", r: "7", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeDasharray: "44", strokeDashoffset: "31" })
8104
- ] }) }) : trailingIcon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-input__icon", children: trailingIcon }) : null
8105
- ]
8106
- }
8107
- );
8108
- });
8109
- Input.displayName = "Input";
8110
- var Popover = react.forwardRef(function Popover2({ trigger, children, align = "left", width = 280, className, ...props }, ref) {
8111
- const [open, setOpen] = react.useState(false);
8112
- const wrapRef = react.useRef(null);
8113
- const panelRef = react.useRef(null);
8114
- const portal = typeof document !== "undefined";
8115
- const [pos, setPos] = react.useState(null);
8116
- react.useEffect(() => {
8117
- if (!open) return;
8118
- const h = (e) => {
8119
- const t = e.target;
8120
- if (wrapRef.current?.contains(t)) return;
8121
- if (panelRef.current?.contains(t)) return;
8122
- setOpen(false);
8123
- };
8124
- document.addEventListener("mousedown", h);
8125
- return () => document.removeEventListener("mousedown", h);
8126
- }, [open]);
8127
- react.useLayoutEffect(() => {
8128
- if (!open || !portal) return;
8129
- const anchor = wrapRef.current;
8130
- const panel2 = panelRef.current;
8131
- if (!anchor || !panel2) return;
8132
- const place2 = () => {
8133
- const a = anchor.getBoundingClientRect();
8134
- const gap = 8;
8135
- const margin = 8;
8136
- const pw = panel2.offsetWidth || width;
8137
- const ph = panel2.offsetHeight;
8138
- const below = window.innerHeight - a.bottom;
8139
- const openUp = below < ph + gap && a.top > below;
8140
- const top = openUp ? Math.max(margin, a.top - gap - ph) : Math.min(a.bottom + gap, window.innerHeight - margin - ph);
8141
- let left = align === "right" ? a.right - pw : a.left;
8142
- if (left + pw > window.innerWidth - margin) left = window.innerWidth - margin - pw;
8143
- if (left < margin) left = margin;
8144
- setPos({ left, top });
8145
- };
8146
- place2();
8147
- window.addEventListener("scroll", place2, true);
8148
- window.addEventListener("resize", place2);
8149
- return () => {
8150
- window.removeEventListener("scroll", place2, true);
8151
- window.removeEventListener("resize", place2);
8152
- };
8153
- }, [open, portal, align, width]);
8154
- react.useEffect(() => {
8155
- if (!open) setPos(null);
8156
- }, [open]);
8157
- const setRefs = (node) => {
8158
- wrapRef.current = node;
8159
- if (typeof ref === "function") ref(node);
8160
- else if (ref) ref.current = node;
8161
- };
8162
- const content = typeof children === "function" ? children(() => setOpen(false)) : children;
8163
- const portalStyle = {
8164
- position: "fixed",
8165
- left: pos?.left ?? 0,
8166
- top: pos?.top ?? 0,
8167
- width,
8168
- zIndex: 1150,
8169
- // keep hidden until measured to avoid a flash at the top-left corner
8170
- visibility: pos ? "visible" : "hidden"
8171
- };
8172
- const panel = open ? /* @__PURE__ */ jsxRuntime.jsx(
8173
- "div",
8174
- {
8175
- ref: panelRef,
8176
- role: "dialog",
8177
- className: chunkTPGAXYFU_cjs.cx(
8178
- "klun-popover__panel",
8179
- // in-flow fallback keeps the legacy left/right anchoring classes
8180
- !portal && `klun-popover__panel--${align}`
8181
- ),
8182
- style: portal ? portalStyle : { width },
8183
- children: content
9692
+ "button",
9693
+ {
9694
+ type: "button",
9695
+ className: "klun-input__clear",
9696
+ onClick: clear,
9697
+ "aria-label": input.clear,
9698
+ children: /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-close-circle-fill" })
9699
+ }
9700
+ ) : null,
9701
+ trailingNode,
9702
+ loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-input__spinner", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "klun-input__spinner-svg", width: 18, height: 18, viewBox: "0 0 20 20", fill: "none", children: [
9703
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "10", cy: "10", r: "7", stroke: "currentColor", strokeOpacity: "0.25", strokeWidth: "2.5" }),
9704
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "10", cy: "10", r: "7", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeDasharray: "44", strokeDashoffset: "31" })
9705
+ ] }) }) : trailingIcon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-input__icon", children: trailingIcon }) : null
9706
+ ]
8184
9707
  }
8185
- ) : null;
8186
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { ref: setRefs, className: chunkTPGAXYFU_cjs.cx("klun-popover", className), ...props, children: [
8187
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-popover__trigger", onClick: () => setOpen((o) => !o), children: trigger }),
8188
- portal ? panel && reactDom.createPortal(panel, document.body) : panel
8189
- ] });
9708
+ );
8190
9709
  });
8191
- Popover.displayName = "Popover";
9710
+ Input.displayName = "Input";
8192
9711
  var same = (a, b) => !!a && !!b && a.toDateString() === b.toDateString();
8193
9712
  var DEFAULT_FORMAT = {
8194
9713
  year: "numeric",
@@ -8689,6 +10208,56 @@ var DigitInput = react.forwardRef(function DigitInput2({ length = 4, value = "",
8689
10208
  );
8690
10209
  });
8691
10210
  DigitInput.displayName = "DigitInput";
10211
+ var FieldGroup = react.forwardRef(
10212
+ function FieldGroup2({ className, ...props }, ref) {
10213
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-field-group", className), ...props });
10214
+ }
10215
+ );
10216
+ FieldGroup.displayName = "FieldGroup";
10217
+ var Field = react.forwardRef(function Field2({ orientation = "vertical", invalid = false, className, ...props }, ref) {
10218
+ return /* @__PURE__ */ jsxRuntime.jsx(
10219
+ "div",
10220
+ {
10221
+ ref,
10222
+ role: "group",
10223
+ "data-orientation": orientation,
10224
+ "data-invalid": invalid ? "" : void 0,
10225
+ className: chunkTPGAXYFU_cjs.cx("klun-field", `klun-field--${orientation}`, className),
10226
+ ...props
10227
+ }
10228
+ );
10229
+ });
10230
+ Field.displayName = "Field";
10231
+ var FieldContent = react.forwardRef(
10232
+ function FieldContent2({ className, ...props }, ref) {
10233
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-field__content", className), ...props });
10234
+ }
10235
+ );
10236
+ FieldContent.displayName = "FieldContent";
10237
+ var FieldLabel = react.forwardRef(
10238
+ function FieldLabel2({ className, ...props }, ref) {
10239
+ return /* @__PURE__ */ jsxRuntime.jsx("label", { ref, className: chunkTPGAXYFU_cjs.cx("klun-field__label", className), ...props });
10240
+ }
10241
+ );
10242
+ FieldLabel.displayName = "FieldLabel";
10243
+ var FieldTitle = react.forwardRef(
10244
+ function FieldTitle2({ className, ...props }, ref) {
10245
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-field__title", className), ...props });
10246
+ }
10247
+ );
10248
+ FieldTitle.displayName = "FieldTitle";
10249
+ var FieldDescription = react.forwardRef(
10250
+ function FieldDescription2({ className, ...props }, ref) {
10251
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-field__description", className), ...props });
10252
+ }
10253
+ );
10254
+ FieldDescription.displayName = "FieldDescription";
10255
+ var FieldError = react.forwardRef(
10256
+ function FieldError2({ className, role = "alert", ...props }, ref) {
10257
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, role, className: chunkTPGAXYFU_cjs.cx("klun-field__error", className), ...props });
10258
+ }
10259
+ );
10260
+ FieldError.displayName = "FieldError";
8692
10261
  var FileUpload = react.forwardRef(function FileUpload2({ onFiles, hint = "SVG, PNG, JPG or GIF (max. 8MB)", className, ...props }, ref) {
8693
10262
  const { fileUpload } = useLocale();
8694
10263
  const [over, setOver] = react.useState(false);
@@ -9101,6 +10670,388 @@ var Hint = react.forwardRef(function Hint2({ children, error = false, icon, clas
9101
10670
  );
9102
10671
  });
9103
10672
  Hint.displayName = "Hint";
10673
+ var Modal = react.forwardRef(function Modal2({
10674
+ open,
10675
+ onClose,
10676
+ onOk,
10677
+ onCancel,
10678
+ title,
10679
+ description,
10680
+ icon,
10681
+ footer,
10682
+ okText,
10683
+ cancelText,
10684
+ confirmLoading = false,
10685
+ okType = "primary",
10686
+ okButtonProps,
10687
+ cancelButtonProps,
10688
+ width = 520,
10689
+ centered = false,
10690
+ closable = true,
10691
+ maskClosable,
10692
+ closeOnBackdrop,
10693
+ keyboard = true,
10694
+ mask = true,
10695
+ draggable = false,
10696
+ maximizable = false,
10697
+ defaultMaximized = false,
10698
+ zIndex,
10699
+ afterClose,
10700
+ afterOpenChange,
10701
+ children,
10702
+ className,
10703
+ style,
10704
+ ...props
10705
+ }, ref) {
10706
+ const { modal } = useLocale();
10707
+ const cancel = onCancel ?? onClose;
10708
+ const backdropClosable = maskClosable ?? closeOnBackdrop ?? true;
10709
+ const [pos, setPos] = react.useState({ x: 0, y: 0 });
10710
+ const [maximized, setMaximized] = react.useState(defaultMaximized);
10711
+ const drag = react.useRef(null);
10712
+ const prevOpen = react.useRef(open);
10713
+ react.useEffect(() => {
10714
+ if (!open) return;
10715
+ const onKey = (e) => {
10716
+ if (e.key === "Escape" && keyboard && closable) cancel?.();
10717
+ };
10718
+ document.addEventListener("keydown", onKey);
10719
+ const prevOverflow = document.body.style.overflow;
10720
+ document.body.style.overflow = "hidden";
10721
+ return () => {
10722
+ document.removeEventListener("keydown", onKey);
10723
+ document.body.style.overflow = prevOverflow;
10724
+ };
10725
+ }, [open, keyboard, closable, cancel]);
10726
+ react.useEffect(() => {
10727
+ if (open) {
10728
+ setPos({ x: 0, y: 0 });
10729
+ setMaximized(defaultMaximized);
10730
+ }
10731
+ if (prevOpen.current !== open) {
10732
+ afterOpenChange?.(open);
10733
+ if (!open) afterClose?.();
10734
+ prevOpen.current = open;
10735
+ }
10736
+ }, [open]);
10737
+ if (!open) return null;
10738
+ const startDrag = (e) => {
10739
+ if (!draggable || maximized) return;
10740
+ if (e.target.closest(".klun-modal__actions")) return;
10741
+ drag.current = { sx: e.clientX, sy: e.clientY, ox: pos.x, oy: pos.y };
10742
+ const move = (ev) => {
10743
+ if (!drag.current) return;
10744
+ setPos({
10745
+ x: drag.current.ox + (ev.clientX - drag.current.sx),
10746
+ y: drag.current.oy + (ev.clientY - drag.current.sy)
10747
+ });
10748
+ };
10749
+ const up = () => {
10750
+ drag.current = null;
10751
+ document.removeEventListener("mousemove", move);
10752
+ document.removeEventListener("mouseup", up);
10753
+ };
10754
+ document.addEventListener("mousemove", move);
10755
+ document.addEventListener("mouseup", up);
10756
+ };
10757
+ const defaultFooter = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
10758
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "neutral", appearance: "stroke", disabled: confirmLoading, onClick: cancel, ...cancelButtonProps, children: cancelText ?? "Cancel" }),
10759
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: okType === "danger" ? "error" : "primary", loading: confirmLoading, onClick: onOk, ...okButtonProps, children: okText ?? "OK" })
10760
+ ] });
10761
+ const resolvedFooter = footer === null ? null : footer !== void 0 ? footer : defaultFooter;
10762
+ const dialogStyle = maximized ? { ...style } : {
10763
+ width,
10764
+ ...pos.x || pos.y ? { transform: `translate(${pos.x}px, ${pos.y}px)` } : null,
10765
+ ...style
10766
+ };
10767
+ return /* @__PURE__ */ jsxRuntime.jsx(
10768
+ "div",
10769
+ {
10770
+ className: chunkTPGAXYFU_cjs.cx("klun-modal", centered && "klun-modal--centered", !mask && "klun-modal--no-mask"),
10771
+ style: zIndex != null ? { zIndex } : void 0,
10772
+ onClick: backdropClosable && closable ? cancel : void 0,
10773
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
10774
+ "div",
10775
+ {
10776
+ ref,
10777
+ role: "dialog",
10778
+ "aria-modal": "true",
10779
+ onClick: (e) => e.stopPropagation(),
10780
+ className: chunkTPGAXYFU_cjs.cx("klun-modal__dialog", maximized && "klun-modal__dialog--maximized", className),
10781
+ style: dialogStyle,
10782
+ ...props,
10783
+ children: [
10784
+ title || icon ? /* @__PURE__ */ jsxRuntime.jsxs(
10785
+ "div",
10786
+ {
10787
+ className: chunkTPGAXYFU_cjs.cx("klun-modal__header", draggable && !maximized && "klun-modal__header--draggable"),
10788
+ onMouseDown: startDrag,
10789
+ children: [
10790
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-modal__icon", children: icon }) : null,
10791
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-modal__heading", children: [
10792
+ title ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-modal__title", children: title }) : null,
10793
+ description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-modal__description", children: description }) : null
10794
+ ] }),
10795
+ maximizable || closable ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-modal__actions", children: [
10796
+ maximizable ? /* @__PURE__ */ jsxRuntime.jsx(
10797
+ "button",
10798
+ {
10799
+ type: "button",
10800
+ onClick: () => setMaximized((m) => !m),
10801
+ "aria-label": maximized ? modal.restore ?? "Restore" : modal.maximize ?? "Maximize",
10802
+ className: "klun-modal__action",
10803
+ children: maximized ? /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 20 20", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 4v4H4M12 16v-4h4M12 4v4h4M8 16v-4H4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) : /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 20 20", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 8V4h4M16 12v4h-4M16 8V4h-4M4 12v4h4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
10804
+ }
10805
+ ) : null,
10806
+ closable ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: cancel, "aria-label": modal.close, className: "klun-modal__action klun-modal__close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 5l10 10M15 5L5 15", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) }) : null
10807
+ ] }) : null
10808
+ ]
10809
+ }
10810
+ ) : null,
10811
+ children ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-modal__body", children }) : null,
10812
+ resolvedFooter ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkTPGAXYFU_cjs.cx("klun-modal__footer", !children && "klun-modal__footer--flush"), children: resolvedFooter }) : null
10813
+ ]
10814
+ }
10815
+ )
10816
+ }
10817
+ );
10818
+ });
10819
+ Modal.displayName = "Modal";
10820
+ var ICON_GROUPS = [
10821
+ {
10822
+ label: "\u5E38\u7528",
10823
+ icons: [
10824
+ "ri-home-4-line",
10825
+ "ri-dashboard-3-line",
10826
+ "ri-settings-3-line",
10827
+ "ri-user-line",
10828
+ "ri-team-line",
10829
+ "ri-file-list-3-line",
10830
+ "ri-calendar-line",
10831
+ "ri-notification-3-line",
10832
+ "ri-search-line",
10833
+ "ri-star-line",
10834
+ "ri-heart-line",
10835
+ "ri-bookmark-line",
10836
+ "ri-link",
10837
+ "ri-share-line",
10838
+ "ri-download-line",
10839
+ "ri-upload-line",
10840
+ "ri-eye-line",
10841
+ "ri-lock-line",
10842
+ "ri-mail-line",
10843
+ "ri-message-2-line"
10844
+ ]
10845
+ },
10846
+ {
10847
+ label: "\u65B9\u5411",
10848
+ icons: [
10849
+ "ri-arrow-up-line",
10850
+ "ri-arrow-down-line",
10851
+ "ri-arrow-left-line",
10852
+ "ri-arrow-right-line",
10853
+ "ri-arrow-up-s-line",
10854
+ "ri-arrow-down-s-line",
10855
+ "ri-arrow-left-s-line",
10856
+ "ri-arrow-right-s-line",
10857
+ "ri-arrow-up-circle-line",
10858
+ "ri-arrow-down-circle-line",
10859
+ "ri-arrow-left-circle-line",
10860
+ "ri-arrow-right-circle-line",
10861
+ "ri-corner-down-right-line",
10862
+ "ri-refresh-line",
10863
+ "ri-loop-left-line",
10864
+ "ri-loop-right-line",
10865
+ "ri-login-circle-line",
10866
+ "ri-logout-circle-line",
10867
+ "ri-menu-line",
10868
+ "ri-more-2-line"
10869
+ ]
10870
+ },
10871
+ {
10872
+ label: "\u7F16\u8F91",
10873
+ icons: [
10874
+ "ri-add-line",
10875
+ "ri-subtract-line",
10876
+ "ri-close-line",
10877
+ "ri-check-line",
10878
+ "ri-edit-line",
10879
+ "ri-delete-bin-line",
10880
+ "ri-file-copy-line",
10881
+ "ri-clipboard-line",
10882
+ "ri-save-line",
10883
+ "ri-magic-line",
10884
+ "ri-filter-line",
10885
+ "ri-drag-move-2-line",
10886
+ "ri-eye-off-line",
10887
+ "ri-eye-2-line",
10888
+ "ri-text",
10889
+ "ri-font-size",
10890
+ "ri-bold",
10891
+ "ri-italic",
10892
+ "ri-underline",
10893
+ "ri-strikethrough"
10894
+ ]
10895
+ },
10896
+ {
10897
+ label: "\u6570\u636E",
10898
+ icons: [
10899
+ "ri-bar-chart-2-line",
10900
+ "ri-line-chart-line",
10901
+ "ri-pie-chart-2-line",
10902
+ "ri-stock-line",
10903
+ "ri-funds-line",
10904
+ "ri-table-line",
10905
+ "ri-list-check",
10906
+ "ri-node-tree",
10907
+ "ri-flow-chart",
10908
+ "ri-percent-line",
10909
+ "ri-calculator-line",
10910
+ "ri-database-2-line",
10911
+ "ri-server-line",
10912
+ "ri-hard-drive-2-line",
10913
+ "ri-cloud-line",
10914
+ "ri-cpu-line",
10915
+ "ri-code-s-slash-line",
10916
+ "ri-terminal-box-line",
10917
+ "ri-history-line",
10918
+ "ri-fingerprint-line"
10919
+ ]
10920
+ },
10921
+ {
10922
+ label: "\u6587\u4EF6",
10923
+ icons: [
10924
+ "ri-file-line",
10925
+ "ri-file-text-line",
10926
+ "ri-folder-line",
10927
+ "ri-folder-open-line",
10928
+ "ri-archive-line",
10929
+ "ri-inbox-line",
10930
+ "ri-image-line",
10931
+ "ri-gallery-line",
10932
+ "ri-video-line",
10933
+ "ri-music-2-line",
10934
+ "ri-movie-line",
10935
+ "ri-camera-line",
10936
+ "ri-file-pdf-line",
10937
+ "ri-file-word-line",
10938
+ "ri-file-excel-line",
10939
+ "ri-file-ppt-line",
10940
+ "ri-printer-line",
10941
+ "ri-attachment-2",
10942
+ "ri-archive-drawer-line",
10943
+ "ri-book-open-line"
10944
+ ]
10945
+ }
10946
+ ];
10947
+ var IconPicker = react.forwardRef(function IconPicker2({
10948
+ value,
10949
+ onChange,
10950
+ groups = ICON_GROUPS,
10951
+ dialogTitle = "\u9009\u62E9\u56FE\u6807",
10952
+ placeholder = "\u641C\u7D22\u56FE\u6807\u540D\u79F0",
10953
+ renderIcon,
10954
+ renderEmpty,
10955
+ width = 520,
10956
+ emptyText = "\u672A\u9009\u62E9\u56FE\u6807",
10957
+ disabled,
10958
+ className,
10959
+ ...props
10960
+ }, ref) {
10961
+ const [open, setOpen] = react.useState(false);
10962
+ const [tab, setTab] = react.useState(groups[0]?.label ?? "");
10963
+ const [keyword, setKeyword] = react.useState("");
10964
+ const icon = renderIcon ?? ((name) => /* @__PURE__ */ jsxRuntime.jsx("i", { className: name }));
10965
+ const empty = renderEmpty ?? (() => /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-add-line" }));
10966
+ const activeTab = groups.some((g) => g.label === tab) ? tab : groups[0]?.label ?? "";
10967
+ const list = react.useMemo(() => {
10968
+ const q = keyword.trim().toLowerCase();
10969
+ if (q) return groups.flatMap((g) => g.icons).filter((name) => name.toLowerCase().includes(q));
10970
+ return groups.find((g) => g.label === activeTab)?.icons ?? [];
10971
+ }, [groups, keyword, activeTab]);
10972
+ const commit = (next) => {
10973
+ onChange?.(next);
10974
+ setOpen(false);
10975
+ };
10976
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-icon-picker", className), ...props, children: [
10977
+ /* @__PURE__ */ jsxRuntime.jsx(
10978
+ "button",
10979
+ {
10980
+ type: "button",
10981
+ className: "klun-icon-picker__trigger",
10982
+ disabled,
10983
+ "aria-haspopup": "dialog",
10984
+ "aria-label": "\u9009\u62E9\u56FE\u6807",
10985
+ title: value,
10986
+ onClick: () => {
10987
+ setKeyword("");
10988
+ setOpen(true);
10989
+ },
10990
+ children: value ? icon(value) : empty()
10991
+ }
10992
+ ),
10993
+ /* @__PURE__ */ jsxRuntime.jsxs(
10994
+ Modal,
10995
+ {
10996
+ open,
10997
+ onClose: () => setOpen(false),
10998
+ title: dialogTitle,
10999
+ width,
11000
+ footer: null,
11001
+ className: "klun-icon-picker__dialog",
11002
+ children: [
11003
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "klun-icon-picker__search", children: [
11004
+ /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-search-line" }),
11005
+ /* @__PURE__ */ jsxRuntime.jsx(
11006
+ "input",
11007
+ {
11008
+ value: keyword,
11009
+ placeholder,
11010
+ "aria-label": placeholder,
11011
+ onChange: (e) => setKeyword(e.target.value)
11012
+ }
11013
+ )
11014
+ ] }),
11015
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-icon-picker__tabs", role: "tablist", children: groups.map((group) => /* @__PURE__ */ jsxRuntime.jsx(
11016
+ "button",
11017
+ {
11018
+ type: "button",
11019
+ role: "tab",
11020
+ "aria-selected": !keyword && activeTab === group.label,
11021
+ className: chunkTPGAXYFU_cjs.cx("klun-icon-picker__tab", !keyword && activeTab === group.label && "is-active"),
11022
+ onClick: () => {
11023
+ setTab(group.label);
11024
+ setKeyword("");
11025
+ },
11026
+ children: group.label
11027
+ },
11028
+ group.label
11029
+ )) }),
11030
+ list.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-icon-picker__grid", children: list.map((name) => /* @__PURE__ */ jsxRuntime.jsx(
11031
+ "button",
11032
+ {
11033
+ type: "button",
11034
+ className: chunkTPGAXYFU_cjs.cx("klun-icon-picker__cell", value === name && "is-selected"),
11035
+ "aria-pressed": value === name,
11036
+ title: name,
11037
+ "aria-label": name,
11038
+ onClick: () => commit(name),
11039
+ children: icon(name)
11040
+ },
11041
+ name
11042
+ )) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-icon-picker__empty", children: "\u6CA1\u6709\u5339\u914D\u7684\u56FE\u6807" }),
11043
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-icon-picker__foot", children: [
11044
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "klun-icon-picker__current", children: [
11045
+ value ? icon(value) : empty(),
11046
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-icon-picker__name", children: value || emptyText })
11047
+ ] }),
11048
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-icon-picker__actions", children: value ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "klun-icon-picker__btn", onClick: () => commit(""), children: "\u6E05\u9664" }) : null })
11049
+ ] })
11050
+ ]
11051
+ }
11052
+ )
11053
+ ] });
11054
+ });
9104
11055
  var ImageUpload = react.forwardRef(function ImageUpload2({
9105
11056
  src,
9106
11057
  shape = "circle",
@@ -9308,7 +11259,77 @@ var InlineSelect = react.forwardRef(
9308
11259
  );
9309
11260
  }
9310
11261
  );
9311
- InlineSelect.displayName = "InlineSelect";
11262
+ InlineSelect.displayName = "InlineSelect";
11263
+ var InputGroup = react.forwardRef(
11264
+ function InputGroup2({ className, ...props }, ref) {
11265
+ return /* @__PURE__ */ jsxRuntime.jsx(
11266
+ "div",
11267
+ {
11268
+ ref,
11269
+ role: "group",
11270
+ className: chunkTPGAXYFU_cjs.cx("klun-input-group", className),
11271
+ ...props
11272
+ }
11273
+ );
11274
+ }
11275
+ );
11276
+ InputGroup.displayName = "InputGroup";
11277
+ var InputGroupInput = react.forwardRef(
11278
+ function InputGroupInput2({ className, ...props }, ref) {
11279
+ return /* @__PURE__ */ jsxRuntime.jsx("input", { ref, className: chunkTPGAXYFU_cjs.cx("klun-input-group__input", className), ...props });
11280
+ }
11281
+ );
11282
+ InputGroupInput.displayName = "InputGroupInput";
11283
+ var InputGroupAddon = react.forwardRef(
11284
+ function InputGroupAddon2({ align = "inline-start", className, onMouseDown, onClick, ...props }, ref) {
11285
+ return /* @__PURE__ */ jsxRuntime.jsx(
11286
+ "div",
11287
+ {
11288
+ ref,
11289
+ role: "group",
11290
+ "data-align": align,
11291
+ className: chunkTPGAXYFU_cjs.cx("klun-input-group__addon", className),
11292
+ onMouseDown: (event) => {
11293
+ if (!event.target.closest("button")) event.preventDefault();
11294
+ onMouseDown?.(event);
11295
+ },
11296
+ onClick: (event) => {
11297
+ if (!event.target.closest("button")) {
11298
+ event.currentTarget.parentElement?.querySelector("input")?.focus();
11299
+ }
11300
+ onClick?.(event);
11301
+ },
11302
+ ...props
11303
+ }
11304
+ );
11305
+ }
11306
+ );
11307
+ InputGroupAddon.displayName = "InputGroupAddon";
11308
+ var InputGroupText = react.forwardRef(
11309
+ function InputGroupText2({ className, ...props }, ref) {
11310
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { ref, className: chunkTPGAXYFU_cjs.cx("klun-input-group__text", className), ...props });
11311
+ }
11312
+ );
11313
+ InputGroupText.displayName = "InputGroupText";
11314
+ var InputGroupButton = react.forwardRef(
11315
+ function InputGroupButton2({ size = "xsmall", variant = "ghost", type = "button", className, ...props }, ref) {
11316
+ return /* @__PURE__ */ jsxRuntime.jsx(
11317
+ "button",
11318
+ {
11319
+ ref,
11320
+ type,
11321
+ className: chunkTPGAXYFU_cjs.cx(
11322
+ "klun-input-group__button",
11323
+ `klun-input-group__button--${size}`,
11324
+ `klun-input-group__button--${variant}`,
11325
+ className
11326
+ ),
11327
+ ...props
11328
+ }
11329
+ );
11330
+ }
11331
+ );
11332
+ InputGroupButton.displayName = "InputGroupButton";
9312
11333
  var Label = react.forwardRef(function Label2({ children, required = false, sublabel, disabled = false, className, ...props }, ref) {
9313
11334
  return /* @__PURE__ */ jsxRuntime.jsxs(
9314
11335
  "label",
@@ -9775,11 +11796,15 @@ var Select = react.forwardRef(function Select2({
9775
11796
  value,
9776
11797
  defaultValue,
9777
11798
  onChange,
11799
+ "aria-label": ariaLabel,
11800
+ "aria-labelledby": ariaLabelledBy,
9778
11801
  ...props
9779
11802
  }, ref) {
9780
11803
  const size = useSize(sizeProp);
9781
11804
  const rootRef = react.useRef(null);
9782
11805
  const s = useSelect({ children, value, defaultValue, disabled: disabled || loading, rootRef });
11806
+ const { select: selectLocale } = useLocale();
11807
+ const fallbackLabel = !ariaLabel && !ariaLabelledBy && !s.selected && !placeholder ? selectLocale?.placeholder ?? "Select" : void 0;
9783
11808
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: chunkTPGAXYFU_cjs.cx("klun-select", `klun-select--${size}`, className), style, children: [
9784
11809
  /* @__PURE__ */ jsxRuntime.jsxs(
9785
11810
  "button",
@@ -9791,6 +11816,8 @@ var Select = react.forwardRef(function Select2({
9791
11816
  onKeyDown: s.triggerKeyDown,
9792
11817
  "aria-haspopup": "listbox",
9793
11818
  "aria-expanded": s.open,
11819
+ "aria-label": ariaLabel ?? fallbackLabel,
11820
+ "aria-labelledby": ariaLabelledBy,
9794
11821
  "data-open": s.open || void 0,
9795
11822
  className: chunkTPGAXYFU_cjs.cx(
9796
11823
  "klun-select__trigger",
@@ -11122,40 +13149,537 @@ var SegmentedControl = react.forwardRef(
11122
13149
  }) });
11123
13150
  }
11124
13151
  );
11125
- SegmentedControl.displayName = "SegmentedControl";
11126
- var StepIndicator = react.forwardRef(function StepIndicator2({ steps = [], current = 0, className, ...props }, ref) {
11127
- return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-step-indicator", className), ...props, children: steps.map((s, i) => {
11128
- const done = i < current;
11129
- const active = i === current;
11130
- const state = done ? "complete" : active ? "active" : "upcoming";
11131
- return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
11132
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-step-indicator__step", "data-state": state, children: [
11133
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-step-indicator__marker", children: done ? /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(
11134
- "path",
11135
- {
11136
- d: "M3.5 8.5l3 3 6-6.5",
11137
- stroke: "currentColor",
11138
- strokeWidth: "2",
11139
- strokeLinecap: "round",
11140
- strokeLinejoin: "round"
11141
- }
11142
- ) }) : i + 1 }),
11143
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-step-indicator__text", children: [
11144
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-step-indicator__label", children: s.label }),
11145
- s.description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-step-indicator__description", children: s.description }) : null
11146
- ] })
11147
- ] }),
11148
- i < steps.length - 1 ? /* @__PURE__ */ jsxRuntime.jsx(
11149
- "div",
11150
- {
11151
- className: "klun-step-indicator__connector",
11152
- "data-state": i < current ? "complete" : "upcoming"
11153
- }
11154
- ) : null
11155
- ] }, i);
11156
- }) });
11157
- });
11158
- StepIndicator.displayName = "StepIndicator";
13152
+ SegmentedControl.displayName = "SegmentedControl";
13153
+ function RailButton({
13154
+ item,
13155
+ active,
13156
+ onClick
13157
+ }) {
13158
+ return /* @__PURE__ */ jsxRuntime.jsx(
13159
+ "button",
13160
+ {
13161
+ type: "button",
13162
+ className: "klun-sidebar__nav-button",
13163
+ "data-active": active ? "" : void 0,
13164
+ disabled: item.disabled,
13165
+ "aria-current": active ? "page" : void 0,
13166
+ "aria-label": item.label,
13167
+ title: item.label,
13168
+ onClick,
13169
+ children: item.icon
13170
+ }
13171
+ );
13172
+ }
13173
+ function MenuItemRow({
13174
+ item,
13175
+ expanded,
13176
+ collapsed,
13177
+ active,
13178
+ onToggle,
13179
+ onSelect
13180
+ }) {
13181
+ const isExpander = Array.isArray(item.children) && item.children.length > 0;
13182
+ const title = collapsed && typeof item.label === "string" ? item.label : void 0;
13183
+ return /* @__PURE__ */ jsxRuntime.jsxs(
13184
+ "button",
13185
+ {
13186
+ type: "button",
13187
+ className: "klun-sidebar__item",
13188
+ "data-active": active ? "" : void 0,
13189
+ disabled: item.disabled,
13190
+ "aria-expanded": isExpander ? expanded : void 0,
13191
+ "aria-current": !isExpander && active ? "page" : void 0,
13192
+ title,
13193
+ onClick: () => {
13194
+ if (isExpander) onToggle();
13195
+ else onSelect?.(item.key, item);
13196
+ },
13197
+ children: [
13198
+ item.icon != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-sidebar__item-icon", children: item.icon }),
13199
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-sidebar__item-label", children: item.label }),
13200
+ isExpander && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-sidebar__item-caret", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-arrow-down-s-line" }) })
13201
+ ]
13202
+ }
13203
+ );
13204
+ }
13205
+ function SubMenuItemRow({
13206
+ item,
13207
+ onSelect
13208
+ }) {
13209
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-sidebar__sub-item", children: /* @__PURE__ */ jsxRuntime.jsx(
13210
+ "button",
13211
+ {
13212
+ type: "button",
13213
+ className: "klun-sidebar__sub-button",
13214
+ disabled: item.disabled,
13215
+ onClick: () => onSelect?.(item.key, item),
13216
+ children: item.label
13217
+ }
13218
+ ) });
13219
+ }
13220
+ var Sidebar = react.forwardRef(function Sidebar2({
13221
+ brand,
13222
+ navItems = [],
13223
+ footNavItems = [],
13224
+ avatar,
13225
+ navKey,
13226
+ defaultNavKey,
13227
+ onNavChange,
13228
+ title,
13229
+ sections = [],
13230
+ selectedKey,
13231
+ onSelect,
13232
+ defaultExpandedKeys = [],
13233
+ searchable = false,
13234
+ searchPlaceholder = "Search",
13235
+ onSearch,
13236
+ collapsed: collapsedProp,
13237
+ defaultCollapsed = false,
13238
+ onCollapse,
13239
+ className,
13240
+ ...props
13241
+ }, ref) {
13242
+ const [internalNav, setInternalNav] = react.useState(defaultNavKey);
13243
+ const [internalCollapsed, setInternalCollapsed] = react.useState(defaultCollapsed);
13244
+ const [expandedKeys, setExpandedKeys] = react.useState(
13245
+ () => new Set(defaultExpandedKeys)
13246
+ );
13247
+ const [query, setQuery] = react.useState("");
13248
+ const navControlled = navKey !== void 0;
13249
+ const activeNav = navControlled ? navKey : internalNav;
13250
+ const collapseControlled = collapsedProp !== void 0;
13251
+ const collapsed = collapseControlled ? collapsedProp : internalCollapsed;
13252
+ const selectNav = (key) => {
13253
+ if (!navControlled) setInternalNav(key);
13254
+ onNavChange?.(key);
13255
+ };
13256
+ const toggleCollapse = () => {
13257
+ const next = !collapsed;
13258
+ if (!collapseControlled) setInternalCollapsed(next);
13259
+ onCollapse?.(next);
13260
+ };
13261
+ const toggleExpanded = (key) => {
13262
+ setExpandedKeys((prev) => {
13263
+ const next = new Set(prev);
13264
+ if (next.has(key)) next.delete(key);
13265
+ else next.add(key);
13266
+ return next;
13267
+ });
13268
+ };
13269
+ return /* @__PURE__ */ jsxRuntime.jsxs(
13270
+ "div",
13271
+ {
13272
+ ref,
13273
+ className: chunkTPGAXYFU_cjs.cx("klun-sidebar", collapsed && "klun-sidebar--collapsed", className),
13274
+ "data-collapsed": collapsed ? "" : void 0,
13275
+ ...props,
13276
+ children: [
13277
+ /* @__PURE__ */ jsxRuntime.jsxs("nav", { className: "klun-sidebar__rail", "aria-label": "Primary", children: [
13278
+ brand != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-sidebar__brand", children: brand }),
13279
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-sidebar__nav", children: navItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
13280
+ RailButton,
13281
+ {
13282
+ item,
13283
+ active: item.key === activeNav,
13284
+ onClick: () => selectNav(item.key)
13285
+ },
13286
+ item.key
13287
+ )) }),
13288
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-sidebar__rail-foot", children: [
13289
+ footNavItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
13290
+ RailButton,
13291
+ {
13292
+ item,
13293
+ active: item.key === activeNav,
13294
+ onClick: () => selectNav(item.key)
13295
+ },
13296
+ item.key
13297
+ )),
13298
+ avatar != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-sidebar__avatar", children: avatar })
13299
+ ] })
13300
+ ] }),
13301
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-sidebar__panel", children: [
13302
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-sidebar__panel-head", children: [
13303
+ !collapsed && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-sidebar__panel-title", children: title }),
13304
+ /* @__PURE__ */ jsxRuntime.jsx(
13305
+ "button",
13306
+ {
13307
+ type: "button",
13308
+ className: "klun-sidebar__collapse",
13309
+ "aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
13310
+ "aria-expanded": !collapsed,
13311
+ onClick: toggleCollapse,
13312
+ children: /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-arrow-left-s-line", "aria-hidden": "true" })
13313
+ }
13314
+ )
13315
+ ] }),
13316
+ searchable && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-sidebar__search", children: [
13317
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-sidebar__search-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-search-line" }) }),
13318
+ /* @__PURE__ */ jsxRuntime.jsx(
13319
+ "input",
13320
+ {
13321
+ type: "text",
13322
+ className: "klun-sidebar__search-input",
13323
+ placeholder: searchPlaceholder,
13324
+ value: query,
13325
+ tabIndex: collapsed ? -1 : 0,
13326
+ onChange: (e) => {
13327
+ setQuery(e.target.value);
13328
+ onSearch?.(e.target.value);
13329
+ }
13330
+ }
13331
+ )
13332
+ ] }),
13333
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-sidebar__scroll", children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-sidebar__section", children: [
13334
+ section.title != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-sidebar__section-title", children: section.title }),
13335
+ section.items.map((item) => {
13336
+ const isExpander = Array.isArray(item.children) && item.children.length > 0;
13337
+ const expanded = expandedKeys.has(item.key);
13338
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-sidebar__group", children: [
13339
+ /* @__PURE__ */ jsxRuntime.jsx(
13340
+ MenuItemRow,
13341
+ {
13342
+ item,
13343
+ expanded,
13344
+ collapsed,
13345
+ active: item.key === selectedKey,
13346
+ onToggle: () => toggleExpanded(item.key),
13347
+ onSelect
13348
+ }
13349
+ ),
13350
+ isExpander && expanded && !collapsed && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-sidebar__sub", children: item.children.map((child) => /* @__PURE__ */ jsxRuntime.jsx(SubMenuItemRow, { item: child, onSelect }, child.key)) })
13351
+ ] }, item.key);
13352
+ })
13353
+ ] }, sectionIndex)) })
13354
+ ] })
13355
+ ]
13356
+ }
13357
+ );
13358
+ });
13359
+ Sidebar.displayName = "Sidebar";
13360
+ var StepIndicator = react.forwardRef(function StepIndicator2({ steps = [], current = 0, className, ...props }, ref) {
13361
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-step-indicator", className), ...props, children: steps.map((s, i) => {
13362
+ const done = i < current;
13363
+ const active = i === current;
13364
+ const state = done ? "complete" : active ? "active" : "upcoming";
13365
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
13366
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-step-indicator__step", "data-state": state, children: [
13367
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-step-indicator__marker", children: done ? /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(
13368
+ "path",
13369
+ {
13370
+ d: "M3.5 8.5l3 3 6-6.5",
13371
+ stroke: "currentColor",
13372
+ strokeWidth: "2",
13373
+ strokeLinecap: "round",
13374
+ strokeLinejoin: "round"
13375
+ }
13376
+ ) }) : i + 1 }),
13377
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-step-indicator__text", children: [
13378
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-step-indicator__label", children: s.label }),
13379
+ s.description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-step-indicator__description", children: s.description }) : null
13380
+ ] })
13381
+ ] }),
13382
+ i < steps.length - 1 ? /* @__PURE__ */ jsxRuntime.jsx(
13383
+ "div",
13384
+ {
13385
+ className: "klun-step-indicator__connector",
13386
+ "data-state": i < current ? "complete" : "upcoming"
13387
+ }
13388
+ ) : null
13389
+ ] }, i);
13390
+ }) });
13391
+ });
13392
+ StepIndicator.displayName = "StepIndicator";
13393
+ var StepperContext = react.createContext(void 0);
13394
+ var StepItemContext = react.createContext(void 0);
13395
+ function useStepper() {
13396
+ const ctx = react.useContext(StepperContext);
13397
+ if (!ctx) throw new Error("useStepper must be used within a <Stepper>");
13398
+ return ctx;
13399
+ }
13400
+ function useStepItem() {
13401
+ const ctx = react.useContext(StepItemContext);
13402
+ if (!ctx) throw new Error("useStepItem must be used within a <StepperItem>");
13403
+ return ctx;
13404
+ }
13405
+ var Stepper = react.forwardRef(function Stepper2({
13406
+ defaultValue = 1,
13407
+ value,
13408
+ onValueChange,
13409
+ orientation = "horizontal",
13410
+ className,
13411
+ children,
13412
+ indicators = {},
13413
+ ...props
13414
+ }, ref) {
13415
+ const [internalStep, setInternalStep] = react.useState(defaultValue);
13416
+ const [triggerNodes, setTriggerNodes] = react.useState([]);
13417
+ const registerTrigger = react.useCallback((node) => {
13418
+ setTriggerNodes((prev) => prev.includes(node) ? prev : [...prev, node]);
13419
+ }, []);
13420
+ const unregisterTrigger = react.useCallback((node) => {
13421
+ setTriggerNodes((prev) => prev.filter((n) => n !== node));
13422
+ }, []);
13423
+ const activeStep = value ?? internalStep;
13424
+ const setActiveStep = react.useCallback(
13425
+ (step) => {
13426
+ if (value === void 0) setInternalStep(step);
13427
+ onValueChange?.(step);
13428
+ },
13429
+ [value, onValueChange]
13430
+ );
13431
+ const focusTrigger = (index) => {
13432
+ triggerNodes[index]?.focus();
13433
+ };
13434
+ const focusNext = (currentIndex) => focusTrigger((currentIndex + 1) % triggerNodes.length);
13435
+ const focusPrev = (currentIndex) => focusTrigger((currentIndex - 1 + triggerNodes.length) % triggerNodes.length);
13436
+ const contextValue = react.useMemo(
13437
+ () => ({
13438
+ activeStep,
13439
+ setActiveStep,
13440
+ orientation,
13441
+ registerTrigger,
13442
+ unregisterTrigger,
13443
+ triggerNodes,
13444
+ focusNext,
13445
+ focusPrev,
13446
+ focusFirst: () => focusTrigger(0),
13447
+ focusLast: () => focusTrigger(triggerNodes.length - 1),
13448
+ indicators
13449
+ }),
13450
+ // eslint-disable-next-line react-hooks/exhaustive-deps
13451
+ [activeStep, setActiveStep, orientation, registerTrigger, unregisterTrigger, triggerNodes, indicators]
13452
+ );
13453
+ return /* @__PURE__ */ jsxRuntime.jsx(StepperContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
13454
+ "div",
13455
+ {
13456
+ ref,
13457
+ role: "tablist",
13458
+ "aria-orientation": orientation,
13459
+ "data-orientation": orientation,
13460
+ className: chunkTPGAXYFU_cjs.cx("klun-stepper", className),
13461
+ ...props,
13462
+ children
13463
+ }
13464
+ ) });
13465
+ });
13466
+ Stepper.displayName = "Stepper";
13467
+ var StepperNav = react.forwardRef(
13468
+ function StepperNav2({ className, ...props }, ref) {
13469
+ const { orientation, activeStep } = useStepper();
13470
+ return /* @__PURE__ */ jsxRuntime.jsx(
13471
+ "nav",
13472
+ {
13473
+ ref,
13474
+ "data-orientation": orientation,
13475
+ "data-state": activeStep,
13476
+ className: chunkTPGAXYFU_cjs.cx("klun-stepper__nav", className),
13477
+ ...props
13478
+ }
13479
+ );
13480
+ }
13481
+ );
13482
+ StepperNav.displayName = "StepperNav";
13483
+ var StepperItem = react.forwardRef(
13484
+ function StepperItem2({ step, completed = false, disabled = false, loading = false, className, children, ...props }, ref) {
13485
+ const { activeStep } = useStepper();
13486
+ const state = completed || step < activeStep ? "completed" : activeStep === step ? "active" : "inactive";
13487
+ const isLoading = loading && step === activeStep;
13488
+ return /* @__PURE__ */ jsxRuntime.jsx(StepItemContext.Provider, { value: { step, state, isDisabled: disabled, isLoading }, children: /* @__PURE__ */ jsxRuntime.jsx(
13489
+ "div",
13490
+ {
13491
+ ref,
13492
+ "data-state": state,
13493
+ "data-loading": isLoading ? "" : void 0,
13494
+ className: chunkTPGAXYFU_cjs.cx("klun-stepper__item", className),
13495
+ ...props,
13496
+ children
13497
+ }
13498
+ ) });
13499
+ }
13500
+ );
13501
+ StepperItem.displayName = "StepperItem";
13502
+ var StepperTrigger = react.forwardRef(
13503
+ function StepperTrigger2({ className, children, tabIndex, onKeyDown, ...props }, ref) {
13504
+ const { step, state, isDisabled, isLoading } = useStepItem();
13505
+ const {
13506
+ activeStep,
13507
+ setActiveStep,
13508
+ registerTrigger,
13509
+ unregisterTrigger,
13510
+ triggerNodes,
13511
+ focusNext,
13512
+ focusPrev,
13513
+ focusFirst,
13514
+ focusLast
13515
+ } = useStepper();
13516
+ const buttonRef = react.useRef(null);
13517
+ react.useEffect(() => {
13518
+ const node = buttonRef.current;
13519
+ if (!node) return;
13520
+ registerTrigger(node);
13521
+ return () => unregisterTrigger(node);
13522
+ }, [registerTrigger, unregisterTrigger]);
13523
+ const isSelected = activeStep === step;
13524
+ return /* @__PURE__ */ jsxRuntime.jsx(
13525
+ "button",
13526
+ {
13527
+ ref: (node) => {
13528
+ buttonRef.current = node;
13529
+ if (typeof ref === "function") ref(node);
13530
+ else if (ref) ref.current = node;
13531
+ },
13532
+ type: "button",
13533
+ role: "tab",
13534
+ id: `stepper-tab-${step}`,
13535
+ "aria-selected": isSelected,
13536
+ "aria-controls": `stepper-panel-${step}`,
13537
+ tabIndex: typeof tabIndex === "number" ? tabIndex : isSelected ? 0 : -1,
13538
+ "data-state": state,
13539
+ "data-loading": isLoading ? "" : void 0,
13540
+ disabled: isDisabled,
13541
+ className: chunkTPGAXYFU_cjs.cx("klun-stepper__trigger", className),
13542
+ onClick: () => setActiveStep(step),
13543
+ onKeyDown: (event) => {
13544
+ switch (event.key) {
13545
+ case "ArrowRight":
13546
+ case "ArrowDown": {
13547
+ event.preventDefault();
13548
+ const index = triggerNodes.findIndex((n) => n === buttonRef.current);
13549
+ if (index !== -1) focusNext(index);
13550
+ break;
13551
+ }
13552
+ case "ArrowLeft":
13553
+ case "ArrowUp": {
13554
+ event.preventDefault();
13555
+ const index = triggerNodes.findIndex((n) => n === buttonRef.current);
13556
+ if (index !== -1) focusPrev(index);
13557
+ break;
13558
+ }
13559
+ case "Home":
13560
+ event.preventDefault();
13561
+ focusFirst();
13562
+ break;
13563
+ case "End":
13564
+ event.preventDefault();
13565
+ focusLast();
13566
+ break;
13567
+ case "Enter":
13568
+ case " ":
13569
+ event.preventDefault();
13570
+ setActiveStep(step);
13571
+ break;
13572
+ }
13573
+ onKeyDown?.(event);
13574
+ },
13575
+ ...props,
13576
+ children
13577
+ }
13578
+ );
13579
+ }
13580
+ );
13581
+ StepperTrigger.displayName = "StepperTrigger";
13582
+ var StepperIndicator = react.forwardRef(
13583
+ function StepperIndicator2({ className, children, ...props }, ref) {
13584
+ const { state, isLoading } = useStepItem();
13585
+ const { indicators } = useStepper();
13586
+ const custom = isLoading && indicators.loading || state === "completed" && indicators.completed || state === "active" && indicators.active || state === "inactive" && indicators.inactive;
13587
+ return /* @__PURE__ */ jsxRuntime.jsx(
13588
+ "div",
13589
+ {
13590
+ ref,
13591
+ "data-state": state,
13592
+ "data-loading": isLoading ? "" : void 0,
13593
+ className: chunkTPGAXYFU_cjs.cx("klun-stepper__indicator", className),
13594
+ ...props,
13595
+ children: custom ?? children
13596
+ }
13597
+ );
13598
+ }
13599
+ );
13600
+ StepperIndicator.displayName = "StepperIndicator";
13601
+ var StepperSeparator = react.forwardRef(
13602
+ function StepperSeparator2({ className, ...props }, ref) {
13603
+ const { state } = useStepItem();
13604
+ return /* @__PURE__ */ jsxRuntime.jsx(
13605
+ "div",
13606
+ {
13607
+ ref,
13608
+ "aria-hidden": "true",
13609
+ "data-state": state,
13610
+ className: chunkTPGAXYFU_cjs.cx("klun-stepper__separator", className),
13611
+ ...props
13612
+ }
13613
+ );
13614
+ }
13615
+ );
13616
+ StepperSeparator.displayName = "StepperSeparator";
13617
+ var StepperTitle = react.forwardRef(
13618
+ function StepperTitle2({ className, ...props }, ref) {
13619
+ const { state } = useStepItem();
13620
+ return /* @__PURE__ */ jsxRuntime.jsx(
13621
+ "h3",
13622
+ {
13623
+ ref,
13624
+ "data-state": state,
13625
+ className: chunkTPGAXYFU_cjs.cx("klun-stepper__title", className),
13626
+ ...props
13627
+ }
13628
+ );
13629
+ }
13630
+ );
13631
+ StepperTitle.displayName = "StepperTitle";
13632
+ var StepperDescription = react.forwardRef(
13633
+ function StepperDescription2({ className, ...props }, ref) {
13634
+ const { state } = useStepItem();
13635
+ return /* @__PURE__ */ jsxRuntime.jsx(
13636
+ "div",
13637
+ {
13638
+ ref,
13639
+ "data-state": state,
13640
+ className: chunkTPGAXYFU_cjs.cx("klun-stepper__description", className),
13641
+ ...props
13642
+ }
13643
+ );
13644
+ }
13645
+ );
13646
+ StepperDescription.displayName = "StepperDescription";
13647
+ var StepperPanel = react.forwardRef(
13648
+ function StepperPanel2({ className, ...props }, ref) {
13649
+ const { activeStep } = useStepper();
13650
+ return /* @__PURE__ */ jsxRuntime.jsx(
13651
+ "div",
13652
+ {
13653
+ ref,
13654
+ "data-state": activeStep,
13655
+ className: chunkTPGAXYFU_cjs.cx("klun-stepper__panel", className),
13656
+ ...props
13657
+ }
13658
+ );
13659
+ }
13660
+ );
13661
+ StepperPanel.displayName = "StepperPanel";
13662
+ var StepperContent = react.forwardRef(
13663
+ function StepperContent2({ value, forceMount = false, className, children, ...props }, ref) {
13664
+ const { activeStep } = useStepper();
13665
+ const isActive = value === activeStep;
13666
+ if (!forceMount && !isActive) return null;
13667
+ return /* @__PURE__ */ jsxRuntime.jsx(
13668
+ "div",
13669
+ {
13670
+ ref,
13671
+ id: `stepper-panel-${value}`,
13672
+ role: "tabpanel",
13673
+ "aria-labelledby": `stepper-tab-${value}`,
13674
+ hidden: forceMount && !isActive,
13675
+ className: chunkTPGAXYFU_cjs.cx("klun-stepper__content", className),
13676
+ ...props,
13677
+ children
13678
+ }
13679
+ );
13680
+ }
13681
+ );
13682
+ StepperContent.displayName = "StepperContent";
11159
13683
  var Wizard = react.forwardRef(function Wizard2({
11160
13684
  steps = [],
11161
13685
  current,
@@ -11781,6 +14305,208 @@ var Dropdown = react.forwardRef(function Dropdown2({ trigger, items: items2 = []
11781
14305
  ] });
11782
14306
  });
11783
14307
  Dropdown.displayName = "Dropdown";
14308
+ var GAP4 = 6;
14309
+ var MARGIN2 = 8;
14310
+ var HoverCardContext = react.createContext(null);
14311
+ function useHoverCard() {
14312
+ const ctx = react.useContext(HoverCardContext);
14313
+ if (!ctx) throw new Error("HoverCard parts must be used inside <HoverCard>");
14314
+ return ctx;
14315
+ }
14316
+ function HoverCard({
14317
+ children,
14318
+ openDelay = 300,
14319
+ closeDelay = 150,
14320
+ open: openProp,
14321
+ onOpenChange
14322
+ }) {
14323
+ const [internalOpen, setInternalOpen] = react.useState(false);
14324
+ const controlled = openProp !== void 0;
14325
+ const open = controlled ? openProp : internalOpen;
14326
+ const triggerRef = react.useRef(null);
14327
+ const openTimer = react.useRef(null);
14328
+ const closeTimer = react.useRef(null);
14329
+ const clearTimers = () => {
14330
+ if (openTimer.current) clearTimeout(openTimer.current);
14331
+ if (closeTimer.current) clearTimeout(closeTimer.current);
14332
+ };
14333
+ const setOpen = (next) => {
14334
+ if (!controlled) setInternalOpen(next);
14335
+ onOpenChange?.(next);
14336
+ };
14337
+ const show = () => {
14338
+ clearTimers();
14339
+ if (open) return;
14340
+ openTimer.current = setTimeout(() => setOpen(true), openDelay);
14341
+ };
14342
+ const hide = () => {
14343
+ clearTimers();
14344
+ closeTimer.current = setTimeout(() => setOpen(false), closeDelay);
14345
+ };
14346
+ const cancelHide = () => {
14347
+ clearTimers();
14348
+ };
14349
+ react.useEffect(() => clearTimers, []);
14350
+ react.useEffect(() => {
14351
+ if (!open) return;
14352
+ const onKey = (event) => {
14353
+ if (event.key === "Escape") setOpen(false);
14354
+ };
14355
+ document.addEventListener("keydown", onKey);
14356
+ return () => document.removeEventListener("keydown", onKey);
14357
+ }, [open]);
14358
+ return /* @__PURE__ */ jsxRuntime.jsx(
14359
+ HoverCardContext.Provider,
14360
+ {
14361
+ value: {
14362
+ open,
14363
+ show,
14364
+ hide,
14365
+ cancelHide,
14366
+ triggerRef,
14367
+ registerTrigger: (el) => {
14368
+ triggerRef.current = el;
14369
+ }
14370
+ },
14371
+ children
14372
+ }
14373
+ );
14374
+ }
14375
+ var HoverCardTrigger = react.forwardRef(
14376
+ function HoverCardTrigger2({ className, onMouseEnter, onMouseLeave, onFocus, onBlur, ...props }, ref) {
14377
+ const ctx = useHoverCard();
14378
+ return /* @__PURE__ */ jsxRuntime.jsx(
14379
+ "span",
14380
+ {
14381
+ ref: (node) => {
14382
+ ctx.registerTrigger(node);
14383
+ if (typeof ref === "function") ref(node);
14384
+ else if (ref) ref.current = node;
14385
+ },
14386
+ className: chunkTPGAXYFU_cjs.cx("klun-hover-card__trigger", className),
14387
+ onMouseEnter: (event) => {
14388
+ ctx.show();
14389
+ onMouseEnter?.(event);
14390
+ },
14391
+ onMouseLeave: (event) => {
14392
+ ctx.hide();
14393
+ onMouseLeave?.(event);
14394
+ },
14395
+ onFocus: (event) => {
14396
+ ctx.show();
14397
+ onFocus?.(event);
14398
+ },
14399
+ onBlur: (event) => {
14400
+ ctx.hide();
14401
+ onBlur?.(event);
14402
+ },
14403
+ ...props
14404
+ }
14405
+ );
14406
+ }
14407
+ );
14408
+ HoverCardTrigger.displayName = "HoverCardTrigger";
14409
+ function alignAxis(start, size, panelSize, align) {
14410
+ if (align === "start") return start;
14411
+ if (align === "end") return start + size - panelSize;
14412
+ return start + size / 2 - panelSize / 2;
14413
+ }
14414
+ var HoverCardContent = react.forwardRef(
14415
+ function HoverCardContent2({
14416
+ side = "bottom",
14417
+ align = "center",
14418
+ className,
14419
+ onClick,
14420
+ onContextMenu,
14421
+ onAuxClick,
14422
+ onDoubleClick,
14423
+ ...props
14424
+ }, ref) {
14425
+ const ctx = useHoverCard();
14426
+ const panelRef = react.useRef(null);
14427
+ const [pos, setPos] = react.useState(null);
14428
+ react.useLayoutEffect(() => {
14429
+ if (!ctx.open) {
14430
+ setPos(null);
14431
+ return;
14432
+ }
14433
+ const place2 = () => {
14434
+ const trigger = ctx.triggerRef.current;
14435
+ const panel = panelRef.current;
14436
+ if (!trigger || !panel) return;
14437
+ const tr = trigger.getBoundingClientRect();
14438
+ const pw = panel.offsetWidth;
14439
+ const ph = panel.offsetHeight;
14440
+ const vw = document.documentElement.clientWidth;
14441
+ const vh = document.documentElement.clientHeight;
14442
+ let top;
14443
+ let left;
14444
+ switch (side) {
14445
+ case "top":
14446
+ top = tr.top - ph - GAP4;
14447
+ left = alignAxis(tr.left, tr.width, pw, align);
14448
+ break;
14449
+ case "left":
14450
+ left = tr.left - pw - GAP4;
14451
+ top = alignAxis(tr.top, tr.height, ph, align);
14452
+ break;
14453
+ case "right":
14454
+ left = tr.right + GAP4;
14455
+ top = alignAxis(tr.top, tr.height, ph, align);
14456
+ break;
14457
+ default:
14458
+ top = tr.bottom + GAP4;
14459
+ left = alignAxis(tr.left, tr.width, pw, align);
14460
+ }
14461
+ left = Math.max(MARGIN2, Math.min(left, vw - pw - MARGIN2));
14462
+ top = Math.max(MARGIN2, Math.min(top, vh - ph - MARGIN2));
14463
+ setPos({ top, left });
14464
+ };
14465
+ place2();
14466
+ window.addEventListener("scroll", place2, true);
14467
+ window.addEventListener("resize", place2);
14468
+ return () => {
14469
+ window.removeEventListener("scroll", place2, true);
14470
+ window.removeEventListener("resize", place2);
14471
+ };
14472
+ }, [ctx.open, side, align, ctx.triggerRef]);
14473
+ if (!ctx.open || typeof document === "undefined") return null;
14474
+ const stop = (forwarded) => (event) => {
14475
+ event.stopPropagation();
14476
+ forwarded?.(event);
14477
+ };
14478
+ const style = {
14479
+ position: "fixed",
14480
+ top: pos?.top ?? 0,
14481
+ left: pos?.left ?? 0,
14482
+ visibility: pos ? "visible" : "hidden"
14483
+ };
14484
+ return reactDom.createPortal(
14485
+ /* @__PURE__ */ jsxRuntime.jsx(
14486
+ "div",
14487
+ {
14488
+ ref: (node) => {
14489
+ panelRef.current = node;
14490
+ if (typeof ref === "function") ref(node);
14491
+ else if (ref) ref.current = node;
14492
+ },
14493
+ className: chunkTPGAXYFU_cjs.cx("klun-hover-card__panel", className),
14494
+ "data-side": side,
14495
+ style,
14496
+ onMouseEnter: ctx.cancelHide,
14497
+ onMouseLeave: ctx.hide,
14498
+ onClick: stop(onClick),
14499
+ onContextMenu: stop(onContextMenu),
14500
+ onAuxClick: stop(onAuxClick),
14501
+ onDoubleClick: stop(onDoubleClick),
14502
+ ...props
14503
+ }
14504
+ ),
14505
+ document.body
14506
+ );
14507
+ }
14508
+ );
14509
+ HoverCardContent.displayName = "HoverCardContent";
11784
14510
  var MIN = 0.25;
11785
14511
  var MAX = 6;
11786
14512
  var clampScale = (s) => Math.min(MAX, Math.max(MIN, +s.toFixed(2)));
@@ -11921,155 +14647,8 @@ function ImageViewer({
11921
14647
  );
11922
14648
  }
11923
14649
  ImageViewer.displayName = "ImageViewer";
11924
- var Modal = react.forwardRef(function Modal2({
11925
- open,
11926
- onClose,
11927
- onOk,
11928
- onCancel,
11929
- title,
11930
- description,
11931
- icon,
11932
- footer,
11933
- okText,
11934
- cancelText,
11935
- confirmLoading = false,
11936
- okType = "primary",
11937
- okButtonProps,
11938
- cancelButtonProps,
11939
- width = 520,
11940
- centered = false,
11941
- closable = true,
11942
- maskClosable,
11943
- closeOnBackdrop,
11944
- keyboard = true,
11945
- mask = true,
11946
- draggable = false,
11947
- maximizable = false,
11948
- defaultMaximized = false,
11949
- zIndex,
11950
- afterClose,
11951
- afterOpenChange,
11952
- children,
11953
- className,
11954
- style,
11955
- ...props
11956
- }, ref) {
11957
- const { modal } = useLocale();
11958
- const cancel = onCancel ?? onClose;
11959
- const backdropClosable = maskClosable ?? closeOnBackdrop ?? true;
11960
- const [pos, setPos] = react.useState({ x: 0, y: 0 });
11961
- const [maximized, setMaximized] = react.useState(defaultMaximized);
11962
- const drag = react.useRef(null);
11963
- const prevOpen = react.useRef(open);
11964
- react.useEffect(() => {
11965
- if (!open) return;
11966
- const onKey = (e) => {
11967
- if (e.key === "Escape" && keyboard && closable) cancel?.();
11968
- };
11969
- document.addEventListener("keydown", onKey);
11970
- const prevOverflow = document.body.style.overflow;
11971
- document.body.style.overflow = "hidden";
11972
- return () => {
11973
- document.removeEventListener("keydown", onKey);
11974
- document.body.style.overflow = prevOverflow;
11975
- };
11976
- }, [open, keyboard, closable, cancel]);
11977
- react.useEffect(() => {
11978
- if (open) {
11979
- setPos({ x: 0, y: 0 });
11980
- setMaximized(defaultMaximized);
11981
- }
11982
- if (prevOpen.current !== open) {
11983
- afterOpenChange?.(open);
11984
- if (!open) afterClose?.();
11985
- prevOpen.current = open;
11986
- }
11987
- }, [open]);
11988
- if (!open) return null;
11989
- const startDrag = (e) => {
11990
- if (!draggable || maximized) return;
11991
- if (e.target.closest(".klun-modal__actions")) return;
11992
- drag.current = { sx: e.clientX, sy: e.clientY, ox: pos.x, oy: pos.y };
11993
- const move = (ev) => {
11994
- if (!drag.current) return;
11995
- setPos({
11996
- x: drag.current.ox + (ev.clientX - drag.current.sx),
11997
- y: drag.current.oy + (ev.clientY - drag.current.sy)
11998
- });
11999
- };
12000
- const up = () => {
12001
- drag.current = null;
12002
- document.removeEventListener("mousemove", move);
12003
- document.removeEventListener("mouseup", up);
12004
- };
12005
- document.addEventListener("mousemove", move);
12006
- document.addEventListener("mouseup", up);
12007
- };
12008
- const defaultFooter = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
12009
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "neutral", appearance: "stroke", disabled: confirmLoading, onClick: cancel, ...cancelButtonProps, children: cancelText ?? "Cancel" }),
12010
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: okType === "danger" ? "error" : "primary", loading: confirmLoading, onClick: onOk, ...okButtonProps, children: okText ?? "OK" })
12011
- ] });
12012
- const resolvedFooter = footer === null ? null : footer !== void 0 ? footer : defaultFooter;
12013
- const dialogStyle = maximized ? { ...style } : {
12014
- width,
12015
- ...pos.x || pos.y ? { transform: `translate(${pos.x}px, ${pos.y}px)` } : null,
12016
- ...style
12017
- };
12018
- return /* @__PURE__ */ jsxRuntime.jsx(
12019
- "div",
12020
- {
12021
- className: chunkTPGAXYFU_cjs.cx("klun-modal", centered && "klun-modal--centered", !mask && "klun-modal--no-mask"),
12022
- style: zIndex != null ? { zIndex } : void 0,
12023
- onClick: backdropClosable && closable ? cancel : void 0,
12024
- children: /* @__PURE__ */ jsxRuntime.jsxs(
12025
- "div",
12026
- {
12027
- ref,
12028
- role: "dialog",
12029
- "aria-modal": "true",
12030
- onClick: (e) => e.stopPropagation(),
12031
- className: chunkTPGAXYFU_cjs.cx("klun-modal__dialog", maximized && "klun-modal__dialog--maximized", className),
12032
- style: dialogStyle,
12033
- ...props,
12034
- children: [
12035
- title || icon ? /* @__PURE__ */ jsxRuntime.jsxs(
12036
- "div",
12037
- {
12038
- className: chunkTPGAXYFU_cjs.cx("klun-modal__header", draggable && !maximized && "klun-modal__header--draggable"),
12039
- onMouseDown: startDrag,
12040
- children: [
12041
- icon ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-modal__icon", children: icon }) : null,
12042
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-modal__heading", children: [
12043
- title ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-modal__title", children: title }) : null,
12044
- description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-modal__description", children: description }) : null
12045
- ] }),
12046
- maximizable || closable ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-modal__actions", children: [
12047
- maximizable ? /* @__PURE__ */ jsxRuntime.jsx(
12048
- "button",
12049
- {
12050
- type: "button",
12051
- onClick: () => setMaximized((m) => !m),
12052
- "aria-label": maximized ? modal.restore ?? "Restore" : modal.maximize ?? "Maximize",
12053
- className: "klun-modal__action",
12054
- children: maximized ? /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 20 20", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 4v4H4M12 16v-4h4M12 4v4h4M8 16v-4H4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) : /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 20 20", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 8V4h4M16 12v4h-4M16 8V4h-4M4 12v4h4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
12055
- }
12056
- ) : null,
12057
- closable ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: cancel, "aria-label": modal.close, className: "klun-modal__action klun-modal__close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 5l10 10M15 5L5 15", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) }) : null
12058
- ] }) : null
12059
- ]
12060
- }
12061
- ) : null,
12062
- children ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-modal__body", children }) : null,
12063
- resolvedFooter ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkTPGAXYFU_cjs.cx("klun-modal__footer", !children && "klun-modal__footer--flush"), children: resolvedFooter }) : null
12064
- ]
12065
- }
12066
- )
12067
- }
12068
- );
12069
- });
12070
- Modal.displayName = "Modal";
12071
- var GAP4 = 8;
12072
- var MARGIN2 = 8;
14650
+ var GAP5 = 8;
14651
+ var MARGIN3 = 8;
12073
14652
  var Popconfirm = react.forwardRef(function Popconfirm2({
12074
14653
  title: titleProp,
12075
14654
  description,
@@ -12130,23 +14709,23 @@ var Popconfirm = react.forwardRef(function Popconfirm2({
12130
14709
  let left;
12131
14710
  switch (placement) {
12132
14711
  case "bottom":
12133
- top = tr.bottom + GAP4;
14712
+ top = tr.bottom + GAP5;
12134
14713
  left = tr.left + tr.width / 2 - bw / 2;
12135
14714
  break;
12136
14715
  case "left":
12137
- left = tr.left - bw - GAP4;
14716
+ left = tr.left - bw - GAP5;
12138
14717
  top = tr.top + tr.height / 2 - bh / 2;
12139
14718
  break;
12140
14719
  case "right":
12141
- left = tr.right + GAP4;
14720
+ left = tr.right + GAP5;
12142
14721
  top = tr.top + tr.height / 2 - bh / 2;
12143
14722
  break;
12144
14723
  default:
12145
- top = tr.top - bh - GAP4;
14724
+ top = tr.top - bh - GAP5;
12146
14725
  left = tr.left + tr.width / 2 - bw / 2;
12147
14726
  }
12148
- left = Math.max(MARGIN2, Math.min(left, vw - bw - MARGIN2));
12149
- top = Math.max(MARGIN2, Math.min(top, vh - bh - MARGIN2));
14727
+ left = Math.max(MARGIN3, Math.min(left, vw - bw - MARGIN3));
14728
+ top = Math.max(MARGIN3, Math.min(top, vh - bh - MARGIN3));
12150
14729
  setPos({ top, left });
12151
14730
  };
12152
14731
  place2();
@@ -12243,18 +14822,23 @@ var Popconfirm = react.forwardRef(function Popconfirm2({
12243
14822
  Popconfirm.displayName = "Popconfirm";
12244
14823
 
12245
14824
  exports.Accordion = Accordion;
14825
+ exports.ActivityHeatmap = ActivityHeatmap;
14826
+ exports.ActorAvatar = ActorAvatar;
12246
14827
  exports.Alert = Alert;
12247
14828
  exports.AutoComplete = AutoComplete;
12248
14829
  exports.Avatar = Avatar;
12249
14830
  exports.AvatarGroup = AvatarGroup;
12250
14831
  exports.Badge = Badge;
12251
14832
  exports.Banner = Banner;
14833
+ exports.BorderBeam = BorderBeam;
12252
14834
  exports.Breadcrumb = Breadcrumb;
12253
14835
  exports.BulkAction = BulkAction;
12254
14836
  exports.BulkActionBar = BulkActionBar;
12255
14837
  exports.Button = Button;
12256
14838
  exports.ButtonGroup = ButtonGroup;
12257
14839
  exports.CRON_PRESETS = CRON_PRESETS;
14840
+ exports.CapabilityBanner = CapabilityBanner;
14841
+ exports.CappedNumberFlow = CappedNumberFlow;
12258
14842
  exports.Card = Card;
12259
14843
  exports.Carousel = Carousel;
12260
14844
  exports.Cascader = Cascader;
@@ -12273,6 +14857,7 @@ exports.ColorDot = ColorDot;
12273
14857
  exports.ColorPicker = ColorPicker;
12274
14858
  exports.ColorSlider = ColorSlider;
12275
14859
  exports.CommandMenu = CommandMenu;
14860
+ exports.CompactNumberFlow = CompactNumberFlow;
12276
14861
  exports.CompactSelect = CompactSelect;
12277
14862
  exports.CompactSelectForInput = CompactSelectForInput;
12278
14863
  exports.ConfigProvider = ConfigProvider;
@@ -12283,6 +14868,7 @@ exports.CopyButton = CopyButton;
12283
14868
  exports.CounterInput = CounterInput;
12284
14869
  exports.CronEditor = CronEditor;
12285
14870
  exports.CrossRefBadge = CrossRefBadge;
14871
+ exports.CurrencyNumberFlow = CurrencyNumberFlow;
12286
14872
  exports.DatePicker = DatePicker;
12287
14873
  exports.DateRangePicker = DateRangePicker;
12288
14874
  exports.DateTimePicker = DateTimePicker;
@@ -12290,10 +14876,19 @@ exports.Descriptions = Descriptions;
12290
14876
  exports.DiffViewer = DiffViewer;
12291
14877
  exports.DigitInput = DigitInput;
12292
14878
  exports.Divider = Divider;
14879
+ exports.DotSphere = DotSphere;
12293
14880
  exports.Drawer = Drawer;
12294
14881
  exports.Dropdown = Dropdown;
14882
+ exports.EmojiPicker = EmojiPicker;
12295
14883
  exports.EmptyState = EmptyState;
12296
14884
  exports.ExpiryCountdown = ExpiryCountdown;
14885
+ exports.Field = Field;
14886
+ exports.FieldContent = FieldContent;
14887
+ exports.FieldDescription = FieldDescription;
14888
+ exports.FieldError = FieldError;
14889
+ exports.FieldGroup = FieldGroup;
14890
+ exports.FieldLabel = FieldLabel;
14891
+ exports.FieldTitle = FieldTitle;
12297
14892
  exports.FileUpload = FileUpload;
12298
14893
  exports.Flex = Flex;
12299
14894
  exports.Form = Form;
@@ -12304,14 +14899,35 @@ exports.GaugeBar = GaugeBar;
12304
14899
  exports.Grid = Grid;
12305
14900
  exports.Hint = Hint;
12306
14901
  exports.HorizontalFilter = HorizontalFilter;
14902
+ exports.HoverCard = HoverCard;
14903
+ exports.HoverCardContent = HoverCardContent;
14904
+ exports.HoverCardTrigger = HoverCardTrigger;
14905
+ exports.ICON_GROUPS = ICON_GROUPS;
14906
+ exports.IconPicker = IconPicker;
12307
14907
  exports.ImageUpload = ImageUpload;
12308
14908
  exports.ImageViewer = ImageViewer;
12309
14909
  exports.InlineInput = InlineInput;
12310
14910
  exports.InlineSelect = InlineSelect;
12311
14911
  exports.Input = Input;
14912
+ exports.InputGroup = InputGroup;
14913
+ exports.InputGroupAddon = InputGroupAddon;
14914
+ exports.InputGroupButton = InputGroupButton;
14915
+ exports.InputGroupInput = InputGroupInput;
14916
+ exports.InputGroupText = InputGroupText;
14917
+ exports.Item = Item;
14918
+ exports.ItemActions = ItemActions;
14919
+ exports.ItemContent = ItemContent;
14920
+ exports.ItemDescription = ItemDescription;
14921
+ exports.ItemFooter = ItemFooter;
14922
+ exports.ItemGroup = ItemGroup;
14923
+ exports.ItemHeader = ItemHeader;
14924
+ exports.ItemMedia = ItemMedia;
14925
+ exports.ItemSeparator = ItemSeparator;
14926
+ exports.ItemTitle = ItemTitle;
12312
14927
  exports.Kanban = Kanban;
12313
14928
  exports.Kbd = Kbd;
12314
14929
  exports.KeyIcon = KeyIcon;
14930
+ exports.LIST_GRID_BOTTOM_CLEARANCE = LIST_GRID_BOTTOM_CLEARANCE;
12315
14931
  exports.Label = Label;
12316
14932
  exports.Layout = Layout;
12317
14933
  exports.LayoutContent = LayoutContent;
@@ -12319,6 +14935,12 @@ exports.LayoutFooter = LayoutFooter;
12319
14935
  exports.LayoutHeader = LayoutHeader;
12320
14936
  exports.LayoutSider = LayoutSider;
12321
14937
  exports.List = List;
14938
+ exports.ListGrid = ListGrid;
14939
+ exports.ListGridBody = ListGridBody;
14940
+ exports.ListGridCell = ListGridCell;
14941
+ exports.ListGridHeader = ListGridHeader;
14942
+ exports.ListGridHeaderCell = ListGridHeaderCell;
14943
+ exports.ListGridRow = ListGridRow;
12322
14944
  exports.ListItem = ListItem;
12323
14945
  exports.LiveDot = LiveDot;
12324
14946
  exports.LogViewer = LogViewer;
@@ -12328,17 +14950,22 @@ exports.Menu = Menu;
12328
14950
  exports.Message = Message;
12329
14951
  exports.Modal = Modal;
12330
14952
  exports.Money = Money;
14953
+ exports.NavigationProgress = NavigationProgress;
12331
14954
  exports.Notification = Notification;
14955
+ exports.NumberFlow = NumberFlow;
12332
14956
  exports.PageHeader = PageHeader;
12333
14957
  exports.Pagination = Pagination;
12334
14958
  exports.PasswordStrength = PasswordStrength;
12335
14959
  exports.Popconfirm = Popconfirm;
12336
14960
  exports.Popover = Popover;
12337
14961
  exports.ProgressBar = ProgressBar;
14962
+ exports.QUICK_EMOJIS = QUICK_EMOJIS;
14963
+ exports.QuickEmojiPicker = QuickEmojiPicker;
12338
14964
  exports.Radio = Radio;
12339
14965
  exports.RadioCard = RadioCard;
12340
14966
  exports.RangeSlider = RangeSlider;
12341
14967
  exports.Rating = Rating;
14968
+ exports.ReactionBar = ReactionBar;
12342
14969
  exports.RelativeTime = RelativeTime;
12343
14970
  exports.Result = Result;
12344
14971
  exports.RichEditor = RichEditor;
@@ -12348,6 +14975,8 @@ exports.SegmentedControl = SegmentedControl;
12348
14975
  exports.SegmentedProgress = SegmentedProgress;
12349
14976
  exports.Select = Select;
12350
14977
  exports.SelectMenu = SelectMenu;
14978
+ exports.ShimmerText = ShimmerText;
14979
+ exports.Sidebar = Sidebar;
12351
14980
  exports.Skeleton = Skeleton;
12352
14981
  exports.Slider = Slider;
12353
14982
  exports.Space = Space;
@@ -12359,6 +14988,16 @@ exports.Statistic = Statistic;
12359
14988
  exports.StatusBadge = StatusBadge;
12360
14989
  exports.StatusDot = StatusDot;
12361
14990
  exports.StepIndicator = StepIndicator;
14991
+ exports.Stepper = Stepper;
14992
+ exports.StepperContent = StepperContent;
14993
+ exports.StepperDescription = StepperDescription;
14994
+ exports.StepperIndicator = StepperIndicator;
14995
+ exports.StepperItem = StepperItem;
14996
+ exports.StepperNav = StepperNav;
14997
+ exports.StepperPanel = StepperPanel;
14998
+ exports.StepperSeparator = StepperSeparator;
14999
+ exports.StepperTitle = StepperTitle;
15000
+ exports.StepperTrigger = StepperTrigger;
12362
15001
  exports.Switch = Switch;
12363
15002
  exports.Table = Table;
12364
15003
  exports.Tabs = Tabs;
@@ -12368,29 +15007,39 @@ exports.TimePicker = TimePicker;
12368
15007
  exports.Timeline = Timeline;
12369
15008
  exports.Toast = Toast;
12370
15009
  exports.Toaster = Toaster;
15010
+ exports.Toggle = Toggle;
12371
15011
  exports.Tooltip = Tooltip;
12372
15012
  exports.Tree = Tree;
15013
+ exports.UnicodeSpinner = UnicodeSpinner;
12373
15014
  exports.VirtualTable = VirtualTable;
12374
15015
  exports.Wizard = Wizard;
12375
15016
  exports.arSA = arSA;
15017
+ exports.buildHeatmapGrid = buildHeatmapGrid;
12376
15018
  exports.deDE = deDE;
12377
15019
  exports.describeCron = describeCron;
12378
15020
  exports.enUS = enUS;
12379
15021
  exports.esES = esES;
12380
15022
  exports.fmt = fmt;
15023
+ exports.formatAvatarEmoji = formatAvatarEmoji;
12381
15024
  exports.frFR = frFR;
15025
+ exports.groupReactions = groupReactions;
12382
15026
  exports.idID = idID;
12383
15027
  exports.itIT = itIT;
12384
15028
  exports.jaJP = jaJP;
12385
15029
  exports.koKR = koKR;
15030
+ exports.localTodayIso = localTodayIso;
12386
15031
  exports.locales = locales;
12387
15032
  exports.nlNL = nlNL;
15033
+ exports.parseAvatarEmoji = parseAvatarEmoji;
12388
15034
  exports.parsePatch = parsePatch;
12389
15035
  exports.plPL = plPL;
12390
15036
  exports.primaryColorVars = primaryColorVars;
12391
15037
  exports.ptBR = ptBR;
12392
15038
  exports.renderMarkdown = renderMarkdown;
15039
+ exports.reorderRows = reorderRows;
15040
+ exports.resolveMove = resolveMove;
12393
15041
  exports.ruRU = ruRU;
15042
+ exports.summarizeHeatmap = summarizeHeatmap;
12394
15043
  exports.toast = toast;
12395
15044
  exports.trTR = trTR;
12396
15045
  exports.useBreakpoint = useBreakpoint;
@@ -12402,8 +15051,10 @@ exports.useMappedSize = useMappedSize;
12402
15051
  exports.useMessage = useMessage;
12403
15052
  exports.useNotification = useNotification;
12404
15053
  exports.useSize = useSize;
15054
+ exports.useStepItem = useStepItem;
15055
+ exports.useStepper = useStepper;
12405
15056
  exports.viVN = viVN;
12406
15057
  exports.zhCN = zhCN;
12407
15058
  exports.zhTW = zhTW;
12408
- //# sourceMappingURL=chunk-IETPQZRQ.cjs.map
12409
- //# sourceMappingURL=chunk-IETPQZRQ.cjs.map
15059
+ //# sourceMappingURL=chunk-ODVX2AVA.cjs.map
15060
+ //# sourceMappingURL=chunk-ODVX2AVA.cjs.map