@rcarls/rc-textarea-adapters 0.6.0 → 0.7.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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @rcarls/rc-textarea-adapters
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 253ba66: Correct package dependency declarations and prevent bundled Markdown implementation types from
8
+ leaking into the editor declarations.
9
+
10
+ BREAKING CHANGE: `@rcarls/rc-textarea-adapters` now treats `@rcarls/rc-textarea` as a peer instead
11
+ of installing it as a runtime dependency. Both textarea extension packages require a compatible
12
+ pre-1 `@rcarls/rc-textarea` release; install it alongside either extension package when upgrading.
13
+
3
14
  ## 0.6.0
4
15
 
5
16
  ### Patch Changes
package/README.md CHANGED
@@ -13,7 +13,8 @@ Full API, usage examples, and keyboard/accessibility notes are on the
13
13
 
14
14
  ## Peer dependencies
15
15
 
16
- All adapters are optional. Install only the peer(s) you use:
16
+ Install `@rcarls/rc-textarea` alongside this package. The tokenizer integrations
17
+ are optional, so install only the additional peer used by your chosen adapter:
17
18
 
18
19
  | Adapter | Peer dependency |
19
20
  | ------- | --------------- |
@@ -12,7 +12,8 @@ function p(o, s) {
12
12
  }
13
13
  function l(o, s) {
14
14
  if (s(o), o.children)
15
- for (const r of o.children) l(r, s);
15
+ for (const r of o.children)
16
+ l(r, s);
16
17
  }
