@telefonica/mistica 16.56.0 → 16.56.1-beta.1

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 (295) hide show
  1. package/README.md +31 -0
  2. package/css/mistica.css +1 -1
  3. package/dist/accordion.css-mistica.js +16 -16
  4. package/dist/align.css-mistica.js +2 -2
  5. package/dist/autocomplete.css-mistica.js +6 -6
  6. package/dist/avatar.css-mistica.js +3 -3
  7. package/dist/badge.css-mistica.js +7 -7
  8. package/dist/box.css-mistica.js +15 -15
  9. package/dist/boxed.css-mistica.js +31 -31
  10. package/dist/button-group.css-mistica.js +10 -10
  11. package/dist/button-layout.css-mistica.js +21 -21
  12. package/dist/button.css-mistica.js +51 -51
  13. package/dist/callout.css-mistica.js +16 -16
  14. package/dist/card-internal.css-mistica.js +36 -36
  15. package/dist/carousel.css-mistica.js +18 -18
  16. package/dist/checkbox.css-mistica.js +21 -21
  17. package/dist/chip.css-mistica.js +30 -30
  18. package/dist/circle.css-mistica.js +2 -2
  19. package/dist/community/advanced-data-card.css-mistica.js +26 -26
  20. package/dist/community/blocks.css-mistica.js +3 -3
  21. package/dist/community/example-component.css-mistica.js +2 -2
  22. package/dist/counter.css-mistica.js +12 -12
  23. package/dist/cover-hero.css-mistica.js +16 -16
  24. package/dist/credit-card-number-field.css-mistica.js +6 -6
  25. package/dist/date-field.css-mistica.js +1 -1
  26. package/dist/date-time-picker.css-mistica.js +2 -2
  27. package/dist/dialog.css-mistica.js +15 -15
  28. package/dist/divider.css-mistica.js +5 -5
  29. package/dist/double-field.css-mistica.js +4 -4
  30. package/dist/drawer.css-mistica.js +15 -15
  31. package/dist/empty-state-card.css-mistica.js +4 -4
  32. package/dist/empty-state.css-mistica.js +14 -14
  33. package/dist/fade-in.css-mistica.js +1 -1
  34. package/dist/feedback.css-mistica.js +14 -14
  35. package/dist/file-upload.css-mistica.js +14 -14
  36. package/dist/fixed-footer-layout.css-mistica.js +12 -12
  37. package/dist/form.css-mistica.js +2 -2
  38. package/dist/grid-layout.css-mistica.js +9 -9
  39. package/dist/grid.css-mistica.js +147 -147
  40. package/dist/header.css-mistica.js +5 -5
  41. package/dist/hero.css-mistica.js +11 -11
  42. package/dist/horizontal-scroll.css-mistica.js +3 -3
  43. package/dist/icon-button.css-mistica.js +66 -66
  44. package/dist/icons/icon-chevron.css-mistica.js +6 -6
  45. package/dist/icons/icon-error.css-mistica.js +3 -3
  46. package/dist/image.css-mistica.js +11 -11
  47. package/dist/inline.css-mistica.js +16 -16
  48. package/dist/list.css-mistica.js +15 -15
  49. package/dist/loading-bar.css-mistica.js +5 -5
  50. package/dist/loading-screen.css-mistica.js +15 -15
  51. package/dist/logo-blau-shell.d.ts +10 -0
  52. package/dist/logo-blau-shell.js +25 -0
  53. package/dist/logo-blau.d.ts +1 -1
  54. package/dist/logo-blau.js +25 -40
  55. package/dist/logo-common.d.ts +0 -1
  56. package/dist/logo-esimflag-shell.d.ts +10 -0
  57. package/dist/logo-esimflag-shell.js +25 -0
  58. package/dist/logo-esimflag.d.ts +1 -1
  59. package/dist/logo-esimflag.js +11 -26
  60. package/dist/logo-movistar-new-shell.d.ts +10 -0
  61. package/dist/logo-movistar-new-shell.js +25 -0
  62. package/dist/logo-movistar-new.d.ts +1 -1
  63. package/dist/logo-movistar-new.js +84 -103
  64. package/dist/logo-movistar-shell.d.ts +10 -0
  65. package/dist/logo-movistar-shell.js +25 -0
  66. package/dist/logo-movistar.d.ts +1 -1
  67. package/dist/logo-movistar.js +16 -31
  68. package/dist/logo-o2-new-shell.d.ts +8 -0
  69. package/dist/logo-o2-new-shell.js +24 -0
  70. package/dist/logo-o2-new.d.ts +1 -1
  71. package/dist/logo-o2-new.js +6 -13
  72. package/dist/logo-o2-shell.d.ts +8 -0
  73. package/dist/logo-o2-shell.js +24 -0
  74. package/dist/logo-o2.d.ts +1 -1
  75. package/dist/logo-o2.js +6 -13
  76. package/dist/logo-telefonica-shell.d.ts +10 -0
  77. package/dist/logo-telefonica-shell.js +25 -0
  78. package/dist/logo-telefonica.d.ts +1 -1
  79. package/dist/logo-telefonica.js +11 -26
  80. package/dist/logo-tu-shell.d.ts +8 -0
  81. package/dist/logo-tu-shell.js +24 -0
  82. package/dist/logo-tu.d.ts +1 -1
  83. package/dist/logo-tu.js +10 -14
  84. package/dist/logo-vivo-shell.d.ts +10 -0
  85. package/dist/logo-vivo-shell.js +25 -0
  86. package/dist/logo-vivo.d.ts +1 -1
  87. package/dist/logo-vivo.js +11 -26
  88. package/dist/logo.css-mistica.js +9 -9
  89. package/dist/logo.js +223 -205
  90. package/dist/menu.css-mistica.js +24 -24
  91. package/dist/mosaic.css-mistica.js +3 -3
  92. package/dist/navigation-bar.css-mistica.js +45 -45
  93. package/dist/navigation-breadcrumbs.css-mistica.js +5 -5
  94. package/dist/package-version.js +2 -2
  95. package/dist/pin-field.css-mistica.js +10 -10
  96. package/dist/popover.css-mistica.js +2 -2
  97. package/dist/progress-bar.css-mistica.js +12 -12
  98. package/dist/radio-button.css-mistica.js +33 -33
  99. package/dist/rating.css-mistica.js +12 -12
  100. package/dist/responsive-layout.css-mistica.js +20 -20
  101. package/dist/screen-reader-only.css-mistica.js +2 -2
  102. package/dist/select.css-mistica.js +29 -29
  103. package/dist/sheet-action-row.css-mistica.js +2 -2
  104. package/dist/sheet-common.css-mistica.js +16 -16
  105. package/dist/sheet-info.css-mistica.js +4 -4
  106. package/dist/skeletons.css-mistica.js +12 -12
  107. package/dist/skins/skin-contract.css-mistica.js +686 -686
  108. package/dist/skip-link.css-mistica.js +3 -3
  109. package/dist/slider.css-mistica.js +28 -28
  110. package/dist/snackbar.css-mistica.js +16 -16
  111. package/dist/spinner.css-mistica.js +5 -5
  112. package/dist/square.css-mistica.js +2 -2
  113. package/dist/stack.css-mistica.js +9 -9
  114. package/dist/stacking-group.css-mistica.js +2 -2
  115. package/dist/stepper.css-mistica.js +16 -16
  116. package/dist/switch-component.css-mistica.js +53 -53
  117. package/dist/table.css-mistica.js +24 -24
  118. package/dist/tabs.css-mistica.js +30 -30
  119. package/dist/tag.css-mistica.js +5 -5
  120. package/dist/text-field-base.css-mistica.js +30 -30
  121. package/dist/text-field-base.js +52 -51
  122. package/dist/text-field-components.css-mistica.js +20 -17
  123. package/dist/text-field-components.css.d.ts +1 -0
  124. package/dist/text-field-components.d.ts +2 -1
  125. package/dist/text-field-components.js +25 -25
  126. package/dist/text-link.css-mistica.js +10 -10
  127. package/dist/text.css-mistica.js +13 -13
  128. package/dist/theme-context.css-mistica.js +2 -2
  129. package/dist/timeline.css-mistica.js +18 -18
  130. package/dist/timer.css-mistica.js +13 -13
  131. package/dist/tooltip.css-mistica.js +12 -12
  132. package/dist/touchable.css-mistica.js +5 -5
  133. package/dist/utils/aspect-ratio-support.css-mistica.js +7 -7
  134. package/dist/video.css-mistica.js +2 -2
  135. package/dist/vivinho-loading-animation/vivinho-loading-animation.css-mistica.js +3 -3
  136. package/dist-es/accordion.css-mistica.js +7 -7
  137. package/dist-es/align.css-mistica.js +2 -2
  138. package/dist-es/autocomplete.css-mistica.js +2 -2
  139. package/dist-es/avatar.css-mistica.js +2 -2
  140. package/dist-es/badge.css-mistica.js +2 -2
  141. package/dist-es/box.css-mistica.js +15 -15
  142. package/dist-es/boxed.css-mistica.js +25 -25
  143. package/dist-es/button-group.css-mistica.js +2 -2
  144. package/dist-es/button-layout.css-mistica.js +16 -16
  145. package/dist-es/button.css-mistica.js +38 -38
  146. package/dist-es/callout.css-mistica.js +12 -12
  147. package/dist-es/card-internal.css-mistica.js +20 -20
  148. package/dist-es/carousel.css-mistica.js +10 -10
  149. package/dist-es/checkbox.css-mistica.js +14 -14
  150. package/dist-es/chip.css-mistica.js +17 -17
  151. package/dist-es/circle.css-mistica.js +2 -2
  152. package/dist-es/community/advanced-data-card.css-mistica.js +7 -7
  153. package/dist-es/community/blocks.css-mistica.js +2 -2
  154. package/dist-es/community/example-component.css-mistica.js +2 -2
  155. package/dist-es/counter.css-mistica.js +2 -2
  156. package/dist-es/cover-hero.css-mistica.js +4 -4
  157. package/dist-es/credit-card-number-field.css-mistica.js +4 -4
  158. package/dist-es/date-field.css-mistica.js +1 -1
  159. package/dist-es/date-time-picker.css-mistica.js +2 -2
  160. package/dist-es/dialog.css-mistica.js +5 -5
  161. package/dist-es/divider.css-mistica.js +5 -5
  162. package/dist-es/double-field.css-mistica.js +4 -4
  163. package/dist-es/drawer.css-mistica.js +2 -2
  164. package/dist-es/empty-state-card.css-mistica.js +2 -2
  165. package/dist-es/empty-state.css-mistica.js +7 -7
  166. package/dist-es/fade-in.css-mistica.js +1 -1
  167. package/dist-es/feedback.css-mistica.js +2 -2
  168. package/dist-es/file-upload.css-mistica.js +8 -8
  169. package/dist-es/fixed-footer-layout.css-mistica.js +4 -4
  170. package/dist-es/form.css-mistica.js +2 -2
  171. package/dist-es/grid-layout.css-mistica.js +4 -4
  172. package/dist-es/grid.css-mistica.js +127 -127
  173. package/dist-es/header.css-mistica.js +2 -2
  174. package/dist-es/hero.css-mistica.js +4 -4
  175. package/dist-es/horizontal-scroll.css-mistica.js +2 -2
  176. package/dist-es/icon-button.css-mistica.js +56 -56
  177. package/dist-es/icons/icon-chevron.css-mistica.js +4 -4
  178. package/dist-es/icons/icon-error.css-mistica.js +2 -2
  179. package/dist-es/image.css-mistica.js +4 -4
  180. package/dist-es/inline.css-mistica.js +10 -10
  181. package/dist-es/list.css-mistica.js +2 -2
  182. package/dist-es/loading-bar.css-mistica.js +2 -2
  183. package/dist-es/loading-screen.css-mistica.js +5 -5
  184. package/dist-es/logo-blau-shell.js +16 -0
  185. package/dist-es/logo-blau.js +36 -51
  186. package/dist-es/logo-esimflag-shell.js +16 -0
  187. package/dist-es/logo-esimflag.js +13 -28
  188. package/dist-es/logo-movistar-new-shell.js +16 -0
  189. package/dist-es/logo-movistar-new.js +86 -105
  190. package/dist-es/logo-movistar-shell.js +16 -0
  191. package/dist-es/logo-movistar.js +18 -33
  192. package/dist-es/logo-o2-new-shell.js +15 -0
  193. package/dist-es/logo-o2-new.js +7 -14
  194. package/dist-es/logo-o2-shell.js +15 -0
  195. package/dist-es/logo-o2.js +7 -14
  196. package/dist-es/logo-telefonica-shell.js +16 -0
  197. package/dist-es/logo-telefonica.js +13 -28
  198. package/dist-es/logo-tu-shell.js +15 -0
  199. package/dist-es/logo-tu.js +12 -16
  200. package/dist-es/logo-vivo-shell.js +16 -0
  201. package/dist-es/logo-vivo.js +13 -28
  202. package/dist-es/logo.css-mistica.js +7 -7
  203. package/dist-es/logo.js +221 -203
  204. package/dist-es/menu.css-mistica.js +15 -15
  205. package/dist-es/mosaic.css-mistica.js +2 -2
  206. package/dist-es/navigation-bar.css-mistica.js +20 -20
  207. package/dist-es/navigation-breadcrumbs.css-mistica.js +2 -2
  208. package/dist-es/package-version.js +2 -2
  209. package/dist-es/pin-field.css-mistica.js +2 -2
  210. package/dist-es/popover.css-mistica.js +2 -2
  211. package/dist-es/progress-bar.css-mistica.js +8 -8
  212. package/dist-es/radio-button.css-mistica.js +25 -25
  213. package/dist-es/rating.css-mistica.js +4 -4
  214. package/dist-es/responsive-layout.css-mistica.js +7 -7
  215. package/dist-es/screen-reader-only.css-mistica.js +2 -2
  216. package/dist-es/select.css-mistica.js +20 -20
  217. package/dist-es/sheet-action-row.css-mistica.js +2 -2
  218. package/dist-es/sheet-common.css-mistica.js +2 -2
  219. package/dist-es/sheet-info.css-mistica.js +2 -2
  220. package/dist-es/skeletons.css-mistica.js +8 -8
  221. package/dist-es/skins/skin-contract.css-mistica.js +686 -686
  222. package/dist-es/skip-link.css-mistica.js +2 -2
  223. package/dist-es/slider.css-mistica.js +20 -20
  224. package/dist-es/snackbar.css-mistica.js +5 -5
  225. package/dist-es/spinner.css-mistica.js +2 -2
  226. package/dist-es/square.css-mistica.js +2 -2
  227. package/dist-es/stack.css-mistica.js +7 -7
  228. package/dist-es/stacking-group.css-mistica.js +2 -2
  229. package/dist-es/stepper.css-mistica.js +4 -4
  230. package/dist-es/style.css +1 -1
  231. package/dist-es/switch-component.css-mistica.js +41 -41
  232. package/dist-es/table.css-mistica.js +11 -11
  233. package/dist-es/tabs.css-mistica.js +21 -21
  234. package/dist-es/tag.css-mistica.js +2 -2
  235. package/dist-es/text-field-base.css-mistica.js +17 -17
  236. package/dist-es/text-field-base.js +52 -51
  237. package/dist-es/text-field-components.css-mistica.js +4 -4
  238. package/dist-es/text-field-components.js +52 -52
  239. package/dist-es/text-link.css-mistica.js +9 -9
  240. package/dist-es/text.css-mistica.js +8 -8
  241. package/dist-es/theme-context.css-mistica.js +2 -2
  242. package/dist-es/timeline.css-mistica.js +11 -11
  243. package/dist-es/timer.css-mistica.js +7 -7
  244. package/dist-es/tooltip.css-mistica.js +3 -3
  245. package/dist-es/touchable.css-mistica.js +2 -2
  246. package/dist-es/utils/aspect-ratio-support.css-mistica.js +4 -4
  247. package/dist-es/video.css-mistica.js +2 -2
  248. package/dist-es/vivinho-loading-animation/vivinho-loading-animation.css-mistica.js +2 -2
  249. package/doc/analytics.md +145 -0
  250. package/doc/components.md +730 -0
  251. package/doc/design-tokens.md +199 -0
  252. package/doc/fonts.md +169 -0
  253. package/doc/forms.md +177 -0
  254. package/doc/images/layout/box.svg +6 -0
  255. package/doc/images/layout/grid-layout-desktop-5-4.svg +8 -0
  256. package/doc/images/layout/grid-layout-desktop-6-6.svg +8 -0
  257. package/doc/images/layout/grid-layout-desktop-8-4.svg +8 -0
  258. package/doc/images/layout/grid-layout-desktop.svg +16 -0
  259. package/doc/images/layout/grid-layout-mobile-5-4.svg +9 -0
  260. package/doc/images/layout/grid-layout-mobile-6-6.svg +9 -0
  261. package/doc/images/layout/grid-layout-mobile-8-4.svg +9 -0
  262. package/doc/images/layout/grid-layout-mobile.svg +5 -0
  263. package/doc/images/layout/grid-layout-tablet-5-4.svg +8 -0
  264. package/doc/images/layout/grid-layout-tablet-6-6.svg +8 -0
  265. package/doc/images/layout/grid-layout-tablet-8-4.svg +8 -0
  266. package/doc/images/layout/grid-layout-tablet.svg +5 -0
  267. package/doc/images/layout/header-layout-desktop.svg +6 -0
  268. package/doc/images/layout/header-layout-mobile.svg +6 -0
  269. package/doc/images/layout/header-layout-tablet.svg +6 -0
  270. package/doc/images/layout/inline-around.svg +6 -0
  271. package/doc/images/layout/inline-between.svg +6 -0
  272. package/doc/images/layout/inline-evenly.svg +6 -0
  273. package/doc/images/layout/inline.svg +6 -0
  274. package/doc/images/layout/master-detail-layout-desktop.svg +8 -0
  275. package/doc/images/layout/master-detail-layout-mobile-detail.svg +6 -0
  276. package/doc/images/layout/master-detail-layout-mobile-master.svg +6 -0
  277. package/doc/images/layout/negative-box-ok-outline.svg +17 -0
  278. package/doc/images/layout/negative-box-ok-preview.svg +11 -0
  279. package/doc/images/layout/negative-box-wrong-outline.svg +14 -0
  280. package/doc/images/layout/negative-box-wrong-preview.svg +11 -0
  281. package/doc/images/layout/responsive-layout-desktop.svg +4 -0
  282. package/doc/images/layout/responsive-layout-mobile.svg +4 -0
  283. package/doc/images/layout/responsive-layout-tablet.svg +4 -0
  284. package/doc/images/layout/stack.svg +8 -0
  285. package/doc/images/layout/vertical-rhythm.png +0 -0
  286. package/doc/layout.md +527 -0
  287. package/doc/llms.md +258 -0
  288. package/doc/lottie.md +17 -0
  289. package/doc/migration-guide.md +76 -0
  290. package/doc/patterns.md +546 -0
  291. package/doc/sheet.md +122 -0
  292. package/doc/testing.md +43 -0
  293. package/doc/texts.md +42 -0
  294. package/doc/theme-config.md +124 -0
  295. package/package.json +2 -1
