superdesk-ui-framework 3.0.1-beta.8 → 3.0.1

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 (160) hide show
  1. package/app/fonts/sd_icons.eot +0 -0
  2. package/app/fonts/sd_icons.svg +1 -0
  3. package/app/fonts/sd_icons.ttf +0 -0
  4. package/app/fonts/sd_icons.woff +0 -0
  5. package/app/scripts/toggleBoxNext.js +1 -1
  6. package/app/styles/_big-icon-font.scss +1 -1
  7. package/app/styles/_buttons.scss +11 -6
  8. package/app/styles/_content-divider.scss +63 -8
  9. package/app/styles/_helpers.scss +24 -1
  10. package/app/styles/_icon-font.scss +11 -10
  11. package/app/styles/_labels.scss +0 -1
  12. package/app/styles/_master-desk.scss +5 -4
  13. package/app/styles/_modals.scss +7 -3
  14. package/app/styles/_normalize.scss +4 -0
  15. package/app/styles/_sd-tag-input.scss +56 -2
  16. package/app/styles/_simple-list.scss +0 -2
  17. package/app/styles/_table-list.scss +116 -12
  18. package/app/styles/app.scss +3 -0
  19. package/app/styles/components/_list-item.scss +23 -16
  20. package/app/styles/components/_sd-collapse-box.scss +6 -6
  21. package/app/styles/components/_sd-comment-box.scss +8 -4
  22. package/app/styles/components/_sd-editor-popup.scss +4 -4
  23. package/app/styles/components/_sd-media-carousel.scss +37 -2
  24. package/app/styles/components/_sd-pagination.scss +41 -0
  25. package/app/styles/components/_sd-photo-preview.scss +2 -2
  26. package/app/styles/components/_subnav.scss +470 -470
  27. package/app/styles/design-tokens/_new-colors.scss +29 -12
  28. package/app/styles/dropdowns/_basic-dropdown.scss +6 -0
  29. package/app/styles/form-elements/_input-wrap.scss +138 -0
  30. package/app/styles/form-elements/_inputs.scss +230 -61
  31. package/app/styles/grids/_grid-layout.scss +13 -14
  32. package/app/styles/interface-elements/_side-panel.scss +1 -1
  33. package/app/styles/layout/_editor.scss +6 -0
  34. package/app/styles/menus/_sd-sidebar-menu.scss +1 -1
  35. package/app/styles/primereact/_pr-datepicker.scss +16 -2
  36. package/app/styles/primereact/_pr-dialog.scss +9 -0
  37. package/app/styles/primereact/_pr-menu.scss +6 -5
  38. package/app/styles/variables/_colors.scss +47 -47
  39. package/app/template/search-handler.html +2 -2
  40. package/app-typescript/components/ContentDivider.tsx +3 -0
  41. package/app-typescript/components/DatePicker.tsx +8 -9
  42. package/app-typescript/components/Dropdown.tsx +127 -82
  43. package/app-typescript/components/DurationInput.tsx +39 -14
  44. package/app-typescript/components/Form/FormLabel.tsx +8 -1
  45. package/app-typescript/components/Form/InputBase.tsx +12 -2
  46. package/app-typescript/components/Input.tsx +4 -4
  47. package/app-typescript/components/Label.tsx +17 -1
  48. package/app-typescript/components/Layouts/AuthoringFrame.tsx +2 -1
  49. package/app-typescript/components/Layouts/AuthoringFrameRightBar.tsx +21 -2
  50. package/app-typescript/components/Layouts/AuthoringInnerHeader.tsx +1 -1
  51. package/app-typescript/components/Layouts/AuthoringMain.tsx +4 -2
  52. package/app-typescript/components/Layouts/CoreLayout.tsx +3 -1
  53. package/app-typescript/components/Layouts/CoreLayoutMain.tsx +10 -1
  54. package/app-typescript/components/Lists/ContentList.tsx +64 -30
  55. package/app-typescript/components/Lists/TableList.tsx +255 -53
  56. package/app-typescript/components/Menu.tsx +2 -2
  57. package/app-typescript/components/Modal.tsx +6 -2
  58. package/app-typescript/components/MultiSelect.tsx +1 -1
  59. package/app-typescript/components/NavButton.tsx +2 -1
  60. package/app-typescript/components/Navigation/SideBarMenu.tsx +30 -4
  61. package/app-typescript/components/SearchBar.tsx +11 -3
  62. package/app-typescript/components/Spacer.tsx +87 -0
  63. package/app-typescript/components/TimePicker.tsx +2 -13
  64. package/app-typescript/components/TreeSelect.tsx +286 -180
  65. package/app-typescript/index.ts +1 -0
  66. package/dist/examples.bundle.css +110 -71
  67. package/dist/examples.bundle.js +23848 -21661
  68. package/dist/playgrounds/react-playgrounds/CoreLayout.tsx +505 -2
  69. package/dist/playgrounds/react-playgrounds/Index.tsx +1 -0
  70. package/dist/playgrounds/react-playgrounds/Multiedit.tsx +321 -0
  71. package/dist/playgrounds/react-playgrounds/RundownEditor.tsx +17 -19
  72. package/dist/playgrounds/react-playgrounds/Rundowns.tsx +22 -23
  73. package/dist/playgrounds/react-playgrounds/TestGround.tsx +226 -25
  74. package/dist/react/ContentDivider.tsx +22 -18
  75. package/dist/react/ContentList.tsx +188 -12
  76. package/dist/react/DatePicker.tsx +50 -2
  77. package/dist/react/Dropdowns.tsx +580 -48
  78. package/dist/react/DurationInput.tsx +7 -3
  79. package/dist/react/Inputs.tsx +1 -7
  80. package/dist/react/Modal.tsx +154 -22
  81. package/dist/react/MultiSelect.tsx +5 -5
  82. package/dist/react/NavButtons.tsx +31 -1
  83. package/dist/react/TableList.tsx +52 -139
  84. package/dist/react/Togglebox.tsx +1 -1
  85. package/dist/react/TreeSelect.tsx +167 -176
  86. package/dist/sd_icons.eot +0 -0
  87. package/dist/sd_icons.svg +1 -0
  88. package/dist/sd_icons.ttf +0 -0
  89. package/dist/sd_icons.woff +0 -0
  90. package/dist/superdesk-ui.bundle.css +1100 -407
  91. package/dist/superdesk-ui.bundle.js +6591 -4035
  92. package/dist/vendor.bundle.js +27 -27
  93. package/examples/css/docs-page.css +4 -4
  94. package/examples/index.js +4 -0
  95. package/examples/pages/playgrounds/react-playgrounds/CoreLayout.tsx +505 -2
  96. package/examples/pages/playgrounds/react-playgrounds/Index.tsx +1 -0
  97. package/examples/pages/playgrounds/react-playgrounds/Multiedit.tsx +321 -0
  98. package/examples/pages/playgrounds/react-playgrounds/RundownEditor.tsx +17 -19
  99. package/examples/pages/playgrounds/react-playgrounds/Rundowns.tsx +22 -23
  100. package/examples/pages/playgrounds/react-playgrounds/TestGround.tsx +226 -25
  101. package/examples/pages/react/ContentDivider.tsx +22 -18
  102. package/examples/pages/react/ContentList.tsx +188 -12
  103. package/examples/pages/react/DatePicker.tsx +50 -2
  104. package/examples/pages/react/Dropdowns.tsx +580 -48
  105. package/examples/pages/react/DurationInput.tsx +7 -3
  106. package/examples/pages/react/Inputs.tsx +1 -7
  107. package/examples/pages/react/Modal.tsx +154 -22
  108. package/examples/pages/react/MultiSelect.tsx +5 -5
  109. package/examples/pages/react/NavButtons.tsx +31 -1
  110. package/examples/pages/react/TableList.tsx +52 -139
  111. package/examples/pages/react/Togglebox.tsx +1 -1
  112. package/examples/pages/react/TreeSelect.tsx +167 -176
  113. package/package.json +3 -5
  114. package/react/components/ContentDivider.d.ts +1 -0
  115. package/react/components/ContentDivider.js +2 -0
  116. package/react/components/DatePicker.d.ts +2 -2
  117. package/react/components/DatePicker.js +3 -3
  118. package/react/components/Dropdown.d.ts +6 -5
  119. package/react/components/Dropdown.js +57 -30
  120. package/react/components/DurationInput.d.ts +1 -1
  121. package/react/components/DurationInput.js +46 -17
  122. package/react/components/Form/FormLabel.d.ts +4 -1
  123. package/react/components/Form/FormLabel.js +9 -3
  124. package/react/components/Form/InputBase.d.ts +0 -1
  125. package/react/components/Form/InputBase.js +15 -1
  126. package/react/components/Input.d.ts +3 -3
  127. package/react/components/Input.js +2 -1
  128. package/react/components/Label.d.ts +1 -0
  129. package/react/components/Label.js +17 -2
  130. package/react/components/Layouts/AuthoringFrame.d.ts +1 -0
  131. package/react/components/Layouts/AuthoringFrame.js +1 -1
  132. package/react/components/Layouts/AuthoringFrameRightBar.d.ts +9 -2
  133. package/react/components/Layouts/AuthoringFrameRightBar.js +14 -3
  134. package/react/components/Layouts/AuthoringInnerHeader.js +1 -1
  135. package/react/components/Layouts/AuthoringMain.js +1 -1
  136. package/react/components/Layouts/CoreLayout.d.ts +2 -0
  137. package/react/components/Layouts/CoreLayout.js +1 -1
  138. package/react/components/Layouts/CoreLayoutMain.d.ts +2 -0
  139. package/react/components/Layouts/CoreLayoutMain.js +8 -1
  140. package/react/components/Lists/ContentList.d.ts +6 -0
  141. package/react/components/Lists/ContentList.js +42 -16
  142. package/react/components/Lists/TableList.d.ts +30 -8
  143. package/react/components/Lists/TableList.js +127 -24
  144. package/react/components/Menu.js +1 -1
  145. package/react/components/Modal.d.ts +2 -0
  146. package/react/components/Modal.js +3 -3
  147. package/react/components/MultiSelect.d.ts +40 -0
  148. package/react/components/MultiSelect.js +70 -0
  149. package/react/components/NavButton.d.ts +1 -1
  150. package/react/components/Navigation/SideBarMenu.d.ts +6 -0
  151. package/react/components/Navigation/SideBarMenu.js +19 -2
  152. package/react/components/SearchBar.d.ts +1 -1
  153. package/react/components/SearchBar.js +15 -7
  154. package/react/components/TimePicker.d.ts +1 -5
  155. package/react/components/TimePicker.js +3 -7
  156. package/react/components/TreeSelect.d.ts +12 -5
  157. package/react/components/TreeSelect.js +189 -116
  158. package/react/index.d.ts +1 -0
  159. package/react/index.js +3 -0
  160. package/patches/@superdesk+primereact+5.0.2-4.patch +0 -66
