@soeditor/projections 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -34,6 +34,7 @@ class InvalidProjectionTransitionError extends Error {
34
34
  }
35
35
  const projectionIds = Object.freeze([
36
36
  "visual",
37
+ "wysiwyg",
37
38
  "source",
38
39
  "markdown",
39
40
  "preview"
@@ -176,7 +177,7 @@ class ProjectionCoordinatorPlugin extends Plugin {
176
177
  }
177
178
  #setVisible(id, visible) {
178
179
  this.#assertAttached(id);
179
- if (!visible && id === this.#primary) {
180
+ if (!visible && id === this.#primary && !(this.editor.state.mode === "preview" && this.#visible.has("preview"))) {
180
181
  throw new InvalidProjectionTransitionError(
181
182
  `Primary projection "${id}" cannot be hidden.`
182
183
  );
@@ -314,7 +315,7 @@ function isCompatible(id, format) {
314
315
  return id === "preview" || isEditableForFormat(id, format);
315
316
  }
316
317
  function isEditableForFormat(id, format) {
317
- return format === "html" ? id === "visual" || id === "source" : id === "markdown";
318
+ return format === "html" ? id === "visual" || id === "wysiwyg" || id === "source" : id === "markdown";
318
319
  }
319
320
  function validateAdapter(adapter) {
320
321
  if (typeof adapter !== "object" || adapter === null) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/projection-coordinator.ts"],"sourcesContent":["import {\n createServiceToken,\n Plugin,\n type DocumentFormat,\n type EditorMode,\n} from '@soeditor/core';\n\n/** Built-in projection identities coordinated in SoEditor 0.6. */\nexport type ProjectionId = 'visual' | 'source' | 'markdown' | 'preview';\n\n/** Projection identities that may hold logical write authority. */\nexport type EditableProjectionId = Exclude<ProjectionId, 'preview'>;\n\n/** Immutable effective activity delivered to one attached projection. */\nexport interface ProjectionActivity {\n readonly id: ProjectionId;\n readonly primary: boolean;\n readonly readonly: boolean;\n readonly visible: boolean;\n}\n\n/** Narrow lifecycle adapter implemented by a surface engine. */\nexport interface ProjectionAdapter {\n readonly id: ProjectionId;\n update(activity: ProjectionActivity): void;\n}\n\n/** Immutable observable coordinator state. */\nexport interface ProjectionSnapshot {\n readonly activities: readonly ProjectionActivity[];\n readonly primary: EditableProjectionId;\n}\n\n/** Per-editor projection attachment and observation capabilities. */\nexport interface ProjectionCoordinatorService {\n readonly snapshot: ProjectionSnapshot;\n attach(adapter: ProjectionAdapter): () => void;\n get(id: ProjectionId): ProjectionActivity;\n isAttached(id: ProjectionId): boolean;\n subscribe(listener: (snapshot: ProjectionSnapshot) => void): () => void;\n}\n\n/** Typed identity of the per-editor projection coordinator. */\nexport const projectionCoordinatorServiceToken =\n createServiceToken<ProjectionCoordinatorService>(\n 'soeditor.projection-coordinator',\n );\n\nexport class ProjectionCoordinatorDestroyedError extends Error {\n constructor() {\n super('The projection coordinator has been destroyed.');\n this.name = 'ProjectionCoordinatorDestroyedError';\n }\n}\n\nexport class ProjectionAlreadyAttachedError extends Error {\n constructor(id: ProjectionId) {\n super(`Projection \"${id}\" is already attached.`);\n this.name = 'ProjectionAlreadyAttachedError';\n }\n}\n\nexport class ProjectionNotAttachedError extends Error {\n constructor(id: ProjectionId) {\n super(`Projection \"${id}\" is not attached.`);\n this.name = 'ProjectionNotAttachedError';\n }\n}\n\nexport class IncompatibleProjectionError extends Error {\n constructor(id: ProjectionId, format: DocumentFormat) {\n super(`Projection \"${id}\" is incompatible with \"${format}\" documents.`);\n this.name = 'IncompatibleProjectionError';\n }\n}\n\nexport class InvalidProjectionTransitionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'InvalidProjectionTransitionError';\n }\n}\n\nconst projectionIds: readonly ProjectionId[] = Object.freeze([\n 'visual',\n 'source',\n 'markdown',\n 'preview',\n]);\n\n/** Coordinates persistent projection activity without owning surface DOM. */\nexport class ProjectionCoordinatorPlugin extends Plugin {\n static readonly id = 'projection-coordinator';\n\n readonly #adapters = new Map<ProjectionId, ProjectionAdapter>();\n readonly #listeners = new Set<(snapshot: ProjectionSnapshot) => void>();\n readonly #visible = new Set<ProjectionId>();\n #destroyed = false;\n #disposeModeChange: (() => void) | undefined;\n #disposeStateChange: (() => void) | undefined;\n #primary: EditableProjectionId = 'visual';\n #synchronizingMode = false;\n\n override init(): void {\n const format = this.editor.state.document.format;\n this.#primary = defaultPrimary(format);\n const initialMode = this.editor.state.mode;\n if (initialMode === 'preview') {\n this.#visible.add(this.#primary);\n this.#visible.add('preview');\n } else if (isEditableForFormat(initialMode, format)) {\n this.#primary = initialMode;\n this.#visible.add(initialMode);\n } else {\n this.#visible.add(this.#primary);\n }\n\n const getSnapshot = (): ProjectionSnapshot => this.#snapshot();\n const service = Object.freeze<ProjectionCoordinatorService>({\n get snapshot() {\n return getSnapshot();\n },\n attach: (adapter) => this.#attach(adapter),\n get: (id) => this.#get(id),\n isAttached: (id) => this.#isAttached(id),\n subscribe: (listener) => this.#subscribe(listener),\n });\n this.editor.services.register(\n projectionCoordinatorServiceToken,\n service,\n );\n this.editor.commands.register({\n id: 'projection.activate',\n execute: (_context, ...args) =>\n this.#activate(\n readProjectionArgument('projection.activate', args),\n ),\n });\n this.editor.commands.register({\n id: 'projection.show',\n execute: (_context, ...args) =>\n this.#setVisible(\n readProjectionArgument('projection.show', args),\n true,\n ),\n });\n this.editor.commands.register({\n id: 'projection.hide',\n execute: (_context, ...args) =>\n this.#setVisible(\n readProjectionArgument('projection.hide', args),\n false,\n ),\n });\n this.#disposeModeChange = this.editor.events.on(\n 'mode:change',\n ({ current }) => this.#handleModeChange(current),\n );\n this.#disposeStateChange = this.editor.events.on(\n 'state:change',\n ({ current, previous }) => {\n if (current.readonly !== previous.readonly) this.#notify();\n },\n );\n }\n\n override destroy(): void {\n this.#destroyed = true;\n this.#disposeModeChange?.();\n this.#disposeModeChange = undefined;\n this.#disposeStateChange?.();\n this.#disposeStateChange = undefined;\n this.#adapters.clear();\n this.#listeners.clear();\n this.#visible.clear();\n }\n\n #attach(adapter: ProjectionAdapter): () => void {\n this.#assertAlive();\n validateAdapter(adapter);\n const format = this.editor.state.document.format;\n if (!isCompatible(adapter.id, format)) {\n throw new IncompatibleProjectionError(adapter.id, format);\n }\n if (this.#adapters.has(adapter.id)) {\n throw new ProjectionAlreadyAttachedError(adapter.id);\n }\n this.#adapters.set(adapter.id, adapter);\n try {\n adapter.update(this.#activity(adapter.id));\n } catch (error: unknown) {\n this.#adapters.delete(adapter.id);\n throw error;\n }\n let active = true;\n return () => {\n if (!active || this.#destroyed) {\n active = false;\n return;\n }\n if (this.#adapters.get(adapter.id) === adapter) {\n this.#adapters.delete(adapter.id);\n this.#repairPrimaryAfterDetach(adapter.id);\n this.#notify();\n }\n active = false;\n };\n }\n\n #activate(id: ProjectionId): void {\n this.#assertAttached(id);\n if (!isEditableForFormat(id, this.editor.state.document.format)) {\n throw new InvalidProjectionTransitionError(\n `Projection \"${id}\" cannot become a writable primary.`,\n );\n }\n if (!this.#visible.has(id)) {\n throw new InvalidProjectionTransitionError(\n `Projection \"${id}\" must be visible before activation.`,\n );\n }\n this.#synchronizingMode = true;\n try {\n if (this.editor.state.mode !== id) {\n this.editor.update((transaction) => transaction.setMode(id), {\n origin: 'command',\n });\n }\n } finally {\n this.#synchronizingMode = false;\n if (this.editor.state.mode === id) {\n this.#primary = id;\n this.#notify();\n }\n }\n }\n\n #setVisible(id: ProjectionId, visible: boolean): void {\n this.#assertAttached(id);\n if (!visible && id === this.#primary) {\n throw new InvalidProjectionTransitionError(\n `Primary projection \"${id}\" cannot be hidden.`,\n );\n }\n const changed = visible\n ? !this.#visible.has(id)\n : this.#visible.has(id);\n if (!changed) {\n return;\n }\n if (visible) {\n this.#visible.add(id);\n } else {\n this.#visible.delete(id);\n }\n this.#notify();\n }\n\n #handleModeChange(mode: EditorMode): void {\n if (this.#synchronizingMode) {\n return;\n }\n if (mode === 'preview') {\n if (this.#adapters.has('preview')) {\n this.#visible.add('preview');\n this.#notify();\n }\n return;\n }\n if (\n isEditableForFormat(mode, this.editor.state.document.format) &&\n this.#adapters.has(mode)\n ) {\n this.#visible.add(mode);\n this.#primary = mode;\n this.#notify();\n }\n }\n\n #repairPrimaryAfterDetach(detached: ProjectionId): void {\n if (detached !== this.#primary) {\n return;\n }\n const format = this.editor.state.document.format;\n const visible = projectionIds.find(\n (id): id is EditableProjectionId =>\n this.#adapters.has(id) &&\n this.#visible.has(id) &&\n isEditableForFormat(id, format),\n );\n const fallback =\n visible ??\n projectionIds.find(\n (id): id is EditableProjectionId =>\n this.#adapters.has(id) && isEditableForFormat(id, format),\n );\n this.#primary = fallback ?? defaultPrimary(format);\n if (fallback !== undefined) {\n this.#visible.add(fallback);\n }\n }\n\n #get(id: ProjectionId): ProjectionActivity {\n this.#assertAlive();\n assertProjectionId(id);\n return this.#activity(id);\n }\n\n #isAttached(id: ProjectionId): boolean {\n this.#assertAlive();\n assertProjectionId(id);\n return this.#adapters.has(id);\n }\n\n #subscribe(listener: (snapshot: ProjectionSnapshot) => void): () => void {\n this.#assertAlive();\n if (typeof listener !== 'function') {\n throw new TypeError('A projection listener must be a function.');\n }\n this.#listeners.add(listener);\n let active = true;\n return () => {\n if (active) {\n this.#listeners.delete(listener);\n }\n active = false;\n };\n }\n\n #activity(id: ProjectionId): ProjectionActivity {\n const primary = id === this.#primary;\n return Object.freeze({\n id,\n primary,\n readonly: this.editor.state.readonly || !primary,\n visible: this.#visible.has(id),\n });\n }\n\n #snapshot(): ProjectionSnapshot {\n this.#assertAlive();\n return Object.freeze({\n activities: Object.freeze(\n projectionIds.map((id) => this.#activity(id)),\n ),\n primary: this.#primary,\n });\n }\n\n #notify(): void {\n const snapshot = this.#snapshot();\n const errors: unknown[] = [];\n for (const activity of snapshot.activities) {\n const adapter = this.#adapters.get(activity.id);\n if (adapter !== undefined) {\n try {\n adapter.update(activity);\n } catch (error: unknown) {\n errors.push(error);\n }\n }\n }\n for (const listener of [...this.#listeners]) {\n try {\n listener(snapshot);\n } catch (error: unknown) {\n errors.push(error);\n }\n }\n if (errors.length > 0) {\n throw new AggregateError(\n errors,\n 'Projection activity notification failed.',\n );\n }\n }\n\n #assertAttached(id: ProjectionId): void {\n this.#assertAlive();\n assertProjectionId(id);\n if (!this.#adapters.has(id)) {\n throw new ProjectionNotAttachedError(id);\n }\n }\n\n #assertAlive(): void {\n if (this.#destroyed) {\n throw new ProjectionCoordinatorDestroyedError();\n }\n }\n}\n\nfunction defaultPrimary(format: DocumentFormat): EditableProjectionId {\n return format === 'markdown' ? 'markdown' : 'visual';\n}\n\nfunction isCompatible(id: ProjectionId, format: DocumentFormat): boolean {\n return id === 'preview' || isEditableForFormat(id, format);\n}\n\nfunction isEditableForFormat(\n id: EditorMode,\n format: DocumentFormat,\n): id is EditableProjectionId {\n return format === 'html'\n ? id === 'visual' || id === 'source'\n : id === 'markdown';\n}\n\nfunction validateAdapter(adapter: ProjectionAdapter): void {\n if (typeof adapter !== 'object' || adapter === null) {\n throw new TypeError('A projection adapter must be an object.');\n }\n assertProjectionId(adapter.id);\n if (typeof adapter.update !== 'function') {\n throw new TypeError(\n `Projection adapter \"${adapter.id}\" requires an update function.`,\n );\n }\n}\n\nfunction readProjectionArgument(\n command: string,\n args: readonly unknown[],\n): ProjectionId {\n if (args.length !== 1) {\n throw new TypeError(`Command \"${command}\" requires one projection ID.`);\n }\n assertProjectionId(args[0]);\n return args[0];\n}\n\nfunction assertProjectionId(value: unknown): asserts value is ProjectionId {\n if (!projectionIds.some((id) => id === value)) {\n throw new TypeError(`Unknown projection ID \"${String(value)}\".`);\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/projection-coordinator.ts"],"sourcesContent":["import {\n createServiceToken,\n Plugin,\n type DocumentFormat,\n type EditorMode,\n} from '@soeditor/core';\n\n/** Built-in projection identities coordinated by SoEditor. */\nexport type ProjectionId =\n 'visual' | 'wysiwyg' | 'source' | 'markdown' | 'preview';\n\n/** Projection identities that may hold logical write authority. */\nexport type EditableProjectionId = Exclude<ProjectionId, 'preview'>;\n\n/** Immutable effective activity delivered to one attached projection. */\nexport interface ProjectionActivity {\n readonly id: ProjectionId;\n readonly primary: boolean;\n readonly readonly: boolean;\n readonly visible: boolean;\n}\n\n/** Narrow lifecycle adapter implemented by a surface engine. */\nexport interface ProjectionAdapter {\n readonly id: ProjectionId;\n update(activity: ProjectionActivity): void;\n}\n\n/** Immutable observable coordinator state. */\nexport interface ProjectionSnapshot {\n readonly activities: readonly ProjectionActivity[];\n readonly primary: EditableProjectionId;\n}\n\n/** Per-editor projection attachment and observation capabilities. */\nexport interface ProjectionCoordinatorService {\n readonly snapshot: ProjectionSnapshot;\n attach(adapter: ProjectionAdapter): () => void;\n get(id: ProjectionId): ProjectionActivity;\n isAttached(id: ProjectionId): boolean;\n subscribe(listener: (snapshot: ProjectionSnapshot) => void): () => void;\n}\n\n/** Typed identity of the per-editor projection coordinator. */\nexport const projectionCoordinatorServiceToken =\n createServiceToken<ProjectionCoordinatorService>(\n 'soeditor.projection-coordinator',\n );\n\nexport class ProjectionCoordinatorDestroyedError extends Error {\n constructor() {\n super('The projection coordinator has been destroyed.');\n this.name = 'ProjectionCoordinatorDestroyedError';\n }\n}\n\nexport class ProjectionAlreadyAttachedError extends Error {\n constructor(id: ProjectionId) {\n super(`Projection \"${id}\" is already attached.`);\n this.name = 'ProjectionAlreadyAttachedError';\n }\n}\n\nexport class ProjectionNotAttachedError extends Error {\n constructor(id: ProjectionId) {\n super(`Projection \"${id}\" is not attached.`);\n this.name = 'ProjectionNotAttachedError';\n }\n}\n\nexport class IncompatibleProjectionError extends Error {\n constructor(id: ProjectionId, format: DocumentFormat) {\n super(`Projection \"${id}\" is incompatible with \"${format}\" documents.`);\n this.name = 'IncompatibleProjectionError';\n }\n}\n\nexport class InvalidProjectionTransitionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'InvalidProjectionTransitionError';\n }\n}\n\nconst projectionIds: readonly ProjectionId[] = Object.freeze([\n 'visual',\n 'wysiwyg',\n 'source',\n 'markdown',\n 'preview',\n]);\n\n/** Coordinates persistent projection activity without owning surface DOM. */\nexport class ProjectionCoordinatorPlugin extends Plugin {\n static readonly id = 'projection-coordinator';\n\n readonly #adapters = new Map<ProjectionId, ProjectionAdapter>();\n readonly #listeners = new Set<(snapshot: ProjectionSnapshot) => void>();\n readonly #visible = new Set<ProjectionId>();\n #destroyed = false;\n #disposeModeChange: (() => void) | undefined;\n #disposeStateChange: (() => void) | undefined;\n #primary: EditableProjectionId = 'visual';\n #synchronizingMode = false;\n\n override init(): void {\n const format = this.editor.state.document.format;\n this.#primary = defaultPrimary(format);\n const initialMode = this.editor.state.mode;\n if (initialMode === 'preview') {\n this.#visible.add(this.#primary);\n this.#visible.add('preview');\n } else if (isEditableForFormat(initialMode, format)) {\n this.#primary = initialMode;\n this.#visible.add(initialMode);\n } else {\n this.#visible.add(this.#primary);\n }\n\n const getSnapshot = (): ProjectionSnapshot => this.#snapshot();\n const service = Object.freeze<ProjectionCoordinatorService>({\n get snapshot() {\n return getSnapshot();\n },\n attach: (adapter) => this.#attach(adapter),\n get: (id) => this.#get(id),\n isAttached: (id) => this.#isAttached(id),\n subscribe: (listener) => this.#subscribe(listener),\n });\n this.editor.services.register(\n projectionCoordinatorServiceToken,\n service,\n );\n this.editor.commands.register({\n id: 'projection.activate',\n execute: (_context, ...args) =>\n this.#activate(\n readProjectionArgument('projection.activate', args),\n ),\n });\n this.editor.commands.register({\n id: 'projection.show',\n execute: (_context, ...args) =>\n this.#setVisible(\n readProjectionArgument('projection.show', args),\n true,\n ),\n });\n this.editor.commands.register({\n id: 'projection.hide',\n execute: (_context, ...args) =>\n this.#setVisible(\n readProjectionArgument('projection.hide', args),\n false,\n ),\n });\n this.#disposeModeChange = this.editor.events.on(\n 'mode:change',\n ({ current }) => this.#handleModeChange(current),\n );\n this.#disposeStateChange = this.editor.events.on(\n 'state:change',\n ({ current, previous }) => {\n if (current.readonly !== previous.readonly) this.#notify();\n },\n );\n }\n\n override destroy(): void {\n this.#destroyed = true;\n this.#disposeModeChange?.();\n this.#disposeModeChange = undefined;\n this.#disposeStateChange?.();\n this.#disposeStateChange = undefined;\n this.#adapters.clear();\n this.#listeners.clear();\n this.#visible.clear();\n }\n\n #attach(adapter: ProjectionAdapter): () => void {\n this.#assertAlive();\n validateAdapter(adapter);\n const format = this.editor.state.document.format;\n if (!isCompatible(adapter.id, format)) {\n throw new IncompatibleProjectionError(adapter.id, format);\n }\n if (this.#adapters.has(adapter.id)) {\n throw new ProjectionAlreadyAttachedError(adapter.id);\n }\n this.#adapters.set(adapter.id, adapter);\n try {\n adapter.update(this.#activity(adapter.id));\n } catch (error: unknown) {\n this.#adapters.delete(adapter.id);\n throw error;\n }\n let active = true;\n return () => {\n if (!active || this.#destroyed) {\n active = false;\n return;\n }\n if (this.#adapters.get(adapter.id) === adapter) {\n this.#adapters.delete(adapter.id);\n this.#repairPrimaryAfterDetach(adapter.id);\n this.#notify();\n }\n active = false;\n };\n }\n\n #activate(id: ProjectionId): void {\n this.#assertAttached(id);\n if (!isEditableForFormat(id, this.editor.state.document.format)) {\n throw new InvalidProjectionTransitionError(\n `Projection \"${id}\" cannot become a writable primary.`,\n );\n }\n if (!this.#visible.has(id)) {\n throw new InvalidProjectionTransitionError(\n `Projection \"${id}\" must be visible before activation.`,\n );\n }\n this.#synchronizingMode = true;\n try {\n if (this.editor.state.mode !== id) {\n this.editor.update((transaction) => transaction.setMode(id), {\n origin: 'command',\n });\n }\n } finally {\n this.#synchronizingMode = false;\n if (this.editor.state.mode === id) {\n this.#primary = id;\n this.#notify();\n }\n }\n }\n\n #setVisible(id: ProjectionId, visible: boolean): void {\n this.#assertAttached(id);\n if (\n !visible &&\n id === this.#primary &&\n !(\n this.editor.state.mode === 'preview' &&\n this.#visible.has('preview')\n )\n ) {\n throw new InvalidProjectionTransitionError(\n `Primary projection \"${id}\" cannot be hidden.`,\n );\n }\n const changed = visible\n ? !this.#visible.has(id)\n : this.#visible.has(id);\n if (!changed) {\n return;\n }\n if (visible) {\n this.#visible.add(id);\n } else {\n this.#visible.delete(id);\n }\n this.#notify();\n }\n\n #handleModeChange(mode: EditorMode): void {\n if (this.#synchronizingMode) {\n return;\n }\n if (mode === 'preview') {\n if (this.#adapters.has('preview')) {\n this.#visible.add('preview');\n this.#notify();\n }\n return;\n }\n if (\n isEditableForFormat(mode, this.editor.state.document.format) &&\n this.#adapters.has(mode)\n ) {\n this.#visible.add(mode);\n this.#primary = mode;\n this.#notify();\n }\n }\n\n #repairPrimaryAfterDetach(detached: ProjectionId): void {\n if (detached !== this.#primary) {\n return;\n }\n const format = this.editor.state.document.format;\n const visible = projectionIds.find(\n (id): id is EditableProjectionId =>\n this.#adapters.has(id) &&\n this.#visible.has(id) &&\n isEditableForFormat(id, format),\n );\n const fallback =\n visible ??\n projectionIds.find(\n (id): id is EditableProjectionId =>\n this.#adapters.has(id) && isEditableForFormat(id, format),\n );\n this.#primary = fallback ?? defaultPrimary(format);\n if (fallback !== undefined) {\n this.#visible.add(fallback);\n }\n }\n\n #get(id: ProjectionId): ProjectionActivity {\n this.#assertAlive();\n assertProjectionId(id);\n return this.#activity(id);\n }\n\n #isAttached(id: ProjectionId): boolean {\n this.#assertAlive();\n assertProjectionId(id);\n return this.#adapters.has(id);\n }\n\n #subscribe(listener: (snapshot: ProjectionSnapshot) => void): () => void {\n this.#assertAlive();\n if (typeof listener !== 'function') {\n throw new TypeError('A projection listener must be a function.');\n }\n this.#listeners.add(listener);\n let active = true;\n return () => {\n if (active) {\n this.#listeners.delete(listener);\n }\n active = false;\n };\n }\n\n #activity(id: ProjectionId): ProjectionActivity {\n const primary = id === this.#primary;\n return Object.freeze({\n id,\n primary,\n readonly: this.editor.state.readonly || !primary,\n visible: this.#visible.has(id),\n });\n }\n\n #snapshot(): ProjectionSnapshot {\n this.#assertAlive();\n return Object.freeze({\n activities: Object.freeze(\n projectionIds.map((id) => this.#activity(id)),\n ),\n primary: this.#primary,\n });\n }\n\n #notify(): void {\n const snapshot = this.#snapshot();\n const errors: unknown[] = [];\n for (const activity of snapshot.activities) {\n const adapter = this.#adapters.get(activity.id);\n if (adapter !== undefined) {\n try {\n adapter.update(activity);\n } catch (error: unknown) {\n errors.push(error);\n }\n }\n }\n for (const listener of [...this.#listeners]) {\n try {\n listener(snapshot);\n } catch (error: unknown) {\n errors.push(error);\n }\n }\n if (errors.length > 0) {\n throw new AggregateError(\n errors,\n 'Projection activity notification failed.',\n );\n }\n }\n\n #assertAttached(id: ProjectionId): void {\n this.#assertAlive();\n assertProjectionId(id);\n if (!this.#adapters.has(id)) {\n throw new ProjectionNotAttachedError(id);\n }\n }\n\n #assertAlive(): void {\n if (this.#destroyed) {\n throw new ProjectionCoordinatorDestroyedError();\n }\n }\n}\n\nfunction defaultPrimary(format: DocumentFormat): EditableProjectionId {\n return format === 'markdown' ? 'markdown' : 'visual';\n}\n\nfunction isCompatible(id: ProjectionId, format: DocumentFormat): boolean {\n return id === 'preview' || isEditableForFormat(id, format);\n}\n\nfunction isEditableForFormat(\n id: EditorMode,\n format: DocumentFormat,\n): id is EditableProjectionId {\n return format === 'html'\n ? id === 'visual' || id === 'wysiwyg' || id === 'source'\n : id === 'markdown';\n}\n\nfunction validateAdapter(adapter: ProjectionAdapter): void {\n if (typeof adapter !== 'object' || adapter === null) {\n throw new TypeError('A projection adapter must be an object.');\n }\n assertProjectionId(adapter.id);\n if (typeof adapter.update !== 'function') {\n throw new TypeError(\n `Projection adapter \"${adapter.id}\" requires an update function.`,\n );\n }\n}\n\nfunction readProjectionArgument(\n command: string,\n args: readonly unknown[],\n): ProjectionId {\n if (args.length !== 1) {\n throw new TypeError(`Command \"${command}\" requires one projection ID.`);\n }\n assertProjectionId(args[0]);\n return args[0];\n}\n\nfunction assertProjectionId(value: unknown): asserts value is ProjectionId {\n if (!projectionIds.some((id) => id === value)) {\n throw new TypeError(`Unknown projection ID \"${String(value)}\".`);\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { Plugin, type DocumentFormat } from '@soeditor/core';
2
- /** Built-in projection identities coordinated in SoEditor 0.6. */
3
- export type ProjectionId = 'visual' | 'source' | 'markdown' | 'preview';
2
+ /** Built-in projection identities coordinated by SoEditor. */
3
+ export type ProjectionId = 'visual' | 'wysiwyg' | 'source' | 'markdown' | 'preview';
4
4
  /** Projection identities that may hold logical write authority. */
5
5
  export type EditableProjectionId = Exclude<ProjectionId, 'preview'>;
6
6
  /** Immutable effective activity delivered to one attached projection. */
@@ -1 +1 @@
1
- {"version":3,"file":"projection-coordinator.d.ts","sourceRoot":"","sources":["../src/projection-coordinator.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,MAAM,EACN,KAAK,cAAc,EAEtB,MAAM,gBAAgB,CAAC;AAExB,kEAAkE;AAClE,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAExE,mEAAmE;AACnE,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;AAEpE,yEAAyE;AACzE,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,EAAE,EAAE,YAAY,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC7B;AAED,gEAAgE;AAChE,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,CAAC,EAAE,EAAE,YAAY,CAAC;IAC1B,MAAM,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;CAC9C;AAED,8CAA8C;AAC9C,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACnD,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;CAC1C;AAED,qEAAqE;AACrE,MAAM,WAAW,4BAA4B;IACzC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAAC;IAC/C,GAAG,CAAC,EAAE,EAAE,YAAY,GAAG,kBAAkB,CAAC;IAC1C,UAAU,CAAC,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC;IACtC,SAAS,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAC3E;AAED,+DAA+D;AAC/D,eAAO,MAAM,iCAAiC,qEAGzC,CAAC;AAEN,qBAAa,mCAAoC,SAAQ,KAAK;;CAK7D;AAED,qBAAa,8BAA+B,SAAQ,KAAK;gBACzC,EAAE,EAAE,YAAY;CAI/B;AAED,qBAAa,0BAA2B,SAAQ,KAAK;gBACrC,EAAE,EAAE,YAAY;CAI/B;AAED,qBAAa,2BAA4B,SAAQ,KAAK;gBACtC,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,cAAc;CAIvD;AAED,qBAAa,gCAAiC,SAAQ,KAAK;gBAC3C,OAAO,EAAE,MAAM;CAI9B;AASD,6EAA6E;AAC7E,qBAAa,2BAA4B,SAAQ,MAAM;;IACnD,MAAM,CAAC,QAAQ,CAAC,EAAE,4BAA4B;IAWrC,IAAI,IAAI,IAAI;IA+DZ,OAAO,IAAI,IAAI;CAgO3B"}
1
+ {"version":3,"file":"projection-coordinator.d.ts","sourceRoot":"","sources":["../src/projection-coordinator.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,MAAM,EACN,KAAK,cAAc,EAEtB,MAAM,gBAAgB,CAAC;AAExB,8DAA8D;AAC9D,MAAM,MAAM,YAAY,GACpB,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAE7D,mEAAmE;AACnE,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;AAEpE,yEAAyE;AACzE,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,EAAE,EAAE,YAAY,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC7B;AAED,gEAAgE;AAChE,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,CAAC,EAAE,EAAE,YAAY,CAAC;IAC1B,MAAM,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;CAC9C;AAED,8CAA8C;AAC9C,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACnD,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;CAC1C;AAED,qEAAqE;AACrE,MAAM,WAAW,4BAA4B;IACzC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAAC;IAC/C,GAAG,CAAC,EAAE,EAAE,YAAY,GAAG,kBAAkB,CAAC;IAC1C,UAAU,CAAC,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC;IACtC,SAAS,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAC3E;AAED,+DAA+D;AAC/D,eAAO,MAAM,iCAAiC,qEAGzC,CAAC;AAEN,qBAAa,mCAAoC,SAAQ,KAAK;;CAK7D;AAED,qBAAa,8BAA+B,SAAQ,KAAK;gBACzC,EAAE,EAAE,YAAY;CAI/B;AAED,qBAAa,0BAA2B,SAAQ,KAAK;gBACrC,EAAE,EAAE,YAAY;CAI/B;AAED,qBAAa,2BAA4B,SAAQ,KAAK;gBACtC,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,cAAc;CAIvD;AAED,qBAAa,gCAAiC,SAAQ,KAAK;gBAC3C,OAAO,EAAE,MAAM;CAI9B;AAUD,6EAA6E;AAC7E,qBAAa,2BAA4B,SAAQ,MAAM;;IACnD,MAAM,CAAC,QAAQ,CAAC,EAAE,4BAA4B;IAWrC,IAAI,IAAI,IAAI;IA+DZ,OAAO,IAAI,IAAI;CAuO3B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soeditor/projections",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "license": "MIT",
5
5
  "description": "Framework-independent projection activity coordination for SoEditor.",
6
6
  "keywords": [
@@ -37,10 +37,10 @@
37
37
  }
38
38
  },
39
39
  "peerDependencies": {
40
- "@soeditor/core": "1.0.0"
40
+ "@soeditor/core": "1.1.0"
41
41
  },
42
42
  "devDependencies": {
43
- "@soeditor/core": "1.0.0"
43
+ "@soeditor/core": "1.1.0"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "vite build && tsc -p tsconfig.build.json",