esm-styles 0.2.4 → 0.2.6

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
@@ -8,8 +8,7 @@ A CSS-in-JS solution for JavaScript/TypeScript projects.
8
8
  - Build CSS from organized source files with a simple CLI
9
9
  - CSS layering support for proper style encapsulation
10
10
  - Media query and device/theme selectors with shorthands
11
- - CSS variables with inheritance between themes
12
- - Supporting modules for easy CSS variable usage
11
+ - CSS variable sets for different themes and devices
13
12
 
14
13
  ## Installation
15
14
 
@@ -21,28 +20,63 @@ npm install esm-styles
21
20
 
22
21
  ### Basic Concept
23
22
 
24
- ESM Styles lets you write CSS in JavaScript objects with a natural syntax that converts to proper CSS:
23
+ ESM Styles lets you write and store styles in JavaScript this way:
25
24
 
26
25
  ```js
27
- // component.styles.mjs
26
+ // article.styles.mjs
27
+ import $device from './$device.mjs'
28
+ import $theme from './$theme.mjs'
29
+ import { card } from './card.styles.mjs'
30
+
28
31
  export default {
29
- button: {
30
- backgroundColor: '#4285f4',
31
- color: 'white',
32
- padding: '10px 20px',
33
- borderRadius: '4px',
32
+ article: {
33
+ display: 'flex',
34
+
35
+ card,
34
36
 
35
- ':hover': {
36
- backgroundColor: '#3367d6',
37
+ '@max-tablet': {
38
+ flexDirection: 'column',
37
39
  },
38
40
 
39
- '@media (max-width: 768px)': {
40
- padding: '8px 16px',
41
+ button: {
42
+ borderRadius: $device.radii.md,
43
+ backgroundColor: $theme.paper.tinted,
44
+
45
+ '@dark': {
46
+ fontWeight: 300,
47
+ },
41
48
  },
42
49
  },
43
50
  }
44
51
  ```
45
52
 
53
+ ### Sample Directory Structure
54
+
55
+ ```
56
+ monorepo/
57
+ ├── package.json
58
+ └── packages/
59
+ ├── app/
60
+ │ ├── package.json
61
+ │ └── src/
62
+ │ ├── css/
63
+ │ ├── styles.css
64
+ │ └── components/
65
+ │ ├── article.tsx
66
+ │ ├── button.tsx
67
+ │ └── card.tsx
68
+ └── styles/
69
+ ├── $device.mjs
70
+ ├── $theme.mjs
71
+ ├── components/
72
+ │ ├── article.styles.mjs
73
+ │ ├── button.styles.mjs
74
+ │ └── card.styles.mjs
75
+ ├── components.styles.mjs
76
+ ├── esm-styles.config.js
77
+ └── package.json
78
+ ```
79
+
46
80
  ### CLI Usage
47
81
 
48
82
  Build your styles by creating a configuration file and running the CLI:
package/dist/lib/build.js CHANGED
@@ -4,6 +4,7 @@ import { getMediaShorthands } from './utils/media-shorthand.js';
4
4
  import { isEndValue } from './utils/index.js';
5
5
  import path from 'node:path';
6
6
  import fs from 'node:fs/promises';
7
+ // import { inspect } from 'node:util'
7
8
  import _ from 'lodash';
