@particle-academy/react-fancy 2.4.0 → 2.6.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.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { forwardRef, useId, useRef, useEffect, useState, useCallback, useMemo, createContext, Children, isValidElement, cloneElement, useLayoutEffect, useContext, Fragment as Fragment$1 } from 'react';
1
+ import { forwardRef, createContext, useId, useRef, useEffect, useState, useCallback, useMemo, Children, isValidElement, cloneElement, useLayoutEffect, useContext, Fragment as Fragment$1 } from 'react';
2
2
  import { clsx } from 'clsx';
3
3
  import { twMerge } from 'tailwind-merge';
4
4
  import * as LucideIcons from 'lucide-react';
@@ -12,6 +12,80 @@ function cn(...inputs) {
12
12
  return twMerge(clsx(inputs));
13
13
  }
14
14
 
15
+ // src/utils/sanitize.ts
16
+ var DANGEROUS_TAGS = /* @__PURE__ */ new Set([
17
+ "script",
18
+ "style",
19
+ "iframe",
20
+ "object",
21
+ "embed",
22
+ "link",
23
+ "meta",
24
+ "base",
25
+ "form"
26
+ ]);
27
+ var URL_ATTRS = /* @__PURE__ */ new Set(["href", "src", "action", "formaction", "xlink:href"]);
28
+ var SAFE_PROTOCOL = /^(?:https?:|mailto:|tel:|sms:|ftp:|#|\/|\.\/|\.\.\/|[^:]*$)/i;
29
+ function sanitizeHref(href) {
30
+ if (href == null) return void 0;
31
+ const trimmed = href.trim();
32
+ if (!trimmed) return void 0;
33
+ return SAFE_PROTOCOL.test(trimmed) ? trimmed : void 0;
34
+ }
35
+ function stripDangerousAttrs(el) {
36
+ const names = [];
37
+ for (let i = 0; i < el.attributes.length; i++) {
38
+ names.push(el.attributes[i].name);
39
+ }
40
+ for (const name of names) {
41
+ const lower = name.toLowerCase();
42
+ if (lower.startsWith("on")) {
43
+ el.removeAttribute(name);
44
+ continue;
45
+ }
46
+ if (URL_ATTRS.has(lower)) {
47
+ const sanitized = sanitizeHref(el.getAttribute(name));
48
+ if (sanitized === void 0) {
49
+ el.removeAttribute(name);
50
+ } else {
51
+ el.setAttribute(name, sanitized);
52
+ }
53
+ continue;
54
+ }
55
+ if (lower === "srcdoc") {
56
+ el.removeAttribute(name);
57
+ }
58
+ }
59
+ }
60
+ function walk(el, removeQueue) {
61
+ const tag = el.tagName.toLowerCase();
62
+ if (DANGEROUS_TAGS.has(tag)) {
63
+ removeQueue.push(el);
64
+ return;
65
+ }
66
+ stripDangerousAttrs(el);
67
+ const children = Array.from(el.children);
68
+ for (const child of children) {
69
+ walk(child, removeQueue);
70
+ }
71
+ }
72
+ function sanitizeHtml(html) {
73
+ if (typeof window === "undefined" || typeof DOMParser === "undefined") {
74
+ return html;
75
+ }
76
+ const doc = new DOMParser().parseFromString(`<body>${html}</body>`, "text/html");
77
+ const body = doc.body;
78
+ if (!body) return html;
79
+ const removeQueue = [];
80
+ for (const child of Array.from(body.children)) {
81
+ walk(child, removeQueue);
82
+ }
83
+ for (const el of removeQueue) {
84
+ el.parentNode?.removeChild(el);
85
+ }
86
+ return body.innerHTML;
87
+ }
88
+
15
89
  // src/data/emoji-data.ts
16
90
  var EMOJI_CATEGORY_ORDER = [
17
91
  "smileys",
@@ -2411,7 +2485,8 @@ var Action = forwardRef(
2411
2485
  children != null && /* @__PURE__ */ jsx("span", { children }),
2412
2486
  trailingElements
2413
2487
  ] });
