@transferwise/components 0.0.0-experimental-9f4c334 → 0.0.0-experimental-4a0eb84

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.
@@ -13,6 +13,7 @@ export type Props = {
13
13
  media?: ReactNode;
14
14
  control?: ReactNode;
15
15
  prompt?: ReactNode;
16
+ partiallyInteractive?: boolean;
16
17
  className?: string;
17
18
  };
18
19
  export type ListItemContextData = {
@@ -24,11 +25,11 @@ export type ListItemContextData = {
24
25
  control: string;
25
26
  prompt: string;
26
27
  };
27
- props: Pick<Props, 'as' | 'disabled' | 'inverted'>;
28
+ props: Pick<Props, 'as' | 'disabled' | 'partiallyInteractive' | 'inverted'>;
28
29
  };
29
30
  export declare const ListItemContext: import("react").Context<ListItemContextData>;
30
31
  export declare const ListItem: {
31
- ({ as: View, title, subtitle, additionalInfo, prompt, inverted, media, spotlight, valueTitle, valueSubtitle, control, disabled, className, }: Props): import("react").JSX.Element;
32
+ ({ as: View, title, subtitle, additionalInfo, prompt, inverted, media, spotlight, valueTitle, valueSubtitle, control, disabled, partiallyInteractive, className, }: Props): import("react").JSX.Element;
32
33
  Image: ({ alt, size, ...props }: import("./ListItemMedia").ListItemImageProps) => import("react").JSX.Element;
33
34
  AvatarView: ({ className, size, ...props }: import("./ListItemMedia").ListItemAvatarViewProps) => import("react").JSX.Element;
34
35
  AvatarLayout: ({ className, size, ...props }: import("./ListItemMedia").ListItemAvatarLayoutProps) => import("react").JSX.Element;
@@ -36,6 +37,7 @@ export declare const ListItem: {
36
37
  Checkbox: (props: import("./ListItemCheckbox").ListItemCheckboxProps) => import("react").JSX.Element;
37
38
  IconButton: (props: import("./ListItemIconButton").ListItemIconButtonProps) => import("react").JSX.Element;
38
39
  Navigation: ({ onClick }: import("./ListItemNavigation").ListItemNavigationProps) => import("react").JSX.Element;
40
+ Radio: (props: import("../common/RadioButton/RadioButton").RadioButtonProps) => import("react").JSX.Element;
39
41
  Button: ({ priority, ...props }: import("./ListItemButton").ListItemButtonProps) => import("react").JSX.Element;
40
42
  Switch: (props: import("..").SwitchProps) => import("react").JSX.Element;
41
43
  Prompt: ({ type, children, action }: import("./prompt/Prompt").ListItemPromptProps) => import("react").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"ListItem.d.ts","sourceRoot":"","sources":["../../../src/listItem/ListItem.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,SAAS,EAA4B,MAAM,OAAO,CAAC;AAa3E,MAAM,MAAM,aAAa,GACrB,iBAAiB,GACjB,YAAY,GACZ,OAAO,GACP,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,aAAa,CAAC;AAElB,MAAM,MAAM,KAAK,GAAG;IAClB,EAAE,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IAClC,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,cAAc,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,GAAG,EAAE;QACH,KAAK,EAAE,MAAM,CAAC;QACd,cAAc,EAAE,MAAM,CAAC;QACvB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,UAAU,GAAG,UAAU,CAAC,CAAC;CACpD,CAAC;AAIF,eAAO,MAAM,eAAe,8CAA2C,CAAC;AAExE,eAAO,MAAM,QAAQ;kJAclB,KAAK;;;;;;;;;;;CA0GP,CAAC;AAeF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"ListItem.d.ts","sourceRoot":"","sources":["../../../src/listItem/ListItem.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,SAAS,EAA4B,MAAM,OAAO,CAAC;AAc3E,MAAM,MAAM,aAAa,GACrB,iBAAiB,GACjB,YAAY,GACZ,OAAO,GACP,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,aAAa,CAAC;AAElB,MAAM,MAAM,KAAK,GAAG;IAClB,EAAE,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IAClC,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,cAAc,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,GAAG,EAAE;QACH,KAAK,EAAE,MAAM,CAAC;QACd,cAAc,EAAE,MAAM,CAAC;QACvB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,UAAU,GAAG,sBAAsB,GAAG,UAAU,CAAC,CAAC;CAC7E,CAAC;AAIF,eAAO,MAAM,eAAe,8CAA2C,CAAC;AAExE,eAAO,MAAM,QAAQ;wKAelB,KAAK;;;;;;;;;;;;CAsHP,CAAC;AAgBF,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { RadioButtonProps } from '../common/RadioButton/RadioButton';
2
+ export declare const Radio: (props: RadioButtonProps) => import("react").JSX.Element;
3
+ //# sourceMappingURL=ListItemRadio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListItemRadio.d.ts","sourceRoot":"","sources":["../../../src/listItem/ListItemRadio.tsx"],"names":[],"mappings":"AAAA,OAAoB,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAGlF,eAAO,MAAM,KAAK,GAAa,OAAO,gBAAgB,gCAYrD,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { ListItemTypes } from './ListItem';
2
+ export declare function useItemControl(controlType: ListItemTypes): {
3
+ ids: {
4
+ label: string;
5
+ additionalInfo: string;
6
+ value: string;
7
+ control: string;
8
+ prompt: string;
9
+ };
10
+ baseItemProps: Pick<import("./ListItem").Props, "as" | "disabled" | "partiallyInteractive" | "inverted">;
11
+ };
12
+ //# sourceMappingURL=useListItemControl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useListItemControl.d.ts","sourceRoot":"","sources":["../../../src/listItem/useListItemControl.tsx"],"names":[],"mappings":"AACA,OAAO,EAAwC,aAAa,EAAE,MAAM,YAAY,CAAC;AAEjF,wBAAgB,cAAc,CAAC,WAAW,EAAE,aAAa;;;;;;;;;EAYxD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transferwise/components",
3
- "version": "0.0.0-experimental-9f4c334",
3
+ "version": "0.0.0-experimental-4a0eb84",
4
4
  "description": "Neptune React components",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -92,8 +92,8 @@
92
92
  "rollup-preserve-directives": "^1.1.3",
93
93
  "storybook": "^8.6.14",
94
94
  "@transferwise/less-config": "3.1.2",
95
- "@transferwise/neptune-css": "14.24.4",
96
95
  "@wise/components-theming": "1.6.3",
96
+ "@transferwise/neptune-css": "14.24.4",
97
97
  "@wise/wds-configs": "0.0.0"
98
98
  },
99
99
  "peerDependencies": {
@@ -29,6 +29,7 @@ type Story = StoryObj<ItemProps>;
29
29
  export const TempPlayground: Story = {
30
30
  render: () => {
31
31
  const [checked, setChecked] = useState(false);
32
+ const [radio, setRadio] = useState('option2');
32
33
 
33
34
  return (
34
35
  <div>
@@ -111,11 +112,15 @@ export const TempPlayground: Story = {
111
112
 
112
113
  <ListItem
113
114
  title="Test title"
114
- disabled
115
115
  subtitle={lorem10}
116
116
  additionalInfo={<ListItem.AdditionalInfo>{lorem20}</ListItem.AdditionalInfo>}
117
- control={<ListItem.Button priority="secondary-neutral">as Button</ListItem.Button>}
117
+ control={
118
+ <ListItem.Button priority="secondary-neutral" onClick={() => console.log('clicked')}>
119
+ as Button
120
+ </ListItem.Button>
121
+ }
118
122
  />
123
+
119
124
  <ListItem
120
125
  title="Test title"
121
126
  disabled
@@ -144,6 +149,31 @@ export const TempPlayground: Story = {
144
149
  </ListItem.Button>
145
150
  }
146
151
  />
152
+ <ListItem
153
+ title="Fully Interactive"
154
+ subtitle={lorem10}
155
+ additionalInfo={<ListItem.AdditionalInfo>{lorem20}</ListItem.AdditionalInfo>}
156
+ control={
157
+ <ListItem.Radio
158
+ name="option1"
159
+ checked={radio === 'option1'}
160
+ onChange={() => setRadio('option1')}
161
+ />
162
+ }
163
+ />
164
+ <ListItem
165
+ title="Partially Interactive"
166
+ partiallyInteractive
167
+ subtitle={lorem10}
168
+ additionalInfo={<ListItem.AdditionalInfo>{lorem20}</ListItem.AdditionalInfo>}
169
+ control={
170
+ <ListItem.Radio
171
+ name="option2"
172
+ checked={radio === 'option2'}
173
+ onChange={() => setRadio('option2')}
174
+ />
175
+ }
176
+ />
147
177
 
148
178
  <ListItem
149
179
  media={
@@ -4,6 +4,7 @@ import Body from '../body';
4
4
  import { AdditionalInfo } from './ListItemAdditionalInfo';
5
5
  import { IconButton } from './ListItemIconButton';
6
6
  import { Checkbox } from './ListItemCheckbox';
7
+ import { Radio } from './ListItemRadio';
7
8
  import { Navigation } from './ListItemNavigation';
8
9
  import { clsx } from 'clsx';
9
10
  import { Button } from './ListItemButton';
@@ -33,6 +34,7 @@ export type Props = {
33
34
  media?: ReactNode;
34
35
  control?: ReactNode;
35
36
  prompt?: ReactNode;
37
+ partiallyInteractive?: boolean;
36
38
  className?: string;
37
39
  };
38
40
 
@@ -45,7 +47,7 @@ export type ListItemContextData = {
45
47
  control: string;
46
48
  prompt: string;
47
49
  };
48
- props: Pick<Props, 'as' | 'disabled' | 'inverted'>;
50
+ props: Pick<Props, 'as' | 'disabled' | 'partiallyInteractive' | 'inverted'>;
49
51
  };
50
52
 
51
53
  // @ts-expect-error for now let's mock it with `null` value
@@ -65,6 +67,7 @@ export const ListItem = ({
65
67
  valueSubtitle,
66
68
  control = null,
67
69
  disabled,
70
+ partiallyInteractive,
68
71
  className,
69
72
  }: Props) => {
70
73
  /*
@@ -105,13 +108,12 @@ export const ListItem = ({
105
108
  const isFullyInteractive = controlType !== 'non-interactive';
106
109
 
107
110
  const listItemContext = useMemo(
108
- () => ({ setControlType, ids, props: { as: View, disabled, inverted } }),
111
+ () => ({ setControlType, ids, props: { as: View, disabled, inverted, partiallyInteractive } }),
109
112
  [],
110
113
  );
111
114
 
112
- return (
113
- <ListItemContext.Provider value={listItemContext}>
114
- <View
115
+ const content = (
116
+ <View
115
117
  className={clsx(
116
118
  'wds-list-item',
117
119
  { 'wds-list-item-interactive': controlType !== 'non-interactive' },
@@ -125,53 +127,66 @@ export const ListItem = ({
125
127
  )}
126
128
  aria-describedby={[ids.additionalInfo].join(' ')}
127
129
  >
128
- {media && <div className="wds-list-item-media">{media}</div>}
129
-
130
- {/* Title + Subtitle + Values + Additional Info - Group */}
131
- <div className="wds-list-item-body">
132
- {/* Title + Subtitle + Values - Group */}
133
- <div className="d-flex justify-content-between">
134
- <span>
135
- {/* @ts-expect-error div can have role and aria-lavel props */}
136
- <Body
137
- type={Typography.BODY_LARGE_BOLD}
138
- className="wds-list-item-title"
139
- // for a11y this needs to be a header but for SEO it shouldn't be `h*` tag
140
- // so we enable header semantics via `role` and `aria-level` attrs
141
- role="heading"
142
- aria-level="4"
143
- >
144
- {title}
145
- </Body>
146
- <Body className="wds-list-item-subtitle">{subtitle}</Body>
130
+ {media && <div className="wds-list-item-media">{media}</div>}
131
+ {/* Title + Subtitle + Values + Additional Info - Group */}
132
+ <div className="wds-list-item-body">
133
+ {/* Title + Subtitle + Values - Group */}
134
+ <div className="d-flex justify-content-between">
135
+ <span>
136
+ {/* @ts-expect-error div can have role and aria-lavel props */}
137
+ <Body
138
+ type={Typography.BODY_LARGE_BOLD}
139
+ className="wds-list-item-title"
140
+ // for a11y this needs to be a header but for SEO it shouldn't be `h*` tag
141
+ // so we enable header semantics via `role` and `aria-level` attrs
142
+ role="heading"
143
+ aria-level="4"
144
+ >
145
+ {title}
146
+ </Body>
147
+ <Body className="wds-list-item-subtitle">{subtitle}</Body>
148
+ </span>
149
+ {(valueTitle || valueSubtitle) && (
150
+ <span
151
+ id={ids.value}
152
+ className={clsx('wds-list-item-value', 'd-flex align-items-center', {
153
+ 'flex-column': valueTitle !== undefined && valueSubtitle !== undefined,
154
+ })}
155
+ >
156
+ {valueTitle && (
157
+ <Body type={Typography.BODY_LARGE_BOLD} className="wds-list-item-title-value">
158
+ {valueTitle}
159
+ </Body>
160
+ )}
161
+ {valueSubtitle && (
162
+ <Body className="wds-list-item-subtitle-value">{valueSubtitle}</Body>
163
+ )}
147
164
  </span>
148
- {(valueTitle || valueSubtitle) && (
149
- <span
150
- id={ids.value}
151
- className={clsx('wds-list-item-value', 'd-flex align-items-center', {
152
- 'flex-column': valueTitle !== undefined && valueSubtitle !== undefined,
153
- })}
154
- >
155
- {valueTitle && (
156
- <Body type={Typography.BODY_LARGE_BOLD} className="wds-list-item-title-value">
157
- {valueTitle}
158
- </Body>
159
- )}
160
- {valueSubtitle && (
161
- <Body className="wds-list-item-subtitle-value">{valueSubtitle}</Body>
162
- )}
163
- </span>
164
- )}
165
- </div>
166
-
167
- {/* Additional Info and Prompt here */}
168
- {Boolean(subtitle) && additionalInfo}
165
+ )}
169
166
  </div>
170
- {control === null ? null : <Body className="wds-list-item-control">{control}</Body>}
171
- {prompt}
172
- </View>
173
- </ListItemContext.Provider>
167
+
168
+ {/* Additional Info and Prompt here */}
169
+ {Boolean(subtitle) && additionalInfo}
170
+ </div>
171
+ {control === null ? null : <Body className="wds-list-item-control">{control}</Body>}
172
+ {prompt}
173
+ </View>
174
174
  );
175
+
176
+ // only apply partiallyInteractive check for button and button icon??
177
+ if (
178
+ !partiallyInteractive &&
179
+ (controlType === 'radio' || controlType === 'button') &&
180
+ ids.control
181
+ ) {
182
+ return (
183
+ <ListItemContext.Provider value={listItemContext}>
184
+ <label htmlFor={ids.control}>{content}</label>
185
+ </ListItemContext.Provider>
186
+ );
187
+ }
188
+
189
+ return <ListItemContext.Provider value={listItemContext}>{content}</ListItemContext.Provider>;
175
190
  };
176
191
 
177
192
  /* eslint-disable functional/immutable-data */
@@ -182,6 +197,7 @@ ListItem.AdditionalInfo = AdditionalInfo;
182
197
  ListItem.Checkbox = Checkbox;
183
198
  ListItem.IconButton = IconButton;
184
199
  ListItem.Navigation = Navigation;
200
+ ListItem.Radio = Radio;
185
201
  ListItem.Button = Button;
186
202
  ListItem.Switch = Switch;
187
203
  ListItem.Prompt = Prompt;
@@ -1,10 +1,10 @@
1
1
  import { default as ButtonComp, NewButtonProps } from '../button';
2
- import { useItemControl } from './useItemControl';
2
+ import { useItemControl } from './useListItemControl';
3
3
 
4
4
  export type ListItemButtonProps = Omit<NewButtonProps, 'v2' | 'size' | 'disabled'>;
5
5
 
6
6
  export const Button = ({ priority = 'secondary', ...props }: ListItemButtonProps) => {
7
- const { baseItemProps } = useItemControl('button');
7
+ const { ids, baseItemProps } = useItemControl('button');
8
8
 
9
9
  const commonProps = {
10
10
  ...props,
@@ -14,5 +14,5 @@ export const Button = ({ priority = 'secondary', ...props }: ListItemButtonProps
14
14
  disabled: baseItemProps.disabled,
15
15
  };
16
16
 
17
- return <ButtonComp {...(commonProps as NewButtonProps)} />;
17
+ return <ButtonComp {...(commonProps as NewButtonProps)} id={ids.control} />;
18
18
  };
@@ -1,6 +1,6 @@
1
1
  import CheckboxButton from '../checkboxButton';
2
2
  import { CheckboxButtonProps } from '../checkboxButton/CheckboxButton';
3
- import { useItemControl } from './useItemControl';
3
+ import { useItemControl } from './useListItemControl';
4
4
 
5
5
  export type ListItemCheckboxProps = Pick<
6
6
  CheckboxButtonProps,
@@ -1,5 +1,5 @@
1
1
  import { default as IconButtonComp, IconButtonProps } from '../iconButton';
2
- import { useItemControl } from './useItemControl';
2
+ import { useItemControl } from './useListItemControl';
3
3
  import { ReactNode } from 'react';
4
4
 
5
5
  export type ListItemIconButtonProps = Pick<IconButtonProps, 'onClick' | 'href' | 'target'> & {
@@ -1,6 +1,6 @@
1
1
  import { ChevronRight, BillSplit as Disabled } from '@transferwise/icons';
2
2
  import { ButtonProps } from '../button/Button.types';
3
- import { useItemControl } from './useItemControl';
3
+ import { useItemControl } from './useListItemControl';
4
4
 
5
5
  export type ListItemNavigationProps = Pick<ButtonProps, 'onClick' | 'href'>;
6
6
 
@@ -0,0 +1,16 @@
1
+ import RadioButton, { RadioButtonProps } from '../common/RadioButton/RadioButton';
2
+ import { useItemControl } from './useListItemControl';
3
+
4
+ export const Radio = function (props: RadioButtonProps) {
5
+ const { ids, baseItemProps } = useItemControl('radio');
6
+
7
+ if (baseItemProps.partiallyInteractive) {
8
+ return (
9
+ <label htmlFor={ids.control}>
10
+ <RadioButton disabled={baseItemProps.disabled} {...props} id={ids.control} />
11
+ </label>
12
+ );
13
+ }
14
+
15
+ return <RadioButton disabled={baseItemProps.disabled} {...props} id={ids.control} />;
16
+ };
@@ -1,5 +1,5 @@
1
1
  import { default as SwitchComp, SwitchProps } from '../switch';
2
- import { useItemControl } from './useItemControl';
2
+ import { useItemControl } from './useListItemControl';
3
3
 
4
4
  export const Switch = function (props: SwitchProps) {
5
5
  const { baseItemProps } = useItemControl('switch');
@@ -2,11 +2,15 @@ import { useContext, useEffect } from 'react';
2
2
  import { ListItemContext, ListItemContextData, ListItemTypes } from './ListItem';
3
3
 
4
4
  export function useItemControl(controlType: ListItemTypes) {
5
- const { setControlType, props: baseItemProps } = useContext<ListItemContextData>(ListItemContext);
5
+ const {
6
+ ids,
7
+ setControlType,
8
+ props: baseItemProps,
9
+ } = useContext<ListItemContextData>(ListItemContext);
6
10
 
7
11
  useEffect(() => {
8
12
  setControlType(controlType);
9
13
  }, [controlType, setControlType]);
10
14
 
11
- return { baseItemProps };
15
+ return { ids, baseItemProps };
12
16
  }
@@ -1,5 +0,0 @@
1
- import { ListItemTypes } from './ListItem';
2
- export declare function useItemControl(controlType: ListItemTypes): {
3
- baseItemProps: Pick<import("./ListItem").Props, "as" | "disabled" | "inverted">;
4
- };
5
- //# sourceMappingURL=useItemControl.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useItemControl.d.ts","sourceRoot":"","sources":["../../../src/listItem/useItemControl.tsx"],"names":[],"mappings":"AACA,OAAO,EAAwC,aAAa,EAAE,MAAM,YAAY,CAAC;AAEjF,wBAAgB,cAAc,CAAC,WAAW,EAAE,aAAa;;EAQxD"}