@ankhorage/surface 3.1.3 → 3.2.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/CHANGELOG.md +6 -0
- package/dist/components/navigation/helpers.d.ts.map +1 -1
- package/dist/components/navigation/helpers.js +16 -8
- package/dist/components/navigation/helpers.js.map +1 -1
- package/dist/internal/resolvers/resolveInteractiveColors.d.ts.map +1 -1
- package/dist/internal/resolvers/resolveInteractiveColors.js +19 -13
- package/dist/internal/resolvers/resolveInteractiveColors.js.map +1 -1
- package/dist/internal/resolvers/resolveSelectionControlColors.d.ts.map +1 -1
- package/dist/internal/resolvers/resolveSelectionControlColors.js +19 -10
- package/dist/internal/resolvers/resolveSelectionControlColors.js.map +1 -1
- package/dist/theme/colorEngine.d.ts +4 -3
- package/dist/theme/colorEngine.d.ts.map +1 -1
- package/dist/theme/colorEngine.js +23 -122
- package/dist/theme/colorEngine.js.map +1 -1
- package/dist/theme/createSurfaceColorDiagnosticCollector.d.ts +14 -0
- package/dist/theme/createSurfaceColorDiagnosticCollector.d.ts.map +1 -0
- package/dist/theme/createSurfaceColorDiagnosticCollector.js +53 -0
- package/dist/theme/createSurfaceColorDiagnosticCollector.js.map +1 -0
- package/dist/theme/createSurfaceSemanticPolicy.d.ts +30 -0
- package/dist/theme/createSurfaceSemanticPolicy.d.ts.map +1 -0
- package/dist/theme/createSurfaceSemanticPolicy.js +118 -0
- package/dist/theme/createSurfaceSemanticPolicy.js.map +1 -0
- package/dist/theme/createTheme.d.ts.map +1 -1
- package/dist/theme/createTheme.js +2 -1
- package/dist/theme/createTheme.js.map +1 -1
- package/dist/theme/defaultTokens.d.ts +1 -1
- package/dist/theme/defaultTokens.d.ts.map +1 -1
- package/dist/theme/defaultTokens.js.map +1 -1
- package/dist/theme/resolveGlobalTokens.d.ts +1 -1
- package/dist/theme/resolveGlobalTokens.d.ts.map +1 -1
- package/dist/theme/resolveGlobalTokens.js.map +1 -1
- package/dist/theme/resolveRoleSemantics.d.ts +19 -0
- package/dist/theme/resolveRoleSemantics.d.ts.map +1 -0
- package/dist/theme/resolveRoleSemantics.js +29 -0
- package/dist/theme/resolveRoleSemantics.js.map +1 -0
- package/dist/theme/resolveSurfaceSemanticModel.d.ts +16 -0
- package/dist/theme/resolveSurfaceSemanticModel.d.ts.map +1 -0
- package/dist/theme/resolveSurfaceSemanticModel.js +128 -0
- package/dist/theme/resolveSurfaceSemanticModel.js.map +1 -0
- package/dist/theme/surfaceColorPolicy.d.ts +8 -0
- package/dist/theme/surfaceColorPolicy.d.ts.map +1 -0
- package/dist/theme/surfaceColorPolicy.js +8 -0
- package/dist/theme/surfaceColorPolicy.js.map +1 -0
- package/dist/theme/types.d.ts +52 -1
- package/dist/theme/types.d.ts.map +1 -1
- package/dist/theme/types.js.map +1 -1
- package/package.json +1 -1
- package/src/components/navigation/helpers.test.ts +4 -4
- package/src/components/navigation/helpers.ts +17 -8
- package/src/index.test.ts +12 -0
- package/src/internal/resolvers/resolveInteractiveColors.test.ts +1 -0
- package/src/internal/resolvers/resolveInteractiveColors.ts +19 -13
- package/src/internal/resolvers/resolveSelectionControlColors.test.ts +3 -2
- package/src/internal/resolvers/resolveSelectionControlColors.ts +19 -10
- package/src/primitives/icon/PortableIcon.web.test.tsx +2 -7
- package/src/surfaceColor.test.ts +8 -10
- package/src/theme/colorEngine.test.ts +85 -34
- package/src/theme/colorEngine.ts +28 -147
- package/src/theme/createSurfaceColorDiagnosticCollector.ts +91 -0
- package/src/theme/createSurfaceSemanticPolicy.ts +174 -0
- package/src/theme/createTheme.ts +2 -1
- package/src/theme/defaultTokens.ts +4 -1
- package/src/theme/resolveGlobalTokens.ts +4 -1
- package/src/theme/resolveRoleSemantics.ts +96 -0
- package/src/theme/resolveSurfaceSemanticModel.ts +230 -0
- package/src/theme/surfaceColorPolicy.ts +7 -0
- package/src/theme/types.ts +65 -1
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ColorSelectionTarget,
|
|
3
|
+
ColorSwatch,
|
|
4
|
+
GeneratedThemeModeColors,
|
|
5
|
+
GeneratedThemeSwatches,
|
|
6
|
+
HexColor,
|
|
7
|
+
SemanticColorReferenceMap,
|
|
8
|
+
SemanticColorToken,
|
|
9
|
+
ThemeColorMode,
|
|
10
|
+
} from '@ankhorage/color-theory';
|
|
11
|
+
import { createDefaultSemanticStatusSwatches } from '@ankhorage/color-theory';
|
|
12
|
+
|
|
13
|
+
import { createSurfaceColorDiagnosticCollector } from './createSurfaceColorDiagnosticCollector';
|
|
14
|
+
import { createSurfaceSemanticPolicy } from './createSurfaceSemanticPolicy';
|
|
15
|
+
import { resolveRoleSemantics } from './resolveRoleSemantics';
|
|
16
|
+
import type {
|
|
17
|
+
BorderSemantics,
|
|
18
|
+
ContentSemantics,
|
|
19
|
+
RoleSemantics,
|
|
20
|
+
SurfaceColorDiagnostics,
|
|
21
|
+
ThemeSemantics,
|
|
22
|
+
} from './types';
|
|
23
|
+
|
|
24
|
+
type ResolvedSemanticColors = Record<SemanticColorToken, HexColor>;
|
|
25
|
+
|
|
26
|
+
interface SemanticResolutionContext {
|
|
27
|
+
collector: ReturnType<typeof createSurfaceColorDiagnosticCollector>;
|
|
28
|
+
generated: GeneratedThemeModeColors;
|
|
29
|
+
isDark: boolean;
|
|
30
|
+
mode: ThemeColorMode;
|
|
31
|
+
neutralSwatch: ColorSwatch;
|
|
32
|
+
policy: ReturnType<typeof createSurfaceSemanticPolicy>;
|
|
33
|
+
quaternarySwatch: ColorSwatch;
|
|
34
|
+
references: SemanticColorReferenceMap;
|
|
35
|
+
resolved: ResolvedSemanticColors;
|
|
36
|
+
secondarySwatch: ColorSwatch;
|
|
37
|
+
statusSwatches: ReturnType<typeof createDefaultSemanticStatusSwatches>;
|
|
38
|
+
swatches: GeneratedThemeSwatches;
|
|
39
|
+
tertiarySwatch: ColorSwatch;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface ResolveSurfaceSemanticModelInput {
|
|
43
|
+
generated: GeneratedThemeModeColors;
|
|
44
|
+
mode: ThemeColorMode;
|
|
45
|
+
references: SemanticColorReferenceMap;
|
|
46
|
+
resolved: ResolvedSemanticColors;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Resolve the complete Surface-owned semantic model from canonical Color Theory output. */
|
|
50
|
+
export function resolveSurfaceSemanticModel(input: ResolveSurfaceSemanticModelInput): {
|
|
51
|
+
semantics: ThemeSemantics;
|
|
52
|
+
colorDiagnostics: SurfaceColorDiagnostics;
|
|
53
|
+
} {
|
|
54
|
+
const context = createResolutionContext(input);
|
|
55
|
+
const roles = resolveSemanticRoles(context);
|
|
56
|
+
const inverseSurface = context.isDark ? context.neutralSwatch[50] : context.neutralSwatch[900];
|
|
57
|
+
const inverseContent = context.isDark ? context.neutralSwatch[900] : context.neutralSwatch[50];
|
|
58
|
+
const neutral = context.policy.buildNeutral(context.neutralSwatch);
|
|
59
|
+
const surface = context.policy.buildSurface(inverseSurface);
|
|
60
|
+
const content = resolveContentSemantics(context, neutral.textSubtle, inverseContent);
|
|
61
|
+
const border = resolveBorderSemantics(context, roles.brand.outline);
|
|
62
|
+
context.policy.measureContent(content, surface);
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
semantics: {
|
|
66
|
+
neutral,
|
|
67
|
+
brand: roles.brand,
|
|
68
|
+
secondary: roles.secondary,
|
|
69
|
+
accent: roles.accent,
|
|
70
|
+
highlight: roles.highlight,
|
|
71
|
+
danger: roles.danger,
|
|
72
|
+
success: roles.success,
|
|
73
|
+
warning: roles.warning,
|
|
74
|
+
error: roles.danger,
|
|
75
|
+
info: roles.info,
|
|
76
|
+
surface,
|
|
77
|
+
content,
|
|
78
|
+
border,
|
|
79
|
+
selection: {
|
|
80
|
+
background: roles.brand.softBg,
|
|
81
|
+
content: roles.brand.onSoftText,
|
|
82
|
+
border: border.focus,
|
|
83
|
+
},
|
|
84
|
+
action: { primary: roles.brand, neutral: roles.neutralAction, danger: roles.danger },
|
|
85
|
+
},
|
|
86
|
+
colorDiagnostics: {
|
|
87
|
+
mode: context.mode,
|
|
88
|
+
generated: context.generated,
|
|
89
|
+
semanticReferences: context.references,
|
|
90
|
+
statusSwatches: context.statusSwatches.diagnostics,
|
|
91
|
+
selections: context.collector.selections,
|
|
92
|
+
contrasts: context.collector.contrasts,
|
|
93
|
+
surfaceSeparation: context.policy.measureSurfaceSeparation(surface),
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function createResolutionContext(
|
|
99
|
+
input: ResolveSurfaceSemanticModelInput,
|
|
100
|
+
): SemanticResolutionContext {
|
|
101
|
+
const { generated, mode, references, resolved } = input;
|
|
102
|
+
const { swatches } = generated;
|
|
103
|
+
const collector = createSurfaceColorDiagnosticCollector();
|
|
104
|
+
const isDark = mode === 'dark';
|
|
105
|
+
return {
|
|
106
|
+
collector,
|
|
107
|
+
generated,
|
|
108
|
+
isDark,
|
|
109
|
+
mode,
|
|
110
|
+
neutralSwatch: swatches.neutral,
|
|
111
|
+
policy: createSurfaceSemanticPolicy(resolved, isDark, collector),
|
|
112
|
+
quaternarySwatch: swatches.quaternary ?? swatches.primary,
|
|
113
|
+
references,
|
|
114
|
+
resolved,
|
|
115
|
+
secondarySwatch: swatches.secondary ?? swatches.primary,
|
|
116
|
+
statusSwatches: createDefaultSemanticStatusSwatches(),
|
|
117
|
+
swatches,
|
|
118
|
+
tertiarySwatch: swatches.tertiary ?? swatches.primary,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function resolveBorderSemantics(
|
|
123
|
+
context: SemanticResolutionContext,
|
|
124
|
+
focus: string,
|
|
125
|
+
): BorderSemantics {
|
|
126
|
+
const { collector, neutralSwatch, policy, resolved } = context;
|
|
127
|
+
return {
|
|
128
|
+
default: collector.selectColor(
|
|
129
|
+
'border.default',
|
|
130
|
+
neutralSwatch,
|
|
131
|
+
policy.neutralTarget(),
|
|
132
|
+
policy.adjacentSurfaceContexts,
|
|
133
|
+
policy.tiePolicy,
|
|
134
|
+
),
|
|
135
|
+
subtle: resolved.border,
|
|
136
|
+
strong: collector.selectColor(
|
|
137
|
+
'border.strong',
|
|
138
|
+
neutralSwatch,
|
|
139
|
+
policy.strongNeutralTarget(),
|
|
140
|
+
policy.adjacentSurfaceContexts,
|
|
141
|
+
policy.tiePolicy,
|
|
142
|
+
),
|
|
143
|
+
divider: resolved.divider,
|
|
144
|
+
focus,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function resolveContentSemantics(
|
|
149
|
+
context: SemanticResolutionContext,
|
|
150
|
+
subtle: string,
|
|
151
|
+
inverse: string,
|
|
152
|
+
): ContentSemantics {
|
|
153
|
+
const { collector, policy, resolved, secondarySwatch, swatches } = context;
|
|
154
|
+
return {
|
|
155
|
+
default: resolved.text,
|
|
156
|
+
muted: resolved.textMuted,
|
|
157
|
+
subtle,
|
|
158
|
+
disabled: resolved.disabledText,
|
|
159
|
+
icon: resolved.text,
|
|
160
|
+
link: collector.selectColor(
|
|
161
|
+
'content.link',
|
|
162
|
+
swatches.primary,
|
|
163
|
+
policy.textTarget(),
|
|
164
|
+
policy.textSurfaceContexts,
|
|
165
|
+
policy.tiePolicy,
|
|
166
|
+
),
|
|
167
|
+
visited: collector.selectColor(
|
|
168
|
+
'content.visited',
|
|
169
|
+
secondarySwatch,
|
|
170
|
+
policy.textTarget(),
|
|
171
|
+
policy.textSurfaceContexts,
|
|
172
|
+
policy.tiePolicy,
|
|
173
|
+
),
|
|
174
|
+
inverse,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function resolveRole(
|
|
179
|
+
context: SemanticResolutionContext,
|
|
180
|
+
id: string,
|
|
181
|
+
swatch: ColorSwatch,
|
|
182
|
+
options: { base?: HexColor; hover?: HexColor; target?: ColorSelectionTarget } = {},
|
|
183
|
+
): RoleSemantics {
|
|
184
|
+
const { collector, isDark, policy, resolved } = context;
|
|
185
|
+
return resolveRoleSemantics({
|
|
186
|
+
base: options.base,
|
|
187
|
+
disabledBg: resolved.disabledBg,
|
|
188
|
+
disabledText: resolved.disabledText,
|
|
189
|
+
hover: options.hover,
|
|
190
|
+
id,
|
|
191
|
+
isDark,
|
|
192
|
+
measureForeground: collector.measureForeground,
|
|
193
|
+
onSurfaceText: collector.selectColor(
|
|
194
|
+
`${id}.content`,
|
|
195
|
+
swatch,
|
|
196
|
+
policy.textTarget(),
|
|
197
|
+
policy.textSurfaceContexts,
|
|
198
|
+
policy.tiePolicy,
|
|
199
|
+
),
|
|
200
|
+
outline: collector.selectColor(
|
|
201
|
+
`${id}.outline`,
|
|
202
|
+
swatch,
|
|
203
|
+
options.target ?? policy.roleTarget(),
|
|
204
|
+
policy.adjacentSurfaceContexts,
|
|
205
|
+
policy.tiePolicy,
|
|
206
|
+
),
|
|
207
|
+
selectForeground: collector.selectForeground,
|
|
208
|
+
swatch,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function resolveSemanticRoles(context: SemanticResolutionContext) {
|
|
213
|
+
const { neutralSwatch, resolved, secondarySwatch, statusSwatches, swatches } = context;
|
|
214
|
+
return {
|
|
215
|
+
brand: resolveRole(context, 'brand', swatches.primary, {
|
|
216
|
+
base: resolved.action,
|
|
217
|
+
hover: resolved.actionEmphasis,
|
|
218
|
+
}),
|
|
219
|
+
secondary: resolveRole(context, 'secondary', secondarySwatch),
|
|
220
|
+
accent: resolveRole(context, 'accent', context.tertiarySwatch),
|
|
221
|
+
highlight: resolveRole(context, 'highlight', context.quaternarySwatch),
|
|
222
|
+
danger: resolveRole(context, 'danger', statusSwatches.swatches.danger),
|
|
223
|
+
success: resolveRole(context, 'success', statusSwatches.swatches.success),
|
|
224
|
+
warning: resolveRole(context, 'warning', statusSwatches.swatches.warning),
|
|
225
|
+
info: resolveRole(context, 'info', statusSwatches.swatches.info),
|
|
226
|
+
neutralAction: resolveRole(context, 'neutral', neutralSwatch, {
|
|
227
|
+
target: context.policy.neutralTarget(),
|
|
228
|
+
}),
|
|
229
|
+
};
|
|
230
|
+
}
|
package/src/theme/types.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
ColorSwatchDiagnostics,
|
|
3
|
+
ColorSwatchSelectionResult,
|
|
4
|
+
DefaultSemanticStatusRole,
|
|
5
|
+
GeneratedThemeModeColors,
|
|
6
|
+
GeneratedThemeSwatches,
|
|
7
|
+
HexColor,
|
|
8
|
+
SemanticColorReferenceMap,
|
|
9
|
+
ThemeColorMode,
|
|
10
|
+
} from '@ankhorage/color-theory';
|
|
2
11
|
import type { ThemeConfig as ContractsThemeConfig } from '@ankhorage/contracts';
|
|
3
12
|
|
|
4
13
|
export type {
|
|
@@ -26,6 +35,8 @@ export interface NeutralSemantics {
|
|
|
26
35
|
text: string;
|
|
27
36
|
textMuted: string;
|
|
28
37
|
textSubtle: string;
|
|
38
|
+
disabledBg: string;
|
|
39
|
+
disabledText: string;
|
|
29
40
|
}
|
|
30
41
|
|
|
31
42
|
export interface RoleSemantics {
|
|
@@ -36,13 +47,25 @@ export interface RoleSemantics {
|
|
|
36
47
|
softHover: string;
|
|
37
48
|
softActive: string;
|
|
38
49
|
outline: string;
|
|
50
|
+
onSurfaceText: string;
|
|
39
51
|
onSolidText: string;
|
|
52
|
+
onHoverText: string;
|
|
53
|
+
onStrongText: string;
|
|
54
|
+
onSoftText: string;
|
|
55
|
+
onSoftHoverText: string;
|
|
56
|
+
onSoftActiveText: string;
|
|
57
|
+
disabledBg: string;
|
|
58
|
+
onDisabledText: string;
|
|
40
59
|
}
|
|
41
60
|
|
|
42
61
|
export interface SurfaceSemantics {
|
|
43
62
|
default: string;
|
|
44
63
|
subtle: string;
|
|
45
64
|
raised: string;
|
|
65
|
+
sunken: string;
|
|
66
|
+
overlay: string;
|
|
67
|
+
scrim: string;
|
|
68
|
+
disabled: string;
|
|
46
69
|
inverse: string;
|
|
47
70
|
}
|
|
48
71
|
|
|
@@ -50,15 +73,27 @@ export interface ContentSemantics {
|
|
|
50
73
|
default: string;
|
|
51
74
|
muted: string;
|
|
52
75
|
subtle: string;
|
|
76
|
+
disabled: string;
|
|
77
|
+
icon: string;
|
|
78
|
+
link: string;
|
|
79
|
+
visited: string;
|
|
53
80
|
inverse: string;
|
|
54
81
|
}
|
|
55
82
|
|
|
56
83
|
export interface BorderSemantics {
|
|
57
84
|
default: string;
|
|
85
|
+
subtle: string;
|
|
58
86
|
strong: string;
|
|
87
|
+
divider: string;
|
|
59
88
|
focus: string;
|
|
60
89
|
}
|
|
61
90
|
|
|
91
|
+
export interface SelectionSemantics {
|
|
92
|
+
background: string;
|
|
93
|
+
content: string;
|
|
94
|
+
border: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
62
97
|
export interface ActionSemantics {
|
|
63
98
|
primary: RoleSemantics;
|
|
64
99
|
neutral: RoleSemantics;
|
|
@@ -79,9 +114,36 @@ export interface ThemeSemantics {
|
|
|
79
114
|
surface: SurfaceSemantics;
|
|
80
115
|
content: ContentSemantics;
|
|
81
116
|
border: BorderSemantics;
|
|
117
|
+
selection: SelectionSemantics;
|
|
82
118
|
action: ActionSemantics;
|
|
83
119
|
}
|
|
84
120
|
|
|
121
|
+
export interface SurfaceContrastDiagnostic {
|
|
122
|
+
id: string;
|
|
123
|
+
foreground: HexColor;
|
|
124
|
+
background: HexColor;
|
|
125
|
+
contrast: number;
|
|
126
|
+
minimumContrast: number;
|
|
127
|
+
passes: boolean;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** A Color Theory swatch selection together with its stable Surface purpose. */
|
|
131
|
+
export interface SurfaceColorSelectionDiagnostic {
|
|
132
|
+
id: string;
|
|
133
|
+
result: ColorSwatchSelectionResult;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Owner-produced color evidence used to explain a resolved Surface theme. */
|
|
137
|
+
export interface SurfaceColorDiagnostics {
|
|
138
|
+
mode: ThemeColorMode;
|
|
139
|
+
generated: GeneratedThemeModeColors;
|
|
140
|
+
semanticReferences: SemanticColorReferenceMap;
|
|
141
|
+
statusSwatches: Record<DefaultSemanticStatusRole, ColorSwatchDiagnostics>;
|
|
142
|
+
selections: readonly SurfaceColorSelectionDiagnostic[];
|
|
143
|
+
contrasts: readonly SurfaceContrastDiagnostic[];
|
|
144
|
+
surfaceSeparation: readonly SurfaceContrastDiagnostic[];
|
|
145
|
+
}
|
|
146
|
+
|
|
85
147
|
export type FontWeight =
|
|
86
148
|
'100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | 'bold' | 'normal';
|
|
87
149
|
|
|
@@ -106,6 +168,8 @@ export interface ThemeTokens {
|
|
|
106
168
|
};
|
|
107
169
|
swatches: GeneratedThemeSwatches;
|
|
108
170
|
semantics: ThemeSemantics;
|
|
171
|
+
/** Generated owner evidence; this is runtime output and is not persisted in ThemeConfig. */
|
|
172
|
+
colorDiagnostics: SurfaceColorDiagnostics;
|
|
109
173
|
spacing: {
|
|
110
174
|
none: 0;
|
|
111
175
|
xs: number;
|