@varlet/ui 3.0.7 → 3.1.0-alpha.1709537939980

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 (70) hide show
  1. package/es/action-sheet/ActionItem.mjs +79 -0
  2. package/es/action-sheet/ActionItemSfc.css +0 -0
  3. package/es/action-sheet/ActionSheet.mjs +29 -56
  4. package/es/action-sheet/actionSheet.css +1 -1
  5. package/es/action-sheet/props.mjs +3 -1
  6. package/es/action-sheet/style/index.mjs +1 -0
  7. package/es/button/Button.mjs +6 -6
  8. package/es/checkbox/Checkbox.mjs +83 -50
  9. package/es/checkbox/checkbox.css +1 -1
  10. package/es/context/stack.mjs +46 -0
  11. package/es/dialog/Dialog.mjs +12 -2
  12. package/es/dialog/props.mjs +4 -1
  13. package/es/field-decorator/FieldDecorator.mjs +10 -7
  14. package/es/field-decorator/props.mjs +1 -1
  15. package/es/hover-overlay/HoverOverlay.mjs +4 -2
  16. package/es/image-preview/ImagePreview.mjs +12 -16
  17. package/es/image-preview/props.mjs +4 -1
  18. package/es/index.bundle.mjs +1 -1
  19. package/es/index.mjs +1 -1
  20. package/es/input/Input.mjs +8 -8
  21. package/es/link/Link.mjs +10 -4
  22. package/es/link/link.css +1 -1
  23. package/es/menu/menu.css +1 -1
  24. package/es/menu/props.mjs +6 -1
  25. package/es/menu/usePopover.mjs +12 -2
  26. package/es/menu-option/MenuOption.mjs +72 -43
  27. package/es/menu-option/menuOption.css +1 -1
  28. package/es/menu-select/MenuSelect.mjs +28 -3
  29. package/es/option/Option.mjs +77 -48
  30. package/es/option/option.css +1 -1
  31. package/es/overlay/Overlay.mjs +19 -2
  32. package/es/overlay/props.mjs +7 -1
  33. package/es/paper/paper.css +1 -1
  34. package/es/picker/Picker.mjs +2 -0
  35. package/es/picker/props.mjs +4 -1
  36. package/es/popup/Popup.mjs +18 -2
  37. package/es/popup/props.mjs +7 -1
  38. package/es/radio/Radio.mjs +84 -42
  39. package/es/radio/radio.css +1 -1
  40. package/es/radio-group/RadioGroup.mjs +43 -1
  41. package/es/select/Select.mjs +279 -213
  42. package/es/select/select.css +1 -1
  43. package/es/style.css +1 -1
  44. package/es/switch/Switch.mjs +82 -52
  45. package/es/switch/switch.css +1 -1
  46. package/es/tab/tab.css +1 -1
  47. package/es/themes/dark/link.mjs +2 -1
  48. package/es/themes/dark/paper.mjs +2 -1
  49. package/es/themes/dark/tab.mjs +3 -1
  50. package/es/themes/md3-dark/link.mjs +2 -1
  51. package/es/themes/md3-dark/paper.mjs +2 -1
  52. package/es/themes/md3-dark/tab.mjs +3 -1
  53. package/es/themes/md3-light/link.mjs +2 -1
  54. package/es/themes/md3-light/paper.mjs +2 -1
  55. package/es/themes/md3-light/tab.mjs +3 -1
  56. package/es/tooltip/props.mjs +6 -1
  57. package/es/uploader/Uploader.mjs +70 -44
  58. package/es/uploader/uploader.css +1 -1
  59. package/es/utils/elements.mjs +32 -0
  60. package/es/varlet.esm.js +8014 -7704
  61. package/highlight/web-types.en-US.json +15 -2
  62. package/lib/style.css +1 -1
  63. package/lib/varlet.cjs.js +1753 -1224
  64. package/package.json +7 -7
  65. package/types/actionSheet.d.ts +4 -0
  66. package/types/input.d.ts +5 -1
  67. package/types/select.d.ts +6 -1
  68. package/types/styleVars.d.ts +100 -92
  69. package/umd/varlet.js +6 -6
  70. package/highlight/web-types.zh-CN.json +0 -8045
@@ -6,64 +6,67 @@ import { defineComponent, computed, ref, watch } from "vue";
6
6
  import { useSelect } from "./provide.mjs";
7
7
  import { createNamespace } from "../utils/components.mjs";
8
8
  import { props } from "./props.mjs";
9
+ import { preventDefault } from "@varlet/shared";
10
+ import { useEventListener } from "@varlet/use";
9
11
  const { name, n, classes } = createNamespace("option");
