@vettvangur/design-system 2.0.58 → 2.0.60

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.
Files changed (2) hide show
  1. package/dist/index.js +76 -43
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2417,6 +2417,42 @@ const extractVariantColors = variantNode => {
2417
2417
  }
2418
2418
  };
2419
2419
  }
2420
+ const hasVisibleFill = node => {
2421
+ const paints = Array.isArray(node?.fills) ? node.fills : null;
2422
+ if (!paints || paints.length === 0) {
2423
+ return false;
2424
+ }
2425
+ for (const paint of paints) {
2426
+ if (!paint || typeof paint !== 'object') {
2427
+ continue;
2428
+ }
2429
+ if (paint.visible === false) {
2430
+ continue;
2431
+ }
2432
+ const opacity = typeof paint.opacity === 'number' ? paint.opacity : 1;
2433
+ if (opacity <= 0) {
2434
+ continue;
2435
+ }
2436
+ const alpha = typeof paint?.color?.a === 'number' ? paint.color.a : 1;
2437
+ if (alpha * opacity <= 0) {
2438
+ continue;
2439
+ }
2440
+ const type = typeof paint.type === 'string' ? paint.type : null;
2441
+ if (type && type !== 'NONE') {
2442
+ return true;
2443
+ }
2444
+ }
2445
+ return false;
2446
+ };
2447
+ const getArea = node => {
2448
+ const box = node?.absoluteBoundingBox;
2449
+ const w = typeof box?.width === 'number' ? box.width : null;
2450
+ const h = typeof box?.height === 'number' ? box.height : null;
2451
+ if (w === null || h === null) {
2452
+ return 0;
2453
+ }
2454
+ return Math.max(0, w) * Math.max(0, h);
2455
+ };
2420
2456
  const getFillToken = node => {
2421
2457
  const fillAlias = Array.isArray(node?.boundVariables?.fills) ? node.boundVariables.fills[0] : null;
2422
2458
  const fillVar = fillAlias?.variable;
@@ -2427,14 +2463,6 @@ const extractVariantColors = variantNode => {
2427
2463
  const strokeVar = strokeAlias?.variable;
2428
2464
  return strokeVar?.resolvedType === 'COLOR' && strokeVar?.nameKebab ? strokeVar.nameKebab : null;
2429
2465
  };
2430
- const isIconNode = node => {
2431
- const name = typeof node?.name === 'string' ? node.name : '';
2432
- return /\bicon\b/i.test(name);
2433
- };
2434
- const isRootBgNode = node => {
2435
- const name = typeof node?.name === 'string' ? node.name : '';
2436
- return /\b(background|container|base|bg)\b/i.test(name);
2437
- };
2438
2466
  const root = {
2439
2467
  bg: null,
2440
2468
  border: null,
@@ -2443,16 +2471,9 @@ const extractVariantColors = variantNode => {
2443
2471
  const icon = {
2444
2472
  bg: null
2445
2473
  };
2446
-
2447
- // Prefer explicit bindings on the component root.
2448
- if (variantNode?.type !== 'TEXT') {
2449
- root.bg = getFillToken(variantNode);
2450
- root.border = getStrokeToken(variantNode);
2451
- }
2452
- let fallbackRootBg = null;
2453
- let namedRootBg = null;
2454
- let fallbackRootBorder = null;
2455
- let namedRootBorder = null;
2474
+ const fillCandidates = [];
2475
+ const strokeCandidates = [];
2476
+ const rootArea = getArea(variantNode);
2456
2477
  walkFigmaNode(variantNode, node => {
2457
2478
  if (!node || typeof node !== 'object') {
2458
2479
  return;
@@ -2467,38 +2488,50 @@ const extractVariantColors = variantNode => {
2467
2488
  if (node?.type === 'TEXT') {
2468
2489
  return;
2469
2490
  }
2470
-
2471
- // Icon background (used for icon-only background buttons).
2472
- if (!icon.bg && isIconNode(node)) {
2491
+ const area = getArea(node);
2492
+ if (hasVisibleFill(node)) {
2473
2493
  const t = getFillToken(node);
2474
2494
  if (t) {
2475
- icon.bg = t;
2495
+ fillCandidates.push({
2496
+ token: t,
2497
+ area
2498
+ });
2476
2499
  }
2477
- return;
2478
2500
  }
2479
-
2480
- // Root background/stroke candidates (exclude icon wrappers).
2481
- if (!root.bg) {
2482
- const t = getFillToken(node);
2483
- if (t) {
2484
- fallbackRootBg ??= t;
2485
- if (!namedRootBg && isRootBgNode(node)) {
2486
- namedRootBg = t;
2487
- }
2488
- }
2501
+ const s = getStrokeToken(node);
2502
+ if (s) {
2503
+ strokeCandidates.push({
2504
+ token: s,
2505
+ area
2506
+ });
2489
2507
  }
2490
- if (!root.border) {
2491
- const t = getStrokeToken(node);
2492
- if (t) {
2493
- fallbackRootBorder ??= t;
2494
- if (!namedRootBorder && isRootBgNode(node)) {
2495
- namedRootBorder = t;
2496
- }
2508
+ });
2509
+
2510
+ // Decide whether the variant has a true button background.
2511
+ // If the only filled element is much smaller than the button itself (common for arrow/icon buttons),
2512
+ // treat it as `.button__icon` background instead.
2513
+ const pickLargest = candidates => {
2514
+ let best = null;
2515
+ for (const c of candidates) {
2516
+ if (!best || c.area > best.area) {
2517
+ best = c;
2497
2518
  }
2498
2519
  }
2499
- });
2500
- root.bg ??= namedRootBg ?? fallbackRootBg;
2501
- root.border ??= namedRootBorder ?? fallbackRootBorder;
2520
+ return best;
2521
+ };
2522
+ const ROOT_BG_RATIO_MIN = 0.6;
2523
+ const bestFill = pickLargest(fillCandidates);
2524
+ const bestStroke = pickLargest(strokeCandidates);
2525
+ const fillRatio = rootArea > 0 && bestFill?.area ? bestFill.area / rootArea : 1;
2526
+ if (bestFill && fillRatio >= ROOT_BG_RATIO_MIN) {
2527
+ root.bg = bestFill.token;
2528
+ } else if (bestFill) {
2529
+ icon.bg = bestFill.token;
2530
+ }
2531
+ const strokeRatio = rootArea > 0 && bestStroke?.area ? bestStroke.area / rootArea : 1;
2532
+ if (bestStroke && strokeRatio >= ROOT_BG_RATIO_MIN) {
2533
+ root.border = bestStroke.token;
2534
+ }
2502
2535
  return {
2503
2536
  root,
2504
2537
  icon
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vettvangur/design-system",
3
- "version": "2.0.58",
3
+ "version": "2.0.60",
4
4
  "description": "",
5
5
  "access": "public",
6
6
  "type": "module",