eco-vue-js 0.27.3 → 0.28.0

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 (50) hide show
  1. package/dist/components/ActionsBar/WActionsBar.vue_vue_type_script_setup_true_lang.js +2 -2
  2. package/dist/components/Button/WButtonAction.vue_vue_type_script_setup_true_lang.js +2 -2
  3. package/dist/components/Button/WButtonDropdown.vue_vue_type_script_setup_true_lang.js +2 -2
  4. package/dist/components/Button/WButtonTab.vue_vue_type_script_setup_true_lang.js +3 -3
  5. package/dist/components/Chart/WChartLine.vue_vue_type_script_setup_true_lang.js +3 -3
  6. package/dist/components/Checkbox/WCheckbox.vue_vue_type_script_setup_true_lang.js +3 -3
  7. package/dist/components/Counter/WCounter.vue_vue_type_script_setup_true_lang.js +1 -1
  8. package/dist/components/DatePicker/WDatePicker.vue_vue_type_script_setup_true_lang.js +2 -2
  9. package/dist/components/DatePicker/WDatePickerSingle.vue_vue_type_script_setup_true_lang.js +2 -2
  10. package/dist/components/DatePicker/components/CalendarToggle.vue_vue_type_script_setup_true_lang.js +2 -2
  11. package/dist/components/Dismissable/WDismissable.vue_vue_type_script_setup_true_lang.js +1 -1
  12. package/dist/components/Expansion/WExpansion.vue_vue_type_script_setup_true_lang.js +3 -3
  13. package/dist/components/Expansion/WExpansionItem.vue_vue_type_script_setup_true_lang.js +1 -1
  14. package/dist/components/FilePicker/components/FilePickerSvg.vue_vue_type_script_setup_true_lang.js +1 -1
  15. package/dist/components/InfiniteList/components/InfiniteListPage.vue_vue_type_script_setup_true_lang.js +1 -1
  16. package/dist/components/Input/WInput.vue_vue_type_script_setup_true_lang.js +1 -1
  17. package/dist/components/Input/WInputSuggest.vue_vue_type_script_setup_true_lang.js +1 -1
  18. package/dist/components/List/WListHeaderItem.vue_vue_type_script_setup_true_lang.js +1 -1
  19. package/dist/components/List/components/HeaderSortItem.vue_vue_type_script_setup_true_lang.js +1 -1
  20. package/dist/components/List/components/ListFilterChip.vue_vue_type_script_setup_true_lang.js +1 -1
  21. package/dist/components/List/components/ListItem.vue_vue_type_script_setup_true_lang.js +1 -1
  22. package/dist/components/Modal/WModal.vue_vue_type_script_setup_true_lang.js +2 -2
  23. package/dist/components/Nav/WNavBar.vue_vue_type_script_setup_true_lang.js +1 -1
  24. package/dist/components/Nav/WNavItem.vue_vue_type_script_setup_true_lang.js +2 -2
  25. package/dist/components/Nav/WNavItemExpand.vue_vue_type_script_setup_true_lang.js +1 -1
  26. package/dist/components/Nav/WNavItemTransition.vue_vue_type_script_setup_true_lang.js +2 -2
  27. package/dist/components/Notify/WNotify.vue_vue_type_script_setup_true_lang.js +1 -1
  28. package/dist/components/Notify/WNotifyCenter.vue_vue_type_script_setup_true_lang.js +2 -2
  29. package/dist/components/Progress/WProgress.vue_vue_type_script_setup_true_lang.js +1 -1
  30. package/dist/components/Progress/WProgressBar.vue_vue_type_script_setup_true_lang.js +4 -4
  31. package/dist/components/Progress/WProgressStriped.vue_vue_type_script_setup_true_lang.js +3 -3
  32. package/dist/components/Skeleton/WSkeleton.vue_vue_type_script_setup_true_lang.js +1 -1
  33. package/dist/components/Slider/WSlider.vue_vue_type_script_setup_true_lang.js +1 -1
  34. package/dist/components/Slider/WSliderRange.vue_vue_type_script_setup_true_lang.js +2 -2
  35. package/dist/components/Spinner/WSpinner.vue.js +1 -1
  36. package/dist/components/Tabs/WTabs.vue_vue_type_script_setup_true_lang.js +3 -3
  37. package/dist/components/TextOverflow/WTextOverflow.vue_vue_type_script_setup_true_lang.js +1 -1
  38. package/dist/components/Toggle/WToggle.vue_vue_type_script_setup_true_lang.js +1 -1
  39. package/docs/llms.txt +1 -1
  40. package/eslint/plugin.js +31 -1
  41. package/eslint/processors/motion-css.js +42 -0
  42. package/eslint/rules/motion/classes.js +74 -0
  43. package/eslint/rules/motion/css.js +196 -0
  44. package/eslint/rules/motion-safe.js +96 -0
  45. package/package.json +4 -2
  46. package/tailwind-base/css/markdown/blocks.css +1 -1
  47. package/tailwind-base/css/reduced-motion.css +8 -2
  48. package/tailwind-base/plugins/internal-classes.ts +6 -2
  49. package/tailwind-base/plugins/w-hover-circle.ts +5 -3
  50. package/tailwind-base/plugins/w-ripple.ts +3 -1
