Skip to content

Commit 6db85a4

Browse files
committed
refactor(instui-config,ui-karma-config,ui-scripts,ui-webpack-config): examples do not use a Webpack plugin
Deleted the ui-component-examples plugin, examples are parsed from a .json instead There is no special treatment for .examples.ks files in the Webpack config
1 parent dab5c81 commit 6db85a4

34 files changed

+522
-699
lines changed

packages/__docs__/buildScripts/build-docs.js

-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ const options = {
109109
'**/template-app/**',
110110
'**/template-component/**',
111111
'**/template-package/**',
112-
'**/ui-component-examples/src/**',
113112
'**/ui-test-*/src/**',
114113
'**/ui-scripts/src/**',
115114

packages/__examples__/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ node_modules/
22
__build__/
33
.babel-cache
44
*.asketch.json
5+
prop-data.json

packages/__examples__/.storybook/main.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@
2323
*/
2424

2525
module.exports = {
26-
stories: ['../stories.js']
26+
stories: ['./stories/stories.js']
2727
}

packages/__examples__/.storybook/manager.js

+24
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2015 - present Instructure, Inc.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
125
import addons from '@storybook/addons'
226
import { create } from '@storybook/theming'
327

packages/__examples__/stories.js packages/__examples__/.storybook/stories/stories.js

+31-8
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,54 @@
2323
*/
2424

2525
import { storiesOf } from '@storybook/react'
26-
2726
import { renderExample } from './renderExample.js'
2827
import { renderPage } from './renderPage.js'
28+
import generateComponentExamples from './generateComponentExamples.js'
2929
import React from 'react'
30+
// must be imported with Webpack because this file cannot contain async calls
31+
import propJSONData from '../../prop-data.json'
3032

3133
const examplesContext = require.context(
32-
'../',
34+
'../../../', // bug: This causes start:watch to recompile endlessly in SB 6.2+
3335
true,
3436
/^.*\/src\/.*\.examples\.tsx?$/,
3537
'sync'
3638
)
3739

40+
const componentsContext = require.context(
41+
'../../../', // bug: This causes start:watch to recompile endlessly in SB 6.2+
42+
true,
43+
/ui-.*\/src\/.*\/index\.tsx$/,
44+
'sync'
45+
)
46+
3847
let numStories = 0
3948
// eslint-disable-next-line no-console
4049
console.log(
41-
`Creating stories for ${examplesContext.keys().length} components...`
50+
`Creating stories for ${examplesContext.keys().length} components..`
4251
)
52+
console.log(`components: ${componentsContext.keys().length}`)
4353

4454
examplesContext.keys().map((requirePath) => {
45-
const ctx = examplesContext(requirePath)
55+
const exampleDir = requirePath.split('/').slice(0, -2).join('/')
56+
const Component = componentsContext(exampleDir + '/index.tsx').default
57+
const ExamplesModule = examplesContext(requirePath).default // xy.example.jsx
58+
const componentName = Component.displayName || Component.name
59+
const generatedPropValues = propJSONData[componentName]
60+
// merge in generated prop values:
61+
ExamplesModule.propValues = Object.assign(
62+
generatedPropValues,
63+
ExamplesModule.propValues || {}
64+
)
65+
ExamplesModule.maxExamples = ExamplesModule.maxExamples
66+
? ExamplesModule.maxExamples
67+
: 500
68+
69+
const sections = generateComponentExamples(Component, ExamplesModule)
4670

47-
if (ctx.sections && ctx.sections.length > 0) {
48-
const stories = storiesOf(ctx.componentName, module)
49-
ctx.sections.forEach(({ pages, sectionName }) => {
71+
if (sections && sections.length > 0) {
72+
const stories = storiesOf(componentName, module)
73+
sections.forEach(({ pages, sectionName }) => {
5074
pages.forEach((page, i) => {
5175
// eslint-disable-next-line no-param-reassign
5276
page.renderExample = renderExample
@@ -67,6 +91,5 @@ examplesContext.keys().map((requirePath) => {
6791
})
6892
}
6993
})
70-
7194
// eslint-disable-next-line no-console
7295
console.log(`Created ${numStories} stories!`)

packages/__examples__/.storybook/webpack.config.js

+24
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2015 - present Instructure, Inc.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
125
const React = require('react')
226
const merge = require('webpack-merge')
327

packages/__examples__/README.md

+236-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## __examples__
1+
## **examples**
22

33
Tools to work with `.examples` files for React components.
44

@@ -13,7 +13,6 @@ From the root of the `instructure-ui` repo:
1313
1. Run `yarn dev:examples`
1414
1. [http://localhost:9090](http://localhost:9090) should open automatically in your browser
1515

16-
1716
### Sketch Asset Generation
1817

1918
[Sketch](https://www.sketchapp.com/) assets for each component can be generated from the component examples that are
@@ -27,5 +26,239 @@ Then to generate the Sketch assets:
2726

2827
1. Run `yarn start:examples` to spin up the examples app on [localhost:9001](http://localhost:9001)
2928
1. Run `yarn generate:sketch` to generate a `stories.asketch.json` file.
30-
1. Once in Sketch, open the "Plugins" menu, select "From *Almost* Sketch to Sketch", and select the
29+
1. Once in Sketch, open the "Plugins" menu, select "From _Almost_ Sketch to Sketch", and select the
3130
`packages/__examples__/stories.asketch.json` file.
31+
32+
### Configuring examples
33+
34+
Given a configuration object, `generateComponentExamples` returns an array of generated examples:
35+
36+
##### Parameters
37+
38+
| Param | Type | Default | Description |
39+
| ------ | -------- | ----------- | ------------------------------------------------------------------------ |
40+
| config | `Object` | `undefined` | the generator config object. See `config` section below for more details |
41+
42+
##### Returns
43+
44+
| Type | Description |
45+
| ------- | ---------------------------------------------------------------------------------------------------------------- |
46+
| `Array` | array of examples broken into sections and pages if configured to do so. See `examples` section for more details |
47+
48+
##### Example config
49+
50+
```js
51+
export default {
52+
sectionProp: 'variant',
53+
maxExamplesPerPage: 50,
54+
maxExamples: 200,
55+
excludeProps: [],
56+
propValues: {
57+
variant: ['circular', 'rectangular'],
58+
placement: ['top', 'bottom', 'start', 'end'],
59+
children: [null, <button>hello</button>, <a href="#">world</a>]
60+
},
61+
getComponentProps: (props) => ({
62+
size: props.variant === 'circular' ? 'large' : 'small'
63+
}),
64+
getExampleProps: (props) => ({
65+
height: props.placement === 'top' ? '50rem' : '10rem'
66+
}),
67+
getParameters: ({ examples, index }) => {
68+
return { delay: 200, viewports: [320, 1200] }
69+
}
70+
}
71+
```
72+
73+
**The `config` is an object that sets the configuration for the example generation. It has the following properties:**
74+
75+
### sectionProp
76+
77+
A string value used to divide the resulting examples into sections. It should correspond to an enumerated prop in the `Component`
78+
79+
| Type | Default |
80+
| -------- | ----------- |
81+
| `string` | `undefined` |
82+
83+
### maxExamplesPerPage
84+
85+
Specifies the max number of examples that can exist in a single page within a section
86+
87+
| Type | Default |
88+
| ---------------------- | ------- |
89+
| `number` or `function` | `null` |
90+
91+
example:
92+
93+
```js
94+
// providing a number
95+
maxExamplesPerPage: 50
96+
97+
// providing a function
98+
maxExamplesPerPage: (sectionName) => (sectionName === 'inverse' ? 20 : 50)
99+
```
100+
101+
##### Parameters
102+
103+
| Param | Type | Default | Description |
104+
| ----------- | -------- | ----------- | --------------------------------------- |
105+
| sectionName | `string` | `undefined` | the name of the current example section |
106+
107+
##### Returns
108+
109+
| Type | Description |
110+
| -------- | ------------------------------------------------- |
111+
| `number` | a number specifying the maximum examples per page |
112+
113+
### maxExamples
114+
115+
Specifies the total max number of examples
116+
117+
| Type | Default |
118+
| -------- | ------- |
119+
| `number` | `500` |
120+
121+
### propValues
122+
123+
An object with keys that correspond to the component props. Each key has a corresponding
124+
value array. This array contains possible values for that prop.
125+
126+
| Type | Default |
127+
| ----------------------------------------------------------- | ----------- |
128+
| `object` of keys corresponding to arrays of possible values | `undefined` |
129+
130+
example:
131+
132+
```js
133+
propValues: {
134+
variant: ['circular', 'rectangular'],
135+
placement: ['top', 'bottom', 'start', 'end'],
136+
children: [null, <button>hello</button>, <a href="#">world</a>]
137+
}
138+
```
139+
140+
### excludeProps
141+
142+
Prop keys to exclude from `propValues`. Useful when generating `propValues` with code.
143+
144+
| Type | Default |
145+
| ------------------ | ------- |
146+
| `array of Strings` | `[]` |
147+
148+
example:
149+
150+
```js
151+
excludeProps: ['readOnly', 'disabled']
152+
```
153+
154+
### getComponentProps
155+
156+
A function called with the prop combination for the current example. It returns an object
157+
of props that will be passed into the `renderExample` function as `componentProps`.
158+
159+
| Type | Default |
160+
| ---------- | ----------- |
161+
| `function` | `undefined` |
162+
163+
example:
164+
165+
```js
166+
getComponentProps: (props) => ({
167+
// Change the size prop passed to the component based on the value of
168+
// `variant` in the current prop combination
169+
size: props.variant === 'circular' ? 'large' : 'small'
170+
})
171+
```
172+
173+
##### Parameters
174+
175+
| Param | Type | Default | Description |
176+
| ----- | -------- | ----------- | -------------------------------------------- |
177+
| props | `Object` | `undefined` | the prop combination for the current example |
178+
179+
##### Returns
180+
181+
| Type | Description |
182+
| -------- | -------------------------------------------------------------------------------------- |
183+
| `Object` | a props object that will be passed to the `renderExample` function as `componentProps` |
184+
185+
### getExampleProps
186+
187+
A function called with the prop combination for the current example. It returns an object
188+
of props that will be passed into the `renderExample` function as `exampleProps`.
189+
190+
| Type | Default |
191+
| ---------- | ----------- |
192+
| `function` | `undefined` |
193+
194+
example:
195+
196+
```js
197+
getExampleProps: (props) => ({
198+
// Change the height prop passed to the example based on the value of
199+
// `placement` in the current prop combination
200+
height: props.placement === 'top' ? '50rem' : '10rem'
201+
})
202+
```
203+
204+
##### Parameters
205+
206+
| Param | Type | Default | Description |
207+
| ----- | -------- | ----------- | -------------------------------------------- |
208+
| props | `Object` | `undefined` | the prop combination for the current example |
209+
210+
##### Returns
211+
212+
| Type | Description |
213+
| -------- | ------------------------------------------------------------------------------------ |
214+
| `Object` | a props object that will be passed to the `renderExample` function as `exampleProps` |
215+
216+
### getParameters
217+
218+
A function called with the examples and index for the current page of examples. It returns an object
219+
of parameters/meta data for that page of examples (e.g. to be passed in to a visual regression tool like chromatic).
220+
221+
| Type | Default |
222+
| ---------- | ----------- |
223+
| `function` | `undefined` |
224+
225+
example:
226+
227+
```js
228+
getParameters: ({ examples, index }) => ({
229+
// add a delay for the first page of examples only:
230+
return index === 1 ? { delay: 200 } : {}
231+
})
232+
```
233+
234+
##### Parameters
235+
236+
| Param | Type | Default | Description |
237+
| ----- | -------- | ----------- | ------------------------------------------ |
238+
| props | `Object` | `undefined` | the examples and index of the current page |
239+
240+
##### Returns
241+
242+
| Type | Description |
243+
| -------- | ---------------------------------------------------------------------------- |
244+
| `Object` | a parameters object with delay and viewport sizes configuration for the page |
245+
246+
### filter
247+
248+
A function to filter `propValues`, returns `boolean`. If it returns `true` the combination
249+
is not generated.
250+
251+
| Type | Default |
252+
| ---------- | ----------- |
253+
| `function` | `undefined` |
254+
255+
example:
256+
257+
```js
258+
filter: (props) => {
259+
return (
260+
props.type !== 'button' ||
261+
(props.textAlign === 'center' && props.display !== 'block')
262+
)
263+
}
264+
```

0 commit comments

Comments
 (0)