superdesk-ui-framework 3.0.1-beta.25 → 3.0.1-beta.26

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/app/styles/_sd-tag-input.scss +36 -1
  2. package/app/styles/_table-list.scss +1 -0
  3. package/app/styles/primereact/_pr-dialog.scss +4 -0
  4. package/app-typescript/components/Label.tsx +10 -6
  5. package/app-typescript/components/Layouts/AuthoringFrame.tsx +2 -1
  6. package/app-typescript/components/Layouts/AuthoringFrameRightBar.tsx +21 -2
  7. package/app-typescript/components/Lists/TableList.tsx +62 -2
  8. package/app-typescript/components/Menu.tsx +2 -2
  9. package/app-typescript/components/Spacer.tsx +1 -1
  10. package/app-typescript/components/TreeSelect.tsx +85 -33
  11. package/dist/examples.bundle.js +1549 -1184
  12. package/dist/playgrounds/react-playgrounds/Index.tsx +1 -0
  13. package/dist/playgrounds/react-playgrounds/Multiedit.tsx +321 -0
  14. package/dist/react/TableList.tsx +2 -0
  15. package/dist/react/TreeSelect.tsx +100 -78
  16. package/dist/superdesk-ui.bundle.css +34 -2
  17. package/dist/superdesk-ui.bundle.js +1132 -1059
  18. package/dist/vendor.bundle.js +4 -4
  19. package/examples/index.js +4 -0
  20. package/examples/pages/playgrounds/react-playgrounds/Index.tsx +1 -0
  21. package/examples/pages/playgrounds/react-playgrounds/Multiedit.tsx +321 -0
  22. package/examples/pages/react/TableList.tsx +2 -0
  23. package/examples/pages/react/TreeSelect.tsx +100 -78
  24. package/package.json +1 -1
  25. package/react/components/Label.d.ts +1 -1
  26. package/react/components/Label.js +10 -5
  27. package/react/components/Layouts/AuthoringFrame.d.ts +1 -0
  28. package/react/components/Layouts/AuthoringFrame.js +1 -1
  29. package/react/components/Layouts/AuthoringFrameRightBar.d.ts +9 -2
  30. package/react/components/Layouts/AuthoringFrameRightBar.js +14 -3
  31. package/react/components/Lists/TableList.d.ts +1 -0
  32. package/react/components/Lists/TableList.js +34 -6
  33. package/react/components/Menu.js +1 -1
  34. package/react/components/TreeSelect.d.ts +3 -1
  35. package/react/components/TreeSelect.js +50 -23
@@ -276,6 +276,7 @@ tags-input,
276
276
  }
277
277
  }
278
278
  .suggestion-item {
279
+ position: relative;
279
280
  padding: 0.5rem 1rem;
280
281
  cursor: pointer;
281
282
  white-space: nowrap;
@@ -312,6 +313,20 @@ tags-input,
312
313
  justify-content: space-between;
313
314
  align-items: center;
314
315
  }
316
+ .suggestion-item--bgcolor {
317
+ min-height: 1.5em;
318
+ min-width: 1.5em;
319
+ padding: 4px 0;
320
+ display: inline-flex;
321
+ justify-content: center;
322
+ align-items: center;
323
+ border-radius: 99px;
324
+ white-space: nowrap;
325
+
326
+ &[style] {
327
+ padding-inline: 8px;
328
+ }
329
+ }
315
330
  .suggestion-item--disabled {
316
331
  opacity: 0.5;
317
332
  }
@@ -493,6 +508,11 @@ tags-input,
493
508
  }
494
509
  }
495
510
 
511
+ .tags-input--single-select {
512
+ display: grid !important;
513
+ align-items: center !important;
514
+ }
515
+
496
516
  .tags-input--multi-select,
497
517
  .tags-input--single-select {
498
518
  position: relative;
@@ -546,7 +566,7 @@ tags-input,
546
566
  .tags-input__remove-button {
547
567
  display: flex;
548
568
  align-items: center;
549
- align-self: flex-end;
569
+ align-self: center;
550
570
  margin-inline-start: auto;
551
571
  z-index: 2;
552
572
  cursor: pointer;
@@ -561,3 +581,18 @@ tags-input,
561
581
  font-weight: 300;
562
582
  }
563
583
  }
