opui-css 5.2.0 → 5.4.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 (87) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/components/Accordion/Accordion.vue +38 -0
  3. package/components/Anchor/Anchor.vue +41 -0
  4. package/components/Avatar/Avatar.vue +24 -0
  5. package/components/Avatar/types.d.vue.ts +2 -2
  6. package/components/Badge/Badge.vue +39 -0
  7. package/components/Button/Button.vue +27 -0
  8. package/components/Button/types.ts +0 -3
  9. package/components/ButtonGroup/ButtonGroup.vue +22 -0
  10. package/components/Callout/Callout.vue +63 -0
  11. package/components/Card/Card.vue +28 -0
  12. package/components/Card/types.ts +1 -0
  13. package/components/Checkbox/Checkbox.vue +43 -0
  14. package/components/Checkbox/CheckboxInput.vue +32 -0
  15. package/components/Checkbox/types.ts +0 -1
  16. package/components/Chip/Chip.vue +37 -0
  17. package/components/ClassicSelect/ClassicSelect.vue +54 -0
  18. package/components/ClassicSelect/types.ts +0 -4
  19. package/components/DescriptionList/Description.vue +12 -0
  20. package/components/DescriptionList/DescriptionList.vue +23 -0
  21. package/components/DescriptionList/Item.vue +12 -0
  22. package/components/DescriptionList/Term.vue +12 -0
  23. package/components/Dialog/Dialog.vue +35 -0
  24. package/components/Dialog/types.ts +1 -0
  25. package/components/Divider/Divider.vue +12 -0
  26. package/components/Drawer/Drawer.astro +9 -3
  27. package/components/Drawer/Drawer.vue +46 -0
  28. package/components/Drawer/DrawerFooter.vue +16 -0
  29. package/components/Drawer/DrawerHeader.vue +36 -0
  30. package/components/Drawer/types.d.vue.ts +3 -1
  31. package/components/Drawer/types.ts +1 -0
  32. package/components/FieldDescription/FieldDescription.vue +12 -0
  33. package/components/FieldGroup/FieldGroup.vue +25 -0
  34. package/components/FieldLegend/FieldLegend.vue +18 -0
  35. package/components/FieldSet/FieldSet.vue +18 -0
  36. package/components/Form/Form.vue +14 -0
  37. package/components/IconButton/IconButton.vue +24 -0
  38. package/components/List/List.vue +28 -0
  39. package/components/ListItem/ListItem.vue +98 -0
  40. package/components/Progress/Progress.vue +34 -0
  41. package/components/Radio/Radio.vue +41 -0
  42. package/components/Radio/RadioInput.vue +14 -0
  43. package/components/Radio/types.ts +0 -1
  44. package/components/Range/Range.vue +85 -0
  45. package/components/Range/types.ts +0 -5
  46. package/components/Select/Select.astro +0 -6
  47. package/components/Select/Select.vue +85 -0
  48. package/components/Switch/Switch.vue +63 -0
  49. package/components/Switch/SwitchInput.vue +14 -0
  50. package/components/Table/Body.vue +5 -0
  51. package/components/Table/Cell.vue +5 -0
  52. package/components/Table/Column.vue +19 -0
  53. package/components/Table/ColumnGroup.vue +5 -0
  54. package/components/Table/Head.vue +5 -0
  55. package/components/Table/HeaderCell.vue +5 -0
  56. package/components/Table/Row.vue +5 -0
  57. package/components/Table/Table.vue +19 -0
  58. package/components/Tabs/Tabs.vue +20 -0
  59. package/components/Tabs/TabsItem.vue +39 -0
  60. package/components/Tabs/TabsPanel.vue +31 -0
  61. package/components/Tabs/TabsTab.vue +24 -0
  62. package/components/TextField/TextField.vue +74 -0
  63. package/components/TextField/types.d.vue.ts +3 -1
  64. package/components/Textarea/Textarea.vue +64 -0
  65. package/components/Textarea/types.d.vue.ts +1 -0
  66. package/components/Toast/Toast.vue +48 -0
  67. package/components/ToggleButton/ToggleButton.vue +41 -0
  68. package/components/ToggleGroup/ToggleGroup.vue +36 -0
  69. package/components/Tooltip/Tooltip.vue +22 -0
  70. package/core/normalize.css +24 -10
  71. package/core/utils.css +1 -3
  72. package/css/components/accordion.css +4 -5
  73. package/css/components/button.css +5 -4
  74. package/css/components/dialog.css +8 -13
  75. package/css/components/drawer.css +2 -1
  76. package/css/components/icon-button.css +8 -10
  77. package/css/components/progress.css +23 -27
  78. package/css/components/range.css +3 -6
  79. package/css/components/select.css +6 -7
  80. package/css/components/switch.css +17 -18
  81. package/css/components/text-field.css +3 -3
  82. package/dist/opui.components.css +79 -94
  83. package/dist/opui.components.css.map +1 -1
  84. package/dist/opui.css +104 -107
  85. package/dist/opui.css.map +1 -1
  86. package/package.json +14 -3
  87. package/vue/index.ts +54 -0
