@v1nt1248/3nclient-lib 0.1.14 → 0.1.15

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.14",
5
+ "version": "0.1.15",
6
6
  "description": "Library for 3NWeb clients",
7
7
  "type": "module",
8
8
  "files": [
@@ -67,6 +67,17 @@ import Ui3nProgressCircular from './ui3n-progress/ui3n-progress-circular.vue';
67
67
  import type { Ui3nProgressCircularProps, Ui3nProgressLinearProps } from './ui3n-progress/types';
68
68
  import Ui3nTooltip from './ui3n-tooltip/ui3n-tooltip.vue';
69
69
  import type { Ui3nTooltipEmits, Ui3nTooltipProps, Ui3nTooltipSlots, Ui3nTooltipPlacement } from './ui3n-tooltip/types';
70
+ import Ui3nRadio from './ui3n-radio-group/ui3n-radio.vue';
71
+ // import Ui3nRadioGroup from './ui3n-radio-group/ui3n-radio-group.vue';
72
+ import type {
73
+ Ui3nRadioEmits,
74
+ Ui3nRadioProps,
75
+ Ui3nRadioSlots,
76
+ // Ui3nRadioGroupEmits,
77
+ Ui3nRadioGroupProps,
78
+ // Ui3nRadioGroupSlots,
79
+ Ui3nRadioValue,
80
+ } from './ui3n-radio-group/types';
70
81
 
71
82
  export {
72
83
  Ui3nIcon,
@@ -157,4 +168,13 @@ export {
157
168
  Ui3nTooltipProps,
158
169
  Ui3nTooltipSlots,
159
170
  Ui3nTooltipPlacement,
171
+ Ui3nRadio,
172
+ // Ui3nRadioGroup,
173
+ Ui3nRadioValue,
174
+ Ui3nRadioEmits,
175
+ Ui3nRadioProps,
176
+ Ui3nRadioSlots,
177
+ // Ui3nRadioGroupEmits,
178
+ Ui3nRadioGroupProps,
179
+ // Ui3nRadioGroupSlots,
160
180
  };
@@ -1,48 +1,43 @@
1
1
  <script lang="ts" setup>
2
- import { computed, getCurrentInstance } from 'vue';
3
- import type { Ui3nBreadcrumbEmits, Ui3nBreadcrumbProps, Ui3nBreadcrumbSlots } from './types';
2
+ import { computed, getCurrentInstance } from 'vue';
3
+ import type { Ui3nBreadcrumbEmits, Ui3nBreadcrumbProps, Ui3nBreadcrumbSlots } from './types';
4
4
 
5
- const props = withDefaults(
6
- defineProps<Ui3nBreadcrumbProps>(),
7
- {
8
- separator: undefined,
9
- isActive: false,
10
- disabled: false,
11
- },
12
- );
13
- const emits = defineEmits<Ui3nBreadcrumbEmits>();
14
- defineSlots<Ui3nBreadcrumbSlots>();
5
+ const props = withDefaults(defineProps<Ui3nBreadcrumbProps>(), {
6
+ separator: undefined,
7
+ isActive: false,
8
+ disabled: false,
9
+ });
10
+ const emits = defineEmits<Ui3nBreadcrumbEmits>();
11
+ defineSlots<Ui3nBreadcrumbSlots>();
15
12
 
16
- const separatorValue = computed(() => {
17
- if (props.separator) {
18
- return props.separator
19
- }
13
+ const separatorValue = computed(() => {
14
+ if (props.separator) {
15
+ return props.separator;
16
+ }
20
17
 
21
- const instance = getCurrentInstance()
22
- return instance?.parent?.props.separator || '/'
23
- });
18
+ const instance = getCurrentInstance();
19
+ return instance?.parent?.props.separator || '/';
20
+ });
24
21
 
25
- const parentDisabled = computed(() => {
26
- const instance = getCurrentInstance()
27
- return instance?.parent?.props.disabled || false
28
- });
22
+ const parentDisabled = computed(() => {
23
+ const instance = getCurrentInstance();
24
+ return instance?.parent?.props.disabled || false;
25
+ });
29
26
 
30
- const onClick = (ev: Event) => {
31
- emits('click', ev)
32
- }
27
+ const onClick = (ev: Event) => {
28
+ emits('click', ev);
29
+ };
33
30
  </script>
34
31
 
35
32
  <template>
36
33
  <div
37
- :class="[
38
- $style.breadcrumb,
39
- isActive && $style.active,
40
- (disabled || parentDisabled) && $style.disabled,
41
- ]"
34
+ :class="[$style.breadcrumb, isActive && $style.active, (disabled || parentDisabled) && $style.disabled]"
42
35
  v-on="isActive && !(disabled || parentDisabled) ? { click: onClick } : {}"
43
36
  >
44
37
  <slot />
45
- <div v-if="isActive" :class="$style.separator"
38
+ <div
39
+ v-if="isActive"
40
+ :class="$style.separator"
46
41
  >
47
42
  <slot name="separator">
48
43
  <span>{{ separatorValue }}</span>
@@ -22,6 +22,16 @@ const checkboxEl = ref<HTMLDivElement | null>(null);
22
22
  const val = ref<Ui3nCheckboxValue>(props.uncheckedValue || false);
23
23
  const uncertain = ref(false);
24
24
 
25
+ const checkBoxValue = computed(() => {
26
+ if (uncertain.value) {
27
+ return 'indeterminate';
28
+ }
29
+
30
+ return val.value === props.checkedValue
31
+ ? 'checked'
32
+ : 'unchecked';
33
+ });
34
+
25
35
  onBeforeMount(() => {
26
36
  const checkedValueType = typeof props.checkedValue;
27
37
  const uncheckedValueType = typeof props.uncheckedValue;
@@ -38,6 +48,7 @@ onBeforeMount(() => {
38
48
  onMounted(() => {
39
49
  if (checkboxEl.value) {
40
50
  checkboxEl.value.style.setProperty('--ui3n-checkbox-size', `${props.size}px`);
51
+ checkboxEl.value.style.setProperty('--ui3n-checkbox-color', props.color);
41
52
  }
42
53
  });
43
54
 
@@ -62,17 +73,16 @@ watch(
62
73
  },
63
74
  );
64
75
 
65
- const checkBoxValue = computed(() => {
66
- if (uncertain.value) {
67
- return 'indeterminate';
68
- }
69
-
70
- return val.value === props.checkedValue
71
- ? 'checked'
72
- : 'unchecked';
73
- });
76
+ watch(
77
+ () => props.color,
78
+ newValue => {
79
+ if (checkboxEl.value) {
80
+ checkboxEl.value.style.setProperty('--ui3n-checkbox-color', newValue);
81
+ }
82
+ },
83
+ );
74
84
 
75
- const change = () => {
85
+ function change() {
76
86
  val.value = checkBoxValue.value !== 'unchecked'
77
87
  ? props.uncheckedValue
78
88
  : props.checkedValue;
@@ -83,7 +93,7 @@ const change = () => {
83
93
 
84
94
  emits('change', val.value);
85
95
  emits('update:modelValue', val.value);
86
- };
96
+ }
87
97
  </script>
88
98
 
89
99
  <template>
@@ -107,9 +117,7 @@ const change = () => {
107
117
  <g id="SVGRepo_bgCarrier" stroke-width="0" />
108
118
  <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" />
109
119
  <g id="SVGRepo_iconCarrier">
110
- <path d="M20.0001 7L9.0001 18L4 13" stroke="#fff" stroke-width="3" stroke-linecap="round"
111
- stroke-linejoin="round"
112
- />
120
+ <path d="M20.0001 7L9.0001 18L4 13" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" />
113
121
  </g>
114
122
  </svg>
115
123
 
@@ -165,7 +173,9 @@ const change = () => {
165
173
  position: relative;
166
174
  display: flex;
167
175
  width: var(--ui3n-checkbox-size);
176
+ min-width: var(--ui3n-checkbox-size);
168
177
  height: var(--ui3n-checkbox-size);
178
+ min-height: var(--ui3n-checkbox-size);
169
179
  justify-content: center;
170
180
  align-items: center;
171
181
  border-radius: calc(var(--ui3n-checkbox-size) / 10);
@@ -0,0 +1,38 @@
1
+ import { VNode } from 'vue';
2
+
3
+ export type Ui3nRadioValue = boolean | string | number;
4
+
5
+ export interface Ui3nRadioProps {
6
+ modelValue?: Ui3nRadioValue;
7
+ checkedValue?: Ui3nRadioValue;
8
+ uncheckedValue?: Ui3nRadioValue;
9
+ size?: number | string;
10
+ color?: string;
11
+ disabled?: boolean;
12
+ }
13
+
14
+ export interface Ui3nRadioEmits {
15
+ (ev: 'change', value: Ui3nRadioValue): void;
16
+ (ev: 'update:modelValue', value: Ui3nRadioValue): void;
17
+ }
18
+
19
+ export interface Ui3nRadioSlots {
20
+ checkedIcon: () => VNode;
21
+ uncheckedIcon: () => VNode;
22
+ default: () => VNode;
23
+ }
24
+
25
+ export interface Ui3nRadioGroupProps {
26
+ modelValue?: Ui3nRadioValue;
27
+ direction?: 'horizontal' | 'vertical';
28
+ disabled?: boolean;
29
+ }
30
+ //
31
+ // export interface Ui3nRadioGroupEmits {
32
+ // (ev: 'change', value: Ui3nRadioValue): void;
33
+ // (ev: 'update:modelValue', value: Ui3nRadioValue): void;
34
+ // }
35
+ //
36
+ // export interface Ui3nRadioGroupSlots {
37
+ // default: () => VNode;
38
+ // }
@@ -0,0 +1,54 @@
1
+ <script lang="ts" setup>
2
+ import { onMounted, ref, SetupContext, useSlots } from 'vue';
3
+ // import { isEmpty } from 'lodash';
4
+ import type {
5
+ // Ui3nRadioGroupEmits,
6
+ Ui3nRadioGroupProps,
7
+ // Ui3nRadioGroupSlots,
8
+ // Ui3nRadioValue,
9
+ } from './types';
10
+
11
+ const props = withDefaults(
12
+ defineProps<Ui3nRadioGroupProps>(),
13
+ {
14
+ modelValue: false,
15
+ direction: 'horizontal',
16
+ disabled: false,
17
+ },
18
+ );
19
+
20
+ const slots: SetupContext['slots'] = useSlots();
21
+ const contentSlot = ref();
22
+ const children = ref([]);
23
+
24
+ function onClick(ev: MouseEvent) {
25
+ console.log('EV: ', ev);
26
+ }
27
+
28
+ onMounted(() => {
29
+ // @ts-ignore
30
+ children.value = slots.default();
31
+ console.log('CH: ', children.value);
32
+ });
33
+ </script>
34
+
35
+ <template>
36
+ <div
37
+ ref="contentSlot"
38
+ :class="$style.radioGroup"
39
+ v-on="disabled ? {} : { click: onClick }"
40
+ >
41
+ <slot />
42
+ </div>
43
+ </template>
44
+
45
+ <style lang="scss" module>
46
+ .radioGroup {
47
+ position: relative;
48
+ display: flex;
49
+ width: max-content;
50
+ justify-content: center;
51
+ align-items: center;
52
+ gap: var(--spacing-s);
53
+ }
54
+ </style>
@@ -0,0 +1,233 @@
1
+ <script lang="ts" setup>
2
+ import {
3
+ computed,
4
+ getCurrentInstance,
5
+ onBeforeMount,
6
+ onMounted,
7
+ ref,
8
+ useSlots,
9
+ watch,
10
+ } from 'vue';
11
+ import type {
12
+ Ui3nRadioEmits,
13
+ Ui3nRadioProps,
14
+ Ui3nRadioSlots,
15
+ Ui3nRadioValue,
16
+ } from './types';
17
+
18
+ const props = withDefaults(
19
+ defineProps<Ui3nRadioProps>(),
20
+ {
21
+ modelValue: false,
22
+ checkedValue: true,
23
+ uncheckedValue: false,
24
+ size: '16',
25
+ color: 'var(--color-icon-control-accent-default)',
26
+ disabled: false,
27
+ },
28
+ );
29
+ const emits = defineEmits<Ui3nRadioEmits>();
30
+ defineSlots<Ui3nRadioSlots>();
31
+
32
+ const slots = useSlots();
33
+ const radioEl = ref<HTMLDivElement | null>(null);
34
+ const val = ref<Ui3nRadioValue>(props.uncheckedValue || false);
35
+ const instance = getCurrentInstance();
36
+
37
+ const radioValue = computed(() => {
38
+ return val.value === props.checkedValue
39
+ ? 'checked'
40
+ : 'unchecked';
41
+ });
42
+
43
+ onBeforeMount(() => {
44
+ if (
45
+ (slots.checkedIcon && !slots.uncheckedIcon) ||
46
+ (!slots.checkedIcon && slots.uncheckedIcon)
47
+ ) {
48
+ throw Error('[Ui3nRadio] Both checkedIcon and uncheckedIcon slots must have values ​​defined.');
49
+ }
50
+
51
+ if (instance?.parent?.type.__name !== 'ui3n-radio-group') {
52
+ const checkedValueType = typeof props.checkedValue;
53
+ const uncheckedValueType = typeof props.uncheckedValue;
54
+ const valueType = typeof props.modelValue;
55
+ if (
56
+ checkedValueType !== uncheckedValueType
57
+ || checkedValueType !== valueType
58
+ || uncheckedValueType !== valueType
59
+ ) {
60
+ throw Error('[Ui3nRadio] types of "value", "checkedValue" and "uncheckedValue" are different');
61
+ }
62
+ } else {
63
+ const groupModelValue = instance?.parent.props.modelValue;
64
+ if (groupModelValue === props.checkedValue) {
65
+ val.value = groupModelValue as Ui3nRadioValue;
66
+ }
67
+ }
68
+ });
69
+
70
+ onMounted(() => {
71
+ if (radioEl.value) {
72
+ radioEl.value.style.setProperty('--ui3n-radio-size', `${props.size}px`);
73
+ radioEl.value.style.setProperty('--ui3n-radio-color', props.color);
74
+ }
75
+ });
76
+
77
+ watch(
78
+ () => props.modelValue,
79
+ newValue => val.value = newValue,
80
+ { immediate: true },
81
+ );
82
+
83
+ watch(
84
+ () => props.size,
85
+ newValue => {
86
+ if (radioEl.value) {
87
+ radioEl.value.style.setProperty('--ui3n-radio-size', `${newValue}px`);
88
+ }
89
+ },
90
+ );
91
+
92
+ watch(
93
+ () => props.color,
94
+ newValue => {
95
+ if (radioEl.value) {
96
+ radioEl.value.style.setProperty('--ui3n-radio-color', newValue);
97
+ }
98
+ },
99
+ );
100
+
101
+
102
+ function change() {
103
+ val.value = radioValue.value !== 'unchecked'
104
+ ? props.uncheckedValue
105
+ : props.checkedValue;
106
+
107
+ emits('change', val.value);
108
+ emits('update:modelValue', val.value);
109
+ };
110
+
111
+ defineExpose({ change, radioEl });
112
+ </script>
113
+
114
+ <template>
115
+ <div
116
+ ref="radioEl"
117
+ :class="[
118
+ $style.radio,
119
+ disabled && $style.disabled,
120
+ !slots.default && $style.noLabel,
121
+ ]"
122
+ >
123
+ <div
124
+ :class="$style.body"
125
+ @click="change"
126
+ >
127
+ <slot
128
+ v-if="radioValue === 'checked'
129
+ "name="checkedIcon"
130
+ >
131
+ <svg
132
+ xmlns="http://www.w3.org/2000/svg"
133
+ :width="Number(size) - 4"
134
+ :height="Number(size) - 4"
135
+ viewBox="0 0 24 24"
136
+ :class="$style.icon"
137
+ >
138
+ <path
139
+ fill="currentColor"
140
+ d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5s5-2.24 5-5s-2.24-5-5-5m0-5C6.48 2 2 6.48 2 12s4.48 10 10 10s10-4.48 10-10S17.52 2 12 2m0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8s8 3.58 8 8s-3.58 8-8 8"
141
+ />
142
+ </svg>
143
+ </slot>
144
+
145
+ <slot
146
+ v-else
147
+ name="uncheckedIcon"
148
+ >
149
+ <svg
150
+ xmlns="http://www.w3.org/2000/svg"
151
+ :width="Number(size) - 4"
152
+ :height="Number(size) - 4"
153
+ viewBox="0 0 24 24"
154
+ :class="$style.icon"
155
+ >
156
+ <path
157
+ fill="currentColor"
158
+ d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10s10-4.48 10-10S17.52 2 12 2m0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8s8 3.58 8 8s-3.58 8-8 8"
159
+ />
160
+ </svg>
161
+ </slot>
162
+ </div>
163
+
164
+ <div :class="$style.label">
165
+ <slot />
166
+ </div>
167
+ </div>
168
+ </template>
169
+
170
+ <style lang="scss" module>
171
+ @import "../../assets/styles/mixins";
172
+
173
+ .radio {
174
+ --ui3n-radio-size: 16px;
175
+ --ui3n-radio-color: var(--color-icon-control-accent-default);
176
+ --ui3n-radio-text-size: 12px;
177
+ --ui3n-radio-text-color: var(--color-text-control-primary-default);
178
+ --ui3n-radio-text-weight: 500;
179
+
180
+ position: relative;
181
+ display: flex;
182
+ justify-content: flex-start;
183
+ align-items: center;
184
+ min-height: var(--spacing-vl);
185
+ gap: var(--spacing-s);
186
+
187
+ &.disabled {
188
+ --ui3n-radio-color: var(--color-icon-control-primary-disabled) !important;
189
+ pointer-events: none;
190
+ cursor: default;
191
+
192
+ .label {
193
+ opacity: 0.7;
194
+ }
195
+ }
196
+ }
197
+
198
+ .noLabel {
199
+ gap: 0;
200
+ }
201
+
202
+ .body {
203
+ position: relative;
204
+ display: flex;
205
+ width: var(--ui3n-radio-size);
206
+ min-width: var(--ui3n-radio-size);
207
+ height: var(--ui3n-radio-size);
208
+ min-height: var(--ui3n-radio-size);
209
+ justify-content: center;
210
+ align-items: center;
211
+ border-radius: 50%;
212
+
213
+ &:hover {
214
+ cursor: pointer;
215
+ background-color: hsl(from transparent h s calc(l - 10));
216
+ @include ripple(hsl(from transparent h s calc(l - 10)));
217
+ }
218
+ }
219
+
220
+ .label {
221
+ font-size: var(--ui3n-radio-text-size);
222
+ font-weight: var(--ui3n-radio-text-weight);
223
+ color: var(--ui3n-radio-text-color);
224
+ user-select: none;
225
+ }
226
+
227
+ .icon {
228
+ color: var(--ui3n-radio-color);
229
+ min-height: calc(var(--ui3n-radion-size) - 2px);
230
+ min-width: calc(var(--ui3n-checkbox-size) - 2px);
231
+ cursor: pointer;
232
+ }
233
+ </style>