mnfst 0.5.231 → 0.5.233

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,205 @@ 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 `el`'s area (default `$edit.target`): `scope(el)` reads it.
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(el?: Element | null): 'instance' | 'main' | null;
441
+ /** Set the component scope of `el`'s area (default `$edit.target`); false if it has none. */
442
+ scope(value: 'instance' | 'main', el?: Element | null): boolean;
443
+ /** Revert a component element's instance overrides (the area element reverts all). */
444
+ revert(el?: Element): boolean;
391
445
  }
392
446
 
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. */
447
+ /** Rich text editor (`x-rich-text`): the area this element sits in, or the last focused one. */
448
+ export interface ManifestRichText {
449
+ /** The stored value, in the area's format. Assigning replaces the document and resets undo history. */
397
450
  value: string;
398
451
  focus(): void;
399
452
  /** The href at the caret; assign to set it, assign '' to unlink. */
400
453
  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>;
454
+ /** Document-wide styles (font, size, leading, align, color, background) as CSS custom
455
+ * properties on the area; not part of the stored value. Assign `{}` to clear. */
456
+ all: Record<string, string>;
405
457
  /** Select the whole document. */
406
458
  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. */
459
+ /** The current selection and its geometry, or null. Also emitted as a `rich-text:selection`
460
+ * event and as --rich-text-selection-* custom properties. */
410
461
  selection: {
411
462
  collapsed: boolean; text: string;
412
463
  x: number; y: number; width: number; height: number;
413
464
  top: number; bottom: number; left: number; right: number;
414
465
  } | 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;
466
+ /** Apply a command. Commands are HTML tag names ('strong', 'h2', 'ul', 'a', 'table', …) plus
467
+ * 'indent', 'outdent', 'align', 'color', 'background', 'font', 'size', 'leading', 'checklist',
468
+ * 'unlink', 'clear', 'undo', 'redo', 'block' and the table operations. Every command is also
469
+ * a method: `$rich.strong()`, `$rich.table(3, 2)` (columns, rows). */
470
+ run(command: string, arg?: unknown): void;
420
471
  /** Whether that command is active at the caret. */
421
472
  active(command: string): boolean;
422
- /** Whether that command is available in this area's mode. */
473
+ /** Whether that command is available here (format, .inline, caret). */
423
474
  can(command: string): boolean;
424
- /** Read the content as markdown regardless of the storage mode. */
475
+ /** Read the content as markdown regardless of the storage format. */
425
476
  markdown(): string;
426
- /** Read the content as sanitized HTML regardless of the storage mode. */
477
+ /** Read the content as sanitized HTML regardless of the storage format. */
427
478
  html(): string;
479
+
480
+ // Inline tags: toggle on the selection, or arm for the next typed text
481
+ strong(): void; b(): void; em(): void; i(): void; s(): void; del(): void; code(): void;
482
+ bdi(): void; cite(): void; ins(): void; kbd(): void; mark(): void; q(): void; samp(): void;
483
+ small(): void; span(): void; sub(): void; sup(): void; u(): void; var(): void;
484
+ /** `title` attribute (html only). */
485
+ abbr(title?: string): void;
486
+ /** `title` attribute (html only). */
487
+ dfn(title?: string): void;
488
+ /** Direction, default 'rtl' (html only). */
489
+ bdo(dir?: 'ltr' | 'rtl' | 'auto'): void;
490
+ /** Machine-readable `value` (html only). */
491
+ data(value?: string): void;
492
+ /** `datetime` attribute (html only). */
493
+ time(datetime?: string): void;
494
+ /** Link the selection; '' unlinks. */
495
+ a(href?: string): void;
496
+ unlink(): void;
497
+ br(): void;
498
+ /** Break opportunity (html only). */
499
+ wbr(): void;
500
+ img(src: string, alt?: string): void;
501
+
502
+ // Block tags: convert the block (again returns to p)
503
+ p(): void; h1(): void; h2(): void; h3(): void; h4(): void; h5(): void; h6(): void;
504
+ blockquote(): void; pre(): void; address(): void;
505
+ ul(): void; ol(): void; li(): void; checklist(): void; hr(): void;
506
+ figure(): void; figcaption(): void; dl(): void; dt(): void; dd(): void;
507
+ /** Any block tag by name, e.g. block('h2'). */
508
+ block(tag: string): void;
509
+
510
+ /** Insert a columns × rows table (default 3 × 3). */
511
+ table(columns?: number, rows?: number): void;
512
+ 'row-before'(): void; 'row-after'(): void; 'row-remove'(): void;
513
+ 'column-before'(): void; 'column-after'(): void; 'column-remove'(): void;
514
+ 'table-remove'(): void; 'table-header'(): void; merge(): void; split(): void;
515
+
516
+ indent(): void; outdent(): void;
517
+ align(value?: 'start' | 'center' | 'end' | 'justify' | string): void;
518
+ leading(value: string): void;
519
+ color(value: string): void;
520
+ background(value: string): void;
521
+ font(value: string): void;
522
+ size(value: string | number): void;
523
+ clear(): void;
524
+ undo(): void;
525
+ redo(): void;
526
+ }
527
+
528
+ /** Options for `ManifestRichText.attach()`. */
529
+ export interface ManifestRichTextAttachOptions {
530
+ /** 'block' (default) or 'inline' (single line: no block commands, Enter fires `rich-text:enter`). */
531
+ mode?: 'block' | 'inline';
532
+ /** Inline html only: `<br>` line breaks are kept, Shift+Enter inserts one, pasted blocks become lines. */
533
+ breaks?: boolean;
534
+ /** false: `.all` controls and `$rich.all` are unavailable (no area-wide --rich-text-* styles). Default true. */
535
+ all?: boolean;
536
+ /** Storage format: 'markdown' (default), 'html' or 'plain'. */
537
+ format?: 'markdown' | 'html' | 'plain';
538
+ /** Initial value; omitted, the element's existing markup is the content. */
539
+ value?: string;
540
+ /** No markdown autoformat while typing. */
541
+ literal?: boolean;
542
+ /** Called with the stored value after every change. */
543
+ onChange?(value: string): void;
544
+ }
545
+
546
+ /** Returned by `ManifestRichText.attach()`: the `$rich` surface plus detach(). */
547
+ export interface ManifestRichTextHandle extends ManifestRichText {
548
+ el: Element;
549
+ /** Remove editing and restore the element's own contenteditable/role/aria-multiline. */
550
+ detach(): void;
551
+ /** Markup of the newest step in the field's undo history (a pending typing burst is recorded first). */
552
+ newest(): string;
428
553
  }
