klun-ui 0.2.2 → 0.4.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.
@@ -3344,6 +3344,170 @@ var DiffViewer = react.forwardRef(function DiffViewer2({
3344
3344
  );
3345
3345
  });
3346
3346
  DiffViewer.displayName = "DiffViewer";
3347
+ var Kanban = react.forwardRef(function Kanban2({ columns = [], onMove, onCardClick, renderCard, columnFooter, columnWidth = 280, className, style, ...props }, ref) {
3348
+ const [drag, setDrag] = react.useState(null);
3349
+ const [overColumn, setOverColumn] = react.useState(null);
3350
+ const handleDrop = (column, index) => {
3351
+ if (drag && (drag.fromColumn !== column.id || index !== index)) {
3352
+ onMove?.(drag.cardId, drag.fromColumn, column.id, index);
3353
+ }
3354
+ setDrag(null);
3355
+ setOverColumn(null);
3356
+ };
3357
+ return /* @__PURE__ */ jsxRuntime.jsx(
3358
+ "div",
3359
+ {
3360
+ ref,
3361
+ className: chunkTPGAXYFU_cjs.cx("klun-kanban", className),
3362
+ style: { ...style, ["--klun-kanban-col"]: `${columnWidth}px` },
3363
+ ...props,
3364
+ children: columns.map((column) => {
3365
+ const over = overColumn === column.id && drag;
3366
+ const full = column.limit !== void 0 && column.cards.length >= column.limit;
3367
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: chunkTPGAXYFU_cjs.cx("klun-kanban__column", over && "klun-kanban__column--over"), children: [
3368
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "klun-kanban__header", children: [
3369
+ column.accent ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-kanban__dot", style: { background: column.accent } }) : null,
3370
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-kanban__title", children: column.title }),
3371
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: chunkTPGAXYFU_cjs.cx("klun-kanban__count", full && "klun-kanban__count--full"), children: [
3372
+ column.cards.length,
3373
+ column.limit !== void 0 ? ` / ${column.limit}` : ""
3374
+ ] })
3375
+ ] }),
3376
+ /* @__PURE__ */ jsxRuntime.jsxs(
3377
+ "div",
3378
+ {
3379
+ className: "klun-kanban__list",
3380
+ onDragOver: (e) => {
3381
+ if (!drag) return;
3382
+ e.preventDefault();
3383
+ setOverColumn(column.id);
3384
+ },
3385
+ onDrop: (e) => {
3386
+ e.preventDefault();
3387
+ handleDrop(column, column.cards.length);
3388
+ },
3389
+ children: [
3390
+ column.cards.map((card, index) => /* @__PURE__ */ jsxRuntime.jsx(
3391
+ "article",
3392
+ {
3393
+ draggable: true,
3394
+ onDragStart: (e) => {
3395
+ e.dataTransfer.effectAllowed = "move";
3396
+ e.dataTransfer.setData("text/plain", card.id);
3397
+ setDrag({ cardId: card.id, fromColumn: column.id });
3398
+ },
3399
+ onDragEnd: () => {
3400
+ setDrag(null);
3401
+ setOverColumn(null);
3402
+ },
3403
+ onDragOver: (e) => {
3404
+ if (!drag) return;
3405
+ e.preventDefault();
3406
+ e.stopPropagation();
3407
+ const rect = e.currentTarget.getBoundingClientRect();
3408
+ const after = e.clientY - rect.top > rect.height / 2;
3409
+ setOverColumn(column.id);
3410
+ setDrag((d) => d ? { ...d, overColumn: column.id, overIndex: index + (after ? 1 : 0) } : d);
3411
+ },
3412
+ onDrop: (e) => {
3413
+ e.preventDefault();
3414
+ e.stopPropagation();
3415
+ handleDrop(column, index);
3416
+ },
3417
+ onClick: () => onCardClick?.(card, column.id),
3418
+ className: chunkTPGAXYFU_cjs.cx(
3419
+ "klun-kanban__card",
3420
+ drag?.cardId === card.id && "klun-kanban__card--dragging",
3421
+ over && drag?.overIndex === index && "klun-kanban__card--dropbefore",
3422
+ over && drag?.overIndex === index + 1 && "klun-kanban__card--dropafter"
3423
+ ),
3424
+ style: card.accent ? { boxShadow: `inset 3px 0 0 ${card.accent}` } : void 0,
3425
+ children: renderCard ? renderCard(card, column.id) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3426
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-kanban__card-title", children: card.title }),
3427
+ card.description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-kanban__card-desc", children: card.description }) : null,
3428
+ card.tags?.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-kanban__card-tags", children: card.tags.map((t, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { children: t }, i)) }) : null,
3429
+ card.meta ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-kanban__card-meta", children: card.meta }) : null
3430
+ ] })
3431
+ },
3432
+ card.id
3433
+ )),
3434
+ column.cards.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-kanban__empty", children: "Drop a card here" }) : null
3435
+ ]
3436
+ }
3437
+ ),
3438
+ columnFooter ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-kanban__footer", children: columnFooter(column) }) : null
3439
+ ] }, column.id);
3440
+ })
3441
+ }
3442
+ );
3443
+ });
3444
+ Kanban.displayName = "Kanban";
3445
+ function VirtualTable({
3446
+ rows = [],
3447
+ columns = [],
3448
+ rowHeight = 40,
3449
+ height = 420,
3450
+ getRowId,
3451
+ onRowClick,
3452
+ overscan = 8,
3453
+ zebra = true,
3454
+ empty,
3455
+ className,
3456
+ style,
3457
+ ...props
3458
+ }) {
3459
+ const [scrollTop, setScrollTop] = react.useState(0);
3460
+ const total = rows.length;
3461
+ const template = react.useMemo(
3462
+ () => columns.map((c) => c.width ? `${c.width}px` : "minmax(0, 1fr)").join(" "),
3463
+ [columns]
3464
+ );
3465
+ const bodyHeight = Math.max(0, height - 36);
3466
+ const start = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
3467
+ const end = Math.min(total, Math.ceil((scrollTop + bodyHeight) / rowHeight) + overscan);
3468
+ const slice = rows.slice(start, end);
3469
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: void 0, className: chunkTPGAXYFU_cjs.cx("klun-vtable", className), style: { ...style, height }, ...props, children: [
3470
+ /* @__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)) }),
3471
+ /* @__PURE__ */ jsxRuntime.jsx(
3472
+ "div",
3473
+ {
3474
+ className: "klun-vtable__body",
3475
+ onScroll: (e) => setScrollTop(e.target.scrollTop),
3476
+ style: { maxHeight: bodyHeight },
3477
+ children: total === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-vtable__empty", children: empty ?? "No rows" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3478
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: start * rowHeight } }),
3479
+ slice.map((row, i) => {
3480
+ const index = start + i;
3481
+ const id = getRowId?.(row, index) ?? index;
3482
+ return /* @__PURE__ */ jsxRuntime.jsx(
3483
+ "div",
3484
+ {
3485
+ role: onRowClick ? "button" : void 0,
3486
+ tabIndex: onRowClick ? 0 : void 0,
3487
+ onClick: () => onRowClick?.(row, index),
3488
+ className: chunkTPGAXYFU_cjs.cx(
3489
+ "klun-vtable__row",
3490
+ zebra && index % 2 === 1 && "klun-vtable__row--zebra",
3491
+ onRowClick && "klun-vtable__row--clickable"
3492
+ ),
3493
+ style: { gridTemplateColumns: template, height: rowHeight },
3494
+ 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))
3495
+ },
3496
+ id
3497
+ );
3498
+ }),
3499
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: Math.max(0, (total - end) * rowHeight) } })
3500
+ ] })
3501
+ }
3502
+ ),
3503
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-vtable__foot", children: [
3504
+ total.toLocaleString("en-US"),
3505
+ " rows \xB7 rendering ",
3506
+ slice.length
3507
+ ] })
3508
+ ] });
3509
+ }
3510
+ VirtualTable.displayName = "VirtualTable";
3347
3511
  var Kbd = react.forwardRef(function Kbd2({ className, children, ...props }, ref) {
3348
3512
  return /* @__PURE__ */ jsxRuntime.jsx("kbd", { ref, className: chunkTPGAXYFU_cjs.cx("klun-kbd", className), ...props, children });
3349
3513
  });
