@talqui-oss/template-builder 0.0.0-stage → 0.1.0-beta.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.
@@ -0,0 +1,315 @@
1
+ import { T as Template, H as HttpRequest, A as Adapter, V as Variables, C as Category, S as StandardTemplate } from './types-CRH48UOs.cjs';
2
+ export { a as AuthenticationTemplate, B as Button, b as CarouselCard, c as CatalogButton, d as CopyCodeButton, F as FlowButton, e as Header, L as LimitedTimeOffer, f as LocationHeader, M as MediaHeader, g as MultiProductButton, O as OrderDetailsButton, h as OtpButton, P as PaymentRequestButton, i as PhoneNumberButton, j as ProductHeader, Q as QuickReplyButton, k as SingleProductButton, l as SupportedApp, m as TextHeader, U as UnsupportedByProviderError, n as UrlButton, o as Variable, p as VoiceCallButton, q as defineAdapter } from './types-CRH48UOs.cjs';
3
+
4
+ /** Every issue `validate` can report, with its default severity. Codes are stable across releases. */
5
+ declare const codes: {
6
+ readonly SCHEMA_INVALID: "error";
7
+ readonly NAME_INVALID: "error";
8
+ readonly NAME_TOO_LONG: "error";
9
+ readonly LANGUAGE_INVALID: "error";
10
+ readonly CATEGORY_MISMATCH: "error";
11
+ readonly TTL_OUT_OF_RANGE: "error";
12
+ readonly PLACEHOLDER_INVALID: "error";
13
+ readonly PLACEHOLDER_DUPLICATED: "error";
14
+ readonly VARIABLE_NOT_DECLARED: "error";
15
+ readonly VARIABLE_MISSING_EXAMPLE: "error";
16
+ readonly VARIABLE_UNUSED: "warning";
17
+ readonly PARAM_RATIO_TOO_HIGH: "error";
18
+ readonly PARAM_ADJACENT: "error";
19
+ readonly PARAM_AT_EDGE: "error";
20
+ readonly HEADER_TEXT_REQUIRED: "error";
21
+ readonly HEADER_TOO_LONG: "error";
22
+ readonly HEADER_TOO_MANY_PARAMS: "error";
23
+ readonly HEADER_NEWLINE: "error";
24
+ readonly HEADER_EMOJI: "error";
25
+ readonly HEADER_FORMATTING: "error";
26
+ readonly HEADER_MEDIA_URL_INVALID: "error";
27
+ readonly BODY_REQUIRED: "error";
28
+ readonly BODY_TOO_LONG: "error";
29
+ readonly BODY_MULTIPLE_NEWLINES: "error";
30
+ readonly BODY_EMOJI_LIMIT: "error";
31
+ readonly FOOTER_TOO_LONG: "error";
32
+ readonly FOOTER_PARAMETER: "error";
33
+ readonly FOOTER_NEWLINE: "error";
34
+ readonly FOOTER_EMOJI: "error";
35
+ readonly COMPONENT_NOT_ALLOWED: "error";
36
+ readonly FOOTER_OPT_OUT_MISSING: "warning";
37
+ readonly BUTTONS_TOO_MANY: "error";
38
+ readonly BUTTONS_TYPE_LIMIT: "error";
39
+ readonly QUICK_REPLIES_NOT_GROUPED: "error";
40
+ readonly BUTTONS_PARTLY_HIDDEN: "warning";
41
+ readonly BUTTONS_DESKTOP_UNSUPPORTED: "warning";
42
+ readonly BUTTON_LABEL_REQUIRED: "error";
43
+ readonly BUTTON_LABEL_TOO_LONG: "error";
44
+ readonly BUTTON_LABEL_PARAMETER: "error";
45
+ readonly BUTTON_LABEL_FORMATTING: "error";
46
+ readonly BUTTON_LABEL_DUPLICATED: "error";
47
+ readonly BUTTON_URL_INVALID: "error";
48
+ readonly BUTTON_URL_TOO_LONG: "error";
49
+ readonly BUTTON_URL_PARAM_POSITION: "error";
50
+ readonly BUTTON_URL_WHATSAPP_DIRECT: "error";
51
+ readonly BUTTON_URL_SHORTENED: "error";
52
+ readonly BUTTON_URL_REDIRECT: "error";
53
+ readonly BUTTON_PHONE_INVALID: "error";
54
+ readonly BUTTON_COPY_CODE_EXAMPLE_REQUIRED: "error";
55
+ readonly BUTTON_COPY_CODE_EXAMPLE_TOO_LONG: "error";
56
+ readonly LTO_TEXT_REQUIRED: "error";
57
+ readonly LTO_TEXT_TOO_LONG: "error";
58
+ readonly LTO_URL_BUTTON_REQUIRED: "error";
59
+ readonly CAROUSEL_CARDS_COUNT: "error";
60
+ readonly CAROUSEL_CARDS_MISMATCH: "error";
61
+ readonly CAROUSEL_CARD_MEDIA_URL_INVALID: "error";
62
+ readonly CAROUSEL_CARD_BODY_REQUIRED: "error";
63
+ readonly CAROUSEL_CARD_BODY_TOO_LONG: "error";
64
+ readonly CAROUSEL_CARD_BODY_NEWLINES: "error";
65
+ readonly CAROUSEL_CARD_BUTTONS_REQUIRED: "error";
66
+ readonly CAROUSEL_CARD_BUTTONS_TOO_MANY: "error";
67
+ readonly CALL_PERMISSION_NOT_COMBINABLE: "error";
68
+ readonly ORDER_DETAILS_MISMATCH: "error";
69
+ readonly BUTTON_ORDER_DETAILS_TEXT: "error";
70
+ readonly OTP_CODE_EXPIRATION_RANGE: "error";
71
+ readonly OTP_BUTTON_TEXT_TOO_LONG: "error";
72
+ readonly OTP_BUTTON_TEXT_URL: "error";
73
+ readonly OTP_SUPPORTED_APPS_REQUIRED: "error";
74
+ readonly OTP_SUPPORTED_APPS_TOO_MANY: "error";
75
+ readonly OTP_SUPPORTED_APP_DUPLICATED: "error";
76
+ readonly OTP_PACKAGE_NAME_INVALID: "error";
77
+ readonly OTP_SIGNATURE_HASH_INVALID: "error";
78
+ readonly OTP_ZERO_TAP_TERMS_NOT_ACCEPTED: "error";
79
+ };
80
+ type Code = keyof typeof codes;
81
+
82
+ type Severity = "error" | "warning";
83
+ type Issue = {
84
+ code: Code;
85
+ /** Dot path to the field, e.g. `buttons.1.text`. Empty for the whole template. */
86
+ path: string;
87
+ message: string;
88
+ severity: Severity;
89
+ };
90
+ type ValidationResult = {
91
+ /** `true` when there are no errors. Warnings do not make a template invalid. */
92
+ valid: boolean;
93
+ issues: Issue[];
94
+ };
95
+ type ValidateOptions = {
96
+ /** Rules to skip, e.g. when a provider has exempted your account from one of them. */
97
+ disable?: Code[];
98
+ /** Domains rejected in URL buttons. */
99
+ shortenerDomains?: string[];
100
+ /** Maximum characters for the limited-time offer text. */
101
+ limitedTimeOfferTextLimit?: number;
102
+ /** Maximum characters for a carousel card body. */
103
+ carouselCardBodyLimit?: number;
104
+ };
105
+
106
+ /** Checks a template against the rules WhatsApp applies before review. */
107
+ declare function validate(template: Template, options?: ValidateOptions): ValidationResult;
108
+
109
+ /** Variable names in order of first appearance: header, body, carousel cards, then button URLs. */
110
+ declare function extractVariables(template: Template): string[];
111
+
112
+ /** Thrown by `toRequests` when the template has validation errors. */
113
+ declare class TemplateValidationError extends Error {
114
+ readonly issues: Issue[];
115
+ constructor(issues: Issue[]);
116
+ }
117
+ /** Validates the template and returns the HTTP requests that create it on the adapter's provider. */
118
+ declare function toRequests(template: Template, adapter: Adapter, options?: ValidateOptions): HttpRequest[];
119
+ /** Prints requests as `curl` commands, in order, ready to paste in a shell. */
120
+ declare function toCurl(requests: HttpRequest | HttpRequest[]): string;
121
+
122
+ /**
123
+ * WhatsApp text formatting, parsed into lines and styled spans.
124
+ *
125
+ * Supported, as WhatsApp renders them:
126
+ * *bold* _italic_ ~strike~ ```monospace``` `inline code`
127
+ * "- " or "* " bullet lines, "1. " numbered lines, "> " quote lines,
128
+ * and ``` blocks spanning several lines.
129
+ */
130
+ type Span = {
131
+ text: string;
132
+ bold?: true;
133
+ italic?: true;
134
+ strike?: true;
135
+ /** ```monospace``` inside a line. */
136
+ mono?: true;
137
+ /** `inline code`. */
138
+ code?: true;
139
+ /** Set when the span is a `{{name}}` placeholder; `text` holds its value. */
140
+ variable?: string;
141
+ };
142
+ type Line = {
143
+ kind: "paragraph" | "quote";
144
+ spans: Span[];
145
+ } | {
146
+ kind: "bullet";
147
+ spans: Span[];
148
+ } | {
149
+ kind: "numbered";
150
+ marker: string;
151
+ spans: Span[];
152
+ } | {
153
+ kind: "code";
154
+ text: string;
155
+ };
156
+
157
+ /** Icon shown next to a button label. Bindings map each one to an SVG. */
158
+ type ButtonIcon = "reply" | "link" | "phone" | "copy" | "list" | "cart";
159
+ type PreviewButton = {
160
+ label: string;
161
+ icon: ButtonIcon;
162
+ };
163
+ type PreviewHeader = {
164
+ type: "TEXT";
165
+ lines: Line[];
166
+ } | {
167
+ type: "IMAGE" | "VIDEO" | "GIF";
168
+ url: string;
169
+ } | {
170
+ type: "DOCUMENT";
171
+ url: string;
172
+ filename: string;
173
+ } | {
174
+ type: "LOCATION";
175
+ } | {
176
+ type: "PRODUCT";
177
+ };
178
+ type PreviewCard = {
179
+ header: PreviewHeader;
180
+ body: Line[];
181
+ buttons: PreviewButton[];
182
+ };
183
+ /** Everything a binding needs to draw a template, already resolved. */
184
+ type PreviewModel = {
185
+ header?: PreviewHeader;
186
+ /** Shown by WhatsApp at the top when there is no header and a button links out. */
187
+ linkPreview?: {
188
+ domain: string;
189
+ };
190
+ limitedTimeOffer?: {
191
+ text: string;
192
+ hasExpiration: boolean;
193
+ };
194
+ body: Line[];
195
+ footer?: Line[];
196
+ /** Buttons inside the bubble, in display order. */
197
+ buttons: PreviewButton[];
198
+ /** Buttons moved behind "See all options" when there are more than 3. */
199
+ overflow: PreviewButton[];
200
+ carousel?: PreviewCard[];
201
+ issues: Issue[];
202
+ };
203
+ type PreviewOptions = {
204
+ /** Values for `{{name}}` placeholders. Falls back to each variable's `example`. */
205
+ values?: Record<string, string>;
206
+ /** Language of the phone, for the texts WhatsApp itself writes there. Default `en`. */
207
+ deviceLanguage?: string;
208
+ };
209
+ /**
210
+ * Turns a template into a render-ready model. Invalid templates still render,
211
+ * so editors can preview while the user types; problems are listed in `issues`.
212
+ */
213
+ declare function toPreviewModel(template: Template, { values, deviceLanguage }?: PreviewOptions): PreviewModel;
214
+
215
+ type PreviewNode = {
216
+ tag: string;
217
+ class?: string;
218
+ attrs?: Record<string, string>;
219
+ children?: (PreviewNode | string)[];
220
+ };
221
+ /** Platforms the preview can imitate. Android is planned. */
222
+ type Platform = "ios";
223
+ type TreeOptions = {
224
+ platform?: Platform;
225
+ /** Time shown in the bubble, e.g. "21:11". */
226
+ time?: string;
227
+ };
228
+ declare function previewTree(model: PreviewModel, { platform, time }?: TreeOptions): PreviewNode;
229
+
230
+ /**
231
+ * The template editor as data: sections of fields that a binding renders, and `applyEdit`
232
+ * to turn a change in one field into the next template. React and Vue share this logic and
233
+ * only translate it into elements.
234
+ */
235
+ type EditorOption = {
236
+ value: string;
237
+ label: string;
238
+ };
239
+ type FieldBase = {
240
+ /** Identifies the field in `applyEdit`, e.g. `"body"` or `"buttons.1.url"`. */
241
+ id: string;
242
+ label: string;
243
+ /** Short note next to the label, such as a character count. */
244
+ hint?: string;
245
+ };
246
+ type EditorField = (FieldBase & {
247
+ kind: "text" | "textarea";
248
+ value: string;
249
+ placeholder?: string;
250
+ /** Code-like values (names, URLs, numbers) use a monospaced font. */
251
+ mono?: boolean;
252
+ }) | (FieldBase & {
253
+ kind: "select";
254
+ value: string;
255
+ options: EditorOption[];
256
+ }) | (FieldBase & {
257
+ kind: "segment";
258
+ value: string;
259
+ options: EditorOption[];
260
+ }) | (FieldBase & {
261
+ kind: "checkbox";
262
+ checked: boolean;
263
+ }) | (FieldBase & {
264
+ kind: "action";
265
+ icon: "add" | "remove";
266
+ disabled?: boolean;
267
+ });
268
+ type EditorRow = {
269
+ fields: EditorField[];
270
+ /** Rows of a list (one per button) get a compact layout. */
271
+ list?: boolean;
272
+ };
273
+ type EditorSection = {
274
+ id: "basics" | "content" | "buttons" | "variables" | "code";
275
+ title: string;
276
+ rows: EditorRow[];
277
+ /** Help text under the section, e.g. the formatting syntax. */
278
+ note?: string;
279
+ };
280
+ type EditorOptions = {
281
+ /** Languages offered in the language select. Default: English (US), Portuguese (BR), Spanish. */
282
+ languages?: EditorOption[];
283
+ };
284
+ /** The sections of the editor for a template. */
285
+ declare function editorSections(template: Template, options?: EditorOptions): EditorSection[];
286
+ /**
287
+ * The template after an edit. `value` is the new text or option for inputs and selects, a
288
+ * boolean for checkboxes, and nothing for actions. Placeholders added or removed in the text
289
+ * are synced into `variables`, keeping the examples already typed.
290
+ *
291
+ * `remembered` holds examples of variables seen earlier: while someone types `{{name}}` the
292
+ * placeholder is briefly incomplete, and its example comes back from here once it is whole.
293
+ */
294
+ declare function applyEdit(template: Template, id: string, value?: string | boolean, remembered?: Variables): Template;
295
+ /**
296
+ * Switches category. Authentication has its own shape, so moving in or out of it keeps only
297
+ * the name and language.
298
+ */
299
+ declare function changeCategory(template: Template, category: Category): Template;
300
+ /** Keeps `variables` in step with the placeholders used in the text, preserving typed examples. */
301
+ declare function syncVariables(template: StandardTemplate, remembered?: Variables): StandardTemplate;
302
+
303
+ /**
304
+ * The editor as a framework-neutral element tree, like `previewTree`. Every control carries
305
+ * `data-edit` (the field id for `applyEdit`); segment items and actions are buttons, the
306
+ * selected value of a segment item is in `data-value`. Boolean attributes (`checked`,
307
+ * `disabled`, `selected`) are present as `""` when true and left out when false.
308
+ */
309
+ declare function editorTree(template: Template, options?: EditorOptions & {
310
+ /** Prefix for element ids, so two editors on a page do not clash. Default: `"tb"`. */
311
+ idPrefix?: string;
312
+ }): PreviewNode;
313
+
314
+ export { Adapter, Category, HttpRequest, StandardTemplate, Template, TemplateValidationError, Variables, applyEdit, changeCategory, codes, editorSections, editorTree, extractVariables, previewTree, syncVariables, toCurl, toPreviewModel, toRequests, validate };
315
+ export type { ButtonIcon, Code, EditorField, EditorOption, EditorOptions, EditorRow, EditorSection, Issue, Line, Platform, PreviewButton, PreviewCard, PreviewHeader, PreviewModel, PreviewNode, PreviewOptions, Severity, Span, TreeOptions, ValidateOptions, ValidationResult };
@@ -0,0 +1,315 @@
1
+ import { T as Template, H as HttpRequest, A as Adapter, V as Variables, C as Category, S as StandardTemplate } from './types-CRH48UOs.js';
2
+ export { a as AuthenticationTemplate, B as Button, b as CarouselCard, c as CatalogButton, d as CopyCodeButton, F as FlowButton, e as Header, L as LimitedTimeOffer, f as LocationHeader, M as MediaHeader, g as MultiProductButton, O as OrderDetailsButton, h as OtpButton, P as PaymentRequestButton, i as PhoneNumberButton, j as ProductHeader, Q as QuickReplyButton, k as SingleProductButton, l as SupportedApp, m as TextHeader, U as UnsupportedByProviderError, n as UrlButton, o as Variable, p as VoiceCallButton, q as defineAdapter } from './types-CRH48UOs.js';
3
+
4
+ /** Every issue `validate` can report, with its default severity. Codes are stable across releases. */
5
+ declare const codes: {
6
+ readonly SCHEMA_INVALID: "error";
7
+ readonly NAME_INVALID: "error";
8
+ readonly NAME_TOO_LONG: "error";
9
+ readonly LANGUAGE_INVALID: "error";
10
+ readonly CATEGORY_MISMATCH: "error";
11
+ readonly TTL_OUT_OF_RANGE: "error";
12
+ readonly PLACEHOLDER_INVALID: "error";
13
+ readonly PLACEHOLDER_DUPLICATED: "error";
14
+ readonly VARIABLE_NOT_DECLARED: "error";
15
+ readonly VARIABLE_MISSING_EXAMPLE: "error";
16
+ readonly VARIABLE_UNUSED: "warning";
17
+ readonly PARAM_RATIO_TOO_HIGH: "error";
18
+ readonly PARAM_ADJACENT: "error";
19
+ readonly PARAM_AT_EDGE: "error";
20
+ readonly HEADER_TEXT_REQUIRED: "error";
21
+ readonly HEADER_TOO_LONG: "error";
22
+ readonly HEADER_TOO_MANY_PARAMS: "error";
23
+ readonly HEADER_NEWLINE: "error";
24
+ readonly HEADER_EMOJI: "error";
25
+ readonly HEADER_FORMATTING: "error";
26
+ readonly HEADER_MEDIA_URL_INVALID: "error";
27
+ readonly BODY_REQUIRED: "error";
28
+ readonly BODY_TOO_LONG: "error";
29
+ readonly BODY_MULTIPLE_NEWLINES: "error";
30
+ readonly BODY_EMOJI_LIMIT: "error";
31
+ readonly FOOTER_TOO_LONG: "error";
32
+ readonly FOOTER_PARAMETER: "error";
33
+ readonly FOOTER_NEWLINE: "error";
34
+ readonly FOOTER_EMOJI: "error";
35
+ readonly COMPONENT_NOT_ALLOWED: "error";
36
+ readonly FOOTER_OPT_OUT_MISSING: "warning";
37
+ readonly BUTTONS_TOO_MANY: "error";
38
+ readonly BUTTONS_TYPE_LIMIT: "error";
39
+ readonly QUICK_REPLIES_NOT_GROUPED: "error";
40
+ readonly BUTTONS_PARTLY_HIDDEN: "warning";
41
+ readonly BUTTONS_DESKTOP_UNSUPPORTED: "warning";
42
+ readonly BUTTON_LABEL_REQUIRED: "error";
43
+ readonly BUTTON_LABEL_TOO_LONG: "error";
44
+ readonly BUTTON_LABEL_PARAMETER: "error";
45
+ readonly BUTTON_LABEL_FORMATTING: "error";
46
+ readonly BUTTON_LABEL_DUPLICATED: "error";
47
+ readonly BUTTON_URL_INVALID: "error";
48
+ readonly BUTTON_URL_TOO_LONG: "error";
49
+ readonly BUTTON_URL_PARAM_POSITION: "error";
50
+ readonly BUTTON_URL_WHATSAPP_DIRECT: "error";
51
+ readonly BUTTON_URL_SHORTENED: "error";
52
+ readonly BUTTON_URL_REDIRECT: "error";
53
+ readonly BUTTON_PHONE_INVALID: "error";
54
+ readonly BUTTON_COPY_CODE_EXAMPLE_REQUIRED: "error";
55
+ readonly BUTTON_COPY_CODE_EXAMPLE_TOO_LONG: "error";
56
+ readonly LTO_TEXT_REQUIRED: "error";
57
+ readonly LTO_TEXT_TOO_LONG: "error";
58
+ readonly LTO_URL_BUTTON_REQUIRED: "error";
59
+ readonly CAROUSEL_CARDS_COUNT: "error";
60
+ readonly CAROUSEL_CARDS_MISMATCH: "error";
61
+ readonly CAROUSEL_CARD_MEDIA_URL_INVALID: "error";
62
+ readonly CAROUSEL_CARD_BODY_REQUIRED: "error";
63
+ readonly CAROUSEL_CARD_BODY_TOO_LONG: "error";
64
+ readonly CAROUSEL_CARD_BODY_NEWLINES: "error";
65
+ readonly CAROUSEL_CARD_BUTTONS_REQUIRED: "error";
66
+ readonly CAROUSEL_CARD_BUTTONS_TOO_MANY: "error";
67
+ readonly CALL_PERMISSION_NOT_COMBINABLE: "error";
68
+ readonly ORDER_DETAILS_MISMATCH: "error";
69
+ readonly BUTTON_ORDER_DETAILS_TEXT: "error";
70
+ readonly OTP_CODE_EXPIRATION_RANGE: "error";
71
+ readonly OTP_BUTTON_TEXT_TOO_LONG: "error";
72
+ readonly OTP_BUTTON_TEXT_URL: "error";
73
+ readonly OTP_SUPPORTED_APPS_REQUIRED: "error";
74
+ readonly OTP_SUPPORTED_APPS_TOO_MANY: "error";
75
+ readonly OTP_SUPPORTED_APP_DUPLICATED: "error";
76
+ readonly OTP_PACKAGE_NAME_INVALID: "error";
77
+ readonly OTP_SIGNATURE_HASH_INVALID: "error";
78
+ readonly OTP_ZERO_TAP_TERMS_NOT_ACCEPTED: "error";
79
+ };
80
+ type Code = keyof typeof codes;
81
+
82
+ type Severity = "error" | "warning";
83
+ type Issue = {
84
+ code: Code;
85
+ /** Dot path to the field, e.g. `buttons.1.text`. Empty for the whole template. */
86
+ path: string;
87
+ message: string;
88
+ severity: Severity;
89
+ };
90
+ type ValidationResult = {
91
+ /** `true` when there are no errors. Warnings do not make a template invalid. */
92
+ valid: boolean;
93
+ issues: Issue[];
94
+ };
95
+ type ValidateOptions = {
96
+ /** Rules to skip, e.g. when a provider has exempted your account from one of them. */
97
+ disable?: Code[];
98
+ /** Domains rejected in URL buttons. */
99
+ shortenerDomains?: string[];
100
+ /** Maximum characters for the limited-time offer text. */
101
+ limitedTimeOfferTextLimit?: number;
102
+ /** Maximum characters for a carousel card body. */
103
+ carouselCardBodyLimit?: number;
104
+ };
105
+
106
+ /** Checks a template against the rules WhatsApp applies before review. */
107
+ declare function validate(template: Template, options?: ValidateOptions): ValidationResult;
108
+
109
+ /** Variable names in order of first appearance: header, body, carousel cards, then button URLs. */
110
+ declare function extractVariables(template: Template): string[];
111
+
112
+ /** Thrown by `toRequests` when the template has validation errors. */
113
+ declare class TemplateValidationError extends Error {
114
+ readonly issues: Issue[];
115
+ constructor(issues: Issue[]);
116
+ }
117
+ /** Validates the template and returns the HTTP requests that create it on the adapter's provider. */
118
+ declare function toRequests(template: Template, adapter: Adapter, options?: ValidateOptions): HttpRequest[];
119
+ /** Prints requests as `curl` commands, in order, ready to paste in a shell. */
120
+ declare function toCurl(requests: HttpRequest | HttpRequest[]): string;
121
+
122
+ /**
123
+ * WhatsApp text formatting, parsed into lines and styled spans.
124
+ *
125
+ * Supported, as WhatsApp renders them:
126
+ * *bold* _italic_ ~strike~ ```monospace``` `inline code`
127
+ * "- " or "* " bullet lines, "1. " numbered lines, "> " quote lines,
128
+ * and ``` blocks spanning several lines.
129
+ */
130
+ type Span = {
131
+ text: string;
132
+ bold?: true;
133
+ italic?: true;
134
+ strike?: true;
135
+ /** ```monospace``` inside a line. */
136
+ mono?: true;
137
+ /** `inline code`. */
138
+ code?: true;
139
+ /** Set when the span is a `{{name}}` placeholder; `text` holds its value. */
140
+ variable?: string;
141
+ };
142
+ type Line = {
143
+ kind: "paragraph" | "quote";
144
+ spans: Span[];
145
+ } | {
146
+ kind: "bullet";
147
+ spans: Span[];
148
+ } | {
149
+ kind: "numbered";
150
+ marker: string;
151
+ spans: Span[];
152
+ } | {
153
+ kind: "code";
154
+ text: string;
155
+ };
156
+
157
+ /** Icon shown next to a button label. Bindings map each one to an SVG. */
158
+ type ButtonIcon = "reply" | "link" | "phone" | "copy" | "list" | "cart";
159
+ type PreviewButton = {
160
+ label: string;
161
+ icon: ButtonIcon;
162
+ };
163
+ type PreviewHeader = {
164
+ type: "TEXT";
165
+ lines: Line[];
166
+ } | {
167
+ type: "IMAGE" | "VIDEO" | "GIF";
168
+ url: string;
169
+ } | {
170
+ type: "DOCUMENT";
171
+ url: string;
172
+ filename: string;
173
+ } | {
174
+ type: "LOCATION";
175
+ } | {
176
+ type: "PRODUCT";
177
+ };
178
+ type PreviewCard = {
179
+ header: PreviewHeader;
180
+ body: Line[];
181
+ buttons: PreviewButton[];
182
+ };
183
+ /** Everything a binding needs to draw a template, already resolved. */
184
+ type PreviewModel = {
185
+ header?: PreviewHeader;
186
+ /** Shown by WhatsApp at the top when there is no header and a button links out. */
187
+ linkPreview?: {
188
+ domain: string;
189
+ };
190
+ limitedTimeOffer?: {
191
+ text: string;
192
+ hasExpiration: boolean;
193
+ };
194
+ body: Line[];
195
+ footer?: Line[];
196
+ /** Buttons inside the bubble, in display order. */
197
+ buttons: PreviewButton[];
198
+ /** Buttons moved behind "See all options" when there are more than 3. */
199
+ overflow: PreviewButton[];
200
+ carousel?: PreviewCard[];
201
+ issues: Issue[];
202
+ };
203
+ type PreviewOptions = {
204
+ /** Values for `{{name}}` placeholders. Falls back to each variable's `example`. */
205
+ values?: Record<string, string>;
206
+ /** Language of the phone, for the texts WhatsApp itself writes there. Default `en`. */
207
+ deviceLanguage?: string;
208
+ };
209
+ /**
210
+ * Turns a template into a render-ready model. Invalid templates still render,
211
+ * so editors can preview while the user types; problems are listed in `issues`.
212
+ */
213
+ declare function toPreviewModel(template: Template, { values, deviceLanguage }?: PreviewOptions): PreviewModel;
214
+
215
+ type PreviewNode = {
216
+ tag: string;
217
+ class?: string;
218
+ attrs?: Record<string, string>;
219
+ children?: (PreviewNode | string)[];
220
+ };
221
+ /** Platforms the preview can imitate. Android is planned. */
222
+ type Platform = "ios";
223
+ type TreeOptions = {
224
+ platform?: Platform;
225
+ /** Time shown in the bubble, e.g. "21:11". */
226
+ time?: string;
227
+ };
228
+ declare function previewTree(model: PreviewModel, { platform, time }?: TreeOptions): PreviewNode;
229
+
230
+ /**
231
+ * The template editor as data: sections of fields that a binding renders, and `applyEdit`
232
+ * to turn a change in one field into the next template. React and Vue share this logic and
233
+ * only translate it into elements.
234
+ */
235
+ type EditorOption = {
236
+ value: string;
237
+ label: string;
238
+ };
239
+ type FieldBase = {
240
+ /** Identifies the field in `applyEdit`, e.g. `"body"` or `"buttons.1.url"`. */
241
+ id: string;
242
+ label: string;
243
+ /** Short note next to the label, such as a character count. */
244
+ hint?: string;
245
+ };
246
+ type EditorField = (FieldBase & {
247
+ kind: "text" | "textarea";
248
+ value: string;
249
+ placeholder?: string;
250
+ /** Code-like values (names, URLs, numbers) use a monospaced font. */
251
+ mono?: boolean;
252
+ }) | (FieldBase & {
253
+ kind: "select";
254
+ value: string;
255
+ options: EditorOption[];
256
+ }) | (FieldBase & {
257
+ kind: "segment";
258
+ value: string;
259
+ options: EditorOption[];
260
+ }) | (FieldBase & {
261
+ kind: "checkbox";
262
+ checked: boolean;
263
+ }) | (FieldBase & {
264
+ kind: "action";
265
+ icon: "add" | "remove";
266
+ disabled?: boolean;
267
+ });
268
+ type EditorRow = {
269
+ fields: EditorField[];
270
+ /** Rows of a list (one per button) get a compact layout. */
271
+ list?: boolean;
272
+ };
273
+ type EditorSection = {
274
+ id: "basics" | "content" | "buttons" | "variables" | "code";
275
+ title: string;
276
+ rows: EditorRow[];
277
+ /** Help text under the section, e.g. the formatting syntax. */
278
+ note?: string;
279
+ };
280
+ type EditorOptions = {
281
+ /** Languages offered in the language select. Default: English (US), Portuguese (BR), Spanish. */
282
+ languages?: EditorOption[];
283
+ };
284
+ /** The sections of the editor for a template. */
285
+ declare function editorSections(template: Template, options?: EditorOptions): EditorSection[];
286
+ /**
287
+ * The template after an edit. `value` is the new text or option for inputs and selects, a
288
+ * boolean for checkboxes, and nothing for actions. Placeholders added or removed in the text
289
+ * are synced into `variables`, keeping the examples already typed.
290
+ *
291
+ * `remembered` holds examples of variables seen earlier: while someone types `{{name}}` the
292
+ * placeholder is briefly incomplete, and its example comes back from here once it is whole.
293
+ */
294
+ declare function applyEdit(template: Template, id: string, value?: string | boolean, remembered?: Variables): Template;
295
+ /**
296
+ * Switches category. Authentication has its own shape, so moving in or out of it keeps only
297
+ * the name and language.
298
+ */
299
+ declare function changeCategory(template: Template, category: Category): Template;
300
+ /** Keeps `variables` in step with the placeholders used in the text, preserving typed examples. */
301
+ declare function syncVariables(template: StandardTemplate, remembered?: Variables): StandardTemplate;
302
+
303
+ /**
304
+ * The editor as a framework-neutral element tree, like `previewTree`. Every control carries
305
+ * `data-edit` (the field id for `applyEdit`); segment items and actions are buttons, the
306
+ * selected value of a segment item is in `data-value`. Boolean attributes (`checked`,
307
+ * `disabled`, `selected`) are present as `""` when true and left out when false.
308
+ */
309
+ declare function editorTree(template: Template, options?: EditorOptions & {
310
+ /** Prefix for element ids, so two editors on a page do not clash. Default: `"tb"`. */
311
+ idPrefix?: string;
312
+ }): PreviewNode;
313
+
314
+ export { Adapter, Category, HttpRequest, StandardTemplate, Template, TemplateValidationError, Variables, applyEdit, changeCategory, codes, editorSections, editorTree, extractVariables, previewTree, syncVariables, toCurl, toPreviewModel, toRequests, validate };
315
+ export type { ButtonIcon, Code, EditorField, EditorOption, EditorOptions, EditorRow, EditorSection, Issue, Line, Platform, PreviewButton, PreviewCard, PreviewHeader, PreviewModel, PreviewNode, PreviewOptions, Severity, Span, TreeOptions, ValidateOptions, ValidationResult };