@nys-cui/cui-section 0.1.2

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/README.md ADDED
@@ -0,0 +1 @@
1
+ Prototype project being pushed to node and npm for testing
package/cui.jsonc ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "section",
3
+ "mode": "component",
4
+ "src": "src",
5
+ "entry": "section.js"
6
+ }
package/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@nys-cui/cui-section",
3
+ "description": "A generic section component used with Core UI 2",
4
+ "author": {
5
+ "name": "New York State Department of Tax and Finance"
6
+ },
7
+ "main": "./dist/js/section.js",
8
+ "type": "module",
9
+ "version": "0.1.2",
10
+ "scripts": {
11
+ "clean": "rm -rf ./dist",
12
+ "build": "npm run clean && cui --dep",
13
+ "postinstall": "node -e \"console.log('Post-Installing cui-section: %s', Date())\" && npm run build"
14
+ }
15
+ }
package/src/section.js ADDED
@@ -0,0 +1,211 @@
1
+ import SECTION_STYLES from './section.scss';
2
+
3
+ export default class CUI_SECTION extends HTMLElement {
4
+
5
+ constructor() {
6
+
7
+ super();
8
+
9
+ this.attachShadow({mode: 'open'});
10
+
11
+ this.state = {
12
+ sTitle: null
13
+ };
14
+
15
+ this.dSection = this;
16
+
17
+ // Key Shadow DOM Fields
18
+ this.sdSection = null;
19
+ this.sdSectionTitle = null;
20
+ this.sdSectionCollapseControl = null;
21
+ this.sdContentsContainer = null;
22
+
23
+ this.bLock = false;
24
+ }
25
+
26
+ get style() {
27
+ return `<style>${SECTION_STYLES}</style>`
28
+ }
29
+
30
+ get template() {
31
+
32
+ let sTemplate = `<section><header>
33
+ <h2 id="section-title"></h2>`;
34
+
35
+ if (!this.state.bHideControls) {
36
+
37
+ sTemplate += `
38
+ <div class="header-controls">
39
+ <button type="button" id="collapse-control">
40
+ <cui-icon src="caret-down"></cui-icon>
41
+ </button>
42
+ </div>`;
43
+ }
44
+
45
+ sTemplate += `</header><div class="container" id="container">
46
+ <slot name="section-text"></slot>
47
+ <slot name="section-contents"></slot>
48
+ <slot name="section-footer"></slot>
49
+ </div></section>`;
50
+
51
+ return sTemplate;
52
+ }
53
+
54
+ expand(dContainer) {
55
+
56
+ function transitionEnd() {
57
+
58
+ // remove "height" from the dContainer's inline styles, so it can return to its initial value
59
+ dContainer.style.height = "";
60
+
61
+ // mark the section as "currently not collapsed"
62
+ dContainer.setAttribute('data-collapsed', 'false');
63
+
64
+ // remove this event listener so it only gets triggered once
65
+ dContainer.removeEventListener('transitionend', transitionEnd, this);
66
+
67
+ }
68
+
69
+ this.bLock = true;
70
+
71
+ var sectionHeight = dContainer.scrollHeight;
72
+
73
+ // have the dContainer transition to the height of its inner content
74
+ dContainer.style.height = sectionHeight + 'px';
75
+
76
+ // when the next css transition finishes (which should be the one we just triggered)
77
+ dContainer.addEventListener('transitionend', transitionEnd, true);
78
+
79
+
80
+ }
81
+
82
+ collapse(dContainer) {
83
+
84
+ function transitionEnd(e) {
85
+
86
+ // mark the section as "currently collapsed"
87
+ dContainer.setAttribute('data-collapsed', 'true');
88
+
89
+ dContainer.style.height = "";
90
+
91
+ dContainer.removeEventListener('transitionend', transitionEnd, true);
92
+ }
93
+
94
+ // get the height of the dContainer's inner content, regardless of its actual size
95
+ var sectionHeight = dContainer.scrollHeight;
96
+
97
+ // temporarily disable all css transitions
98
+ var dContainerTransition = dContainer.style.transition;
99
+ dContainer.style.transition = '';
100
+
101
+ // on the next frame (as soon as the previous style change has taken effect),
102
+ // explicitly set the dContainer's height to its current pixel height, so we
103
+ // aren't transitioning out of 'auto'
104
+ requestAnimationFrame(function() {
105
+ dContainer.style.height = sectionHeight + 'px';
106
+ dContainer.style.transition = dContainerTransition;
107
+
108
+
109
+ // on the next frame (as soon as the previous style change has taken effect),
110
+ // have the dContainer transition to height: 0
111
+ requestAnimationFrame(function() {
112
+
113
+ dContainer.style.height = 0 + 'px';
114
+
115
+ dContainer.addEventListener('transitionend', transitionEnd, true);
116
+
117
+ });
118
+
119
+ });
120
+
121
+
122
+ }
123
+
124
+ connectedCallback() {
125
+
126
+ this.state = {
127
+ sTitle: this.getAttribute('sectiontitle') || "SECTION TITLE",
128
+ bHideControls: (this.getAttribute("hideControls") === "true") ? true : false,
129
+ bCollapsed: (this.getAttribute('collapsed') === "true") ? true : false,
130
+ asStyles: (this.getAttribute('styles')) ? this.getAttribute('styles').split(',') : null
131
+ }
132
+
133
+ this.render();
134
+ }
135
+
136
+ render() {
137
+
138
+ this.shadowRoot.innerHTML = `${this.style}${this.template}`;
139
+
140
+ this.sdSection = this.shadowRoot.querySelector(`:host > section`);
141
+ this.sdSectionTitle = this.shadowRoot.querySelector(`#section-title`);
142
+ this.sdContentsContainer = this.shadowRoot.querySelector(`#container`);
143
+
144
+ this.sdSectionTitle.appendChild(document.createTextNode(this.state.sTitle));
145
+
146
+ if (!this.state.bHideControls) {
147
+
148
+ this.sdSectionCollapseControl = this.shadowRoot.querySelector(`#collapse-control`);
149
+
150
+ // Bind the expand and collapse controls
151
+ if (this.sdSectionCollapseControl) {
152
+
153
+ // Configure the the inital collapse state
154
+ if (this.state.bCollapsed) {
155
+
156
+ this.sdSectionCollapseControl.classList.add('collapsed');
157
+ this.sdContentsContainer.setAttribute('data-collapsed', "true");
158
+ }
159
+
160
+ this.sdSectionCollapseControl.addEventListener('click', () => {
161
+
162
+ if (!this.bLock) {
163
+
164
+ if (this.sdContentsContainer.getAttribute('data-collapsed') === "true") {
165
+
166
+ this.sdSectionCollapseControl.classList.remove('collapsed');
167
+
168
+ this.expand(this.sdContentsContainer);
169
+ }
170
+ else {
171
+
172
+ this.sdSectionCollapseControl.classList.add('collapsed');
173
+
174
+ this.collapse(this.sdContentsContainer);
175
+ }
176
+
177
+ this.bLock = false;
178
+ }
179
+
180
+ });
181
+ }
182
+
183
+ }
184
+
185
+ if (this.state.asStyles) {
186
+
187
+ for (let sStyle of this.state.asStyles) {
188
+
189
+ switch(sStyle.toLowerCase()) {
190
+
191
+ case "subsection":
192
+
193
+ this.sdSection.classList.add('sub-section');
194
+ break;
195
+
196
+ }
197
+
198
+ }
199
+
200
+ }
201
+
202
+ setTimeout(() => {
203
+ let dSubSections = [...this.querySelectorAll('cui-section')];
204
+ dSubSections.forEach((dSubSection) => {
205
+ dSubSection.setAttribute('subsection', true);
206
+ })
207
+ })
208
+
209
+ }
210
+
211
+ }
@@ -0,0 +1,106 @@
1
+ :host {
2
+ display: block;
3
+ margin-bottom: 20px;
4
+
5
+ * {
6
+ box-sizing: border-box;
7
+ }
8
+
9
+ section {
10
+ background: var(--section-background-color);
11
+ border-radius: 5px;
12
+ box-shadow: var(--section-box-shadow-color) var(--section-box-shadow-x) var(--section-box-shadow-y) var(--section-box-shadow-blur);
13
+
14
+ header {
15
+ border-bottom: solid 1px var(--section-header-border-color);
16
+ display: flex;
17
+ margin: 0.75em 0.75em 20px;
18
+
19
+ h2, h3, h4, h5, h6 {
20
+ color: var(--section-header-text-color);
21
+ font-family: var(--section-header-fonts);
22
+ font-size: 20px;
23
+ margin: 10px 0 3px;
24
+ flex: 1;
25
+ }
26
+
27
+ .header-controls {
28
+ flex: 0 1 0;
29
+ margin: 10px 0 3px;
30
+
31
+ button {
32
+ background: transparent;
33
+ border: 0;
34
+ border-radius: 32px;
35
+ cursor: pointer;
36
+ height: 32px;
37
+ margin-left: 0.5em;
38
+ margin-top: -7px;
39
+ transform: rotate(180deg);
40
+ width: 32px;
41
+
42
+ cui-icon {
43
+
44
+ svg {
45
+ fill: var(--section-header-icon-color);
46
+ height: 16px;
47
+ position: relative;
48
+ top: 2px;
49
+ width: 16px;
50
+ }
51
+ }
52
+
53
+ &:hover {
54
+ background-color: var(--section-header-button-hover-color);
55
+ }
56
+
57
+ &.collapsed {
58
+ transform: rotate(0);
59
+ }
60
+ }
61
+ }
62
+
63
+ }
64
+
65
+ .container {
66
+ //margin: 0 0.75em 20px;
67
+ //margin: 0 0.75em;
68
+ transition: height 0.5s ease;
69
+ overflow: hidden;
70
+
71
+ &[data-collapsed="true"] {
72
+ height: 0;
73
+ }
74
+
75
+
76
+ }
77
+ }
78
+
79
+ }
80
+
81
+ :host([subsection]) {
82
+ section {
83
+ border: 1px solid var(--section-header-border-color);
84
+ box-shadow: none;
85
+
86
+ header {
87
+ margin: 0 0 20px;
88
+
89
+ h2, h3, h4, h5, h6 {
90
+ font-size: 18px;
91
+ margin: 10px 0 3px 0.75em;
92
+ }
93
+
94
+ .header-controls {
95
+ margin: 10px 0.75em 3px 0;
96
+ }
97
+ }
98
+ }
99
+ }
100
+
101
+ :host([subsection]):first-child {
102
+ section {
103
+ margin-top: 20px;
104
+ }
105
+ }
106
+