@gitlab/ui 115.0.0 → 115.1.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 (127) hide show
  1. package/bin/migrate_custom_utils_to_tw.bundled.mjs +172489 -139144
  2. package/dist/components/base/new_dropdowns/base_dropdown/base_dropdown.js +15 -3
  3. package/dist/components/base/new_dropdowns/constants.js +5 -2
  4. package/dist/components/dashboards/dashboard_layout/grid_layout/grid_layout.js +286 -0
  5. package/dist/components/dashboards/mock_data.js +49 -0
  6. package/dist/index.css +2 -2
  7. package/dist/index.css.map +1 -1
  8. package/dist/tailwind.css +1 -1
  9. package/dist/tailwind.css.map +1 -1
  10. package/dist/tokens/docs/tokens-tailwind-docs.dark.json +7986 -0
  11. package/dist/tokens/docs/tokens-tailwind-docs.json +7986 -0
  12. package/dist/tokens/figma/constants.tokens.json +944 -236
  13. package/dist/tokens/figma/contextual.tokens.json +2721 -418
  14. package/dist/tokens/figma/deprecated.tokens.json +664 -8
  15. package/dist/tokens/figma/semantic.tokens.json +1130 -169
  16. package/dist/tokens/js/tokens.dark.js +1089 -1047
  17. package/dist/tokens/js/tokens.js +1078 -1047
  18. package/dist/tokens/json/tokens.dark.json +9267 -3
  19. package/dist/tokens/json/tokens.json +9267 -3
  20. package/dist/tokens/tailwind/tokens.cjs +76 -407
  21. package/package.json +22 -49
  22. package/src/components/base/accordion/accordion_item.vue +1 -1
  23. package/src/components/base/avatar/avatar.vue +1 -1
  24. package/src/components/base/button/button.vue +1 -1
  25. package/src/components/base/dropdown/dropdown.vue +3 -1
  26. package/src/components/base/filtered_search/filtered_search.vue +1 -1
  27. package/src/components/base/filtered_search/filtered_search_suggestion_list.vue +1 -1
  28. package/src/components/base/filtered_search/filtered_search_token.vue +1 -1
  29. package/src/components/base/filtered_search/filtered_search_token_segment.vue +3 -3
  30. package/src/components/base/form/form_checkbox_tree/models/tree.js +1 -1
  31. package/src/components/base/form/form_date/form_date.vue +1 -1
  32. package/src/components/base/form/form_input/form_input.vue +1 -1
  33. package/src/components/base/form/form_select/form_select.vue +1 -1
  34. package/src/components/base/modal/modal.vue +2 -2
  35. package/src/components/base/new_dropdowns/base_dropdown/base_dropdown.vue +23 -6
  36. package/src/components/base/new_dropdowns/constants.js +4 -1
  37. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.md +1 -2
  38. package/src/components/base/new_dropdowns/listbox/listbox.vue +7 -7
  39. package/src/components/base/pagination/pagination.vue +2 -2
  40. package/src/components/base/path/path.vue +1 -1
  41. package/src/components/base/skeleton_loader/skeleton_loader.vue +9 -9
  42. package/src/components/base/table/table.md +1 -2
  43. package/src/components/base/table_lite/table_lite.md +1 -1
  44. package/src/components/base/tabs/tabs/tabs.vue +1 -1
  45. package/src/components/base/toast/toast.js +2 -2
  46. package/src/components/base/token_selector/token_container.vue +1 -1
  47. package/src/components/base/token_selector/token_selector.vue +2 -2
  48. package/src/components/base/token_selector/token_selector_dropdown.vue +1 -1
  49. package/src/components/charts/area/area.vue +3 -3
  50. package/src/components/charts/bar/bar.vue +2 -2
  51. package/src/components/charts/column/column.vue +2 -2
  52. package/src/components/charts/discrete_scatter/discrete_scatter.vue +2 -2
  53. package/src/components/charts/gauge/gauge.vue +1 -1
  54. package/src/components/charts/heatmap/heatmap.vue +2 -2
  55. package/src/components/charts/heatmap/index.js +1 -0
  56. package/src/components/charts/legend/legend.vue +1 -1
  57. package/src/components/charts/line/line.vue +3 -3
  58. package/src/components/charts/sparkline/sparkline.vue +1 -1
  59. package/src/components/charts/stacked_column/stacked_column.vue +1 -1
  60. package/src/components/dashboards/dashboard_layout/grid_layout/grid_layout.scss +1 -0
  61. package/src/components/dashboards/dashboard_layout/grid_layout/grid_layout.vue +247 -0
  62. package/src/components/dashboards/mock_data.js +40 -0
  63. package/src/components/mixins/tooltip_mixin.js +1 -1
  64. package/src/components/utilities/intersection_observer/intersection_observer.vue +1 -1
  65. package/src/components/utilities/intersperse/intersperse.vue +2 -2
  66. package/src/components/utilities/sprintf/sprintf.md +1 -1
  67. package/src/components/utilities/sprintf/sprintf.vue +1 -1
  68. package/src/components/utilities/truncate/truncate.vue +2 -2
  69. package/src/config.js +1 -1
  70. package/src/directives/outside/outside.js +4 -4
  71. package/src/directives/tooltip/tooltip.js +1 -1
  72. package/src/scss/components.scss +1 -0
  73. package/src/tokens/build/docs/tokens-tailwind-docs.dark.json +7986 -0
  74. package/src/tokens/build/docs/tokens-tailwind-docs.json +7986 -0
  75. package/src/tokens/build/figma/constants.tokens.json +944 -236
  76. package/src/tokens/build/figma/contextual.tokens.json +2721 -418
  77. package/src/tokens/build/figma/deprecated.tokens.json +664 -8
  78. package/src/tokens/build/figma/semantic.tokens.json +1130 -169
  79. package/src/tokens/build/json/tokens.dark.json +9267 -3
  80. package/src/tokens/build/json/tokens.json +9267 -3
  81. package/src/tokens/constant/color.alpha.tokens.json +60 -15
  82. package/src/tokens/constant/color.tokens.json +844 -211
  83. package/src/tokens/constant/line_height.tokens.json +40 -10
  84. package/src/tokens/contextual/alert.tokens.json +119 -19
  85. package/src/tokens/contextual/avatar.tokens.json +90 -14
  86. package/src/tokens/contextual/badge.tokens.json +728 -112
  87. package/src/tokens/contextual/banner.tokens.json +19 -3
  88. package/src/tokens/contextual/breadcrumb.tokens.json +6 -1
  89. package/src/tokens/contextual/broadcast.tokens.json +301 -81
  90. package/src/tokens/contextual/button.tokens.json +793 -120
  91. package/src/tokens/contextual/chart.tokens.json +42 -7
  92. package/src/tokens/contextual/datepicker.tokens.json +13 -2
  93. package/src/tokens/contextual/dropdown.tokens.json +142 -21
  94. package/src/tokens/contextual/filtered-search.tokens.json +42 -6
  95. package/src/tokens/contextual/illustration.tokens.json +195 -33
  96. package/src/tokens/contextual/label.tokens.json +81 -12
  97. package/src/tokens/contextual/link.tokens.json +26 -4
  98. package/src/tokens/contextual/progress-bar.tokens.json +35 -5
  99. package/src/tokens/contextual/skeleton-loader.tokens.json +12 -2
  100. package/src/tokens/contextual/spinner.tokens.json +24 -4
  101. package/src/tokens/contextual/table.tokens.json +14 -2
  102. package/src/tokens/contextual/tabs.tokens.json +7 -1
  103. package/src/tokens/contextual/toggle.tokens.json +54 -9
  104. package/src/tokens/contextual/token-selector.tokens.json +7 -1
  105. package/src/tokens/contextual/token.tokens.json +14 -2
  106. package/src/tokens/deprecated/deprecated.color.data_viz.tokens.json +165 -0
  107. package/src/tokens/deprecated/deprecated.color.theme.tokens.json +216 -0
  108. package/src/tokens/deprecated/deprecated.color.tokens.json +240 -0
  109. package/src/tokens/deprecated/deprecated.color.transparency.tokens.json +39 -0
  110. package/src/tokens/semantic/action.tokens.json +500 -75
  111. package/src/tokens/semantic/background.tokens.json +49 -7
  112. package/src/tokens/semantic/border.tokens.json +30 -5
  113. package/src/tokens/semantic/control.tokens.json +129 -20
  114. package/src/tokens/semantic/feedback.tokens.json +126 -19
  115. package/src/tokens/semantic/focus-ring.tokens.json +12 -2
  116. package/src/tokens/semantic/highlight.tokens.json +26 -4
  117. package/src/tokens/semantic/icon.tokens.json +63 -9
  118. package/src/tokens/semantic/shadow.tokens.json +6 -1
  119. package/src/tokens/semantic/status.tokens.json +120 -18
  120. package/src/tokens/semantic/text.tokens.json +69 -9
  121. package/src/tokens/tokens_tailwind_table.vue +1 -1
  122. package/src/utils/charts/config.js +7 -7
  123. package/src/utils/charts/utils.js +1 -1
  124. package/src/utils/use_mock_intersection_observer.js +1 -1
  125. package/src/utils/utils.js +1 -1
  126. package/tailwind.defaults.js +1 -1
  127. package/translations.js +2 -2
