refactor(dom-css): use CSS acronym in identifiers
This commit is contained in:
parent
107b52d473
commit
c613df838c
|
|
@ -6,7 +6,7 @@ import type { DesignStyleDeclaration } from './types'
|
|||
|
||||
const TRANSPARENT_KEYWORDS = new Set(['transparent', 'rgba(0, 0, 0, 0)', 'rgb(0 0 0 / 0)'])
|
||||
|
||||
export function parseCssNumber(value: string | undefined): number | null {
|
||||
export function parseCSSNumber(value: string | undefined): number | null {
|
||||
if (!value) return null
|
||||
const trimmed = value.trim()
|
||||
if (trimmed.length === 0 || trimmed === 'auto') return null
|
||||
|
|
@ -14,20 +14,20 @@ export function parseCssNumber(value: string | undefined): number | null {
|
|||
return Number.isFinite(parsed) ? parsed : null
|
||||
}
|
||||
|
||||
export function parseCssColor(value: string | undefined): Color | null {
|
||||
export function parseCSSColor(value: string | undefined): Color | null {
|
||||
if (!value) return null
|
||||
const trimmed = value.trim()
|
||||
if (trimmed.length === 0 || TRANSPARENT_KEYWORDS.has(trimmed.toLowerCase())) return null
|
||||
return parseColor(trimmed)
|
||||
}
|
||||
|
||||
export function fillToCss(fill: Fill | undefined): string | undefined {
|
||||
export function fillToCSS(fill: Fill | undefined): string | undefined {
|
||||
if (fill?.type !== 'SOLID' || !fill.visible) return undefined
|
||||
return colorToCSS({ ...fill.color, a: fill.opacity })
|
||||
}
|
||||
|
||||
export function cssColorToFill(value: string | undefined): Fill[] {
|
||||
const color = parseCssColor(value)
|
||||
export function colorToFillFromCSS(value: string | undefined): Fill[] {
|
||||
const color = parseCSSColor(value)
|
||||
if (!color) return []
|
||||
return [{ type: 'SOLID', color, opacity: color.a, visible: true }]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { colorToCSS } from '@open-pencil/core/color'
|
|||
import { BLACK } from '@open-pencil/core/constants'
|
||||
import type { SceneGraph, SceneNode } from '@open-pencil/core/scene-graph'
|
||||
|
||||
import { fillToCss, sceneNodeSizeStyle } from './css-values'
|
||||
import { fillToCSS, sceneNodeSizeStyle } from './css-values'
|
||||
import type { DesignDocument, DesignNode, DesignStyleDeclaration } from './types'
|
||||
|
||||
export interface SceneGraphToDesignOptions {
|
||||
|
|
@ -18,7 +18,7 @@ function nodeChildren(graph: SceneGraph, node: SceneNode): SceneNode[] {
|
|||
|
||||
function styleFromSceneNode(node: SceneNode): DesignStyleDeclaration {
|
||||
const style = sceneNodeSizeStyle(node)
|
||||
const fill = fillToCss(node.fills[0])
|
||||
const fill = fillToCSS(node.fills[0])
|
||||
if (fill) style['background-color'] = fill
|
||||
if (node.opacity < 1) style.opacity = String(node.opacity)
|
||||
if (node.cornerRadius > 0) style['border-radius'] = `${node.cornerRadius}px`
|
||||
|
|
@ -38,7 +38,7 @@ function styleFromSceneNode(node: SceneNode): DesignStyleDeclaration {
|
|||
|
||||
function styleFromTextNode(node: SceneNode): DesignStyleDeclaration {
|
||||
const style = sceneNodeSizeStyle(node)
|
||||
style.color = fillToCss(node.fills[0]) ?? colorToCSS(BLACK)
|
||||
style.color = fillToCSS(node.fills[0]) ?? colorToCSS(BLACK)
|
||||
style['font-family'] = node.fontFamily
|
||||
style['font-size'] = `${node.fontSize}px`
|
||||
style['font-weight'] = String(node.fontWeight)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { parse, type CSSStyleDeclarationLike, type CSSStyleRuleLike } from '@ace
|
|||
|
||||
import type { DesignDocument, DesignElement, DesignNode, DesignStyleDeclaration } from './types'
|
||||
|
||||
interface CssRule {
|
||||
interface HeadlessCSSRule {
|
||||
selectors: string[]
|
||||
style: DesignStyleDeclaration
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ function isStyleRule(rule: unknown): rule is CSSStyleRuleLike {
|
|||
)
|
||||
}
|
||||
|
||||
function parseRules(cssText: string): CssRule[] {
|
||||
function parseRules(cssText: string): HeadlessCSSRule[] {
|
||||
const sheet = parse(cssText)
|
||||
return sheet.cssRules.filter(isStyleRule).map((rule) => ({
|
||||
selectors: rule.selectorText
|
||||
|
|
@ -49,11 +49,11 @@ function matchesSimpleSelector(element: DesignElement, selector: string): boolea
|
|||
return element.tagName.toLowerCase() === selector.toLowerCase()
|
||||
}
|
||||
|
||||
function matchesRule(element: DesignElement, rule: CssRule): boolean {
|
||||
function matchesRule(element: DesignElement, rule: HeadlessCSSRule): boolean {
|
||||
return rule.selectors.some((selector) => matchesSimpleSelector(element, selector))
|
||||
}
|
||||
|
||||
function applyComputedStyles(node: DesignNode, rules: CssRule[]): DesignNode {
|
||||
function applyComputedStyles(node: DesignNode, rules: HeadlessCSSRule[]): DesignNode {
|
||||
if (node.type === 'text') return node
|
||||
|
||||
const computedStyle: DesignStyleDeclaration = {}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
export { serializeHTML, serializeNode } from './serialize'
|
||||
export { createBrowserCssRuntime, createCssRuntime, createHeadlessCssRuntime } from './runtime'
|
||||
export { createBrowserCSSRuntime, createCSSRuntime, createHeadlessCSSRuntime } from './runtime'
|
||||
export { designDocumentToSceneGraph } from './to-scene-graph'
|
||||
export { sceneGraphToDesignDocument } from './from-scene-graph'
|
||||
export type { ToDesignDocumentOptions } from './from-scene-graph'
|
||||
export type { ToSceneGraphOptions } from './to-scene-graph'
|
||||
export type {
|
||||
CssComputeOptions,
|
||||
CssRuntime,
|
||||
CSSComputeOptions,
|
||||
CSSRuntime,
|
||||
DesignDocument,
|
||||
DesignElement,
|
||||
DesignNode,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { serializeHTML } from '../serialize'
|
||||
import type {
|
||||
CssComputeOptions,
|
||||
CssRuntime,
|
||||
CSSComputeOptions,
|
||||
CSSRuntime,
|
||||
DesignDocument,
|
||||
DesignElement,
|
||||
DesignNode
|
||||
|
|
@ -125,7 +125,7 @@ function collectElementPairs(
|
|||
|
||||
function computedStyleToRecord(
|
||||
style: CSSStyleDeclaration,
|
||||
options: CssComputeOptions
|
||||
options: CSSComputeOptions
|
||||
): Record<string, string> {
|
||||
const entries: Record<string, string> = {}
|
||||
const properties = options.includeBrowserDefaults
|
||||
|
|
@ -143,7 +143,7 @@ function computedStyleToRecord(
|
|||
async function computeStyles(
|
||||
designDocument: DesignDocument,
|
||||
cssText = '',
|
||||
options: CssComputeOptions = {}
|
||||
options: CSSComputeOptions = {}
|
||||
): Promise<DesignDocument> {
|
||||
const browserDocument = requireBrowserDocument()
|
||||
const host = browserDocument.createElement('div')
|
||||
|
|
@ -191,7 +191,7 @@ async function computeStyles(
|
|||
}
|
||||
}
|
||||
|
||||
export function createBrowserCssRuntime(): CssRuntime {
|
||||
export function createBrowserCSSRuntime(): CSSRuntime {
|
||||
return {
|
||||
kind: 'browser',
|
||||
parseHTML,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { parseFragment, type DefaultTreeAdapterTypes } from 'parse5'
|
|||
import { computeHeadlessStyles } from '../headless-css'
|
||||
import { serializeHTML } from '../serialize'
|
||||
import { parseStyleAttribute } from '../style-attribute'
|
||||
import type { CssRuntime, DesignDocument, DesignElement, DesignNode } from '../types'
|
||||
import type { CSSRuntime, DesignDocument, DesignElement, DesignNode } from '../types'
|
||||
|
||||
function attrsToRecord(attrs: DefaultTreeAdapterTypes.Element['attrs']): Record<string, string> {
|
||||
const result: Record<string, string> = {}
|
||||
|
|
@ -50,7 +50,7 @@ function parseHTML(html: string): DesignDocument {
|
|||
}
|
||||
}
|
||||
|
||||
export function createHeadlessCssRuntime(): CssRuntime {
|
||||
export function createHeadlessCSSRuntime(): CSSRuntime {
|
||||
return {
|
||||
kind: 'headless',
|
||||
parseHTML,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import type { CssRuntime } from '../types'
|
||||
import { createBrowserCssRuntime } from './browser'
|
||||
import { createHeadlessCssRuntime } from './headless'
|
||||
import type { CSSRuntime } from '../types'
|
||||
import { createBrowserCSSRuntime } from './browser'
|
||||
import { createHeadlessCSSRuntime } from './headless'
|
||||
|
||||
export { createBrowserCssRuntime } from './browser'
|
||||
export { createHeadlessCssRuntime } from './headless'
|
||||
export { createBrowserCSSRuntime } from './browser'
|
||||
export { createHeadlessCSSRuntime } from './headless'
|
||||
|
||||
export function createCssRuntime(): CssRuntime {
|
||||
return typeof document !== 'undefined' ? createBrowserCssRuntime() : createHeadlessCssRuntime()
|
||||
export function createCSSRuntime(): CSSRuntime {
|
||||
return typeof document !== 'undefined' ? createBrowserCSSRuntime() : createHeadlessCSSRuntime()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { SceneGraph, type Fill, type SceneNode } from '@open-pencil/core/scene-graph'
|
||||
|
||||
import { cssColorToFill, mergedStyle, parseCssNumber, pickStyle } from './css-values'
|
||||
import { colorToFillFromCSS, mergedStyle, parseCSSNumber, pickStyle } from './css-values'
|
||||
import type { DesignDocument, DesignElement, DesignNode, DesignStyleDeclaration } from './types'
|
||||
|
||||
export interface DesignDocumentToSceneGraphOptions {
|
||||
|
|
@ -30,21 +30,21 @@ function isTextLikeElement(node: DesignElement): boolean {
|
|||
].includes(node.tagName.toLowerCase())
|
||||
}
|
||||
|
||||
function firstCssNumber(style: DesignStyleDeclaration, ...properties: string[]): number | null {
|
||||
function firstCSSNumber(style: DesignStyleDeclaration, ...properties: string[]): number | null {
|
||||
for (const property of properties) {
|
||||
const parsed = parseCssNumber(pickStyle(style, property))
|
||||
const parsed = parseCSSNumber(pickStyle(style, property))
|
||||
if (parsed !== null) return parsed
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function fillsFromStyle(style: DesignStyleDeclaration, property: string): Fill[] {
|
||||
return cssColorToFill(pickStyle(style, property))
|
||||
return colorToFillFromCSS(pickStyle(style, property))
|
||||
}
|
||||
|
||||
function setNodeBox(node: SceneNode, style: DesignStyleDeclaration): void {
|
||||
const width = firstCssNumber(style, 'width')
|
||||
const height = firstCssNumber(style, 'height')
|
||||
const width = firstCSSNumber(style, 'width')
|
||||
const height = firstCSSNumber(style, 'height')
|
||||
if (width !== null) node.width = width
|
||||
if (height !== null) node.height = height
|
||||
}
|
||||
|
|
@ -55,19 +55,19 @@ function applyElementStyle(node: SceneNode, style: DesignStyleDeclaration): void
|
|||
const fills = fillsFromStyle(style, 'background-color')
|
||||
if (fills.length > 0) node.fills = fills
|
||||
|
||||
const opacity = parseCssNumber(pickStyle(style, 'opacity'))
|
||||
const opacity = parseCSSNumber(pickStyle(style, 'opacity'))
|
||||
if (opacity !== null) node.opacity = opacity
|
||||
|
||||
const cornerRadius = firstCssNumber(style, 'border-radius')
|
||||
const cornerRadius = firstCSSNumber(style, 'border-radius')
|
||||
if (cornerRadius !== null) node.cornerRadius = cornerRadius
|
||||
|
||||
if (pickStyle(style, 'display') === 'flex') {
|
||||
node.layoutMode = pickStyle(style, 'flex-direction') === 'column' ? 'VERTICAL' : 'HORIZONTAL'
|
||||
node.itemSpacing = firstCssNumber(style, 'gap', 'column-gap', 'row-gap') ?? 0
|
||||
node.paddingTop = firstCssNumber(style, 'padding-top', 'padding') ?? 0
|
||||
node.paddingRight = firstCssNumber(style, 'padding-right', 'padding') ?? 0
|
||||
node.paddingBottom = firstCssNumber(style, 'padding-bottom', 'padding') ?? 0
|
||||
node.paddingLeft = firstCssNumber(style, 'padding-left', 'padding') ?? 0
|
||||
node.itemSpacing = firstCSSNumber(style, 'gap', 'column-gap', 'row-gap') ?? 0
|
||||
node.paddingTop = firstCSSNumber(style, 'padding-top', 'padding') ?? 0
|
||||
node.paddingRight = firstCSSNumber(style, 'padding-right', 'padding') ?? 0
|
||||
node.paddingBottom = firstCSSNumber(style, 'padding-bottom', 'padding') ?? 0
|
||||
node.paddingLeft = firstCSSNumber(style, 'padding-left', 'padding') ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,16 +77,16 @@ function applyTextStyle(node: SceneNode, style: DesignStyleDeclaration): void {
|
|||
const fills = fillsFromStyle(style, 'color')
|
||||
if (fills.length > 0) node.fills = fills
|
||||
|
||||
const fontSize = parseCssNumber(pickStyle(style, 'font-size'))
|
||||
const fontSize = parseCSSNumber(pickStyle(style, 'font-size'))
|
||||
if (fontSize !== null) node.fontSize = fontSize
|
||||
|
||||
const fontWeight = parseCssNumber(pickStyle(style, 'font-weight'))
|
||||
const fontWeight = parseCSSNumber(pickStyle(style, 'font-weight'))
|
||||
if (fontWeight !== null) node.fontWeight = fontWeight
|
||||
|
||||
const lineHeight = parseCssNumber(pickStyle(style, 'line-height'))
|
||||
const lineHeight = parseCSSNumber(pickStyle(style, 'line-height'))
|
||||
if (lineHeight !== null) node.lineHeight = lineHeight
|
||||
|
||||
const letterSpacing = parseCssNumber(pickStyle(style, 'letter-spacing'))
|
||||
const letterSpacing = parseCSSNumber(pickStyle(style, 'letter-spacing'))
|
||||
if (letterSpacing !== null) node.letterSpacing = letterSpacing
|
||||
|
||||
const fontFamily = pickStyle(style, 'font-family')
|
||||
|
|
|
|||
|
|
@ -33,17 +33,17 @@ export interface DesignStyleSheet {
|
|||
|
||||
export type DesignStyleDeclaration = Record<string, string>
|
||||
|
||||
export interface CssComputeOptions {
|
||||
export interface CSSComputeOptions {
|
||||
includeBrowserDefaults?: boolean
|
||||
}
|
||||
|
||||
export interface CssRuntime {
|
||||
export interface CSSRuntime {
|
||||
readonly kind: 'browser' | 'headless'
|
||||
parseHTML(html: string): DesignDocument
|
||||
serializeHTML(document: DesignDocument): string
|
||||
computeStyles(
|
||||
document: DesignDocument,
|
||||
cssText?: string,
|
||||
options?: CssComputeOptions
|
||||
options?: CSSComputeOptions
|
||||
): Promise<DesignDocument>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { describe, expect, it } from 'bun:test'
|
||||
|
||||
import {
|
||||
createCssRuntime,
|
||||
createHeadlessCssRuntime,
|
||||
createCSSRuntime,
|
||||
createHeadlessCSSRuntime,
|
||||
serializeHTML,
|
||||
type DesignDocument
|
||||
} from '@open-pencil/dom-css'
|
||||
|
|
@ -27,7 +27,7 @@ describe('@open-pencil/dom-css', () => {
|
|||
})
|
||||
|
||||
it('uses the headless runtime outside browser contexts', () => {
|
||||
const runtime = createCssRuntime()
|
||||
const runtime = createCSSRuntime()
|
||||
|
||||
expect(runtime.kind).toBe('headless')
|
||||
expect(runtime.serializeHTML(documentFixture)).toBe(
|
||||
|
|
@ -36,7 +36,7 @@ describe('@open-pencil/dom-css', () => {
|
|||
})
|
||||
|
||||
it('parses HTML with the headless runtime', () => {
|
||||
const runtime = createHeadlessCssRuntime()
|
||||
const runtime = createHeadlessCSSRuntime()
|
||||
const document = runtime.parseHTML(
|
||||
'<section class="card" style="width: 320px; color: rgb(17, 24, 39)">OpenPencil</section>'
|
||||
)
|
||||
|
|
@ -52,7 +52,7 @@ describe('@open-pencil/dom-css', () => {
|
|||
})
|
||||
|
||||
it('computes simple headless styles from CSSOM rules', async () => {
|
||||
const runtime = createHeadlessCssRuntime()
|
||||
const runtime = createHeadlessCSSRuntime()
|
||||
const document = await runtime.computeStyles(
|
||||
documentFixture,
|
||||
'.card { width: 320px; color: rgb(17, 24, 39); } #missing { color: red; }'
|
||||
|
|
|
|||
Loading…
Reference in a new issue