@@ -2,30 +2,30 @@
2
2
  // -------------------------------------------------------------------------
3
3
 
4
4
  // Refernce Colours
5
- $ref-color-primary: hsla(198, 50%, 50%, 1);
6
- $ref-color-success: hsla(120, 40%, 50%, 1);
7
- $ref-color-alert: hsla(358, 79%, 50%, 1);
8
- $ref-color-warning: hsla(35, 100%, 50%, 1);
9
- $ref-color-highlight: hsla(291, 64%, 50%, 1);
10
- $ref-color-neutral: hsla(0, 0%, 50%, 1);
5
+ // $ref-color-primary: hsla(198, 50%, 50%, 1);
6
+ // $ref-color-success: hsla(120, 40%, 50%, 1);
7
+ // $ref-color-alert: hsla(358, 79%, 50%, 1);
8
+ // $ref-color-warning: hsla(35, 100%, 50%, 1);
9
+ // $ref-color-highlight: hsla(291, 64%, 50%, 1);
10
+ // $ref-color-neutral: hsla(0, 0%, 50%, 1);
11
11
 
12
12
  // Refernce Colours -- DARK BGs & Lines
13
- $ref-color-cool-grey--00: hsl(214, 13%, 12%);
14
- $ref-color-cool-grey--01: hsl(214, 13%, 16%);
15
- $ref-color-cool-grey--02: hsl(214, 13%, 20%);
16
- $ref-color-cool-grey--03: hsl(214, 13%, 25%);
17
- $ref-color-cool-grey--04: hsl(214, 13%, 30%);
13
+ // $ref-color-cool-grey--00: hsl(214, 13%, 12%);
14
+ // $ref-color-cool-grey--01: hsl(214, 13%, 16%);
15
+ // $ref-color-cool-grey--02: hsl(214, 13%, 20%);
16
+ // $ref-color-cool-grey--03: hsl(214, 13%, 25%);
17
+ // $ref-color-cool-grey--04: hsl(214, 13%, 30%);
18
18
 
