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 CHANGED
@@ -1,240 +1,174 @@
1
- # CSS Typed OM Polyfill
1
+ # Moonlight CSS Typed OM Polyfill
2
2
 
3
- A JavaScript polyfill for the [CSS Typed Object Model (OM) Level 1](https://www.w3.org/TR/css-typed-om/) specification. This polyfill aims to provide a functional subset of the CSS Typed OM API for browsers that do not natively support it, allowing developers to interact with CSS values as typed JavaScript objects.
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
- - [Features](#features)
9
- - [Supported CSS Typed OM Interfaces](#supported-css-typed-om-interfaces)
12
+ - [Core Evolutions](#core-evolutions)
13
+ - [Supported Interfaces](#supported-interfaces)
10
14
  - [Installation](#installation)
11
15
  - [Basic Usage](#basic-usage)
12
- - [Advanced Usage & Notes](#advanced-usage--notes)
13
- - [Parsing CSS Values](#parsing-css-values)
14
- - [`calc()` and Math Functions](#calc-and-math-functions)
15
- - [Arithmetic Operations](#arithmetic-operations)
16
- - [`var()` (CSS Variables)](#var-css-variables)
17
- - [Limitations & To-Do](#limitations--to-do)
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 provides a way to manipulate CSS values in JavaScript with type awareness, rather than just dealing with strings. This can lead to more robust and performant code. This polyfill brings some of that power to environments lacking native support.
24
-
25
- It focuses on parsing CSS strings into typed objects, performing arithmetic on numeric values, and providing the `element.attributeStyleMap` interface for getting and setting styles in a typed manner.
26
-
27
- ## Features
28
-
29
- * **`HTMLElement.prototype.attributeStyleMap`:** Access and modify inline styles using a `StylePropertyMap`.
30
- * **CSS Value Parsing:**
31
- * `CSSStyleValue.parse(property, cssText)`: Parses a single CSS value string.
32
- * `CSSStyleValue.parseAll(property, cssText)`: Parses a comma-separated list of CSS values.
33
- * **Numeric Values:**
34
- * `CSSNumericValue` (base class for numbers and units).
35
- * `CSSUnitValue` (e.g., `10px`, `50%`, `3.14rad`).
36
- * `CSS.*` factory functions (e.g., `CSS.px(10)`, `CSS.percent(50)`, `CSS.number(5)`).
37
- * Arithmetic operations: `.add()`, `.sub()`, `.mul()`, `.div()`, `.negate()`, `.invert()`.
38
- * Unit conversion: `.to('targetUnit')` for compatible types (e.g., `s` to `ms`).
39
- * Type checking for math operations (e.g., `length + angle` is invalid).
40
- * **Mathematical Expressions:**
41
- * `CSSMathSum`, `CSSMathProduct`, `CSSMathNegate`, `CSSMathInvert`.
42
- * `CSSMathMin`, `CSSMathMax`.
43
- * Recursive parsing of `calc()`, `min()`, `max()` expressions, including nested functions and `var()`.
44
- * **Other CSS Values:**
45
- * `CSSKeywordValue` (e.g., `auto`, `inherit`, `initial`).
46
- * `CSSVariableReferenceValue` (for `var(--custom-property)`).
47
- * `CSSUnparsedValue` (for values not fully parsed or unsupported).
48
- * **Stubbed/Partial Implementations:**
49
- * `CSSImageValue` (basic stub, returns `url(...)` as string).
50
- * `CSSPositionValue` (basic stub).
51
- * `CSSTransformValue` and its components (`CSSTranslate`, `CSSRotate`, `CSSScale`) (basic stubs with constructors and `toString()`).
52
-
53
- ## Supported CSS Typed OM Interfaces
54
-
55
- **Core Classes:**
56
- * `CSSStyleValue` (Abstract Base)
57
- * `CSSNumericValue` (Abstract Base for numeric types)
58
- * `CSSUnitValue`
59
- * `CSSKeywordValue`
60
- * `CSSUnparsedValue`
61
- * `CSSVariableReferenceValue`
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 HTML file before any scripts that use the CSS Typed OM API:
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="css-typed-om-polyfill.js"></script>
71
+ <script src="cssom.js"></script>
90
72
  <script>
91
- // Your code using Typed OM
92
- const el = document.getElementById('myElement');
93
- if (el && el.attributeStyleMap) {
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
- ### Accessing `attributeStyleMap`
81
+ ### Manipulating `attributeStyleMap`
105
82
 
106
83
  ```javascript
107
- const element = document.createElement('div');
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
- ### Using `CSS.*` Factory Functions
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
- ```javascript
128
- const length = CSS.px(100);
129
- const percentage = CSS.percent(50);
130
- const duration = CSS.s(2.5);
131
- const angle = CSS.deg(90);
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
- console.log(length.add(CSS.vw(10)).toString()); // "calc(100px + 10vw)"
97
+ // Type Checking
98
+ console.log(width instanceof CSSUnitValue); // true
135
99
  ```
136
100
 
137
- ## Advanced Usage & Notes
138
-
139
- ### Parsing CSS Values
101
+ ### Using Factory Functions
140
102
 
141
103
  ```javascript
142
- // Parse a single value
143
- const parsedWidth = CSSStyleValue.parse('width', 'calc(100% - 20px)');
144
- console.log(parsedWidth.toString()); // "calc(100% - 20px)"
145
- if (parsedWidth instanceof CSSMathSum) {
146
- console.log(parsedWidth.operator); // "sum"
147
- console.log(parsedWidth.values[0].toString()); // "100%"
148
- console.log(parsedWidth.values[1].toString()); // "calc(-1 * 20px)" (negated second term)
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
- ### `calc()` and Math Functions
114
+ ## Advanced Usage
163
115
 
164
- The polyfill includes a robust parser for `calc()`, `min()`, and `max()` expressions, respecting operator precedence and parentheses.
116
+ ### Algebraic Logic & Optimization
117
+
118
+ Moonlight doesn't just store expressions; it optimizes them like a compiler.
165
119
 
166
120
  ```javascript
167
- const complexCalc = CSSStyleValue.parse('width', 'calc( (var(--A) + 2 * ( 5vw - var(--B) )) / 3 )');
168
- console.log(complexCalc.toString()); // "calc((var(--A) + 2 * (5vw - var(--B))) / 3)"
169
- // The internal structure will be a tree of CSSMathProduct, CSSMathSum, etc.
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
- ### Arithmetic Operations
132
+ ### Transforms & Matrix
173
133
 
174
- `CSSNumericValue` and its subclasses support arithmetic. Operations involving different compatible units or `var()` will result in `CSSMathSum` or `CSSMathProduct` objects.
134
+ Supports the full Transform Object Model and matrix computation.
175
135
 
176
136
  ```javascript
177
- const val1 = CSS.px(10);
178
- const val2 = CSS.em(2);
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
- // Multiplication
190
- console.log(val1.mul(num).toString()); // "50px" (length * number = length)
191
- console.log(val1.mul(CSS.percent(200)).toString()); // "calc(10px * 200%)" (length * percent)
140
+ // Access like an array
141
+ console.log(transform[0] instanceof CSSTranslate); // true
142
+ console.log(transform[1] instanceof CSSRotate); // true
192
143
 
193
- // Division
194
- console.log(val1.div(num).toString()); // "2px"
195
- console.log(val1.div(CSS.px(2)).toString()); // "5" (length / length = number)
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
- const calcWithVar = CSS.px(10).add(myVar);
208
- console.log(calcWithVar.toString()); // "calc(10px + var(--my-width, 100px))"
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
- ## Limitations & To-Do
154
+ ## Performance Philosophy
212
155
 
213
- This polyfill is a work in progress and does not cover the entire CSS Typed OM specification. Key limitations include:
156
+ Moonlight is built upon the **"Velocity"** philosophy:
214
157
 
215
- * **`clamp()`:** Not currently supported in the math expression parser (will parse as `CSSUnparsedValue` if top-level, or throw error if inside `calc`).
216
- * **Color Values:** Complex color functions (e.g., `rgb()`, `hsl()`, `color()`) are generally parsed as `CSSUnparsedValue`. Basic named colors might parse as `CSSKeywordValue`.
217
- * **Detailed Transform Parsing:** While `CSSTransformValue` and component classes (`CSSTranslate`, `CSSRotate`, `CSSScale`) exist with constructors, the main `CSSStyleValue.parse` will return `CSSUnparsedValue` for transform function strings. You'd need to construct them manually.
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
- **Future Enhancements (To-Do):**
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
- ## Development
164
+ ## Limitations
233
165
 
234
- The code is contained within a single IIFE (Immediately Invoked Function Expression). The core parsing logic for math expressions is in `parseCssMathExpression`. `CSSStyleValue.parse` is the main entry point for parsing CSS text.
166
+ While Moonlight is powerful, it is physically limited by the lack of context from the browser's layout engine:
235
167
 
236
- The script includes example usage code wrapped in a `setTimeout` at the end, which can be used for testing in a browser environment.
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.