@antify/ui 2.4.5 → 2.4.10

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.
@@ -128,7 +128,7 @@ const classes = computed(() => {
128
128
  };
129
129
 
130
130
  return {
131
- 'transition-all inline-flex items-center justify-center relative font-medium': true,
131
+ 'transition-all inline-flex items-center justify-center relative font-medium cursor-pointer select-none': true,
132
132
  'active:shadow-[inset_0_4px_4px_rgba(0,0,0,0.25)]': !hasInputState.value,
133
133
  'p-1 text-xs gap-1': props.size === Size.xs2,
134
134
  'p-1.5 text-xs gap-1.5': props.size === Size.xs,
@@ -33,6 +33,7 @@ const meta = {
33
33
  };
34
34
  module.exports = meta;
35
35
  const defaultOptions = ["primary-500", "red-500", "green-500", "blue-500", "yellow-500", "purple-500", "pink-500", "orange-500"];
36
+ const lightColorOptions = ["primary-300", "red-300", "green-300", "blue-300", "yellow-300", "purple-300", "pink-300", "orange-300"];
36
37
  const Docs = exports.Docs = {
37
38
  render: args => ({
38
39
  components: {
@@ -79,9 +80,12 @@ const Summary = exports.Summary = {
79
80
  set: val => args.modelValue = val
80
81
  });
81
82
  const skeleton = (0, _vue.ref)(true);
83
+ const lightModelValue = (0, _vue.ref)("primary-300");
82
84
  return {
83
85
  args,
84
86
  modelValue,
87
+ lightModelValue,
88
+ lightColorOptions,
85
89
  InputState: _enums.InputState,
86
90
  skeleton,
87
91
  Size: _enums.Size
@@ -92,71 +96,73 @@ const Summary = exports.Summary = {
92
96
  <AntFormGroupLabel>States</AntFormGroupLabel>
93
97
  <AntFormGroup direction="row">
94
98
  <AntColorInput v-bind="args" v-model="modelValue" label="Label"
95
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
96
- :state="InputState.base"/>
99
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
100
+ :state="InputState.base"/>
97
101
  <AntColorInput v-bind="args" v-model="modelValue" label="Label"
98
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
99
- :state="InputState.info"/>
102
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
103
+ :state="InputState.info"/>
100
104
  <AntColorInput v-bind="args" v-model="modelValue" label="Label"
101
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
102
- :state="InputState.success"/>
105
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
106
+ :state="InputState.success"/>
103
107
  <AntColorInput v-bind="args" v-model="modelValue" label="Label"
104
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
105
- :state="InputState.warning"/>
108
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
109
+ :state="InputState.warning"/>
106
110
  <AntColorInput v-bind="args" v-model="modelValue" label="Label"
107
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
108
- :state="InputState.danger"/>
111
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
112
+ :state="InputState.danger"/>
109
113
  </AntFormGroup>
110
114
  <AntFormGroupLabel>Sizes</AntFormGroupLabel>
111
115
  <AntFormGroup direction="row">
112
116
  <AntColorInput v-bind="args" v-model="modelValue" label="Label" :size="Size.lg"
113
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
117
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
114
118
  />
115
119
  <AntColorInput v-bind="args" v-model="modelValue" label="Label" :size="Size.md"
116
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
120
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
117
121
  />
118
122
  <AntColorInput v-bind="args" v-model="modelValue" label="Label" :size="Size.sm"
119
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
123
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
120
124
  />
121
125
  <AntColorInput v-bind="args" v-model="modelValue" label="Label" :size="Size.xs"
122
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
126
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
123
127
  />
124
128
  <AntColorInput v-bind="args" v-model="modelValue" label="Label" :size="Size.xs2"
125
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
129
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
126
130
  />
127
131
  </AntFormGroup>
128
132
  <AntFormGroup direction="row">
129
133
  <AntFormGroup>
130
134
  <AntFormGroupLabel>Disabled</AntFormGroupLabel>
131
135
  <AntColorInput v-bind="args" v-model="modelValue" :disabled="true" label="Label"
132
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
136
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
133
137
  />
134
138
  </AntFormGroup>
135
139
  <AntFormGroup>
136
140
  <AntFormGroupLabel>Readonly</AntFormGroupLabel>
137
141
  <AntColorInput v-bind="args" v-model="modelValue" :readonly="true" label="Label"
138
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
142
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
139
143
  />
140
144
  </AntFormGroup>
141
145
  <AntFormGroup>
142
146
  <AntFormGroupLabel>Skeleton</AntFormGroupLabel>
143
147
  <AntColorInput v-bind="args" v-model="modelValue" :skeleton="true" label="Label"
144
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
148
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
145
149
  />
146
150
  </AntFormGroup>
147
151
  </AntFormGroup>
148
152
  <AntFormGroupLabel>Plain</AntFormGroupLabel>
149
153
  <AntColorInput v-bind="args" v-model="modelValue"/>
154
+ <AntFormGroupLabel>Light Color Options</AntFormGroupLabel>
155
+ <AntColorInput v-model="lightModelValue" :options="lightColorOptions" />
150
156
  <AntFormGroupLabel>Nullable</AntFormGroupLabel>
151
157
  <AntColorInput v-bind="args" v-model="modelValue" nullable/>
152
158
  <AntFormGroupLabel>With label</AntFormGroupLabel>
153
159
  <AntColorInput v-bind="args" v-model="modelValue" label="Label"/>
154
160
  <AntFormGroupLabel>With description</AntFormGroupLabel>
155
161
  <AntColorInput v-bind="args" v-model="modelValue"
156
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"/>
162
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"/>
157
163
  <AntFormGroupLabel>With label + description</AntFormGroupLabel>
158
164
  <AntColorInput v-bind="args" v-model="modelValue" label="Label"
159
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"/>
165
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"/>
160
166
  </AntFormGroup>
161
167
  `
162
168
  }),
@@ -43,6 +43,16 @@ const defaultOptions = [
43
43
  "pink-500",
44
44
  "orange-500"
45
45
  ];
46
+ const lightColorOptions = [
47
+ "primary-300",
48
+ "red-300",
49
+ "green-300",
50
+ "blue-300",
51
+ "yellow-300",
52
+ "purple-300",
53
+ "pink-300",
54
+ "orange-300"
55
+ ];
46
56
  export const Docs = {
47
57
  render: (args) => ({
48
58
  components: {
@@ -89,9 +99,12 @@ export const Summary = {
89
99
  set: (val) => args.modelValue = val
90
100
  });
91
101
  const skeleton = ref(true);
102
+ const lightModelValue = ref("primary-300");
92
103
  return {
93
104
  args,
94
105
  modelValue,
106
+ lightModelValue,
107
+ lightColorOptions,
95
108
  InputState,
96
109
  skeleton,
97
110
  Size
@@ -102,71 +115,73 @@ export const Summary = {
102
115
  <AntFormGroupLabel>States</AntFormGroupLabel>
103
116
  <AntFormGroup direction="row">
104
117
  <AntColorInput v-bind="args" v-model="modelValue" label="Label"
105
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
106
- :state="InputState.base"/>
118
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
119
+ :state="InputState.base"/>
107
120
  <AntColorInput v-bind="args" v-model="modelValue" label="Label"
108
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
109
- :state="InputState.info"/>
121
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
122
+ :state="InputState.info"/>
110
123
  <AntColorInput v-bind="args" v-model="modelValue" label="Label"
111
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
112
- :state="InputState.success"/>
124
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
125
+ :state="InputState.success"/>
113
126
  <AntColorInput v-bind="args" v-model="modelValue" label="Label"
114
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
115
- :state="InputState.warning"/>
127
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
128
+ :state="InputState.warning"/>
116
129
  <AntColorInput v-bind="args" v-model="modelValue" label="Label"
117
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
118
- :state="InputState.danger"/>
130
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
131
+ :state="InputState.danger"/>
119
132
  </AntFormGroup>
120
133
  <AntFormGroupLabel>Sizes</AntFormGroupLabel>
121
134
  <AntFormGroup direction="row">
122
135
  <AntColorInput v-bind="args" v-model="modelValue" label="Label" :size="Size.lg"
123
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
136
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
124
137
  />
125
138
  <AntColorInput v-bind="args" v-model="modelValue" label="Label" :size="Size.md"
126
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
139
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
127
140
  />
128
141
  <AntColorInput v-bind="args" v-model="modelValue" label="Label" :size="Size.sm"
129
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
142
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
130
143
  />
131
144
  <AntColorInput v-bind="args" v-model="modelValue" label="Label" :size="Size.xs"
132
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
145
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
133
146
  />
134
147
  <AntColorInput v-bind="args" v-model="modelValue" label="Label" :size="Size.xs2"
135
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
148
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
136
149
  />
137
150
  </AntFormGroup>
138
151
  <AntFormGroup direction="row">
139
152
  <AntFormGroup>
140
153
  <AntFormGroupLabel>Disabled</AntFormGroupLabel>
141
154
  <AntColorInput v-bind="args" v-model="modelValue" :disabled="true" label="Label"
142
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
155
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
143
156
  />
144
157
  </AntFormGroup>
145
158
  <AntFormGroup>
146
159
  <AntFormGroupLabel>Readonly</AntFormGroupLabel>
147
160
  <AntColorInput v-bind="args" v-model="modelValue" :readonly="true" label="Label"
148
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
161
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
149
162
  />
150
163
  </AntFormGroup>
151
164
  <AntFormGroup>
152
165
  <AntFormGroupLabel>Skeleton</AntFormGroupLabel>
153
166
  <AntColorInput v-bind="args" v-model="modelValue" :skeleton="true" label="Label"
154
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
167
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"
155
168
  />
156
169
  </AntFormGroup>
157
170
  </AntFormGroup>
158
171
  <AntFormGroupLabel>Plain</AntFormGroupLabel>
159
172
  <AntColorInput v-bind="args" v-model="modelValue"/>
173
+ <AntFormGroupLabel>Light Color Options</AntFormGroupLabel>
174
+ <AntColorInput v-model="lightModelValue" :options="lightColorOptions" />
160
175
  <AntFormGroupLabel>Nullable</AntFormGroupLabel>
161
176
  <AntColorInput v-bind="args" v-model="modelValue" nullable/>
162
177
  <AntFormGroupLabel>With label</AntFormGroupLabel>
163
178
  <AntColorInput v-bind="args" v-model="modelValue" label="Label"/>
164
179
  <AntFormGroupLabel>With description</AntFormGroupLabel>
165
180
  <AntColorInput v-bind="args" v-model="modelValue"
166
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"/>
181
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"/>
167
182
  <AntFormGroupLabel>With label + description</AntFormGroupLabel>
168
183
  <AntColorInput v-bind="args" v-model="modelValue" label="Label"
169
- description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"/>
184
+ description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod"/>
170
185
  </AntFormGroup>
171
186
  `
172
187
  }),
@@ -6,16 +6,10 @@ import {
6
6
  } from '@fortawesome/free-solid-svg-icons';
7
7
  import AntSkeleton from '../../AntSkeleton.vue';
8
8
  import {
9
- Size,
10
- State,
11
- Grouped,
12
- InputState,
9
+ Grouped, InputState, Size, State,
13
10
  } from '../../../enums';
14
11
  import {
15
- ref,
16
- watch,
17
- computed,
18
- onMounted, nextTick,
12
+ computed, nextTick, onMounted, ref, watch,
19
13
  } from 'vue';
20
14
  import Color from './Color.vue';
21
15
  import AntDropdown from '../../AntDropdown.vue';
@@ -67,15 +61,13 @@ const containerClasses = computed(() => {
67
61
  [key: string]: boolean;
68
62
  } = {
69
63
  'flex relative w-fit ring-primary/25 rounded-md outline-hidden': true,
70
- 'focus-within:ring-2': (props.size === Size.xs2 || props.size === Size.xs || props.size === Size.sm) && !hasInputState.value,
71
- 'focus-within:ring-4': (props.size === Size.md || props.size === Size.lg) && !hasInputState.value,
72
64
  };
73
65
  const colorVariant = {
74
- [InputState.base]: 'focus-within:ring-primary-200',
75
- [InputState.danger]: 'focus-within:ring-danger-200',
76
- [InputState.info]: 'focus-within:ring-info-200',
77
- [InputState.success]: 'focus-within:ring-success-200',
78
- [InputState.warning]: 'focus-within:ring-warning-200',
66
+ [InputState.base]: 'focus:ring-primary-200',
67
+ [InputState.danger]: 'focus:ring-danger-200',
68
+ [InputState.info]: 'focus:ring-info-200',
69
+ [InputState.success]: 'focus:ring-success-200',
70
+ [InputState.warning]: 'focus:ring-warning-200',
79
71
  };
80
72
 
81
73
  classes[colorVariant[props.state]] = true;
@@ -94,6 +86,8 @@ const itemClasses = computed(() => {
94
86
  [key: string]: boolean;
95
87
  } = {
96
88
  'relative outline outline-1 -outline-offset-1 rounded-l-md cursor-pointer': true,
89
+ 'focus:ring-2': (props.size === Size.xs2 || props.size === Size.xs || props.size === Size.sm) && !hasInputState.value,
90
+ 'focus:ring-4': (props.size === Size.md || props.size === Size.lg) && !hasInputState.value,
97
91
  'rounded-r-md': !hasRemoveButton.value,
98
92
  'p-1': props.size === Size.xs2,
99
93
  'p-1.5': props.size === Size.xs || props.size === Size.sm,
@@ -104,11 +98,11 @@ const itemClasses = computed(() => {
104
98
  };
105
99
 
106
100
  const colorVariant = {
107
- [InputState.danger]: 'outline-danger-500 bg-danger-100',
108
- [InputState.base]: 'outline-base-300 bg-white',
109
- [InputState.info]: 'outline-info-500 bg-info-100',
110
- [InputState.success]: 'outline-success-500 bg-success-100',
111
- [InputState.warning]: 'outline-warning-500 bg-warning-100',
101
+ [InputState.base]: 'outline-base-300 bg-white focus:ring-primary-200',
102
+ [InputState.success]: 'outline-success-500 bg-success-100 focus:ring-success-200',
103
+ [InputState.info]: 'outline-info-500 bg-info-100 focus:ring-info-200',
104
+ [InputState.warning]: 'outline-warning-500 bg-warning-100 focus:ring-warning-200',
105
+ [InputState.danger]: 'outline-danger-500 bg-danger-100 focus:ring-danger-200',
112
106
  };
113
107
 
114
108
  classes[colorVariant[props.state]] = true;
@@ -116,6 +110,7 @@ const itemClasses = computed(() => {
116
110
  return classes;
117
111
  });
118
112
  const showDropdown = ref<boolean>(false);
113
+ const itemRef = ref<HTMLDivElement | null>(null);
119
114
 
120
115
  /**
121
116
  * Validate default value if given after delayed data fetching.
@@ -136,6 +131,30 @@ function onBlur(e: FocusEvent) {
136
131
  emit('blur', e);
137
132
  }
138
133
 
134
+ function onColorSelect(val: string | null) {
135
+ emit('update:modelValue', val);
136
+ nextTick(() => showDropdown.value = false);
137
+ itemRef.value?.focus();
138
+ }
139
+
140
+ function onClick() {
141
+ if (props.readonly || props.disabled) {
142
+ return;
143
+ }
144
+
145
+ showDropdown.value = true;
146
+ }
147
+
148
+ function onKeyDown(e: KeyboardEvent) {
149
+ if (props.readonly || props.disabled) {
150
+ return;
151
+ }
152
+
153
+ if (e.key === 'Enter') {
154
+ showDropdown.value = true;
155
+ }
156
+ }
157
+
139
158
  onMounted(() => {
140
159
  if (!props.skeleton && props.modelValue !== null) {
141
160
  emit('validate', props.modelValue);
@@ -159,15 +178,22 @@ onMounted(() => {
159
178
  >
160
179
  <div
161
180
  :class="containerClasses"
162
- tabindex="0"
163
- @blur="onBlur"
164
181
  >
165
- <div class="relative">
166
- <div :class="itemClasses">
182
+ <div
183
+ class="relative"
184
+ >
185
+ <div
186
+ ref="itemRef"
187
+ :class="itemClasses"
188
+ :tabindex="disabled || readonly ? -1 : 0"
189
+ @click="onClick"
190
+ @keydown="onKeyDown"
191
+ @blur="onBlur"
192
+ >
167
193
  <Color
168
194
  :value="modelValue"
169
195
  :size="size as unknown as ColorInputSize"
170
- @click="showDropdown = true"
196
+ readonly
171
197
  />
172
198
  </div>
173
199
 
@@ -183,7 +209,6 @@ onMounted(() => {
183
209
  v-if="hasRemoveButton"
184
210
  :icon-left="faMultiply"
185
211
  :grouped="Grouped.right"
186
- :no-focus="true"
187
212
  :state="state as unknown as State"
188
213
  :size="size"
189
214
  :skeleton="skeleton"
@@ -198,10 +223,7 @@ onMounted(() => {
198
223
  <ColorSelection
199
224
  :value="modelValue"
200
225
  :colors="props.options"
201
- @select="(val) => {
202
- $emit('update:modelValue', val);
203
- nextTick(() => showDropdown = false);
204
- }"
226
+ @select="onColorSelect"
205
227
  />
206
228
  </template>
207
229
  </AntDropdown>
@@ -6,12 +6,15 @@ import AntIcon from '../../AntIcon.vue';
6
6
  import {
7
7
  ColorInputSize,
8
8
  } from './AntColorInput.types';
9
+ import {
10
+ computed, ref,
11
+ } from 'vue';
9
12
 
10
13
  defineEmits([
11
14
  'select',
12
15
  ]);
13
16
 
14
- withDefaults(defineProps<{
17
+ const props = withDefaults(defineProps<{
15
18
  /**
16
19
  * Value needs to be a variable name which exists in
17
20
  * document computed style as CSS variable like --color-{value}
@@ -19,31 +22,60 @@ withDefaults(defineProps<{
19
22
  value: string | null;
20
23
  selected?: boolean;
21
24
  size?: ColorInputSize;
25
+ readonly?: boolean;
22
26
  }>(), {
23
27
  selected: false,
24
28
  size: ColorInputSize.xl,
29
+ readonly: false,
30
+ });
31
+
32
+ const buttonRef = ref<HTMLButtonElement | null>(null);
33
+
34
+ defineExpose({
35
+ buttonRef: buttonRef,
36
+ });
37
+
38
+ const buttonClasses = computed(() => ({
39
+ 'rounded-sm cursor-pointer flex items-center justify-center': true,
40
+ 'h-4 w-4': [
41
+ ColorInputSize.xs,
42
+ ColorInputSize.xs2,
43
+ ].includes(props.size),
44
+ 'h-5 w-5': [
45
+ ColorInputSize.lg,
46
+ ColorInputSize.md,
47
+ ColorInputSize.sm,
48
+ ].includes(props.size),
49
+ 'h-8 w-8': ColorInputSize.xl === props.size,
50
+ 'h-10 w-10': ColorInputSize.xl2 === props.size,
51
+ }));
52
+
53
+ const iconClasses = computed(() => {
54
+ const colorIntensity = Number(props.value?.split('-')[1]);
55
+
56
+ if(!colorIntensity) {
57
+ return 'text-white!';
58
+ }
59
+
60
+ return colorIntensity < 500 ? 'text-black!' : 'text-white!';
25
61
  });
26
62
  </script>
27
63
 
28
64
  <template>
29
- <div
30
- class="rounded-sm cursor-pointer flex items-center justify-center"
31
- :class="{
32
- 'h-4 w-4': [ColorInputSize.xs, ColorInputSize.xs2].includes(size),
33
- 'h-5 w-5': [ColorInputSize.lg, ColorInputSize.md, ColorInputSize.sm].includes(size),
34
- 'h-8 w-8': ColorInputSize.xl === size,
35
- 'h-10 w-10': ColorInputSize.xl2 === size,
36
- }"
65
+ <button
66
+ ref="buttonRef"
67
+ :class="buttonClasses"
37
68
  :style="{
38
69
  backgroundColor: `var(--color-${value})`,
39
70
  outlineColor: `var(--color-${value})`,
40
71
  }"
41
- @click="$emit('select', value)"
72
+ :tabindex="readonly ? -1 : 0"
73
+ @click.prevent="$emit('select', value)"
42
74
  >
43
75
  <AntIcon
44
76
  v-if="selected"
45
77
  :icon="faCheck"
46
- class="text-white"
78
+ :class="iconClasses"
47
79
  />
48
- </div>
80
+ </button>
49
81
  </template>
@@ -6,6 +6,9 @@ import Color from './Color.vue';
6
6
  import {
7
7
  ColorInputSize,
8
8
  } from './AntColorInput.types';
9
+ import {
10
+ onMounted, ref,
11
+ } from 'vue';
9
12
 
10
13
  defineEmits([
11
14
  'select',
@@ -19,6 +22,19 @@ withDefaults(defineProps<{
19
22
  }>(), {
20
23
  size: Size.md,
21
24
  });
25
+
26
+ type ColorComponentInstance = Element & {
27
+ buttonRef: HTMLButtonElement | null;
28
+ };
29
+
30
+ const colorButtonRefs = ref<(ColorComponentInstance | null)[]>([]);
31
+
32
+ onMounted(() => {
33
+ // Set focus to the first item in the colors list
34
+ setTimeout(() => {
35
+ colorButtonRefs.value[0]?.buttonRef?.focus();
36
+ }, 50);
37
+ });
22
38
  </script>
23
39
 
24
40
  <template>
@@ -32,8 +48,9 @@ withDefaults(defineProps<{
32
48
  }"
33
49
  >
34
50
  <Color
35
- v-for="color in colors"
51
+ v-for="(color, index) in colors"
36
52
  :key="color"
53
+ :ref="(val) => colorButtonRefs[index] = val as ColorComponentInstance"
37
54
  :value="color"
38
55
  :selected="color === value"
39
56
  :size="ColorInputSize.xl2"
@@ -1,8 +1,6 @@
1
1
  <script lang="ts" setup>
2
2
  import {
3
- computed,
4
- onMounted,
5
- ref,
3
+ computed, onBeforeUnmount, onMounted, ref,
6
4
  } from 'vue';
7
5
  import AntField from '../forms/AntField.vue';
8
6
  import {
@@ -11,9 +9,6 @@ import {
11
9
  import {
12
10
  InputState, State,
13
11
  } from '../../enums';
14
- import {
15
- useVModel,
16
- } from '@vueuse/core';
17
12
  import {
18
13
  handleEnumValidation,
19
14
  } from '../../handler';
@@ -73,6 +68,44 @@ const openFileDialog = () => {
73
68
  fileInput.value?.click();
74
69
  };
75
70
 
71
+ const isDragging = ref<boolean>(false);
72
+ const isDraggingOverDropZone = ref<boolean>(false);
73
+
74
+ const dropZoneClasses = computed(() => {
75
+ return {
76
+ 'h-full w-full border-2 border-transparent rounded overflow-y-auto p-2 -top-2 -left-2': true,
77
+ 'border-primary-500!': isDraggingOverDropZone.value,
78
+ 'border-dashed border-base-300!': isDragging.value,
79
+ };
80
+ });
81
+
82
+ const handleDragOver = () => {
83
+ isDraggingOverDropZone.value = true;
84
+ };
85
+
86
+ const handleDragEnter = () => {
87
+ isDraggingOverDropZone.value = true;
88
+ };
89
+
90
+ const handleDragLeave = () => {
91
+ isDraggingOverDropZone.value = false;
92
+ };
93
+
94
+ const handleDrop = (event: DragEvent) => {
95
+ isDraggingOverDropZone.value = false;
96
+ isDragging.value = false;
97
+
98
+ if(!event.dataTransfer) {
99
+ return;
100
+ }
101
+
102
+ const file = event.dataTransfer.files?.[0];
103
+
104
+ if(file) {
105
+ emit('upload', file as File);
106
+ }
107
+ };
108
+
76
109
  const handleFileChange = (event: Event) => {
77
110
  const target = event.target as HTMLInputElement;
78
111
  const file = target.files?.[0];
@@ -82,9 +115,34 @@ const handleFileChange = (event: Event) => {
82
115
  }
83
116
  };
84
117
 
118
+ const handleDragOverBody = (e: DragEvent) => {
119
+ e.preventDefault();
120
+ isDragging.value = true;
121
+ };
122
+
123
+ const handleDragLeaveBody = (e: DragEvent) => {
124
+ e.preventDefault();
125
+ isDragging.value = false;
126
+ };
127
+
128
+ const handleDropBody = (e: DragEvent) => {
129
+ e.preventDefault();
130
+ isDragging.value = false;
131
+ };
132
+
85
133
  onMounted(() => {
86
134
  handleEnumValidation(props.state, InputState, 'state');
87
135
  handleEnumValidation(props.size, Size, 'size');
136
+
137
+ document.body.addEventListener('dragover', handleDragOverBody);
138
+ document.body.addEventListener('dragleave', handleDragLeaveBody);
139
+ document.body.addEventListener('drop', handleDropBody);
140
+ });
141
+
142
+ onBeforeUnmount(() => {
143
+ document.body.removeEventListener('dragover', handleDragOverBody);
144
+ document.body.removeEventListener('dragleave', handleDragLeaveBody);
145
+ document.body.removeEventListener('drop', handleDropBody);
88
146
  });
89
147
  </script>
90
148
 
@@ -135,25 +193,36 @@ onMounted(() => {
135
193
  </div>
136
194
 
137
195
  <div class="flex flex-col gap-2.5 w-full">
138
- <div class="flex items-center relative w-full justify-between">
139
- <input
140
- v-if="!disabled && !skeleton"
141
- ref="fileInput"
142
- type="file"
143
- accept="image/*"
144
- class="hidden"
145
- @change="handleFileChange"
146
- >
196
+ <div class="flex items-center relative w-full justify-between gap-2">
197
+ <div class="relative w-full h-full flex items-center">
198
+ <input
199
+ v-if="!disabled && !skeleton"
200
+ ref="fileInput"
201
+ type="file"
202
+ accept="image/*"
203
+ class="hidden"
204
+ @change="handleFileChange"
205
+ >
206
+
207
+ <span class="text-sm text-for-white-bg-font relative">
208
+ Upload Image
147
209
 
148
- <span class="text-sm text-for-white-bg-font relative">
149
- Upload Image
210
+ <AntSkeleton
211
+ v-if="skeleton"
212
+ absolute
213
+ rounded
214
+ />
215
+ </span>
150
216
 
151
- <AntSkeleton
152
- v-if="skeleton"
153
- absolute
154
- rounded
217
+ <div
218
+ class="absolute top-0 left-0 w-full h-full border bg-transparent"
219
+ :class="dropZoneClasses"
220
+ @drop.prevent="handleDrop"
221
+ @dragenter.prevent="handleDragEnter"
222
+ @dragover.prevent="handleDragOver"
223
+ @dragleave.prevent="handleDragLeave"
155
224
  />
156
- </span>
225
+ </div>
157
226
 
158
227
  <AntButton
159
228
  v-if="src"
@@ -283,7 +283,6 @@ function onClickRemoveButton() {
283
283
  :size="size"
284
284
  :state="state"
285
285
  :close-on-enter="true"
286
- @select-element="(e) => _modelValue = e"
287
286
  >
288
287
  <template #contentLeft="props">
289
288
  <slot
@@ -324,7 +323,7 @@ function onClickRemoveButton() {
324
323
 
325
324
  <div
326
325
  v-else
327
- class="flex items-center select-none text-ellipsis overflow-hidden whitespace-nowrap w-full text-black"
326
+ class="flex items-center select-none overflow-hidden w-full"
328
327
  :class="{
329
328
  'gap-1': size === Size.xs2,
330
329
  'gap1.5': size === Size.xs,
@@ -338,7 +337,9 @@ function onClickRemoveButton() {
338
337
  name="contentLeft"
339
338
  v-bind="selectedOption"
340
339
  />
341
- {{ valueLabel }}
340
+ <div class="text-ellipsis overflow-hidden whitespace-nowrap w-full text-black">
341
+ {{ valueLabel }}
342
+ </div>
342
343
  <slot
343
344
  v-if="selectedOption !== null"
344
345
  name="contentRight"
@@ -154,7 +154,6 @@ function onClickOutside() {
154
154
  if (!dropDownOpen.value) {
155
155
  return;
156
156
  }
157
- console.log('click outside');
158
157
  // dropDownOpen.value = false;
159
158
  }
160
159
 
@@ -183,7 +182,6 @@ function addTagFromOptions(item: string | number) {
183
182
  addTag(item);
184
183
 
185
184
  if (props.autoCloseAfterSelection) {
186
- console.log('HIER');
187
185
  dropDownOpen.value = false;
188
186
  }
189
187
  }
@@ -221,6 +219,10 @@ function changeFocus() {
221
219
  dropDownOpen.value = true;
222
220
  }
223
221
 
222
+ function closeDropdown() {
223
+ dropDownOpen.value = false;
224
+ }
225
+
224
226
  function onBlur(e: FocusEvent) {
225
227
  emit('validate', props.modelValue);
226
228
  emit('blur', e);
@@ -312,9 +314,11 @@ onMounted(() => {
312
314
  :class="inputClasses"
313
315
  :disabled="disabled"
314
316
  :readonly="readonly"
317
+ @click="changeFocus"
315
318
  @focus="changeFocus"
316
319
  @keydown.delete="removeLastTag"
317
320
  @keydown.enter.prevent="checkCreateTag(tagInput)"
321
+ @keydown.esc.prevent="closeDropdown"
318
322
  @blur="onBlur"
319
323
  >
320
324
  </div>
@@ -16,13 +16,13 @@ import type {
16
16
  SelectOption,
17
17
  } from '../__types';
18
18
  import {
19
- useElementSize, useVModel, onClickOutside,
19
+ onClickOutside, useElementSize, useVModel,
20
20
  } from '@vueuse/core';
21
21
  import type {
22
22
  Validator,
23
23
  } from '@antify/validate';
24
24
  import {
25
- autoUpdate, flip, offset, useFloating,
25
+ autoPlacement, autoUpdate, flip, offset, useFloating,
26
26
  } from '@floating-ui/vue';
27
27
 
28
28
  const emit = defineEmits([
@@ -56,13 +56,21 @@ const floating = ref<HTMLElement | null>(null);
56
56
  const {
57
57
  floatingStyles,
58
58
  } = useFloating(reference, floating, {
59
- placement: 'bottom',
59
+ placement: 'bottom-start',
60
60
  whileElementsMounted: autoUpdate,
61
61
  middleware: [
62
62
  offset(8),
63
+ autoPlacement({
64
+ allowedPlacements: [
65
+ 'top-start',
66
+ 'top-end',
67
+ 'bottom-start',
68
+ 'bottom-end',
69
+ ],
70
+ }),
63
71
  flip({
64
72
  fallbackPlacements: [
65
- 'top',
73
+ 'top-start',
66
74
  ],
67
75
  }),
68
76
  ],
@@ -89,7 +97,7 @@ const dropdownClasses = computed(() => {
89
97
  };
90
98
 
91
99
  return {
92
- 'w-full border flex flex-col gap-px outline-none -mt-px overflow-y-auto shadow-md z-[90] max-h-[250px]': true,
100
+ 'w-fit border flex flex-col gap-px outline-none -mt-px overflow-y-auto shadow-md z-[90] max-h-[250px]': true,
93
101
  'rounded-md': true,
94
102
  [variants[props.state]]: true,
95
103
  };
@@ -121,7 +129,7 @@ watch(isOpen, () => {
121
129
  focusedDropDownItem.value =
122
130
  typeof _modelValue.value === 'string' || typeof _modelValue.value === 'number' ? _modelValue.value :
123
131
  Array.isArray(_modelValue.value) ? _modelValue.value[0] :
124
- (props.options[0].value || null);
132
+ (props.options[0]?.value || null);
125
133
  } else {
126
134
  focusedDropDownItem.value = null;
127
135
  }
@@ -288,7 +296,7 @@ watch(_modelValue, (val) => {
288
296
  ref="floating"
289
297
  :class="dropdownClasses"
290
298
  data-e2e="select-menu"
291
- :style="{width: `${elementSize.width.value}px!important`, ...floatingStyles}"
299
+ :style="{minWidth: `${elementSize.width.value}px!important`, ...floatingStyles}"
292
300
  >
293
301
  <div
294
302
  v-for="(option, index) in options"
@@ -6,6 +6,7 @@ type Story = StoryObj<typeof AntSelect>;
6
6
  export declare const Docs: Story;
7
7
  export declare const WithSlots: Story;
8
8
  export declare const manyOptions: Story;
9
+ export declare const longOptions: Story;
9
10
  export declare const nullable: Story;
10
11
  export declare const skeleton: Story;
11
12
  export declare const disabled: Story;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.withPlaceholder = exports.summary = exports.skeleton = exports.nullable = exports.manyOptions = exports.grouped = exports.ellipsisText = exports.disabled = exports.default = exports.WithSlots = exports.Docs = void 0;
6
+ exports.withPlaceholder = exports.summary = exports.skeleton = exports.nullable = exports.manyOptions = exports.longOptions = exports.grouped = exports.ellipsisText = exports.disabled = exports.default = exports.WithSlots = exports.Docs = void 0;
7
7
  var _Size = require("../../../enums/Size.enum");
8
8
  var _AntSelect = _interopRequireDefault(require("../AntSelect.vue"));
9
9
  var _AntIcon = _interopRequireDefault(require("../../AntIcon.vue"));
@@ -11,6 +11,8 @@ var _AntSelectMenu = _interopRequireDefault(require("../Elements/AntSelectMenu.v
11
11
  var _freeSolidSvgIcons = require("@fortawesome/free-solid-svg-icons");
12
12
  var _vue = require("vue");
13
13
  var _enums = require("../../../enums");
14
+ var _AntFormGroup = _interopRequireDefault(require("../../forms/AntFormGroup.vue"));
15
+ var _AntFormGroupLabel = _interopRequireDefault(require("../../forms/AntFormGroupLabel.vue"));
14
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
17
  const meta = {
16
18
  title: "Inputs/Select",
@@ -81,6 +83,10 @@ const manySelectOptions = [...Array(24).keys()].map(key => ({
81
83
  label: `Option ${Number(key) + 1}`,
82
84
  value: Number(key) + 1
83
85
  }));
86
+ const longSelectOptions = [...Array(4).keys()].map(key => ({
87
+ label: `Very Long Select Option Possibly Larger Than Container ${Number(key) + 1}`,
88
+ value: Number(key) + 1
89
+ }));
84
90
  const Docs = exports.Docs = {
85
91
  render: args => ({
86
92
  components: {
@@ -193,6 +199,25 @@ const manyOptions = exports.manyOptions = {
193
199
  options: manySelectOptions
194
200
  }
195
201
  };
202
+ const longOptions = exports.longOptions = {
203
+ render: (args, ctx) => ({
204
+ // @ts-ignore
205
+ components: Docs.render(args, ctx).components,
206
+ // @ts-ignore
207
+ setup: Docs.render(args, ctx).setup,
208
+ template: `
209
+ <div class="flex justify-center overflow-y-auto h-[100vh] p-2.5 dashed">
210
+ <div class="flex flex-col gap-4 justify-center h-[250vh] max-w-[150px]">
211
+ <AntSelect v-bind="args" v-model="modelValue"/>
212
+ </div>
213
+ </div>
214
+ `
215
+ }),
216
+ args: {
217
+ ...Docs.args,
218
+ options: longSelectOptions
219
+ }
220
+ };
196
221
  const nullable = exports.nullable = {
197
222
  render: Docs.render,
198
223
  args: {
@@ -312,9 +337,18 @@ const summary = exports.summary = {
312
337
  },
313
338
  render: (args, ctx) => ({
314
339
  // @ts-ignore
315
- components: Docs.render(args, ctx).components,
340
+ components: {
341
+ AntSelect: _AntSelect.default,
342
+ AntFormGroup: _AntFormGroup.default,
343
+ AntFormGroupLabel: _AntFormGroupLabel.default
344
+ },
316
345
  // @ts-ignore
317
- setup: Docs.render(args, ctx).setup,
346
+ setup() {
347
+ return {
348
+ ...Docs.render(args, ctx).setup(),
349
+ longSelectOptions
350
+ };
351
+ },
318
352
  template: `
319
353
  <div class="p-4 flex flex-col gap-2.5">
320
354
  <div class="flex w-2/5 gap-2.5">
@@ -385,6 +419,16 @@ const summary = exports.summary = {
385
419
  <AntSelect v-bind="args" v-model="modelValue" size="sm" nullable state="warning"/>
386
420
  <AntSelect v-bind="args" v-model="modelValue" size="sm" nullable state="danger"/>
387
421
  </div>
422
+ <AntFormGroup>
423
+ <AntFormGroupLabel>Long Select Options</AntFormGroupLabel>
424
+ <div class="grid grid-cols-5 gap-2.5">
425
+ <AntSelect v-bind="args" v-model="modelValue" :options="longSelectOptions"/>
426
+ <AntSelect v-bind="args" v-model="modelValue" :options="longSelectOptions"/>
427
+ <AntSelect v-bind="args" v-model="modelValue" :options="longSelectOptions"/>
428
+ <AntSelect v-bind="args" v-model="modelValue" :options="longSelectOptions"/>
429
+ <AntSelect v-bind="args" v-model="modelValue" :options="longSelectOptions"/>
430
+ </div>
431
+ </AntFormGroup>
388
432
  </div>
389
433
  `
390
434
  }),
@@ -15,6 +15,8 @@ import {
15
15
  import {
16
16
  InputState
17
17
  } from "../../../enums/index.mjs";
18
+ import AntFormGroup from "../../forms/AntFormGroup.vue";
19
+ import AntFormGroupLabel from "../../forms/AntFormGroupLabel.vue";
18
20
  const meta = {
19
21
  title: "Inputs/Select",
20
22
  component: AntSelect,
@@ -91,6 +93,12 @@ const manySelectOptions = [
91
93
  label: `Option ${Number(key) + 1}`,
92
94
  value: Number(key) + 1
93
95
  }));
96
+ const longSelectOptions = [
97
+ ...Array(4).keys()
98
+ ].map((key) => ({
99
+ label: `Very Long Select Option Possibly Larger Than Container ${Number(key) + 1}`,
100
+ value: Number(key) + 1
101
+ }));
94
102
  export const Docs = {
95
103
  render: (args) => ({
96
104
  components: {
@@ -208,6 +216,25 @@ export const manyOptions = {
208
216
  options: manySelectOptions
209
217
  }
210
218
  };
219
+ export const longOptions = {
220
+ render: (args, ctx) => ({
221
+ // @ts-ignore
222
+ components: Docs.render(args, ctx).components,
223
+ // @ts-ignore
224
+ setup: Docs.render(args, ctx).setup,
225
+ template: `
226
+ <div class="flex justify-center overflow-y-auto h-[100vh] p-2.5 dashed">
227
+ <div class="flex flex-col gap-4 justify-center h-[250vh] max-w-[150px]">
228
+ <AntSelect v-bind="args" v-model="modelValue"/>
229
+ </div>
230
+ </div>
231
+ `
232
+ }),
233
+ args: {
234
+ ...Docs.args,
235
+ options: longSelectOptions
236
+ }
237
+ };
211
238
  export const nullable = {
212
239
  render: Docs.render,
213
240
  args: {
@@ -334,9 +361,18 @@ export const summary = {
334
361
  },
335
362
  render: (args, ctx) => ({
336
363
  // @ts-ignore
337
- components: Docs.render(args, ctx).components,
364
+ components: {
365
+ AntSelect,
366
+ AntFormGroup,
367
+ AntFormGroupLabel
368
+ },
338
369
  // @ts-ignore
339
- setup: Docs.render(args, ctx).setup,
370
+ setup() {
371
+ return {
372
+ ...Docs.render(args, ctx).setup(),
373
+ longSelectOptions
374
+ };
375
+ },
340
376
  template: `
341
377
  <div class="p-4 flex flex-col gap-2.5">
342
378
  <div class="flex w-2/5 gap-2.5">
@@ -407,6 +443,16 @@ export const summary = {
407
443
  <AntSelect v-bind="args" v-model="modelValue" size="sm" nullable state="warning"/>
408
444
  <AntSelect v-bind="args" v-model="modelValue" size="sm" nullable state="danger"/>
409
445
  </div>
446
+ <AntFormGroup>
447
+ <AntFormGroupLabel>Long Select Options</AntFormGroupLabel>
448
+ <div class="grid grid-cols-5 gap-2.5">
449
+ <AntSelect v-bind="args" v-model="modelValue" :options="longSelectOptions"/>
450
+ <AntSelect v-bind="args" v-model="modelValue" :options="longSelectOptions"/>
451
+ <AntSelect v-bind="args" v-model="modelValue" :options="longSelectOptions"/>
452
+ <AntSelect v-bind="args" v-model="modelValue" :options="longSelectOptions"/>
453
+ <AntSelect v-bind="args" v-model="modelValue" :options="longSelectOptions"/>
454
+ </div>
455
+ </AntFormGroup>
410
456
  </div>
411
457
  `
412
458
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antify/ui",
3
- "version": "2.4.5",
3
+ "version": "2.4.10",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {