@transferwise/components 46.128.3 → 46.130.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 (121) hide show
  1. package/build/alert/Alert.js +1 -1
  2. package/build/alert/Alert.mjs +1 -1
  3. package/build/card/Card.js.map +1 -1
  4. package/build/card/Card.mjs.map +1 -1
  5. package/build/common/{card/Card.js → baseCard/BaseCard.js} +4 -4
  6. package/build/common/baseCard/BaseCard.js.map +1 -0
  7. package/build/common/{card/Card.mjs → baseCard/BaseCard.mjs} +4 -4
  8. package/build/common/baseCard/BaseCard.mjs.map +1 -0
  9. package/build/common/liveRegion/LiveRegion.js +42 -0
  10. package/build/common/liveRegion/LiveRegion.js.map +1 -0
  11. package/build/common/liveRegion/LiveRegion.mjs +40 -0
  12. package/build/common/liveRegion/LiveRegion.mjs.map +1 -0
  13. package/build/criticalBanner/CriticalCommsBanner.js +68 -3
  14. package/build/criticalBanner/CriticalCommsBanner.js.map +1 -1
  15. package/build/criticalBanner/CriticalCommsBanner.mjs +69 -4
  16. package/build/criticalBanner/CriticalCommsBanner.mjs.map +1 -1
  17. package/build/flowNavigation/FlowNavigation.js +1 -1
  18. package/build/flowNavigation/FlowNavigation.mjs +1 -1
  19. package/build/index.js +4 -4
  20. package/build/index.mjs +1 -1
  21. package/build/inputs/SelectInput.js +1 -1
  22. package/build/inputs/SelectInput.js.map +1 -1
  23. package/build/inputs/SelectInput.mjs +1 -1
  24. package/build/inputs/SelectInput.mjs.map +1 -1
  25. package/build/inputs/_ButtonInput.js +2 -2
  26. package/build/inputs/_ButtonInput.js.map +1 -1
  27. package/build/inputs/_ButtonInput.mjs +2 -2
  28. package/build/inputs/_ButtonInput.mjs.map +1 -1
  29. package/build/main.css +191 -165
  30. package/build/overlayHeader/OverlayHeader.js +1 -1
  31. package/build/overlayHeader/OverlayHeader.mjs +1 -1
  32. package/build/promoCard/PromoCard.js +2 -2
  33. package/build/promoCard/PromoCard.js.map +1 -1
  34. package/build/promoCard/PromoCard.mjs +2 -2
  35. package/build/promoCard/PromoCard.mjs.map +1 -1
  36. package/build/prompt/InfoPrompt/InfoPrompt.js +35 -29
  37. package/build/prompt/InfoPrompt/InfoPrompt.js.map +1 -1
  38. package/build/prompt/InfoPrompt/InfoPrompt.mjs +35 -29
  39. package/build/prompt/InfoPrompt/InfoPrompt.mjs.map +1 -1
  40. package/build/sentimentSurface/SentimentSurface.js +5 -1
  41. package/build/sentimentSurface/SentimentSurface.js.map +1 -1
  42. package/build/sentimentSurface/SentimentSurface.mjs +5 -1
  43. package/build/sentimentSurface/SentimentSurface.mjs.map +1 -1
  44. package/build/styles/criticalBanner/CriticalCommsBanner.css +33 -15
  45. package/build/styles/inputs/SelectInput.css +8 -0
  46. package/build/styles/listItem/ListItem.css +1 -1
  47. package/build/styles/main.css +191 -165
  48. package/build/styles/sentimentSurface/SentimentSurface.css +100 -100
  49. package/build/types/card/Card.d.ts +1 -1
  50. package/build/types/common/{card/Card.d.ts → baseCard/BaseCard.d.ts} +8 -8
  51. package/build/types/common/baseCard/BaseCard.d.ts.map +1 -0
  52. package/build/types/common/baseCard/index.d.ts +3 -0
  53. package/build/types/common/baseCard/index.d.ts.map +1 -0
  54. package/build/types/common/index.d.ts +2 -0
  55. package/build/types/common/index.d.ts.map +1 -1
  56. package/build/types/common/liveRegion/LiveRegion.d.ts +23 -0
  57. package/build/types/common/liveRegion/LiveRegion.d.ts.map +1 -0
  58. package/build/types/common/liveRegion/index.d.ts +3 -0
  59. package/build/types/common/liveRegion/index.d.ts.map +1 -0
  60. package/build/types/criticalBanner/CriticalCommsBanner.d.ts +4 -1
  61. package/build/types/criticalBanner/CriticalCommsBanner.d.ts.map +1 -1
  62. package/build/types/criticalBanner/index.d.ts +1 -0
  63. package/build/types/criticalBanner/index.d.ts.map +1 -1
  64. package/build/types/index.d.ts +2 -1
  65. package/build/types/index.d.ts.map +1 -1
  66. package/build/types/inputs/SelectInput.d.ts.map +1 -1
  67. package/build/types/promoCard/PromoCard.d.ts +3 -3
  68. package/build/types/promoCard/PromoCard.d.ts.map +1 -1
  69. package/build/types/prompt/InfoPrompt/InfoPrompt.d.ts +11 -2
  70. package/build/types/prompt/InfoPrompt/InfoPrompt.d.ts.map +1 -1
  71. package/build/types/sentimentSurface/SentimentSurface.d.ts.map +1 -1
  72. package/package.json +2 -2
  73. package/src/card/Card.story.tsx +3 -2
  74. package/src/card/Card.tsx +1 -1
  75. package/src/common/{card/Card.less → baseCard/BaseCard.less} +1 -1
  76. package/src/common/{card/Card.story.tsx → baseCard/BaseCard.story.tsx} +5 -5
  77. package/src/common/{card/Card.test.tsx → baseCard/BaseCard.test.tsx} +11 -12
  78. package/src/common/{card/Card.tsx → baseCard/BaseCard.tsx} +9 -9
  79. package/src/common/baseCard/index.ts +2 -0
  80. package/src/common/index.ts +2 -0
  81. package/src/common/liveRegion/LiveRegion.test.tsx +56 -0
  82. package/src/common/liveRegion/LiveRegion.tsx +49 -0
  83. package/src/common/liveRegion/index.ts +2 -0
  84. package/src/criticalBanner/CriticalCommsBanner.css +33 -15
  85. package/src/criticalBanner/CriticalCommsBanner.less +46 -36
  86. package/src/criticalBanner/CriticalCommsBanner.story.tsx +9 -15
  87. package/src/criticalBanner/CriticalCommsBanner.test.story.tsx +70 -0
  88. package/src/criticalBanner/CriticalCommsBanner.test.tsx +66 -0
  89. package/src/criticalBanner/CriticalCommsBanner.tsx +54 -5
  90. package/src/criticalBanner/index.ts +1 -0
  91. package/src/index.ts +2 -1
  92. package/src/inputs/SelectInput.css +8 -0
  93. package/src/inputs/SelectInput.story.tsx +2 -2
  94. package/src/inputs/SelectInput.test.story.tsx +57 -1
  95. package/src/inputs/SelectInput.test.tsx +33 -1
  96. package/src/inputs/SelectInput.tsx +2 -1
  97. package/src/inputs/_ButtonInput.less +8 -0
  98. package/src/inputs/_ButtonInput.tsx +1 -1
  99. package/src/listItem/ListItem.css +1 -1
  100. package/src/listItem/ListItem.less +4 -2
  101. package/src/listItem/_stories/Breakpoints/ListItem.noMedia.test.story.tsx +62 -0
  102. package/src/listItem/_stories/Breakpoints/ListItem.sideMedia.test.story.tsx +62 -0
  103. package/src/listItem/_stories/Breakpoints/ListItem.stackedMedia.test.story.tsx +62 -0
  104. package/src/listItem/_stories/ListItem.story.tsx +3 -2
  105. package/src/main.css +191 -165
  106. package/src/main.less +2 -2
  107. package/src/promoCard/PromoCard.tsx +6 -5
  108. package/src/prompt/InfoPrompt/InfoPrompt.test.story.tsx +119 -0
  109. package/src/prompt/InfoPrompt/InfoPrompt.tsx +47 -34
  110. package/src/sentimentSurface/SentimentSurface.css +100 -100
  111. package/src/sentimentSurface/SentimentSurface.less +50 -50
  112. package/src/sentimentSurface/SentimentSurface.test.story.tsx +19 -0
  113. package/src/sentimentSurface/SentimentSurface.tsx +3 -0
  114. package/build/common/card/Card.js.map +0 -1
  115. package/build/common/card/Card.mjs.map +0 -1
  116. package/build/types/common/card/Card.d.ts.map +0 -1
  117. package/build/types/common/card/index.d.ts +0 -3
  118. package/build/types/common/card/index.d.ts.map +0 -1
  119. package/src/common/card/index.ts +0 -2
  120. /package/build/styles/common/{card/Card.css → baseCard/BaseCard.css} +0 -0
  121. /package/src/common/{card/Card.css → baseCard/BaseCard.css} +0 -0
