mnfst 0.5.231 → 0.5.232

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/lib/manifest.d.ts CHANGED
@@ -351,80 +351,203 @@ export interface ManifestCamera {
351
351
  pick(opts?: Record<string, unknown>): Promise<unknown>;
352
352
  }
353
353
 
354
- /** Element editor (`x-edit`) — opt-in plugin. Sortable lists and resizable elements
355
- * by default; add `.authoring` where a region is a page being edited. */
354
+ /** Edit action names for `$edit.can()` and per-action locks. */
355
+ export type ManifestEditAction = 'move' | 'remove' | 'duplicate' | 'text' | 'attrs' | 'size';
356
+ /** `can()` also answers 'class' (the class list; component nodes allow only this) and copy/cut/paste. */
357
+
358
+ /** Class controls on `$edit.classes`. `el` defaults to `$edit.target`. */
359
+ export interface ManifestEditClasses {
360
+ add(cls: string, el?: Element): boolean;
361
+ remove(cls: string, el?: Element): boolean;
362
+ toggle(cls: string, el?: Element, force?: boolean): boolean;
363
+ has(cls: string, el?: Element): boolean;
364
+ /** Replace the static class list. */
365
+ set(value: string, el?: Element): boolean;
366
+ /** The static classes (bound :class classes excluded). */
367
+ list(el?: Element): string[];
368
+ }
369
+
370
+ /** Element editor (`x-edit`) — opt-in plugin. Modifiers: `.text` `.move` `.size`
371
+ * `.data` (default text + move), `.lock[.action]`, `.gated`, `.persist`, `.bare`,
372
+ * `.theme`, `.cssvar`. Every edit is logged; actions default to `$edit.target`. */
356
373
  export interface ManifestEdit {
357
- /** True while a `.gated` area is editable. */
374
+ /** True while `.gated` areas are editable. */
358
375
  active: boolean;
359
376
  canUndo: boolean;
360
377
  canRedo: boolean;
378
+ /** Bumps on every change to the log or target; read it to make a binding re-evaluate. */
379
+ version: number;
361
380
  /** Set a handler to route patches somewhere other than the dev server. */
362
381
  onPublish: ((patches: unknown[], state: { log: unknown[]; cursor: number }) => unknown) | null;
363
382
  toggle(): void;
364
383
  on(): void;
365
384
  off(): void;
366
- undo(): void;
367
- redo(): void;
368
- /** Lock an element and its subtree out of editing (runtime, not logged). */
369
- lock(el: Element): void;
370
- unlock(el: Element): void;
371
- /** Resolve the edit log into source patches and send them. */
372
- publish(): Promise<unknown>;
373
- /** The resolved source patches, without sending them. */
385
+ undo(): Promise<void>;
386
+ redo(): Promise<void>;
387
+ /** Source files that changed since the page loaded, from the last refused publish (also an
388
+ * `edit:stale` event on document, detail `{ files }`), or a reload held back because it
389
+ * would lose unpublished edits. */
390
+ stale: string[];
391
+ /** Edits that could not be applied because the source changed under them (also an
392
+ * `edit:conflict` event on document, detail `{ conflicts }`, and a console warning).
393
+ * `element` names what was edited (tag and opening text, or the region for layout);
394
+ * `value` what the edit held; `reason` says what happened in words.
395
+ * - A text or attribute edit whose element changed: `prop` is the edited property.
396
+ * - Layout (`prop: 'structure'`): kept when only unmoved children changed text in place;
397
+ * dropped when a moved, added or removed child changed, with `value`
398
+ * `{ changed: [{ was, now }], moved: [...], copies: [{ of, html, text }] }` so typed
399
+ * content can be recovered. */
400
+ conflicts: Array<{ region: string; key: string; element: string; prop: string; value: unknown; before: unknown; reason: string }>;
401
+ /** Empty `conflicts`. Those of `.persist` regions are kept across reloads until this is called. */
402
+ clearConflicts(): void;
403
+ /** Send every area's patches; on success the history is cleared (the source now holds it).
404
+ * `rebase: true` takes the current source as the base (writes over external changes). */
405
+ publish(opts?: { rebase?: boolean }): Promise<unknown>;
406
+ /** The resolved source patches for every area, without sending them. */
374
407
  patches(): unknown[];
375
408
  /** The raw delta log — persist it yourself to move edits between devices. */
376
409
  export(): { log: unknown[]; cursor: number };
377
- /** The block a context menu is acting on — set by the last right-click, or
378
- * assignable. Block operations default to it when called with no element. */
410
+ /** The piece a right-click landed on (set before any menu opens), or assignable. */
379
411
  target: Element | null;
380
- /** Whether an operation applies right now: copy, cut, paste, duplicate, remove. */
381
- can(op: string, el?: Element): boolean;
412
+ /** Whether an action applies to `el` (default `$edit.target`): capability and locks. */
413
+ can(action: ManifestEditAction | 'class' | 'copy' | 'cut' | 'paste', el?: Element | null): boolean;
414
+ /** Lock `el` and its subtree for one action, or all when omitted. Logged. A component host
415
+ * (see `block`) locks by its host key, for all its roots and what is in them. */
416
+ lock(el?: Element | null, action?: ManifestEditAction): boolean;
417
+ unlock(el?: Element | null, action?: ManifestEditAction): boolean;
382
418
  copy(el?: Element): boolean;
383
419
  cut(el?: Element): boolean;
384
420
  paste(el?: Element): boolean;
385
421
  duplicate(el?: Element): boolean;
386
422
  remove(el?: Element): boolean;
387
- /** Move a block into another static region (area element or x-edit key), before `ref` or at the end. */
423
+ /** Move a piece into a container (element or area key), before `before` or at the end. */
388
424
  move(el: Element | null, dest: Element | string, before?: Element | null): boolean;
389
- /** The addressable block containing a node, or null. */
425
+ /** Nest a piece into the container before it. */
426
+ nest(el?: Element): boolean;
427
+ /** Move a piece out of its container, after it. */
428
+ unnest(el?: Element): boolean;
429
+ /** The piece containing a node, or null. In a static area a component instance is one
430
+ * piece, its host (its first rendered root; the rest follow it): it moves, duplicates
431
+ * (a new instance) and is removed as one, and its markup is not edited from here. */
390
432
  block(node: Element): Element | null;
433
+ /** Set an attribute: a string sets it, `true` sets it empty, `null`/`false` removes it. */
434
+ attr(name: string, value: string | boolean | null, el?: Element): boolean;
435
+ classes: ManifestEditClasses;
436
+ /** Component scope of the target's area: read with no value, set 'instance' or 'main'.
437
+ * Instance overrides apply to an area that wraps exactly one component with no x-edit region
438
+ * of its own; a component among other content is a host piece of a static area instead, and
439
+ * a component's own region is edited in its own file. */
440
+ scope(value?: 'instance' | 'main', el?: Element): 'instance' | 'main' | null | boolean;
441
+ /** Revert a component element's instance overrides (the area element reverts all). */
442
+ revert(el?: Element): boolean;
391
443
  }
