Skip to content

Commit

Permalink
feat: support css.-webkit-scrollbar (close #19)
Browse files Browse the repository at this point in the history
  • Loading branch information
qq15725 committed Apr 14, 2023
1 parent 9a2e6d6 commit 0a3bfe3
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 72 deletions.
4 changes: 2 additions & 2 deletions src/clone-node.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { copyPseudoContent } from './copy-pseudo-content'
import { copyPseudoClass } from './copy-pseudo-class'
import { copyInputValue } from './copy-input-value'
import { copyCssStyles } from './copy-css-styles'
import {
Expand Down Expand Up @@ -103,7 +103,7 @@ export async function cloneNode<T extends Node>(
.map(val => val.toLowerCase())
.forEach(val => fontFamilies.add(val))

copyPseudoContent(node, clone, ownerWindow)
copyPseudoClass(node, clone, context)

copyInputValue(node, clone)

Expand Down
15 changes: 3 additions & 12 deletions src/copy-css-styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { getDefaultStyle } from './get-default-style'
import { IN_CHROME } from './utils'
import type { Context } from './context'

const ignored = [
const ignoredStyle = [
'transitionProperty',
'all', // svg: all
'd', // svg: d
Expand All @@ -17,20 +17,15 @@ export function copyCssStyles<T extends HTMLElement | SVGElement>(
context: Context,
) {
const cloneStyle = clone.style
const defaultStyle = getDefaultStyle(node.tagName, context)
const defaultStyle = getDefaultStyle(node.tagName, null, context)

cloneStyle.transitionProperty = 'none'

for (let i = style.length - 1; i >= 0; i--) {
const name = style.item(i)

if (ignored.includes(name)) {
continue
}

if (ignoredStyle.includes(name)) continue
const value = style.getPropertyValue(name)
const priority = style.getPropertyPriority(name)

// Clean "margin" of root node
if (
isRoot
Expand All @@ -40,12 +35,10 @@ export function copyCssStyles<T extends HTMLElement | SVGElement>(
cloneStyle.setProperty(name, '0', priority)
continue
}

// fix background-clip: text
if (name === 'background-clip' && value === 'text') {
clone.classList.add('______background-clip--text')
}

// Skip default style
if (
defaultStyle[name] === value
Expand All @@ -54,9 +47,7 @@ export function copyCssStyles<T extends HTMLElement | SVGElement>(
) {
continue
}

cloneStyle.setProperty(name, value, priority)

// fix border width
if (name.startsWith('border') && name.endsWith('style')) {
const widthName = name.replace('style', 'width')
Expand Down
65 changes: 65 additions & 0 deletions src/copy-pseudo-class.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { getDefaultStyle } from './get-default-style'
import { uuid } from './utils'
import type { Context } from './context'

const ignoredStyles = [
'content',
'-webkit-locale',
]

const pseudoClasses = [
':before',
':after',
':-webkit-scrollbar',
':-webkit-scrollbar-button',
// ':-webkit-scrollbar:horizontal', TODO
':-webkit-scrollbar-thumb',
':-webkit-scrollbar-track',
':-webkit-scrollbar-track-piece',
// ':-webkit-scrollbar:vertical', TODO
':-webkit-scrollbar-corner',
':-webkit-resizer',
]

export function copyPseudoClass<T extends HTMLElement | SVGElement>(
node: T,
cloned: T,
context: Context,
) {
const { ownerDocument, ownerWindow, svgStyleElement } = context

if (!svgStyleElement || !ownerDocument || !ownerWindow) return

pseudoClasses.forEach(pseudoClass => {
const style = ownerWindow.getComputedStyle(node, pseudoClass)
const content = style.getPropertyValue('content')
if (!content || content === 'none') return
const klasses = [uuid()]
const defaultStyle = getDefaultStyle(node.tagName, pseudoClass, context)
const cloneStyle = [
`content: '${ content.replace(/'|"/g, '') }';`,
]
for (let i = style.length - 1; i >= 0; i--) {
const name = style.item(i)
if (ignoredStyles.includes(name)) continue
const value = style.getPropertyValue(name)
const priority = style.getPropertyPriority(name)
// fix background-clip: text
if (name === 'background-clip' && value === 'text') {
klasses.push(' ______background-clip--text')
}
// Skip default style
if (defaultStyle[name] === value && !priority) continue
cloneStyle.push(`${ name }: ${ value }${ priority ? ' !important' : '' };`)
}
if (cloneStyle.length === 1) return
try {
(cloned as any).className += ` ${ klasses.join(' ') }`
} catch (err) {
return
}
svgStyleElement.appendChild(
ownerDocument.createTextNode(`.${ klasses[0] }:${ pseudoClass } {\n ${ cloneStyle.join('\n ') }\n}\n`),
)
})
}
54 changes: 0 additions & 54 deletions src/copy-pseudo-content.ts

This file was deleted.

9 changes: 5 additions & 4 deletions src/get-default-style.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { uuid } from './utils'
import type { Context } from './context'

export function getDefaultStyle(tagName: string, context: Context) {
export function getDefaultStyle(tagName: string, pseudoElement: string | null, context: Context) {
const { defaultComputedStyles, ownerDocument } = context
if (defaultComputedStyles.has(tagName)) return defaultComputedStyles.get(tagName)!
const key = `${ tagName }${ pseudoElement ?? '' }`
if (defaultComputedStyles.has(key)) return defaultComputedStyles.get(key)!
let sandbox = context.sandbox
if (!sandbox) {
if (ownerDocument) {
Expand All @@ -26,7 +27,7 @@ export function getDefaultStyle(tagName: string, context: Context) {
sandboxDocument.body.appendChild(el)
// Ensure that there is some content, so properties like margin are applied
el.textContent = ' '
const style = sandboxWindow.getComputedStyle(el)
const style = sandboxWindow.getComputedStyle(el, pseudoElement)
const styles: Record<string, any> = {}
for (let i = style.length - 1; i >= 0; i--) {
const name = style.item(i)
Expand All @@ -37,6 +38,6 @@ export function getDefaultStyle(tagName: string, context: Context) {
}
}
sandboxDocument.body.removeChild(el)
defaultComputedStyles.set(tagName, styles)
defaultComputedStyles.set(key, styles)
return styles
}
30 changes: 30 additions & 0 deletions test/fixtures/css.-webkit-scrollbar.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<style>
.scrollbar {
display: block;
width: 10em;
overflow: auto;
height: 2em;
}

/* Demonstrate a "mostly customized" scrollbar
* (won't be visible otherwise if width/height is specified) */
.scrollbar::-webkit-scrollbar {
width: 5px;
height: 8px;
background-color: #aaa; /* or add it to the track */
}

/* Add a thumb */
.scrollbar::-webkit-scrollbar-thumb {
background: #000;
}
</style>

<template>
<div id="root" class="scrollbar">
Thisisaveeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeerylongword<br />
And pretty tall<br />
thing with weird scrollbars.<br />
Who thought scrollbars could be made weird?
</div>
</template>
Binary file added test/fixtures/css.-webkit-scrollbar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

1 comment on commit 0a3bfe3

@vercel
Copy link

@vercel vercel bot commented on 0a3bfe3 Apr 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

modern-screenshot – ./

modern-screenshot-qq15725.vercel.app
modern-screenshot.vercel.app
modern-screenshot-git-main-qq15725.vercel.app

Please sign in to comment.