Skip to content

Commit c3cd180

Browse files
authored
feat(comp: form): add controlTooltip,controlTooltipIcon,labelTooltipIcon props (#852)
1 parent 789a266 commit c3cd180

File tree

17 files changed

+169
-17
lines changed

17 files changed

+169
-17
lines changed

packages/components/config/src/defaultConfig.ts

+2
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ export const defaultConfig: GlobalConfig = {
106106
labelAlign: 'end',
107107
layout: 'horizontal',
108108
size: 'md',
109+
labelTooltipIcon: 'question-circle',
110+
controlTooltipIcon: 'info-circle',
109111
},
110112
icon: {},
111113
input: {

packages/components/config/src/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ export interface FormConfig {
202202
labelAlign: FormLabelAlign
203203
layout: FormLayout
204204
size: FormSize
205+
labelTooltipIcon: string
206+
controlTooltipIcon: string
205207
}
206208

207209
export interface IconConfig {

packages/components/form/__tests__/__snapshots__/form.spec.ts.snap

+8
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ exports[`Form > basic work > render work 1`] = `
1010
<div class=\\"ix-form-item-control-input\\">
1111
<div class=\\"ix-form-item-control-input-content\\"><input class=\\"ix-input ix-input-md\\"></div>
1212
<!---->
13+
<!---->
1314
</div>
1415
<!---->
1516
<!---->
@@ -23,6 +24,7 @@ exports[`Form > basic work > render work 1`] = `
2324
<div class=\\"ix-form-item-control-input\\">
2425
<div class=\\"ix-form-item-control-input-content\\"><input class=\\"ix-input ix-input-md\\"></div>
2526
<!---->
27+
<!---->
2628
</div>
2729
<!---->
2830
<!---->
@@ -39,6 +41,7 @@ exports[`Form > basic work > render work 1`] = `
3941
<!---->
4042
</label></div>
4143
<!---->
44+
<!---->
4245
</div>
4346
<!---->
4447
<!---->
@@ -50,6 +53,7 @@ exports[`Form > basic work > render work 1`] = `
5053
<div class=\\"ix-form-item-control-input\\">
5154
<div class=\\"ix-form-item-control-input-content\\"><button class=\\"ix-button ix-button-md\\" type=\\"button\\"><span>Click</span></button></div>
5255
<!---->
56+
<!---->
5357
</div>
5458
<!---->
5559
<!---->
@@ -67,6 +71,7 @@ exports[`Form > item work > render work 1`] = `
6771
<div class=\\"ix-form-item-control-input\\">
6872
<div class=\\"ix-form-item-control-input-content\\"><input class=\\"ix-input ix-input-md\\"></div>
6973
<!---->
74+
<!---->
7075
</div>
7176
<!---->
7277
<!---->
@@ -83,6 +88,7 @@ exports[`Form > wrapper work > render work 1`] = `
8388
<div class=\\"ix-form-item-control-input\\">
8489
<div class=\\"ix-form-item-control-input-content\\"><input class=\\"ix-input ix-input-md\\"></div>
8590
<!---->
91+
<!---->
8692
</div>
8793
<!---->
8894
<!---->
@@ -96,6 +102,7 @@ exports[`Form > wrapper work > render work 1`] = `
96102
<div class=\\"ix-form-item-control-input\\">
97103
<div class=\\"ix-form-item-control-input-content\\"><input class=\\"ix-input ix-input-md\\"></div>
98104
<!---->
105+
<!---->
99106
</div>
100107
<!---->
101108
<!---->
@@ -112,6 +119,7 @@ exports[`Form > wrapper work > render work 1`] = `
112119
<!---->
113120
</label></div>
114121
<!---->
122+
<!---->
115123
</div>
116124
<!---->
117125
<!---->

packages/components/form/__tests__/form.spec.ts

+72
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,35 @@ describe('Form', () => {
114114
expect(items[2].find('.ix-form-item-control').classes()).toContain('ix-col-span-8')
115115
})
116116

117+
test('labelTooltipIcon and controlTooltipIcon work', async () => {
118+
const wrapper = FormMount({
119+
props: {
120+
labelTooltipIcon: 'info',
121+
controlTooltipIcon: 'info',
122+
},
123+
slots: {
124+
default: () => [
125+
h(
126+
FormItem,
127+
{
128+
label: 'Username',
129+
labelTooltip: 'labelTooltip',
130+
labelTooltipIcon: 'up',
131+
controlTooltip: 'controlTooltip',
132+
controlTooltipIcon: 'up',
133+
},
134+
() => h(IxInput),
135+
),
136+
],
137+
},
138+
})
139+
140+
const items = wrapper.findAll('.ix-form-item')
141+
142+
expect(items[0].find('.ix-form-item-label .ix-icon').classes()).not.toContain('ix-icon-info')
143+
expect(items[0].find('.ix-form-item-control-input .ix-icon').classes()).not.toContain('ix-icon-info')
144+
})
145+
117146
test('labelAlign work', async () => {
118147
const wrapper = FormMount({
119148
props: { labelAlign: 'start' },
@@ -275,6 +304,36 @@ describe('Form', () => {
275304
expect(wrapper.find('.ix-form-item-control').classes()).toContain('ix-col-span-5')
276305
})
277306

307+
test('controlTooltip work', async () => {
308+
const wrapper = FormItemMount({
309+
props: { controlTooltip: 'controlTooltip' },
310+
slots: { default: () => h(IxInput) },
311+
})
312+
313+
expect(wrapper.find('.ix-form-item-control-tooltip').exists()).toBe(true)
314+
})
315+
316+
test('controlTooltip slot work', async () => {
317+
const wrapper = FormItemMount({
318+
slots: { default: () => h(IxInput), controlTooltip: () => 'controlTooltip slot' },
319+
})
320+
321+
expect(wrapper.find('.ix-form-item-control-tooltip').exists()).toBe(true)
322+
})
323+
324+
test('controlTooltipIcon work', async () => {
325+
const wrapper = FormItemMount({
326+
props: { controlTooltip: 'controlTooltip', controlTooltipIcon: 'info-circle' },
327+
slots: { default: () => h(IxInput) },
328+
})
329+
330+
expect(wrapper.find('.ix-form-item-control-tooltip .ix-icon-info-circle').exists()).toBe(true)
331+
332+
await wrapper.setProps({ controlTooltipIcon: 'up' })
333+
334+
expect(wrapper.find('.ix-form-item-control-tooltip .ix-icon-up').exists()).toBe(true)
335+
})
336+
278337
test('extraMessage work', async () => {
279338
let extraMessage = 'extraMessage'
280339
const wrapper = FormItemMount({
@@ -382,6 +441,19 @@ describe('Form', () => {
382441
expect(wrapper.find('.ix-form-item-label-tooltip').exists()).toBe(true)
383442
})
384443

444+
test('labelTooltipIcon work', async () => {
445+
const wrapper = FormItemMount({
446+
props: { label: 'Username', labelTooltip: 'labelTooltipIcon', labelTooltipIcon: 'info-circle' },
447+
slots: { default: () => h(IxInput) },
448+
})
449+
450+
expect(wrapper.find('.ix-form-item-label-tooltip .ix-icon-info-circle').exists()).toBe(true)
451+
452+
await wrapper.setProps({ labelTooltipIcon: 'up' })
453+
454+
expect(wrapper.find('.ix-form-item-label-tooltip .ix-icon-up').exists()).toBe(true)
455+
})
456+
385457
test('required work', async () => {
386458
const wrapper = FormItemMount({
387459
props: { label: 'Username', required: true },

packages/components/form/docs/Index.zh.md

+7
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ order: 0
1717
| `colonless` | 配置 `IxFormItem``colon` 默认值 | `boolean` | `false` || - |
1818
| `control` | 表单的控制器 | `string \| number \| AbstractControl` | - | - | 通常是配合 `useFormGroup` 使用 |
1919
| `controlCol` | 配置 `IxFormItem``controlCol` 默认值 | `number \| ColProps` | - | - | - |
20+
| `controlTooltipIcon` | 配置表单控件的提示信息icon | `string` | `'info-circle'` || - |
2021
| `labelAlign` | 配置 `IxFormItem``labelAlign` 默认值 | `'start' \| 'end'` | `'end'` || - |
2122
| `labelCol` | 配置 `IxFormItem``labelCol` 默认值 | `number \| ColProps` | - | - | - |
23+
| `labelTooltipIcon` | 配置表单文本的提示信息icon | `string` | `'question-circle'` || - |
2224
| `layout` | 表单布局 | `'horizontal' \| 'vertical' \| 'inline'` | `'horizontal'` || - |
2325
| `size` | 表单大小 | `'sm' \| 'md' \| 'lg'` | `'md'` || - |
2426
| `statusIcon` | 配置 `IxFormItem``statusIcon` 默认值 | `boolean \| Record<ValidateStatus, string>` | `false` | - | - |
@@ -37,12 +39,14 @@ order: 0
3739
| `control` | 表单控件的控制器 | `string \| number \| AbstractControl` | - | - | 默认取第 1 个子输入控件的 control,如果存在多个输入控件,建议手动指定,参考示例中的 `Phone Number`|
3840
| `controlCol` | 配置表单控件的布局配置,可参考 `IxCol` 组件 | `number \| ColProps` | - | - | 传入 `string` 或者 `number` 时,为 `IxCol``span` 配置 |
3941
| `controlTooltip` | 配置表单控件的提示信息 | `string \| #controlTooltip` | - | - | 通常用于对输入规则的详细说明 |
42+
| `controlTooltipIcon` | 配置表单控件的提示信息icon | `string` | - | - | - |
4043
| `extraMessage` | 额外的提示信息 | `string \| #extraMessage` | - | - | 当需要错误信息和提示文案同时出现时使用 |
4144
| `label` | `label` 标签的文本| `string \| #label` | - | - | - |
4245
| `labelAlign` | `label` 标签文本对齐方式 | `'start' \| 'end'` | - | - | - |
4346
| `labelCol` | `label` 标签布局配置,可参考 `IxCol` 组件 | `number \| ColProps` | - | - | 传入 `string` 或者 `number` 时,为 `IxCol``span` 配置 |
4447
| `labelFor` | `label` 标签的 `for` 属性 | `string` | - | - | - |
4548
| `labelTooltip` | 配置表单文本的提示信息 | `string \| #labelTooltip` | - | - | 通常用于对表单本文的解释说名 |
49+
| `labelTooltipIcon` | 配置表单文本的提示信息icon | `string` | - | -| - |
4650
| `required` | 必填样式设置 | `boolean` | `false` | - | 仅控制样式 |
4751
| `message` | 手动指定表单项的校验提示 | `string \| (control?: AbstractControl) => string \| FormValidateMessage` | - | - | 传入 `string` 时,为 `invalid` 状态的提示 |
4852
| `status` | 手动指定表单项的校验状态 | `valid \| invalid \| validating` | - | - | - |
@@ -165,4 +169,7 @@ export default defineComponent({
165169
| `@form-item-label-colon-margin-left` | `2px` | - | - |
166170
| `@form-item-label-margin-left` | `8px` | - | - |
167171
| `@form-item-label-before-content-left` | `-8px` | - | - |
172+
| `@form-item-tooltip-icon-font-size` | `@font-size-lg` | - | - |
173+
| `@form-item-tooltip-icon-color` | `@color-primary-l10` | - | - |
174+
| `@form-item-control-tooltip-right` | `-(@form-item-tooltip-icon-font-size + 4)` | - | - |
168175
<!--- insert less variable end --->

packages/components/form/src/FormItem.tsx

+17-7
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,13 @@ export default defineComponent({
3030
const colonless = computed(() => props.colonless ?? formProps?.colonless ?? config?.colonless)
3131
const labelAlign = computed(() => props.labelAlign ?? formProps?.labelAlign ?? config?.labelAlign)
3232
const labelColConfig = computed(() => normalizeColConfig(props.labelCol ?? formProps?.labelCol))
33+
const labelTooltipIcon = computed(
34+
() => props.labelTooltipIcon ?? formProps?.labelTooltipIcon ?? config?.labelTooltipIcon,
35+
)
3336
const controlColConfig = computed(() => normalizeColConfig(props.controlCol ?? formProps?.controlCol))
37+
const controlTooltipIcon = computed(
38+
() => props.controlTooltipIcon ?? formProps?.controlTooltipIcon ?? config?.controlTooltipIcon,
39+
)
3440
const { status, statusIcon, message } = useFormItem(props, formProps)
3541

3642
const classes = computed(() => {
@@ -58,8 +64,8 @@ export default defineComponent({
5864
const prefixCls = mergedPrefixCls.value
5965
return (
6066
<IxRow class={classes.value}>
61-
{renderLabel(props, slots, labelClasses, labelColConfig, prefixCls)}
62-
{renderControl(props, slots, controlColConfig, statusIcon, message, prefixCls)}
67+
{renderLabel(props, slots, labelClasses, labelColConfig, labelTooltipIcon, prefixCls)}
68+
{renderControl(props, slots, controlColConfig, controlTooltipIcon, statusIcon, message, prefixCls)}
6369
</IxRow>
6470
)
6571
}
@@ -75,14 +81,15 @@ function renderLabel(
7581
slots: Slots,
7682
classes: ComputedRef<string>,
7783
labelColConfig: ComputedRef<ColProps | undefined>,
84+
labelTooltipIcon: ComputedRef<string | undefined>,
7885
prefixCls: string,
7986
) {
8087
const { label, labelFor, labelTooltip } = props
8188
const { label: labelSlot, labelTooltip: labelTooltipSlot } = slots
8289
if (!(label || labelSlot)) {
8390
return undefined
8491
}
85-
const tooltipNode = renderTooltip(labelTooltipSlot, labelTooltip)
92+
const tooltipNode = renderTooltip(labelTooltipSlot, labelTooltip, labelTooltipIcon.value)
8693
return (
8794
<IxCol class={classes.value} {...labelColConfig.value}>
8895
<label for={labelFor}>
@@ -97,12 +104,13 @@ function renderControl(
97104
props: FormItemProps,
98105
slots: Slots,
99106
controlColConfig: ComputedRef<ColProps | undefined>,
107+
controlTooltipIcon: ComputedRef<string | undefined>,
100108
statusIcon: ComputedRef<string | undefined>,
101109
message: ComputedRef<string | undefined>,
102110
prefixCls: string,
103111
) {
104-
const { extra, extraMessage } = props
105-
const { extra: extraSlot, extraMessage: extraMessageSlot } = slots
112+
const { controlTooltip, extra, extraMessage } = props
113+
const { controlTooltip: controlTooltipSlot, extra: extraSlot, extraMessage: extraMessageSlot } = slots
106114
if (__DEV__ && (extra || extraSlot)) {
107115
Logger.warn('components/form', '`extra` was deprecated, please use `extraMessage` instead.')
108116
}
@@ -114,26 +122,28 @@ function renderControl(
114122
const messageNode = message.value && <div class={`${prefixCls}-message`}>{message.value}</div>
115123
const extraNode = extraSlot ? extraSlot() : extraMessageSlot ? extraMessageSlot() : extra || extraMessage
116124
const extraWrapper = extraNode && <div class={`${prefixCls}-extra-message`}>{extraNode}</div>
125+
const tooltipNode = renderTooltip(controlTooltipSlot, controlTooltip, controlTooltipIcon.value)
117126
return (
118127
<IxCol class={`${prefixCls}-control`} {...controlColConfig.value}>
119128
<div class={`${prefixCls}-control-input`}>
120129
<div class={`${prefixCls}-control-input-content`}>{slots.default && slots.default()}</div>
121130
{statusNode}
131+
{tooltipNode && <span class={`${prefixCls}-control-tooltip`}>{tooltipNode}</span>}
122132
</div>
123133
{messageNode}
124134
{extraWrapper}
125135
</IxCol>
126136
)
127137
}
128138

129-
function renderTooltip(slot: Slot | undefined, tooltip: string | undefined) {
139+
function renderTooltip(slot: Slot | undefined, tooltip: string | undefined, iconName: string | undefined) {
130140
if (slot) {
131141
return slot()
132142
}
133143
return (
134144
tooltip && (
135145
<IxTooltip title={tooltip}>
136-
<IxIcon name="question-circle" />
146+
<IxIcon name={iconName} />
137147
</IxTooltip>
138148
)
139149
)

packages/components/form/src/types.ts

+5
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ export const formProps = {
1919
control: controlPropDef,
2020
colonless: IxPropTypes.bool,
2121
controlCol: colProp,
22+
controlTooltipIcon: IxPropTypes.string,
2223
hasFeedback: IxPropTypes.bool,
2324
labelAlign: IxPropTypes.oneOf<FormLabelAlign>(['start', 'end']),
2425
labelCol: colProp,
26+
labelTooltipIcon: IxPropTypes.string,
2527
layout: IxPropTypes.oneOf<FormLayout>(['horizontal', 'vertical', 'inline']),
2628
size: IxPropTypes.oneOf<FormSize>(['lg', 'md', 'sm']),
2729
statusIcon: IxPropTypes.oneOfType([Boolean, IxPropTypes.object<Record<ValidateStatus, string>>()]).def(false),
@@ -42,6 +44,8 @@ export const formItemProps = {
4244
colonless: IxPropTypes.bool,
4345
control: controlPropDef,
4446
controlCol: colProp,
47+
controlTooltip: IxPropTypes.string,
48+
controlTooltipIcon: IxPropTypes.string,
4549
hasFeedback: IxPropTypes.bool,
4650
extra: IxPropTypes.string,
4751
extraMessage: IxPropTypes.string,
@@ -50,6 +54,7 @@ export const formItemProps = {
5054
labelCol: colProp,
5155
labelFor: IxPropTypes.string,
5256
labelTooltip: IxPropTypes.string,
57+
labelTooltipIcon: IxPropTypes.string,
5358
required: IxPropTypes.bool.def(false),
5459
message: IxPropTypes.oneOfType([
5560
String,

packages/components/form/style/index.less

+16-1
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,13 @@
7070
}
7171

7272
&-tooltip {
73-
color: @form-color-secondary;
7473
cursor: help;
7574
writing-mode: horizontal-tb;
7675
margin-inline-start: @spacing-xs;
76+
.@{icon-prefix} {
77+
font-size: @form-item-tooltip-icon-font-size;
78+
color: @form-item-tooltip-icon-color;
79+
}
7780
}
7881
}
7982

@@ -92,6 +95,18 @@
9295
max-width: 100%;
9396
}
9497
}
98+
99+
&-tooltip {
100+
position: absolute;
101+
right: @form-item-control-tooltip-right;
102+
top: 50%;
103+
transform: translateY(-50%);
104+
writing-mode: horizontal-tb;
105+
.@{icon-prefix} {
106+
font-size: @form-item-tooltip-icon-font-size;
107+
color: @form-item-tooltip-icon-color;
108+
}
109+
}
95110
}
96111

97112
&-message,

packages/components/form/style/themes/default.variable.less

+4
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,7 @@
6262
@form-item-label-colon-margin-left: 2px;
6363
@form-item-label-margin-left: 8px;
6464
@form-item-label-before-content-left: -8px;
65+
66+
@form-item-tooltip-icon-font-size: @font-size-lg;
67+
@form-item-tooltip-icon-color: @color-primary-l10;
68+
@form-item-control-tooltip-right: -(@form-item-tooltip-icon-font-size + 4);

packages/components/message/docs/Index.zh.md

+5
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,9 @@ export interface MessageRef {
114114
| `@message-icon-margin-right` | `@spacing-sm` | - | - |
115115
| `@message-wrapper-top` | `15%` | - | - |
116116
| `@message-wrapper-zindex` | `@zindex-l4-1` | - | - |
117+
| `@message-icon-info-color` | `@color-info-l10` | - | - |
118+
| `@message-icon-success-color` | `@color-success` | - | - |
119+
| `@message-icon-warning-color` | `@color-warning-l10` | - | - |
120+
| `@message-icon-error-color` | `@color-error-l10` | - | - |
121+
| `@message-icon-loading-color` | `@color-primary-l10` | - | - |
117122
<!--- insert less variable end --->

packages/components/message/style/index.less

+5-5
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@
3131
}
3232
}
3333

34-
.message-icon-color(info, @color-info);
35-
.message-icon-color(success, @color-success);
36-
.message-icon-color( warning, @color-warning-l10);
37-
.message-icon-color(error, @color-error);
38-
.message-icon-color(loading, @color-primary);
34+
.message-icon-color(info, @message-icon-info-color);
35+
.message-icon-color(success, @message-icon-success-color);
36+
.message-icon-color( warning, @message-icon-warning-color);
37+
.message-icon-color(error, @message-icon-error-color);
38+
.message-icon-color(loading, @message-icon-loading-color);
3939

4040
&-wrapper {
4141
position: fixed;

0 commit comments

Comments
 (0)