跳转到内容

Editable 就地编辑 ​

用于在当前位置查看和编辑短文本。

用法 ​

点击文本就地编辑

曦寒

组件结构 ​

加粗的是必需部件。

data-scope="editable":root · label · control · preview · input · edit-trigger · submit-trigger · cancel-trigger

示例 ​

提交方式 ​

使用失焦或回车提交

失焦即提交
回车才提交

状态 ​

禁用、只读与空值

改不动
只能看
未填写

变体 ​

设置编辑框外观

曦寒
曦寒
曦寒

设计指引 ​

何时使用 ​

  • 编辑标题、昵称或简短备注。
  • 在列表和表格中快速修改单个值。

何时不用 ​

  • 一次修改多个字段时,使用表单或对话框。
  • 值需要复杂校验或多步确认。

特性 ​

  • submitMode 设置回车、失焦或显式按钮提交。
  • activationMode 设置单击、双击或按钮激活。
  • 支持提交、取消、受控值和受控编辑状态。
  • autoResize 让输入框随内容调整宽度。
  • 标题在上;预览文字或输入框与右侧动作组共用一个字段边框和背景,不把动作按钮挂在编辑框外。预览态只显示编辑按钮,编辑态只显示确认与取消按钮。
  • 三个动作使用图标呈现:编辑、确认、取消;图标按钮必须提供可访问名称。

组合 ​

最佳实践 ​

  • 为展示态提供清晰的可编辑提示。
  • 保持预览态和编辑态高度一致。
  • 保留 Escape 取消并还原原值。
  • 使用空按钮时由皮肤绘制默认图标,并通过 aria-label 写明编辑、确认与取消。

反模式 ​

  • 使用失焦提交但不提供取消方式。
  • 用就地编辑处理长文本或复杂表单。

API 参考 ​

产物 ​

层值
自定义元素<xh-editable>
Vue 组件XhEditableCancelTrigger XhEditableControl XhEditableEditTrigger XhEditableInput XhEditableLabel XhEditablePreview XhEditableRoot XhEditableSubmitTrigger
组合式函数useEditable
状态机editableMachine
皮肤@xihan-ui/styles/editable.css

Props ​

属性类型必填说明
valuestring受控值;提供后由宿主决定,状态机不自行修改(cell 原生受控,无影子事件)。
defaultValuestring非受控初值。
editboolean受控编辑态;提供后由宿主决定,用户交互只发 onEditChange。
defaultEditboolean非受控初始编辑态。为真时挂载即进入编辑态并把焦点移入输入框。
placeholderstring值为空时预览区显示它,输入框也将其用作占位。
disabledboolean禁用:无法进入编辑态,输入框带原生 disabled。
readOnlyboolean只读:无法进入编辑态,但已在编辑态时仍能退出(撤销 / 提交都可用)。
invalidboolean校验失败标注。
maxLengthnumber字符数上限;同时落为原生 maxlength 与状态机侧截断。
namestring表单字段名;提供后输入框才参与提交。
submitModeEditableSubmitMode编辑态的收尾方式,默认 both。
activationModeEditableActivationMode预览区的激活方式,默认 click。
selectOnFocusboolean进入编辑态时全选已有内容,默认开启。关闭则光标停在原处。
autoResizeboolean输入框宽度跟随内容:连接层把字符数写为原生 size 属性。
variantControlVariant形态:outline / subtle / ghost,决定底色与描边的绘制方式。默认 outline。
toneTone语气:brand / neutral / success / warning / danger / info,决定 control 的聚焦描边与焦点环颜色。
sizeSize尺寸:sm / md / lg,决定 control、预览区、输入框与三个动作按钮的几何档位。
onValueChange(details: EditableValueChangeDetails) => void值变化意图回调;编辑途中每次输入都发出,受控时是唯一出口。
onValueCommit(details: EditableValueCommitDetails) => void提交时才发出;编辑途中的输入不触发它。
onValueRevert(details: EditableValueRevertDetails) => void撤销时发出(Escape、取消按钮、不视为提交的离场)。
onEditChange(details: EditableEditChangeDetails) => void编辑态变化意图回调;受控时是唯一出口,非受控时随内部转移一并通知。

