@flyos/design-system 1.2.0 → 1.4.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.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "FlyOS design system — shared components, directives, pipes, services, and models for Business App developers.",
5
5
  "keywords": [
6
6
  "flyos",
@@ -19,61 +19,27 @@
19
19
  font-variant-numeric: tabular-nums;
20
20
  }
21
21
 
22
- // ── Tooltip (CSS-only, no JS dependency) ─────────────────────────────────────
23
- // Add `data-tooltip="text"` to any element to show a floating label on hover or
24
- // keyboard focus. Always pair with `aria-label` for screen-reader users —
25
- // data-tooltip is a *visual* affordance only (the flyTooltip directive wires
26
- // both together). Consumers should use `data-tooltip` *instead of* `title`.
22
+ // ── Tooltip ──────────────────────────────────────────────────────────────────
23
+ // `data-tooltip="text"` still shows a floating label on hover / keyboard focus, but the
24
+ // SURFACE is no longer drawn here. It used to be a `::before` + `::after` pair on this
25
+ // selector, and a pseudo-element is a child box of its host: every scrolling or
26
+ // `overflow: hidden` ancestor clipped it. The boards toolbar rail (an `overflow-y: auto`
27
+ // plate ~47px wide) cut every tool's tip off inside its own column, and no z-index could
28
+ // help — clipping is not a stacking question, and `position: fixed` on the pseudo would
29
+ // still be trapped by those plates' `backdrop-filter` containing block.
30
+ //
31
+ // `FlyTooltipDirective` now owns the surface for BOTH `[flyTooltip]` and `[data-tooltip]`:
32
+ // a `position: fixed` node parented to `<body>`, so it escapes every clip, flips placement
33
+ // and clamps to the viewport. Components that write `data-tooltip` imperatively (the DS
34
+ // icon button) list the directive in `hostDirectives`; templates with a static or bound
35
+ // `data-tooltip` must IMPORT `FlyTooltipDirective` for the label to appear.
36
+ //
37
+ // Only the positioning context the attribute implied is kept, since callers may still hang
38
+ // their own absolutely-positioned adornments (badges, dots) off a tooltip'd control.
27
39
  [data-tooltip] {
28
40
  position: relative;
29
41
  }
30
42
 
31
- [data-tooltip]::before,
32
- [data-tooltip]::after {
33
- position: absolute;
34
- left: 50%;
35
- pointer-events: none;
36
- opacity: 0;
37
- transition: opacity 0.14s ease, transform 0.14s ease;
38
- z-index: var(--z-tooltip);
39
- }
40
-
41
- [data-tooltip]::before {
42
- content: attr(data-tooltip);
43
- bottom: calc(100% + 8px);
44
- transform: translateX(-50%) translateY(3px);
45
- background: var(--ink);
46
- color: var(--ink-inverse);
47
- font-family: var(--font-sans, system-ui, sans-serif);
48
- font-size: var(--text-xs);
49
- font-weight: var(--fw-medium);
50
- line-height: 1.3;
51
- letter-spacing: 0;
52
- padding: 5px 9px;
53
- border-radius: var(--r-sm);
54
- white-space: nowrap;
55
- box-shadow: var(--shadow-tooltip);
56
- }
57
-
58
- [data-tooltip]::after {
59
- content: '';
60
- bottom: calc(100% + 3px);
61
- transform: translateX(-50%) translateY(3px);
62
- width: 0;
63
- height: 0;
64
- border-left: 5px solid transparent;
65
- border-right: 5px solid transparent;
66
- border-top: 5px solid var(--ink);
67
- }
68
-
69
- [data-tooltip]:hover::before,
70
- [data-tooltip]:hover::after,
71
- [data-tooltip]:focus-visible::before,
72
- [data-tooltip]:focus-visible::after {
73
- opacity: 1;
74
- transform: translateX(-50%) translateY(0);
75
- }
76
-
77
43
  // ── CDK overlay container ────────────────────────────────────────────────────
78
44
  // Styled entirely by @angular/cdk/overlay-prebuilt.css (imported by the global
79
45
  // stylesheet). Its default z-index 1000 is correct here: a connected dropdown
