@underverse-ui/underverse 0.2.44 → 0.2.45

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/index.cjs CHANGED
@@ -8123,19 +8123,23 @@ var defaultLabels = {
8123
8123
  emptyText: "No categories",
8124
8124
  selectedText: (count) => `${count} selected`
8125
8125
  };
8126
- function CategoryTreeSelect({
8127
- categories,
8128
- value = [],
8129
- onChange,
8130
- placeholder = "Select category",
8131
- disabled,
8132
- viewOnly = false,
8133
- defaultExpanded = false,
8134
- labels
8135
- }) {
8126
+ function CategoryTreeSelect(props) {
8127
+ const {
8128
+ categories,
8129
+ placeholder = "Select category",
8130
+ disabled,
8131
+ viewOnly = false,
8132
+ defaultExpanded = false,
8133
+ labels,
8134
+ inline = false,
8135
+ onNodeClick,
8136
+ className,
8137
+ singleSelect = false
8138
+ } = props;
8136
8139
  const [isOpen, setIsOpen] = (0, import_react18.useState)(false);
8137
8140
  const [expandedNodes, setExpandedNodes] = (0, import_react18.useState)(/* @__PURE__ */ new Set());
8138
8141
  const mergedLabels = { ...defaultLabels, ...labels };
8142
+ const valueArray = singleSelect ? props.value != null ? [props.value] : [] : props.value || [];
8139
8143
  const parentCategories = categories.filter((c) => !c.parent_id);
8140
8144
  const childrenMap = /* @__PURE__ */ new Map();
8141
8145
  categories.forEach((cat) => {
@@ -8147,11 +8151,11 @@ function CategoryTreeSelect({
8147
8151
  }
8148
8152
  });
8149
8153
  (0, import_react18.useEffect)(() => {
8150
- if (viewOnly && defaultExpanded) {
8154
+ if ((viewOnly || inline) && defaultExpanded) {
8151
8155
  const allParentIds = categories.filter((c) => childrenMap.has(c.id)).map((c) => c.id);
8152
8156
  setExpandedNodes(new Set(allParentIds));
8153
8157
  }
8154
- }, [viewOnly, defaultExpanded, categories]);
8158
+ }, [viewOnly, inline, defaultExpanded, categories]);
8155
8159
  const toggleExpand = (id) => {
8156
8160
  const newExpanded = new Set(expandedNodes);
8157
8161
  if (newExpanded.has(id)) {
@@ -8162,25 +8166,41 @@ function CategoryTreeSelect({
8162
8166
  setExpandedNodes(newExpanded);
8163
8167
  };
8164
8168
  const handleSelect = (categoryId, category) => {
8165
- if (viewOnly || !onChange) return;
8166
- const newSelected = new Set(value);
8167
- if (newSelected.has(categoryId)) {
8168
- newSelected.delete(categoryId);
8169
- const children = childrenMap.get(categoryId) || [];
8170
- children.forEach((child) => newSelected.delete(child.id));
8169
+ if (viewOnly) return;
8170
+ onNodeClick?.(category);
8171
+ if (!props.onChange) return;
8172
+ if (singleSelect) {
8173
+ const onChange = props.onChange;
8174
+ const currentValue = props.value;
8175
+ if (currentValue === categoryId) {
8176
+ onChange(null);
8177
+ } else {
8178
+ onChange(categoryId);
8179
+ }
8180
+ if (!inline) {
8181
+ setIsOpen(false);
8182
+ }
8171
8183
  } else {
8172
- newSelected.add(categoryId);
8173
- if (category.parent_id) {
8174
- newSelected.add(category.parent_id);
8184
+ const onChange = props.onChange;
8185
+ const newSelected = new Set(valueArray);
8186
+ if (newSelected.has(categoryId)) {
8187
+ newSelected.delete(categoryId);
8188
+ const children = childrenMap.get(categoryId) || [];
8189
+ children.forEach((child) => newSelected.delete(child.id));
8190
+ } else {
8191
+ newSelected.add(categoryId);
8192
+ if (category.parent_id) {
8193
+ newSelected.add(category.parent_id);
8194
+ }
8175
8195
  }
8196
+ onChange(Array.from(newSelected));
8176
8197
  }
8177
- onChange(Array.from(newSelected));
8178
8198
  };
8179
8199
  const renderCategory = (category, level = 0) => {
8180
8200
  const children = childrenMap.get(category.id) || [];
8181
8201
  const hasChildren = children.length > 0;
8182
8202
  const isExpanded = expandedNodes.has(category.id);
8183
- const isSelected = value.includes(category.id);
8203
+ const isSelected = valueArray.includes(category.id);
8184
8204
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { children: [
8185
8205
  /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
8186
8206
  "div",
@@ -8209,8 +8229,23 @@ function CategoryTreeSelect({
8209
8229
  viewOnly ? (
8210
8230
  // View-only mode: just display the name
8211
8231
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "text-sm", children: category.name })
8232
+ ) : singleSelect ? (
8233
+ // Single select mode: radio-style indicator
8234
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { onClick: () => handleSelect(category.id, category), className: "flex items-center gap-2 flex-1", children: [
8235
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8236
+ "div",
8237
+ {
8238
+ className: cn(
8239
+ "w-4 h-4 border-2 rounded-full flex items-center justify-center transition-colors",
8240
+ isSelected ? "border-primary" : "border-muted-foreground/30"
8241
+ ),
8242
+ children: isSelected && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "w-2 h-2 rounded-full bg-primary" })
8243
+ }
8244
+ ),
8245
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: cn("text-sm", isSelected && "font-medium text-primary"), children: category.name })
8246
+ ] })
8212
8247
  ) : (
8213
- // Select mode: clickable with checkbox
8248
+ // Multi select mode: checkbox-style indicator
8214
8249
  /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { onClick: () => handleSelect(category.id, category), className: "flex items-center gap-2 flex-1", children: [
8215
8250
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8216
8251
  "div",
@@ -8231,12 +8266,16 @@ function CategoryTreeSelect({
8231
8266
  hasChildren && isExpanded && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { children: children.map((child) => renderCategory(child, level + 1)) })
8232
8267
  ] }, category.id);
8233
8268
  };
8269
+ const renderTreeContent = () => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_jsx_runtime36.Fragment, { children: parentCategories.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: mergedLabels.emptyText }) : parentCategories.map((cat) => renderCategory(cat)) });
8234
8270
  if (viewOnly) {
8235
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: cn("rounded-md border bg-background p-2", disabled && "opacity-50"), children: parentCategories.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: mergedLabels.emptyText }) : parentCategories.map((cat) => renderCategory(cat)) });
8271
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: cn("rounded-md border bg-background p-2", disabled && "opacity-50", className), children: renderTreeContent() });
8272
+ }
8273
+ if (inline) {
8274
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: cn("rounded-md border bg-background p-2", disabled && "opacity-50 pointer-events-none", className), children: renderTreeContent() });
8236
8275
  }
8237
- const selectedCount = value.length;
8238
- const displayText = selectedCount > 0 ? mergedLabels.selectedText(selectedCount) : placeholder;
8239
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "relative", children: [
8276
+ const selectedCount = valueArray.length;
8277
+ const displayText = singleSelect ? selectedCount > 0 ? categories.find((c) => c.id === valueArray[0])?.name || placeholder : placeholder : selectedCount > 0 ? mergedLabels.selectedText(selectedCount) : placeholder;
8278
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: cn("relative", className), children: [
8240
8279
  /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
8241
8280
  "button",
8242
8281
  {
@@ -8268,7 +8307,7 @@ function CategoryTreeSelect({
8268
8307
  "rounded-md border bg-popover text-popover-foreground shadow-md",
8269
8308
  "backdrop-blur-sm bg-popover/95 border-border/60"
8270
8309
  ),
8271
- children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "p-1", children: parentCategories.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: mergedLabels.emptyText }) : parentCategories.map((cat) => renderCategory(cat)) })
8310
+ children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "p-1", children: renderTreeContent() })
8272
8311
  }
8273
8312
  )
8274
8313
  ] })