19
19
  // Refernce Colours -- LIGHT BGs & Lines
20
- $ref-color-light-grey--00: hsl(214, 13%, 100%);
21
- $ref-color-light-grey--01: hsl(214, 13%, 96%);
22
- $ref-color-light-grey--02: hsl(214, 13%, 92%);
23
- $ref-color-light-grey--03: hsl(214, 13%, 85%);
24
- $ref-color-light-grey--04: hsl(214, 13%, 80%);
25
- $ref-color-light-grey--05: hsl(214, 13%, 75%);
26
- $ref-color-light-grey--06: hsl(214, 13%, 70%);
27
- $ref-color-light-grey--07: hsl(214, 13%, 65%);
28
- $ref-color-light-grey--08: hsl(214, 13%, 60%);
20
+ // $ref-color-light-grey--00: hsl(214, 13%, 100%);
21
+ // $ref-color-light-grey--01: hsl(214, 13%, 96%);
22
+ // $ref-color-light-grey--02: hsl(214, 13%, 92%);
23
+ // $ref-color-light-grey--03: hsl(214, 13%, 85%);
24
+ // $ref-color-light-grey--04: hsl(214, 13%, 80%);
25
+ // $ref-color-light-grey--05: hsl(214, 13%, 75%);
26
+ // $ref-color-light-grey--06: hsl(214, 13%, 70%);
27
+ // $ref-color-light-grey--07: hsl(214, 13%, 65%);
28
+ // $ref-color-light-grey--08: hsl(214, 13%, 60%);
29
29
 
