@itfin/components 1.2.107 → 1.2.108

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": "@itfin/components",
3
- "version": "1.2.107",
3
+ "version": "1.2.108",
4
4
  "author": "Vitalii Savchuk <esvit666@gmail.com>",
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -0,0 +1,67 @@
1
+ <template>
2
+ <itf-button icon small @click.stop="copy">
3
+ <slot>
4
+ <itf-icon name="clipboard_copy" />
5
+ </slot>
6
+ </itf-button>
7
+ </template>
8
+ <script>
9
+ import { Vue, Component, Prop } from 'vue-property-decorator';
10
+ import itfIcon from '../icon/Icon';
11
+ import itfButton from '../button/Button';
12
+
13
+ export default @Component({
14
+ components: {
15
+ itfIcon,
16
+ itfButton
17
+ }
18
+ })
19
+ class CopyToClipboard extends Vue {
20
+ @Prop(String) value;
21
+
22
+ async copy () {
23
+ const showSuccess = this.$showSuccess;
24
+ const showError = this.$showError;
25
+ const $t = this.$t.bind(this);
26
+
27
+ function fallbackCopyTextToClipboard (text) {
28
+ const textArea = document.createElement('textarea');
29
+ textArea.value = text;
30
+
31
+ // Avoid scrolling to bottom
32
+ textArea.style.top = '0';
33
+ textArea.style.left = '0';
34
+ textArea.style.position = 'fixed';
35
+
36
+ document.body.appendChild(textArea);
37
+ textArea.focus();
38
+ textArea.select();
39
+
40
+ try {
41
+ if (document.execCommand('copy')) {
42
+ showSuccess($t('components.copyToClipboard.copyingToClipboardWasSuccessful'));
43
+ }
44
+ } catch (err) {
45
+ showError(err.message);
46
+ }
47
+
48
+ document.body.removeChild(textArea);
49
+ }
50
+ async function copyTextToClipboard (text) {
51
+ if (!navigator.clipboard) {
52
+ fallbackCopyTextToClipboard(text);
53
+ return;
54
+ }
55
+ try {
56
+ await navigator.clipboard.writeText(text);
57
+
58
+ showSuccess($t('components.copyToClipboard.copyingToClipboardWasSuccessful'));
59
+ } catch (err) {
60
+ showError(err.message);
61
+ }
62
+ }
63
+
64
+ await copyTextToClipboard(this.value);
65
+ }
66
+ }
67
+ </script>
@@ -2,17 +2,20 @@
2
2
  <div class="itf-inline-edit">
3
3
  <itf-select
4
4
  ref="input"
5
- class="input"
5
+ class="input flex-grow-1"
6
6
  role="button"
7
7
  multiple
8
8
  :placeholder="focused ? 'Search for an option...' : 'Empty'"
9
9
  :tabindex="1"
10
10
  :disabled="!editable"
11
- :options="field && field.Options"
11
+ :options="options"
12
12
  :reduce="option => option.Name"
13
13
  :get-option-label="option => option.Name"
14
14
  @search:focus="$emit('focus')"
15
- @search:blur="$emit('blur')">
15
+ @search:blur="$emit('blur')"
16
+ :value="itemsValue"
17
+ @input="onInput"
18
+ >
16
19
  <template #option="{ option }">
17
20
  <div>{{ option.Name }}</div>
18
21
  </template>
@@ -51,5 +54,20 @@ class itfCustomizeInlineMultiselect extends Vue {
51
54
  @Prop(Boolean) focused;
52
55
  @Prop(Boolean) editable;
53
56
  @Prop() field;
57
+
58
+ get itemsValue () {
59
+ return (this.value || '').toString().split(';;;').filter(v => v.length);
60
+ }
61
+
62
+ get options() {
63
+ const list = (this.field && this.field.Options) || [];
64
+ const notExists = this.itemsValue.filter(v => !list.find(o => o.Name === v));
65
+
66
+ return [...list, ...notExists.map(v => ({ Name: v }))];
67
+ }
68
+
69
+ onInput(val) {
70
+ this.$emit('input', val.join(';;;'));
71
+ }
54
72
  }
55
73
  </script>
@@ -10,7 +10,10 @@
10
10
  :reduce="option => option.Name"
11
11
  :get-option-label="option => option.Name"
12
12
  @search:focus="$emit('focus')"
13
- @search:blur="$emit('blur')">
13
+ @search:blur="$emit('blur')"
14
+ :value="value"
15
+ @input="$emit('input', $event)"
16
+ >
14
17
  <template #option="{ option }">
15
18
  <div>{{ option.Name }}</div>
16
19
  </template>
@@ -14,6 +14,7 @@
14
14
  :contenteditable="editable"
15
15
  v-html="value">
16
16
  </div>
17
+ <itf-copy-to-clipboard :value="value" />
17
18
  </div>
