@transferwise/components 46.136.1 → 46.137.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 (153) hide show
  1. package/build/common/hooks/useContainerSize.js +30 -0
  2. package/build/common/hooks/useContainerSize.js.map +1 -0
  3. package/build/common/hooks/useContainerSize.mjs +28 -0
  4. package/build/common/hooks/useContainerSize.mjs.map +1 -0
  5. package/build/common/hooks/useResizeObserver.js +3 -3
  6. package/build/common/hooks/useResizeObserver.js.map +1 -1
  7. package/build/common/hooks/useResizeObserver.mjs +3 -3
  8. package/build/common/hooks/useResizeObserver.mjs.map +1 -1
  9. package/build/criticalBanner/CriticalCommsBanner.js +3 -0
  10. package/build/criticalBanner/CriticalCommsBanner.js.map +1 -1
  11. package/build/criticalBanner/CriticalCommsBanner.mjs +3 -0
  12. package/build/criticalBanner/CriticalCommsBanner.mjs.map +1 -1
  13. package/build/field/Field.js +3 -2
  14. package/build/field/Field.js.map +1 -1
  15. package/build/field/Field.mjs +3 -2
  16. package/build/field/Field.mjs.map +1 -1
  17. package/build/i18n/en.json +2 -0
  18. package/build/i18n/en.json.js +2 -0
  19. package/build/i18n/en.json.js.map +1 -1
  20. package/build/i18n/en.json.mjs +2 -0
  21. package/build/i18n/en.json.mjs.map +1 -1
  22. package/build/index.js +2 -0
  23. package/build/index.js.map +1 -1
  24. package/build/index.mjs +1 -0
  25. package/build/index.mjs.map +1 -1
  26. package/build/listItem/Prompt/ListItemPrompt.js +3 -2
  27. package/build/listItem/Prompt/ListItemPrompt.js.map +1 -1
  28. package/build/listItem/Prompt/ListItemPrompt.mjs +3 -2
  29. package/build/listItem/Prompt/ListItemPrompt.mjs.map +1 -1
  30. package/build/logo/Logo.js +77 -25
  31. package/build/logo/Logo.js.map +1 -1
  32. package/build/logo/Logo.mjs +79 -27
  33. package/build/logo/Logo.mjs.map +1 -1
  34. package/build/logo/logo-assets.js +68 -97
  35. package/build/logo/logo-assets.js.map +1 -1
  36. package/build/logo/logo-assets.mjs +62 -90
  37. package/build/logo/logo-assets.mjs.map +1 -1
  38. package/build/main.css +225 -58
  39. package/build/prompt/ActionPrompt/ActionPrompt.js +8 -40
  40. package/build/prompt/ActionPrompt/ActionPrompt.js.map +1 -1
  41. package/build/prompt/ActionPrompt/ActionPrompt.mjs +8 -40
  42. package/build/prompt/ActionPrompt/ActionPrompt.mjs.map +1 -1
  43. package/build/prompt/CriticalBanner/CriticalBanner.js +143 -0
  44. package/build/prompt/CriticalBanner/CriticalBanner.js.map +1 -0
  45. package/build/prompt/CriticalBanner/CriticalBanner.mjs +141 -0
  46. package/build/prompt/CriticalBanner/CriticalBanner.mjs.map +1 -0
  47. package/build/prompt/CriticalBanner/helpers.js +29 -0
  48. package/build/prompt/CriticalBanner/helpers.js.map +1 -0
  49. package/build/prompt/CriticalBanner/helpers.mjs +26 -0
  50. package/build/prompt/CriticalBanner/helpers.mjs.map +1 -0
  51. package/build/prompt/InfoPrompt/InfoPrompt.js +3 -2
  52. package/build/prompt/InfoPrompt/InfoPrompt.js.map +1 -1
  53. package/build/prompt/InfoPrompt/InfoPrompt.mjs +3 -2
  54. package/build/prompt/InfoPrompt/InfoPrompt.mjs.map +1 -1
  55. package/build/prompt/PrimitivePrompt/PrimitivePrompt.js +11 -4
  56. package/build/prompt/PrimitivePrompt/PrimitivePrompt.js.map +1 -1
  57. package/build/prompt/PrimitivePrompt/PrimitivePrompt.mjs +11 -4
  58. package/build/prompt/PrimitivePrompt/PrimitivePrompt.mjs.map +1 -1
  59. package/build/prompt/common/Expander/Expander.js +35 -0
  60. package/build/prompt/common/Expander/Expander.js.map +1 -0
  61. package/build/prompt/common/Expander/Expander.messages.js +17 -0
  62. package/build/prompt/common/Expander/Expander.messages.js.map +1 -0
  63. package/build/prompt/common/Expander/Expander.messages.mjs +13 -0
  64. package/build/prompt/common/Expander/Expander.messages.mjs.map +1 -0
  65. package/build/prompt/common/Expander/Expander.mjs +33 -0
  66. package/build/prompt/common/Expander/Expander.mjs.map +1 -0
  67. package/build/prompt/helpers/promptMedia.js +52 -0
  68. package/build/prompt/helpers/promptMedia.js.map +1 -0
  69. package/build/prompt/helpers/promptMedia.mjs +50 -0
  70. package/build/prompt/helpers/promptMedia.mjs.map +1 -0
  71. package/build/styles/logo/Logo.css +3 -23
  72. package/build/styles/main.css +225 -58
  73. package/build/styles/prompt/CriticalBanner/CriticalBanner.css +134 -0
  74. package/build/styles/prompt/CriticalBanner/CriticalBanner.vars.css +0 -0
  75. package/build/styles/prompt/InfoPrompt/InfoPrompt.css +24 -0
  76. package/build/styles/prompt/common/Expander/Expander.css +8 -0
  77. package/build/typeahead/Typeahead.js +3 -2
  78. package/build/typeahead/Typeahead.js.map +1 -1
  79. package/build/typeahead/Typeahead.mjs +3 -2
  80. package/build/typeahead/Typeahead.mjs.map +1 -1
  81. package/build/types/common/hooks/useContainerSize.d.ts +14 -0
  82. package/build/types/common/hooks/useContainerSize.d.ts.map +1 -0
  83. package/build/types/common/hooks/useResizeObserver.d.ts +1 -1
  84. package/build/types/common/hooks/useResizeObserver.d.ts.map +1 -1
  85. package/build/types/criticalBanner/CriticalCommsBanner.d.ts +3 -0
  86. package/build/types/criticalBanner/CriticalCommsBanner.d.ts.map +1 -1
  87. package/build/types/index.d.ts +2 -2
  88. package/build/types/index.d.ts.map +1 -1
  89. package/build/types/logo/Logo.d.ts +33 -1
  90. package/build/types/logo/Logo.d.ts.map +1 -1
  91. package/build/types/logo/logo-assets.d.ts +33 -9
  92. package/build/types/logo/logo-assets.d.ts.map +1 -1
  93. package/build/types/prompt/ActionPrompt/ActionPrompt.d.ts +2 -11
  94. package/build/types/prompt/ActionPrompt/ActionPrompt.d.ts.map +1 -1
  95. package/build/types/prompt/CriticalBanner/CriticalBanner.d.ts +39 -0
  96. package/build/types/prompt/CriticalBanner/CriticalBanner.d.ts.map +1 -0
  97. package/build/types/prompt/CriticalBanner/helpers.d.ts +18 -0
  98. package/build/types/prompt/CriticalBanner/helpers.d.ts.map +1 -0
  99. package/build/types/prompt/CriticalBanner/index.d.ts +3 -0
  100. package/build/types/prompt/CriticalBanner/index.d.ts.map +1 -0
  101. package/build/types/prompt/InfoPrompt/InfoPrompt.d.ts.map +1 -1
  102. package/build/types/prompt/PrimitivePrompt/PrimitivePrompt.d.ts +35 -3
  103. package/build/types/prompt/PrimitivePrompt/PrimitivePrompt.d.ts.map +1 -1
  104. package/build/types/prompt/common/Expander/Expander.d.ts +20 -0
  105. package/build/types/prompt/common/Expander/Expander.d.ts.map +1 -0
  106. package/build/types/prompt/common/Expander/Expander.messages.d.ts +14 -0
  107. package/build/types/prompt/common/Expander/Expander.messages.d.ts.map +1 -0
  108. package/build/types/prompt/helpers/promptMedia.d.ts +22 -0
  109. package/build/types/prompt/helpers/promptMedia.d.ts.map +1 -0
  110. package/build/types/prompt/index.d.ts +2 -0
  111. package/build/types/prompt/index.d.ts.map +1 -1
  112. package/build/types/test-utils/index.d.ts +4 -0
  113. package/build/types/test-utils/index.d.ts.map +1 -1
  114. package/package.json +6 -6
  115. package/src/common/hooks/useContainerSize.test.tsx +125 -0
  116. package/src/common/hooks/useContainerSize.ts +32 -0
  117. package/src/common/hooks/useResizeObserver.ts +3 -2
  118. package/src/criticalBanner/CriticalCommsBanner.story.tsx +4 -0
  119. package/src/criticalBanner/CriticalCommsBanner.test.story.tsx +1 -1
  120. package/src/criticalBanner/CriticalCommsBanner.tsx +3 -0
  121. package/src/i18n/en.json +2 -0
  122. package/src/index.ts +2 -2
  123. package/src/logo/Logo.css +3 -23
  124. package/src/logo/Logo.less +3 -29
  125. package/src/logo/Logo.story.tsx +117 -89
  126. package/src/logo/Logo.test.story.tsx +15 -24
  127. package/src/logo/Logo.tsx +90 -28
  128. package/src/logo/logo-assets.tsx +36 -92
  129. package/src/main.css +225 -58
  130. package/src/main.less +3 -1
  131. package/src/prompt/ActionPrompt/ActionPrompt.tsx +9 -62
  132. package/src/prompt/CriticalBanner/CriticalBanner.accessibility.docs.mdx +113 -0
  133. package/src/prompt/CriticalBanner/CriticalBanner.css +134 -0
  134. package/src/prompt/CriticalBanner/CriticalBanner.less +155 -0
  135. package/src/prompt/CriticalBanner/CriticalBanner.story.tsx +635 -0
  136. package/src/prompt/CriticalBanner/CriticalBanner.test.story.tsx +422 -0
  137. package/src/prompt/CriticalBanner/CriticalBanner.tsx +179 -0
  138. package/src/prompt/CriticalBanner/CriticalBanner.vars.css +0 -0
  139. package/src/prompt/CriticalBanner/CriticalBanner.vars.less +6 -0
  140. package/src/prompt/CriticalBanner/helpers.ts +39 -0
  141. package/src/prompt/CriticalBanner/index.ts +2 -0
  142. package/src/prompt/InfoPrompt/InfoPrompt.css +24 -0
  143. package/src/prompt/InfoPrompt/InfoPrompt.less +23 -0
  144. package/src/prompt/InfoPrompt/InfoPrompt.tsx +5 -1
  145. package/src/prompt/PrimitivePrompt/PrimitivePrompt.tsx +56 -40
  146. package/src/prompt/common/Expander/Expander.css +8 -0
  147. package/src/prompt/common/Expander/Expander.less +9 -0
  148. package/src/prompt/common/Expander/Expander.messages.ts +14 -0
  149. package/src/prompt/common/Expander/Expander.test.tsx +167 -0
  150. package/src/prompt/common/Expander/Expander.tsx +83 -0
  151. package/src/prompt/helpers/promptMedia.tsx +79 -0
  152. package/src/prompt/index.ts +4 -0
  153. package/src/sentimentSurface/SentimentSurface.story.tsx +43 -17