30
30
  ///// ==============
31
31
 
@@ -81,29 +81,29 @@ $yellow: hsla(45, 100%, 53%, 1);
81
81
  $orange: hsla(35, 100%, 43%, 1);
82
82
  $purple: hsla(291, 64%, 42%, 1);
83
83
 
84
- $black: #000;
85
- $grayDarker: #222;
86
- $grayDark: #333333;
87
- $grayMedium: #444;
88
- $gray: #666;
89
- $grayNeutral: #7b7b7b;
90
- $grayText: #747474;
91
- $grayLight: #999;
92
- $grayLighter: #F5F5F5;
93
- $white: #fff;
84
+ $black: hsl(214, 13%, 0%);
85
+ $grayDarker: hsl(214, 13%, 13%);
86
+ $grayDark: hsl(214, 13%, 20%);
87
+ $grayMedium: hsl(214, 13%, 27%);
88
+ $gray: hsl(214, 13%, 40%);
89
+ $grayNeutral: hsl(214, 13%, 48%);
90
+ $grayText: hsl(214, 13%, 45%);
91
+ $grayLight: hsl(214, 13%, 60%);
92
+ $grayLighter: hsl(214, 13%, 96%);
93
+ $white: hsl(214, 13%, 100%);
94
94
 
95
95
  // Greys
96
- $gray--900: #333;
97
- $gray--800: #444;
98
- $gray--700: #555;
99
- $gray--600: #666;
100
- $gray--500: #747474;
101
- $gray--400: #888;
102
- $gray--300: #999;
103
- $gray--200: #ccc;
104
- $gray--100: #dedede;
105
- $gray--75: #ededed;
106
- $grey--50: #F5F5F5;
96
+ // $gray--900: hsl(214, 13%, 20%);
97
+ // $gray--800: hsl(214, 13%, 27%);
98
+ // $gray--700: hsl(214, 13%, 33%);
99
+ // $gray--600: hsl(214, 13%, 40%);
100
+ // $gray--500: hsl(214, 13%, 45%);
101
+ // $gray--400: hsl(214, 13%, 53%);
102
+ // $gray--300: hsl(214, 13%, 60%);
103
+ // $gray--200: hsl(214, 13%, 80%);
104
+ // $gray--100: hsl(214, 13%, 87%);
105
+ // $gray--75: hsl(214, 13%, 93%);
106
+ // $grey--50: hsl(214, 13%, 96%);
107
107
 
108
108
  // Extended colors
109
109
  $fernGreen: hsla(91, 47%, 34%, 1);
@@ -116,12 +116,12 @@ $darkViolet: hsla(280, 100%, 34%, 1);
116
116
  $navy: hsla(240, 100%, 25%, 1);
117
117
 
118
118
  // Panel backgrounds
119
- $panel-bg--00: #fff;
120
- $panel-bg--01: #f8f8f8;
121
- $panel-bg--02: #f5f5f5;
122
- $panel-bg--03: #ededed;
123
- $panel-bg--04: #dedede;
124
- $panel-bg--05: #a1a1a1;
119
+ // $panel-bg--00: #fff;
120
+ // $panel-bg--01: #f8f8f8;
121
+ // $panel-bg--02: #f5f5f5;
122
+ // $panel-bg--03: #ededed;
123
+ // $panel-bg--04: #dedede;
124
+ // $panel-bg--05: #a1a1a1;
125
125
 
126
126
  // Text specific colors
127
127
  //Subnav colours
@@ -1,6 +1,6 @@
1
- <div class="flat-searchbar" ng-class="{extended: extended}">
1
+ <div class="flat-searchbar extended">
2
2
  <div class="search-handler" ng-class="{'search-handler--left-border': borderleft}">
3
- <label for="search-input" class="trigger-icon" ng-click="extended = !extended"><i class="icon-search"></i></label>
3
+ <label for="search-input" class="trigger-icon"><i class="icon-search"></i></label>
4
4
  <input id="search-input" type="text" placeholder="{{ :: label || 'Search' }}" ng-model="model" ng-model-options="{debounce: debounce}">
5
5
  <button class="search-close" ng-if="model.length" ng-click="clearInput()" ng-class="{visible: model.length}"><i class="icon-remove-sign"></i></button>
