@telefonica/mistica 16.61.0 → 16.62.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 (215) hide show
  1. package/css/mistica.css +1 -1
  2. package/dist/accordion.css-mistica.js +6 -6
  3. package/dist/align.css-mistica.js +1 -1
  4. package/dist/autocomplete.css-mistica.js +1 -1
  5. package/dist/avatar.css-mistica.js +1 -1
  6. package/dist/badge.css-mistica.js +1 -1
  7. package/dist/box.css-mistica.js +13 -13
  8. package/dist/boxed.css-mistica.js +24 -24
  9. package/dist/button-group.css-mistica.js +1 -1
  10. package/dist/button-layout.css-mistica.js +14 -14
  11. package/dist/button.css-mistica.js +30 -30
  12. package/dist/callout.css-mistica.js +11 -11
  13. package/dist/card-internal.css-mistica.js +15 -15
  14. package/dist/carousel.css-mistica.js +8 -8
  15. package/dist/checkbox.css-mistica.js +11 -11
  16. package/dist/chip.css-mistica.js +15 -15
  17. package/dist/circle.css-mistica.js +1 -1
  18. package/dist/community/advanced-data-card.css-mistica.js +6 -6
  19. package/dist/community/ai-card.css-mistica.js +48 -0
  20. package/dist/community/ai-card.css.d.ts +13 -0
  21. package/dist/community/ai-card.d.ts +19 -0
  22. package/dist/community/ai-card.js +312 -0
  23. package/dist/community/blocks.css-mistica.js +1 -1
  24. package/dist/community/example-component.css-mistica.js +1 -1
  25. package/dist/community/index.d.ts +1 -0
  26. package/dist/community/index.js +4 -0
  27. package/dist/counter.css-mistica.js +1 -1
  28. package/dist/cover-hero.css-mistica.js +2 -2
  29. package/dist/credit-card-number-field.css-mistica.js +3 -3
  30. package/dist/date-field.css-mistica.js +1 -1
  31. package/dist/date-time-picker.css-mistica.js +1 -1
  32. package/dist/dialog.css-mistica.js +4 -4
  33. package/dist/divider.css-mistica.js +5 -5
  34. package/dist/double-field.css-mistica.js +2 -2
  35. package/dist/drawer.css-mistica.js +1 -1
  36. package/dist/empty-state-card.css-mistica.js +1 -1
  37. package/dist/empty-state.css-mistica.js +5 -5
  38. package/dist/fade-in.css-mistica.js +1 -1
  39. package/dist/feedback.css-mistica.js +1 -1
  40. package/dist/file-upload.css-mistica.js +7 -7
  41. package/dist/fixed-footer-layout.css-mistica.js +2 -2
  42. package/dist/form.css-mistica.js +1 -1
  43. package/dist/generated/mistica-icons/icon-artificial-intelligence-filled.js +7 -7
  44. package/dist/generated/mistica-icons/icon-artificial-intelligence-light.js +9 -9
  45. package/dist/generated/mistica-icons/icon-artificial-intelligence-regular.js +12 -12
  46. package/dist/grid-layout.css-mistica.js +3 -3
  47. package/dist/grid.css-mistica.js +120 -120
  48. package/dist/header.css-mistica.js +1 -1
  49. package/dist/hero.css-mistica.js +2 -2
  50. package/dist/horizontal-scroll.css-mistica.js +1 -1
  51. package/dist/icon-button.css-mistica.js +53 -53
  52. package/dist/icons/icon-chevron.css-mistica.js +2 -2
  53. package/dist/icons/icon-error.css-mistica.js +1 -1
  54. package/dist/image.css-mistica.js +2 -2
  55. package/dist/index.d.ts +1 -0
  56. package/dist/index.js +4 -0
  57. package/dist/inline.css-mistica.js +9 -9
  58. package/dist/list.css-mistica.js +1 -1
  59. package/dist/loading-bar.css-mistica.js +1 -1
  60. package/dist/loading-screen.css-mistica.js +4 -4
  61. package/dist/logo.css-mistica.js +5 -5
  62. package/dist/menu.css-mistica.js +19 -16
  63. package/dist/menu.css.d.ts +1 -0
  64. package/dist/menu.d.ts +2 -1
  65. package/dist/menu.js +139 -132
  66. package/dist/mosaic.css-mistica.js +1 -1
  67. package/dist/navigation-bar.css-mistica.js +18 -18
  68. package/dist/navigation-breadcrumbs.css-mistica.js +1 -1
  69. package/dist/package-version.js +1 -1
  70. package/dist/pin-field.css-mistica.js +1 -1
  71. package/dist/popover.css-mistica.js +1 -1
  72. package/dist/progress-bar.css-mistica.js +6 -6
  73. package/dist/radio-button.css-mistica.js +19 -19
  74. package/dist/rating.css-mistica.js +2 -2
  75. package/dist/responsive-layout.css-mistica.js +6 -6
  76. package/dist/screen-reader-only.css-mistica.js +1 -1
  77. package/dist/select.css-mistica.js +15 -15
  78. package/dist/sheet-action-row.css-mistica.js +1 -1
  79. package/dist/sheet-common.css-mistica.js +1 -1
  80. package/dist/sheet-info.css-mistica.js +1 -1
  81. package/dist/skeletons.css-mistica.js +6 -6
  82. package/dist/skins/skin-contract.css-mistica.js +684 -684
  83. package/dist/skip-link.css-mistica.js +1 -1
  84. package/dist/slider.css-mistica.js +18 -18
  85. package/dist/snackbar.css-mistica.js +4 -4
  86. package/dist/spinner.css-mistica.js +1 -1
  87. package/dist/square.css-mistica.js +1 -1
  88. package/dist/stack.css-mistica.js +5 -5
  89. package/dist/stacking-group.css-mistica.js +1 -1
  90. package/dist/stepper.css-mistica.js +2 -2
  91. package/dist/switch-component.css-mistica.js +35 -35
  92. package/dist/table.css-mistica.js +9 -9
  93. package/dist/tabs.css-mistica.js +17 -17
  94. package/dist/tag.css-mistica.js +1 -1
  95. package/dist/text-field-base.css-mistica.js +15 -15
  96. package/dist/text-field-components.css-mistica.js +3 -3
  97. package/dist/text-link.css-mistica.js +6 -6
  98. package/dist/text.css-mistica.js +6 -6
  99. package/dist/theme-context.css-mistica.js +1 -1
  100. package/dist/timeline.css-mistica.js +9 -9
  101. package/dist/timer.css-mistica.js +6 -6
  102. package/dist/tooltip.css-mistica.js +1 -1
  103. package/dist/touchable.css-mistica.js +1 -1
  104. package/dist/utils/aspect-ratio-support.css-mistica.js +2 -2
  105. package/dist/video.css-mistica.js +1 -1
  106. package/dist/vivinho-loading-animation/vivinho-loading-animation.css-mistica.js +1 -1
  107. package/dist-es/accordion.css-mistica.js +6 -6
  108. package/dist-es/align.css-mistica.js +1 -1
  109. package/dist-es/autocomplete.css-mistica.js +1 -1
  110. package/dist-es/avatar.css-mistica.js +1 -1
  111. package/dist-es/badge.css-mistica.js +1 -1
  112. package/dist-es/box.css-mistica.js +13 -13
  113. package/dist-es/boxed.css-mistica.js +23 -23
  114. package/dist-es/button-group.css-mistica.js +1 -1
  115. package/dist-es/button-layout.css-mistica.js +14 -14
  116. package/dist-es/button.css-mistica.js +30 -30
  117. package/dist-es/callout.css-mistica.js +11 -11
  118. package/dist-es/card-internal.css-mistica.js +15 -15
  119. package/dist-es/carousel.css-mistica.js +8 -8
  120. package/dist-es/checkbox.css-mistica.js +11 -11
  121. package/dist-es/chip.css-mistica.js +15 -15
  122. package/dist-es/circle.css-mistica.js +1 -1
  123. package/dist-es/community/advanced-data-card.css-mistica.js +6 -6
  124. package/dist-es/community/ai-card.css-mistica.js +4 -0
  125. package/dist-es/community/ai-card.js +257 -0
  126. package/dist-es/community/blocks.css-mistica.js +1 -1
  127. package/dist-es/community/example-component.css-mistica.js +1 -1
  128. package/dist-es/community/index.js +5 -4
  129. package/dist-es/counter.css-mistica.js +1 -1
  130. package/dist-es/cover-hero.css-mistica.js +2 -2
  131. package/dist-es/credit-card-number-field.css-mistica.js +3 -3
  132. package/dist-es/date-field.css-mistica.js +1 -1
  133. package/dist-es/date-time-picker.css-mistica.js +1 -1
  134. package/dist-es/dialog.css-mistica.js +4 -4
  135. package/dist-es/divider.css-mistica.js +5 -5
  136. package/dist-es/double-field.css-mistica.js +2 -2
  137. package/dist-es/drawer.css-mistica.js +1 -1
  138. package/dist-es/empty-state-card.css-mistica.js +1 -1
  139. package/dist-es/empty-state.css-mistica.js +5 -5
  140. package/dist-es/fade-in.css-mistica.js +1 -1
  141. package/dist-es/feedback.css-mistica.js +1 -1
  142. package/dist-es/file-upload.css-mistica.js +7 -7
  143. package/dist-es/fixed-footer-layout.css-mistica.js +2 -2
  144. package/dist-es/form.css-mistica.js +1 -1
  145. package/dist-es/generated/mistica-icons/icon-artificial-intelligence-filled.js +12 -12
  146. package/dist-es/generated/mistica-icons/icon-artificial-intelligence-light.js +15 -15
  147. package/dist-es/generated/mistica-icons/icon-artificial-intelligence-regular.js +17 -17
  148. package/dist-es/grid-layout.css-mistica.js +3 -3
  149. package/dist-es/grid.css-mistica.js +120 -120
  150. package/dist-es/header.css-mistica.js +1 -1
  151. package/dist-es/hero.css-mistica.js +2 -2
  152. package/dist-es/horizontal-scroll.css-mistica.js +1 -1
  153. package/dist-es/icon-button.css-mistica.js +53 -53
  154. package/dist-es/icons/icon-chevron.css-mistica.js +2 -2
  155. package/dist-es/icons/icon-error.css-mistica.js +1 -1
  156. package/dist-es/image.css-mistica.js +2 -2
  157. package/dist-es/index.js +2183 -2182
  158. package/dist-es/inline.css-mistica.js +9 -9
  159. package/dist-es/list.css-mistica.js +1 -1
  160. package/dist-es/loading-bar.css-mistica.js +1 -1
  161. package/dist-es/loading-screen.css-mistica.js +4 -4
  162. package/dist-es/logo.css-mistica.js +5 -5
  163. package/dist-es/menu.css-mistica.js +14 -14
  164. package/dist-es/menu.js +186 -179
  165. package/dist-es/mosaic.css-mistica.js +1 -1
  166. package/dist-es/navigation-bar.css-mistica.js +18 -18
  167. package/dist-es/navigation-breadcrumbs.css-mistica.js +1 -1
  168. package/dist-es/package-version.js +1 -1
  169. package/dist-es/pin-field.css-mistica.js +1 -1
  170. package/dist-es/popover.css-mistica.js +1 -1
  171. package/dist-es/progress-bar.css-mistica.js +6 -6
  172. package/dist-es/radio-button.css-mistica.js +19 -19
  173. package/dist-es/rating.css-mistica.js +2 -2
  174. package/dist-es/responsive-layout.css-mistica.js +6 -6
  175. package/dist-es/screen-reader-only.css-mistica.js +1 -1
  176. package/dist-es/select.css-mistica.js +15 -15
  177. package/dist-es/sheet-action-row.css-mistica.js +1 -1
  178. package/dist-es/sheet-common.css-mistica.js +1 -1
  179. package/dist-es/sheet-info.css-mistica.js +1 -1
  180. package/dist-es/skeletons.css-mistica.js +6 -6
  181. package/dist-es/skins/skin-contract.css-mistica.js +684 -684
  182. package/dist-es/skip-link.css-mistica.js +1 -1
  183. package/dist-es/slider.css-mistica.js +18 -18
  184. package/dist-es/snackbar.css-mistica.js +4 -4
  185. package/dist-es/spinner.css-mistica.js +1 -1
  186. package/dist-es/square.css-mistica.js +1 -1
  187. package/dist-es/stack.css-mistica.js +5 -5
  188. package/dist-es/stacking-group.css-mistica.js +1 -1
  189. package/dist-es/stepper.css-mistica.js +2 -2
  190. package/dist-es/style.css +1 -1
  191. package/dist-es/switch-component.css-mistica.js +35 -35
  192. package/dist-es/table.css-mistica.js +9 -9
  193. package/dist-es/tabs.css-mistica.js +17 -17
  194. package/dist-es/tag.css-mistica.js +1 -1
  195. package/dist-es/text-field-base.css-mistica.js +15 -15
  196. package/dist-es/text-field-components.css-mistica.js +3 -3
  197. package/dist-es/text-link.css-mistica.js +6 -6
  198. package/dist-es/text.css-mistica.js +6 -6
  199. package/dist-es/theme-context.css-mistica.js +1 -1
  200. package/dist-es/timeline.css-mistica.js +9 -9
  201. package/dist-es/timer.css-mistica.js +6 -6
  202. package/dist-es/tooltip.css-mistica.js +1 -1
  203. package/dist-es/touchable.css-mistica.js +1 -1
  204. package/dist-es/utils/aspect-ratio-support.css-mistica.js +2 -2
  205. package/dist-es/video.css-mistica.js +1 -1
  206. package/dist-es/vivinho-loading-animation/vivinho-loading-animation.css-mistica.js +1 -1
  207. package/package.json +1 -1
  208. package/src/community/__stories__/ai-card-story.tsx +101 -0
  209. package/src/community/ai-card.css.ts +135 -0
  210. package/src/community/ai-card.tsx +231 -0
  211. package/src/community/index.tsx +1 -0
  212. package/src/index.tsx +1 -0
  213. package/src/menu.css.ts +6 -0
  214. package/src/menu.tsx +19 -8
  215. package/src/package-version.tsx +1 -1
