@almadar/ui 5.163.0 → 5.164.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22562,6 +22562,7 @@ var init_DashboardLayout = __esm({
22562
22562
  onNotificationClick,
22563
22563
  showThemeToggle = true,
22564
22564
  sidebarFooter,
22565
+ sidebarContent,
22565
22566
  onSignOut: onSignOutProp,
22566
22567
  currentPath,
22567
22568
  layoutMode = "sidebar",
@@ -22691,7 +22692,11 @@ var init_DashboardLayout = __esm({
22691
22692
  {
22692
22693
  as: "nav",
22693
22694
  gap: "none",
22694
- className: cn("flex-1 py-4 space-y-1 overflow-y-auto", isRail ? "px-2" : "px-3"),
22695
+ className: cn(
22696
+ "py-4 space-y-1 overflow-y-auto",
22697
+ sidebarContent && !isRail ? "shrink-0" : "flex-1",
22698
+ isRail ? "px-2" : "px-3"
22699
+ ),
22695
22700
  children: navItems.map((item) => /* @__PURE__ */ jsx(
22696
22701
  NavLink,
22697
22702
  {
@@ -22703,6 +22708,7 @@ var init_DashboardLayout = __esm({
22703
22708
  ))
22704
22709
  }
22705
22710
  ),
22711
+ sidebarContent && !isRail && /* @__PURE__ */ jsx(Box, { className: "flex-1 overflow-y-auto border-t border-border dark:border-border px-2 py-3", children: sidebarContent }),
22706
22712
  sidebarFooter && /* @__PURE__ */ jsx(Box, { className: "p-4 border-t border-border dark:border-border", children: sidebarFooter })
22707
22713
  ]
22708
22714
  }
@@ -25773,7 +25779,17 @@ function fileIcon(name) {
25773
25779
  return "file";
25774
25780
  }
25775
25781
  }
25776
- var TreeNodeItem, FlatTreeNodeItem, FileTree;
25782
+ function ancestorsOf(id, byId) {
25783
+ const out = /* @__PURE__ */ new Set();
25784
+ if (!id) return out;
25785
+ let cur = byId.get(id)?.parentId;
25786
+ while (cur && byId.has(cur) && !out.has(cur)) {
25787
+ out.add(cur);
25788
+ cur = byId.get(cur)?.parentId;
25789
+ }
25790
+ return out;
25791
+ }
25792
+ var TreeNodeItem, FlatTreeNodeItem, FlatFileTree, FileTree;
25777
25793
  var init_FileTree = __esm({
25778
25794
  "components/core/molecules/FileTree.tsx"() {
25779
25795
  "use client";
@@ -25864,42 +25880,77 @@ var init_FileTree = __esm({
25864
25880
  indent,
25865
25881
  childrenByParent,
25866
25882
  onNodeSelect,
25867
- defaultExpanded = false
25883
+ onNodeAction,
25884
+ nodeActionIcon,
25885
+ nodeActionLabel,
25886
+ selectedId,
25887
+ look,
25888
+ isExpanded,
25889
+ onToggle
25868
25890
  }) => {
25869
- const [expanded, setExpanded] = useState(defaultExpanded || depth < 1);
25870
25891
  const children = childrenByParent.get(item.id);
25871
25892
  const hasChildren = !!children && children.length > 0;
25893
+ const expanded = hasChildren && isExpanded(item.id, depth);
25894
+ const isSelected = selectedId !== void 0 && selectedId !== "" && item.id === selectedId;
25895
+ const nav = look === "nav";
25872
25896
  const handleClick = useCallback(() => {
25873
- if (hasChildren) setExpanded((prev) => !prev);
25897
+ if (hasChildren && !onNodeSelect) onToggle(item.id, expanded);
25874
25898
  onNodeSelect?.(item.id);
25875
- }, [hasChildren, item.id, onNodeSelect]);
25899
+ }, [hasChildren, expanded, item.id, onNodeSelect, onToggle]);
25900
+ const handleChevron = useCallback((e) => {
25901
+ e.stopPropagation();
25902
+ onToggle(item.id, expanded);
25903
+ }, [item.id, expanded, onToggle]);
25904
+ const handleAction = useCallback((e) => {
25905
+ e.stopPropagation();
25906
+ onNodeAction?.(item.id);
25907
+ }, [item.id, onNodeAction]);
25876
25908
  return /* @__PURE__ */ jsxs(Fragment, { children: [
25877
25909
  /* @__PURE__ */ jsxs(
25878
25910
  Box,
25879
25911
  {
25880
- className: "flex items-center gap-1.5 py-0.5 px-2 cursor-pointer rounded-sm transition-colors hover:bg-muted",
25912
+ className: `group/treerow flex items-center gap-1.5 px-2 cursor-pointer rounded-sm transition-colors ${nav ? "py-1" : "py-0.5"} ${isSelected ? "bg-primary text-primary-foreground" : nav ? "text-foreground hover:bg-muted" : "hover:bg-muted"}`,
25881
25913
  style: { paddingLeft: depth * indent + 8 },
25882
25914
  onClick: handleClick,
25883
25915
  role: "treeitem",
25916
+ "aria-selected": isSelected,
25884
25917
  "aria-expanded": hasChildren ? expanded : void 0,
25885
25918
  children: [
25886
- hasChildren ? /* @__PURE__ */ jsx(
25919
+ hasChildren ? /* @__PURE__ */ jsx(Box, { onClick: handleChevron, className: "flex items-center flex-shrink-0", role: "button", "aria-label": expanded ? "Collapse" : "Expand", children: /* @__PURE__ */ jsx(
25887
25920
  Icon,
25888
25921
  {
25889
25922
  name: expanded ? "chevron-down" : "chevron-right",
25890
25923
  size: "xs",
25891
- className: "text-[var(--color-muted-foreground)] flex-shrink-0"
25924
+ className: isSelected ? "text-inherit" : "text-[var(--color-muted-foreground)]"
25892
25925
  }
25893
- ) : /* @__PURE__ */ jsx(Box, { style: { width: 12, flexShrink: 0 } }),
25926
+ ) }) : /* @__PURE__ */ jsx(Box, { style: { width: 12, flexShrink: 0 } }),
25894
25927
  /* @__PURE__ */ jsx(
25895
25928
  Icon,
25896
25929
  {
25897
- name: item.icon ?? (hasChildren ? expanded ? "folder-open" : "folder" : "file"),
25930
+ name: item.icon || (nav ? "file-text" : hasChildren ? expanded ? "folder-open" : "folder" : "file"),
25898
25931
  size: "xs",
25899
- className: hasChildren ? "text-[var(--color-warning)]" : "text-[var(--color-muted-foreground)]"
25932
+ className: isSelected ? "text-inherit" : nav || !hasChildren ? "text-[var(--color-muted-foreground)]" : "text-[var(--color-warning)]"
25933
+ }
25934
+ ),
25935
+ /* @__PURE__ */ jsx(
25936
+ Typography,
25937
+ {
25938
+ variant: "caption",
25939
+ className: `truncate ${nav ? "text-sm" : "font-mono text-xs"} !text-inherit ${isSelected ? "font-semibold" : ""}`,
25940
+ children: item.label
25900
25941
  }
25901
25942
  ),
25902
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "truncate font-mono text-xs", children: item.label })
25943
+ onNodeAction && /* @__PURE__ */ jsx(
25944
+ Box,
25945
+ {
25946
+ onClick: handleAction,
25947
+ role: "button",
25948
+ "aria-label": nodeActionLabel ?? "Node action",
25949
+ title: nodeActionLabel,
25950
+ className: `ml-auto flex-shrink-0 rounded-sm p-0.5 opacity-0 group-hover/treerow:opacity-100 transition-opacity ${isSelected ? "hover:bg-primary-foreground/20" : "hover:bg-border"}`,
25951
+ children: /* @__PURE__ */ jsx(Icon, { name: nodeActionIcon ?? "plus", size: "xs", className: "text-inherit" })
25952
+ }
25953
+ )
25903
25954
  ]
25904
25955
  }
25905
25956
  ),
@@ -25910,47 +25961,116 @@ var init_FileTree = __esm({
25910
25961
  depth: depth + 1,
25911
25962
  indent,
25912
25963
  childrenByParent,
25913
- onNodeSelect
25964
+ onNodeSelect,
25965
+ onNodeAction,
25966
+ nodeActionIcon,
25967
+ nodeActionLabel,
25968
+ selectedId,
25969
+ look,
25970
+ isExpanded,
25971
+ onToggle
25914
25972
  },
25915
25973
  child.id
25916
25974
  )) })
25917
25975
  ] });