392
444
 
393
- /** Text editor (`x-text-edit`) — the area this element sits in, or the last focused one. */
394
- export interface ManifestTextEdit {
395
- /** The stored value, in the mode the directive was given. Assigning replaces the
396
- * document and resets undo history. */
445
+ /** Rich text editor (`x-rich-text`): the area this element sits in, or the last focused one. */
446
+ export interface ManifestRichText {
447
+ /** The stored value, in the area's format. Assigning replaces the document and resets undo history. */
397
448
  value: string;
398
449
  focus(): void;
399
450
  /** The href at the caret; assign to set it, assign '' to unlink. */
400
451
  link: string;
401
- /** Page-level styles (font, size, leading, align, color, background) as CSS
402
- * custom properties on the area. Presentation, not document content — persist
403
- * it yourself. Assign `{}` to clear. */
404
- page: Record<string, string>;
452
+ /** Document-wide styles (font, size, leading, align, color, background) as CSS custom
453
+ * properties on the area; not part of the stored value. Assign `{}` to clear. */
454
+ all: Record<string, string>;
405
455
  /** Select the whole document. */
406
456
  selectAll(): void;
407
- /** The current selection and its geometry, or null. Also emitted as a
408
- * `text-edit:selection` event and as --text-edit-selection-* custom properties
409
- * on the area, for anchoring a menu to it. */
457
+ /** The current selection and its geometry, or null. Also emitted as a `rich-text:selection`
458
+ * event and as --rich-text-selection-* custom properties. */
410
459
  selection: {
411
460
  collapsed: boolean; text: string;
412
461
  x: number; y: number; width: number; height: number;
413
462
  top: number; bottom: number; left: number; right: number;
414
463
  } | null;
415
- /** Apply a command. Commands are named for the tag they produce — 'strong',
416
- * 'blockquote', 'h2', 'ul', 'a', 'img', 'table' — plus the operations with no
417
- * tag of their own: 'indent', 'outdent', 'align', 'color', 'background',
418
- * 'font', 'size', 'checklist', 'clear', 'undo', 'redo', 'block'. */
419
- run(command: string, arg?: string | number): void;
464
+ /** Apply a command. Commands are HTML tag names ('strong', 'h2', 'ul', 'a', 'table', …) plus
465
+ * 'indent', 'outdent', 'align', 'color', 'background', 'font', 'size', 'leading', 'checklist',
466
+ * 'unlink', 'clear', 'undo', 'redo', 'block' and the table operations. Every command is also
467
+ * a method: `$rich.strong()`, `$rich.table(3, 2)` (columns, rows). */
468
+ run(command: string, arg?: unknown): void;
420
469
  /** Whether that command is active at the caret. */
421
470
  active(command: string): boolean;
422
- /** Whether that command is available in this area's mode. */
471
+ /** Whether that command is available here (format, .inline, caret). */
423
472
  can(command: string): boolean;
424
- /** Read the content as markdown regardless of the storage mode. */
473
+ /** Read the content as markdown regardless of the storage format. */
425
474
  markdown(): string;
426
- /** Read the content as sanitized HTML regardless of the storage mode. */
475
+ /** Read the content as sanitized HTML regardless of the storage format. */
427
476
  html(): string;
477
+
478
+ // Inline tags: toggle on the selection, or arm for the next typed text
479
+ strong(): void; b(): void; em(): void; i(): void; s(): void; del(): void; code(): void;
480
+ bdi(): void; cite(): void; ins(): void; kbd(): void; mark(): void; q(): void; samp(): void;
481
+ small(): void; span(): void; sub(): void; sup(): void; u(): void; var(): void;
482
+ /** `title` attribute (html only). */
483
+ abbr(title?: string): void;
484
+ /** `title` attribute (html only). */
485
+ dfn(title?: string): void;
486
+ /** Direction, default 'rtl' (html only). */
487
+ bdo(dir?: 'ltr' | 'rtl' | 'auto'): void;
488
+ /** Machine-readable `value` (html only). */
489
+ data(value?: string): void;
490
+ /** `datetime` attribute (html only). */
491
+ time(datetime?: string): void;
492
+ /** Link the selection; '' unlinks. */
493
+ a(href?: string): void;
494
+ unlink(): void;
495
+ br(): void;
496
+ /** Break opportunity (html only). */
497
+ wbr(): void;
498
+ img(src: string, alt?: string): void;
499
+
500
+ // Block tags: convert the block (again returns to p)
501
+ p(): void; h1(): void; h2(): void; h3(): void; h4(): void; h5(): void; h6(): void;
502
+ blockquote(): void; pre(): void; address(): void;
503
+ ul(): void; ol(): void; li(): void; checklist(): void; hr(): void;
504
+ figure(): void; figcaption(): void; dl(): void; dt(): void; dd(): void;
505
+ /** Any block tag by name, e.g. block('h2'). */
506
+ block(tag: string): void;
507
+
508
+ /** Insert a columns × rows table (default 3 × 3). */
509
+ table(columns?: number, rows?: number): void;
510
+ 'row-before'(): void; 'row-after'(): void; 'row-remove'(): void;
511
+ 'column-before'(): void; 'column-after'(): void; 'column-remove'(): void;
512
+ 'table-remove'(): void; 'table-header'(): void; merge(): void; split(): void;
513
+
514
+ indent(): void; outdent(): void;
515
+ align(value?: 'start' | 'center' | 'end' | 'justify' | string): void;
516
+ leading(value: string): void;
517
+ color(value: string): void;
518
+ background(value: string): void;
519
+ font(value: string): void;
520
+ size(value: string | number): void;
521
+ clear(): void;
522
+ undo(): void;
523
+ redo(): void;
524
+ }
525
+
526
+ /** Options for `ManifestRichText.attach()`. */
527
+ export interface ManifestRichTextAttachOptions {
528
+ /** 'block' (default) or 'inline' (single line: no block commands, Enter fires `rich-text:enter`). */
529
+ mode?: 'block' | 'inline';
530
+ /** Inline html only: `<br>` line breaks are kept, Shift+Enter inserts one, pasted blocks become lines. */
531
+ breaks?: boolean;
532
+ /** false: `.all` controls and `$rich.all` are unavailable (no area-wide --rich-text-* styles). Default true. */
533
+ all?: boolean;
534
+ /** Storage format: 'markdown' (default), 'html' or 'plain'. */
535
+ format?: 'markdown' | 'html' | 'plain';
536
+ /** Initial value; omitted, the element's existing markup is the content. */
537
+ value?: string;
538
+ /** No markdown autoformat while typing. */
539
+ literal?: boolean;
540
+ /** Called with the stored value after every change. */
541
+ onChange?(value: string): void;
542
+ }
543
+
544
+ /** Returned by `ManifestRichText.attach()`: the `$rich` surface plus detach(). */
545
+ export interface ManifestRichTextHandle extends ManifestRichText {
546
+ el: Element;
547
+ /** Remove editing and restore the element's own contenteditable/role/aria-multiline. */
548
+ detach(): void;
549
+ /** Markup of the newest step in the field's undo history (a pending typing burst is recorded first). */
550
+ newest(): string;
428
551
  }
429
552
 
430
553
  /**
@@ -437,7 +560,7 @@ export type ManifestDirective =
437
560
  | 'x-toast' | 'x-tooltip' | 'x-carousel' | 'x-virtual' | 'x-computed' | 'x-defer'
438
561
  | 'x-chart' | 'x-date' | 'x-color' | 'x-colorpicker' | 'x-combobox'
439
562
  | 'x-export' | 'x-import' | 'x-pay' | 'x-files' | 'x-data-files'
440
- | 'x-edit' | 'x-text-edit';
563
+ | 'x-edit' | 'x-rich-text';
441
564
 
442
565
  // ---------------------------------------------------------------------------
443
566
  // Global declarations (what Alpine exposes inside `x-data`, `x-show`, etc.)
@@ -487,8 +610,8 @@ declare global {
487
610
  const $import: ManifestImport;
488
611
  /** Element editor (edit plugin; opt-in). */
489
612
  const $edit: ManifestEdit;
490
- /** Text editor (text-edit plugin). */
491
- const $text: ManifestTextEdit;
613
+ /** Rich text editor (rich-text plugin; loaded on use). */
614
+ const $rich: ManifestRichText;
492
615
  /** Device/platform info (utilities; enriched by the device plugin). */
493
616
  const $device: ManifestDevice;
494
617
  /** Native share (device plugin). */
@@ -523,6 +646,14 @@ declare global {
523
646
  };
524
647
  Alpine?: unknown;
525
648
  __manifestLoaded?: unknown;
649
+ /** Rich text engine (rich-text plugin). */
650
+ ManifestRichText?: {
651
+ attach(el: Element, options?: ManifestRichTextAttachOptions): ManifestRichTextHandle | null;
652
+ toMarkdown(root: Element): string;
653
+ fromMarkdown(markdown: string): string;
654
+ sanitize(html: string, allowBlocks?: boolean, keepStyle?: boolean): string;
655
+ commands(): string[];
656
+ };
526
657
  }
