@v1nt1248/3nclient-lib 0.1.37 → 0.1.39

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
@@ -2,7 +2,7 @@
2
2
  "name": "@v1nt1248/3nclient-lib",
3
3
  "license": "AGPL-3.0-or-later",
4
4
  "author": "v1nt1248",
5
- "version": "0.1.37",
5
+ "version": "0.1.39",
6
6
  "description": "Library for 3NWeb clients",
7
7
  "type": "module",
8
8
  "files": [
@@ -57,7 +57,7 @@
57
57
  "mitt": "3.0.1",
58
58
  "sanitize-html": "2.13.1",
59
59
  "tslib": "2.8.0",
60
- "vuedraggable": "^4.1.0"
60
+ "vuedraggable": "4.1.0"
61
61
  },
62
62
  "peerDependencies": {
63
63
  "pinia": "2.2.4",
@@ -1,7 +1,9 @@
1
+ import { VNodeProps, AllowedComponentProps } from 'vue';
2
+
1
3
  export type ExtractComponentProps<TComponent> = TComponent extends new () => {
2
4
  $props: infer P;
3
5
  }
4
- ? P
6
+ ? Omit<P, keyof VNodeProps | keyof AllowedComponentProps>
5
7
  : never;
6
8
 
7
9
  export type Nullable<T> = T | null;
@@ -77,6 +77,7 @@ const onClick = (ev: Event) => {
77
77
  font-size: var(--ui3n-breadcrumb-font-size);
78
78
  line-height: 1.25;
79
79
  color: var(--ui3n-breadcrumb-color-default);
80
+ padding-right: var(--spacing-xs);
80
81
 
81
82
  &:hover {
82
83
  cursor: pointer;
@@ -88,6 +89,10 @@ const onClick = (ev: Event) => {
88
89
  }
89
90
  }
90
91
 
92
+ .ui3nBreadcrumbSeparator {
93
+ padding-left: var(--spacing-xs);
94
+ }
95
+
91
96
  .ui3nBreadcrumbDisabled {
92
97
  cursor: default;
93
98
  pointer-events: none;
@@ -1,11 +1,14 @@
1
1
  import type { Component } from 'vue';
2
+ import type { ExtractComponentProps } from '../types/index';
2
3
 
3
4
  export type Ui3nDialogEvent = 'open' | 'before-close' | 'close' | 'confirm' | 'cancel' | 'click-overlay';
4
5
 
5
6
  export interface Ui3nDialogProps {
7
+ id?: string;
6
8
  teleport?: string;
7
9
  title?: string;
8
10
  width?: string | number;
11
+ draggable?: boolean;
9
12
  cssClass?: string[];
10
13
  cssStyle?: Record<string, string>;
11
14
  contentCssClass?: string[];
@@ -13,8 +16,8 @@ export interface Ui3nDialogProps {
13
16
  confirmButton?: boolean;
14
17
  cancelButton?: boolean;
15
18
  onClose?: () => void;
16
- onConfirm?: (data: any) => void;
17
- onCancel?: (data: any) => void;
19
+ onConfirm?: (data: unknown) => void;
20
+ onCancel?: (data: unknown) => void;
18
21
  confirmButtonText?: string;
19
22
  cancelButtonText?: string;
20
23
  confirmButtonColor?: string;
@@ -24,17 +27,17 @@ export interface Ui3nDialogProps {
24
27
  closeOnClickOverlay?: boolean;
25
28
  }
26
29
 
27
- export interface Ui3nDialogComponentProps<T extends Component, P extends Record<string, unknown>> {
30
+ export interface Ui3nDialogComponentProps<T extends Component> {
28
31
  component: T;
29
- componentProps?: P;
32
+ componentProps?: ExtractComponentProps<T>;
30
33
  dialogProps?: Ui3nDialogProps;
31
34
  }
32
35
 
33
36
  export interface Ui3nDialogComponentEmits {
34
- (ev: 'open', value?: any): void;
35
- (ev: 'before-close', value?: any): void;
36
- (ev: 'close', value?: any): void;
37
- (ev: 'confirm', value?: any): void;
38
- (ev: 'cancel', value?: any): void;
39
- (ev: 'click-overlay', value?: any): void;
37
+ (ev: 'open', value?: unknown): void;
38
+ (ev: 'before-close', value?: unknown): void;
39
+ (ev: 'close', value?: unknown): void;
40
+ (ev: 'confirm', value?: unknown): void;
41
+ (ev: 'cancel', value?: unknown): void;
42
+ (ev: 'click-overlay', value?: unknown): void;
40
43
  }
@@ -1,61 +1,62 @@
1
- <script lang="ts" setup generic="T extends Component, P extends Record<string, unknown>">
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
1
+ <script lang="ts" setup generic="T extends Component">
3
2
  import { type Component, computed, nextTick, onMounted, ref } from 'vue';
4
3
  import Ui3nButton from '../ui3n-button/ui3n-button.vue';
5
- import type { Ui3nDialogEvent, Ui3nDialogProps, Ui3nDialogComponentProps, Ui3nDialogComponentEmits } from './types';
4
+ import type { Ui3nDialogEvent, Ui3nDialogComponentProps, Ui3nDialogComponentEmits } from './types';
5
+ import { ExtractComponentProps } from '@/components/types';
6
6
 
7
- const props = defineProps<Ui3nDialogComponentProps<T, P>>();
7
+ const props = defineProps<Ui3nDialogComponentProps<T>>();
8
8
  const emits = defineEmits<Ui3nDialogComponentEmits>();
9
9
 
10
+ const currentDialogProps = computed(() => ({
11
+ teleport: props.dialogProps?.teleport || 'body',
12
+ title: props.dialogProps?.title || '',
13
+ width: props.dialogProps?.width || 380,
14
+ cssClass: props.dialogProps?.cssClass || [],
15
+ cssStyle: props.dialogProps?.cssStyle || {},
16
+ contentCssClass: props.dialogProps?.contentCssClass || [],
17
+ contentCssStyle: props.dialogProps?.contentCssStyle || {},
18
+ confirmButton: props.dialogProps?.confirmButton || true,
19
+ cancelButton: props.dialogProps?.cancelButton || true,
20
+ confirmButtonText: props.dialogProps?.confirmButtonText || 'Done',
21
+ cancelButtonText: props.dialogProps?.cancelButtonText || 'Cancel',
22
+ confirmButtonColor: props.dialogProps?.confirmButtonColor || 'var(--color-text-button-primary-default)',
23
+ cancelButtonColor: props.dialogProps?.cancelButtonColor || 'var(--color-text-button-secondary-default)',
24
+ confirmButtonBackground: props.dialogProps?.confirmButtonBackground || 'var(--color-bg-button-primary-default)',
25
+ cancelButtonBackground: props.dialogProps?.cancelButtonBackground || 'var(--color-bg-button-secondary-default)',
26
+ closeOnClickOverlay: props.dialogProps?.closeOnClickOverlay || true,
27
+ }));
28
+
10
29
  const show = ref(true);
11
- const data = ref(null);
30
+ const data = ref<unknown>(null);
12
31
  const isValid = ref(true);
32
+ const dialogOverlayElement = ref<HTMLElement | null>(null);
13
33
  const dialogElement = ref<HTMLDivElement | null>(null);
34
+ const isMousedown = ref(false);
35
+ const dragData = ref({
36
+ initialLeft: 0,
37
+ initialTop: 0,
38
+ left: 0,
39
+ top: 0,
40
+ shiftX: 0,
41
+ shiftY: 0,
42
+ });
14
43
 
15
- const dialogProps = computed<Required<Omit<Ui3nDialogProps, 'onClose' | 'onConfirm' | 'onCancel'>>>(() => ({
16
- teleport: props.dialogProps?.teleport ?? 'body',
17
- title: props.dialogProps?.title ?? '',
18
- width: props.dialogProps?.width ?? 380,
19
- cssClass: props.dialogProps?.cssClass ?? [],
20
- cssStyle: props.dialogProps?.cssStyle ?? {},
21
- contentCssClass: props.dialogProps?.contentCssClass ?? [],
22
- contentCssStyle: props.dialogProps?.contentCssStyle ?? {},
23
- confirmButton: props.dialogProps?.confirmButton ?? true,
24
- cancelButton: props.dialogProps?.confirmButton ?? true,
25
- confirmButtonText: props.dialogProps?.confirmButtonText ?? 'Done',
26
- cancelButtonText: props.dialogProps?.cancelButtonText ?? 'Cancel',
27
- confirmButtonColor: props.dialogProps?.confirmButtonColor ?? 'var(--color-text-button-primary-default)',
28
- cancelButtonColor: props.dialogProps?.cancelButtonColor ?? 'var(--color-text-button-secondary-default)',
29
- confirmButtonBackground: props.dialogProps?.confirmButtonBackground ?? 'var(--color-bg-button-primary-default)',
30
- cancelButtonBackground: props.dialogProps?.cancelButtonBackground ?? 'var(--color-bg-button-secondary-default)',
31
- closeOnClickOverlay: props.dialogProps?.closeOnClickOverlay ?? true,
44
+ const cssStyle = computed(() => ({
45
+ ...currentDialogProps.value.cssStyle,
46
+ width: `${currentDialogProps.value.width}px`,
47
+ ...(props.dialogProps?.draggable && {
48
+ left: `${dragData.value.left}px`,
49
+ top: `${dragData.value.top}px`,
50
+ }),
32
51
  }));
33
- const cssStyle = computed(() => ({ width: `${dialogProps.value.width}px`, ...dialogProps.value.cssStyle }));
34
-
35
- onMounted(() => {
36
- if (dialogElement.value) {
37
- dialogElement.value.style.setProperty('--dialog-confirm-button-color', dialogProps.value.confirmButtonColor!);
38
- dialogElement.value.style.setProperty('--dialog-cancel-button-color', dialogProps.value.cancelButtonColor!);
39
- dialogElement.value.style.setProperty(
40
- '--dialog-confirm-background-color',
41
- dialogProps.value.confirmButtonBackground!,
42
- );
43
- dialogElement.value.style.setProperty(
44
- '--dialog-cancel-background-color',
45
- dialogProps.value.cancelButtonBackground!,
46
- );
47
- }
48
-
49
- if (dialogElement.value) {
50
- nextTick(() => {
51
- dialogElement.value!.focus();
52
- });
53
- }
54
- });
55
52
 
56
- function selectData(value: any) {
53
+ function selectData(value: unknown) {
57
54
  data.value = value;
58
- if (!dialogProps.value.confirmButton && !dialogProps.value.cancelButton && props.dialogProps?.onConfirm) {
55
+ if (
56
+ !currentDialogProps.value.confirmButton &&
57
+ !currentDialogProps.value.cancelButton &&
58
+ props.dialogProps?.onConfirm
59
+ ) {
59
60
  props.dialogProps?.onConfirm(data.value);
60
61
  closeDialog();
61
62
  }
@@ -81,7 +82,7 @@ function closeDialog(arg?: { ev?: Event; withAction?: boolean }) {
81
82
  function startEmit(event: Ui3nDialogEvent, ev?: Event) {
82
83
  if (event === 'click-overlay') {
83
84
  emits(event);
84
- dialogProps.value.closeOnClickOverlay && closeDialog({ ev });
85
+ currentDialogProps.value.closeOnClickOverlay && closeDialog({ ev });
85
86
  return;
86
87
  }
87
88
 
@@ -109,28 +110,95 @@ function handleEvent(event: Event, eventName: Ui3nDialogEvent) {
109
110
  event.preventDefault();
110
111
  startEmit(eventName);
111
112
  }
113
+
114
+ /* drag */
115
+ function onDragstart() {
116
+ return false;
117
+ }
118
+
119
+ function onMouseup() {
120
+ isMousedown.value = false;
121
+ dragData.value.shiftX = 0;
122
+ dragData.value.shiftY = 0;
123
+ return false;
124
+ }
125
+
126
+ function onMousedown(ev: MouseEvent) {
127
+ isMousedown.value = true;
128
+ const dialogElementRect = dialogElement.value!.getBoundingClientRect();
129
+ dragData.value.shiftX = ev.clientX - dialogElementRect.left;
130
+ dragData.value.shiftY = ev.clientY - dialogElementRect.top;
131
+ }
132
+
133
+ function onMousemove(ev: MouseEvent) {
134
+ if (!isMousedown.value) {
135
+ return;
136
+ }
137
+ dragData.value.left = ev.clientX - dragData.value.shiftX - dragData.value.initialLeft;
138
+ dragData.value.top = ev.clientY - dragData.value.shiftY - dragData.value.initialTop;
139
+ }
140
+
141
+ onMounted(() => {
142
+ if (dialogElement.value) {
143
+ dialogElement.value.style.setProperty(
144
+ '--dialog-confirm-button-color',
145
+ currentDialogProps.value.confirmButtonColor!,
146
+ );
147
+ dialogElement.value.style.setProperty(
148
+ '--dialog-cancel-button-color',
149
+ currentDialogProps.value.cancelButtonColor!,
150
+ );
151
+ dialogElement.value.style.setProperty(
152
+ '--dialog-confirm-background-color',
153
+ currentDialogProps.value.confirmButtonBackground!,
154
+ );
155
+ dialogElement.value.style.setProperty(
156
+ '--dialog-cancel-background-color',
157
+ currentDialogProps.value.cancelButtonBackground!,
158
+ );
159
+
160
+ nextTick(() => {
161
+ dialogElement.value!.focus();
162
+
163
+ setTimeout(() => {
164
+ const dialogClientRect = dialogElement.value!.getBoundingClientRect();
165
+ dragData.value.initialLeft = dialogClientRect.left;
166
+ dragData.value.initialTop = dialogClientRect.top;
167
+ }, 100);
168
+ });
169
+ }
170
+ });
112
171
  </script>
113
172
 
114
173
  <template>
115
174
  <div
116
175
  v-if="show"
176
+ ref="dialogOverlayElement"
117
177
  :class="$style.overlay"
118
178
  @click="startEmit('click-overlay', $event)"
119
179
  >
120
180
  <div
181
+ :id="dialogProps?.id"
121
182
  ref="dialogElement"
122
183
  tabindex="1"
123
- :class="[$style.dialog, ...dialogProps.cssClass]"
184
+ :class="[
185
+ $style.dialog,
186
+ dialogProps?.draggable && isMousedown && $style.draggable,
187
+ ...currentDialogProps.cssClass!,
188
+ ]"
124
189
  :style="cssStyle"
190
+ v-on="dialogProps?.draggable
191
+ ? { dragstart: onDragstart, mousedown: onMousedown, mouseup: onMouseup, mousemove: onMousemove }
192
+ : {}"
125
193
  @keydown.esc.stop="startEmit('cancel')"
126
194
  @keydown.enter.stop="isValid && startEmit('confirm')"
127
195
  >
128
196
  <div
129
- v-if="dialogProps.title"
197
+ v-if="currentDialogProps.title"
130
198
  :class="$style.title"
131
199
  @click.stop
132
200
  >
133
- <span>{{ dialogProps.title }}</span>
201
+ <span>{{ currentDialogProps.title }}</span>
134
202
  </div>
135
203
 
136
204
  <ui3n-button
@@ -146,14 +214,14 @@ function handleEvent(event: Event, eventName: Ui3nDialogEvent) {
146
214
 
147
215
  <div
148
216
  v-if="component"
149
- :class="[$style.content, ...dialogProps.contentCssClass]"
150
- :style="dialogProps.contentCssStyle"
217
+ :class="[$style.content, ...currentDialogProps.contentCssClass!]"
218
+ :style="currentDialogProps.contentCssStyle"
151
219
  @click.stop
152
220
  >
153
221
  <!-- @vue-ignore -->
154
222
  <component
155
223
  :is="component"
156
- v-bind="componentProps as Object"
224
+ v-bind="componentProps as ExtractComponentProps<T>"
157
225
  @select="selectData"
158
226
  @validate="validate"
159
227
  @close="closeDialog({ ev: $event })"
@@ -163,28 +231,31 @@ function handleEvent(event: Event, eventName: Ui3nDialogEvent) {
163
231
  </div>
164
232
 
165
233
  <div
166
- v-if="dialogProps.confirmButton || dialogProps.cancelButton"
167
- :class="[$style.actions, dialogProps.confirmButton && dialogProps.cancelButton && $style.bothBtns]"
234
+ v-if="currentDialogProps.confirmButton || currentDialogProps.cancelButton"
235
+ :class="[
236
+ $style.actions,
237
+ currentDialogProps.confirmButton && currentDialogProps.cancelButton && $style.bothBtns
238
+ ]"
168
239
  @click.stop
169
240
  >
170
241
  <ui3n-button
171
- v-if="dialogProps.cancelButton"
242
+ v-if="currentDialogProps.cancelButton"
172
243
  type="secondary"
173
- :color="dialogProps.cancelButtonBackground"
174
- :text-color="dialogProps.cancelButtonColor"
244
+ :color="currentDialogProps.cancelButtonBackground"
245
+ :text-color="currentDialogProps.cancelButtonColor"
175
246
  @click="handleEvent($event, 'cancel')"
176
247
  >
177
- {{ dialogProps.cancelButtonText }}
248
+ {{ currentDialogProps.cancelButtonText }}
178
249
  </ui3n-button>
179
250
 
180
251
  <ui3n-button
181
- v-if="dialogProps.confirmButton"
182
- :color="dialogProps.confirmButtonBackground"
183
- :text-color="dialogProps.confirmButtonColor"
252
+ v-if="currentDialogProps.confirmButton"
253
+ :color="currentDialogProps.confirmButtonBackground"
254
+ :text-color="currentDialogProps.confirmButtonColor"
184
255
  :disabled="!isValid"
185
256
  @click="handleEvent($event, 'confirm')"
186
257
  >
187
- {{ dialogProps.confirmButtonText }}
258
+ {{ currentDialogProps.confirmButtonText }}
188
259
  </ui3n-button>
189
260
  </div>
190
261
  </div>
@@ -224,6 +295,10 @@ function handleEvent(event: Event, eventName: Ui3nDialogEvent) {
224
295
  outline: none;
225
296
 
226
297
  @include mixins.elevation();
298
+
299
+ &.draggable {
300
+ cursor: move;
301
+ }
227
302
  }
228
303
 
229
304
  .title {
@@ -242,6 +317,12 @@ function handleEvent(event: Event, eventName: Ui3nDialogEvent) {
242
317
  @include mixins.text-overflow-ellipsis();
243
318
  }
244
319
 
320
+ .dragHandleIcon {
321
+ position: absolute;
322
+ left: 0;
323
+ top: 16px;
324
+ }
325
+
245
326
  .closeBtn {
246
327
  position: absolute;
247
328
  right: 4px;