事件 ​

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
value-changeEditableValueChangeDetails编辑途中的值变化;detail 为 { value: string }
value-commitEditableValueCommitDetails提交;detail 为 { value: string, previousValue: string }
value-revertEditableValueRevertDetails撤销;detail 为 { value: string, discardedValue: string }
edit-changeEditableEditChangeDetails编辑态变化;detail 为 { edit: boolean }

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhEditableRootdefaultEditableRootSlotProps

React 适配器 props ​

只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。

React 组件属性类型必填说明
XhEditableRootchildrenSlotChildren<EditableRootSlotProps>

状态 ​

公开状态写入 data-state。

部件取值
root'edit' | 'preview'
label'edit' | 'preview'
control'edit' | 'preview'
preview'edit' | 'preview'
input'edit' | 'preview'
edit-trigger'edit' | 'preview'
submit-trigger'edit' | 'preview'
cancel-trigger'edit' | 'preview'

以下名称仅用于内部状态机。

状态:preview · edit

事件:EDIT.START · EDIT.SUBMIT · EDIT.CANCEL · EDIT.LEAVE · VALUE.SET · CONTROLLED.EDIT · CONTROLLED.PREVIEW · FORM.RESET · PRESS.START · PRESS.END

判据:isEditControlled · canEdit · submitsOnLeave · canPressEditTrigger · canPressEditControls

connect API ​

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
valuestring当前的值(编辑途中即输入框中的内容)。
committedValuestring上一次提交的值,也是撤销的落点。
editingboolean处于编辑态。
emptyboolean值为空串。
displayValuestring预览区当前应显示的文字:值为空时回退为 placeholder。
disabledboolean
readOnlyboolean
invalidboolean
interactiveboolean可以进入编辑态(既未禁用也不只读)。
setValue(next: string) => void直接写值,只受 disabled / readOnly 与 maxLength 约束,与编辑态无关。
edit() => void进入编辑态;禁用或只读时不生效。
submit() => void提交当前的值并回到预览态。
cancel() => void撤销回上一次提交的值并回到预览态。
getRootProps() => T['element']
getLabelProps() => T['label']
getPreviewProps() => T['element']
getInputProps() => T['input']
getEditTriggerProps() => T['button']
getSubmitTriggerProps() => T['button']
getCancelTriggerProps() => T['button']
getControlProps() => T['element']

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
Enterfocus in input, submitMode 为 enter 或 both提交当下的值并回到预览态;其余模式不接管该键,交回给浏览器与外层表单
Escapefocus in input撤销回上一次提交的值并回到预览态
Tab / Shift+Tabfocus in input按 submitMode 收尾(blur/both 提交,enter/none 撤销);不拦默认行为,焦点照常移出
Enter / Spaceheld on edit-trigger(预览态,not disabled/readOnly)或 submit-trigger / cancel-trigger(编辑态)按住期间这颗钮投影 data-pressed,与指针 :active 同一副按压面;抬起或失焦撤下,进出编辑态后按钮藏起一并撤下

ARIA ​

以下属性由 connect 生成。

部件属性值
rootaria-labelledbylabel 部件的 id
rootrole'group'
previewaria-disabled'true' | 'false'
inputaria-invalid'true' | 'false'
inputaria-labelledbylabel 部件的 id
edit-triggeraria-controlsinput 部件的 id

样式参考 ​

皮肤 ​

@xihan-ui/styles/editable.css 使用 [data-scope="editable"][data-part="root"] 部件选择器,位于 xihan.components 层。覆盖样式使用 xihan.overrides。

forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。

数据属性 ​

由 connect 生成;条件不成立时不输出无值属性。

