Skip to content

Commit d261b56

Browse files
committed
chore: Deploy EDS blocks from migration tool
1 parent 3c7140d commit d261b56

23 files changed

+1063
-545
lines changed

blocks/accordion/accordion.css

Lines changed: 14 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,22 @@
1-
/* blocks/accordion/accordion.css */
2-
.accordion {
3-
--accordion-bg: #fff;
4-
--accordion-header-bg: #f8f8f8;
5-
--accordion-header-hover-bg: #efefef;
6-
--accordion-border-color: #e0e0e0;
7-
--accordion-accent-color: #ff6b35;
8-
--accordion-text-color: #333;
9-
--accordion-content-text: #666;
10-
--accordion-focus-ring: #2c5f7c;
11-
12-
background: var(--accordion-bg);
13-
padding: 60px 20px;
14-
}
15-
16-
.accordion > div {
17-
max-width: 1200px;
18-
margin: 0 auto;
19-
}
20-
21-
.accordion .accordion-header {
22-
display: flex;
23-
align-items: center;
24-
gap: 20px;
25-
padding: 24px;
26-
background: var(--accordion-header-bg);
27-
border: 2px solid var(--accordion-border-color);
28-
border-radius: 8px 8px 0 0;
29-
cursor: pointer;
30-
position: relative;
31-
margin-top: 16px;
32-
transition: background 0.2s, box-shadow 0.2s;
33-
}
34-
35-
.accordion .accordion-header:hover {
36-
background: var(--accordion-header-hover-bg);
37-
}
38-
39-
.accordion .accordion-header:focus-visible {
40-
outline: none;
41-
box-shadow: 0 0 0 3px var(--accordion-focus-ring);
42-
z-index: 1;
43-
}
44-
45-
.accordion .accordion-header:first-child {
46-
margin-top: 0;
47-
}
48-
49-
.accordion .accordion-header::after {
50-
content: '+';
51-
position: absolute;
52-
right: 24px;
53-
font-size: 36px;
54-
font-weight: bold;
55-
color: var(--accordion-accent-color);
56-
line-height: 1;
57-
transition: transform 0.3s;
58-
}
59-
60-
.accordion .accordion-header.active::after {
61-
content: '-';
62-
transform: rotate(180deg);
63-
}
64-
65-
.accordion .accordion-header img {
66-
width: 60px;
67-
height: 60px;
68-
object-fit: contain;
69-
}
70-
71-
.accordion .accordion-header strong {
72-
font-size: 20px;
73-
color: var(--accordion-text-color);
74-
flex: 1;
75-
}
1+
/**
2+
* accordion Block Styles
3+
* Generated by NxPlatform Migration Tool
4+
*/
765

