@shipload/item-renderer 0.2.3 → 1.0.0-beta1

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 (89) hide show
  1. package/package.json +47 -49
  2. package/src/assets/stardust-base64.ts +1 -1
  3. package/src/errors.ts +14 -14
  4. package/src/fonts/index.ts +24 -24
  5. package/src/fonts/load-bun.ts +12 -12
  6. package/src/index.ts +31 -31
  7. package/src/links.ts +13 -13
  8. package/src/meta.ts +26 -26
  9. package/src/payload/base64url.ts +21 -21
  10. package/src/payload/codec.ts +19 -19
  11. package/src/primitives/category-icon.ts +88 -86
  12. package/src/primitives/compact-row.ts +32 -32
  13. package/src/primitives/divider.ts +14 -14
  14. package/src/primitives/icon-hex.ts +36 -36
  15. package/src/primitives/module-slot.ts +131 -131
  16. package/src/primitives/panel.ts +18 -18
  17. package/src/primitives/quantity-badge.ts +32 -32
  18. package/src/primitives/span-paragraph.ts +56 -56
  19. package/src/primitives/stat-bar.ts +72 -72
  20. package/src/primitives/svg.ts +16 -16
  21. package/src/primitives/text.ts +33 -33
  22. package/src/primitives/wrap.ts +19 -19
  23. package/src/render.ts +20 -20
  24. package/src/templates/_shared.ts +5 -5
  25. package/src/templates/component.ts +124 -124
  26. package/src/templates/index.ts +23 -23
  27. package/src/templates/item-cell.ts +84 -84
  28. package/src/templates/module.ts +182 -181
  29. package/src/templates/packed-entity.ts +22 -22
  30. package/src/templates/resource.ts +136 -134
  31. package/src/templates/ship-panel.ts +122 -118
  32. package/src/templates/social-card.ts +36 -36
  33. package/src/tokens/colors.ts +42 -42
  34. package/src/tokens/index.ts +6 -6
  35. package/src/tokens/spacing.ts +9 -9
  36. package/src/tokens/typography.ts +18 -18
  37. package/.claude/settings.local.json +0 -6
  38. package/.github/workflows/ci.yml +0 -14
  39. package/.gitignore +0 -6
  40. package/Makefile +0 -50
  41. package/biome.json +0 -18
  42. package/bun.lock +0 -123
  43. package/scripts/check-bundle-size.ts +0 -37
  44. package/scripts/copy-fonts.ts +0 -41
  45. package/scripts/preview.ts +0 -41
  46. package/test/__image_snapshots__/.gitkeep +0 -0
  47. package/test/__image_snapshots__/component-hull-plates.diff.png +0 -0
  48. package/test/__image_snapshots__/component-hull-plates.png +0 -0
  49. package/test/__image_snapshots__/module-engine-t1.diff.png +0 -0
  50. package/test/__image_snapshots__/module-engine-t1.png +0 -0
  51. package/test/__image_snapshots__/module-storage-t1.diff.png +0 -0
  52. package/test/__image_snapshots__/module-storage-t1.png +0 -0
  53. package/test/__image_snapshots__/packed-entity-ship-t1-only-engine.diff.png +0 -0
  54. package/test/__image_snapshots__/packed-entity-ship-t1-only-engine.png +0 -0
  55. package/test/__image_snapshots__/packed-entity-ship-t1-two-modules.diff.png +0 -0
  56. package/test/__image_snapshots__/packed-entity-ship-t1-two-modules.png +0 -0
  57. package/test/__image_snapshots__/resource-ore-t1.diff.png +0 -0
  58. package/test/__image_snapshots__/resource-ore-t1.png +0 -0
  59. package/test/__snapshots__/templates-component.test.ts.snap +0 -5
  60. package/test/__snapshots__/templates-item-cell.test.ts.snap +0 -9
  61. package/test/__snapshots__/templates-module.test.ts.snap +0 -17
  62. package/test/__snapshots__/templates-packed-entity.test.ts.snap +0 -5
  63. package/test/__snapshots__/templates-resource.test.ts.snap +0 -7
  64. package/test/base64url.test.ts +0 -33
  65. package/test/codec.test.ts +0 -34
  66. package/test/errors.test.ts +0 -24
  67. package/test/fixtures/cargo-items.ts +0 -122
  68. package/test/fonts.test.ts +0 -28
  69. package/test/links-meta.test.ts +0 -43
  70. package/test/pixel.test.ts +0 -69
  71. package/test/primitives-category-icon.test.ts +0 -86
  72. package/test/primitives-compact-row.test.ts +0 -44
  73. package/test/primitives-domain.test.ts +0 -83
  74. package/test/primitives-layout.test.ts +0 -56
  75. package/test/primitives-module-slot.test.ts +0 -88
  76. package/test/render.test.ts +0 -43
  77. package/test/sanity.test.ts +0 -6
  78. package/test/sdk-link.test.ts +0 -19
  79. package/test/snapshots/.gitkeep +0 -0
  80. package/test/svg.test.ts +0 -30
  81. package/test/templates-component.test.ts +0 -36
  82. package/test/templates-dispatch.test.ts +0 -35
  83. package/test/templates-item-cell.test.ts +0 -94
  84. package/test/templates-module.test.ts +0 -63
  85. package/test/templates-packed-entity.test.ts +0 -47
  86. package/test/templates-resource.test.ts +0 -71
  87. package/test/templates-ship-panel.test.ts +0 -91
  88. package/test/tokens.test.ts +0 -34
  89. package/tsconfig.json +0 -20
