@cssints/data 0.0.0-stage → 0.33.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alexei Accio
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,175 @@
1
- # Temporary Holding Version
1
+ # @cssints/data
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Statistics over runtime values, computed by the browser's layout for [cssints](../../README.md): `max`, `sum` and
4
+ `count` of a list, the [dCSS](https://noscript.ing/compute) idea as one call member of `cssints/plugin` `scope()`. It
5
+ prints a small global rig and no class; there is no runtime. The browser lays the values out as widths, reads the
6
+ resulting width back as a number with a container query, and prints it with a counter.
7
+
8
+ ```ts
9
+ import { data } from "@cssints/data" with { type: "cssints" };
10
+
11
+ // at a module's top level, once: the rig, and no class
12
+ data();
13
+ ```
14
+
15
+ ```css
16
+ @layer _.k {
17
+ [data-data] {
18
+ display: inline-grid;
19
+ grid-template-columns: auto;
20
+ width: max-content;
21
+ overflow: clip;
22
+ }
23
+ [data-data] > ul {
24
+ margin: 0;
25
+ padding: 0;
26
+ list-style: none;
27
+ height: 0;
28
+ }
29
+ [data-data="max"] > ul {
30
+ display: grid;
31
+ }
32
+ [data-data="max"] > ul > li {
33
+ width: calc(var(--value) * 1px);
34
+ height: 0;
35
+ }
36
+ [data-data="sum"] > ul {
37
+ display: flex;
38
+ width: max-content;
39
+ }
40
+ [data-data="sum"] > ul > li {
41
+ flex: none;
42
+ width: calc(var(--value) * 1px);
43
+ height: 0;
44
+ }
45
+ [data-data="count"] > ul {
46
+ display: flex;
47
+ width: max-content;
48
+ }
49
+ [data-data="count"] > ul > li {
50
+ width: 1px;
51
+ height: 0;
52
+ }
53
+ [data-read] {
54
+ display: block;
55
+ container-type: inline-size;
56
+ }
57
+ [data-read] > * {
58
+ --data-result: round(100cqw / 1px);
59
+ }
60
+ [data-data="max"] [data-read] output::after,
61
+ [data-data="sum"] [data-read] output::after,
62
+ [data-data="count"] [data-read] output::after {
63
+ counter-reset: out var(--data-result);
64
+ content: counter(out);
65
+ }
66
+ }
67
+ ```
68
+
69
+ ## The DOM contract
70
+
71
+ ```html
72
+ <figure data-data="max">
73
+ <ul aria-hidden="true">
74
+ <li style="--value: 12"></li>
75
+ <li style="--value: 40"></li>
76
+ <li style="--value: 30"></li>
77
+ </ul>
78
+ <b data-read><output></output></b>
79
+ </figure>
80
+ ```
81
+
82
+ - **The figure** picks the statistic with `data-data`: `max`, `sum` or `count`. Any other value matches no statistic
83
+ rule and prints nothing.
84
+ - **The measuring list** is a ruler, not content: it is `aria-hidden` and has no height. Each `<li>` carries `--value`,
85
+ a unitless number of pixels. Nothing reads the list's text; the rig reads its widths.
86
+ - **The reader** is a `<b data-read>` (any element): a block that fills the figure's single auto column and is a
87
+ `container-type: inline-size` size container. Its children get `--data-result`, the reader's width in pixels as a
88
+ number; its `<output>` prints that number with a counter. Put the output inside the reader: CSS cannot hand a number
89
+ to a sibling.
90
+
91
+ ## A worked example
92
+
93
+ `max` of 12, 40 and 30:
94
+
95
+ - the list is a grid of one implicit column, so its width is its widest item;
96
+ - each `<li>` is `calc(var(--value) * 1px)` wide and `0` tall: 12px, 40px, 30px, so the column is **40px**;
97
+ - the reader is a block in that column, so it is 40px wide; `round(100cqw / 1px)` is `40`;
98
+ - `counter-reset: out var(--data-result)` sets the counter to 40, and `content: counter(out)` paints `40`.
99
+
100
+ `sum` makes the list a hug-width flex row instead, so the row is `12 + 40 + 30 = 82px` and the counter prints `82`.
101
+ `count` is a row of `1px` items, so its width is the number of items: `3`.
102
+
103
+ ## What layout computes
104
+
105
+ | `data-data` | The layout that is the answer | A list of 12, 40, 30 |
106
+ | ----------- | -------------------------------------- | -------------------- |
107
+ | `max` | the widest item (one auto grid column) | `40` |
108
+ | `sum` | the total (a hug-width flex row) | `82` |
109
+ | `count` | the number of items (a row of 1px) | `3` |
110
+
111
+ The reader's inline size is its width in the figure's column. Because it is `container-type: inline-size` (size
112
+ containment on the inline axis), its own contents cannot widen it: it is sized by the measuring list, not by the printed
113
+ answer. `round(100cqw / 1px)` divides the container width by a pixel, so the result is the width as a unitless number,
114
+ rounded to an integer.
115
+
116
+ ## The rules
117
+
118
+ - **One member, no arguments.** `data()` is called at a module's top level; it prints no class and no import.
119
+ - **Once per sheet.** Each rule is a global identified by its text: `data()` in two modules, or twice in one, prints the
120
+ rig once.
121
+ - **The three names.** The statistic rules match only `max`, `sum` and `count`; the counter rule only applies inside
122
+ those figures. An unknown `data-data` gets the base figure and the measuring list, and prints nothing.
123
+ - **In `_.k`.** The rules are global rules, in the engine's kernel layer, like `global()`. A class layer beats them; do
124
+ not style the rig's own elements.
125
+
126
+ ## Accessibility
127
+
128
+ The measuring list is `aria-hidden="true"`: it is a ruler, not content, and a reader should not hear three empty items.
129
+ The printed answer is **generated content** (`output::after`): no screen reader reads it as text, find-in-page does not
130
+ find it, and it is not copied. Do not make it the only place the number exists. Put the number in a `<figcaption>`, as
131
+ [dCSS](https://noscript.ing/compute) does, so the figure has a name and a value a reader and a search can reach:
132
+
133
+ ```html
134
+ <figure data-data="max">
135
+ <ul aria-hidden="true">
136
+ <li style="--value: 12"></li>
137
+ <li style="--value: 40"></li>
138
+ <li style="--value: 30"></li>
139
+ </ul>
140
+ <b data-read><output></output></b>
141
+ <figcaption>Busiest hour: 40 requests</figcaption>
142
+ </figure>
143
+ ```
144
+
145
+ The caption is text; keep it in step with the same values. When the host can render both (server-side or at the same
146
+ moment it writes `--value`), write the number there too.
147
+
148
+ ## Limits
149
+
150
+ - **Needs container query units and `round()`.** `cqw` is Chrome 105, Firefox 110 and Safari 16; `round()` is Chrome
151
+ 125, Firefox 118 and Safari 15.4. A browser without them prints nothing or an empty answer.
152
+ - **The answer only reaches the reader's subtree.** `--data-result` is a custom property on the reader's children; CSS
153
+ cannot hand a number to a sibling or to the figure. A `<figcaption>` outside the reader cannot read it. To show the
154
+ number elsewhere, put another reader there or use a script.
155
+ - **Pixels.** `--value` is a unitless, non-negative number that the rig multiplies by `1px`; widths cannot be negative
156
+ (a max of negatives is `0`), and the printed answer is a whole pixel because `round()` rounds it.
157
+ - **`count` counts `<li>` elements**, whether or not they carry `--value`. `max` and `sum` read `--value` only.
158
+ - **No median, average or sort.** This is the three primitives: a maximum, a sum and a count. The article's sorting,
159
+ `anchor()` and `sibling-index()` are not here.
160
+ - **The rig is global.** Its selectors target `[data-data]` and `[data-read]`, which a page may use for its own
161
+ content; do not repurpose those attributes. One figure per statistic.
162
+
163
+ ```bash
164
+ cd packages/data && bun run test # the sheet through the engine: the rig once for two calls, no class, the rules
165
+ cd packages/data && bun run test:browsers # Chromium through playwright-core: 40, 82 and 3, then a changed value
166
+ cd packages/data && bun run typecheck
167
+ cd packages/data && bun run build
168
+ ```
169
+
170
+ ## Credits
171
+
172
+ The idea and the DOM contract are [Computing with CSS Layout](https://noscript.ing/compute) by Agustin Capeletto and
173
+ [dCSS](https://github.com/noscripting/dCSS): an auto grid column is a maximum, a hug-width flex row is a sum, a row of
174
+ 1px items is a count, and a container query read back through `round(100cqw / 1px)` is the number, printed by a counter.
175
+ The rules are written here, as globals of `scope()`; no code is copied.
@@ -0,0 +1,14 @@
1
+ declare const dataScope: import("cssints/plugin").Scope<"data", {
2
+ readonly data: {
3
+ readonly args: readonly [];
4
+ };
5
+ }>;
6
+ type Members = ReturnType<typeof dataScope.export>;
7
+ /**
8
+ * `data()`: prints the rig that computes `max`, `sum` or `count` of the `--value`s of a `<li>` list by layout and prints
9
+ * the answer with a counter. The figure picks the statistic with `data-data`; the answer reaches what lives inside
10
+ * `[data-read]` (CSS cannot hand a number to a sibling). No arguments, no class; call it at a module's top level. See
11
+ * the README for the DOM contract and the accessibility note.
12
+ */
13
+ export declare const data: Members["data"];
14
+ export {};
package/dist/index.mjs ADDED
@@ -0,0 +1,17 @@
1
+ import { scope } from "cssints/plugin";
2
+ // src/index.ts
3
+ const RULES = [
4
+ "[data-data] { display: inline-grid; grid-template-columns: auto; width: max-content; overflow: clip } [data-data] > ul { margin: 0; padding: 0; list-style: none; height: 0 }",
5
+ "[data-data=\"max\"] > ul { display: grid } [data-data=\"max\"] > ul > li { width: calc(var(--value) * 1px); height: 0 }",
6
+ "[data-data=\"sum\"] > ul { display: flex; width: max-content } [data-data=\"sum\"] > ul > li { flex: none; width: calc(var(--value) * 1px); height: 0 }",
7
+ "[data-data=\"count\"] > ul { display: flex; width: max-content } [data-data=\"count\"] > ul > li { width: 1px; height: 0 }",
8
+ "[data-read] { display: block; container-type: inline-size } [data-read] > * { --data-result: round(100cqw / 1px) } [data-data=\"max\"] [data-read] output::after, [data-data=\"sum\"] [data-read] output::after, [data-data=\"count\"] [data-read] output::after { counter-reset: out var(--data-result); content: counter(out) }"
9
+ ];
10
+ /**
11
+ * `data()`: prints the rig that computes `max`, `sum` or `count` of the `--value`s of a `<li>` list by layout and prints
12
+ * the answer with a counter. The figure picks the statistic with `data-data`; the answer reaches what lives inside
13
+ * `[data-read]` (CSS cannot hand a number to a sibling). No arguments, no class; call it at a module's top level. See
14
+ * the README for the DOM contract and the accessibility note.
15
+ */
16
+ const data = scope("data", { data: { args: [] } }).build({ data: () => ({ globals: RULES.map((css) => ({ css })) }) }).export().data;
17
+ export { data };
package/package.json CHANGED
@@ -1,6 +1,32 @@
1
1
  {
2
2
  "name": "@cssints/data",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.33.0",
4
+ "description": "Statistics over runtime values, computed by the browser's layout for cssints: max, sum and count, printed by a counter",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/alexeiaccio/css-in-ts-compiler.git",
9
+ "directory": "packages/data"
10
+ },
11
+ "homepage": "https://cssints.dev",
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "type": "module",
16
+ "sideEffects": false,
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.mts",
20
+ "default": "./dist/index.mjs"
21
+ }
22
+ },
23
+ "peerDependencies": {
24
+ "cssints": "^0.33.0"
25
+ },
26
+ "engines": {
27
+ "node": ">=22"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ }
32
+ }