@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 +68 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -5
- package/dist/index.d.ts +20 -5
- package/dist/index.js +68 -29
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1000,20 +1000,35 @@ interface CategoryTreeSelectLabels {
|
|
|
1000
1000
|
/** Text shown when categories are selected, receives count as parameter */
|
|
1001
1001
|
selectedText?: (count: number) => string;
|
|
1002
1002
|
}
|
|
1003
|
-
interface
|
|
1003
|
+
interface CategoryTreeSelectBaseProps {
|
|
1004
1004
|
categories: Category[];
|
|
1005
|
-
value?: number[];
|
|
1006
|
-
onChange?: (selectedIds: number[]) => void;
|
|
1007
1005
|
placeholder?: string;
|
|
1008
1006
|
disabled?: boolean;
|
|
1009
1007
|
/** When true, renders as a read-only tree view without select functionality */
|
|
1010
1008
|
viewOnly?: boolean;
|
|
1011
|
-
/** Default expanded state for all nodes
|
|
1009
|
+
/** Default expanded state for all nodes */
|
|
1012
1010
|
defaultExpanded?: boolean;
|
|
1013
1011
|
/** i18n labels for localization */
|
|
1014
1012
|
labels?: CategoryTreeSelectLabels;
|
|
1013
|
+
/** When true, render tree directly without dropdown trigger */
|
|
1014
|
+
inline?: boolean;
|
|
1015
|
+
/** Callback when a node is clicked (useful for navigation) */
|
|
1016
|
+
onNodeClick?: (node: Category) => void;
|
|
1017
|
+
/** Custom class for the tree container */
|
|
1018
|
+
className?: string;
|
|
1019
|
+
}
|
|
1020
|
+
interface CategoryTreeSelectMultiProps extends CategoryTreeSelectBaseProps {
|
|
1021
|
+
singleSelect?: false;
|
|
1022
|
+
value?: number[];
|
|
1023
|
+
onChange?: (selectedIds: number[]) => void;
|
|
1024
|
+
}
|
|
1025
|
+
interface CategoryTreeSelectSingleProps extends CategoryTreeSelectBaseProps {
|
|
1026
|
+
singleSelect: true;
|
|
1027
|
+
value?: number | null;
|
|
1028
|
+
onChange?: (selectedId: number | null) => void;
|
|
1015
1029
|
}
|
|
1016
|
-
|
|
1030
|
+
type CategoryTreeSelectProps = CategoryTreeSelectMultiProps | CategoryTreeSelectSingleProps;
|
|
1031
|
+
declare function CategoryTreeSelect(props: CategoryTreeSelectProps): react_jsx_runtime.JSX.Element;
|
|
1017
1032
|
|
|
1018
1033
|
type Fit = "cover" | "contain";
|
|
1019
1034
|
interface SmartImageProps {
|
package/dist/index.d.ts
CHANGED
|
@@ -1000,20 +1000,35 @@ interface CategoryTreeSelectLabels {
|
|
|
1000
1000
|
/** Text shown when categories are selected, receives count as parameter */
|
|
1001
1001
|
selectedText?: (count: number) => string;
|
|
1002
1002
|
}
|
|
1003
|
-
interface
|
|
1003
|
+
interface CategoryTreeSelectBaseProps {
|
|
1004
1004
|
categories: Category[];
|
|
1005
|
-
value?: number[];
|
|
1006
|
-
onChange?: (selectedIds: number[]) => void;
|
|
1007
1005
|
placeholder?: string;
|
|
1008
1006
|
disabled?: boolean;
|
|
1009
1007
|
/** When true, renders as a read-only tree view without select functionality */
|
|
1010
1008
|
viewOnly?: boolean;
|
|
1011
|
-
/** Default expanded state for all nodes
|
|
1009
|
+
/** Default expanded state for all nodes */
|
|
1012
1010
|
defaultExpanded?: boolean;
|
|
1013
1011
|
/** i18n labels for localization */
|
|
1014
1012
|
labels?: CategoryTreeSelectLabels;
|
|
1013
|
+
/** When true, render tree directly without dropdown trigger */
|
|
1014
|
+
inline?: boolean;
|
|
1015
|
+
/** Callback when a node is clicked (useful for navigation) */
|
|
1016
|
+
onNodeClick?: (node: Category) => void;
|
|
1017
|
+
/** Custom class for the tree container */
|
|
1018
|
+
className?: string;
|
|
1019
|
+
}
|
|
1020
|
+
interface CategoryTreeSelectMultiProps extends CategoryTreeSelectBaseProps {
|
|
1021
|
+
singleSelect?: false;
|
|
1022
|
+
value?: number[];
|
|
1023
|
+
onChange?: (selectedIds: number[]) => void;
|
|
1024
|
+
}
|
|
1025
|
+
interface CategoryTreeSelectSingleProps extends CategoryTreeSelectBaseProps {
|
|
1026
|
+
singleSelect: true;
|
|
1027
|
+
value?: number | null;
|
|
1028
|
+
onChange?: (selectedId: number | null) => void;
|
|
1015
1029
|
}
|
|
1016
|
-
|
|
1030
|
+
type CategoryTreeSelectProps = CategoryTreeSelectMultiProps | CategoryTreeSelectSingleProps;
|
|
1031
|
+
declare function CategoryTreeSelect(props: CategoryTreeSelectProps): react_jsx_runtime.JSX.Element;
|
|
1017
1032
|
|
|
1018
1033
|
type Fit = "cover" | "contain";
|
|
1019
1034
|
interface SmartImageProps {
|
package/dist/index.js
CHANGED
|
@@ -7951,19 +7951,23 @@ var defaultLabels = {
|
|
|
7951
7951
|
emptyText: "No categories",
|
|
7952
7952
|
selectedText: (count) => `${count} selected`
|
|
7953
7953
|
};
|
|
7954
|
-
function CategoryTreeSelect({
|
|
7955
|
-
|
|
7956
|
-
|
|
7957
|
-
|
|
7958
|
-
|
|
7959
|
-
|
|
7960
|
-
|
|
7961
|
-
|
|
7962
|
-
|
|
7963
|
-
|
|
7954
|
+
function CategoryTreeSelect(props) {
|
|
7955
|
+
const {
|
|
7956
|
+
categories,
|
|
7957
|
+
placeholder = "Select category",
|
|
7958
|
+
disabled,
|
|
7959
|
+
viewOnly = false,
|
|
7960
|
+
defaultExpanded = false,
|
|
7961
|
+
labels,
|
|
7962
|
+
inline = false,
|
|
7963
|
+
onNodeClick,
|
|
7964
|
+
className,
|
|
7965
|
+
singleSelect = false
|
|
7966
|
+
} = props;
|
|
7964
7967
|
const [isOpen, setIsOpen] = useState25(false);
|
|
7965
7968
|
const [expandedNodes, setExpandedNodes] = useState25(/* @__PURE__ */ new Set());
|
|
7966
7969
|
const mergedLabels = { ...defaultLabels, ...labels };
|
|
7970
|
+
const valueArray = singleSelect ? props.value != null ? [props.value] : [] : props.value || [];
|
|
7967
7971
|
const parentCategories = categories.filter((c) => !c.parent_id);
|
|
7968
7972
|
const childrenMap = /* @__PURE__ */ new Map();
|
|
7969
7973
|
categories.forEach((cat) => {
|
|
@@ -7975,11 +7979,11 @@ function CategoryTreeSelect({
|
|
|
7975
7979
|
}
|
|
7976
7980
|
});
|
|
7977
7981
|
useEffect15(() => {
|
|
7978
|
-
if (viewOnly && defaultExpanded) {
|
|
7982
|
+
if ((viewOnly || inline) && defaultExpanded) {
|
|
7979
7983
|
const allParentIds = categories.filter((c) => childrenMap.has(c.id)).map((c) => c.id);
|
|
7980
7984
|
setExpandedNodes(new Set(allParentIds));
|
|
7981
7985
|
}
|
|
7982
|
-
}, [viewOnly, defaultExpanded, categories]);
|
|
7986
|
+
}, [viewOnly, inline, defaultExpanded, categories]);
|
|
7983
7987
|
const toggleExpand = (id) => {
|
|
7984
7988
|
const newExpanded = new Set(expandedNodes);
|
|
7985
7989
|
if (newExpanded.has(id)) {
|
|
@@ -7990,25 +7994,41 @@ function CategoryTreeSelect({
|
|
|
7990
7994
|
setExpandedNodes(newExpanded);
|
|
7991
7995
|
};
|
|
7992
7996
|
const handleSelect = (categoryId, category) => {
|
|
7993
|
-
if (viewOnly
|
|
7994
|
-
|
|
7995
|
-
if (
|
|
7996
|
-
|
|
7997
|
-
const
|
|
7998
|
-
|
|
7997
|
+
if (viewOnly) return;
|
|
7998
|
+
onNodeClick?.(category);
|
|
7999
|
+
if (!props.onChange) return;
|
|
8000
|
+
if (singleSelect) {
|
|
8001
|
+
const onChange = props.onChange;
|
|
8002
|
+
const currentValue = props.value;
|
|
8003
|
+
if (currentValue === categoryId) {
|
|
8004
|
+
onChange(null);
|
|
8005
|
+
} else {
|
|
8006
|
+
onChange(categoryId);
|
|
8007
|
+
}
|
|
8008
|
+
if (!inline) {
|
|
8009
|
+
setIsOpen(false);
|
|
8010
|
+
}
|
|
7999
8011
|
} else {
|
|
8000
|
-
|
|
8001
|
-
|
|
8002
|
-
|
|
8012
|
+
const onChange = props.onChange;
|
|
8013
|
+
const newSelected = new Set(valueArray);
|
|
8014
|
+
if (newSelected.has(categoryId)) {
|
|
8015
|
+
newSelected.delete(categoryId);
|
|
8016
|
+
const children = childrenMap.get(categoryId) || [];
|
|
8017
|
+
children.forEach((child) => newSelected.delete(child.id));
|
|
8018
|
+
} else {
|
|
8019
|
+
newSelected.add(categoryId);
|
|
8020
|
+
if (category.parent_id) {
|
|
8021
|
+
newSelected.add(category.parent_id);
|
|
8022
|
+
}
|
|
8003
8023
|
}
|
|
8024
|
+
onChange(Array.from(newSelected));
|
|
8004
8025
|
}
|
|
8005
|
-
onChange(Array.from(newSelected));
|
|
8006
8026
|
};
|
|
8007
8027
|
const renderCategory = (category, level = 0) => {
|
|
8008
8028
|
const children = childrenMap.get(category.id) || [];
|
|
8009
8029
|
const hasChildren = children.length > 0;
|
|
8010
8030
|
const isExpanded = expandedNodes.has(category.id);
|
|
8011
|
-
const isSelected =
|
|
8031
|
+
const isSelected = valueArray.includes(category.id);
|
|
8012
8032
|
return /* @__PURE__ */ jsxs31("div", { children: [
|
|
8013
8033
|
/* @__PURE__ */ jsxs31(
|
|
8014
8034
|
"div",
|
|
@@ -8037,8 +8057,23 @@ function CategoryTreeSelect({
|
|
|
8037
8057
|
viewOnly ? (
|
|
8038
8058
|
// View-only mode: just display the name
|
|
8039
8059
|
/* @__PURE__ */ jsx36("span", { className: "text-sm", children: category.name })
|
|
8060
|
+
) : singleSelect ? (
|
|
8061
|
+
// Single select mode: radio-style indicator
|
|
8062
|
+
/* @__PURE__ */ jsxs31("div", { onClick: () => handleSelect(category.id, category), className: "flex items-center gap-2 flex-1", children: [
|
|
8063
|
+
/* @__PURE__ */ jsx36(
|
|
8064
|
+
"div",
|
|
8065
|
+
{
|
|
8066
|
+
className: cn(
|
|
8067
|
+
"w-4 h-4 border-2 rounded-full flex items-center justify-center transition-colors",
|
|
8068
|
+
isSelected ? "border-primary" : "border-muted-foreground/30"
|
|
8069
|
+
),
|
|
8070
|
+
children: isSelected && /* @__PURE__ */ jsx36("div", { className: "w-2 h-2 rounded-full bg-primary" })
|
|
8071
|
+
}
|
|
8072
|
+
),
|
|
8073
|
+
/* @__PURE__ */ jsx36("span", { className: cn("text-sm", isSelected && "font-medium text-primary"), children: category.name })
|
|
8074
|
+
] })
|
|
8040
8075
|
) : (
|
|
8041
|
-
//
|
|
8076
|
+
// Multi select mode: checkbox-style indicator
|
|
8042
8077
|
/* @__PURE__ */ jsxs31("div", { onClick: () => handleSelect(category.id, category), className: "flex items-center gap-2 flex-1", children: [
|
|
8043
8078
|
/* @__PURE__ */ jsx36(
|
|
8044
8079
|
"div",
|
|
@@ -8059,12 +8094,16 @@ function CategoryTreeSelect({
|
|
|
8059
8094
|
hasChildren && isExpanded && /* @__PURE__ */ jsx36("div", { children: children.map((child) => renderCategory(child, level + 1)) })
|
|
8060
8095
|
] }, category.id);
|
|
8061
8096
|
};
|
|
8097
|
+
const renderTreeContent = () => /* @__PURE__ */ jsx36(Fragment11, { children: parentCategories.length === 0 ? /* @__PURE__ */ jsx36("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: mergedLabels.emptyText }) : parentCategories.map((cat) => renderCategory(cat)) });
|
|
8062
8098
|
if (viewOnly) {
|
|
8063
|
-
return /* @__PURE__ */ jsx36("div", { className: cn("rounded-md border bg-background p-2", disabled && "opacity-50"
|
|
8099
|
+
return /* @__PURE__ */ jsx36("div", { className: cn("rounded-md border bg-background p-2", disabled && "opacity-50", className), children: renderTreeContent() });
|
|
8100
|
+
}
|
|
8101
|
+
if (inline) {
|
|
8102
|
+
return /* @__PURE__ */ jsx36("div", { className: cn("rounded-md border bg-background p-2", disabled && "opacity-50 pointer-events-none", className), children: renderTreeContent() });
|
|
8064
8103
|
}
|
|
8065
|
-
const selectedCount =
|
|
8066
|
-
const displayText = selectedCount > 0 ? mergedLabels.selectedText(selectedCount) : placeholder;
|
|
8067
|
-
return /* @__PURE__ */ jsxs31("div", { className: "relative", children: [
|
|
8104
|
+
const selectedCount = valueArray.length;
|
|
8105
|
+
const displayText = singleSelect ? selectedCount > 0 ? categories.find((c) => c.id === valueArray[0])?.name || placeholder : placeholder : selectedCount > 0 ? mergedLabels.selectedText(selectedCount) : placeholder;
|
|
8106
|
+
return /* @__PURE__ */ jsxs31("div", { className: cn("relative", className), children: [
|
|
8068
8107
|
/* @__PURE__ */ jsxs31(
|
|
8069
8108
|
"button",
|
|
8070
8109
|
{
|
|
@@ -8096,7 +8135,7 @@ function CategoryTreeSelect({
|
|
|
8096
8135
|
"rounded-md border bg-popover text-popover-foreground shadow-md",
|
|
8097
8136
|
"backdrop-blur-sm bg-popover/95 border-border/60"
|
|
8098
8137
|
),
|
|
8099
|
-
children: /* @__PURE__ */ jsx36("div", { className: "p-1", children:
|
|
8138
|
+
children: /* @__PURE__ */ jsx36("div", { className: "p-1", children: renderTreeContent() })
|
|
8100
8139
|
}
|
|
8101
8140
|
)
|
|
8102
8141
|
] })
|