部件属性值
rootdata-disabled''(条件成立时才出现)
rootdata-empty''(条件成立时才出现)
rootdata-invalid''(条件成立时才出现)
rootdata-readonly''(条件成立时才出现)
rootdata-sizeprops.size
rootdata-state'edit' | 'preview'
rootdata-toneprops.tone
rootdata-variantprops.variant
labeldata-disabled''(条件成立时才出现)
labeldata-state'edit' | 'preview'
controldata-disabled''(条件成立时才出现)
controldata-invalid''(条件成立时才出现)
controldata-readonly''(条件成立时才出现)
controldata-state'edit' | 'preview'
controldata-variantprops.variant
controldata-xh-field-chrome''
controldata-xh-field-sizeprops.size
previewdata-activation-modeprops.activationMode
previewdata-disabled''(条件成立时才出现)
previewdata-invalid''(条件成立时才出现)
previewdata-placeholder''(条件成立时才出现)
previewdata-readonly''(条件成立时才出现)
previewdata-state'edit' | 'preview'
inputdata-auto-resize''(条件成立时才出现)
inputdata-disabled''(条件成立时才出现)
inputdata-invalid''(条件成立时才出现)
inputdata-readonly''(条件成立时才出现)
inputdata-state'edit' | 'preview'
inputdata-xh-field-input''
inputdata-xh-field-layout'single-line'
edit-triggerdata-disabled''(条件成立时才出现)
edit-triggerdata-pressed''(条件成立时才出现)
edit-triggerdata-state'edit' | 'preview'
edit-triggerdata-xh-action-control''
edit-triggerdata-xh-action-display'always'
edit-triggerdata-xh-action-profile'field-inset'
edit-triggerdata-xh-action-sizeprops.size
edit-triggerdata-xh-action-variant'ghost'
submit-triggerdata-disabled''(条件成立时才出现)
submit-triggerdata-pressed''(条件成立时才出现)
submit-triggerdata-state'edit' | 'preview'
submit-triggerdata-xh-action-control''
submit-triggerdata-xh-action-display'always'
submit-triggerdata-xh-action-profile'field-inset'
submit-triggerdata-xh-action-sizeprops.size
submit-triggerdata-xh-action-variant'ghost'
cancel-triggerdata-disabled''(条件成立时才出现)
cancel-triggerdata-pressed''(条件成立时才出现)
cancel-triggerdata-state'edit' | 'preview'
cancel-triggerdata-xh-action-control''
cancel-triggerdata-xh-action-display'always'
cancel-triggerdata-xh-action-profile'field-inset'
cancel-triggerdata-xh-action-sizeprops.size
cancel-triggerdata-xh-action-variant'ghost'

