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.
@@ -3342,6 +3342,170 @@ var DiffViewer = forwardRef(function DiffViewer2({
3342
3342
  );
3343
3343
  });
3344
3344
  DiffViewer.displayName = "DiffViewer";
3345
+ var Kanban = forwardRef(function Kanban2({ columns = [], onMove, onCardClick, renderCard, columnFooter, columnWidth = 280, className, style, ...props }, ref) {
3346
+ const [drag, setDrag] = useState(null);
3347
+ const [overColumn, setOverColumn] = useState(null);
3348
+ const handleDrop = (column, index) => {
3349
+ if (drag && (drag.fromColumn !== column.id || index !== index)) {
3350
+ onMove?.(drag.cardId, drag.fromColumn, column.id, index);
3351
+ }
3352
+ setDrag(null);
3353
+ setOverColumn(null);
3354
+ };
3355
+ return /* @__PURE__ */ jsx(
3356
+ "div",
3357
+ {
3358
+ ref,
3359
+ className: cx("klun-kanban", className),
3360
+ style: { ...style, ["--klun-kanban-col"]: `${columnWidth}px` },
3361
+ ...props,
3362
+ children: columns.map((column) => {
3363
+ const over = overColumn === column.id && drag;
3364
+ const full = column.limit !== void 0 && column.cards.length >= column.limit;
3365
+ return /* @__PURE__ */ jsxs("section", { className: cx("klun-kanban__column", over && "klun-kanban__column--over"), children: [
3366
+ /* @__PURE__ */ jsxs("header", { className: "klun-kanban__header", children: [
3367
+ column.accent ? /* @__PURE__ */ jsx("span", { className: "klun-kanban__dot", style: { background: column.accent } }) : null,
3368
+ /* @__PURE__ */ jsx("span", { className: "klun-kanban__title", children: column.title }),
3369
+ /* @__PURE__ */ jsxs("span", { className: cx("klun-kanban__count", full && "klun-kanban__count--full"), children: [
3370
+ column.cards.length,
3371
+ column.limit !== void 0 ? ` / ${column.limit}` : ""
3372
+ ] })
3373
+ ] }),
3374
+ /* @__PURE__ */ jsxs(
3375
+ "div",
3376
+ {
3377
+ className: "klun-kanban__list",
3378
+ onDragOver: (e) => {
3379
+ if (!drag) return;
3380
+ e.preventDefault();
3381
+ setOverColumn(column.id);
3382
+ },
3383
+ onDrop: (e) => {
3384
+ e.preventDefault();
3385
+ handleDrop(column, column.cards.length);
3386
+ },
3387
+ children: [
3388
+ column.cards.map((card, index) => /* @__PURE__ */ jsx(
3389
+ "article",
3390
+ {
3391
+ draggable: true,
3392
+ onDragStart: (e) => {
3393
+ e.dataTransfer.effectAllowed = "move";
3394
+ e.dataTransfer.setData("text/plain", card.id);
3395
+ setDrag({ cardId: card.id, fromColumn: column.id });
3396
+ },
3397
+ onDragEnd: () => {
3398
+ setDrag(null);
3399
+ setOverColumn(null);
3400
+ },
3401
+ onDragOver: (e) => {
3402
+ if (!drag) return;
3403
+ e.preventDefault();
3404
+ e.stopPropagation();
3405
+ const rect = e.currentTarget.getBoundingClientRect();
3406
+ const after = e.clientY - rect.top > rect.height / 2;
3407
+ setOverColumn(column.id);
3408
+ setDrag((d) => d ? { ...d, overColumn: column.id, overIndex: index + (after ? 1 : 0) } : d);
3409
+ },
3410
+ onDrop: (e) => {
3411
+ e.preventDefault();
3412
+ e.stopPropagation();
3413
+ handleDrop(column, index);
3414
+ },
3415
+ onClick: () => onCardClick?.(card, column.id),
3416
+ className: cx(
3417
+ "klun-kanban__card",
3418
+ drag?.cardId === card.id && "klun-kanban__card--dragging",
3419
+ over && drag?.overIndex === index && "klun-kanban__card--dropbefore",
3420
+ over && drag?.overIndex === index + 1 && "klun-kanban__card--dropafter"
3421
+ ),
3422
+ style: card.accent ? { boxShadow: `inset 3px 0 0 ${card.accent}` } : void 0,
3423
+ children: renderCard ? renderCard(card, column.id) : /* @__PURE__ */ jsxs(Fragment, { children: [
3424
+ /* @__PURE__ */ jsx("div", { className: "klun-kanban__card-title", children: card.title }),
3425
+ card.description ? /* @__PURE__ */ jsx("div", { className: "klun-kanban__card-desc", children: card.description }) : null,
3426
+ card.tags?.length ? /* @__PURE__ */ jsx("div", { className: "klun-kanban__card-tags", children: card.tags.map((t, i) => /* @__PURE__ */ jsx("span", { children: t }, i)) }) : null,
3427
+ card.meta ? /* @__PURE__ */ jsx("div", { className: "klun-kanban__card-meta", children: card.meta }) : null
3428
+ ] })
3429
+ },
3430
+ card.id
3431
+ )),
3432
+ column.cards.length === 0 ? /* @__PURE__ */ jsx("div", { className: "klun-kanban__empty", children: "Drop a card here" }) : null
3433
+ ]
3434
+ }
3435
+ ),
3436
+ columnFooter ? /* @__PURE__ */ jsx("div", { className: "klun-kanban__footer", children: columnFooter(column) }) : null
3437
+ ] }, column.id);
3438
+ })
3439
+ }
3440
+ );
3441
+ });
3442
+ Kanban.displayName = "Kanban";
3443
+ function VirtualTable({
3444
+ rows = [],
3445
+ columns = [],
3446
+ rowHeight = 40,
3447
+ height = 420,
3448
+ getRowId,
3449
+ onRowClick,
3450
+ overscan = 8,
3451
+ zebra = true,
3452
+ empty,
3453
+ className,
3454
+ style,
3455
+ ...props
3456
+ }) {
3457
+ const [scrollTop, setScrollTop] = useState(0);
3458
+ const total = rows.length;
3459
+ const template = useMemo(
3460
+ () => columns.map((c) => c.width ? `${c.width}px` : "minmax(0, 1fr)").join(" "),
3461
+ [columns]
3462
+ );
3463
+ const bodyHeight = Math.max(0, height - 36);
3464
+ const start = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
3465
+ const end = Math.min(total, Math.ceil((scrollTop + bodyHeight) / rowHeight) + overscan);
3466
+ const slice = rows.slice(start, end);
3467
+ return /* @__PURE__ */ jsxs("div", { ref: void 0, className: cx("klun-vtable", className), style: { ...style, height }, ...props, children: [
3468
+ /* @__PURE__ */ jsx("div", { className: "klun-vtable__head", style: { gridTemplateColumns: template }, children: columns.map((c) => /* @__PURE__ */ jsx("div", { className: cx("klun-vtable__th", c.align && `klun-vtable__th--${c.align}`), children: c.header }, c.key)) }),
3469
+ /* @__PURE__ */ jsx(
3470
+ "div",
3471
+ {
3472
+ className: "klun-vtable__body",
3473
+ onScroll: (e) => setScrollTop(e.target.scrollTop),
3474
+ style: { maxHeight: bodyHeight },
3475
+ children: total === 0 ? /* @__PURE__ */ jsx("div", { className: "klun-vtable__empty", children: empty ?? "No rows" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3476
+ /* @__PURE__ */ jsx("div", { style: { height: start * rowHeight } }),
3477
+ slice.map((row, i) => {
3478
+ const index = start + i;
3479
+ const id = getRowId?.(row, index) ?? index;
3480
+ return /* @__PURE__ */ jsx(
3481
+ "div",
3482
+ {
3483
+ role: onRowClick ? "button" : void 0,
3484
+ tabIndex: onRowClick ? 0 : void 0,
3485
+ onClick: () => onRowClick?.(row, index),
3486
+ className: cx(
3487
+ "klun-vtable__row",
3488
+ zebra && index % 2 === 1 && "klun-vtable__row--zebra",
3489
+ onRowClick && "klun-vtable__row--clickable"
3490
+ ),
3491
+ style: { gridTemplateColumns: template, height: rowHeight },
3492
+ children: columns.map((c) => /* @__PURE__ */ jsx("div", { className: cx("klun-vtable__td", c.align && `klun-vtable__td--${c.align}`), children: c.render ? c.render(row, index) : String(row[c.key] ?? "") }, c.key))
3493
+ },
3494
+ id
3495
+ );
3496
+ }),
3497
+ /* @__PURE__ */ jsx("div", { style: { height: Math.max(0, (total - end) * rowHeight) } })
3498
+ ] })
3499
+ }
3500
+ ),
3501
+ /* @__PURE__ */ jsxs("div", { className: "klun-vtable__foot", children: [
3502
+ total.toLocaleString("en-US"),
3503
+ " rows \xB7 rendering ",
3504
+ slice.length
3505
+ ] })
3506
+ ] });
3507
+ }
3508
+ VirtualTable.displayName = "VirtualTable";
3345
3509
  var Kbd = forwardRef(function Kbd2({ className, children, ...props }, ref) {
3346
3510
  return /* @__PURE__ */ jsx("kbd", { ref, className: cx("klun-kbd", className), ...props, children });
3347
3511
  });
