Commit 7c126e8e authored by Mike Greiling's avatar Mike Greiling

Merge branch 'design-note-pin-component' into 'master'

Add `design_note_pin` component

See merge request gitlab-org/gitlab!24246
parents fd11e813 7ba8d30c
<script>
import { __, sprintf } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
export default {
name: 'DesignNotePin',
components: {
Icon,
},
props: {
position: {
type: Object,
required: true,
},
label: {
type: String,
required: false,
default: null,
},
repositioning: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
isNewNote() {
return this.label === null;
},
pinStyle() {
const style = this.position;
if (this.repositioning) {
style.cursor = 'move';
}
return style;
},
pinLabel() {
return this.isNewNote
? __('Comment form position')
: sprintf(__("Comment '%{label}' position"), { label: this.label });
},
},
};
</script>
<template>
<button
:style="pinStyle"
:aria-label="pinLabel"
:class="{
'btn-transparent comment-indicator': isNewNote,
'js-image-badge badge badge-pill': !isNewNote,
}"
class="position-absolute"
type="button"
@mousedown="$emit('mousedown', $event)"
@mouseup="$emit('mouseup', $event)"
@click="$emit('click', $event)"
>
<icon v-if="isNewNote" name="image-comment-dark" />
<template v-else>
{{ label }}
</template>
</button>
</template>
<script> <script>
import Icon from '~/vue_shared/components/icon.vue'; import DesignNotePin from './design_note_pin.vue';
export default { export default {
name: 'DesignOverlay', name: 'DesignOverlay',
components: { components: {
Icon, DesignNotePin,
}, },
props: { props: {
dimensions: { dimensions: {
...@@ -60,23 +60,12 @@ export default { ...@@ -60,23 +60,12 @@ export default {
data-qa-selector="design_image_button" data-qa-selector="design_image_button"
@click="clickedImage($event.offsetX, $event.offsetY)" @click="clickedImage($event.offsetX, $event.offsetY)"
></button> ></button>
<button <design-note-pin
v-for="(note, index) in notes" v-for="(note, index) in notes"
:key="note.id" :key="note.id"
:style="getNotePosition(note.position)" :label="`${index + 1}`"
class="js-image-badge badge badge-pill position-absolute" :position="getNotePosition(note.position)"
type="button" />
> <design-note-pin v-if="currentCommentForm" :position="getNotePosition(currentCommentForm)" />
{{ index + 1 }}
</button>
<button
v-if="currentCommentForm"
:style="getNotePosition(currentCommentForm)"
:aria-label="__('Comment form position')"
class="btn-transparent comment-indicator position-absolute"
type="button"
>
<icon name="image-comment-dark" />
</button>
</div> </div>
</template> </template>
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Design discussions component should match the snapshot of note when repositioning 1`] = `
<button
aria-label="Comment form position"
class="position-absolute btn-transparent comment-indicator"
style="left: 10px; top: 10px; cursor: move;"
type="button"
>
<icon-stub
name="image-comment-dark"
size="16"
/>
</button>
`;
exports[`Design discussions component should match the snapshot of note with index 1`] = `
<button
aria-label="Comment '1' position"
class="position-absolute js-image-badge badge badge-pill"
style="left: 10px; top: 10px;"
type="button"
>
1
</button>
`;
exports[`Design discussions component should match the snapshot of note without index 1`] = `
<button
aria-label="Comment form position"
class="position-absolute btn-transparent comment-indicator"
style="left: 10px; top: 10px;"
type="button"
>
<icon-stub
name="image-comment-dark"
size="16"
/>
</button>
`;
import { shallowMount } from '@vue/test-utils';
import DesignNotePin from 'ee/design_management/components/design_note_pin.vue';
describe('Design discussions component', () => {
let wrapper;
function createComponent(propsData = {}) {
wrapper = shallowMount(DesignNotePin, {
propsData: {
position: {
left: '10px',
top: '10px',
},
...propsData,
},
});
}
afterEach(() => {
wrapper.destroy();
});
it('should match the snapshot of note without index', () => {
createComponent();
expect(wrapper.element).toMatchSnapshot();
});
it('should match the snapshot of note with index', () => {
createComponent({ label: '1' });
expect(wrapper.element).toMatchSnapshot();
});
it('should match the snapshot of note when repositioning', () => {
createComponent({ repositioning: true });
expect(wrapper.element).toMatchSnapshot();
});
describe('pinStyle', () => {
it('sets cursor to `move` when repositioning = true', () => {
createComponent({ repositioning: true });
expect(wrapper.vm.pinStyle.cursor).toBe('move');
});
it('does not set cursor when repositioning = false', () => {
createComponent();
expect(wrapper.vm.pinStyle.cursor).toBe(undefined);
});
});
});
import { shallowMount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import DesignOverlay from 'ee/design_management/components/design_overlay.vue'; import DesignOverlay from 'ee/design_management/components/design_overlay.vue';
describe('Design overlay component', () => { describe('Design overlay component', () => {
...@@ -29,7 +29,7 @@ describe('Design overlay component', () => { ...@@ -29,7 +29,7 @@ describe('Design overlay component', () => {
const findSecondBadge = () => findAllNotes().at(1); const findSecondBadge = () => findAllNotes().at(1);
function createComponent(props = {}) { function createComponent(props = {}) {
wrapper = shallowMount(DesignOverlay, { wrapper = mount(DesignOverlay, {
propsData: { propsData: {
dimensions: { dimensions: {
width: 100, width: 100,
......
...@@ -4799,6 +4799,9 @@ msgstr "" ...@@ -4799,6 +4799,9 @@ msgstr ""
msgid "Comment & unresolve thread" msgid "Comment & unresolve thread"
msgstr "" msgstr ""
msgid "Comment '%{label}' position"
msgstr ""
msgid "Comment form position" msgid "Comment form position"
msgstr "" msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment