@workday/canvas-kit-docs 5.3.17 → 5.4.0-next.1

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 (78) hide show
  1. package/dist/commonjs/lib/specs.js +429 -19
  2. package/dist/es6/lib/specs.js +429 -19
  3. package/dist/mdx/6.0-MIGRATION-GUIDE.mdx +567 -0
  4. package/dist/mdx/COMPOUND_COMPONENTS.mdx +31 -30
  5. package/dist/mdx/TESTING.mdx +30 -6
  6. package/dist/mdx/changelog.stories.mdx +0 -1
  7. package/dist/mdx/labs-react/layout/Stack.mdx +7 -2
  8. package/dist/mdx/labs-react/search-form/SearchForm.mdx +62 -0
  9. package/dist/mdx/labs-react/search-form/examples/Basic.tsx +61 -0
  10. package/dist/mdx/labs-react/search-form/examples/CustomTheme.tsx +72 -0
  11. package/dist/mdx/labs-react/search-form/examples/Grow.tsx +62 -0
  12. package/dist/mdx/labs-react/search-form/examples/PropTables.splitProps.tsx +4 -0
  13. package/dist/mdx/labs-react/search-form/examples/RTL.tsx +70 -0
  14. package/dist/mdx/labs-react/search-form/examples/Theming.tsx +64 -0
  15. package/dist/mdx/preview-react/_examples/SelectWithFormik.mdx +8 -0
  16. package/dist/mdx/preview-react/_examples/TextInputWithFormik.mdx +8 -0
  17. package/dist/mdx/preview-react/_examples/examples/SelectWithFormik.tsx +47 -0
  18. package/dist/mdx/preview-react/_examples/examples/TextInputWithFormik.tsx +105 -0
  19. package/dist/mdx/preview-react/form-field/FormField.mdx +39 -0
  20. package/dist/mdx/preview-react/form-field/examples/Custom.tsx +57 -0
  21. package/dist/mdx/preview-react/form-field/examples/Select.tsx +50 -0
  22. package/dist/mdx/preview-react/side-panel/examples/AlwaysOpen.tsx +1 -1
  23. package/dist/mdx/preview-react/side-panel/examples/Basic.tsx +1 -1
  24. package/dist/mdx/preview-react/side-panel/examples/ExternalControl.tsx +1 -1
  25. package/dist/mdx/preview-react/side-panel/examples/RightOrigin.tsx +1 -1
  26. package/dist/mdx/preview-react/side-panel/examples/Variant.tsx +1 -1
  27. package/dist/mdx/preview-react/text-area/TextArea.mdx +122 -0
  28. package/dist/mdx/preview-react/text-area/examples/Alert.tsx +36 -0
  29. package/dist/mdx/preview-react/text-area/examples/Basic.tsx +17 -0
  30. package/dist/mdx/preview-react/text-area/examples/Disabled.tsx +17 -0
  31. package/dist/mdx/preview-react/text-area/examples/Error.tsx +40 -0
  32. package/dist/mdx/preview-react/text-area/examples/Grow.tsx +17 -0
  33. package/dist/mdx/preview-react/text-area/examples/HiddenLabel.tsx +20 -0
  34. package/dist/mdx/preview-react/text-area/examples/LabelPositionHorizontal.tsx +17 -0
  35. package/dist/mdx/preview-react/text-area/examples/LabelPositionVertical.tsx +17 -0
  36. package/dist/mdx/preview-react/text-area/examples/Placeholder.tsx +17 -0
  37. package/dist/mdx/preview-react/text-area/examples/RefForwarding.tsx +28 -0
  38. package/dist/mdx/preview-react/text-area/examples/Required.tsx +17 -0
  39. package/dist/mdx/preview-react/text-area/examples/ResizeConstraints.tsx +22 -0
  40. package/dist/mdx/preview-react/text-input/TextInput.mdx +138 -0
  41. package/dist/mdx/preview-react/text-input/examples/Alert.tsx +35 -0
  42. package/dist/mdx/preview-react/text-input/examples/Basic.tsx +17 -0
  43. package/dist/mdx/preview-react/text-input/examples/Disabled.tsx +17 -0
  44. package/dist/mdx/preview-react/text-input/examples/Error.tsx +40 -0
  45. package/dist/mdx/preview-react/text-input/examples/Grow.tsx +17 -0
  46. package/dist/mdx/preview-react/text-input/examples/HiddenLabel.tsx +20 -0
  47. package/dist/mdx/preview-react/text-input/examples/LabelPositionHorizontal.tsx +17 -0
  48. package/dist/mdx/preview-react/text-input/examples/LabelPositionVertical.tsx +17 -0
  49. package/dist/mdx/preview-react/text-input/examples/Password.tsx +17 -0
  50. package/dist/mdx/preview-react/text-input/examples/Placeholder.tsx +17 -0
  51. package/dist/mdx/preview-react/text-input/examples/RefForwarding.tsx +28 -0
  52. package/dist/mdx/preview-react/text-input/examples/Required.tsx +17 -0
  53. package/dist/mdx/preview-react/text-input/examples/ThemedAlert.tsx +46 -0
  54. package/dist/mdx/preview-react/text-input/examples/ThemedError.tsx +35 -0
  55. package/dist/mdx/react/_examples/CookieBanner.mdx +8 -0
  56. package/dist/mdx/react/_examples/GlobalHeader.mdx +12 -0
  57. package/dist/mdx/react/_examples/PageHeader.mdx +8 -0
  58. package/dist/mdx/react/_examples/examples/CookieBanner.tsx +97 -0
  59. package/dist/mdx/react/_examples/examples/GlobalHeader.tsx +66 -0
  60. package/dist/mdx/react/_examples/examples/PageHeader.tsx +63 -0
  61. package/dist/mdx/react/button/button/Button.mdx +26 -2
  62. package/dist/mdx/react/button/button/examples/Primary.tsx +10 -1
  63. package/dist/mdx/react/button/button/examples/PrimaryInverse.tsx +14 -0
  64. package/dist/mdx/react/button/button/examples/Secondary.tsx +10 -1
  65. package/dist/mdx/react/button/button/examples/SecondaryInverse.tsx +14 -0
  66. package/dist/mdx/react/button/button/examples/Tertiary.tsx +13 -1
  67. package/dist/mdx/react/button/button/examples/TertiaryInverse.tsx +14 -0
  68. package/dist/mdx/react/popup/examples/FocusRedirect.tsx +2 -1
  69. package/dist/mdx/react/tabs/Tabs.mdx +31 -5
  70. package/dist/mdx/react/tabs/examples/DisabledTab.tsx +1 -1
  71. package/dist/mdx/react/tabs/examples/DynamicTabs.tsx +82 -38
  72. package/dist/mdx/react/tabs/examples/HoistedModel.tsx +4 -4
  73. package/dist/mdx/react/tabs/examples/Icons.tsx +36 -0
  74. package/dist/mdx/react/tabs/examples/{NamedKeys.tsx → NamedTabs.tsx} +0 -0
  75. package/dist/mdx/react/tabs/examples/OverflowTabs.tsx +58 -0
  76. package/dist/mdx/react/tabs/examples/SinglePanel.tsx +1 -1
  77. package/dist/mdx/react/text-area/TextArea.mdx +1 -1
  78. package/package.json +3 -3
