@tamagui/themes 3.0.0-beta.1402.1 → 3.0.0-beta.1407.1

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.
@@ -22,10 +22,12 @@ var builder_exports = {};
22
22
  __export(builder_exports, {
23
23
  activeScale: () => activeScale,
24
24
  colorTokens: () => import_tokens2.colorTokens,
25
+ createPaletteThemes: () => createPaletteThemes,
25
26
  createThemes: () => import_create_theme2.createThemes,
26
27
  fromShades: () => fromShades,
27
28
  getTheme: () => getTheme,
28
29
  levels: () => levels,
30
+ paletteTokens: () => paletteTokens,
29
31
  raise: () => raise,
30
32
  ramp: () => ramp,
31
33
  rampReversed: () => rampReversed,
@@ -58,13 +60,13 @@ const shades = [
58
60
  ];
59
61
  const shadows = {
60
62
  light: {
61
- "shadow-1": "rgba(0, 0, 0, 0.04)",
62
- "shadow-2": "rgba(0, 0, 0, 0.08)",
63
- "shadow-3": "rgba(0, 0, 0, 0.12)",
64
- "shadow-4": "rgba(0, 0, 0, 0.22)",
65
- "shadow-5": "rgba(0, 0, 0, 0.33)",
66
- "shadow-6": "rgba(0, 0, 0, 0.44)",
67
- "shadow-7": "rgba(0, 0, 0, 0.6)"
63
+ "shadow-1": "rgba(0, 0, 0, 0.03)",
64
+ "shadow-2": "rgba(0, 0, 0, 0.06)",
65
+ "shadow-3": "rgba(0, 0, 0, 0.1)",
66
+ "shadow-4": "rgba(0, 0, 0, 0.17)",
67
+ "shadow-5": "rgba(0, 0, 0, 0.26)",
68
+ "shadow-6": "rgba(0, 0, 0, 0.36)",
69
+ "shadow-7": "rgba(0, 0, 0, 0.5)"
68
70
  },
69
71
  dark: {
70
72
  "shadow-1": "rgba(0, 0, 0, 0.15)",
@@ -332,15 +334,178 @@ function ramp(palette, scheme, scale) {
332
334
  function fromShades(palette, scale) {
333
335
  return Object.fromEntries(Object.entries(scale).map(([key, value]) => [key, typeof value === "number" ? `${palette}-${value}` : value]));
334
336
  }
335
- function getTheme({ recipe }) {
337
+ function channels(color) {
338
+ const value = color.trim().toLowerCase();
339
+ const hex = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/.exec(value);
340
+ if (hex) {
341
+ const digits = hex[1].length < 6 ? hex[1].split("").map((digit) => digit + digit).join("") : hex[1];
342
+ return [
343
+ 0,
344
+ 2,
345
+ 4
346
+ ].map((offset) => parseInt(digits.slice(offset, offset + 2), 16));
347
+ }
348
+ const fn = /^(rgba?|hsla?)\((.+)\)$/.exec(value);
349
+ if (!fn) return null;
350
+ const parts = fn[2].split(/[\s,/]+/).filter(Boolean);
351
+ if (parts.length < 3) return null;
352
+ const numbers = parts.slice(0, 3).map((part) => Number.parseFloat(part));
353
+ if (numbers.some((number) => Number.isNaN(number))) return null;
354
+ if (fn[1].startsWith("rgb")) return numbers;
355
+ const [hue, saturation, lightness] = [
356
+ numbers[0],
357
+ numbers[1] / 100,
358
+ numbers[2] / 100
359
+ ];
360
+ const chroma = (1 - Math.abs(2 * lightness - 1)) * saturation;
361
+ const x = chroma * (1 - Math.abs(hue / 60 % 2 - 1));
362
+ const sector = Math.floor((hue % 360 + 360) % 360 / 60);
363
+ const [r, g, b] = [
364
+ [
365
+ chroma,
366
+ x,
367
+ 0
368
+ ],
369
+ [
370
+ x,
371
+ chroma,
372
+ 0
373
+ ],
374
+ [
375
+ 0,
376
+ chroma,
377
+ x
378
+ ],
379
+ [
380
+ 0,
381
+ x,
382
+ chroma
383
+ ],
384
+ [
385
+ x,
386
+ 0,
387
+ chroma
388
+ ],
389
+ [
390
+ chroma,
391
+ 0,
392
+ x
393
+ ]
394
+ ][sector];
395
+ const m = lightness - chroma / 2;
396
+ return [
397
+ (r + m) * 255,
398
+ (g + m) * 255,
399
+ (b + m) * 255
400
+ ];
401
+ }
402
+ function luminance(color) {
403
+ const rgb = channels(color);
404
+ if (!rgb) return null;
405
+ const [r, g, b] = rgb.map((channel) => {
406
+ const unit = channel / 255;
407
+ return unit <= .03928 ? unit / 12.92 : ((unit + .055) / 1.055) ** 2.4;
408
+ });
409
+ return .2126 * r + .7152 * g + .0722 * b;
410
+ }
411
+ function contrast(a, b) {
412
+ return (Math.max(a, b) + .05) / (Math.min(a, b) + .05);
413
+ }
414
+ const MIN_TEXT_CONTRAST = 4.5;
415
+ const mirroredShade = {
416
+ 50: 950,
417
+ 100: 900,
418
+ 200: 800,
419
+ 300: 700,
420
+ 400: 600,
421
+ 500: 500,
422
+ 600: 400,
423
+ 700: 300,
424
+ 800: 200,
425
+ 900: 100,
426
+ 950: 50
427
+ };
428
+ function readable(theme, colors, bold) {
429
+ const pairs = [["accent-background", ["accent-color"]]];
430
+ if (bold) pairs.push(["background", [
431
+ "color",
432
+ "color-hover",
433
+ "color-press",
434
+ "color-focus"
435
+ ]]);
436
+ const valueOf = (token) => luminance(colors[token] ?? token);
437
+ for (const [fill, keys] of pairs) {
438
+ const fillLuminance = valueOf(theme[fill]);
439
+ if (fillLuminance === null) continue;
440
+ for (const key of keys) {
441
+ const named = theme[key];
442
+ const match = /^(.*)-(\d+)$/.exec(named);
443
+ const shade = match ? Number(match[2]) : null;
444
+ if (!match || !shade || !(shade in mirroredShade)) continue;
445
+ const mirrored = `${match[1]}-${mirroredShade[shade]}`;
446
+ const namedLuminance = valueOf(named);
447
+ const mirroredLuminance = mirrored in colors ? valueOf(mirrored) : null;
448
+ if (namedLuminance === null || mirroredLuminance === null) continue;
449
+ const namedContrast = contrast(fillLuminance, namedLuminance);
450
+ if (namedContrast >= MIN_TEXT_CONTRAST) continue;
451
+ if (contrast(fillLuminance, mirroredLuminance) > namedContrast) theme[key] = mirrored;
452
+ }
453
+ }
454
+ return theme;
455
+ }
456
+ function getTheme({ recipe, tokens: themeTokens }) {
336
457
  const resting = scales[recipe.treatment ?? "normal"][recipe.scheme][recipe.level ?? 1];
337
458
  const scale = recipe.active ? activeScale(resting) : resting;
338
459
  const schemeShadows = shadows[recipe.scheme];
339
- return {
460
+ return readable({
340
461
  ...ramp(recipe.palette, recipe.scheme, scale),
341
462
  ...fromShades(recipe.palette, scale),
342
463
  ...schemeShadows,
343
464
  "shadow-color": schemeShadows[scale["shadow-color"]]
465
+ }, themeTokens.color, recipe.treatment === "bold");
466
+ }
467
+ function paletteTokens(palettes) {
468
+ const result = {};
469
+ for (const name in palettes) {
470
+ const colors = palettes[name];
471
+ if (colors.length !== shades.length) {
472
+ throw new Error(`palette "${name}" needs ${shades.length} colors from shade 50 to 950, got ${colors.length}`);
473
+ }
474
+ shades.forEach((shade, index) => {
475
+ result[`${name}-${shade}`] = colors[index];
476
+ });
477
+ }
478
+ return result;
479
+ }
480
+ function createPaletteThemes(palettes) {
481
+ const colorTokens2 = {
482
+ ...import_tokens.colorTokens,
483
+ ...paletteTokens(palettes)
484
+ };
485
+ const surface = palettes.surface ? "surface" : "mauve";
486
+ const paletteTree = {
487
+ ...tree,
488
+ light: {
489
+ scheme: "light",
490
+ palette: surface
491
+ },
492
+ dark: {
493
+ scheme: "dark",
494
+ palette: surface
495
+ },
496
+ children: {
497
+ ...tree.children,
498
+ ...palettes.brand ? { brand: {
499
+ palette: "brand",
500
+ treatment: "bold",
501
+ children: levels()
502
+ } } : {}
503
+ }
504
+ };
505
+ const themes2 = (0, import_create_theme.createThemes)({ color: colorTokens2 }, paletteTree, { getTheme });
506
+ return {
507
+ colorTokens: colorTokens2,
508
+ themes: themes2
344
509
  };
345
510
  }
346
511
  function createLevels(max, depth) {
@@ -24,10 +24,12 @@ var builder_exports = {};
24
24
  __export(builder_exports, {
25
25
  activeScale: () => activeScale,
26
26
  colorTokens: () => import_tokens2.colorTokens,
27
+ createPaletteThemes: () => createPaletteThemes,
27
28
  createThemes: () => import_create_theme2.createThemes,
28
29
  fromShades: () => fromShades,
29
30
  getTheme: () => getTheme,
30
31
  levels: () => levels,
32
+ paletteTokens: () => paletteTokens,
31
33
  raise: () => raise,
32
34
  ramp: () => ramp,
33
35
  rampReversed: () => rampReversed,
@@ -60,13 +62,13 @@ var shades = [
60
62
  ];
61
63
  var shadows = {
62
64
  light: {
63
- "shadow-1": "rgba(0, 0, 0, 0.04)",
64
- "shadow-2": "rgba(0, 0, 0, 0.08)",
65
- "shadow-3": "rgba(0, 0, 0, 0.12)",
66
- "shadow-4": "rgba(0, 0, 0, 0.22)",
67
- "shadow-5": "rgba(0, 0, 0, 0.33)",
68
- "shadow-6": "rgba(0, 0, 0, 0.44)",
69
- "shadow-7": "rgba(0, 0, 0, 0.6)"
65
+ "shadow-1": "rgba(0, 0, 0, 0.03)",
66
+ "shadow-2": "rgba(0, 0, 0, 0.06)",
67
+ "shadow-3": "rgba(0, 0, 0, 0.1)",
68
+ "shadow-4": "rgba(0, 0, 0, 0.17)",
69
+ "shadow-5": "rgba(0, 0, 0, 0.26)",
70
+ "shadow-6": "rgba(0, 0, 0, 0.36)",
71
+ "shadow-7": "rgba(0, 0, 0, 0.5)"
70
72
  },
71
73
  dark: {
72
74
  "shadow-1": "rgba(0, 0, 0, 0.15)",
@@ -340,17 +342,226 @@ function fromShades(palette, scale) {
340
342
  return [key, typeof value === "number" ? `${palette}-${value}` : value];
341
343
  }));
342
344
  }
345
+ function channels(color) {
346
+ var value = color.trim().toLowerCase();
347
+ var hex = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/.exec(value);
348
+ if (hex) {
349
+ var digits = hex[1].length < 6 ? hex[1].split("").map(function(digit) {
350
+ return digit + digit;
351
+ }).join("") : hex[1];
352
+ return [
353
+ 0,
354
+ 2,
355
+ 4
356
+ ].map(function(offset) {
357
+ return parseInt(digits.slice(offset, offset + 2), 16);
358
+ });
359
+ }
360
+ var fn = /^(rgba?|hsla?)\((.+)\)$/.exec(value);
361
+ if (!fn) return null;
362
+ var parts = fn[2].split(/[\s,/]+/).filter(Boolean);
363
+ if (parts.length < 3) return null;
364
+ var numbers = parts.slice(0, 3).map(function(part) {
365
+ return Number.parseFloat(part);
366
+ });
367
+ if (numbers.some(function(number) {
368
+ return Number.isNaN(number);
369
+ })) return null;
370
+ if (fn[1].startsWith("rgb")) return numbers;
371
+ var [hue, saturation, lightness] = [
372
+ numbers[0],
373
+ numbers[1] / 100,
374
+ numbers[2] / 100
375
+ ];
376
+ var chroma = (1 - Math.abs(2 * lightness - 1)) * saturation;
377
+ var x = chroma * (1 - Math.abs(hue / 60 % 2 - 1));
378
+ var sector = Math.floor((hue % 360 + 360) % 360 / 60);
379
+ var [r, g, b] = [
380
+ [
381
+ chroma,
382
+ x,
383
+ 0
384
+ ],
385
+ [
386
+ x,
387
+ chroma,
388
+ 0
389
+ ],
390
+ [
391
+ 0,
392
+ chroma,
393
+ x
394
+ ],
395
+ [
396
+ 0,
397
+ x,
398
+ chroma
399
+ ],
400
+ [
401
+ x,
402
+ 0,
403
+ chroma
404
+ ],
405
+ [
406
+ chroma,
407
+ 0,
408
+ x
409
+ ]
410
+ ][sector];
411
+ var m = lightness - chroma / 2;
412
+ return [
413
+ (r + m) * 255,
414
+ (g + m) * 255,
415
+ (b + m) * 255
416
+ ];
417
+ }
418
+ function luminance(color) {
419
+ var rgb = channels(color);
420
+ if (!rgb) return null;
421
+ var [r, g, b] = rgb.map(function(channel) {
422
+ var unit = channel / 255;
423
+ return unit <= .03928 ? unit / 12.92 : Math.pow((unit + .055) / 1.055, 2.4);
424
+ });
425
+ return .2126 * r + .7152 * g + .0722 * b;
426
+ }
427
+ function contrast(a, b) {
428
+ return (Math.max(a, b) + .05) / (Math.min(a, b) + .05);
429
+ }
430
+ var MIN_TEXT_CONTRAST = 4.5;
431
+ var mirroredShade = {
432
+ 50: 950,
433
+ 100: 900,
434
+ 200: 800,
435
+ 300: 700,
436
+ 400: 600,
437
+ 500: 500,
438
+ 600: 400,
439
+ 700: 300,
440
+ 800: 200,
441
+ 900: 100,
442
+ 950: 50
443
+ };
444
+ function readable(theme, colors, bold) {
445
+ var pairs = [["accent-background", ["accent-color"]]];
446
+ if (bold) pairs.push(["background", [
447
+ "color",
448
+ "color-hover",
449
+ "color-press",
450
+ "color-focus"
451
+ ]]);
452
+ var valueOf = function(token) {
453
+ var _colors_token;
454
+ return luminance((_colors_token = colors[token]) !== null && _colors_token !== void 0 ? _colors_token : token);
455
+ };
456
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
457
+ try {
458
+ for (var _iterator = pairs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
459
+ var [fill, keys] = _step.value;
460
+ var fillLuminance = valueOf(theme[fill]);
461
+ if (fillLuminance === null) continue;
462
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = void 0;
463
+ try {
464
+ for (var _iterator1 = keys[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true) {
465
+ var key = _step1.value;
466
+ var named = theme[key];
467
+ var match = /^(.*)-(\d+)$/.exec(named);
468
+ var shade = match ? Number(match[2]) : null;
469
+ if (!match || !shade || !(shade in mirroredShade)) continue;
470
+ var mirrored = `${match[1]}-${mirroredShade[shade]}`;
471
+ var namedLuminance = valueOf(named);
472
+ var mirroredLuminance = mirrored in colors ? valueOf(mirrored) : null;
473
+ if (namedLuminance === null || mirroredLuminance === null) continue;
474
+ var namedContrast = contrast(fillLuminance, namedLuminance);
475
+ if (namedContrast >= MIN_TEXT_CONTRAST) continue;
476
+ if (contrast(fillLuminance, mirroredLuminance) > namedContrast) theme[key] = mirrored;
477
+ }
478
+ } catch (err) {
479
+ _didIteratorError1 = true;
480
+ _iteratorError1 = err;
481
+ } finally {
482
+ try {
483
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
484
+ _iterator1.return();
485
+ }
486
+ } finally {
487
+ if (_didIteratorError1) {
488
+ throw _iteratorError1;
489
+ }
490
+ }
491
+ }
492
+ }
493
+ } catch (err) {
494
+ _didIteratorError = true;
495
+ _iteratorError = err;
496
+ } finally {
497
+ try {
498
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
499
+ _iterator.return();
500
+ }
501
+ } finally {
502
+ if (_didIteratorError) {
503
+ throw _iteratorError;
504
+ }
505
+ }
506
+ }
507
+ return theme;
508
+ }
343
509
  function getTheme(param) {
344
- var { recipe } = param;
510
+ var { recipe, tokens: themeTokens } = param;
345
511
  var _recipe_treatment, _recipe_level;
346
512
  var resting = scales[(_recipe_treatment = recipe.treatment) !== null && _recipe_treatment !== void 0 ? _recipe_treatment : "normal"][recipe.scheme][(_recipe_level = recipe.level) !== null && _recipe_level !== void 0 ? _recipe_level : 1];
347
513
  var scale = recipe.active ? activeScale(resting) : resting;
348
514
  var schemeShadows = shadows[recipe.scheme];
349
- return {
515
+ return readable({
350
516
  ...ramp(recipe.palette, recipe.scheme, scale),
351
517
  ...fromShades(recipe.palette, scale),
352
518
  ...schemeShadows,
353
519
  "shadow-color": schemeShadows[scale["shadow-color"]]
520
+ }, themeTokens.color, recipe.treatment === "bold");
521
+ }
522
+ function paletteTokens(palettes) {
523
+ var _loop = function(name2) {
524
+ var colors = palettes[name2];
525
+ if (colors.length !== shades.length) {
526
+ throw new Error(`palette "${name2}" needs ${shades.length} colors from shade 50 to 950, got ${colors.length}`);
527
+ }
528
+ shades.forEach(function(shade, index) {
529
+ result[`${name2}-${shade}`] = colors[index];
530
+ });
531
+ };
532
+ var result = {};
533
+ for (var name in palettes) _loop(name);
534
+ return result;
535
+ }
536
+ function createPaletteThemes(palettes) {
537
+ var colorTokens2 = {
538
+ ...import_tokens.colorTokens,
539
+ ...paletteTokens(palettes)
540
+ };
541
+ var surface = palettes.surface ? "surface" : "mauve";
542
+ var paletteTree = {
543
+ ...tree,
544
+ light: {
545
+ scheme: "light",
546
+ palette: surface
547
+ },
548
+ dark: {
549
+ scheme: "dark",
550
+ palette: surface
551
+ },
552
+ children: {
553
+ ...tree.children,
554
+ ...palettes.brand ? { brand: {
555
+ palette: "brand",
556
+ treatment: "bold",
557
+ children: levels()
558
+ } } : {}
559
+ }
560
+ };
561
+ var themes2 = (0, import_create_theme.createThemes)({ color: colorTokens2 }, paletteTree, { getTheme });
562
+ return {
563
+ colorTokens: colorTokens2,
564
+ themes: themes2
354
565
  };
355
566
  }
356
567
  function createLevels(max, depth) {