scb-wc 0.1.70 → 0.1.72

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/README.md CHANGED
@@ -66,17 +66,19 @@ Vill du selfhosta kan du istället importera:
66
66
  import 'scb-wc/scb-wc-selfhost.css';
67
67
  ```
68
68
 
69
- Då används paketets egna fontfiler under `node_modules/scb-wc/fonts/`.
69
+ Då används paketets egna fontfiler under `node_modules/scb-wc/fonts/`. Material Symbols är inte hela Google-fonten här. Selfhost-filen innehåller alla ikoner som visas under `Foundations/Icons (ikoner)` i Storybook. Listan kommer från paketets `icons.json`. Fonten behåller stöd för både fyllda och ofyllda varianter.
70
70
 
71
71
  ### Optimera Material Symbols med eget ikon-subset
72
72
 
73
- Vill du selfhosta bara de Material Symbols-ikoner din app använder kan du generera en liten ikonfont i din app:
73
+ Det här är bara för appar som behöver Material Symbols utöver paketets `icons.json`. Då använder du `scb-wc-core.css` + ditt genererade `scb-wc-icons.css` i stället för `scb-wc-selfhost.css`.
74
+
75
+ Skapa en ikonlista i appens rot. Om du vill ersätta paketets selfhost-lista, kopiera paketets `icons.json` och lägg till dina egna ikon-namn:
74
76
 
75
77
  ```sh
76
78
  npx scb-wc subset-icons --icons ./src/scb-icons.json --out ./public/scb-icons
77
79
  ```
78
80
 
79
- Om `--icons` utelämnas används paketets standardlista `icons.json`. Kommandot skapar `scb-wc-icons.css`, en lokal fontfil och en kopia av ikonlistan i målmappen. Ladda då den fontlösa bas-CSS:en plus den genererade ikon-CSS:en:
81
+ Om `--icons` utelämnas används paketets standardlista `icons.json`. Om du skickar in en egen fil lägger kommandot till några basikoner, men inte hela paketets ikonlista. Kommandot skapar `scb-wc-icons.css`, en lokal fontfil och en kopia av ikonlistan i målmappen. Ladda då den fontlösa bas-CSS:en plus den genererade ikon-CSS:en:
80
82
 
81
83
  ```js
82
84
  import 'scb-wc/scb-wc-core.css';
@@ -84,6 +86,8 @@ import '/scb-icons/scb-wc-icons.css';
84
86
  import 'scb-wc/scb-typography.css';
85
87
  ```
86
88
 
89
+ För MVC/MPA räcker det normalt att använda `scb-wc-selfhost.css`, eftersom den redan pekar på paketets selfhostade fontfiler.
90
+
87
91
  ---
88
92
 
89
93
  ## Alternativ 2: Använd i MVC/MPA via `<script type="module">`
@@ -112,22 +116,23 @@ Kör sedan:
112
116
  npm run ui:install
113
117
  ```
114
118
 
115
- Det kopierar hela `node_modules/scb-wc/mvc/` till `wwwroot/ui/` i din applikation (komponenter, vendor och CSS).
119
+ Det kopierar hela `node_modules/scb-wc/mvc/` till `wwwroot/ui/` i din applikation (komponenter, vendor, CSS och fonts).
116
120
 
117
- ### 2.2) Ladda filer i din layout (Razor, .cshtml, klassisk MVC)
121
+ ### 2.2) Ladda filer i layouten (Razor, .cshtml, klassisk MVC)
118
122
 
119
- Du kan byta till `~/ui/scb-wc-selfhost.css` om du vill selfhosta fonterna (mappen `ui/fonts/` kopieras av `ui:install`).
123
+ Exemplet använder selfhost-läget. Lägg CSS i `<head>` och ladda bara de komponentskript som sidan använder.
120
124
 
