@aiao/code-editor-angular 0.0.23 → 0.0.25

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/README.md CHANGED
@@ -8,6 +8,10 @@
8
8
  pnpm add @aiao/code-editor @aiao/code-editor-angular
9
9
  ```
10
10
 
11
+ `@aiao/code-editor` 是 peer 依赖,且下界跟随本包版本抬升 —— 本包生成的 `.d.ts`
12
+ 直接引用核心包的 `CodeEditorLanguageDescription` / `ResolvedCodeEditorLanguage` /
13
+ `CodeEditorLanguageError`,装到更旧的核心包上会在消费者侧编译失败。
14
+
11
15
  ## 使用
12
16
 
13
17
  ```ts
@@ -30,3 +34,128 @@ export class AppComponent {
30
34
  }
31
35
  }
32
36
  ```
37
+
38
+ ## Reactive Forms
39
+
40
+ ```ts
41
+ import { Component } from '@angular/core';
42
+ import { FormControl, ReactiveFormsModule } from '@angular/forms';
43
+ import { CodeEditor } from '@aiao/code-editor-angular';
44
+
45
+ @Component({
46
+ selector: 'app-editor',
47
+ imports: [ReactiveFormsModule, CodeEditor],
48
+ template: `<ao-code-editor [formControl]="code" label="SQL 查询" language="sql" />`
49
+ })
50
+ export class EditorComponent {
51
+ code = new FormControl('select 1', { nonNullable: true });
52
+ }
53
+ ```
54
+
55
+ `writeValue()` 只接受 `string | null | undefined`(`null` / `undefined` 规整成空串)。
56
+ `FormControl` 里放别的类型会立刻抛 `TypeError`,而不是等到 CodeMirror 内部炸掉。
57
+
58
+ ## Inputs
59
+
60
+ | 名称 | 类型 | 默认值 | 说明 |
61
+ | --------------------- | ------------------------------------------ | ------------------- | ------------------------------------------------------- |
62
+ | `value` | `string` | `''` | 文档内容;与 `ngModel` / `formControl` 同用时以表单为准 |
63
+ | `language` | `string` | `'sql'` | 语言名或别名;`''` 与 `'plaintext'` 表示不高亮 |
64
+ | `languages` | `readonly CodeEditorLanguageDescription[]` | `SUPPORT_LANGUAGES` | 候选语言列表 |
65
+ | `theme` | `'light' \| 'dark'` | `'light'` | 主题 |
66
+ | `setup` | `'basic' \| 'minimal' \| null` | `'basic'` | CodeMirror 预设扩展集 |
67
+ | `placeholder` | `string` | `''` | 空文档时的占位文本 |
68
+ | `disabled` | `boolean` | `false` | 禁用(只读且不可聚焦) |
69
+ | `readonly` | `boolean` | `false` | 只读(仍可聚焦与选择) |
70
+ | `lineWrapping` | `boolean` | `false` | 自动换行 |
71
+ | `indentUnit` | `string` | `' '` | 一级缩进使用的字符串 |
72
+ | `indentWithTab` | `boolean` | `false` | 允许 Tab 缩进(会牺牲键盘可达性) |
73
+ | `highlightWhitespace` | `boolean` | `false` | 显示空白字符 |
74
+ | `label` | `string` | `''` | 内部 textbox 的 `aria-label` |
75
+ | `labelledBy` | `string` | `''` | 内部 textbox 的 `aria-labelledby` |
76
+ | `describedBy` | `string` | `''` | 内部 textbox 的 `aria-describedby` |
77
+ | `autoFocus` | `boolean` | `false` | **仅初始化生效**,见下 |
78
+ | `root` | `Document \| ShadowRoot` | — | **仅初始化生效**,见下 |
79
+
80
+ 三个 `aria-*` 输入落在 CodeMirror 的 `.cm-content` 上 —— 承担 `role="textbox"` 的是它,
81
+ 不是宿主元素。空串按「未设置」处理,不产出属性。
82
+
83
+ ## Outputs
84
+
85
+ | 名称 | 载荷 | 说明 |
86
+ | ----------------- | ------------------------- | ---------------------------------------------------------- |
87
+ | `aoChange` | `string` | 用户编辑导致的内容变化;程序化写入**不**触发 |
88
+ | `aoFocus` | `void` | 获得焦点 |
89
+ | `aoBlur` | `void` | 失去焦点,同时触发表单 `touched` |
90
+ | `aoLanguageError` | `CodeEditorLanguageError` | 语言查不到(`not-found`)或 `load()` 失败(`load-failed`) |
91
+
92
+ 语言失败时编辑器**降级为纯文本**并继续可用,宿主可据此重试或提示:
93
+
94
+ ```html
95
+ <ao-code-editor (aoLanguageError)="onLanguageError($event)" [language]="lang" />
96
+ ```
97
+
98
+ ```ts
99
+ onLanguageError(error: CodeEditorLanguageError): void {
100
+ if (error.kind === 'load-failed') this.retry(error.language);
101
+ }
102
+ ```
103
+
104
+ ## 仅初始化生效的输入
105
+
106
+ `autoFocus` 与 `root` 只在 `ngOnInit` 构造 `EditorView` 时读取一次,后续变更被忽略 ——
107
+ 两者都对应 CodeMirror 无法重配置的构造期决策。需要改 `root` 时请用 `@if` 重建组件。
108
+
109
+ `autoFocus` 还受访问状态约束:`disabled` 或 `readonly` 为真时**不**抢焦点,
110
+ 否则用户得到一个无法输入、也无从得知为什么无法输入的控件。
111
+
112
+ ## disabled 与 value 的优先级
113
+
114
+ `disabled` 有**两条独立来源**,任一为真即禁用:
115
+
116
+ 1. 模板上的 `[disabled]` 输入;
117
+ 2. 表单调用的 `setDisabledState()`(`FormControl.disable()` / `.enable()`)。
118
+
119
+ 它们不互相覆盖 —— Reactive Forms 在控件 enabled 时会主动调 `setDisabledState(false)`,
120
+ 若两者压成一个值,模板上的 `[disabled]="true"` 会被静默抹掉。要恢复可编辑,两条都得放开。
121
+
122
+ `value` 与表单同时存在时以表单为准:`ngModel` / `formControl` 经 `writeValue()` 写入,
123
+ 时序上晚于 `value` 输入。只用 `value` 而不接表单时,它是普通的单向输入 ——
124
+ 组件不会把用户编辑写回该输入,请配合 `(aoChange)` 自行回填。
125
+
126
+ ## 命令式 handle
127
+
128
+ 组件实例暴露与 React / Vue **同名同义**的四个成员:
129
+
130
+ | 成员 | 类型 | 说明 |
131
+ | --------- | --------------------- | ------------------------------------------------ |
132
+ | `view` | `EditorView \| null` | 底层 CodeMirror 实例;未初始化 / 已销毁为 `null` |
133
+ | `host` | `HTMLElement \| null` | CodeMirror 挂载所在的元素;同上 |
134
+ | `focus()` | `void` | 把键盘焦点交给编辑器;未初始化时空操作 |
135
+ | `blur()` | `void` | 移开键盘焦点;未初始化时空操作 |
136
+
137
+ ```ts
138
+ @Component({
139
+ imports: [CodeEditor],
140
+ template: `<ao-code-editor #editor language="sql" />`
141
+ })
142
+ export class HostComponent {
143
+ private readonly editor = viewChild.required(CodeEditor);
144
+
145
+ jumpIn(): void {
146
+ this.editor().focus();
147
+ }
148
+ }
149
+ ```
150
+
151
+ `setExtensions(extensions)` 是装入自定义 CodeMirror 扩展的受支持入口,
152
+ **整体替换**上一次传入的那批,且只影响消费者自己的槽 —— 组件的主题、语言、
153
+ 只读状态与变更回调都不受影响。
154
+
155
+ `setLanguage(name)` 是**无条件重载**入口,供宿主换掉了同名描述背后的 loader 实现时使用;
156
+ 日常切换语言请改 `language` 输入(它会跳过等价的重复加载)。
157
+
158
+ 其余命令式 setter(`setValue` / `setTheme` / `setReadonly` / `setEditable` /
159
+ `setPlaceholder` / `setIndentUnit` / `setIndentWithTab` / `setLineWrapping` /
160
+ `setHighlightWhitespace`)均已标记 `@deprecated`:它们与同名输入是双轨,
161
+ 直接调用会在下一次输入同步时被覆盖。请改用对应输入,这些方法将在下一个主版本移除。
@@ -1,17 +1,21 @@
1
- import { SUPPORT_LANGUAGES, findLanguageByName } from '@aiao/code-editor';
1
+ import { SUPPORT_LANGUAGES, shouldAutoFocusCodeEditor, computeMinimalDocumentChange, resolveCodeEditorLanguage, codeEditorLanguageNotFound, codeEditorLanguageLoadFailed, isSameResolvedLanguage, buildCodeEditorContentAttributes } from '@aiao/code-editor';
2
2
  import { isPlatformBrowser } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { inject, ElementRef, PLATFORM_ID, input, booleanAttribute, output, linkedSignal, forwardRef, ChangeDetectionStrategy, Component } from '@angular/core';
4
+ import { inject, ElementRef, PLATFORM_ID, signal, computed, input, booleanAttribute, output, forwardRef, ChangeDetectionStrategy, Component } from '@angular/core';
5
5
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
6
6
  import { indentWithTab } from '@codemirror/commands';
7
7
  import { indentUnit } from '@codemirror/language';
8
- import { Annotation, Compartment, EditorState, StateEffect } from '@codemirror/state';
8
+ import { Annotation, Compartment, EditorState, Transaction } from '@codemirror/state';
9
9
  import { oneDark } from '@codemirror/theme-one-dark';
10
10
  import { EditorView, placeholder, keymap, highlightWhitespace } from '@codemirror/view';
11
11
  import { basicSetup, minimalSetup } from 'codemirror';
12
12
 
13
13
  /**
14
- * Annotation to mark external changes that should not trigger onChange
14
+ * 标记「外部写入」的注解,用于让 updateListener 跳过 onChange 回调。
15
+ *
16
+ * @internal
17
+ * 模块私有,不对外导出:每个框架绑定各有一个互不相同的 Annotation 实例,
18
+ * 一旦暴露就等于承诺了一个三端无法对齐的语义(React / Vue 两端同样是模块私有)。
15
19
  */
16
20
  const External = Annotation.define();
17
21
  /**
@@ -31,16 +35,18 @@ const External = Annotation.define();
31
35
  */
32
36
  class CodeEditor {
33
37
  /**
34
- * EditorView instance
38
+ * EditorView 实例。
35
39
  * https://codemirror.net/docs/ref/#view.EditorView
36
40
  */
37
41
  #view;
38
42
  #pendingValue;
39
43
  #languageRequest = 0;
44
+ /** 最近一次**已生效**的语言解析结果,用于跳过等价的重复配置(CEA-006)。 */
45
+ #appliedLanguage;
40
46
  #elementRef = inject(ElementRef);
41
47
  #platformId = inject(PLATFORM_ID);
42
48
  #isBrowser = isPlatformBrowser(this.#platformId);
43
- // Compartments for dynamic reconfiguration
49
+ // 用于动态重新配置的 Compartments。
44
50
  // https://codemirror.net/docs/ref/#state.Compartment
45
51
  #editableConf = new Compartment();
46
52
  #readonlyConf = new Compartment();
@@ -51,46 +57,179 @@ class CodeEditor {
51
57
  #lineWrappingConf = new Compartment();
52
58
  #highlightWhitespaceConf = new Compartment();
53
59
  #languageConf = new Compartment();
54
- // Update listener for content changes
60
+ #a11yConf = new Compartment();
61
+ /** `setup` 预设的专属槽 —— 与 React(`CodeEditor.tsx`)、Vue(`CodeEditor.vue`)同构。 */
62
+ #setupConf = new Compartment();
63
+ /** 消费者经 {@link CodeEditor.setExtensions} 装入的扩展的专属槽,见 CEA-003。 */
64
+ #userExtensionsConf = new Compartment();
65
+ // 内容变化监听器。
55
66
  #updateListener = EditorView.updateListener.of(vu => {
56
67
  if (vu.docChanged && !vu.transactions.some(tr => tr.annotation(External))) {
57
68
  const value = vu.state.doc.toString();
58
- this.onChange?.(value);
69
+ this.#onChange?.(value);
59
70
  this.aoChange.emit(value);
60
71
  }
61
72
  });
62
- // Input properties
73
+ // 焦点事件必须随初始 extensions 一起装配,不能在 EditorView 构造完再 addEventListener:
74
+ // `autoFocus` 的 `view.focus()` 紧跟构造同步派发 focus,后注册的监听器永远吞掉第一次。
75
+ // 用 domEventObservers 还顺带解决了裸监听器没有 removeEventListener 的问题 ——
76
+ // 它随 view.destroy() 一起回收。与 Vue(`CodeEditor.vue:75-78`)同构。
77
+ #domEventObservers = EditorView.domEventObservers({
78
+ focus: () => {
79
+ this.aoFocus.emit();
80
+ },
81
+ blur: () => {
82
+ this.#onTouched?.();
83
+ this.aoBlur.emit();
84
+ }
85
+ });
86
+ /**
87
+ * 表单侧的禁用状态,只由 {@link CodeEditor.setDisabledState} 写入。
88
+ *
89
+ * @internal
90
+ * 必须私有:它只在 `#effectiveDisabled` 里被消费,外部 `.set()` 写了也不会同步到编辑器。
91
+ */
92
+ #formDisabled = signal(false, /* @ts-ignore */
93
+ ...(ngDevMode ? [{ debugName: "#formDisabled" }] : /* istanbul ignore next */ []));
94
+ /**
95
+ * 有效禁用状态 = `disabled` 输入与表单禁用**任一为真**。
96
+ *
97
+ * @internal
98
+ * CEA-004:两条来源早先被压进同一个 `linkedSignal(() => this.disabled())`,
99
+ * 成了「最后写的赢」。它们是**独立的事实**:模板的 `[disabled]="true"` 说
100
+ * 「这个控件永远禁用」,`setDisabledState()` 说「这个 FormControl 当前 disable 了」。
101
+ * 压成一个值有两个可复现的后果 —— Reactive Forms 在控件 enabled 时会主动调
102
+ * `setDisabledState(false)`,把 `[disabled]="true"` 静默抹掉;反过来 `disabled`
103
+ * 输入一变化 `linkedSignal` 就重算,把表单侧刚设的禁用丢掉。
104
+ */
105
+ #effectiveDisabled = computed(() => this.disabled() || this.#formDisabled(), /* @ts-ignore */
106
+ ...(ngDevMode ? [{ debugName: "#effectiveDisabled" }] : /* istanbul ignore next */ []));
107
+ /** @internal 只能经 {@link registerOnChange} 注入,公开会让消费者覆盖后静默切断表单双向绑定。 */
108
+ #onChange;
109
+ /** @internal 只能经 {@link registerOnTouched} 注入,理由同 {@link registerOnChange}。 */
110
+ #onTouched;
111
+ /**
112
+ * 宿主元素上的 `aria-disabled`。
113
+ *
114
+ * @internal
115
+ * 未禁用时返回 `null` 让 Angular **移除**属性,而不是写 `aria-disabled="false"`;
116
+ * 理由与 {@link buildCodeEditorContentAttributes} 一致。`protected` 是可见性下限 ——
117
+ * host 绑定表达式读不到 `#` 私有字段。
118
+ */
119
+ _ariaDisabled = computed(() => (this.#effectiveDisabled() ? 'true' : null), /* @ts-ignore */
120
+ ...(ngDevMode ? [{ debugName: "_ariaDisabled" }] : /* istanbul ignore next */ []));
121
+ // 输入属性。
122
+ /** 初始化后立即聚焦编辑器。**仅初始化生效**,后续变更被忽略。 @defaultValue false */
63
123
  autoFocus = input(false, { ...(ngDevMode ? { debugName: "autoFocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
124
+ /**
125
+ * 补充说明元素的 id,写成内部 textbox 的 `aria-describedby`。可动态更新。
126
+ *
127
+ * @defaultValue ''(空串按「未设置」处理,不产出属性)
128
+ * @remarks 属性落在 CodeMirror 的 `.cm-content` 上 —— 承担 `role="textbox"` 的是它,
129
+ * 不是本组件的宿主元素。三端同名同义。
130
+ */
131
+ describedBy = input('', /* @ts-ignore */
132
+ ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
133
+ /**
134
+ * 禁用编辑(只读且不可聚焦)。可动态更新。
135
+ *
136
+ * @defaultValue false
137
+ * @remarks 与表单的 `setDisabledState()` 是**两条独立来源**,任一为真即禁用。
138
+ * 用 Reactive Forms 时把控件设成 `disabled` 与在模板上写 `[disabled]="true"` 效果一样,
139
+ * 但只解开其中一条不会恢复可编辑 —— 两条都得放开。
140
+ */
64
141
  disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
142
+ /** 显示空白字符。可动态更新。 @defaultValue false */
65
143
  highlightWhitespace = input(false, { ...(ngDevMode ? { debugName: "highlightWhitespace" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
66
- indentUnit = input('', /* @ts-ignore */
144
+ /** 一级缩进使用的字符串。可动态更新。 @defaultValue ' '(两个空格,三端一致) */
145
+ indentUnit = input(' ', /* @ts-ignore */
67
146
  ...(ngDevMode ? [{ debugName: "indentUnit" }] : /* istanbul ignore next */ []));
147
+ /** 允许 Tab 键缩进(会牺牲键盘可达性)。可动态更新。 @defaultValue false */
68
148
  indentWithTab = input(false, { ...(ngDevMode ? { debugName: "indentWithTab" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
69
- language = input('', /* @ts-ignore */
149
+ /** 语法高亮语言名,取值见 {@link languages};`'plaintext'` 表示不高亮。可动态更新。 @defaultValue 'sql' */
150
+ language = input('sql', /* @ts-ignore */
70
151
  ...(ngDevMode ? [{ debugName: "language" }] : /* istanbul ignore next */ []));
152
+ /** 可选语言列表。可动态更新。 @defaultValue SUPPORT_LANGUAGES */
71
153
  languages = input(SUPPORT_LANGUAGES, /* @ts-ignore */
72
154
  ...(ngDevMode ? [{ debugName: "languages" }] : /* istanbul ignore next */ []));
155
+ /**
156
+ * 可访问名称,写成内部 textbox 的 `aria-label`。可动态更新。
157
+ *
158
+ * @defaultValue ''(空串按「未设置」处理,不产出属性)
159
+ * @remarks 落点与 {@link CodeEditor.describedBy} 相同。
160
+ */
161
+ label = input('', /* @ts-ignore */
162
+ ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
163
+ /**
164
+ * 承担标签的元素 id,写成内部 textbox 的 `aria-labelledby`。可动态更新。
165
+ *
166
+ * @defaultValue ''(空串按「未设置」处理,不产出属性)
167
+ * @remarks 落点与 {@link CodeEditor.describedBy} 相同。
168
+ */
169
+ labelledBy = input('', /* @ts-ignore */
170
+ ...(ngDevMode ? [{ debugName: "labelledBy" }] : /* istanbul ignore next */ []));
171
+ /** 自动换行。可动态更新。 @defaultValue false */
73
172
  lineWrapping = input(false, { ...(ngDevMode ? { debugName: "lineWrapping" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
173
+ /** 空文档时显示的占位文本。可动态更新。 @defaultValue '' */
74
174
  placeholder = input('', /* @ts-ignore */
75
175
  ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
176
+ /** 只读(仍可聚焦与选择)。可动态更新。 @defaultValue false */
76
177
  readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
178
+ /** CodeMirror 挂载的 DOM 根,用于 Shadow DOM 场景。**仅初始化生效**。 */
77
179
  root = input(/* @ts-ignore */
78
180
  ...(ngDevMode ? [undefined, { debugName: "root" }] : /* istanbul ignore next */ []));
181
+ /** 预设扩展集;`null` 表示不加载任何预设。可动态更新。 @defaultValue 'basic' */
79
182
  setup = input('basic', /* @ts-ignore */
80
183
  ...(ngDevMode ? [{ debugName: "setup" }] : /* istanbul ignore next */ []));
184
+ /** 主题。可动态更新。 @defaultValue 'light' */
81
185
  theme = input('light', /* @ts-ignore */
82
186
  ...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
187
+ /** 文档内容。作为受控输入使用时由外部驱动;与 `ngModel` 同时使用以 `ngModel` 为准。 @defaultValue '' */
83
188
  value = input('', /* @ts-ignore */
84
189
  ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
85
- // Output events
190
+ // 输出事件。
191
+ /** 编辑器获得焦点。 */
86
192
  aoFocus = output();
193
+ /** 文档内容变化(外部写入不触发,见 {@link External})。 */
87
194
  aoChange = output();
195
+ /** 编辑器失去焦点,同时触发表单 touched。 */
88
196
  aoBlur = output();
89
- // Linked signal for disabled state
90
- useDisabled = linkedSignal(() => this.disabled(), /* @ts-ignore */
91
- ...(ngDevMode ? [{ debugName: "useDisabled" }] : /* istanbul ignore next */ []));
92
- onChange;
93
- onTouched;
197
+ /**
198
+ * 语言解析或加载失败。
199
+ *
200
+ * @remarks
201
+ * CEA-007:这条路径此前只有一条 `console.error`,宿主完全观测不到 ——
202
+ * 拿不到错误、没有重试或降级的机会,用户只看到高亮突然消失。
203
+ * 降级策略不变(清空语言扩展退回纯文本),日志也保留,本事件是**新增的**观测通道。
204
+ * 与 React 的 `onLanguageError` 属性、Vue 的 `language-error` 事件同载荷。
205
+ */
206
+ aoLanguageError = output();
207
+ /**
208
+ * 底层 CodeMirror `EditorView`;未初始化或已销毁时为 `null`。
209
+ *
210
+ * @remarks 三端命令式面统一为 `view` / `host` / `focus()` / `blur()`(CEA-009)。
211
+ */
212
+ get view() {
213
+ return this.#view ?? null;
214
+ }
215
+ /**
216
+ * CodeMirror 挂载所在的宿主元素;未初始化或已销毁时为 `null`。
217
+ *
218
+ * @remarks
219
+ * Angular 的宿主是 `<ao-code-editor>` 元素本身,React / Vue 是组件渲染出的 `div`——
220
+ * 类型不同但语义一致:「CodeMirror 挂在哪个元素里」。
221
+ */
222
+ get host() {
223
+ return this.#view ? this.#elementRef.nativeElement : null;
224
+ }
225
+ /** 把键盘焦点交给编辑器。未初始化时是空操作。 */
226
+ focus() {
227
+ this.#view?.focus();
228
+ }
229
+ /** 移开键盘焦点。未初始化时是空操作。 */
230
+ blur() {
231
+ this.#view?.contentDOM.blur();
232
+ }
94
233
  ngOnInit() {
95
234
  if (!this.#isBrowser)
96
235
  return;
@@ -101,57 +240,68 @@ class CodeEditor {
101
240
  root: this.root(),
102
241
  state
103
242
  });
104
- if (this.autoFocus()) {
243
+ // 访问状态必须先落地:`autoFocus` 要读**已生效**的禁用 / 只读语义,而 `focus()`
244
+ // 又会同步派发 focus 事件,晚同步等于让监听者先读到一个还没对齐的状态。
245
+ this.#syncAccessState();
246
+ // CEA-008(用户可见的行为修正):`disabled` / `readonly` 都会把编辑器配成不可编辑,
247
+ // 此时仍然抢焦点,用户只会得到一个无法输入、也无从得知为什么无法输入的控件。
248
+ if (this.autoFocus() &&
249
+ shouldAutoFocusCodeEditor({ disabled: this.#effectiveDisabled(), readonly: this.readonly() })) {
105
250
  this.#view.focus();
106
251
  }
107
- this.#view.contentDOM.addEventListener('focus', () => {
108
- this.aoFocus.emit();
109
- });
110
- this.#view.contentDOM.addEventListener('blur', () => {
111
- this.onTouched?.();
112
- this.aoBlur.emit();
113
- });
114
- this.#syncAccessState();
115
- this.setTheme(this.theme());
116
- this.setPlaceholder(this.placeholder());
117
- this.setIndentWithTab(this.indentWithTab());
118
- this.setIndentUnit(this.indentUnit());
119
- this.setLineWrapping(this.lineWrapping());
120
- this.setHighlightWhitespace(this.highlightWhitespace());
252
+ this._dispatch_effects(this.#themeConf.reconfigure(this.theme() === 'dark' ? oneDark : []));
253
+ this._dispatch_effects(this.#placeholderConf.reconfigure(this.placeholder() ? placeholder(this.placeholder()) : []));
254
+ this._dispatch_effects(this.#indentWithTabConf.reconfigure(this.indentWithTab() ? keymap.of([indentWithTab]) : []));
255
+ this._dispatch_effects(this.#indentUnitConf.reconfigure(this.indentUnit() ? indentUnit.of(this.indentUnit()) : []));
256
+ this._dispatch_effects(this.#lineWrappingConf.reconfigure(this.lineWrapping() ? EditorView.lineWrapping : []));
257
+ this._dispatch_effects(this.#highlightWhitespaceConf.reconfigure(this.highlightWhitespace() ? highlightWhitespace() : []));
121
258
  this.setLanguage(this.language());
122
259
  }
123
260
  ngOnChanges(changes) {
124
261
  if (!this.#view)
125
262
  return;
126
- if (changes['value']) {
127
- this.setValue(this.value(), true);
263
+ if (changes['value'] && this.#view) {
264
+ const newValue = this.value();
265
+ const change = computeMinimalDocumentChange(this.#view.state.doc.toString(), newValue);
266
+ if (change) {
267
+ this.#view.dispatch({
268
+ changes: change,
269
+ annotations: [External.of(true), Transaction.addToHistory.of(false)],
270
+ scrollIntoView: false
271
+ });
272
+ }
128
273
  }
129
274
  if (changes['disabled'] || changes['readonly']) {
130
275
  this.#syncAccessState();
131
276
  }
277
+ if (changes['describedBy'] || changes['label'] || changes['labelledBy']) {
278
+ this.#syncContentAttributes();
279
+ }
132
280
  if (changes['theme']) {
133
- this.setTheme(this.theme());
281
+ this._dispatch_effects(this.#themeConf.reconfigure(this.theme() === 'dark' ? oneDark : []));
134
282
  }
135
283
  if (changes['placeholder']) {
136
- this.setPlaceholder(this.placeholder());
284
+ this._dispatch_effects(this.#placeholderConf.reconfigure(this.placeholder() ? placeholder(this.placeholder()) : []));
137
285
  }
138
286
  if (changes['indentWithTab']) {
139
- this.setIndentWithTab(this.indentWithTab());
287
+ this._dispatch_effects(this.#indentWithTabConf.reconfigure(this.indentWithTab() ? keymap.of([indentWithTab]) : []));
140
288
  }
141
289
  if (changes['indentUnit']) {
142
- this.setIndentUnit(this.indentUnit());
290
+ this._dispatch_effects(this.#indentUnitConf.reconfigure(this.indentUnit() ? indentUnit.of(this.indentUnit()) : []));
143
291
  }
144
292
  if (changes['lineWrapping']) {
145
- this.setLineWrapping(this.lineWrapping());
293
+ this._dispatch_effects(this.#lineWrappingConf.reconfigure(this.lineWrapping() ? EditorView.lineWrapping : []));
146
294
  }
147
295
  if (changes['highlightWhitespace']) {
148
- this.setHighlightWhitespace(this.highlightWhitespace());
296
+ this._dispatch_effects(this.#highlightWhitespaceConf.reconfigure(this.highlightWhitespace() ? highlightWhitespace() : []));
149
297
  }
150
298
  if (changes['language'] || changes['languages']) {
151
- this.setLanguage(this.language());
299
+ this.#syncLanguage();
152
300
  }
153
301
  if (changes['setup']) {
154
- this.setExtensions(this._get_all_extensions());
302
+ // CEA-003:早先这里调的是 `setExtensions(this._get_all_extensions())`,
303
+ // 即换个预设就把整棵扩展树连同消费者自己装的扩展一起重建。
304
+ this._dispatch_effects(this.#setupConf.reconfigure(this.#setupExtension()));
155
305
  }
156
306
  }
157
307
  ngOnDestroy() {
@@ -160,89 +310,114 @@ class CodeEditor {
160
310
  this.#view = undefined;
161
311
  view?.destroy();
162
312
  }
313
+ /**
314
+ * `ControlValueAccessor` 的写入入口,由 Angular Forms 调用。
315
+ *
316
+ * @param value `null` / `undefined` 规整成空串;`string` 原样写入
317
+ * @throws TypeError 收到其他类型时立即抛出,错误信息含包名与实际类型
318
+ *
319
+ * @remarks
320
+ * CEA-005:签名此前写成 `string | null`,但 CVA 的契约是 `any` —— Angular
321
+ * **不做**运行时校验,`FormControl` 里放什么就原样送到这里。类型标注只骗过了编译期。
322
+ * 于是 `FormControl(42)` 在初始化前进 `#pendingValue`、在 `EditorState.create` 处炸,
323
+ * 初始化后又在 `computeMinimalDocumentChange` 处炸 —— 同一个错误配置,两个时机两种错,
324
+ * 且都指不回 `writeValue`。现在两个时机抛同一个错,且直接点名包与类型。
325
+ */
163
326
  writeValue(value) {
164
- const normalized = value ?? '';
327
+ const normalized = this.#normalizeFormValue(value);
165
328
  if (!this.#view) {
166
329
  this.#pendingValue = normalized;
167
330
  return;
168
331
  }
169
- this.setValue(normalized, true);
332
+ const change = computeMinimalDocumentChange(this.#view.state.doc.toString(), normalized);
333
+ if (change) {
334
+ this.#view.dispatch({
335
+ changes: change,
336
+ annotations: [External.of(true), Transaction.addToHistory.of(false)],
337
+ scrollIntoView: false
338
+ });
339
+ }
170
340
  }
171
341
  registerOnChange(fn) {
172
- this.onChange = fn;
342
+ this.#onChange = fn;
173
343
  }
174
344
  registerOnTouched(fn) {
175
- this.onTouched = fn;
345
+ this.#onTouched = fn;
176
346
  }
347
+ /**
348
+ * 表单侧的禁用开关,由 Angular Forms 调用。
349
+ *
350
+ * @remarks 只写 {@link CodeEditor.#formDisabled} 这一条来源;模板上的
351
+ * `[disabled]` 输入是另一条独立来源,两者取或,见 {@link CodeEditor.#effectiveDisabled}。
352
+ */
177
353
  setDisabledState(isDisabled) {
178
- this.useDisabled.set(isDisabled);
354
+ this.#formDisabled.set(isDisabled);
179
355
  this.#syncAccessState();
180
356
  }
357
+ /**
358
+ * 装入消费者自己的 CodeMirror 扩展。
359
+ *
360
+ * @param value 本次要生效的扩展;**整体替换**上一次传入的那批,传 `[]` 即全部撤下
361
+ *
362
+ * @remarks
363
+ * CEA-003:早先这里发的是全局 `StateEffect.reconfigure.of(value)`,
364
+ * 它替换的是**整棵扩展树** —— 一次调用就清掉 updateListener、全部 Compartment、
365
+ * 主题、语言与 a11y 属性,名字叫「设置扩展」,实际是「摧毁编辑器配置」。
366
+ * 现在只重配 {@link CodeEditor.#userExtensionsConf} 这一个专属槽,
367
+ * 组件自身的配置与消费者的扩展互不影响。
368
+ */
181
369
  setExtensions(value) {
182
- this._dispatch_effects(StateEffect.reconfigure.of(value));
183
- }
184
- setValue(value, external = false) {
185
- const view = this.#view;
186
- if (!view || view.state.doc.toString() === value)
187
- return;
188
- view.dispatch({
189
- changes: { from: 0, to: view.state.doc.length, insert: value },
190
- annotations: external ? External.of(true) : undefined
191
- });
192
- }
193
- setEditable(value) {
194
- this._dispatch_effects(this.#editableConf.reconfigure(EditorView.editable.of(value)));
195
- }
196
- setReadonly(value) {
197
- this._dispatch_effects(this.#readonlyConf.reconfigure(EditorState.readOnly.of(value)));
198
- }
199
- setTheme(value) {
200
- this._dispatch_effects(this.#themeConf.reconfigure(value === 'dark' ? oneDark : []));
201
- }
202
- setPlaceholder(value) {
203
- this._dispatch_effects(this.#placeholderConf.reconfigure(value ? placeholder(value) : []));
204
- }
205
- setIndentWithTab(value) {
206
- this._dispatch_effects(this.#indentWithTabConf.reconfigure(value ? keymap.of([indentWithTab]) : []));
207
- }
208
- setIndentUnit(value) {
209
- this._dispatch_effects(this.#indentUnitConf.reconfigure(value ? indentUnit.of(value) : []));
210
- }
211
- setLineWrapping(value) {
212
- this._dispatch_effects(this.#lineWrappingConf.reconfigure(value ? EditorView.lineWrapping : []));
213
- }
214
- setHighlightWhitespace(value) {
215
- this._dispatch_effects(this.#highlightWhitespaceConf.reconfigure(value ? highlightWhitespace() : []));
370
+ this._dispatch_effects(this.#userExtensionsConf.reconfigure(value));
216
371
  }
372
+ /**
373
+ * 命令式地(重新)应用语言配置。
374
+ *
375
+ * @param lang 语言名或别名;空串与 `'plaintext'` 表示不高亮
376
+ *
377
+ * @remarks
378
+ * **无条件重新加载**,即使解析结果与当前生效的完全一致 —— 这是宿主换掉了同名描述
379
+ * 背后的 loader 实现时的显式重载入口,`language` 输入做不到(它走的是
380
+ * {@link CodeEditor.#syncLanguage} 里的等价性判断,CEA-006,不会重复加载)。
381
+ * 日常切换语言应当改 `language` 输入。
382
+ *
383
+ * 解析失败时清空语言扩展退回纯文本,并经 {@link CodeEditor.aoLanguageError} 报告。
384
+ */
217
385
  setLanguage(lang) {
218
386
  const request = ++this.#languageRequest;
219
387
  const view = this.#view;
220
388
  if (!view)
221
389
  return;
222
- const languages = this.languages();
223
- if (!lang || lang === 'plaintext' || languages.length === 0) {
390
+ const resolved = resolveCodeEditorLanguage(lang, this.languages());
391
+ this.#appliedLanguage = resolved;
392
+ if (resolved.kind === 'none') {
224
393
  view.dispatch({ effects: this.#languageConf.reconfigure([]) });
225
394
  return;
226
395
  }
227
- const langDesc = this._find_language(lang);
228
- if (!langDesc) {
396
+ if (resolved.kind === 'not-found') {
229
397
  view.dispatch({ effects: this.#languageConf.reconfigure([]) });
398
+ // 日志与另两端逐字一致,作为最后兜底诊断保留;结构化事件才是给宿主的契约通道。
399
+ console.error(`[CodeEditor] Language '${lang}' not found.`);
400
+ this.aoLanguageError.emit(codeEditorLanguageNotFound(lang));
230
401
  return;
231
402
  }
232
- void langDesc.load().then(languageSupport => {
403
+ // 直接用解析结果里的 description:早先这里又调一次 `_find_language(lang)` 重查一遍,
404
+ // 同一个名字解析两遍,两处判定一旦分叉就会出现「解析说找到了、重查说没有」。
405
+ void resolved.description.load().then(languageSupport => {
233
406
  if (request !== this.#languageRequest || this.#view !== view)
234
407
  return;
235
408
  view.dispatch({ effects: this.#languageConf.reconfigure(languageSupport.extension) });
236
- }, error => {
409
+ }, (error) => {
237
410
  if (request !== this.#languageRequest || this.#view !== view)
238
411
  return;
239
- console.error(`[code-editor-angular] Failed to load language "${lang}":`, error);
240
412
  view.dispatch({ effects: this.#languageConf.reconfigure([]) });
413
+ console.error(`[CodeEditor] Failed to load language '${lang}':`, error);
414
+ this.aoLanguageError.emit(codeEditorLanguageLoadFailed(lang, error));
241
415
  });
242
416
  }
243
417
  _get_all_extensions() {
244
418
  const extensions = [
245
419
  this.#updateListener,
420
+ this.#domEventObservers,
246
421
  this.#editableConf.of([]),
247
422
  this.#readonlyConf.of([]),
248
423
  this.#themeConf.of([]),
@@ -251,37 +426,93 @@ class CodeEditor {
251
426
  this.#indentUnitConf.of([]),
252
427
  this.#lineWrappingConf.of([]),
253
428
  this.#highlightWhitespaceConf.of([]),
254
- this.#languageConf.of([])
429
+ this.#languageConf.of([]),
430
+ this.#a11yConf.of([]),
431
+ this.#setupConf.of(this.#setupExtension()),
432
+ // 消费者扩展排在最后 —— CodeMirror 里后来的优先级更高,
433
+ // 宿主装的 keymap / 主题覆盖才压得住预设。
434
+ this.#userExtensionsConf.of([])
255
435
  ];
256
- const setup = this.setup();
257
- if (setup === 'basic') {
258
- extensions.push(basicSetup);
259
- }
260
- else if (setup === 'minimal') {
261
- extensions.push(minimalSetup);
262
- }
263
436
  return extensions;
264
437
  }
265
- _find_language(name) {
266
- const languages = this.languages();
267
- const language = findLanguageByName(name, languages);
268
- if (language) {
269
- return language;
270
- }
271
- console.error(`Language "${name}" not found. Supported: ${languages.map(lang => lang.name).join(', ')}`);
272
- return null;
273
- }
274
438
  _dispatch_effects(effects) {
275
439
  return this.#view?.dispatch({ effects });
276
440
  }
441
+ /**
442
+ * `language` / `languages` 输入变化后的语言同步。
443
+ *
444
+ * CEA-006:早先只要 `languages` 的**数组引用**变了就无条件 `setLanguage()`。
445
+ * 父模板写 `[languages]="[myLang]"` 这类内联字面量时每轮变更检测都产生新数组,
446
+ * 于是每轮都重新 `load()` 并 reconfigure 语言 Compartment ——
447
+ * 大文档等于每次输入都整篇重新词法分析,自定义异步 loader 还会多发请求。
448
+ * 判定基准改成「当前语言实际解析到的 description identity」,与 React / Vue 同构。
449
+ */
450
+ #syncLanguage() {
451
+ const language = this.language();
452
+ const resolved = resolveCodeEditorLanguage(language, this.languages());
453
+ if (isSameResolvedLanguage(this.#appliedLanguage, resolved))
454
+ return;
455
+ this.setLanguage(language);
456
+ }
457
+ /**
458
+ * 把无障碍属性写到真正承担 `role="textbox"` 的 `.cm-content` 上。
459
+ *
460
+ * CEA-008 / CER-006:只在宿主 `div` 上补 `aria-*` 是把缺陷换个位置 —— 屏幕阅读器
461
+ * 进到 textbox 之后读到的仍然是一个没有可访问名称、只报 `aria-readonly` 的多行文本框。
462
+ * 属性字典由核心包计算,三端共用同一份实现。
463
+ */
464
+ #syncContentAttributes() {
465
+ this._dispatch_effects(this.#contentAttributesEffect(this.#effectiveDisabled()));
466
+ }
467
+ #contentAttributesEffect(disabled) {
468
+ const attributes = buildCodeEditorContentAttributes({
469
+ describedBy: this.describedBy(),
470
+ disabled,
471
+ label: this.label(),
472
+ labelledBy: this.labelledBy()
473
+ });
474
+ return this.#a11yConf.reconfigure(EditorView.contentAttributes.of(attributes));
475
+ }
277
476
  #syncAccessState() {
278
- const disabled = this.useDisabled();
477
+ const disabled = this.#effectiveDisabled();
279
478
  const readonly = this.readonly();
280
- this.setReadonly(readonly || disabled);
281
- this.setEditable(!readonly && !disabled);
479
+ // CEA-004:三个 Compartment 必须在**同一次** dispatch 里重配。早先是
480
+ // readonly → editable → a11y 三次派发,中间两拍是「只读但仍标记可编辑」
481
+ // 这种自相矛盾的状态,装了 updateListener 的插件全都看得见,还各自重算一遍。
482
+ //
483
+ // 禁用语义也要写给辅助技术:只配 readonly 的话 CodeMirror 只写出 `aria-readonly`,
484
+ // 屏幕阅读器会把禁用控件读成「可编辑但当前只读」,用户以为解锁后就能输入。
485
+ this._dispatch_effects([
486
+ this.#readonlyConf.reconfigure(EditorState.readOnly.of(readonly || disabled)),
487
+ this.#editableConf.reconfigure(EditorView.editable.of(!readonly && !disabled)),
488
+ this.#contentAttributesEffect(disabled)
489
+ ]);
490
+ }
491
+ /** 当前 `setup` 预设对应的扩展;`null` 预设为空数组。 */
492
+ #setupExtension() {
493
+ const setup = this.setup();
494
+ if (setup === 'basic')
495
+ return basicSetup;
496
+ if (setup === 'minimal')
497
+ return minimalSetup;
498
+ return [];
282
499
  }
283
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CodeEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
284
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.5", type: CodeEditor, isStandalone: true, selector: "ao-code-editor", inputs: { autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, highlightWhitespace: { classPropertyName: "highlightWhitespace", publicName: "highlightWhitespace", isSignal: true, isRequired: false, transformFunction: null }, indentUnit: { classPropertyName: "indentUnit", publicName: "indentUnit", isSignal: true, isRequired: false, transformFunction: null }, indentWithTab: { classPropertyName: "indentWithTab", publicName: "indentWithTab", isSignal: true, isRequired: false, transformFunction: null }, language: { classPropertyName: "language", publicName: "language", isSignal: true, isRequired: false, transformFunction: null }, languages: { classPropertyName: "languages", publicName: "languages", isSignal: true, isRequired: false, transformFunction: null }, lineWrapping: { classPropertyName: "lineWrapping", publicName: "lineWrapping", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, root: { classPropertyName: "root", publicName: "root", isSignal: true, isRequired: false, transformFunction: null }, setup: { classPropertyName: "setup", publicName: "setup", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { aoFocus: "aoFocus", aoChange: "aoChange", aoBlur: "aoBlur" }, providers: [
500
+ /**
501
+ * 把 `ControlValueAccessor` 收到的任意值规整成文档内容,见 {@link CodeEditor.writeValue}。
502
+ *
503
+ * @throws TypeError 值既不是字符串也不是 `null` / `undefined`
504
+ */
505
+ #normalizeFormValue(value) {
506
+ if (value === null || value === undefined)
507
+ return '';
508
+ if (typeof value === 'string')
509
+ return value;
510
+ const actual = typeof value === 'object' ? (value.constructor?.name ?? 'object') : typeof value;
511
+ throw new TypeError(`[@aiao/code-editor-angular] writeValue() 只接受 string | null | undefined,实际收到 ${actual}。` +
512
+ '请检查绑定的 FormControl 初始值或 ngModel 表达式。');
513
+ }
514
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: CodeEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
515
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.2", type: CodeEditor, isStandalone: true, selector: "ao-code-editor", inputs: { autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null }, describedBy: { classPropertyName: "describedBy", publicName: "describedBy", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, highlightWhitespace: { classPropertyName: "highlightWhitespace", publicName: "highlightWhitespace", isSignal: true, isRequired: false, transformFunction: null }, indentUnit: { classPropertyName: "indentUnit", publicName: "indentUnit", isSignal: true, isRequired: false, transformFunction: null }, indentWithTab: { classPropertyName: "indentWithTab", publicName: "indentWithTab", isSignal: true, isRequired: false, transformFunction: null }, language: { classPropertyName: "language", publicName: "language", isSignal: true, isRequired: false, transformFunction: null }, languages: { classPropertyName: "languages", publicName: "languages", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, labelledBy: { classPropertyName: "labelledBy", publicName: "labelledBy", isSignal: true, isRequired: false, transformFunction: null }, lineWrapping: { classPropertyName: "lineWrapping", publicName: "lineWrapping", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, root: { classPropertyName: "root", publicName: "root", isSignal: true, isRequired: false, transformFunction: null }, setup: { classPropertyName: "setup", publicName: "setup", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { aoFocus: "aoFocus", aoChange: "aoChange", aoBlur: "aoBlur", aoLanguageError: "aoLanguageError" }, host: { properties: { "attr.aria-disabled": "_ariaDisabled()" } }, providers: [
285
516
  {
286
517
  provide: NG_VALUE_ACCESSOR,
287
518
  useExisting: forwardRef(() => CodeEditor),
@@ -289,31 +520,36 @@ class CodeEditor {
289
520
  }
290
521
  ], usesOnChanges: true, ngImport: i0, template: ``, isInline: true, styles: [":host{display:block;height:100%}:host ::ng-deep .cm-editor{height:100%}:host ::ng-deep .cm-editor.cm-focused{outline:2px solid Highlight;outline-offset:-2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
291
522
  }
292
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CodeEditor, decorators: [{
523
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: CodeEditor, decorators: [{
293
524
  type: Component,
294
- args: [{ selector: 'ao-code-editor', template: ``, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
525
+ args: [{ selector: 'ao-code-editor', template: ``, changeDetection: ChangeDetectionStrategy.OnPush, host: {
526
+ '[attr.aria-disabled]': '_ariaDisabled()'
527
+ }, providers: [
295
528
  {
296
529
  provide: NG_VALUE_ACCESSOR,
297
530
  useExisting: forwardRef(() => CodeEditor),
298
531
  multi: true
299
532
  }
300
533
  ], styles: [":host{display:block;height:100%}:host ::ng-deep .cm-editor{height:100%}:host ::ng-deep .cm-editor.cm-focused{outline:2px solid Highlight;outline-offset:-2px}\n"] }]
301
- }], propDecorators: { autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], highlightWhitespace: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightWhitespace", required: false }] }], indentUnit: [{ type: i0.Input, args: [{ isSignal: true, alias: "indentUnit", required: false }] }], indentWithTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "indentWithTab", required: false }] }], language: [{ type: i0.Input, args: [{ isSignal: true, alias: "language", required: false }] }], languages: [{ type: i0.Input, args: [{ isSignal: true, alias: "languages", required: false }] }], lineWrapping: [{ type: i0.Input, args: [{ isSignal: true, alias: "lineWrapping", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], root: [{ type: i0.Input, args: [{ isSignal: true, alias: "root", required: false }] }], setup: [{ type: i0.Input, args: [{ isSignal: true, alias: "setup", required: false }] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], aoFocus: [{ type: i0.Output, args: ["aoFocus"] }], aoChange: [{ type: i0.Output, args: ["aoChange"] }], aoBlur: [{ type: i0.Output, args: ["aoBlur"] }] } });
534
+ }], propDecorators: { autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], describedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "describedBy", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], highlightWhitespace: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightWhitespace", required: false }] }], indentUnit: [{ type: i0.Input, args: [{ isSignal: true, alias: "indentUnit", required: false }] }], indentWithTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "indentWithTab", required: false }] }], language: [{ type: i0.Input, args: [{ isSignal: true, alias: "language", required: false }] }], languages: [{ type: i0.Input, args: [{ isSignal: true, alias: "languages", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], labelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelledBy", required: false }] }], lineWrapping: [{ type: i0.Input, args: [{ isSignal: true, alias: "lineWrapping", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], root: [{ type: i0.Input, args: [{ isSignal: true, alias: "root", required: false }] }], setup: [{ type: i0.Input, args: [{ isSignal: true, alias: "setup", required: false }] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], aoFocus: [{ type: i0.Output, args: ["aoFocus"] }], aoChange: [{ type: i0.Output, args: ["aoChange"] }], aoBlur: [{ type: i0.Output, args: ["aoBlur"] }], aoLanguageError: [{ type: i0.Output, args: ["aoLanguageError"] }] } });
302
535
 
303
536
  /**
304
- * @aiao/code-editor-angular
537
+ * @fileoverview `@aiao/code-editor-angular` 包入口。
305
538
  *
306
- * Angular CodeMirror 代码编辑器组件
539
+ * 导出 Angular `CodeEditor` 组件、`CodeEditorSetup` 与 `CodeEditorTheme` 类型。
540
+ * 与 React / Vue 绑定同名同语义,三端共用 `@aiao/code-editor` 的语言解析与无障碍工具。
307
541
  *
308
542
  * @example
309
543
  * ```ts
310
544
  * import { CodeEditor } from '@aiao/code-editor-angular';
311
545
  * ```
546
+ *
547
+ * @module @aiao/code-editor-angular
312
548
  */
313
549
 
314
550
  /**
315
551
  * Generated bundle index. Do not edit.
316
552
  */
317
553
 
318
- export { CodeEditor, External };
554
+ export { CodeEditor };
319
555
  //# sourceMappingURL=aiao-code-editor-angular.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"aiao-code-editor-angular.mjs","sources":["../../../../packages/code-editor-angular/src/code-editor.ts","../../../../packages/code-editor-angular/src/index.ts","../../../../packages/code-editor-angular/src/aiao-code-editor-angular.ts"],"sourcesContent":["/**\n * @file\n * @aiao/code-editor-angular\n *\n * Angular CodeMirror 代码编辑器组件实现\n */\nimport type { CodeEditorLanguageDescription, CodeEditorTheme } from '@aiao/code-editor';\nimport { findLanguageByName, SUPPORT_LANGUAGES } from '@aiao/code-editor';\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n forwardRef,\n inject,\n input,\n linkedSignal,\n OnChanges,\n OnDestroy,\n OnInit,\n output,\n PLATFORM_ID,\n SimpleChanges\n} from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { indentWithTab } from '@codemirror/commands';\nimport { indentUnit } from '@codemirror/language';\nimport { Annotation, Compartment, EditorState, Extension, StateEffect } from '@codemirror/state';\nimport { oneDark } from '@codemirror/theme-one-dark';\nimport { EditorView, highlightWhitespace, keymap, placeholder } from '@codemirror/view';\nimport { basicSetup, minimalSetup } from 'codemirror';\n\nexport type { CodeEditorTheme } from '@aiao/code-editor';\n\n/** CodeMirror 预设配置。 */\nexport type CodeEditorSetup = 'basic' | 'minimal' | null;\n\n/**\n * Annotation to mark external changes that should not trigger onChange\n */\nexport const External = Annotation.define<boolean>();\n\n/**\n * CodeEditor Angular 组件\n *\n * 基于 CodeMirror 6 的代码编辑器 Angular 组件,支持多种语言和主题\n *\n * @example\n * ```html\n * <ao-code-editor\n * [(ngModel)]=\"code\"\n * language=\"typescript\"\n * theme=\"dark\"\n * (aoChange)=\"onCodeChange($event)\"\n * />\n * ```\n */\n@Component({\n selector: 'ao-code-editor',\n template: ``,\n styleUrl: './code-editor.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => CodeEditor),\n multi: true\n }\n ]\n})\nexport class CodeEditor implements OnInit, ControlValueAccessor, OnDestroy, OnChanges {\n /**\n * EditorView instance\n * https://codemirror.net/docs/ref/#view.EditorView\n */\n #view?: EditorView;\n #pendingValue?: string;\n #languageRequest = 0;\n\n #elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n #platformId = inject(PLATFORM_ID);\n #isBrowser = isPlatformBrowser(this.#platformId);\n\n // Compartments for dynamic reconfiguration\n // https://codemirror.net/docs/ref/#state.Compartment\n #editableConf = new Compartment();\n #readonlyConf = new Compartment();\n #themeConf = new Compartment();\n #placeholderConf = new Compartment();\n #indentWithTabConf = new Compartment();\n #indentUnitConf = new Compartment();\n #lineWrappingConf = new Compartment();\n #highlightWhitespaceConf = new Compartment();\n #languageConf = new Compartment();\n\n // Update listener for content changes\n #updateListener = EditorView.updateListener.of(vu => {\n if (vu.docChanged && !vu.transactions.some(tr => tr.annotation(External))) {\n const value = vu.state.doc.toString();\n this.onChange?.(value);\n this.aoChange.emit(value);\n }\n });\n\n // Input properties\n autoFocus = input(false, { transform: booleanAttribute });\n disabled = input(false, { transform: booleanAttribute });\n highlightWhitespace = input(false, { transform: booleanAttribute });\n indentUnit = input<string>('');\n indentWithTab = input(false, { transform: booleanAttribute });\n language = input<string>('');\n languages = input<readonly CodeEditorLanguageDescription[]>(SUPPORT_LANGUAGES);\n lineWrapping = input(false, { transform: booleanAttribute });\n placeholder = input<string>('');\n readonly = input(false, { transform: booleanAttribute });\n root = input<Document | ShadowRoot>();\n setup = input<CodeEditorSetup>('basic');\n theme = input<CodeEditorTheme>('light');\n value = input<string>('');\n\n // Output events\n aoFocus = output<void>();\n aoChange = output<string>();\n aoBlur = output<void>();\n\n // Linked signal for disabled state\n useDisabled = linkedSignal(() => this.disabled());\n\n onChange?: (value: string) => void;\n onTouched?: () => void;\n\n ngOnInit() {\n if (!this.#isBrowser) return;\n const extensions: Extension[] = this._get_all_extensions();\n const state = EditorState.create({ doc: this.#pendingValue ?? this.value(), extensions });\n this.#view = new EditorView({\n parent: this.#elementRef.nativeElement,\n root: this.root(),\n state\n });\n\n if (this.autoFocus()) {\n this.#view.focus();\n }\n\n this.#view.contentDOM.addEventListener('focus', () => {\n this.aoFocus.emit();\n });\n\n this.#view.contentDOM.addEventListener('blur', () => {\n this.onTouched?.();\n this.aoBlur.emit();\n });\n this.#syncAccessState();\n this.setTheme(this.theme());\n this.setPlaceholder(this.placeholder());\n this.setIndentWithTab(this.indentWithTab());\n this.setIndentUnit(this.indentUnit());\n this.setLineWrapping(this.lineWrapping());\n this.setHighlightWhitespace(this.highlightWhitespace());\n this.setLanguage(this.language());\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (!this.#view) return;\n if (changes['value']) {\n this.setValue(this.value(), true);\n }\n if (changes['disabled'] || changes['readonly']) {\n this.#syncAccessState();\n }\n if (changes['theme']) {\n this.setTheme(this.theme());\n }\n if (changes['placeholder']) {\n this.setPlaceholder(this.placeholder());\n }\n if (changes['indentWithTab']) {\n this.setIndentWithTab(this.indentWithTab());\n }\n if (changes['indentUnit']) {\n this.setIndentUnit(this.indentUnit());\n }\n if (changes['lineWrapping']) {\n this.setLineWrapping(this.lineWrapping());\n }\n if (changes['highlightWhitespace']) {\n this.setHighlightWhitespace(this.highlightWhitespace());\n }\n if (changes['language'] || changes['languages']) {\n this.setLanguage(this.language());\n }\n if (changes['setup']) {\n this.setExtensions(this._get_all_extensions());\n }\n }\n\n ngOnDestroy(): void {\n this.#languageRequest += 1;\n const view = this.#view;\n this.#view = undefined;\n view?.destroy();\n }\n\n public writeValue(value: string | null): void {\n const normalized = value ?? '';\n if (!this.#view) {\n this.#pendingValue = normalized;\n return;\n }\n this.setValue(normalized, true);\n }\n\n public registerOnChange(fn: (value: string) => void): void {\n this.onChange = fn;\n }\n\n public registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n public setDisabledState(isDisabled: boolean): void {\n this.useDisabled.set(isDisabled);\n this.#syncAccessState();\n }\n\n setExtensions(value: Extension[]) {\n this._dispatch_effects(StateEffect.reconfigure.of(value));\n }\n\n setValue(value: string, external = false) {\n const view = this.#view;\n if (!view || view.state.doc.toString() === value) return;\n view.dispatch({\n changes: { from: 0, to: view.state.doc.length, insert: value },\n annotations: external ? External.of(true) : undefined\n });\n }\n\n setEditable(value: boolean) {\n this._dispatch_effects(this.#editableConf.reconfigure(EditorView.editable.of(value)));\n }\n\n setReadonly(value: boolean) {\n this._dispatch_effects(this.#readonlyConf.reconfigure(EditorState.readOnly.of(value)));\n }\n\n setTheme(value: CodeEditorTheme) {\n this._dispatch_effects(this.#themeConf.reconfigure(value === 'dark' ? oneDark : []));\n }\n\n setPlaceholder(value: string) {\n this._dispatch_effects(this.#placeholderConf.reconfigure(value ? placeholder(value) : []));\n }\n\n setIndentWithTab(value: boolean) {\n this._dispatch_effects(this.#indentWithTabConf.reconfigure(value ? keymap.of([indentWithTab]) : []));\n }\n\n setIndentUnit(value: string) {\n this._dispatch_effects(this.#indentUnitConf.reconfigure(value ? indentUnit.of(value) : []));\n }\n\n setLineWrapping(value: boolean) {\n this._dispatch_effects(this.#lineWrappingConf.reconfigure(value ? EditorView.lineWrapping : []));\n }\n\n setHighlightWhitespace(value: boolean) {\n this._dispatch_effects(this.#highlightWhitespaceConf.reconfigure(value ? highlightWhitespace() : []));\n }\n\n setLanguage(lang: string) {\n const request = ++this.#languageRequest;\n const view = this.#view;\n if (!view) return;\n const languages = this.languages();\n if (!lang || lang === 'plaintext' || languages.length === 0) {\n view.dispatch({ effects: this.#languageConf.reconfigure([]) });\n return;\n }\n const langDesc = this._find_language(lang);\n if (!langDesc) {\n view.dispatch({ effects: this.#languageConf.reconfigure([]) });\n return;\n }\n void langDesc.load().then(\n languageSupport => {\n if (request !== this.#languageRequest || this.#view !== view) return;\n view.dispatch({ effects: this.#languageConf.reconfigure(languageSupport.extension as Extension) });\n },\n error => {\n if (request !== this.#languageRequest || this.#view !== view) return;\n console.error(`[code-editor-angular] Failed to load language \"${lang}\":`, error);\n view.dispatch({ effects: this.#languageConf.reconfigure([]) });\n }\n );\n }\n\n protected _get_all_extensions() {\n const extensions: Extension[] = [\n this.#updateListener,\n this.#editableConf.of([]),\n this.#readonlyConf.of([]),\n this.#themeConf.of([]),\n this.#placeholderConf.of([]),\n this.#indentWithTabConf.of([]),\n this.#indentUnitConf.of([]),\n this.#lineWrappingConf.of([]),\n this.#highlightWhitespaceConf.of([]),\n this.#languageConf.of([])\n ];\n const setup = this.setup();\n if (setup === 'basic') {\n extensions.push(basicSetup);\n } else if (setup === 'minimal') {\n extensions.push(minimalSetup);\n }\n return extensions;\n }\n\n protected _find_language(name: string): CodeEditorLanguageDescription | null {\n const languages = this.languages();\n const language = findLanguageByName(name, languages);\n if (language) {\n return language;\n }\n console.error(`Language \"${name}\" not found. Supported: ${languages.map(lang => lang.name).join(', ')}`);\n return null;\n }\n\n protected _dispatch_effects(effects: StateEffect<unknown> | readonly StateEffect<unknown>[]) {\n return this.#view?.dispatch({ effects });\n }\n\n #syncAccessState() {\n const disabled = this.useDisabled();\n const readonly = this.readonly();\n this.setReadonly(readonly || disabled);\n this.setEditable(!readonly && !disabled);\n }\n}\n","/**\n * @aiao/code-editor-angular\n *\n * Angular CodeMirror 代码编辑器组件\n *\n * @example\n * ```ts\n * import { CodeEditor } from '@aiao/code-editor-angular';\n * ```\n */\nexport * from './code-editor';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"aiao-code-editor-angular.mjs","sources":["../../../../packages/code-editor-angular/src/code-editor.ts","../../../../packages/code-editor-angular/src/index.ts","../../../../packages/code-editor-angular/src/aiao-code-editor-angular.ts"],"sourcesContent":["/**\n * @fileoverview `@aiao/code-editor-angular` —— 基于 CodeMirror 6 的 Angular 组件实现。\n *\n * 与 React / Vue 同名同语义:三端共用 `@aiao/code-editor` 的语言解析与无障碍工具,\n * 这里只承担 Angular 生命周期、`signal` 输入与 `ControlValueAccessor` 表单集成。\n *\n * @module @aiao/code-editor-angular\n */\nimport type {\n CodeEditorLanguageDescription,\n CodeEditorLanguageError,\n CodeEditorTheme,\n ResolvedCodeEditorLanguage\n} from '@aiao/code-editor';\nimport {\n buildCodeEditorContentAttributes,\n codeEditorLanguageLoadFailed,\n codeEditorLanguageNotFound,\n computeMinimalDocumentChange,\n isSameResolvedLanguage,\n resolveCodeEditorLanguage,\n shouldAutoFocusCodeEditor,\n SUPPORT_LANGUAGES\n} from '@aiao/code-editor';\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n ElementRef,\n forwardRef,\n inject,\n input,\n OnChanges,\n OnDestroy,\n OnInit,\n output,\n PLATFORM_ID,\n signal,\n SimpleChanges\n} from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { indentWithTab } from '@codemirror/commands';\nimport { indentUnit } from '@codemirror/language';\nimport { Annotation, Compartment, EditorState, Extension, StateEffect, Transaction } from '@codemirror/state';\nimport { oneDark } from '@codemirror/theme-one-dark';\nimport { EditorView, highlightWhitespace, keymap, placeholder } from '@codemirror/view';\nimport { basicSetup, minimalSetup } from 'codemirror';\n\nexport type { CodeEditorTheme } from '@aiao/code-editor';\n\n/** CodeMirror 预设配置。 */\nexport type CodeEditorSetup = 'basic' | 'minimal' | null;\n\n/**\n * 标记「外部写入」的注解,用于让 updateListener 跳过 onChange 回调。\n *\n * @internal\n * 模块私有,不对外导出:每个框架绑定各有一个互不相同的 Annotation 实例,\n * 一旦暴露就等于承诺了一个三端无法对齐的语义(React / Vue 两端同样是模块私有)。\n */\nconst External = Annotation.define<boolean>();\n\n/**\n * CodeEditor Angular 组件\n *\n * 基于 CodeMirror 6 的代码编辑器 Angular 组件,支持多种语言和主题\n *\n * @example\n * ```html\n * <ao-code-editor\n * [(ngModel)]=\"code\"\n * language=\"typescript\"\n * theme=\"dark\"\n * (aoChange)=\"onCodeChange($event)\"\n * />\n * ```\n */\n@Component({\n selector: 'ao-code-editor',\n template: ``,\n styleUrl: './code-editor.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n // 宿主上的 `aria-disabled` 与 React / Vue 同名同值。但承担 `role=\"textbox\"` 的是\n // CodeMirror 的 `.cm-content`,那一侧另走 `#a11yConf`,见 {@link CodeEditor.#syncContentAttributes}。\n host: {\n '[attr.aria-disabled]': '_ariaDisabled()'\n },\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => CodeEditor),\n multi: true\n }\n ]\n})\nexport class CodeEditor implements OnInit, ControlValueAccessor, OnDestroy, OnChanges {\n /**\n * EditorView 实例。\n * https://codemirror.net/docs/ref/#view.EditorView\n */\n #view?: EditorView;\n #pendingValue?: string;\n #languageRequest = 0;\n /** 最近一次**已生效**的语言解析结果,用于跳过等价的重复配置(CEA-006)。 */\n #appliedLanguage?: ResolvedCodeEditorLanguage;\n\n #elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n #platformId = inject(PLATFORM_ID);\n #isBrowser = isPlatformBrowser(this.#platformId);\n\n // 用于动态重新配置的 Compartments。\n // https://codemirror.net/docs/ref/#state.Compartment\n #editableConf = new Compartment();\n #readonlyConf = new Compartment();\n #themeConf = new Compartment();\n #placeholderConf = new Compartment();\n #indentWithTabConf = new Compartment();\n #indentUnitConf = new Compartment();\n #lineWrappingConf = new Compartment();\n #highlightWhitespaceConf = new Compartment();\n #languageConf = new Compartment();\n #a11yConf = new Compartment();\n /** `setup` 预设的专属槽 —— 与 React(`CodeEditor.tsx`)、Vue(`CodeEditor.vue`)同构。 */\n #setupConf = new Compartment();\n /** 消费者经 {@link CodeEditor.setExtensions} 装入的扩展的专属槽,见 CEA-003。 */\n #userExtensionsConf = new Compartment();\n\n // 内容变化监听器。\n #updateListener = EditorView.updateListener.of(vu => {\n if (vu.docChanged && !vu.transactions.some(tr => tr.annotation(External))) {\n const value = vu.state.doc.toString();\n this.#onChange?.(value);\n this.aoChange.emit(value);\n }\n });\n\n // 焦点事件必须随初始 extensions 一起装配,不能在 EditorView 构造完再 addEventListener:\n // `autoFocus` 的 `view.focus()` 紧跟构造同步派发 focus,后注册的监听器永远吞掉第一次。\n // 用 domEventObservers 还顺带解决了裸监听器没有 removeEventListener 的问题 ——\n // 它随 view.destroy() 一起回收。与 Vue(`CodeEditor.vue:75-78`)同构。\n #domEventObservers = EditorView.domEventObservers({\n focus: () => {\n this.aoFocus.emit();\n },\n blur: () => {\n this.#onTouched?.();\n this.aoBlur.emit();\n }\n });\n\n /**\n * 表单侧的禁用状态,只由 {@link CodeEditor.setDisabledState} 写入。\n *\n * @internal\n * 必须私有:它只在 `#effectiveDisabled` 里被消费,外部 `.set()` 写了也不会同步到编辑器。\n */\n readonly #formDisabled = signal(false);\n\n /**\n * 有效禁用状态 = `disabled` 输入与表单禁用**任一为真**。\n *\n * @internal\n * CEA-004:两条来源早先被压进同一个 `linkedSignal(() => this.disabled())`,\n * 成了「最后写的赢」。它们是**独立的事实**:模板的 `[disabled]=\"true\"` 说\n * 「这个控件永远禁用」,`setDisabledState()` 说「这个 FormControl 当前 disable 了」。\n * 压成一个值有两个可复现的后果 —— Reactive Forms 在控件 enabled 时会主动调\n * `setDisabledState(false)`,把 `[disabled]=\"true\"` 静默抹掉;反过来 `disabled`\n * 输入一变化 `linkedSignal` 就重算,把表单侧刚设的禁用丢掉。\n */\n readonly #effectiveDisabled = computed(() => this.disabled() || this.#formDisabled());\n\n /** @internal 只能经 {@link registerOnChange} 注入,公开会让消费者覆盖后静默切断表单双向绑定。 */\n #onChange?: (value: string) => void;\n /** @internal 只能经 {@link registerOnTouched} 注入,理由同 {@link registerOnChange}。 */\n #onTouched?: () => void;\n\n /**\n * 宿主元素上的 `aria-disabled`。\n *\n * @internal\n * 未禁用时返回 `null` 让 Angular **移除**属性,而不是写 `aria-disabled=\"false\"`;\n * 理由与 {@link buildCodeEditorContentAttributes} 一致。`protected` 是可见性下限 ——\n * host 绑定表达式读不到 `#` 私有字段。\n */\n protected readonly _ariaDisabled = computed(() => (this.#effectiveDisabled() ? 'true' : null));\n\n // 输入属性。\n /** 初始化后立即聚焦编辑器。**仅初始化生效**,后续变更被忽略。 @defaultValue false */\n autoFocus = input(false, { transform: booleanAttribute });\n /**\n * 补充说明元素的 id,写成内部 textbox 的 `aria-describedby`。可动态更新。\n *\n * @defaultValue ''(空串按「未设置」处理,不产出属性)\n * @remarks 属性落在 CodeMirror 的 `.cm-content` 上 —— 承担 `role=\"textbox\"` 的是它,\n * 不是本组件的宿主元素。三端同名同义。\n */\n describedBy = input<string>('');\n /**\n * 禁用编辑(只读且不可聚焦)。可动态更新。\n *\n * @defaultValue false\n * @remarks 与表单的 `setDisabledState()` 是**两条独立来源**,任一为真即禁用。\n * 用 Reactive Forms 时把控件设成 `disabled` 与在模板上写 `[disabled]=\"true\"` 效果一样,\n * 但只解开其中一条不会恢复可编辑 —— 两条都得放开。\n */\n disabled = input(false, { transform: booleanAttribute });\n /** 显示空白字符。可动态更新。 @defaultValue false */\n highlightWhitespace = input(false, { transform: booleanAttribute });\n /** 一级缩进使用的字符串。可动态更新。 @defaultValue ' '(两个空格,三端一致) */\n indentUnit = input<string>(' ');\n /** 允许 Tab 键缩进(会牺牲键盘可达性)。可动态更新。 @defaultValue false */\n indentWithTab = input(false, { transform: booleanAttribute });\n /** 语法高亮语言名,取值见 {@link languages};`'plaintext'` 表示不高亮。可动态更新。 @defaultValue 'sql' */\n language = input<string>('sql');\n /** 可选语言列表。可动态更新。 @defaultValue SUPPORT_LANGUAGES */\n languages = input<readonly CodeEditorLanguageDescription[]>(SUPPORT_LANGUAGES);\n /**\n * 可访问名称,写成内部 textbox 的 `aria-label`。可动态更新。\n *\n * @defaultValue ''(空串按「未设置」处理,不产出属性)\n * @remarks 落点与 {@link CodeEditor.describedBy} 相同。\n */\n label = input<string>('');\n /**\n * 承担标签的元素 id,写成内部 textbox 的 `aria-labelledby`。可动态更新。\n *\n * @defaultValue ''(空串按「未设置」处理,不产出属性)\n * @remarks 落点与 {@link CodeEditor.describedBy} 相同。\n */\n labelledBy = input<string>('');\n /** 自动换行。可动态更新。 @defaultValue false */\n lineWrapping = input(false, { transform: booleanAttribute });\n /** 空文档时显示的占位文本。可动态更新。 @defaultValue '' */\n placeholder = input<string>('');\n /** 只读(仍可聚焦与选择)。可动态更新。 @defaultValue false */\n readonly = input(false, { transform: booleanAttribute });\n /** CodeMirror 挂载的 DOM 根,用于 Shadow DOM 场景。**仅初始化生效**。 */\n root = input<Document | ShadowRoot>();\n /** 预设扩展集;`null` 表示不加载任何预设。可动态更新。 @defaultValue 'basic' */\n setup = input<CodeEditorSetup>('basic');\n /** 主题。可动态更新。 @defaultValue 'light' */\n theme = input<CodeEditorTheme>('light');\n /** 文档内容。作为受控输入使用时由外部驱动;与 `ngModel` 同时使用以 `ngModel` 为准。 @defaultValue '' */\n value = input<string>('');\n\n // 输出事件。\n /** 编辑器获得焦点。 */\n aoFocus = output<void>();\n /** 文档内容变化(外部写入不触发,见 {@link External})。 */\n aoChange = output<string>();\n /** 编辑器失去焦点,同时触发表单 touched。 */\n aoBlur = output<void>();\n /**\n * 语言解析或加载失败。\n *\n * @remarks\n * CEA-007:这条路径此前只有一条 `console.error`,宿主完全观测不到 ——\n * 拿不到错误、没有重试或降级的机会,用户只看到高亮突然消失。\n * 降级策略不变(清空语言扩展退回纯文本),日志也保留,本事件是**新增的**观测通道。\n * 与 React 的 `onLanguageError` 属性、Vue 的 `language-error` 事件同载荷。\n */\n aoLanguageError = output<CodeEditorLanguageError>();\n\n /**\n * 底层 CodeMirror `EditorView`;未初始化或已销毁时为 `null`。\n *\n * @remarks 三端命令式面统一为 `view` / `host` / `focus()` / `blur()`(CEA-009)。\n */\n get view(): EditorView | null {\n return this.#view ?? null;\n }\n\n /**\n * CodeMirror 挂载所在的宿主元素;未初始化或已销毁时为 `null`。\n *\n * @remarks\n * Angular 的宿主是 `<ao-code-editor>` 元素本身,React / Vue 是组件渲染出的 `div`——\n * 类型不同但语义一致:「CodeMirror 挂在哪个元素里」。\n */\n get host(): HTMLElement | null {\n return this.#view ? this.#elementRef.nativeElement : null;\n }\n\n /** 把键盘焦点交给编辑器。未初始化时是空操作。 */\n focus(): void {\n this.#view?.focus();\n }\n\n /** 移开键盘焦点。未初始化时是空操作。 */\n blur(): void {\n this.#view?.contentDOM.blur();\n }\n\n ngOnInit() {\n if (!this.#isBrowser) return;\n const extensions: Extension[] = this._get_all_extensions();\n const state = EditorState.create({ doc: this.#pendingValue ?? this.value(), extensions });\n this.#view = new EditorView({\n parent: this.#elementRef.nativeElement,\n root: this.root(),\n state\n });\n\n // 访问状态必须先落地:`autoFocus` 要读**已生效**的禁用 / 只读语义,而 `focus()`\n // 又会同步派发 focus 事件,晚同步等于让监听者先读到一个还没对齐的状态。\n this.#syncAccessState();\n // CEA-008(用户可见的行为修正):`disabled` / `readonly` 都会把编辑器配成不可编辑,\n // 此时仍然抢焦点,用户只会得到一个无法输入、也无从得知为什么无法输入的控件。\n if (\n this.autoFocus() &&\n shouldAutoFocusCodeEditor({ disabled: this.#effectiveDisabled(), readonly: this.readonly() })\n ) {\n this.#view.focus();\n }\n this._dispatch_effects(this.#themeConf.reconfigure(this.theme() === 'dark' ? oneDark : []));\n this._dispatch_effects(\n this.#placeholderConf.reconfigure(this.placeholder() ? placeholder(this.placeholder()) : [])\n );\n this._dispatch_effects(this.#indentWithTabConf.reconfigure(this.indentWithTab() ? keymap.of([indentWithTab]) : []));\n this._dispatch_effects(this.#indentUnitConf.reconfigure(this.indentUnit() ? indentUnit.of(this.indentUnit()) : []));\n this._dispatch_effects(this.#lineWrappingConf.reconfigure(this.lineWrapping() ? EditorView.lineWrapping : []));\n this._dispatch_effects(\n this.#highlightWhitespaceConf.reconfigure(this.highlightWhitespace() ? highlightWhitespace() : [])\n );\n this.setLanguage(this.language());\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (!this.#view) return;\n if (changes['value'] && this.#view) {\n const newValue = this.value();\n const change = computeMinimalDocumentChange(this.#view.state.doc.toString(), newValue);\n if (change) {\n this.#view.dispatch({\n changes: change,\n annotations: [External.of(true), Transaction.addToHistory.of(false)],\n scrollIntoView: false\n });\n }\n }\n if (changes['disabled'] || changes['readonly']) {\n this.#syncAccessState();\n }\n if (changes['describedBy'] || changes['label'] || changes['labelledBy']) {\n this.#syncContentAttributes();\n }\n if (changes['theme']) {\n this._dispatch_effects(this.#themeConf.reconfigure(this.theme() === 'dark' ? oneDark : []));\n }\n if (changes['placeholder']) {\n this._dispatch_effects(\n this.#placeholderConf.reconfigure(this.placeholder() ? placeholder(this.placeholder()) : [])\n );\n }\n if (changes['indentWithTab']) {\n this._dispatch_effects(\n this.#indentWithTabConf.reconfigure(this.indentWithTab() ? keymap.of([indentWithTab]) : [])\n );\n }\n if (changes['indentUnit']) {\n this._dispatch_effects(\n this.#indentUnitConf.reconfigure(this.indentUnit() ? indentUnit.of(this.indentUnit()) : [])\n );\n }\n if (changes['lineWrapping']) {\n this._dispatch_effects(this.#lineWrappingConf.reconfigure(this.lineWrapping() ? EditorView.lineWrapping : []));\n }\n if (changes['highlightWhitespace']) {\n this._dispatch_effects(\n this.#highlightWhitespaceConf.reconfigure(this.highlightWhitespace() ? highlightWhitespace() : [])\n );\n }\n if (changes['language'] || changes['languages']) {\n this.#syncLanguage();\n }\n if (changes['setup']) {\n // CEA-003:早先这里调的是 `setExtensions(this._get_all_extensions())`,\n // 即换个预设就把整棵扩展树连同消费者自己装的扩展一起重建。\n this._dispatch_effects(this.#setupConf.reconfigure(this.#setupExtension()));\n }\n }\n\n ngOnDestroy(): void {\n this.#languageRequest += 1;\n const view = this.#view;\n this.#view = undefined;\n view?.destroy();\n }\n\n /**\n * `ControlValueAccessor` 的写入入口,由 Angular Forms 调用。\n *\n * @param value `null` / `undefined` 规整成空串;`string` 原样写入\n * @throws TypeError 收到其他类型时立即抛出,错误信息含包名与实际类型\n *\n * @remarks\n * CEA-005:签名此前写成 `string | null`,但 CVA 的契约是 `any` —— Angular\n * **不做**运行时校验,`FormControl` 里放什么就原样送到这里。类型标注只骗过了编译期。\n * 于是 `FormControl(42)` 在初始化前进 `#pendingValue`、在 `EditorState.create` 处炸,\n * 初始化后又在 `computeMinimalDocumentChange` 处炸 —— 同一个错误配置,两个时机两种错,\n * 且都指不回 `writeValue`。现在两个时机抛同一个错,且直接点名包与类型。\n */\n public writeValue(value: unknown): void {\n const normalized = this.#normalizeFormValue(value);\n if (!this.#view) {\n this.#pendingValue = normalized;\n return;\n }\n const change = computeMinimalDocumentChange(this.#view.state.doc.toString(), normalized);\n if (change) {\n this.#view.dispatch({\n changes: change,\n annotations: [External.of(true), Transaction.addToHistory.of(false)],\n scrollIntoView: false\n });\n }\n }\n\n public registerOnChange(fn: (value: string) => void): void {\n this.#onChange = fn;\n }\n\n public registerOnTouched(fn: () => void): void {\n this.#onTouched = fn;\n }\n\n /**\n * 表单侧的禁用开关,由 Angular Forms 调用。\n *\n * @remarks 只写 {@link CodeEditor.#formDisabled} 这一条来源;模板上的\n * `[disabled]` 输入是另一条独立来源,两者取或,见 {@link CodeEditor.#effectiveDisabled}。\n */\n public setDisabledState(isDisabled: boolean): void {\n this.#formDisabled.set(isDisabled);\n this.#syncAccessState();\n }\n\n /**\n * 装入消费者自己的 CodeMirror 扩展。\n *\n * @param value 本次要生效的扩展;**整体替换**上一次传入的那批,传 `[]` 即全部撤下\n *\n * @remarks\n * CEA-003:早先这里发的是全局 `StateEffect.reconfigure.of(value)`,\n * 它替换的是**整棵扩展树** —— 一次调用就清掉 updateListener、全部 Compartment、\n * 主题、语言与 a11y 属性,名字叫「设置扩展」,实际是「摧毁编辑器配置」。\n * 现在只重配 {@link CodeEditor.#userExtensionsConf} 这一个专属槽,\n * 组件自身的配置与消费者的扩展互不影响。\n */\n setExtensions(value: Extension[]) {\n this._dispatch_effects(this.#userExtensionsConf.reconfigure(value));\n }\n\n /**\n * 命令式地(重新)应用语言配置。\n *\n * @param lang 语言名或别名;空串与 `'plaintext'` 表示不高亮\n *\n * @remarks\n * **无条件重新加载**,即使解析结果与当前生效的完全一致 —— 这是宿主换掉了同名描述\n * 背后的 loader 实现时的显式重载入口,`language` 输入做不到(它走的是\n * {@link CodeEditor.#syncLanguage} 里的等价性判断,CEA-006,不会重复加载)。\n * 日常切换语言应当改 `language` 输入。\n *\n * 解析失败时清空语言扩展退回纯文本,并经 {@link CodeEditor.aoLanguageError} 报告。\n */\n setLanguage(lang: string) {\n const request = ++this.#languageRequest;\n const view = this.#view;\n if (!view) return;\n const resolved = resolveCodeEditorLanguage(lang, this.languages());\n this.#appliedLanguage = resolved;\n if (resolved.kind === 'none') {\n view.dispatch({ effects: this.#languageConf.reconfigure([]) });\n return;\n }\n if (resolved.kind === 'not-found') {\n view.dispatch({ effects: this.#languageConf.reconfigure([]) });\n // 日志与另两端逐字一致,作为最后兜底诊断保留;结构化事件才是给宿主的契约通道。\n console.error(`[CodeEditor] Language '${lang}' not found.`);\n this.aoLanguageError.emit(codeEditorLanguageNotFound(lang));\n return;\n }\n // 直接用解析结果里的 description:早先这里又调一次 `_find_language(lang)` 重查一遍,\n // 同一个名字解析两遍,两处判定一旦分叉就会出现「解析说找到了、重查说没有」。\n void resolved.description.load().then(\n languageSupport => {\n if (request !== this.#languageRequest || this.#view !== view) return;\n view.dispatch({ effects: this.#languageConf.reconfigure(languageSupport.extension as Extension) });\n },\n (error: unknown) => {\n if (request !== this.#languageRequest || this.#view !== view) return;\n view.dispatch({ effects: this.#languageConf.reconfigure([]) });\n console.error(`[CodeEditor] Failed to load language '${lang}':`, error);\n this.aoLanguageError.emit(codeEditorLanguageLoadFailed(lang, error));\n }\n );\n }\n\n protected _get_all_extensions() {\n const extensions: Extension[] = [\n this.#updateListener,\n this.#domEventObservers,\n this.#editableConf.of([]),\n this.#readonlyConf.of([]),\n this.#themeConf.of([]),\n this.#placeholderConf.of([]),\n this.#indentWithTabConf.of([]),\n this.#indentUnitConf.of([]),\n this.#lineWrappingConf.of([]),\n this.#highlightWhitespaceConf.of([]),\n this.#languageConf.of([]),\n this.#a11yConf.of([]),\n this.#setupConf.of(this.#setupExtension()),\n // 消费者扩展排在最后 —— CodeMirror 里后来的优先级更高,\n // 宿主装的 keymap / 主题覆盖才压得住预设。\n this.#userExtensionsConf.of([])\n ];\n return extensions;\n }\n\n protected _dispatch_effects(effects: StateEffect<unknown> | readonly StateEffect<unknown>[]) {\n return this.#view?.dispatch({ effects });\n }\n\n /**\n * `language` / `languages` 输入变化后的语言同步。\n *\n * CEA-006:早先只要 `languages` 的**数组引用**变了就无条件 `setLanguage()`。\n * 父模板写 `[languages]=\"[myLang]\"` 这类内联字面量时每轮变更检测都产生新数组,\n * 于是每轮都重新 `load()` 并 reconfigure 语言 Compartment ——\n * 大文档等于每次输入都整篇重新词法分析,自定义异步 loader 还会多发请求。\n * 判定基准改成「当前语言实际解析到的 description identity」,与 React / Vue 同构。\n */\n #syncLanguage() {\n const language = this.language();\n const resolved = resolveCodeEditorLanguage(language, this.languages());\n if (isSameResolvedLanguage(this.#appliedLanguage, resolved)) return;\n this.setLanguage(language);\n }\n\n /**\n * 把无障碍属性写到真正承担 `role=\"textbox\"` 的 `.cm-content` 上。\n *\n * CEA-008 / CER-006:只在宿主 `div` 上补 `aria-*` 是把缺陷换个位置 —— 屏幕阅读器\n * 进到 textbox 之后读到的仍然是一个没有可访问名称、只报 `aria-readonly` 的多行文本框。\n * 属性字典由核心包计算,三端共用同一份实现。\n */\n #syncContentAttributes() {\n this._dispatch_effects(this.#contentAttributesEffect(this.#effectiveDisabled()));\n }\n\n #contentAttributesEffect(disabled: boolean): StateEffect<unknown> {\n const attributes = buildCodeEditorContentAttributes({\n describedBy: this.describedBy(),\n disabled,\n label: this.label(),\n labelledBy: this.labelledBy()\n });\n return this.#a11yConf.reconfigure(EditorView.contentAttributes.of(attributes));\n }\n\n #syncAccessState() {\n const disabled = this.#effectiveDisabled();\n const readonly = this.readonly();\n // CEA-004:三个 Compartment 必须在**同一次** dispatch 里重配。早先是\n // readonly → editable → a11y 三次派发,中间两拍是「只读但仍标记可编辑」\n // 这种自相矛盾的状态,装了 updateListener 的插件全都看得见,还各自重算一遍。\n //\n // 禁用语义也要写给辅助技术:只配 readonly 的话 CodeMirror 只写出 `aria-readonly`,\n // 屏幕阅读器会把禁用控件读成「可编辑但当前只读」,用户以为解锁后就能输入。\n this._dispatch_effects([\n this.#readonlyConf.reconfigure(EditorState.readOnly.of(readonly || disabled)),\n this.#editableConf.reconfigure(EditorView.editable.of(!readonly && !disabled)),\n this.#contentAttributesEffect(disabled)\n ]);\n }\n\n /** 当前 `setup` 预设对应的扩展;`null` 预设为空数组。 */\n #setupExtension(): Extension {\n const setup = this.setup();\n if (setup === 'basic') return basicSetup;\n if (setup === 'minimal') return minimalSetup;\n return [];\n }\n\n /**\n * 把 `ControlValueAccessor` 收到的任意值规整成文档内容,见 {@link CodeEditor.writeValue}。\n *\n * @throws TypeError 值既不是字符串也不是 `null` / `undefined`\n */\n #normalizeFormValue(value: unknown): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'string') return value;\n const actual = typeof value === 'object' ? (value.constructor?.name ?? 'object') : typeof value;\n throw new TypeError(\n `[@aiao/code-editor-angular] writeValue() 只接受 string | null | undefined,实际收到 ${actual}。` +\n '请检查绑定的 FormControl 初始值或 ngModel 表达式。'\n );\n }\n}\n","/**\n * @fileoverview `@aiao/code-editor-angular` 包入口。\n *\n * 导出 Angular `CodeEditor` 组件、`CodeEditorSetup` 与 `CodeEditorTheme` 类型。\n * 与 React / Vue 绑定同名同语义,三端共用 `@aiao/code-editor` 的语言解析与无障碍工具。\n *\n * @example\n * ```ts\n * import { CodeEditor } from '@aiao/code-editor-angular';\n * ```\n *\n * @module @aiao/code-editor-angular\n */\nexport { CodeEditor } from './code-editor';\nexport type { CodeEditorSetup, CodeEditorTheme } from './code-editor';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,21 +1,27 @@
1
1
  {
2
2
  "name": "@aiao/code-editor-angular",
3
- "version": "0.0.23",
3
+ "version": "0.0.25",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/aiao-io/rxdb.git",
8
+ "directory": "packages/code-editor-angular"
9
+ },
4
10
  "dependencies": {
5
11
  "@codemirror/commands": "^6.10.4",
6
- "@codemirror/language": "^6.12.4",
12
+ "@codemirror/language": "6.12.4",
7
13
  "@codemirror/state": "6.7.1",
8
14
  "@codemirror/theme-one-dark": "^6.1.3",
9
- "@codemirror/view": "^6.43.5",
15
+ "@codemirror/view": "6.43.8",
10
16
  "codemirror": "^6.0.1",
11
17
  "tslib": "^2.3.0"
12
18
  },
13
19
  "peerDependencies": {
14
- "@aiao/code-editor": "*",
15
- "@angular/common": ">=20.0.0",
16
- "@angular/core": ">=20.0.0",
17
- "@angular/forms": ">=20.0.0",
18
- "@angular/platform-browser": ">=20.0.0"
20
+ "@aiao/code-editor": ">=0.0.24",
21
+ "@angular/common": "^22.0.0",
22
+ "@angular/core": "^22.0.0",
23
+ "@angular/forms": "^22.0.0",
24
+ "@angular/platform-browser": "^22.0.0"
19
25
  },
20
26
  "publishConfig": {
21
27
  "access": "public"
@@ -1,17 +1,13 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { OnInit, OnDestroy, OnChanges, SimpleChanges } from '@angular/core';
3
- import * as _codemirror_state from '@codemirror/state';
4
- import { Extension, StateEffect } from '@codemirror/state';
5
- import { CodeEditorLanguageDescription, CodeEditorTheme } from '@aiao/code-editor';
3
+ import { CodeEditorLanguageDescription, CodeEditorTheme, CodeEditorLanguageError } from '@aiao/code-editor';
6
4
  export { CodeEditorTheme } from '@aiao/code-editor';
7
5
  import { ControlValueAccessor } from '@angular/forms';
6
+ import { Extension, StateEffect } from '@codemirror/state';
7
+ import { EditorView } from '@codemirror/view';
8
8
 
9
9
  /** CodeMirror 预设配置。 */
10
10
  type CodeEditorSetup = 'basic' | 'minimal' | null;
11
- /**
12
- * Annotation to mark external changes that should not trigger onChange
13
- */
14
- declare const External: _codemirror_state.AnnotationType<boolean>;
15
11
  /**
16
12
  * CodeEditor Angular 组件
17
13
  *
@@ -29,50 +25,164 @@ declare const External: _codemirror_state.AnnotationType<boolean>;
29
25
  */
30
26
  declare class CodeEditor implements OnInit, ControlValueAccessor, OnDestroy, OnChanges {
31
27
  #private;
28
+ /**
29
+ * 宿主元素上的 `aria-disabled`。
30
+ *
31
+ * @internal
32
+ * 未禁用时返回 `null` 让 Angular **移除**属性,而不是写 `aria-disabled="false"`;
33
+ * 理由与 {@link buildCodeEditorContentAttributes} 一致。`protected` 是可见性下限 ——
34
+ * host 绑定表达式读不到 `#` 私有字段。
35
+ */
36
+ protected readonly _ariaDisabled: _angular_core.Signal<"true" | null>;
37
+ /** 初始化后立即聚焦编辑器。**仅初始化生效**,后续变更被忽略。 @defaultValue false */
32
38
  autoFocus: _angular_core.InputSignalWithTransform<boolean, unknown>;
39
+ /**
40
+ * 补充说明元素的 id,写成内部 textbox 的 `aria-describedby`。可动态更新。
41
+ *
42
+ * @defaultValue ''(空串按「未设置」处理,不产出属性)
43
+ * @remarks 属性落在 CodeMirror 的 `.cm-content` 上 —— 承担 `role="textbox"` 的是它,
44
+ * 不是本组件的宿主元素。三端同名同义。
45
+ */
46
+ describedBy: _angular_core.InputSignal<string>;
47
+ /**
48
+ * 禁用编辑(只读且不可聚焦)。可动态更新。
49
+ *
50
+ * @defaultValue false
51
+ * @remarks 与表单的 `setDisabledState()` 是**两条独立来源**,任一为真即禁用。
52
+ * 用 Reactive Forms 时把控件设成 `disabled` 与在模板上写 `[disabled]="true"` 效果一样,
53
+ * 但只解开其中一条不会恢复可编辑 —— 两条都得放开。
54
+ */
33
55
  disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
56
+ /** 显示空白字符。可动态更新。 @defaultValue false */
34
57
  highlightWhitespace: _angular_core.InputSignalWithTransform<boolean, unknown>;
58
+ /** 一级缩进使用的字符串。可动态更新。 @defaultValue ' '(两个空格,三端一致) */
35
59
  indentUnit: _angular_core.InputSignal<string>;
60
+ /** 允许 Tab 键缩进(会牺牲键盘可达性)。可动态更新。 @defaultValue false */
36
61
  indentWithTab: _angular_core.InputSignalWithTransform<boolean, unknown>;
62
+ /** 语法高亮语言名,取值见 {@link languages};`'plaintext'` 表示不高亮。可动态更新。 @defaultValue 'sql' */
37
63
  language: _angular_core.InputSignal<string>;
64
+ /** 可选语言列表。可动态更新。 @defaultValue SUPPORT_LANGUAGES */
38
65
  languages: _angular_core.InputSignal<readonly CodeEditorLanguageDescription[]>;
66
+ /**
67
+ * 可访问名称,写成内部 textbox 的 `aria-label`。可动态更新。
68
+ *
69
+ * @defaultValue ''(空串按「未设置」处理,不产出属性)
70
+ * @remarks 落点与 {@link CodeEditor.describedBy} 相同。
71
+ */
72
+ label: _angular_core.InputSignal<string>;
73
+ /**
74
+ * 承担标签的元素 id,写成内部 textbox 的 `aria-labelledby`。可动态更新。
75
+ *
76
+ * @defaultValue ''(空串按「未设置」处理,不产出属性)
77
+ * @remarks 落点与 {@link CodeEditor.describedBy} 相同。
78
+ */
79
+ labelledBy: _angular_core.InputSignal<string>;
80
+ /** 自动换行。可动态更新。 @defaultValue false */
39
81
  lineWrapping: _angular_core.InputSignalWithTransform<boolean, unknown>;
82
+ /** 空文档时显示的占位文本。可动态更新。 @defaultValue '' */
40
83
  placeholder: _angular_core.InputSignal<string>;
84
+ /** 只读(仍可聚焦与选择)。可动态更新。 @defaultValue false */
41
85
  readonly: _angular_core.InputSignalWithTransform<boolean, unknown>;
86
+ /** CodeMirror 挂载的 DOM 根,用于 Shadow DOM 场景。**仅初始化生效**。 */
42
87
  root: _angular_core.InputSignal<Document | ShadowRoot | undefined>;
88
+ /** 预设扩展集;`null` 表示不加载任何预设。可动态更新。 @defaultValue 'basic' */
43
89
  setup: _angular_core.InputSignal<CodeEditorSetup>;
90
+ /** 主题。可动态更新。 @defaultValue 'light' */
44
91
  theme: _angular_core.InputSignal<CodeEditorTheme>;
92
+ /** 文档内容。作为受控输入使用时由外部驱动;与 `ngModel` 同时使用以 `ngModel` 为准。 @defaultValue '' */
45
93
  value: _angular_core.InputSignal<string>;
94
+ /** 编辑器获得焦点。 */
46
95
  aoFocus: _angular_core.OutputEmitterRef<void>;
96
+ /** 文档内容变化(外部写入不触发,见 {@link External})。 */
47
97
  aoChange: _angular_core.OutputEmitterRef<string>;
98
+ /** 编辑器失去焦点,同时触发表单 touched。 */
48
99
  aoBlur: _angular_core.OutputEmitterRef<void>;
49
- useDisabled: _angular_core.WritableSignal<boolean>;
50
- onChange?: (value: string) => void;
51
- onTouched?: () => void;
100
+ /**
101
+ * 语言解析或加载失败。
102
+ *
103
+ * @remarks
104
+ * CEA-007:这条路径此前只有一条 `console.error`,宿主完全观测不到 ——
105
+ * 拿不到错误、没有重试或降级的机会,用户只看到高亮突然消失。
106
+ * 降级策略不变(清空语言扩展退回纯文本),日志也保留,本事件是**新增的**观测通道。
107
+ * 与 React 的 `onLanguageError` 属性、Vue 的 `language-error` 事件同载荷。
108
+ */
109
+ aoLanguageError: _angular_core.OutputEmitterRef<CodeEditorLanguageError>;
110
+ /**
111
+ * 底层 CodeMirror `EditorView`;未初始化或已销毁时为 `null`。
112
+ *
113
+ * @remarks 三端命令式面统一为 `view` / `host` / `focus()` / `blur()`(CEA-009)。
114
+ */
115
+ get view(): EditorView | null;
116
+ /**
117
+ * CodeMirror 挂载所在的宿主元素;未初始化或已销毁时为 `null`。
118
+ *
119
+ * @remarks
120
+ * Angular 的宿主是 `<ao-code-editor>` 元素本身,React / Vue 是组件渲染出的 `div`——
121
+ * 类型不同但语义一致:「CodeMirror 挂在哪个元素里」。
122
+ */
123
+ get host(): HTMLElement | null;
124
+ /** 把键盘焦点交给编辑器。未初始化时是空操作。 */
125
+ focus(): void;
126
+ /** 移开键盘焦点。未初始化时是空操作。 */
127
+ blur(): void;
52
128
  ngOnInit(): void;
53
129
  ngOnChanges(changes: SimpleChanges): void;
54
130
  ngOnDestroy(): void;
55
- writeValue(value: string | null): void;
131
+ /**
132
+ * `ControlValueAccessor` 的写入入口,由 Angular Forms 调用。
133
+ *
134
+ * @param value `null` / `undefined` 规整成空串;`string` 原样写入
135
+ * @throws TypeError 收到其他类型时立即抛出,错误信息含包名与实际类型
136
+ *
137
+ * @remarks
138
+ * CEA-005:签名此前写成 `string | null`,但 CVA 的契约是 `any` —— Angular
139
+ * **不做**运行时校验,`FormControl` 里放什么就原样送到这里。类型标注只骗过了编译期。
140
+ * 于是 `FormControl(42)` 在初始化前进 `#pendingValue`、在 `EditorState.create` 处炸,
141
+ * 初始化后又在 `computeMinimalDocumentChange` 处炸 —— 同一个错误配置,两个时机两种错,
142
+ * 且都指不回 `writeValue`。现在两个时机抛同一个错,且直接点名包与类型。
143
+ */
144
+ writeValue(value: unknown): void;
56
145
  registerOnChange(fn: (value: string) => void): void;
57
146
  registerOnTouched(fn: () => void): void;
147
+ /**
148
+ * 表单侧的禁用开关,由 Angular Forms 调用。
149
+ *
150
+ * @remarks 只写 {@link CodeEditor.#formDisabled} 这一条来源;模板上的
151
+ * `[disabled]` 输入是另一条独立来源,两者取或,见 {@link CodeEditor.#effectiveDisabled}。
152
+ */
58
153
  setDisabledState(isDisabled: boolean): void;
154
+ /**
155
+ * 装入消费者自己的 CodeMirror 扩展。
156
+ *
157
+ * @param value 本次要生效的扩展;**整体替换**上一次传入的那批,传 `[]` 即全部撤下
158
+ *
159
+ * @remarks
160
+ * CEA-003:早先这里发的是全局 `StateEffect.reconfigure.of(value)`,
161
+ * 它替换的是**整棵扩展树** —— 一次调用就清掉 updateListener、全部 Compartment、
162
+ * 主题、语言与 a11y 属性,名字叫「设置扩展」,实际是「摧毁编辑器配置」。
163
+ * 现在只重配 {@link CodeEditor.#userExtensionsConf} 这一个专属槽,
164
+ * 组件自身的配置与消费者的扩展互不影响。
165
+ */
59
166
  setExtensions(value: Extension[]): void;
60
- setValue(value: string, external?: boolean): void;
61
- setEditable(value: boolean): void;
62
- setReadonly(value: boolean): void;
63
- setTheme(value: CodeEditorTheme): void;
64
- setPlaceholder(value: string): void;
65
- setIndentWithTab(value: boolean): void;
66
- setIndentUnit(value: string): void;
67
- setLineWrapping(value: boolean): void;
68
- setHighlightWhitespace(value: boolean): void;
167
+ /**
168
+ * 命令式地(重新)应用语言配置。
169
+ *
170
+ * @param lang 语言名或别名;空串与 `'plaintext'` 表示不高亮
171
+ *
172
+ * @remarks
173
+ * **无条件重新加载**,即使解析结果与当前生效的完全一致 —— 这是宿主换掉了同名描述
174
+ * 背后的 loader 实现时的显式重载入口,`language` 输入做不到(它走的是
175
+ * {@link CodeEditor.#syncLanguage} 里的等价性判断,CEA-006,不会重复加载)。
176
+ * 日常切换语言应当改 `language` 输入。
177
+ *
178
+ * 解析失败时清空语言扩展退回纯文本,并经 {@link CodeEditor.aoLanguageError} 报告。
179
+ */
69
180
  setLanguage(lang: string): void;
70
181
  protected _get_all_extensions(): Extension[];
71
- protected _find_language(name: string): CodeEditorLanguageDescription | null;
72
182
  protected _dispatch_effects(effects: StateEffect<unknown> | readonly StateEffect<unknown>[]): void | undefined;
73
183
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<CodeEditor, never>;
74
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<CodeEditor, "ao-code-editor", never, { "autoFocus": { "alias": "autoFocus"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "highlightWhitespace": { "alias": "highlightWhitespace"; "required": false; "isSignal": true; }; "indentUnit": { "alias": "indentUnit"; "required": false; "isSignal": true; }; "indentWithTab": { "alias": "indentWithTab"; "required": false; "isSignal": true; }; "language": { "alias": "language"; "required": false; "isSignal": true; }; "languages": { "alias": "languages"; "required": false; "isSignal": true; }; "lineWrapping": { "alias": "lineWrapping"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "root": { "alias": "root"; "required": false; "isSignal": true; }; "setup": { "alias": "setup"; "required": false; "isSignal": true; }; "theme": { "alias": "theme"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "aoFocus": "aoFocus"; "aoChange": "aoChange"; "aoBlur": "aoBlur"; }, never, never, true, never>;
184
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<CodeEditor, "ao-code-editor", never, { "autoFocus": { "alias": "autoFocus"; "required": false; "isSignal": true; }; "describedBy": { "alias": "describedBy"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "highlightWhitespace": { "alias": "highlightWhitespace"; "required": false; "isSignal": true; }; "indentUnit": { "alias": "indentUnit"; "required": false; "isSignal": true; }; "indentWithTab": { "alias": "indentWithTab"; "required": false; "isSignal": true; }; "language": { "alias": "language"; "required": false; "isSignal": true; }; "languages": { "alias": "languages"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "labelledBy": { "alias": "labelledBy"; "required": false; "isSignal": true; }; "lineWrapping": { "alias": "lineWrapping"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "root": { "alias": "root"; "required": false; "isSignal": true; }; "setup": { "alias": "setup"; "required": false; "isSignal": true; }; "theme": { "alias": "theme"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "aoFocus": "aoFocus"; "aoChange": "aoChange"; "aoBlur": "aoBlur"; "aoLanguageError": "aoLanguageError"; }, never, never, true, never>;
75
185
  }
76
186
 
77
- export { CodeEditor, External };
187
+ export { CodeEditor };
78
188
  export type { CodeEditorSetup };