klun-ui 0.3.0 → 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
  });
@@ -7497,6 +7661,149 @@ var CompactSelectForInput = forwardRef(function CompactSelectForInput2({
7497
7661
  );
7498
7662
  });
7499
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";
7500
7807
  var CounterInput = forwardRef(function CounterInput2({
7501
7808
  value = 0,
7502
7809
  min = -Infinity,
@@ -7926,7 +8233,7 @@ var DateRangePicker = forwardRef(
7926
8233
  }
7927
8234
  );
7928
8235
  DateRangePicker.displayName = "DateRangePicker";
7929
- var pad = (n) => String(n).padStart(2, "0");
8236
+ var pad2 = (n) => String(n).padStart(2, "0");
7930
8237
  var TimePicker = forwardRef(
7931
8238
  function TimePicker2({ value = "09:00", onChange, className, style, ...props }, ref) {
7932
8239
  const t = useLocale();
@@ -7936,7 +8243,7 @@ var TimePicker = forwardRef(
7936
8243
  const set = (nh, nm, nmer) => {
7937
8244
  let hh = nh % 12;
7938
8245
  if (nmer === "PM") hh += 12;
7939
- onChange?.(`${pad(hh)}:${pad(nm)}`);
8246
+ onChange?.(`${pad2(hh)}:${pad2(nm)}`);
7940
8247
  };
7941
8248
  const [open, setOpen] = useState(null);
7942
8249
  const rootRef = useRef(null);
@@ -7955,11 +8262,11 @@ var TimePicker = forwardRef(
7955
8262
  }, [open]);
7956
8263
  const hourOpts = Array.from({ length: 12 }, (_, i) => ({
7957
8264
  value: String(i + 1),
7958
- label: pad(i + 1)
8265
+ label: pad2(i + 1)
7959
8266
  }));
7960
8267
  const minOpts = Array.from({ length: 60 }, (_, i) => ({
7961
8268
  value: String(i),
7962
- label: pad(i)
8269
+ label: pad2(i)
7963
8270
  }));
7964
8271
  const merOpts = [
7965
8272
  { value: "AM", label: t.timePicker.am },
@@ -8126,7 +8433,7 @@ function TimeColumn({
8126
8433
  ] });
8127
8434
  }
8128
8435
  TimePicker.displayName = "TimePicker";
8129
- var pad2 = (n) => String(n).padStart(2, "0");
8436
+ var pad3 = (n) => String(n).padStart(2, "0");
8130
8437
  var DEFAULT_FORMAT3 = {
8131
8438
  year: "numeric",
8132
8439
  month: "short",
@@ -8135,7 +8442,7 @@ var DEFAULT_FORMAT3 = {
8135
8442
  minute: "2-digit"
8136
8443
  };
8137
8444
  function DateTimePanel({ value, onChange }) {
8138
- const hhmm = value ? `${pad2(value.getHours())}:${pad2(value.getMinutes())}` : "09:00";
8445
+ const hhmm = value ? `${pad3(value.getHours())}:${pad3(value.getMinutes())}` : "09:00";
8139
8446
  const setDate = (d) => {
8140
8447
  const next = new Date(d);
8141
8448
  if (value) next.setHours(value.getHours(), value.getMinutes(), 0, 0);
@@ -9118,6 +9425,192 @@ var RichEditorToolbar = forwardRef(
9118
9425
  }
9119
9426
  );
9120
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";
9121
9614
  var Select = forwardRef(function Select2({
9122
9615
  size: sizeProp,
9123
9616
  placeholder,
@@ -9397,35 +9890,6 @@ var Switch = forwardRef(function Switch2({ disabled = false, size: sizeProp, onC
9397
9890
  );
9398
9891
  });
9399
9892
  Switch.displayName = "Switch";
9400
- var Textarea = forwardRef(function Textarea2({ error = false, disabled = false, readOnly = false, size: sizeProp, rows = 4, className, style, ...props }, ref) {
9401
- const size = useSize(sizeProp);
9402
- return /* @__PURE__ */ jsx(
9403
- "div",
9404
- {
9405
- className: cx(
9406
- "klun-textarea",
9407
- `klun-textarea--${size}`,
9408
- error && "klun-textarea--error",
9409
- disabled && "klun-textarea--disabled",
9410
- readOnly && "klun-textarea--readonly",
9411
- className
9412
- ),
9413
- style,
9414
- children: /* @__PURE__ */ jsx(
9415
- "textarea",
9416
- {
9417
- ref,
9418
- className: "klun-textarea__field",
9419
- rows,
9420
- disabled,
9421
- readOnly,
9422
- ...props
9423
- }
9424
- )
9425
- }
9426
- );
9427
- });
9428
- Textarea.displayName = "Textarea";
9429
9893
  var Card = forwardRef(function Card2({ variant = "stroke", padding, className, style, children, ...props }, ref) {
9430
9894
  return /* @__PURE__ */ jsx(
9431
9895
  "div",
@@ -11627,6 +12091,6 @@ var Popconfirm = forwardRef(function Popconfirm2({
11627
12091
  });
11628
12092
  Popconfirm.displayName = "Popconfirm";
11629
12093
 
11630
- 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 };
11631
- //# sourceMappingURL=chunk-I4OHTBZQ.js.map
11632
- //# sourceMappingURL=chunk-I4OHTBZQ.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