@milaboratories/uikit 2.2.78 → 2.2.80

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 (36) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/pl-uikit.css +1 -0
  3. package/dist/pl-uikit.js +5043 -4909
  4. package/dist/pl-uikit.js.map +1 -1
  5. package/dist/src/components/PlAlert/PlAlert.vue.d.ts +1 -1
  6. package/dist/src/components/PlAlert/PlAlert.vue.d.ts.map +1 -1
  7. package/dist/src/components/PlClipboard/PlClipboard.vue.d.ts +12 -0
  8. package/dist/src/components/PlClipboard/PlClipboard.vue.d.ts.map +1 -0
  9. package/dist/src/components/PlClipboard/index.d.ts +2 -0
  10. package/dist/src/components/PlClipboard/index.d.ts.map +1 -0
  11. package/dist/src/components/PlErrorAlert/PlErrorAlert.vue.d.ts +26 -0
  12. package/dist/src/components/PlErrorAlert/PlErrorAlert.vue.d.ts.map +1 -0
  13. package/dist/src/components/PlErrorAlert/index.d.ts +2 -0
  14. package/dist/src/components/PlErrorAlert/index.d.ts.map +1 -0
  15. package/dist/src/components/PlErrorBoundary/PlErrorBoundary.vue.d.ts +92 -0
  16. package/dist/src/components/PlErrorBoundary/PlErrorBoundary.vue.d.ts.map +1 -0
  17. package/dist/src/components/PlErrorBoundary/index.d.ts +2 -0
  18. package/dist/src/components/PlErrorBoundary/index.d.ts.map +1 -0
  19. package/dist/src/components/PlFileInput/PlFileInput.vue.d.ts.map +1 -1
  20. package/dist/src/index.d.ts +1 -0
  21. package/dist/src/index.d.ts.map +1 -1
  22. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  23. package/package.json +6 -9
  24. package/src/assets/base.scss +3 -2
  25. package/src/assets/variables.scss +2 -0
  26. package/src/components/PlAutocomplete/PlAutocomplete.vue +1 -1
  27. package/src/components/PlClipboard/PlClipboard.vue +47 -0
  28. package/src/components/PlClipboard/index.ts +1 -0
  29. package/src/components/PlErrorAlert/PlErrorAlert.vue +105 -0
  30. package/src/components/PlErrorAlert/index.ts +1 -0
  31. package/src/components/PlErrorBoundary/PlErrorBoundary.vue +59 -0
  32. package/src/components/PlErrorBoundary/index.ts +1 -0
  33. package/src/components/PlFileInput/PlFileInput.vue +5 -9
  34. package/src/index.ts +2 -0
  35. package/vite.config.ts +0 -7
  36. package/dist/style.css +0 -1