@@ -1,8 +1,8 @@
1
1
  import uniqueId from 'lodash/uniqueId';
2
2
  import { offset, autoPlacement, shift, arrow, size, autoUpdate, computePosition } from '@floating-ui/dom';
3
3
  import { buttonCategoryOptions, dropdownVariantOptions, buttonSizeOptions, dropdownPlacements, dropdownAllowedAutoPlacements } from '../../../../utils/constants';
4
- import { POSITION_ABSOLUTE, POSITION_FIXED, GL_DROPDOWN_CONTENTS_CLASS, GL_DROPDOWN_BEFORE_CLOSE, GL_DROPDOWN_SHOWN, GL_DROPDOWN_HIDDEN, ENTER, SPACE, ARROW_DOWN, GL_DROPDOWN_FOCUS_CONTENT } from '../constants';
5
- import { logWarning, isElementFocusable, isElementTabbable } from '../../../../utils/utils';
4
+ import { POSITION_ABSOLUTE, POSITION_FIXED, GL_DROPDOWN_CONTENTS_CLASS, GL_DROPDOWN_BEFORE_CLOSE, GL_DROPDOWN_SHOWN, GL_DROPDOWN_HIDDEN, KEY_CODE_ESCAPE, ENTER, SPACE, ARROW_DOWN, GL_DROPDOWN_FOCUS_CONTENT } from '../constants';
5
+ import { logWarning, isElementFocusable, isElementTabbable, stopEvent } from '../../../../utils/utils';
6
6
  import { OutsideDirective } from '../../../../directives/outside/outside';
