@wovenui/components 0.0.0-stage → 1.0.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 (130) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +284 -2
  3. package/dist/components.json +4204 -0
  4. package/dist/llms-full.txt +2839 -0
  5. package/dist/wovenui-kit.css +5002 -0
  6. package/dist/wovenui-kit.css.map +1 -0
  7. package/dist/wovenui-kit.iife.js +532 -0
  8. package/dist/wovenui-kit.js +529 -0
  9. package/dist/wovenui-kit.min.css +2 -0
  10. package/dist/wovenui-kit.min.css.map +1 -0
  11. package/package.json +268 -4
  12. package/src/_close.scss +45 -0
  13. package/src/_helpers.scss +11 -0
  14. package/src/_kit.scss +124 -0
  15. package/src/_shared.scss +10 -0
  16. package/src/components/_accordion.scss +132 -0
  17. package/src/components/_alert.scss +161 -0
  18. package/src/components/_autocomplete.scss +129 -0
  19. package/src/components/_avatar-group.scss +80 -0
  20. package/src/components/_avatar.scss +134 -0
  21. package/src/components/_badge.scss +91 -0
  22. package/src/components/_breadcrumb.scss +115 -0
  23. package/src/components/_btn-group.scss +113 -0
  24. package/src/components/_button.scss +301 -0
  25. package/src/components/_card.scss +120 -0
  26. package/src/components/_checkbox.scss +168 -0
  27. package/src/components/_code-block.scss +78 -0
  28. package/src/components/_confirm-modal.scss +75 -0
  29. package/src/components/_data-table.scss +79 -0
  30. package/src/components/_desc-list.scss +180 -0
  31. package/src/components/_divider.scss +66 -0
  32. package/src/components/_dot.scss +115 -0
  33. package/src/components/_drawer.scss +200 -0
  34. package/src/components/_dropdown.scss +182 -0
  35. package/src/components/_empty-state.scss +146 -0
  36. package/src/components/_field-group.scss +68 -0
  37. package/src/components/_field-message.scss +75 -0
  38. package/src/components/_field.scss +127 -0
  39. package/src/components/_form-actions.scss +58 -0
  40. package/src/components/_info-row.scss +69 -0
  41. package/src/components/_input-group.scss +87 -0
  42. package/src/components/_input.scss +278 -0
  43. package/src/components/_list.scss +76 -0
  44. package/src/components/_modal.scss +168 -0
  45. package/src/components/_page-header.scss +85 -0
  46. package/src/components/_pagination.scss +138 -0
  47. package/src/components/_panel.scss +69 -0
  48. package/src/components/_popover.scss +154 -0
  49. package/src/components/_progress-circle.scss +123 -0
  50. package/src/components/_progress.scss +122 -0
  51. package/src/components/_radio.scss +162 -0
  52. package/src/components/_segmented.scss +183 -0
  53. package/src/components/_select.scss +154 -0
  54. package/src/components/_sidebar.scss +300 -0
  55. package/src/components/_skeleton.scss +90 -0
  56. package/src/components/_spinner.scss +84 -0
  57. package/src/components/_stat.scss +92 -0
  58. package/src/components/_table.scss +460 -0
  59. package/src/components/_tabs.scss +327 -0
  60. package/src/components/_tag.scss +143 -0
  61. package/src/components/_text.scss +42 -0
  62. package/src/components/_textarea.scss +57 -0
  63. package/src/components/_timeline.scss +196 -0
  64. package/src/components/_title.scss +41 -0
  65. package/src/components/_toast.scss +221 -0
  66. package/src/components/_toggle.scss +171 -0
  67. package/src/components/_toolbar.scss +74 -0
  68. package/src/components/_topbar.scss +204 -0
  69. package/src/entries/accordion.scss +4 -0
  70. package/src/entries/alert.scss +4 -0
  71. package/src/entries/autocomplete.scss +4 -0
  72. package/src/entries/avatar-group.scss +4 -0
  73. package/src/entries/avatar.scss +4 -0
  74. package/src/entries/badge.scss +4 -0
  75. package/src/entries/breadcrumb.scss +4 -0
  76. package/src/entries/btn-group.scss +4 -0
  77. package/src/entries/button.scss +4 -0
  78. package/src/entries/card.scss +4 -0
  79. package/src/entries/checkbox.scss +4 -0
  80. package/src/entries/code-block.scss +4 -0
  81. package/src/entries/confirm-modal.scss +4 -0
  82. package/src/entries/data-table.scss +4 -0
  83. package/src/entries/desc-list.scss +4 -0
  84. package/src/entries/divider.scss +4 -0
  85. package/src/entries/dot.scss +4 -0
  86. package/src/entries/drawer.scss +4 -0
  87. package/src/entries/dropdown.scss +4 -0
  88. package/src/entries/empty-state.scss +4 -0
  89. package/src/entries/field-group.scss +4 -0
  90. package/src/entries/field-message.scss +4 -0
  91. package/src/entries/field.scss +4 -0
  92. package/src/entries/form-actions.scss +4 -0
  93. package/src/entries/info-row.scss +4 -0
  94. package/src/entries/input-group.scss +4 -0
  95. package/src/entries/input.scss +4 -0
  96. package/src/entries/list.scss +4 -0
  97. package/src/entries/modal.scss +4 -0
  98. package/src/entries/page-header.scss +4 -0
  99. package/src/entries/pagination.scss +4 -0
  100. package/src/entries/panel.scss +4 -0
  101. package/src/entries/popover.scss +4 -0
  102. package/src/entries/progress-circle.scss +4 -0
  103. package/src/entries/progress.scss +4 -0
  104. package/src/entries/radio.scss +4 -0
  105. package/src/entries/segmented.scss +4 -0
  106. package/src/entries/select.scss +4 -0
  107. package/src/entries/sidebar.scss +4 -0
  108. package/src/entries/skeleton.scss +4 -0
  109. package/src/entries/spinner.scss +4 -0
  110. package/src/entries/stat.scss +4 -0
  111. package/src/entries/table.scss +4 -0
  112. package/src/entries/tabs.scss +4 -0
  113. package/src/entries/tag.scss +4 -0
  114. package/src/entries/text.scss +4 -0
  115. package/src/entries/textarea.scss +4 -0
  116. package/src/entries/timeline.scss +4 -0
  117. package/src/entries/title.scss +4 -0
  118. package/src/entries/toast.scss +4 -0
  119. package/src/entries/toggle.scss +4 -0
  120. package/src/entries/toolbar.scss +4 -0
  121. package/src/entries/topbar.scss +4 -0
  122. package/src/index.scss +7 -0
  123. package/src/js/autocomplete.js +86 -0
  124. package/src/js/data-table.js +141 -0
  125. package/src/js/index.js +34 -0
  126. package/src/js/input-clear.js +25 -0
  127. package/src/js/package.json +3 -0
  128. package/src/js/tabs.js +73 -0
  129. package/src/js/toast.js +161 -0
  130. package/src/js/util.js +21 -0
