@rufous/ui 0.3.21 → 0.3.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.cjs CHANGED
@@ -9088,6 +9088,14 @@ function getTopLevelSelected(nodes, selected) {
9088
9088
  }
9089
9089
  return result;
9090
9090
  }
9091
+ function getAllSelected(nodes, selected) {
9092
+ const result = [];
9093
+ for (const node of nodes) {
9094
+ if (selected.has(String(node.id))) result.push(node);
9095
+ if (node.children?.length) result.push(...getAllSelected(node.children, selected));
9096
+ }
9097
+ return result;
9098
+ }
9091
9099
  function filterTree(nodes, query) {
9092
9100
  if (!query) return nodes;
9093
9101
  const q = query.toLowerCase();
@@ -9116,6 +9124,7 @@ function TreeNodeItem({
9116
9124
  selected,
9117
9125
  expanded,
9118
9126
  selectionMode,
9127
+ allowChildSelection,
9119
9128
  onToggleExpand,
9120
9129
  onSelect,
9121
9130
  isFiltering
@@ -9123,7 +9132,7 @@ function TreeNodeItem({
9123
9132
  const nodeId = String(node.id);
9124
9133
  const hasChildren = !!node.children?.length;
9125
9134
  const isExpanded = isFiltering || expanded.has(nodeId);
9126
- const state = getNodeState(node, selected);
9135
+ const state = allowChildSelection ? getNodeState(node, selected) : selected.has(nodeId) ? "checked" : "unchecked";
9127
9136
  return /* @__PURE__ */ import_react49.default.createElement("div", { className: "rf-tsn" }, /* @__PURE__ */ import_react49.default.createElement(
9128
9137
  "div",
9129
9138
  {
@@ -9143,16 +9152,8 @@ function TreeNodeItem({
9143
9152
  },
9144
9153
  isExpanded ? /* @__PURE__ */ import_react49.default.createElement(import_lucide_react3.ChevronDown, { size: 14 }) : /* @__PURE__ */ import_react49.default.createElement(import_lucide_react3.ChevronRight, { size: 14 })
9145
9154
  ) : /* @__PURE__ */ import_react49.default.createElement("span", { className: "rf-tsn__expand-ph" }),
9146
- selectionMode === "multiple" && /* @__PURE__ */ import_react49.default.createElement(
9147
- "span",
9148
- {
9149
- className: `rf-tsn__cb${state === "checked" ? " rf-tsn__cb--checked" : state === "partial" ? " rf-tsn__cb--partial" : ""}`
9150
- },
9151
- state === "checked" && /* @__PURE__ */ import_react49.default.createElement(import_lucide_react3.Check, { size: 10, strokeWidth: 3 }),
9152
- state === "partial" && /* @__PURE__ */ import_react49.default.createElement("span", { className: "rf-tsn__cb-dash" })
9153
- ),
9154
- selectionMode === "single" && /* @__PURE__ */ import_react49.default.createElement("span", { className: `rf-tsn__radio${state === "checked" ? " rf-tsn__radio--checked" : ""}` }),
9155
- /* @__PURE__ */ import_react49.default.createElement("span", { className: "rf-tsn__label" }, node.label)
9155
+ /* @__PURE__ */ import_react49.default.createElement("span", { className: "rf-tsn__label" }, node.label),
9156
+ /* @__PURE__ */ import_react49.default.createElement("span", { className: "rf-tsn__check", "aria-hidden": "true" }, state === "partial" ? /* @__PURE__ */ import_react49.default.createElement(import_lucide_react3.Minus, { size: 13, strokeWidth: 2.5 }) : /* @__PURE__ */ import_react49.default.createElement(import_lucide_react3.Check, { size: 13, strokeWidth: 2.5 }))
9156
9157
  ), hasChildren && isExpanded && /* @__PURE__ */ import_react49.default.createElement("div", null, node.children.map((child) => /* @__PURE__ */ import_react49.default.createElement(
9157
9158
  TreeNodeItem,
9158
9159
  {
@@ -9162,6 +9163,7 @@ function TreeNodeItem({
9162
9163
  selected,
9163
9164
  expanded,
9164
9165
  selectionMode,
9166
+ allowChildSelection,
9165
9167
  onToggleExpand,
9166
9168
  onSelect,
9167
9169
  isFiltering
@@ -9175,6 +9177,7 @@ function TreeSelect({
9175
9177
  onNodeSelect,
9176
9178
  onNodeUnselect,
9177
9179
  selectionMode = "single",
9180
+ allowChildSelection = false,
9178
9181
  placeholder = "Select",
9179
9182
  filter = false,
9180
9183
  filterInputAutoFocus = false,
@@ -9295,15 +9298,25 @@ function TreeSelect({
9295
9298
  const handleSelect = (node) => {
9296
9299
  const nodeId = String(node.id);
9297
9300
  if (isMultiple) {
9298
- const state = getNodeState(node, selectedSet);
9299
- const descendants = collectDescendants(node);
9300
9301
  const newSet = new Set(selectedSet);
9301
- if (state === "checked" || state === "partial") {
9302
- descendants.forEach((id) => newSet.delete(id));
9303
- onNodeUnselect?.({ node });
9302
+ if (allowChildSelection) {
9303
+ const state = getNodeState(node, selectedSet);
9304
+ const descendants = collectDescendants(node);
9305
+ if (state === "checked" || state === "partial") {
9306
+ descendants.forEach((id) => newSet.delete(id));
9307
+ onNodeUnselect?.({ node });
9308
+ } else {
9309
+ descendants.forEach((id) => newSet.add(id));
9310
+ onNodeSelect?.({ node });
9311
+ }
9304
9312
  } else {
9305
- descendants.forEach((id) => newSet.add(id));
9306
- onNodeSelect?.({ node });
9313
+ if (newSet.has(nodeId)) {
9314
+ newSet.delete(nodeId);
9315
+ onNodeUnselect?.({ node });
9316
+ } else {
9317
+ newSet.add(nodeId);
9318
+ onNodeSelect?.({ node });
9319
+ }
9307
9320
  }
9308
9321
  onChange?.({ value: setToRecord(newSet) });
9309
9322
  } else {
@@ -9336,7 +9349,7 @@ function TreeSelect({
9336
9349
  onNodeUnselect?.({ node });
9337
9350
  };
9338
9351
  const filteredTree = filterTree(options, filterQuery);
9339
- const tagNodes = isMultiple ? getTopLevelSelected(options, selectedSet) : value != null ? findNodeById(options, String(value)) ? [findNodeById(options, String(value))] : [] : [];
9352
+ const tagNodes = isMultiple ? allowChildSelection ? getTopLevelSelected(options, selectedSet) : getAllSelected(options, selectedSet) : value != null ? findNodeById(options, String(value)) ? [findNodeById(options, String(value))] : [] : [];
9340
9353
  const hasValue = tagNodes.length > 0;
9341
9354
  const isFloating = open || hasValue || focused;
9342
9355
  const rootClasses = [
@@ -9434,6 +9447,7 @@ function TreeSelect({
9434
9447
  selected: selectedSet,
9435
9448
  expanded: expandedKeys,
9436
9449
  selectionMode,
9450
+ allowChildSelection,
9437
9451
  onToggleExpand: handleToggleExpand,
9438
9452
  onSelect: handleSelect,
9439
9453
  isFiltering: !!filterQuery
@@ -9598,6 +9612,14 @@ function SmartSelect({
9598
9612
  (0, import_react51.useEffect)(() => () => {
9599
9613
  if (debounceTimer.current) clearTimeout(debounceTimer.current);
9600
9614
  }, []);
9615
+ const [inputValue, setInputValue] = (0, import_react51.useState)(
9616
+ () => !multiple && value != null ? getOptionLabel(value) : ""
9617
+ );
9618
+ (0, import_react51.useEffect)(() => {
9619
+ if (!multiple) {
9620
+ setInputValue(value != null ? getOptionLabel(value) : "");
9621
+ }
9622
+ }, [value, multiple, getOptionLabel]);
9601
9623
  const getValue = (0, import_react51.useCallback)(
9602
9624
  (o) => getOptionValue ? getOptionValue(o) : String(getOptionLabel(o)),
9603
9625
  [getOptionValue, getOptionLabel]
@@ -9628,14 +9650,15 @@ function SmartSelect({
9628
9650
  }
9629
9651
  return value != null ? /* @__PURE__ */ new Set([getValue(value)]) : /* @__PURE__ */ new Set();
9630
9652
  }, [multiple, value, getValue]);
9631
- const handleInputChange = (0, import_react51.useCallback)((_, inputValue) => {
9653
+ const handleInputChange = (0, import_react51.useCallback)((_, inputValue2) => {
9654
+ setInputValue(inputValue2);
9632
9655
  if (!onSearchChange) return;
9633
9656
  if (debounceTimer.current) clearTimeout(debounceTimer.current);
9634
- if (!inputValue) {
9657
+ if (!inputValue2) {
9635
9658
  onSearchChange("", 0);
9636
9659
  return;
9637
9660
  }
9638
- const q = inputValue.toLowerCase();
9661
+ const q = inputValue2.toLowerCase();
9639
9662
  let localCount = 0;
9640
9663
  for (const opt of flatOptionsList) {
9641
9664
  if (getOptionLabel(opt).toLowerCase().includes(q) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q)) {
@@ -9646,10 +9669,10 @@ function SmartSelect({
9646
9669
  if (localCount >= searchThreshold) return;
9647
9670
  const needed = searchThreshold - localCount;
9648
9671
  if (debounceMs <= 0) {
9649
- onSearchChange(inputValue, needed);
9672
+ onSearchChange(inputValue2, needed);
9650
9673
  } else {
9651
9674
  debounceTimer.current = setTimeout(() => {
9652
- onSearchChange(inputValue, needed);
9675
+ onSearchChange(inputValue2, needed);
9653
9676
  }, debounceMs);
9654
9677
  }
9655
9678
  }, [onSearchChange, debounceMs, searchThreshold, flatOptionsList, getOptionLabel, getOptionSubLabel]);
@@ -9704,43 +9727,37 @@ function SmartSelect({
9704
9727
  {
9705
9728
  key,
9706
9729
  ...rest,
9707
- className: muiClass,
9730
+ className: [
9731
+ muiClass,
9732
+ "rf-select__option",
9733
+ isSelected ? "rf-select__option--selected" : ""
9734
+ ].filter(Boolean).join(" "),
9708
9735
  style: {
9709
9736
  ...muiStyle,
9710
- display: "flex",
9711
- alignItems: "center",
9712
- gap: 10,
9713
- padding: "8px 16px",
9714
9737
  paddingLeft: 16 + depth * 20,
9715
- fontSize: "0.9rem",
9716
- color: "rgba(0,0,0,0.87)",
9717
- cursor: "pointer",
9718
- userSelect: "none",
9719
- minHeight: 40,
9720
- boxSizing: "border-box",
9721
- fontWeight: isSelected ? 500 : void 0,
9722
- backgroundColor: isSelected ? "rgba(164,27,6,0.08)" : void 0,
9723
- listStyle: "none"
9738
+ listStyle: "none",
9739
+ alignItems: subLabel ? "flex-start" : void 0
9724
9740
  }
9725
9741
  },
9726
- /* @__PURE__ */ import_react51.default.createElement("span", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column" } }, /* @__PURE__ */ import_react51.default.createElement("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", lineHeight: 1.3 } }, getOptionLabel(option)), subLabel && /* @__PURE__ */ import_react51.default.createElement("span", { style: { fontSize: "0.75rem", color: "var(--text-secondary)", lineHeight: 1.3, marginTop: 1 } }, subLabel)),
9727
- /* @__PURE__ */ import_react51.default.createElement("span", { style: {
9728
- color: "var(--primary-color, #a41b06)",
9729
- flexShrink: 0,
9730
- display: "flex",
9731
- alignItems: "center",
9732
- opacity: isSelected ? 1 : 0,
9733
- transition: "opacity 0.1s"
9734
- } }, /* @__PURE__ */ import_react51.default.createElement(CheckIcon3, null))
9742
+ /* @__PURE__ */ import_react51.default.createElement(
9743
+ "span",
9744
+ {
9745
+ className: "rf-select__option-label",
9746
+ style: subLabel ? { display: "flex", flexDirection: "column", whiteSpace: "normal" } : void 0
9747
+ },
9748
+ /* @__PURE__ */ import_react51.default.createElement("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", lineHeight: 1.3 } }, getOptionLabel(option)),
9749
+ subLabel && /* @__PURE__ */ import_react51.default.createElement("span", { style: { fontSize: "0.75rem", color: "var(--text-secondary)", lineHeight: 1.3, marginTop: 1 } }, subLabel)
9750
+ ),
9751
+ /* @__PURE__ */ import_react51.default.createElement("span", { className: "rf-select__option-check", "aria-hidden": "true" }, /* @__PURE__ */ import_react51.default.createElement(CheckIcon3, null))
9735
9752
  );
9736
9753
  }, [depthMap, getValue, getOptionLabel, getOptionSubLabel, selectedKeys]);
9737
- const computedFilterOptions = (0, import_react51.useCallback)((opts, inputValue) => {
9738
- if (filterOptionsProp) return filterOptionsProp(opts, inputValue);
9754
+ const computedFilterOptions = (0, import_react51.useCallback)((opts, inputValue2) => {
9755
+ if (filterOptionsProp) return filterOptionsProp(opts, inputValue2);
9739
9756
  if (multiple) {
9740
9757
  const selected = opts.filter((o) => selectedKeys.has(getValue(o)));
9741
9758
  const unselected = opts.filter((o) => !selectedKeys.has(getValue(o)));
9742
- if (!inputValue) return [...selected, ...unselected];
9743
- const q2 = inputValue.toLowerCase();
9759
+ if (!inputValue2) return [...selected, ...unselected];
9760
+ const q2 = inputValue2.toLowerCase();
9744
9761
  const filteredUnselected = unselected.filter(
9745
9762
  (opt) => getOptionLabel(opt).toLowerCase().includes(q2) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q2)
9746
9763
  ).slice(0, searchThreshold);
@@ -9748,7 +9765,7 @@ function SmartSelect({
9748
9765
  }
9749
9766
  if (value != null) {
9750
9767
  const selectedLabel = getOptionLabel(value);
9751
- if (inputValue === selectedLabel) {
9768
+ if (inputValue2 === selectedLabel) {
9752
9769
  const selectedKey = getValue(value);
9753
9770
  return [
9754
9771
  ...opts.filter((o) => getValue(o) === selectedKey),
@@ -9756,8 +9773,8 @@ function SmartSelect({
9756
9773
  ];
9757
9774
  }
9758
9775
  }
9759
- if (!inputValue) return opts;
9760
- const q = inputValue.toLowerCase();
9776
+ if (!inputValue2) return opts;
9777
+ const q = inputValue2.toLowerCase();
9761
9778
  return opts.filter(
9762
9779
  (opt) => getOptionLabel(opt).toLowerCase().includes(q) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q)
9763
9780
  ).slice(0, searchThreshold);
@@ -9768,6 +9785,7 @@ function SmartSelect({
9768
9785
  options: displayOptions,
9769
9786
  value: value ?? (multiple ? [] : null),
9770
9787
  onChange: handleChange,
9788
+ inputValue: multiple ? void 0 : inputValue,
9771
9789
  onInputChange: handleInputChange,
9772
9790
  multiple,
9773
9791
  limitTags,
package/dist/main.css CHANGED
@@ -1370,6 +1370,12 @@ pre {
1370
1370
  .rf-tsn__row:hover {
1371
1371
  background: rgba(241, 91, 36, 0.06);
1372
1372
  }
1373
+ .rf-tsn__row--active {
1374
+ background: rgba(164, 27, 6, 0.08);
1375
+ }
1376
+ .rf-tsn__row--active:hover {
1377
+ background: rgba(164, 27, 6, 0.12);
1378
+ }
1373
1379
  .rf-tsn__row--active .rf-tsn__label {
1374
1380
  color: rgba(0, 0, 0, 0.87);
1375
1381
  font-weight: 500;
@@ -1397,56 +1403,17 @@ pre {
1397
1403
  flex-shrink: 0;
1398
1404
  display: inline-block;
1399
1405
  }
1400
- .rf-tsn__cb {
1401
- width: 16px;
1402
- height: 16px;
1403
- border: 2px solid var(--border-color);
1404
- border-radius: 4px;
1406
+ .rf-tsn__check {
1407
+ color: var(--primary-color, #a41b06);
1408
+ flex-shrink: 0;
1405
1409
  display: flex;
1406
1410
  align-items: center;
1407
- justify-content: center;
1408
- flex-shrink: 0;
1409
- transition: border-color 0.15s, background 0.15s;
1410
- background: var(--surface-color);
1411
- color: transparent;
1412
- }
1413
- .rf-tsn__cb--checked {
1414
- background: var(--primary-color);
1415
- border-color: var(--primary-color);
1416
- color: #fff;
1417
- }
1418
- .rf-tsn__cb--partial {
1419
- border-color: var(--primary-color);
1420
- }
1421
- .rf-tsn__cb-dash {
1422
- display: block;
1423
- width: 8px;
1424
- height: 2px;
1425
- background: var(--primary-color);
1426
- border-radius: 1px;
1427
- }
1428
- .rf-tsn__radio {
1429
- width: 16px;
1430
- height: 16px;
1431
- border: 2px solid var(--border-color);
1432
- border-radius: 50%;
1433
- flex-shrink: 0;
1434
- transition: border-color 0.15s;
1435
- position: relative;
1436
- }
1437
- .rf-tsn__radio--checked {
1438
- border-color: var(--primary-color);
1411
+ margin-left: auto;
1412
+ opacity: 0;
1413
+ transition: opacity 0.1s;
1439
1414
  }
1440
- .rf-tsn__radio--checked::after {
1441
- content: "";
1442
- position: absolute;
1443
- top: 50%;
1444
- left: 50%;
1445
- transform: translate(-50%, -50%);
1446
- width: 8px;
1447
- height: 8px;
1448
- background: var(--primary-color);
1449
- border-radius: 50%;
1415
+ .rf-tsn__row--active .rf-tsn__check {
1416
+ opacity: 1;
1450
1417
  }
1451
1418
  .rf-tsn__label {
1452
1419
  font-size: 0.875rem;
package/dist/main.d.cts CHANGED
@@ -1830,7 +1830,13 @@ interface TreeSelectProps {
1830
1830
  filterInputAutoFocus?: boolean;
1831
1831
  /** Clear filter text when the dropdown closes */
1832
1832
  resetFilterOnHide?: boolean;
1833
- /** PrimeReact compat — accepted but not used (checkboxes handle multi-select) */
1833
+ /**
1834
+ * When **true**, selecting a parent selects all its descendants and vice-versa (cascade).
1835
+ * When **false** (default), every node is selected/deselected independently — no cascade.
1836
+ * Only relevant in `multiple` mode.
1837
+ */
1838
+ allowChildSelection?: boolean;
1839
+ /** PrimeReact compat — accepted but not used */
1834
1840
  metaKeySelection?: boolean;
1835
1841
  /** Disable the whole control */
1836
1842
  disabled?: boolean;
@@ -1854,7 +1860,7 @@ interface TreeSelectProps {
1854
1860
  className?: string;
1855
1861
  sx?: SxProp;
1856
1862
  }
1857
- declare function TreeSelect({ options, value, onChange, onNodeSelect, onNodeUnselect, selectionMode, placeholder, filter, filterInputAutoFocus, resetFilterOnHide, metaKeySelection: _metaKeySelection, disabled, label, variant, size, error, helperText, fullWidth, clearable, required, style, className, sx, }: TreeSelectProps): React__default.JSX.Element;
1863
+ declare function TreeSelect({ options, value, onChange, onNodeSelect, onNodeUnselect, selectionMode, allowChildSelection, placeholder, filter, filterInputAutoFocus, resetFilterOnHide, metaKeySelection: _metaKeySelection, disabled, label, variant, size, error, helperText, fullWidth, clearable, required, style, className, sx, }: TreeSelectProps): React__default.JSX.Element;
1858
1864
 
1859
1865
  interface UserOption {
1860
1866
  id?: string | number;
package/dist/main.d.ts CHANGED
@@ -1830,7 +1830,13 @@ interface TreeSelectProps {
1830
1830
  filterInputAutoFocus?: boolean;
1831
1831
  /** Clear filter text when the dropdown closes */
1832
1832
  resetFilterOnHide?: boolean;
1833
- /** PrimeReact compat — accepted but not used (checkboxes handle multi-select) */
1833
+ /**
1834
+ * When **true**, selecting a parent selects all its descendants and vice-versa (cascade).
1835
+ * When **false** (default), every node is selected/deselected independently — no cascade.
1836
+ * Only relevant in `multiple` mode.
1837
+ */
1838
+ allowChildSelection?: boolean;
1839
+ /** PrimeReact compat — accepted but not used */
1834
1840
  metaKeySelection?: boolean;
1835
1841
  /** Disable the whole control */
1836
1842
  disabled?: boolean;
@@ -1854,7 +1860,7 @@ interface TreeSelectProps {
1854
1860
  className?: string;
1855
1861
  sx?: SxProp;
1856
1862
  }
1857
- declare function TreeSelect({ options, value, onChange, onNodeSelect, onNodeUnselect, selectionMode, placeholder, filter, filterInputAutoFocus, resetFilterOnHide, metaKeySelection: _metaKeySelection, disabled, label, variant, size, error, helperText, fullWidth, clearable, required, style, className, sx, }: TreeSelectProps): React__default.JSX.Element;
1863
+ declare function TreeSelect({ options, value, onChange, onNodeSelect, onNodeUnselect, selectionMode, allowChildSelection, placeholder, filter, filterInputAutoFocus, resetFilterOnHide, metaKeySelection: _metaKeySelection, disabled, label, variant, size, error, helperText, fullWidth, clearable, required, style, className, sx, }: TreeSelectProps): React__default.JSX.Element;
1858
1864
 
1859
1865
  interface UserOption {
1860
1866
  id?: string | number;
package/dist/main.js CHANGED
@@ -8978,7 +8978,7 @@ import React106, {
8978
8978
  useCallback as useCallback10
8979
8979
  } from "react";
8980
8980
  import ReactDOM10 from "react-dom";
8981
- import { ChevronDown as ChevronDown2, ChevronRight as ChevronRight2, X as X3, Search as Search2, Check } from "lucide-react";
8981
+ import { ChevronDown as ChevronDown2, ChevronRight as ChevronRight2, X as X3, Search as Search2, Check, Minus } from "lucide-react";
8982
8982
  function collectDescendants(node) {
8983
8983
  const ids = [String(node.id)];
8984
8984
  node.children?.forEach((c) => ids.push(...collectDescendants(c)));
@@ -9012,6 +9012,14 @@ function getTopLevelSelected(nodes, selected) {
9012
9012
  }
9013
9013
  return result;
9014
9014
  }
9015
+ function getAllSelected(nodes, selected) {
9016
+ const result = [];
9017
+ for (const node of nodes) {
9018
+ if (selected.has(String(node.id))) result.push(node);
9019
+ if (node.children?.length) result.push(...getAllSelected(node.children, selected));
9020
+ }
9021
+ return result;
9022
+ }
9015
9023
  function filterTree(nodes, query) {
9016
9024
  if (!query) return nodes;
9017
9025
  const q = query.toLowerCase();
@@ -9040,6 +9048,7 @@ function TreeNodeItem({
9040
9048
  selected,
9041
9049
  expanded,
9042
9050
  selectionMode,
9051
+ allowChildSelection,
9043
9052
  onToggleExpand,
9044
9053
  onSelect,
9045
9054
  isFiltering
@@ -9047,7 +9056,7 @@ function TreeNodeItem({
9047
9056
  const nodeId = String(node.id);
9048
9057
  const hasChildren = !!node.children?.length;
9049
9058
  const isExpanded = isFiltering || expanded.has(nodeId);
9050
- const state = getNodeState(node, selected);
9059
+ const state = allowChildSelection ? getNodeState(node, selected) : selected.has(nodeId) ? "checked" : "unchecked";
9051
9060
  return /* @__PURE__ */ React106.createElement("div", { className: "rf-tsn" }, /* @__PURE__ */ React106.createElement(
9052
9061
  "div",
9053
9062
  {
@@ -9067,16 +9076,8 @@ function TreeNodeItem({
9067
9076
  },
9068
9077
  isExpanded ? /* @__PURE__ */ React106.createElement(ChevronDown2, { size: 14 }) : /* @__PURE__ */ React106.createElement(ChevronRight2, { size: 14 })
9069
9078
  ) : /* @__PURE__ */ React106.createElement("span", { className: "rf-tsn__expand-ph" }),
9070
- selectionMode === "multiple" && /* @__PURE__ */ React106.createElement(
9071
- "span",
9072
- {
9073
- className: `rf-tsn__cb${state === "checked" ? " rf-tsn__cb--checked" : state === "partial" ? " rf-tsn__cb--partial" : ""}`
9074
- },
9075
- state === "checked" && /* @__PURE__ */ React106.createElement(Check, { size: 10, strokeWidth: 3 }),
9076
- state === "partial" && /* @__PURE__ */ React106.createElement("span", { className: "rf-tsn__cb-dash" })
9077
- ),
9078
- selectionMode === "single" && /* @__PURE__ */ React106.createElement("span", { className: `rf-tsn__radio${state === "checked" ? " rf-tsn__radio--checked" : ""}` }),
9079
- /* @__PURE__ */ React106.createElement("span", { className: "rf-tsn__label" }, node.label)
9079
+ /* @__PURE__ */ React106.createElement("span", { className: "rf-tsn__label" }, node.label),
9080
+ /* @__PURE__ */ React106.createElement("span", { className: "rf-tsn__check", "aria-hidden": "true" }, state === "partial" ? /* @__PURE__ */ React106.createElement(Minus, { size: 13, strokeWidth: 2.5 }) : /* @__PURE__ */ React106.createElement(Check, { size: 13, strokeWidth: 2.5 }))
9080
9081
  ), hasChildren && isExpanded && /* @__PURE__ */ React106.createElement("div", null, node.children.map((child) => /* @__PURE__ */ React106.createElement(
9081
9082
  TreeNodeItem,
9082
9083
  {
@@ -9086,6 +9087,7 @@ function TreeNodeItem({
9086
9087
  selected,
9087
9088
  expanded,
9088
9089
  selectionMode,
9090
+ allowChildSelection,
9089
9091
  onToggleExpand,
9090
9092
  onSelect,
9091
9093
  isFiltering
@@ -9099,6 +9101,7 @@ function TreeSelect({
9099
9101
  onNodeSelect,
9100
9102
  onNodeUnselect,
9101
9103
  selectionMode = "single",
9104
+ allowChildSelection = false,
9102
9105
  placeholder = "Select",
9103
9106
  filter = false,
9104
9107
  filterInputAutoFocus = false,
@@ -9219,15 +9222,25 @@ function TreeSelect({
9219
9222
  const handleSelect = (node) => {
9220
9223
  const nodeId = String(node.id);
9221
9224
  if (isMultiple) {
9222
- const state = getNodeState(node, selectedSet);
9223
- const descendants = collectDescendants(node);
9224
9225
  const newSet = new Set(selectedSet);
9225
- if (state === "checked" || state === "partial") {
9226
- descendants.forEach((id) => newSet.delete(id));
9227
- onNodeUnselect?.({ node });
9226
+ if (allowChildSelection) {
9227
+ const state = getNodeState(node, selectedSet);
9228
+ const descendants = collectDescendants(node);
9229
+ if (state === "checked" || state === "partial") {
9230
+ descendants.forEach((id) => newSet.delete(id));
9231
+ onNodeUnselect?.({ node });
9232
+ } else {
9233
+ descendants.forEach((id) => newSet.add(id));
9234
+ onNodeSelect?.({ node });
9235
+ }
9228
9236
  } else {
9229
- descendants.forEach((id) => newSet.add(id));
9230
- onNodeSelect?.({ node });
9237
+ if (newSet.has(nodeId)) {
9238
+ newSet.delete(nodeId);
9239
+ onNodeUnselect?.({ node });
9240
+ } else {
9241
+ newSet.add(nodeId);
9242
+ onNodeSelect?.({ node });
9243
+ }
9231
9244
  }
9232
9245
  onChange?.({ value: setToRecord(newSet) });
9233
9246
  } else {
@@ -9260,7 +9273,7 @@ function TreeSelect({
9260
9273
  onNodeUnselect?.({ node });
9261
9274
  };
9262
9275
  const filteredTree = filterTree(options, filterQuery);
9263
- const tagNodes = isMultiple ? getTopLevelSelected(options, selectedSet) : value != null ? findNodeById(options, String(value)) ? [findNodeById(options, String(value))] : [] : [];
9276
+ const tagNodes = isMultiple ? allowChildSelection ? getTopLevelSelected(options, selectedSet) : getAllSelected(options, selectedSet) : value != null ? findNodeById(options, String(value)) ? [findNodeById(options, String(value))] : [] : [];
9264
9277
  const hasValue = tagNodes.length > 0;
9265
9278
  const isFloating = open || hasValue || focused;
9266
9279
  const rootClasses = [
@@ -9358,6 +9371,7 @@ function TreeSelect({
9358
9371
  selected: selectedSet,
9359
9372
  expanded: expandedKeys,
9360
9373
  selectionMode,
9374
+ allowChildSelection,
9361
9375
  onToggleExpand: handleToggleExpand,
9362
9376
  onSelect: handleSelect,
9363
9377
  isFiltering: !!filterQuery
@@ -9466,7 +9480,7 @@ function UserSelectionField({
9466
9480
  }
9467
9481
 
9468
9482
  // lib/SmartSelect/SmartSelect.tsx
9469
- import React108, { useCallback as useCallback11, useEffect as useEffect21, useMemo as useMemo3, useRef as useRef25 } from "react";
9483
+ import React108, { useCallback as useCallback11, useEffect as useEffect21, useMemo as useMemo3, useRef as useRef25, useState as useState26 } from "react";
9470
9484
  var CheckIcon3 = () => /* @__PURE__ */ React108.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React108.createElement("polyline", { points: "20 6 9 17 4 12" }));
9471
9485
  function flattenTree(options, getChildren, depth = 0) {
9472
9486
  return options.flatMap((opt) => [
@@ -9522,6 +9536,14 @@ function SmartSelect({
9522
9536
  useEffect21(() => () => {
9523
9537
  if (debounceTimer.current) clearTimeout(debounceTimer.current);
9524
9538
  }, []);
9539
+ const [inputValue, setInputValue] = useState26(
9540
+ () => !multiple && value != null ? getOptionLabel(value) : ""
9541
+ );
9542
+ useEffect21(() => {
9543
+ if (!multiple) {
9544
+ setInputValue(value != null ? getOptionLabel(value) : "");
9545
+ }
9546
+ }, [value, multiple, getOptionLabel]);
9525
9547
  const getValue = useCallback11(
9526
9548
  (o) => getOptionValue ? getOptionValue(o) : String(getOptionLabel(o)),
9527
9549
  [getOptionValue, getOptionLabel]
@@ -9552,14 +9574,15 @@ function SmartSelect({
9552
9574
  }
9553
9575
  return value != null ? /* @__PURE__ */ new Set([getValue(value)]) : /* @__PURE__ */ new Set();
9554
9576
  }, [multiple, value, getValue]);
9555
- const handleInputChange = useCallback11((_, inputValue) => {
9577
+ const handleInputChange = useCallback11((_, inputValue2) => {
9578
+ setInputValue(inputValue2);
9556
9579
  if (!onSearchChange) return;
9557
9580
  if (debounceTimer.current) clearTimeout(debounceTimer.current);
9558
- if (!inputValue) {
9581
+ if (!inputValue2) {
9559
9582
  onSearchChange("", 0);
9560
9583
  return;
9561
9584
  }
9562
- const q = inputValue.toLowerCase();
9585
+ const q = inputValue2.toLowerCase();
9563
9586
  let localCount = 0;
9564
9587
  for (const opt of flatOptionsList) {
9565
9588
  if (getOptionLabel(opt).toLowerCase().includes(q) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q)) {
@@ -9570,10 +9593,10 @@ function SmartSelect({
9570
9593
  if (localCount >= searchThreshold) return;
9571
9594
  const needed = searchThreshold - localCount;
9572
9595
  if (debounceMs <= 0) {
9573
- onSearchChange(inputValue, needed);
9596
+ onSearchChange(inputValue2, needed);
9574
9597
  } else {
9575
9598
  debounceTimer.current = setTimeout(() => {
9576
- onSearchChange(inputValue, needed);
9599
+ onSearchChange(inputValue2, needed);
9577
9600
  }, debounceMs);
9578
9601
  }
9579
9602
  }, [onSearchChange, debounceMs, searchThreshold, flatOptionsList, getOptionLabel, getOptionSubLabel]);
@@ -9628,43 +9651,37 @@ function SmartSelect({
9628
9651
  {
9629
9652
  key,
9630
9653
  ...rest,
9631
- className: muiClass,
9654
+ className: [
9655
+ muiClass,
9656
+ "rf-select__option",
9657
+ isSelected ? "rf-select__option--selected" : ""
9658
+ ].filter(Boolean).join(" "),
9632
9659
  style: {
9633
9660
  ...muiStyle,
9634
- display: "flex",
9635
- alignItems: "center",
9636
- gap: 10,
9637
- padding: "8px 16px",
9638
9661
  paddingLeft: 16 + depth * 20,
9639
- fontSize: "0.9rem",
9640
- color: "rgba(0,0,0,0.87)",
9641
- cursor: "pointer",
9642
- userSelect: "none",
9643
- minHeight: 40,
9644
- boxSizing: "border-box",
9645
- fontWeight: isSelected ? 500 : void 0,
9646
- backgroundColor: isSelected ? "rgba(164,27,6,0.08)" : void 0,
9647
- listStyle: "none"
9662
+ listStyle: "none",
9663
+ alignItems: subLabel ? "flex-start" : void 0
9648
9664
  }
9649
9665
  },
9650
- /* @__PURE__ */ React108.createElement("span", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column" } }, /* @__PURE__ */ React108.createElement("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", lineHeight: 1.3 } }, getOptionLabel(option)), subLabel && /* @__PURE__ */ React108.createElement("span", { style: { fontSize: "0.75rem", color: "var(--text-secondary)", lineHeight: 1.3, marginTop: 1 } }, subLabel)),
9651
- /* @__PURE__ */ React108.createElement("span", { style: {
9652
- color: "var(--primary-color, #a41b06)",
9653
- flexShrink: 0,
9654
- display: "flex",
9655
- alignItems: "center",
9656
- opacity: isSelected ? 1 : 0,
9657
- transition: "opacity 0.1s"
9658
- } }, /* @__PURE__ */ React108.createElement(CheckIcon3, null))
9666
+ /* @__PURE__ */ React108.createElement(
9667
+ "span",
9668
+ {
9669
+ className: "rf-select__option-label",
9670
+ style: subLabel ? { display: "flex", flexDirection: "column", whiteSpace: "normal" } : void 0
9671
+ },
9672
+ /* @__PURE__ */ React108.createElement("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", lineHeight: 1.3 } }, getOptionLabel(option)),
9673
+ subLabel && /* @__PURE__ */ React108.createElement("span", { style: { fontSize: "0.75rem", color: "var(--text-secondary)", lineHeight: 1.3, marginTop: 1 } }, subLabel)
9674
+ ),
9675
+ /* @__PURE__ */ React108.createElement("span", { className: "rf-select__option-check", "aria-hidden": "true" }, /* @__PURE__ */ React108.createElement(CheckIcon3, null))
9659
9676
  );
9660
9677
  }, [depthMap, getValue, getOptionLabel, getOptionSubLabel, selectedKeys]);
9661
- const computedFilterOptions = useCallback11((opts, inputValue) => {
9662
- if (filterOptionsProp) return filterOptionsProp(opts, inputValue);
9678
+ const computedFilterOptions = useCallback11((opts, inputValue2) => {
9679
+ if (filterOptionsProp) return filterOptionsProp(opts, inputValue2);
9663
9680
  if (multiple) {
9664
9681
  const selected = opts.filter((o) => selectedKeys.has(getValue(o)));
9665
9682
  const unselected = opts.filter((o) => !selectedKeys.has(getValue(o)));
9666
- if (!inputValue) return [...selected, ...unselected];
9667
- const q2 = inputValue.toLowerCase();
9683
+ if (!inputValue2) return [...selected, ...unselected];
9684
+ const q2 = inputValue2.toLowerCase();
9668
9685
  const filteredUnselected = unselected.filter(
9669
9686
  (opt) => getOptionLabel(opt).toLowerCase().includes(q2) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q2)
9670
9687
  ).slice(0, searchThreshold);
@@ -9672,7 +9689,7 @@ function SmartSelect({
9672
9689
  }
9673
9690
  if (value != null) {
9674
9691
  const selectedLabel = getOptionLabel(value);
9675
- if (inputValue === selectedLabel) {
9692
+ if (inputValue2 === selectedLabel) {
9676
9693
  const selectedKey = getValue(value);
9677
9694
  return [
9678
9695
  ...opts.filter((o) => getValue(o) === selectedKey),
@@ -9680,8 +9697,8 @@ function SmartSelect({
9680
9697
  ];
9681
9698
  }
9682
9699
  }
9683
- if (!inputValue) return opts;
9684
- const q = inputValue.toLowerCase();
9700
+ if (!inputValue2) return opts;
9701
+ const q = inputValue2.toLowerCase();
9685
9702
  return opts.filter(
9686
9703
  (opt) => getOptionLabel(opt).toLowerCase().includes(q) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q)
9687
9704
  ).slice(0, searchThreshold);
@@ -9692,6 +9709,7 @@ function SmartSelect({
9692
9709
  options: displayOptions,
9693
9710
  value: value ?? (multiple ? [] : null),
9694
9711
  onChange: handleChange,
9712
+ inputValue: multiple ? void 0 : inputValue,
9695
9713
  onInputChange: handleInputChange,
9696
9714
  multiple,
9697
9715
  limitTags,
@@ -9718,7 +9736,7 @@ function SmartSelect({
9718
9736
  }
9719
9737
 
9720
9738
  // lib/RufousTextEditor/RufousTextEditor.tsx
9721
- import React119, { useMemo as useMemo5, useCallback as useCallback16, useState as useState35, useRef as useRef33, useEffect as useEffect30 } from "react";
9739
+ import React119, { useMemo as useMemo5, useCallback as useCallback16, useState as useState36, useRef as useRef33, useEffect as useEffect30 } from "react";
9722
9740
  import { createPortal as createPortal8 } from "react-dom";
9723
9741
  import { useEditor, EditorContent, EditorContext, FloatingMenu, BubbleMenu } from "@tiptap/react";
9724
9742
  import StarterKit from "@tiptap/starter-kit";
@@ -9744,9 +9762,9 @@ import { ReactRenderer } from "@tiptap/react";
9744
9762
  import tippy from "tippy.js";
9745
9763
 
9746
9764
  // lib/RufousTextEditor/MentionList.tsx
9747
- import React109, { forwardRef as forwardRef11, useEffect as useEffect22, useImperativeHandle, useState as useState26 } from "react";
9765
+ import React109, { forwardRef as forwardRef11, useEffect as useEffect22, useImperativeHandle, useState as useState27 } from "react";
9748
9766
  var MentionList = forwardRef11((props, ref) => {
9749
- const [selectedIndex, setSelectedIndex] = useState26(0);
9767
+ const [selectedIndex, setSelectedIndex] = useState27(0);
9750
9768
  const selectItem = (index) => {
9751
9769
  const item = props.items[index];
9752
9770
  if (item) {
@@ -9840,18 +9858,18 @@ function createMentionSuggestion(users) {
9840
9858
  }
9841
9859
 
9842
9860
  // lib/RufousTextEditor/Toolbar.tsx
9843
- import React115, { useState as useState31, useRef as useRef29, useEffect as useEffect26, useCallback as useCallback15 } from "react";
9861
+ import React115, { useState as useState32, useRef as useRef29, useEffect as useEffect26, useCallback as useCallback15 } from "react";
9844
9862
  import { createPortal as createPortal4 } from "react-dom";
9845
9863
 
9846
9864
  // lib/RufousTextEditor/TextToSpeech.tsx
9847
- import React110, { useState as useState27, useEffect as useEffect23, useRef as useRef26, useCallback as useCallback12, forwardRef as forwardRef12, useImperativeHandle as useImperativeHandle2 } from "react";
9865
+ import React110, { useState as useState28, useEffect as useEffect23, useRef as useRef26, useCallback as useCallback12, forwardRef as forwardRef12, useImperativeHandle as useImperativeHandle2 } from "react";
9848
9866
  var TextToSpeech = forwardRef12(({ editor, onTextToSpeech }, ref) => {
9849
- const [speaking, setSpeaking] = useState27(false);
9850
- const [paused, setPaused] = useState27(false);
9851
- const [voices, setVoices] = useState27([]);
9852
- const [selectedVoice, setSelectedVoice] = useState27("");
9853
- const [rate, setRate] = useState27(1);
9854
- const [showPanel, setShowPanel] = useState27(false);
9867
+ const [speaking, setSpeaking] = useState28(false);
9868
+ const [paused, setPaused] = useState28(false);
9869
+ const [voices, setVoices] = useState28([]);
9870
+ const [selectedVoice, setSelectedVoice] = useState28("");
9871
+ const [rate, setRate] = useState28(1);
9872
+ const [showPanel, setShowPanel] = useState28(false);
9855
9873
  const utteranceRef = useRef26(null);
9856
9874
  const panelRef = useRef26(null);
9857
9875
  useEffect23(() => {
@@ -9989,12 +10007,12 @@ var TextToSpeech = forwardRef12(({ editor, onTextToSpeech }, ref) => {
9989
10007
  var TextToSpeech_default = TextToSpeech;
9990
10008
 
9991
10009
  // lib/RufousTextEditor/SpeechToText.tsx
9992
- import React111, { useState as useState28, useRef as useRef27, useCallback as useCallback13, useEffect as useEffect24, forwardRef as forwardRef13, useImperativeHandle as useImperativeHandle3 } from "react";
10010
+ import React111, { useState as useState29, useRef as useRef27, useCallback as useCallback13, useEffect as useEffect24, forwardRef as forwardRef13, useImperativeHandle as useImperativeHandle3 } from "react";
9993
10011
  var SpeechToText = forwardRef13(({ editor, onSpeechToText }, ref) => {
9994
- const [listening, setListening] = useState28(false);
9995
- const [showPanel, setShowPanel] = useState28(false);
9996
- const [language, setLanguage] = useState28("en-US");
9997
- const [interim, setInterim] = useState28("");
10012
+ const [listening, setListening] = useState29(false);
10013
+ const [showPanel, setShowPanel] = useState29(false);
10014
+ const [language, setLanguage] = useState29("en-US");
10015
+ const [interim, setInterim] = useState29("");
9998
10016
  const recognitionRef = useRef27(null);
9999
10017
  const panelRef = useRef27(null);
10000
10018
  const isListeningRef = useRef27(false);
@@ -10151,7 +10169,7 @@ var SpeechToText = forwardRef13(({ editor, onSpeechToText }, ref) => {
10151
10169
  var SpeechToText_default = SpeechToText;
10152
10170
 
10153
10171
  // lib/RufousTextEditor/AICommands.tsx
10154
- import React112, { useState as useState29, useRef as useRef28, useEffect as useEffect25, useCallback as useCallback14 } from "react";
10172
+ import React112, { useState as useState30, useRef as useRef28, useEffect as useEffect25, useCallback as useCallback14 } from "react";
10155
10173
  import { createPortal as createPortal2 } from "react-dom";
10156
10174
  var AI_COMMANDS = [
10157
10175
  { id: "improve", label: "Improve writing", prompt: "Improve the following text to make it clearer, more engaging, and well-structured. Return only the improved text, no explanations." },
@@ -10199,14 +10217,14 @@ var callOpenAI = async (prompt, text, previousResults = []) => {
10199
10217
  return data.choices?.[0]?.message?.content?.trim() || "";
10200
10218
  };
10201
10219
  var AICommands = ({ editor, onAICommand }) => {
10202
- const [open, setOpen] = useState29(false);
10203
- const [showModal, setShowModal] = useState29(false);
10204
- const [loading, setLoading] = useState29(false);
10205
- const [promptText, setPromptText] = useState29("");
10206
- const [resultText, setResultText] = useState29("");
10207
- const [originalText, setOriginalText] = useState29("");
10208
- const [selectionRange, setSelectionRange] = useState29(null);
10209
- const [previousResults, setPreviousResults] = useState29([]);
10220
+ const [open, setOpen] = useState30(false);
10221
+ const [showModal, setShowModal] = useState30(false);
10222
+ const [loading, setLoading] = useState30(false);
10223
+ const [promptText, setPromptText] = useState30("");
10224
+ const [resultText, setResultText] = useState30("");
10225
+ const [originalText, setOriginalText] = useState30("");
10226
+ const [selectionRange, setSelectionRange] = useState30(null);
10227
+ const [previousResults, setPreviousResults] = useState30([]);
10210
10228
  const panelRef = useRef28(null);
10211
10229
  useEffect25(() => {
10212
10230
  const handleClick = (e) => {
@@ -10356,7 +10374,7 @@ var AICommands = ({ editor, onAICommand }) => {
10356
10374
  var AICommands_default = AICommands;
10357
10375
 
10358
10376
  // lib/RufousTextEditor/TranslateModal.tsx
10359
- import React113, { useState as useState30, useMemo as useMemo4 } from "react";
10377
+ import React113, { useState as useState31, useMemo as useMemo4 } from "react";
10360
10378
  import { createPortal as createPortal3 } from "react-dom";
10361
10379
  var LANGUAGES = [
10362
10380
  { code: "af", name: "Afrikaans" },
@@ -10496,12 +10514,12 @@ async function translateText(text, sourceLang, targetLang) {
10496
10514
  return null;
10497
10515
  }
10498
10516
  var TranslateModal = ({ editor, onClose, onTranslate, initialSource, initialTarget, onLangChange }) => {
10499
- const [sourceLang, setSourceLang] = useState30(initialSource || "en");
10500
- const [targetLang, setTargetLang] = useState30(initialTarget || "hi");
10501
- const [sourceFilter, setSourceFilter] = useState30("");
10502
- const [targetFilter, setTargetFilter] = useState30("");
10503
- const [translating, setTranslating] = useState30(false);
10504
- const [error, setError] = useState30("");
10517
+ const [sourceLang, setSourceLang] = useState31(initialSource || "en");
10518
+ const [targetLang, setTargetLang] = useState31(initialTarget || "hi");
10519
+ const [sourceFilter, setSourceFilter] = useState31("");
10520
+ const [targetFilter, setTargetFilter] = useState31("");
10521
+ const [translating, setTranslating] = useState31(false);
10522
+ const [error, setError] = useState31("");
10505
10523
  const filteredSource = useMemo4(() => LANGUAGES.filter(
10506
10524
  (l) => l.name.toLowerCase().includes(sourceFilter.toLowerCase()) || l.code.toLowerCase().includes(sourceFilter.toLowerCase())
10507
10525
  ), [sourceFilter]);
@@ -11405,7 +11423,7 @@ var SPECIAL_CHARS = [
11405
11423
  "\xA2"
11406
11424
  ];
11407
11425
  var Dropdown = ({ trigger, children, className = "", keepOpen = false }) => {
11408
- const [open, setOpen] = useState31(false);
11426
+ const [open, setOpen] = useState32(false);
11409
11427
  const ref = useRef29(null);
11410
11428
  const menuRef = useRef29(null);
11411
11429
  useEffect26(() => {
@@ -11463,8 +11481,8 @@ var Dropdown = ({ trigger, children, className = "", keepOpen = false }) => {
11463
11481
  ));
11464
11482
  };
11465
11483
  var InsertPanel = ({ editor, onClose, mode = "video" }) => {
11466
- const [activeTab, setActiveTab] = useState31("link");
11467
- const [url, setUrl] = useState31("");
11484
+ const [activeTab, setActiveTab] = useState32("link");
11485
+ const [url, setUrl] = useState32("");
11468
11486
  const extractIframeSrc = (html) => {
11469
11487
  const match = html.match(/<iframe[^>]+src=["']([^"']+)["']/);
11470
11488
  return match ? match[1] : null;
@@ -11534,9 +11552,9 @@ var InsertPanel = ({ editor, onClose, mode = "video" }) => {
11534
11552
  ), /* @__PURE__ */ React115.createElement("button", { className: "insert-panel-btn", onClick: handleInsert }, "Insert"));
11535
11553
  };
11536
11554
  var ImagePanel = ({ editor, onClose, onImageUpload }) => {
11537
- const [activeTab, setActiveTab] = useState31("upload");
11538
- const [url, setUrl] = useState31("");
11539
- const [isDragging, setIsDragging] = useState31(false);
11555
+ const [activeTab, setActiveTab] = useState32("upload");
11556
+ const [url, setUrl] = useState32("");
11557
+ const [isDragging, setIsDragging] = useState32(false);
11540
11558
  const fileInputRef = useRef29(null);
11541
11559
  const getBase64 = (file) => {
11542
11560
  return new Promise((resolve, reject) => {
@@ -11627,8 +11645,8 @@ var ImagePanel = ({ editor, onClose, onImageUpload }) => {
11627
11645
  };
11628
11646
  var MAX_GRID = 10;
11629
11647
  var TableGridSelector = ({ editor, onClose }) => {
11630
- const [hoverRow, setHoverRow] = useState31(0);
11631
- const [hoverCol, setHoverCol] = useState31(0);
11648
+ const [hoverRow, setHoverRow] = useState32(0);
11649
+ const [hoverCol, setHoverCol] = useState32(0);
11632
11650
  const handleInsert = () => {
11633
11651
  if (!editor || hoverRow === 0 || hoverCol === 0) return;
11634
11652
  editor.chain().focus().insertTable({ rows: hoverRow, cols: hoverCol, withHeaderRow: true }).run();
@@ -11666,9 +11684,9 @@ var TableGridSelector = ({ editor, onClose }) => {
11666
11684
  )));
11667
11685
  };
11668
11686
  var ColorPickerPanel = ({ editor, onClose }) => {
11669
- const [tab, setTab] = useState31("background");
11670
- const [activeBg, setActiveBg] = useState31(() => editor.getAttributes("highlight").color || null);
11671
- const [activeText, setActiveText] = useState31(() => editor.getAttributes("textStyle").color || null);
11687
+ const [tab, setTab] = useState32("background");
11688
+ const [activeBg, setActiveBg] = useState32(() => editor.getAttributes("highlight").color || null);
11689
+ const [activeText, setActiveText] = useState32(() => editor.getAttributes("textStyle").color || null);
11672
11690
  const activeColor = tab === "background" ? activeBg : activeText;
11673
11691
  const applyColor = (color) => {
11674
11692
  if (tab === "background") {
@@ -11713,8 +11731,8 @@ var ColorPickerPanel = ({ editor, onClose }) => {
11713
11731
  )))), /* @__PURE__ */ React115.createElement("div", { className: "color-picker-footer" }, /* @__PURE__ */ React115.createElement("div", { className: "color-picker-preview", style: { background: activeColor || "#000" } }), /* @__PURE__ */ React115.createElement(Tooltip, { title: "Remove color", placement: "top" }, /* @__PURE__ */ React115.createElement("button", { className: "color-picker-remove", onClick: removeColor }, "\u2713"))));
11714
11732
  };
11715
11733
  var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTextToSpeech, onClose, onImageUpload, visibleButtons, isFullscreen, onToggleFullscreen }) => {
11716
- const [, setEditorState] = useState31(0);
11717
- const [todoEnabled, setTodoEnabled] = useState31(false);
11734
+ const [, setEditorState] = useState32(0);
11735
+ const [todoEnabled, setTodoEnabled] = useState32(false);
11718
11736
  const ttsRef = useRef29(null);
11719
11737
  const sttRef = useRef29(null);
11720
11738
  const show = (id) => !visibleButtons || visibleButtons.has(id);
@@ -11728,11 +11746,11 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
11728
11746
  if (!editor) return;
11729
11747
  editor.chain().focus().insertContent(char).run();
11730
11748
  }, [editor]);
11731
- const [copySuccess, setCopySuccess] = useState31(false);
11732
- const [translateSource, setTranslateSource] = useState31("en");
11733
- const [translateTarget, setTranslateTarget] = useState31("hi");
11734
- const [translateStatus, setTranslateStatus] = useState31("");
11735
- const [showTranslateModal, setShowTranslateModal] = useState31(false);
11749
+ const [copySuccess, setCopySuccess] = useState32(false);
11750
+ const [translateSource, setTranslateSource] = useState32("en");
11751
+ const [translateTarget, setTranslateTarget] = useState32("hi");
11752
+ const [translateStatus, setTranslateStatus] = useState32("");
11753
+ const [showTranslateModal, setShowTranslateModal] = useState32(false);
11736
11754
  const handleCopy = useCallback15(async () => {
11737
11755
  if (!editor) return;
11738
11756
  const { from, to, empty } = editor.state.selection;
@@ -12341,7 +12359,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
12341
12359
  var Toolbar_default = Toolbar;
12342
12360
 
12343
12361
  // lib/RufousTextEditor/ImageToolbar.tsx
12344
- import React116, { useState as useState32, useEffect as useEffect27, useRef as useRef30 } from "react";
12362
+ import React116, { useState as useState33, useEffect as useEffect27, useRef as useRef30 } from "react";
12345
12363
  import { createPortal as createPortal5 } from "react-dom";
12346
12364
  var ALIGNMENTS = [
12347
12365
  { value: "left", label: "Left", icon: "\u2630" },
@@ -12349,17 +12367,17 @@ var ALIGNMENTS = [
12349
12367
  { value: "right", label: "Right", icon: "\u2263" }
12350
12368
  ];
12351
12369
  var ImagePropertiesModal = ({ editor, node, onClose }) => {
12352
- const [activeTab, setActiveTab] = useState32("image");
12353
- const [src, setSrc] = useState32(node?.attrs?.src || "");
12354
- const [title, setTitle] = useState32(node?.attrs?.title || "");
12355
- const [alt, setAlt] = useState32(node?.attrs?.alt || "");
12356
- const [link, setLink] = useState32("");
12357
- const [openInNewTab, setOpenInNewTab] = useState32(false);
12358
- const [width, setWidth] = useState32("");
12359
- const [height, setHeight] = useState32("");
12360
- const [lockRatio, setLockRatio] = useState32(true);
12361
- const [naturalWidth, setNaturalWidth] = useState32(0);
12362
- const [naturalHeight, setNaturalHeight] = useState32(0);
12370
+ const [activeTab, setActiveTab] = useState33("image");
12371
+ const [src, setSrc] = useState33(node?.attrs?.src || "");
12372
+ const [title, setTitle] = useState33(node?.attrs?.title || "");
12373
+ const [alt, setAlt] = useState33(node?.attrs?.alt || "");
12374
+ const [link, setLink] = useState33("");
12375
+ const [openInNewTab, setOpenInNewTab] = useState33(false);
12376
+ const [width, setWidth] = useState33("");
12377
+ const [height, setHeight] = useState33("");
12378
+ const [lockRatio, setLockRatio] = useState33(true);
12379
+ const [naturalWidth, setNaturalWidth] = useState33(0);
12380
+ const [naturalHeight, setNaturalHeight] = useState33(0);
12363
12381
  useEffect27(() => {
12364
12382
  if (src) {
12365
12383
  const img = new window.Image();
@@ -12478,11 +12496,11 @@ var ImagePropertiesModal = ({ editor, node, onClose }) => {
12478
12496
  ), "Open link in new tab")) : /* @__PURE__ */ React116.createElement(React116.Fragment, null, /* @__PURE__ */ React116.createElement("label", { className: "modal-label" }, "CSS Class"), /* @__PURE__ */ React116.createElement("input", { type: "text", className: "modal-input", placeholder: "e.g. rounded shadow" }), /* @__PURE__ */ React116.createElement("label", { className: "modal-label" }, "Inline Style"), /* @__PURE__ */ React116.createElement("input", { type: "text", className: "modal-input", placeholder: "e.g. border: 1px solid #ccc" }))))), /* @__PURE__ */ React116.createElement("div", { className: "modal-footer" }, /* @__PURE__ */ React116.createElement("div", { className: "modal-footer-left" }, /* @__PURE__ */ React116.createElement("button", { className: "modal-btn-cancel", onClick: onClose }, "Cancel"), /* @__PURE__ */ React116.createElement("button", { className: "modal-btn-delete", onClick: handleDelete }, "Delete")), /* @__PURE__ */ React116.createElement("button", { className: "modal-btn-apply", onClick: handleApply }, "Apply"))));
12479
12497
  };
12480
12498
  var ImageToolbar = ({ editor }) => {
12481
- const [showModal, setShowModal] = useState32(false);
12482
- const [showAlign, setShowAlign] = useState32(false);
12483
- const [showVAlign, setShowVAlign] = useState32(false);
12484
- const [copyStatus, setCopyStatus] = useState32("");
12485
- const [pos, setPos] = useState32(null);
12499
+ const [showModal, setShowModal] = useState33(false);
12500
+ const [showAlign, setShowAlign] = useState33(false);
12501
+ const [showVAlign, setShowVAlign] = useState33(false);
12502
+ const [copyStatus, setCopyStatus] = useState33("");
12503
+ const [pos, setPos] = useState33(null);
12486
12504
  const toolbarRef = useRef30(null);
12487
12505
  useEffect27(() => {
12488
12506
  if (!editor) return;
@@ -12620,7 +12638,7 @@ var ImageToolbar = ({ editor }) => {
12620
12638
  var ImageToolbar_default = ImageToolbar;
12621
12639
 
12622
12640
  // lib/RufousTextEditor/VideoToolbar.tsx
12623
- import React117, { useState as useState33, useEffect as useEffect28, useRef as useRef31 } from "react";
12641
+ import React117, { useState as useState34, useEffect as useEffect28, useRef as useRef31 } from "react";
12624
12642
  import { createPortal as createPortal6 } from "react-dom";
12625
12643
  var ALIGNMENTS2 = [
12626
12644
  { value: "left", label: "Left", icon: "\u2630" },
@@ -12629,10 +12647,10 @@ var ALIGNMENTS2 = [
12629
12647
  ];
12630
12648
  var VIDEO_TYPES = ["youtube", "video"];
12631
12649
  var VideoPropertiesModal = ({ editor, node, nodeType, onClose }) => {
12632
- const [src, setSrc] = useState33(node?.attrs?.src || "");
12633
- const [width, setWidth] = useState33(String(node?.attrs?.width || 640));
12634
- const [height, setHeight] = useState33(String(node?.attrs?.height || 360));
12635
- const [lockRatio, setLockRatio] = useState33(true);
12650
+ const [src, setSrc] = useState34(node?.attrs?.src || "");
12651
+ const [width, setWidth] = useState34(String(node?.attrs?.width || 640));
12652
+ const [height, setHeight] = useState34(String(node?.attrs?.height || 360));
12653
+ const [lockRatio, setLockRatio] = useState34(true);
12636
12654
  const handleWidthChange = (val) => {
12637
12655
  setWidth(val);
12638
12656
  if (lockRatio) {
@@ -12730,11 +12748,11 @@ var VideoPropertiesModal = ({ editor, node, nodeType, onClose }) => {
12730
12748
  )))), /* @__PURE__ */ React117.createElement("div", { className: "modal-footer" }, /* @__PURE__ */ React117.createElement("div", { className: "modal-footer-left" }, /* @__PURE__ */ React117.createElement("button", { className: "modal-btn-cancel", onClick: onClose }, "Cancel"), /* @__PURE__ */ React117.createElement("button", { className: "modal-btn-delete", onClick: handleDelete }, "Delete")), /* @__PURE__ */ React117.createElement("button", { className: "modal-btn-apply", onClick: handleApply }, "Apply"))));
12731
12749
  };
12732
12750
  var VideoToolbar = ({ editor }) => {
12733
- const [showModal, setShowModal] = useState33(false);
12734
- const [showSize, setShowSize] = useState33(false);
12735
- const [showAlign, setShowAlign] = useState33(false);
12736
- const [copyStatus, setCopyStatus] = useState33("");
12737
- const [pos, setPos] = useState33(null);
12751
+ const [showModal, setShowModal] = useState34(false);
12752
+ const [showSize, setShowSize] = useState34(false);
12753
+ const [showAlign, setShowAlign] = useState34(false);
12754
+ const [copyStatus, setCopyStatus] = useState34("");
12755
+ const [pos, setPos] = useState34(null);
12738
12756
  const toolbarRef = useRef31(null);
12739
12757
  useEffect28(() => {
12740
12758
  if (!editor) return;
@@ -12860,7 +12878,7 @@ var VideoToolbar = ({ editor }) => {
12860
12878
  var VideoToolbar_default = VideoToolbar;
12861
12879
 
12862
12880
  // lib/RufousTextEditor/TableToolbar.tsx
12863
- import React118, { useState as useState34, useEffect as useEffect29, useRef as useRef32 } from "react";
12881
+ import React118, { useState as useState35, useEffect as useEffect29, useRef as useRef32 } from "react";
12864
12882
  import { createPortal as createPortal7 } from "react-dom";
12865
12883
  var IconAddRowBefore = () => /* @__PURE__ */ React118.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React118.createElement("path", { d: "M20 3H4c-.55 0-1 .45-1 1v16c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zm-1 8H5V5h14v6zm0 8H5v-6h14v6z" }), /* @__PURE__ */ React118.createElement("path", { d: "M9 6h2v1.5h1.5v2H11V11H9V9.5H7.5v-2H9z" }));
12866
12884
  var IconAddRowAfter = () => /* @__PURE__ */ React118.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React118.createElement("path", { d: "M20 3H4c-.55 0-1 .45-1 1v16c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zm-1 8H5V5h14v6zm0 8H5v-6h14v6z" }), /* @__PURE__ */ React118.createElement("path", { d: "M9 14h2v1.5h1.5v2H11V19H9v-1.5H7.5v-2H9z" }));
@@ -12873,7 +12891,7 @@ var IconMergeCells = () => /* @__PURE__ */ React118.createElement("svg", { width
12873
12891
  var IconSplitCell = () => /* @__PURE__ */ React118.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React118.createElement("path", { d: "M3 3h18v18H3V3zm2 2v5h6V5H5zm8 0v5h6V5h-6zM5 13v6h6v-6H5zm8 0v6h6v-6h-6z" }));
12874
12892
  var IconToggleHeader = () => /* @__PURE__ */ React118.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React118.createElement("path", { d: "M3 3h18v18H3V3zm2 2v4h14V5H5zm0 6v8h14v-8H5z" }), /* @__PURE__ */ React118.createElement("rect", { x: "5", y: "5", width: "14", height: "4", opacity: "0.4" }));
12875
12893
  var TableToolbar = ({ editor }) => {
12876
- const [pos, setPos] = useState34(null);
12894
+ const [pos, setPos] = useState35(null);
12877
12895
  const toolbarRef = useRef32(null);
12878
12896
  useEffect29(() => {
12879
12897
  if (!editor) return;
@@ -13240,13 +13258,13 @@ var RufousTextEditor = ({
13240
13258
  };
13241
13259
  }, [editor]);
13242
13260
  const setLinkRef = useRef33(null);
13243
- const [linkModalOpen, setLinkModalOpen] = useState35(false);
13244
- const [linkUrl, setLinkUrl] = useState35("");
13245
- const [linkText, setLinkText] = useState35("");
13246
- const [linkClassName, setLinkClassName] = useState35("");
13247
- const [linkNewTab, setLinkNewTab] = useState35(true);
13248
- const [linkNoFollow, setLinkNoFollow] = useState35(true);
13249
- const [linkSelection, setLinkSelection] = useState35(null);
13261
+ const [linkModalOpen, setLinkModalOpen] = useState36(false);
13262
+ const [linkUrl, setLinkUrl] = useState36("");
13263
+ const [linkText, setLinkText] = useState36("");
13264
+ const [linkClassName, setLinkClassName] = useState36("");
13265
+ const [linkNewTab, setLinkNewTab] = useState36(true);
13266
+ const [linkNoFollow, setLinkNoFollow] = useState36(true);
13267
+ const [linkSelection, setLinkSelection] = useState36(null);
13250
13268
  const setLink = useCallback16(() => {
13251
13269
  if (!editor) return;
13252
13270
  const attrs = editor.getAttributes("link");
@@ -13372,7 +13390,7 @@ var RufousTextEditor = ({
13372
13390
  setLinkSelection(null);
13373
13391
  editor?.chain().focus().run();
13374
13392
  }, [editor]);
13375
- const [saveStatus, setSaveStatus] = useState35("");
13393
+ const [saveStatus, setSaveStatus] = useState36("");
13376
13394
  const handleSave = useCallback16(() => {
13377
13395
  if (!editor || !onSaveProp) return;
13378
13396
  onSaveProp(editor.getHTML(), editor.getJSON());
@@ -13384,7 +13402,7 @@ var RufousTextEditor = ({
13384
13402
  onExportProp(editor.getHTML(), editor.getJSON());
13385
13403
  }, [editor, onExportProp]);
13386
13404
  const providerValue = useMemo5(() => ({ editor }), [editor]);
13387
- const [isFullscreen, setIsFullscreen] = useState35(false);
13405
+ const [isFullscreen, setIsFullscreen] = useState36(false);
13388
13406
  const toggleFullscreen = useCallback16(() => setIsFullscreen((prev) => !prev), []);
13389
13407
  const wrapperJsx = /* @__PURE__ */ React119.createElement(
13390
13408
  "div",
@@ -13707,10 +13725,10 @@ function getCitiesByName(name, exact = false) {
13707
13725
  }
13708
13726
 
13709
13727
  // lib/utils/useLocationSearch.ts
13710
- import { useState as useState36, useEffect as useEffect31, useRef as useRef34, useCallback as useCallback17 } from "react";
13728
+ import { useState as useState37, useEffect as useEffect31, useRef as useRef34, useCallback as useCallback17 } from "react";
13711
13729
  function useDebounced(searcher, debounceMs) {
13712
- const [query, setQuery] = useState36("");
13713
- const [results, setResults] = useState36([]);
13730
+ const [query, setQuery] = useState37("");
13731
+ const [results, setResults] = useState37([]);
13714
13732
  const timer = useRef34(null);
13715
13733
  useEffect31(() => () => {
13716
13734
  if (timer.current) clearTimeout(timer.current);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rufous/ui",
3
3
  "private": false,
4
- "version": "0.3.21",
4
+ "version": "0.3.23",
5
5
  "type": "module",
6
6
  "description": "Experimental: A lightweight React UI component library (Beta)",
7
7
  "style": "./dist/main.css",