@hbdlzy/ui-core 0.1.1 → 0.1.2

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 (35) hide show
  1. package/README.md +37 -2
  2. package/components.manifest.json +195 -163
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.js +1877 -13
  5. package/dist/style.css +1 -1
  6. package/package.json +2 -1
  7. package/src/components/OutlinedCascader/OutlinedCascader.types.ts +28 -0
  8. package/src/components/OutlinedCascader/OutlinedCascader.vue +250 -0
  9. package/src/components/OutlinedCascader/README.md +91 -0
  10. package/src/components/OutlinedCascader/index.ts +10 -0
  11. package/src/components/OutlinedDatePicker/OutlinedDatePicker.types.ts +40 -0
  12. package/src/components/OutlinedDatePicker/OutlinedDatePicker.vue +365 -0
  13. package/src/components/OutlinedDatePicker/README.md +137 -0
  14. package/src/components/OutlinedDatePicker/index.ts +11 -0
  15. package/src/components/OutlinedDateTimePicker/OutlinedDateTimePicker.types.ts +34 -0
  16. package/src/components/OutlinedDateTimePicker/OutlinedDateTimePicker.vue +421 -0
  17. package/src/components/OutlinedDateTimePicker/README.md +88 -0
  18. package/src/components/OutlinedDateTimePicker/index.ts +11 -0
  19. package/src/components/OutlinedInput/OutlinedInput.types.ts +32 -0
  20. package/src/components/OutlinedInput/OutlinedInput.vue +307 -0
  21. package/src/components/OutlinedInput/README.md +154 -0
  22. package/src/components/OutlinedInput/index.ts +10 -0
  23. package/src/components/OutlinedSelect/OutlinedSelect.types.ts +48 -0
  24. package/src/components/OutlinedSelect/OutlinedSelect.vue +359 -0
  25. package/src/components/OutlinedSelect/README.md +166 -0
  26. package/src/components/OutlinedSelect/index.ts +12 -0
  27. package/src/components/OutlinedTimePicker/OutlinedTimePicker.types.ts +36 -0
  28. package/src/components/OutlinedTimePicker/OutlinedTimePicker.vue +303 -0
  29. package/src/components/OutlinedTimePicker/README.md +93 -0
  30. package/src/components/OutlinedTimePicker/index.ts +10 -0
  31. package/src/components/OutlinedTreeSelect/OutlinedTreeSelect.types.ts +56 -0
  32. package/src/components/OutlinedTreeSelect/OutlinedTreeSelect.vue +354 -0
  33. package/src/components/OutlinedTreeSelect/README.md +107 -0
  34. package/src/components/OutlinedTreeSelect/index.ts +12 -0
  35. package/src/index.ts +14 -0
