@flyos/design-system 1.6.0 → 1.8.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flyos/design-system",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "description": "FlyOS design system — shared components, directives, pipes, services, and models for Business App developers.",
5
5
  "keywords": [
6
6
  "flyos",
@@ -47,6 +47,107 @@
47
47
  // `_fly-theme.scss`, so `@use 'fly-theme'` is all a consumer needs.
48
48
  // ─────────────────────────────────────────────────────────────────────────────
49
49
 
50
+ // ── The platform TYPE layer (UX v2, S1.7–S1.10 fallout) ──────────────────────
51
+ // `_tokens.scss` owns `--font-family` / `--font-family-mono` and the `--font-*`
52
+ // role ramp (`--font-footnote`, `--font-caption1`, …). Like the two Nova
53
+ // partials below it was reachable only through `_fly-theme.scss`, i.e. only in
54
+ // the desktop shell.
55
+
56
+ // The type layer fails harder than the colour layers do, and it fails silently.
57
+ // The Nova form/overlay/content tasks landed 26 declarations across `lib/**` of
58
+ // the form `font: 600 13px/1.3 var(--font-family)` or `font: var(--nova-font-
59
+ // menu-item)`. A `var()` naming an undefined custom property is invalid at
60
+ // computed-value time, and in a SHORTHAND that invalidates the WHOLE
61
+ // declaration — weight, size and line-height all fall back to inherited, not
62
+ // just the family. Standalone that is a 13px control label rendering at the
63
+ // app's 16px body size inside a box hard-sized to 36/30/26px: a `fly-select`
64
+ // trigger, a `fly-form-field` label, a `fly-checkbox` label, a `fly-drawer`
65
+ // title. Nothing reported it because the shell renders every one of them
66
+ // correctly. Before this line the DS had ZERO `var(--font-family)` references
67
+ // in `lib/**`; the guard that now walks those files lives in
68
+ // `app-surface-nova-bridge.spec.ts`.
69
+
70
+ // Idempotent in the shell for the same reason as the two below: `_fly-theme.scss`
71
+ // already `@use`s `tokens` FIRST, Sass loads a module once per compilation, and
72
+ // the compiled entry is byte-identical either way.
73
+
74
+ // Standalone it adds 120 greenfield names, of which the three External Apps
75
+ // reference five. Four of those (`--font-title2`, `--system-blue`,
76
+ // `--system-indigo`, `--system-red`) were dangling references that now resolve.
77
+ // The fifth is `--font-family` itself, and it is the one behavioural change in
78
+ // this commit: Circles already loads the DS's own Geist from its
79
+ // `public/ui-fonts/geist.css` and is unaffected, but Thoughts and PPM write
80
+ // `var(--font-family, 'Roboto', …)` on `html, body` while bundling Roboto and
81
+ // NOT Geist. Both must bind `--font-family` to their own stack (or drop the
82
+ // indirection) before taking this DS release, or their body text falls through
83
+ // to a face they do not ship. Recorded here rather than worked around: the
84
+ // alternative — leaving the token undefined so their fallback keeps firing —
85
+ // is what dropped the 26 declarations above.
86
+ @use 'tokens';
87
+
88
+ // ── The Nova bridge (UX v2, S1.11) ───────────────────────────────────────────
89
+ // `_nova-tokens.scss` carries the Nova vocabulary — the `--w*` ink ramp,
90
+ // `--mat-*`, `--sys-*`, `--tint-*`, the `--glass2-*` quartet. `_fly-theme.scss`
91
+ // loads it, and the desktop shell is the only consumer that loads that entry.
92
+ // The three External Apps do NOT: Circles, Thoughts and PPM each `@use` THIS
93
+ // partial by bare name, and Circles keeps `// @use 'fly-theme';` commented out
94
+ // on line 1 of its `styles.scss` — the same fact this file's header records.
95
+
96
+ // So without the line below, the Nova names are undefined in precisely the
97
+ // builds that render this family on its own opaque paper. That matters for what
98
+ // comes NEXT rather than for anything today: at the DS 2.0 flip the values in
99
+ // this file are re-pointed at ramp steps (`--ink: var(--w95)`,
100
+ // `--line: var(--w18)`; the whole table is in `.workflow/plans/ux-refresh/
101
+ // notes/S1.11-app-surface-bridge.md`). A `var()` whose token is undefined makes
102
+ // the entire declaration invalid at computed-value time, so that flip would
103
+ // silently unset ink and hairlines for every standalone External App while
104
+ // looking perfect in the shell — the light-mode-only failure that
105
+ // `_shell-embed-bridge.scss` and `_ink-baseline.scss` were each written to end,
106
+ // arriving a third time through a different door.
107
+
108
+ // It is additive in both directions. In the shell it changes nothing at all:
109
+ // `_fly-theme.scss` already `@use`s `nova-tokens` first, Sass loads a module
110
+ // once per compilation, and the compiled entry is byte-identical either way.
111
+ // Standalone it adds greenfield names only — no Nova name is referenced or
112
+ // declared anywhere in Circles, Thoughts or PPM. It is also invisible to
113
+ // `tools/ds-compat`, which derives the token surface by scanning `src/scss/**`
114
+ // per file, not by compiling this entry.
115
+
116
+ // `app-surface-nova-bridge.spec.ts` holds the wire in place and proves that
117
+ // every `var()` this file emits still resolves inside the standalone bundle.
118
+ @use 'nova-tokens';
119
+
120
+ // The same argument, for motion. The app-surface components now reach for the
121
+ // Nova keyframes (`itemIn` / `riseIn` / `appTileIn`) and the `--nova-ease-*` /
122
+ // `--nova-duration-*` tokens, and those live in `_nova-motion.scss` — which,
123
+ // like `_nova-tokens.scss`, was reachable only through `_fly-theme.scss` and so
124
+ // only in the shell. Standalone, an `animation: itemIn …` naming an undefined
125
+ // keyframe is not an error: it silently does nothing, so a list that staggers
126
+ // in for a Core App would appear instantly in an External App with no gate
127
+ // anywhere reporting a difference. Bridging it here is what makes the two
128
+ // builds agree. Same idempotence: the shell already loads this module, so the
129
+ // compiled shell entry is unchanged, and standalone it adds one `:root` block,
130
+ // the keyframe inventory and the single `prefers-reduced-motion` block.
131
+ @use 'nova-motion';
132
+
133
+ // The same argument again, for the Nova TYPE roles — and the reason `tokens`
134
+ // above is not optional. Half the `--nova-font-*` table SNAPs onto the platform
135
+ // ramp by reference (`--nova-font-menu-item: var(--font-footnote)`,
136
+ // `--nova-font-body`, `--nova-font-tooltip`), so loading this partial without
137
+ // `tokens` would not fix anything: it would move the dangling reference one
138
+ // level down, where a component's `font: var(--nova-font-menu-item)` still
139
+ // resolves to an invalid value and still drops whole. The two travel together
140
+ // or neither is worth loading.
141
+
142
+ // This is the one `@use` in this file that the partial's own header argues
143
+ // against ("`@use`d exactly once, from `_fly-theme.scss` … never a second
144
+ // time"). That warning is about COMPONENT-level `@use`, which re-emits the
145
+ // `:root` block into each component's compiled stylesheet; this is a global
146
+ // entry, the same role `_fly-theme.scss` plays, and Sass still emits the module
147
+ // exactly once per compilation. Federated it is `_fly-theme.scss`'s copy;
148
+ // standalone it is this one. Never both.
149
+ @use 'nova-type';
150
+
50
151
  :root,
51
152
  html.light-theme {
52
153
  // ── Neutrals — text ──────────────────────────────────────────────────────
@@ -27,13 +27,18 @@
27
27
  // plate ~47px wide) cut every tool's tip off inside its own column, and no z-index could
28
28
  // help — clipping is not a stacking question, and `position: fixed` on the pseudo would
29
29
  // still be trapped by those plates' `backdrop-filter` containing block.
30
- //
30
+
31
31
  // `FlyTooltipDirective` now owns the surface for BOTH `[flyTooltip]` and `[data-tooltip]`:
32
32
  // a `position: fixed` node parented to `<body>`, so it escapes every clip, flips placement
33
33
  // and clamps to the viewport. Components that write `data-tooltip` imperatively (the DS
34
34
  // icon button) list the directive in `hostDirectives`; templates with a static or bound
35
35
  // `data-tooltip` must IMPORT `FlyTooltipDirective` for the label to appear.
36
- //
36
+
37
+ // The surface itself (Nova's `--mat-tip-a`/`-b` material, opaque, no blur) lives entirely
38
+ // in the directive's injected `<style>` — see `fly-tooltip.directive.ts` for the recipe and
39
+ // why it is deliberately NOT a `glass.popover()` thin-blur surface (S1.8). Nothing here
40
+ // draws a tooltip; this selector only keeps the positioning context callers relied on.
41
+
37
42
  // Only the positioning context the attribute implied is kept, since callers may still hang
38
43
  // their own absolutely-positioned adornments (badges, dots) off a tooltip'd control.
39
44
  [data-tooltip] {
@@ -1,9 +1,32 @@
1
- @use 'vos-button-mixins' as *;
1
+ @use 'fos-button-mixins' as *;
2
2
 
3
- // ─── visionOS Button Utility Classes (shared with FlyOS desktop shell) ────────
3
+ // ─── FlyOS Button Utility Classes (shared with the desktop shell) ─────────────
4
4
  // Requires @use 'fly-theme' (or equivalent tokens) before this partial.
5
5
 
6
+ // ## The `.vos-` aliases are a deprecation window, not a style
7
+
8
+ // These three classes are the only PUBLISHED part of the old `vos-` prefix: External
9
+ // Apps write them in their own templates (measured: Circles authors `vos-btn` x21 and
10
+ // `vos-link` x4 across 6 files; Thoughts and PPM use none). Removing the old spelling
11
+ // is therefore a breaking change to this package's CSS surface — and a silent one,
12
+ // because a class that stops matching is not a build error in either repo, it simply
13
+ // renders unstyled.
14
+
15
+ // **And no gate would have caught it.** ds-compat extracts four things — the TS export
16
+ // surface, CSS CUSTOM PROPERTIES, CSS layers, and peer floors. It has no class-name
17
+ // extractor, so a renamed class is invisible to it: dropping `.vos-btn` outright still
18
+ // reports "federation-safe". The gate protects the token surface, not the class surface,
19
+ // even though the class surface is the one External-App TEMPLATES are written against.
20
+
21
+ // So `fos-` is canonical and `vos-` rides along as an alias, and the alias is doing the
22
+ // work the gate cannot.
23
+
24
+ // **Delete the `.vos-` halves at DS 2.0 (plan item S6.1b) — and only AFTER S6.2 lands
25
+ // the Circles migration.** Removing them first breaks Circles with no diagnostic.
26
+ // Verify against a grep of the Circles worktree, not of this repo.
27
+
6
28
  @layer designsystem {
29
+ .fos-btn,
7
30
  .vos-btn {
8
31
  position: relative;
9
32
  display: inline-flex;
@@ -60,11 +83,11 @@
60
83
  }
61
84
 
62
85
  &.platter::before {
63
- @include vos-platter-layers(inherit);
86
+ @include fos-platter-layers(inherit);
64
87
  }
65
88
 
66
89
  &:hover:not(:disabled, .selected, .active)::before {
67
- @include vos-platter-layers(inherit);
90
+ @include fos-platter-layers(inherit);
68
91
  }
69
92
 
70
93
  &.selected,
@@ -81,7 +104,7 @@
81
104
  pointer-events: none;
82
105
 
83
106
  &::before {
84
- @include vos-disabled-layers(inherit);
107
+ @include fos-disabled-layers(inherit);
85
108
  }
86
109
  }
87
110
 
@@ -104,6 +127,8 @@
104
127
  }
105
128
  }
106
129
 
130
+ // `.vos-btn-symbol` alias: see the deprecation note at the top of this file.
131
+ .fos-btn-symbol,
107
132
  .vos-btn-symbol {
108
133
  position: relative;
109
134
  display: inline-flex;
@@ -152,11 +177,11 @@
152
177
  }
153
178
 
154
179
  &.platter::before {
155
- @include vos-platter-layers(500px);
180
+ @include fos-platter-layers(500px);
156
181
  }
157
182
 
158
183
  &:hover:not(:disabled, .selected, .active)::before {
159
- @include vos-platter-layers(500px);
184
+ @include fos-platter-layers(500px);
160
185
  }
161
186
 
162
187
  &.selected,
@@ -173,7 +198,7 @@
173
198
  pointer-events: none;
174
199
 
175
200
  &::before {
176
- @include vos-disabled-layers(500px);
201
+ @include fos-disabled-layers(500px);
177
202
  }
178
203
  }