package/package.json CHANGED
@@ -1,21 +1,18 @@
1
1
  {
2
2
  "name": "@milaboratories/uikit",
3
- "version": "2.2.78",
3
+ "version": "2.2.80",
4
4
  "type": "module",
5
5
  "main": "dist/pl-uikit.js",
6
6
  "module": "dist/pl-uikit.js",
7
7
  "types": "dist/src/index.d.ts",
8
- "styles": "dist/style.css",
8
+ "styles": "dist/pl-uikit.css",
9
9
  "exports": {
10
10
  ".": {
11
- "style": "./styles/main.css",
12
11
  "types": "./dist/src/index.d.ts",
13
12
  "default": "./dist/pl-uikit.js"
14
13
  },
15
- "./styles": {
16
- "default": "./dist/style.css"
17
- },
18
- "./*": "./*"
14
+ "./styles": "./dist/pl-uikit.css",
15
+ "./styles/mixins": "./src/assets/mixins.scss"
19
16
  },
20
17
  "dependencies": {
21
18
  "vue": "^3.5.13",
@@ -29,13 +26,13 @@
29
26
  "@vitejs/plugin-vue": "^5.2.3",
30
27
  "tsc-alias": "^1.8.11",
31
28
  "vitest": "^2.1.9",
32
- "vite": "^5.4.11",
29
+ "vite": "^6.3.5",
33
30
  "vue-tsc": "^2.1.10",
34
31
  "yarpm": "^1.2.0",
35
32
  "svgo": "^3.3.2",
36
33
  "@types/d3": "^7.4.3",
37
34
  "@milaboratories/eslint-config": "^1.0.4",
38
- "@milaboratories/helpers": "^1.6.11",
35
+ "@milaboratories/helpers": "^1.6.12",
39
36
  "@platforma-sdk/model": "^1.33.2"
40
37
  },
41
38
  "scripts": {
@@ -37,6 +37,7 @@
37
37
 
38
38
  --font-size-base: 14px;
39
39
  --font-weigh-base: 500;
40
+ --line-height-base: 16px;
40
41
 
41
42
  --control-height: 40px;
42
43
  --control-hover-color: #363452;
@@ -135,8 +136,8 @@ body,
135
136
  height: 100%;
136
137
  padding: 0;
137
138
  margin: 0;
138
- font-size: 14px;
139
- line-height: 16px;
139
+ font-size: var(--font-size-base);
140
+ line-height: var(--line-height-base);
140
141
  color: var(--main-dark-color);
141
142
  box-sizing: border-box;
142
143
  position: relative;
@@ -39,6 +39,7 @@
39
39
  --bg-base-light: #f7f8fa;
40
40
  --bg-elevated-01: #ffffff;
41
41
  --bg-elevated-02: #e1e3eb;
42
+ --bg-error: #FFF5F5;
42
43
  //filled
43
44
  --filled-V-BG: #d0f0c0;
44
45
  --filled-D-BG: #ffcecc;
@@ -120,6 +121,7 @@
120
121
  --bg-base-light: #0d0d0f;
121
122
  --bg-elevated-01: #1b1b1f;
122
123
  --bg-elevated-02: #2d2d33;
124
+ --bg-error: #FFF5F5;
123
125
  //filled
124
126
  --filled-V-BG: rgba(66, 184, 66, 0.4);
125
127
  --filled-D-BG: rgba(229, 83, 229, 0.4);
@@ -209,7 +209,7 @@ const toggleOpen = () => {
209
209
 
210
210
  watch(() => data.open, (v) => {
211
211
  search.value = v ? '' : null;
212
- })
212
+ });
213
213
 
214
214
  const onInputFocus = () => {
215
215
  data.open = true;
@@ -0,0 +1,47 @@
1
+ <script lang="ts">
2
+ export default {
3
+ name: 'PlClipboard',
4
+ };
5
+ </script>
6
+
7
+ <script lang="ts" setup>
8
+ import { PlMaskIcon16 } from '@/components/PlMaskIcon16';
9
+ import type { Size } from '@/types.ts';
10
+ import { computed, onUnmounted, ref } from 'vue';
11
+
12
+ const props = defineProps<{
13
+ size?: Size;
14
+ }>();
15
+
16
+ const emit = defineEmits(['copy']);
17
+
18
+ const copyEffect = ref<boolean>(false);
19
+
20
+ const iconName = computed(() => copyEffect.value ? 'clipboard-copied' : 'clipboard');
21
+
22
+ let timeoutId: undefined | number;
23
+
24
+ function onCopy() {
25
+ clearTimeout(timeoutId);
26
+ copyEffect.value = true;
27
+ emit('copy');
28
+ timeoutId = window.setTimeout(() => {
29
+ copyEffect.value = false;
30
+ }, 1000);
31
+ }
32
+
33
+ onUnmounted(() => {
34
+ clearTimeout(timeoutId);
35
+ });
36
+ </script>
37
+
38
+ <template>
39
+ <PlMaskIcon16 :name="iconName" :size="props.size" :class="$style.copy" @click="onCopy" />
40
+ </template>
41
+
42
+ <style module>
43
+ .copy {
44
+ cursor: pointer;
45
+ display: block;
46
+ }
47
+ </style>
@@ -0,0 +1 @@
1
+ export { default as PlClipboard } from './PlClipboard.vue';
@@ -0,0 +1,105 @@
1
+ <script lang="ts">
2
+ export default {
3
+ name: 'PlErrorAlert',
4
+ };
5
+ </script>
6
+
7
+ <script lang="ts" setup>
8
+ import { PlClipboard } from '@/components/PlClipboard';
9
+ import { PlMaskIcon16 } from '@/components/PlMaskIcon16';
10
+
11
+ const props = withDefaults(
12
+ defineProps<{
13
+ title?: string;
14
+ message?: string;
15
+ maxHeight?: string;
16
+ copyMessage?: string;
17
+ }>(),
18
+ {
19
+ title: undefined,
20
+ message: undefined,
21
+ maxHeight: '300px',
22
+ copyMessage: undefined,
23
+ },
24
+ );
25
+
26
+ function onCopy() {
27
+ const value = props.copyMessage ?? props.message;
28
+ if (typeof value === 'string') {
29
+ navigator.clipboard.writeText(value);
30
+ }
31
+ }
32
+ </script>
33
+
34
+ <template>
35
+ <div :style="{ maxHeight: props.maxHeight }" :class="$style.root">
36
+ <PlClipboard :class="$style.copy" @copy="onCopy" />
37
+ <slot name="title">
38
+ <div :class="$style.title">
39
+ <PlMaskIcon16 :class="$style.titleIcon" name="warning" />
40
+ <div :class="$style.titleText">{{ props.title }}</div>
41
+ </div>
42
+ </slot>
43
+ <slot name="message">
44
+ <div :class="$style.message">
45
+ {{ props.message }}
46
+ </div>
47
+ </slot>
48
+ </div>
49
+ </template>
50
+
51
+ <style module>
52
+ .root {
53
+ position: relative;
54
+ overflow: auto;
55
+ display: flex;
56
+ flex-direction: column;
57
+ gap: 12px;
58
+ padding: 12px;
59
+ background: var(--bg-error);
60
+ border: 1px var(--border-color-error) solid;
61
+ border-radius: var(--border-radius-control);
62
+ /* color: var(--txt-error); */
63
+ }
64
+
65
+ .copy {
66
+ position: absolute;
67
+ right: 12px;
68
+ top: 12px;
69
+ opacity: 0.4;
70
+ transition: opacity 0.3s;
71
+
72
+ &:hover {
73
+ opacity: 1;
74
+ }
75
+ }
76
+
77
+ .title {
78
+ display: flex;
79
+ align-items: center;
80
+ gap: 10px;
81
+ max-width: calc(100% - 20px);
82
+ min-height: 24px;
83
+ line-height: 24px;
84
+ font-weight: bold;
85
+ overflow: hidden;
86
+ }
87
+
88
+ .titleIcon {
89
+ background-color: var(--txt-error);
90
+ }
91
+
92
+ .titleText {
93
+ width: 100%;
94
+ overflow: hidden;
95
+ text-overflow: ellipsis;
96
+ }
97
+
98
+ .message {
99
+ overflow: auto;
100
+ max-height: 100%;
101
+ white-space: pre-wrap;
102
+ word-break: break-word;
103
+ font-family: var(--font-family-monospace);
104
+ }
105
+ </style>
@@ -0,0 +1 @@
1
+ export { default as PlErrorAlert } from './PlErrorAlert.vue';
@@ -0,0 +1,59 @@
1
+ <script lang="ts" setup>
2
+ import { computed, onErrorCaptured, ref, onBeforeUpdate } from 'vue';
3
+ import { PlErrorAlert } from '@/components/PlErrorAlert';
4
+ import { isErrorLike, tryDo } from '@milaboratories/helpers';
5
+
6
+ const extractMessage = (err: unknown): undefined | string => {
7
+ if (err == null) {
8
+ return undefined;
9
+ }
10
+
11
+ if (isErrorLike(err)) {
12
+ return err.stack == null || err.stack.length === 0
13
+ ? err.message
14
+ : err.stack.includes(err.message)
15
+ ? err.stack
16
+ : err.message + '\n' + err.stack;
17
+ }
18
+
19
+ return tryDo(() => JSON.stringify(err, null, 4), () => err.toString());
20
+ };
21
+
22
+ const data = ref<null | {
23
+ title: undefined | string;
24
+ error: Error;
25
+ }>(null);
26
+
27
+ const error = computed(() => data.value?.error);
28
+ const message = computed(() => extractMessage(error.value));
29
+
30
+ function reset() {
31
+ data.value = null;
32
+ }
33
+
34
+ const errorAlert = ref<InstanceType<typeof PlErrorAlert> | null>(null);
35
+
36
+ onBeforeUpdate(() => {
37
+ // If an error is currently displayed, and the component updates (e.g., due to slot content changing),
38
+ // reset the error state.
39
+ if (data.value !== null && errorAlert.value) {
40
+ reset();
41
+ }
42
+ });
43
+
44
+ onErrorCaptured((err, instance) => {
45
+ data.value = {
46
+ title: instance?.$?.type?.name ?? undefined,
47
+ error: err,
48
+ };
49
+ // stop error propagation
50
+ return false;
51
+ });
52
+
53
+ defineExpose({ error, reset });
54
+ </script>
55
+
56
+ <template>
57
+ <slot />
58
+ <PlErrorAlert v-if="error" ref="errorAlert" :message="message" :title="data?.title" />
59
+ </template>
@@ -0,0 +1 @@
1
+ export { default as PlErrorBoundary } from './PlErrorBoundary.vue';
@@ -9,7 +9,7 @@ import type { ImportFileHandle, ImportProgress } from '@platforma-sdk/model';
9
9
  import { getFileNameFromHandle, getFilePathFromHandle } from '@platforma-sdk/model';
10
10
  import DoubleContour from '@/utils/DoubleContour.vue';
11
11
  import { useLabelNotch } from '@/utils/useLabelNotch';
12
- import { prettyBytes, tryDo } from '@milaboratories/helpers';
12
+ import { isErrorLike, prettyBytes, tryDo } from '@milaboratories/helpers';
13
13
 
14
14
  const data = reactive({
15
15
  fileDialogOpen: false,
@@ -99,10 +99,6 @@ const tryValue = <T extends ImportFileHandle>(v: T | undefined, cb: (v: T) => st
99
99
  }
100
100
  };
101
101
 
102
- const isErrorObject = (error: unknown): error is { message: string } => {
103
- return typeof error === 'object' && error != null && 'message' in error && typeof error.message === 'string';
104
- };
105
-
106
102
  const fileName = computed(() => tryValue(props.modelValue, getFileNameFromHandle));
107
103
 
108
104
  const filePath = computed(() => tryValue(props.modelValue, getFilePathFromHandle));
@@ -118,7 +114,7 @@ const computedError = computed(() => {
118
114
  message = data.error;
119
115
  } else if (typeof props.error === 'string') {
120
116
  message = props.error;
121
- } else if (isErrorObject(props.error)) {
117
+ } else if (isErrorLike(props.error)) {
122
118
  message = props.error.message;
123
119
  } else if (props.error != null) {
124
120
  const unknownString = tryDo(() => JSON.stringify(props.error, null, 4), () => String(props.error));
@@ -191,13 +187,13 @@ if (!props.cellStyle) {
191
187
  <div :class="{ 'pl-file-input__cell-style': !!cellStyle, 'has-file': !!fileName }" class="pl-file-input__envelope">
192
188
  <div
193
189
  ref="rootRef"
190
+ :class="{ dashed, error: hasErrors }"
194
191
  class="pl-file-input"
195
192
  tabindex="0"
196
- :class="{ dashed, error: hasErrors }"
197
193
  @keyup.enter="openFileDialog"
198
194
  @click.stop="openFileDialog"
199
195
  >
200
- <div class="pl-file-input__progress" :style="progressStyle" />
196
+ <div :style="progressStyle" class="pl-file-input__progress" />
201
197
  <label v-if="!cellStyle && label" ref="label">
202
198
  <i v-if="required" class="required-icon" />
203
199
  <span>{{ label }}</span>
@@ -226,9 +222,9 @@ if (!props.cellStyle) {
226
222
  </div>
227
223
  <PlFileDialog
228
224
  v-model="data.fileDialogOpen"
225
+ :close-on-outside-click="fileDialogCloseOnOutsideClick"
229
226
  :extensions="extensions"
230
227
  :title="fileDialogTitle"
231
- :close-on-outside-click="fileDialogCloseOnOutsideClick"
232
228
  @import:files="onImport"
233
229
  />
234
230
  </template>
package/src/index.ts CHANGED
@@ -17,6 +17,8 @@ export * from './layout/PlGrid';
17
17
  /**
18
18
  * Components
19
19
  */
20
+ export * from './components/PlErrorBoundary';
21
+ // export * from './components/PlErrorAlert'; // @TODO discuss if we should export it
20
22
  export * from './components/PlAlert';
21
23
  export * from './components/PlBtnSplit';
22
24
  export * from './components/PlBtnPrimary';
package/vite.config.ts CHANGED
@@ -59,11 +59,4 @@ export default defineConfig({
59
59
  },
60
60
  },
61
61
  },
62
- css: {
63
- preprocessorOptions: {
64
- scss: {
65
- api: 'modern-compiler',
66
- },
67
- },
68
- },
69
62
  });