6
6
 
@@ -6,6 +6,7 @@ interface IProps {
6
6
  orientation?: 'horizontal' |'vertical'; // defaults to 'horizontal'
7
7
  align?: 'center' | 'left' | 'right'; // defaults to 'center'
8
8
  border?: boolean;
9
+ margin?: 'x-small' | 'small' |'medium' | 'large' | 'none';
9
10
  children?: React.ReactNode;
10
11
  }
11
12
 
@@ -19,6 +20,8 @@ export class ContentDivider extends React.PureComponent<IProps> {
19
20
  [`sd-content-divider--text-${this.props.align}`]: this.props.align || this.props.align !== undefined,
20
21
  [`sd-content-divider--${this.props.orientation}`]:
21
22
  this.props.orientation || this.props.orientation !== undefined,
23
+ 'sd-content-divider--margin-medium': this.props.margin === undefined,
24
+ [`sd-content-divider--margin-${this.props.margin}`]: this.props.margin || this.props.margin !== undefined,
22
25
  });
23
26
 
24
27
  if (this.props.children) {
@@ -10,12 +10,11 @@ import { InputWrapper } from './Form';
10
10
  export type DatePickerLocaleSettings = Omit<LocaleSettings, 'today' | 'clear'>;
11
11
 
12
12
  interface IDatePickerBase {
13
- disabled?: boolean;
14
13
  dateFormat: string; // a combination of YYYY, MM, and DD with a custom separator e.g. 'MM/DD/YYYY'
15
14
 
16
15
  // shortcuts can be used to jump to a date relative to today
17
16
  // for example [{label: 'tomorrow', days: 1}, {label: 'yesterday', days: -1}]
18
- shortcuts?: Array<{days: number, label: string}>;
17
+ headerButtonBar?: Array<{days: number, label: string}>;
19
18
 
20
19
  // ability to provide localisation. for example (see https://primefaces.org/primereact/showcase/#/calendar):
21
20
  /*
@@ -34,6 +33,7 @@ interface IDatePickerBase {
34
33
  locale?: DatePickerLocaleSettings;
35
34
 
36
35
  // label props
36
+ disabled?: boolean;
37
37
  inlineLabel?: boolean;
38
38
  required?: boolean;
39
39
  fullWidth?: boolean;
@@ -180,23 +180,22 @@ export class DatePicker extends React.PureComponent<IDatePicker, IState> {
180
180
  dateFormat={this.props.dateFormat.replace('YYYY', 'yy').replace('MM', 'mm').replace('DD', 'dd')}
181
181
  showIcon={true}
182
182
  icon="icon-calendar"
183
- headerTemplate={() => this.props.shortcuts == null ? null : (
183
+ headerTemplate={() => this.props.headerButtonBar == null ? null : (
184
184
  <div
185
- style={{width: '100%', display: 'flex', justifyContent: 'space-between', marginBottom: 10}}>
186
- {this.props.shortcuts.map(({label, days}, i) => (
185
+ className="datepicker-header-toolbar">
186
+ {this.props.headerButtonBar.map(({label, days}, i) => (
187
187
  <button
188
188
  key={i}
189
- className="btn btn--hollow btn--small"
189
+ className="btn btn--small"
190
190
  onClick={() => {
191
191
  this.props.onChange(addDays(new Date(), days));
192
-
193
192
  if (this.instance != null && typeof this.instance.hideOverlay === 'function') {
194
193
  this.instance.hideOverlay();
195
194
  }
196
195
  }}>
197
196
  {label}
198
197
  </button>
199
- ))}
198
+ ))}
200
199
  </div>
201
200
  )}
202
201
  appendTo={document.body} // making it work inside `overflow:hidden`
@@ -234,7 +233,7 @@ export class DatePickerISO extends React.PureComponent<IDatePickerISO> {
234
233
  }
235
234
  }}
236
235
  disabled={this.props.disabled}
237
- shortcuts={this.props.shortcuts}
236
+ headerButtonBar={this.props.headerButtonBar}
238
237
  dateFormat={this.props.dateFormat}
239
238
  locale={this.props.locale}
240
239
  inlineLabel={this.props.inlineLabel}
@@ -4,35 +4,42 @@ import { createPopper } from '@popperjs/core';
4
4
  import { useId } from "react-id-generator";
5
5
 
6
6
  export interface IMenuItem {
7
- label: string;
7
+ label: string | React.ReactNode;
8
8
  icon?: string;
9
9
  active?: boolean;
10
10
  onSelect(): void;
11
11
  }
12
12
 
13
+ interface IMenuItemRes extends IMenuItem {
14
+ onChange?(event?: any): void;
15
+ }
16
+
13
17
  export interface ISubmenu {
14
18
  type: 'submenu';
15
- label: string;
19
+ label: string | React.ReactNode;
16
20
  icon?: string;
17
21
  items: Array<IMenuItem | ISubmenu | IMenuGroup | 'divider'>;
18
22
  }
19
23
 
20
24
  export interface IMenuGroup {
21
25
  type: 'group';
22
- label?: string;
26
+ label?: string | React.ReactNode;
23
27
  items: Array<IMenuItem | ISubmenu | IMenuGroup | 'divider'>;
24
28
  }
25
29
 
26
30
  interface IMenu {
27
- label?: string;
31
+ label?: string | React.ReactNode;
28
32
  align?: 'left' | 'right';
29
33
  items: Array<IMenuItem | ISubmenu | IMenuGroup | 'divider'>;
30
34
  header?: Array<IMenuItem | ISubmenu | IMenuGroup | 'divider'>;
31
35
  footer?: Array<IMenuItem | ISubmenu | IMenuGroup | 'divider'>;
32
36
  append?: boolean;
33
37
  children: React.ReactNode;
38
+ onChange?(event?: any): void;
34
39
  }
35
40
 
41
+ const DROPDOWN_ID_CONTAINER = "sd-dropdown-constainer";
42
+
36
43
  export const Dropdown = ({
37
44
  items,
38
45
  header,
@@ -40,15 +47,13 @@ export const Dropdown = ({
40
47
  children,
41
48
  append,
42
49
  align,
50
+ onChange,
43
51
  }: IMenu) => {
44
52
  const [open, setOpen] = React.useState(false);
45
53
  const [change, setChange] = React.useState(false);
46
54
  const [menuID] = useId();
47
- const DROPDOWN_ID = "react-placeholder";
48
55
  const ref = React.useRef(null);
49
- const refSubMenu = React.useRef(null);
50
56
  const buttonRef = React.useRef(null);
51
- const refButtonSubMenu = React.useRef(null);
52
57
  const headerElements = header?.map((el, index) => {
53
58
  return each(el, index);
54
59
  });
@@ -60,12 +65,12 @@ export const Dropdown = ({
60
65
  const footerElements = footer?.map((el, index) => {
61
66
  return each(el, index);
62
67
  });
68
+
63
69
  React.useEffect(() => {
64
- const existingElement = document.getElementById(DROPDOWN_ID);
70
+ const existingElement = document.getElementById(DROPDOWN_ID_CONTAINER);
65
71
  if (!existingElement) {
66
72
  const el = document.createElement("div");
67
- el.id = DROPDOWN_ID;
68
- // style placeholder
73
+ el.id = DROPDOWN_ID_CONTAINER;
69
74
  el.style.position = 'absolute';
70
75
  el.style.top = '0';
71
76
  el.style.left = '0';
@@ -74,7 +79,6 @@ export const Dropdown = ({
74
79
 
75
80
  document.body.appendChild(el);
76
81
  }
77
-
78
82
  }, [change]);
79
83
 
80
84
  React.useLayoutEffect(() => {
@@ -82,17 +86,12 @@ export const Dropdown = ({
82
86
  addInPlaceholder();
83
87
  }
84
88
  setChange(true);
85
-
86
89
  }, [open]);
87
90
 
88
- // structure for append menu
89
91
  function createAppendMenu() {
90
92
  if (header && footer) {
91
93
  return (
92
- <div className='dropdown__menu dropdown__menu--has-head-foot'
93
- id={menuID}
94
- role='menu'
95
- ref={ref}>
94
+ <div className='dropdown__menu dropdown__menu--has-head-foot' id={menuID} role='menu' ref={ref}>
96
95
  <ul className='dropdown__menu-header'>
97
96
  {headerElements}
98
97
  </ul>
@@ -106,10 +105,7 @@ export const Dropdown = ({
106
105
  );
107
106
  } else if (header) {
108
107
  return (
109
- <div className='dropdown__menu dropdown__menu--has-head-foot'
110
- id={menuID}
111
- role='menu'
112
- ref={ref}>
108
+ <div className='dropdown__menu dropdown__menu--has-head-foot' id={menuID} role='menu' ref={ref}>
113
109
  <ul className='dropdown__menu-header'>
114
110
  {headerElements}
115
111
  </ul>
@@ -120,10 +116,7 @@ export const Dropdown = ({
120
116
  );
121
117
  } else if (footer) {
122
118
  return (
123
- <div className='dropdown__menu dropdown__menu--has-head-foot'
124
- id={menuID}
125
- role='menu'
126
- ref={ref}>
119
+ <div className='dropdown__menu dropdown__menu--has-head-foot' id={menuID} role='menu' ref={ref}>
127
120
  <ul className='dropdown__menu-body'>
128
121
  {dropdownElements}
129
122
  </ul>
@@ -134,17 +127,13 @@ export const Dropdown = ({
134
127
  );
135
128
  } else {
136
129
  return (
137
- <ul className='dropdown__menu '
138
- id={menuID}
139
- role='menu'
140
- ref={ref}>
130
+ <ul className='dropdown__menu ' id={menuID} role='menu' ref={ref}>
141
131
  {dropdownElements}
142
132
  </ul>
143
133
  );
144
134
  }
145
135
  }
146
136
 
147
- // toggle menu
148
137
  function toggleDisplay() {
149
138
  if (!open) {
150
139
  let menuRef: any;
@@ -193,14 +182,13 @@ export const Dropdown = ({
193
182
  }
194
183
 
195
184
  function addInPlaceholder() {
196
- const placeholder = document.getElementById(DROPDOWN_ID);
185
+ const placeholder = document.getElementById(DROPDOWN_ID_CONTAINER);
197
186
  let menu = createAppendMenu();
198
187
  if (open) {
199
188
  return ReactDOM.render(menu, placeholder);
200
189
  } else {
201
- const menuDOM = document.getElementById(menuID);
202
- if (menuDOM) {
203
- menuDOM.style.display = 'none';
190
+ if (placeholder) {
191
+ ReactDOM.unmountComponentAtNode(placeholder);
204
192
  }
205
193
  }
206
194
  }
@@ -212,33 +200,13 @@ export const Dropdown = ({
212
200
  submenuItems.push(each(el, key));
213
201
  });
214
202
  return (
215
- <li key={index}>
216
- <div className='dropdown' >
217
- <button
218
- ref={refButtonSubMenu}
219
- className='dropdown__toggle dropdown-toggle'
220
- aria-haspopup="menu"
221
- tabIndex={0}
222
- onMouseOver={() => {
223
- let subMenuRef = refSubMenu.current;
224
- let subToggleRef = refButtonSubMenu.current;
225
- if (subMenuRef && subToggleRef) {
226
- createPopper(subToggleRef, subMenuRef, {
227
- placement: 'right-start',
228
- });
229
- }
230
- }}
231
- onClick={item['onSelect']}>
232
- {item['icon'] ? <i className={'icon-' + item['icon']}></i> : null}
233
- {item['label']}
234
- </button>
235
- <ul ref={refSubMenu}
236
- role='menu'
237
- className='dropdown__menu'>
238
- {submenuItems}
239
- </ul>
240
- </div>
241
- </li>
203
+ <DropdownItemWithSubmenu
204
+ key={index}
205
+ index={index}
206
+ item={item}
207
+ menuID={menuID}
208
+ subMenuItems={submenuItems}
209
+ onChange={onChange} />
242
210
  );
243
211
  } else if (item['type'] === 'group') {
244
212
  let groupItems: any = [];
@@ -258,16 +226,18 @@ export const Dropdown = ({
258
226
  } else {
259
227
  return (
260
228
  <DropdownItem
261
- key={index}
262
- label={item['label']}
263
- icon={item['icon']}
264
- active={item['active']}
265
- onSelect={item['onSelect']} />);
229
+ key={index}
230
+ label={item['label']}
231
+ icon={item['icon']}
232
+ active={item['active']}
233
+ onSelect={item['onSelect']}
234
+ onChange={onChange} />
235
+ );
266
236
  }
267
237
  }
268
238
 
269
239
  return (
270
- <div className={'dropdown ' + (open ? 'open' : '')} >
240
+ <div className={'dropdown ' + (open ? 'open' : '')}>
271
241
  {typeof children === 'object' ?
272
242
  (React.isValidElement(children) ?
273
243
  <div ref={buttonRef} style={{ display: 'content' }}>
@@ -281,11 +251,11 @@ export const Dropdown = ({
281
251
  </div> : null)
282
252
  :
283
253
  <button ref={buttonRef}
284
- className=' dropdown__toggle dropdown-toggle'
285
- aria-haspopup="menu"
286
- tabIndex={0}
287
- aria-expanded={open}
288
- onClick={toggleDisplay}>
254
+ className=' dropdown__toggle dropdown-toggle'
255
+ aria-haspopup="menu"
256
+ tabIndex={0}
257
+ aria-expanded={open}
258
+ onClick={toggleDisplay}>
289
259
  {children}
290
260
  <span className="dropdown__caret"></span>
291
261
  </button>}
@@ -294,7 +264,7 @@ export const Dropdown = ({
294
264
  null : (function() {
295
265
  if (header && footer) {
296
266
  return (
297
- <div className='dropdown__menu dropdown__menu--has-head-foot' role='menu' ref={ref} >
267
+ <div className='dropdown__menu dropdown__menu--has-head-foot' role='menu' ref={ref}>
298
268
  <ul className='dropdown__menu-header'>
299
269
  {headerElements}
300
270
  </ul>
@@ -308,7 +278,7 @@ export const Dropdown = ({
308
278
  );
309
279
  } else if (header) {
310
280
  return (
311
- <div className='dropdown__menu dropdown__menu--has-head-foot' role='menu' ref={ref} >
281
+ <div className='dropdown__menu dropdown__menu--has-head-foot' role='menu' ref={ref}>
312
282
  <ul className='dropdown__menu-header'>
313
283
  {headerElements}
314
284
  </ul>
@@ -319,7 +289,7 @@ export const Dropdown = ({
319
289
  );
320
290
  } else if (footer) {
321
291
  return (
322
- <div className='dropdown__menu dropdown__menu--has-head-foot' role='menu' ref={ref} >
292
+ <div className='dropdown__menu dropdown__menu--has-head-foot' role='menu' ref={ref}>
323
293
  <ul className='dropdown__menu-body'>
324
294
  {dropdownElements}
325
295
  </ul>
@@ -330,7 +300,7 @@ export const Dropdown = ({
330
300
  );
331
301
  } else {
332
302
  return (
333
- <ul className='dropdown__menu' role='menu' ref={ref} >
303
+ <ul className='dropdown__menu' role='menu' ref={ref}>
334
304
  {dropdownElements}
335
305
  </ul>
336
306
  );
@@ -341,18 +311,93 @@ export const Dropdown = ({
341
311
  };
342
312
 
343
313
  const DropdownItem = ({
344
- label,
345
- icon,
346
- active,
347
- onSelect,
348
- }: IMenuItem) => {
314
+ label,
315
+ icon,
316
+ active,
317
+ onSelect,
318
+ onChange,
319
+ }: IMenuItemRes) => {
349
320
  return (
350
321
  <li role='none' className={active ? 'dropdown__menu-item--active' : ''}>
351
- <button tabIndex={0} role='menuitem' onClick={onSelect}>
322
+ <button tabIndex={0}
323
+ role='menuitem'
324
+ onClick={() => {
325
+ setTimeout(() => {
326
+ onSelect();
327
+ });
328
+ if (onChange) {
329
+ onChange();
330
+ }
331
+ }}>
352
332
  <i className={icon ? ('icon-' + icon) : ''}></i>
353
333
  {label}
354
334
  </button>
355
335
  </li>
356
336
  );
337
+ };
338
+
339
+ const DropdownItemWithSubmenu = ({
340
+ index,
341
+ item,
342
+ menuID,
343
+ subMenuItems,
344
+ onChange,
345
+ }: IMenuItem | any) => {
346
+ const [open, setOpen] = React.useState<undefined | boolean>(undefined);
347
+
348
+ const refButtonSubMenu = React.useRef(null);
349
+ const refSubMenu = React.useRef(null);
350
+ const placeholder = document.getElementById(menuID);
357
351
 
352
+ React.useEffect(() => {
353
+ let subMenuRef: any = refSubMenu.current;
354
+ let subToggleRef = refButtonSubMenu.current;
355
+
356
+ if (open === true) {
357
+ placeholder?.appendChild(subMenuRef);
358
+ subMenuRef.style.display = 'block';
359
+ } else if (open === false) {
360
+ placeholder?.removeChild(subMenuRef);
361
+ subMenuRef.style.display = 'none';
362
+ }
363
+
364
+ if (subMenuRef && subToggleRef) {
365
+ createPopper(subToggleRef, subMenuRef, {
366
+ placement: 'right-start',
367
+ });
368
+ }
369
+ }, [open]);
370
+
371
+ return (
372
+ <li key={index} ref={refButtonSubMenu}>
373
+ <div className='dropdown'
374
+ onMouseLeave={() => setOpen(false)}>
375
+ <button
376
+ className='dropdown__toggle dropdown-toggle'
377
+ aria-haspopup="menu"
378
+ tabIndex={0}
379
+ onClick={() => {
380
+ if (item.onSelect) {
381
+ setTimeout(() => {
382
+ item.onSelect();
383
+ });
384
+ }
385
+ if (onChange) {
386
+ onChange();
387
+ }
388
+ }}
389
+ onMouseOver={() => setOpen(true) }>
390
+ {item['icon'] ? <i className={'icon-' + item['icon']}></i> : null}
391
+ {item['label']}
392
+ </button>
393
+ <ul
394
+ role='menu'
395
+ ref={refSubMenu}
396
+ style={{display: 'none'}}
397
+ className='dropdown__menu'>
398
+ {subMenuItems}
399
+ </ul>
400
+ </div>
401
+ </li>
402
+ );
358
403
  };