@underverse-ui/underverse 0.2.43 → 0.2.44
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 +50 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -4
- package/dist/index.d.ts +16 -4
- package/dist/index.js +58 -41
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -994,14 +994,26 @@ interface Category {
|
|
|
994
994
|
name: string;
|
|
995
995
|
parent_id?: number | null;
|
|
996
996
|
}
|
|
997
|
+
interface CategoryTreeSelectLabels {
|
|
998
|
+
/** Text shown when no categories available */
|
|
999
|
+
emptyText?: string;
|
|
1000
|
+
/** Text shown when categories are selected, receives count as parameter */
|
|
1001
|
+
selectedText?: (count: number) => string;
|
|
1002
|
+
}
|
|
997
1003
|
interface CategoryTreeSelectProps {
|
|
998
1004
|
categories: Category[];
|
|
999
|
-
value
|
|
1000
|
-
onChange
|
|
1005
|
+
value?: number[];
|
|
1006
|
+
onChange?: (selectedIds: number[]) => void;
|
|
1001
1007
|
placeholder?: string;
|
|
1002
1008
|
disabled?: boolean;
|
|
1003
|
-
|
|
1004
|
-
|
|
1009
|
+
/** When true, renders as a read-only tree view without select functionality */
|
|
1010
|
+
viewOnly?: boolean;
|
|
1011
|
+
/** Default expanded state for all nodes in viewOnly mode */
|
|
1012
|
+
defaultExpanded?: boolean;
|
|
1013
|
+
/** i18n labels for localization */
|
|
1014
|
+
labels?: CategoryTreeSelectLabels;
|
|
1015
|
+
}
|
|
1016
|
+
declare function CategoryTreeSelect({ categories, value, onChange, placeholder, disabled, viewOnly, defaultExpanded, labels, }: CategoryTreeSelectProps): react_jsx_runtime.JSX.Element;
|
|
1005
1017
|
|
|
1006
1018
|
type Fit = "cover" | "contain";
|
|
1007
1019
|
interface SmartImageProps {
|
package/dist/index.d.ts
CHANGED
|
@@ -994,14 +994,26 @@ interface Category {
|
|
|
994
994
|
name: string;
|
|
995
995
|
parent_id?: number | null;
|
|
996
996
|
}
|
|
997
|
+
interface CategoryTreeSelectLabels {
|
|
998
|
+
/** Text shown when no categories available */
|
|
999
|
+
emptyText?: string;
|
|
1000
|
+
/** Text shown when categories are selected, receives count as parameter */
|
|
1001
|
+
selectedText?: (count: number) => string;
|
|
1002
|
+
}
|
|
997
1003
|
interface CategoryTreeSelectProps {
|
|
998
1004
|
categories: Category[];
|
|
999
|
-
value
|
|
1000
|
-
onChange
|
|
1005
|
+
value?: number[];
|
|
1006
|
+
onChange?: (selectedIds: number[]) => void;
|
|
1001
1007
|
placeholder?: string;
|
|
1002
1008
|
disabled?: boolean;
|
|
1003
|
-
|
|
1004
|
-
|
|
1009
|
+
/** When true, renders as a read-only tree view without select functionality */
|
|
1010
|
+
viewOnly?: boolean;
|
|
1011
|
+
/** Default expanded state for all nodes in viewOnly mode */
|
|
1012
|
+
defaultExpanded?: boolean;
|
|
1013
|
+
/** i18n labels for localization */
|
|
1014
|
+
labels?: CategoryTreeSelectLabels;
|
|
1015
|
+
}
|
|
1016
|
+
declare function CategoryTreeSelect({ categories, value, onChange, placeholder, disabled, viewOnly, defaultExpanded, labels, }: CategoryTreeSelectProps): react_jsx_runtime.JSX.Element;
|
|
1005
1017
|
|
|
1006
1018
|
type Fit = "cover" | "contain";
|
|
1007
1019
|
interface SmartImageProps {
|
package/dist/index.js
CHANGED
|
@@ -7944,12 +7944,26 @@ function OverlayControls({
|
|
|
7944
7944
|
}
|
|
7945
7945
|
|
|
7946
7946
|
// ../../components/ui/CategoryTreeSelect.tsx
|
|
7947
|
-
import { useState as useState25 } from "react";
|
|
7947
|
+
import { useState as useState25, useEffect as useEffect15 } from "react";
|
|
7948
7948
|
import { ChevronRight as ChevronRight5, ChevronDown as ChevronDown3, Check as Check6 } from "lucide-react";
|
|
7949
7949
|
import { Fragment as Fragment11, jsx as jsx36, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
7950
|
-
|
|
7950
|
+
var defaultLabels = {
|
|
7951
|
+
emptyText: "No categories",
|
|
7952
|
+
selectedText: (count) => `${count} selected`
|
|
7953
|
+
};
|
|
7954
|
+
function CategoryTreeSelect({
|
|
7955
|
+
categories,
|
|
7956
|
+
value = [],
|
|
7957
|
+
onChange,
|
|
7958
|
+
placeholder = "Select category",
|
|
7959
|
+
disabled,
|
|
7960
|
+
viewOnly = false,
|
|
7961
|
+
defaultExpanded = false,
|
|
7962
|
+
labels
|
|
7963
|
+
}) {
|
|
7951
7964
|
const [isOpen, setIsOpen] = useState25(false);
|
|
7952
7965
|
const [expandedNodes, setExpandedNodes] = useState25(/* @__PURE__ */ new Set());
|
|
7966
|
+
const mergedLabels = { ...defaultLabels, ...labels };
|
|
7953
7967
|
const parentCategories = categories.filter((c) => !c.parent_id);
|
|
7954
7968
|
const childrenMap = /* @__PURE__ */ new Map();
|
|
7955
7969
|
categories.forEach((cat) => {
|
|
@@ -7960,6 +7974,12 @@ function CategoryTreeSelect({ categories, value, onChange, placeholder = "Ch\u1E
|
|
|
7960
7974
|
childrenMap.get(cat.parent_id).push(cat);
|
|
7961
7975
|
}
|
|
7962
7976
|
});
|
|
7977
|
+
useEffect15(() => {
|
|
7978
|
+
if (viewOnly && defaultExpanded) {
|
|
7979
|
+
const allParentIds = categories.filter((c) => childrenMap.has(c.id)).map((c) => c.id);
|
|
7980
|
+
setExpandedNodes(new Set(allParentIds));
|
|
7981
|
+
}
|
|
7982
|
+
}, [viewOnly, defaultExpanded, categories]);
|
|
7963
7983
|
const toggleExpand = (id) => {
|
|
7964
7984
|
const newExpanded = new Set(expandedNodes);
|
|
7965
7985
|
if (newExpanded.has(id)) {
|
|
@@ -7970,6 +7990,7 @@ function CategoryTreeSelect({ categories, value, onChange, placeholder = "Ch\u1E
|
|
|
7970
7990
|
setExpandedNodes(newExpanded);
|
|
7971
7991
|
};
|
|
7972
7992
|
const handleSelect = (categoryId, category) => {
|
|
7993
|
+
if (viewOnly || !onChange) return;
|
|
7973
7994
|
const newSelected = new Set(value);
|
|
7974
7995
|
if (newSelected.has(categoryId)) {
|
|
7975
7996
|
newSelected.delete(categoryId);
|
|
@@ -7993,20 +8014,14 @@ function CategoryTreeSelect({ categories, value, onChange, placeholder = "Ch\u1E
|
|
|
7993
8014
|
"div",
|
|
7994
8015
|
{
|
|
7995
8016
|
className: cn(
|
|
7996
|
-
"relative flex items-center gap-2 px-3 py-2
|
|
7997
|
-
"hover:bg-accent",
|
|
7998
|
-
// Selected state: subtle bg + square left indicator
|
|
7999
|
-
isSelected && "bg-primary/10 rounded-r-md"
|
|
8017
|
+
"relative flex items-center gap-2 px-3 py-2 rounded-md transition-colors",
|
|
8018
|
+
!viewOnly && "cursor-pointer hover:bg-accent",
|
|
8019
|
+
// Selected state: subtle bg + square left indicator (only in select mode)
|
|
8020
|
+
!viewOnly && isSelected && "bg-primary/10 rounded-r-md"
|
|
8000
8021
|
),
|
|
8001
8022
|
style: { paddingLeft: `${level * 1.5 + 0.75}rem` },
|
|
8002
8023
|
children: [
|
|
8003
|
-
isSelected && /* @__PURE__ */ jsx36(
|
|
8004
|
-
"span",
|
|
8005
|
-
{
|
|
8006
|
-
"aria-hidden": true,
|
|
8007
|
-
className: "absolute left-0 top-0 bottom-0 w-1 bg-primary"
|
|
8008
|
-
}
|
|
8009
|
-
),
|
|
8024
|
+
!viewOnly && isSelected && /* @__PURE__ */ jsx36("span", { "aria-hidden": true, className: "absolute left-0 top-0 bottom-0 w-1 bg-primary" }),
|
|
8010
8025
|
hasChildren ? /* @__PURE__ */ jsx36(
|
|
8011
8026
|
"button",
|
|
8012
8027
|
{
|
|
@@ -8019,25 +8034,24 @@ function CategoryTreeSelect({ categories, value, onChange, placeholder = "Ch\u1E
|
|
|
8019
8034
|
children: isExpanded ? /* @__PURE__ */ jsx36(ChevronDown3, { className: "w-4 h-4" }) : /* @__PURE__ */ jsx36(ChevronRight5, { className: "w-4 h-4" })
|
|
8020
8035
|
}
|
|
8021
8036
|
) : /* @__PURE__ */ jsx36("span", { className: "w-5" }),
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
{
|
|
8025
|
-
|
|
8026
|
-
|
|
8027
|
-
|
|
8028
|
-
|
|
8029
|
-
|
|
8030
|
-
|
|
8031
|
-
|
|
8032
|
-
|
|
8033
|
-
|
|
8034
|
-
|
|
8035
|
-
|
|
8036
|
-
|
|
8037
|
-
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
}
|
|
8037
|
+
viewOnly ? (
|
|
8038
|
+
// View-only mode: just display the name
|
|
8039
|
+
/* @__PURE__ */ jsx36("span", { className: "text-sm", children: category.name })
|
|
8040
|
+
) : (
|
|
8041
|
+
// Select mode: clickable with checkbox
|
|
8042
|
+
/* @__PURE__ */ jsxs31("div", { onClick: () => handleSelect(category.id, category), className: "flex items-center gap-2 flex-1", children: [
|
|
8043
|
+
/* @__PURE__ */ jsx36(
|
|
8044
|
+
"div",
|
|
8045
|
+
{
|
|
8046
|
+
className: cn(
|
|
8047
|
+
"w-4 h-4 border-2 rounded flex items-center justify-center transition-colors",
|
|
8048
|
+
isSelected ? "bg-primary border-primary" : "border-muted-foreground/30"
|
|
8049
|
+
),
|
|
8050
|
+
children: isSelected && /* @__PURE__ */ jsx36(Check6, { className: "w-3 h-3 text-primary-foreground" })
|
|
8051
|
+
}
|
|
8052
|
+
),
|
|
8053
|
+
/* @__PURE__ */ jsx36("span", { className: cn("text-sm", isSelected && "font-medium text-primary"), children: category.name })
|
|
8054
|
+
] })
|
|
8041
8055
|
)
|
|
8042
8056
|
]
|
|
8043
8057
|
}
|
|
@@ -8045,8 +8059,11 @@ function CategoryTreeSelect({ categories, value, onChange, placeholder = "Ch\u1E
|
|
|
8045
8059
|
hasChildren && isExpanded && /* @__PURE__ */ jsx36("div", { children: children.map((child) => renderCategory(child, level + 1)) })
|
|
8046
8060
|
] }, category.id);
|
|
8047
8061
|
};
|
|
8062
|
+
if (viewOnly) {
|
|
8063
|
+
return /* @__PURE__ */ jsx36("div", { className: cn("rounded-md border bg-background p-2", disabled && "opacity-50"), 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)) });
|
|
8064
|
+
}
|
|
8048
8065
|
const selectedCount = value.length;
|
|
8049
|
-
const displayText = selectedCount > 0 ?
|
|
8066
|
+
const displayText = selectedCount > 0 ? mergedLabels.selectedText(selectedCount) : placeholder;
|
|
8050
8067
|
return /* @__PURE__ */ jsxs31("div", { className: "relative", children: [
|
|
8051
8068
|
/* @__PURE__ */ jsxs31(
|
|
8052
8069
|
"button",
|
|
@@ -8079,7 +8096,7 @@ function CategoryTreeSelect({ categories, value, onChange, placeholder = "Ch\u1E
|
|
|
8079
8096
|
"rounded-md border bg-popover text-popover-foreground shadow-md",
|
|
8080
8097
|
"backdrop-blur-sm bg-popover/95 border-border/60"
|
|
8081
8098
|
),
|
|
8082
|
-
children: /* @__PURE__ */ jsx36("div", { className: "p-1", children: parentCategories.length === 0 ? /* @__PURE__ */ jsx36("div", { className: "px-3 py-2 text-sm text-muted-foreground", children:
|
|
8099
|
+
children: /* @__PURE__ */ jsx36("div", { className: "p-1", 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)) })
|
|
8083
8100
|
}
|
|
8084
8101
|
)
|
|
8085
8102
|
] })
|
|
@@ -10304,16 +10321,16 @@ var Grid_default = Grid;
|
|
|
10304
10321
|
import { useMemo as useMemo6, useState as useState33, useRef as useRef14 } from "react";
|
|
10305
10322
|
|
|
10306
10323
|
// ../../components/ui/ChartTooltip.tsx
|
|
10307
|
-
import { useEffect as
|
|
10324
|
+
import { useEffect as useEffect19, useState as useState32 } from "react";
|
|
10308
10325
|
import { createPortal as createPortal10 } from "react-dom";
|
|
10309
10326
|
import { Fragment as Fragment16, jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
10310
10327
|
function ChartTooltip({ x, y, visible, label, value, color, secondaryLabel, secondaryValue, items, containerRef }) {
|
|
10311
10328
|
const [isMounted, setIsMounted] = useState32(false);
|
|
10312
10329
|
const [position, setPosition] = useState32(null);
|
|
10313
|
-
|
|
10330
|
+
useEffect19(() => {
|
|
10314
10331
|
setIsMounted(true);
|
|
10315
10332
|
}, []);
|
|
10316
|
-
|
|
10333
|
+
useEffect19(() => {
|
|
10317
10334
|
if (visible && containerRef?.current) {
|
|
10318
10335
|
const rect = containerRef.current.getBoundingClientRect();
|
|
10319
10336
|
setPosition({
|
|
@@ -11665,11 +11682,11 @@ function GaugeChart({
|
|
|
11665
11682
|
}
|
|
11666
11683
|
|
|
11667
11684
|
// ../../components/ui/ClientOnly.tsx
|
|
11668
|
-
import { useEffect as
|
|
11685
|
+
import { useEffect as useEffect20, useState as useState38 } from "react";
|
|
11669
11686
|
import { Fragment as Fragment19, jsx as jsx53 } from "react/jsx-runtime";
|
|
11670
11687
|
function ClientOnly({ children, fallback = null }) {
|
|
11671
11688
|
const [hasMounted, setHasMounted] = useState38(false);
|
|
11672
|
-
|
|
11689
|
+
useEffect20(() => {
|
|
11673
11690
|
setHasMounted(true);
|
|
11674
11691
|
}, []);
|
|
11675
11692
|
if (!hasMounted) {
|
|
@@ -12622,7 +12639,7 @@ function AccessDenied({
|
|
|
12622
12639
|
|
|
12623
12640
|
// ../../components/ui/ThemeToggleHeadless.tsx
|
|
12624
12641
|
import { Moon, Sun, Monitor } from "lucide-react";
|
|
12625
|
-
import { useEffect as
|
|
12642
|
+
import { useEffect as useEffect22, useRef as useRef19, useState as useState39 } from "react";
|
|
12626
12643
|
import { createPortal as createPortal11 } from "react-dom";
|
|
12627
12644
|
import { Fragment as Fragment21, jsx as jsx61, jsxs as jsxs55 } from "react/jsx-runtime";
|
|
12628
12645
|
function ThemeToggleHeadless({
|
|
@@ -12635,7 +12652,7 @@ function ThemeToggleHeadless({
|
|
|
12635
12652
|
const [mounted, setMounted] = useState39(false);
|
|
12636
12653
|
const triggerRef = useRef19(null);
|
|
12637
12654
|
const [dropdownPosition, setDropdownPosition] = useState39(null);
|
|
12638
|
-
|
|
12655
|
+
useEffect22(() => setMounted(true), []);
|
|
12639
12656
|
const themes = [
|
|
12640
12657
|
{ value: "light", label: labels?.light ?? "Light", icon: Sun },
|
|
12641
12658
|
{ value: "dark", label: labels?.dark ?? "Dark", icon: Moon },
|