@particle-academy/fancy-code 0.8.0 → 0.9.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,34 +1,9 @@
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
+ import { ThemeColors, DiffAnnotations, LineChangeType, Token, Tokenizer } from '@particle-academy/fancy-file-commons';
4
+ export { ThemeColors, Token, TokenType, Tokenizer, languageFromFilename } from '@particle-academy/fancy-file-commons';
5
5
  import { MediaKind, MediaViewerProps, InputTagProps, InputTagTriggers, InputTagAdapter } from '@particle-academy/react-fancy';
6
6
 
7
- interface ThemeColors {
8
- background: string;
9
- foreground: string;
10
- gutterBackground: string;
11
- gutterForeground: string;
12
- gutterBorder: string;
13
- activeLineBackground: string;
14
- selectionBackground: string;
15
- cursorColor: string;
16
- diffAdded?: string;
17
- diffModified?: string;
18
- diffRemoved?: string;
19
- keyword: string;
20
- string: string;
21
- comment: string;
22
- number: string;
23
- operator: string;
24
- function: string;
25
- type: string;
26
- tag: string;
27
- attribute: string;
28
- attributeValue: string;
29
- punctuation: string;
30
- variable: string;
31
- }
32
7
  interface ThemeDefinition {
33
8
  /** Unique theme name */
34
9
  name: string;
@@ -407,14 +382,6 @@ declare function diffRemovedColor(colors: ThemeColors): string;
407
382
  */
408
383
  declare function renderMarkdown(markdown: string): string;
409
384
 
410
- type TokenType = "keyword" | "string" | "comment" | "number" | "operator" | "tag" | "attribute" | "attributeValue" | "punctuation" | "function" | "type" | "variable" | "plain";
411
- interface Token {
412
- type: TokenType;
413
- start: number;
414
- end: number;
415
- }
416
- type Tokenizer = (source: string) => Token[];
417
-
418
385
  /**
419
386
  * Minimal, dependency-free Markdown tokenizer for editor highlighting. Line-based
420
387
  * for block constructs (fences, headings, blockquotes, list markers) plus a few
@@ -481,4 +448,4 @@ interface CodeEditorInputTagProps extends Omit<InputTagProps, "adapter"> {
481
448
  */
482
449
  declare function CodeEditorInputTag(props: CodeEditorInputTagProps): react.JSX.Element;
483
450
 
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 };
451
+ 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 ThemeDefinition, diffMarkColor, diffRemovedColor, getLanguage, getRegisteredLanguages, getRegisteredThemes, getTheme, gutterDiffMark, hasDeletedAtEnd, registerLanguage, registerTheme, renderMarkdown, resolveFileKind, tokenizeMarkdown, useCodeEditor, useCodeEditorInputTagAdapter };
package/dist/index.d.ts CHANGED
@@ -1,34 +1,9 @@
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
+ import { ThemeColors, DiffAnnotations, LineChangeType, Token, Tokenizer } from '@particle-academy/fancy-file-commons';
4
+ export { ThemeColors, Token, TokenType, Tokenizer, languageFromFilename } from '@particle-academy/fancy-file-commons';
5
5
  import { MediaKind, MediaViewerProps, InputTagProps, InputTagTriggers, InputTagAdapter } from '@particle-academy/react-fancy';
6
6
 
