@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.
@@ -3,6 +3,7 @@ import { withValueOnChange } from '@lumx/react/stories/decorators/withValueOnCha
3
3
  import { withNestedProps } from '@lumx/react/stories/decorators/withNestedProps';
4
4
  import { withCombinations } from '@lumx/react/stories/decorators/withCombinations';
5
5
  import { withWrapper } from '@lumx/react/stories/decorators/withWrapper';
6
+ import { withTheming } from '@lumx/react/stories/utils/theming';
6
7
 
7
8
  export default {
8
9
  title: 'LumX components/date-picker/DatePicker',
@@ -36,3 +37,82 @@ export const LocalesVariations = {
36
37
  withWrapper({ maxColumns: 5, itemMinWidth: 300 }, GridColumn),
37
38
  ],
38
39
  };
40
+
41
+ /**
42
+ * Demo LumX CSS theming variables
43
+ */
44
+ export const Theming = {
45
+ args: { ...Default.args, value: new Date('2023-02-15') },
46
+ decorators: [
47
+ withTheming({
48
+ values: `
49
+ --lumx-button-border-radius: 10px;
50
+
51
+ /////////////
52
+ --lumx-button-emphasis-low-state-default-padding-horizontal: 1px;
53
+ --lumx-button-emphasis-low-state-default-border-width: 1px;
54
+ --lumx-button-emphasis-low-state-hover-padding-horizontal: 2px;
55
+ --lumx-button-emphasis-low-state-hover-border-width: 1px;
56
+ --lumx-button-emphasis-low-state-active-padding-horizontal: 3px;
57
+ --lumx-button-emphasis-low-state-active-border-width: 1px;
58
+
59
+ --lumx-button-emphasis-low-state-default-theme-light-background-color: rgb(from green r g b / 10%);
60
+ --lumx-button-emphasis-low-state-default-theme-light-color: black;
61
+ --lumx-button-emphasis-low-state-default-theme-light-border-color: transparent;
62
+ --lumx-button-emphasis-low-state-hover-theme-light-background-color: rgb(from darkslategray r g b / 50%);
63
+ --lumx-button-emphasis-low-state-hover-theme-light-color: crimson;
64
+ --lumx-button-emphasis-low-state-hover-theme-light-border-color: transparent;
65
+ --lumx-button-emphasis-low-state-active-theme-light-background-color: rgb(from blanchedalmond r g b / 50%);
66
+ --lumx-button-emphasis-low-state-active-theme-light-color: firebrick;
67
+ --lumx-button-emphasis-low-state-active-theme-light-border-color: transparent;
68
+
69
+ /////////////
70
+ --lumx-button-emphasis-selected-state-default-padding-horizontal: 1px;
71
+ --lumx-button-emphasis-selected-state-default-border-width: 1px;
72
+ --lumx-button-emphasis-selected-state-hover-padding-horizontal: 2px;
73
+ --lumx-button-emphasis-selected-state-hover-border-width: 1px;
74
+ --lumx-button-emphasis-selected-state-active-padding-horizontal: 3px;
75
+ --lumx-button-emphasis-selected-state-active-border-width: 1px;
76
+
77
+ --lumx-button-emphasis-selected-state-default-theme-light-background-color: rgb(from green r g b / 50%);
78
+ --lumx-button-emphasis-selected-state-default-theme-light-color: green;
79
+ --lumx-button-emphasis-selected-state-default-theme-light-border-color: currentcolor;
80
+ --lumx-button-emphasis-selected-state-hover-theme-light-background-color: rgb(from darkslategray r g b / 50%);
81
+ --lumx-button-emphasis-selected-state-hover-theme-light-color: crimson;
82
+ --lumx-button-emphasis-selected-state-hover-theme-light-border-color: currentcolor;
83
+ --lumx-button-emphasis-selected-state-active-theme-light-background-color: rgb(from blanchedalmond r g b / 50%);
84
+ --lumx-button-emphasis-selected-state-active-theme-light-color: firebrick;
85
+ --lumx-button-emphasis-selected-state-active-theme-light-border-color: currentcolor;
86
+
87
+ /////////
88
+ --lumx-text-field-input-min-height: 26px;
89
+ --lumx-text-field-input-padding-horizontal: 5px;
90
+ --lumx-text-field-input-border-radius: 10px;
91
+ --lumx-text-field-state-default-input-border-top-width: 0;
92
+ --lumx-text-field-state-default-input-border-right-width: 0;
93
+ --lumx-text-field-state-default-input-border-bottom-width: 0;
94
+ --lumx-text-field-state-default-input-border-left-width: 0;
95
+ --lumx-text-field-state-default-theme-light-header-label-color: var(--lumx-color-dark-N);
96
+ --lumx-text-field-state-default-theme-light-input-background-color: rgb(from green r g b / 10%);
97
+ --lumx-text-field-state-default-theme-light-input-border-color: var(--lumx-color-dark-L4);
98
+ --lumx-text-field-state-default-theme-light-input-content-color: var(--lumx-color-dark-N);
99
+ --lumx-text-field-state-hover-input-border-top-width: 1px;
100
+ --lumx-text-field-state-hover-input-border-right-width: 1px;
101
+ --lumx-text-field-state-hover-input-border-bottom-width: 1px;
102
+ --lumx-text-field-state-hover-input-border-left-width: 1px;
103
+ --lumx-text-field-state-hover-theme-light-header-label-color: var(--lumx-color-dark-N);
104
+ --lumx-text-field-state-hover-theme-light-input-background-color: rgb(from green r g b / 30%);
105
+ --lumx-text-field-state-hover-theme-light-input-border-color: green;
106
+ --lumx-text-field-state-hover-theme-light-input-content-color: var(--lumx-color-dark-N);
107
+ --lumx-text-field-state-focus-input-border-top-width: 2px;
108
+ --lumx-text-field-state-focus-input-border-right-width: 2px;
109
+ --lumx-text-field-state-focus-input-border-bottom-width: 2px;
110
+ --lumx-text-field-state-focus-input-border-left-width: 2px;
111
+ --lumx-text-field-state-focus-theme-light-header-label-color: var(--lumx-color-dark-N);
112
+ --lumx-text-field-state-focus-theme-light-input-background-color: rgb(from green r g b / 50%);
113
+ --lumx-text-field-state-focus-theme-light-input-border-color: green;
114
+ --lumx-text-field-state-focus-theme-light-input-content-color: var(--lumx-color-dark-N);
115
+ `,
116
+ }),
117
+ ],
118
+ };
@@ -59,7 +59,7 @@ describe(`<${DatePickerControlled.displayName}>`, () => {
59
59
  expect(queries.getAccessibleMonthYear(toolbar)).toBeInTheDocument();
60
60
  expect(queries.getAccessibleMonthYear(toolbar)).toHaveTextContent('février 2017');
61
61
 
62
- const selected = queryByClassName(datePickerControlled, `${CLASSNAME}__month-day--is-selected`);
62
+ const selected = queryByClassName(datePickerControlled, `lumx-button--is-selected`);
63
63
  expect(selected).toBe(screen.queryByRole('button', { name: /22 février 2017/i }));
64
64
  });