7
7
  import GlButton from '../../button/button';
8
8
  import GlIcon from '../../icon/icon';
@@ -461,11 +461,23 @@ var script = {
461
461
  },
462
462
  onKeydown(event) {
463
463
  const {
464
+ keyCode,
464
465
  code,
465
466
  target: {
466
467
  tagName
467
468
  }
468
469
  } = event;
470
+
471
+ // Use keyCode because @vue/test-utils doesn't correctly set the
472
+ // `code` and `key` KeyboardEvent properties. This is only needed in this case because:
473
+ // - We are not using the @keydown.esc template syntax, which under Vue 2 checks against `keyCode` anyway.
474
+ // - The `.trigger('keydown.esc')` shorthand @vue/test-utils provides is useful.
475
+ // See https://github.com/vuejs/vue-test-utils/issues/2096
476
+ if (keyCode === KEY_CODE_ESCAPE && this.visible) {
477
+ stopEvent(event);
478
+ this.close();
479
+ return;
480
+ }
469
481
  let toggleOnEnter = true;
470
482
  let toggleOnSpace = true;
471
483
  if (tagName === 'BUTTON') {
@@ -496,7 +508,7 @@ var script = {
496
508
  const __vue_script__ = script;
497
509
 
498
510
  /* template */
499
- var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{directives:[{name:"outside",rawName:"v-outside.click.focusin",value:(_vm.close),expression:"close",modifiers:{"click":true,"focusin":true}}],class:[_vm.$options.BASE_DROPDOWN_CLASS, { '!gl-block': _vm.block }]},[_c(_vm.toggleComponent,_vm._g(_vm._b({ref:"toggle",tag:"component",attrs:{"id":_vm.toggleId,"data-testid":"base-dropdown-toggle"},on:{"keydown":function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"esc",27,$event.key,["Esc","Escape"])){ return null; }$event.stopPropagation();$event.preventDefault();return _vm.close.apply(null, arguments)}}},'component',_vm.toggleAttributes,false),_vm.toggleListeners),[_vm._t("toggle",function(){return [_c('span',{staticClass:"gl-new-dropdown-button-text",class:{ 'gl-sr-only': _vm.textSrOnly }},[_vm._v("\n "+_vm._s(_vm.toggleText)+"\n ")]),_vm._v(" "),(!_vm.noCaret)?_c('gl-icon',{staticClass:"gl-button-icon gl-new-dropdown-chevron",attrs:{"name":"chevron-down"}}):_vm._e()]})],2),_vm._v(" "),_c('div',{ref:"content",staticClass:"gl-new-dropdown-panel",class:_vm.panelClasses,attrs:{"id":_vm.baseDropdownId,"data-testid":"base-dropdown-menu"},on:{"keydown":function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"esc",27,$event.key,["Esc","Escape"])){ return null; }$event.stopPropagation();$event.preventDefault();return _vm.closeAndFocus.apply(null, arguments)}}},[_c('div',{ref:"dropdownArrow",staticClass:"gl-new-dropdown-arrow"}),_vm._v(" "),_c('div',{staticClass:"gl-new-dropdown-inner"},[_vm._t("default",null,{"visible":_vm.visible})],2)])],1)};
511
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{directives:[{name:"outside",rawName:"v-outside.click.focusin",value:(_vm.close),expression:"close",modifiers:{"click":true,"focusin":true}}],class:[_vm.$options.BASE_DROPDOWN_CLASS, { '!gl-block': _vm.block }]},[_c(_vm.toggleComponent,_vm._g(_vm._b({ref:"toggle",tag:"component",attrs:{"id":_vm.toggleId,"data-testid":"base-dropdown-toggle"}},'component',_vm.toggleAttributes,false),_vm.toggleListeners),[_vm._t("toggle",function(){return [_c('span',{staticClass:"gl-new-dropdown-button-text",class:{ 'gl-sr-only': _vm.textSrOnly }},[_vm._v("\n "+_vm._s(_vm.toggleText)+"\n ")]),_vm._v(" "),(!_vm.noCaret)?_c('gl-icon',{staticClass:"gl-button-icon gl-new-dropdown-chevron",attrs:{"name":"chevron-down"}}):_vm._e()]})],2),_vm._v(" "),_c('div',{ref:"content",staticClass:"gl-new-dropdown-panel",class:_vm.panelClasses,attrs:{"id":_vm.baseDropdownId,"data-testid":"base-dropdown-menu"},on:{"keydown":function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"esc",27,$event.key,["Esc","Escape"])){ return null; }$event.stopPropagation();$event.preventDefault();return _vm.closeAndFocus.apply(null, arguments)}}},[_c('div',{ref:"dropdownArrow",staticClass:"gl-new-dropdown-arrow"}),_vm._v(" "),_c('div',{staticClass:"gl-new-dropdown-inner"},[_vm._t("default",null,{"visible":_vm.visible})],2)])],1)};
500
512
  var __vue_staticRenderFns__ = [];
