@sankhyatronics/sankhya-cms 0.2.0 → 0.3.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 +10968 -3080
- package/dist/attention-panel/index.js +2 -2
- package/dist/bar-chart/index.js +2 -2
- package/dist/bento-grid/index.d.ts +25 -0
- package/dist/bento-grid/index.js +4 -4
- package/dist/booking/index.d.ts +309 -0
- package/dist/booking/index.js +20 -0
- package/dist/booking/index.js.map +1 -0
- package/dist/card/index.js +2 -2
- package/dist/carousel/index.d.ts +20 -6
- package/dist/carousel/index.js +3 -3
- package/dist/chip/index.js +2 -2
- package/dist/{chunk-OLA35A2O.js → chunk-2GTR37PU.js} +2 -2
- package/dist/{chunk-7NIWQWTA.js → chunk-2HMOX253.js} +128 -25
- package/dist/chunk-2HMOX253.js.map +1 -0
- package/dist/{chunk-DH53HZPB.js → chunk-37KFBKPD.js} +32 -4
- package/dist/chunk-37KFBKPD.js.map +1 -0
- package/dist/{chunk-EE6PAN3B.js → chunk-4XPKKYVZ.js} +23 -15
- package/dist/chunk-4XPKKYVZ.js.map +1 -0
- package/dist/chunk-535QAZ6A.js +236 -0
- package/dist/chunk-535QAZ6A.js.map +1 -0
- package/dist/{chunk-AKJQ345O.js → chunk-5AWGZQWU.js} +2 -2
- package/dist/chunk-6OZKZG5J.js +300 -0
- package/dist/chunk-6OZKZG5J.js.map +1 -0
- package/dist/chunk-AYNT7G3J.js +805 -0
- package/dist/chunk-AYNT7G3J.js.map +1 -0
- package/dist/chunk-BEWX3E6P.js +32 -0
- package/dist/chunk-BEWX3E6P.js.map +1 -0
- package/dist/chunk-CZUGPKXV.js +275 -0
- package/dist/chunk-CZUGPKXV.js.map +1 -0
- package/dist/{chunk-2DXHPEB5.js → chunk-DJFWZOZM.js} +107 -11
- package/dist/chunk-DJFWZOZM.js.map +1 -0
- package/dist/chunk-DPANTC3O.js +1714 -0
- package/dist/chunk-DPANTC3O.js.map +1 -0
- package/dist/chunk-EKZFFY45.js +426 -0
- package/dist/chunk-EKZFFY45.js.map +1 -0
- package/dist/chunk-ER7MCPDV.js +7 -0
- package/dist/chunk-ER7MCPDV.js.map +1 -0
- package/dist/chunk-EW2RK5Y6.js +383 -0
- package/dist/chunk-EW2RK5Y6.js.map +1 -0
- package/dist/{chunk-BLQV2YMO.js → chunk-EZOKT7NJ.js} +2 -2
- package/dist/chunk-FF2LWEF3.js +386 -0
- package/dist/chunk-FF2LWEF3.js.map +1 -0
- package/dist/chunk-FOUK3NHR.js +7 -0
- package/dist/chunk-FOUK3NHR.js.map +1 -0
- package/dist/{chunk-O4FCRKDX.js → chunk-GB4NGCZI.js} +6 -3
- package/dist/chunk-GB4NGCZI.js.map +1 -0
- package/dist/{chunk-5F5PTVWR.js → chunk-GOFSMD6W.js} +9 -10
- package/dist/chunk-GOFSMD6W.js.map +1 -0
- package/dist/{chunk-6D6ROU7X.js → chunk-IGMVF3KK.js} +2 -2
- package/dist/{chunk-INMSEYT6.js → chunk-IVPVYVWG.js} +2 -2
- package/dist/{chunk-ZRC5BVDX.js → chunk-JURCF4OD.js} +174 -12
- package/dist/chunk-JURCF4OD.js.map +1 -0
- package/dist/{chunk-FZ36KL73.js → chunk-KZ7PMFWS.js} +11 -1
- package/dist/chunk-KZ7PMFWS.js.map +1 -0
- package/dist/{chunk-EMCQBT3S.js → chunk-LO6TZBGD.js} +129 -35
- package/dist/chunk-LO6TZBGD.js.map +1 -0
- package/dist/chunk-MFRGAT6D.js +860 -0
- package/dist/chunk-MFRGAT6D.js.map +1 -0
- package/dist/chunk-MIBVQXRU.js +1098 -0
- package/dist/chunk-MIBVQXRU.js.map +1 -0
- package/dist/{chunk-35TX3AOA.js → chunk-NABSRUXG.js} +2 -2
- package/dist/{chunk-2FJDNJ7R.js → chunk-NXKDZWS7.js} +44 -6
- package/dist/chunk-NXKDZWS7.js.map +1 -0
- package/dist/{chunk-KMU6ABQF.js → chunk-NXUS2CH7.js} +14 -1
- package/dist/chunk-NXUS2CH7.js.map +1 -0
- package/dist/{chunk-GJO3RGOB.js → chunk-OCPGOLVF.js} +56 -11
- package/dist/chunk-OCPGOLVF.js.map +1 -0
- package/dist/chunk-OEOE6IFY.js +628 -0
- package/dist/chunk-OEOE6IFY.js.map +1 -0
- package/dist/{chunk-OELI3IWC.js → chunk-PV6OCXXN.js} +2 -2
- package/dist/{chunk-5C6C6K5U.js → chunk-Q66CJO3P.js} +200 -12
- package/dist/chunk-Q66CJO3P.js.map +1 -0
- package/dist/{chunk-MG2VTZA4.js → chunk-QS3ANOWN.js} +2 -2
- package/dist/{chunk-3OEEOBHB.js → chunk-QSJ543V2.js} +2 -2
- package/dist/{chunk-FML6AG2V.js → chunk-RANC3OI6.js} +2 -2
- package/dist/chunk-T4BIN37Q.js +32 -0
- package/dist/chunk-T4BIN37Q.js.map +1 -0
- package/dist/{chunk-YVTFQHVY.js → chunk-TEAZZPDQ.js} +2 -2
- package/dist/chunk-TJK55CJ2.js +49 -0
- package/dist/chunk-TJK55CJ2.js.map +1 -0
- package/dist/chunk-UKIVLF7S.js +32 -0
- package/dist/chunk-UKIVLF7S.js.map +1 -0
- package/dist/chunk-V4R7PYP5.js +905 -0
- package/dist/chunk-V4R7PYP5.js.map +1 -0
- package/dist/{chunk-AG2COC64.js → chunk-VVYQ2DDS.js} +2 -2
- package/dist/chunk-WAMOAAMN.js +16 -0
- package/dist/chunk-WAMOAAMN.js.map +1 -0
- package/dist/chunk-WAYHHL4J.js +1234 -0
- package/dist/chunk-WAYHHL4J.js.map +1 -0
- package/dist/{chunk-PHEGSCOM.js → chunk-WH6HE6SY.js} +10 -4
- package/dist/chunk-WH6HE6SY.js.map +1 -0
- package/dist/{chunk-5MY6OWMK.js → chunk-XP6DI3VY.js} +59 -4
- package/dist/chunk-XP6DI3VY.js.map +1 -0
- package/dist/{chunk-QLA4BH2B.js → chunk-XS6LNTSH.js} +73 -11
- package/dist/chunk-XS6LNTSH.js.map +1 -0
- package/dist/{chunk-WT4OATGP.js → chunk-ZKFCDVB4.js} +16 -7
- package/dist/chunk-ZKFCDVB4.js.map +1 -0
- package/dist/cms-theme.css +22 -0
- package/dist/contact-form/index.d.ts +220 -0
- package/dist/contact-form/index.js +16 -0
- package/dist/contact-form/index.js.map +1 -0
- package/dist/content-block/index.d.ts +39 -3
- package/dist/content-block/index.js +8 -5
- package/dist/cookie-consent/index.d.ts +60 -12
- package/dist/cookie-consent/index.js +3 -2
- package/dist/date-tile/index.js +2 -2
- package/dist/dropdown/index.d.ts +22 -1
- package/dist/dropdown/index.js +4 -2
- package/dist/feature-split/index.d.ts +6 -1
- package/dist/feature-split/index.js +5 -5
- package/dist/features-section/index.d.ts +49 -5
- package/dist/features-section/index.js +6 -6
- package/dist/flow/index.js +2 -2
- package/dist/footer/index.d.ts +13 -0
- package/dist/footer/index.js +2 -2
- package/dist/header/index.d.ts +127 -1
- package/dist/header/index.js +3 -2
- package/dist/hero/index.d.ts +75 -6
- package/dist/hero/index.js +6 -3
- package/dist/icon-button/index.d.ts +5 -3
- package/dist/icon-button/index.js +2 -2
- package/dist/index.d.ts +9 -3
- package/dist/index.js +118 -57
- package/dist/items-accordion/index.d.ts +5 -1
- package/dist/items-accordion/index.js +4 -4
- package/dist/kpi-card/index.js +2 -2
- package/dist/markdown/index.d.ts +18 -0
- package/dist/markdown/index.js +3 -3
- package/dist/mega-menu/index.d.ts +95 -7
- package/dist/mega-menu/index.js +7 -2
- package/dist/menu-grid/index.js +2 -2
- package/dist/menu-grid-item/index.js +2 -2
- package/dist/menu-item/index.d.ts +6 -0
- package/dist/menu-item/index.js +3 -2
- package/dist/plan-cards/index.d.ts +69 -0
- package/dist/plan-cards/index.js +13 -0
- package/dist/plan-cards/index.js.map +1 -0
- package/dist/product-nav/index.d.ts +127 -0
- package/dist/product-nav/index.js +11 -0
- package/dist/product-nav/index.js.map +1 -0
- package/dist/promo-banner/index.d.ts +34 -7
- package/dist/promo-banner/index.js +6 -3
- package/dist/quote-dialog/index.d.ts +174 -0
- package/dist/quote-dialog/index.js +22 -0
- package/dist/quote-dialog/index.js.map +1 -0
- package/dist/schema/index.d.ts +8 -0
- package/dist/schema/index.js +6 -0
- package/dist/schema/index.js.map +1 -1
- package/dist/screenshot-tour/index.d.ts +54 -0
- package/dist/screenshot-tour/index.js +9 -0
- package/dist/screenshot-tour/index.js.map +1 -0
- package/dist/section/index.js +3 -3
- package/dist/segmented-control/index.js +2 -2
- package/dist/select/index.js +2 -2
- package/dist/shared/styles.d.ts +7 -1
- package/dist/shared/styles.js +3 -1
- package/dist/stats/index.js +2 -2
- package/dist/steps/index.d.ts +12 -0
- package/dist/steps/index.js +4 -3
- package/dist/tag-strip/index.d.ts +7 -0
- package/dist/tag-strip/index.js +2 -2
- package/dist/testimonials/index.d.ts +9 -1
- package/dist/testimonials/index.js +3 -3
- package/dist/tooltip/index.js +2 -2
- package/package.json +26 -2
- package/dist/chunk-2DXHPEB5.js.map +0 -1
- package/dist/chunk-2FJDNJ7R.js.map +0 -1
- package/dist/chunk-4AFOKKSU.js +0 -158
- package/dist/chunk-4AFOKKSU.js.map +0 -1
- package/dist/chunk-5C6C6K5U.js.map +0 -1
- package/dist/chunk-5F5PTVWR.js.map +0 -1
- package/dist/chunk-5MY6OWMK.js.map +0 -1
- package/dist/chunk-7NIWQWTA.js.map +0 -1
- package/dist/chunk-DH53HZPB.js.map +0 -1
- package/dist/chunk-EE6PAN3B.js.map +0 -1
- package/dist/chunk-EMCQBT3S.js.map +0 -1
- package/dist/chunk-FZ36KL73.js.map +0 -1
- package/dist/chunk-GJO3RGOB.js.map +0 -1
- package/dist/chunk-HMUZON6I.js +0 -202
- package/dist/chunk-HMUZON6I.js.map +0 -1
- package/dist/chunk-J6EO4R73.js +0 -633
- package/dist/chunk-J6EO4R73.js.map +0 -1
- package/dist/chunk-KMU6ABQF.js.map +0 -1
- package/dist/chunk-MSSH3HFK.js +0 -205
- package/dist/chunk-MSSH3HFK.js.map +0 -1
- package/dist/chunk-O4FCRKDX.js.map +0 -1
- package/dist/chunk-PHEGSCOM.js.map +0 -1
- package/dist/chunk-QLA4BH2B.js.map +0 -1
- package/dist/chunk-SQ3OZO32.js +0 -486
- package/dist/chunk-SQ3OZO32.js.map +0 -1
- package/dist/chunk-UAIUBPDN.js +0 -11
- package/dist/chunk-UAIUBPDN.js.map +0 -1
- package/dist/chunk-WT4OATGP.js.map +0 -1
- package/dist/chunk-XUGEXERO.js +0 -708
- package/dist/chunk-XUGEXERO.js.map +0 -1
- package/dist/chunk-ZRC5BVDX.js.map +0 -1
- /package/dist/{chunk-OLA35A2O.js.map → chunk-2GTR37PU.js.map} +0 -0
- /package/dist/{chunk-AKJQ345O.js.map → chunk-5AWGZQWU.js.map} +0 -0
- /package/dist/{chunk-BLQV2YMO.js.map → chunk-EZOKT7NJ.js.map} +0 -0
- /package/dist/{chunk-6D6ROU7X.js.map → chunk-IGMVF3KK.js.map} +0 -0
- /package/dist/{chunk-INMSEYT6.js.map → chunk-IVPVYVWG.js.map} +0 -0
- /package/dist/{chunk-35TX3AOA.js.map → chunk-NABSRUXG.js.map} +0 -0
- /package/dist/{chunk-OELI3IWC.js.map → chunk-PV6OCXXN.js.map} +0 -0
- /package/dist/{chunk-MG2VTZA4.js.map → chunk-QS3ANOWN.js.map} +0 -0
- /package/dist/{chunk-3OEEOBHB.js.map → chunk-QSJ543V2.js.map} +0 -0
- /package/dist/{chunk-FML6AG2V.js.map → chunk-RANC3OI6.js.map} +0 -0
- /package/dist/{chunk-YVTFQHVY.js.map → chunk-TEAZZPDQ.js.map} +0 -0
- /package/dist/{chunk-AG2COC64.js.map → chunk-VVYQ2DDS.js.map} +0 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PlanCards
|
|
3
|
+
} from "../chunk-FF2LWEF3.js";
|
|
4
|
+
import "../chunk-FOUK3NHR.js";
|
|
5
|
+
import "../chunk-XS6LNTSH.js";
|
|
6
|
+
import "../chunk-TJK55CJ2.js";
|
|
7
|
+
import "../chunk-KZ7PMFWS.js";
|
|
8
|
+
import "../chunk-NXUS2CH7.js";
|
|
9
|
+
import "../chunk-EUXUH3YW.js";
|
|
10
|
+
export {
|
|
11
|
+
PlanCards
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import * as lit from 'lit';
|
|
2
|
+
import { LitElement } from 'lit';
|
|
3
|
+
|
|
4
|
+
interface ProductNavLink {
|
|
5
|
+
label: string;
|
|
6
|
+
/** An in-page anchor, e.g. `#features`. A link to another site (e.g. the docs) opens in a new tab, with the ↗ icon. */
|
|
7
|
+
href: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A product sub-navigation bar for a product page, shown under the site header: a lockup (the product
|
|
11
|
+
* icon, a prefix and a name, with a tagline under it), in-page section links, an optional site-menu
|
|
12
|
+
* button and an optional external button.
|
|
13
|
+
*
|
|
14
|
+
* The lockup is one link (icon, wordmark, rule and tagline) to `brand-href`.
|
|
15
|
+
*
|
|
16
|
+
* The link whose section is in view gets `aria-current="true"`, found with an IntersectionObserver
|
|
17
|
+
* on the sections the `#anchor` links point at. On phones the links move to their own row and scroll
|
|
18
|
+
* sideways inside the bar. `sticky` pins the bar to the top of the viewport; set
|
|
19
|
+
* `--st-product-nav-top` to the height of a fixed site header above it.
|
|
20
|
+
*
|
|
21
|
+
* `embedded` drops the bar's own background, rule, shadow and sticky positioning, so it fills the
|
|
22
|
+
* row of a host, e.g. the `slot="context"` of `st-header` (its context mode). Desktop: lockup, links
|
|
23
|
+
* centred, site-menu button and action pill at the right, vertically centred. Phones: lockup (wordmark
|
|
24
|
+
* 18px, icon 32px, then 28px under 480px; tagline 9px under 480px and still shown), then a
|
|
25
|
+
* sideways-scrolling links row, then a compact action pill.
|
|
26
|
+
*
|
|
27
|
+
* `site-menu-label` adds a 44px hamburger button before the action pill. Clicking it dispatches
|
|
28
|
+
* `product-nav-site-menu`, which the host `st-header` answers by opening its site menu. While that menu
|
|
29
|
+
* is open the host sets `site-menu-open`, which is reflected to the button's `aria-expanded`.
|
|
30
|
+
*
|
|
31
|
+
* `scroll-spy` marks the link for the section currently in view with `aria-current="location"` and
|
|
32
|
+
* an active style (accent colour and a 2px underline). The section is the one whose top is nearest
|
|
33
|
+
* the top of the viewport at or above a 64px line; none is marked while the page is above the first
|
|
34
|
+
* section.
|
|
35
|
+
*
|
|
36
|
+
* @fires product-nav-site-menu - The site-menu button was clicked. Detail: `{ trigger }`, the button itself, so the host can return focus to it. Bubbles, composed.
|
|
37
|
+
* @attr icon - Product icon image URL, shown in the brand link before the wordmark (40px; 32px, then 28px under 480px, when `embedded`).
|
|
38
|
+
* @attr icon-dark - Dark-theme icon image URL, shown on `:root.dark` in place of `icon`. Needs `icon`.
|
|
39
|
+
* @attr label - Accessible name of the `<nav>` (e.g. `T-pilot`). Default: the brand prefix and name (e.g. `T-pilot`).
|
|
40
|
+
* @attr brand-href - Target of the brand link (icon and wordmark). Default `#top`.
|
|
41
|
+
* @attr site-menu-label - Accessible name of the site-menu button (a hamburger before the action pill). Empty (default): no button.
|
|
42
|
+
* @attr site-menu-open - Reflected. True while the host header's site menu is open, which sets the button's `aria-expanded`. Set by the host header, never from outside.
|
|
43
|
+
* @attr embedded - Fills the host row: no sticky positioning, background, rule or shadow of its own.
|
|
44
|
+
* @attr scroll-spy - Marks the link for the section in view (`aria-current="location"`).
|
|
45
|
+
* @cssprop --st-product-nav-top - The `top` offset of a sticky bar (default `0px`).
|
|
46
|
+
* @cssprop --st-product-nav-z - The `z-index` of a sticky bar (default `90`, under st-header's 100 so its open mega panel paints above).
|
|
47
|
+
* @cssprop --st-product-nav-border - Colour of the bottom rule (default `--st-cms-primary-100`).
|
|
48
|
+
* @csspart nav - The `<nav>` landmark.
|
|
49
|
+
* @csspart lockup - The wrapper of the brand link.
|
|
50
|
+
* @csspart brand - The brand link (icon, wordmark, rule and tagline).
|
|
51
|
+
* @csspart icon - The product icon image (one, or two when `icon-dark` is set).
|
|
52
|
+
* @csspart links - The list of section links.
|
|
53
|
+
* @csspart link - One section link.
|
|
54
|
+
* @csspart site-menu - The site-menu button.
|
|
55
|
+
* @csspart action - The external button.
|
|
56
|
+
*/
|
|
57
|
+
declare class ProductNav extends LitElement {
|
|
58
|
+
static styles: lit.CSSResult;
|
|
59
|
+
/** Brand prefix, e.g. `T-`. Shown in the brand navy. */
|
|
60
|
+
brandPrefix: string;
|
|
61
|
+
/** Product name, e.g. `pilot`. Shown in the brand azure with an underline. */
|
|
62
|
+
brandName: string;
|
|
63
|
+
/** Small line under the name, e.g. `by Sankhyatronics`. Plain text inside the brand link. */
|
|
64
|
+
brandTagline: string;
|
|
65
|
+
/** Target of the brand link (the icon, wordmark, rule and tagline). */
|
|
66
|
+
brandHref: string;
|
|
67
|
+
/** Product icon image URL, shown inside the brand link before the wordmark (40px; 32px and 28px on phones when `embedded`). Omitted when empty. */
|
|
68
|
+
icon: string;
|
|
69
|
+
/** Dark-theme variant of `icon`, shown on the site's dark theme (`:root.dark`) in place of it. Needs `icon`; without it `icon` shows on every theme. */
|
|
70
|
+
iconDark: string;
|
|
71
|
+
/** In-page section links. */
|
|
72
|
+
links: ProductNavLink[];
|
|
73
|
+
/** Label of the external button at the end of the bar. Shown only together with `href`. */
|
|
74
|
+
actionLabel: string;
|
|
75
|
+
/** Shorter button label for phones in `embedded` mode (e.g. `Open ↗`), so the links row keeps its room. Optional; the full `action-label` is used otherwise. */
|
|
76
|
+
actionShortLabel: string;
|
|
77
|
+
/** Target of the external button. It opens in the same tab. */
|
|
78
|
+
href: string;
|
|
79
|
+
/** Accessible name of the site-menu button, e.g. `Sankhyatronics menu`. Empty (default): no button. Clicking it dispatches `product-nav-site-menu`. */
|
|
80
|
+
siteMenuLabel: string;
|
|
81
|
+
/** True while the host header's site menu is open. Set by the header, never from outside: it drives the button's `aria-expanded`. */
|
|
82
|
+
siteMenuOpen: boolean;
|
|
83
|
+
/** Pins the bar to the top of the viewport (`position: sticky`). Ignored when `embedded`. */
|
|
84
|
+
sticky: boolean;
|
|
85
|
+
/** Accessible name of the `<nav>` landmark, e.g. `T-pilot`. Falls back to the brand prefix and name. */
|
|
86
|
+
label: string;
|
|
87
|
+
/** Fills the row of a host header (see the class docs): no bar background, rule, shadow or sticky positioning. */
|
|
88
|
+
embedded: boolean;
|
|
89
|
+
/** Marks the link for the section in view with `aria-current="location"` and an active style. */
|
|
90
|
+
scrollSpy: boolean;
|
|
91
|
+
/** The id of the section in view, from the IntersectionObserver. */
|
|
92
|
+
private activeId;
|
|
93
|
+
private observer?;
|
|
94
|
+
/** The sections the scroll spy measures (set while `scrollSpy` is on). */
|
|
95
|
+
private spyTargets;
|
|
96
|
+
private spyFrame;
|
|
97
|
+
/** Distance from the top of the viewport that counts as "passed", matching the 64px header row. */
|
|
98
|
+
private static readonly SPY_OFFSET;
|
|
99
|
+
/** Extra pixels past the offset line, so a section an anchor jump lands just under it (sub-pixel) still counts. */
|
|
100
|
+
private static readonly SPY_TOLERANCE;
|
|
101
|
+
connectedCallback(): void;
|
|
102
|
+
disconnectedCallback(): void;
|
|
103
|
+
protected updated(changed: Map<string, unknown>): void;
|
|
104
|
+
/** When the links row scrolls sideways (phones), keeps the current section's link in view. Only the
|
|
105
|
+
* row scrolls, never the page. */
|
|
106
|
+
private revealActiveLink;
|
|
107
|
+
/**
|
|
108
|
+
* Scroll spy: the section in view is the LAST one, in document order, whose top is at or above
|
|
109
|
+
* `SPY_OFFSET + SPY_TOLERANCE`. None above that line (above the first section) leaves no active id.
|
|
110
|
+
* At the bottom of the page the last section is active, even if its top never reaches the line.
|
|
111
|
+
*/
|
|
112
|
+
private updateScrollSpy;
|
|
113
|
+
/** Scroll spy re-checks on every scroll frame: an IntersectionObserver alone misses a long section passing the line. */
|
|
114
|
+
private onSpyScroll;
|
|
115
|
+
private stopSpyScroll;
|
|
116
|
+
/** Watches the sections the `#anchor` links point at, so the link for the one in view is current. */
|
|
117
|
+
private observe;
|
|
118
|
+
/** The product icon: the light image, plus the dark one (theme-switched) when `iconDark` is set. Alt is empty: the link text names the product. */
|
|
119
|
+
private renderIcon;
|
|
120
|
+
/** The site-menu button, before the action pill. Only with `site-menu-label`. */
|
|
121
|
+
private renderSiteMenu;
|
|
122
|
+
/** Dispatches `product-nav-site-menu`, with the button as the detail's `trigger`, for the host header to open its site menu. */
|
|
123
|
+
private onSiteMenuClick;
|
|
124
|
+
render(): lit.TemplateResult<1>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export { ProductNav, type ProductNavLink };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -3,21 +3,38 @@ import { LitElement } from 'lit';
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Rounded call-to-action banner (title, subtitle, one or two outlined buttons) on a dark panel or a
|
|
6
|
-
* background image.
|
|
7
|
-
*
|
|
8
|
-
* `
|
|
6
|
+
* background image. A button with an `href` is a real link (`<a href>`): the browser follows it
|
|
7
|
+
* unless the `action` event is cancelled, so external URLs, `#anchors` and `/path?x=y` work without
|
|
8
|
+
* JavaScript. A button without an `href` is a `<button>`. `variant="accent"` fills the banner with
|
|
9
|
+
* the brand colour.
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
+
* `cta-note` is a short line with a small padlock under the buttons (e.g. "No credit card needed"). In the
|
|
12
|
+
* inline layout it sits under the buttons in the right-hand group, left-aligned with the first button.
|
|
13
|
+
*
|
|
14
|
+
* `layout="inline"` sets the copy on the left and the buttons on the right of one row (wrapping on
|
|
15
|
+
* small screens), with 56px/48px padding (24px on phones). Its buttons are 52px pills; with
|
|
16
|
+
* `variant="accent"` the first is a white pill with navy text and the second a transparent pill with
|
|
17
|
+
* a light blue outline. `button-style="pill"` gives the buttons the same pill shape in the default
|
|
18
|
+
* `stack` layout, which is otherwise unchanged.
|
|
19
|
+
*
|
|
20
|
+
* @fires action - Cancelable, before following the link. Detail `{ href, kind? }`. `kind` is `secondary` for the second button only.
|
|
11
21
|
* @cssprop --st-promo-banner-margin - Overrides the banner's margin.
|
|
12
22
|
* @cssprop --st-promo-banner-padding - Overrides the banner's padding.
|
|
13
|
-
* @
|
|
23
|
+
* @cssprop --st-promo-banner-cta-note-color - Colour of the `cta-note` line (default `currentColor` at 85%).
|
|
24
|
+
* @csspart action - The primary button (`<a>` with an `href`, `<button>` without).
|
|
14
25
|
* @csspart secondary-action - The second button.
|
|
26
|
+
* @csspart cta-note - The small line with a padlock under the buttons (`cta-note`).
|
|
15
27
|
*/
|
|
16
28
|
declare class PromoBanner extends LitElement {
|
|
17
29
|
static styles: lit.CSSResult;
|
|
18
30
|
title: string;
|
|
19
31
|
subtitle: string;
|
|
20
32
|
actionLabel: string;
|
|
33
|
+
/** Shorter `action-label` for phones (< 480px); the full label stays the accessible name. */
|
|
34
|
+
actionLabelShort: string;
|
|
35
|
+
/** Shorter `secondary-action-label` for phones (< 480px). */
|
|
36
|
+
secondaryActionLabelShort: string;
|
|
37
|
+
/** Target of the first button. With a value the button is a link; the `action` event can cancel the navigation. */
|
|
21
38
|
href: string;
|
|
22
39
|
imageSrc: string;
|
|
23
40
|
/** Label of a second, outlined button next to the first. */
|
|
@@ -27,9 +44,19 @@ declare class PromoBanner extends LitElement {
|
|
|
27
44
|
/** `default` is the dark panel; `accent` fills the banner with the brand colour and makes the first button white. */
|
|
28
45
|
variant: 'default' | 'accent';
|
|
29
46
|
inverted: boolean;
|
|
47
|
+
/** `stack` (default) centres the copy above the buttons; `inline` puts the buttons beside the copy. */
|
|
48
|
+
layout: 'stack' | 'inline';
|
|
49
|
+
/** `default` keeps the plain buttons; `pill` gives them the 52px pill shape (`inline` always uses pills). */
|
|
50
|
+
buttonStyle: 'default' | 'pill';
|
|
51
|
+
/** Short line with a small check under the buttons (e.g. "No credit card needed"). Empty hides it. */
|
|
52
|
+
ctaNote: string;
|
|
53
|
+
/** Iconify icon for the `cta-note` line (e.g. `mdi:open-source-initiative`). Empty keeps the padlock. */
|
|
54
|
+
ctaNoteIcon: string;
|
|
30
55
|
protected willUpdate(): void;
|
|
31
|
-
|
|
32
|
-
private
|
|
56
|
+
/** Fires the cancelable `action` event; a cancelled click keeps the page where it is. */
|
|
57
|
+
private emitAction;
|
|
58
|
+
private renderCta;
|
|
59
|
+
private renderCopy;
|
|
33
60
|
render(): lit.TemplateResult<1>;
|
|
34
61
|
}
|
|
35
62
|
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PromoBanner
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-EW2RK5Y6.js";
|
|
4
|
+
import "../chunk-BEWX3E6P.js";
|
|
5
|
+
import "../chunk-T4BIN37Q.js";
|
|
6
|
+
import "../chunk-WTD2YIAA.js";
|
|
7
|
+
import "../chunk-KZ7PMFWS.js";
|
|
8
|
+
import "../chunk-NXUS2CH7.js";
|
|
6
9
|
import "../chunk-EUXUH3YW.js";
|
|
7
10
|
export {
|
|
8
11
|
PromoBanner
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import * as lit from 'lit';
|
|
2
|
+
import { LitElement } from 'lit';
|
|
3
|
+
|
|
4
|
+
interface QuoteOption {
|
|
5
|
+
id: string;
|
|
6
|
+
label: string;
|
|
7
|
+
hint?: string;
|
|
8
|
+
/** Short name for the e-mail subject's `{option}` (e.g. "Cloud" for "Cloud (SaaS)"). Defaults to `label`. */
|
|
9
|
+
subjectLabel?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A quote-request dialog: radio cards for the kind of request, then name, e-mail, company, a user
|
|
13
|
+
* count, an optional message and a required consent box. It opens when a window `st-quote-open`
|
|
14
|
+
* event names its `id` (`st-plan-cards` does this on a button click), with that option preselected.
|
|
15
|
+
*
|
|
16
|
+
* It is a native `<dialog>` opened with `showModal()`, so focus is trapped, Esc closes it and the page
|
|
17
|
+
* behind is inert. Closing (Esc, the close button or a click on the backdrop) returns focus to the
|
|
18
|
+
* element that opened it. While open, `<html>` carries `data-st-modal-open` (removed on every close and
|
|
19
|
+
* on disconnect), so other fixed page UI such as `st-cookie-consent` steps aside.
|
|
20
|
+
* Submitting checks the fields, opens a `mailto:` message to `mailto` with
|
|
21
|
+
* every answer in the body, dispatches `quote-submit` and shows `success-title` / `success-text`
|
|
22
|
+
* (`{option}` in the text becomes the chosen option's label). Without `mailto` nothing is opened and
|
|
23
|
+
* the success state still shows. `subject` may use `{option}` (the option's `subjectLabel`, else its
|
|
24
|
+
* label), `{company}` and `{name}`. `mailto-note` is shown under the success text (`{email}` becomes
|
|
25
|
+
* the `mailto` address, as a link) with a button that copies the address, for visitors whose mail
|
|
26
|
+
* app did not open. An empty `consent-label` leaves out the consent box.
|
|
27
|
+
*
|
|
28
|
+
* The element's `id` is the dialog name: set it on the JSON node (`"id": "quote"`), and point
|
|
29
|
+
* `quoteDialog` on a `st-plan-cards` at the same value.
|
|
30
|
+
*
|
|
31
|
+
* @fires quote-submit - Bubbles and is composed. Detail `{ option, name, email, company, count, message, consent }`.
|
|
32
|
+
* @cssprop --st-quote-dialog-backdrop - Colour of the backdrop behind the dialog (default a navy at 55%).
|
|
33
|
+
* @csspart dialog - The native dialog.
|
|
34
|
+
* @csspart form - The request form.
|
|
35
|
+
* @csspart submit - The submit button.
|
|
36
|
+
* @csspart close - The close button.
|
|
37
|
+
*/
|
|
38
|
+
declare class QuoteDialog extends LitElement {
|
|
39
|
+
static styles: lit.CSSResult;
|
|
40
|
+
/** Heading of the dialog (an `<h2>`, named by the dialog). */
|
|
41
|
+
title: string;
|
|
42
|
+
subtitle: string;
|
|
43
|
+
/** The radio cards for the kind of request. */
|
|
44
|
+
options: QuoteOption[];
|
|
45
|
+
optionsLabel: string;
|
|
46
|
+
nameLabel: string;
|
|
47
|
+
namePlaceholder: string;
|
|
48
|
+
emailLabel: string;
|
|
49
|
+
emailPlaceholder: string;
|
|
50
|
+
companyLabel: string;
|
|
51
|
+
companyPlaceholder: string;
|
|
52
|
+
countLabel: string;
|
|
53
|
+
countPlaceholder: string;
|
|
54
|
+
/** Label of the optional message box. "(optional)" is appended. */
|
|
55
|
+
messageLabel: string;
|
|
56
|
+
messagePlaceholder: string;
|
|
57
|
+
consentLabel: string;
|
|
58
|
+
submitLabel: string;
|
|
59
|
+
successTitle: string;
|
|
60
|
+
/** Shown after submitting. `{option}` is replaced with the chosen option's label. */
|
|
61
|
+
successText: string;
|
|
62
|
+
closeLabel: string;
|
|
63
|
+
/** Recipient of the request e-mail. Without it, submitting opens no e-mail. */
|
|
64
|
+
mailto: string;
|
|
65
|
+
/** Subject of the request e-mail. `{option}`, `{company}` and `{name}` are filled in. */
|
|
66
|
+
subject: string;
|
|
67
|
+
/** Shown under the success text when `mailto` is set. `{email}` becomes the address as a link. Empty hides it. */
|
|
68
|
+
mailtoNote: string;
|
|
69
|
+
copyLabel: string;
|
|
70
|
+
copiedLabel: string;
|
|
71
|
+
private selected;
|
|
72
|
+
private copied;
|
|
73
|
+
private submitted;
|
|
74
|
+
private errors;
|
|
75
|
+
private submittedOption;
|
|
76
|
+
private dialogEl?;
|
|
77
|
+
private formEl?;
|
|
78
|
+
private trigger;
|
|
79
|
+
connectedCallback(): void;
|
|
80
|
+
disconnectedCallback(): void;
|
|
81
|
+
/** Opens for `st-quote-open` events aimed at this dialog's `id`. */
|
|
82
|
+
private onOpenRequest;
|
|
83
|
+
/** Renders the reset form first, so every open starts empty, then shows the modal. */
|
|
84
|
+
private open;
|
|
85
|
+
private close;
|
|
86
|
+
/** Runs on every close (Esc, the close button, the backdrop): focus goes back to the opener. */
|
|
87
|
+
private onDialogClose;
|
|
88
|
+
private onBackdropClick;
|
|
89
|
+
private fieldValue;
|
|
90
|
+
private validate;
|
|
91
|
+
private onSubmit;
|
|
92
|
+
private renderField;
|
|
93
|
+
/** One sentence listing every failing field, for the live region ("" when valid). */
|
|
94
|
+
private errorSummary;
|
|
95
|
+
private renderForm;
|
|
96
|
+
private renderConsent;
|
|
97
|
+
private copyAddress;
|
|
98
|
+
/** The mailto note with `{email}` as a link to the address. */
|
|
99
|
+
private renderMailtoNote;
|
|
100
|
+
private renderSuccess;
|
|
101
|
+
render(): lit.TemplateResult<1>;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Window-level event that asks a `st-quote-dialog` with the matching `id` to open. */
|
|
105
|
+
declare const QUOTE_OPEN_EVENT = "st-quote-open";
|
|
106
|
+
/** Detail of `st-quote-open`. `trigger` is the element that opened the dialog; focus returns to it on close. */
|
|
107
|
+
interface QuoteOpenEventDetail {
|
|
108
|
+
/** The `id` of the `st-quote-dialog` to open. */
|
|
109
|
+
dialog: string;
|
|
110
|
+
/** Option to preselect (an option `id`, or `unsure`). */
|
|
111
|
+
option?: string;
|
|
112
|
+
trigger?: HTMLElement | null;
|
|
113
|
+
}
|
|
114
|
+
/** Detail of the `quote-submit` event: the chosen option and every field the visitor filled in. */
|
|
115
|
+
interface QuoteSubmitEventDetail {
|
|
116
|
+
option: string;
|
|
117
|
+
name: string;
|
|
118
|
+
email: string;
|
|
119
|
+
company: string;
|
|
120
|
+
count: string;
|
|
121
|
+
message: string;
|
|
122
|
+
consent: boolean;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** One labelled line of a `mailto:` body. */
|
|
126
|
+
interface MailtoField {
|
|
127
|
+
label: string;
|
|
128
|
+
value: string;
|
|
129
|
+
}
|
|
130
|
+
interface MailtoInput {
|
|
131
|
+
/** Recipient address. */
|
|
132
|
+
to: string;
|
|
133
|
+
subject: string;
|
|
134
|
+
/** Written into the body as one `Label: value` line each, in order. */
|
|
135
|
+
fields: MailtoField[];
|
|
136
|
+
/**
|
|
137
|
+
* Longest the percent-encoded body may be (default 1800). Mail apps and browsers cut off long
|
|
138
|
+
* `mailto:` URLs, so the field picked by `truncateField` is shortened with "…" until the body fits.
|
|
139
|
+
*/
|
|
140
|
+
maxBodyLength?: number;
|
|
141
|
+
/** Index of the field to shorten when the body is too long (default: the last field). */
|
|
142
|
+
truncateField?: number;
|
|
143
|
+
}
|
|
144
|
+
declare const DEFAULT_MAILTO_BODY_LIMIT = 1800;
|
|
145
|
+
/**
|
|
146
|
+
* Builds a `mailto:` URL whose body is plain text: one `Label: value` line per field (an empty value
|
|
147
|
+
* is written as `-`). Subject and body are percent-encoded, so line breaks and symbols survive the
|
|
148
|
+
* URL. When the encoded body is longer than `maxBodyLength`, one field (the last, unless
|
|
149
|
+
* `truncateField` says otherwise) is cut short, on a character boundary, and ends in "…".
|
|
150
|
+
*/
|
|
151
|
+
declare function buildMailto({ to, subject, fields, maxBodyLength, truncateField }: MailtoInput): string;
|
|
152
|
+
|
|
153
|
+
/** One labelled line of the request e-mail. */
|
|
154
|
+
type QuoteMailField = MailtoField;
|
|
155
|
+
interface QuoteMailtoInput {
|
|
156
|
+
/** Recipient address. */
|
|
157
|
+
to: string;
|
|
158
|
+
subject: string;
|
|
159
|
+
/** Human label of the chosen option, written into the body. */
|
|
160
|
+
optionLabel: string;
|
|
161
|
+
fields: QuoteMailField[];
|
|
162
|
+
/** Longest the encoded body may be; the last field is shortened with "…" to fit (default 1800). */
|
|
163
|
+
maxBodyLength?: number;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Builds a `mailto:` URL whose body is plain text: the chosen option, then one `Label: value` line
|
|
167
|
+
* per field (see `buildMailto`). Subject and body are percent-encoded, so line breaks and symbols
|
|
168
|
+
* survive the URL. An empty value is written as `-`.
|
|
169
|
+
*/
|
|
170
|
+
declare function buildQuoteMailto({ to, subject, optionLabel, fields, maxBodyLength }: QuoteMailtoInput): string;
|
|
171
|
+
/** Fills `{name}` placeholders in a subject or text line; unknown names are left as they are. */
|
|
172
|
+
declare function fillTemplate(template: string, values: Record<string, string>): string;
|
|
173
|
+
|
|
174
|
+
export { DEFAULT_MAILTO_BODY_LIMIT, type MailtoField, type MailtoInput, QUOTE_OPEN_EVENT, QuoteDialog, type QuoteMailField, type QuoteMailtoInput, type QuoteOpenEventDetail, type QuoteOption, type QuoteSubmitEventDetail, buildMailto, buildQuoteMailto, fillTemplate };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_MAILTO_BODY_LIMIT,
|
|
3
|
+
QuoteDialog,
|
|
4
|
+
buildMailto,
|
|
5
|
+
buildQuoteMailto,
|
|
6
|
+
fillTemplate
|
|
7
|
+
} from "../chunk-AYNT7G3J.js";
|
|
8
|
+
import {
|
|
9
|
+
QUOTE_OPEN_EVENT
|
|
10
|
+
} from "../chunk-FOUK3NHR.js";
|
|
11
|
+
import "../chunk-WAMOAAMN.js";
|
|
12
|
+
import "../chunk-NXUS2CH7.js";
|
|
13
|
+
import "../chunk-EUXUH3YW.js";
|
|
14
|
+
export {
|
|
15
|
+
DEFAULT_MAILTO_BODY_LIMIT,
|
|
16
|
+
QUOTE_OPEN_EVENT,
|
|
17
|
+
QuoteDialog,
|
|
18
|
+
buildMailto,
|
|
19
|
+
buildQuoteMailto,
|
|
20
|
+
fillTemplate
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/schema/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ interface NodeEnvelope<TNode> {
|
|
|
8
8
|
slot?: string;
|
|
9
9
|
/** Editor-only label, never passed to the component. */
|
|
10
10
|
label?: string;
|
|
11
|
+
/** `false` leaves the node (and its children) out of the rendered page. Omit, or `true`, to show it. Never passed to the component. */
|
|
12
|
+
visible?: boolean;
|
|
11
13
|
children?: TNode[];
|
|
12
14
|
}
|
|
13
15
|
/**
|
|
@@ -38,8 +40,10 @@ declare const componentTags: {
|
|
|
38
40
|
readonly Card: "st-card";
|
|
39
41
|
readonly AttentionPanel: "st-attention-panel";
|
|
40
42
|
readonly BarChart: "st-bar-chart";
|
|
43
|
+
readonly Booking: "st-booking";
|
|
41
44
|
readonly Carousel: "st-carousel";
|
|
42
45
|
readonly Chip: "st-chip";
|
|
46
|
+
readonly ContactForm: "st-contact-form";
|
|
43
47
|
readonly ContentBlock: "st-content-block";
|
|
44
48
|
readonly CookieConsent: "st-cookie-consent";
|
|
45
49
|
readonly DateTile: "st-date-tile";
|
|
@@ -60,7 +64,11 @@ declare const componentTags: {
|
|
|
60
64
|
readonly MenuGrid: "st-menu-grid";
|
|
61
65
|
readonly MenuGridItem: "st-menu-grid-item";
|
|
62
66
|
readonly MenuItem: "st-menu-item";
|
|
67
|
+
readonly PlanCards: "st-plan-cards";
|
|
68
|
+
readonly ProductNav: "st-product-nav";
|
|
63
69
|
readonly PromoBanner: "st-promo-banner";
|
|
70
|
+
readonly QuoteDialog: "st-quote-dialog";
|
|
71
|
+
readonly ScreenshotTour: "st-screenshot-tour";
|
|
64
72
|
readonly SegmentedControl: "st-segmented-control";
|
|
65
73
|
readonly Section: "st-section";
|
|
66
74
|
readonly Select: "st-select";
|
package/dist/schema/index.js
CHANGED
|
@@ -19,8 +19,10 @@ var componentTags = {
|
|
|
19
19
|
Card: "st-card",
|
|
20
20
|
AttentionPanel: "st-attention-panel",
|
|
21
21
|
BarChart: "st-bar-chart",
|
|
22
|
+
Booking: "st-booking",
|
|
22
23
|
Carousel: "st-carousel",
|
|
23
24
|
Chip: "st-chip",
|
|
25
|
+
ContactForm: "st-contact-form",
|
|
24
26
|
ContentBlock: "st-content-block",
|
|
25
27
|
CookieConsent: "st-cookie-consent",
|
|
26
28
|
DateTile: "st-date-tile",
|
|
@@ -41,7 +43,11 @@ var componentTags = {
|
|
|
41
43
|
MenuGrid: "st-menu-grid",
|
|
42
44
|
MenuGridItem: "st-menu-grid-item",
|
|
43
45
|
MenuItem: "st-menu-item",
|
|
46
|
+
PlanCards: "st-plan-cards",
|
|
47
|
+
ProductNav: "st-product-nav",
|
|
44
48
|
PromoBanner: "st-promo-banner",
|
|
49
|
+
QuoteDialog: "st-quote-dialog",
|
|
50
|
+
ScreenshotTour: "st-screenshot-tour",
|
|
45
51
|
SegmentedControl: "st-segmented-control",
|
|
46
52
|
Section: "st-section",
|
|
47
53
|
Select: "st-select",
|
package/dist/schema/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/schema/node.ts","../../src/schema/nodeUtils.ts","../../src/schema/components.ts","../../src/schema/validate.ts"],"sourcesContent":["/** Dependency-free node types, safe to import from the content API layer. */\n\n/** Action reference in JSON, resolved against the `handlers` prop of `DynamicRenderer`. */\nexport type ActionRef = `@action:${string}`;\n\n/** Keys the renderer owns; everything else on a node is passed to the component as a prop. */\nexport interface NodeEnvelope<TNode> {\n id?: string;\n /** Named slot in the parent (e.g. Header: \"utility\"). Omit for the default slot. */\n slot?: string;\n /** Editor-only label, never passed to the component. */\n label?: string;\n children?: TNode[];\n}\n\n/**\n * A node as it appears in JSON: flat, no `data` wrapper.\n * `{ \"type\": \"Hero\", \"id\": \"home-hero\", \"title\": \"...\", \"children\": [...] }`\n */\nexport interface ComponentNode extends NodeEnvelope<ComponentNode> {\n type: string;\n [prop: string]: unknown;\n}\n\n/** A page is a list of nodes. */\nexport type PageContent = ComponentNode[];\n\nexport function isComponentNode(value: unknown): value is ComponentNode {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n typeof (value as { type?: unknown }).type === 'string' &&\n (value as { type: string }).type.trim().length > 0\n );\n}\n","import type { ComponentNode } from './node';\n\n/**\n * Returns a copy of `nodes` where the node with the given `id` has `props` merged in.\n * Use it to inject runtime state (e.g. the selected language) into fetched JSON without mutating it.\n */\nexport function patchNodeById(nodes: ComponentNode[], id: string, props: Record<string, unknown>): ComponentNode[] {\n return nodes.map(node => {\n const patched = node.id === id ? { ...node, ...props } : node;\n return patched.children\n ? { ...patched, children: patchNodeById(patched.children, id, props) }\n : patched;\n });\n}\n","/**\n * The JSON `type` of every base component, and the Lit element that renders it.\n * This is the contract page JSON is written against — renderers (React, or any other binding)\n * map each `type` to their own component for that element.\n */\nexport const componentTags = {\n BentoGrid: 'st-bento-grid',\n Card: 'st-card',\n AttentionPanel: 'st-attention-panel',\n BarChart: 'st-bar-chart',\n Carousel: 'st-carousel',\n Chip: 'st-chip',\n ContentBlock: 'st-content-block',\n CookieConsent: 'st-cookie-consent',\n DateTile: 'st-date-tile',\n Dropdown: 'st-dropdown',\n FeatureItem: 'st-feature-item',\n FeatureSplit: 'st-feature-split',\n FeaturesSection: 'st-features-section',\n Flow: 'st-flow',\n Footer: 'st-footer',\n Header: 'st-header',\n Hero: 'st-hero',\n IconButton: 'st-icon-button',\n ItemsAccordion: 'st-items-accordion',\n KpiCard: 'st-kpi-card',\n MegaMenu: 'st-mega-menu',\n MegaMenuColumn: 'st-mega-menu-column',\n MegaMenuFeature: 'st-mega-menu-feature',\n MenuGrid: 'st-menu-grid',\n MenuGridItem: 'st-menu-grid-item',\n MenuItem: 'st-menu-item',\n PromoBanner: 'st-promo-banner',\n SegmentedControl: 'st-segmented-control',\n Section: 'st-section',\n Select: 'st-select',\n Stats: 'st-stats',\n Steps: 'st-steps',\n TagStrip: 'st-tag-strip',\n Testimonials: 'st-testimonials'\n} as const;\n\n/** Every `type` the base set knows. */\nexport type ComponentType = keyof typeof componentTags;\n\nexport function isBaseComponentType(type: string): type is ComponentType {\n return Object.hasOwn(componentTags, type);\n}\n","import { isBaseComponentType } from './components';\nimport type { ComponentNode } from './node';\n\n/** Keys from the pre-flat schema; their presence means the JSON still needs `scripts/migrate-json.mjs`. */\nconst LEGACY_KEYS = ['data', 'embeddedView', 'data-position', 'image', 'contentUrl'] as const;\n\n/**\n * Returns the schema violations for a node and its descendants (empty when valid).\n * `isKnownType` defaults to the base component set; pass a wider predicate when a renderer also\n * registers custom components.\n */\nexport function validateNode(node: unknown, where = 'node', isKnownType: (type: string) => boolean = isBaseComponentType): string[] {\n if (typeof node !== 'object' || node === null || Array.isArray(node)) return [`${where}: node must be an object`];\n const n = node as ComponentNode;\n const found: string[] = [];\n if (typeof n.type !== 'string' || !isKnownType(n.type)) found.push(`${where}: unknown type \"${String(n.type)}\"`);\n for (const legacy of LEGACY_KEYS) {\n if (legacy in n) found.push(`${where}: legacy key \"${legacy}\"`);\n }\n if (Array.isArray(n.items) && n.items.some(item => typeof item === 'object' && item !== null && 'type' in item)) {\n found.push(`${where}: \"items\" must hold plain data; nest components under \"children\"`);\n }\n if (n.children !== undefined) {\n if (!Array.isArray(n.children)) found.push(`${where}: children must be an array`);\n else n.children.forEach((child, i) => found.push(...validateNode(child, `${where}.children[${i}]`, isKnownType)));\n }\n return found;\n}\n\n/** Validates a page: a node or a list of nodes. */\nexport function validatePage(page: unknown, isKnownType?: (type: string) => boolean): string[] {\n const nodes = Array.isArray(page) ? page : [page];\n return nodes.flatMap((node, i) => validateNode(node, `[${i}]`, isKnownType));\n}\n"],"mappings":";;;
|
|
1
|
+
{"version":3,"sources":["../../src/schema/node.ts","../../src/schema/nodeUtils.ts","../../src/schema/components.ts","../../src/schema/validate.ts"],"sourcesContent":["/** Dependency-free node types, safe to import from the content API layer. */\n\n/** Action reference in JSON, resolved against the `handlers` prop of `DynamicRenderer`. */\nexport type ActionRef = `@action:${string}`;\n\n/** Keys the renderer owns; everything else on a node is passed to the component as a prop. */\nexport interface NodeEnvelope<TNode> {\n id?: string;\n /** Named slot in the parent (e.g. Header: \"utility\"). Omit for the default slot. */\n slot?: string;\n /** Editor-only label, never passed to the component. */\n label?: string;\n /** `false` leaves the node (and its children) out of the rendered page. Omit, or `true`, to show it. Never passed to the component. */\n visible?: boolean;\n children?: TNode[];\n}\n\n/**\n * A node as it appears in JSON: flat, no `data` wrapper.\n * `{ \"type\": \"Hero\", \"id\": \"home-hero\", \"title\": \"...\", \"children\": [...] }`\n */\nexport interface ComponentNode extends NodeEnvelope<ComponentNode> {\n type: string;\n [prop: string]: unknown;\n}\n\n/** A page is a list of nodes. */\nexport type PageContent = ComponentNode[];\n\nexport function isComponentNode(value: unknown): value is ComponentNode {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n typeof (value as { type?: unknown }).type === 'string' &&\n (value as { type: string }).type.trim().length > 0\n );\n}\n","import type { ComponentNode } from './node';\n\n/**\n * Returns a copy of `nodes` where the node with the given `id` has `props` merged in.\n * Use it to inject runtime state (e.g. the selected language) into fetched JSON without mutating it.\n */\nexport function patchNodeById(nodes: ComponentNode[], id: string, props: Record<string, unknown>): ComponentNode[] {\n return nodes.map(node => {\n const patched = node.id === id ? { ...node, ...props } : node;\n return patched.children\n ? { ...patched, children: patchNodeById(patched.children, id, props) }\n : patched;\n });\n}\n","/**\n * The JSON `type` of every base component, and the Lit element that renders it.\n * This is the contract page JSON is written against — renderers (React, or any other binding)\n * map each `type` to their own component for that element.\n */\nexport const componentTags = {\n BentoGrid: 'st-bento-grid',\n Card: 'st-card',\n AttentionPanel: 'st-attention-panel',\n BarChart: 'st-bar-chart',\n Booking: 'st-booking',\n Carousel: 'st-carousel',\n Chip: 'st-chip',\n ContactForm: 'st-contact-form',\n ContentBlock: 'st-content-block',\n CookieConsent: 'st-cookie-consent',\n DateTile: 'st-date-tile',\n Dropdown: 'st-dropdown',\n FeatureItem: 'st-feature-item',\n FeatureSplit: 'st-feature-split',\n FeaturesSection: 'st-features-section',\n Flow: 'st-flow',\n Footer: 'st-footer',\n Header: 'st-header',\n Hero: 'st-hero',\n IconButton: 'st-icon-button',\n ItemsAccordion: 'st-items-accordion',\n KpiCard: 'st-kpi-card',\n MegaMenu: 'st-mega-menu',\n MegaMenuColumn: 'st-mega-menu-column',\n MegaMenuFeature: 'st-mega-menu-feature',\n MenuGrid: 'st-menu-grid',\n MenuGridItem: 'st-menu-grid-item',\n MenuItem: 'st-menu-item',\n PlanCards: 'st-plan-cards',\n ProductNav: 'st-product-nav',\n PromoBanner: 'st-promo-banner',\n QuoteDialog: 'st-quote-dialog',\n ScreenshotTour: 'st-screenshot-tour',\n SegmentedControl: 'st-segmented-control',\n Section: 'st-section',\n Select: 'st-select',\n Stats: 'st-stats',\n Steps: 'st-steps',\n TagStrip: 'st-tag-strip',\n Testimonials: 'st-testimonials'\n} as const;\n\n/** Every `type` the base set knows. */\nexport type ComponentType = keyof typeof componentTags;\n\nexport function isBaseComponentType(type: string): type is ComponentType {\n return Object.hasOwn(componentTags, type);\n}\n","import { isBaseComponentType } from './components';\nimport type { ComponentNode } from './node';\n\n/** Keys from the pre-flat schema; their presence means the JSON still needs `scripts/migrate-json.mjs`. */\nconst LEGACY_KEYS = ['data', 'embeddedView', 'data-position', 'image', 'contentUrl'] as const;\n\n/**\n * Returns the schema violations for a node and its descendants (empty when valid).\n * `isKnownType` defaults to the base component set; pass a wider predicate when a renderer also\n * registers custom components.\n */\nexport function validateNode(node: unknown, where = 'node', isKnownType: (type: string) => boolean = isBaseComponentType): string[] {\n if (typeof node !== 'object' || node === null || Array.isArray(node)) return [`${where}: node must be an object`];\n const n = node as ComponentNode;\n const found: string[] = [];\n if (typeof n.type !== 'string' || !isKnownType(n.type)) found.push(`${where}: unknown type \"${String(n.type)}\"`);\n for (const legacy of LEGACY_KEYS) {\n if (legacy in n) found.push(`${where}: legacy key \"${legacy}\"`);\n }\n if (Array.isArray(n.items) && n.items.some(item => typeof item === 'object' && item !== null && 'type' in item)) {\n found.push(`${where}: \"items\" must hold plain data; nest components under \"children\"`);\n }\n if (n.children !== undefined) {\n if (!Array.isArray(n.children)) found.push(`${where}: children must be an array`);\n else n.children.forEach((child, i) => found.push(...validateNode(child, `${where}.children[${i}]`, isKnownType)));\n }\n return found;\n}\n\n/** Validates a page: a node or a list of nodes. */\nexport function validatePage(page: unknown, isKnownType?: (type: string) => boolean): string[] {\n const nodes = Array.isArray(page) ? page : [page];\n return nodes.flatMap((node, i) => validateNode(node, `[${i}]`, isKnownType));\n}\n"],"mappings":";;;AA6BO,SAAS,gBAAgB,OAAwC;AACpE,SACI,OAAO,UAAU,YACjB,UAAU,QACV,CAAC,MAAM,QAAQ,KAAK,KACpB,OAAQ,MAA6B,SAAS,YAC7C,MAA2B,KAAK,KAAK,EAAE,SAAS;AAEzD;;;AC/BO,SAAS,cAAc,OAAwB,IAAY,OAAiD;AAC/G,SAAO,MAAM,IAAI,UAAQ;AACrB,UAAM,UAAU,KAAK,OAAO,KAAK,EAAE,GAAG,MAAM,GAAG,MAAM,IAAI;AACzD,WAAO,QAAQ,WACT,EAAE,GAAG,SAAS,UAAU,cAAc,QAAQ,UAAU,IAAI,KAAK,EAAE,IACnE;AAAA,EACV,CAAC;AACL;;;ACRO,IAAM,gBAAgB;AAAA,EACzB,WAAW;AAAA,EACX,MAAM;AAAA,EACN,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,SAAS;AAAA,EACT,UAAU;AAAA,EACV,MAAM;AAAA,EACN,aAAa;AAAA,EACb,cAAc;AAAA,EACd,eAAe;AAAA,EACf,UAAU;AAAA,EACV,UAAU;AAAA,EACV,aAAa;AAAA,EACb,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,SAAS;AAAA,EACT,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,cAAc;AAAA,EACd,UAAU;AAAA,EACV,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AAAA,EACP,UAAU;AAAA,EACV,cAAc;AAClB;AAKO,SAAS,oBAAoB,MAAqC;AACrE,SAAO,OAAO,OAAO,eAAe,IAAI;AAC5C;;;ACjDA,IAAM,cAAc,CAAC,QAAQ,gBAAgB,iBAAiB,SAAS,YAAY;AAO5E,SAAS,aAAa,MAAe,QAAQ,QAAQ,cAAyC,qBAA+B;AAChI,MAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,QAAQ,IAAI,EAAG,QAAO,CAAC,GAAG,KAAK,0BAA0B;AAChH,QAAM,IAAI;AACV,QAAM,QAAkB,CAAC;AACzB,MAAI,OAAO,EAAE,SAAS,YAAY,CAAC,YAAY,EAAE,IAAI,EAAG,OAAM,KAAK,GAAG,KAAK,mBAAmB,OAAO,EAAE,IAAI,CAAC,GAAG;AAC/G,aAAW,UAAU,aAAa;AAC9B,QAAI,UAAU,EAAG,OAAM,KAAK,GAAG,KAAK,iBAAiB,MAAM,GAAG;AAAA,EAClE;AACA,MAAI,MAAM,QAAQ,EAAE,KAAK,KAAK,EAAE,MAAM,KAAK,UAAQ,OAAO,SAAS,YAAY,SAAS,QAAQ,UAAU,IAAI,GAAG;AAC7G,UAAM,KAAK,GAAG,KAAK,kEAAkE;AAAA,EACzF;AACA,MAAI,EAAE,aAAa,QAAW;AAC1B,QAAI,CAAC,MAAM,QAAQ,EAAE,QAAQ,EAAG,OAAM,KAAK,GAAG,KAAK,6BAA6B;AAAA,QAC3E,GAAE,SAAS,QAAQ,CAAC,OAAO,MAAM,MAAM,KAAK,GAAG,aAAa,OAAO,GAAG,KAAK,aAAa,CAAC,KAAK,WAAW,CAAC,CAAC;AAAA,EACpH;AACA,SAAO;AACX;AAGO,SAAS,aAAa,MAAe,aAAmD;AAC3F,QAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;AAChD,SAAO,MAAM,QAAQ,CAAC,MAAM,MAAM,aAAa,MAAM,IAAI,CAAC,KAAK,WAAW,CAAC;AAC/E;","names":[]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as lit from 'lit';
|
|
2
|
+
import { LitElement } from 'lit';
|
|
3
|
+
|
|
4
|
+
interface ScreenshotTourItem {
|
|
5
|
+
/** Text on the tab button that selects this screen. */
|
|
6
|
+
label: string;
|
|
7
|
+
/** Small uppercase line above the title (e.g. "Step 2"). */
|
|
8
|
+
step?: string;
|
|
9
|
+
/** Heading shown under the screenshot. */
|
|
10
|
+
title: string;
|
|
11
|
+
/** Body text shown under the heading. */
|
|
12
|
+
caption?: string;
|
|
13
|
+
/** Screenshot URL. */
|
|
14
|
+
src: string;
|
|
15
|
+
/** Alternative text for the screenshot. */
|
|
16
|
+
alt: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A product tour: a row of tab buttons, one per screenshot, and below it the selected screenshot
|
|
20
|
+
* in a framed figure with its step, title and caption. Only the selected screen is shown; the
|
|
21
|
+
* others are not rendered in the document flow.
|
|
22
|
+
*
|
|
23
|
+
* Keyboard (on the tab row): Arrow Right/Down moves to the next tab and Arrow Left/Up to the
|
|
24
|
+
* previous one, both wrapping at the ends; Home and End jump to the first and last tab. Each of
|
|
25
|
+
* these moves focus to the tab and selects it. Tab and Shift+Tab move through the tabs as usual.
|
|
26
|
+
* On narrow screens the tab row scrolls sideways (it never scrolls the page vertically).
|
|
27
|
+
*
|
|
28
|
+
* @csspart tabs - The row of tab buttons (`role="group"`).
|
|
29
|
+
* @csspart tab - Each tab button. Selected tabs carry `aria-pressed="true"`.
|
|
30
|
+
* @csspart figure - The `figure` holding the screenshot and its caption.
|
|
31
|
+
* @csspart frame - The bordered frame around the screenshot.
|
|
32
|
+
* @csspart image - The screenshot `img`.
|
|
33
|
+
* @csspart caption - The `figcaption` with the text beside (or below, on narrow screens) the image.
|
|
34
|
+
* @csspart step - The small eyebrow line above the title.
|
|
35
|
+
* @csspart title - The screen's heading.
|
|
36
|
+
* @csspart text - The caption paragraph.
|
|
37
|
+
*/
|
|
38
|
+
declare class ScreenshotTour extends LitElement {
|
|
39
|
+
static styles: lit.CSSResult;
|
|
40
|
+
/** The screens, in tab order. */
|
|
41
|
+
items: ScreenshotTourItem[];
|
|
42
|
+
/** Accessible name for the tab group. */
|
|
43
|
+
label: string;
|
|
44
|
+
/** Index of the selected screen. Clamped to the range of `items`. */
|
|
45
|
+
private active;
|
|
46
|
+
/** The selected index, kept inside the range of `items`. */
|
|
47
|
+
private get current();
|
|
48
|
+
private tabButtons;
|
|
49
|
+
private select;
|
|
50
|
+
private onKeydown;
|
|
51
|
+
render(): lit.TemplateResult<1>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { ScreenshotTour, type ScreenshotTourItem };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/section/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Section
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-GOFSMD6W.js";
|
|
4
|
+
import "../chunk-KZ7PMFWS.js";
|
|
5
|
+
import "../chunk-NXUS2CH7.js";
|
|
6
6
|
import "../chunk-EUXUH3YW.js";
|
|
7
7
|
export {
|
|
8
8
|
Section
|
package/dist/select/index.js
CHANGED