65
65
 
@@ -1,6 +1,16 @@
1
1
  import React, { KeyboardEventHandler, forwardRef } from 'react';
2
2
  import classNames from 'classnames';
3
- import { DatePickerProps, Emphasis, FlexBox, IconButton, Text, TextField, TextFieldProps, Toolbar } from '@lumx/react';
3
+ import {
4
+ Button,
5
+ DatePickerProps,
6
+ Emphasis,
7
+ FlexBox,
8
+ IconButton,
9
+ Text,
10
+ TextField,
11
+ TextFieldProps,
12
+ Toolbar,
13
+ } from '@lumx/react';
4
14
  import { mdiChevronLeft, mdiChevronRight } from '@lumx/icons';
5
15
  import { Comp } from '@lumx/react/utils/type';
6
16
  import { getMonthCalendar } from '@lumx/react/utils/date/getMonthCalendar';
@@ -56,6 +66,7 @@ export const DatePickerControlled: Comp<DatePickerControlledProps, HTMLDivElemen
56
66
  todayOrSelectedDateRef,
57
67
  value,
58
68
  onMonthChange,
69
+ style,
59
70
  } = props;
60
71
  const { weeks, weekDays } = React.useMemo(() => {
61
72
  const localeObj = parseLocale(locale) as Locale;
@@ -127,7 +138,7 @@ export const DatePickerControlled: Comp<DatePickerControlledProps, HTMLDivElemen
127
138
  const yearLabel = getYearDisplayName(locale);
128
139
 
129
140
  return (
130
- <div ref={ref} className={`${CLASSNAME}`}>
141
+ <div ref={ref} className={`${CLASSNAME}`} style={style}>
131
142
  <Toolbar
132
143
  className={`${CLASSNAME}__toolbar`}
133
144
  after={
@@ -212,14 +223,14 @@ export const DatePickerControlled: Comp<DatePickerControlledProps, HTMLDivElemen
212
223
  return (
213
224
  <div key={key} className={`${CLASSNAME}__day-wrapper`}>
214
225
  {date && (
215
- <button
226
+ <Button
216
227
  ref={isSelected || (!value && isToday) ? todayOrSelectedDateRef : null}
217
228
  className={classNames(`${CLASSNAME}__month-day`, {
218
- [`${CLASSNAME}__month-day--is-selected`]: isSelected,
219
229
  [`${CLASSNAME}__month-day--is-today`]: isToday,
220
230
  })}
221
231
  disabled={isOutOfRange}
222
- type="button"
232
+ isSelected={isSelected}
233
+ emphasis="low"
223
234
  onClick={() => onChange(date)}
224
235
  >
225
236
  <span aria-hidden>{formatDayNumber(locale, date)}</span>
@@ -230,7 +241,7 @@ export const DatePickerControlled: Comp<DatePickerControlledProps, HTMLDivElemen
230
241
  year: 'numeric',
231
242
  })}
232
243
  </span>
233
- </button>
244
+ </Button>
234
245
  )}
235
246
  </div>
236
247
  );
@@ -9,59 +9,228 @@ import {
9
9
  mdiGoogleCirclesExtended,
10
10
  mdiFolder,
11
11
  } from '@lumx/icons';
12
- import { Navigation, Orientation } from '@lumx/react';
12
+ import { Navigation, Orientation, Theme } from '@lumx/react';
13
13
  import { CustomLink } from '@lumx/react/stories/utils/CustomLink';
14
+ import { withCombinations } from '@lumx/react/stories/decorators/withCombinations';
15
+ import { withThemedBackground } from '@lumx/react/stories/decorators/withThemedBackground';
16
+ import { withTheming } from '@lumx/react/stories/utils/theming';
17
+ import pick from 'lodash/pick';
18
+ import { DESIGN_TOKENS } from '@lumx/core/js/constants/design-tokens';
19
+ import { withNestedProps } from '@lumx/react/stories/decorators/withNestedProps';
20
+ import { iconArgType } from '@lumx/react/stories/controls/icons';
21
+ import { getSelectArgType } from '@lumx/react/stories/controls/selectArgType';
14
22
 
15
- export default { title: 'LumX components/navigation/Navigation' };
23
+ export default {
24
+ title: 'LumX components/navigation/Navigation',
25
+ component: Navigation,
26
+ argTypes: {
27
+ 'itemProps.onClick': { action: true, table: { disable: true } },
28
+ },
29
+ };
16
30
 
17
- export const Default = ({ theme, onClick, orientation }: any) => {
18
- return (
19
- <Navigation theme={theme} aria-label="navigation" orientation={orientation}>
20
- <Navigation.Item isCurrentPage label="Homepage" icon={mdiHome} href="#" />
21
- <Navigation.Item
22
- label="Some very very very very very very very very very very very very very very very very very very very very very very very very very very very long text"
23
- href="#"
24
- />
25
- <Navigation.Item
26
- label="Custom link element"
27
- icon={mdiMessageTextOutline}
28
- as={CustomLink}
29
- // `to` prop is required in CustomLink
30
- to="#"
31
- />
32
- <Navigation.Item as="button" label="Button element" icon={mdiFolderGoogleDrive} onClick={onClick} />
33
- <Navigation.Section label="Section 1" icon={mdiFolder}>
34
- <Navigation.Item label="A content" href="#content" />
35
- <Navigation.Item label="A button" icon={mdiLink} href="https://www.google.com" />
31
+ /**
32
+ * Demonstrate a full-featured navigation
33
+ */
34
+ export const FullFeatured = {
35
+ render({ theme, itemProps, orientation }: any) {
36
+ return (
37
+ <Navigation theme={theme} aria-label="navigation" orientation={orientation}>
38
+ <Navigation.Item isCurrentPage label="Homepage" icon={mdiHome} href="#" {...itemProps} />
36
39
  <Navigation.Item
37
40
  label="Some very very very very very very very very very very very very very very very very very very very very very very very very very very very long text"
38
- icon={mdiTextBox}
39
- href="#content"
41
+ href="#"
42
+ {...itemProps}
43
+ />
44
+ <Navigation.Item
45
+ label="Custom link element"
46
+ icon={mdiMessageTextOutline}
47
+ as={CustomLink}
48
+ // `to` prop is required in CustomLink
49
+ to="#"
50
+ {...itemProps}
40
51
  />
41
- <Navigation.Item label="A community" icon={mdiGoogleCirclesExtended} href="#community" />
42
- <Navigation.Section label="Section 1.1" icon={mdiFolder}>
43
- <Navigation.Item label="A content" icon={mdiTextBox} href="#content" />
52
+ <Navigation.Item as="button" label="Button element" icon={mdiFolderGoogleDrive} {...itemProps} />
53
+ <Navigation.Section label="Section 1" icon={mdiFolder} {...itemProps}>
54
+ <Navigation.Item label="A content" href="#content" {...itemProps} />
55
+ <Navigation.Item label="A button" icon={mdiLink} href="https://www.google.com" {...itemProps} />
44
56
  <Navigation.Item
45
57
  label="Some very very very very very very very very very very very very very very very very very very very very very very very very very very very long text"
46
58
  icon={mdiTextBox}
47
59
  href="#content"
60
+ {...itemProps}
48
61
  />
49
- <Navigation.Item label="A link" icon={mdiLink} href="https://www.google.com" />
50
- <Navigation.Item label="A community" icon={mdiGoogleCirclesExtended} href="#community" />
62
+ <Navigation.Item
63
+ label="A community"
64
+ icon={mdiGoogleCirclesExtended}
65
+ href="#community"
66
+ {...itemProps}
67
+ />
68
+ <Navigation.Section label="Section 1.1" icon={mdiFolder} {...itemProps}>
69
+ <Navigation.Item label="A content" icon={mdiTextBox} href="#content" {...itemProps} />
70
+ <Navigation.Item
71
+ label="Some very very very very very very very very very very very very very very very very very very very very very very very very very very very long text"
72
+ icon={mdiTextBox}
73
+ href="#content"
74
+ {...itemProps}
75
+ />
76
+ <Navigation.Item label="A link" icon={mdiLink} href="https://www.google.com" {...itemProps} />
77
+ <Navigation.Item
78
+ label="A community"
79
+ icon={mdiGoogleCirclesExtended}
80
+ href="#community"
81
+ {...itemProps}
82
+ />
83
+ </Navigation.Section>
51
84
  </Navigation.Section>
52
- </Navigation.Section>
53
- <Navigation.Section label="Section 2" icon={mdiFolder}>
54
- <Navigation.Item label="A content" icon={mdiTextBox} href="#content" />
55
- <Navigation.Item label="A link" icon={mdiLink} href="https://www.google.com" />
56
- <Navigation.Item label="A community" icon={mdiGoogleCirclesExtended} href="#community" />
57
- </Navigation.Section>
85
+ <Navigation.Section label="Section 2" icon={mdiFolder} {...itemProps}>
86
+ <Navigation.Item label="A content" icon={mdiTextBox} href="#content" {...itemProps} />
87
+ <Navigation.Item label="A link" icon={mdiLink} href="https://www.google.com" {...itemProps} />
88
+ <Navigation.Item
89
+ label="A community"
90
+ icon={mdiGoogleCirclesExtended}
91
+ href="#community"
92
+ {...itemProps}
93
+ />
94
+ </Navigation.Section>
95
+ </Navigation>
96
+ );
97
+ },
98
+ decorators: [withNestedProps()],
99
+ };
100
+
101
+ /**
102
+ * Horizontal navigation
103
+ */
104
+ export const FullFeaturedHorizontal = { ...FullFeatured, args: { orientation: Orientation.horizontal } };
105
+
106
+ /**
107
+ * Demonstrate all item variants
108
+ */
109
+ export const ItemVariants = {
110
+ args: {
111
+ 'itemProps.icon': mdiHome,
112
+ 'itemProps.as': 'button',
113
+ },
114
+ argTypes: {
115
+ 'itemProps.icon': iconArgType,
116
+ 'itemProps.as': getSelectArgType(['button', 'a']),
117
+ 'itemProps.href': { control: 'text', if: { arg: 'itemProps.as', eq: 'a' } },
118
+ },
119
+ render: ({ itemProps, ...args }: any) => (
120
+ <Navigation aria-label="navigation" {...args}>
121
+ {Object.entries({
122
+ '': {},
123
+ Current: { isCurrentPage: true },
124
+ }).map(([key1, currentProps]) =>
125
+ Object.entries({
126
+ Item: {},
127
+ 'Item (hover)': { 'data-lumx-hover': true },
128
+ 'Item (active)': { 'data-lumx-active': true },
129
+ }).map(([key2, stateProps]) => (
130
+ <Navigation.Item
131
+ key={key1 + key2}
132
+ label={`${key1} ${key2}`}
133
+ {...currentProps}
134
+ {...stateProps}
135
+ {...itemProps}
136
+ />
137
+ )),
138
+ )}
139
+
140
+ {Object.entries({
141
+ Section: {},
142
+ 'Section (hover)': { 'data-lumx-hover': true },
143
+ 'Section (active)': { 'data-lumx-active': true },
144
+ }).map(([key2, stateProps]) => (
145
+ <Navigation.Section key={key2} label={key2} {...stateProps} {...itemProps}>
146
+ <Navigation.Item as="button" label="SubItem 1" />
147
+ <Navigation.Item as="button" label="SubItem 2" />
148
+ </Navigation.Section>
149
+ ))}
58
150
  </Navigation>
59
- );
151
+ ),
152
+ decorators: [
153
+ withNestedProps(),
154
+ withThemedBackground(),
155
+ withCombinations({
156
+ sectionStyle: { display: 'inline-block' },
157
+ combinations: {
158
+ cols: { '': {}, Focused: { 'itemProps.data-focus-visible-added': true } },
159
+ sections: {
160
+ 'Theme light': { theme: undefined },
161
+ 'Theme dark': { theme: Theme.dark },
162
+ },
163
+ },
164
+ }),
165
+ ],
60
166
  };
61
- Default.argTypes = { onClick: { action: true } };
62
167
 
63
- export const VerticalWithSection: any = Default.bind({});
64
- VerticalWithSection.args = { orientation: Orientation.vertical };
168
+ /**
169
+ * Test CSS variable theming
170
+ */
171
+ export const Theming = {
172
+ ...ItemVariants,
173
+ decorators: [
174
+ ...ItemVariants.decorators,
175
+ withTheming({
176
+ properties: pick(DESIGN_TOKENS, ['navigation']),
177
+ values: `
178
+ --lumx-navigation-item-emphasis-low-state-default-border-top-width: 5px;
179
+ --lumx-navigation-item-emphasis-low-state-default-border-right-width: 2px;
180
+ --lumx-navigation-item-emphasis-low-state-default-border-bottom-width: 3px;
181
+ --lumx-navigation-item-emphasis-low-state-default-border-left-width: 4px;
182
+ --lumx-navigation-item-emphasis-low-state-default-theme-light-border-color: lightcoral;
183
+ --lumx-navigation-item-emphasis-low-state-default-theme-light-background-color: lightsalmon;
184
+ --lumx-navigation-item-emphasis-low-state-default-theme-dark-border-color: lightsalmon;
185
+ --lumx-navigation-item-emphasis-low-state-default-theme-dark-background-color: lightcoral;
186
+
187
+ --lumx-navigation-item-emphasis-low-state-hover-border-top-width: 4px;
188
+ --lumx-navigation-item-emphasis-low-state-hover-border-right-width: 5px;
189
+ --lumx-navigation-item-emphasis-low-state-hover-border-bottom-width: 2px;
190
+ --lumx-navigation-item-emphasis-low-state-hover-border-left-width: 3px;
191
+ --lumx-navigation-item-emphasis-low-state-hover-theme-light-border-color: lightgreen;
192
+ --lumx-navigation-item-emphasis-low-state-hover-theme-light-background-color: lightpink;
193
+ --lumx-navigation-item-emphasis-low-state-hover-theme-dark-border-color: lightpink;
194
+ --lumx-navigation-item-emphasis-low-state-hover-theme-dark-background-color: lightgreen;
65
195
 
66
- export const HorizontalWithSection: any = Default.bind({});
67
- HorizontalWithSection.args = { orientation: Orientation.horizontal };
196
+ --lumx-navigation-item-emphasis-low-state-active-border-top-width: 3px;
197
+ --lumx-navigation-item-emphasis-low-state-active-border-right-width: 4px;
198
+ --lumx-navigation-item-emphasis-low-state-active-border-bottom-width: 5px;
199
+ --lumx-navigation-item-emphasis-low-state-active-border-left-width: 2px;
200
+ --lumx-navigation-item-emphasis-low-state-active-theme-light-border-color: lemonchiffon;
201
+ --lumx-navigation-item-emphasis-low-state-active-theme-light-background-color: lavenderblush;
202
+ --lumx-navigation-item-emphasis-low-state-active-theme-dark-border-color: lavenderblush;
203
+ --lumx-navigation-item-emphasis-low-state-active-theme-dark-background-color: lemonchiffon;
204
+
205
+ ////
206
+
207
+ --lumx-navigation-item-emphasis-selected-state-default-border-top-width: 2px;
208
+ --lumx-navigation-item-emphasis-selected-state-default-border-right-width: 3px;
209
+ --lumx-navigation-item-emphasis-selected-state-default-border-bottom-width: 4px;
210
+ --lumx-navigation-item-emphasis-selected-state-default-border-left-width: 5px;
211
+ --lumx-navigation-item-emphasis-selected-state-default-theme-light-border-color: red;
212
+ --lumx-navigation-item-emphasis-selected-state-default-theme-light-background-color: orange;
213
+ --lumx-navigation-item-emphasis-selected-state-default-theme-dark-border-color: blue;
214
+ --lumx-navigation-item-emphasis-selected-state-default-theme-dark-background-color: violet;
215
+
216
+ --lumx-navigation-item-emphasis-selected-state-hover-border-top-width: 3px;
217
+ --lumx-navigation-item-emphasis-selected-state-hover-border-right-width: 4px;
218
+ --lumx-navigation-item-emphasis-selected-state-hover-border-bottom-width: 5px;
219
+ --lumx-navigation-item-emphasis-selected-state-hover-border-left-width: 2px;
220
+ --lumx-navigation-item-emphasis-selected-state-hover-theme-light-border-color: green;
221
+ --lumx-navigation-item-emphasis-selected-state-hover-theme-light-background-color: violet;
222
+ --lumx-navigation-item-emphasis-selected-state-hover-theme-dark-border-color: violet;
223
+ --lumx-navigation-item-emphasis-selected-state-hover-theme-dark-background-color: green;
224
+
225
+ --lumx-navigation-item-emphasis-selected-state-active-border-top-width: 4px;
226
+ --lumx-navigation-item-emphasis-selected-state-active-border-right-width: 5px;
227
+ --lumx-navigation-item-emphasis-selected-state-active-border-bottom-width: 2px;
228
+ --lumx-navigation-item-emphasis-selected-state-active-border-left-width: 3px;
229
+ --lumx-navigation-item-emphasis-selected-state-active-theme-light-border-color: orange;
230
+ --lumx-navigation-item-emphasis-selected-state-active-theme-light-background-color: pink;
231
+ --lumx-navigation-item-emphasis-selected-state-active-theme-dark-border-color: pink;
232
+ --lumx-navigation-item-emphasis-selected-state-active-theme-dark-background-color: orange;
233
+ `,
234
+ }),
235
+ ],
236
+ };
@@ -18,10 +18,10 @@ type SetupProps = Partial<NavigationSectionProps>;
18
18
  */
19
19
 
20
20
  const setup = (propsOverride: SetupProps = {}, orientation: Orientation = Orientation.vertical) => {
21
- const props = { ...propsOverride };
21
+ const props = { label: 'Section 1', ...propsOverride };
22
22
  const { container } = render(
23
23
  <NavigationContext.Provider value={{ orientation }}>
24
- <NavigationSection label="Section 1" {...props}>
24
+ <NavigationSection {...props}>
25
25
  <NavigationItem label="A content" href="" />
26
26
  <NavigationItem label="A link" href="" />
27
27
  <NavigationItem label="A community" href="" />
@@ -29,17 +29,16 @@ const setup = (propsOverride: SetupProps = {}, orientation: Orientation = Orient
29
29
  </NavigationContext.Provider>,
30
30
  );
31
31
 
32
+ const query = {
33
+ button: () => screen.getByRole('button', { name: props.label as string }),
34
+ content: () => queryByClassName(container, `${CLASSNAME}__drawer`),
35
+ popover: () => queryByClassName(container, `${CLASSNAME}__drawer--popover`),
36
+ };
32
37
  return {
33
38
  container,
34
39
  element: getByClassName(container, CLASSNAME),
35
- query: {
36
- button: () =>
37
- screen.getByRole('button', {
38
- name: /section 1/i,
39
- }),
40
- content: () => queryByClassName(container, `${CLASSNAME}__drawer`),
41
- popover: () => queryByClassName(container, `${CLASSNAME}__drawer--popover`),
42
- },
40
+ button: query.button(),
41
+ query,
43
42
  props,
44
43
  };
45
44
  };
@@ -122,5 +121,5 @@ describe(`<${NavigationSection.displayName}>`, () => {
122
121
  });
123
122
 
124
123
  // Common tests suite.
125
- commonTestsSuiteRTL(setup, { baseClassName: CLASSNAME, forwardClassName: 'element', forwardAttributes: 'element' });
124
+ commonTestsSuiteRTL(setup, { baseClassName: CLASSNAME, forwardClassName: 'element', forwardAttributes: 'button' });
126
125
  });
@@ -11,7 +11,7 @@ import { useId } from '@lumx/react/hooks/useId';
11
11
  import { CLASSNAME as ITEM_CLASSNAME } from './NavigationItem';
12
12
  import { NavigationContext } from './context';
13
13
 
14
- export interface NavigationSectionProps extends React.ComponentPropsWithoutRef<'li'>, HasClassName {
14
+ export interface NavigationSectionProps extends React.ComponentPropsWithoutRef<'button'>, HasClassName {
15
15
  /** Items inside the section */
16
16
  children: ReactNode;
17
17
  /** Icon (SVG path). */
@@ -51,9 +51,9 @@ export const NavigationSection = Object.assign(
51
51
  }),
52
52
  )}