527
658
 
528
659
  /**
@@ -2,7 +2,7 @@
2
2
 
3
3
  (function () {
4
4
 
5
- const MANIFEST_BUILD_VERSION = '0.5.231';
5
+ const MANIFEST_BUILD_VERSION = '0.5.232';
6
6
 
7
7
  /* Manifest Data Sources - Configuration */
8
8
 
@@ -6,7 +6,7 @@
6
6
  // Directives that render their own children — never stash under them
7
7
  const OWNS_CHILDREN = new Set([
8
8
  'x-html', 'x-text', 'x-ignore', 'x-markdown', 'x-icon', 'x-svg', 'x-code', 'x-code-group',
9
- 'x-chart', 'x-carousel', 'x-virtual', 'x-combobox', 'x-colorpicker', 'x-date', 'x-text-edit'
9
+ 'x-chart', 'x-carousel', 'x-virtual', 'x-combobox', 'x-colorpicker', 'x-date', 'x-rich-text'
10
10
  ]);
11
11
 
12
12
  // Kill switch: data-defer="off" on the loader script; prerender snapshots keep eager markup
@@ -359,6 +359,8 @@ function initializeDropdownPlugin() {
359
359
  pressTimer = null;
360
360
  restoreCallout();
361
361
  el.__mnfstLongPressOpenedAt = Date.now();
362
+ // No contextmenu event on iOS: announce the press so composing plugins (x-edit) can track the target.
363
+ pressTarget.dispatchEvent(new CustomEvent('dropdown:context', { bubbles: true, detail: { x: startX, y: startY } }));
362
364
  openContextMenuAt(pressTarget, startX, startY);
363
365
  }, LONG_PRESS_MS);
364
366
  });