@itfin/components 1.2.107 → 1.2.109

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.109",
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
  }
@@ -3,7 +3,7 @@
3
3
  <slot name="header"></slot>
4
4
 
5
5
  <div class="itf-board-card-inner d-flex">
6
- <div class="flex-grow-1 itf-board-card-inner-content">
6
+ <div class="flex-grow-1">
7
7
  <slot>{{text}}</slot>
8
8
  </div>
9
9
  <div v-if="dropdown">
@@ -15,7 +15,7 @@
15
15
  {{ newItemText }}
16
16
  </itf-button>
17
17
 
18
- <div class="itf-board-cards-wrapper" ref="container">
18
+ <div class="itf-board-cards-wrapper" ref="container" :class="{'empty-column': !items.length}">
19
19
  <template v-if="!items.length">
20
20
  <slot name="empty"></slot>
21
21
  </template>
@@ -22,6 +22,8 @@
22
22
  display: flex;
23
23
  flex-wrap: nowrap;
24
24
  flex-direction: column;
25
+ overflow-x: scroll;
26
+ overflow-y: hidden;
25
27
 
26
28
  .draggable-mirror {
27
29
  z-index: 100000001;
@@ -107,6 +109,7 @@
107
109
  .itf-board-column {
108
110
  position: relative;
109
111
  width: var(--itf-board-column-width);
112
+ min-width: var(--itf-board-column-width);
110
113
  border-radius: 0 0 var(--bs-border-radius) var(--bs-border-radius);
111
114
 
112
115
  &__title {
@@ -150,12 +153,18 @@
150
153
  }
151
154
 
152
155
  .itf-board-titles {
156
+ width: max-content;
153
157
  border-bottom: 1px solid var(--itf-board-card-border-color);
154
158
  }
155
159
 
156
160
  .itf-board-columns {
157
161
  max-height: 100%;
162
+ padding-bottom: 45px;
158
163
 
164
+ .empty-column .itf-board-card-space.bottom {
165
+ top: 0;
166
+ height: 100%;
167
+ }
159
168
  .itf-board-column {
160
169
  display: flex;
161
170
  }
@@ -181,8 +190,8 @@
181
190
  right: 0;
182
191
  top: -50px;
183
192
  left: 0;
184
- bottom: -50px;
185
- height: 100px;
193
+ bottom: 0px;
194
+ height: 50px;
186
195
  }
187
196
  &.bottom {
188
197
  top: auto;
@@ -225,17 +234,7 @@
225
234
  font-size: .875rem;
226
235
  word-wrap: break-word;
227
236
  -webkit-line-clamp: unset;
228
- overflow: hidden;
229
237
  word-break: break-word;
230
-
231
- .itf-board-card-inner-content {
232
- padding-right: 0.2rem;
233
- overflow-x: hidden;
234
- }
235
- }
236
-
237
- .itf-board-card-footer {
238
- overflow-x: hidden;
239
238
  }
240
239
  }
241
240
 
@@ -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
  };