7
- interface ThemeColors {
8
- background: string;
9
- foreground: string;
10
- gutterBackground: string;
11
- gutterForeground: string;
12
- gutterBorder: string;
13
- activeLineBackground: string;
14
- selectionBackground: string;
15
- cursorColor: string;
16
- diffAdded?: string;
17
- diffModified?: string;
18
- diffRemoved?: string;
19
- keyword: string;
20
- string: string;
21
- comment: string;
22
- number: string;
23
- operator: string;
24
- function: string;
25
- type: string;
26
- tag: string;
27
- attribute: string;
28
- attributeValue: string;
29
- punctuation: string;
30
- variable: string;
31
- }
32
7
  interface ThemeDefinition {
33
8
  /** Unique theme name */
34
9
  name: string;
@@ -407,14 +382,6 @@ declare function diffRemovedColor(colors: ThemeColors): string;
407
382
  */
408
383
  declare function renderMarkdown(markdown: string): string;
409
384
 
410
- type TokenType = "keyword" | "string" | "comment" | "number" | "operator" | "tag" | "attribute" | "attributeValue" | "punctuation" | "function" | "type" | "variable" | "plain";
411
- interface Token {
412
- type: TokenType;
413
- start: number;
414
- end: number;
415
- }
416
- type Tokenizer = (source: string) => Token[];
417
-
418
385
  /**
419
386
  * Minimal, dependency-free Markdown tokenizer for editor highlighting. Line-based
420
387
  * for block constructs (fences, headings, blockquotes, list markers) plus a few
@@ -481,4 +448,4 @@ interface CodeEditorInputTagProps extends Omit<InputTagProps, "adapter"> {
481
448
  */
482
449
  declare function CodeEditorInputTag(props: CodeEditorInputTagProps): react.JSX.Element;
483
450
 
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 };
451
+ 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 ThemeDefinition, diffMarkColor, diffRemovedColor, getLanguage, getRegisteredLanguages, getRegisteredThemes, getTheme, gutterDiffMark, hasDeletedAtEnd, registerLanguage, registerTheme, renderMarkdown, resolveFileKind, tokenizeMarkdown, useCodeEditor, useCodeEditorInputTagAdapter };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
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';
3
+ import { annotateLines, highlightCode, tok, tokenizeHtml, LIGHT_COLORS, DARK_COLORS, languageFromFilename } from '@particle-academy/fancy-file-commons';
4
4
  export { languageFromFilename } from '@particle-academy/fancy-file-commons';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
6
 
@@ -445,89 +445,6 @@ var tokenizeJavaScript = (source) => {
445
445
  return tokens;
446
446
  };
447
447
 
448
- // src/engine/tokenizers/html.ts
449
- var tokenizeHtml = (source) => {
450
- const tokens = [];
451
- const len = source.length;
452
- let i = 0;
453
- while (i < len) {
454
- if (source[i] === "<" && source.slice(i, i + 4) === "<!--") {
455
- const pos2 = i;
456
- i += 4;
457
- while (i < len && source.slice(i, i + 3) !== "-->") i++;
458
- i += 3;
459
- tokens.push({ type: "comment", start: pos2, end: i });
460
- continue;
461
- }
462
- if (source[i] === "<" && source.slice(i, i + 9).toUpperCase() === "<!DOCTYPE") {
463
- const pos2 = i;
464
- while (i < len && source[i] !== ">") i++;
465
- i++;
466
- tokens.push({ type: "keyword", start: pos2, end: i });
467
- continue;
468
- }
469
- if (source[i] === "<") {
470
- tokens.push({ type: "punctuation", start: i, end: i + 1 });
471
- i++;
472
- if (i < len && source[i] === "/") {
473
- tokens.push({ type: "punctuation", start: i, end: i + 1 });
474
- i++;
475
- }
476
- if (i < len && /[a-zA-Z]/.test(source[i])) {
477
- const pos2 = i;
478
- while (i < len && /[a-zA-Z0-9-]/.test(source[i])) i++;
479
- tokens.push({ type: "tag", start: pos2, end: i });
480
- }
481
- while (i < len && source[i] !== ">" && !(source[i] === "/" && source[i + 1] === ">")) {
482
- if (source[i] === " " || source[i] === " " || source[i] === "\n" || source[i] === "\r") {
483
- i++;
484
- continue;
485
- }
486
- if (/[a-zA-Z_@:]/.test(source[i])) {
487
- const pos2 = i;
488
- while (i < len && /[a-zA-Z0-9_\-:.]/.test(source[i])) i++;
489
- tokens.push({ type: "attribute", start: pos2, end: i });
490
- while (i < len && (source[i] === " " || source[i] === " ")) i++;
491
- if (i < len && source[i] === "=") {
492
- tokens.push({ type: "operator", start: i, end: i + 1 });
493
- i++;
494
- while (i < len && (source[i] === " " || source[i] === " ")) i++;
495
- if (i < len && (source[i] === '"' || source[i] === "'")) {
496
- const quote = source[i];
497
- const pos3 = i;
498
- i++;
499
- while (i < len && source[i] !== quote) i++;
500
- i++;
501
- tokens.push({ type: "attributeValue", start: pos3, end: i });
502
- } else if (i < len && /[^\s>]/.test(source[i])) {
503
- const pos3 = i;
504
- while (i < len && /[^\s>]/.test(source[i])) i++;
505
- tokens.push({ type: "attributeValue", start: pos3, end: i });
506
- }
507
- }
508
- continue;
509
- }
510
- i++;
511
- }
512
- if (i < len && source[i] === "/") {
513
- tokens.push({ type: "punctuation", start: i, end: i + 1 });
514
- i++;
515
- }
516
- if (i < len && source[i] === ">") {
517
- tokens.push({ type: "punctuation", start: i, end: i + 1 });
518
- i++;
519
- }
520
- continue;
521
- }
522
- const pos = i;
523
- while (i < len && source[i] !== "<") i++;
524
- if (i > pos) {
525
- tokens.push({ type: "plain", start: pos, end: i });
526
- }
527
- }
528
- return tokens;
529
- };
530
-
531
448
  // src/engine/tokenizers/php.ts