429
554
 
430
555
  /**
@@ -437,7 +562,7 @@ export type ManifestDirective =
437
562
  | 'x-toast' | 'x-tooltip' | 'x-carousel' | 'x-virtual' | 'x-computed' | 'x-defer'
438
563
  | 'x-chart' | 'x-date' | 'x-color' | 'x-colorpicker' | 'x-combobox'
439
564
  | 'x-export' | 'x-import' | 'x-pay' | 'x-files' | 'x-data-files'
440
- | 'x-edit' | 'x-text-edit';
565
+ | 'x-edit' | 'x-rich-text';
441
566
 
442
567
  // ---------------------------------------------------------------------------
443
568
  // Global declarations (what Alpine exposes inside `x-data`, `x-show`, etc.)
@@ -487,8 +612,8 @@ declare global {
487
612
  const $import: ManifestImport;
488
613
  /** Element editor (edit plugin; opt-in). */
489
614
  const $edit: ManifestEdit;
490
- /** Text editor (text-edit plugin). */
491
- const $text: ManifestTextEdit;
615
+ /** Rich text editor (rich-text plugin; loaded on use). */
616
+ const $rich: ManifestRichText;
492
617
  /** Device/platform info (utilities; enriched by the device plugin). */
493
618
  const $device: ManifestDevice;
494
619
  /** Native share (device plugin). */
@@ -523,6 +648,14 @@ declare global {
523
648
  };
524
649
  Alpine?: unknown;
525
650
  __manifestLoaded?: unknown;
651
+ /** Rich text engine (rich-text plugin). */
652
+ ManifestRichText?: {
653
+ attach(el: Element, options?: ManifestRichTextAttachOptions): ManifestRichTextHandle | null;
654
+ toMarkdown(root: Element): string;
655
+ fromMarkdown(markdown: string): string;
656
+ sanitize(html: string, allowBlocks?: boolean, keepStyle?: boolean): string;
657
+ commands(): string[];
658
+ };
526
659
  }
527
660
 
528
661
  /**
@@ -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.233';
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
  });