@@ -0,0 +1,66 @@
1
+ import { render, screen, mockMatchMedia } from '../test-utils';
2
+
3
+ import CriticalCommsBanner from './CriticalCommsBanner';
4
+
5
+ mockMatchMedia();
6
+
7
+ describe('CriticalCommsBanner', () => {
8
+ const defaultProps = {
9
+ title: 'Test title',
10
+ subtitle: 'Test subtitle',
11
+ action: { label: 'Take action', href: 'https://wise.com' },
12
+ };
13
+
14
+ it('renders with default negative sentiment', () => {
15
+ render(<CriticalCommsBanner {...defaultProps} />);
16
+
17
+ expect(screen.getByText('Test title')).toBeInTheDocument();
18
+ expect(screen.getByText('Test subtitle')).toBeInTheDocument();
19
+ expect(screen.getByTestId('alert')).toHaveClass('alert-negative');
20
+ });
21
+
22
+ it('renders the action', () => {
23
+ render(<CriticalCommsBanner {...defaultProps} />);
24
+
25
+ expect(screen.getByText('Take action')).toBeInTheDocument();
26
+ });
27
+
28
+ describe('sentiment variants', () => {
29
+ it('renders negative sentiment with correct alert type and icon', () => {
30
+ render(<CriticalCommsBanner {...defaultProps} sentiment="negative" />);
31
+
32
+ expect(screen.getByTestId('alert')).toHaveClass('alert-negative');
33
+ // Custom icon replaces the default StatusIcon
34
+ expect(screen.queryByTestId('status-icon')).not.toBeInTheDocument();
35
+ });
36
+
37
+ it('renders warning sentiment with correct alert type and icon', () => {
38
+ render(<CriticalCommsBanner {...defaultProps} sentiment="warning" />);
39
+
40
+ expect(screen.getByTestId('alert')).toHaveClass('alert-warning');
41
+ expect(screen.queryByTestId('status-icon')).not.toBeInTheDocument();
42
+ });
43
+
44
+ it('renders neutral sentiment with correct alert type and icon', () => {
45
+ render(<CriticalCommsBanner {...defaultProps} sentiment="neutral" />);
46
+
47
+ expect(screen.getByTestId('alert')).toHaveClass('alert-neutral');
48
+ expect(screen.queryByTestId('status-icon')).not.toBeInTheDocument();
49
+ });
50
+ });
51
+
52
+ it('wraps content in SentimentSurface with elevated emphasis', () => {
53
+ render(<CriticalCommsBanner {...defaultProps} sentiment="warning" />);
54
+
55
+ const surface = screen.getByTestId('alert').closest('.critical-comms');
56
+ expect(surface).toHaveClass('wds-sentiment-surface');
57
+ expect(surface).toHaveClass('wds-sentiment-surface-warning-elevated');
58
+ });
59
+
60
+ it('applies className to the wrapper', () => {
61
+ render(<CriticalCommsBanner {...defaultProps} className="custom-class" />);
62
+
63
+ const surface = screen.getByTestId('alert').closest('.critical-comms');
64
+ expect(surface).toHaveClass('custom-class');
65
+ });
66
+ });
@@ -1,5 +1,16 @@
1
- import Alert from '../alert';
1
+ import { Alert as AlertIcon, ClockBorderless as ClockIcon } from '@transferwise/icons';
2
2
  import { clsx } from 'clsx';
