@neatui/vue 2.17.1 → 2.17.3

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.
@@ -1,230 +0,0 @@
1
- <template>
2
- <div
3
- :ui-form="`${theme} sz:${sz} ${state.error.co} type:input ${block ? ' :block' : ''} ${disabled ? 'disabled' : ''} ${readonly ? 'readonly' : ''}`"
4
- @click="emits('click', $event)"
5
- >
6
- <div :ui-form-tips="state.error.ontips">{{ state.error.tips }}</div>
7
- <div ui-form-prefix="">
8
- <template v-for="(item, idx) in prefix" :key="idx">
9
- <div v-html="isObject(item) ? item.html : item"></div>
10
- </template>
11
- <slot name="prefix"></slot>
12
- </div>
13
- <slot>
14
- <input
15
- v-model="state.value"
16
- :type="type"
17
- :placeholder="placeholder"
18
- :readonly="readonly || disabled"
19
- autocomplete="new-password"
20
- @focus="emits('focus', $event, state)"
21
- @input="input($event)"
22
- @change="emits('change', $event, state)"
23
- @blur="blur($event)"
24
- />
25
- </slot>
26
- <div ui-form-suffix="">
27
- <i ui-form-clean="" v-if="clearable && state.value && !readonly && !disabled" @click.stop="clear"></i>
28
- <slot name="suffix"></slot>
29
- <template v-for="(item, idx) in suffix" :key="idx">
30
- <div v-html="isObject(item) ? item.html : item"></div>
31
- </template>
32
- </div>
33
- <i v-if="ready && verify" :ui-form-verify="verify"></i>
34
- </div>
35
- </template>
36
-
37
- <script setup lang="ts">
38
- import { reactive, watch } from 'vue';
39
- import { isObject } from '@fekit/utils';
40
-
41
- const emits = defineEmits(['update:modelValue', 'click', 'blur', 'focus', 'change', 'input', 'clear']);
42
-
43
- /**
44
- * 入参说明
45
- *
46
- * modelValue 值
47
- * theme 主题
48
- * sz 尺寸
49
- * co 颜色
50
- * block 撑满
51
- * ready 准备就绪
52
- * type 类型
53
- * tips 提示文案
54
- * placeholder 内容占位
55
- * maxlength 最大长度
56
- * minlength 最小长度
57
- * disabled 是否禁用
58
- * readonly 是否只读
59
- * clearable 是否显示清除按钮
60
- * rules 校验规则
61
- * verify 是否是示校验图标
62
- * prefix 前缀内容
63
- * suffix 后缀内容
64
- * interacted 用户是否交互
65
- */
66
-
67
- // 类型
68
- interface Props {
69
- modelValue?: string | number;
70
- placeholder?: string;
71
- rules?: Array<object>;
72
- theme?: string;
73
- sz?: '' | 'xs' | 's' | 'm' | 'l' | 'xl';
74
- co?: string;
75
- block?: boolean;
76
- ready?: boolean;
77
- type?: string;
78
- tips?: string;
79
- maxlength?: null | number;
80
- minlength?: null | number;
81
- disabled?: boolean;
82
- readonly?: boolean;
83
- clearable?: boolean;
84
- verify?: boolean;
85
- prefix?: Array<any>;
86
- suffix?: Array<any>;
87
- interacted?: boolean;
88
- }
89
- const props: any = withDefaults(defineProps<Props>(), {
90
- modelValue: '',
91
- placeholder: '',
92
- rules: () => [],
93
- theme: '@a',
94
- sz: '',
95
- co: '',
96
- block: true,
97
- ready: false,
98
- type: 'text',
99
- tips: '',
100
- maxlength: null,
101
- minlength: null,
102
- disabled: false,
103
- readonly: false,
104
- clearable: true,
105
- verify: false,
106
- prefix: () => [],
107
- suffix: () => [],
108
- interacted: false
109
- });
110
-
111
- const state: any = reactive({
112
- // 用户是否交互
113
- interacted: false,
114
- // 值
115
- value: props.modelValue,
116
- // 错误
117
- error: {}
118
- });
119
- // 外部传入交互标识,主要用于外部没有输入但点击了提交
120
- watch(
121
- () => props.interacted,
122
- (interacted: any) => {
123
- if (interacted) {
124
- state.interacted = interacted;
125
- }
126
- },
127
- { deep: true, immediate: true }
128
- );
129
-
130
- // 监听异步数据
131
- watch(
132
- () => props.modelValue,
133
- (value: any) => {
134
- if (state.value !== value) {
135
- state.value = value;
136
- }
137
- },
138
- { deep: true, immediate: true }
139
- );
140
- watch(
141
- () => state.value,
142
- (value: any) => {
143
- emits('update:modelValue', value);
144
- },
145
- { deep: true, immediate: true }
146
- );
147
-
148
- // 校验
149
- watch(
150
- [() => state.interacted, () => state.value],
151
- async () => {
152
- if (state.interacted) {
153
- // 提示文案
154
- let tips = '';
155
- // 错误类型
156
- let type = '';
157
- // 验证结果
158
- let verify = '';
159
-
160
- if (props.modelValue) {
161
- // 有值
162
- let hasError = false;
163
- // 遍历校验规则
164
- for (const rule of props.rules) {
165
- if (rule && rule.validator) {
166
- const yes = !(await rule.validator(props.modelValue));
167
- if (yes) {
168
- tips = rule.msg;
169
- type = rule.type;
170
- hasError = true;
171
- break;
172
- }
173
- }
174
- }
175
- verify = hasError ? 'no' : 'ok';
176
- } else {
177
- // 无值
178
- let hasError = false;
179
- // 遍历校验规则
180
- for (const rule of props.rules) {
181
- if (rule) {
182
- tips = rule.msg;
183
- type = rule.type;
184
- if (rule.required) {
185
- hasError = true;
186
- break;
187
- }
188
- }
189
- }
190
- verify = hasError ? 'no' : '';
191
- }
192
- if (verify !== 'no' && props.tips) {
193
- tips = props.tips;
194
- }
195
- // 是否显示提示
196
- const ontips = (verify === 'no' && tips) || props.tips ? 'show' : '';
197
- // 状态颜色
198
- const co = verify === 'no' ? 'co:' + type : props.co ? 'co:' + props.co : '';
199
- state.error = { tips, ontips, verify, co };
200
- } else {
201
- state.error = { tips: props.tips, ontips: props.tips ? 'show' : '', verify: '', co: '' };
202
- }
203
- },
204
- { deep: true, immediate: true }
205
- );
206
-
207
- // 清空
208
- function clear() {
209
- emits('update:modelValue', '');
210
- emits('clear');
211
- }
212
- // 输入
213
- const input = (e: any) => {
214
- if (!state.interacted) {
215
- setTimeout(() => {
216
- state.interacted = true;
217
- }, 50);
218
- }
219
- emits('input', e, state);
220
- };
221
- // 失焦
222
- const blur = (e: any) => {
223
- if (!state.interacted) {
224
- setTimeout(() => {
225
- state.interacted = true;
226
- }, 50);
227
- }
228
- emits('blur', e, state);
229
- };
230
- </script>
@@ -1,144 +0,0 @@
1
- <template>
2
- <div :ui-form="`@a type:select ${sz ? 'sz:' + sz : ''}`">
3
- <IFollowView ref="ifollow" tipBoxClass="ny-sm nx-no" tipBoxStyle="min-width: 100%">
4
- <slot>
5
- <Input v-bind="$props" :clearable="false" readonly v-model="state.value" :interacted="interacted">
6
- <template #suffix><i ui-form-select=""></i></template>
7
- </Input>
8
- </slot>
9
- <template #tips>
10
- <ul v-if="props.options?.length" ui-scroll=":y s" class="nx-sm lh-ml" style="min-width: 100%; max-height: 15em">
11
- <template v-for="(item, idx) of props.options" :key="idx">
12
- <li v-if="item.disable" class="ux-hover nx-sm r-ss o-ms">
13
- <label style="pointer-events: none" ui-form="@a type:checkbox :block">
14
- <input type="checkbox" :name="state.name" :checked="modelValue?.some((i: any) => `${i}` === `${item.value}`)" />
15
- <del class="ml-sm">{{ item.label || item }}</del>
16
- </label>
17
- </li>
18
- <li v-else class="ux-hover nx-sm r-ss" @click.stop="select(item.value)">
19
- <label style="pointer-events: none" ui-form="@a type:checkbox :block">
20
- <input type="checkbox" :name="state.name" :checked="modelValue?.some((i: any) => `${i}` === `${item.value}`)" />
21
- <span class="ml-sm">{{ item.label || item }}</span>
22
- </label>
23
- </li>
24
- </template>
25
- </ul>
26
- <div v-else class="w-full ny-ms" ui-flex="col cm" v-html="spare"></div>
27
- <ul class="nx-sm lh-ml" v-if="tools">
28
- <li class="my-ss"><div class="o-mm" ui-line="@a"></div></li>
29
- <li ui-flex="row xm">
30
- <div class="ux-hover nx-sm r-ss nowrap co-main" @click.stop="allselect()">
31
- <label style="pointer-events: none" ui-form="@a type:checkbox :block">
32
- <input type="checkbox" :name="state.name" :checked="state.all" />
33
- <span class="ml-sm">全选({{ props.options?.length || 0 }})</span>
34
- </label>
35
- </div>
36
- <div>
37
- <button v-show="state.has" class="co-risk" ui-btn="@a none s" @click="remove">清空</button>
38
- </div>
39
- </li>
40
- </ul>
41
- </template>
42
- </IFollowView>
43
- </div>
44
- </template>
45
-
46
- <script setup lang="ts">
47
- import { reactive, ref, computed, watch } from 'vue';
48
- import { Input } from '../form';
49
- import { IFollowView } from '../basic';
50
- const ifollow: any = ref(null);
51
-
52
- const emits = defineEmits(['update:modelValue']);
53
- const props: any = defineProps({
54
- // 用户是否交互
55
- interacted: {
56
- type: Boolean,
57
- default: false
58
- },
59
- theme: { type: String, default: '@a' },
60
- sz: { type: String, default: '' },
61
- co: { type: String, default: '' },
62
- block: { type: Boolean, default: true },
63
- // 提示文案
64
- tips: {
65
- type: String,
66
- default: ''
67
- },
68
- placeholder: {
69
- type: String,
70
- default: ''
71
- },
72
- modelValue: {
73
- type: Array as () => any[],
74
- default: () => []
75
- },
76
- options: {
77
- type: Array as () => any[],
78
- default: () => []
79
- },
80
- // 校验规则
81
- rules: {
82
- type: Array,
83
- default: () => []
84
- },
85
- // 是否是示校验图标
86
- verify: {
87
- type: Boolean,
88
- default: false
89
- },
90
- tools: {
91
- type: Boolean,
92
- default: true
93
- },
94
- spare: {
95
- type: String,
96
- default: '当前没有可选项'
97
- }
98
- });
99
-
100
- const state: any = reactive({
101
- name: computed(() => {
102
- return Array.from({ length: 8 }, () => String.fromCharCode(97 + Math.floor(Math.random() * 26))).join('');
103
- }),
104
- show: 0,
105
- value: '',
106
- all: computed(() => {
107
- return props.options?.every((item: any) => props.modelValue?.some((i: any) => `${i}` === `${item.value}`));
108
- }),
109
- has: computed(() => {
110
- return props.options?.some((item: any) => props.modelValue?.some((i: any) => `${i}` === `${item.value}`));
111
- })
112
- });
113
-
114
- // 监听外部数据
115
- watch(
116
- () => props.modelValue,
117
- (v: any = []) => {
118
- const selectd: any = props.options?.filter((item: any) => v?.some((i: any) => `${i}` === `${item.value}`))?.map((item: any) => item.label) || [];
119
- state.value = selectd.join(' Ι ') || '';
120
- },
121
- { deep: true, immediate: true }
122
- );
123
-
124
- // 更新
125
- const change = (item: any) => {
126
- emits('update:modelValue', item);
127
- };
128
- // 选中
129
- const select = (item: any) => {
130
- const s = [...props.modelValue];
131
- s?.indexOf(item) !== -1 ? s?.splice(s?.indexOf(item), 1) : s?.push(item);
132
- change(s);
133
- };
134
- // 全选
135
- const allselect = () => {
136
- const s = state.all ? [] : props.options?.map((item: any) => item.value);
137
- change(s);
138
- };
139
- // 清除
140
- const remove = () => {
141
- change([]);
142
- ifollow.value.cancel();
143
- };
144
- </script>
@@ -1,194 +0,0 @@
1
- <template>
2
- <div :ui-form="`@a type:select sz:${sz}`" :ui-form-open="state.show ? 'show' : ''">
3
- <IFollowView ref="ifollow" tipBoxClass="ny-sm nx-no" tipBoxStyle="min-width: 100%" @onshow="onshow" @onhide="onhide">
4
- <Input
5
- v-bind="{ placeholder, rules, theme, sz, co, block, ready, type, tips, disabled, readonly: true, clearable: false, verify, prefix, suffix, interacted }"
6
- v-model="state.selectd.label"
7
- :interacted="interacted"
8
- >
9
- <template #suffix><i ui-form-select=""></i></template>
10
- </Input>
11
- <template #tips v-if="!readonly || !disabled">
12
- <div v-if="search" class="ny-sm nx-sl">
13
- <Input v-model="state.search" sz="s">
14
- <template #suffix>
15
- <i ui-form-search="" class="co-note"></i>
16
- </template>
17
- </Input>
18
- </div>
19
- <ul v-if="props.options?.length" ui-scroll=":y s" class="nx-sm lh-ml" style="min-width: 100%; max-height: 16em">
20
- <li class="ux-hover nx-sm r-ss nowrap" :class="item.value === state.selectd?.value ? 'co-main' : ''" v-for="(item, idx) of state.filter" :key="idx" @click="select(item)">
21
- {{ item.label || item }}
22
- </li>
23
- </ul>
24
- <div v-else class="w-full ny-ms" ui-flex="col cm" v-html="spare"></div>
25
- <ul class="nx-sm lh-ml" v-if="tools">
26
- <li class="my-ss"><div class="o-mm" ui-line="@a"></div></li>
27
- <li ui-flex="row xm">
28
- <div class="co-main">
29
- <p class="nx-sm r-ss nowrap">
30
- <span>{{ state.filter?.length || 0 }}个可选项</span>
31
- </p>
32
- </div>
33
- <div>
34
- <button v-show="state.selectd?.value" class="co-risk" ui-btn="@a none s" @click="remove">清空</button>
35
- </div>
36
- </li>
37
- </ul>
38
- </template>
39
- </IFollowView>
40
- </div>
41
- </template>
42
-
43
- <script setup lang="ts">
44
- import { reactive, ref, computed } from 'vue';
45
- import { Input } from '../form';
46
- import { IFollowView } from '../basic';
47
- const ifollow: any = ref(null);
48
-
49
- const emits = defineEmits(['update:modelValue', 'change', 'onshow', 'onhide']);
50
-
51
- /**
52
- * 入参说明
53
- * modelValue 值
54
- * options 枚举列表
55
- * tools 是否显示工具栏
56
- * spare 空闲兜底内容
57
- * search 是否启用搜索框
58
- * pagination 是否启用分页
59
- * refresh 是否显示刷新
60
- *
61
- * ---------------------------
62
- * theme 主题
63
- * sz 尺寸
64
- * co 颜色
65
- * block 撑满
66
- * ready 准备就绪
67
- * type 类型
68
- * tips 提示文案
69
- * placeholder 内容占位
70
- * maxlength 最大长度
71
- * minlength 最小长度
72
- * disabled 是否禁用
73
- * readonly 是否只读
74
- * clearable 是否显示清除按钮
75
- * rules 校验规则
76
- * verify 是否是示校验图标
77
- * prefix 前缀内容
78
- * suffix 后缀内容
79
- * interacted 用户是否交互
80
- */
81
-
82
- // 类型
83
- interface Props {
84
- modelValue?: string | number;
85
- options: Array<object>;
86
- tools?: boolean;
87
- spare?: string;
88
- search?: boolean;
89
- pagination?: boolean;
90
- refresh?: boolean;
91
-
92
- // Input
93
- placeholder?: string;
94
- rules?: Array<object>;
95
- theme?: string;
96
- sz?: '' | 'xs' | 's' | 'm' | 'l' | 'xl';
97
- co?: string;
98
- block?: boolean;
99
- ready?: boolean;
100
- type?: string;
101
- tips?: string;
102
- maxlength?: null | number;
103
- minlength?: null | number;
104
- disabled?: boolean;
105
- readonly?: boolean;
106
- clearable?: boolean;
107
- verify?: boolean;
108
- prefix?: Array<any>;
109
- suffix?: Array<any>;
110
- interacted?: boolean;
111
- }
112
-
113
- // 入参
114
- const props: any = withDefaults(defineProps<Props>(), {
115
- modelValue: '',
116
- options: () => [],
117
- tools: true,
118
- spare: '当前没有可选项',
119
- search: true,
120
- pagination: false,
121
- refresh: false,
122
-
123
- // INPUT
124
- placeholder: '',
125
- rules: () => [],
126
- theme: '@a',
127
- sz: '',
128
- co: '',
129
- block: true,
130
- ready: false,
131
- type: 'text',
132
- tips: '',
133
- maxlength: null,
134
- minlength: null,
135
- disabled: false,
136
- readonly: false,
137
- clearable: false,
138
- verify: false,
139
- prefix: () => [],
140
- suffix: () => [],
141
- interacted: false
142
- });
143
-
144
- const change = ({ value = '' }: any = {}) => {
145
- emits('update:modelValue', value);
146
- emits('change', value);
147
- };
148
-
149
- const state = reactive({
150
- show: 0,
151
- search: '',
152
- selectd: computed(() => {
153
- return props.options.find((option: any) => `${option.value}` === `${props.modelValue}`) || {};
154
- }),
155
- filter: computed(() => {
156
- if (state.search) {
157
- return props.options?.filter((item: any) => {
158
- return item.label?.includes(state.search);
159
- });
160
- } else {
161
- return props.options;
162
- }
163
- })
164
- });
165
- // 选择
166
- const select = (item: any = {}) => {
167
- change(item);
168
- ifollow.value.cancel();
169
- };
170
- // 清空
171
- const remove = () => {
172
- change({});
173
- ifollow.value.cancel();
174
- };
175
- // 取消
176
- const cancel = () => {
177
- ifollow.value.cancel();
178
- };
179
- // 显示
180
- const onshow = () => {
181
- emits('onshow', state.selectd);
182
- };
183
- // 折叠
184
- const onhide = () => {
185
- emits('onhide', state.selectd);
186
- };
187
-
188
- defineExpose({
189
- select,
190
- remove,
191
- change,
192
- cancel
193
- });
194
- </script>