@salty-css/core 0.1.0-alpha.2 → 0.1.0-alpha.21
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 +83 -0
- package/astro-component-5hrNTCJ5.js +4 -0
- package/astro-component-Dj3enX6K.cjs +4 -0
- package/bin/commands/build.d.ts +2 -0
- package/bin/commands/generate.d.ts +2 -0
- package/bin/commands/init.d.ts +2 -0
- package/bin/commands/update.d.ts +2 -0
- package/bin/commands/version.d.ts +2 -0
- package/bin/confirm-install.d.ts +34 -0
- package/bin/context.d.ts +22 -0
- package/bin/detection/css-file.d.ts +5 -0
- package/bin/frameworks/astro.d.ts +4 -0
- package/bin/frameworks/index.d.ts +13 -0
- package/bin/frameworks/react.d.ts +2 -0
- package/bin/frameworks/types.d.ts +27 -0
- package/bin/integrations/astro.d.ts +11 -0
- package/bin/integrations/eslint.d.ts +6 -0
- package/bin/integrations/index.d.ts +21 -0
- package/bin/integrations/next.d.ts +9 -0
- package/bin/integrations/types.d.ts +29 -0
- package/bin/integrations/vite.d.ts +8 -0
- package/bin/main.cjs +653 -336
- package/bin/main.d.ts +8 -0
- package/bin/main.js +653 -336
- package/bin/package-json.d.ts +21 -0
- package/bin/saltyrc.d.ts +31 -0
- package/bin/templates.d.ts +14 -0
- package/{class-name-generator-B2Pb2obX.cjs → class-name-generator-DVuPkyrS.cjs} +1 -1
- package/{class-name-generator-YeSQe_Ik.js → class-name-generator-DkByUzHU.js} +1 -1
- package/compiler/salty-compiler.cjs +29 -8
- package/compiler/salty-compiler.d.ts +7 -1
- package/compiler/salty-compiler.js +29 -8
- package/config/index.cjs +2 -0
- package/config/index.js +3 -1
- package/css/dynamic-styles.cjs +15 -0
- package/css/dynamic-styles.d.ts +10 -0
- package/css/dynamic-styles.js +15 -0
- package/css/index.cjs +3 -0
- package/css/index.d.ts +1 -0
- package/css/index.js +3 -0
- package/css/keyframes.cjs +1 -1
- package/css/keyframes.js +1 -1
- package/factories/define-font.d.ts +28 -0
- package/factories/index.cjs +128 -0
- package/factories/index.d.ts +1 -0
- package/factories/index.js +128 -0
- package/generators/index.cjs +1 -1
- package/generators/index.js +2 -2
- package/instances/classname-instance.cjs +1 -1
- package/instances/classname-instance.js +1 -1
- package/package.json +5 -1
- package/{parse-styles-CA3TP5n1.cjs → parse-styles-CX1WjafO.cjs} +106 -7
- package/{parse-styles-BTIoYnBr.js → parse-styles-DIqJjXF3.js} +107 -8
- package/parsers/index.cjs +2 -1
- package/parsers/index.d.ts +1 -0
- package/parsers/index.js +4 -3
- package/parsers/parser-regexes.d.ts +3 -0
- package/parsers/strict.d.ts +2 -0
- package/runtime/index.cjs +1 -1
- package/runtime/index.js +1 -1
- package/{salty.config-cqavVm2t.cjs → salty.config-DogY_sSQ.cjs} +1 -1
- package/salty.config-GV37Q-D2.js +4 -0
- package/styled-file-BzmB9_Ez.cjs +12 -0
- package/{react-styled-file-U02jek-B.cjs → styled-file-CPd_rTW2.cjs} +2 -2
- package/{react-styled-file-B99mwk0w.js → styled-file-Cda3EeR6.js} +2 -2
- package/styled-file-DLcgYmGN.js +12 -0
- package/types/config-types.d.ts +10 -1
- package/types/font-types.d.ts +53 -0
- package/{react-vanilla-file-D9px70iK.js → vanilla-file-1kOqbCIM.js} +2 -2
- package/{react-vanilla-file-Bj6XC8GS.cjs → vanilla-file-r0fp2q_m.cjs} +2 -2
- package/salty.config-DjosWdPw.js +0 -4
package/README.md
CHANGED
|
@@ -57,6 +57,7 @@ To get help with problems, [Join Salty CSS Discord server](https://discord.gg/R6
|
|
|
57
57
|
- [defineVariables](#variables) - create CSS variables (tokens) that can be used in any styling function
|
|
58
58
|
- [defineMediaQuery](#media-queries) - create CSS media queries and use them in any styling function
|
|
59
59
|
- [defineTemplates](#templates) - create reusable templates that can be applied when same styles are used over and over again
|
|
60
|
+
- [defineFont](#custom-fonts) - register custom fonts via `@font-face` (or a remote stylesheet) and expose them as a CSS variable
|
|
60
61
|
- [keyframes](#keyframes-animations) - create CSS keyframes animation that can be used and imported in any styling function
|
|
61
62
|
|
|
62
63
|
### Styling helpers & utility
|
|
@@ -319,6 +320,88 @@ Example usage:
|
|
|
319
320
|
styled('div', { base: { textStyle: 'headline.large', card: '20px' } });
|
|
320
321
|
```
|
|
321
322
|
|
|
323
|
+
## Custom fonts
|
|
324
|
+
|
|
325
|
+
Register custom fonts that will be emitted as `@font-face` declarations and exposed as a CSS variable. Mirrors the developer experience of Next.js / Astro font loaders, but generated at build time alongside the rest of your Salty CSS output.
|
|
326
|
+
|
|
327
|
+
The returned object stringifies to its `font-family` value and exposes helpers for explicit usage:
|
|
328
|
+
|
|
329
|
+
- `Font.variable` → CSS variable name (e.g. `--font-inter`)
|
|
330
|
+
- `Font.fontFamily` → final `font-family` string with fallbacks
|
|
331
|
+
- `Font.className` → class that sets the variable + applies the font on a subtree
|
|
332
|
+
- `Font.style` → object you can spread on a React `style` prop
|
|
333
|
+
|
|
334
|
+
```ts
|
|
335
|
+
// /styles/fonts.css.ts
|
|
336
|
+
import { defineFont } from '@salty-css/core/factories';
|
|
337
|
+
|
|
338
|
+
// 1. Local or self-hosted @font-face sources.
|
|
339
|
+
// URLs are passed through as-is (use a public-folder path or a CDN URL).
|
|
340
|
+
export const Inter = defineFont({
|
|
341
|
+
name: 'Inter', // CSS font-family value
|
|
342
|
+
variable: '--font-inter', // Optional — accepts 'font-inter' too; if omitted we derive `--font-<name>-<hash>` from the inputs
|
|
343
|
+
display: 'swap', // Optional default applied to variants without their own `display`
|
|
344
|
+
fallback: ['system-ui', 'sans-serif'], // Optional family fallbacks appended after `name`
|
|
345
|
+
variants: [
|
|
346
|
+
{
|
|
347
|
+
weight: 400,
|
|
348
|
+
style: 'normal',
|
|
349
|
+
// Shorthand: pass a string and the `format()` descriptor is auto-detected
|
|
350
|
+
// from the file extension (woff2, woff, ttf, otf, eot, svg, ttc).
|
|
351
|
+
src: '/fonts/inter-400.woff2',
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
weight: 700,
|
|
355
|
+
style: 'normal',
|
|
356
|
+
// Multiple sources can be a string array — first entry is preferred;
|
|
357
|
+
// the browser picks the first format it supports.
|
|
358
|
+
src: ['/fonts/inter-700.woff2', '/fonts/inter-700.ttf'],
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
weight: 400,
|
|
362
|
+
style: 'italic',
|
|
363
|
+
// Use the `{ url, format }` object form when the URL has no recognisable
|
|
364
|
+
// extension (signed CDN URLs, query-only endpoints, etc.). You can also
|
|
365
|
+
// mix strings and objects in the same array.
|
|
366
|
+
src: ['/fonts/inter-400-italic.woff2', { url: 'https://cdn.example.com/inter-italic', format: 'woff' }],
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
// 2. Remote stylesheet (Google Fonts, etc.). Emits `@import url(...)` and still
|
|
372
|
+
// registers the CSS variable so usage stays the same as the @font-face flow.
|
|
373
|
+
export const InterCdn = defineFont({
|
|
374
|
+
name: 'Inter',
|
|
375
|
+
variable: '--font-inter',
|
|
376
|
+
import: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap',
|
|
377
|
+
});
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Example usage:
|
|
381
|
+
|
|
382
|
+
```tsx
|
|
383
|
+
import { Inter } from './fonts.css';
|
|
384
|
+
import { styled } from '@salty-css/react/styled';
|
|
385
|
+
|
|
386
|
+
// Apply the font globally by attaching its className high up in the tree.
|
|
387
|
+
// This sets `--font-inter` on the subtree and applies `font-family: var(--font-inter)`.
|
|
388
|
+
export const App = ({ children }) => <div className={Inter.className}>{children}</div>;
|
|
389
|
+
|
|
390
|
+
// `Inter` stringifies to its font-family value (with fallbacks), so it can be used directly.
|
|
391
|
+
export const Heading = styled('h1', {
|
|
392
|
+
base: {
|
|
393
|
+
fontFamily: `${Inter}`,
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
// Or reference the CSS variable explicitly.
|
|
398
|
+
export const Body = styled('p', {
|
|
399
|
+
base: {
|
|
400
|
+
fontFamily: `var(${Inter.variable})`,
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
```
|
|
404
|
+
|
|
322
405
|
## Keyframes animations
|
|
323
406
|
|
|
324
407
|
```ts
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
const astroComponent = "---\nimport { <%- styledComponentName %> } from './<%- fileName %>.css';\n\ninterface Props {\n text?: string;\n}\n\nconst { text = 'Lorem ipsum' } = Astro.props;\n---\n\n<<%- styledComponentName %>>\n {text}\n</<%- styledComponentName %>>\n";
|
|
2
|
+
export {
|
|
3
|
+
astroComponent as default
|
|
4
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const astroComponent = "---\nimport { <%- styledComponentName %> } from './<%- fileName %>.css';\n\ninterface Props {\n text?: string;\n}\n\nconst { text = 'Lorem ipsum' } = Astro.props;\n---\n\n<<%- styledComponentName %>>\n {text}\n</<%- styledComponentName %>>\n";
|
|
4
|
+
exports.default = astroComponent;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders a single package spec for display. Translates the internal
|
|
3
|
+
* `'-D <pkg>@<ver>'` shorthand used by `npmInstall` into a `<pkg>@<ver> (dev)`
|
|
4
|
+
* suffix so the user-facing list reads naturally.
|
|
5
|
+
*/
|
|
6
|
+
export declare const formatPackageForDisplay: (spec: string) => string;
|
|
7
|
+
export declare const renderPackageList: (packages: string[]) => string;
|
|
8
|
+
export interface ConfirmInstallOptions {
|
|
9
|
+
/** Streams used for the prompt — defaults to process.stdin/stdout. Allows tests to inject. */
|
|
10
|
+
input?: NodeJS.ReadableStream;
|
|
11
|
+
output?: NodeJS.WritableStream;
|
|
12
|
+
/** Whether the input is a TTY — defaults to process.stdin.isTTY. Allows tests to override. */
|
|
13
|
+
isTTY?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Confirm a batched install. Resolves on success, throws on decline.
|
|
17
|
+
*
|
|
18
|
+
* - `yes=true` or empty `packages` → no prompt, resolves immediately.
|
|
19
|
+
* - Non-TTY without `yes` → throws, telling the user to pass `--yes`.
|
|
20
|
+
* - Otherwise prints the list and asks `Proceed? (y/N)`. Accepts y/yes
|
|
21
|
+
* (case-insensitive); anything else throws to abort the command.
|
|
22
|
+
*/
|
|
23
|
+
export declare const confirmInstall: (packages: string[], yes: boolean, options?: ConfirmInstallOptions) => Promise<void>;
|
|
24
|
+
export interface ConfirmYesNoOptions extends ConfirmInstallOptions {
|
|
25
|
+
/** When true, resolves true without prompting. */
|
|
26
|
+
yes?: boolean;
|
|
27
|
+
/** When true, an empty answer counts as yes. Defaults to false (empty = no). */
|
|
28
|
+
defaultYes?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Generic yes/no prompt. Unlike `confirmInstall`, non-TTY without `yes`
|
|
32
|
+
* resolves `false` instead of throwing — callers can choose policy.
|
|
33
|
+
*/
|
|
34
|
+
export declare const confirmYesNo: (question: string, options?: ConfirmYesNoOptions) => Promise<boolean>;
|
package/bin/context.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { RCFile } from '../types/cli-types';
|
|
2
|
+
import { PackageJson } from './package-json';
|
|
3
|
+
export interface ProjectContext {
|
|
4
|
+
cwd: string;
|
|
5
|
+
projectDir: string;
|
|
6
|
+
relativeProjectPath: string;
|
|
7
|
+
packageJson?: PackageJson;
|
|
8
|
+
rcFile: RCFile;
|
|
9
|
+
cliVersion: string;
|
|
10
|
+
skipInstall: boolean;
|
|
11
|
+
yes: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare const resolveProjectDir: (dir: string, rootDir?: string) => string;
|
|
14
|
+
export interface BuildContextOptions {
|
|
15
|
+
dir: string;
|
|
16
|
+
skipInstall?: boolean;
|
|
17
|
+
/** Skip the install confirmation prompt and install without asking. */
|
|
18
|
+
yes?: boolean;
|
|
19
|
+
/** When false, build context even if package.json is missing (used by commands that should not require one). */
|
|
20
|
+
requirePackageJson?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare const buildContext: (opts: BuildContextOptions) => Promise<ProjectContext>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { FrameworkAdapter } from './types';
|
|
2
|
+
export declare const astroConfigFiles: readonly ["astro.config.mjs", "astro.config.ts", "astro.config.js", "astro.config.cjs"];
|
|
3
|
+
export declare const findAstroConfig: (projectDir: string) => string | null;
|
|
4
|
+
export declare const astroFramework: FrameworkAdapter;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ProjectContext } from '../context';
|
|
2
|
+
import { FrameworkAdapter, FrameworkName } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Adapters are evaluated in this order; the first whose `detect()` returns true wins.
|
|
5
|
+
* React is the final fallback, so its `detect()` always returns true.
|
|
6
|
+
*/
|
|
7
|
+
export declare const frameworkRegistry: FrameworkAdapter[];
|
|
8
|
+
export declare const frameworksByName: Record<FrameworkName, FrameworkAdapter>;
|
|
9
|
+
export declare const detectFramework: (ctx: ProjectContext) => Promise<FrameworkAdapter>;
|
|
10
|
+
export declare const getFramework: (name: string | undefined) => FrameworkAdapter | undefined;
|
|
11
|
+
export type { FrameworkAdapter, FrameworkName } from './types';
|
|
12
|
+
export { reactFramework } from './react';
|
|
13
|
+
export { astroFramework, findAstroConfig, astroConfigFiles } from './astro';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ProjectContext } from '../context';
|
|
2
|
+
import { TemplateKey } from '../templates';
|
|
3
|
+
export type FrameworkName = 'react' | 'astro';
|
|
4
|
+
export interface ComponentTemplates {
|
|
5
|
+
/** Template used for the styled-file when the wrapper component is requested. */
|
|
6
|
+
styled: TemplateKey;
|
|
7
|
+
/** Template used for the wrapper component file. */
|
|
8
|
+
wrapper: TemplateKey;
|
|
9
|
+
/** Extension for the wrapper component file (including dot), e.g. '.tsx' or '.astro'. */
|
|
10
|
+
wrapperExt: string;
|
|
11
|
+
}
|
|
12
|
+
export interface FrameworkAdapter {
|
|
13
|
+
name: FrameworkName;
|
|
14
|
+
/** The path to the framework's source files. */
|
|
15
|
+
srcDirectory: string;
|
|
16
|
+
/** True when this framework matches the project. Adapters are evaluated in registry order. */
|
|
17
|
+
detect(ctx: ProjectContext): Promise<boolean> | boolean;
|
|
18
|
+
/** The runtime npm spec to install for this framework, e.g. `@salty-css/react@1.2.3`. */
|
|
19
|
+
runtimePackage(version: string): string;
|
|
20
|
+
/** Templates used by the `generate` command. */
|
|
21
|
+
templates: {
|
|
22
|
+
/** Template used for a standalone styled-file (no wrapper). */
|
|
23
|
+
styled: TemplateKey;
|
|
24
|
+
/** Optional wrapper component templates. Omit if the framework does not support `--reactComponent`. */
|
|
25
|
+
component?: ComponentTemplates;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BuildIntegrationAdapter, ConfigEdit } from './types';
|
|
2
|
+
export declare const astroPackage: (version: string) => string;
|
|
3
|
+
/**
|
|
4
|
+
* Returns the new content of an Astro config (with saltyIntegration wired in),
|
|
5
|
+
* or `{ content: null }` if the integration is already present or if no safe
|
|
6
|
+
* insertion point was found.
|
|
7
|
+
*/
|
|
8
|
+
export declare const editAstroConfig: (existing: string) => ConfigEdit & {
|
|
9
|
+
warning?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare const astroIntegration: BuildIntegrationAdapter;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { BuildIntegrationAdapter, ConfigEdit } from './types';
|
|
2
|
+
export declare const eslintConfigCandidates: (projectDir: string, rootDir: string) => string[];
|
|
3
|
+
export declare const editEslintConfig: (existing: string, isJsFlat: boolean) => ConfigEdit & {
|
|
4
|
+
warning?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const eslintIntegration: BuildIntegrationAdapter;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ProjectContext } from '../context';
|
|
2
|
+
import { BuildIntegrationAdapter, IntegrationPlan } from './types';
|
|
3
|
+
export declare const buildIntegrationRegistry: BuildIntegrationAdapter[];
|
|
4
|
+
export interface PlannedIntegration {
|
|
5
|
+
name: string;
|
|
6
|
+
configPath: string;
|
|
7
|
+
plan: IntegrationPlan;
|
|
8
|
+
}
|
|
9
|
+
/** Detect every integration that has work to do and compute its plan. */
|
|
10
|
+
export declare const planIntegrations: (ctx: ProjectContext) => Promise<PlannedIntegration[]>;
|
|
11
|
+
/** Execute each previously-planned integration (writes config files). */
|
|
12
|
+
export declare const applyIntegrationPlans: (planned: PlannedIntegration[]) => Promise<{
|
|
13
|
+
name: string;
|
|
14
|
+
configPath: string;
|
|
15
|
+
changed: boolean;
|
|
16
|
+
}[]>;
|
|
17
|
+
export type { BuildIntegrationAdapter, ConfigEdit, IntegrationPlan } from './types';
|
|
18
|
+
export { viteIntegration, editViteConfig, vitePackage } from './vite';
|
|
19
|
+
export { nextIntegration, editNextConfig, nextPackage, nextConfigFiles } from './next';
|
|
20
|
+
export { astroIntegration, editAstroConfig, astroPackage } from './astro';
|
|
21
|
+
export { eslintIntegration, editEslintConfig, eslintConfigCandidates } from './eslint';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BuildIntegrationAdapter, ConfigEdit } from './types';
|
|
2
|
+
export declare const nextConfigFiles: readonly ["next.config.js", "next.config.cjs", "next.config.ts", "next.config.mjs"];
|
|
3
|
+
export declare const nextPackage: (version: string) => string;
|
|
4
|
+
/**
|
|
5
|
+
* Returns the new content of a Next.js config (with withSaltyCss wired in),
|
|
6
|
+
* or `{ content: null }` if the plugin is already present.
|
|
7
|
+
*/
|
|
8
|
+
export declare const editNextConfig: (existing: string) => ConfigEdit;
|
|
9
|
+
export declare const nextIntegration: BuildIntegrationAdapter;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ProjectContext } from '../context';
|
|
2
|
+
export interface IntegrationApplyResult {
|
|
3
|
+
/** Whether any file was edited or any install was performed. */
|
|
4
|
+
changed: boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Pending integration work — the packages it would like installed and a
|
|
8
|
+
* closure that writes the config edits once the install (if any) has run.
|
|
9
|
+
*/
|
|
10
|
+
export interface IntegrationPlan {
|
|
11
|
+
/** Packages to install, using the same `npmInstall` shorthand (e.g. `'-D @salty-css/vite@1.2.3'`). */
|
|
12
|
+
packages: string[];
|
|
13
|
+
execute(): Promise<IntegrationApplyResult>;
|
|
14
|
+
}
|
|
15
|
+
export interface BuildIntegrationAdapter {
|
|
16
|
+
name: string;
|
|
17
|
+
/** Returns the config file path this integration targets, or null when not applicable. */
|
|
18
|
+
detect(ctx: ProjectContext): Promise<string | null> | string | null;
|
|
19
|
+
/**
|
|
20
|
+
* Idempotently produce the work needed to wire the integration in. Returns
|
|
21
|
+
* null when the integration is already wired (nothing to do).
|
|
22
|
+
*/
|
|
23
|
+
plan(ctx: ProjectContext, configPath: string): Promise<IntegrationPlan | null>;
|
|
24
|
+
}
|
|
25
|
+
/** Pure transform — returned by an integration when it knows how to rewrite a config file. */
|
|
26
|
+
export interface ConfigEdit {
|
|
27
|
+
/** New content to write, or null when no edit is needed. */
|
|
28
|
+
content: string | null;
|
|
29
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BuildIntegrationAdapter, ConfigEdit } from './types';
|
|
2
|
+
export declare const vitePackage: (version: string) => string;
|
|
3
|
+
/**
|
|
4
|
+
* Returns the new content of a Vite config (with the salty plugin wired in),
|
|
5
|
+
* or `{ content: null }` if the plugin is already present.
|
|
6
|
+
*/
|
|
7
|
+
export declare const editViteConfig: (existing: string) => ConfigEdit;
|
|
8
|
+
export declare const viteIntegration: BuildIntegrationAdapter;
|