@aparte/plugin-cards 0.0.0-stage → 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.
Files changed (105) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -2
  3. package/dist/carousel-DwgHvriV.js +63 -0
  4. package/dist/carousel-DwgHvriV.js.map +1 -0
  5. package/dist/controls-BYUm4aRV.js +62 -0
  6. package/dist/controls-BYUm4aRV.js.map +1 -0
  7. package/dist/format-BFq79ydr.js +728 -0
  8. package/dist/format-BFq79ydr.js.map +1 -0
  9. package/dist/index.d.ts +30 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +120 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/items/icons.d.ts +12 -0
  14. package/dist/items/icons.d.ts.map +1 -0
  15. package/dist/items/index.d.ts +100 -0
  16. package/dist/items/index.d.ts.map +1 -0
  17. package/dist/items.js +698 -0
  18. package/dist/items.js.map +1 -0
  19. package/dist/kit/carousel.d.ts +17 -0
  20. package/dist/kit/carousel.d.ts.map +1 -0
  21. package/dist/kit/controls.d.ts +51 -0
  22. package/dist/kit/controls.d.ts.map +1 -0
  23. package/dist/kit/define.d.ts +201 -0
  24. package/dist/kit/define.d.ts.map +1 -0
  25. package/dist/kit/dom.d.ts +40 -0
  26. package/dist/kit/dom.d.ts.map +1 -0
  27. package/dist/kit/fence.d.ts +39 -0
  28. package/dist/kit/fence.d.ts.map +1 -0
  29. package/dist/kit/format.d.ts +49 -0
  30. package/dist/kit/format.d.ts.map +1 -0
  31. package/dist/kit/rating.d.ts +19 -0
  32. package/dist/kit/rating.d.ts.map +1 -0
  33. package/dist/kit/sparkline.d.ts +19 -0
  34. package/dist/kit/sparkline.d.ts.map +1 -0
  35. package/dist/kit/strings.d.ts +139 -0
  36. package/dist/kit/strings.d.ts.map +1 -0
  37. package/dist/link/icons.d.ts +16 -0
  38. package/dist/link/icons.d.ts.map +1 -0
  39. package/dist/link/index.d.ts +98 -0
  40. package/dist/link/index.d.ts.map +1 -0
  41. package/dist/link.js +387 -0
  42. package/dist/link.js.map +1 -0
  43. package/dist/media/icons.d.ts +28 -0
  44. package/dist/media/icons.d.ts.map +1 -0
  45. package/dist/media/index.d.ts +107 -0
  46. package/dist/media/index.d.ts.map +1 -0
  47. package/dist/media.js +610 -0
  48. package/dist/media.js.map +1 -0
  49. package/dist/order/icons.d.ts +49 -0
  50. package/dist/order/icons.d.ts.map +1 -0
  51. package/dist/order/index.d.ts +204 -0
  52. package/dist/order/index.d.ts.map +1 -0
  53. package/dist/order.js +1843 -0
  54. package/dist/order.js.map +1 -0
  55. package/dist/place/icons.d.ts +18 -0
  56. package/dist/place/icons.d.ts.map +1 -0
  57. package/dist/place/index.d.ts +207 -0
  58. package/dist/place/index.d.ts.map +1 -0
  59. package/dist/place.js +1456 -0
  60. package/dist/place.js.map +1 -0
  61. package/dist/plan/icons.d.ts +25 -0
  62. package/dist/plan/icons.d.ts.map +1 -0
  63. package/dist/plan/index.d.ts +153 -0
  64. package/dist/plan/index.d.ts.map +1 -0
  65. package/dist/plan.js +1191 -0
  66. package/dist/plan.js.map +1 -0
  67. package/dist/product/icons.d.ts +16 -0
  68. package/dist/product/icons.d.ts.map +1 -0
  69. package/dist/product/index.d.ts +133 -0
  70. package/dist/product/index.d.ts.map +1 -0
  71. package/dist/product.js +1245 -0
  72. package/dist/product.js.map +1 -0
  73. package/dist/rating-CHVajQ2b.js +35 -0
  74. package/dist/rating-CHVajQ2b.js.map +1 -0
  75. package/dist/score/icons.d.ts +35 -0
  76. package/dist/score/icons.d.ts.map +1 -0
  77. package/dist/score/index.d.ts +185 -0
  78. package/dist/score/index.d.ts.map +1 -0
  79. package/dist/score.js +1843 -0
  80. package/dist/score.js.map +1 -0
  81. package/dist/sparkline-C-cA9obz.js +56 -0
  82. package/dist/sparkline-C-cA9obz.js.map +1 -0
  83. package/dist/stats/icons.d.ts +19 -0
  84. package/dist/stats/icons.d.ts.map +1 -0
  85. package/dist/stats/index.d.ts +137 -0
  86. package/dist/stats/index.d.ts.map +1 -0
  87. package/dist/stats.js +1085 -0
  88. package/dist/stats.js.map +1 -0
  89. package/dist/stock/chart.d.ts +135 -0
  90. package/dist/stock/chart.d.ts.map +1 -0
  91. package/dist/stock/icons.d.ts +15 -0
  92. package/dist/stock/icons.d.ts.map +1 -0
  93. package/dist/stock/index.d.ts +195 -0
  94. package/dist/stock/index.d.ts.map +1 -0
  95. package/dist/stock.js +1013 -0
  96. package/dist/stock.js.map +1 -0
  97. package/dist/weather/conditions.d.ts +25 -0
  98. package/dist/weather/conditions.d.ts.map +1 -0
  99. package/dist/weather/icons.d.ts +12 -0
  100. package/dist/weather/icons.d.ts.map +1 -0
  101. package/dist/weather/index.d.ts +146 -0
  102. package/dist/weather/index.d.ts.map +1 -0
  103. package/dist/weather.js +1162 -0
  104. package/dist/weather.js.map +1 -0
  105. package/package.json +137 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"items.js","sources":["../src/items/icons.ts","../src/items/items.css?raw","../src/items/index.ts"],"sourcesContent":["/**\n * The items card's two glyphs: the stack it shows on its one-line state drawing, and the\n * picture that stands in for an image a result did not give (or that failed to load).\n *\n * Line drawings in `currentColor`, so the sheet tints them with a token and they follow\n * the theme. Constants of this package — the only markup the card parses.\n */\n\n/** Three cards fanned out: \"a set of results\", on the waiting / refused / failed line. */\nexport 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>`;\n\n/** A framed landscape: the placeholder where an item has no picture. */\nexport 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>`;\n","export default \"/* =========================================\\n The items card — @aparte/plugin-cards/items\\n =========================================\\n Three variants of one card, chosen by `data-variant` on its root:\\n carousel tiles in a row that scrolls sideways (the kit's carousel)\\n grid the same tiles, two columns, one when the card is narrow\\n list rows inside one card: a square thumbnail, the text, one button\\n One item, in the carousel or the grid, is one tile at the card's full width.\\n\\n In the carousel and the grid each tile is its own card, so the root lays them out and\\n draws no frame of its own — a boxed row of boxes reads as a form. The list keeps the\\n frame: its rows are parts of one card, divided by hairlines.\\n */\\n\\n.aparte-items-card {\\n /* The picture's box in a tile; a single item's is wider. */\\n --aparte-items-media-ratio: 4 / 3;\\n /* A tile's width in the carousel (the kit's slide size reads it). */\\n --aparte-items-tile-size: 13.5rem;\\n /* The thumbnail's side in a list row. */\\n --aparte-items-thumb-size: 4.5rem;\\n --aparte-items-tile-radius: var(--aparte-radius-lg);\\n /* Behind a missing picture: a wash of the accent on the surface, in either theme. */\\n --aparte-items-placeholder: linear-gradient(\\n 135deg,\\n color-mix(in oklab, var(--aparte-primary) 16%, var(--aparte-surface-2)) 0%,\\n var(--aparte-surface-2) 55%,\\n color-mix(in oklab, var(--aparte-text) 6%, var(--aparte-surface-2)) 100%\\n );\\n --aparte-items-placeholder-ink: color-mix(in oklab, var(--aparte-text) 32%, transparent);\\n --aparte-items-shadow: 0 1px 2px rgb(0 0 0 / 0.05), 0 8px 20px -14px rgb(0 0 0 / 0.35);\\n --aparte-items-shadow-hover: 0 2px 4px rgb(0 0 0 / 0.06), 0 14px 28px -14px rgb(0 0 0 / 0.42);\\n}\\n\\n.aparte-items-card[data-variant=\\\"carousel\\\"] { --aparte-rich-card-max-inline-size: 34rem; }\\n.aparte-items-card[data-variant=\\\"grid\\\"] { --aparte-rich-card-max-inline-size: 30rem; }\\n.aparte-items-card[data-variant=\\\"list\\\"] { --aparte-rich-card-max-inline-size: 28rem; }\\n\\n/* One item is one card, as wide as a card reads well — not as wide as a row of tiles. */\\n.aparte-items-card:not([data-variant=\\\"list\\\"]):has(> .aparte-items[data-count=\\\"1\\\"]) {\\n --aparte-rich-card-max-inline-size: 22rem;\\n --aparte-items-media-ratio: 16 / 9;\\n}\\n\\n/* Tiles are cards: the root only lays them out. */\\n.aparte-items-card:not([data-variant=\\\"list\\\"])[data-state=\\\"ready\\\"],\\n.aparte-items-card:not([data-variant=\\\"list\\\"])[data-state=\\\"loading\\\"] {\\n overflow: visible;\\n border-color: transparent;\\n border-radius: 0;\\n background: transparent;\\n}\\n\\n.aparte-items-card:not([data-variant=\\\"list\\\"]) > .aparte-rich-card__actions {\\n padding-inline: 0;\\n padding-block-end: 0;\\n border-block-start: 0;\\n background: transparent;\\n}\\n\\n.aparte-items {\\n container: aparte-items / inline-size;\\n}\\n\\n/* ── The card's title ─────────────────────────────────────────────────── */\\n\\n.aparte-items__header {\\n display: flex;\\n align-items: baseline;\\n justify-content: space-between;\\n gap: var(--aparte-space-4);\\n padding-block-end: var(--aparte-space-4);\\n}\\n\\n.aparte-items-card[data-variant=\\\"list\\\"] .aparte-items__header {\\n padding: var(--aparte-space-5) var(--aparte-space-6) var(--aparte-space-3);\\n}\\n\\n.aparte-items__heading {\\n min-inline-size: 0;\\n overflow: hidden;\\n font-size: var(--aparte-font-size-md);\\n font-weight: var(--aparte-font-weight-semibold);\\n letter-spacing: -0.005em;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\\n.aparte-items__count {\\n flex: none;\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-xs);\\n}\\n\\n/* ── One item ─────────────────────────────────────────────────────────── */\\n\\n.aparte-items__item {\\n position: relative;\\n min-inline-size: 0;\\n}\\n\\n.aparte-items__tile {\\n display: flex;\\n flex-direction: column;\\n block-size: 100%;\\n box-sizing: border-box;\\n overflow: hidden;\\n border: var(--aparte-border-width) solid var(--aparte-border);\\n border-radius: var(--aparte-items-tile-radius);\\n background: var(--aparte-surface-1);\\n color: var(--aparte-text);\\n box-shadow: var(--aparte-items-shadow);\\n transition:\\n transform var(--aparte-duration-slow) var(--aparte-ease),\\n box-shadow var(--aparte-duration-slow) var(--aparte-ease),\\n border-color var(--aparte-duration-slow) var(--aparte-ease);\\n}\\n\\n/* The picture: a fixed box, so a slow or missing image moves nothing below it. */\\n.aparte-items__media {\\n position: relative;\\n display: grid;\\n flex: none;\\n place-items: center;\\n aspect-ratio: var(--aparte-items-media-ratio);\\n overflow: hidden;\\n background: var(--aparte-items-placeholder);\\n color: var(--aparte-items-placeholder-ink);\\n --aparte-rich-card-glyph-size: 2rem;\\n}\\n\\n/* The glyph only where there is no picture: not through a transparent PNG, nor while\\n a slow one arrives. */\\n.aparte-items__media:not([data-empty]) .aparte-items__placeholder { visibility: hidden; }\\n\\n.aparte-items__image {\\n position: absolute;\\n inset: 0;\\n inline-size: 100%;\\n block-size: 100%;\\n object-fit: cover;\\n transition: transform var(--aparte-duration-slower) var(--aparte-ease);\\n}\\n\\n/* The badge over the picture's corner: the solid badge recipe, lifted off the photo. */\\n.aparte-items__media .aparte-items__badge {\\n position: absolute;\\n inset-block-start: var(--aparte-space-4);\\n inset-inline-start: var(--aparte-space-4);\\n max-inline-size: calc(100% - var(--aparte-space-8));\\n overflow: hidden;\\n box-shadow: 0 1px 4px rgb(0 0 0 / 0.22);\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\\n.aparte-items__body {\\n display: flex;\\n flex: 1;\\n flex-direction: column;\\n gap: var(--aparte-space-1);\\n min-inline-size: 0;\\n padding: var(--aparte-space-5) var(--aparte-space-6) var(--aparte-space-6);\\n}\\n\\n.aparte-items__title {\\n display: -webkit-box;\\n overflow: hidden;\\n color: var(--aparte-text);\\n font-size: var(--aparte-font-size-base);\\n font-weight: var(--aparte-font-weight-semibold);\\n line-height: 1.3;\\n letter-spacing: -0.01em;\\n text-decoration: none;\\n overflow-wrap: anywhere;\\n -webkit-box-orient: vertical;\\n -webkit-line-clamp: 2;\\n line-clamp: 2;\\n}\\n\\n.aparte-items__subtitle {\\n overflow: hidden;\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-sm);\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\\n.aparte-items__description {\\n display: -webkit-box;\\n margin: var(--aparte-space-1) 0 0;\\n overflow: hidden;\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-sm);\\n line-height: 1.45;\\n overflow-wrap: anywhere;\\n -webkit-box-orient: vertical;\\n -webkit-line-clamp: 3;\\n line-clamp: 3;\\n}\\n\\n/* The details sit at the foot of the text, so they line up across tiles of one row.\\n The first line is the one a person scans for — a price, a date — so it reads first. */\\n.aparte-items__meta {\\n display: flex;\\n flex-direction: column;\\n gap: 1px;\\n margin: auto 0 0;\\n padding: var(--aparte-space-3) 0 0;\\n list-style: none;\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-xs);\\n}\\n\\n.aparte-items__meta > li {\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\\n.aparte-items__meta > li:first-child {\\n color: var(--aparte-text);\\n font-size: var(--aparte-font-size-sm);\\n font-weight: var(--aparte-font-weight-semibold);\\n}\\n\\n/* The buttons sit above the stretched link, so a click on one is the button's. */\\n.aparte-items__actions {\\n position: relative;\\n z-index: 2;\\n display: flex;\\n flex-wrap: wrap;\\n gap: var(--aparte-space-3);\\n padding: 0 var(--aparte-space-6) var(--aparte-space-6);\\n}\\n\\n.aparte-items__tile .aparte-items__action {\\n flex: 1 1 auto;\\n justify-content: center;\\n}\\n\\n/* ── The link: the title's, stretched over the whole item ───────────── */\\n\\n.aparte-items__link {\\n color: inherit;\\n text-decoration: none;\\n outline: none;\\n}\\n\\n.aparte-items__link::after {\\n content: \\\"\\\";\\n position: absolute;\\n inset: 0;\\n z-index: 1;\\n border-radius: inherit;\\n}\\n\\n.aparte-items__tile .aparte-items__link::after { border-radius: calc(var(--aparte-items-tile-radius) - var(--aparte-border-width)); }\\n\\n/* The focus ring goes round the whole item it opens, drawn inside its edge so neither\\n the tile's corners nor the carousel's scroller can clip it. */\\n.aparte-items__link:focus-visible::after {\\n outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);\\n outline-offset: calc(var(--aparte-focus-outline-width) * -1);\\n}\\n\\n.aparte-items__item[data-link] .aparte-items__link:focus-visible {\\n text-decoration: underline;\\n text-underline-offset: 0.18em;\\n}\\n\\n@media (hover: hover) {\\n .aparte-items__tile[data-link]:hover {\\n border-color: color-mix(in oklab, var(--aparte-text) 16%, var(--aparte-border));\\n box-shadow: var(--aparte-items-shadow-hover);\\n transform: translateY(-2px);\\n }\\n\\n .aparte-items__tile[data-link]:hover .aparte-items__image { transform: scale(1.04); }\\n\\n .aparte-items__item[data-link]:hover .aparte-items__link {\\n text-decoration: underline;\\n text-decoration-color: color-mix(in oklab, currentColor 40%, transparent);\\n text-underline-offset: 0.18em;\\n }\\n}\\n\\n/* ── Carousel ─────────────────────────────────────────────────────────── */\\n\\n.aparte-items .aparte-rich-card__carousel {\\n --aparte-rich-card-slide-size: var(--aparte-items-tile-size);\\n}\\n\\n/* A deeper shadow than the kit's room below the tiles allows. */\\n.aparte-items .aparte-rich-card__track {\\n --aparte-rich-card-track-inset-end: var(--aparte-space-8);\\n}\\n\\n/* ── Grid ─────────────────────────────────────────────────────────────── */\\n\\n.aparte-items__list {\\n margin: 0;\\n padding: 0;\\n list-style: none;\\n}\\n\\n.aparte-items__grid {\\n display: grid;\\n grid-template-columns: repeat(2, minmax(0, 1fr));\\n gap: var(--aparte-space-5);\\n}\\n\\n.aparte-items__grid > .aparte-items__entry {\\n display: flex;\\n min-inline-size: 0;\\n}\\n\\n.aparte-items__grid > .aparte-items__entry > .aparte-items__tile { flex: 1; }\\n\\n@container aparte-items (max-width: 420px) {\\n .aparte-items__grid { grid-template-columns: minmax(0, 1fr); }\\n}\\n\\n/* ── List ─────────────────────────────────────────────────────────────── */\\n\\n.aparte-items__rows > .aparte-items__entry + .aparte-items__entry {\\n border-block-start: var(--aparte-border-width) solid var(--aparte-border);\\n}\\n\\n.aparte-items-card[data-variant=\\\"list\\\"] .aparte-items__header + .aparte-items__rows {\\n border-block-start: var(--aparte-border-width) solid var(--aparte-border);\\n}\\n\\n.aparte-items__row {\\n display: grid;\\n grid-template-columns: var(--aparte-items-thumb-size) minmax(0, 1fr) auto;\\n align-items: center;\\n gap: var(--aparte-space-5);\\n padding: var(--aparte-space-4) var(--aparte-space-6);\\n transition: background-color var(--aparte-duration-base) var(--aparte-ease);\\n}\\n\\n/* No item of the list has a picture: no thumbnail column. */\\n.aparte-items__row[data-bare] { grid-template-columns: minmax(0, 1fr) auto; }\\n\\n.aparte-items__row .aparte-items__media {\\n --aparte-items-media-ratio: 1;\\n --aparte-rich-card-glyph-size: 1.5rem;\\n border-radius: var(--aparte-radius-md);\\n}\\n\\n/* A hairline round the thumbnail, so a white product shot does not melt into the card. */\\n.aparte-items__row .aparte-items__media::after {\\n content: \\\"\\\";\\n position: absolute;\\n inset: 0;\\n border-radius: inherit;\\n box-shadow: inset 0 0 0 var(--aparte-border-width) color-mix(in oklab, var(--aparte-text) 8%, transparent);\\n pointer-events: none;\\n}\\n\\n.aparte-items__row .aparte-items__body {\\n gap: 2px;\\n padding: 0;\\n}\\n\\n.aparte-items__title-line {\\n display: flex;\\n align-items: baseline;\\n gap: var(--aparte-space-3);\\n min-inline-size: 0;\\n}\\n\\n.aparte-items__title-line .aparte-items__badge { flex: none; }\\n\\n.aparte-items__row .aparte-items__title {\\n font-size: var(--aparte-font-size-md);\\n -webkit-line-clamp: 1;\\n line-clamp: 1;\\n}\\n\\n.aparte-items__row .aparte-items__description {\\n margin-block-start: 0;\\n -webkit-line-clamp: 2;\\n line-clamp: 2;\\n}\\n\\n/* In a row the details run on one line, a dot between them. */\\n.aparte-items__row .aparte-items__meta {\\n flex-flow: row wrap;\\n column-gap: 0;\\n padding-block-start: var(--aparte-space-1);\\n}\\n\\n.aparte-items__row .aparte-items__meta > li:first-child { font-size: var(--aparte-font-size-xs); }\\n\\n.aparte-items__row .aparte-items__meta > li + li::before {\\n content: \\\"·\\\";\\n margin-inline: var(--aparte-space-2);\\n color: var(--aparte-text-muted);\\n}\\n\\n.aparte-items__row .aparte-items__actions { padding: 0; }\\n\\n@media (hover: hover) {\\n .aparte-items__row[data-link]:hover { background: var(--aparte-surface-2); }\\n}\\n\\n/* A narrow card: the button goes under the text rather than squeezing it. */\\n@container aparte-items (max-width: 360px) {\\n .aparte-items__row {\\n grid-template-columns: var(--aparte-items-thumb-size) minmax(0, 1fr);\\n align-items: start;\\n }\\n .aparte-items__row .aparte-items__actions { grid-column: 2; }\\n .aparte-items__row,\\n .aparte-items-card[data-variant=\\\"list\\\"] .aparte-items__header { padding-inline: var(--aparte-space-5); }\\n}\\n\\n/* ── Skeleton ─────────────────────────────────────────────────────────── */\\n\\n.aparte-items__skeleton--carousel {\\n display: grid;\\n grid-auto-flow: column;\\n grid-auto-columns: var(--aparte-items-tile-size);\\n gap: var(--aparte-space-4);\\n overflow: hidden;\\n}\\n\\n.aparte-items__skeleton--grid {\\n display: grid;\\n grid-template-columns: repeat(2, minmax(0, 1fr));\\n gap: var(--aparte-space-5);\\n}\\n\\n.aparte-items__skeleton--list > .aparte-items__row + .aparte-items__row {\\n border-block-start: var(--aparte-border-width) solid var(--aparte-border);\\n}\\n\\n.aparte-items__skeleton .aparte-items__tile { box-shadow: none; }\\n\\n.aparte-items .aparte-items__sk-media {\\n block-size: auto;\\n inline-size: 100%;\\n aspect-ratio: var(--aparte-items-media-ratio);\\n border-radius: 0;\\n}\\n\\n.aparte-items .aparte-items__row .aparte-items__sk-media {\\n aspect-ratio: 1;\\n border-radius: var(--aparte-radius-md);\\n}\\n\\n.aparte-items .aparte-items__sk-title { inline-size: 85%; }\\n\\n@media (prefers-reduced-motion: reduce) {\\n .aparte-items__tile[data-link]:hover,\\n .aparte-items__tile[data-link]:hover .aparte-items__image { transform: none; }\\n}\\n\\n@media (max-width: 380px) {\\n .aparte-items-card { --aparte-items-tile-size: 12rem; }\\n .aparte-items__body { padding: var(--aparte-space-4) var(--aparte-space-5) var(--aparte-space-5); }\\n .aparte-items__actions { padding: 0 var(--aparte-space-5) var(--aparte-space-5); }\\n}\\n\"","/**\n * @aparte/plugin-cards/items — a tool's list of things, drawn as cards.\n *\n * import { setupItemsCard } from '@aparte/plugin-cards/items';\n *\n * setupItemsCard({\n * tool: 'search_articles',\n * map: (result) => ({\n * title: `Articles on ${result.query}`,\n * items: result.hits.map((h) => ({ title: h.headline, subtitle: h.source, image: h.thumbnail, url: h.link })),\n * }),\n * });\n *\n * The generic card: anything with a title — an article, a recipe, a listing, a course.\n * Each item may add a picture, a badge over it, a few lines of detail and up to two\n * buttons; the whole tile opens its `url`. Three variants of one card: `carousel` (tiles\n * in a row that scrolls sideways), `grid` (two columns of tiles) and `list` (rows, a\n * thumbnail at the start). One item, in any variant, is one card at full width.\n *\n * The numbers come from what the chat UIs that ship this card settled on: three to eight\n * items in a carousel (ten at most here), one picture each, three lines of detail and two\n * buttons at most per item, a title of about eighty characters.\n */\nimport type { AparteConfig } from '@aparte/core';\nimport { carousel } from '../kit/carousel.js';\nimport { defineCard, type CardAction, type CardContext, type CardSetupOptions } from '../kit/define.js';\nimport { el, glyph, safeUrl, str, webUrl } from '../kit/dom.js';\nimport { formatNumber } from '../kit/format.js';\nimport { intlTag, languageOf, word, type CardWord } from '../kit/strings.js';\nimport { IMAGE_ICON, ITEMS_ICON } from './icons.js';\nimport itemsStyles from './items.css?raw';\n\nexport type ItemsVariant = 'carousel' | 'grid' | 'list';\n\n/** A picture: its address (`http(s)` only) and what it shows. */\nexport interface ItemImage {\n src: string;\n /** What the picture shows. Leave it out when the title already says it: the picture is then decorative. */\n alt?: string;\n}\n\n/** One item, as `map` returns it. Only `title` is needed. */\nexport interface ItemInput {\n title: string;\n subtitle?: string;\n /** A few sentences; the card shows three lines of it. */\n description?: string;\n /** A URL, or `{ src, alt }`. Anything but `http(s)` draws the placeholder instead. */\n image?: string | ItemImage;\n /** A short word over the picture's corner: \"New\", \"−20 %\", \"4.8 ★\". */\n badge?: string;\n /** Up to three short lines: a date, a price, a distance. */\n meta?: string[];\n /** What the whole tile opens, in a new tab. Anything but `http(s)`, `mailto` or `tel` makes no link. */\n url?: string;\n /**\n * Up to two buttons, each a link (`http(s)`) or an `id`; the `aparte-card-action` event\n * carries the item as its `data`. A `send` is dropped: a result never writes the person's\n * next message — send one from your listener, or the card's `actions`.\n */\n actions?: CardAction[];\n /** Your own key for the item, handed back with its actions. */\n id?: string;\n}\n\n/** What `map` returns: the items, with a title above them — or one item, or a bare array. */\nexport interface ItemsInput {\n title?: string;\n items: ItemInput[];\n}\n\n/** One item, once read. */\nexport interface Item {\n title: string;\n subtitle?: string;\n description?: string;\n image?: { src: string; alt: string };\n badge?: string;\n meta: string[];\n url?: string;\n actions: CardAction[];\n id?: string;\n}\n\n/** The data as the card draws it, once read. */\nexport interface ItemsData {\n title?: string;\n items: Item[];\n}\n\nconst W = {\n cardsItemsTitle: { en: 'Results', fr: 'Résultats', de: 'Ergebnisse', es: 'Resultados', it: 'Risultati', ja: '結果', ko: '결과', pt: 'Resultados', ru: 'Результаты', zh: '结果' },\n // Russian counts with a colon so one form serves every number, as the kit's reviews do.\n cardsItemsCount: { en: '{n} items', fr: '{n} éléments', de: '{n} Einträge', es: '{n} elementos', it: '{n} elementi', ja: '{n}件', ko: '{n}개 항목', pt: '{n} itens', ru: 'Элементов: {n}', zh: '{n} 项' },\n cardsItemsNewTab: { en: 'opens in a new tab', fr: 's’ouvre dans un nouvel onglet', de: 'öffnet in einem neuen Tab', es: 'se abre en una pestaña nueva', it: 'si apre in una nuova scheda', ja: '新しいタブで開きます', ko: '새 탭에서 열림', pt: 'abre em uma nova aba', ru: 'откроется в новой вкладке', zh: '在新标签页中打开' },\n} satisfies Record<string, CardWord>;\n\n/** The most items drawn: a carousel past ten is a search page, not an answer. */\nexport const ITEMS_MAX = 10;\nconst META_MAX = 3;\nconst ACTIONS_MAX = 2;\n\n// ── Reading ──────────────────────────────────────────────────────────────────\n\nfunction readImage(value: unknown, alt: unknown): Item['image'] {\n let src: unknown = value;\n let text: unknown = alt;\n if (value && typeof value === 'object') {\n const o = value as Record<string, unknown>;\n src = o['src'] ?? o['url'];\n text = o['alt'] ?? alt;\n }\n // An absolute `http(s)` address only: a relative one would be fetched from the app's own origin.\n const url = webUrl(src);\n return url ? { src: url, alt: str(text) ?? '' } : undefined;\n}\n\n/**\n * An action the card can run: a label, and a web link (`http(s)`) or an `id` the app's\n * `aparte-card-action` listener handles. Never a `send`: the item is the tool's result — a\n * search hit, a page, a feed — and a button that posts its text as the person's next message\n * lets that text speak for them, a lever for prompt injection. The message is the app's to\n * write, in its listener (the item comes as `data`) or the card's `actions` option.\n */\nfunction readAction(value: unknown): CardAction | null {\n if (!value || typeof value !== 'object') return null;\n const o = value as Record<string, unknown>;\n const label = str(o['label']);\n if (!label) return null;\n const action: CardAction = { label };\n if (o['url'] !== undefined) {\n const url = webUrl(o['url']);\n if (!url) return null;\n action.url = url;\n }\n if (typeof o['id'] === 'string') action.id = o['id'];\n if (o['primary'] === true) action.primary = true;\n return action.url || action.id !== undefined ? action : null;\n}\n\nfunction readItem(raw: unknown): Item | null {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null;\n const r = raw as Record<string, unknown>;\n const title = str(r['title'] ?? r['name']);\n if (!title) return null;\n const meta = (Array.isArray(r['meta']) ? r['meta'] : r['meta'] !== undefined ? [r['meta']] : [])\n .map(str)\n .filter((m): m is string => m !== undefined)\n .slice(0, META_MAX);\n const actions = (Array.isArray(r['actions']) ? r['actions'] : [])\n .map(readAction)\n .filter((a): a is CardAction => a !== null)\n .slice(0, ACTIONS_MAX);\n const url = safeUrl(r['url'] ?? r['link'] ?? r['href']);\n return {\n title,\n subtitle: str(r['subtitle']),\n description: str(r['description'] ?? r['snippet'] ?? r['summary']),\n image: readImage(r['image'] ?? r['imageUrl'] ?? r['image_url'] ?? r['thumbnail'], r['alt'] ?? r['imageAlt']),\n badge: str(r['badge']),\n meta,\n ...(url ? { url } : {}),\n actions,\n id: str(r['id']),\n };\n}\n\n/**\n * The card's data from what `map` returns — `{ title?, items }`, a bare array, or one\n * item — or `null` when no item has a title. Ten items at most.\n */\nexport function readItems(raw: unknown): ItemsData | null {\n let list: unknown[];\n let title: string | undefined;\n if (Array.isArray(raw)) {\n list = raw;\n } else if (raw && typeof raw === 'object' && Array.isArray((raw as Record<string, unknown>)['items'])) {\n const r = raw as Record<string, unknown>;\n list = r['items'] as unknown[];\n title = str(r['title']);\n } else {\n list = [raw];\n }\n const items = list.map(readItem).filter((i): i is Item => i !== null).slice(0, ITEMS_MAX);\n return items.length ? { ...(title ? { title } : {}), items } : null;\n}\n\n// ── Drawing ──────────────────────────────────────────────────────────────────\n\nfunction countText(config: AparteConfig, n: number): string {\n return word(config, 'cardsItemsCount', W.cardsItemsCount, { n: formatNumber(config, n) });\n}\n\n/** The card's name: its title, the one item's, or how many there are. */\nfunction labelOf(data: Partial<ItemsData> | null, config: AparteConfig): string {\n if (data?.title) return data.title;\n const items = data?.items ?? [];\n if (items.length === 1) return items[0]!.title;\n if (items.length > 1) return countText(config, items.length);\n return word(config, 'cardsItemsTitle', W.cardsItemsTitle);\n}\n\n/**\n * The picture in a fixed box, the placeholder underneath it. When the picture fails to\n * load it is taken out and the placeholder shows — the box keeps its size either way, so\n * nothing below it moves.\n */\nfunction media(item: Item, badge: boolean): HTMLElement {\n const box = el('div', { class: 'aparte-items__media', attrs: { 'data-empty': !item.image } },\n glyph(IMAGE_ICON, 'aparte-rich-card__glyph aparte-items__placeholder'));\n if (item.image) {\n const img = el('img', {\n class: 'aparte-items__image',\n attrs: {\n src: item.image.src,\n alt: item.image.alt,\n loading: 'lazy',\n decoding: 'async',\n // A third-party picture learns nothing of the page that shows it.\n referrerpolicy: 'no-referrer',\n },\n });\n img.addEventListener('error', () => {\n img.remove();\n box.setAttribute('data-empty', '');\n }, { once: true });\n box.append(img);\n }\n if (badge && item.badge) box.append(badgeOf(item.badge, 'aparte-badge--solid'));\n return box;\n}\n\nfunction badgeOf(text: string, fill: string): HTMLElement {\n return el('span', { class: `aparte-badge aparte-badge--primary ${fill} aparte-badge--sm aparte-items__badge`, text });\n}\n\n/**\n * The title, and the link when there is one. The link is the title alone — its name is\n * the title — and the sheet stretches its hit area over the whole tile, so the tile opens\n * it without wrapping the buttons inside a link, which HTML forbids.\n */\nfunction titleOf(ctx: CardContext, item: Item): HTMLElement {\n if (!item.url) return el('span', { class: 'aparte-items__title', text: item.title });\n const hint = el('span', { class: 'aparte-sr-only' });\n ctx.bind(hint, () => ` (${word(ctx.config, 'cardsItemsNewTab', W.cardsItemsNewTab)})`);\n return el('a', {\n class: 'aparte-items__title aparte-items__link',\n attrs: { href: item.url, target: '_blank', rel: 'noopener noreferrer' },\n }, item.title, hint);\n}\n\nfunction details(item: Item): Array<HTMLElement | null> {\n return [\n item.subtitle ? el('span', { class: 'aparte-items__subtitle', text: item.subtitle }) : null,\n item.description ? el('p', { class: 'aparte-items__description', text: item.description }) : null,\n item.meta.length\n ? el('ul', { class: 'aparte-items__meta', attrs: { role: 'list' } }, ...item.meta.map((m) => el('li', { text: m })))\n : null,\n ];\n}\n\nfunction actionsOf(ctx: CardContext, item: Item, max: number): HTMLElement | null {\n const buttons = item.actions\n .map((action) => ctx.action(action, item, 'aparte-items__action'))\n .filter((b): b is HTMLButtonElement => b !== null)\n .slice(0, max);\n return buttons.length ? el('div', { class: 'aparte-items__actions' }, ...buttons) : null;\n}\n\n/** A tile: the picture on top, its badge in the corner, the text, the buttons at the foot. */\nfunction tile(ctx: CardContext, item: Item): HTMLElement {\n const body = el('div', { class: 'aparte-items__body' }, titleOf(ctx, item), ...details(item));\n return el('article', { class: 'aparte-items__item aparte-items__tile', attrs: { 'data-link': !!item.url } },\n media(item, true), body, actionsOf(ctx, item, ACTIONS_MAX));\n}\n\n/**\n * A row: a square thumbnail at the start, the text, one button at the end. A list where no\n * item has a picture draws no thumbnail column at all — a column of placeholders is noise.\n */\nfunction row(ctx: CardContext, item: Item, pictures: boolean): HTMLElement {\n const head = el('div', { class: 'aparte-items__title-line' }, titleOf(ctx, item), item.badge ? badgeOf(item.badge, 'aparte-badge--soft') : null);\n const body = el('div', { class: 'aparte-items__body' }, head, ...details(item));\n return el('article', { class: 'aparte-items__item aparte-items__row', attrs: { 'data-link': !!item.url, 'data-bare': !pictures } },\n pictures ? media(item, false) : null, body, actionsOf(ctx, item, 1));\n}\n\nfunction header(ctx: CardContext, title: string | undefined, count: number): HTMLElement | null {\n if (!title) return null;\n const head = el('div', { class: 'aparte-items__header' }, el('span', { class: 'aparte-items__heading', text: title }));\n if (count > 1) {\n const n = el('span', { class: 'aparte-items__count' });\n ctx.bind(n, () => countText(ctx.config, count));\n head.append(n);\n }\n return head;\n}\n\nfunction list(ctx: CardContext, data: ItemsData, draw: (ctx: CardContext, item: Item) => HTMLElement, className: string): HTMLElement {\n const ul = el('ul', { class: `aparte-items__list ${className}`, attrs: { role: 'list' } },\n ...data.items.map((item) => el('li', { class: 'aparte-items__entry' }, draw(ctx, item))));\n ctx.bind(ul, () => labelOf(data, ctx.config), 'aria-label');\n return ul;\n}\n\nfunction render(data: ItemsData, ctx: CardContext<ItemsVariant>): Node[] {\n const count = data.items.length;\n const root = el('div', { class: 'aparte-items', attrs: { 'data-count': count } }, header(ctx, data.title, count));\n if (ctx.variant === 'list') {\n const pictures = data.items.some((item) => item.image);\n root.append(list(ctx, data, (c, item) => row(c, item, pictures), 'aparte-items__rows'));\n } else if (count === 1) {\n // One item is one card: no carousel chrome, no grid of one.\n root.append(tile(ctx, data.items[0]!));\n } else if (ctx.variant === 'grid') {\n root.append(list(ctx, data, tile, 'aparte-items__grid'));\n } else {\n root.append(carousel(ctx, data.items.map((item) => tile(ctx, item)), { label: () => labelOf(data, ctx.config) }));\n }\n return [root];\n}\n\n/** Three tiles (two in a grid's row, three rows in a list) in the shape the result will take. */\nfunction skeleton(partial: Partial<ItemsData> | null, ctx: CardContext<ItemsVariant>): Node[] {\n const block = (cls: string, kind: 'text' | 'rect' = 'rect') =>\n el('span', { class: `aparte-skeleton aparte-skeleton--${kind} ${cls}`, attrs: { 'aria-hidden': 'true' } });\n const text = () => el('div', { class: 'aparte-items__body' }, block('aparte-items__sk-title', 'text'), block('aparte-items__sk-line', 'text'));\n const root = el('div', { class: 'aparte-items' }, header(ctx, partial?.title, 0));\n const shapes = ctx.variant === 'list'\n ? [0, 1, 2].map(() => el('div', { class: 'aparte-items__item aparte-items__row' }, block('aparte-items__sk-media'), text()))\n : Array.from({ length: ctx.variant === 'grid' ? 2 : 3 }, () =>\n el('div', { class: 'aparte-items__item aparte-items__tile' }, block('aparte-items__sk-media'), text()));\n root.append(el('div', { class: `aparte-items__skeleton aparte-items__skeleton--${ctx.variant}`, attrs: { 'aria-hidden': 'true' } }, ...shapes));\n return [root];\n}\n\n/** One sentence: the title, then the items' titles as the language lists them. */\nfunction fallback(data: ItemsData, ctx: CardContext<ItemsVariant>): string {\n const titles = data.items.map((i) => i.title);\n let joined: string;\n try {\n // The language the words are in: with no tag they read English, and so does the \"and\".\n joined = new Intl.ListFormat(intlTag(ctx.config) ?? languageOf(ctx.config), { type: 'conjunction' }).format(titles);\n } catch {\n joined = titles.join(', ');\n }\n return `${data.title ?? word(ctx.config, 'cardsItemsTitle', W.cardsItemsTitle)}: ${joined}.`;\n}\n\nexport const itemsCard = defineCard<ItemsData, ItemsVariant>({\n name: 'items',\n variants: ['carousel', 'list', 'grid'],\n styles: itemsStyles,\n icon: ITEMS_ICON,\n normalize: readItems,\n render,\n skeleton,\n label: (data, ctx) => labelOf(data, ctx.config),\n fallback,\n partial: (input) => {\n const title = str(input['title'] ?? input['query'] ?? input['q']);\n return title ? { title } : null;\n },\n});\n\n/** Draw a tool's list of things as this card — returns the function that stops it. */\nexport function setupItemsCard(options: CardSetupOptions<ItemsData, ItemsVariant> = {}): () => void {\n return itemsCard.setup(options);\n}\n"],"names":["list"],"mappings":";;AASO,MAAM,aAAa;AAGnB,MAAM,aAAa;ACZ1B,MAAA,cAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AC0Ff,MAAM,IAAI;AAAA,EACN,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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * A row of slides that scrolls sideways: products, places, articles.