18
19
  </template>
19
20
  <style lang="scss" scoped>
@@ -36,12 +37,16 @@
36
37
  </style>
37
38
  <script>
38
39
  import { Vue, Component, Model, Prop } from 'vue-property-decorator';
40
+ import itfIcon from '../../icon/Icon.vue';
39
41
  import itfTextField from '../../text-field/TextField.vue';
42
+ import itfCopyToClipboard from '../../copyToClipboard/CopyToClipboard';
40
43
 
41
44
  export default @Component({
42
45
  name: 'itfCustomizeInlineText',
43
46
  components: {
44
- itfTextField
47
+ itfIcon,
48
+ itfTextField,
49
+ itfCopyToClipboard
45
50
  }
46
51
  })
47
52
 
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="itf-append-context" style="min-width: 300px">
3
- <div class="d-flex align-items-center px-3 py-2">
3
+ <div class="d-flex align-items-center px-3 py-2" sortable-skip>
4
4
  <!--div class="me-1">
5
5
  <itf-icon-popover title="Icon" removable :value="value.Icon" @input="setParam({ Icon: $event })">
6
6
  <itf-button slot="activator" icon>
@@ -8,7 +8,6 @@
8
8
  </itf-button>
9
9
  </itf-icon-popover>
10
10
  </div-->
11
-
12
11
  <div class="flex-grow-1">
13
12
  <itf-text-field ref="input" :value="value.Name" @input="setParam({ Name: $event })" />
14
13
  </div>
@@ -39,7 +38,7 @@
39
38
  </div>
40
39
  </div>
41
40
 
42
- <div v-if="isNewOptionVisible" class="px-3">
41
+ <div v-if="isNewOptionVisible" class="px-3" sortable-skip>
43
42
  <itf-text-field
44
43
  ref="newOptionInput"
45
44
  v-model="newOption"
@@ -117,7 +116,7 @@ import itfIconPopover from '../popover/IconPopover.vue';
117
116
  import { INLINE_TYPES } from './constants';
118
117
  import itfDeleteConfirmModal from '../modal/DeleteConfirmModal.vue';
119
118
  import PropertyItem from './PropertyItem.vue';
120
- import PropertiesPopupMenu from "@/components/customize/PropertiesPopupMenu.vue";
119
+ import PropertiesPopupMenu from './PropertiesPopupMenu.vue';
121
120
 
122
121
  export default @Component({
123
122
  components: {
@@ -165,7 +165,9 @@ class itfPropertiesList extends Vue {
165
165
  prop.hideEditMenu();
166
166
  }
167
167
  setTimeout(() => {
168
- this.$refs.properties[list.length - 1].showEditMenu();
168
+ if (this.$refs.properties && this.$refs.properties[list.length - 1]) {
169
+ this.$refs.properties[list.length - 1].showEditMenu();
170
+ }
169
171
  }, 10);
170
172
  });
171
173
  }
@@ -186,7 +188,9 @@ class itfPropertiesList extends Vue {
186
188
 
187
189
  this.$nextTick(() => {
188
190
  setTimeout(() => {
189
- this.$refs.properties[list.length - 1].showEditMenu();
191
+ if (this.$refs.properties && this.$refs.properties[list.length - 1]) {
192
+ this.$refs.properties[list.length - 1].showEditMenu();
193
+ }
190
194
  }, 10);
191
195
  });
192
196
  }
@@ -32,9 +32,8 @@
32
32
  <itf-button
33
33
  icon
34
34
  small
35
- v-if="multiple"
35
+ v-if="multiple && !disabled"
36
36
  ref="deselectButtons"
37
- :disabled="disabled"
38
37
  class="vs__deselect"
39
38
  :title="`Deselect ${getOptionLabel(option)}`"
40
39
  :aria-label="`Deselect ${getOptionLabel(option)}`"
package/src/locales/en.js CHANGED
@@ -93,5 +93,8 @@ module.exports = {
93
93
  hideMoreProperties: 'Hide {n} property|Hide {n} properties',
94
94
  deleteItem: 'Delete',
95
95
  areYouSureYouWantToDeleteThisItem: 'Are you sure you want to remove this option?',
96
+ },
97
+ copyToClipboard: {
98
+ copyingToClipboardWasSuccessful: 'Copying to clipboard was successful',
96
99
  }
97
100
  };
package/src/locales/uk.js CHANGED
@@ -93,5 +93,8 @@ module.exports = {
93
93
  hideMoreProperties: 'Приховати {n} поле|Приховати {n} полів',
94
94
  deleteItem: 'Видалити',
95
95
  areYouSureYouWantToDeleteThisItem: 'Ви впевнені, що хочете видалити цю опцію?',
96
+ },
97
+ copyToClipboard: {
98
+ copyingToClipboardWasSuccessful: 'Скопійовано в буфер',
96
99
  }
97
100
  };