77-
.accordion .accordion-content {
78-
max-height: 0;
79-
overflow: hidden;
80-
padding: 0 24px;
81-
border: 2px solid var(--accordion-border-color);
82-
border-top: none;
83-
border-radius: 0 0 8px 8px;
84-
background: var(--accordion-bg);
85-
transition: max-height 0.4s ease, padding 0.4s ease;
6+
.accordion {
7+
display: block;
8+
padding: var(--spacing-l);
869
}
8710

88-
.accordion .accordion-content.active {
89-
max-height: 800px;
90-
padding: 24px;
11+
.accordion .items {
12+
margin-bottom: var(--spacing-m);
9113
}
9214

93-
.accordion .accordion-content p {
94-
margin: 0;
95-
line-height: 1.6;
96-
color: var(--accordion-content-text);
15+
/* Responsive styles */
16+
@media (min-width: 900px) {
17+
.accordion {
18+
padding: var(--spacing-xl);
19+
}
9720
}
9821

99-
@media (width < 768px) {
100-
.accordion .accordion-header {
101-
padding: 16px;
102-
gap: 12px;
103-
}
10422

105-
.accordion .accordion-header img {
106-
width: 40px;
107-
height: 40px;
108-
}
109-
110-
.accordion .accordion-header strong {
111-
font-size: 16px;
112-
}
113-
}

blocks/accordion/accordion.js

Lines changed: 88 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,104 @@
11
/**
2-
* Accordion Block
3-
* Accessible accordion component with keyboard navigation
2+
* accordion Block
3+
* Generated by NxPlatform Migration Tool
44
*/
55

6-
let accordionIdCounter = 0;
7-
8-
function generateId() {
9-
accordionIdCounter += 1;
10-
return `accordion-panel-${accordionIdCounter}`;
11-
}
12-
13-
function toggleAccordion(header, content, children, forceState = null) {
14-
const isActive = forceState !== null ? !forceState : header.classList.contains('active');
15-
16-
// Close all panels
17-
children.forEach((child) => {
18-
child.classList.remove('active');
19-
if (child.hasAttribute('aria-expanded')) {
20-
child.setAttribute('aria-expanded', 'false');
21-
}
22-
});
23-
24-
// Open clicked panel if it wasn't active
25-
if (!isActive) {
26-
header.classList.add('active');
27-
header.setAttribute('aria-expanded', 'true');
28-
content.classList.add('active');
29-
}
30-
}
31-
32-
function handleKeydown(e, header, content, children, headers) {
33-
const currentIndex = headers.indexOf(header);
34-
35-
switch (e.key) {
36-
case 'Enter':
37-
case ' ':
38-
e.preventDefault();
39-
toggleAccordion(header, content, children);
40-
break;
41-
case 'ArrowDown':
42-
e.preventDefault();
43-
if (currentIndex < headers.length - 1) {
44-
headers[currentIndex + 1].focus();
45-
}
46-
break;
47-
case 'ArrowUp':
48-
e.preventDefault();
49-
if (currentIndex > 0) {
50-
headers[currentIndex - 1].focus();
51-
}
52-
break;
53-
case 'Home':
54-
e.preventDefault();
55-
headers[0].focus();
56-
break;
57-
case 'End':
58-
e.preventDefault();
59-
headers[headers.length - 1].focus();
60-
break;
61-
default:
62-
break;
63-
}
64-
}
65-
666
export default function decorate(block) {
67-
const container = block.querySelector(':scope > div');
68-
if (!container) return;
7+
// Get block configuration
8+
const config = readBlockConfig(block);
699

70-
const children = Array.from(container.children);
71-
const headers = [];
10+
// Process rows and cells
11+
const rows = [...block.children];
7212

73-
// Set up accordion role
74-
block.setAttribute('role', 'presentation');
13+
rows.forEach((row, index) => {
14+
const cells = [...row.children];
7515

76-
for (let i = 0; i < children.length; i += 2) {
77-
const header = children[i];
78-
const content = children[i + 1];
16+
cells.forEach((cell, cellIndex) => {
17+
// Add semantic classes based on field mapping
18+
const fieldName = getFieldName(index, cellIndex);
19+
if (fieldName) {
20+
cell.classList.add(fieldName);
21+
}
7922

80-
if (header && content) {
81-
const panelId = generateId();
23+
// Process images
24+
processImages(cell);
8225

83-
// Set up header accessibility attributes
84-
header.setAttribute('role', 'button');
85-
header.setAttribute('tabindex', '0');
86-
header.setAttribute('aria-expanded', 'false');
87-
header.setAttribute('aria-controls', panelId);
88-
header.classList.add('accordion-header');
26+
// Process links
27+
processLinks(cell);
28+
});
29+
});
8930

90-
// Set up content accessibility attributes
91-
content.setAttribute('id', panelId);
92-
content.setAttribute('role', 'region');
93-
content.setAttribute('aria-labelledby', `${panelId}-header`);
94-
header.setAttribute('id', `${panelId}-header`);
95-
content.classList.add('accordion-content');
31+
// Add block-specific initialization
32+
initializeBlock(block, config);
33+
}
9634

97-
headers.push(header);
35+
/**
36+
* Read block configuration from data attributes
37+
*/
38+
function readBlockConfig(block) {
39+
const config = {};
40+
[...block.querySelectorAll(':scope > div > div')].forEach((cell) => {
41+
const key = cell.textContent?.trim().toLowerCase().replace(/\s+/g, '-');
42+
const value = cell.nextElementSibling?.textContent?.trim();
43+
if (key && value) {
44+
config[key] = value;
45+
}
46+
});
47+
return config;
48+
}
9849

99-
// Click handler
100-
header.addEventListener('click', () => {
101-
toggleAccordion(header, content, children);
102-
});
50+
/**
51+
* Map row/cell index to field name
52+
*/
53+
function getFieldName(rowIndex, cellIndex) {
54+
const fieldMap = {
55+
'0-0': 'items'
56+
};
57+
return fieldMap[`${rowIndex}-${cellIndex}`];
58+
}
10359

104-
// Keyboard handler
105-
header.addEventListener('keydown', (e) => {
106-
handleKeydown(e, header, content, children, headers);
107-
});
60+
/**
61+
* Process images in a cell
62+
*/
63+
function processImages(cell) {
64+
const images = cell.querySelectorAll('img');
65+
images.forEach((img) => {
66+
// Add lazy loading
67+
img.loading = 'lazy';
68+
69+
// Wrap in picture element if not already
70+
if (img.parentElement.tagName !== 'PICTURE') {
71+
const picture = document.createElement('picture');
72+
img.parentElement.insertBefore(picture, img);
73+
picture.appendChild(img);
74+
}
75+
});
76+
}
10877

109-
// Open first panel by default
110-
if (i === 0) {
111-
header.classList.add('active');
112-
header.setAttribute('aria-expanded', 'true');
113-
content.classList.add('active');
114-
}
78+
/**
79+
* Process links in a cell
80+
*/
81+
function processLinks(cell) {
82+
const links = cell.querySelectorAll('a');
83+
links.forEach((link) => {
84+
// Add target blank for external links
85+
if (link.hostname !== window.location.hostname) {
86+
link.target = '_blank';
87+
link.rel = 'noopener noreferrer';
11588
}
116-
}
89+
});
90+
}
91+
92+
/**
93+
* Initialize block functionality
94+
*/
95+
function initializeBlock(block, config) {
96+
// Add loaded class for CSS transitions
97+
block.classList.add('loaded');
98+
99+
// Dispatch custom event for extensibility
100+
block.dispatchEvent(new CustomEvent('block:loaded', {
101+
detail: { config },
102+
bubbles: true,
103+
}));
117104
}

blocks/accordion/accordion.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"id": "accordion",
3+
"fields": [
4+
{
5+
"component": "container",
6+
"name": "items",
7+
"label": "Accordion Items"
8+
}
9+
]
10+
}

0 commit comments

Comments
 (0)