@@ -0,0 +1,63 @@
1
+ <script setup lang="ts">
2
+ import SwitchInput from "./SwitchInput.vue"
3
+ import type { Slots, SwitchProps } from "./types.d.vue"
4
+ import { useId } from "vue"
5
+
6
+ defineOptions({
7
+ inheritAttrs: false,
8
+ })
9
+
10
+ const props = defineProps<SwitchProps>()
11
+ defineSlots<Slots>()
12
+ const modelValue = defineModel<boolean | (string | number)[]>()
13
+
14
+ const endTextId = useId()
15
+ </script>
16
+
17
+ <template>
18
+ <label
19
+ :class="[
20
+ 'ui-switch',
21
+ {
22
+ 'ui-small': props.small,
23
+ 'ui-stack': props.stack,
24
+ 'ui-spread': props.spread,
25
+ },
26
+ props.class,
27
+ ]"
28
+ :data-invalid="props.error || undefined"
29
+ >
30
+ <span
31
+ v-if="$slots['icon-unchecked']"
32
+ class="ui-icon-unchecked"
33
+ aria-hidden="true"
34
+ >
35
+ <slot name="icon-unchecked"></slot>
36
+ </span>
37
+
38
+ <span
39
+ v-if="$slots['icon-checked']"
40
+ class="ui-icon-checked"
41
+ aria-hidden="true"
42
+ >
43
+ <slot name="icon-checked"></slot>
44
+ </span>
45
+
46
+ <SwitchInput
47
+ v-bind="$attrs"
48
+ v-model="modelValue"
49
+ :aria-describedby="endTextId"
50
+ />
51
+
52
+ <span
53
+ v-if="$slots.default"
54
+ :class="[props.hideLabel ? 'ui-sr-only' : 'ui-label']"
55
+ >
56
+ <slot></slot>
57
+ </span>
58
+
59
+ <span v-if="$slots['end-text']" :id="endTextId" class="ui-end-text">
60
+ <slot name="end-text"></slot>
61
+ </span>
62
+ </label>
63
+ </template>
@@ -0,0 +1,14 @@
1
+ <script setup lang="ts">
2
+ import type { SwitchInputProps } from "./types"
3
+
4
+ defineOptions({
5
+ inheritAttrs: false,
6
+ })
7
+
8
+ defineProps<SwitchInputProps>()
9
+ const modelValue = defineModel<boolean | (string | number)[]>()
10
+ </script>
11
+
12
+ <template>
13
+ <input type="checkbox" role="switch" v-bind="$attrs" v-model="modelValue" />
14
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <tbody>
3
+ <slot></slot>
4
+ </tbody>
5
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <td>
3
+ <slot></slot>
4
+ </td>
5
+ </template>
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ import type { ColumnProps } from "./types"
3
+
4
+ const { width } = defineProps<ColumnProps>()
5
+
6
+ defineOptions({
7
+ inheritAttrs: false,
8
+ })
9
+
10
+ const colStyle = width
11
+ ? width.includes(":")
12
+ ? width
13
+ : `width: ${width}`
14
+ : undefined
15
+ </script>
16
+
17
+ <template>
18
+ <col :style="colStyle" v-bind="$attrs" />
19
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <colgroup>
3
+ <slot></slot>
4
+ </colgroup>
5
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <thead>
3
+ <slot></slot>
4
+ </thead>
5
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <th>
3
+ <slot></slot>
4
+ </th>
5
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <tr>
3
+ <slot></slot>
4
+ </tr>
5
+ </template>
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ import type { Props, Slots } from "./types.d.vue"
3
+
4
+ const { variant } = defineProps<Props>()
5
+ defineSlots<Slots>()
6
+
7
+ defineOptions({
8
+ inheritAttrs: false,
9
+ })
10
+ </script>
11
+
12
+ <template>
13
+ <table
14
+ :class="['ui-table', variant && `ui-${variant}`, $props.class]"
15
+ v-bind="$attrs"
16
+ >
17
+ <slot></slot>
18
+ </table>
19
+ </template>
@@ -0,0 +1,20 @@
1
+ <script setup lang="ts">
2
+ import { provide, useId } from "vue"
3
+ import { TabsGroupNameKey, type Props, type Slots } from "./types.d.vue"
4
+
5
+ const { name } = defineProps<Props>()
6
+ defineSlots<Slots>()
7
+
8
+ defineOptions({
9
+ inheritAttrs: false,
10
+ })
11
+
12
+ const groupName = name || useId()
13
+ provide(TabsGroupNameKey, groupName)
14
+ </script>
15
+
16
+ <template>
17
+ <div :class="['ui-tabs', $props.class]" role="tablist" v-bind="$attrs">
18
+ <slot></slot>
19
+ </div>
20
+ </template>
@@ -0,0 +1,39 @@
1
+ <script setup lang="ts">
2
+ import { inject, provide, useId } from "vue"
3
+ import {
4
+ CurrentPanelIdKey,
5
+ CurrentTabIdKey,
6
+ TabsGroupNameKey,
7
+ type Slots,
8
+ type TabsItemProps,
9
+ } from "./types.d.vue"
10
+
11
+ const { name, open, panelId, tabId } = defineProps<TabsItemProps>()
12
+ defineSlots<Slots>()
13
+
14
+ defineOptions({
15
+ inheritAttrs: false,
16
+ })
17
+
18
+ const tabsGroupName = name || inject(TabsGroupNameKey, undefined) || useId()
19
+ provide(TabsGroupNameKey, tabsGroupName)
20
+
21
+ const computedTabId = tabId || useId()
22
+ const computedPanelId = panelId || useId()
23
+
24
+ provide(CurrentTabIdKey, computedTabId)
25
+ provide(CurrentPanelIdKey, computedPanelId)
26
+ </script>
27
+
28
+ <template>
29
+ <input
30
+ :aria-controls="computedPanelId"
31
+ :checked="open"
32
+ :class="['ui-tab-input', $props.class]"
33
+ :id="computedTabId"
34
+ :name="tabsGroupName"
35
+ type="radio"
36
+ v-bind="$attrs"
37
+ />
38
+ <slot></slot>
39
+ </template>
@@ -0,0 +1,31 @@
1
+ <script setup lang="ts">
2
+ import { inject } from "vue"
3
+ import {
4
+ CurrentPanelIdKey,
5
+ CurrentTabIdKey,
6
+ type Slots,
7
+ type TabsPanelProps,
8
+ } from "./types.d.vue"
9
+
10
+ const { panelId, tabId } = defineProps<TabsPanelProps>()
11
+ defineSlots<Slots>()
12
+
13
+ defineOptions({
14
+ inheritAttrs: false,
15
+ })
16
+
17
+ const currentPanelId = inject(CurrentPanelIdKey, undefined)
18
+ const currentTabId = inject(CurrentTabIdKey, undefined)
19
+ </script>
20
+
21
+ <template>
22
+ <div
23
+ :id="panelId || currentPanelId"
24
+ :class="['ui-tab-panel', $props.class]"
25
+ role="tabpanel"
26
+ :aria-labelledby="tabId || currentTabId"
27
+ v-bind="$attrs"
28
+ >
29
+ <slot></slot>
30
+ </div>
31
+ </template>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import { inject } from "vue"
3
+ import { CurrentTabIdKey, type Slots, type TabsTabProps } from "./types.d.vue"
4
+
5
+ const { tabId } = defineProps<TabsTabProps>()
6
+ defineSlots<Slots>()
7
+
8
+ defineOptions({
9
+ inheritAttrs: false,
10
+ })
11
+
12
+ const currentTabId = inject(CurrentTabIdKey, undefined)
13
+ </script>
14
+
15
+ <template>
16
+ <label
17
+ :for="tabId || currentTabId"
18
+ :class="['ui-tab-label', $props.class]"
19
+ role="tab"
20
+ v-bind="$attrs"
21
+ >
22
+ <slot></slot>
23
+ </label>
24
+ </template>
@@ -0,0 +1,74 @@
1
+ <script setup lang="ts">
2
+ import { useId, computed } from "vue"
3
+ import type { Props, Slots } from "./types.d.vue"
4
+
5
+ defineOptions({
6
+ inheritAttrs: false,
7
+ })
8
+
9
+ const props = withDefaults(defineProps<Props>(), {
10
+ type: "text",
11
+ })
12
+ defineSlots<Slots>()
13
+ const modelValue = defineModel<string | number>()
14
+
15
+ const fieldId = props.id || useId()
16
+ const startTextValue = computed(() => props.description || props.startText)
17
+ </script>
18
+
19
+ <template>
20
+ <label
21
+ :class="[
22
+ 'ui-text-field',
23
+ {
24
+ 'ui-auto-fit': props.autoFit,
25
+ 'ui-filled': props.filled,
26
+ 'ui-spread': props.spread,
27
+ 'ui-small': props.small,
28
+ },
29
+ props.class,
30
+ ]"
31
+ :data-invalid="props.error || undefined"
32
+ >
33
+ <span v-if="props.label || $slots.label" class="ui-label">
34
+ <slot name="label">{{ props.label }}</slot>
35
+ </span>
36
+
37
+ <span v-if="startTextValue || $slots.description" class="ui-start-text">
38
+ <slot name="description">{{ startTextValue }}</slot>
39
+ </span>
40
+
41
+ <span class="ui-field">
42
+ <input
43
+ :id="fieldId"
44
+ :inputmode="props.type === 'numeric' ? 'numeric' : undefined"
45
+ :pattern="props.type === 'numeric' ? '[0-9]*' : undefined"
46
+ :type="props.type === 'numeric' ? 'text' : props.type"
47
+ v-bind="$attrs"
48
+ v-model="modelValue"
49
+ />
50
+ <span class="ui-prefix" v-if="$slots.prefix"
51
+ ><slot name="prefix"></slot
52
+ ></span>
53
+ <span class="ui-suffix" v-if="$slots.suffix"
54
+ ><slot name="suffix"></slot
55
+ ></span>
56
+ <span class="ui-header" v-if="$slots.header"
57
+ ><slot name="header"></slot
58
+ ></span>
59
+ <span class="ui-footer" v-if="$slots.footer"
60
+ ><slot name="footer"></slot
61
+ ></span>
62
+ </span>
63
+
64
+ <span
65
+ v-if="props.endText || $slots['end-text'] || $slots['supporting-text']"
66
+ class="ui-end-text"
67
+ >
68
+ <slot name="end-text">{{ props.endText }}</slot
69
+ ><slot name="supporting-text"></slot>
70
+ </span>
71
+
72
+ <slot></slot>
73
+ </label>
74
+ </template>
@@ -1,8 +1,10 @@
1
- import type { HTMLAttributes, Slot } from "vue"
1
+ import type { HTMLAttributes, InputHTMLAttributes, Slot } from "vue"
2
2
  import type { Props as BaseProps } from "./types"
