@farm-investimentos/front-mfe-components 11.4.6 → 11.5.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 (33) hide show
  1. package/dist/front-mfe-components.common.js +592 -384
  2. package/dist/front-mfe-components.common.js.map +1 -1
  3. package/dist/front-mfe-components.css +1 -1
  4. package/dist/front-mfe-components.umd.js +592 -384
  5. package/dist/front-mfe-components.umd.js.map +1 -1
  6. package/dist/front-mfe-components.umd.min.js +1 -1
  7. package/dist/front-mfe-components.umd.min.js.map +1 -1
  8. package/package.json +3 -2
  9. package/src/components/CopyToClipboard/CopyToClipboard.stories.js +7 -0
  10. package/src/components/CopyToClipboard/CopyToClipboard.vue +11 -3
  11. package/src/components/Form/Form.stories.js +16 -2
  12. package/src/components/Form/Form.vue +4 -2
  13. package/src/components/IdCaption/IdCaption.vue +1 -1
  14. package/src/components/RadioGroup/RadioGroup.vue +14 -2
  15. package/src/components/Switcher/Switcher.scss +16 -12
  16. package/src/components/Switcher/Switcher.stories.js +24 -2
  17. package/src/components/Switcher/Switcher.vue +5 -3
  18. package/src/components/TableContextMenu/TableContextMenu.vue +3 -1
  19. package/src/components/TextFieldV2/TextFieldV2.scss +64 -0
  20. package/src/components/TextFieldV2/TextFieldV2.stories.js +176 -2
  21. package/src/components/TextFieldV2/TextFieldV2.vue +143 -5
  22. package/src/components/TextFieldV2/__tests__/TextFieldV2.spec.js +21 -0
  23. package/src/components/Typography/BodyText/BodyText.vue +1 -1
  24. package/src/components/Typography/Caption/Caption.vue +1 -1
  25. package/src/components/Typography/Heading/Heading.vue +1 -1
  26. package/src/components/Typography/Subtitle/Subtitle.stories.js +4 -4
  27. package/src/components/Typography/Subtitle/Subtitle.vue +1 -1
  28. package/src/components/Typography/Typography.vue +14 -1
  29. package/src/components/layout/Col/Col.scss +1 -1
  30. package/src/components/layout/Line/Line.vue +4 -1
  31. package/src/examples/VuetifyDialog.stories.js +119 -0
  32. package/src/examples/ConfirmDialog.stories.js +0 -43
  33. package/src/examples/Modal.stories.js +0 -181
@@ -1,13 +1,47 @@
1
1
  <template>
2
- <div class="farm-textfield">
2
+ <div
3
+ class="farm-textfield"
4
+ :class="{
5
+ 'farm-textfield': true,
6
+ 'farm-textfield--validatable': rules.length > 0,
7
+ 'farm-textfield--touched': isTouched,
8
+ 'farm-textfield--blured': isBlured,
9
+ 'farm-textfield--error': hasError,
10
+ }"
11
+ >
3
12
  <div class="farm-textfield--input">
4
- <input v-bind="$attrs" v-model="innerValue" />
13
+ <button v-if="icon && iconPosition === 'left'" @click="$emit('onClickIcon')">
14
+ <farm-icon color="gray" size="20px">{{ icon }}</farm-icon>
15
+ </button>
16
+ <input
17
+ v-bind="$attrs"
18
+ v-model="innerValue"
19
+ v-mask="$props.vMask"
20
+ :disabled="disabled"
21
+ :readonly="readonly"
22
+ @keyup="onKeyUp"
23
+ @blur="onBlur"
24
+ />
25
+ <button v-if="icon && iconPosition === 'right'" @click="$emit('onClickIcon')">
26
+ <farm-icon color="gray" size="20px">{{ icon }}</farm-icon>
27
+ </button>
5
28
  </div>
6
- <span class="farm-textfield--text"> hint text</span>
29
+
30
+ <farm-caption v-if="showErrorText" color="error" variation="regular">
31
+ {{ errorBucket[0] }}
32
+ </farm-caption>
33
+ <farm-caption v-if="hint && !showErrorText" color="gray" variation="regular">
34
+ {{ hint }}
35
+ </farm-caption>
7
36
  </div>
8
37
  </template>
38
+
9
39
  <script lang="ts">