8
9
  export async function build(configPath = 'esm-styles.config.js') {
9
10
  // --- Supporting module generation ---
@@ -19,7 +20,7 @@ export async function build(configPath = 'esm-styles.config.js') {
19
20
  const sourcePath = path.join(basePath, config.sourcePath || '');
20
21
  const outputPath = path.join(basePath, config.outputPath || '');
21
22
  const suffix = config.sourceFilesSuffix || '.styles.mjs';
22
- const layers = config.layers || [];
23
+ const floors = config.floors || [];
23
24
  const mainCssFile = config.mainCssFile || 'styles.css';
24
25
  // Merge media shorthands
25
26
  const mediaShorthands = getMediaShorthands(config);
@@ -161,41 +162,64 @@ export async function build(configPath = 'esm-styles.config.js') {
161
162
  await fs.writeFile(supportingModulePath, moduleContent, 'utf8');
162
163
  }
163
164
  }
164
- // 4. Process each layer (legacy, keep for now)
165
- for (const layer of layers) {
166
- const inputFile = path.join(sourcePath, `${layer}${suffix}`);
167
- const outputFile = path.join(outputPath, `${layer}.css`);
165
+ // 4. Process each floor (replaces legacy layers)
166
+ const importFloors = config.importFloors || floors.map((f) => f.source);
167
+ // Track unique layer names in order of first appearance (for imported floors only)
168
+ const uniqueLayers = [];
169
+ // Track output files for each floor
170
+ const floorFiles = [];
171
+ for (const floor of floors) {
172
+ const { source, layer } = floor;
173
+ const inputFile = path.join(sourcePath, `${source}${suffix}`);
174
+ const outputFile = path.join(outputPath, `${source}.css`);
168
175
  const fileUrl = pathToFileUrl(inputFile).href + `?update=${Date.now()}`;
169
176
  const stylesObj = (await import(fileUrl)).default;
170
- // Always call getCss for the layer object, so media queries are rendered
171
177
  const css = getCss(stylesObj, {
172
178
  ...mediaShorthands,
173
179
  globalRootSelector: config.globalRootSelector,
174
180
  });
175
- const wrappedCss = `@layer ${layer} {\n${css}\n}`;
181
+ let wrappedCss = css;
182
+ if (layer) {
183
+ // add layer to order in any case, even if the floor is not imported
184
+ if (!uniqueLayers.includes(layer)) {
185
+ uniqueLayers.push(layer);
186
+ }
187
+ wrappedCss = `@layer ${layer} {\n${css}\n}`;
188
+ }
176
189
  await fs.writeFile(outputFile, wrappedCss, 'utf8');
177
- cssFiles.push({ layer, file: `${layer}.css` });
190
+ floorFiles.push({ file: `${source}.css`, layer, source });
191
+ cssFiles.push({ floor: source, file: `${source}.css`, layer });
178
192
  }
179
193
  // 5. Create main CSS file
180
194
  const mainCssPath = path.join(outputPath, mainCssFile);
195
+ // Type guard for cssFiles entries with type 'global' or 'media'
196
+ function isGlobalOrMedia(f) {
197
+ return ((f.type === 'global' || f.type === 'media') && typeof f.file === 'string');
198
+ }
181
199
  // Compose imports for variable sets
182
- const varImports = cssFiles
183
- .filter((f) => f.type === 'global' || f.type === 'media')
184
- .map((f) => {
200
+ function toImportStatement(f) {
185
201
  if (f.mediaQuery) {
186
202
  return `@import '${f.file}' ${f.mediaQuery};`;
187
203
  }
188
204
  return `@import '${f.file}';`;
189
- })
205
+ }
206
+ const varImports = cssFiles.filter(isGlobalOrMedia)
207
+ .map(toImportStatement)
190
208
  .join('\n');
191
- // Compose imports for layers
192
- const layerFiles = cssFiles.filter((f) => f.layer).map((f) => f.file);
193
- const layerNames = cssFiles
194
- .filter((f) => f.layer)
195
- .map((f) => f.layer)
196
- .join(', ');
197
- const layerImports = layerFiles.map((f) => `@import '${f}';`).join('\n');
198
- const mainCss = [layerNames ? `@layer ${layerNames};` : '', layerImports, varImports]
209
+ // Compose imports for floors (in order, only those in importFloors)
210
+ function isImportedFloor(f) {
211
+ return importFloors.includes(f.source);
212
+ }
213
+ function importStatement(f) {
214
+ return `@import '${f.file}';`;
215
+ }
216
+ const importedFloorFiles = floorFiles.filter(isImportedFloor);
217
+ const floorImports = importedFloorFiles.map(importStatement).join('\n');
218
+ const mainCss = [
219
+ uniqueLayers.length ? `@layer ${uniqueLayers.join(', ')};` : '',
220
+ floorImports,
221
+ varImports,
222
+ ]
199
223
  .filter(Boolean)
200
224
  .join('\n') + '\n';
201
225
  await fs.writeFile(mainCssPath, mainCss, 'utf8');
@@ -73,12 +73,21 @@ export default {
73
73
  outputPath: 'css',
74
74
  sourceFilesSuffix: '.styles.mjs',
75
75
 
76
- // Input layers - order matters
77
- layers: ['defaults', 'components', 'layout'],
76
+ // Input files and their layers (order of layers matters)
77
+ floors: [
78
+ { source: 'defaults', layer: 'defaults' }, // wrap in layer 'defaults'
79
+ { source: 'components', layer: 'components' }, // wrap in layer 'components'
80
+ { source: 'layout', layer: 'layout' }, // wrap in layer 'layout'
81
+ { source: 'basic' }, // stay out of any layer
82
+ { source: 'more-layout', layer: 'layout' }, // wrap in layer 'layout'
83
+ ],
78
84
 
79
85
  // Output
80
86
  mainCssFile: 'styles.css',
81
87
 
88
+ // floors to include in the main CSS file
89
+ importFloors: ['defaults', 'components', 'layout'],
90
+
82
91
  // CSS Variables configuration
83
92
  globalVariables: 'global',
84
93
  globalRootSelector: ':root',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "esm-styles",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "A library for working with ESM styles",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",