superdesk-ui-framework 3.0.66 → 3.0.68

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 (78) hide show
  1. package/app/styles/components/_list-item.scss +22 -11
  2. package/app-typescript/components/Autocomplete.tsx +9 -3
  3. package/app-typescript/components/Badge.tsx +16 -2
  4. package/app-typescript/components/Dropdown.tsx +3 -1
  5. package/app-typescript/components/DropdownFirst.tsx +14 -2
  6. package/app-typescript/components/DurationInput.tsx +19 -4
  7. package/app-typescript/components/EmptyState.tsx +11 -2
  8. package/app-typescript/components/Layouts/Panel.tsx +12 -1
  9. package/app-typescript/components/Lists/ContentList.tsx +5 -1
  10. package/app-typescript/components/Modal.tsx +10 -1
  11. package/app-typescript/components/Navigation/BottomNav.tsx +9 -2
  12. package/app-typescript/components/Navigation/QuickNavBar.tsx +10 -2
  13. package/app-typescript/components/Navigation/SideBarMenu.tsx +9 -4
  14. package/app-typescript/components/SidebarMenu.tsx +8 -1
  15. package/app-typescript/components/TabList.tsx +5 -1
  16. package/app-typescript/components/TagInput.tsx +4 -1
  17. package/app-typescript/components/ThemeSelector.tsx +13 -2
  18. package/app-typescript/components/TreeMenu.tsx +127 -122
  19. package/app-typescript/components/TreeSelect/TreeSelect.tsx +157 -141
  20. package/app-typescript/components/WithPortal.tsx +49 -0
  21. package/app-typescript/components/avatar/avatar-image.tsx +2 -0
  22. package/app-typescript/components/avatar/avatar.tsx +2 -1
  23. package/dist/examples.bundle.js +1446 -1318
  24. package/dist/playgrounds/planning.html +121 -43
  25. package/dist/playgrounds/react-playgrounds/CoreLayout.tsx +398 -385
  26. package/dist/playgrounds/react-playgrounds/EditorTest.tsx +359 -365
  27. package/dist/playgrounds/react-playgrounds/FirstPlayground.tsx +33 -33
  28. package/dist/playgrounds/react-playgrounds/Multiedit.tsx +227 -231
  29. package/dist/playgrounds/react-playgrounds/PageLayoutTest.tsx +41 -38
  30. package/dist/playgrounds/react-playgrounds/PersonalProfile.tsx +76 -96
  31. package/dist/playgrounds/react-playgrounds/RundownEditor.tsx +73 -101
  32. package/dist/playgrounds/react-playgrounds/Rundowns.tsx +788 -729
  33. package/dist/playgrounds/react-playgrounds/SamsPlayground.tsx +35 -26
  34. package/dist/playgrounds/react-playgrounds/TestGround.tsx +99 -128
  35. package/dist/playgrounds/react-playgrounds/UiPlayground.tsx +40 -25
  36. package/dist/playgrounds/react-playgrounds/components/GraphicButton.tsx +6 -5
  37. package/dist/playgrounds/react-playgrounds/components/Layout.tsx +0 -2
  38. package/dist/playgrounds/react-playgrounds/components/SearchBar.tsx +16 -9
  39. package/dist/playgrounds/react-playgrounds/tsconfig.json +4 -0
  40. package/dist/superdesk-ui.bundle.css +24 -14
  41. package/dist/superdesk-ui.bundle.js +830 -727
  42. package/dist/vendor.bundle.js +14 -14
  43. package/examples/pages/playgrounds/planning.html +121 -43
  44. package/examples/pages/playgrounds/react-playgrounds/CoreLayout.tsx +398 -385
  45. package/examples/pages/playgrounds/react-playgrounds/EditorTest.tsx +359 -365
  46. package/examples/pages/playgrounds/react-playgrounds/FirstPlayground.tsx +33 -33
  47. package/examples/pages/playgrounds/react-playgrounds/Multiedit.tsx +227 -231
  48. package/examples/pages/playgrounds/react-playgrounds/PageLayoutTest.tsx +41 -38
  49. package/examples/pages/playgrounds/react-playgrounds/PersonalProfile.tsx +76 -96
  50. package/examples/pages/playgrounds/react-playgrounds/RundownEditor.tsx +73 -101
  51. package/examples/pages/playgrounds/react-playgrounds/Rundowns.tsx +788 -729
  52. package/examples/pages/playgrounds/react-playgrounds/SamsPlayground.tsx +35 -26
  53. package/examples/pages/playgrounds/react-playgrounds/TestGround.tsx +99 -128
  54. package/examples/pages/playgrounds/react-playgrounds/UiPlayground.tsx +40 -25
  55. package/examples/pages/playgrounds/react-playgrounds/components/GraphicButton.tsx +6 -5
  56. package/examples/pages/playgrounds/react-playgrounds/components/Layout.tsx +0 -2
  57. package/examples/pages/playgrounds/react-playgrounds/components/SearchBar.tsx +16 -9
  58. package/examples/pages/playgrounds/react-playgrounds/tsconfig.json +4 -0
  59. package/package.json +3 -2
  60. package/react/components/Autocomplete.js +2 -2
  61. package/react/components/Badge.js +1 -1
  62. package/react/components/Dropdown.js +3 -1
  63. package/react/components/DropdownFirst.js +6 -2
  64. package/react/components/DurationInput.js +5 -1
  65. package/react/components/EmptyState.js +2 -1
  66. package/react/components/Lists/ContentList.js +1 -1
  67. package/react/components/Navigation/BottomNav.js +4 -1
  68. package/react/components/Navigation/QuickNavBar.js +2 -1
  69. package/react/components/Navigation/SideBarMenu.js +3 -1
  70. package/react/components/TabList.js +2 -1
  71. package/react/components/TagInput.js +1 -1
  72. package/react/components/TreeSelect/TreeSelect.d.ts +3 -2
  73. package/react/components/TreeSelect/TreeSelect.js +81 -73
  74. package/react/components/WithPortal.d.ts +14 -0
  75. package/react/components/WithPortal.js +69 -0
  76. package/react/components/avatar/avatar.js +2 -1
  77. /package/dist/playgrounds/dummy-data/{items.js → items.ts} +0 -0
  78. /package/examples/pages/playgrounds/dummy-data/{items.js → items.ts} +0 -0
