@nuucognition/ncm-ui 0.1.1-beta.2 → 0.1.1-beta.3

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.
@@ -970,6 +970,48 @@ function DefinitionBlock({ block, className }) {
970
970
  }
971
971
  );
972
972
  }
973
+ function fileNameOf(src) {
974
+ let path = src.split(/[?#]/)[0] ?? "";
975
+ if (/^https?:\/\//i.test(src)) {
976
+ try {
977
+ path = new URL(src).pathname;
978
+ } catch {
979
+ return "";
980
+ }
981
+ }
982
+ return path.slice(path.lastIndexOf("/") + 1);
983
+ }
984
+ function isExtensionless(src) {
985
+ const name = fileNameOf(src);
986
+ const dot = name.lastIndexOf(".");
987
+ return dot <= 0 || dot === name.length - 1;
988
+ }
989
+ function EmbedPictureOrLink({
990
+ src,
991
+ alt,
992
+ title,
993
+ imgClassName,
994
+ linkAttrs
995
+ }) {
996
+ const [failedSrc, setFailedSrc] = useState(null);
997
+ useEffect(() => {
998
+ setFailedSrc(null);
999
+ }, [src]);
1000
+ if (failedSrc === src) {
1001
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
1002
+ }
1003
+ return /* @__PURE__ */ jsx(
1004
+ "img",
1005
+ {
1006
+ "data-ncm-embed-picture": "",
1007
+ src,
1008
+ alt,
1009
+ title,
1010
+ className: imgClassName,
1011
+ onError: () => setFailedSrc(src)
1012
+ }
1013
+ );
1014
+ }
973
1015
  function toEmbeddingConfigType(embedType) {
974
1016
  switch (embedType) {
975
1017
  case "image":
@@ -998,6 +1040,9 @@ function EmbedBlock({ block, className }) {
998
1040
  if (block.embedType === "image") {
999
1041
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1000
1042
  }
1043
+ if (block.embedType === "file" && isExtensionless(block.src)) {
1044
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1045
+ }
1001
1046
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
1002
1047
  }
1003
1048
  var embedFrameStyle = {
@@ -1174,7 +1219,19 @@ function FigureBlock({ block, className }) {
1174
1219
  "data-ncm-figure": "",
1175
1220
  className: cn("space-y-2", className),
1176
1221
  children: [
1177
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
1222
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
1223
+ // Same rule as the standalone embed block: an image spelling with an
1224
+ // extension-less destination is a picture until it fails to load.
1225
+ /* @__PURE__ */ jsx(
1226
+ EmbedPictureOrLink,
1227
+ {
1228
+ src: embed.src,
1229
+ alt: embed.alt,
1230
+ title: embed.title ?? void 0,
1231
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
1232
+ }
1233
+ )
1234
+ ) : /* @__PURE__ */ jsx(
1178
1235
  "a",
1179
1236
  {
1180
1237
  href: embed.src,
@@ -995,6 +995,48 @@ function DefinitionBlock({ block, className }) {
995
995
  }
996
996
  );
997
997
  }
998
+ function fileNameOf(src) {
999
+ let path = src.split(/[?#]/)[0] ?? "";
1000
+ if (/^https?:\/\//i.test(src)) {
1001
+ try {
1002
+ path = new URL(src).pathname;
1003
+ } catch {
1004
+ return "";
1005
+ }
1006
+ }
1007
+ return path.slice(path.lastIndexOf("/") + 1);
1008
+ }
1009
+ function isExtensionless(src) {
1010
+ const name = fileNameOf(src);
1011
+ const dot = name.lastIndexOf(".");
1012
+ return dot <= 0 || dot === name.length - 1;
1013
+ }
1014
+ function EmbedPictureOrLink({
1015
+ src,
1016
+ alt,
1017
+ title,
1018
+ imgClassName,
1019
+ linkAttrs
1020
+ }) {
1021
+ const [failedSrc, setFailedSrc] = useState(null);
1022
+ useEffect(() => {
1023
+ setFailedSrc(null);
1024
+ }, [src]);
1025
+ if (failedSrc === src) {
1026
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
1027
+ }
1028
+ return /* @__PURE__ */ jsx(
1029
+ "img",
1030
+ {
1031
+ "data-ncm-embed-picture": "",
1032
+ src,
1033
+ alt,
1034
+ title,
1035
+ className: imgClassName,
1036
+ onError: () => setFailedSrc(src)
1037
+ }
1038
+ );
1039
+ }
998
1040
  function toEmbeddingConfigType(embedType) {
999
1041
  switch (embedType) {
1000
1042
  case "image":
@@ -1023,6 +1065,9 @@ function EmbedBlock({ block, className }) {
1023
1065
  if (block.embedType === "image") {
1024
1066
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1025
1067
  }
1068
+ if (block.embedType === "file" && isExtensionless(block.src)) {
1069
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1070
+ }
1026
1071
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
1027
1072
  }
1028
1073
  var embedFrameStyle = {
@@ -1199,7 +1244,19 @@ function FigureBlock({ block, className }) {
1199
1244
  "data-ncm-figure": "",
1200
1245
  className: cn("space-y-2", className),
1201
1246
  children: [
1202
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
1247
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
1248
+ // Same rule as the standalone embed block: an image spelling with an
1249
+ // extension-less destination is a picture until it fails to load.
1250
+ /* @__PURE__ */ jsx(
1251
+ EmbedPictureOrLink,
1252
+ {
1253
+ src: embed.src,
1254
+ alt: embed.alt,
1255
+ title: embed.title ?? void 0,
1256
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
1257
+ }
1258
+ )
1259
+ ) : /* @__PURE__ */ jsx(
1203
1260
  "a",
1204
1261
  {
1205
1262
  href: embed.src,
@@ -999,6 +999,48 @@ function DefinitionBlock({ block, className }) {
999
999
  }
1000
1000
  );
1001
1001
  }
1002
+ function fileNameOf(src) {
1003
+ let path = src.split(/[?#]/)[0] ?? "";
1004
+ if (/^https?:\/\//i.test(src)) {
1005
+ try {
1006
+ path = new URL(src).pathname;
1007
+ } catch {
1008
+ return "";
1009
+ }
1010
+ }
1011
+ return path.slice(path.lastIndexOf("/") + 1);
1012
+ }
1013
+ function isExtensionless(src) {
1014
+ const name = fileNameOf(src);
1015
+ const dot = name.lastIndexOf(".");
1016
+ return dot <= 0 || dot === name.length - 1;
1017
+ }
1018
+ function EmbedPictureOrLink({
1019
+ src,
1020
+ alt,
1021
+ title,
1022
+ imgClassName,
1023
+ linkAttrs
1024
+ }) {
1025
+ const [failedSrc, setFailedSrc] = useState(null);
1026
+ useEffect(() => {
1027
+ setFailedSrc(null);
1028
+ }, [src]);
1029
+ if (failedSrc === src) {
1030
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
1031
+ }
1032
+ return /* @__PURE__ */ jsx(
1033
+ "img",
1034
+ {
1035
+ "data-ncm-embed-picture": "",
1036
+ src,
1037
+ alt,
1038
+ title,
1039
+ className: imgClassName,
1040
+ onError: () => setFailedSrc(src)
1041
+ }
1042
+ );
1043
+ }
1002
1044
  function toEmbeddingConfigType(embedType) {
1003
1045
  switch (embedType) {
1004
1046
  case "image":
@@ -1027,6 +1069,9 @@ function EmbedBlock({ block, className }) {
1027
1069
  if (block.embedType === "image") {
1028
1070
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1029
1071
  }
1072
+ if (block.embedType === "file" && isExtensionless(block.src)) {
1073
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1074
+ }
1030
1075
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
1031
1076
  }
1032
1077
  var embedFrameStyle = {
@@ -1203,7 +1248,19 @@ function FigureBlock({ block, className }) {
1203
1248
  "data-ncm-figure": "",
1204
1249
  className: cn("space-y-2", className),
1205
1250
  children: [
1206
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
1251
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
1252
+ // Same rule as the standalone embed block: an image spelling with an
1253
+ // extension-less destination is a picture until it fails to load.
1254
+ /* @__PURE__ */ jsx(
1255
+ EmbedPictureOrLink,
1256
+ {
1257
+ src: embed.src,
1258
+ alt: embed.alt,
1259
+ title: embed.title ?? void 0,
1260
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
1261
+ }
1262
+ )
1263
+ ) : /* @__PURE__ */ jsx(
1207
1264
  "a",
1208
1265
  {
1209
1266
  href: embed.src,
@@ -992,6 +992,48 @@ function DataviewBlock({ block, className }) {
992
992
  }
993
993
  );
994
994
  }
995
+ function fileNameOf(src) {
996
+ let path = src.split(/[?#]/)[0] ?? "";
997
+ if (/^https?:\/\//i.test(src)) {
998
+ try {
999
+ path = new URL(src).pathname;
1000
+ } catch {
1001
+ return "";
1002
+ }
1003
+ }
1004
+ return path.slice(path.lastIndexOf("/") + 1);
1005
+ }
1006
+ function isExtensionless(src) {
1007
+ const name = fileNameOf(src);
1008
+ const dot = name.lastIndexOf(".");
1009
+ return dot <= 0 || dot === name.length - 1;
1010
+ }
1011
+ function EmbedPictureOrLink({
1012
+ src,
1013
+ alt,
1014
+ title,
1015
+ imgClassName,
1016
+ linkAttrs
1017
+ }) {
1018
+ const [failedSrc, setFailedSrc] = useState(null);
1019
+ useEffect(() => {
1020
+ setFailedSrc(null);
1021
+ }, [src]);
1022
+ if (failedSrc === src) {
1023
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
1024
+ }
1025
+ return /* @__PURE__ */ jsx(
1026
+ "img",
1027
+ {
1028
+ "data-ncm-embed-picture": "",
1029
+ src,
1030
+ alt,
1031
+ title,
1032
+ className: imgClassName,
1033
+ onError: () => setFailedSrc(src)
1034
+ }
1035
+ );
1036
+ }
995
1037
  function toEmbeddingConfigType(embedType) {
996
1038
  switch (embedType) {
997
1039
  case "image":
@@ -1020,6 +1062,9 @@ function EmbedBlock({ block, className }) {
1020
1062
  if (block.embedType === "image") {
1021
1063
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1022
1064
  }
1065
+ if (block.embedType === "file" && isExtensionless(block.src)) {
1066
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1067
+ }
1023
1068
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
1024
1069
  }
1025
1070
  var embedFrameStyle = {
@@ -1196,7 +1241,19 @@ function FigureBlock({ block, className }) {
1196
1241
  "data-ncm-figure": "",
1197
1242
  className: cn("space-y-2", className),
1198
1243
  children: [
1199
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
1244
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
1245
+ // Same rule as the standalone embed block: an image spelling with an
1246
+ // extension-less destination is a picture until it fails to load.
1247
+ /* @__PURE__ */ jsx(
1248
+ EmbedPictureOrLink,
1249
+ {
1250
+ src: embed.src,
1251
+ alt: embed.alt,
1252
+ title: embed.title ?? void 0,
1253
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
1254
+ }
1255
+ )
1256
+ ) : /* @__PURE__ */ jsx(
1200
1257
  "a",
1201
1258
  {
1202
1259
  href: embed.src,
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { createContext, useContext } from 'react';
2
+ import { createContext, useContext, useState, useEffect } from 'react';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
@@ -12,6 +12,48 @@ function useNcmConfig() {
12
12
  function cn(...inputs) {
13
13
  return twMerge(clsx(inputs));
14
14
  }
15
+ function fileNameOf(src) {
16
+ let path = src.split(/[?#]/)[0] ?? "";
17
+ if (/^https?:\/\//i.test(src)) {
18
+ try {
19
+ path = new URL(src).pathname;
20
+ } catch {
21
+ return "";
22
+ }
23
+ }
24
+ return path.slice(path.lastIndexOf("/") + 1);
25
+ }
26
+ function isExtensionless(src) {
27
+ const name = fileNameOf(src);
28
+ const dot = name.lastIndexOf(".");
29
+ return dot <= 0 || dot === name.length - 1;
30
+ }
31
+ function EmbedPictureOrLink({
32
+ src,
33
+ alt,
34
+ title,
35
+ imgClassName,
36
+ linkAttrs
37
+ }) {
38
+ const [failedSrc, setFailedSrc] = useState(null);
39
+ useEffect(() => {
40
+ setFailedSrc(null);
41
+ }, [src]);
42
+ if (failedSrc === src) {
43
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
44
+ }
45
+ return /* @__PURE__ */ jsx(
46
+ "img",
47
+ {
48
+ "data-ncm-embed-picture": "",
49
+ src,
50
+ alt,
51
+ title,
52
+ className: imgClassName,
53
+ onError: () => setFailedSrc(src)
54
+ }
55
+ );
56
+ }
15
57
  function toEmbeddingConfigType(embedType) {
16
58
  switch (embedType) {
17
59
  case "image":
@@ -40,6 +82,9 @@ function EmbedBlock({ block, className }) {
40
82
  if (block.embedType === "image") {
41
83
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
42
84
  }
85
+ if (block.embedType === "file" && isExtensionless(block.src)) {
86
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
87
+ }
43
88
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
44
89
  }
45
90
 
@@ -5,7 +5,9 @@ import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
5
5
  type FigureBlockProps = BlockRendererProps<FigureBlock$1>;
6
6
  /**
7
7
  * Figure renderer — an embed plus caption, promoted from `embed + paragraph`
8
- * (no blank line). Images render inline; other embed types render as a link.
8
+ * (no blank line). Images render inline, as does a `file` embed whose
9
+ * destination has no extension (see `embed-picture.tsx`); other embed types
10
+ * render as a link.
9
11
  */
10
12
  declare function FigureBlock({ block, className }: FigureBlockProps): react.JSX.Element;
11
13
 
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { serializeInlineContent } from '@nuucognition/ncm';
3
- import { createContext, createElement, useMemo, useContext, useRef, useState, useEffect, useId, useCallback } from 'react';
3
+ import { createContext, createElement, useState, useEffect, useMemo, useContext, useRef, useId, useCallback } from 'react';
4
4
  import { extractExtension, embedTypeFromExtension } from '@nuucognition/mesh-core';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
6
  import { clsx } from 'clsx';
@@ -681,6 +681,48 @@ function renderReadingText(content, opts) {
681
681
  function cn(...inputs) {
682
682
  return twMerge(clsx(inputs));
683
683
  }
684
+ function fileNameOf(src) {
685
+ let path = src.split(/[?#]/)[0] ?? "";
686
+ if (/^https?:\/\//i.test(src)) {
687
+ try {
688
+ path = new URL(src).pathname;
689
+ } catch {
690
+ return "";
691
+ }
692
+ }
693
+ return path.slice(path.lastIndexOf("/") + 1);
694
+ }
695
+ function isExtensionless(src) {
696
+ const name = fileNameOf(src);
697
+ const dot = name.lastIndexOf(".");
698
+ return dot <= 0 || dot === name.length - 1;
699
+ }
700
+ function EmbedPictureOrLink({
701
+ src,
702
+ alt,
703
+ title,
704
+ imgClassName,
705
+ linkAttrs
706
+ }) {
707
+ const [failedSrc, setFailedSrc] = useState(null);
708
+ useEffect(() => {
709
+ setFailedSrc(null);
710
+ }, [src]);
711
+ if (failedSrc === src) {
712
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
713
+ }
714
+ return /* @__PURE__ */ jsx(
715
+ "img",
716
+ {
717
+ "data-ncm-embed-picture": "",
718
+ src,
719
+ alt,
720
+ title,
721
+ className: imgClassName,
722
+ onError: () => setFailedSrc(src)
723
+ }
724
+ );
725
+ }
684
726
  function blockDataAttributes(block) {
685
727
  return {
686
728
  "data-ncm-block": block.id,
@@ -710,7 +752,19 @@ function FigureBlock({ block, className }) {
710
752
  "data-ncm-figure": "",
711
753
  className: cn("space-y-2", className),
712
754
  children: [
713
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
755
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
756
+ // Same rule as the standalone embed block: an image spelling with an
757
+ // extension-less destination is a picture until it fails to load.
758
+ /* @__PURE__ */ jsx(
759
+ EmbedPictureOrLink,
760
+ {
761
+ src: embed.src,
762
+ alt: embed.alt,
763
+ title: embed.title ?? void 0,
764
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
765
+ }
766
+ )
767
+ ) : /* @__PURE__ */ jsx(
714
768
  "a",
715
769
  {
716
770
  href: embed.src,
@@ -1007,6 +1007,48 @@ function DefinitionBlock({ block, className }) {
1007
1007
  }
1008
1008
  );
1009
1009
  }
1010
+ function fileNameOf(src) {
1011
+ let path = src.split(/[?#]/)[0] ?? "";
1012
+ if (/^https?:\/\//i.test(src)) {
1013
+ try {
1014
+ path = new URL(src).pathname;
1015
+ } catch {
1016
+ return "";
1017
+ }
1018
+ }
1019
+ return path.slice(path.lastIndexOf("/") + 1);
1020
+ }
1021
+ function isExtensionless(src) {
1022
+ const name = fileNameOf(src);
1023
+ const dot = name.lastIndexOf(".");
1024
+ return dot <= 0 || dot === name.length - 1;
1025
+ }
1026
+ function EmbedPictureOrLink({
1027
+ src,
1028
+ alt,
1029
+ title,
1030
+ imgClassName,
1031
+ linkAttrs
1032
+ }) {
1033
+ const [failedSrc, setFailedSrc] = useState(null);
1034
+ useEffect(() => {
1035
+ setFailedSrc(null);
1036
+ }, [src]);
1037
+ if (failedSrc === src) {
1038
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
1039
+ }
1040
+ return /* @__PURE__ */ jsx(
1041
+ "img",
1042
+ {
1043
+ "data-ncm-embed-picture": "",
1044
+ src,
1045
+ alt,
1046
+ title,
1047
+ className: imgClassName,
1048
+ onError: () => setFailedSrc(src)
1049
+ }
1050
+ );
1051
+ }
1010
1052
  function toEmbeddingConfigType(embedType) {
1011
1053
  switch (embedType) {
1012
1054
  case "image":
@@ -1035,6 +1077,9 @@ function EmbedBlock({ block, className }) {
1035
1077
  if (block.embedType === "image") {
1036
1078
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1037
1079
  }
1080
+ if (block.embedType === "file" && isExtensionless(block.src)) {
1081
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1082
+ }
1038
1083
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
1039
1084
  }
1040
1085
  var embedFrameStyle = {
@@ -1211,7 +1256,19 @@ function FigureBlock({ block, className }) {
1211
1256
  "data-ncm-figure": "",
1212
1257
  className: cn("space-y-2", className),
1213
1258
  children: [
1214
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
1259
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
1260
+ // Same rule as the standalone embed block: an image spelling with an
1261
+ // extension-less destination is a picture until it fails to load.
1262
+ /* @__PURE__ */ jsx(
1263
+ EmbedPictureOrLink,
1264
+ {
1265
+ src: embed.src,
1266
+ alt: embed.alt,
1267
+ title: embed.title ?? void 0,
1268
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
1269
+ }
1270
+ )
1271
+ ) : /* @__PURE__ */ jsx(
1215
1272
  "a",
1216
1273
  {
1217
1274
  href: embed.src,
@@ -970,6 +970,48 @@ function DefinitionBlock({ block, className }) {
970
970
  }
971
971
  );
972
972
  }
973
+ function fileNameOf(src) {
974
+ let path = src.split(/[?#]/)[0] ?? "";
975
+ if (/^https?:\/\//i.test(src)) {
976
+ try {
977
+ path = new URL(src).pathname;
978
+ } catch {
979
+ return "";
980
+ }
981
+ }
982
+ return path.slice(path.lastIndexOf("/") + 1);
983
+ }
984
+ function isExtensionless(src) {
985
+ const name = fileNameOf(src);
986
+ const dot = name.lastIndexOf(".");
987
+ return dot <= 0 || dot === name.length - 1;
988
+ }
989
+ function EmbedPictureOrLink({
990
+ src,
991
+ alt,
992
+ title,
993
+ imgClassName,
994
+ linkAttrs
995
+ }) {
996
+ const [failedSrc, setFailedSrc] = useState(null);
997
+ useEffect(() => {
998
+ setFailedSrc(null);
999
+ }, [src]);
1000
+ if (failedSrc === src) {
1001
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
1002
+ }
1003
+ return /* @__PURE__ */ jsx(
1004
+ "img",
1005
+ {
1006
+ "data-ncm-embed-picture": "",
1007
+ src,
1008
+ alt,
1009
+ title,
1010
+ className: imgClassName,
1011
+ onError: () => setFailedSrc(src)
1012
+ }
1013
+ );
1014
+ }
973
1015
  function toEmbeddingConfigType(embedType) {
974
1016
  switch (embedType) {
975
1017
  case "image":
@@ -998,6 +1040,9 @@ function EmbedBlock({ block, className }) {
998
1040
  if (block.embedType === "image") {
999
1041
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1000
1042
  }
1043
+ if (block.embedType === "file" && isExtensionless(block.src)) {
1044
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1045
+ }
1001
1046
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
1002
1047
  }
1003
1048
  var embedFrameStyle = {
@@ -1174,7 +1219,19 @@ function FigureBlock({ block, className }) {
1174
1219
  "data-ncm-figure": "",
1175
1220
  className: cn("space-y-2", className),
1176
1221
  children: [
1177
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
1222
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
1223
+ // Same rule as the standalone embed block: an image spelling with an
1224
+ // extension-less destination is a picture until it fails to load.
1225
+ /* @__PURE__ */ jsx(
1226
+ EmbedPictureOrLink,
1227
+ {
1228
+ src: embed.src,
1229
+ alt: embed.alt,
1230
+ title: embed.title ?? void 0,
1231
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
1232
+ }
1233
+ )
1234
+ ) : /* @__PURE__ */ jsx(
1178
1235
  "a",
1179
1236
  {
1180
1237
  href: embed.src,
@@ -1007,6 +1007,48 @@ function DefinitionBlock({ block, className }) {
1007
1007
  }
1008
1008
  );
1009
1009
  }
1010
+ function fileNameOf(src) {
1011
+ let path = src.split(/[?#]/)[0] ?? "";
1012
+ if (/^https?:\/\//i.test(src)) {
1013
+ try {
1014
+ path = new URL(src).pathname;
1015
+ } catch {
1016
+ return "";
1017
+ }
1018
+ }
1019
+ return path.slice(path.lastIndexOf("/") + 1);
1020
+ }
1021
+ function isExtensionless(src) {
1022
+ const name = fileNameOf(src);
1023
+ const dot = name.lastIndexOf(".");
1024
+ return dot <= 0 || dot === name.length - 1;
1025
+ }
1026
+ function EmbedPictureOrLink({
1027
+ src,
1028
+ alt,
1029
+ title,
1030
+ imgClassName,
1031
+ linkAttrs
1032
+ }) {
1033
+ const [failedSrc, setFailedSrc] = useState(null);
1034
+ useEffect(() => {
1035
+ setFailedSrc(null);
1036
+ }, [src]);
1037
+ if (failedSrc === src) {
1038
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
1039
+ }
1040
+ return /* @__PURE__ */ jsx(
1041
+ "img",
1042
+ {
1043
+ "data-ncm-embed-picture": "",
1044
+ src,
1045
+ alt,
1046
+ title,
1047
+ className: imgClassName,
1048
+ onError: () => setFailedSrc(src)
1049
+ }
1050
+ );
1051
+ }
1010
1052
  function toEmbeddingConfigType(embedType) {
1011
1053
  switch (embedType) {
1012
1054
  case "image":
@@ -1035,6 +1077,9 @@ function EmbedBlock({ block, className }) {
1035
1077
  if (block.embedType === "image") {
1036
1078
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1037
1079
  }
1080
+ if (block.embedType === "file" && isExtensionless(block.src)) {
1081
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1082
+ }
1038
1083
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
1039
1084
  }
1040
1085
  var embedFrameStyle = {
@@ -1211,7 +1256,19 @@ function FigureBlock({ block, className }) {
1211
1256
  "data-ncm-figure": "",
1212
1257
  className: cn("space-y-2", className),
1213
1258
  children: [
1214
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
1259
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
1260
+ // Same rule as the standalone embed block: an image spelling with an
1261
+ // extension-less destination is a picture until it fails to load.
1262
+ /* @__PURE__ */ jsx(
1263
+ EmbedPictureOrLink,
1264
+ {
1265
+ src: embed.src,
1266
+ alt: embed.alt,
1267
+ title: embed.title ?? void 0,
1268
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
1269
+ }
1270
+ )
1271
+ ) : /* @__PURE__ */ jsx(
1215
1272
  "a",
1216
1273
  {
1217
1274
  href: embed.src,
@@ -1098,6 +1098,48 @@ function DefinitionBlock({ block, className }) {
1098
1098
  }
1099
1099
  );
1100
1100
  }
1101
+ function fileNameOf(src) {
1102
+ let path = src.split(/[?#]/)[0] ?? "";
1103
+ if (/^https?:\/\//i.test(src)) {
1104
+ try {
1105
+ path = new URL(src).pathname;
1106
+ } catch {
1107
+ return "";
1108
+ }
1109
+ }
1110
+ return path.slice(path.lastIndexOf("/") + 1);
1111
+ }
1112
+ function isExtensionless(src) {
1113
+ const name = fileNameOf(src);
1114
+ const dot = name.lastIndexOf(".");
1115
+ return dot <= 0 || dot === name.length - 1;
1116
+ }
1117
+ function EmbedPictureOrLink({
1118
+ src,
1119
+ alt,
1120
+ title,
1121
+ imgClassName,
1122
+ linkAttrs
1123
+ }) {
1124
+ const [failedSrc, setFailedSrc] = useState(null);
1125
+ useEffect(() => {
1126
+ setFailedSrc(null);
1127
+ }, [src]);
1128
+ if (failedSrc === src) {
1129
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
1130
+ }
1131
+ return /* @__PURE__ */ jsx(
1132
+ "img",
1133
+ {
1134
+ "data-ncm-embed-picture": "",
1135
+ src,
1136
+ alt,
1137
+ title,
1138
+ className: imgClassName,
1139
+ onError: () => setFailedSrc(src)
1140
+ }
1141
+ );
1142
+ }
1101
1143
  function toEmbeddingConfigType(embedType) {
1102
1144
  switch (embedType) {
1103
1145
  case "image":
@@ -1126,6 +1168,9 @@ function EmbedBlock({ block, className }) {
1126
1168
  if (block.embedType === "image") {
1127
1169
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1128
1170
  }
1171
+ if (block.embedType === "file" && isExtensionless(block.src)) {
1172
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1173
+ }
1129
1174
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
1130
1175
  }
1131
1176
  var embedFrameStyle = {
@@ -1302,7 +1347,19 @@ function FigureBlock({ block, className }) {
1302
1347
  "data-ncm-figure": "",
1303
1348
  className: cn("space-y-2", className),
1304
1349
  children: [
1305
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
1350
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
1351
+ // Same rule as the standalone embed block: an image spelling with an
1352
+ // extension-less destination is a picture until it fails to load.
1353
+ /* @__PURE__ */ jsx(
1354
+ EmbedPictureOrLink,
1355
+ {
1356
+ src: embed.src,
1357
+ alt: embed.alt,
1358
+ title: embed.title ?? void 0,
1359
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
1360
+ }
1361
+ )
1362
+ ) : /* @__PURE__ */ jsx(
1306
1363
  "a",
1307
1364
  {
1308
1365
  href: embed.src,
@@ -1039,6 +1039,48 @@ function DefinitionBlock({ block, className }) {
1039
1039
  }
1040
1040
  );
1041
1041
  }
1042
+ function fileNameOf(src) {
1043
+ let path = src.split(/[?#]/)[0] ?? "";
1044
+ if (/^https?:\/\//i.test(src)) {
1045
+ try {
1046
+ path = new URL(src).pathname;
1047
+ } catch {
1048
+ return "";
1049
+ }
1050
+ }
1051
+ return path.slice(path.lastIndexOf("/") + 1);
1052
+ }
1053
+ function isExtensionless(src) {
1054
+ const name = fileNameOf(src);
1055
+ const dot = name.lastIndexOf(".");
1056
+ return dot <= 0 || dot === name.length - 1;
1057
+ }
1058
+ function EmbedPictureOrLink({
1059
+ src,
1060
+ alt,
1061
+ title,
1062
+ imgClassName,
1063
+ linkAttrs
1064
+ }) {
1065
+ const [failedSrc, setFailedSrc] = useState(null);
1066
+ useEffect(() => {
1067
+ setFailedSrc(null);
1068
+ }, [src]);
1069
+ if (failedSrc === src) {
1070
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
1071
+ }
1072
+ return /* @__PURE__ */ jsx(
1073
+ "img",
1074
+ {
1075
+ "data-ncm-embed-picture": "",
1076
+ src,
1077
+ alt,
1078
+ title,
1079
+ className: imgClassName,
1080
+ onError: () => setFailedSrc(src)
1081
+ }
1082
+ );
1083
+ }
1042
1084
  function toEmbeddingConfigType(embedType) {
1043
1085
  switch (embedType) {
1044
1086
  case "image":
@@ -1067,6 +1109,9 @@ function EmbedBlock({ block, className }) {
1067
1109
  if (block.embedType === "image") {
1068
1110
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1069
1111
  }
1112
+ if (block.embedType === "file" && isExtensionless(block.src)) {
1113
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1114
+ }
1070
1115
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
1071
1116
  }
1072
1117
  var embedFrameStyle = {
@@ -1243,7 +1288,19 @@ function FigureBlock({ block, className }) {
1243
1288
  "data-ncm-figure": "",
1244
1289
  className: cn("space-y-2", className),
1245
1290
  children: [
1246
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
1291
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
1292
+ // Same rule as the standalone embed block: an image spelling with an
1293
+ // extension-less destination is a picture until it fails to load.
1294
+ /* @__PURE__ */ jsx(
1295
+ EmbedPictureOrLink,
1296
+ {
1297
+ src: embed.src,
1298
+ alt: embed.alt,
1299
+ title: embed.title ?? void 0,
1300
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
1301
+ }
1302
+ )
1303
+ ) : /* @__PURE__ */ jsx(
1247
1304
  "a",
1248
1305
  {
1249
1306
  href: embed.src,
@@ -1130,6 +1130,48 @@ function DefinitionBlock({ block, className }) {
1130
1130
  }
1131
1131
  );
1132
1132
  }
1133
+ function fileNameOf(src) {
1134
+ let path = src.split(/[?#]/)[0] ?? "";
1135
+ if (/^https?:\/\//i.test(src)) {
1136
+ try {
1137
+ path = new URL(src).pathname;
1138
+ } catch {
1139
+ return "";
1140
+ }
1141
+ }
1142
+ return path.slice(path.lastIndexOf("/") + 1);
1143
+ }
1144
+ function isExtensionless(src) {
1145
+ const name = fileNameOf(src);
1146
+ const dot = name.lastIndexOf(".");
1147
+ return dot <= 0 || dot === name.length - 1;
1148
+ }
1149
+ function EmbedPictureOrLink({
1150
+ src,
1151
+ alt,
1152
+ title,
1153
+ imgClassName,
1154
+ linkAttrs
1155
+ }) {
1156
+ const [failedSrc, setFailedSrc] = useState(null);
1157
+ useEffect(() => {
1158
+ setFailedSrc(null);
1159
+ }, [src]);
1160
+ if (failedSrc === src) {
1161
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
1162
+ }
1163
+ return /* @__PURE__ */ jsx(
1164
+ "img",
1165
+ {
1166
+ "data-ncm-embed-picture": "",
1167
+ src,
1168
+ alt,
1169
+ title,
1170
+ className: imgClassName,
1171
+ onError: () => setFailedSrc(src)
1172
+ }
1173
+ );
1174
+ }
1133
1175
  function toEmbeddingConfigType(embedType) {
1134
1176
  switch (embedType) {
1135
1177
  case "image":
@@ -1158,6 +1200,9 @@ function EmbedBlock({ block, className }) {
1158
1200
  if (block.embedType === "image") {
1159
1201
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1160
1202
  }
1203
+ if (block.embedType === "file" && isExtensionless(block.src)) {
1204
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1205
+ }
1161
1206
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
1162
1207
  }
1163
1208
  var embedFrameStyle = {
@@ -1334,7 +1379,19 @@ function FigureBlock({ block, className }) {
1334
1379
  "data-ncm-figure": "",
1335
1380
  className: cn("space-y-2", className),
1336
1381
  children: [
1337
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
1382
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
1383
+ // Same rule as the standalone embed block: an image spelling with an
1384
+ // extension-less destination is a picture until it fails to load.
1385
+ /* @__PURE__ */ jsx(
1386
+ EmbedPictureOrLink,
1387
+ {
1388
+ src: embed.src,
1389
+ alt: embed.alt,
1390
+ title: embed.title ?? void 0,
1391
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
1392
+ }
1393
+ )
1394
+ ) : /* @__PURE__ */ jsx(
1338
1395
  "a",
1339
1396
  {
1340
1397
  href: embed.src,
@@ -1114,6 +1114,48 @@ function DefinitionBlock({ block, className }) {
1114
1114
  }
1115
1115
  );
1116
1116
  }
1117
+ function fileNameOf(src) {
1118
+ let path = src.split(/[?#]/)[0] ?? "";
1119
+ if (/^https?:\/\//i.test(src)) {
1120
+ try {
1121
+ path = new URL(src).pathname;
1122
+ } catch {
1123
+ return "";
1124
+ }
1125
+ }
1126
+ return path.slice(path.lastIndexOf("/") + 1);
1127
+ }
1128
+ function isExtensionless(src) {
1129
+ const name = fileNameOf(src);
1130
+ const dot = name.lastIndexOf(".");
1131
+ return dot <= 0 || dot === name.length - 1;
1132
+ }
1133
+ function EmbedPictureOrLink({
1134
+ src,
1135
+ alt,
1136
+ title,
1137
+ imgClassName,
1138
+ linkAttrs
1139
+ }) {
1140
+ const [failedSrc, setFailedSrc] = useState(null);
1141
+ useEffect(() => {
1142
+ setFailedSrc(null);
1143
+ }, [src]);
1144
+ if (failedSrc === src) {
1145
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
1146
+ }
1147
+ return /* @__PURE__ */ jsx(
1148
+ "img",
1149
+ {
1150
+ "data-ncm-embed-picture": "",
1151
+ src,
1152
+ alt,
1153
+ title,
1154
+ className: imgClassName,
1155
+ onError: () => setFailedSrc(src)
1156
+ }
1157
+ );
1158
+ }
1117
1159
  function toEmbeddingConfigType(embedType) {
1118
1160
  switch (embedType) {
1119
1161
  case "image":
@@ -1142,6 +1184,9 @@ function EmbedBlock({ block, className }) {
1142
1184
  if (block.embedType === "image") {
1143
1185
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1144
1186
  }
1187
+ if (block.embedType === "file" && isExtensionless(block.src)) {
1188
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1189
+ }
1145
1190
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
1146
1191
  }
1147
1192
  var embedFrameStyle = {
@@ -1318,7 +1363,19 @@ function FigureBlock({ block, className }) {
1318
1363
  "data-ncm-figure": "",
1319
1364
  className: cn("space-y-2", className),
1320
1365
  children: [
1321
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
1366
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
1367
+ // Same rule as the standalone embed block: an image spelling with an
1368
+ // extension-less destination is a picture until it fails to load.
1369
+ /* @__PURE__ */ jsx(
1370
+ EmbedPictureOrLink,
1371
+ {
1372
+ src: embed.src,
1373
+ alt: embed.alt,
1374
+ title: embed.title ?? void 0,
1375
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
1376
+ }
1377
+ )
1378
+ ) : /* @__PURE__ */ jsx(
1322
1379
  "a",
1323
1380
  {
1324
1381
  href: embed.src,
@@ -1114,6 +1114,48 @@ function DefinitionBlock({ block, className }) {
1114
1114
  }
1115
1115
  );
1116
1116
  }
1117
+ function fileNameOf(src) {
1118
+ let path = src.split(/[?#]/)[0] ?? "";
1119
+ if (/^https?:\/\//i.test(src)) {
1120
+ try {
1121
+ path = new URL(src).pathname;
1122
+ } catch {
1123
+ return "";
1124
+ }
1125
+ }
1126
+ return path.slice(path.lastIndexOf("/") + 1);
1127
+ }
1128
+ function isExtensionless(src) {
1129
+ const name = fileNameOf(src);
1130
+ const dot = name.lastIndexOf(".");
1131
+ return dot <= 0 || dot === name.length - 1;
1132
+ }
1133
+ function EmbedPictureOrLink({
1134
+ src,
1135
+ alt,
1136
+ title,
1137
+ imgClassName,
1138
+ linkAttrs
1139
+ }) {
1140
+ const [failedSrc, setFailedSrc] = useState(null);
1141
+ useEffect(() => {
1142
+ setFailedSrc(null);
1143
+ }, [src]);
1144
+ if (failedSrc === src) {
1145
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
1146
+ }
1147
+ return /* @__PURE__ */ jsx(
1148
+ "img",
1149
+ {
1150
+ "data-ncm-embed-picture": "",
1151
+ src,
1152
+ alt,
1153
+ title,
1154
+ className: imgClassName,
1155
+ onError: () => setFailedSrc(src)
1156
+ }
1157
+ );
1158
+ }
1117
1159
  function toEmbeddingConfigType(embedType) {
1118
1160
  switch (embedType) {
1119
1161
  case "image":
@@ -1142,6 +1184,9 @@ function EmbedBlock({ block, className }) {
1142
1184
  if (block.embedType === "image") {
1143
1185
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1144
1186
  }
1187
+ if (block.embedType === "file" && isExtensionless(block.src)) {
1188
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1189
+ }
1145
1190
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
1146
1191
  }
1147
1192
  var embedFrameStyle = {
@@ -1318,7 +1363,19 @@ function FigureBlock({ block, className }) {
1318
1363
  "data-ncm-figure": "",
1319
1364
  className: cn("space-y-2", className),
1320
1365
  children: [
1321
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
1366
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
1367
+ // Same rule as the standalone embed block: an image spelling with an
1368
+ // extension-less destination is a picture until it fails to load.
1369
+ /* @__PURE__ */ jsx(
1370
+ EmbedPictureOrLink,
1371
+ {
1372
+ src: embed.src,
1373
+ alt: embed.alt,
1374
+ title: embed.title ?? void 0,
1375
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
1376
+ }
1377
+ )
1378
+ ) : /* @__PURE__ */ jsx(
1322
1379
  "a",
1323
1380
  {
1324
1381
  href: embed.src,
package/dist/index.js CHANGED
@@ -1118,6 +1118,48 @@ function DefinitionBlock({ block, className }) {
1118
1118
  }
1119
1119
  );
1120
1120
  }
1121
+ function fileNameOf(src) {
1122
+ let path = src.split(/[?#]/)[0] ?? "";
1123
+ if (/^https?:\/\//i.test(src)) {
1124
+ try {
1125
+ path = new URL(src).pathname;
1126
+ } catch {
1127
+ return "";
1128
+ }
1129
+ }
1130
+ return path.slice(path.lastIndexOf("/") + 1);
1131
+ }
1132
+ function isExtensionless(src) {
1133
+ const name = fileNameOf(src);
1134
+ const dot = name.lastIndexOf(".");
1135
+ return dot <= 0 || dot === name.length - 1;
1136
+ }
1137
+ function EmbedPictureOrLink({
1138
+ src,
1139
+ alt,
1140
+ title,
1141
+ imgClassName,
1142
+ linkAttrs
1143
+ }) {
1144
+ const [failedSrc, setFailedSrc] = useState(null);
1145
+ useEffect(() => {
1146
+ setFailedSrc(null);
1147
+ }, [src]);
1148
+ if (failedSrc === src) {
1149
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
1150
+ }
1151
+ return /* @__PURE__ */ jsx(
1152
+ "img",
1153
+ {
1154
+ "data-ncm-embed-picture": "",
1155
+ src,
1156
+ alt,
1157
+ title,
1158
+ className: imgClassName,
1159
+ onError: () => setFailedSrc(src)
1160
+ }
1161
+ );
1162
+ }
1121
1163
  function toEmbeddingConfigType(embedType) {
1122
1164
  switch (embedType) {
1123
1165
  case "image":
@@ -1146,6 +1188,9 @@ function EmbedBlock({ block, className }) {
1146
1188
  if (block.embedType === "image") {
1147
1189
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1148
1190
  }
1191
+ if (block.embedType === "file" && isExtensionless(block.src)) {
1192
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1193
+ }
1149
1194
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
1150
1195
  }
1151
1196
  var embedFrameStyle = {
@@ -1322,7 +1367,19 @@ function FigureBlock({ block, className }) {
1322
1367
  "data-ncm-figure": "",
1323
1368
  className: cn("space-y-2", className),
1324
1369
  children: [
1325
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
1370
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
1371
+ // Same rule as the standalone embed block: an image spelling with an
1372
+ // extension-less destination is a picture until it fails to load.
1373
+ /* @__PURE__ */ jsx(
1374
+ EmbedPictureOrLink,
1375
+ {
1376
+ src: embed.src,
1377
+ alt: embed.alt,
1378
+ title: embed.title ?? void 0,
1379
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
1380
+ }
1381
+ )
1382
+ ) : /* @__PURE__ */ jsx(
1326
1383
  "a",
1327
1384
  {
1328
1385
  href: embed.src,
@@ -1114,6 +1114,48 @@ function DefinitionBlock({ block, className }) {
1114
1114
  }
1115
1115
  );
1116
1116
  }
1117
+ function fileNameOf(src) {
1118
+ let path = src.split(/[?#]/)[0] ?? "";
1119
+ if (/^https?:\/\//i.test(src)) {
1120
+ try {
1121
+ path = new URL(src).pathname;
1122
+ } catch {
1123
+ return "";
1124
+ }
1125
+ }
1126
+ return path.slice(path.lastIndexOf("/") + 1);
1127
+ }
1128
+ function isExtensionless(src) {
1129
+ const name = fileNameOf(src);
1130
+ const dot = name.lastIndexOf(".");
1131
+ return dot <= 0 || dot === name.length - 1;
1132
+ }
1133
+ function EmbedPictureOrLink({
1134
+ src,
1135
+ alt,
1136
+ title,
1137
+ imgClassName,
1138
+ linkAttrs
1139
+ }) {
1140
+ const [failedSrc, setFailedSrc] = useState(null);
1141
+ useEffect(() => {
1142
+ setFailedSrc(null);
1143
+ }, [src]);
1144
+ if (failedSrc === src) {
1145
+ return /* @__PURE__ */ jsx("a", { href: src, title, ...linkAttrs, children: alt || src });
1146
+ }
1147
+ return /* @__PURE__ */ jsx(
1148
+ "img",
1149
+ {
1150
+ "data-ncm-embed-picture": "",
1151
+ src,
1152
+ alt,
1153
+ title,
1154
+ className: imgClassName,
1155
+ onError: () => setFailedSrc(src)
1156
+ }
1157
+ );
1158
+ }
1117
1159
  function toEmbeddingConfigType(embedType) {
1118
1160
  switch (embedType) {
1119
1161
  case "image":
@@ -1142,6 +1184,9 @@ function EmbedBlock({ block, className }) {
1142
1184
  if (block.embedType === "image") {
1143
1185
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx("img", { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1144
1186
  }
1187
+ if (block.embedType === "file" && isExtensionless(block.src)) {
1188
+ return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className: cn(config.embeddings?.imageClassName, className), children: /* @__PURE__ */ jsx(EmbedPictureOrLink, { src: resolvedUrl, alt: block.alt, title: block.title ?? void 0 }) });
1189
+ }
1145
1190
  return /* @__PURE__ */ jsx("figure", { ...dataAttrs(block), className, children: /* @__PURE__ */ jsx("a", { href: resolvedUrl, title: block.title ?? void 0, children: block.alt || block.src }) });
1146
1191
  }
1147
1192
  var embedFrameStyle = {
@@ -1318,7 +1363,19 @@ function FigureBlock({ block, className }) {
1318
1363
  "data-ncm-figure": "",
1319
1364
  className: cn("space-y-2", className),
1320
1365
  children: [
1321
- embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : /* @__PURE__ */ jsx(
1366
+ embed.embedType === "image" ? /* @__PURE__ */ jsx("img", { src: embed.src, alt: embed.alt, title: embed.title ?? void 0 }) : embed.embedType === "file" && isExtensionless(embed.src) ? (
1367
+ // Same rule as the standalone embed block: an image spelling with an
1368
+ // extension-less destination is a picture until it fails to load.
1369
+ /* @__PURE__ */ jsx(
1370
+ EmbedPictureOrLink,
1371
+ {
1372
+ src: embed.src,
1373
+ alt: embed.alt,
1374
+ title: embed.title ?? void 0,
1375
+ linkAttrs: { "data-ncm-embed-type": embed.embedType }
1376
+ }
1377
+ )
1378
+ ) : /* @__PURE__ */ jsx(
1322
1379
  "a",
1323
1380
  {
1324
1381
  href: embed.src,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuucognition/ncm-ui",
3
- "version": "0.1.1-beta.2",
3
+ "version": "0.1.1-beta.3",
4
4
  "description": "React renderers for NUU Cognition Markdown (NCM) blocks — a component library that renders parsed NCM Blocks to accessible, themeable markup.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -45,8 +45,8 @@
45
45
  "tsup": "^8.5.1",
46
46
  "typescript": "^5.9.2",
47
47
  "vitest": "^2.1.9",
48
- "@nuucognition/typescript-config": "0.0.0",
49
- "@nuucognition/eslint-config": "0.0.0"
48
+ "@nuucognition/eslint-config": "0.0.0",
49
+ "@nuucognition/typescript-config": "0.0.0"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "react": "^18.0.0 || ^19.0.0",