@v1nt1248/3nclient-lib 0.2.33 → 0.2.34

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 (51) hide show
  1. package/README.md +2 -0
  2. package/dist/components/ui3n-dialog/types.d.ts +1 -1
  3. package/dist/components/ui3n-editable/types.d.ts +1 -1
  4. package/dist/components/ui3n-editable/ui3n-editable.vue.d.ts +1 -1
  5. package/dist/components/ui3n-editable/useContentEditable.d.ts +1 -1
  6. package/dist/directives/index.d.ts +2 -1
  7. package/dist/directives/ui3n-long-press.d.ts +27 -0
  8. package/dist/index.d.ts +3 -2
  9. package/dist/style.css +1 -1
  10. package/dist/types/directives.types.d.ts +7 -0
  11. package/dist/types/index.d.ts +3 -0
  12. package/dist/ui3n-components.d.ts +3 -1
  13. package/dist/ui3n-components.js +3902 -3845
  14. package/dist/ui3n-plugins.d.ts +1 -2
  15. package/dist/ui3n-plugins.js +2 -2
  16. package/dist/ui3n-utils.js +154 -144
  17. package/dist/utils/files/create-video-thumbnail.d.ts +1 -1
  18. package/dist/utils/for-vue/try-on-scope-dispose.d.ts +2 -0
  19. package/dist/utils/for-vue/unref-element.d.ts +2 -0
  20. package/dist/utils/index.d.ts +3 -1
  21. package/package.json +18 -13
  22. package/src/components/ui3n-autocomplete/ui3n-autocomplete.vue +32 -9
  23. package/src/components/ui3n-breadcrumbs/ui3n-breadcrumbs.vue +14 -14
  24. package/src/components/ui3n-button/ui3n-button.vue +229 -226
  25. package/src/components/ui3n-checkbox/ui3n-checkbox.vue +30 -7
  26. package/src/components/ui3n-chip/ui3n-chip.vue +113 -109
  27. package/src/components/ui3n-dialog/types.ts +1 -1
  28. package/src/components/ui3n-dialog/ui3n-dialog.vue +7 -8
  29. package/src/components/ui3n-editable/types.ts +1 -1
  30. package/src/components/ui3n-editable/ui3n-editable.vue +34 -12
  31. package/src/components/ui3n-editable/useContentEditable.ts +6 -3
  32. package/src/components/ui3n-icon/ui3n-icon.vue +1 -1
  33. package/src/components/ui3n-input/ui3n-input.vue +272 -273
  34. package/src/components/ui3n-input-file/ui3n-input-file.vue +2 -2
  35. package/src/components/ui3n-list/ui3n-list.vue +70 -60
  36. package/src/components/ui3n-menu/ui3n-menu.vue +1 -1
  37. package/src/components/ui3n-notification/ui3n-notification.vue +4 -1
  38. package/src/components/ui3n-progress/ui3n-progress-circular.vue +168 -147
  39. package/src/components/ui3n-progress/ui3n-progress-linear.vue +77 -73
  40. package/src/components/ui3n-radio-group/ui3n-radio.vue +178 -177
  41. package/src/components/ui3n-step-line-bar/ui3n-step-line-bar.vue +50 -46
  42. package/src/components/ui3n-switch/ui3n-switch.vue +114 -116
  43. package/src/components/ui3n-table/composables/useTable.ts +17 -9
  44. package/src/components/ui3n-table/ui3n-table-sort-icon.vue +9 -6
  45. package/src/components/ui3n-table/ui3n-table.vue +7 -5
  46. package/src/components/ui3n-text/ui3n-text.vue +157 -215
  47. package/src/components/ui3n-tooltip/ui3n-tooltip.vue +4 -5
  48. package/src/components/types/index.ts +0 -15
  49. /package/dist/{components/types/index.d.ts → types/components.types.d.ts} +0 -0
  50. /package/dist/{plugins/types.d.ts → types/plugins.types.d.ts} +0 -0
  51. /package/dist/utils/{for-we3n.d.ts → for-web3n.d.ts} +0 -0