121
125
  ```html
122
- <!-- Lägg helst i <head> -->
123
- <link rel="stylesheet" href="~/ui/scb-wc.css" />
126
+ <!-- Global layout, helst i <head> -->
127
+ <link rel="stylesheet" href="~/ui/scb-wc-selfhost.css" />
124
128
  <link rel="stylesheet" href="~/ui/scb-typography.css" />
125
129
 
126
- <!-- Ladda ENDAST de komponenter du använder på sidan, gärna precis före </body> -->
127
- <script type="module" src="~/ui/components/scb-link/scb-link.js"></script>
130
+ <!-- Ladda bara de komponenter sidan använder -->
128
131
  <script type="module" src="~/ui/components/scb-button/scb-button.js"></script>
129
132
  ```
130
133
 
134
+ `~/ui/scb-wc-selfhost.css` laddar Inter och paketets Material Symbols-subset från `~/ui/fonts/`.
135
+
131
136
  ### 2.3) CI/CD‑exempel
132
137
 
133
138
  Kör samma script i din pipeline:
package/bin/scb-wc.mjs CHANGED
@@ -21,7 +21,7 @@ const defaultSubsetOutDir = 'public/scb-icons';
21
21
  const defaultSubsetCssFile = 'scb-wc-icons.css';
22
22
  const defaultSubsetFontBase = 'material-symbols-outlined-subset';
23
23
  const materialSymbolsCssUrl = 'https://fonts.googleapis.com/css2';