@@ -0,0 +1,546 @@
1
+ # Patterns and Best Practices
2
+
3
+ ## Critical rules
4
+
5
+ 1. **NEVER hardcode colors.** Always use `skinVars.colors.*` from `@telefonica/mistica`.
6
+ 2. **NEVER use raw `<div>` for layout.** Use `Box`, `Stack`, `Inline`, `ResponsiveLayout`, `GridLayout`,
7
+ `Grid`.
8
+ 3. **NEVER set font sizes manually.** Use text components (`Text1`-`Text10`, `Title1`-`Title4`).
9
+ 4. **NEVER set border radius manually.** Use `skinVars.borderRadii.*` or components that handle it (`Boxed`,
10
+ cards, etc.).
11
+ 5. **Always wrap your app** with `ThemeContextProvider` and import `@telefonica/mistica/css/mistica.css`.
12
+ 6. **Always namespace React hooks**: `React.useState`, `React.useEffect`, `React.useRef`, etc.
13
+ 7. **Add `'use client';`** directive to client components when using Next.js app router.
14
+
15
+ ## Page layout composition
16
+
17
+ A standard Mistica page follows this structure:
18
+
19
+ ```tsx
20
+ // Navigation
21
+ <MainNavigationBar ... />
22
+
23
+ // Header section
24
+ <HeaderLayout
25
+ header={<Header pretitle="Section" title="Page Title" description="Description" />}
26
+ />
27
+
28
+ // Content sections
29
+ <ResponsiveLayout>
30
+ <Box paddingY={24}>
31
+ <Stack space={32}>
32
+ {/* Section 1 */}
33
+ <Stack space={16}>
34
+ <Title1 as="h2">Section Title</Title1>
35
+ <Text2 regular as="p">Section description</Text2>
36
+ </Stack>
37
+
38
+ {/* Section 2 - List */}
39
+ <Stack space={16}>
40
+ <Title1 as="h2">Another Section</Title1>
41
+ <NegativeBox>
42
+ <RowList>
43
+ <Row title="Item 1" onPress={() => {}} />
44
+ <Row title="Item 2" onPress={() => {}} />
45
+ </RowList>
46
+ </NegativeBox>
47
+ </Stack>
48
+ </Stack>
49
+ </Box>
50
+ </ResponsiveLayout>
51
+ ```
52
+
53
+ ### Vertical rhythm
54
+
55
+ Follow the 24/32/16 rule:
56
+
57
+ - **Containers**: 24px top and bottom padding (`<Box paddingY={24}>`)
58
+ - **Sections**: 32px space between them (`<Stack space={32}>`)
59
+ - **Elements**: 16px space between them (`<Stack space={16}>`)
60
+
61
+ ## Layout dos and don'ts
62
+
63
+ ### DO: Use layout components
64
+
65
+ ```tsx
66
+ // Vertical spacing
67
+ <Stack space={16}>
68
+ <Text2 regular>First</Text2>
69
+ <Text2 regular>Second</Text2>
70
+ </Stack>
71
+
72
+ // Horizontal spacing
73
+ <Inline space={16}>
74
+ <ButtonPrimary onPress={() => {}}>Accept</ButtonPrimary>
75
+ <ButtonSecondary onPress={() => {}}>Cancel</ButtonSecondary>
76
+ </Inline>
77
+
78
+ // Padding
79
+ <Box padding={16}>
80
+ <Text2 regular>Padded content</Text2>
81
+ </Box>
82
+
83
+ // Page container
84
+ <ResponsiveLayout>
85
+ <Text2 regular>Responsive content</Text2>
86
+ </ResponsiveLayout>
87
+ ```
88
+
89
+ ### DON'T: Use divs for spacing/layout
90
+
91
+ ```tsx
92
+ // BAD - raw divs for spacing
93
+ <div style={{display: 'flex', flexDirection: 'column', gap: 16}}>
94
+ <div style={{padding: 16}}>
95
+ <span style={{fontSize: 14, color: '#333'}}>Text</span>
96
+ </div>
97
+ </div>
98
+
99
+ // GOOD - Mistica components
100
+ <Stack space={16}>
101
+ <Box padding={16}>
102
+ <Text2 regular>Text</Text2>
103
+ </Box>
104
+ </Stack>
105
+ ```
106
+
107
+ ## Color dos and don'ts
108
+
109
+ ### DO: Use design tokens
110
+
111
+ ```tsx
112
+ import {skinVars, applyAlpha} from '@telefonica/mistica';
113
+
114
+ // Direct token usage
115
+ <Text2 regular color={skinVars.colors.textSecondary}>Secondary text</Text2>
116
+
117
+ // In styles (when absolutely needed)
118
+ <div style={{backgroundColor: skinVars.colors.backgroundContainer}}>...</div>
119
+
120
+ // Semi-transparent colors
121
+ const overlay = applyAlpha(skinVars.rawColors.backgroundBrand, 0.8);
122
+ ```
123
+
124
+ ### DON'T: Hardcode colors
125
+
126
+ ```tsx
127
+ // BAD - hardcoded colors
128
+ <Text2 regular color="#666">Text</Text2>
129
+ <div style={{backgroundColor: '#f5f5f5'}}>...</div>
130
+ <div style={{color: 'rgb(0, 112, 224)'}}>...</div>
131
+
132
+ // GOOD - design tokens
133
+ <Text2 regular color={skinVars.colors.textSecondary}>Text</Text2>
134
+ <Boxed><Text2 regular>Content in container</Text2></Boxed>
135
+ ```
136
+
137
+ ## Responsive patterns
138
+
139
+ ### Conditional rendering by screen size
140
+
141
+ ```tsx
142
+ const {isDesktopOrBigger, isTabletOrSmaller} = useScreenSize();
143
+
144
+ return (
145
+ <ResponsiveLayout>
146
+ <Box paddingY={24}>
147
+ {isDesktopOrBigger ? (
148
+ <GridLayout template="6+6" left={<LeftContent />} right={<RightContent />} />
149
+ ) : (
150
+ <Stack space={16}>
151
+ <LeftContent />
152
+ <RightContent />
153
+ </Stack>
154
+ )}
155
+ </Box>
156
+ </ResponsiveLayout>
157
+ );
158
+ ```
159
+
160
+ ### Grid templates for desktop/mobile
161
+
162
+ ```tsx
163
+ <ResponsiveLayout>
164
+ <GridLayout template="8+4" left={<MainContent />} right={<Sidebar />} />
165
+ </ResponsiveLayout>
166
+ ```
167
+
168
+ On mobile, GridLayout stacks content vertically automatically.
169
+
170
+ ### Master-detail pattern
171
+
172
+ ```tsx
173
+ const [selectedId, setSelectedId] = React.useState(null);
174
+
175
+ <MasterDetailLayout
176
+ isOpen={!!selectedId}
177
+ master={
178
+ <RowList>
179
+ {items.map((item) => (
180
+ <Row key={item.id} title={item.name} onPress={() => setSelectedId(item.id)} />
181
+ ))}
182
+ </RowList>
183
+ }
184
+ detail={selectedId ? <DetailView id={selectedId} /> : <Text2 regular>Select an item</Text2>}
185
+ />;
186
+ ```
187
+
188
+ ## Form patterns
189
+
190
+ ### Automatic state management (preferred)
191
+
192
+ ```tsx
193
+ <Form initialValues={{email: '', name: ''}} onSubmit={(formData) => api.submit(formData)}>
194
+ <Stack space={16}>
195
+ <TextField name="name" label="Name" />
196
+ <EmailField name="email" label="Email" />
197
+ <PhoneNumberField name="phone" label="Phone" optional />
198
+ <DoubleField>
199
+ <DateField name="startDate" label="Start date" />
200
+ <DateField name="endDate" label="End date" />
201
+ </DoubleField>
202
+ <Select
203
+ name="country"
204
+ label="Country"
205
+ options={[
206
+ {value: 'es', text: 'Spain'},
207
+ {value: 'uk', text: 'United Kingdom'},
208
+ ]}
209
+ />
210
+ <Switch name="newsletter">Receive newsletter</Switch>
211
+ <ButtonLayout
212
+ primaryButton={
213
+ <ButtonPrimary submit loadingText="Sending...">
214
+ Submit
215
+ </ButtonPrimary>
216
+ }
217
+ />
218
+ </Stack>
219
+ </Form>
220
+ ```
221
+
222
+ ### Form with fixed footer
223
+
224
+ ```tsx
225
+ <ButtonFixedFooterLayout button={<ButtonPrimary submit>Continue</ButtonPrimary>}>
226
+ <ResponsiveLayout>
227
+ <Box paddingY={24}>
228
+ <Form onSubmit={handleSubmit}>
229
+ <Stack space={16}>
230
+ <TextField name="name" label="Name" />
231
+ <EmailField name="email" label="Email" />
232
+ </Stack>
233
+ </Form>
234
+ </Box>
235
+ </ResponsiveLayout>
236
+ </ButtonFixedFooterLayout>
237
+ ```
238
+
239
+ ## Carousel patterns
240
+
241
+ `Carousel`, `CenteredCarousel`, and `Slideshow` are **horizontal-scroll** components. Use them when content
242
+ needs to be navigated left-to-right (e.g. product cards, promotional banners, image galleries).
243
+
244
+ ### Carousel vs CenteredCarousel vs Slideshow
245
+
246
+ | Component | Best for | Visible items |
247
+ | ------------------ | -------------------------------------------------- | --------------------------- |
248
+ | `Carousel` | Card collections, product grids | Configurable per breakpoint |
249
+ | `CenteredCarousel` | Featured/highlighted items with neighbour peek | 1 on mobile, 3 on desktop |
250
+ | `Slideshow` | Full-width hero banners, autoplay image slideshows | 1 at a time |
251
+
252
+ ### Placement rules
253
+
254
+ - **`Carousel` and `CenteredCarousel`**: place inside `ResponsiveLayout` so they respect the page grid.
255
+ - **`Slideshow`**: place **outside** `ResponsiveLayout` — it bleeds full-width on mobile and tablet
256
+ automatically.
257
+
258
+ ```tsx
259
+ {
260
+ /* Carousel inside ResponsiveLayout */
261
+ }
262
+ <ResponsiveLayout>
263
+ <Box paddingY={24}>
264
+ <Stack space={16}>
265
+ <Title2 as="h2">Featured products</Title2>
266
+ <Carousel
267
+ itemsPerPage={{mobile: 1, tablet: 2, desktop: 3}}
268
+ withBullets
269
+ items={products.map((p, i) => (
270
+ <DataCard
271
+ key={i}
272
+ title={p.name}
273
+ description={p.description}
274
+ buttonPrimary={
275
+ <ButtonPrimary small onPress={() => navigate(p.url)}>
276
+ View
277
+ </ButtonPrimary>
278
+ }
279
+ />
280
+ ))}
281
+ />
282
+ </Stack>
283
+ </Box>
284
+ </ResponsiveLayout>;
285
+
286
+ {
287
+ /* Slideshow at page level (outside ResponsiveLayout) */
288
+ }
289
+ <Slideshow
290
+ withBullets
291
+ autoplay={{time: 5000, loop: true}}
292
+ items={[
293
+ <CoverCard key="1" imageSrc="/banner1.jpg" title="Offer 1" />,
294
+ <CoverCard key="2" imageSrc="/banner2.jpg" title="Offer 2" />,
295
+ ]}
296
+ />;
297
+ ```
298
+
299
+ ## Card patterns
300
+
301
+ ### Asset pattern for cards and rows
302
+
303
+ The idiomatic way to create card/row assets is `Circle` + icon:
304
+
305
+ ```tsx
306
+ <Circle backgroundColor={skinVars.colors.brandLow} size={40}>
307
+ <IconShopRegular color={skinVars.colors.brand} />
308
+ </Circle>
309
+ ```
310
+
311
+ ### Card grid
312
+
313
+ ```tsx
314
+ <ResponsiveLayout>
315
+ <Box paddingY={24}>
316
+ <Stack space={16}>
317
+ <Title1 as="h2">Featured</Title1>
318
+ <Carousel
319
+ itemsPerPage={{mobile: 1, tablet: 2, desktop: 3}}
320
+ items={products.map((p) => (
321
+ <DataCard
322
+ key={p.id}
323
+ asset={
324
+ <Circle backgroundColor={skinVars.colors.brandLow} size={40}>
325
+ <IconShopRegular color={skinVars.colors.brand} />
326
+ </Circle>
327
+ }
328
+ title={p.name}
329
+ description={p.description}
330
+ buttonPrimary={
331
+ <ButtonPrimary small onPress={() => navigate(p.url)}>
332
+ View
333
+ </ButtonPrimary>
334
+ }
335
+ />
336
+ ))}
337
+ />
338
+ </Stack>
339
+ </Box>
340
+ </ResponsiveLayout>
341
+ ```
342
+
343
+ ## List patterns
344
+
345
+ ### Unbounded list with NegativeBox
346
+
347
+ When placing a `RowList` inside a `ResponsiveLayout`, wrap it with `NegativeBox` so hover effects and
348
+ alignment are correct:
349
+
350
+ ```tsx
351
+ <ResponsiveLayout>
352
+ <Box paddingY={24}>
353
+ <Stack space={16}>
354
+ <Title1>Settings</Title1>
355
+ <NegativeBox>
356
+ <RowList>
357
+ <Row
358
+ asset={
359
+ <Circle backgroundColor={skinVars.colors.brandLow} size={40}>
360
+ <IconSettingsRegular color={skinVars.colors.brand} />
361
+ </Circle>
362
+ }
363
+ title="General"
364
+ description="App settings"
365
+ onPress={() => {}}
366
+ />
367
+ <Row
368
+ asset={
369
+ <Circle backgroundColor={skinVars.colors.brandLow} size={40}>
370
+ <IconBellRegular color={skinVars.colors.brand} />
371
+ </Circle>
372
+ }
373
+ title="Notifications"
374
+ description="Manage alerts"
375
+ onPress={() => {}}
376
+ />
377
+ </RowList>
378
+ </NegativeBox>
379
+ </Stack>
380
+ </Box>
381
+ </ResponsiveLayout>
382
+ ```
383
+
384
+ ### Boxed list (no NegativeBox needed)
385
+
386
+ ```tsx
387
+ <BoxedRowList>
388
+ <BoxedRow title="Option A" onPress={() => {}} />
389
+ <BoxedRow title="Option B" onPress={() => {}} />
390
+ </BoxedRowList>
391
+ ```
392
+
393
+ ## Variant sections
394
+
395
+ Use `variant` on `ResponsiveLayout` to create colored sections. Components inside adapt automatically:
396
+
397
+ ```tsx
398
+ {
399
+ /* Default section */
400
+ }
401
+ <ResponsiveLayout>
402
+ <Box paddingY={24}>
403
+ <Text2 regular>Default background</Text2>
404
+ </Box>
405
+ </ResponsiveLayout>;
406
+
407
+ {
408
+ /* Brand section */
409
+ }
410
+ <ResponsiveLayout variant="brand" fullWidth>
411
+ <ResponsiveLayout>
412
+ <Box paddingY={24}>
413
+ <Stack space={16}>
414
+ <Title1>Brand Section</Title1>
415
+ <Text2 regular>Colors adapt automatically</Text2>
416
+ <ButtonPrimary onPress={() => {}}>Action</ButtonPrimary>
417
+ </Stack>
418
+ </Box>
419
+ </ResponsiveLayout>
420
+ </ResponsiveLayout>;
421
+
422
+ {
423
+ /* Alternative section */
424
+ }
425
+ <ResponsiveLayout variant="alternative" fullWidth>
426
+ <ResponsiveLayout>
427
+ <Box paddingY={24}>
428
+ <Text2 regular>Alternative background</Text2>
429
+ </Box>
430
+ </ResponsiveLayout>
431
+ </ResponsiveLayout>;
432
+ ```
433
+
434
+ ## Boxed containers
435
+
436
+ Use `Boxed` for card-like containers without card semantics:
437
+
438
+ ```tsx
439
+ <Boxed>
440
+ <Box padding={16}>
441
+ <Stack space={16}>
442
+ <Title3>Container Title</Title3>
443
+ <Text2 regular>Container content</Text2>
444
+ </Stack>
445
+ </Box>
446
+ </Boxed>
447
+ ```
448
+
449
+ ## Skeleton loading patterns
450
+
451
+ Replace content with matching skeleton shapes while loading:
452
+
453
+ ```tsx
454
+ const {data, isLoading} = useFetch('/api/data');
455
+
456
+ if (isLoading) {
457
+ return (
458
+ <Stack space={16}>
459
+ <SkeletonLine width="40%" />
460
+ <SkeletonText />
461
+ <Inline space={16}>
462
+ <SkeletonCircle size={40} />
463
+ <SkeletonLine width="60%" />
464
+ </Inline>
465
+ </Stack>
466
+ );
467
+ }
468
+
469
+ return (
470
+ <Stack space={16}>
471
+ <Title1>{data.title}</Title1>
472
+ <Text2 regular>{data.description}</Text2>
473
+ <Inline space={16}>
474
+ <Avatar size={40} src={data.avatar} />
475
+ <Text2 regular>{data.author}</Text2>
476
+ </Inline>
477
+ </Stack>
478
+ );
479
+ ```
480
+
481
+ ## Funnel / step-by-step flow
482
+
483
+ ```tsx
484
+ <FunnelNavigationBar
485
+ right={
486
+ <NavigationBarActionGroup>
487
+ <NavigationBarAction aria-label="Close" onPress={handleClose}>
488
+ <IconCloseRegular color="currentColor" />
489
+ </NavigationBarAction>
490
+ </NavigationBarActionGroup>
491
+ }
492
+ />
493
+ <Stepper currentIndex={currentStep} steps={['Personal', 'Address', 'Payment', 'Confirm']} />
494
+ <ResponsiveLayout>
495
+ <Box paddingY={24}>
496
+ {currentStep === 0 && <PersonalInfoForm />}
497
+ {currentStep === 1 && <AddressForm />}
498
+ {currentStep === 2 && <PaymentForm />}
499
+ {currentStep === 3 && <ConfirmationScreen />}
500
+ </Box>
501
+ </ResponsiveLayout>
502
+ ```
503
+
504
+ ## Next.js integration
505
+
506
+ ### Link configuration
507
+
508
+ ```tsx
509
+ import Link from 'next/link';
510
+
511
+ const theme = {
512
+ skin: getMovistarSkin(),
513
+ i18n: {locale: 'es-ES', phoneNumberFormattingRegionCode: 'ES'},
514
+ Link: {type: 'Next14', Component: Link},
515
+ };
516
+ ```
517
+
518
+ ### React Router integration
519
+
520
+ ```tsx
521
+ import {Link} from 'react-router-dom';
522
+
523
+ const theme = {
524
+ skin: getMovistarSkin(),
525
+ i18n: {locale: 'es-ES', phoneNumberFormattingRegionCode: 'ES'},
526
+ Link: {type: 'ReactRouter6', Component: Link},
527
+ };
528
+ ```
529
+
530
+ After configuring, use the `to` prop on touchable components for client-side navigation:
531
+
532
+ ```tsx
533
+ <ButtonPrimary to="/dashboard">Go to dashboard</ButtonPrimary>
534
+ <Row title="Profile" to="/profile" />
535
+ <TextLink to="/settings">Settings</TextLink>
536
+ ```
537
+
538
+ ## Dark mode
539
+
540
+ Mistica supports dark mode out of the box via `colorScheme` in theme config:
541
+
542
+ - `'auto'` (default) -- follows OS/browser preference
543
+ - `'light'` -- force light mode
544
+ - `'dark'` -- force dark mode
545
+
546
+ All `skinVars.colors.*` tokens automatically resolve to their dark mode values. No additional code is needed.
package/doc/sheet.md ADDED
@@ -0,0 +1,122 @@
1
+ # Sheet
2
+
3
+ Mística provides a sheet component that can be used to display a modal-like content from over the main content
4
+ of the screen.
5
+
6
+ ## Predefined sheets
7
+
8
+ Some predefined sheets are available: `RadioListSheet`, `ActionsListSheet`, `InfoSheet` and `ActionsSheet`.
9
+ You can see examples in Storybook.
10
+
11
+ To use them, first you must configure the `SheetRoot` component in your app:
12
+
13
+ ```jsx
14
+ import {SheetRoot} from '@telefonica/mistica';
15
+
16
+ export const App = () => {
17
+ return (
18
+ <SheetRoot>
19
+ <MyApplication />
20
+ </SheetRoot>
21
+ );
22
+ };
23
+ ```
24
+
25
+ Then you can call `showSheet` from anywhere:
26
+
27
+ ```jsx
28
+ import {showSheet} from '@telefonica/mistica';
29
+
30
+ const MyComponent = () => {
31
+ return (
32
+ <ButtonPrimary
33
+ onPress={() =>
34
+ showSheet({
35
+ type: 'RADIO_LIST',
36
+ props: {
37
+ title: 'Select an fruit',
38
+ items: [
39
+ {id: '1', title: 'Apple'},
40
+ {id: '2', title: 'Banana'},
41
+ {id: '3', title: 'Orange'},
42
+ ],
43
+ },
44
+ }).then((result) => {
45
+ // The promise is resolved when the sheet is closed
46
+ console.log(result);
47
+ })
48
+ }
49
+ >
50
+ show sheet
51
+ </ButtonPrimary>
52
+ );
53
+ };
54
+ ```
55
+
56
+ ### Native implementation
57
+
58
+ If your app is served inside a webview and uses the `webview-bridge` library, the native implementation of the
59
+ predefined sheets will be used.
60
+
61
+ ```tsx
62
+ import {bottomSheet, isWebViewBridgeAvailable} from '@tef-novum/webview-bridge';
63
+
64
+ // ...
65
+
66
+ <SheetRoot nativeImplementation={isWebViewBridgeAvailable() ? bottomSheet : undefined}>
67
+ ```
68
+
69
+ When possible, always use the native implementation, as it provides a better user experience.
70
+
71
+ ## Custom sheets
72
+
73
+ You can show any content you want inside the sheet by passing it as a child of the component.
74
+
75
+ ```jsx
76
+ import {Sheet} from 'mistica';
77
+
78
+ const MyComponent = () => {
79
+ const [showSheet, setShowSheet] = useState(false);
80
+ return (
81
+ <>
82
+ <ButtonPrimary onPress={() => setShowSheet(true)}>show sheet</ButtonPrimary>
83
+ {showSheet && (
84
+ <Sheet onClose={() => setShowSheet(false)}>
85
+ <Placeholder />
86
+ </Sheet>
87
+ )}
88
+ </>
89
+ );
90
+ };
91
+ ```
92
+
93
+ The sheet will close when the user does the swipe down gesture, when the background overlay is touched, or by
94
+ using the visible dismiss button (close icon) that appears in the top-right corner aligned with the title. The
95
+ `onClose` callback is called when the closing animation finishes, that's the right place to unmount the sheet
96
+ as shown in the example above.
97
+
98
+ You can also close the sheet programmatically using the render prop:
99
+
100
+ ```jsx
101
+ import {Sheet} from 'mistica';
102
+
103
+ const MyComponent = () => {
104
+ const [showSheet, setShowSheet] = useState(false);
105
+ return (
106
+ <>
107
+ <ButtonPrimary onPress={() => setShowSheet(true)}>show sheet</ButtonPrimary>
108
+ {showSheet && (
109
+ <Sheet onClose={() => setShowSheet(false)}>
110
+ {({closeModal, modalTitleId}) => (
111
+ <>
112
+ <Title1 id={modalTitleId}>My sheet</Title1>
113
+ <Placeholder />
114
+ <ButtonPrimary onPress={closeModal}>Close</ButtonPrimary>
115
+ </>
116
+ )}
117
+ </Sheet>
118
+ )}
119
+ </>
120
+ );
121
+ };
122
+ ```
package/doc/testing.md ADDED
@@ -0,0 +1,43 @@
1
+ # Testing notes
2
+
3
+ ## Environment variables
4
+
5
+ Our code uses the NODE_ENV var to define code blocks that should be executed in specific environments, like
6
+ `'test'` or `'production'`.
7
+
8
+ For example:
9
+
10
+ ```js
11
+ if (process.env.NODE_ENV !== 'test') {
12
+ // this will only be executed if not inside a test
13
+ }
14
+ ```
15
+
16
+ Make sure your bundler (webpack, rollup, parcel, etc) makes the correct substitutions and the minifier
17
+ effectively removes unused code.
18
+
19
+ ## Unit tests
20
+
21
+ Unit tests usually don't require CSS because they test component functionality. Some Mistica components have
22
+ different layouts in mobile and desktop, and there are cases in which we use CSS styles to achieve this
23
+ result. If you are trying to test something that depends on these styles, you can either import `mistica.css`
24
+ classes in the HTML content you render in the test or write acceptance/screenshot tests instead.
25
+
26
+ ## Acceptance tests
27
+
28
+ To change some behaviors to facilitate acceptance tests (tests that run in a browser), a helper function is
29
+ used.
30
+
31
+ `isRunningAcceptanceTest` returns true if the user agent includes the `'acceptance-test'` string.
32
+
33
+ To make this work in your test environment, you should add that string to the browser's user agent. For
34
+ example in `Puppeteer`:
35
+
36
+ ```js
37
+ await page.setUserAgent(`${currentUserAgent} acceptance-test`);
38
+ ```
39
+
40
+ ## Questions?
41
+
42
+ Don't hesistate to ask at
43
+ [Mistica Teams Channel](https://teams.microsoft.com/l/channel/19%3ad2e3607a32ec411b8bf492f43cd0fe0c%40thread.tacv2/General?groupId=e265fe99-929f-45d1-8154-699649674a40&tenantId=9744600e-3e04-492e-baa1-25ec245c6f10)