@particle-academy/fancy-code 0.7.0 → 0.8.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.d.cts CHANGED
@@ -1,5 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { RefObject, ReactNode, CSSProperties } from 'react';
3
+ import { DiffAnnotations, LineChangeType } from '@particle-academy/fancy-file-commons';
4
+ export { languageFromFilename } from '@particle-academy/fancy-file-commons';
3
5
  import { MediaKind, MediaViewerProps, InputTagProps, InputTagTriggers, InputTagAdapter } from '@particle-academy/react-fancy';
4
6
 
5
7
  interface ThemeColors {
@@ -11,6 +13,9 @@ interface ThemeColors {
11
13
  activeLineBackground: string;
12
14
  selectionBackground: string;
13
15
  cursorColor: string;
16
+ diffAdded?: string;
17
+ diffModified?: string;
18
+ diffRemoved?: string;
14
19
  keyword: string;
15
20
  string: string;
16
21
  comment: string;
@@ -93,6 +98,15 @@ interface CodeEditorProps {
93
98
  cursorLine?: number;
94
99
  /** 1-based column for {@link cursorLine} (default 1). */
95
100
  cursorColumn?: number;
101
+ /**
102
+ * Baseline document for the diff gutter. When set, the line-number column
103
+ * shows per-line change marks of the CURRENT value against this baseline —
104
+ * VS Code convention: a green bar for added lines, a blue bar for modified
105
+ * lines, and a red wedge where lines were deleted. Recomputed live as the
106
+ * user types (line-level only — cheap). `null`/omitted disables the gutter
107
+ * marks. Requires `lineNumbers`.
108
+ */
109
+ diffBase?: string | null;
96
110
  }
97
111
  interface CodeEditorContextValue {
98
112
  /** Get the current document text */
@@ -151,6 +165,18 @@ interface CodeEditorContextValue {
151
165
  textareaRef: RefObject<HTMLTextAreaElement | null>;
152
166
  /** Placeholder text */
153
167
  placeholder?: string;
168
+ /**
169
+ * Totals of the live diff against {@link CodeEditorProps.diffBase} —
170
+ * `{ added, modified, removed }` — or `null` when no baseline is set.
171
+ * Handy for a status-bar chip or a host's save indicator.
172
+ */
173
+ diffStats: {
174
+ added: number;
175
+ modified: number;
176
+ removed: number;
177
+ } | null;
178
+ /** @internal — per-line gutter annotations for the diff marks. */
179
+ _diffAnnotations: DiffAnnotations | null;
154
180
  /** @internal */
155
181
  _engineReturn: UseEditorEngineReturn | null;
156
182
  /** @internal */
@@ -190,7 +216,7 @@ declare namespace CodeEditorStatusBar {
190
216
  var displayName: string;
191
217
  }
192
218
 
193
- declare function CodeEditorRoot({ children, className, value: valueProp, defaultValue, onChange, language: languageProp, onLanguageChange, theme, readOnly, lineNumbers: lineNumbersProp, wordWrap: wordWrapProp, tabSize: tabSizeProp, placeholder, minHeight, maxHeight, cursorLine, cursorColumn, }: CodeEditorProps): react.JSX.Element;
219
+ declare function CodeEditorRoot({ children, className, value: valueProp, defaultValue, onChange, language: languageProp, onLanguageChange, theme, readOnly, lineNumbers: lineNumbersProp, wordWrap: wordWrapProp, tabSize: tabSizeProp, placeholder, minHeight, maxHeight, cursorLine, cursorColumn, diffBase, }: CodeEditorProps): react.JSX.Element;
194
220
  declare namespace CodeEditorRoot {
195
221
  var displayName: string;
196
222
  }
@@ -270,11 +296,7 @@ interface ResolveFileKindInput {
270
296
  /** MIME type — preferred over the filename when known. */
271
297
  mime?: string;
272
298
  }
273
- /**
274
- * Resolve the fancy-code editor language for a filename. Returns `"plaintext"`
275
- * (no syntax highlighting) for unknown or extension-less files.
276
- */
277
- declare function languageFromFilename(filename?: string): string;
299
+
278
300
  /**
279
301
  * Decide whether a file is previewable media (image / video / audio / PDF) or
280
302
  * text, from its MIME type (preferred) and/or filename. Media wins when the
@@ -352,6 +374,29 @@ declare namespace FileViewer {
352
374
  var displayName: string;
353
375
  }
354
376
 
377
+ /**
378
+ * Diff-gutter model — the pure mapping between fancy-file-commons line
379
+ * annotations and what the CodeEditor gutter renders per line-number row.
380
+ * Kept DOM-free (like engine/position.ts) so it's unit-testable; the panel
381
+ * only paints what this resolves.
382
+ */
383
+
384
+ /** What one line-number row shows: its own change bar and/or a deletion wedge above. */
385
+ interface GutterDiffMark {
386
+ /** The line's own change (colored bar), if any. */
387
+ type?: LineChangeType;
388
+ /** True when one or more lines were deleted immediately above this line (wedge). */
389
+ deletedAbove: boolean;
390
+ }
391
+ /** Resolve the mark for a 1-based line, or null when the line is untouched. */
392
+ declare function gutterDiffMark(annotations: DiffAnnotations | null, line: number): GutterDiffMark | null;
393
+ /** Whether the deleted-at-EOF wedge should render under the last line. */
394
+ declare function hasDeletedAtEnd(annotations: DiffAnnotations | null): boolean;
395
+ /** The bar color for a change type, honoring theme overrides. */
396
+ declare function diffMarkColor(type: LineChangeType, colors: ThemeColors): string;
397
+ /** The deletion-wedge color, honoring theme overrides. */
398
+ declare function diffRemovedColor(colors: ThemeColors): string;
399
+
355
400
  /**
356
401
  * Tiny, dependency-free Markdown → HTML renderer for the MarkdownEditor preview
357
402
  * pane. Covers the common subset — headings, bold/italic, inline + fenced code,
@@ -436,4 +481,4 @@ interface CodeEditorInputTagProps extends Omit<InputTagProps, "adapter"> {
436
481
  */
437
482
  declare function CodeEditorInputTag(props: CodeEditorInputTagProps): react.JSX.Element;
438
483
 
439
- export { CodeEditor, type CodeEditorContextValue, CodeEditorInputTag, type CodeEditorInputTagProps, type CodeEditorPanelProps, type CodeEditorProps, type CodeEditorStatusBarProps, type CodeEditorToolbarProps, type FileKind, FileViewer, type FileViewerProps, type LanguageDefinition, MarkdownEditor, type MarkdownEditorMode, type MarkdownEditorProps, type ResolveFileKindInput, type ThemeColors, type ThemeDefinition, type Token, type TokenType, type Tokenizer, getLanguage, getRegisteredLanguages, getRegisteredThemes, getTheme, languageFromFilename, registerLanguage, registerTheme, renderMarkdown, resolveFileKind, tokenizeMarkdown, useCodeEditor, useCodeEditorInputTagAdapter };
484
+ export { CodeEditor, type CodeEditorContextValue, CodeEditorInputTag, type CodeEditorInputTagProps, type CodeEditorPanelProps, type CodeEditorProps, type CodeEditorStatusBarProps, type CodeEditorToolbarProps, type FileKind, FileViewer, type FileViewerProps, type GutterDiffMark, type LanguageDefinition, MarkdownEditor, type MarkdownEditorMode, type MarkdownEditorProps, type ResolveFileKindInput, type ThemeColors, type ThemeDefinition, type Token, type TokenType, type Tokenizer, diffMarkColor, diffRemovedColor, getLanguage, getRegisteredLanguages, getRegisteredThemes, getTheme, gutterDiffMark, hasDeletedAtEnd, registerLanguage, registerTheme, renderMarkdown, resolveFileKind, tokenizeMarkdown, useCodeEditor, useCodeEditorInputTagAdapter };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { RefObject, ReactNode, CSSProperties } from 'react';
3
+ import { DiffAnnotations, LineChangeType } from '@particle-academy/fancy-file-commons';
4
+ export { languageFromFilename } from '@particle-academy/fancy-file-commons';
3
5
  import { MediaKind, MediaViewerProps, InputTagProps, InputTagTriggers, InputTagAdapter } from '@particle-academy/react-fancy';
4
6
 
5
7
  interface ThemeColors {
@@ -11,6 +13,9 @@ interface ThemeColors {
11
13
  activeLineBackground: string;
12
14
  selectionBackground: string;
13
15
  cursorColor: string;
16
+ diffAdded?: string;
17
+ diffModified?: string;
18
+ diffRemoved?: string;
14
19
  keyword: string;
15
20
  string: string;
16
21
  comment: string;
@@ -93,6 +98,15 @@ interface CodeEditorProps {
93
98
  cursorLine?: number;
94
99
  /** 1-based column for {@link cursorLine} (default 1). */
95
100
  cursorColumn?: number;
101
+ /**
102
+ * Baseline document for the diff gutter. When set, the line-number column
103
+ * shows per-line change marks of the CURRENT value against this baseline —
104
+ * VS Code convention: a green bar for added lines, a blue bar for modified
105
+ * lines, and a red wedge where lines were deleted. Recomputed live as the
106
+ * user types (line-level only — cheap). `null`/omitted disables the gutter
107
+ * marks. Requires `lineNumbers`.
108
+ */
109
+ diffBase?: string | null;
96
110
  }
97
111
  interface CodeEditorContextValue {
98
112
  /** Get the current document text */
@@ -151,6 +165,18 @@ interface CodeEditorContextValue {
151
165
  textareaRef: RefObject<HTMLTextAreaElement | null>;
152
166
  /** Placeholder text */
153
167
  placeholder?: string;
168
+ /**
169
+ * Totals of the live diff against {@link CodeEditorProps.diffBase} —
170
+ * `{ added, modified, removed }` — or `null` when no baseline is set.
171
+ * Handy for a status-bar chip or a host's save indicator.
172
+ */
173
+ diffStats: {
174
+ added: number;
175
+ modified: number;
176
+ removed: number;
177
+ } | null;
178
+ /** @internal — per-line gutter annotations for the diff marks. */
179
+ _diffAnnotations: DiffAnnotations | null;
154
180
  /** @internal */
155
181
  _engineReturn: UseEditorEngineReturn | null;
156
182
  /** @internal */
@@ -190,7 +216,7 @@ declare namespace CodeEditorStatusBar {
190
216
  var displayName: string;
191
217
  }
192
218
 
193
- declare function CodeEditorRoot({ children, className, value: valueProp, defaultValue, onChange, language: languageProp, onLanguageChange, theme, readOnly, lineNumbers: lineNumbersProp, wordWrap: wordWrapProp, tabSize: tabSizeProp, placeholder, minHeight, maxHeight, cursorLine, cursorColumn, }: CodeEditorProps): react.JSX.Element;
219
+ declare function CodeEditorRoot({ children, className, value: valueProp, defaultValue, onChange, language: languageProp, onLanguageChange, theme, readOnly, lineNumbers: lineNumbersProp, wordWrap: wordWrapProp, tabSize: tabSizeProp, placeholder, minHeight, maxHeight, cursorLine, cursorColumn, diffBase, }: CodeEditorProps): react.JSX.Element;
194
220
  declare namespace CodeEditorRoot {
195
221
  var displayName: string;
196
222
  }
@@ -270,11 +296,7 @@ interface ResolveFileKindInput {
270
296
  /** MIME type — preferred over the filename when known. */
271
297
  mime?: string;
272
298
  }
273
- /**
274
- * Resolve the fancy-code editor language for a filename. Returns `"plaintext"`
275
- * (no syntax highlighting) for unknown or extension-less files.
276
- */
277
- declare function languageFromFilename(filename?: string): string;
299
+
278
300
  /**
279
301
  * Decide whether a file is previewable media (image / video / audio / PDF) or
280
302
  * text, from its MIME type (preferred) and/or filename. Media wins when the
@@ -352,6 +374,29 @@ declare namespace FileViewer {
352
374
  var displayName: string;
353
375
  }
354
376
 
377
+ /**
378
+ * Diff-gutter model — the pure mapping between fancy-file-commons line
379
+ * annotations and what the CodeEditor gutter renders per line-number row.
380
+ * Kept DOM-free (like engine/position.ts) so it's unit-testable; the panel
381
+ * only paints what this resolves.
382
+ */
383
+
384
+ /** What one line-number row shows: its own change bar and/or a deletion wedge above. */
385
+ interface GutterDiffMark {
386
+ /** The line's own change (colored bar), if any. */
387
+ type?: LineChangeType;
388
+ /** True when one or more lines were deleted immediately above this line (wedge). */
389
+ deletedAbove: boolean;
390
+ }
391
+ /** Resolve the mark for a 1-based line, or null when the line is untouched. */
392
+ declare function gutterDiffMark(annotations: DiffAnnotations | null, line: number): GutterDiffMark | null;
393
+ /** Whether the deleted-at-EOF wedge should render under the last line. */
394
+ declare function hasDeletedAtEnd(annotations: DiffAnnotations | null): boolean;
395
+ /** The bar color for a change type, honoring theme overrides. */
396
+ declare function diffMarkColor(type: LineChangeType, colors: ThemeColors): string;
397
+ /** The deletion-wedge color, honoring theme overrides. */
398
+ declare function diffRemovedColor(colors: ThemeColors): string;
399
+
355
400
  /**
356
401
  * Tiny, dependency-free Markdown → HTML renderer for the MarkdownEditor preview
357
402
  * pane. Covers the common subset — headings, bold/italic, inline + fenced code,
@@ -436,4 +481,4 @@ interface CodeEditorInputTagProps extends Omit<InputTagProps, "adapter"> {
436
481
  */
437
482
  declare function CodeEditorInputTag(props: CodeEditorInputTagProps): react.JSX.Element;
438
483
 
439
- export { CodeEditor, type CodeEditorContextValue, CodeEditorInputTag, type CodeEditorInputTagProps, type CodeEditorPanelProps, type CodeEditorProps, type CodeEditorStatusBarProps, type CodeEditorToolbarProps, type FileKind, FileViewer, type FileViewerProps, type LanguageDefinition, MarkdownEditor, type MarkdownEditorMode, type MarkdownEditorProps, type ResolveFileKindInput, type ThemeColors, type ThemeDefinition, type Token, type TokenType, type Tokenizer, getLanguage, getRegisteredLanguages, getRegisteredThemes, getTheme, languageFromFilename, registerLanguage, registerTheme, renderMarkdown, resolveFileKind, tokenizeMarkdown, useCodeEditor, useCodeEditorInputTagAdapter };
484
+ export { CodeEditor, type CodeEditorContextValue, CodeEditorInputTag, type CodeEditorInputTagProps, type CodeEditorPanelProps, type CodeEditorProps, type CodeEditorStatusBarProps, type CodeEditorToolbarProps, type FileKind, FileViewer, type FileViewerProps, type GutterDiffMark, type LanguageDefinition, MarkdownEditor, type MarkdownEditorMode, type MarkdownEditorProps, type ResolveFileKindInput, type ThemeColors, type ThemeDefinition, type Token, type TokenType, type Tokenizer, diffMarkColor, diffRemovedColor, getLanguage, getRegisteredLanguages, getRegisteredThemes, getTheme, gutterDiffMark, hasDeletedAtEnd, registerLanguage, registerTheme, renderMarkdown, resolveFileKind, tokenizeMarkdown, useCodeEditor, useCodeEditorInputTagAdapter };
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
- import { createContext, useState, useCallback, useRef, useEffect, useMemo, useSyncExternalStore, useContext } from 'react';
1
+ import { createContext, useMemo, useState, useCallback, useRef, useEffect, useSyncExternalStore, useContext } from 'react';
2
2
  import { cn, useControllableState, resolveMediaType, MediaViewer, textareaAdapter, InputTag } from '@particle-academy/react-fancy';
3
+ import { annotateLines, languageFromFilename } from '@particle-academy/fancy-file-commons';
4
+ export { languageFromFilename } from '@particle-academy/fancy-file-commons';
3
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
6
 
5
7
  // src/components/CodeEditor/CodeEditor.tsx
@@ -11,6 +13,24 @@ function useCodeEditor() {
11
13
  }
12
14
  return ctx;
13
15
  }
16
+
17
+ // src/components/CodeEditor/diff-gutter.ts
18
+ function gutterDiffMark(annotations, line) {
19
+ if (!annotations) return null;
20
+ const a = annotations.byLine[line];
21
+ if (!a) return null;
22
+ return { type: a.type, deletedAbove: (a.deletedAbove ?? 0) > 0 };
23
+ }
24
+ function hasDeletedAtEnd(annotations) {
25
+ return (annotations?.deletedAtEnd ?? 0) > 0;
26
+ }
27
+ var FALLBACK = { added: "#3fb950", modified: "#4184e4", removed: "#f85149" };
28
+ function diffMarkColor(type, colors) {
29
+ return type === "added" ? colors.diffAdded ?? FALLBACK.added : colors.diffModified ?? FALLBACK.modified;
30
+ }
31
+ function diffRemovedColor(colors) {
32
+ return colors.diffRemoved ?? FALLBACK.removed;
33
+ }
14
34
  function CodeEditorPanel({ className }) {
15
35
  const {
16
36
  _engineReturn: engine,
@@ -18,6 +38,7 @@ function CodeEditorPanel({ className }) {
18
38
  wordWrap,
19
39
  readOnly,
20
40
  placeholder,
41
+ _diffAnnotations: diffAnnotations,
21
42
  _maxHeight,
22
43
  _minHeight
23
44
  } = useCodeEditor();
@@ -38,25 +59,80 @@ function CodeEditorPanel({ className }) {
38
59
  const gutterWidth = lineNumbers ? `${Math.max(String(lineCount).length, 2) * 0.75 + 1.5}em` : "0";
39
60
  const lineNumberElements = useMemo(() => {
40
61
  if (!lineNumbers) return null;
62
+ const removed = diffRemovedColor(themeColors);
41
63
  const lines = [];
42
64
  for (let i = 1; i <= lineCount; i++) {
65
+ const mark = gutterDiffMark(diffAnnotations, i);
43
66
  lines.push(
44
- /* @__PURE__ */ jsx(
67
+ /* @__PURE__ */ jsxs(
45
68
  "div",
46
69
  {
70
+ "data-diff": mark?.type,
71
+ "data-diff-deleted-above": mark?.deletedAbove ? "" : void 0,
47
72
  style: {
73
+ position: "relative",
48
74
  color: i === activeLine ? themeColors.foreground : themeColors.gutterForeground,
49
75
  backgroundColor: i === activeLine ? themeColors.activeLineBackground : void 0
50
76
  },
51
77
  className: "pr-3 text-right text-[13px] leading-[1.5] select-none",
52
- children: i
78
+ children: [
79
+ mark?.type && /* @__PURE__ */ jsx(
80
+ "span",
81
+ {
82
+ "aria-hidden": "true",
83
+ style: {
84
+ position: "absolute",
85
+ left: 0,
86
+ top: 0,
87
+ bottom: 0,
88
+ width: 3,
89
+ borderRadius: 2,
90
+ backgroundColor: diffMarkColor(mark.type, themeColors)
91
+ }
92
+ }
93
+ ),
94
+ mark?.deletedAbove && /* @__PURE__ */ jsx(
95
+ "span",
96
+ {
97
+ "aria-hidden": "true",
98
+ style: {
99
+ position: "absolute",
100
+ left: 0,
101
+ top: -4,
102
+ width: 0,
103
+ height: 0,
104
+ borderLeft: `8px solid ${removed}`,
105
+ borderTop: "4px solid transparent",
106
+ borderBottom: "4px solid transparent"
107
+ }
108
+ }
109
+ ),
110
+ i,
111
+ i === lineCount && hasDeletedAtEnd(diffAnnotations) && /* @__PURE__ */ jsx(
112
+ "span",
113
+ {
114
+ "aria-hidden": "true",
115
+ "data-diff-deleted-at-end": "",
116
+ style: {
117
+ position: "absolute",
118
+ left: 0,
119
+ bottom: -4,
120
+ width: 0,
121
+ height: 0,
122
+ borderLeft: `8px solid ${removed}`,
123
+ borderTop: "4px solid transparent",
124
+ borderBottom: "4px solid transparent"
125
+ }
126
+ }
127
+ )
128
+ ]
53
129
  },
54
130
  i
55
131
  )
56
132
  );
57
133
  }
58
134
  return lines;
59
- }, [lineNumbers, lineCount, activeLine, themeColors]);
135
+ }, [lineNumbers, lineCount, activeLine, themeColors, diffAnnotations]);
60
136
  const containerStyle = {
61
137
  backgroundColor: themeColors.background,
62
138
  color: themeColors.foreground,
@@ -1258,6 +1334,9 @@ registerTheme({
1258
1334
  activeLineBackground: "#f8fafc",
1259
1335
  selectionBackground: "#dbeafe",
1260
1336
  cursorColor: "#3b82f6",
1337
+ diffAdded: "#1a7f37",
1338
+ diffModified: "#0969da",
1339
+ diffRemoved: "#cf222e",
1261
1340
  keyword: "#8b5cf6",
1262
1341
  string: "#059669",
1263
1342
  comment: "#94a3b8",
@@ -1286,6 +1365,9 @@ registerTheme({
1286
1365
  activeLineBackground: "#27272a",
1287
1366
  selectionBackground: "#1e3a5f",
1288
1367
  cursorColor: "#60a5fa",
1368
+ diffAdded: "#3fb950",
1369
+ diffModified: "#4184e4",
1370
+ diffRemoved: "#f85149",
1289
1371
  keyword: "#c084fc",
1290
1372
  string: "#34d399",
1291
1373
  comment: "#71717a",
@@ -1615,9 +1697,14 @@ function CodeEditorRoot({
1615
1697
  minHeight,
1616
1698
  maxHeight,
1617
1699
  cursorLine,
1618
- cursorColumn
1700
+ cursorColumn,
1701
+ diffBase
1619
1702
  }) {
1620
1703
  const [currentValue, setCurrentValue] = useControllableState(valueProp, defaultValue, onChange);
1704
+ const diffAnnotations = useMemo(
1705
+ () => diffBase == null ? null : annotateLines(diffBase, currentValue),
1706
+ [diffBase, currentValue]
1707
+ );
1621
1708
  const isDark = useDarkMode();
1622
1709
  const resolvedTheme = theme === "auto" ? isDark ? "dark" : "light" : theme;
1623
1710
  const [currentLanguage, setCurrentLanguageState] = useState(() => {
@@ -1696,11 +1783,17 @@ function CodeEditorRoot({
1696
1783
  selectionLength,
1697
1784
  textareaRef: engineReturn.textareaRef,
1698
1785
  placeholder,
1786
+ diffStats: diffAnnotations ? {
1787
+ added: diffAnnotations.added,
1788
+ modified: diffAnnotations.modified,
1789
+ removed: diffAnnotations.removed
1790
+ } : null,
1791
+ _diffAnnotations: diffAnnotations,
1699
1792
  _engineReturn: engineReturn,
1700
1793
  _minHeight: minHeight,
1701
1794
  _maxHeight: maxHeight
1702
1795
  }),
1703
- [engineReturn, currentValue, currentLanguage, setLanguage, resolvedTheme, readOnly, showLineNumbers, isWordWrap, tabSizeProp, cursorPosition, selectionLength, setCurrentValue, placeholder, minHeight, maxHeight]
1796
+ [engineReturn, currentValue, currentLanguage, setLanguage, resolvedTheme, readOnly, showLineNumbers, isWordWrap, tabSizeProp, cursorPosition, selectionLength, setCurrentValue, placeholder, diffAnnotations, minHeight, maxHeight]
1704
1797
  );
1705
1798
  return /* @__PURE__ */ jsx(CodeEditorContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
1706
1799
  "div",
@@ -1876,44 +1969,6 @@ function MarkdownEditor({
1876
1969
  );
1877
1970
  }
1878
1971
  MarkdownEditor.displayName = "MarkdownEditor";
1879
- var EXT_LANGUAGE = {
1880
- js: "javascript",
1881
- mjs: "javascript",
1882
- cjs: "javascript",
1883
- jsx: "javascript",
1884
- json: "javascript",
1885
- // the JS tokenizer highlights JSON acceptably
1886
- jsonc: "javascript",
1887
- ts: "typescript",
1888
- mts: "typescript",
1889
- cts: "typescript",
1890
- tsx: "typescript",
1891
- html: "html",
1892
- htm: "html",
1893
- xml: "html",
1894
- xhtml: "html",
1895
- vue: "html",
1896
- php: "php",
1897
- phtml: "php",
1898
- py: "python",
1899
- pyw: "python",
1900
- go: "go",
1901
- md: "markdown",
1902
- markdown: "markdown",
1903
- mkd: "markdown",
1904
- mdx: "markdown"
1905
- };
1906
- function basename(filename) {
1907
- return filename.split(/[?#]/, 1)[0].split(/[\\/]/).pop() ?? "";
1908
- }
1909
- function languageFromFilename(filename) {
1910
- if (!filename) return "plaintext";
1911
- const seg = basename(filename);
1912
- const dot = seg.lastIndexOf(".");
1913
- if (dot <= 0) return "plaintext";
1914
- const ext = seg.slice(dot + 1).toLowerCase();
1915
- return EXT_LANGUAGE[ext] ?? "plaintext";
1916
- }
1917
1972
  function resolveFileKind({ filename, mime }) {
1918
1973
  const media = resolveMediaType({ mime, src: filename });
1919
1974
  if (media !== "unknown") return { kind: "media", mediaKind: media };
@@ -1997,6 +2052,6 @@ function CodeEditorInputTag(props) {
1997
2052
  return /* @__PURE__ */ jsx(InputTag, { adapter, ...props });
1998
2053
  }
1999
2054
 
2000
- export { CodeEditor, CodeEditorInputTag, FileViewer, MarkdownEditor, getLanguage, getRegisteredLanguages, getRegisteredThemes, getTheme, languageFromFilename, registerLanguage, registerTheme, renderMarkdown, resolveFileKind, tokenizeMarkdown, useCodeEditor, useCodeEditorInputTagAdapter };
2055
+ export { CodeEditor, CodeEditorInputTag, FileViewer, MarkdownEditor, diffMarkColor, diffRemovedColor, getLanguage, getRegisteredLanguages, getRegisteredThemes, getTheme, gutterDiffMark, hasDeletedAtEnd, registerLanguage, registerTheme, renderMarkdown, resolveFileKind, tokenizeMarkdown, useCodeEditor, useCodeEditorInputTagAdapter };
2001
2056
  //# sourceMappingURL=index.js.map
2002
2057
  //# sourceMappingURL=index.js.map