24
- const materialSymbolsFamilyQuery = 'Material Symbols Outlined:opsz,wght,FILL,GRAD@24,400,0,0';
24
+ const materialSymbolsFamilyQuery = 'Material Symbols Outlined:opsz,wght,FILL,GRAD@20..48,400,0..1,0';
25
25
  const requiredIconNames = [
26
26
  'arrow_back',
27
27
  'arrow_forward',
@@ -108,7 +108,7 @@ function parseFlags(args) {
108
108
  fail(`Ogiltigt argument: ${arg}`);
109
109
  }
110
110
 
111
- if (key === 'dry-run' || key === 'help') {
111
+ if (key === 'dry-run' || key === 'help' || key === 'no-required-icons' || key === 'allow-empty') {
112
112
  flags[key] = true;
113
113
  continue;
114
114
  }
@@ -161,8 +161,9 @@ function readIconList(iconsPath) {
161
161
  return list.map((icon) => String(icon ?? '').trim()).filter(Boolean);
162
162
  }
163
163
 
164
- function normalizeIconNames(iconNames) {
165
- const normalized = Array.from(new Set([...requiredIconNames, ...iconNames]))
164
+ function normalizeIconNames(iconNames, { includeRequired = true } = {}) {
165
+ const baseIconNames = includeRequired ? requiredIconNames : [];
166
+ const normalized = Array.from(new Set([...baseIconNames, ...iconNames]))
166
167
  .map((icon) => icon.trim())
167
168
  .filter(Boolean)
168
169
  .sort((a, b) => a.localeCompare(b));
@@ -191,7 +192,8 @@ function requestUrl(url, redirects = 5) {
191
192
  url,
192
193
  {
193
194
  headers: {
194
- 'User-Agent': `${packageJson.name}/${packageJson.version} subset-icons`,
195
+ Accept: 'text/css,*/*;q=0.1',
196
+ 'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124 Safari/537.36',
195
197
  },
196
198
  },
197
199
  (response) => {
@@ -264,6 +266,19 @@ function findFontSources(cssText) {
264
266
  }));
265
267
  }
266
268
 
269
+ function writeEmptySubsetFiles({ iconNames, outDir, cssFile }) {
270
+ fs.mkdirSync(outDir, { recursive: true });
271
+
272
+ const header = [
273
+ '/* Generated by `npx scb-wc subset-icons`. */',
274
+ '/* Icons: none */',
275
+ '',
276
+ ].join('\n');
277
+
278
+ fs.writeFileSync(path.join(outDir, cssFile), `${header}`, 'utf8');
279
+ fs.writeFileSync(path.join(outDir, 'icons.json'), `${JSON.stringify(iconNames, null, 2)}\n`, 'utf8');
280
+ }
281
+
267
282
  async function writeSubsetFiles({ cssText, iconNames, outDir, cssFile }) {
268
283
  const sources = findFontSources(cssText);
269
284
  if (!sources.length) {
@@ -299,6 +314,10 @@ async function runSubsetIcons(args) {
299
314
  return;
300
315
  }
301
316
 
317
+ if (flags.preset) {
318
+ fail('--preset stöds inte längre. Använd --icons för att ange ikonlista.');
319
+ }
320
+
302
321
  const iconsPath = flags.icons ?? resolveDefaultIconsPath();
303
322
  const outDir = path.resolve(process.cwd(), flags.out ?? defaultSubsetOutDir);
304
323
  const cssFile = flags['css-file'] ?? defaultSubsetCssFile;
@@ -312,8 +331,13 @@ async function runSubsetIcons(args) {
312
331
  fail('--display måste vara auto, block, swap, fallback eller optional.');
313
332
  }
314
333
 
315
- const iconNames = normalizeIconNames(readIconList(iconsPath));
316
- const cssUrl = buildMaterialSymbolsUrl(iconNames, display);
334
+ const iconNames = normalizeIconNames(readIconList(iconsPath), {
335
+ includeRequired: !flags['no-required-icons'],
336
+ });
337
+
338
+ if (!iconNames.length && !flags['allow-empty']) {
339
+ fail('Ikonlistan är tom. Lägg till ikoner eller använd --allow-empty.');
340
+ }
317
341
 
318
342
  if (flags['dry-run']) {
319
343
  console.log(`Skulle skapa Material Symbols-subset med ${iconNames.length} ikoner.`);
@@ -323,6 +347,14 @@ async function runSubsetIcons(args) {
323
347
  return;
324
348
  }
325
349
 
350
+ if (!iconNames.length) {
351
+ writeEmptySubsetFiles({ iconNames, outDir, cssFile });
352
+ console.log(`Skapade tom ikon-CSS i ${outDir}`);
353
+ console.log(`Ladda CSS-filen: ${path.join(outDir, cssFile)}`);
354
+ return;
355
+ }
356
+
357
+ const cssUrl = buildMaterialSymbolsUrl(iconNames, display);
326
358
  const cssText = await fetchText(cssUrl);
327
359
  await writeSubsetFiles({ cssText, iconNames, outDir, cssFile });
328
360
  console.log(`Skapade ikon-subset med ${iconNames.length} ikoner i ${outDir}`);
@@ -739,6 +739,9 @@ namespace ScbBlazor
739
739
  Type = dto.Type ?? string.Empty,
740
740
  Variant = dto.Variant ?? string.Empty,
741
741
  Direction = dto.Direction ?? string.Empty,
742
+ Title = dto.Title ?? string.Empty,
743
+ Subtitle = dto.Subtitle ?? string.Empty,
744
+ SupportingText = dto.SupportingText ?? string.Empty,
742
745
  CardHref = dto.CardHref ?? string.Empty,
743
746
 
744
747
  MediaType = dto.MediaType ?? string.Empty,
@@ -2974,6 +2977,9 @@ namespace ScbBlazor
2974
2977
  public string Type { get; set; } = string.Empty;
2975
2978
  public string Variant { get; set; } = string.Empty;
2976
2979
  public string Direction { get; set; } = string.Empty;
2980
+ public string Title { get; set; } = string.Empty;
2981
+ public string Subtitle { get; set; } = string.Empty;
2982
+ public string SupportingText { get; set; } = string.Empty;
2977
2983
  public string CardHref { get; set; } = string.Empty;
2978
2984
 
2979
2985
  public string MediaType { get; set; } = string.Empty;
@@ -3840,6 +3846,9 @@ namespace ScbBlazor
3840
3846
  public string? Type { get; set; }
3841
3847
  public string? Variant { get; set; }
3842
3848
  public string? Direction { get; set; }
3849
+ public string? Title { get; set; }
3850
+ public string? Subtitle { get; set; }
3851
+ public string? SupportingText { get; set; }
3843
3852
  public string? CardHref { get; set; }
3844
3853
 
3845
3854
  public string? MediaType { get; set; }
@@ -308,4 +308,4 @@ import"../../vendor/vendor-material.js";import{_ as y,b as v,g as w,h as d,p as
308
308
  transition: none;
309
309
  }
310
310
  }
311
- `,g);a([d({type:String})],r.prototype,"label",void 0);a([d({type:String})],r.prototype,"variant",void 0);a([d({type:String,reflect:!0})],r.prototype,"size",void 0);a([d({type:Boolean,reflect:!0})],r.prototype,"open",void 0);a([d({type:Boolean,reflect:!0})],r.prototype,"disabled",void 0);a([d({type:String,reflect:!0})],r.prototype,"spacing",void 0);a([d({type:String,attribute:"spacing-top",reflect:!0})],r.prototype,"spacingTop",void 0);a([d({type:String,attribute:"spacing-bottom",reflect:!0})],r.prototype,"spacingBottom",void 0);a([d({type:String,attribute:"spacing-left",reflect:!0})],r.prototype,"spacingLeft",void 0);a([d({type:String,attribute:"spacing-right",reflect:!0})],r.prototype,"spacingRight",void 0);a([d({type:String,attribute:"menu-gap"})],r.prototype,"menuGap",void 0);a([d({type:String})],r.prototype,"width",void 0);a([d({type:String,attribute:"min-width"})],r.prototype,"minWidth",void 0);a([d({type:String,attribute:"max-width"})],r.prototype,"maxWidth",void 0);a([d({type:String,attribute:"data-index"})],r.prototype,"dataIndex",void 0);a([d({type:String,attribute:"aria-current"})],r.prototype,"ariaCurrent",void 0);a([b("[data-scb-dropdown-trigger]")],r.prototype,"_triggerEl",void 0);a([b("slot")],r.prototype,"_slotEl",void 0);a([b(".panel-surface")],r.prototype,"_panelSurfaceEl",void 0);a([b(".panel-inner")],r.prototype,"_panelInnerEl",void 0);r=a([w("scb-dropdown")],r);
311
+ `,g);a([d({type:String})],r.prototype,"label",void 0);a([d({type:String})],r.prototype,"variant",void 0);a([d({type:String,reflect:!0})],r.prototype,"size",void 0);a([d({type:Boolean,reflect:!0})],r.prototype,"open",void 0);a([d({type:Boolean,reflect:!0})],r.prototype,"disabled",void 0);a([d({type:String,reflect:!0})],r.prototype,"spacing",void 0);a([d({type:String,attribute:"spacing-top",reflect:!0})],r.prototype,"spacingTop",void 0);a([d({type:String,attribute:"spacing-bottom",reflect:!0})],r.prototype,"spacingBottom",void 0);a([d({type:String,attribute:"spacing-left",reflect:!0})],r.prototype,"spacingLeft",void 0);a([d({type:String,attribute:"spacing-right",reflect:!0})],r.prototype,"spacingRight",void 0);a([d({type:String,attribute:"menu-gap"})],r.prototype,"menuGap",void 0);a([d({type:String})],r.prototype,"width",void 0);a([d({type:String,attribute:"min-width"})],r.prototype,"minWidth",void 0);a([d({type:String,attribute:"max-width"})],r.prototype,"maxWidth",void 0);a([d({type:String,attribute:"data-index"})],r.prototype,"dataIndex",void 0);a([d({type:String,attribute:"aria-current"})],r.prototype,"ariaCurrent",void 0);a([b("[data-scb-dropdown-trigger]")],r.prototype,"_triggerEl",void 0);a([b("slot")],r.prototype,"_slotEl",void 0);a([b(".panel-surface")],r.prototype,"_panelSurfaceEl",void 0);a([b(".panel-inner")],r.prototype,"_panelInnerEl",void 0);r=a([w("scb-dropdown")],r);export{r as ScbDropdown};