2414
- const buttonEl = href && !disabled ? /* @__PURE__ */ jsx("a", { href, className: classes, "data-react-fancy-action": "", children: content }) : /* @__PURE__ */ jsx(
2488
+ const safeHref = sanitizeHref(href);
2489
+ const buttonEl = safeHref && !disabled ? /* @__PURE__ */ jsx("a", { href: safeHref, className: classes, "data-react-fancy-action": "", children: content }) : /* @__PURE__ */ jsx(
2415
2490
  "button",
2416
2491
  {
2417
2492
  ref,
@@ -2481,6 +2556,283 @@ var Action = forwardRef(
2481
2556
  }
2482
2557
  );
2483
2558
  Action.displayName = "Action";
2559
+ function useControllableState(controlledValue, defaultValue, onChange) {
2560
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
2561
+ const isControlled = controlledValue !== void 0;
2562
+ const value = isControlled ? controlledValue : uncontrolledValue;
2563
+ const onChangeRef = useRef(onChange);
2564
+ onChangeRef.current = onChange;
2565
+ const setValue = useCallback(
2566
+ (next) => {
2567
+ const nextValue = typeof next === "function" ? next(value) : next;
2568
+ if (!isControlled) {
2569
+ setUncontrolledValue(nextValue);
2570
+ }
2571
+ onChangeRef.current?.(nextValue);
2572
+ },
2573
+ [isControlled, value]
2574
+ );
2575
+ return [value, setValue];
2576
+ }
2577
+ var AccordionPanelContext = createContext(null);
2578
+ function useAccordionPanel() {
2579
+ const ctx = useContext(AccordionPanelContext);
2580
+ if (!ctx) {
2581
+ throw new Error(
2582
+ "AccordionPanel components must be used inside <AccordionPanel>"
2583
+ );
2584
+ }
2585
+ return ctx;
2586
+ }
2587
+ var AccordionSectionContext = createContext(null);
2588
+ function useAccordionSection() {
2589
+ const ctx = useContext(AccordionSectionContext);
2590
+ if (!ctx) {
2591
+ throw new Error(
2592
+ "<AccordionPanel.Trigger> must be rendered inside <AccordionPanel.Section>"
2593
+ );
2594
+ }
2595
+ return ctx;
2596
+ }
2597
+ function AccordionPanelSection({
2598
+ id,
2599
+ pinned = false,
2600
+ className,
2601
+ openClassName,
2602
+ closedClassName,
2603
+ children
2604
+ }) {
2605
+ const panel = useAccordionPanel();
2606
+ const { orientation, isOpen, toggle, registerSection } = panel;
2607
+ useEffect(() => registerSection(id), [id, registerSection]);
2608
+ const open = pinned || isOpen(id);
2609
+ const sectionCtx = useMemo(
2610
+ () => ({
2611
+ id,
2612
+ open,
2613
+ pinned,
2614
+ orientation,
2615
+ toggle: () => toggle(id)
2616
+ }),
2617
+ [id, open, pinned, orientation, toggle]
2618
+ );
2619
+ return /* @__PURE__ */ jsx(AccordionSectionContext.Provider, { value: sectionCtx, children: /* @__PURE__ */ jsx(
2620
+ "div",
2621
+ {
2622
+ "data-react-fancy-accordion-section": "",
2623
+ "data-state": open ? "open" : "closed",
2624
+ "data-pinned": pinned ? "" : void 0,
2625
+ "data-orientation": orientation,
2626
+ className: cn(
2627
+ "flex shrink-0 items-center gap-1",
2628
+ orientation === "horizontal" ? "flex-row" : "flex-col",
2629
+ className,
2630
+ open ? openClassName : closedClassName
2631
+ ),
2632
+ children
2633
+ }
2634
+ ) });
2635
+ }
2636
+ AccordionPanelSection.displayName = "AccordionPanelSection";
2637
+ function renderSlot(slot, state) {
2638
+ return typeof slot === "function" ? slot(state) : slot;
2639
+ }
2640
+ function AccordionPanelTrigger({
2641
+ children,
2642
+ className,
2643
+ "aria-label": ariaLabel
2644
+ }) {
2645
+ const { id, open, orientation, toggle } = useAccordionSection();
2646
+ const state = { id, open, orientation, toggle };
2647
+ if (children !== void 0) {
2648
+ return /* @__PURE__ */ jsx(
2649
+ "div",
2650
+ {
2651
+ "data-react-fancy-accordion-trigger": "",
2652
+ "data-state": open ? "open" : "closed",
2653
+ "data-orientation": orientation,
2654
+ className,
2655
+ children: renderSlot(children, state)
2656
+ }
2657
+ );
2658
+ }
2659
+ if (open) {
2660
+ return /* @__PURE__ */ jsx(
2661
+ "button",
2662
+ {
2663
+ type: "button",
2664
+ onClick: toggle,
2665
+ "aria-label": ariaLabel ?? "Collapse section",
2666
+ "data-react-fancy-accordion-trigger": "",
2667
+ "data-state": "open",
2668
+ "data-orientation": orientation,
2669
+ className: cn(
2670
+ "group relative flex shrink-0 items-center justify-center cursor-pointer",
2671
+ "text-zinc-500 dark:text-zinc-500",
2672
+ "hover:text-zinc-900 dark:hover:text-zinc-100",
2673
+ orientation === "horizontal" ? "w-px self-stretch hover:w-3 mx-1" : "h-px self-stretch hover:h-3 my-1",
2674
+ "before:absolute before:inset-0 before:bg-zinc-200 dark:before:bg-zinc-700",
2675
+ orientation === "horizontal" ? "before:w-px before:left-1/2 before:-translate-x-1/2" : "before:h-px before:top-1/2 before:-translate-y-1/2",
2676
+ "transition-all duration-150",
2677
+ className
2678
+ ),
2679
+ children: /* @__PURE__ */ jsx(
2680
+ ChevronIcon,
2681
+ {
2682
+ orientation,
2683
+ purpose: "collapse",
2684
+ className: "relative opacity-0 group-hover:opacity-100 transition-opacity"
2685
+ }
2686
+ )
2687
+ }
2688
+ );
2689
+ }
2690
+ return /* @__PURE__ */ jsx(
2691
+ "button",
2692
+ {
2693
+ type: "button",
2694
+ onClick: toggle,
2695
+ "aria-label": ariaLabel ?? "Expand section",
2696
+ "data-react-fancy-accordion-trigger": "",
2697
+ "data-state": "closed",
2698
+ "data-orientation": orientation,
2699
+ className: cn(
2700
+ "flex shrink-0 items-center justify-center rounded-md",
2701
+ "text-zinc-400 dark:text-zinc-500",
2702
+ "hover:text-zinc-900 dark:hover:text-zinc-100",
2703
+ "hover:bg-zinc-100 dark:hover:bg-zinc-800",
2704
+ "transition-colors cursor-pointer",
2705
+ orientation === "horizontal" ? "h-8 w-6 mx-0.5" : "w-8 h-6 my-0.5",
2706
+ className
2707
+ ),
2708
+ children: /* @__PURE__ */ jsx(ChevronIcon, { orientation, purpose: "expand" })
2709
+ }
2710
+ );
2711
+ }
2712
+ AccordionPanelTrigger.displayName = "AccordionPanelTrigger";
2713
+ function ChevronIcon({
2714
+ orientation,
2715
+ purpose,
2716
+ className
2717
+ }) {
2718
+ const transform = orientation === "horizontal" ? "rotate(180deg)" : purpose === "expand" ? "rotate(90deg)" : "rotate(270deg)";
2719
+ return /* @__PURE__ */ jsx(
2720
+ "svg",
2721
+ {
2722
+ viewBox: "0 0 16 16",
2723
+ width: "12",
2724
+ height: "12",
2725
+ fill: "none",
2726
+ stroke: "currentColor",
2727
+ strokeWidth: "2",
2728
+ strokeLinecap: "round",
2729
+ strokeLinejoin: "round",
2730
+ style: { transform },
2731
+ className,
2732
+ "aria-hidden": "true",
2733
+ children: /* @__PURE__ */ jsx("polyline", { points: "6 4 10 8 6 12" })
2734
+ }
2735
+ );
2736
+ }
2737
+ function AccordionPanelContent({
2738
+ children,
2739
+ className
2740
+ }) {
2741
+ const { open, orientation } = useAccordionSection();
2742
+ if (!open) return null;
2743
+ return /* @__PURE__ */ jsx(
2744
+ "div",
2745
+ {
2746
+ "data-react-fancy-accordion-content": "",
2747
+ "data-orientation": orientation,
2748
+ className: cn(
2749
+ "flex items-center gap-1",
2750
+ orientation === "horizontal" ? "flex-row" : "flex-col",
2751
+ className
2752
+ ),
2753
+ children
2754
+ }
2755
+ );
2756
+ }
2757
+ AccordionPanelContent.displayName = "AccordionPanelContent";
2758
+ function AccordionPanelRoot({
2759
+ orientation = "horizontal",
2760
+ value: controlledValue,
2761
+ defaultValue,
2762
+ onValueChange,
2763
+ className,
2764
+ children
2765
+ }) {
2766
+ const [openIds, setOpenIds] = useControllableState(
2767
+ controlledValue,
2768
+ defaultValue ?? [],
2769
+ onValueChange
2770
+ );
2771
+ const openSet = useMemo(() => new Set(openIds), [openIds]);
2772
+ const isOpen = useCallback((id) => openSet.has(id), [openSet]);
2773
+ const open = useCallback(
2774
+ (id) => {
2775
+ setOpenIds(openSet.has(id) ? openIds ?? [] : [...openIds ?? [], id]);
2776
+ },
2777
+ [openSet, openIds, setOpenIds]
2778
+ );
2779
+ const close = useCallback(
2780
+ (id) => {
2781
+ setOpenIds((openIds ?? []).filter((x) => x !== id));
2782
+ },
2783
+ [openIds, setOpenIds]
2784
+ );
2785
+ const toggle = useCallback(
2786
+ (id) => {
2787
+ setOpenIds(
2788
+ openSet.has(id) ? (openIds ?? []).filter((x) => x !== id) : [...openIds ?? [], id]
2789
+ );
2790
+ },
2791
+ [openSet, openIds, setOpenIds]
2792
+ );
2793
+ const [sectionIds, setSectionIds] = useState([]);
2794
+ const orderRef = useRef([]);
2795
+ const registerSection = useCallback((id) => {
2796
+ if (!orderRef.current.includes(id)) {
2797
+ orderRef.current = [...orderRef.current, id];
2798
+ setSectionIds(orderRef.current);
2799
+ }
2800
+ return () => {
2801
+ orderRef.current = orderRef.current.filter((x) => x !== id);
2802
+ setSectionIds(orderRef.current);
2803
+ };
2804
+ }, []);
2805
+ const ctx = useMemo(
2806
+ () => ({
2807
+ orientation,
2808
+ isOpen,
2809
+ toggle,
2810
+ open,
2811
+ close,
2812
+ sectionIds,
2813
+ registerSection
2814
+ }),
2815
+ [orientation, isOpen, toggle, open, close, sectionIds, registerSection]
2816
+ );
2817
+ return /* @__PURE__ */ jsx(AccordionPanelContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx(
2818
+ "div",
2819
+ {
2820
+ "data-react-fancy-accordion-panel": "",
2821
+ "data-orientation": orientation,
2822
+ className: cn(
2823
+ "inline-flex items-stretch",
2824
+ orientation === "horizontal" ? "flex-row" : "flex-col",
2825
+ className
2826
+ ),
2827
+ children
2828
+ }
2829
+ ) });
2830
+ }
2831
+ AccordionPanelRoot.displayName = "AccordionPanel";
2832
+ var AccordionPanel = AccordionPanelRoot;
2833
+ AccordionPanel.Section = AccordionPanelSection;
2834
+ AccordionPanel.Trigger = AccordionPanelTrigger;
2835
+ AccordionPanel.Content = AccordionPanelContent;
2484
2836
 
2485
2837
  // src/components/inputs/inputs.utils.ts
2486
2838
  var inputSizeClasses = {
@@ -3367,24 +3719,6 @@ var Select = forwardRef(
3367
3719
  }
3368
3720
  );
3369
3721
  Select.displayName = "Select";
3370
- function useControllableState(controlledValue, defaultValue, onChange) {
3371
- const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
3372
- const isControlled = controlledValue !== void 0;
3373
- const value = isControlled ? controlledValue : uncontrolledValue;
3374
- const onChangeRef = useRef(onChange);
3375
- onChangeRef.current = onChange;
3376
- const setValue = useCallback(
3377
- (next) => {
3378
- const nextValue = typeof next === "function" ? next(value) : next;
3379
- if (!isControlled) {
3380
- setUncontrolledValue(nextValue);
3381
- }
3382
- onChangeRef.current?.(nextValue);
3383
- },
3384
- [isControlled, value]
3385
- );
3386
- return [value, setValue];
3387
- }
3388
3722
  var Checkbox = forwardRef(
3389
3723
  ({
3390
3724
  size = "md",
@@ -10077,13 +10411,15 @@ function mergeExtensions(instanceExtensions) {
10077
10411
  }
10078
10412
  return merged;
10079
10413
  }
10080
- function toHtml(value, outputFormat) {
10414
+ function toHtml(value, outputFormat, unsafe) {
10081
10415
  if (!value) return "";
10082
- if (outputFormat === "html") return value;
10083
- const format = detectFormat(value);
10084
- if (format === "html") return value;
10085
- const result = marked.parse(value, { async: false });
10086
- return result.trim();
10416
+ const raw = (() => {
10417
+ if (outputFormat === "html") return value;
10418
+ const format = detectFormat(value);
10419
+ if (format === "html") return value;
10420
+ return marked.parse(value, { async: false }).trim();
10421
+ })();
10422
+ return unsafe ? raw : sanitizeHtml(raw);
10087
10423
  }
10088
10424
  function EditorRoot({
10089
10425
  children,
@@ -10094,12 +10430,13 @@ function EditorRoot({
10094
10430
  outputFormat = "html",
10095
10431
  lineSpacing = 1.6,
10096
10432
  placeholder,
10097
- extensions: instanceExtensions
10433
+ extensions: instanceExtensions,
10434
+ unsafe = false
10098
10435
  }) {
10099
10436
  const contentRef = useRef(null);
10100
10437
  const [, setValue] = useControllableState(controlledValue, defaultValue, onChange);
10101
10438
  const initialHtml = useMemo(
10102
- () => toHtml(controlledValue ?? defaultValue, outputFormat),
10439
+ () => toHtml(controlledValue ?? defaultValue, outputFormat, unsafe),
10103
10440
  // Only compute once on mount — don't re-run when value changes from user input
10104
10441
  // eslint-disable-next-line react-hooks/exhaustive-deps
10105
10442
  []
@@ -10184,7 +10521,11 @@ var Editor = Object.assign(EditorRoot, {
10184
10521
  Toolbar: ToolbarWithSeparator,
10185
10522
  Content: EditorContent
10186
10523
  });
10187
- function RenderedContent({ html, extensions: instanceExtensions }) {
10524
+ function RenderedContent({
10525
+ html,
10526
+ extensions: instanceExtensions,
10527
+ unsafe = false
10528
+ }) {
10188
10529
  const extensions = useMemo(
10189
10530
  () => mergeExtensions(instanceExtensions),
10190
10531
  [instanceExtensions]
@@ -10193,15 +10534,16 @@ function RenderedContent({ html, extensions: instanceExtensions }) {
10193
10534
  () => parseSegments(html, extensions),
10194
10535
  [html, extensions]
10195
10536
  );
10537
+ const renderHtml = (content) => unsafe ? content : sanitizeHtml(content);
10196
10538
  if (segments.length === 1 && segments[0].type === "html") {
10197
- return /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: segments[0].content } });
10539
+ return /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: renderHtml(segments[0].content) } });
10198
10540
  }
10199
10541
  if (segments.length === 0) {
10200
10542
  return null;
10201
10543
  }
10202
10544
  return /* @__PURE__ */ jsx(Fragment, { children: segments.map((segment, i) => {
10203
10545
  if (segment.type === "html") {
10204
- return segment.content ? /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: segment.content } }, i) : null;
10546
+ return segment.content ? /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: renderHtml(segment.content) } }, i) : null;
10205
10547
  }
10206
10548
  const ext = extensions.find(
10207
10549
  (e) => e.tag.toLowerCase() === segment.tag
@@ -10219,7 +10561,8 @@ function ContentRenderer({
10219
10561
  format = "auto",
10220
10562
  lineSpacing = 1.6,
10221
10563
  className,
10222
- extensions: instanceExtensions
10564
+ extensions: instanceExtensions,
10565
+ unsafe = false
10223
10566
  }) {
10224
10567
  const extensions = useMemo(
10225
10568
  () => mergeExtensions(instanceExtensions),
@@ -10227,11 +10570,9 @@ function ContentRenderer({
10227
10570
  );
10228
10571
  const html = useMemo(() => {
10229
10572
  const resolvedFormat = format === "auto" ? detectFormat(value) : format;
10230
- if (resolvedFormat === "markdown") {
10231
- return marked.parse(value, { async: false });
10232
- }
10233
- return value;
10234
- }, [value, format]);
10573
+ const raw = resolvedFormat === "markdown" ? marked.parse(value, { async: false }) : value;
10574
+ return unsafe ? raw : sanitizeHtml(raw);
10575
+ }, [value, format, unsafe]);
10235
10576
  const hasExtensions = extensions.length > 0;
10236
10577
  return /* @__PURE__ */ jsx(
10237
10578
  "div",
@@ -10239,7 +10580,7 @@ function ContentRenderer({
10239
10580
  "data-react-fancy-content-renderer": "",
10240
10581
  style: { lineHeight: lineSpacing },
10241
10582
  className: cn("text-sm", proseClasses, className),
10242
- children: hasExtensions ? /* @__PURE__ */ jsx(RenderedContent, { html, extensions }) : /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: html } })
10583
+ children: hasExtensions ? /* @__PURE__ */ jsx(RenderedContent, { html, extensions, unsafe }) : /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: html } })
10243
10584
  }
10244
10585
  );
