@grantcodes/ui 2.10.1 → 2.11.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.
- package/CHANGELOG.md +16 -0
- package/custom-elements.json +159 -10
- package/package.json +1 -1
- package/src/components/accordion/accordion-item.component.js +37 -0
- package/src/components/accordion/accordion-item.css +82 -0
- package/src/components/accordion/accordion.component.js +2 -30
- package/src/components/accordion/accordion.css +0 -73
- package/src/components/accordion/accordion.js +3 -0
- package/src/components/accordion/accordion.stories.js +89 -63
- package/src/components/accordion/accordion.test.js +103 -0
- package/src/components/accordion/index.js +3 -0
- package/src/css/elements/forms/input.css +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.11.0](https://github.com/grantcodes/ui/compare/ui-v2.10.2...ui-v2.11.0) (2026-05-03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **17-02:** add accordion htmlContent stories ([dbaafa6](https://github.com/grantcodes/ui/commit/dbaafa65806aa83c85e08254a59853f2b5aef4a6))
|
|
9
|
+
* **17-02:** implement accordion htmlContent rendering ([19f4fe1](https://github.com/grantcodes/ui/commit/19f4fe1f7fb40e06ab4e069233061716264ef130))
|
|
10
|
+
* **accordion:** redesign with slot-based GrantCodesAccordionItem ([59506a6](https://github.com/grantcodes/ui/commit/59506a6a51018837792679b93c641b7303faa5ad))
|
|
11
|
+
|
|
12
|
+
## [2.10.2](https://github.com/grantcodes/ui/compare/ui-v2.10.1...ui-v2.10.2) (2026-05-02)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* **ui:** only show invalid input style on focus ([3474346](https://github.com/grantcodes/ui/commit/3474346104c1073de2c866ea4f721991521df46d))
|
|
18
|
+
|
|
3
19
|
## [2.10.1](https://github.com/grantcodes/ui/compare/ui-v2.10.0...ui-v2.10.1) (2026-05-01)
|
|
4
20
|
|
|
5
21
|
|
package/custom-elements.json
CHANGED
|
@@ -4,38 +4,87 @@
|
|
|
4
4
|
"modules": [
|
|
5
5
|
{
|
|
6
6
|
"kind": "javascript-module",
|
|
7
|
-
"path": "src/components/accordion/accordion.component.js",
|
|
7
|
+
"path": "src/components/accordion/accordion-item.component.js",
|
|
8
8
|
"declarations": [
|
|
9
9
|
{
|
|
10
10
|
"kind": "class",
|
|
11
11
|
"description": "",
|
|
12
|
-
"name": "
|
|
12
|
+
"name": "GrantCodesAccordionItem",
|
|
13
13
|
"members": [
|
|
14
14
|
{
|
|
15
15
|
"kind": "field",
|
|
16
|
-
"name": "
|
|
16
|
+
"name": "open",
|
|
17
17
|
"privacy": "public",
|
|
18
18
|
"type": {
|
|
19
|
-
"text": "
|
|
19
|
+
"text": "boolean"
|
|
20
20
|
},
|
|
21
|
-
"default": "
|
|
22
|
-
"attribute": "
|
|
21
|
+
"default": "false",
|
|
22
|
+
"attribute": "open",
|
|
23
|
+
"reflects": true
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"kind": "field",
|
|
27
|
+
"name": "title",
|
|
28
|
+
"privacy": "public",
|
|
29
|
+
"type": {
|
|
30
|
+
"text": "string"
|
|
31
|
+
},
|
|
32
|
+
"default": "\"\"",
|
|
33
|
+
"attribute": "title"
|
|
23
34
|
}
|
|
24
35
|
],
|
|
25
36
|
"attributes": [
|
|
26
37
|
{
|
|
27
|
-
"name": "
|
|
38
|
+
"name": "open",
|
|
28
39
|
"type": {
|
|
29
|
-
"text": "
|
|
40
|
+
"text": "boolean"
|
|
30
41
|
},
|
|
31
|
-
"default": "
|
|
32
|
-
"fieldName": "
|
|
42
|
+
"default": "false",
|
|
43
|
+
"fieldName": "open"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "title",
|
|
47
|
+
"type": {
|
|
48
|
+
"text": "string"
|
|
49
|
+
},
|
|
50
|
+
"default": "\"\"",
|
|
51
|
+
"fieldName": "title"
|
|
33
52
|
}
|
|
34
53
|
],
|
|
35
54
|
"superclass": {
|
|
36
55
|
"name": "LitElement",
|
|
37
56
|
"package": "lit"
|
|
38
57
|
},
|
|
58
|
+
"tagName": "grantcodes-accordion-item",
|
|
59
|
+
"customElement": true,
|
|
60
|
+
"modulePath": "src/components/accordion/accordion-item.component.js",
|
|
61
|
+
"definitionPath": "src/components/accordion/index.js"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"exports": [
|
|
65
|
+
{
|
|
66
|
+
"kind": "js",
|
|
67
|
+
"name": "GrantCodesAccordionItem",
|
|
68
|
+
"declaration": {
|
|
69
|
+
"name": "GrantCodesAccordionItem",
|
|
70
|
+
"module": "src/components/accordion/accordion-item.component.js"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"kind": "javascript-module",
|
|
77
|
+
"path": "src/components/accordion/accordion.component.js",
|
|
78
|
+
"declarations": [
|
|
79
|
+
{
|
|
80
|
+
"kind": "class",
|
|
81
|
+
"description": "",
|
|
82
|
+
"name": "GrantCodesAccordion",
|
|
83
|
+
"members": [],
|
|
84
|
+
"superclass": {
|
|
85
|
+
"name": "LitElement",
|
|
86
|
+
"package": "lit"
|
|
87
|
+
},
|
|
39
88
|
"tagName": "grantcodes-accordion",
|
|
40
89
|
"customElement": true,
|
|
41
90
|
"modulePath": "src/components/accordion/accordion.component.js",
|
|
@@ -66,6 +115,14 @@
|
|
|
66
115
|
"module": "src/components/accordion/accordion.component.js"
|
|
67
116
|
}
|
|
68
117
|
},
|
|
118
|
+
{
|
|
119
|
+
"kind": "js",
|
|
120
|
+
"name": "*",
|
|
121
|
+
"declaration": {
|
|
122
|
+
"name": "*",
|
|
123
|
+
"module": "src/components/accordion/accordion-item.component.js"
|
|
124
|
+
}
|
|
125
|
+
},
|
|
69
126
|
{
|
|
70
127
|
"kind": "js",
|
|
71
128
|
"name": "default",
|
|
@@ -81,6 +138,14 @@
|
|
|
81
138
|
"name": "GrantCodesAccordion",
|
|
82
139
|
"module": "/src/components/accordion/accordion.component.js"
|
|
83
140
|
}
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"kind": "custom-element-definition",
|
|
144
|
+
"name": "grantcodes-accordion-item",
|
|
145
|
+
"declaration": {
|
|
146
|
+
"name": "GrantCodesAccordionItem",
|
|
147
|
+
"module": "/src/components/accordion/accordion-item.component.js"
|
|
148
|
+
}
|
|
84
149
|
}
|
|
85
150
|
]
|
|
86
151
|
},
|
|
@@ -97,6 +162,14 @@
|
|
|
97
162
|
"module": "src/components/accordion/accordion.component.js"
|
|
98
163
|
}
|
|
99
164
|
},
|
|
165
|
+
{
|
|
166
|
+
"kind": "js",
|
|
167
|
+
"name": "*",
|
|
168
|
+
"declaration": {
|
|
169
|
+
"name": "*",
|
|
170
|
+
"module": "src/components/accordion/accordion-item.component.js"
|
|
171
|
+
}
|
|
172
|
+
},
|
|
100
173
|
{
|
|
101
174
|
"kind": "js",
|
|
102
175
|
"name": "default",
|
|
@@ -112,6 +185,14 @@
|
|
|
112
185
|
"name": "GrantCodesAccordion",
|
|
113
186
|
"module": "/src/components/accordion/accordion.component.js"
|
|
114
187
|
}
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"kind": "custom-element-definition",
|
|
191
|
+
"name": "grantcodes-accordion-item",
|
|
192
|
+
"declaration": {
|
|
193
|
+
"name": "GrantCodesAccordionItem",
|
|
194
|
+
"module": "/src/components/accordion/accordion-item.component.js"
|
|
195
|
+
}
|
|
115
196
|
}
|
|
116
197
|
]
|
|
117
198
|
},
|
|
@@ -1435,6 +1516,16 @@
|
|
|
1435
1516
|
},
|
|
1436
1517
|
"default": "false"
|
|
1437
1518
|
},
|
|
1519
|
+
{
|
|
1520
|
+
"kind": "method",
|
|
1521
|
+
"name": "_animateChangedValues",
|
|
1522
|
+
"parameters": [
|
|
1523
|
+
{
|
|
1524
|
+
"name": "changed"
|
|
1525
|
+
}
|
|
1526
|
+
],
|
|
1527
|
+
"description": "Re-trigger the flip animation on value elements that changed."
|
|
1528
|
+
},
|
|
1438
1529
|
{
|
|
1439
1530
|
"kind": "field",
|
|
1440
1531
|
"name": "_days",
|
|
@@ -3210,6 +3301,27 @@
|
|
|
3210
3301
|
"text": "any[]"
|
|
3211
3302
|
},
|
|
3212
3303
|
"default": "[]"
|
|
3304
|
+
},
|
|
3305
|
+
{
|
|
3306
|
+
"kind": "field",
|
|
3307
|
+
"name": "variant",
|
|
3308
|
+
"privacy": "public",
|
|
3309
|
+
"type": {
|
|
3310
|
+
"text": "string"
|
|
3311
|
+
},
|
|
3312
|
+
"default": "\"default\"",
|
|
3313
|
+
"attribute": "variant",
|
|
3314
|
+
"reflects": true
|
|
3315
|
+
}
|
|
3316
|
+
],
|
|
3317
|
+
"attributes": [
|
|
3318
|
+
{
|
|
3319
|
+
"name": "variant",
|
|
3320
|
+
"type": {
|
|
3321
|
+
"text": "string"
|
|
3322
|
+
},
|
|
3323
|
+
"default": "\"default\"",
|
|
3324
|
+
"fieldName": "variant"
|
|
3213
3325
|
}
|
|
3214
3326
|
],
|
|
3215
3327
|
"superclass": {
|
|
@@ -3307,6 +3419,18 @@
|
|
|
3307
3419
|
"default": "\"\"",
|
|
3308
3420
|
"attribute": "button"
|
|
3309
3421
|
},
|
|
3422
|
+
{
|
|
3423
|
+
"kind": "field",
|
|
3424
|
+
"name": "center",
|
|
3425
|
+
"privacy": "public",
|
|
3426
|
+
"type": {
|
|
3427
|
+
"text": "boolean"
|
|
3428
|
+
},
|
|
3429
|
+
"description": "Whether to center-align text content.",
|
|
3430
|
+
"default": "false",
|
|
3431
|
+
"attribute": "center",
|
|
3432
|
+
"reflects": true
|
|
3433
|
+
},
|
|
3310
3434
|
{
|
|
3311
3435
|
"kind": "field",
|
|
3312
3436
|
"name": "href",
|
|
@@ -3363,6 +3487,15 @@
|
|
|
3363
3487
|
"default": "\"\"",
|
|
3364
3488
|
"fieldName": "button"
|
|
3365
3489
|
},
|
|
3490
|
+
{
|
|
3491
|
+
"name": "center",
|
|
3492
|
+
"type": {
|
|
3493
|
+
"text": "boolean"
|
|
3494
|
+
},
|
|
3495
|
+
"description": "Whether to center-align text content.",
|
|
3496
|
+
"default": "false",
|
|
3497
|
+
"fieldName": "center"
|
|
3498
|
+
},
|
|
3366
3499
|
{
|
|
3367
3500
|
"name": "href",
|
|
3368
3501
|
"type": {
|
|
@@ -3775,6 +3908,10 @@
|
|
|
3775
3908
|
},
|
|
3776
3909
|
"default": "\"\""
|
|
3777
3910
|
},
|
|
3911
|
+
{
|
|
3912
|
+
"kind": "field",
|
|
3913
|
+
"name": "_darkQuery"
|
|
3914
|
+
},
|
|
3778
3915
|
{
|
|
3779
3916
|
"kind": "field",
|
|
3780
3917
|
"name": "_embedUrl",
|
|
@@ -3796,6 +3933,18 @@
|
|
|
3796
3933
|
],
|
|
3797
3934
|
"description": "Calculate a bounding box around a point for the given zoom level."
|
|
3798
3935
|
},
|
|
3936
|
+
{
|
|
3937
|
+
"kind": "method",
|
|
3938
|
+
"name": "_isDark"
|
|
3939
|
+
},
|
|
3940
|
+
{
|
|
3941
|
+
"kind": "field",
|
|
3942
|
+
"name": "_onSchemeChange"
|
|
3943
|
+
},
|
|
3944
|
+
{
|
|
3945
|
+
"kind": "method",
|
|
3946
|
+
"name": "_updateFilter"
|
|
3947
|
+
},
|
|
3799
3948
|
{
|
|
3800
3949
|
"kind": "field",
|
|
3801
3950
|
"name": "\"directions-url\"",
|
package/package.json
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
import { html } from "lit/static-html.js";
|
|
3
|
+
import focusRingStyles from "../../lib/styles/focus-ring.css" with {
|
|
4
|
+
type: "css",
|
|
5
|
+
};
|
|
6
|
+
import accordionItemStyles from "./accordion-item.css" with { type: "css" };
|
|
7
|
+
|
|
8
|
+
export class GrantCodesAccordionItem extends LitElement {
|
|
9
|
+
static styles = [focusRingStyles, accordionItemStyles];
|
|
10
|
+
|
|
11
|
+
static properties = {
|
|
12
|
+
title: { type: String },
|
|
13
|
+
open: { type: Boolean, reflect: true },
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
constructor() {
|
|
17
|
+
super();
|
|
18
|
+
this.title = "";
|
|
19
|
+
this.open = false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
render() {
|
|
23
|
+
return html`
|
|
24
|
+
<details class="accordion__item" ?open=${this.open}>
|
|
25
|
+
<summary class="accordion__summary focus-ring">
|
|
26
|
+
<span>${this.title}</span>
|
|
27
|
+
<svg class="accordion__chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
28
|
+
<polyline points="6 9 12 15 18 9"></polyline>
|
|
29
|
+
</svg>
|
|
30
|
+
</summary>
|
|
31
|
+
<div class="accordion__content">
|
|
32
|
+
<slot></slot>
|
|
33
|
+
</div>
|
|
34
|
+
</details>
|
|
35
|
+
`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
*,
|
|
2
|
+
*::before,
|
|
3
|
+
*::after {
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
:host {
|
|
8
|
+
display: block;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.accordion__item {
|
|
12
|
+
border: 1px solid
|
|
13
|
+
var(--g-theme-color-border-subtle, var(--g-theme-color-border-default));
|
|
14
|
+
border-radius: var(--g-theme-border-radius-md, 0.5rem);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.accordion__item::details-content {
|
|
18
|
+
block-size: 0;
|
|
19
|
+
overflow: clip;
|
|
20
|
+
transition:
|
|
21
|
+
block-size 0.25s ease,
|
|
22
|
+
content-visibility 0.25s allow-discrete;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.accordion__item[open]::details-content {
|
|
26
|
+
block-size: auto;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.accordion__summary {
|
|
30
|
+
padding: var(--g-theme-spacing-md);
|
|
31
|
+
cursor: pointer;
|
|
32
|
+
background: var(--g-theme-color-background-subtle);
|
|
33
|
+
font-weight: var(--g-typography-font-weight-500);
|
|
34
|
+
list-style: none;
|
|
35
|
+
display: flex;
|
|
36
|
+
justify-content: space-between;
|
|
37
|
+
align-items: center;
|
|
38
|
+
gap: var(--g-theme-spacing-md);
|
|
39
|
+
border-radius: var(--g-theme-border-radius-md, 0.5rem);
|
|
40
|
+
transition-property: background-color, outline-width, outline-color;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.accordion__summary:hover {
|
|
44
|
+
background: var(
|
|
45
|
+
--g-theme-color-background-subtle-hover,
|
|
46
|
+
var(--g-theme-color-background-subtle)
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.accordion__summary::-webkit-details-marker {
|
|
51
|
+
display: none;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.accordion__chevron {
|
|
55
|
+
display: block;
|
|
56
|
+
inline-size: 1em;
|
|
57
|
+
block-size: 1em;
|
|
58
|
+
flex-shrink: 0;
|
|
59
|
+
transition: transform 0.25s ease;
|
|
60
|
+
color: var(--g-theme-color-content-subtle, currentColor);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.accordion__item[open] .accordion__chevron {
|
|
64
|
+
transform: rotateX(180deg);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.accordion__content {
|
|
68
|
+
padding: var(--g-theme-spacing-md);
|
|
69
|
+
background: var(--g-theme-color-background-default);
|
|
70
|
+
border-radius: 0 0 var(--g-theme-border-radius-md, 0.5rem)
|
|
71
|
+
var(--g-theme-border-radius-md, 0.5rem);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@media (prefers-reduced-motion: reduce) {
|
|
75
|
+
.accordion__chevron {
|
|
76
|
+
transition: none;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.accordion__item::details-content {
|
|
80
|
+
transition: none;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -1,39 +1,11 @@
|
|
|
1
1
|
import { LitElement } from "lit";
|
|
2
2
|
import { html } from "lit/static-html.js";
|
|
3
|
-
import focusRingStyles from "../../lib/styles/focus-ring.css" with {
|
|
4
|
-
type: "css",
|
|
5
|
-
};
|
|
6
3
|
import accordionStyles from "./accordion.css" with { type: "css" };
|
|
7
4
|
|
|
8
5
|
export class GrantCodesAccordion extends LitElement {
|
|
9
|
-
static styles = [
|
|
10
|
-
|
|
11
|
-
static properties = {
|
|
12
|
-
items: { type: Array },
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
constructor() {
|
|
16
|
-
super();
|
|
17
|
-
this.items = [];
|
|
18
|
-
}
|
|
6
|
+
static styles = [accordionStyles];
|
|
19
7
|
|
|
20
8
|
render() {
|
|
21
|
-
return html
|
|
22
|
-
<div class="accordion">
|
|
23
|
-
${this.items.map(
|
|
24
|
-
(item, index) => html`
|
|
25
|
-
<details class="accordion__item">
|
|
26
|
-
<summary class="accordion__summary focus-ring">
|
|
27
|
-
<span>${item.title}</span>
|
|
28
|
-
<svg class="accordion__chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
29
|
-
<polyline points="6 9 12 15 18 9"></polyline>
|
|
30
|
-
</svg>
|
|
31
|
-
</summary>
|
|
32
|
-
<div class="accordion__content">${item.content}</div>
|
|
33
|
-
</details>
|
|
34
|
-
`,
|
|
35
|
-
)}
|
|
36
|
-
</div>
|
|
37
|
-
`;
|
|
9
|
+
return html`<div class="accordion"><slot></slot></div>`;
|
|
38
10
|
}
|
|
39
11
|
}
|
|
@@ -13,76 +13,3 @@
|
|
|
13
13
|
flex-direction: column;
|
|
14
14
|
gap: var(--g-theme-spacing-sm);
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
.accordion__item {
|
|
18
|
-
border: 1px solid
|
|
19
|
-
var(--g-theme-color-border-subtle, var(--g-theme-color-border-default));
|
|
20
|
-
border-radius: var(--g-theme-border-radius-md, 0.5rem);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.accordion__item::details-content {
|
|
24
|
-
block-size: 0;
|
|
25
|
-
overflow: clip;
|
|
26
|
-
transition:
|
|
27
|
-
block-size 0.25s ease,
|
|
28
|
-
content-visibility 0.25s allow-discrete;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.accordion__item[open]::details-content {
|
|
32
|
-
block-size: auto;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.accordion__summary {
|
|
36
|
-
padding: var(--g-theme-spacing-md);
|
|
37
|
-
cursor: pointer;
|
|
38
|
-
background: var(--g-theme-color-background-subtle);
|
|
39
|
-
font-weight: var(--g-typography-font-weight-500);
|
|
40
|
-
list-style: none;
|
|
41
|
-
display: flex;
|
|
42
|
-
justify-content: space-between;
|
|
43
|
-
align-items: center;
|
|
44
|
-
gap: var(--g-theme-spacing-md);
|
|
45
|
-
border-radius: var(--g-theme-border-radius-md, 0.5rem);
|
|
46
|
-
transition-property: background-color, outline-width, outline-color;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.accordion__summary:hover {
|
|
50
|
-
background: var(
|
|
51
|
-
--g-theme-color-background-subtle-hover,
|
|
52
|
-
var(--g-theme-color-background-subtle)
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.accordion__summary::-webkit-details-marker {
|
|
57
|
-
display: none;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.accordion__chevron {
|
|
61
|
-
display: block;
|
|
62
|
-
inline-size: 1em;
|
|
63
|
-
block-size: 1em;
|
|
64
|
-
flex-shrink: 0;
|
|
65
|
-
transition: transform 0.25s ease;
|
|
66
|
-
color: var(--g-theme-color-content-subtle, currentColor);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.accordion__item[open] .accordion__chevron {
|
|
70
|
-
transform: rotateX(180deg);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.accordion__content {
|
|
74
|
-
padding: var(--g-theme-spacing-md);
|
|
75
|
-
background: var(--g-theme-color-background-default);
|
|
76
|
-
border-radius: 0 0 var(--g-theme-border-radius-md, 0.5rem)
|
|
77
|
-
var(--g-theme-border-radius-md, 0.5rem);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
@media (prefers-reduced-motion: reduce) {
|
|
81
|
-
.accordion__chevron {
|
|
82
|
-
transition: none;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.accordion__item::details-content {
|
|
86
|
-
transition: none;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { GrantCodesAccordion } from "./accordion.component.js";
|
|
2
|
+
import { GrantCodesAccordionItem } from "./accordion-item.component.js";
|
|
2
3
|
|
|
3
4
|
export * from "./accordion.component.js";
|
|
5
|
+
export * from "./accordion-item.component.js";
|
|
4
6
|
export default GrantCodesAccordion;
|
|
5
7
|
|
|
6
8
|
customElements.define("grantcodes-accordion", GrantCodesAccordion);
|
|
9
|
+
customElements.define("grantcodes-accordion-item", GrantCodesAccordionItem);
|
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { html } from "lit/static-html.js";
|
|
1
|
+
import { html } from "lit";
|
|
3
2
|
import "./accordion.js";
|
|
4
|
-
const { events, args, argTypes, template } = getStorybookHelpers(
|
|
5
|
-
"grantcodes-accordion",
|
|
6
|
-
);
|
|
7
3
|
|
|
8
4
|
const meta = {
|
|
9
5
|
title: "Components/Accordion",
|
|
10
6
|
component: "grantcodes-accordion",
|
|
11
|
-
args,
|
|
12
|
-
argTypes,
|
|
13
|
-
parameters: {
|
|
14
|
-
actions: {
|
|
15
|
-
handles: events,
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
7
|
};
|
|
19
8
|
|
|
20
9
|
export default meta;
|
|
@@ -23,66 +12,103 @@ export default meta;
|
|
|
23
12
|
* Default accordion with multiple items.
|
|
24
13
|
*/
|
|
25
14
|
export const Accordion = {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
title: "Can I customize it?",
|
|
40
|
-
content:
|
|
41
|
-
"Yes, you can style the accordion using CSS custom properties and theme variables.",
|
|
42
|
-
},
|
|
43
|
-
],
|
|
44
|
-
},
|
|
15
|
+
render: () => html`
|
|
16
|
+
<grantcodes-accordion>
|
|
17
|
+
<grantcodes-accordion-item title="What is this?">
|
|
18
|
+
This is an accordion component that allows you to collapse and expand content sections.
|
|
19
|
+
</grantcodes-accordion-item>
|
|
20
|
+
<grantcodes-accordion-item title="How do I use it?">
|
|
21
|
+
Wrap grantcodes-accordion-item elements inside a grantcodes-accordion.
|
|
22
|
+
</grantcodes-accordion-item>
|
|
23
|
+
<grantcodes-accordion-item title="Can I customize it?">
|
|
24
|
+
Yes, you can style the accordion using CSS custom properties and theme variables.
|
|
25
|
+
</grantcodes-accordion-item>
|
|
26
|
+
</grantcodes-accordion>
|
|
27
|
+
`,
|
|
45
28
|
};
|
|
46
29
|
|
|
47
30
|
/**
|
|
48
31
|
* Single item accordion.
|
|
49
32
|
*/
|
|
50
33
|
export const SingleItem = {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
],
|
|
59
|
-
},
|
|
34
|
+
render: () => html`
|
|
35
|
+
<grantcodes-accordion>
|
|
36
|
+
<grantcodes-accordion-item title="Click to expand">
|
|
37
|
+
This is the content that appears when you expand this accordion item.
|
|
38
|
+
</grantcodes-accordion-item>
|
|
39
|
+
</grantcodes-accordion>
|
|
40
|
+
`,
|
|
60
41
|
};
|
|
61
42
|
|
|
62
43
|
/**
|
|
63
|
-
* Accordion with multiple items expanded by default.
|
|
64
|
-
* Note: Native HTML details/summary doesn't support open by default,
|
|
65
|
-
* but you can control this with CSS or JavaScript if needed.
|
|
44
|
+
* Accordion with multiple items, first one expanded by default.
|
|
66
45
|
*/
|
|
67
46
|
export const MultipleItems = {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
47
|
+
render: () => html`
|
|
48
|
+
<grantcodes-accordion>
|
|
49
|
+
<grantcodes-accordion-item title="First Section" open>
|
|
50
|
+
Content for the first section.
|
|
51
|
+
</grantcodes-accordion-item>
|
|
52
|
+
<grantcodes-accordion-item title="Second Section">
|
|
53
|
+
Content for the second section.
|
|
54
|
+
</grantcodes-accordion-item>
|
|
55
|
+
<grantcodes-accordion-item title="Third Section">
|
|
56
|
+
Content for the third section.
|
|
57
|
+
</grantcodes-accordion-item>
|
|
58
|
+
<grantcodes-accordion-item title="Fourth Section">
|
|
59
|
+
Content for the fourth section.
|
|
60
|
+
</grantcodes-accordion-item>
|
|
61
|
+
</grantcodes-accordion>
|
|
62
|
+
`,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Text content in slots is plain text — HTML-looking strings display literally.
|
|
67
|
+
*/
|
|
68
|
+
export const EscapedPlainTextContent = {
|
|
69
|
+
render: () => html`
|
|
70
|
+
<grantcodes-accordion>
|
|
71
|
+
<grantcodes-accordion-item title="HTML-looking plain text">
|
|
72
|
+
<strong>This stays text</strong>
|
|
73
|
+
</grantcodes-accordion-item>
|
|
74
|
+
</grantcodes-accordion>
|
|
75
|
+
`,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Slotted HTML content renders naturally — consumers compose their own markup.
|
|
80
|
+
*/
|
|
81
|
+
export const TrustedHtmlContent = {
|
|
82
|
+
render: () => html`
|
|
83
|
+
<grantcodes-accordion>
|
|
84
|
+
<grantcodes-accordion-item title="Trusted rich content">
|
|
85
|
+
<p>This renders <strong>trusted HTML</strong>.</p>
|
|
86
|
+
<ul>
|
|
87
|
+
<li>Content is composed directly in your template</li>
|
|
88
|
+
<li>No unsafeHTML needed in the component</li>
|
|
89
|
+
</ul>
|
|
90
|
+
</grantcodes-accordion-item>
|
|
91
|
+
</grantcodes-accordion>
|
|
92
|
+
`,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Items can slot any HTML — paragraphs, lists, images, or plain text.
|
|
97
|
+
*/
|
|
98
|
+
export const MixedContent = {
|
|
99
|
+
render: () => html`
|
|
100
|
+
<grantcodes-accordion>
|
|
101
|
+
<grantcodes-accordion-item title="Rich markup">
|
|
102
|
+
<p>This panel uses <em>multiple</em> HTML elements:</p>
|
|
103
|
+
<ul>
|
|
104
|
+
<li>Paragraphs</li>
|
|
105
|
+
<li>Lists</li>
|
|
106
|
+
<li><strong>Emphasis</strong></li>
|
|
107
|
+
</ul>
|
|
108
|
+
</grantcodes-accordion-item>
|
|
109
|
+
<grantcodes-accordion-item title="Plain text">
|
|
110
|
+
This panel is just plain text.
|
|
111
|
+
</grantcodes-accordion-item>
|
|
112
|
+
</grantcodes-accordion>
|
|
113
|
+
`,
|
|
88
114
|
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { describe, it, afterEach } from "node:test";
|
|
2
|
+
import { strict as assert } from "node:assert";
|
|
3
|
+
import { fixture, cleanup } from "../../test-utils/index.js";
|
|
4
|
+
import "./accordion.js";
|
|
5
|
+
|
|
6
|
+
describe("Accordion", () => {
|
|
7
|
+
let element;
|
|
8
|
+
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
cleanup(element);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("renders a slot for accordion items", async () => {
|
|
14
|
+
element = await fixture("grantcodes-accordion");
|
|
15
|
+
const slot = element.shadowRoot.querySelector("slot:not([name])");
|
|
16
|
+
assert.ok(slot, "Default slot should exist");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("renders accordion wrapper", async () => {
|
|
20
|
+
element = await fixture("grantcodes-accordion");
|
|
21
|
+
const wrapper = element.shadowRoot.querySelector(".accordion");
|
|
22
|
+
assert.ok(wrapper, "Accordion wrapper should exist");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("accepts slotted accordion items", async () => {
|
|
26
|
+
element = await fixture("grantcodes-accordion");
|
|
27
|
+
const item = document.createElement("grantcodes-accordion-item");
|
|
28
|
+
item.setAttribute("title", "FAQ");
|
|
29
|
+
item.textContent = "Answer text";
|
|
30
|
+
element.appendChild(item);
|
|
31
|
+
await element.updateComplete;
|
|
32
|
+
await item.updateComplete;
|
|
33
|
+
|
|
34
|
+
const found = element.querySelector("grantcodes-accordion-item");
|
|
35
|
+
assert.ok(found, "Slotted accordion item should be present");
|
|
36
|
+
assert.strictEqual(found.getAttribute("title"), "FAQ");
|
|
37
|
+
assert.strictEqual(found.textContent, "Answer text");
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("GrantCodesAccordionItem", () => {
|
|
42
|
+
let element;
|
|
43
|
+
|
|
44
|
+
afterEach(() => {
|
|
45
|
+
cleanup(element);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("renders a details element with summary and slot", async () => {
|
|
49
|
+
element = await fixture("grantcodes-accordion-item", {
|
|
50
|
+
title: "Section",
|
|
51
|
+
});
|
|
52
|
+
const details = element.shadowRoot.querySelector("details");
|
|
53
|
+
const summary = element.shadowRoot.querySelector("summary");
|
|
54
|
+
const slot = element.shadowRoot.querySelector("slot");
|
|
55
|
+
|
|
56
|
+
assert.ok(details, "Details element should exist");
|
|
57
|
+
assert.ok(summary, "Summary should exist");
|
|
58
|
+
assert.ok(slot, "Slot should exist");
|
|
59
|
+
assert.strictEqual(summary.textContent.trim().replace(/\s+/g, " "), "Section");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("renders HTML content via slot", async () => {
|
|
63
|
+
element = await fixture("grantcodes-accordion-item", {
|
|
64
|
+
title: "Rich",
|
|
65
|
+
});
|
|
66
|
+
element.innerHTML = "<strong>Trusted</strong>";
|
|
67
|
+
await element.updateComplete;
|
|
68
|
+
|
|
69
|
+
const strong = element.querySelector("strong");
|
|
70
|
+
assert.ok(strong, "Slotted HTML should render a strong element");
|
|
71
|
+
assert.strictEqual(strong.textContent, "Trusted");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("renders text content as escaped plain text", async () => {
|
|
75
|
+
element = await fixture("grantcodes-accordion-item", {
|
|
76
|
+
title: "Plain",
|
|
77
|
+
});
|
|
78
|
+
element.textContent = "<strong>Plain</strong>";
|
|
79
|
+
await element.updateComplete;
|
|
80
|
+
|
|
81
|
+
const strong = element.querySelector("strong");
|
|
82
|
+
assert.strictEqual(strong, null, "Escaped text should not create a strong element");
|
|
83
|
+
assert.strictEqual(element.textContent, "<strong>Plain</strong>");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("supports the open attribute", async () => {
|
|
87
|
+
element = await fixture("grantcodes-accordion-item", {
|
|
88
|
+
title: "Open item",
|
|
89
|
+
open: true,
|
|
90
|
+
});
|
|
91
|
+
const details = element.shadowRoot.querySelector("details");
|
|
92
|
+
assert.ok(details.hasAttribute("open"), "Details should be open");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("renders an empty slot by default", async () => {
|
|
96
|
+
element = await fixture("grantcodes-accordion-item", {
|
|
97
|
+
title: "Empty",
|
|
98
|
+
});
|
|
99
|
+
const content = element.shadowRoot.querySelector(".accordion__content");
|
|
100
|
+
const slot = content.querySelector("slot");
|
|
101
|
+
assert.ok(slot, "Slot should exist in content area");
|
|
102
|
+
});
|
|
103
|
+
});
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { GrantCodesAccordion } from "./accordion.component.js";
|
|
2
|
+
import { GrantCodesAccordionItem } from "./accordion-item.component.js";
|
|
2
3
|
|
|
3
4
|
export * from "./accordion.component.js";
|
|
5
|
+
export * from "./accordion-item.component.js";
|
|
4
6
|
export default GrantCodesAccordion;
|
|
5
7
|
|
|
6
8
|
customElements.define("grantcodes-accordion", GrantCodesAccordion);
|
|
9
|
+
customElements.define("grantcodes-accordion-item", GrantCodesAccordionItem);
|