package/package.json CHANGED
@@ -1,6 +1,270 @@
1
1
  {
2
2
  "name": "@wovenui/components",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0",
4
+ "description": "WovenUI Components (UI kit): components built on @wovenui/core tokens. CSS, plus a small optional script.",
5
+ "author": {
6
+ "name": "AALA IT Solutions",
7
+ "url": "https://aalasolutions.com"
8
+ },
9
+ "license": "MIT",
10
+ "publishConfig": {
11
+ "access": "public"
12
+ },
13
+ "homepage": "https://wovenui.com/components/",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/WovenUI/components.git"
17
+ },
18
+ "bugs": {
19
+ "url": "https://github.com/WovenUI/components/issues"
20
+ },
21
+ "main": "dist/wovenui-kit.min.css",
22
+ "style": "dist/wovenui-kit.min.css",
23
+ "sass": "src/index.scss",
24
+ "keywords": [
25
+ "wovenui",
26
+ "css",
27
+ "html",
28
+ "components",
29
+ "ui-components",
30
+ "ui-kit",
31
+ "design-system",
32
+ "css-components",
33
+ "sass",
34
+ "accessible",
35
+ "native-html",
36
+ "dialog",
37
+ "popover",
38
+ "rtl",
39
+ "dark-mode",
40
+ "themes",
41
+ "css-only-components",
42
+ "css-framework",
43
+ "ui-library",
44
+ "component-library",
45
+ "html-css",
46
+ "bootstrap-alternative",
47
+ "modal",
48
+ "dropdown",
49
+ "tabs",
50
+ "toast",
51
+ "accordion",
52
+ "data-table",
53
+ "anchor-positioning",
54
+ "invoker-commands",
55
+ "logical-properties",
56
+ "wovenui-core"
57
+ ],
58
+ "files": [
59
+ "dist",
60
+ "src"
61
+ ],
62
+ "exports": {
63
+ ".": {
64
+ "sass": "./src/index.scss",
65
+ "style": "./dist/wovenui-kit.min.css",
66
+ "default": "./dist/wovenui-kit.min.css"
67
+ },
68
+ "./scss": "./src/index.scss",
69
+ "./css": "./dist/wovenui-kit.css",
70
+ "./min.css": "./dist/wovenui-kit.min.css",
71
+ "./button": {
72
+ "sass": "./src/entries/button.scss"
73
+ },
74
+ "./btn-group": {
75
+ "sass": "./src/entries/btn-group.scss"
76
+ },
77
+ "./badge": {
78
+ "sass": "./src/entries/badge.scss"
79
+ },
80
+ "./tag": {
81
+ "sass": "./src/entries/tag.scss"
82
+ },
83
+ "./dot": {
84
+ "sass": "./src/entries/dot.scss"
85
+ },
86
+ "./divider": {
87
+ "sass": "./src/entries/divider.scss"
88
+ },
89
+ "./spinner": {
90
+ "sass": "./src/entries/spinner.scss"
91
+ },
92
+ "./avatar": {
93
+ "sass": "./src/entries/avatar.scss"
94
+ },
95
+ "./avatar-group": {
96
+ "sass": "./src/entries/avatar-group.scss"
97
+ },
98
+ "./card": {
99
+ "sass": "./src/entries/card.scss"
100
+ },
101
+ "./panel": {
102
+ "sass": "./src/entries/panel.scss"
103
+ },
104
+ "./alert": {
105
+ "sass": "./src/entries/alert.scss"
106
+ },
107
+ "./empty-state": {
108
+ "sass": "./src/entries/empty-state.scss"
109
+ },
110
+ "./stat": {
111
+ "sass": "./src/entries/stat.scss"
112
+ },
113
+ "./desc-list": {
114
+ "sass": "./src/entries/desc-list.scss"
115
+ },
116
+ "./info-row": {
117
+ "sass": "./src/entries/info-row.scss"
118
+ },
119
+ "./list": {
120
+ "sass": "./src/entries/list.scss"
121
+ },
122
+ "./timeline": {
123
+ "sass": "./src/entries/timeline.scss"
124
+ },
125
+ "./title": {
126
+ "sass": "./src/entries/title.scss"
127
+ },
128
+ "./text": {
129
+ "sass": "./src/entries/text.scss"
130
+ },
131
+ "./code-block": {
132
+ "sass": "./src/entries/code-block.scss"
133
+ },
134
+ "./breadcrumb": {
135
+ "sass": "./src/entries/breadcrumb.scss"
136
+ },
137
+ "./pagination": {
138
+ "sass": "./src/entries/pagination.scss"
139
+ },
140
+ "./page-header": {
141
+ "sass": "./src/entries/page-header.scss"
142
+ },
143
+ "./toolbar": {
144
+ "sass": "./src/entries/toolbar.scss"
145
+ },
146
+ "./topbar": {
147
+ "sass": "./src/entries/topbar.scss"
148
+ },
149
+ "./sidebar": {
150
+ "sass": "./src/entries/sidebar.scss"
151
+ },
152
+ "./table": {
153
+ "sass": "./src/entries/table.scss"
154
+ },
155
+ "./progress": {
156
+ "sass": "./src/entries/progress.scss"
157
+ },
158
+ "./progress-circle": {
159
+ "sass": "./src/entries/progress-circle.scss"
160
+ },
161
+ "./skeleton": {
162
+ "sass": "./src/entries/skeleton.scss"
163
+ },
164
+ "./field": {
165
+ "sass": "./src/entries/field.scss"
166
+ },
167
+ "./field-group": {
168
+ "sass": "./src/entries/field-group.scss"
169
+ },
170
+ "./field-message": {
171
+ "sass": "./src/entries/field-message.scss"
172
+ },
173
+ "./form-actions": {
174
+ "sass": "./src/entries/form-actions.scss"
175
+ },
176
+ "./input": {
177
+ "sass": "./src/entries/input.scss"
178
+ },
179
+ "./input-group": {
180
+ "sass": "./src/entries/input-group.scss"
181
+ },
182
+ "./textarea": {
183
+ "sass": "./src/entries/textarea.scss"
184
+ },
185
+ "./select": {
186
+ "sass": "./src/entries/select.scss"
187
+ },
188
+ "./checkbox": {
189
+ "sass": "./src/entries/checkbox.scss"
190
+ },
191
+ "./radio": {
192
+ "sass": "./src/entries/radio.scss"
193
+ },
194
+ "./toggle": {
195
+ "sass": "./src/entries/toggle.scss"
196
+ },
197
+ "./segmented": {
198
+ "sass": "./src/entries/segmented.scss"
199
+ },
200
+ "./accordion": {
201
+ "sass": "./src/entries/accordion.scss"
202
+ },
203
+ "./modal": {
204
+ "sass": "./src/entries/modal.scss"
205
+ },
206
+ "./confirm-modal": {
207
+ "sass": "./src/entries/confirm-modal.scss"
208
+ },
209
+ "./drawer": {
210
+ "sass": "./src/entries/drawer.scss"
211
+ },
212
+ "./dropdown": {
213
+ "sass": "./src/entries/dropdown.scss"
214
+ },
215
+ "./popover": {
216
+ "sass": "./src/entries/popover.scss"
217
+ },
218
+ "./tabs": {
219
+ "sass": "./src/entries/tabs.scss"
220
+ },
221
+ "./toast": {
222
+ "sass": "./src/entries/toast.scss"
223
+ },
224
+ "./autocomplete": {
225
+ "sass": "./src/entries/autocomplete.scss"
226
+ },
227
+ "./data-table": {
228
+ "sass": "./src/entries/data-table.scss"
229
+ },
230
+ "./js": "./dist/wovenui-kit.js",
231
+ "./components.json": "./dist/components.json",
232
+ "./llms-full.txt": "./dist/llms-full.txt",
233
+ "./package.json": "./package.json"
234
+ },
235
+ "scripts": {
236
+ "lint": "stylelint \"src/**/*.scss\"",
237
+ "format": "prettier --write \"src/**/*.scss\" \"src/js/**/*.js\" \"scripts/**/*.mjs\"",
238
+ "format:check": "prettier --check \"src/**/*.scss\" \"src/js/**/*.js\" \"scripts/**/*.mjs\"",
239
+ "build:scss": "node --conditions=sass scripts/build-scss.mjs src/index.scss dist/wovenui-kit.css",
240
+ "build:minify": "postcss dist/wovenui-kit.css -o dist/wovenui-kit.min.css --use cssnano --map",
241
+ "build": "pnpm run build:scss && pnpm run build:minify && pnpm run build:js && pnpm run build:docs",
242
+ "dev": "node --conditions=sass --watch-path=src scripts/build-scss.mjs src/index.scss dist/wovenui-kit.css",
243
+ "check": "node scripts/check-modifiers.mjs",
244
+ "test": "pnpm run build && node --conditions=sass test/compile.mjs && node --conditions=sass test/switches.mjs && node --conditions=sass test/entries.mjs && node --conditions=sass test/caret.mjs && node test/modifiers.mjs && node test/size.mjs && node test/js.mjs && node --conditions=sass test/docs.mjs",
245
+ "build:js": "node scripts/build-js.mjs",
246
+ "build:docs": "node scripts/build-docs.mjs"
247
+ },
248
+ "browserslist": [
249
+ "> 1%",
250
+ "last 2 versions",
251
+ "not dead"
252
+ ],
253
+ "devDependencies": {
254
+ "@wovenui/core": "^2.2.2",
255
+ "cssnano": "^8.0.10",
256
+ "postcss": "^8.5.28",
257
+ "postcss-cli": "^11.0.1",
258
+ "prettier": "^3.9.6",
259
+ "sass": "^1.103.1",
260
+ "stylelint": "^17.14.1",
261
+ "stylelint-config-standard-scss": "^17.0.0"
262
+ },
263
+ "peerDependencies": {
264
+ "@wovenui/core": "^2.2.2",
265
+ "sass": ">=1.79.0 <2"
266
+ },
267
+ "engines": {
268
+ "node": ">=14.0.0"
269
+ }
270
+ }
@@ -0,0 +1,45 @@
1
+ // Close button shared by modal, drawer and toast: a cross drawn from two bars.
2
+ // Outputs nothing on its own; each component includes it in its close part.
3
+ @use "@wovenui/core/mixins" as woven;
4
+
5
+ @mixin button {
6
+ display: grid;
7
+ flex: none;
8
+ place-items: center;
9
+ inline-size: woven.token(control-height-sm);
10
+ block-size: woven.token(control-height-sm);
11
+ padding: 0;
12
+ border: 0;
13
+ border-radius: woven.token(radius-sm);
14
+ background: transparent;
15
+ color: woven.token(text-muted);
16
+ cursor: pointer;
17
+ transition-property: background-color, color;
18
+ transition-duration: woven.token(duration-150);
19
+ transition-timing-function: woven.token(ease-out);
20
+
21
+ &::before,
22
+ &::after {
23
+ content: "";
24
+ grid-area: 1 / 1;
25
+ inline-size: 1rem;
26
+ block-size: woven.token(border-width-2);
27
+ border-radius: woven.token(radius-full);
28
+ background: currentcolor;
29
+ rotate: 45deg;
30
+ }
31
+
32
+ &::after {
33
+ rotate: -45deg;
34
+ }
35
+
36
+ &:hover {
37
+ background: woven.token(bg-hover);
38
+ color: woven.token(text-regular);
39
+ }
40
+
41
+ &:focus-visible {
42
+ outline: woven.token(border-focus-width) solid woven.token(border-focus);
43
+ outline-offset: woven.token(border-focus-offset);
44
+ }
45
+ }
@@ -0,0 +1,11 @@
1
+ // Kit-wide helpers, emitted with every component
2
+
3
+ // <svg class="wu-mirror">: flips an app's directional icon (back, next, arrow) in right to left.
4
+ // Works on svg, img and icon-font elements; inline elements become inline-block so the flip applies.
5
+ :where(i, span, em).wu-mirror {
6
+ display: inline-block;
7
+ }
8
+
9
+ .wu-mirror:dir(rtl) {
10
+ scale: -1 1;
11
+ }
package/src/_kit.scss ADDED
@@ -0,0 +1,124 @@
1
+ // Component registry and loader shared by the bundle and the per-component entries
2
+ @use "sass:list";
3
+ @use "sass:map";
4
+ @use "sass:meta";
5
+
6
+ // One line per component: name and the components it needs
7
+ $registry: (
8
+ "button": (),
9
+ "btn-group": ("button"),
10
+ "badge": (),
11
+ "tag": (),
12
+ "dot": (),
13
+ "divider": (),
14
+ "spinner": (),
15
+ "avatar": (),
16
+ "avatar-group": ("avatar"),
17
+ "card": (),
18
+ "panel": (),
19
+ "alert": (),
20
+ "empty-state": (),
21
+ "stat": (),
22
+ "desc-list": (),
23
+ "info-row": (),
24
+ "list": (),
25
+ "timeline": (),
26
+ "title": (),
27
+ "text": (),
28
+ "code-block": (),
29
+ "breadcrumb": (),
30
+ "pagination": ("button"),
31
+ "page-header": (),
32
+ "toolbar": (),
33
+ "topbar": (),
34
+ "sidebar": (),
35
+ "table": (),
36
+ "progress": (),
37
+ "progress-circle": (),
38
+ "skeleton": (),
39
+ "field": (),
40
+ "field-group": (),
41
+ "field-message": (),
42
+ "form-actions": (),
43
+ "input": (),
44
+ "input-group": (),
45
+ "textarea": (),
46
+ "select": (),
47
+ "checkbox": (),
48
+ "radio": (),
49
+ "toggle": (),
50
+ "segmented": (),
51
+ "accordion": (),
52
+ "modal": (),
53
+ "confirm-modal": (
54
+ "modal",
55
+ "button",
56
+ ),
57
+ "drawer": (),
58
+ "dropdown": (),
59
+ "popover": (),
60
+ "tabs": (),
61
+ "toast": (),
62
+ "autocomplete": ("input"),
63
+ "data-table": ("table"),
64
+ );
65
+
66
+ // Names enabled after merging $overrides (name: false) over the registry, all on by default
67
+ @function enabled($overrides, $registry: $registry) {
68
+ @each $name, $on in $overrides {
69
+ @if not map.has-key($registry, $name) {
70
+ @error "$components: unknown component \"#{$name}\". Known: #{map.keys($registry)}";
71
+ }
72
+ @if meta.type-of($on) != "bool" {
73
+ @error "$components: \"#{$name}\" takes true or false, got #{meta.inspect($on)}";
74
+ }
75
+ }
76
+
77
+ $names: ();
78
+ @each $name, $needs in $registry {
79
+ @if map.get($overrides, $name) != false {
80
+ $names: list.append($names, $name, comma);
81
+ }
82
+ }
83
+
84
+ @each $name in $names {
85
+ @each $need in map.get($registry, $name) {
86
+ @if not list.index($names, $need) {
87
+ @error "$components: \"#{$name}\" needs \"#{$need}\", but \"#{$need}\" is switched off";
88
+ }
89
+ }
90
+ }
91
+ @return $names;
92
+ }
93
+
94
+ // A component plus everything it needs, needs first
95
+ @function with-needs($name, $registry: $registry, $names: ()) {
96
+ @if not map.has-key($registry, $name) {
97
+ @error "Unknown component \"#{$name}\". Known: #{map.keys($registry)}";
98
+ }
99
+ @each $need in map.get($registry, $name) {
100
+ @if not list.index($names, $need) {
101
+ $names: with-needs($need, $registry, $names);
102
+ }
103
+ }
104
+ @if not list.index($names, $name) {
105
+ $names: list.append($names, $name, comma);
106
+ }
107
+ @return $names;
108
+ }
109
+
110
+ // Layer order, shared values and helpers, then the components in registry order
111
+ @mixin emit($names) {
112
+ @layer reset, base, components, recipes;
113
+
114
+ @layer components {
115
+ @include meta.load-css("shared");
116
+ @include meta.load-css("helpers");
117
+
118
+ @each $name in map.keys($registry) {
119
+ @if list.index($names, $name) {
120
+ @include meta.load-css("components/#{$name}");
121
+ }
122
+ }
123
+ }
124
+ }
@@ -0,0 +1,10 @@
1
+ // Shared kit values, declared once as custom properties
2
+ :root {
3
+ --wu-kit-ease-spring: linear(0, 0.25 7%, 0.69 17%, 0.95 26%, 1.07 35%, 1.09 42%, 1.05 52%, 1 63%, 0.99 75%, 1);
4
+
5
+ // Role marker shapes for clip-path, so meaning is not carried by color alone:
6
+ // check for success, triangle for warning, octagon for danger
7
+ --wu-kit-marker-check: polygon(12% 48%, 0 62%, 38% 96%, 100% 24%, 86% 10%, 38% 70%);
8
+ --wu-kit-marker-triangle: polygon(50% 4%, 100% 96%, 0 96%);
9
+ --wu-kit-marker-octagon: polygon(30% 0, 70% 0, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0 70%, 0 30%);
10
+ }
@@ -0,0 +1,132 @@
1
+ ////
2
+ //// @component wu-accordion
3
+ //// Stacked disclosure panels built on native `details`, in one bordered group.
4
+ ////
5
+ //// The same `name` on several `details` makes the group exclusive, one open at a time. Leave it out to allow several open.
6
+ ////
7
+ //// @since 1.0.0
8
+ //// @needs none
9
+ //// @js none
10
+ //// @example html
11
+ //// <div class="wu-accordion">
12
+ //// <details class="wu-accordion-item" name="faq" open>
13
+ //// <summary class="wu-accordion-trigger">What is included?</summary>
14
+ //// <div class="wu-accordion-body">Every plan includes support.</div>
15
+ //// </details>
16
+ //// <details class="wu-accordion-item" name="faq">
17
+ //// <summary class="wu-accordion-trigger">Can I cancel?</summary>
18
+ //// <div class="wu-accordion-body">Yes, at any time.</div>
19
+ //// </details>
20
+ //// </div>
21
+ //// @example html
22
+ //// <div class="wu-accordion animated">
23
+ //// <details class="wu-accordion-item">
24
+ //// <summary class="wu-accordion-trigger">Shipping</summary>
25
+ //// <div class="wu-accordion-body">Orders ship in two days.</div>
26
+ //// </details>
27
+ //// </div>
28
+ //// @modifier animated - The chevron turns and the panel height glides when the user allows motion; `wu-animated` on an ancestor does the same @since 1.0.0
29
+ //// @part wu-accordion-item - A `details` element holding one trigger and one body @since 1.0.0
30
+ //// @part wu-accordion-trigger - The `summary` that opens and closes the item, with a chevron @since 1.0.0
31
+ //// @part wu-accordion-body - The panel content shown when the item is open @since 1.0.0
32
+ //// @state open - The chevron points up and the body is shown @since 1.0.0
33
+ ////
34
+
35
+ @use "@wovenui/core/mixins" as woven;
36
+
37
+ .wu-accordion {
38
+ border: woven.token(border-width-1) solid woven.token(border-regular);
39
+ border-radius: woven.token(radius-md);
40
+ background: woven.token(bg-surface);
41
+ color: woven.token(text-regular);
42
+ font-size: woven.token(font-size-sm);
43
+ overflow: clip;
44
+ }
45
+
46
+ .wu-accordion-item + .wu-accordion-item {
47
+ border-block-start: woven.token(border-width-1) solid woven.token(border-regular);
48
+ }
49
+
50
+ .wu-accordion-trigger {
51
+ display: flex;
52
+ align-items: center;
53
+ justify-content: space-between;
54
+ gap: woven.token(space-3);
55
+ min-height: woven.token(control-height-lg);
56
+ padding-block: woven.token(space-2);
57
+ padding-inline: woven.token(space-4);
58
+ font-weight: woven.token(font-weight-medium);
59
+ list-style: none;
60
+ cursor: pointer;
61
+ transition: background-color woven.token(duration-150) woven.token(ease-out);
62
+
63
+ &::-webkit-details-marker {
64
+ display: none;
65
+ }
66
+
67
+ &:hover {
68
+ background: woven.token(bg-hover);
69
+ }
70
+
71
+ // Inset ring, so the bordered group does not clip it
72
+ &:focus-visible {
73
+ outline: woven.token(border-focus-width) solid woven.token(border-focus);
74
+ outline-offset: calc(-1 * #{woven.token(border-focus-width)});
75
+ }
76
+
77
+ // Chevron drawn with two borders: down when closed, up when open
78
+ &::after {
79
+ content: "";
80
+ flex: none;
81
+ width: 0.45em;
82
+ height: 0.45em;
83
+ border-right: woven.token(border-width-2) solid currentcolor;
84
+ border-bottom: woven.token(border-width-2) solid currentcolor;
85
+ color: woven.token(text-muted);
86
+ translate: 0 -0.1em;
87
+ rotate: 45deg;
88
+ }
89
+ }
90
+
91
+ .wu-accordion-item[open] > .wu-accordion-trigger::after {
92
+ translate: 0 0.1em;
93
+ rotate: -135deg;
94
+ }
95
+
96
+ // Regular text: the body is what the reader opened the item for, often settings, not a secondary hint
97
+ .wu-accordion-body {
98
+ padding-block: 0 woven.token(space-4);
99
+ padding-inline: woven.token(space-4);
100
+ line-height: woven.token(line-height-normal);
101
+ }
102
+
103
+ // Opt-in motion: the chevron turns and the panel height glides
104
+ @media (prefers-reduced-motion: no-preference) {
105
+ .wu-accordion.animated,
106
+ .wu-animated .wu-accordion {
107
+ .wu-accordion-trigger::after {
108
+ transition-property: rotate, translate;
109
+ transition-duration: woven.token(duration-200);
110
+ transition-timing-function: woven.token(ease-out);
111
+ }
112
+ }
113
+
114
+ @supports (interpolate-size: allow-keywords) and selector(::details-content) {
115
+ .wu-accordion.animated,
116
+ .wu-animated .wu-accordion {
117
+ interpolate-size: allow-keywords;
118
+
119
+ .wu-accordion-item::details-content {
120
+ block-size: 0;
121
+ overflow: clip;
122
+ transition:
123
+ block-size woven.token(duration-200) woven.token(ease-out),
124
+ content-visibility woven.token(duration-200) allow-discrete;
125
+ }
126
+
127
+ .wu-accordion-item[open]::details-content {
128
+ block-size: auto;
129
+ }
130
+ }
131
+ }
132
+ }