foldkit-primitives 0.2.1 → 0.4.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/README.md +514 -43
- package/dist/device/index.d.mts +11 -11
- package/dist/device/index.d.mts.map +1 -1
- package/dist/device/index.mjs +95 -87
- package/dist/device/index.mjs.map +1 -1
- package/dist/dom/index.d.mts +71 -1
- package/dist/dom/index.d.mts.map +1 -1
- package/dist/dom/index.mjs +303 -5
- package/dist/dom/index.mjs.map +1 -1
- package/dist/editable-text-CKkS_mWt.d.mts +235 -0
- package/dist/editable-text-CKkS_mWt.d.mts.map +1 -0
- package/dist/events/index.d.mts +10 -1
- package/dist/events/index.d.mts.map +1 -1
- package/dist/events/index.mjs +34 -18
- package/dist/events/index.mjs.map +1 -1
- package/dist/follow-tab-stop-DpxwLXvU.mjs +800 -0
- package/dist/follow-tab-stop-DpxwLXvU.mjs.map +1 -0
- package/dist/index-Cppf-lBx.d.mts +130 -0
- package/dist/index-Cppf-lBx.d.mts.map +1 -0
- package/dist/index.d.mts +8 -6
- package/dist/index.mjs +8 -6
- package/dist/input-modality-DGOhAknO.d.mts +26 -0
- package/dist/input-modality-DGOhAknO.d.mts.map +1 -0
- package/dist/input-modality-m6v7__Xs.mjs +43 -0
- package/dist/input-modality-m6v7__Xs.mjs.map +1 -0
- package/dist/interaction/index.d.mts +1017 -0
- package/dist/interaction/index.d.mts.map +1 -0
- package/dist/interaction/index.mjs +1647 -0
- package/dist/interaction/index.mjs.map +1 -0
- package/dist/internal-DP-xLKbT.mjs +37 -0
- package/dist/internal-DP-xLKbT.mjs.map +1 -0
- package/dist/media/index.d.mts.map +1 -1
- package/dist/media/index.mjs +3 -3
- package/dist/media/index.mjs.map +1 -1
- package/dist/motion/index.d.mts +2 -112
- package/dist/motion/index.mjs +2 -208
- package/dist/motion-DGGBZ0wt.mjs +240 -0
- package/dist/motion-DGGBZ0wt.mjs.map +1 -0
- package/dist/net/index.d.mts +68 -4
- package/dist/net/index.d.mts.map +1 -1
- package/dist/net/index.mjs +139 -56
- package/dist/net/index.mjs.map +1 -1
- package/dist/observers/index.d.mts +1 -1
- package/dist/observers/index.mjs +3 -0
- package/dist/observers/index.mjs.map +1 -1
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/dist/state/index.d.mts +57 -15
- package/dist/state/index.d.mts.map +1 -1
- package/dist/state/index.mjs +198 -90
- package/dist/state/index.mjs.map +1 -1
- package/dist/time/index.d.mts +21 -1
- package/dist/time/index.d.mts.map +1 -1
- package/dist/time/index.mjs +48 -19
- package/dist/time/index.mjs.map +1 -1
- package/package.json +31 -8
- package/dist/motion/index.d.mts.map +0 -1
- package/dist/motion/index.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["Layer","Model","Message","bundle","behavior","behavior","EditableTextMount","behavior","FocusScopeMount","behavior","Model","Message","Args","bundle","isPlain","move","tabStop","behavior","Model","Message","Args","bundle","move","behavior","RovingTabindex.tabStop","RovingTabindex.idSelector","RovingTabindex.itemAttributes","ScrollLockMount","HideOutsideMount","Model","Message","Args","bundle","Model","Message","Args","bundle","behavior","Model","Message","Args","RovingTabindex.Orientation","bundle","RovingTabindex.move","Typeahead.isPrintable","Typeahead.match","behavior","RovingTabindex.tabStop","RovingTabindex.idSelector","RovingTabindex.itemAttributes","Model","Message","Args","isActivationKey","bundle","behavior","Model","Message","Press.PointerType","Args","bundle","behavior","Press.events","behavior","MoveMount","Model","Message","Args","bundle","behavior","behavior","TargetsMount","behavior","PointerDragMount"],"sources":["../../src/interaction/dismiss-layer.ts","../../src/interaction/editable-text.ts","../../src/interaction/focus-scope.ts","../../src/interaction/focus-visible.ts","../../src/interaction/roving-tabindex.ts","../../src/interaction/grid-navigation.ts","../../src/interaction/layers.ts","../../src/interaction/live-announce.ts","../../src/interaction/typeahead.ts","../../src/interaction/list-navigation.ts","../../src/interaction/press.ts","../../src/interaction/long-press.ts","../../src/interaction/move.ts","../../src/interaction/selection.ts","../../src/interaction/targets.ts","../../src/interaction/pointer-drag.ts","../../src/interaction/tree-navigation.ts"],"sourcesContent":["/**\n * Dismissable layers: Escape closes the topmost open layer, a pointer press\n * outside closes the layers it is outside of. One Bundle, placed once, owns\n * the document listeners; each layer's Behavior marks its container (and its\n * trigger) with data attributes. The stack is the DOM order of the marked\n * elements at the moment of the event, so a layer opening or closing needs no\n * registration. A press inside a parent layer is outside its children, so the\n * parent stays and the children go; a press on a layer's trigger counts as\n * inside it, so a trigger never dismisses and reopens in one click. What a\n * dismissal does is the placement's `onOut`.\n */\nimport { Effect, Queue, Schema, Stream } from 'effect'\nimport type { HtmlBuilder } from 'foldkit/html'\nimport { defineMessageUnion } from 'foldkit/message'\nimport * as Subscription from 'foldkit/subscription'\nimport type * as Update from 'foldkit/update'\nimport { Bundle, type Declared } from 'foldkit-bundle'\nimport { Behavior, Capability } from 'foldkit-mixins'\n\nexport const LAYER_ATTRIBUTE = 'data-foldkit-plus-layer'\nexport const TRIGGER_ATTRIBUTE = 'data-foldkit-plus-layer-trigger'\nconst OUTSIDE_ATTRIBUTE = 'data-foldkit-plus-layer-outside'\nconst ESCAPE_ATTRIBUTE = 'data-foldkit-plus-layer-escape'\n\n/** An open layer as the document showed it: bottom to top is DOM order. */\nexport const Layer = Schema.Struct({\n id: Schema.String,\n /** Dismiss on a press outside it. */\n outside: Schema.Boolean,\n /** Dismiss on Escape when topmost. */\n escape: Schema.Boolean,\n})\nexport type Layer = typeof Layer.Type\n\nexport const Model = Schema.Struct({\n /** The open layers at the last event, bottom to top. */\n layers: Schema.Array(Layer),\n})\nexport type Model = typeof Model.Type\n\nexport const Message = defineMessageUnion({\n /** A pointer went down; `inside` are the layers whose element or trigger was on the event's path. */\n PressedAt: { layers: Schema.Array(Layer), inside: Schema.Array(Schema.String) },\n PressedEscape: { layers: Schema.Array(Layer) },\n})\nexport type Message = typeof Message.Type\n\nexport const Dismiss = Schema.TaggedStruct('Dismiss', { ids: Schema.Array(Schema.String) })\nexport type Dismiss = typeof Dismiss.Type\n\n/** Which layers a press inside `inside` dismisses: every layer above the topmost one hit, or all when none was. */\nexport const toDismiss = (\n layers: ReadonlyArray<Layer>,\n inside: ReadonlyArray<string>,\n): ReadonlyArray<string> => {\n let topmostHit = -1\n layers.forEach((layer, index) => {\n if (inside.includes(layer.id)) topmostHit = index\n })\n return layers\n .slice(topmostHit + 1)\n .filter(layer => layer.outside)\n .map(layer => layer.id)\n}\n\ntype Return = Update.ReturnWithOutMessage<Model, Message, Dismiss>\n\nconst sameLayers = (a: ReadonlyArray<Layer>, b: ReadonlyArray<Layer>): boolean =>\n a.length === b.length &&\n a.every(\n (layer, index) =>\n layer.id === b[index]!.id &&\n layer.outside === b[index]!.outside &&\n layer.escape === b[index]!.escape,\n )\n\nexport const bundle = Bundle.make('DismissLayer', {\n Model,\n Message,\n init: () => ({ model: { layers: [] } }),\n update: (model, message): Return => {\n // Every press in the document reports the layers, which are usually the\n // ones already held: keep the Model, or each click re-renders the page.\n const next = sameLayers(model.layers, message.layers) ? model : { layers: message.layers }\n return Message.match<Return>(message, {\n PressedAt: ({ layers, inside }) => {\n const ids = toDismiss(layers, inside)\n return ids.length === 0\n ? { model: next }\n : { model: next, outMessage: Dismiss.make({ ids }) }\n },\n PressedEscape: ({ layers }) => {\n const top = layers[layers.length - 1]\n return top !== undefined && top.escape\n ? { model: next, outMessage: Dismiss.make({ ids: [top.id] }) }\n : { model: next }\n },\n })\n },\n subscriptions: () =>\n Subscription.make<Model, Message>()(() => ({\n document: Subscription.persistent(documentEvents()),\n })),\n})\n\nconst openLayers = (root: ParentNode): ReadonlyArray<Layer> =>\n Array.from(root.querySelectorAll(`[${LAYER_ATTRIBUTE}]`)).map(element => ({\n id: element.getAttribute(LAYER_ATTRIBUTE) ?? '',\n outside: element.getAttribute(OUTSIDE_ATTRIBUTE) !== 'false',\n escape: element.getAttribute(ESCAPE_ATTRIBUTE) !== 'false',\n }))\n\n/** The layer ids whose element or trigger is on the event's composed path. */\nexport const layersOnPath = (path: ReadonlyArray<EventTarget>): ReadonlyArray<string> => {\n const ids: Array<string> = []\n for (const target of path) {\n if (!(target instanceof Element)) continue\n const id = target.getAttribute(LAYER_ATTRIBUTE) ?? target.getAttribute(TRIGGER_ATTRIBUTE)\n if (id !== null && !ids.includes(id)) ids.push(id)\n }\n return ids\n}\n\n/**\n * The facts are read inside the listener, not after: `composedPath()` is\n * empty once dispatch has finished, and the open layers must be the ones the\n * press saw, not the ones a later render left.\n */\nconst documentEvents = (): Stream.Stream<Message> => {\n if (typeof document === 'undefined') return Stream.empty\n return Stream.callback<Message>(queue =>\n Effect.acquireRelease(\n Effect.sync(() => {\n const onPointerDown = (event: Event) =>\n Queue.offerUnsafe(\n queue,\n Message.PressedAt({\n layers: openLayers(document),\n inside: layersOnPath(event.composedPath()),\n }),\n )\n const onKeyDown = (event: Event) => {\n if ((event as KeyboardEvent).key !== 'Escape') return\n Queue.offerUnsafe(queue, Message.PressedEscape({ layers: openLayers(document) }))\n }\n document.addEventListener('pointerdown', onPointerDown, { capture: true })\n document.addEventListener('keydown', onKeyDown, { capture: true })\n return { onPointerDown, onKeyDown }\n }),\n ({ onPointerDown, onKeyDown }) =>\n Effect.sync(() => {\n document.removeEventListener('pointerdown', onPointerDown, { capture: true })\n document.removeEventListener('keydown', onKeyDown, { capture: true })\n }),\n ),\n )\n}\n\nexport interface BehaviorOptions<Input, Slots> {\n /** The layer's root, rendered only while the layer is open. */\n readonly layer: keyof Slots & string\n /** The element that opens the layer, so a press on it is inside. */\n readonly trigger?: keyof Slots & string\n readonly id: (input: Input) => string\n /** Dismiss on a press outside. Default `true`. */\n readonly outsidePress?: boolean\n /** Dismiss on Escape when topmost. Default `true`. */\n readonly escape?: boolean\n}\n\n/**\n * Marks the layer's container and trigger for the placed stack. The layer\n * takes part only while its element is rendered, so an `open` flag in the\n * parent Model is the whole lifecycle. Not for an element with `popover`,\n * which the browser dismisses itself.\n */\nexport const behavior =\n <Field extends string>(_declared: Declared<typeof bundle, Field>) =>\n <Slots>(slots: Slots) =>\n <Input, ParentMessage>(\n options: BehaviorOptions<Input, Slots>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.layer]: Behavior.slot({\n requires: { capability: Capability.Container },\n attributes: ({\n input,\n h,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n }) => [\n h.Attribute(LAYER_ATTRIBUTE, options.id(input)),\n ...(options.outsidePress === false ? [h.Attribute(OUTSIDE_ATTRIBUTE, 'false')] : []),\n ...(options.escape === false ? [h.Attribute(ESCAPE_ATTRIBUTE, 'false')] : []),\n ],\n }),\n ...(options.trigger === undefined\n ? {}\n : {\n [options.trigger]: Behavior.slot({\n requires: { capability: Capability.Interactive },\n attributes: ({\n input,\n h,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n }) => [h.Attribute(TRIGGER_ATTRIBUTE, options.id(input))],\n }),\n }),\n // Keyed by values the caller chose; `forSlots` checks the keys exist.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'DismissLayer' },\n )\n","/**\n * `EditableText` as a Behavior: attaches the `foldkit-primitives/dom` Mount to\n * a container slot and maps what it reports into the view's Messages. No\n * Bundle: the text typed is a fact, and what it changes is the parent's\n * `update`.\n */\nimport * as Mount from 'foldkit/mount'\nimport { Behavior, Capability } from 'foldkit-mixins'\nimport { EditableText as EditableTextMount, type TextFact } from '../dom/editable-text.js'\n\nexport {\n EditAsked,\n EditableText as mount,\n TextCancelled,\n TextCommitted,\n TextEdited,\n textOf,\n type TextFact,\n} from '../dom/editable-text.js'\n\nexport interface BehaviorOptions<Slots, ParentMessage> {\n /** The slot holding the fields. */\n readonly container: keyof Slots & string\n /** The attribute that marks a field, holding its name. */\n readonly attribute: string\n /** Turns each fact into the view's Message. */\n readonly toMessage: (fact: TextFact) => ParentMessage\n}\n\nexport const behavior =\n <Slots>(slots: Slots) =>\n <Input, ParentMessage>(\n options: BehaviorOptions<Slots, ParentMessage>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.container]: Behavior.slot({\n requires: { capability: Capability.Container },\n mount: () =>\n Mount.mapMessage(\n EditableTextMount({ attribute: options.attribute }),\n options.toMessage,\n ),\n }),\n // Keyed by a value the caller chose; `forSlots` checks the key exists.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'EditableText' },\n )\n","/**\n * `FocusScope` as a Behavior: attaches the `foldkit-primitives/dom` Mount to a\n * container slot. No Bundle, because which element has focus is a DOM fact.\n */\nimport { Behavior, Capability } from 'foldkit-mixins'\nimport { FocusScope as FocusScopeMount } from '../dom/focus-scope.js'\n\nexport { FocusScope as mount, tabbableWithin } from '../dom/focus-scope.js'\n\nexport interface BehaviorOptions<Slots> {\n readonly container: keyof Slots & string\n /** Keep Tab, Shift+Tab, and a stray focus inside. Default `true`. */\n readonly contain?: boolean\n /** Give focus back to what had it when the container unmounts. Default `true`. */\n readonly restore?: boolean\n /** A selector inside the container to focus first. */\n readonly initialFocus?: string\n}\n\n/**\n * On insert the container focuses `initialFocus`, else its first tabbable\n * descendant, else itself; with `contain`, Tab and Shift+Tab wrap inside and\n * focus that lands outside comes back to the first tabbable; on unmount, with\n * `restore`, focus returns to the element that had it. A dialog that is not\n * a native `<dialog>`, a menu, or a command palette takes this.\n */\nexport const behavior =\n <Slots>(slots: Slots) =>\n <Input, ParentMessage>(\n options: BehaviorOptions<Slots>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.container]: Behavior.slot({\n requires: { capability: Capability.Container },\n mount: () =>\n FocusScopeMount({\n contain: options.contain ?? true,\n restore: options.restore ?? true,\n initialFocus: options.initialFocus ?? null,\n }),\n }),\n // Keyed by a value the caller chose; `forSlots` checks the key exists.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'FocusScope' },\n )\n","/**\n * `FocusVisible` as a Behavior over a placed `InputModality`: the target gets\n * `data-focus-visible` while the page is being driven by keyboard, so a\n * stylesheet can show a ring with `[data-focus-visible]:focus` and hide it\n * for pointer users. CSS `:focus-visible` does this without any of it; this\n * is for a design system that must decide in the Model.\n */\nimport type { HtmlBuilder } from 'foldkit/html'\nimport type { Declared } from 'foldkit-bundle'\nimport { Behavior, Capability } from 'foldkit-mixins'\nimport { InputModality, type InputModalityModel } from '../events/input-modality.js'\n\nexport { InputModality as bundle, Modality, modalityOfKey } from '../events/input-modality.js'\nexport type { InputModalityModel as Model } from '../events/input-modality.js'\n\nexport interface BehaviorOptions<Slots> {\n readonly target: keyof Slots & string\n}\n\nexport const behavior =\n <Field extends string>(declared: Declared<typeof InputModality, Field>) =>\n <Slots>(slots: Slots) =>\n <Input extends { readonly [K in Field]: InputModalityModel }, ParentMessage>(\n options: BehaviorOptions<Slots>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.target]: Behavior.slot({\n requires: { capability: Capability.Focusable },\n attributes: ({\n input,\n h,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n }) =>\n input[declared.field].modality === 'keyboard'\n ? [h.DataAttribute('focus-visible', 'true')]\n : [],\n }),\n // Keyed by a value the caller chose; `forSlots` checks the key exists.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'FocusVisible' },\n )\n","/**\n * One tab stop for a set of items (a toolbar, a tab list, a listbox): arrows\n * move focus between them, the rest stay out of the tab order. The current\n * item's id is the Model slice, so a reorder keeps the same item current and a\n * resumed page knows where focus was. Which item comes next is a pure\n * function of the items and the key; the Behavior wires it to the slots.\n */\nimport { Option, Schema } from 'effect'\nimport type { Attribute, HtmlBuilder, KeyboardModifiers } from 'foldkit/html'\nimport { defineMessageUnion } from 'foldkit/message'\nimport { Bundle } from 'foldkit-bundle'\nimport { Behavior, Behaviors, Capability, type SlotItem } from 'foldkit-mixins'\nimport type { Declared } from 'foldkit-bundle'\nimport { perInput } from '../internal.js'\n\nexport const Orientation = Schema.Literals(['vertical', 'horizontal', 'both'])\nexport type Orientation = typeof Orientation.Type\n\nexport const Model = Schema.Struct({\n /** The current item's id, or `null` before any item has been focused. */\n current: Schema.NullOr(Schema.String),\n})\nexport type Model = typeof Model.Type\n\nexport const Message = defineMessageUnion({\n /** An item became current: the user focused it, or a key moved there. */\n Focused: { id: Schema.String },\n})\nexport type Message = typeof Message.Type\n\nexport const Args = Schema.Struct({\n orientation: Orientation,\n /** Wrap from the last enabled item to the first, and back. */\n loop: Schema.Boolean,\n /** Keep DOM focus on the container and point at the current item with\n * `aria-activedescendant` instead of moving focus. */\n virtual: Schema.Boolean,\n})\nexport type Args = typeof Args.Type\n\nexport const bundle = Bundle.make('RovingTabindex', {\n Model,\n Message,\n args: Args,\n init: () => ({ model: { current: null } }),\n // Moving focus by key dispatches `Focused`, and the item's `OnFocus` reports it again.\n update: (model, message) =>\n model.current === message.id ? { model } : { model: { current: message.id } },\n})\n\nexport type Direction = 'ltr' | 'rtl'\n\nexport interface MoveOptions {\n readonly orientation: Orientation\n readonly loop: boolean\n readonly direction: Direction\n /** How many enabled items PageUp and PageDown move; absent, they are not handled. */\n readonly page?: number\n}\n\nconst isPlain = (modifiers: KeyboardModifiers): boolean =>\n !modifiers.ctrlKey && !modifiers.altKey && !modifiers.metaKey\n\n/**\n * The index the key moves to from `current`, over the enabled indices only, or\n * `undefined` when the key is not a navigation key here. `current` may be\n * `-1` (nothing current yet): arrows then land on the first or last enabled\n * item. Under `rtl`, left and right swap. PageUp and PageDown move by `page`\n * and clamp at the ends, never wrapping.\n */\nexport const move = (\n enabled: ReadonlyArray<number>,\n current: number,\n key: string,\n modifiers: KeyboardModifiers,\n options: MoveOptions,\n): number | undefined => {\n if (enabled.length === 0 || !isPlain(modifiers)) return undefined\n const first = enabled[0]!\n const last = enabled[enabled.length - 1]!\n if (key === 'Home') return first\n if (key === 'End') return last\n if (options.page !== undefined && (key === 'PageUp' || key === 'PageDown')) {\n const position = enabled.indexOf(current)\n if (position === -1) return key === 'PageDown' ? first : last\n const jumped = position + (key === 'PageDown' ? options.page : -options.page)\n return enabled[Math.min(enabled.length - 1, Math.max(0, jumped))]\n }\n const vertical = options.orientation !== 'horizontal'\n const horizontal = options.orientation !== 'vertical'\n const forwardKey = options.direction === 'rtl' ? 'ArrowLeft' : 'ArrowRight'\n const backwardKey = options.direction === 'rtl' ? 'ArrowRight' : 'ArrowLeft'\n const step =\n (vertical && key === 'ArrowDown') || (horizontal && key === forwardKey)\n ? 1\n : (vertical && key === 'ArrowUp') || (horizontal && key === backwardKey)\n ? -1\n : 0\n if (step === 0) return undefined\n const position = enabled.indexOf(current)\n if (position === -1) return step === 1 ? first : last\n const next = position + step\n if (next < 0) return options.loop ? last : first\n if (next >= enabled.length) return options.loop ? first : last\n return enabled[next]\n}\n\n/** The item that holds the tab stop: the current one, else the first enabled. */\nexport const tabStop = (\n items: Behaviors.Collection.Items<unknown>,\n current: string | null,\n): number => {\n const index = current === null ? -1 : items.indexOf(current)\n if (index !== -1 && !items.isDisabled(index)) return index\n return items.enabled[0] ?? -1\n}\n\nexport interface BehaviorOptions<Input, Slots> {\n /** The slot that receives the arrow keys. */\n readonly container: keyof Slots & string\n /** The slot rendered once per item; must carry the item's id (see `Behaviors.Collection`). */\n readonly item: keyof Slots & string\n readonly items: (input: Input) => Behaviors.Collection.Items<unknown>\n /** Default `'ltr'`; return `'rtl'` to swap left and right. */\n readonly direction?: (input: Input) => Direction\n}\n\n/** A selector for an element by id, safe for any id. */\nexport const idSelector = (id: string): string => `[id=\"${id.replace(/[\"\\\\]/g, '\\\\$&')}\"]`\n\n/**\n * The attributes one item gets: `tabindex` 0 when it holds the tab stop and\n * -1 otherwise (none under `virtual`), and `OnFocus` reporting it current.\n * Shared with `ListNavigation`.\n */\nexport const itemAttributes = <ParentMessage>(\n h: HtmlBuilder<ParentMessage>,\n items: Behaviors.Collection.Items<unknown>,\n current: string | null,\n item: SlotItem,\n virtual: boolean,\n focused: (id: string) => ParentMessage,\n): ReadonlyArray<Attribute<ParentMessage>> => {\n const id = item.id ?? items.ids[item.index]\n if (id === undefined) return []\n const isStop = tabStop(items, current) === item.index\n return [...(virtual ? [] : [h.Tabindex(isStop ? 0 : -1)]), h.OnFocus(focused(id))]\n}\n\n/**\n * Wires a placed `RovingTabindex` to the slots: the container's arrow, Home\n * and End keys focus the next item (synchronously, then dispatch), each item\n * gets `tabindex` 0 or -1 and reports `Focused` when focused. Under `virtual`\n * DOM focus never leaves the container: the key only dispatches, the\n * container carries `aria-activedescendant`, and items keep no `tabindex`.\n *\n * Every handled key is default-prevented. Nothing is written on dispose: the\n * attributes are data, so a view that no longer attaches this leaves no\n * `tabindex` behind.\n */\nexport const behavior =\n <Field extends string>(declared: Declared<typeof bundle, Field>, args: Args) =>\n <Slots>(slots: Slots) =>\n <Input extends { readonly [K in Field]: Model }, ParentMessage>(\n options: BehaviorOptions<Input, Slots>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> => {\n const wrap = (id: string): ParentMessage =>\n declared.wrapper.make(Message.Focused({ id })) as unknown as ParentMessage\n const slice = (input: Input): Model => input[declared.field]\n const itemsOf = perInput(options.items)\n return Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.container]: Behavior.slot({\n requires: { capability: Capability.Interactive },\n attributes: ({\n input,\n h,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n }) => {\n const items = itemsOf(input)\n const current = slice(input).current\n const from = current === null ? -1 : items.indexOf(current)\n const direction = options.direction?.(input) ?? 'ltr'\n const stop = tabStop(items, current)\n const stopId = stop === -1 ? undefined : items.ids[stop]\n const target = (key: string, modifiers: KeyboardModifiers): string | undefined => {\n const next = move(items.enabled, from, key, modifiers, { ...args, direction })\n return next === undefined ? undefined : items.ids[next]\n }\n // Virtual: DOM focus stays on the container, only the pointer moves.\n if (args.virtual) {\n return [\n h.OnKeyDownPreventDefault((key, modifiers) =>\n Option.map(Option.fromNullishOr(target(key, modifiers)), wrap),\n ),\n ...(stopId === undefined ? [] : [h.AriaActiveDescendant(stopId)]),\n ]\n }\n return [\n h.OnKeyDownFocus((key, modifiers) =>\n Option.map(Option.fromNullishOr(target(key, modifiers)), id => ({\n focusSelector: idSelector(id),\n message: wrap(id),\n })),\n ),\n ]\n },\n }),\n [options.item]: Behavior.slot({\n requires: { capability: Capability.Focusable },\n attributes: ({\n input,\n h,\n item,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n readonly item?: SlotItem\n }) => {\n if (item === undefined) return []\n return itemAttributes(h, itemsOf(input), slice(input).current, item, args.virtual, wrap)\n },\n }),\n // Keyed by values the caller chose; `forSlots` checks both keys exist.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'RovingTabindex' },\n )\n }\n","/**\n * Two-dimensional arrow keys over a set of items laid out in rows of\n * `columns` (a calendar grid, a color swatch picker, an emoji palette). The\n * Model slice is the current item's id, as with `RovingTabindex`, so a\n * reorder keeps the same item current. Which cell a key lands on is the pure\n * `move`; the Behavior wires it to a container slot and a per-item slot and\n * shares `RovingTabindex`'s item attributes, so the two are interchangeable\n * on a view.\n */\nimport { Option, Schema } from 'effect'\nimport type { HtmlBuilder, KeyboardModifiers } from 'foldkit/html'\nimport { defineMessageUnion } from 'foldkit/message'\nimport { Bundle, type Declared } from 'foldkit-bundle'\nimport { Behavior, Behaviors, Capability, type SlotItem } from 'foldkit-mixins'\nimport * as RovingTabindex from './roving-tabindex.js'\nimport { perInput } from '../internal.js'\n\nexport const Model = Schema.Struct({\n /** The current cell's id, or `null` before any cell has been focused. */\n current: Schema.NullOr(Schema.String),\n})\nexport type Model = typeof Model.Type\n\nexport const Message = defineMessageUnion({\n /** A cell became current: the user focused it, or a key moved there. */\n Focused: { id: Schema.String },\n})\nexport type Message = typeof Message.Type\n\nexport const Args = Schema.Struct({\n /** Cells per row; the last row may be short. */\n columns: Schema.Number.pipe(Schema.check(Schema.isGreaterThanOrEqualTo(1))),\n /** Left and right continue into the previous and next row; up and down\n * continue into the previous and next column. Off, they stop at the edge. */\n wrap: Schema.Boolean,\n /** Keep DOM focus on the container and point at the current cell with\n * `aria-activedescendant` instead of moving focus. */\n virtual: Schema.Boolean,\n})\nexport type Args = typeof Args.Type\n\nexport const bundle = Bundle.make('GridNavigation', {\n Model,\n Message,\n args: Args,\n init: () => ({ model: { current: null } }),\n // Moving focus by key dispatches `Focused`, and the cell's `OnFocus` reports it again.\n update: (model, message) =>\n model.current === message.id ? { model } : { model: { current: message.id } },\n})\n\nexport interface MoveOptions {\n readonly columns: number\n readonly wrap: boolean\n readonly direction: RovingTabindex.Direction\n}\n\n/**\n * The index the key moves to from `current` over a grid of `count` cells in\n * rows of `columns`, skipping cells not in `enabled`, or `undefined` when the\n * key is not a grid key. Left and right step within the row, and across rows\n * under `wrap`; up and down step within the column, and across columns under\n * `wrap`. Home and End are the row's first and last enabled cell; with Ctrl\n * they are the grid's. At an edge without `wrap` the key is consumed and\n * `current` is returned. From `-1` (nothing current) a forward key lands on\n * the first enabled cell and a backward key on the last. Under `rtl`, left\n * and right swap.\n */\nexport const move = (\n enabled: ReadonlyArray<number>,\n count: number,\n current: number,\n key: string,\n modifiers: KeyboardModifiers,\n options: MoveOptions,\n): number | undefined => {\n if (enabled.length === 0 || modifiers.altKey || modifiers.metaKey) return undefined\n const first = enabled[0]!\n const last = enabled[enabled.length - 1]!\n const isEnabled = (index: number) => enabled.includes(index)\n const { columns } = options\n const row = (index: number) => Math.floor(index / columns)\n\n if (key === 'Home' || key === 'End') {\n if (modifiers.ctrlKey || current === -1) return key === 'Home' ? first : last\n const inRow = enabled.filter(index => row(index) === row(current))\n return key === 'Home' ? (inRow[0] ?? current) : (inRow[inRow.length - 1] ?? current)\n }\n if (modifiers.ctrlKey) return undefined\n\n const forwardKey = options.direction === 'rtl' ? 'ArrowLeft' : 'ArrowRight'\n const backwardKey = options.direction === 'rtl' ? 'ArrowRight' : 'ArrowLeft'\n const axis: 'row' | 'column' | undefined =\n key === forwardKey || key === backwardKey\n ? 'row'\n : key === 'ArrowDown' || key === 'ArrowUp'\n ? 'column'\n : undefined\n if (axis === undefined) return undefined\n const step = key === forwardKey || key === 'ArrowDown' ? 1 : -1\n if (current === -1) return step === 1 ? first : last\n\n if (axis === 'row') {\n // Reading order; without wrap the walk stops at the row's edge.\n for (let index = current + step; index >= 0 && index < count; index += step) {\n if (!options.wrap && row(index) !== row(current)) return current\n if (isEnabled(index)) return index\n }\n return current\n }\n // Column-major; without wrap the walk stops at the column's edge.\n const column = current % columns\n for (let index = current + step * columns; ; index += step * columns) {\n if (index < 0 || index >= count) {\n if (!options.wrap) return current\n const nextColumn = column + step\n if (nextColumn < 0 || nextColumn >= columns) return current\n // Continue from the top (or bottom) of the neighbouring column.\n const start =\n step === 1\n ? nextColumn\n : nextColumn + columns * Math.floor((count - 1 - nextColumn) / columns)\n for (let next = start; next >= 0 && next < count; next += step * columns) {\n if (isEnabled(next)) return next\n }\n return current\n }\n if (isEnabled(index)) return index\n }\n}\n\nexport interface BehaviorOptions<Input, Slots> {\n /** The slot that receives the arrow keys. */\n readonly container: keyof Slots & string\n /** The slot rendered once per cell; must carry the cell's id (see `Behaviors.Collection`). */\n readonly item: keyof Slots & string\n readonly items: (input: Input) => Behaviors.Collection.Items<unknown>\n /** Default `'ltr'`; return `'rtl'` to swap left and right. */\n readonly direction?: (input: Input) => RovingTabindex.Direction\n}\n\n/**\n * Wires a placed `GridNavigation` to the slots exactly as `RovingTabindex`\n * does, with `move` above deciding the cell: the container's arrows, Home and\n * End focus the next cell (synchronously, then dispatch) or, under `virtual`,\n * only dispatch and point with `aria-activedescendant`; each cell gets\n * `tabindex` 0 or -1 and reports `Focused` when focused.\n */\nexport const behavior =\n <Field extends string>(declared: Declared<typeof bundle, Field>, args: Args) =>\n <Slots>(slots: Slots) =>\n <Input extends { readonly [K in Field]: Model }, ParentMessage>(\n options: BehaviorOptions<Input, Slots>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> => {\n const wrap = (id: string): ParentMessage =>\n declared.wrapper.make(Message.Focused({ id })) as unknown as ParentMessage\n const slice = (input: Input): Model => input[declared.field]\n const itemsOf = perInput(options.items)\n return Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.container]: Behavior.slot({\n requires: { capability: Capability.Interactive },\n attributes: ({\n input,\n h,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n }) => {\n const items = itemsOf(input)\n const current = slice(input).current\n const from = current === null ? -1 : items.indexOf(current)\n const direction = options.direction?.(input) ?? 'ltr'\n const stop = RovingTabindex.tabStop(items, current)\n const stopId = stop === -1 ? undefined : items.ids[stop]\n const target = (key: string, modifiers: KeyboardModifiers): string | undefined => {\n const next = move(items.enabled, items.size, from, key, modifiers, {\n columns: args.columns,\n wrap: args.wrap,\n direction,\n })\n return next === undefined ? undefined : items.ids[next]\n }\n if (args.virtual) {\n return [\n h.OnKeyDownPreventDefault((key, modifiers) =>\n Option.map(Option.fromNullishOr(target(key, modifiers)), wrap),\n ),\n ...(stopId === undefined ? [] : [h.AriaActiveDescendant(stopId)]),\n ]\n }\n return [\n h.OnKeyDownFocus((key, modifiers) =>\n Option.map(Option.fromNullishOr(target(key, modifiers)), id => ({\n focusSelector: RovingTabindex.idSelector(id),\n message: wrap(id),\n })),\n ),\n ]\n },\n }),\n [options.item]: Behavior.slot({\n requires: { capability: Capability.Focusable },\n attributes: ({\n input,\n h,\n item,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n readonly item?: SlotItem\n }) => {\n if (item === undefined) return []\n return RovingTabindex.itemAttributes(\n h,\n itemsOf(input),\n slice(input).current,\n item,\n args.virtual,\n wrap,\n )\n },\n }),\n // Keyed by values the caller chose; `forSlots` checks both keys exist.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'GridNavigation' },\n )\n }\n","/**\n * `ScrollLock` and `HideOutside` as Behaviors: each attaches its\n * `foldkit-primitives/dom` Mount to a container slot. No Bundle, because the\n * lock and the inert set are document facts Foldkit already refcounts and\n * keys.\n */\nimport type { MountAction } from 'foldkit/mount'\nimport { Behavior, Capability } from 'foldkit-mixins'\nimport { HideOutside as HideOutsideMount, ScrollLock as ScrollLockMount } from '../dom/layers.js'\n\nexport { HideOutside as hideOutsideMount, ScrollLock as scrollLockMount } from '../dom/layers.js'\n\nconst mountOn =\n (name: string, mount: () => MountAction<never>) =>\n <Slots>(slots: Slots) =>\n <Input, ParentMessage>(options: {\n readonly container: keyof Slots & string\n }): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.container]: Behavior.slot({\n requires: { capability: Capability.Container },\n mount,\n }),\n // Keyed by a value the caller chose; `forSlots` checks the key exists.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name },\n )\n\n/** Locks the document's scroll while the container is mounted; nested locks release together. */\nexport const scrollLock = mountOn('ScrollLock', () => ScrollLockMount())\n\n/** Marks everything outside the container inert while it is mounted. */\nexport const hideOutside = mountOn('HideOutside', () => HideOutsideMount())\n","/**\n * Announcements for assistive technology: one Bundle, placed once, holds the\n * text of a polite and an assertive live region. An announcement waits\n * `debounceMs` so a burst reads once, then clears after `clearAfterMs`, both\n * on Effect's clock with a generation so a superseded timer changes nothing.\n * The same text twice gets a trailing no-break space toggled, which is what\n * makes a screen reader read it again. `view` renders the two regions; put it\n * once in the page and style them visually hidden.\n */\nimport { Effect, Schema } from 'effect'\nimport type { Html, HtmlBuilder } from 'foldkit/html'\nimport { defineMessageUnion } from 'foldkit/message'\nimport type * as Update from 'foldkit/update'\nimport { Bundle, type Declared } from 'foldkit-bundle'\n\nexport const Politeness = Schema.Literals(['polite', 'assertive'])\nexport type Politeness = typeof Politeness.Type\n\nexport const Model = Schema.Struct({\n polite: Schema.String,\n assertive: Schema.String,\n /** Waiting for the debounce to read. */\n pending: Schema.NullOr(Schema.Struct({ message: Schema.String, politeness: Politeness })),\n generation: Schema.Number,\n})\nexport type Model = typeof Model.Type\n\nexport const Message = defineMessageUnion({\n Announced: { message: Schema.String, politeness: Politeness },\n Read: { generation: Schema.Number },\n Cleared: { generation: Schema.Number },\n})\nexport type Message = typeof Message.Type\n\nconst positive = Schema.Number.pipe(\n Schema.check(Schema.isGreaterThanOrEqualTo(0)),\n Schema.check(Schema.isFinite()),\n)\n\nexport const Args = Schema.Struct({\n /** A burst of announcements inside this window reads once, the last one. */\n debounceMs: positive,\n /** How long the text stays in the region. */\n clearAfterMs: positive,\n})\nexport type Args = typeof Args.Type\n\nconst NBSP = ' '\n\n/** The text to put in the region so that `next` is read even when it equals `current`. */\nexport const reread = (current: string, next: string): string =>\n current === next ? `${next}${NBSP}` : current === `${next}${NBSP}` ? next : next\n\ntype Return = Update.Return<Model, Message>\n\nconst after = (ms: number, message: Message, name: string, generation: number) => ({\n name,\n args: { generation },\n effect: Effect.as(Effect.sleep(ms), message),\n})\n\nexport const bundle = Bundle.make('LiveAnnounce', {\n Model,\n Message,\n args: Args,\n init: () => ({ model: { polite: '', assertive: '', pending: null, generation: 0 } }),\n update: (model, message, args): Return =>\n Message.match<Return>(message, {\n Announced: ({ message: text, politeness }) => {\n const generation = model.generation + 1\n return {\n model: { ...model, pending: { message: text, politeness }, generation },\n commands: [\n after(args.debounceMs, Message.Read({ generation }), 'LiveAnnounce.read', generation),\n ],\n }\n },\n Read: ({ generation }) => {\n if (generation !== model.generation || model.pending === null) return { model }\n const { message: text, politeness } = model.pending\n const region = politeness === 'polite' ? 'polite' : 'assertive'\n return {\n model: { ...model, pending: null, [region]: reread(model[region], text) },\n commands: [\n after(\n args.clearAfterMs,\n Message.Cleared({ generation }),\n 'LiveAnnounce.clear',\n generation,\n ),\n ],\n }\n },\n Cleared: ({ generation }) =>\n generation === model.generation\n ? { model: { ...model, polite: '', assertive: '' } }\n : { model },\n }),\n})\n\n/** The parent Message that announces `text`, to return from `update` or `onOut`. */\nexport const say =\n <Field extends string>(declared: Declared<typeof bundle, Field>) =>\n <ParentMessage>(text: string, politeness: Politeness = 'polite'): ParentMessage =>\n declared.wrapper.make(\n Message.Announced({ message: text, politeness }),\n ) as unknown as ParentMessage\n\nexport const REGION_ATTRIBUTE = 'data-foldkit-plus-live'\n\n/**\n * The two live regions. Render once, anywhere in the page, and hide them\n * visually with a rule on `[data-foldkit-plus-live]`; they must stay in the\n * accessibility tree, so no `display: none`.\n */\nexport const view = <ParentMessage>(model: Model, h: HtmlBuilder<ParentMessage>): Html =>\n h.div(\n [h.Attribute(REGION_ATTRIBUTE, 'regions')],\n [\n h.div(\n [h.Attribute(REGION_ATTRIBUTE, 'polite'), h.AriaLive('polite'), h.AriaAtomic(true)],\n [model.polite],\n ),\n h.div(\n [h.Attribute(REGION_ATTRIBUTE, 'assertive'), h.AriaLive('assertive'), h.AriaAtomic(true)],\n [model.assertive],\n ),\n ],\n )\n","/**\n * Typeahead over a set of items: printable keys build a query that a timer\n * clears, and the query picks the item to move to. The query lives in the\n * Model so a replay sees the same picks; the timer runs on Effect's clock so\n * TestClock drives it. Which item matches is a pure function.\n */\nimport { Effect, Option, Schema } from 'effect'\nimport type { HtmlBuilder, KeyboardModifiers } from 'foldkit/html'\nimport { defineMessageUnion } from 'foldkit/message'\nimport type * as Update from 'foldkit/update'\nimport { Bundle, type Declared } from 'foldkit-bundle'\nimport { Behavior, Behaviors, Capability } from 'foldkit-mixins'\nimport { idSelector } from './roving-tabindex.js'\nimport { clearQuery } from '../internal.js'\n\nexport const Model = Schema.Struct({\n query: Schema.String,\n /** Bumped per keystroke, carried by the clear it schedules, so a superseded\n * timer's `Expired` changes nothing. */\n generation: Schema.Number,\n})\nexport type Model = typeof Model.Type\n\nexport const Message = defineMessageUnion({\n /** A printable key was pressed with no ctrl, alt or meta. */\n Typed: { char: Schema.String },\n /** The clear timer fired for `generation`. */\n Expired: { generation: Schema.Number },\n /** The query was dropped on purpose (a blur, a selection). */\n Cleared: {},\n})\nexport type Message = typeof Message.Type\n\nexport const Args = Schema.Struct({\n /** How long the query survives after the last key. */\n timeoutMs: Schema.Number.pipe(\n Schema.check(Schema.isGreaterThan(0)),\n Schema.check(Schema.isFinite()),\n ),\n})\nexport type Args = typeof Args.Type\n\nexport const bundle = Bundle.make('Typeahead', {\n Model,\n Message,\n args: Args,\n init: () => ({ model: { query: '', generation: 0 } }),\n update: (model, message, args) =>\n Message.match<Update.Return<Model, Message>>(message, {\n Typed: ({ char }) => {\n const generation = model.generation + 1\n return {\n model: { query: model.query + char, generation },\n commands: [\n {\n name: 'Typeahead.expire',\n args: { generation },\n effect: Effect.as(Effect.sleep(args.timeoutMs), Message.Expired({ generation })),\n },\n ],\n }\n },\n Expired: ({ generation }) =>\n generation === model.generation ? clearQuery(model) : { model },\n Cleared: () => clearQuery(model),\n }),\n})\n\nconst normalize = (text: string): string => text.trimStart().toLocaleLowerCase()\n\nconst isRepeated = (query: string): boolean =>\n query.length > 1 && [...query].every(char => char === query[0])\n\n/**\n * The enabled index whose text starts with `query`, searching forward from\n * `current` and wrapping, or `undefined`. A query of one character, or one\n * character repeated (`aaa`), starts *after* the current item so repeated\n * presses cycle through the items that begin with it; a longer query starts\n * *at* the current item, since the user is refining a match. Case and leading\n * whitespace are ignored.\n */\nexport const match = (\n texts: ReadonlyArray<string>,\n enabled: ReadonlyArray<number>,\n query: string,\n current: number,\n): number | undefined => {\n if (query === '' || enabled.length === 0) return undefined\n const needle = normalize(isRepeated(query) ? query[0]! : query)\n const position = enabled.indexOf(current)\n const startAfter = needle.length === 1 || isRepeated(query)\n const start = position === -1 ? 0 : startAfter ? position + 1 : position\n for (let offset = 0; offset < enabled.length; offset += 1) {\n const index = enabled[(start + offset) % enabled.length]!\n if (normalize(texts[index] ?? '').startsWith(needle)) return index\n }\n return undefined\n}\n\n/** A single character with no ctrl, alt or meta: a typeahead key. */\nexport const isPrintable = (key: string, modifiers: KeyboardModifiers): boolean =>\n key.length === 1 && !modifiers.ctrlKey && !modifiers.altKey && !modifiers.metaKey\n\nexport interface BehaviorOptions<Input, Slots> {\n /** The slot that receives the keys. */\n readonly host: keyof Slots & string\n readonly items: (input: Input) => Behaviors.Collection.Items<unknown>\n /** The text an item is matched by. */\n readonly text: (input: Input, index: number) => string\n /** The current item's id, so the search starts from it; a placed\n * `RovingTabindex` is the usual source. */\n readonly current: (input: Input) => string | null\n}\n\n/**\n * Wires a placed `Typeahead` to the host slot: a printable key extends the\n * query, focuses the matching item by its id (which then reports itself\n * current, through `RovingTabindex`'s `OnFocus`), and dispatches `Typed`.\n * With no match the key still extends the query, so the next one can match;\n * a space with an empty query is left to the host (it activates).\n */\nexport const behavior =\n <Field extends string>(declared: Declared<typeof bundle, Field>) =>\n <Slots>(slots: Slots) =>\n <Input extends { readonly [K in Field]: Model }, ParentMessage>(\n options: BehaviorOptions<Input, Slots>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> => {\n const wrap = (char: string): ParentMessage =>\n declared.wrapper.make(Message.Typed({ char })) as unknown as ParentMessage\n return Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.host]: Behavior.slot({\n requires: { capability: Capability.Interactive },\n attributes: ({\n input,\n h,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n }) => {\n const items = options.items(input)\n const query = input[declared.field].query\n const currentId = options.current(input)\n const current = currentId === null ? -1 : items.indexOf(currentId)\n return [\n h.OnKeyDownFocus((key, modifiers) => {\n if (!isPrintable(key, modifiers)) return Option.none()\n if (key === ' ' && query === '') return Option.none()\n // Read on a key, not on every render.\n const texts = items.ids.map((_, index) => options.text(input, index))\n const found = match(texts, items.enabled, query + key, current)\n const target = found === undefined ? currentId : items.ids[found]\n return Option.some({\n // `:not(*)` matches nothing: no match and nothing current\n // moves no focus, but the key is still recorded.\n focusSelector:\n target === null || target === undefined ? ':not(*)' : idSelector(target),\n message: wrap(key),\n })\n }),\n ]\n },\n }),\n // Keyed by a value the caller chose; `forSlots` checks the key exists.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'Typeahead' },\n )\n }\n","/**\n * Keyboard navigation of a list in one placement: a roving tab stop, type to\n * find, and PageUp and PageDown. One Bundle holds the current item's id and\n * the typeahead query, so a printable key can move the pointer and extend the\n * query in one transition, which two placements cannot do under `virtual`.\n * The resolver allows one owner per event on a slot, so a host that needs\n * both arrows and typeahead takes this, not `RovingTabindex` plus `Typeahead`.\n */\nimport { Effect, Option, Schema } from 'effect'\nimport type { HtmlBuilder, KeyboardModifiers } from 'foldkit/html'\nimport { defineMessageUnion } from 'foldkit/message'\nimport type * as Update from 'foldkit/update'\nimport { Bundle, type Declared } from 'foldkit-bundle'\nimport { Behavior, Behaviors, Capability, type SlotItem } from 'foldkit-mixins'\nimport * as RovingTabindex from './roving-tabindex.js'\nimport * as Typeahead from './typeahead.js'\nimport { clearQuery, perInput } from '../internal.js'\n\nexport const Model = Schema.Struct({\n current: Schema.NullOr(Schema.String),\n query: Schema.String,\n generation: Schema.Number,\n})\nexport type Model = typeof Model.Type\n\nexport const Message = defineMessageUnion({\n /** An item became current: focused, or reached by a key. */\n Focused: { id: Schema.String },\n /** A printable key extended the query; `match` is the item it now picks, if any. */\n Typed: { char: Schema.String, match: Schema.NullOr(Schema.String) },\n Expired: { generation: Schema.Number },\n Cleared: {},\n})\nexport type Message = typeof Message.Type\n\nexport const Args = Schema.Struct({\n orientation: RovingTabindex.Orientation,\n loop: Schema.Boolean,\n virtual: Schema.Boolean,\n /** How long the typeahead query survives after the last key. */\n timeoutMs: Schema.Number.pipe(\n Schema.check(Schema.isGreaterThan(0)),\n Schema.check(Schema.isFinite()),\n ),\n /** How many enabled items PageUp and PageDown move. */\n page: Schema.Number.pipe(Schema.check(Schema.isInt()), Schema.check(Schema.isGreaterThan(0))),\n})\nexport type Args = typeof Args.Type\n\nexport const bundle = Bundle.make('ListNavigation', {\n Model,\n Message,\n args: Args,\n init: () => ({ model: { current: null, query: '', generation: 0 } }),\n update: (model, message, args) =>\n Message.match<Update.Return<Model, Message>>(message, {\n // Moving focus by key dispatches `Focused`, and the item's `OnFocus` reports it again.\n Focused: ({ id }) =>\n model.current === id ? { model } : { model: { ...model, current: id } },\n Typed: ({ char, match }) => {\n const generation = model.generation + 1\n return {\n model: { current: match ?? model.current, query: model.query + char, generation },\n commands: [\n {\n name: 'ListNavigation.expire',\n args: { generation },\n effect: Effect.as(Effect.sleep(args.timeoutMs), Message.Expired({ generation })),\n },\n ],\n }\n },\n Expired: ({ generation }) =>\n generation === model.generation ? clearQuery(model) : { model },\n Cleared: () => clearQuery(model),\n }),\n})\n\nexport interface BehaviorOptions<Input, Slots> {\n readonly container: keyof Slots & string\n /** The slot rendered once per item; must carry the item's id (see `Behaviors.Collection`). */\n readonly item: keyof Slots & string\n readonly items: (input: Input) => Behaviors.Collection.Items<unknown>\n /** The text an item is matched by when typing. */\n readonly text: (input: Input, index: number) => string\n readonly direction?: (input: Input) => RovingTabindex.Direction\n}\n\n/**\n * The key's outcome, before it is turned into an attribute: navigation to an\n * id, a typed character with its match, or nothing.\n */\nexport type KeyOutcome =\n | { readonly _tag: 'Navigate'; readonly id: string }\n | { readonly _tag: 'Type'; readonly char: string; readonly match: string | null }\n\nexport const keyOutcome = (\n items: Behaviors.Collection.Items<unknown>,\n texts: ReadonlyArray<string>,\n state: { readonly current: string | null; readonly query: string },\n key: string,\n modifiers: KeyboardModifiers,\n options: RovingTabindex.MoveOptions,\n): KeyOutcome | undefined => {\n const from = state.current === null ? -1 : items.indexOf(state.current)\n const moved = RovingTabindex.move(items.enabled, from, key, modifiers, options)\n const movedId = moved === undefined ? undefined : items.ids[moved]\n if (movedId !== undefined) return { _tag: 'Navigate', id: movedId }\n if (!Typeahead.isPrintable(key, modifiers)) return undefined\n if (key === ' ' && state.query === '') return undefined\n const found = Typeahead.match(texts, items.enabled, state.query + key, from)\n return { _tag: 'Type', char: key, match: found === undefined ? null : (items.ids[found] ?? null) }\n}\n\n/**\n * Wires a placed `ListNavigation` to the slots. The container gets one key\n * handler: arrows, Home, End, PageUp and PageDown move by id; a printable key\n * extends the query and moves to its match. Each item gets `tabindex` and\n * `OnFocus` as under `RovingTabindex`. Under `virtual` nothing takes DOM focus\n * and the container carries `aria-activedescendant`.\n */\nexport const behavior =\n <Field extends string>(declared: Declared<typeof bundle, Field>, args: Args) =>\n <Slots>(slots: Slots) =>\n <Input extends { readonly [K in Field]: Model }, ParentMessage>(\n options: BehaviorOptions<Input, Slots>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> => {\n const wrap = (message: Message): ParentMessage =>\n declared.wrapper.make(message) as unknown as ParentMessage\n const focused = (id: string): ParentMessage => wrap(Message.Focused({ id }))\n const slice = (input: Input): Model => input[declared.field]\n const itemsOf = perInput(options.items)\n const outcomeMessage = (outcome: KeyOutcome): ParentMessage =>\n outcome._tag === 'Navigate'\n ? focused(outcome.id)\n : wrap(Message.Typed({ char: outcome.char, match: outcome.match }))\n return Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.container]: Behavior.slot({\n requires: { capability: Capability.Interactive },\n attributes: ({\n input,\n h,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n }) => {\n const items = itemsOf(input)\n const state = slice(input)\n const moveOptions: RovingTabindex.MoveOptions = {\n orientation: args.orientation,\n loop: args.loop,\n direction: options.direction?.(input) ?? 'ltr',\n page: args.page,\n }\n const outcome = (key: string, modifiers: KeyboardModifiers) =>\n Option.fromNullishOr(\n keyOutcome(\n items,\n // Read on a key, not on every render.\n items.ids.map((_, index) => options.text(input, index)),\n state,\n key,\n modifiers,\n moveOptions,\n ),\n )\n const stop = RovingTabindex.tabStop(items, state.current)\n const stopId = stop === -1 ? undefined : items.ids[stop]\n if (args.virtual) {\n return [\n h.OnKeyDownPreventDefault((key, modifiers) =>\n Option.map(outcome(key, modifiers), outcomeMessage),\n ),\n ...(stopId === undefined ? [] : [h.AriaActiveDescendant(stopId)]),\n ]\n }\n return [\n h.OnKeyDownFocus((key, modifiers) =>\n Option.map(outcome(key, modifiers), result => {\n const target =\n result._tag === 'Navigate' ? result.id : (result.match ?? state.current)\n return {\n // `:not(*)` matches nothing: a typed key with no match and\n // nothing current moves no focus but is still recorded.\n focusSelector: target === null ? ':not(*)' : RovingTabindex.idSelector(target),\n message: outcomeMessage(result),\n }\n }),\n ),\n ]\n },\n }),\n [options.item]: Behavior.slot({\n requires: { capability: Capability.Focusable },\n attributes: ({\n input,\n h,\n item,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n readonly item?: SlotItem\n }) =>\n item === undefined\n ? []\n : RovingTabindex.itemAttributes(\n h,\n itemsOf(input),\n slice(input).current,\n item,\n args.virtual,\n focused,\n ),\n }),\n // Keyed by values the caller chose; `forSlots` checks both keys exist.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'ListNavigation' },\n )\n }\n","/**\n * Press: pointer and keyboard activation of one element as one fact. A Mount\n * reports what the element saw (pointer down, up, cancel, key down, up,\n * click) with the detail Foldkit's declarative attributes do not carry; the\n * Bundle's `update` decides what counts as a press; the ghost click that\n * follows a touch is suppressed by a timed Command on Effect's clock, never\n * by a clock read in a handler. Activation is an OutMessage, `Pressed`, so\n * the placement must say what a press does.\n */\nimport { Effect, Queue, Schema, Stream } from 'effect'\nimport type { HtmlBuilder } from 'foldkit/html'\nimport { defineMessageUnion } from 'foldkit/message'\nimport * as Mount from 'foldkit/mount'\nimport type * as Update from 'foldkit/update'\nimport { Bundle, type Declared } from 'foldkit-bundle'\nimport { Behavior, Capability } from 'foldkit-mixins'\n\nexport const PointerType = Schema.Literals(['mouse', 'touch', 'pen', 'keyboard', 'virtual'])\nexport type PointerType = typeof PointerType.Type\n\nexport const Model = Schema.Struct({\n /** Down and not yet released or cancelled. For styling. */\n pressed: Schema.Boolean,\n /** The pointer that pressed, so another pointer's up cannot release it. */\n pointerId: Schema.NullOr(Schema.Number),\n /** Enter or Space is down. */\n key: Schema.NullOr(Schema.String),\n /** A click arriving before this generation's window ends is the ghost of a pointer press. */\n suppressing: Schema.NullOr(Schema.Number),\n generation: Schema.Number,\n})\nexport type Model = typeof Model.Type\n\nexport const Message = defineMessageUnion({\n PointerDown: { pointerId: Schema.Number, button: Schema.Number, pointerType: Schema.String },\n PointerUp: { pointerId: Schema.Number, pointerType: Schema.String, shiftKey: Schema.Boolean },\n PointerCancelled: { pointerId: Schema.Number },\n KeyDown: { key: Schema.String, repeat: Schema.Boolean },\n KeyUp: { key: Schema.String, shiftKey: Schema.Boolean },\n /** `detail` is 0 for a click no pointer made: keyboard on a native control, or assistive technology. */\n Clicked: { detail: Schema.Number, shiftKey: Schema.Boolean },\n Unsuppressed: { generation: Schema.Number },\n})\nexport type Message = typeof Message.Type\n\nexport const Pressed = Schema.TaggedStruct('Pressed', {\n pointerType: PointerType,\n /** Shift was held, for a range selection. */\n shiftKey: Schema.Boolean,\n})\nexport type Pressed = typeof Pressed.Type\n\nexport const Args = Schema.Struct({\n /** How long after a pointer press a `click` is taken for its ghost. */\n clickSuppressionMs: Schema.Number.pipe(\n Schema.check(Schema.isGreaterThanOrEqualTo(0)),\n Schema.check(Schema.isFinite()),\n ),\n})\nexport type Args = typeof Args.Type\n\nconst idle = (model: Model): Model => ({ ...model, pressed: false, pointerId: null, key: null })\n\nconst isActivationKey = (key: string): boolean => key === 'Enter' || key === ' '\n\nconst asPointerType = (raw: string): PointerType =>\n raw === 'touch' || raw === 'pen' ? raw : 'mouse'\n\ntype Return = Update.ReturnWithOutMessage<Model, Message, Pressed>\n\nexport const bundle = Bundle.make('Press', {\n Model,\n Message,\n args: Args,\n init: () => ({\n model: { pressed: false, pointerId: null, key: null, suppressing: null, generation: 0 },\n }),\n update: (model, message, args): Return =>\n Message.match<Return>(message, {\n PointerDown: ({ pointerId, button }) =>\n button !== 0 || model.pointerId !== null\n ? { model }\n : { model: { ...model, pressed: true, pointerId } },\n PointerUp: ({ pointerId, pointerType, shiftKey }) => {\n if (model.pointerId !== pointerId) return { model }\n const generation = model.generation + 1\n return {\n model: { ...idle(model), suppressing: generation, generation },\n commands: [\n {\n name: 'Press.unsuppress',\n args: { generation },\n effect: Effect.as(\n Effect.sleep(args.clickSuppressionMs),\n Message.Unsuppressed({ generation }),\n ),\n },\n ],\n outMessage: Pressed.make({ pointerType: asPointerType(pointerType), shiftKey }),\n }\n },\n PointerCancelled: ({ pointerId }) =>\n model.pointerId === pointerId ? { model: idle(model) } : { model },\n KeyDown: ({ key, repeat }) =>\n !isActivationKey(key) || repeat || model.key !== null || model.pointerId !== null\n ? { model }\n : { model: { ...model, pressed: true, key } },\n KeyUp: ({ key, shiftKey }) =>\n model.key === key\n ? { model: idle(model), outMessage: Pressed.make({ pointerType: 'keyboard', shiftKey }) }\n : { model },\n Clicked: ({ detail, shiftKey }) =>\n detail === 0\n ? { model, outMessage: Pressed.make({ pointerType: 'virtual', shiftKey }) }\n : model.suppressing !== null\n ? { model }\n : { model, outMessage: Pressed.make({ pointerType: 'mouse', shiftKey }) },\n Unsuppressed: ({ generation }) =>\n model.suppressing === generation ? { model: { ...model, suppressing: null } } : { model },\n }),\n})\n\ntype PointerLike = Event & {\n readonly pointerId?: number\n readonly button?: number\n readonly pointerType?: string\n readonly shiftKey?: boolean\n}\n\n/** What the element reports; `Unsuppressed` comes from the timer, not the DOM. */\nexport type Fact = Exclude<Message, { readonly _tag: 'Unsuppressed' }>\n\n/**\n * The element's press-relevant events as facts. Enter and Space key downs\n * are default-prevented so a native control does not also click, and Space\n * does not scroll; the Bundle owns activation. An element marked\n * `aria-disabled=\"true\"` (which the Behavior writes) reports nothing, read\n * at event time so a toggle needs no remount. Nothing else is decided here.\n */\nexport const events = Mount.defineStream('PressEvents', {\n messages: [\n Message.PointerDown,\n Message.PointerUp,\n Message.PointerCancelled,\n Message.KeyDown,\n Message.KeyUp,\n Message.Clicked,\n ],\n execute: ({ element }) =>\n Stream.callback<Fact>(queue =>\n Effect.acquireRelease(\n Effect.sync(() => {\n const offer = (message: Fact) => {\n if (element.getAttribute('aria-disabled') === 'true') return\n Queue.offerUnsafe(queue, message)\n }\n const listeners: ReadonlyArray<readonly [string, (event: Event) => void]> = [\n [\n 'pointerdown',\n event => {\n const pointer = event as PointerLike\n offer(\n Message.PointerDown({\n pointerId: pointer.pointerId ?? 0,\n button: pointer.button ?? 0,\n pointerType: pointer.pointerType ?? 'mouse',\n }),\n )\n },\n ],\n [\n 'pointerup',\n event => {\n const pointer = event as PointerLike\n offer(\n Message.PointerUp({\n pointerId: pointer.pointerId ?? 0,\n pointerType: pointer.pointerType ?? 'mouse',\n shiftKey: pointer.shiftKey ?? false,\n }),\n )\n },\n ],\n [\n 'pointerleave',\n event =>\n offer(\n Message.PointerCancelled({ pointerId: (event as PointerLike).pointerId ?? 0 }),\n ),\n ],\n [\n 'pointercancel',\n event =>\n offer(\n Message.PointerCancelled({ pointerId: (event as PointerLike).pointerId ?? 0 }),\n ),\n ],\n [\n 'keydown',\n event => {\n const key = event as KeyboardEvent\n if (isActivationKey(key.key)) key.preventDefault()\n offer(Message.KeyDown({ key: key.key, repeat: key.repeat }))\n },\n ],\n [\n 'keyup',\n event => {\n const key = event as KeyboardEvent\n offer(Message.KeyUp({ key: key.key, shiftKey: key.shiftKey }))\n },\n ],\n [\n 'click',\n event => {\n const click = event as MouseEvent\n offer(\n Message.Clicked({ detail: click.detail ?? 0, shiftKey: click.shiftKey ?? false }),\n )\n },\n ],\n ]\n for (const [type, listener] of listeners) element.addEventListener(type, listener)\n return listeners\n }),\n listeners =>\n Effect.sync(() => {\n for (const [type, listener] of listeners) element.removeEventListener(type, listener)\n }),\n ),\n ),\n})\n\nexport interface BehaviorOptions<Input, Slots> {\n readonly target: keyof Slots & string\n /** Marks the target `aria-disabled`, which also silences its events. */\n readonly disabled?: (input: Input) => boolean\n}\n\n/**\n * Attaches the events Mount to the target slot, mapped into the placement's\n * Messages, and writes `data-pressed` while down for styling. The element\n * decides nothing; a click, a touch, Enter, Space, or an assistive\n * technology's click all reach `update` and come out as one `Pressed`.\n */\nexport const behavior =\n <Field extends string>(declared: Declared<typeof bundle, Field>) =>\n <Slots>(slots: Slots) =>\n <Input extends { readonly [K in Field]: Model }, ParentMessage>(\n options: BehaviorOptions<Input, Slots>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.target]: Behavior.slot({\n requires: { capability: Capability.Interactive },\n attributes: ({\n input,\n h,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n }) => [\n ...(input[declared.field].pressed ? [h.DataAttribute('pressed', 'true')] : []),\n ...(options.disabled?.(input) === true ? [h.AriaDisabled(true)] : []),\n ],\n mount: () =>\n Mount.mapMessage(\n events(),\n (message): ParentMessage =>\n declared.wrapper.make(message) as unknown as ParentMessage,\n ),\n }),\n // Keyed by a value the caller chose; `forSlots` checks the key exists.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'Press' },\n )\n","/**\n * LongPress: holding an element down for `thresholdMs` is one fact. It reads\n * the same facts `Press.events` reports; the threshold is a Command on\n * Effect's clock carrying a generation, so a release before it fires makes\n * its `Elapsed` a no-op. `LongPressed` is an OutMessage the placement must\n * handle. A short press is `Press`'s business, not this Bundle's.\n */\nimport { Effect, Schema } from 'effect'\nimport type { HtmlBuilder } from 'foldkit/html'\nimport { defineMessageUnion } from 'foldkit/message'\nimport * as Mount from 'foldkit/mount'\nimport type * as Update from 'foldkit/update'\nimport { Bundle, type Declared } from 'foldkit-bundle'\nimport { Behavior, Capability } from 'foldkit-mixins'\nimport * as Press from './press.js'\n\nexport const Model = Schema.Struct({\n /** Down, and the threshold has not passed. */\n holding: Schema.Boolean,\n pointerId: Schema.NullOr(Schema.Number),\n key: Schema.NullOr(Schema.String),\n generation: Schema.Number,\n})\nexport type Model = typeof Model.Type\n\nexport const Message = defineMessageUnion({\n PointerDown: { pointerId: Schema.Number, button: Schema.Number, pointerType: Schema.String },\n PointerUp: { pointerId: Schema.Number, pointerType: Schema.String, shiftKey: Schema.Boolean },\n PointerCancelled: { pointerId: Schema.Number },\n KeyDown: { key: Schema.String, repeat: Schema.Boolean },\n KeyUp: { key: Schema.String, shiftKey: Schema.Boolean },\n Clicked: { detail: Schema.Number, shiftKey: Schema.Boolean },\n Elapsed: { generation: Schema.Number, pointerType: Press.PointerType },\n})\nexport type Message = typeof Message.Type\n\nexport const LongPressed = Schema.TaggedStruct('LongPressed', { pointerType: Press.PointerType })\nexport type LongPressed = typeof LongPressed.Type\n\nexport const Args = Schema.Struct({\n thresholdMs: Schema.Number.pipe(\n Schema.check(Schema.isGreaterThan(0)),\n Schema.check(Schema.isFinite()),\n ),\n})\nexport type Args = typeof Args.Type\n\nconst isActivationKey = (key: string): boolean => key === 'Enter' || key === ' '\n\nconst released = (model: Model): Model => ({ ...model, holding: false, pointerId: null, key: null })\n\ntype Return = Update.ReturnWithOutMessage<Model, Message, LongPressed>\n\nconst start = (\n model: Model,\n args: Args,\n by: { readonly pointerId: number } | { readonly key: string },\n pointerType: Press.PointerType,\n): Return => {\n const generation = model.generation + 1\n return {\n model: {\n holding: true,\n pointerId: 'pointerId' in by ? by.pointerId : null,\n key: 'key' in by ? by.key : null,\n generation,\n },\n commands: [\n {\n name: 'LongPress.elapse',\n args: { generation },\n effect: Effect.as(\n Effect.sleep(args.thresholdMs),\n Message.Elapsed({ generation, pointerType }),\n ),\n },\n ],\n }\n}\n\nexport const bundle = Bundle.make('LongPress', {\n Model,\n Message,\n args: Args,\n init: () => ({ model: { holding: false, pointerId: null, key: null, generation: 0 } }),\n update: (model, message, args): Return =>\n Message.match<Return>(message, {\n PointerDown: ({ pointerId, button, pointerType }) =>\n button !== 0 || model.holding\n ? { model }\n : start(\n model,\n args,\n { pointerId },\n pointerType === 'touch' || pointerType === 'pen' ? pointerType : 'mouse',\n ),\n PointerUp: ({ pointerId }) =>\n model.pointerId === pointerId ? { model: released(model) } : { model },\n PointerCancelled: ({ pointerId }) =>\n model.pointerId === pointerId ? { model: released(model) } : { model },\n KeyDown: ({ key, repeat }) =>\n !isActivationKey(key) || repeat || model.holding\n ? { model }\n : start(model, args, { key }, 'keyboard'),\n KeyUp: ({ key }) => (model.key === key ? { model: released(model) } : { model }),\n Clicked: () => ({ model }),\n Elapsed: ({ generation, pointerType }) =>\n model.holding && model.generation === generation\n ? { model: released(model), outMessage: LongPressed.make({ pointerType }) }\n : { model },\n }),\n})\n\nexport interface BehaviorOptions<Slots> {\n readonly target: keyof Slots & string\n}\n\n/**\n * Attaches `Press.events` to the target, mapped into this placement's\n * Messages, and writes `data-holding` while the element is down. `Press` and\n * `LongPress` on one slot are refused by the resolver (two Mounts of one\n * name), so today a slot takes one of them.\n */\nexport const behavior =\n <Field extends string>(declared: Declared<typeof bundle, Field>) =>\n <Slots>(slots: Slots) =>\n <Input extends { readonly [K in Field]: Model }, ParentMessage>(\n options: BehaviorOptions<Slots>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.target]: Behavior.slot({\n requires: { capability: Capability.Interactive },\n attributes: ({\n input,\n h,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n }) => (input[declared.field].holding ? [h.DataAttribute('holding', 'true')] : []),\n mount: () =>\n Mount.mapMessage(\n Press.events(),\n // The facts are the same tagged structs; only the union differs.\n (fact): ParentMessage =>\n declared.wrapper.make(fact as unknown as Message) as unknown as ParentMessage,\n ),\n }),\n // Keyed by a value the caller chose; `forSlots` checks the key exists.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'LongPress' },\n )\n","/**\n * `Move` as a Behavior: attaches the `foldkit-primitives/dom` Mount to a\n * draggable slot and maps its facts into the view's Messages. No Bundle: a\n * drag's meaning (a threshold, a snap, a reorder) is the parent's `update`,\n * and the deltas are already facts.\n */\nimport * as Mount from 'foldkit/mount'\nimport { Behavior, Capability } from 'foldkit-mixins'\nimport { Move as MoveMount, type Fact } from '../dom/move.js'\n\nexport { Move as mount, MoveEnded, MoveStarted, Moved, type Fact } from '../dom/move.js'\n\nexport interface BehaviorOptions<Slots, ParentMessage> {\n readonly handle: keyof Slots & string\n /** Turns each fact into the view's Message. */\n readonly toMessage: (fact: Fact) => ParentMessage\n}\n\nexport const behavior =\n <Slots>(slots: Slots) =>\n <Input, ParentMessage>(\n options: BehaviorOptions<Slots, ParentMessage>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.handle]: Behavior.slot({\n requires: { capability: Capability.Draggable },\n mount: () => Mount.mapMessage(MoveMount(), options.toMessage),\n }),\n // Keyed by a value the caller chose; `forSlots` checks the key exists.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'Move' },\n )\n","/**\n * Selection over a set of items: which ids are selected, and the anchor a\n * range extends from. `mode` is `'single'` (a click replaces), `'multiple'`\n * (a click toggles), or `'none'`. Single mode keeps one item selected unless\n * `allowEmpty`. A range needs the items' order, which the view knows and the\n * Bundle does not, so `Ranged` carries it. The Behavior says the state in\n * ARIA and wires a plain click; a Shift range comes from `Press`, whose\n * `Pressed` carries `shiftKey`.\n */\nimport { Schema } from 'effect'\nimport type { HtmlBuilder } from 'foldkit/html'\nimport { defineMessageUnion } from 'foldkit/message'\nimport { Bundle, type Declared } from 'foldkit-bundle'\nimport { Behavior, Behaviors, Capability, type SlotItem } from 'foldkit-mixins'\nimport { perInput, sameIds } from '../internal.js'\n\nexport const Mode = Schema.Literals(['single', 'multiple', 'none'])\nexport type Mode = typeof Mode.Type\n\nexport const Model = Schema.Struct({\n /** In selection order. */\n selected: Schema.Array(Schema.String),\n /** Where the last plain selection happened; a range extends from it. */\n anchor: Schema.NullOr(Schema.String),\n})\nexport type Model = typeof Model.Type\n\nexport const Message = defineMessageUnion({\n /** A plain activation: replaces in single mode, toggles in multiple mode. */\n Activated: { id: Schema.String },\n /** A Shift activation: selects everything between the anchor and `id` in `order`. */\n Ranged: { id: Schema.String, order: Schema.Array(Schema.String) },\n Replaced: { ids: Schema.Array(Schema.String) },\n Cleared: {},\n})\nexport type Message = typeof Message.Type\n\nexport const Args = Schema.Struct({\n mode: Mode,\n /** In single mode, whether activating the selected item deselects it. */\n allowEmpty: Schema.Boolean,\n})\nexport type Args = typeof Args.Type\n\nconst without = (ids: ReadonlyArray<string>, id: string) => ids.filter(other => other !== id)\n\n/** The ids between `from` and `to` in `order`, inclusive, in `order`'s order. */\nexport const between = (\n order: ReadonlyArray<string>,\n from: string | null,\n to: string,\n): ReadonlyArray<string> => {\n const end = order.indexOf(to)\n if (end === -1) return []\n const start = from === null ? -1 : order.indexOf(from)\n if (start === -1) return [to]\n return order.slice(Math.min(start, end), Math.max(start, end) + 1)\n}\n\nexport const bundle = Bundle.make('Selection', {\n Model,\n Message,\n args: Args,\n init: () => ({ model: { selected: [], anchor: null } }),\n update: (model, message, args) =>\n Message.match(message, {\n Activated: ({ id }) => {\n if (args.mode === 'none') return { model }\n const isSelected = model.selected.includes(id)\n if (args.mode === 'single') {\n return isSelected\n ? args.allowEmpty\n ? { model: { selected: [], anchor: id } }\n : { model }\n : { model: { selected: [id], anchor: id } }\n }\n return {\n model: {\n selected: isSelected ? without(model.selected, id) : [...model.selected, id],\n anchor: id,\n },\n }\n },\n Ranged: ({ id, order }) => {\n if (args.mode !== 'multiple') return { model }\n const range = between(order, model.anchor, id)\n const inRange = new Set(range)\n const selected = [...model.selected.filter(other => !inRange.has(other)), ...range]\n const anchor = model.anchor ?? id\n // Shift-clicking the same item twice ranges over what is selected already.\n return sameIds(selected, model.selected) && anchor === model.anchor\n ? { model }\n : { model: { selected, anchor } }\n },\n Replaced: ({ ids }) => {\n const selected = args.mode === 'none' ? [] : [...new Set(ids)]\n return sameIds(selected, model.selected)\n ? { model }\n : { model: { selected, anchor: model.anchor } }\n },\n Cleared: () =>\n model.selected.length === 0 ? { model } : { model: { selected: [], anchor: model.anchor } },\n }),\n})\n\nexport interface BehaviorOptions<Input, Slots> {\n /** The slot holding the items, for `aria-multiselectable`. */\n readonly container?: keyof Slots & string\n /** The slot rendered once per item; must carry the item's id. */\n readonly item: keyof Slots & string\n readonly items: (input: Input) => Behaviors.Collection.Items<unknown>\n /** Wire a plain click on each item to `Activated`. Default `true`; turn off\n * when `Press` or the view owns the click. */\n readonly click?: boolean\n}\n\n/**\n * Writes `aria-selected` on each item from the placed slice, and\n * `aria-multiselectable` on the container in multiple mode; wires `OnClick`\n * to `Activated` unless told not to. A disabled item gets no click.\n */\nexport const behavior =\n <Field extends string>(declared: Declared<typeof bundle, Field>, args: Args) =>\n <Slots>(slots: Slots) =>\n <Input extends { readonly [K in Field]: Model }, ParentMessage>(\n options: BehaviorOptions<Input, Slots>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> => {\n const wrap = (message: Message): ParentMessage =>\n declared.wrapper.make(message) as unknown as ParentMessage\n const itemsOf = perInput(options.items)\n const selectedOf = perInput((input: Input) => new Set(input[declared.field].selected))\n return Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n ...(options.container === undefined\n ? {}\n : {\n [options.container]: Behavior.slot({\n requires: { capability: Capability.Container },\n attributes: ({ h }: { readonly h: HtmlBuilder<ParentMessage> }) => [\n h.AriaMultiSelectable(args.mode === 'multiple'),\n ],\n }),\n }),\n [options.item]: Behavior.slot({\n requires: { capability: Capability.Interactive },\n attributes: ({\n input,\n h,\n item,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n readonly item?: SlotItem\n }) => {\n if (item === undefined) return []\n const items = itemsOf(input)\n const id = item.id ?? items.ids[item.index]\n if (id === undefined) return []\n const clickable =\n options.click !== false && args.mode !== 'none' && !items.isDisabled(item.index)\n return [\n h.AriaSelected(selectedOf(input).has(id)),\n ...(clickable ? [h.OnClick(wrap(Message.Activated({ id })))] : []),\n ]\n },\n }),\n // Keyed by values the caller chose; `forSlots` checks the keys exist.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'Selection' },\n )\n }\n","/**\n * `Targets` as a Behavior: attaches the `foldkit-primitives/dom` Mount to a\n * container slot and maps what it reports into the view's Messages. No Bundle:\n * which descendant is under the pointer, or was pressed, is already a fact, and\n * what it means is the parent's `update`.\n */\nimport * as Mount from 'foldkit/mount'\nimport { Behavior, Capability } from 'foldkit-mixins'\nimport { Targets as TargetsMount, type TargetFact } from '../dom/targets.js'\n\nexport {\n TargetHovered,\n TargetPressed,\n Targets as mount,\n targetOf,\n type TargetFact,\n} from '../dom/targets.js'\n\nexport interface BehaviorOptions<Slots, ParentMessage> {\n /** The slot holding the marked descendants. */\n readonly container: keyof Slots & string\n /** The attribute that marks a descendant, holding its id. */\n readonly attribute: string\n /** Prevent a press's default, such as a link navigating. Default `false`. */\n readonly preventDefault?: boolean\n /** Turns each fact into the view's Message. */\n readonly toMessage: (fact: TargetFact) => ParentMessage\n}\n\nexport const behavior =\n <Slots>(slots: Slots) =>\n <Input, ParentMessage>(\n options: BehaviorOptions<Slots, ParentMessage>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.container]: Behavior.slot({\n requires: { capability: Capability.Container },\n mount: () =>\n Mount.mapMessage(\n TargetsMount({\n attribute: options.attribute,\n preventDefault: options.preventDefault ?? false,\n }),\n options.toMessage,\n ),\n }),\n // Keyed by a value the caller chose; `forSlots` checks the key exists.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'Targets' },\n )\n","/**\n * `PointerDrag` as a Behavior: attaches the `foldkit-primitives/dom` Mount to\n * a container slot and maps what it reports into the view's Messages. No\n * Bundle: what is dragged and where the pointer is are facts, and what a drop\n * means, and whether it is allowed, is the parent's `update`.\n */\nimport * as Mount from 'foldkit/mount'\nimport { Behavior, Capability } from 'foldkit-mixins'\nimport { PointerDrag as PointerDragMount, type DragFact } from '../dom/pointer-drag.js'\n\nexport {\n DRAG_THRESHOLD,\n DragCancelled,\n DragDropped,\n DragPlace,\n DragStarted,\n DragZone,\n DraggedOver,\n PointerDrag as mount,\n boxOf,\n zoneOf,\n type DragFact,\n} from '../dom/pointer-drag.js'\n\nexport interface BehaviorOptions<Slots, ParentMessage> {\n /** The slot holding the marked descendants. */\n readonly container: keyof Slots & string\n /** The attribute that marks a descendant, holding its id. */\n readonly attribute: string\n /**\n * Where a drag may land when not among the container's own: elements marked\n * by `attribute` inside the one `within` selects, such as a page for a palette.\n */\n readonly targets?: { readonly attribute: string; readonly within: string }\n /** Turns each fact into the view's Message. */\n readonly toMessage: (fact: DragFact) => ParentMessage\n}\n\nexport const behavior =\n <Slots>(slots: Slots) =>\n <Input, ParentMessage>(\n options: BehaviorOptions<Slots, ParentMessage>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.container]: Behavior.slot({\n requires: { capability: Capability.Container },\n mount: () =>\n Mount.mapMessage(\n PointerDragMount(\n options.targets === undefined\n ? { attribute: options.attribute }\n : { attribute: options.attribute, targets: options.targets },\n ),\n options.toMessage,\n ),\n }),\n // Keyed by a value the caller chose; `forSlots` checks the key exists.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'PointerDrag' },\n )\n","/**\n * Keyboard navigation of a tree (a file explorer, a page's layers, a nested\n * menu), after the WAI-ARIA tree pattern: one tab stop, Up and Down through the\n * rows that are showing, Right to open a row or step into it, Left to close it\n * or step out to its parent, Home and End to the first and last row.\n *\n * The Model slice is the current row's id and which rows are open. Openness is\n * stored as the rows `toggled` away from a default, so a layers panel that\n * starts with everything open and a file tree that starts closed are the same\n * bundle with a different `openByDefault`, and neither stores every row.\n *\n * Which rows exist is the view's to say, each with its parent, in tree order.\n * What a key does is a pure function of those rows and the Model; the Behavior\n * wires it to the slots and writes the tree's ARIA attributes.\n */\nimport { Option, Schema } from 'effect'\nimport type { HtmlBuilder, KeyboardModifiers } from 'foldkit/html'\nimport { defineMessageUnion } from 'foldkit/message'\nimport { Bundle } from 'foldkit-bundle'\nimport type { Declared } from 'foldkit-bundle'\nimport { Behavior, Capability, type SlotItem } from 'foldkit-mixins'\nimport { FollowTabStop } from '../dom/follow-tab-stop.js'\nimport { idSelector } from './roving-tabindex.js'\nimport { perInput } from '../internal.js'\n\nexport const Model = Schema.Struct({\n /** The current row's id, or `null` before any row has been focused. */\n current: Schema.NullOr(Schema.String),\n /** The rows whose open state differs from `openByDefault`. */\n toggled: Schema.Array(Schema.String),\n})\nexport type Model = typeof Model.Type\n\nexport const Message = defineMessageUnion({\n /** A row became current: the user focused it, or a key moved there. */\n Focused: { id: Schema.String },\n Opened: { id: Schema.String },\n Closed: { id: Schema.String },\n})\nexport type Message = typeof Message.Type\n\nexport const Args = Schema.Struct({\n /** Whether a row with children starts open. */\n openByDefault: Schema.Boolean,\n})\nexport type Args = typeof Args.Type\n\n/** Whether a row is open, given the default and what was toggled. */\nexport const isOpen = (model: Model, args: Args, id: string): boolean =>\n args.openByDefault !== model.toggled.includes(id)\n\nconst setOpen = (model: Model, args: Args, id: string, open: boolean): Model =>\n isOpen(model, args, id) === open\n ? model\n : {\n ...model,\n toggled: model.toggled.includes(id)\n ? model.toggled.filter(toggled => toggled !== id)\n : [...model.toggled, id],\n }\n\nexport const bundle = Bundle.make('TreeNavigation', {\n Model,\n Message,\n args: Args,\n init: () => ({ model: { current: null, toggled: [] } }),\n update: (model, message, args) => {\n switch (message._tag) {\n // Moving focus by key dispatches `Focused`, and the row's `OnFocus` reports it again.\n case 'Focused':\n return model.current === message.id\n ? { model }\n : { model: { ...model, current: message.id } }\n case 'Opened':\n return { model: setOpen(model, args, message.id, true) }\n case 'Closed':\n return { model: setOpen(model, args, message.id, false) }\n }\n },\n})\n\n/** One row of the tree, in tree order: a parent comes before its children. */\nexport interface Row {\n readonly id: string\n /** The parent's id, or `null` for a top-level row. */\n readonly parent: string | null\n /** Whether it has children, so it can be opened and closed. */\n readonly branch: boolean\n readonly disabled?: boolean\n}\n\n/** A row as it is showing: where it sits, for its ARIA attributes. */\nexport interface Shown extends Row {\n /** 1 for a top-level row. */\n readonly level: number\n /** Its place among its siblings, from 1, and how many there are. */\n readonly position: number\n readonly siblings: number\n}\n\n/**\n * The rows that are showing: every row whose ancestors are all open, with its\n * level and its place among its siblings. A row whose parent is not a row is\n * treated as top-level.\n */\nexport const shown = (rows: ReadonlyArray<Row>, model: Model, args: Args): ReadonlyArray<Shown> => {\n const byId = new Map(rows.map(row => [row.id, row]))\n // Each row's place among its siblings, counted once: a page of a thousand rows\n // under one parent is not a million steps.\n const siblingsOf = new Map<string | null, number>()\n const positionOf = new Map<string, number>()\n for (const row of rows) {\n const parent = row.parent !== null && byId.has(row.parent) ? row.parent : null\n const count = (siblingsOf.get(parent) ?? 0) + 1\n siblingsOf.set(parent, count)\n positionOf.set(row.id, count)\n }\n const levels = new Map<string, number>()\n const showing = new Map<string, boolean>()\n const result: Array<Shown> = []\n for (const row of rows) {\n const parent = row.parent !== null && byId.has(row.parent) ? row.parent : null\n const level = parent === null ? 1 : (levels.get(parent) ?? 0) + 1\n levels.set(row.id, level)\n const visible = parent === null || (showing.get(parent) === true && isOpen(model, args, parent))\n showing.set(row.id, visible)\n if (!visible) continue\n result.push({\n ...row,\n level,\n position: positionOf.get(row.id) ?? 1,\n siblings: siblingsOf.get(parent) ?? 1,\n })\n }\n return result\n}\n\n/** What a key does: move to a row, or open or close one. */\nexport type Action =\n | { readonly _tag: 'Focus'; readonly id: string }\n | { readonly _tag: 'Open'; readonly id: string }\n | { readonly _tag: 'Close'; readonly id: string }\n\nconst isPlain = (modifiers: KeyboardModifiers): boolean =>\n !modifiers.ctrlKey && !modifiers.altKey && !modifiers.metaKey\n\n/**\n * What a key does from the current row, over the rows that are showing, or\n * `undefined` when it is not a key the tree handles. Disabled rows are stepped\n * over. With nothing current, Down and Home land on the first row, Up and End\n * on the last. Right and Left swap under `rtl`.\n */\nexport const move = (\n rows: ReadonlyArray<Shown>,\n current: string | null,\n key: string,\n modifiers: KeyboardModifiers,\n model: Model,\n args: Args,\n direction: 'ltr' | 'rtl' = 'ltr',\n): Action | undefined => {\n const enabled = rows.filter(row => row.disabled !== true)\n if (enabled.length === 0 || !isPlain(modifiers)) return undefined\n const focus = (row: Row | undefined): Action | undefined =>\n row === undefined ? undefined : { _tag: 'Focus', id: row.id }\n const at = enabled.findIndex(row => row.id === current)\n const inward = direction === 'rtl' ? 'ArrowLeft' : 'ArrowRight'\n const outward = direction === 'rtl' ? 'ArrowRight' : 'ArrowLeft'\n if (key === 'Home') return focus(enabled[0])\n if (key === 'End') return focus(enabled[enabled.length - 1])\n if (key === 'ArrowDown')\n return focus(at === -1 ? enabled[0] : enabled[Math.min(at + 1, enabled.length - 1)])\n if (key === 'ArrowUp')\n return focus(at === -1 ? enabled[enabled.length - 1] : enabled[Math.max(at - 1, 0)])\n const row = enabled[at]\n if (row === undefined) return key === inward || key === outward ? focus(enabled[0]) : undefined\n if (key === inward) {\n if (!row.branch) return undefined\n if (!isOpen(model, args, row.id)) return { _tag: 'Open', id: row.id }\n return focus(enabled.find(child => child.parent === row.id))\n }\n if (key === outward) {\n if (row.branch && isOpen(model, args, row.id)) return { _tag: 'Close', id: row.id }\n return focus(enabled.find(parent => parent.id === row.parent))\n }\n return undefined\n}\n\n/** The row that holds the tab stop: the current one while it is showing, else the first. */\nexport const tabStop = (rows: ReadonlyArray<Shown>, current: string | null): string | undefined => {\n const here = rows.find(row => row.id === current && row.disabled !== true)\n return (here ?? rows.find(row => row.disabled !== true))?.id\n}\n\nexport interface BehaviorOptions<Input, Slots> {\n /** The slot that receives the keys: the element with `role=\"tree\"`. */\n readonly container: keyof Slots & string\n /** The slot rendered once per showing row, with `item.id` or `item.index` into `shown`. */\n readonly item: keyof Slots & string\n /** Every row, open or not, in tree order. */\n readonly rows: (input: Input) => ReadonlyArray<Row>\n /** The DOM id a row's element carries. Default: the row's own id. */\n readonly domId?: (id: string) => string\n readonly direction?: (input: Input) => 'ltr' | 'rtl'\n}\n\n/** The rows showing for one input, with what each row's attributes look up. */\ninterface Prepared {\n readonly model: Model\n readonly rows: ReadonlyArray<Shown>\n readonly byId: ReadonlyMap<string, Shown>\n readonly stop: string | undefined\n}\n\n/**\n * Wires a placed `TreeNavigation` to the slots. The container's keys move focus\n * to the row they pick, or open or close the current row with focus left where\n * it is. Each showing row gets its id, `role=\"treeitem\"`, `aria-level` (and\n * the same level as `--fk-tree-level`, so one `calc` indents any depth),\n * `aria-posinset`, `aria-setsize`, `aria-expanded` when it has children,\n * `aria-disabled` when disabled, a roving `tabindex`, and `OnFocus` reporting\n * it current. Every handled key is default-prevented.\n */\n\nexport const behavior =\n <Field extends string>(declared: Declared<typeof bundle, Field>, args: Args) =>\n <Slots>(slots: Slots) =>\n <Input extends { readonly [K in Field]: Model }, ParentMessage>(\n options: BehaviorOptions<Input, Slots>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> => {\n const wrap = (message: Message): ParentMessage =>\n declared.wrapper.make(message) as unknown as ParentMessage\n const slice = (input: Input): Model => input[declared.field]\n const domId = options.domId ?? ((id: string) => id)\n // Every row's attributes read the same rows: work them out once per input,\n // or a tree of n rows costs n times its whole.\n const prepare = perInput((input: Input): Prepared => {\n const model = slice(input)\n const rows = shown(options.rows(input), model, args)\n return {\n model,\n rows,\n byId: new Map(rows.map(row => [row.id, row])),\n stop: tabStop(rows, model.current),\n }\n })\n return Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.container]: Behavior.slot({\n requires: { capability: Capability.Interactive },\n // Focus in the tree stays on its stop when an edit elsewhere moves or removes it.\n mount: () => FollowTabStop(),\n attributes: ({\n input,\n h,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n }) => {\n const { model, rows } = prepare(input)\n const direction = options.direction?.(input) ?? 'ltr'\n return [\n h.OnKeyDownFocus((key, modifiers) => {\n const action = move(rows, model.current, key, modifiers, model, args, direction)\n if (action === undefined) return Option.none()\n // Opening or closing keeps focus on the row it acted on.\n const message =\n action._tag === 'Focus'\n ? Message.Focused({ id: action.id })\n : action._tag === 'Open'\n ? Message.Opened({ id: action.id })\n : Message.Closed({ id: action.id })\n return Option.some({\n focusSelector: idSelector(domId(action.id)),\n message: wrap(message),\n })\n }),\n ]\n },\n }),\n [options.item]: Behavior.slot({\n requires: { capability: Capability.Focusable },\n attributes: ({\n input,\n h,\n item,\n }: {\n readonly input: Input\n readonly h: HtmlBuilder<ParentMessage>\n readonly item?: SlotItem\n }) => {\n if (item === undefined) return []\n const { model, rows, byId, stop } = prepare(input)\n const row = item.id === undefined ? rows[item.index] : byId.get(item.id)\n if (row === undefined) return []\n return [\n h.Id(domId(row.id)),\n h.Role('treeitem'),\n h.AriaLevel(row.level),\n h.Style({ '--fk-tree-level': String(row.level) }),\n h.AriaPosinset(row.position),\n h.AriaSetsize(row.siblings),\n ...(row.branch ? [h.AriaExpanded(isOpen(model, args, row.id))] : []),\n ...(row.disabled === true ? [h.AriaDisabled(true)] : []),\n h.Tabindex(stop === row.id ? 0 : -1),\n h.OnFocus(wrap(Message.Focused({ id: row.id }))),\n ]\n },\n }),\n // Keyed by values the caller chose; `forSlots` checks both keys exist.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'TreeNavigation' },\n )\n }\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmBA,MAAa,kBAAkB;AAC/B,MAAa,oBAAoB;AACjC,MAAM,oBAAoB;AAC1B,MAAM,mBAAmB;;AAGzB,MAAaA,UAAQ,OAAO,OAAO;CACjC,IAAI,OAAO;;CAEX,SAAS,OAAO;;CAEhB,QAAQ,OAAO;AACjB,CAAC;AAGD,MAAaC,UAAQ,OAAO,OAAO;;AAEjC,QAAQ,OAAO,MAAMD,OAAK,EAC5B,CAAC;AAGD,MAAaE,YAAU,mBAAmB;;CAExC,WAAW;EAAE,QAAQ,OAAO,MAAMF,OAAK;EAAG,QAAQ,OAAO,MAAM,OAAO,MAAM;CAAE;CAC9E,eAAe,EAAE,QAAQ,OAAO,MAAMA,OAAK,EAAE;AAC/C,CAAC;AAGD,MAAa,UAAU,OAAO,aAAa,WAAW,EAAE,KAAK,OAAO,MAAM,OAAO,MAAM,EAAE,CAAC;;AAI1F,MAAa,aACX,QACA,WAC0B;CAC1B,IAAI,aAAa;CACjB,OAAO,SAAS,OAAO,UAAU;EAC/B,IAAI,OAAO,SAAS,MAAM,EAAE,GAAG,aAAa;CAC9C,CAAC;CACD,OAAO,OACJ,MAAM,aAAa,CAAC,CAAC,CACrB,QAAO,UAAS,MAAM,OAAO,CAAC,CAC9B,KAAI,UAAS,MAAM,EAAE;AAC1B;AAIA,MAAM,cAAc,GAAyB,MAC3C,EAAE,WAAW,EAAE,UACf,EAAE,OACC,OAAO,UACN,MAAM,OAAO,EAAE,MAAM,CAAE,MACvB,MAAM,YAAY,EAAE,MAAM,CAAE,WAC5B,MAAM,WAAW,EAAE,MAAM,CAAE,MAC/B;AAEF,MAAaG,WAAS,OAAO,KAAK,gBAAgB;CAChD,OAAA;CACA,SAAA;CACA,aAAa,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE;CACrC,SAAS,OAAO,YAAoB;EAGlC,MAAM,OAAO,WAAW,MAAM,QAAQ,QAAQ,MAAM,IAAI,QAAQ,EAAE,QAAQ,QAAQ,OAAO;EACzF,OAAOD,UAAQ,MAAc,SAAS;GACpC,YAAY,EAAE,QAAQ,aAAa;IACjC,MAAM,MAAM,UAAU,QAAQ,MAAM;IACpC,OAAO,IAAI,WAAW,IAClB,EAAE,OAAO,KAAK,IACd;KAAE,OAAO;KAAM,YAAY,QAAQ,KAAK,EAAE,IAAI,CAAC;IAAE;GACvD;GACA,gBAAgB,EAAE,aAAa;IAC7B,MAAM,MAAM,OAAO,OAAO,SAAS;IACnC,OAAO,QAAQ,KAAA,KAAa,IAAI,SAC5B;KAAE,OAAO;KAAM,YAAY,QAAQ,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;IAAE,IAC3D,EAAE,OAAO,KAAK;GACpB;EACF,CAAC;CACH;CACA,qBACE,aAAa,KAAqB,CAAC,QAAQ,EACzC,UAAU,aAAa,WAAW,eAAe,CAAC,EACpD,EAAE;AACN,CAAC;AAED,MAAM,cAAc,SAClB,MAAM,KAAK,KAAK,iBAAiB,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,KAAI,aAAY;CACxE,IAAI,QAAQ,aAAA,yBAA4B,KAAK;CAC7C,SAAS,QAAQ,aAAa,iBAAiB,MAAM;CACrD,QAAQ,QAAQ,aAAa,gBAAgB,MAAM;AACrD,EAAE;;AAGJ,MAAa,gBAAgB,SAA4D;CACvF,MAAM,MAAqB,CAAC;CAC5B,KAAK,MAAM,UAAU,MAAM;EACzB,IAAI,EAAE,kBAAkB,UAAU;EAClC,MAAM,KAAK,OAAO,aAAA,yBAA4B,KAAK,OAAO,aAAA,iCAA8B;EACxF,IAAI,OAAO,QAAQ,CAAC,IAAI,SAAS,EAAE,GAAG,IAAI,KAAK,EAAE;CACnD;CACA,OAAO;AACT;;;;;;AAOA,MAAM,uBAA+C;CACnD,IAAI,OAAO,aAAa,aAAa,OAAO,OAAO;CACnD,OAAO,OAAO,UAAkB,UAC9B,OAAO,eACL,OAAO,WAAW;EAChB,MAAM,iBAAiB,UACrB,MAAM,YACJ,OACAA,UAAQ,UAAU;GAChB,QAAQ,WAAW,QAAQ;GAC3B,QAAQ,aAAa,MAAM,aAAa,CAAC;EAC3C,CAAC,CACH;EACF,MAAM,aAAa,UAAiB;GAClC,IAAK,MAAwB,QAAQ,UAAU;GAC/C,MAAM,YAAY,OAAOA,UAAQ,cAAc,EAAE,QAAQ,WAAW,QAAQ,EAAE,CAAC,CAAC;EAClF;EACA,SAAS,iBAAiB,eAAe,eAAe,EAAE,SAAS,KAAK,CAAC;EACzE,SAAS,iBAAiB,WAAW,WAAW,EAAE,SAAS,KAAK,CAAC;EACjE,OAAO;GAAE;GAAe;EAAU;CACpC,CAAC,IACA,EAAE,eAAe,gBAChB,OAAO,WAAW;EAChB,SAAS,oBAAoB,eAAe,eAAe,EAAE,SAAS,KAAK,CAAC;EAC5E,SAAS,oBAAoB,WAAW,WAAW,EAAE,SAAS,KAAK,CAAC;CACtE,CAAC,CACL,CACF;AACF;;;;;;;AAoBA,MAAaE,eACY,eACf,WAEN,YAEA,SAAS,SAAS,KAAK,CAAC,CACtB;EACG,QAAQ,QAAQ,SAAS,KAAK;EAC7B,UAAU,EAAE,YAAY,WAAW,UAAU;EAC7C,aAAa,EACX,OACA,QAII;GACJ,EAAE,UAAU,iBAAiB,QAAQ,GAAG,KAAK,CAAC;GAC9C,GAAI,QAAQ,iBAAiB,QAAQ,CAAC,EAAE,UAAU,mBAAmB,OAAO,CAAC,IAAI,CAAC;GAClF,GAAI,QAAQ,WAAW,QAAQ,CAAC,EAAE,UAAU,kBAAkB,OAAO,CAAC,IAAI,CAAC;EAC7E;CACF,CAAC;CACD,GAAI,QAAQ,YAAY,KAAA,IACpB,CAAC,IACD,GACG,QAAQ,UAAU,SAAS,KAAK;EAC/B,UAAU,EAAE,YAAY,WAAW,YAAY;EAC/C,aAAa,EACX,OACA,QAII,CAAC,EAAE,UAAU,mBAAmB,QAAQ,GAAG,KAAK,CAAC,CAAC;CAC1D,CAAC,EACH;AAEN,GACA,EAAE,MAAM,eAAe,CACzB;;;;;;;;;;;;;;;;;;AC1LJ,MAAaC,eACH,WAEN,YAEA,SAAS,SAAS,KAAK,CAAC,CACtB,GACG,QAAQ,YAAY,SAAS,KAAK;CACjC,UAAU,EAAE,YAAY,WAAW,UAAU;CAC7C,aACE,MAAM,WACJC,aAAkB,EAAE,WAAW,QAAQ,UAAU,CAAC,GAClD,QAAQ,SACV;AACJ,CAAC,EAEH,GACA,EAAE,MAAM,eAAe,CACzB;;;;;;;;;;;;;;;;;;;ACrBJ,MAAaC,eACH,WAEN,YAEA,SAAS,SAAS,KAAK,CAAC,CACtB,GACG,QAAQ,YAAY,SAAS,KAAK;CACjC,UAAU,EAAE,YAAY,WAAW,UAAU;CAC7C,aACEC,WAAgB;EACd,SAAS,QAAQ,WAAW;EAC5B,SAAS,QAAQ,WAAW;EAC5B,cAAc,QAAQ,gBAAgB;CACxC,CAAC;AACL,CAAC,EAEH,GACA,EAAE,MAAM,aAAa,CACvB;;;;;;;;;AC1BJ,MAAaC,eACY,cACf,WAEN,YAEA,SAAS,SAAS,KAAK,CAAC,CACtB,GACG,QAAQ,SAAS,SAAS,KAAK;CAC9B,UAAU,EAAE,YAAY,WAAW,UAAU;CAC7C,aAAa,EACX,OACA,QAKA,MAAM,SAAS,MAAM,CAAC,aAAa,aAC/B,CAAC,EAAE,cAAc,iBAAiB,MAAM,CAAC,IACzC,CAAC;AACT,CAAC,EAEH,GACA,EAAE,MAAM,eAAe,CACzB;;;;;;;;;;;;;;;;;;;;;;AC5BJ,MAAa,cAAc,OAAO,SAAS;CAAC;CAAY;CAAc;AAAM,CAAC;AAG7E,MAAaC,UAAQ,OAAO,OAAO;;AAEjC,SAAS,OAAO,OAAO,OAAO,MAAM,EACtC,CAAC;AAGD,MAAaC,YAAU,mBAAmB;;AAExC,SAAS,EAAE,IAAI,OAAO,OAAO,EAC/B,CAAC;AAGD,MAAaC,SAAO,OAAO,OAAO;CAChC,aAAa;;CAEb,MAAM,OAAO;;;CAGb,SAAS,OAAO;AAClB,CAAC;AAGD,MAAaC,WAAS,OAAO,KAAK,kBAAkB;CAClD,OAAA;CACA,SAAA;CACA,MAAMD;CACN,aAAa,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE;CAExC,SAAS,OAAO,YACd,MAAM,YAAY,QAAQ,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,SAAS,QAAQ,GAAG,EAAE;AAChF,CAAC;AAYD,MAAME,aAAW,cACf,CAAC,UAAU,WAAW,CAAC,UAAU,UAAU,CAAC,UAAU;;;;;;;;AASxD,MAAaC,UACX,SACA,SACA,KACA,WACA,YACuB;CACvB,IAAI,QAAQ,WAAW,KAAK,CAACD,UAAQ,SAAS,GAAG,OAAO,KAAA;CACxD,MAAM,QAAQ,QAAQ;CACtB,MAAM,OAAO,QAAQ,QAAQ,SAAS;CACtC,IAAI,QAAQ,QAAQ,OAAO;CAC3B,IAAI,QAAQ,OAAO,OAAO;CAC1B,IAAI,QAAQ,SAAS,KAAA,MAAc,QAAQ,YAAY,QAAQ,aAAa;EAC1E,MAAM,WAAW,QAAQ,QAAQ,OAAO;EACxC,IAAI,aAAa,IAAI,OAAO,QAAQ,aAAa,QAAQ;EACzD,MAAM,SAAS,YAAY,QAAQ,aAAa,QAAQ,OAAO,CAAC,QAAQ;EACxE,OAAO,QAAQ,KAAK,IAAI,QAAQ,SAAS,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC;CACjE;CACA,MAAM,WAAW,QAAQ,gBAAgB;CACzC,MAAM,aAAa,QAAQ,gBAAgB;CAC3C,MAAM,aAAa,QAAQ,cAAc,QAAQ,cAAc;CAC/D,MAAM,cAAc,QAAQ,cAAc,QAAQ,eAAe;CACjE,MAAM,OACH,YAAY,QAAQ,eAAiB,cAAc,QAAQ,aACxD,IACC,YAAY,QAAQ,aAAe,cAAc,QAAQ,cACxD,KACA;CACR,IAAI,SAAS,GAAG,OAAO,KAAA;CACvB,MAAM,WAAW,QAAQ,QAAQ,OAAO;CACxC,IAAI,aAAa,IAAI,OAAO,SAAS,IAAI,QAAQ;CACjD,MAAM,OAAO,WAAW;CACxB,IAAI,OAAO,GAAG,OAAO,QAAQ,OAAO,OAAO;CAC3C,IAAI,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,OAAO,QAAQ;CAC1D,OAAO,QAAQ;AACjB;;AAGA,MAAaE,aACX,OACA,YACW;CACX,MAAM,QAAQ,YAAY,OAAO,KAAK,MAAM,QAAQ,OAAO;CAC3D,IAAI,UAAU,MAAM,CAAC,MAAM,WAAW,KAAK,GAAG,OAAO;CACrD,OAAO,MAAM,QAAQ,MAAM;AAC7B;;AAaA,MAAa,cAAc,OAAuB,QAAQ,GAAG,QAAQ,UAAU,MAAM,EAAE;;;;;;AAOvF,MAAa,kBACX,GACA,OACA,SACA,MACA,SACA,YAC4C;CAC5C,MAAM,KAAK,KAAK,MAAM,MAAM,IAAI,KAAK;CACrC,IAAI,OAAO,KAAA,GAAW,OAAO,CAAC;CAC9B,MAAM,SAASA,UAAQ,OAAO,OAAO,MAAM,KAAK;CAChD,OAAO,CAAC,GAAI,UAAU,CAAC,IAAI,CAAC,EAAE,SAAS,SAAS,IAAI,EAAE,CAAC,GAAI,EAAE,QAAQ,QAAQ,EAAE,CAAC,CAAC;AACnF;;;;;;;;;;;;AAaA,MAAaC,eACY,UAA0C,UACzD,WAEN,YACwD;CACxD,MAAM,QAAQ,OACZ,SAAS,QAAQ,KAAKN,UAAQ,QAAQ,EAAE,GAAG,CAAC,CAAC;CAC/C,MAAM,SAAS,UAAwB,MAAM,SAAS;CACtD,MAAM,UAAU,SAAS,QAAQ,KAAK;CACtC,OAAO,SAAS,SAAS,KAAK,CAAC,CAC7B;GACG,QAAQ,YAAY,SAAS,KAAK;GACjC,UAAU,EAAE,YAAY,WAAW,YAAY;GAC/C,aAAa,EACX,OACA,QAII;IACJ,MAAM,QAAQ,QAAQ,KAAK;IAC3B,MAAM,UAAU,MAAM,KAAK,CAAC,CAAC;IAC7B,MAAM,OAAO,YAAY,OAAO,KAAK,MAAM,QAAQ,OAAO;IAC1D,MAAM,YAAY,QAAQ,YAAY,KAAK,KAAK;IAChD,MAAM,OAAOK,UAAQ,OAAO,OAAO;IACnC,MAAM,SAAS,SAAS,KAAK,KAAA,IAAY,MAAM,IAAI;IACnD,MAAM,UAAU,KAAa,cAAqD;KAChF,MAAM,OAAOD,OAAK,MAAM,SAAS,MAAM,KAAK,WAAW;MAAE,GAAG;MAAM;KAAU,CAAC;KAC7E,OAAO,SAAS,KAAA,IAAY,KAAA,IAAY,MAAM,IAAI;IACpD;IAEA,IAAI,KAAK,SACP,OAAO,CACL,EAAE,yBAAyB,KAAK,cAC9B,OAAO,IAAI,OAAO,cAAc,OAAO,KAAK,SAAS,CAAC,GAAG,IAAI,CAC/D,GACA,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,CAAC,EAAE,qBAAqB,MAAM,CAAC,CACjE;IAEF,OAAO,CACL,EAAE,gBAAgB,KAAK,cACrB,OAAO,IAAI,OAAO,cAAc,OAAO,KAAK,SAAS,CAAC,IAAG,QAAO;KAC9D,eAAe,WAAW,EAAE;KAC5B,SAAS,KAAK,EAAE;IAClB,EAAE,CACJ,CACF;GACF;EACF,CAAC;GACA,QAAQ,OAAO,SAAS,KAAK;GAC5B,UAAU,EAAE,YAAY,WAAW,UAAU;GAC7C,aAAa,EACX,OACA,GACA,WAKI;IACJ,IAAI,SAAS,KAAA,GAAW,OAAO,CAAC;IAChC,OAAO,eAAe,GAAG,QAAQ,KAAK,GAAG,MAAM,KAAK,CAAC,CAAC,SAAS,MAAM,KAAK,SAAS,IAAI;GACzF;EACF,CAAC;CAEH,GACA,EAAE,MAAM,iBAAiB,CAC3B;AACF;;;;;;;;;;;;;;;;;;;;ACpNF,MAAaG,UAAQ,OAAO,OAAO;;AAEjC,SAAS,OAAO,OAAO,OAAO,MAAM,EACtC,CAAC;AAGD,MAAaC,YAAU,mBAAmB;;AAExC,SAAS,EAAE,IAAI,OAAO,OAAO,EAC/B,CAAC;AAGD,MAAaC,SAAO,OAAO,OAAO;;CAEhC,SAAS,OAAO,OAAO,KAAK,OAAO,MAAM,OAAO,uBAAuB,CAAC,CAAC,CAAC;;;CAG1E,MAAM,OAAO;;;CAGb,SAAS,OAAO;AAClB,CAAC;AAGD,MAAaC,WAAS,OAAO,KAAK,kBAAkB;CAClD,OAAA;CACA,SAAA;CACA,MAAMD;CACN,aAAa,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE;CAExC,SAAS,OAAO,YACd,MAAM,YAAY,QAAQ,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,SAAS,QAAQ,GAAG,EAAE;AAChF,CAAC;;;;;;;;;;;;AAmBD,MAAaE,UACX,SACA,OACA,SACA,KACA,WACA,YACuB;CACvB,IAAI,QAAQ,WAAW,KAAK,UAAU,UAAU,UAAU,SAAS,OAAO,KAAA;CAC1E,MAAM,QAAQ,QAAQ;CACtB,MAAM,OAAO,QAAQ,QAAQ,SAAS;CACtC,MAAM,aAAa,UAAkB,QAAQ,SAAS,KAAK;CAC3D,MAAM,EAAE,YAAY;CACpB,MAAM,OAAO,UAAkB,KAAK,MAAM,QAAQ,OAAO;CAEzD,IAAI,QAAQ,UAAU,QAAQ,OAAO;EACnC,IAAI,UAAU,WAAW,YAAY,IAAI,OAAO,QAAQ,SAAS,QAAQ;EACzE,MAAM,QAAQ,QAAQ,QAAO,UAAS,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC;EACjE,OAAO,QAAQ,SAAU,MAAM,MAAM,UAAY,MAAM,MAAM,SAAS,MAAM;CAC9E;CACA,IAAI,UAAU,SAAS,OAAO,KAAA;CAE9B,MAAM,aAAa,QAAQ,cAAc,QAAQ,cAAc;CAC/D,MAAM,cAAc,QAAQ,cAAc,QAAQ,eAAe;CACjE,MAAM,OACJ,QAAQ,cAAc,QAAQ,cAC1B,QACA,QAAQ,eAAe,QAAQ,YAC7B,WACA,KAAA;CACR,IAAI,SAAS,KAAA,GAAW,OAAO,KAAA;CAC/B,MAAM,OAAO,QAAQ,cAAc,QAAQ,cAAc,IAAI;CAC7D,IAAI,YAAY,IAAI,OAAO,SAAS,IAAI,QAAQ;CAEhD,IAAI,SAAS,OAAO;EAElB,KAAK,IAAI,QAAQ,UAAU,MAAM,SAAS,KAAK,QAAQ,OAAO,SAAS,MAAM;GAC3E,IAAI,CAAC,QAAQ,QAAQ,IAAI,KAAK,MAAM,IAAI,OAAO,GAAG,OAAO;GACzD,IAAI,UAAU,KAAK,GAAG,OAAO;EAC/B;EACA,OAAO;CACT;CAEA,MAAM,SAAS,UAAU;CACzB,KAAK,IAAI,QAAQ,UAAU,OAAO,UAAW,SAAS,OAAO,SAAS;EACpE,IAAI,QAAQ,KAAK,SAAS,OAAO;GAC/B,IAAI,CAAC,QAAQ,MAAM,OAAO;GAC1B,MAAM,aAAa,SAAS;GAC5B,IAAI,aAAa,KAAK,cAAc,SAAS,OAAO;GAEpD,MAAM,QACJ,SAAS,IACL,aACA,aAAa,UAAU,KAAK,OAAO,QAAQ,IAAI,cAAc,OAAO;GAC1E,KAAK,IAAI,OAAO,OAAO,QAAQ,KAAK,OAAO,OAAO,QAAQ,OAAO,SAC/D,IAAI,UAAU,IAAI,GAAG,OAAO;GAE9B,OAAO;EACT;EACA,IAAI,UAAU,KAAK,GAAG,OAAO;CAC/B;AACF;;;;;;;;AAmBA,MAAaC,cACY,UAA0C,UACzD,WAEN,YACwD;CACxD,MAAM,QAAQ,OACZ,SAAS,QAAQ,KAAKJ,UAAQ,QAAQ,EAAE,GAAG,CAAC,CAAC;CAC/C,MAAM,SAAS,UAAwB,MAAM,SAAS;CACtD,MAAM,UAAU,SAAS,QAAQ,KAAK;CACtC,OAAO,SAAS,SAAS,KAAK,CAAC,CAC7B;GACG,QAAQ,YAAY,SAAS,KAAK;GACjC,UAAU,EAAE,YAAY,WAAW,YAAY;GAC/C,aAAa,EACX,OACA,QAII;IACJ,MAAM,QAAQ,QAAQ,KAAK;IAC3B,MAAM,UAAU,MAAM,KAAK,CAAC,CAAC;IAC7B,MAAM,OAAO,YAAY,OAAO,KAAK,MAAM,QAAQ,OAAO;IAC1D,MAAM,YAAY,QAAQ,YAAY,KAAK,KAAK;IAChD,MAAM,OAAOK,UAAuB,OAAO,OAAO;IAClD,MAAM,SAAS,SAAS,KAAK,KAAA,IAAY,MAAM,IAAI;IACnD,MAAM,UAAU,KAAa,cAAqD;KAChF,MAAM,OAAOF,OAAK,MAAM,SAAS,MAAM,MAAM,MAAM,KAAK,WAAW;MACjE,SAAS,KAAK;MACd,MAAM,KAAK;MACX;KACF,CAAC;KACD,OAAO,SAAS,KAAA,IAAY,KAAA,IAAY,MAAM,IAAI;IACpD;IACA,IAAI,KAAK,SACP,OAAO,CACL,EAAE,yBAAyB,KAAK,cAC9B,OAAO,IAAI,OAAO,cAAc,OAAO,KAAK,SAAS,CAAC,GAAG,IAAI,CAC/D,GACA,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,CAAC,EAAE,qBAAqB,MAAM,CAAC,CACjE;IAEF,OAAO,CACL,EAAE,gBAAgB,KAAK,cACrB,OAAO,IAAI,OAAO,cAAc,OAAO,KAAK,SAAS,CAAC,IAAG,QAAO;KAC9D,eAAeG,WAA0B,EAAE;KAC3C,SAAS,KAAK,EAAE;IAClB,EAAE,CACJ,CACF;GACF;EACF,CAAC;GACA,QAAQ,OAAO,SAAS,KAAK;GAC5B,UAAU,EAAE,YAAY,WAAW,UAAU;GAC7C,aAAa,EACX,OACA,GACA,WAKI;IACJ,IAAI,SAAS,KAAA,GAAW,OAAO,CAAC;IAChC,OAAOC,eACL,GACA,QAAQ,KAAK,GACb,MAAM,KAAK,CAAC,CAAC,SACb,MACA,KAAK,SACL,IACF;GACF;EACF,CAAC;CAEH,GACA,EAAE,MAAM,iBAAiB,CAC3B;AACF;;;;;;;;;ACvNF,MAAM,WACH,MAAc,WACP,WACe,YAGrB,SAAS,SAAS,KAAK,CAAC,CACtB,GACG,QAAQ,YAAY,SAAS,KAAK;CACjC,UAAU,EAAE,YAAY,WAAW,UAAU;CAC7C;AACF,CAAC,EAEH,GACA,EAAE,KAAK,CACT;;AAGJ,MAAa,aAAa,QAAQ,oBAAoBC,WAAgB,CAAC;;AAGvE,MAAa,cAAc,QAAQ,qBAAqBC,YAAiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;AClB1E,MAAa,aAAa,OAAO,SAAS,CAAC,UAAU,WAAW,CAAC;AAGjE,MAAaC,UAAQ,OAAO,OAAO;CACjC,QAAQ,OAAO;CACf,WAAW,OAAO;;CAElB,SAAS,OAAO,OAAO,OAAO,OAAO;EAAE,SAAS,OAAO;EAAQ,YAAY;CAAW,CAAC,CAAC;CACxF,YAAY,OAAO;AACrB,CAAC;AAGD,MAAaC,YAAU,mBAAmB;CACxC,WAAW;EAAE,SAAS,OAAO;EAAQ,YAAY;CAAW;CAC5D,MAAM,EAAE,YAAY,OAAO,OAAO;CAClC,SAAS,EAAE,YAAY,OAAO,OAAO;AACvC,CAAC;AAGD,MAAM,WAAW,OAAO,OAAO,KAC7B,OAAO,MAAM,OAAO,uBAAuB,CAAC,CAAC,GAC7C,OAAO,MAAM,OAAO,SAAS,CAAC,CAChC;AAEA,MAAaC,SAAO,OAAO,OAAO;;CAEhC,YAAY;;CAEZ,cAAc;AAChB,CAAC;AAGD,MAAM,OAAO;;AAGb,MAAa,UAAU,SAAiB,SACtC,YAAY,OAAO,GAAG,OAAO,SAAS,YAAY,GAAG,OAAO,SAAS,OAAO;AAI9E,MAAM,SAAS,IAAY,SAAkB,MAAc,gBAAwB;CACjF;CACA,MAAM,EAAE,WAAW;CACnB,QAAQ,OAAO,GAAG,OAAO,MAAM,EAAE,GAAG,OAAO;AAC7C;AAEA,MAAaC,WAAS,OAAO,KAAK,gBAAgB;CAChD,OAAA;CACA,SAAA;CACA,MAAMD;CACN,aAAa,EAAE,OAAO;EAAE,QAAQ;EAAI,WAAW;EAAI,SAAS;EAAM,YAAY;CAAE,EAAE;CAClF,SAAS,OAAO,SAAS,SACvBD,UAAQ,MAAc,SAAS;EAC7B,YAAY,EAAE,SAAS,MAAM,iBAAiB;GAC5C,MAAM,aAAa,MAAM,aAAa;GACtC,OAAO;IACL,OAAO;KAAE,GAAG;KAAO,SAAS;MAAE,SAAS;MAAM;KAAW;KAAG;IAAW;IACtE,UAAU,CACR,MAAM,KAAK,YAAYA,UAAQ,KAAK,EAAE,WAAW,CAAC,GAAG,qBAAqB,UAAU,CACtF;GACF;EACF;EACA,OAAO,EAAE,iBAAiB;GACxB,IAAI,eAAe,MAAM,cAAc,MAAM,YAAY,MAAM,OAAO,EAAE,MAAM;GAC9E,MAAM,EAAE,SAAS,MAAM,eAAe,MAAM;GAC5C,MAAM,SAAS,eAAe,WAAW,WAAW;GACpD,OAAO;IACL,OAAO;KAAE,GAAG;KAAO,SAAS;MAAO,SAAS,OAAO,MAAM,SAAS,IAAI;IAAE;IACxE,UAAU,CACR,MACE,KAAK,cACLA,UAAQ,QAAQ,EAAE,WAAW,CAAC,GAC9B,sBACA,UACF,CACF;GACF;EACF;EACA,UAAU,EAAE,iBACV,eAAe,MAAM,aACjB,EAAE,OAAO;GAAE,GAAG;GAAO,QAAQ;GAAI,WAAW;EAAG,EAAE,IACjD,EAAE,MAAM;CAChB,CAAC;AACL,CAAC;;AAGD,MAAa,OACY,cACP,MAAc,aAAyB,aACrD,SAAS,QAAQ,KACfA,UAAQ,UAAU;CAAE,SAAS;CAAM;AAAW,CAAC,CACjD;AAEJ,MAAa,mBAAmB;;;;;;AAOhC,MAAa,QAAuB,OAAc,MAChD,EAAE,IACA,CAAC,EAAE,UAAU,kBAAkB,SAAS,CAAC,GACzC,CACE,EAAE,IACA;CAAC,EAAE,UAAU,kBAAkB,QAAQ;CAAG,EAAE,SAAS,QAAQ;CAAG,EAAE,WAAW,IAAI;AAAC,GAClF,CAAC,MAAM,MAAM,CACf,GACA,EAAE,IACA;CAAC,EAAE,UAAU,kBAAkB,WAAW;CAAG,EAAE,SAAS,WAAW;CAAG,EAAE,WAAW,IAAI;AAAC,GACxF,CAAC,MAAM,SAAS,CAClB,CACF,CACF;;;;;;;;;;;;;;;;;;ACjHF,MAAaG,UAAQ,OAAO,OAAO;CACjC,OAAO,OAAO;;;CAGd,YAAY,OAAO;AACrB,CAAC;AAGD,MAAaC,YAAU,mBAAmB;;CAExC,OAAO,EAAE,MAAM,OAAO,OAAO;;CAE7B,SAAS,EAAE,YAAY,OAAO,OAAO;;CAErC,SAAS,CAAC;AACZ,CAAC;AAGD,MAAaC,SAAO,OAAO,OAAO;;AAEhC,WAAW,OAAO,OAAO,KACvB,OAAO,MAAM,OAAO,cAAc,CAAC,CAAC,GACpC,OAAO,MAAM,OAAO,SAAS,CAAC,CAChC,EACF,CAAC;AAGD,MAAaC,WAAS,OAAO,KAAK,aAAa;CAC7C,OAAA;CACA,SAAA;CACA,MAAMD;CACN,aAAa,EAAE,OAAO;EAAE,OAAO;EAAI,YAAY;CAAE,EAAE;CACnD,SAAS,OAAO,SAAS,SACvBD,UAAQ,MAAqC,SAAS;EACpD,QAAQ,EAAE,WAAW;GACnB,MAAM,aAAa,MAAM,aAAa;GACtC,OAAO;IACL,OAAO;KAAE,OAAO,MAAM,QAAQ;KAAM;IAAW;IAC/C,UAAU,CACR;KACE,MAAM;KACN,MAAM,EAAE,WAAW;KACnB,QAAQ,OAAO,GAAG,OAAO,MAAM,KAAK,SAAS,GAAGA,UAAQ,QAAQ,EAAE,WAAW,CAAC,CAAC;IACjF,CACF;GACF;EACF;EACA,UAAU,EAAE,iBACV,eAAe,MAAM,aAAa,WAAW,KAAK,IAAI,EAAE,MAAM;EAChE,eAAe,WAAW,KAAK;CACjC,CAAC;AACL,CAAC;AAED,MAAM,aAAa,SAAyB,KAAK,UAAU,CAAC,CAAC,kBAAkB;AAE/E,MAAM,cAAc,UAClB,MAAM,SAAS,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,OAAM,SAAQ,SAAS,MAAM,EAAE;;;;;;;;;AAUhE,MAAa,SACX,OACA,SACA,OACA,YACuB;CACvB,IAAI,UAAU,MAAM,QAAQ,WAAW,GAAG,OAAO,KAAA;CACjD,MAAM,SAAS,UAAU,WAAW,KAAK,IAAI,MAAM,KAAM,KAAK;CAC9D,MAAM,WAAW,QAAQ,QAAQ,OAAO;CACxC,MAAM,aAAa,OAAO,WAAW,KAAK,WAAW,KAAK;CAC1D,MAAM,QAAQ,aAAa,KAAK,IAAI,aAAa,WAAW,IAAI;CAChE,KAAK,IAAI,SAAS,GAAG,SAAS,QAAQ,QAAQ,UAAU,GAAG;EACzD,MAAM,QAAQ,SAAS,QAAQ,UAAU,QAAQ;EACjD,IAAI,UAAU,MAAM,UAAU,EAAE,CAAC,CAAC,WAAW,MAAM,GAAG,OAAO;CAC/D;AAEF;;AAGA,MAAa,eAAe,KAAa,cACvC,IAAI,WAAW,KAAK,CAAC,UAAU,WAAW,CAAC,UAAU,UAAU,CAAC,UAAU;;;;;;;;AAoB5E,MAAaG,cACY,cACf,WAEN,YACwD;CACxD,MAAM,QAAQ,SACZ,SAAS,QAAQ,KAAKH,UAAQ,MAAM,EAAE,KAAK,CAAC,CAAC;CAC/C,OAAO,SAAS,SAAS,KAAK,CAAC,CAC7B,GACG,QAAQ,OAAO,SAAS,KAAK;EAC5B,UAAU,EAAE,YAAY,WAAW,YAAY;EAC/C,aAAa,EACX,OACA,QAII;GACJ,MAAM,QAAQ,QAAQ,MAAM,KAAK;GACjC,MAAM,QAAQ,MAAM,SAAS,MAAM,CAAC;GACpC,MAAM,YAAY,QAAQ,QAAQ,KAAK;GACvC,MAAM,UAAU,cAAc,OAAO,KAAK,MAAM,QAAQ,SAAS;GACjE,OAAO,CACL,EAAE,gBAAgB,KAAK,cAAc;IACnC,IAAI,CAAC,YAAY,KAAK,SAAS,GAAG,OAAO,OAAO,KAAK;IACrD,IAAI,QAAQ,OAAO,UAAU,IAAI,OAAO,OAAO,KAAK;IAEpD,MAAM,QAAQ,MAAM,IAAI,KAAK,GAAG,UAAU,QAAQ,KAAK,OAAO,KAAK,CAAC;IACpE,MAAM,QAAQ,MAAM,OAAO,MAAM,SAAS,QAAQ,KAAK,OAAO;IAC9D,MAAM,SAAS,UAAU,KAAA,IAAY,YAAY,MAAM,IAAI;IAC3D,OAAO,OAAO,KAAK;KAGjB,eACE,WAAW,QAAQ,WAAW,KAAA,IAAY,YAAY,WAAW,MAAM;KACzE,SAAS,KAAK,GAAG;IACnB,CAAC;GACH,CAAC,CACH;EACF;CACF,CAAC,EAEH,GACA,EAAE,MAAM,YAAY,CACtB;AACF;;;;;;;;;;;;;;;;;;;ACrJF,MAAaI,UAAQ,OAAO,OAAO;CACjC,SAAS,OAAO,OAAO,OAAO,MAAM;CACpC,OAAO,OAAO;CACd,YAAY,OAAO;AACrB,CAAC;AAGD,MAAaC,YAAU,mBAAmB;;CAExC,SAAS,EAAE,IAAI,OAAO,OAAO;;CAE7B,OAAO;EAAE,MAAM,OAAO;EAAQ,OAAO,OAAO,OAAO,OAAO,MAAM;CAAE;CAClE,SAAS,EAAE,YAAY,OAAO,OAAO;CACrC,SAAS,CAAC;AACZ,CAAC;AAGD,MAAaC,SAAO,OAAO,OAAO;CAChC,aAAaC;CACb,MAAM,OAAO;CACb,SAAS,OAAO;;CAEhB,WAAW,OAAO,OAAO,KACvB,OAAO,MAAM,OAAO,cAAc,CAAC,CAAC,GACpC,OAAO,MAAM,OAAO,SAAS,CAAC,CAChC;;CAEA,MAAM,OAAO,OAAO,KAAK,OAAO,MAAM,OAAO,MAAM,CAAC,GAAG,OAAO,MAAM,OAAO,cAAc,CAAC,CAAC,CAAC;AAC9F,CAAC;AAGD,MAAaC,WAAS,OAAO,KAAK,kBAAkB;CAClD,OAAA;CACA,SAAA;CACA,MAAMF;CACN,aAAa,EAAE,OAAO;EAAE,SAAS;EAAM,OAAO;EAAI,YAAY;CAAE,EAAE;CAClE,SAAS,OAAO,SAAS,SACvBD,UAAQ,MAAqC,SAAS;EAEpD,UAAU,EAAE,SACV,MAAM,YAAY,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO;GAAE,GAAG;GAAO,SAAS;EAAG,EAAE;EACxE,QAAQ,EAAE,MAAM,YAAY;GAC1B,MAAM,aAAa,MAAM,aAAa;GACtC,OAAO;IACL,OAAO;KAAE,SAAS,SAAS,MAAM;KAAS,OAAO,MAAM,QAAQ;KAAM;IAAW;IAChF,UAAU,CACR;KACE,MAAM;KACN,MAAM,EAAE,WAAW;KACnB,QAAQ,OAAO,GAAG,OAAO,MAAM,KAAK,SAAS,GAAGA,UAAQ,QAAQ,EAAE,WAAW,CAAC,CAAC;IACjF,CACF;GACF;EACF;EACA,UAAU,EAAE,iBACV,eAAe,MAAM,aAAa,WAAW,KAAK,IAAI,EAAE,MAAM;EAChE,eAAe,WAAW,KAAK;CACjC,CAAC;AACL,CAAC;AAoBD,MAAa,cACX,OACA,OACA,OACA,KACA,WACA,YAC2B;CAC3B,MAAM,OAAO,MAAM,YAAY,OAAO,KAAK,MAAM,QAAQ,MAAM,OAAO;CACtE,MAAM,QAAQI,OAAoB,MAAM,SAAS,MAAM,KAAK,WAAW,OAAO;CAC9E,MAAM,UAAU,UAAU,KAAA,IAAY,KAAA,IAAY,MAAM,IAAI;CAC5D,IAAI,YAAY,KAAA,GAAW,OAAO;EAAE,MAAM;EAAY,IAAI;CAAQ;CAClE,IAAI,CAACC,YAAsB,KAAK,SAAS,GAAG,OAAO,KAAA;CACnD,IAAI,QAAQ,OAAO,MAAM,UAAU,IAAI,OAAO,KAAA;CAC9C,MAAM,QAAQC,MAAgB,OAAO,MAAM,SAAS,MAAM,QAAQ,KAAK,IAAI;CAC3E,OAAO;EAAE,MAAM;EAAQ,MAAM;EAAK,OAAO,UAAU,KAAA,IAAY,OAAQ,MAAM,IAAI,UAAU;CAAM;AACnG;;;;;;;;AASA,MAAaC,cACY,UAA0C,UACzD,WAEN,YACwD;CACxD,MAAM,QAAQ,YACZ,SAAS,QAAQ,KAAK,OAAO;CAC/B,MAAM,WAAW,OAA8B,KAAKP,UAAQ,QAAQ,EAAE,GAAG,CAAC,CAAC;CAC3E,MAAM,SAAS,UAAwB,MAAM,SAAS;CACtD,MAAM,UAAU,SAAS,QAAQ,KAAK;CACtC,MAAM,kBAAkB,YACtB,QAAQ,SAAS,aACb,QAAQ,QAAQ,EAAE,IAClB,KAAKA,UAAQ,MAAM;EAAE,MAAM,QAAQ;EAAM,OAAO,QAAQ;CAAM,CAAC,CAAC;CACtE,OAAO,SAAS,SAAS,KAAK,CAAC,CAC7B;GACG,QAAQ,YAAY,SAAS,KAAK;GACjC,UAAU,EAAE,YAAY,WAAW,YAAY;GAC/C,aAAa,EACX,OACA,QAII;IACJ,MAAM,QAAQ,QAAQ,KAAK;IAC3B,MAAM,QAAQ,MAAM,KAAK;IACzB,MAAM,cAA0C;KAC9C,aAAa,KAAK;KAClB,MAAM,KAAK;KACX,WAAW,QAAQ,YAAY,KAAK,KAAK;KACzC,MAAM,KAAK;IACb;IACA,MAAM,WAAW,KAAa,cAC5B,OAAO,cACL,WACE,OAEA,MAAM,IAAI,KAAK,GAAG,UAAU,QAAQ,KAAK,OAAO,KAAK,CAAC,GACtD,OACA,KACA,WACA,WACF,CACF;IACF,MAAM,OAAOQ,UAAuB,OAAO,MAAM,OAAO;IACxD,MAAM,SAAS,SAAS,KAAK,KAAA,IAAY,MAAM,IAAI;IACnD,IAAI,KAAK,SACP,OAAO,CACL,EAAE,yBAAyB,KAAK,cAC9B,OAAO,IAAI,QAAQ,KAAK,SAAS,GAAG,cAAc,CACpD,GACA,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,CAAC,EAAE,qBAAqB,MAAM,CAAC,CACjE;IAEF,OAAO,CACL,EAAE,gBAAgB,KAAK,cACrB,OAAO,IAAI,QAAQ,KAAK,SAAS,IAAG,WAAU;KAC5C,MAAM,SACJ,OAAO,SAAS,aAAa,OAAO,KAAM,OAAO,SAAS,MAAM;KAClE,OAAO;MAGL,eAAe,WAAW,OAAO,YAAYC,WAA0B,MAAM;MAC7E,SAAS,eAAe,MAAM;KAChC;IACF,CAAC,CACH,CACF;GACF;EACF,CAAC;GACA,QAAQ,OAAO,SAAS,KAAK;GAC5B,UAAU,EAAE,YAAY,WAAW,UAAU;GAC7C,aAAa,EACX,OACA,GACA,WAMA,SAAS,KAAA,IACL,CAAC,IACDC,eACE,GACA,QAAQ,KAAK,GACb,MAAM,KAAK,CAAC,CAAC,SACb,MACA,KAAK,SACL,OACF;EACR,CAAC;CAEH,GACA,EAAE,MAAM,iBAAiB,CAC3B;AACF;;;;;;;;;;;;;;;;;;;;;;AC1MF,MAAa,cAAc,OAAO,SAAS;CAAC;CAAS;CAAS;CAAO;CAAY;AAAS,CAAC;AAG3F,MAAaC,UAAQ,OAAO,OAAO;;CAEjC,SAAS,OAAO;;CAEhB,WAAW,OAAO,OAAO,OAAO,MAAM;;CAEtC,KAAK,OAAO,OAAO,OAAO,MAAM;;CAEhC,aAAa,OAAO,OAAO,OAAO,MAAM;CACxC,YAAY,OAAO;AACrB,CAAC;AAGD,MAAaC,YAAU,mBAAmB;CACxC,aAAa;EAAE,WAAW,OAAO;EAAQ,QAAQ,OAAO;EAAQ,aAAa,OAAO;CAAO;CAC3F,WAAW;EAAE,WAAW,OAAO;EAAQ,aAAa,OAAO;EAAQ,UAAU,OAAO;CAAQ;CAC5F,kBAAkB,EAAE,WAAW,OAAO,OAAO;CAC7C,SAAS;EAAE,KAAK,OAAO;EAAQ,QAAQ,OAAO;CAAQ;CACtD,OAAO;EAAE,KAAK,OAAO;EAAQ,UAAU,OAAO;CAAQ;;CAEtD,SAAS;EAAE,QAAQ,OAAO;EAAQ,UAAU,OAAO;CAAQ;CAC3D,cAAc,EAAE,YAAY,OAAO,OAAO;AAC5C,CAAC;AAGD,MAAa,UAAU,OAAO,aAAa,WAAW;CACpD,aAAa;;CAEb,UAAU,OAAO;AACnB,CAAC;AAGD,MAAaC,SAAO,OAAO,OAAO;;AAEhC,oBAAoB,OAAO,OAAO,KAChC,OAAO,MAAM,OAAO,uBAAuB,CAAC,CAAC,GAC7C,OAAO,MAAM,OAAO,SAAS,CAAC,CAChC,EACF,CAAC;AAGD,MAAM,QAAQ,WAAyB;CAAE,GAAG;CAAO,SAAS;CAAO,WAAW;CAAM,KAAK;AAAK;AAE9F,MAAMC,qBAAmB,QAAyB,QAAQ,WAAW,QAAQ;AAE7E,MAAM,iBAAiB,QACrB,QAAQ,WAAW,QAAQ,QAAQ,MAAM;AAI3C,MAAaC,WAAS,OAAO,KAAK,SAAS;CACzC,OAAA;CACA,SAAA;CACA,MAAMF;CACN,aAAa,EACX,OAAO;EAAE,SAAS;EAAO,WAAW;EAAM,KAAK;EAAM,aAAa;EAAM,YAAY;CAAE,EACxF;CACA,SAAS,OAAO,SAAS,SACvBD,UAAQ,MAAc,SAAS;EAC7B,cAAc,EAAE,WAAW,aACzB,WAAW,KAAK,MAAM,cAAc,OAChC,EAAE,MAAM,IACR,EAAE,OAAO;GAAE,GAAG;GAAO,SAAS;GAAM;EAAU,EAAE;EACtD,YAAY,EAAE,WAAW,aAAa,eAAe;GACnD,IAAI,MAAM,cAAc,WAAW,OAAO,EAAE,MAAM;GAClD,MAAM,aAAa,MAAM,aAAa;GACtC,OAAO;IACL,OAAO;KAAE,GAAG,KAAK,KAAK;KAAG,aAAa;KAAY;IAAW;IAC7D,UAAU,CACR;KACE,MAAM;KACN,MAAM,EAAE,WAAW;KACnB,QAAQ,OAAO,GACb,OAAO,MAAM,KAAK,kBAAkB,GACpCA,UAAQ,aAAa,EAAE,WAAW,CAAC,CACrC;IACF,CACF;IACA,YAAY,QAAQ,KAAK;KAAE,aAAa,cAAc,WAAW;KAAG;IAAS,CAAC;GAChF;EACF;EACA,mBAAmB,EAAE,gBACnB,MAAM,cAAc,YAAY,EAAE,OAAO,KAAK,KAAK,EAAE,IAAI,EAAE,MAAM;EACnE,UAAU,EAAE,KAAK,aACf,CAACE,kBAAgB,GAAG,KAAK,UAAU,MAAM,QAAQ,QAAQ,MAAM,cAAc,OACzE,EAAE,MAAM,IACR,EAAE,OAAO;GAAE,GAAG;GAAO,SAAS;GAAM;EAAI,EAAE;EAChD,QAAQ,EAAE,KAAK,eACb,MAAM,QAAQ,MACV;GAAE,OAAO,KAAK,KAAK;GAAG,YAAY,QAAQ,KAAK;IAAE,aAAa;IAAY;GAAS,CAAC;EAAE,IACtF,EAAE,MAAM;EACd,UAAU,EAAE,QAAQ,eAClB,WAAW,IACP;GAAE;GAAO,YAAY,QAAQ,KAAK;IAAE,aAAa;IAAW;GAAS,CAAC;EAAE,IACxE,MAAM,gBAAgB,OACpB,EAAE,MAAM,IACR;GAAE;GAAO,YAAY,QAAQ,KAAK;IAAE,aAAa;IAAS;GAAS,CAAC;EAAE;EAC9E,eAAe,EAAE,iBACf,MAAM,gBAAgB,aAAa,EAAE,OAAO;GAAE,GAAG;GAAO,aAAa;EAAK,EAAE,IAAI,EAAE,MAAM;CAC5F,CAAC;AACL,CAAC;;;;;;;;AAmBD,MAAa,SAAS,MAAM,aAAa,eAAe;CACtD,UAAU;EACRF,UAAQ;EACRA,UAAQ;EACRA,UAAQ;EACRA,UAAQ;EACRA,UAAQ;EACRA,UAAQ;CACV;CACA,UAAU,EAAE,cACV,OAAO,UAAe,UACpB,OAAO,eACL,OAAO,WAAW;EAChB,MAAM,SAAS,YAAkB;GAC/B,IAAI,QAAQ,aAAa,eAAe,MAAM,QAAQ;GACtD,MAAM,YAAY,OAAO,OAAO;EAClC;EACA,MAAM,YAAsE;GAC1E,CACE,gBACA,UAAS;IACP,MAAM,UAAU;IAChB,MACEA,UAAQ,YAAY;KAClB,WAAW,QAAQ,aAAa;KAChC,QAAQ,QAAQ,UAAU;KAC1B,aAAa,QAAQ,eAAe;IACtC,CAAC,CACH;GACF,CACF;GACA,CACE,cACA,UAAS;IACP,MAAM,UAAU;IAChB,MACEA,UAAQ,UAAU;KAChB,WAAW,QAAQ,aAAa;KAChC,aAAa,QAAQ,eAAe;KACpC,UAAU,QAAQ,YAAY;IAChC,CAAC,CACH;GACF,CACF;GACA,CACE,iBACA,UACE,MACEA,UAAQ,iBAAiB,EAAE,WAAY,MAAsB,aAAa,EAAE,CAAC,CAC/E,CACJ;GACA,CACE,kBACA,UACE,MACEA,UAAQ,iBAAiB,EAAE,WAAY,MAAsB,aAAa,EAAE,CAAC,CAC/E,CACJ;GACA,CACE,YACA,UAAS;IACP,MAAM,MAAM;IACZ,IAAIE,kBAAgB,IAAI,GAAG,GAAG,IAAI,eAAe;IACjD,MAAMF,UAAQ,QAAQ;KAAE,KAAK,IAAI;KAAK,QAAQ,IAAI;IAAO,CAAC,CAAC;GAC7D,CACF;GACA,CACE,UACA,UAAS;IACP,MAAM,MAAM;IACZ,MAAMA,UAAQ,MAAM;KAAE,KAAK,IAAI;KAAK,UAAU,IAAI;IAAS,CAAC,CAAC;GAC/D,CACF;GACA,CACE,UACA,UAAS;IACP,MAAM,QAAQ;IACd,MACEA,UAAQ,QAAQ;KAAE,QAAQ,MAAM,UAAU;KAAG,UAAU,MAAM,YAAY;IAAM,CAAC,CAClF;GACF,CACF;EACF;EACA,KAAK,MAAM,CAAC,MAAM,aAAa,WAAW,QAAQ,iBAAiB,MAAM,QAAQ;EACjF,OAAO;CACT,CAAC,IACD,cACE,OAAO,WAAW;EAChB,KAAK,MAAM,CAAC,MAAM,aAAa,WAAW,QAAQ,oBAAoB,MAAM,QAAQ;CACtF,CAAC,CACL,CACF;AACJ,CAAC;;;;;;;AAcD,MAAaI,cACY,cACf,WAEN,YAEA,SAAS,SAAS,KAAK,CAAC,CACtB,GACG,QAAQ,SAAS,SAAS,KAAK;CAC9B,UAAU,EAAE,YAAY,WAAW,YAAY;CAC/C,aAAa,EACX,OACA,QAII,CACJ,GAAI,MAAM,SAAS,MAAM,CAAC,UAAU,CAAC,EAAE,cAAc,WAAW,MAAM,CAAC,IAAI,CAAC,GAC5E,GAAI,QAAQ,WAAW,KAAK,MAAM,OAAO,CAAC,EAAE,aAAa,IAAI,CAAC,IAAI,CAAC,CACrE;CACA,aACE,MAAM,WACJ,OAAO,IACN,YACC,SAAS,QAAQ,KAAK,OAAO,CACjC;AACJ,CAAC,EAEH,GACA,EAAE,MAAM,QAAQ,CAClB;;;;;;;;;;;;;;;;;;ACnQJ,MAAaC,UAAQ,OAAO,OAAO;;CAEjC,SAAS,OAAO;CAChB,WAAW,OAAO,OAAO,OAAO,MAAM;CACtC,KAAK,OAAO,OAAO,OAAO,MAAM;CAChC,YAAY,OAAO;AACrB,CAAC;AAGD,MAAaC,YAAU,mBAAmB;CACxC,aAAa;EAAE,WAAW,OAAO;EAAQ,QAAQ,OAAO;EAAQ,aAAa,OAAO;CAAO;CAC3F,WAAW;EAAE,WAAW,OAAO;EAAQ,aAAa,OAAO;EAAQ,UAAU,OAAO;CAAQ;CAC5F,kBAAkB,EAAE,WAAW,OAAO,OAAO;CAC7C,SAAS;EAAE,KAAK,OAAO;EAAQ,QAAQ,OAAO;CAAQ;CACtD,OAAO;EAAE,KAAK,OAAO;EAAQ,UAAU,OAAO;CAAQ;CACtD,SAAS;EAAE,QAAQ,OAAO;EAAQ,UAAU,OAAO;CAAQ;CAC3D,SAAS;EAAE,YAAY,OAAO;EAAQ,aAAaC;CAAkB;AACvE,CAAC;AAGD,MAAa,cAAc,OAAO,aAAa,eAAe,EAAE,aAAaA,YAAkB,CAAC;AAGhG,MAAaC,SAAO,OAAO,OAAO,EAChC,aAAa,OAAO,OAAO,KACzB,OAAO,MAAM,OAAO,cAAc,CAAC,CAAC,GACpC,OAAO,MAAM,OAAO,SAAS,CAAC,CAChC,EACF,CAAC;AAGD,MAAM,mBAAmB,QAAyB,QAAQ,WAAW,QAAQ;AAE7E,MAAM,YAAY,WAAyB;CAAE,GAAG;CAAO,SAAS;CAAO,WAAW;CAAM,KAAK;AAAK;AAIlG,MAAM,SACJ,OACA,MACA,IACA,gBACW;CACX,MAAM,aAAa,MAAM,aAAa;CACtC,OAAO;EACL,OAAO;GACL,SAAS;GACT,WAAW,eAAe,KAAK,GAAG,YAAY;GAC9C,KAAK,SAAS,KAAK,GAAG,MAAM;GAC5B;EACF;EACA,UAAU,CACR;GACE,MAAM;GACN,MAAM,EAAE,WAAW;GACnB,QAAQ,OAAO,GACb,OAAO,MAAM,KAAK,WAAW,GAC7BF,UAAQ,QAAQ;IAAE;IAAY;GAAY,CAAC,CAC7C;EACF,CACF;CACF;AACF;AAEA,MAAaG,WAAS,OAAO,KAAK,aAAa;CAC7C,OAAA;CACA,SAAA;CACA,MAAMD;CACN,aAAa,EAAE,OAAO;EAAE,SAAS;EAAO,WAAW;EAAM,KAAK;EAAM,YAAY;CAAE,EAAE;CACpF,SAAS,OAAO,SAAS,SACvBF,UAAQ,MAAc,SAAS;EAC7B,cAAc,EAAE,WAAW,QAAQ,kBACjC,WAAW,KAAK,MAAM,UAClB,EAAE,MAAM,IACR,MACE,OACA,MACA,EAAE,UAAU,GACZ,gBAAgB,WAAW,gBAAgB,QAAQ,cAAc,OACnE;EACN,YAAY,EAAE,gBACZ,MAAM,cAAc,YAAY,EAAE,OAAO,SAAS,KAAK,EAAE,IAAI,EAAE,MAAM;EACvE,mBAAmB,EAAE,gBACnB,MAAM,cAAc,YAAY,EAAE,OAAO,SAAS,KAAK,EAAE,IAAI,EAAE,MAAM;EACvE,UAAU,EAAE,KAAK,aACf,CAAC,gBAAgB,GAAG,KAAK,UAAU,MAAM,UACrC,EAAE,MAAM,IACR,MAAM,OAAO,MAAM,EAAE,IAAI,GAAG,UAAU;EAC5C,QAAQ,EAAE,UAAW,MAAM,QAAQ,MAAM,EAAE,OAAO,SAAS,KAAK,EAAE,IAAI,EAAE,MAAM;EAC9E,gBAAgB,EAAE,MAAM;EACxB,UAAU,EAAE,YAAY,kBACtB,MAAM,WAAW,MAAM,eAAe,aAClC;GAAE,OAAO,SAAS,KAAK;GAAG,YAAY,YAAY,KAAK,EAAE,YAAY,CAAC;EAAE,IACxE,EAAE,MAAM;CAChB,CAAC;AACL,CAAC;;;;;;;AAYD,MAAaI,cACY,cACf,WAEN,YAEA,SAAS,SAAS,KAAK,CAAC,CACtB,GACG,QAAQ,SAAS,SAAS,KAAK;CAC9B,UAAU,EAAE,YAAY,WAAW,YAAY;CAC/C,aAAa,EACX,OACA,QAIK,MAAM,SAAS,MAAM,CAAC,UAAU,CAAC,EAAE,cAAc,WAAW,MAAM,CAAC,IAAI,CAAC;CAC/E,aACE,MAAM,WACJC,OAAa,IAEZ,SACC,SAAS,QAAQ,KAAK,IAA0B,CACpD;AACJ,CAAC,EAEH,GACA,EAAE,MAAM,YAAY,CACtB;;;;;;;;;;;;;;;;ACrIJ,MAAaC,cACH,WAEN,YAEA,SAAS,SAAS,KAAK,CAAC,CACtB,GACG,QAAQ,SAAS,SAAS,KAAK;CAC9B,UAAU,EAAE,YAAY,WAAW,UAAU;CAC7C,aAAa,MAAM,WAAWC,KAAU,GAAG,QAAQ,SAAS;AAC9D,CAAC,EAEH,GACA,EAAE,MAAM,OAAO,CACjB;;;;;;;;;;;;;;;;;;;;;AChBJ,MAAa,OAAO,OAAO,SAAS;CAAC;CAAU;CAAY;AAAM,CAAC;AAGlE,MAAaC,UAAQ,OAAO,OAAO;;CAEjC,UAAU,OAAO,MAAM,OAAO,MAAM;;CAEpC,QAAQ,OAAO,OAAO,OAAO,MAAM;AACrC,CAAC;AAGD,MAAaC,YAAU,mBAAmB;;CAExC,WAAW,EAAE,IAAI,OAAO,OAAO;;CAE/B,QAAQ;EAAE,IAAI,OAAO;EAAQ,OAAO,OAAO,MAAM,OAAO,MAAM;CAAE;CAChE,UAAU,EAAE,KAAK,OAAO,MAAM,OAAO,MAAM,EAAE;CAC7C,SAAS,CAAC;AACZ,CAAC;AAGD,MAAaC,SAAO,OAAO,OAAO;CAChC,MAAM;;CAEN,YAAY,OAAO;AACrB,CAAC;AAGD,MAAM,WAAW,KAA4B,OAAe,IAAI,QAAO,UAAS,UAAU,EAAE;;AAG5F,MAAa,WACX,OACA,MACA,OAC0B;CAC1B,MAAM,MAAM,MAAM,QAAQ,EAAE;CAC5B,IAAI,QAAQ,IAAI,OAAO,CAAC;CACxB,MAAM,QAAQ,SAAS,OAAO,KAAK,MAAM,QAAQ,IAAI;CACrD,IAAI,UAAU,IAAI,OAAO,CAAC,EAAE;CAC5B,OAAO,MAAM,MAAM,KAAK,IAAI,OAAO,GAAG,GAAG,KAAK,IAAI,OAAO,GAAG,IAAI,CAAC;AACnE;AAEA,MAAaC,WAAS,OAAO,KAAK,aAAa;CAC7C,OAAA;CACA,SAAA;CACA,MAAMD;CACN,aAAa,EAAE,OAAO;EAAE,UAAU,CAAC;EAAG,QAAQ;CAAK,EAAE;CACrD,SAAS,OAAO,SAAS,SACvBD,UAAQ,MAAM,SAAS;EACrB,YAAY,EAAE,SAAS;GACrB,IAAI,KAAK,SAAS,QAAQ,OAAO,EAAE,MAAM;GACzC,MAAM,aAAa,MAAM,SAAS,SAAS,EAAE;GAC7C,IAAI,KAAK,SAAS,UAChB,OAAO,aACH,KAAK,aACH,EAAE,OAAO;IAAE,UAAU,CAAC;IAAG,QAAQ;GAAG,EAAE,IACtC,EAAE,MAAM,IACV,EAAE,OAAO;IAAE,UAAU,CAAC,EAAE;IAAG,QAAQ;GAAG,EAAE;GAE9C,OAAO,EACL,OAAO;IACL,UAAU,aAAa,QAAQ,MAAM,UAAU,EAAE,IAAI,CAAC,GAAG,MAAM,UAAU,EAAE;IAC3E,QAAQ;GACV,EACF;EACF;EACA,SAAS,EAAE,IAAI,YAAY;GACzB,IAAI,KAAK,SAAS,YAAY,OAAO,EAAE,MAAM;GAC7C,MAAM,QAAQ,QAAQ,OAAO,MAAM,QAAQ,EAAE;GAC7C,MAAM,UAAU,IAAI,IAAI,KAAK;GAC7B,MAAM,WAAW,CAAC,GAAG,MAAM,SAAS,QAAO,UAAS,CAAC,QAAQ,IAAI,KAAK,CAAC,GAAG,GAAG,KAAK;GAClF,MAAM,SAAS,MAAM,UAAU;GAE/B,OAAO,QAAQ,UAAU,MAAM,QAAQ,KAAK,WAAW,MAAM,SACzD,EAAE,MAAM,IACR,EAAE,OAAO;IAAE;IAAU;GAAO,EAAE;EACpC;EACA,WAAW,EAAE,UAAU;GACrB,MAAM,WAAW,KAAK,SAAS,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC;GAC7D,OAAO,QAAQ,UAAU,MAAM,QAAQ,IACnC,EAAE,MAAM,IACR,EAAE,OAAO;IAAE;IAAU,QAAQ,MAAM;GAAO,EAAE;EAClD;EACA,eACE,MAAM,SAAS,WAAW,IAAI,EAAE,MAAM,IAAI,EAAE,OAAO;GAAE,UAAU,CAAC;GAAG,QAAQ,MAAM;EAAO,EAAE;CAC9F,CAAC;AACL,CAAC;;;;;;AAkBD,MAAaG,cACY,UAA0C,UACzD,WAEN,YACwD;CACxD,MAAM,QAAQ,YACZ,SAAS,QAAQ,KAAK,OAAO;CAC/B,MAAM,UAAU,SAAS,QAAQ,KAAK;CACtC,MAAM,aAAa,UAAU,UAAiB,IAAI,IAAI,MAAM,SAAS,MAAM,CAAC,QAAQ,CAAC;CACrF,OAAO,SAAS,SAAS,KAAK,CAAC,CAC7B;EACE,GAAI,QAAQ,cAAc,KAAA,IACtB,CAAC,IACD,GACG,QAAQ,YAAY,SAAS,KAAK;GACjC,UAAU,EAAE,YAAY,WAAW,UAAU;GAC7C,aAAa,EAAE,QAAoD,CACjE,EAAE,oBAAoB,KAAK,SAAS,UAAU,CAChD;EACF,CAAC,EACH;GACH,QAAQ,OAAO,SAAS,KAAK;GAC5B,UAAU,EAAE,YAAY,WAAW,YAAY;GAC/C,aAAa,EACX,OACA,GACA,WAKI;IACJ,IAAI,SAAS,KAAA,GAAW,OAAO,CAAC;IAChC,MAAM,QAAQ,QAAQ,KAAK;IAC3B,MAAM,KAAK,KAAK,MAAM,MAAM,IAAI,KAAK;IACrC,IAAI,OAAO,KAAA,GAAW,OAAO,CAAC;IAC9B,MAAM,YACJ,QAAQ,UAAU,SAAS,KAAK,SAAS,UAAU,CAAC,MAAM,WAAW,KAAK,KAAK;IACjF,OAAO,CACL,EAAE,aAAa,WAAW,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,GACxC,GAAI,YAAY,CAAC,EAAE,QAAQ,KAAKH,UAAQ,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAClE;GACF;EACF,CAAC;CAEH,GACA,EAAE,MAAM,YAAY,CACtB;AACF;;;;;;;;;;;;;;;;AC7IF,MAAaI,cACH,WAEN,YAEA,SAAS,SAAS,KAAK,CAAC,CACtB,GACG,QAAQ,YAAY,SAAS,KAAK;CACjC,UAAU,EAAE,YAAY,WAAW,UAAU;CAC7C,aACE,MAAM,WACJC,QAAa;EACX,WAAW,QAAQ;EACnB,gBAAgB,QAAQ,kBAAkB;CAC5C,CAAC,GACD,QAAQ,SACV;AACJ,CAAC,EAEH,GACA,EAAE,MAAM,UAAU,CACpB;;;;;;;;;;;;;;;;;;;;;;ACZJ,MAAaC,cACH,WAEN,YAEA,SAAS,SAAS,KAAK,CAAC,CACtB,GACG,QAAQ,YAAY,SAAS,KAAK;CACjC,UAAU,EAAE,YAAY,WAAW,UAAU;CAC7C,aACE,MAAM,WACJC,YACE,QAAQ,YAAY,KAAA,IAChB,EAAE,WAAW,QAAQ,UAAU,IAC/B;EAAE,WAAW,QAAQ;EAAW,SAAS,QAAQ;CAAQ,CAC/D,GACA,QAAQ,SACV;AACJ,CAAC,EAEH,GACA,EAAE,MAAM,cAAc,CACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCJ,MAAa,QAAQ,OAAO,OAAO;;CAEjC,SAAS,OAAO,OAAO,OAAO,MAAM;;CAEpC,SAAS,OAAO,MAAM,OAAO,MAAM;AACrC,CAAC;AAGD,MAAa,UAAU,mBAAmB;;CAExC,SAAS,EAAE,IAAI,OAAO,OAAO;CAC7B,QAAQ,EAAE,IAAI,OAAO,OAAO;CAC5B,QAAQ,EAAE,IAAI,OAAO,OAAO;AAC9B,CAAC;AAGD,MAAa,OAAO,OAAO,OAAO;;AAEhC,eAAe,OAAO,QACxB,CAAC;;AAID,MAAa,UAAU,OAAc,MAAY,OAC/C,KAAK,kBAAkB,MAAM,QAAQ,SAAS,EAAE;AAElD,MAAM,WAAW,OAAc,MAAY,IAAY,SACrD,OAAO,OAAO,MAAM,EAAE,MAAM,OACxB,QACA;CACE,GAAG;CACH,SAAS,MAAM,QAAQ,SAAS,EAAE,IAC9B,MAAM,QAAQ,QAAO,YAAW,YAAY,EAAE,IAC9C,CAAC,GAAG,MAAM,SAAS,EAAE;AAC3B;AAEN,MAAa,SAAS,OAAO,KAAK,kBAAkB;CAClD;CACA;CACA,MAAM;CACN,aAAa,EAAE,OAAO;EAAE,SAAS;EAAM,SAAS,CAAC;CAAE,EAAE;CACrD,SAAS,OAAO,SAAS,SAAS;EAChC,QAAQ,QAAQ,MAAhB;GAEE,KAAK,WACH,OAAO,MAAM,YAAY,QAAQ,KAC7B,EAAE,MAAM,IACR,EAAE,OAAO;IAAE,GAAG;IAAO,SAAS,QAAQ;GAAG,EAAE;GACjD,KAAK,UACH,OAAO,EAAE,OAAO,QAAQ,OAAO,MAAM,QAAQ,IAAI,IAAI,EAAE;GACzD,KAAK,UACH,OAAO,EAAE,OAAO,QAAQ,OAAO,MAAM,QAAQ,IAAI,KAAK,EAAE;EAC5D;CACF;AACF,CAAC;;;;;;AA0BD,MAAa,SAAS,MAA0B,OAAc,SAAqC;CACjG,MAAM,OAAO,IAAI,IAAI,KAAK,KAAI,QAAO,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC;CAGnD,MAAM,6BAAa,IAAI,IAA2B;CAClD,MAAM,6BAAa,IAAI,IAAoB;CAC3C,KAAK,MAAM,OAAO,MAAM;EACtB,MAAM,SAAS,IAAI,WAAW,QAAQ,KAAK,IAAI,IAAI,MAAM,IAAI,IAAI,SAAS;EAC1E,MAAM,SAAS,WAAW,IAAI,MAAM,KAAK,KAAK;EAC9C,WAAW,IAAI,QAAQ,KAAK;EAC5B,WAAW,IAAI,IAAI,IAAI,KAAK;CAC9B;CACA,MAAM,yBAAS,IAAI,IAAoB;CACvC,MAAM,0BAAU,IAAI,IAAqB;CACzC,MAAM,SAAuB,CAAC;CAC9B,KAAK,MAAM,OAAO,MAAM;EACtB,MAAM,SAAS,IAAI,WAAW,QAAQ,KAAK,IAAI,IAAI,MAAM,IAAI,IAAI,SAAS;EAC1E,MAAM,QAAQ,WAAW,OAAO,KAAK,OAAO,IAAI,MAAM,KAAK,KAAK;EAChE,OAAO,IAAI,IAAI,IAAI,KAAK;EACxB,MAAM,UAAU,WAAW,QAAS,QAAQ,IAAI,MAAM,MAAM,QAAQ,OAAO,OAAO,MAAM,MAAM;EAC9F,QAAQ,IAAI,IAAI,IAAI,OAAO;EAC3B,IAAI,CAAC,SAAS;EACd,OAAO,KAAK;GACV,GAAG;GACH;GACA,UAAU,WAAW,IAAI,IAAI,EAAE,KAAK;GACpC,UAAU,WAAW,IAAI,MAAM,KAAK;EACtC,CAAC;CACH;CACA,OAAO;AACT;AAQA,MAAM,WAAW,cACf,CAAC,UAAU,WAAW,CAAC,UAAU,UAAU,CAAC,UAAU;;;;;;;AAQxD,MAAa,QACX,MACA,SACA,KACA,WACA,OACA,MACA,YAA2B,UACJ;CACvB,MAAM,UAAU,KAAK,QAAO,QAAO,IAAI,aAAa,IAAI;CACxD,IAAI,QAAQ,WAAW,KAAK,CAAC,QAAQ,SAAS,GAAG,OAAO,KAAA;CACxD,MAAM,SAAS,QACb,QAAQ,KAAA,IAAY,KAAA,IAAY;EAAE,MAAM;EAAS,IAAI,IAAI;CAAG;CAC9D,MAAM,KAAK,QAAQ,WAAU,QAAO,IAAI,OAAO,OAAO;CACtD,MAAM,SAAS,cAAc,QAAQ,cAAc;CACnD,MAAM,UAAU,cAAc,QAAQ,eAAe;CACrD,IAAI,QAAQ,QAAQ,OAAO,MAAM,QAAQ,EAAE;CAC3C,IAAI,QAAQ,OAAO,OAAO,MAAM,QAAQ,QAAQ,SAAS,EAAE;CAC3D,IAAI,QAAQ,aACV,OAAO,MAAM,OAAO,KAAK,QAAQ,KAAK,QAAQ,KAAK,IAAI,KAAK,GAAG,QAAQ,SAAS,CAAC,EAAE;CACrF,IAAI,QAAQ,WACV,OAAO,MAAM,OAAO,KAAK,QAAQ,QAAQ,SAAS,KAAK,QAAQ,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE;CACrF,MAAM,MAAM,QAAQ;CACpB,IAAI,QAAQ,KAAA,GAAW,OAAO,QAAQ,UAAU,QAAQ,UAAU,MAAM,QAAQ,EAAE,IAAI,KAAA;CACtF,IAAI,QAAQ,QAAQ;EAClB,IAAI,CAAC,IAAI,QAAQ,OAAO,KAAA;EACxB,IAAI,CAAC,OAAO,OAAO,MAAM,IAAI,EAAE,GAAG,OAAO;GAAE,MAAM;GAAQ,IAAI,IAAI;EAAG;EACpE,OAAO,MAAM,QAAQ,MAAK,UAAS,MAAM,WAAW,IAAI,EAAE,CAAC;CAC7D;CACA,IAAI,QAAQ,SAAS;EACnB,IAAI,IAAI,UAAU,OAAO,OAAO,MAAM,IAAI,EAAE,GAAG,OAAO;GAAE,MAAM;GAAS,IAAI,IAAI;EAAG;EAClF,OAAO,MAAM,QAAQ,MAAK,WAAU,OAAO,OAAO,IAAI,MAAM,CAAC;CAC/D;AAEF;;AAGA,MAAa,WAAW,MAA4B,YAA+C;CAEjG,QADa,KAAK,MAAK,QAAO,IAAI,OAAO,WAAW,IAAI,aAAa,IAC1D,KAAK,KAAK,MAAK,QAAO,IAAI,aAAa,IAAI,EAAA,EAAI;AAC5D;;;;;;;;;;AAgCA,MAAa,YACY,UAA0C,UACzD,WAEN,YACwD;CACxD,MAAM,QAAQ,YACZ,SAAS,QAAQ,KAAK,OAAO;CAC/B,MAAM,SAAS,UAAwB,MAAM,SAAS;CACtD,MAAM,QAAQ,QAAQ,WAAW,OAAe;CAGhD,MAAM,UAAU,UAAU,UAA2B;EACnD,MAAM,QAAQ,MAAM,KAAK;EACzB,MAAM,OAAO,MAAM,QAAQ,KAAK,KAAK,GAAG,OAAO,IAAI;EACnD,OAAO;GACL;GACA;GACA,MAAM,IAAI,IAAI,KAAK,KAAI,QAAO,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC;GAC5C,MAAM,QAAQ,MAAM,MAAM,OAAO;EACnC;CACF,CAAC;CACD,OAAO,SAAS,SAAS,KAAK,CAAC,CAC7B;GACG,QAAQ,YAAY,SAAS,KAAK;GACjC,UAAU,EAAE,YAAY,WAAW,YAAY;GAE/C,aAAa,cAAc;GAC3B,aAAa,EACX,OACA,QAII;IACJ,MAAM,EAAE,OAAO,SAAS,QAAQ,KAAK;IACrC,MAAM,YAAY,QAAQ,YAAY,KAAK,KAAK;IAChD,OAAO,CACL,EAAE,gBAAgB,KAAK,cAAc;KACnC,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,KAAK,WAAW,OAAO,MAAM,SAAS;KAC/E,IAAI,WAAW,KAAA,GAAW,OAAO,OAAO,KAAK;KAE7C,MAAM,UACJ,OAAO,SAAS,UACZ,QAAQ,QAAQ,EAAE,IAAI,OAAO,GAAG,CAAC,IACjC,OAAO,SAAS,SACd,QAAQ,OAAO,EAAE,IAAI,OAAO,GAAG,CAAC,IAChC,QAAQ,OAAO,EAAE,IAAI,OAAO,GAAG,CAAC;KACxC,OAAO,OAAO,KAAK;MACjB,eAAe,WAAW,MAAM,OAAO,EAAE,CAAC;MAC1C,SAAS,KAAK,OAAO;KACvB,CAAC;IACH,CAAC,CACH;GACF;EACF,CAAC;GACA,QAAQ,OAAO,SAAS,KAAK;GAC5B,UAAU,EAAE,YAAY,WAAW,UAAU;GAC7C,aAAa,EACX,OACA,GACA,WAKI;IACJ,IAAI,SAAS,KAAA,GAAW,OAAO,CAAC;IAChC,MAAM,EAAE,OAAO,MAAM,MAAM,SAAS,QAAQ,KAAK;IACjD,MAAM,MAAM,KAAK,OAAO,KAAA,IAAY,KAAK,KAAK,SAAS,KAAK,IAAI,KAAK,EAAE;IACvE,IAAI,QAAQ,KAAA,GAAW,OAAO,CAAC;IAC/B,OAAO;KACL,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;KAClB,EAAE,KAAK,UAAU;KACjB,EAAE,UAAU,IAAI,KAAK;KACrB,EAAE,MAAM,EAAE,mBAAmB,OAAO,IAAI,KAAK,EAAE,CAAC;KAChD,EAAE,aAAa,IAAI,QAAQ;KAC3B,EAAE,YAAY,IAAI,QAAQ;KAC1B,GAAI,IAAI,SAAS,CAAC,EAAE,aAAa,OAAO,OAAO,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;KAClE,GAAI,IAAI,aAAa,OAAO,CAAC,EAAE,aAAa,IAAI,CAAC,IAAI,CAAC;KACtD,EAAE,SAAS,SAAS,IAAI,KAAK,IAAI,EAAE;KACnC,EAAE,QAAQ,KAAK,QAAQ,QAAQ,EAAE,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;IACjD;GACF;EACF,CAAC;CAEH,GACA,EAAE,MAAM,iBAAiB,CAC3B;AACF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/internal.ts
|
|
2
|
+
/** Whether two id lists hold the same ids in the same order. */
|
|
3
|
+
const sameIds = (a, b) => a.length === b.length && a.every((id, index) => id === b[index]);
|
|
4
|
+
/**
|
|
5
|
+
* Memoizes `derive` by the identity of its input. Every slot a Behavior writes
|
|
6
|
+
* in one render reads the same input, so a derivation each item needs runs
|
|
7
|
+
* once per render rather than once per item.
|
|
8
|
+
*/
|
|
9
|
+
const perInput = (derive) => {
|
|
10
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
11
|
+
return (input) => {
|
|
12
|
+
if (cache.has(input)) return cache.get(input);
|
|
13
|
+
const value = derive(input);
|
|
14
|
+
cache.set(input, value);
|
|
15
|
+
return value;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
/** Clears a typeahead query; blur and selection usually find it empty already. */
|
|
19
|
+
const clearQuery = (model) => model.query === "" ? { model } : { model: {
|
|
20
|
+
...model,
|
|
21
|
+
query: ""
|
|
22
|
+
} };
|
|
23
|
+
/**
|
|
24
|
+
* `next`, or `model` itself when both hold the same fields with the same
|
|
25
|
+
* values. Foldkit renders only when the root Model changes identity, so an
|
|
26
|
+
* equal copy renders the whole page for nothing.
|
|
27
|
+
*/
|
|
28
|
+
const unlessSame = (model, next) => {
|
|
29
|
+
const keys = Object.keys(next);
|
|
30
|
+
if (keys.length !== Object.keys(model).length) return next;
|
|
31
|
+
for (const key of keys) if (!Object.hasOwn(model, key) || !Object.is(next[key], model[key])) return next;
|
|
32
|
+
return model;
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
export { unlessSame as i, perInput as n, sameIds as r, clearQuery as t };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=internal-DP-xLKbT.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal-DP-xLKbT.mjs","names":[],"sources":["../src/internal.ts"],"sourcesContent":["/** Whether two id lists hold the same ids in the same order. */\nexport const sameIds = (a: ReadonlyArray<string>, b: ReadonlyArray<string>): boolean =>\n a.length === b.length && a.every((id, index) => id === b[index])\n\n/**\n * Memoizes `derive` by the identity of its input. Every slot a Behavior writes\n * in one render reads the same input, so a derivation each item needs runs\n * once per render rather than once per item.\n */\nexport const perInput = <Input extends object, Value>(\n derive: (input: Input) => Value,\n): ((input: Input) => Value) => {\n const cache = new WeakMap<Input, Value>()\n return input => {\n if (cache.has(input)) return cache.get(input)!\n const value = derive(input)\n cache.set(input, value)\n return value\n }\n}\n\n/** Clears a typeahead query; blur and selection usually find it empty already. */\nexport const clearQuery = <Model extends { readonly query: string }>(\n model: Model,\n): { readonly model: Model } =>\n model.query === '' ? { model } : { model: { ...model, query: '' } }\n\n/**\n * `next`, or `model` itself when both hold the same fields with the same\n * values. Foldkit renders only when the root Model changes identity, so an\n * equal copy renders the whole page for nothing.\n */\nexport const unlessSame = <Model extends object>(model: Model, next: Model): Model => {\n const keys = Object.keys(next) as Array<keyof Model>\n if (keys.length !== Object.keys(model).length) return next\n for (const key of keys) {\n if (!Object.hasOwn(model, key) || !Object.is(next[key], model[key])) return next\n }\n return model\n}\n"],"mappings":";;AACA,MAAa,WAAW,GAA0B,MAChD,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,IAAI,UAAU,OAAO,EAAE,MAAM;;;;;;AAOjE,MAAa,YACX,WAC8B;CAC9B,MAAM,wBAAQ,IAAI,QAAsB;CACxC,QAAO,UAAS;EACd,IAAI,MAAM,IAAI,KAAK,GAAG,OAAO,MAAM,IAAI,KAAK;EAC5C,MAAM,QAAQ,OAAO,KAAK;EAC1B,MAAM,IAAI,OAAO,KAAK;EACtB,OAAO;CACT;AACF;;AAGA,MAAa,cACX,UAEA,MAAM,UAAU,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO;CAAE,GAAG;CAAO,OAAO;AAAG,EAAE;;;;;;AAOpE,MAAa,cAAoC,OAAc,SAAuB;CACpF,MAAM,OAAO,OAAO,KAAK,IAAI;CAC7B,IAAI,KAAK,WAAW,OAAO,KAAK,KAAK,CAAC,CAAC,QAAQ,OAAO;CACtD,KAAK,MAAM,OAAO,MAChB,IAAI,CAAC,OAAO,OAAO,OAAO,GAAG,KAAK,CAAC,OAAO,GAAG,KAAK,MAAM,MAAM,IAAI,GAAG,OAAO;CAE9E,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/media/breakpoints.ts","../../src/media/mediaquery.ts","../../src/media/platform.ts"],"mappings":";;;qBAWa,kBAAgB,OAAA;;;;YAIjB,0BAA0B,iBAAiB;qBAE1C,8CAAkB;;oBAAlB,OAAA;;;YACD,4BAA4B,mBAAmB;qBAE9C,gBACX,eACA,aAAa,SAAS;qBAyCX,aAAW,OAAA;;;;;;;;;;;;;qBCrDX,iBAAe,OAAA;;;YAChB,yBAAyB,gBAAgB;qBAExC,6CAAiB;;sBAAjB,OAAA;;;YACD,2BAA2B,kBAAkB;qBA4B5C,YAAU,OAAA;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/media/breakpoints.ts","../../src/media/mediaquery.ts","../../src/media/platform.ts"],"mappings":";;;qBAWa,kBAAgB,OAAA;;;;YAIjB,0BAA0B,iBAAiB;qBAE1C,8CAAkB;;oBAAlB,OAAA;;;YACD,4BAA4B,mBAAmB;qBAE9C,gBACX,eACA,aAAa,SAAS;qBAyCX,aAAW,OAAA;;;;;;;;;;;;;qBCrDX,iBAAe,OAAA;;;YAChB,yBAAyB,gBAAgB;qBAExC,6CAAiB;;sBAAjB,OAAA;;;YACD,2BAA2B,kBAAkB;qBA4B5C,YAAU,OAAA;;;;;;;;;qBAcV,aAAW,OAAA;;;;;;;qBAGX,sBAAoB,OAAA;;;;;;;;;;;;;;;qBCpDpB;YACD,mBAAmB;;;;;;;iBAQd;WACN;WACA;;qBAoBE,iBAAkB,mBAAmB,QAAO,kBAAqB;;qBAkBjE;;qBAGA"}
|
package/dist/media/index.mjs
CHANGED
|
@@ -48,10 +48,10 @@ const Breakpoints = Bundle.make("Breakpoints", {
|
|
|
48
48
|
width: 0,
|
|
49
49
|
breakpoint: breakpointFor(0, args.breakpoints)
|
|
50
50
|
} }),
|
|
51
|
-
update: (model, message, args) => BreakpointsMessage.match(message, { Changed: ({ width }) =>
|
|
51
|
+
update: (model, message, args) => BreakpointsMessage.match(message, { Changed: ({ width }) => width === model.width ? { model } : { model: {
|
|
52
52
|
width,
|
|
53
53
|
breakpoint: breakpointFor(width, args.breakpoints)
|
|
54
|
-
} }
|
|
54
|
+
} } }),
|
|
55
55
|
subscriptions: () => Subscription.make()(() => ({ changes: Subscription.persistent(widthStream()) }))
|
|
56
56
|
});
|
|
57
57
|
//#endregion
|
|
@@ -83,7 +83,7 @@ const MediaQuery = Bundle.make("MediaQuery", {
|
|
|
83
83
|
Message: MediaQueryMessage,
|
|
84
84
|
args: Schema.Struct({ query: Schema.String }),
|
|
85
85
|
init: () => ({ model: { matches: false } }),
|
|
86
|
-
update: (model, message) =>
|
|
86
|
+
update: (model, message) => message.matches === model.matches ? { model } : { model: { matches: message.matches } },
|
|
87
87
|
subscriptions: ({ query }) => Subscription.make()(() => ({ changes: Subscription.persistent(matchMediaStream(query)) }))
|
|
88
88
|
});
|
|
89
89
|
/** `(prefers-color-scheme: dark)`, bound so placements give no args. */
|
package/dist/media/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/media/breakpoints.ts","../../src/media/mediaquery.ts","../../src/media/platform.ts"],"sourcesContent":["/**\n * Named breakpoints over the viewport width: one `resize` listener, derived\n * names in `update`. Thresholds are mobile-first min-widths: the breakpoint\n * is the largest name whose threshold is <= width. Ties break\n * alphabetically so duplicates stay deterministic.\n */\nimport { Effect, Queue, Schema, Stream } from 'effect'\nimport { defineMessageUnion } from 'foldkit/message'\nimport * as Subscription from 'foldkit/subscription'\nimport { Bundle } from 'foldkit-bundle'\n\nexport const BreakpointsModel = Schema.Struct({\n width: Schema.Number,\n breakpoint: Schema.NullOr(Schema.String),\n})\nexport type BreakpointsModel = typeof BreakpointsModel.Type\n\nexport const BreakpointsMessage = defineMessageUnion({ Changed: { width: Schema.Number } })\nexport type BreakpointsMessage = typeof BreakpointsMessage.Type\n\nexport const breakpointFor = (\n width: number,\n breakpoints: Readonly<Record<string, number>>,\n): string | null => {\n let best: string | null = null\n let bestThreshold = -Infinity\n for (const name of Object.keys(breakpoints)) {\n const threshold = breakpoints[name]!\n if (\n threshold <= width &&\n (threshold > bestThreshold || (threshold === bestThreshold && (best === null || name > best)))\n ) {\n best = name\n bestThreshold = threshold\n }\n }\n return best\n}\n\nconst widthStream = (): Stream.Stream<BreakpointsMessage> => {\n if (typeof window === 'undefined' || typeof window.addEventListener !== 'function') {\n return Stream.empty\n }\n return Stream.unwrap(\n Effect.gen(function* () {\n const queue = yield* Queue.unbounded<BreakpointsMessage>()\n const onResize = () => {\n Effect.runFork(Queue.offer(queue, BreakpointsMessage.Changed({ width: window.innerWidth })))\n }\n window.addEventListener('resize', onResize)\n yield* Effect.addFinalizer(() =>\n Effect.sync(() => {\n window.removeEventListener('resize', onResize)\n }),\n )\n return Stream.concat(\n Stream.make(BreakpointsMessage.Changed({ width: window.innerWidth })),\n Stream.fromQueue(queue),\n )\n }),\n )\n}\n\nexport const Breakpoints = Bundle.make('Breakpoints', {\n Model: BreakpointsModel,\n Message: BreakpointsMessage,\n args: Schema.Struct({\n breakpoints: Schema.Record(Schema.String, Schema.Number.pipe(Schema.check(Schema.isFinite()))),\n }),\n init: args => ({\n model: { width: 0, breakpoint: breakpointFor(0, args.breakpoints) },\n }),\n update: (model, message, args) =>\n BreakpointsMessage.match(message, {\n Changed: ({ width }) => ({\n model: { width, breakpoint: breakpointFor(width, args.breakpoints) },\n }),\n }),\n subscriptions: (): Subscription.Subscriptions<BreakpointsModel, BreakpointsMessage> =>\n Subscription.make<BreakpointsModel, BreakpointsMessage>()(() => ({\n changes: Subscription.persistent(widthStream()),\n })),\n})\n","/**\n * A media query as a bundle: `matches` in the Model, kept current by a\n * `matchMedia` change stream. State stays in the parent Model, so it replays\n * and time-travels like any other state; the browser only reports facts.\n */\nimport { Effect, Queue, Schema, Stream } from 'effect'\nimport { defineMessageUnion } from 'foldkit/message'\nimport * as Subscription from 'foldkit/subscription'\nimport { Bundle } from 'foldkit-bundle'\n\nexport const MediaQueryModel = Schema.Struct({ matches: Schema.Boolean })\nexport type MediaQueryModel = typeof MediaQueryModel.Type\n\nexport const MediaQueryMessage = defineMessageUnion({ Changed: { matches: Schema.Boolean } })\nexport type MediaQueryMessage = typeof MediaQueryMessage.Type\n\nconst matchMediaStream = (query: string): Stream.Stream<MediaQueryMessage> => {\n // No window (SSR) or no matchMedia (old browser, minimal DOM): nothing to\n // listen to, so the slice keeps its initial value instead of throwing.\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return Stream.empty\n return Stream.unwrap(\n Effect.gen(function* () {\n const queue = yield* Queue.unbounded<MediaQueryMessage>()\n const list = window.matchMedia(query)\n const onChange = (event: MediaQueryListEvent) => {\n Effect.runFork(Queue.offer(queue, MediaQueryMessage.Changed({ matches: event.matches })))\n }\n list.addEventListener('change', onChange)\n yield* Effect.addFinalizer(() =>\n Effect.sync(() => {\n list.removeEventListener('change', onChange)\n }),\n )\n // The current value first, so the Model is right before the first change.\n return Stream.concat(\n Stream.make(MediaQueryMessage.Changed({ matches: list.matches })),\n Stream.fromQueue(queue),\n )\n }),\n )\n}\n\nexport const MediaQuery = Bundle.make('MediaQuery', {\n Model: MediaQueryModel,\n Message: MediaQueryMessage,\n args: Schema.Struct({ query: Schema.String }),\n init: () => ({ model: { matches: false } }),\n update: (model, message) => ({ model: { matches: message.matches } }),\n subscriptions: ({ query }): Subscription.Subscriptions<MediaQueryModel, MediaQueryMessage> =>\n Subscription.make<MediaQueryModel, MediaQueryMessage>()(() => ({\n changes: Subscription.persistent(matchMediaStream(query)),\n })),\n})\n\n/** `(prefers-color-scheme: dark)`, bound so placements give no args. */\nexport const PrefersDark = MediaQuery.with({ query: '(prefers-color-scheme: dark)' })\n\n/** `(prefers-reduced-motion: reduce)`, bound so placements give no args. */\nexport const PrefersReducedMotion = MediaQuery.with({ query: '(prefers-reduced-motion: reduce)' })\n","/**\n * Platform detection as pure functions. `platformFromUA` reads a user-agent\n * string (passed in, so tests pin it without stubbing globals); order\n * matters — Android contains \"Linux\", iPhones mention \"Mac\" — so mobile\n * checks come first. `isBrowser`/`isServer` split SSR from client for init\n * defaults.\n */\nexport const Platform = ['mac', 'windows', 'linux', 'android', 'ios', 'unknown'] as const\nexport type Platform = (typeof Platform)[number]\n\n/**\n * Client Hints (`navigator.userAgentData`) plus touch points\n * (`navigator.maxTouchPoints`), passed in so detection stays pure and\n * pinned. Only `platform` and `touchPoints` can change the answer — the\n * `mobile` flag never disambiguates on its own, so it is not accepted.\n */\nexport interface PlatformHints {\n readonly platform?: string | undefined\n readonly touchPoints?: number | undefined\n}\n\nconst hintedPlatform = (platform: string): Platform | null => {\n switch (platform.toLowerCase()) {\n case 'macos':\n return 'mac'\n case 'windows':\n return 'windows'\n case 'linux':\n return 'linux'\n case 'android':\n return 'android'\n case 'ios':\n return 'ios'\n default:\n return null\n }\n}\n\nexport const platformFromUA = (userAgent: string, hints: PlatformHints = {}): Platform => {\n const hinted = hints.platform === undefined ? null : hintedPlatform(hints.platform)\n const ua = userAgent.toLowerCase()\n let sniffed: Platform = 'unknown'\n if (ua.includes('android')) sniffed = 'android'\n else if (ua.includes('iphone') || ua.includes('ipad') || ua.includes('ipod')) sniffed = 'ios'\n else if (ua.includes('windows') || ua.includes('win32') || ua.includes('win64')) {\n sniffed = 'windows'\n } else if (ua.includes('macintosh') || ua.includes('mac os')) sniffed = 'mac'\n else if (ua.includes('linux')) sniffed = 'linux'\n const candidate = hinted ?? sniffed\n // Desktop-mode iPads report \"macOS\" with a tablet touchscreen: only a\n // multi-touch Mac UA is really an iPad. Touchscreen Windows and Linux\n // machines keep their platform.\n return candidate === 'mac' && (hints.touchPoints ?? 0) > 1 ? 'ios' : candidate\n}\n\n/** Whether a window exists: the client side of an SSR split. */\nexport const isBrowser = (): boolean => typeof window !== 'undefined'\n\n/** Whether no window exists: the server side of an SSR split. */\nexport const isServer = (): boolean => !isBrowser()\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/media/breakpoints.ts","../../src/media/mediaquery.ts","../../src/media/platform.ts"],"sourcesContent":["/**\n * Named breakpoints over the viewport width: one `resize` listener, derived\n * names in `update`. Thresholds are mobile-first min-widths: the breakpoint\n * is the largest name whose threshold is <= width. Ties break\n * alphabetically so duplicates stay deterministic.\n */\nimport { Effect, Queue, Schema, Stream } from 'effect'\nimport { defineMessageUnion } from 'foldkit/message'\nimport * as Subscription from 'foldkit/subscription'\nimport { Bundle } from 'foldkit-bundle'\n\nexport const BreakpointsModel = Schema.Struct({\n width: Schema.Number,\n breakpoint: Schema.NullOr(Schema.String),\n})\nexport type BreakpointsModel = typeof BreakpointsModel.Type\n\nexport const BreakpointsMessage = defineMessageUnion({ Changed: { width: Schema.Number } })\nexport type BreakpointsMessage = typeof BreakpointsMessage.Type\n\nexport const breakpointFor = (\n width: number,\n breakpoints: Readonly<Record<string, number>>,\n): string | null => {\n let best: string | null = null\n let bestThreshold = -Infinity\n for (const name of Object.keys(breakpoints)) {\n const threshold = breakpoints[name]!\n if (\n threshold <= width &&\n (threshold > bestThreshold || (threshold === bestThreshold && (best === null || name > best)))\n ) {\n best = name\n bestThreshold = threshold\n }\n }\n return best\n}\n\nconst widthStream = (): Stream.Stream<BreakpointsMessage> => {\n if (typeof window === 'undefined' || typeof window.addEventListener !== 'function') {\n return Stream.empty\n }\n return Stream.unwrap(\n Effect.gen(function* () {\n const queue = yield* Queue.unbounded<BreakpointsMessage>()\n const onResize = () => {\n Effect.runFork(Queue.offer(queue, BreakpointsMessage.Changed({ width: window.innerWidth })))\n }\n window.addEventListener('resize', onResize)\n yield* Effect.addFinalizer(() =>\n Effect.sync(() => {\n window.removeEventListener('resize', onResize)\n }),\n )\n return Stream.concat(\n Stream.make(BreakpointsMessage.Changed({ width: window.innerWidth })),\n Stream.fromQueue(queue),\n )\n }),\n )\n}\n\nexport const Breakpoints = Bundle.make('Breakpoints', {\n Model: BreakpointsModel,\n Message: BreakpointsMessage,\n args: Schema.Struct({\n breakpoints: Schema.Record(Schema.String, Schema.Number.pipe(Schema.check(Schema.isFinite()))),\n }),\n init: args => ({\n model: { width: 0, breakpoint: breakpointFor(0, args.breakpoints) },\n }),\n update: (model, message, args) =>\n BreakpointsMessage.match(message, {\n // A height-only resize reports the same width.\n Changed: ({ width }) =>\n width === model.width\n ? { model }\n : { model: { width, breakpoint: breakpointFor(width, args.breakpoints) } },\n }),\n subscriptions: (): Subscription.Subscriptions<BreakpointsModel, BreakpointsMessage> =>\n Subscription.make<BreakpointsModel, BreakpointsMessage>()(() => ({\n changes: Subscription.persistent(widthStream()),\n })),\n})\n","/**\n * A media query as a bundle: `matches` in the Model, kept current by a\n * `matchMedia` change stream. State stays in the parent Model, so it replays\n * and time-travels like any other state; the browser only reports facts.\n */\nimport { Effect, Queue, Schema, Stream } from 'effect'\nimport { defineMessageUnion } from 'foldkit/message'\nimport * as Subscription from 'foldkit/subscription'\nimport { Bundle } from 'foldkit-bundle'\n\nexport const MediaQueryModel = Schema.Struct({ matches: Schema.Boolean })\nexport type MediaQueryModel = typeof MediaQueryModel.Type\n\nexport const MediaQueryMessage = defineMessageUnion({ Changed: { matches: Schema.Boolean } })\nexport type MediaQueryMessage = typeof MediaQueryMessage.Type\n\nconst matchMediaStream = (query: string): Stream.Stream<MediaQueryMessage> => {\n // No window (SSR) or no matchMedia (old browser, minimal DOM): nothing to\n // listen to, so the slice keeps its initial value instead of throwing.\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return Stream.empty\n return Stream.unwrap(\n Effect.gen(function* () {\n const queue = yield* Queue.unbounded<MediaQueryMessage>()\n const list = window.matchMedia(query)\n const onChange = (event: MediaQueryListEvent) => {\n Effect.runFork(Queue.offer(queue, MediaQueryMessage.Changed({ matches: event.matches })))\n }\n list.addEventListener('change', onChange)\n yield* Effect.addFinalizer(() =>\n Effect.sync(() => {\n list.removeEventListener('change', onChange)\n }),\n )\n // The current value first, so the Model is right before the first change.\n return Stream.concat(\n Stream.make(MediaQueryMessage.Changed({ matches: list.matches })),\n Stream.fromQueue(queue),\n )\n }),\n )\n}\n\nexport const MediaQuery = Bundle.make('MediaQuery', {\n Model: MediaQueryModel,\n Message: MediaQueryMessage,\n args: Schema.Struct({ query: Schema.String }),\n init: () => ({ model: { matches: false } }),\n update: (model, message) =>\n message.matches === model.matches ? { model } : { model: { matches: message.matches } },\n subscriptions: ({ query }): Subscription.Subscriptions<MediaQueryModel, MediaQueryMessage> =>\n Subscription.make<MediaQueryModel, MediaQueryMessage>()(() => ({\n changes: Subscription.persistent(matchMediaStream(query)),\n })),\n})\n\n/** `(prefers-color-scheme: dark)`, bound so placements give no args. */\nexport const PrefersDark = MediaQuery.with({ query: '(prefers-color-scheme: dark)' })\n\n/** `(prefers-reduced-motion: reduce)`, bound so placements give no args. */\nexport const PrefersReducedMotion = MediaQuery.with({ query: '(prefers-reduced-motion: reduce)' })\n","/**\n * Platform detection as pure functions. `platformFromUA` reads a user-agent\n * string (passed in, so tests pin it without stubbing globals); order\n * matters — Android contains \"Linux\", iPhones mention \"Mac\" — so mobile\n * checks come first. `isBrowser`/`isServer` split SSR from client for init\n * defaults.\n */\nexport const Platform = ['mac', 'windows', 'linux', 'android', 'ios', 'unknown'] as const\nexport type Platform = (typeof Platform)[number]\n\n/**\n * Client Hints (`navigator.userAgentData`) plus touch points\n * (`navigator.maxTouchPoints`), passed in so detection stays pure and\n * pinned. Only `platform` and `touchPoints` can change the answer — the\n * `mobile` flag never disambiguates on its own, so it is not accepted.\n */\nexport interface PlatformHints {\n readonly platform?: string | undefined\n readonly touchPoints?: number | undefined\n}\n\nconst hintedPlatform = (platform: string): Platform | null => {\n switch (platform.toLowerCase()) {\n case 'macos':\n return 'mac'\n case 'windows':\n return 'windows'\n case 'linux':\n return 'linux'\n case 'android':\n return 'android'\n case 'ios':\n return 'ios'\n default:\n return null\n }\n}\n\nexport const platformFromUA = (userAgent: string, hints: PlatformHints = {}): Platform => {\n const hinted = hints.platform === undefined ? null : hintedPlatform(hints.platform)\n const ua = userAgent.toLowerCase()\n let sniffed: Platform = 'unknown'\n if (ua.includes('android')) sniffed = 'android'\n else if (ua.includes('iphone') || ua.includes('ipad') || ua.includes('ipod')) sniffed = 'ios'\n else if (ua.includes('windows') || ua.includes('win32') || ua.includes('win64')) {\n sniffed = 'windows'\n } else if (ua.includes('macintosh') || ua.includes('mac os')) sniffed = 'mac'\n else if (ua.includes('linux')) sniffed = 'linux'\n const candidate = hinted ?? sniffed\n // Desktop-mode iPads report \"macOS\" with a tablet touchscreen: only a\n // multi-touch Mac UA is really an iPad. Touchscreen Windows and Linux\n // machines keep their platform.\n return candidate === 'mac' && (hints.touchPoints ?? 0) > 1 ? 'ios' : candidate\n}\n\n/** Whether a window exists: the client side of an SSR split. */\nexport const isBrowser = (): boolean => typeof window !== 'undefined'\n\n/** Whether no window exists: the server side of an SSR split. */\nexport const isServer = (): boolean => !isBrowser()\n"],"mappings":"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"}
|
package/dist/motion/index.d.mts
CHANGED
|
@@ -1,112 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
//#region src/motion/presence.d.ts
|
|
4
|
-
export declare const PresenceModel: Schema.Struct<{
|
|
5
|
-
readonly phase: Schema.Literals<readonly ["shown", "hiding", "hidden"]>;
|
|
6
|
-
readonly generation: Schema.Number;
|
|
7
|
-
}>;
|
|
8
|
-
export type PresenceModel = typeof PresenceModel.Type;
|
|
9
|
-
export declare const PresenceMessage: import("foldkit/message").MessageUnion<{
|
|
10
|
-
readonly Show: {};
|
|
11
|
-
readonly Hide: {};
|
|
12
|
-
readonly Hidden: {
|
|
13
|
-
readonly generation: Schema.Number;
|
|
14
|
-
};
|
|
15
|
-
}>;
|
|
16
|
-
export type PresenceMessage = typeof PresenceMessage.Type;
|
|
17
|
-
/** Whether the content renders: shown or mid-exit. */
|
|
18
|
-
export declare const isVisible: (model: PresenceModel) => boolean;
|
|
19
|
-
export declare const Presence: Bundle.Bundle<"Presence", {
|
|
20
|
-
readonly durationMs: number;
|
|
21
|
-
}, {
|
|
22
|
-
readonly phase: "shown" | "hiding" | "hidden";
|
|
23
|
-
readonly generation: number;
|
|
24
|
-
}, {
|
|
25
|
-
readonly _tag: "Show";
|
|
26
|
-
} | {
|
|
27
|
-
readonly _tag: "Hide";
|
|
28
|
-
} | {
|
|
29
|
-
readonly _tag: "Hidden";
|
|
30
|
-
readonly generation: number;
|
|
31
|
-
}, never, never, never, void, {}, {}>;
|
|
32
|
-
//#endregion
|
|
33
|
-
//#region src/motion/spring.d.ts
|
|
34
|
-
export declare const SpringModel: Schema.Struct<{
|
|
35
|
-
readonly value: Schema.Number;
|
|
36
|
-
readonly velocity: Schema.Number;
|
|
37
|
-
readonly running: Schema.Boolean;
|
|
38
|
-
}>;
|
|
39
|
-
export type SpringModel = typeof SpringModel.Type;
|
|
40
|
-
export declare const SpringMessage: import("foldkit/message").MessageUnion<{
|
|
41
|
-
readonly Started: {};
|
|
42
|
-
readonly Stopped: {};
|
|
43
|
-
readonly Ticked: {
|
|
44
|
-
readonly value: Schema.Number;
|
|
45
|
-
readonly velocity: Schema.Number;
|
|
46
|
-
};
|
|
47
|
-
/** Carries the exact end value: the integrator stops near it, not on it. */
|
|
48
|
-
readonly Finished: {
|
|
49
|
-
readonly value: Schema.Number;
|
|
50
|
-
};
|
|
51
|
-
}>;
|
|
52
|
-
export type SpringMessage = typeof SpringMessage.Type;
|
|
53
|
-
export declare const Spring: Bundle.Bundle<"Spring", {
|
|
54
|
-
readonly from: number;
|
|
55
|
-
readonly to: number;
|
|
56
|
-
readonly stiffness: number;
|
|
57
|
-
readonly damping: number;
|
|
58
|
-
}, {
|
|
59
|
-
readonly value: number;
|
|
60
|
-
readonly velocity: number;
|
|
61
|
-
readonly running: boolean;
|
|
62
|
-
}, {
|
|
63
|
-
readonly _tag: "Started";
|
|
64
|
-
} | {
|
|
65
|
-
readonly _tag: "Stopped";
|
|
66
|
-
} | {
|
|
67
|
-
readonly _tag: "Ticked";
|
|
68
|
-
readonly value: number;
|
|
69
|
-
readonly velocity: number;
|
|
70
|
-
} | {
|
|
71
|
-
readonly _tag: "Finished";
|
|
72
|
-
readonly value: number;
|
|
73
|
-
}, never, never, never, void, {}, {}>;
|
|
74
|
-
//#endregion
|
|
75
|
-
//#region src/motion/tween.d.ts
|
|
76
|
-
export declare const TweenModel: Schema.Struct<{
|
|
77
|
-
readonly value: Schema.Number;
|
|
78
|
-
readonly running: Schema.Boolean;
|
|
79
|
-
}>;
|
|
80
|
-
export type TweenModel = typeof TweenModel.Type;
|
|
81
|
-
export declare const TweenMessage: import("foldkit/message").MessageUnion<{
|
|
82
|
-
readonly Started: {};
|
|
83
|
-
readonly Stopped: {};
|
|
84
|
-
readonly Ticked: {
|
|
85
|
-
readonly value: Schema.Number;
|
|
86
|
-
};
|
|
87
|
-
/** Carries the exact end value: the stream may stop on either side of it. */
|
|
88
|
-
readonly Finished: {
|
|
89
|
-
readonly value: Schema.Number;
|
|
90
|
-
};
|
|
91
|
-
}>;
|
|
92
|
-
export type TweenMessage = typeof TweenMessage.Type;
|
|
93
|
-
export declare const Tween: Bundle.Bundle<"Tween", {
|
|
94
|
-
readonly from: number;
|
|
95
|
-
readonly to: number;
|
|
96
|
-
readonly ms: number;
|
|
97
|
-
}, {
|
|
98
|
-
readonly value: number;
|
|
99
|
-
readonly running: boolean;
|
|
100
|
-
}, {
|
|
101
|
-
readonly _tag: "Started";
|
|
102
|
-
} | {
|
|
103
|
-
readonly _tag: "Stopped";
|
|
104
|
-
} | {
|
|
105
|
-
readonly _tag: "Ticked";
|
|
106
|
-
readonly value: number;
|
|
107
|
-
} | {
|
|
108
|
-
readonly _tag: "Finished";
|
|
109
|
-
readonly value: number;
|
|
110
|
-
}, never, never, never, void, {}, {}>;
|
|
111
|
-
//#endregion
|
|
112
|
-
//# sourceMappingURL=index.d.mts.map
|
|
1
|
+
import { a as SpringMessage, c as PresenceMessage, d as motion_d_exports, i as Spring, l as PresenceModel, n as TweenMessage, o as SpringModel, r as TweenModel, s as Presence, t as Tween, u as isVisible } from "../index-Cppf-lBx.mjs";
|
|
2
|
+
export { motion_d_exports as Motion, Presence, PresenceMessage, PresenceModel, Spring, SpringMessage, SpringModel, Tween, TweenMessage, TweenModel, isVisible };
|