3
+ import { PropsWithChildren } from 'react';
4
+
5
+ import Alert from '../alert';
6
+ import { Sentiment } from '../common';
7
+ import Circle, { CircleProps } from '../common/circle';
8
+ import SentimentSurface from '../sentimentSurface';
9
+
10
+ export type CriticalCommsBannerSentiment =
11
+ | `${Sentiment.WARNING}`
12
+ | `${Sentiment.NEGATIVE}`
13
+ | `${Sentiment.NEUTRAL}`;
3
14
 
4
15
  export type CriticalCommsBannerProps = {
5
16
  title: string;
@@ -9,20 +20,58 @@ export type CriticalCommsBannerProps = {
9
20
  href?: string;
10
21
  onClick?: () => void;
11
22
  };
23
+ sentiment?: CriticalCommsBannerSentiment;
12
24
  className?: string;
13
25
  };
14
26
 
15
- function CriticalCommsBanner({ title, subtitle, action, className }: CriticalCommsBannerProps) {
27
+ const makeSurface = (sentiment: CriticalCommsBannerSentiment) => {
28
+ const Surface = (props: PropsWithChildren<Pick<CircleProps, 'className'>>) => (
29
+ <SentimentSurface as="span" emphasis="elevated" sentiment={sentiment} {...props} />
30
+ );
31
+ Surface.displayName = `CriticalCommsSurface(${sentiment})`;
32
+ return Surface;
33
+ };
34
+
35
+ const iconBySentiment: Record<CriticalCommsBannerSentiment, React.ReactNode> = {
36
+ [Sentiment.NEGATIVE]: (
37
+ <Circle as={makeSurface(Sentiment.NEGATIVE)} size={32} className="status-circle negative">
38
+ <AlertIcon className="status-icon light" />
39
+ </Circle>
40
+ ),
41
+ [Sentiment.WARNING]: (
42
+ <Circle as={makeSurface(Sentiment.WARNING)} size={32} className="status-circle warning">
43
+ <AlertIcon className="status-icon dark" />
44
+ </Circle>
45
+ ),
46
+ [Sentiment.NEUTRAL]: (
47
+ <Circle as={makeSurface(Sentiment.NEUTRAL)} size={32} className="status-circle neutral">
48
+ <ClockIcon className="status-icon dark" />
49
+ </Circle>
50
+ ),
51
+ };
52
+
53
+ function CriticalCommsBanner({
54
+ title,
55
+ subtitle,
56
+ action,
57
+ sentiment = Sentiment.NEGATIVE,
58
+ className,
59
+ }: CriticalCommsBannerProps) {
16
60
  return (
17
- <div className={clsx('critical-comms', className)}>
61
+ <SentimentSurface
62
+ sentiment={sentiment}
63
+ emphasis="elevated"
64
+ className={clsx('critical-comms', className)}
65
+ >
18
66
  <Alert
19
67
  title={title}
20
68
  message={subtitle}
21
69
  action={{ onClick: action?.onClick, target: action?.href, text: action?.label }}
22
70
  className={className}
23
- type="warning"
71
+ type={sentiment}
72
+ icon={iconBySentiment[sentiment]}
24
73
  />
25
- </div>
74
+ </SentimentSurface>
26
75
  );
27
76
  }
28
77
 
@@ -1 +1,2 @@
1
1
  export { default } from './CriticalCommsBanner';
2
+ export type { CriticalCommsBannerProps } from './CriticalCommsBanner';
package/src/index.ts CHANGED
@@ -154,8 +154,9 @@ export { Chip, default as Chips } from './chips';
154
154
  export { default as CircularButton } from './circularButton';
155
155
  export { default as Option } from './common/Option';
156
156
  export { default as BottomSheet } from './common/bottomSheet';
157
- export { default as BaseCard } from './common/card';
157
+ export { default as BaseCard } from './common/baseCard';
158
158
  export { default as CriticalCommsBanner } from './criticalBanner';
159
+ export type { CriticalCommsBannerProps } from './criticalBanner';
159
160
  export { default as DateInput } from './dateInput';
160
161
  export { default as DateLookup } from './dateLookup';
161
162
  export { default as Decision } from './decision';
@@ -102,6 +102,14 @@
102
102
  border-radius: var(--size-10);
103
103
  text-align: start;
104
104
  }