@@ -78,8 +78,8 @@ const Tabs = ({children, model, ...config}) => {
78
78
 
79
79
  ## Subcomponents
80
80
 
81
- A subcomponent typically follows ARIA roles. For the `Tabs` example, these are the `tablist`,
82
- `tab`, and `tabpanel` roles. A subcomponent provides direct access to semantic or key elements of a
81
+ A subcomponent typically follows ARIA roles. For the `Tabs` example, these are the `tablist`, `tab`,
82
+ and `tabpanel` roles. A subcomponent provides direct access to semantic or key elements of a
83
83
  compound component. In the `IconButton` example, the icon is not semantic and might be hidden from
84
84
  screen readers while the `IconButton.Text` content is instead used for a tooltip and as the
85
85
  accessible name while being visibly hidden.
@@ -175,35 +175,35 @@ Components that directly wrap an element (most of them) will have the following
175
175
 
176
176
  Compound components are also made up of [models](#models) that accept [guards](#guards) to
177
177
  conditionally prevent state changes and [callbacks](#callbacks) to attach listeners. For example, in
178
- our Tabs component clicking a Tab will activate that tab. The `Tabs` container component will accept
179
- a `shouldActivate` and a `onActivate` for the event called `activate`.
178
+ our Tabs component clicking a Tab will select that tab. The `Tabs` container component will accept a
179
+ `shouldSelect` and a `onSelect` for the event called `select`.
180
180
 
181
181
  ```tsx
182
182
  const MyComponent = () => {
183
- // `data` is all event data from the `activate` event
183
+ // `data` is all event data from the `select` event
184
184
 
185
185
  // `state` is the current state of the `Tabs` component
186
- const shouldActivate = ({data, state}) => {
187
- // for some reason, we only want to allow activation the 'first' tab
188
- // Clicking on the first tab will activate it, but clicking on the
186
+ const shouldSelect = ({data, state}) => {
187
+ // for some reason, we only want to allow selection the 'first' tab
188
+ // Clicking on the first tab will select it, but clicking on the
189
189
  // second tab will do nothing
190
190
  return data.tab === 'first' ? true : false;
191
191
 
192
192
  // returning true allows the event to trigger a state change and will
193
- // also call the `onActivate` callback
193
+ // also call the `onSelect` callback
194
194
  };
195
195
 
196
196
  // `prevState` is the previous state of the model. Callbacks are called _before_ state has resolved.
197
197
  // This means the passed state hasn't updated yet. It also means it is safe to call `setState` without
198
198
  // triggering extra renders. `setState` calls will add to React's batching system before a state changes
199
199
  // are flushed and render functions are called.
200
- const onActivate = ({data, prevState}) => {
201
- // called any time the `activate` event is triggered
202
- console.log('onActivate', data, prevState);
200
+ const onSelect = ({data, prevState}) => {
201
+ // called any time the `select` event is triggered
202
+ console.log('onSelect', data, prevState);
203
203
  };
204
204
 
205
205
  return (
206
- <Tabs shouldActivate={shouldActivate} onActivate={onActivate}>
206
+ <Tabs shouldSelect={shouldSelect} onSelect={onSelect}>
207
207
  <Tabs.List>
208
208
  <Tabs.Item name="first">First</Tabs.Item>
209
209
  <Tabs.Item name="second">Second</Tabs.Item>
@@ -324,20 +324,20 @@ const useEllipsisTooltipModel = (config = {}) => {
324
324
 
325
325
  Models are meant to be composable. For example, a `TabsModel` uses a `CursorModel` (which itself
326
326
  uses `ListModel`) and a `ListModel` for a list of panels. `TabsModel` also keeps track of which tab
327
- is currently active. This might look like the following:
327
+ is currently selected. This might look like the following:
328
328
 
329
329
  ```ts
330
330
  const useTabsModel = (config = {}) => {
331
331
  // id is used for ARIA attributes
332
332
  const id = useUniqueId(config.id);
333
- const [activeTab, setActiveTab] = React.useState('');
333
+ const [selectedTab, setSelectedTab] = React.useState('');
334
334
  const cursor = useCursorModel(config);
335
335
  const panels = useListModel(config);
336
336
 
337
337
  const state = {
338
338
  ...cursor.state, // extend the CursorModel state
339
339
  id,
340
- activeTab,
340
+ selectedTab,
341
341
  panels: panels.state.items, // we only care about
342
342
  };
343
343
 
@@ -346,12 +346,12 @@ const useTabsModel = (config = {}) => {
346
346
  registerPanel: panels.events.registerItem,
347
347
  unregisterPanel: panels.events.unregisterItem,
348
348
 
349
- activate(data) {
350
- if (config.shouldActivate?.({data, prevState: state}) === false) {
349
+ select(data) {
350
+ if (config.shouldSelect?.({data, prevState: state}) === false) {
351
351
  return;
352
352
  }
353
- setActiveTab(data.tab);
354
- config.onActivate?.({data, prevState: state});
353
+ setSelectedTab(data.tab);
354
+ config.onSelect?.({data, prevState: state});
355
355
  },
356
356
  };
357
357
 
@@ -362,10 +362,11 @@ const useTabsModel = (config = {}) => {
362
362
  Model composition allows for components to share functionality with other components. In the Tabs
363
363
  example, `ListModel` is in charge of maintaining a list of tab elements. The `CursorModel` is in
364
364
  charge of maintaining a current cursor position of the tab list. The `Tabs.List` component uses the
365
- cursor to allow keyboard navigation of the tabs. The `TabsModel` also maintains the currently active
366
- tab to ensure the correct `TabPanel` is visible. The `TabsModel` is also using a `ListModel` to
367
- maintain a list of tab panels. The `TabsModel` is in charge of composing all this and providing data
368
- and events to the `Tabs` compound component - coordination state between subcomponents.
365
+ cursor to allow keyboard navigation of the tabs. The `TabsModel` also maintains the currently
366
+ selected tab to ensure the correct `TabPanel` is visible. The `TabsModel` is also using a
367
+ `ListModel` to maintain a list of tab panels. The `TabsModel` is in charge of composing all this and
368
+ providing data and events to the `Tabs` compound component - coordination state between
369
+ subcomponents.
369
370
 
370
371
  Many other components like `Select`, `Breadcrumbs`, or dropdown menus can also use the `ListModel`
371
372
  and/or the `CursorModel`. These models could be thought of as abstract models where they do not
@@ -463,11 +464,11 @@ const TabList = ({children, ...elemProps}) => {
463
464
 
464
465
  A container component can either accept model configuration _or_ a model. Passing model
465
466
  configuration allows for simpler model configuration of guards, callbacks, or any other model
466
- configuration. The following example provides an `onActivate` callback that fetches some data from
467
- the server:
467
+ configuration. The following example provides an `onSelect` callback that fetches some data from the
468
+ server:
468
469
 
469
470
  ```tsx
470
- <Tabs onActivate={({data}) => fetch('/api/activate' + data.id)}>...</Tabs>
471
+ <Tabs onSelect={({data}) => fetch('/api/selectTab' + data.id)}>...</Tabs>
471
472
  ```
472
473
 
473
474
  If you need direct access to a model's state or events, you can hoist the model into your component
@@ -479,15 +480,15 @@ look like this:
479
480
  const MyTabs = () => {
480
481
  const model = useTabsModel({
481
482
  // we can still load data from the server
482
- onActivate: ({data}) => fetch('/api/activate' + data.id),
483
+ onSelect: ({data}) => fetch('/api/selectTab' + data.id),
483
484
  });
484
485
 
485
486
  return (
486
487
  <>
487
488
  <Tabs model={model}>...</Tabs>
488
- // direct access to the model's state Currently selected tab: {model.state.activeTab}
489
+ // direct access to the model's state Currently selected tab: {model.state.selectedTab}
489
490
  // Now we can send events directly to the model
490
- <button onClick={() => model.events.activate({tab: 'third'})}>Activate third tab</button>
491
+ <button onClick={() => model.events.select({tab: 'third'})}>Select third tab</button>
491
492
  </>
492
493
  );
493
494
  };
@@ -29,7 +29,7 @@ do. A "test" simply has to pass. A specification requires meaning.
29
29
  test('SomeComponent should render correctly', async () => {
30
30
  const {getByTestId} = render(<SomeComponent data-testid="test" text="foo" />);
31
31
 
32
- const component = await getByTestId('test');
32
+ const component = getByTestId('test');
33
33
 
34
34
  expect(component.textContent).toEqual('foo');
35
35
  expect(component.getAttribute('aria-label')).toEqual('foo');
@@ -53,14 +53,14 @@ describe('SomeComponent', () => {
53
53
  it('should render the "text" prop as the text', async () => {
54
54
  const {getByTestId} = render(<SomeComponent data-testid="test" text="foo" />);
55
55
 
56
- const component = await getByTestId('test');
56
+ const component = getByTestId('test');
57
57
  expect(component).toHaveTextContent('foo');
58
58
  });
59
59
 
60
60
  it('should render the "text" prop as an aria-label for accessibility', async () => {
61
61
  const {getByTestId} = render(<SomeComponent data-testid="test" text="foo" />);
62
62
 
63
- const component = await getByTestId('test');
63
+ const component = getByTestId('test');
64
64
  expect(component).toHaveAttribute('aria-label', 'foo');
65
65
  });
66
66
  });
@@ -124,8 +124,8 @@ const {getByTestId} = render(
124
124
  </SomeComponent>
125
125
  );
126
126
 
127
- const component = await getByTestId('container');
128
- const child = await getByTestId('test');
127
+ const component = getByTestId('container');
128
+ const child = getByTestId('test');
129
129
 
130
130
  expect(component).toContainElement(child);
131
131
  ```
@@ -136,9 +136,33 @@ specification is met). Also this example will have a more useful failure message
136
136
  `.toContainElement` has the context that it is expecting an element in another element vs a match of
137
137
  a string.
138
138
 
139
+ ### Snapshot tests
140
+
141
+ Canvas Kit does not contain DOM-based snapshot tests and uses [Visual Tests](#visual-tests) instead.
142
+ DOM snapshots failures are often difficult to parse. Humans tend to be better at noticing and
143
+ discerning visual changes than changes to a DOM structure.
144
+
145
+ If your project uses snapshot tests and Canvas Kit, chances are you'll run into issues with changing
146
+ ids and other ARIA attributes. Canvas Kit generates unique ids that are different every time the
147
+ page loads. This can be a problem with snapshot tests. To fix this, you'll need to add special code
148
+ to your test bootstrap file. For example:
149
+
150
+ ```ts
151
+ import {setUniqueSeed, resetUniqueIdCount} from '@workday/canvas-kit-react/common';
152
+
153
+ beforeEach(() => {
154
+ setUniqueSeed('a'); // set a static seed
155
+ resetUniqueIdCount(); // reset the id counter before every test
156
+ });
157
+ ```
158
+
159
+ This will ensure snapshot tests have stable ids for each snapshot. It is still possible to get ids
160
+ changing if you add an additional component that uses id generation - subsequent ids will be
161
+ different, but this will prevent snapshot tests that don't have any changes from showing diffs.
162
+
139
163
  ## Functional tests
140
164
 
141
- Canvas Kit uses [Cypress][https://cypress.io] for browser-based behavior testing (additional info:
165
+ Canvas Kit uses [Cypress](https://cypress.io) for browser-based behavior testing (additional info:
142
166
  [Why Cypress?](https://github.com/Workday/canvas-kit/tree/master/cypress/WHY_CYPRESS.md)).
143
167
  Functional tests ensure the code meets functional specifications from a user's perspective. All
144
168
  functional tests are written against a Storybook Story. Specifications can come from many different
@@ -1,5 +1,4 @@
1
1
  import Changelog from '../../../CHANGELOG.md';
2
2
  import Markdown from '../../../utils/storybook/Markdown.tsx';
3
3
 
4
-
5
4
  <Markdown content={Changelog} />
@@ -153,6 +153,11 @@ further to the right. You could use two separate horizontal stacks here to achie
153
153
  but you could also use `shouldWrapChildren` and then put additional margin only where needed. Either
154
154
  approach would be fine; it's a matter of personal preference.
155
155
 
156
+ > Note: `shouldWrapChildren` implicitly passes the child element's index as a unique `key` prop to
157
+ > the `Stack.Item`, which works well for static lists. If you have dynamic lists with child elements
158
+ > that change over time, you'll want to provide a unique `id` prop to each child element for the
159
+ > `Stack.Item` to use as a key instead.
160
+
156
161
  <ExampleCodeBlock code={ShouldWrapChildren} />
157
162
 
158
163
  Use this approach when:
@@ -170,8 +175,8 @@ wrapping children in `Stack.Item`s. A `Stack.Item` is a `Box` with some preset s
170
175
  overridden if needed.
171
176
 
172
177
  In the example below, we wanted to keep our `li` elements as direct children of the `ul` stack. So
173
- we're wrapping each of the links with `Stack.Item`s, casting them as `li`s and applying custom styles to each.
174
- This would not be possible with `shouldWrapChildren`.
178
+ we're wrapping each of the links with `Stack.Item`s, casting them as `li`s and applying custom
179
+ styles to each. This would not be possible with `shouldWrapChildren`.
175
180
 
176
181
  <ExampleCodeBlock code={StackItems} />
177
182
 
@@ -0,0 +1,62 @@
1
+ import {SearchForm} from '@workday/canvas-kit-labs-react/search-form';
2
+ // examples
3
+ import Basic from './examples/Basic';
4
+ import CustomTheme from './examples/CustomTheme';
5
+ import Grow from './examples/Grow';
6
+ import RTL from './examples/RTL';
7
+ import Theming from './examples/Theming';
8
+ import ThemeAttributes from './examples/PropTables.splitProps';
9
+
10
+
11
+ # Canvas Kit Search Form
12
+
13
+ `SearchForm` is a search form that contains a `Combobox` for rendering search results. It's
14
+ primarily intended to be used within a `Header`.
15
+
16
+ ## Installation
17
+
18
+ ```sh
19
+ yarn add @workday/canvas-kit-labs-react
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ### Basic Example
25
+
26
+ You will most likely use `SearchForm` within the context of a `Header` component, but it's helpful
27
+ to see its functionality as a standalone component. Below is a basic example that filters results
28
+ based on search input.
29
+
30
+ <ExampleCodeBlock code={Basic} />
31
+
32
+ ### Grow
33
+
34
+ If you'd like `SearchForm` to grow to the width of its container, set the `grow` prop to `true`.
35
+
36
+ <ExampleCodeBlock code={Grow} />
37
+
38
+ ### Theming
39
+
40
+ `SearchForm` can be themed to use one of the preset `SearchThemes`: `Light`, `Dark`, or
41
+ `Transparent`. Below is an example of `SearchForm` using the `Dark` theme.
42
+
43
+ <ExampleCodeBlock code={Theming} />
44
+
45
+ You can also provide more specific theming values by providing specific `SearchThemeAttributes`.
46
+
47
+ <ExampleCodeBlock code={CustomTheme} />
48
+
49
+ Below is a table of attributes that can be supplied to `SearchForm`:
50
+
51
+ <ArgsTable of={ThemeAttributes} />
52
+
53
+ ### RTL (Right-To-Left)
54
+
55
+ `SearchForm` provides bidirectional support out of the box. You shouldn't need to provide any
56
+ additional configuration.
57
+
58
+ <ExampleCodeBlock code={RTL} />
59
+
60
+ ## Props
61
+
62
+ <ArgsTable of={SearchForm} />
@@ -0,0 +1,61 @@
1
+ import * as React from 'react';
2
+ import {MenuItem} from '@workday/canvas-kit-preview-react/menu';
3
+ import {SearchForm} from '@workday/canvas-kit-labs-react/search-form';
4
+ import {Flex} from '@workday/canvas-kit-labs-react/layout';
5
+
6
+ const initialWineList = [
7
+ 'Beaujolais',
8
+ 'Bordeaux',
9
+ 'Cabernet Sauvignon',
10
+ 'Champagne',
11
+ 'Chardonnay',
12
+ 'Chianti',
13
+ 'Malbec',
14
+ 'Merlot',
15
+ 'Pinot Grigio',
16
+ 'Pinot Gris',
17
+ 'Pinot Noir',
18
+ 'Primitivo',
19
+ 'Prosecco',
20
+ 'Riesling',
21
+ 'Rioja',
22
+ 'Rosé',
23
+ 'Sauvignon Blanc',
24
+ 'Syrah',
25
+ 'Zinfandel',
26
+ ];
27
+
28
+ export default () => {
29
+ const [wineList, setWineList] = React.useState(initialWineList);
30
+ // Tracking the input value for onSubmit
31
+ const [searchInput, setSearchInput] = React.useState('');
32
+ const menuItems = wineList.map(wine => <MenuItem key={wine}>{wine}</MenuItem>);
33
+
34
+ const filterMenuItems = e => {
35
+ setSearchInput(e.target.value);
36
+ const formattedValue = e.target.value.toLowerCase();
37
+
38
+ // Reset the list if the input is cleared
39
+ if (!formattedValue.length) {
40
+ setWineList(initialWineList);
41
+ } else {
42
+ const filteredItems = wineList.filter(wine => wine.toLowerCase().startsWith(formattedValue));
43
+ setWineList(filteredItems);
44
+ }
45
+ };
46
+
47
+ const handleSubmit = () => {
48
+ // We don't need to prevent the default event because SearchForm handles that internally
49
+ console.log(`Searching for: ${searchInput}`);
50
+ };
51
+
52
+ return (
53
+ <Flex minHeight={200} alignItems="flex-start" padding="xs">
54
+ <SearchForm
55
+ autocompleteItems={menuItems}
56
+ onInputChange={filterMenuItems}
57
+ onSubmit={handleSubmit}
58
+ />
59
+ </Flex>
60
+ );
61
+ };
@@ -0,0 +1,72 @@
1
+ import * as React from 'react';
2
+ import {MenuItem} from '@workday/canvas-kit-preview-react/menu';
3
+ import {SearchForm, SearchThemeAttributes} from '@workday/canvas-kit-labs-react/search-form';
4
+ import {Flex} from '@workday/canvas-kit-labs-react/layout';
5
+ import {colors} from '@workday/canvas-kit-react/tokens';
6
+
7
+ const initialWineList = [
8
+ 'Beaujolais',
9
+ 'Bordeaux',
10
+ 'Cabernet Sauvignon',
11
+ 'Champagne',
12
+ 'Chardonnay',
13
+ 'Chianti',
14
+ 'Malbec',
15
+ 'Merlot',
16
+ 'Pinot Grigio',
17
+ 'Pinot Gris',
18
+ 'Pinot Noir',
19
+ 'Primitivo',
20
+ 'Prosecco',
21
+ 'Riesling',
22
+ 'Rioja',
23
+ 'Rosé',
24
+ 'Sauvignon Blanc',
25
+ 'Syrah',
26
+ 'Zinfandel',
27
+ ];
28
+
29
+ export default () => {
30
+ const [wineList, setWineList] = React.useState(initialWineList);
31
+ // Tracking the input value for onSubmit
32
+ const [searchInput, setSearchInput] = React.useState('');
33
+ const menuItems = wineList.map(wine => <MenuItem key={wine}>{wine}</MenuItem>);
34
+
35
+ const filterMenuItems = e => {
36
+ setSearchInput(e.target.value);
37
+ const formattedValue = e.target.value.toLowerCase();
38
+
39
+ // Reset the list if the input is cleared
40
+ if (!formattedValue.length) {
41
+ setWineList(initialWineList);
42
+ } else {
43
+ const filteredItems = wineList.filter(wine => wine.toLowerCase().startsWith(formattedValue));
44
+ setWineList(filteredItems);
45
+ }
46
+ };
47
+
48
+ const handleSubmit = () => {
49
+ // We don't need to prevent the default event because SearchForm handles that internally
50
+ console.log(`Searching for: ${searchInput}`);
51
+ };
52
+
53
+ const customTheme = {
54
+ background: colors.cinnamon600,
55
+ backgroundFocus: colors.frenchVanilla100,
56
+ placeholderColor: colors.frenchVanilla100,
57
+ placeholderColorFocus: colors.blackPepper400,
58
+ } as SearchThemeAttributes;
59
+
60
+ return (
61
+ <Flex minHeight={200} alignItems="flex-start">
62
+ <Flex padding="xs" backgroundColor="cinnamon500" flex={1} flexBasis="auto">
63
+ <SearchForm
64
+ searchTheme={customTheme}
65
+ autocompleteItems={menuItems}
66
+ onInputChange={filterMenuItems}
67
+ onSubmit={handleSubmit}
68
+ />
69
+ </Flex>
70
+ </Flex>
71
+ );
72
+ };
@@ -0,0 +1,62 @@
1
+ import * as React from 'react';
2
+ import {MenuItem} from '@workday/canvas-kit-preview-react/menu';
3
+ import {SearchForm} from '@workday/canvas-kit-labs-react/search-form';
4
+ import {Flex} from '@workday/canvas-kit-labs-react/layout';
5
+
6
+ const initialWineList = [
7
+ 'Beaujolais',
8
+ 'Bordeaux',
9
+ 'Cabernet Sauvignon',
10
+ 'Champagne',
11
+ 'Chardonnay',
12
+ 'Chianti',
13
+ 'Malbec',
14
+ 'Merlot',
15
+ 'Pinot Grigio',
16
+ 'Pinot Gris',
17
+ 'Pinot Noir',
18
+ 'Primitivo',
19
+ 'Prosecco',
20
+ 'Riesling',
21
+ 'Rioja',
22
+ 'Rosé',
23
+ 'Sauvignon Blanc',
24
+ 'Syrah',
25
+ 'Zinfandel',
26
+ ];
27
+
28
+ export default () => {
29
+ const [wineList, setWineList] = React.useState(initialWineList);
30
+ // Tracking the input value for onSubmit
31
+ const [searchInput, setSearchInput] = React.useState('');
32
+ const menuItems = wineList.map(wine => <MenuItem key={wine}>{wine}</MenuItem>);
33
+
34
+ const filterMenuItems = e => {
35
+ setSearchInput(e.target.value);
36
+ const formattedValue = e.target.value.toLowerCase();
37
+
38
+ // Reset the list if the input is cleared
39
+ if (!formattedValue.length) {
40
+ setWineList(initialWineList);
41
+ } else {
42
+ const filteredItems = wineList.filter(wine => wine.toLowerCase().startsWith(formattedValue));
43
+ setWineList(filteredItems);
44
+ }
45
+ };
46
+
47
+ const handleSubmit = () => {
48
+ // We don't need to prevent the default event because SearchForm handles that internally
49
+ console.log(`Searching for: ${searchInput}`);
50
+ };
51
+
52
+ return (
53
+ <Flex minHeight={200} alignItems="flex-start" padding="xs">
54
+ <SearchForm
55
+ autocompleteItems={menuItems}
56
+ grow
57
+ onInputChange={filterMenuItems}
58
+ onSubmit={handleSubmit}
59
+ />
60
+ </Flex>
61
+ );
62
+ };
@@ -0,0 +1,4 @@
1
+ import * as React from 'react';
2
+ import {SearchThemeAttributes} from '@workday/canvas-kit-labs-react/search-form';
3
+
4
+ export default (props: SearchThemeAttributes) => <div />;
@@ -0,0 +1,70 @@
1
+ import * as React from 'react';
2
+ import {MenuItem} from '@workday/canvas-kit-preview-react/menu';
3
+ import {SearchForm} from '@workday/canvas-kit-labs-react/search-form';
4
+ import {Flex} from '@workday/canvas-kit-labs-react/layout';
5
+ import {CanvasProvider, ContentDirection} from '@workday/canvas-kit-react/common';
6
+
7
+ const initialWineList = [
8
+ 'Beaujolais',
9
+ 'Bordeaux',
10
+ 'Cabernet Sauvignon',
11
+ 'Champagne',
12
+ 'Chardonnay',
13
+ 'Chianti',
14
+ 'Malbec',
15
+ 'Merlot',
16
+ 'Pinot Grigio',
17
+ 'Pinot Gris',
18
+ 'Pinot Noir',
19
+ 'Primitivo',
20
+ 'Prosecco',
21
+ 'Riesling',
22
+ 'Rioja',
23
+ 'Rosé',
24
+ 'Sauvignon Blanc',
25
+ 'Syrah',
26
+ 'Zinfandel',
27
+ ];
28
+
29
+ export default () => {
30
+ const [wineList, setWineList] = React.useState(initialWineList);
31
+ // Tracking the input value for onSubmit
32
+ const [searchInput, setSearchInput] = React.useState('');
33
+ const menuItems = wineList.map(wine => <MenuItem key={wine}>{wine}</MenuItem>);
34
+
35
+ const filterMenuItems = e => {
36
+ setSearchInput(e.target.value);
37
+ const formattedValue = e.target.value.toLowerCase();
38
+
39
+ // Reset the list if the input is cleared
40
+ if (!formattedValue.length) {
41
+ setWineList(initialWineList);
42
+ } else {
43
+ const filteredItems = wineList.filter(wine => wine.toLowerCase().startsWith(formattedValue));
44
+ setWineList(filteredItems);
45
+ }
46
+ };
47
+
48
+ const handleSubmit = () => {
49
+ // We don't need to prevent the default event because SearchForm handles that internally
50
+ console.log(`Searching for: ${searchInput}`);
51
+ };
52
+
53
+ const theme = {
54
+ canvas: {
55
+ direction: ContentDirection.RTL,
56
+ },
57
+ };
58
+
59
+ return (
60
+ <CanvasProvider theme={theme}>
61
+ <Flex minHeight={200} alignItems="flex-start" padding="xs">
62
+ <SearchForm
63
+ autocompleteItems={menuItems}
64
+ onInputChange={filterMenuItems}
65
+ onSubmit={handleSubmit}
66
+ />
67
+ </Flex>
68
+ </CanvasProvider>
69
+ );
70
+ };
@@ -0,0 +1,64 @@
1
+ import * as React from 'react';
2
+ import {MenuItem} from '@workday/canvas-kit-preview-react/menu';
3
+ import {SearchForm, SearchTheme} from '@workday/canvas-kit-labs-react/search-form';
4
+ import {Flex} from '@workday/canvas-kit-labs-react/layout';
5
+
6
+ const initialWineList = [
7
+ 'Beaujolais',
8
+ 'Bordeaux',
9
+ 'Cabernet Sauvignon',
10
+ 'Champagne',
11
+ 'Chardonnay',
12
+ 'Chianti',
13
+ 'Malbec',
14
+ 'Merlot',
15
+ 'Pinot Grigio',
16
+ 'Pinot Gris',
17
+ 'Pinot Noir',
18
+ 'Primitivo',
19
+ 'Prosecco',
20
+ 'Riesling',
21
+ 'Rioja',
22
+ 'Rosé',
23
+ 'Sauvignon Blanc',
24
+ 'Syrah',
25
+ 'Zinfandel',
26
+ ];
27
+
28
+ export default () => {
29
+ const [wineList, setWineList] = React.useState(initialWineList);
30
+ // Tracking the input value for onSubmit
31
+ const [searchInput, setSearchInput] = React.useState('');
32
+ const menuItems = wineList.map(wine => <MenuItem key={wine}>{wine}</MenuItem>);
33
+
34
+ const filterMenuItems = e => {
35
+ setSearchInput(e.target.value);
36
+ const formattedValue = e.target.value.toLowerCase();
37
+
38
+ // Reset the list if the input is cleared
39
+ if (!formattedValue.length) {
40
+ setWineList(initialWineList);
41
+ } else {
42
+ const filteredItems = wineList.filter(wine => wine.toLowerCase().startsWith(formattedValue));
43
+ setWineList(filteredItems);
44
+ }
45
+ };
46
+
47
+ const handleSubmit = () => {
48
+ // We don't need to prevent the default event because SearchForm handles that internally
49
+ console.log(`Searching for: ${searchInput}`);
50
+ };
51
+
52
+ return (
53
+ <Flex minHeight={200} alignItems="flex-start">
54
+ <Flex padding="xs" backgroundColor="blueberry500" flex={1} flexBasis="auto">
55
+ <SearchForm
56
+ searchTheme={SearchTheme.Dark}
57
+ autocompleteItems={menuItems}
58
+ onInputChange={filterMenuItems}
59
+ onSubmit={handleSubmit}
60
+ />
61
+ </Flex>
62
+ </Flex>
63
+ );
64
+ };
@@ -0,0 +1,8 @@
1
+ import SelectWithFormik from './examples/SelectWithFormik';
2
+
3
+
4
+ # Canvas Kit Examples
5
+
6
+ ## Select With Formik
7
+
8
+ <ExampleCodeBlock code={SelectWithFormik} />
@@ -0,0 +1,8 @@
1
+ import TextInputWithFormik from './examples/TextInputWithFormik';
2
+
3
+
4
+ # Canvas Kit Examples
5
+
6
+ ## Text Input With Formik
7
+
8
+ <ExampleCodeBlock code={TextInputWithFormik} />