@textmode/design-system 0.3.4

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 ADDED
@@ -0,0 +1,102 @@
1
+ # @textmode/design-system
2
+
3
+ Shared, React-free visual foundations for textmode.art products. This package is a
4
+ deep CSS module: callers learn four stable stylesheet entry points while palette,
5
+ typography, accessibility, and small reusable primitives stay local to one
6
+ implementation. Product layout, content, motion choreography, and canvas
7
+ lifecycle remain app-owned.
8
+
9
+ ```css
10
+ @import '@textmode/design-system/styles.css';
11
+ ```
12
+
13
+ Applications self-host Monogram Extended and must declare an `@font-face` named
14
+ `Monogram Extended`. The package never references font assets. Crimson
15
+ (`--tm-signal`) is reserved for live/active state, meaningful emphasis, and
16
+ errors; it is never a decorative wash.
17
+
18
+ ## Public CSS entry points
19
+
20
+ - `styles.css` — deterministic aggregate entry point: tokens, foundations, then primitives
21
+ - `tokens.css` — primitive and semantic custom properties
22
+ - `foundations.css` — reset, focus, selection, forced-colors, reduced motion
23
+ - `primitives.css` — commands, ruled panels, ledger rows, and status signals
24
+
25
+ Import `styles.css` once per document. Lower-level entry points are only for
26
+ deliberate composition; applications must not import package-internal files or
27
+ recreate aggregate ordering. The package deliberately does not opt pages into
28
+ scroll snapping, prescribe a layout, or provide React modules. Those behaviors
29
+ remain product-owned so dense workspaces are unaffected.
30
+
31
+ ## Token inventory
32
+
33
+ ### Primitive palette
34
+
35
+ `--tm-color-black`, `--tm-color-black-raised`, `--tm-color-black-elevated`,
36
+ `--tm-color-white`, `--tm-color-white-muted`, `--tm-color-gray`,
37
+ `--tm-color-gray-dark`, `--tm-color-line`, `--tm-color-line-muted`,
38
+ `--tm-color-crimson`, `--tm-color-crimson-readable`, `--tm-color-danger`.
39
+
40
+ ### Semantic roles
41
+
42
+ `--tm-ink`, `--tm-surface`, `--tm-surface-raised`, `--tm-paper`,
43
+ `--tm-paper-muted`, `--tm-text-muted`, `--tm-rule`, `--tm-rule-muted`,
44
+ `--tm-signal`, `--tm-signal-text`, `--tm-error`, `--tm-focus`.
45
+
46
+ ### Typography
47
+
48
+ `--tm-font-display`, `--tm-font-interface`, `--tm-font-copy`,
49
+ `--tm-font-code`, `--tm-type-meta`, `--tm-type-control`, `--tm-type-copy`,
50
+ `--tm-type-copy-large`, `--tm-type-title`, `--tm-leading-tight`,
51
+ `--tm-leading-copy`, `--tm-tracking-display`.
52
+
53
+ ### Geometry and layout
54
+
55
+ `--tm-space-1`, `--tm-space-2`, `--tm-space-3`, `--tm-space-4`,
56
+ `--tm-space-5`, `--tm-space-6`, `--tm-space-7`, `--tm-space-8`,
57
+ `--tm-page-pad`, `--tm-header-height`, `--tm-control-height`,
58
+ `--tm-section-height`, `--tm-section-rail-width`, `--tm-section-pager-height`,
59
+ `--tm-rule-width`, `--tm-touch-target`.
60
+
61
+ ### Motion and stacking
62
+
63
+ `--tm-duration-fast`, `--tm-duration-state`, `--tm-duration-section`,
64
+ `--tm-ease-out`, `--tm-z-dropdown`, `--tm-z-sticky`, `--tm-z-rail`,
65
+ `--tm-z-modal-backdrop`, `--tm-z-modal`, `--tm-z-toast`, `--tm-z-tooltip`.
66
+
67
+ Section-based brand surfaces may consume `--tm-section-rail-width`,
68
+ `--tm-section-pager-height`, and `--tm-duration-section`, but navigation and
69
+ responsive behavior remain local to their product.
70
+
71
+ ## Primitive inventory
72
+
73
+ - `.tm-command` and `.tm-command--signal` — 44 px command links or buttons with
74
+ inverse and signal states.
75
+ - `.tm-rule-panel` — product-neutral ruled surface.
76
+ - `.tm-ledger-row` — tabular metadata row.
77
+ - `.tm-status-signal` — live or active state marker.
78
+ - `.tm-sr-only` — visually hidden accessible text.
79
+
80
+ The foundation contract includes `:focus-visible`, disabled and
81
+ `[aria-disabled='true']` states, selection, reduced-motion behavior, and
82
+ forced-colors treatment for `aria-current` and `aria-pressed` state.
83
+
84
+ ## Consumer migration
85
+
86
+ 1. Import `@textmode/design-system/styles.css` before product-owned stylesheet
87
+ imports.
88
+ 2. Keep product-local aliases while moving rules to `--tm-*` tokens; do not
89
+ rename markup classes or change selector ordering as part of token adoption.
90
+ 3. Remove aliases only after every consumer style has moved, visual baselines
91
+ pass unchanged, and no supported integration reads the alias.
92
+ 4. To roll back, remove the aggregate import and restore the prior local token
93
+ declarations in one change. Do not update visual baselines to accept an
94
+ unintended difference.
95
+
96
+ The package has no JavaScript runtime or peer dependencies. Publish releases with
97
+ semantic versioning: patch for value corrections, minor for additive tokens or
98
+ classes, and major for removals or semantic changes. Version 0.3.4 adds
99
+ `--tm-font-copy`, `--tm-section-height`, and package contract verification
100
+ without changing the existing public token values; it also keeps reduced-motion
101
+ rules limited to scroll and transition behavior so product-owned animation state
102
+ remains overrideable.
@@ -0,0 +1,93 @@
1
+ @layer textmode-foundations {
2
+ *,
3
+ *::before,
4
+ *::after {
5
+ box-sizing: border-box;
6
+ }
7
+
8
+ html {
9
+ background: var(--tm-ink);
10
+ color-scheme: dark;
11
+ font-synthesis: none;
12
+ -moz-osx-font-smoothing: grayscale;
13
+ -webkit-font-smoothing: none;
14
+ }
15
+
16
+ body {
17
+ background: var(--tm-ink);
18
+ color: var(--tm-paper);
19
+ font-family: var(--tm-font-interface);
20
+ text-rendering: geometricPrecision;
21
+ }
22
+
23
+ button,
24
+ input,
25
+ select,
26
+ textarea {
27
+ font: inherit;
28
+ }
29
+
30
+ button,
31
+ input,
32
+ select,
33
+ summary,
34
+ a {
35
+ touch-action: manipulation;
36
+ -webkit-tap-highlight-color: rgb(242 242 236 / 18%);
37
+ }
38
+
39
+ h1,
40
+ h2,
41
+ h3 {
42
+ text-wrap: balance;
43
+ }
44
+
45
+ p,
46
+ dd,
47
+ figcaption {
48
+ text-wrap: pretty;
49
+ }
50
+
51
+ ::selection {
52
+ background: var(--tm-paper);
53
+ color: var(--tm-ink);
54
+ }
55
+
56
+ :focus-visible {
57
+ outline: 2px solid var(--tm-focus);
58
+ outline-offset: 3px;
59
+ }
60
+
61
+ [aria-disabled='true'],
62
+ :disabled {
63
+ cursor: not-allowed;
64
+ opacity: 0.5;
65
+ }
66
+
67
+ @media (forced-colors: active) {
68
+ :focus-visible {
69
+ outline-color: Highlight;
70
+ }
71
+
72
+ [aria-current='page'],
73
+ [aria-current='location'],
74
+ [aria-current='true'],
75
+ [aria-pressed='true'] {
76
+ outline: 2px solid Highlight;
77
+ outline-offset: -2px;
78
+ }
79
+ }
80
+
81
+ @media (prefers-reduced-motion: reduce) {
82
+ html {
83
+ scroll-behavior: auto;
84
+ }
85
+
86
+ *,
87
+ *::before,
88
+ *::after {
89
+ scroll-behavior: auto;
90
+ transition-duration: 0.01ms;
91
+ }
92
+ }
93
+ }
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@textmode/design-system",
3
+ "version": "0.3.4",
4
+ "description": "Shared visual foundations and CSS primitives for textmode.art interfaces",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": [
8
+ "*.css"
9
+ ],
10
+ "files": [
11
+ "*.css",
12
+ "README.md"
13
+ ],
14
+ "exports": {
15
+ "./styles.css": "./styles.css",
16
+ "./tokens.css": "./tokens.css",
17
+ "./foundations.css": "./foundations.css",
18
+ "./primitives.css": "./primitives.css"
19
+ },
20
+ "scripts": {
21
+ "build": "npm run check",
22
+ "check": "npm run check:format && npm run check:package && npm test",
23
+ "check:format": "prettier --check .",
24
+ "check:package": "node scripts/check-package.mjs",
25
+ "test": "node --test tests/*.test.mjs",
26
+ "format": "prettier --write ."
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ }
31
+ }
package/primitives.css ADDED
@@ -0,0 +1,81 @@
1
+ @layer textmode-primitives {
2
+ .tm-command {
3
+ display: inline-flex;
4
+ min-height: var(--tm-touch-target);
5
+ align-items: center;
6
+ justify-content: center;
7
+ gap: var(--tm-space-2);
8
+ border: var(--tm-rule-width) solid var(--tm-rule);
9
+ padding: var(--tm-space-3) var(--tm-space-4);
10
+ background: transparent;
11
+ color: var(--tm-paper);
12
+ font-family: var(--tm-font-interface);
13
+ font-size: var(--tm-type-control);
14
+ line-height: 1;
15
+ text-decoration: none;
16
+ transition:
17
+ background-color var(--tm-duration-state) var(--tm-ease-out),
18
+ border-color var(--tm-duration-state) var(--tm-ease-out),
19
+ color var(--tm-duration-state) var(--tm-ease-out);
20
+ }
21
+
22
+ .tm-command:hover,
23
+ .tm-command:active,
24
+ .tm-command[aria-pressed='true'] {
25
+ border-color: var(--tm-paper);
26
+ background: var(--tm-paper);
27
+ color: var(--tm-ink);
28
+ }
29
+
30
+ .tm-command--signal {
31
+ border-color: var(--tm-signal);
32
+ background: var(--tm-signal);
33
+ color: var(--tm-paper);
34
+ }
35
+
36
+ .tm-command--signal:hover,
37
+ .tm-command--signal:active {
38
+ border-color: var(--tm-paper);
39
+ }
40
+
41
+ .tm-rule-panel {
42
+ border-block: var(--tm-rule-width) solid var(--tm-rule);
43
+ background: var(--tm-ink);
44
+ }
45
+
46
+ .tm-ledger-row {
47
+ display: flex;
48
+ min-height: var(--tm-touch-target);
49
+ align-items: center;
50
+ justify-content: space-between;
51
+ gap: var(--tm-space-4);
52
+ border-bottom: var(--tm-rule-width) solid var(--tm-rule-muted);
53
+ font-variant-numeric: tabular-nums;
54
+ }
55
+
56
+ .tm-status-signal {
57
+ display: inline-flex;
58
+ align-items: center;
59
+ gap: var(--tm-space-2);
60
+ color: var(--tm-paper-muted);
61
+ }
62
+
63
+ .tm-status-signal::before {
64
+ width: 0.55em;
65
+ height: 0.55em;
66
+ background: var(--tm-signal);
67
+ content: '';
68
+ }
69
+
70
+ .tm-sr-only {
71
+ position: absolute;
72
+ width: 1px;
73
+ height: 1px;
74
+ padding: 0;
75
+ border: 0;
76
+ margin: -1px;
77
+ clip: rect(0, 0, 0, 0);
78
+ overflow: hidden;
79
+ white-space: nowrap;
80
+ }
81
+ }
package/styles.css ADDED
@@ -0,0 +1,3 @@
1
+ @import './tokens.css';
2
+ @import './foundations.css';
3
+ @import './primitives.css';
package/tokens.css ADDED
@@ -0,0 +1,78 @@
1
+ @layer tokens {
2
+ :root {
3
+ color-scheme: dark;
4
+
5
+ /* Primitive palette */
6
+ --tm-color-black: #0a0a0a;
7
+ --tm-color-black-raised: #101010;
8
+ --tm-color-black-elevated: #171717;
9
+ --tm-color-white: #f2f2ec;
10
+ --tm-color-white-muted: #d8d8d2;
11
+ --tm-color-gray: #9a9a95;
12
+ --tm-color-gray-dark: #343432;
13
+ --tm-color-line: #5a5a56;
14
+ --tm-color-line-muted: #292927;
15
+ --tm-color-crimson: #b11226;
16
+ --tm-color-crimson-readable: #ef4960;
17
+ --tm-color-danger: #ff7e8c;
18
+
19
+ /* Semantic color roles */
20
+ --tm-ink: var(--tm-color-black);
21
+ --tm-surface: var(--tm-color-black-raised);
22
+ --tm-surface-raised: var(--tm-color-black-elevated);
23
+ --tm-paper: var(--tm-color-white);
24
+ --tm-paper-muted: var(--tm-color-white-muted);
25
+ --tm-text-muted: var(--tm-color-gray);
26
+ --tm-rule: var(--tm-color-line);
27
+ --tm-rule-muted: var(--tm-color-line-muted);
28
+ --tm-signal: var(--tm-color-crimson);
29
+ --tm-signal-text: var(--tm-color-crimson-readable);
30
+ --tm-error: var(--tm-color-danger);
31
+ --tm-focus: var(--tm-color-white);
32
+
33
+ /* Typography */
34
+ --tm-font-display: 'Monogram Extended';
35
+ --tm-font-interface: 'Monogram Extended';
36
+ --tm-font-copy: 'Monogram Extended';
37
+ --tm-font-code: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
38
+ --tm-type-meta: 1rem;
39
+ --tm-type-control: 1.25rem;
40
+ --tm-type-copy: 1.25rem;
41
+ --tm-type-copy-large: 1.5rem;
42
+ --tm-type-title: clamp(3.5rem, 8vw, 6rem);
43
+ --tm-leading-tight: 0.82;
44
+ --tm-leading-copy: 1.18;
45
+ --tm-tracking-display: -0.02em;
46
+
47
+ /* Geometry and layout */
48
+ --tm-space-1: 0.25rem;
49
+ --tm-space-2: 0.5rem;
50
+ --tm-space-3: 0.75rem;
51
+ --tm-space-4: 1rem;
52
+ --tm-space-5: 1.5rem;
53
+ --tm-space-6: 2rem;
54
+ --tm-space-7: 3rem;
55
+ --tm-space-8: 4rem;
56
+ --tm-page-pad: clamp(0.75rem, 1.8vw, 1.75rem);
57
+ --tm-header-height: 3.75rem;
58
+ --tm-control-height: 2.75rem;
59
+ --tm-section-height: calc(100svh - var(--tm-header-height));
60
+ --tm-section-rail-width: 3rem;
61
+ --tm-section-pager-height: 3rem;
62
+ --tm-rule-width: 1px;
63
+ --tm-touch-target: 2.75rem;
64
+
65
+ /* Motion and stacking */
66
+ --tm-duration-fast: 120ms;
67
+ --tm-duration-state: 180ms;
68
+ --tm-duration-section: 280ms;
69
+ --tm-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
70
+ --tm-z-dropdown: 20;
71
+ --tm-z-sticky: 30;
72
+ --tm-z-rail: 35;
73
+ --tm-z-modal-backdrop: 40;
74
+ --tm-z-modal: 50;
75
+ --tm-z-toast: 60;
76
+ --tm-z-tooltip: 70;
77
+ }
78
+ }