105
+ .np-button-input:has(.np-select-input-option-description-in-trigger) {
106
+ height: auto !important;
107
+ align-content: start;
108
+ padding-top: 12px !important;
109
+ padding-top: var(--size-12) !important;
110
+ padding-bottom: 12px !important;
111
+ padding-bottom: var(--size-12) !important;
112
+ }
105
113
  .np-popover-v2-container {
106
114
  z-index: 1060;
107
115
  display: flex;
@@ -430,11 +430,11 @@ export const Advanced: Story<Month> = {
430
430
  { type: 'separator' },
431
431
  ])
432
432
  .slice(0, -1),
433
- renderValue: (month, withinTrigger) => (
433
+ renderValue: (month) => (
434
434
  <SelectInputOptionContent
435
435
  title={month.name}
436
436
  note="Note"
437
- description={withinTrigger ? undefined : `Month #${month.id}`}
437
+ description={`Month #${month.id}`}
438
438
  icon={<Calendar size={24} />}
439
439
  />
440
440
  ),
@@ -1,11 +1,17 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { fireEvent, fn, type Mock, screen, userEvent, within } from 'storybook/test';
3
+ import { useState } from 'react';
3
4
 
4
5
  import { allModes } from '../../.storybook/modes';
5
6
  import Body from '../body';
6
7
  import { Field } from '../field/Field';
7
8
  import { lorem5, lorem500 } from '../test-utils';
8
- import { SelectInput, type SelectInputProps, sortByRelevance } from './SelectInput';
9
+ import {
10
+ SelectInput,
11
+ SelectInputOptionContent,
12
+ type SelectInputProps,
13
+ sortByRelevance,
14
+ } from './SelectInput';
9
15
 
10
16
  const meta = {
11
17
  title: 'Forms/SelectInput/Tests',
@@ -1364,3 +1370,53 @@ export const SmoothScrollReset: Story<string> = {
1364
1370
  },
1365
1371
  },
1366
1372
  };
