@cssints/mise-en-mode 0.0.0-stage → 0.2.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,81 @@
1
- # Temporary Holding Version
1
+ # @cssints/mise-en-mode
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
+ The look layer of Mise en Mode for [cssints](../../README.md): a **look** is a theme set on a `data-mode` scope, and looks
4
+ from three sources are resolved by the Mode Contract. It is one call member of `cssints/plugin` `scope()` (positional
5
+ arguments `$tokens` and `$overrides`, returning themes), so a look is checked against your token set, and `check.contrast` sees it.
6
+ No runtime.
7
+
8
+ ```ts
9
+ import { createTokens } from "cssints" with { type: "cssints" };
10
+ import { look } from "@cssints/mise-en-mode" with { type: "cssints" };
11
+
12
+ const t = createTokens({
13
+ color: { $type: "color", bg: { $value: "#ffffff" }, fg: { $value: "#111111" } },
14
+ });
15
+
16
+ // look(tokens, expression, source, overrides, { scope? })
17
+ look(t, "dark", "app", { color: { bg: "#0b0b0f", fg: "#f3f4f6" } });
18
+ look(t, "dark", "viewer", { color: { bg: "#101018" } });
19
+ look(t, "hero", "author", { color: { bg: "#123456" } }, { scope: "article.post" });
20
+ ```
21
+
22
+ ```css
23
+ @layer app, author, viewer;
24
+ @layer app {
25
+ :where([data-mode="dark"], [data-mode~="dark/color"]) {
26
+ --color-bg: #0b0b0f;
27
+ --color-fg: #f3f4f6;
28
+ }
29
+ }
30
+ @layer viewer {
31
+ :where([data-mode="dark"], [data-mode~="dark/color"]) {
32
+ --color-bg: #101018;
33
+ }
34
+ }
35
+ @layer author {
36
+ @scope (article.post) {
37
+ :where([data-mode="hero"], [data-mode~="hero/color"]) {
38
+ --color-bg: #123456;
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ ## The contract, as the package does it
45
+
46
+ - **Sources (Rule 5).** `source` is `"app"`, `"author"` or `"viewer"`: the layers `app < author < viewer`, declared once
47
+ after the engine's own (`layers()` of cssints), so a look beats the engine's `:root` fallbacks and a viewer's look beats an
48
+ author's over the app's. Each variable fills from the most preferred source that sets it: the viewer look above sets only
49
+ `--color-bg`, and `--color-fg` still comes from the app look.
50
+ - **Aspects and fragments (Rule 4).** An aspect is a top-level group of the token set (`color`, `typography`). A look's
51
+ `overrides` are split by it, one rule per aspect, and each rule matches the bare marker or its fragment:
52
+ `data-mode="dark"` applies every aspect, `data-mode="dark/color"` only the color group.
53
+ - **Expressions.** `expression` is a `<custom-ident>` or a string; a dotted reverse-DNS key is quoted at the call,
54
+ `look(t, '"com.alice.midnight"', "author", …)`, and matched exactly.
55
+ - **Containment (Rule 7).** `{ scope: "article.post" }` wraps the rule in `@scope (article.post) { … }`, so a foreign look
56
+ cannot repaint the host's chrome. It is a selector, checked by the build.
57
+ - **Overrides** are `createGlobalTheme`'s: values by token path, each of the token's type, `{color.bg}` references allowed,
58
+ checked in the types as you type and again at build time (`color.bg value "blu" is not a <color>`, located at the call).
59
+ The aliases that depend on an overridden token are declared again on the scope.
60
+ - **Contrast.** The looks of one expression and aspect are one cascade to `check.contrast`: they are laid over each other in
61
+ layer order, so a viewer look that sets only the text colour is checked on the _app_ look's background, and a poor
62
+ combination fails the build.
63
+
64
+ A look prints no class: call it at a module's top level, like `createGlobalTheme`. Its types are inferred from the `scope()`
65
+ definition in `src/index.ts`: there is no types file.
66
+
67
+ Changed from `cssints/mise-en-mode`, which this package replaces: `look(expression, source, declarations, { scope })` took
68
+ raw custom-property declarations (`"--color-bg": "#000"`) that nothing checked; it is now `look(tokens, expression, source,
69
+ overrides, { scope })` with the token set first and the overrides by token path, so the declarations are checked, the
70
+ aliases are re-derived and contrast sees them. Aspects are the groups of the tokens, no longer a table of `--color-` and
71
+ `--typography-` prefixes, and a look emits themes, no longer globals.
72
+
73
+ ```bash
74
+ cd packages/mise-en-mode && bun run test # fixtures through the engine (output, errors, contrast), and the type test via bun run typecheck
75
+ ```
76
+
77
+ ## Credits
78
+
79
+ Mise en Mode is an open style standard on AT Protocol (<https://standard.mode.place>), and the Mode Contract is its
80
+ rules: `data-mode` scopes, the layers `app < author < viewer`, aspects. This package is an implementation of the
81
+ contract on `scope()`; no code of the standard's site is copied.
@@ -0,0 +1,23 @@
1
+ //#region src/index.d.ts
2
+ declare const mise: import("cssints/plugin").Scope<"mise-en-mode", {
3
+ readonly "#sources": {
4
+ readonly layers: readonly ["app", "author", "viewer"];
5
+ };
6
+ readonly look: {
7
+ readonly args: readonly ["$tokens", "<custom-ident> | <string>", "app | author | viewer", "$overrides", {
8
+ readonly "scope?": "$selector";
9
+ }];
10
+ readonly uses: readonly ["sources"];
11
+ };
12
+ }>;
13
+ /**
14
+ * `look(tokens, expression, source, overrides, { scope? })`: the theme of one `data-mode` expression, in the layer of its
15
+ * `source` (`"app"`, `"author"` or `"viewer"`), so a viewer's look fills over an author's over the app's, value by value.
16
+ * `overrides` are values by token path, split by their top-level groups (aspects): `data-mode="dark"` takes every aspect,
17
+ * `data-mode="dark/color"` only the color group. They are checked against `tokens` in the types and at build time, and
18
+ * `check.contrast` reads them with the other looks of the expression. With `scope` the look is confined to that subtree
19
+ * (`@scope`, Rule 7). A dotted reverse-DNS expression is quoted: `look(t, '"com.alice.midnight"', "author", { … })`. Call it
20
+ * at a module's top level; it prints no class.
21
+ */
22
+ export declare const look: ReturnType<typeof mise.export>["look"];
23
+ //#endregion
package/dist/index.mjs ADDED
@@ -0,0 +1,37 @@
1
+ import { scope } from "cssints/plugin";
2
+ //#region src/index.ts
3
+ const selector = (expression, aspect) => `:where([data-mode="${expression}"], [data-mode~="${expression}/${aspect}"])`;
4
+ /**
5
+ * `look(tokens, expression, source, overrides, { scope? })`: the theme of one `data-mode` expression, in the layer of its
6
+ * `source` (`"app"`, `"author"` or `"viewer"`), so a viewer's look fills over an author's over the app's, value by value.
7
+ * `overrides` are values by token path, split by their top-level groups (aspects): `data-mode="dark"` takes every aspect,
8
+ * `data-mode="dark/color"` only the color group. They are checked against `tokens` in the types and at build time, and
9
+ * `check.contrast` reads them with the other looks of the expression. With `scope` the look is confined to that subtree
10
+ * (`@scope`, Rule 7). A dotted reverse-DNS expression is quoted: `look(t, '"com.alice.midnight"', "author", { … })`. Call it
11
+ * at a module's top level; it prints no class.
12
+ */
13
+ const look = scope("mise-en-mode", {
14
+ "#sources": { layers: [
15
+ "app",
16
+ "author",
17
+ "viewer"
18
+ ] },
19
+ look: {
20
+ args: [
21
+ "$tokens",
22
+ "<custom-ident> | <string>",
23
+ "app | author | viewer",
24
+ "$overrides",
25
+ { "scope?": "$selector" }
26
+ ],
27
+ uses: ["sources"]
28
+ }
29
+ }).build({ look: (tokens, expression, source, overrides, options) => ({ themes: Object.entries(overrides).map(([aspect, values]) => ({
30
+ tokens,
31
+ overrides: { [aspect]: values },
32
+ selector: selector(expression.replace(/^"|"$/g, ""), aspect),
33
+ layer: source,
34
+ scope: options.scope
35
+ })) }) }).export().look;
36
+ //#endregion
37
+ export { look };
package/package.json CHANGED
@@ -1,6 +1,32 @@
1
1
  {
2
2
  "name": "@cssints/mise-en-mode",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "Mise en Mode for cssints: looks are themes in the layers app < author < viewer, set on data-mode scopes",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/alexeiaccio/css-in-ts-compiler.git",
9
+ "directory": "packages/mise-en-mode"
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.2.0"
25
+ },
26
+ "engines": {
27
+ "node": ">=22"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ }
32
+ }