@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.cjs CHANGED
@@ -186,9 +186,9 @@ function deserializeERD(input) {
186
186
  const toEntity = entities.find((e) => e.name === toName);
187
187
  if (fromEntity && toEntity) {
188
188
  relations.push({
189
- id: `${fromEntity.id}_${toEntity.id}`,
190
- from: fromEntity.id,
191
- to: toEntity.id,
189
+ id: `${fromEntity.id ?? fromEntity.name}_${toEntity.id ?? toEntity.name}`,
190
+ from: fromEntity.id ?? fromEntity.name,
191
+ to: toEntity.id ?? toEntity.name,
192
192
  type: parseERDMarker(marker),
193
193
  label
194
194
  });
@@ -265,9 +265,9 @@ function deserializeUML(input) {
265
265
  if (fromEntity && toEntity) {
266
266
  const type = fromCard === "1" && toCard === "1" ? "one-to-one" : fromCard === "1" && toCard === "*" ? "one-to-many" : "many-to-many";
267
267
  relations.push({
268
- id: `${fromEntity.id}_${toEntity.id}`,
269
- from: fromEntity.id,
270
- to: toEntity.id,
268
+ id: `${fromEntity.id ?? fromEntity.name}_${toEntity.id ?? toEntity.name}`,
269
+ from: fromEntity.id ?? fromEntity.name,
270
+ to: toEntity.id ?? toEntity.name,
271
271
  type,
272
272
  label
273
273
  });
@@ -303,9 +303,9 @@ function deserializeDFD(input) {
303
303
  const toEntity = entities.find((e) => e.name === toName);
304
304
  if (fromEntity && toEntity) {
305
305
  relations.push({
306
- id: `${fromEntity.id}_${toEntity.id}`,
307
- from: fromEntity.id,
308
- to: toEntity.id,
306
+ id: `${fromEntity.id ?? fromEntity.name}_${toEntity.id ?? toEntity.name}`,
307
+ from: fromEntity.id ?? fromEntity.name,
308
+ to: toEntity.id ?? toEntity.name,
309
309
  type: "one-to-many",
310
310
  label
311
311
  });
@@ -322,6 +322,80 @@ function cn(...inputs) {
322
322
  return tailwindMerge.twMerge(clsx.clsx(inputs));
323
323
  }
324
324
 
325
+ // src/utils/sanitize.ts
326
+ var DANGEROUS_TAGS = /* @__PURE__ */ new Set([
327
+ "script",
328
+ "style",
329
+ "iframe",
330
+ "object",
331
+ "embed",
332
+ "link",
333
+ "meta",
334
+ "base",
335
+ "form"
336
+ ]);
337
+ var URL_ATTRS = /* @__PURE__ */ new Set(["href", "src", "action", "formaction", "xlink:href"]);
338
+ var SAFE_PROTOCOL = /^(?:https?:|mailto:|tel:|sms:|ftp:|#|\/|\.\/|\.\.\/|[^:]*$)/i;
339
+ function sanitizeHref(href) {
340
+ if (href == null) return void 0;
341
+ const trimmed = href.trim();
342
+ if (!trimmed) return void 0;
343
+ return SAFE_PROTOCOL.test(trimmed) ? trimmed : void 0;
344
+ }
345
+ function stripDangerousAttrs(el) {
346
+ const names = [];
347
+ for (let i = 0; i < el.attributes.length; i++) {
348
+ names.push(el.attributes[i].name);
349
+ }
350
+ for (const name of names) {
351
+ const lower = name.toLowerCase();
352
+ if (lower.startsWith("on")) {
353
+ el.removeAttribute(name);
354
+ continue;
355
+ }
356
+ if (URL_ATTRS.has(lower)) {
357
+ const sanitized = sanitizeHref(el.getAttribute(name));
358
+ if (sanitized === void 0) {
359
+ el.removeAttribute(name);
360
+ } else {
361
+ el.setAttribute(name, sanitized);
362
+ }
363
+ continue;
364
+ }
365
+ if (lower === "srcdoc") {
366
+ el.removeAttribute(name);
367
+ }
368
+ }
369
+ }
370
+ function walk(el, removeQueue) {
371
+ const tag = el.tagName.toLowerCase();
372
+ if (DANGEROUS_TAGS.has(tag)) {
373
+ removeQueue.push(el);
374
+ return;
375
+ }
376
+ stripDangerousAttrs(el);
377
+ const children = Array.from(el.children);
378
+ for (const child of children) {
379
+ walk(child, removeQueue);
380
+ }
381
+ }
382
+ function sanitizeHtml(html) {
383
+ if (typeof window === "undefined" || typeof DOMParser === "undefined") {
384
+ return html;
385
+ }
386
+ const doc = new DOMParser().parseFromString(`<body>${html}</body>`, "text/html");
387
+ const body = doc.body;
388
+ if (!body) return html;
389
+ const removeQueue = [];
390
+ for (const child of Array.from(body.children)) {
391
+ walk(child, removeQueue);
392
+ }
393
+ for (const el of removeQueue) {
394
+ el.parentNode?.removeChild(el);
395
+ }
396
+ return body.innerHTML;
397
+ }
398
+
325
399
  // src/data/emoji-data.ts
326
400
  var EMOJI_CATEGORY_ORDER = [
327
401
  "smileys",
@@ -2721,7 +2795,8 @@ var Action = react.forwardRef(
2721
2795
  children != null && /* @__PURE__ */ jsxRuntime.jsx("span", { children }),
2722
2796
  trailingElements
2723
2797
  ] });
2724
- const buttonEl = href && !disabled ? /* @__PURE__ */ jsxRuntime.jsx("a", { href, className: classes, "data-react-fancy-action": "", children: content }) : /* @__PURE__ */ jsxRuntime.jsx(
2798
+ const safeHref = sanitizeHref(href);
2799
+ const buttonEl = safeHref && !disabled ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: safeHref, className: classes, "data-react-fancy-action": "", children: content }) : /* @__PURE__ */ jsxRuntime.jsx(
2725
2800
  "button",
2726
2801
  {
2727
2802
  ref,
@@ -2791,6 +2866,283 @@ var Action = react.forwardRef(
2791
2866
  }
2792
2867
  );
2793
2868
  Action.displayName = "Action";
2869
+ function useControllableState(controlledValue, defaultValue, onChange) {
2870
+ const [uncontrolledValue, setUncontrolledValue] = react.useState(defaultValue);
2871
+ const isControlled = controlledValue !== void 0;
2872
+ const value = isControlled ? controlledValue : uncontrolledValue;
2873
+ const onChangeRef = react.useRef(onChange);
2874
+ onChangeRef.current = onChange;
2875
+ const setValue = react.useCallback(
2876
+ (next) => {
2877
+ const nextValue = typeof next === "function" ? next(value) : next;
2878
+ if (!isControlled) {
2879
+ setUncontrolledValue(nextValue);
2880
+ }
2881
+ onChangeRef.current?.(nextValue);
2882
+ },
2883
+ [isControlled, value]
2884
+ );
2885
+ return [value, setValue];
2886
+ }
2887
+ var AccordionPanelContext = react.createContext(null);
2888
+ function useAccordionPanel() {
2889
+ const ctx = react.useContext(AccordionPanelContext);
2890
+ if (!ctx) {
2891
+ throw new Error(
2892
+ "AccordionPanel components must be used inside <AccordionPanel>"
2893
+ );
2894
+ }
2895
+ return ctx;
2896
+ }
2897
+ var AccordionSectionContext = react.createContext(null);
2898
+ function useAccordionSection() {
2899
+ const ctx = react.useContext(AccordionSectionContext);
2900
+ if (!ctx) {
2901
+ throw new Error(
2902
+ "<AccordionPanel.Trigger> must be rendered inside <AccordionPanel.Section>"
2903
+ );
2904
+ }
2905
+ return ctx;
2906
+ }
2907
+ function AccordionPanelSection({
2908
+ id,
2909
+ pinned = false,
2910
+ className,
2911
+ openClassName,
2912
+ closedClassName,
2913
+ children
2914
+ }) {
2915
+ const panel = useAccordionPanel();
2916
+ const { orientation, isOpen, toggle, registerSection } = panel;
2917
+ react.useEffect(() => registerSection(id), [id, registerSection]);
2918
+ const open = pinned || isOpen(id);
2919
+ const sectionCtx = react.useMemo(
2920
+ () => ({
2921
+ id,
2922
+ open,
2923
+ pinned,
2924
+ orientation,
2925
+ toggle: () => toggle(id)
2926
+ }),
2927
+ [id, open, pinned, orientation, toggle]
2928
+ );
2929
+ return /* @__PURE__ */ jsxRuntime.jsx(AccordionSectionContext.Provider, { value: sectionCtx, children: /* @__PURE__ */ jsxRuntime.jsx(
2930
+ "div",
2931
+ {
2932
+ "data-react-fancy-accordion-section": "",
2933
+ "data-state": open ? "open" : "closed",
2934
+ "data-pinned": pinned ? "" : void 0,
2935
+ "data-orientation": orientation,
2936
+ className: cn(
2937
+ "flex shrink-0 items-center gap-1",
2938
+ orientation === "horizontal" ? "flex-row" : "flex-col",
2939
+ className,
2940
+ open ? openClassName : closedClassName
2941
+ ),
2942
+ children
2943
+ }
2944
+ ) });
2945
+ }
2946
+ AccordionPanelSection.displayName = "AccordionPanelSection";
2947
+ function renderSlot(slot, state) {
2948
+ return typeof slot === "function" ? slot(state) : slot;
2949
+ }
2950
+ function AccordionPanelTrigger({
2951
+ children,
2952
+ className,
2953
+ "aria-label": ariaLabel
2954
+ }) {
2955
+ const { id, open, orientation, toggle } = useAccordionSection();
2956
+ const state = { id, open, orientation, toggle };
2957
+ if (children !== void 0) {
2958
+ return /* @__PURE__ */ jsxRuntime.jsx(
2959
+ "div",
2960
+ {
2961
+ "data-react-fancy-accordion-trigger": "",
2962
+ "data-state": open ? "open" : "closed",
2963
+ "data-orientation": orientation,
2964
+ className,
2965
+ children: renderSlot(children, state)
2966
+ }
2967
+ );
2968
+ }
2969
+ if (open) {
2970
+ return /* @__PURE__ */ jsxRuntime.jsx(
2971
+ "button",
2972
+ {
2973
+ type: "button",
2974
+ onClick: toggle,
2975
+ "aria-label": ariaLabel ?? "Collapse section",
2976
+ "data-react-fancy-accordion-trigger": "",
2977
+ "data-state": "open",
2978
+ "data-orientation": orientation,
2979
+ className: cn(
2980
+ "group relative flex shrink-0 items-center justify-center cursor-pointer",
2981
+ "text-zinc-500 dark:text-zinc-500",
2982
+ "hover:text-zinc-900 dark:hover:text-zinc-100",
2983
+ orientation === "horizontal" ? "w-px self-stretch hover:w-3 mx-1" : "h-px self-stretch hover:h-3 my-1",
2984
+ "before:absolute before:inset-0 before:bg-zinc-200 dark:before:bg-zinc-700",
2985
+ 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",
2986
+ "transition-all duration-150",
2987
+ className
2988
+ ),
2989
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2990
+ ChevronIcon,
2991
+ {
2992
+ orientation,
2993
+ purpose: "collapse",
2994
+ className: "relative opacity-0 group-hover:opacity-100 transition-opacity"
2995
+ }
2996
+ )
2997
+ }
2998
+ );
2999
+ }
3000
+ return /* @__PURE__ */ jsxRuntime.jsx(
3001
+ "button",
3002
+ {
3003
+ type: "button",
3004
+ onClick: toggle,
3005
+ "aria-label": ariaLabel ?? "Expand section",
3006
+ "data-react-fancy-accordion-trigger": "",
3007
+ "data-state": "closed",
3008
+ "data-orientation": orientation,
3009
+ className: cn(
3010
+ "flex shrink-0 items-center justify-center rounded-md",
3011
+ "text-zinc-400 dark:text-zinc-500",
3012
+ "hover:text-zinc-900 dark:hover:text-zinc-100",
3013
+ "hover:bg-zinc-100 dark:hover:bg-zinc-800",
3014
+ "transition-colors cursor-pointer",
3015
+ orientation === "horizontal" ? "h-8 w-6 mx-0.5" : "w-8 h-6 my-0.5",
3016
+ className
3017
+ ),
3018
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChevronIcon, { orientation, purpose: "expand" })
3019
+ }
3020
+ );
3021
+ }
3022
+ AccordionPanelTrigger.displayName = "AccordionPanelTrigger";
3023
+ function ChevronIcon({
3024
+ orientation,
3025
+ purpose,
3026
+ className
3027
+ }) {
3028
+ const transform = orientation === "horizontal" ? "rotate(180deg)" : purpose === "expand" ? "rotate(90deg)" : "rotate(270deg)";
3029
+ return /* @__PURE__ */ jsxRuntime.jsx(
3030
+ "svg",
3031
+ {
3032
+ viewBox: "0 0 16 16",
3033
+ width: "12",
3034
+ height: "12",
3035
+ fill: "none",
3036
+ stroke: "currentColor",
3037
+ strokeWidth: "2",
3038
+ strokeLinecap: "round",
3039
+ strokeLinejoin: "round",
3040
+ style: { transform },
3041
+ className,
3042
+ "aria-hidden": "true",
3043
+ children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "6 4 10 8 6 12" })
3044
+ }
3045
+ );
3046
+ }
3047
+ function AccordionPanelContent({
3048
+ children,
3049
+ className
3050
+ }) {
3051
+ const { open, orientation } = useAccordionSection();
3052
+ if (!open) return null;
3053
+ return /* @__PURE__ */ jsxRuntime.jsx(
3054
+ "div",
3055
+ {
3056
+ "data-react-fancy-accordion-content": "",
3057
+ "data-orientation": orientation,
3058
+ className: cn(
3059
+ "flex items-center gap-1",
3060
+ orientation === "horizontal" ? "flex-row" : "flex-col",
3061
+ className
3062
+ ),
3063
+ children
3064
+ }
3065
+ );
3066
+ }
3067
+ AccordionPanelContent.displayName = "AccordionPanelContent";
3068
+ function AccordionPanelRoot({
3069
+ orientation = "horizontal",
3070
+ value: controlledValue,
3071
+ defaultValue,
3072
+ onValueChange,
3073
+ className,
3074
+ children
3075
+ }) {
3076
+ const [openIds, setOpenIds] = useControllableState(
3077
+ controlledValue,
3078
+ defaultValue ?? [],
3079
+ onValueChange
3080
+ );
3081
+ const openSet = react.useMemo(() => new Set(openIds), [openIds]);
3082
+ const isOpen = react.useCallback((id) => openSet.has(id), [openSet]);
3083
+ const open = react.useCallback(
3084
+ (id) => {
3085
+ setOpenIds(openSet.has(id) ? openIds ?? [] : [...openIds ?? [], id]);
3086
+ },
3087
+ [openSet, openIds, setOpenIds]
3088
+ );
3089
+ const close = react.useCallback(
3090
+ (id) => {
3091
+ setOpenIds((openIds ?? []).filter((x) => x !== id));
3092
+ },
3093
+ [openIds, setOpenIds]
3094
+ );
3095
+ const toggle = react.useCallback(
3096
+ (id) => {
3097
+ setOpenIds(
3098
+ openSet.has(id) ? (openIds ?? []).filter((x) => x !== id) : [...openIds ?? [], id]
3099
+ );
3100
+ },
3101
+ [openSet, openIds, setOpenIds]
3102
+ );
3103
+ const [sectionIds, setSectionIds] = react.useState([]);
3104
+ const orderRef = react.useRef([]);
3105
+ const registerSection = react.useCallback((id) => {
3106
+ if (!orderRef.current.includes(id)) {
3107
+ orderRef.current = [...orderRef.current, id];
3108
+ setSectionIds(orderRef.current);
3109
+ }
3110
+ return () => {
3111
+ orderRef.current = orderRef.current.filter((x) => x !== id);
3112
+ setSectionIds(orderRef.current);
3113
+ };
3114
+ }, []);
3115
+ const ctx = react.useMemo(
3116
+ () => ({
3117
+ orientation,
3118
+ isOpen,
3119
+ toggle,
3120
+ open,
3121
+ close,
3122
+ sectionIds,
3123
+ registerSection
3124
+ }),
3125
+ [orientation, isOpen, toggle, open, close, sectionIds, registerSection]
3126
+ );
3127
+ return /* @__PURE__ */ jsxRuntime.jsx(AccordionPanelContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsx(
3128
+ "div",
3129
+ {
3130
+ "data-react-fancy-accordion-panel": "",
3131
+ "data-orientation": orientation,
3132
+ className: cn(
3133
+ "inline-flex items-stretch",
3134
+ orientation === "horizontal" ? "flex-row" : "flex-col",
3135
+ className
3136
+ ),
3137
+ children
3138
+ }
3139
+ ) });
3140
+ }
3141
+ AccordionPanelRoot.displayName = "AccordionPanel";
3142
+ var AccordionPanel = AccordionPanelRoot;
3143
+ AccordionPanel.Section = AccordionPanelSection;
3144
+ AccordionPanel.Trigger = AccordionPanelTrigger;
3145
+ AccordionPanel.Content = AccordionPanelContent;
2794
3146
 
2795
3147
  // src/components/inputs/inputs.utils.ts
2796
3148
  var inputSizeClasses = {
@@ -3677,24 +4029,6 @@ var Select = react.forwardRef(
3677
4029
  }
3678
4030
  );
3679
4031
  Select.displayName = "Select";
3680
- function useControllableState(controlledValue, defaultValue, onChange) {
3681
- const [uncontrolledValue, setUncontrolledValue] = react.useState(defaultValue);
3682
- const isControlled = controlledValue !== void 0;
3683
- const value = isControlled ? controlledValue : uncontrolledValue;
3684
- const onChangeRef = react.useRef(onChange);
3685
- onChangeRef.current = onChange;
3686
- const setValue = react.useCallback(
3687
- (next) => {
3688
- const nextValue = typeof next === "function" ? next(value) : next;
3689
- if (!isControlled) {
3690
- setUncontrolledValue(nextValue);
3691
- }
3692
- onChangeRef.current?.(nextValue);
3693
- },
3694
- [isControlled, value]
3695
- );
3696
- return [value, setValue];
3697
- }
3698
4032
  var Checkbox = react.forwardRef(
3699
4033
  ({
3700
4034
  size = "md",
@@ -10387,13 +10721,15 @@ function mergeExtensions(instanceExtensions) {
10387
10721
  }
10388
10722
  return merged;
10389
10723
  }
10390
- function toHtml(value, outputFormat) {
10724
+ function toHtml(value, outputFormat, unsafe) {
10391
10725
  if (!value) return "";
10392
- if (outputFormat === "html") return value;
10393
- const format = detectFormat(value);
10394
- if (format === "html") return value;
10395
- const result = marked.marked.parse(value, { async: false });
10396
- return result.trim();
10726
+ const raw = (() => {
10727
+ if (outputFormat === "html") return value;
10728
+ const format = detectFormat(value);
10729
+ if (format === "html") return value;
10730
+ return marked.marked.parse(value, { async: false }).trim();
10731
+ })();
10732
+ return unsafe ? raw : sanitizeHtml(raw);
10397
10733
  }
10398
10734
  function EditorRoot({
10399
10735
  children,
@@ -10404,12 +10740,13 @@ function EditorRoot({
10404
10740
  outputFormat = "html",
10405
10741
  lineSpacing = 1.6,
10406
10742
  placeholder,
10407
- extensions: instanceExtensions
10743
+ extensions: instanceExtensions,
10744
+ unsafe = false
10408
10745
  }) {
10409
10746
  const contentRef = react.useRef(null);
10410
10747
  const [, setValue] = useControllableState(controlledValue, defaultValue, onChange);
10411
10748
  const initialHtml = react.useMemo(
10412
- () => toHtml(controlledValue ?? defaultValue, outputFormat),
10749
+ () => toHtml(controlledValue ?? defaultValue, outputFormat, unsafe),
10413
10750
  // Only compute once on mount — don't re-run when value changes from user input
10414
10751
  // eslint-disable-next-line react-hooks/exhaustive-deps
10415
10752
  []
@@ -10494,7 +10831,11 @@ var Editor = Object.assign(EditorRoot, {
10494
10831
  Toolbar: ToolbarWithSeparator,
10495
10832
  Content: EditorContent
10496
10833
  });
10497
- function RenderedContent({ html, extensions: instanceExtensions }) {
10834
+ function RenderedContent({
10835
+ html,
10836
+ extensions: instanceExtensions,
10837
+ unsafe = false
10838
+ }) {
10498
10839
  const extensions = react.useMemo(
10499
10840
  () => mergeExtensions(instanceExtensions),
10500
10841
  [instanceExtensions]
@@ -10503,15 +10844,16 @@ function RenderedContent({ html, extensions: instanceExtensions }) {
10503
10844
  () => parseSegments(html, extensions),
10504
10845
  [html, extensions]
10505
10846
  );
10847
+ const renderHtml = (content) => unsafe ? content : sanitizeHtml(content);
10506
10848
  if (segments.length === 1 && segments[0].type === "html") {
10507
- return /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: segments[0].content } });
10849
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: renderHtml(segments[0].content) } });
10508
10850
  }
10509
10851
  if (segments.length === 0) {
10510
10852
  return null;
10511
10853
  }
10512
10854
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: segments.map((segment, i) => {
10513
10855
  if (segment.type === "html") {
10514
- return segment.content ? /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: segment.content } }, i) : null;
10856
+ return segment.content ? /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: renderHtml(segment.content) } }, i) : null;
10515
10857
  }
10516
10858
  const ext = extensions.find(
10517
10859
  (e) => e.tag.toLowerCase() === segment.tag
@@ -10529,7 +10871,8 @@ function ContentRenderer({
10529
10871
  format = "auto",
10530
10872
  lineSpacing = 1.6,
10531
10873
  className,
10532
- extensions: instanceExtensions
10874
+ extensions: instanceExtensions,
10875
+ unsafe = false
10533
10876
  }) {
10534
10877
  const extensions = react.useMemo(
10535
10878
  () => mergeExtensions(instanceExtensions),
@@ -10537,11 +10880,9 @@ function ContentRenderer({
10537
10880
  );
10538
10881
  const html = react.useMemo(() => {
10539
10882
  const resolvedFormat = format === "auto" ? detectFormat(value) : format;
10540
- if (resolvedFormat === "markdown") {
10541
- return marked.marked.parse(value, { async: false });
10542
- }
10543
- return value;
10544
- }, [value, format]);
10883
+ const raw = resolvedFormat === "markdown" ? marked.marked.parse(value, { async: false }) : value;
10884
+ return unsafe ? raw : sanitizeHtml(raw);
10885
+ }, [value, format, unsafe]);
10545
10886
  const hasExtensions = extensions.length > 0;
10546
10887
  return /* @__PURE__ */ jsxRuntime.jsx(
10547
10888
  "div",
@@ -10549,7 +10890,7 @@ function ContentRenderer({
10549
10890
  "data-react-fancy-content-renderer": "",
10550
10891
  style: { lineHeight: lineSpacing },
10551
10892
  className: cn("text-sm", proseClasses, className),
10552
- children: hasExtensions ? /* @__PURE__ */ jsxRuntime.jsx(RenderedContent, { html, extensions }) : /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: html } })
10893
+ children: hasExtensions ? /* @__PURE__ */ jsxRuntime.jsx(RenderedContent, { html, extensions, unsafe }) : /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: html } })
10553
10894
  }