1373
+
1374
+ interface OptionWithDescription {
1375
+ id: string;
1376
+ title: string;
1377
+ description?: string;
1378
+ }
1379
+
1380
+ const optionsWithDescription: OptionWithDescription[] = [
1381
+ { id: '1', title: 'Option One', description: 'This is the first option' },
1382
+ { id: '2', title: 'Option Two (no description)' },
1383
+ { id: '3', title: 'Option Three', description: 'This is the third option' },
1384
+ ];
1385
+
1386
+ /**
1387
+ * Test story to verify that SelectInput correctly displays an item with a description
1388
+ * when shown in the trigger button. The description should be visible in the trigger
1389
+ * after selection.
1390
+ */
1391
+ export const TriggerWithDescription: Story<OptionWithDescription> = {
1392
+ args: {
1393
+ items: optionsWithDescription.map((option) => ({
1394
+ type: 'option',
1395
+ value: option,
1396
+ })),
1397
+ defaultValue: optionsWithDescription[0],
1398
+ placeholder: 'Select an option',
1399
+ renderValue: (option, withinTrigger) => (
1400
+ <SelectInputOptionContent
1401
+ title={option.title}
1402
+ description={withinTrigger ? option.description : undefined}
1403
+ />
1404
+ ),
1405
+ },
1406
+ render: function Render({ onChange, ...args }) {
1407
+ const [selectedOption, setSelectedOption] = useState<OptionWithDescription>(
1408
+ optionsWithDescription[0],
1409
+ );
1410
+
1411
+ return (
1412
+ <SelectInput
1413
+ {...args}
1414
+ value={selectedOption}
1415
+ onChange={(option) => {
1416
+ setSelectedOption(option);
1417
+ onChange?.(option);
1418
+ }}
1419
+ />
1420
+ );
1421
+ },
1422
+ };
@@ -4,7 +4,12 @@ import { mockAnimationsApi } from 'jsdom-testing-mocks';
4
4
 
