@sankhyatronics/sankhya-cms 0.1.18 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/custom-elements.json +608 -15
  2. package/dist/bento-grid/index.d.ts +8 -1
  3. package/dist/bento-grid/index.js +2 -1
  4. package/dist/card/index.d.ts +3 -4
  5. package/dist/card/index.js +1 -1
  6. package/dist/{chunk-LEXZKGQX.js → chunk-2DXHPEB5.js} +1 -1
  7. package/dist/chunk-2DXHPEB5.js.map +1 -0
  8. package/dist/{chunk-R5G6KFTJ.js → chunk-2FJDNJ7R.js} +1 -1
  9. package/dist/chunk-2FJDNJ7R.js.map +1 -0
  10. package/dist/{chunk-ZN4LIKVG.js → chunk-3OEEOBHB.js} +1 -1
  11. package/dist/chunk-3OEEOBHB.js.map +1 -0
  12. package/dist/{chunk-BMHMNXIA.js → chunk-4AFOKKSU.js} +1 -1
  13. package/dist/chunk-4AFOKKSU.js.map +1 -0
  14. package/dist/{chunk-76AVBQUA.js → chunk-5C6C6K5U.js} +98 -4
  15. package/dist/chunk-5C6C6K5U.js.map +1 -0
  16. package/dist/{chunk-7NLZND6Q.js → chunk-5F5PTVWR.js} +27 -2
  17. package/dist/chunk-5F5PTVWR.js.map +1 -0
  18. package/dist/chunk-5MY6OWMK.js +125 -0
  19. package/dist/chunk-5MY6OWMK.js.map +1 -0
  20. package/dist/{chunk-FLY7TNRT.js → chunk-7NIWQWTA.js} +1 -1
  21. package/dist/chunk-7NIWQWTA.js.map +1 -0
  22. package/dist/{chunk-ALI26WOB.js → chunk-EE6PAN3B.js} +33 -2
  23. package/dist/chunk-EE6PAN3B.js.map +1 -0
  24. package/dist/{chunk-VWS53WY4.js → chunk-HMUZON6I.js} +49 -4
  25. package/dist/chunk-HMUZON6I.js.map +1 -0
  26. package/dist/chunk-O4FCRKDX.js +178 -0
  27. package/dist/chunk-O4FCRKDX.js.map +1 -0
  28. package/dist/{chunk-SMLR736E.js → chunk-OELI3IWC.js} +1 -1
  29. package/dist/chunk-OELI3IWC.js.map +1 -0
  30. package/dist/{chunk-JQY2G4QK.js → chunk-OLA35A2O.js} +1 -1
  31. package/dist/chunk-OLA35A2O.js.map +1 -0
  32. package/dist/{chunk-YQ42EBK5.js → chunk-PHEGSCOM.js} +1 -1
  33. package/dist/chunk-PHEGSCOM.js.map +1 -0
  34. package/dist/{chunk-5EBWMPJS.js → chunk-QLA4BH2B.js} +5 -5
  35. package/dist/chunk-QLA4BH2B.js.map +1 -0
  36. package/dist/{chunk-JKBWZLG4.js → chunk-SQ3OZO32.js} +141 -3
  37. package/dist/chunk-SQ3OZO32.js.map +1 -0
  38. package/dist/chunk-UAIUBPDN.js +11 -0
  39. package/dist/chunk-UAIUBPDN.js.map +1 -0
  40. package/dist/{chunk-XWB4CKDU.js → chunk-XUGEXERO.js} +6 -6
  41. package/dist/chunk-XUGEXERO.js.map +1 -0
  42. package/dist/chunk-ZRC5BVDX.js +219 -0
  43. package/dist/chunk-ZRC5BVDX.js.map +1 -0
  44. package/dist/cms-theme.css +7 -0
  45. package/dist/content-block/index.d.ts +2 -3
  46. package/dist/content-block/index.js +3 -2
  47. package/dist/dropdown/index.d.ts +8 -11
  48. package/dist/dropdown/index.js +1 -1
  49. package/dist/feature-split/index.js +2 -1
  50. package/dist/features-section/index.d.ts +4 -4
  51. package/dist/features-section/index.js +4 -3
  52. package/dist/flow/index.d.ts +35 -0
  53. package/dist/flow/index.js +9 -0
  54. package/dist/flow/index.js.map +1 -0
  55. package/dist/header/index.d.ts +8 -15
  56. package/dist/header/index.js +1 -1
  57. package/dist/hero/index.d.ts +18 -3
  58. package/dist/hero/index.js +1 -1
  59. package/dist/icon-button/index.d.ts +2 -4
  60. package/dist/icon-button/index.js +1 -1
  61. package/dist/index.d.ts +3 -0
  62. package/dist/index.js +36 -23
  63. package/dist/items-accordion/index.d.ts +5 -0
  64. package/dist/items-accordion/index.js +2 -1
  65. package/dist/markdown/index.d.ts +1 -2
  66. package/dist/markdown/index.js +2 -1
  67. package/dist/menu-grid/index.d.ts +2 -3
  68. package/dist/menu-grid/index.js +1 -1
  69. package/dist/menu-grid-item/index.d.ts +6 -8
  70. package/dist/menu-grid-item/index.js +1 -1
  71. package/dist/menu-item/index.d.ts +5 -7
  72. package/dist/menu-item/index.js +1 -1
  73. package/dist/promo-banner/index.d.ts +14 -3
  74. package/dist/promo-banner/index.js +1 -1
  75. package/dist/schema/index.d.ts +3 -0
  76. package/dist/schema/index.js +3 -0
  77. package/dist/schema/index.js.map +1 -1
  78. package/dist/section/index.d.ts +3 -0
  79. package/dist/section/index.js +1 -1
  80. package/dist/steps/index.d.ts +33 -0
  81. package/dist/steps/index.js +10 -0
  82. package/dist/steps/index.js.map +1 -0
  83. package/dist/tag-strip/index.d.ts +26 -0
  84. package/dist/tag-strip/index.js +9 -0
  85. package/dist/tag-strip/index.js.map +1 -0
  86. package/package.json +14 -2
  87. package/dist/chunk-5EBWMPJS.js.map +0 -1
  88. package/dist/chunk-76AVBQUA.js.map +0 -1
  89. package/dist/chunk-7NLZND6Q.js.map +0 -1
  90. package/dist/chunk-ALI26WOB.js.map +0 -1
  91. package/dist/chunk-BMHMNXIA.js.map +0 -1
  92. package/dist/chunk-FLY7TNRT.js.map +0 -1
  93. package/dist/chunk-JKBWZLG4.js.map +0 -1
  94. package/dist/chunk-JQY2G4QK.js.map +0 -1
  95. package/dist/chunk-LEXZKGQX.js.map +0 -1
  96. package/dist/chunk-R5G6KFTJ.js.map +0 -1
  97. package/dist/chunk-SMLR736E.js.map +0 -1
  98. package/dist/chunk-VWS53WY4.js.map +0 -1
  99. package/dist/chunk-XWB4CKDU.js.map +0 -1
  100. package/dist/chunk-YQ42EBK5.js.map +0 -1
  101. package/dist/chunk-ZN4LIKVG.js.map +0 -1
@@ -278,4 +278,4 @@ export {
278
278
  FeatureItem,
279
279
  FeaturesSection
280
280
  };