@@ -6539,25 +6703,30 @@ var AutoComplete = forwardRef(
6539
6703
  AutoComplete.displayName = "AutoComplete";
6540
6704
  var Cascader = forwardRef(function Cascader2({
6541
6705
  options = [],
6542
- value = [],
6706
+ value,
6707
+ defaultValue,
6543
6708
  onChange,
6544
6709
  placeholder: placeholderProp,
6545
6710
  size: sizeProp,
6546
6711
  disabled = false,
6547
6712
  separator = " / ",
6548
6713
  changeOnSelect = false,
6714
+ clearable = false,
6715
+ renderOption,
6549
6716
  error = false,
6550
6717
  className,
6551
6718
  ...props
6552
6719
  }, ref) {
6553
6720
  const size = useSize(sizeProp);
6554
- const { cascader } = useLocale();
6721
+ const { cascader, input: inputText } = useLocale();
6555
6722
  const placeholder = placeholderProp ?? cascader.placeholder;
6723
+ const [inner, setInner] = useState(defaultValue ?? []);
6724
+ const current = value ?? inner;
6556
6725
  const [open, setOpen] = useState(false);
6557
- const [active, setActive] = useState(value);
6726
+ const [active, setActive] = useState(current);
6558
6727
  const rootRef = useRef(null);
6559
6728
  useEffect(() => {
6560
- setActive(value);
6729
+ setActive(current);
6561
6730
  }, [open]);
6562
6731
  useEffect(() => {
6563
6732
  if (!open) return;
@@ -6586,7 +6755,7 @@ var Cascader = forwardRef(function Cascader2({
6586
6755
  }
6587
6756
  const labelPath = [];
6588
6757
  let lvl = options;
6589
- for (const key of value) {
6758
+ for (const key of current) {
6590
6759
  const found = (lvl || []).find((o) => o.value === key);
6591
6760
  if (!found) break;
6592
6761
  labelPath.push(found.label);
@@ -6598,10 +6767,16 @@ var Cascader = forwardRef(function Cascader2({
6598
6767
  setActive(nextPath);
6599
6768
  const leaf = !opt.children || !opt.children.length;
6600
6769
  if (leaf || changeOnSelect) {
6770
+ if (value === void 0) setInner(nextPath);
6601
6771
  onChange && onChange(nextPath);
6602
6772
  if (leaf) setOpen(false);
6603
6773
  }
6604
6774
  };
6775
+ const clear = () => {
6776
+ if (value === void 0) setInner([]);
6777
+ setActive([]);
6778
+ onChange && onChange([]);
6779
+ };
6605
6780
  const setRefs = (node) => {
6606
6781
  rootRef.current = node;
6607
6782
  if (typeof ref === "function") ref(node);
@@ -6631,6 +6806,20 @@ var Cascader = forwardRef(function Cascader2({
6631
6806
  i > 0 ? /* @__PURE__ */ jsx("span", { className: "klun-cascader__separator", children: separator }) : null,
6632
6807
  lbl
6633
6808
  ] }, i)) : placeholder }),
6809
+ clearable && labelPath.length && !disabled ? /* @__PURE__ */ jsx(
6810
+ "span",
6811
+ {
6812
+ role: "button",
6813
+ tabIndex: -1,
6814
+ "aria-label": inputText.clear,
6815
+ className: "klun-cascader__clear",
6816
+ onClick: (e) => {
6817
+ e.stopPropagation();
6818
+ clear();
6819
+ },
6820
+ children: /* @__PURE__ */ jsx("i", { className: "ri-close-circle-fill" })
6821
+ }
6822
+ ) : null,
6634
6823
  /* @__PURE__ */ jsx(
6635
6824
  "svg",
6636
6825
  {
@@ -6655,7 +6844,7 @@ var Cascader = forwardRef(function Cascader2({
6655
6844
  ]
6656
6845
  }
6657
6846
  ),
6658
- open ? /* @__PURE__ */ jsx("div", { className: "klun-cascader__panel", children: columns.map((col, ci) => /* @__PURE__ */ jsx(
6847
+ open ? /* @__PURE__ */ jsx("div", { className: "klun-cascader__panel", role: "menu", children: columns.map((col, ci) => /* @__PURE__ */ jsx(
6659
6848
  "div",
6660
6849
  {
6661
6850
  className: cx(
@@ -6669,12 +6858,14 @@ var Cascader = forwardRef(function Cascader2({
6669
6858
  "button",
6670
6859
  {
6671
6860
  type: "button",
6861
+ role: "menuitem",
6672
6862
  className: "klun-cascader__option",
6673
6863
  disabled: opt.disabled,
6674
6864
  onClick: () => pick(ci, opt),
6865
+ "aria-selected": selected,
6675
6866
  "data-selected": selected || void 0,
6676
6867
  children: [
6677
- /* @__PURE__ */ jsx("span", { className: "klun-cascader__option-label", children: opt.label }),
6868
+ /* @__PURE__ */ jsx("span", { className: "klun-cascader__option-label", children: renderOption ? renderOption(opt, ci) : opt.label }),
6678
6869
  hasChildren2 ? /* @__PURE__ */ jsx("i", { className: "ri-arrow-right-s-line klun-cascader__option-arrow" }) : selected ? /* @__PURE__ */ jsx("i", { className: "ri-check-line klun-cascader__option-check" }) : null
6679
6870
  ]
6680
6871
  },
@@ -7470,6 +7661,149 @@ var CompactSelectForInput = forwardRef(function CompactSelectForInput2({
7470
7661
  );
7471
7662
  });
7472
7663
  CompactSelectForInput.displayName = "CompactSelectForInput";
7664
+ var CRON_PRESETS = [
7665
+ { label: "Every 5 minutes", value: "*/5 * * * *" },
7666
+ { label: "Every 15 minutes", value: "*/15 * * * *" },
7667
+ { label: "Hourly", value: "0 * * * *" },
7668
+ { label: "Every day at 03:00", value: "0 3 * * *" },
7669
+ { label: "Weekdays at 09:00", value: "0 9 * * 1-5" },
7670
+ { label: "Mondays at 09:00", value: "0 9 * * 1" },
7671
+ { label: "1st of the month", value: "0 6 1 * *" }
7672
+ ];
7673
+ var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
7674
+ var DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
7675
+ var pad = (n) => n.padStart(2, "0");
7676
+ function describeCron(cron) {
7677
+ const parts = cron.trim().split(/\s+/);
7678
+ if (parts.length !== 5) return cron;
7679
+ const [min, hour, day, month, week] = parts;
7680
+ const everyMin = min.startsWith("*/") ? `every ${min.slice(2)} minutes` : min === "*" ? "every minute" : null;
7681
+ const at = hour === "*" ? "" : ` at ${pad(hour)}:${pad(min)}`;
7682
+ 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`;
7683
+ if (everyMin) return `${everyMin.charAt(0).toUpperCase()}${everyMin.slice(1)}${at}`;
7684
+ if (min !== "*" && hour !== "*" && day === "*" && week === "*") {
7685
+ return `${month === "*" ? "Every day" : `On day ${day} of month ${MONTHS[Number(month) - 1] ?? month}`}${at}`;
7686
+ }
7687
+ return `${dayPart.charAt(0).toUpperCase()}${dayPart.slice(1)}${at}`;
7688
+ }
7689
+ function parse(cron) {
7690
+ const p = cron.trim().split(/\s+/);
7691
+ return [p[0] ?? "*", p[1] ?? "*", p[2] ?? "*", p[3] ?? "*", p[4] ?? "*"];
7692
+ }
7693
+ var CronEditor = forwardRef(function CronEditor2({
7694
+ value,
7695
+ defaultValue = "0 3 * * *",
7696
+ onChange,
7697
+ hidePresets = false,
7698
+ disabled = false,
7699
+ size: sizeProp,
7700
+ labels,
7701
+ className,
7702
+ style,
7703
+ ...props
7704
+ }, ref) {
7705
+ const size = useSize(sizeProp) === "small" ? "small" : "medium";
7706
+ const text = {
7707
+ minute: "Minute",
7708
+ hour: "Hour",
7709
+ day: "Day",
7710
+ month: "Month",
7711
+ weekday: "Weekday",
7712
+ every: "Every",
7713
+ expression: "Expression",
7714
+ ...labels
7715
+ };
7716
+ const [inner, setInner] = useState(defaultValue);
7717
+ const current = value ?? inner;
7718
+ const [fields, setFields] = useState(parse(current));
7719
+ useEffect(() => {
7720
+ setFields(parse(current));
7721
+ }, [current]);
7722
+ const commit = (next) => {
7723
+ if (value === void 0) setInner(next);
7724
+ onChange?.(next);
7725
+ };
7726
+ const setField = (index, next) => {
7727
+ const copy = [...fields];
7728
+ copy[index] = next;
7729
+ setFields(copy);
7730
+ commit(copy.join(" "));
7731
+ };
7732
+ const options = useMemo(
7733
+ () => ({
7734
+ minute: ["*", "*/5", "*/10", "*/15", "*/30", "0", "15", "30", "45"],
7735
+ hour: ["*", ...Array.from({ length: 24 }, (_, i) => String(i))],
7736
+ day: ["*", ...Array.from({ length: 31 }, (_, i) => String(i + 1))],
7737
+ month: ["*", ...Array.from({ length: 12 }, (_, i) => String(i + 1))],
7738
+ weekday: ["*", "1-5", "0", "1", "2", "3", "4", "5", "6"]
7739
+ }),
7740
+ []
7741
+ );
7742
+ const fieldLabel = (key, v) => {
7743
+ if (v === "*") return text.every;
7744
+ if (key === "month") return MONTHS[Number(v) - 1] ?? v;
7745
+ if (key === "weekday") return v.includes("-") ? "Mon\u2013Fri" : DAYS[Number(v)] ?? v;
7746
+ if (key === "hour") return `${pad(v)}:00`;
7747
+ return v;
7748
+ };
7749
+ const desc = describeCron(current);
7750
+ return /* @__PURE__ */ jsxs(
7751
+ "div",
7752
+ {
7753
+ ref,
7754
+ className: cx("klun-cron", `klun-cron--${size}`, disabled && "klun-cron--disabled", className),
7755
+ style,
7756
+ ...props,
7757
+ children: [
7758
+ !hidePresets ? /* @__PURE__ */ jsx("div", { className: "klun-cron__presets", children: CRON_PRESETS.map((p) => /* @__PURE__ */ jsx(
7759
+ "button",
7760
+ {
7761
+ type: "button",
7762
+ disabled,
7763
+ onClick: () => commit(p.value),
7764
+ "data-active": current === p.value || void 0,
7765
+ className: "klun-cron__preset",
7766
+ children: p.label
7767
+ },
7768
+ p.value
7769
+ )) }) : null,
7770
+ /* @__PURE__ */ jsx("div", { className: "klun-cron__fields", children: ["minute", "hour", "day", "month", "weekday"].map((key, i) => /* @__PURE__ */ jsxs("label", { className: "klun-cron__field", children: [
7771
+ /* @__PURE__ */ jsx("span", { className: "klun-cron__field-label", children: text[key] }),
7772
+ /* @__PURE__ */ jsx(
7773
+ "select",
7774
+ {
7775
+ disabled,
7776
+ value: fields[i],
7777
+ onChange: (e) => setField(i, e.target.value),
7778
+ className: "klun-cron__select",
7779
+ children: options[key].map((v) => /* @__PURE__ */ jsx("option", { value: v, children: fieldLabel(key, v) }, v))
7780
+ }
7781
+ )
7782
+ ] }, key)) }),
7783
+ /* @__PURE__ */ jsxs("div", { className: "klun-cron__footer", children: [
7784
+ /* @__PURE__ */ jsxs("label", { className: "klun-cron__raw", children: [
7785
+ /* @__PURE__ */ jsx("span", { className: "klun-cron__field-label", children: text.expression }),
7786
+ /* @__PURE__ */ jsx(
7787
+ "input",
7788
+ {
7789
+ disabled,
7790
+ value: current,
7791
+ onChange: (e) => commit(e.target.value),
7792
+ spellCheck: false,
7793
+ className: "klun-cron__input"
7794
+ }
7795
+ )
7796
+ ] }),
7797
+ /* @__PURE__ */ jsxs("div", { className: "klun-cron__preview", children: [
7798
+ /* @__PURE__ */ jsx("i", { className: "ri-time-line" }),
7799
+ desc
7800
+ ] })
7801
+ ] })
7802
+ ]
7803
+ }
7804
+ );
7805
+ });
7806
+ CronEditor.displayName = "CronEditor";
7473
7807
  var CounterInput = forwardRef(function CounterInput2({
7474
7808
  value = 0,
7475
7809
  min = -Infinity,
@@ -7899,7 +8233,7 @@ var DateRangePicker = forwardRef(
7899
8233
  }
7900
8234
  );
7901
8235
  DateRangePicker.displayName = "DateRangePicker";
7902
- var pad = (n) => String(n).padStart(2, "0");
8236
+ var pad2 = (n) => String(n).padStart(2, "0");
7903
8237
  var TimePicker = forwardRef(
7904
8238
  function TimePicker2({ value = "09:00", onChange, className, style, ...props }, ref) {
7905
8239
  const t = useLocale();
@@ -7909,7 +8243,7 @@ var TimePicker = forwardRef(
7909
8243
  const set = (nh, nm, nmer) => {
7910
8244
  let hh = nh % 12;
7911
8245
  if (nmer === "PM") hh += 12;
7912
- onChange?.(`${pad(hh)}:${pad(nm)}`);
8246
+ onChange?.(`${pad2(hh)}:${pad2(nm)}`);
7913
8247
  };
7914
8248
  const [open, setOpen] = useState(null);
7915
8249
  const rootRef = useRef(null);
@@ -7928,11 +8262,11 @@ var TimePicker = forwardRef(
7928
8262
  }, [open]);
7929
8263
  const hourOpts = Array.from({ length: 12 }, (_, i) => ({
7930
8264
  value: String(i + 1),
7931
- label: pad(i + 1)
8265
+ label: pad2(i + 1)
7932
8266
  }));
7933
8267
  const minOpts = Array.from({ length: 60 }, (_, i) => ({
7934
8268
  value: String(i),
7935
- label: pad(i)
8269
+ label: pad2(i)
7936
8270
  }));
7937
8271
  const merOpts = [
7938
8272
  { value: "AM", label: t.timePicker.am },
@@ -8099,7 +8433,7 @@ function TimeColumn({
8099
8433
  ] });
8100
8434
  }
8101
8435
  TimePicker.displayName = "TimePicker";
8102
- var pad2 = (n) => String(n).padStart(2, "0");
8436
+ var pad3 = (n) => String(n).padStart(2, "0");
8103
8437
  var DEFAULT_FORMAT3 = {
8104
8438
  year: "numeric",
8105
8439
  month: "short",
@@ -8108,7 +8442,7 @@ var DEFAULT_FORMAT3 = {
8108
8442
  minute: "2-digit"
8109
8443
  };
8110
8444
  function DateTimePanel({ value, onChange }) {
8111
- const hhmm = value ? `${pad2(value.getHours())}:${pad2(value.getMinutes())}` : "09:00";
8445
+ const hhmm = value ? `${pad3(value.getHours())}:${pad3(value.getMinutes())}` : "09:00";
8112
8446
  const setDate = (d) => {
8113
8447
  const next = new Date(d);
8114
8448
  if (value) next.setHours(value.getHours(), value.getMinutes(), 0, 0);
@@ -9091,6 +9425,192 @@ var RichEditorToolbar = forwardRef(
9091
9425
  }
9092
9426
  );
9093
9427
  RichEditorToolbar.displayName = "RichEditorToolbar";
9428
+ var Textarea = forwardRef(function Textarea2({ error = false, disabled = false, readOnly = false, size: sizeProp, rows = 4, className, style, ...props }, ref) {
9429
+ const size = useSize(sizeProp);
9430
+ return /* @__PURE__ */ jsx(
9431
+ "div",
9432
+ {
9433
+ className: cx(
9434
+ "klun-textarea",
9435
+ `klun-textarea--${size}`,
9436
+ error && "klun-textarea--error",
9437
+ disabled && "klun-textarea--disabled",
9438
+ readOnly && "klun-textarea--readonly",
9439
+ className
9440
+ ),
9441
+ style,
9442
+ children: /* @__PURE__ */ jsx(
9443
+ "textarea",
9444
+ {
9445
+ ref,
9446
+ className: "klun-textarea__field",
9447
+ rows,
9448
+ disabled,
9449
+ readOnly,
9450
+ ...props
9451
+ }
9452
+ )
9453
+ }
9454
+ );
9455
+ });
9456
+ Textarea.displayName = "Textarea";
9457
+ function runCommand(id) {
9458
+ const exec = (cmd, arg) => document.execCommand(cmd, false, arg);
9459
+ if (typeof document.execCommand !== "function") return;
9460
+ switch (id) {
9461
+ case "bold":
9462
+ case "italic":
9463
+ case "underline":
9464
+ case "strikeThrough":
9465
+ exec(id);
9466
+ break;
9467
+ case "strike":
9468
+ exec("strikeThrough");
9469
+ break;
9470
+ case "h1":
9471
+ exec("formatBlock", "<h1>");
9472
+ break;
9473
+ case "h2":
9474
+ exec("formatBlock", "<h2>");
9475
+ break;
9476
+ case "quote":
9477
+ exec("formatBlock", "<blockquote>");
9478
+ break;
9479
+ case "code":
9480
+ exec("formatBlock", "<pre>");
9481
+ break;
9482
+ case "ul":
9483
+ exec("insertUnorderedList");
9484
+ break;
9485
+ case "ol":
9486
+ exec("insertOrderedList");
9487
+ break;
9488
+ case "link": {
9489
+ const url = typeof window !== "undefined" ? window.prompt("Link URL", "https://") : null;
9490
+ if (url) exec("createLink", url);
9491
+ break;
9492
+ }
9493
+ case "image": {
9494
+ const url = typeof window !== "undefined" ? window.prompt("Image URL", "https://") : null;
9495
+ if (url) exec("insertImage", url);
9496
+ break;
9497
+ }
9498
+ }
9499
+ }
9500
+ var RichEditor = forwardRef(function RichEditor2({
9501
+ value,
9502
+ defaultValue = "",
9503
+ onChange,
9504
+ placeholder = "Write something\u2026",
9505
+ disabled = false,
9506
+ hideToolbar = false,
9507
+ minHeight = 160,
9508
+ maxHeight,
9509
+ allowSource = true,
9510
+ editorLabel = "Rich text editor",
9511
+ className,
9512
+ style,
9513
+ ...props
9514
+ }, ref) {
9515
+ const editorRef = useRef(null);
9516
+ const [active, setActive] = useState([]);
9517
+ const [source, setSource] = useState(false);
9518
+ const [html, setHtml] = useState(value ?? defaultValue);
9519
+ useEffect(() => {
9520
+ const el = editorRef.current;
9521
+ if (!el) return;
9522
+ const next = value ?? html;
9523
+ if (document.activeElement !== el && el.innerHTML !== next) el.innerHTML = next;
9524
+ }, [value]);
9525
+ useEffect(() => {
9526
+ if (disabled || typeof document.execCommand !== "function") return;
9527
+ document.execCommand("defaultParagraphSeparator", false, "p");
9528
+ }, [disabled]);
9529
+ const emit2 = () => {
9530
+ const next = editorRef.current?.innerHTML ?? "";
9531
+ setHtml(next);
9532
+ onChange?.(next);
9533
+ };
9534
+ const syncActive = () => {
9535
+ if (typeof document.queryCommandState !== "function") return;
9536
+ const next = [];
9537
+ ["bold", "italic", "underline"].forEach((c) => {
9538
+ if (document.queryCommandState(c)) next.push(c);
9539
+ });
9540
+ setActive(next);
9541
+ };
9542
+ const onAction = (id) => {
9543
+ if (disabled) return;
9544
+ editorRef.current?.focus();
9545
+ runCommand(id);
9546
+ emit2();
9547
+ syncActive();
9548
+ };
9549
+ const setRefs = (node) => {
9550
+ editorRef.current = node;
9551
+ if (typeof ref === "function") ref(node);
9552
+ else if (ref) ref.current = node;
9553
+ };
9554
+ return /* @__PURE__ */ jsxs(
9555
+ "div",
9556
+ {
9557
+ className: cx("klun-rich-editor", disabled && "klun-rich-editor--disabled", className),
9558
+ style,
9559
+ ...props,
9560
+ children: [
9561
+ !hideToolbar ? /* @__PURE__ */ jsxs("div", { className: "klun-rich-editor__bar", children: [
9562
+ /* @__PURE__ */ jsx(RichEditorToolbar, { active, onAction }),
9563
+ allowSource ? /* @__PURE__ */ jsxs(
9564
+ "button",
9565
+ {
9566
+ type: "button",
9567
+ className: "klun-rich-editor__source",
9568
+ onClick: () => setSource((s) => !s),
9569
+ "data-active": source || void 0,
9570
+ "aria-pressed": source,
9571
+ children: [
9572
+ /* @__PURE__ */ jsx("i", { className: "ri-code-s-slash-line" }),
9573
+ "HTML"
9574
+ ]
9575
+ }
9576
+ ) : null
9577
+ ] }) : null,
9578
+ source && allowSource ? /* @__PURE__ */ jsx("div", { className: "klun-rich-editor__sourcearea", children: /* @__PURE__ */ jsx(
9579
+ Textarea,
9580
+ {
9581
+ rows: Math.max(4, Math.round(minHeight / 22)),
9582
+ value: html,
9583
+ style: { border: "none", boxShadow: "none", fontFamily: "var(--klun-font-mono, monospace)" },
9584
+ onChange: (e) => {
9585
+ setHtml(e.target.value);
9586
+ onChange?.(e.target.value);
9587
+ if (editorRef.current) editorRef.current.innerHTML = e.target.value;
9588
+ }
9589
+ }
9590
+ ) }) : null,
9591
+ /* @__PURE__ */ jsx(
9592
+ "div",
9593
+ {
9594
+ ref: setRefs,
9595
+ role: "textbox",
9596
+ "aria-multiline": "true",
9597
+ "aria-label": editorLabel,
9598
+ contentEditable: !disabled,
9599
+ suppressContentEditableWarning: true,
9600
+ "data-placeholder": placeholder,
9601
+ className: "klun-rich-editor__area",
9602
+ style: { minHeight, maxHeight, overflowY: maxHeight ? "auto" : void 0 },
9603
+ onInput: emit2,
9604
+ onBlur: emit2,
9605
+ onKeyUp: syncActive,
9606
+ onMouseUp: syncActive
9607
+ }
9608
+ )
9609
+ ]
9610
+ }
9611
+ );
9612
+ });
9613
+ RichEditor.displayName = "RichEditor";
9094
9614
  var Select = forwardRef(function Select2({
9095
9615
  size: sizeProp,
9096
9616
  placeholder,
@@ -9370,35 +9890,6 @@ var Switch = forwardRef(function Switch2({ disabled = false, size: sizeProp, onC
9370
9890
  );
9371
9891
  });
9372
9892
  Switch.displayName = "Switch";
9373
- var Textarea = forwardRef(function Textarea2({ error = false, disabled = false, readOnly = false, size: sizeProp, rows = 4, className, style, ...props }, ref) {
9374
- const size = useSize(sizeProp);
9375
- return /* @__PURE__ */ jsx(
9376
- "div",
9377
- {
9378
- className: cx(
9379
- "klun-textarea",
9380
- `klun-textarea--${size}`,
9381
- error && "klun-textarea--error",
9382
- disabled && "klun-textarea--disabled",
9383
- readOnly && "klun-textarea--readonly",
9384
- className
9385
- ),
9386
- style,
9387
- children: /* @__PURE__ */ jsx(
9388
- "textarea",
9389
- {
9390
- ref,
9391
- className: "klun-textarea__field",
9392
- rows,
9393
- disabled,
9394
- readOnly,
9395
- ...props
9396
- }
9397
- )
9398
- }
9399
- );
9400
- });
9401
- Textarea.displayName = "Textarea";
9402
9893
  var Card = forwardRef(function Card2({ variant = "stroke", padding, className, style, children, ...props }, ref) {
9403
9894
  return /* @__PURE__ */ jsx(
9404
9895
  "div",
@@ -11600,6 +12091,6 @@ var Popconfirm = forwardRef(function Popconfirm2({
11600
12091
  });
11601
12092
  Popconfirm.displayName = "Popconfirm";
11602
12093
 
11603
- export { Accordion, Alert, AutoComplete, Avatar, AvatarGroup, Badge, Banner, Breadcrumb, BulkAction, BulkActionBar, Button, ButtonGroup, Card, Carousel, Cascader, CharacterCounter, ChartLegend, ChartTooltip, Checkbox, CheckboxCard, CheckboxGroup, Chip, CircularProgress, CodeViewer, Col, Collapse, ColorDot, ColorPicker, ColorSlider, CommandMenu, CompactSelect, CompactSelectForInput, ConfigProvider, Confirm, ContentLabel, ContextMenu2 as ContextMenu, CopyButton, CounterInput, CrossRefBadge, DatePicker, DateRangePicker, DateTimePicker, Descriptions, DiffViewer, DigitInput, Divider, Drawer, Dropdown, EmptyState, ExpiryCountdown, FileUpload, Flex, Form, FormItem, FormList, Format, GaugeBar, Grid, Hint, HorizontalFilter, ImageUpload, ImageViewer, InlineInput, InlineSelect, Input, Kbd, KeyIcon, Label, Layout, LayoutContent, LayoutFooter, LayoutHeader, LayoutSider, List, ListItem, LiveDot, LogViewer, Markdown, Masonry, Menu, Message, Modal, Money, Notification, PageHeader, Pagination, PasswordStrength, Popconfirm, Popover, ProgressBar, Radio, RadioCard, RangeSlider, Rating, RelativeTime, Result, RichEditorToolbar, Row, SegmentedControl, SegmentedProgress, Select, SelectMenu, Skeleton, Slider, Space, Spinner2 as Spinner, Splitter2 as Splitter, SplitterPanel, StatCard, Statistic, StatusBadge, StatusDot, StepIndicator, Switch, Table, Tabs, Tag, Textarea, TimePicker, Timeline, Toast, Toaster, Tooltip, Tree, Wizard, arSA, deDE, enUS, esES, fmt, frFR, idID, itIT, jaJP, koKR, locales, nlNL, parsePatch, plPL, primaryColorVars, ptBR, renderMarkdown, ruRU, toast, trTR, useBreakpoint, useConfig, useContextMenu, useForm, useLocale, useMappedSize, useMessage, useNotification, useSize, viVN, zhCN, zhTW };
11604
- //# sourceMappingURL=chunk-UJOMGMCV.js.map
11605
- //# sourceMappingURL=chunk-UJOMGMCV.js.map
12094
+ export { Accordion, Alert, AutoComplete, Avatar, AvatarGroup, Badge, Banner, Breadcrumb, BulkAction, BulkActionBar, Button, ButtonGroup, CRON_PRESETS, Card, Carousel, Cascader, CharacterCounter, ChartLegend, ChartTooltip, Checkbox, CheckboxCard, CheckboxGroup, Chip, CircularProgress, CodeViewer, Col, Collapse, ColorDot, ColorPicker, ColorSlider, CommandMenu, CompactSelect, CompactSelectForInput, ConfigProvider, Confirm, ContentLabel, ContextMenu2 as ContextMenu, CopyButton, CounterInput, CronEditor, CrossRefBadge, DatePicker, DateRangePicker, DateTimePicker, Descriptions, DiffViewer, DigitInput, Divider, Drawer, Dropdown, EmptyState, ExpiryCountdown, FileUpload, Flex, Form, FormItem, FormList, Format, GaugeBar, Grid, Hint, HorizontalFilter, ImageUpload, ImageViewer, InlineInput, InlineSelect, Input, Kanban, Kbd, KeyIcon, Label, Layout, LayoutContent, LayoutFooter, LayoutHeader, LayoutSider, List, ListItem, LiveDot, LogViewer, Markdown, Masonry, Menu, Message, Modal, Money, Notification, PageHeader, Pagination, PasswordStrength, Popconfirm, Popover, ProgressBar, Radio, RadioCard, RangeSlider, Rating, RelativeTime, Result, RichEditor, RichEditorToolbar, Row, SegmentedControl, SegmentedProgress, Select, SelectMenu, Skeleton, Slider, Space, Spinner2 as Spinner, Splitter2 as Splitter, SplitterPanel, StatCard, Statistic, StatusBadge, StatusDot, StepIndicator, Switch, Table, Tabs, Tag, Textarea, TimePicker, Timeline, Toast, Toaster, Tooltip, Tree, VirtualTable, Wizard, arSA, deDE, describeCron, enUS, esES, fmt, frFR, idID, itIT, jaJP, koKR, locales, nlNL, parsePatch, plPL, primaryColorVars, ptBR, renderMarkdown, ruRU, toast, trTR, useBreakpoint, useConfig, useContextMenu, useForm, useLocale, useMappedSize, useMessage, useNotification, useSize, viVN, zhCN, zhTW };
12095
+ //# sourceMappingURL=chunk-TREMQLWT.js.map
12096
+ //# sourceMappingURL=chunk-TREMQLWT.js.map