@ids-group-ltd/ids-design-system 0.2.2 → 0.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/README.md +2 -2
- package/fesm2022/ids-group-ltd-ids-design-system.mjs +3208 -531
- package/fesm2022/ids-group-ltd-ids-design-system.mjs.map +1 -1
- package/package.json +4 -3
- package/schematics/collection.json +10 -0
- package/schematics/ng-add/index.js +47 -0
- package/schematics/ng-add/schema.json +13 -0
- package/styles/_breakpoints.scss +50 -0
- package/styles/_dropdown-overlay.scss +4 -3
- package/styles/_ds-color.scss +36 -0
- package/styles/_fonts.scss +11 -5
- package/styles/_layout-utils.scss +2 -2
- package/styles/_link.scss +3 -2
- package/styles/_overlay-motion.scss +18 -0
- package/styles/_page-grid.scss +6 -3
- package/styles/_reset.scss +6 -1
- package/styles/_scrollbar.scss +2 -1
- package/styles/_theme-activation.scss +49 -0
- package/styles/_tokens-charts.scss +18 -18
- package/styles/_tokens.scss +74 -25
- package/styles/_typography.scss +21 -21
- package/styles/ds.scss +15 -9
- package/themes/README.md +72 -58
- package/themes/{default/_palette.scss → _base-palette.scss} +67 -50
- package/themes/{default/_theme.scss → _semantic.scss} +103 -87
- package/themes/dark/_palette.scss +39 -0
- package/themes/dark/_theme.scss +122 -0
- package/themes/light/_palette.scss +34 -0
- package/themes/light/_theme.scss +15 -0
- package/types/ids-group-ltd-ids-design-system.d.ts +738 -36
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ids-group-ltd/ids-design-system",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "IDS Group Angular design system: components, tokens, themes",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://ids-ds.proto.ids-group.co.uk/",
|
|
@@ -39,5 +39,6 @@
|
|
|
39
39
|
"sideEffects": false,
|
|
40
40
|
"module": "fesm2022/ids-group-ltd-ids-design-system.mjs",
|
|
41
41
|
"typings": "types/ids-group-ltd-ids-design-system.d.ts",
|
|
42
|
-
"type": "module"
|
|
43
|
-
|
|
42
|
+
"type": "module",
|
|
43
|
+
"schematics": "./schematics/collection.json"
|
|
44
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
|
|
3
|
+
"schematics": {
|
|
4
|
+
"ng-add": {
|
|
5
|
+
"description": "Wire the IDS design system's global styles into a project.",
|
|
6
|
+
"factory": "./ng-add/index#ngAdd",
|
|
7
|
+
"schema": "./ng-add/schema.json"
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ngAdd = ngAdd;
|
|
4
|
+
const DS_IMPORT = "@use '@ids-group-ltd/ids-design-system/styles/ds';";
|
|
5
|
+
/**
|
|
6
|
+
* `ng add @ids-group-ltd/ids-design-system` — wires the design system's global
|
|
7
|
+
* styles (palette + theme + tokens + globals) into the target project's styles
|
|
8
|
+
* entry. Idempotent. Components are standalone — import them directly where used.
|
|
9
|
+
*/
|
|
10
|
+
function ngAdd(options) {
|
|
11
|
+
return (tree, context) => {
|
|
12
|
+
const angularJson = tree.read('angular.json');
|
|
13
|
+
if (!angularJson) {
|
|
14
|
+
context.logger.warn('ng-add: angular.json not found — skipping styles wiring.');
|
|
15
|
+
return tree;
|
|
16
|
+
}
|
|
17
|
+
const workspace = JSON.parse(angularJson.toString());
|
|
18
|
+
const projects = workspace.projects ?? {};
|
|
19
|
+
const projectName = options.project ??
|
|
20
|
+
workspace.defaultProject ??
|
|
21
|
+
Object.keys(projects).find((name) => projects[name].projectType === 'application');
|
|
22
|
+
const stylesEntry = projectName
|
|
23
|
+
? findStylesFile(projects[projectName])
|
|
24
|
+
: undefined;
|
|
25
|
+
if (!stylesEntry || !tree.exists(stylesEntry)) {
|
|
26
|
+
context.logger.info(`ng-add: add \`${DS_IMPORT}\` to your global styles file manually.`);
|
|
27
|
+
return tree;
|
|
28
|
+
}
|
|
29
|
+
const current = tree.read(stylesEntry).toString();
|
|
30
|
+
if (current.includes(DS_IMPORT)) {
|
|
31
|
+
context.logger.info('ng-add: design system already imported — nothing to do.');
|
|
32
|
+
return tree;
|
|
33
|
+
}
|
|
34
|
+
tree.overwrite(stylesEntry, `${DS_IMPORT}\n${current}`);
|
|
35
|
+
context.logger.info(`ng-add: imported the design system into ${stylesEntry}.`);
|
|
36
|
+
return tree;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function findStylesFile(project) {
|
|
40
|
+
const styles = project?.architect?.build?.options?.styles;
|
|
41
|
+
if (!styles?.length) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
const first = styles[0];
|
|
45
|
+
const path = typeof first === 'string' ? first : first.input;
|
|
46
|
+
return path && /\.s?css$/.test(path) ? path : undefined;
|
|
47
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/schema",
|
|
3
|
+
"$id": "IdsNgAdd",
|
|
4
|
+
"title": "IDS ng-add Options",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"project": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "Project to wire the design system into (defaults to the workspace default / first application)."
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"required": []
|
|
13
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Breakpoint scale — SINGLE source for both representations:
|
|
2
|
+
// --bp-* runtime custom properties (regular rules, JS via getComputedStyle)
|
|
3
|
+
// $bp-* compile-time Sass aliases, usable inside @media
|
|
4
|
+
//
|
|
5
|
+
// Why $bp-* exist: a custom property CANNOT be used in a @media condition
|
|
6
|
+
// (`@media (width >= var(--bp-md))` is ignored — the condition is evaluated
|
|
7
|
+
// before custom-property resolution). Sass variables resolve at build time, so
|
|
8
|
+
// they can. Use this partial wherever a media query needs the scale:
|
|
9
|
+
// @use 'breakpoints' as bp; // same dir; relative path elsewhere
|
|
10
|
+
// @include bp.up(md) { … } // width >= 768px
|
|
11
|
+
// @include bp.down(sm) { … } // width < 640px
|
|
12
|
+
// @media (width >= #{bp.$bp-lg}) { } // or read an alias directly
|
|
13
|
+
|
|
14
|
+
@use 'sass:map';
|
|
15
|
+
|
|
16
|
+
$breakpoints: (
|
|
17
|
+
'xs': 480px,
|
|
18
|
+
'sm': 640px,
|
|
19
|
+
'md': 768px,
|
|
20
|
+
'lg': 1024px,
|
|
21
|
+
'xl': 1441px, // page-grid wide-tier threshold (12 cols, caps at --col-cap-content)
|
|
22
|
+
'2xl': 1536px,
|
|
23
|
+
);
|
|
24
|
+
$bp-xs: map.get($breakpoints, 'xs');
|
|
25
|
+
$bp-sm: map.get($breakpoints, 'sm');
|
|
26
|
+
$bp-md: map.get($breakpoints, 'md');
|
|
27
|
+
$bp-lg: map.get($breakpoints, 'lg');
|
|
28
|
+
$bp-xl: map.get($breakpoints, 'xl');
|
|
29
|
+
$bp-2xl: map.get($breakpoints, '2xl');
|
|
30
|
+
|
|
31
|
+
// width >= breakpoint — mobile-first / min-width semantics.
|
|
32
|
+
@mixin up($name) {
|
|
33
|
+
@media (width >= #{map.get($breakpoints, $name)}) {
|
|
34
|
+
@content;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// width < breakpoint — max-width semantics, exclusive of the breakpoint itself.
|
|
39
|
+
@mixin down($name) {
|
|
40
|
+
@media (width < #{map.get($breakpoints, $name)}) {
|
|
41
|
+
@content;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Runtime mirror — emitted from the same map so the two never drift.
|
|
46
|
+
:root {
|
|
47
|
+
@each $name, $value in $breakpoints {
|
|
48
|
+
--bp-#{$name}: #{$value};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
.optgroup-label {
|
|
40
40
|
display: block;
|
|
41
41
|
padding: var(--space-2) var(--space-3) var(--space-1);
|
|
42
|
-
font: var(--font-weight-semibold) var(--font-size-xs)/var(--line-height-flat) var(--font-sans);
|
|
42
|
+
font: var(--font-weight-semibold) var(--font-size-xs) / var(--line-height-flat) var(--font-sans);
|
|
43
43
|
color: var(--text-tertiary);
|
|
44
44
|
text-transform: uppercase;
|
|
45
45
|
letter-spacing: var(--letter-spacing-wide);
|
|
@@ -67,11 +67,12 @@
|
|
|
67
67
|
padding: var(--space-2) var(--space-2-5);
|
|
68
68
|
border: 0;
|
|
69
69
|
background: transparent;
|
|
70
|
-
font: var(--font-weight-medium) var(--font-size-s)/var(--line-height-flat) var(--font-sans);
|
|
70
|
+
font: var(--font-weight-medium) var(--font-size-s) / var(--line-height-flat) var(--font-sans);
|
|
71
71
|
color: var(--text-primary);
|
|
72
72
|
cursor: pointer;
|
|
73
73
|
border-radius: var(--radius-sm);
|
|
74
74
|
text-align: left;
|
|
75
|
+
transition: background-color var(--duration-fast) var(--ease-standard);
|
|
75
76
|
|
|
76
77
|
.option-icon {
|
|
77
78
|
color: var(--icon-default);
|
|
@@ -98,7 +99,7 @@
|
|
|
98
99
|
|
|
99
100
|
&:focus-visible {
|
|
100
101
|
outline: none;
|
|
101
|
-
box-shadow: var(--focus-
|
|
102
|
+
box-shadow: var(--ds-control-focus-shadow);
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
&.is-selected {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Scoped accent recolour. A `ds-color="<family>"` attribute — on a zone
|
|
2
|
+
// container, on a component host, or applied via the ds.color() mixin in
|
|
3
|
+
// consumer config — flips the --accent-* pointer family to another brand/status
|
|
4
|
+
// family for its subtree. Components read --accent-* for their accent (the
|
|
5
|
+
// Phase 2 sweep), so the whole subtree recolours from this one rule. Pairs with
|
|
6
|
+
// the button/icon-button `color` input (Phase 1), which flips the same pointers
|
|
7
|
+
// per instance. With no attribute, --accent-* stays the primary family (see
|
|
8
|
+
// themes/_semantic.scss), so the default theme is unchanged.
|
|
9
|
+
|
|
10
|
+
@mixin family-vars($family) {
|
|
11
|
+
--accent: var(--#{$family});
|
|
12
|
+
--accent-hover: var(--#{$family}-hover);
|
|
13
|
+
--accent-pressed: var(--#{$family}-pressed);
|
|
14
|
+
--accent-strong: var(--#{$family}-strong);
|
|
15
|
+
--accent-subtitle: var(--#{$family}-subtitle);
|
|
16
|
+
--accent-muted: var(--#{$family}-muted);
|
|
17
|
+
--accent-muted-strong: var(--#{$family}-muted-strong);
|
|
18
|
+
--accent-on: var(--#{$family}-on);
|
|
19
|
+
--accent-focus-ring: var(--focus-ring-#{$family});
|
|
20
|
+
--accent-focus-field: var(--focus-field-#{$family});
|
|
21
|
+
--accent-surface-tint: var(--#{$family}-subtitle);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/// Recolour the DS accent for a type or scope from consumer SCSS, e.g.
|
|
25
|
+
/// `ds-switch { @include ds.color(secondary); }`.
|
|
26
|
+
@mixin color($family) {
|
|
27
|
+
@include family-vars($family);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
$families: secondary, tertiary, error, success, warning;
|
|
31
|
+
|
|
32
|
+
@each $family in $families {
|
|
33
|
+
[ds-color='#{$family}'] {
|
|
34
|
+
@include family-vars($family);
|
|
35
|
+
}
|
|
36
|
+
}
|
package/styles/_fonts.scss
CHANGED
|
@@ -1,35 +1,39 @@
|
|
|
1
1
|
// Self-hosted DS default fonts (latin subset). Consumers override --font-sans / --font-mono to swap.
|
|
2
2
|
|
|
3
3
|
@font-face {
|
|
4
|
-
font-family:
|
|
4
|
+
font-family: Mulish;
|
|
5
5
|
font-style: normal;
|
|
6
6
|
font-weight: 400;
|
|
7
7
|
font-display: swap;
|
|
8
8
|
src: url('./fonts/mulish-latin-400-normal.woff2') format('woff2');
|
|
9
9
|
}
|
|
10
|
+
|
|
10
11
|
@font-face {
|
|
11
|
-
font-family:
|
|
12
|
+
font-family: Mulish;
|
|
12
13
|
font-style: normal;
|
|
13
14
|
font-weight: 500;
|
|
14
15
|
font-display: swap;
|
|
15
16
|
src: url('./fonts/mulish-latin-500-normal.woff2') format('woff2');
|
|
16
17
|
}
|
|
18
|
+
|
|
17
19
|
@font-face {
|
|
18
|
-
font-family:
|
|
20
|
+
font-family: Mulish;
|
|
19
21
|
font-style: normal;
|
|
20
22
|
font-weight: 600;
|
|
21
23
|
font-display: swap;
|
|
22
24
|
src: url('./fonts/mulish-latin-600-normal.woff2') format('woff2');
|
|
23
25
|
}
|
|
26
|
+
|
|
24
27
|
@font-face {
|
|
25
|
-
font-family:
|
|
28
|
+
font-family: Mulish;
|
|
26
29
|
font-style: normal;
|
|
27
30
|
font-weight: 700;
|
|
28
31
|
font-display: swap;
|
|
29
32
|
src: url('./fonts/mulish-latin-700-normal.woff2') format('woff2');
|
|
30
33
|
}
|
|
34
|
+
|
|
31
35
|
@font-face {
|
|
32
|
-
font-family:
|
|
36
|
+
font-family: Mulish;
|
|
33
37
|
font-style: normal;
|
|
34
38
|
font-weight: 800;
|
|
35
39
|
font-display: swap;
|
|
@@ -43,6 +47,7 @@
|
|
|
43
47
|
font-display: swap;
|
|
44
48
|
src: url('./fonts/jetbrains-mono-latin-400-normal.woff2') format('woff2');
|
|
45
49
|
}
|
|
50
|
+
|
|
46
51
|
@font-face {
|
|
47
52
|
font-family: 'JetBrains Mono';
|
|
48
53
|
font-style: normal;
|
|
@@ -50,6 +55,7 @@
|
|
|
50
55
|
font-display: swap;
|
|
51
56
|
src: url('./fonts/jetbrains-mono-latin-500-normal.woff2') format('woff2');
|
|
52
57
|
}
|
|
58
|
+
|
|
53
59
|
@font-face {
|
|
54
60
|
font-family: 'JetBrains Mono';
|
|
55
61
|
font-style: normal;
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-4); }
|
|
6
6
|
.grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-4); }
|
|
7
7
|
|
|
8
|
-
@media (
|
|
8
|
+
@media (width <= 1100px) {
|
|
9
9
|
.grid-4 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
@media (
|
|
12
|
+
@media (width <= 820px) {
|
|
13
13
|
.grid-3, .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
14
14
|
}
|
package/styles/_link.scss
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
&:focus-visible {
|
|
32
32
|
outline: none;
|
|
33
|
-
box-shadow: var(--focus-
|
|
33
|
+
box-shadow: var(--ds-control-focus-shadow);
|
|
34
34
|
border-radius: var(--radius-sm);
|
|
35
35
|
text-decoration-color: var(--_link-color);
|
|
36
36
|
}
|
|
@@ -43,12 +43,13 @@
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
.icon {
|
|
46
|
-
color:
|
|
46
|
+
color: currentcolor;
|
|
47
47
|
flex-shrink: 0;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
&.quiet {
|
|
51
51
|
color: var(--text-secondary);
|
|
52
|
+
|
|
52
53
|
/* Pull the underline down to match the muted text — the base rule sets
|
|
53
54
|
text-decoration-color to the link color, which would leave a bright
|
|
54
55
|
underline under grey text at rest. */
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Enter/leave motion for CDK-overlay panels that carry the `ds-overlay-pane`
|
|
2
|
+
// panelClass (select, dropdown, combobox, date-picker, popover, tooltip).
|
|
3
|
+
// Animates the panel's ROOT CHILD, not the pane itself, so CDK's positioning
|
|
4
|
+
// transforms on `.cdk-overlay-pane` are left untouched. The leave variant is
|
|
5
|
+
// driven by `ds-leaving`, added by disposeWithLeave() (components/overlay-motion.ts).
|
|
6
|
+
// prefers-reduced-motion zeroes --duration-fast → instant (animationend still
|
|
7
|
+
// fires, so disposeWithLeave still tears down).
|
|
8
|
+
|
|
9
|
+
.cdk-overlay-pane.ds-overlay-pane > * {
|
|
10
|
+
animation: ds-overlay-in var(--duration-fast) var(--ease-decelerate);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@keyframes ds-overlay-in {
|
|
14
|
+
from {
|
|
15
|
+
opacity: 0;
|
|
16
|
+
transform: translateY(-4px);
|
|
17
|
+
}
|
|
18
|
+
}
|
package/styles/_page-grid.scss
CHANGED
|
@@ -27,24 +27,27 @@
|
|
|
27
27
|
// Mobile (default, <= 640px) — 4 columns
|
|
28
28
|
--page-gutter: var(--page-gutter-mobile);
|
|
29
29
|
--page-margin: var(--page-margin-mobile);
|
|
30
|
+
|
|
30
31
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
31
32
|
|
|
32
33
|
// Tablet (641-1024px) — 8 columns
|
|
33
|
-
@media (
|
|
34
|
+
@media (width >= 641px) {
|
|
34
35
|
--page-gutter: var(--page-gutter-tablet);
|
|
35
36
|
--page-margin: var(--page-margin-tablet);
|
|
37
|
+
|
|
36
38
|
grid-template-columns: repeat(8, minmax(0, 1fr));
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
// Desktop (1025-1440px) — 12 columns, fluid width
|
|
40
|
-
@media (
|
|
42
|
+
@media (width >= 1025px) {
|
|
41
43
|
--page-gutter: var(--page-gutter-desktop);
|
|
42
44
|
--page-margin: var(--page-margin-desktop);
|
|
45
|
+
|
|
43
46
|
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
// Desktop wide (>= 1441px) — 12 columns, container capped at --col-cap-content
|
|
47
|
-
@media (
|
|
50
|
+
@media (width >= 1441px) {
|
|
48
51
|
--page-gutter: var(--page-gutter-wide);
|
|
49
52
|
--page-margin: var(--page-margin-wide);
|
|
50
53
|
}
|
package/styles/_reset.scss
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
// Reset — ported from CLAUDE_DESIGN_DS/tokens.css §Base.
|
|
2
2
|
|
|
3
3
|
*, *::before, *::after { box-sizing: border-box; }
|
|
4
|
+
|
|
5
|
+
/* Opt into animating to/from intrinsic sizes (height: auto, max-content).
|
|
6
|
+
Inherited, so components can transition height:0 ↔ auto natively
|
|
7
|
+
(accordion, sidenav group) without max-height magic numbers. */
|
|
8
|
+
:root { interpolate-size: allow-keywords; }
|
|
4
9
|
html, body {
|
|
5
10
|
margin: 0;
|
|
6
11
|
font-family: var(--font-sans);
|
|
7
12
|
color: var(--text-primary);
|
|
8
13
|
background: var(--surface-canvas);
|
|
9
14
|
-webkit-font-smoothing: antialiased;
|
|
10
|
-
text-rendering:
|
|
15
|
+
text-rendering: optimizelegibility;
|
|
11
16
|
}
|
|
12
17
|
button, input, select, textarea { font-family: inherit; }
|
|
13
18
|
|
package/styles/_scrollbar.scss
CHANGED
|
@@ -9,9 +9,10 @@ html { scrollbar-width: thin; scrollbar-color: var(--scrollbar-thumb) transparen
|
|
|
9
9
|
border-radius: var(--radius-pill);
|
|
10
10
|
border: var(--space-0-5) solid transparent;
|
|
11
11
|
background-clip: padding-box;
|
|
12
|
+
transition: background-color var(--duration-fast) var(--ease-standard);
|
|
12
13
|
}
|
|
13
14
|
*::-webkit-scrollbar-thumb:hover { background: var(--scrollbar-thumb-hover); background-clip: padding-box; }
|
|
14
15
|
*::-webkit-scrollbar-thumb:active { background: var(--scrollbar-thumb-active); background-clip: padding-box; }
|
|
15
16
|
|
|
16
17
|
// Global text-selection — sourced from components-extras.css line 910.
|
|
17
|
-
::selection { background: var(--select-bg, color-mix(in srgb, var(--primary) 22%, transparent)); color: var(--text-primary); }
|
|
18
|
+
::selection { background-color: var(--select-bg-color, color-mix(in srgb, var(--primary) 22%, transparent)); color: var(--text-primary); }
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// =========================================================================
|
|
2
|
+
// Theme activation.
|
|
3
|
+
//
|
|
4
|
+
// Light is the DEFAULT — applied at bare :root, no attribute needed. Dark is
|
|
5
|
+
// OPT-IN via <html data-theme="dark">; because the dark block declares the
|
|
6
|
+
// complete token set (palette + roles + overrides), the more-specific
|
|
7
|
+
// [data-theme='dark'] selector fully replaces light when present — it is not
|
|
8
|
+
// a delta-patch.
|
|
9
|
+
//
|
|
10
|
+
// There is no automatic prefers-color-scheme switch. To follow the OS, a
|
|
11
|
+
// consumer opts in at the app root: provideDsTheme({ followSystem: true })
|
|
12
|
+
// (exported from the package; see themes/README.md).
|
|
13
|
+
//
|
|
14
|
+
// Order matters: the dark block comes LAST so it wins over the light-context
|
|
15
|
+
// overrides (brand-gray neutrals) at equal specificity.
|
|
16
|
+
// =========================================================================
|
|
17
|
+
|
|
18
|
+
@use '../themes/light/theme' as light;
|
|
19
|
+
@use '../themes/dark/theme' as dark;
|
|
20
|
+
|
|
21
|
+
:root {
|
|
22
|
+
color-scheme: light; // native UI (scrollbars, form controls) match; opts out of UA force-dark
|
|
23
|
+
|
|
24
|
+
@include light.theme;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Brand-gray neutral family — opt-in light-context switch (ds-docs tweaks panel).
|
|
28
|
+
// A light-theme feature: dark ships its own neutral ramp and wins below.
|
|
29
|
+
:root[data-neutrals='brand'] {
|
|
30
|
+
--neutral-0: var(--brand-gray-0);
|
|
31
|
+
--neutral-50: var(--brand-gray-50);
|
|
32
|
+
--neutral-100: var(--brand-gray-100);
|
|
33
|
+
--neutral-150: var(--brand-gray-150);
|
|
34
|
+
--neutral-200: var(--brand-gray-200);
|
|
35
|
+
--neutral-300: var(--brand-gray-300);
|
|
36
|
+
--neutral-400: var(--brand-gray-400);
|
|
37
|
+
--neutral-500: var(--brand-gray-500);
|
|
38
|
+
--neutral-600: var(--brand-gray-600);
|
|
39
|
+
--neutral-700: var(--brand-gray-700);
|
|
40
|
+
--neutral-800: var(--brand-gray-800);
|
|
41
|
+
--neutral-900: var(--brand-gray-900);
|
|
42
|
+
--neutral-950: var(--brand-gray-950);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
:root[data-theme='dark'] {
|
|
46
|
+
color-scheme: dark; // native UI (scrollbars, form controls) render dark to match
|
|
47
|
+
|
|
48
|
+
@include dark.theme;
|
|
49
|
+
}
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
|
|
16
16
|
:root {
|
|
17
17
|
/* CATEGORICAL (8) ----------------------------------------- */
|
|
18
|
-
--chart-cat-1: hsl(
|
|
19
|
-
--chart-cat-2: hsl(
|
|
20
|
-
--chart-cat-3: hsl(
|
|
21
|
-
--chart-cat-4: hsl(
|
|
22
|
-
--chart-cat-5: hsl(
|
|
23
|
-
--chart-cat-6: hsl(
|
|
24
|
-
--chart-cat-7: hsl(
|
|
25
|
-
--chart-cat-8: hsl(
|
|
18
|
+
--chart-cat-1: hsl(229deg 100% 59%); /* blue (primary) */
|
|
19
|
+
--chart-cat-2: hsl(165deg 72% 38%); /* teal */
|
|
20
|
+
--chart-cat-3: hsl( 24deg 95% 55%); /* orange */
|
|
21
|
+
--chart-cat-4: hsl(330deg 82% 55%); /* magenta */
|
|
22
|
+
--chart-cat-5: hsl(45deg 95% 50%); /* amber */
|
|
23
|
+
--chart-cat-6: hsl(190deg 85% 45%); /* cyan */
|
|
24
|
+
--chart-cat-7: hsl(280deg 60% 60%); /* lavender */
|
|
25
|
+
--chart-cat-8: hsl(130deg 45% 50%); /* moss */
|
|
26
26
|
|
|
27
27
|
/* SEQUENTIAL — single-hue, light → dark */
|
|
28
28
|
--chart-seq-1: var(--blue-100);
|
|
@@ -38,13 +38,13 @@
|
|
|
38
38
|
matches the reference one-for-one. Explicit HSL keeps the ramp
|
|
39
39
|
independent of palette retunes — re-skinning brand/red/green
|
|
40
40
|
should not shift the dataviz colour story. */
|
|
41
|
-
--chart-div--3: hsl(
|
|
42
|
-
--chart-div--2: hsl(
|
|
43
|
-
--chart-div--1: hsl(
|
|
44
|
-
--chart-div-0: hsl(
|
|
45
|
-
--chart-div-1: hsl(
|
|
46
|
-
--chart-div-2: hsl(
|
|
47
|
-
--chart-div-3: hsl(
|
|
41
|
+
--chart-div--3: hsl(0deg 70% 40%); /* large negative (worst) */
|
|
42
|
+
--chart-div--2: hsl(0deg 60% 58%);
|
|
43
|
+
--chart-div--1: hsl(0deg 50% 80%);
|
|
44
|
+
--chart-div-0: hsl(225deg 8% 92%); /* zero */
|
|
45
|
+
--chart-div-1: hsl(140deg 35% 80%);
|
|
46
|
+
--chart-div-2: hsl(140deg 45% 55%);
|
|
47
|
+
--chart-div-3: hsl(140deg 55% 35%); /* large positive (best) */
|
|
48
48
|
|
|
49
49
|
/* AXIS / GRID / LEGEND */
|
|
50
50
|
--chart-axis-line: var(--neutral-300);
|
|
@@ -56,10 +56,10 @@
|
|
|
56
56
|
--chart-axis-fs: var(--font-size-2xs);
|
|
57
57
|
|
|
58
58
|
/* HIGHLIGHT / HOVER */
|
|
59
|
-
--chart-hover-bg:
|
|
59
|
+
--chart-hover-bg-color: hsl(225deg 39% 7% / 4%);
|
|
60
60
|
--chart-cursor-line: var(--neutral-400);
|
|
61
|
-
--chart-tooltip-bg: var(--neutral-900);
|
|
62
|
-
--chart-tooltip-
|
|
61
|
+
--chart-tooltip-bg-color: var(--neutral-900);
|
|
62
|
+
--chart-tooltip-text-color: var(--neutral-0);
|
|
63
63
|
--chart-tooltip-border: var(--neutral-700);
|
|
64
64
|
|
|
65
65
|
/* DIMENSIONS */
|