25918
25976
  };
25977
+ FlatFileTree = ({
25978
+ items,
25979
+ selectedId,
25980
+ look = "files",
25981
+ onNodeSelect,
25982
+ onNodeAction,
25983
+ nodeActionIcon,
25984
+ nodeActionLabel,
25985
+ className,
25986
+ indent = 16
25987
+ }) => {
25988
+ const [overrides, setOverrides] = useState(() => /* @__PURE__ */ new Map());
25989
+ const byId = React77__default.useMemo(() => new Map(items.map((node) => [node.id, node])), [items]);
25990
+ const selectedAncestors = React77__default.useMemo(() => ancestorsOf(selectedId, byId), [selectedId, byId]);
25991
+ const lastSelectedRef = React77__default.useRef(selectedId);
25992
+ React77__default.useEffect(() => {
25993
+ if (selectedId === lastSelectedRef.current) return;
25994
+ lastSelectedRef.current = selectedId;
25995
+ setOverrides((prev) => {
25996
+ if (![...selectedAncestors].some((a) => prev.get(a) === false)) return prev;
25997
+ const next = new Map(prev);
25998
+ for (const a of selectedAncestors) if (next.get(a) === false) next.delete(a);
25999
+ return next;
26000
+ });
26001
+ }, [selectedId, selectedAncestors]);
26002
+ const isExpanded = useCallback(
26003
+ (id, depth) => overrides.get(id) ?? (depth < 1 || selectedAncestors.has(id)),
26004
+ [overrides, selectedAncestors]
26005
+ );
26006
+ const onToggle = useCallback((id, effective) => {
26007
+ setOverrides((prev) => {
26008
+ const next = new Map(prev);
26009
+ next.set(id, !effective);
26010
+ return next;
26011
+ });
26012
+ }, []);
26013
+ if (items.length === 0) return null;
26014
+ const ids = new Set(items.map((node) => node.id));
26015
+ const childrenByParent = /* @__PURE__ */ new Map();
26016
+ const roots = [];
26017
+ for (const item of items) {
26018
+ if (item.parentId && ids.has(item.parentId)) {
26019
+ const siblings = childrenByParent.get(item.parentId);
26020
+ if (siblings) siblings.push(item);
26021
+ else childrenByParent.set(item.parentId, [item]);
26022
+ } else {
26023
+ roots.push(item);
26024
+ }
26025
+ }
26026
+ return /* @__PURE__ */ jsx(Box, { className: `py-1 overflow-y-auto ${className ?? ""}`, role: "tree", children: roots.map((item) => /* @__PURE__ */ jsx(
26027
+ FlatTreeNodeItem,
26028
+ {
26029
+ item,
26030
+ depth: 0,
26031
+ indent,
26032
+ childrenByParent,
26033
+ onNodeSelect,
26034
+ onNodeAction,
26035
+ nodeActionIcon,
26036
+ nodeActionLabel,
26037
+ selectedId,
26038
+ look,
26039
+ isExpanded,
26040
+ onToggle
26041
+ },
26042
+ item.id
26043
+ )) });
26044
+ };
25919
26045
  FileTree = ({
25920
26046
  tree,
25921
26047
  items,
25922
26048
  selectedPath,
26049
+ selectedId,
26050
+ look = "files",
25923
26051
  onFileSelect,
25924
26052
  onNodeSelect,
26053
+ onNodeAction,
26054
+ nodeActionIcon,
26055
+ nodeActionLabel,
25925
26056
  className,
25926
26057
  indent = 16
25927
26058
  }) => {
25928
26059
  if (items) {
25929
- if (items.length === 0) return null;
25930
- const ids = new Set(items.map((node) => node.id));
25931
- const childrenByParent = /* @__PURE__ */ new Map();
25932
- const roots = [];
25933
- for (const item of items) {
25934
- if (item.parentId && ids.has(item.parentId)) {
25935
- const siblings = childrenByParent.get(item.parentId);
25936
- if (siblings) siblings.push(item);
25937
- else childrenByParent.set(item.parentId, [item]);
25938
- } else {
25939
- roots.push(item);
25940
- }
25941
- }
25942
- return /* @__PURE__ */ jsx(Box, { className: `py-1 overflow-y-auto ${className ?? ""}`, role: "tree", children: roots.map((item) => /* @__PURE__ */ jsx(
25943
- FlatTreeNodeItem,
26060
+ return /* @__PURE__ */ jsx(
26061
+ FlatFileTree,
25944
26062
  {
25945
- item,
25946
- depth: 0,
25947
- indent,
25948
- childrenByParent,
26063
+ items,
26064
+ selectedId,
26065
+ look,
25949
26066
  onNodeSelect,
25950
- defaultExpanded: true
25951
- },
25952
- item.id
25953
- )) });
26067
+ onNodeAction,
26068
+ nodeActionIcon,
26069
+ nodeActionLabel,
26070
+ className,
26071
+ indent
26072
+ }
26073
+ );
25954
26074
  }
