@samva/markup 0.13.1 → 0.15.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/AGENTS.md +12 -2
- package/CHANGELOG.md +58 -0
- package/README.md +1 -1
- package/dist/{assets-DCULM6QD.d.ts → assets-tISHaQNF.d.ts} +1 -1
- package/dist/{brand-C45QBKX9.js → brand-nreeKWxF.js} +5 -5
- package/dist/brand.d.ts +48 -25
- package/dist/brand.js +4 -4
- package/dist/compiler.d.ts +23 -6
- package/dist/compiler.js +658 -200
- package/dist/components-3XHjYD3i.js +401 -0
- package/dist/dark-scheme-CbCwGDWH.js +12 -0
- package/dist/{diagnostic-codes-DdZ4tka5.js → diagnostic-codes-UXwOO3A-.js} +22 -0
- package/dist/diagnostics.d.ts +17 -0
- package/dist/diagnostics.js +1 -1
- package/dist/edit.js +2 -2
- package/dist/email.d.ts +52 -9
- package/dist/email.js +1 -1
- package/dist/{html-eOZfDwVf.js → html-BvRFepeO.js} +9 -0
- package/dist/{ir-C-ubz6N3.js → ir-DNL6H7jA.js} +203 -79
- package/dist/{profile-CXnkfEMi.js → profile-AatO_SvP.js} +135 -13
- package/dist/{render-C6OTH8BQ.d.ts → render-BdvewoQt.d.ts} +19 -0
- package/dist/{render-Cja448i0.js → render-DpYouYYG.js} +8 -6
- package/dist/render.d.ts +1 -1
- package/dist/render.js +3 -3
- package/dist/{theme-css-CEUrDpqq.js → theme-css-s9QwD5Ko.js} +108 -46
- package/dist/whatsapp.d.ts +20 -2
- package/dist/whatsapp.js +3 -2
- package/generated/contract.json +206 -2
- package/generated/reference.md +165 -110
- package/package.json +1 -1
- package/skills/sml/SKILL.md +63 -5
- package/dist/components-DycSEKva.js +0 -273
package/dist/whatsapp.d.ts
CHANGED
|
@@ -36,9 +36,26 @@ interface WhatsAppCopyCodeButtonProps {
|
|
|
36
36
|
/** The code the button copies. */
|
|
37
37
|
readonly children?: EmailChild;
|
|
38
38
|
}
|
|
39
|
+
type WhatsAppFlowAction = "navigate" | "data_exchange";
|
|
40
|
+
interface WhatsAppFlowButtonProps {
|
|
41
|
+
/**
|
|
42
|
+
* The Samva flow handle: lowercase kebab-case, the file `flows/<handle>.json` in the template
|
|
43
|
+
* project. Samva maps it to Meta's flow id per business account when it registers the template.
|
|
44
|
+
*/
|
|
45
|
+
readonly flow: string;
|
|
46
|
+
/** `navigate` by default; `data_exchange` has the flow's endpoint choose the first screen. */
|
|
47
|
+
readonly action?: WhatsAppFlowAction | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* The screen a `navigate` flow opens on (Meta's `navigate_screen`); omitted, the flow's first
|
|
50
|
+
* entry screen. Refused with `data_exchange`.
|
|
51
|
+
*/
|
|
52
|
+
readonly screen?: string | undefined;
|
|
53
|
+
/** The button label. */
|
|
54
|
+
readonly children?: EmailChild;
|
|
55
|
+
}
|
|
39
56
|
/**
|
|
40
57
|
* The root of a WhatsApp body. Meta's template anatomy is the vocabulary: `WhatsApp.Header`,
|
|
41
|
-
* `WhatsApp.Body`, `WhatsApp.Footer` and `WhatsApp.Buttons`, whose children are the
|
|
58
|
+
* `WhatsApp.Body`, `WhatsApp.Footer` and `WhatsApp.Buttons`, whose children are the five button
|
|
42
59
|
* kinds.
|
|
43
60
|
*/
|
|
44
61
|
declare const WhatsApp: ((props: WhatsAppProps) => EmailNode) & {
|
|
@@ -50,6 +67,7 @@ declare const WhatsApp: ((props: WhatsAppProps) => EmailNode) & {
|
|
|
50
67
|
QuickReplyButton: (props: WhatsAppQuickReplyButtonProps) => EmailNode;
|
|
51
68
|
PhoneButton: (props: WhatsAppPhoneButtonProps) => EmailNode;
|
|
52
69
|
CopyCodeButton: (props: WhatsAppCopyCodeButtonProps) => EmailNode;
|
|
70
|
+
FlowButton: (props: WhatsAppFlowButtonProps) => EmailNode;
|
|
53
71
|
};
|
|
54
72
|
//#endregion
|
|
55
|
-
export { WhatsApp, WhatsAppButtonsProps, type WhatsAppCategory, WhatsAppCopyCodeButtonProps, WhatsAppHeaderProps, type WhatsAppHeaderType, WhatsAppPhoneButtonProps, WhatsAppProps, WhatsAppQuickReplyButtonProps, WhatsAppTextProps, WhatsAppUrlButtonProps };
|
|
73
|
+
export { WhatsApp, WhatsAppButtonsProps, type WhatsAppCategory, WhatsAppCopyCodeButtonProps, WhatsAppFlowAction, WhatsAppFlowButtonProps, WhatsAppHeaderProps, type WhatsAppHeaderType, WhatsAppPhoneButtonProps, WhatsAppProps, WhatsAppQuickReplyButtonProps, WhatsAppTextProps, WhatsAppUrlButtonProps };
|
package/dist/whatsapp.js
CHANGED
|
@@ -3,7 +3,7 @@ import { a as jsx, n as Fragment } from "./jsx-runtime-CBlexoeR.js";
|
|
|
3
3
|
const fragment = (children) => jsx(Fragment, { children });
|
|
4
4
|
/**
|
|
5
5
|
* The root of a WhatsApp body. Meta's template anatomy is the vocabulary: `WhatsApp.Header`,
|
|
6
|
-
* `WhatsApp.Body`, `WhatsApp.Footer` and `WhatsApp.Buttons`, whose children are the
|
|
6
|
+
* `WhatsApp.Body`, `WhatsApp.Footer` and `WhatsApp.Buttons`, whose children are the five button
|
|
7
7
|
* kinds.
|
|
8
8
|
*/
|
|
9
9
|
const WhatsApp = Object.assign((props) => fragment(props.children), {
|
|
@@ -14,7 +14,8 @@ const WhatsApp = Object.assign((props) => fragment(props.children), {
|
|
|
14
14
|
UrlButton: (props) => fragment(props.children),
|
|
15
15
|
QuickReplyButton: (props) => fragment(props.children),
|
|
16
16
|
PhoneButton: (props) => fragment(props.children),
|
|
17
|
-
CopyCodeButton: (props) => fragment(props.children)
|
|
17
|
+
CopyCodeButton: (props) => fragment(props.children),
|
|
18
|
+
FlowButton: (props) => fragment(props.children)
|
|
18
19
|
});
|
|
19
20
|
//#endregion
|
|
20
21
|
export { WhatsApp };
|
package/generated/contract.json
CHANGED
|
@@ -164,7 +164,14 @@
|
|
|
164
164
|
{
|
|
165
165
|
"name": "backgroundColor",
|
|
166
166
|
"type": "string",
|
|
167
|
-
"optional": true
|
|
167
|
+
"optional": true,
|
|
168
|
+
"description": "The page color, painted across the whole body and, as `bgcolor`, on the wrapper table for clients that drop body styles. Defaults to the theme's `--color-background`, which switches in dark mode."
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"name": "gutter",
|
|
172
|
+
"type": "number",
|
|
173
|
+
"optional": true,
|
|
174
|
+
"description": "Pixels of space each side of the content, so it never touches the screen edge on a narrow viewport. Defaults to 16; `0` lets content run edge to edge."
|
|
168
175
|
},
|
|
169
176
|
{
|
|
170
177
|
"name": "style",
|
|
@@ -197,7 +204,8 @@
|
|
|
197
204
|
{
|
|
198
205
|
"name": "width",
|
|
199
206
|
"type": "number | string",
|
|
200
|
-
"optional": true
|
|
207
|
+
"optional": true,
|
|
208
|
+
"description": "The band's width. A pixel width (`600`) is a maximum: the band fills a narrower screen, and classic Outlook, which ignores `max-width`, draws it at that width."
|
|
201
209
|
},
|
|
202
210
|
{
|
|
203
211
|
"name": "bgcolor",
|
|
@@ -259,6 +267,18 @@
|
|
|
259
267
|
"optional": true,
|
|
260
268
|
"description": "With `each`, the cells in a row; each chunk of items is its own `Columns` table."
|
|
261
269
|
},
|
|
270
|
+
{
|
|
271
|
+
"name": "stack",
|
|
272
|
+
"type": "boolean",
|
|
273
|
+
"optional": true,
|
|
274
|
+
"description": "Stack the cells into one column, each full width, on a viewport narrower than 600px. On by default; `stack={false}` keeps a row of small cells (icons, a price beside a label) side by side. Clients that ignore media queries keep the row."
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
"name": "gap",
|
|
278
|
+
"type": "number",
|
|
279
|
+
"optional": true,
|
|
280
|
+
"description": "Pixels between the cells of a row. A stacked row puts the same space between the stacked cells instead, so a gap needs no padding on the cells that would misalign them when stacked. The cells must be written out and always render."
|
|
281
|
+
},
|
|
262
282
|
{
|
|
263
283
|
"name": "children",
|
|
264
284
|
"type": "EmailChild | ((item: Item, index: number) => EmailChild)",
|
|
@@ -700,6 +720,36 @@
|
|
|
700
720
|
"description": "The code the button copies."
|
|
701
721
|
}
|
|
702
722
|
]
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
"name": "WhatsApp.FlowButton",
|
|
726
|
+
"import": "@samva/markup/whatsapp",
|
|
727
|
+
"props": [
|
|
728
|
+
{
|
|
729
|
+
"name": "flow",
|
|
730
|
+
"type": "string",
|
|
731
|
+
"optional": false,
|
|
732
|
+
"description": "The Samva flow handle: lowercase kebab-case, the file `flows/<handle>.json` in the template project. Samva maps it to Meta's flow id per business account when it registers the template."
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
"name": "action",
|
|
736
|
+
"type": "WhatsAppFlowAction",
|
|
737
|
+
"optional": true,
|
|
738
|
+
"description": "`navigate` by default; `data_exchange` has the flow's endpoint choose the first screen."
|
|
739
|
+
},
|
|
740
|
+
{
|
|
741
|
+
"name": "screen",
|
|
742
|
+
"type": "string",
|
|
743
|
+
"optional": true,
|
|
744
|
+
"description": "The screen a `navigate` flow opens on (Meta's `navigate_screen`); omitted, the flow's first entry screen. Refused with `data_exchange`."
|
|
745
|
+
},
|
|
746
|
+
{
|
|
747
|
+
"name": "children",
|
|
748
|
+
"type": "EmailChild",
|
|
749
|
+
"optional": true,
|
|
750
|
+
"description": "The button label."
|
|
751
|
+
}
|
|
752
|
+
]
|
|
703
753
|
}
|
|
704
754
|
],
|
|
705
755
|
"elements": {
|
|
@@ -1274,10 +1324,143 @@
|
|
|
1274
1324
|
"styles": {
|
|
1275
1325
|
"dialect": "Tailwind classes plus theme.css tokens. Classes must be literal.",
|
|
1276
1326
|
"themeLayers": [
|
|
1327
|
+
"the default theme",
|
|
1277
1328
|
"@import \"./starter.css\";",
|
|
1278
1329
|
"@import \"samva:brand\";",
|
|
1279
1330
|
"the project's own @theme"
|
|
1280
1331
|
],
|
|
1332
|
+
"theme": {
|
|
1333
|
+
"colors": [
|
|
1334
|
+
{
|
|
1335
|
+
"name": "background",
|
|
1336
|
+
"variable": "--color-background",
|
|
1337
|
+
"role": "The page, behind everything.",
|
|
1338
|
+
"light": "#ffffff",
|
|
1339
|
+
"dark": "#0a0a0a"
|
|
1340
|
+
},
|
|
1341
|
+
{
|
|
1342
|
+
"name": "foreground",
|
|
1343
|
+
"variable": "--color-foreground",
|
|
1344
|
+
"role": "Text on the page.",
|
|
1345
|
+
"light": "#0a0a0a",
|
|
1346
|
+
"dark": "#fafafa"
|
|
1347
|
+
},
|
|
1348
|
+
{
|
|
1349
|
+
"name": "card",
|
|
1350
|
+
"variable": "--color-card",
|
|
1351
|
+
"role": "A surface that groups the message's content.",
|
|
1352
|
+
"light": "#ffffff",
|
|
1353
|
+
"dark": "#171717"
|
|
1354
|
+
},
|
|
1355
|
+
{
|
|
1356
|
+
"name": "card-foreground",
|
|
1357
|
+
"variable": "--color-card-foreground",
|
|
1358
|
+
"role": "Text on a card.",
|
|
1359
|
+
"light": "#0a0a0a",
|
|
1360
|
+
"dark": "#fafafa"
|
|
1361
|
+
},
|
|
1362
|
+
{
|
|
1363
|
+
"name": "primary",
|
|
1364
|
+
"variable": "--color-primary",
|
|
1365
|
+
"role": "The main action's fill (a button), and links.",
|
|
1366
|
+
"light": "#171717",
|
|
1367
|
+
"dark": "#fafafa"
|
|
1368
|
+
},
|
|
1369
|
+
{
|
|
1370
|
+
"name": "primary-foreground",
|
|
1371
|
+
"variable": "--color-primary-foreground",
|
|
1372
|
+
"role": "Text on a primary fill.",
|
|
1373
|
+
"light": "#fafafa",
|
|
1374
|
+
"dark": "#171717"
|
|
1375
|
+
},
|
|
1376
|
+
{
|
|
1377
|
+
"name": "secondary",
|
|
1378
|
+
"variable": "--color-secondary",
|
|
1379
|
+
"role": "A quieter action's fill.",
|
|
1380
|
+
"light": "#f5f5f5",
|
|
1381
|
+
"dark": "#262626"
|
|
1382
|
+
},
|
|
1383
|
+
{
|
|
1384
|
+
"name": "secondary-foreground",
|
|
1385
|
+
"variable": "--color-secondary-foreground",
|
|
1386
|
+
"role": "Text on a secondary fill.",
|
|
1387
|
+
"light": "#171717",
|
|
1388
|
+
"dark": "#fafafa"
|
|
1389
|
+
},
|
|
1390
|
+
{
|
|
1391
|
+
"name": "muted",
|
|
1392
|
+
"variable": "--color-muted",
|
|
1393
|
+
"role": "A subdued surface: a code block, a table header.",
|
|
1394
|
+
"light": "#f5f5f5",
|
|
1395
|
+
"dark": "#262626"
|
|
1396
|
+
},
|
|
1397
|
+
{
|
|
1398
|
+
"name": "muted-foreground",
|
|
1399
|
+
"variable": "--color-muted-foreground",
|
|
1400
|
+
"role": "Secondary text on the page, a card or a muted surface: labels, captions, the footer.",
|
|
1401
|
+
"light": "#737373",
|
|
1402
|
+
"dark": "#a3a3a3"
|
|
1403
|
+
},
|
|
1404
|
+
{
|
|
1405
|
+
"name": "accent",
|
|
1406
|
+
"variable": "--color-accent",
|
|
1407
|
+
"role": "A highlighted surface: a callout, a selected row.",
|
|
1408
|
+
"light": "#f5f5f5",
|
|
1409
|
+
"dark": "#262626"
|
|
1410
|
+
},
|
|
1411
|
+
{
|
|
1412
|
+
"name": "accent-foreground",
|
|
1413
|
+
"variable": "--color-accent-foreground",
|
|
1414
|
+
"role": "Text on an accent surface.",
|
|
1415
|
+
"light": "#171717",
|
|
1416
|
+
"dark": "#fafafa"
|
|
1417
|
+
},
|
|
1418
|
+
{
|
|
1419
|
+
"name": "border",
|
|
1420
|
+
"variable": "--color-border",
|
|
1421
|
+
"role": "Rules, dividers and outlines.",
|
|
1422
|
+
"light": "#e5e5e5",
|
|
1423
|
+
"dark": "#2e2e2e"
|
|
1424
|
+
}
|
|
1425
|
+
],
|
|
1426
|
+
"tokens": [
|
|
1427
|
+
{
|
|
1428
|
+
"variable": "--radius",
|
|
1429
|
+
"default": "8px"
|
|
1430
|
+
},
|
|
1431
|
+
{
|
|
1432
|
+
"variable": "--font-sans",
|
|
1433
|
+
"default": "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif"
|
|
1434
|
+
},
|
|
1435
|
+
{
|
|
1436
|
+
"variable": "--font-heading",
|
|
1437
|
+
"default": "var(--font-sans)"
|
|
1438
|
+
}
|
|
1439
|
+
],
|
|
1440
|
+
"darkMode": "One mechanism: the theme's @media (prefers-color-scheme: dark) { @theme { --color-*: … } } block. Write each token's utility once (bg-card); every declaration that reads a color the dark block sets switches in dark mode. Use dark: only to pick a different token in dark mode. Opacity modifiers (bg-primary/10) keep the light value.",
|
|
1441
|
+
"layering": "Each layer owns the colors it sets: a color a layer sets in light mode and not in its dark block keeps that value in dark mode.",
|
|
1442
|
+
"fillForegrounds": "A layer that sets --color-primary, --color-secondary, --color-accent without its -foreground gets black or white, whichever contrasts more, in each mode."
|
|
1443
|
+
},
|
|
1444
|
+
"contrast": {
|
|
1445
|
+
"textError": 3,
|
|
1446
|
+
"textWarning": 4.5,
|
|
1447
|
+
"largePx": 24,
|
|
1448
|
+
"largeBoldPx": 18.5,
|
|
1449
|
+
"shapeError": 1.5,
|
|
1450
|
+
"shapeWarning": 3,
|
|
1451
|
+
"border": 3
|
|
1452
|
+
},
|
|
1453
|
+
"primitives": {
|
|
1454
|
+
"classes": {
|
|
1455
|
+
"email": "sml-email",
|
|
1456
|
+
"button": "sml-button",
|
|
1457
|
+
"link": "sml-link",
|
|
1458
|
+
"divider": "sml-divider",
|
|
1459
|
+
"stack": "sml-stack"
|
|
1460
|
+
},
|
|
1461
|
+
"stackBelowPx": 600,
|
|
1462
|
+
"defaults": "Primitive defaults sit beneath utilities: a class on a primitive overrides its default; a prop is an inline style and overrides both."
|
|
1463
|
+
},
|
|
1281
1464
|
"fonts": "WOFF2 files in the project through @font-face; a stack must end in a generic family."
|
|
1282
1465
|
},
|
|
1283
1466
|
"channels": {
|
|
@@ -1367,6 +1550,12 @@
|
|
|
1367
1550
|
"summary": "A prop that sizes layout at compile time is not a number literal.",
|
|
1368
1551
|
"fix": "Write the number literally, for example height={44}."
|
|
1369
1552
|
},
|
|
1553
|
+
{
|
|
1554
|
+
"code": "email-contrast",
|
|
1555
|
+
"summary": "Text, or a filled button against its surroundings, falls below the contrast ratio in light or dark mode (below 1.5:1 a button is indistinguishable from its surface; WCAG 1.4.11 asks 3:1).",
|
|
1556
|
+
"fix": "Pair background and text tokens (bg-primary with text-primary-foreground), give the theme's dark-mode @theme a value for the token, or choose colors that reach the required ratio.",
|
|
1557
|
+
"upgrade": "Move the project's theme onto the theme vocabulary with one dark-mode block. In starter.css and theme.css, rename each color token to the vocabulary name for its role (reference.md, Theme): a page color to --color-background, the main text to --color-foreground, a surface to --color-card with --color-card-foreground, the brand or action color to --color-primary with --color-primary-foreground, subdued text to --color-muted-foreground, a highlight to --color-accent with --color-accent-foreground, rules to --color-border, body and heading fonts to --font-sans and --font-heading, and a corner radius to --radius. Keep every value.\n\nMove each --color-<name>-dark value into @media (prefers-color-scheme: dark) { @theme { --color-<name>: <value>; } } under the renamed token, and delete the -dark tokens. In every template and partial, rename the utilities to match (bg-surface to bg-card, text-muted to text-muted-foreground, and so on) and delete each dark:…-dark class whose token now has a dark value; keep a dark: class only where it picks a different token in dark mode.\n\nThen fix what email-contrast still reports at its location: pair each fill with its -foreground token, or give the dark block a value that reaches the ratio. Do not weaken the design to pass: keep the brand's colors and adjust the paired token.\n\nCompile every entry and render every fixture in light and dark mode; confirm the light render is unchanged apart from fixes. Resolve errors before requesting one saved version for the whole project, approved by the user; do not publish."
|
|
1558
|
+
},
|
|
1370
1559
|
{
|
|
1371
1560
|
"code": "email-font-fallback",
|
|
1372
1561
|
"summary": "A font stack names a project font without a generic fallback.",
|
|
@@ -1453,11 +1642,21 @@
|
|
|
1453
1642
|
"summary": "<Columns each> is not a list from the input.",
|
|
1454
1643
|
"fix": "Write each={input.items} with a callback returning <Column>."
|
|
1455
1644
|
},
|
|
1645
|
+
{
|
|
1646
|
+
"code": "invalid-columns-gap",
|
|
1647
|
+
"summary": "<Columns gap> is set on a Columns whose cells are repeated with each or rendered conditionally.",
|
|
1648
|
+
"fix": "Write each Column out unconditionally, or pad the cells instead of using gap."
|
|
1649
|
+
},
|
|
1456
1650
|
{
|
|
1457
1651
|
"code": "invalid-columns-per",
|
|
1458
1652
|
"summary": "<Columns per> is not a positive integer literal.",
|
|
1459
1653
|
"fix": "Write per={2}."
|
|
1460
1654
|
},
|
|
1655
|
+
{
|
|
1656
|
+
"code": "invalid-columns-stack",
|
|
1657
|
+
"summary": "<Columns stack> is not a true or false literal.",
|
|
1658
|
+
"fix": "Write stack={false}, or leave it out to stack on narrow screens."
|
|
1659
|
+
},
|
|
1461
1660
|
{
|
|
1462
1661
|
"code": "invalid-content",
|
|
1463
1662
|
"summary": "An element holds content its content model does not allow.",
|
|
@@ -1473,6 +1672,11 @@
|
|
|
1473
1672
|
"summary": "The template's default locale is not a string literal.",
|
|
1474
1673
|
"fix": "Write locale: \"en-US\"."
|
|
1475
1674
|
},
|
|
1675
|
+
{
|
|
1676
|
+
"code": "invalid-number-prop",
|
|
1677
|
+
"summary": "A primitive's numeric prop, such as <Email gutter>, is not a finite number in range.",
|
|
1678
|
+
"fix": "Pass a finite number the message allows, for example gutter={16}."
|
|
1679
|
+
},
|
|
1476
1680
|
{
|
|
1477
1681
|
"code": "invalid-preheader",
|
|
1478
1682
|
"summary": "The preheader is not a string.",
|