17
18
  function d(o, s) {
18
19
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"rc-textarea-adapters.js","sources":["../src/lezer.ts","../src/unified.ts","../src/shiki.ts"],"sourcesContent":["import type { RCTextareaPlugin, MarkDecoration, DecorationInput } from '@rcarls/rc-textarea';\n\n/** Minimal structural shape of a lezer `Parser` / language's `.parser`. */\ninterface LezerParser {\n parse(input: string): {\n cursor(): LezerCursor;\n };\n}\n\ninterface LezerCursor {\n type: { name: string };\n from: number;\n to: number;\n next(): boolean;\n}\n\n/**\n * Create an `rc-textarea` plugin that uses a lezer parser (e.g. any `@codemirror/lang-*` package)\n * to produce syntax decorations.\n *\n * Lezer node offsets (`.from` / `.to`) are already absolute character offsets, identical to\n * rc-textarea's coordinate space — no conversion is needed.\n *\n * ```ts\n * import { javascript } from '@codemirror/lang-javascript';\n * import { createLezerPlugin } from '@rcarls/rc-textarea-adapters';\n *\n * editor.usePlugin(createLezerPlugin(javascript().language.parser, {\n * VariableDeclaration: { color: 'var(--color-keyword)' },\n * String: { color: 'var(--color-string)' },\n * LineComment: { italic: true, color: 'var(--color-comment)' },\n * }));\n * ```\n */\nexport function createLezerPlugin(\n parser: LezerParser,\n nodeTypeToStyle: Record<string, Omit<MarkDecoration, 'id' | 'type' | 'from' | 'to'>>,\n): RCTextareaPlugin {\n return {\n update(value, api) {\n const tree = parser.parse(value);\n const cursor = tree.cursor();\n const decorations: DecorationInput[] = [];\n do {\n const style = nodeTypeToStyle[cursor.type.name];\n if (style) {\n decorations.push({ type: 'mark', from: cursor.from, to: cursor.to, ...style });\n }\n } while (cursor.next());\n api.setDecorations(decorations);\n },\n };\n}\n","import type { RCTextareaPlugin, MarkDecoration, DecorationInput } from '@rcarls/rc-textarea';\n\n/** Minimal structural shape of a unist `Node` (shared by mdast, hast, etc.). */\ninterface UnistNode {\n type: string;\n position?: {\n start: { offset?: number };\n end: { offset?: number };\n };\n children?: UnistNode[];\n}\n\n/** Minimal structural shape of a unified `Processor`. */\ninterface UnifiedProcessor {\n parse(value: string): UnistNode;\n}\n\nfunction visit(node: UnistNode, visitor: (n: UnistNode) => void): void {\n visitor(node);\n if (node.children) {\n for (const child of node.children) visit(child, visitor);\n }\n}\n\n/**\n * Create an `rc-textarea` plugin that uses a unified processor (e.g. `remark-parse` for\n * Markdown, `rehype-parse` for HTML) to produce syntax decorations.\n *\n * Node `position.start.offset` / `position.end.offset` values are absolute character offsets,\n * identical to rc-textarea's coordinate space — no conversion is needed.\n *\n * ```ts\n * import { unified } from 'unified';\n * import remarkParse from 'remark-parse';\n * import { createUnifiedPlugin } from '@rcarls/rc-textarea-adapters';\n *\n * const processor = unified().use(remarkParse);\n *\n * editor.usePlugin(createUnifiedPlugin(processor, {\n * strong: { bold: true },\n * emphasis: { italic: true },\n * inlineCode: { className: 'md-inline-code' },\n * heading: { bold: true, color: 'var(--color-heading)' },\n * }));\n * ```\n */\nexport function createUnifiedPlugin(\n processor: UnifiedProcessor,\n nodeTypeToStyle: Record<string, Omit<MarkDecoration, 'id' | 'type' | 'from' | 'to'>>,\n): RCTextareaPlugin {\n return {\n update(value, api) {\n const tree = processor.parse(value);\n const decorations: DecorationInput[] = [];\n visit(tree, (node) => {\n const style = nodeTypeToStyle[node.type];\n const start = node.position?.start.offset;\n const end = node.position?.end.offset;\n if (style && start !== undefined && end !== undefined) {\n decorations.push({ type: 'mark', from: start, to: end, ...style });\n }\n });\n api.setDecorations(decorations);\n },\n };\n}\n","import type { RCTextareaPlugin, DecorationInput } from '@rcarls/rc-textarea';\n\ninterface ShikiToken {\n content: string;\n color?: string;\n}\n\n/** Minimal structural shape of a shiki `Highlighter`. */\ninterface ShikiHighlighter {\n codeToTokens(\n code: string,\n opts: { lang: string; theme?: string },\n ): Promise<{ tokens: ShikiToken[][] }>;\n}\n\n/**\n * Create an `rc-textarea` plugin that uses a [shiki](https://shiki.style/) `Highlighter`\n * to produce syntax decorations.\n *\n * Shiki tokens carry line-relative offsets; this adapter converts them to the absolute\n * character offsets that rc-textarea expects by tracking position across lines.\n *\n * ```ts\n * import { createHighlighter } from 'shiki';\n * import { createShikiPlugin } from '@rcarls/rc-textarea-adapters';\n *\n * const highlighter = await createHighlighter({\n * themes: ['github-dark'],\n * langs: ['typescript'],\n * });\n *\n * editor.usePlugin(createShikiPlugin(highlighter, 'typescript', 'github-dark'));\n * ```\n */\nexport function createShikiPlugin(\n highlighter: ShikiHighlighter,\n lang: string,\n theme?: string,\n): RCTextareaPlugin {\n return {\n async update(value, api) {\n const result = await highlighter.codeToTokens(value, {\n lang,\n ...(theme ? { theme } : {}),\n });\n\n const decorations: DecorationInput[] = [];\n let offset = 0;\n\n for (const line of result.tokens) {\n for (const token of line) {\n const len = token.content.length;\n if (token.color) {\n decorations.push({\n type: 'mark',\n from: offset,\n to: offset + len,\n color: token.color,\n });\n }\n offset += len;\n }\n offset += 1; // '\\n'\n }\n\n api.setDecorations(decorations);\n },\n };\n}\n"],"names":["createLezerPlugin","parser","nodeTypeToStyle","value","api","cursor","decorations","style","visit","node","visitor","child","createUnifiedPlugin","processor","tree","start","end","createShikiPlugin","highlighter","lang","theme","result","offset","line","token","len"],"mappings":"AAkCO,SAASA,EACdC,GACAC,GACkB;AAClB,SAAO;AAAA,IACL,OAAOC,GAAOC,GAAK;AAEjB,YAAMC,IADOJ,EAAO,MAAME,CAAK,EACX,OAAA,GACdG,IAAiC,CAAA;AACvC,SAAG;AACD,cAAMC,IAAQL,EAAgBG,EAAO,KAAK,IAAI;AAC9C,QAAIE,KACFD,EAAY,KAAK,EAAE,MAAM,QAAQ,MAAMD,EAAO,MAAM,IAAIA,EAAO,IAAI,GAAGE,EAAA,CAAO;AAAA,MAEjF,SAASF,EAAO,KAAA;AAChB,MAAAD,EAAI,eAAeE,CAAW;AAAA,IAChC;AAAA,EAAA;AAEJ;ACnCA,SAASE,EAAMC,GAAiBC,GAAuC;AAErE,MADAA,EAAQD,CAAI,GACRA,EAAK;AACP,eAAWE,KAASF,EAAK,SAAU,CAAAD,EAAMG,GAAOD,CAAO;AAE3D;AAwBO,SAASE,EACdC,GACAX,GACkB;AAClB,SAAO;AAAA,IACL,OAAOC,GAAOC,GAAK;AACjB,YAAMU,IAAOD,EAAU,MAAMV,CAAK,GAC5BG,IAAiC,CAAA;AACvC,MAAAE,EAAMM,GAAM,CAACL,MAAS;AACpB,cAAMF,IAAQL,EAAgBO,EAAK,IAAI,GACjCM,IAAQN,EAAK,UAAU,MAAM,QAC7BO,IAAMP,EAAK,UAAU,IAAI;AAC/B,QAAIF,KAASQ,MAAU,UAAaC,MAAQ,UAC1CV,EAAY,KAAK,EAAE,MAAM,QAAQ,MAAMS,GAAO,IAAIC,GAAK,GAAGT,GAAO;AAAA,MAErE,CAAC,GACDH,EAAI,eAAeE,CAAW;AAAA,IAChC;AAAA,EAAA;AAEJ;AC/BO,SAASW,EACdC,GACAC,GACAC,GACkB;AAClB,SAAO;AAAA,IACL,MAAM,OAAOjB,GAAOC,GAAK;AACvB,YAAMiB,IAAS,MAAMH,EAAY,aAAaf,GAAO;AAAA,QACnD,MAAAgB;AAAA,QACA,GAAIC,IAAQ,EAAE,OAAAA,MAAU,CAAA;AAAA,MAAC,CAC1B,GAEKd,IAAiC,CAAA;AACvC,UAAIgB,IAAS;AAEb,iBAAWC,KAAQF,EAAO,QAAQ;AAChC,mBAAWG,KAASD,GAAM;AACxB,gBAAME,IAAMD,EAAM,QAAQ;AAC1B,UAAIA,EAAM,SACRlB,EAAY,KAAK;AAAA,YACf,MAAM;AAAA,YACN,MAAMgB;AAAA,YACN,IAAIA,IAASG;AAAA,YACb,OAAOD,EAAM;AAAA,UAAA,CACd,GAEHF,KAAUG;AAAA,QACZ;AACA,QAAAH,KAAU;AAAA,MACZ;AAEA,MAAAlB,EAAI,eAAeE,CAAW;AAAA,IAChC;AAAA,EAAA;AAEJ;"}
1
+ {"version":3,"file":"rc-textarea-adapters.js","sources":["../src/lezer.ts","../src/unified.ts","../src/shiki.ts"],"sourcesContent":["import type { RCTextareaPlugin, MarkDecoration, DecorationInput } from '@rcarls/rc-textarea';\n\n/** Minimal structural shape of a lezer `Parser` / language's `.parser`. */\ninterface LezerParser {\n parse(input: string): {\n cursor(): LezerCursor;\n };\n}\n\ninterface LezerCursor {\n type: { name: string };\n from: number;\n to: number;\n next(): boolean;\n}\n\n/**\n * Create an `rc-textarea` plugin that uses a lezer parser (e.g. any `@codemirror/lang-*` package)\n * to produce syntax decorations.\n *\n * Lezer node offsets (`.from` / `.to`) are already absolute character offsets, identical to\n * rc-textarea's coordinate space — no conversion is needed.\n *\n * ```ts\n * import { javascript } from '@codemirror/lang-javascript';\n * import { createLezerPlugin } from '@rcarls/rc-textarea-adapters';\n *\n * editor.usePlugin(createLezerPlugin(javascript().language.parser, {\n * VariableDeclaration: { color: 'var(--color-keyword)' },\n * String: { color: 'var(--color-string)' },\n * LineComment: { italic: true, color: 'var(--color-comment)' },\n * }));\n * ```\n */\nexport function createLezerPlugin(\n parser: LezerParser,\n nodeTypeToStyle: Record<string, Omit<MarkDecoration, 'id' | 'type' | 'from' | 'to'>>,\n): RCTextareaPlugin {\n return {\n update(value, api) {\n const tree = parser.parse(value);\n const cursor = tree.cursor();\n const decorations: DecorationInput[] = [];\n\n do {\n const style = nodeTypeToStyle[cursor.type.name];\n\n if (style) {\n decorations.push({ type: 'mark', from: cursor.from, to: cursor.to, ...style });\n }\n } while (cursor.next());\n\n api.setDecorations(decorations);\n },\n };\n}\n","import type { RCTextareaPlugin, MarkDecoration, DecorationInput } from '@rcarls/rc-textarea';\n\n/** Minimal structural shape of a unist `Node` (shared by mdast, hast, etc.). */\ninterface UnistNode {\n type: string;\n position?: {\n start: { offset?: number };\n end: { offset?: number };\n };\n children?: UnistNode[];\n}\n\n/** Minimal structural shape of a unified `Processor`. */\ninterface UnifiedProcessor {\n parse(value: string): UnistNode;\n}\n\nfunction visit(node: UnistNode, visitor: (n: UnistNode) => void): void {\n visitor(node);\n\n if (node.children) {\n for (const child of node.children) {\n visit(child, visitor);\n }\n }\n}\n\n/**\n * Create an `rc-textarea` plugin that uses a unified processor (e.g. `remark-parse` for\n * Markdown, `rehype-parse` for HTML) to produce syntax decorations.\n *\n * Node `position.start.offset` / `position.end.offset` values are absolute character offsets,\n * identical to rc-textarea's coordinate space — no conversion is needed.\n *\n * ```ts\n * import { unified } from 'unified';\n * import remarkParse from 'remark-parse';\n * import { createUnifiedPlugin } from '@rcarls/rc-textarea-adapters';\n *\n * const processor = unified().use(remarkParse);\n *\n * editor.usePlugin(createUnifiedPlugin(processor, {\n * strong: { bold: true },\n * emphasis: { italic: true },\n * inlineCode: { className: 'md-inline-code' },\n * heading: { bold: true, color: 'var(--color-heading)' },\n * }));\n * ```\n */\nexport function createUnifiedPlugin(\n processor: UnifiedProcessor,\n nodeTypeToStyle: Record<string, Omit<MarkDecoration, 'id' | 'type' | 'from' | 'to'>>,\n): RCTextareaPlugin {\n return {\n update(value, api) {\n const tree = processor.parse(value);\n const decorations: DecorationInput[] = [];\n\n visit(tree, (node) => {\n const style = nodeTypeToStyle[node.type];\n const start = node.position?.start.offset;\n const end = node.position?.end.offset;\n\n if (style && start !== undefined && end !== undefined) {\n decorations.push({ type: 'mark', from: start, to: end, ...style });\n }\n });\n\n api.setDecorations(decorations);\n },\n };\n}\n","import type { RCTextareaPlugin, DecorationInput } from '@rcarls/rc-textarea';\n\ninterface ShikiToken {\n content: string;\n color?: string;\n}\n\n/** Minimal structural shape of a shiki `Highlighter`. */\ninterface ShikiHighlighter {\n codeToTokens(\n code: string,\n opts: { lang: string; theme?: string },\n ): Promise<{ tokens: ShikiToken[][] }>;\n}\n\n/**\n * Create an `rc-textarea` plugin that uses a [shiki](https://shiki.style/) `Highlighter`\n * to produce syntax decorations.\n *\n * Shiki tokens carry line-relative offsets; this adapter converts them to the absolute\n * character offsets that rc-textarea expects by tracking position across lines.\n *\n * ```ts\n * import { createHighlighter } from 'shiki';\n * import { createShikiPlugin } from '@rcarls/rc-textarea-adapters';\n *\n * const highlighter = await createHighlighter({\n * themes: ['github-dark'],\n * langs: ['typescript'],\n * });\n *\n * editor.usePlugin(createShikiPlugin(highlighter, 'typescript', 'github-dark'));\n * ```\n */\nexport function createShikiPlugin(\n highlighter: ShikiHighlighter,\n lang: string,\n theme?: string,\n): RCTextareaPlugin {\n return {\n async update(value, api) {\n const result = await highlighter.codeToTokens(value, {\n lang,\n ...(theme ? { theme } : {}),\n });\n\n const decorations: DecorationInput[] = [];\n let offset = 0;\n\n for (const line of result.tokens) {\n for (const token of line) {\n const len = token.content.length;\n\n if (token.color) {\n decorations.push({\n type: 'mark',\n from: offset,\n to: offset + len,\n color: token.color,\n });\n }\n\n offset += len;\n }\n\n offset += 1; // '\\n'\n }\n\n api.setDecorations(decorations);\n },\n };\n}\n"],"names":["createLezerPlugin","parser","nodeTypeToStyle","value","api","cursor","decorations","style","visit","node","visitor","child","createUnifiedPlugin","processor","tree","start","end","createShikiPlugin","highlighter","lang","theme","result","offset","line","token","len"],"mappings":"AAkCO,SAASA,EACdC,GACAC,GACkB;AAClB,SAAO;AAAA,IACL,OAAOC,GAAOC,GAAK;AAEjB,YAAMC,IADOJ,EAAO,MAAME,CAAK,EACX,OAAA,GACdG,IAAiC,CAAA;AAEvC,SAAG;AACD,cAAMC,IAAQL,EAAgBG,EAAO,KAAK,IAAI;AAE9C,QAAIE,KACFD,EAAY,KAAK,EAAE,MAAM,QAAQ,MAAMD,EAAO,MAAM,IAAIA,EAAO,IAAI,GAAGE,EAAA,CAAO;AAAA,MAEjF,SAASF,EAAO,KAAA;AAEhB,MAAAD,EAAI,eAAeE,CAAW;AAAA,IAChC;AAAA,EAAA;AAEJ;ACtCA,SAASE,EAAMC,GAAiBC,GAAuC;AAGrE,MAFAA,EAAQD,CAAI,GAERA,EAAK;AACP,eAAWE,KAASF,EAAK;AACvB,MAAAD,EAAMG,GAAOD,CAAO;AAG1B;AAwBO,SAASE,EACdC,GACAX,GACkB;AAClB,SAAO;AAAA,IACL,OAAOC,GAAOC,GAAK;AACjB,YAAMU,IAAOD,EAAU,MAAMV,CAAK,GAC5BG,IAAiC,CAAA;AAEvC,MAAAE,EAAMM,GAAM,CAACL,MAAS;AACpB,cAAMF,IAAQL,EAAgBO,EAAK,IAAI,GACjCM,IAAQN,EAAK,UAAU,MAAM,QAC7BO,IAAMP,EAAK,UAAU,IAAI;AAE/B,QAAIF,KAASQ,MAAU,UAAaC,MAAQ,UAC1CV,EAAY,KAAK,EAAE,MAAM,QAAQ,MAAMS,GAAO,IAAIC,GAAK,GAAGT,GAAO;AAAA,MAErE,CAAC,GAEDH,EAAI,eAAeE,CAAW;AAAA,IAChC;AAAA,EAAA;AAEJ;ACrCO,SAASW,EACdC,GACAC,GACAC,GACkB;AAClB,SAAO;AAAA,IACL,MAAM,OAAOjB,GAAOC,GAAK;AACvB,YAAMiB,IAAS,MAAMH,EAAY,aAAaf,GAAO;AAAA,QACnD,MAAAgB;AAAA,QACA,GAAIC,IAAQ,EAAE,OAAAA,MAAU,CAAA;AAAA,MAAC,CAC1B,GAEKd,IAAiC,CAAA;AACvC,UAAIgB,IAAS;AAEb,iBAAWC,KAAQF,EAAO,QAAQ;AAChC,mBAAWG,KAASD,GAAM;AACxB,gBAAME,IAAMD,EAAM,QAAQ;AAE1B,UAAIA,EAAM,SACRlB,EAAY,KAAK;AAAA,YACf,MAAM;AAAA,YACN,MAAMgB;AAAA,YACN,IAAIA,IAASG;AAAA,YACb,OAAOD,EAAM;AAAA,UAAA,CACd,GAGHF,KAAUG;AAAA,QACZ;AAEA,QAAAH,KAAU;AAAA,MACZ;AAEA,MAAAlB,EAAI,eAAeE,CAAW;AAAA,IAChC;AAAA,EAAA;AAEJ;"}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.6.0",
6
+ "version": "0.7.0",
7
7
  "description": "Adapter factories that connect Lezer, unified, and Shiki tokenizers to rc-textarea.",
8
8
  "repository": {
9
9
  "type": "git",
@@ -30,11 +30,9 @@
30
30
  "scripts": {
31
31
  "build": "tsc && vite build"
32
32
  },
33
- "dependencies": {
34
- "@rcarls/rc-textarea": "0.6.0"
35
- },
36
33
  "peerDependencies": {
37
34
  "@lezer/common": ">=1.0.0",
35
+ "@rcarls/rc-textarea": ">=0.2.0 <1.0.0",
38
36
  "shiki": ">=1.0.0",
39
37
  "unified": ">=11.0.0"
40
38
  },
@@ -50,6 +48,8 @@
50
48
  }
51
49
  },
52
50
  "devDependencies": {
51
+ "@rcarls/rc-textarea": "0.7.0",
52
+ "lit": "^3.0.0",
53
53
  "typescript": "~5.9.3",
54
54
  "vite": "^7.1.7",
55
55
  "vite-plugin-dts": "^4.5.4"