@aparte/plugin-cards 0.29.0 → 0.29.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/{carousel-CPy-0JGN.js → carousel-DwgHvriV.js} +2 -2
- package/dist/{carousel-CPy-0JGN.js.map → carousel-DwgHvriV.js.map} +1 -1
- package/dist/{controls-BVX2u7sK.js → controls-BYUm4aRV.js} +2 -2
- package/dist/{controls-BVX2u7sK.js.map → controls-BYUm4aRV.js.map} +1 -1
- package/dist/{format-CchcJRum.js → format-BFq79ydr.js} +25 -17
- package/dist/format-BFq79ydr.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +105 -20
- package/dist/index.js.map +1 -1
- package/dist/items.js +2 -2
- package/dist/kit/define.d.ts +7 -0
- package/dist/kit/define.d.ts.map +1 -1
- package/dist/kit/fence.d.ts +39 -0
- package/dist/kit/fence.d.ts.map +1 -0
- package/dist/link.js +1 -1
- package/dist/media.js +2 -2
- package/dist/order.js +1 -1
- package/dist/place.js +3 -3
- package/dist/plan.js +1 -1
- package/dist/product.js +3 -3
- package/dist/{rating-B8Mdx_b_.js → rating-CHVajQ2b.js} +2 -2
- package/dist/{rating-B8Mdx_b_.js.map → rating-CHVajQ2b.js.map} +1 -1
- package/dist/score.js +1 -1
- package/dist/stats.js +1 -1
- package/dist/stock.js +2 -2
- package/dist/weather.js +1 -1
- package/package.json +3 -3
- package/dist/format-CchcJRum.js.map +0 -1
package/README.md
CHANGED
|
@@ -132,6 +132,9 @@ keys and the usual search APIs; the card fetches nothing.
|
|
|
132
132
|
What every card is made with, for a card of your own that behaves like ours (three sources,
|
|
133
133
|
states, variants, language switch, buttons):
|
|
134
134
|
|
|
135
|
+
- `setupCardFences(options)` (`CardFenceOptions`, `CARD_FENCE_PREFIX`): draws a ```` ```card-weather ````
|
|
136
|
+
block of JSON in an answer as its card, for backends that send only text; `load` fetches each
|
|
137
|
+
card the first time a block names it.
|
|
135
138
|
- `defineCard(definition)` and `CARD_SEGMENT_TYPE`; types `CardDefinition`, `CardSetupOptions`,
|
|
136
139
|
`CardContext`, `CardAction`, `CardActionEventDetail`, `CardChangeEventDetail`, `AparteCardSegment`.
|
|
137
140
|
- Controls, drawn only when the card has an `onChange`: `segmented` (`SegmentedOptions`), `toggle`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { e as el,
|
|
1
|
+
import { e as el, r as word, h as formatNumber, K as KIT_WORDS, v as bindMarkup } from "./format-BFq79ydr.js";
|
|
2
2
|
function carousel(ctx, slides, { label } = {}) {
|
|
3
3
|
const track = el("div", { class: "aparte-rich-card__track", attrs: label ? { tabindex: 0 } : {} });
|
|
4
4
|
if (label) ctx.bind(track, label, "aria-label");
|
|
@@ -60,4 +60,4 @@ function carousel(ctx, slides, { label } = {}) {
|
|
|
60
60
|
export {
|
|
61
61
|
carousel as c
|
|
62
62
|
};
|
|
63
|
-
//# sourceMappingURL=carousel-
|
|
63
|
+
//# sourceMappingURL=carousel-DwgHvriV.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"carousel-
|
|
1
|
+
{"version":3,"file":"carousel-DwgHvriV.js","sources":["../src/kit/carousel.ts"],"sourcesContent":["/**\n * A row of slides that scrolls sideways: products, places, articles.\n *\n * Native scrolling with snap points, so touch, trackpad, wheel and keyboard (the track is\n * focusable; arrows scroll it) all work as the platform does. Two buttons step a slide at\n * a time and switch off at each end; they are not drawn when everything fits. Announced as\n * a carousel, each slide as \"2 of 5\" (the WAI-ARIA carousel pattern, without auto-play:\n * nothing here moves on its own).\n */\nimport { bindMarkup, type CardContext } from './define.js';\nimport { el } from './dom.js';\nimport { formatNumber } from './format.js';\nimport { KIT_WORDS, word } from './strings.js';\n\nexport interface CarouselOptions {\n /** The carousel's accessible name (\"Products\"); its slides are counted inside it. */\n label?: () => string;\n}\n\n/** The slides in a scrolling row, with its two buttons. */\nexport function carousel(ctx: CardContext, slides: HTMLElement[], { label }: CarouselOptions = {}): HTMLElement {\n // Focusable so the arrow keys scroll it — and then named, since a focus stop must say what\n // it is. Without a label the two buttons are the keyboard's way through.\n const track = el('div', { class: 'aparte-rich-card__track', attrs: label ? { tabindex: 0 } : {} });\n if (label) ctx.bind(track, label, 'aria-label');\n slides.forEach((slide, i) => {\n const wrap = el('div', { class: 'aparte-rich-card__slide', attrs: { role: 'group', 'aria-roledescription': 'slide' } }, slide);\n ctx.bind(wrap, () => word(ctx.config, 'cardsSlide', KIT_WORDS.cardsSlide, { n: formatNumber(ctx.config, i + 1), total: formatNumber(ctx.config, slides.length) }), 'aria-label');\n track.append(wrap);\n });\n\n const button = (dir: -1 | 1) => {\n const b = el('button', {\n class: `aparte-btn aparte-btn--icon aparte-btn--sm aparte-btn--surface aparte-rich-card__nav aparte-rich-card__nav--${dir < 0 ? 'prev' : 'next'}`,\n attrs: { type: 'button' },\n });\n bindMarkup(b, () => ctx.config.getIcon(dir < 0 ? 'prevBranch' : 'nextBranch'));\n ctx.bind(b, () => word(ctx.config, dir < 0 ? 'cardsPrevious' : 'cardsNext', dir < 0 ? KIT_WORDS.cardsPrevious : KIT_WORDS.cardsNext), 'aria-label');\n b.addEventListener('click', () => step(dir));\n return b;\n };\n const prev = button(-1);\n const next = button(1);\n // A region is a landmark, and a landmark needs a name: without a label it is a plain box.\n const root = el('div', { class: 'aparte-rich-card__carousel', attrs: label ? { role: 'region', 'aria-roledescription': 'carousel' } : {} }, track, prev, next);\n if (label) ctx.bind(root, label, 'aria-label');\n\n const rtl = () => typeof getComputedStyle === 'function' && getComputedStyle(track).direction === 'rtl';\n function step(dir: -1 | 1): void {\n const slide = track.firstElementChild as HTMLElement | null;\n const gap = parseFloat(getComputedStyle(track).columnGap) || 0;\n const by = ((slide?.offsetWidth ?? track.clientWidth) + gap) * dir * (rtl() ? -1 : 1);\n const still = typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;\n track.scrollBy({ left: by, behavior: still ? 'auto' : 'smooth' });\n }\n function sync(): void {\n // In a right-to-left page `scrollLeft` runs from 0 down to a negative number.\n const at = Math.abs(track.scrollLeft);\n const room = track.scrollWidth - track.clientWidth;\n root.toggleAttribute('data-overflow', room > 1);\n // A button switched off while it holds the focus would drop it on the page: the\n // focus moves to the other button (or the track) first.\n const active = typeof document === 'undefined' ? null : document.activeElement;\n prev.disabled = at <= 1;\n next.disabled = at >= room - 1;\n if (active === prev && prev.disabled) (next.disabled ? track : next).focus({ preventScroll: true });\n if (active === next && next.disabled) (prev.disabled ? track : prev).focus({ preventScroll: true });\n }\n let frame = 0;\n track.addEventListener('scroll', () => {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(sync);\n }, { passive: true });\n if (typeof ResizeObserver === 'function') {\n // A card has no teardown hook: the observer lets itself go once the track has left\n // the page (a removal reports a size change).\n const watch = new ResizeObserver(() => {\n if (!track.isConnected) { watch.disconnect(); return; }\n sync();\n });\n watch.observe(track);\n }\n sync();\n return root;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { e as el } from "./format-
|
|
1
|
+
import { e as el } from "./format-BFq79ydr.js";
|
|
2
2
|
function segmented(ctx, { name, options, value, label }) {
|
|
3
3
|
if (!ctx.live || options.length === 0) return null;
|
|
4
4
|
const group = el("div", { class: "aparte-rich-card__segmented", attrs: { role: "group" } });
|
|
@@ -59,4 +59,4 @@ export {
|
|
|
59
59
|
segmented as s,
|
|
60
60
|
toggle as t
|
|
61
61
|
};
|
|
62
|
-
//# sourceMappingURL=controls-
|
|
62
|
+
//# sourceMappingURL=controls-BYUm4aRV.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controls-
|
|
1
|
+
{"version":3,"file":"controls-BYUm4aRV.js","sources":["../src/kit/controls.ts"],"sourcesContent":["/**\n * Controls a card can carry: a row of choices, a switch, a slider. Each reports through\n * `ctx.change(name, value)`, so the card fires `aparte-card-change` and the app's\n * `onChange` answers with new data, drawn in place — a stock chart's range, a light's\n * brightness.\n *\n * A control is drawn only when something will answer it (`ctx.live`): without an\n * `onChange`, a button that does nothing would be a promise the card cannot keep\n * (ratified decision #8). Each control carries a `data-card-key`, so a redraw puts the\n * focus back on the control that was pressed.\n */\nimport type { CardContext } from './define.js';\nimport { el } from './dom.js';\n\nexport interface SegmentedOptions {\n /** The control's name in the change (`range`). */\n name: string;\n /** The choices; a label is a string or a function read again on a language switch. */\n options: Array<{ value: string; label: string | (() => string) }>;\n /** The choice in force. */\n value?: string;\n /** The group's accessible name. */\n label?: () => string;\n}\n\n/** A row of choices, one pressed (`aria-pressed`). `null` when nothing would answer it. */\nexport function segmented(ctx: CardContext, { name, options, value, label }: SegmentedOptions): HTMLElement | null {\n if (!ctx.live || options.length === 0) return null;\n const group = el('div', { class: 'aparte-rich-card__segmented', attrs: { role: 'group' } });\n if (label) ctx.bind(group, label, 'aria-label');\n for (const option of options) {\n const pressed = option.value === value;\n const button = el('button', {\n class: 'aparte-rich-card__segment',\n attrs: { type: 'button', 'aria-pressed': pressed ? 'true' : 'false', 'data-card-key': `${name}:${option.value}` },\n });\n if (typeof option.label === 'function') ctx.bind(button, option.label);\n else button.textContent = option.label;\n button.addEventListener('click', () => {\n if (button.getAttribute('aria-pressed') === 'true') return;\n // Pressed at once, before the app answers: a second press reads what was chosen.\n for (const other of group.querySelectorAll('.aparte-rich-card__segment')) other.setAttribute('aria-pressed', other === button ? 'true' : 'false');\n ctx.change(name, option.value);\n });\n group.append(button);\n }\n return group;\n}\n\nexport interface ToggleOptions {\n name: string;\n checked: boolean;\n /** What it switches (\"Living-room light\"). */\n label: () => string;\n}\n\n/** A switch (`role=\"switch\"`). `null` when nothing would answer it. */\nexport function toggle(ctx: CardContext, { name, checked, label }: ToggleOptions): HTMLElement | null {\n if (!ctx.live) return null;\n const button = el('button', {\n class: 'aparte-rich-card__toggle',\n attrs: { type: 'button', role: 'switch', 'aria-checked': checked ? 'true' : 'false', 'data-card-key': name },\n }, el('span', { class: 'aparte-rich-card__toggle-thumb', attrs: { 'aria-hidden': 'true' } }));\n ctx.bind(button, label, 'aria-label');\n button.addEventListener('click', () => {\n // Flipped at once, before the app answers: a second click before the answer flips it\n // back, rather than sending the same state twice.\n const next = button.getAttribute('aria-checked') !== 'true';\n button.setAttribute('aria-checked', next ? 'true' : 'false');\n ctx.change(name, next);\n });\n return button;\n}\n\nexport interface SliderOptions {\n name: string;\n value: number;\n min?: number;\n max?: number;\n step?: number;\n label: () => string;\n /** How the value reads beside it, and to a screen reader (\"60 %\"). */\n format?: (value: number) => string;\n}\n\n/**\n * A slider: the value beside it follows while it moves, the change is reported once it is\n * let go (`change`, not `input`) — one request for a drag, not one per pixel.\n */\nexport function slider(ctx: CardContext, { name, value, min = 0, max = 100, step = 1, label, format = String }: SliderOptions): HTMLElement | null {\n if (!ctx.live) return null;\n const input = el('input', {\n class: 'aparte-rich-card__slider-input',\n attrs: { type: 'range', min, max, step, value, 'data-card-key': name },\n });\n const shown = el('output', { class: 'aparte-rich-card__slider-value' });\n const name_ = el('span', { class: 'aparte-rich-card__slider-label' });\n ctx.bind(name_, label);\n ctx.bind(input, label, 'aria-label');\n const paint = (v: number) => {\n shown.textContent = format(v);\n input.setAttribute('aria-valuetext', format(v));\n };\n ctx.bind(shown, () => format(Number(input.value)));\n paint(value);\n input.addEventListener('input', () => paint(Number(input.value)));\n input.addEventListener('change', () => ctx.change(name, Number(input.value)));\n return el('label', { class: 'aparte-rich-card__slider' }, name_, input, shown);\n}\n"],"names":[],"mappings":";AA0BO,SAAS,UAAU,KAAkB,EAAE,MAAM,SAAS,OAAO,SAA+C;AAC/G,MAAI,CAAC,IAAI,QAAQ,QAAQ,WAAW,EAAG,QAAO;AAC9C,QAAM,QAAQ,GAAG,OAAO,EAAE,OAAO,+BAA+B,OAAO,EAAE,MAAM,QAAA,GAAW;AAC1F,MAAI,MAAO,KAAI,KAAK,OAAO,OAAO,YAAY;AAC9C,aAAW,UAAU,SAAS;AAC1B,UAAM,UAAU,OAAO,UAAU;AACjC,UAAM,SAAS,GAAG,UAAU;AAAA,MACxB,OAAO;AAAA,MACP,OAAO,EAAE,MAAM,UAAU,gBAAgB,UAAU,SAAS,SAAS,iBAAiB,GAAG,IAAI,IAAI,OAAO,KAAK,GAAA;AAAA,IAAG,CACnH;AACD,QAAI,OAAO,OAAO,UAAU,gBAAgB,KAAK,QAAQ,OAAO,KAAK;AAAA,QAChE,QAAO,cAAc,OAAO;AACjC,WAAO,iBAAiB,SAAS,MAAM;AACnC,UAAI,OAAO,aAAa,cAAc,MAAM,OAAQ;AAEpD,iBAAW,SAAS,MAAM,iBAAiB,4BAA4B,EAAG,OAAM,aAAa,gBAAgB,UAAU,SAAS,SAAS,OAAO;AAChJ,UAAI,OAAO,MAAM,OAAO,KAAK;AAAA,IACjC,CAAC;AACD,UAAM,OAAO,MAAM;AAAA,EACvB;AACA,SAAO;AACX;AAUO,SAAS,OAAO,KAAkB,EAAE,MAAM,SAAS,SAA4C;AAClG,MAAI,CAAC,IAAI,KAAM,QAAO;AACtB,QAAM,SAAS,GAAG,UAAU;AAAA,IACxB,OAAO;AAAA,IACP,OAAO,EAAE,MAAM,UAAU,MAAM,UAAU,gBAAgB,UAAU,SAAS,SAAS,iBAAiB,KAAA;AAAA,EAAK,GAC5G,GAAG,QAAQ,EAAE,OAAO,kCAAkC,OAAO,EAAE,eAAe,OAAA,EAAO,CAAG,CAAC;AAC5F,MAAI,KAAK,QAAQ,OAAO,YAAY;AACpC,SAAO,iBAAiB,SAAS,MAAM;AAGnC,UAAM,OAAO,OAAO,aAAa,cAAc,MAAM;AACrD,WAAO,aAAa,gBAAgB,OAAO,SAAS,OAAO;AAC3D,QAAI,OAAO,MAAM,IAAI;AAAA,EACzB,CAAC;AACD,SAAO;AACX;AAiBO,SAAS,OAAO,KAAkB,EAAE,MAAM,OAAO,MAAM,GAAG,MAAM,KAAK,OAAO,GAAG,OAAO,SAAS,UAA6C;AAC/I,MAAI,CAAC,IAAI,KAAM,QAAO;AACtB,QAAM,QAAQ,GAAG,SAAS;AAAA,IACtB,OAAO;AAAA,IACP,OAAO,EAAE,MAAM,SAAS,KAAK,KAAK,MAAM,OAAO,iBAAiB,KAAA;AAAA,EAAK,CACxE;AACD,QAAM,QAAQ,GAAG,UAAU,EAAE,OAAO,kCAAkC;AACtE,QAAM,QAAQ,GAAG,QAAQ,EAAE,OAAO,kCAAkC;AACpE,MAAI,KAAK,OAAO,KAAK;AACrB,MAAI,KAAK,OAAO,OAAO,YAAY;AACnC,QAAM,QAAQ,CAAC,MAAc;AACzB,UAAM,cAAc,OAAO,CAAC;AAC5B,UAAM,aAAa,kBAAkB,OAAO,CAAC,CAAC;AAAA,EAClD;AACA,MAAI,KAAK,OAAO,MAAM,OAAO,OAAO,MAAM,KAAK,CAAC,CAAC;AACjD,QAAM,KAAK;AACX,QAAM,iBAAiB,SAAS,MAAM,MAAM,OAAO,MAAM,KAAK,CAAC,CAAC;AAChE,QAAM,iBAAiB,UAAU,MAAM,IAAI,OAAO,MAAM,OAAO,MAAM,KAAK,CAAC,CAAC;AAC5E,SAAO,GAAG,SAAS,EAAE,OAAO,8BAA8B,OAAO,OAAO,KAAK;AACjF;"}
|
|
@@ -181,6 +181,12 @@ const KIT_WORDS = {
|
|
|
181
181
|
const kitStyles = '/* =========================================\n @aparte/plugin-cards — what every card shares\n =========================================\n A card wears core\'s `.aparte-card` recipe (border, radius, surface) and adds only what\n is its own: its width in the bubble, its one-line state drawing, its actions. Every\n value is a token, so a theme that restyles `--aparte-*` restyles the cards with it.\n */\n\n.aparte-rich-card {\n --aparte-rich-card-max-inline-size: 26rem;\n --aparte-rich-card-gap: var(--aparte-space-4);\n --aparte-rich-card-padding: var(--aparte-space-6);\n\n position: relative;\n /* A definite width: a bubble shrinks to its content, so a percentage would resolve to\n nothing. The card asks for its size and the bubble\'s own limit caps it. */\n inline-size: var(--aparte-rich-card-max-inline-size);\n max-inline-size: 100%;\n margin-block: var(--aparte-space-3);\n font-family: var(--aparte-font-family);\n font-variant-numeric: tabular-nums;\n line-height: 1.35;\n isolation: isolate;\n}\n\n.aparte-rich-card__glyph {\n display: inline-flex;\n flex: none;\n inline-size: var(--aparte-rich-card-glyph-size, 1.5rem);\n block-size: var(--aparte-rich-card-glyph-size, 1.5rem);\n}\n\n.aparte-rich-card__glyph > svg {\n inline-size: 100%;\n block-size: 100%;\n overflow: visible;\n}\n\n/* The one line a call shows when it has nothing to draw: waiting, refused, failed. */\n.aparte-rich-card[data-state="waiting"],\n.aparte-rich-card[data-state="refused"],\n.aparte-rich-card[data-state="unavailable"] {\n inline-size: fit-content;\n background: var(--aparte-surface-1);\n}\n\n.aparte-rich-card__strip {\n display: flex;\n align-items: center;\n gap: var(--aparte-space-3);\n padding: var(--aparte-space-3) var(--aparte-space-5);\n color: var(--aparte-text-muted);\n font-size: var(--aparte-font-size-md);\n --aparte-rich-card-glyph-size: 1.25rem;\n}\n\n.aparte-rich-card__strip .aparte-rich-card__glyph {\n opacity: 0.7;\n filter: grayscale(0.6);\n}\n\n.aparte-rich-card__strip-title {\n color: var(--aparte-text);\n font-weight: var(--aparte-font-weight-medium);\n}\n\n.aparte-rich-card__strip-state::before {\n content: "·";\n margin-inline-end: var(--aparte-space-3);\n}\n\n/* Buttons under a card: the button recipe, laid out. */\n.aparte-rich-card__actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--aparte-space-3);\n padding: var(--aparte-space-4) var(--aparte-rich-card-padding) var(--aparte-space-5);\n border-block-start: var(--aparte-border-width) solid var(--aparte-border);\n background: var(--aparte-surface-1);\n}\n\n/* A card this page did not set up: its sentence. */\n.aparte-rich-card__fallback {\n margin-block: var(--aparte-space-2);\n}\n\n/* Sparklines: the line takes the card\'s accent, the area fades from it. */\n.aparte-rich-card__sparkline {\n display: block;\n inline-size: 100%;\n block-size: 100%;\n overflow: visible;\n}\n\n.aparte-rich-card__sparkline-line {\n fill: none;\n stroke: var(--aparte-rich-card-spark, currentColor);\n stroke-width: 2;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.aparte-rich-card__sparkline-area {\n fill: var(--aparte-rich-card-spark, currentColor);\n opacity: 0.14;\n stroke: none;\n}\n\n/* ── Rating: five stars, the coloured row clipped to the value ─────────── */\n\n.aparte-rich-card__rating {\n display: inline-flex;\n align-items: center;\n gap: var(--aparte-space-2);\n font-size: var(--aparte-font-size-sm);\n white-space: nowrap;\n}\n\n.aparte-rich-card__stars {\n position: relative;\n display: inline-block;\n inline-size: 5.25em;\n block-size: 1.05em;\n flex: none;\n}\n\n.aparte-rich-card__stars-base,\n.aparte-rich-card__stars-fill {\n position: absolute;\n inset: 0;\n inline-size: 100%;\n block-size: 100%;\n}\n\n.aparte-rich-card__stars-base { fill: color-mix(in oklab, var(--aparte-text) 16%, transparent); }\n\n.aparte-rich-card__stars-fill {\n fill: var(--aparte-rich-card-star, #f5a623);\n clip-path: inset(0 calc(100% - var(--aparte-rich-card-rating, 0%)) 0 0);\n}\n\n/* Right to left the fill grows from the right: the clip is mirrored. The stars are symmetric,\n so the glyphs themselves need no flip — a scaleX(-1) here moved the fill back to the left. */\n.aparte-rich-card__stars-fill:dir(rtl) {\n clip-path: inset(0 0 0 calc(100% - var(--aparte-rich-card-rating, 0%)));\n}\n\n.aparte-rich-card__stars svg {\n display: block;\n inline-size: 100%;\n block-size: 100%;\n}\n\n.aparte-rich-card__rating-value { font-weight: var(--aparte-font-weight-semibold); }\n.aparte-rich-card__rating-count { color: var(--aparte-text-muted); }\n\n/* ── Carousel: native scrolling, snap points, two buttons ───────────────── */\n\n.aparte-rich-card__carousel {\n --aparte-rich-card-slide-size: 13.5rem;\n --aparte-rich-card-slide-gap: var(--aparte-space-4);\n position: relative;\n}\n\n.aparte-rich-card__track {\n display: grid;\n grid-auto-flow: column;\n grid-auto-columns: var(--aparte-rich-card-slide-size);\n column-gap: var(--aparte-rich-card-slide-gap);\n overflow-x: auto;\n overscroll-behavior-x: contain;\n scroll-snap-type: x mandatory;\n /* Room round the slides for a tile\'s shadow, its lift on hover and its focus ring —\n a scroller clips everything outside its box — given back by the margin, so the\n slides still line up with what is above and below them. */\n --aparte-rich-card-track-inset: var(--aparte-space-3);\n --aparte-rich-card-track-inset-end: var(--aparte-space-6);\n margin: calc(var(--aparte-rich-card-track-inset) * -1) calc(var(--aparte-rich-card-track-inset) * -1) calc(var(--aparte-rich-card-track-inset-end) * -1);\n padding: var(--aparte-rich-card-track-inset) var(--aparte-rich-card-track-inset) var(--aparte-rich-card-track-inset-end);\n scroll-padding-inline: var(--aparte-rich-card-track-inset);\n scrollbar-width: none;\n}\n\n.aparte-rich-card__track::-webkit-scrollbar { display: none; }\n\n.aparte-rich-card__track:focus-visible {\n outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);\n outline-offset: var(--aparte-focus-outline-offset);\n border-radius: var(--aparte-radius-lg);\n}\n\n.aparte-rich-card__slide {\n display: flex;\n scroll-snap-align: start;\n min-inline-size: 0;\n}\n\n.aparte-rich-card__slide > * { flex: 1; min-inline-size: 0; }\n\n.aparte-rich-card__nav {\n position: absolute;\n inset-block-start: 50%;\n z-index: 1;\n translate: 0 -50%;\n border-radius: var(--aparte-radius-full);\n box-shadow: 0 2px 10px -2px rgb(0 0 0 / 0.25);\n opacity: 0;\n transition: opacity var(--aparte-duration-fast, 120ms) ease;\n}\n\n.aparte-rich-card__nav--prev { inset-inline-start: calc(var(--aparte-space-3) * -1); }\n.aparte-rich-card__nav--next { inset-inline-end: calc(var(--aparte-space-3) * -1); }\n.aparte-rich-card__nav--prev:dir(rtl), .aparte-rich-card__nav--next:dir(rtl) { transform: scaleX(-1); }\n\n.aparte-rich-card__carousel[data-overflow] .aparte-rich-card__nav:not(:disabled) { opacity: 1; }\n.aparte-rich-card__carousel:not([data-overflow]) .aparte-rich-card__nav,\n.aparte-rich-card__nav:disabled { pointer-events: none; }\n\n/* ── Live cards: busy while the app answers a change ────────────────────── */\n\n.aparte-rich-card[data-busy] {\n cursor: progress;\n}\n\n.aparte-rich-card[data-busy]::after {\n content: "";\n position: absolute;\n inset-inline: 0;\n inset-block-start: 0;\n z-index: 3;\n block-size: 2px;\n background: linear-gradient(90deg, transparent, var(--aparte-primary), transparent);\n background-size: 50% 100%;\n background-repeat: no-repeat;\n animation: aparte-rich-card-busy 1s linear infinite;\n}\n\n@keyframes aparte-rich-card-busy {\n from { background-position: -50% 0; }\n to { background-position: 150% 0; }\n}\n\n/* ── Controls: a row of choices, a switch, a slider ─────────────────────── */\n\n.aparte-rich-card__segmented {\n display: inline-flex;\n gap: 2px;\n padding: 2px;\n border-radius: var(--aparte-radius-full);\n background: color-mix(in oklab, var(--aparte-text) 7%, transparent);\n}\n\n.aparte-rich-card__segment {\n min-inline-size: 2.5rem;\n /* 24px at least: the smallest target WCAG 2.2 accepts for a pointer (2.5.8). */\n min-block-size: 1.5rem;\n padding: var(--aparte-space-1) var(--aparte-space-3);\n border: 0;\n border-radius: var(--aparte-radius-full);\n background: transparent;\n color: var(--aparte-text-muted);\n font: inherit;\n font-size: var(--aparte-font-size-xs);\n font-weight: var(--aparte-font-weight-semibold);\n cursor: pointer;\n}\n\n.aparte-rich-card__segment:hover { color: var(--aparte-text); }\n\n.aparte-rich-card__segment[aria-pressed="true"] {\n background: var(--aparte-surface-1);\n color: var(--aparte-text);\n box-shadow: 0 1px 3px rgb(0 0 0 / 0.14);\n cursor: default;\n}\n\n.aparte-rich-card__segment:focus-visible,\n.aparte-rich-card__toggle:focus-visible,\n.aparte-rich-card__slider-input:focus-visible {\n outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);\n outline-offset: var(--aparte-focus-outline-offset);\n}\n\n.aparte-rich-card__toggle {\n position: relative;\n flex: none;\n inline-size: 2.5rem;\n block-size: 1.5rem;\n padding: 0;\n border: 0;\n border-radius: var(--aparte-radius-full);\n background: color-mix(in oklab, var(--aparte-text) 22%, transparent);\n cursor: pointer;\n transition: background-color 0.15s ease;\n}\n\n.aparte-rich-card__toggle[aria-checked="true"] { background: var(--aparte-primary); }\n\n.aparte-rich-card__toggle-thumb {\n position: absolute;\n inset-block-start: 3px;\n inset-inline-start: 3px;\n inline-size: calc(1.5rem - 6px);\n block-size: calc(1.5rem - 6px);\n border-radius: var(--aparte-radius-full);\n background: #fff;\n box-shadow: 0 1px 3px rgb(0 0 0 / 0.25);\n transition: inset-inline-start 0.15s ease;\n}\n\n.aparte-rich-card__toggle[aria-checked="true"] .aparte-rich-card__toggle-thumb {\n inset-inline-start: calc(100% - 1.5rem + 3px);\n}\n\n.aparte-rich-card__slider {\n display: grid;\n grid-template-columns: 1fr auto;\n align-items: center;\n gap: var(--aparte-space-1) var(--aparte-space-4);\n font-size: var(--aparte-font-size-sm);\n}\n\n.aparte-rich-card__slider-label { color: var(--aparte-text-muted); }\n\n.aparte-rich-card__slider-value {\n grid-row: 1;\n grid-column: 2;\n font-weight: var(--aparte-font-weight-semibold);\n font-variant-numeric: tabular-nums;\n}\n\n.aparte-rich-card__slider-input {\n grid-column: 1 / -1;\n inline-size: 100%;\n margin: 0;\n accent-color: var(--aparte-primary);\n cursor: pointer;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .aparte-rich-card,\n .aparte-rich-card::after,\n .aparte-rich-card *,\n .aparte-rich-card *::before,\n .aparte-rich-card *::after {\n animation: none !important;\n transition: none !important;\n }\n}\n';
|
|
182
182
|
const CARD_SEGMENT_TYPE = "card";
|
|
183
183
|
const registries = /* @__PURE__ */ new WeakMap();
|
|
184
|
+
function drawCardSegment(config, segment) {
|
|
185
|
+
return registries.get(config)?.get(segment.card)?.at(-1)?.draw(segment) ?? null;
|
|
186
|
+
}
|
|
187
|
+
function cardsSetUp(config) {
|
|
188
|
+
return [...registries.get(config)?.keys() ?? []];
|
|
189
|
+
}
|
|
184
190
|
const bindings = /* @__PURE__ */ new WeakMap();
|
|
185
191
|
const MARKUP = ":markup";
|
|
186
192
|
function apply(target, compute, attr) {
|
|
@@ -695,26 +701,28 @@ function formatWhen(config, date) {
|
|
|
695
701
|
export {
|
|
696
702
|
CARD_SEGMENT_TYPE as C,
|
|
697
703
|
KIT_WORDS as K,
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
704
|
+
currencyCode as a,
|
|
705
|
+
defineCard as b,
|
|
706
|
+
cardsSetUp as c,
|
|
707
|
+
drawCardSegment as d,
|
|
702
708
|
el as e,
|
|
703
709
|
formatDay as f,
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
710
|
+
formatHour as g,
|
|
711
|
+
formatNumber as h,
|
|
712
|
+
formatPercent as i,
|
|
713
|
+
formatPrice as j,
|
|
714
|
+
formatUnit as k,
|
|
715
|
+
formatWhen as l,
|
|
716
|
+
glyph as m,
|
|
717
|
+
intlTag as n,
|
|
718
|
+
languageOf as o,
|
|
719
|
+
num as p,
|
|
720
|
+
str as q,
|
|
721
|
+
word as r,
|
|
716
722
|
safeUrl as s,
|
|
717
723
|
toDate as t,
|
|
724
|
+
readPriceText as u,
|
|
725
|
+
bindMarkup as v,
|
|
718
726
|
webUrl as w
|
|
719
727
|
};
|
|
720
|
-
//# sourceMappingURL=format-
|
|
728
|
+
//# sourceMappingURL=format-BFq79ydr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-BFq79ydr.js","sources":["../src/kit/dom.ts","../src/kit/strings.ts","../src/kit/cards.css?raw","../src/kit/define.ts","../src/kit/format.ts"],"sourcesContent":["/**\n * The few DOM helpers every card draws with.\n *\n * A card shows what a tool returned, and a tool's result is untrusted: every value goes\n * in through `textContent` or an attribute, never through `innerHTML`. The one markup a\n * card parses is its own glyphs, which are constants of this package.\n */\n\ntype Child = Node | string | null | undefined | false;\n\n/** An element with classes, attributes and children; text children become text nodes. */\nexport function el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n props: { class?: string; attrs?: Record<string, string | number | boolean | null | undefined>; text?: string } = {},\n ...children: Child[]\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n if (props.class) node.className = props.class;\n for (const [name, value] of Object.entries(props.attrs ?? {})) {\n if (value === null || value === undefined || value === false) continue;\n node.setAttribute(name, value === true ? '' : String(value));\n }\n if (props.text !== undefined) node.textContent = props.text;\n for (const child of children) {\n if (child === null || child === undefined || child === false) continue;\n node.append(child);\n }\n return node;\n}\n\n/** One of this package's own SVG glyphs, as an element. Never call it with outside markup. */\nexport function glyph(markup: string, className = 'aparte-rich-card__glyph'): HTMLElement {\n const holder = document.createElement('span');\n holder.className = className;\n holder.setAttribute('aria-hidden', 'true');\n holder.innerHTML = markup;\n return holder;\n}\n\n/**\n * A link a card may open: `http(s)`, `mailto` and `tel` only, resolved against the page.\n * Anything else — `javascript:`, `data:`, a typo — is no link, so the action is not drawn.\n */\nexport function safeUrl(raw: unknown): string | null {\n if (typeof raw !== 'string' || !raw.trim()) return null;\n try {\n const url = new URL(raw.trim(), typeof location === 'undefined' ? 'https://localhost/' : location.href);\n return ['http:', 'https:', 'mailto:', 'tel:'].includes(url.protocol) ? url.href : null;\n } catch {\n return null;\n }\n}\n\n/**\n * A web address (`http`/`https`) — for an image or a page, where `mailto:` and `tel:` make no\n * sense. Absolute only: it comes from a tool's result, and a relative one (`lille.png`,\n * `/api/logout`) would become a request to the app's own origin, with its cookies, on render.\n */\nexport function webUrl(raw: unknown): string | null {\n if (typeof raw !== 'string' || !/^\\s*(https?:)?\\/\\//i.test(raw)) return null;\n const url = safeUrl(raw);\n return url && /^https?:/i.test(url) ? url : null;\n}\n\n/**\n * A tool's JSON, read key by key through the vendors' shapes (`r['geometry']?.['location']`).\n * Loose on purpose: no value read from it is used before a reader (`num`, `str`, `webUrl`,\n * `toDate`…) has checked it, so typing every level would add casts and no safety. Not exported\n * from the package.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type Loose = Record<string, any>;\n\n/** A finite number, or `undefined` — a tool's \"N/A\", `null` or `\"12\"` handled once. */\nexport function num(value: unknown): number | undefined {\n if (typeof value === 'number') return Number.isFinite(value) ? value : undefined;\n if (typeof value === 'string' && value.trim() !== '') {\n const n = Number(value);\n return Number.isFinite(n) ? n : undefined;\n }\n return undefined;\n}\n\n/** A non-empty trimmed string, or `undefined`. */\nexport function str(value: unknown): string | undefined {\n if (typeof value === 'string') return value.trim() || undefined;\n if (typeof value === 'number' && Number.isFinite(value)) return String(value);\n return undefined;\n}\n","/**\n * A card's words, in the chat's language.\n *\n * Core's locale is a closed list of what CORE draws, so a plugin reads its own keys off\n * `getLocale()` and defaults them at the call site (the localization guide). A card does\n * that, with one step in between: this package carries its words in the ten languages\n * `@aparte/locales` ships, picked by the locale's `tag`. An app that sets a key wins;\n * a language the table does not have reads English.\n *\n * aparteGlobalConfig.extendLocale({ cardsWeatherWind: 'Vent' });\n */\nimport type { AparteConfig } from '@aparte/core';\n\n/** The languages a card's words come in, beside English. */\nexport type CardLanguage = 'fr' | 'de' | 'es' | 'it' | 'ja' | 'ko' | 'pt' | 'ru' | 'zh';\n\n/** One word or phrase, in English and in as many of the other languages as it has. */\nexport type CardWord = { en: string } & Partial<Record<CardLanguage, string>>;\n\n/** The language part of the locale's tag: `pt-BR` → `pt`, `zh-CN` → `zh`, none → `en`. */\nexport function languageOf(config: AparteConfig): string {\n const tag = config.getLocale().tag;\n return (typeof tag === 'string' && tag ? tag.split('-')[0]!.toLowerCase() : 'en');\n}\n\n/** The locale's tag for `Intl`, or `undefined` to follow the browser (never `''`, which throws). */\nexport function intlTag(config: AparteConfig): string | undefined {\n const tag = config.getLocale().tag;\n if (typeof tag !== 'string' || !tag) return undefined;\n // A tag `Intl` refuses (`en_US`, a typo) would make every number and date on the card\n // throw, so the card would not draw at all: the underscore form is mended, anything else\n // follows the browser.\n for (const candidate of [tag, tag.replace(/_/g, '-')]) {\n try {\n return Intl.getCanonicalLocales(candidate)[0];\n } catch {\n // the next candidate\n }\n }\n return undefined;\n}\n\n/**\n * The word for `key`: the app's locale first, then this package's table for the chat's\n * language, then English. `{name}` placeholders are filled from `vars`.\n */\nexport function word(config: AparteConfig, key: string, table: CardWord, vars: Record<string, string> = {}): string {\n const fromApp = config.getLocale()[key];\n const lang = languageOf(config) as CardLanguage;\n const text = (typeof fromApp === 'string' && fromApp) || table[lang] || table.en;\n return text.replace(/\\{(\\w+)\\}/g, (all, name: string) => vars[name] ?? all);\n}\n\n/** The words every card shares. */\nexport const KIT_WORDS = {\n cardsUnavailable: {\n en: 'Not available', fr: 'Indisponible', de: 'Nicht verfügbar', es: 'No disponible', it: 'Non disponibile',\n ja: '利用できません', ko: '사용할 수 없음', pt: 'Indisponível', ru: 'Недоступно', zh: '不可用',\n },\n cardsWaiting: {\n en: 'Waiting for your approval', fr: 'En attente de votre accord', de: 'Wartet auf Ihre Zustimmung',\n es: 'Esperando tu aprobación', it: 'In attesa della tua approvazione', ja: '承認を待っています',\n ko: '승인을 기다리는 중', pt: 'Aguardando sua aprovação', ru: 'Ожидает вашего подтверждения', zh: '等待您的批准',\n },\n cardsRefused: {\n en: 'Not run', fr: 'Non exécuté', de: 'Nicht ausgeführt', es: 'No ejecutado', it: 'Non eseguito',\n ja: '実行されませんでした', ko: '실행되지 않음', pt: 'Não executado', ru: 'Не выполнено', zh: '未执行',\n },\n cardsLoading: {\n en: 'Loading', fr: 'Chargement', de: 'Wird geladen', es: 'Cargando', it: 'Caricamento',\n ja: '読み込み中', ko: '불러오는 중', pt: 'Carregando', ru: 'Загрузка', zh: '加载中',\n },\n cardsPrevious: {\n en: 'Previous', fr: 'Précédent', de: 'Zurück', es: 'Anterior', it: 'Precedente',\n ja: '前へ', ko: '이전', pt: 'Anterior', ru: 'Назад', zh: '上一个',\n },\n cardsNext: {\n en: 'Next', fr: 'Suivant', de: 'Weiter', es: 'Siguiente', it: 'Successivo',\n ja: '次へ', ko: '다음', pt: 'Próximo', ru: 'Далее', zh: '下一个',\n },\n cardsSlide: {\n en: '{n} of {total}', fr: '{n} sur {total}', de: '{n} von {total}', es: '{n} de {total}', it: '{n} di {total}',\n ja: '{total}件中{n}件目', ko: '{total}개 중 {n}번째', pt: '{n} de {total}', ru: '{n} из {total}', zh: '第 {n} 个,共 {total} 个',\n },\n cardsRating: {\n en: 'Rated {value} out of {max}', fr: 'Noté {value} sur {max}', de: 'Bewertet mit {value} von {max}',\n es: 'Valoración: {value} de {max}', it: 'Valutato {value} su {max}', ja: '{max}点中{value}点',\n ko: '{max}점 만점에 {value}점', pt: 'Avaliado em {value} de {max}', ru: 'Оценка {value} из {max}', zh: '评分 {value}/{max}',\n },\n cardsReviews: {\n en: '{count} reviews', fr: '{count} avis', de: '{count} Bewertungen', es: '{count} reseñas', it: '{count} recensioni',\n ja: 'レビュー{count}件', ko: '리뷰 {count}개', pt: '{count} avaliações', ru: 'Отзывов: {count}', zh: '{count} 条评价',\n },\n} satisfies Record<string, CardWord>;\n","export default \"/* =========================================\\n @aparte/plugin-cards — what every card shares\\n =========================================\\n A card wears core's `.aparte-card` recipe (border, radius, surface) and adds only what\\n is its own: its width in the bubble, its one-line state drawing, its actions. Every\\n value is a token, so a theme that restyles `--aparte-*` restyles the cards with it.\\n */\\n\\n.aparte-rich-card {\\n --aparte-rich-card-max-inline-size: 26rem;\\n --aparte-rich-card-gap: var(--aparte-space-4);\\n --aparte-rich-card-padding: var(--aparte-space-6);\\n\\n position: relative;\\n /* A definite width: a bubble shrinks to its content, so a percentage would resolve to\\n nothing. The card asks for its size and the bubble's own limit caps it. */\\n inline-size: var(--aparte-rich-card-max-inline-size);\\n max-inline-size: 100%;\\n margin-block: var(--aparte-space-3);\\n font-family: var(--aparte-font-family);\\n font-variant-numeric: tabular-nums;\\n line-height: 1.35;\\n isolation: isolate;\\n}\\n\\n.aparte-rich-card__glyph {\\n display: inline-flex;\\n flex: none;\\n inline-size: var(--aparte-rich-card-glyph-size, 1.5rem);\\n block-size: var(--aparte-rich-card-glyph-size, 1.5rem);\\n}\\n\\n.aparte-rich-card__glyph > svg {\\n inline-size: 100%;\\n block-size: 100%;\\n overflow: visible;\\n}\\n\\n/* The one line a call shows when it has nothing to draw: waiting, refused, failed. */\\n.aparte-rich-card[data-state=\\\"waiting\\\"],\\n.aparte-rich-card[data-state=\\\"refused\\\"],\\n.aparte-rich-card[data-state=\\\"unavailable\\\"] {\\n inline-size: fit-content;\\n background: var(--aparte-surface-1);\\n}\\n\\n.aparte-rich-card__strip {\\n display: flex;\\n align-items: center;\\n gap: var(--aparte-space-3);\\n padding: var(--aparte-space-3) var(--aparte-space-5);\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-md);\\n --aparte-rich-card-glyph-size: 1.25rem;\\n}\\n\\n.aparte-rich-card__strip .aparte-rich-card__glyph {\\n opacity: 0.7;\\n filter: grayscale(0.6);\\n}\\n\\n.aparte-rich-card__strip-title {\\n color: var(--aparte-text);\\n font-weight: var(--aparte-font-weight-medium);\\n}\\n\\n.aparte-rich-card__strip-state::before {\\n content: \\\"·\\\";\\n margin-inline-end: var(--aparte-space-3);\\n}\\n\\n/* Buttons under a card: the button recipe, laid out. */\\n.aparte-rich-card__actions {\\n display: flex;\\n flex-wrap: wrap;\\n gap: var(--aparte-space-3);\\n padding: var(--aparte-space-4) var(--aparte-rich-card-padding) var(--aparte-space-5);\\n border-block-start: var(--aparte-border-width) solid var(--aparte-border);\\n background: var(--aparte-surface-1);\\n}\\n\\n/* A card this page did not set up: its sentence. */\\n.aparte-rich-card__fallback {\\n margin-block: var(--aparte-space-2);\\n}\\n\\n/* Sparklines: the line takes the card's accent, the area fades from it. */\\n.aparte-rich-card__sparkline {\\n display: block;\\n inline-size: 100%;\\n block-size: 100%;\\n overflow: visible;\\n}\\n\\n.aparte-rich-card__sparkline-line {\\n fill: none;\\n stroke: var(--aparte-rich-card-spark, currentColor);\\n stroke-width: 2;\\n stroke-linecap: round;\\n stroke-linejoin: round;\\n}\\n\\n.aparte-rich-card__sparkline-area {\\n fill: var(--aparte-rich-card-spark, currentColor);\\n opacity: 0.14;\\n stroke: none;\\n}\\n\\n/* ── Rating: five stars, the coloured row clipped to the value ─────────── */\\n\\n.aparte-rich-card__rating {\\n display: inline-flex;\\n align-items: center;\\n gap: var(--aparte-space-2);\\n font-size: var(--aparte-font-size-sm);\\n white-space: nowrap;\\n}\\n\\n.aparte-rich-card__stars {\\n position: relative;\\n display: inline-block;\\n inline-size: 5.25em;\\n block-size: 1.05em;\\n flex: none;\\n}\\n\\n.aparte-rich-card__stars-base,\\n.aparte-rich-card__stars-fill {\\n position: absolute;\\n inset: 0;\\n inline-size: 100%;\\n block-size: 100%;\\n}\\n\\n.aparte-rich-card__stars-base { fill: color-mix(in oklab, var(--aparte-text) 16%, transparent); }\\n\\n.aparte-rich-card__stars-fill {\\n fill: var(--aparte-rich-card-star, #f5a623);\\n clip-path: inset(0 calc(100% - var(--aparte-rich-card-rating, 0%)) 0 0);\\n}\\n\\n/* Right to left the fill grows from the right: the clip is mirrored. The stars are symmetric,\\n so the glyphs themselves need no flip — a scaleX(-1) here moved the fill back to the left. */\\n.aparte-rich-card__stars-fill:dir(rtl) {\\n clip-path: inset(0 0 0 calc(100% - var(--aparte-rich-card-rating, 0%)));\\n}\\n\\n.aparte-rich-card__stars svg {\\n display: block;\\n inline-size: 100%;\\n block-size: 100%;\\n}\\n\\n.aparte-rich-card__rating-value { font-weight: var(--aparte-font-weight-semibold); }\\n.aparte-rich-card__rating-count { color: var(--aparte-text-muted); }\\n\\n/* ── Carousel: native scrolling, snap points, two buttons ───────────────── */\\n\\n.aparte-rich-card__carousel {\\n --aparte-rich-card-slide-size: 13.5rem;\\n --aparte-rich-card-slide-gap: var(--aparte-space-4);\\n position: relative;\\n}\\n\\n.aparte-rich-card__track {\\n display: grid;\\n grid-auto-flow: column;\\n grid-auto-columns: var(--aparte-rich-card-slide-size);\\n column-gap: var(--aparte-rich-card-slide-gap);\\n overflow-x: auto;\\n overscroll-behavior-x: contain;\\n scroll-snap-type: x mandatory;\\n /* Room round the slides for a tile's shadow, its lift on hover and its focus ring —\\n a scroller clips everything outside its box — given back by the margin, so the\\n slides still line up with what is above and below them. */\\n --aparte-rich-card-track-inset: var(--aparte-space-3);\\n --aparte-rich-card-track-inset-end: var(--aparte-space-6);\\n margin: calc(var(--aparte-rich-card-track-inset) * -1) calc(var(--aparte-rich-card-track-inset) * -1) calc(var(--aparte-rich-card-track-inset-end) * -1);\\n padding: var(--aparte-rich-card-track-inset) var(--aparte-rich-card-track-inset) var(--aparte-rich-card-track-inset-end);\\n scroll-padding-inline: var(--aparte-rich-card-track-inset);\\n scrollbar-width: none;\\n}\\n\\n.aparte-rich-card__track::-webkit-scrollbar { display: none; }\\n\\n.aparte-rich-card__track:focus-visible {\\n outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);\\n outline-offset: var(--aparte-focus-outline-offset);\\n border-radius: var(--aparte-radius-lg);\\n}\\n\\n.aparte-rich-card__slide {\\n display: flex;\\n scroll-snap-align: start;\\n min-inline-size: 0;\\n}\\n\\n.aparte-rich-card__slide > * { flex: 1; min-inline-size: 0; }\\n\\n.aparte-rich-card__nav {\\n position: absolute;\\n inset-block-start: 50%;\\n z-index: 1;\\n translate: 0 -50%;\\n border-radius: var(--aparte-radius-full);\\n box-shadow: 0 2px 10px -2px rgb(0 0 0 / 0.25);\\n opacity: 0;\\n transition: opacity var(--aparte-duration-fast, 120ms) ease;\\n}\\n\\n.aparte-rich-card__nav--prev { inset-inline-start: calc(var(--aparte-space-3) * -1); }\\n.aparte-rich-card__nav--next { inset-inline-end: calc(var(--aparte-space-3) * -1); }\\n.aparte-rich-card__nav--prev:dir(rtl), .aparte-rich-card__nav--next:dir(rtl) { transform: scaleX(-1); }\\n\\n.aparte-rich-card__carousel[data-overflow] .aparte-rich-card__nav:not(:disabled) { opacity: 1; }\\n.aparte-rich-card__carousel:not([data-overflow]) .aparte-rich-card__nav,\\n.aparte-rich-card__nav:disabled { pointer-events: none; }\\n\\n/* ── Live cards: busy while the app answers a change ────────────────────── */\\n\\n.aparte-rich-card[data-busy] {\\n cursor: progress;\\n}\\n\\n.aparte-rich-card[data-busy]::after {\\n content: \\\"\\\";\\n position: absolute;\\n inset-inline: 0;\\n inset-block-start: 0;\\n z-index: 3;\\n block-size: 2px;\\n background: linear-gradient(90deg, transparent, var(--aparte-primary), transparent);\\n background-size: 50% 100%;\\n background-repeat: no-repeat;\\n animation: aparte-rich-card-busy 1s linear infinite;\\n}\\n\\n@keyframes aparte-rich-card-busy {\\n from { background-position: -50% 0; }\\n to { background-position: 150% 0; }\\n}\\n\\n/* ── Controls: a row of choices, a switch, a slider ─────────────────────── */\\n\\n.aparte-rich-card__segmented {\\n display: inline-flex;\\n gap: 2px;\\n padding: 2px;\\n border-radius: var(--aparte-radius-full);\\n background: color-mix(in oklab, var(--aparte-text) 7%, transparent);\\n}\\n\\n.aparte-rich-card__segment {\\n min-inline-size: 2.5rem;\\n /* 24px at least: the smallest target WCAG 2.2 accepts for a pointer (2.5.8). */\\n min-block-size: 1.5rem;\\n padding: var(--aparte-space-1) var(--aparte-space-3);\\n border: 0;\\n border-radius: var(--aparte-radius-full);\\n background: transparent;\\n color: var(--aparte-text-muted);\\n font: inherit;\\n font-size: var(--aparte-font-size-xs);\\n font-weight: var(--aparte-font-weight-semibold);\\n cursor: pointer;\\n}\\n\\n.aparte-rich-card__segment:hover { color: var(--aparte-text); }\\n\\n.aparte-rich-card__segment[aria-pressed=\\\"true\\\"] {\\n background: var(--aparte-surface-1);\\n color: var(--aparte-text);\\n box-shadow: 0 1px 3px rgb(0 0 0 / 0.14);\\n cursor: default;\\n}\\n\\n.aparte-rich-card__segment:focus-visible,\\n.aparte-rich-card__toggle:focus-visible,\\n.aparte-rich-card__slider-input:focus-visible {\\n outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);\\n outline-offset: var(--aparte-focus-outline-offset);\\n}\\n\\n.aparte-rich-card__toggle {\\n position: relative;\\n flex: none;\\n inline-size: 2.5rem;\\n block-size: 1.5rem;\\n padding: 0;\\n border: 0;\\n border-radius: var(--aparte-radius-full);\\n background: color-mix(in oklab, var(--aparte-text) 22%, transparent);\\n cursor: pointer;\\n transition: background-color 0.15s ease;\\n}\\n\\n.aparte-rich-card__toggle[aria-checked=\\\"true\\\"] { background: var(--aparte-primary); }\\n\\n.aparte-rich-card__toggle-thumb {\\n position: absolute;\\n inset-block-start: 3px;\\n inset-inline-start: 3px;\\n inline-size: calc(1.5rem - 6px);\\n block-size: calc(1.5rem - 6px);\\n border-radius: var(--aparte-radius-full);\\n background: #fff;\\n box-shadow: 0 1px 3px rgb(0 0 0 / 0.25);\\n transition: inset-inline-start 0.15s ease;\\n}\\n\\n.aparte-rich-card__toggle[aria-checked=\\\"true\\\"] .aparte-rich-card__toggle-thumb {\\n inset-inline-start: calc(100% - 1.5rem + 3px);\\n}\\n\\n.aparte-rich-card__slider {\\n display: grid;\\n grid-template-columns: 1fr auto;\\n align-items: center;\\n gap: var(--aparte-space-1) var(--aparte-space-4);\\n font-size: var(--aparte-font-size-sm);\\n}\\n\\n.aparte-rich-card__slider-label { color: var(--aparte-text-muted); }\\n\\n.aparte-rich-card__slider-value {\\n grid-row: 1;\\n grid-column: 2;\\n font-weight: var(--aparte-font-weight-semibold);\\n font-variant-numeric: tabular-nums;\\n}\\n\\n.aparte-rich-card__slider-input {\\n grid-column: 1 / -1;\\n inline-size: 100%;\\n margin: 0;\\n accent-color: var(--aparte-primary);\\n cursor: pointer;\\n}\\n\\n@media (prefers-reduced-motion: reduce) {\\n .aparte-rich-card,\\n .aparte-rich-card::after,\\n .aparte-rich-card *,\\n .aparte-rich-card *::before,\\n .aparte-rich-card *::after {\\n animation: none !important;\\n transition: none !important;\\n }\\n}\\n\"","/**\n * `defineCard()` — what every card is made of, so a card only draws.\n *\n * A card is one drawing reached three ways, all of them seams core already has:\n *\n * - **a tool's result**: `registerToolRenderer` puts the card where the tool's row would\n * be. The app says which tool, and how its result maps onto the card's fields — its\n * data keeps its own shape;\n * - **a `card` segment**: a server, a runner or the app adds\n * `{ type: 'card', card: 'weather', data }` and the same card draws it. One segment\n * type for every card, not `custom`: an app has ONE renderer for `custom`, and taking\n * it would take the app's;\n * - a block in the text, for a source that only sends text — a later step.\n *\n * While the tool runs the card shows its skeleton, with what the call's input already\n * says (the city before the forecast). Waiting for a decision, refused, stopped or failed,\n * it shrinks to one line that says so — the result of a call that did not run is not\n * drawn as if it had.\n *\n * A **variant** is the same card laid out another way — `data-variant` on its root, read\n * by its sheet and its `render` — never a second registration.\n */\nimport {\n aparteGlobalConfig,\n cssEscape,\n overrideSegmentRenderer,\n type AparteConfig,\n type AparteSegmentBase,\n type AparteSegmentRenderer,\n type AparteToolCallSegment,\n type AparteToolMatcher,\n type AparteToolRenderer,\n} from '@aparte/core';\nimport { el, glyph, safeUrl } from './dom.js';\nimport { KIT_WORDS, word, type CardWord } from './strings.js';\nimport kitStyles from './cards.css?raw';\n\n/** The segment type every card shares. */\nexport const CARD_SEGMENT_TYPE = 'card';\n\n/**\n * A card added as a segment: `card` names it, `data` is in the card's own fields, and\n * `fallback` is the sentence a text-only reader gets — the history sent back to a model,\n * a build without this card.\n */\nexport interface AparteCardSegment extends AparteSegmentBase {\n type: 'card';\n card: string;\n data: unknown;\n variant?: string;\n fallback?: string;\n}\n\ndeclare module '@aparte/core' {\n interface AparteSegmentTypes {\n card: AparteCardSegment;\n }\n}\n\n/** A button under a card: a link it opens, a message it sends, or an `id` the app handles. */\nexport interface CardAction {\n label: string;\n /** Opened in a new tab; `http(s)`, `mailto` and `tel` only, otherwise the button is not drawn. */\n url?: string;\n /** Sent as the person's next message, through the chat's composer. */\n send?: string;\n /** Only reported, in the `aparte-card-action` event. */\n id?: string;\n /** Drawn as the card's main action. */\n primary?: boolean;\n}\n\n/**\n * A button under a card was pressed. Bubbles out of the chat; cancel it to handle the action\n * yourself instead of the link or the message. The detail is the card's name, the action and\n * the data the card was drawn from.\n *\n * @event aparte-card-action\n */\nexport interface CardActionEventDetail {\n card: string;\n action: CardAction;\n data: unknown;\n}\n\n/**\n * What `aparte-card-change` carries: a control inside a card was moved — a range chosen,\n * a switch flipped, a slider let go. Bubbles out of the chat; cancel the event to stop the\n * card's `onChange`.\n *\n * @event aparte-card-change\n */\nexport interface CardChangeEventDetail {\n card: string;\n /** The control's name, as the card gave it (`range`, `power`, `brightness`…). */\n name: string;\n value: unknown;\n /** The data the card was drawn from when the control moved. */\n data: unknown;\n}\n\n// Typed where they are dispatched: `addEventListener('aparte-card-action', (e) => e.detail.action)`\n// with no cast, on an element, the document or the window (both bubble out of the chat). The\n// types name the plugin's actions, so they cannot live in core's event map.\ninterface CardEventMap {\n 'aparte-card-action': CustomEvent<CardActionEventDetail>;\n 'aparte-card-change': CustomEvent<CardChangeEventDetail>;\n}\ndeclare global {\n interface HTMLElementEventMap extends CardEventMap {}\n interface DocumentEventMap extends CardEventMap {}\n interface WindowEventMap extends CardEventMap {}\n}\n\n/** What a card's drawing functions are handed. */\nexport interface CardContext<V extends string = string> {\n config: AparteConfig;\n variant: V;\n /** Where the data came from. */\n source: 'tool' | 'segment';\n /** Set `el`'s text to a word, and again after a language switch. */\n word(el: Element, key: string, table: CardWord, vars?: Record<string, string>): void;\n /** Set `el`'s text (or `attr`) from `compute`, and again after a language switch. */\n bind(el: Element, compute: () => string, attr?: string): void;\n /**\n * A button for an action inside the card — one per item of a carousel, say — wired like\n * the card's own: the `aparte-card-action` event (with `data`), then the link or the\n * message. `null` for an action that cannot run (no label, a link that is not http(s)).\n */\n action(action: CardAction, data?: unknown, className?: string): HTMLButtonElement | null;\n /**\n * Report that a control inside the card moved: `aparte-card-change` fires, then the\n * app's `onChange` runs, and what it returns is drawn in place — the same element,\n * the focus kept. The kit's controls (`segmented`, `toggle`, `slider`) call it.\n */\n change(name: string, value: unknown): void;\n /** Whether the app handles a change (an `onChange` was given): a card draws a control only when it does. */\n readonly live: boolean;\n}\n\n/** A card: its name, its variants, its sheet, and how it draws. */\nexport interface CardDefinition<D, V extends string = string> {\n /** The name a `card` segment gives, and the root's `data-card`. */\n name: string;\n /** Its layouts; the first is the default. */\n variants: readonly V[];\n /** Its stylesheet. The kit's own is added in front of it. */\n styles: string;\n /** The card's data from what it is given — `null` when there is nothing it can draw. */\n normalize(raw: unknown): D | null;\n /** The inside of the card, in `ctx.variant`. */\n render(data: D, ctx: CardContext<V>): Node[];\n /** The inside while the tool runs, from what its input already says. */\n skeleton(partial: Partial<D> | null, ctx: CardContext<V>): Node[];\n /** The card's accessible name (\"Weather in Lille\"), from whatever is known. */\n label(data: Partial<D> | null, ctx: CardContext<V>): string;\n /** One sentence of the data, for a reader that gets no card. */\n fallback(data: D, ctx: CardContext<V>): string;\n /** The one-line state drawing's glyph. */\n icon: string;\n /** What a running call's input already says: the city before the forecast. */\n partial?(input: Record<string, unknown>): Partial<D> | null;\n}\n\n/** How an app plugs a card in. */\nexport interface CardSetupOptions<D, V extends string = string> {\n /** The tool (or tools) whose result this card draws. Without it, only `card` segments draw it. */\n tool?: AparteToolMatcher | AparteToolMatcher[];\n /**\n * The card's fields from the tool's result — its `structuredContent` when it has one,\n * else its text parsed as JSON, else the text. Return `null` for a result the card\n * cannot draw. Without `map`, the result must already be in the card's fields.\n */\n // `any`: the result's shape is your tool's, and `map` is where you read it.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n map?: (result: any, input: Record<string, unknown>, segment: AparteToolCallSegment) => unknown;\n /** What the call's input already says, shown while it runs. Defaults to the card's own reading. */\n mapInput?: (input: Record<string, unknown>) => Partial<D> | null;\n /** A variant, or a function choosing one from the data. A name the card lacks reads as its default. */\n variant?: V | ((data: D) => V);\n /** Buttons under the card, at most three. */\n actions?: (data: D) => CardAction[];\n /**\n * A control inside the card moved (a range, a switch, a slider). Return the card's new\n * fields — the shape `map` returns — and the card is drawn again in place, the same\n * element with the focus kept; return nothing to leave it as it is. While it runs the\n * card is marked busy. Only the latest change is drawn when several overlap. The new\n * data lives in the page: a conversation reloaded from storage shows what was saved.\n */\n onChange?: (change: { name: string; value: unknown }, data: D) => unknown;\n /** The config to register on (the global one by default). */\n config?: AparteConfig;\n}\n\ntype DrawState = 'ready' | 'loading' | 'waiting' | 'refused' | 'unavailable';\n\n/** What a registered card keeps, per config. */\ninterface Entry {\n draw(segment: AparteCardSegment): HTMLElement;\n}\n\n/** Per config, each card's setups, the newest last: the newest draws the card's segments. */\nconst registries = new WeakMap<AparteConfig, Map<string, Entry[]>>();\n\n/**\n * Draw a `card` segment with the card set up under `card` on `config`, or `null` when none\n * is. Internal to the kit (the fences draw through it); not exported from the package.\n */\nexport function drawCardSegment(config: AparteConfig, segment: AparteCardSegment): HTMLElement | null {\n return registries.get(config)?.get(segment.card)?.at(-1)?.draw(segment) ?? null;\n}\n\n/** The names of the cards set up on `config`. Internal to the kit. */\nexport function cardsSetUp(config: AparteConfig): string[] {\n return [...(registries.get(config)?.keys() ?? [])];\n}\nconst bindings = new WeakMap<Element, Array<{ attr?: string; compute: () => string }>>();\n\n/**\n * Where a binding writes: an attribute, the text, or — for a glyph from core's icon provider —\n * the markup. Not a valid attribute name, so no attribute binding can be mistaken for it.\n */\nconst MARKUP = ':markup';\n\nfunction apply(target: Element, compute: () => string, attr?: string): void {\n const text = compute();\n if (attr === MARKUP) target.innerHTML = text; // safe-text: only bindMarkup writes here, with core's icon markup\n else if (attr) target.setAttribute(attr, text);\n else target.textContent = text;\n}\n\n/**\n * A glyph from core's icon provider, written again on a relabel — the provider can change\n * after the card is drawn (`setIconProvider`), and core's relabel contract re-reads it. Only\n * for markup that is core's own (`config.getIcon`), never for a value from the data.\n */\nexport function bindMarkup(target: Element, compute: () => string): void {\n apply(target, compute, MARKUP);\n const list = bindings.get(target) ?? [];\n list.push({ attr: MARKUP, compute });\n bindings.set(target, list);\n target.setAttribute('data-card-bound', '');\n}\n\n/** The text a drawn card holds in the chat's language, read again on a switch. */\nfunction relabel(root: Element): void {\n const own = bindings.get(root);\n if (own) for (const b of own) apply(root, b.compute, b.attr);\n for (const node of root.querySelectorAll('[data-card-bound]')) {\n for (const b of bindings.get(node) ?? []) apply(node, b.compute, b.attr);\n }\n}\n\nfunction makeContext<V extends string>(\n config: AparteConfig,\n variant: V,\n source: 'tool' | 'segment',\n card: string,\n onChange?: (name: string, value: unknown) => void,\n): CardContext<V> {\n const bind = (target: Element, compute: () => string, attr?: string) => {\n apply(target, compute, attr);\n const list = bindings.get(target) ?? [];\n list.push({ attr, compute });\n bindings.set(target, list);\n target.setAttribute('data-card-bound', '');\n };\n return {\n config,\n variant,\n source,\n bind,\n word: (target, key, table, vars) => bind(target, () => word(config, key, table, vars)),\n action: (action, data, className) => actionButton(card, action, data, className),\n change: (name, value) => onChange?.(name, value),\n live: onChange !== undefined,\n };\n}\n\n/**\n * Put `next`'s inside into `element` — the element already on the page — keeping it, its\n * place, and the focus: a control the reader just pressed is pressed again in the new\n * drawing (by its `data-card-key`, else by its position).\n */\nfunction patch(element: HTMLElement, next: HTMLElement): void {\n const active = typeof document === 'undefined' ? null : document.activeElement;\n let key: string | null = null;\n let path: number[] | null = null;\n if (active instanceof HTMLElement && element.contains(active) && active !== element) {\n key = active.getAttribute('data-card-key');\n path = [];\n for (let node: Element = active; node !== element; node = node.parentElement!) {\n path.unshift(Array.prototype.indexOf.call(node.parentElement!.children, node));\n }\n }\n for (const name of element.getAttributeNames()) if (!next.hasAttribute(name)) element.removeAttribute(name);\n for (const name of next.getAttributeNames()) element.setAttribute(name, next.getAttribute(name)!);\n element.replaceChildren(...next.childNodes);\n const moved = bindings.get(next);\n if (moved) bindings.set(element, moved);\n const from = drawnFrom.get(next);\n if (from === undefined) drawnFrom.delete(element);\n else drawnFrom.set(element, from);\n homes.set(next, element);\n if (key !== null || path) {\n let target: Element | null = key ? element.querySelector(`[data-card-key=\"${cssEscape(key)}\"]`) : null;\n if (!target && path) {\n target = element;\n for (const i of path) target = target?.children[i] ?? null;\n }\n if (target instanceof HTMLElement) target.focus({ preventScroll: true });\n }\n}\n\n/** A drawing that was moved into an element already on the page, and that element. */\nconst homes = new WeakMap<Element, HTMLElement>();\n\n/** Per drawn card, how many times core gave it a new result: a change started before is dropped. */\nconst changeTurns = new WeakMap<Element, number>();\n\n/** The changes a card is working through, and the data the last one left. */\ninterface Queue<D> {\n pending: Map<string, unknown>;\n running: boolean;\n data: D;\n variant: string;\n}\nconst queues = new WeakMap<Element, Queue<unknown>>();\n\n/** What each drawing was drawn from (see `fingerprint`), carried onto the page by `patch`. */\nconst drawnFrom = new WeakMap<Element, string>();\n\n/** Core drew the card from a new result: what was waiting on the app's answer no longer applies. */\nfunction bumpTurn(element: Element): void {\n changeTurns.set(element, (changeTurns.get(element) ?? 0) + 1);\n queues.delete(element);\n}\n\nfunction busy(element: Element, on: boolean): void {\n element.toggleAttribute('data-busy', on);\n if (on) element.setAttribute('aria-busy', 'true');\n else element.removeAttribute('aria-busy');\n}\n\n/** A button that runs `action`, or `null` when it cannot run. */\nfunction actionButton(card: string, action: CardAction, data: unknown, className = ''): HTMLButtonElement | null {\n if (!action || typeof action.label !== 'string' || !action.label.trim()) return null;\n const url = action.url === undefined ? undefined : safeUrl(action.url);\n if (action.url !== undefined && !url) return null;\n if (!url && action.send === undefined && action.id === undefined) return null;\n const button = el('button', {\n class: `aparte-btn aparte-btn--sm ${action.primary ? 'aparte-btn--primary aparte-btn--solid' : 'aparte-btn--surface'} aparte-rich-card__action${className ? ` ${className}` : ''}`,\n attrs: { type: 'button' },\n text: action.label,\n });\n button.addEventListener('click', (event) => {\n // A button inside a card that is itself a link must not follow the link too.\n event.stopPropagation();\n runAction(card, button, action, url, data);\n });\n return button;\n}\n\nfunction runAction(card: string, button: HTMLElement, action: CardAction, url: string | null | undefined, data: unknown): void {\n const detail: CardActionEventDetail = { card, action, data };\n const proceed = button.dispatchEvent(new CustomEvent<CardActionEventDetail>('aparte-card-action', {\n detail, bubbles: true, composed: true, cancelable: true,\n }));\n if (!proceed) return;\n if (url) {\n // `mailto:` and `tel:` hand over to the mail or phone app: a new tab for them is left\n // empty in some browsers. A web page opens beside the chat.\n if (/^https?:/i.test(url)) window.open(url, '_blank', 'noopener,noreferrer');\n else window.location.href = url;\n return;\n }\n if (action.send !== undefined) {\n type Composer = HTMLElement & { value: string; streaming: boolean; panelActive: boolean; setValue(v: string): void; submit(): void };\n // The chat the card is in, in every shape: `<aparte-chat>` (vanilla, Angular) or the\n // `<div data-aparte-chat>` the React, Vue and Svelte wrappers render.\n const composer = (button.closest('aparte-chat, [data-aparte-chat]')?.querySelector('aparte-composer')\n ?? document.querySelector('aparte-composer')) as Composer | null;\n if (!composer) {\n console.warn(`[aparte-cards] the ${card} card has no <aparte-composer> to send \"${action.send}\" through.`);\n return;\n }\n // While a reply streams, `submit()` stops it; while a question holds the composer, it\n // answers the question. Neither is what a card's button means.\n if (composer.streaming || composer.panelActive) return;\n const draft = composer.value;\n composer.setValue(action.send);\n composer.submit();\n // What the person was writing is theirs: it comes back once the card's message is sent.\n if (draft.trim()) composer.setValue(draft);\n }\n}\n\nfunction parseResult(segment: AparteToolCallSegment): unknown {\n if (segment.structuredResult !== undefined) return segment.structuredResult;\n const text = segment.result;\n if (typeof text !== 'string') return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction stateOf(segment: AparteToolCallSegment): DrawState {\n switch (segment.status) {\n case 'resolved': return 'ready';\n case 'pending': return 'loading';\n case 'awaiting-approval': return 'waiting';\n case 'rejected': return 'refused';\n default: return 'unavailable';\n }\n}\n\n/**\n * Define a card. Returns its `setup`, which plugs it into a chat and returns the function\n * that unplugs it.\n */\nexport function defineCard<D, V extends string>(definition: CardDefinition<D, V>) {\n const styles = `${kitStyles}\\n${definition.styles}`;\n const defaultVariant = definition.variants[0]!;\n const known = new Set<string>(definition.variants);\n const warned = new WeakSet<object>();\n\n function chooseVariant(options: CardSetupOptions<D, V>, data: D | null, asked?: string): V {\n const wanted = asked ?? (typeof options.variant === 'function' ? (data ? options.variant(data) : undefined) : options.variant);\n return (wanted && known.has(wanted) ? wanted : defaultVariant) as V;\n }\n\n function root(state: DrawState, variant: V, id: string): HTMLElement {\n return el('div', {\n class: `aparte-segment aparte-card aparte-rich-card aparte-${definition.name}-card`,\n attrs: {\n 'data-segment-id': id,\n 'data-card': definition.name,\n 'data-variant': variant,\n 'data-state': state,\n role: 'group',\n 'aria-busy': state === 'loading' ? 'true' : undefined,\n },\n });\n }\n\n function actionsOf(options: CardSetupOptions<D, V>, data: D): HTMLElement | null {\n const buttons = (options.actions?.(data) ?? [])\n .map((action) => actionButton(definition.name, action, data))\n .filter((b): b is HTMLButtonElement => b !== null)\n .slice(0, 3);\n return buttons.length ? el('div', { class: 'aparte-rich-card__actions' }, ...buttons) : null;\n }\n\n /** The one-line drawing of a call that has no data to show. */\n function strip(config: AparteConfig, state: Exclude<DrawState, 'ready' | 'loading'>, partial: Partial<D> | null, variant: V, id: string, source: 'tool' | 'segment' = 'tool'): HTMLElement {\n const node = root(state, variant, id);\n const ctx = makeContext(config, variant, source, definition.name);\n const key = state === 'waiting' ? 'cardsWaiting' : state === 'refused' ? 'cardsRefused' : 'cardsUnavailable';\n const title = el('span', { class: 'aparte-rich-card__strip-title' });\n ctx.bind(title, () => definition.label(partial, ctx));\n const status = el('span', { class: 'aparte-rich-card__strip-state' });\n ctx.word(status, key, KIT_WORDS[key]);\n node.append(el('div', { class: 'aparte-rich-card__strip' }, glyph(definition.icon), title, status));\n ctx.bind(node, () => definition.label(partial, ctx), 'aria-label');\n return node;\n }\n\n function drawTool(options: CardSetupOptions<D, V>, config: AparteConfig, segment: AparteToolCallSegment): HTMLElement {\n const state = stateOf(segment);\n const input = (segment.toolCall?.input ?? {}) as Record<string, unknown>;\n const readInput = options.mapInput ?? definition.partial;\n let partial: Partial<D> | null = null;\n try {\n partial = readInput?.(input) ?? null;\n } catch {\n partial = null;\n }\n if (state === 'loading') {\n const variant = chooseVariant(options, null);\n const node = root(state, variant, segment.id);\n const ctx = makeContext(config, variant, 'tool', definition.name);\n node.append(...definition.skeleton(partial, ctx));\n ctx.bind(node, () => `${definition.label(partial, ctx)} — ${word(config, 'cardsLoading', KIT_WORDS.cardsLoading)}`, 'aria-label');\n return node;\n }\n if (state !== 'ready') return strip(config, state, partial, chooseVariant(options, null), segment.id);\n let data: D | null = null;\n let from = '';\n try {\n const raw = parseResult(segment);\n from = fingerprint(raw);\n const live = recall(options, `tool:${segment.id}`, from);\n if (live) return drawData(options, config, live.data, live.variant, segment.id, 'tool', from);\n data = definition.normalize(options.map ? options.map(raw, input, segment) : raw);\n } catch (error) {\n console.warn(`[aparte-cards] the ${definition.name} card's map threw:`, error);\n }\n if (!data) {\n if (!warned.has(options)) {\n warned.add(options);\n console.warn(`[aparte-cards] the ${definition.name} card got a result it cannot draw — check its \\`map\\` (tool \"${segment.toolCall?.name}\").`);\n }\n return strip(config, 'unavailable', partial, chooseVariant(options, null), segment.id);\n }\n return drawData(options, config, data, chooseVariant(options, data), segment.id, 'tool', from);\n }\n\n /**\n * What `onChange` gave each card, by the segment it is drawn for and what it was drawn\n * from. Core draws a segment again from the message — when a turn ends, when the\n * conversation is saved, when a Markdown provider arrives late — and only a framework\n * component's drawing survives that; without this, a card would go back to its first\n * data at the next save. A new result for the segment is drawn as it is; the old one,\n * shown again (a branch switched back), comes back as the person left it.\n */\n const kept = new WeakMap<CardSetupOptions<D, V>, Map<string, { from: string; data: D; variant: V }>>();\n\n function recall(options: CardSetupOptions<D, V>, key: string, from: string): { data: D; variant: V } | undefined {\n // A different result is not used, and not forgotten either: a segment id is not unique\n // across conversations (a model may number its calls the same way every time), and a\n // branch switched away and back shows the first result again — the card the person\n // left is the one they come back to. KEPT_MAX bounds what is kept.\n const entry = kept.get(options)?.get(key);\n return entry && from && entry.from === from ? entry : undefined;\n }\n\n function remember(options: CardSetupOptions<D, V>, key: string, from: string, data: D, variant: V): void {\n // A result that cannot be told apart from another cannot be matched again.\n if (!from) return;\n const byKey = kept.get(options) ?? new Map<string, { from: string; data: D; variant: V }>();\n kept.set(options, byKey);\n byKey.delete(key);\n byKey.set(key, { from, data, variant });\n // The oldest go first: a page that changed a hundred cards still remembers the latest.\n if (byKey.size > KEPT_MAX) byKey.delete(byKey.keys().next().value!);\n }\n\n function drawData(options: CardSetupOptions<D, V>, config: AparteConfig, data: D, variant: V, id: string, source: 'tool' | 'segment', from: string): HTMLElement {\n const node = root('ready', variant, id);\n drawnFrom.set(node, from);\n // The element on the page: a redraw moves this drawing into the one already there.\n const onChange = (name: string, value: unknown) => void change(homes.get(node) ?? node, options, config, data, variant, id, source, from, name, value);\n const ctx = makeContext(config, variant, source, definition.name, options.onChange ? onChange : undefined);\n node.append(...definition.render(data, ctx));\n const actions = actionsOf(options, data);\n if (actions) node.append(actions);\n ctx.bind(node, () => definition.label(data, ctx), 'aria-label');\n return node;\n }\n\n async function change(\n node: HTMLElement,\n options: CardSetupOptions<D, V>,\n config: AparteConfig,\n data: D,\n variant: V,\n id: string,\n source: 'tool' | 'segment',\n from: string,\n name: string,\n value: unknown,\n ): Promise<void> {\n const element = node;\n const waiting = queues.get(element) as Queue<D> | undefined;\n const detail: CardChangeEventDetail = { card: definition.name, name, value, data: waiting?.data ?? data };\n const proceed = element.dispatchEvent(new CustomEvent<CardChangeEventDetail>('aparte-card-change', {\n detail, bubbles: true, composed: true, cancelable: true,\n }));\n if (!proceed || !options.onChange) return;\n /*\n * One change at a time, in order, each from the data the one before it left. Run side\n * by side, each would start from the drawing it was pressed in, and the later answer —\n * built on data that never saw the earlier change — would undo it: the light turned on,\n * then dimmed, would come back off. A control moved again before its turn keeps only\n * its latest value: three presses on a range button ask for one range.\n */\n const queue: Queue<D> = waiting ?? { pending: new Map(), running: false, data, variant };\n queues.set(element, queue);\n queue.pending.delete(name);\n queue.pending.set(name, value);\n if (queue.running) return;\n queue.running = true;\n const turn = changeTurns.get(element) ?? 0;\n busy(element, true);\n try {\n while (queue.pending.size > 0) {\n const [nextName, nextValue] = queue.pending.entries().next().value!;\n queue.pending.delete(nextName);\n let next: unknown;\n try {\n next = await options.onChange({ name: nextName, value: nextValue }, queue.data);\n } catch (error) {\n console.warn(`[aparte-cards] the ${definition.name} card's onChange threw:`, error);\n continue;\n }\n // Core drew the card again from a new result while this ran: that result is newer.\n if ((changeTurns.get(element) ?? 0) !== turn) return;\n if (next === undefined || next === null) continue;\n const fresh = definition.normalize(next);\n if (!fresh) {\n console.warn(`[aparte-cards] the ${definition.name} card's onChange returned data it cannot draw — it was left as it was.`);\n continue;\n }\n queue.data = fresh;\n queue.variant = chooseVariant(options, fresh, queue.variant as V);\n remember(options, `${source}:${id}`, from, fresh, queue.variant as V);\n patch(element, drawData(options, config, fresh, queue.variant as V, id, source, from));\n if (queue.pending.size > 0) busy(element, true);\n }\n } finally {\n queue.running = false;\n if (queues.get(element) === queue) queues.delete(element);\n if ((changeTurns.get(element) ?? 0) === turn) busy(element, false);\n }\n }\n\n function setup(options: CardSetupOptions<D, V> = {}): () => void {\n const config = options.config ?? aparteGlobalConfig;\n const matchers = options.tool === undefined ? [] : Array.isArray(options.tool) ? options.tool : [options.tool];\n\n const toolRenderer: AparteToolRenderer = {\n render: (segment) => drawTool(options, config, segment),\n // Same element, new inside: the card the reader is looking at stays put.\n update: (element, segment) => {\n const next = drawTool(options, config, segment);\n // A new result is newer than any change still waiting on the app's answer; the\n // same result sent again (a turn ending, a save) leaves that change running.\n if (drawnFrom.get(next) !== drawnFrom.get(element)) bumpTurn(element);\n const wasBusy = element.hasAttribute('data-busy') && queues.has(element);\n patch(element, next);\n if (wasBusy) busy(element, true);\n },\n relabel: (element) => relabel(element),\n getStyles: () => styles,\n };\n // Overrides, not registrations: they stack. Two setups of the same tool — two components\n // that each declare it, a page that sets a card up twice — the newer draws, and taking\n // the older off leaves the newer in place; the last one off gives back what was there.\n const restores = matchers.map((match) => config.overrideToolRenderer(match, toolRenderer));\n\n const registry = registries.get(config) ?? new Map<string, Entry[]>();\n registries.set(config, registry);\n const entry: Entry = {\n draw: (segment) => {\n const from = fingerprint(segment.data);\n const live = recall(options, `segment:${segment.id}`, from);\n if (live) return drawData(options, config, live.data, live.variant, segment.id, 'segment', from);\n const data = definition.normalize(segment.data);\n const variant = chooseVariant(options, data, segment.variant);\n if (!data) return strip(config, 'unavailable', null, variant, segment.id, 'segment');\n return drawData(options, config, data, variant, segment.id, 'segment', from);\n },\n };\n const stack = registry.get(definition.name) ?? [];\n stack.push(entry);\n registry.set(definition.name, stack);\n // One override per setup, stacked like the tool's. Each registration injects the sheets\n // as they are now — a card whose module loaded after the first setup brings its own —\n // and draws again the `card` segments already on screen, so one drawn as its fallback\n // sentence before its card was set up becomes the card.\n const restoreSegments = overrideSegmentRenderer(cardSegmentRenderer(config), config);\n\n let stopped = false;\n return () => {\n if (stopped) return;\n stopped = true;\n for (const restore of restores) restore();\n const own = registry.get(definition.name);\n const at = own?.indexOf(entry) ?? -1;\n if (own && at >= 0) own.splice(at, 1);\n if (own && own.length === 0) registry.delete(definition.name);\n restoreSegments();\n };\n }\n\n /**\n * A `card` segment for this card, with its `fallback` sentence written — what a\n * server or a scenario adds to a message: `viewport.addSegment(id, weather.segment(data))`.\n */\n function segment(raw: unknown, options: { id?: string; variant?: V; config?: AparteConfig } = {}): AparteCardSegment {\n const config = options.config ?? aparteGlobalConfig;\n const data = definition.normalize(raw);\n const ctx = makeContext(config, (options.variant ?? defaultVariant) as V, 'segment', definition.name);\n return {\n id: options.id ?? `card-${definition.name}-${Math.random().toString(36).slice(2, 10)}`,\n type: CARD_SEGMENT_TYPE,\n card: definition.name,\n data: raw,\n ...(options.variant ? { variant: options.variant } : {}),\n ...(data ? { fallback: definition.fallback(data, ctx) } : {}),\n };\n }\n\n // One sheet per document for every card's segments: the kit's, then each card's.\n sheets.add(styles);\n\n return { name: definition.name, variants: definition.variants, setup, segment };\n}\n\nconst sheets = new Set<string>();\n\n/** Cards whose `onChange` data is remembered, per setup. */\nconst KEPT_MAX = 100;\n\n/** What a card was drawn from, as text to compare — `''` when it cannot be written (a cycle). */\nfunction fingerprint(raw: unknown): string {\n try {\n return JSON.stringify(raw) ?? '';\n } catch {\n return '';\n }\n}\n\n/** The renderer for `card` segments: it hands each one to the card it names. */\nfunction cardSegmentRenderer(config: AparteConfig): AparteSegmentRenderer<AparteCardSegment> {\n return {\n type: CARD_SEGMENT_TYPE,\n render: (segment) => {\n const entry = registries.get(config)?.get(segment.card)?.at(-1);\n if (entry) return entry.draw(segment);\n // A card this page did not set up: its sentence, not nothing.\n return el('p', { class: 'aparte-segment aparte-rich-card__fallback', attrs: { 'data-segment-id': segment.id }, text: segment.fallback ?? '' });\n },\n // A card segment sent again with new data (`updateSegment`) is drawn in place.\n update: (element, segment) => {\n const entry = registries.get(config)?.get(segment.card)?.at(-1);\n if (!entry) return;\n // Drawn as its fallback sentence before its card was set up: the card replaces it.\n if (!element.hasAttribute('data-card')) {\n element.replaceWith(entry.draw(segment));\n return;\n }\n const next = entry.draw(segment);\n if (drawnFrom.get(next) !== drawnFrom.get(element)) bumpTurn(element);\n const wasBusy = element.hasAttribute('data-busy') && queues.has(element);\n patch(element, next);\n if (wasBusy) busy(element, true);\n },\n relabel: (element) => relabel(element),\n getStyles: () => [...sheets].join('\\n'),\n };\n}\n","/**\n * Numbers, dates and times as the chat's language writes them.\n *\n * Every call reads the locale's `tag`, not the browser's: on a French page a card says\n * `12 %` and `mar.`, on a Japanese one `12%` and `火` — the same rule as the context\n * gauge and the bubble's clock. Nothing here needs a word of ours; `Intl` has them.\n */\nimport type { AparteConfig } from '@aparte/core';\nimport { intlTag } from './strings.js';\n\n/** A date from what a tool returns: an ISO string, an epoch (seconds or milliseconds) or a Date. */\nexport function toDate(value: unknown): Date | null {\n if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;\n if (typeof value === 'number' && Number.isFinite(value)) {\n // Below 10^12 it is seconds (Open-Meteo's `unixtime`, OpenWeather's `dt`).\n const d = new Date(value < 1e12 ? value * 1000 : value);\n return Number.isNaN(d.getTime()) ? null : d;\n }\n if (typeof value === 'string' && value.trim()) {\n // A day alone (`2026-10-31`) is that day where the reader is. `new Date()` reads it as\n // midnight UTC, which is the evening before anywhere west of Greenwich.\n const day = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value.trim());\n if (day) {\n const local = new Date(Number(day[1]), Number(day[2]) - 1, Number(day[3]));\n return local.getMonth() === Number(day[2]) - 1 ? local : null;\n }\n const d = new Date(value.trim());\n return Number.isNaN(d.getTime()) ? null : d;\n }\n return null;\n}\n\nexport function formatNumber(config: AparteConfig, value: number, options: Intl.NumberFormatOptions = {}): string {\n return new Intl.NumberFormat(intlTag(config), options).format(value);\n}\n\n/**\n * A price in its currency, as the language writes it: `49,00 €`, `€49.00`, `¥4,900`.\n * The currency is an ISO 4217 code (`EUR`); a symbol a tool gives (`€`, `$`) is read for\n * the usual ones. Without a currency, the number alone.\n */\nexport function formatPrice(config: AparteConfig, amount: number, currency?: string): string {\n const code = currencyCode(currency);\n const plain = () => formatNumber(config, amount, { minimumFractionDigits: Number.isInteger(amount) ? 0 : 2, maximumFractionDigits: 2 });\n // A currency `Intl` cannot name (`kr`, `zł`, `A$`) is still a currency: written as given.\n if (!code) return typeof currency === 'string' && currency.trim() ? `${plain()} ${currency.trim()}` : plain();\n try {\n return formatNumber(config, amount, { style: 'currency', currency: code });\n } catch {\n return `${formatNumber(config, amount, { maximumFractionDigits: 2 })} ${currency}`;\n }\n}\n\nconst SYMBOLS: Record<string, string> = { '€': 'EUR', $: 'USD', '£': 'GBP', '¥': 'JPY', '₩': 'KRW', '₽': 'RUB', '₹': 'INR', 'R$': 'BRL', CHF: 'CHF' };\n\n/** An ISO 4217 code from what a tool wrote (`eur`, `€`, `USD`), or `undefined`. */\nexport function currencyCode(value: unknown): string | undefined {\n if (typeof value !== 'string' || !value.trim()) return undefined;\n const v = value.trim();\n if (SYMBOLS[v]) return SYMBOLS[v];\n return /^[A-Za-z]{3}$/.test(v) ? v.toUpperCase() : undefined;\n}\n\n/**\n * The number in a price written as text, with its group and decimal separators. It may open\n * on its decimal separator — `.99`, `$.99` — or the digits after it would be read as 99.\n */\nconst AMOUNT = /(?:\\d|[.,]\\d)[\\d.,'\\s]*/;\n\n/** The dollars a shop writes with their country before the sign. */\nconst DOLLARS: Record<string, string> = { US: 'USD', CA: 'CAD', A: 'AUD', AU: 'AUD', NZ: 'NZD', HK: 'HKD', S: 'SGD', SG: 'SGD', MX: 'MXN', NT: 'TWD', R: 'BRL' };\n\nlet isoCodes: Set<string> | null | undefined;\n/** Whether `code` is a currency the runtime knows — `TTC`, or `ALL` in \"all included\", is a word. */\nfunction isCurrency(code: string): boolean {\n if (isoCodes === undefined) {\n try {\n isoCodes = new Set(Intl.supportedValuesOf('currency'));\n } catch {\n isoCodes = null;\n }\n }\n // A runtime without the list takes a code written in capitals, as ISO 4217 writes them.\n return isoCodes ? isoCodes.has(code) : /^[A-Z]{3}$/.test(code);\n}\n\n/**\n * The currency in what is left of a price once its number is out — `€ TTC`, `From $`, `US$`,\n * `GBP incl. VAT`: a country's dollar first (`US$` is not just any `$`), then a sign, then a\n * three-letter code the runtime knows, written in capitals or standing alone.\n */\nfunction currencyIn(text: string): string | undefined {\n const dollar = /(?:^|[^A-Za-z])([A-Z]{1,2})\\$/.exec(text);\n if (dollar && DOLLARS[dollar[1]!]) return DOLLARS[dollar[1]!];\n if (/(?:^|[^A-Za-z])CHF(?:$|[^A-Za-z])/.test(text)) return 'CHF';\n const sign = /[€£¥₩₽₹$]/.exec(text);\n if (sign) return currencyCode(sign[0]);\n const words = text.match(/[A-Za-z]+/g) ?? [];\n for (const w of words) {\n const code = w.toUpperCase();\n if (w.length === 3 && (w === code || words.length === 1) && isCurrency(code)) return code;\n }\n return undefined;\n}\n\n/**\n * A price a shop or a tool wrote as text — `$1,299.00`, `1.299,00 €`, `49,90`, `29,99 € TTC`,\n * `US$49.90`, `−€5` — read into its amount and currency. The separator that comes last is the\n * decimal one when both are there; a lone comma followed by one or two digits is a decimal\n * comma, otherwise a thousands separator; `1.299` is a German thousands dot. A minus before\n * the number, whatever sits between, makes it negative (an order's discount, a refund).\n * Shared by the product and order cards, which read prices the same way.\n */\nexport function readPriceText(text: string): { amount?: number; currency?: string } {\n // `\\s` takes in the no-break and narrow no-break spaces `Intl` groups digits with.\n const match = AMOUNT.exec(text);\n const currency = currencyIn(text.replace(AMOUNT, ' '));\n if (!match) return currency ? { currency } : {};\n let digits = match[0].replace(/[\\s']/g, '').replace(/[.,]+$/, '');\n const dot = digits.lastIndexOf('.');\n const comma = digits.lastIndexOf(',');\n if (dot >= 0 && comma >= 0) {\n const [decimal, group] = dot > comma ? ['.', ','] : [',', '.'];\n digits = digits.split(group).join('').replace(decimal, '.');\n } else if (comma >= 0) {\n digits = /^\\d*,\\d{1,2}$/.test(digits) ? digits.replace(',', '.') : digits.split(',').join('');\n } else if (dot >= 0 && (digits.indexOf('.') !== dot || /^[1-9]\\d{0,2}\\.\\d{3}$/.test(digits))) {\n digits = digits.split('.').join('');\n }\n const n = Number(digits);\n if (!Number.isFinite(n)) return currency ? { currency } : {};\n const amount = /[-−][^\\d]*$/.test(text.slice(0, match.index)) ? -n : n;\n return currency ? { amount, currency } : { amount };\n}\n\n/** `0.12` → `12 %` in French, `12%` in English. */\nexport function formatPercent(config: AparteConfig, ratio: number): string {\n return formatNumber(config, ratio, { style: 'percent', maximumFractionDigits: 0 });\n}\n\n/** A value with its unit, as `Intl` writes it: `14 km/h`, `14 km/h`, `9 mph`. */\nexport function formatUnit(config: AparteConfig, value: number, unit: string, digits = 0): string {\n try {\n return formatNumber(config, value, { style: 'unit', unit, unitDisplay: 'short', maximumFractionDigits: digits });\n } catch {\n // A unit `Intl` does not know: the number, then the unit as given.\n return `${formatNumber(config, value, { maximumFractionDigits: digits })} ${unit}`;\n }\n}\n\n/**\n * The day as a person says it: \"Today\", \"Tomorrow\", then the weekday (\"Thu\").\n * The first letter is raised, because `Intl` writes \"aujourd’hui\" for the middle of a sentence.\n */\nexport function formatDay(config: AparteConfig, date: Date, style: 'short' | 'long' = 'short', now: Date = new Date()): string {\n const tag = intlTag(config);\n const startOf = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\n const days = Math.round((startOf(date) - startOf(now)) / 86_400_000);\n let text: string;\n if (days === 0 || days === 1) {\n text = new Intl.RelativeTimeFormat(tag, { numeric: 'auto' }).format(days, 'day');\n } else {\n text = new Intl.DateTimeFormat(tag, { weekday: style }).format(date);\n }\n return text.charAt(0).toLocaleUpperCase(tag) + text.slice(1);\n}\n\n/**\n * The time, as the language writes it: `2 PM` where the clock has twelve hours, `14:00`\n * where it has twenty-four — never a bare `14`, which is what `{ hour: 'numeric' }`\n * gives in en-GB, Spanish, Italian, Portuguese and Russian.\n */\nexport function formatHour(config: AparteConfig, date: Date): string {\n const tag = intlTag(config);\n const twelve = /h1[12]/.test(new Intl.DateTimeFormat(tag, { hour: 'numeric' }).resolvedOptions().hourCycle ?? '');\n return twelve\n ? new Intl.DateTimeFormat(tag, { hour: 'numeric', minute: date.getMinutes() ? '2-digit' : undefined }).format(date)\n : new Intl.DateTimeFormat(tag, { hour: '2-digit', minute: '2-digit' }).format(date);\n}\n\n/** Weekday and time, for \"as of\": `Sat 14:05`. */\nexport function formatWhen(config: AparteConfig, date: Date): string {\n return new Intl.DateTimeFormat(intlTag(config), { weekday: 'short', hour: 'numeric', minute: '2-digit' }).format(date);\n}\n"],"names":["segment"],"mappings":";AAWO,SAAS,GACZ,KACA,QAAiH,CAAA,MAC9G,UACqB;AACxB,QAAM,OAAO,SAAS,cAAc,GAAG;AACvC,MAAI,MAAM,MAAO,MAAK,YAAY,MAAM;AACxC,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,MAAM,SAAS,CAAA,CAAE,GAAG;AAC3D,QAAI,UAAU,QAAQ,UAAU,UAAa,UAAU,MAAO;AAC9D,SAAK,aAAa,MAAM,UAAU,OAAO,KAAK,OAAO,KAAK,CAAC;AAAA,EAC/D;AACA,MAAI,MAAM,SAAS,OAAW,MAAK,cAAc,MAAM;AACvD,aAAW,SAAS,UAAU;AAC1B,QAAI,UAAU,QAAQ,UAAU,UAAa,UAAU,MAAO;AAC9D,SAAK,OAAO,KAAK;AAAA,EACrB;AACA,SAAO;AACX;AAGO,SAAS,MAAM,QAAgB,YAAY,2BAAwC;AACtF,QAAM,SAAS,SAAS,cAAc,MAAM;AAC5C,SAAO,YAAY;AACnB,SAAO,aAAa,eAAe,MAAM;AACzC,SAAO,YAAY;AACnB,SAAO;AACX;AAMO,SAAS,QAAQ,KAA6B;AACjD,MAAI,OAAO,QAAQ,YAAY,CAAC,IAAI,KAAA,EAAQ,QAAO;AACnD,MAAI;AACA,UAAM,MAAM,IAAI,IAAI,IAAI,KAAA,GAAQ,OAAO,aAAa,cAAc,uBAAuB,SAAS,IAAI;AACtG,WAAO,CAAC,SAAS,UAAU,WAAW,MAAM,EAAE,SAAS,IAAI,QAAQ,IAAI,IAAI,OAAO;AAAA,EACtF,QAAQ;AACJ,WAAO;AAAA,EACX;AACJ;AAOO,SAAS,OAAO,KAA6B;AAChD,MAAI,OAAO,QAAQ,YAAY,CAAC,sBAAsB,KAAK,GAAG,EAAG,QAAO;AACxE,QAAM,MAAM,QAAQ,GAAG;AACvB,SAAO,OAAO,YAAY,KAAK,GAAG,IAAI,MAAM;AAChD;AAYO,SAAS,IAAI,OAAoC;AACpD,MAAI,OAAO,UAAU,SAAU,QAAO,OAAO,SAAS,KAAK,IAAI,QAAQ;AACvE,MAAI,OAAO,UAAU,YAAY,MAAM,KAAA,MAAW,IAAI;AAClD,UAAM,IAAI,OAAO,KAAK;AACtB,WAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAAA,EACpC;AACA,SAAO;AACX;AAGO,SAAS,IAAI,OAAoC;AACpD,MAAI,OAAO,UAAU,SAAU,QAAO,MAAM,UAAU;AACtD,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,EAAG,QAAO,OAAO,KAAK;AAC5E,SAAO;AACX;ACpEO,SAAS,WAAW,QAA8B;AACrD,QAAM,MAAM,OAAO,UAAA,EAAY;AAC/B,SAAQ,OAAO,QAAQ,YAAY,MAAM,IAAI,MAAM,GAAG,EAAE,CAAC,EAAG,YAAA,IAAgB;AAChF;AAGO,SAAS,QAAQ,QAA0C;AAC9D,QAAM,MAAM,OAAO,UAAA,EAAY;AAC/B,MAAI,OAAO,QAAQ,YAAY,CAAC,IAAK,QAAO;AAI5C,aAAW,aAAa,CAAC,KAAK,IAAI,QAAQ,MAAM,GAAG,CAAC,GAAG;AACnD,QAAI;AACA,aAAO,KAAK,oBAAoB,SAAS,EAAE,CAAC;AAAA,IAChD,QAAQ;AAAA,IAER;AAAA,EACJ;AACA,SAAO;AACX;AAMO,SAAS,KAAK,QAAsB,KAAa,OAAiB,OAA+B,CAAA,GAAY;AAChH,QAAM,UAAU,OAAO,UAAA,EAAY,GAAG;AACtC,QAAM,OAAO,WAAW,MAAM;AAC9B,QAAM,OAAQ,OAAO,YAAY,YAAY,WAAY,MAAM,IAAI,KAAK,MAAM;AAC9E,SAAO,KAAK,QAAQ,cAAc,CAAC,KAAK,SAAiB,KAAK,IAAI,KAAK,GAAG;AAC9E;AAGO,MAAM,YAAY;AAAA,EACrB,kBAAkB;AAAA,IACd,IAAI;AAAA,IAAiB,IAAI;AAAA,IAAgB,IAAI;AAAA,IAAmB,IAAI;AAAA,IAAiB,IAAI;AAAA,IACzF,IAAI;AAAA,IAAW,IAAI;AAAA,IAAY,IAAI;AAAA,IAAgB,IAAI;AAAA,IAAc,IAAI;AAAA,EAAA;AAAA,EAE7E,cAAc;AAAA,IACV,IAAI;AAAA,IAA6B,IAAI;AAAA,IAA8B,IAAI;AAAA,IACvE,IAAI;AAAA,IAA2B,IAAI;AAAA,IAAoC,IAAI;AAAA,IAC3E,IAAI;AAAA,IAAc,IAAI;AAAA,IAA4B,IAAI;AAAA,IAAgC,IAAI;AAAA,EAAA;AAAA,EAE9F,cAAc;AAAA,IACV,IAAI;AAAA,IAAW,IAAI;AAAA,IAAe,IAAI;AAAA,IAAoB,IAAI;AAAA,IAAgB,IAAI;AAAA,IAClF,IAAI;AAAA,IAAc,IAAI;AAAA,IAAW,IAAI;AAAA,IAAiB,IAAI;AAAA,IAAgB,IAAI;AAAA,EAAA;AAAA,EAElF,cAAc;AAAA,IACV,IAAI;AAAA,IAAW,IAAI;AAAA,IAAc,IAAI;AAAA,IAAgB,IAAI;AAAA,IAAY,IAAI;AAAA,IACzE,IAAI;AAAA,IAAS,IAAI;AAAA,IAAU,IAAI;AAAA,IAAc,IAAI;AAAA,IAAY,IAAI;AAAA,EAAA;AAAA,EAErE,eAAe;AAAA,IACX,IAAI;AAAA,IAAY,IAAI;AAAA,IAAa,IAAI;AAAA,IAAU,IAAI;AAAA,IAAY,IAAI;AAAA,IACnE,IAAI;AAAA,IAAM,IAAI;AAAA,IAAM,IAAI;AAAA,IAAY,IAAI;AAAA,IAAS,IAAI;AAAA,EAAA;AAAA,EAEzD,WAAW;AAAA,IACP,IAAI;AAAA,IAAQ,IAAI;AAAA,IAAW,IAAI;AAAA,IAAU,IAAI;AAAA,IAAa,IAAI;AAAA,IAC9D,IAAI;AAAA,IAAM,IAAI;AAAA,IAAM,IAAI;AAAA,IAAW,IAAI;AAAA,IAAS,IAAI;AAAA,EAAA;AAAA,EAExD,YAAY;AAAA,IACR,IAAI;AAAA,IAAkB,IAAI;AAAA,IAAmB,IAAI;AAAA,IAAmB,IAAI;AAAA,IAAkB,IAAI;AAAA,IAC9F,IAAI;AAAA,IAAkB,IAAI;AAAA,IAAoB,IAAI;AAAA,IAAkB,IAAI;AAAA,IAAkB,IAAI;AAAA,EAAA;AAAA,EAElG,aAAa;AAAA,IACT,IAAI;AAAA,IAA8B,IAAI;AAAA,IAA0B,IAAI;AAAA,IACpE,IAAI;AAAA,IAAgC,IAAI;AAAA,IAA6B,IAAI;AAAA,IACzE,IAAI;AAAA,IAAuB,IAAI;AAAA,IAAgC,IAAI;AAAA,IAA2B,IAAI;AAAA,EAAA;AAAA,EAEtG,cAAc;AAAA,IACV,IAAI;AAAA,IAAmB,IAAI;AAAA,IAAgB,IAAI;AAAA,IAAuB,IAAI;AAAA,IAAmB,IAAI;AAAA,IACjG,IAAI;AAAA,IAAgB,IAAI;AAAA,IAAe,IAAI;AAAA,IAAsB,IAAI;AAAA,IAAoB,IAAI;AAAA,EAAA;AAErG;AC7FA,MAAA,YAAe;ACsCR,MAAM,oBAAoB;AAoKjC,MAAM,iCAAiB,QAAA;AAMhB,SAAS,gBAAgB,QAAsB,SAAgD;AAClG,SAAO,WAAW,IAAI,MAAM,GAAG,IAAI,QAAQ,IAAI,GAAG,GAAG,EAAE,GAAG,KAAK,OAAO,KAAK;AAC/E;AAGO,SAAS,WAAW,QAAgC;AACvD,SAAO,CAAC,GAAI,WAAW,IAAI,MAAM,GAAG,KAAA,KAAU,EAAG;AACrD;AACA,MAAM,+BAAe,QAAA;AAMrB,MAAM,SAAS;AAEf,SAAS,MAAM,QAAiB,SAAuB,MAAqB;AACxE,QAAM,OAAO,QAAA;AACb,MAAI,SAAS,OAAQ,QAAO,YAAY;AAAA,WAC/B,KAAM,QAAO,aAAa,MAAM,IAAI;AAAA,cACjC,cAAc;AAC9B;AAOO,SAAS,WAAW,QAAiB,SAA6B;AACrE,QAAM,QAAQ,SAAS,MAAM;AAC7B,QAAM,OAAO,SAAS,IAAI,MAAM,KAAK,CAAA;AACrC,OAAK,KAAK,EAAE,MAAM,QAAQ,SAAS;AACnC,WAAS,IAAI,QAAQ,IAAI;AACzB,SAAO,aAAa,mBAAmB,EAAE;AAC7C;AAGA,SAAS,QAAQ,MAAqB;AAClC,QAAM,MAAM,SAAS,IAAI,IAAI;AAC7B,MAAI,gBAAgB,KAAK,WAAW,MAAM,EAAE,SAAS,EAAE,IAAI;AAC3D,aAAW,QAAQ,KAAK,iBAAiB,mBAAmB,GAAG;AAC3D,eAAW,KAAK,SAAS,IAAI,IAAI,KAAK,CAAA,EAAI,OAAM,MAAM,EAAE,SAAS,EAAE,IAAI;AAAA,EAC3E;AACJ;AAEA,SAAS,YACL,QACA,SACA,QACA,MACA,UACc;AACd,QAAM,OAAO,CAAC,QAAiB,SAAuB,SAAkB;AACpE,UAAM,QAAQ,SAAS,IAAI;AAC3B,UAAM,OAAO,SAAS,IAAI,MAAM,KAAK,CAAA;AACrC,SAAK,KAAK,EAAE,MAAM,QAAA,CAAS;AAC3B,aAAS,IAAI,QAAQ,IAAI;AACzB,WAAO,aAAa,mBAAmB,EAAE;AAAA,EAC7C;AACA,SAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM,CAAC,QAAQ,KAAK,OAAO,SAAS,KAAK,QAAQ,MAAM,KAAK,QAAQ,KAAK,OAAO,IAAI,CAAC;AAAA,IACrF,QAAQ,CAAC,QAAQ,MAAM,cAAc,aAAa,MAAM,QAAQ,MAAM,SAAS;AAAA,IAC/E,QAAQ,CAAC,MAAM,UAAU,WAAW,MAAM,KAAK;AAAA,IAC/C,MAAM,aAAa;AAAA,EAAA;AAE3B;AAOA,SAAS,MAAM,SAAsB,MAAyB;AAC1D,QAAM,SAAS,OAAO,aAAa,cAAc,OAAO,SAAS;AACjE,MAAI,MAAqB;AACzB,MAAI,OAAwB;AAC5B,MAAI,kBAAkB,eAAe,QAAQ,SAAS,MAAM,KAAK,WAAW,SAAS;AACjF,UAAM,OAAO,aAAa,eAAe;AACzC,WAAO,CAAA;AACP,aAAS,OAAgB,QAAQ,SAAS,SAAS,OAAO,KAAK,eAAgB;AAC3E,WAAK,QAAQ,MAAM,UAAU,QAAQ,KAAK,KAAK,cAAe,UAAU,IAAI,CAAC;AAAA,IACjF;AAAA,EACJ;AACA,aAAW,QAAQ,QAAQ,kBAAA,EAAqB,KAAI,CAAC,KAAK,aAAa,IAAI,EAAG,SAAQ,gBAAgB,IAAI;AAC1G,aAAW,QAAQ,KAAK,oBAAqB,SAAQ,aAAa,MAAM,KAAK,aAAa,IAAI,CAAE;AAChG,UAAQ,gBAAgB,GAAG,KAAK,UAAU;AAC1C,QAAM,QAAQ,SAAS,IAAI,IAAI;AAC/B,MAAI,MAAO,UAAS,IAAI,SAAS,KAAK;AACtC,QAAM,OAAO,UAAU,IAAI,IAAI;AAC/B,MAAI,SAAS,OAAW,WAAU,OAAO,OAAO;AAAA,MAC3C,WAAU,IAAI,SAAS,IAAI;AAChC,QAAM,IAAI,MAAM,OAAO;AACvB,MAAI,QAAQ,QAAQ,MAAM;AACtB,QAAI,SAAyB,MAAM,QAAQ,cAAc,mBAAmB,UAAU,GAAG,CAAC,IAAI,IAAI;AAClG,QAAI,CAAC,UAAU,MAAM;AACjB,eAAS;AACT,iBAAW,KAAK,KAAM,UAAS,QAAQ,SAAS,CAAC,KAAK;AAAA,IAC1D;AACA,QAAI,kBAAkB,YAAa,QAAO,MAAM,EAAE,eAAe,MAAM;AAAA,EAC3E;AACJ;AAGA,MAAM,4BAAY,QAAA;AAGlB,MAAM,kCAAkB,QAAA;AASxB,MAAM,6BAAa,QAAA;AAGnB,MAAM,gCAAgB,QAAA;AAGtB,SAAS,SAAS,SAAwB;AACtC,cAAY,IAAI,UAAU,YAAY,IAAI,OAAO,KAAK,KAAK,CAAC;AAC5D,SAAO,OAAO,OAAO;AACzB;AAEA,SAAS,KAAK,SAAkB,IAAmB;AAC/C,UAAQ,gBAAgB,aAAa,EAAE;AACvC,MAAI,GAAI,SAAQ,aAAa,aAAa,MAAM;AAAA,MAC3C,SAAQ,gBAAgB,WAAW;AAC5C;AAGA,SAAS,aAAa,MAAc,QAAoB,MAAe,YAAY,IAA8B;AAC7G,MAAI,CAAC,UAAU,OAAO,OAAO,UAAU,YAAY,CAAC,OAAO,MAAM,KAAA,EAAQ,QAAO;AAChF,QAAM,MAAM,OAAO,QAAQ,SAAY,SAAY,QAAQ,OAAO,GAAG;AACrE,MAAI,OAAO,QAAQ,UAAa,CAAC,IAAK,QAAO;AAC7C,MAAI,CAAC,OAAO,OAAO,SAAS,UAAa,OAAO,OAAO,OAAW,QAAO;AACzE,QAAM,SAAS,GAAG,UAAU;AAAA,IACxB,OAAO,6BAA6B,OAAO,UAAU,0CAA0C,qBAAqB,4BAA4B,YAAY,IAAI,SAAS,KAAK,EAAE;AAAA,IAChL,OAAO,EAAE,MAAM,SAAA;AAAA,IACf,MAAM,OAAO;AAAA,EAAA,CAChB;AACD,SAAO,iBAAiB,SAAS,CAAC,UAAU;AAExC,UAAM,gBAAA;AACN,cAAU,MAAM,QAAQ,QAAQ,KAAK,IAAI;AAAA,EAC7C,CAAC;AACD,SAAO;AACX;AAEA,SAAS,UAAU,MAAc,QAAqB,QAAoB,KAAgC,MAAqB;AAC3H,QAAM,SAAgC,EAAE,MAAM,QAAQ,KAAA;AACtD,QAAM,UAAU,OAAO,cAAc,IAAI,YAAmC,sBAAsB;AAAA,IAC9F;AAAA,IAAQ,SAAS;AAAA,IAAM,UAAU;AAAA,IAAM,YAAY;AAAA,EAAA,CACtD,CAAC;AACF,MAAI,CAAC,QAAS;AACd,MAAI,KAAK;AAGL,QAAI,YAAY,KAAK,GAAG,UAAU,KAAK,KAAK,UAAU,qBAAqB;AAAA,QACtE,QAAO,SAAS,OAAO;AAC5B;AAAA,EACJ;AACA,MAAI,OAAO,SAAS,QAAW;AAI3B,UAAM,WAAY,OAAO,QAAQ,iCAAiC,GAAG,cAAc,iBAAiB,KAC7F,SAAS,cAAc,iBAAiB;AAC/C,QAAI,CAAC,UAAU;AACX,cAAQ,KAAK,sBAAsB,IAAI,2CAA2C,OAAO,IAAI,YAAY;AACzG;AAAA,IACJ;AAGA,QAAI,SAAS,aAAa,SAAS,YAAa;AAChD,UAAM,QAAQ,SAAS;AACvB,aAAS,SAAS,OAAO,IAAI;AAC7B,aAAS,OAAA;AAET,QAAI,MAAM,KAAA,EAAQ,UAAS,SAAS,KAAK;AAAA,EAC7C;AACJ;AAEA,SAAS,YAAY,SAAyC;AAC1D,MAAI,QAAQ,qBAAqB,OAAW,QAAO,QAAQ;AAC3D,QAAM,OAAO,QAAQ;AACrB,MAAI,OAAO,SAAS,SAAU,QAAO;AACrC,MAAI;AACA,WAAO,KAAK,MAAM,IAAI;AAAA,EAC1B,QAAQ;AACJ,WAAO;AAAA,EACX;AACJ;AAEA,SAAS,QAAQ,SAA2C;AACxD,UAAQ,QAAQ,QAAA;AAAA,IACZ,KAAK;AAAY,aAAO;AAAA,IACxB,KAAK;AAAW,aAAO;AAAA,IACvB,KAAK;AAAqB,aAAO;AAAA,IACjC,KAAK;AAAY,aAAO;AAAA,IACxB;AAAS,aAAO;AAAA,EAAA;AAExB;AAMO,SAAS,WAAgC,YAAkC;AAC9E,QAAM,SAAS,GAAG,SAAS;AAAA,EAAK,WAAW,MAAM;AACjD,QAAM,iBAAiB,WAAW,SAAS,CAAC;AAC5C,QAAM,QAAQ,IAAI,IAAY,WAAW,QAAQ;AACjD,QAAM,6BAAa,QAAA;AAEnB,WAAS,cAAc,SAAiC,MAAgB,OAAmB;AACvF,UAAM,SAAS,UAAU,OAAO,QAAQ,YAAY,aAAc,OAAO,QAAQ,QAAQ,IAAI,IAAI,SAAa,QAAQ;AACtH,WAAQ,UAAU,MAAM,IAAI,MAAM,IAAI,SAAS;AAAA,EACnD;AAEA,WAAS,KAAK,OAAkB,SAAY,IAAyB;AACjE,WAAO,GAAG,OAAO;AAAA,MACb,OAAO,sDAAsD,WAAW,IAAI;AAAA,MAC5E,OAAO;AAAA,QACH,mBAAmB;AAAA,QACnB,aAAa,WAAW;AAAA,QACxB,gBAAgB;AAAA,QAChB,cAAc;AAAA,QACd,MAAM;AAAA,QACN,aAAa,UAAU,YAAY,SAAS;AAAA,MAAA;AAAA,IAChD,CACH;AAAA,EACL;AAEA,WAAS,UAAU,SAAiC,MAA6B;AAC7E,UAAM,WAAW,QAAQ,UAAU,IAAI,KAAK,CAAA,GACvC,IAAI,CAAC,WAAW,aAAa,WAAW,MAAM,QAAQ,IAAI,CAAC,EAC3D,OAAO,CAAC,MAA8B,MAAM,IAAI,EAChD,MAAM,GAAG,CAAC;AACf,WAAO,QAAQ,SAAS,GAAG,OAAO,EAAE,OAAO,4BAAA,GAA+B,GAAG,OAAO,IAAI;AAAA,EAC5F;AAGA,WAAS,MAAM,QAAsB,OAAgD,SAA4B,SAAY,IAAY,SAA6B,QAAqB;AACvL,UAAM,OAAO,KAAK,OAAO,SAAS,EAAE;AACpC,UAAM,MAAM,YAAY,QAAQ,SAAS,QAAQ,WAAW,IAAI;AAChE,UAAM,MAAM,UAAU,YAAY,iBAAiB,UAAU,YAAY,iBAAiB;AAC1F,UAAM,QAAQ,GAAG,QAAQ,EAAE,OAAO,iCAAiC;AACnE,QAAI,KAAK,OAAO,MAAM,WAAW,MAAM,SAAS,GAAG,CAAC;AACpD,UAAM,SAAS,GAAG,QAAQ,EAAE,OAAO,iCAAiC;AACpE,QAAI,KAAK,QAAQ,KAAK,UAAU,GAAG,CAAC;AACpC,SAAK,OAAO,GAAG,OAAO,EAAE,OAAO,6BAA6B,MAAM,WAAW,IAAI,GAAG,OAAO,MAAM,CAAC;AAClG,QAAI,KAAK,MAAM,MAAM,WAAW,MAAM,SAAS,GAAG,GAAG,YAAY;AACjE,WAAO;AAAA,EACX;AAEA,WAAS,SAAS,SAAiC,QAAsBA,UAA6C;AAClH,UAAM,QAAQ,QAAQA,QAAO;AAC7B,UAAM,QAASA,SAAQ,UAAU,SAAS,CAAA;AAC1C,UAAM,YAAY,QAAQ,YAAY,WAAW;AACjD,QAAI,UAA6B;AACjC,QAAI;AACA,gBAAU,YAAY,KAAK,KAAK;AAAA,IACpC,QAAQ;AACJ,gBAAU;AAAA,IACd;AACA,QAAI,UAAU,WAAW;AACrB,YAAM,UAAU,cAAc,SAAS,IAAI;AAC3C,YAAM,OAAO,KAAK,OAAO,SAASA,SAAQ,EAAE;AAC5C,YAAM,MAAM,YAAY,QAAQ,SAAS,QAAQ,WAAW,IAAI;AAChE,WAAK,OAAO,GAAG,WAAW,SAAS,SAAS,GAAG,CAAC;AAChD,UAAI,KAAK,MAAM,MAAM,GAAG,WAAW,MAAM,SAAS,GAAG,CAAC,MAAM,KAAK,QAAQ,gBAAgB,UAAU,YAAY,CAAC,IAAI,YAAY;AAChI,aAAO;AAAA,IACX;AACA,QAAI,UAAU,QAAS,QAAO,MAAM,QAAQ,OAAO,SAAS,cAAc,SAAS,IAAI,GAAGA,SAAQ,EAAE;AACpG,QAAI,OAAiB;AACrB,QAAI,OAAO;AACX,QAAI;AACA,YAAM,MAAM,YAAYA,QAAO;AAC/B,aAAO,YAAY,GAAG;AACtB,YAAM,OAAO,OAAO,SAAS,QAAQA,SAAQ,EAAE,IAAI,IAAI;AACvD,UAAI,KAAM,QAAO,SAAS,SAAS,QAAQ,KAAK,MAAM,KAAK,SAASA,SAAQ,IAAI,QAAQ,IAAI;AAC5F,aAAO,WAAW,UAAU,QAAQ,MAAM,QAAQ,IAAI,KAAK,OAAOA,QAAO,IAAI,GAAG;AAAA,IACpF,SAAS,OAAO;AACZ,cAAQ,KAAK,sBAAsB,WAAW,IAAI,sBAAsB,KAAK;AAAA,IACjF;AACA,QAAI,CAAC,MAAM;AACP,UAAI,CAAC,OAAO,IAAI,OAAO,GAAG;AACtB,eAAO,IAAI,OAAO;AAClB,gBAAQ,KAAK,sBAAsB,WAAW,IAAI,gEAAgEA,SAAQ,UAAU,IAAI,KAAK;AAAA,MACjJ;AACA,aAAO,MAAM,QAAQ,eAAe,SAAS,cAAc,SAAS,IAAI,GAAGA,SAAQ,EAAE;AAAA,IACzF;AACA,WAAO,SAAS,SAAS,QAAQ,MAAM,cAAc,SAAS,IAAI,GAAGA,SAAQ,IAAI,QAAQ,IAAI;AAAA,EACjG;AAUA,QAAM,2BAAW,QAAA;AAEjB,WAAS,OAAO,SAAiC,KAAa,MAAmD;AAK7G,UAAM,QAAQ,KAAK,IAAI,OAAO,GAAG,IAAI,GAAG;AACxC,WAAO,SAAS,QAAQ,MAAM,SAAS,OAAO,QAAQ;AAAA,EAC1D;AAEA,WAAS,SAAS,SAAiC,KAAa,MAAc,MAAS,SAAkB;AAErG,QAAI,CAAC,KAAM;AACX,UAAM,QAAQ,KAAK,IAAI,OAAO,yBAAS,IAAA;AACvC,SAAK,IAAI,SAAS,KAAK;AACvB,UAAM,OAAO,GAAG;AAChB,UAAM,IAAI,KAAK,EAAE,MAAM,MAAM,SAAS;AAEtC,QAAI,MAAM,OAAO,SAAU,OAAM,OAAO,MAAM,KAAA,EAAO,KAAA,EAAO,KAAM;AAAA,EACtE;AAEA,WAAS,SAAS,SAAiC,QAAsB,MAAS,SAAY,IAAY,QAA4B,MAA2B;AAC7J,UAAM,OAAO,KAAK,SAAS,SAAS,EAAE;AACtC,cAAU,IAAI,MAAM,IAAI;AAExB,UAAM,WAAW,CAAC,MAAc,UAAmB,KAAK,OAAO,MAAM,IAAI,IAAI,KAAK,MAAM,SAAS,QAAQ,MAAM,SAAS,IAAI,QAAQ,MAAM,MAAM,KAAK;AACrJ,UAAM,MAAM,YAAY,QAAQ,SAAS,QAAQ,WAAW,MAAM,QAAQ,WAAW,WAAW,MAAS;AACzG,SAAK,OAAO,GAAG,WAAW,OAAO,MAAM,GAAG,CAAC;AAC3C,UAAM,UAAU,UAAU,SAAS,IAAI;AACvC,QAAI,QAAS,MAAK,OAAO,OAAO;AAChC,QAAI,KAAK,MAAM,MAAM,WAAW,MAAM,MAAM,GAAG,GAAG,YAAY;AAC9D,WAAO;AAAA,EACX;AAEA,iBAAe,OACX,MACA,SACA,QACA,MACA,SACA,IACA,QACA,MACA,MACA,OACa;AACb,UAAM,UAAU;AAChB,UAAM,UAAU,OAAO,IAAI,OAAO;AAClC,UAAM,SAAgC,EAAE,MAAM,WAAW,MAAM,MAAM,OAAO,MAAM,SAAS,QAAQ,KAAA;AACnG,UAAM,UAAU,QAAQ,cAAc,IAAI,YAAmC,sBAAsB;AAAA,MAC/F;AAAA,MAAQ,SAAS;AAAA,MAAM,UAAU;AAAA,MAAM,YAAY;AAAA,IAAA,CACtD,CAAC;AACF,QAAI,CAAC,WAAW,CAAC,QAAQ,SAAU;AAQnC,UAAM,QAAkB,WAAW,EAAE,SAAS,oBAAI,OAAO,SAAS,OAAO,MAAM,QAAA;AAC/E,WAAO,IAAI,SAAS,KAAK;AACzB,UAAM,QAAQ,OAAO,IAAI;AACzB,UAAM,QAAQ,IAAI,MAAM,KAAK;AAC7B,QAAI,MAAM,QAAS;AACnB,UAAM,UAAU;AAChB,UAAM,OAAO,YAAY,IAAI,OAAO,KAAK;AACzC,SAAK,SAAS,IAAI;AAClB,QAAI;AACA,aAAO,MAAM,QAAQ,OAAO,GAAG;AAC3B,cAAM,CAAC,UAAU,SAAS,IAAI,MAAM,QAAQ,QAAA,EAAU,KAAA,EAAO;AAC7D,cAAM,QAAQ,OAAO,QAAQ;AAC7B,YAAI;AACJ,YAAI;AACA,iBAAO,MAAM,QAAQ,SAAS,EAAE,MAAM,UAAU,OAAO,UAAA,GAAa,MAAM,IAAI;AAAA,QAClF,SAAS,OAAO;AACZ,kBAAQ,KAAK,sBAAsB,WAAW,IAAI,2BAA2B,KAAK;AAClF;AAAA,QACJ;AAEA,aAAK,YAAY,IAAI,OAAO,KAAK,OAAO,KAAM;AAC9C,YAAI,SAAS,UAAa,SAAS,KAAM;AACzC,cAAM,QAAQ,WAAW,UAAU,IAAI;AACvC,YAAI,CAAC,OAAO;AACR,kBAAQ,KAAK,sBAAsB,WAAW,IAAI,wEAAwE;AAC1H;AAAA,QACJ;AACA,cAAM,OAAO;AACb,cAAM,UAAU,cAAc,SAAS,OAAO,MAAM,OAAY;AAChE,iBAAS,SAAS,GAAG,MAAM,IAAI,EAAE,IAAI,MAAM,OAAO,MAAM,OAAY;AACpE,cAAM,SAAS,SAAS,SAAS,QAAQ,OAAO,MAAM,SAAc,IAAI,QAAQ,IAAI,CAAC;AACrF,YAAI,MAAM,QAAQ,OAAO,EAAG,MAAK,SAAS,IAAI;AAAA,MAClD;AAAA,IACJ,UAAA;AACI,YAAM,UAAU;AAChB,UAAI,OAAO,IAAI,OAAO,MAAM,MAAO,QAAO,OAAO,OAAO;AACxD,WAAK,YAAY,IAAI,OAAO,KAAK,OAAO,KAAM,MAAK,SAAS,KAAK;AAAA,IACrE;AAAA,EACJ;AAEA,WAAS,MAAM,UAAkC,IAAgB;AAC7D,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,WAAW,QAAQ,SAAS,SAAY,CAAA,IAAK,MAAM,QAAQ,QAAQ,IAAI,IAAI,QAAQ,OAAO,CAAC,QAAQ,IAAI;AAE7G,UAAM,eAAmC;AAAA,MACrC,QAAQ,CAACA,aAAY,SAAS,SAAS,QAAQA,QAAO;AAAA;AAAA,MAEtD,QAAQ,CAAC,SAASA,aAAY;AAC1B,cAAM,OAAO,SAAS,SAAS,QAAQA,QAAO;AAG9C,YAAI,UAAU,IAAI,IAAI,MAAM,UAAU,IAAI,OAAO,EAAG,UAAS,OAAO;AACpE,cAAM,UAAU,QAAQ,aAAa,WAAW,KAAK,OAAO,IAAI,OAAO;AACvE,cAAM,SAAS,IAAI;AACnB,YAAI,QAAS,MAAK,SAAS,IAAI;AAAA,MACnC;AAAA,MACA,SAAS,CAAC,YAAY,QAAQ,OAAO;AAAA,MACrC,WAAW,MAAM;AAAA,IAAA;AAKrB,UAAM,WAAW,SAAS,IAAI,CAAC,UAAU,OAAO,qBAAqB,OAAO,YAAY,CAAC;AAEzF,UAAM,WAAW,WAAW,IAAI,MAAM,yBAAS,IAAA;AAC/C,eAAW,IAAI,QAAQ,QAAQ;AAC/B,UAAM,QAAe;AAAA,MACjB,MAAM,CAACA,aAAY;AACf,cAAM,OAAO,YAAYA,SAAQ,IAAI;AACrC,cAAM,OAAO,OAAO,SAAS,WAAWA,SAAQ,EAAE,IAAI,IAAI;AAC1D,YAAI,KAAM,QAAO,SAAS,SAAS,QAAQ,KAAK,MAAM,KAAK,SAASA,SAAQ,IAAI,WAAW,IAAI;AAC/F,cAAM,OAAO,WAAW,UAAUA,SAAQ,IAAI;AAC9C,cAAM,UAAU,cAAc,SAAS,MAAMA,SAAQ,OAAO;AAC5D,YAAI,CAAC,KAAM,QAAO,MAAM,QAAQ,eAAe,MAAM,SAASA,SAAQ,IAAI,SAAS;AACnF,eAAO,SAAS,SAAS,QAAQ,MAAM,SAASA,SAAQ,IAAI,WAAW,IAAI;AAAA,MAC/E;AAAA,IAAA;AAEJ,UAAM,QAAQ,SAAS,IAAI,WAAW,IAAI,KAAK,CAAA;AAC/C,UAAM,KAAK,KAAK;AAChB,aAAS,IAAI,WAAW,MAAM,KAAK;AAKnC,UAAM,kBAAkB,wBAAwB,oBAAoB,MAAM,GAAG,MAAM;AAEnF,QAAI,UAAU;AACd,WAAO,MAAM;AACT,UAAI,QAAS;AACb,gBAAU;AACV,iBAAW,WAAW,SAAU,SAAA;AAChC,YAAM,MAAM,SAAS,IAAI,WAAW,IAAI;AACxC,YAAM,KAAK,KAAK,QAAQ,KAAK,KAAK;AAClC,UAAI,OAAO,MAAM,EAAG,KAAI,OAAO,IAAI,CAAC;AACpC,UAAI,OAAO,IAAI,WAAW,EAAG,UAAS,OAAO,WAAW,IAAI;AAC5D,sBAAA;AAAA,IACJ;AAAA,EACJ;AAMA,WAAS,QAAQ,KAAc,UAA+D,IAAuB;AACjH,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,OAAO,WAAW,UAAU,GAAG;AACrC,UAAM,MAAM,YAAY,QAAS,QAAQ,WAAW,gBAAsB,WAAW,WAAW,IAAI;AACpG,WAAO;AAAA,MACH,IAAI,QAAQ,MAAM,QAAQ,WAAW,IAAI,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,MACpF,MAAM;AAAA,MACN,MAAM,WAAW;AAAA,MACjB,MAAM;AAAA,MACN,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAA,IAAY,CAAA;AAAA,MACrD,GAAI,OAAO,EAAE,UAAU,WAAW,SAAS,MAAM,GAAG,MAAM,CAAA;AAAA,IAAC;AAAA,EAEnE;AAGA,SAAO,IAAI,MAAM;AAEjB,SAAO,EAAE,MAAM,WAAW,MAAM,UAAU,WAAW,UAAU,OAAO,QAAA;AAC1E;AAEA,MAAM,6BAAa,IAAA;AAGnB,MAAM,WAAW;AAGjB,SAAS,YAAY,KAAsB;AACvC,MAAI;AACA,WAAO,KAAK,UAAU,GAAG,KAAK;AAAA,EAClC,QAAQ;AACJ,WAAO;AAAA,EACX;AACJ;AAGA,SAAS,oBAAoB,QAAgE;AACzF,SAAO;AAAA,IACH,MAAM;AAAA,IACN,QAAQ,CAAC,YAAY;AACjB,YAAM,QAAQ,WAAW,IAAI,MAAM,GAAG,IAAI,QAAQ,IAAI,GAAG,GAAG,EAAE;AAC9D,UAAI,MAAO,QAAO,MAAM,KAAK,OAAO;AAEpC,aAAO,GAAG,KAAK,EAAE,OAAO,6CAA6C,OAAO,EAAE,mBAAmB,QAAQ,MAAM,MAAM,QAAQ,YAAY,IAAI;AAAA,IACjJ;AAAA;AAAA,IAEA,QAAQ,CAAC,SAAS,YAAY;AAC1B,YAAM,QAAQ,WAAW,IAAI,MAAM,GAAG,IAAI,QAAQ,IAAI,GAAG,GAAG,EAAE;AAC9D,UAAI,CAAC,MAAO;AAEZ,UAAI,CAAC,QAAQ,aAAa,WAAW,GAAG;AACpC,gBAAQ,YAAY,MAAM,KAAK,OAAO,CAAC;AACvC;AAAA,MACJ;AACA,YAAM,OAAO,MAAM,KAAK,OAAO;AAC/B,UAAI,UAAU,IAAI,IAAI,MAAM,UAAU,IAAI,OAAO,EAAG,UAAS,OAAO;AACpE,YAAM,UAAU,QAAQ,aAAa,WAAW,KAAK,OAAO,IAAI,OAAO;AACvE,YAAM,SAAS,IAAI;AACnB,UAAI,QAAS,MAAK,SAAS,IAAI;AAAA,IACnC;AAAA,IACA,SAAS,CAAC,YAAY,QAAQ,OAAO;AAAA,IACrC,WAAW,MAAM,CAAC,GAAG,MAAM,EAAE,KAAK,IAAI;AAAA,EAAA;AAE9C;AC5tBO,SAAS,OAAO,OAA6B;AAChD,MAAI,iBAAiB,KAAM,QAAO,OAAO,MAAM,MAAM,QAAA,CAAS,IAAI,OAAO;AACzE,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,GAAG;AAErD,UAAM,IAAI,IAAI,KAAK,QAAQ,OAAO,QAAQ,MAAO,KAAK;AACtD,WAAO,OAAO,MAAM,EAAE,QAAA,CAAS,IAAI,OAAO;AAAA,EAC9C;AACA,MAAI,OAAO,UAAU,YAAY,MAAM,QAAQ;AAG3C,UAAM,MAAM,4BAA4B,KAAK,MAAM,MAAM;AACzD,QAAI,KAAK;AACL,YAAM,QAAQ,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,IAAI,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC;AACzE,aAAO,MAAM,eAAe,OAAO,IAAI,CAAC,CAAC,IAAI,IAAI,QAAQ;AAAA,IAC7D;AACA,UAAM,IAAI,IAAI,KAAK,MAAM,MAAM;AAC/B,WAAO,OAAO,MAAM,EAAE,QAAA,CAAS,IAAI,OAAO;AAAA,EAC9C;AACA,SAAO;AACX;AAEO,SAAS,aAAa,QAAsB,OAAe,UAAoC,CAAA,GAAY;AAC9G,SAAO,IAAI,KAAK,aAAa,QAAQ,MAAM,GAAG,OAAO,EAAE,OAAO,KAAK;AACvE;AAOO,SAAS,YAAY,QAAsB,QAAgB,UAA2B;AACzF,QAAM,OAAO,aAAa,QAAQ;AAClC,QAAM,QAAQ,MAAM,aAAa,QAAQ,QAAQ,EAAE,uBAAuB,OAAO,UAAU,MAAM,IAAI,IAAI,GAAG,uBAAuB,GAAG;AAEtI,MAAI,CAAC,KAAM,QAAO,OAAO,aAAa,YAAY,SAAS,KAAA,IAAS,GAAG,OAAO,IAAI,SAAS,KAAA,CAAM,KAAK,MAAA;AACtG,MAAI;AACA,WAAO,aAAa,QAAQ,QAAQ,EAAE,OAAO,YAAY,UAAU,MAAM;AAAA,EAC7E,QAAQ;AACJ,WAAO,GAAG,aAAa,QAAQ,QAAQ,EAAE,uBAAuB,GAAG,CAAC,IAAI,QAAQ;AAAA,EACpF;AACJ;AAEA,MAAM,UAAkC,EAAE,KAAK,OAAO,GAAG,OAAO,KAAK,OAAO,KAAK,OAAO,KAAK,OAAO,KAAK,OAAO,KAAK,OAAO,MAAM,OAAO,KAAK,MAAA;AAGvI,SAAS,aAAa,OAAoC;AAC7D,MAAI,OAAO,UAAU,YAAY,CAAC,MAAM,KAAA,EAAQ,QAAO;AACvD,QAAM,IAAI,MAAM,KAAA;AAChB,MAAI,QAAQ,CAAC,EAAG,QAAO,QAAQ,CAAC;AAChC,SAAO,gBAAgB,KAAK,CAAC,IAAI,EAAE,gBAAgB;AACvD;AAMA,MAAM,SAAS;AAGf,MAAM,UAAkC,EAAE,IAAI,OAAO,IAAI,OAAO,GAAG,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,GAAG,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,GAAG,MAAA;AAEzJ,IAAI;AAEJ,SAAS,WAAW,MAAuB;AACvC,MAAI,aAAa,QAAW;AACxB,QAAI;AACA,iBAAW,IAAI,IAAI,KAAK,kBAAkB,UAAU,CAAC;AAAA,IACzD,QAAQ;AACJ,iBAAW;AAAA,IACf;AAAA,EACJ;AAEA,SAAO,WAAW,SAAS,IAAI,IAAI,IAAI,aAAa,KAAK,IAAI;AACjE;AAOA,SAAS,WAAW,MAAkC;AAClD,QAAM,SAAS,gCAAgC,KAAK,IAAI;AACxD,MAAI,UAAU,QAAQ,OAAO,CAAC,CAAE,EAAG,QAAO,QAAQ,OAAO,CAAC,CAAE;AAC5D,MAAI,oCAAoC,KAAK,IAAI,EAAG,QAAO;AAC3D,QAAM,OAAO,YAAY,KAAK,IAAI;AAClC,MAAI,KAAM,QAAO,aAAa,KAAK,CAAC,CAAC;AACrC,QAAM,QAAQ,KAAK,MAAM,YAAY,KAAK,CAAA;AAC1C,aAAW,KAAK,OAAO;AACnB,UAAM,OAAO,EAAE,YAAA;AACf,QAAI,EAAE,WAAW,MAAM,MAAM,QAAQ,MAAM,WAAW,MAAM,WAAW,IAAI,EAAG,QAAO;AAAA,EACzF;AACA,SAAO;AACX;AAUO,SAAS,cAAc,MAAsD;AAEhF,QAAM,QAAQ,OAAO,KAAK,IAAI;AAC9B,QAAM,WAAW,WAAW,KAAK,QAAQ,QAAQ,GAAG,CAAC;AACrD,MAAI,CAAC,MAAO,QAAO,WAAW,EAAE,SAAA,IAAa,CAAA;AAC7C,MAAI,SAAS,MAAM,CAAC,EAAE,QAAQ,UAAU,EAAE,EAAE,QAAQ,UAAU,EAAE;AAChE,QAAM,MAAM,OAAO,YAAY,GAAG;AAClC,QAAM,QAAQ,OAAO,YAAY,GAAG;AACpC,MAAI,OAAO,KAAK,SAAS,GAAG;AACxB,UAAM,CAAC,SAAS,KAAK,IAAI,MAAM,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;AAC7D,aAAS,OAAO,MAAM,KAAK,EAAE,KAAK,EAAE,EAAE,QAAQ,SAAS,GAAG;AAAA,EAC9D,WAAW,SAAS,GAAG;AACnB,aAAS,gBAAgB,KAAK,MAAM,IAAI,OAAO,QAAQ,KAAK,GAAG,IAAI,OAAO,MAAM,GAAG,EAAE,KAAK,EAAE;AAAA,EAChG,WAAW,OAAO,MAAM,OAAO,QAAQ,GAAG,MAAM,OAAO,wBAAwB,KAAK,MAAM,IAAI;AAC1F,aAAS,OAAO,MAAM,GAAG,EAAE,KAAK,EAAE;AAAA,EACtC;AACA,QAAM,IAAI,OAAO,MAAM;AACvB,MAAI,CAAC,OAAO,SAAS,CAAC,UAAU,WAAW,EAAE,SAAA,IAAa,CAAA;AAC1D,QAAM,SAAS,cAAc,KAAK,KAAK,MAAM,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI;AACrE,SAAO,WAAW,EAAE,QAAQ,SAAA,IAAa,EAAE,OAAA;AAC/C;AAGO,SAAS,cAAc,QAAsB,OAAuB;AACvE,SAAO,aAAa,QAAQ,OAAO,EAAE,OAAO,WAAW,uBAAuB,GAAG;AACrF;AAGO,SAAS,WAAW,QAAsB,OAAe,MAAc,SAAS,GAAW;AAC9F,MAAI;AACA,WAAO,aAAa,QAAQ,OAAO,EAAE,OAAO,QAAQ,MAAM,aAAa,SAAS,uBAAuB,OAAA,CAAQ;AAAA,EACnH,QAAQ;AAEJ,WAAO,GAAG,aAAa,QAAQ,OAAO,EAAE,uBAAuB,QAAQ,CAAC,IAAI,IAAI;AAAA,EACpF;AACJ;AAMO,SAAS,UAAU,QAAsB,MAAY,QAA0B,SAAS,MAAY,oBAAI,QAAgB;AAC3H,QAAM,MAAM,QAAQ,MAAM;AAC1B,QAAM,UAAU,CAAC,MAAY,IAAI,KAAK,EAAE,YAAA,GAAe,EAAE,YAAY,EAAE,QAAA,CAAS,EAAE,QAAA;AAClF,QAAM,OAAO,KAAK,OAAO,QAAQ,IAAI,IAAI,QAAQ,GAAG,KAAK,KAAU;AACnE,MAAI;AACJ,MAAI,SAAS,KAAK,SAAS,GAAG;AAC1B,WAAO,IAAI,KAAK,mBAAmB,KAAK,EAAE,SAAS,QAAQ,EAAE,OAAO,MAAM,KAAK;AAAA,EACnF,OAAO;AACH,WAAO,IAAI,KAAK,eAAe,KAAK,EAAE,SAAS,MAAA,CAAO,EAAE,OAAO,IAAI;AAAA,EACvE;AACA,SAAO,KAAK,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI,KAAK,MAAM,CAAC;AAC/D;AAOO,SAAS,WAAW,QAAsB,MAAoB;AACjE,QAAM,MAAM,QAAQ,MAAM;AAC1B,QAAM,SAAS,SAAS,KAAK,IAAI,KAAK,eAAe,KAAK,EAAE,MAAM,WAAW,EAAE,gBAAA,EAAkB,aAAa,EAAE;AAChH,SAAO,SACD,IAAI,KAAK,eAAe,KAAK,EAAE,MAAM,WAAW,QAAQ,KAAK,WAAA,IAAe,YAAY,OAAA,CAAW,EAAE,OAAO,IAAI,IAChH,IAAI,KAAK,eAAe,KAAK,EAAE,MAAM,WAAW,QAAQ,UAAA,CAAW,EAAE,OAAO,IAAI;AAC1F;AAGO,SAAS,WAAW,QAAsB,MAAoB;AACjE,SAAO,IAAI,KAAK,eAAe,QAAQ,MAAM,GAAG,EAAE,SAAS,SAAS,MAAM,WAAW,QAAQ,UAAA,CAAW,EAAE,OAAO,IAAI;AACzH;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* three sources, states, variants, language switch and actions.
|
|
13
13
|
*/
|
|
14
14
|
export { defineCard, CARD_SEGMENT_TYPE } from './kit/define.js';
|
|
15
|
+
export { setupCardFences, CARD_FENCE_PREFIX } from './kit/fence.js';
|
|
16
|
+
export type { CardFenceOptions } from './kit/fence.js';
|
|
15
17
|
export type { AparteCardSegment, CardAction, CardActionEventDetail, CardChangeEventDetail, CardContext, CardDefinition, CardSetupOptions, } from './kit/define.js';
|
|
16
18
|
export { el, glyph, safeUrl, webUrl, num, str } from './kit/dom.js';
|
|
17
19
|
export { formatNumber, formatPercent, formatPrice, currencyCode, formatUnit, formatDay, formatHour, formatWhen, toDate } from './kit/format.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAChE,YAAY,EACR,iBAAiB,EACjB,UAAU,EACV,qBAAqB,EACrB,qBAAqB,EACrB,WAAW,EACX,cAAc,EACd,gBAAgB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAChJ,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC9D,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC9D,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACxF,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACpE,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,YAAY,EACR,iBAAiB,EACjB,UAAU,EACV,qBAAqB,EACrB,qBAAqB,EACrB,WAAW,EACX,cAAc,EACd,gBAAgB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAChJ,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC9D,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC9D,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACxF,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,35 +1,120 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as cardsSetUp, d as drawCardSegment } from "./format-BFq79ydr.js";
|
|
2
|
+
import { C, a, b, e, f, g, h, i, j, k, l, m, n, o, p, s, q, t, w, r } from "./format-BFq79ydr.js";
|
|
3
|
+
import { aparteGlobalConfig, escapeAttr, resolveConfig } from "@aparte/core";
|
|
2
4
|
import { s as s2, a as a2 } from "./sparkline-C-cA9obz.js";
|
|
3
|
-
import { r } from "./rating-
|
|
4
|
-
import { c
|
|
5
|
-
import { s as s3, a as a3, t as t2 } from "./controls-
|
|
5
|
+
import { r as r2 } from "./rating-CHVajQ2b.js";
|
|
6
|
+
import { c } from "./carousel-DwgHvriV.js";
|
|
7
|
+
import { s as s3, a as a3, t as t2 } from "./controls-BYUm4aRV.js";
|
|
8
|
+
const CARD_FENCE_PREFIX = "card-";
|
|
9
|
+
const SHIPPED = ["weather", "items", "product", "place", "stats", "order", "stock", "plan", "score", "media", "link"];
|
|
10
|
+
const TAG = "aparte-card-fence";
|
|
11
|
+
const loaders = /* @__PURE__ */ new WeakMap();
|
|
12
|
+
const setupName = (card) => `setup${card.charAt(0).toUpperCase()}${card.slice(1)}Card`;
|
|
13
|
+
function fetchCard(config, card) {
|
|
14
|
+
const own = loaders.get(config);
|
|
15
|
+
const loader = own?.load[card];
|
|
16
|
+
if (!own || !loader) return Promise.resolve(false);
|
|
17
|
+
let pending = own.pending.get(card);
|
|
18
|
+
if (!pending) {
|
|
19
|
+
pending = loader().then((module) => {
|
|
20
|
+
const setup = module[setupName(card)];
|
|
21
|
+
if (typeof setup !== "function") return false;
|
|
22
|
+
setup({ config });
|
|
23
|
+
return true;
|
|
24
|
+
}, (error) => {
|
|
25
|
+
console.warn(`[aparte-cards] the ${card} card could not be loaded; its fence shows its source.`, error);
|
|
26
|
+
return false;
|
|
27
|
+
});
|
|
28
|
+
own.pending.set(card, pending);
|
|
29
|
+
}
|
|
30
|
+
return pending;
|
|
31
|
+
}
|
|
32
|
+
function idOf(card, source) {
|
|
33
|
+
let h2 = 0;
|
|
34
|
+
for (let i2 = 0; i2 < source.length; i2++) h2 = Math.imul(31, h2) + source.charCodeAt(i2) | 0;
|
|
35
|
+
return `fence-${card}-${(h2 >>> 0).toString(36)}`;
|
|
36
|
+
}
|
|
37
|
+
async function drawFence(el) {
|
|
38
|
+
const card = el.getAttribute("data-card") ?? "";
|
|
39
|
+
const source = el.getAttribute("data-source") ?? "";
|
|
40
|
+
const config = resolveConfig(el);
|
|
41
|
+
const showSource = () => {
|
|
42
|
+
const code = document.createElement("code");
|
|
43
|
+
code.className = "aparte-code-error";
|
|
44
|
+
code.textContent = source;
|
|
45
|
+
el.replaceChildren(code);
|
|
46
|
+
};
|
|
47
|
+
let data;
|
|
48
|
+
try {
|
|
49
|
+
data = JSON.parse(source);
|
|
50
|
+
} catch {
|
|
51
|
+
showSource();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const segment = { id: idOf(card, source), type: "card", card, data };
|
|
55
|
+
let drawn = drawCardSegment(config, segment);
|
|
56
|
+
if (!drawn && await fetchCard(config, card) && el.isConnected) drawn = drawCardSegment(config, segment);
|
|
57
|
+
if (drawn) el.replaceChildren(drawn);
|
|
58
|
+
else showSource();
|
|
59
|
+
}
|
|
60
|
+
function defineElement() {
|
|
61
|
+
if (typeof customElements === "undefined" || typeof HTMLElement === "undefined" || customElements.get(TAG)) return;
|
|
62
|
+
customElements.define(TAG, class extends HTMLElement {
|
|
63
|
+
connectedCallback() {
|
|
64
|
+
if (this.hasAttribute("data-drawn")) return;
|
|
65
|
+
this.setAttribute("data-drawn", "");
|
|
66
|
+
void drawFence(this);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function setupCardFences(options = {}) {
|
|
71
|
+
const config = options.config ?? aparteGlobalConfig;
|
|
72
|
+
if (options.load) loaders.set(config, { load: options.load, pending: /* @__PURE__ */ new Map() });
|
|
73
|
+
defineElement();
|
|
74
|
+
const names = /* @__PURE__ */ new Set([...SHIPPED, ...cardsSetUp(config), ...Object.keys(options.load ?? {})]);
|
|
75
|
+
const renderer = {
|
|
76
|
+
languages: [...names].map((name) => `${CARD_FENCE_PREFIX}${name}`),
|
|
77
|
+
render: ({ language, source, open }) => {
|
|
78
|
+
if (open) return '<span class="aparte-skeleton aparte-skeleton--rect aparte-rich-card__fence-wait" aria-hidden="true"></span>';
|
|
79
|
+
const card = language.slice(CARD_FENCE_PREFIX.length);
|
|
80
|
+
return `<${TAG} data-card="${escapeAttr(card)}" data-source="${escapeAttr(source)}"></${TAG}>`;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const stop = config.registerCodeLanguageRenderer(renderer);
|
|
84
|
+
return () => {
|
|
85
|
+
stop();
|
|
86
|
+
loaders.delete(config);
|
|
87
|
+
};
|
|
88
|
+
}
|
|
6
89
|
export {
|
|
90
|
+
CARD_FENCE_PREFIX,
|
|
7
91
|
C as CARD_SEGMENT_TYPE,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
92
|
+
c as carousel,
|
|
93
|
+
a as currencyCode,
|
|
94
|
+
b as defineCard,
|
|
11
95
|
e as el,
|
|
12
96
|
f as formatDay,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
97
|
+
g as formatHour,
|
|
98
|
+
h as formatNumber,
|
|
99
|
+
i as formatPercent,
|
|
100
|
+
j as formatPrice,
|
|
101
|
+
k as formatUnit,
|
|
102
|
+
l as formatWhen,
|
|
103
|
+
m as glyph,
|
|
104
|
+
n as intlTag,
|
|
105
|
+
o as languageOf,
|
|
106
|
+
p as num,
|
|
107
|
+
r2 as rating,
|
|
24
108
|
s as safeUrl,
|
|
25
109
|
s3 as segmented,
|
|
110
|
+
setupCardFences,
|
|
26
111
|
a3 as slider,
|
|
27
112
|
s2 as sparkline,
|
|
28
113
|
a2 as sparklinePath,
|
|
29
|
-
|
|
114
|
+
q as str,
|
|
30
115
|
t as toDate,
|
|
31
116
|
t2 as toggle,
|
|
32
117
|
w as webUrl,
|
|
33
|
-
|
|
118
|
+
r as word
|
|
34
119
|
};
|
|
35
120
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/kit/fence.ts"],"sourcesContent":["/**\n * Cards written as text: a fenced block whose language names the card and whose body is its\n * fields, the way ```echarts holds a chart's option —\n *\n * ```card-weather\n * { \"location\": \"Lille\", \"temperature\": 11, \"condition\": \"rain\" }\n * ```\n *\n * For whatever produces text and no tool calls the chat can see: a backend that runs its tools\n * itself and streams only its answer, a workflow engine, a model with no tools. A client\n * without this plugin shows the block as code, which reads; one with it draws the card.\n *\n * A code-language renderer answers with markup, and a card is live DOM (its buttons, its\n * controls, its language switch), so the markup is an element that draws the card when it\n * reaches the page, through the card's own setup. A card that is not set up yet is fetched\n * by `load`, the first time its type appears.\n */\nimport { aparteGlobalConfig, escapeAttr, resolveConfig, type AparteConfig } from '@aparte/core';\nimport { cardsSetUp, drawCardSegment } from './define.js';\n\n/** The language prefix: ```card-weather draws the weather card. */\nexport const CARD_FENCE_PREFIX = 'card-';\n\n/** The cards this package ships, so their fences are known before any of them is set up. */\nconst SHIPPED = ['weather', 'items', 'product', 'place', 'stats', 'order', 'stock', 'plan', 'score', 'media', 'link'];\n\nconst TAG = 'aparte-card-fence';\n\nexport interface CardFenceOptions {\n /** The config to register on (the global one by default). */\n config?: AparteConfig;\n /**\n * How to fetch a card the page has not set up, by its name: called the first time a\n * fence names it, and its `setup…Card` export run on this config. Without an entry for\n * a name, a fence that names it shows its source.\n *\n * @example\n * setupCardFences({ load: { weather: () => import('@aparte/plugin-cards/weather') } });\n */\n load?: Record<string, () => Promise<Record<string, unknown>>>;\n}\n\n/** Each config's loaders, and what each load has become. */\nconst loaders = new WeakMap<AparteConfig, { load: NonNullable<CardFenceOptions['load']>; pending: Map<string, Promise<boolean>> }>();\n\n/** `weather` → `setupWeatherCard`, the setup each card's entry exports. */\nconst setupName = (card: string) => `setup${card.charAt(0).toUpperCase()}${card.slice(1)}Card`;\n\nfunction fetchCard(config: AparteConfig, card: string): Promise<boolean> {\n const own = loaders.get(config);\n const loader = own?.load[card];\n if (!own || !loader) return Promise.resolve(false);\n let pending = own.pending.get(card);\n if (!pending) {\n pending = loader().then((module) => {\n const setup = module[setupName(card)];\n if (typeof setup !== 'function') return false;\n (setup as (options: { config: AparteConfig }) => unknown)({ config });\n return true;\n }, (error: unknown) => {\n console.warn(`[aparte-cards] the ${card} card could not be loaded; its fence shows its source.`, error);\n return false;\n });\n own.pending.set(card, pending);\n }\n return pending;\n}\n\n/** A short, stable id for a fence's card, from what it holds: the same block, the same card. */\nfunction idOf(card: string, source: string): string {\n let h = 0;\n for (let i = 0; i < source.length; i++) h = (Math.imul(31, h) + source.charCodeAt(i)) | 0;\n return `fence-${card}-${(h >>> 0).toString(36)}`;\n}\n\n/** The fence drawn as its card, or its source when it cannot be. */\nasync function drawFence(el: HTMLElement): Promise<void> {\n const card = el.getAttribute('data-card') ?? '';\n const source = el.getAttribute('data-source') ?? '';\n const config = resolveConfig(el);\n const showSource = () => {\n const code = document.createElement('code');\n code.className = 'aparte-code-error';\n code.textContent = source;\n el.replaceChildren(code);\n };\n let data: unknown;\n try {\n data = JSON.parse(source);\n } catch {\n showSource();\n return;\n }\n const segment = { id: idOf(card, source), type: 'card' as const, card, data };\n let drawn = drawCardSegment(config, segment);\n if (!drawn && await fetchCard(config, card) && el.isConnected) drawn = drawCardSegment(config, segment);\n if (drawn) el.replaceChildren(drawn);\n else showSource();\n}\n\nfunction defineElement(): void {\n if (typeof customElements === 'undefined' || typeof HTMLElement === 'undefined' || customElements.get(TAG)) return;\n customElements.define(TAG, class extends HTMLElement {\n connectedCallback(): void {\n // Drawn once: a fence moved inside the page keeps the card it already holds.\n if (this.hasAttribute('data-drawn')) return;\n this.setAttribute('data-drawn', '');\n void drawFence(this);\n }\n });\n}\n\n/**\n * Draw the ```card-<name> fences in replies as their cards. Returns the function that stops\n * it. The cards are the ones set up on the config, and those `load` can fetch.\n */\nexport function setupCardFences(options: CardFenceOptions = {}): () => void {\n const config = options.config ?? aparteGlobalConfig;\n if (options.load) loaders.set(config, { load: options.load, pending: new Map() });\n defineElement();\n const names = new Set([...SHIPPED, ...cardsSetUp(config), ...Object.keys(options.load ?? {})]);\n const renderer = {\n languages: [...names].map((name) => `${CARD_FENCE_PREFIX}${name}`),\n render: ({ language, source, open }: { language: string; source: string; open: boolean }): string => {\n // A card arrives whole: until the fence closes, a quiet box where it will be.\n if (open) return '<span class=\"aparte-skeleton aparte-skeleton--rect aparte-rich-card__fence-wait\" aria-hidden=\"true\"></span>';\n const card = language.slice(CARD_FENCE_PREFIX.length);\n return `<${TAG} data-card=\"${escapeAttr(card)}\" data-source=\"${escapeAttr(source)}\"></${TAG}>`;\n },\n };\n const stop = config.registerCodeLanguageRenderer(renderer);\n return () => {\n stop();\n loaders.delete(config);\n };\n}\n"],"names":["h","i"],"mappings":"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"}
|
package/dist/items.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as carousel } from "./carousel-
|
|
2
|
-
import {
|
|
1
|
+
import { c as carousel } from "./carousel-DwgHvriV.js";
|
|
2
|
+
import { b as defineCard, q as str, n as intlTag, o as languageOf, r as word, e as el, s as safeUrl, h as formatNumber, w as webUrl, m as glyph } from "./format-BFq79ydr.js";
|
|
3
3
|
const ITEMS_ICON = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><rect x="3" y="6" width="12" height="14" rx="2.2"/><path d="M18 7.5v10.3a2.2 2.2 0 0 1-1.2 2" opacity="0.7"/><path d="M21 9v7.6" opacity="0.45"/><path d="M6 15.5l2.3-2.6a1 1 0 0 1 1.5 0l2.2 2.6"/><circle cx="11.2" cy="10.2" r="1.2"/></svg>`;
|
|
4
4
|
const IMAGE_ICON = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><rect x="3" y="4.5" width="18" height="15" rx="2.5"/><circle cx="8.6" cy="9.6" r="1.6"/><path d="M3.5 17.2l4.9-4.6a1.4 1.4 0 0 1 1.9 0l3.4 3.2"/><path d="M12.4 14.6l2.4-2.2a1.4 1.4 0 0 1 1.9 0l3.8 3.6"/></svg>`;
|
|
5
5
|
const itemsStyles = `/* =========================================
|
package/dist/kit/define.d.ts
CHANGED
|
@@ -170,6 +170,13 @@ export interface CardSetupOptions<D, V extends string = string> {
|
|
|
170
170
|
/** The config to register on (the global one by default). */
|
|
171
171
|
config?: AparteConfig;
|
|
172
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Draw a `card` segment with the card set up under `card` on `config`, or `null` when none
|
|
175
|
+
* is. Internal to the kit (the fences draw through it); not exported from the package.
|
|
176
|
+
*/
|
|
177
|
+
export declare function drawCardSegment(config: AparteConfig, segment: AparteCardSegment): HTMLElement | null;
|
|
178
|
+
/** The names of the cards set up on `config`. Internal to the kit. */
|
|
179
|
+
export declare function cardsSetUp(config: AparteConfig): string[];
|
|
173
180
|
/**
|
|
174
181
|
* A glyph from core's icon provider, written again on a relabel — the provider can change
|
|
175
182
|
* after the card is drawn (`setIconProvider`), and core's relabel contract re-reads it. Only
|
package/dist/kit/define.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/kit/define.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAIH,KAAK,YAAY,EACjB,KAAK,iBAAiB,EAEtB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EAEzB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG9D,0CAA0C;AAC1C,eAAO,MAAM,iBAAiB,SAAS,CAAC;AAExC;;;;GAIG;AACH,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,OAAO,QAAQ,cAAc,CAAC;IAC1B,UAAU,kBAAkB;QACxB,IAAI,EAAE,iBAAiB,CAAC;KAC3B;CACJ;AAED,8FAA8F;AAC9F,MAAM,WAAW,UAAU;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,kGAAkG;IAClG,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,+DAA+D;IAC/D,IAAI,EAAE,OAAO,CAAC;CACjB;AAKD,UAAU,YAAY;IAClB,oBAAoB,EAAE,WAAW,CAAC,qBAAqB,CAAC,CAAC;IACzD,oBAAoB,EAAE,WAAW,CAAC,qBAAqB,CAAC,CAAC;CAC5D;AACD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,mBAAoB,SAAQ,YAAY;KAAG;IACrD,UAAU,gBAAiB,SAAQ,YAAY;KAAG;IAClD,UAAU,cAAe,SAAQ,YAAY;KAAG;CACnD;AAED,kDAAkD;AAClD,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAClD,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,CAAC,CAAC;IACX,gCAAgC;IAChC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,oEAAoE;IACpE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACrF,qFAAqF;IACrF,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9D;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAAC;IACzF;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3C,4GAA4G;IAC5G,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CAC1B;AAED,mEAAmE;AACnE,MAAM,WAAW,cAAc,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM;IACxD,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC;IACvB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,wFAAwF;IACxF,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC;IAClC,gDAAgD;IAChD,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC;IAC7C,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC;IAClE,+EAA+E;IAC/E,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;IAC5D,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;IAC/C,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,OAAO,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CAC/D;AAED,kCAAkC;AAClC,MAAM,WAAW,gBAAgB,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM;IAC1D,kGAAkG;IAClG,IAAI,CAAC,EAAE,iBAAiB,GAAG,iBAAiB,EAAE,CAAC;IAC/C;;;;OAIG;IAGH,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,qBAAqB,KAAK,OAAO,CAAC;IAC/F,mGAAmG;IACnG,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACjE,uGAAuG;IACvG,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,UAAU,EAAE,CAAC;IACpC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,EAAE,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IAC1E,6DAA6D;IAC7D,MAAM,CAAC,EAAE,YAAY,CAAC;CACzB;
|
|
1
|
+
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/kit/define.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cards written as text: a fenced block whose language names the card and whose body is its
|
|
3
|
+
* fields, the way ```echarts holds a chart's option —
|
|
4
|
+
*
|
|
5
|
+
* ```card-weather
|
|
6
|
+
* { "location": "Lille", "temperature": 11, "condition": "rain" }
|
|
7
|
+
* ```
|
|
8
|
+
*
|
|
9
|
+
* For whatever produces text and no tool calls the chat can see: a backend that runs its tools
|
|
10
|
+
* itself and streams only its answer, a workflow engine, a model with no tools. A client
|
|
11
|
+
* without this plugin shows the block as code, which reads; one with it draws the card.
|
|
12
|
+
*
|
|
13
|
+
* A code-language renderer answers with markup, and a card is live DOM (its buttons, its
|
|
14
|
+
* controls, its language switch), so the markup is an element that draws the card when it
|
|
15
|
+
* reaches the page, through the card's own setup. A card that is not set up yet is fetched
|
|
16
|
+
* by `load`, the first time its type appears.
|
|
17
|
+
*/
|
|
18
|
+
import { type AparteConfig } from '@aparte/core';
|
|
19
|
+
/** The language prefix: ```card-weather draws the weather card. */
|
|
20
|
+
export declare const CARD_FENCE_PREFIX = "card-";
|
|
21
|
+
export interface CardFenceOptions {
|
|
22
|
+
/** The config to register on (the global one by default). */
|
|
23
|
+
config?: AparteConfig;
|
|
24
|
+
/**
|
|
25
|
+
* How to fetch a card the page has not set up, by its name: called the first time a
|
|
26
|
+
* fence names it, and its `setup…Card` export run on this config. Without an entry for
|
|
27
|
+
* a name, a fence that names it shows its source.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* setupCardFences({ load: { weather: () => import('@aparte/plugin-cards/weather') } });
|
|
31
|
+
*/
|
|
32
|
+
load?: Record<string, () => Promise<Record<string, unknown>>>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Draw the ```card-<name> fences in replies as their cards. Returns the function that stops
|
|
36
|
+
* it. The cards are the ones set up on the config, and those `load` can fetch.
|
|
37
|
+
*/
|
|
38
|
+
export declare function setupCardFences(options?: CardFenceOptions): () => void;
|
|
39
|
+
//# sourceMappingURL=fence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fence.d.ts","sourceRoot":"","sources":["../../src/kit/fence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAiD,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAGhG,mEAAmE;AACnE,eAAO,MAAM,iBAAiB,UAAU,CAAC;AAOzC,MAAM,WAAW,gBAAgB;IAC7B,6DAA6D;IAC7D,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;CACjE;AAwED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,gBAAqB,GAAG,MAAM,IAAI,CAmB1E"}
|
package/dist/link.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as defineCard, q as str, r as word, e as el, h as formatNumber, m as glyph, w as webUrl, t as toDate, p as num, n as intlTag } from "./format-BFq79ydr.js";
|
|
2
2
|
const svg = (body) => `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">${body}</svg>`;
|
|
3
3
|
const CHAIN = svg('<path d="M10 14a4.2 4.2 0 0 0 6 0l3-3a4.2 4.2 0 0 0-6-6l-1 1"/><path d="M14 10a4.2 4.2 0 0 0-6 0l-3 3a4.2 4.2 0 0 0 6 6l1-1"/>');
|
|
4
4
|
const PLAY = '<svg viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M8.5 5.6v12.8a1 1 0 0 0 1.5.86l10.2-6.4a1 1 0 0 0 0-1.72L10 4.74a1 1 0 0 0-1.5.86z"/></svg>';
|
package/dist/media.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as carousel } from "./carousel-
|
|
2
|
-
import {
|
|
1
|
+
import { c as carousel } from "./carousel-DwgHvriV.js";
|
|
2
|
+
import { b as defineCard, q as str, r as word, e as el, h as formatNumber, m as glyph, k as formatUnit, s as safeUrl, w as webUrl, p as num, K as KIT_WORDS } from "./format-BFq79ydr.js";
|
|
3
3
|
const svg = (body) => `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">${body}</svg>`;
|
|
4
4
|
const IMAGE = svg('<rect x="3.5" y="4.5" width="17" height="15" rx="2.5"/><circle cx="9" cy="9.5" r="1.6"/><path d="m4 17.5 4.6-4.6a1.4 1.4 0 0 1 2 0l3.4 3.4 1.6-1.6a1.4 1.4 0 0 1 2 0l2.9 2.9"/>');
|
|
5
5
|
const FILM = svg('<rect x="3.5" y="5" width="17" height="14" rx="2.5"/><path d="M7.5 5v14M16.5 5v14M3.5 9.5h4M3.5 14.5h4M16.5 9.5h4M16.5 14.5h4"/>');
|
package/dist/order.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as defineCard, q as str, n as intlTag, e as el, a as currencyCode, w as webUrl, h as formatNumber, r as word, j as formatPrice, m as glyph, p as num, t as toDate, u as readPriceText } from "./format-BFq79ydr.js";
|
|
2
2
|
const svg = (body) => `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">${body}</svg>`;
|
|
3
3
|
const BAG = svg('<path d="M5.5 8h13l-1 11.2a1.8 1.8 0 0 1-1.8 1.6H8.3a1.8 1.8 0 0 1-1.8-1.6z"/><path d="M9 10.5V6.8a3 3 0 0 1 6 0v3.7"/>');
|
|
4
4
|
const CALENDAR = svg('<rect x="3.5" y="5" width="17" height="15.5" rx="2.2"/><path d="M3.5 9.8h17M8 3v4M16 3v4"/><path d="M7.5 13.6h2M11 13.6h2M14.5 13.6h2M7.5 16.8h2M11 16.8h2"/>');
|
package/dist/place.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { c as carousel } from "./carousel-
|
|
2
|
-
import {
|
|
3
|
-
import { r as rating } from "./rating-
|
|
1
|
+
import { c as carousel } from "./carousel-DwgHvriV.js";
|
|
2
|
+
import { b as defineCard, q as str, h as formatNumber, r as word, e as el, p as num, m as glyph, s as safeUrl, k as formatUnit, n as intlTag } from "./format-BFq79ydr.js";
|
|
3
|
+
import { r as rating } from "./rating-CHVajQ2b.js";
|
|
4
4
|
const svg = (body) => `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">${body}</svg>`;
|
|
5
5
|
const PIN = svg('<path d="M12 21s-6.5-5.6-6.5-11a6.5 6.5 0 0 1 13 0c0 5.4-6.5 11-6.5 11z"/><circle cx="12" cy="10" r="2.4"/>');
|
|
6
6
|
const PHONE = svg('<path d="M5.2 4h3l1.6 4-2 1.3a10.5 10.5 0 0 0 5 5l1.3-2 4 1.6v3a2 2 0 0 1-2.1 2A15.2 15.2 0 0 1 3.2 6.1 2 2 0 0 1 5.2 4z"/>');
|
package/dist/plan.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as defineCard, q as str, e as el, t as toDate, r as word, h as formatNumber, m as glyph, i as formatPercent, p as num, n as intlTag } from "./format-BFq79ydr.js";
|
|
2
2
|
const svg = (body, className) => `<svg${className ? ` class="${className}"` : ""} viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">${body}</svg>`;
|
|
3
3
|
const PENDING = svg('<circle cx="12" cy="12" r="8"/>');
|
|
4
4
|
const RUNNING = svg('<circle cx="12" cy="12" r="8" opacity="0.4"/><path d="M12 4a8 8 0 0 1 8 8"/>', "aparte-plan__spinner");
|
package/dist/product.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { c as carousel } from "./carousel-
|
|
3
|
-
import { r as rating } from "./rating-
|
|
1
|
+
import { b as defineCard, q as str, h as formatNumber, r as word, e as el, m as glyph, j as formatPrice, a as currencyCode, w as webUrl, u as readPriceText, p as num, i as formatPercent } from "./format-BFq79ydr.js";
|
|
2
|
+
import { c as carousel } from "./carousel-DwgHvriV.js";
|
|
3
|
+
import { r as rating } from "./rating-CHVajQ2b.js";
|
|
4
4
|
const svg = (body) => `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">${body}</svg>`;
|
|
5
5
|
const BAG = svg('<path d="M5.5 8h13l-1 11.2a1.8 1.8 0 0 1-1.8 1.6H8.3a1.8 1.8 0 0 1-1.8-1.6z"/><path d="M9 10.5V6.8a3 3 0 0 1 6 0v3.7"/>');
|
|
6
6
|
const TRUCK = svg('<path d="M2.8 6.5h10.4v9.3H2.8z"/><path d="M13.2 9.5h4.1l3 3.2v3.1h-7.1"/><circle cx="7" cy="17.3" r="1.7"/><circle cx="17" cy="17.3" r="1.7"/>');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { e as el,
|
|
1
|
+
import { e as el, m as glyph, h as formatNumber, r as word, K as KIT_WORDS } from "./format-BFq79ydr.js";
|
|
2
2
|
const STAR = "M12 2.6l2.9 5.9 6.5.95-4.7 4.6 1.1 6.5L12 17.5l-5.8 3.05 1.1-6.5-4.7-4.6 6.5-.95z";
|
|
3
3
|
const FIVE = `<svg viewBox="0 0 120 24" xmlns="http://www.w3.org/2000/svg">${[0, 24, 48, 72, 96].map((x) => `<path transform="translate(${x} 0)" d="${STAR}"/>`).join("")}</svg>`;
|
|
4
4
|
function rating(ctx, value, { max = 5, count, starsOnly = false } = {}) {
|
|
@@ -32,4 +32,4 @@ function rating(ctx, value, { max = 5, count, starsOnly = false } = {}) {
|
|
|
32
32
|
export {
|
|
33
33
|
rating as r
|
|
34
34
|
};
|
|
35
|
-
//# sourceMappingURL=rating-
|
|
35
|
+
//# sourceMappingURL=rating-CHVajQ2b.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rating-
|
|
1
|
+
{"version":3,"file":"rating-CHVajQ2b.js","sources":["../src/kit/rating.ts"],"sourcesContent":["/**\n * A rating: stars filled to the value, the value, and how many reviews it averages.\n *\n * Two rows of the same five stars, the coloured one clipped to the value's width, so\n * 4.6 shows six tenths of the fifth star. Read aloud as one sentence (\"Rated 4.6 out\n * of 5, 1,284 reviews\"); the stars themselves are hidden from a screen reader.\n */\nimport type { CardContext } from './define.js';\nimport { el, glyph } from './dom.js';\nimport { formatNumber } from './format.js';\nimport { KIT_WORDS, word } from './strings.js';\n\nconst STAR = 'M12 2.6l2.9 5.9 6.5.95-4.7 4.6 1.1 6.5L12 17.5l-5.8 3.05 1.1-6.5-4.7-4.6 6.5-.95z';\nconst FIVE = `<svg viewBox=\"0 0 120 24\" xmlns=\"http://www.w3.org/2000/svg\">${[0, 24, 48, 72, 96].map((x) => `<path transform=\"translate(${x} 0)\" d=\"${STAR}\"/>`).join('')}</svg>`; // safe-attr: this package's own glyph constants and loop numbers, never data // safe-text: this package's own SVG, built from its glyph constants\n\nexport interface RatingOptions {\n /** The scale's top (5 by default). */\n max?: number;\n /** How many reviews the value averages. */\n count?: number;\n /** Leave the number out and keep the stars. */\n starsOnly?: boolean;\n}\n\n/** The rating as an element, or `null` for no value. */\nexport function rating(ctx: CardContext, value: number | undefined, { max = 5, count, starsOnly = false }: RatingOptions = {}): HTMLElement | null {\n if (value === undefined || !Number.isFinite(value) || max <= 0) return null;\n const clamped = Math.max(0, Math.min(max, value));\n const stars = el('span', { class: 'aparte-rich-card__stars', attrs: { 'aria-hidden': 'true' } },\n glyph(FIVE, 'aparte-rich-card__stars-base'),\n glyph(FIVE, 'aparte-rich-card__stars-fill'));\n stars.style.setProperty('--aparte-rich-card-rating', `${(clamped / max) * 100}%`);\n const node = el('span', { class: 'aparte-rich-card__rating', attrs: { role: 'img' } }, stars);\n const shown = (n: number) => formatNumber(ctx.config, n, { maximumFractionDigits: 1 });\n if (!starsOnly) {\n const number = el('span', { class: 'aparte-rich-card__rating-value', attrs: { 'aria-hidden': 'true' } });\n ctx.bind(number, () => shown(clamped));\n node.append(number);\n }\n if (count !== undefined && Number.isFinite(count)) {\n const reviews = el('span', { class: 'aparte-rich-card__rating-count', attrs: { 'aria-hidden': 'true' } });\n ctx.bind(reviews, () => `(${formatNumber(ctx.config, count, { notation: count >= 10_000 ? 'compact' : 'standard' })})`);\n node.append(reviews);\n }\n ctx.bind(node, () => {\n const sentence = word(ctx.config, 'cardsRating', KIT_WORDS.cardsRating, { value: shown(clamped), max: shown(max) });\n return count !== undefined && Number.isFinite(count)\n ? `${sentence}, ${word(ctx.config, 'cardsReviews', KIT_WORDS.cardsReviews, { count: formatNumber(ctx.config, count) })}`\n : sentence;\n }, 'aria-label');\n return node;\n}\n"],"names":[],"mappings":";AAYA,MAAM,OAAO;AACb,MAAM,OAAO,gEAAgE,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC,MAAM,8BAA8B,CAAC,WAAW,IAAI,KAAK,EAAE,KAAK,EAAE,CAAC;AAYlK,SAAS,OAAO,KAAkB,OAA2B,EAAE,MAAM,GAAG,OAAO,YAAY,MAAA,IAAyB,IAAwB;AAC/I,MAAI,UAAU,UAAa,CAAC,OAAO,SAAS,KAAK,KAAK,OAAO,EAAG,QAAO;AACvE,QAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,CAAC;AAChD,QAAM,QAAQ;AAAA,IAAG;AAAA,IAAQ,EAAE,OAAO,2BAA2B,OAAO,EAAE,eAAe,SAAO;AAAA,IACxF,MAAM,MAAM,8BAA8B;AAAA,IAC1C,MAAM,MAAM,8BAA8B;AAAA,EAAA;AAC9C,QAAM,MAAM,YAAY,6BAA6B,GAAI,UAAU,MAAO,GAAG,GAAG;AAChF,QAAM,OAAO,GAAG,QAAQ,EAAE,OAAO,4BAA4B,OAAO,EAAE,MAAM,MAAA,EAAM,GAAK,KAAK;AAC5F,QAAM,QAAQ,CAAC,MAAc,aAAa,IAAI,QAAQ,GAAG,EAAE,uBAAuB,GAAG;AACrF,MAAI,CAAC,WAAW;AACZ,UAAM,SAAS,GAAG,QAAQ,EAAE,OAAO,kCAAkC,OAAO,EAAE,eAAe,OAAA,GAAU;AACvG,QAAI,KAAK,QAAQ,MAAM,MAAM,OAAO,CAAC;AACrC,SAAK,OAAO,MAAM;AAAA,EACtB;AACA,MAAI,UAAU,UAAa,OAAO,SAAS,KAAK,GAAG;AAC/C,UAAM,UAAU,GAAG,QAAQ,EAAE,OAAO,kCAAkC,OAAO,EAAE,eAAe,OAAA,GAAU;AACxG,QAAI,KAAK,SAAS,MAAM,IAAI,aAAa,IAAI,QAAQ,OAAO,EAAE,UAAU,SAAS,MAAS,YAAY,WAAA,CAAY,CAAC,GAAG;AACtH,SAAK,OAAO,OAAO;AAAA,EACvB;AACA,MAAI,KAAK,MAAM,MAAM;AACjB,UAAM,WAAW,KAAK,IAAI,QAAQ,eAAe,UAAU,aAAa,EAAE,OAAO,MAAM,OAAO,GAAG,KAAK,MAAM,GAAG,GAAG;AAClH,WAAO,UAAU,UAAa,OAAO,SAAS,KAAK,IAC7C,GAAG,QAAQ,KAAK,KAAK,IAAI,QAAQ,gBAAgB,UAAU,cAAc,EAAE,OAAO,aAAa,IAAI,QAAQ,KAAK,GAAG,CAAC,KACpH;AAAA,EACV,GAAG,YAAY;AACf,SAAO;AACX;"}
|
package/dist/score.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as defineCard, q as str, r as word, e as el, m as glyph, h as formatNumber, t as toDate, w as webUrl, n as intlTag, p as num, f as formatDay, g as formatHour } from "./format-BFq79ydr.js";
|
|
2
2
|
const svg = (body) => `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">${body}</svg>`;
|
|
3
3
|
const FOOTBALL = svg('<circle cx="12" cy="12" r="9"/><path d="M12 7.6l4.2 3-1.6 4.9H9.4L7.8 10.6z"/><path d="M12 7.6V3.2M16.2 10.6l4.3-1.3M14.6 15.5l2.6 3.7M9.4 15.5l-2.6 3.7M7.8 10.6L3.5 9.3"/>');
|
|
4
4
|
const BASKETBALL = svg('<circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3v18"/><path d="M5.7 5.6a9 9 0 0 1 0 12.8M18.3 5.6a9 9 0 0 0 0 12.8"/>');
|
package/dist/stats.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as defineCard, q as str, r as word, h as formatNumber, e as el, t as toDate, n as intlTag, l as formatWhen, a as currencyCode, p as num, m as glyph, k as formatUnit } from "./format-BFq79ydr.js";
|
|
2
2
|
import { s as sparkline } from "./sparkline-C-cA9obz.js";
|
|
3
3
|
const svg = (body) => `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">${body}</svg>`;
|
|
4
4
|
const MONEY = svg('<ellipse cx="12" cy="6.5" rx="6.5" ry="2.7"/><path d="M5.5 6.5v5c0 1.5 2.9 2.7 6.5 2.7s6.5-1.2 6.5-2.7v-5"/><path d="M5.5 11.5v5c0 1.5 2.9 2.7 6.5 2.7s6.5-1.2 6.5-2.7v-5"/>');
|
package/dist/stock.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { e as el,
|
|
1
|
+
import { e as el, r as word, b as defineCard, q as str, h as formatNumber, p as num, w as webUrl, a as currencyCode, m as glyph, t as toDate, n as intlTag, g as formatHour, l as formatWhen } from "./format-BFq79ydr.js";
|
|
2
2
|
import { s as sparkline } from "./sparkline-C-cA9obz.js";
|
|
3
|
-
import { s as segmented } from "./controls-
|
|
3
|
+
import { s as segmented } from "./controls-BYUm4aRV.js";
|
|
4
4
|
const CHART_ROLE = { en: "chart", fr: "graphique", de: "Diagramm", es: "gráfico", it: "grafico", ja: "チャート", ko: "차트", pt: "gráfico", ru: "график", zh: "图表" };
|
|
5
5
|
const SVG = "http://www.w3.org/2000/svg";
|
|
6
6
|
const PAD = 0.2;
|
package/dist/weather.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as defineCard, q as str, r as word, e as el, p as num, t as toDate, k as formatUnit, m as glyph, f as formatDay, i as formatPercent, h as formatNumber, l as formatWhen, g as formatHour } from "./format-BFq79ydr.js";
|
|
2
2
|
import { s as sparkline } from "./sparkline-C-cA9obz.js";
|
|
3
3
|
const WEATHER_CONDITIONS = [
|
|
4
4
|
"clear",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aparte/plugin-cards",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.1",
|
|
4
4
|
"homepage": "https://apartejs.dev/guides/cards/",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -94,12 +94,12 @@
|
|
|
94
94
|
"node": ">=18"
|
|
95
95
|
},
|
|
96
96
|
"peerDependencies": {
|
|
97
|
-
"@aparte/core": ">=0.29.
|
|
97
|
+
"@aparte/core": ">=0.29.1 <1.0.0"
|
|
98
98
|
},
|
|
99
99
|
"devDependencies": {
|
|
100
100
|
"typescript": "~5.7.0",
|
|
101
101
|
"vite": "^6.0.0",
|
|
102
|
-
"@aparte/core": "0.29.
|
|
102
|
+
"@aparte/core": "0.29.1"
|
|
103
103
|
},
|
|
104
104
|
"keywords": [
|
|
105
105
|
"aparte",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"format-CchcJRum.js","sources":["../src/kit/dom.ts","../src/kit/strings.ts","../src/kit/cards.css?raw","../src/kit/define.ts","../src/kit/format.ts"],"sourcesContent":["/**\n * The few DOM helpers every card draws with.\n *\n * A card shows what a tool returned, and a tool's result is untrusted: every value goes\n * in through `textContent` or an attribute, never through `innerHTML`. The one markup a\n * card parses is its own glyphs, which are constants of this package.\n */\n\ntype Child = Node | string | null | undefined | false;\n\n/** An element with classes, attributes and children; text children become text nodes. */\nexport function el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n props: { class?: string; attrs?: Record<string, string | number | boolean | null | undefined>; text?: string } = {},\n ...children: Child[]\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n if (props.class) node.className = props.class;\n for (const [name, value] of Object.entries(props.attrs ?? {})) {\n if (value === null || value === undefined || value === false) continue;\n node.setAttribute(name, value === true ? '' : String(value));\n }\n if (props.text !== undefined) node.textContent = props.text;\n for (const child of children) {\n if (child === null || child === undefined || child === false) continue;\n node.append(child);\n }\n return node;\n}\n\n/** One of this package's own SVG glyphs, as an element. Never call it with outside markup. */\nexport function glyph(markup: string, className = 'aparte-rich-card__glyph'): HTMLElement {\n const holder = document.createElement('span');\n holder.className = className;\n holder.setAttribute('aria-hidden', 'true');\n holder.innerHTML = markup;\n return holder;\n}\n\n/**\n * A link a card may open: `http(s)`, `mailto` and `tel` only, resolved against the page.\n * Anything else — `javascript:`, `data:`, a typo — is no link, so the action is not drawn.\n */\nexport function safeUrl(raw: unknown): string | null {\n if (typeof raw !== 'string' || !raw.trim()) return null;\n try {\n const url = new URL(raw.trim(), typeof location === 'undefined' ? 'https://localhost/' : location.href);\n return ['http:', 'https:', 'mailto:', 'tel:'].includes(url.protocol) ? url.href : null;\n } catch {\n return null;\n }\n}\n\n/**\n * A web address (`http`/`https`) — for an image or a page, where `mailto:` and `tel:` make no\n * sense. Absolute only: it comes from a tool's result, and a relative one (`lille.png`,\n * `/api/logout`) would become a request to the app's own origin, with its cookies, on render.\n */\nexport function webUrl(raw: unknown): string | null {\n if (typeof raw !== 'string' || !/^\\s*(https?:)?\\/\\//i.test(raw)) return null;\n const url = safeUrl(raw);\n return url && /^https?:/i.test(url) ? url : null;\n}\n\n/**\n * A tool's JSON, read key by key through the vendors' shapes (`r['geometry']?.['location']`).\n * Loose on purpose: no value read from it is used before a reader (`num`, `str`, `webUrl`,\n * `toDate`…) has checked it, so typing every level would add casts and no safety. Not exported\n * from the package.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type Loose = Record<string, any>;\n\n/** A finite number, or `undefined` — a tool's \"N/A\", `null` or `\"12\"` handled once. */\nexport function num(value: unknown): number | undefined {\n if (typeof value === 'number') return Number.isFinite(value) ? value : undefined;\n if (typeof value === 'string' && value.trim() !== '') {\n const n = Number(value);\n return Number.isFinite(n) ? n : undefined;\n }\n return undefined;\n}\n\n/** A non-empty trimmed string, or `undefined`. */\nexport function str(value: unknown): string | undefined {\n if (typeof value === 'string') return value.trim() || undefined;\n if (typeof value === 'number' && Number.isFinite(value)) return String(value);\n return undefined;\n}\n","/**\n * A card's words, in the chat's language.\n *\n * Core's locale is a closed list of what CORE draws, so a plugin reads its own keys off\n * `getLocale()` and defaults them at the call site (the localization guide). A card does\n * that, with one step in between: this package carries its words in the ten languages\n * `@aparte/locales` ships, picked by the locale's `tag`. An app that sets a key wins;\n * a language the table does not have reads English.\n *\n * aparteGlobalConfig.extendLocale({ cardsWeatherWind: 'Vent' });\n */\nimport type { AparteConfig } from '@aparte/core';\n\n/** The languages a card's words come in, beside English. */\nexport type CardLanguage = 'fr' | 'de' | 'es' | 'it' | 'ja' | 'ko' | 'pt' | 'ru' | 'zh';\n\n/** One word or phrase, in English and in as many of the other languages as it has. */\nexport type CardWord = { en: string } & Partial<Record<CardLanguage, string>>;\n\n/** The language part of the locale's tag: `pt-BR` → `pt`, `zh-CN` → `zh`, none → `en`. */\nexport function languageOf(config: AparteConfig): string {\n const tag = config.getLocale().tag;\n return (typeof tag === 'string' && tag ? tag.split('-')[0]!.toLowerCase() : 'en');\n}\n\n/** The locale's tag for `Intl`, or `undefined` to follow the browser (never `''`, which throws). */\nexport function intlTag(config: AparteConfig): string | undefined {\n const tag = config.getLocale().tag;\n if (typeof tag !== 'string' || !tag) return undefined;\n // A tag `Intl` refuses (`en_US`, a typo) would make every number and date on the card\n // throw, so the card would not draw at all: the underscore form is mended, anything else\n // follows the browser.\n for (const candidate of [tag, tag.replace(/_/g, '-')]) {\n try {\n return Intl.getCanonicalLocales(candidate)[0];\n } catch {\n // the next candidate\n }\n }\n return undefined;\n}\n\n/**\n * The word for `key`: the app's locale first, then this package's table for the chat's\n * language, then English. `{name}` placeholders are filled from `vars`.\n */\nexport function word(config: AparteConfig, key: string, table: CardWord, vars: Record<string, string> = {}): string {\n const fromApp = config.getLocale()[key];\n const lang = languageOf(config) as CardLanguage;\n const text = (typeof fromApp === 'string' && fromApp) || table[lang] || table.en;\n return text.replace(/\\{(\\w+)\\}/g, (all, name: string) => vars[name] ?? all);\n}\n\n/** The words every card shares. */\nexport const KIT_WORDS = {\n cardsUnavailable: {\n en: 'Not available', fr: 'Indisponible', de: 'Nicht verfügbar', es: 'No disponible', it: 'Non disponibile',\n ja: '利用できません', ko: '사용할 수 없음', pt: 'Indisponível', ru: 'Недоступно', zh: '不可用',\n },\n cardsWaiting: {\n en: 'Waiting for your approval', fr: 'En attente de votre accord', de: 'Wartet auf Ihre Zustimmung',\n es: 'Esperando tu aprobación', it: 'In attesa della tua approvazione', ja: '承認を待っています',\n ko: '승인을 기다리는 중', pt: 'Aguardando sua aprovação', ru: 'Ожидает вашего подтверждения', zh: '等待您的批准',\n },\n cardsRefused: {\n en: 'Not run', fr: 'Non exécuté', de: 'Nicht ausgeführt', es: 'No ejecutado', it: 'Non eseguito',\n ja: '実行されませんでした', ko: '실행되지 않음', pt: 'Não executado', ru: 'Не выполнено', zh: '未执行',\n },\n cardsLoading: {\n en: 'Loading', fr: 'Chargement', de: 'Wird geladen', es: 'Cargando', it: 'Caricamento',\n ja: '読み込み中', ko: '불러오는 중', pt: 'Carregando', ru: 'Загрузка', zh: '加载中',\n },\n cardsPrevious: {\n en: 'Previous', fr: 'Précédent', de: 'Zurück', es: 'Anterior', it: 'Precedente',\n ja: '前へ', ko: '이전', pt: 'Anterior', ru: 'Назад', zh: '上一个',\n },\n cardsNext: {\n en: 'Next', fr: 'Suivant', de: 'Weiter', es: 'Siguiente', it: 'Successivo',\n ja: '次へ', ko: '다음', pt: 'Próximo', ru: 'Далее', zh: '下一个',\n },\n cardsSlide: {\n en: '{n} of {total}', fr: '{n} sur {total}', de: '{n} von {total}', es: '{n} de {total}', it: '{n} di {total}',\n ja: '{total}件中{n}件目', ko: '{total}개 중 {n}번째', pt: '{n} de {total}', ru: '{n} из {total}', zh: '第 {n} 个,共 {total} 个',\n },\n cardsRating: {\n en: 'Rated {value} out of {max}', fr: 'Noté {value} sur {max}', de: 'Bewertet mit {value} von {max}',\n es: 'Valoración: {value} de {max}', it: 'Valutato {value} su {max}', ja: '{max}点中{value}点',\n ko: '{max}점 만점에 {value}점', pt: 'Avaliado em {value} de {max}', ru: 'Оценка {value} из {max}', zh: '评分 {value}/{max}',\n },\n cardsReviews: {\n en: '{count} reviews', fr: '{count} avis', de: '{count} Bewertungen', es: '{count} reseñas', it: '{count} recensioni',\n ja: 'レビュー{count}件', ko: '리뷰 {count}개', pt: '{count} avaliações', ru: 'Отзывов: {count}', zh: '{count} 条评价',\n },\n} satisfies Record<string, CardWord>;\n","export default \"/* =========================================\\n @aparte/plugin-cards — what every card shares\\n =========================================\\n A card wears core's `.aparte-card` recipe (border, radius, surface) and adds only what\\n is its own: its width in the bubble, its one-line state drawing, its actions. Every\\n value is a token, so a theme that restyles `--aparte-*` restyles the cards with it.\\n */\\n\\n.aparte-rich-card {\\n --aparte-rich-card-max-inline-size: 26rem;\\n --aparte-rich-card-gap: var(--aparte-space-4);\\n --aparte-rich-card-padding: var(--aparte-space-6);\\n\\n position: relative;\\n /* A definite width: a bubble shrinks to its content, so a percentage would resolve to\\n nothing. The card asks for its size and the bubble's own limit caps it. */\\n inline-size: var(--aparte-rich-card-max-inline-size);\\n max-inline-size: 100%;\\n margin-block: var(--aparte-space-3);\\n font-family: var(--aparte-font-family);\\n font-variant-numeric: tabular-nums;\\n line-height: 1.35;\\n isolation: isolate;\\n}\\n\\n.aparte-rich-card__glyph {\\n display: inline-flex;\\n flex: none;\\n inline-size: var(--aparte-rich-card-glyph-size, 1.5rem);\\n block-size: var(--aparte-rich-card-glyph-size, 1.5rem);\\n}\\n\\n.aparte-rich-card__glyph > svg {\\n inline-size: 100%;\\n block-size: 100%;\\n overflow: visible;\\n}\\n\\n/* The one line a call shows when it has nothing to draw: waiting, refused, failed. */\\n.aparte-rich-card[data-state=\\\"waiting\\\"],\\n.aparte-rich-card[data-state=\\\"refused\\\"],\\n.aparte-rich-card[data-state=\\\"unavailable\\\"] {\\n inline-size: fit-content;\\n background: var(--aparte-surface-1);\\n}\\n\\n.aparte-rich-card__strip {\\n display: flex;\\n align-items: center;\\n gap: var(--aparte-space-3);\\n padding: var(--aparte-space-3) var(--aparte-space-5);\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-md);\\n --aparte-rich-card-glyph-size: 1.25rem;\\n}\\n\\n.aparte-rich-card__strip .aparte-rich-card__glyph {\\n opacity: 0.7;\\n filter: grayscale(0.6);\\n}\\n\\n.aparte-rich-card__strip-title {\\n color: var(--aparte-text);\\n font-weight: var(--aparte-font-weight-medium);\\n}\\n\\n.aparte-rich-card__strip-state::before {\\n content: \\\"·\\\";\\n margin-inline-end: var(--aparte-space-3);\\n}\\n\\n/* Buttons under a card: the button recipe, laid out. */\\n.aparte-rich-card__actions {\\n display: flex;\\n flex-wrap: wrap;\\n gap: var(--aparte-space-3);\\n padding: var(--aparte-space-4) var(--aparte-rich-card-padding) var(--aparte-space-5);\\n border-block-start: var(--aparte-border-width) solid var(--aparte-border);\\n background: var(--aparte-surface-1);\\n}\\n\\n/* A card this page did not set up: its sentence. */\\n.aparte-rich-card__fallback {\\n margin-block: var(--aparte-space-2);\\n}\\n\\n/* Sparklines: the line takes the card's accent, the area fades from it. */\\n.aparte-rich-card__sparkline {\\n display: block;\\n inline-size: 100%;\\n block-size: 100%;\\n overflow: visible;\\n}\\n\\n.aparte-rich-card__sparkline-line {\\n fill: none;\\n stroke: var(--aparte-rich-card-spark, currentColor);\\n stroke-width: 2;\\n stroke-linecap: round;\\n stroke-linejoin: round;\\n}\\n\\n.aparte-rich-card__sparkline-area {\\n fill: var(--aparte-rich-card-spark, currentColor);\\n opacity: 0.14;\\n stroke: none;\\n}\\n\\n/* ── Rating: five stars, the coloured row clipped to the value ─────────── */\\n\\n.aparte-rich-card__rating {\\n display: inline-flex;\\n align-items: center;\\n gap: var(--aparte-space-2);\\n font-size: var(--aparte-font-size-sm);\\n white-space: nowrap;\\n}\\n\\n.aparte-rich-card__stars {\\n position: relative;\\n display: inline-block;\\n inline-size: 5.25em;\\n block-size: 1.05em;\\n flex: none;\\n}\\n\\n.aparte-rich-card__stars-base,\\n.aparte-rich-card__stars-fill {\\n position: absolute;\\n inset: 0;\\n inline-size: 100%;\\n block-size: 100%;\\n}\\n\\n.aparte-rich-card__stars-base { fill: color-mix(in oklab, var(--aparte-text) 16%, transparent); }\\n\\n.aparte-rich-card__stars-fill {\\n fill: var(--aparte-rich-card-star, #f5a623);\\n clip-path: inset(0 calc(100% - var(--aparte-rich-card-rating, 0%)) 0 0);\\n}\\n\\n/* Right to left the fill grows from the right: the clip is mirrored. The stars are symmetric,\\n so the glyphs themselves need no flip — a scaleX(-1) here moved the fill back to the left. */\\n.aparte-rich-card__stars-fill:dir(rtl) {\\n clip-path: inset(0 0 0 calc(100% - var(--aparte-rich-card-rating, 0%)));\\n}\\n\\n.aparte-rich-card__stars svg {\\n display: block;\\n inline-size: 100%;\\n block-size: 100%;\\n}\\n\\n.aparte-rich-card__rating-value { font-weight: var(--aparte-font-weight-semibold); }\\n.aparte-rich-card__rating-count { color: var(--aparte-text-muted); }\\n\\n/* ── Carousel: native scrolling, snap points, two buttons ───────────────── */\\n\\n.aparte-rich-card__carousel {\\n --aparte-rich-card-slide-size: 13.5rem;\\n --aparte-rich-card-slide-gap: var(--aparte-space-4);\\n position: relative;\\n}\\n\\n.aparte-rich-card__track {\\n display: grid;\\n grid-auto-flow: column;\\n grid-auto-columns: var(--aparte-rich-card-slide-size);\\n column-gap: var(--aparte-rich-card-slide-gap);\\n overflow-x: auto;\\n overscroll-behavior-x: contain;\\n scroll-snap-type: x mandatory;\\n /* Room round the slides for a tile's shadow, its lift on hover and its focus ring —\\n a scroller clips everything outside its box — given back by the margin, so the\\n slides still line up with what is above and below them. */\\n --aparte-rich-card-track-inset: var(--aparte-space-3);\\n --aparte-rich-card-track-inset-end: var(--aparte-space-6);\\n margin: calc(var(--aparte-rich-card-track-inset) * -1) calc(var(--aparte-rich-card-track-inset) * -1) calc(var(--aparte-rich-card-track-inset-end) * -1);\\n padding: var(--aparte-rich-card-track-inset) var(--aparte-rich-card-track-inset) var(--aparte-rich-card-track-inset-end);\\n scroll-padding-inline: var(--aparte-rich-card-track-inset);\\n scrollbar-width: none;\\n}\\n\\n.aparte-rich-card__track::-webkit-scrollbar { display: none; }\\n\\n.aparte-rich-card__track:focus-visible {\\n outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);\\n outline-offset: var(--aparte-focus-outline-offset);\\n border-radius: var(--aparte-radius-lg);\\n}\\n\\n.aparte-rich-card__slide {\\n display: flex;\\n scroll-snap-align: start;\\n min-inline-size: 0;\\n}\\n\\n.aparte-rich-card__slide > * { flex: 1; min-inline-size: 0; }\\n\\n.aparte-rich-card__nav {\\n position: absolute;\\n inset-block-start: 50%;\\n z-index: 1;\\n translate: 0 -50%;\\n border-radius: var(--aparte-radius-full);\\n box-shadow: 0 2px 10px -2px rgb(0 0 0 / 0.25);\\n opacity: 0;\\n transition: opacity var(--aparte-duration-fast, 120ms) ease;\\n}\\n\\n.aparte-rich-card__nav--prev { inset-inline-start: calc(var(--aparte-space-3) * -1); }\\n.aparte-rich-card__nav--next { inset-inline-end: calc(var(--aparte-space-3) * -1); }\\n.aparte-rich-card__nav--prev:dir(rtl), .aparte-rich-card__nav--next:dir(rtl) { transform: scaleX(-1); }\\n\\n.aparte-rich-card__carousel[data-overflow] .aparte-rich-card__nav:not(:disabled) { opacity: 1; }\\n.aparte-rich-card__carousel:not([data-overflow]) .aparte-rich-card__nav,\\n.aparte-rich-card__nav:disabled { pointer-events: none; }\\n\\n/* ── Live cards: busy while the app answers a change ────────────────────── */\\n\\n.aparte-rich-card[data-busy] {\\n cursor: progress;\\n}\\n\\n.aparte-rich-card[data-busy]::after {\\n content: \\\"\\\";\\n position: absolute;\\n inset-inline: 0;\\n inset-block-start: 0;\\n z-index: 3;\\n block-size: 2px;\\n background: linear-gradient(90deg, transparent, var(--aparte-primary), transparent);\\n background-size: 50% 100%;\\n background-repeat: no-repeat;\\n animation: aparte-rich-card-busy 1s linear infinite;\\n}\\n\\n@keyframes aparte-rich-card-busy {\\n from { background-position: -50% 0; }\\n to { background-position: 150% 0; }\\n}\\n\\n/* ── Controls: a row of choices, a switch, a slider ─────────────────────── */\\n\\n.aparte-rich-card__segmented {\\n display: inline-flex;\\n gap: 2px;\\n padding: 2px;\\n border-radius: var(--aparte-radius-full);\\n background: color-mix(in oklab, var(--aparte-text) 7%, transparent);\\n}\\n\\n.aparte-rich-card__segment {\\n min-inline-size: 2.5rem;\\n /* 24px at least: the smallest target WCAG 2.2 accepts for a pointer (2.5.8). */\\n min-block-size: 1.5rem;\\n padding: var(--aparte-space-1) var(--aparte-space-3);\\n border: 0;\\n border-radius: var(--aparte-radius-full);\\n background: transparent;\\n color: var(--aparte-text-muted);\\n font: inherit;\\n font-size: var(--aparte-font-size-xs);\\n font-weight: var(--aparte-font-weight-semibold);\\n cursor: pointer;\\n}\\n\\n.aparte-rich-card__segment:hover { color: var(--aparte-text); }\\n\\n.aparte-rich-card__segment[aria-pressed=\\\"true\\\"] {\\n background: var(--aparte-surface-1);\\n color: var(--aparte-text);\\n box-shadow: 0 1px 3px rgb(0 0 0 / 0.14);\\n cursor: default;\\n}\\n\\n.aparte-rich-card__segment:focus-visible,\\n.aparte-rich-card__toggle:focus-visible,\\n.aparte-rich-card__slider-input:focus-visible {\\n outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);\\n outline-offset: var(--aparte-focus-outline-offset);\\n}\\n\\n.aparte-rich-card__toggle {\\n position: relative;\\n flex: none;\\n inline-size: 2.5rem;\\n block-size: 1.5rem;\\n padding: 0;\\n border: 0;\\n border-radius: var(--aparte-radius-full);\\n background: color-mix(in oklab, var(--aparte-text) 22%, transparent);\\n cursor: pointer;\\n transition: background-color 0.15s ease;\\n}\\n\\n.aparte-rich-card__toggle[aria-checked=\\\"true\\\"] { background: var(--aparte-primary); }\\n\\n.aparte-rich-card__toggle-thumb {\\n position: absolute;\\n inset-block-start: 3px;\\n inset-inline-start: 3px;\\n inline-size: calc(1.5rem - 6px);\\n block-size: calc(1.5rem - 6px);\\n border-radius: var(--aparte-radius-full);\\n background: #fff;\\n box-shadow: 0 1px 3px rgb(0 0 0 / 0.25);\\n transition: inset-inline-start 0.15s ease;\\n}\\n\\n.aparte-rich-card__toggle[aria-checked=\\\"true\\\"] .aparte-rich-card__toggle-thumb {\\n inset-inline-start: calc(100% - 1.5rem + 3px);\\n}\\n\\n.aparte-rich-card__slider {\\n display: grid;\\n grid-template-columns: 1fr auto;\\n align-items: center;\\n gap: var(--aparte-space-1) var(--aparte-space-4);\\n font-size: var(--aparte-font-size-sm);\\n}\\n\\n.aparte-rich-card__slider-label { color: var(--aparte-text-muted); }\\n\\n.aparte-rich-card__slider-value {\\n grid-row: 1;\\n grid-column: 2;\\n font-weight: var(--aparte-font-weight-semibold);\\n font-variant-numeric: tabular-nums;\\n}\\n\\n.aparte-rich-card__slider-input {\\n grid-column: 1 / -1;\\n inline-size: 100%;\\n margin: 0;\\n accent-color: var(--aparte-primary);\\n cursor: pointer;\\n}\\n\\n@media (prefers-reduced-motion: reduce) {\\n .aparte-rich-card,\\n .aparte-rich-card::after,\\n .aparte-rich-card *,\\n .aparte-rich-card *::before,\\n .aparte-rich-card *::after {\\n animation: none !important;\\n transition: none !important;\\n }\\n}\\n\"","/**\n * `defineCard()` — what every card is made of, so a card only draws.\n *\n * A card is one drawing reached three ways, all of them seams core already has:\n *\n * - **a tool's result**: `registerToolRenderer` puts the card where the tool's row would\n * be. The app says which tool, and how its result maps onto the card's fields — its\n * data keeps its own shape;\n * - **a `card` segment**: a server, a runner or the app adds\n * `{ type: 'card', card: 'weather', data }` and the same card draws it. One segment\n * type for every card, not `custom`: an app has ONE renderer for `custom`, and taking\n * it would take the app's;\n * - a block in the text, for a source that only sends text — a later step.\n *\n * While the tool runs the card shows its skeleton, with what the call's input already\n * says (the city before the forecast). Waiting for a decision, refused, stopped or failed,\n * it shrinks to one line that says so — the result of a call that did not run is not\n * drawn as if it had.\n *\n * A **variant** is the same card laid out another way — `data-variant` on its root, read\n * by its sheet and its `render` — never a second registration.\n */\nimport {\n aparteGlobalConfig,\n cssEscape,\n overrideSegmentRenderer,\n type AparteConfig,\n type AparteSegmentBase,\n type AparteSegmentRenderer,\n type AparteToolCallSegment,\n type AparteToolMatcher,\n type AparteToolRenderer,\n} from '@aparte/core';\nimport { el, glyph, safeUrl } from './dom.js';\nimport { KIT_WORDS, word, type CardWord } from './strings.js';\nimport kitStyles from './cards.css?raw';\n\n/** The segment type every card shares. */\nexport const CARD_SEGMENT_TYPE = 'card';\n\n/**\n * A card added as a segment: `card` names it, `data` is in the card's own fields, and\n * `fallback` is the sentence a text-only reader gets — the history sent back to a model,\n * a build without this card.\n */\nexport interface AparteCardSegment extends AparteSegmentBase {\n type: 'card';\n card: string;\n data: unknown;\n variant?: string;\n fallback?: string;\n}\n\ndeclare module '@aparte/core' {\n interface AparteSegmentTypes {\n card: AparteCardSegment;\n }\n}\n\n/** A button under a card: a link it opens, a message it sends, or an `id` the app handles. */\nexport interface CardAction {\n label: string;\n /** Opened in a new tab; `http(s)`, `mailto` and `tel` only, otherwise the button is not drawn. */\n url?: string;\n /** Sent as the person's next message, through the chat's composer. */\n send?: string;\n /** Only reported, in the `aparte-card-action` event. */\n id?: string;\n /** Drawn as the card's main action. */\n primary?: boolean;\n}\n\n/**\n * A button under a card was pressed. Bubbles out of the chat; cancel it to handle the action\n * yourself instead of the link or the message. The detail is the card's name, the action and\n * the data the card was drawn from.\n *\n * @event aparte-card-action\n */\nexport interface CardActionEventDetail {\n card: string;\n action: CardAction;\n data: unknown;\n}\n\n/**\n * What `aparte-card-change` carries: a control inside a card was moved — a range chosen,\n * a switch flipped, a slider let go. Bubbles out of the chat; cancel the event to stop the\n * card's `onChange`.\n *\n * @event aparte-card-change\n */\nexport interface CardChangeEventDetail {\n card: string;\n /** The control's name, as the card gave it (`range`, `power`, `brightness`…). */\n name: string;\n value: unknown;\n /** The data the card was drawn from when the control moved. */\n data: unknown;\n}\n\n// Typed where they are dispatched: `addEventListener('aparte-card-action', (e) => e.detail.action)`\n// with no cast, on an element, the document or the window (both bubble out of the chat). The\n// types name the plugin's actions, so they cannot live in core's event map.\ninterface CardEventMap {\n 'aparte-card-action': CustomEvent<CardActionEventDetail>;\n 'aparte-card-change': CustomEvent<CardChangeEventDetail>;\n}\ndeclare global {\n interface HTMLElementEventMap extends CardEventMap {}\n interface DocumentEventMap extends CardEventMap {}\n interface WindowEventMap extends CardEventMap {}\n}\n\n/** What a card's drawing functions are handed. */\nexport interface CardContext<V extends string = string> {\n config: AparteConfig;\n variant: V;\n /** Where the data came from. */\n source: 'tool' | 'segment';\n /** Set `el`'s text to a word, and again after a language switch. */\n word(el: Element, key: string, table: CardWord, vars?: Record<string, string>): void;\n /** Set `el`'s text (or `attr`) from `compute`, and again after a language switch. */\n bind(el: Element, compute: () => string, attr?: string): void;\n /**\n * A button for an action inside the card — one per item of a carousel, say — wired like\n * the card's own: the `aparte-card-action` event (with `data`), then the link or the\n * message. `null` for an action that cannot run (no label, a link that is not http(s)).\n */\n action(action: CardAction, data?: unknown, className?: string): HTMLButtonElement | null;\n /**\n * Report that a control inside the card moved: `aparte-card-change` fires, then the\n * app's `onChange` runs, and what it returns is drawn in place — the same element,\n * the focus kept. The kit's controls (`segmented`, `toggle`, `slider`) call it.\n */\n change(name: string, value: unknown): void;\n /** Whether the app handles a change (an `onChange` was given): a card draws a control only when it does. */\n readonly live: boolean;\n}\n\n/** A card: its name, its variants, its sheet, and how it draws. */\nexport interface CardDefinition<D, V extends string = string> {\n /** The name a `card` segment gives, and the root's `data-card`. */\n name: string;\n /** Its layouts; the first is the default. */\n variants: readonly V[];\n /** Its stylesheet. The kit's own is added in front of it. */\n styles: string;\n /** The card's data from what it is given — `null` when there is nothing it can draw. */\n normalize(raw: unknown): D | null;\n /** The inside of the card, in `ctx.variant`. */\n render(data: D, ctx: CardContext<V>): Node[];\n /** The inside while the tool runs, from what its input already says. */\n skeleton(partial: Partial<D> | null, ctx: CardContext<V>): Node[];\n /** The card's accessible name (\"Weather in Lille\"), from whatever is known. */\n label(data: Partial<D> | null, ctx: CardContext<V>): string;\n /** One sentence of the data, for a reader that gets no card. */\n fallback(data: D, ctx: CardContext<V>): string;\n /** The one-line state drawing's glyph. */\n icon: string;\n /** What a running call's input already says: the city before the forecast. */\n partial?(input: Record<string, unknown>): Partial<D> | null;\n}\n\n/** How an app plugs a card in. */\nexport interface CardSetupOptions<D, V extends string = string> {\n /** The tool (or tools) whose result this card draws. Without it, only `card` segments draw it. */\n tool?: AparteToolMatcher | AparteToolMatcher[];\n /**\n * The card's fields from the tool's result — its `structuredContent` when it has one,\n * else its text parsed as JSON, else the text. Return `null` for a result the card\n * cannot draw. Without `map`, the result must already be in the card's fields.\n */\n // `any`: the result's shape is your tool's, and `map` is where you read it.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n map?: (result: any, input: Record<string, unknown>, segment: AparteToolCallSegment) => unknown;\n /** What the call's input already says, shown while it runs. Defaults to the card's own reading. */\n mapInput?: (input: Record<string, unknown>) => Partial<D> | null;\n /** A variant, or a function choosing one from the data. A name the card lacks reads as its default. */\n variant?: V | ((data: D) => V);\n /** Buttons under the card, at most three. */\n actions?: (data: D) => CardAction[];\n /**\n * A control inside the card moved (a range, a switch, a slider). Return the card's new\n * fields — the shape `map` returns — and the card is drawn again in place, the same\n * element with the focus kept; return nothing to leave it as it is. While it runs the\n * card is marked busy. Only the latest change is drawn when several overlap. The new\n * data lives in the page: a conversation reloaded from storage shows what was saved.\n */\n onChange?: (change: { name: string; value: unknown }, data: D) => unknown;\n /** The config to register on (the global one by default). */\n config?: AparteConfig;\n}\n\ntype DrawState = 'ready' | 'loading' | 'waiting' | 'refused' | 'unavailable';\n\n/** What a registered card keeps, per config. */\ninterface Entry {\n draw(segment: AparteCardSegment): HTMLElement;\n}\n\n/** Per config, each card's setups, the newest last: the newest draws the card's segments. */\nconst registries = new WeakMap<AparteConfig, Map<string, Entry[]>>();\nconst bindings = new WeakMap<Element, Array<{ attr?: string; compute: () => string }>>();\n\n/**\n * Where a binding writes: an attribute, the text, or — for a glyph from core's icon provider —\n * the markup. Not a valid attribute name, so no attribute binding can be mistaken for it.\n */\nconst MARKUP = ':markup';\n\nfunction apply(target: Element, compute: () => string, attr?: string): void {\n const text = compute();\n if (attr === MARKUP) target.innerHTML = text; // safe-text: only bindMarkup writes here, with core's icon markup\n else if (attr) target.setAttribute(attr, text);\n else target.textContent = text;\n}\n\n/**\n * A glyph from core's icon provider, written again on a relabel — the provider can change\n * after the card is drawn (`setIconProvider`), and core's relabel contract re-reads it. Only\n * for markup that is core's own (`config.getIcon`), never for a value from the data.\n */\nexport function bindMarkup(target: Element, compute: () => string): void {\n apply(target, compute, MARKUP);\n const list = bindings.get(target) ?? [];\n list.push({ attr: MARKUP, compute });\n bindings.set(target, list);\n target.setAttribute('data-card-bound', '');\n}\n\n/** The text a drawn card holds in the chat's language, read again on a switch. */\nfunction relabel(root: Element): void {\n const own = bindings.get(root);\n if (own) for (const b of own) apply(root, b.compute, b.attr);\n for (const node of root.querySelectorAll('[data-card-bound]')) {\n for (const b of bindings.get(node) ?? []) apply(node, b.compute, b.attr);\n }\n}\n\nfunction makeContext<V extends string>(\n config: AparteConfig,\n variant: V,\n source: 'tool' | 'segment',\n card: string,\n onChange?: (name: string, value: unknown) => void,\n): CardContext<V> {\n const bind = (target: Element, compute: () => string, attr?: string) => {\n apply(target, compute, attr);\n const list = bindings.get(target) ?? [];\n list.push({ attr, compute });\n bindings.set(target, list);\n target.setAttribute('data-card-bound', '');\n };\n return {\n config,\n variant,\n source,\n bind,\n word: (target, key, table, vars) => bind(target, () => word(config, key, table, vars)),\n action: (action, data, className) => actionButton(card, action, data, className),\n change: (name, value) => onChange?.(name, value),\n live: onChange !== undefined,\n };\n}\n\n/**\n * Put `next`'s inside into `element` — the element already on the page — keeping it, its\n * place, and the focus: a control the reader just pressed is pressed again in the new\n * drawing (by its `data-card-key`, else by its position).\n */\nfunction patch(element: HTMLElement, next: HTMLElement): void {\n const active = typeof document === 'undefined' ? null : document.activeElement;\n let key: string | null = null;\n let path: number[] | null = null;\n if (active instanceof HTMLElement && element.contains(active) && active !== element) {\n key = active.getAttribute('data-card-key');\n path = [];\n for (let node: Element = active; node !== element; node = node.parentElement!) {\n path.unshift(Array.prototype.indexOf.call(node.parentElement!.children, node));\n }\n }\n for (const name of element.getAttributeNames()) if (!next.hasAttribute(name)) element.removeAttribute(name);\n for (const name of next.getAttributeNames()) element.setAttribute(name, next.getAttribute(name)!);\n element.replaceChildren(...next.childNodes);\n const moved = bindings.get(next);\n if (moved) bindings.set(element, moved);\n const from = drawnFrom.get(next);\n if (from === undefined) drawnFrom.delete(element);\n else drawnFrom.set(element, from);\n homes.set(next, element);\n if (key !== null || path) {\n let target: Element | null = key ? element.querySelector(`[data-card-key=\"${cssEscape(key)}\"]`) : null;\n if (!target && path) {\n target = element;\n for (const i of path) target = target?.children[i] ?? null;\n }\n if (target instanceof HTMLElement) target.focus({ preventScroll: true });\n }\n}\n\n/** A drawing that was moved into an element already on the page, and that element. */\nconst homes = new WeakMap<Element, HTMLElement>();\n\n/** Per drawn card, how many times core gave it a new result: a change started before is dropped. */\nconst changeTurns = new WeakMap<Element, number>();\n\n/** The changes a card is working through, and the data the last one left. */\ninterface Queue<D> {\n pending: Map<string, unknown>;\n running: boolean;\n data: D;\n variant: string;\n}\nconst queues = new WeakMap<Element, Queue<unknown>>();\n\n/** What each drawing was drawn from (see `fingerprint`), carried onto the page by `patch`. */\nconst drawnFrom = new WeakMap<Element, string>();\n\n/** Core drew the card from a new result: what was waiting on the app's answer no longer applies. */\nfunction bumpTurn(element: Element): void {\n changeTurns.set(element, (changeTurns.get(element) ?? 0) + 1);\n queues.delete(element);\n}\n\nfunction busy(element: Element, on: boolean): void {\n element.toggleAttribute('data-busy', on);\n if (on) element.setAttribute('aria-busy', 'true');\n else element.removeAttribute('aria-busy');\n}\n\n/** A button that runs `action`, or `null` when it cannot run. */\nfunction actionButton(card: string, action: CardAction, data: unknown, className = ''): HTMLButtonElement | null {\n if (!action || typeof action.label !== 'string' || !action.label.trim()) return null;\n const url = action.url === undefined ? undefined : safeUrl(action.url);\n if (action.url !== undefined && !url) return null;\n if (!url && action.send === undefined && action.id === undefined) return null;\n const button = el('button', {\n class: `aparte-btn aparte-btn--sm ${action.primary ? 'aparte-btn--primary aparte-btn--solid' : 'aparte-btn--surface'} aparte-rich-card__action${className ? ` ${className}` : ''}`,\n attrs: { type: 'button' },\n text: action.label,\n });\n button.addEventListener('click', (event) => {\n // A button inside a card that is itself a link must not follow the link too.\n event.stopPropagation();\n runAction(card, button, action, url, data);\n });\n return button;\n}\n\nfunction runAction(card: string, button: HTMLElement, action: CardAction, url: string | null | undefined, data: unknown): void {\n const detail: CardActionEventDetail = { card, action, data };\n const proceed = button.dispatchEvent(new CustomEvent<CardActionEventDetail>('aparte-card-action', {\n detail, bubbles: true, composed: true, cancelable: true,\n }));\n if (!proceed) return;\n if (url) {\n // `mailto:` and `tel:` hand over to the mail or phone app: a new tab for them is left\n // empty in some browsers. A web page opens beside the chat.\n if (/^https?:/i.test(url)) window.open(url, '_blank', 'noopener,noreferrer');\n else window.location.href = url;\n return;\n }\n if (action.send !== undefined) {\n type Composer = HTMLElement & { value: string; streaming: boolean; panelActive: boolean; setValue(v: string): void; submit(): void };\n // The chat the card is in, in every shape: `<aparte-chat>` (vanilla, Angular) or the\n // `<div data-aparte-chat>` the React, Vue and Svelte wrappers render.\n const composer = (button.closest('aparte-chat, [data-aparte-chat]')?.querySelector('aparte-composer')\n ?? document.querySelector('aparte-composer')) as Composer | null;\n if (!composer) {\n console.warn(`[aparte-cards] the ${card} card has no <aparte-composer> to send \"${action.send}\" through.`);\n return;\n }\n // While a reply streams, `submit()` stops it; while a question holds the composer, it\n // answers the question. Neither is what a card's button means.\n if (composer.streaming || composer.panelActive) return;\n const draft = composer.value;\n composer.setValue(action.send);\n composer.submit();\n // What the person was writing is theirs: it comes back once the card's message is sent.\n if (draft.trim()) composer.setValue(draft);\n }\n}\n\nfunction parseResult(segment: AparteToolCallSegment): unknown {\n if (segment.structuredResult !== undefined) return segment.structuredResult;\n const text = segment.result;\n if (typeof text !== 'string') return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction stateOf(segment: AparteToolCallSegment): DrawState {\n switch (segment.status) {\n case 'resolved': return 'ready';\n case 'pending': return 'loading';\n case 'awaiting-approval': return 'waiting';\n case 'rejected': return 'refused';\n default: return 'unavailable';\n }\n}\n\n/**\n * Define a card. Returns its `setup`, which plugs it into a chat and returns the function\n * that unplugs it.\n */\nexport function defineCard<D, V extends string>(definition: CardDefinition<D, V>) {\n const styles = `${kitStyles}\\n${definition.styles}`;\n const defaultVariant = definition.variants[0]!;\n const known = new Set<string>(definition.variants);\n const warned = new WeakSet<object>();\n\n function chooseVariant(options: CardSetupOptions<D, V>, data: D | null, asked?: string): V {\n const wanted = asked ?? (typeof options.variant === 'function' ? (data ? options.variant(data) : undefined) : options.variant);\n return (wanted && known.has(wanted) ? wanted : defaultVariant) as V;\n }\n\n function root(state: DrawState, variant: V, id: string): HTMLElement {\n return el('div', {\n class: `aparte-segment aparte-card aparte-rich-card aparte-${definition.name}-card`,\n attrs: {\n 'data-segment-id': id,\n 'data-card': definition.name,\n 'data-variant': variant,\n 'data-state': state,\n role: 'group',\n 'aria-busy': state === 'loading' ? 'true' : undefined,\n },\n });\n }\n\n function actionsOf(options: CardSetupOptions<D, V>, data: D): HTMLElement | null {\n const buttons = (options.actions?.(data) ?? [])\n .map((action) => actionButton(definition.name, action, data))\n .filter((b): b is HTMLButtonElement => b !== null)\n .slice(0, 3);\n return buttons.length ? el('div', { class: 'aparte-rich-card__actions' }, ...buttons) : null;\n }\n\n /** The one-line drawing of a call that has no data to show. */\n function strip(config: AparteConfig, state: Exclude<DrawState, 'ready' | 'loading'>, partial: Partial<D> | null, variant: V, id: string, source: 'tool' | 'segment' = 'tool'): HTMLElement {\n const node = root(state, variant, id);\n const ctx = makeContext(config, variant, source, definition.name);\n const key = state === 'waiting' ? 'cardsWaiting' : state === 'refused' ? 'cardsRefused' : 'cardsUnavailable';\n const title = el('span', { class: 'aparte-rich-card__strip-title' });\n ctx.bind(title, () => definition.label(partial, ctx));\n const status = el('span', { class: 'aparte-rich-card__strip-state' });\n ctx.word(status, key, KIT_WORDS[key]);\n node.append(el('div', { class: 'aparte-rich-card__strip' }, glyph(definition.icon), title, status));\n ctx.bind(node, () => definition.label(partial, ctx), 'aria-label');\n return node;\n }\n\n function drawTool(options: CardSetupOptions<D, V>, config: AparteConfig, segment: AparteToolCallSegment): HTMLElement {\n const state = stateOf(segment);\n const input = (segment.toolCall?.input ?? {}) as Record<string, unknown>;\n const readInput = options.mapInput ?? definition.partial;\n let partial: Partial<D> | null = null;\n try {\n partial = readInput?.(input) ?? null;\n } catch {\n partial = null;\n }\n if (state === 'loading') {\n const variant = chooseVariant(options, null);\n const node = root(state, variant, segment.id);\n const ctx = makeContext(config, variant, 'tool', definition.name);\n node.append(...definition.skeleton(partial, ctx));\n ctx.bind(node, () => `${definition.label(partial, ctx)} — ${word(config, 'cardsLoading', KIT_WORDS.cardsLoading)}`, 'aria-label');\n return node;\n }\n if (state !== 'ready') return strip(config, state, partial, chooseVariant(options, null), segment.id);\n let data: D | null = null;\n let from = '';\n try {\n const raw = parseResult(segment);\n from = fingerprint(raw);\n const live = recall(options, `tool:${segment.id}`, from);\n if (live) return drawData(options, config, live.data, live.variant, segment.id, 'tool', from);\n data = definition.normalize(options.map ? options.map(raw, input, segment) : raw);\n } catch (error) {\n console.warn(`[aparte-cards] the ${definition.name} card's map threw:`, error);\n }\n if (!data) {\n if (!warned.has(options)) {\n warned.add(options);\n console.warn(`[aparte-cards] the ${definition.name} card got a result it cannot draw — check its \\`map\\` (tool \"${segment.toolCall?.name}\").`);\n }\n return strip(config, 'unavailable', partial, chooseVariant(options, null), segment.id);\n }\n return drawData(options, config, data, chooseVariant(options, data), segment.id, 'tool', from);\n }\n\n /**\n * What `onChange` gave each card, by the segment it is drawn for and what it was drawn\n * from. Core draws a segment again from the message — when a turn ends, when the\n * conversation is saved, when a Markdown provider arrives late — and only a framework\n * component's drawing survives that; without this, a card would go back to its first\n * data at the next save. A new result for the segment is drawn as it is; the old one,\n * shown again (a branch switched back), comes back as the person left it.\n */\n const kept = new WeakMap<CardSetupOptions<D, V>, Map<string, { from: string; data: D; variant: V }>>();\n\n function recall(options: CardSetupOptions<D, V>, key: string, from: string): { data: D; variant: V } | undefined {\n // A different result is not used, and not forgotten either: a segment id is not unique\n // across conversations (a model may number its calls the same way every time), and a\n // branch switched away and back shows the first result again — the card the person\n // left is the one they come back to. KEPT_MAX bounds what is kept.\n const entry = kept.get(options)?.get(key);\n return entry && from && entry.from === from ? entry : undefined;\n }\n\n function remember(options: CardSetupOptions<D, V>, key: string, from: string, data: D, variant: V): void {\n // A result that cannot be told apart from another cannot be matched again.\n if (!from) return;\n const byKey = kept.get(options) ?? new Map<string, { from: string; data: D; variant: V }>();\n kept.set(options, byKey);\n byKey.delete(key);\n byKey.set(key, { from, data, variant });\n // The oldest go first: a page that changed a hundred cards still remembers the latest.\n if (byKey.size > KEPT_MAX) byKey.delete(byKey.keys().next().value!);\n }\n\n function drawData(options: CardSetupOptions<D, V>, config: AparteConfig, data: D, variant: V, id: string, source: 'tool' | 'segment', from: string): HTMLElement {\n const node = root('ready', variant, id);\n drawnFrom.set(node, from);\n // The element on the page: a redraw moves this drawing into the one already there.\n const onChange = (name: string, value: unknown) => void change(homes.get(node) ?? node, options, config, data, variant, id, source, from, name, value);\n const ctx = makeContext(config, variant, source, definition.name, options.onChange ? onChange : undefined);\n node.append(...definition.render(data, ctx));\n const actions = actionsOf(options, data);\n if (actions) node.append(actions);\n ctx.bind(node, () => definition.label(data, ctx), 'aria-label');\n return node;\n }\n\n async function change(\n node: HTMLElement,\n options: CardSetupOptions<D, V>,\n config: AparteConfig,\n data: D,\n variant: V,\n id: string,\n source: 'tool' | 'segment',\n from: string,\n name: string,\n value: unknown,\n ): Promise<void> {\n const element = node;\n const waiting = queues.get(element) as Queue<D> | undefined;\n const detail: CardChangeEventDetail = { card: definition.name, name, value, data: waiting?.data ?? data };\n const proceed = element.dispatchEvent(new CustomEvent<CardChangeEventDetail>('aparte-card-change', {\n detail, bubbles: true, composed: true, cancelable: true,\n }));\n if (!proceed || !options.onChange) return;\n /*\n * One change at a time, in order, each from the data the one before it left. Run side\n * by side, each would start from the drawing it was pressed in, and the later answer —\n * built on data that never saw the earlier change — would undo it: the light turned on,\n * then dimmed, would come back off. A control moved again before its turn keeps only\n * its latest value: three presses on a range button ask for one range.\n */\n const queue: Queue<D> = waiting ?? { pending: new Map(), running: false, data, variant };\n queues.set(element, queue);\n queue.pending.delete(name);\n queue.pending.set(name, value);\n if (queue.running) return;\n queue.running = true;\n const turn = changeTurns.get(element) ?? 0;\n busy(element, true);\n try {\n while (queue.pending.size > 0) {\n const [nextName, nextValue] = queue.pending.entries().next().value!;\n queue.pending.delete(nextName);\n let next: unknown;\n try {\n next = await options.onChange({ name: nextName, value: nextValue }, queue.data);\n } catch (error) {\n console.warn(`[aparte-cards] the ${definition.name} card's onChange threw:`, error);\n continue;\n }\n // Core drew the card again from a new result while this ran: that result is newer.\n if ((changeTurns.get(element) ?? 0) !== turn) return;\n if (next === undefined || next === null) continue;\n const fresh = definition.normalize(next);\n if (!fresh) {\n console.warn(`[aparte-cards] the ${definition.name} card's onChange returned data it cannot draw — it was left as it was.`);\n continue;\n }\n queue.data = fresh;\n queue.variant = chooseVariant(options, fresh, queue.variant as V);\n remember(options, `${source}:${id}`, from, fresh, queue.variant as V);\n patch(element, drawData(options, config, fresh, queue.variant as V, id, source, from));\n if (queue.pending.size > 0) busy(element, true);\n }\n } finally {\n queue.running = false;\n if (queues.get(element) === queue) queues.delete(element);\n if ((changeTurns.get(element) ?? 0) === turn) busy(element, false);\n }\n }\n\n function setup(options: CardSetupOptions<D, V> = {}): () => void {\n const config = options.config ?? aparteGlobalConfig;\n const matchers = options.tool === undefined ? [] : Array.isArray(options.tool) ? options.tool : [options.tool];\n\n const toolRenderer: AparteToolRenderer = {\n render: (segment) => drawTool(options, config, segment),\n // Same element, new inside: the card the reader is looking at stays put.\n update: (element, segment) => {\n const next = drawTool(options, config, segment);\n // A new result is newer than any change still waiting on the app's answer; the\n // same result sent again (a turn ending, a save) leaves that change running.\n if (drawnFrom.get(next) !== drawnFrom.get(element)) bumpTurn(element);\n const wasBusy = element.hasAttribute('data-busy') && queues.has(element);\n patch(element, next);\n if (wasBusy) busy(element, true);\n },\n relabel: (element) => relabel(element),\n getStyles: () => styles,\n };\n // Overrides, not registrations: they stack. Two setups of the same tool — two components\n // that each declare it, a page that sets a card up twice — the newer draws, and taking\n // the older off leaves the newer in place; the last one off gives back what was there.\n const restores = matchers.map((match) => config.overrideToolRenderer(match, toolRenderer));\n\n const registry = registries.get(config) ?? new Map<string, Entry[]>();\n registries.set(config, registry);\n const entry: Entry = {\n draw: (segment) => {\n const from = fingerprint(segment.data);\n const live = recall(options, `segment:${segment.id}`, from);\n if (live) return drawData(options, config, live.data, live.variant, segment.id, 'segment', from);\n const data = definition.normalize(segment.data);\n const variant = chooseVariant(options, data, segment.variant);\n if (!data) return strip(config, 'unavailable', null, variant, segment.id, 'segment');\n return drawData(options, config, data, variant, segment.id, 'segment', from);\n },\n };\n const stack = registry.get(definition.name) ?? [];\n stack.push(entry);\n registry.set(definition.name, stack);\n // One override per setup, stacked like the tool's. Each registration injects the sheets\n // as they are now — a card whose module loaded after the first setup brings its own —\n // and draws again the `card` segments already on screen, so one drawn as its fallback\n // sentence before its card was set up becomes the card.\n const restoreSegments = overrideSegmentRenderer(cardSegmentRenderer(config), config);\n\n let stopped = false;\n return () => {\n if (stopped) return;\n stopped = true;\n for (const restore of restores) restore();\n const own = registry.get(definition.name);\n const at = own?.indexOf(entry) ?? -1;\n if (own && at >= 0) own.splice(at, 1);\n if (own && own.length === 0) registry.delete(definition.name);\n restoreSegments();\n };\n }\n\n /**\n * A `card` segment for this card, with its `fallback` sentence written — what a\n * server or a scenario adds to a message: `viewport.addSegment(id, weather.segment(data))`.\n */\n function segment(raw: unknown, options: { id?: string; variant?: V; config?: AparteConfig } = {}): AparteCardSegment {\n const config = options.config ?? aparteGlobalConfig;\n const data = definition.normalize(raw);\n const ctx = makeContext(config, (options.variant ?? defaultVariant) as V, 'segment', definition.name);\n return {\n id: options.id ?? `card-${definition.name}-${Math.random().toString(36).slice(2, 10)}`,\n type: CARD_SEGMENT_TYPE,\n card: definition.name,\n data: raw,\n ...(options.variant ? { variant: options.variant } : {}),\n ...(data ? { fallback: definition.fallback(data, ctx) } : {}),\n };\n }\n\n // One sheet per document for every card's segments: the kit's, then each card's.\n sheets.add(styles);\n\n return { name: definition.name, variants: definition.variants, setup, segment };\n}\n\nconst sheets = new Set<string>();\n\n/** Cards whose `onChange` data is remembered, per setup. */\nconst KEPT_MAX = 100;\n\n/** What a card was drawn from, as text to compare — `''` when it cannot be written (a cycle). */\nfunction fingerprint(raw: unknown): string {\n try {\n return JSON.stringify(raw) ?? '';\n } catch {\n return '';\n }\n}\n\n/** The renderer for `card` segments: it hands each one to the card it names. */\nfunction cardSegmentRenderer(config: AparteConfig): AparteSegmentRenderer<AparteCardSegment> {\n return {\n type: CARD_SEGMENT_TYPE,\n render: (segment) => {\n const entry = registries.get(config)?.get(segment.card)?.at(-1);\n if (entry) return entry.draw(segment);\n // A card this page did not set up: its sentence, not nothing.\n return el('p', { class: 'aparte-segment aparte-rich-card__fallback', attrs: { 'data-segment-id': segment.id }, text: segment.fallback ?? '' });\n },\n // A card segment sent again with new data (`updateSegment`) is drawn in place.\n update: (element, segment) => {\n const entry = registries.get(config)?.get(segment.card)?.at(-1);\n if (!entry) return;\n // Drawn as its fallback sentence before its card was set up: the card replaces it.\n if (!element.hasAttribute('data-card')) {\n element.replaceWith(entry.draw(segment));\n return;\n }\n const next = entry.draw(segment);\n if (drawnFrom.get(next) !== drawnFrom.get(element)) bumpTurn(element);\n const wasBusy = element.hasAttribute('data-busy') && queues.has(element);\n patch(element, next);\n if (wasBusy) busy(element, true);\n },\n relabel: (element) => relabel(element),\n getStyles: () => [...sheets].join('\\n'),\n };\n}\n","/**\n * Numbers, dates and times as the chat's language writes them.\n *\n * Every call reads the locale's `tag`, not the browser's: on a French page a card says\n * `12 %` and `mar.`, on a Japanese one `12%` and `火` — the same rule as the context\n * gauge and the bubble's clock. Nothing here needs a word of ours; `Intl` has them.\n */\nimport type { AparteConfig } from '@aparte/core';\nimport { intlTag } from './strings.js';\n\n/** A date from what a tool returns: an ISO string, an epoch (seconds or milliseconds) or a Date. */\nexport function toDate(value: unknown): Date | null {\n if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;\n if (typeof value === 'number' && Number.isFinite(value)) {\n // Below 10^12 it is seconds (Open-Meteo's `unixtime`, OpenWeather's `dt`).\n const d = new Date(value < 1e12 ? value * 1000 : value);\n return Number.isNaN(d.getTime()) ? null : d;\n }\n if (typeof value === 'string' && value.trim()) {\n // A day alone (`2026-10-31`) is that day where the reader is. `new Date()` reads it as\n // midnight UTC, which is the evening before anywhere west of Greenwich.\n const day = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value.trim());\n if (day) {\n const local = new Date(Number(day[1]), Number(day[2]) - 1, Number(day[3]));\n return local.getMonth() === Number(day[2]) - 1 ? local : null;\n }\n const d = new Date(value.trim());\n return Number.isNaN(d.getTime()) ? null : d;\n }\n return null;\n}\n\nexport function formatNumber(config: AparteConfig, value: number, options: Intl.NumberFormatOptions = {}): string {\n return new Intl.NumberFormat(intlTag(config), options).format(value);\n}\n\n/**\n * A price in its currency, as the language writes it: `49,00 €`, `€49.00`, `¥4,900`.\n * The currency is an ISO 4217 code (`EUR`); a symbol a tool gives (`€`, `$`) is read for\n * the usual ones. Without a currency, the number alone.\n */\nexport function formatPrice(config: AparteConfig, amount: number, currency?: string): string {\n const code = currencyCode(currency);\n const plain = () => formatNumber(config, amount, { minimumFractionDigits: Number.isInteger(amount) ? 0 : 2, maximumFractionDigits: 2 });\n // A currency `Intl` cannot name (`kr`, `zł`, `A$`) is still a currency: written as given.\n if (!code) return typeof currency === 'string' && currency.trim() ? `${plain()} ${currency.trim()}` : plain();\n try {\n return formatNumber(config, amount, { style: 'currency', currency: code });\n } catch {\n return `${formatNumber(config, amount, { maximumFractionDigits: 2 })} ${currency}`;\n }\n}\n\nconst SYMBOLS: Record<string, string> = { '€': 'EUR', $: 'USD', '£': 'GBP', '¥': 'JPY', '₩': 'KRW', '₽': 'RUB', '₹': 'INR', 'R$': 'BRL', CHF: 'CHF' };\n\n/** An ISO 4217 code from what a tool wrote (`eur`, `€`, `USD`), or `undefined`. */\nexport function currencyCode(value: unknown): string | undefined {\n if (typeof value !== 'string' || !value.trim()) return undefined;\n const v = value.trim();\n if (SYMBOLS[v]) return SYMBOLS[v];\n return /^[A-Za-z]{3}$/.test(v) ? v.toUpperCase() : undefined;\n}\n\n/**\n * The number in a price written as text, with its group and decimal separators. It may open\n * on its decimal separator — `.99`, `$.99` — or the digits after it would be read as 99.\n */\nconst AMOUNT = /(?:\\d|[.,]\\d)[\\d.,'\\s]*/;\n\n/** The dollars a shop writes with their country before the sign. */\nconst DOLLARS: Record<string, string> = { US: 'USD', CA: 'CAD', A: 'AUD', AU: 'AUD', NZ: 'NZD', HK: 'HKD', S: 'SGD', SG: 'SGD', MX: 'MXN', NT: 'TWD', R: 'BRL' };\n\nlet isoCodes: Set<string> | null | undefined;\n/** Whether `code` is a currency the runtime knows — `TTC`, or `ALL` in \"all included\", is a word. */\nfunction isCurrency(code: string): boolean {\n if (isoCodes === undefined) {\n try {\n isoCodes = new Set(Intl.supportedValuesOf('currency'));\n } catch {\n isoCodes = null;\n }\n }\n // A runtime without the list takes a code written in capitals, as ISO 4217 writes them.\n return isoCodes ? isoCodes.has(code) : /^[A-Z]{3}$/.test(code);\n}\n\n/**\n * The currency in what is left of a price once its number is out — `€ TTC`, `From $`, `US$`,\n * `GBP incl. VAT`: a country's dollar first (`US$` is not just any `$`), then a sign, then a\n * three-letter code the runtime knows, written in capitals or standing alone.\n */\nfunction currencyIn(text: string): string | undefined {\n const dollar = /(?:^|[^A-Za-z])([A-Z]{1,2})\\$/.exec(text);\n if (dollar && DOLLARS[dollar[1]!]) return DOLLARS[dollar[1]!];\n if (/(?:^|[^A-Za-z])CHF(?:$|[^A-Za-z])/.test(text)) return 'CHF';\n const sign = /[€£¥₩₽₹$]/.exec(text);\n if (sign) return currencyCode(sign[0]);\n const words = text.match(/[A-Za-z]+/g) ?? [];\n for (const w of words) {\n const code = w.toUpperCase();\n if (w.length === 3 && (w === code || words.length === 1) && isCurrency(code)) return code;\n }\n return undefined;\n}\n\n/**\n * A price a shop or a tool wrote as text — `$1,299.00`, `1.299,00 €`, `49,90`, `29,99 € TTC`,\n * `US$49.90`, `−€5` — read into its amount and currency. The separator that comes last is the\n * decimal one when both are there; a lone comma followed by one or two digits is a decimal\n * comma, otherwise a thousands separator; `1.299` is a German thousands dot. A minus before\n * the number, whatever sits between, makes it negative (an order's discount, a refund).\n * Shared by the product and order cards, which read prices the same way.\n */\nexport function readPriceText(text: string): { amount?: number; currency?: string } {\n // `\\s` takes in the no-break and narrow no-break spaces `Intl` groups digits with.\n const match = AMOUNT.exec(text);\n const currency = currencyIn(text.replace(AMOUNT, ' '));\n if (!match) return currency ? { currency } : {};\n let digits = match[0].replace(/[\\s']/g, '').replace(/[.,]+$/, '');\n const dot = digits.lastIndexOf('.');\n const comma = digits.lastIndexOf(',');\n if (dot >= 0 && comma >= 0) {\n const [decimal, group] = dot > comma ? ['.', ','] : [',', '.'];\n digits = digits.split(group).join('').replace(decimal, '.');\n } else if (comma >= 0) {\n digits = /^\\d*,\\d{1,2}$/.test(digits) ? digits.replace(',', '.') : digits.split(',').join('');\n } else if (dot >= 0 && (digits.indexOf('.') !== dot || /^[1-9]\\d{0,2}\\.\\d{3}$/.test(digits))) {\n digits = digits.split('.').join('');\n }\n const n = Number(digits);\n if (!Number.isFinite(n)) return currency ? { currency } : {};\n const amount = /[-−][^\\d]*$/.test(text.slice(0, match.index)) ? -n : n;\n return currency ? { amount, currency } : { amount };\n}\n\n/** `0.12` → `12 %` in French, `12%` in English. */\nexport function formatPercent(config: AparteConfig, ratio: number): string {\n return formatNumber(config, ratio, { style: 'percent', maximumFractionDigits: 0 });\n}\n\n/** A value with its unit, as `Intl` writes it: `14 km/h`, `14 km/h`, `9 mph`. */\nexport function formatUnit(config: AparteConfig, value: number, unit: string, digits = 0): string {\n try {\n return formatNumber(config, value, { style: 'unit', unit, unitDisplay: 'short', maximumFractionDigits: digits });\n } catch {\n // A unit `Intl` does not know: the number, then the unit as given.\n return `${formatNumber(config, value, { maximumFractionDigits: digits })} ${unit}`;\n }\n}\n\n/**\n * The day as a person says it: \"Today\", \"Tomorrow\", then the weekday (\"Thu\").\n * The first letter is raised, because `Intl` writes \"aujourd’hui\" for the middle of a sentence.\n */\nexport function formatDay(config: AparteConfig, date: Date, style: 'short' | 'long' = 'short', now: Date = new Date()): string {\n const tag = intlTag(config);\n const startOf = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\n const days = Math.round((startOf(date) - startOf(now)) / 86_400_000);\n let text: string;\n if (days === 0 || days === 1) {\n text = new Intl.RelativeTimeFormat(tag, { numeric: 'auto' }).format(days, 'day');\n } else {\n text = new Intl.DateTimeFormat(tag, { weekday: style }).format(date);\n }\n return text.charAt(0).toLocaleUpperCase(tag) + text.slice(1);\n}\n\n/**\n * The time, as the language writes it: `2 PM` where the clock has twelve hours, `14:00`\n * where it has twenty-four — never a bare `14`, which is what `{ hour: 'numeric' }`\n * gives in en-GB, Spanish, Italian, Portuguese and Russian.\n */\nexport function formatHour(config: AparteConfig, date: Date): string {\n const tag = intlTag(config);\n const twelve = /h1[12]/.test(new Intl.DateTimeFormat(tag, { hour: 'numeric' }).resolvedOptions().hourCycle ?? '');\n return twelve\n ? new Intl.DateTimeFormat(tag, { hour: 'numeric', minute: date.getMinutes() ? '2-digit' : undefined }).format(date)\n : new Intl.DateTimeFormat(tag, { hour: '2-digit', minute: '2-digit' }).format(date);\n}\n\n/** Weekday and time, for \"as of\": `Sat 14:05`. */\nexport function formatWhen(config: AparteConfig, date: Date): string {\n return new Intl.DateTimeFormat(intlTag(config), { weekday: 'short', hour: 'numeric', minute: '2-digit' }).format(date);\n}\n"],"names":["segment"],"mappings":"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"}
|