@@ -38,7 +38,7 @@ var WActionsBar_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
38
38
  return (_ctx, _cache) => {
39
39
  return openBlock(), createElementBlock("div", {
40
40
  ref: "bar",
41
- class: normalizeClass(["w-actions-bar sm-not:[--actions-bar-filter-width:calc(100vw-var(--w-actions-bar-width))] fixed right-(--w-right-margin,0px) top-0 grid grid-cols-[var(--actions-bar-filter-width-current,0)_var(--w-actions-bar-width)] grid-rows-[var(--header-height)_1fr] justify-end overflow-hidden transition-[grid-template-columns] duration-300 print:hidden", { "[--actions-bar-filter-width-current:var(--actions-bar-filter-width)]": isOpen.value && hasFilter.value }]),
41
+ class: normalizeClass(["w-actions-bar sm-not:[--actions-bar-filter-width:calc(100vw-var(--w-actions-bar-width))] fixed right-(--w-right-margin,0px) top-0 grid grid-cols-[var(--actions-bar-filter-width-current,0)_var(--w-actions-bar-width)] grid-rows-[var(--header-height)_1fr] justify-end overflow-hidden motion-safe:transition-[grid-template-columns] motion-safe:duration-300 print:hidden", { "[--actions-bar-filter-width-current:var(--actions-bar-filter-width)]": isOpen.value && hasFilter.value }]),
42
42
  style: normalizeStyle({ zIndex: unref(40) })
43
43
  }, [createElementVNode("div", _hoisted_1, [createElementVNode("div", _hoisted_2, [createElementVNode("div", _hoisted_3, toDisplayString(__props.textFilter ?? "Filters"), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(unref(filter), (slot, index) => {
44
44
  return openBlock(), createBlock(resolveDynamicComponent(slot), { key: index });
@@ -48,7 +48,7 @@ var WActionsBar_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
48
48
  "aria-expanded": isOpen.value,
49
49
  "aria-label": "Toggle filters",
50
50
  onClick: toggle
51
- }, [createVNode(unref(IconBack_default), { class: normalizeClass(["text-description square-4 transition-transform", { "transform-[rotateY(180deg)]": isOpen.value }]) }, null, 8, ["class"])], 8, _hoisted_5)) : createCommentVNode("", true), createElementVNode("div", _hoisted_6, [createElementVNode("div", null, [
51
+ }, [createVNode(unref(IconBack_default), { class: normalizeClass(["text-description square-4 motion-safe:transition-transform", { "transform-[rotateY(180deg)]": isOpen.value }]) }, null, 8, ["class"])], 8, _hoisted_5)) : createCommentVNode("", true), createElementVNode("div", _hoisted_6, [createElementVNode("div", null, [
52
52
  renderSlot(_ctx.$slots, "top"),
53
53
  _ctx.$slots.top && (hasFilter.value || _ctx.$slots.bottom) ? (openBlock(), createElementBlock("div", _hoisted_7)) : createCommentVNode("", true),
54
54
  hasFilter.value ? (openBlock(), createBlock(WButtonAction_default, {
@@ -82,10 +82,10 @@ var WButtonAction_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
82
82
  }, null, 8, ["count"])), [[vShow, __props.count > 0]]) : createCommentVNode("", true),
83
83
  renderSlot(_ctx.$slots, "icon", {}, () => [__props.icon ? (openBlock(), createBlock(resolveDynamicComponent(__props.icon), {
84
84
  key: 0,
85
- class: normalizeClass(["square-6 w-svg-stroke-width-sm place-self-center transition-transform", { "group-hover:scale-120": !__props.disabled }])
85
+ class: normalizeClass(["square-6 w-svg-stroke-width-sm place-self-center motion-safe:transition-transform", { "group-hover:scale-120": !__props.disabled }])
86
86
  }, null, 8, ["class"])) : createCommentVNode("", true)]),
87
87
  !__props.disabled && !unref(isBackdrop) && !__props.loading ? (openBlock(), createBlock(WShine_default, { key: 1 })) : createCommentVNode("", true),
88
- __props.loading ? (openBlock(), createElementBlock("div", _hoisted_1, [..._cache[0] || (_cache[0] = [createElementVNode("div", { class: "absolute inset-0 bg-linear-90 from-current/0 to-current/0 via-current animate-ticker" }, null, -1)])])) : createCommentVNode("", true)
88
+ __props.loading ? (openBlock(), createElementBlock("div", _hoisted_1, [..._cache[0] || (_cache[0] = [createElementVNode("div", { class: "absolute inset-0 bg-linear-90 from-current/0 to-current/0 via-current motion-safe:animate-ticker" }, null, -1)])])) : createCommentVNode("", true)
89
89
  ], 2)),
90
90
  __props.titleText ? (openBlock(), createElementBlock("div", {
91
91
  key: 2,
@@ -62,7 +62,7 @@ var WButtonDropdown_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
62
62
  join: "",
63
63
  onClick: toggle
64
64
  }, {
65
- default: withCtx(() => [createVNode(unref(IconArrow_default), { class: normalizeClass(["square-4 transition-transform", { "rotate-180": isOpen.value }]) }, null, 8, ["class"])]),
65
+ default: withCtx(() => [createVNode(unref(IconArrow_default), { class: normalizeClass(["square-4 motion-safe:transition-transform", { "rotate-180": isOpen.value }]) }, null, 8, ["class"])]),
66
66
  _: 1
67
67
  }, 8, ["semantic-type", "disabled"])) : createCommentVNode("", true),
68
68
  (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.$slots.button?.(), (item, index) => {
@@ -79,7 +79,7 @@ var WButtonDropdown_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
79
79
  join: "",
80
80
  onClick: toggle
81
81
  }, {
82
- default: withCtx(() => [createVNode(unref(IconArrow_default), { class: normalizeClass(["square-[1em] transition-transform", { "rotate-180": isOpen.value }]) }, null, 8, ["class"])]),
82
+ default: withCtx(() => [createVNode(unref(IconArrow_default), { class: normalizeClass(["square-[1em] motion-safe:transition-transform", { "rotate-180": isOpen.value }]) }, null, 8, ["class"])]),
83
83
  _: 1
84
84
  }, 8, ["semantic-type", "disabled"])) : createCommentVNode("", true)
85
85
  ]), __props.tooltipText ? (openBlock(), createBlock(WTooltip_default, {
@@ -52,7 +52,7 @@ var WButtonTab_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defin
52
52
  }],
53
53
  onClick: _cache[0] || (_cache[0] = ($event) => !__props.disabled && _ctx.$emit("click", $event))
54
54
  }), {
55
- default: withCtx(() => [__props.indicator ? (openBlock(), createElementBlock("div", _hoisted_1, [createElementVNode("div", { class: normalizeClass(["text-surface rounded-full bg-inherit p-1 outline transition-[outline-width] duration-500", {
55
+ default: withCtx(() => [__props.indicator ? (openBlock(), createElementBlock("div", _hoisted_1, [createElementVNode("div", { class: normalizeClass(["text-surface rounded-full bg-inherit p-1 outline motion-safe:transition-[outline-width] motion-safe:duration-500", {
56
56
  "tone-negative bg-tone-fill outline-tone/10": __props.hasError,
57
57
  "tone-positive bg-tone-fill outline-tone/10": !__props.hasError && __props.hasValue && __props.showHasValue,
58
58
  "bg-track-strong outline-track-strong/10": !__props.hasError && (!__props.showHasValue || !__props.hasValue),
@@ -124,8 +124,8 @@ var WButtonTab_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defin
124
124
  _: 1
125
125
  }),
126
126
  createVNode(Transition, {
127
- "enter-active-class": "transition-[scale,opacity] origin-center duration-300",
128
- "leave-active-class": "transition-[scale,opacity] origin-center duration-300",
127
+ "enter-active-class": "motion-safe:transition-[scale,opacity] origin-center motion-safe:duration-300",
128
+ "leave-active-class": "motion-safe:transition-[scale,opacity] origin-center motion-safe:duration-300",
129
129
  "enter-from-class": "scale-x-0 opacity-0",
130
130
  "leave-to-class": "scale-x-0 opacity-0",
131
131
  css: !__props.indicator
@@ -240,12 +240,12 @@ var WChartLine_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defin
240
240
  d: minMaxAreaPath.value,
241
241
  fill: "white",
242
242
  "fill-opacity": "0.2",
243
- class: "transition-[d]"
243
+ class: "motion-safe:transition-[d]"
244
244
  }, null, 8, _hoisted_5)) : createCommentVNode("", true)], 64)) : __props.hasArea && areaPath.value ? (openBlock(), createElementBlock("path", {
245
245
  key: 1,
246
246
  d: areaPath.value,
247
247
  fill: `url(#${unref(gradientAreaId)})`,
248
- class: "transition-[d]"
248
+ class: "motion-safe:transition-[d]"
249
249
  }, null, 8, _hoisted_6)) : createCommentVNode("", true),
250
250
  linePath.value ? (openBlock(), createElementBlock("path", {
251
251
  key: 2,
@@ -256,7 +256,7 @@ var WChartLine_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defin
256
256
  stroke: "white",
257
257
  "stroke-linejoin": "round",
258
258
  "stroke-linecap": "round",
259
- class: "transition-[d]"
259
+ class: "motion-safe:transition-[d]"
260
260
  }, null, 8, _hoisted_7)) : createCommentVNode("", true),
261
261
  _ctx.$slots.tooltip && hoveredData.value && tooltipRef.value?.isOpen ? (openBlock(), createElementBlock("g", _hoisted_8, [createElementVNode("circle", {
262
262
  cx: hoveredData.value.x,
@@ -89,8 +89,8 @@ var WCheckbox_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
89
89
  onKeypress: withKeys(withModifiers(toggle, ["stop", "prevent"]), ["enter"])
90
90
  }, [
91
91
  createVNode(Transition, {
92
- "enter-active-class": "transition-[scale,opacity]",
93
- "leave-active-class": "transition-[scale,opacity]",
92
+ "enter-active-class": "motion-safe:transition-[scale,opacity]",
93
+ "leave-active-class": "motion-safe:transition-[scale,opacity]",
94
94
  "enter-from-class": __props.radio ? "opacity-0 scale-25!" : "opacity-0 scale-50!",
95
95
  "leave-to-class": __props.radio ? "opacity-0 scale-25!" : "opacity-0 scale-50!",
96
96
  css: !__props.lessTransitions
@@ -102,7 +102,7 @@ var WCheckbox_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
102
102
  "rounded-[calc(0.25rem+1px)]": !__props.radio && !(__props.intermediate && __props.modelValue === null),
103
103
  "tone-primary bg-tone-fill [.w-hover-checked:hover_&]:block!": !unref(isDisabled) && !unref(isSkeleton),
104
104
  "bg-track": unref(isDisabled) || unref(isSkeleton),
105
- "transition-[scale,opacity]": !__props.lessTransitions
105
+ "motion-safe:transition-[scale,opacity]": !__props.lessTransitions
106
106
  }]) }, null, 2), [[vShow, __props.modelValue !== false && !__props.loading]])]),
107
107
  _: 1
108
108
  }, 8, [
@@ -25,7 +25,7 @@ var WCounter_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineC
25
25
  }
26
26
  });
27
27
  return (_ctx, _cache) => {
28
- return openBlock(), createElementBlock("div", { class: normalizeClass(["flex min-w-[1.25em] items-center justify-center rounded-full px-[0.375em] font-medium leading-tight", [{ "animate-shake": isShake.value }, unref(semanticTypeBgMap)[__props.semanticType]]]) }, toDisplayString(unref(numberCompactFormatter).format(__props.count)), 3);
28
+ return openBlock(), createElementBlock("div", { class: normalizeClass(["flex min-w-[1.25em] items-center justify-center rounded-full px-[0.375em] font-medium leading-tight", [{ "motion-safe:animate-shake": isShake.value }, unref(semanticTypeBgMap)[__props.semanticType]]]) }, toDisplayString(unref(numberCompactFormatter).format(__props.count)), 3);
29
29
  };
30
30
  }
31
31
  });
@@ -121,8 +121,8 @@ var WDatePicker_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
121
121
  "onClick:previous",
122
122
  "onClick:next"
123
123
  ])]), createElementVNode("div", _hoisted_3, [createVNode(Transition, {
124
- "enter-active-class": "transition-transform duration-250 w-full",
125
- "leave-active-class": "transition-transform duration-250 w-full absolute top-0",
124
+ "enter-active-class": "motion-safe:transition-transform motion-safe:duration-250 w-full",
125
+ "leave-active-class": "motion-safe:transition-transform motion-safe:duration-250 w-full absolute top-0",
126
126
  "enter-from-class": "translate-x-[calc(100%*var(--direction-factor))]",
127
127
  "leave-to-class": "translate-x-[calc(100%*var(--direction-factor)*-1)]"
128
128
  }, {
@@ -75,8 +75,8 @@ var WDatePickerSingle_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
75
75
  "onClick:previous",
76
76
  "onClick:next"
77
77
  ])]), createElementVNode("div", _hoisted_2, [createVNode(Transition, {
78
- "enter-active-class": "transition-transform duration-250 w-full",
79
- "leave-active-class": "transition-transform duration-250 w-full absolute top-0",
78
+ "enter-active-class": "motion-safe:transition-transform motion-safe:duration-250 w-full",
79
+ "leave-active-class": "motion-safe:transition-transform motion-safe:duration-250 w-full absolute top-0",
80
80
  "enter-from-class": "translate-x-[calc(100%*var(--direction-factor))]",
81
81
  "leave-to-class": "translate-x-[calc(100%*var(--direction-factor)*-1)]"
82
82
  }, {
@@ -19,8 +19,8 @@ var CalendarToggle_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
19
19
  onClick: _cache[0] || (_cache[0] = ($event) => !__props.disabledPrevious && _ctx.$emit("click:previous"))
20
20
  }, [createVNode(unref(IconArrow_default), { class: "-ml-1 rotate-90" })], 2),
21
21
  createElementVNode("div", _hoisted_2, [createVNode(Transition, {
22
- "enter-active-class": "transition-transform duration-250 w-full",
23
- "leave-active-class": "transition-transform duration-250 w-full absolute top-0",
22
+ "enter-active-class": "motion-safe:transition-transform motion-safe:duration-250 w-full",
23
+ "leave-active-class": "motion-safe:transition-transform motion-safe:duration-250 w-full absolute top-0",
24
24
  "enter-from-class": "translate-x-[calc(100%*var(--direction-factor))]",
25
25
  "leave-to-class": "translate-x-[calc(100%*var(--direction-factor)*-1)]"
26
26
  }, {
@@ -4,7 +4,7 @@ import { Transition, createBlock, createCommentVNode, createElementBlock, create
4
4
  var _hoisted_1 = {
5
5
  key: 0,
6
6
  ref: "container",
7
- class: "no-scrollbar snap-y snap-mandatory snap-always overflow-scroll overflow-y-auto overscroll-contain scroll-smooth"
7
+ class: "no-scrollbar snap-y snap-mandatory snap-always overflow-scroll overflow-y-auto overscroll-contain motion-safe:scroll-smooth"
8
8
  };
9
9
  var WDismissable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
10
10
  __name: "WDismissable",
@@ -2,7 +2,7 @@ import { KeepAlive, Transition, createBlock, createCommentVNode, createElementBl
2
2
  // src/components/Expansion/WExpansion.vue?vue&type=script&setup=true&lang.ts
3
3
  var _hoisted_1 = {
4
4
  key: 0,
5
- class: "duration-(--expansion-duration,200ms)"
5
+ class: "motion-safe:duration-(--expansion-duration,200ms)"
6
6
  };
7
7
  var _hoisted_2 = { class: "grid grid-cols-1 [overflow:inherit]" };
8
8
  var WExpansion_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
@@ -21,10 +21,10 @@ var WExpansion_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defin
21
21
  setup(__props) {
22
22
  return (_ctx, _cache) => {
23
23
  return openBlock(), createBlock(Transition, {
24
- "enter-active-class": "transition-[grid-template-rows] overflow-y-hidden grid",
24
+ "enter-active-class": "motion-safe:transition-[grid-template-rows] overflow-y-hidden grid",
25
25
  "enter-from-class": "grid-rows-[0fr]",
26
26
  "enter-to-class": "grid-rows-[1fr]",
27
- "leave-active-class": "transition-[grid-template-rows] overflow-y-hidden grid",
27
+ "leave-active-class": "motion-safe:transition-[grid-template-rows] overflow-y-hidden grid",
28
28
  "leave-from-class": "grid-rows-[1fr]",
29
29
  "leave-to-class": "grid-rows-[0fr]",
30
30
  onBeforeEnter: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:visible", true)),
@@ -51,7 +51,7 @@ var WExpansionItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
51
51
  default: withCtx(() => [__props.hasFlag ? (openBlock(), createElementBlock("div", _hoisted_1)) : createCommentVNode("", true)]),
52
52
  _: 1
53
53
  })], 2)
54
- ]), createElementVNode("div", _hoisted_2, [createVNode(unref(IconArrow_default), { class: normalizeClass(["text-accent square-[1.25em] transition-transform", { "rotate-180": __props.isOpen }]) }, null, 8, ["class"])])]),
54
+ ]), createElementVNode("div", _hoisted_2, [createVNode(unref(IconArrow_default), { class: normalizeClass(["text-accent square-[1.25em] motion-safe:transition-transform", { "rotate-180": __props.isOpen }]) }, null, 8, ["class"])])]),
55
55
  _: 1
56
56
  }, 40, ["aria-expanded", "class"])), createVNode(WExpansion_default, {
57
57
  "is-open": __props.isOpen,
@@ -10,7 +10,7 @@ var FilePickerSvg_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
10
10
  stroke: "currentColor",
11
11
  "stroke-linecap": "round",
12
12
  "stroke-dasharray": "4px 8px",
13
- "rect-class": __props.animate ? "animate-border-march" : void 0
13
+ "rect-class": __props.animate ? "motion-safe:animate-border-march" : void 0
14
14
  }, null, 8, ["rect-class"]);
15
15
  };
16
16
  }
@@ -303,7 +303,7 @@ var InfiniteListPage_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
303
303
  default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(slotList.value, (slot, slotIndex) => {
304
304
  return openBlock(), createElementBlock("div", {
305
305
  key: slot.key,
306
- class: "grid w-full transition-[grid-template-rows] duration-300"
306
+ class: "grid w-full motion-safe:transition-[grid-template-rows] motion-safe:duration-300"
307
307
  }, [createElementVNode("div", _hoisted_4, [createVNode(InfiniteListPageItem_default, {
308
308
  ref_for: true,
309
309
  ref: (item) => setItemRef(slot.key, item)
@@ -714,7 +714,7 @@ var WInput_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCom
714
714
  default: withCtx(() => [unref(asyncState).timeout.value ? (openBlock(), createElementBlock("div", _hoisted_8)) : createCommentVNode("", true)]),
715
715
  _: 1
716
716
  }), createVNode(Transition, {
717
- "enter-active-class": "transition-[width] ease-linear rounded-sm duration-(--debounce-duration)",
717
+ "enter-active-class": "motion-safe:transition-[width] ease-linear rounded-sm motion-safe:duration-(--debounce-duration)",
718
718
  "enter-from-class": "w-0",
719
719
  "enter-to-class": "w-full",
720
720
  "leave-active-class": "hidden"
@@ -243,7 +243,7 @@ var WInputSuggest_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
243
243
  disabled: unref(isDisabled),
244
244
  onClick: ($event) => isOpen.value ? toggleScope.unclickable === false ? close() : blur() : focus()
245
245
  }, {
246
- default: withCtx(() => [createVNode(unref(IconArrow_default), { class: normalizeClass(["square-3 text-description transition-transform", { "rotate-180": isOpen.value }]) }, null, 8, ["class"])]),
246
+ default: withCtx(() => [createVNode(unref(IconArrow_default), { class: normalizeClass(["square-3 text-description motion-safe:transition-transform", { "rotate-180": isOpen.value }]) }, null, 8, ["class"])]),
247
247
  _: 1
248
248
  }, 8, [
249
249
  "expanded",
@@ -62,7 +62,7 @@ var WListHeaderItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
62
62
  "enter-from-class": "opacity-0",
63
63
  "leave-to-class": "opacity-0"
64
64
  }, {
65
- default: withCtx(() => [index.value !== -1 ? (openBlock(), createElementBlock("div", _hoisted_1, [createVNode(unref(IconBack_default), { class: normalizeClass(["square-3 transition-transform", {
65
+ default: withCtx(() => [index.value !== -1 ? (openBlock(), createElementBlock("div", _hoisted_1, [createVNode(unref(IconBack_default), { class: normalizeClass(["square-3 motion-safe:transition-transform", {
66
66
  "rotate-90": __props.ordering[index.value]?.order === "ASC",
67
67
  "-rotate-90": __props.ordering[index.value]?.order === "DESC"
68
68
  }]) }, null, 8, ["class"]), __props.ordering.length > 1 ? (openBlock(), createElementBlock("div", _hoisted_2, toDisplayString(index.value + 1), 1)) : createCommentVNode("", true)])) : createCommentVNode("", true)]),
@@ -45,7 +45,7 @@ var HeaderSortItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
45
45
  }, {
46
46
  default: withCtx(() => [index.value !== -1 ? (openBlock(), createBlock(unref(IconBack_default), {
47
47
  key: 0,
48
- class: normalizeClass(["square-4 transition-transform", {
48
+ class: normalizeClass(["square-4 motion-safe:transition-transform", {
49
49
  "rotate-90": __props.ordering[index.value]?.order === "ASC",
50
50
  "-rotate-90": __props.ordering[index.value]?.order === "DESC"
51
51
  }])
@@ -61,7 +61,7 @@ var ListFilterChip_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
61
61
  badge.value ? (openBlock(), createElementBlock("span", _hoisted_3, toDisplayString(badge.value), 1)) : createCommentVNode("", true),
62
62
  !hasValue.value ? (openBlock(), createBlock(unref(IconArrow_default), {
63
63
  key: 3,
64
- class: normalizeClass(["square-[1em] text-description shrink-0 transition-transform", { "rotate-180": __props.isOpen }])
64
+ class: normalizeClass(["square-[1em] text-description shrink-0 motion-safe:transition-transform", { "rotate-180": __props.isOpen }])
65
65
  }, null, 8, ["class"])) : createCommentVNode("", true)
66
66
  ], 10, _hoisted_1), isRemovable.value ? (openBlock(), createElementBlock("button", {
67
67
  key: 0,
@@ -130,7 +130,7 @@ var ListItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineC
130
130
  }, [
131
131
  __props.mobile ? (openBlock(), createElementBlock("div", {
132
132
  key: 0,
133
- class: normalizeClass(["tone-primary bg-tone-fill @sm:hidden pointer-events-none absolute left-0 top-0 h-full w-2 transition-[translate,opacity] duration-200", { "-translate-x-2 opacity-0": !__props.selected }])
133
+ class: normalizeClass(["tone-primary bg-tone-fill @sm:hidden pointer-events-none absolute left-0 top-0 h-full w-2 motion-safe:transition-[translate,opacity] motion-safe:duration-200", { "-translate-x-2 opacity-0": !__props.selected }])
134
134
  }, null, 2)) : createCommentVNode("", true),
135
135
  !__props.card ? (openBlock(), createElementBlock("div", {
136
136
  key: 1,
@@ -128,8 +128,8 @@ var WModal_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCom
128
128
  _: 1
129
129
  }),
130
130
  createVNode(TransitionGroup, {
131
- "enter-active-class": "transition-all duration-300",
132
- "leave-active-class": "transition-all duration-300",
131
+ "enter-active-class": "motion-safe:transition-all motion-safe:duration-300",
132
+ "leave-active-class": "motion-safe:transition-all motion-safe:duration-300",
133
133
  "enter-from-class": "translate-y-8 opacity-0",
134
134
  "leave-to-class": "-translate-y-5 opacity-0"
135
135
  }, {
@@ -56,7 +56,7 @@ var WNavBar_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
56
56
  }),
57
57
  createElementVNode("nav", {
58
58
  ref: "nav",
59
- class: normalizeClass(["w-nav-bar fixed left-(--w-left-margin,0px) top-0 flex h-full flex-col overflow-hidden transition-[clip-path] duration-200 [clip-path:inset(-2rem)] print:hidden", [{ "xl-not:[clip-path:inset(-2rem_calc(100%+2rem)_-2rem_-2rem)]": !isOpen.value }, _ctx.$attrs.class]]),
59
+ class: normalizeClass(["w-nav-bar fixed left-(--w-left-margin,0px) top-0 flex h-full flex-col overflow-hidden motion-safe:transition-[clip-path] motion-safe:duration-200 [clip-path:inset(-2rem)] print:hidden", [{ "xl-not:[clip-path:inset(-2rem_calc(100%+2rem)_-2rem_-2rem)]": !isOpen.value }, _ctx.$attrs.class]]),
60
60
  style: normalizeStyle({ zIndex: unref(30) })
61
61
  }, [
62
62
  _ctx.$slots.brand && __props.brandTo ? (openBlock(), createBlock(WRouterLink_default, {
@@ -79,8 +79,8 @@ var WNavItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineC
79
79
  }, {
80
80
  default: withCtx(() => [
81
81
  createVNode(Transition, {
82
- "enter-active-class": "transition-transform duration-200",
83
- "leave-active-class": "transition-transform duration-200",
82
+ "enter-active-class": "motion-safe:transition-transform motion-safe:duration-200",
83
+ "leave-active-class": "motion-safe:transition-transform motion-safe:duration-200",
84
84
  "enter-from-class": "-translate-x-1",
85
85
  "leave-to-class": "-translate-x-1"
86
86
  }, {
@@ -87,7 +87,7 @@ var WNavItemExpand_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
87
87
  "param-fields": __props.paramFields,
88
88
  hovered: unref(isDropdownOpen) && !hasActive.value
89
89
  }), createSlots({
90
- right: withCtx(() => [createVNode(unref(IconArrow_default), { class: normalizeClass(["square-3 transition-transform", { "-rotate-90": !hasActive.value && !__props.even }]) }, null, 8, ["class"])]),
90
+ right: withCtx(() => [createVNode(unref(IconArrow_default), { class: normalizeClass(["square-3 motion-safe:transition-transform", { "-rotate-90": !hasActive.value && !__props.even }]) }, null, 8, ["class"])]),
91
91
  _: 2
92
92
  }, [_ctx.$slots.icon ? {
93
93
  name: "icon",
@@ -5,10 +5,10 @@ var WNavItemTransition_vue_vue_type_script_setup_true_lang_default = /*@__PURE__
5
5
  setup(__props) {
6
6
  return (_ctx, _cache) => {
7
7
  return openBlock(), createBlock(TransitionGroup, {
8
- "enter-active-class": "transition-[grid-template-rows] overflow-hidden grid",
8
+ "enter-active-class": "motion-safe:transition-[grid-template-rows] overflow-hidden grid",
9
9
  "enter-from-class": "grid-rows-[0fr]",
10
10
  "enter-to-class": "grid-rows-[1fr]",
11
- "leave-active-class": "transition-[grid-template-rows] overflow-hidden grid",
11
+ "leave-active-class": "motion-safe:transition-[grid-template-rows] overflow-hidden grid",
12
12
  "leave-from-class": "grid-rows-[1fr]",
13
13
  "leave-to-class": "grid-rows-[0fr]"
14
14
  }, {
@@ -37,7 +37,7 @@ var WNotify_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
37
37
  default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(notifyCenterToastEntries), (item) => {
38
38
  return openBlock(), createElementBlock("div", {
39
39
  key: unref(getNotifyItemKey)(item),
40
- class: normalizeClass(["grid transition-[translate,opacity,grid-template-rows] duration-300", isCenter.value ? "justify-center" : "justify-end"])
40
+ class: normalizeClass(["grid motion-safe:transition-[translate,opacity,grid-template-rows] motion-safe:duration-300", isCenter.value ? "justify-center" : "justify-end"])
41
41
  }, [createElementVNode("div", _hoisted_1, [createVNode(NotifyCard_default, {
42
42
  item,
43
43
  "onClick:close": _cache[0] || (_cache[0] = (entry) => (entry.items ?? [entry]).forEach((value) => unref(hideToast)(value.id)))
@@ -80,7 +80,7 @@ var WNotifyCenter_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
80
80
  default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(notifyCenterActionEntries), (item) => {
81
81
  return openBlock(), createElementBlock("div", {
82
82
  key: unref(getNotifyItemKey)(item),
83
- class: "grid transition-[transform,grid-template-rows] duration-300"
83
+ class: "grid motion-safe:transition-[transform,grid-template-rows] motion-safe:duration-300"
84
84
  }, [createElementVNode("div", _hoisted_6, [createVNode(NotifyCard_default, {
85
85
  item,
86
86
  history: "",
@@ -110,7 +110,7 @@ var WNotifyCenter_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
110
110
  default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(notifyCenterActivityEntries), (item) => {
111
111
  return openBlock(), createElementBlock("div", {
112
112
  key: unref(getNotifyItemKey)(item),
113
- class: "grid transition-[transform,grid-template-rows] duration-300"
113
+ class: "grid motion-safe:transition-[transform,grid-template-rows] motion-safe:duration-300"
114
114
  }, [createElementVNode("div", _hoisted_8, [createVNode(NotifyCard_default, {
115
115
  item,
116
116
  history: "",
@@ -7,7 +7,7 @@ var WProgress_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
7
7
  setup(__props) {
8
8
  return (_ctx, _cache) => {
9
9
  return openBlock(), createElementBlock("div", _hoisted_1, [createElementVNode("div", {
10
- class: "tone-primary bg-tone-fill h-full transition-[width]",
10
+ class: "tone-primary bg-tone-fill h-full motion-safe:transition-[width]",
11
11
  style: normalizeStyle({ width: __props.modelValue + "%" })
12
12
  }, null, 4)]);
13
13
  };
@@ -7,7 +7,7 @@ import { Fragment, computed, createCommentVNode, createElementBlock, createEleme
7
7
  var _hoisted_1 = ["aria-valuenow", "aria-busy"];
8
8
  var _hoisted_2 = {
9
9
  key: 0,
10
- class: "animate-ticker absolute inset-0 bg-linear-to-r from-transparent via-white/30 to-transparent [--tiker-duration:1.6s]"
10
+ class: "motion-safe:animate-ticker absolute inset-0 bg-linear-to-r from-transparent via-white/30 to-transparent [--tiker-duration:1.6s]"
11
11
  };
12
12
  var _hoisted_3 = { class: "text-accent relative flex h-full items-center justify-center" };
13
13
  var _hoisted_4 = { class: "text-description relative flex h-full items-center justify-center gap-2 font-medium" };
@@ -30,16 +30,16 @@ var WProgressBar_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
30
30
  "aria-busy": __props.modelValue === null || __props.modelValue < 1
31
31
  }, [__props.modelValue !== null ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
32
32
  createElementVNode("div", {
33
- class: normalizeClass(["absolute inset-y-0 left-0 overflow-hidden rounded-xl transition-[width] duration-500 ease-out", unref(progressBarClass)[__props.semanticType]]),
33
+ class: normalizeClass(["absolute inset-y-0 left-0 overflow-hidden rounded-xl motion-safe:transition-[width] motion-safe:duration-500 ease-out", unref(progressBarClass)[__props.semanticType]]),
34
34
  style: normalizeStyle({ width: percent.value })
35
35
  }, [__props.modelValue < 1 ? (openBlock(), createElementBlock("div", _hoisted_2)) : createCommentVNode("", true)], 6),
36
36
  createElementVNode("div", _hoisted_3, toDisplayString(percent.value), 1),
37
37
  createElementVNode("div", {
38
38
  "aria-hidden": "true",
39
- class: normalizeClass(["absolute inset-0 flex items-center justify-center transition-[clip-path] duration-500 ease-out", unref(progressBarTextClass)[__props.semanticType]]),
39
+ class: normalizeClass(["absolute inset-0 flex items-center justify-center motion-safe:transition-[clip-path] motion-safe:duration-500 ease-out", unref(progressBarTextClass)[__props.semanticType]]),
40
40
  style: normalizeStyle({ clipPath: `inset(0 calc(100% - ${percent.value}) 0 0)` })
41
41
  }, toDisplayString(percent.value), 7)
42
- ], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createElementVNode("div", { class: normalizeClass(["animate-ticker absolute inset-0 bg-linear-to-r from-transparent to-transparent [--tiker-duration:1.4s]", unref(progressBarIndeterminateClass)[__props.semanticType]]) }, null, 2), createElementVNode("div", _hoisted_4, [createVNode(WSpinner_default, { class: "square-4" }), _cache[0] || (_cache[0] = createElementVNode("span", null, "In progress", -1))])], 64))], 8, _hoisted_1);
42
+ ], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createElementVNode("div", { class: normalizeClass(["motion-safe:animate-ticker absolute inset-0 bg-linear-to-r from-transparent to-transparent [--tiker-duration:1.4s]", unref(progressBarIndeterminateClass)[__props.semanticType]]) }, null, 2), createElementVNode("div", _hoisted_4, [createVNode(WSpinner_default, { class: "square-4" }), _cache[0] || (_cache[0] = createElementVNode("span", null, "In progress", -1))])], 64))], 8, _hoisted_1);
43
43
  };
44
44
  }
45
45
  });
@@ -3,7 +3,7 @@ import { createElementBlock, createElementVNode, defineComponent, normalizeClass
3
3
  var _hoisted_1 = ["aria-valuenow", "aria-busy"];
4
4
  var _hoisted_2 = {
5
5
  key: 0,
6
- class: "animate-ticker tone-primary via-tone/60 absolute inset-0 bg-linear-to-r from-transparent to-transparent [--tiker-duration:1.4s]"
6
+ class: "motion-safe:animate-ticker tone-primary via-tone/60 absolute inset-0 bg-linear-to-r from-transparent to-transparent [--tiker-duration:1.4s]"
7
7
  };
8
8
  var WProgressStriped_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
9
9
  __name: "WProgressStriped",
@@ -19,9 +19,9 @@ var WProgressStriped_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
19
19
  "aria-busy": __props.modelValue < 100
20
20
  }, [__props.modelValue <= 0 ? (openBlock(), createElementBlock("div", _hoisted_2)) : (openBlock(), createElementBlock("div", {
21
21
  key: 1,
22
- class: "from-primary-dark to-primary relative h-full overflow-hidden rounded-full bg-linear-to-r transition-[width] duration-500 ease-out",
22
+ class: "from-primary-dark to-primary relative h-full overflow-hidden rounded-full bg-linear-to-r motion-safe:transition-[width] motion-safe:duration-500 ease-out",
23
23
  style: normalizeStyle({ width: Math.min(__props.modelValue, 100) + "%" })
24
- }, [createElementVNode("div", { class: normalizeClass(["absolute inset-0", __props.modelValue < 100 ? "animate-ticker bg-linear-to-r from-transparent via-white/40 to-transparent [--tiker-duration:1.6s]" : "bg-default/30 animate-pulse"]) }, null, 2)], 4))], 10, _hoisted_1);
24
+ }, [createElementVNode("div", { class: normalizeClass(["absolute inset-0", __props.modelValue < 100 ? "motion-safe:animate-ticker bg-linear-to-r from-transparent via-white/40 to-transparent [--tiker-duration:1.6s]" : "bg-default/30 motion-safe:animate-pulse"]) }, null, 2)], 4))], 10, _hoisted_1);
25
25
  };
26
26
  }
27
27
  });
@@ -15,7 +15,7 @@ var WSkeleton_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
15
15
  });
16
16
  return (_ctx, _cache) => {
17
17
  return openBlock(), createElementBlock("div", {
18
- class: "tone-primary bg-tone-soft w-skeleton w-skeleton-opacity-50 dark:w-skeleton-opacity-5 before:animate-ticker w-option-has-bg",
18
+ class: "tone-primary bg-tone-soft w-skeleton w-skeleton-opacity-50 dark:w-skeleton-opacity-5 motion-safe:before:animate-ticker w-option-has-bg",
19
19
  style: normalizeStyle({ "--skeleton-width-internal": skeletonWidth.value + "%" })
20
20
  }, [renderSlot(_ctx.$slots, "default")], 4);
21
21
  };
@@ -102,7 +102,7 @@ var WSlider_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
102
102
  "bg-track-strong": __props.disabled
103
103
  }]),
104
104
  style: normalizeStyle({ width: `${rangeScale(cursor.value ?? __props.modelValue) * 100}%` })
105
- }, [createElementVNode("div", { class: normalizeClass(["square-4 relative right-0 -mr-2 rounded-full bg-inherit transition-transform", {
105
+ }, [createElementVNode("div", { class: normalizeClass(["square-4 relative right-0 -mr-2 rounded-full bg-inherit motion-safe:transition-transform", {
106
106
  "scale-180": isMoveStarted.value,
107
107
  "hover:scale-200": !__props.readonly && !isMoveStarted.value
108
108
  }]) }, null, 2)], 6)], 512), createVNode(Transition, {
@@ -124,11 +124,11 @@ var WSliderRange_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
124
124
  })
125
125
  }, [
126
126
  !__props.disabled ? (openBlock(), createElementBlock("div", _hoisted_3)) : createCommentVNode("", true),
127
- createElementVNode("div", { class: normalizeClass(["square-4 absolute left-0 -ml-2 rounded-full bg-(--w-slider-from,var(--color-primary)) transition-transform", {
127
+ createElementVNode("div", { class: normalizeClass(["square-4 absolute left-0 -ml-2 rounded-full bg-(--w-slider-from,var(--color-primary)) motion-safe:transition-transform", {
128
128
  "scale-180": isCursorFrom.value === true,
129
129
  "hover:scale-200": !__props.readonly && isCursorFrom.value === null
130
130
  }]) }, null, 2),
131
- createElementVNode("div", { class: normalizeClass(["square-4 absolute right-0 -mr-2 rounded-full bg-(--w-slider-to,var(--color-primary)) transition-transform", {
131
+ createElementVNode("div", { class: normalizeClass(["square-4 absolute right-0 -mr-2 rounded-full bg-(--w-slider-to,var(--color-primary)) motion-safe:transition-transform", {
132
132
  "scale-180": isCursorFrom.value === false,
133
133
  "hover:scale-200": !__props.readonly && isCursorFrom.value === null
134
134
  }]) }, null, 2)
@@ -6,7 +6,7 @@ var _hoisted_1 = {
6
6
  width: "20",
7
7
  height: "20",
8
8
  viewBox: "0 0 24 24",
9
- class: "animate-spin"
9
+ class: "motion-safe:animate-spin"
10
10
  };
11
11
  function _sfc_render(_ctx, _cache) {
12
12
  return openBlock(), createElementBlock("svg", _hoisted_1, [..._cache[0] || (_cache[0] = [createElementVNode("circle", {
@@ -484,7 +484,7 @@ var WTabs_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComp
484
484
  ]);
485
485
  }), 128)) : defaultSlots.value.some((slot) => slot.children?.default) ? (openBlock(), createElementBlock("div", {
486
486
  key: 1,
487
- class: normalizeClass(["relative h-full transition-[min-height] duration-300", {
487
+ class: normalizeClass(["relative h-full motion-safe:transition-[min-height] motion-safe:duration-300", {
488
488
  "[overflow-anchor:none]": isSwitching.value,
489
489
  "surface-section-joined": !__props.side && __props.section && !joined,
490
490
  "sm-not:snap-start sm-not:px-(--w-frame-padding,var(--inner-margin))": __props.side
@@ -494,8 +494,8 @@ var WTabs_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComp
494
494
  "--direction-factor": isDirect.value ? "1" : "-1"
495
495
  })
496
496
  }, [createVNode(TransitionGroup, {
497
- "enter-active-class": "transition-[translate,opacity] duration-250 w-full [overflow-anchor:none]",
498
- "leave-active-class": "transition-[translate,opacity] duration-250 w-full absolute top-0 [overflow-anchor:none]",
497
+ "enter-active-class": "motion-safe:transition-[translate,opacity] motion-safe:duration-250 w-full [overflow-anchor:none]",
498
+ "leave-active-class": "motion-safe:transition-[translate,opacity] motion-safe:duration-250 w-full absolute top-0 [overflow-anchor:none]",
499
499
  "enter-from-class": __props.lessTransitions || __props.side || unref(hasScrollbar) ? "opacity-0" : "opacity-0 translate-x-[calc((100%+var(--inner-margin))*var(--direction-factor))]",
500
500
  "leave-to-class": __props.lessTransitions || __props.side || unref(hasScrollbar) ? "opacity-0 absolute" : "opacity-0 translate-x-[calc((100%+var(--inner-margin))*var(--direction-factor)*-1)]",
501
501
  onAfterEnter: _cache[1] || (_cache[1] = ($event) => isSwitching.value = false),
@@ -29,7 +29,7 @@ var WTextOverflow_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
29
29
  onMouseenter: updateOverflow
30
30
  }, [createElementVNode("span", _hoisted_1, [renderSlot(_ctx.$slots, "default")]), createElementVNode("div", {
31
31
  ref: "element",
32
- class: normalizeClass(["absolute inset-y-0 left-0", { "delay-300 group-hover/overflow:translate-x-(--text-overflow,0px) group-hover/overflow:transition-transform group-hover/overflow:duration-(--text-overflow-duration,150ms) group-hover/overflow:ease-linear": overflow.value }]),
32
+ class: normalizeClass(["absolute inset-y-0 left-0", { "delay-300 group-hover/overflow:translate-x-(--text-overflow,0px) motion-safe:group-hover/overflow:transition-transform motion-safe:group-hover/overflow:duration-(--text-overflow-duration,150ms) group-hover/overflow:ease-linear": overflow.value }]),
33
33
  style: normalizeStyle(overflow.value ? {
34
34
  "--text-overflow": `-${overflow.value}px`,
35
35
  "--text-overflow-duration": `${overflow.value * 30}ms`
@@ -111,7 +111,7 @@ var WToggle_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
111
111
  }, [renderSlot(_ctx.$slots, "title", {}, () => [createTextVNode(toDisplayString(__props.title), 1)])], 2)) : createCommentVNode("", true), createElementVNode("div", _hoisted_2, [createElementVNode("div", { class: normalizeClass(["width-[calc(var(--w-input-height)+0.5rem)] p-0.75 h-full rounded-full bg-size-[200%_auto] bg-right", {
112
112
  "bg-track": !value.value || __props.loading,
113
113
  [unref(semanticTypeBackgroundMap)[unref(SemanticType).PRIMARY]]: value.value && !__props.loading
114
- }]) }, [createElementVNode("div", _hoisted_3, [createElementVNode("div", { class: normalizeClass(["tone-primary text-tone scheme-light absolute z-10 flex aspect-square h-full items-center justify-center rounded-full bg-(--w-toggle-caret,#ffffff) shadow-md transition-[right]", {
114
+ }]) }, [createElementVNode("div", _hoisted_3, [createElementVNode("div", { class: normalizeClass(["tone-primary text-tone scheme-light absolute z-10 flex aspect-square h-full items-center justify-center rounded-full bg-(--w-toggle-caret,#ffffff) shadow-md motion-safe:transition-[right]", {
115
115
  "right-[calc(100%-(var(--w-input-height)-0.75rem))]": value.value === false,
116
116
  "right-[calc(50%-(var(--w-input-height)-0.75rem)/2)]": value.value === null,
117
117
  "right-0": value.value === true,
package/docs/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # eco-vue-js
2
2
 
3
- > Vue 3 UI kit with Tailwind v4 — components, utilities, icons and recipes. These are the docs of version 0.27.3, the one installed next to them. Start with Getting started and Conventions; each component page lists its props, events and slots with examples.
3
+ > Vue 3 UI kit with Tailwind v4 — components, utilities, icons and recipes. These are the docs of version 0.28.0, the one installed next to them. Start with Getting started and Conventions; each component page lists its props, events and slots with examples.
4
4
 
5
5
  Release notes, for what changed between versions: https://github.com/rsmple/eco-vue-js/releases. The docs site, with live demos: https://rsmple.github.io/eco-vue-js/
6
6
 
package/eslint/plugin.js CHANGED
@@ -1,7 +1,9 @@
1
+ import motionCss from './processors/motion-css.js'
1
2
  import recommended from './recommended.js'
2
3
  import modalDeclaration from './rules/modal-declaration.js'
3
4
  import modalImportAsync from './rules/modal-import-async.js'
4
5
  import modalImport from './rules/modal-import.js'
6
+ import motionSafe from './rules/motion-safe.js'
5
7
  import uiKitImports from './rules/ui-kit-imports.js'
6
8
 
7
9
  const plugin = {
@@ -9,9 +11,14 @@ const plugin = {
9
11
  'modal-declaration': modalDeclaration,
10
12
  'modal-import-async': modalImportAsync,
11
13
  'modal-import': modalImport,
14
+ 'motion-safe': motionSafe,
12
15
  'ui-kit-imports': uiKitImports,
13
16
  },
14
17
 
18
+ processors: {
19
+ 'motion-css': motionCss(),
20
+ },
21
+
15
22
  configs: {},
16
23
  }
17
24
 
@@ -41,10 +48,33 @@ const customRules = {
41
48
  },
42
49
  }
43
50
 
51
+ const motionRules = (config = {}) => [
52
+ {
53
+ name: 'custom-rules/motion',
54
+ files: config.astro ? ['**/*.{ts,js,vue,astro}'] : ['**/*.{ts,js,vue}'],
55
+ plugins: {
56
+ 'custom-rules': plugin,
57
+ },
58
+ rules: {
59
+ 'custom-rules/motion-safe': ['warn'],
60
+ },
61
+ },
62
+ {
63
+ name: 'custom-rules/motion-css',
64
+ files: ['**/*.css'],
65
+ plugins: {
66
+ 'custom-rules': plugin,
67
+ },
68
+ processor: 'custom-rules/motion-css',
69
+ },
70
+ ]
71
+
72
+ plugin.configs.motion = motionRules
73
+
44
74
  plugin.configs.recommended = (config = {}) => [
45
75
  ...recommended(config),
46
76
 
47
- ...config.noCustom ? [] : [customRules],
77
+ ...config.noCustom ? [] : [customRules, ...motionRules(config)],
48
78
  ]
49
79
 
50
80
  export default plugin
@@ -0,0 +1,42 @@
1
+ import {checkCss} from '../rules/motion/css.js'
2
+
3
+ const RULE_ID = 'custom-rules/motion-safe'
4
+ const MESSAGE = 'runs under reduced motion. Put it inside `@media (prefers-reduced-motion: no-preference)` or `@variant motion-safe`; in `@apply`, prefix the class with `motion-safe:`.'
5
+
6
+ /**
7
+ * Checks `.css` files for motion outside a reduced-motion query. It hands ESLint no code blocks, so no
8
+ * other rule runs on CSS: rules a consumer configures without `files` would otherwise crash on it.
9
+ */
10
+ export default ({severity = 1, allow = []} = {}) => {
11
+ const pending = new Map()
12
+
13
+ return {
14
+ meta: {name: 'motion-css'},
15
+
16
+ preprocess(text, filename) {
17
+ const messages = []
18
+
19
+ checkCss(text, {ruleId: RULE_ID, allow}, ({start, end}, token) => {
20
+ messages.push({
21
+ ruleId: RULE_ID,
22
+ severity,
23
+ message: `\`${ token }\` ${ MESSAGE }`,
24
+ line: start.line,
25
+ column: start.column + 1,
26
+ endLine: end.line,
27
+ endColumn: end.column + 1,
28
+ })
29
+ })
30
+
31
+ pending.set(filename, messages)
32
+
33
+ return []
34
+ },
35
+
36
+ postprocess(_, filename) {
37
+ const messages = pending.get(filename) ?? []
38
+ pending.delete(filename)
39
+ return messages
40
+ },
41
+ }
42
+ }
@@ -0,0 +1,74 @@
1
+ const MOTION = /^(?:transition(?:-(?:all|colors|opacity|shadow|transform|\[.+\]|\(.+\)))?|animate-(?!none$)[\w-[\]().,%/]+|scroll-smooth)$/
2
+ // Class lists never hold sentence punctuation; UI copy such as "Status transition failed." does.
3
+ const PROSE = /[`;?]|[.,:](?:\s|$)/
4
+ const DURATION = /^duration-(?!0$|initial$)(?:\d+|\[.+\]|\(.+\))$/
5
+
6
+ // Fading or recolouring is not motion, so it may still play when the OS asks for reduced motion.
7
+ export const FADE_UTILITIES = ['transition-opacity', 'transition-colors', 'transition-shadow']
8
+ export const FADE_PROPERTIES = [
9
+ 'opacity',
10
+ 'color',
11
+ 'background-color',
12
+ 'border-color',
13
+ 'outline-color',
14
+ 'text-decoration-color',
15
+ 'fill',
16
+ 'stroke',
17
+ 'box-shadow',
18
+ ]
19
+
20
+ const isFade = utility => {
21
+ if (FADE_UTILITIES.includes(utility)) return true
22
+
23
+ const properties = utility.match(/^transition-\[(.+)\]$/)?.[1].split(',')
24
+
25
+ return !!properties && properties.every(property => FADE_PROPERTIES.includes(property.trim()))
26
+ }
27
+
28
+ const splitVariants = token => {
29
+ const parts = []
30
+ let depth = 0
31
+ let start = 0
32
+
33
+ for (let i = 0; i < token.length; i++) {
34
+ const char = token[i]
35
+ if (char === '[' || char === '(') depth++
36
+ else if (char === ']' || char === ')') depth--
37
+ else if (char === ':' && depth === 0) {
38
+ parts.push(token.slice(start, i))
39
+ start = i + 1
40
+ }
41
+ }
42
+
43
+ parts.push(token.slice(start))
44
+
45
+ return parts
46
+ }
47
+
48
+ /**
49
+ * Returns `{token, duration}` for each class that would still animate under reduced motion. `duration` marks a
50
+ * `duration-*` class with no ungated transition property beside it: `transition-property` defaults to `all`, so on
51
+ * its own it transitions every property.
52
+ */
53
+ export const findUngated = (value, allow) => {
54
+ if (PROSE.test(value)) return []
55
+
56
+ const tokens = value.split(/\s+/).filter(Boolean).map(token => {
57
+ const parts = splitVariants(token)
58
+ return {token, utility: parts.pop().replace(/^!|!$/g, ''), gated: parts.includes('motion-safe')}
59
+ })
60
+
61
+ if (tokens.some(({token}) => splitVariants(token).includes('motion-reduce'))) return []
62
+
63
+ const hasStillProperty = tokens.some(({utility, gated}) => !gated && (utility === 'transition-none' || isFade(utility)))
64
+ const found = []
65
+
66
+ for (const {token, utility, gated} of tokens) {
67
+ if (gated || allow.includes(utility)) continue
68
+
69
+ if (MOTION.test(utility) && !isFade(utility)) found.push({token, duration: false})
70
+ else if (DURATION.test(utility) && !hasStillProperty) found.push({token, duration: true})
71
+ }
72
+
73
+ return found
74
+ }
@@ -0,0 +1,196 @@
1
+ import {fork} from '@eslint/css-tree'
2
+ import {tailwind4} from 'tailwind-csstree'
3
+
4
+ import {FADE_PROPERTIES, findUngated} from './classes.js'
5
+
6
+ const {parse, generate} = fork(tailwind4)
7
+
8
+ const GATES = [
9
+ /prefers-reduced-motion:\s*(?:no-preference|reduce)/,
10
+ ]
11
+
12
+ const isGate = atrule => {
13
+ const name = atrule.name.toLowerCase()
14
+ const prelude = atrule.prelude ? generate(atrule.prelude) : ''
15
+
16
+ if (name === 'media') return GATES.some(gate => gate.test(prelude))
17
+ if (name === 'variant') return /^motion-(?:safe|reduce)$/.test(prelude.trim())
18
+
19
+ return false
20
+ }
21
+
22
+ const unprefixed = property => property.toLowerCase().replace(/^-(?:webkit|moz|ms|o)-/, '')
23
+
24
+ const splitTopLevel = value => {
25
+ const parts = []
26
+ let depth = 0
27
+ let start = 0
28
+
29
+ for (let i = 0; i < value.length; i++) {
30
+ const char = value[i]
31
+ if (char === '(') depth++
32
+ else if (char === ')') depth--
33
+ else if (char === ',' && depth === 0) {
34
+ parts.push(value.slice(start, i).trim())
35
+ start = i + 1
36
+ }
37
+ }
38
+
39
+ parts.push(value.slice(start).trim())
40
+
41
+ return parts.filter(Boolean)
42
+ }
43
+
44
+ const RESET = /^(?:none|initial|unset|revert|revert-layer)$/i
45
+ const ZERO = /^(?:0|0?\.0+|0+)(?:m?s)?$/
46
+
47
+ const transitionedProperties = (property, value) => {
48
+ if (property === 'transition-property') return splitTopLevel(value)
49
+
50
+ return splitTopLevel(value).map(item => {
51
+ const words = item.split(/\s+/).filter(word => !/^[\d.]/.test(word) && !/\(/.test(word))
52
+ return words.find(word => !/^(?:ease|ease-in|ease-out|ease-in-out|linear|step-start|step-end|normal|allow-discrete)$/i.test(word)) ?? 'all'
53
+ })
54
+ }
55
+
56
+ /**
57
+ * Walks a parsed stylesheet and reports motion that is not inside a reduced-motion query.
58
+ * `report(node, token)` gets the offending declaration or `@apply` rule.
59
+ */
60
+ export const checkStylesheet = (stylesheet, report, allow = []) => {
61
+ const checkDeclaration = (declaration, siblings) => {
62
+ const property = unprefixed(declaration.property)
63
+ const value = generate(declaration.value).trim()
64
+
65
+ if (property === 'scroll-behavior') {
66
+ if (value.toLowerCase() === 'smooth') report(declaration, 'scroll-behavior: smooth')
67
+ return
68
+ }
69
+
70
+ if (property === 'animation' || property === 'animation-name') {
71
+ if (!RESET.test(value)) report(declaration, `${ declaration.property }: ${ value }`)
72
+ return
73
+ }
74
+
75
+ if (property === 'transition' || property === 'transition-property') {
76
+ if (RESET.test(value)) return
77
+
78
+ const properties = transitionedProperties(property, value).map(item => item.toLowerCase())
79
+ if (properties.every(item => FADE_PROPERTIES.includes(item))) return
80
+
81
+ report(declaration, `${ declaration.property }: ${ value }`)
82
+ return
83
+ }
84
+
85
+ if (property === 'transition-duration') {
86
+ if (splitTopLevel(value).every(item => ZERO.test(item))) return
87
+ if (siblings.some(item => ['transition', 'transition-property'].includes(unprefixed(item.property)))) return
88
+
89
+ report(declaration, `${ declaration.property }: ${ value } (transitions all properties)`)
90
+ }
91
+ }
92
+
93
+ const visitChildren = (list, gated) => {
94
+ const nodes = Array.isArray(list) ? list : list?.toArray?.() ?? []
95
+ const declarations = nodes.filter(node => node.type === 'Declaration')
96
+
97
+ for (const node of nodes) {
98
+ if (node.type === 'Declaration') {
99
+ if (!gated) checkDeclaration(node, declarations)
100
+ } else {
101
+ visit(node, gated)
102
+ }
103
+ }
104
+ }
105
+
106
+ const visit = (node, gated) => {
107
+ switch (node.type) {
108
+ case 'StyleSheet':
109
+ case 'Block':
110
+ visitChildren(node.children, gated)
111
+ break
112
+ case 'Rule':
113
+ visit(node.block, gated)
114
+ break
115
+ case 'Atrule': {
116
+ const name = node.name.toLowerCase()
117
+
118
+ if (name === 'keyframes' || name.endsWith('-keyframes')) return
119
+
120
+ if (name === 'apply') {
121
+ if (gated || !node.prelude) return
122
+ for (const {token, duration} of findUngated(generate(node.prelude), allow)) {
123
+ report(node, duration ? `${ token } (transitions all properties)` : token)
124
+ }
125
+ return
126
+ }
127
+
128
+ if (node.block) visit(node.block, gated || isGate(node))
129
+ break
130
+ }
131
+ }
132
+ }
133
+
134
+ visit(stylesheet, false)
135
+ }
136
+
137
+ const STYLE_BLOCK = /<style\b([^>]*)>([\s\S]*?)<\/style\s*>/gi
138
+ const SKIPPED_LANG = /\blang\s*=\s*["']?(?:scss|sass|less|stylus|styl)\b/i
139
+ const DISABLE = /eslint-disable(-next-line|-line)?(?:\s+([^*]+?))?\s*$/
140
+
141
+ const isDisabledBy = (comment, ruleId) => {
142
+ const match = comment.match(DISABLE)
143
+ if (!match) return null
144
+ const rules = match[2]?.split(',').map(item => item.trim()).filter(Boolean)
145
+ if (rules?.length && !rules.includes(ruleId)) return null
146
+ return match[1] ?? ''
147
+ }
148
+
149
+ /**
150
+ * Checks CSS text that starts at `startLine`/`startColumn` (1-based line, 0-based column) of its file.
151
+ * `/* eslint-disable *\/`, `/* eslint-disable-line <rule> *\/` and `/* eslint-disable-next-line <rule> *\/` work inside it.
152
+ */
153
+ export const checkCss = (css, {startLine = 1, startColumn = 0, ruleId, allow = []}, report) => {
154
+ const disabledLines = new Set()
155
+ let disabledAll = false
156
+
157
+ const stylesheet = parse(css, {
158
+ positions: true,
159
+ onParseError: () => {},
160
+ onComment: (value, loc) => {
161
+ const kind = isDisabledBy(value.trim(), ruleId)
162
+ if (kind === null) return
163
+ if (kind === '') disabledAll = true
164
+ else if (kind === '-line') disabledLines.add(loc.start.line)
165
+ else disabledLines.add(loc.end.line + 1)
166
+ },
167
+ })
168
+
169
+ if (disabledAll) return
170
+
171
+ checkStylesheet(stylesheet, (node, token) => {
172
+ const {start, end} = node.loc
173
+ if (disabledLines.has(start.line)) return
174
+
175
+ const toLoc = point => ({
176
+ line: startLine + point.line - 1,
177
+ column: point.line === 1 ? startColumn + point.column - 1 : point.column - 1,
178
+ })
179
+
180
+ report({start: toLoc(start), end: toLoc(end)}, token)
181
+ }, allow)
182
+ }
183
+
184
+ /**
185
+ * Finds `<style>` blocks in a Vue or Astro file and checks each like a CSS file.
186
+ */
187
+ export const checkStyleBlocks = (text, options, report) => {
188
+ for (const match of text.matchAll(STYLE_BLOCK)) {
189
+ if (SKIPPED_LANG.test(match[1])) continue
190
+
191
+ const offset = match.index + match[0].indexOf('>') + 1
192
+ const before = text.slice(0, offset).split('\n')
193
+
194
+ checkCss(match[2], {...options, startLine: before.length, startColumn: before.at(-1).length}, report)
195
+ }
196
+ }
@@ -0,0 +1,96 @@
1
+ import {findUngated} from './motion/classes.js'
2
+ import {checkStyleBlocks} from './motion/css.js'
3
+
4
+ const CLASS_ATTRIBUTE = /^(?:class|className|class:list)$|-class$|Class$/
5
+
6
+ const attributeName = node => {
7
+ const name = node.name
8
+ if (!name) return null
9
+ if (name.type === 'JSXNamespacedName') return `${ name.namespace.name }:${ name.name.name }`
10
+ return name.name ?? null
11
+ }
12
+
13
+ export default {
14
+ meta: {
15
+ type: 'suggestion',
16
+ docs: {
17
+ description: 'Require motion to be opted into with motion-safe: (classes) or a prefers-reduced-motion query (<style> blocks)',
18
+ recommended: true,
19
+ },
20
+ schema: [
21
+ {
22
+ type: 'object',
23
+ properties: {
24
+ allow: {
25
+ type: 'array',
26
+ items: {type: 'string'},
27
+ },
28
+ },
29
+ additionalProperties: false,
30
+ },
31
+ ],
32
+ messages: {
33
+ ungated: '`{{token}}` runs under reduced motion. Prefix it with `motion-safe:`, or add a `motion-reduce:` fallback in the same class string.',
34
+ ungatedDuration: '`{{token}}` has no transition property beside it, so under reduced motion it transitions every property. Prefix it with `motion-safe:` like the transition it belongs to.',
35
+ ungatedCss: '`{{token}}` runs under reduced motion. Put it inside `@media (prefers-reduced-motion: no-preference)` or `@variant motion-safe`; in `@apply`, prefix the class with `motion-safe:`.',
36
+ },
37
+ },
38
+
39
+ create(context) {
40
+ const allow = context.options[0]?.allow ?? []
41
+
42
+ const check = (node, value) => {
43
+ if (typeof value !== 'string' || !value) return
44
+
45
+ for (const {token, duration} of findUngated(value, allow)) {
46
+ context.report({node, messageId: duration ? 'ungatedDuration' : 'ungated', data: {token}})
47
+ }
48
+ }
49
+
50
+ const isModuleSource = node => {
51
+ const parent = node.parent
52
+ return parent && (
53
+ parent.type === 'ImportDeclaration'
54
+ || parent.type === 'ExportNamedDeclaration'
55
+ || parent.type === 'ExportAllDeclaration'
56
+ || parent.type === 'ImportExpression'
57
+ )
58
+ }
59
+
60
+ const scriptVisitor = {
61
+ Literal(node) {
62
+ if (isModuleSource(node)) return
63
+ if (node.parent?.type === 'JSXAttribute' && !CLASS_ATTRIBUTE.test(attributeName(node.parent) ?? '')) return
64
+ check(node, node.value)
65
+ },
66
+ TemplateElement(node) {
67
+ check(node, node.value.cooked)
68
+ },
69
+ }
70
+
71
+ const templateVisitor = {
72
+ 'VAttribute[directive=false]'(node) {
73
+ if (!CLASS_ATTRIBUTE.test(node.key.name)) return
74
+ check(node, node.value?.value)
75
+ },
76
+ Literal: scriptVisitor.Literal,
77
+ TemplateElement: scriptVisitor.TemplateElement,
78
+ }
79
+
80
+ if (/\.(?:vue|astro)$/.test(context.filename)) {
81
+ scriptVisitor['Program:exit'] = () => {
82
+ checkStyleBlocks(context.sourceCode.text, {ruleId: context.id, allow}, (loc, token) => {
83
+ context.report({loc, messageId: 'ungatedCss', data: {token}})
84
+ })
85
+ }
86
+ }
87
+
88
+ const parserServices = context.sourceCode.parserServices
89
+
90
+ if (parserServices?.defineTemplateBodyVisitor) {
91
+ return parserServices.defineTemplateBodyVisitor(templateVisitor, scriptVisitor)
92
+ }
93
+
94
+ return scriptVisitor
95
+ },
96
+ }
package/package.json CHANGED
@@ -4,9 +4,10 @@
4
4
  "type": "git",
5
5
  "url": "https://github.com/rsmple/eco-vue-js.git"
6
6
  },
7
- "version": "0.27.3",
7
+ "version": "0.28.0",
8
8
  "homepage": "https://rsmple.github.io/eco-vue-js/",
9
9
  "dependencies": {
10
+ "@eslint/css-tree": "4.1.2",
10
11
  "@stylistic/eslint-plugin": "5.10.0",
11
12
  "@tanstack/eslint-plugin-query": "5.105.0",
12
13
  "@vue/eslint-config-typescript": "14.9.0",
@@ -17,7 +18,8 @@
17
18
  "eslint-plugin-tailwindcss": "4.4.0",
18
19
  "eslint-plugin-template-security": "0.2.0",
19
20
  "eslint-plugin-unused-imports": "4.4.1",
20
- "eslint-plugin-vue": "10.12.0"
21
+ "eslint-plugin-vue": "10.12.0",
22
+ "tailwind-csstree": "0.4.2"
21
23
  },
22
24
  "peerDependencies": {
23
25
  "@tanstack/vue-query": ">=5.92.9",
@@ -75,7 +75,7 @@
75
75
  }
76
76
 
77
77
  .w-markdown summary svg {
78
- @apply transition-transform self-center;
78
+ @apply motion-safe:transition-transform self-center;
79
79
  }
80
80
 
81
81
  .w-markdown details:open summary svg {
@@ -1,4 +1,10 @@
1
- /* Turns off animations, transitions and smooth scrolling when the user asks the OS for reduced motion. Transitions still run for a moment so `transitionend` and Vue's `after-enter`/`after-leave` fire. */
1
+ /*
2
+ * Turns off animations, transitions and smooth scrolling when the user asks the OS for reduced motion.
3
+ * Animations still run for a moment so `animationend` fires; they only run where one is declared.
4
+ * Transitions get no duration at all: `transition-property` defaults to `all`, so any duration here would make every
5
+ * element transition each inherited change — a theme switch would start one per SVG node. Vue's `after-enter` and
6
+ * `after-leave` still fire, since Vue finds no transition and finishes at once.
7
+ */
2
8
  @layer base {
3
9
  @media (prefers-reduced-motion: reduce) {
4
10
  *,
@@ -8,7 +14,7 @@
8
14
  animation-duration: 0.01ms !important;
9
15
  animation-iteration-count: 1 !important;
10
16
  transition-delay: 0s !important;
11
- transition-duration: 0.01ms !important;
17
+ transition-duration: 0s !important;
12
18
  scroll-behavior: auto !important;
13
19
  }
14
20
  }
@@ -167,7 +167,9 @@ const pluginDefault = plugin(function ({addBase, addUtilities, theme}) {
167
167
  height: '100%',
168
168
  'background-repeat': 'repeat',
169
169
  'background-size': '40px 40px',
170
- animation: theme('animation.move-horizontal'),
170
+ '@media (prefers-reduced-motion: no-preference)': {
171
+ animation: theme('animation.move-horizontal'),
172
+ },
171
173
  },
172
174
  [DARK_SELECTOR]: {
173
175
  '&::before': {
@@ -208,7 +210,9 @@ const pluginDefault = plugin(function ({addBase, addUtilities, theme}) {
208
210
  width: '100%',
209
211
  height: '100%',
210
212
  'background-image': 'linear-gradient(90deg, rgb(255 255 255 / 0), rgb(255 255 255 / var(--w-skeleton-opacity)), rgb(255 255 255 / 0))',
211
- animation: theme('animation.ticker'),
213
+ '@media (prefers-reduced-motion: no-preference)': {
214
+ animation: theme('animation.ticker'),
215
+ },
212
216
  },
213
217
  },
214
218
  })
@@ -18,9 +18,11 @@ const pluginDefault = plugin(function ({addBase}) {
18
18
  'user-select': 'none',
19
19
  opacity: '0',
20
20
  transform: 'scaleX(0.5) scaleY(0.5)',
21
- 'transition-property': 'opacity, transform',
22
- 'transition-timing-function': 'cubic-bezier(0.4, 0, 0.2, 1)',
23
- 'transition-duration': '200ms',
21
+ '@media (prefers-reduced-motion: no-preference)': {
22
+ 'transition-property': 'opacity, transform',
23
+ 'transition-timing-function': 'cubic-bezier(0.4, 0, 0.2, 1)',
24
+ 'transition-duration': '200ms',
25
+ },
24
26
  },
25
27
 
26
28
  '&:hover::after, .w-hover-circle-trigger:hover &::after, &:focus::after, .w-hover-circle-trigger:focus &::after': {
@@ -48,7 +48,9 @@ const pluginRipple = plugin(function ({matchUtilities, addUtilities, addBase}) {
48
48
  const configRippleStatic = {
49
49
  'w-ripple-active:not(:active)': () => ({
50
50
  '&::before': {
51
- animation: 'ripple-active infinite linear alternate 0.5s',
51
+ '@media (prefers-reduced-motion: no-preference)': {
52
+ animation: 'ripple-active infinite linear alternate 0.5s',
53
+ },
52
54
  },
53
55
  }),
54
56
  }