@workday/canvas-kit-docs 8.4.7 → 8.4.9

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.
@@ -0,0 +1,330 @@
1
+ import {Specifications} from '@workday/canvas-kit-docs';
2
+ import CreateModelHook from './examples/CreateModelHook';
3
+ import CreateContainer from './examples/CreateContainer';
4
+ import CreateSubcomponent from './examples/CreateSubcomponent';
5
+ import CreateElemPropsHook from './examples/CreateElemPropsHook';
6
+ import CreateComponent from './examples/CreateComponent';
7
+
8
+
9
+ # Compound Component Utilities
10
+
11
+ The following utilities are used to create and compose
12
+ [compound components](/getting-started/for-developers/resources/compound-components/).
13
+
14
+ ## Installation
15
+
16
+ ```sh
17
+ yarn add @workday/canvas-kit-react
18
+ ```
19
+
20
+ # createComponent
21
+
22
+ `createComponent` is a factory function that creates components to be exported. It enforces React
23
+ `ref` forwarding, `as` prop, `displayName`, `subComponents`, and handles proper typing without much
24
+ boiler plate. The return type is `Component<element, Props>` which looks like
25
+ `Component<'div', Props>` which is a clean interface that tells you the default element that is
26
+ used.
27
+
28
+ ## Usage
29
+
30
+ `createComponent` is great to use if you want to create quick compound components or you need to set
31
+ up components with `ref` forwarding.
32
+
33
+ <ExampleCodeBlock code={CreateComponent} />
34
+
35
+ # createModelHook
36
+
37
+ When building compound components that might have some internal state or events, you typically want
38
+ a model. A model allows a component to share information. This is where `createModelHook` comes in
39
+ handy.
40
+
41
+ ## Usage
42
+
43
+ `createModelHook` is a factory function that takes in `defaultConfig` and `requiredConfig` and
44
+ returns a function which is your model hook.
45
+
46
+ Let's make a simple disclosure component as an example. This is how we'd use `createModelHook`.
47
+
48
+ ```tsx
49
+ import {createModelHook} from '@workday/canvas-kit-react/common';
50
+ export const useDisclosureModel = createModelHook({
51
+ // This becomes the default values on the model
52
+ defaultConfig: {
53
+ // some default config
54
+ },
55
+ })(config => {
56
+ const state = {
57
+ // some state
58
+ };
59
+ // Sets events that can be used across subcomponents
60
+ const events = {
61
+ // some events
62
+ };
63
+
64
+ return {state, events};
65
+ });
66
+ ```
67
+
68
+ <ExampleCodeBlock code={CreateModelHook} />
69
+
70
+ Typescript will infer all config from the returned `state`, `events`, `defaultConfig` and the
71
+ `requiredConfig`.
72
+
73
+ ## API
74
+
75
+ When `useDisclosureModel`is created, five properties are attached to it for composability:
76
+ `defaultConfig`, `requiredConfig`, `TConfig`, `getElemProps`, `Context`.
77
+
78
+ ### defaultConfig
79
+
80
+ All config that has default values. Optional values also go here, but are represented as `undefined`
81
+ as part of the union type `(undefined as undefined | string)`. Using this can be useful when
82
+ creating other models that share similar config.
83
+
84
+ ```tsx
85
+ import {createModelHook} from '@workday/canvas-kit-react/common';
86
+ export const useExpandableModel = createModelHook({
87
+ defaultConfig: {
88
+ // extend the default config from the `useDisclosureModel`
89
+ ...useDisclosureModel.defaultConfig,
90
+ },
91
+ })(config => {
92
+ const disclosure = useDisclosureModel(config);
93
+ const state = {
94
+ ...disclosure.state,
95
+ };
96
+ const events = {
97
+ ...disclosure.events,
98
+ };
99
+ return {state, events};
100
+ });
101
+ ```
102
+
103
+ ### requiredConfig
104
+
105
+ All config that is required by the model. Most config should go into default config with thoughtful
106
+ defaults.
107
+
108
+ ### contextOverride
109
+
110
+ The React context used by components to share a model between a container component and
111
+ subcomponents. It is used internally by `createContainer` and `createSubcomponents` and should not
112
+ need to be referenced directly.
113
+
114
+ Each subcomponent is tied to a model hook's context. For example, `useModalModel` extends
115
+ `usePopupModel`, but `Modal` components point directly to `Popup` components. The
116
+ `contextOverride: usePopupModel.Context` forces `useModalModel`'s internal context to point to the
117
+ same context reference as the one used in `usePopupModel`. This allows the model returned by
118
+ `useModalModel` to be compatible with both `Modal` subcomponents and `Popup` subcomponents. If you
119
+ do not override context, you must create a new container and subcomponent for every component using
120
+ the newly created model hook.
121
+
122
+ ```tsx
123
+ import {createModelHook} from '@workday/canvas-kit-react/common';
124
+ export const useModalModel = createModelHook({
125
+ defaultConfig: usePopupModel.defaultConfig,
126
+ requiredConfig: usePopupModel.requiredConfig,
127
+ // share context from the usePopupModel instead of the default one created by createModelHook
128
+ contextOverride: usePopupModel.Context,
129
+ })(config => {
130
+ const model = usePopupModel(config);
131
+
132
+ useInitialFocus(model);
133
+ useReturnFocus(model);
134
+ useCloseOnOverlayClick(model);
135
+ useCloseOnEscape(model);
136
+ useFocusTrap(model);
137
+ useAssistiveHideSiblings(model);
138
+ useDisableBodyScroll(model);
139
+
140
+ return model;
141
+ });
142
+ ```
143
+
144
+ ### TConfig
145
+
146
+ TConfig gives you the typings that are defined in `defaultConfig` and `requiredConfig` instead of
147
+ having to redfine those types. This is useful when building a model that share similar config and
148
+ you want to merge them while getting the correct typings.
149
+
150
+ ```tsx
151
+ import {createModelHook} from '@workday/canvas-kit-react/common';
152
+ export const useActionBarModel = createModelHook({
153
+ defaultConfig: {
154
+ // We define the config and use the typings that come from useMenuModel for when an action bar renders a menu
155
+ menuConfig: {} as typeof useMenuModel.TConfig,
156
+ },
157
+ requiredConfig: useOverflowListModel.requiredConfig,
158
+ })(config => {
159
+ // define your internal state and events
160
+ });
161
+ ```
162
+
163
+ ### getElemProps
164
+
165
+ This function will separate all `elemProps` or default attributes from an element from the model
166
+ config props. If a prop is both a `config` _and_ an `elemProp`, you can manually apply the prop
167
+ again. `elemProps` is called internally automatically by `createContainer`. If you use
168
+ `createContainer`, you shouldn't need to use this function.
169
+
170
+ By default `createModelHook` does this for you and spreads the `elemProps` onto the component.
171
+
172
+ # createContainer and createSubcomponent
173
+
174
+ `createContainer` and `createSubcomponent` functions take a default React.ElementType which can be
175
+ an element string like div or button or a component like Button. It also takes a config object
176
+ containing the following:
177
+
178
+ - `displayName`: This will be the name of the component when shown by the React Dev tools. By
179
+ convention, we make that name be the same as typed in a render function. For example
180
+ `Disclosure.Target` vs `DisclosureTarget`.
181
+ - `modelHook`: This is the model hook used by the compound component (`useDisclosureModel` in our
182
+ case). This model hook is used to determine proper prop types and seamlessly handle the option
183
+ model prop. For `createContainer`, if a `model` is not passed, a `model` is created and added to
184
+ React Context. For `createSubcomponent`, if a `model` is not passed, the `model` comes from React
185
+ Context.
186
+ - `elemPropsHook`: This is the elemPropsHook that takes a model and elemProps and returns elemProps.
187
+
188
+ - `subComponents`: For container components. A list of sub components to add to the returned
189
+ component. For example, a sub component called `DisclosureTarget` will be added to the export of
190
+ `Disclosure` so that the user can import only `Disclosure` and use `Disclosure.Target`.
191
+ `subComponents` is needed for Typescript because static properties cannot be added to predefined
192
+ interfaces. `Disclosure.Target` = `DisclosureTarget` will caused a type error. This property
193
+ allows the createComponent factory function to infer the final interface of the returned
194
+ component.
195
+
196
+ Finally, a generic function is returned that takes the component configuration. The first argument
197
+ is `elemProps` with `ref` and hook props already merged in with props handed to the component. The
198
+ model config props will already be filtered out. We'll worry about `elemPropsHook` later. The second
199
+ is an Element property. Element is the value passed to the Component's as prop. It will default to
200
+ the provided element. The last parameter is an optional model reference. Ideally, the model is used
201
+ in `elemPropsHook` and therefore not normally needed inside the render function.
202
+
203
+ ## createContainer
204
+
205
+ When building a component that has a model, you typically start with a container component.
206
+ `createContainer` is a utility function that hooks up all the pieces for you.
207
+
208
+ ### Usage
209
+
210
+ - It will wrap your component in a context provider so that `subComponents` have access to the
211
+ model.
212
+ - It attaches your model hook to your component.
213
+ - It runs any `elemPropsHook` hooks defined.
214
+ - You can attach `subComponents`.
215
+ - It will also extract the element attributes and define the `ref` type based on the element you
216
+ give it.
217
+
218
+ ```tsx
219
+ import {createContainer} from '@workday/canvas-kit-react/common';
220
+ interface DisclosureProps {}
221
+
222
+ //... useDisclosureModel
223
+
224
+ export const Disclosure = createContainer('div')({
225
+ displayName: 'Disclosure',
226
+ modelHook: useDisclosureModel,
227
+ })<DisclosureProps>(({children, ...elemProps}, Element, model) => {
228
+ return (
229
+ // spread div attributes including ref
230
+ <Element {...elemProps}>{children}</Element>
231
+ );
232
+ });
233
+ ```
234
+
235
+ <ExampleCodeBlock code={CreateContainer} />
236
+
237
+ ## createSubcomponent
238
+
239
+ Once you've built a container component, adding a subcomponent is easy. `createSubcomponent` is
240
+ similar to `createContainer` in that it hooks up many of the pieces for you. The main difference is
241
+ it uses the context created by `createContainer`. This allows access to the model created at the
242
+ root level so that you can use any state or events at a child component level.
243
+
244
+ ### Usage
245
+
246
+ - It subscribes to the parent context allowing you access to the model hook `state` and `events`
247
+ - It attaches your model hook to your component.
248
+ - It runs any `elemPropsHook` hooks defined.
249
+ - You can attach `subComponents`.
250
+ - It will also extract the element attributes and define the `ref` type based on the element you
251
+ give it.
252
+
253
+ ```tsx
254
+ import {createSubcomponent} from '@workday/canvas-kit-react/common';
255
+ import {PrimaryButton} from '@workday/canvas-kit-react/button';
256
+ export interface DisclosureTargetProps {
257
+ /**
258
+ * The children of the `Expandable.Target`
259
+ */
260
+ children?: React.ReactNode;
261
+ }
262
+
263
+ //... useDisclosureModel
264
+
265
+ export const DisclosureTarget = createSubcomponent('button')({
266
+ modelHook: useDisclosureModel,
267
+ })<DisclosureTargetProps>(({children, ...elemProps}, Element, model) => {
268
+ return (
269
+ <PrimaryButton
270
+ as={Element}
271
+ onClick={() =>
272
+ model.state.visibility === 'hidden' ? model.events.show() : model.events.hide()
273
+ }
274
+ {...elemProps}
275
+ >
276
+ {children}
277
+ </PrimaryButton>
278
+ );
279
+ });
280
+ ```
281
+
282
+ <ExampleCodeBlock code={CreateSubcomponent} />
283
+
284
+ # createElemPropsHook
285
+
286
+ This is a utility function that is helpful to use when you have elem attributes that need to be
287
+ dyanmic based on the model hook state. This function will also handle merging of element props.
288
+
289
+ Once you create your element props hook you then attach your hook to either your `createContainer`
290
+ component or `createSubcomponent` by adding it to the `elemPropsHook` property.
291
+
292
+ ## Usage
293
+
294
+ ```tsx
295
+ import {createSubcomponent, createElemPropsHook} from '@workday/canvas-kit-react/common';
296
+ import {Box} from '@workday/canvas-kit-react/layout';
297
+
298
+ export interface DisclosureContentProps extends BoxProps {
299
+ /**
300
+ * The children of the `Expandable.Content` whose visibility is controlled by the associated
301
+ * `Expandable.Target`
302
+ */
303
+ children?: React.ReactNode;
304
+ }
305
+
306
+ //...useDisclosureModel defined
307
+
308
+ // Use createElemPropsHook to add style and id attribute based on the disclosure model hook state
309
+ // These attributes will be merged with the rest of elemProps that come from DisclosureContentProps
310
+ const useDisclosureContent = createElemPropsHook(useDisclosureModel)(({state}) => {
311
+ return {
312
+ style: state.visibility !== 'hidden' ? {} : {display: 'none'},
313
+ id: state.id,
314
+ };
315
+ });
316
+
317
+ export const DisclosureContent = createSubcomponent('div')({
318
+ modelHook: useDisclosureModel,
319
+ // attached our elemPropsHook to the component
320
+ elemPropsHook: useDisclosureContent,
321
+ })<DisclosureContentProps>(({children, ...elementProps}, Element) => {
322
+ return (
323
+ <Box as={Element} {...elementProps}>
324
+ {children}
325
+ </Box>
326
+ );
327
+ });
328
+ ```
329
+
330
+ <ExampleCodeBlock code={CreateElemPropsHook} />
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import {createComponent, ExtractProps} from '@workday/canvas-kit-react/common';
3
+ import {Box, BoxProps} from '@workday/canvas-kit-react/layout';
4
+ import {Heading} from '@workday/canvas-kit-react/text';
5
+ import {colors} from '@workday/canvas-kit-react/tokens';
6
+
7
+ // Extend Heading Props and omitting size since we've added a default
8
+ interface CardHeadingProps extends Omit<ExtractProps<typeof Heading>, 'size'> {}
9
+ export default createComponent('h2')({
10
+ displayName: 'CardHeading',
11
+ Component: ({children, ...elemProps}: CardHeadingProps, ref, Element) => {
12
+ return (
13
+ <Heading size="medium" as={Element} ref={ref} {...elemProps}>
14
+ {children}
15
+ </Heading>
16
+ );
17
+ },
18
+ });
19
+
20
+ // Extend Box Props for customization
21
+ interface CardProps extends BoxProps {}
22
+ export default createComponent('div')({
23
+ displayName: 'Card',
24
+ subComponents: {
25
+ Heading: CardHeading,
26
+ },
27
+ Component: ({children, ...elemProps}: CardProps, ref, Element) => {
28
+ return (
29
+ <Box as={Element} {...elemProps} ref={ref}>
30
+ {children}
31
+ </Box>
32
+ );
33
+ },
34
+ });
35
+
36
+ export default () => {
37
+ return (
38
+ <Card depth={2} border={`1px solid ${colors.soap400}`} padding="s" as="section">
39
+ <Card.Heading>Card Heading</Card.Heading>
40
+ </Card>
41
+ );
42
+ };
@@ -0,0 +1,75 @@
1
+ import React from 'react';
2
+ import {createContainer, createModelHook, useUniqueId} from '@workday/canvas-kit-react/common';
3
+
4
+ export type Visibility = 'hidden' | 'visible';
5
+
6
+ // First we define a model using out createModelHook
7
+ const useDisclosureModel = createModelHook({
8
+ // This becomes the default values on the model
9
+ defaultConfig: {
10
+ /** ID reference of the list. Children ids can be derived from this id */
11
+ id: '',
12
+ /**
13
+ * The initial visibility of the disclosed content
14
+ * @default 'hidden'
15
+ */
16
+ initialVisibility: 'hidden' as Visibility,
17
+ },
18
+ })(config => {
19
+ const id = useUniqueId(config.id);
20
+ const [visibility, setVisibility] = React.useState(config.initialVisibility || 'hidden');
21
+ // Set the default internal state for your model.
22
+ const state = {
23
+ /** ID reference of the list. Children ids can be derived from this id */
24
+ id,
25
+ /**
26
+ * Visibility state of the disclosed content. Models are allowed to extend the states to fit
27
+ * their needs, so if you need to consistently determine "not hidden", use `visibility !==
28
+ * 'hidden'` rather than `visibility === 'visible'`
29
+ */
30
+ visibility,
31
+ };
32
+ // Sets events that can be used across subcomponents
33
+ const events = {
34
+ /**
35
+ * Start showing the disclosed content. If a DOM event triggered this event, the event data will
36
+ * be passed along. This data can be used by guards and callbacks.
37
+ */
38
+ show(event?: Event | React.SyntheticEvent) {
39
+ setVisibility('visible');
40
+ },
41
+ /**
42
+ * Start hiding this disclosed content. If a DOM event triggered this event, the event data will
43
+ * be passed along. This data can be used by guards and callbacks.
44
+ */
45
+ hide(event?: Event | React.SyntheticEvent) {
46
+ setVisibility('hidden');
47
+ },
48
+ };
49
+
50
+ return {state, events};
51
+ });
52
+
53
+ // Disclosure Container Component
54
+ interface DisclosureProps extends React.HtmlHTMLAttributes<HTMLButtonElement> {}
55
+
56
+ const Disclosure = createContainer('button')({
57
+ displayName: 'Disclosure',
58
+ modelHook: useDisclosureModel,
59
+ subComponents: {},
60
+ })<DisclosureProps>(({children, ...elemProps}, Element, model) => {
61
+ return (
62
+ <Element
63
+ onClick={() =>
64
+ model.state.visibility === 'visible' ? model.events.hide() : model.events.show()
65
+ }
66
+ {...elemProps}
67
+ >
68
+ {model.state.visibility === 'visible' ? 'close' : 'open'}
69
+ </Element>
70
+ );
71
+ });
72
+
73
+ export default () => {
74
+ return <Disclosure />;
75
+ };
@@ -0,0 +1,131 @@
1
+ import React from 'react';
2
+ import {
3
+ createContainer,
4
+ createModelHook,
5
+ createSubcomponent,
6
+ createElemPropsHook,
7
+ useUniqueId,
8
+ } from '@workday/canvas-kit-react/common';
9
+ import {PrimaryButton, PrimaryButtonProps} from '@workday/canvas-kit-react/button';
10
+ import {Box, BoxProps} from '@workday/canvas-kit-react/layout';
11
+
12
+ type Visibility = 'hidden' | 'visible';
13
+
14
+ // First we define a model using out createModelHook
15
+ const useDisclosureModel = createModelHook({
16
+ // This becomes the default values on the model
17
+ defaultConfig: {
18
+ /** ID reference of the list. Children ids can be derived from this id */
19
+ id: '',
20
+ /**
21
+ * The initial visibility of the disclosed content
22
+ * @default 'hidden'
23
+ */
24
+ initialVisibility: 'hidden' as Visibility,
25
+ },
26
+ })(config => {
27
+ const id = useUniqueId(config.id);
28
+ const [visibility, setVisibility] = React.useState(config.initialVisibility || 'hidden');
29
+ // Set the default internal state for your model.
30
+ const state = {
31
+ /** ID reference of the list. Children ids can be derived from this id */
32
+ id,
33
+ /**
34
+ * Visibility state of the disclosed content. Models are allowed to extend the states to fit
35
+ * their needs, so if you need to consistently determine "not hidden", use `visibility !==
36
+ * 'hidden'` rather than `visibility === 'visible'`
37
+ */
38
+ visibility,
39
+ };
40
+ // Sets events that can be used across subcomponents
41
+ const events = {
42
+ /**
43
+ * Start showing the disclosed content. If a DOM event triggered this event, the event data will
44
+ * be passed along. This data can be used by guards and callbacks.
45
+ */
46
+ show(event?: Event | React.SyntheticEvent) {
47
+ setVisibility('visible');
48
+ },
49
+ /**
50
+ * Start hiding this disclosed content. If a DOM event triggered this event, the event data will
51
+ * be passed along. This data can be used by guards and callbacks.
52
+ */
53
+ hide(event?: Event | React.SyntheticEvent) {
54
+ setVisibility('hidden');
55
+ },
56
+ };
57
+
58
+ return {state, events};
59
+ });
60
+
61
+ // Disclose Target
62
+ interface DisclosureTargetProps extends PrimaryButtonProps {}
63
+
64
+ // Use createElemPropsHook to define an onClick prop using the model state and events
65
+ // This will be merged into the rest of the elemProps of the component
66
+ const useDisclosureTarget = createElemPropsHook(useDisclosureModel)(({state, events}) => {
67
+ return {
68
+ onClick: (event: React.MouseEvent) => {
69
+ if (state.visibility !== 'hidden') {
70
+ events.hide(event);
71
+ } else {
72
+ events.show(event);
73
+ }
74
+ },
75
+ };
76
+ });
77
+
78
+ const DisclosureTarget = createSubcomponent('button')({
79
+ modelHook: useDisclosureModel,
80
+ elemPropsHook: useDisclosureTarget,
81
+ })<DisclosureTargetProps>(({children, ...elemProps}, Element, model) => {
82
+ return (
83
+ <PrimaryButton as={Element} {...elemProps}>
84
+ {children}
85
+ </PrimaryButton>
86
+ );
87
+ });
88
+
89
+ // Disclosure Content
90
+ interface DisclosureContentProps extends BoxProps {}
91
+ const useDisclosureContent = createElemPropsHook(useDisclosureModel)(({state}) => {
92
+ return {
93
+ style: state.visibility !== 'hidden' ? {} : {display: 'none'},
94
+ id: state.id,
95
+ };
96
+ });
97
+
98
+ const DisclosureContent = createSubcomponent('div')({
99
+ modelHook: useDisclosureModel,
100
+ // attached our elemPropsHook to the component
101
+ elemPropsHook: useDisclosureContent,
102
+ })<DisclosureContentProps>(({children, ...elementProps}, Element) => {
103
+ return (
104
+ <Box as={Element} {...elementProps}>
105
+ {children}
106
+ </Box>
107
+ );
108
+ });
109
+
110
+ // Disclosure Container Component
111
+ interface DisclosureProps {}
112
+
113
+ const Disclosure = createContainer()({
114
+ displayName: 'Disclosure',
115
+ modelHook: useDisclosureModel,
116
+ subComponents: {
117
+ Target: DisclosureTarget,
118
+ Content: DisclosureContent,
119
+ },
120
+ })<DisclosureProps>(({children}, Element, model) => {
121
+ return <>{children}</>;
122
+ });
123
+
124
+ export default () => {
125
+ return (
126
+ <Disclosure>
127
+ <Disclosure.Target>Open</Disclosure.Target>
128
+ <Disclosure.Content>Content</Disclosure.Content>
129
+ </Disclosure>
130
+ );
131
+ };
@@ -0,0 +1,73 @@
1
+ import React from 'react';
2
+ import {createContainer, createModelHook, useUniqueId} from '@workday/canvas-kit-react/common';
3
+
4
+ export type Visibility = 'hidden' | 'visible';
5
+
6
+ // First we define a model using out createModelHook
7
+ const useDisclosureModel = createModelHook({
8
+ // This becomes the default values on the model
9
+ defaultConfig: {
10
+ /** ID reference of the list. Children ids can be derived from this id */
11
+ id: '',
12
+ /**
13
+ * The initial visibility of the disclosed content. The `as Visibility` overrides the inferred type.
14
+ */
15
+ initialVisibility: 'hidden' as Visibility,
16
+ },
17
+ })(config => {
18
+ const id = useUniqueId(config.id);
19
+ const [visibility, setVisibility] = React.useState(config.initialVisibility);
20
+ // Set the default internal state for your model.
21
+ const state = {
22
+ /** ID reference of the list. Children ids can be derived from this id */
23
+ id,
24
+ /**
25
+ * Visibility state of the disclosed content. Models are allowed to extend the states to fit
26
+ * their needs, so if you need to consistently determine "not hidden", use `visibility !==
27
+ * 'hidden'` rather than `visibility === 'visible'`
28
+ */
29
+ visibility,
30
+ };
31
+ // Sets events that can be used across subcomponents
32
+ const events = {
33
+ /**
34
+ * Start showing the disclosed content. If a DOM event triggered this event, the event data will
35
+ * be passed along. This data can be used by guards and callbacks.
36
+ */
37
+ show(event?: Event | React.SyntheticEvent) {
38
+ setVisibility('visible');
39
+ },
40
+ /**
41
+ * Start hiding this disclosed content. If a DOM event triggered this event, the event data will
42
+ * be passed along. This data can be used by guards and callbacks.
43
+ */
44
+ hide(event?: Event | React.SyntheticEvent) {
45
+ setVisibility('hidden');
46
+ },
47
+ };
48
+
49
+ return {state, events};
50
+ });
51
+
52
+ // Disclosure Container Component
53
+ interface DisclosureProps {}
54
+
55
+ const Disclosure = createContainer()({
56
+ displayName: 'Disclosure',
57
+ modelHook: useDisclosureModel,
58
+ })<DisclosureProps>(({children, ...elemProps}, Element, model) => {
59
+ return (
60
+ <button
61
+ onClick={() =>
62
+ model.state.visibility === 'visible' ? model.events.hide() : model.events.show()
63
+ }
64
+ {...elemProps}
65
+ >
66
+ {model.state.visibility === 'visible' ? 'close' : 'open'}
67
+ </button>
68
+ );
69
+ });
70
+
71
+ export default () => {
72
+ return <Disclosure />;
73
+ };
@@ -0,0 +1,101 @@
1
+ import React from 'react';
2
+ import {
3
+ createContainer,
4
+ createModelHook,
5
+ createSubcomponent,
6
+ useUniqueId,
7
+ } from '@workday/canvas-kit-react/common';
8
+ import {PrimaryButton, PrimaryButtonProps} from '@workday/canvas-kit-react/button';
9
+
10
+ export type Visibility = 'hidden' | 'visible';
11
+
12
+ // First we define a model using out createModelHook
13
+ const useDisclosureModel = createModelHook({
14
+ // This becomes the default values on the model
15
+ defaultConfig: {
16
+ /** ID reference of the list. Children ids can be derived from this id */
17
+ id: '',
18
+ /**
19
+ * The initial visibility of the disclosed content
20
+ * @default 'hidden'
21
+ */
22
+ initialVisibility: 'hidden' as Visibility,
23
+ },
24
+ })(config => {
25
+ const id = useUniqueId(config.id);
26
+ const [visibility, setVisibility] = React.useState(config.initialVisibility || 'hidden');
27
+ // Set the default internal state for your model.
28
+ const state = {
29
+ /** ID reference of the list. Children ids can be derived from this id */
30
+ id,
31
+ /**
32
+ * Visibility state of the disclosed content. Models are allowed to extend the states to fit
33
+ * their needs, so if you need to consistently determine "not hidden", use `visibility !==
34
+ * 'hidden'` rather than `visibility === 'visible'`
35
+ */
36
+ visibility,
37
+ };
38
+ // Sets events that can be used across subcomponents
39
+ const events = {
40
+ /**
41
+ * Start showing the disclosed content. If a DOM event triggered this event, the event data will
42
+ * be passed along. This data can be used by guards and callbacks.
43
+ */
44
+ show(event?: Event | React.SyntheticEvent) {
45
+ setVisibility('visible');
46
+ },
47
+ /**
48
+ * Start hiding this disclosed content. If a DOM event triggered this event, the event data will
49
+ * be passed along. This data can be used by guards and callbacks.
50
+ */
51
+ hide(event?: Event | React.SyntheticEvent) {
52
+ setVisibility('hidden');
53
+ },
54
+ };
55
+
56
+ return {state, events};
57
+ });
58
+
59
+ // Disclose Target
60
+ export interface DisclosureTargetProps extends PrimaryButtonProps {}
61
+
62
+ export default createSubcomponent('button')({
63
+ modelHook: useDisclosureModel,
64
+ })<DisclosureTargetProps>(({children, ...elemProps}, Element, model) => {
65
+ return (
66
+ <PrimaryButton
67
+ onClick={(event: React.MouseEvent) => {
68
+ if (model.state.visibility !== 'hidden') {
69
+ model.events.hide(event);
70
+ } else {
71
+ model.events.show(event);
72
+ }
73
+ }}
74
+ as={Element}
75
+ {...elemProps}
76
+ >
77
+ {model.state.visibility === 'visible' ? 'Close' : 'Open'}
78
+ </PrimaryButton>
79
+ );
80
+ });
81
+
82
+ // Disclosure Container Component
83
+ interface DisclosureProps {}
84
+
85
+ const Disclosure = createContainer()({
86
+ displayName: 'Disclosure',
87
+ modelHook: useDisclosureModel,
88
+ subComponents: {
89
+ Target: DisclosureTarget,
90
+ },
91
+ })<DisclosureProps>(({children}, Element, model) => {
92
+ return <>{children}</>;
93
+ });
94
+
95
+ export default () => {
96
+ return (
97
+ <Disclosure>
98
+ <Disclosure.Target />
99
+ </Disclosure>
100
+ );
101
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workday/canvas-kit-docs",
3
- "version": "8.4.7",
3
+ "version": "8.4.9",
4
4
  "description": "Documentation components of Canvas Kit components",
5
5
  "author": "Workday, Inc. (https://www.workday.com)",
6
6
  "license": "Apache-2.0",
@@ -42,7 +42,7 @@
42
42
  ],
43
43
  "dependencies": {
44
44
  "@storybook/csf": "0.0.1",
45
- "@workday/canvas-kit-react": "^8.4.7",
45
+ "@workday/canvas-kit-react": "^8.4.9",
46
46
  "@workday/canvas-system-icons-web": "^3.0.0"
47
47
  },
48
48
  "devDependencies": {
@@ -51,5 +51,5 @@
51
51
  "mkdirp": "^1.0.3",
52
52
  "typescript": "4.1"
53
53
  },
54
- "gitHead": "f60d81f57ac03edebfcea6337277780ebecd416a"
54
+ "gitHead": "2afa0a6e3c1bae0b94a209ed3ad9c07db25edbbf"
55
55
  }