figspec

Unofficial static Figma frame/file viewer available as HTML CustomElement

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
import { attr, className, el } from "../../dom";
import { compute, Signal } from "../../signal";

export const styles = /* css */ `
  .ii-list {
    padding: 0;
    margin: 0;
    user-select: text;
  }

  .ii-label {
    padding: 0;
    margin: 0;
    margin-bottom: var(--spacing_-5);
    font-size: calc(var(--font-size) * 0.8);
    font-weight: bold;

    color: var(--subtle-fg);
  }

  .ii-content {
    padding: 0;
    margin: 0;
    margin-bottom: var(--spacing_3);
    font-size: var(--font-size);
    font-weight: normal;

    color: var(--fg);
  }
`;

type Children = NonNullable<Parameters<typeof el>[2]>;

interface Item {
  label: Children[number];

  content: Children;
}

export function infoItems(
  items: readonly (Item | Signal<Item | null> | null)[],
): HTMLElement {
  return el(
    "dl",
    [className("ii-list")],
    items
      .map((item) => {
        if (!item) {
          return [];
        }

        if (item instanceof Signal) {
          return [map(label, item), map(content, item)];
        }

        return [label(item), content(item)];
      })
      .flat(),
  );
}

function map<T, P>(f: (v: T) => P, s: Signal<T | null>): Signal<P | null> {
  return compute(() => {
    const v = s.get();
    if (v === null) {
      return null;
    }

    return f(v);
  });
}

function label(item: Item): HTMLElement {
  return el(
    "dt",
    [className("ii-label")],
    [item.label, el("span", [attr("aria-hidden", "true")], [":"])],
  );
}

function content(item: Item): HTMLElement {
  return el("dd", [className("ii-content")], item.content);
}