css-typed-om-polyfill 0.1.0 → 1.0.0
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 +119 -185
- package/README.zh.md +115 -182
- package/cssom.js +1732 -0
- package/package.json +3 -3
- package/css-typed-om-polyfill.js +0 -1369
package/README.md
CHANGED
|
@@ -1,240 +1,174 @@
|
|
|
1
|
-
# CSS Typed OM Polyfill
|
|
1
|
+
# Moonlight CSS Typed OM Polyfill
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Moonlight** is a high-performance, high-precision JavaScript polyfill for the [CSS Typed Object Model (OM) Level 1](https://www.w3.org/TR/css-typed-om/) specification.
|
|
4
|
+
|
|
5
|
+
Unlike generic shims, Moonlight aims to provide a native-like (and in specific scenarios, faster-than-native) experience in environments lacking native support, driven by its **Velocity Engine** and **Algebraic Soul**.
|
|
6
|
+
|
|
7
|
+
It is not just a tool; it is a symbiosis of logic and speed.
|
|
4
8
|
|
|
5
9
|
## Table of Contents
|
|
6
10
|
|
|
7
11
|
- [Introduction](#introduction)
|
|
8
|
-
- [
|
|
9
|
-
- [Supported
|
|
12
|
+
- [Core Evolutions](#core-evolutions)
|
|
13
|
+
- [Supported Interfaces](#supported-interfaces)
|
|
10
14
|
- [Installation](#installation)
|
|
11
15
|
- [Basic Usage](#basic-usage)
|
|
12
|
-
- [Advanced Usage
|
|
13
|
-
- [Parsing
|
|
14
|
-
- [
|
|
15
|
-
- [
|
|
16
|
-
|
|
17
|
-
- [Limitations
|
|
18
|
-
- [Development](#development)
|
|
16
|
+
- [Advanced Usage](#advanced-usage)
|
|
17
|
+
- [Parsing & Strict Mode](#parsing--strict-mode)
|
|
18
|
+
- [Algebraic Logic & Optimization](#algebraic-logic--optimization)
|
|
19
|
+
- [Transforms & Matrix](#transforms--matrix)
|
|
20
|
+
- [Performance Philosophy](#performance-philosophy)
|
|
21
|
+
- [Limitations](#limitations)
|
|
19
22
|
- [License](#license)
|
|
20
23
|
|
|
21
24
|
## Introduction
|
|
22
25
|
|
|
23
|
-
The CSS Typed Object Model
|
|
24
|
-
|
|
25
|
-
It focuses on
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
* **
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
*
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
* `
|
|
57
|
-
* `
|
|
58
|
-
* `
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
* `
|
|
62
|
-
|
|
63
|
-
**Math Classes (subclass `CSSNumericValue`):**
|
|
64
|
-
* `CSSMathValue` (Abstract Base)
|
|
65
|
-
* `CSSMathSum`
|
|
66
|
-
* `CSSMathProduct`
|
|
67
|
-
* `CSSMathNegate`
|
|
68
|
-
* `CSSMathInvert`
|
|
69
|
-
* `CSSMathMin`
|
|
70
|
-
* `CSSMathMax`
|
|
71
|
-
|
|
72
|
-
**Other (Stubbed/Partial):**
|
|
73
|
-
* `CSSImageValue`
|
|
74
|
-
* `CSSPositionValue`
|
|
75
|
-
* `CSSTransformValue`
|
|
76
|
-
* `CSSTransformComponent` (Abstract Base)
|
|
77
|
-
* `CSSTranslate`
|
|
78
|
-
* `CSSRotate`
|
|
79
|
-
* `CSSScale`
|
|
80
|
-
|
|
81
|
-
**Interfaces:**
|
|
82
|
-
* `StylePropertyMap` (via `element.attributeStyleMap`)
|
|
26
|
+
The CSS Typed Object Model allows developers to manipulate CSS values as typed JavaScript objects rather than fragile strings. Moonlight brings this capability to all modern browsers.
|
|
27
|
+
|
|
28
|
+
It focuses on:
|
|
29
|
+
1. **Type Safety**: Strictly distinguishes between `number`, `length`, `angle`, etc., rejecting illegal calculations.
|
|
30
|
+
2. **Algebraic Simplification**: Automatically applies distributive laws and constant folding to reduce complex `calc()` trees to their optimal form.
|
|
31
|
+
3. **Zero-Allocation Parsing**: Uses an optimized lexer to minimize Garbage Collection (GC) pressure.
|
|
32
|
+
|
|
33
|
+
## Core Evolutions
|
|
34
|
+
|
|
35
|
+
* **Velocity Engine**: Removed `Proxy` wrappers in favor of array-like structures for Transform lists; implemented a "Hot Path" for 2-argument `calc()` operations to bypass generic allocation overhead.
|
|
36
|
+
* **Algebraic Soul**: Implements the distributive law (`(A + B) * k = Ak + Bk`) and smart invert folding.
|
|
37
|
+
* **Strict Typing**: Strictly adheres to the spec, forbidding operations like `number + length` (e.g., `calc(0 + 10px)`), providing precise error feedback.
|
|
38
|
+
* **Full Transforms**: Complete support for CSS Transform Module Level 2, including `skew`, `perspective`, and `toMatrix()` computation.
|
|
39
|
+
|
|
40
|
+
## Supported Interfaces
|
|
41
|
+
|
|
42
|
+
Moonlight implements the core mathematical and transform interfaces of the specification:
|
|
43
|
+
|
|
44
|
+
**Primitives:**
|
|
45
|
+
* `CSSStyleValue` (Entry point for parsing)
|
|
46
|
+
* `CSSNumericValue` (Base class for all numeric values)
|
|
47
|
+
* `CSSUnitValue` (e.g., `10px`, `50%`)
|
|
48
|
+
* `CSSKeywordValue` (e.g., `auto`)
|
|
49
|
+
* `CSSUnparsedValue` (Fallback type)
|
|
50
|
+
|
|
51
|
+
**Math Expressions:**
|
|
52
|
+
* `CSSMathSum`, `CSSMathProduct`
|
|
53
|
+
* `CSSMathNegate`, `CSSMathInvert`
|
|
54
|
+
* `CSSMathMin`, `CSSMathMax`, `CSSMathClamp`
|
|
55
|
+
|
|
56
|
+
**Transforms & Matrix:**
|
|
57
|
+
* `CSSTransformValue` (Array-like object, iterable)
|
|
58
|
+
* `CSSTranslate`, `CSSRotate`, `CSSScale`
|
|
59
|
+
* `CSSSkew`, `CSSSkewX`, `CSSSkewY`
|
|
60
|
+
* `CSSPerspective`
|
|
61
|
+
* Supports `.toMatrix()` returning a `DOMMatrix`
|
|
62
|
+
|
|
63
|
+
**DOM Extension:**
|
|
64
|
+
* `HTMLElement.prototype.attributeStyleMap`
|
|
83
65
|
|
|
84
66
|
## Installation
|
|
85
67
|
|
|
86
|
-
Simply include the polyfill script in your
|
|
68
|
+
Simply include the polyfill script in your project. It automatically detects native support and activates only when necessary.
|
|
87
69
|
|
|
88
70
|
```html
|
|
89
|
-
<script src="
|
|
71
|
+
<script src="cssom.js"></script>
|
|
90
72
|
<script>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
el.attributeStyleMap.set('width', CSS.px(100));
|
|
95
|
-
console.log(el.attributeStyleMap.get('width').toString()); // "100px"
|
|
96
|
-
}
|
|
73
|
+
const el = document.querySelector('#box');
|
|
74
|
+
// If the browser lacks native Typed OM support, Moonlight takes over attributeStyleMap
|
|
75
|
+
el.attributeStyleMap.set('opacity', 0.5);
|
|
97
76
|
</script>
|
|
98
77
|
```
|
|
99
78
|
|
|
100
|
-
The polyfill will automatically initialize and attach necessary properties to the global scope (`window`) and `HTMLElement.prototype`.
|
|
101
|
-
|
|
102
79
|
## Basic Usage
|
|
103
80
|
|
|
104
|
-
###
|
|
81
|
+
### Manipulating `attributeStyleMap`
|
|
105
82
|
|
|
106
83
|
```javascript
|
|
107
|
-
const
|
|
108
|
-
document.body.appendChild(element);
|
|
109
|
-
|
|
110
|
-
// Set a style
|
|
111
|
-
element.attributeStyleMap.set('width', CSS.px(200));
|
|
112
|
-
element.attributeStyleMap.set('opacity', CSS.number(0.5));
|
|
113
|
-
element.attributeStyleMap.set('margin-top', CSS.em(1.5));
|
|
114
|
-
|
|
115
|
-
// Get a style
|
|
116
|
-
const width = element.attributeStyleMap.get('width'); // CSSUnitValue { value: 200, unit: "px" }
|
|
117
|
-
console.log(width.value); // 200
|
|
118
|
-
console.log(width.unit); // "px"
|
|
119
|
-
console.log(width.toString()); // "200px"
|
|
120
|
-
|
|
121
|
-
const opacity = element.attributeStyleMap.get('opacity'); // CSSNumericValue { _value: 0.5, _unitType: "number" }
|
|
122
|
-
console.log(opacity.toString()); // "0.5"
|
|
123
|
-
```
|
|
84
|
+
const el = document.getElementById('hero');
|
|
124
85
|
|
|
125
|
-
|
|
86
|
+
// Setting styles (Auto-boxing)
|
|
87
|
+
el.attributeStyleMap.set('font-size', CSS.rem(1.5));
|
|
88
|
+
el.attributeStyleMap.set('width', CSS.px(100));
|
|
89
|
+
el.attributeStyleMap.set('opacity', CSS.number(0.8));
|
|
126
90
|
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const number = CSS.number(10);
|
|
91
|
+
// Getting styles
|
|
92
|
+
const width = el.attributeStyleMap.get('width');
|
|
93
|
+
console.log(width.value); // 100
|
|
94
|
+
console.log(width.unit); // "px"
|
|
95
|
+
console.log(width.toString()); // "100px"
|
|
133
96
|
|
|
134
|
-
|
|
97
|
+
// Type Checking
|
|
98
|
+
console.log(width instanceof CSSUnitValue); // true
|
|
135
99
|
```
|
|
136
100
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
### Parsing CSS Values
|
|
101
|
+
### Using Factory Functions
|
|
140
102
|
|
|
141
103
|
```javascript
|
|
142
|
-
//
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const keyword = CSSStyleValue.parse('display', 'block');
|
|
152
|
-
console.log(keyword.value); // "block"
|
|
153
|
-
|
|
154
|
-
// Parse a list of values (e.g., for font-family)
|
|
155
|
-
const fontFamilies = CSSStyleValue.parseAll('font-family', '"Arial", sans-serif');
|
|
156
|
-
fontFamilies.forEach(font => console.log(font.toString()));
|
|
157
|
-
// Output:
|
|
158
|
-
// "Arial" (CSSUnparsedValue for the string)
|
|
159
|
-
// "sans-serif" (CSSKeywordValue)
|
|
104
|
+
// Create values with different units
|
|
105
|
+
const angle = CSS.deg(45);
|
|
106
|
+
const time = CSS.s(1.5);
|
|
107
|
+
const percent = CSS.percent(100);
|
|
108
|
+
|
|
109
|
+
// Chained Calculations
|
|
110
|
+
const result = CSS.px(10).add(CSS.px(20)).mul(2);
|
|
111
|
+
console.log(result.toString()); // "60px" (Auto-simplified)
|
|
160
112
|
```
|
|
161
113
|
|
|
162
|
-
|
|
114
|
+
## Advanced Usage
|
|
163
115
|
|
|
164
|
-
|
|
116
|
+
### Algebraic Logic & Optimization
|
|
117
|
+
|
|
118
|
+
Moonlight doesn't just store expressions; it optimizes them like a compiler.
|
|
165
119
|
|
|
166
120
|
```javascript
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
//
|
|
121
|
+
// 1. Constant Folding
|
|
122
|
+
const a = CSS.px(10).mul(2);
|
|
123
|
+
console.log(a.toString()); // "20px" (Instead of calc(10px * 2))
|
|
124
|
+
|
|
125
|
+
// 2. Distributive Law Application
|
|
126
|
+
// (100% - 20px) / 2 => 50% - 10px
|
|
127
|
+
const b = CSS.percent(100).sub(CSS.px(20)).div(2);
|
|
128
|
+
console.log(b.toString()); // "calc(50% + -10px)"
|
|
129
|
+
// This optimization is crucial to prevent deeply nested calc() trees.
|
|
170
130
|
```
|
|
171
131
|
|
|
172
|
-
###
|
|
132
|
+
### Transforms & Matrix
|
|
173
133
|
|
|
174
|
-
|
|
134
|
+
Supports the full Transform Object Model and matrix computation.
|
|
175
135
|
|
|
176
136
|
```javascript
|
|
177
|
-
|
|
178
|
-
const
|
|
179
|
-
const val3 = CSS.percent(50);
|
|
180
|
-
const num = CSS.number(5);
|
|
181
|
-
|
|
182
|
-
// Addition
|
|
183
|
-
console.log(val1.add(val2).toString()); // "calc(10px + 2em)"
|
|
184
|
-
console.log(val1.add(CSS.px(5)).toString()); // "15px" (same unit)
|
|
185
|
-
|
|
186
|
-
// Subtraction
|
|
187
|
-
console.log(val3.sub(CSS.px(10)).toString()); // "calc(50% - 10px)"
|
|
137
|
+
// Parse a transform string
|
|
138
|
+
const transform = CSSStyleValue.parse('transform', 'translate(10px, 50%) rotate(45deg)');
|
|
188
139
|
|
|
189
|
-
//
|
|
190
|
-
console.log(
|
|
191
|
-
console.log(
|
|
140
|
+
// Access like an array
|
|
141
|
+
console.log(transform[0] instanceof CSSTranslate); // true
|
|
142
|
+
console.log(transform[1] instanceof CSSRotate); // true
|
|
192
143
|
|
|
193
|
-
//
|
|
194
|
-
|
|
195
|
-
console.log(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
### `var()` (CSS Variables)
|
|
199
|
-
|
|
200
|
-
`var()` expressions are parsed into `CSSVariableReferenceValue` objects. They can be used within math functions and arithmetic operations, remaining unresolved.
|
|
201
|
-
|
|
202
|
-
```javascript
|
|
203
|
-
const myVar = CSSStyleValue.parse('width', 'var(--my-width, 100px)');
|
|
204
|
-
console.log(myVar.variable); // "--my-width"
|
|
205
|
-
console.log(myVar.fallback.toString()); // "100px"
|
|
144
|
+
// Iteration
|
|
145
|
+
for (const component of transform) {
|
|
146
|
+
console.log(component.toString());
|
|
147
|
+
}
|
|
206
148
|
|
|
207
|
-
|
|
208
|
-
|
|
149
|
+
// Compute Matrix (Requires DOMMatrix support in browser)
|
|
150
|
+
const matrix = transform.toMatrix();
|
|
151
|
+
console.log(matrix.m11, matrix.m12, ...);
|
|
209
152
|
```
|
|
210
153
|
|
|
211
|
-
##
|
|
154
|
+
## Performance Philosophy
|
|
212
155
|
|
|
213
|
-
|
|
156
|
+
Moonlight is built upon the **"Velocity"** philosophy:
|
|
214
157
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
* **`CSSNumericValue.equals()`:** Provides a simplified structural check, primarily via `toString()` comparison, which may not be robust for all mathematically equivalent but structurally different expressions.
|
|
219
|
-
* **Type System Nuances:** The `type()` method on math values attempts to determine the resulting type (e.g., `length`, `angle`, `percent`), but complex interactions, especially with `var()`, can lead to indeterminate types.
|
|
220
|
-
* **No Actual Value Computation:** The polyfill parses and represents CSS values and expressions. It does **not** compute the final used value of expressions (e.g., it won't resolve `calc(10px + 5%)` to a single pixel value, as that requires layout context).
|
|
221
|
-
* **Shorthand Properties:** `StylePropertyMap.get()` might return `null` or an unparsed value for shorthands if the browser doesn't expand them into longhands in `element.style`. The polyfill relies on what `element.style.getPropertyValue()` returns.
|
|
222
|
-
* **Limited Property-Specific Parsing:** `CSSStyleValue.parse(property, cssText)` does not currently use the `property` argument to guide parsing specific to that property's grammar (beyond basic distinctions).
|
|
158
|
+
1. **Hot Path Optimization**: Dedicated fast paths for the most common binary operations (e.g., `width: calc(100% - 20px)`), bypassing generic array allocations.
|
|
159
|
+
2. **Singleton Cache**: Uses singletons or fast-creation patterns for common values like `0px`, `1`, `0` to reduce GC pressure.
|
|
160
|
+
3. **V8 Friendly**: Removed features that are hard for JS engines to optimize (like `Proxy` on hot paths), ensuring the code structure remains JIT-friendly.
|
|
223
161
|
|
|
224
|
-
|
|
225
|
-
* Implement `clamp()`.
|
|
226
|
-
* Improve parsing for color values.
|
|
227
|
-
* Full parsing of transform functions into `CSSTransformValue`.
|
|
228
|
-
* More robust `CSSNumericValue.equals()`.
|
|
229
|
-
* Support for more `CSSStyleValue` subclasses (e.g., `CSSSkew`, `CSSPerspective`, `CSSMatrixComponent`).
|
|
230
|
-
* Consider `CSSMathClamp`.
|
|
162
|
+
In micro-benchmarks, Moonlight performs comparably to native implementations in pure algebraic computation scenarios.
|
|
231
163
|
|
|
232
|
-
##
|
|
164
|
+
## Limitations
|
|
233
165
|
|
|
234
|
-
|
|
166
|
+
While Moonlight is powerful, it is physically limited by the lack of context from the browser's layout engine:
|
|
235
167
|
|
|
236
|
-
|
|
168
|
+
* **Relative Unit Resolution**: Cannot resolve `em`, `rem`, `vw`, or `%` to absolute pixels (`px`) because this depends on the DOM tree and layout calculation.
|
|
169
|
+
* **Context Agnostic**: `CSSStyleValue.parse` does not know which element it applies to, so it cannot handle `inherit` or current-font-based calculations.
|
|
170
|
+
* **Colors & Images**: Focuses primarily on numerics, math, and transforms. Complex `color()` or `image-set()` values may fall back to `CSSUnparsedValue`.
|
|
237
171
|
|
|
238
172
|
## License
|
|
239
173
|
|
|
240
|
-
[MIT](LICENSE)
|
|
174
|
+
[MIT](LICENSE) - Dedicated to all developers who strive for perfection.
|