@qoretechnologies/reqore 0.39.0 → 0.40.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.
Files changed (35) hide show
  1. package/dist/components/ControlGroup/index.d.ts +4 -2
  2. package/dist/components/ControlGroup/index.d.ts.map +1 -1
  3. package/dist/components/ControlGroup/index.js.map +1 -1
  4. package/dist/components/Menu/section.d.ts +12 -0
  5. package/dist/components/Menu/section.d.ts.map +1 -0
  6. package/dist/components/Menu/section.js +87 -0
  7. package/dist/components/Menu/section.js.map +1 -0
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +3 -3
  11. package/dist/index.js.map +1 -1
  12. package/package.json +1 -1
  13. package/src/components/ControlGroup/index.tsx +8 -4
  14. package/src/components/Menu/section.tsx +82 -0
  15. package/src/index.tsx +1 -1
  16. package/src/mock/menu.ts +46 -48
  17. package/src/stories/Menu/Menu.stories.tsx +161 -108
  18. package/tests.json +1 -1
  19. package/__tests__/sidebar.test.tsx +0 -225
  20. package/dist/components/Sidebar/index.d.ts +0 -60
  21. package/dist/components/Sidebar/index.d.ts.map +0 -1
  22. package/dist/components/Sidebar/index.js +0 -266
  23. package/dist/components/Sidebar/index.js.map +0 -1
  24. package/dist/components/Sidebar/item.d.ts +0 -35
  25. package/dist/components/Sidebar/item.d.ts.map +0 -1
  26. package/dist/components/Sidebar/item.js +0 -98
  27. package/dist/components/Sidebar/item.js.map +0 -1
  28. package/dist/helpers/sidebar.d.ts +0 -5
  29. package/dist/helpers/sidebar.d.ts.map +0 -1
  30. package/dist/helpers/sidebar.js +0 -92
  31. package/dist/helpers/sidebar.js.map +0 -1
  32. package/src/components/Sidebar/index.tsx +0 -536
  33. package/src/components/Sidebar/item.tsx +0 -264
  34. package/src/helpers/sidebar.ts +0 -89
  35. package/src/stories/Sidebar/Sidebar.stories.tsx +0 -97