10554
10895
  );
10555
10896
  }
@@ -11920,9 +12261,12 @@ var VERTICAL_GAP = 60;
11920
12261
  function getEntityHeight(fieldCount) {
11921
12262
  return HEADER_HEIGHT2 + Math.max(fieldCount, 1) * FIELD_HEIGHT2;
11922
12263
  }
12264
+ function resolveEntityId(entity) {
12265
+ return entity.id ?? entity.name;
12266
+ }
11923
12267
  function computeDiagramLayout(schema) {
11924
12268
  const positions = /* @__PURE__ */ new Map();
11925
- const entityIds = new Set(schema.entities.map((e) => e.id));
12269
+ const entityIds = new Set(schema.entities.map(resolveEntityId));
11926
12270
  const incoming = /* @__PURE__ */ new Map();
11927
12271
  for (const id of entityIds) {
11928
12272
  incoming.set(id, /* @__PURE__ */ new Set());
@@ -11943,7 +12287,7 @@ function computeDiagramLayout(schema) {
11943
12287
  }
11944
12288
  }
11945
12289
  if (queue.length === 0 && entityIds.size > 0) {
11946
- const firstId = schema.entities[0].id;
12290
+ const firstId = resolveEntityId(schema.entities[0]);
11947
12291
  rowAssignment.set(firstId, 0);
11948
12292
  assigned.add(firstId);
11949
12293
  queue.push(firstId);
@@ -11983,7 +12327,7 @@ function computeDiagramLayout(schema) {
11983
12327
  }
11984
12328
  const fieldCounts = /* @__PURE__ */ new Map();
11985
12329
  for (const entity of schema.entities) {
11986
- fieldCounts.set(entity.id, entity.fields?.length ?? 0);
12330
+ fieldCounts.set(resolveEntityId(entity), entity.fields?.length ?? 0);
11987
12331
  }
11988
12332
  const sortedRows = Array.from(rows.keys()).sort((a, b) => a - b);
11989
12333
  let currentY = 0;
@@ -12180,7 +12524,7 @@ function FolderIcon({ open }) {
12180
12524
  }
12181
12525
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "shrink-0", children: /* @__PURE__ */ jsxRuntime.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" }) });
12182
12526
  }
12183
- function ChevronIcon({ open }) {
12527
+ function ChevronIcon2({ open }) {
12184
12528
  return /* @__PURE__ */ jsxRuntime.jsx(
12185
12529
  "svg",
12186
12530
  {
@@ -12362,7 +12706,7 @@ function TreeNode({ node, depth }) {
12362
12706
  ),
12363
12707
  style: { paddingLeft },
12364
12708
  children: [
12365
- isFolder && /* @__PURE__ */ jsxRuntime.jsx(ChevronIcon, { open: isExpanded }),
12709
+ isFolder && /* @__PURE__ */ jsxRuntime.jsx(ChevronIcon2, { open: isExpanded }),
12366
12710
  !isFolder && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-3.5 shrink-0" }),
12367
12711
  showIcons && (node.icon ?? (isFolder ? /* @__PURE__ */ jsxRuntime.jsx(FolderIcon, { open: isExpanded }) : /* @__PURE__ */ jsxRuntime.jsx(FileIcon, { ext: node.ext ?? node.label.split(".").pop() }))),
12368
12712
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: node.label })
@@ -12492,6 +12836,10 @@ var TreeNav = Object.assign(TreeNavRoot, {
12492
12836
  });
12493
12837
 
12494
12838
  exports.Accordion = Accordion;
12839
+ exports.AccordionPanel = AccordionPanel;
12840
+ exports.AccordionPanelContent = AccordionPanelContent;
12841
+ exports.AccordionPanelSection = AccordionPanelSection;
12842
+ exports.AccordionPanelTrigger = AccordionPanelTrigger;
12495
12843
  exports.Action = Action;
12496
12844
  exports.Autocomplete = Autocomplete;
12497
12845
  exports.Avatar = Avatar;
@@ -12565,9 +12913,13 @@ exports.registerExtensions = registerExtensions;
12565
12913
  exports.registerIconSet = registerIconSet;
12566
12914
  exports.registerIcons = registerIcons;
12567
12915
  exports.resolve = resolve;
12916
+ exports.sanitizeHref = sanitizeHref;
12917
+ exports.sanitizeHtml = sanitizeHtml;
12568
12918
  exports.search = search;
12569
12919
  exports.skinTones = skinTones;
12570
12920
  exports.useAccordion = useAccordion;
12921
+ exports.useAccordionPanel = useAccordionPanel;
12922
+ exports.useAccordionSection = useAccordionSection;
12571
12923
  exports.useAnimation = useAnimation;
12572
12924
  exports.useCanvas = useCanvas;
12573
12925
  exports.useCarousel = useCarousel;