@@ -4,6 +4,7 @@ import { createPopper, Instance } from '@popperjs/core';
4
4
  import {getPrefixedItemId, TreeSelectItem} from './TreeSelect/TreeSelectItem';
5
5
  import {keyboardNavigation} from './TreeSelect/KeyboardNavigation';
6
6
  import {createPortal} from 'react-dom';
7
+ import {WithPortal} from './WithPortal';
7
8
 
8
9
  interface IState<T> {
9
10
  options: Array<ITreeMenuNode<T>>;
@@ -23,6 +24,7 @@ interface IProps<T> {
23
24
  zIndex?: number;
24
25
  searchPlaceholder?: string;
25
26
  singleLevelSearch?: boolean;
27
+ 'data-test-id'?: string;
26
28
  getOptions?(): Array<ITreeMenuNode<T>>;
27
29
  getLabel(item: T): string;
28
30
  getId(item: T): string;
@@ -57,7 +59,7 @@ export class TreeMenu<T> extends React.Component<IProps<T>, IState<T>> {
57
59
  private dropdownRef: React.RefObject<HTMLInputElement>;
58
60
  private ref: React.RefObject<HTMLUListElement>;
59
61
  private openDropdownRef: React.RefObject<HTMLDivElement>;
60
- private treeSelectRef: React.RefObject<HTMLDivElement>;
62
+ private treeMenuRef: React.RefObject<HTMLDivElement>;
61
63
  private inputRef: React.RefObject<HTMLInputElement>;
62
64
  private popperInstance: Instance | null;
63
65
 
@@ -80,14 +82,15 @@ export class TreeMenu<T> extends React.Component<IProps<T>, IState<T>> {
80
82
  this.handleButton = this.handleButton.bind(this);
81
83
  this.handleTree = this.handleTree.bind(this);
82
84
  this.toggleMenu = this.toggleMenu.bind(this);
85
+ this.toggle = this.toggle.bind(this);
83
86
  this.onMouseDown = this.onMouseDown.bind(this);
84
87
  this.onKeyDown = this.onKeyDown.bind(this);
85
- this.toggle = this.toggle.bind(this);
88
+ this.onPressEsc = this.onPressEsc.bind(this);
86
89
 
87
90
  this.dropdownRef = React.createRef();
88
91
  this.ref = React.createRef();
89
92
  this.openDropdownRef = React.createRef();
90
- this.treeSelectRef = React.createRef();
93
+ this.treeMenuRef = React.createRef();
91
94
  this.inputRef = React.createRef();
92
95
 
93
96
  this.popperInstance = null;
@@ -105,10 +108,13 @@ export class TreeMenu<T> extends React.Component<IProps<T>, IState<T>> {
105
108
  onMouseDown = (event: MouseEvent) => {
106
109
  if (
107
110
  (this.dropdownRef.current?.contains(event.target as HTMLElement) !== true)
108
- && (this.treeSelectRef.current?.contains(event.target as HTMLElement) !== true)
111
+ && (this.treeMenuRef.current?.contains(event.target as HTMLElement) !== true)
109
112
  && this.state.openDropdown
110
113
  ) {
111
- this.setState({openDropdown: false});
114
+ this.setState({
115
+ openDropdown: false,
116
+ searchFieldValue: '',
117
+ });
112
118
  }
113
119
  }
114
120
 
@@ -134,16 +140,27 @@ export class TreeMenu<T> extends React.Component<IProps<T>, IState<T>> {
134
140
  }
135
141
  }
136
142
 
143
+ onPressEsc = (event: KeyboardEvent) => {
144
+ if (event.key === 'Escape' && this.state.openDropdown) {
145
+ this.setState({
146
+ openDropdown: false,
147
+ searchFieldValue: '',
148
+ });
149
+ }
150
+ }
151
+
137
152
  componentDidMount = () => {
138
153
  this.recursion(this.state.options);
139
154
 
140
155
  document.addEventListener("mousedown", this.onMouseDown);
141
156
  document.addEventListener("keydown", this.onKeyDown);
157
+ document.addEventListener("keydown", this.onPressEsc);
142
158
  }
143
159
 
144
160
  componentWillUnmount(): void {
145
161
  document.removeEventListener("mousedown", this.onMouseDown);
146
162
  document.removeEventListener("keydown", this.onKeyDown);
163
+ document.addEventListener("keydown", this.onPressEsc);
147
164
  }
148
165
 
149
166
  componentDidUpdate(prevProps: Readonly<IProps<T>>, prevState: Readonly<IState<T>>): void {
@@ -165,14 +182,6 @@ export class TreeMenu<T> extends React.Component<IProps<T>, IState<T>> {
165
182
  if (this.openDropdownRef.current && this.dropdownRef.current) {
166
183
  this.popperInstance = createPopper(this.openDropdownRef.current, this.dropdownRef.current, {
167
184
  placement: 'bottom-start',
168
- modifiers: [
169
- {
170
- name: 'offset',
171
- options: {
172
- offset: [-4, 4],
173
- },
174
- },
175
- ],
176
185
  });
177
186
  }
178
187
 
@@ -335,125 +344,121 @@ export class TreeMenu<T> extends React.Component<IProps<T>, IState<T>> {
335
344
 
336
345
  render() {
337
346
  return (
338
- <div ref={this.treeSelectRef}>
347
+ <div ref={this.treeMenuRef}>
339
348
  <div ref={this.openDropdownRef}>
340
349
  {this.props.children(this.toggle)}
341
350
  </div>
342
351
 
343
- {createPortal(
344
- this.state.openDropdown
345
- && <div id='TREEMENU_DROPDOWN'>
352
+ <WithPortal active={this.state.openDropdown} data-test-id="tree-menu-popover">
353
+ <div
354
+ ref={this.dropdownRef}
355
+ className="autocomplete autocomplete--multi-select autocomplete--fixed-width"
356
+ style={{
357
+ zIndex: this.props.zIndex,
358
+ }}
359
+ >
360
+ <div className='autocomplete__header'>
346
361
  <div
347
- ref={this.dropdownRef}
348
- className="autocomplete autocomplete--multi-select autocomplete--fixed-width"
349
- style={{
350
- zIndex: this.props.zIndex,
362
+ className="autocomplete__icon"
363
+ onClick={() => {
364
+ this.backButton();
351
365
  }}
352
366
  >
353
- <div className='autocomplete__header'>
354
- <div
355
- className="autocomplete__icon"
356
- onClick={() => {
357
- this.backButton();
358
- }}
359
- >
360
- <Icon name="search" className="search"></Icon>
361
- </div>
362
-
363
- <div className='autocomplete__filter'>
364
- <input
365
- className="autocomplete__input"
366
- type="text"
367
- placeholder={this.props.searchPlaceholder}
368
- ref={this.inputRef}
369
- value={this.state.searchFieldValue}
370
- onChange={(event) => {
371
- this.setState({searchFieldValue: event.target.value});
372
- this.popperInstance?.update();
373
- }}
374
- />
375
- </div>
367
+ <Icon name="search" className="search"></Icon>
368
+ </div>
369
+
370
+ <div className='autocomplete__filter'>
371
+ <input
372
+ className="autocomplete__input"
373
+ type="text"
374
+ placeholder={this.props.searchPlaceholder}
375
+ ref={this.inputRef}
376
+ value={this.state.searchFieldValue}
377
+ onChange={(event) => {
378
+ this.setState({searchFieldValue: event.target.value});
379
+ this.popperInstance?.update();
380
+ }}
381
+ />
382
+ </div>
383
+ </div>
384
+
385
+ {(this.state.activeTree.length > 0 && this.state.buttonValue != null)
386
+ && <div className='autocomplete__category-header'>
387
+ <div
388
+ className="autocomplete__icon"
389
+ onClick={() => {
390
+ this.backButton();
391
+ }}
392
+ >
393
+ <Icon name="arrow-left" className="arrow-left"></Icon>
376
394
  </div>
377
395
 
378
- {(this.state.activeTree.length > 0 && this.state.buttonValue != null)
379
- && <div className='autocomplete__category-header'>
380
- <div
381
- className="autocomplete__icon"
382
- onClick={() => {
383
- this.backButton();
384
- }}
385
- >
386
- <Icon name="arrow-left" className="arrow-left"></Icon>
387
- </div>
388
-
389
- <div className='autocomplete__filter'>
390
- <button className='autocomplete__category-title'>
391
- {this.props.optionTemplate
392
- ? this.props.optionTemplate(this.state.buttonValue.value)
393
- : this.props.getLabel(this.state.buttonValue.value)
394
- }
395
- </button>
396
- </div>
397
- </div>
398
- }
399
-
400
- {this.state.searchFieldValue === '' ?
401
- this.props.getOptions ?
402
- <ul
403
- ref={this.ref}
404
- className="suggestion-list suggestion-list--multi-select"
405
- >
406
- {this.state.options.map((option, i: React.Key | undefined) => {
407
- const onSelect = (item) => {
408
- if (nodeCanBeSelected(item)) {
409
- return item.onSelect;
410
- }
411
- };
412
-
413
- const disabledItem = (item) => {
414
- if (nodeCanBeSelected(item)) {
415
- return item.disabled;
416
- }
417
- };
418
-
419
- return (
420
- <TreeSelectItem
421
- key={i}
422
- option={option}
423
- handleTree={this.handleTree}
424
- onClick={onSelect(option)}
425
- disabledItem={disabledItem(option)}
426
- getBorderColor={this.props.getBorderColor}
427
- getBackgroundColor={this.props.getBackgroundColor}
428
- getId={this.props.getId}
429
- optionTemplate={this.props.optionTemplate}
430
- getLabel={this.props.getLabel}
431
- onKeyDown={() => this.setState({
432
- buttonTarget: [
433
- ...this.state.buttonTarget,
434
- this.props.getId(option.value),
435
- ],
436
- })}
437
- />
438
- );
439
- })}
440
- </ul>
441
- : null
442
- : <ul
443
- className="suggestion-list suggestion-list--multi-select"
444
- ref={this.ref}
445
- >
446
- {this.filteredItem(
447
- this.props.singleLevelSearch
448
- ? this.state.options
449
- : this.state.filterArr,
450
- )}
451
- </ul>
452
- }
396
+ <div className='autocomplete__filter'>
397
+ <button className='autocomplete__category-title'>
398
+ {this.props.optionTemplate
399
+ ? this.props.optionTemplate(this.state.buttonValue.value)
400
+ : this.props.getLabel(this.state.buttonValue.value)
401
+ }
402
+ </button>
403
+ </div>
453
404
  </div>
454
- </div>,
455
- document.body,
456
- )}
405
+ }
406
+
407
+ {this.state.searchFieldValue === '' ?
408
+ this.props.getOptions ?
409
+ <ul
410
+ ref={this.ref}
411
+ className="suggestion-list suggestion-list--multi-select"
412
+ >
413
+ {this.state.options.map((option, i: React.Key | undefined) => {
414
+ const onSelect = (item) => {
415
+ if (nodeCanBeSelected(item)) {
416
+ return item.onSelect;
417
+ }
418
+ };
419
+
420
+ const disabledItem = (item) => {
421
+ if (nodeCanBeSelected(item)) {
422
+ return item.disabled;
423
+ }
424
+ };
425
+
426
+ return (
427
+ <TreeSelectItem
428
+ key={i}
429
+ option={option}
430
+ handleTree={this.handleTree}
431
+ onClick={onSelect(option)}
432
+ disabledItem={disabledItem(option)}
433
+ getBorderColor={this.props.getBorderColor}
434
+ getBackgroundColor={this.props.getBackgroundColor}
435
+ getId={this.props.getId}
436
+ optionTemplate={this.props.optionTemplate}
437
+ getLabel={this.props.getLabel}
438
+ onKeyDown={() => this.setState({
439
+ buttonTarget: [
440
+ ...this.state.buttonTarget,
441
+ this.props.getId(option.value),
442
+ ],
443
+ })}
444
+ />
445
+ );
446
+ })}
447
+ </ul>
448
+ : null
449
+ : <ul
450
+ className="suggestion-list suggestion-list--multi-select"
451
+ ref={this.ref}
452
+ >
453
+ {this.filteredItem(
454
+ this.props.singleLevelSearch
455
+ ? this.state.options
456
+ : this.state.filterArr,
457
+ )}
458
+ </ul>
459
+ }
460
+ </div>
461
+ </WithPortal>
457
462
  </div>
458
463
  );
459
464
  }