25955
26075
  if (!tree || tree.length === 0) return null;
25956
26076
  return /* @__PURE__ */ jsx(Box, { className: `py-1 overflow-y-auto ${className ?? ""}`, role: "tree", children: tree.map((node) => /* @__PURE__ */ jsx(
@@ -38084,13 +38204,35 @@ var init_RichTextEditor = __esm({
38084
38204
  document.execCommand("createLink", false, safe);
38085
38205
  afterEdit();
38086
38206
  }, [afterEdit, t, toolbar.link]);
38207
+ const imageInputRef = useRef(null);
38208
+ const savedRangeRef = useRef(null);
38087
38209
  const execImage = useCallback(() => {
38088
- const url = window.prompt(t("richTextEditor.imagePrompt"));
38089
- if (!url) return;
38090
- const safe = safeUrl(url, ["http://", "https://", "data:image/"]) ?? `https://${url}`;
38091
- document.execCommand("insertImage", false, safe);
38092
- afterEdit();
38093
- }, [afterEdit, t]);
38210
+ const root = ref.current;
38211
+ const sel = window.getSelection();
38212
+ savedRangeRef.current = root && sel && sel.rangeCount > 0 && root.contains(sel.anchorNode) ? sel.getRangeAt(0).cloneRange() : null;
38213
+ imageInputRef.current?.click();
38214
+ }, []);
38215
+ const handleImageFile = useCallback((e) => {
38216
+ const file = e.target.files?.[0];
38217
+ e.target.value = "";
38218
+ if (!file) return;
38219
+ const reader = new FileReader();
38220
+ reader.onload = () => {
38221
+ const url = typeof reader.result === "string" ? reader.result : "";
38222
+ if (!url.startsWith("data:image/")) return;
38223
+ const root = ref.current;
38224
+ if (!root) return;
38225
+ root.focus();
38226
+ const sel = window.getSelection();
38227
+ if (sel && savedRangeRef.current && root.contains(savedRangeRef.current.startContainer)) {
38228
+ sel.removeAllRanges();
38229
+ sel.addRange(savedRangeRef.current);
38230
+ }
38231
+ document.execCommand("insertImage", false, url);
38232
+ afterEdit();
38233
+ };
38234
+ reader.readAsDataURL(file);
38235
+ }, [afterEdit]);
38094
38236
  const execRule = useCallback(() => {
38095
38237
  document.execCommand("insertHorizontalRule", false);
38096
38238
  afterEdit();
@@ -38103,6 +38245,18 @@ var init_RichTextEditor = __esm({
38103
38245
  }
38104
38246
  return /* @__PURE__ */ jsxs(Box, { className: cn("flex flex-col gap-2", className), children: [
38105
38247
  /* @__PURE__ */ jsx(RichTextStyles, {}),
38248
+ /* @__PURE__ */ jsx(
38249
+ "input",
38250
+ {
38251
+ ref: imageInputRef,
38252
+ type: "file",
38253
+ accept: "image/*",
38254
+ className: "hidden",
38255
+ "aria-hidden": "true",
38256
+ tabIndex: -1,
38257
+ onChange: handleImageFile
38258
+ }
38259
+ ),
38106
38260
  showToolbar && /* @__PURE__ */ jsxs(
38107
38261
  Box,
38108
38262
  {
@@ -45229,15 +45383,6 @@ var init_Form = __esm({
45229
45383
  "data-testid": `image-preview-${fieldName2}`
45230
45384
  }
45231
45385
  ) : null,
45232
- /* @__PURE__ */ jsx(
45233
- Input,
45234
- {
45235
- ...commonProps,
45236
- type: "url",
45237
- value: imageUrl,
45238
- onChange: (e) => handleChange(fieldName2, e.target.value)
45239
- }
45240
- ),
45241
45386
  /* @__PURE__ */ jsx(
45242
45387
  UploadDropZone,
45243
45388
  {
@@ -45256,6 +45401,16 @@ var init_Form = __esm({
45256
45401
  reader.readAsDataURL(f3);
45257
45402
  }
45258
45403
  }
45404
+ ),
45405
+ /* @__PURE__ */ jsx(
45406
+ Input,
45407
+ {
45408
+ ...commonProps,
45409
+ type: "url",
45410
+ placeholder: t("form.imageUrlFallback"),
45411
+ value: imageUrl,
45412
+ onChange: (e) => handleChange(fieldName2, e.target.value)
45413
+ }
45259
45414
  )
45260
45415
  ] });
45261
45416
  }
@@ -54027,7 +54182,8 @@ var en_default = {
54027
54182
  "richTextEditor.linkPrompt": "Link address",
54028
54183
  "richTextEditor.image": "Insert image",
54029
54184
  "richTextEditor.imagePrompt": "Image URL",
54030
- "richTextEditor.placeholder": "Start writing\u2026"
54185
+ "richTextEditor.placeholder": "Start writing\u2026",
54186
+ "form.imageUrlFallback": "\u2026or paste an image address"
54031
54187
  };
54032
54188
 
54033
54189
  // hooks/useTranslate.ts
@@ -2214,7 +2214,8 @@ var en_default = {
2214
2214
  "richTextEditor.linkPrompt": "Link address",
2215
2215
  "richTextEditor.image": "Insert image",
2216
2216
  "richTextEditor.imagePrompt": "Image URL",
2217
- "richTextEditor.placeholder": "Start writing\u2026"
2217
+ "richTextEditor.placeholder": "Start writing\u2026",
2218
+ "form.imageUrlFallback": "\u2026or paste an image address"
2218
2219
  };
2219
2220
 
2220
2221
  // hooks/useTranslate.ts
@@ -2209,7 +2209,8 @@ var en_default = {
2209
2209
  "richTextEditor.linkPrompt": "Link address",
2210
2210
  "richTextEditor.image": "Insert image",
2211
2211
  "richTextEditor.imagePrompt": "Image URL",
2212
- "richTextEditor.placeholder": "Start writing\u2026"
2212
+ "richTextEditor.placeholder": "Start writing\u2026",
2213
+ "form.imageUrlFallback": "\u2026or paste an image address"
2213
2214
  };
2214
2215
 
2215
2216
  // hooks/useTranslate.ts
@@ -553,7 +553,8 @@ var en_default = {
553
553
  "richTextEditor.linkPrompt": "Link address",
554
554
  "richTextEditor.image": "Insert image",
555
555
  "richTextEditor.imagePrompt": "Image URL",
556
- "richTextEditor.placeholder": "Start writing\u2026"
556
+ "richTextEditor.placeholder": "Start writing\u2026",
557
+ "form.imageUrlFallback": "\u2026or paste an image address"
557
558
  };
558
559
 
559
560
  // locales/ar.json
@@ -1109,7 +1110,8 @@ var ar_default = {
1109
1110
  "richTextEditor.linkPrompt": "\u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0631\u0627\u0628\u0637",
1110
1111
  "richTextEditor.image": "\u0625\u062F\u0631\u0627\u062C \u0635\u0648\u0631\u0629",
1111
1112
  "richTextEditor.imagePrompt": "\u0631\u0627\u0628\u0637 \u0627\u0644\u0635\u0648\u0631\u0629",
1112
- "richTextEditor.placeholder": "\u0627\u0628\u062F\u0623 \u0627\u0644\u0643\u062A\u0627\u0628\u0629\u2026"
1113
+ "richTextEditor.placeholder": "\u0627\u0628\u062F\u0623 \u0627\u0644\u0643\u062A\u0627\u0628\u0629\u2026",
1114
+ "form.imageUrlFallback": "\u2026\u0623\u0648 \u0627\u0644\u0635\u0642 \u0631\u0627\u0628\u0637 \u0627\u0644\u0635\u0648\u0631\u0629"
1113
1115
  };
1114
1116
 
1115
1117
  // locales/sl.json
@@ -1665,7 +1667,8 @@ var sl_default = {
1665
1667
  "richTextEditor.linkPrompt": "Naslov povezave",
1666
1668
  "richTextEditor.image": "Vstavi sliko",
1667
1669
  "richTextEditor.imagePrompt": "URL slike",
1668
- "richTextEditor.placeholder": "Za\u010Dnite pisati \u2026"
1670
+ "richTextEditor.placeholder": "Za\u010Dnite pisati \u2026",
1671
+ "form.imageUrlFallback": "\u2026ali prilepite naslov slike"
1669
1672
  };
1670
1673
 
1671
1674
  // locales/index.ts
@@ -551,7 +551,8 @@ var en_default = {
551
551
  "richTextEditor.linkPrompt": "Link address",
552
552
  "richTextEditor.image": "Insert image",
553
553
  "richTextEditor.imagePrompt": "Image URL",
554
- "richTextEditor.placeholder": "Start writing\u2026"
554
+ "richTextEditor.placeholder": "Start writing\u2026",
555
+ "form.imageUrlFallback": "\u2026or paste an image address"
555
556
  };
556
557
 
557
558
  // locales/ar.json
@@ -1107,7 +1108,8 @@ var ar_default = {
1107
1108
  "richTextEditor.linkPrompt": "\u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0631\u0627\u0628\u0637",
1108
1109
  "richTextEditor.image": "\u0625\u062F\u0631\u0627\u062C \u0635\u0648\u0631\u0629",
1109
1110
  "richTextEditor.imagePrompt": "\u0631\u0627\u0628\u0637 \u0627\u0644\u0635\u0648\u0631\u0629",
1110
- "richTextEditor.placeholder": "\u0627\u0628\u062F\u0623 \u0627\u0644\u0643\u062A\u0627\u0628\u0629\u2026"
1111
+ "richTextEditor.placeholder": "\u0627\u0628\u062F\u0623 \u0627\u0644\u0643\u062A\u0627\u0628\u0629\u2026",
1112
+ "form.imageUrlFallback": "\u2026\u0623\u0648 \u0627\u0644\u0635\u0642 \u0631\u0627\u0628\u0637 \u0627\u0644\u0635\u0648\u0631\u0629"
1111
1113
  };
1112
1114
 
1113
1115
  // locales/sl.json
@@ -1663,7 +1665,8 @@ var sl_default = {
1663
1665
  "richTextEditor.linkPrompt": "Naslov povezave",
1664
1666
  "richTextEditor.image": "Vstavi sliko",
1665
1667
  "richTextEditor.imagePrompt": "URL slike",
1666
- "richTextEditor.placeholder": "Za\u010Dnite pisati \u2026"
1668
+ "richTextEditor.placeholder": "Za\u010Dnite pisati \u2026",
1669
+ "form.imageUrlFallback": "\u2026ali prilepite naslov slike"
1667
1670
  };
1668
1671
 
1669
1672
  // locales/index.ts