@gitlab/ui 53.3.0 → 54.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "53.3.0",
3
+ "version": "54.1.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -44,8 +44,12 @@ After closing, `GlDisclosureDropdown` emits a `hidden` event.
44
44
 
45
45
  ### Setting disclosure dropdown items
46
46
 
47
- Use the `items` prop to provide actions/links to the disclosure dropdown. Each item can be
48
- either an item or a group. For `Item`s, either the `href` or the `action` may be null, but not both.
47
+ Use the `items` prop to provide actions/links to the disclosure dropdown. Each
48
+ item can be either an item or a group. For `Item`s, provide an `href` string to
49
+ make them render as links. Otherwise, they will be buttons. Provide an `action`
50
+ function to items to be called when they are pressed, or, listen for the
51
+ `action` event on the top-level component. Both will receive the given item as
52
+ an argument.
49
53
  A <!-- markdownlint-disable-next-line line-length -->
50
54
  [validation error](https://gitlab.com/gitlab-org/gitlab-ui/-/blob/6cbff4f908b429cc01f17a4cc2868e881db1aa31/src/components/base/new_dropdowns/disclosure/utils.js#L1)
51
55
  will be triggered if neither field is set.
@@ -56,7 +60,7 @@ Below are the expected shapes of these objects:
56
60
  type Item = {
57
61
  text: string
58
62
  href?: string,
59
- action?: function,
63
+ action?: (item: Item) => void,
60
64
  }
61
65
 
62
66
  type Group = {
@@ -75,15 +79,17 @@ template. If you want to render a custom template for items, use the
75
79
 
76
80
  ```html
77
81
  <gl-disclosure-dropdown :items="items">
78
- <template #list-item="{ item }">
79
- <a class="gl-hover-text-decoration-none gl-text-gray-900"
80
- tabindex="-1"
81
- :href="item.href"
82
- v-bind="item.extraAttrs">
83
- {{ item.text }}
84
- <gl-badge pill variant="info" v-if="item.count">{{ item.count }}</gl-badge>
85
- </a>
86
- </template>
82
+ <template #list-item="{ item }">
83
+ <a
84
+ class="gl-hover-text-decoration-none gl-text-gray-900"
85
+ tabindex="-1"
86
+ :href="item.href"
87
+ v-bind="item.extraAttrs"
88
+ >
89
+ {{ item.text }}
90
+ <gl-badge v-if="item.count" pill variant="info">{{ item.count }}</gl-badge>
91
+ </a>
92
+ </template>
87
93
  </gl-disclosure-dropdown>
88
94
  ```
89
95
 
@@ -18,8 +18,10 @@ describe('GlDisclosureDropdownItem', () => {
18
18
  describe('when default slot content provided', () => {
19
19
  const content = 'This is an item';
20
20
  const slots = { default: content };
21
+ const item = mockItems[1];
22
+
21
23
  beforeEach(() => {
22
- buildWrapper({}, slots);
24
+ buildWrapper({ item }, slots);
23
25
  });
24
26
 
25
27
  it('renders it', () => {
@@ -33,7 +35,7 @@ describe('GlDisclosureDropdownItem', () => {
33
35
  ${() => findItem().trigger('keydown', { code: SPACE })} | ${'SPACE'}
34
36
  `(`$event should emit 'action' event`, ({ trigger }) => {
35
37
  trigger();
36
- expect(wrapper.emitted('action')).toHaveLength(1);
38
+ expect(wrapper.emitted('action')).toEqual([[item]]);
37
39
  });
38
40
  });
39
41
 
@@ -55,10 +57,11 @@ describe('GlDisclosureDropdownItem', () => {
55
57
  });
56
58
 
57
59
  describe('when item has an `action`', () => {
58
- const action = jest.spyOn(mockItems[1], 'action');
60
+ const item = mockItems[1];
61
+ const action = jest.spyOn(item, 'action');
59
62
 
60
63
  beforeEach(() => {
61
- buildWrapper({ item: mockItems[1] });
64
+ buildWrapper({ item });
62
65
  action.mockClear();
63
66
  });
64
67
 
@@ -69,16 +72,23 @@ describe('GlDisclosureDropdownItem', () => {
69
72
  });
70
73
 
71
74
  it('should set correct attributes', () => {
72
- const attrs = { ...mockItems[1].extraAttrs };
75
+ const attrs = { ...item.extraAttrs };
73
76
  delete attrs.class;
74
- expect(findButton().classes()).toContain(mockItems[1].extraAttrs.class);
77
+ expect(findButton().classes()).toContain(item.extraAttrs.class);
75
78
  expect(findButton().attributes()).toMatchObject(attrs);
76
79
  });
77
80
 
78
81
  it('should call `action` on `click`', () => {
79
82
  findButton().trigger('click');
80
- expect(action).toHaveBeenCalled();
81
- expect(wrapper.emitted('action')).toHaveLength(1);
83
+ expect(action).toHaveBeenCalledTimes(1);
84
+
85
+ const actionThisArg = action.mock.contexts[0];
86
+ expect(actionThisArg).toBe(undefined);
87
+
88
+ const actionArgs = action.mock.calls[0];
89
+ expect(actionArgs).toEqual([item]);
90
+
91
+ expect(wrapper.emitted('action')).toEqual([[item]]);
82
92
  });
83
93
 
84
94
  it.each`
@@ -88,7 +98,7 @@ describe('GlDisclosureDropdownItem', () => {
88
98
  ${() => findItem().trigger('keydown', { code: SPACE })} | ${'SPACE'}
89
99
  `(`$event will execute action and emit 'action' event`, ({ trigger }) => {
90
100
  trigger();
91
- expect(wrapper.emitted('action')).toHaveLength(1);
101
+ expect(wrapper.emitted('action')).toEqual([[item]]);
92
102
  });
93
103
  });
94
104
  });
@@ -16,31 +16,34 @@ export default {
16
16
  },
17
17
  },
18
18
  computed: {
19
- isActionItem() {
20
- return this.item?.action;
19
+ isLink() {
20
+ return typeof this.item?.href === 'string';
21
21
  },
22
22
  isCustomContent() {
23
23
  return Boolean(this.$scopedSlots.default);
24
24
  },
25
25
  itemComponent() {
26
- if (this.isActionItem)
26
+ const { item } = this;
27
+
28
+ if (this.isLink)
27
29
  return {
28
- is: 'button',
30
+ is: 'a',
29
31
  attrs: {
30
- ...this.item.extraAttrs,
31
- type: 'button',
32
- },
33
- listeners: {
34
- click: () => this.item.action(),
32
+ href: item.href,
33
+ ...item.extraAttrs,
35
34
  },
35
+ listeners: {},
36
36
  };
37
+
37
38
  return {
38
- is: 'a',
39
+ is: 'button',
39
40
  attrs: {
40
- href: this.item.href,
41
- ...this.item.extraAttrs,
41
+ ...item.extraAttrs,
42
+ type: 'button',
43
+ },
44
+ listeners: {
45
+ click: () => item.action?.call(undefined, item),
42
46
  },
43
- listeners: {},
44
47
  };
45
48
  },
46
49
  },
@@ -1,5 +1,4 @@
1
- const itemValidator = ({ text, href, action }) =>
2
- Boolean(text?.length && (href?.length || typeof action === 'function'));
1
+ const itemValidator = (item) => item?.text?.length > 0 && !Array.isArray(item?.items);
3
2
 
4
3
  const isItem = (item) => Boolean(item) && itemValidator(item);
5
4
 
@@ -10,6 +10,7 @@ describe('isItem', () => {
10
10
  );
11
11
 
12
12
  it.each([
13
+ { text: 'Action' },
13
14
  { text: 'Action', href: 'gitlab.com' },
14
15
  {
15
16
  text: 'Action',
package/src/index.js CHANGED
@@ -98,7 +98,6 @@ export { default as GlAccordion } from './components/base/accordion/accordion.vu
98
98
  export { default as GlAccordionItem } from './components/base/accordion/accordion_item.vue';
99
99
  export { default as GlCarousel } from './components/base/carousel/carousel.vue';
100
100
  export { default as GlCarouselSlide } from './components/base/carousel/carousel_slide.vue';
101
- export { default as RichTextEditor } from './components/editors/rich_text_editor/rich_text_editor.vue';
102
101
 
103
102
  // Utilities
104
103
  export { default as GlAnimatedNumber } from './components/utilities/animated_number/animated_number.vue';
@@ -6374,6 +6374,12 @@
6374
6374
  margin-top: #{$gl-spacing-scale-3} !important;
6375
6375
  }
6376
6376
  }
6377
+ .gl-gap-2 {
6378
+ gap: $gl-spacing-scale-2;
6379
+ }
6380
+ .gl-gap-2\! {
6381
+ gap: $gl-spacing-scale-2 !important;
6382
+ }
6377
6383
  .gl-gap-3 {
6378
6384
  gap: $gl-spacing-scale-3;
6379
6385
  }
@@ -819,6 +819,10 @@
819
819
  }
820
820
  }
821
821
 
822
+ @mixin gl-gap-2 {
823
+ gap: $gl-spacing-scale-2;
824
+ }
825
+
822
826
  @mixin gl-gap-3 {
823
827
  gap: $gl-spacing-scale-3;
824
828
  }
@@ -1,41 +0,0 @@
1
- import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
2
-
3
- var script = {};
4
-
5
- /* script */
6
- const __vue_script__ = script;
7
-
8
- /* template */
9
- var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_vm._v("This is a rich-text-editor")])};
10
- var __vue_staticRenderFns__ = [];
11
-
12
- /* style */
13
- const __vue_inject_styles__ = undefined;
14
- /* scoped */
15
- const __vue_scope_id__ = undefined;
16
- /* module identifier */
17
- const __vue_module_identifier__ = undefined;
18
- /* functional template */
19
- const __vue_is_functional_template__ = false;
20
- /* style inject */
21
-
22
- /* style inject SSR */
23
-
24
- /* style inject shadow dom */
25
-
26
-
27
-
28
- const __vue_component__ = __vue_normalize__(
29
- { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
30
- __vue_inject_styles__,
31
- __vue_script__,
32
- __vue_scope_id__,
33
- __vue_is_functional_template__,
34
- __vue_module_identifier__,
35
- false,
36
- undefined,
37
- undefined,
38
- undefined
39
- );
40
-
41
- export default __vue_component__;
@@ -1,38 +0,0 @@
1
- <!--
2
- Briefly describe the component's purpose here.
3
- This should correspond to the short description in Pajamas' website: https://design.gitlab.com/components/status/
4
- -->
5
-
6
- The Rich Text Editor is a UI component that provides a WYSIWYG editing
7
- experience for[GitLab Flavored Markdown](https://docs.gitlab.com/ee/user/markdown.md#gitlab-flavored-markdown-gfm)
8
- (GFM) in the GitLab application.
9
- It also serves as the foundation for implementing Markdown-focused editors that target other engines,
10
- like static site generators.
11
-
12
- <!-- Provide technical information on how to use the component, add code examples if relevant. -->
13
-
14
- <!--
15
- ## Dos and don'ts
16
-
17
- If relevant, describe how the component is expected to be used, and how it's not.
18
- -->
19
-
20
- <!--
21
- ## Browser compatibility
22
-
23
- If the component requires any polyfill or fallback on certain browsers, describe those requirements
24
- here.
25
- -->
26
-
27
- <!--
28
- ## Edge cases
29
-
30
- If the component has some known limitations, describe them here.
31
- -->
32
-
33
- <!--
34
- ## Deprecation warning
35
-
36
- If and when this component introduced API changes that would require deprecating old APIs, describe
37
- the changes here, and provide a migration paths to the new API.
38
- -->
@@ -1,9 +0,0 @@
1
- import { shallowMount } from '@vue/test-utils';
2
- import GlRichTextEditor from './rich_text_editor.vue';
3
-
4
- describe('GlRichTextEditor', () => {
5
- it('renders main components', () => {
6
- const wrapper = shallowMount(GlRichTextEditor);
7
- expect(wrapper).toBeInstanceOf(Object);
8
- });
9
- });
@@ -1,25 +0,0 @@
1
- import readme from './rich_text_editor.md';
2
- import GlRichTextEditor from './rich_text_editor.vue';
3
-
4
- export default {
5
- title: 'editor/Rich Text Editor',
6
- component: GlRichTextEditor,
7
- parameters: {
8
- docs: {
9
- description: {
10
- component: readme,
11
- },
12
- },
13
- },
14
- argTypes: {},
15
- };
16
-
17
- const Template = (_, { argTypes }) => ({
18
- components: { GlRichTextEditor },
19
- props: Object.keys(argTypes),
20
- template: `
21
- <gl-rich-text-editor />
22
- `,
23
- });
24
-
25
- export const Default = Template.bind({});
@@ -1,7 +0,0 @@
1
- <script>
2
- export default {};
3
- </script>
4
-
5
- <template>
6
- <div>This is a rich-text-editor</div>
7
- </template>