@@ -1,163 +1,162 @@
1
1
  <script lang="ts" setup>
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
3
- import { computed, onMounted, ref, watch, useCssModule } from 'vue';
4
- import Ui3nIcon from '../ui3n-icon/ui3n-icon.vue';
5
- import Ui3nButton from '../ui3n-button/ui3n-button.vue';
6
- import type { Ui3nInputEmits, Ui3nInputProps } from './types';
7
-
8
- const props = defineProps<Ui3nInputProps>();
9
- const emits = defineEmits<Ui3nInputEmits>();
10
-
11
- const $css = useCssModule();
12
-
13
- const inputElement = ref<HTMLInputElement | null>(null);
14
- const text = ref<string>('');
15
- const isDirty = ref(false);
16
- const isFocused = ref(false);
17
- const errorMessage = ref('');
18
-
19
- const cssIconColor = computed(() => {
20
- if (props.disabled) {
21
- return 'var(--color-icon-control-primary-disabled)';
2
+ import { computed, onMounted, ref, watch, useCssModule } from 'vue';
3
+ import Ui3nIcon from '../ui3n-icon/ui3n-icon.vue';
4
+ import Ui3nButton from '../ui3n-button/ui3n-button.vue';
5
+ import type { Ui3nInputEmits, Ui3nInputProps } from './types';
6
+
7
+ const props = defineProps<Ui3nInputProps>();
8
+ const emits = defineEmits<Ui3nInputEmits>();
9
+
10
+ const $css = useCssModule();
11
+
12
+ const inputElement = ref<HTMLInputElement | null>(null);
13
+ const text = ref<string>('');
14
+ const isDirty = ref(false);
15
+ const isFocused = ref(false);
16
+ const errorMessage = ref('');
17
+
18
+ const cssIconColor = computed(() => {
19
+ if (props.disabled) {
20
+ return 'var(--color-icon-control-primary-disabled)';
21
+ }
22
+
23
+ return props.iconColor || 'var(--color-icon-control-primary-default)';
24
+ });
25
+
26
+ const isValid = computed(() => {
27
+ if (!isDirty.value) {
28
+ return true;
29
+ }
30
+
31
+ return !errorMessage.value;
32
+ });
33
+
34
+ const mainCssClasses = computed(() => {
35
+ const val = [$css.ui3nInput];
36
+ props.label && val.push($css.withLabel);
37
+ props.icon && val.push($css.withIcon);
38
+ props.clearable && text.value && val.push($css.clearable);
39
+ props.disabled && val.push($css.disabled);
40
+ ((!!errorMessage.value && !isValid.value) || props.displayStateMode === 'error') && val.push($css.error);
41
+ props.displayStateMode === 'success' && val.push($css.success);
42
+
43
+ return val;
44
+ });
45
+
46
+ const iconCssClasses = computed(() => {
47
+ const val = [$css.ui3nInputIcon];
48
+ props.disabled && val.push($css.ui3nInputIconDisabled);
49
+
50
+ return val;
51
+ });
52
+
53
+ const messageCssClasses = computed(() => {
54
+ const val = [$css.ui3nInputFieldMessage];
55
+ (errorMessage.value || (props.displayStateMode === 'error' && !!props.displayStateMessage)) &&
56
+ val.push($css.ui3nInputErrorMessage);
57
+ props.displayStateMode === 'success' && props.displayStateMessage && val.push($css.ui3nInputSuccessMessage);
58
+
59
+ return val;
60
+ });
61
+
62
+ function onFocus(event: Event) {
63
+ isFocused.value = true;
64
+ emits('focus', event);
65
+ }
66
+
67
+ function onBlur(event: Event) {
68
+ setTimeout(() => {
69
+ isFocused.value = false;
70
+ emits('blur', event);
71
+ }, 100);
22
72
  }
23
73
 
24
- return props.iconColor || 'var(--color-icon-control-primary-default)';
25
- });
74
+ function onChange(event: Event) {
75
+ const value = (event.target as HTMLInputElement).value;
76
+ validate(value);
77
+ emits('change', value);
78
+ }
79
+
80
+ function onInput(ev: Event) {
81
+ const value = (ev.target as HTMLInputElement).value;
82
+ text.value = value;
83
+ isDirty.value = true;
84
+ validate(value);
85
+ emits('update:modelValue', value);
86
+ emits('input', value);
87
+ }
88
+
89
+ function onEnterKeydown(event: KeyboardEvent) {
90
+ const { altKey, ctrlKey, metaKey, shiftKey, target } = event;
91
+ const value = (target as HTMLInputElement).value;
92
+ isDirty.value = true;
93
+ validate(value);
94
+ emits('update:modelValue', value);
95
+ emits('enter', { value, altKey, ctrlKey, metaKey, shiftKey });
96
+ }
26
97
 
27
- const isValid = computed(() => {
28
- if (!isDirty.value) {
29
- return true;
98
+ function onEscapeKeydown(event: KeyboardEvent) {
99
+ const value = (event.target as HTMLInputElement).value;
100
+ isDirty.value = true;
101
+ validate(value);
102
+ emits('update:modelValue', value);
103
+ emits('escape', event);
30
104
  }
31
105
 
32
- return !errorMessage.value;
33
- });
34
-
35
- const mainCssClasses = computed(() => {
36
- const val = [$css.ui3nInput];
37
- props.label && val.push($css.withLabel);
38
- props.icon && val.push($css.withIcon);
39
- props.clearable && text.value && val.push($css.clearable);
40
- props.disabled && val.push($css.disabled);
41
- ((!!errorMessage.value && !isValid.value) || props.displayStateMode === 'error') && val.push($css.error);
42
- props.displayStateMode === 'success' && val.push($css.success);
43
-
44
- return val;
45
- });
46
-
47
- const iconCssClasses = computed(() => {
48
- const val = [$css.ui3nInputIcon];
49
- props.disabled && val.push($css.ui3nInputIconDisabled);
50
-
51
- return val;
52
- });
53
-
54
- const messageCssClasses = computed(() => {
55
- const val = [$css.ui3nInputFieldMessage];
56
- (errorMessage.value || (props.displayStateMode === 'error' && !!props.displayStateMessage)) &&
57
- val.push($css.ui3nInputErrorMessage);
58
- props.displayStateMode === 'success' && props.displayStateMessage && val.push($css.ui3nInputSuccessMessage);
59
-
60
- return val;
61
- });
62
-
63
- function onFocus(event: Event) {
64
- isFocused.value = true;
65
- emits('focus', event);
66
- }
67
-
68
- function onBlur(event: Event) {
69
- setTimeout(() => {
70
- isFocused.value = false;
71
- emits('blur', event);
72
- }, 100);
73
- }
74
-
75
- function onChange(event: Event) {
76
- const value = (event.target as HTMLInputElement).value;
77
- validate(value);
78
- emits('change', value);
79
- }
80
-
81
- function onInput(ev: Event) {
82
- const value = (ev.target as HTMLInputElement).value;
83
- text.value = value;
84
- isDirty.value = true;
85
- validate(value);
86
- emits('update:modelValue', value);
87
- emits('input', value);
88
- }
89
-
90
- function onEnterKeydown(event: KeyboardEvent) {
91
- const { altKey, ctrlKey, metaKey, shiftKey, target } = event;
92
- const value = (target as HTMLInputElement).value;
93
- isDirty.value = true;
94
- validate(value);
95
- emits('update:modelValue', value);
96
- emits('enter', { value, altKey, ctrlKey, metaKey, shiftKey });
97
- }
98
-
99
- function onEscapeKeydown(event: KeyboardEvent) {
100
- const value = (event.target as HTMLInputElement).value;
101
- isDirty.value = true;
102
- validate(value);
103
- emits('update:modelValue', value);
104
- emits('escape', event);
105
- }
106
-
107
- function clearValue() {
108
- text.value = '';
109
- isDirty.value = false;
110
- validate('');
111
- emits('update:modelValue', '');
112
- emits('input', '');
113
- emits('change', '');
114
- emits('clear');
115
- }
116
-
117
- function validate(text: string) {
118
- errorMessage.value = '';
119
- if (props.rules && props.rules.length) {
120
- for (const validateFunction of props.rules) {
121
- if (typeof validateFunction === 'function') {
122
- const res = validateFunction(text);
123
- if (typeof res === 'string') {
124
- errorMessage.value += `${res} `;
106
+ function clearValue() {
107
+ text.value = '';
108
+ isDirty.value = false;
109
+ validate('');
110
+ emits('update:modelValue', '');
111
+ emits('input', '');
112
+ emits('change', '');
113
+ emits('clear');
114
+ }
115
+
116
+ function validate(text: string) {
117
+ errorMessage.value = '';
118
+ if (props.rules && props.rules.length) {
119
+ for (const validateFunction of props.rules) {
120
+ if (typeof validateFunction === 'function') {
121
+ const res = validateFunction(text);
122
+ if (typeof res === 'string') {
123
+ errorMessage.value += `${res} `;
124
+ }
125
125
  }
126
126
  }
127
127
  }
128
128
  }
129
- }
130
129
 
131
- defineExpose({
132
- isDirty,
133
- isFocused,
134
- clearValue,
135
- })
130
+ defineExpose({
131
+ isDirty,
132
+ isFocused,
133
+ clearValue,
134
+ });
136
135
 
137
- onMounted(() => {
138
- if (props.autofocus && inputElement.value) {
139
- inputElement.value.focus();
140
- }
136
+ onMounted(() => {
137
+ if (props.autofocus && inputElement.value) {
138
+ inputElement.value.focus();
139
+ }
141
140
 
142
- emits('init', inputElement.value!);
143
- });
144
-
145
- watch(
146
- () => props.modelValue,
147
- val => {
148
- text.value = val;
149
- validate(text.value);
150
- },
151
- { immediate: true },
152
- );
153
-
154
- watch(
155
- () => isValid.value,
156
- val => {
157
- emits('update:valid', val);
158
- },
159
- { immediate: true },
160
- );
141
+ emits('init', inputElement.value!);
142
+ });
143
+
144
+ watch(
145
+ () => props.modelValue,
146
+ val => {
147
+ text.value = val;
148
+ validate(text.value);
149
+ },
150
+ { immediate: true },
151
+ );
152
+
153
+ watch(
154
+ () => isValid.value,
155
+ val => {
156
+ emits('update:valid', val);
157
+ },
158
+ { immediate: true },
159
+ );
161
160
  </script>
162
161
 
163
162
  <template>
@@ -186,7 +185,7 @@ watch(
186
185
  @focusin="onFocus"
187
186
  @focusout="onBlur"
188
187
  @change="onChange"
189
- />
188
+ >
190
189
 
191
190
  <ui3n-icon
192
191
  v-if="icon"
@@ -227,161 +226,161 @@ watch(
227
226
  </template>
228
227
 
229
228
  <style lang="scss" module>
230
- .ui3nInput {
231
- --ui3n-input-height: var(--spacing-l);
232
- --ui3n-input-padding-left: var(--spacing-s);
233
- --ui3n-input-padding-right: var(--spacing-s);
234
-
235
- position: relative;
236
- width: 100%;
237
- padding: 1px;
238
- border-radius: var(--spacing-xs);
239
-
240
- &:hover {
241
- .ui3nInputField:not(:focus-within) {
242
- background-color: var(--color-bg-control-secondary-hover);
243
-
244
- &::placeholder {
245
- color: var(--color-text-control-secondary-hover);
229
+ .ui3nInput {
230
+ --ui3n-input-height: var(--spacing-l);
231
+ --ui3n-input-padding-left: var(--spacing-s);
232
+ --ui3n-input-padding-right: var(--spacing-s);
233
+
234
+ position: relative;
235
+ width: 100%;
236
+ padding: 1px;
237
+ border-radius: var(--spacing-xs);
238
+
239
+ &:hover {
240
+ .ui3nInputField:not(:focus-within) {
241
+ background-color: var(--color-bg-control-secondary-hover);
242
+
243
+ &::placeholder {
244
+ color: var(--color-text-control-secondary-hover);
245
+ }
246
246
  }
247
247
  }
248
- }
249
248
 
250
- &:focus-within {
251
- .ui3nInputField {
252
- background-color: var(--color-bg-control-secondary-focused);
253
- outline: 1px solid var(--color-border-control-accent-focused);
254
- }
249
+ &:focus-within {
250
+ .ui3nInputField {
251
+ background-color: var(--color-bg-control-secondary-focused);
252
+ outline: 1px solid var(--color-border-control-accent-focused);
253
+ }
255
254
 
256
- .ui3nInputIcon {
257
- color: v-bind(cssIconColor) !important;
255
+ .ui3nInputIcon {
256
+ color: v-bind(cssIconColor) !important;
257
+ }
258
258
  }
259
259
  }
260
- }
261
-
262
- .ui3nInputLabel {
263
- display: block;
264
- width: 100%;
265
- font-size: var(--font-12);
266
- line-height: var(--font-16);
267
- font-weight: 500;
268
- color: var(--color-text-control-primary-default);
269
- margin-bottom: var(--spacing-xs);
270
- }
271
-
272
- .ui3nInputField {
273
- display: block;
274
- box-sizing: border-box;
275
- width: 100%;
276
- position: relative;
277
- border: none;
278
- outline: none;
279
- height: var(--ui3n-input-height);
280
- padding: 0 var(--ui3n-input-padding-right) 0 var(--ui3n-input-padding-left);
281
- border-radius: var(--spacing-xs);
282
- background-color: var(--color-bg-control-secondary-default);
283
- font-size: var(--font-13);
284
- line-height: var(--font-16);
285
- font-weight: 400;
286
- color: var(--color-text-control-primary-default);
287
- transition: all 0.2s ease-in-out;
288
-
289
- &::placeholder {
290
- color: var(--color-text-control-secondary-default);
291
- font-style: italic;
260
+
261
+ .ui3nInputLabel {
262
+ display: block;
263
+ width: 100%;
264
+ font-size: var(--font-12);
265
+ line-height: var(--font-16);
266
+ font-weight: 500;
267
+ color: var(--color-text-control-primary-default);
268
+ margin-bottom: var(--spacing-xs);
269
+ }
270
+
271
+ .ui3nInputField {
272
+ display: block;
273
+ box-sizing: border-box;
274
+ width: 100%;
275
+ position: relative;
276
+ border: none;
277
+ outline: none;
278
+ height: var(--ui3n-input-height);
279
+ padding: 0 var(--ui3n-input-padding-right) 0 var(--ui3n-input-padding-left);
280
+ border-radius: var(--spacing-xs);
281
+ background-color: var(--color-bg-control-secondary-default);
292
282
  font-size: var(--font-13);
293
283
  line-height: var(--font-16);
294
284
  font-weight: 400;
285
+ color: var(--color-text-control-primary-default);
286
+ transition: all 0.2s ease-in-out;
287
+
288
+ &::placeholder {
289
+ color: var(--color-text-control-secondary-default);
290
+ font-style: italic;
291
+ font-size: var(--font-13);
292
+ line-height: var(--font-16);
293
+ font-weight: 400;
294
+ }
295
+
296
+ &[disabled] {
297
+ background-color: var(--color-bg-control-secondary-disabled);
298
+ color: var(--color-text-control-secondary-disabled);
299
+ }
295
300
  }
296
301
 
297
- &[disabled] {
298
- background-color: var(--color-bg-control-secondary-disabled);
299
- color: var(--color-text-control-secondary-disabled);
302
+ .ui3nInputIcon {
303
+ position: absolute;
304
+ left: var(--half-size, 4px);
305
+ top: calc((var(--ui3n-input-height) - 16px) / 2);
306
+ color: var(--color-icon-control-secondary-default) !important;
300
307
  }
301
- }
302
-
303
- .ui3nInputIcon {
304
- position: absolute;
305
- left: var(--half-size, 4px);
306
- top: calc((var(--ui3n-input-height) - 16px) / 2);
307
- color: var(--color-icon-control-secondary-default) !important;
308
- }
309
-
310
- .ui3nInputIconDisabled {
311
- color: v-bind(cssIconColor) !important;
312
- }
313
-
314
- .clearBtn {
315
- position: absolute;
316
- right: 0;
317
- top: calc((var(--ui3n-input-height) - 24px) / 2);
318
- z-index: 2;
319
- }
320
-
321
- .ui3nInputFieldMessage {
322
- font-style: italic;
323
- font-size: var(--font-10);
324
- font-weight: 400;
325
- line-height: 1.4;
326
- margin-top: 2px;
327
-
328
- &.ui3nInputErrorMessage {
329
- color: var(--error-content-default);
308
+
309
+ .ui3nInputIconDisabled {
310
+ color: v-bind(cssIconColor) !important;
330
311
  }
331
312
 
332
- &.ui3nInputSuccessMessage {
333
- color: var(--success-content-default);
313
+ .clearBtn {
314
+ position: absolute;
315
+ right: 0;
316
+ top: calc((var(--ui3n-input-height) - 24px) / 2);
317
+ z-index: 2;
334
318
  }
335
- }
336
319
 
337
- .clearable {
338
- --ui3n-input-padding-right: var(--spacing-ml);
339
- }
320
+ .ui3nInputFieldMessage {
321
+ font-style: italic;
322
+ font-size: var(--font-10);
323
+ font-weight: 400;
324
+ line-height: 1.4;
325
+ margin-top: 2px;
340
326
 
341
- .withIcon {
342
- --ui3n-input-padding-left: var(--spacing-ml);
343
- }
327
+ &.ui3nInputErrorMessage {
328
+ color: var(--error-content-default);
329
+ }
344
330
 
345
- .error {
346
- .ui3nInputLabel {
347
- color: var(--error-content-default) !important;
331
+ &.ui3nInputSuccessMessage {
332
+ color: var(--success-content-default);
333
+ }
348
334
  }
349
335
 
350
- .ui3nInputField {
351
- outline: 1px solid var(--error-content-default) !important;
336
+ .clearable {
337
+ --ui3n-input-padding-right: var(--spacing-ml);
352
338
  }
353
- }
354
339
 
355
- .success {
356
- .ui3nInputLabel {
357
- color: var(--success-content-default) !important;
340
+ .withIcon {
341
+ --ui3n-input-padding-left: var(--spacing-ml);
358
342
  }
359
- }
360
343
 
361
- .ui3nInputSuccessIcon {
362
- position: absolute;
363
- right: var(--spacing-s);
364
- bottom: var(--spacing-s);
365
- }
344
+ .error {
345
+ .ui3nInputLabel {
346
+ color: var(--error-content-default) !important;
347
+ }
366
348
 
367
- .disabled {
368
- pointer-events: none;
369
- user-select: none;
370
- }
349
+ .ui3nInputField {
350
+ outline: 1px solid var(--error-content-default) !important;
351
+ }
352
+ }
371
353
 
372
- .withLabel {
373
- .ui3nInputIcon {
374
- top: calc((var(--ui3n-input-height) - 16px) / 2 + 20px);
354
+ .success {
355
+ .ui3nInputLabel {
356
+ color: var(--success-content-default) !important;
357
+ }
375
358
  }
376
359
 
377
360
  .ui3nInputSuccessIcon {
378
- bottom: auto;
379
- top: calc((var(--ui3n-input-height) - 16px) / 2 + 20px);
361
+ position: absolute;
362
+ right: var(--spacing-s);
363
+ bottom: var(--spacing-s);
380
364
  }
381
365
 
382
- .clearBtn {
383
- top: calc((var(--ui3n-input-height) - 24px) / 2 + 20px);
384
- z-index: 1;
366
+ .disabled {
367
+ pointer-events: none;
368
+ user-select: none;
369
+ }
370
+
371
+ .withLabel {
372
+ .ui3nInputIcon {
373
+ top: calc((var(--ui3n-input-height) - 16px) / 2 + 20px);
374
+ }
375
+
376
+ .ui3nInputSuccessIcon {
377
+ bottom: auto;
378
+ top: calc((var(--ui3n-input-height) - 16px) / 2 + 20px);
379
+ }
380
+
381
+ .clearBtn {
382
+ top: calc((var(--ui3n-input-height) - 24px) / 2 + 20px);
383
+ z-index: 1;
384
+ }
385
385
  }
386
- }
387
386
  </style>
@@ -18,7 +18,7 @@
18
18
  :accept="allowedFileTypes"
19
19
  :disabled="disabled"
20
20
  @change="onChange"
21
- />
21
+ >
22
22
  </div>
23
23
  </template>
24
24
 
@@ -29,7 +29,7 @@
29
29
  import trim from 'lodash/trim';
30
30
  import { getRandomId, formatFileSize } from '@/utils';
31
31
  import type { Ui3nInputFileProps, Ui3nInputFileEmits } from './types';
32
- import type { Nullable } from '@/components/types';
32
+ import type { Nullable } from '@/types';
33
33
 
34
34
  const props = withDefaults(defineProps<Ui3nInputFileProps>(), {
35
35
  modelValue: () => [],