@nuvia-ui/components 4.0.1
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/package.json +27 -0
- package/src/ds-accordion/ds-accordion-item.js +288 -0
- package/src/ds-accordion/ds-accordion-item.stories.js +82 -0
- package/src/ds-accordion/ds-accordion.a11y.test.js +92 -0
- package/src/ds-accordion/ds-accordion.js +68 -0
- package/src/ds-accordion/ds-accordion.stories.js +118 -0
- package/src/ds-accordion/ds-accordion.test.js +146 -0
- package/src/ds-accordion/index.js +2 -0
- package/src/ds-action-bar/ds-action-bar.js +116 -0
- package/src/ds-action-bar/ds-action-bar.stories.js +86 -0
- package/src/ds-action-bar/ds-action-bar.test.js +64 -0
- package/src/ds-action-bar/index.js +1 -0
- package/src/ds-alert/ds-alert.a11y.test.js +151 -0
- package/src/ds-alert/ds-alert.js +223 -0
- package/src/ds-alert/ds-alert.mdx +142 -0
- package/src/ds-alert/ds-alert.stories.js +166 -0
- package/src/ds-alert/ds-alert.test.js +256 -0
- package/src/ds-alert/index.js +1 -0
- package/src/ds-avatar/ds-avatar.a11y.test.js +45 -0
- package/src/ds-avatar/ds-avatar.js +216 -0
- package/src/ds-avatar/ds-avatar.stories.js +120 -0
- package/src/ds-avatar/ds-avatar.test.js +83 -0
- package/src/ds-avatar/index.js +1 -0
- package/src/ds-avatar-extended/ds-avatar-extended.a11y.test.js +29 -0
- package/src/ds-avatar-extended/ds-avatar-extended.js +108 -0
- package/src/ds-avatar-extended/ds-avatar-extended.stories.js +93 -0
- package/src/ds-avatar-extended/ds-avatar-extended.test.js +66 -0
- package/src/ds-avatar-extended/index.js +1 -0
- package/src/ds-banner/ds-banner.a11y.test.js +51 -0
- package/src/ds-banner/ds-banner.js +233 -0
- package/src/ds-banner/ds-banner.stories.js +185 -0
- package/src/ds-banner/ds-banner.test.js +116 -0
- package/src/ds-banner/index.js +1 -0
- package/src/ds-breadcrumb-item/ds-breadcrumb-item.js +135 -0
- package/src/ds-breadcrumb-item/ds-breadcrumb-item.stories.js +49 -0
- package/src/ds-breadcrumb-item/ds-breadcrumb-item.test.js +55 -0
- package/src/ds-breadcrumbs/ds-breadcrumbs.js +194 -0
- package/src/ds-breadcrumbs/ds-breadcrumbs.stories.js +54 -0
- package/src/ds-breadcrumbs/ds-breadcrumbs.test.js +33 -0
- package/src/ds-button/ds-button.a11y.test.js +49 -0
- package/src/ds-button/ds-button.js +205 -0
- package/src/ds-button/ds-button.mdx +141 -0
- package/src/ds-button/ds-button.stories.js +152 -0
- package/src/ds-button/ds-button.test.js +62 -0
- package/src/ds-button/index.js +1 -0
- package/src/ds-button-group/ds-button-group.js +82 -0
- package/src/ds-button-group/ds-button-group.mdx +39 -0
- package/src/ds-button-group/ds-button-group.stories.js +47 -0
- package/src/ds-button-group/ds-button-group.test.js +47 -0
- package/src/ds-button-group/index.js +1 -0
- package/src/ds-checkbox/ds-checkbox.a11y.test.js +79 -0
- package/src/ds-checkbox/ds-checkbox.js +271 -0
- package/src/ds-checkbox/ds-checkbox.stories.js +77 -0
- package/src/ds-checkbox/ds-checkbox.test.js +191 -0
- package/src/ds-checkbox/index.js +1 -0
- package/src/ds-checkbox-group/ds-checkbox-group.a11y.test.js +146 -0
- package/src/ds-checkbox-group/ds-checkbox-group.js +235 -0
- package/src/ds-checkbox-group/ds-checkbox-group.stories.js +210 -0
- package/src/ds-checkbox-group/ds-checkbox-group.test.js +150 -0
- package/src/ds-checkbox-group/index.js +1 -0
- package/src/ds-dialog/ds-dialog.js +466 -0
- package/src/ds-dialog/ds-dialog.stories.js +274 -0
- package/src/ds-dialog/ds-dialog.test.js +441 -0
- package/src/ds-dialog/index.js +1 -0
- package/src/ds-dropdown/ds-dropdown.a11y.test.js +80 -0
- package/src/ds-dropdown/ds-dropdown.js +891 -0
- package/src/ds-dropdown/ds-dropdown.stories.js +259 -0
- package/src/ds-dropdown/ds-dropdown.test.js +268 -0
- package/src/ds-dropdown/index.js +1 -0
- package/src/ds-dropdown-group/ds-dropdown-group.js +55 -0
- package/src/ds-dropdown-panel/ds-dropdown-panel.js +34 -0
- package/src/ds-file-uploaded/ds-file-uploaded.a11y.test.js +40 -0
- package/src/ds-file-uploaded/ds-file-uploaded.js +135 -0
- package/src/ds-file-uploaded/ds-file-uploaded.mdx +33 -0
- package/src/ds-file-uploaded/ds-file-uploaded.stories.js +81 -0
- package/src/ds-file-uploaded/ds-file-uploaded.test.js +85 -0
- package/src/ds-file-uploader/ds-file-uploader.a11y.test.js +61 -0
- package/src/ds-file-uploader/ds-file-uploader.js +442 -0
- package/src/ds-file-uploader/ds-file-uploader.mdx +44 -0
- package/src/ds-file-uploader/ds-file-uploader.stories.js +76 -0
- package/src/ds-file-uploader/ds-file-uploader.test.js +142 -0
- package/src/ds-header/ds-header.a11y.test.js +38 -0
- package/src/ds-header/ds-header.js +149 -0
- package/src/ds-header/ds-header.stories.js +63 -0
- package/src/ds-header/ds-header.test.js +52 -0
- package/src/ds-header/index.js +1 -0
- package/src/ds-header-nav/ds-header-nav.a11y.test.js +69 -0
- package/src/ds-header-nav/ds-header-nav.js +114 -0
- package/src/ds-header-nav/ds-header-nav.stories.js +17 -0
- package/src/ds-header-nav/ds-header-nav.test.js +93 -0
- package/src/ds-header-nav-item/ds-header-nav-item.a11y.test.js +71 -0
- package/src/ds-header-nav-item/ds-header-nav-item.js +124 -0
- package/src/ds-header-nav-item/ds-header-nav-item.stories.js +43 -0
- package/src/ds-header-nav-item/ds-header-nav-item.test.js +61 -0
- package/src/ds-icon/ds-icon.a11y.test.js +49 -0
- package/src/ds-icon/ds-icon.js +75 -0
- package/src/ds-icon/ds-icon.mdx +36 -0
- package/src/ds-icon/ds-icon.stories.js +88 -0
- package/src/ds-icon/ds-icon.test.js +97 -0
- package/src/ds-icon/index.js +1 -0
- package/src/ds-icon-button/ds-icon-button.a11y.test.js +55 -0
- package/src/ds-icon-button/ds-icon-button.js +224 -0
- package/src/ds-icon-button/ds-icon-button.mdx +131 -0
- package/src/ds-icon-button/ds-icon-button.stories.js +128 -0
- package/src/ds-icon-button/ds-icon-button.test.js +90 -0
- package/src/ds-icon-button/index.js +1 -0
- package/src/ds-input/ds-input.a11y.test.js +145 -0
- package/src/ds-input/ds-input.js +645 -0
- package/src/ds-input/ds-input.mdx +251 -0
- package/src/ds-input/ds-input.stories.js +298 -0
- package/src/ds-input/ds-input.test.js +792 -0
- package/src/ds-input/index.js +1 -0
- package/src/ds-link/ds-link.js +111 -0
- package/src/ds-link/ds-link.stories.js +56 -0
- package/src/ds-link/ds-link.test.js +74 -0
- package/src/ds-list-item/ds-list-item.a11y.test.js +39 -0
- package/src/ds-list-item/ds-list-item.js +292 -0
- package/src/ds-list-item/ds-list-item.stories.js +101 -0
- package/src/ds-list-item/ds-list-item.test.js +63 -0
- package/src/ds-menu/ds-menu.js +30 -0
- package/src/ds-menu/ds-menu.stories.js +120 -0
- package/src/ds-menu/ds-menu.test.js +123 -0
- package/src/ds-menu-group/ds-menu-group.js +101 -0
- package/src/ds-menu-group/ds-menu-group.stories.js +99 -0
- package/src/ds-nav-item/ds-nav-item.a11y.test.js +91 -0
- package/src/ds-nav-item/ds-nav-item.js +307 -0
- package/src/ds-nav-item/ds-nav-item.stories.js +99 -0
- package/src/ds-nav-item/ds-nav-item.test.js +169 -0
- package/src/ds-nav-item/index.js +1 -0
- package/src/ds-nav-vertical/ds-nav-vertical.a11y.test.js +69 -0
- package/src/ds-nav-vertical/ds-nav-vertical.js +173 -0
- package/src/ds-nav-vertical/ds-nav-vertical.stories.js +124 -0
- package/src/ds-nav-vertical/ds-nav-vertical.test.js +176 -0
- package/src/ds-nav-vertical/index.js +1 -0
- package/src/ds-pagination/ds-pagination.a11y.test.js +50 -0
- package/src/ds-pagination/ds-pagination.js +232 -0
- package/src/ds-pagination/ds-pagination.stories.js +63 -0
- package/src/ds-pagination/ds-pagination.test.js +141 -0
- package/src/ds-pagination/index.js +1 -0
- package/src/ds-progress-bar/ds-progress-bar.a11y.test.js +25 -0
- package/src/ds-progress-bar/ds-progress-bar.js +81 -0
- package/src/ds-progress-bar/ds-progress-bar.stories.js +69 -0
- package/src/ds-progress-bar/ds-progress-bar.test.js +60 -0
- package/src/ds-radio/ds-radio.a11y.test.js +69 -0
- package/src/ds-radio/ds-radio.js +240 -0
- package/src/ds-radio/ds-radio.stories.js +102 -0
- package/src/ds-radio/ds-radio.test.js +114 -0
- package/src/ds-radio/index.js +1 -0
- package/src/ds-radio-group/ds-radio-group.a11y.test.js +164 -0
- package/src/ds-radio-group/ds-radio-group.js +257 -0
- package/src/ds-radio-group/ds-radio-group.stories.js +247 -0
- package/src/ds-radio-group/ds-radio-group.test.js +194 -0
- package/src/ds-radio-group/index.js +1 -0
- package/src/ds-rich-list/ds-rich-list.js +246 -0
- package/src/ds-rich-list/ds-rich-list.stories.js +368 -0
- package/src/ds-rich-list/ds-rich-list.test.js +293 -0
- package/src/ds-rich-list-item/ds-rich-list-item.js +579 -0
- package/src/ds-rich-list-item/ds-rich-list-item.stories.js +197 -0
- package/src/ds-rich-list-item/ds-rich-list-item.test.js +434 -0
- package/src/ds-slider/ds-slider.js +399 -0
- package/src/ds-slider/ds-slider.stories.js +107 -0
- package/src/ds-slider/ds-slider.test.js +308 -0
- package/src/ds-spinner/ds-spinner.js +173 -0
- package/src/ds-spinner/ds-spinner.stories.js +52 -0
- package/src/ds-spinner/ds-spinner.test.js +50 -0
- package/src/ds-status-border/ds-status-border.js +88 -0
- package/src/ds-status-border/ds-status-border.stories.js +242 -0
- package/src/ds-status-border/ds-status-border.test.js +168 -0
- package/src/ds-stepper/ds-stepper.a11y.test.js +198 -0
- package/src/ds-stepper/ds-stepper.js +207 -0
- package/src/ds-stepper/ds-stepper.stories.js +530 -0
- package/src/ds-stepper/ds-stepper.test.js +311 -0
- package/src/ds-stepper-item/ds-stepper-item.js +485 -0
- package/src/ds-stepper-item/ds-stepper-item.stories.js +288 -0
- package/src/ds-switch/ds-switch.js +348 -0
- package/src/ds-switch/ds-switch.stories.js +145 -0
- package/src/ds-switch/ds-switch.test.js +226 -0
- package/src/ds-switch/index.js +1 -0
- package/src/ds-tab-item/ds-tab-item.js +341 -0
- package/src/ds-tab-item/ds-tab-item.stories.js +69 -0
- package/src/ds-tabs/ds-tab-panel.js +48 -0
- package/src/ds-tabs/ds-tabs.a11y.test.js +56 -0
- package/src/ds-tabs/ds-tabs.js +180 -0
- package/src/ds-tabs/ds-tabs.stories.js +152 -0
- package/src/ds-tabs/ds-tabs.test.js +306 -0
- package/src/ds-tabs/index.js +3 -0
- package/src/ds-tag-action/ds-tag-action.a11y.test.js +32 -0
- package/src/ds-tag-action/ds-tag-action.js +185 -0
- package/src/ds-tag-action/ds-tag-action.stories.js +55 -0
- package/src/ds-tag-action/ds-tag-action.test.js +44 -0
- package/src/ds-tag-removable/ds-tag-removable.a11y.test.js +24 -0
- package/src/ds-tag-removable/ds-tag-removable.js +146 -0
- package/src/ds-tag-removable/ds-tag-removable.stories.js +52 -0
- package/src/ds-tag-removable/ds-tag-removable.test.js +46 -0
- package/src/ds-tag-status/ds-tag-status.a11y.test.js +93 -0
- package/src/ds-tag-status/ds-tag-status.js +164 -0
- package/src/ds-tag-status/ds-tag-status.stories.js +200 -0
- package/src/ds-tag-status/ds-tag-status.test.js +140 -0
- package/src/ds-tag-status/index.js +1 -0
- package/src/ds-textarea/ds-textarea-clearable.test.js +89 -0
- package/src/ds-textarea/ds-textarea.a11y.test.js +66 -0
- package/src/ds-textarea/ds-textarea.js +505 -0
- package/src/ds-textarea/ds-textarea.stories.js +335 -0
- package/src/ds-textarea/ds-textarea.test.js +218 -0
- package/src/ds-textarea/index.js +1 -0
- package/src/ds-thumbnail/ds-thumbnail.js +207 -0
- package/src/ds-thumbnail/ds-thumbnail.stories.js +217 -0
- package/src/ds-thumbnail/ds-thumbnail.test.js +220 -0
- package/src/ds-toast/ds-toast-provider.js +110 -0
- package/src/ds-toast/ds-toast.a11y.test.js +34 -0
- package/src/ds-toast/ds-toast.js +243 -0
- package/src/ds-toast/ds-toast.stories.js +143 -0
- package/src/ds-toast/ds-toast.test.js +93 -0
- package/src/ds-toast/index.js +2 -0
- package/src/ds-tooltip/ds-tooltip.a11y.test.js +110 -0
- package/src/ds-tooltip/ds-tooltip.js +217 -0
- package/src/ds-tooltip/ds-tooltip.mdx +75 -0
- package/src/ds-tooltip/ds-tooltip.stories.js +72 -0
- package/src/ds-tooltip/ds-tooltip.test.js +191 -0
- package/src/ds-tooltip/index.js +1 -0
- package/src/ds-tooltip/positioner.js +117 -0
- package/src/index.js +50 -0
- package/src/mixins/field-label.mixin.js +113 -0
- package/src/mixins/field-message.mixin.js +66 -0
- package/src/token-provider/index.js +1 -0
- package/src/token-provider/token-provider.a11y.test.js +44 -0
- package/src/token-provider/token-provider.js +85 -0
- package/src/token-provider/token-provider.stories.js +105 -0
- package/src/token-provider/token-provider.test.js +134 -0
- package/src/utils/number-input.utils.js +42 -0
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nuvia-ui/components",
|
|
3
|
+
"version": "4.0.1",
|
|
4
|
+
"description": "Web Components for the UI Kit",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.js",
|
|
9
|
+
"./ds-icon": "./src/ds-icon.js",
|
|
10
|
+
"./token-provider": "./src/token-provider.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"src/"
|
|
14
|
+
],
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@floating-ui/dom": "^1.7.4",
|
|
17
|
+
"lit": "^3.0.0"
|
|
18
|
+
},
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"@nuvia-ui/icons": "^4.0.1",
|
|
21
|
+
"@nuvia-ui/tokens": "^4.0.1"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public",
|
|
25
|
+
"registry": "https://registry.npmjs.org/"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { LitElement, html, css } from 'lit';
|
|
2
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
3
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
4
|
+
import '../ds-icon/ds-icon.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @element ds-accordion-item
|
|
8
|
+
* @summary An expandable section within an accordion.
|
|
9
|
+
*
|
|
10
|
+
* @slot - Content of the accordion item body.
|
|
11
|
+
* @slot icon - Decorative icon in the header.
|
|
12
|
+
* @slot title - Title content (replaces heading prop if present).
|
|
13
|
+
*
|
|
14
|
+
* @prop {boolean} open - Whether the item is expanded.
|
|
15
|
+
* @prop {boolean} disabled - Whether the item is disabled.
|
|
16
|
+
* @prop {string} chevronPosition - Position of the chevron ('left' | 'right'). Default: 'right'.
|
|
17
|
+
* @prop {boolean} divider - Whether to show a top divider.
|
|
18
|
+
* @prop {string} heading - Title text.
|
|
19
|
+
*
|
|
20
|
+
* @fires ds-accordion-item-toggle - Dispatched when the user toggles the item.
|
|
21
|
+
*/
|
|
22
|
+
export class DsAccordionItem extends LitElement {
|
|
23
|
+
static properties = {
|
|
24
|
+
open: { type: Boolean, reflect: true },
|
|
25
|
+
disabled: { type: Boolean, reflect: true },
|
|
26
|
+
chevronPosition: { type: String, attribute: 'chevron-position', reflect: true },
|
|
27
|
+
divider: { type: Boolean, reflect: true },
|
|
28
|
+
heading: { type: String },
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
static styles = css`
|
|
32
|
+
:host {
|
|
33
|
+
display: block;
|
|
34
|
+
box-sizing: border-box;
|
|
35
|
+
width: 100%;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.wrapper {
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Header Styles */
|
|
44
|
+
.header {
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
padding: 8px var(--ds-space-sm); /* Target 40px height: 20px (lh from token) + 4px (border) + 16px (padding) */
|
|
48
|
+
cursor: pointer;
|
|
49
|
+
user-select: none;
|
|
50
|
+
background-color: transparent;
|
|
51
|
+
border: 2px solid transparent;
|
|
52
|
+
outline: none;
|
|
53
|
+
transition: background-color 0.2s ease;
|
|
54
|
+
position: relative;
|
|
55
|
+
gap: 0; /* Gaps handled individually */
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Hover State */
|
|
59
|
+
.header:hover:not(.disabled) {
|
|
60
|
+
background-color: var(--ds-color-bg-hover, #f5f5f5);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* Focus State - Border around header */
|
|
64
|
+
.header:focus-visible:not(.disabled) {
|
|
65
|
+
border: 2px solid var(--ds-color-border-focus);
|
|
66
|
+
border-radius: var(--ds-radius-container, 4px);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Disabled State */
|
|
70
|
+
:host([disabled]) {
|
|
71
|
+
pointer-events: none;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.header.disabled {
|
|
75
|
+
opacity: var(--ds-opacity-disabled, 0.5);
|
|
76
|
+
cursor: not-allowed;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.divider {
|
|
80
|
+
height: 1px;
|
|
81
|
+
/* "Border is always strong" */
|
|
82
|
+
background-color: var(--ds-color-border-strong);
|
|
83
|
+
margin-bottom: 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Typography */
|
|
87
|
+
.title {
|
|
88
|
+
flex: 1; /* Takes available space */
|
|
89
|
+
font: var(--ds-typo-content-body-bold);
|
|
90
|
+
color: var(--ds-color-text-default);
|
|
91
|
+
display: flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Icons */
|
|
96
|
+
ds-icon {
|
|
97
|
+
--ds-icon-size: var(--ds-size-sm);
|
|
98
|
+
color: var(--ds-color-icon-default);
|
|
99
|
+
display: flex;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.chevron-container {
|
|
103
|
+
display: flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
justify-content: center;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.chevron-icon {
|
|
109
|
+
transition: transform 0.2s ease;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
:host([open]) .chevron-icon {
|
|
113
|
+
transform: rotate(180deg);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* Spacing Logic */
|
|
117
|
+
/*
|
|
118
|
+
"Distance between decorative icon and title is 4 pixels"
|
|
119
|
+
"Distance between this content and Chevron is 8 pixels"
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
/* Default (Chevron Right) */
|
|
123
|
+
.header:not(.chevron-left) .icon-slot-container {
|
|
124
|
+
margin-right: var(--ds-space-xs); /* 4px */
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.header:not(.chevron-left) .chevron-container {
|
|
128
|
+
margin-left: var(--ds-space-sm); /* 8px */
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* Chevron Left */
|
|
132
|
+
.header.chevron-left .chevron-container {
|
|
133
|
+
margin-right: var(--ds-space-sm); /* 8px "Distance between this content and Chevron" */
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.header.chevron-left .icon-slot-container {
|
|
137
|
+
margin-right: var(--ds-space-xs); /* 4px "Distance between decorative icon and title" */
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Hide empty icon container to avoid margin issues */
|
|
141
|
+
.icon-slot-container[hidden] {
|
|
142
|
+
display: none;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Body Styles - Grid Height Transition */
|
|
146
|
+
.body {
|
|
147
|
+
display: grid;
|
|
148
|
+
grid-template-rows: 0fr;
|
|
149
|
+
transition: grid-template-rows 0.3s ease-out, padding-bottom 0.3s ease-out, padding-top 0.3s ease-out;
|
|
150
|
+
padding-top: 0;
|
|
151
|
+
padding-bottom: 0;
|
|
152
|
+
padding-right: var(--ds-space-sm); /* Keep horizontal padding constant or transition it? Constant is safer for layout. */
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* Target the inner wrapper for height expansion */
|
|
156
|
+
.body-inner {
|
|
157
|
+
overflow: hidden;
|
|
158
|
+
opacity: 0;
|
|
159
|
+
transition: opacity 0.2s ease-out;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
:host([open]) .body {
|
|
163
|
+
grid-template-rows: 1fr;
|
|
164
|
+
padding-top: var(--ds-space-sm);
|
|
165
|
+
padding-bottom: var(--ds-space-md);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
:host([open]) .body-inner {
|
|
169
|
+
opacity: 1;
|
|
170
|
+
transition-delay: 0.1s; /* Slight delay for dissolve effect */
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
:host([chevron-position="left"]) .body {
|
|
174
|
+
padding-left: 40px;
|
|
175
|
+
padding-right: var(--ds-space-sm);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
:host([chevron-position="right"]) .body {
|
|
179
|
+
padding-left: var(--ds-space-sm);
|
|
180
|
+
padding-right: 40px;
|
|
181
|
+
}
|
|
182
|
+
`;
|
|
183
|
+
|
|
184
|
+
constructor() {
|
|
185
|
+
super();
|
|
186
|
+
this.open = false;
|
|
187
|
+
this.disabled = false;
|
|
188
|
+
this.chevronPosition = 'right';
|
|
189
|
+
this.divider = false;
|
|
190
|
+
this.heading = '';
|
|
191
|
+
this._hasIcon = false;
|
|
192
|
+
this._uniqueId = `ds-accordion-item-${Math.random().toString(36).substr(2, 9)}`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
_handleClick() {
|
|
196
|
+
if (this.disabled) return;
|
|
197
|
+
this.open = !this.open;
|
|
198
|
+
this.dispatchEvent(new CustomEvent('ds-accordion-item-toggle', {
|
|
199
|
+
detail: { open: this.open },
|
|
200
|
+
bubbles: true,
|
|
201
|
+
composed: true
|
|
202
|
+
}));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
_handleKeydown(e) {
|
|
206
|
+
if (this.disabled) return;
|
|
207
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
208
|
+
e.preventDefault();
|
|
209
|
+
this._handleClick();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
_handleIconSlotChange(e) {
|
|
214
|
+
const nodes = e.target.assignedNodes({ flatten: true });
|
|
215
|
+
this._hasIcon = nodes.length > 0;
|
|
216
|
+
this.requestUpdate();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
render() {
|
|
220
|
+
const isChevronLeft = this.chevronPosition === 'left';
|
|
221
|
+
const headerId = `${this._uniqueId}-header`;
|
|
222
|
+
const bodyId = `${this._uniqueId}-body`;
|
|
223
|
+
|
|
224
|
+
const chevron = html`
|
|
225
|
+
<div class="chevron-container">
|
|
226
|
+
<ds-icon
|
|
227
|
+
name="expand-more"
|
|
228
|
+
class="chevron-icon"
|
|
229
|
+
size="sm">
|
|
230
|
+
</ds-icon>
|
|
231
|
+
</div>
|
|
232
|
+
`;
|
|
233
|
+
|
|
234
|
+
const iconSlot = html`
|
|
235
|
+
<div class="icon-slot-container" ?hidden=${!this._hasIcon}>
|
|
236
|
+
<slot name="icon" @slotchange=${this._handleIconSlotChange}></slot>
|
|
237
|
+
</div>
|
|
238
|
+
`;
|
|
239
|
+
|
|
240
|
+
return html`
|
|
241
|
+
<div class="wrapper">
|
|
242
|
+
${this.divider ? html`<div class="divider"></div>` : ''}
|
|
243
|
+
|
|
244
|
+
<div
|
|
245
|
+
id=${headerId}
|
|
246
|
+
class=${classMap({
|
|
247
|
+
header: true,
|
|
248
|
+
'chevron-left': isChevronLeft,
|
|
249
|
+
disabled: this.disabled
|
|
250
|
+
})}
|
|
251
|
+
role="button"
|
|
252
|
+
aria-expanded=${this.open}
|
|
253
|
+
aria-disabled=${this.disabled}
|
|
254
|
+
aria-controls=${bodyId}
|
|
255
|
+
tabindex=${this.disabled ? '-1' : '0'}
|
|
256
|
+
@click=${this._handleClick}
|
|
257
|
+
@keydown=${this._handleKeydown}
|
|
258
|
+
>
|
|
259
|
+
${isChevronLeft ? chevron : ''}
|
|
260
|
+
|
|
261
|
+
${iconSlot}
|
|
262
|
+
|
|
263
|
+
<div class="title">
|
|
264
|
+
<slot name="title">${this.heading}</slot>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
${!isChevronLeft ? chevron : ''}
|
|
268
|
+
</div>
|
|
269
|
+
|
|
270
|
+
<div
|
|
271
|
+
id=${bodyId}
|
|
272
|
+
class="body"
|
|
273
|
+
role="region"
|
|
274
|
+
aria-labelledby=${headerId}
|
|
275
|
+
aria-hidden=${this.open ? 'false' : 'true'}
|
|
276
|
+
>
|
|
277
|
+
<div class="body-inner">
|
|
278
|
+
<slot></slot>
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
</div>
|
|
282
|
+
`;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (!customElements.get('ds-accordion-item')) {
|
|
287
|
+
customElements.define('ds-accordion-item', DsAccordionItem);
|
|
288
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
import './ds-accordion-item.js';
|
|
3
|
+
import '../ds-icon/ds-icon.js';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Components/Accordion Item',
|
|
7
|
+
component: 'ds-accordion-item',
|
|
8
|
+
argTypes: {
|
|
9
|
+
heading: { control: 'text' },
|
|
10
|
+
open: { control: 'boolean' },
|
|
11
|
+
disabled: { control: 'boolean' },
|
|
12
|
+
divider: { control: 'boolean' },
|
|
13
|
+
chevronPosition: {
|
|
14
|
+
control: 'radio',
|
|
15
|
+
options: ['left', 'right'],
|
|
16
|
+
description: 'Position of the chevron icon'
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const Template = ({ heading, open, disabled, divider, chevronPosition }) => html`
|
|
22
|
+
<style>
|
|
23
|
+
p {
|
|
24
|
+
font: var(--ds-typo-content-body-regular);
|
|
25
|
+
color: var(--ds-color-text-default);
|
|
26
|
+
margin: 0;
|
|
27
|
+
}
|
|
28
|
+
</style>
|
|
29
|
+
<ds-accordion-item
|
|
30
|
+
heading=${heading}
|
|
31
|
+
?open=${open}
|
|
32
|
+
?disabled=${disabled}
|
|
33
|
+
?divider=${divider}
|
|
34
|
+
chevron-position=${chevronPosition}
|
|
35
|
+
>
|
|
36
|
+
<p>This is the body content of the accordion item. It uses the system typography tokens.</p>
|
|
37
|
+
</ds-accordion-item>
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
export const Default = Template.bind({});
|
|
41
|
+
Default.args = {
|
|
42
|
+
heading: 'Accordion Item',
|
|
43
|
+
open: false,
|
|
44
|
+
disabled: false,
|
|
45
|
+
divider: true,
|
|
46
|
+
chevronPosition: 'right',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const WithoutDivider = Template.bind({});
|
|
50
|
+
WithoutDivider.args = {
|
|
51
|
+
heading: 'Item without Divider',
|
|
52
|
+
divider: false,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const WithIcon = () => html`
|
|
56
|
+
<style>
|
|
57
|
+
p {
|
|
58
|
+
font: var(--ds-typo-content-body-regular);
|
|
59
|
+
color: var(--ds-color-text-default);
|
|
60
|
+
margin: 0;
|
|
61
|
+
}
|
|
62
|
+
</style>
|
|
63
|
+
<ds-accordion-item heading="Item with Icon" divider>
|
|
64
|
+
<ds-icon slot="icon" name="info" size="sm"></ds-icon>
|
|
65
|
+
<p>This item has a decorative icon in the header.</p>
|
|
66
|
+
</ds-accordion-item>
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
export const ChevronLeft = Template.bind({});
|
|
70
|
+
ChevronLeft.args = {
|
|
71
|
+
heading: 'Chevron Left',
|
|
72
|
+
chevronPosition: 'left',
|
|
73
|
+
open: true,
|
|
74
|
+
divider: true,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const Disabled = Template.bind({});
|
|
78
|
+
Disabled.args = {
|
|
79
|
+
heading: 'Disabled Item',
|
|
80
|
+
disabled: true,
|
|
81
|
+
divider: true,
|
|
82
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import './ds-accordion.js';
|
|
3
|
+
import './ds-accordion-item.js';
|
|
4
|
+
|
|
5
|
+
describe('ds-accordion a11y', () => {
|
|
6
|
+
let container;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
container = document.createElement('div');
|
|
10
|
+
document.body.appendChild(container);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
container.remove();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('ds-accordion-item has correct aria attributes and linkage', async () => {
|
|
18
|
+
container.innerHTML = '<ds-accordion-item heading="Test">Content</ds-accordion-item>';
|
|
19
|
+
const el = container.querySelector('ds-accordion-item');
|
|
20
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
21
|
+
|
|
22
|
+
const header = el.shadowRoot.querySelector('.header');
|
|
23
|
+
const body = el.shadowRoot.querySelector('.body');
|
|
24
|
+
|
|
25
|
+
expect(header.getAttribute('role')).toBe('button');
|
|
26
|
+
expect(header.getAttribute('aria-expanded')).toBe('false');
|
|
27
|
+
expect(header.getAttribute('aria-disabled')).toBe('false');
|
|
28
|
+
|
|
29
|
+
// precise ID check
|
|
30
|
+
const headerId = header.getAttribute('id');
|
|
31
|
+
const bodyId = body.getAttribute('id');
|
|
32
|
+
expect(headerId).toBeTruthy();
|
|
33
|
+
expect(bodyId).toBeTruthy();
|
|
34
|
+
|
|
35
|
+
expect(header.getAttribute('aria-controls')).toBe(bodyId);
|
|
36
|
+
|
|
37
|
+
expect(body.getAttribute('role')).toBe('region');
|
|
38
|
+
expect(body.getAttribute('aria-hidden')).toBe('true');
|
|
39
|
+
expect(body.getAttribute('aria-labelledby')).toBe(headerId);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('updates aria-expanded and aria-hidden on toggle', async () => {
|
|
43
|
+
container.innerHTML = '<ds-accordion-item heading="Test">Content</ds-accordion-item>';
|
|
44
|
+
const el = container.querySelector('ds-accordion-item');
|
|
45
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
46
|
+
|
|
47
|
+
const header = el.shadowRoot.querySelector('.header');
|
|
48
|
+
const body = el.shadowRoot.querySelector('.body');
|
|
49
|
+
|
|
50
|
+
header.click();
|
|
51
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
52
|
+
|
|
53
|
+
expect(header.getAttribute('aria-expanded')).toBe('true');
|
|
54
|
+
expect(body.getAttribute('aria-hidden')).toBe('false');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('handles keyboard interaction (Enter)', async () => {
|
|
58
|
+
container.innerHTML = '<ds-accordion-item heading="Test">Content</ds-accordion-item>';
|
|
59
|
+
const el = container.querySelector('ds-accordion-item');
|
|
60
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
61
|
+
|
|
62
|
+
const header = el.shadowRoot.querySelector('.header');
|
|
63
|
+
|
|
64
|
+
header.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, composed: true }));
|
|
65
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
66
|
+
|
|
67
|
+
expect(el.open).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('handles keyboard interaction (Space)', async () => {
|
|
71
|
+
container.innerHTML = '<ds-accordion-item heading="Test">Content</ds-accordion-item>';
|
|
72
|
+
const el = container.querySelector('ds-accordion-item');
|
|
73
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
74
|
+
|
|
75
|
+
const header = el.shadowRoot.querySelector('.header');
|
|
76
|
+
|
|
77
|
+
header.dispatchEvent(new KeyboardEvent('keydown', { key: ' ', bubbles: true, composed: true }));
|
|
78
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
79
|
+
|
|
80
|
+
expect(el.open).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('disabled item has aria-disabled true and tabindex -1', async () => {
|
|
84
|
+
container.innerHTML = '<ds-accordion-item heading="Test" disabled>Content</ds-accordion-item>';
|
|
85
|
+
const el = container.querySelector('ds-accordion-item');
|
|
86
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
87
|
+
|
|
88
|
+
const header = el.shadowRoot.querySelector('.header');
|
|
89
|
+
expect(header.getAttribute('aria-disabled')).toBe('true');
|
|
90
|
+
expect(header.getAttribute('tabindex')).toBe('-1');
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { LitElement, html, css, unsafeCSS } from 'lit';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @element ds-accordion
|
|
5
|
+
* @summary A container for expandable content sections.
|
|
6
|
+
*
|
|
7
|
+
* @slot - Default slot for ds-accordion-item children.
|
|
8
|
+
*
|
|
9
|
+
* @prop {boolean} multiple - If true, allows multiple items to be open at once.
|
|
10
|
+
*/
|
|
11
|
+
export class DsAccordion extends LitElement {
|
|
12
|
+
static properties = {
|
|
13
|
+
multiple: { type: Boolean, reflect: true },
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
static styles = css`
|
|
17
|
+
:host {
|
|
18
|
+
display: block;
|
|
19
|
+
width: 100%;
|
|
20
|
+
}
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
constructor() {
|
|
24
|
+
super();
|
|
25
|
+
this.multiple = false;
|
|
26
|
+
this._handleToggle = this._handleToggle.bind(this);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
connectedCallback() {
|
|
30
|
+
super.connectedCallback();
|
|
31
|
+
this.addEventListener('ds-accordion-item-toggle', this._handleToggle);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
disconnectedCallback() {
|
|
35
|
+
super.disconnectedCallback();
|
|
36
|
+
this.removeEventListener('ds-accordion-item-toggle', this._handleToggle);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Handles the toggle event from accordion items.
|
|
41
|
+
* If not in multiple mode, closes other open items.
|
|
42
|
+
* @param {CustomEvent} event
|
|
43
|
+
*/
|
|
44
|
+
_handleToggle(event) {
|
|
45
|
+
if (this.multiple) return;
|
|
46
|
+
|
|
47
|
+
const toggledItem = event.target;
|
|
48
|
+
// If the item was just opened (it is open now), close others
|
|
49
|
+
if (toggledItem.open) {
|
|
50
|
+
const items = [...this.querySelectorAll('ds-accordion-item')];
|
|
51
|
+
items.forEach((item) => {
|
|
52
|
+
if (item !== toggledItem && item.open) {
|
|
53
|
+
item.open = false;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
render() {
|
|
60
|
+
return html`
|
|
61
|
+
<slot></slot>
|
|
62
|
+
`;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!customElements.get('ds-accordion')) {
|
|
67
|
+
customElements.define('ds-accordion', DsAccordion);
|
|
68
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
import './ds-accordion.js';
|
|
3
|
+
import './ds-accordion-item.js';
|
|
4
|
+
import '../ds-icon/ds-icon.js';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: 'Components/Accordion',
|
|
8
|
+
component: 'ds-accordion',
|
|
9
|
+
argTypes: {
|
|
10
|
+
multiple: { control: 'boolean' },
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const Template = ({ multiple }) => html`
|
|
15
|
+
<style>
|
|
16
|
+
p {
|
|
17
|
+
font: var(--ds-typo-content-body-regular);
|
|
18
|
+
color: var(--ds-color-text-default);
|
|
19
|
+
margin: 0;
|
|
20
|
+
}
|
|
21
|
+
</style>
|
|
22
|
+
<ds-accordion ?multiple=${multiple}>
|
|
23
|
+
<ds-accordion-item heading="First Item" open divider>
|
|
24
|
+
<p>This is the content of the first item.</p>
|
|
25
|
+
</ds-accordion-item>
|
|
26
|
+
<ds-accordion-item heading="Second Item" divider>
|
|
27
|
+
<p>This is the content of the second item.</p>
|
|
28
|
+
</ds-accordion-item>
|
|
29
|
+
<ds-accordion-item heading="Third Item (Disabled)" disabled divider>
|
|
30
|
+
<p>This content is not accessible.</p>
|
|
31
|
+
</ds-accordion-item>
|
|
32
|
+
</ds-accordion>
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
export const Default = Template.bind({});
|
|
36
|
+
Default.args = {
|
|
37
|
+
multiple: false,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const MultipleOpen = Template.bind({});
|
|
41
|
+
MultipleOpen.args = {
|
|
42
|
+
multiple: true,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const WithIcons = () => html`
|
|
46
|
+
<style>
|
|
47
|
+
p {
|
|
48
|
+
font: var(--ds-typo-content-body-regular);
|
|
49
|
+
color: var(--ds-color-text-default);
|
|
50
|
+
margin: 0;
|
|
51
|
+
}
|
|
52
|
+
</style>
|
|
53
|
+
<ds-accordion>
|
|
54
|
+
<ds-accordion-item heading="Account Settings" divider>
|
|
55
|
+
<ds-icon slot="icon" name="settings" size="sm"></ds-icon>
|
|
56
|
+
<p>Manage your account settings here.</p>
|
|
57
|
+
</ds-accordion-item>
|
|
58
|
+
<ds-accordion-item heading="Notifications" divider>
|
|
59
|
+
<ds-icon slot="icon" name="notifications" size="sm"></ds-icon>
|
|
60
|
+
<p>Configure your notification preferences.</p>
|
|
61
|
+
</ds-accordion-item>
|
|
62
|
+
</ds-accordion>
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
export const ChevronLeft = () => html`
|
|
66
|
+
<style>
|
|
67
|
+
p {
|
|
68
|
+
font: var(--ds-typo-content-body-regular);
|
|
69
|
+
color: var(--ds-color-text-default);
|
|
70
|
+
margin: 0;
|
|
71
|
+
}
|
|
72
|
+
</style>
|
|
73
|
+
<ds-accordion>
|
|
74
|
+
<ds-accordion-item heading="Chevron Left Item 1" chevron-position="left" divider>
|
|
75
|
+
<p>Notice the indentation of the content matches the header content.</p>
|
|
76
|
+
</ds-accordion-item>
|
|
77
|
+
<ds-accordion-item heading="Chevron Left Item 2" chevron-position="left" divider>
|
|
78
|
+
<p>Content padding left should be 40px.</p>
|
|
79
|
+
</ds-accordion-item>
|
|
80
|
+
</ds-accordion>
|
|
81
|
+
`;
|
|
82
|
+
|
|
83
|
+
export const CustomTitleSlot = () => html`
|
|
84
|
+
<style>
|
|
85
|
+
p {
|
|
86
|
+
font: var(--ds-typo-content-body-regular);
|
|
87
|
+
color: var(--ds-color-text-default);
|
|
88
|
+
margin: 0;
|
|
89
|
+
}
|
|
90
|
+
</style>
|
|
91
|
+
<ds-accordion>
|
|
92
|
+
<ds-accordion-item divider>
|
|
93
|
+
<div slot="title" style="display: flex; align-items: center; justify-content: space-between; width: 100%;">
|
|
94
|
+
<span>Complex Title</span>
|
|
95
|
+
<span style="font-size: 12px; color: grey;">Meta info</span>
|
|
96
|
+
</div>
|
|
97
|
+
<p>Content for complex title item.</p>
|
|
98
|
+
</ds-accordion-item>
|
|
99
|
+
</ds-accordion>
|
|
100
|
+
`;
|
|
101
|
+
|
|
102
|
+
export const WithoutDivider = () => html`
|
|
103
|
+
<style>
|
|
104
|
+
p {
|
|
105
|
+
font: var(--ds-typo-content-body-regular);
|
|
106
|
+
color: var(--ds-color-text-default);
|
|
107
|
+
margin: 0;
|
|
108
|
+
}
|
|
109
|
+
</style>
|
|
110
|
+
<ds-accordion>
|
|
111
|
+
<ds-accordion-item heading="Item without Divider">
|
|
112
|
+
<p>This item has no top divider.</p>
|
|
113
|
+
</ds-accordion-item>
|
|
114
|
+
<ds-accordion-item heading="Another Item">
|
|
115
|
+
<p>Also has no divider.</p>
|
|
116
|
+
</ds-accordion-item>
|
|
117
|
+
</ds-accordion>
|
|
118
|
+
`;
|