@@ -0,0 +1,231 @@
1
+ 'use client';
2
+ import * as React from 'react';
3
+ import classnames from 'classnames';
4
+ import {BaseTouchable} from '../touchable';
5
+ import {Text3} from '../text';
6
+ import {vars} from '../skins/skin-contract.css';
7
+ import {useIsInViewport} from '../hooks';
8
+ import {isClientSide} from '../utils/environment';
9
+ import {applyCssVars} from '../utils/css';
10
+ import * as styles from './ai-card.css';
11
+
12
+ import type {TouchableComponentProps} from '../touchable';
13
+
14
+ type CommonProps = {
15
+ /** Static text shown before the animated words. */
16
+ text: string;
17
+ /** Words to animate in sequence. typed, held, then erased one by one. Maximum of 4 words. */
18
+ words?: ReadonlyArray<string>;
19
+ /** Number of characters to keep at the start of each word during deletion. Omit to erase fully. */
20
+ deleteChars?: number;
21
+ /** Wraps the text line after this many characters. */
22
+ lineBreakAtChars?: number;
23
+ /** Border color. Accepts any CSS color or gradient string. Defaults to the skin border token. */
24
+ borderColor?: string;
25
+ /** Icon or element rendered on the left side of the card. */
26
+ asset?: React.ReactElement;
27
+ };
28
+
29
+ export type AiCardProps = TouchableComponentProps<CommonProps>;
30
+
31
+ type AnimationStage = 'typing' | 'holding' | 'deleting' | 'done';
32
+
33
+ const TYPING_SPEEDS = [50, 60, 70, 80];
34
+ const DELETE_SPEED = 30;
35
+ const HOLD_DURATION = 2000;
36
+ const MAX_WORDS = 4;
37
+
38
+ const getRandomTypingSpeed = (previousSpeed?: number) => {
39
+ const candidates = TYPING_SPEEDS.filter((speed) => speed !== previousSpeed);
40
+ return candidates[Math.floor(Math.random() * candidates.length)];
41
+ };
42
+
43
+ const getDeleteFloor = (currentWord: string, nextWord: string, deleteChars?: number) => {
44
+ const sharedStartFloor = currentWord[0]?.toLowerCase() === nextWord[0]?.toLowerCase() ? 1 : 0;
45
+ const configuredDeleteFloor = typeof deleteChars === 'number' ? Math.max(0, Math.floor(deleteChars)) : 0;
46
+ return Math.max(sharedStartFloor, configuredDeleteFloor);
47
+ };
48
+
49
+ const getPrefersReducedMotion = () =>
50
+ isClientSide() && !!window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
51
+
52
+ type AnimationState = {index: number; text: string; stage: AnimationStage};
53
+
54
+ const INITIAL_STATE: AnimationState = {index: 0, text: '', stage: 'typing'};
55
+
56
+ const tick = (state: AnimationState, words: ReadonlyArray<string>, deleteChars?: number): AnimationState => {
57
+ const {index, text, stage} = state;
58
+ const currentWord = words[index] || '';
59
+ const nextWord = words[index + 1] || '';
60
+ const deleteFloor = getDeleteFloor(currentWord, nextWord, deleteChars);
61
+
62
+ if (stage === 'typing') {
63
+ if (text.length < currentWord.length) return {...state, text: currentWord.slice(0, text.length + 1)};
64
+ return {...state, stage: 'holding'};
65
+ }
66
+ if (stage === 'holding') {
67
+ if (index === words.length - 1) return {...state, stage: 'done'};
68
+ return text.length > deleteFloor
69
+ ? {...state, stage: 'deleting'}
70
+ : {index: index + 1, text, stage: 'typing'};
71
+ }
72
+ if (stage === 'deleting') {
73
+ if (text.length <= deleteFloor) {
74
+ let commonLen = 0;
75
+ while (
76
+ commonLen < text.length &&
77
+ commonLen < nextWord.length &&
78
+ text[commonLen] === nextWord[commonLen]
79
+ ) {
80
+ commonLen++;
81
+ }
82
+ return {index: index + 1, text: text.slice(0, commonLen), stage: 'typing'};
83
+ }
84
+ return {...state, text: text.slice(0, -1)};
85
+ }
86
+ return state;
87
+ };
88
+
89
+ const useAiCardAnimation = ({
90
+ words,
91
+ deleteChars,
92
+ prefersReducedMotion,
93
+ isInViewport,
94
+ }: {
95
+ words: ReadonlyArray<string>;
96
+ deleteChars?: number;
97
+ prefersReducedMotion: boolean;
98
+ isInViewport: boolean;
99
+ }) => {
100
+ const wordsKey = words.join('\0');
101
+ const wordCount = words.length;
102
+ const [state, setState] = React.useState<AnimationState>(INITIAL_STATE);
103
+ const prevSpeedRef = React.useRef<number | undefined>(undefined);
104
+ const wordsRef = React.useRef(words);
105
+ wordsRef.current = words;
106
+
107
+ React.useEffect(() => {
108
+ setState(
109
+ prefersReducedMotion && wordCount
110
+ ? {index: wordCount - 1, text: wordsRef.current.at(-1) || '', stage: 'done'}
111
+ : INITIAL_STATE
112
+ );
113
+ }, [wordsKey, prefersReducedMotion, wordCount]);
114
+
115
+ React.useEffect(() => {
116
+ if (state.stage === 'done' || !isInViewport || prefersReducedMotion || !wordCount) return;
117
+ let speed: number;
118
+ if (state.stage === 'typing') {
119
+ speed = getRandomTypingSpeed(prevSpeedRef.current);
120
+ prevSpeedRef.current = speed;
121
+ } else if (state.stage === 'holding') {
122
+ speed = HOLD_DURATION;
123
+ } else {
124
+ speed = DELETE_SPEED;
125
+ }
126
+ const id = window.setTimeout(() => setState((s) => tick(s, wordsRef.current, deleteChars)), speed);
127
+ return () => window.clearTimeout(id);
128
+ }, [state, isInViewport, prefersReducedMotion, wordCount, deleteChars]);
129
+
130
+ return {
131
+ dynamicText: state.text,
132
+ isDone: state.stage === 'done',
133
+ shouldBlinkCaret: !prefersReducedMotion && !!wordCount && state.stage === 'holding' && isInViewport,
134
+ };
135
+ };
136
+
137
+ const AiCard = ({
138
+ text,
139
+ words = [],
140
+ deleteChars,
141
+ lineBreakAtChars,
142
+ borderColor,
143
+ asset,
144
+ dataAttributes,
145
+ 'aria-label': ariaLabel,
146
+ ...touchableProps
147
+ }: AiCardProps): JSX.Element => {
148
+ const textLineRef = React.useRef<HTMLDivElement>(null);
149
+ const prefersReducedMotion = getPrefersReducedMotion();
150
+ const isInViewport = useIsInViewport(textLineRef, false);
151
+ const isInteractive = 'onPress' in touchableProps || 'href' in touchableProps || 'to' in touchableProps;
152
+
153
+ const safeWords = React.useMemo(
154
+ () =>
155
+ words
156
+ .map((word) => word.trim())
157
+ .filter((word) => word.length > 0)
158
+ .slice(0, MAX_WORDS),
159
+ [words]
160
+ );
161
+
162
+ const longestWord = React.useMemo(
163
+ () => safeWords.reduce((acc, word) => (word.length > acc.length ? word : acc), safeWords[0] || ''),
164
+ [safeWords]
165
+ );
166
+
167
+ const {dynamicText, isDone, shouldBlinkCaret} = useAiCardAnimation({
168
+ words: safeWords,
169
+ deleteChars,
170
+ prefersReducedMotion,
171
+ isInViewport,
172
+ });
173
+
174
+ const lastWord = safeWords.at(-1) ?? '';
175
+ const autoAriaLabel = [text, lastWord].filter(Boolean).join('') || undefined;
176
+
177
+ const textLineStyle: React.CSSProperties =
178
+ typeof lineBreakAtChars === 'number'
179
+ ? {maxWidth: `min(100%, ${Math.max(1, Math.floor(lineBreakAtChars))}ch)`}
180
+ : {};
181
+
182
+ return (
183
+ <BaseTouchable
184
+ className={classnames(styles.container, {[styles.containerInteractive]: isInteractive})}
185
+ style={
186
+ borderColor
187
+ ? applyCssVars({
188
+ [styles.vars.borderColorVar]: /gradient/.test(borderColor)
189
+ ? borderColor
190
+ : `linear-gradient(${borderColor}, ${borderColor})`,
191
+ })
192
+ : undefined
193
+ }
194
+ dataAttributes={{'component-name': 'AiCard', testid: 'AiCard', ...dataAttributes}}
195
+ {...(touchableProps as any)}
196
+ aria-label={ariaLabel ?? autoAriaLabel}
197
+ >
198
+ {asset && (
199
+ <span className={styles.slot} aria-hidden="true">
200
+ {asset}
201
+ </span>
202
+ )}
203
+ <div ref={textLineRef} className={styles.textLine} aria-hidden="true" style={textLineStyle}>
204
+ <Text3 regular color={vars.colors.textPrimary} as="span">
205
+ <span className={styles.textWrapper}>
206
+ <span className={styles.ghost}>
207
+ {text}
208
+ {longestWord}
209
+ </span>
210
+ <span className={styles.visibleContent}>
211
+ {text}
212
+ {dynamicText}
213
+ {!prefersReducedMotion && !!safeWords.length && (
214
+ <span
215
+ className={classnames(styles.caret, {
216
+ [styles.caretBlinking]: shouldBlinkCaret,
217
+ [styles.caretHidden]: isDone,
218
+ })}
219
+ >
220
+ |
221
+ </span>
222
+ )}
223
+ </span>
224
+ </span>
225
+ </Text3>
226
+ </div>
227
+ </BaseTouchable>
228
+ );
229
+ };
230
+
231
+ export default AiCard;
@@ -1,3 +1,4 @@
1
+ export {default as AiCard} from './ai-card';
1
2
  export {default as ExampleComponent} from './example-component';