@@ -1,144 +1,144 @@
1
- import type { ResolvedItem, ResourceCategory } from "@shipload/sdk";
2
- import { formatTier, getRecipe, getStatDefinitions, categoryColors } from "@shipload/sdk";
3
- import type { CargoItem } from "../payload/codec.ts";
4
- import { panel } from "../primitives/panel.ts";
5
- import { iconHex } from "../primitives/icon-hex.ts";
6
- import { text } from "../primitives/text.ts";
7
- import { divider } from "../primitives/divider.ts";
8
- import { statBar } from "../primitives/stat-bar.ts";
9
- import { quantityBadge } from "../primitives/quantity-badge.ts";
10
- import { tokens } from "../tokens/index.ts";
11
- import { shortCode, formatMass, tierBorder } from "./_shared.ts";
1
+ import type {ResolvedItem, ResourceCategory} from '@shipload/sdk'
2
+ import {formatTier, getRecipe, getStatDefinitions, categoryColors} from '@shipload/sdk'
3
+ import type {CargoItem} from '../payload/codec.ts'
4
+ import {panel} from '../primitives/panel.ts'
5
+ import {iconHex} from '../primitives/icon-hex.ts'
6
+ import {text} from '../primitives/text.ts'
7
+ import {divider} from '../primitives/divider.ts'
8
+ import {statBar} from '../primitives/stat-bar.ts'
9
+ import {quantityBadge} from '../primitives/quantity-badge.ts'
10
+ import {tokens} from '../tokens/index.ts'
11
+ import {shortCode, formatMass, tierBorder} from './_shared.ts'
12
12
 
13
13
  export interface RenderComponentOpts {
14
- mode?: "values" | "ranges";
14
+ mode?: 'values' | 'ranges'
15
15
  }
16
16
 
17
17
  type StatRow = {
18
- label: string;
19
- abbreviation: string;
20
- value: number | null;
21
- color: string;
22
- inverted?: boolean;
23
- };
18
+ label: string
19
+ abbreviation: string
20
+ value: number | null
21
+ color: string
22
+ inverted?: boolean
23
+ }
24
24
 