3
+ *
4
+ * Native scrolling with snap points, so touch, trackpad, wheel and keyboard (the track is
5
+ * focusable; arrows scroll it) all work as the platform does. Two buttons step a slide at
6
+ * a time and switch off at each end; they are not drawn when everything fits. Announced as
7
+ * a carousel, each slide as "2 of 5" (the WAI-ARIA carousel pattern, without auto-play:
8
+ * nothing here moves on its own).
9
+ */
10
+ import { type CardContext } from './define.js';
11
+ export interface CarouselOptions {
12
+ /** The carousel's accessible name ("Products"); its slides are counted inside it. */
13
+ label?: () => string;
14
+ }
15
+ /** The slides in a scrolling row, with its two buttons. */
16
+ export declare function carousel(ctx: CardContext, slides: HTMLElement[], { label }?: CarouselOptions): HTMLElement;
17
+ //# sourceMappingURL=carousel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"carousel.d.ts","sourceRoot":"","sources":["../../src/kit/carousel.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAK3D,MAAM,WAAW,eAAe;IAC5B,qFAAqF;IACrF,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CACxB;AAED,2DAA2D;AAC3D,wBAAgB,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,KAAK,EAAE,GAAE,eAAoB,GAAG,WAAW,CAgE9G"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Controls a card can carry: a row of choices, a switch, a slider. Each reports through
3
+ * `ctx.change(name, value)`, so the card fires `aparte-card-change` and the app's
4
+ * `onChange` answers with new data, drawn in place — a stock chart's range, a light's
5
+ * brightness.
6
+ *
7
+ * A control is drawn only when something will answer it (`ctx.live`): without an
8
+ * `onChange`, a button that does nothing would be a promise the card cannot keep
9
+ * (ratified decision #8). Each control carries a `data-card-key`, so a redraw puts the
10
+ * focus back on the control that was pressed.
11
+ */
12
+ import type { CardContext } from './define.js';
13
+ export interface SegmentedOptions {
14
+ /** The control's name in the change (`range`). */
15
+ name: string;
16
+ /** The choices; a label is a string or a function read again on a language switch. */
17
+ options: Array<{
18
+ value: string;
19
+ label: string | (() => string);
20
+ }>;
21
+ /** The choice in force. */
22
+ value?: string;
23
+ /** The group's accessible name. */
24
+ label?: () => string;
25
+ }
26
+ /** A row of choices, one pressed (`aria-pressed`). `null` when nothing would answer it. */
27
+ export declare function segmented(ctx: CardContext, { name, options, value, label }: SegmentedOptions): HTMLElement | null;
28
+ export interface ToggleOptions {
29
+ name: string;
30
+ checked: boolean;
31
+ /** What it switches ("Living-room light"). */
32
+ label: () => string;
33
+ }
34
+ /** A switch (`role="switch"`). `null` when nothing would answer it. */
35
+ export declare function toggle(ctx: CardContext, { name, checked, label }: ToggleOptions): HTMLElement | null;
36
+ export interface SliderOptions {
37
+ name: string;
38
+ value: number;
39
+ min?: number;
40
+ max?: number;
41
+ step?: number;
42
+ label: () => string;
43
+ /** How the value reads beside it, and to a screen reader ("60 %"). */
44
+ format?: (value: number) => string;
45
+ }
46
+ /**
47
+ * A slider: the value beside it follows while it moves, the change is reported once it is
48
+ * let go (`change`, not `input`) — one request for a drag, not one per pixel.
49
+ */
50
+ export declare function slider(ctx: CardContext, { name, value, min, max, step, label, format }: SliderOptions): HTMLElement | null;
51
+ //# sourceMappingURL=controls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controls.d.ts","sourceRoot":"","sources":["../../src/kit/controls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,WAAW,gBAAgB;IAC7B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,sFAAsF;IACtF,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAA;KAAE,CAAC,CAAC;IAClE,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CACxB;AAED,2FAA2F;AAC3F,wBAAgB,SAAS,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,gBAAgB,GAAG,WAAW,GAAG,IAAI,CAqBjH;AAED,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,8CAA8C;IAC9C,KAAK,EAAE,MAAM,MAAM,CAAC;CACvB;AAED,uEAAuE;AACvE,wBAAgB,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,aAAa,GAAG,WAAW,GAAG,IAAI,CAepG;AAED,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,MAAM,CAAC;IACpB,sEAAsE;IACtE,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CACtC;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAO,EAAE,GAAS,EAAE,IAAQ,EAAE,KAAK,EAAE,MAAe,EAAE,EAAE,aAAa,GAAG,WAAW,GAAG,IAAI,CAmBjJ"}
@@ -0,0 +1,201 @@
1
+ /**
2
+ * `defineCard()` — what every card is made of, so a card only draws.
3
+ *
4
+ * A card is one drawing reached three ways, all of them seams core already has:
5
+ *
6
+ * - **a tool's result**: `registerToolRenderer` puts the card where the tool's row would
7
+ * be. The app says which tool, and how its result maps onto the card's fields — its
8
+ * data keeps its own shape;
9
+ * - **a `card` segment**: a server, a runner or the app adds
10
+ * `{ type: 'card', card: 'weather', data }` and the same card draws it. One segment
11
+ * type for every card, not `custom`: an app has ONE renderer for `custom`, and taking
12
+ * it would take the app's;
13
+ * - a block in the text, for a source that only sends text — a later step.
14
+ *
15
+ * While the tool runs the card shows its skeleton, with what the call's input already
16
+ * says (the city before the forecast). Waiting for a decision, refused, stopped or failed,
17
+ * it shrinks to one line that says so — the result of a call that did not run is not
18
+ * drawn as if it had.
19
+ *
20
+ * A **variant** is the same card laid out another way — `data-variant` on its root, read
21
+ * by its sheet and its `render` — never a second registration.
22
+ */
23
+ import { type AparteConfig, type AparteSegmentBase, type AparteToolCallSegment, type AparteToolMatcher } from '@aparte/core';
24
+ import { type CardWord } from './strings.js';
25
+ /** The segment type every card shares. */
26
+ export declare const CARD_SEGMENT_TYPE = "card";
27
+ /**
28
+ * A card added as a segment: `card` names it, `data` is in the card's own fields, and
29
+ * `fallback` is the sentence a text-only reader gets — the history sent back to a model,
30
+ * a build without this card.
31
+ */
32
+ export interface AparteCardSegment extends AparteSegmentBase {
33
+ type: 'card';
34
+ card: string;
35
+ data: unknown;
36
+ variant?: string;
37
+ fallback?: string;
38
+ }
39
+ declare module '@aparte/core' {
40
+ interface AparteSegmentTypes {
41
+ card: AparteCardSegment;
42
+ }
43
+ }
44
+ /** A button under a card: a link it opens, a message it sends, or an `id` the app handles. */
45
+ export interface CardAction {
46
+ label: string;
47
+ /** Opened in a new tab; `http(s)`, `mailto` and `tel` only, otherwise the button is not drawn. */
48
+ url?: string;
49
+ /** Sent as the person's next message, through the chat's composer. */
50
+ send?: string;
51
+ /** Only reported, in the `aparte-card-action` event. */
52
+ id?: string;
53
+ /** Drawn as the card's main action. */
54
+ primary?: boolean;
55
+ }
56
+ /**
57
+ * A button under a card was pressed. Bubbles out of the chat; cancel it to handle the action
58
+ * yourself instead of the link or the message. The detail is the card's name, the action and
59
+ * the data the card was drawn from.
60
+ *
61
+ * @event aparte-card-action
62
+ */
63
+ export interface CardActionEventDetail {
64
+ card: string;
65
+ action: CardAction;
66
+ data: unknown;
67
+ }
68
+ /**
69
+ * What `aparte-card-change` carries: a control inside a card was moved — a range chosen,
70
+ * a switch flipped, a slider let go. Bubbles out of the chat; cancel the event to stop the
71
+ * card's `onChange`.
72
+ *
73
+ * @event aparte-card-change
74
+ */
75
+ export interface CardChangeEventDetail {
76
+ card: string;
77
+ /** The control's name, as the card gave it (`range`, `power`, `brightness`…). */
78
+ name: string;
79
+ value: unknown;
80
+ /** The data the card was drawn from when the control moved. */
81
+ data: unknown;
82
+ }
83
+ interface CardEventMap {
84
+ 'aparte-card-action': CustomEvent<CardActionEventDetail>;
85
+ 'aparte-card-change': CustomEvent<CardChangeEventDetail>;
86
+ }
87
+ declare global {
88
+ interface HTMLElementEventMap extends CardEventMap {
89
+ }
90
+ interface DocumentEventMap extends CardEventMap {
91
+ }
92
+ interface WindowEventMap extends CardEventMap {
93
+ }
94
+ }
95
+ /** What a card's drawing functions are handed. */
96
+ export interface CardContext<V extends string = string> {
97
+ config: AparteConfig;
98
+ variant: V;
99
+ /** Where the data came from. */
100
+ source: 'tool' | 'segment';
101
+ /** Set `el`'s text to a word, and again after a language switch. */
102
+ word(el: Element, key: string, table: CardWord, vars?: Record<string, string>): void;
103
+ /** Set `el`'s text (or `attr`) from `compute`, and again after a language switch. */
104
+ bind(el: Element, compute: () => string, attr?: string): void;
105
+ /**
106
+ * A button for an action inside the card — one per item of a carousel, say — wired like
107
+ * the card's own: the `aparte-card-action` event (with `data`), then the link or the
108
+ * message. `null` for an action that cannot run (no label, a link that is not http(s)).
109
+ */
110
+ action(action: CardAction, data?: unknown, className?: string): HTMLButtonElement | null;
111
+ /**
112
+ * Report that a control inside the card moved: `aparte-card-change` fires, then the
113
+ * app's `onChange` runs, and what it returns is drawn in place — the same element,
114
+ * the focus kept. The kit's controls (`segmented`, `toggle`, `slider`) call it.
115
+ */
116
+ change(name: string, value: unknown): void;
117
+ /** Whether the app handles a change (an `onChange` was given): a card draws a control only when it does. */
118
+ readonly live: boolean;
119
+ }
120
+ /** A card: its name, its variants, its sheet, and how it draws. */
121
+ export interface CardDefinition<D, V extends string = string> {
122
+ /** The name a `card` segment gives, and the root's `data-card`. */
123
+ name: string;
124
+ /** Its layouts; the first is the default. */
125
+ variants: readonly V[];
126
+ /** Its stylesheet. The kit's own is added in front of it. */
127
+ styles: string;
128
+ /** The card's data from what it is given — `null` when there is nothing it can draw. */
129
+ normalize(raw: unknown): D | null;
130
+ /** The inside of the card, in `ctx.variant`. */
131
+ render(data: D, ctx: CardContext<V>): Node[];
132
+ /** The inside while the tool runs, from what its input already says. */
133
+ skeleton(partial: Partial<D> | null, ctx: CardContext<V>): Node[];
134
+ /** The card's accessible name ("Weather in Lille"), from whatever is known. */
135
+ label(data: Partial<D> | null, ctx: CardContext<V>): string;
136
+ /** One sentence of the data, for a reader that gets no card. */
137
+ fallback(data: D, ctx: CardContext<V>): string;
138
+ /** The one-line state drawing's glyph. */
139
+ icon: string;
140
+ /** What a running call's input already says: the city before the forecast. */
141
+ partial?(input: Record<string, unknown>): Partial<D> | null;
142
+ }
143
+ /** How an app plugs a card in. */
144
+ export interface CardSetupOptions<D, V extends string = string> {
145
+ /** The tool (or tools) whose result this card draws. Without it, only `card` segments draw it. */
146
+ tool?: AparteToolMatcher | AparteToolMatcher[];
147
+ /**
148
+ * The card's fields from the tool's result — its `structuredContent` when it has one,
149
+ * else its text parsed as JSON, else the text. Return `null` for a result the card
150
+ * cannot draw. Without `map`, the result must already be in the card's fields.
151
+ */
152
+ map?: (result: any, input: Record<string, unknown>, segment: AparteToolCallSegment) => unknown;
153
+ /** What the call's input already says, shown while it runs. Defaults to the card's own reading. */
154
+ mapInput?: (input: Record<string, unknown>) => Partial<D> | null;
155
+ /** A variant, or a function choosing one from the data. A name the card lacks reads as its default. */
156
+ variant?: V | ((data: D) => V);
157
+ /** Buttons under the card, at most three. */
158
+ actions?: (data: D) => CardAction[];
159
+ /**
160
+ * A control inside the card moved (a range, a switch, a slider). Return the card's new
161
+ * fields — the shape `map` returns — and the card is drawn again in place, the same
162
+ * element with the focus kept; return nothing to leave it as it is. While it runs the
163
+ * card is marked busy. Only the latest change is drawn when several overlap. The new
164
+ * data lives in the page: a conversation reloaded from storage shows what was saved.
165
+ */
166
+ onChange?: (change: {
167
+ name: string;
168
+ value: unknown;
169
+ }, data: D) => unknown;
170
+ /** The config to register on (the global one by default). */
171
+ config?: AparteConfig;
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[];
180
+ /**
181
+ * A glyph from core's icon provider, written again on a relabel — the provider can change
182
+ * after the card is drawn (`setIconProvider`), and core's relabel contract re-reads it. Only
183
+ * for markup that is core's own (`config.getIcon`), never for a value from the data.
184
+ */
185
+ export declare function bindMarkup(target: Element, compute: () => string): void;
186
+ /**
187
+ * Define a card. Returns its `setup`, which plugs it into a chat and returns the function
188
+ * that unplugs it.
189
+ */
190
+ export declare function defineCard<D, V extends string>(definition: CardDefinition<D, V>): {
191
+ name: string;
192
+ variants: readonly V[];
193
+ setup: (options?: CardSetupOptions<D, V>) => () => void;
194
+ segment: (raw: unknown, options?: {
195
+ id?: string;
196
+ variant?: V;
197
+ config?: AparteConfig;
198
+ }) => AparteCardSegment;
199
+ };
200
+ export {};
201
+ //# sourceMappingURL=define.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/kit/define.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The few DOM helpers every card draws with.
3
+ *
4
+ * A card shows what a tool returned, and a tool's result is untrusted: every value goes
5
+ * in through `textContent` or an attribute, never through `innerHTML`. The one markup a
6
+ * card parses is its own glyphs, which are constants of this package.
7
+ */
8
+ type Child = Node | string | null | undefined | false;
9
+ /** An element with classes, attributes and children; text children become text nodes. */
10
+ export declare function el<K extends keyof HTMLElementTagNameMap>(tag: K, props?: {
11
+ class?: string;
12
+ attrs?: Record<string, string | number | boolean | null | undefined>;
13
+ text?: string;
14
+ }, ...children: Child[]): HTMLElementTagNameMap[K];
15
+ /** One of this package's own SVG glyphs, as an element. Never call it with outside markup. */
16
+ export declare function glyph(markup: string, className?: string): HTMLElement;
17
+ /**
18
+ * A link a card may open: `http(s)`, `mailto` and `tel` only, resolved against the page.
19
+ * Anything else — `javascript:`, `data:`, a typo — is no link, so the action is not drawn.
20
+ */
21
+ export declare function safeUrl(raw: unknown): string | null;
22
+ /**
23
+ * A web address (`http`/`https`) — for an image or a page, where `mailto:` and `tel:` make no
24
+ * sense. Absolute only: it comes from a tool's result, and a relative one (`lille.png`,
25
+ * `/api/logout`) would become a request to the app's own origin, with its cookies, on render.
26
+ */
27
+ export declare function webUrl(raw: unknown): string | null;
28
+ /**
29
+ * A tool's JSON, read key by key through the vendors' shapes (`r['geometry']?.['location']`).
30
+ * Loose on purpose: no value read from it is used before a reader (`num`, `str`, `webUrl`,
31
+ * `toDate`…) has checked it, so typing every level would add casts and no safety. Not exported
32
+ * from the package.
33
+ */
34
+ export type Loose = Record<string, any>;
35
+ /** A finite number, or `undefined` — a tool's "N/A", `null` or `"12"` handled once. */
36
+ export declare function num(value: unknown): number | undefined;
37
+ /** A non-empty trimmed string, or `undefined`. */
38
+ export declare function str(value: unknown): string | undefined;
39
+ export {};
40
+ //# sourceMappingURL=dom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/kit/dom.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,KAAK,KAAK,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC;AAEtD,yFAAyF;AACzF,wBAAgB,EAAE,CAAC,CAAC,SAAS,MAAM,qBAAqB,EACpD,GAAG,EAAE,CAAC,EACN,KAAK,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,EACnH,GAAG,QAAQ,EAAE,KAAK,EAAE,GACrB,qBAAqB,CAAC,CAAC,CAAC,CAa1B;AAED,8FAA8F;AAC9F,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,SAA4B,GAAG,WAAW,CAMxF;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAQnD;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAIlD;AAED;;;;;GAKG;AAEH,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAExC,uFAAuF;AACvF,wBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAOtD;AAED,kDAAkD;AAClD,wBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAItD"}
@@ -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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Numbers, dates and times as the chat's language writes them.
3
+ *
4
+ * Every call reads the locale's `tag`, not the browser's: on a French page a card says
5
+ * `12 %` and `mar.`, on a Japanese one `12%` and `火` — the same rule as the context
6
+ * gauge and the bubble's clock. Nothing here needs a word of ours; `Intl` has them.
7
+ */
8
+ import type { AparteConfig } from '@aparte/core';
9
+ /** A date from what a tool returns: an ISO string, an epoch (seconds or milliseconds) or a Date. */
10
+ export declare function toDate(value: unknown): Date | null;
11
+ export declare function formatNumber(config: AparteConfig, value: number, options?: Intl.NumberFormatOptions): string;
12
+ /**
13
+ * A price in its currency, as the language writes it: `49,00 €`, `€49.00`, `¥4,900`.
14
+ * The currency is an ISO 4217 code (`EUR`); a symbol a tool gives (`€`, `$`) is read for
15
+ * the usual ones. Without a currency, the number alone.
16
+ */
17
+ export declare function formatPrice(config: AparteConfig, amount: number, currency?: string): string;
18
+ /** An ISO 4217 code from what a tool wrote (`eur`, `€`, `USD`), or `undefined`. */
19
+ export declare function currencyCode(value: unknown): string | undefined;
20
+ /**
21
+ * A price a shop or a tool wrote as text — `$1,299.00`, `1.299,00 €`, `49,90`, `29,99 € TTC`,
22
+ * `US$49.90`, `−€5` — read into its amount and currency. The separator that comes last is the
23
+ * decimal one when both are there; a lone comma followed by one or two digits is a decimal
24
+ * comma, otherwise a thousands separator; `1.299` is a German thousands dot. A minus before
25
+ * the number, whatever sits between, makes it negative (an order's discount, a refund).
26
+ * Shared by the product and order cards, which read prices the same way.
27
+ */
28
+ export declare function readPriceText(text: string): {
29
+ amount?: number;
30
+ currency?: string;
31
+ };
32
+ /** `0.12` → `12 %` in French, `12%` in English. */
33
+ export declare function formatPercent(config: AparteConfig, ratio: number): string;
34
+ /** A value with its unit, as `Intl` writes it: `14 km/h`, `14 km/h`, `9 mph`. */
35
+ export declare function formatUnit(config: AparteConfig, value: number, unit: string, digits?: number): string;
36
+ /**
37
+ * The day as a person says it: "Today", "Tomorrow", then the weekday ("Thu").
38
+ * The first letter is raised, because `Intl` writes "aujourd’hui" for the middle of a sentence.
39
+ */
40
+ export declare function formatDay(config: AparteConfig, date: Date, style?: 'short' | 'long', now?: Date): string;
41
+ /**
42
+ * The time, as the language writes it: `2 PM` where the clock has twelve hours, `14:00`
43
+ * where it has twenty-four — never a bare `14`, which is what `{ hour: 'numeric' }`
44
+ * gives in en-GB, Spanish, Italian, Portuguese and Russian.
45
+ */
46
+ export declare function formatHour(config: AparteConfig, date: Date): string;
47
+ /** Weekday and time, for "as of": `Sat 14:05`. */
48
+ export declare function formatWhen(config: AparteConfig, date: Date): string;
49
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/kit/format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD,oGAAoG;AACpG,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,GAAG,IAAI,CAmBlD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,IAAI,CAAC,mBAAwB,GAAG,MAAM,CAEhH;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAU3F;AAID,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAK/D;AA4CD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAoBlF;AAED,mDAAmD;AACnD,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,iFAAiF;AACjF,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,MAAM,CAOhG;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,GAAE,OAAO,GAAG,MAAgB,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,CAW7H;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAMnE;AAED,kDAAkD;AAClD,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAEnE"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * A rating: stars filled to the value, the value, and how many reviews it averages.
3
+ *
4
+ * Two rows of the same five stars, the coloured one clipped to the value's width, so
5
+ * 4.6 shows six tenths of the fifth star. Read aloud as one sentence ("Rated 4.6 out
6
+ * of 5, 1,284 reviews"); the stars themselves are hidden from a screen reader.
7
+ */
8
+ import type { CardContext } from './define.js';
9
+ export interface RatingOptions {
10
+ /** The scale's top (5 by default). */
11
+ max?: number;
12
+ /** How many reviews the value averages. */
13
+ count?: number;
14
+ /** Leave the number out and keep the stars. */
15
+ starsOnly?: boolean;
16
+ }
17
+ /** The rating as an element, or `null` for no value. */
18
+ export declare function rating(ctx: CardContext, value: number | undefined, { max, count, starsOnly }?: RatingOptions): HTMLElement | null;
19
+ //# sourceMappingURL=rating.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rating.d.ts","sourceRoot":"","sources":["../../src/kit/rating.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ/C,MAAM,WAAW,aAAa;IAC1B,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wDAAwD;AACxD,wBAAgB,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,GAAO,EAAE,KAAK,EAAE,SAAiB,EAAE,GAAE,aAAkB,GAAG,WAAW,GAAG,IAAI,CA0BjJ"}
@@ -0,0 +1,19 @@
1
+ export interface SparklineOptions {
2
+ /** Extra class on the `<svg>`. */
3
+ className?: string;
4
+ /** Fill the area under the line (a gradient from the stroke's colour, in the sheet). */
5
+ area?: boolean;
6
+ /** Padding above and below the line, as a share of the height (0.15 by default). */
7
+ pad?: number;
8
+ /** The value range to scale against, when several charts must share one. */
9
+ range?: [number, number];
10
+ }
11
+ /** The points of a smooth line through `values`, in a 100 × 40 box. */
12
+ export declare function sparklinePath(values: number[], { pad, range }?: SparklineOptions): {
13
+ line: string;
14
+ area: string;
15
+ points: Array<[number, number]>;
16
+ };
17
+ /** The chart as an `<svg>`; decorative (`aria-hidden`), so put the numbers in text beside it. */
18
+ export declare function sparkline(values: number[], options?: SparklineOptions): SVGSVGElement;
19
+ //# sourceMappingURL=sparkline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sparkline.d.ts","sourceRoot":"","sources":["../../src/kit/sparkline.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,gBAAgB;IAC7B,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,oFAAoF;IACpF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B;AAED,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAU,EAAE,KAAK,EAAE,GAAE,gBAAqB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAAE,CA8B7J;AAED,iGAAiG;AACjG,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,gBAAqB,GAAG,aAAa,CAuBzF"}