281
- //# sourceMappingURL=chunk-FLY7TNRT.js.map
281
+ //# sourceMappingURL=chunk-7NIWQWTA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/features-section/FeaturesSection.ts","../src/features-section/FeatureItem.ts"],"sourcesContent":["import { LitElement, css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\nimport { controlBaseStyles, fontFamilyStyles } from '../shared/styles';\nimport { sectionSubtitleStyles, sectionTitleStyles, sectionHeaderStyles } from '../shared/section-styles';\nimport './FeatureItem';\n\n/** Data for one tile when using the `items` property (mirrors `st-feature-item`'s properties). */\nexport interface FeatureItemData {\n icon?: string;\n title: string;\n description: string;\n href?: string;\n}\n\n/**\n * A titled grid of feature tiles. Tiles come from the `items` property, from slotted\n * `st-feature-item` elements, or both (slotted first). `columns` sets the grid width (default 2;\n * one column below 768px). `inverted` is passed on to the `items` tiles; slotted tiles need their\n * own `inverted` attribute.\n *\n * @cssprop --st-features-section-padding - Overrides the section's padding.\n */\n@customElement('st-features-section')\nexport class FeaturesSection extends LitElement {\n static styles = css`\n ${controlBaseStyles}\n\n :host {\n display: block;\n ${fontFamilyStyles}\n /* !important: a page-level reset (e.g. Tailwind Preflight) otherwise zeroes a shadow host's\n padding; override with --st-features-section-padding instead. */\n padding: var(--st-features-section-padding, var(--st-cms-section-padding) var(--st-space-24)) !important;\n background: var(--st-color-surface);\n }\n\n :host([inverted]) {\n background: var(--st-color-text-strong);\n }\n\n .container {\n max-width: var(--st-cms-container-max);\n margin: 0 auto;\n }\n\n .header {\n ${sectionHeaderStyles}\n }\n\n .title {\n ${sectionTitleStyles}\n margin: 0;\n }\n\n .subtitle {\n ${sectionSubtitleStyles}\n margin: 0 auto;\n }\n\n :host([inverted]) .title,\n :host([inverted]) .subtitle {\n color: var(--st-color-on-solid);\n }\n\n .grid {\n display: grid;\n grid-template-columns: repeat(var(--features-columns, 2), 1fr);\n gap: var(--st-space-32);\n }\n\n @media (max-width: 768px) {\n :host {\n padding: var(--st-features-section-padding, var(--st-space-48) var(--st-space-16)) !important;\n }\n\n .grid {\n grid-template-columns: 1fr;\n }\n }\n `;\n\n @property({ type: String })\n title = '';\n\n @property({ type: String })\n subtitle = '';\n\n /** Applied to every tile built from `items`. */\n @property({ type: String, attribute: 'action-label' })\n actionLabel = 'Learn more';\n\n @property({ type: Number })\n columns = 0;\n\n @property({ type: Boolean, reflect: true })\n inverted = false;\n\n /** Tiles to render (property only). */\n @property({ attribute: false })\n items: FeatureItemData[] = [];\n\n render() {\n const gridStyle = this.columns ? `--features-columns: ${this.columns}` : nothing;\n return html`\n <section class=\"container\" part=\"container\">\n <div class=\"header\" part=\"header\">\n <div class=\"title\" part=\"title\">${this.title}</div>\n ${this.subtitle ? html`<div class=\"subtitle\" part=\"subtitle\">${this.subtitle}</div>` : nothing}\n </div>\n <div class=\"grid\" part=\"grid\" style=${gridStyle}>\n <slot></slot>\n ${this.items.map(\n (item) => html`\n <st-feature-item\n .icon=${item.icon ?? ''}\n .title=${item.title}\n .description=${item.description}\n .href=${item.href ?? ''}\n .actionLabel=${this.actionLabel}\n ?inverted=${this.inverted}\n ></st-feature-item>\n `\n )}\n </div>\n </section>\n `;\n }\n}\n","import { LitElement, css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport 'iconify-icon';\n\nimport { controlBaseStyles, fontFamilyStyles } from '../shared/styles';\nimport { cardDescriptionStyles, cardTitleStyles } from '../shared/section-styles';\nimport '../card';\nimport '../markdown';\n\n/**\n * One feature tile for `st-features-section`: optional icon, title, Markdown description and an\n * optional \"Learn more\" link, rendered on an `st-card`. `icon` is an Iconify name (e.g.\n * `mdi:rocket`). The link is a plain `<a>` (the source used react-router's `Link` for non-http\n * hrefs; there is no Lit equivalent). The click is composed, so an SPA router can intercept it\n * (e.g. via `event.composedPath()`) and navigate client-side; `http(s)` links open in a new tab.\n */\n@customElement('st-feature-item')\nexport class FeatureItem extends LitElement {\n static styles = css`\n ${controlBaseStyles}\n\n :host {\n display: block;\n ${fontFamilyStyles}\n }\n\n st-card {\n height: 100%;\n }\n\n .content {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: var(--st-space-16);\n height: 100%;\n }\n\n .icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n border-radius: var(--st-radius-lg);\n background: var(--st-color-subtle);\n color: var(--st-color-text-strong);\n margin-bottom: var(--st-space-8);\n font-size: 24px;\n }\n\n :host([inverted]) .icon {\n background: var(--st-color-text-muted);\n color: var(--st-color-on-solid);\n }\n\n .title {\n ${cardTitleStyles}\n margin: 0;\n }\n\n .description {\n ${cardDescriptionStyles}\n margin: 0;\n }\n\n :host([inverted]) .title,\n :host([inverted]) .description {\n color: inherit;\n }\n\n .link {\n display: flex;\n align-items: center;\n gap: var(--st-space-4);\n margin-top: auto;\n color: var(--st-color-text-muted);\n font-weight: var(--st-font-weight-medium);\n font-size: var(--st-text-md);\n text-decoration: none;\n transition: color 0.2s ease;\n }\n\n .link:hover {\n color: var(--st-color-text-strong);\n text-decoration: underline;\n }\n\n :host([inverted]) .link,\n :host([inverted]) .link:hover {\n color: inherit;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .link {\n transition: none;\n }\n }\n `;\n\n /** Iconify icon name, e.g. `mdi:rocket`. */\n @property({ type: String })\n icon = '';\n\n @property({ type: String })\n title = '';\n\n /** Markdown. */\n @property({ type: String })\n description = '';\n\n @property({ type: String })\n href = '';\n\n @property({ type: String, attribute: 'action-label' })\n actionLabel = 'Learn more';\n\n @property({ type: Boolean, reflect: true })\n inverted = false;\n\n render() {\n const external = this.href.startsWith('http');\n return html`\n <st-card hoverable elevation=\"sm\" ?inverted=${this.inverted} part=\"card\">\n <div class=\"content\" part=\"content\">\n ${this.icon\n ? html`<div class=\"icon\" part=\"icon\"><iconify-icon icon=${this.icon}></iconify-icon></div>`\n : nothing}\n <h3 class=\"title\" part=\"title\">${this.title}</h3>\n <st-markdown class=\"description\" part=\"description\" .content=${this.description}></st-markdown>\n ${this.href\n ? html`\n <a\n class=\"link\"\n part=\"link\"\n href=${this.href}\n target=${external ? '_blank' : '_self'}\n rel=${external ? 'noopener noreferrer' : nothing}\n >\n ${this.actionLabel} <span>&rarr;</span>\n </a>\n `\n : nothing}\n </div>\n </st-card>\n `;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA,SAAS,cAAAA,aAAY,OAAAC,MAAK,QAAAC,OAAM,WAAAC,gBAAe;AAC/C,SAAS,iBAAAC,gBAAe,YAAAC,iBAAgB;;;ACDxC,SAAS,YAAY,KAAK,MAAM,eAAe;AAC/C,SAAS,eAAe,gBAAgB;AACxC,OAAO;AAeA,IAAM,cAAN,cAA0B,WAAW;AAAA,EAArC;AAAA;AAqFL,gBAAO;AAGP,iBAAQ;AAIR,uBAAc;AAGd,gBAAO;AAGP,uBAAc;AAGd,oBAAW;AAAA;AAAA,EAEX,SAAS;AACP,UAAM,WAAW,KAAK,KAAK,WAAW,MAAM;AAC5C,WAAO;AAAA,oDACyC,KAAK,QAAQ;AAAA;AAAA,YAErD,KAAK,OACH,wDAAwD,KAAK,IAAI,2BACjE,OAAO;AAAA,2CACsB,KAAK,KAAK;AAAA,yEACoB,KAAK,WAAW;AAAA,YAC7E,KAAK,OACH;AAAA;AAAA;AAAA;AAAA,yBAIW,KAAK,IAAI;AAAA,2BACP,WAAW,WAAW,OAAO;AAAA,wBAChC,WAAW,wBAAwB,OAAO;AAAA;AAAA,oBAE9C,KAAK,WAAW;AAAA;AAAA,kBAGtB,OAAO;AAAA;AAAA;AAAA;AAAA,EAInB;AACF;AAlIa,YACJ,SAAS;AAAA,MACZ,iBAAiB;AAAA;AAAA;AAAA;AAAA,QAIf,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAkChB,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA,QAKf,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwC3B;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GApFf,YAqFX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GAvFf,YAwFX;AAIA;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GA3Ff,YA4FX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GA9Ff,YA+FX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,QAAQ,WAAW,eAAe,CAAC;AAAA,GAjG1C,YAkGX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,SAAS,KAAK,CAAC;AAAA,GApG/B,YAqGX;AArGW,cAAN;AAAA,EADN,cAAc,iBAAiB;AAAA,GACnB;;;ADON,IAAM,kBAAN,cAA8BC,YAAW;AAAA,EAAzC;AAAA;AA2DL,iBAAQ;AAGR,oBAAW;AAIX,uBAAc;AAGd,mBAAU;AAGV,oBAAW;AAIX,iBAA2B,CAAC;AAAA;AAAA,EAE5B,SAAS;AACP,UAAM,YAAY,KAAK,UAAU,uBAAuB,KAAK,OAAO,KAAKC;AACzE,WAAOC;AAAA;AAAA;AAAA,4CAGiC,KAAK,KAAK;AAAA,YAC1C,KAAK,WAAWA,8CAA6C,KAAK,QAAQ,WAAWD,QAAO;AAAA;AAAA,8CAE1D,SAAS;AAAA;AAAA,YAE3C,KAAK,MAAM;AAAA,MACX,CAAC,SAASC;AAAA;AAAA,wBAEE,KAAK,QAAQ,EAAE;AAAA,yBACd,KAAK,KAAK;AAAA,+BACJ,KAAK,WAAW;AAAA,wBACvB,KAAK,QAAQ,EAAE;AAAA,+BACR,KAAK,WAAW;AAAA,4BACnB,KAAK,QAAQ;AAAA;AAAA;AAAA,IAG/B,CAAC;AAAA;AAAA;AAAA;AAAA,EAIT;AACF;AAxGa,gBACJ,SAASC;AAAA,MACZ,iBAAiB;AAAA;AAAA;AAAA;AAAA,QAIf,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAiBhB,mBAAmB;AAAA;AAAA;AAAA;AAAA,QAInB,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA,QAKlB,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2B3B;AAAA,EADCC,UAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GA1Df,gBA2DX;AAGA;AAAA,EADCA,UAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GA7Df,gBA8DX;AAIA;AAAA,EADCA,UAAS,EAAE,MAAM,QAAQ,WAAW,eAAe,CAAC;AAAA,GAjE1C,gBAkEX;AAGA;AAAA,EADCA,UAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GApEf,gBAqEX;AAGA;AAAA,EADCA,UAAS,EAAE,MAAM,SAAS,SAAS,KAAK,CAAC;AAAA,GAvE/B,gBAwEX;AAIA;AAAA,EADCA,UAAS,EAAE,WAAW,MAAM,CAAC;AAAA,GA3EnB,gBA4EX;AA5EW,kBAAN;AAAA,EADNC,eAAc,qBAAqB;AAAA,GACvB;","names":["LitElement","css","html","nothing","customElement","property","LitElement","nothing","html","css","property","customElement"]}
@@ -1,3 +1,6 @@
1
+ import {
2
+ renderMarkdown
3
+ } from "./chunk-UAIUBPDN.js";
1
4
  import {
2
5
  reducedMotionStyles,
3
6
  sectionHeaderStyles,
@@ -16,6 +19,7 @@ import {
16
19
  // src/items-accordion/ItemsAccordion.ts
17
20
  import { LitElement, css, html, nothing } from "lit";
18
21
  import { customElement, property, state } from "lit/decorators.js";
22
+ import { unsafeHTML } from "lit/directives/unsafe-html.js";
19
23
  import "iconify-icon";
20
24
  var ItemsAccordion = class extends LitElement {
21
25
  constructor() {
@@ -24,8 +28,14 @@ var ItemsAccordion = class extends LitElement {
24
28
  this.subtitle = "";
25
29
  this.items = [];
26
30
  this.allowMultiple = false;
31
+ this.openFirst = false;
27
32
  this.openIds = /* @__PURE__ */ new Set();
28
33
  }
34
+ willUpdate(changed) {
35
+ if (this.openFirst && (changed.has("items") || changed.has("openFirst")) && this.openIds.size === 0 && this.items.length) {
36
+ this.openIds = /* @__PURE__ */ new Set([this.items[0].id]);
37
+ }
38
+ }
29
39
  toggle(id) {
30
40
  const wasOpen = this.openIds.has(id);
31
41
  const next = new Set(this.allowMultiple ? this.openIds : []);
@@ -65,7 +75,7 @@ var ItemsAccordion = class extends LitElement {
65
75
  </button>
66
76
  <div class="content" id="content-${item.id}" part="content" role="region" ?inert=${!open}>
67
77
  <div class="content-clip">
68
- <div class="content-inner">${item.content}</div>
78
+ <div class="content-inner">${unsafeHTML(renderMarkdown(item.content))}</div>
69
79
  </div>
70
80
  </div>
71
81
  </div>
@@ -180,6 +190,24 @@ ItemsAccordion.styles = css`
180
190
  line-height: 1.6;
181
191
  }
182
192
 
193
+ .content-inner > :first-child {
194
+ margin-top: 0;
195
+ }
196
+
197
+ .content-inner > :last-child {
198
+ margin-bottom: 0;
199
+ }
200
+
201
+ .content-inner p {
202
+ margin: 0 0 var(--st-space-12);
203
+ }
204
+
205
+ .content-inner a {
206
+ color: inherit;
207
+ text-decoration: underline;
208
+ text-underline-offset: 3px;
209
+ }
210
+
183
211
  @media (max-width: 768px) {
184
212
  :host {
185
213
  padding: var(--st-items-accordion-padding, var(--st-space-48) var(--st-space-20)) !important;
@@ -204,6 +232,9 @@ __decorateClass([
204
232
  __decorateClass([
205
233
  property({ type: Boolean, attribute: "allow-multiple" })
206
234
  ], ItemsAccordion.prototype, "allowMultiple", 2);
235
+ __decorateClass([
236
+ property({ type: Boolean, attribute: "open-first" })
237
+ ], ItemsAccordion.prototype, "openFirst", 2);
207
238
  __decorateClass([
208
239
  state()
209
240
  ], ItemsAccordion.prototype, "openIds", 2);
@@ -214,4 +245,4 @@ ItemsAccordion = __decorateClass([
214
245
  export {
215
246
  ItemsAccordion
216
247
  };
217
- //# sourceMappingURL=chunk-ALI26WOB.js.map
248
+ //# sourceMappingURL=chunk-EE6PAN3B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/items-accordion/ItemsAccordion.ts"],"sourcesContent":["import { LitElement, css, html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\nimport 'iconify-icon';\n\nimport { buttonResetStyles, controlBaseStyles, fontFamilyStyles } from '../shared/styles';\nimport { renderMarkdown } from '../shared/markdown';\nimport {\n reducedMotionStyles,\n sectionHeaderStyles,\n sectionSubtitleStyles,\n sectionTitleStyles,\n} from '../shared/section-styles';\nimport type { AccordionToggleEventDetail } from './ItemsAccordionEvents';\n\nexport interface AccordionItem {\n id: string;\n title: string;\n /** Markdown (plain text works too). */\n content: string;\n}\n\n/**\n * A vertical list of collapsible title/content rows; one open at a time unless `allow-multiple`.\n * Each row's `content` is Markdown, sanitized. `open-first` starts with the first row open.\n *\n * @cssprop --st-items-accordion-padding - Overrides the block's padding.\n */\n@customElement('st-items-accordion')\nexport class ItemsAccordion extends LitElement {\n static styles = css`\n ${controlBaseStyles}\n\n :host {\n display: block;\n /* !important: a page-level reset (e.g. Tailwind Preflight) otherwise zeroes a shadow host's\n padding; override with --st-items-accordion-padding instead. */\n padding: var(--st-items-accordion-padding, var(--st-cms-section-padding) var(--st-space-24)) !important;\n background: var(--st-color-page);\n ${fontFamilyStyles}\n }\n\n .container {\n max-width: 800px;\n margin: 0 auto;\n }\n\n .header {\n ${sectionHeaderStyles}\n }\n\n .title {\n ${sectionTitleStyles}\n font-size: var(--st-text-2xl);\n margin-bottom: var(--st-space-12);\n }\n\n .subtitle {\n ${sectionSubtitleStyles}\n font-size: var(--st-text-base);\n margin: 0;\n }\n\n .list {\n display: flex;\n flex-direction: column;\n gap: var(--st-space-16);\n }\n\n .item {\n border: 1px solid var(--st-color-border);\n border-radius: var(--st-radius-lg);\n background: var(--st-color-surface);\n overflow: hidden;\n transition:\n border-color 0.2s ease,\n box-shadow 0.2s ease;\n }\n\n .item.open {\n border-color: var(--st-color-border-strong);\n box-shadow: 0 4px 6px -1px var(--st-shadow-color-sm);\n }\n\n .trigger {\n ${buttonResetStyles}\n width: 100%;\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: var(--st-space-24);\n text-align: left;\n font-size: var(--st-text-lg);\n font-weight: var(--st-font-weight-semibold);\n color: var(--st-color-text-strong);\n }\n\n .trigger:hover {\n background: var(--st-color-hover);\n }\n\n .chevron {\n flex-shrink: 0;\n margin-left: var(--st-space-16);\n font-size: 24px;\n color: var(--st-color-text-faint);\n transition: transform 0.3s ease;\n }\n\n .open .chevron {\n transform: rotate(180deg);\n }\n\n .content {\n display: grid;\n grid-template-rows: 0fr;\n transition: grid-template-rows 0.3s ease;\n }\n\n .open .content {\n grid-template-rows: 1fr;\n }\n\n .content-clip {\n overflow: hidden;\n min-height: 0;\n }\n\n .content-inner {\n padding: 0 var(--st-space-24) var(--st-space-24);\n color: var(--st-color-text);\n line-height: 1.6;\n }\n\n .content-inner > :first-child {\n margin-top: 0;\n }\n\n .content-inner > :last-child {\n margin-bottom: 0;\n }\n\n .content-inner p {\n margin: 0 0 var(--st-space-12);\n }\n\n .content-inner a {\n color: inherit;\n text-decoration: underline;\n text-underline-offset: 3px;\n }\n\n @media (max-width: 768px) {\n :host {\n padding: var(--st-items-accordion-padding, var(--st-space-48) var(--st-space-20)) !important;\n }\n\n .title {\n font-size: var(--st-text-xl);\n }\n }\n\n ${reducedMotionStyles}\n `;\n\n @property({ type: String })\n title = '';\n\n @property({ type: String })\n subtitle = '';\n\n @property({ attribute: false })\n items: AccordionItem[] = [];\n\n @property({ type: Boolean, attribute: 'allow-multiple' })\n allowMultiple = false;\n\n /** Starts with the first row open. Applies when `items` or this flag changes while nothing is open. */\n @property({ type: Boolean, attribute: 'open-first' })\n openFirst = false;\n\n @state() private openIds = new Set<string>();\n\n protected willUpdate(changed: Map<string, unknown>): void {\n if (this.openFirst && (changed.has('items') || changed.has('openFirst')) && this.openIds.size === 0 && this.items.length) {\n this.openIds = new Set([this.items[0].id]);\n }\n }\n\n private toggle(id: string) {\n const wasOpen = this.openIds.has(id);\n const next = new Set(this.allowMultiple ? this.openIds : []);\n if (wasOpen) next.delete(id);\n else next.add(id);\n this.openIds = next;\n this.dispatchEvent(\n new CustomEvent<AccordionToggleEventDetail>('accordion-toggle', {\n detail: { id, open: !wasOpen },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n render() {\n return html`\n <div class=\"container\" part=\"container\">\n ${this.title || this.subtitle\n ? html`<div class=\"header\" part=\"header\">\n ${this.title ? html`<h2 class=\"title\" part=\"title\">${this.title}</h2>` : nothing}\n ${this.subtitle ? html`<p class=\"subtitle\" part=\"subtitle\">${this.subtitle}</p>` : nothing}\n </div>`\n : nothing}\n <div class=\"list\" part=\"list\">\n ${this.items.map((item) => {\n const open = this.openIds.has(item.id);\n return html`\n <div class=\"item ${open ? 'open' : ''}\" part=\"item\">\n <button\n class=\"trigger\"\n part=\"trigger\"\n type=\"button\"\n aria-expanded=${open ? 'true' : 'false'}\n aria-controls=\"content-${item.id}\"\n @click=${() => this.toggle(item.id)}\n >\n <span>${item.title}</span>\n <iconify-icon class=\"chevron\" icon=\"mdi:chevron-down\"></iconify-icon>\n </button>\n <div class=\"content\" id=\"content-${item.id}\" part=\"content\" role=\"region\" ?inert=${!open}>\n <div class=\"content-clip\">\n <div class=\"content-inner\">${unsafeHTML(renderMarkdown(item.content))}</div>\n </div>\n </div>\n </div>\n `;\n })}\n </div>\n </div>\n `;\n }\n}\n"],"mappings":"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","names":[]}
@@ -23,12 +23,24 @@ var PromoBanner = class extends LitElement {
23
23
  this.actionLabel = "";
24
24
  this.href = "";
25
25
  this.imageSrc = "";
26
+ this.secondaryActionLabel = "";
27
+ this.secondaryHref = "";
28
+ this.variant = "default";
26
29
  this.inverted = false;
27
30
  this.onAction = () => {
28
31
  this.dispatchEvent(
29
32
  new CustomEvent("action", { detail: { href: this.href }, bubbles: true, composed: true })
30
33
  );
31
34
  };
35
+ this.onSecondaryAction = () => {
36
+ this.dispatchEvent(
37
+ new CustomEvent("action", {
38
+ detail: { href: this.secondaryHref, kind: "secondary" },
39
+ bubbles: true,
40
+ composed: true
41
+ })
42
+ );
43
+ };
32
44
  }
33
45
  willUpdate() {
34
46
  this.style.backgroundImage = this.imageSrc ? `url(${JSON.stringify(this.imageSrc)})` : "";
@@ -39,8 +51,9 @@ var PromoBanner = class extends LitElement {
39
51
  <h2 class="title" part="title">${this.title}</h2>
40
52
  ${this.subtitle ? html`<p class="subtitle" part="subtitle">${this.subtitle}</p>` : nothing}
41
53
  <slot></slot>
42
- ${this.actionLabel ? html`<div class="actions" part="actions">
43
- <button class="cta" part="action" type="button" @click=${this.onAction}>${this.actionLabel}</button>
54
+ ${this.actionLabel || this.secondaryActionLabel ? html`<div class="actions" part="actions">
55
+ ${this.actionLabel ? html`<button class="cta" part="action" type="button" @click=${this.onAction}>${this.actionLabel}</button>` : nothing}
56
+ ${this.secondaryActionLabel ? html`<button class="cta secondary" part="secondary-action" type="button" @click=${this.onSecondaryAction}>${this.secondaryActionLabel}</button>` : nothing}
44
57
  </div>` : nothing}
45
58
  </div>
46
59
  `;
@@ -67,6 +80,17 @@ PromoBanner.styles = css`
67
80
  ${rootFontFamilyStyles}
68
81
  }
69
82
 
83
+ :host([variant='accent']) {
84
+ background-color: var(--st-color-accent);
85
+ color: var(--st-cms-on-dark);
86
+ }
87
+
88
+ :host([variant='accent']) .cta:not(.secondary) {
89
+ background: var(--st-cms-on-dark);
90
+ border-color: transparent;
91
+ color: var(--st-cms-navy);
92
+ }
93
+
70
94
  :host([inverted]) {
71
95
  background-color: var(--st-color-subtle);
72
96
  color: var(--st-color-text-strong);
@@ -96,6 +120,10 @@ PromoBanner.styles = css`
96
120
  }
97
121
 
98
122
  .actions {
123
+ display: flex;
124
+ flex-wrap: wrap;
125
+ justify-content: center;
126
+ gap: var(--st-space-12);
99
127
  margin-top: var(--st-space-16);
100
128
  }
101
129
 
@@ -110,6 +138,11 @@ PromoBanner.styles = css`
110
138
  transform: scale(1.05);
111
139
  }
112
140
 
141
+ .cta:focus-visible {
142
+ outline: var(--st-focus-ring);
143
+ outline-offset: 2px;
144
+ }
145
+
113
146
  @media (max-width: 768px) {
114
147
  :host {
115
148
  width: auto;
@@ -117,7 +150,10 @@ PromoBanner.styles = css`
117
150
  padding: var(--st-promo-banner-padding, 60px var(--st-space-24)) !important;
118
151
  border-radius: var(--st-radius-lg);
119
152
  }
120
- .actions,
153
+ .actions {
154
+ flex-direction: column;
155
+ align-items: stretch;
156
+ }
121
157
  .cta {
122
158
  width: 100%;
123
159
  }
@@ -144,6 +180,15 @@ __decorateClass([
144
180
  __decorateClass([
145
181
  property({ type: String, attribute: "image-src" })
146
182
  ], PromoBanner.prototype, "imageSrc", 2);
183
+ __decorateClass([
184
+ property({ type: String, attribute: "secondary-action-label" })
185
+ ], PromoBanner.prototype, "secondaryActionLabel", 2);
186
+ __decorateClass([
187
+ property({ type: String, attribute: "secondary-href" })
188
+ ], PromoBanner.prototype, "secondaryHref", 2);
189
+ __decorateClass([
190
+ property({ type: String, reflect: true })
191
+ ], PromoBanner.prototype, "variant", 2);
147
192
  __decorateClass([
148
193
  property({ type: Boolean, reflect: true })
149
194
  ], PromoBanner.prototype, "inverted", 2);
@@ -154,4 +199,4 @@ PromoBanner = __decorateClass([
154
199
  export {
155
200
  PromoBanner
156
201
  };
157
- //# sourceMappingURL=chunk-VWS53WY4.js.map
202
+ //# sourceMappingURL=chunk-HMUZON6I.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/promo-banner/PromoBanner.ts"],"sourcesContent":["import { LitElement, css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\nimport { buttonResetStyles, controlBaseStyles, rootFontFamilyStyles } from '../shared/styles';\nimport { ctaLinkStyles, sectionSubtitleStyles, sectionTitleStyles } from '../shared/section-styles';\nimport type { HeroActionEventDetail } from '../hero/HeroEvents';\n\n/**\n * Rounded call-to-action banner (title, subtitle, one or two outlined buttons) on a dark panel or a\n * background image. The buttons fire an `action` event\n * (detail `{ href }`, empty unless set; the secondary button adds `kind: 'secondary'`).\n * `onAction`. `variant=\"accent\"` fills the banner with the brand colour.\n *\n * @fires action - Detail `{ href, kind? }`. `kind` is `secondary` for the second button only.\n * @cssprop --st-promo-banner-margin - Overrides the banner's margin.\n * @cssprop --st-promo-banner-padding - Overrides the banner's padding.\n * @csspart action - The primary button.\n * @csspart secondary-action - The second button.\n */\n@customElement('st-promo-banner')\nexport class PromoBanner extends LitElement {\n static styles = css`\n ${controlBaseStyles}\n\n :host {\n display: block;\n box-sizing: border-box;\n width: calc(100% - 48px);\n max-width: var(--st-cms-container-max);\n /* !important: a page-level reset (e.g. Tailwind Preflight) otherwise zeroes a shadow host's\n margin/padding; override with --st-promo-banner-margin/-padding instead. */\n margin: var(--st-promo-banner-margin, var(--st-space-40) auto) !important;\n padding: var(--st-promo-banner-padding, 100px var(--st-space-24)) !important;\n border-radius: var(--st-space-24);\n background-color: var(--st-color-text-strong);\n background-size: cover;\n background-position: center;\n color: var(--st-color-on-solid);\n text-align: center;\n ${rootFontFamilyStyles}\n }\n\n :host([variant='accent']) {\n background-color: var(--st-color-accent);\n color: var(--st-cms-on-dark);\n }\n\n :host([variant='accent']) .cta:not(.secondary) {\n background: var(--st-cms-on-dark);\n border-color: transparent;\n color: var(--st-cms-navy);\n }\n\n :host([inverted]) {\n background-color: var(--st-color-subtle);\n color: var(--st-color-text-strong);\n }\n\n .container {\n max-width: 800px;\n margin: 0 auto;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--st-space-32);\n }\n\n .title {\n ${sectionTitleStyles}\n color: inherit;\n margin: 0;\n letter-spacing: -0.02em;\n }\n\n .subtitle {\n ${sectionSubtitleStyles}\n color: inherit;\n opacity: 0.8;\n margin: 0;\n }\n\n .actions {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: var(--st-space-12);\n margin-top: var(--st-space-16);\n }\n\n .cta {\n ${buttonResetStyles}\n ${ctaLinkStyles}\n border: 1px solid currentColor;\n color: inherit;\n }\n\n .cta:hover {\n transform: scale(1.05);\n }\n\n .cta:focus-visible {\n outline: var(--st-focus-ring);\n outline-offset: 2px;\n }\n\n @media (max-width: 768px) {\n :host {\n width: auto;\n margin: var(--st-promo-banner-margin, var(--st-space-24)) !important;\n padding: var(--st-promo-banner-padding, 60px var(--st-space-24)) !important;\n border-radius: var(--st-radius-lg);\n }\n .actions {\n flex-direction: column;\n align-items: stretch;\n }\n .cta {\n width: 100%;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .cta {\n transition: none;\n }\n }\n `;\n\n @property({ type: String })\n title = '';\n\n @property({ type: String })\n subtitle = '';\n\n @property({ type: String, attribute: 'action-label' })\n actionLabel = '';\n\n @property({ type: String })\n href = '';\n\n @property({ type: String, attribute: 'image-src' })\n imageSrc = '';\n\n /** Label of a second, outlined button next to the first. */\n @property({ type: String, attribute: 'secondary-action-label' })\n secondaryActionLabel = '';\n\n /** Target of the second button, sent in the `action` event detail. */\n @property({ type: String, attribute: 'secondary-href' })\n secondaryHref = '';\n\n /** `default` is the dark panel; `accent` fills the banner with the brand colour and makes the first button white. */\n @property({ type: String, reflect: true })\n variant: 'default' | 'accent' = 'default';\n\n @property({ type: Boolean, reflect: true })\n inverted = false;\n\n protected willUpdate(): void {\n this.style.backgroundImage = this.imageSrc ? `url(${JSON.stringify(this.imageSrc)})` : '';\n }\n\n private onAction = (): void => {\n this.dispatchEvent(\n new CustomEvent<HeroActionEventDetail>('action', { detail: { href: this.href }, bubbles: true, composed: true })\n );\n };\n\n private onSecondaryAction = (): void => {\n this.dispatchEvent(\n new CustomEvent<HeroActionEventDetail>('action', {\n detail: { href: this.secondaryHref, kind: 'secondary' },\n bubbles: true,\n composed: true\n })\n );\n };\n\n render() {\n return html`\n <div class=\"container\" part=\"container\">\n <h2 class=\"title\" part=\"title\">${this.title}</h2>\n ${this.subtitle ? html`<p class=\"subtitle\" part=\"subtitle\">${this.subtitle}</p>` : nothing}\n <slot></slot>\n ${this.actionLabel || this.secondaryActionLabel\n ? html`<div class=\"actions\" part=\"actions\">\n ${this.actionLabel\n ? html`<button class=\"cta\" part=\"action\" type=\"button\" @click=${this.onAction}>${this.actionLabel}</button>`\n : nothing}\n ${this.secondaryActionLabel\n ? html`<button class=\"cta secondary\" part=\"secondary-action\" type=\"button\" @click=${this.onSecondaryAction}>${this.secondaryActionLabel}</button>`\n : nothing}\n </div>`\n : nothing}\n </div>\n `;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAAA,SAAS,YAAY,KAAK,MAAM,eAAe;AAC/C,SAAS,eAAe,gBAAgB;AAmBjC,IAAM,cAAN,cAA0B,WAAW;AAAA,EAArC;AAAA;AA6GL,iBAAQ;AAGR,oBAAW;AAGX,uBAAc;AAGd,gBAAO;AAGP,oBAAW;AAIX,gCAAuB;AAIvB,yBAAgB;AAIhB,mBAAgC;AAGhC,oBAAW;AAMX,SAAQ,WAAW,MAAY;AAC7B,WAAK;AAAA,QACH,IAAI,YAAmC,UAAU,EAAE,QAAQ,EAAE,MAAM,KAAK,KAAK,GAAG,SAAS,MAAM,UAAU,KAAK,CAAC;AAAA,MACjH;AAAA,IACF;AAEA,SAAQ,oBAAoB,MAAY;AACtC,WAAK;AAAA,QACH,IAAI,YAAmC,UAAU;AAAA,UAC/C,QAAQ,EAAE,MAAM,KAAK,eAAe,MAAM,YAAY;AAAA,UACtD,SAAS;AAAA,UACT,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,IACF;AAAA;AAAA,EAlBU,aAAmB;AAC3B,SAAK,MAAM,kBAAkB,KAAK,WAAW,OAAO,KAAK,UAAU,KAAK,QAAQ,CAAC,MAAM;AAAA,EACzF;AAAA,EAkBA,SAAS;AACP,WAAO;AAAA;AAAA,yCAE8B,KAAK,KAAK;AAAA,UACzC,KAAK,WAAW,2CAA2C,KAAK,QAAQ,SAAS,OAAO;AAAA;AAAA,UAExF,KAAK,eAAe,KAAK,uBACvB;AAAA,gBACI,KAAK,cACH,8DAA8D,KAAK,QAAQ,IAAI,KAAK,WAAW,cAC/F,OAAO;AAAA,gBACT,KAAK,uBACH,kFAAkF,KAAK,iBAAiB,IAAI,KAAK,oBAAoB,cACrI,OAAO;AAAA,sBAEb,OAAO;AAAA;AAAA;AAAA,EAGjB;AACF;AAjLa,YACJ,SAAS;AAAA,MACZ,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAiBf,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QA6BpB,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOlB,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAerB,iBAAiB;AAAA,QACjB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsCnB;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GA5Gf,YA6GX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GA/Gf,YAgHX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,QAAQ,WAAW,eAAe,CAAC;AAAA,GAlH1C,YAmHX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GArHf,YAsHX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,QAAQ,WAAW,YAAY,CAAC;AAAA,GAxHvC,YAyHX;AAIA;AAAA,EADC,SAAS,EAAE,MAAM,QAAQ,WAAW,yBAAyB,CAAC;AAAA,GA5HpD,YA6HX;AAIA;AAAA,EADC,SAAS,EAAE,MAAM,QAAQ,WAAW,iBAAiB,CAAC;AAAA,GAhI5C,YAiIX;AAIA;AAAA,EADC,SAAS,EAAE,MAAM,QAAQ,SAAS,KAAK,CAAC;AAAA,GApI9B,YAqIX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,SAAS,KAAK,CAAC;AAAA,GAvI/B,YAwIX;AAxIW,cAAN;AAAA,EADN,cAAc,iBAAiB;AAAA,GACnB;","names":[]}
@@ -0,0 +1,178 @@
1
+ import {
2
+ controlBaseStyles,
3
+ fontFamilyStyles
4
+ } from "./chunk-KMU6ABQF.js";
5
+ import {
6
+ __decorateClass
7
+ } from "./chunk-EUXUH3YW.js";
8
+
9
+ // src/flow/Flow.ts
10
+ import { LitElement, css, html, nothing, svg } from "lit";
11
+ import { customElement, property } from "lit/decorators.js";
12
+ var Flow = class extends LitElement {
13
+ constructor() {
14
+ super(...arguments);
15
+ this.nodes = [];
16
+ this.label = "";
17
+ this.inverted = false;
18
+ }
19
+ arrow() {
20
+ return svg`<svg class="arrow" part="arrow" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
21
+ <path d="M5 12h13m-5-5 5 5-5 5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
22
+ </svg>`;
23
+ }
24
+ render() {
25
+ const last = this.nodes.length - 1;
26
+ return html`
27
+ <ol class="flow" part="flow" aria-label=${this.label || nothing}>
28
+ ${this.nodes.map(
29
+ (node, index) => html`
30
+ <li class="step">
31
+ <div class="node ${node.variant ?? "solid"}" part="node">
32
+ <p class="label" part="label">${node.label}</p>
33
+ ${node.caption ? html`<p class="caption" part="caption">${node.caption}</p>` : nothing}
34
+ </div>
35
+ ${index < last ? this.arrow() : nothing}
36
+ </li>
37
+ `
38
+ )}
39
+ </ol>
40
+ `;
41
+ }
42
+ };
43
+ Flow.styles = css`
44
+ ${controlBaseStyles}
45
+ ${fontFamilyStyles}
46
+
47
+ :host {
48
+ display: block;
49
+ box-sizing: border-box;
50
+ /* !important: a page-level reset (e.g. Tailwind Preflight) otherwise zeroes a shadow host's
51
+ padding; override with --st-flow-padding instead. */
52
+ padding: var(--st-flow-padding, var(--st-space-40) var(--st-space-24)) !important;
53
+ background: var(--st-color-page);
54
+ }
55
+
56
+ :host([inverted]) {
57
+ background: var(--st-cms-band-dark-bg);
58
+ }
59
+
60
+ .flow {
61
+ display: flex;
62
+ align-items: stretch;
63
+ max-width: var(--st-cms-container-max);
64
+ margin: 0 auto;
65
+ padding: 0;
66
+ list-style: none;
67
+ }
68
+
69
+ .step {
70
+ display: flex;
71
+ align-items: center;
72
+ flex: 1 1 0;
73
+ min-width: 0;
74
+ margin: 0;
75
+ }
76
+
77
+ .node {
78
+ display: flex;
79
+ flex: 1 1 auto;
80
+ flex-direction: column;
81
+ justify-content: center;
82
+ gap: var(--st-space-4);
83
+ box-sizing: border-box;
84
+ min-width: 0;
85
+ min-height: 84px;
86
+ padding: var(--st-space-16) var(--st-space-20);
87
+ border: 1.5px solid transparent;
88
+ border-radius: var(--st-radius-lg);
89
+ text-align: center;
90
+ overflow-wrap: anywhere;
91
+ }
92
+
93
+ .label {
94
+ margin: 0;
95
+ font-size: var(--st-text-lg);
96
+ font-weight: var(--st-font-weight-bold);
97
+ line-height: 1.3;
98
+ }
99
+
100
+ .caption {
101
+ margin: 0;
102
+ font-size: var(--st-text-sm);
103
+ line-height: 1.5;
104
+ opacity: 0.85;
105
+ }
106
+
107
+ .node.solid {
108
+ background: var(--st-button-primary-bg);
109
+ color: var(--st-button-primary-color);
110
+ }
111
+
112
+ .node.outline {
113
+ background: var(--st-color-surface);
114
+ border-color: var(--st-color-accent);
115
+ border-style: dashed;
116
+ color: var(--st-color-text-strong);
117
+ }
118
+
119
+ .node.accent {
120
+ background: var(--st-cms-highlight);
121
+ color: var(--st-cms-navy);
122
+ }
123
+
124
+ .arrow {
125
+ flex: 0 0 auto;
126
+ width: 24px;
127
+ height: 24px;
128
+ margin: 0 var(--st-space-8);
129
+ color: var(--st-color-text-faint);
130
+ }
131
+
132
+ /* inverted: outlined boxes take the cyan highlight so the dashed edge reads on navy. */
133
+ :host([inverted]) .node.outline {
134
+ background: transparent;
135
+ border-color: var(--st-cms-highlight);
136
+ color: var(--st-cms-band-dark-color);
137
+ }
138
+
139
+ :host([inverted]) .arrow {
140
+ color: color-mix(in oklch, var(--st-cms-band-dark-color) 60%, transparent);
141
+ }
142
+
143
+ @media (max-width: 600px) {
144
+ :host {
145
+ padding: var(--st-flow-padding, var(--st-space-32) var(--st-space-20)) !important;
146
+ }
147
+ .flow {
148
+ flex-direction: column;
149
+ }
150
+ .step {
151
+ flex: 0 0 auto;
152
+ flex-direction: column;
153
+ align-items: stretch;
154
+ }
155
+ .arrow {
156
+ align-self: center;
157
+ transform: rotate(90deg);
158
+ margin: var(--st-space-4) 0;
159
+ }
160
+ }
161
+ `;
162
+ __decorateClass([
163
+ property({ attribute: false })
164
+ ], Flow.prototype, "nodes", 2);
165
+ __decorateClass([
166
+ property({ type: String })
167
+ ], Flow.prototype, "label", 2);
168
+ __decorateClass([
169
+ property({ type: Boolean, reflect: true })
170
+ ], Flow.prototype, "inverted", 2);
171
+ Flow = __decorateClass([
172
+ customElement("st-flow")
173
+ ], Flow);
174
+
175
+ export {
176
+ Flow
177
+ };
178
+ //# sourceMappingURL=chunk-O4FCRKDX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/flow/Flow.ts"],"sourcesContent":["import { LitElement, css, html, nothing, svg } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\nimport { controlBaseStyles, fontFamilyStyles } from '../shared/styles';\n\nexport interface FlowNode {\n label: string;\n caption?: string;\n /** `solid` (default, primary fill), `outline` (dashed accent border) or `accent` (cyan fill). */\n variant?: 'solid' | 'outline' | 'accent';\n}\n\n/**\n * A left-to-right process or architecture flow: boxes joined by arrows. Boxes come in three looks\n * (`solid`, `outline`, `accent`); the arrows are decorative (`aria-hidden`), and the list is exposed\n * as an ordered list. Below 600px the row stacks vertically and the arrows point down.\n * `inverted` puts the flow on the dark band (`--st-cms-band-dark-bg`).\n *\n * @cssprop --st-flow-padding - Overrides the block's padding.\n * @csspart flow - The ordered list of nodes.\n * @csspart node - Each step's box (a `li`'s child).\n * @csspart label - The box's label.\n * @csspart caption - The box's caption.\n * @csspart arrow - The arrow between two boxes.\n */\n@customElement('st-flow')\nexport class Flow extends LitElement {\n static styles = css`\n ${controlBaseStyles}\n ${fontFamilyStyles}\n\n :host {\n display: block;\n box-sizing: border-box;\n /* !important: a page-level reset (e.g. Tailwind Preflight) otherwise zeroes a shadow host's\n padding; override with --st-flow-padding instead. */\n padding: var(--st-flow-padding, var(--st-space-40) var(--st-space-24)) !important;\n background: var(--st-color-page);\n }\n\n :host([inverted]) {\n background: var(--st-cms-band-dark-bg);\n }\n\n .flow {\n display: flex;\n align-items: stretch;\n max-width: var(--st-cms-container-max);\n margin: 0 auto;\n padding: 0;\n list-style: none;\n }\n\n .step {\n display: flex;\n align-items: center;\n flex: 1 1 0;\n min-width: 0;\n margin: 0;\n }\n\n .node {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n justify-content: center;\n gap: var(--st-space-4);\n box-sizing: border-box;\n min-width: 0;\n min-height: 84px;\n padding: var(--st-space-16) var(--st-space-20);\n border: 1.5px solid transparent;\n border-radius: var(--st-radius-lg);\n text-align: center;\n overflow-wrap: anywhere;\n }\n\n .label {\n margin: 0;\n font-size: var(--st-text-lg);\n font-weight: var(--st-font-weight-bold);\n line-height: 1.3;\n }\n\n .caption {\n margin: 0;\n font-size: var(--st-text-sm);\n line-height: 1.5;\n opacity: 0.85;\n }\n\n .node.solid {\n background: var(--st-button-primary-bg);\n color: var(--st-button-primary-color);\n }\n\n .node.outline {\n background: var(--st-color-surface);\n border-color: var(--st-color-accent);\n border-style: dashed;\n color: var(--st-color-text-strong);\n }\n\n .node.accent {\n background: var(--st-cms-highlight);\n color: var(--st-cms-navy);\n }\n\n .arrow {\n flex: 0 0 auto;\n width: 24px;\n height: 24px;\n margin: 0 var(--st-space-8);\n color: var(--st-color-text-faint);\n }\n\n /* inverted: outlined boxes take the cyan highlight so the dashed edge reads on navy. */\n :host([inverted]) .node.outline {\n background: transparent;\n border-color: var(--st-cms-highlight);\n color: var(--st-cms-band-dark-color);\n }\n\n :host([inverted]) .arrow {\n color: color-mix(in oklch, var(--st-cms-band-dark-color) 60%, transparent);\n }\n\n @media (max-width: 600px) {\n :host {\n padding: var(--st-flow-padding, var(--st-space-32) var(--st-space-20)) !important;\n }\n .flow {\n flex-direction: column;\n }\n .step {\n flex: 0 0 auto;\n flex-direction: column;\n align-items: stretch;\n }\n .arrow {\n align-self: center;\n transform: rotate(90deg);\n margin: var(--st-space-4) 0;\n }\n }\n `;\n\n /** The boxes, in order. */\n @property({ attribute: false })\n nodes: FlowNode[] = [];\n\n /** Accessible name for the list of steps. */\n @property({ type: String })\n label = '';\n\n /** Puts the flow on the dark band (`--st-cms-band-dark-bg`), which stays dark in the dark theme. */\n @property({ type: Boolean, reflect: true })\n inverted = false;\n\n private arrow() {\n return svg`<svg class=\"arrow\" part=\"arrow\" viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\">\n <path d=\"M5 12h13m-5-5 5 5-5 5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>`;\n }\n\n render() {\n const last = this.nodes.length - 1;\n return html`\n <ol class=\"flow\" part=\"flow\" aria-label=${this.label || nothing}>\n ${this.nodes.map(\n (node, index) => html`\n <li class=\"step\">\n <div class=\"node ${node.variant ?? 'solid'}\" part=\"node\">\n <p class=\"label\" part=\"label\">${node.label}</p>\n ${node.caption ? html`<p class=\"caption\" part=\"caption\">${node.caption}</p>` : nothing}\n </div>\n ${index < last ? this.arrow() : nothing}\n </li>\n `\n )}\n </ol>\n `;\n }\n}\n"],"mappings":";;;;;;;;;AAAA,SAAS,YAAY,KAAK,MAAM,SAAS,WAAW;AACpD,SAAS,eAAe,gBAAgB;AAyBjC,IAAM,OAAN,cAAmB,WAAW;AAAA,EAA9B;AAAA;AA2HL,iBAAoB,CAAC;AAIrB,iBAAQ;AAIR,oBAAW;AAAA;AAAA,EAEH,QAAQ;AACd,WAAO;AAAA;AAAA;AAAA,EAGT;AAAA,EAEA,SAAS;AACP,UAAM,OAAO,KAAK,MAAM,SAAS;AACjC,WAAO;AAAA,gDACqC,KAAK,SAAS,OAAO;AAAA,UAC3D,KAAK,MAAM;AAAA,MACX,CAAC,MAAM,UAAU;AAAA;AAAA,iCAEM,KAAK,WAAW,OAAO;AAAA,gDACR,KAAK,KAAK;AAAA,kBACxC,KAAK,UAAU,yCAAyC,KAAK,OAAO,SAAS,OAAO;AAAA;AAAA,gBAEtF,QAAQ,OAAO,KAAK,MAAM,IAAI,OAAO;AAAA;AAAA;AAAA,IAG7C,CAAC;AAAA;AAAA;AAAA,EAGP;AACF;AA7Ja,KACJ,SAAS;AAAA,MACZ,iBAAiB;AAAA,MACjB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwHpB;AAAA,EADC,SAAS,EAAE,WAAW,MAAM,CAAC;AAAA,GA1HnB,KA2HX;AAIA;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GA9Hf,KA+HX;AAIA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,SAAS,KAAK,CAAC;AAAA,GAlI/B,KAmIX;AAnIW,OAAN;AAAA,EADN,cAAc,SAAS;AAAA,GACX;","names":[]}
@@ -87,4 +87,4 @@ MenuGrid = __decorateClass([
87
87
  export {
88
88
  MenuGrid
89
89
  };
90
- //# sourceMappingURL=chunk-SMLR736E.js.map
90
+ //# sourceMappingURL=chunk-OELI3IWC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/menu-grid/MenuGrid.ts"],"sourcesContent":["import { LitElement, css, html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\nimport { controlBaseStyles } from '../shared/styles';\n\n/**\n * A responsive grid of `st-menu-grid-item`s — the \"rich\" nav-menu layout (icon + title +\n * description per entry, arranged in columns), typically slotted into `st-dropdown`'s default\n * slot. Markup is `.menu-grid-container` > `.menu-grid.columns-N`; breakpoints: at 768px, 2–4\n * columns become 2; at 480px, everything becomes 1 (a 1-column grid stays 1).\n */\n@customElement('st-menu-grid')\nexport class MenuGrid extends LitElement {\n static styles = css`\n ${controlBaseStyles}\n\n :host {\n display: block;\n }\n\n .menu-grid-container {\n width: 100%;\n }\n\n .menu-grid {\n display: grid;\n gap: 12px;\n }\n\n .menu-grid.columns-1 {\n grid-template-columns: repeat(1, 1fr);\n }\n\n .menu-grid.columns-2 {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .menu-grid.columns-3 {\n grid-template-columns: repeat(3, 1fr);\n }\n\n .menu-grid.columns-4 {\n grid-template-columns: repeat(4, 1fr);\n }\n\n @media (max-width: 768px) {\n .menu-grid.columns-2,\n .menu-grid.columns-3,\n .menu-grid.columns-4 {\n grid-template-columns: repeat(2, 1fr);\n }\n }\n\n @media (max-width: 480px) {\n .menu-grid.columns-1,\n .menu-grid.columns-2,\n .menu-grid.columns-3,\n .menu-grid.columns-4 {\n grid-template-columns: 1fr;\n }\n }\n `;\n\n /** Number of columns at full width (1–4, same as the source component's `columns-N` classes). */\n @property({ type: Number })\n columns = 3;\n\n /** Extra class(es) appended to the inner grid element — the source component's `gridClassName`.\n * Its outer `className` is the host element itself here: set a `class` attribute on `st-menu-grid`. */\n @property({ type: String, attribute: 'grid-class-name' })\n gridClassName = '';\n\n render() {\n const columns = Math.min(4, Math.max(1, Math.round(this.columns) || 1));\n return html`\n <div class=\"menu-grid-container\" part=\"container\">\n <div part=\"grid\" class=\"menu-grid columns-${columns} ${this.gridClassName}\">\n <slot></slot>\n </div>\n </div>\n `;\n }\n}\n"],"mappings":";;;;;;;;AAAA,SAAS,YAAY,KAAK,YAAY;AACtC,SAAS,eAAe,gBAAgB;AAWjC,IAAM,WAAN,cAAuB,WAAW;AAAA,EAAlC;AAAA;AAqDL,mBAAU;AAKV,yBAAgB;AAAA;AAAA,EAEhB,SAAS;AACP,UAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,OAAO,KAAK,CAAC,CAAC;AACtE,WAAO;AAAA;AAAA,oDAEyC,OAAO,IAAI,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,EAK/E;AACF;AAtEa,SACJ,SAAS;AAAA,MACZ,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmDrB;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GApDf,SAqDX;AAKA;AAAA,EADC,SAAS,EAAE,MAAM,QAAQ,WAAW,kBAAkB,CAAC;AAAA,GAzD7C,SA0DX;AA1DW,WAAN;AAAA,EADN,cAAc,cAAc;AAAA,GAChB;","names":[]}
@@ -309,4 +309,4 @@ MenuGridItem = __decorateClass([
309
309
  export {
310
310
  MenuGridItem
311
311
  };
312
- //# sourceMappingURL=chunk-JQY2G4QK.js.map
312
+ //# sourceMappingURL=chunk-OLA35A2O.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/menu-grid-item/MenuGridItem.ts"],"sourcesContent":["import { LitElement, css, html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\n\nimport { controlBaseStyles, fontFamilyStyles } from '../shared/styles';\nimport type { MenuGridItemSelectEventDetail } from './MenuGridItemEvents';\n\n/**\n * One entry in an `st-menu-grid` — icon (via `slot=\"icon\"`) + title on one line, an optional\n * description below, and an optional corner badge (\"New\", \"Popular\", ...). Effects are CSS:\n * fades up the first time it scrolls into view, scales to 1.02 on hover / 0.98 while pressed, the\n * icon tilts on hover, the badge pops in. Colors come from the suite theme rather than per-item\n * utility classes.\n *\n * An `http(s)` `href` opens in a new tab. Any other `href` fires a *cancelable*\n * `menu-grid-item-select` event (detail: `{ href }`) first: a host doing client-side routing calls\n * `event.preventDefault()` on it, which also cancels the anchor's own navigation.\n */\n@customElement('st-menu-grid-item')\nexport class MenuGridItem extends LitElement {\n /** `focus()` on the element focuses its link, so `st-dropdown` can arrow-key between items. */\n static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true };\n\n static styles = css`\n ${controlBaseStyles}\n\n :host {\n display: block;\n ${fontFamilyStyles}\n }\n\n @keyframes st-menu-grid-badge-pop {\n from {\n transform: scale(0);\n }\n 70% {\n transform: scale(1.12);\n }\n to {\n transform: scale(1);\n }\n }\n\n .menu-grid-item {\n display: flex;\n flex-direction: column;\n border-radius: 8px;\n position: relative;\n overflow: hidden;\n color: var(--st-color-text);\n transition:\n opacity 0.4s ease-out,\n transform 0.2s ease,\n background-color 0.2s ease;\n }\n\n .menu-grid-item.pending {\n opacity: 0;\n transform: translateY(20px);\n }\n\n .menu-grid-item.regular {\n padding: 16px;\n }\n\n .menu-grid-item.compact {\n padding: 12px;\n }\n\n /* Keyboard focus gets the same treatment as hover. */\n .menu-grid-item:hover,\n .menu-grid-item:has(.menu-grid-link:focus-visible) {\n background: var(--st-color-hover);\n transform: scale(1.02);\n }\n\n .menu-grid-item:active {\n transform: scale(0.98);\n }\n\n .menu-grid-link {\n display: flex;\n flex-direction: column;\n text-decoration: none;\n color: inherit;\n width: 100%;\n height: 100%;\n gap: 8px;\n }\n\n .menu-grid-badge {\n position: absolute;\n top: 2px;\n right: 8px;\n font-size: 0.5rem;\n padding: 2px 8px;\n border-radius: 9999px;\n font-weight: 500;\n z-index: 1;\n background-color: var(--st-color-text-strong);\n color: var(--st-color-on-solid);\n animation: st-menu-grid-badge-pop 0.35s ease-out;\n }\n\n .menu-grid-header {\n display: flex;\n align-items: center;\n gap: 12px;\n width: 100%;\n }\n\n .menu-grid-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: 6px;\n transition:\n background-color 0.2s ease,\n transform 0.2s ease;\n flex-shrink: 0;\n padding: 0;\n margin-bottom: 0;\n }\n\n .menu-grid-icon:hover {\n transform: rotate(5deg) scale(1.1);\n }\n\n .menu-grid-icon[hidden] {\n display: none;\n }\n\n .menu-grid-icon ::slotted(*) {\n width: 18px;\n height: 18px;\n }\n\n .menu-grid-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: var(--st-color-text-strong);\n transition: color 0.2s ease;\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-bottom: 0;\n }\n\n .menu-grid-description {\n font-size: 0.75rem;\n color: var(--st-color-text-muted);\n display: -webkit-box;\n -webkit-box-orient: vertical;\n overflow: hidden;\n line-height: 1.4;\n transition: color 0.2s ease;\n }\n\n .menu-grid-item.compact .menu-grid-header {\n gap: 8px;\n }\n\n .menu-grid-item.compact .menu-grid-icon {\n width: 24px;\n height: 24px;\n }\n\n .menu-grid-item.compact .menu-grid-icon ::slotted(*) {\n width: 14px;\n height: 14px;\n }\n\n .menu-grid-item.compact .menu-grid-title {\n font-size: 0.75rem;\n }\n\n .menu-grid-item.compact .menu-grid-description {\n font-size: 0.75rem;\n }\n\n .menu-grid-header.icon-only {\n justify-content: center;\n }\n\n @media (max-width: 480px) {\n .menu-grid-header {\n gap: 8px;\n }\n\n .menu-grid-icon {\n width: 28px;\n height: 28px;\n }\n\n .menu-grid-icon ::slotted(*) {\n width: 16px;\n height: 16px;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .menu-grid-item,\n .menu-grid-icon {\n transition: none;\n }\n\n .menu-grid-item.pending {\n opacity: 1;\n transform: none;\n }\n\n .menu-grid-badge {\n animation: none;\n }\n }\n `;\n\n @property({ type: String })\n title = '';\n\n @property({ type: String })\n description = '';\n\n @property({ type: String })\n href = '';\n\n /** Small corner label, e.g. \"New\"/\"Beta\" — omit for none. */\n @property({ type: String })\n badge = '';\n\n @property({ type: Boolean, reflect: true })\n compact = false;\n\n /** Suppresses the description even when `description` is set (source: `showDescription`, default `true`). */\n @property({ type: Boolean, attribute: 'show-description' })\n showDescription = true;\n\n /** Whether `slot=\"icon\"` has content, so an omitted icon leaves no empty box. */\n @state() private hasIcon = false;\n\n /** True until the item first scrolls into view (the source's `whileInView ... once`). */\n @state() private pending = true;\n\n private observer?: IntersectionObserver;\n\n connectedCallback(): void {\n super.connectedCallback();\n if (typeof IntersectionObserver === 'undefined') {\n this.pending = false;\n return;\n }\n this.observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n this.pending = false;\n this.observer?.disconnect();\n }\n });\n this.observer.observe(this);\n }\n\n disconnectedCallback(): void {\n this.observer?.disconnect();\n super.disconnectedCallback();\n }\n\n private onIconSlotChange = (event: Event): void => {\n this.hasIcon = (event.target as HTMLSlotElement).assignedNodes({ flatten: true }).length > 0;\n };\n\n private get isExternal(): boolean {\n return this.href.startsWith('http');\n }\n\n private onClick = (event: MouseEvent): void => {\n if (this.isExternal) return;\n const selectEvent = new CustomEvent<MenuGridItemSelectEventDetail>('menu-grid-item-select', {\n detail: { href: this.href },\n bubbles: true,\n composed: true,\n cancelable: true\n });\n this.dispatchEvent(selectEvent);\n if (selectEvent.defaultPrevented) event.preventDefault();\n };\n\n render() {\n const iconOnly = this.hasIcon && !this.title;\n return html`\n <div class=\"menu-grid-item ${this.compact ? 'compact' : 'regular'} ${this.pending ? 'pending' : ''}\" part=\"item\">\n <a\n part=\"link\"\n class=\"menu-grid-link\"\n href=${this.href}\n target=${this.isExternal ? '_blank' : '_self'}\n rel=${this.isExternal ? 'noopener noreferrer' : nothing}\n @click=${this.onClick}\n >\n ${this.badge ? html`<span part=\"badge\" class=\"menu-grid-badge\">${this.badge}</span>` : nothing}\n <span class=\"menu-grid-header ${iconOnly ? 'icon-only' : ''}\" part=\"header\">\n <span class=\"menu-grid-icon\" part=\"icon\" ?hidden=${!this.hasIcon}><slot name=\"icon\" @slotchange=${this.onIconSlotChange}></slot></span>\n ${this.title ? html`<span part=\"title\" class=\"menu-grid-title\">${this.title}</span>` : nothing}\n </span>\n ${this.description && this.showDescription\n ? html`<span part=\"description\" class=\"menu-grid-description\">${this.description}</span>`\n : nothing}\n </a>\n </div>\n `;\n }\n}\n"],"mappings":";;;;;;;;;AAAA,SAAS,YAAY,KAAK,MAAM,eAAe;AAC/C,SAAS,eAAe,UAAU,aAAa;AAiBxC,IAAM,eAAN,cAA2B,WAAW;AAAA,EAAtC;AAAA;AA2ML,iBAAQ;AAGR,uBAAc;AAGd,gBAAO;AAIP,iBAAQ;AAGR,mBAAU;AAIV,2BAAkB;AAGT,SAAQ,UAAU;AAGlB,SAAQ,UAAU;AAwB3B,SAAQ,mBAAmB,CAAC,UAAuB;AACjD,WAAK,UAAW,MAAM,OAA2B,cAAc,EAAE,SAAS,KAAK,CAAC,EAAE,SAAS;AAAA,IAC7F;AAMA,SAAQ,UAAU,CAAC,UAA4B;AAC7C,UAAI,KAAK,WAAY;AACrB,YAAM,cAAc,IAAI,YAA2C,yBAAyB;AAAA,QAC1F,QAAQ,EAAE,MAAM,KAAK,KAAK;AAAA,QAC1B,SAAS;AAAA,QACT,UAAU;AAAA,QACV,YAAY;AAAA,MACd,CAAC;AACD,WAAK,cAAc,WAAW;AAC9B,UAAI,YAAY,iBAAkB,OAAM,eAAe;AAAA,IACzD;AAAA;AAAA,EAtCA,oBAA0B;AACxB,UAAM,kBAAkB;AACxB,QAAI,OAAO,yBAAyB,aAAa;AAC/C,WAAK,UAAU;AACf;AAAA,IACF;AACA,SAAK,WAAW,IAAI,qBAAqB,CAAC,YAAY;AACpD,UAAI,QAAQ,KAAK,CAAC,UAAU,MAAM,cAAc,GAAG;AACjD,aAAK,UAAU;AACf,aAAK,UAAU,WAAW;AAAA,MAC5B;AAAA,IACF,CAAC;AACD,SAAK,SAAS,QAAQ,IAAI;AAAA,EAC5B;AAAA,EAEA,uBAA6B;AAC3B,SAAK,UAAU,WAAW;AAC1B,UAAM,qBAAqB;AAAA,EAC7B;AAAA,EAMA,IAAY,aAAsB;AAChC,WAAO,KAAK,KAAK,WAAW,MAAM;AAAA,EACpC;AAAA,EAcA,SAAS;AACP,UAAM,WAAW,KAAK,WAAW,CAAC,KAAK;AACvC,WAAO;AAAA,mCACwB,KAAK,UAAU,YAAY,SAAS,IAAI,KAAK,UAAU,YAAY,EAAE;AAAA;AAAA;AAAA;AAAA,iBAIvF,KAAK,IAAI;AAAA,mBACP,KAAK,aAAa,WAAW,OAAO;AAAA,gBACvC,KAAK,aAAa,wBAAwB,OAAO;AAAA,mBAC9C,KAAK,OAAO;AAAA;AAAA,YAEnB,KAAK,QAAQ,kDAAkD,KAAK,KAAK,YAAY,OAAO;AAAA,0CAC9D,WAAW,cAAc,EAAE;AAAA,+DACN,CAAC,KAAK,OAAO,kCAAkC,KAAK,gBAAgB;AAAA,cACrH,KAAK,QAAQ,kDAAkD,KAAK,KAAK,YAAY,OAAO;AAAA;AAAA,YAE9F,KAAK,eAAe,KAAK,kBACvB,8DAA8D,KAAK,WAAW,YAC9E,OAAO;AAAA;AAAA;AAAA;AAAA,EAInB;AACF;AAAA;AAtSa,aAEJ,oBAAoB,EAAE,GAAG,WAAW,mBAAmB,gBAAgB,KAAK;AAFxE,aAIJ,SAAS;AAAA,MACZ,iBAAiB;AAAA;AAAA;AAAA;AAAA,QAIf,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkMtB;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GA1Mf,aA2MX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GA7Mf,aA8MX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GAhNf,aAiNX;AAIA;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GApNf,aAqNX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,SAAS,KAAK,CAAC;AAAA,GAvN/B,aAwNX;AAIA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,WAAW,mBAAmB,CAAC;AAAA,GA3N/C,aA4NX;AAGiB;AAAA,EAAhB,MAAM;AAAA,GA/NI,aA+NM;AAGA;AAAA,EAAhB,MAAM;AAAA,GAlOI,aAkOM;AAlON,eAAN;AAAA,EADN,cAAc,mBAAmB;AAAA,GACrB;","names":[]}
@@ -67,4 +67,4 @@ IconButton = __decorateClass([
67
67
  export {
68
68
  IconButton
69
69
  };
70
- //# sourceMappingURL=chunk-YQ42EBK5.js.map
70
+ //# sourceMappingURL=chunk-PHEGSCOM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/icon-button/IconButton.ts"],"sourcesContent":["import { LitElement, css, html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\nimport { buttonResetStyles, controlBaseStyles, rootFontFamilyStyles } from '../shared/styles';\n\n/**\n * A small, icon-only action button. The icon is default-slotted content (the package has no icon\n * library dependency), the same convention as `st-dropdown`/`st-menu-grid-item`'s `slot=\"icon\"`.\n *\n * Fires a plain native `click` — no custom event, since a caller just wants an ordinary button.\n */\n@customElement('st-icon-button')\nexport class IconButton extends LitElement {\n static styles = css`\n ${controlBaseStyles}\n\n :host {\n display: inline-flex;\n ${rootFontFamilyStyles}\n }\n\n button {\n ${buttonResetStyles}\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--st-size-32);\n height: var(--st-size-32);\n border-radius: var(--st-radius-sm);\n color: var(--st-color-text-muted);\n }\n\n button:hover {\n background: var(--st-color-hover);\n color: var(--st-color-text-strong);\n }\n\n :host([disabled]) button {\n color: var(--st-color-text-muted);\n cursor: not-allowed;\n pointer-events: none;\n }\n `;\n\n /** Accessible name and tooltip — matches the source component's `ariaLabel` (renamed: modern\n * browsers already expose a native `ariaLabel` reflected property on every `Element`, so reusing\n * that exact name as a Lit reactive property would shadow it). Required for a control with no\n * visible text. */\n @property({ type: String })\n label = '';\n\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n render() {\n return html`\n <button part=\"button\" type=\"button\" aria-label=${this.label} title=${this.label} ?disabled=${this.disabled}>\n <slot></slot>\n </button>\n `;\n }\n}\n"],"mappings":";;;;;;;;;;AAAA,SAAS,YAAY,KAAK,YAAY;AACtC,SAAS,eAAe,gBAAgB;AAWjC,IAAM,aAAN,cAAyB,WAAW;AAAA,EAApC;AAAA;AAqCL,iBAAQ;AAGR,oBAAW;AAAA;AAAA,EAEX,SAAS;AACP,WAAO;AAAA,uDAC4C,KAAK,KAAK,UAAU,KAAK,KAAK,cAAc,KAAK,QAAQ;AAAA;AAAA;AAAA;AAAA,EAI9G;AACF;AAjDa,WACJ,SAAS;AAAA,MACZ,iBAAiB;AAAA;AAAA;AAAA;AAAA,QAIf,oBAAoB;AAAA;AAAA;AAAA;AAAA,QAIpB,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2BvB;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GApCf,WAqCX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,SAAS,KAAK,CAAC;AAAA,GAvC/B,WAwCX;AAxCW,aAAN;AAAA,EADN,cAAc,gBAAgB;AAAA,GAClB;","names":[]}
@@ -1,3 +1,6 @@
1
+ import {
2
+ renderMarkdown
3
+ } from "./chunk-UAIUBPDN.js";
1
4
  import {
2
5
  controlBaseStyles,
3
6
  fontFamilyStyles
@@ -10,8 +13,6 @@ import {
10
13
  import { LitElement, css, html, nothing } from "lit";
11
14
  import { customElement, property, state } from "lit/decorators.js";
12
15
  import { unsafeHTML } from "lit/directives/unsafe-html.js";
13
- import DOMPurify from "dompurify";
14
- import { marked } from "marked";
15
16
  var Markdown = class extends LitElement {
16
17
  constructor() {
17
18
  super(...arguments);
@@ -63,8 +64,7 @@ var Markdown = class extends LitElement {
63
64
  if (this.error) return html`<div part="error">Error loading content.</div>`;
64
65
  const source = this.src ? this.fetched : this.content;
65
66
  if (!source) return nothing;
66
- const rendered = DOMPurify.sanitize(marked.parse(source, { gfm: true, breaks: true, async: false }));
67
- return html`<div part="body">${unsafeHTML(rendered)}</div>`;
67
+ return html`<div part="body">${unsafeHTML(renderMarkdown(source))}</div>`;
68
68
  }
69
69
  };
70
70
  Markdown.styles = css`
@@ -190,4 +190,4 @@ Markdown = __decorateClass([
190
190
  export {
191
191
  Markdown
192
192
  };
193
- //# sourceMappingURL=chunk-5EBWMPJS.js.map
193
+ //# sourceMappingURL=chunk-QLA4BH2B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/markdown/Markdown.ts"],"sourcesContent":["import { LitElement, css, html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\n\nimport { controlBaseStyles, fontFamilyStyles } from '../shared/styles';\nimport { renderMarkdown } from '../shared/markdown';\nimport type { MarkdownErrorEventDetail } from './MarkdownEvents';\n\n/**\n * Renders Markdown (GFM, single newlines become `<br>`) from either an inline `content` string or\n * a `src` URL it fetches. Output is sanitized with DOMPurify. `src` wins over `content` when both are set.\n * While a fetch is pending it shows \"Loading content...\"; on failure \"Error loading content.\" and\n * a `markdown-error` event (detail: `{ error }`).\n *\n * Text color is inherited from the parent so inverted containers just work.\n */\n@customElement('st-markdown')\nexport class Markdown extends LitElement {\n static styles = css`\n ${controlBaseStyles}\n\n :host {\n display: block;\n ${fontFamilyStyles}\n line-height: 1.7;\n }\n\n :host > div > :first-child {\n margin-top: 0;\n }\n\n h1,\n h2,\n h3,\n h4 {\n color: inherit;\n font-weight: var(--st-font-weight-bold);\n line-height: 1.3;\n }\n\n h2 {\n font-size: var(--st-text-2xl);\n margin: var(--st-space-48) 0 var(--st-space-24);\n }\n\n h3 {\n font-size: var(--st-text-xl);\n font-weight: var(--st-font-weight-semibold);\n margin: var(--st-space-32) 0 var(--st-space-16);\n }\n\n p {\n margin: 0 0 var(--st-space-24);\n }\n\n ul,\n ol {\n margin: 0 0 var(--st-space-24);\n padding-left: var(--st-space-24);\n }\n\n li {\n margin-bottom: var(--st-space-8);\n }\n\n a {\n color: inherit;\n text-decoration: underline;\n text-underline-offset: 4px;\n }\n\n a:hover {\n color: var(--st-color-text-strong);\n }\n\n img {\n max-width: 100%;\n height: auto;\n border-radius: var(--st-radius-sm);\n margin: var(--st-space-32) 0;\n }\n\n blockquote {\n border-left: 4px solid var(--st-color-border);\n margin: var(--st-space-32) 0;\n padding-left: var(--st-space-24);\n font-style: italic;\n }\n\n table {\n border-collapse: collapse;\n margin: 0 0 var(--st-space-24);\n }\n\n th,\n td {\n border: 1px solid var(--st-color-border);\n padding: var(--st-space-8) var(--st-space-12);\n }\n\n pre,\n code {\n background: var(--st-color-subtle);\n border-radius: var(--st-radius-xs);\n }\n\n code {\n padding: 0 var(--st-space-4);\n }\n\n pre {\n padding: var(--st-space-16);\n overflow-x: auto;\n }\n\n pre code {\n padding: 0;\n }\n `;\n\n /** Inline Markdown source. Ignored when `src` is set. */\n @property({ type: String })\n content = '';\n\n /** URL of a Markdown file to fetch. */\n @property({ type: String })\n src = '';\n\n @state() private fetched = '';\n @state() private loading = false;\n @state() private error: Error | null = null;\n\n private abort?: AbortController;\n\n willUpdate(changed: Map<string, unknown>): void {\n if (changed.has('src')) void this.load();\n }\n\n disconnectedCallback(): void {\n this.abort?.abort();\n super.disconnectedCallback();\n }\n\n private async load(): Promise<void> {\n this.abort?.abort();\n this.fetched = '';\n this.error = null;\n if (!this.src) {\n this.loading = false;\n return;\n }\n const controller = new AbortController();\n this.abort = controller;\n this.loading = true;\n try {\n const response = await fetch(this.src, { signal: controller.signal });\n if (!response.ok) throw new Error(`Failed to fetch markdown: ${response.statusText}`);\n const text = await response.text();\n if (controller.signal.aborted) return;\n this.fetched = text;\n } catch (err) {\n if (controller.signal.aborted) return;\n this.error = err instanceof Error ? err : new Error('Unknown error fetching markdown');\n this.dispatchEvent(\n new CustomEvent<MarkdownErrorEventDetail>('markdown-error', {\n detail: { error: this.error },\n bubbles: true,\n composed: true\n })\n );\n }\n this.loading = false;\n }\n\n render() {\n if (this.loading) return html`<div part=\"loading\">Loading content...</div>`;\n if (this.error) return html`<div part=\"error\">Error loading content.</div>`;\n const source = this.src ? this.fetched : this.content;\n if (!source) return nothing;\n return html`<div part=\"body\">${unsafeHTML(renderMarkdown(source))}</div>`;\n }\n}\n"],"mappings":"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","names":[]}