@tutti-os/ui-system 0.0.229 → 0.0.231

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.
@@ -0,0 +1,56 @@
1
+ /* This file is generated from ../tokens/renderer-theme.json. Do not edit it directly. */
2
+ :root {
3
+ --renderer-accent: rgb(65 130 245);
4
+ --renderer-accent-pressed: rgb(53 110 222);
5
+ --renderer-background: oklch(0.986 0.004 84);
6
+ --renderer-background-fronted: rgb(255 255 255 / 1);
7
+ --renderer-background-panel: rgb(248 250 252);
8
+ --renderer-border: oklch(0.904 0.005 252);
9
+ --renderer-danger: rgb(220 38 38);
10
+ --renderer-foreground: oklch(0.248 0.016 258);
11
+ --renderer-muted: rgb(60 60 60 / 50%);
12
+ --renderer-panel: oklch(0.975 0.004 84 / 92%);
13
+ --renderer-scrim: rgb(0 0 0 / 60%);
14
+ --renderer-scrim-strong: rgb(0 0 0 / 64%);
15
+ --renderer-success: rgb(34 197 94);
16
+ --renderer-text-primary: rgb(60 60 60);
17
+ --renderer-text-secondary: rgb(60 60 60 / 70%);
18
+ }
19
+
20
+ :root[data-theme="dark"] {
21
+ --renderer-accent: rgb(90 155 255);
22
+ --renderer-accent-pressed: rgb(79 143 255);
23
+ --renderer-background: oklch(0.192 0.008 255);
24
+ --renderer-background-fronted: rgb(51 51 51 / 1);
25
+ --renderer-background-panel: rgb(42 42 43);
26
+ --renderer-border: oklch(0.352 0.012 255);
27
+ --renderer-danger: rgb(244 91 91);
28
+ --renderer-foreground: oklch(0.955 0.004 84);
29
+ --renderer-muted: rgb(255 255 255 / 50%);
30
+ --renderer-panel: oklch(0.236 0.009 255 / 92%);
31
+ --renderer-scrim: rgb(0 0 0 / 60%);
32
+ --renderer-scrim-strong: rgb(0 0 0 / 64%);
33
+ --renderer-success: rgb(74 222 128);
34
+ --renderer-text-primary: rgb(255 255 255);
35
+ --renderer-text-secondary: rgb(255 255 255 / 70%);
36
+ }
37
+
38
+ @media (prefers-color-scheme: dark) {
39
+ :root:not([data-theme="light"]) {
40
+ --renderer-accent: rgb(90 155 255);
41
+ --renderer-accent-pressed: rgb(79 143 255);
42
+ --renderer-background: oklch(0.192 0.008 255);
43
+ --renderer-background-fronted: rgb(51 51 51 / 1);
44
+ --renderer-background-panel: rgb(42 42 43);
45
+ --renderer-border: oklch(0.352 0.012 255);
46
+ --renderer-danger: rgb(244 91 91);
47
+ --renderer-foreground: oklch(0.955 0.004 84);
48
+ --renderer-muted: rgb(255 255 255 / 50%);
49
+ --renderer-panel: oklch(0.236 0.009 255 / 92%);
50
+ --renderer-scrim: rgb(0 0 0 / 60%);
51
+ --renderer-scrim-strong: rgb(0 0 0 / 64%);
52
+ --renderer-success: rgb(74 222 128);
53
+ --renderer-text-primary: rgb(255 255 255);
54
+ --renderer-text-secondary: rgb(255 255 255 / 70%);
55
+ }
56
+ }
@@ -0,0 +1,3 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
@@ -0,0 +1 @@
1
+ declare module "@tutti-os/ui-system/native.css";
@@ -1,3 +1,5 @@
1
+ @import "./generated/renderer-theme.css";
2
+
1
3
  :root {
2
4
  --font-sans-system:
3
5
  "Lexend Variable", "Lexend", -apple-system, BlinkMacSystemFont,
@@ -17,16 +19,16 @@
17
19
 
18
20
  --radius: 0.625rem;
19
21
 
20
- --background: oklch(0.986 0.004 84);
21
- --background-panel: rgb(248 250 252);
22
+ --background: var(--renderer-background);
23
+ --background-panel: var(--renderer-background-panel);
22
24
  --background-1: rgb(244 245 247);
23
25
  --background-session-flow: rgb(252 253 255);
24
26
  --background-session-sidepanel: rgb(244 245 247);
25
- --background-fronted: rgb(255 255 255 / 1);
27
+ --background-fronted: var(--renderer-background-fronted);
26
28
  --background-soft: oklch(0.968 0.006 84);
27
29
  --background-board-card: rgb(255 255 255 / 1);
28
- --foreground: oklch(0.248 0.016 258);
29
- --text-primary: rgb(60 60 60);
30
+ --foreground: var(--renderer-foreground);
31
+ --text-primary: var(--renderer-text-primary);
30
32
  --text-primary-hover: rgb(60 60 60 / 90%);
31
33
  --text-tertiary: rgb(60 60 60 / 50%);
32
34
  --text-placeholder: rgb(60 60 60 / 30%);
@@ -49,7 +51,7 @@
49
51
  --secondary-foreground: oklch(0.314 0.018 258);
50
52
  --muted: oklch(0.958 0.005 84);
51
53
  --muted-foreground: oklch(0.528 0.013 258);
52
- --text-secondary: rgb(60 60 60 / 70%);
54
+ --text-secondary: var(--renderer-text-secondary);
53
55
  --text-disabled: rgb(60 60 60 / 30%);
54
56
  --rich-text-mention-app: rgb(191, 90, 242);
55
57
  --rich-text-mention-issue: var(--tutti-purple);
@@ -57,7 +59,7 @@
57
59
  --folder: rgb(80, 175, 238);
58
60
  --rich-text-folder: rgb(80, 175, 238);
59
61
  --rich-text-mention-file: rgb(80, 175, 238);
60
- --accent-codex: rgb(65 130 245);
62
+ --accent-codex: var(--renderer-accent);
61
63
  --accent: var(--accent-codex);
62
64
  --accent-codex-border: color-mix(
63
65
  in srgb,
@@ -80,13 +82,13 @@
80
82
  --accent-foreground: oklch(0.302 0.02 258);
81
83
  --destructive: oklch(0.62 0.21 25);
82
84
  --destructive-foreground: oklch(0.985 0.004 25);
83
- --state-danger: rgb(220 38 38);
85
+ --state-danger: var(--renderer-danger);
84
86
  --state-danger-hover: color-mix(
85
87
  in srgb,
86
88
  var(--state-danger) 90%,
87
89
  transparent
88
90
  );
89
- --state-success: rgb(34 197 94);
91
+ --state-success: var(--renderer-success);
90
92
  --state-warning: rgb(234 121 8);
91
93
  --on-danger: rgb(220 38 38 / 8%);
92
94
  --on-danger-hover: color-mix(
@@ -94,7 +96,7 @@
94
96
  var(--on-danger) 92%,
95
97
  var(--state-danger)
96
98
  );
97
- --border: oklch(0.904 0.005 252);
99
+ --border: var(--renderer-border);
98
100
  --border-1: rgb(60 60 60 / 8%);
99
101
  --border-2: rgb(60 60 60 / 8%);
100
102
  --line-1: var(--border-1);
@@ -109,13 +111,13 @@
109
111
  var(--accent-codex) 12%
110
112
  );
111
113
 
112
- --panel: oklch(0.975 0.004 84 / 92%);
114
+ --panel: var(--renderer-panel);
113
115
  --panel-foreground: var(--foreground);
114
116
  --success: oklch(0.642 0.124 158);
115
117
  --success-foreground: oklch(0.985 0.004 145);
116
118
  --warning: oklch(0.774 0.116 86);
117
119
  --warning-foreground: oklch(0.29 0.05 84);
118
- --backdrop: rgb(0 0 0 / 60%);
120
+ --backdrop: var(--renderer-scrim);
119
121
 
120
122
  --shadow-soft: 0 10px 28px rgb(0 0 0 / 5%);
121
123
  --shadow-panel: 0 20px 44px rgb(0 0 0 / 8%);
@@ -207,16 +209,16 @@
207
209
  }