584
+
585
+ .item-border {
586
+ width: 5px;
587
+ z-index: 2;
588
+ position: absolute;
589
+ inset-block: 7px;
590
+ inset-inline-start: 3px;
591
+ border-radius: 2px;
592
+
593
+ &-selected {
594
+ inset-block: 5px;
595
+ }
596
+ }
597
+
598
+
@@ -6,6 +6,7 @@
6
6
  flex-direction: column;
7
7
  align-self: stretch;
8
8
  overflow: hidden !important;
9
+ padding: 1px;
9
10
  //gap: $sd-base-increment * 1.5;
10
11
  &--comfortable {
11
12
  gap: $sd-base-increment * 2;
@@ -43,6 +43,10 @@
43
43
  overflow-y: auto;
44
44
  }
45
45
 
46
+ .p-dialog-flex {
47
+ display: flex;
48
+ }
49
+
46
50
  .p-dialog-header {
47
51
  display: flex;
48
52
  align-items: center;
@@ -78,11 +78,15 @@ export class Label extends React.PureComponent<IProps> {
78
78
  }
79
79
  }
80
80
 
81
- export function getTextColor(backgroundColor: string): 'black' | 'white' {
82
- const r = parseInt(backgroundColor.substr(1, 2), 16);
83
- const g = parseInt(backgroundColor.substr(3, 2), 16);
84
- const b = parseInt(backgroundColor.substr(5, 2), 16);
85
- const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
81
+ export function getTextColor(backgroundColor: string): 'black' | 'white' | undefined {
82
+ if (backgroundColor) {
83
+ const r = parseInt(backgroundColor.substr(1, 2), 16);
84
+ const g = parseInt(backgroundColor.substr(3, 2), 16);
85
+ const b = parseInt(backgroundColor.substr(5, 2), 16);
86
+ const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
86
87
 
87
- return (yiq >= 128) ? 'black' : 'white';
88
+ return (yiq >= 128) ? 'black' : 'white';
89
+ } else {
90
+ return;
91
+ }
88
92
  }
@@ -16,6 +16,7 @@ interface IProps {
16
16
  header?: React.ReactNode;
17
17
  main?: React.ReactNode;
18
18
  sideBar?: React.ReactNode;
19
+ sideBarClosed?: boolean;
19
20
  sidePanel?: React.ReactNode;
20
21
  sideOverlay?: React.ReactNode;
21
22
  sideOverlayOpen?: boolean;
@@ -56,7 +57,7 @@ export class AuthoringFrame extends React.PureComponent<IProps> {
56
57
  </AuthoringFrameSidePanelOverlay>
57
58
  )}
58
59
  {this.props.sideBar && (
59
- <AuthoringFrameRightBar>
60
+ <AuthoringFrameRightBar closed={this.props.sideBarClosed}>
60
61
  {this.props.sideBar}
61
62
  </AuthoringFrameRightBar>
62
63
  )}
@@ -2,12 +2,31 @@ import * as React from 'react';
2
2
 
3
3
  interface IProps {
4
4
  children?: React.ReactNode;
5
+ closed?: boolean;
5
6
  }
6
7
 
7
- export class AuthoringFrameRightBar extends React.PureComponent<IProps> {
8
+ interface IState {
9
+ children?: React.ReactNode;
10
+ closed?: boolean;
11
+ }
12
+
13
+ export class AuthoringFrameRightBar extends React.PureComponent<IProps, IState> {
14
+ constructor(props: IProps) {
15
+ super(props);
16
+ this.state = {
17
+ closed: this.props.closed ? this.props.closed : false,
18
+ };
19
+ }
20
+ componentDidUpdate(prevProps: Readonly<IProps>): void {
21
+ if (prevProps.closed !== this.props.closed) {
22
+ this.setState({
23
+ closed: this.props.closed,
24
+ });
25
+ }
26
+ }
8
27
  render() {
9
28
  return (
10
- <div className="sd-editor-grid__sidetabs-bar">
29
+ !this.state.closed && <div className="sd-editor-grid__sidetabs-bar">
11
30
  {this.props.children}
12
31
  </div>
13
32
  );
@@ -4,6 +4,7 @@ import { DragDropContext, Droppable, Draggable, DropResult } from "react-beautif
4
4
  import { Tooltip } from '../Tooltip';
5
5
  import { Button } from '../Button';
6
6
  import { Dropdown, IMenuItem, ISubmenu, IMenuGroup } from '../Dropdown';
7
+ import ReactDOM from 'react-dom';
7
8
 
8
9
  export interface IProps {
9
10
  array: Array<IPropsArrayItem>;
@@ -12,6 +13,7 @@ export interface IProps {
12
13
  className?: string;
13
14
  readOnly?: boolean;
14
15
  showDragHandle?: 'always' | 'onHover' | 'none'; // always default
16
+ append?: boolean;
15
17
  onDrag?(start: number, end: number): void;
16
18
  onAddItem?(index: number, item?: IPropsArrayItem ): void;
17
19
  itemsDropdown?(index?: number): Array<IMenuItem | ISubmenu | IMenuGroup | 'divider'>;
@@ -122,8 +124,23 @@ class TableList extends React.PureComponent<IProps, IState> {
122
124
  {...provided.droppableProps} >
123
125
  {this.state.items.map((item: IPropsArrayItem, index: number) => (
124
126
  <Draggable key={index} draggableId={`${index}`} index={index}>
125
- {(provided2, _snapshot2) => (
126
- <div
127
+ {(provided2, snapshot) => (
128
+ this.props.append
129
+ ? <PortalItem
130
+ provided={provided2}
131
+ snapshot={snapshot}
132
+ item={item}
133
+ index={index}
134
+ dragAndDrop={this.props.dragAndDrop}
135
+ showDragHandle={this.props.showDragHandle}
136
+ addItem={this.props.addItem}
137
+ onAddItem={() => this.props.onAddItem
138
+ && this.props.onAddItem(index, item)}
139
+ itemsDropdown={() => this.props.itemsDropdown
140
+ ? this.props.itemsDropdown(index)
141
+ : []}
142
+ />
143
+ : <div
127
144
  ref={provided2.innerRef}
128
145
  {...provided2.draggableProps}
129
146
  {...provided2.dragHandleProps} >
@@ -335,6 +352,49 @@ class TableListItem extends React.PureComponent<IPropsItem> {
335
352
  }
336
353
  }
337
354
 
355
+ class PortalItem extends React.PureComponent {
356
+ props: any;
357
+ render() {
358
+ const provided = this.props.provided;
359
+ const snapshot = this.props.snapshot;
360
+
361
+ const usePortal: boolean = snapshot.isDragging;
362
+
363
+ const child = (
364
+ <div
365
+ ref={provided.innerRef}
366
+ {...provided.draggableProps}
367
+ {...provided.dragHandleProps}>
368
+ <TableListItem
369
+ dragAndDrop={this.props.dragAndDrop}
370
+ start={this.props.item.start}
371
+ center={this.props.item.center}
372
+ end={this.props.item.end}
373
+ action={this.props.item.action}
374
+ onClick={this.props.item.onClick ? this.props.item.onClick : undefined}
375
+ onDoubleClick={this.props.item.onDoubleClick
376
+ ? this.props.item.onDoubleClick
377
+ : undefined}
378
+ addItem={this.props.addItem}
379
+ itemsDropdown={this.props.itemsDropdown}
380
+ hexColor={this.props.item.hexColor}
381
+ locked={this.props.item.locked}
382
+ positionLocked={this.props.item.positionLocked}
383
+ onAddItem={() => this.props.onAddItem}
384
+ showDragHandle={this.props.showDragHandle}
385
+ />
386
+ </div>
387
+ );
388
+
389
+ if (!usePortal) {
390
+ return child;
391
+ }
392
+
393
+ // if dragging - put the item in a portal
394
+ return ReactDOM.createPortal(child, document.body);
395
+ }
396
+ }
397
+
338
398
  export {
339
399
  TableList, TableListItem
340
400
  };
@@ -131,7 +131,7 @@ export class Menu extends React.Component<IProps, {}> {
131
131
 
132
132
  render() {
133
133
  return (
134
- <div>
134
+ <React.Fragment>
135
135
  {
136
136
  this.props.children(this.toggle)
137
137
  }
@@ -167,7 +167,7 @@ export class Menu extends React.Component<IProps, {}> {
167
167
  baseZIndex={this.props.zIndex ?? superdeskTopBarZIndex}
168
168
  />
169
169
  </div>
170
- </div>
170
+ </React.Fragment>
171
171
  );
172
172
  }
173
173
  }
@@ -4,7 +4,7 @@ import classNames from 'classnames';
4
4
  export interface IPropsSpacer {
5
5
  h?: boolean; // horizontal
6
6
  v?: boolean; // vertical
7
- gap: '4' | '8' | '16' | '32' | '64';
7
+ gap: '0' | '4' | '8' | '16' | '32' | '64';
8
8
  justifyContent?: 'start' | 'end' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'stretch';
9
9
  alignItems?: 'start' | 'end' | 'center' | 'stretch';
10
10
  noGrow?: boolean;
@@ -6,6 +6,7 @@ import _debounce from 'lodash/debounce';
6
6
  import { InputWrapper } from "./Form";
7
7
  import { createPopper } from '@popperjs/core';
8
8
  import {isEqual} from 'lodash';
9
+ import {getTextColor} from './Label';
9
10
 
10
11
  interface IState<T> {
11
12
  value: Array<T>;
@@ -44,8 +45,10 @@ interface IPropsBase<T> {
44
45
  disabled?: boolean;
45
46
  getLabel(item: T): string;
46
47
  getId(item: T): string;
48
+ getBackgroundColor?(item: T): string;
49
+ getBorderColor?(item: T): string;
47
50
  optionTemplate?(item: T): React.ComponentType<T> | JSX.Element;
48
- valueTemplate?(item: T): React.ComponentType<T> | JSX.Element;
51
+ valueTemplate?(item: T, Wrapper: any): React.ComponentType<T> | JSX.Element;
49
52
  onChange(e: Array<T>): void;
50
53
  }
51
54
 
@@ -102,7 +105,6 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
102
105
  this.toggleMenu = this.toggleMenu.bind(this);
103
106
  this.dropdownRef = React.createRef();
104
107
  this.openDropdownRef = React.createRef();
105
-
106
108
  }
107
109
 
108
110
  componentDidMount = () => {
@@ -339,17 +341,24 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
339
341
  event.stopPropagation();
340
342
  this.handleTree(event, option);
341
343
  }}>
342
- {this.props.optionTemplate
344
+ {this.props.getBorderColor
345
+ && <div className="item-border"
346
+ style={{backgroundColor: this.props.getBorderColor(option.value)}}></div>}
347
+ <span
348
+ style={this.props.getBackgroundColor
349
+ ? {backgroundColor: this.props.getBackgroundColor(option.value),
350
+ color: getTextColor(this.props.getBackgroundColor(option.value))}
351
+ : undefined}
352
+ className={'suggestion-item--bgcolor'
353
+ + (selectedItem ? ' suggestion-item--disabled' : '')}
354
+ >
355
+ {this.props.optionTemplate
343
356
  ? this.props.optionTemplate(option.value)
344
- : <span
345
- className={selectedItem
346
- ? 'suggestion-item--disabled' : undefined}
347
- >
348
- {this.props.getLabel(option.value)}
349
- </span>}
350
- {option.children && <span className="suggestion-item__icon">
351
- <Icon name="chevron-right-thin"></Icon>
352
- </span>}
357
+ : this.props.getLabel(option.value)}
358
+ </span>
359
+ {option.children && <span className="suggestion-item__icon">
360
+ <Icon name="chevron-right-thin"></Icon>
361
+ </span>}
353
362
  </li>;
354
363
  });
355
364
  }
@@ -451,27 +460,46 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
451
460
  </button>}
452
461
  <ul className="tags-input__tag-list">
453
462
  {this.state.value.map((item, i: number) => {
454
- return <React.Fragment key={i}>
463
+ const Wrapper: React.ComponentType<{backgroundColor?: string}>
464
+ = ({backgroundColor, children}) => (
455
465
  <li
456
466
  className={"tags-input__tag-item tags-input__tag-item--multi-select"
457
467
  + (this.props.readOnly ? ' tags-input__tag-item--readonly' : '')}
458
- onClick={() => this.props.readOnly || this.removeClick(i)}>
459
- <span className="tags-input__helper-box">
460
- {this.props.valueTemplate
461
- ? this.props.valueTemplate(item)
462
- : <span>{this.props.getLabel(item)}</span>}
463
- {this.props.readOnly
464
- || <span className="tags-input__remove-button">
468
+ onClick={() => !this.props.readOnly && this.removeClick(i)}
469
+ style={this.props.valueTemplate
470
+ ? {backgroundColor}
471
+ : this.props.getBackgroundColor
472
+ && {backgroundColor: this.props.getBackgroundColor(item)}}>
473
+ <span
474
+ style={{color: backgroundColor
475
+ ? getTextColor(backgroundColor)
476
+ : this.props.getBackgroundColor
477
+ && getTextColor(this.props.getBackgroundColor(item))}}
478
+ className="tags-input__helper-box">
479
+ {children}
480
+ {!this.props.readOnly && <span className="tags-input__remove-button">
465
481
  <Icon name="close-small"></Icon>
466
482
  </span>}
467
483
  </span>
468
484
  </li>
469
- </React.Fragment>;
485
+ );
486
+
487
+ return (
488
+ <React.Fragment key={i}>
489
+ {this.props.valueTemplate
490
+ ? this.props.valueTemplate(item, Wrapper)
491
+ : <Wrapper>
492
+ <span>{this.props.getLabel(item)}</span>
493
+ </Wrapper>
494
+ }
495
+ </React.Fragment>
496
+ );
470
497
  })}
471
498
  </ul>
472
499
  {this.state.value.length > 0
473
500
  ? this.props.readOnly
474
501
  || <button className="tags-input__remove-value"
502
+ style={{position: 'relative', bottom: '2px'}}
475
503
  onClick={() => this.setState({value: []})}>
476
504
  <Icon name='remove-sign'></Icon>
477
505
  </button> : null}
@@ -490,21 +518,40 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
490
518
  </span>
491
519
  </span>}
492
520
  {this.state.value.map((item, i: number) => {
493
- return <React.Fragment key={i}>
521
+ const Wrapper: React.ComponentType<{backgroundColor?: string, borderColor?: string}>
522
+ = ({backgroundColor, borderColor, children}) => (
494
523
  <span
495
524
  className={ 'tags-input__single-item'
496
525
  + (this.props.readOnly ? ' tags-input__tag-item--readonly' : '')}
497
526
  onClick={() => this.props.readOnly || this.removeClick(i)}>
498
- <span className="tags-input__helper-box">
499
- {this.props.valueTemplate
500
- ? this.props.valueTemplate(item)
501
- : <span>{this.props.getLabel(item)}</span>}
527
+ {this.props.getBorderColor
528
+ && <div className="item-border item-border-selected"
529
+ style={borderColor
530
+ ? {backgroundColor: borderColor}
531
+ : {backgroundColor: this.props.getBorderColor(item)}}></div>}
532
+ <span
533
+ style={{color: backgroundColor && getTextColor(backgroundColor)}}
534
+ className="tags-input__helper-box">
535
+ <span
536
+ className={backgroundColor && `tags-input__tag-item`}
537
+ style={{backgroundColor, margin: 0}}>
538
+ {children}
539
+ </span>
502
540
  {this.props.readOnly
503
541
  || <span className="tags-input__remove-button">
504
542
  <Icon name='remove-sign'></Icon>
505
543
  </span>}
506
544
  </span>
507
545
  </span>
546
+ );
547
+
548
+ return <React.Fragment key={i}>
549
+ {this.props.valueTemplate
550
+ ? this.props.valueTemplate(item, Wrapper)
551
+ : <Wrapper>
552
+ <span>{this.props.getLabel(item)}</span>
553
+ </Wrapper>
554
+ }
508
555
  </React.Fragment>;
509
556
  })}
510
557
  </div>
@@ -583,14 +630,19 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
583
630
  event.stopPropagation();
584
631
  this.handleTree(event, option);
585
632
  }}>
586
- {this.props.optionTemplate
587
- ? this.props.optionTemplate(option.value)
588
- : <span
589
- className={selectedItem
590
- ? 'suggestion-item--disabled' : undefined}
633
+ {(this.props.getBorderColor && !this.props.allowMultiple) && <div className="item-border" style={{backgroundColor: this.props.getBorderColor(option.value)}}></div>}
634
+ <span
635
+ style={(this.props.getBackgroundColor && option.value)
636
+ ? {backgroundColor: this.props.getBackgroundColor(option.value),
637
+ color: getTextColor(this.props.getBackgroundColor(option.value))}
638
+ : undefined}
639
+ className={'suggestion-item--bgcolor'
640
+ + (selectedItem ? ' suggestion-item--disabled' : '')}
591
641
  >
592
- {this.props.getLabel(option.value)}
593
- </span>}
642
+ {this.props.optionTemplate
643
+ ? this.props.optionTemplate(option.value)
644
+ : this.props.getLabel(option.value)}
645
+ </span>
594
646
  {option.children && <span className="suggestion-item__icon">
595
647
  <Icon name="chevron-right-thin"></Icon>
596
648
  </span>}