@@ -1,536 +0,0 @@
1
- import classnames from 'classnames';
2
- import { size } from 'lodash';
3
- import map from 'lodash/map';
4
- import { darken, rgba } from 'polished';
5
- import React, { useState } from 'react';
6
- import Scroll from 'react-scrollbar';
7
- import { useUpdateEffect } from 'react-use';
8
- import styled, { css } from 'styled-components';
9
- import { IReqoreSidebarTheme, IReqoreTheme } from '../../constants/theme';
10
- import { changeLightness, getMainColor, getReadableColor } from '../../helpers/colors';
11
- import { transformMenu } from '../../helpers/sidebar';
12
- import useLatestZIndex from '../../hooks/useLatestZIndex';
13
- import { useReqoreTheme } from '../../hooks/useTheme';
14
- import { ActiveIconScale, InactiveIconScale, ScaleIconOnHover } from '../../styles';
15
- import { IReqoreIconName } from '../../types/icons';
16
- import { ReqoreBackdrop } from '../Drawer/backdrop';
17
- import ReqoreIcon from '../Icon';
18
- import SidebarItem from './item';
19
-
20
- export interface IQorusSidebarCustomItem {
21
- element: React.FC<any>;
22
- }
23
-
24
- export interface IQorusSidebarItems {
25
- [sectionId: string]: {
26
- title?: string | undefined;
27
- items: IQorusSidebarItem[];
28
- };
29
- }
30
-
31
- export interface IQorusSidebarItem {
32
- name: string;
33
- props?: any;
34
- activePaths?: string[];
35
- submenu?: IQorusSidebarItem[];
36
- id: string;
37
- as?: React.ElementType | string;
38
- icon?: IReqoreIconName;
39
- exact?: boolean;
40
- element?: React.ElementType;
41
- }
42
-
43
- export interface IQorusSidebarProps {
44
- isCollapsed?: boolean;
45
- onCollapseChange?: (isCollapsed?: boolean) => void;
46
- items: IQorusSidebarItems;
47
- bookmarks?: string[];
48
- customItems?: IQorusSidebarCustomItem[];
49
- collapseLabel?: string;
50
- closeLabel?: string;
51
- path: string;
52
- wrapperStyle?: React.CSSProperties;
53
- onBookmarksChange?: (bookmarks: string[]) => void;
54
- useNativeTitle?: boolean;
55
- position?: 'left' | 'right';
56
- collapsible?: boolean;
57
- bordered?: boolean;
58
- customTheme?: IReqoreSidebarTheme;
59
- flat?: boolean;
60
- floating?: boolean;
61
- hasFloatingBackdrop?: boolean;
62
- onCloseClick?: () => void;
63
- isOpen?: boolean;
64
- closeOnItemClick?: boolean;
65
- }
66
-
67
- export interface IReqoreSidebarStyle {
68
- expanded?: boolean;
69
- theme: IReqoreTheme;
70
- bordered?: boolean;
71
- position?: 'left' | 'right';
72
- customThemeId?: string;
73
- flat?: boolean;
74
- floating?: boolean;
75
- isOpen?: boolean;
76
- zIndex?: number;
77
- }
78
-
79
- const StyledSidebar = styled.div<IReqoreSidebarStyle>`
80
- // 80px is header + footer
81
- font-size: 14px;
82
- font-weight: 500;
83
- display: flex;
84
- overflow: hidden;
85
- flex-flow: column;
86
- color: ${({ theme }: IReqoreSidebarStyle) =>
87
- theme.sidebar?.color ||
88
- getReadableColor(theme, undefined, undefined, true, getMainColor(theme, 'sidebar'))};
89
- background-color: ${({ theme }) => theme.sidebar?.main || theme.main};
90
- box-shadow: ${({ floating }) =>
91
- floating ? `0px 0px 30px 0px ${rgba('#000000', 0.4)}` : undefined};
92
-
93
- ${({ theme, bordered, position, flat, floating }) =>
94
- !floating &&
95
- css`
96
- ${(position === 'left' || bordered) &&
97
- !flat &&
98
- css`
99
- border-right: 1px solid
100
- ${theme.sidebar?.border || darken(0.05, getMainColor(theme, 'sidebar'))};
101
- `}
102
- ${(position === 'right' || bordered) &&
103
- !flat &&
104
- css`
105
- border-left: 1px solid
106
- ${theme.sidebar?.border || darken(0.05, getMainColor(theme, 'sidebar'))};
107
- `}
108
- `}
109
-
110
- ${({ floating, flat, theme, position, isOpen, zIndex }) =>
111
- floating
112
- ? css`
113
- position: fixed;
114
- top: 10px;
115
- ${position}: ${isOpen ? 10 : -200}px;
116
- bottom: 10px;
117
- border-radius: 10px;
118
- z-index: ${zIndex};
119
- border: ${!flat
120
- ? `1px solid ${theme.sidebar?.border || darken(0.05, getMainColor(theme, 'sidebar'))}`
121
- : undefined};
122
- `
123
- : css`
124
- height: 100%;
125
- `}
126
-
127
- // Custom scrollbar
128
- .sidebarScroll {
129
- flex: 1;
130
- }
131
-
132
- transition: all 0.2s ease-in-out;
133
-
134
- &.expanded {
135
- min-width: 180px !important;
136
- max-width: 180px !important;
137
-
138
- .sidebarItem {
139
- text-align: left;
140
-
141
- span.bp3-icon {
142
- margin-right: 10px;
143
- vertical-align: text-bottom;
144
- }
145
-
146
- .submenuExpand {
147
- margin-left: 10px;
148
- }
149
-
150
- &:hover {
151
- .favorite {
152
- display: block;
153
- }
154
- }
155
- }
156
-
157
- .sidebarSubItem {
158
- padding-left: 24px;
159
- }
160
-
161
- .favorite {
162
- display: none;
163
- opacity: 0.6;
164
- position: absolute;
165
- top: 50%;
166
- transform: translateY(-50%);
167
- right: 10px;
168
-
169
- &:hover {
170
- opacity: 1;
171
- }
172
- }
173
- }
174
-
175
- &:not(.expanded) {
176
- min-width: 50px !important;
177
- max-width: 50px !important;
178
- .sidebarItem,
179
- .sidebarSubItem {
180
- text-align: center;
181
- justify-content: center;
182
- }
183
- }
184
-
185
- // Section
186
- .sidebarSection {
187
- .sidebarLink {
188
- display: inline-block;
189
- color: inherit;
190
- width: 100%;
191
-
192
- .bp3-popover-target {
193
- width: 100%;
194
- }
195
-
196
- &:hover {
197
- text-decoration: none;
198
- }
199
- }
200
-
201
- .sidebarItem.active {
202
- ${ActiveIconScale}
203
-
204
- color: ${({ theme }) =>
205
- theme.sidebar?.item?.activeColor ||
206
- theme.sidebar?.item?.color ||
207
- getReadableColor(theme, undefined, undefined, false, getMainColor(theme, 'sidebar'))};
208
-
209
- background-color: ${({ theme }) =>
210
- theme.sidebar?.item?.activeBackground ||
211
- theme.sidebar?.item?.background ||
212
- darken(0.06, getMainColor(theme, 'sidebar'))};
213
-
214
- span.bp3-icon:not(.favorite) {
215
- color: ${({ theme }) =>
216
- theme.sidebar?.icon?.activeColor ||
217
- theme.sidebar?.item?.activeColor ||
218
- theme.sidebar?.icon?.color ||
219
- theme.sidebar?.item?.color ||
220
- 'inherit'};
221
- }
222
- }
223
-
224
- .sidebarSubItem.active {
225
- ${ActiveIconScale}
226
-
227
- color: ${({ theme }) =>
228
- theme.sidebar?.subItem?.activeColor ||
229
- theme.sidebar?.subItem?.color ||
230
- getReadableColor(theme, undefined, undefined, false, getMainColor(theme, 'sidebar'))};
231
- background-color: ${({ theme }) =>
232
- theme.sidebar?.subItem?.activeBackground ||
233
- theme.sidebar?.subItem?.background ||
234
- darken(0.08, getMainColor(theme, 'sidebar'))};
235
- span.bp3-icon:not(.favorite) {
236
- color: ${({ theme }) =>
237
- theme.sidebar?.icon?.activeColor ||
238
- theme.sidebar?.subItem?.activeColor ||
239
- theme.sidebar?.item?.activeColor ||
240
- theme.sidebar?.icon?.color ||
241
- theme.sidebar?.subItem?.color ||
242
- theme.sidebar?.item?.color ||
243
- 'inherit'};
244
- }
245
- }
246
-
247
- .sidebarItem {
248
- ${InactiveIconScale}
249
-
250
- position: relative;
251
-
252
- span.bp3-icon:not(.favorite) {
253
- display: inline-block;
254
- font-size: 16px;
255
- color: ${({ theme }) => theme.sidebar?.icon?.color || 'inherit'};
256
- }
257
-
258
- padding: 12px;
259
- }
260
-
261
- .sidebarItem,
262
- .bp3-popover-wrapper.reqore-sidebar-item {
263
- color: ${({ theme }) => theme.sidebar?.item?.color || 'inherit'};
264
-
265
- background-color: ${({ theme }) =>
266
- theme.sidebar?.item?.background || getMainColor(theme, 'sidebar')};
267
-
268
- &:hover {
269
- ${ScaleIconOnHover}
270
-
271
- color: ${({ theme }) =>
272
- theme.sidebar?.item?.hoverColor || theme.sidebar?.item?.color || 'inherit'};
273
- background-color: ${({ theme }) =>
274
- theme.sidebar?.item?.hoverBackground ||
275
- theme.sidebar?.item?.background ||
276
- darken(0.03, getMainColor(theme, 'sidebar'))};
277
-
278
- span.bp3-icon:not(.favorite) {
279
- color: ${({ theme }) =>
280
- theme.sidebar?.icon?.hoverColor ||
281
- theme.sidebar?.item?.hoverColor ||
282
- theme.sidebar?.icon?.color ||
283
- theme.sidebar?.item?.color ||
284
- 'inherit'};
285
- }
286
- }
287
- }
288
-
289
- .sidebarSubItem {
290
- border-left: 5px solid
291
- ${({ theme }) => {
292
- if (theme.sidebar?.subItem?.border) {
293
- return theme.sidebar?.subItem?.border;
294
- }
295
-
296
- const color = getMainColor(theme, 'sidebar');
297
-
298
- return changeLightness(color, 0.17);
299
- }};
300
- }
301
-
302
- .sidebarSubItem,
303
- .bp3-popover-wrapper.reqore-sidebar-subitem {
304
- color: ${({ theme }) => theme.sidebar?.subItem?.color || 'inherit'};
305
-
306
- background-color: ${({ theme }) =>
307
- theme.sidebar?.subItem?.background || darken(0.04, getMainColor(theme, 'sidebar'))};
308
-
309
- &:hover {
310
- ${ScaleIconOnHover}
311
-
312
- color: ${({ theme }) =>
313
- theme.sidebar?.subItem?.hoverColor || theme.sidebar?.subItem?.color || 'inherit'};
314
- background-color: ${({ theme }) =>
315
- theme.sidebar?.subItem?.hoverBackground ||
316
- theme.sidebar?.subItem?.background ||
317
- darken(0.06, getMainColor(theme, 'sidebar'))};
318
-
319
- span.bp3-icon:not(.favorite) {
320
- color: ${({ theme }) =>
321
- theme.sidebar?.icon?.hoverColor ||
322
- theme.sidebar?.subItem?.hoverColor ||
323
- theme.sidebar?.icon?.color ||
324
- theme.sidebar?.subItem?.color ||
325
- 'inherit'};
326
- }
327
- }
328
- }
329
-
330
- .sidebarItem,
331
- .sidebarSubItem {
332
- min-height: 50px;
333
- display: flex;
334
- align-items: center;
335
- cursor: pointer;
336
- transition: all 0.2s ease-in-out;
337
-
338
- &.active {
339
- font-weight: 500;
340
- }
341
- }
342
- }
343
- `;
344
-
345
- const StyledDivider = styled.div<{ theme?: any; hasTitle?: boolean }>`
346
- width: 100%;
347
- text-transform: uppercase;
348
- font-size: 11px;
349
- font-weight: 600;
350
- display: flex;
351
- justify-content: center;
352
- align-items: center;
353
- letter-spacing: 1.8px;
354
- margin-top: 0;
355
- padding: 8px;
356
-
357
- background-color: ${({ theme, hasTitle }) =>
358
- theme.sidebar?.section?.background ||
359
- (hasTitle ? darken(0.02, getMainColor(theme, 'sidebar')) : getMainColor(theme, 'sidebar'))};
360
- color: inherit;
361
- `;
362
-
363
- const ReqoreSidebar: React.FC<IQorusSidebarProps> = ({
364
- isCollapsed,
365
- onCollapseChange,
366
- onCloseClick,
367
- path,
368
- items,
369
- bookmarks,
370
- customItems,
371
- collapseLabel,
372
- closeLabel,
373
- wrapperStyle,
374
- onBookmarksChange,
375
- useNativeTitle,
376
- position = 'left',
377
- collapsible = true,
378
- bordered,
379
- customTheme,
380
- flat,
381
- floating,
382
- hasFloatingBackdrop,
383
- isOpen,
384
- closeOnItemClick,
385
- }) => {
386
- const [_isCollapsed, setIsCollapsed] = useState<boolean>(isCollapsed || false);
387
- useState;
388
- const [expandedSection, setExpandedSection] = useState<string | null>(null);
389
- const [_bookmarks, setBookmarks] = useState<string[]>(bookmarks || []);
390
- const theme: IReqoreTheme = useReqoreTheme('sidebar', customTheme);
391
- const zIndex = useLatestZIndex();
392
-
393
- useUpdateEffect(() => {
394
- if (onBookmarksChange) {
395
- onBookmarksChange(_bookmarks);
396
- }
397
- }, [_bookmarks]);
398
-
399
- useUpdateEffect(() => {
400
- setIsCollapsed(isCollapsed);
401
- }, [isCollapsed]);
402
-
403
- const handleSectionToggle: (sectionId: string) => void = (sectionId) => {
404
- setExpandedSection((currentExpandedSection) =>
405
- sectionId === currentExpandedSection ? null : sectionId
406
- );
407
- };
408
-
409
- const handleFavoriteClick = (id: string) => {
410
- setBookmarks((current) => {
411
- return [...current, id];
412
- });
413
- };
414
-
415
- const handleUnfavoriteClick = (id: string) => {
416
- setBookmarks((current) => {
417
- return [...current].filter((item) => item !== id);
418
- });
419
- };
420
-
421
- const menu: IQorusSidebarItems = transformMenu(items, _bookmarks, customItems);
422
-
423
- return (
424
- <>
425
- {floating && hasFloatingBackdrop && isOpen ? (
426
- <ReqoreBackdrop
427
- className='reqore-sidebar-backdrop'
428
- onClose={() => onCloseClick?.()}
429
- zIndex={zIndex}
430
- />
431
- ) : null}
432
- <StyledSidebar
433
- className={classnames('sidebar', {
434
- expanded: !_isCollapsed,
435
- })}
436
- style={wrapperStyle}
437
- role='qorus-sidebar-wrapper'
438
- position={position}
439
- bordered={bordered}
440
- theme={theme}
441
- flat={flat}
442
- floating={floating}
443
- isOpen={isOpen}
444
- zIndex={zIndex}
445
- >
446
- <Scroll horizontal={false} className='sidebarScroll' key='reqore-sidebar-scroll'>
447
- {map(menu, ({ title, items }, sectionId: string) =>
448
- size(items) ? (
449
- <>
450
- {sectionId !== '_qorusCustomElements' && (
451
- <StyledDivider hasTitle={!!title} key={sectionId + 'title'} theme={theme}>
452
- {!_isCollapsed ? title || '' : ''}
453
- </StyledDivider>
454
- )}
455
- <div className='sidebarSection' key={sectionId} role='qorus-sidebar-section-title'>
456
- {map(items, (itemData, key) => (
457
- <SidebarItem
458
- itemData={itemData}
459
- key={key}
460
- isCollapsed={_isCollapsed}
461
- expandedSection={expandedSection}
462
- onSectionToggle={handleSectionToggle}
463
- bookmarks={bookmarks}
464
- currentPath={path}
465
- onFavoriteClick={handleFavoriteClick}
466
- onUnfavoriteClick={handleUnfavoriteClick}
467
- sectionName={sectionId}
468
- hasFavorites={!!onBookmarksChange}
469
- useNativeTitle={useNativeTitle}
470
- onClick={
471
- closeOnItemClick && onCloseClick ? () => void onCloseClick() : undefined
472
- }
473
- />
474
- ))}
475
- </div>
476
- </>
477
- ) : null
478
- )}
479
- </Scroll>
480
- <StyledDivider theme={theme} />
481
- {collapsible && (
482
- <div className='sidebarSection' id='menuCollapse'>
483
- <div
484
- role='qorus-sidebar-collapse-button'
485
- className='sidebarItem'
486
- style={{
487
- justifyContent: _isCollapsed
488
- ? 'center'
489
- : position === 'left'
490
- ? 'flex-start'
491
- : 'flex-end',
492
- }}
493
- onClick={() => {
494
- setIsCollapsed(!_isCollapsed);
495
-
496
- if (onCollapseChange) {
497
- onCollapseChange(!_isCollapsed);
498
- }
499
- }}
500
- >
501
- {position === 'left' && (
502
- <ReqoreIcon icon={isCollapsed ? 'ArrowRightSLine' : 'ArrowLeftSLine'} />
503
- )}{' '}
504
- {!_isCollapsed && (collapseLabel || 'Collapse')}
505
- {position === 'right' && (
506
- <ReqoreIcon icon={_isCollapsed ? 'ArrowLeftSLine' : 'ArrowRightSLine'} />
507
- )}{' '}
508
- </div>
509
- </div>
510
- )}
511
- {floating && onCloseClick ? (
512
- <div className='sidebarSection' id='menuClose'>
513
- <div
514
- role='qorus-sidebar-close-button'
515
- className='sidebarItem'
516
- style={{
517
- justifyContent: _isCollapsed
518
- ? 'center'
519
- : position === 'left'
520
- ? 'flex-start'
521
- : 'flex-end',
522
- }}
523
- onClick={() => void onCloseClick()}
524
- >
525
- {position === 'left' && <ReqoreIcon icon='CloseLine' />}{' '}
526
- {!_isCollapsed && (closeLabel || 'Close')}
527
- {position === 'right' && <ReqoreIcon icon='CloseLine' />}{' '}
528
- </div>
529
- </div>
530
- ) : null}
531
- </StyledSidebar>
532
- </>
533
- );
534
- };
535
-
536
- export default ReqoreSidebar;