@@ -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 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,81 +1,81 @@
1
- // ─── Shell-embed bridge — app-surface tokens re-tinted onto shell glass ──────
2
- // MIXIN ONLY. This partial emits no CSS on import; it exists so the mapping
3
- // below lives in ONE place instead of being retyped per feature app.
4
- //
5
- // WHY IT IS NEEDED
6
- // The DS carries two token families on purpose (see `_app-surface-tokens.scss`'s
7
- // header). `--ink-*`/`--bg-*`/`--line-*` dress BUSINESS-APP CONTENT: an opaque
8
- // reading surface, dark ink on white in light mode. `--label-*`/`--surface-*`
9
- // dress SHELL CHROME: white ink on translucent glass over the user's wallpaper.
10
- //
11
- // A desktop-shell feature app renders inside a glass window, so its chrome is
12
- // necessarily the second family — but the moment it mounts a component from the
13
- // `fly-*` app-surface kit (or `@flyos/design-system-board`), that component
14
- // themes itself from the FIRST family and paints an opaque white slab with
15
- // near-black ink. One region, two families: the app's own header ink is white,
16
- // the slab beneath it is white, and the header goes invisible.
17
- //
18
- // That is not hypothetical. It shipped in canvas-boards and was measured live:
19
- // `.cbe__export-btn` computed `color: rgb(255,255,255)` sitting on a board whose
20
- // `--_surface` resolved to `oklch(100% 0 0deg)`. `core/theme/feature-app-surface-tokens.ts`
21
- // documents the same class of trap ("a dark-mode-only review passes while light
22
- // mode renders a white slab") — and note the failure is LIGHT-mode-only, because
23
- // in dark mode both families happen to agree on light-ink-on-dark.
24
- //
25
- // THE FIX is the seam the tokens file already names: an app that embeds in the
26
- // shell re-tints the content family onto glass. help-center (`.hc-shell`) and
27
- // dashboard-app hand-rolled identical copies of this map before it lived here.
28
- //
29
- // ALIASES ONLY — every value is another token, never a literal, so the whole map
30
- // follows the shell's theme automatically. The ONE exception is `--on-ink`, and
31
- // its reason is written at the declaration.
32
- @mixin app-surface-on-glass {
33
- // Surfaces: the window chrome supplies the material, so the app's own page
34
- // background is nothing at all; cards/tracks are lifts ON that plate.
35
- --bg: transparent;
36
- --bg-2: var(--surface-card);
37
- --bg-3: var(--fill-tertiary);
38
- --bg-hover: var(--surface-active);
39
-
40
- // Hairlines.
41
- --line: var(--separator);
42
- --line-2: var(--surface-border);
43
- --line-3: var(--separator);
44
-
45
- // Ink — opaque label tokens, never a surface token. Aliasing a translucent
46
- // surface onto an ink slot is what turns a control into an empty coloured
47
- // square (see the note in help-center.component.scss).
48
- --ink: var(--label-primary);
49
- --ink-2: var(--label-secondary);
50
- --ink-3: var(--label-secondary);
51
- --ink-4: var(--label-tertiary);
52
-
53
- // CONTRACT (`_app-surface-tokens.scss`): anything that redefines `--ink` MUST
54
- // redefine `--on-ink`, and it must be OPAQUE. `--on-ink` labels a fill of
55
- // `--ink` itself — the primary button. Above we pin `--ink` to the shell's
56
- // white label ink in BOTH themes, so its counter-ink is a fixed DARK value in
57
- // both. It cannot alias a shell token: the shell is glass and owns no
58
- // dark-opaque ink. This literal is the same value `--ink` carries in the
59
- // app-surface light theme, i.e. the colour a white pill is designed to label.
60
- //
61
- // `app-surface-conventions.spec.ts` can only police the DS token file itself;
62
- // its doc says consumers that remap `--ink` "carry the same obligation".
63
- // Routing every consumer through this mixin is how that obligation is met.
64
- --on-ink: oklch(18% 0.005 250deg);
65
-
66
- // `--ink-inverse` carries the SAME obligation as `--on-ink` and was missed.
67
- //
68
- // The app-surface family defines it once, as "text on dark / gradient fills" — near-white, which
69
- // is correct while `--ink` is near-black. This mixin flips `--ink` to the shell's WHITE label ink
70
- // and updated `--on-ink` accordingly, but left `--ink-inverse` at its near-white resting value.
71
- // Every `background: var(--ink); color: var(--ink-inverse)` pair inside an embedded app therefore
72
- // became WHITE ON WHITE at a contrast ratio of about 1:1.
73
- //
74
- // That is not hypothetical: it is what made `[data-tooltip]` (the CSS tooltip behind every
75
- // `fly-icon-button`'s `tooltipKey`) invisible across the board editor — measured live at
76
- // background rgb(255,255,255) with colour oklch(0.99 0 0). The same pair is used by the button,
77
- // icon-button, checkbox and card components, so this was never a Boards-only bug.
78
- //
79
- // Pinned to `--on-ink` rather than restated, so the two counter-inks cannot drift apart again.
80
- --ink-inverse: var(--on-ink);
81
- }
1
+ // ─── Shell-embed bridge — app-surface tokens re-tinted onto shell glass ──────
2
+ // MIXIN ONLY. This partial emits no CSS on import; it exists so the mapping
3
+ // below lives in ONE place instead of being retyped per feature app.
4
+ //
5
+ // WHY IT IS NEEDED
6
+ // The DS carries two token families on purpose (see `_app-surface-tokens.scss`'s
7
+ // header). `--ink-*`/`--bg-*`/`--line-*` dress BUSINESS-APP CONTENT: an opaque
8
+ // reading surface, dark ink on white in light mode. `--label-*`/`--surface-*`
9
+ // dress SHELL CHROME: white ink on translucent glass over the user's wallpaper.
10
+ //
11
+ // A desktop-shell feature app renders inside a glass window, so its chrome is
12
+ // necessarily the second family — but the moment it mounts a component from the
13
+ // `fly-*` app-surface kit (or `@flyos/design-system-board`), that component
14
+ // themes itself from the FIRST family and paints an opaque white slab with
15
+ // near-black ink. One region, two families: the app's own header ink is white,
16
+ // the slab beneath it is white, and the header goes invisible.
17
+ //
18
+ // That is not hypothetical. It shipped in canvas-boards and was measured live:
19
+ // `.cbe__export-btn` computed `color: rgb(255,255,255)` sitting on a board whose
20
+ // `--_surface` resolved to `oklch(100% 0 0deg)`. `core/theme/feature-app-surface-tokens.ts`
21
+ // documents the same class of trap ("a dark-mode-only review passes while light
22
+ // mode renders a white slab") — and note the failure is LIGHT-mode-only, because
23
+ // in dark mode both families happen to agree on light-ink-on-dark.
24
+ //
25
+ // THE FIX is the seam the tokens file already names: an app that embeds in the
26
+ // shell re-tints the content family onto glass. help-center (`.hc-shell`) and
27
+ // dashboard-app hand-rolled identical copies of this map before it lived here.
28
+ //
29
+ // ALIASES ONLY — every value is another token, never a literal, so the whole map
30
+ // follows the shell's theme automatically. The ONE exception is `--on-ink`, and
31
+ // its reason is written at the declaration.
32
+ @mixin app-surface-on-glass {
33
+ // Surfaces: the window chrome supplies the material, so the app's own page
34
+ // background is nothing at all; cards/tracks are lifts ON that plate.
35
+ --bg: transparent;
36
+ --bg-2: var(--surface-card);
37
+ --bg-3: var(--fill-tertiary);
38
+ --bg-hover: var(--surface-active);
39
+
40
+ // Hairlines.
41
+ --line: var(--separator);
42
+ --line-2: var(--surface-border);
43
+ --line-3: var(--separator);
44
+
45
+ // Ink — opaque label tokens, never a surface token. Aliasing a translucent
46
+ // surface onto an ink slot is what turns a control into an empty coloured
47
+ // square (see the note in help-center.component.scss).
48
+ --ink: var(--label-primary);
49
+ --ink-2: var(--label-secondary);
50
+ --ink-3: var(--label-secondary);
51
+ --ink-4: var(--label-tertiary);
52
+
53
+ // CONTRACT (`_app-surface-tokens.scss`): anything that redefines `--ink` MUST
54
+ // redefine `--on-ink`, and it must be OPAQUE. `--on-ink` labels a fill of
55
+ // `--ink` itself — the primary button. Above we pin `--ink` to the shell's
56
+ // white label ink in BOTH themes, so its counter-ink is a fixed DARK value in
57
+ // both. It cannot alias a shell token: the shell is glass and owns no
58
+ // dark-opaque ink. This literal is the same value `--ink` carries in the
59
+ // app-surface light theme, i.e. the colour a white pill is designed to label.
60
+ //
61
+ // `app-surface-conventions.spec.ts` can only police the DS token file itself;
62
+ // its doc says consumers that remap `--ink` "carry the same obligation".
63
+ // Routing every consumer through this mixin is how that obligation is met.
64
+ --on-ink: oklch(18% 0.005 250deg);
65
+
66
+ // `--ink-inverse` carries the SAME obligation as `--on-ink` and was missed.
67
+ //
68
+ // The app-surface family defines it once, as "text on dark / gradient fills" — near-white, which
69
+ // is correct while `--ink` is near-black. This mixin flips `--ink` to the shell's WHITE label ink
70
+ // and updated `--on-ink` accordingly, but left `--ink-inverse` at its near-white resting value.
71
+ // Every `background: var(--ink); color: var(--ink-inverse)` pair inside an embedded app therefore
72
+ // became WHITE ON WHITE at a contrast ratio of about 1:1.
73
+ //
74
+ // That is not hypothetical: it is what made `[data-tooltip]` (the CSS tooltip behind every
75
+ // `fly-icon-button`'s `tooltipKey`) invisible across the board editor — measured live at
76
+ // background rgb(255,255,255) with colour oklch(0.99 0 0). The same pair is used by the button,
77
+ // icon-button, checkbox and card components, so this was never a Boards-only bug.
78
+ //
79
+ // Pinned to `--on-ink` rather than restated, so the two counter-inks cannot drift apart again.
80
+ --ink-inverse: var(--on-ink);
81
+ }
@@ -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
+ // 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
+ }