3
3
 
4
4
  export type Props = BaseProps & {
5
5
  class?: HTMLAttributes["class"]
6
+ id?: HTMLAttributes["id"]
7
+ type?: InputHTMLAttributes["type"] | "numeric"
6
8
  }
7
9
 
8
10
  export type Slots = {
@@ -0,0 +1,64 @@
1
+ <script setup lang="ts">
2
+ import { useId } from "vue"
3
+ import type { Props, Slots } from "./types.d.vue"
4
+
5
+ defineOptions({
6
+ inheritAttrs: false,
7
+ })
8
+
9
+ const props = defineProps<Props>()
10
+ defineSlots<Slots>()
11
+ const modelValue = defineModel<string>()
12
+
13
+ const fieldId = props.id || useId()
14
+ </script>
15
+
16
+ <template>
17
+ <label
18
+ :class="[
19
+ 'ui-textarea',
20
+ {
21
+ 'ui-auto-fit': props.autoFit,
22
+ 'ui-filled': props.filled,
23
+ 'ui-spread': props.spread,
24
+ 'ui-small': props.small,
25
+ },
26
+ props.class,
27
+ ]"
28
+ :data-invalid="props.error || undefined"
29
+ >
30
+ <span v-if="props.label || $slots.label" class="ui-label">
31
+ <slot name="label">{{ props.label }}</slot>
32
+ </span>
33
+
34
+ <span v-if="props.description || $slots.description" class="ui-start-text">
35
+ <slot name="description">{{ props.description }}</slot>
36
+ </span>
37
+
38
+ <span class="ui-field">
39
+ <textarea :id="fieldId" v-bind="$attrs" v-model="modelValue"></textarea>
40
+ <span class="ui-prefix" v-if="$slots.prefix"
41
+ ><slot name="prefix"></slot
42
+ ></span>
43
+ <span class="ui-suffix" v-if="$slots.suffix"
44
+ ><slot name="suffix"></slot
45
+ ></span>
46
+ <span class="ui-header" v-if="$slots.header"
47
+ ><slot name="header"></slot
48
+ ></span>
49
+ <span class="ui-footer" v-if="$slots.footer"
50
+ ><slot name="footer"></slot
51
+ ></span>
52
+ </span>
53
+
54
+ <span
55
+ v-if="props.endText || $slots['end-text'] || $slots['supporting-text']"
56
+ class="ui-end-text"
57
+ >
58
+ <slot name="end-text">{{ props.endText }}</slot
59
+ ><slot name="supporting-text"></slot>
60
+ </span>
61
+
62
+ <slot></slot>
63
+ </label>
64
+ </template>
@@ -3,6 +3,7 @@ import type { Props as BaseProps } from "./types"
3
3
 