CSS 变量 ​

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-editable-control-bgcontrolbackground-colorxh-field-chrome--xh-_field-variant-bg-resteditable 的 control 部件 background-color 覆盖槽。
--xh-editable-control-bg-disabledcontrolbackground-colordisabled
xh-field-chrome
--xh-_field-variant-bg-disablededitable 的 control 部件 background-color 覆盖槽。
--xh-editable-control-bg-hovercontrolbackground-colordisabled
hover
invalid
loading
not([data-disabled])
not([data-invalid])
not([data-loading])
not([data-readonly])
readonly
xh-field-chrome
--xh-_field-variant-bg-hovereditable 的 control 部件 background-color 覆盖槽。
--xh-editable-control-bg-readonlycontrolbackground-colorreadonly
xh-field-chrome
--xh-_field-variant-bg-read-onlyeditable 的 control 部件 background-color 覆盖槽。
--xh-editable-control-bordercontrolborderxh-field-chrome--xh-_field-variant-border-resteditable 的 control 部件 border 覆盖槽。
--xh-editable-control-border-disabledcontrolborder-colordisabled
xh-field-chrome
--xh-_field-variant-border-disablededitable 的 control 部件 border-color 覆盖槽。
--xh-editable-control-border-focuscontrolborder-colordisabled
focus-within
not([data-disabled])
xh-field-chrome
--xh-_field-variant-border-focuseditable 的 control 部件 border-color 覆盖槽。
--xh-editable-control-border-hovercontrolborder-colordisabled
hover
invalid
loading
not([data-disabled])
not([data-invalid])
not([data-loading])
not([data-readonly])
readonly
xh-field-chrome
--xh-_field-variant-border-hovereditable 的 control 部件 border-color 覆盖槽。
--xh-editable-control-border-invalidcontrolborder-colorinvalid
xh-field-chrome
--xh-_field-variant-border-invalideditable 的 control 部件 border-color 覆盖槽。
--xh-editable-control-fgcontrolcolorxh-field-chrome--xh-fg-defaulteditable 的 control 部件 color 覆盖槽。
--xh-editable-control-gapcontrolgapxh-field-chrome--xh-_editable-control-gapeditable 的 control 部件 gap 覆盖槽。
--xh-editable-control-hcontrolblock-size
min-block-size
has([data-xh-field-input][data-xh-field-layout='multi-tag'])
has([data-xh-field-input][data-xh-field-layout='single-line'])
has([data-xh-field-input][data-xh-field-layout='textarea'])
xh-field-chrome
xh-field-input
xh-field-layout=multi-tag
xh-field-layout=single-line
xh-field-layout=textarea
--xh-_editable-heditable 的 control 部件 block-size、min-block-size 覆盖槽。
--xh-editable-control-min-wcontrol
root
min-inline-sizedefault
xh-field-chrome
--xh-control-min-weditable 的 control、root 部件 min-inline-size 覆盖槽。
--xh-editable-control-pxcontrolpadding-inlinexh-field-chrome0editable 的 control 部件 padding-inline 覆盖槽。
--xh-editable-control-radiuscontrolborder-radiusxh-field-chrome--xh-shape-controleditable 的 control 部件 border-radius 覆盖槽。
--xh-editable-control-shadowcontrolbox-shadowxh-field-chromenoneeditable 的 control 部件 box-shadow 覆盖槽。
--xh-editable-control-wrootinline-size
min-inline-size
default--xh-control-weditable 的 root 部件 inline-size、min-inline-size 覆盖槽。
--xh-editable-gaprootgapdefault--xh-space-1editable 的 root 部件 gap 覆盖槽。
--xh-editable-icon-sizecontrol
root
--xh-icon-sizedefault
size=lg
size=sm
xh-field-chrome
--xh-_field-size-glyph-size
--xh-glyph-size-lg
--xh-glyph-size-md
--xh-glyph-size-sm
editable 的 control、root 部件 --xh-icon-size 覆盖槽。
--xh-editable-input-autofill-bginputbox-shadow-webkit-autofill
autofill
xh-field-input
--xh-bg-canvaseditable 的 input 部件 box-shadow 覆盖槽。
--xh-editable-input-autofill-fginput-webkit-text-fill-color-webkit-autofill
autofill
xh-field-input
--xh-fg-defaulteditable 的 input 部件 -webkit-text-fill-color 覆盖槽。
--xh-editable-input-fginputcolorxh-field-input--xh-fg-defaulteditable 的 input 部件 color 覆盖槽。
--xh-editable-input-font-sizeinputfont-sizexh-field-input--xh-_editable-font-sizeeditable 的 input 部件 font-size 覆盖槽。
--xh-editable-input-pxinputpadding-inlinedefault--xh-_editable-pxeditable 的 input 部件 padding-inline 覆盖槽。
--xh-editable-label-fglabelcolordefault--xh-fg-defaulteditable 的 label 部件 color 覆盖槽。
--xh-editable-label-fg-disabledlabelcolordisabled--xh-fg-subtleeditable 的 label 部件 color 覆盖槽。
--xh-editable-label-font-sizelabelfont-sizedefault--xh-text-label-sizeeditable 的 label 部件 font-size 覆盖槽。
--xh-editable-label-font-weightlabelfont-weightdefault--xh-text-label-weighteditable 的 label 部件 font-weight 覆盖槽。
--xh-editable-placeholder-fginput
preview
colorplaceholder
xh-field-input
--xh-fg-subtleeditable 的 input、preview 部件 color 覆盖槽。
--xh-editable-preview-fgpreviewcolordefault--xh-fg-defaulteditable 的 preview 部件 color 覆盖槽。
--xh-editable-preview-font-sizepreviewfont-sizedefault--xh-_editable-font-sizeeditable 的 preview 部件 font-size 覆盖槽。
--xh-editable-preview-min-hpreviewmin-block-sizedefault--xh-_editable-heditable 的 preview 部件 min-block-size 覆盖槽。
--xh-editable-preview-pxpreviewpadding-inlinedefault--xh-_editable-pxeditable 的 preview 部件 padding-inline 覆盖槽。
--xh-editable-trigger-bgcancel-trigger
edit-trigger
submit-trigger
--xh-ink-surface
background-color
default
xh-ink-surface
--xh-_action-variant-bg-resteditable 的 cancel-trigger、edit-trigger、submit-trigger 部件 --xh-ink-surface、background-color 覆盖槽。
--xh-editable-trigger-bg-activecancel-trigger
edit-trigger
submit-trigger
background-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-bg-pressededitable 的 cancel-trigger、edit-trigger、submit-trigger 部件 background-color 覆盖槽。
--xh-editable-trigger-bg-disabledcancel-trigger
edit-trigger
submit-trigger
--xh-ink-surface
background-color
disabled
xh-ink-surface
--xh-_action-variant-bg-disablededitable 的 cancel-trigger、edit-trigger、submit-trigger 部件 --xh-ink-surface、background-color 覆盖槽。
--xh-editable-trigger-bg-hovercancel-trigger
edit-trigger
submit-trigger
background-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hovereditable 的 cancel-trigger、edit-trigger、submit-trigger 部件 background-color 覆盖槽。
--xh-editable-trigger-divideredit-trigger
submit-trigger
background-imagedefault--xh-material-soft-separatoreditable 的 edit-trigger、submit-trigger 部件 background-image 覆盖槽。
--xh-editable-trigger-divider-hedit-trigger
submit-trigger
background-sizedefault--xh-_editable-divider-heditable 的 edit-trigger、submit-trigger 部件 background-size 覆盖槽。
--xh-editable-trigger-fgcancel-trigger
edit-trigger
submit-trigger
colordefault--xh-fg-defaulteditable 的 cancel-trigger、edit-trigger、submit-trigger 部件 color 覆盖槽。
--xh-editable-trigger-fg-hovercancel-trigger
edit-trigger
submit-trigger
colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-fg-defaulteditable 的 cancel-trigger、edit-trigger、submit-trigger 部件 color 覆盖槽。
--xh-editable-trigger-font-sizecancel-trigger
edit-trigger
submit-trigger
font-sizedefault--xh-text-secondary-sizeeditable 的 cancel-trigger、edit-trigger、submit-trigger 部件 font-size 覆盖槽。
--xh-editable-trigger-radiuscancel-trigger
edit-trigger
submit-trigger
border-radiusdefault--xh-shape-inseteditable 的 cancel-trigger、edit-trigger、submit-trigger 部件 border-radius 覆盖槽。
--xh-editable-trigger-sizecancel-trigger
edit-trigger
submit-trigger
block-size
inline-size
min-inline-size
default
xh-action-profile=field-inset
--xh-_action-profile-visual-sizeeditable 的 cancel-trigger、edit-trigger、submit-trigger 部件 block-size、inline-size、min-inline-size 覆盖槽。

动效 ​

动效角色:按压 · 状态(见动效规范)。

本组件皮肤不含过渡与关键帧,也没有脚本驱动的动效:状态一变,外观立即到位。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像;另有按 dir 分支的规则。

Released under The MIT License