5
5
  import { render, mockMatchMedia, mockResizeObserver } from '../test-utils';
6
6
 
7
- import { SelectInput, type SelectInputOptionItem, type SelectInputProps } from './SelectInput';
7
+ import {
8
+ SelectInput,
9
+ SelectInputOptionContent,
10
+ type SelectInputOptionItem,
11
+ type SelectInputProps,
12
+ } from './SelectInput';
8
13
  import { Field } from '../field/Field';
9
14
 
10
15
  mockMatchMedia();
@@ -511,6 +516,33 @@ describe('SelectInput', () => {
511
516
  expect(options[2]).toHaveTextContent('Zambia');
512
517
  });
513
518
 
519
+ it('adds class to description wrapper when description is present', () => {
520
+ interface Currency {
521
+ code: string;
522
+ name: string;
523
+ description: string;
524
+ }
525
+
526
+ const usd: Currency = { code: 'USD', name: 'US Dollar', description: 'United States Dollar' };
527
+ const eur: Currency = { code: 'EUR', name: 'Euro', description: 'European Currency' };
528
+
529
+ render(
530
+ <SelectInput<Currency>
531
+ items={[
532
+ { type: 'option', value: usd },
533
+ { type: 'option', value: eur },
534
+ ]}
535
+ renderValue={(currency) => (
536
+ <SelectInputOptionContent title={currency.name} description={currency.description} />
537
+ )}
538
+ value={usd}
539
+ />,
540
+ );
541
+
542
+ const descriptionElement = screen.getByText('United States Dollar');
543
+ expect(descriptionElement).toHaveClass('np-select-input-option-description-in-trigger');
544
+ });
545
+
514
546
  describe('listbox label', () => {
515
547
  const fieldLabel = 'Fruits';
516
548
  const triggerLabel = 'Select fruit';
@@ -1256,7 +1256,8 @@ export function SelectInputOptionContent({
1256
1256
  <div
1257
1257
  className={clsx(
1258
1258
  'np-select-input-option-content-text-secondary np-text-body-default',
1259
- withinTrigger && 'np-select-input-option-content-text-within-trigger',
1259
+ withinTrigger &&
1260
+ 'np-select-input-option-content-text-within-trigger np-select-input-option-description-in-trigger',
1260
1261
  )}
1261
1262
  >
1262
1263
  {description}
@@ -4,4 +4,12 @@
4
4
  align-content: center;
5
5
  border-radius: var(--size-10);
6
6
  text-align: start;
7
+
8
+ // Using !important to overwrite styles from .form-control and inputClassNameBase util, which also use !important
9
+ &:has(.np-select-input-option-description-in-trigger) {
10
+ height: auto !important;
11
+ align-content: start;
12
+ padding-top: var(--size-12) !important;
13
+ padding-bottom: var(--size-12) !important;
14
+ }
7
15
  }
@@ -18,7 +18,7 @@ export const ButtonInput = forwardRef(function ButtonInput(
18
18
  <button
19
19
  ref={ref}
20
20
  type="button"
21
- className={clsx(className, inputClassNameBase({ size }), 'np-button-input')}
21
+ className={clsx(inputClassNameBase({ size }), 'np-button-input', className)}
22
22
  style={{ ...inputPaddings, ...style }}
23
23
  {...restProps}
24
24
  />
@@ -599,7 +599,7 @@
599
599
  .wds-list-item.disabled--has-prompt-reason .wds-list-item-prompt {
600
600
  opacity: 0.93;
601
601
  }
602
- .wds-list-item-spotlight {
602
+ .wds-list-item-spotlight .wds-list-item-gridWrapper {
603
603
  padding-left: 12px;
604
604
  padding-left: var(--size-12);
605
605
  padding-right: 12px;
@@ -266,8 +266,10 @@
266
266
  }
267
267
 
268
268
  &-spotlight {
269
- padding-left: var(--size-12);
270
- padding-right: var(--size-12);
269
+ .wds-list-item-gridWrapper {
270
+ padding-left: var(--size-12);
271
+ padding-right: var(--size-12);
272
+ }
271
273
 
272
274
  &-active {
273
275
  background-color: var(--color-background-neutral);
@@ -0,0 +1,62 @@
1
+ import { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import List from '../../../list';
3
+ import { ListItem, type ListItemProps } from '../../ListItem';
4
+ import {
5
+ SB_LIST_ITEM_ADDITIONAL_INFO as INFO,
6
+ SB_LIST_ITEM_CONTROLS as CONTROLS,
7
+ SB_LIST_ITEM_PROMPTS as PROMPT,
8
+ SB_LIST_ITEM_TEXT as TEXT,
9
+ SB_LIST_ITEM_MEDIA as MEDIA,
10
+ } from '../subcomponents';
11
+
12
+ export default {
13
+ component: ListItem,
14
+ title: 'Content/ListItem/tests/Breakpoints/NoMedia',
15
+ tags: ['!autodocs', '!manifest'],
16
+ parameters: {
17
+ controls: { disable: true },
18
+ actions: { disable: true },
19
+ knobs: { disable: true },
20
+ },
21
+ } satisfies Meta<ListItemProps>;
22
+
23
+ type Story = StoryObj<ListItemProps>;
24
+
25
+ const widths = [240, 241];
26
+
27
+ const sharedProps: Partial<ListItemProps> = {
28
+ subtitle: TEXT.subtitle,
29
+ valueTitle: TEXT.valueTitle,
30
+ valueSubtitle: TEXT.valueSubtitle,
31
+ additionalInfo: INFO.nonInteractive,
32
+ control: CONTROLS.switch,
33
+ prompt: PROMPT.interactive,
34
+ media: MEDIA.avatarSingle,
35
+ };
36
+
37
+ export const NoMedia: Story = {
38
+ render: () => (
39
+ <div
40
+ style={{
41
+ display: 'grid',
42
+ gridTemplateColumns: widths.map((w) => `${w}px`).join(' '),
43
+ gap: 16,
44
+ }}
45
+ >
46
+ {widths.map((w) => (
47
+ <div key={w} style={{ textAlign: 'center', fontWeight: 'bold' }}>
48
+ {w}px
49
+ </div>
50
+ ))}
51
+ {widths.map((w) => (
52
+ <div key={w} style={{ width: w }}>
53
+ <List>
54
+ <ListItem {...sharedProps} title="Inactive Spotlight" spotlight="inactive" />
55
+ <ListItem {...sharedProps} title="Active Spotlight" spotlight="active" />
56
+ <ListItem {...sharedProps} title="No Spotlight" />
57
+ </List>
58
+ </div>
59
+ ))}
60
+ </div>
61
+ ),
62
+ };
@@ -0,0 +1,62 @@
1
+ import { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import List from '../../../list';
3
+ import { ListItem, type ListItemProps } from '../../ListItem';
4
+ import {
5
+ SB_LIST_ITEM_ADDITIONAL_INFO as INFO,
6
+ SB_LIST_ITEM_CONTROLS as CONTROLS,
7
+ SB_LIST_ITEM_MEDIA as MEDIA,
8
+ SB_LIST_ITEM_PROMPTS as PROMPT,
9
+ SB_LIST_ITEM_TEXT as TEXT,
10
+ } from '../subcomponents';
11
+
12
+ export default {
13
+ component: ListItem,
14
+ title: 'Content/ListItem/tests/Breakpoints/SideMedia',
15
+ tags: ['!autodocs', '!manifest'],
16
+ parameters: {
17
+ controls: { disable: true },
18
+ actions: { disable: true },
19
+ knobs: { disable: true },
20
+ },
21
+ } satisfies Meta<ListItemProps>;
22
+
23
+ type Story = StoryObj<ListItemProps>;
24
+
25
+ const widths = [332, 333];
26
+
27
+ const sharedProps: Partial<ListItemProps> = {
28
+ subtitle: TEXT.subtitle,
29
+ valueTitle: TEXT.valueTitle,
30
+ valueSubtitle: TEXT.valueSubtitle,
31
+ additionalInfo: INFO.nonInteractive,
32
+ control: CONTROLS.switch,
33
+ prompt: PROMPT.interactive,
34
+ media: MEDIA.avatarSingle,
35
+ };
36
+
37
+ export const SideMedia: Story = {
38
+ render: () => (
39
+ <div
40
+ style={{
41
+ display: 'grid',
42
+ gridTemplateColumns: widths.map((w) => `${w}px`).join(' '),
43
+ gap: 16,
44
+ }}
45
+ >
46
+ {widths.map((w) => (
47
+ <div key={w} style={{ textAlign: 'center', fontWeight: 'bold' }}>
48
+ {w}px
49
+ </div>
50
+ ))}
51
+ {widths.map((w) => (
52
+ <div key={w} style={{ width: w }}>
53
+ <List>
54
+ <ListItem {...sharedProps} title="Inactive Spotlight" spotlight="inactive" />
55
+ <ListItem {...sharedProps} title="Active Spotlight" spotlight="active" />
56
+ <ListItem {...sharedProps} title="No Spotlight" />
57
+ </List>
58
+ </div>
59
+ ))}
60
+ </div>
61
+ ),
62
+ };
@@ -0,0 +1,62 @@
1
+ import { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import List from '../../../list';
3
+ import { ListItem, type ListItemProps } from '../../ListItem';
4
+ import {
5
+ SB_LIST_ITEM_ADDITIONAL_INFO as INFO,
6
+ SB_LIST_ITEM_CONTROLS as CONTROLS,
7
+ SB_LIST_ITEM_MEDIA as MEDIA,
8
+ SB_LIST_ITEM_PROMPTS as PROMPT,
9
+ SB_LIST_ITEM_TEXT as TEXT,
10
+ } from '../subcomponents';
11
+
12
+ export default {
13
+ component: ListItem,
14
+ title: 'Content/ListItem/tests/Breakpoints/StackedMedia',
15
+ tags: ['!autodocs', '!manifest'],
16
+ parameters: {
17
+ controls: { disable: true },
18
+ actions: { disable: true },
19
+ knobs: { disable: true },
20
+ },
21
+ } satisfies Meta<ListItemProps>;
22
+
23
+ type Story = StoryObj<ListItemProps>;
24
+
25
+ const widths = [308, 309];
26
+
27
+ const sharedProps: Partial<ListItemProps> = {
28
+ subtitle: TEXT.subtitle,
29
+ valueTitle: TEXT.valueTitle,
30
+ valueSubtitle: TEXT.valueSubtitle,
31
+ additionalInfo: INFO.nonInteractive,
32
+ control: CONTROLS.switch,
33
+ prompt: PROMPT.interactive,
34
+ media: MEDIA.avatarSingle,
35
+ };
36
+
37
+ export const StackedMedia: Story = {
38
+ render: () => (
39
+ <div
40
+ style={{
41
+ display: 'grid',
42
+ gridTemplateColumns: widths.map((w) => `${w}px`).join(' '),
43
+ gap: 16,
44
+ }}
45
+ >
46
+ {widths.map((w) => (
47
+ <div key={w} style={{ textAlign: 'center', fontWeight: 'bold' }}>
48
+ {w}px
49
+ </div>
50
+ ))}
51
+ {widths.map((w) => (
52
+ <div key={w} style={{ width: w }}>
53
+ <List>
54
+ <ListItem {...sharedProps} title="Inactive Spotlight" spotlight="inactive" />
55
+ <ListItem {...sharedProps} title="Active Spotlight" spotlight="active" />
56
+ <ListItem {...sharedProps} title="No Spotlight" />
57
+ </List>
58
+ </div>
59
+ ))}
60
+ </div>
61
+ ),
62
+ };
@@ -428,8 +428,9 @@ export const Spotlight: StoryObj<PreviewStoryArgs> = {
428
428
 
429
429
  return (
430
430
  <List>
431
- <ListItem {...props} {...previewProps} spotlight="inactive" />
432
- <ListItem {...props} {...previewProps} spotlight="active" />
431
+ <ListItem {...props} {...previewProps} title="Inactive Spotlight" spotlight="inactive" />
432
+ <ListItem {...props} {...previewProps} title="Active Spotlight" spotlight="active" />
433
+ <ListItem {...props} {...previewProps} title="No Spotlight" />
433
434
  </List>
434
435
  );
435
436
  },