@@ -0,0 +1,125 @@
1
+ import React, { act } from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+
4
+ import { mockResizeObserver } from '../../test-utils/window-mock';
5
+
6
+ import { useContainerSize } from './useContainerSize';
7
+
8
+ mockResizeObserver();
9
+
10
+ describe('useContainerSize', () => {
11
+ let resizeObserverCallback: ResizeObserverCallback | null = null;
12
+ const OriginalResizeObserver = global.ResizeObserver;
13
+
14
+ beforeEach(() => {
15
+ resizeObserverCallback = null;
16
+
17
+ // Capture the ResizeObserver callback for testing
18
+ global.ResizeObserver = jest.fn().mockImplementation((callback: ResizeObserverCallback) => {
19
+ resizeObserverCallback = callback;
20
+ const instance = new OriginalResizeObserver(callback);
21
+ return instance;
22
+ }) as unknown as typeof ResizeObserver;
23
+ });
24
+
25
+ afterEach(() => {
26
+ global.ResizeObserver = OriginalResizeObserver;
27
+ });
28
+
29
+ // Helper to create a test component
30
+ function TestComponent({
31
+ breakpoint,
32
+ onStateChange,
33
+ }: {
34
+ breakpoint: number;
35
+ onStateChange: (state: boolean) => void;
36
+ }) {
37
+ const [ref, isAboveBreakpoint] = useContainerSize(breakpoint);
38
+
39
+ // Call the callback whenever state changes
40
+ React.useEffect(() => {
41
+ onStateChange(isAboveBreakpoint);
42
+ }, [isAboveBreakpoint, onStateChange]);
43
+
44
+ return (
45
+ <div ref={ref} data-testid="container">
46
+ Test
47
+ </div>
48
+ );
49
+ }
50
+
51
+ // Helper to simulate container resize
52
+ function simulateResize(width: number, options?: { noBorderBoxSize?: boolean }) {
53
+ const container = screen.getByTestId('container');
54
+
55
+ act(() => {
56
+ if (resizeObserverCallback) {
57
+ const entry = {
58
+ target: container,
59
+ borderBoxSize: options?.noBorderBoxSize
60
+ ? undefined
61
+ : [{ inlineSize: width, blockSize: 100 }],
62
+ contentRect: {
63
+ width,
64
+ height: 100,
65
+ x: 0,
66
+ y: 0,
67
+ top: 0,
68
+ right: width,
69
+ bottom: 100,
70
+ left: 0,
71
+ toJSON: () => ({}),
72
+ },
73
+ contentBoxSize: [{ inlineSize: width, blockSize: 100 }],
74
+ devicePixelContentBoxSize: [{ inlineSize: width, blockSize: 100 }],
75
+ } as ResizeObserverEntry;
76
+
77
+ resizeObserverCallback([entry], {} as ResizeObserver);
78
+ }
79
+ });
80
+ }
81
+
82
+ it('returns initial state as false', () => {
83
+ const onStateChange = jest.fn();
84
+ render(<TestComponent breakpoint={480} onStateChange={onStateChange} />);
85
+
86
+ // Initial call with false
87
+ expect(onStateChange).toHaveBeenCalledWith(false);
88
+ });
89
+
90
+ it('updates to true when container width is above breakpoint', () => {
91
+ const onStateChange = jest.fn();
92
+ render(<TestComponent breakpoint={480} onStateChange={onStateChange} />);
93
+
94
+ simulateResize(600);
95
+ expect(onStateChange).toHaveBeenCalledWith(true);
96
+ });
97
+
98
+ it('remains false when container width is below breakpoint', () => {
99
+ const onStateChange = jest.fn();
100
+ render(<TestComponent breakpoint={480} onStateChange={onStateChange} />);
101
+
102
+ simulateResize(400);
103
+ expect(onStateChange).toHaveBeenCalledWith(false);
104
+ expect(onStateChange).not.toHaveBeenCalledWith(true);
105
+ });
106
+
107
+ it('returns true when container width equals breakpoint', () => {
108
+ const onStateChange = jest.fn();
109
+ render(<TestComponent breakpoint={480} onStateChange={onStateChange} />);
110
+
111
+ simulateResize(480);
112
+ expect(onStateChange).toHaveBeenCalledWith(true);
113
+ });
114
+
115
+ it('updates state when container crosses breakpoint from below to above', () => {
116
+ const onStateChange = jest.fn();
117
+ render(<TestComponent breakpoint={480} onStateChange={onStateChange} />);
118
+
119
+ simulateResize(400);
120
+ expect(onStateChange).toHaveBeenCalledWith(false);
121
+
122
+ simulateResize(600);
123
+ expect(onStateChange).toHaveBeenCalledWith(true);
124
+ });
125
+ });
@@ -0,0 +1,32 @@
1
+ import { useRef, useState } from 'react';
2
+
3
+ import { useResizeObserver } from './useResizeObserver';
4
+
5
+ /**
6
+ * Hook that returns a ref and a boolean indicating if the container
7
+ * has a width >= the specified breakpoint.
8
+ *
9
+ * Useful for synchronizing React state with CSS container queries.
10
+ *
11
+ * Uses content-box measurements to match CSS container query behavior
12
+ * (excludes padding and border).
13
+ *
14
+ * @param breakpoint - Minimum width in pixels
15
+ * @returns [ref, isAboveBreakpoint] tuple
16
+ */
17
+ export function useContainerSize(breakpoint: number): [React.RefObject<HTMLDivElement>, boolean] {
18
+ const ref = useRef<HTMLDivElement>(null);
19
+ const [isAboveBreakpoint, setIsAboveBreakpoint] = useState(false);
20
+
21
+ useResizeObserver(
22
+ ref,
23
+ (entry) => {
24
+ // Use contentRect.width to match CSS container query box model (content-box)
25
+ const inlineSize = entry.contentRect.width;
26
+ setIsAboveBreakpoint(inlineSize >= breakpoint);
27
+ },
28
+ 'content-box',
29
+ );
30
+
31
+ return [ref, isAboveBreakpoint];
32
+ }
@@ -5,6 +5,7 @@ import { useEffectEvent } from './useEffectEvent';
5
5
  export function useResizeObserver(
6
6
  ref: React.MutableRefObject<Element | null>,
7
7
  callback: (entry: ResizeObserverEntry) => void,
8
+ box: ResizeObserverBoxOptions = 'border-box',
8
9
  ) {
9
10
  const handleCallback = useEffectEvent(callback);
10
11
  useEffect(() => {
@@ -12,11 +13,11 @@ export function useResizeObserver(
12
13
  const resizeObserver = new ResizeObserver(([entry]) => {
13
14
  handleCallback(entry);
14
15
  });
15
- resizeObserver.observe(ref.current, { box: 'border-box' });
16
+ resizeObserver.observe(ref.current, { box });
16
17
  return () => {
17
18
  resizeObserver.disconnect();
18
19
  };
19
20
  }
20
21
  return () => {};
21
- }, [handleCallback, ref]);
22
+ }, [handleCallback, ref, box]);
22
23
  }