@@ -0,0 +1,354 @@
1
+ <template>
2
+ <div
3
+ class="outlined-tree-select"
4
+ :class="[containerClasses, rootClass]"
5
+ :style="[containerStyle, rootStyle]"
6
+ >
7
+ <el-tree-select
8
+ ref="treeSelectRef"
9
+ v-bind="treeSelectAttrs"
10
+ class="outlined-tree-select__control"
11
+ :model-value="treeSelectValue"
12
+ :data="data"
13
+ :props="resolvedTreeProps"
14
+ :placeholder="placeholder"
15
+ :disabled="disabled"
16
+ :clearable="clearable"
17
+ :filterable="filterable"
18
+ :multiple="multiple"
19
+ :show-checkbox="showCheckbox"
20
+ :check-strictly="checkStrictly"
21
+ :check-on-click-node="checkOnClickNode"
22
+ :default-expand-all="defaultExpandAll"
23
+ :expand-on-click-node="expandOnClickNode"
24
+ :render-after-expand="renderAfterExpand"
25
+ :collapse-tags="collapseTags"
26
+ :collapse-tags-tooltip="collapseTagsTooltip"
27
+ :max-collapse-tags="maxCollapseTags"
28
+ :popper-class="popperClass"
29
+ :node-key="nodeKey"
30
+ :style="treeSelectStyle"
31
+ @update:model-value="handleModelValueUpdate"
32
+ @focus="handleFocus"
33
+ @blur="handleBlur"
34
+ @change="handleChange"
35
+ @visible-change="handleVisibleChange"
36
+ @clear="handleClear"
37
+ >
38
+ <template #empty>
39
+ <slot name="empty" />
40
+ </template>
41
+
42
+ <template #header>
43
+ <slot name="header" />
44
+ </template>
45
+
46
+ <template #footer>
47
+ <slot name="footer" />
48
+ </template>
49
+ </el-tree-select>
50
+
51
+ <div
52
+ v-if="floatingLabel"
53
+ class="outlined-tree-select__label"
54
+ :class="labelClasses"
55
+ >
56
+ {{ floatingLabel }}
57
+ </div>
58
+ </div>
59
+ </template>
60
+
61
+ <script setup lang="ts">
62
+ import { computed, ref, useAttrs, watch } from 'vue'
63
+ import type {
64
+ OutlinedTreeSelectCssValue,
65
+ OutlinedTreeSelectExpose,
66
+ OutlinedTreeSelectOptionValue,
67
+ OutlinedTreeSelectProps,
68
+ OutlinedTreeSelectValue
69
+ } from './OutlinedTreeSelect.types'
70
+
71
+ defineOptions({
72
+ name: 'OutlinedTreeSelect',
73
+ inheritAttrs: false
74
+ })
75
+
76
+ const props = withDefaults(defineProps<OutlinedTreeSelectProps>(), {
77
+ value: undefined,
78
+ data: () => [],
79
+ propsValue: undefined,
80
+ placeholder: '',
81
+ label: '',
82
+ disabled: false,
83
+ clearable: true,
84
+ filterable: true,
85
+ multiple: false,
86
+ showCheckbox: false,
87
+ checkStrictly: false,
88
+ checkOnClickNode: false,
89
+ defaultExpandAll: false,
90
+ expandOnClickNode: false,
91
+ renderAfterExpand: false,
92
+ collapseTags: false,
93
+ collapseTagsTooltip: true,
94
+ maxCollapseTags: 5,
95
+ popperClass: '',
96
+ nodeKey: 'value',
97
+ keyValue: 'value',
98
+ labelValue: 'label',
99
+ childrenValue: 'children',
100
+ disabledValue: 'disabled',
101
+ inputHeight: 40,
102
+ isBorder: false,
103
+ marginBottom: 20,
104
+ paddingTop: 20
105
+ })
106
+
107
+ const emit = defineEmits<{
108
+ (event: 'input', value: OutlinedTreeSelectValue | ''): void
109
+ (event: 'update:value', value: OutlinedTreeSelectValue | ''): void
110
+ (event: 'change', value: OutlinedTreeSelectValue | ''): void
111
+ (event: 'focus', value: FocusEvent): void
112
+ (event: 'blur', value: FocusEvent): void
113
+ (event: 'visible-change', value: boolean): void
114
+ (event: 'clear'): void
115
+ }>()
116
+
117
+ const attrs = useAttrs()
118
+ const treeSelectRef = ref<any>(null)
119
+ const treeSelectValue = ref<OutlinedTreeSelectValue | ''>(normalizeTreeSelectValue(props.value, isArrayMode()))
120
+ const focused = ref(false)
121
+ const blurred = ref(false)
122
+ const visible = ref(false)
123
+
124
+ watch(
125
+ () => [props.value, props.multiple, props.showCheckbox] as const,
126
+ ([value]) => {
127
+ treeSelectValue.value = normalizeTreeSelectValue(value, isArrayMode())
128
+ },
129
+ { immediate: true }
130
+ )
131
+
132
+ const rootClass = computed(() => attrs.class)
133
+ const rootStyle = computed(() => attrs.style)
134
+
135
+ const treeSelectAttrs = computed(() => {
136
+ const { class: _class, style: _style, ...rest } = attrs
137
+ return rest
138
+ })
139
+
140
+ const containerClasses = computed(() => ({
141
+ 'outlined-tree-select--bordered': props.isBorder
142
+ }))
143
+
144
+ const containerStyle = computed(() => ({
145
+ marginBottom: toCssValue(props.marginBottom),
146
+ paddingTop: toCssValue(props.paddingTop)
147
+ }))
148
+
149
+ const treeSelectStyle = computed(() => ({
150
+ minHeight: `${props.inputHeight}px`,
151
+ height: isArrayMode() ? 'auto' : `${props.inputHeight}px`
152
+ }))
153
+
154
+ const resolvedTreeProps = computed(() => {
155
+ if (props.propsValue) {
156
+ return props.propsValue
157
+ }
158
+
159
+ return {
160
+ value: props.keyValue,
161
+ label: props.labelValue,
162
+ children: props.childrenValue,
163
+ disabled: props.disabledValue
164
+ }
165
+ })
166
+
167
+ const floatingLabel = computed(() => props.label || props.placeholder || '')
168
+
169
+ const hasContent = computed(() => {
170
+ if (isArrayMode()) {
171
+ return Array.isArray(treeSelectValue.value) && treeSelectValue.value.length > 0
172
+ }
173
+
174
+ return hasFilledValue(treeSelectValue.value)
175
+ })
176
+
177
+ const labelClasses = computed(() => ({
178
+ 'outlined-tree-select__label--floating': focused.value || hasContent.value,
179
+ 'outlined-tree-select__label--placeholder': !focused.value && !hasContent.value,
180
+ 'outlined-tree-select__label--filled': hasContent.value && !focused.value
181
+ }))
182
+
183
+ function isArrayMode() {
184
+ return props.multiple || props.showCheckbox
185
+ }
186
+
187
+ function handleModelValueUpdate(value: OutlinedTreeSelectValue) {
188
+ const normalizedValue = normalizeTreeSelectValue(value, isArrayMode())
189
+ treeSelectValue.value = normalizedValue
190
+ emitModelValue(normalizedValue)
191
+ }
192
+
193
+ function handleChange(value: OutlinedTreeSelectValue) {
194
+ const normalizedValue = normalizeTreeSelectValue(value, isArrayMode())
195
+ treeSelectValue.value = normalizedValue
196
+ emit('change', normalizedValue)
197
+ }
198
+
199
+ function handleFocus(event: FocusEvent) {
200
+ blurred.value = false
201
+ focused.value = true
202
+ emit('focus', event)
203
+ }
204
+
205
+ function handleBlur(event: FocusEvent) {
206
+ blurred.value = true
207
+
208
+ if (!visible.value) {
209
+ focused.value = false
210
+ emitModelValue(treeSelectValue.value)
211
+ }
212
+
213
+ emit('blur', event)
214
+ }
215
+
216
+ function handleVisibleChange(nextVisible: boolean) {
217
+ visible.value = nextVisible
218
+
219
+ if (!nextVisible && blurred.value) {
220
+ focused.value = false
221
+ }
222
+
223
+ emit('visible-change', nextVisible)
224
+ }
225
+
226
+ function handleClear() {
227
+ emit('clear')
228
+ }
229
+
230
+ function emitModelValue(value: OutlinedTreeSelectValue | '') {
231
+ emit('input', value)
232
+ emit('update:value', value)
233
+ }
234
+
235
+ function normalizeTreeSelectValue(
236
+ value: OutlinedTreeSelectValue | undefined,
237
+ arrayMode: boolean
238
+ ): OutlinedTreeSelectValue | '' {
239
+ if (arrayMode) {
240
+ if (Array.isArray(value)) {
241
+ return value
242
+ }
243
+
244
+ if (value === undefined || value === null || value === '') {
245
+ return []
246
+ }
247
+
248
+ return [value as OutlinedTreeSelectOptionValue]
249
+ }
250
+
251
+ return value ?? ''
252
+ }
253
+
254
+ function hasFilledValue(value: unknown) {
255
+ return value !== undefined && value !== null && String(value) !== ''
256
+ }
257
+
258
+ function toCssValue(value: OutlinedTreeSelectCssValue | undefined) {
259
+ if (typeof value === 'number') {
260
+ return `${value}px`
261
+ }
262
+
263
+ return value
264
+ }
265
+
266
+ defineExpose<OutlinedTreeSelectExpose>({
267
+ focus: () => {
268
+ treeSelectRef.value?.focus?.()
269
+ },
270
+ blur: () => {
271
+ treeSelectRef.value?.blur?.()
272
+ },
273
+ clear: () => {
274
+ if (isArrayMode()) {
275
+ treeSelectValue.value = []
276
+ emitModelValue([])
277
+ emit('change', [])
278
+ emit('clear')
279
+ return
280
+ }
281
+
282
+ treeSelectValue.value = ''
283
+ emitModelValue('')
284
+ emit('change', '')
285
+ emit('clear')
286
+ },
287
+ getTreeSelectRef: () => treeSelectRef.value
288
+ })
289
+ </script>
290
+
291
+ <style scoped>
292
+ .outlined-tree-select {
293
+ position: relative;
294
+ }
295
+
296
+ .outlined-tree-select__label {
297
+ position: absolute;
298
+ left: -2px;
299
+ padding: 2px 5px;
300
+ border-radius: 2px;
301
+ background-color: #ffffff;
302
+ font-size: 12px;
303
+ line-height: 1;
304
+ transition: color 200ms cubic-bezier(0, 0, 0.2, 1), transform 200ms cubic-bezier(0, 0, 0.2, 1);
305
+ pointer-events: none;
306
+ }
307
+
308
+ .outlined-tree-select__label--floating {
309
+ top: 18px;
310
+ z-index: 1;
311
+ opacity: 1;
312
+ transform: translate(14px, -6px) scale(1);
313
+ color: var(--el-color-primary);
314
+ }
315
+
316
+ .outlined-tree-select__label--placeholder {
317
+ top: 50%;
318
+ left: 1px;
319
+ z-index: -1;
320
+ opacity: 0;
321
+ transform: translate(14px, 6px) scale(1);
322
+ }
323
+
324
+ .outlined-tree-select__label--filled {
325
+ color: var(--el-text-color-regular);
326
+ }
327
+
328
+ :deep(.outlined-tree-select__control.el-select) {
329
+ width: 100%;
330
+ }
331
+
332
+ :deep(.outlined-tree-select__control .el-select__wrapper) {
333
+ min-height: inherit;
334
+ height: inherit;
335
+ }
336
+
337
+ :deep(.outlined-tree-select__control .el-select__selection) {
338
+ min-height: inherit;
339
+ }
340
+
341
+ :deep(.outlined-tree-select__control .el-select__tags) {
342
+ padding-top: 4px;
343
+ }
344
+
345
+ :deep(.outlined-tree-select--bordered .el-select__wrapper) {
346
+ box-shadow: none;
347
+ border-radius: 0;
348
+ border-bottom: 1px solid #cccccc;
349
+ }
350
+
351
+ :deep(.outlined-tree-select--bordered .el-select__wrapper.is-focused) {
352
+ border-bottom-color: var(--el-color-primary);
353
+ }
354
+ </style>
@@ -0,0 +1,107 @@
1
+ # OutlinedTreeSelect
2
+
3
+ `OutlinedTreeSelect` 是 `OutlinedForm` 系列里的树形下拉选择控件,用来统一封装浮动标签、树节点字段映射、树面板显隐和常用树选择参数。
4
+
5
+ ## 适用场景
6
+
7
+ - 页面里需要在下拉框中选择组织树、区域树、节点树
8
+ - 需要统一 `el-tree-select` 的浮动标签样式
9
+ - 需要兼容自定义节点字段,比如 `id`、`name`、`children`
10
+ - 需要直接在页面层调用聚焦、清空等实例方法
11
+
12
+ ## 基本用法
13
+
14
+ ```vue
15
+ <script setup lang="ts">
16
+ import { ref } from 'vue'
17
+ import { OutlinedTreeSelect, type OutlinedTreeSelectExpose } from '@hbdlzy/ui'
18
+
19
+ const treeSelectRef = ref<OutlinedTreeSelectExpose | null>(null)
20
+ const parentId = ref('')
21
+
22
+ const treeData = [
23
+ {
24
+ id: 'north',
25
+ name: '华北',
26
+ children: [
27
+ { id: 'beijing', name: '北京节点' },
28
+ { id: 'tianjin', name: '天津节点' }
29
+ ]
30
+ }
31
+ ]
32
+ </script>
33
+
34
+ <template>
35
+ <OutlinedTreeSelect
36
+ ref="treeSelectRef"
37
+ v-model:value="parentId"
38
+ placeholder="选择父节点"
39
+ :data="treeData"
40
+ :props-value="{ value: 'id', label: 'name', children: 'children' }"
41
+ :check-strictly="true"
42
+ :is-border="true"
43
+ clearable
44
+ filterable
45
+ />
46
+ </template>
47
+ ```
48
+
49
+ ## Props
50
+
51
+ | 属性 | 类型 | 默认值 | 说明 |
52
+ | --- | --- | --- | --- |
53
+ | `value` | `string \| number \| boolean \| object \| Array<...>` | `undefined` | `v-model:value` 绑定值 |
54
+ | `data` | `OutlinedTreeSelectNode[]` | `[]` | 树节点数据 |
55
+ | `propsValue` | `Record<string, unknown>` | `undefined` | 透传给 `el-tree-select` 的 `props` |
56
+ | `placeholder` | `string` | `''` | 占位文案,也会作为浮动标签文案 |
57
+ | `label` | `string` | `''` | 自定义浮动标签文案,优先级高于 `placeholder` |
58
+ | `disabled` | `boolean` | `false` | 是否禁用 |
59
+ | `clearable` | `boolean` | `true` | 是否允许清空 |
60
+ | `filterable` | `boolean` | `true` | 是否允许搜索 |
61
+ | `multiple` | `boolean` | `false` | 是否多选 |
62
+ | `showCheckbox` | `boolean` | `false` | 是否显示树节点勾选框 |
63
+ | `checkStrictly` | `boolean` | `false` | 是否取消父子节点关联 |
64
+ | `checkOnClickNode` | `boolean` | `false` | 是否点击节点内容时选中 |
65
+ | `defaultExpandAll` | `boolean` | `false` | 是否默认展开所有节点 |
66
+ | `expandOnClickNode` | `boolean` | `false` | 是否点击节点展开树 |
67
+ | `renderAfterExpand` | `boolean` | `false` | 是否在展开后再渲染子节点 |
68
+ | `collapseTags` | `boolean` | `false` | 多选时是否折叠 tag |
69
+ | `collapseTagsTooltip` | `boolean` | `true` | 折叠 tag 时是否显示 tooltip |
70
+ | `maxCollapseTags` | `number` | `5` | 最多展示多少个折叠 tag |
71
+ | `popperClass` | `string` | `''` | 自定义弹层类名 |
72
+ | `nodeKey` | `string` | `'value'` | 树节点唯一标识字段 |
73
+ | `keyValue` | `string` | `'value'` | 默认值字段名 |
74
+ | `labelValue` | `string` | `'label'` | 默认标签字段名 |
75
+ | `childrenValue` | `string` | `'children'` | 默认子节点字段名 |
76
+ | `disabledValue` | `string` | `'disabled'` | 默认禁用字段名 |
77
+ | `inputHeight` | `number` | `40` | 输入框高度 |
78
+ | `isBorder` | `boolean` | `false` | 是否启用下边框风格 |
79
+ | `marginBottom` | `string \| number` | `20` | 外层下边距 |
80
+ | `paddingTop` | `string \| number` | `20` | 外层上内边距,用于浮动标签留白 |
81
+
82
+ ## Emits
83
+
84
+ | 事件 | 参数 | 说明 |
85
+ | --- | --- | --- |
86
+ | `input` | `OutlinedTreeSelectValue \| ''` | 输入值变化时触发 |
87
+ | `update:value` | `OutlinedTreeSelectValue \| ''` | `v-model:value` 同步事件 |
88
+ | `change` | `OutlinedTreeSelectValue \| ''` | 选项确认变化时触发 |
89
+ | `focus` | `FocusEvent` | 聚焦时触发 |
90
+ | `blur` | `FocusEvent` | 失焦时触发 |
91
+ | `visible-change` | `boolean` | 面板显隐变化时触发 |
92
+ | `clear` | 无 | 清空时触发 |
93
+
94
+ ## Expose
95
+
96
+ | 方法 | 说明 |
97
+ | --- | --- |
98
+ | `focus()` | 聚焦树选择控件 |
99
+ | `blur()` | 取消聚焦 |
100
+ | `clear()` | 清空当前值 |
101
+ | `getTreeSelectRef()` | 获取内部 `el-tree-select` 实例 |
102
+
103
+ ## 设计约束
104
+
105
+ - 组件只处理通用树选择壳子和交互状态,不直接耦合组织树接口、区域树接口等业务数据源
106
+ - 如果业务已经有固定的树字段协议,优先传 `propsValue`,不要在页面层二次转一份树数据
107
+ - 如果后续要支持领域级树选择行为,比如自动拼接父路径、限定层级,只建议在业务包里再封一层
@@ -0,0 +1,12 @@
1
+ import OutlinedTreeSelect from './OutlinedTreeSelect.vue'
2
+
3
+ export default OutlinedTreeSelect
4
+
5
+ export type {
6
+ OutlinedTreeSelectCssValue,
7
+ OutlinedTreeSelectExpose,
8
+ OutlinedTreeSelectNode,
9
+ OutlinedTreeSelectOptionValue,
10
+ OutlinedTreeSelectProps,
11
+ OutlinedTreeSelectValue
12
+ } from './OutlinedTreeSelect.types'
package/src/index.ts CHANGED
@@ -15,5 +15,19 @@ export { default as BaseEChart } from './components/BaseEChart'
15
15
  export * from './components/BaseEChart'
16
16
  export { default as BaseExportButton } from './components/BaseExportButton'
17
17
  export * from './components/BaseExportButton'
18
+ export { default as OutlinedInput } from './components/OutlinedInput'
19
+ export * from './components/OutlinedInput'
20
+ export { default as OutlinedSelect } from './components/OutlinedSelect'
21
+ export * from './components/OutlinedSelect'
22
+ export { default as OutlinedDatePicker } from './components/OutlinedDatePicker'
23
+ export * from './components/OutlinedDatePicker'
24
+ export { default as OutlinedDateTimePicker } from './components/OutlinedDateTimePicker'
25
+ export * from './components/OutlinedDateTimePicker'
26
+ export { default as OutlinedTimePicker } from './components/OutlinedTimePicker'
27
+ export * from './components/OutlinedTimePicker'
28
+ export { default as OutlinedCascader } from './components/OutlinedCascader'
29
+ export * from './components/OutlinedCascader'
30
+ export { default as OutlinedTreeSelect } from './components/OutlinedTreeSelect'
31
+ export * from './components/OutlinedTreeSelect'
18
32
  export { exportExcel } from './excel/exportExcel'
19
33
  export type { ExcelCellValue, ExcelExportColumn, ExcelExportOptions } from './excel/exportExcel'