4
4
  export type Props = BaseProps & {
5
5
  class?: HTMLAttributes["class"]
6
+ id?: HTMLAttributes["id"]
6
7
  }
7
8
 
8
9
  export type Slots = {
@@ -0,0 +1,48 @@
1
+ <script setup lang="ts">
2
+ import { onMounted } from "vue"
3
+ import { initToastManager } from "../../css/js/toast.js"
4
+
5
+ onMounted(() => {
6
+ initToastManager()
7
+ })
8
+ </script>
9
+
10
+ <template>
11
+ <output
12
+ aria-live="polite"
13
+ id="toast-manager"
14
+ popover="manual"
15
+ role="status"
16
+ ></output>
17
+
18
+ <template id="toast-template">
19
+ <div class="ui-toast" role="alert">
20
+ <span class="ui-icon" data-toast-icon></span>
21
+ <div class="ui-content">
22
+ <div class="ui-title" data-toast-title></div>
23
+ <div class="ui-description" data-toast-description></div>
24
+ </div>
25
+ <button
26
+ aria-label="Close"
27
+ class="ui-close-button"
28
+ data-toast-close
29
+ type="button"
30
+ >
31
+ <svg
32
+ fill="none"
33
+ height="20"
34
+ stroke="currentColor"
35
+ stroke-linecap="round"
36
+ stroke-linejoin="round"
37
+ stroke-width="2"
38
+ viewBox="0 0 24 24"
39
+ width="20"
40
+ xmlns="http://www.w3.org/2000/svg"
41
+ >
42
+ <path d="M18 6 6 18"></path>
43
+ <path d="m6 6 12 12"></path>
44
+ </svg>
45
+ </button>
46
+ </div>
47
+ </template>
48
+ </template>
@@ -0,0 +1,41 @@
1
+ <script setup lang="ts">
2
+ import { inject, useId } from "vue"
3
+ import { ToggleGroupKey } from "../ToggleGroup/types.d.vue"
4
+ import type { Props, Slots } from "./types.d.vue"
5
+
6
+ const { disabled, id, label, name, pressed, size, type, value } =
7
+ defineProps<Props>()
8
+ defineSlots<Slots>()
9
+
10
+ defineOptions({
11
+ inheritAttrs: false,
12
+ })
13
+
14
+ const group = inject(ToggleGroupKey, undefined)
15
+ const finalName = name || group?.name
16
+ const finalType = type || group?.type || "checkbox"
17
+ const inputId = id || useId()
18
+ </script>
19
+
20
+ <template>
21
+ <label
22
+ :class="[
23
+ 'ui-toggle-button',
24
+ { 'ui-disabled': disabled },
25
+ size && `ui-${size}`,
26
+ $props.class,
27
+ ]"
28
+ >
29
+ <input
30
+ :aria-pressed="finalType === 'checkbox' ? pressed : undefined"
31
+ :checked="pressed"
32
+ :disabled="disabled"
33
+ :id="inputId"
34
+ :name="finalName"
35
+ :type="finalType"
36
+ :value="value || label"
37
+ v-bind="$attrs"
38
+ />
39
+ <slot></slot>
40
+ </label>
41
+ </template>
@@ -0,0 +1,36 @@
1
+ <script setup lang="ts">
2
+ import { provide, useId } from "vue"
3
+ import { ToggleGroupKey, type Props, type Slots } from "./types.d.vue"
4
+
5
+ const {
6
+ name,
7
+ orientation,
8
+ selection = "multiple",
9
+ size = "default",
10
+ } = defineProps<Props>()
11
+ defineSlots<Slots>()
12
+
13
+ defineOptions({
14
+ inheritAttrs: false,
15
+ })
16
+
17
+ const groupName = name || useId()
18
+ const inputType = selection === "single" ? "radio" : "checkbox"
19
+
20
+ provide(ToggleGroupKey, { name: groupName, type: inputType })
21
+ </script>
22
+
23
+ <template>
24
+ <div
25
+ :class="[
26
+ 'ui-toggle-group',
27
+ size !== 'default' && size && `ui-${size}`,
28
+ orientation && `ui-${orientation}`,
29
+ $props.class,
30
+ ]"
31
+ :role="selection === 'single' ? 'radiogroup' : 'group'"
32
+ v-bind="$attrs"
33
+ >
34
+ <slot></slot>
35
+ </div>
36
+ </template>
@@ -0,0 +1,22 @@
1
+ <script setup lang="ts">
2
+ import Anchor from "../Anchor/Anchor.vue"
3
+ import type { Props, Slots } from "./types.d.vue"
4
+
5
+ const { alignment, arrow, id, label } = defineProps<Props>()
6
+ defineSlots<Slots>()
7
+ </script>
8
+
9
+ <template>
10
+ <Anchor
11
+ :alignment="alignment"
12
+ :class="['ui-tooltip', { 'ui-with-arrow': arrow }, $props.class]"
13
+ :id="id"
14
+ trigger="hover"
15
+ >
16
+ <slot></slot>
17
+ <template #anchored>
18
+ {{ label }}
19
+ <slot name="content"></slot>
20
+ </template>
21
+ </Anchor>
22
+ </template>
@@ -11,6 +11,28 @@
11
11
  scrollbar-width: thin;