501
513
 
502
514
  /* style */
@@ -4,7 +4,7 @@ const GL_DROPDOWN_HIDDEN = 'hidden';
4
4
  const GL_DROPDOWN_BEFORE_CLOSE = 'beforeClose';
5
5
  const GL_DROPDOWN_FOCUS_CONTENT = 'focusContent';
6
6
 
7
- // KEY Codes
7
+ // KeyboardEvent.code values
8
8
  const ARROW_DOWN = 'ArrowDown';
9
9
  const ARROW_UP = 'ArrowUp';
10
10
  const END = 'End';
@@ -12,10 +12,13 @@ const ENTER = 'Enter';
12
12
  const HOME = 'Home';
13
13
  const SPACE = 'Space';
14
14
 
15
+ // KeyboardEvent.keyCode values
16
+ const KEY_CODE_ESCAPE = 27;
17
+
15
18
  // Positioning strategies
16
19
  // https://floating-ui.com/docs/computePosition#strategy
17
20
  const POSITION_ABSOLUTE = 'absolute';
18
21
  const POSITION_FIXED = 'fixed';
19
22
  const GL_DROPDOWN_CONTENTS_CLASS = 'gl-new-dropdown-contents';
20
23
 
21
- export { ARROW_DOWN, ARROW_UP, END, ENTER, GL_DROPDOWN_BEFORE_CLOSE, GL_DROPDOWN_CONTENTS_CLASS, GL_DROPDOWN_FOCUS_CONTENT, GL_DROPDOWN_HIDDEN, GL_DROPDOWN_SHOWN, HOME, POSITION_ABSOLUTE, POSITION_FIXED, SPACE };
24
+ export { ARROW_DOWN, ARROW_UP, END, ENTER, GL_DROPDOWN_BEFORE_CLOSE, GL_DROPDOWN_CONTENTS_CLASS, GL_DROPDOWN_FOCUS_CONTENT, GL_DROPDOWN_HIDDEN, GL_DROPDOWN_SHOWN, HOME, KEY_CODE_ESCAPE, POSITION_ABSOLUTE, POSITION_FIXED, SPACE };
@@ -0,0 +1,286 @@
1
+ import { GridStack } from 'gridstack';
2
+ import pickBy from 'lodash/pickBy';
3
+ import { breakpoints } from '../../../../utils/breakpoints';
4
+ import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
5
+
6
+ const CURSOR_GRABBING_CLASS = '!gl-cursor-grabbing';
7
+ var script = {
8
+ name: 'GlGridLayout',
9
+ props: {
10
+ value: {
11
+ type: Object,
12
+ required: true
13
+ },
14
+ isStatic: {
15
+ type: Boolean,
16
+ required: false,
17
+ default: true
18
+ }
19
+ },
20
+ data() {
21
+ return {
22
+ grid: undefined,
23
+ gridPanels: []
24
+ };
25
+ },
26
+ computed: {
27
+ gridConfig() {
28
+ return this.value.panels.map(panel => {
29
+ const {
30
+ gridAttributes,
31
+ ...otherProps
32
+ } = panel;
33
+ return {
34
+ ...this.getPanelGridItemConfig(panel),
35
+ props: otherProps
36
+ };
37
+ });
38
+ }
39
+ },
40
+ watch: {
41
+ isStatic(value) {
42
+ var _this$grid;
43
+ (_this$grid = this.grid) === null || _this$grid === void 0 ? void 0 : _this$grid.setStatic(value);
44
+ },
45
+ gridConfig: {
46
+ handler(config) {
47
+ var _this$grid2;
48
+ (_this$grid2 = this.grid) === null || _this$grid2 === void 0 ? void 0 : _this$grid2.load(config);
49
+ },
50
+ deep: true
51
+ },
52
+ /**
53
+ * Data flow:
54
+ * 1. Initial: mounted → initGridStack() → grid.load(gridConfig) →
55
+ * grid.getGridItems() → initGridPanelSlots → gridPanels populated with DOM references
56
+ * 2. Updates: value.panels changes → two parallel paths:
57
+ * a. gridConfig changes → grid.load() updates grid layout (but not gridPanels)
58
+ * b. this watcher updates gridPanels with new panel properties
59
+ */
60
+ 'value.panels': {
61
+ handler(newPanels) {
62
+ if (this.gridPanels.length === 0) return;
63
+
64
+ // Only update panels that have changed to improve performance
65
+ newPanels.forEach(updatedPanel => {
66
+ const panel = this.gridPanels.find(p => p.id === updatedPanel.id);
67
+ if (panel) {
68
+ // Exclude `gridAttributes` from being included in the panel props as it's not a valid prop for the panel component
69
+ const panelPropsWithoutGridAttributes = pickBy(updatedPanel, (_, k) => k !== 'gridAttributes');
70
+ panel.props = {
71
+ ...panelPropsWithoutGridAttributes
72
+ };
73
+ }
74
+ });
75
+ },
76
+ deep: true
77
+ }
78
+ },
79
+ mounted() {
80
+ this.initGridStack();
81
+ },
82
+ beforeDestroy() {
83
+ var _this$grid3;
84
+ const removeDom = Boolean(this.$el.parentElement);
85
+ (_this$grid3 = this.grid) === null || _this$grid3 === void 0 ? void 0 : _this$grid3.destroy(removeDom);
86
+ },
87
+ methods: {
88
+ // TODO: Refactor this to use render methods once Vue 3 migration is complete
89
+ // https://gitlab.com/gitlab-org/gitlab/-/issues/549095
90
+ async mountGridComponents(panels) {
91
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
92
+ scrollIntoView: false
93
+ };
94
+ // Ensure new panels are always rendered first
95
+ await this.$nextTick();
96
+ panels.forEach(panel => {
97
+ var _this$$refs$panelWrap;
98
+ const wrapper = (_this$$refs$panelWrap = this.$refs.panelWrappers) === null || _this$$refs$panelWrap === void 0 ? void 0 : _this$$refs$panelWrap.find(w => w.id === panel.id);
99
+ const widgetContentEl = panel.el.querySelector('.grid-stack-item-content');
100
+ if (wrapper && widgetContentEl) {
101
+ widgetContentEl.appendChild(wrapper);
102
+ }
103
+ });
104
+ if (options.scrollIntoView) {
105
+ const mostRecent = panels[panels.length - 1];
106
+ mostRecent.el.scrollIntoView({
107
+ behavior: 'smooth'
108
+ });
109
+ }
110
+ },
111
+ getGridItemForElement(el) {
112
+ return this.gridConfig.find(item => item.id === el.getAttribute('gs-id'));
113
+ },
114
+ initGridPanelSlots(gridElements) {
115
+ if (!gridElements) return;
116
+ this.gridPanels = gridElements.map(el => ({
117
+ ...this.getGridItemForElement(el),
118
+ el
119
+ }));
120
+ this.mountGridComponents(this.gridPanels);
121
+ },
122
+ initGridStack() {
123
+ // See https://github.com/gridstack/gridstack.js/tree/master/doc#grid-options
124
+ this.grid = GridStack.init({
125
+ // Uniform gap between panels
126
+ margin: '8px',
127
+ // CSS Selector for finding the drag handle element
128
+ handle: '.grid-stack-item-handle',
129
+ /* Magic number 125px:
130
+ * After allowing for padding, and the panel title row, this leaves us with minimum 48px height for the cell content.
131
+ * This means text/content with our spacing scale can fit up to 49px without scrolling.
132
+ */
133
+ cellHeight: '125px',
134
+ // Setting 1 in minRow prevents the grid collapsing when all panels are removed
135
+ minRow: 1,
136
+ // Define the number of columns for anything below a set width, defaults to fill the available space
137
+ columnOpts: {
138
+ breakpoints: [{
139
+ w: breakpoints.md,
140
+ c: 1
141
+ }]
142
+ },
143
+ alwaysShowResizeHandle: true,
144
+ animate: true,
145
+ float: true,
146
+ // Toggles user-customization of grid layout
147
+ staticGrid: this.isStatic
148
+ }, this.$refs.grid).load(this.gridConfig);
149
+
150
+ // Sync Vue components array with gridstack items
151
+ this.initGridPanelSlots(this.grid.getGridItems());
152
+ this.grid.on('dragstart', () => {
153
+ this.$el.classList.add(CURSOR_GRABBING_CLASS);
154
+ });
155
+ this.grid.on('dragstop', () => {
156
+ this.$el.classList.remove(CURSOR_GRABBING_CLASS);
157
+ });
158
+ this.grid.on('change', (_, items) => {
159
+ if (!items) return;
160
+ this.emitLayoutChanges(items);
161
+ });
162
+ this.grid.on('added', (_, items) => {
163
+ this.addGridPanels(items);
164
+ });
165
+ this.grid.on('removed', (_, items) => {
166
+ this.removeGridPanels(items);
167
+ });
168
+ },
169
+ getPanelGridItemConfig(_ref) {
170
+ let {
171
+ gridAttributes: {
172
+ xPos,
173
+ yPos,
174
+ width,
175
+ height,
176
+ minHeight,
177
+ minWidth,
178
+ maxHeight,
179
+ maxWidth
180
+ },
181
+ id
182
+ } = _ref;
183
+ const filterUndefinedValues = obj => pickBy(obj, value => value !== undefined);
184
+
185
+ // GridStack renders undefined layout values so we need to filter them out.
186
+ return filterUndefinedValues({
187
+ x: xPos,
188
+ y: yPos,
189
+ w: width,
190
+ h: height,
191
+ minH: minHeight,
192
+ minW: minWidth,
193
+ maxH: maxHeight,
194
+ maxW: maxWidth,
195
+ id
196
+ });
197
+ },
198
+ convertToGridAttributes(gridStackItem) {
199
+ return {
200
+ yPos: gridStackItem.y,
201
+ xPos: gridStackItem.x,
202
+ width: gridStackItem.w,
203
+ height: gridStackItem.h
204
+ };
205
+ },
206
+ removeGridPanels(items) {
207
+ items.forEach(item => {
208
+ const index = this.gridPanels.findIndex(c => c.id === item.id);
209
+ this.gridPanels.splice(index, 1);
210
+ // Finally, remove the gridstack element
211
+ item.el.remove();
212
+ });
213
+ },
214
+ addGridPanels(items) {
215
+ const newPanels = items.map(_ref2 => {
216
+ let {
217
+ grid,
218
+ ...rest
219
+ } = _ref2;
220
+ return {
221
+ ...rest
222
+ };
223
+ });
224
+ this.gridPanels.push(...newPanels);
225
+ this.mountGridComponents(newPanels, {
226
+ scrollIntoView: true
227
+ });
228
+ },
229
+ emitLayoutChanges(items) {
230
+ /**
231
+ * Uses JSON parse and stringify to remove object references.
232
+ * Lodash's `cloneDeep` retains circular references.
233
+ * See https://github.com/lodash/lodash/issues/4710#issuecomment-606892867 for details on cloneDeep circular references
234
+ * See https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm for the underlying mechanism used by Lodash
235
+ */
236
+ const newValue = JSON.parse(JSON.stringify(this.value));
237
+ items.forEach(item => {
238
+ const panel = newValue.panels.find(p => p.id === item.id);
239
+ if (!panel) return;
240
+ panel.gridAttributes = {
241
+ ...panel.gridAttributes,
242
+ ...this.convertToGridAttributes(item)
243
+ };
244
+ });
245
+ this.$emit('input', newValue);
246
+ }
247
+ }
248
+ };
249
+
250
+ /* script */
251
+ const __vue_script__ = script;
252
+
253
+ /* template */
254
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{ref:"grid",staticClass:"grid-stack",attrs:{"data-testid":"gridstack-grid"}},_vm._l((_vm.gridPanels),function(panel){return _c('div',{key:panel.id,ref:"panelWrappers",refInFor:true,staticClass:"gl-h-full",class:{ 'gl-cursor-grab': !_vm.isStatic },attrs:{"id":panel.id,"data-testid":"gridstack-panel"}},[_vm._t("panel",null,null,{ panel: panel.props })],2)}),0)};
255
+ var __vue_staticRenderFns__ = [];
256
+
257
+ /* style */
258
+ const __vue_inject_styles__ = undefined;
259
+ /* scoped */
260
+ const __vue_scope_id__ = undefined;
261
+ /* module identifier */
262
+ const __vue_module_identifier__ = undefined;
263
+ /* functional template */
264
+ const __vue_is_functional_template__ = false;
265
+ /* style inject */
266
+
267
+ /* style inject SSR */
268
+
269
+ /* style inject shadow dom */
270
+
271
+
272
+
273
+ const __vue_component__ = /*#__PURE__*/__vue_normalize__(
274
+ { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
275
+ __vue_inject_styles__,
276
+ __vue_script__,
277
+ __vue_scope_id__,
278
+ __vue_is_functional_template__,
279
+ __vue_module_identifier__,
280
+ false,
281
+ undefined,
282
+ undefined,
283
+ undefined
284
+ );
285
+
286
+ export { __vue_component__ as default };
@@ -0,0 +1,49 @@
1
+ import uniqueId from 'lodash/uniqueId';
2
+
3
+ const getUniquePanelId = () => uniqueId('panel-');
4
+ const dashboard = {
5
+ id: 'analytics_overview',
6
+ slug: 'analytics_overview',
7
+ title: 'Analytics Overview',
8
+ description: 'This is a dashboard',
9
+ userDefined: true,
10
+ panels: [{
11
+ title: 'Test A',
12
+ gridAttributes: {
13
+ width: 3,
14
+ height: 3,
15
+ xPos: 0,
16
+ yPos: 0
17
+ },
18
+ id: getUniquePanelId()
19
+ }, {
20
+ title: 'Test B',
21
+ gridAttributes: {
22
+ width: 2,
23
+ height: 4,
24
+ xPos: 1,
25
+ yPos: 1,
26
+ minHeight: 2,
27
+ minWidth: 2
28
+ },
29
+ id: getUniquePanelId()
30
+ }],
31
+ status: null,
32
+ errors: null
33
+ };
34
+ const mockPanel = {
35
+ title: 'Test A',
36
+ gridAttributes: {
37
+ width: 1,
38
+ height: 2,
39
+ xPos: 0,
40
+ yPos: 3,
41
+ minWidth: 1,
42
+ minHeight: 2,
43
+ maxWidth: 1,
44
+ maxHeight: 2
45
+ },
46
+ id: getUniquePanelId()
47
+ };
48
+
49
+ export { dashboard, getUniquePanelId, mockPanel };