@vettvangur/design-system 2.0.46 → 2.0.49
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/dist/index.js +260 -62
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2193,70 +2193,267 @@ async function generateFile(variables, config) {
|
|
|
2193
2193
|
await fs$1.writeFile(outPath, css, 'utf8');
|
|
2194
2194
|
}
|
|
2195
2195
|
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2196
|
+
const FIGMA_API_BASE_URL = 'https://api.figma.com/v1';
|
|
2197
|
+
const FIGMA_PAGE = 'Buttons';
|
|
2198
|
+
const assertNonEmptyString = (value, name) => {
|
|
2199
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
2200
|
+
throw new TypeError(`${name} must be a non-empty string`);
|
|
2201
|
+
}
|
|
2202
|
+
};
|
|
2203
|
+
const walkFigmaNode = (node, visit) => {
|
|
2204
|
+
if (!node || typeof node !== 'object') {
|
|
2205
|
+
return;
|
|
2206
|
+
}
|
|
2207
|
+
visit(node);
|
|
2208
|
+
const children = node.children;
|
|
2209
|
+
if (!Array.isArray(children)) {
|
|
2210
|
+
return;
|
|
2211
|
+
}
|
|
2212
|
+
for (const child of children) {
|
|
2213
|
+
walkFigmaNode(child, visit);
|
|
2214
|
+
}
|
|
2215
|
+
};
|
|
2216
|
+
const stripButtonVariantPrefix = name => {
|
|
2217
|
+
if (typeof name !== 'string') {
|
|
2218
|
+
return null;
|
|
2219
|
+
}
|
|
2220
|
+
return name.replace(/^\s*button\s*variant\s*=\s*/i, '');
|
|
2221
|
+
};
|
|
2222
|
+
const findPageNodeId = (fileResponse, pageName) => {
|
|
2223
|
+
const pages = fileResponse?.document?.children;
|
|
2224
|
+
if (!Array.isArray(pages)) {
|
|
2225
|
+
return null;
|
|
2226
|
+
}
|
|
2227
|
+
const target = String(pageName).trim().toLowerCase();
|
|
2228
|
+
const canvases = pages.filter(child => child?.type === 'CANVAS' && typeof child?.name === 'string');
|
|
2229
|
+
const exact = canvases.find(child => child.name.trim().toLowerCase() === target);
|
|
2230
|
+
if (typeof exact?.id === 'string') {
|
|
2231
|
+
return exact.id;
|
|
2232
|
+
}
|
|
2233
|
+
const partial = canvases.find(child => child.name.trim().toLowerCase().includes(target));
|
|
2234
|
+
return typeof partial?.id === 'string' ? partial.id : null;
|
|
2235
|
+
};
|
|
2236
|
+
const isButtonComponentSet = node => {
|
|
2237
|
+
if (node?.type !== 'COMPONENT_SET') {
|
|
2238
|
+
return false;
|
|
2239
|
+
}
|
|
2240
|
+
const name = typeof node?.name === 'string' ? node.name : '';
|
|
2241
|
+
return /\bbutton\b/i.test(name);
|
|
2242
|
+
};
|
|
2243
|
+
const fetchButtonsPageNodes = async (fileKey, pageName = FIGMA_PAGE) => {
|
|
2244
|
+
assertNonEmptyString(fileKey, 'fileKey');
|
|
2245
|
+
assertNonEmptyString(pageName, 'pageName');
|
|
2246
|
+
const fileResponse = await jget(`${FIGMA_API_BASE_URL}/files/${encodeURIComponent(fileKey)}`);
|
|
2247
|
+
const pageNodeId = findPageNodeId(fileResponse, pageName);
|
|
2248
|
+
if (!pageNodeId) {
|
|
2249
|
+
const availablePages = Array.isArray(fileResponse?.document?.children) ? fileResponse.document.children.map(p => p?.name).filter(Boolean) : [];
|
|
2250
|
+
throw new Error(`Page not found: ${pageName}. Available pages: ${availablePages.join(', ')}`);
|
|
2251
|
+
}
|
|
2252
|
+
const nodesResponse = await jget(`${FIGMA_API_BASE_URL}/files/${encodeURIComponent(fileKey)}/nodes?ids=${encodeURIComponent(pageNodeId)}`);
|
|
2253
|
+
return {
|
|
2254
|
+
pageNodeId,
|
|
2255
|
+
nodesResponse
|
|
2256
|
+
};
|
|
2257
|
+
};
|
|
2258
|
+
const fetchFigmaLocalVariables = async fileKey => {
|
|
2259
|
+
assertNonEmptyString(fileKey, 'fileKey');
|
|
2260
|
+
return jget(`${FIGMA_API_BASE_URL}/files/${encodeURIComponent(fileKey)}/variables/local`);
|
|
2261
|
+
};
|
|
2262
|
+
const asArray = value => {
|
|
2263
|
+
if (!value) {
|
|
2264
|
+
return [];
|
|
2265
|
+
}
|
|
2266
|
+
if (Array.isArray(value)) {
|
|
2267
|
+
return value;
|
|
2268
|
+
}
|
|
2269
|
+
if (typeof value === 'object') {
|
|
2270
|
+
return Object.values(value);
|
|
2271
|
+
}
|
|
2272
|
+
return [];
|
|
2273
|
+
};
|
|
2274
|
+
const formatVariableValue = value => {
|
|
2275
|
+
if (value && typeof value === 'object' && typeof value.r === 'number' && typeof value.g === 'number' && typeof value.b === 'number') {
|
|
2276
|
+
return {
|
|
2277
|
+
kind: 'COLOR',
|
|
2278
|
+
hex: colorToHexRgba(value),
|
|
2279
|
+
rgba: rgba255(value),
|
|
2280
|
+
raw: value
|
|
2281
|
+
};
|
|
2282
|
+
}
|
|
2283
|
+
return {
|
|
2284
|
+
kind: 'RAW',
|
|
2285
|
+
raw: value
|
|
2286
|
+
};
|
|
2287
|
+
};
|
|
2288
|
+
const buildVariableResolver = variablesResponse => {
|
|
2289
|
+
const meta = variablesResponse?.meta ?? variablesResponse;
|
|
2290
|
+
const variablesRaw = meta?.variables ?? {};
|
|
2291
|
+
const collectionsRaw = meta?.variableCollections ?? {};
|
|
2292
|
+
const variablesById = new Map();
|
|
2293
|
+
for (const variable of asArray(variablesRaw)) {
|
|
2294
|
+
if (variable?.id) {
|
|
2295
|
+
variablesById.set(variable.id, variable);
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
const collectionsById = new Map();
|
|
2299
|
+
for (const collection of asArray(collectionsRaw)) {
|
|
2300
|
+
if (collection?.id) {
|
|
2301
|
+
collectionsById.set(collection.id, collection);
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
const modeNameById = new Map();
|
|
2305
|
+
for (const collection of collectionsById.values()) {
|
|
2306
|
+
for (const mode of asArray(collection?.modes)) {
|
|
2307
|
+
if (mode?.modeId && mode?.name) {
|
|
2308
|
+
modeNameById.set(mode.modeId, mode.name);
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
const resolve = variableId => {
|
|
2313
|
+
const variable = variablesById.get(variableId);
|
|
2314
|
+
if (!variable) {
|
|
2315
|
+
return null;
|
|
2316
|
+
}
|
|
2317
|
+
const collection = variable.variableCollectionId ? collectionsById.get(variable.variableCollectionId) : null;
|
|
2318
|
+
const valuesByMode = variable.valuesByMode && typeof variable.valuesByMode === 'object' ? variable.valuesByMode : {};
|
|
2319
|
+
return {
|
|
2320
|
+
id: variable.id,
|
|
2321
|
+
key: variable.key ?? null,
|
|
2322
|
+
name: variable.name ?? null,
|
|
2323
|
+
nameKebab: toKebab(variable.name),
|
|
2324
|
+
resolvedType: variable.resolvedType ?? null,
|
|
2325
|
+
collection: collection ? {
|
|
2326
|
+
id: collection.id,
|
|
2327
|
+
name: collection.name ?? null
|
|
2328
|
+
} : null,
|
|
2329
|
+
valuesByMode: Object.entries(valuesByMode).map(([modeId, value]) => ({
|
|
2330
|
+
modeId,
|
|
2331
|
+
modeName: modeNameById.get(modeId) ?? null,
|
|
2332
|
+
value: formatVariableValue(value)
|
|
2333
|
+
}))
|
|
2334
|
+
};
|
|
2335
|
+
};
|
|
2336
|
+
return {
|
|
2337
|
+
resolve
|
|
2338
|
+
};
|
|
2339
|
+
};
|
|
2340
|
+
const enrichVariableAliases = (value, resolveVariable) => {
|
|
2341
|
+
if (!value) {
|
|
2342
|
+
return value;
|
|
2343
|
+
}
|
|
2344
|
+
if (Array.isArray(value)) {
|
|
2345
|
+
return value.map(item => enrichVariableAliases(item, resolveVariable));
|
|
2346
|
+
}
|
|
2347
|
+
if (typeof value !== 'object') {
|
|
2348
|
+
return value;
|
|
2349
|
+
}
|
|
2350
|
+
if (value.type === 'VARIABLE_ALIAS' && typeof value.id === 'string') {
|
|
2351
|
+
return {
|
|
2352
|
+
...value,
|
|
2353
|
+
variable: resolveVariable(value.id)
|
|
2354
|
+
};
|
|
2355
|
+
}
|
|
2356
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, enrichVariableAliases(child, resolveVariable)]));
|
|
2357
|
+
};
|
|
2358
|
+
const enrichBoundVariablesInNodeTree = (root, resolveVariable) => {
|
|
2359
|
+
walkFigmaNode(root, node => {
|
|
2360
|
+
if (node?.boundVariables && typeof node.boundVariables === 'object') {
|
|
2361
|
+
node.boundVariables = enrichVariableAliases(node.boundVariables, resolveVariable);
|
|
2362
|
+
}
|
|
2363
|
+
const fills = Array.isArray(node?.fills) ? node.fills : null;
|
|
2364
|
+
if (fills) {
|
|
2365
|
+
for (const paint of fills) {
|
|
2366
|
+
if (paint?.boundVariables && typeof paint.boundVariables === 'object') {
|
|
2367
|
+
paint.boundVariables = enrichVariableAliases(paint.boundVariables, resolveVariable);
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
});
|
|
2372
|
+
};
|
|
2373
|
+
const extractButtonGroupsByComponentSet = (nodesResponse, {
|
|
2374
|
+
pageNodeId
|
|
2375
|
+
}) => {
|
|
2376
|
+
const nodes = nodesResponse?.nodes;
|
|
2377
|
+
if (!nodes || typeof nodes !== 'object') {
|
|
2378
|
+
return [];
|
|
2379
|
+
}
|
|
2380
|
+
const pageDocument = nodes?.[pageNodeId]?.document;
|
|
2381
|
+
if (!pageDocument || typeof pageDocument !== 'object') {
|
|
2382
|
+
return [];
|
|
2383
|
+
}
|
|
2384
|
+
const groups = [];
|
|
2385
|
+
walkFigmaNode(pageDocument, node => {
|
|
2386
|
+
if (!isButtonComponentSet(node)) {
|
|
2387
|
+
return;
|
|
2388
|
+
}
|
|
2389
|
+
const variants = Array.isArray(node?.children) ? node.children : [];
|
|
2390
|
+
for (const variant of variants) {
|
|
2391
|
+
if (!variant || typeof variant !== 'object') {
|
|
2392
|
+
continue;
|
|
2393
|
+
}
|
|
2394
|
+
variant.nameKebab = toKebab(stripButtonVariantPrefix(variant?.name));
|
|
2395
|
+
}
|
|
2396
|
+
groups.push({
|
|
2397
|
+
componentSet: {
|
|
2398
|
+
id: typeof node?.id === 'string' ? node.id : null,
|
|
2399
|
+
name: typeof node?.name === 'string' ? node.name : null,
|
|
2400
|
+
nameKebab: toKebab(node?.name),
|
|
2401
|
+
variants
|
|
2402
|
+
}
|
|
2403
|
+
});
|
|
2404
|
+
});
|
|
2405
|
+
return groups;
|
|
2406
|
+
};
|
|
2237
2407
|
function renderUtility(name) {
|
|
2238
|
-
return `@utility ${name} {\n @apply button;\n\n
|
|
2408
|
+
return `@utility ${name} {\n @apply button;\n\n &:not([disabled]):hover {\n \n }\n}\n`;
|
|
2239
2409
|
}
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
const
|
|
2256
|
-
const
|
|
2410
|
+
async function generateButtons$1(_components, config) {
|
|
2411
|
+
message('generating buttons (from figma Buttons page)...');
|
|
2412
|
+
const fileKey = config?.figma?.fileKey;
|
|
2413
|
+
assertNonEmptyString(fileKey, 'config.figma.fileKey');
|
|
2414
|
+
const coreOutDir = path.join(config.paths.styles, 'core');
|
|
2415
|
+
await fs$1.mkdir(coreOutDir, {
|
|
2416
|
+
recursive: true
|
|
2417
|
+
});
|
|
2418
|
+
const {
|
|
2419
|
+
pageNodeId,
|
|
2420
|
+
nodesResponse
|
|
2421
|
+
} = await fetchButtonsPageNodes(fileKey, FIGMA_PAGE);
|
|
2422
|
+
const groups = extractButtonGroupsByComponentSet(nodesResponse, {
|
|
2423
|
+
pageNodeId
|
|
2424
|
+
});
|
|
2425
|
+
const variablesResponse = await fetchFigmaLocalVariables(fileKey);
|
|
2426
|
+
const {
|
|
2427
|
+
resolve
|
|
2428
|
+
} = buildVariableResolver(variablesResponse);
|
|
2429
|
+
for (const group of groups) {
|
|
2430
|
+
for (const variant of group.componentSet?.variants ?? []) {
|
|
2431
|
+
enrichBoundVariablesInNodeTree(variant, resolve);
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
const snapshotPath = path.join(coreOutDir, 'button-variants.figma.json');
|
|
2435
|
+
await fs$1.writeFile(snapshotPath, `${JSON.stringify({
|
|
2436
|
+
fileKey,
|
|
2437
|
+
page: FIGMA_PAGE,
|
|
2438
|
+
pageNodeId,
|
|
2439
|
+
groups
|
|
2440
|
+
}, null, 2)}\n`, 'utf8');
|
|
2441
|
+
const utilityNames = [];
|
|
2442
|
+
for (const group of groups) {
|
|
2443
|
+
const setKey = group.componentSet?.nameKebab;
|
|
2444
|
+
for (const variant of group.componentSet?.variants ?? []) {
|
|
2445
|
+
const variantKey = variant?.nameKebab;
|
|
2446
|
+
if (!setKey || !variantKey) {
|
|
2447
|
+
continue;
|
|
2448
|
+
}
|
|
2449
|
+
utilityNames.push(`button-${setKey}-${variantKey}`);
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
const blocks = Array.from(new Set(utilityNames)).sort().map(renderUtility);
|
|
2257
2453
|
const css = `/* AUTO-GENERATED ONCE - Safe to edit */\n${blocks.join('\n')}`;
|
|
2258
|
-
const outPath = path.join(
|
|
2454
|
+
const outPath = path.join(coreOutDir, 'button-variants.css');
|
|
2259
2455
|
await fs$1.writeFile(outPath, css, 'utf8');
|
|
2456
|
+
message(`finished generating button variants (count=${blocks.length})`);
|
|
2260
2457
|
}
|
|
2261
2458
|
|
|
2262
2459
|
/**
|
|
@@ -3604,11 +3801,12 @@ async function generateScreens(figmaVariables, config) {
|
|
|
3604
3801
|
}
|
|
3605
3802
|
}
|
|
3606
3803
|
const fluidStyles = `/* AUTO-GENERATED - DO NOT EDIT BY HAND */
|
|
3804
|
+
|
|
3607
3805
|
@utility fluid-html {
|
|
3608
3806
|
/* unfortunatelly min-width values in media queries can't come from variables. */
|
|
3609
3807
|
|
|
3610
3808
|
/* mobile */
|
|
3611
|
-
font-size: calc((100 / {extrasUnitless['mobile-design-width']}) * 1vw);
|
|
3809
|
+
font-size: calc((100 / ${extrasUnitless['mobile-design-width']}) * 1vw);
|
|
3612
3810
|
|
|
3613
3811
|
/* this needs to match --breakpoint-desktop-xs */
|
|
3614
3812
|
@media (min-width: ${BASE_SCREENS['desktop-xs']}px) {
|
|
@@ -3618,7 +3816,7 @@ async function generateScreens(figmaVariables, config) {
|
|
|
3618
3816
|
/* this needs to match --breakpoint ultrawide-design-width */
|
|
3619
3817
|
@media (min-width: ${extrasUnitless['ultrawide-design-width']}px) {
|
|
3620
3818
|
font-size: calc(
|
|
3621
|
-
((100 / ${extrasUnitless['desktop-design-width']}
|
|
3819
|
+
((100 / ${extrasUnitless['desktop-design-width']}) * ${extrasUnitless['ultrawide-design-width']} / 16) * 0.01rem
|
|
3622
3820
|
);
|
|
3623
3821
|
}
|
|
3624
3822
|
}
|