10245
10586
  }
@@ -11511,7 +11852,7 @@ function DiagramToolbar({ className }) {
11511
11852
  const canImport = importableRef.current;
11512
11853
  const handleDownload = useCallback(
11513
11854
  async (format) => {
11514
- const { serializeToERD, serializeToUML, serializeToDFD } = await import('./diagram.serializers-OK4HP7AB.js');
11855
+ const { serializeToERD, serializeToUML, serializeToDFD } = await import('./diagram.serializers-6RPUO46U.js');
11515
11856
  let content;
11516
11857
  switch (format) {
11517
11858
  case "erd":
@@ -11542,7 +11883,7 @@ function DiagramToolbar({ className }) {
11542
11883
  if (!file || !onImport) return;
11543
11884
  const text = await file.text();
11544
11885
  const ext = file.name.split(".").pop()?.toLowerCase();
11545
- const { deserializeSchema } = await import('./diagram.serializers-OK4HP7AB.js');
11886
+ const { deserializeSchema } = await import('./diagram.serializers-6RPUO46U.js');
11546
11887
  let format = "erd";
11547
11888
  if (ext === "puml" || ext === "uml") format = "uml";
11548
11889
  else if (ext === "dfd") format = "dfd";
@@ -11610,9 +11951,12 @@ var VERTICAL_GAP = 60;
11610
11951
  function getEntityHeight(fieldCount) {
11611
11952
  return HEADER_HEIGHT2 + Math.max(fieldCount, 1) * FIELD_HEIGHT2;
11612
11953
  }
11954
+ function resolveEntityId(entity) {
11955
+ return entity.id ?? entity.name;
11956
+ }
11613
11957
  function computeDiagramLayout(schema) {
11614
11958
  const positions = /* @__PURE__ */ new Map();
11615
- const entityIds = new Set(schema.entities.map((e) => e.id));
11959
+ const entityIds = new Set(schema.entities.map(resolveEntityId));
11616
11960
  const incoming = /* @__PURE__ */ new Map();
11617
11961
  for (const id of entityIds) {
11618
11962
  incoming.set(id, /* @__PURE__ */ new Set());
@@ -11633,7 +11977,7 @@ function computeDiagramLayout(schema) {
11633
11977
  }
11634
11978
  }
11635
11979
  if (queue.length === 0 && entityIds.size > 0) {
11636
- const firstId = schema.entities[0].id;
11980
+ const firstId = resolveEntityId(schema.entities[0]);
11637
11981
  rowAssignment.set(firstId, 0);
11638
11982
  assigned.add(firstId);
11639
11983
  queue.push(firstId);
@@ -11673,7 +12017,7 @@ function computeDiagramLayout(schema) {
11673
12017
  }
11674
12018
  const fieldCounts = /* @__PURE__ */ new Map();
11675
12019
  for (const entity of schema.entities) {
11676
- fieldCounts.set(entity.id, entity.fields?.length ?? 0);
12020
+ fieldCounts.set(resolveEntityId(entity), entity.fields?.length ?? 0);
11677
12021
  }
11678
12022
  const sortedRows = Array.from(rows.keys()).sort((a, b) => a - b);
11679
12023
  let currentY = 0;
@@ -11870,7 +12214,7 @@ function FolderIcon({ open }) {
11870
12214
  }
11871
12215
  return /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "shrink-0", children: /* @__PURE__ */ jsx("path", { d: "M1.5 3a1 1 0 011-1h3l1.5 1.5H13a1 1 0 011 1v8a1 1 0 01-1 1H2.5a1 1 0 01-1-1V3z", fill: "#fbbf24" }) });
11872
12216
  }
11873
- function ChevronIcon({ open }) {
12217
+ function ChevronIcon2({ open }) {
11874
12218
  return /* @__PURE__ */ jsx(
11875
12219
  "svg",
11876
12220
  {
@@ -12052,7 +12396,7 @@ function TreeNode({ node, depth }) {
12052
12396
  ),
12053
12397
  style: { paddingLeft },
12054
12398
  children: [
12055
- isFolder && /* @__PURE__ */ jsx(ChevronIcon, { open: isExpanded }),
12399
+ isFolder && /* @__PURE__ */ jsx(ChevronIcon2, { open: isExpanded }),
12056
12400
  !isFolder && /* @__PURE__ */ jsx("span", { className: "w-3.5 shrink-0" }),
12057
12401
  showIcons && (node.icon ?? (isFolder ? /* @__PURE__ */ jsx(FolderIcon, { open: isExpanded }) : /* @__PURE__ */ jsx(FileIcon, { ext: node.ext ?? node.label.split(".").pop() }))),
12058
12402
  /* @__PURE__ */ jsx("span", { className: "truncate", children: node.label })
@@ -12181,6 +12525,6 @@ var TreeNav = Object.assign(TreeNavRoot, {
12181
12525
  Node: TreeNode
12182
12526
  });
12183
12527
 
12184
- export { Accordion, Action, Autocomplete, Avatar, Badge, Brand, Breadcrumbs, Calendar, Callout, Canvas, Card, Carousel, Chart, Checkbox, CheckboxGroup, ColorPicker, Command, Composer, ContentRenderer, ContextMenu, DatePicker, Diagram, Dropdown, EMOJI_CATEGORY_ORDER, EMOJI_DATA, EMOJI_ENTRIES, Editor, Emoji, EmojiSelect, Field, FileUpload, Heading, Icon, Input, Kanban, Menu2 as Menu, MobileMenu, Modal, MultiSwitch, Navbar, OtpInput, Pagination, Pillbox, Popover, Portal, Profile, Progress, RadioGroup, SKIN_TONES, Select, Separator, Sidebar, Skeleton, Slider, Switch, Table, Tabs, Text, Textarea, TimePicker, Timeline, Toast, Tooltip, TreeNav, applyTone, cn, configureIcons, find, hasSkinTones, registerExtension, registerExtensions, registerIconSet, registerIcons, resolve, search, skinTones, useAccordion, useAnimation, useCanvas, useCarousel, useCommand, useContextMenu, useControllableState, useDiagram, useDropdown, useEditor, useEscapeKey, useFileUpload, useFloatingPosition, useFocusTrap, useId12 as useId, useKanban, useMenu, useMobileMenu, useModal, useNavbar, useNodeRegistry, useOutsideClick, usePanZoom, usePopover, useSidebar, useTabs, useToast, useTreeNav };
12528
+ export { Accordion, AccordionPanel, AccordionPanelContent, AccordionPanelSection, AccordionPanelTrigger, Action, Autocomplete, Avatar, Badge, Brand, Breadcrumbs, Calendar, Callout, Canvas, Card, Carousel, Chart, Checkbox, CheckboxGroup, ColorPicker, Command, Composer, ContentRenderer, ContextMenu, DatePicker, Diagram, Dropdown, EMOJI_CATEGORY_ORDER, EMOJI_DATA, EMOJI_ENTRIES, Editor, Emoji, EmojiSelect, Field, FileUpload, Heading, Icon, Input, Kanban, Menu2 as Menu, MobileMenu, Modal, MultiSwitch, Navbar, OtpInput, Pagination, Pillbox, Popover, Portal, Profile, Progress, RadioGroup, SKIN_TONES, Select, Separator, Sidebar, Skeleton, Slider, Switch, Table, Tabs, Text, Textarea, TimePicker, Timeline, Toast, Tooltip, TreeNav, applyTone, cn, configureIcons, find, hasSkinTones, registerExtension, registerExtensions, registerIconSet, registerIcons, resolve, sanitizeHref, sanitizeHtml, search, skinTones, useAccordion, useAccordionPanel, useAccordionSection, useAnimation, useCanvas, useCarousel, useCommand, useContextMenu, useControllableState, useDiagram, useDropdown, useEditor, useEscapeKey, useFileUpload, useFloatingPosition, useFocusTrap, useId12 as useId, useKanban, useMenu, useMobileMenu, useModal, useNavbar, useNodeRegistry, useOutsideClick, usePanZoom, usePopover, useSidebar, useTabs, useToast, useTreeNav };
12185
12529
  //# sourceMappingURL=index.js.map
12186
12530
  //# sourceMappingURL=index.js.map