brand-shell 0.10.0 → 0.12.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/dist/brand-shell.schema.json +22 -3
- package/dist/default.css +38 -19
- package/dist/index.d.mts +21 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +61 -23
- package/dist/index.mjs.map +1 -1
- package/dist/svelte.d.mts +1 -1
- package/dist/svelte.mjs +1 -1
- package/dist/{types-PQziYg7Z.d.mts → types-B_CLRZMO.d.mts} +27 -3
- package/dist/types-B_CLRZMO.d.mts.map +1 -0
- package/dist/{validation-xdqzwr3p.mjs → validation-CtH2UkVv.mjs} +90 -39
- package/dist/validation-CtH2UkVv.mjs.map +1 -0
- package/dist/vue.d.mts +22 -2
- package/dist/vue.d.mts.map +1 -1
- package/dist/vue.mjs +9 -3
- package/dist/vue.mjs.map +1 -1
- package/dist/web.d.mts +17 -5
- package/dist/web.d.mts.map +1 -1
- package/dist/web.mjs +76 -32
- package/dist/web.mjs.map +1 -1
- package/package.json +6 -4
- package/src/svelte/BrandFooter.svelte +24 -0
- package/src/svelte/BrandHeader.svelte +24 -0
- package/src/svelte/index.svelte.ts +4 -0
- package/dist/types-PQziYg7Z.d.mts.map +0 -1
- package/dist/validation-xdqzwr3p.mjs.map +0 -1
|
@@ -15,6 +15,17 @@
|
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"$defs": {
|
|
18
|
+
"CustomSocialLink": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"required": ["platform", "href", "label"],
|
|
22
|
+
"properties": {
|
|
23
|
+
"platform": { "type": "string", "minLength": 1 },
|
|
24
|
+
"href": { "type": "string", "minLength": 1 },
|
|
25
|
+
"label": { "type": "string", "minLength": 1 },
|
|
26
|
+
"iconSvg": { "type": "string", "minLength": 1 }
|
|
27
|
+
}
|
|
28
|
+
},
|
|
18
29
|
"Target": {
|
|
19
30
|
"type": "string",
|
|
20
31
|
"enum": ["_blank", "_self", "_parent", "_top"]
|
|
@@ -63,12 +74,16 @@
|
|
|
63
74
|
"primaryAction": { "$ref": "#/$defs/BrandAction" },
|
|
64
75
|
"secondaryAction": { "$ref": "#/$defs/BrandAction" },
|
|
65
76
|
"linkedin": { "type": "string", "minLength": 1 },
|
|
66
|
-
"
|
|
77
|
+
"email": { "type": "string", "minLength": 1 },
|
|
67
78
|
"github": { "type": "string", "minLength": 1 },
|
|
68
79
|
"twitter": { "type": "string", "minLength": 1 },
|
|
69
80
|
"discord": { "type": "string", "minLength": 1 },
|
|
70
81
|
"website": { "type": "string", "minLength": 1 },
|
|
71
|
-
"tagline": { "type": "string", "minLength": 1 }
|
|
82
|
+
"tagline": { "type": "string", "minLength": 1 },
|
|
83
|
+
"customSocialLinks": {
|
|
84
|
+
"type": "array",
|
|
85
|
+
"items": { "$ref": "#/$defs/CustomSocialLink" }
|
|
86
|
+
}
|
|
72
87
|
}
|
|
73
88
|
},
|
|
74
89
|
"BrandTheme": {
|
|
@@ -82,7 +97,11 @@
|
|
|
82
97
|
"linkColor": { "type": "string", "minLength": 1 },
|
|
83
98
|
"socialIconSize": { "type": "string", "minLength": 1 },
|
|
84
99
|
"buttonTextColor": { "type": "string", "minLength": 1 },
|
|
85
|
-
"ctaLayout": { "type": "string", "enum": ["inline", "stacked"] }
|
|
100
|
+
"ctaLayout": { "type": "string", "enum": ["inline", "stacked"] },
|
|
101
|
+
"borderRadius": { "type": "string", "minLength": 1 },
|
|
102
|
+
"headerHeight": { "type": "string", "minLength": 1 },
|
|
103
|
+
"footerPadding": { "type": "string", "minLength": 1 },
|
|
104
|
+
"secondaryButtonBg": { "type": "string", "minLength": 1 }
|
|
86
105
|
}
|
|
87
106
|
}
|
|
88
107
|
}
|
package/dist/default.css
CHANGED
|
@@ -293,16 +293,16 @@
|
|
|
293
293
|
|
|
294
294
|
.brand-shell-header__nav {
|
|
295
295
|
min-width: 0;
|
|
296
|
-
|
|
297
|
-
|
|
296
|
+
width: 100%;
|
|
297
|
+
overflow: visible;
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
.brand-shell-header__list {
|
|
301
|
-
flex-wrap:
|
|
302
|
-
width:
|
|
303
|
-
min-width:
|
|
304
|
-
padding-bottom: 0
|
|
305
|
-
gap: 0.24rem;
|
|
301
|
+
flex-wrap: wrap;
|
|
302
|
+
width: 100%;
|
|
303
|
+
min-width: 0;
|
|
304
|
+
padding-bottom: 0;
|
|
305
|
+
gap: 0.24rem 0.34rem;
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
.brand-shell-header__link {
|
|
@@ -346,18 +346,33 @@
|
|
|
346
346
|
|
|
347
347
|
.brand-shell-header__social {
|
|
348
348
|
justify-content: flex-start;
|
|
349
|
-
flex-wrap:
|
|
349
|
+
flex-wrap: wrap;
|
|
350
350
|
gap: 0.36rem;
|
|
351
351
|
margin-top: 0.12rem;
|
|
352
352
|
padding-block: 0.08rem 0.12rem;
|
|
353
|
-
overflow
|
|
354
|
-
position: relative;
|
|
355
|
-
z-index: 1;
|
|
353
|
+
overflow: visible;
|
|
356
354
|
}
|
|
357
355
|
|
|
358
356
|
.brand-shell-header__social-link:hover {
|
|
359
357
|
transform: none;
|
|
360
358
|
}
|
|
359
|
+
|
|
360
|
+
.brand-shell-header__nav,
|
|
361
|
+
.brand-shell-header__social,
|
|
362
|
+
.brand-shell-footer__nav,
|
|
363
|
+
.brand-shell-footer__social {
|
|
364
|
+
-ms-overflow-style: none;
|
|
365
|
+
scrollbar-width: none;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.brand-shell-header__nav::-webkit-scrollbar,
|
|
369
|
+
.brand-shell-header__social::-webkit-scrollbar,
|
|
370
|
+
.brand-shell-footer__nav::-webkit-scrollbar,
|
|
371
|
+
.brand-shell-footer__social::-webkit-scrollbar {
|
|
372
|
+
width: 0;
|
|
373
|
+
height: 0;
|
|
374
|
+
display: none;
|
|
375
|
+
}
|
|
361
376
|
}
|
|
362
377
|
|
|
363
378
|
@media (max-width: 460px) {
|
|
@@ -568,15 +583,15 @@
|
|
|
568
583
|
|
|
569
584
|
.brand-shell-footer__nav {
|
|
570
585
|
width: 100%;
|
|
571
|
-
overflow
|
|
572
|
-
scrollbar-width: thin;
|
|
586
|
+
overflow: visible;
|
|
573
587
|
}
|
|
574
588
|
|
|
575
589
|
.brand-shell-footer__list {
|
|
576
|
-
flex-wrap:
|
|
577
|
-
width:
|
|
578
|
-
min-width:
|
|
579
|
-
padding-bottom: 0
|
|
590
|
+
flex-wrap: wrap;
|
|
591
|
+
width: 100%;
|
|
592
|
+
min-width: 0;
|
|
593
|
+
padding-bottom: 0;
|
|
594
|
+
gap: 0.24rem 0.4rem;
|
|
580
595
|
}
|
|
581
596
|
|
|
582
597
|
.brand-shell-footer__ctas {
|
|
@@ -604,11 +619,15 @@
|
|
|
604
619
|
|
|
605
620
|
.brand-shell-footer__social {
|
|
606
621
|
width: 100%;
|
|
607
|
-
flex-wrap:
|
|
608
|
-
overflow
|
|
622
|
+
flex-wrap: wrap;
|
|
623
|
+
overflow: visible;
|
|
609
624
|
gap: 0.4rem;
|
|
610
625
|
margin-top: 0.12rem;
|
|
611
626
|
}
|
|
627
|
+
|
|
628
|
+
.brand-shell-footer__link {
|
|
629
|
+
white-space: nowrap;
|
|
630
|
+
}
|
|
612
631
|
}
|
|
613
632
|
|
|
614
633
|
@media (max-width: 460px) {
|
package/dist/index.d.mts
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
|
-
import { i as BrandTheme, n as BrandDetails, r as BrandNavLink, t as BrandAction } from "./types-
|
|
1
|
+
import { a as CustomSocialLink, i as BrandTheme, n as BrandDetails, r as BrandNavLink, t as BrandAction } from "./types-B_CLRZMO.mjs";
|
|
2
2
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
|
+
import { ReactElement, ReactNode } from "react";
|
|
3
4
|
|
|
4
5
|
//#region src/Header.d.ts
|
|
6
|
+
interface LinkRenderProps {
|
|
7
|
+
href: string;
|
|
8
|
+
className: string;
|
|
9
|
+
"aria-label": string;
|
|
10
|
+
target: string;
|
|
11
|
+
rel?: string;
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}
|
|
5
14
|
interface HeaderProps {
|
|
6
15
|
details: BrandDetails;
|
|
7
16
|
theme?: BrandTheme | null;
|
|
8
17
|
className?: string;
|
|
18
|
+
renderLink?: (props: LinkRenderProps) => ReactElement;
|
|
9
19
|
}
|
|
10
20
|
declare function Header({
|
|
11
21
|
details,
|
|
12
22
|
theme,
|
|
13
|
-
className
|
|
23
|
+
className,
|
|
24
|
+
renderLink
|
|
14
25
|
}: HeaderProps): react_jsx_runtime0.JSX.Element;
|
|
15
26
|
//#endregion
|
|
16
27
|
//#region src/Footer.d.ts
|
|
@@ -18,19 +29,22 @@ interface FooterProps {
|
|
|
18
29
|
details: BrandDetails;
|
|
19
30
|
theme?: BrandTheme | null;
|
|
20
31
|
className?: string;
|
|
32
|
+
renderLink?: (props: LinkRenderProps) => ReactElement;
|
|
21
33
|
}
|
|
22
34
|
declare function Footer({
|
|
23
35
|
details,
|
|
24
36
|
theme,
|
|
25
|
-
className
|
|
37
|
+
className,
|
|
38
|
+
renderLink
|
|
26
39
|
}: FooterProps): react_jsx_runtime0.JSX.Element;
|
|
27
40
|
//#endregion
|
|
28
41
|
//#region src/core/social.d.ts
|
|
29
42
|
type SocialPlatform = "website" | "linkedin" | "email" | "github" | "twitter" | "discord";
|
|
30
43
|
interface SocialLink {
|
|
31
|
-
platform: SocialPlatform;
|
|
44
|
+
platform: SocialPlatform | string;
|
|
32
45
|
href: string;
|
|
33
46
|
label: string;
|
|
47
|
+
iconSvg?: string;
|
|
34
48
|
}
|
|
35
49
|
declare function detailsToSocialLinks(details: BrandDetails): SocialLink[];
|
|
36
50
|
//#endregion
|
|
@@ -61,8 +75,9 @@ interface NormalizedBrandDetails extends Omit<BrandDetails, "navLinks" | "primar
|
|
|
61
75
|
declare function normalizeNavLinks(navLinks?: BrandNavLink[]): ShellNavLink[];
|
|
62
76
|
declare function normalizeBrandDetails(details: BrandDetails): NormalizedBrandDetails;
|
|
63
77
|
declare function normalizeCtaLinks(primaryAction?: BrandAction, secondaryAction?: BrandAction): ShellActionLink[];
|
|
78
|
+
declare function buildShellViewModelFromNormalized(normalized: NormalizedBrandDetails): ShellViewModel;
|
|
64
79
|
declare function buildShellViewModel(details: BrandDetails): ShellViewModel;
|
|
65
|
-
declare function
|
|
80
|
+
declare function normalizeEmailHref(email?: string): string | undefined;
|
|
66
81
|
//#endregion
|
|
67
82
|
//#region src/core/dev.d.ts
|
|
68
83
|
declare function shouldValidateInDev(): boolean;
|
|
@@ -89,5 +104,5 @@ declare function assertValidBrandTheme(theme: unknown, context?: string): assert
|
|
|
89
104
|
declare function normalizeBrandTheme(theme?: BrandTheme | null): BrandTheme | null;
|
|
90
105
|
declare function formatValidationErrors(context: string, errors: string[]): string;
|
|
91
106
|
//#endregion
|
|
92
|
-
export { type BrandAction, type BrandDetails, type BrandNavLink, BrandShellValidationError, type BrandTheme, type BrandValidationResult, Footer, Header, type LinkTarget, type NormalizedBrandDetails, type ShellActionLink, type ShellNavLink, type ShellViewModel, type SocialLink, type SocialPlatform, type ThemeVariables, assertValidBrandDetails, assertValidBrandTheme, buildShellViewModel, detailsToSocialLinks, formatValidationErrors, normalizeBrandDetails, normalizeBrandTheme, normalizeCtaLinks,
|
|
107
|
+
export { type BrandAction, type BrandDetails, type BrandNavLink, BrandShellValidationError, type BrandTheme, type BrandValidationResult, type CustomSocialLink, Footer, type FooterProps, Header, type HeaderProps, type LinkRenderProps, type LinkTarget, type NormalizedBrandDetails, type ShellActionLink, type ShellNavLink, type ShellViewModel, type SocialLink, type SocialPlatform, type ThemeVariables, assertValidBrandDetails, assertValidBrandTheme, buildShellViewModel, buildShellViewModelFromNormalized, detailsToSocialLinks, formatValidationErrors, normalizeBrandDetails, normalizeBrandTheme, normalizeCtaLinks, normalizeEmailHref, normalizeNavLinks, shouldValidateInDev, themeToCssVariables, validateBrandDetails, validateBrandTheme };
|
|
93
108
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/Header.tsx","../src/Footer.tsx","../src/core/social.ts","../src/core/shell.ts","../src/core/dev.ts","../src/core/theme.ts","../src/core/validation.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/Header.tsx","../src/Footer.tsx","../src/core/social.ts","../src/core/shell.ts","../src/core/dev.ts","../src/core/theme.ts","../src/core/validation.ts"],"mappings":";;;;;UAsBiB,eAAA;EACf,IAAA;EACA,SAAA;EACA,YAAA;EACA,MAAA;EACA,GAAA;EACA,QAAA,EAAU,SAAA;AAAA;AAAA,UAGK,WAAA;EACf,OAAA,EAAS,YAAA;EACT,KAAA,GAAQ,UAAA;EACR,SAAA;EACA,UAAA,IAAc,KAAA,EAAO,eAAA,KAAoB,YAAA;AAAA;AAAA,iBAG3B,MAAA,CAAA;EAAS,OAAA;EAAS,KAAA;EAAO,SAAA;EAAW;AAAA,GAAc,WAAA,GAAW,kBAAA,CAAA,GAAA,CAAA,OAAA;;;UCd5D,WAAA;EACf,OAAA,EAAS,YAAA;EACT,KAAA,GAAQ,UAAA;EACR,SAAA;EACA,UAAA,IAAc,KAAA,EAAO,eAAA,KAAoB,YAAA;AAAA;AAAA,iBAG3B,MAAA,CAAA;EAAS,OAAA;EAAS,KAAA;EAAO,SAAA;EAAW;AAAA,GAAc,WAAA,GAAW,kBAAA,CAAA,GAAA,CAAA,OAAA;;;KC7BjE,cAAA;AAAA,UAEK,UAAA;EACf,QAAA,EAAU,cAAA;EACV,IAAA;EACA,KAAA;EACA,OAAA;AAAA;AAAA,iBAGc,oBAAA,CAAqB,OAAA,EAAS,YAAA,GAAe,UAAA;;;KCPjD,UAAA,GAAa,WAAA,CAAY,YAAA;AAAA,UAEpB,YAAA,SAAqB,YAAA;EACpC,SAAA;EACA,GAAA;EACA,MAAA,EAAQ,UAAA;AAAA;AAAA,UAGO,eAAA,SAAwB,WAAA;EACvC,SAAA;EACA,GAAA;EACA,MAAA,EAAQ,UAAA;EACR,OAAA,EAAS,WAAA,CAAY,WAAA;AAAA;AAAA,UAGN,cAAA;EACf,QAAA,EAAU,YAAA;EACV,QAAA,EAAU,eAAA;EACV,WAAA,EAAa,UAAA;AAAA;AAAA,KAGH,oBAAA,GAAuB,IAAA,CAAK,eAAA,eAA8B,IAAA,CAAK,WAAA;AAAA,UAE1D,sBAAA,SAA+B,IAAA,CAAK,YAAA;EACnD,QAAA,EAAU,YAAA;EACV,aAAA,GAAgB,oBAAA;EAChB,eAAA,GAAkB,oBAAA;AAAA;AAAA,iBAGJ,iBAAA,CAAkB,QAAA,GAAU,YAAA,KAAsB,YAAA;AAAA,iBAgBlD,qBAAA,CAAsB,OAAA,EAAS,YAAA,GAAe,sBAAA;AAAA,iBAoB9C,iBAAA,CACd,aAAA,GAAgB,WAAA,EAChB,eAAA,GAAkB,WAAA,GACjB,eAAA;AAAA,iBAkBa,iCAAA,CAAkC,UAAA,EAAY,sBAAA,GAAyB,cAAA;AAAA,iBAQvE,mBAAA,CAAoB,OAAA,EAAS,YAAA,GAAe,cAAA;AAAA,iBAI5C,kBAAA,CAAmB,KAAA;;;iBC7FnB,mBAAA,CAAA;;;KCHJ,cAAA,GAAiB,MAAA;AAAA,iBAEb,mBAAA,CAAoB,KAAA,GAAQ,UAAA,UAAoB,cAAA;;;UCgB/C,qBAAA;EACf,KAAA;EACA,MAAA;EACA,UAAA,EAAY,CAAA;AAAA;AAAA,cAGD,yBAAA,SAAkC,KAAA;EAAA,SACpC,OAAA;EAAA,SACA,MAAA;cAEG,OAAA,UAAiB,MAAA;AAAA;AAAA,iBAQf,oBAAA,CAAqB,OAAA,YAAmB,qBAAA,CAAsB,sBAAA;AAAA,iBA6D9D,kBAAA,CAAmB,KAAA,YAAiB,qBAAA,CAAsB,UAAA;AAAA,iBAuC1D,uBAAA,CAAwB,OAAA,WAAkB,OAAA,oBAAmC,OAAA,IAAW,YAAA;AAAA,iBAOxF,qBAAA,CAAsB,KAAA,WAAgB,OAAA,oBAAiC,KAAA,IAAS,UAAA;AAAA,iBAOhF,mBAAA,CAAoB,KAAA,GAAQ,UAAA,UAAoB,UAAA;AAAA,iBAwBhD,sBAAA,CAAuB,OAAA,UAAiB,MAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as normalizeBrandTheme, c as themeToCssVariables, d as
|
|
1
|
+
import { a as normalizeBrandTheme, c as themeToCssVariables, d as buildShellViewModelFromNormalized, f as normalizeBrandDetails, g as detailsToSocialLinks, h as normalizeNavLinks, i as formatValidationErrors, l as shouldValidateInDev, m as normalizeEmailHref, n as assertValidBrandDetails, o as validateBrandDetails, p as normalizeCtaLinks, r as assertValidBrandTheme, s as validateBrandTheme, t as BrandShellValidationError, u as buildShellViewModel } from "./validation-CtH2UkVv.mjs";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/react/theme.ts
|
|
@@ -73,8 +73,8 @@ function MailIcon({ className, width = "1em", height = "1em", ...props }) {
|
|
|
73
73
|
}), /* @__PURE__ */ jsx("path", { d: "m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" })]
|
|
74
74
|
});
|
|
75
75
|
}
|
|
76
|
-
function
|
|
77
|
-
return /* @__PURE__ */
|
|
76
|
+
function GlobeIcon({ className, width = "1em", height = "1em", ...props }) {
|
|
77
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
78
78
|
viewBox: "0 0 24 24",
|
|
79
79
|
fill: "none",
|
|
80
80
|
stroke: "currentColor",
|
|
@@ -85,13 +85,21 @@ function MessageCircleIcon({ className, width = "1em", height = "1em", ...props
|
|
|
85
85
|
width,
|
|
86
86
|
height,
|
|
87
87
|
...props,
|
|
88
|
-
children:
|
|
88
|
+
children: [
|
|
89
|
+
/* @__PURE__ */ jsx("circle", {
|
|
90
|
+
cx: "12",
|
|
91
|
+
cy: "12",
|
|
92
|
+
r: "10"
|
|
93
|
+
}),
|
|
94
|
+
/* @__PURE__ */ jsx("path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" }),
|
|
95
|
+
/* @__PURE__ */ jsx("path", { d: "M2 12h20" })
|
|
96
|
+
]
|
|
89
97
|
});
|
|
90
98
|
}
|
|
91
99
|
|
|
92
100
|
//#endregion
|
|
93
101
|
//#region src/Header.tsx
|
|
94
|
-
function Header({ details, theme, className }) {
|
|
102
|
+
function Header({ details, theme, className, renderLink }) {
|
|
95
103
|
if (shouldValidateInDev()) {
|
|
96
104
|
assertValidBrandDetails(details, "brand-shell/Header details");
|
|
97
105
|
assertValidBrandTheme(theme, "brand-shell/Header theme");
|
|
@@ -100,12 +108,21 @@ function Header({ details, theme, className }) {
|
|
|
100
108
|
const normalizedTheme = normalizeBrandTheme(theme);
|
|
101
109
|
const ctaLayout = normalizedTheme?.ctaLayout === "stacked" ? "stacked" : "inline";
|
|
102
110
|
const style = themeToStyle(normalizedTheme);
|
|
103
|
-
const { navLinks, ctaLinks, socialLinks } =
|
|
111
|
+
const { navLinks, ctaLinks, socialLinks } = buildShellViewModelFromNormalized(normalizedDetails);
|
|
104
112
|
const combinedClassName = ["brand-shell-header", className].filter(Boolean).join(" ");
|
|
105
|
-
const
|
|
113
|
+
const LinkEl = renderLink ? renderLink : ({ href, className: cls, "aria-label": ariaLabel, target, rel, children }) => /* @__PURE__ */ jsx("a", {
|
|
114
|
+
href,
|
|
115
|
+
className: cls,
|
|
116
|
+
"aria-label": ariaLabel,
|
|
117
|
+
target,
|
|
118
|
+
rel,
|
|
119
|
+
children
|
|
120
|
+
});
|
|
121
|
+
const brandIdentity = normalizedDetails.homeHref ? /* @__PURE__ */ jsx(LinkEl, {
|
|
106
122
|
href: normalizedDetails.homeHref,
|
|
107
123
|
className: "brand-shell-header__name",
|
|
108
124
|
"aria-label": `${normalizedDetails.name} home`,
|
|
125
|
+
target: "_self",
|
|
109
126
|
children: normalizedDetails.name
|
|
110
127
|
}) : /* @__PURE__ */ jsx("span", {
|
|
111
128
|
className: "brand-shell-header__name",
|
|
@@ -127,7 +144,7 @@ function Header({ details, theme, className }) {
|
|
|
127
144
|
children: /* @__PURE__ */ jsx("ul", {
|
|
128
145
|
className: "brand-shell-header__list",
|
|
129
146
|
children: navLinks.map((link) => {
|
|
130
|
-
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
147
|
+
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(LinkEl, {
|
|
131
148
|
href: link.href,
|
|
132
149
|
className: "brand-shell-header__link",
|
|
133
150
|
"aria-label": link.ariaLabel,
|
|
@@ -140,7 +157,7 @@ function Header({ details, theme, className }) {
|
|
|
140
157
|
}),
|
|
141
158
|
ctaLinks.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
142
159
|
className: "brand-shell-header__ctas",
|
|
143
|
-
children: ctaLinks.map((action) => /* @__PURE__ */ jsx(
|
|
160
|
+
children: ctaLinks.map((action) => /* @__PURE__ */ jsx(LinkEl, {
|
|
144
161
|
href: action.href,
|
|
145
162
|
className: ["brand-shell-button", `brand-shell-button--${action.variant}`].join(" "),
|
|
146
163
|
"aria-label": action.ariaLabel,
|
|
@@ -154,13 +171,19 @@ function Header({ details, theme, className }) {
|
|
|
154
171
|
"aria-label": "Social links",
|
|
155
172
|
children: socialLinks.map((link) => {
|
|
156
173
|
const Icon = SOCIAL_ICON_COMPONENTS$1[link.platform];
|
|
174
|
+
const isMailto = link.href.startsWith("mailto:");
|
|
157
175
|
return /* @__PURE__ */ jsx("a", {
|
|
158
176
|
href: link.href,
|
|
159
177
|
className: "brand-shell-header__social-link",
|
|
160
178
|
"aria-label": link.label,
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
179
|
+
...!isMailto && {
|
|
180
|
+
target: "_blank",
|
|
181
|
+
rel: "noopener noreferrer"
|
|
182
|
+
},
|
|
183
|
+
children: Icon ? /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true" }) : link.iconSvg ? /* @__PURE__ */ jsx("span", {
|
|
184
|
+
dangerouslySetInnerHTML: { __html: link.iconSvg },
|
|
185
|
+
"aria-hidden": "true"
|
|
186
|
+
}) : /* @__PURE__ */ jsx("span", { children: link.label[0] })
|
|
164
187
|
}, link.href + link.platform);
|
|
165
188
|
})
|
|
166
189
|
})
|
|
@@ -170,7 +193,7 @@ function Header({ details, theme, className }) {
|
|
|
170
193
|
});
|
|
171
194
|
}
|
|
172
195
|
const SOCIAL_ICON_COMPONENTS$1 = {
|
|
173
|
-
website:
|
|
196
|
+
website: GlobeIcon,
|
|
174
197
|
linkedin: LinkedinIcon,
|
|
175
198
|
email: MailIcon,
|
|
176
199
|
github: GithubIcon,
|
|
@@ -180,7 +203,7 @@ const SOCIAL_ICON_COMPONENTS$1 = {
|
|
|
180
203
|
|
|
181
204
|
//#endregion
|
|
182
205
|
//#region src/Footer.tsx
|
|
183
|
-
function Footer({ details, theme, className }) {
|
|
206
|
+
function Footer({ details, theme, className, renderLink }) {
|
|
184
207
|
if (shouldValidateInDev()) {
|
|
185
208
|
assertValidBrandDetails(details, "brand-shell/Footer details");
|
|
186
209
|
assertValidBrandTheme(theme, "brand-shell/Footer theme");
|
|
@@ -189,9 +212,18 @@ function Footer({ details, theme, className }) {
|
|
|
189
212
|
const normalizedTheme = normalizeBrandTheme(theme);
|
|
190
213
|
const ctaLayout = normalizedTheme?.ctaLayout === "stacked" ? "stacked" : "inline";
|
|
191
214
|
const style = themeToStyle(normalizedTheme);
|
|
192
|
-
const { navLinks, ctaLinks, socialLinks } =
|
|
215
|
+
const { navLinks, ctaLinks, socialLinks } = buildShellViewModelFromNormalized(normalizedDetails);
|
|
216
|
+
const combinedClassName = ["brand-shell-footer", className].filter(Boolean).join(" ");
|
|
217
|
+
const LinkEl = renderLink ? renderLink : ({ href, className: cls, "aria-label": ariaLabel, target, rel, children }) => /* @__PURE__ */ jsx("a", {
|
|
218
|
+
href,
|
|
219
|
+
className: cls,
|
|
220
|
+
"aria-label": ariaLabel,
|
|
221
|
+
target,
|
|
222
|
+
rel,
|
|
223
|
+
children
|
|
224
|
+
});
|
|
193
225
|
return /* @__PURE__ */ jsx("footer", {
|
|
194
|
-
className:
|
|
226
|
+
className: combinedClassName,
|
|
195
227
|
"data-brand-cta-layout": ctaLayout,
|
|
196
228
|
style,
|
|
197
229
|
role: "contentinfo",
|
|
@@ -216,7 +248,7 @@ function Footer({ details, theme, className }) {
|
|
|
216
248
|
children: /* @__PURE__ */ jsx("ul", {
|
|
217
249
|
className: "brand-shell-footer__list",
|
|
218
250
|
children: navLinks.map((link) => {
|
|
219
|
-
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
251
|
+
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(LinkEl, {
|
|
220
252
|
href: link.href,
|
|
221
253
|
className: "brand-shell-footer__link",
|
|
222
254
|
"aria-label": link.ariaLabel,
|
|
@@ -229,7 +261,7 @@ function Footer({ details, theme, className }) {
|
|
|
229
261
|
}),
|
|
230
262
|
ctaLinks.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
231
263
|
className: "brand-shell-footer__ctas",
|
|
232
|
-
children: ctaLinks.map((action) => /* @__PURE__ */ jsx(
|
|
264
|
+
children: ctaLinks.map((action) => /* @__PURE__ */ jsx(LinkEl, {
|
|
233
265
|
href: action.href,
|
|
234
266
|
className: ["brand-shell-button", `brand-shell-button--${action.variant}`].join(" "),
|
|
235
267
|
"aria-label": action.ariaLabel,
|
|
@@ -243,13 +275,19 @@ function Footer({ details, theme, className }) {
|
|
|
243
275
|
"aria-label": "Social links",
|
|
244
276
|
children: socialLinks.map((link) => {
|
|
245
277
|
const Icon = SOCIAL_ICON_COMPONENTS[link.platform];
|
|
278
|
+
const isMailto = link.href.startsWith("mailto:");
|
|
246
279
|
return /* @__PURE__ */ jsx("a", {
|
|
247
280
|
href: link.href,
|
|
248
281
|
className: "brand-shell-footer__social-link",
|
|
249
282
|
"aria-label": link.label,
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
283
|
+
...!isMailto && {
|
|
284
|
+
target: "_blank",
|
|
285
|
+
rel: "noopener noreferrer"
|
|
286
|
+
},
|
|
287
|
+
children: Icon ? /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true" }) : link.iconSvg ? /* @__PURE__ */ jsx("span", {
|
|
288
|
+
dangerouslySetInnerHTML: { __html: link.iconSvg },
|
|
289
|
+
"aria-hidden": "true"
|
|
290
|
+
}) : /* @__PURE__ */ jsx("span", { children: link.label[0] })
|
|
253
291
|
}, link.href + link.platform);
|
|
254
292
|
})
|
|
255
293
|
})
|
|
@@ -267,7 +305,7 @@ function Footer({ details, theme, className }) {
|
|
|
267
305
|
});
|
|
268
306
|
}
|
|
269
307
|
const SOCIAL_ICON_COMPONENTS = {
|
|
270
|
-
website:
|
|
308
|
+
website: GlobeIcon,
|
|
271
309
|
linkedin: LinkedinIcon,
|
|
272
310
|
email: MailIcon,
|
|
273
311
|
github: GithubIcon,
|
|
@@ -276,5 +314,5 @@ const SOCIAL_ICON_COMPONENTS = {
|
|
|
276
314
|
};
|
|
277
315
|
|
|
278
316
|
//#endregion
|
|
279
|
-
export { BrandShellValidationError, Footer, Header, assertValidBrandDetails, assertValidBrandTheme, buildShellViewModel, detailsToSocialLinks, formatValidationErrors, normalizeBrandDetails, normalizeBrandTheme, normalizeCtaLinks,
|
|
317
|
+
export { BrandShellValidationError, Footer, Header, assertValidBrandDetails, assertValidBrandTheme, buildShellViewModel, buildShellViewModelFromNormalized, detailsToSocialLinks, formatValidationErrors, normalizeBrandDetails, normalizeBrandTheme, normalizeCtaLinks, normalizeEmailHref, normalizeNavLinks, shouldValidateInDev, themeToCssVariables, validateBrandDetails, validateBrandTheme };
|
|
280
318
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["SOCIAL_ICON_COMPONENTS"],"sources":["../src/react/theme.ts","../src/icons.tsx","../src/Header.tsx","../src/Footer.tsx"],"sourcesContent":["import type { CSSProperties } from \"react\";\nimport type { BrandTheme } from \"../core/types\";\nimport { themeToCssVariables } from \"../core/theme\";\n\nexport function themeToStyle(theme?: BrandTheme | null): CSSProperties {\n return themeToCssVariables(theme) as CSSProperties;\n}\n","/**\n * Social Media Icons\n *\n * Brand icons from lucide-react are deprecated and will be removed in v1.0.\n * This file provides reusable icon components using Simple Icons SVG paths.\n * See: https://github.com/lucide-icons/lucide/issues/670\n */\n\nimport type { SVGProps } from \"react\";\n\nexport interface IconProps extends SVGProps<SVGSVGElement> {\n className?: string;\n \"aria-label\"?: string;\n}\n\nexport function GithubIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z\" />\n </svg>\n );\n}\n\nexport function TwitterIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z\" />\n </svg>\n );\n}\n\nexport function LinkedinIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z\" />\n </svg>\n );\n}\n\nexport function DiscordIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z\" />\n </svg>\n );\n}\n\nexport function MailIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n width={width}\n height={height}\n {...props}\n >\n <rect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\" />\n <path d=\"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\" />\n </svg>\n );\n}\n\nexport function MessageCircleIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n width={width}\n height={height}\n {...props}\n >\n <path d=\"M7.9 20A9 9 0 1 0 4 16.1L2 22Z\" />\n </svg>\n );\n}\n","import type { BrandDetails, BrandTheme } from \"./types\";\nimport {\n assertValidBrandDetails,\n assertValidBrandTheme,\n buildShellViewModel,\n normalizeBrandDetails,\n normalizeBrandTheme,\n shouldValidateInDev,\n} from \"./core\";\nimport type { SocialPlatform } from \"./core\";\nimport type { IconProps } from \"./icons\";\nimport { themeToStyle } from \"./react/theme\";\nimport {\n DiscordIcon,\n GithubIcon,\n LinkedinIcon,\n MailIcon,\n MessageCircleIcon,\n TwitterIcon,\n} from \"./icons\";\n\nexport interface HeaderProps {\n details: BrandDetails;\n theme?: BrandTheme | null;\n className?: string;\n}\n\nexport function Header({ details, theme, className }: HeaderProps) {\n if (shouldValidateInDev()) {\n assertValidBrandDetails(details, \"brand-shell/Header details\");\n assertValidBrandTheme(theme, \"brand-shell/Header theme\");\n }\n\n const normalizedDetails = normalizeBrandDetails(details);\n const normalizedTheme = normalizeBrandTheme(theme);\n const ctaLayout = normalizedTheme?.ctaLayout === \"stacked\" ? \"stacked\" : \"inline\";\n const style = themeToStyle(normalizedTheme);\n const { navLinks, ctaLinks, socialLinks } = buildShellViewModel(normalizedDetails);\n const combinedClassName = [\"brand-shell-header\", className].filter(Boolean).join(\" \");\n const brandIdentity = normalizedDetails.homeHref ? (\n <a\n href={normalizedDetails.homeHref}\n className=\"brand-shell-header__name\"\n aria-label={`${normalizedDetails.name} home`}\n >\n {normalizedDetails.name}\n </a>\n ) : (\n <span className=\"brand-shell-header__name\">{normalizedDetails.name}</span>\n );\n\n return (\n <header className={combinedClassName} data-brand-cta-layout={ctaLayout} style={style} role=\"banner\">\n <div className=\"brand-shell-header__inner\">\n {brandIdentity}\n <div className=\"brand-shell-header__actions\">\n {navLinks.length > 0 && (\n <nav className=\"brand-shell-header__nav\" aria-label=\"Primary\">\n <ul className=\"brand-shell-header__list\">\n {navLinks.map((link) => {\n return (\n <li key={link.href + link.label}>\n <a\n href={link.href}\n className=\"brand-shell-header__link\"\n aria-label={link.ariaLabel}\n target={link.target}\n rel={link.rel}\n >\n {link.label}\n </a>\n </li>\n );\n })}\n </ul>\n </nav>\n )}\n {ctaLinks.length > 0 && (\n <div className=\"brand-shell-header__ctas\">\n {ctaLinks.map((action) => (\n <a\n key={action.href + action.label}\n href={action.href}\n className={[\"brand-shell-button\", `brand-shell-button--${action.variant}`].join(\" \")}\n aria-label={action.ariaLabel}\n target={action.target}\n rel={action.rel}\n >\n {action.label}\n </a>\n ))}\n </div>\n )}\n {socialLinks.length > 0 && (\n <div className=\"brand-shell-header__social\" aria-label=\"Social links\">\n {socialLinks.map((link) => {\n const Icon = SOCIAL_ICON_COMPONENTS[link.platform];\n return (\n <a\n key={link.href + link.platform}\n href={link.href}\n className=\"brand-shell-header__social-link\"\n aria-label={link.label}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {Icon ? <Icon aria-hidden=\"true\" /> : <span>{link.label[0]}</span>}\n </a>\n );\n })}\n </div>\n )}\n </div>\n </div>\n </header>\n );\n}\n\nconst SOCIAL_ICON_COMPONENTS: Record<SocialPlatform, (props: IconProps) => JSX.Element> = {\n website: MessageCircleIcon,\n linkedin: LinkedinIcon,\n email: MailIcon,\n github: GithubIcon,\n twitter: TwitterIcon,\n discord: DiscordIcon,\n};\n","import type { BrandDetails, BrandTheme } from \"./types\";\nimport {\n assertValidBrandDetails,\n assertValidBrandTheme,\n buildShellViewModel,\n normalizeBrandDetails,\n normalizeBrandTheme,\n shouldValidateInDev,\n} from \"./core\";\nimport type { SocialPlatform } from \"./core\";\nimport type { IconProps } from \"./icons\";\nimport { themeToStyle } from \"./react/theme\";\nimport {\n DiscordIcon,\n GithubIcon,\n LinkedinIcon,\n MailIcon,\n MessageCircleIcon,\n TwitterIcon,\n} from \"./icons\";\n\nexport interface FooterProps {\n details: BrandDetails;\n theme?: BrandTheme | null;\n className?: string;\n}\n\nexport function Footer({ details, theme, className }: FooterProps) {\n if (shouldValidateInDev()) {\n assertValidBrandDetails(details, \"brand-shell/Footer details\");\n assertValidBrandTheme(theme, \"brand-shell/Footer theme\");\n }\n\n const normalizedDetails = normalizeBrandDetails(details);\n const normalizedTheme = normalizeBrandTheme(theme);\n const ctaLayout = normalizedTheme?.ctaLayout === \"stacked\" ? \"stacked\" : \"inline\";\n const style = themeToStyle(normalizedTheme);\n const { navLinks, ctaLinks, socialLinks } = buildShellViewModel(normalizedDetails);\n const combinedClassName = [\"brand-shell-footer\", className].filter(Boolean).join(\" \");\n\n return (\n <footer className={combinedClassName} data-brand-cta-layout={ctaLayout} style={style} role=\"contentinfo\">\n <div className=\"brand-shell-footer__inner\">\n <div className=\"brand-shell-footer__top\">\n <div className=\"brand-shell-footer__brand\">\n <p className=\"brand-shell-footer__name\">{normalizedDetails.name}</p>\n {normalizedDetails.tagline && <p className=\"brand-shell-footer__tagline\">{normalizedDetails.tagline}</p>}\n </div>\n {navLinks.length > 0 && (\n <nav className=\"brand-shell-footer__nav\" aria-label=\"Footer\">\n <ul className=\"brand-shell-footer__list\">\n {navLinks.map((link) => {\n return (\n <li key={link.href + link.label}>\n <a\n href={link.href}\n className=\"brand-shell-footer__link\"\n aria-label={link.ariaLabel}\n target={link.target}\n rel={link.rel}\n >\n {link.label}\n </a>\n </li>\n );\n })}\n </ul>\n </nav>\n )}\n {ctaLinks.length > 0 && (\n <div className=\"brand-shell-footer__ctas\">\n {ctaLinks.map((action) => (\n <a\n key={action.href + action.label}\n href={action.href}\n className={[\"brand-shell-button\", `brand-shell-button--${action.variant}`].join(\" \")}\n aria-label={action.ariaLabel}\n target={action.target}\n rel={action.rel}\n >\n {action.label}\n </a>\n ))}\n </div>\n )}\n {socialLinks.length > 0 && (\n <div className=\"brand-shell-footer__social\" aria-label=\"Social links\">\n {socialLinks.map((link) => {\n const Icon = SOCIAL_ICON_COMPONENTS[link.platform];\n return (\n <a\n key={link.href + link.platform}\n href={link.href}\n className=\"brand-shell-footer__social-link\"\n aria-label={link.label}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {Icon ? <Icon aria-hidden=\"true\" /> : <span>{link.label[0]}</span>}\n </a>\n );\n })}\n </div>\n )}\n </div>\n <p className=\"brand-shell-footer__copy\">© {new Date().getFullYear()} {normalizedDetails.name}</p>\n </div>\n </footer>\n );\n}\n\nconst SOCIAL_ICON_COMPONENTS: Record<SocialPlatform, (props: IconProps) => JSX.Element> = {\n website: MessageCircleIcon,\n linkedin: LinkedinIcon,\n email: MailIcon,\n github: GithubIcon,\n twitter: TwitterIcon,\n discord: DiscordIcon,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["SOCIAL_ICON_COMPONENTS"],"sources":["../src/react/theme.ts","../src/icons.tsx","../src/Header.tsx","../src/Footer.tsx"],"sourcesContent":["import type { CSSProperties } from \"react\";\nimport type { BrandTheme } from \"../core/types\";\nimport { themeToCssVariables } from \"../core/theme\";\n\nexport function themeToStyle(theme?: BrandTheme | null): CSSProperties {\n return themeToCssVariables(theme) as CSSProperties;\n}\n","/**\n * Social Media Icons\n *\n * Brand icons from lucide-react are deprecated and will be removed in v1.0.\n * This file provides reusable icon components using Simple Icons SVG paths.\n * See: https://github.com/lucide-icons/lucide/issues/670\n */\n\nimport type { SVGProps } from \"react\";\n\nexport interface IconProps extends SVGProps<SVGSVGElement> {\n className?: string;\n \"aria-label\"?: string;\n}\n\nexport function GithubIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z\" />\n </svg>\n );\n}\n\nexport function TwitterIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z\" />\n </svg>\n );\n}\n\nexport function LinkedinIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z\" />\n </svg>\n );\n}\n\nexport function DiscordIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} width={width} height={height} {...props}>\n <path d=\"M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z\" />\n </svg>\n );\n}\n\nexport function MailIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n width={width}\n height={height}\n {...props}\n >\n <rect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\" />\n <path d=\"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\" />\n </svg>\n );\n}\n\nexport function GlobeIcon({ className, width = \"1em\", height = \"1em\", ...props }: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n width={width}\n height={height}\n {...props}\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20\" />\n <path d=\"M2 12h20\" />\n </svg>\n );\n}\n","import type { ReactElement, ReactNode } from \"react\";\nimport type { BrandDetails, BrandTheme } from \"./types\";\nimport {\n assertValidBrandDetails,\n assertValidBrandTheme,\n buildShellViewModelFromNormalized,\n normalizeBrandDetails,\n normalizeBrandTheme,\n shouldValidateInDev,\n} from \"./core\";\nimport type { SocialPlatform } from \"./core\";\nimport type { IconProps } from \"./icons\";\nimport { themeToStyle } from \"./react/theme\";\nimport {\n DiscordIcon,\n GithubIcon,\n GlobeIcon,\n LinkedinIcon,\n MailIcon,\n TwitterIcon,\n} from \"./icons\";\n\nexport interface LinkRenderProps {\n href: string;\n className: string;\n \"aria-label\": string;\n target: string;\n rel?: string;\n children: ReactNode;\n}\n\nexport interface HeaderProps {\n details: BrandDetails;\n theme?: BrandTheme | null;\n className?: string;\n renderLink?: (props: LinkRenderProps) => ReactElement;\n}\n\nexport function Header({ details, theme, className, renderLink }: HeaderProps) {\n if (shouldValidateInDev()) {\n assertValidBrandDetails(details, \"brand-shell/Header details\");\n assertValidBrandTheme(theme, \"brand-shell/Header theme\");\n }\n\n const normalizedDetails = normalizeBrandDetails(details);\n const normalizedTheme = normalizeBrandTheme(theme);\n const ctaLayout = normalizedTheme?.ctaLayout === \"stacked\" ? \"stacked\" : \"inline\";\n const style = themeToStyle(normalizedTheme);\n const { navLinks, ctaLinks, socialLinks } = buildShellViewModelFromNormalized(normalizedDetails);\n const combinedClassName = [\"brand-shell-header\", className].filter(Boolean).join(\" \");\n\n const LinkEl = renderLink\n ? renderLink\n : ({ href, className: cls, \"aria-label\": ariaLabel, target, rel, children }: LinkRenderProps) => (\n <a href={href} className={cls} aria-label={ariaLabel} target={target} rel={rel}>{children}</a>\n );\n\n const brandIdentity = normalizedDetails.homeHref ? (\n <LinkEl\n href={normalizedDetails.homeHref}\n className=\"brand-shell-header__name\"\n aria-label={`${normalizedDetails.name} home`}\n target=\"_self\"\n >\n {normalizedDetails.name}\n </LinkEl>\n ) : (\n <span className=\"brand-shell-header__name\">{normalizedDetails.name}</span>\n );\n\n return (\n <header className={combinedClassName} data-brand-cta-layout={ctaLayout} style={style} role=\"banner\">\n <div className=\"brand-shell-header__inner\">\n {brandIdentity}\n <div className=\"brand-shell-header__actions\">\n {navLinks.length > 0 && (\n <nav className=\"brand-shell-header__nav\" aria-label=\"Primary\">\n <ul className=\"brand-shell-header__list\">\n {navLinks.map((link) => {\n return (\n <li key={link.href + link.label}>\n <LinkEl\n href={link.href}\n className=\"brand-shell-header__link\"\n aria-label={link.ariaLabel}\n target={link.target}\n rel={link.rel}\n >\n {link.label}\n </LinkEl>\n </li>\n );\n })}\n </ul>\n </nav>\n )}\n {ctaLinks.length > 0 && (\n <div className=\"brand-shell-header__ctas\">\n {ctaLinks.map((action) => (\n <LinkEl\n key={action.href + action.label}\n href={action.href}\n className={[\"brand-shell-button\", `brand-shell-button--${action.variant}`].join(\" \")}\n aria-label={action.ariaLabel}\n target={action.target}\n rel={action.rel}\n >\n {action.label}\n </LinkEl>\n ))}\n </div>\n )}\n {socialLinks.length > 0 && (\n <div className=\"brand-shell-header__social\" aria-label=\"Social links\">\n {socialLinks.map((link) => {\n const Icon = SOCIAL_ICON_COMPONENTS[link.platform as SocialPlatform];\n const isMailto = link.href.startsWith(\"mailto:\");\n return (\n <a\n key={link.href + link.platform}\n href={link.href}\n className=\"brand-shell-header__social-link\"\n aria-label={link.label}\n {...(!isMailto && { target: \"_blank\", rel: \"noopener noreferrer\" })}\n >\n {Icon ? (\n <Icon aria-hidden=\"true\" />\n ) : link.iconSvg ? (\n <span dangerouslySetInnerHTML={{ __html: link.iconSvg }} aria-hidden=\"true\" />\n ) : (\n <span>{link.label[0]}</span>\n )}\n </a>\n );\n })}\n </div>\n )}\n </div>\n </div>\n </header>\n );\n}\n\nconst SOCIAL_ICON_COMPONENTS: Record<SocialPlatform, (props: IconProps) => JSX.Element> = {\n website: GlobeIcon,\n linkedin: LinkedinIcon,\n email: MailIcon,\n github: GithubIcon,\n twitter: TwitterIcon,\n discord: DiscordIcon,\n};\n","import type { ReactElement } from \"react\";\nimport type { BrandDetails, BrandTheme } from \"./types\";\nimport {\n assertValidBrandDetails,\n assertValidBrandTheme,\n buildShellViewModelFromNormalized,\n normalizeBrandDetails,\n normalizeBrandTheme,\n shouldValidateInDev,\n} from \"./core\";\nimport type { SocialPlatform } from \"./core\";\nimport type { IconProps } from \"./icons\";\nimport { themeToStyle } from \"./react/theme\";\nimport {\n DiscordIcon,\n GithubIcon,\n GlobeIcon,\n LinkedinIcon,\n MailIcon,\n TwitterIcon,\n} from \"./icons\";\n\nimport type { LinkRenderProps } from \"./Header\";\n\nexport interface FooterProps {\n details: BrandDetails;\n theme?: BrandTheme | null;\n className?: string;\n renderLink?: (props: LinkRenderProps) => ReactElement;\n}\n\nexport function Footer({ details, theme, className, renderLink }: FooterProps) {\n if (shouldValidateInDev()) {\n assertValidBrandDetails(details, \"brand-shell/Footer details\");\n assertValidBrandTheme(theme, \"brand-shell/Footer theme\");\n }\n\n const normalizedDetails = normalizeBrandDetails(details);\n const normalizedTheme = normalizeBrandTheme(theme);\n const ctaLayout = normalizedTheme?.ctaLayout === \"stacked\" ? \"stacked\" : \"inline\";\n const style = themeToStyle(normalizedTheme);\n const { navLinks, ctaLinks, socialLinks } = buildShellViewModelFromNormalized(normalizedDetails);\n const combinedClassName = [\"brand-shell-footer\", className].filter(Boolean).join(\" \");\n\n const LinkEl = renderLink\n ? renderLink\n : ({ href, className: cls, \"aria-label\": ariaLabel, target, rel, children }: LinkRenderProps) => (\n <a href={href} className={cls} aria-label={ariaLabel} target={target} rel={rel}>{children}</a>\n );\n\n return (\n <footer className={combinedClassName} data-brand-cta-layout={ctaLayout} style={style} role=\"contentinfo\">\n <div className=\"brand-shell-footer__inner\">\n <div className=\"brand-shell-footer__top\">\n <div className=\"brand-shell-footer__brand\">\n <p className=\"brand-shell-footer__name\">{normalizedDetails.name}</p>\n {normalizedDetails.tagline && <p className=\"brand-shell-footer__tagline\">{normalizedDetails.tagline}</p>}\n </div>\n {navLinks.length > 0 && (\n <nav className=\"brand-shell-footer__nav\" aria-label=\"Footer\">\n <ul className=\"brand-shell-footer__list\">\n {navLinks.map((link) => {\n return (\n <li key={link.href + link.label}>\n <LinkEl\n href={link.href}\n className=\"brand-shell-footer__link\"\n aria-label={link.ariaLabel}\n target={link.target}\n rel={link.rel}\n >\n {link.label}\n </LinkEl>\n </li>\n );\n })}\n </ul>\n </nav>\n )}\n {ctaLinks.length > 0 && (\n <div className=\"brand-shell-footer__ctas\">\n {ctaLinks.map((action) => (\n <LinkEl\n key={action.href + action.label}\n href={action.href}\n className={[\"brand-shell-button\", `brand-shell-button--${action.variant}`].join(\" \")}\n aria-label={action.ariaLabel}\n target={action.target}\n rel={action.rel}\n >\n {action.label}\n </LinkEl>\n ))}\n </div>\n )}\n {socialLinks.length > 0 && (\n <div className=\"brand-shell-footer__social\" aria-label=\"Social links\">\n {socialLinks.map((link) => {\n const Icon = SOCIAL_ICON_COMPONENTS[link.platform as SocialPlatform];\n const isMailto = link.href.startsWith(\"mailto:\");\n return (\n <a\n key={link.href + link.platform}\n href={link.href}\n className=\"brand-shell-footer__social-link\"\n aria-label={link.label}\n {...(!isMailto && { target: \"_blank\", rel: \"noopener noreferrer\" })}\n >\n {Icon ? (\n <Icon aria-hidden=\"true\" />\n ) : link.iconSvg ? (\n <span dangerouslySetInnerHTML={{ __html: link.iconSvg }} aria-hidden=\"true\" />\n ) : (\n <span>{link.label[0]}</span>\n )}\n </a>\n );\n })}\n </div>\n )}\n </div>\n <p className=\"brand-shell-footer__copy\">© {new Date().getFullYear()} {normalizedDetails.name}</p>\n </div>\n </footer>\n );\n}\n\nconst SOCIAL_ICON_COMPONENTS: Record<SocialPlatform, (props: IconProps) => JSX.Element> = {\n website: GlobeIcon,\n linkedin: LinkedinIcon,\n email: MailIcon,\n github: GithubIcon,\n twitter: TwitterIcon,\n discord: DiscordIcon,\n};\n"],"mappings":"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"}
|
package/dist/svelte.d.mts
CHANGED
package/dist/svelte.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { l as shouldValidateInDev, n as assertValidBrandDetails, r as assertValidBrandTheme } from "./validation-
|
|
1
|
+
import { l as shouldValidateInDev, n as assertValidBrandDetails, r as assertValidBrandTheme } from "./validation-CtH2UkVv.mjs";
|
|
2
2
|
import { applyBrandShellProps, registerBrandShellElements } from "./web.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/svelte/index.ts
|
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
//#region src/core/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A custom social link for platforms not built into brand-shell.
|
|
4
|
+
* Built-in platforms retain priority; custom links are appended in insertion order.
|
|
5
|
+
*/
|
|
6
|
+
interface CustomSocialLink {
|
|
7
|
+
/** Arbitrary identifier used as a key (e.g. "bluesky", "mastodon") */
|
|
8
|
+
platform: string;
|
|
9
|
+
/** Link URL (must be a safe href) */
|
|
10
|
+
href: string;
|
|
11
|
+
/** Accessible label (used as aria-label) */
|
|
12
|
+
label: string;
|
|
13
|
+
/** Optional inline SVG string (24×24 viewBox). aria-hidden="true" is added automatically. */
|
|
14
|
+
iconSvg?: string;
|
|
15
|
+
}
|
|
2
16
|
/**
|
|
3
17
|
* Schema for header/footer content. Caller passes these; package does not store them.
|
|
4
18
|
*/
|
|
@@ -42,7 +56,7 @@ interface BrandDetails {
|
|
|
42
56
|
/** LinkedIn profile URL */
|
|
43
57
|
linkedin?: string;
|
|
44
58
|
/** Email address (e.g. mailto: or plain) */
|
|
45
|
-
|
|
59
|
+
email?: string;
|
|
46
60
|
/** GitHub profile URL */
|
|
47
61
|
github?: string;
|
|
48
62
|
/** Twitter/X profile URL */
|
|
@@ -53,6 +67,8 @@ interface BrandDetails {
|
|
|
53
67
|
website?: string;
|
|
54
68
|
/** Optional tagline (e.g. in footer) */
|
|
55
69
|
tagline?: string;
|
|
70
|
+
/** Additional social links for custom platforms (Bluesky, Mastodon, YouTube, etc.) */
|
|
71
|
+
customSocialLinks?: CustomSocialLink[];
|
|
56
72
|
}
|
|
57
73
|
/**
|
|
58
74
|
* Optional theme to adapt branding without custom CSS.
|
|
@@ -75,7 +91,15 @@ interface BrandTheme {
|
|
|
75
91
|
buttonTextColor?: string;
|
|
76
92
|
/** Mobile CTA arrangement: side-by-side (`inline`) or one-per-row (`stacked`) */
|
|
77
93
|
ctaLayout?: "inline" | "stacked";
|
|
94
|
+
/** Border radius for buttons and containers (e.g. 0.5rem, 4px) → --brand-radius */
|
|
95
|
+
borderRadius?: string;
|
|
96
|
+
/** Header height override (e.g. 4rem, 64px) → --brand-header-height */
|
|
97
|
+
headerHeight?: string;
|
|
98
|
+
/** Footer padding override (e.g. 3rem 1.5rem) → --brand-footer-padding */
|
|
99
|
+
footerPadding?: string;
|
|
100
|
+
/** Secondary button background color → --brand-button-secondary */
|
|
101
|
+
secondaryButtonBg?: string;
|
|
78
102
|
}
|
|
79
103
|
//#endregion
|
|
80
|
-
export { BrandTheme as i, BrandDetails as n, BrandNavLink as r, BrandAction as t };
|
|
81
|
-
//# sourceMappingURL=types-
|
|
104
|
+
export { CustomSocialLink as a, BrandTheme as i, BrandDetails as n, BrandNavLink as r, BrandAction as t };
|
|
105
|
+
//# sourceMappingURL=types-B_CLRZMO.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-B_CLRZMO.d.mts","names":[],"sources":["../src/core/types.ts"],"mappings":";;AAIA;;;UAAiB,gBAAA;EAEf;EAAA,QAAA;EAIA;EAFA,IAAA;EAIO;EAFP,KAAA;EAQe;EANf,OAAA;AAAA;;;;UAMe,YAAA;EAQf;EANA,KAAA;EAQG;EANH,IAAA;EASe;EAPf,SAAA;;EAEA,MAAA;EAOA;EALA,GAAA;AAAA;AAAA,UAGe,WAAA;EAUf;EARA,KAAA;EAUO;EARP,IAAA;EAWe;EATf,SAAA;;EAEA,MAAA;EAegB;EAbhB,GAAA;EA+BoB;EA7BpB,OAAA;AAAA;AAAA,UAGe,YAAA;EAIf;EAFA,IAAA;EAIW;EAFX,QAAA;EAIgB;EAFhB,QAAA,GAAW,YAAA;EAIO;EAFlB,aAAA,GAAgB,WAAA;EAMhB;EAJA,eAAA,GAAkB,WAAA;EAQlB;EANA,QAAA;EAUA;EARA,KAAA;EAYA;EAVA,MAAA;EAUoC;EARpC,OAAA;EAee;EAbf,OAAA;;EAEA,OAAA;EAaA;EAXA,OAAA;EAeA;EAbA,iBAAA,GAAoB,gBAAA;AAAA;;;;;UAOL,UAAA;EAsBf;EApBA,YAAA;EAsBiB;EApBjB,eAAA;;EAEA,SAAA;;EAEA,UAAA;;EAEA,SAAA;;EAEA,cAAA;;EAEA,eAAA;;EAEA,SAAA;;EAEA,YAAA;;EAEA,YAAA;;EAEA,aAAA;;EAEA,iBAAA;AAAA"}
|