@plannotator/ui 0.45.0 → 0.45.1

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/HANDOFF.md CHANGED
@@ -450,6 +450,8 @@ The package now owns the reusable two-stage `/embed` authoring flow. The host st
450
450
 
451
451
  4. **Grammar belongs to the host; splicing belongs to the package.** `buildInsertLine(target)` returns the exact line the host wants stored. `planEmbedInsert()` then normalizes that line into its own blank-line-delimited paragraph and places the caret on the following line. Host-specific path resolution, label escaping, and embed-fragment grammar stay outside the package.
452
452
 
453
+ **Host labels (0.45.1).** `EmbedPickerConfig.labels?: { upload?: string; empty?: string; noMatch?: (query: string) => string }` replaces the three rows that name the target type ("Upload HTML...", "No HTML files in this workspace", "No HTML files match “<query>”") for a host that feeds the picker more than HTML files. Each absent key keeps the built-in text, so a host passing nothing (Plannotator) renders exactly the menu it always did. The "Uploading..." row and the notice row are unchanged.
454
+
453
455
  5. **Upload is optional and single-flight.** When `uploadTarget` is absent, no upload row is rendered. When present, every picker state includes `Upload HTML...`. While its promise is pending, the typed `/embed` text stays visible and a reopened picker shows an inert `Uploading...` row. Resolving with a target inserts it through `buildInsertLine` and the same splice as an existing target; resolving `null` or rejecting leaves the typed command untouched. The package maps the anchor through CodeMirror transactions and silently drops the insert if the command was edited away. The host owns all failure UI.
454
456
 
455
457
  6. **One CodeMirror dependency graph.** The picker imports `@codemirror/autocomplete`, `@codemirror/state`, and `@codemirror/view` from `@plannotator/ui`'s declared dependencies. `@plannotator/atomic-editor` declares these as peers, so a consumer must resolve one shared copy. A second live copy of `@codemirror/state` breaks extensions just as it does for `wikiLinks`.
package/README.md CHANGED
@@ -74,7 +74,7 @@ Plannotator's own entries import the eager math and identity modules (`math-eage
74
74
  const editorExtensions = [wikiLinks({ suggest, resolve, onOpen })]; // stable reference!
75
75
  <MarkdownEditor markdown={md} documentId={docId} editorHandleRef={ref} extensions={editorExtensions} />
76
76
  ```
77
- - **`embedPicker(config)` and `embedSlashItem()` are re-exported from the same surface.** Compose the static item into `slashCommands({ items: [...] })` and pass the picker beside it in the stable `extensions` array. `getTargets`, `buildInsertLine`, optional `uploadTarget`, and optional `getNotice` stay live through callbacks. The host owns embed grammar and upload error UI; the package owns filtering, async anchor mapping, single-flight upload state, and paragraph-safe insertion through the re-exported `planEmbedInsert()`.
77
+ - **`embedPicker(config)` and `embedSlashItem()` are re-exported from the same surface.** Compose the static item into `slashCommands({ items: [...] })` and pass the picker beside it in the stable `extensions` array. `getTargets`, `buildInsertLine`, optional `uploadTarget`, and optional `getNotice` stay live through callbacks. Optional `labels` (`upload`, `empty`, `noMatch(query)`) reword the three rows that say "HTML"; absent keys keep the built-in text. The host owns embed grammar and upload error UI; the package owns filtering, async anchor mapping, single-flight upload state, and paragraph-safe insertion through the re-exported `planEmbedInsert()`.
78
78
  - **The viewer resolves wiki-links synchronously.** `InlineMarkdown` takes `resolveLinkedDoc?: (target) => { label?; status?: 'active' | 'deleted' } | null` — called with the raw stored target (opaque ids like `doc_01XYZ`, no `.md` normalization). Return a `label` to display live titles (stored label is the fallback, target the last resort); return `status: 'deleted'` for a muted non-link ("Document deleted") instead of a live link. Absent or `null` → rendering is unchanged. Sync-only by design: back it with an in-memory cache.
79
79
 
80
80
  Requires `@plannotator/markdown-editor ^0.3.2` and `@plannotator/atomic-editor ^0.7.0`. See HANDOFF.md § "Wiki-link seams (0.27.0)".
@@ -42,6 +42,19 @@ export interface EmbedPickerConfig {
42
42
  readonly uploadTarget?: (kind: EmbedKind) => Promise<EmbedTarget | null>;
43
43
  /** Return an optional informational row for the current document text. */
44
44
  readonly getNotice?: (docBody: string) => string | null;
45
+ /**
46
+ * Host copy for the three rows that name the target type (0.45.1). A host
47
+ * that feeds the picker more than HTML files passes its own wording; each
48
+ * absent key keeps the built-in text, so Plannotator's menu is unchanged.
49
+ */
50
+ readonly labels?: {
51
+ /** The upload row. Default: "Upload HTML..." */
52
+ readonly upload?: string;
53
+ /** The row shown when there are no targets at all. Default: "No HTML files in this workspace" */
54
+ readonly empty?: string;
55
+ /** The row shown when the query matches nothing. Default: "No HTML files match “<query>”" */
56
+ readonly noMatch?: (query: string) => string;
57
+ };
45
58
  }
46
59
 
47
60
  type IconCompletion = Completion & {
@@ -175,8 +188,8 @@ function createEmbedPickerSource(
175
188
  options.push({
176
189
  label:
177
190
  targets.length === 0
178
- ? 'No HTML files in this workspace'
179
- : `No HTML files match “${query.trim()}”`,
191
+ ? config.labels?.empty ?? 'No HTML files in this workspace'
192
+ : config.labels?.noMatch?.(query.trim()) ?? `No HTML files match “${query.trim()}”`,
180
193
  apply: (view, completion, _from, to) => {
181
194
  view.dispatch({
182
195
  changes: { from: line.from, to, insert: '' },
@@ -209,7 +222,7 @@ function createEmbedPickerSource(
209
222
  },
210
223
  }
211
224
  : {
212
- label: 'Upload HTML...',
225
+ label: config.labels?.upload ?? 'Upload HTML...',
213
226
  slashCommandIcon: UPLOAD_ICON,
214
227
  apply: (view, completion, from, to) => {
215
228
  startUpload(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plannotator/ui",
3
- "version": "0.45.0",
3
+ "version": "0.45.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./components/*": "./components/*.tsx",