25
25
  export function renderComponent(
26
- item: CargoItem,
27
- resolved: ResolvedItem,
28
- opts?: RenderComponentOpts,
26
+ item: CargoItem,
27
+ resolved: ResolvedItem,
28
+ opts?: RenderComponentOpts
29
29
  ): string {
30
- const mode = opts?.mode ?? "values";
31
- const w = tokens.spacing.panelWidth;
32
- const pad = tokens.spacing.panelPadding;
33
- const innerW = w - pad * 2;
30
+ const mode = opts?.mode ?? 'values'
31
+ const w = tokens.spacing.panelWidth
32
+ const pad = tokens.spacing.panelPadding
33
+ const innerW = w - pad * 2
34
34
 
35
- let rows: StatRow[];
36
- if (mode === "values") {
37
- rows = (resolved.stats ?? []).map((s) => ({
38
- label: s.label,
39
- abbreviation: s.abbreviation,
40
- value: s.value,
41
- color: s.color,
42
- inverted: s.inverted,
43
- }));
44
- } else {
45
- const recipe = getRecipe(resolved.itemId);
46
- rows = (recipe?.statSlots ?? []).flatMap((slot) => {
47
- const src = slot.sources[0];
48
- if (!src) return [];
49
- const input = recipe!.inputs[src.inputIndex];
50
- if (!input || !("category" in input)) return [];
51
- const category = input.category as ResourceCategory;
52
- const def = getStatDefinitions(category)[src.statIndex];
53
- if (!def) return [];
54
- return [
55
- {
56
- label: def.label,
57
- abbreviation: def.abbreviation,
58
- value: null,
59
- color: categoryColors[category],
60
- inverted: def.inverted,
61
- },
62
- ];
63
- });
64
- }
35
+ let rows: StatRow[]
36
+ if (mode === 'values') {
37
+ rows = (resolved.stats ?? []).map((s) => ({
38
+ label: s.label,
39
+ abbreviation: s.abbreviation,
40
+ value: s.value,
41
+ color: s.color,
42
+ inverted: s.inverted,
43
+ }))
44
+ } else {
45
+ const recipe = getRecipe(resolved.itemId)
46
+ rows = (recipe?.statSlots ?? []).flatMap((slot) => {
47
+ const src = slot.sources[0]
48
+ if (!src) return []
49
+ const input = recipe!.inputs[src.inputIndex]
50
+ if (!input || !('category' in input)) return []
51
+ const category = input.category as ResourceCategory
52
+ const def = getStatDefinitions(category)[src.statIndex]
53
+ if (!def) return []
54
+ return [
55
+ {
56
+ label: def.label,
57
+ abbreviation: def.abbreviation,
58
+ value: null,
59
+ color: categoryColors[category],
60
+ inverted: def.inverted,
61
+ },
62
+ ]
63
+ })
64
+ }
65
65
 
66
- const headerH = 48;
67
- const metaRowH = 28;
68
- const statsH = rows.length * 26 + 8;
69
- const height = headerH + metaRowH + 14 + statsH + pad;
66
+ const headerH = 48
67
+ const metaRowH = 28
68
+ const statsH = rows.length * 26 + 8
69
+ const height = headerH + metaRowH + 14 + statsH + pad
70
70
 
71
- const chrome = panel({ width: w, height, borderColor: tierBorder(resolved.tier) });
71
+ const chrome = panel({width: w, height, borderColor: tierBorder(resolved.tier)})
72
72
 
73
- const quantity = Number(BigInt(item.quantity.toString()));
74
- const badge = quantityBadge({ x: w - pad, y: pad, quantity });
73
+ const quantity = Number(BigInt(item.quantity.toString()))
74
+ const badge = quantityBadge({x: w - pad, y: pad, quantity})
75
75
 
76
- const icon = iconHex({
77
- x: pad,
78
- y: pad + 4,
79
- color: tokens.colors.accent.component,
80
- code: shortCode(resolved.itemId),
81
- });
76
+ const icon = iconHex({
77
+ x: pad,
78
+ y: pad + 4,
79
+ color: tokens.colors.accent.component,
80
+ code: shortCode(resolved.itemId),
81
+ })
82
82
 
83
- const name = text({
84
- x: pad + 34,
85
- y: pad + 22,
86
- value: resolved.name,
87
- size: tokens.typography.sizes.title,
88
- weight: 700,
89
- family: tokens.typography.display,
90
- });
83
+ const name = text({
84
+ x: pad + 34,
85
+ y: pad + 22,
86
+ value: resolved.name,
87
+ size: tokens.typography.sizes.title,
88
+ weight: 700,
89
+ family: tokens.typography.display,
90
+ })
91
91
 
92
- const subtitleText = text({
93
- x: pad,
94
- y: pad + headerH + 4,
95
- value: "Type",
96
- size: tokens.typography.sizes.body,
97
- color: tokens.colors.text.secondary,
98
- });
99
- const subtitleValue = text({
100
- x: w - pad,
101
- y: pad + headerH + 4,
102
- value: `COMPONENT · ${formatTier(resolved.tier)}`,
103
- size: tokens.typography.sizes.body,
104
- weight: 600,
105
- anchor: "end",
106
- });
107
- const massLabel = text({
108
- x: pad,
109
- y: pad + headerH + metaRowH - 8,
110
- value: "Mass",
111
- size: tokens.typography.sizes.body,
112
- color: tokens.colors.text.secondary,
113
- });
114
- const massValue = text({
115
- x: w - pad,
116
- y: pad + headerH + metaRowH - 8,
117
- value: formatMass(resolved.mass),
118
- size: tokens.typography.sizes.body,
119
- weight: 600,
120
- anchor: "end",
121
- });
92
+ const subtitleText = text({
93
+ x: pad,
94
+ y: pad + headerH + 4,
95
+ value: 'Type',
96
+ size: tokens.typography.sizes.body,
97
+ color: tokens.colors.text.secondary,
98
+ })
99
+ const subtitleValue = text({
100
+ x: w - pad,
101
+ y: pad + headerH + 4,
102
+ value: `COMPONENT · ${formatTier(resolved.tier)}`,
103
+ size: tokens.typography.sizes.body,
104
+ weight: 600,
105
+ anchor: 'end',
106
+ })
107
+ const massLabel = text({
108
+ x: pad,
109
+ y: pad + headerH + metaRowH - 8,
110
+ value: 'Mass',
111
+ size: tokens.typography.sizes.body,
112
+ color: tokens.colors.text.secondary,
113
+ })
114
+ const massValue = text({
115
+ x: w - pad,
116
+ y: pad + headerH + metaRowH - 8,
117
+ value: formatMass(resolved.mass),
118
+ size: tokens.typography.sizes.body,
119
+ weight: 600,
120
+ anchor: 'end',
121
+ })
122
122
 
123
- const sepY = pad + headerH + metaRowH + 6;
124
- const sep = divider({ x: pad, y: sepY, width: innerW });
123
+ const sepY = pad + headerH + metaRowH + 6
124
+ const sep = divider({x: pad, y: sepY, width: innerW})
125
125
 
126
- const statsSvg = rows
127
- .map((row, i) =>
128
- statBar({
129
- x: pad,
130
- y: sepY + 18 + i * 26,
131
- width: innerW,
132
- label: row.label,
133
- abbreviation: row.abbreviation,
134
- value: row.value,
135
- color: row.color,
136
- inverted: row.inverted,
137
- }),
138
- )
139
- .join("");
126
+ const statsSvg = rows
127
+ .map((row, i) =>
128
+ statBar({
129
+ x: pad,
130
+ y: sepY + 18 + i * 26,
131
+ width: innerW,
132
+ label: row.label,
133
+ abbreviation: row.abbreviation,
134
+ value: row.value,
135
+ color: row.color,
136
+ inverted: row.inverted,
137
+ })
138
+ )
139
+ .join('')
140
140
 
141
- const inner = `${chrome}${icon}${name}${badge}${subtitleText}${subtitleValue}${massLabel}${massValue}${sep}${statsSvg}`;
141
+ const inner = `${chrome}${icon}${name}${badge}${subtitleText}${subtitleValue}${massLabel}${massValue}${sep}${statsSvg}`
142
142
 
143
- return `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${height}" viewBox="0 0 ${w} ${height}">${inner}</svg>`;
143
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${height}" viewBox="0 0 ${w} ${height}">${inner}</svg>`
144
144
  }
