@workday/canvas-kit-docs 6.1.1 → 6.1.5

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.
@@ -10,6 +10,7 @@ any questions about the update.
10
10
  - [Canvas Kit Preview](#canvas-kit-preview)
11
11
  - [Type Deprecations and Hierarchy Updates](#type-deprecations-and-hierarchy-updates)
12
12
  - [Canvas Kit CSS Maintenance Mode](#canvas-kit-css-maintenance-mode)
13
+ - [Prop Interfaces](#prop-interfaces)
13
14
  - [Component Changes](#component-changes)
14
15
  - [Component Promotions](#component-promotions)
15
16
  - [Core](#core)
@@ -423,6 +424,59 @@ provide more focused support and to dedicate our efforts to making bigger and be
423
424
  our most used components: Canvas Kit React. If you have questions or concerns, please
424
425
  [let us know](https://github.com/Workday/canvas-kit/issues/new?labels=&template=question.md).
425
426
 
427
+ ### Prop Interfaces
428
+
429
+ Many components were updated to be polymorphic using the `createComponent` utility function. Most
430
+ components in Canvas Kit extend from an HTML interface and spread extra props onto the HTML element.
431
+ Since these components are now polymorphic, the exported props no longer extend from an HTML
432
+ interface since the HTML interface is now determined by an optional `as` prop. It is common to wrap
433
+ Canvas Kit components with your own component and extend from the Canvas Kit component's prop
434
+ interface. To support this use-case in addition to polymorphic prop interfaces, `ExtractProp` was
435
+ introduced. `ExtractProp` understands these polymorphic components and will return the base props in
436
+ addition to the HTML interface. There is an optional second argument that can override the default
437
+ HTML interface if your wrapper component uses the `as`.
438
+
439
+ ```tsx
440
+ // v4
441
+ import {TextInput, TextInputProps} from '@workday/canvas-kit-react-text-input';
442
+
443
+ const FancyTextInput: React.FC<TextInputProps> = props => <TextInput {...props} />;
444
+
445
+ // v5
446
+ import {TextInput} from '@workday/canvas-kit-react/text-input';
447
+ import {ExtractProps} from '@workday/canvas-kit-react/common';
448
+
449
+ const FancyTextInput: React.FC<ExtractProps<typeof TextInput>> = props => {};
450
+
451
+ // v5 via createComponent
452
+ import {TextInput} from '@workday/canvas-kit-react/text-input';
453
+ import {createComponent} from '@workday/canvas-kit-react/common';
454
+
455
+ const FancyTextInput = createComponent(TextInput)({
456
+ displayName: 'FancyTextInput',
457
+ Component((props) => <TextInput {...props} />)
458
+ })
459
+ ```
460
+
461
+ Components that made this change:
462
+
463
+ - Button
464
+ - IconButton
465
+ - Card
466
+ - Hyperlink
467
+ - Select
468
+ - TextArea
469
+ - TextInput
470
+ - Checkbox
471
+ - Radio
472
+ - ColorInput
473
+ - ColorPreview
474
+ - Modal
475
+ - Popup
476
+ - Skeleton
477
+ - Tabs
478
+ - Toast
479
+
426
480
  ## Component Changes
427
481
 
428
482
  ### Component Promotions
@@ -799,20 +853,25 @@ Button prop interface and accesses properties like `onClick`, you'll need to pro
799
853
  attribute yourself in order to avoid TypeScript issues (this doesn't affect runtime). This is not
800
854
  code-moddable since intent cannot be pre-determined.
801
855
 
856
+ #### Props
857
+
858
+ The exported props no longer extend from the `HTMLButtonElement` interface. Use
859
+ [ExtractProps](#prop-interfaces) instead.
860
+
802
861
  ```tsx
803
862
  interface MyButtonProps extends ButtonProps {}
804
863
 
805
864
  // onClick no longer exists in `ButtonProps`, so TypeScript will complain about onClick not
806
865
  // existing in `MyButtonProps` (`onClick` does exist as a prop on `<Button>`, however)
807
866
  const MyButton = ({children, onClick}: MyButtonProps) => (
808
- <Button onClick={onClick}>{children}</Button>
867
+ <SecondaryButton onClick={onClick}>{children}</SecondaryButton>
809
868
  );
810
869
 
811
870
  // After
812
- interface MyButtonProps extends ButtonProps, React.ButtonHTMLAttributes<HTMLButtonElement> {}
871
+ interface MyButtonProps extends ExtractProps<typeof SecondaryButton> {}
813
872
 
814
873
  // After (alternate fix)
815
- interface MyButtonProps extends ButtonProps {
874
+ interface MyButtonProps extends ExtractProps<> {
816
875
  onClick?: React.MouseEventHandler<HTMLButtonElement>;
817
876
  }
818
877
  ```
@@ -881,6 +940,21 @@ const props = {
881
940
  import {Card} from './Card' // where `Card` is a re-exported Canvas Kit `Card`
882
941
  ```
883
942
 
943
+ #### Props
944
+
945
+ The exported props no longer extend from the `HTMLDivElement` interface. Use
946
+ [ExtractProps](#prop-interfaces) instead.
947
+
948
+ ```tsx
949
+ // NOT handled by the codemod
950
+
951
+ // v4
952
+ interface MyCard extends CardProps {}
953
+
954
+ // v5
955
+ interface MyCard extends ExtractProps<typeof Card>
956
+ ```
957
+
884
958
  ---
885
959
 
886
960
  ### Inputs
@@ -924,14 +998,14 @@ element that `inputRef` was applied to previously. Select and Select (Preview) d
924
998
  `inputRef` in v4, but now support `ref` in v5. See each component's documentation for information on
925
999
  which element `ref` is forwarded to for that particular component.
926
1000
 
1001
+ #### Props
1002
+
927
1003
  Input component prop interfaces no longer extend directly from their underlying element interface
928
1004
  (e.g. `TextInputProps` no longer extends from `React.InputHTMLAttributes<HTMLInputElement>`).
929
1005
  `createComponent` returns a component that determines the element interface via the `as` prop. This
930
1006
  is why input component props no longer contain an element interface directly. If you extend from an
931
1007
  input component prop interface, or have code that uses an input component prop interface and
932
- accesses properties like `onClick`, you'll need to provide the input attribute yourself in order to
933
- avoid TypeScript issues (this doesn't affect runtime). This is not code-moddable since intent cannot
934
- be pre-determined.
1008
+ accesses properties like `onClick`, you'll need to use [ExtractProps](#prop-interfaces) instead.
935
1009
 
936
1010
  ```tsx
937
1011
  interface MyTextInputProps extends TextInputProps {}
@@ -941,7 +1015,7 @@ interface MyTextInputProps extends TextInputProps {}
941
1015
  const MyTextInput = ({onClick}: MyTextInputProps) => <TextInput onClick={onClick} />;
942
1016
 
943
1017
  // Fix
944
- interface MyTextInputProps extends TextInputProps, React.InputHTMLAttributes<HTMLInputElement> {}
1018
+ interface MyTextInputProps extends ExtractProps<typeof TextInput> {}
945
1019
 
946
1020
  // Alternate fix
947
1021
  interface MyTextInputProps extends TextInputProps {
@@ -0,0 +1,8 @@
1
+ import Basic from './examples/CookieBanner';
2
+
3
+
4
+ # Canvas Kit Examples
5
+
6
+ ## CookieBanner
7
+
8
+ <ExampleCodeBlock code={Basic} />
@@ -0,0 +1,97 @@
1
+ import * as React from 'react';
2
+
3
+ import {createComponent, styled, StyledType} from '@workday/canvas-kit-react/common';
4
+ import {colors, commonColors, depth, type, space} from '@workday/canvas-kit-react/tokens';
5
+ import {PrimaryButton, TertiaryButton} from '@workday/canvas-kit-react/button';
6
+
7
+ const CookieBannerItem = createComponent('div')({
8
+ displayName: 'CookieBanner.Item',
9
+ Component: ({isRow, ...elProps}: ItemProps, ref) => (
10
+ <BannerItem ref={ref} isRow={isRow} {...elProps} />
11
+ ),
12
+ });
13
+
14
+ const CookieBanner = createComponent('div')({
15
+ displayName: 'CookieBanner',
16
+ Component: (props: BannerProps, ref, Element) => <Banner ref={ref} as={Element} {...props} />,
17
+ subComponents: {Item: CookieBannerItem},
18
+ });
19
+
20
+ export default () => {
21
+ const DefaultNotice = `We use cookies to ensure that we give you the best experience on our website.
22
+ If you continue without changing your settings, we'll assume that you are willing to receive cookies.`;
23
+
24
+ return (
25
+ <ExampleContainer>
26
+ <CookieBanner isClosed={false}>
27
+ <CookieBanner.Item>{DefaultNotice}</CookieBanner.Item>
28
+ <CookieBanner.Item isRow>
29
+ <TertiaryButton>Settings</TertiaryButton>
30
+ <PrimaryButton>Continue</PrimaryButton>
31
+ </CookieBanner.Item>
32
+ </CookieBanner>
33
+ </ExampleContainer>
34
+ );
35
+ };
36
+
37
+ interface BannerProps {
38
+ isClosed?: boolean;
39
+ }
40
+
41
+ interface ItemProps {
42
+ isRow?: boolean;
43
+ }
44
+
45
+ const ExampleContainer = styled('div')({
46
+ minHeight: 84,
47
+ margin: space.xs,
48
+ position: 'relative',
49
+ });
50
+
51
+ const Banner = styled('div')<BannerProps & StyledType>(
52
+ type.levels.subtext.medium,
53
+ {
54
+ backgroundColor: commonColors.background,
55
+ borderTop: `1px solid ${colors.soap400}`,
56
+ display: 'flex',
57
+ ...depth[1],
58
+ padding: space.m,
59
+ alignItems: 'center',
60
+ justifyContent: 'space-between',
61
+ position: 'absolute',
62
+ bottom: 0,
63
+ left: 0,
64
+ right: 0,
65
+ zIndex: 99,
66
+ transition: 'transform 0.2s ease-out',
67
+ '@media (max-width: 450px)': {
68
+ flexDirection: 'column',
69
+ alignItems: 'stretch',
70
+ textAlign: 'center',
71
+ padding: `${space.s} 0`,
72
+ },
73
+ },
74
+ ({isClosed}) => isClosed && {transform: 'translateY(100%)'}
75
+ );
76
+
77
+ const BannerItem = styled('div')<ItemProps & StyledType>(
78
+ {
79
+ marginLeft: space.s,
80
+ marginRight: space.s,
81
+ '@media (max-width: 450px)': {
82
+ '&:not(:first-of-type)': {
83
+ marginTop: space.s,
84
+ '> *': {
85
+ flex: 1,
86
+ },
87
+ },
88
+ },
89
+ },
90
+ ({isRow}) =>
91
+ isRow && {
92
+ display: 'flex',
93
+ '> *': {
94
+ marginLeft: space.s,
95
+ },
96
+ }
97
+ );
@@ -4,17 +4,28 @@ import {space} from '@workday/canvas-kit-react/tokens';
4
4
  import {Tabs, useTabsModel, TabsModel} from '@workday/canvas-kit-react/tabs';
5
5
  import {SelectionModel} from '../../lib/selection';
6
6
 
7
+ type Tab = {
8
+ tab: string;
9
+ id: string;
10
+ };
11
+
7
12
  export default () => {
8
- const [tabs, setTabs] = React.useState([
13
+ const [tabs, setTabs] = React.useState<Tab[]>([
9
14
  {tab: 'Tab 1', id: 'tab-1'},
10
15
  {tab: 'Tab 2', id: 'tab-2'},
11
16
  {tab: 'Tab 3', id: 'tab-3'},
17
+ {tab: 'Add Tab', id: 'add'},
12
18
  ]);
13
- const addedRef = React.useRef(tabs.length);
19
+ const addedRef = React.useRef(tabs.length - 1);
14
20
  const model = useTabsModel({
15
- shouldSelect: ({data}) => data.id !== 'last',
21
+ items: tabs,
22
+ shouldSelect: ({data}) => data.id !== 'add',
16
23
  });
17
24
 
25
+ // A ref of the model for the render functions to work around the caching done to lists
26
+ const modelRef = React.useRef(model);
27
+ modelRef.current = model;
28
+
18
29
  /**
19
30
  * Helper function that should be called when an item is programmatically removed. The following
20
31
  * side effects depend on state of the model:
@@ -22,8 +33,9 @@ export default () => {
22
33
  * * **Item is selected**: Selection will be moved to the next item in the list
23
34
  * @param id The id of the item that will be removed
24
35
  */
25
- const removeItem = (id: string, model: SelectionModel) => {
36
+ const removeItem = <T extends unknown>(id: string, model: SelectionModel<T>) => {
26
37
  const index = model.state.items.findIndex(item => model.getId(item) === model.state.cursorId);
38
+ console.log('index', index, id, model.state.cursorId, model.state.items);
27
39
  const nextIndex = index === model.state.items.length - 1 ? index - 1 : index + 1;
28
40
  const nextId = model.getId(model.state.items[nextIndex]);
29
41
  if (model.state.selectedIds[0] === id) {
@@ -41,48 +53,52 @@ export default () => {
41
53
  }
42
54
  };
43
55
 
44
- const onKeyDown = (e: React.KeyboardEvent<HTMLElement>, id: string) => {
45
- if (e.key === 'Delete') {
56
+ const onKeyDown = (id: string) => (e: React.KeyboardEvent<HTMLElement>) => {
57
+ if (e.key === 'Delete' && id !== 'add') {
46
58
  setTabs(tabs.filter(item => item.id !== id));
59
+ const model = modelRef.current;
47
60
  removeItem(id, model);
48
61
  }
49
62
  };
50
63
 
64
+ const onClick = (id: string) => (e: React.MouseEvent) => {
65
+ if (id === 'add') {
66
+ addedRef.current += 1;
67
+ setTabs(tabs => {
68
+ const newTabs = tabs.slice(0, tabs.length - 1);
69
+ const addTab = tabs.slice(-1);
70
+ return newTabs.concat(
71
+ {tab: `Tab ${addedRef.current}`, id: `tab-${addedRef.current}`},
72
+ addTab
73
+ );
74
+ });
75
+ model.events.goTo({id: 'add'});
76
+ }
77
+ };
78
+
51
79
  return (
52
80
  <Tabs model={model}>
53
- <Tabs.List>
54
- {tabs.map((item, index) => (
55
- <Tabs.Item
56
- key={item.id}
57
- name={item.id}
58
- index={index}
59
- onKeyDown={e => onKeyDown(e, item.id)}
60
- >
81
+ <Tabs.List overflowButton={<Tabs.OverflowButton>More</Tabs.OverflowButton>}>
82
+ {(item: Tab) => (
83
+ <Tabs.Item name={item.id} onKeyDown={onKeyDown(item.id)} onClick={onClick(item.id)}>
61
84
  {item.tab}
62
85
  </Tabs.Item>
63
- ))}
64
- <Tabs.Item
65
- key={'last'}
66
- index={tabs.length}
67
- name={'last'}
68
- onClick={() => {
69
- addedRef.current += 1;
70
- setTabs(tabs =>
71
- tabs.concat({tab: `Tab ${addedRef.current}`, id: `tab-${addedRef.current}`})
72
- );
73
- model.events.goTo({id: 'last'});
74
- }}
75
- >
76
- Add Tab
77
- </Tabs.Item>
86
+ )}
78
87
  </Tabs.List>
79
- <div style={{marginTop: space.m}}>
80
- {tabs.map((item, index) => (
81
- <Tabs.Panel key={item.id} name={item.id}>
88
+ <Tabs.Menu.Popper>
89
+ <Tabs.Menu.Card maxWidth={300} maxHeight={200}>
90
+ <Tabs.Menu.List>
91
+ {(item: Tab) => <Tabs.Menu.Item name={item.id}>{item.tab}</Tabs.Menu.Item>}
92
+ </Tabs.Menu.List>
93
+ </Tabs.Menu.Card>
94
+ </Tabs.Menu.Popper>
95
+ <Tabs.Panels>
96
+ {(item: Tab) => (
97
+ <Tabs.Panel marginTop="m" name={item.id}>
82
98
  Contents of {item.tab}
83
99
  </Tabs.Panel>
84
- ))}
85
- </div>
100
+ )}
101
+ </Tabs.Panels>
86
102
  </Tabs>
87
103
  );
88
104
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workday/canvas-kit-docs",
3
- "version": "6.1.1",
3
+ "version": "6.1.5",
4
4
  "description": "Documentation components of Canvas Kit components",
5
5
  "author": "Workday, Inc. (https://www.workday.com)",
6
6
  "license": "Apache-2.0",
@@ -50,7 +50,7 @@
50
50
  ],
51
51
  "dependencies": {
52
52
  "@storybook/csf": "0.0.1",
53
- "@workday/canvas-kit-react": "^6.1.1"
53
+ "@workday/canvas-kit-react": "^6.1.5"
54
54
  },
55
55
  "devDependencies": {
56
56
  "fs-extra": "^10.0.0",
@@ -58,5 +58,5 @@
58
58
  "mkdirp": "^1.0.3",
59
59
  "typescript": "^3.8.3"
60
60
  },
61
- "gitHead": "265ecd66ee2244f8f6be4b6ac87bf56af815fcac"
61
+ "gitHead": "33b9994408c63b78923a201af73d8c2e6f7e5914"
62
62
  }