Primitives / foldkit-primitives/interaction

EditableText

namespace · packages/primitives/src/interaction/editable-text.ts:7

export * as EditableText from './editable-text.js'

EditableText as a Behavior: attaches the foldkit-primitives/dom Mount to a container slot and maps what it reports into the view's Messages. No Bundle: the text typed is a fact, and what it changes is the parent's update.

Members

EditableText.behavior

function · packages/primitives/src/interaction/editable-text.ts:30

function behavior<Slots>(
  slots: Slots,
): <Input, ParentMessage>(
  options: BehaviorOptions<Slots, ParentMessage>,
) => Behavior.NamedBehavior<Slots, Input, ParentMessage>

EditableText.BehaviorOptions

interface · packages/primitives/src/interaction/editable-text.ts:21

interface BehaviorOptions<Slots, ParentMessage> {
  readonly container: keyof Slots & string
  readonly attribute: string
  readonly toMessage: (fact: TextFact) => ParentMessage
}

EditableText.EditAsked

const · packages/primitives/src/dom/editable-text.ts:24

const EditAsked: Schema.TaggedStruct<
  'EditAsked',
  { readonly field: Schema.String }
>

EditableText.mount

const · packages/primitives/src/dom/editable-text.ts:81

const mount: Mount.MountDefinitionWithArgs<
  'EditableText',
  { attribute: Schema.String },
  | {
      readonly _tag: 'TextEdited'
      readonly field: string
      readonly text: string
    }
  | {
      readonly _tag: 'TextCommitted'
      readonly field: string
      readonly text: string
    }
  | {
      readonly _tag: 'TextCancelled'
      readonly field: string
      readonly initial: string
    }
  | { readonly _tag: 'EditAsked'; readonly field: string }
>

Text typed into an editable descendant of an element, as a Mount: one set of listeners on the container, like Targets. A field is a descendant marked by an attribute whose value names it, while it is contenteditable. The view decides which one is; the Mount focuses it as it becomes so (made editable, or drawn editable), with the caret at its end, and at no other time. When Enter or Escape ends an edit and the view then removes the field or makes it no longer editable, focus, left on nothing, comes back to the container, so the next key reaches it; give the container a tabindex. A double-click on a marked field that is not editable yet asks for it to be (EditAsked).

It reads innerText, never innerHTML, so what arrives is text. A field is one line unless it carries aria-multiline="true": in one line, a line break becomes a space. Nothing is reported while an input method composes; the composed text arrives once, when it is done.

Enter commits (Shift+Enter breaks a line in a multiline field), and so does leaving the field. Escape cancels, and puts the text the field had when editing began back in the DOM, since a view that stopped redrawing the field while it was edited will not. Where the browser lacks plaintext-only, a paste is inserted as text. What an edit means is the parent's update.

EditableText.TextCancelled

const · packages/primitives/src/dom/editable-text.ts:17

const TextCancelled: Schema.TaggedStruct<
  'TextCancelled',
  { readonly field: Schema.String; readonly initial: Schema.String }
>

EditableText.TextCommitted

const · packages/primitives/src/dom/editable-text.ts:11

const TextCommitted: Schema.TaggedStruct<
  'TextCommitted',
  { readonly field: Schema.String; readonly text: Schema.String }
>

EditableText.TextEdited

const · packages/primitives/src/dom/editable-text.ts:4

const TextEdited: Schema.TaggedStruct<
  'TextEdited',
  { readonly field: Schema.String; readonly text: Schema.String }
>

EditableText.TextFact

type · packages/primitives/src/dom/editable-text.ts:30

type TextFact = TextEdited | TextCommitted | TextCancelled | EditAsked

EditableText.textOf

function · packages/primitives/src/dom/editable-text.ts:39

function textOf(element: HTMLElement): string

A field's text. A browser ends an edited element with a line break it adds itself, which is not the author's; in one line, the author's breaks are spaces.