@@ -1,30 +1,30 @@
1
- import type { ResolvedItem } from "@shipload/sdk";
2
- import type { CargoItem } from "../payload/codec.ts";
3
- import { RenderError } from "../errors.ts";
4
- import { renderResource } from "./resource.ts";
5
- import { renderPackedEntity } from "./packed-entity.ts";
6
- import { renderComponent } from "./component.ts";
7
- import { renderModule } from "./module.ts";
1
+ import type {ResolvedItem} from '@shipload/sdk'
2
+ import type {CargoItem} from '../payload/codec.ts'
3
+ import {RenderError} from '../errors.ts'
4
+ import {renderResource} from './resource.ts'
5
+ import {renderPackedEntity} from './packed-entity.ts'
6
+ import {renderComponent} from './component.ts'
7
+ import {renderModule} from './module.ts'
8
8
 
9
9
  export interface RenderByTypeOpts {
10
- mode?: "values" | "ranges";
10
+ mode?: 'values' | 'ranges'
11
11
  }
12
12
 
13
13
  export function renderByType(
14
- item: CargoItem,
15
- resolved: ResolvedItem,
16
- opts?: RenderByTypeOpts,
14
+ item: CargoItem,
15
+ resolved: ResolvedItem,
16
+ opts?: RenderByTypeOpts
17
17
  ): string {
18
- switch (resolved.itemType) {
19
- case "resource":
20
- return renderResource(item, resolved, opts);
21
- case "entity":
22
- return renderPackedEntity(item, resolved);
23
- case "component":
24
- return renderComponent(item, resolved, opts);
25
- case "module":
26
- return renderModule(item, resolved, opts);
27
- default:
28
- throw new RenderError(`unknown itemType '${String(resolved.itemType)}'`);
29
- }
18
+ switch (resolved.itemType) {
19
+ case 'resource':
20
+ return renderResource(item, resolved, opts)
21
+ case 'entity':
22
+ return renderPackedEntity(item, resolved)
23
+ case 'component':
24
+ return renderComponent(item, resolved, opts)
25
+ case 'module':
26
+ return renderModule(item, resolved, opts)
27
+ default:
28
+ throw new RenderError(`unknown itemType '${String(resolved.itemType)}'`)
29
+ }
30
30
  }
