@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.
- package/custom-elements.json +608 -15
- package/dist/bento-grid/index.d.ts +8 -1
- package/dist/bento-grid/index.js +2 -1
- package/dist/card/index.d.ts +3 -4
- package/dist/card/index.js +1 -1
- package/dist/{chunk-LEXZKGQX.js → chunk-2DXHPEB5.js} +1 -1
- package/dist/chunk-2DXHPEB5.js.map +1 -0
- package/dist/{chunk-R5G6KFTJ.js → chunk-2FJDNJ7R.js} +1 -1
- package/dist/chunk-2FJDNJ7R.js.map +1 -0
- package/dist/{chunk-ZN4LIKVG.js → chunk-3OEEOBHB.js} +1 -1
- package/dist/chunk-3OEEOBHB.js.map +1 -0
- package/dist/{chunk-BMHMNXIA.js → chunk-4AFOKKSU.js} +1 -1
- package/dist/chunk-4AFOKKSU.js.map +1 -0
- package/dist/{chunk-76AVBQUA.js → chunk-5C6C6K5U.js} +98 -4
- package/dist/chunk-5C6C6K5U.js.map +1 -0
- package/dist/{chunk-7NLZND6Q.js → chunk-5F5PTVWR.js} +27 -2
- package/dist/chunk-5F5PTVWR.js.map +1 -0
- package/dist/chunk-5MY6OWMK.js +125 -0
- package/dist/chunk-5MY6OWMK.js.map +1 -0
- package/dist/{chunk-FLY7TNRT.js → chunk-7NIWQWTA.js} +1 -1
- package/dist/chunk-7NIWQWTA.js.map +1 -0
- package/dist/{chunk-ALI26WOB.js → chunk-EE6PAN3B.js} +33 -2
- package/dist/chunk-EE6PAN3B.js.map +1 -0
- package/dist/{chunk-VWS53WY4.js → chunk-HMUZON6I.js} +49 -4
- package/dist/chunk-HMUZON6I.js.map +1 -0
- package/dist/chunk-O4FCRKDX.js +178 -0
- package/dist/chunk-O4FCRKDX.js.map +1 -0
- package/dist/{chunk-SMLR736E.js → chunk-OELI3IWC.js} +1 -1
- package/dist/chunk-OELI3IWC.js.map +1 -0
- package/dist/{chunk-JQY2G4QK.js → chunk-OLA35A2O.js} +1 -1
- package/dist/chunk-OLA35A2O.js.map +1 -0
- package/dist/{chunk-YQ42EBK5.js → chunk-PHEGSCOM.js} +1 -1
- package/dist/chunk-PHEGSCOM.js.map +1 -0
- package/dist/{chunk-5EBWMPJS.js → chunk-QLA4BH2B.js} +5 -5
- package/dist/chunk-QLA4BH2B.js.map +1 -0
- package/dist/{chunk-JKBWZLG4.js → chunk-SQ3OZO32.js} +141 -3
- package/dist/chunk-SQ3OZO32.js.map +1 -0
- package/dist/chunk-UAIUBPDN.js +11 -0
- package/dist/chunk-UAIUBPDN.js.map +1 -0
- package/dist/{chunk-XWB4CKDU.js → chunk-XUGEXERO.js} +6 -6
- package/dist/chunk-XUGEXERO.js.map +1 -0
- package/dist/chunk-ZRC5BVDX.js +219 -0
- package/dist/chunk-ZRC5BVDX.js.map +1 -0
- package/dist/cms-theme.css +7 -0
- package/dist/content-block/index.d.ts +2 -3
- package/dist/content-block/index.js +3 -2
- package/dist/dropdown/index.d.ts +8 -11
- package/dist/dropdown/index.js +1 -1
- package/dist/feature-split/index.js +2 -1
- package/dist/features-section/index.d.ts +4 -4
- package/dist/features-section/index.js +4 -3
- package/dist/flow/index.d.ts +35 -0
- package/dist/flow/index.js +9 -0
- package/dist/flow/index.js.map +1 -0
- package/dist/header/index.d.ts +8 -15
- package/dist/header/index.js +1 -1
- package/dist/hero/index.d.ts +18 -3
- package/dist/hero/index.js +1 -1
- package/dist/icon-button/index.d.ts +2 -4
- package/dist/icon-button/index.js +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +36 -23
- package/dist/items-accordion/index.d.ts +5 -0
- package/dist/items-accordion/index.js +2 -1
- package/dist/markdown/index.d.ts +1 -2
- package/dist/markdown/index.js +2 -1
- package/dist/menu-grid/index.d.ts +2 -3
- package/dist/menu-grid/index.js +1 -1
- package/dist/menu-grid-item/index.d.ts +6 -8
- package/dist/menu-grid-item/index.js +1 -1
- package/dist/menu-item/index.d.ts +5 -7
- package/dist/menu-item/index.js +1 -1
- package/dist/promo-banner/index.d.ts +14 -3
- package/dist/promo-banner/index.js +1 -1
- package/dist/schema/index.d.ts +3 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema/index.js.map +1 -1
- package/dist/section/index.d.ts +3 -0
- package/dist/section/index.js +1 -1
- package/dist/steps/index.d.ts +33 -0
- package/dist/steps/index.js +10 -0
- package/dist/steps/index.js.map +1 -0
- package/dist/tag-strip/index.d.ts +26 -0
- package/dist/tag-strip/index.js +9 -0
- package/dist/tag-strip/index.js.map +1 -0
- package/package.json +14 -2
- package/dist/chunk-5EBWMPJS.js.map +0 -1
- package/dist/chunk-76AVBQUA.js.map +0 -1
- package/dist/chunk-7NLZND6Q.js.map +0 -1
- package/dist/chunk-ALI26WOB.js.map +0 -1
- package/dist/chunk-BMHMNXIA.js.map +0 -1
- package/dist/chunk-FLY7TNRT.js.map +0 -1
- package/dist/chunk-JKBWZLG4.js.map +0 -1
- package/dist/chunk-JQY2G4QK.js.map +0 -1
- package/dist/chunk-LEXZKGQX.js.map +0 -1
- package/dist/chunk-R5G6KFTJ.js.map +0 -1
- package/dist/chunk-SMLR736E.js.map +0 -1
- package/dist/chunk-VWS53WY4.js.map +0 -1
- package/dist/chunk-XWB4CKDU.js.map +0 -1
- package/dist/chunk-YQ42EBK5.js.map +0 -1
- package/dist/chunk-ZN4LIKVG.js.map +0 -1
|
@@ -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>→</span>\n </a>\n `\n : nothing}\n </div>\n </st-card>\n `;\n }\n}\n"],"mappings":"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","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-
|
|
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
|
-
|
|
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-
|
|
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":"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","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":[]}
|
|
@@ -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":[]}
|
|
@@ -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":"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","names":[]}
|
|
@@ -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
|
-
|
|
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-
|
|
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":[]}
|