532
449
  var PHP_KEYWORDS = /* @__PURE__ */ new Set([
533
450
  "abstract",
@@ -1111,11 +1028,6 @@ var tokenizeGo = (source) => {
1111
1028
  return tokens;
1112
1029
  };
1113
1030
 
1114
- // src/engine/tokenizer.ts
1115
- function tok(type, s, e) {
1116
- return { type, start: s, end: e };
1117
- }
1118
-
1119
1031
  // src/engine/tokenizers/markdown.ts
1120
1032
  function tokenizeMarkdown(source) {
1121
1033
  const tokens = [];
@@ -1320,112 +1232,17 @@ function getTheme(name) {
1320
1232
  function getRegisteredThemes() {
1321
1233
  return Array.from(themeRegistry.keys());
1322
1234
  }
1323
-
1324
- // src/themes/light.ts
1325
1235
  registerTheme({
1326
1236
  name: "light",
1327
1237
  variant: "light",
1328
- colors: {
1329
- background: "#ffffff",
1330
- foreground: "#1e1e2e",
1331
- gutterBackground: "#f8fafc",
1332
- gutterForeground: "#94a3b8",
1333
- gutterBorder: "#e2e8f0",
1334
- activeLineBackground: "#f8fafc",
1335
- selectionBackground: "#dbeafe",
1336
- cursorColor: "#3b82f6",
1337
- diffAdded: "#1a7f37",
1338
- diffModified: "#0969da",
1339
- diffRemoved: "#cf222e",
1340
- keyword: "#8b5cf6",
1341
- string: "#059669",
1342
- comment: "#94a3b8",
1343
- number: "#d97706",
1344
- operator: "#0891b2",
1345
- function: "#2563eb",
1346
- type: "#d97706",
1347
- tag: "#dc2626",
1348
- attribute: "#d97706",
1349
- attributeValue: "#059669",
1350
- punctuation: "#64748b",
1351
- variable: "#1e1e2e"
1352
- }
1238
+ colors: LIGHT_COLORS
1353
1239
  });
1354
-
1355
- // src/themes/dark.ts
1356
1240
  registerTheme({
1357
1241
  name: "dark",
1358
1242
  variant: "dark",
1359
- colors: {
1360
- background: "#18181b",
1361
- foreground: "#e4e4e7",
1362
- gutterBackground: "#18181b",
1363
- gutterForeground: "#52525b",
1364
- gutterBorder: "#27272a",
1365
- activeLineBackground: "#27272a",
1366
- selectionBackground: "#1e3a5f",
1367
- cursorColor: "#60a5fa",
1368
- diffAdded: "#3fb950",
1369
- diffModified: "#4184e4",
1370
- diffRemoved: "#f85149",
1371
- keyword: "#c084fc",
1372
- string: "#34d399",
1373
- comment: "#71717a",
1374
- number: "#fbbf24",
1375
- operator: "#22d3ee",
1376
- function: "#60a5fa",
1377
- type: "#fbbf24",
1378
- tag: "#f87171",
1379
- attribute: "#fbbf24",
1380
- attributeValue: "#34d399",
1381
- punctuation: "#a1a1aa",
1382
- variable: "#e4e4e7"
1383
- }
1243
+ colors: DARK_COLORS
1384
1244
  });
1385
1245
 
1386
- // src/engine/highlight.ts
1387
- function escapeHtml(text) {
1388
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1389
- }
1390
- var COLOR_RE = /^(#[0-9a-fA-F]{3,8}|(?:rgb|rgba|hsl|hsla)\([\d\s,.%/-]+\)|[a-zA-Z]+)$/;
1391
- function safeColor(value) {
1392
- return typeof value === "string" && COLOR_RE.test(value.trim()) ? value.trim() : "inherit";
1393
- }
1394
- function highlightCode(source, tokens, colors) {
1395
- if (tokens.length === 0) return escapeHtml(source);
1396
- const colorMap = {
1397
- keyword: colors.keyword,
1398
- string: colors.string,
1399
- comment: colors.comment,
1400
- number: colors.number,
1401
- operator: colors.operator,
1402
- function: colors.function,
1403
- type: colors.type,
1404
- tag: colors.tag,
1405
- attribute: colors.attribute,
1406
- attributeValue: colors.attributeValue,
1407
- punctuation: colors.punctuation,
1408
- variable: colors.variable,
1409
- plain: colors.foreground
1410
- };
1411
- const parts = [];
1412
- let pos = 0;
1413
- for (const token of tokens) {
1414
- if (token.start > pos) {
1415
- parts.push(escapeHtml(source.slice(pos, token.start)));
1416
- }
1417
- const text = escapeHtml(source.slice(token.start, token.end));
1418
- const color = safeColor(colorMap[token.type]);
1419
- const style = token.type === "comment" ? `color:${color};font-style:italic` : `color:${color}`;
1420
- parts.push(`<span style="${style}">${text}</span>`);
1421
- pos = token.end;
1422
- }
1423
- if (pos < source.length) {
1424
- parts.push(escapeHtml(source.slice(pos)));
1425
- }
1426
- return parts.join("");
1427
- }
1428
-
1429
1246
  // src/engine/position.ts
1430
1247
  function lineColumnToOffset(text, line, column = 1) {
1431
1248
  const lines = text.split("\n");
@@ -1818,7 +1635,7 @@ var CodeEditor = Object.assign(CodeEditorRoot, {
1818
1635
  });
1819
1636
 
1820
1637
  // src/engine/markdown-render.ts
1821
- function escapeHtml2(s) {
1638
+ function escapeHtml(s) {
1822
1639
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1823
1640
  }
1824
1641
  function escapeAttr(s) {
@@ -1859,10 +1676,10 @@ function renderMarkdown(markdown) {
1859
1676
  i++;
1860
1677
  }
1861
1678
  i++;
1862
- out.push(`<pre><code${lang ? ` class="language-${escapeAttr(escapeHtml2(lang))}"` : ""}>${escapeHtml2(body.join("\n"))}</code></pre>`);
1679
+ out.push(`<pre><code${lang ? ` class="language-${escapeAttr(escapeHtml(lang))}"` : ""}>${escapeHtml(body.join("\n"))}</code></pre>`);
1863
1680
  continue;
1864
1681
  }
1865
- const esc = escapeHtml2(line);
1682
+ const esc = escapeHtml(line);
1866
1683
  if (/^\s*$/.test(line)) {
1867
1684
  flushPara();
1868
1685
  closeList();