10
- import { normalizeClass as _normalizeClass, normalizeStyle as _normalizeStyle, createElementVNode as _createElementVNode, resolveComponent as _resolveComponent, withModifiers as _withModifiers, openBlock as _openBlock, createBlock as _createBlock, createCommentVNode as _createCommentVNode, renderSlot as _renderSlot, toDisplayString as _toDisplayString, createVNode as _createVNode, resolveDirective as _resolveDirective, createElementBlock as _createElementBlock, withDirectives as _withDirectives } from "vue";
12
+ import { normalizeClass as _normalizeClass, normalizeStyle as _normalizeStyle, createElementVNode as _createElementVNode, resolveComponent as _resolveComponent, withModifiers as _withModifiers, openBlock as _openBlock, createBlock as _createBlock, createCommentVNode as _createCommentVNode, renderSlot as _renderSlot, toDisplayString as _toDisplayString, createVNode as _createVNode, resolveDirective as _resolveDirective, createElementBlock as _createElementBlock, withDirectives as _withDirectives, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from "vue";
13
+ const _withScopeId = (n2) => (_pushScopeId(""), n2 = n2(), _popScopeId(), n2);
14
+ const _hoisted_1 = ["tabindex"];
11
15
  function __render__(_ctx, _cache) {
12
16
  const _component_var_checkbox = _resolveComponent("var-checkbox");
13
17
  const _component_var_hover_overlay = _resolveComponent("var-hover-overlay");
14
18
  const _directive_ripple = _resolveDirective("ripple");
15
19
  const _directive_hover = _resolveDirective("hover");
16
- return _withDirectives((_openBlock(), _createElementBlock(
17
- "div",
18
- {
19
- class: _normalizeClass(_ctx.classes(_ctx.n(), _ctx.n("$--box"), [_ctx.optionSelected, _ctx.n("--selected-color")], [_ctx.disabled, _ctx.n("--disabled")])),
20
- style: _normalizeStyle({
21
- color: _ctx.optionSelected ? _ctx.focusColor : void 0
22
- }),
23
- onClick: _cache[2] || (_cache[2] = (...args) => _ctx.handleClick && _ctx.handleClick(...args))
24
- },
25
- [
20
+ return _withDirectives((_openBlock(), _createElementBlock("div", {
21
+ ref: "root",
22
+ class: _normalizeClass(_ctx.classes(_ctx.n(), _ctx.n("$--box"), [_ctx.optionSelected, _ctx.n("--selected-color")], [_ctx.disabled, _ctx.n("--disabled")])),
23
+ style: _normalizeStyle({
24
+ color: _ctx.optionSelected ? _ctx.focusColor : void 0
25
+ }),
26
+ tabindex: _ctx.disabled ? void 0 : "-1",
27
+ onFocus: _cache[2] || (_cache[2] = ($event) => _ctx.isFocusing = true),
28
+ onBlur: _cache[3] || (_cache[3] = ($event) => _ctx.isFocusing = false),
29
+ onClick: _cache[4] || (_cache[4] = (...args) => _ctx.handleClick && _ctx.handleClick(...args))
30
+ }, [
31
+ _createElementVNode(
32
+ "div",
33
+ {
34
+ class: _normalizeClass(_ctx.classes(_ctx.n("cover"), [_ctx.optionSelected, _ctx.n("--selected-background")])),
35
+ style: _normalizeStyle({
36
+ background: _ctx.optionSelected ? _ctx.focusColor : void 0
37
+ })
38
+ },
39
+ null,
40
+ 6
41
+ /* CLASS, STYLE */
42
+ ),
43
+ _ctx.multiple ? (_openBlock(), _createBlock(_component_var_checkbox, {
44
+ key: 0,
45
+ ref: "checkbox",
46
+ modelValue: _ctx.optionSelected,
47
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => _ctx.optionSelected = $event),
48
+ "checked-color": _ctx.focusColor,
49
+ disabled: _ctx.disabled,
50
+ onClick: _cache[1] || (_cache[1] = _withModifiers(() => {
51
+ }, ["stop"])),
52
+ onChange: _ctx.handleSelect
53
+ }, null, 8, ["modelValue", "checked-color", "disabled", "onChange"])) : _createCommentVNode("v-if", true),
54
+ _renderSlot(_ctx.$slots, "default", {}, () => [
26
55
  _createElementVNode(
27
56
  "div",
28
57
  {
29
- class: _normalizeClass(_ctx.classes(_ctx.n("cover"), [_ctx.optionSelected, _ctx.n("--selected-background")])),
30
- style: _normalizeStyle({
31
- background: _ctx.optionSelected ? _ctx.focusColor : void 0
32
- })
58
+ class: _normalizeClass(_ctx.classes(_ctx.n("text"), _ctx.n("$--ellipsis")))
33
59
  },
34
- null,
35
- 6
36
- /* CLASS, STYLE */
37
- ),
38
- _ctx.multiple ? (_openBlock(), _createBlock(_component_var_checkbox, {
39
- key: 0,
40
- ref: "checkbox",
41
- modelValue: _ctx.optionSelected,
42
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => _ctx.optionSelected = $event),
43
- "checked-color": _ctx.focusColor,
44
- disabled: _ctx.disabled,
45
- onClick: _cache[1] || (_cache[1] = _withModifiers(() => {
46
- }, ["stop"])),
47
- onChange: _ctx.handleSelect
48
- }, null, 8, ["modelValue", "checked-color", "disabled", "onChange"])) : _createCommentVNode("v-if", true),
49
- _renderSlot(_ctx.$slots, "default", {}, () => [
50
- _createElementVNode(
51
- "div",
52
- {
53
- class: _normalizeClass(_ctx.classes(_ctx.n("text"), _ctx.n("$--ellipsis")))
54
- },
55
- _toDisplayString(_ctx.label),
56
- 3
57
- /* TEXT, CLASS */
58
- )
59
- ]),
60
- _createVNode(_component_var_hover_overlay, {
61
- hovering: _ctx.hovering && !_ctx.disabled
62
- }, null, 8, ["hovering"])
63
- ],
64
- 6
65
- /* CLASS, STYLE */
66
- )), [
60
+ _toDisplayString(_ctx.label),
61
+ 3
62
+ /* TEXT, CLASS */
63
+ )
64
+ ]),
65
+ _createVNode(_component_var_hover_overlay, {
66
+ hovering: _ctx.hovering && !_ctx.disabled,
67
+ focusing: _ctx.isFocusing && !_ctx.disabled
68
+ }, null, 8, ["hovering", "focusing"])
69
+ ], 46, _hoisted_1)), [
67
70
  [_directive_ripple, { disabled: _ctx.disabled }],
68
71
  [_directive_hover, _ctx.handleHovering, "desktop"]
69
72
  ]);
@@ -77,6 +80,8 @@ const __sfc__ = defineComponent({
77
80
  },
78
81
  props,
79
82
  setup(props2) {
83
+ const root = ref();
84
+ const isFocusing = ref(false);
80
85
  const optionSelected = ref(false);
81
86
  const selected = computed(() => optionSelected.value);
82
87
  const label = computed(() => props2.label);
@@ -92,12 +97,34 @@ const __sfc__ = defineComponent({
92
97
  };
93
98
  watch([() => props2.label, () => props2.value], computeLabel);
94
99
  bindSelect(optionProvider);
100
+ useEventListener(() => window, "keydown", handleKeydown);
101
+ useEventListener(() => window, "keyup", handleKeyup);
95
102
  function handleClick() {
96
103
  if (props2.disabled) {
97
104
  return;
98
105
  }
99
106
  handleSelect();
100
107
  }
108
+ function handleKeydown(event) {
109
+ if (!isFocusing.value) {
110
+ return;
111
+ }
112
+ if (event.key === " " || event.key === "Enter") {
113
+ preventDefault(event);
114
+ }
115
+ if (event.key === "Enter") {
116
+ root.value.click();
117
+ }
118
+ }
119
+ function handleKeyup(event) {
120
+ if (!isFocusing.value) {
121
+ return;
122
+ }
123
+ if (event.key === " ") {
124
+ preventDefault(event);
125
+ root.value.click();
126
+ }
127
+ }
101
128
  function handleSelect() {
102
129
  if (multiple.value) {
103
130
  optionSelected.value = !optionSelected.value;
@@ -108,10 +135,12 @@ const __sfc__ = defineComponent({
108
135
  optionSelected.value = checked;
109
136
  }
110
137
  return {
138
+ root,
111
139
  optionSelected,
112
140
  multiple,
113
141
  focusColor,
114
142
  hovering,
143
+ isFocusing,
115
144
  n,
116
145
  classes,
117
146
  handleHovering,
@@ -1 +1 @@
1
- :root { --option-height: 38px; --option-padding: 0 12px; --option-font-size: 16px; --option-selected-background: var(--field-decorator-focus-color); --option-text-color: #555; --option-disabled-color: var(--color-text-disabled);}.var-option { position: relative; display: flex; align-items: center; height: var(--option-height); padding: var(--option-padding); cursor: pointer; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); color: var(--option-text-color);}.var-option__cover { position: absolute; top: 0; left: 0; right: 0; bottom: 0; opacity: 0.2; background: transparent;}.var-option__text { font-size: var(--option-font-size);}.var-option--selected-background { background: var(--option-selected-background);}.var-option--selected-color { color: var(--option-selected-background);}.var-option--disabled { color: var(--option-disabled-color); cursor: not-allowed;}
1
+ :root { --option-height: 38px; --option-padding: 0 12px; --option-font-size: 16px; --option-selected-background: var(--field-decorator-focus-color); --option-text-color: #555; --option-disabled-color: var(--color-text-disabled);}.var-option { position: relative; display: flex; align-items: center; height: var(--option-height); padding: var(--option-padding); cursor: pointer; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); color: var(--option-text-color); outline: none;}.var-option__cover { position: absolute; top: 0; left: 0; right: 0; bottom: 0; opacity: 0.2; background: transparent;}.var-option__text { font-size: var(--option-font-size);}.var-option--selected-background { background: var(--option-selected-background);}.var-option--selected-color { color: var(--option-selected-background);}.var-option--disabled { color: var(--option-disabled-color); cursor: not-allowed;}
@@ -4,9 +4,11 @@ import { props } from "./props.mjs";
4
4
  import { useLock } from "../context/lock.mjs";
5
5
  import { useZIndex } from "../context/zIndex.mjs";
6
6
  import { createNamespace, useTeleport } from "../utils/components.mjs";
7
- import { call } from "@varlet/shared";
7
+ import { call, preventDefault } from "@varlet/shared";
8
8
 
9
9
 
10
+ import { useStack } from "../context/stack.mjs";
11
+ import { useEventListener } from "@varlet/use";
10
12
  const {
11
13
  name,
12
14
  n
@@ -22,10 +24,25 @@ var stdin_default = defineComponent({
22
24
  const {
23
25
  zIndex
24
26
  } = useZIndex(() => props2.show, 1);
27
+ const {
28
+ onStackTop
29
+ } = useStack(() => props2.show, zIndex);
25
30
  const {
26
31
  disabled
27
32
  } = useTeleport();
28
33
  useLock(() => props2.show, () => props2.lockScroll);
34
+ useEventListener(() => window, "keydown", handleKeydown);
35
+ function handleKeydown(event) {
36
+ if (!onStackTop() || event.key !== "Escape" || !props2.show) {
37
+ return;
38
+ }
39
+ call(props2.onKeyEscape);
40
+ if (!props2.closeOnKeyEscape) {
41
+ return;
42
+ }
43
+ preventDefault(event);
44
+ call(props2["onUpdate:show"], false);
45
+ }
29
46
  function handleClickOverlay() {
30
47
  call(props2.onClick);
31
48
  call(props2["onUpdate:show"], false);
@@ -34,7 +51,7 @@ var stdin_default = defineComponent({
34
51
  return _createVNode("div", _mergeProps({
35
52
  "class": n(),
36
53
  "style": {
37
- zIndex: zIndex.value - 1
54
+ zIndex: zIndex.value
38
55
  }
39
56
  }, attrs, {
40
57
  "onClick": handleClickOverlay
@@ -7,7 +7,13 @@ const props = {
7
7
  },
8
8
  teleport: [String, Object, Boolean],
9
9
  onClick: defineListenerProp(),
10
- "onUpdate:show": defineListenerProp()
10
+ "onUpdate:show": defineListenerProp(),
11
+ // internal for esc
12
+ onKeyEscape: defineListenerProp(),
13
+ closeOnKeyEscape: {
14
+ type: Boolean,
15
+ default: true
16
+ }
11
17
  };
12
18
  export {
13
19
  props
@@ -1 +1 @@
1
- :root { --paper-background: var(--color-surface-container-highest);}.var-paper { background: var(--paper-background); transition: background-color 0.25s; overflow: hidden;}.var-paper--round { border-radius: 50%;}.var-paper--cursor { cursor: pointer;}
1
+ :root { --paper-background: var(--color-surface-container-highest); --paper-border-radius: 4px;}.var-paper { background: var(--paper-background); transition: background-color 0.25s; overflow: hidden; border-radius: var(--paper-border-radius);}.var-paper--round { border-radius: 50%;}.var-paper--cursor { cursor: pointer;}
@@ -30,7 +30,9 @@ function __render__(_ctx, _cache) {
30
30
  onClosed: _ctx.onClosed,
31
31
  onClickOverlay: _ctx.onClickOverlay,
32
32
  onRouteChange: _ctx.onRouteChange,
33
+ onKeyEscape: _ctx.onKeyEscape,
33
34
  closeOnClickOverlay: _ctx.closeOnClickOverlay,
35
+ closeOnKeyEscape: _ctx.closeOnKeyEscape,
34
36
  teleport: _ctx.teleport,
35
37
  show: _ctx.show,
36
38
  safeArea: _ctx.safeArea,
@@ -72,7 +72,10 @@ const props = __spreadValues({
72
72
  "onOpened",
73
73
  "onClosed",
74
74
  "onClickOverlay",
75
- "onRouteChange"
75
+ "onRouteChange",
76
+ // internal for esc
77
+ "onKeyEscape",
78
+ "closeOnKeyEscape"
76
79
  ]));
77
80
  export {
78
81
  props
@@ -19,10 +19,11 @@ import { defineComponent, watch, Transition, Teleport, computed } from "vue";
19
19
  import { props } from "./props.mjs";
20
20
  import { useLock } from "../context/lock.mjs";
21
21
  import { useZIndex } from "../context/zIndex.mjs";
22
+ import { useStack } from "../context/stack.mjs";
22
23
  import { useRouteListener, useTeleport, createNamespace } from "../utils/components.mjs";
23
24
  import { usePopupItems } from "./provide.mjs";
24
- import { useInitialized } from "@varlet/use";
25
- import { call } from "@varlet/shared";
25
+ import { useEventListener, useInitialized } from "@varlet/use";
26
+ import { call, preventDefault } from "@varlet/shared";
26
27
 
27
28
 
28
29
  const {
@@ -42,6 +43,9 @@ var stdin_default = defineComponent({
42
43
  const {
43
44
  zIndex
44
45
  } = useZIndex(() => props2.show, 3);
46
+ const {
47
+ onStackTop
48
+ } = useStack(() => props2.show, zIndex);
45
49
  const {
46
50
  disabled
47
51
  } = useTeleport();
@@ -55,6 +59,7 @@ var stdin_default = defineComponent({
55
59
  bindPopupItems({
56
60
  show: computed(() => props2.show)
57
61
  });
62
+ useEventListener(() => window, "keydown", handleKeydown);
58
63
  useRouteListener(() => call(props2.onRouteChange));
59
64
  function hidePopup() {
60
65
  const {
@@ -106,6 +111,17 @@ var stdin_default = defineComponent({
106
111
  })]), [[_vShow, props2.show]])]
107
112
  });
108
113
  }
114
+ function handleKeydown(event) {
115
+ if (!onStackTop() || event.key !== "Escape" || !props2.show) {
116
+ return;
117
+ }
118
+ call(props2.onKeyEscape);
119
+ if (!props2.closeOnKeyEscape) {
120
+ return;
121
+ }
122
+ preventDefault(event);
123
+ call(props2["onUpdate:show"], false);
124
+ }
109
125
  return () => {
110
126
  const {
111
127
  teleport
@@ -37,7 +37,13 @@ const props = {
37
37
  onClickOverlay: defineListenerProp(),
38
38
  "onUpdate:show": defineListenerProp(),
39
39
  // internal for Dialog
40
- onRouteChange: defineListenerProp()
40
+ onRouteChange: defineListenerProp(),
41
+ // internal for esc
42
+ onKeyEscape: defineListenerProp(),
43
+ closeOnKeyEscape: {
44
+ type: Boolean,
45
+ default: true
46
+ }
41
47
  };
42
48
  export {
43
49
  props
@@ -8,10 +8,12 @@ import { props } from "./props.mjs";
8
8
  import { useValidation, createNamespace } from "../utils/components.mjs";
9
9
  import { useRadioGroup } from "./provide.mjs";
10
10
  import { useForm } from "../form/provide.mjs";
11
- import { call } from "@varlet/shared";
12
- import { useVModel } from "@varlet/use";
11
+ import { call, preventDefault } from "@varlet/shared";
12
+ import { useEventListener, useVModel } from "@varlet/use";
13
13
  const { name, n, classes } = createNamespace("radio");
14
- import { renderSlot as _renderSlot, resolveComponent as _resolveComponent, normalizeClass as _normalizeClass, createVNode as _createVNode, createCommentVNode as _createCommentVNode, normalizeStyle as _normalizeStyle, resolveDirective as _resolveDirective, openBlock as _openBlock, createElementBlock as _createElementBlock, withDirectives as _withDirectives, mergeProps as _mergeProps, createElementVNode as _createElementVNode } from "vue";
14
+ import { renderSlot as _renderSlot, resolveComponent as _resolveComponent, normalizeClass as _normalizeClass, createVNode as _createVNode, createCommentVNode as _createCommentVNode, normalizeStyle as _normalizeStyle, resolveDirective as _resolveDirective, openBlock as _openBlock, createElementBlock as _createElementBlock, withDirectives as _withDirectives, mergeProps as _mergeProps, createElementVNode as _createElementVNode, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from "vue";
15
+ const _withScopeId = (n2) => (_pushScopeId(""), n2 = n2(), _popScopeId(), n2);
16
+ const _hoisted_1 = ["tabindex"];
15
17
  function __render__(_ctx, _cache) {
16
18
  const _component_var_icon = _resolveComponent("var-icon");
17
19
  const _component_var_hover_overlay = _resolveComponent("var-hover-overlay");
@@ -28,45 +30,44 @@ function __render__(_ctx, _cache) {
28
30
  "div",
29
31
  _mergeProps({
30
32
  class: _ctx.n(),
31
- onClick: _cache[0] || (_cache[0] = (...args) => _ctx.handleClick && _ctx.handleClick(...args))
33
+ onClick: _cache[3] || (_cache[3] = (...args) => _ctx.handleClick && _ctx.handleClick(...args))
32
34
  }, _ctx.$attrs),
33
35
  [
34
- _withDirectives((_openBlock(), _createElementBlock(
35
- "div",
36
- {
37
- class: _normalizeClass(
38
- _ctx.classes(
39
- _ctx.n("action"),
40
- [_ctx.checked, _ctx.n("--checked"), _ctx.n("--unchecked")],
41
- [_ctx.errorMessage || _ctx.radioGroupErrorMessage, _ctx.n("--error")],
42
- [_ctx.formDisabled || _ctx.disabled, _ctx.n("--disabled")]
43
- )
44
- ),
45
- style: _normalizeStyle({ color: _ctx.checked ? _ctx.checkedColor : _ctx.uncheckedColor })
46
- },
47
- [
48
- _ctx.checked ? _renderSlot(_ctx.$slots, "checked-icon", { key: 0 }, () => [
49
- _createVNode(_component_var_icon, {
50
- class: _normalizeClass(_ctx.classes(_ctx.n("icon"), [_ctx.withAnimation, _ctx.n("--with-animation")])),
51
- "var-radio-cover": "",
52
- name: "radio-marked",
53
- size: _ctx.iconSize
54
- }, null, 8, ["class", "size"])
55
- ]) : _renderSlot(_ctx.$slots, "unchecked-icon", { key: 1 }, () => [
56
- _createVNode(_component_var_icon, {
57
- class: _normalizeClass(_ctx.classes(_ctx.n("icon"), [_ctx.withAnimation, _ctx.n("--with-animation")])),
58
- "var-radio-cover": "",
59
- name: "radio-blank",
60
- size: _ctx.iconSize
61
- }, null, 8, ["class", "size"])
62
- ]),
63
- _createVNode(_component_var_hover_overlay, {
64
- hovering: !_ctx.disabled && !_ctx.formDisabled && _ctx.hovering
65
- }, null, 8, ["hovering"])
66
- ],
67
- 6
68
- /* CLASS, STYLE */
69
- )), [
36
+ _withDirectives((_openBlock(), _createElementBlock("div", {
37
+ ref: "action",
38
+ class: _normalizeClass(
39
+ _ctx.classes(
40
+ _ctx.n("action"),
41
+ [_ctx.checked, _ctx.n("--checked"), _ctx.n("--unchecked")],
42
+ [_ctx.errorMessage || _ctx.radioGroupErrorMessage, _ctx.n("--error")],
43
+ [_ctx.formDisabled || _ctx.disabled, _ctx.n("--disabled")]
44
+ )
45
+ ),
46
+ tabindex: _ctx.formDisabled || _ctx.disabled ? void 0 : "0",
47
+ style: _normalizeStyle({ color: _ctx.checked ? _ctx.checkedColor : _ctx.uncheckedColor }),
48
+ onFocus: _cache[0] || (_cache[0] = ($event) => _ctx.isFocusing = true),
49
+ onBlur: _cache[1] || (_cache[1] = ($event) => _ctx.isFocusing = false)
50
+ }, [
51
+ _ctx.checked ? _renderSlot(_ctx.$slots, "checked-icon", { key: 0 }, () => [
52
+ _createVNode(_component_var_icon, {
53
+ class: _normalizeClass(_ctx.classes(_ctx.n("icon"), [_ctx.withAnimation, _ctx.n("--with-animation")])),
54
+ "var-radio-cover": "",
55
+ name: "radio-marked",
56
+ size: _ctx.iconSize
57
+ }, null, 8, ["class", "size"])
58
+ ]) : _renderSlot(_ctx.$slots, "unchecked-icon", { key: 1 }, () => [
59
+ _createVNode(_component_var_icon, {
60
+ class: _normalizeClass(_ctx.classes(_ctx.n("icon"), [_ctx.withAnimation, _ctx.n("--with-animation")])),
61
+ "var-radio-cover": "",
62
+ name: "radio-blank",
63
+ size: _ctx.iconSize
64
+ }, null, 8, ["class", "size"])
65
+ ]),
66
+ _createVNode(_component_var_hover_overlay, {
67
+ hovering: !_ctx.disabled && !_ctx.formDisabled && _ctx.hovering,
68
+ focusing: !_ctx.disabled && !_ctx.formDisabled && _ctx.isFocusing
69
+ }, null, 8, ["hovering", "focusing"])
70
+ ], 46, _hoisted_1)), [
70
71
  [_directive_ripple, { disabled: _ctx.formReadonly || _ctx.readonly || _ctx.formDisabled || _ctx.disabled || !_ctx.ripple }],
71
72
  [_directive_hover, _ctx.handleHovering, "desktop"]
72
73
  ]),
@@ -80,7 +81,8 @@ function __render__(_ctx, _cache) {
80
81
  [_ctx.errorMessage || _ctx.radioGroupErrorMessage, _ctx.n("--error")],
81
82
  [_ctx.formDisabled || _ctx.disabled, _ctx.n("--disabled")]
82
83
  )
83
- )
84
+ ),
85
+ onClick: _cache[2] || (_cache[2] = (...args) => _ctx.handleTextClick && _ctx.handleTextClick(...args))
84
86
  },
85
87
  [
86
88
  _renderSlot(_ctx.$slots, "default")
@@ -109,6 +111,8 @@ const __sfc__ = defineComponent({
109
111
  inheritAttrs: false,
110
112
  props,
111
113
  setup(props2) {
114
+ const action = ref();
115
+ const isFocusing = ref(false);
112
116
  const value = useVModel(props2, "modelValue");
113
117
  const checked = computed(() => value.value === props2.checkedValue);
114
118
  const withAnimation = ref(false);
@@ -126,10 +130,42 @@ const __sfc__ = defineComponent({
126
130
  sync,
127
131
  validate,
128
132
  resetValidation,
129
- reset
133
+ reset,
134
+ isFocusing: computed(() => isFocusing.value),
135
+ // keyboard arrow move
136
+ move() {
137
+ action.value.focus();
138
+ action.value.click();
139
+ },
140
+ moveable() {
141
+ return !(form == null ? void 0 : form.disabled.value) && !props2.disabled && !(form == null ? void 0 : form.readonly.value) && !props2.readonly;
142
+ }
130
143
  };
131
144
  call(bindRadioGroup, radioProvider);
132
145
  call(bindForm, radioProvider);
146
+ useEventListener(() => window, "keydown", handleKeydown);
147
+ useEventListener(() => window, "keyup", handleKeyup);
148
+ function handleKeydown(event) {
149
+ if (!isFocusing.value) {
150
+ return;
151
+ }
152
+ const { key } = event;
153
+ if (key === "Enter" || key === " ") {
154
+ preventDefault(event);
155
+ }
156
+ if (key === "Enter") {
157
+ action.value.click();
158
+ }
159
+ }
160
+ function handleKeyup(event) {
161
+ if (!isFocusing.value) {
162
+ return;
163
+ }
164
+ if (event.key === " ") {
165
+ preventDefault(event);
166
+ action.value.click();
167
+ }
168
+ }
133
169
  function validateWithTrigger(trigger) {
134
170
  nextTick(() => {
135
171
  const { validateTrigger, rules, modelValue } = props2;
@@ -158,6 +194,9 @@ const __sfc__ = defineComponent({
158
194
  withAnimation.value = true;
159
195
  change(checked.value ? uncheckedValue : checkedValue);
160
196
  }
197
+ function handleTextClick() {
198
+ action.value.focus();
199
+ }
161
200
  function sync(v2) {
162
201
  const { checkedValue, uncheckedValue } = props2;
163
202
  value.value = v2 === checkedValue ? checkedValue : uncheckedValue;
@@ -178,6 +217,8 @@ const __sfc__ = defineComponent({
178
217
  change(changedValue);
179
218
  }
180
219
  return {
220
+ action,
221
+ isFocusing,
181
222
  withAnimation,
182
223
  checked,
183
224
  errorMessage,
@@ -189,6 +230,7 @@ const __sfc__ = defineComponent({
189
230
  n,
190
231
  classes,
191
232
  handleClick,
233
+ handleTextClick,
192
234
  toggle,
193
235
  reset,
194
236
  validate,
@@ -1 +1 @@
1
- :root { --radio-checked-color: var(--color-primary); --radio-unchecked-color: #555; --radio-disabled-color: var(--color-text-disabled); --radio-error-color: var(--color-danger); --radio-icon-size: 24px; --radio-action-padding: 6px; --radio-text-color: #555;}@keyframes var-vibrate-animation { 0% { opacity: 1; transform: scale(1); } 50% { opacity: 0.8; transform: scale(0.8); } 100% { opacity: 1; transform: scale(1); }}.var-radio { display: flex; align-items: center; transform: translateX(calc(-1 * var(--radio-action-padding))); cursor: pointer; -webkit-tap-highlight-color: rgba(0, 0, 0, 0);}.var-radio__wrap { display: inline-flex; flex-direction: column;}.var-radio__action { position: relative; display: flex; justify-content: center; align-items: center; flex-shrink: 0; padding: var(--radio-action-padding); border-radius: 50%; transition: background-color 0.25s, color 0.25s;}.var-radio__icon[var-radio-cover] { display: block; font-size: var(--radio-icon-size);}.var-radio__text { color: var(--radio-text-color);}.var-radio--with-animation[var-radio-cover] { animation: var-vibrate-animation 0.25s;}.var-radio--checked { color: var(--radio-checked-color);}.var-radio--unchecked { color: var(--radio-unchecked-color);}.var-radio--disabled { color: var(--radio-disabled-color); cursor: not-allowed;}.var-radio--error { color: var(--radio-error-color);}
1
+ :root { --radio-checked-color: var(--color-primary); --radio-unchecked-color: #555; --radio-disabled-color: var(--color-text-disabled); --radio-error-color: var(--color-danger); --radio-icon-size: 24px; --radio-action-padding: 6px; --radio-text-color: #555;}@keyframes var-vibrate-animation { 0% { opacity: 1; transform: scale(1); } 50% { opacity: 0.8; transform: scale(0.8); } 100% { opacity: 1; transform: scale(1); }}.var-radio { display: flex; align-items: center; transform: translateX(calc(-1 * var(--radio-action-padding))); cursor: pointer; -webkit-tap-highlight-color: rgba(0, 0, 0, 0);}.var-radio__wrap { display: inline-flex; flex-direction: column;}.var-radio__action { position: relative; display: flex; justify-content: center; align-items: center; flex-shrink: 0; padding: var(--radio-action-padding); border-radius: 50%; outline: none; transition: background-color 0.25s, color 0.25s;}.var-radio__icon[var-radio-cover] { display: block; font-size: var(--radio-icon-size);}.var-radio__text { color: var(--radio-text-color);}.var-radio--with-animation[var-radio-cover] { animation: var-vibrate-animation 0.25s;}.var-radio--checked { color: var(--radio-checked-color);}.var-radio--unchecked { color: var(--radio-unchecked-color);}.var-radio--disabled { color: var(--radio-disabled-color); cursor: not-allowed;}.var-radio--error { color: var(--radio-error-color);}
@@ -4,7 +4,8 @@ import { props } from "./props.mjs";
4
4
  import { useValidation, createNamespace } from "../utils/components.mjs";
5
5
  import { useRadios } from "./provide.mjs";
6
6
  import { useForm } from "../form/provide.mjs";
7
- import { call } from "@varlet/shared";
7
+ import { call, preventDefault } from "@varlet/shared";
8
+ import { useEventListener } from "@varlet/use";
8
9
  const { name, n, classes } = createNamespace("radio-group");
9
10
  import { renderSlot as _renderSlot, normalizeClass as _normalizeClass, createElementVNode as _createElementVNode, resolveComponent as _resolveComponent, createVNode as _createVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue";
10
11
  function __render__(_ctx, _cache) {
@@ -58,6 +59,47 @@ const __sfc__ = defineComponent({
58
59
  watch(() => length.value, syncRadios);
59
60
  call(bindForm, radioGroupProvider);
60
61
  bindRadios(radioGroupProvider);
62
+ useEventListener(() => window, "keydown", handleKeydown);
63
+ function handleKeydown(event) {
64
+ const focusingRadioIndex = radios.findIndex(({ isFocusing }) => isFocusing.value);
65
+ if (focusingRadioIndex === -1) {
66
+ return;
67
+ }
68
+ const hasMoveableRadio = radios.some(({ moveable }, index) => index === focusingRadioIndex ? false : moveable());
69
+ if (!hasMoveableRadio) {
70
+ return;
71
+ }
72
+ if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(event.key)) {
73
+ preventDefault(event);
74
+ }
75
+ if (event.key === "ArrowUp" || event.key === "ArrowLeft") {
76
+ moveRadio(focusingRadioIndex, "prev");
77
+ return;
78
+ }
79
+ if (event.key === "ArrowDown" || event.key === "ArrowRight") {
80
+ moveRadio(focusingRadioIndex, "next");
81
+ }
82
+ }
83
+ function moveRadio(fromIndex, method) {
84
+ while (true) {
85
+ if (method === "prev") {
86
+ fromIndex--;
87
+ } else {
88
+ fromIndex++;
89
+ }
90
+ if (fromIndex < 0) {
91
+ fromIndex = radios.length - 1;
92
+ }
93
+ if (fromIndex > radios.length - 1) {
94
+ fromIndex = 0;
95
+ }
96
+ const radio = radios[fromIndex];
97
+ if (radio.moveable()) {
98
+ radio.move();
99
+ break;
100
+ }
101
+ }
102
+ }
61
103
  function validateWithTrigger(trigger) {
62
104
  nextTick(() => {
63
105
  const { validateTrigger, rules, modelValue } = props2;