53
53
  ref={ref}
54
- {...forwardedProps}
55
54
  >
56
55
  <button
56
+ {...forwardedProps}
57
57
  aria-controls={sectionId}
58
58
  aria-expanded={isOpen}
59
59
  className={classNames(`${ITEM_CLASSNAME}__link`)}
@@ -0,0 +1,133 @@
1
+ /* eslint-disable react-hooks/rules-of-hooks,import/no-extraneous-dependencies */
2
+ import React from 'react';
3
+ import pick from 'lodash/pick';
4
+
5
+ import { Emphasis, GridColumn, SideNavigation, SideNavigationItem } from '@lumx/react';
6
+ import { getSelectArgType } from '@lumx/react/stories/controls/selectArgType';
7
+ import { withNestedProps } from '@lumx/react/stories/decorators/withNestedProps';
8
+ import { withCombinations } from '@lumx/react/stories/decorators/withCombinations';
9
+ import { withTheming } from '@lumx/react/stories/utils/theming';
10
+ import { DESIGN_TOKENS } from '@lumx/core/js/constants/design-tokens';
11
+ import { disableArgTypes } from '@lumx/react/stories/utils/disableArgTypes';
12
+ import { iconArgType } from '@lumx/react/stories/controls/icons';
13
+ import { withWrapper } from '@lumx/react/stories/decorators/withWrapper';
14
+ import { action } from '@storybook/addon-actions';
15
+
16
+ const EMPHASIS = [Emphasis.high, Emphasis.medium, Emphasis.low];
17
+
18
+ export default {
19
+ title: 'LumX components/side-navigation/Side Navigation Item',
20
+ component: SideNavigationItem,
21
+ args: {
22
+ label: 'Item',
23
+ 'toggleButtonProps.label': 'Toggle',
24
+ },
25
+ argTypes: {
26
+ emphasis: getSelectArgType(EMPHASIS),
27
+ icon: iconArgType,
28
+ closeMode: { control: { type: 'inline-radio' }, if: { arg: 'children', exists: true } },
29
+ isOpen: { if: { arg: 'children', exists: true } },
30
+ onClick: { action: true, table: { disable: true } },
31
+ ...disableArgTypes(['ref', 'children', 'linkAs', 'linkProps', 'toggleButtonProps', 'onActionClick']),
32
+ },
33
+ render: (args: any) => {
34
+ const [isOpen, setIsOpen] = React.useState<boolean | undefined>(undefined);
35
+
36
+ const toggleCallback = args.onActionClick ? 'onActionClick' : 'onClick';
37
+ const toggle: React.MouseEventHandler = (event) => {
38
+ args?.[toggleCallback]?.(event);
39
+ setIsOpen((wasOpen) => !wasOpen);
40
+ };
41
+ return (
42
+ <SideNavigation>
43
+ <SideNavigationItem {...args} {...{ [toggleCallback]: toggle }} isOpen={isOpen} />
44
+ </SideNavigation>
45
+ );
46
+ },
47
+ };
48
+
49
+ const STATE_COMBINATIONS = withCombinations({
50
+ combinations: {
51
+ cols: {
52
+ Default: {},
53
+ Hover: { 'linkProps.data-lumx-hover': true },
54
+ Active: { 'linkProps.data-lumx-active': true },
55
+ },
56
+ rows: {
57
+ Default: {},
58
+ Focused: { 'linkProps.data-focus-visible-added': true },
59
+ Selected: { isSelected: true },
60
+ 'Selected & Focused': { isSelected: true, 'linkProps.data-focus-visible-added': true },
61
+ },
62
+ },
63
+ });
64
+
65
+ /**
66
+ * Demonstrate item & section variants
67
+ */
68
+ export const ItemsAndSections = {
69
+ argTypes: { ...disableArgTypes(['isSelected']) },
70
+ decorators: [
71
+ withNestedProps(),
72
+ STATE_COMBINATIONS,
73
+ withCombinations({
74
+ combinations: {
75
+ rows: {
76
+ '': {},
77
+ 'With children': {
78
+ children: <SideNavigationItem label="Item 1" toggleButtonProps={{ label: 'Open' }} />,
79
+ },
80
+ },
81
+ cols: {
82
+ '': {},
83
+ 'With action click': {
84
+ onActionClick: action('onActionClick'),
85
+ },
86
+ },
87
+ },
88
+ }),
89
+ ],
90
+ };
91
+
92
+ /**
93
+ * Demonstrate emphasis variants
94
+ */
95
+ export const EmphasisVariants = {
96
+ argTypes: { ...disableArgTypes(['emphasis', 'isSelected']) },
97
+ decorators: [
98
+ withNestedProps(),
99
+ STATE_COMBINATIONS,
100
+ withCombinations({
101
+ combinations: {
102
+ sections: { key: 'emphasis', options: EMPHASIS },
103
+ },
104
+ }),
105
+ withWrapper({ itemMinWidth: 300, maxColumns: 3 }, GridColumn),
106
+ ],
107
+ };
108
+
109
+ /**
110
+ * Test CSS variable theming
111
+ */
112
+ export const Theming = {
113
+ ...ItemsAndSections,
114
+ decorators: [
115
+ ...ItemsAndSections.decorators,
116
+ withTheming({
117
+ properties: pick(DESIGN_TOKENS, ['side-navigation']),
118
+ values: `
119
+ --lumx-side-navigation-item-emphasis-selected-state-default-border-width: 2px;
120
+ --lumx-side-navigation-item-emphasis-selected-state-default-theme-light-border-color: red;
121
+ --lumx-side-navigation-item-emphasis-selected-state-default-theme-light-background-color: orange;
122
+
123
+ --lumx-side-navigation-item-emphasis-selected-state-hover-border-width: 3px;
124
+ --lumx-side-navigation-item-emphasis-selected-state-hover-theme-light-border-color: green;
125
+ --lumx-side-navigation-item-emphasis-selected-state-hover-theme-light-background-color: red;
126
+
127
+ --lumx-side-navigation-item-emphasis-selected-state-active-border-width: 4px;
128
+ --lumx-side-navigation-item-emphasis-selected-state-active-theme-light-border-color: orange;
129
+ --lumx-side-navigation-item-emphasis-selected-state-active-theme-light-background-color: violet;
130
+ `,
131
+ }),
132
+ ],
133
+ };
@@ -1,6 +1,7 @@
1
1
  import { ColorPalette, ColorVariant } from '@lumx/react';
2
2
  import { getSelectArgType } from '@lumx/react/stories/controls/selectArgType';
3
+ import { withUndefined } from '@lumx/react/stories/controls/withUndefined';
3
4
 
4
5
  export const ALL_COLORS = Object.values(ColorPalette);
5
- export const colorArgType = getSelectArgType(ALL_COLORS);
6
+ export const colorArgType = getSelectArgType(withUndefined(ALL_COLORS));
6
7
  export const colorVariantArgType = getSelectArgType(ColorVariant);