@memberjunction/react-runtime 5.51.0 → 6.1.0-edge.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/.turbo/turbo-build.log +26 -18
- package/CHANGELOG.md +35 -0
- package/LICENSE +7 -0
- package/dist/324.runtime.umd.js +12 -12
- package/dist/{490.runtime.umd.js → 456.runtime.umd.js} +40 -40
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime.umd.js +940 -286
- package/dist/utilities/component-styles.d.ts +2 -1
- package/dist/utilities/component-styles.d.ts.map +1 -1
- package/dist/utilities/component-styles.js +79 -0
- package/dist/utilities/component-styles.js.map +1 -1
- package/package.json +17 -17
- package/src/__tests__/component-styles.test.ts +252 -0
- package/src/index.ts +2 -1
- package/src/utilities/component-styles.ts +130 -2
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module @memberjunction/react-runtime/utilities
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { ComponentStyles } from '@memberjunction/interactive-component-types';
|
|
6
|
+
import { ComponentStyles, StyleOverrides } from '@memberjunction/interactive-component-types';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Creates the default component styles for Skip components
|
|
@@ -27,17 +27,26 @@ export function SetupStyles(): ComponentStyles {
|
|
|
27
27
|
// Status colors
|
|
28
28
|
success: '#10B981',
|
|
29
29
|
successLight: '#D1FAE5',
|
|
30
|
+
successText: '#047857',
|
|
31
|
+
successBorder: '#b7eb8f',
|
|
30
32
|
warning: '#F59E0B',
|
|
31
33
|
warningLight: '#FEF3C7',
|
|
34
|
+
warningText: '#8c6c00',
|
|
35
|
+
warningBorder: '#ffe58f',
|
|
32
36
|
error: '#EF4444',
|
|
33
37
|
errorLight: '#FEE2E2',
|
|
38
|
+
errorText: '#B91C1C',
|
|
39
|
+
errorBorder: '#FECACA',
|
|
34
40
|
info: '#3B82F6',
|
|
35
41
|
infoLight: '#DBEAFE',
|
|
36
|
-
|
|
42
|
+
infoText: '#1D4ED8',
|
|
43
|
+
infoBorder: '#91d5ff',
|
|
44
|
+
|
|
37
45
|
// Base colors
|
|
38
46
|
background: '#FFFFFF',
|
|
39
47
|
surface: '#F8FAFC',
|
|
40
48
|
surfaceHover: '#F1F5F9',
|
|
49
|
+
overlay: 'rgba(0, 0, 0, 0.5)', // Modal scrim
|
|
41
50
|
|
|
42
51
|
// Text colors with better contrast
|
|
43
52
|
text: '#1E293B',
|
|
@@ -125,6 +134,18 @@ export function SetupStyles(): ComponentStyles {
|
|
|
125
134
|
'#2196F3', '#4CAF50', '#FF9800', '#E91E63', '#9C27B0',
|
|
126
135
|
'#00BCD4', '#F44336', '#8BC34A', '#FF5722', '#3F51B5',
|
|
127
136
|
],
|
|
137
|
+
// Default sequential (single-hue) intensity ramp, light-to-dark, for heatmaps
|
|
138
|
+
// and density shading. Overridden per-theme from `--mj-viz-seq-*`.
|
|
139
|
+
sequentialScale: [
|
|
140
|
+
'#E3F2FD', '#BBDEFB', '#90CAF9', '#42A5F5', '#2196F3', '#1976D2', '#0D47A1',
|
|
141
|
+
],
|
|
142
|
+
// Default diverging ramp for measures with a meaningful midpoint.
|
|
143
|
+
// Overridden per-theme from `--mj-viz-div-*`.
|
|
144
|
+
divergingScale: {
|
|
145
|
+
low: '#F44336',
|
|
146
|
+
mid: '#EEEEEE',
|
|
147
|
+
high: '#4CAF50',
|
|
148
|
+
},
|
|
128
149
|
}
|
|
129
150
|
}
|
|
130
151
|
|
|
@@ -143,19 +164,31 @@ const THEME_COLOR_TOKEN_MAP: Record<string, string> = {
|
|
|
143
164
|
primaryHover: '--mj-brand-primary-hover',
|
|
144
165
|
primaryActive: '--mj-brand-primary-active',
|
|
145
166
|
primaryLight: '--mj-brand-primary-light',
|
|
167
|
+
// Secondary
|
|
168
|
+
secondary: '--mj-brand-secondary',
|
|
169
|
+
secondaryHover: '--mj-brand-secondary-hover',
|
|
146
170
|
// Status
|
|
147
171
|
success: '--mj-status-success',
|
|
148
172
|
successLight: '--mj-status-success-bg',
|
|
173
|
+
successText: '--mj-status-success-text',
|
|
174
|
+
successBorder: '--mj-status-success-border',
|
|
149
175
|
warning: '--mj-status-warning',
|
|
150
176
|
warningLight: '--mj-status-warning-bg',
|
|
177
|
+
warningText: '--mj-status-warning-text',
|
|
178
|
+
warningBorder: '--mj-status-warning-border',
|
|
151
179
|
error: '--mj-status-error',
|
|
152
180
|
errorLight: '--mj-status-error-bg',
|
|
181
|
+
errorText: '--mj-status-error-text',
|
|
182
|
+
errorBorder: '--mj-status-error-border',
|
|
153
183
|
info: '--mj-status-info',
|
|
154
184
|
infoLight: '--mj-status-info-bg',
|
|
185
|
+
infoText: '--mj-status-info-text',
|
|
186
|
+
infoBorder: '--mj-status-info-border',
|
|
155
187
|
// Surfaces (MJ: page = tinted, surface = elevated/white in light mode)
|
|
156
188
|
background: '--mj-bg-page',
|
|
157
189
|
surface: '--mj-bg-surface',
|
|
158
190
|
surfaceHover: '--mj-bg-surface-hover',
|
|
191
|
+
overlay: '--mj-bg-overlay',
|
|
159
192
|
// Text
|
|
160
193
|
text: '--mj-text-primary',
|
|
161
194
|
textSecondary: '--mj-text-secondary',
|
|
@@ -173,6 +206,9 @@ const THEME_COLOR_TOKEN_MAP: Record<string, string> = {
|
|
|
173
206
|
/** Number of `--mj-viz-N` categorical tokens the bridge probes for `chartPalette`. */
|
|
174
207
|
const VIZ_TOKEN_COUNT = 10;
|
|
175
208
|
|
|
209
|
+
/** Number of `--mj-viz-seq-N` tokens the bridge probes for `sequentialScale`. */
|
|
210
|
+
const VIZ_SEQ_TOKEN_COUNT = 7;
|
|
211
|
+
|
|
176
212
|
/**
|
|
177
213
|
* Reads the live MJ theme (`--mj-*` custom properties on the document root) and
|
|
178
214
|
* layers it over `SetupStyles()`, producing a `ComponentStyles` that follows the
|
|
@@ -216,5 +252,97 @@ export function BuildStylesFromTheme(root?: Element): ComponentStyles {
|
|
|
216
252
|
base.chartPalette = palette;
|
|
217
253
|
}
|
|
218
254
|
|
|
255
|
+
const sequential: string[] = [];
|
|
256
|
+
for (let i = 1; i <= VIZ_SEQ_TOKEN_COUNT; i++) {
|
|
257
|
+
const value = read(`--mj-viz-seq-${i}`);
|
|
258
|
+
if (value) {
|
|
259
|
+
sequential.push(value);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// A ramp needs at least two stops to interpolate; a single resolved token is
|
|
263
|
+
// treated as an incomplete theme and left on the default.
|
|
264
|
+
if (sequential.length > 1) {
|
|
265
|
+
base.sequentialScale = sequential;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Endpoints are required for a diverging scale to mean anything; `mid` is
|
|
269
|
+
// optional, so only the low/high pair gates the swap.
|
|
270
|
+
const divLow = read('--mj-viz-div-low');
|
|
271
|
+
const divHigh = read('--mj-viz-div-high');
|
|
272
|
+
if (divLow && divHigh) {
|
|
273
|
+
const divMid = read('--mj-viz-div-mid');
|
|
274
|
+
base.divergingScale = divMid ? { low: divLow, mid: divMid, high: divHigh } : { low: divLow, high: divHigh };
|
|
275
|
+
}
|
|
276
|
+
|
|
219
277
|
return base;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** Multipliers applied to the whole `fontSize` ladder per `StyleOverrides.fontScale`. */
|
|
281
|
+
const FONT_SCALE_FACTOR: Record<string, number> = { small: 0.875, large: 1.25 };
|
|
282
|
+
|
|
283
|
+
/** Smallest px size the scale may produce, so `small` cannot render text illegible. */
|
|
284
|
+
const MIN_FONT_SIZE_PX = 10;
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Rescales every px value in a `fontSize` token map, leaving anything not expressed
|
|
288
|
+
* in whole px (rem, em, clamp(), a keyword) untouched rather than guessing at it.
|
|
289
|
+
*/
|
|
290
|
+
function scaleFontSizes(fontSize: Record<string, string | undefined>, factor: number): Record<string, string | undefined> {
|
|
291
|
+
const scaled: Record<string, string | undefined> = {};
|
|
292
|
+
for (const [key, value] of Object.entries(fontSize)) {
|
|
293
|
+
const px = typeof value === 'string' ? /^\s*(\d+(?:\.\d+)?)px\s*$/.exec(value) : null;
|
|
294
|
+
scaled[key] = px
|
|
295
|
+
? `${Math.max(MIN_FONT_SIZE_PX, Math.round(parseFloat(px[1]) * factor))}px`
|
|
296
|
+
: value;
|
|
297
|
+
}
|
|
298
|
+
return scaled;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Layers explicitly user-requested styling (`ComponentSpec.styleOverrides`) over
|
|
303
|
+
* theme-resolved styles, producing the `styles` a component actually receives.
|
|
304
|
+
*
|
|
305
|
+
* This is what lets "make the charts blue" be honored without a color literal ever
|
|
306
|
+
* entering generated code: the request is carried as spec data and resolved here,
|
|
307
|
+
* above the org theme, so the component keeps reading `styles.chartPalette` and
|
|
308
|
+
* friends. Of the color slots only visualization ones are merged — the override
|
|
309
|
+
* contract deliberately has no background/text/border slots, since those cannot be
|
|
310
|
+
* flipped for dark mode without derived per-mode variants.
|
|
311
|
+
*
|
|
312
|
+
* `fontScale` is the one non-color slot, and it rescales the `typography.fontSize`
|
|
313
|
+
* ladder in place. Doing it here rather than in the generator is what makes a type
|
|
314
|
+
* scale hold: every token moves at once, so text inside registry components and
|
|
315
|
+
* third-party libraries scales along with the generated markup.
|
|
316
|
+
*
|
|
317
|
+
* Returns `base` unchanged when there are no overrides, and never mutates `base`.
|
|
318
|
+
*
|
|
319
|
+
* @param base theme-resolved styles (from `BuildStylesFromTheme()` or `SetupStyles()`)
|
|
320
|
+
* @param overrides the spec's `styleOverrides`, if any
|
|
321
|
+
*/
|
|
322
|
+
export function ApplyStyleOverrides<T extends Partial<ComponentStyles>>(base: T, overrides?: StyleOverrides): T {
|
|
323
|
+
if (!overrides) {
|
|
324
|
+
return base;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const hasChartPalette = Array.isArray(overrides.chartPalette) && overrides.chartPalette.length > 0;
|
|
328
|
+
// A ramp needs at least two stops to interpolate between.
|
|
329
|
+
const hasSequential = Array.isArray(overrides.sequentialScale) && overrides.sequentialScale.length > 1;
|
|
330
|
+
const hasDiverging = !!overrides.divergingScale?.low && !!overrides.divergingScale?.high;
|
|
331
|
+
// 'normal' — and any unrecognized value — leaves the ladder alone.
|
|
332
|
+
const fontFactor = overrides.fontScale ? FONT_SCALE_FACTOR[overrides.fontScale] : undefined;
|
|
333
|
+
const hasFontScale = !!fontFactor && !!base.typography?.fontSize;
|
|
334
|
+
|
|
335
|
+
if (!hasChartPalette && !hasSequential && !hasDiverging && !hasFontScale) {
|
|
336
|
+
return base;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return {
|
|
340
|
+
...base,
|
|
341
|
+
...(hasChartPalette ? { chartPalette: overrides.chartPalette } : {}),
|
|
342
|
+
...(hasSequential ? { sequentialScale: overrides.sequentialScale } : {}),
|
|
343
|
+
...(hasDiverging ? { divergingScale: overrides.divergingScale } : {}),
|
|
344
|
+
...(hasFontScale
|
|
345
|
+
? { typography: { ...base.typography!, fontSize: scaleFontSizes(base.typography!.fontSize, fontFactor!) } }
|
|
346
|
+
: {}),
|
|
347
|
+
};
|
|
220
348
|
}
|