12
12
  }
13
13
 
14
+ html {
15
+ --motion: 1;
16
+ }
17
+
18
+ @media (prefers-reduced-motion: reduce) {
19
+ html {
20
+ --motion: 0;
21
+ }
22
+ }
23
+
24
+ .ui-motion-off {
25
+ --motion: 0 !important;
26
+ }
27
+
28
+ .ui-motion-on {
29
+ --motion: 1 !important;
30
+ }
31
+
32
+ .ui-motion-debug {
33
+ --motion: 10 !important;
34
+ }
35
+
14
36
  :where(html) {
15
37
  --_page-bg-color: var(--surface-default);
16
38
 
@@ -119,19 +141,11 @@
119
141
  border-radius: var(--border-radius, 0px);
120
142
  outline: 2px solid var(--_focus-visible-color);
121
143
  outline-offset: 2px;
122
- }
123
-
124
- @media (prefers-reduced-motion: no-preference) {
125
- :where(:focus-visible) {
126
- transition: outline-offset 0.15 var(--ease-2);
127
- }
128
-
129
- :where(:not(:active):focus-visible) {
130
- transition-duration: 0.15s;
131
- }
144
+ transition: outline-offset calc(0.15s * var(--motion)) var(--ease-2);
132
145
  }
133
146
 
