react-native-revnix 1.4.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.
Files changed (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +766 -0
  3. package/dist/blocks/background.d.ts +101 -0
  4. package/dist/blocks/background.js +165 -0
  5. package/dist/blocks/color.d.ts +88 -0
  6. package/dist/blocks/color.js +329 -0
  7. package/dist/blocks/locale.d.ts +42 -0
  8. package/dist/blocks/locale.js +263 -0
  9. package/dist/blocks/selection.d.ts +49 -0
  10. package/dist/blocks/selection.js +109 -0
  11. package/dist/blocks/style.d.ts +93 -0
  12. package/dist/blocks/style.js +365 -0
  13. package/dist/blocks/tags.d.ts +12 -0
  14. package/dist/blocks/tags.js +121 -0
  15. package/dist/blocks/types.d.ts +301 -0
  16. package/dist/blocks/types.js +44 -0
  17. package/dist/client.d.ts +402 -0
  18. package/dist/client.js +1653 -0
  19. package/dist/device.d.ts +29 -0
  20. package/dist/device.js +137 -0
  21. package/dist/errors.d.ts +39 -0
  22. package/dist/errors.js +68 -0
  23. package/dist/esm/blocks/background.js +160 -0
  24. package/dist/esm/blocks/color.js +318 -0
  25. package/dist/esm/blocks/locale.js +255 -0
  26. package/dist/esm/blocks/selection.js +100 -0
  27. package/dist/esm/blocks/style.js +356 -0
  28. package/dist/esm/blocks/tags.js +117 -0
  29. package/dist/esm/blocks/types.js +40 -0
  30. package/dist/esm/client.js +1649 -0
  31. package/dist/esm/device.js +130 -0
  32. package/dist/esm/errors.js +59 -0
  33. package/dist/esm/iap.js +101 -0
  34. package/dist/esm/implicit.js +63 -0
  35. package/dist/esm/index.js +29 -0
  36. package/dist/esm/package.json +1 -0
  37. package/dist/esm/storage.js +78 -0
  38. package/dist/esm/types.js +4 -0
  39. package/dist/esm/ui/RevnixBlockPaywall.js +706 -0
  40. package/dist/esm/ui/RevnixPaywall.js +890 -0
  41. package/dist/esm/ui/index.js +6 -0
  42. package/dist/esm/version.js +4 -0
  43. package/dist/iap.d.ts +20 -0
  44. package/dist/iap.js +104 -0
  45. package/dist/implicit.d.ts +69 -0
  46. package/dist/implicit.js +67 -0
  47. package/dist/index.d.ts +18 -0
  48. package/dist/index.js +50 -0
  49. package/dist/storage.d.ts +14 -0
  50. package/dist/storage.js +85 -0
  51. package/dist/types.d.ts +463 -0
  52. package/dist/types.js +5 -0
  53. package/dist/ui/RevnixBlockPaywall.d.ts +96 -0
  54. package/dist/ui/RevnixBlockPaywall.js +742 -0
  55. package/dist/ui/RevnixPaywall.d.ts +148 -0
  56. package/dist/ui/RevnixPaywall.js +927 -0
  57. package/dist/ui/index.d.ts +7 -0
  58. package/dist/ui/index.js +25 -0
  59. package/dist/version.d.ts +1 -0
  60. package/dist/version.js +7 -0
  61. package/package.json +79 -0
  62. package/src/blocks/background.ts +232 -0
  63. package/src/blocks/color.ts +352 -0
  64. package/src/blocks/locale.ts +271 -0
  65. package/src/blocks/paywall-background-wire.json +12 -0
  66. package/src/blocks/paywall-selection-wire.json +149 -0
  67. package/src/blocks/selection.ts +161 -0
  68. package/src/blocks/style.ts +411 -0
  69. package/src/blocks/tags.ts +125 -0
  70. package/src/blocks/types.ts +352 -0
  71. package/src/client.ts +1993 -0
  72. package/src/device.ts +146 -0
  73. package/src/errors.ts +69 -0
  74. package/src/iap.ts +137 -0
  75. package/src/implicit.ts +129 -0
  76. package/src/index.ts +82 -0
  77. package/src/storage.ts +92 -0
  78. package/src/types.ts +528 -0
  79. package/src/ui/RevnixBlockPaywall.tsx +1423 -0
  80. package/src/ui/RevnixPaywall.tsx +1542 -0
  81. package/src/ui/index.ts +43 -0
  82. package/src/version.ts +4 -0
  83. package/ui.d.ts +1 -0
  84. package/ui.js +5 -0
@@ -0,0 +1,352 @@
1
+ // The paywall block model — a portable description of a designed paywall.
2
+ //
3
+ // A block paywall is a TREE of styled elements: the screen owns a background
4
+ // and a list of blocks; every block carries its own style. The dashboard's
5
+ // builder authors this tree and publishes it on the paywall config as
6
+ // `blocks`, where it takes precedence over the classic `template` layouts.
7
+ //
8
+ // This file mirrors revnix-app's src/lib/paywall-blocks/types.ts one-for-one.
9
+ // The two must stay in lockstep: the dashboard preview and this SDK renderer
10
+ // are two interpreters of the SAME document, and a field only one side knows
11
+ // is a design that ships looking different from the design that was approved.
12
+
13
+ /** Per-block visual style. Everything optional — a block renders sensibly
14
+ * with no style at all. Sizes are px numbers; colors are any CSS color, or
15
+ * a palette token (see `resolveColor`). */
16
+ import type { PaywallBackground } from "./background.js";
17
+
18
+ export type {
19
+ BackgroundFit,
20
+ BackgroundImage,
21
+ BackgroundLayers,
22
+ BackgroundOverlay,
23
+ PaywallBackground,
24
+ PaywallBackgroundSpec,
25
+ } from "./background.js";
26
+
27
+ export interface BlockStyle {
28
+ fill?: string;
29
+ /** Sizing for an image or repeating-gradient `fill` (CSS background-size).
30
+ * RN paints `fill` as a flat colour, so tiled washes do not survive the
31
+ * trip and this is ignored. */
32
+ fillSize?: string;
33
+ textColor?: string;
34
+ /** 0–100, like the dashboard's opacity inputs. */
35
+ opacity?: number;
36
+ borderColor?: string;
37
+ borderWidth?: number;
38
+ /** Per-side rules, as a CSS border shorthand ("1px solid @text/12"). */
39
+ borderTop?: string;
40
+ borderRight?: string;
41
+ borderBottom?: string;
42
+ borderLeft?: string;
43
+ radius?: number;
44
+ padding?: number;
45
+ paddingX?: number;
46
+ paddingY?: number;
47
+ /** Per-side padding wins over the shorthands above. */
48
+ paddingTop?: number;
49
+ paddingRight?: number;
50
+ paddingBottom?: number;
51
+ paddingLeft?: number;
52
+ /** px numbers, or "auto" — the designs centre and bottom-pin with it. */
53
+ margin?: number;
54
+ marginTop?: number | "auto";
55
+ marginRight?: number | "auto";
56
+ marginBottom?: number | "auto";
57
+ marginLeft?: number | "auto";
58
+ fontSize?: number;
59
+ fontWeight?: number;
60
+ /** A design font family name (e.g. "Newsreader"). Renders only when the
61
+ * host app has that font registered — see `fontFamilyMap`. */
62
+ fontFamily?: string;
63
+ fontStyle?: "normal" | "italic";
64
+ align?: "left" | "center" | "right";
65
+ /** In em, like CSS. Converted to points against the block's font size. */
66
+ letterSpacing?: number;
67
+ /** Unitless multiplier, like CSS. Converted to points. */
68
+ lineHeight?: number;
69
+ textTransform?: "none" | "uppercase";
70
+ decoration?: "none" | "underline" | "line-through";
71
+ /** Line-breaking preference. No RN equivalent — ignored. */
72
+ textWrap?: "balance" | "pretty";
73
+ /** Keep the copy on one line. */
74
+ nowrap?: boolean;
75
+ /** Gap between a container's children. */
76
+ gap?: number;
77
+ /** px number, or a percentage string ("78%") for proportional boxes. */
78
+ height?: number | string;
79
+ minHeight?: number;
80
+ /** px number, or a percentage string ("50%"). */
81
+ width?: number | string;
82
+ maxWidth?: number | string;
83
+ /** Width-to-height ratio; "16/9" strings are parsed. */
84
+ aspectRatio?: number | string;
85
+ /** flex-grow inside a row/column container. */
86
+ flex?: number;
87
+ /** flex-shrink; 0 stops a row item from being squashed. */
88
+ shrink?: number;
89
+ /** flex-basis in px — carousel cards and side rails are sized by basis,
90
+ * and collapse to nothing without it. */
91
+ basis?: number;
92
+ /** Let a row wrap onto more lines. */
93
+ wrap?: boolean;
94
+ /** Main-axis distribution for row/column containers. */
95
+ justify?: "start" | "center" | "end" | "between";
96
+ /** Cross-axis alignment for row/column containers. */
97
+ items?: "start" | "center" | "end" | "baseline" | "stretch";
98
+ /** Cross-axis alignment for THIS block, overriding the container's
99
+ * `items` — how a design opts one chip out of a stretched row. */
100
+ selfAlign?: "start" | "center" | "end" | "baseline" | "stretch";
101
+ /** Raw CSS box-shadow. Approximated by a soft RN shadow. */
102
+ shadow?: string;
103
+ /** backdrop-filter blur radius in px (glass cards). RN has no backdrop
104
+ * filter; the translucent `fill` carries the effect on its own. */
105
+ blur?: number;
106
+ /** Raw CSS filter. No RN equivalent — ignored. */
107
+ filter?: string;
108
+ /** Raw CSS clip-path (starbursts, ticket notches). No RN equivalent —
109
+ * ignored, so the shape renders as its uncut box. */
110
+ clipPath?: string;
111
+ rotate?: number;
112
+ /** CSS `translate` ("-50% 0"), which the designs pair with a 50% offset to
113
+ * centre a pinned badge. RN transforms take points, not percentages, so a
114
+ * percentage translate is ignored; a px one is applied. */
115
+ translate?: string;
116
+ /** Placement inside a `stack` container. `inset` fills the stack; the
117
+ * individual offsets pin an edge. Ignored outside a stack. */
118
+ inset?: boolean;
119
+ /** px numbers, or percentage strings ("50%") for proportional pinning. */
120
+ top?: number | string;
121
+ right?: number | string;
122
+ bottom?: number | string;
123
+ left?: number | string;
124
+ zIndex?: number;
125
+ overflow?: "hidden" | "visible";
126
+ }
127
+
128
+ /** What tapping a block does. Omitted means the block is decoration.
129
+ *
130
+ * A FIELD on the existing block types rather than a new block type, so an
131
+ * SDK older than this one drops it and still renders the element exactly as
132
+ * it does today — a design carrying a close chip degrades to inert rather
133
+ * than losing the chip, which is what a new block type would have cost. */
134
+ /** REV-262: draw a block only while its plan card is (or is not) the selected
135
+ * one. Ignored outside a package card — a root block is always drawn. */
136
+ export type BlockVisibility = "selected" | "unselected";
137
+
138
+ export type BlockAction = "close";
139
+
140
+ export interface TextBlock {
141
+ id: string;
142
+ type: "text";
143
+ text: string;
144
+ /** Tapping this block dismisses the paywall. See BlockAction. */
145
+ action?: BlockAction;
146
+ style?: BlockStyle;
147
+ /** REV-262: merged over `style`, field by field, while the block sits in a
148
+ * selected plan card (a pinned or repeated card whose package is the
149
+ * selected one, or any descendant of such a card). */
150
+ selectedStyle?: BlockStyle;
151
+ visibility?: BlockVisibility;
152
+ }
153
+
154
+ export interface ImageBlock {
155
+ id: string;
156
+ type: "image";
157
+ /** Empty falls back to the config's hero image, then to a blank slot. */
158
+ url?: string;
159
+ shape?: "rect" | "circle";
160
+ fit?: "cover" | "contain";
161
+ placeholder?: string;
162
+ /** Tapping this block dismisses the paywall. See BlockAction. */
163
+ action?: BlockAction;
164
+ style?: BlockStyle;
165
+ /** REV-262: merged over `style`, field by field, while the block sits in a
166
+ * selected plan card (a pinned or repeated card whose package is the
167
+ * selected one, or any descendant of such a card). */
168
+ selectedStyle?: BlockStyle;
169
+ visibility?: BlockVisibility;
170
+ }
171
+
172
+ export interface ListBlock {
173
+ id: string;
174
+ type: "list";
175
+ items: Array<{ icon?: string; title: string; description?: string }>;
176
+ /** Icon color; defaults to the screen accent. */
177
+ iconColor?: string;
178
+ style?: BlockStyle;
179
+ /** REV-262: merged over `style`, field by field, while the block sits in a
180
+ * selected plan card (a pinned or repeated card whose package is the
181
+ * selected one, or any descendant of such a card). */
182
+ selectedStyle?: BlockStyle;
183
+ visibility?: BlockVisibility;
184
+ }
185
+
186
+ /** Renders the attached offering's packages as selectable cards. */
187
+ export interface ProductsBlock {
188
+ id: string;
189
+ type: "products";
190
+ direction?: "column" | "row";
191
+ titleTpl?: string;
192
+ priceTpl?: string;
193
+ highlightSub?: string;
194
+ badgeText?: string;
195
+ cardStyle?: BlockStyle;
196
+ highlightStyle?: BlockStyle;
197
+ style?: BlockStyle;
198
+ /** REV-262: merged over `style`, field by field, while the block sits in a
199
+ * selected plan card (a pinned or repeated card whose package is the
200
+ * selected one, or any descendant of such a card). */
201
+ selectedStyle?: BlockStyle;
202
+ visibility?: BlockVisibility;
203
+ }
204
+
205
+ export interface ButtonBlock {
206
+ id: string;
207
+ type: "button";
208
+ label: string;
209
+ /** `close` turns this button into a dismiss ("Not now") instead of the
210
+ * purchase CTA, which is what a button means by default. */
211
+ action?: BlockAction;
212
+ style?: BlockStyle;
213
+ /** REV-262: merged over `style`, field by field, while the block sits in a
214
+ * selected plan card (a pinned or repeated card whose package is the
215
+ * selected one, or any descendant of such a card). */
216
+ selectedStyle?: BlockStyle;
217
+ visibility?: BlockVisibility;
218
+ }
219
+
220
+ export interface LinksBlock {
221
+ id: string;
222
+ type: "links";
223
+ showRestore?: boolean;
224
+ showTerms?: boolean;
225
+ showPrivacy?: boolean;
226
+ termsUrl?: string;
227
+ privacyUrl?: string;
228
+ style?: BlockStyle;
229
+ /** REV-262: merged over `style`, field by field, while the block sits in a
230
+ * selected plan card (a pinned or repeated card whose package is the
231
+ * selected one, or any descendant of such a card). */
232
+ selectedStyle?: BlockStyle;
233
+ visibility?: BlockVisibility;
234
+ }
235
+
236
+ export interface LineBlock {
237
+ id: string;
238
+ type: "line";
239
+ style?: BlockStyle;
240
+ /** REV-262: merged over `style`, field by field, while the block sits in a
241
+ * selected plan card (a pinned or repeated card whose package is the
242
+ * selected one, or any descendant of such a card). */
243
+ selectedStyle?: BlockStyle;
244
+ visibility?: BlockVisibility;
245
+ }
246
+
247
+ export interface SpacerBlock {
248
+ id: string;
249
+ type: "spacer";
250
+ /** Grows to push what follows to the bottom. */
251
+ flex?: boolean;
252
+ style?: BlockStyle;
253
+ /** REV-262: merged over `style`, field by field, while the block sits in a
254
+ * selected plan card (a pinned or repeated card whose package is the
255
+ * selected one, or any descendant of such a card). */
256
+ selectedStyle?: BlockStyle;
257
+ visibility?: BlockVisibility;
258
+ }
259
+
260
+ /** The one container block. `layout` picks how children are placed: column /
261
+ * row are flex lines, `stack` layers them (children position with
262
+ * style.inset or the edge offsets), and `grid` is an N-column grid. */
263
+ export interface CardBlock {
264
+ id: string;
265
+ type: "card";
266
+ layout?: "column" | "row" | "stack" | "grid";
267
+ /** Renders this container once per package in the attached offering. Its
268
+ * subtree reads the package through tag variables. */
269
+ repeat?: "packages";
270
+ /** "This card describes package N of the offering". A card whose index the
271
+ * offering does not reach is hidden. */
272
+ packageIndex?: number;
273
+ /** grid only; defaults to 2. */
274
+ columns?: number;
275
+ /** grid only — a CSS track list ("1fr 60px 66px"). */
276
+ gridColumns?: string;
277
+ children: PaywallBlock[];
278
+ style?: BlockStyle;
279
+ /** REV-262: merged over `style`, field by field, while the block sits in a
280
+ * selected plan card (a pinned or repeated card whose package is the
281
+ * selected one, or any descendant of such a card). */
282
+ selectedStyle?: BlockStyle;
283
+ visibility?: BlockVisibility;
284
+ }
285
+
286
+ export type PaywallBlock =
287
+ | TextBlock
288
+ | ImageBlock
289
+ | ListBlock
290
+ | ProductsBlock
291
+ | ButtonBlock
292
+ | LinksBlock
293
+ | LineBlock
294
+ | SpacerBlock
295
+ | CardBlock;
296
+
297
+ /** The published document: screen palette plus the block tree. */
298
+ export interface PaywallBlockDoc {
299
+ version: number;
300
+ /** "canvas" designs are authored against a fixed device screen and scale as
301
+ * a whole; "flow" designs lay out in a scrolling column. */
302
+ layout?: "canvas" | "flow";
303
+ /** Any CSS color or gradient string — or the layered form with a photo
304
+ * and scrim (see ./background.ts). */
305
+ background: PaywallBackground;
306
+ textColor: string;
307
+ accent: string;
308
+ accentInk: string;
309
+ fontFamily?: string;
310
+ blocks: PaywallBlock[];
311
+ /** REV-271: the language the blocks' own copy is written in. Absent = "en".
312
+ * Never a key in a stored doc's `locales` — the tree IS that language's
313
+ * version. A localized copy names the language it was localized to. */
314
+ defaultLocale?: string;
315
+ /** REV-271: translations, keyed by BCP-47 tag then by block string key
316
+ * (`<blockId>.text`, `<blockId>.items.0.title`, …). Only words differ per
317
+ * language; styles, layout and ids are shared. `RevnixBlockPaywall`
318
+ * applies the right one — see ./locale.ts. */
319
+ locales?: Record<string, Record<string, string>>;
320
+ }
321
+
322
+ /** The device screen `canvas` designs are authored against. */
323
+ export const DESIGN_CANVAS = { width: 393, height: 852 } as const;
324
+
325
+ /** Does this tree author a dismiss affordance that is CERTAIN to render?
326
+ *
327
+ * The renderer draws its own close button only when this is false, so a
328
+ * design written before close existed becomes dismissible without being
329
+ * edited, and a design that DOES author a close chip never shows two. The
330
+ * same predicate is implemented in every Revnix SDK — keep them identical.
331
+ *
332
+ * Conditional containers are deliberately not searched: a `repeat` card
333
+ * renders once per package (none, when the offering is empty) and a
334
+ * `packageIndex` card is hidden when the offering does not reach that index,
335
+ * so a close authored inside one MIGHT not appear. Counting it would
336
+ * suppress the fallback and leave the customer with no way out — the exact
337
+ * bug this feature exists to fix. Two close buttons is merely ugly, so the
338
+ * tie breaks toward always having one. */
339
+ export function hasCloseAction(blocks: PaywallBlock[]): boolean {
340
+ return blocks.some((b) =>
341
+ // A close the design only draws in one selection state (`visibility`)
342
+ // must not suppress the fallback chip — the other state would have none.
343
+ b.visibility !== undefined
344
+ ? false
345
+ : b.type === "card"
346
+ ? b.repeat === undefined &&
347
+ b.packageIndex === undefined &&
348
+ hasCloseAction(b.children)
349
+ : (b.type === "text" || b.type === "image" || b.type === "button") &&
350
+ b.action === "close"
351
+ );
352
+ }