208
210
 
209
211
  :root[data-theme="dark"] {
210
- --background: oklch(0.192 0.008 255);
211
- --background-panel: rgb(42 42 43);
212
+ --background: var(--renderer-background);
213
+ --background-panel: var(--renderer-background-panel);
212
214
  --background-1: rgb(24 24 24);
213
215
  --background-session-flow: rgb(24 24 24);
214
216
  --background-session-sidepanel: rgb(42 42 43);
215
- --background-fronted: rgb(51 51 51 / 1);
217
+ --background-fronted: var(--renderer-background-fronted);
216
218
  --background-soft: oklch(0.224 0.01 255);
217
219
  --background-board-card: rgb(255 255 255 / 8%);
218
- --foreground: oklch(0.955 0.004 84);
219
- --text-primary: rgb(255 255 255);
220
+ --foreground: var(--renderer-foreground);
221
+ --text-primary: var(--renderer-text-primary);
220
222
  --text-primary-hover: rgb(255 255 255 / 90%);
221
223
  --text-tertiary: rgb(255 255 255 / 50%);
222
224
  --text-placeholder: rgb(255 255 255 / 30%);
@@ -239,7 +241,7 @@
239
241
  --secondary-foreground: var(--foreground);
240
242
  --muted: oklch(0.282 0.008 255);
241
243
  --muted-foreground: oklch(0.734 0.012 255);
242
- --text-secondary: rgb(255 255 255 / 70%);
244
+ --text-secondary: var(--renderer-text-secondary);
243
245
  --text-disabled: rgb(255 255 255 / 30%);
244
246
  --rich-text-mention-app: rgb(191, 90, 242);
245
247
  --rich-text-mention-issue: var(--tutti-purple);
@@ -247,7 +249,7 @@
247
249
  --folder: rgb(80, 175, 238);
248
250
  --rich-text-folder: rgb(80, 175, 238);
249
251
  --rich-text-mention-file: rgb(80, 175, 238);
250
- --accent-codex: rgb(90 155 255);
252
+ --accent-codex: var(--renderer-accent);
251
253
  --accent: var(--accent-codex);
252
254
  --accent-codex-border: color-mix(
253
255
  in srgb,
@@ -270,13 +272,13 @@
270
272
  --accent-foreground: var(--foreground);
271
273
  --destructive: oklch(0.672 0.172 25);
272
274
  --destructive-foreground: oklch(0.19 0.01 25);
273
- --state-danger: rgb(244 91 91);
275
+ --state-danger: var(--renderer-danger);
274
276
  --state-danger-hover: color-mix(
275
277
  in srgb,
276
278
  var(--state-danger) 90%,
277
279
  transparent
278
280
  );
279
- --state-success: rgb(74 222 128);
281
+ --state-success: var(--renderer-success);
280
282
  --state-warning: rgb(251 146 60);
281
283
  --on-danger: rgb(248 113 113 / 10%);
282
284
  --on-danger-hover: color-mix(
@@ -284,7 +286,7 @@
284
286
  var(--on-danger) 82%,
285
287
  var(--state-danger)
286
288
  );
287
- --border: oklch(0.352 0.012 255);
289
+ --border: var(--renderer-border);
288
290
  --border-1: rgb(255 255 255 / 12%);
289
291
  --border-2: rgb(255 255 255 / 8%);
290
292
  --line-1: var(--border-1);
@@ -299,13 +301,13 @@
299
301
  var(--accent-codex) 12%
300
302
  );
301
303
 
302
- --panel: oklch(0.236 0.009 255 / 92%);
304
+ --panel: var(--renderer-panel);
303
305
  --panel-foreground: var(--foreground);
304
306
  --success: oklch(0.702 0.124 158);
305
307
  --success-foreground: oklch(0.172 0.01 158);
306
308
  --warning: oklch(0.82 0.108 86);
307
309
  --warning-foreground: oklch(0.204 0.02 84);
308
- --backdrop: rgb(0 0 0 / 60%);
310
+ --backdrop: var(--renderer-scrim);
309
311
 
310
312
  --shadow-soft: 0 14px 32px rgb(0 0 0 / 24%);
311
313
  --shadow-panel: 0 24px 52px rgb(0 0 0 / 34%);
@@ -387,16 +389,16 @@
387
389
 
388
390
  @media (prefers-color-scheme: dark) {
389
391
  :root:not([data-theme="light"]) {
390
- --background: oklch(0.192 0.008 255);
391
- --background-panel: rgb(42 42 43);
392
+ --background: var(--renderer-background);
393
+ --background-panel: var(--renderer-background-panel);
392
394
  --background-1: rgb(24 24 24);
393
395
  --background-session-flow: rgb(24 24 24);
394
396
  --background-session-sidepanel: rgb(42 42 43);
395
- --background-fronted: rgb(51 51 51 / 1);
397
+ --background-fronted: var(--renderer-background-fronted);
396
398
  --background-soft: oklch(0.224 0.01 255);
397
399
  --background-board-card: rgb(255 255 255 / 8%);
398
- --foreground: oklch(0.955 0.004 84);
399
- --text-primary: rgb(255 255 255);
400
+ --foreground: var(--renderer-foreground);
401
+ --text-primary: var(--renderer-text-primary);
400
402
  --text-primary-hover: rgb(255 255 255 / 90%);
401
403
  --text-tertiary: rgb(255 255 255 / 50%);
402
404
  --text-placeholder: rgb(255 255 255 / 30%);
@@ -419,7 +421,7 @@
419
421
  --secondary-foreground: var(--foreground);
420
422
  --muted: oklch(0.282 0.008 255);
421
423
  --muted-foreground: oklch(0.734 0.012 255);
422
- --text-secondary: rgb(255 255 255 / 70%);
424
+ --text-secondary: var(--renderer-text-secondary);
423
425
  --text-disabled: rgb(255 255 255 / 30%);
424
426
  --rich-text-mention-app: rgb(191, 90, 242);
425
427
  --rich-text-mention-issue: var(--tutti-purple);
@@ -427,7 +429,7 @@
427
429
  --folder: rgb(80, 175, 238);
428
430
  --rich-text-folder: rgb(80, 175, 238);
429
431
  --rich-text-mention-file: rgb(80, 175, 238);
430
- --accent-codex: rgb(90 155 255);
432
+ --accent-codex: var(--renderer-accent);
431
433
  --accent: var(--accent-codex);
432
434
  --accent-codex-border: color-mix(
433
435
  in srgb,
@@ -450,13 +452,13 @@
450
452
  --accent-foreground: var(--foreground);
451
453
  --destructive: oklch(0.672 0.172 25);
452
454
  --destructive-foreground: oklch(0.19 0.01 25);
453
- --state-danger: rgb(244 91 91);
455
+ --state-danger: var(--renderer-danger);
454
456
  --state-danger-hover: color-mix(
455
457
  in srgb,
456
458
  var(--state-danger) 90%,
457
459
  transparent
458
460
  );
459
- --state-success: rgb(74 222 128);
461
+ --state-success: var(--renderer-success);
460
462
  --state-warning: rgb(251 146 60);
461
463
  --on-danger: rgb(248 113 113 / 10%);
462
464
  --on-danger-hover: color-mix(
@@ -464,7 +466,7 @@
464
466
  var(--on-danger) 82%,
465
467
  var(--state-danger)
466
468
  );
467
- --border: oklch(0.352 0.012 255);
469
+ --border: var(--renderer-border);
468
470
  --border-1: rgb(255 255 255 / 12%);
469
471
  --border-2: rgb(255 255 255 / 8%);
470
472
  --line-1: var(--border-1);
@@ -479,13 +481,13 @@
479
481
  var(--accent-codex) 12%
480
482
  );
481
483
 
482
- --panel: oklch(0.236 0.009 255 / 92%);
484
+ --panel: var(--renderer-panel);
483
485
  --panel-foreground: var(--foreground);
484
486
  --success: oklch(0.702 0.124 158);
485
487
  --success-foreground: oklch(0.172 0.01 158);
486
488
  --warning: oklch(0.82 0.108 86);
487
489
  --warning-foreground: oklch(0.204 0.02 84);
488
- --backdrop: rgb(0 0 0 / 60%);
490
+ --backdrop: var(--renderer-scrim);
489
491
 
490
492
  --shadow-soft: 0 14px 32px rgb(0 0 0 / 24%);
491
493
  --shadow-panel: 0 24px 52px rgb(0 0 0 / 34%);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tutti-os/ui-system",
3
- "version": "0.0.229",
3
+ "version": "0.0.231",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -42,6 +42,14 @@
42
42
  "types": "./dist/metadata/index.d.ts",
43
43
  "import": "./dist/metadata/index.js"
44
44
  },
45
+ "./native": {
46
+ "types": "./dist/native.d.ts",
47
+ "import": "./dist/native.js"
48
+ },
49
+ "./native.css": {
50
+ "types": "./dist/styles/native.css.d.ts",
51
+ "default": "./dist/styles/native.css"
52
+ },
45
53
  "./styles.css": "./dist/styles/index.css",
46
54
  "./utils": {
47
55
  "types": "./dist/utils.d.ts",
@@ -78,11 +86,13 @@
78
86
  "ws": "^8.20.1"
79
87
  },
80
88
  "devDependencies": {
89
+ "@gorhom/bottom-sheet": "5.2.14",
81
90
  "@testing-library/jest-dom": "^6.9.1",
82
91
  "@testing-library/react": "^16.3.0",
83
92
  "@types/react": "^19.1.6",
84
93
  "@types/react-dom": "^19.1.5",
85
94
  "@types/ws": "^8.18.1",
95
+ "react-native": "0.86.0",
86
96
  "jsdom": "^27.2.0",
87
97
  "tsx": "^4.22.3",
88
98
  "typescript": "^5.8.3",
@@ -91,8 +101,18 @@
91
101
  "@tutti-os/config-tsconfig": "0.0.0"
92
102
  },
93
103
  "peerDependencies": {
104
+ "@gorhom/bottom-sheet": ">=5 <6",
94
105
  "react": "^19.1.0",
95
- "react-dom": "^19.1.0"
106
+ "react-dom": "^19.1.0",
107
+ "react-native": ">=0.86 <0.87"
108
+ },
109
+ "peerDependenciesMeta": {
110
+ "react-dom": {
111
+ "optional": true
112
+ },
113
+ "react-native": {
114
+ "optional": true
115
+ }
96
116
  },
97
117
  "tutti": {
98
118
  "tailwindSourceRoot": "src"
@@ -120,6 +140,9 @@
120
140
  "metadata": [
121
141
  "./dist/metadata/index.d.ts"
122
142
  ],
143
+ "native": [
144
+ "./dist/native.d.ts"
145
+ ],
123
146
  "utils": [
124
147
  "./dist/utils.d.ts"
125
148
  ]
package/ui-system.md CHANGED
@@ -90,6 +90,13 @@ The visual language that this package should serve is defined in [Desktop Visual
90
90
  Root runtime entry for shared primitives, icon components, and the small set of utility exports that primitives depend on
91
91
  - `@tutti-os/ui-system/styles.css`
92
92
  Shared stylesheet entry loaded by renderer shells
93
+ - `@tutti-os/ui-system/native.css`
94
+ NativeWind stylesheet entry loaded once by React Native renderer shells
95
+ - `@tutti-os/ui-system/native`
96
+ React Native primitive and semantic-token entry; this is separate from the
97
+ DOM component entry and must not be imported by desktop renderers. Native
98
+ consumers provide React Native and the documented Bottom Sheet runtime;
99
+ `react-dom` is optional for this platform-specific entry.
93
100
  - `@tutti-os/ui-system/components`
94
101
  Stable component barrel for tooling and rare category-focused imports
95
102
  - `@tutti-os/ui-system/icons`
@@ -107,6 +114,11 @@ Default consumption rules:
107
114
 
108
115
  - application code should prefer importing primitives and icons from `@tutti-os/ui-system`
109
116
  - renderer entrypoints should import `@tutti-os/ui-system/styles.css` once
117
+ - React Native renderer entrypoints should import
118
+ `@tutti-os/ui-system/native.css` once
119
+ - React Native components and screens should import Native primitives and
120
+ semantic tokens from `@tutti-os/ui-system/native`, never from a private app
121
+ palette
110
122
  - shadcn monorepo aliases may target `@tutti-os/ui-system/components` and `@tutti-os/ui-system/utils`
111
123
  - application runtime code must not import `@tutti-os/ui-system/dev-vite`
112
124
  - consumers must not deep import `@tutti-os/ui-system/src/*` or component file
@@ -276,7 +288,21 @@ host-owned caller logic.
276
288
 
277
289
  ## Token Rules
278
290
 
279
- - CSS variables are the source of truth for theme values
291
+ - `src/tokens/renderer-theme.json` is the single semantic-token manifest for
292
+ the shared Web/Native subset. It generates Web CSS renderer variables and
293
+ Native light/dark palettes; renderer-specific literal values may differ when
294
+ their color syntaxes or current visual languages require it. Do not duplicate
295
+ these values in application code.
296
+ - `NativeThemeProvider` resolves the operating-system scheme by default, or a
297
+ caller-provided `"light" | "dark"` product preference. Native primitives and
298
+ Mobile composition consume `useNativeTheme()` rather than application-local
299
+ palettes. `nativeTheme` remains only as a dark compatibility value for
300
+ non-rendering callers; this does not yet promise full Desktop/Mobile visual
301
+ parity.
302
+ - `pnpm check:ui-boundaries` verifies generated renderer-token outputs stay in
303
+ sync with the manifest. Regenerate them with
304
+ `node tools/scripts/check-ui-renderer-tokens.mjs --write` before formatting
305
+ and committing a manifest change.
280
306
  - Shared theme styles must support both host-managed
281
307
  `html[data-theme="light" | "dark"]` and workspace-app CSS
282
308
  `prefers-color-scheme`; explicit `data-theme` values should override system
@@ -287,6 +313,22 @@ host-owned caller logic.
287
313
  - Build primitives for a calm workbench shell, not for marketing-card
288
314
  theatrics.
289
315
 
316
+ ### Native renderer review
317
+
318
+ The DOM storyboard cannot render React Native primitives faithfully. Each
319
+ public Native primitive must therefore have a concrete example in the Mobile
320
+ development gallery and be reviewed on a Native renderer before it is promoted
321
+ from experimental status. The gallery must import only the stable
322
+ `@tutti-os/ui-system/native` entrypoint and render the primitive's public
323
+ states; it is the Native counterpart of a DOM storyboard example, not a second
324
+ component implementation.
325
+
326
+ `NativeSheet` additionally requires the consuming app to install
327
+ `@gorhom/bottom-sheet` and provide its `BottomSheetModalProvider` below a
328
+ `GestureHandlerRootView`. Reanimated and Gesture Handler remain part of that
329
+ Native renderer contract; application roots own provider placement, not the
330
+ shared primitive.
331
+
290
332
  For cross-surface stacking, use shared semantic `z-index` tokens instead of
291
333
  local magic numbers. Current global layer tokens live in
292
334
  `packages/ui/system/src/styles/theme.css` and should be the default source of