134
147
  :where(:not(:active):focus-visible) {
148
+ transition-duration: calc(0.15s * var(--motion));
135
149
  outline-offset: var(--outline-offset, 0px);
136
150
  }
137
151
 
package/core/utils.css CHANGED
@@ -62,9 +62,7 @@ Add `.ui-scroll-lock` to any element that uses the [open] attribute (native <dia
62
62
  translateZ(-1px) scale(var(--thumb-scale));
63
63
  will-change: transform;
64
64
 
65
- @media (prefers-reduced-motion: no-preference) {
66
- transition: transform 0.2s ease;
67
- }
65
+ transition: transform calc(0.2s * var(--motion, 1)) ease;
68
66
  }
69
67
  }
70
68
  }
@@ -1,5 +1,6 @@
1
1
  @layer components.extended {
2
2
  :where(details.ui-accordion) {
3
+ --_motion: var(--motion, 1);
3
4
  --_actions-gap: var(--size-1);
4
5
  --_actions-margin-block-start: var(--size-3);
5
6
  --_actions-padding-block-end: var(--size-1);
@@ -15,8 +16,8 @@
15
16
  --_shadow: none;
16
17
  --_summary-padding-block: var(--size-3);
17
18
  --_summary-padding-inline: var(--_padding-inline);
18
- --_svg-transition: 0.2s var(--ease-1);
19
- --_transition: 0.2s;
19
+ --_svg-transition: calc(0.2s * var(--_motion)) var(--ease-1);
20
+ --_transition: calc(0.2s * var(--_motion));
20
21
 
21
22
  background-color: var(--_bg-color);
22
23
  border: var(--_border-width) solid var(--_border-color);
@@ -49,9 +50,7 @@
49
50
 
50
51
  /* Accordion animation */
51
52
  /* https://nerdy.dev/open-and-close-transitions-for-the-details-element */
52
- @media (prefers-reduced-motion: no-preference) {
53
- interpolate-size: allow-keywords;
54
- }
53
+ interpolate-size: allow-keywords;
55
54
 
56
55
  &::details-content {
57
56
  block-size: 0;