@lumx/react 3.9.5 → 3.9.6-alpha.0
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.
- package/index.d.ts +1 -1
- package/index.js +10 -8
- package/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/button/Button.stories.tsx +257 -68
- package/src/components/button/IconButton.stories.tsx +11 -11
- package/src/components/chip/Chip.stories.tsx +74 -8
- package/src/components/date-picker/DatePicker.stories.tsx +80 -0
- package/src/components/date-picker/DatePickerControlled.test.tsx +1 -1
- package/src/components/date-picker/DatePickerControlled.tsx +17 -6
- package/src/components/navigation/Navigation.stories.tsx +209 -40
- package/src/components/navigation/NavigationSection.test.tsx +10 -11
- package/src/components/navigation/NavigationSection.tsx +2 -2
- package/src/components/side-navigation/SideNavigationItem.stories.tsx +133 -0
- package/src/stories/controls/color.ts +2 -1
- package/src/stories/controls/icons.ts +121 -2
- package/src/stories/controls/selectArgType.ts +6 -5
- package/src/stories/decorators/withCombinations.tsx +101 -70
- package/src/stories/decorators/withThemedBackground.tsx +18 -0
- package/src/stories/utils/disableArgTypes.ts +3 -0
- package/src/stories/utils/theming.tsx +164 -0
|
@@ -1,6 +1,125 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
mdiAbTesting,
|
|
3
|
+
mdiAbjadArabic,
|
|
4
|
+
mdiAccount,
|
|
5
|
+
mdiAccountBox,
|
|
6
|
+
mdiAlert,
|
|
7
|
+
mdiAlertCircle,
|
|
8
|
+
mdiArrowDown,
|
|
9
|
+
mdiArrowUp,
|
|
10
|
+
mdiAtom,
|
|
11
|
+
mdiBee,
|
|
12
|
+
mdiBell,
|
|
13
|
+
mdiBullhornOutline,
|
|
14
|
+
mdiCheck,
|
|
15
|
+
mdiCheckCircle,
|
|
16
|
+
mdiChevronDown,
|
|
17
|
+
mdiChevronLeft,
|
|
18
|
+
mdiChevronRight,
|
|
19
|
+
mdiChevronUp,
|
|
20
|
+
mdiClose,
|
|
21
|
+
mdiCloseCircle,
|
|
22
|
+
mdiDelete,
|
|
23
|
+
mdiDotsHorizontal,
|
|
24
|
+
mdiDragVertical,
|
|
25
|
+
mdiEarth,
|
|
26
|
+
mdiEmail,
|
|
27
|
+
mdiEye,
|
|
28
|
+
mdiFileEdit,
|
|
29
|
+
mdiFlag,
|
|
30
|
+
mdiFolder,
|
|
31
|
+
mdiFolderGoogleDrive,
|
|
32
|
+
mdiFoodApple,
|
|
33
|
+
mdiGoogleCirclesExtended,
|
|
34
|
+
mdiHeart,
|
|
35
|
+
mdiHome,
|
|
36
|
+
mdiImageBroken,
|
|
37
|
+
mdiInformation,
|
|
38
|
+
mdiLink,
|
|
39
|
+
mdiMagnifyMinusOutline,
|
|
40
|
+
mdiMagnifyPlusOutline,
|
|
41
|
+
mdiMenuDown,
|
|
42
|
+
mdiMessageTextOutline,
|
|
43
|
+
mdiMinus,
|
|
44
|
+
mdiOpenInNew,
|
|
45
|
+
mdiPauseCircleOutline,
|
|
46
|
+
mdiPencil,
|
|
47
|
+
mdiPlay,
|
|
48
|
+
mdiPlayCircleOutline,
|
|
49
|
+
mdiPlus,
|
|
50
|
+
mdiRadioboxBlank,
|
|
51
|
+
mdiRadioboxMarked,
|
|
52
|
+
mdiReply,
|
|
53
|
+
mdiSend,
|
|
54
|
+
mdiStar,
|
|
55
|
+
mdiTextBox,
|
|
56
|
+
mdiTextBoxPlus,
|
|
57
|
+
mdiTram,
|
|
58
|
+
mdiTranslate,
|
|
59
|
+
mdiViewList,
|
|
60
|
+
} from '@lumx/icons';
|
|
2
61
|
|
|
62
|
+
// Small selection of mdi icons to
|
|
3
63
|
export const iconArgType = {
|
|
4
64
|
control: { type: 'select' },
|
|
5
|
-
options:
|
|
65
|
+
options: {
|
|
66
|
+
mdiAbTesting,
|
|
67
|
+
mdiAbjadArabic,
|
|
68
|
+
mdiAccount,
|
|
69
|
+
mdiAccountBox,
|
|
70
|
+
mdiAlert,
|
|
71
|
+
mdiAlertCircle,
|
|
72
|
+
mdiArrowDown,
|
|
73
|
+
mdiArrowUp,
|
|
74
|
+
mdiAtom,
|
|
75
|
+
mdiBee,
|
|
76
|
+
mdiBell,
|
|
77
|
+
mdiBullhornOutline,
|
|
78
|
+
mdiCheck,
|
|
79
|
+
mdiCheckCircle,
|
|
80
|
+
mdiChevronDown,
|
|
81
|
+
mdiChevronLeft,
|
|
82
|
+
mdiChevronRight,
|
|
83
|
+
mdiChevronUp,
|
|
84
|
+
mdiClose,
|
|
85
|
+
mdiCloseCircle,
|
|
86
|
+
mdiDelete,
|
|
87
|
+
mdiDotsHorizontal,
|
|
88
|
+
mdiDragVertical,
|
|
89
|
+
mdiEarth,
|
|
90
|
+
mdiEmail,
|
|
91
|
+
mdiEye,
|
|
92
|
+
mdiFileEdit,
|
|
93
|
+
mdiFlag,
|
|
94
|
+
mdiFolder,
|
|
95
|
+
mdiFolderGoogleDrive,
|
|
96
|
+
mdiFoodApple,
|
|
97
|
+
mdiGoogleCirclesExtended,
|
|
98
|
+
mdiHeart,
|
|
99
|
+
mdiHome,
|
|
100
|
+
mdiImageBroken,
|
|
101
|
+
mdiInformation,
|
|
102
|
+
mdiLink,
|
|
103
|
+
mdiMagnifyMinusOutline,
|
|
104
|
+
mdiMagnifyPlusOutline,
|
|
105
|
+
mdiMenuDown,
|
|
106
|
+
mdiMessageTextOutline,
|
|
107
|
+
mdiMinus,
|
|
108
|
+
mdiOpenInNew,
|
|
109
|
+
mdiPauseCircleOutline,
|
|
110
|
+
mdiPencil,
|
|
111
|
+
mdiPlay,
|
|
112
|
+
mdiPlayCircleOutline,
|
|
113
|
+
mdiPlus,
|
|
114
|
+
mdiRadioboxBlank,
|
|
115
|
+
mdiRadioboxMarked,
|
|
116
|
+
mdiReply,
|
|
117
|
+
mdiSend,
|
|
118
|
+
mdiStar,
|
|
119
|
+
mdiTextBox,
|
|
120
|
+
mdiTextBoxPlus,
|
|
121
|
+
mdiTram,
|
|
122
|
+
mdiTranslate,
|
|
123
|
+
mdiViewList,
|
|
124
|
+
},
|
|
6
125
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export const getSelectArgType = <E>(
|
|
2
|
+
options: Array<E> | Record<string, E>,
|
|
3
|
+
type: 'select' | 'inline-radio' = 'inline-radio',
|
|
4
|
+
) => ({
|
|
5
|
+
control: { type },
|
|
5
6
|
options: Object.values(options),
|
|
6
|
-
mapping:
|
|
7
|
+
mapping: !Array.isArray(options) ? options : undefined,
|
|
7
8
|
});
|
|
@@ -1,22 +1,47 @@
|
|
|
1
|
-
/* eslint-disable react/display-name,jsx-a11y/control-has-associated-label */
|
|
1
|
+
/* eslint-disable react/display-name,jsx-a11y/control-has-associated-label,prefer-object-spread */
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import isEmpty from 'lodash/isEmpty';
|
|
4
|
+
import { Heading, HeadingLevelProvider } from '@lumx/react';
|
|
4
5
|
|
|
6
|
+
type PropEntry = [key: string, value: unknown];
|
|
5
7
|
type PropCombination = Record<string, Record<string, unknown>>;
|
|
6
8
|
type PropArrayCombination = { key: string; options: Array<any> };
|
|
7
9
|
type Combination = PropArrayCombination | PropCombination;
|
|
8
10
|
|
|
9
|
-
const toProps = <E,>(arr: Array<E>, prop: string) =>
|
|
10
|
-
|
|
11
|
+
const toProps = <E,>(arr: Array<E>, prop: string): PropEntry[] =>
|
|
12
|
+
arr.map((value) => [String(value), { [prop]: value }]);
|
|
11
13
|
|
|
12
14
|
const isArrayConfig = (c?: Combination): c is PropArrayCombination => !!c?.key;
|
|
13
15
|
|
|
14
|
-
function
|
|
15
|
-
if (isEmpty(config)) return
|
|
16
|
+
function toPropEntries(config?: Combination): PropEntry[] {
|
|
17
|
+
if (isEmpty(config)) return [['', {}]];
|
|
16
18
|
if (isArrayConfig(config)) return toProps(config.options, config.key);
|
|
17
|
-
return config as PropCombination;
|
|
19
|
+
return Object.entries(config as PropCombination);
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
type Options = {
|
|
23
|
+
/** Props combinations */
|
|
24
|
+
combinations: {
|
|
25
|
+
rows?: Combination;
|
|
26
|
+
cols?: Combination;
|
|
27
|
+
sections?: Combination;
|
|
28
|
+
};
|
|
29
|
+
/** Inject style on table */
|
|
30
|
+
tableStyle?: React.CSSProperties;
|
|
31
|
+
/** Inject style on first col */
|
|
32
|
+
firstColStyle?: React.CSSProperties;
|
|
33
|
+
/** Inject style on sections */
|
|
34
|
+
sectionStyle?: React.CSSProperties;
|
|
35
|
+
/** Inject style on cols */
|
|
36
|
+
colStyle?: React.CSSProperties;
|
|
37
|
+
/** Inject style on cells */
|
|
38
|
+
cellStyle?: React.CSSProperties;
|
|
39
|
+
/** Combinator function */
|
|
40
|
+
combinator?: (a: any, b: any) => any;
|
|
41
|
+
/** Exclude a combination */
|
|
42
|
+
excludeCombination?: (args: any) => boolean;
|
|
43
|
+
};
|
|
44
|
+
|
|
20
45
|
/**
|
|
21
46
|
* SB decorator generating a tables of combination of props (max 3 levels of props)
|
|
22
47
|
*/
|
|
@@ -26,76 +51,82 @@ export const withCombinations =
|
|
|
26
51
|
tableStyle,
|
|
27
52
|
firstColStyle,
|
|
28
53
|
cellStyle,
|
|
54
|
+
colStyle,
|
|
55
|
+
sectionStyle,
|
|
29
56
|
combinator = Object.assign,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
combinations: {
|
|
33
|
-
rows?: Combination;
|
|
34
|
-
cols?: Combination;
|
|
35
|
-
sections?: Combination;
|
|
36
|
-
};
|
|
37
|
-
/** Inject style on table */
|
|
38
|
-
tableStyle?: React.CSSProperties;
|
|
39
|
-
/** Inject style on first col */
|
|
40
|
-
firstColStyle?: React.CSSProperties;
|
|
41
|
-
/** Inject style on cells */
|
|
42
|
-
cellStyle?: React.CSSProperties;
|
|
43
|
-
/** Combinator function */
|
|
44
|
-
combinator?: (a: any, b: any) => any;
|
|
45
|
-
}) =>
|
|
57
|
+
excludeCombination,
|
|
58
|
+
}: Options) =>
|
|
46
59
|
(Story: any, ctx: any) => {
|
|
47
|
-
const rows =
|
|
48
|
-
const cols =
|
|
49
|
-
const sections =
|
|
60
|
+
const rows = toPropEntries(combinations.rows);
|
|
61
|
+
const cols = toPropEntries(combinations.cols);
|
|
62
|
+
const sections = toPropEntries(combinations.sections);
|
|
63
|
+
const hasRows = rows.length > 1;
|
|
64
|
+
const hasCols = cols.length > 1;
|
|
50
65
|
|
|
51
66
|
return (
|
|
52
67
|
<>
|
|
53
|
-
{
|
|
54
|
-
|
|
55
|
-
|
|
68
|
+
{sections.map(([level2Key, level2Value]) => {
|
|
69
|
+
const sectionArgs = combinator({ ...ctx.args }, level2Value);
|
|
70
|
+
const sectionCols = cols
|
|
71
|
+
.map(([level1Key, level1Value]) => {
|
|
72
|
+
const args = combinator({ ...sectionArgs }, level1Value);
|
|
73
|
+
if (excludeCombination?.(args)) return null;
|
|
74
|
+
return [level1Key, args];
|
|
75
|
+
})
|
|
76
|
+
.filter(Boolean) as Array<[string, any]>;
|
|
77
|
+
return (
|
|
78
|
+
<section key={level2Key} style={sectionStyle}>
|
|
79
|
+
<HeadingLevelProvider>
|
|
80
|
+
{level2Key && <Heading style={{ textTransform: 'capitalize' }}>{level2Key}</Heading>}
|
|
56
81
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
82
|
+
{hasRows || hasCols ? (
|
|
83
|
+
<table style={{ ...tableStyle, borderCollapse: 'separate', borderSpacing: 8 }}>
|
|
84
|
+
{combinations.cols && (
|
|
85
|
+
<thead>
|
|
86
|
+
<tr>
|
|
87
|
+
{hasRows && <th aria-hidden />}
|
|
88
|
+
{sectionCols.map(([key]) => (
|
|
89
|
+
<th key={key} style={colStyle}>
|
|
90
|
+
<small>{key}</small>
|
|
91
|
+
</th>
|
|
92
|
+
))}
|
|
93
|
+
</tr>
|
|
94
|
+
</thead>
|
|
95
|
+
)}
|
|
96
|
+
<tbody>
|
|
97
|
+
{rows.map(([level0Key, level0Value], i1) => {
|
|
98
|
+
const rowArgs = combinator({ ...sectionArgs }, level0Value);
|
|
99
|
+
if (excludeCombination?.(rowArgs)) return null;
|
|
100
|
+
return (
|
|
101
|
+
<tr key={i1}>
|
|
102
|
+
{hasRows && (
|
|
103
|
+
<th style={{ ...firstColStyle, textAlign: 'left' }}>
|
|
104
|
+
<small>{level0Key}</small>
|
|
105
|
+
</th>
|
|
106
|
+
)}
|
|
107
|
+
{cols.map(([level1Key, level1Value]) => {
|
|
108
|
+
const args = combinator({ ...rowArgs }, level1Value);
|
|
109
|
+
let render: React.ReactNode = <Story args={args} />;
|
|
110
|
+
if (excludeCombination?.(args)) render = null;
|
|
111
|
+
const textAlign = combinations.cols ? 'center' : undefined;
|
|
112
|
+
return (
|
|
113
|
+
<td key={level1Key} style={{ textAlign, ...cellStyle }}>
|
|
114
|
+
{render}
|
|
115
|
+
</td>
|
|
116
|
+
);
|
|
117
|
+
})}
|
|
118
|
+
</tr>
|
|
119
|
+
);
|
|
120
|
+
})}
|
|
121
|
+
</tbody>
|
|
122
|
+
</table>
|
|
123
|
+
) : (
|
|
124
|
+
<Story args={sectionArgs} />
|
|
125
|
+
)}
|
|
126
|
+
</HeadingLevelProvider>
|
|
127
|
+
</section>
|
|
128
|
+
);
|
|
129
|
+
})}
|
|
99
130
|
</>
|
|
100
131
|
);
|
|
101
132
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
const LIGHT_BACKGROUND_COLOR = '#EEE';
|
|
4
|
+
const DARK_BACKGROUND_COLOR = '#333';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* SB decorator adding a background adapted to the current theme.
|
|
8
|
+
*/
|
|
9
|
+
export const withThemedBackground = () => {
|
|
10
|
+
return (Story: any, { args }: any) => {
|
|
11
|
+
const backgroundColor = args.theme === 'dark' ? DARK_BACKGROUND_COLOR : LIGHT_BACKGROUND_COLOR;
|
|
12
|
+
return (
|
|
13
|
+
<div style={{ backgroundColor, padding: 8 }}>
|
|
14
|
+
<Story />
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
18
|
+
};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Predicate } from '@lumx/react/utils/type';
|
|
3
|
+
import { FlexBox } from '@lumx/react';
|
|
4
|
+
|
|
5
|
+
type Property = string | { value: string };
|
|
6
|
+
interface PropertyTree {
|
|
7
|
+
[key: string]: PropertyTree | Property;
|
|
8
|
+
}
|
|
9
|
+
type Entry = [key: string, value: string];
|
|
10
|
+
type Variables = Record<string, string>;
|
|
11
|
+
|
|
12
|
+
function asValue(prop?: PropertyTree | Property): string | undefined {
|
|
13
|
+
if (typeof prop === 'string') {
|
|
14
|
+
return prop;
|
|
15
|
+
}
|
|
16
|
+
if (typeof prop === 'object' && 'value' in prop) {
|
|
17
|
+
return prop.value as string;
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Convert property tree into a list of args entries ([key, value]) */
|
|
23
|
+
function* toArgEntries(props: PropertyTree | Property, parent = ''): Iterable<Entry> {
|
|
24
|
+
const value = asValue(props);
|
|
25
|
+
if (value) {
|
|
26
|
+
yield [parent, value];
|
|
27
|
+
} else {
|
|
28
|
+
for (const [key, prop] of Object.entries(props)) {
|
|
29
|
+
const newParent = parent ? `${parent}-${key}` : key;
|
|
30
|
+
yield* toArgEntries(prop, newParent);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function* parseVariableEntries(cssString: string, strict = false) {
|
|
35
|
+
for (const line of cssString.split(/(?<=;)/)) {
|
|
36
|
+
if (!line.trim()) continue;
|
|
37
|
+
const match = line.match(/^\s*(--lumx[^:]+)\s*:\s*([^;]+);/m);
|
|
38
|
+
if (!match) {
|
|
39
|
+
if (strict) throw new Error(`Could not parse \`${line}\``);
|
|
40
|
+
else continue;
|
|
41
|
+
}
|
|
42
|
+
const [, variableName, variableValue] = match;
|
|
43
|
+
yield [variableName, variableValue];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function VariableEditor({
|
|
48
|
+
variable: [key, value],
|
|
49
|
+
setVariable,
|
|
50
|
+
defaultStyle,
|
|
51
|
+
}: {
|
|
52
|
+
variable: Entry;
|
|
53
|
+
setVariable: (newVariable: Entry) => void;
|
|
54
|
+
defaultStyle: Variables;
|
|
55
|
+
}) {
|
|
56
|
+
const onChange = React.useCallback<React.ChangeEventHandler<HTMLInputElement>>(
|
|
57
|
+
(evt) => {
|
|
58
|
+
setVariable([evt.target.name, evt.target.value]);
|
|
59
|
+
},
|
|
60
|
+
[setVariable],
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<FlexBox as="label" orientation="horizontal" hAlign="center" style={{ whiteSpace: 'nowrap' }}>
|
|
65
|
+
<span style={{ flexShrink: 0 }}>{key}</span>:
|
|
66
|
+
<input
|
|
67
|
+
name={key}
|
|
68
|
+
onChange={onChange}
|
|
69
|
+
style={{ border: 0, padding: 8, fieldSizing: 'content', display: 'inline' } as any}
|
|
70
|
+
value={defaultStyle[key] === value ? '' : value}
|
|
71
|
+
placeholder={value}
|
|
72
|
+
/>
|
|
73
|
+
;
|
|
74
|
+
</FlexBox>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function VariablesEditor({
|
|
79
|
+
style,
|
|
80
|
+
defaultStyle,
|
|
81
|
+
setStyle,
|
|
82
|
+
}: {
|
|
83
|
+
style: Variables;
|
|
84
|
+
defaultStyle: Variables;
|
|
85
|
+
setStyle: (fn: (newStyle: Variables) => Variables) => void;
|
|
86
|
+
}) {
|
|
87
|
+
const setVariable = React.useCallback(
|
|
88
|
+
([key, value]: Entry) => {
|
|
89
|
+
setStyle((prevStyle) => ({ ...prevStyle, [key]: value }));
|
|
90
|
+
},
|
|
91
|
+
[setStyle],
|
|
92
|
+
);
|
|
93
|
+
return (
|
|
94
|
+
<details style={{ fontFamily: 'monospace' }} className="lumx-spacing-margin-vertical-huge">
|
|
95
|
+
<summary className="lumx-typography-subtitle2">Edit variables</summary>
|
|
96
|
+
{Object.entries(style).map((variable) => (
|
|
97
|
+
<VariableEditor
|
|
98
|
+
key={variable[0]}
|
|
99
|
+
defaultStyle={defaultStyle}
|
|
100
|
+
variable={variable}
|
|
101
|
+
setVariable={setVariable}
|
|
102
|
+
/>
|
|
103
|
+
))}
|
|
104
|
+
</details>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const FILTER_PROPS = ['theme', 'emphasis', 'size'];
|
|
109
|
+
|
|
110
|
+
export function withTheming<P extends PropertyTree>({
|
|
111
|
+
properties,
|
|
112
|
+
values,
|
|
113
|
+
}: {
|
|
114
|
+
properties?: P;
|
|
115
|
+
values?: string | Partial<P>;
|
|
116
|
+
}) {
|
|
117
|
+
const initialStyle = values
|
|
118
|
+
? Object.fromEntries(
|
|
119
|
+
typeof values === 'string'
|
|
120
|
+
? parseVariableEntries(values)
|
|
121
|
+
: toArgEntries(values as PropertyTree, '--lumx'),
|
|
122
|
+
)
|
|
123
|
+
: [];
|
|
124
|
+
const defaultStyle = Object.fromEntries(properties ? Array.from(toArgEntries(properties, '--lumx')) : []);
|
|
125
|
+
|
|
126
|
+
const varNames = new Set(Object.keys(initialStyle).concat(Object.keys(defaultStyle)));
|
|
127
|
+
|
|
128
|
+
function filteredStyles(args: any) {
|
|
129
|
+
// Create predicate
|
|
130
|
+
const filterArgs = Object.entries(args)
|
|
131
|
+
.map(([argName, argValue]) => {
|
|
132
|
+
if (typeof argValue === 'string' && FILTER_PROPS.includes(argName)) {
|
|
133
|
+
return (varName: string) =>
|
|
134
|
+
// Has the given arg with value
|
|
135
|
+
varName.match(new RegExp(`${argName}-${argValue}`)) ||
|
|
136
|
+
(argName === 'emphasis' && argValue === 'medium' && varName.match(/emphasis-selected/)) ||
|
|
137
|
+
// Or does not have the arg at all
|
|
138
|
+
!varName.match(new RegExp(`${argName}-\\w+`));
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
})
|
|
142
|
+
.filter(Boolean) as Array<Predicate<string>>;
|
|
143
|
+
const styles = Object.fromEntries(
|
|
144
|
+
Array.from(varNames.values())
|
|
145
|
+
.map((varName) => {
|
|
146
|
+
if (!filterArgs.every((filter) => filter(varName))) return null as any;
|
|
147
|
+
return [varName, initialStyle[varName] || defaultStyle[varName]];
|
|
148
|
+
})
|
|
149
|
+
.filter(Boolean),
|
|
150
|
+
);
|
|
151
|
+
return () => styles;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return (Story: any, ctx: any) => {
|
|
155
|
+
const [style, setStyle] = React.useState<Variables>(filteredStyles(ctx.args));
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<>
|
|
159
|
+
<Story args={{ ...ctx.args, style: { ...ctx.args.style, ...style } }} />
|
|
160
|
+
<VariablesEditor style={style} defaultStyle={defaultStyle} setStyle={setStyle} />
|
|
161
|
+
</>
|
|
162
|
+
);
|
|
163
|
+
};
|
|
164
|
+
}
|