brand-shell 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/LICENSE +21 -0
- package/README.md +316 -0
- package/dist/brand-shell.schema.json +89 -0
- package/dist/default.css +644 -0
- package/dist/index.d.mts +93 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +280 -0
- package/dist/index.mjs.map +1 -0
- package/dist/svelte.d.mts +14 -0
- package/dist/svelte.d.mts.map +1 -0
- package/dist/svelte.mjs +29 -0
- package/dist/svelte.mjs.map +1 -0
- package/dist/types-PQziYg7Z.d.mts +81 -0
- package/dist/types-PQziYg7Z.d.mts.map +1 -0
- package/dist/validation-xdqzwr3p.mjs +430 -0
- package/dist/validation-xdqzwr3p.mjs.map +1 -0
- package/dist/vue.d.mts +81 -0
- package/dist/vue.d.mts.map +1 -0
- package/dist/vue.mjs +62 -0
- package/dist/vue.mjs.map +1 -0
- package/dist/web.d.mts +61 -0
- package/dist/web.d.mts.map +1 -0
- package/dist/web.mjs +328 -0
- package/dist/web.mjs.map +1 -0
- package/package.json +112 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Venkatesh Bommadevara
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
## Brand Shell
|
|
2
|
+
|
|
3
|
+
Reusable header and footer components that ship with a premium default theme, typed props, and Storybook-based docs. Drop the package into React, Next.js, TanStack Router, Vue, or Svelte apps to keep your brand chrome consistent across projects.
|
|
4
|
+
|
|
5
|
+
### Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add brand-shell
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Basic usage
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { Header, Footer, type BrandDetails, type BrandTheme } from "brand-shell";
|
|
15
|
+
import "brand-shell/default.css";
|
|
16
|
+
|
|
17
|
+
const details: BrandDetails = {
|
|
18
|
+
name: "Mounika Thota",
|
|
19
|
+
homeHref: "/",
|
|
20
|
+
navLinks: [
|
|
21
|
+
{ label: "Blog", href: "/blog" },
|
|
22
|
+
{ label: "Docs", href: "/docs" },
|
|
23
|
+
],
|
|
24
|
+
primaryAction: { label: "Hire Me", href: "mailto:hello@example.com" },
|
|
25
|
+
secondaryAction: { label: "Resume", href: "/resume.pdf", target: "_blank" },
|
|
26
|
+
linkedin: "https://linkedin.com/in/example",
|
|
27
|
+
github: "https://github.com/example",
|
|
28
|
+
twitter: "https://twitter.com/example",
|
|
29
|
+
gmail: "hello@example.com",
|
|
30
|
+
tagline: "Design-system quality shell for every project.",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const theme: BrandTheme = {
|
|
34
|
+
primaryColor: "#0ea5e9",
|
|
35
|
+
backgroundColor: "#0f172a",
|
|
36
|
+
textColor: "#f8fafc",
|
|
37
|
+
fontFamily: '"Inter", system-ui, sans-serif',
|
|
38
|
+
socialIconSize: "2.25rem",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export function Layout({ children }: { children: React.ReactNode }) {
|
|
42
|
+
return (
|
|
43
|
+
<>
|
|
44
|
+
<Header details={details} theme={theme} />
|
|
45
|
+
{children}
|
|
46
|
+
<Footer details={details} theme={theme} />
|
|
47
|
+
</>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Framework-agnostic core helpers
|
|
53
|
+
|
|
54
|
+
The package now exports pure TypeScript helpers you can reuse in other framework adapters:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import {
|
|
58
|
+
buildShellViewModel,
|
|
59
|
+
validateBrandDetails,
|
|
60
|
+
validateBrandTheme,
|
|
61
|
+
} from "brand-shell";
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`buildShellViewModel` normalizes nav links and CTA behavior (target/rel/variants) so framework adapters share the same rules.
|
|
65
|
+
|
|
66
|
+
Validation + normalization are also exported for external integrations. The adapters run these checks in development mode.
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
const detailsCheck = validateBrandDetails(input.details);
|
|
70
|
+
const themeCheck = validateBrandTheme(input.theme);
|
|
71
|
+
|
|
72
|
+
if (!detailsCheck.valid || !themeCheck.valid) {
|
|
73
|
+
throw new Error([...detailsCheck.errors, ...themeCheck.errors].join("\n"));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const normalizedDetails = detailsCheck.normalized;
|
|
77
|
+
const normalizedTheme = themeCheck.normalized;
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### JSON schema
|
|
81
|
+
|
|
82
|
+
You can validate payloads in any runtime using the published schema:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import schema from "brand-shell/schema";
|
|
86
|
+
// also available as: brand-shell/schema.json
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
This repo validates the schema with Ajv in unit tests (`src/core/schema.test.ts`) to catch contract regressions before release.
|
|
90
|
+
|
|
91
|
+
Package publish surface is also guarded by `bun run pack:check` (allowed files + unpacked size budget) so docs/dev-webapp files cannot bloat the npm package.
|
|
92
|
+
|
|
93
|
+
### Web Components adapter
|
|
94
|
+
|
|
95
|
+
You can also use framework-agnostic custom elements:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { applyBrandShellProps, registerBrandShellElements } from "brand-shell/web";
|
|
99
|
+
import "brand-shell/default.css";
|
|
100
|
+
|
|
101
|
+
registerBrandShellElements();
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```html
|
|
105
|
+
<brand-header id="app-header"></brand-header>
|
|
106
|
+
<brand-footer id="app-footer"></brand-footer>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
const details = {
|
|
111
|
+
name: "Brand Shell",
|
|
112
|
+
homeHref: "/",
|
|
113
|
+
navLinks: [{ label: "Docs", href: "/docs" }],
|
|
114
|
+
primaryAction: { label: "Contact", href: "mailto:hello@example.com" },
|
|
115
|
+
linkedin: "https://linkedin.com/in/example",
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const theme = {
|
|
119
|
+
primaryColor: "#0ea5e9",
|
|
120
|
+
backgroundColor: "#0f172a",
|
|
121
|
+
textColor: "#f8fafc",
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const header = document.getElementById("app-header");
|
|
125
|
+
const footer = document.getElementById("app-footer");
|
|
126
|
+
|
|
127
|
+
if (header && footer) {
|
|
128
|
+
applyBrandShellProps(header, { details, theme });
|
|
129
|
+
applyBrandShellProps(footer, { details, theme });
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Vue adapter
|
|
134
|
+
|
|
135
|
+
Use framework-native Vue components:
|
|
136
|
+
|
|
137
|
+
```vue
|
|
138
|
+
<script setup>
|
|
139
|
+
import { BrandFooter, BrandHeader } from "brand-shell/vue";
|
|
140
|
+
import "brand-shell/default.css";
|
|
141
|
+
|
|
142
|
+
const details = { name: "Brand Shell" };
|
|
143
|
+
const theme = { primaryColor: "#0ea5e9" };
|
|
144
|
+
</script>
|
|
145
|
+
|
|
146
|
+
<template>
|
|
147
|
+
<BrandHeader :details="details" :theme="theme" />
|
|
148
|
+
<BrandFooter :details="details" :theme="theme" />
|
|
149
|
+
</template>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Svelte adapter
|
|
153
|
+
|
|
154
|
+
Use a Svelte action on the custom element tags:
|
|
155
|
+
|
|
156
|
+
```svelte
|
|
157
|
+
<script>
|
|
158
|
+
import { brandShell } from "brand-shell/svelte";
|
|
159
|
+
import "brand-shell/default.css";
|
|
160
|
+
|
|
161
|
+
const shellProps = {
|
|
162
|
+
details: { name: "Brand Shell" },
|
|
163
|
+
theme: { primaryColor: "#0ea5e9" },
|
|
164
|
+
};
|
|
165
|
+
</script>
|
|
166
|
+
|
|
167
|
+
<brand-header use:brandShell={shellProps}></brand-header>
|
|
168
|
+
<brand-footer use:brandShell={shellProps}></brand-footer>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Props reference
|
|
172
|
+
|
|
173
|
+
#### `BrandDetails`
|
|
174
|
+
|
|
175
|
+
| Field | Type | Description |
|
|
176
|
+
| --- | --- | --- |
|
|
177
|
+
| `name` | `string` | Required brand name shown in header/footer |
|
|
178
|
+
| `homeHref` | `string` | Optional link applied to the header name/logo |
|
|
179
|
+
| `navLinks` | `BrandNavLink[]` | Optional text links (e.g. Blog, Docs, About) |
|
|
180
|
+
| `primaryAction` | `BrandAction` | Highlighted CTA button (e.g. Hire me) |
|
|
181
|
+
| `secondaryAction` | `BrandAction` | Optional secondary CTA button |
|
|
182
|
+
| `linkedin`, `github`, `twitter`, `discord`, `website` | `string` | Social/profile URLs rendered as icon buttons |
|
|
183
|
+
| `gmail` | `string` | Email address or `mailto:` link |
|
|
184
|
+
| `tagline` | `string` | Short line shown in the footer |
|
|
185
|
+
|
|
186
|
+
#### `BrandNavLink`
|
|
187
|
+
|
|
188
|
+
| Field | Type | Description |
|
|
189
|
+
| --- | --- | --- |
|
|
190
|
+
| `label` | `string` | Visible text |
|
|
191
|
+
| `href` | `string` | Destination |
|
|
192
|
+
| `ariaLabel` | `string` | Optional accessible label override |
|
|
193
|
+
| `target` | `_blank \| _self \| _parent \| _top` | Optional target |
|
|
194
|
+
| `rel` | `string` | Optional rel attribute |
|
|
195
|
+
|
|
196
|
+
#### `BrandAction`
|
|
197
|
+
|
|
198
|
+
| Field | Type | Description |
|
|
199
|
+
| --- | --- | --- |
|
|
200
|
+
| `label` | `string` | CTA text |
|
|
201
|
+
| `href` | `string` | Destination URL |
|
|
202
|
+
| `ariaLabel` | `string` | Optional accessible label |
|
|
203
|
+
| `target` | `_blank \| _self \| _parent \| _top` | Optional target |
|
|
204
|
+
| `rel` | `string` | Optional rel |
|
|
205
|
+
| `variant` | `"primary" \| "secondary" \| "ghost"` | Optional style hint (defaults to primary for the last CTA) |
|
|
206
|
+
|
|
207
|
+
#### `BrandTheme`
|
|
208
|
+
|
|
209
|
+
| Field | Type | Description |
|
|
210
|
+
| --- | --- | --- |
|
|
211
|
+
| `primaryColor` | `string` | Accent color for links/buttons |
|
|
212
|
+
| `backgroundColor` | `string` | Header/footer background |
|
|
213
|
+
| `textColor` | `string` | Primary text color |
|
|
214
|
+
| `fontFamily` | `string` | Font stack |
|
|
215
|
+
| `linkColor` | `string` | Optional base link color |
|
|
216
|
+
| `socialIconSize` | `string` | Size of the circular social buttons (defaults to `2.5rem`) |
|
|
217
|
+
| `buttonTextColor` | `string` | Optional primary CTA text color override |
|
|
218
|
+
| `ctaLayout` | `"inline" \| "stacked"` | Mobile CTA layout: side-by-side (`inline`) or one-per-row (`stacked`) |
|
|
219
|
+
|
|
220
|
+
### Theming via CSS variables
|
|
221
|
+
|
|
222
|
+
`styles/default.css` exposes CSS custom properties you can override globally:
|
|
223
|
+
|
|
224
|
+
| Variable | Defaults to | Purpose |
|
|
225
|
+
| --- | --- | --- |
|
|
226
|
+
| `--brand-primary` | `#2563eb` | Accent + CTA background |
|
|
227
|
+
| `--brand-bg` | `#0f172a` | Header/footer background |
|
|
228
|
+
| `--brand-text` | `#f1f5f9` | Base text color |
|
|
229
|
+
| `--brand-font` | `"Inter", system-ui` | Font stack |
|
|
230
|
+
| `--brand-link` | `#94a3b8` | Link color |
|
|
231
|
+
| `--brand-social-size` | `2.5rem` | Icon button size |
|
|
232
|
+
| `--brand-button-text` | `#f8fafc` | Primary button text color |
|
|
233
|
+
|
|
234
|
+
Set them once in your consuming app:
|
|
235
|
+
|
|
236
|
+
```css
|
|
237
|
+
:root {
|
|
238
|
+
--brand-primary: #ec4899;
|
|
239
|
+
--brand-font: "Space Grotesk", system-ui, sans-serif;
|
|
240
|
+
--brand-social-size: 2rem;
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Storybook
|
|
245
|
+
|
|
246
|
+
Run Storybook locally to explore examples and tweak controls:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
bun run storybook
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
The stories showcase default, themed, and minimal configurations and expose controls for nav links, CTA buttons, and theme tokens.
|
|
253
|
+
|
|
254
|
+
### Framework demo consumers
|
|
255
|
+
|
|
256
|
+
Minimal demo apps for React (Vite), Next.js, TanStack Router (Vite), Vue, and Svelte are available under `examples/` and all share
|
|
257
|
+
`examples/shared/brand-contract.json`.
|
|
258
|
+
|
|
259
|
+
- `examples/react-vite`
|
|
260
|
+
- `examples/next-app`
|
|
261
|
+
- `examples/tanstack-vite`
|
|
262
|
+
- `examples/vue-vite`
|
|
263
|
+
- `examples/svelte-vite`
|
|
264
|
+
|
|
265
|
+
Quick commands from repo root:
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
bun run demo:setup
|
|
269
|
+
bun run demo:dev:react
|
|
270
|
+
bun run demo:dev:vue
|
|
271
|
+
bun run demo:dev:svelte
|
|
272
|
+
bun run demo:build:all
|
|
273
|
+
bun run test:smoke
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
See `examples/README.md` for details.
|
|
277
|
+
|
|
278
|
+
### Dev Webapp Docs
|
|
279
|
+
|
|
280
|
+
An interactive docs/playground app lives in `apps/docs` and is intentionally excluded from npm package publish size.
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
bun run docs:setup
|
|
284
|
+
bun run docs:dev
|
|
285
|
+
bun run docs:build
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Versioning and release
|
|
289
|
+
|
|
290
|
+
This repo uses Changesets for controlled SemVer bumps.
|
|
291
|
+
|
|
292
|
+
- every PR must include a changeset (minimum `patch`)
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
bun run changeset
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Bump policy:
|
|
299
|
+
|
|
300
|
+
- `patch`: bug fixes and non-breaking internal changes
|
|
301
|
+
- `minor`: backward-compatible features (new optional fields/exports/adapters)
|
|
302
|
+
- `major`: breaking API/schema/peer range changes
|
|
303
|
+
|
|
304
|
+
Commit enforcement:
|
|
305
|
+
|
|
306
|
+
- PR commits must follow Conventional Commits (checked by `.github/workflows/ci.yml`)
|
|
307
|
+
- every PR must include a `.changeset/*.md` bump entry for `brand-shell` (`patch`/`minor`/`major`)
|
|
308
|
+
- bump intent is auto-checked from commits:
|
|
309
|
+
- `feat` => at least `minor`
|
|
310
|
+
- `fix` / `perf` / `refactor` => at least `patch`
|
|
311
|
+
- `!` or `BREAKING CHANGE:` => `major`
|
|
312
|
+
|
|
313
|
+
Release automation runs in `.github/workflows/release.yml`, which calls the same reusable verification workflow as CI before running Changesets publish steps:
|
|
314
|
+
|
|
315
|
+
- if pending changesets exist, it opens/updates a release PR
|
|
316
|
+
- once that release PR is merged, it publishes to npm with provenance
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://brand-shell.dev/schema/brand-shell.schema.json",
|
|
4
|
+
"title": "Brand Shell Contract",
|
|
5
|
+
"description": "JSON Schema for Brand Shell details and theme payloads.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["details"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"details": {
|
|
11
|
+
"$ref": "#/$defs/BrandDetails"
|
|
12
|
+
},
|
|
13
|
+
"theme": {
|
|
14
|
+
"$ref": "#/$defs/BrandTheme"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"$defs": {
|
|
18
|
+
"Target": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"enum": ["_blank", "_self", "_parent", "_top"]
|
|
21
|
+
},
|
|
22
|
+
"Variant": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"enum": ["primary", "secondary", "ghost"]
|
|
25
|
+
},
|
|
26
|
+
"BrandNavLink": {
|
|
27
|
+
"type": "object",
|
|
28
|
+
"additionalProperties": false,
|
|
29
|
+
"required": ["label", "href"],
|
|
30
|
+
"properties": {
|
|
31
|
+
"label": { "type": "string", "minLength": 1 },
|
|
32
|
+
"href": { "type": "string", "minLength": 1 },
|
|
33
|
+
"ariaLabel": { "type": "string", "minLength": 1 },
|
|
34
|
+
"target": { "$ref": "#/$defs/Target" },
|
|
35
|
+
"rel": { "type": "string", "minLength": 1 }
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"BrandAction": {
|
|
39
|
+
"type": "object",
|
|
40
|
+
"additionalProperties": false,
|
|
41
|
+
"required": ["label", "href"],
|
|
42
|
+
"properties": {
|
|
43
|
+
"label": { "type": "string", "minLength": 1 },
|
|
44
|
+
"href": { "type": "string", "minLength": 1 },
|
|
45
|
+
"ariaLabel": { "type": "string", "minLength": 1 },
|
|
46
|
+
"target": { "$ref": "#/$defs/Target" },
|
|
47
|
+
"rel": { "type": "string", "minLength": 1 },
|
|
48
|
+
"variant": { "$ref": "#/$defs/Variant" }
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"BrandDetails": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"additionalProperties": false,
|
|
54
|
+
"required": ["name"],
|
|
55
|
+
"properties": {
|
|
56
|
+
"name": { "type": "string", "minLength": 1 },
|
|
57
|
+
"homeHref": { "type": "string", "minLength": 1 },
|
|
58
|
+
"navLinks": {
|
|
59
|
+
"type": "array",
|
|
60
|
+
"default": [],
|
|
61
|
+
"items": { "$ref": "#/$defs/BrandNavLink" }
|
|
62
|
+
},
|
|
63
|
+
"primaryAction": { "$ref": "#/$defs/BrandAction" },
|
|
64
|
+
"secondaryAction": { "$ref": "#/$defs/BrandAction" },
|
|
65
|
+
"linkedin": { "type": "string", "minLength": 1 },
|
|
66
|
+
"gmail": { "type": "string", "minLength": 1 },
|
|
67
|
+
"github": { "type": "string", "minLength": 1 },
|
|
68
|
+
"twitter": { "type": "string", "minLength": 1 },
|
|
69
|
+
"discord": { "type": "string", "minLength": 1 },
|
|
70
|
+
"website": { "type": "string", "minLength": 1 },
|
|
71
|
+
"tagline": { "type": "string", "minLength": 1 }
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"BrandTheme": {
|
|
75
|
+
"type": "object",
|
|
76
|
+
"additionalProperties": false,
|
|
77
|
+
"properties": {
|
|
78
|
+
"primaryColor": { "type": "string", "minLength": 1 },
|
|
79
|
+
"backgroundColor": { "type": "string", "minLength": 1 },
|
|
80
|
+
"textColor": { "type": "string", "minLength": 1 },
|
|
81
|
+
"fontFamily": { "type": "string", "minLength": 1 },
|
|
82
|
+
"linkColor": { "type": "string", "minLength": 1 },
|
|
83
|
+
"socialIconSize": { "type": "string", "minLength": 1 },
|
|
84
|
+
"buttonTextColor": { "type": "string", "minLength": 1 },
|
|
85
|
+
"ctaLayout": { "type": "string", "enum": ["inline", "stacked"] }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|