@@ -1,9 +1,13 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import CriticalCommsBanner from '.';
3
3
 
4
+ /**
5
+ * @deprecated Use **`CriticalBanner`** component instead.
6
+ */
4
7
  export default {
5
8
  component: CriticalCommsBanner,
6
9
  title: 'Prompts/CriticalCommsBanner',
10
+ tags: ['deprecated'],
7
11
  } satisfies Meta<typeof CriticalCommsBanner>;
8
12
 
9
13
  type Story = StoryObj<typeof CriticalCommsBanner>;
@@ -6,7 +6,7 @@ import { withVariantConfig } from '../../.storybook/helpers';
6
6
  export default {
7
7
  component: CriticalCommsBanner,
8
8
  title: 'Prompts/CriticalCommsBanner/Tests',
9
- tags: ['!autodocs'],
9
+ tags: ['!autodocs', 'deprecated'],
10
10
  } satisfies Meta<typeof CriticalCommsBanner>;
11
11
 
12
12
  type Story = StoryObj<typeof CriticalCommsBanner>;
@@ -51,6 +51,9 @@ const iconBySentiment: Record<CriticalCommsBannerSentiment, React.ReactNode> = {
51
51
  ),
52
52
  };
53
53
 
54
+ /**
55
+ * @deprecated `CriticalCommsBanner` component is deprecated and now replaced by the `CriticalBanner` component.
56
+ */
54
57
  function CriticalCommsBanner({
55
58
  title,
56
59
  subtitle,
package/src/i18n/en.json CHANGED
@@ -16,6 +16,8 @@
16
16
  "neptune.DateLookup.selected": "selected",
17
17
  "neptune.DateLookup.twentyYears": "20 years",
18
18
  "neptune.DateLookup.year": "year",
19
+ "neptune.Expander.collapseAriaLabel": "Collapse",
20
+ "neptune.Expander.expandAriaLabel": "Expand",
19
21
  "neptune.ExpressiveMoneyInput.currency.search.placeholder": "Type a currency / country",
20
22
  "neptune.ExpressiveMoneyInput.currency.select.currency": "Select currency",
21
23
  "neptune.FlowNavigation.back": "back to previous step",
package/src/index.ts CHANGED
@@ -36,7 +36,7 @@ export type { HeaderProps } from './header';
36
36
  export type { EmphasisProps } from './emphasis';
37
37
  export type { FieldProps } from './field/Field';
38
38
  export type { InfoProps } from './info';
39
- export type { InlinePromptProps, ActionPromptProps } from './prompt';
39
+ export type { InlinePromptProps, ActionPromptProps, CriticalBannerProps } from './prompt';
40
40
  export type { InfoPromptProps, InfoPromptAction, InfoPromptMedia } from './prompt';
41
41
  export type { InputWithDisplayFormatProps } from './inputWithDisplayFormat';
42
42
  export type { InputProps } from './inputs/Input';
@@ -175,7 +175,7 @@ export { default as Header } from './header';
175
175
  export { default as Image } from './image';
176
176
  export { default as Info } from './info';
177
177
  export { default as InlineAlert } from './inlineAlert';
178
- export { InfoPrompt, InlinePrompt, ActionPrompt } from './prompt';
178
+ export { InfoPrompt, InlinePrompt, ActionPrompt, CriticalBanner } from './prompt';
179
179
  export { default as InputWithDisplayFormat } from './inputWithDisplayFormat';
180
180
  export { Input } from './inputs/Input';
181
181
  export { InputGroup } from './inputs/InputGroup';
package/src/logo/Logo.css CHANGED
@@ -1,26 +1,6 @@
1
1
  .np-logo {
2
2
  display: inline-block;
3
- }
4
- .np-theme-personal--forest-green .np-logo-svg path,
5
- .np-theme-personal--bright-green .np-logo-svg path {
6
- fill: var(--color-interactive-primary);
7
- }
8
- .np-theme-personal--dark .np-logo-svg path {
9
- fill: var(--color-white);
10
- }
11
- .np-logo-svg--size-sm {
12
- display: block;
13
- }
14
- @media (min-width: 576px) {
15
- .np-logo-svg--size-sm {
16
- display: none;
17
- }
18
- }
19
- .np-logo-svg--size-md {
20
- display: none;
21
- }
22
- @media (min-width: 576px) {
23
- .np-logo-svg--size-md {
24
- display: block;
25
- }
3
+ color: var(--color-interactive-primary);
4
+ width: var(--wds-logo-width);
5
+ height: var(--wds-logo-height);
26
6
  }
@@ -1,32 +1,6 @@
1
1
  .np-logo {
2
2
  display: inline-block;
3
- }
4
-
5
- .np-logo-svg {
6
- path {
7
- .np-theme-personal--forest-green &,
8
- .np-theme-personal--bright-green & {
9
- fill: var(--color-interactive-primary);
10
- }
11
-
12
- .np-theme-personal--dark & {
13
- fill: var(--color-white);
14
- }
15
- }
16
-
17
- &--size-sm {
18
- display: block;
19
-
20
- @media (--screen-sm) {
21
- display: none;
22
- }
23
- }
24
-
25
- &--size-md {
26
- display: none;
27
-
28
- @media (--screen-sm) {
29
- display: block;
30
- }
31
- }
3
+ color: var(--color-interactive-primary);
4
+ width: var(--wds-logo-width);
5
+ height: var(--wds-logo-height);
32
6
  }
@@ -1,6 +1,7 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
 
3
- import Logo, { LogoType } from '.';
3
+ import Logo, { LogoType, LogoDisplay, LogoFormat } from './Logo';
4
+ import { withVariantConfig } from '../../.storybook/helpers';
4
5
 
5
6
  /**
6
7
  * **Design guidance**: <a href="https://wise.design/foundations/logo" target="_blank">wise.design/foundations/logo</a>
@@ -10,13 +11,21 @@ const meta: Meta<typeof Logo> = {
10
11
  title: 'Content/Logo',
11
12
  args: {
12
13
  type: 'WISE',
13
- inverse: false,
14
14
  },
15
15
  argTypes: {
16
16
  type: {
17
17
  control: 'radio',
18
18
  options: Object.values(LogoType),
19
19
  },
20
+ display: {
21
+ control: 'radio',
22
+ options: Object.values(LogoDisplay),
23
+ },
24
+ format: {
25
+ control: 'radio',
26
+ options: Object.values(LogoFormat),
27
+ },
28
+ inverse: { control: { disable: true } },
20
29
  },
21
30
  parameters: {
22
31
  docs: { toc: true },
@@ -29,23 +38,15 @@ type Story = StoryObj<typeof Logo>;
29
38
 
30
39
  /** Explore all props via the controls panel. */
31
40
  export const Playground: Story = {
32
- render: (args) => (
33
- <div
34
- style={{
35
- padding: '2rem',
36
- ...(args.inverse
37
- ? { backgroundColor: 'var(--color-background-screen-dark, #0e0f0c)' }
38
- : {}),
39
- }}
40
- >
41
- <Logo {...args} />
42
- </div>
43
- ),
41
+ args: {
42
+ type: 'WISE',
43
+ format: 'primary-lockup',
44
+ },
45
+ render: (args) => <Logo {...args} />,
44
46
  };
45
47
 
46
48
  /**
47
- * The three logo types: standard Wise, Wise Business, and Wise Platform. <br />
48
- * `WISE_BUSINESS` renders the same SVG as `WISE` but with the accessible label "Wise Business".
49
+ * The three logo types: standard Wise, Wise Business, and Wise Platform.
49
50
  */
50
51
  export const Types: Story = {
51
52
  argTypes: {
@@ -59,9 +60,6 @@ export const Types: Story = {
59
60
  alignItems: 'center',
60
61
  padding: '2rem',
61
62
  borderRadius: '8px',
62
- ...(args.inverse
63
- ? { backgroundColor: 'var(--color-background-screen-dark, #0e0f0c)' }
64
- : {}),
65
63
  }}
66
64
  >
67
65
  {Object.values(LogoType).map((type) => (
@@ -75,14 +73,6 @@ export const Types: Story = {
75
73
  }}
76
74
  >
77
75
  <Logo {...args} type={type} />
78
- <span
79
- style={{
80
- fontSize: '12px',
81
- ...(args.inverse ? { color: 'rgba(255,255,255,0.6)' } : { opacity: 0.6 }),
82
- }}
83
- >
84
- {type}
85
- </span>
86
76
  </div>
87
77
  ))}
88
78
  </div>
@@ -99,99 +89,137 @@ export const Types: Story = {
99
89
  };
100
90
 
101
91
  /**
102
- * Below `576px` the flag-only mark is shown; at `576px` and above the full wordmark is displayed.
92
+ * The `format="primary-lockup"` variant shows the product name inline alongside the wordmark.
103
93
  */
104
- export const Responsive: Story = {
94
+ export const PrimaryLockup: Story = {
105
95
  argTypes: {
106
96
  type: { table: { disable: true } },
107
- inverse: { table: { disable: true } },
97
+ format: { table: { disable: true } },
108
98
  },
109
99
  render: (args) => (
110
- <div style={{ display: 'flex', flexDirection: 'column', gap: '2rem' }}>
111
- <div>
112
- <span style={{ fontSize: '12px', opacity: 0.6, display: 'block', marginBottom: '0.5rem' }}>
113
- {'< 576px (flag only)'}
114
- </span>
115
- <div style={{ display: 'flex', gap: '3rem', alignItems: 'center' }}>
116
- {Object.values(LogoType).map((type) => (
117
- <span key={type} className="np-logo" style={{ display: 'inline-block' }}>
118
- <style>{`.responsive-sm .np-logo-svg--size-md { display: none !important; } .responsive-sm .np-logo-svg--size-sm { display: block !important; }`}</style>
119
- <span className="responsive-sm">
120
- <Logo type={type} />
121
- </span>
122
- </span>
123
- ))}
124
- </div>
125
- </div>
126
- <div>
127
- <span style={{ fontSize: '12px', opacity: 0.6, display: 'block', marginBottom: '0.5rem' }}>
128
- {'\u2265 576px (full wordmark)'}
129
- </span>
130
- <div style={{ display: 'flex', gap: '3rem', alignItems: 'center' }}>
131
- {Object.values(LogoType).map((type) => (
132
- <Logo key={type} type={type} />
133
- ))}
100
+ <div style={{ display: 'flex', gap: '3rem', alignItems: 'center', padding: '2rem' }}>
101
+ {Object.values(LogoType).map((type) => (
102
+ <div key={type} style={{ display: 'flex', gap: '3rem', alignItems: 'center' }}>
103
+ <div
104
+ style={{
105
+ display: 'flex',
106
+ flexDirection: 'column',
107
+ alignItems: 'center',
108
+ gap: '0.5rem',
109
+ }}
110
+ >
111
+ <Logo {...args} type={type} format="primary-lockup" />
112
+ </div>
134
113
  </div>
135
- </div>
114
+ ))}
136
115
  </div>
137
116
  ),
138
117
  parameters: {
139
118
  docs: {
140
- source: { code: null },
119
+ source: {
120
+ code: `<Logo type="WISE" format="primary-lockup" />
121
+ <Logo type="WISE_BUSINESS" format="primary-lockup" />
122
+ <Logo type="WISE_PLATFORM" format="primary-lockup" />`,
123
+ },
141
124
  },
142
125
  },
143
126
  };
144
127
 
145
128
  /**
146
- * All logo types on a dark background using the `inverse` prop, which renders a
147
- * light-coloured version suited for dark surfaces.
129
+ * The `format="secondary-lockup"` variant uses a stacked two-line layout with the product name.
148
130
  */
149
- export const Inverse: Story = {
131
+ export const SecondaryLockup: Story = {
150
132
  argTypes: {
151
133
  type: { table: { disable: true } },
152
- inverse: { table: { disable: true } },
134
+ format: { table: { disable: true } },
153
135
  },
154
- decorators: [
155
- (Story) => (
156
- <div
157
- style={{
158
- display: 'flex',
159
- gap: '3rem',
160
- alignItems: 'center',
161
- backgroundColor: 'var(--color-background-screen-dark, #0e0f0c)',
162
- padding: '2rem',
163
- borderRadius: '8px',
164
- }}
165
- >
166
- <Story />
167
- </div>
168
- ),
169
- ],
170
136
  render: (args) => (
171
- <>
137
+ <div style={{ display: 'flex', gap: '3rem', alignItems: 'flex-end', padding: '2rem' }}>
138
+ {Object.values(LogoType).map((type) => (
139
+ <div key={type} style={{ display: 'flex', gap: '3rem', alignItems: 'flex-end' }}>
140
+ <div
141
+ style={{
142
+ display: 'flex',
143
+ flexDirection: 'column',
144
+ alignItems: 'center',
145
+ gap: '0.5rem',
146
+ }}
147
+ >
148
+ <Logo {...args} type={type} format="secondary-lockup" />
149
+ </div>
150
+ </div>
151
+ ))}
152
+ </div>
153
+ ),
154
+ parameters: {
155
+ docs: {
156
+ source: {
157
+ code: `<Logo type="WISE" format="secondary-lockup" />
158
+ <Logo type="WISE_BUSINESS" format="secondary-lockup" />
159
+ <Logo type="WISE_PLATFORM" format="secondary-lockup" />`,
160
+ },
161
+ },
162
+ },
163
+ };
164
+
165
+ /**
166
+ * When `display` is `"compact"`, only the fast-flag mark is rendered regardless of type or other settings.
167
+ */
168
+ export const Compact: Story = {
169
+ render: (args) => (
170
+ <div style={{ display: 'flex', gap: '3rem', alignItems: 'center', padding: '2rem' }}>
172
171
  {Object.values(LogoType).map((type) => (
173
172
  <div
174
173
  key={type}
175
- style={{
176
- display: 'flex',
177
- flexDirection: 'column',
178
- alignItems: 'center',
179
- gap: '0.5rem',
180
- }}
174
+ style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '0.5rem' }}
181
175
  >
182
- <Logo type={type} inverse />
183
- <span style={{ fontSize: '12px', color: 'rgba(255,255,255,0.6)' }}>{type}</span>
176
+ <Logo {...args} type={type} format="primary-lockup" display="compact" />
177
+ <Logo {...args} type={type} format="secondary-lockup" display="compact" />
184
178
  </div>
185
179
  ))}
186
- </>
180
+ </div>
187
181
  ),
188
182
  parameters: {
189
183
  docs: {
190
184
  source: {
191
- code: `<Logo type="WISE" inverse />
192
- <Logo type="WISE_BUSINESS" inverse />
193
- <Logo type="WISE_PLATFORM" inverse />`,
185
+ code: `<Logo type=".." format="primary-lockup" display="compact" />
186
+ <Logo type=".." format="secondary-lockup" display="compact" />`,
194
187
  },
195
188
  },
196
189
  },
197
190
  };
191
+
192
+ /**
193
+ * When `display` is `"full"`, the full wordmark/lockup is rendered regardless of screen width.
194
+ */
195
+ export const Full: Story = {
196
+ render: (args) => (
197
+ <div style={{ display: 'flex', gap: '3rem', alignItems: 'flex-end', padding: '2rem' }}>
198
+ {Object.values(LogoType).map((type) => (
199
+ <div key={type} style={{ display: 'flex', gap: '3rem', alignItems: 'flex-end' }}>
200
+ <div
201
+ style={{
202
+ display: 'flex',
203
+ flexDirection: 'column',
204
+ alignItems: 'center',
205
+ gap: '0.5rem',
206
+ }}
207
+ >
208
+ <Logo {...args} type={type} format="primary-lockup" display="full" />
209
+ <Logo {...args} type={type} format="secondary-lockup" display="full" />
210
+ </div>
211
+ </div>
212
+ ))}
213
+ </div>
214
+ ),
215
+ ...withVariantConfig(['mobile'], {
216
+ parameters: {
217
+ docs: {
218
+ source: {
219
+ code: `<Logo type=".." format="primary-lockup" display="full" />
220
+ <Logo type=".." format="secondary-lockup" display="full" />`,
221
+ },
222
+ },
223
+ },
224
+ }),
225
+ };
@@ -17,37 +17,28 @@ const AllVariants = () => (
17
17
  <div style={{ display: 'flex', flexDirection: 'column', gap: '2rem' }}>
18
18
  <div style={{ display: 'flex', gap: '2rem', alignItems: 'center' }}>
19
19
  {Object.values(LogoType).map((type) => (
20
- <Logo key={type} type={type} />
21
- ))}
22
- </div>
23
- <div
24
- style={{
25
- display: 'flex',
26
- gap: '2rem',
27
- alignItems: 'center',
28
- backgroundColor: 'var(--color-content-primary)',
29
- padding: '1rem',
30
- borderRadius: '8px',
31
- }}
32
- >
33
- {Object.values(LogoType).map((type) => (
34
- <Logo key={type} type={type} inverse />
20
+ <div key={type}>
21
+ <Logo type={type} className="d-block" format="primary-lockup" />
22
+ <Logo type={type} className="d-block" format="secondary-lockup" />
23
+ <Logo type={type} className="d-block" format="primary-lockup" display="compact" />
24
+ <Logo type={type} className="d-block" format="primary-lockup" display="full" />
25
+ <Logo type={type} className="d-block" format="primary-lockup" display="responsive" />
26
+ </div>
35
27
  ))}
36
28
  </div>
37
29
  </div>
38
30
  );
39
31
 
40
- export const Variants: Story = {
41
- render: () => <AllVariants />,
42
- ...withVariantConfig(['default', 'dark', 'bright-green', 'forest-green']),
43
- };
44
-
45
- export const RTL: Story = {
32
+ export const Themes: Story = {
46
33
  render: () => <AllVariants />,
47
- ...withVariantConfig(['rtl']),
34
+ ...withVariantConfig(['default', 'dark', 'bright-green', 'forest-green'], {
35
+ parameters: {
36
+ padding: '',
37
+ },
38
+ }),
48
39
  };
49
40
 
50
- export const Zoom400: Story = {
41
+ export const Responsive: Story = {
51
42
  render: () => <AllVariants />,
52
- ...withVariantConfig(['400%']),
43
+ ...withVariantConfig(['mobile']),
53
44
  };