10
- import Vue, { ref, watch } from 'vue';
40
+ import Vue, { computed, onBeforeMount, PropType, ref, toRefs, watch } from 'vue';
41
+ import validateFormStateBuilder from '../../composition/validateFormStateBuilder';
42
+ import validateFormFieldBuilder from '../../composition/validateFormFieldBuilder';
43
+ import validateFormMethodBuilder from '../../composition/validateFormMethodBuilder';
44
+ import deepEqual from '../../composition/deepEqual';
11
45
 
12
46
  export default Vue.extend({
13
47
  name: 'farm-textfield-v2',
@@ -16,15 +50,77 @@ export default Vue.extend({
16
50
  /**
17
51
  * v-model binding
18
52
  */
19
- value: {},
53
+ value: { type: [String, Number], default: '' },
54
+ /**
55
+ * Show icon?
56
+ */
57
+ icon: {
58
+ type: String,
59
+ default: null,
60
+ },
61
+ /**
62
+ * Icon position
63
+ */
64
+ iconPosition: { type: String as PropType<'left' | 'right'>, default: 'right' },
65
+ /**
66
+ * Show hint text
67
+ */
68
+ hint: {
69
+ type: String,
70
+ default: null,
71
+ },
72
+ /**
73
+ * Disabled the input
74
+ */
75
+ disabled: {
76
+ type: Boolean,
77
+ default: false,
78
+ },
79
+ /**
80
+ * Puts input in readonly state
81
+ */
82
+ readonly: {
83
+ type: Boolean,
84
+ default: false,
85
+ },
86
+
87
+ errorMessage: String,
88
+ /**
89
+ * Array of rules used for validation
90
+ */
91
+ rules: {
92
+ type: Array as PropType<Array<Function>>,
93
+ default: () => [],
94
+ },
95
+ /**
96
+ * Mask
97
+ */
98
+ vMask: {
99
+ default: '',
100
+ type: [String, Function],
101
+ },
20
102
  },
21
103
  setup(props, { emit }) {
104
+ const { rules } = toRefs(props);
22
105
  const innerValue = ref(props.value);
106
+ const isTouched = ref(false);
107
+ const isBlured = ref(false);
108
+
109
+ const { errorBucket, valid, validatable } = validateFormStateBuilder();
110
+
111
+ let fieldValidator = validateFormFieldBuilder(rules.value);
112
+
113
+ const hasError = computed(() => {
114
+ return errorBucket.value.length > 0;
115
+ });
116
+
117
+ const showErrorText = computed(() => hasError.value && isTouched.value);
23
118
 
24
119
  watch(
25
120
  () => props.value,
26
121
  () => {
27
122
  innerValue.value = props.value;
123
+ validate(innerValue.value);
28
124
  }
29
125
  );
30
126
 
@@ -32,11 +128,53 @@ export default Vue.extend({
32
128
  () => innerValue.value,
33
129
  () => {
34
130
  emit('input', innerValue.value);
131
+ emit('change', innerValue.value);
132
+ }
133
+ );
134
+
135
+ watch(
136
+ () => props.rules,
137
+ (newVal, oldVal) => {
138
+ if (deepEqual(newVal, oldVal)) return;
139
+ fieldValidator = validateFormFieldBuilder(rules.value);
140
+ validate = validateFormMethodBuilder(errorBucket, valid, fieldValidator);
141
+ validate(innerValue.value);
35
142
  }
36
143
  );
37
144
 
145
+ onBeforeMount(() => {
146
+ validate(innerValue.value);
147
+ });
148
+
149
+ let validate = validateFormMethodBuilder(errorBucket, valid, fieldValidator);
150
+
151
+ const onKeyUp = () => {
152
+ isTouched.value = true;
153
+ };
154
+
155
+ const onBlur = () => {
156
+ isBlured.value = true;
157
+ };
158
+
159
+ const reset = () => {
160
+ innerValue.value = '';
161
+ isTouched.value = true;
162
+ emit('input', innerValue.value);
163
+ };
164
+
38
165
  return {
39
166
  innerValue,
167
+ errorBucket,
168
+ valid,
169
+ validatable,
170
+ hasError,
171
+ isTouched,
172
+ isBlured,
173
+ showErrorText,
174
+ validate,
175
+ onKeyUp,
176
+ onBlur,
177
+ reset,
40
178
  };
41
179
  },
42
180
  });
@@ -3,9 +3,11 @@ import TextFieldV2 from '../TextFieldV2';
3
3
 
4
4
  describe('TextFieldV2 component', () => {
5
5
  let wrapper;
6
+ let component;
6
7
 
7
8
  beforeEach(() => {
8
9
  wrapper = shallowMount(TextFieldV2);
10
+ component = wrapper.vm;
9
11
  });
10
12
 
11
13
  test('Created hook', () => {
@@ -17,4 +19,23 @@ describe('TextFieldV2 component', () => {
17
19
  expect(wrapper.element).toMatchSnapshot();
18
20
  });
19
21
  });
22
+
23
+ describe('methods', () => {
24
+ it('reset', () => {
25
+ component.reset();
26
+ expect(component.isTouched).toBeTruthy();
27
+ expect(component.innerValue).toEqual('');
28
+ });
29
+
30
+ it('onKeyUp', () => {
31
+ component.onKeyUp();
32
+ expect(component.isTouched).toBeTruthy();
33
+ });
34
+
35
+ it('onBlur', () => {
36
+ component.onBlur();
37
+ expect(component.isBlured).toBeTruthy();
38
+ });
39
+
40
+ });
20
41
  });
@@ -20,7 +20,7 @@ export default Vue.extend({
20
20
  /**
21
21
  * Type of the bodytext
22
22
  */
23
- type: { type: Number as PropType<1 | 2>, default: 1 },
23
+ type: { type: [Number, String] as PropType<1 | 2>, default: 1 },
24
24
  /**
25
25
  * Variation of the bodytext
26
26
  */
@@ -3,7 +3,7 @@
3
3
  :weight="weight"
4
4
  :size="size"
5
5
  :key="key"
6
- :class="{ [`farm-caption--${variation}`]: true }"
6
+ :class="{ 'farm-caption': true, [`farm-caption--${variation}`]: true }"
7
7
  v-bind="$attrs"
8
8
  >
9
9
  <slot></slot>
@@ -21,7 +21,7 @@ export default Vue.extend({
21
21
  /**
22
22
  * Type of the heading
23
23
  */
24
- type: { type: Number as PropType<1 | 2 | 3 | 4 | 5 | 6>, default: 1 },
24
+ type: { type: [String, Number] as PropType<1 | 2 | 3 | 4 | 5 | 6>, default: 1 },
25
25
  },
26
26
  setup(props) {
27
27
  const { type } = toRefs(props);
@@ -24,15 +24,15 @@ export const Primary = () => ({
24
24
  };
25
25
  },
26
26
  template: `<div>
27
- <template v-for="type in types" :key="type">
27
+ <div v-for="type in types" :key="type">
28
28
  <farm-subtitle
29
29
  v-for="variation in variations"
30
- :key="variation"
30
+ :key="'primary_' + variation + type"
31
31
  :type="type"
32
32
  :variation="variation">
33
33
  Subtitle {{ type }} {{ variation }}
34
34
  </farm-subtitle>
35
- </template>
35
+ </div>
36
36
  </div>`,
37
37
  });
38
38
 
@@ -47,7 +47,7 @@ export const CustomTag = () => ({
47
47
  <farm-subtitle
48
48
  v-for="t in tags"
49
49
  :tag="t"
50
- :key="t"
50
+ :key="'customtag_' + t"
51
51
  :type="1"
52
52
  variation="regular"
53
53
  >
@@ -21,7 +21,7 @@ export default Vue.extend({
21
21
  /**
22
22
  * Type of the subtitle
23
23
  */
24
- type: { type: Number as PropType<1 | 2>, default: 1 },
24
+ type: { type: [Number, String] as PropType<1 | 2>, default: 1 },
25
25
  /**
26
26
  * Variation of the subtitle
27
27
  */
@@ -23,20 +23,32 @@ export default Vue.extend({
23
23
  inheritAttrs: true,
24
24
  name: 'farm-typography',
25
25
  props: {
26
+ /**
27
+ * Html tag
28
+ */
26
29
  tag: {
27
30
  type: String as PropType<
28
31
  'p' | 'span' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'legend' | 'label' | 'li'
29
32
  >,
30
33
  default: 'p',
31
34
  },
35
+ /**
36
+ * Size
37
+ */
32
38
  size: {
33
39
  type: String as PropType<'xs' | 'sm' | 'md' | 'lg' | 'xl'>,
34
40
  },
41
+ /**
42
+ * Line Height
43
+ */
35
44
  lineHeight: {
36
45
  type: String,
37
46
  },
47
+ /**
48
+ * Font-weight
49
+ */
38
50
  weight: {
39
- type: Number as PropType<100 | 200 | 300 | 400 | 500 | 600 | 700>,
51
+ type: [Number, String] as PropType<100 | 200 | 300 | 400 | 500 | 600 | 700>,
40
52
  },
41
53
  /**
42
54
  * Color
@@ -53,6 +65,7 @@ export default Vue.extend({
53
65
  | 'success'
54
66
  | 'extra-1'
55
67
  | 'extra-2'
68
+ | 'gray'
56
69
  >,
57
70
  default: 'default',
58
71
  },
@@ -6,7 +6,7 @@
6
6
  flex-basis: 0;
7
7
  flex-grow: 1;
8
8
  max-width: 100%;
9
- width: 100;
9
+ width: 100%;
10
10
 
11
11
  &--no-gutters {
12
12
  padding: 0;
@@ -8,6 +8,9 @@ import Vue from 'vue';
8
8
  export default Vue.extend({
9
9
  name: 'farm-line',
10
10
  props: {
11
+ /**
12
+ * Remove default margins
13
+ */
11
14
  noSpacing: {
12
15
  type: Boolean,
13
16
  default: false,
@@ -17,5 +20,5 @@ export default Vue.extend({
17
20
  </script>
18
21
 
19
22
  <style lang="scss" scoped>
20
- @import './Line.scss'
23
+ @import './Line'
21
24
  </style>
@@ -0,0 +1,119 @@
1
+ import { withDesign } from 'storybook-addon-designs';
2
+
3
+ export default {
4
+ title: 'Display/Dialog/Vuetify',
5
+ decorators: [withDesign],
6
+ parameters: {
7
+ viewMode: 'docs',
8
+ docs: {
9
+ description: {
10
+ component: `Dialog created by vuetify-dialog`,
11
+ },
12
+ },
13
+ },
14
+ };
15
+
16
+ export const Primary = () => ({
17
+ methods: {
18
+ openDialog() {
19
+ this.$dialog.confirm({
20
+ text: `Deseja realmente sair?`,
21
+ title: 'Sair',
22
+ actions: {
23
+ true: {
24
+ text: 'Sim',
25
+ color: 'secondary',
26
+ handle: () => {
27
+ alert('Clicked: Sim');
28
+ },
29
+ },
30
+ },
31
+ });
32
+ },
33
+ },
34
+ template: `<div style="display: flex; flex-direction: column; max-width: 160px; width: 100%;">
35
+ <farm-btn @click="openDialog">
36
+ Open
37
+ </farm-btn>
38
+ </div>`,
39
+ });
40
+
41
+ export const Default = () => ({
42
+ methods: {
43
+ openDialog() {
44
+ this.$dialog.confirm({
45
+ text: `Deseja realmente sair?`,
46
+ title: 'Sair',
47
+ actions: {
48
+ false: {
49
+ text: 'Cancelar',
50
+ color: 'secondary-outlined',
51
+ handle: () => {
52
+ alert('Clicked: Cancelar');
53
+ },
54
+ },
55
+ true: {
56
+ text: 'Sim',
57
+ color: 'secondary',
58
+ handle: () => {
59
+ alert('Clicked: Sim');
60
+ },
61
+ },
62
+ },
63
+ });
64
+ },
65
+ },
66
+ template: `<div style="display: flex; flex-direction: column; max-width: 160px; width: 100%;">
67
+ <farm-btn @click="openDialog">
68
+ Open
69
+ </farm-btn>
70
+ </div>`,
71
+ });
72
+
73
+ export const ErrorColor = () => ({
74
+ methods: {
75
+ openDialog() {
76
+ this.$dialog.confirm({
77
+ text: `Deseja realmente sair?`,
78
+ title: 'Sair',
79
+ actions: {
80
+ true: {
81
+ text: 'Sair',
82
+ color: 'error',
83
+ handle: () => {
84
+ alert('Clicked: Sair');
85
+ },
86
+ },
87
+ },
88
+ });
89
+ },
90
+ },
91
+ template: `<div style="display: flex; flex-direction: column; max-width: 160px; width: 100%;">
92
+ <farm-btn @click="openDialog">
93
+ Open
94
+ </farm-btn>
95
+ </div>`,
96
+ });
97
+
98
+
99
+ export const CustomContent = () => ({
100
+ methods: {
101
+ openDialog() {
102
+ this.$dialog.confirm({
103
+ text: `This is a text with <strong>html markup</strong> and<br />break line!`,
104
+ title: 'Sair',
105
+ actions: {
106
+ true: {
107
+ text: 'Sim',
108
+ color: 'secondary',
109
+ },
110
+ },
111
+ });
112
+ },
113
+ },
114
+ template: `<div style="display: flex; flex-direction: column; max-width: 160px; width: 100%;">
115
+ <farm-btn @click="openDialog">
116
+ Open
117
+ </farm-btn>
118
+ </div>`,
119
+ });
@@ -1,43 +0,0 @@
1
- import { withDesign } from 'storybook-addon-designs';
2
-
3
- export default {
4
- title: 'Display/Dialog/Confirm',
5
- decorators: [withDesign],
6
- parameters: {
7
- viewMode: 'docs',
8
- docs: {
9
- description: {
10
- component: `ConfirmDialog created by vuetify-dialog`,
11
- },
12
- },
13
- },
14
- };
15
-
16
- export const ConfirmDialog = () => ({
17
- methods: {
18
- openDialog() {
19
- this.$dialog.confirm({
20
- text: `Deseja realmente sair?`,
21
- title: 'Sair',
22
- actions: {
23
- false: {
24
- text: 'Cancelar',
25
- color: 'primary',
26
- },
27
- true: {
28
- text: 'Sim',
29
- color: 'secondary',
30
- handle: () => {
31
- this.$emit('onLogout');
32
- },
33
- },
34
- },
35
- });
36
- },
37
- },
38
- template: `<div style="display: flex; flex-direction: column; max-width: 160px; width: 100%;">
39
- <ConfirmButton @click="openDialog">
40
- Open
41
- </ConfirmButton>
42
- </div>`,
43
- });
@@ -1,181 +0,0 @@
1
- import { withDesign } from 'storybook-addon-designs';
2
-
3
- export default {
4
- title: 'Display/Dialog/Examples',
5
- decorators: [withDesign],
6
- component: Modal,
7
- };
8
-
9
- export const Modal = () => ({
10
- /*
11
- * How to create the default modal following FARM's Design System guideline
12
- */
13
- data() {
14
- return {
15
- inputVal: false,
16
- };
17
- },
18
- template: `<div>
19
- <v-dialog content-class="modal-default" v-model="inputVal">
20
- <DialogHeader title="Exemplo" @onClose="inputVal = false;" />
21
- <v-main class="pa-6 pt-12">
22
- Place dialog content here!
23
- </v-main>
24
- <DialogFooter :hasConfirm="false" @onClose="inputVal = false;" />
25
- </v-dialog>
26
- <v-btn @click="inputVal = true;" color="secondary">
27
- Clique para abrir
28
- </v-btn>
29
- </div>`,
30
- });
31
-
32
- export const ModalSmall = () => ({
33
- data() {
34
- return {
35
- showModalSmall: false,
36
- };
37
- },
38
- template: `<div>
39
- <v-dialog content-class="modal-default modal-default-small" v-model="showModalSmall">
40
- <DialogHeader title="Exemplo" @onClose="showModalSmall = false;" />
41
- <v-main class="pa-6 pt-12">
42
- Place dialog content here!
43
- </v-main>
44
- <DialogFooter :hasConfirm="false" @onClose="showModalSmall = false;" />
45
- </v-dialog>
46
- <v-btn @click="showModalSmall = true;" color="secondary">
47
- Clique para abrir
48
- </v-btn>
49
- </div>`,
50
- });
51
-
52
- export const ModalExtremeSmall = () => ({
53
- data() {
54
- return {
55
- showModalSmall: false,
56
- };
57
- },
58
- template: `<div>
59
- <v-dialog content-class="modal-default modal-default-x-small" v-model="showModalSmall">
60
- <DialogHeader title="Exemplo" @onClose="showModalSmall = false;" />
61
- <v-main class="pa-6 pt-12">
62
- Place dialog content here!
63
- </v-main>
64
- <DialogFooter :hasConfirm="false" @onClose="showModalSmall = false;" />
65
- </v-dialog>
66
- <v-btn @click="showModalSmall = true;" color="secondary">
67
- Clique para abrir
68
- </v-btn>
69
- </div>`,
70
- });
71
-
72
- export const ModalMedium = () => ({
73
- data() {
74
- return {
75
- showModalSmall: false,
76
- };
77
- },
78
- template: `<div>
79
- <v-dialog content-class="modal-default modal-default-md" v-model="showModalSmall">
80
- <DialogHeader title="Exemplo" @onClose="showModalSmall = false;" />
81
- <v-main class="pa-6 pt-12">
82
- Place dialog content here!
83
- </v-main>
84
- <DialogFooter :hasConfirm="false" @onClose="showModalSmall = false;" />
85
- </v-dialog>
86
- <v-btn @click="showModalSmall = true;" color="secondary">
87
- Clique para abrir
88
- </v-btn>
89
- </div>`,
90
- });
91
-
92
- export const ModalScrollVertical = () => ({
93
- data() {
94
- return {
95
- showModalSmall: false,
96
- };
97
- },
98
- template: `<div>
99
- <v-dialog content-class="modal-default modal-default-small" v-model="showModalSmall">
100
- <DialogHeader title="Exemplo" @onClose="showModalSmall = false;" />
101
- <v-main class="pa-6 pt-12">
102
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
103
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
104
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
105
- </v-main>
106
- <DialogFooter :hasConfirm="false" @onClose="showModalSmall = false;" />
107
- </v-dialog>
108
- <v-btn @click="showModalSmall = true;" color="secondary">
109
- Clique para abrir
110
- </v-btn>
111
- </div>`,
112
- });
113
-
114
- export const ModalScrollHorizontal = () => ({
115
- data() {
116
- return {
117
- open: false,
118
- };
119
- },
120
- template: `<div>
121
- <v-dialog content-class="modal-default modal-default-small" v-model="open">
122
- <DialogHeader title="Exemplo" @onClose="open = false;" />
123
- <v-main class="pa-6 pt-12" >
124
- <table>
125
- <tr>
126
- <th>Company</th>
127
- <th>Name</th>
128
- <th>Country</th>
129
- <th>Contact</th>
130
- <th>Email</th>
131
- </tr>
132
- <tr>
133
- <td>Alfreds Futterkiste</td>
134
- <td>Maria Anders</td>
135
- <td>Germany</td>
136
- <td>+55193764-8418</td>
137
- <td>najes39390@dufeed.com</td>
138
- </tr>
139
- <tr>
140
- <td>Centro comercial Moctezuma</td>
141
- <td>Francisco Chang</td>
142
- <td>Mexico</td>
143
- <td>+55193764-8418</td>
144
- <td>najes39390@dufeed.com</td>
145
- </tr>
146
- <tr>
147
- <td>Ernst Handel</td>
148
- <td>Roland Mendel</td>
149
- <td>Austria</td>
150
- <td>+55193764-8418</td>
151
- <td>najes39390@dufeed.com</td>
152
- </tr>
153
- <tr>
154
- <td>Island Trading</td>
155
- <td>Helen Bennett</td>
156
- <td>UK</td>
157
- <td>+55193764-8418</td>
158
- <td>najes39390@dufeed.com</td>
159
- </tr>
160
- <tr>
161
- <td>Laughing Bacchus Winecellars</td>
162
- <td>Yoshi Tannamuri</td>
163
- <td>Canada</td>
164
- <td>+55193764-8418</td>
165
- <td>najes39390@dufeed.com</td>
166
- </tr>
167
- <tr>
168
- <td>Magazzini Alimentari Riuniti</td>
169
- <td>Giovanni Rovelli</td>
170
- <td>Italy</td>
171
- <td>+55193764-8418</td>
172
- <td>najes39390@dufeed.com</td>
173
- </tr>
174
- </table>
175
- </v-main>
176
- </v-dialog>
177
- <v-btn @click="open = true;" color="secondary">
178
- Clique para abrir
179
- </v-btn>
180
- </div>`,
181
- });