179
204
 
@@ -185,6 +210,8 @@
185
210
  }
186
211
  }
187
212
 
213
+ // `.vos-link` alias: see the deprecation note at the top of this file.
214
+ .fos-link,
188
215
  .vos-link {
189
216
  display: inline-flex;
190
217
  align-items: center;
@@ -6,6 +6,15 @@
6
6
  @use 'theme-light';
7
7
  @use 'theme-dark';
8
8
 
9
+ // ── Nova (UX v2) design language ─────────────────────────────────────────────
10
+ // Additive layer: new vocabulary only, nothing here re-values a token the three
11
+ // partials above already define (the colliding glass quartet is renamed
12
+ // `--glass2-*` per the D1 ruling). Canon: `skills/desktop-design-language.md`.
13
+ // `nova-glass` is mixins-only and is @used by components, not from here.
14
+ @use 'nova-tokens';
15
+ @use 'nova-motion';
16
+ @use 'nova-type';
17
+
9
18
  // The inherited `color` for themed documents. Emits a rule, not tokens, so it
10
19
  // lives apart from the theme partials — see its header for why the absence of a
11
20
  // baseline was the root cause of the recurring black-ink-on-glass bug.
@@ -1,28 +1,28 @@
1
- // visionOS button pseudo-element layers (used by _business-app-buttons.scss).
2
- // Kept separate from desktop-app glass mixins so Business Apps only pull button-related SCSS.
3
-
4
- @mixin vos-platter-layers($radius) {
5
- content: '';
6
- position: absolute;
7
- inset: 0;
8
- border-radius: $radius;
9
- pointer-events: none;
10
- background:
11
- linear-gradient(var(--btn-platter-lighten), var(--btn-platter-lighten)),
12
- linear-gradient(var(--btn-platter-dodge), var(--btn-platter-dodge));
13
- background-blend-mode: lighten, color-dodge;
14
- mix-blend-mode: screen;
15
- }
16
-
17
- @mixin vos-disabled-layers($radius) {
18
- content: '';
19
- position: absolute;
20
- inset: 0;
21
- border-radius: $radius;
22
- pointer-events: none;
23
- background:
24
- linear-gradient(var(--btn-disabled-lighten), var(--btn-disabled-lighten)),
25
- linear-gradient(var(--btn-disabled-dodge), var(--btn-disabled-dodge));
26
- background-blend-mode: lighten, color-dodge;
27
- mix-blend-mode: screen;
28
- }
1
+ // FlyOS button pseudo-element layers (used by _business-app-buttons.scss).
2
+ // Kept separate from desktop-app glass mixins so Business Apps only pull button-related SCSS.
3
+
4
+ @mixin fos-platter-layers($radius) {
5
+ content: '';
6
+ position: absolute;
7
+ inset: 0;
8
+ border-radius: $radius;
9
+ pointer-events: none;
10
+ background:
11
+ linear-gradient(var(--btn-platter-lighten), var(--btn-platter-lighten)),
12
+ linear-gradient(var(--btn-platter-dodge), var(--btn-platter-dodge));
13
+ background-blend-mode: lighten, color-dodge;
14
+ mix-blend-mode: screen;
15
+ }
16
+
17
+ @mixin fos-disabled-layers($radius) {
18
+ content: '';
19
+ position: absolute;
20
+ inset: 0;
21
+ border-radius: $radius;
22
+ pointer-events: none;
23
+ background:
24
+ linear-gradient(var(--btn-disabled-lighten), var(--btn-disabled-lighten)),
25
+ linear-gradient(var(--btn-disabled-dodge), var(--btn-disabled-dodge));
26
+ background-blend-mode: lighten, color-dodge;
27
+ mix-blend-mode: screen;
28
+ }
@@ -1,29 +1,29 @@
1
- // ─── Inherited-ink baseline ──────────────────────────────────────────────────
2
- //
3
- // Establishes the document's inherited `color`. Until this existed, NOTHING in
4
- // the shell ever set `color` on `html` or `body` — `_theme-light.scss` and
5
- // `_theme-dark.scss` declare custom properties only. So the inherited colour was
6
- // the user-agent default, **black**, and every component that says
7
- // `color: inherit` (fly-tree-nav rows, fly-breadcrumb's current crumb,
8
- // fly-search-input's typed text, fly-card's meta slot, and any consumer markup
9
- // that simply doesn't mention colour) rendered black ink on the smoked glass.
10
- //
11
- // That is why the "text is invisible in light theme" bug kept coming back app
12
- // after app: it was never really an app's mistake. There was no baseline to
13
- // inherit, so *forgetting* to set a colour was the failure mode, and the fix
14
- // kept being applied one component at a time. `--text-color` is white in BOTH
15
- // themes since the Liquid-Glass flip, so one declaration settles it everywhere.
16
- //
17
- // Scoped to the two theme classes on purpose — NOT `:root`. A business app
18
- // running STANDALONE renders on its own opaque paper (`--bg`, near-black
19
- // `--ink`) and does not load `fly-theme` at all; keying on the class means a
20
- // surface that never opted into a shell theme is never repainted white.
21
- //
22
- // A deliberate paper surface inside the shell (the documents editor) still
23
- // brings its own dark ink locally — a component rule beats this baseline, which
24
- // is exactly the intended precedence.
25
-
26
- html.light-theme,
27
- html.dark-theme {
28
- color: var(--text-color);
29
- }
1
+ // ─── Inherited-ink baseline ──────────────────────────────────────────────────
2
+ //
3
+ // Establishes the document's inherited `color`. Until this existed, NOTHING in
4
+ // the shell ever set `color` on `html` or `body` — `_theme-light.scss` and
5
+ // `_theme-dark.scss` declare custom properties only. So the inherited colour was
6
+ // the user-agent default, **black**, and every component that says
7
+ // `color: inherit` (fly-tree-nav rows, fly-breadcrumb's current crumb,
8
+ // fly-search-input's typed text, fly-card's meta slot, and any consumer markup
9
+ // that simply doesn't mention colour) rendered black ink on the smoked glass.
10
+ //
11
+ // That is why the "text is invisible in light theme" bug kept coming back app
12
+ // after app: it was never really an app's mistake. There was no baseline to
13
+ // inherit, so *forgetting* to set a colour was the failure mode, and the fix
14
+ // kept being applied one component at a time. `--text-color` is white in BOTH
15
+ // themes since the vibrancy flip, so one declaration settles it everywhere.
16
+ //
17
+ // Scoped to the two theme classes on purpose — NOT `:root`. A business app
18
+ // running STANDALONE renders on its own opaque paper (`--bg`, near-black
19
+ // `--ink`) and does not load `fly-theme` at all; keying on the class means a
20
+ // surface that never opted into a shell theme is never repainted white.
21
+ //
22
+ // A deliberate paper surface inside the shell (the documents editor) still
23
+ // brings its own dark ink locally — a component rule beats this baseline, which
24
+ // is exactly the intended precedence.
25
+
26
+ html.light-theme,
27
+ html.dark-theme {
28
+ color: var(--text-color);
29
+ }