@@ -6541,25 +6705,30 @@ var AutoComplete = react.forwardRef(
6541
6705
  AutoComplete.displayName = "AutoComplete";
6542
6706
  var Cascader = react.forwardRef(function Cascader2({
6543
6707
  options = [],
6544
- value = [],
6708
+ value,
6709
+ defaultValue,
6545
6710
  onChange,
6546
6711
  placeholder: placeholderProp,
6547
6712
  size: sizeProp,
6548
6713
  disabled = false,
6549
6714
  separator = " / ",
6550
6715
  changeOnSelect = false,
6716
+ clearable = false,
6717
+ renderOption,
6551
6718
  error = false,
6552
6719
  className,
6553
6720
  ...props
6554
6721
  }, ref) {
6555
6722
  const size = useSize(sizeProp);
6556
- const { cascader } = useLocale();
6723
+ const { cascader, input: inputText } = useLocale();
6557
6724
  const placeholder = placeholderProp ?? cascader.placeholder;
6725
+ const [inner, setInner] = react.useState(defaultValue ?? []);
6726
+ const current = value ?? inner;
6558
6727
  const [open, setOpen] = react.useState(false);
6559
- const [active, setActive] = react.useState(value);
6728
+ const [active, setActive] = react.useState(current);
6560
6729
  const rootRef = react.useRef(null);
6561
6730
  react.useEffect(() => {
6562
- setActive(value);
6731
+ setActive(current);
6563
6732
  }, [open]);
6564
6733
  react.useEffect(() => {
6565
6734
  if (!open) return;
@@ -6588,7 +6757,7 @@ var Cascader = react.forwardRef(function Cascader2({
6588
6757
  }
6589
6758
  const labelPath = [];
6590
6759
  let lvl = options;
6591
- for (const key of value) {
6760
+ for (const key of current) {
6592
6761
  const found = (lvl || []).find((o) => o.value === key);
6593
6762
  if (!found) break;
6594
6763
  labelPath.push(found.label);
@@ -6600,10 +6769,16 @@ var Cascader = react.forwardRef(function Cascader2({
6600
6769
  setActive(nextPath);
6601
6770
  const leaf = !opt.children || !opt.children.length;
6602
6771
  if (leaf || changeOnSelect) {
6772
+ if (value === void 0) setInner(nextPath);
6603
6773
  onChange && onChange(nextPath);
6604
6774
  if (leaf) setOpen(false);
6605
6775
  }
6606
6776
  };
6777
+ const clear = () => {
6778
+ if (value === void 0) setInner([]);
6779
+ setActive([]);
6780
+ onChange && onChange([]);
6781
+ };
6607
6782
  const setRefs = (node) => {
6608
6783
  rootRef.current = node;
6609
6784
  if (typeof ref === "function") ref(node);
@@ -6633,6 +6808,20 @@ var Cascader = react.forwardRef(function Cascader2({
6633
6808
  i > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-cascader__separator", children: separator }) : null,
6634
6809
  lbl
6635
6810
  ] }, i)) : placeholder }),
6811
+ clearable && labelPath.length && !disabled ? /* @__PURE__ */ jsxRuntime.jsx(
6812
+ "span",
6813
+ {
6814
+ role: "button",
6815
+ tabIndex: -1,
6816
+ "aria-label": inputText.clear,
6817
+ className: "klun-cascader__clear",
6818
+ onClick: (e) => {
6819
+ e.stopPropagation();
6820
+ clear();
6821
+ },
6822
+ children: /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-close-circle-fill" })
6823
+ }
6824
+ ) : null,
6636
6825
  /* @__PURE__ */ jsxRuntime.jsx(
6637
6826
  "svg",
6638
6827
  {
@@ -6657,7 +6846,7 @@ var Cascader = react.forwardRef(function Cascader2({
6657
6846
  ]
6658
6847
  }
6659
6848
  ),
6660
- open ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-cascader__panel", children: columns.map((col, ci) => /* @__PURE__ */ jsxRuntime.jsx(
6849
+ open ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-cascader__panel", role: "menu", children: columns.map((col, ci) => /* @__PURE__ */ jsxRuntime.jsx(
6661
6850
  "div",
6662
6851
  {
6663
6852
  className: chunkTPGAXYFU_cjs.cx(
@@ -6671,12 +6860,14 @@ var Cascader = react.forwardRef(function Cascader2({
6671
6860
  "button",
6672
6861
  {
6673
6862
  type: "button",
6863
+ role: "menuitem",
6674
6864
  className: "klun-cascader__option",
6675
6865
  disabled: opt.disabled,
6676
6866
  onClick: () => pick(ci, opt),
6867
+ "aria-selected": selected,
6677
6868
  "data-selected": selected || void 0,
6678
6869
  children: [
6679
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-cascader__option-label", children: opt.label }),
6870
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-cascader__option-label", children: renderOption ? renderOption(opt, ci) : opt.label }),
6680
6871
  hasChildren2 ? /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-arrow-right-s-line klun-cascader__option-arrow" }) : selected ? /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-check-line klun-cascader__option-check" }) : null
6681
6872
  ]
6682
6873
  },
@@ -7472,6 +7663,149 @@ var CompactSelectForInput = react.forwardRef(function CompactSelectForInput2({
7472
7663
  );
7473
7664
  });
7474
7665
  CompactSelectForInput.displayName = "CompactSelectForInput";
7666
+ var CRON_PRESETS = [
7667
+ { label: "Every 5 minutes", value: "*/5 * * * *" },
7668
+ { label: "Every 15 minutes", value: "*/15 * * * *" },
7669
+ { label: "Hourly", value: "0 * * * *" },
7670
+ { label: "Every day at 03:00", value: "0 3 * * *" },
7671
+ { label: "Weekdays at 09:00", value: "0 9 * * 1-5" },
7672
+ { label: "Mondays at 09:00", value: "0 9 * * 1" },
7673
+ { label: "1st of the month", value: "0 6 1 * *" }
7674
+ ];
7675
+ var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
7676
+ var DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
7677
+ var pad = (n) => n.padStart(2, "0");
7678
+ function describeCron(cron) {
7679
+ const parts = cron.trim().split(/\s+/);
7680
+ if (parts.length !== 5) return cron;
7681
+ const [min, hour, day, month, week] = parts;
7682
+ const everyMin = min.startsWith("*/") ? `every ${min.slice(2)} minutes` : min === "*" ? "every minute" : null;
7683
+ const at = hour === "*" ? "" : ` at ${pad(hour)}:${pad(min)}`;
7684
+ const dayPart = week === "*" && day === "*" ? month === "*" ? "every day" : `on day ${day} of month ${month}` : week !== "*" ? `on ${week.split(",").map((w) => w.includes("-") ? w.split("-").map((x) => DAYS[Number(x)] ?? x).join("\u2013") : DAYS[Number(w)] ?? w).join(", ")}` : `on day ${day} of the month`;
7685
+ if (everyMin) return `${everyMin.charAt(0).toUpperCase()}${everyMin.slice(1)}${at}`;
7686
+ if (min !== "*" && hour !== "*" && day === "*" && week === "*") {
7687
+ return `${month === "*" ? "Every day" : `On day ${day} of month ${MONTHS[Number(month) - 1] ?? month}`}${at}`;
7688
+ }
7689
+ return `${dayPart.charAt(0).toUpperCase()}${dayPart.slice(1)}${at}`;
7690
+ }
7691
+ function parse(cron) {
7692
+ const p = cron.trim().split(/\s+/);
7693
+ return [p[0] ?? "*", p[1] ?? "*", p[2] ?? "*", p[3] ?? "*", p[4] ?? "*"];
7694
+ }
7695
+ var CronEditor = react.forwardRef(function CronEditor2({
7696
+ value,
7697
+ defaultValue = "0 3 * * *",
7698
+ onChange,
7699
+ hidePresets = false,
7700
+ disabled = false,
7701
+ size: sizeProp,
7702
+ labels,
7703
+ className,
7704
+ style,
7705
+ ...props
7706
+ }, ref) {
7707
+ const size = useSize(sizeProp) === "small" ? "small" : "medium";
7708
+ const text = {
7709
+ minute: "Minute",
7710
+ hour: "Hour",
7711
+ day: "Day",
7712
+ month: "Month",
7713
+ weekday: "Weekday",
7714
+ every: "Every",
7715
+ expression: "Expression",
7716
+ ...labels
7717
+ };
7718
+ const [inner, setInner] = react.useState(defaultValue);
7719
+ const current = value ?? inner;
7720
+ const [fields, setFields] = react.useState(parse(current));
7721
+ react.useEffect(() => {
7722
+ setFields(parse(current));
7723
+ }, [current]);
7724
+ const commit = (next) => {
7725
+ if (value === void 0) setInner(next);
7726
+ onChange?.(next);
7727
+ };
7728
+ const setField = (index, next) => {
7729
+ const copy = [...fields];
7730
+ copy[index] = next;
7731
+ setFields(copy);
7732
+ commit(copy.join(" "));
7733
+ };
7734
+ const options = react.useMemo(
7735
+ () => ({
7736
+ minute: ["*", "*/5", "*/10", "*/15", "*/30", "0", "15", "30", "45"],
7737
+ hour: ["*", ...Array.from({ length: 24 }, (_, i) => String(i))],
7738
+ day: ["*", ...Array.from({ length: 31 }, (_, i) => String(i + 1))],
7739
+ month: ["*", ...Array.from({ length: 12 }, (_, i) => String(i + 1))],
7740
+ weekday: ["*", "1-5", "0", "1", "2", "3", "4", "5", "6"]
7741
+ }),
7742
+ []
7743
+ );
7744
+ const fieldLabel = (key, v) => {
7745
+ if (v === "*") return text.every;
7746
+ if (key === "month") return MONTHS[Number(v) - 1] ?? v;
7747
+ if (key === "weekday") return v.includes("-") ? "Mon\u2013Fri" : DAYS[Number(v)] ?? v;
7748
+ if (key === "hour") return `${pad(v)}:00`;
7749
+ return v;
7750
+ };
7751
+ const desc = describeCron(current);
7752
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7753
+ "div",
7754
+ {
7755
+ ref,
7756
+ className: chunkTPGAXYFU_cjs.cx("klun-cron", `klun-cron--${size}`, disabled && "klun-cron--disabled", className),
7757
+ style,
7758
+ ...props,
7759
+ children: [
7760
+ !hidePresets ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-cron__presets", children: CRON_PRESETS.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
7761
+ "button",
7762
+ {
7763
+ type: "button",
7764
+ disabled,
7765
+ onClick: () => commit(p.value),
7766
+ "data-active": current === p.value || void 0,
7767
+ className: "klun-cron__preset",
7768
+ children: p.label
7769
+ },
7770
+ p.value
7771
+ )) }) : null,
7772
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-cron__fields", children: ["minute", "hour", "day", "month", "weekday"].map((key, i) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "klun-cron__field", children: [
7773
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-cron__field-label", children: text[key] }),
7774
+ /* @__PURE__ */ jsxRuntime.jsx(
7775
+ "select",
7776
+ {
7777
+ disabled,
7778
+ value: fields[i],
7779
+ onChange: (e) => setField(i, e.target.value),
7780
+ className: "klun-cron__select",
7781
+ children: options[key].map((v) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: v, children: fieldLabel(key, v) }, v))
7782
+ }
7783
+ )
7784
+ ] }, key)) }),
7785
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-cron__footer", children: [
7786
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "klun-cron__raw", children: [
7787
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-cron__field-label", children: text.expression }),
7788
+ /* @__PURE__ */ jsxRuntime.jsx(
7789
+ "input",
7790
+ {
7791
+ disabled,
7792
+ value: current,
7793
+ onChange: (e) => commit(e.target.value),
7794
+ spellCheck: false,
7795
+ className: "klun-cron__input"
7796
+ }
7797
+ )
7798
+ ] }),
7799
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-cron__preview", children: [
7800
+ /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-time-line" }),
7801
+ desc
7802
+ ] })
7803
+ ] })
7804
+ ]
7805
+ }
7806
+ );
7807
+ });
7808
+ CronEditor.displayName = "CronEditor";
7475
7809
  var CounterInput = react.forwardRef(function CounterInput2({
7476
7810
  value = 0,
7477
7811
  min = -Infinity,
@@ -7901,7 +8235,7 @@ var DateRangePicker = react.forwardRef(
7901
8235
  }
7902
8236
  );
7903
8237
  DateRangePicker.displayName = "DateRangePicker";
7904
- var pad = (n) => String(n).padStart(2, "0");
8238
+ var pad2 = (n) => String(n).padStart(2, "0");
7905
8239
  var TimePicker = react.forwardRef(
7906
8240
  function TimePicker2({ value = "09:00", onChange, className, style, ...props }, ref) {
7907
8241
  const t = useLocale();
@@ -7911,7 +8245,7 @@ var TimePicker = react.forwardRef(
7911
8245
  const set = (nh, nm, nmer) => {
7912
8246
  let hh = nh % 12;
7913
8247
  if (nmer === "PM") hh += 12;
7914
- onChange?.(`${pad(hh)}:${pad(nm)}`);
8248
+ onChange?.(`${pad2(hh)}:${pad2(nm)}`);
7915
8249
  };
7916
8250
  const [open, setOpen] = react.useState(null);
7917
8251
  const rootRef = react.useRef(null);
@@ -7930,11 +8264,11 @@ var TimePicker = react.forwardRef(
7930
8264
  }, [open]);
7931
8265
  const hourOpts = Array.from({ length: 12 }, (_, i) => ({
7932
8266
  value: String(i + 1),
7933
- label: pad(i + 1)
8267
+ label: pad2(i + 1)
7934
8268
  }));
7935
8269
  const minOpts = Array.from({ length: 60 }, (_, i) => ({
7936
8270
  value: String(i),
7937
- label: pad(i)
8271
+ label: pad2(i)
7938
8272
  }));
7939
8273
  const merOpts = [
7940
8274
  { value: "AM", label: t.timePicker.am },
@@ -8101,7 +8435,7 @@ function TimeColumn({
8101
8435
  ] });
8102
8436
  }
8103
8437
  TimePicker.displayName = "TimePicker";
8104
- var pad2 = (n) => String(n).padStart(2, "0");
8438
+ var pad3 = (n) => String(n).padStart(2, "0");
8105
8439
  var DEFAULT_FORMAT3 = {
8106
8440
  year: "numeric",
8107
8441
  month: "short",
@@ -8110,7 +8444,7 @@ var DEFAULT_FORMAT3 = {
8110
8444
  minute: "2-digit"
8111
8445
  };
8112
8446
  function DateTimePanel({ value, onChange }) {
8113
- const hhmm = value ? `${pad2(value.getHours())}:${pad2(value.getMinutes())}` : "09:00";
8447
+ const hhmm = value ? `${pad3(value.getHours())}:${pad3(value.getMinutes())}` : "09:00";
8114
8448
  const setDate = (d) => {
8115
8449
  const next = new Date(d);
8116
8450
  if (value) next.setHours(value.getHours(), value.getMinutes(), 0, 0);
@@ -9093,6 +9427,192 @@ var RichEditorToolbar = react.forwardRef(
9093
9427
  }
9094
9428
  );
9095
9429
  RichEditorToolbar.displayName = "RichEditorToolbar";
9430
+ var Textarea = react.forwardRef(function Textarea2({ error = false, disabled = false, readOnly = false, size: sizeProp, rows = 4, className, style, ...props }, ref) {
9431
+ const size = useSize(sizeProp);
9432
+ return /* @__PURE__ */ jsxRuntime.jsx(
9433
+ "div",
9434
+ {
9435
+ className: chunkTPGAXYFU_cjs.cx(
9436
+ "klun-textarea",
9437
+ `klun-textarea--${size}`,
9438
+ error && "klun-textarea--error",
9439
+ disabled && "klun-textarea--disabled",
9440
+ readOnly && "klun-textarea--readonly",
9441
+ className
9442
+ ),
9443
+ style,
9444
+ children: /* @__PURE__ */ jsxRuntime.jsx(
9445
+ "textarea",
9446
+ {
9447
+ ref,
9448
+ className: "klun-textarea__field",
9449
+ rows,
9450
+ disabled,
9451
+ readOnly,
9452
+ ...props
9453
+ }
9454
+ )
9455
+ }
9456
+ );
9457
+ });
9458
+ Textarea.displayName = "Textarea";
9459
+ function runCommand(id) {
9460
+ const exec = (cmd, arg) => document.execCommand(cmd, false, arg);
9461
+ if (typeof document.execCommand !== "function") return;
9462
+ switch (id) {
9463
+ case "bold":
9464
+ case "italic":
9465
+ case "underline":
9466
+ case "strikeThrough":
9467
+ exec(id);
9468
+ break;
9469
+ case "strike":
9470
+ exec("strikeThrough");
9471
+ break;
9472
+ case "h1":
9473
+ exec("formatBlock", "<h1>");
9474
+ break;
9475
+ case "h2":
9476
+ exec("formatBlock", "<h2>");
9477
+ break;
9478
+ case "quote":
9479
+ exec("formatBlock", "<blockquote>");
9480
+ break;
9481
+ case "code":
9482
+ exec("formatBlock", "<pre>");
9483
+ break;
9484
+ case "ul":
9485
+ exec("insertUnorderedList");
9486
+ break;
9487
+ case "ol":
9488
+ exec("insertOrderedList");
9489
+ break;
9490
+ case "link": {
9491
+ const url = typeof window !== "undefined" ? window.prompt("Link URL", "https://") : null;
9492
+ if (url) exec("createLink", url);
9493
+ break;
9494
+ }
9495
+ case "image": {
9496
+ const url = typeof window !== "undefined" ? window.prompt("Image URL", "https://") : null;
9497
+ if (url) exec("insertImage", url);
9498
+ break;
9499
+ }
9500
+ }
9501
+ }
9502
+ var RichEditor = react.forwardRef(function RichEditor2({
9503
+ value,
9504
+ defaultValue = "",
9505
+ onChange,
9506
+ placeholder = "Write something\u2026",
9507
+ disabled = false,
9508
+ hideToolbar = false,
9509
+ minHeight = 160,
9510
+ maxHeight,
9511
+ allowSource = true,
9512
+ editorLabel = "Rich text editor",
9513
+ className,
9514
+ style,
9515
+ ...props
9516
+ }, ref) {
9517
+ const editorRef = react.useRef(null);
9518
+ const [active, setActive] = react.useState([]);
9519
+ const [source, setSource] = react.useState(false);
9520
+ const [html, setHtml] = react.useState(value ?? defaultValue);
9521
+ react.useEffect(() => {
9522
+ const el = editorRef.current;
9523
+ if (!el) return;
9524
+ const next = value ?? html;
9525
+ if (document.activeElement !== el && el.innerHTML !== next) el.innerHTML = next;
9526
+ }, [value]);
9527
+ react.useEffect(() => {
9528
+ if (disabled || typeof document.execCommand !== "function") return;
9529
+ document.execCommand("defaultParagraphSeparator", false, "p");
9530
+ }, [disabled]);
9531
+ const emit2 = () => {
9532
+ const next = editorRef.current?.innerHTML ?? "";
9533
+ setHtml(next);
9534
+ onChange?.(next);
9535
+ };
9536
+ const syncActive = () => {
9537
+ if (typeof document.queryCommandState !== "function") return;
9538
+ const next = [];
9539
+ ["bold", "italic", "underline"].forEach((c) => {
9540
+ if (document.queryCommandState(c)) next.push(c);
9541
+ });
9542
+ setActive(next);
9543
+ };
9544
+ const onAction = (id) => {
9545
+ if (disabled) return;
9546
+ editorRef.current?.focus();
9547
+ runCommand(id);
9548
+ emit2();
9549
+ syncActive();
9550
+ };
9551
+ const setRefs = (node) => {
9552
+ editorRef.current = node;
9553
+ if (typeof ref === "function") ref(node);
9554
+ else if (ref) ref.current = node;
9555
+ };
9556
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9557
+ "div",
9558
+ {
9559
+ className: chunkTPGAXYFU_cjs.cx("klun-rich-editor", disabled && "klun-rich-editor--disabled", className),
9560
+ style,
9561
+ ...props,
9562
+ children: [
9563
+ !hideToolbar ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-rich-editor__bar", children: [
9564
+ /* @__PURE__ */ jsxRuntime.jsx(RichEditorToolbar, { active, onAction }),
9565
+ allowSource ? /* @__PURE__ */ jsxRuntime.jsxs(
9566
+ "button",
9567
+ {
9568
+ type: "button",
9569
+ className: "klun-rich-editor__source",
9570
+ onClick: () => setSource((s) => !s),
9571
+ "data-active": source || void 0,
9572
+ "aria-pressed": source,
9573
+ children: [
9574
+ /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-code-s-slash-line" }),
9575
+ "HTML"
9576
+ ]
9577
+ }
9578
+ ) : null
9579
+ ] }) : null,
9580
+ source && allowSource ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-rich-editor__sourcearea", children: /* @__PURE__ */ jsxRuntime.jsx(
9581
+ Textarea,
9582
+ {
9583
+ rows: Math.max(4, Math.round(minHeight / 22)),
9584
+ value: html,
9585
+ style: { border: "none", boxShadow: "none", fontFamily: "var(--klun-font-mono, monospace)" },
9586
+ onChange: (e) => {
9587
+ setHtml(e.target.value);
9588
+ onChange?.(e.target.value);
9589
+ if (editorRef.current) editorRef.current.innerHTML = e.target.value;
9590
+ }
9591
+ }
9592
+ ) }) : null,
9593
+ /* @__PURE__ */ jsxRuntime.jsx(
9594
+ "div",
9595
+ {
9596
+ ref: setRefs,
9597
+ role: "textbox",
9598
+ "aria-multiline": "true",
9599
+ "aria-label": editorLabel,
9600
+ contentEditable: !disabled,
9601
+ suppressContentEditableWarning: true,
9602
+ "data-placeholder": placeholder,
9603
+ className: "klun-rich-editor__area",
9604
+ style: { minHeight, maxHeight, overflowY: maxHeight ? "auto" : void 0 },
9605
+ onInput: emit2,
9606
+ onBlur: emit2,
9607
+ onKeyUp: syncActive,
9608
+ onMouseUp: syncActive
9609
+ }
9610
+ )
9611
+ ]
9612
+ }
9613
+ );
9614
+ });
9615
+ RichEditor.displayName = "RichEditor";
9096
9616
  var Select = react.forwardRef(function Select2({
9097
9617
  size: sizeProp,
9098
9618
  placeholder,
@@ -9372,35 +9892,6 @@ var Switch = react.forwardRef(function Switch2({ disabled = false, size: sizePro
9372
9892
  );
9373
9893
  });
9374
9894
  Switch.displayName = "Switch";
9375
- var Textarea = react.forwardRef(function Textarea2({ error = false, disabled = false, readOnly = false, size: sizeProp, rows = 4, className, style, ...props }, ref) {
9376
- const size = useSize(sizeProp);
9377
- return /* @__PURE__ */ jsxRuntime.jsx(
9378
- "div",
9379
- {
9380
- className: chunkTPGAXYFU_cjs.cx(
9381
- "klun-textarea",
9382
- `klun-textarea--${size}`,
9383
- error && "klun-textarea--error",
9384
- disabled && "klun-textarea--disabled",
9385
- readOnly && "klun-textarea--readonly",
9386
- className
9387
- ),
9388
- style,
9389
- children: /* @__PURE__ */ jsxRuntime.jsx(
9390
- "textarea",
9391
- {
9392
- ref,
9393
- className: "klun-textarea__field",
9394
- rows,
9395
- disabled,
9396
- readOnly,
9397
- ...props
9398
- }
9399
- )
9400
- }
9401
- );
9402
- });
9403
- Textarea.displayName = "Textarea";
9404
9895
  var Card = react.forwardRef(function Card2({ variant = "stroke", padding, className, style, children, ...props }, ref) {
9405
9896
  return /* @__PURE__ */ jsxRuntime.jsx(
9406
9897
  "div",
@@ -11614,6 +12105,7 @@ exports.BulkAction = BulkAction;
11614
12105
  exports.BulkActionBar = BulkActionBar;
11615
12106
  exports.Button = Button;
11616
12107
  exports.ButtonGroup = ButtonGroup;
12108
+ exports.CRON_PRESETS = CRON_PRESETS;
11617
12109
  exports.Card = Card;
11618
12110
  exports.Carousel = Carousel;
11619
12111
  exports.Cascader = Cascader;
@@ -11640,6 +12132,7 @@ exports.ContentLabel = ContentLabel;
11640
12132
  exports.ContextMenu = ContextMenu2;
11641
12133
  exports.CopyButton = CopyButton;
11642
12134
  exports.CounterInput = CounterInput;
12135
+ exports.CronEditor = CronEditor;
11643
12136
  exports.CrossRefBadge = CrossRefBadge;
11644
12137
  exports.DatePicker = DatePicker;
11645
12138
  exports.DateRangePicker = DateRangePicker;
@@ -11667,6 +12160,7 @@ exports.ImageViewer = ImageViewer;
11667
12160
  exports.InlineInput = InlineInput;
11668
12161
  exports.InlineSelect = InlineSelect;
11669
12162
  exports.Input = Input;
12163
+ exports.Kanban = Kanban;
11670
12164
  exports.Kbd = Kbd;
11671
12165
  exports.KeyIcon = KeyIcon;
11672
12166
  exports.Label = Label;
@@ -11698,6 +12192,7 @@ exports.RangeSlider = RangeSlider;
11698
12192
  exports.Rating = Rating;
11699
12193
  exports.RelativeTime = RelativeTime;
11700
12194
  exports.Result = Result;
12195
+ exports.RichEditor = RichEditor;
11701
12196
  exports.RichEditorToolbar = RichEditorToolbar;
11702
12197
  exports.Row = Row;
11703
12198
  exports.SegmentedControl = SegmentedControl;
@@ -11726,9 +12221,11 @@ exports.Toast = Toast;
11726
12221
  exports.Toaster = Toaster;
11727
12222
  exports.Tooltip = Tooltip;
11728
12223
  exports.Tree = Tree;
12224
+ exports.VirtualTable = VirtualTable;
11729
12225
  exports.Wizard = Wizard;
11730
12226
  exports.arSA = arSA;
11731
12227
  exports.deDE = deDE;
12228
+ exports.describeCron = describeCron;
11732
12229
  exports.enUS = enUS;
11733
12230
  exports.esES = esES;
11734
12231
  exports.fmt = fmt;
@@ -11759,5 +12256,5 @@ exports.useSize = useSize;
11759
12256
  exports.viVN = viVN;
11760
12257
  exports.zhCN = zhCN;
11761
12258
  exports.zhTW = zhTW;
11762
- //# sourceMappingURL=chunk-T7O3RMWL.cjs.map
11763
- //# sourceMappingURL=chunk-T7O3RMWL.cjs.map
12259
+ //# sourceMappingURL=chunk-XLK6BYW3.cjs.map
12260
+ //# sourceMappingURL=chunk-XLK6BYW3.cjs.map