@@ -1,103 +1,103 @@
1
- import type { ResolvedItem } from "@shipload/sdk";
2
- import { tierColors, categoryColors, categoryIconShapes } from "@shipload/sdk";
3
- import { el } from "../primitives/svg.ts";
4
- import { text } from "../primitives/text.ts";
5
- import { categoryIconPath } from "../primitives/category-icon.ts";
6
- import { tokens } from "../tokens/index.ts";
1
+ import type {ResolvedItem} from '@shipload/sdk'
2
+ import {tierColors, categoryColors, categoryIconShapes} from '@shipload/sdk'
3
+ import {el} from '../primitives/svg.ts'
4
+ import {text} from '../primitives/text.ts'
5
+ import {categoryIconPath} from '../primitives/category-icon.ts'
6
+ import {tokens} from '../tokens/index.ts'
7
7
 
8
8
  export interface ItemCellProps {
9
- resolved: ResolvedItem;
10
- quantity?: number;
11
- size?: number;
9
+ resolved: ResolvedItem
10
+ quantity?: number
11
+ size?: number
12
12
  }
13
13
 
14
14
  export interface ItemCellGroupProps extends ItemCellProps {
15
- x: number;
16
- y: number;
15
+ x: number
16
+ y: number
17
17
  }
18
18
 