2
3
  export {default as AdvancedDataCard} from './advanced-data-card';
3
4
  export {
package/src/index.tsx CHANGED
@@ -274,6 +274,7 @@ export type {TextToken, Dictionary} from './text-tokens';
274
274
  * the community.js export has issues because it exports an ES module and next12 interterprets it as a CommonJS module
275
275
  * importing from /dist/ is not an option because those modules don't get the context from the theme provider
276
276
  */
277
+ export {default as CommunityAiCard} from './community/ai-card';
277
278
  export {default as CommunityExampleComponent} from './community/example-component';
278
279
  export {default as CommunityAdvancedDataCard} from './community/advanced-data-card';
279
280
  export {
package/src/menu.css.ts CHANGED
@@ -126,6 +126,12 @@ export const itemContent = style({
126
126
  alignItems: 'center',
127
127
  });
128
128
 
129
+ export const itemTextContent = style({
130
+ display: 'flex',
131
+ flexDirection: 'column',
132
+ gap: 2,
133
+ });
134
+
129
135
  export const iconContainer = style({
130
136
  display: 'flex',
131
137
  paddingRight: 8,
package/src/menu.tsx CHANGED
@@ -10,7 +10,7 @@ import {Portal} from './portal';
10
10
  import Box from './box';
11
11
  import Inline from './inline';
12
12
  import Touchable from './touchable';
13
- import {Text3} from './text';
13
+ import {Text2, Text3} from './text';
14
14
  import {vars} from './skins/skin-contract.css';
15
15
  import Divider from './divider';
16
16
  import Checkbox from './checkbox';
@@ -53,6 +53,7 @@ const getItemIndexInMenu = (menu: HTMLElement | null, item: HTMLElement | null):
53
53
 
54
54
  interface MenuItemBaseProps {
55
55
  label: string;
56
+ description?: string;
56
57
  Icon?: (props: IconProps) => JSX.Element;
57
58
  destructive?: boolean;
58
59
  disabled?: boolean;
@@ -80,6 +81,7 @@ export const MenuItem = ({
80
81
  onPress,
81
82
  controlType,
82
83
  checked,
84
+ description,
83
85
  dataAttributes,
84
86
  }: MenuItemProps): JSX.Element => {
85
87
  const {focusedItem, setFocusedItem, closeMenu, isMenuOpen} = useMenuContext();
@@ -93,6 +95,19 @@ export const MenuItem = ({
93
95
 
94
96
  const menuItemDataAttributes = {testid: 'MenuItem', ...dataAttributes};
95
97
 
98
+ const renderTextContent = (id?: string) => (
99
+ <div id={id} className={styles.itemTextContent}>
100
+ <Text3 regular color={contentColor}>
101
+ {label}
102
+ </Text3>
103
+ {description && (
104
+ <Text2 regular color={vars.colors.textSecondary}>
105
+ {description}
106
+ </Text2>
107
+ )}
108
+ </div>
109
+ );
110
+
96
111
  const renderContent = () =>
97
112
  controlType === 'checkbox' ? (
98
113
  <Checkbox
@@ -108,7 +123,7 @@ export const MenuItem = ({
108
123
  disabled={disabled}
109
124
  role="menuitemcheckbox"
110
125
  dataAttributes={menuItemDataAttributes}
111
- render={({controlElement}) => (
126
+ render={({controlElement, labelId}) => (
112
127
  <Box paddingX={8} paddingY={12}>
113
128
  <Inline space="between" alignItems="center">
114
129
  <div className={styles.itemContent}>
@@ -117,9 +132,7 @@ export const MenuItem = ({
117
132
  <Icon size={24} color={contentColor} />
118
133
  </div>
119
134
  )}
120
- <Text3 regular color={contentColor}>
121
- {label}
122
- </Text3>
135
+ {renderTextContent(labelId)}
123
136
  </div>
124
137
  <Box paddingLeft={16}>{controlElement}</Box>
125
138
  </Inline>
@@ -146,9 +159,7 @@ export const MenuItem = ({
146
159
  <Icon size={24} color={contentColor} />
147
160
  </div>
148
161
  )}
149
- <Text3 regular color={contentColor}>
150
- {label}
151
- </Text3>
162
+ {renderTextContent()}
152
163
  </div>
153
164
  </Box>
154
165
  </Touchable>
@@ -1,2 +1,2 @@
1
1
  // DO NOT EDIT THIS FILE. It's autogenerated by set-version.js
2
- export const PACKAGE_VERSION = '16.61.0' as string;
2
+ export const PACKAGE_VERSION = '16.62.0' as string;