Skip to content

Commit

Permalink
feat(element): highly reworked Swiper web component
Browse files Browse the repository at this point in the history
- navigation arrows use SVGs instead of font
- changed shadow DOM layout to have `<div class="swiper">` inside
- component styles now added using adoptedStylesheets
- no more global styles injection
  • Loading branch information
nolimits4web committed Jun 22, 2023
1 parent e9e8039 commit a6f8a0f
Show file tree
Hide file tree
Showing 29 changed files with 385 additions and 292 deletions.
127 changes: 76 additions & 51 deletions scripts/build-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,48 +18,85 @@ import config from './build-config.js';

const __dirname = url.fileURLToPath(new URL('.', import.meta.url));

const getSplittedCSS = (content) => {
const cssStylesSlideCore = content.split(`/* 3D Shadows */`)[1].split(`/* CSS Mode */`)[0];
const cssStylesSlideCube = (content.split(`/* Cube slide shadows start */`)[1] || '').split(
`/* Cube slide shadows end */`,
)[0];
const cssStylesSlideFlip = (content.split(`/* Flip slide shadows start */`)[1] || '').split(
`/* Flip slide shadows end */`,
)[0];
const navigationFontStyles = (content.split('/* Navigation font start */')[1] || '').split(
'/* Navigation font end */',
)[0];
content = content
.replace(cssStylesSlideCore, '')
.replace(cssStylesSlideCube, '')
.replace(cssStylesSlideFlip, '')
.replace(navigationFontStyles, '')
.split('/* FONT_END */')[1];

return {
slides: [cssStylesSlideCore || '', cssStylesSlideCube || '', cssStylesSlideFlip || ''].join(
'\n',
),
container: content,
};
};
const proceedReplacements = (content) => {
// add :host
// eslint-disable-next-line
const replace = ['invisible-blank', 'visible', 'zoomed', 'active', 'next', 'prev'];

content = content
.replace(/:root/g, ':host')
.split('\n')
.map((line) => {
const lineSplitted = line.replace('{', '').replace(',', '').trim().split(' ');
if (
(lineSplitted.length > 1 &&
lineSplitted.filter((part) => part.includes('.swiper-wrapper')).length > 0 &&
!line.includes('.swiper-wrapper > .swiper-slide')) ||
line.includes(
`.swiper-rtl .swiper-pagination-progressbar .swiper-pagination-progressbar-fill`,
)
) {
const newRule = [...lineSplitted];
return line.replace(newRule[0], `:host(${newRule[0]})`);
if (line.includes('> .swiper-wrapper > .swiper-slide')) {
return line.replace('> .swiper-wrapper > .swiper-slide', '::slotted(swiper-slide)');
}
let replaced = '';
if (line.includes('.swiper-slide ')) {
replaced = line.replaceAll(/\.swiper-slide /g, '::slotted(swiper-slide) ');
}
if (line.includes('.swiper-slide,')) {
replaced = line.replaceAll(/\.swiper-slide,/g, '::slotted(swiper-slide),');
}
if (line.includes('.swiper-slide:')) {
replaced = line.replaceAll(/\.swiper-slide:/g, '::slotted(swiper-slide):');
}
replace.forEach((key) => {
const l = replaced || line;
if (l.includes(`.swiper-slide-${key}`)) {
replaced = l.replaceAll(`.swiper-slide-${key}`, `::slotted(.swiper-slide-${key})`);
}
});
if (replaced) {
return replaced;
}

return line;
})
.join('\n');
// add replacement for RTL
content = content.replace(/.swiper-rtl .swiper-button/g, ':host(.swiper-rtl) .swiper-button');
// add/replace .swiper-slide to swiper-slide
return content;
};
const proceedSlideReplacements = (content) => {
content = content
.split('\n')
.map((line) => {
if (line.includes('> .swiper-wrapper > .swiper-slide')) {
return line.replace('> .swiper-wrapper > .swiper-slide', '> swiper-slide');
if (line.includes('.swiper-3d .swiper-slide-shadow')) {
return line.replace('.swiper-3d ', '::slotted(').replace(',', '),').replace(' {', ') {');
}
if (
line.includes('.swiper-slide ') ||
line.includes('.swiper-slide,') ||
line.includes('.swiper-slide:')
) {
return line.replace(/\.swiper-slide/g, 'swiper-slide');
if (line.includes('.swiper-cube .swiper-slide-shadow')) {
return line.replace('.swiper-cube ', '::slotted(').replace(',', '),').replace(' {', ') {');
}
if (line.includes('.swiper-flip .swiper-slide-shadow')) {
return line.replace('.swiper-flip ', '::slotted(').replace(',', '),').replace(' {', ') {');
}
return line;
})
.join('\n');
return content;
};

export default async function buildElement() {
// eslint-disable-next-line
const modules = config.modules.filter((name) => {
Expand Down Expand Up @@ -88,15 +125,18 @@ export default async function buildElement() {
let cssStylesCore = await autoprefixer(
await less(lessContentCore, path.resolve(__dirname, '../src')),
);
// eslint-disable-next-line
let cssStylesSlide = getSplittedCSS(cssStylesBundle).slides;
cssStylesBundle = getSplittedCSS(cssStylesBundle).container;
cssStylesCore = getSplittedCSS(cssStylesCore).container;

cssStylesBundle = proceedReplacements(cssStylesBundle);
cssStylesCore = proceedReplacements(cssStylesCore);
cssStylesSlide = proceedSlideReplacements(cssStylesSlide);

const cssStylesBundleStandalone = cssStylesBundle;
const cssStylesCoreStandalone = cssStylesCore;

const fontStyles = await cleanCss(cssStylesCore.split('/* FONT_END */')[0]);
cssStylesBundle = await cleanCss(cssStylesBundle.split('/* FONT_END */')[1]);
cssStylesCore = await cleanCss(cssStylesCore.split('/* FONT_END */')[1]);
cssStylesBundle = await cleanCss(cssStylesBundle);
cssStylesCore = await cleanCss(cssStylesCore);
cssStylesSlide = await cleanCss(cssStylesSlide);

if (!fs.existsSync(path.resolve(outputDir, 'element'))) {
fs.mkdirSync(path.resolve(outputDir, 'element'));
Expand All @@ -123,37 +163,21 @@ export default async function buildElement() {
}),
);

// standalone styles
fs.writeFileSync(path.resolve(outputDir, 'swiper-element.css'), cssStylesCoreStandalone);
fs.writeFileSync(
path.resolve(outputDir, 'swiper-element.min.css'),
await cleanCss(cssStylesCoreStandalone),
);
fs.writeFileSync(path.resolve(outputDir, 'swiper-element-bundle.css'), cssStylesBundleStandalone);
fs.writeFileSync(
path.resolve(outputDir, 'swiper-element-bundle.min.css'),
await cleanCss(cssStylesBundleStandalone),
);

// ESM
fs.copyFileSync('./src/element/get-params.js', path.resolve(outputDir, 'element/get-params.js'));
const elementContent = fs.readFileSync('./src/element/swiper-element.js', 'utf-8');

const esmBundleContent = elementContent
.replace(
'//SWIPER_STYLES',
`const SwiperFontCSS = \`${fontStyles}\`; const SwiperCSS = \`${cssStylesBundle}\`;`,
)
.replace('//SWIPER_STYLES', `const SwiperCSS = \`${cssStylesBundle}\`;`)
.replace('//SWIPER_SLIDE_STYLES', `const SwiperSlideCSS = \`${cssStylesSlide}\`;`)
.replace('//IMPORT_SWIPER', `import Swiper from 'swiper/bundle';`)
.replace('//EXPORT', `export { SwiperContainer, SwiperSlide, register };`);

fs.writeFileSync(path.resolve(outputDir, 'element/swiper-element-bundle.js'), esmBundleContent);

const esmContent = elementContent
.replace(
'//SWIPER_STYLES',
`const SwiperFontCSS = \`${fontStyles}\`; const SwiperCSS = \`${cssStylesCore}\`;`,
)
.replace('//SWIPER_STYLES', `const SwiperCSS = \`${cssStylesCore}\`;`)
.replace('//SWIPER_SLIDE_STYLES', `const SwiperSlideCSS = \`${cssStylesSlide}\`;`)
.replace('//IMPORT_SWIPER', `import Swiper from 'swiper';`)
.replace('//EXPORT', `export { SwiperContainer, SwiperSlide, register };`);
fs.writeFileSync(path.resolve(outputDir, 'element/swiper-element.js'), esmContent);
Expand All @@ -166,7 +190,8 @@ export default async function buildElement() {
plugins: [
replace({
delimiters: ['', ''],
'//SWIPER_STYLES': `const SwiperFontCSS = \`${fontStyles}\`; const SwiperCSS = \`${cssStylesBundle}\`;`,
'//SWIPER_STYLES': `const SwiperCSS = \`${cssStylesBundle}\`;`,
'//SWIPER_SLIDE_STYLES': `const SwiperSlideCSS = \`${cssStylesSlide}\`;`,
[`import Swiper from 'swiper/bundle';`]: `import Swiper from '../swiper-bundle.esm.js';`,
[`import Swiper from 'swiper';`]: `import Swiper from '../swiper.esm.js';`,
'//BROWSER_REGISTER': `register()`,
Expand Down
10 changes: 6 additions & 4 deletions src/components-shared/update-swiper.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ function updateSwiper({
if (swiper.isElement && (!paginationEl || typeof paginationEl === 'string')) {
paginationEl = document.createElement('div');
paginationEl.classList.add('swiper-pagination');
swiper.el.shadowEl.appendChild(paginationEl);
swiper.el.appendChild(paginationEl);
}
if (paginationEl) currentParams.pagination.el = paginationEl;
pagination.init();
Expand All @@ -174,7 +174,7 @@ function updateSwiper({
if (swiper.isElement && (!scrollbarEl || typeof scrollbarEl === 'string')) {
scrollbarEl = document.createElement('div');
scrollbarEl.classList.add('swiper-scrollbar');
swiper.el.shadowEl.appendChild(scrollbarEl);
swiper.el.appendChild(scrollbarEl);
}
if (scrollbarEl) currentParams.scrollbar.el = scrollbarEl;
scrollbar.init();
Expand All @@ -187,12 +187,14 @@ function updateSwiper({
if (!nextEl || typeof nextEl === 'string') {
nextEl = document.createElement('div');
nextEl.classList.add('swiper-button-next');
swiper.el.shadowEl.appendChild(nextEl);
nextEl.innerHTML = swiper.hostEl.nextButtonSvg;
swiper.el.appendChild(nextEl);
}
if (!prevEl || typeof prevEl === 'string') {
prevEl = document.createElement('div');
prevEl.classList.add('swiper-button-prev');
swiper.el.shadowEl.appendChild(prevEl);
nextEl.innerHTML = swiper.hostEl.prevButtonSvg;
swiper.el.appendChild(prevEl);
}
}
if (nextEl) currentParams.navigation.nextEl = nextEl;
Expand Down
5 changes: 3 additions & 2 deletions src/core/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ class Swiper {
}

el.swiper = swiper;
if (el.shadowEl) {
if (el.parentNode && el.parentNode.host) {
swiper.isElement = true;
}

Expand Down Expand Up @@ -514,7 +514,8 @@ class Swiper {
Object.assign(swiper, {
el,
wrapperEl,
slidesEl: swiper.isElement ? el : wrapperEl,
slidesEl: swiper.isElement ? el.parentNode.host : wrapperEl,
hostEl: swiper.isElement ? el.parentNode.host : el,
mounted: true,

// RTL
Expand Down
Loading

0 comments on commit a6f8a0f

Please sign in to comment.