19
19
  function cellInner(props: ItemCellProps): string {
20
- const size = props.size ?? 48;
21
- const height = Math.round(size * 1.25);
22
- const r = Math.max(4, Math.round(size * 0.12));
23
- const cx = size / 2;
20
+ const size = props.size ?? 48
21
+ const height = Math.round(size * 1.25)
22
+ const r = Math.max(4, Math.round(size * 0.12))
23
+ const cx = size / 2
24
24
 
25
- const border = el("rect", {
26
- x: 0.5,
27
- y: 0.5,
28
- width: size - 1,
29
- height: height - 1,
30
- rx: r,
31
- ry: r,
32
- fill: tokens.colors.surface.panel,
33
- stroke: tierColors[props.resolved.tier] ?? tokens.colors.surface.panelBorder,
34
- "stroke-width": 1.5,
35
- });
25
+ const border = el('rect', {
26
+ x: 0.5,
27
+ y: 0.5,
28
+ width: size - 1,
29
+ height: height - 1,
30
+ rx: r,
31
+ ry: r,
32
+ fill: tokens.colors.surface.panel,
33
+ stroke: tierColors[props.resolved.tier] ?? tokens.colors.surface.panelBorder,
34
+ 'stroke-width': 1.5,
35
+ })
36
36
 
37
- let content = "";
38
- if (props.resolved.abbreviation) {
39
- const iconCy = size * 0.45;
40
- content = text({
41
- x: cx,
42
- y: iconCy,
43
- value: props.resolved.abbreviation,
44
- size: Math.round(size * 0.28),
45
- weight: 700,
46
- anchor: "middle",
47
- color: tokens.colors.text.primary,
48
- family: tokens.typography.display,
49
- });
50
- } else if (props.resolved.category) {
51
- const shape = categoryIconShapes[props.resolved.category];
52
- const color = categoryColors[props.resolved.category];
53
- const iconCy = size * 0.4;
54
- content = categoryIconPath({
55
- shape,
56
- cx,
57
- cy: iconCy,
58
- size: size * 0.32,
59
- color,
60
- strokeWidth: 1.5,
61
- });
62
- } else if (props.resolved.icon) {
63
- content = text({
64
- x: cx,
65
- y: size * 0.4,
66
- value: props.resolved.icon,
67
- size: Math.round(size * 0.44),
68
- weight: 400,
69
- anchor: "middle",
70
- dominantBaseline: "central",
71
- color: tokens.colors.text.primary,
72
- });
73
- }
37
+ let content = ''
38
+ if (props.resolved.abbreviation) {
39
+ const iconCy = size * 0.45
40
+ content = text({
41
+ x: cx,
42
+ y: iconCy,
43
+ value: props.resolved.abbreviation,
44
+ size: Math.round(size * 0.28),
45
+ weight: 700,
46
+ anchor: 'middle',
47
+ color: tokens.colors.text.primary,
48
+ family: tokens.typography.display,
49
+ })
50
+ } else if (props.resolved.category) {
51
+ const shape = categoryIconShapes[props.resolved.category]
52
+ const color = categoryColors[props.resolved.category]
53
+ const iconCy = size * 0.4
54
+ content = categoryIconPath({
55
+ shape,
56
+ cx,
57
+ cy: iconCy,
58
+ size: size * 0.32,
59
+ color,
60
+ strokeWidth: 1.5,
61
+ })
62
+ } else if (props.resolved.icon) {
63
+ content = text({
64
+ x: cx,
65
+ y: size * 0.4,
66
+ value: props.resolved.icon,
67
+ size: Math.round(size * 0.44),
68
+ weight: 400,
69
+ anchor: 'middle',
70
+ dominantBaseline: 'central',
71
+ color: tokens.colors.text.primary,
72
+ })
73
+ }
74
74
 
75
- const qty = props.quantity ?? 0;
76
- let quantityText = "";
77
- if (qty > 1) {
78
- const qtyFontSize = Math.max(9, Math.round(size * 0.22));
79
- const qtyPad = Math.max(3, Math.round(size * 0.12));
80
- quantityText = text({
81
- x: size - qtyPad,
82
- y: height - qtyPad,
83
- value: String(qty),
84
- size: qtyFontSize,
85
- weight: 700,
86
- anchor: "end",
87
- color: tokens.colors.text.primary,
88
- family: tokens.typography.display,
89
- });
90
- }
75
+ const qty = props.quantity ?? 0
76
+ let quantityText = ''
77
+ if (qty > 1) {
78
+ const qtyFontSize = Math.max(9, Math.round(size * 0.22))
79
+ const qtyPad = Math.max(3, Math.round(size * 0.12))
80
+ quantityText = text({
81
+ x: size - qtyPad,
82
+ y: height - qtyPad,
83
+ value: String(qty),
84
+ size: qtyFontSize,
85
+ weight: 700,
86
+ anchor: 'end',
87
+ color: tokens.colors.text.primary,
88
+ family: tokens.typography.display,
89
+ })
90
+ }
91
91
 
92
- return border + content + quantityText;
92
+ return border + content + quantityText
93
93
  }
94
94
 
95
95
  export function itemCellGroup(props: ItemCellGroupProps): string {
96
- return `<g transform="translate(${props.x}, ${props.y})">${cellInner(props)}</g>`;
96
+ return `<g transform="translate(${props.x}, ${props.y})">${cellInner(props)}</g>`
97
97
  }
98
98
 
99
99
  export function renderItemCell(props: ItemCellProps): string {
100
- const size = props.size ?? 48;
101
- const height = Math.round(size * 1.25);
102
- return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${height}" viewBox="0 0 ${size} ${height}">${cellInner(props)}</svg>`;
100
+ const size = props.size ?? 48
101
+ const height = Math.round(size * 1.25)
102
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${height}" viewBox="0 0 ${size} ${height}">${cellInner(props)}</svg>`
103
103
  }