@teacss/preset-standard 0.5.2 → 0.6.2

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
@@ -12,7 +12,7 @@ bun add @teacss/preset-standard
12
12
  ```
13
13
 
14
14
  ```css
15
- @preset "standard";
15
+ @presets "standard";
16
16
  @source "./src/**/*.{ts,tsx}";
17
17
  @teacss;
18
18
  ```
@@ -35,14 +35,32 @@ separate. `multiplerKeywords` remains a deprecated alias for
35
35
  ## Application shortcuts
36
36
 
37
37
  ```css
38
- @shortcut hstack "d:flex flex-direction:row align-items:center";
39
- @shortcut truncate "overflow:hidden text-overflow:ellipsis white-space:nowrap";
38
+ @shortcut stack-row "d:flex flex-direction:row align-items:center";
39
+ @shortcut text-truncate "overflow:hidden text-overflow:ellipsis white-space:nowrap";
40
40
  ```
41
41
 
42
42
  Declarations may live in the CSS entry, imported CSS, or CSS matched by
43
43
  `@source`. Conditions remain valid on use, and the last declaration of a name
44
44
  wins. Programmatic shortcuts use Core's generic `UserConfig` types.
45
45
 
46
+ ## Paired sizing and logical dividers
47
+
48
+ For text-flow sizing, `size:4x`, `min-size:4x`, and `max-size:4x` set both
49
+ inline and block sizes. For fixed geometry, use `dimensions:4x`,
50
+ `min-dimensions:4x`, and `max-dimensions:4x` for width and height. These are
51
+ ordinary Standard declarations. Values must be accepted by both underlying
52
+ single-axis rules. Variables, arbitrary values, and suffix conditions work as
53
+ they do on those rules. `size:screen` emits `100vi` and `100vb`;
54
+ `dimensions:screen` emits `100vw` and `100vh`.
55
+
56
+ `divide-inline-width:` and `divide-block-width:` draw on logical inline-end
57
+ and block-end edges. `divide-x-width:` and `divide-y-width:` keep physical
58
+ right and bottom edges. `divide-color:` and `divide-style:` supply common
59
+ settings. `divide-inline-color/style:` and `divide-block-color/style:` override
60
+ only the named logical axis. Color and style alone do not draw a divider; each
61
+ axis needs its own width. To change axes at a breakpoint, set the old width to
62
+ `0` and the new width explicitly.
63
+
46
64
  ## Preflight and themes
47
65
 
48
66
  Preflight emits low-specificity reset rules and theme variables. Set
@@ -50,11 +68,11 @@ Preflight emits low-specificity reset rules and theme variables. Set
50
68
  reset while limiting variables to referenced keys (including the reset's sans
51
69
  and monospace families).
52
70
 
53
- Selecting `@preset "standard"` also normalizes headings, links, lists, media,
71
+ Selecting `@presets "standard"` also normalizes headings, links, lists, media,
54
72
  tables, horizontal rules, code typography, and form-control typography. Headings
55
73
  inherit size and weight; links inherit color and decoration; lists lose their
56
74
  markers; images and videos fit their container without losing aspect ratio.
57
- Use utilities or Shortcuts' `prose` family to author their visible presentation.
75
+ Use utilities or Official's `prose` family to author their visible presentation.
58
76
 
59
77
  Small text, sub/sup, titled abbreviations, and progress have consistent baselines.
60
78
  Dialogs and popovers retain native auto-margin centering after the universal
@@ -64,67 +82,227 @@ appearance. Fieldsets use `min-inline-size: 0` so their boxes can shrink inside
64
82
  narrow containers; oversized descendants still need responsive sizing.
65
83
  Grouped options in `select[multiple]` and `select[size]` retain a 20px
66
84
  inline-start indent, following text direction and allowing utility overrides.
67
- Hidden elements remain hidden despite media/summary display resets, while
68
- `hidden="until-found"` (case-insensitive) retains native discovery behavior.
69
- Explicit display utilities can still override this low-specificity baseline.
85
+ The reset enforces native hiding with two global rules:
86
+
87
+ ```css
88
+ :where([hidden]:not([hidden="until-found" i])) { display: none !important; }
89
+ :where([hidden="until-found" i]) { display: revert !important; }
90
+ ```
91
+
92
+ Ordinary display utilities, component CSS and inline styles cannot reveal an
93
+ element with `hidden`; remove the attribute to show it. Explicit `!important`
94
+ declarations still follow the CSS cascade. `until-found` restores the tag's
95
+ native display, with discovery depending on the tag and browser. Prefer `div`
96
+ or `section` containers for discoverable content:
97
+
98
+ ```html
99
+ <section hidden="until-found">Searchable content</section>
100
+ ```
101
+
102
+ These rules run in both default and on-demand preflight. With preflight disabled,
103
+ the application supplies its own hiding rules.
70
104
 
71
105
  Native control appearance, focus outlines, disabled state, and disclosure
72
106
  behavior remain intact. Marker-free semantic lists should use `role="list"`
73
107
  for Safari/VoiceOver. The reset adds no brand palette or global motion policy.
74
- Element-local `reset-*` shortcuts remain in the optional Shortcuts preset;
108
+ Element-local `reset-*` shortcuts belong to the optional Official preset;
75
109
  Standard does not register those classes.
76
110
 
77
- CSS entries declare named variants with `@custom theme <name> {}`. Each emits
78
- zero-specificity variable overrides and a dynamic `theme-<name>` class.
79
- Preset-aware merging treats those classes as one opaque family.
111
+ ### Global role palettes and color scheme
80
112
 
81
- ## Class merging
113
+ Standard has seven 12-step roles: primary → gray, neutral → sage, focused →
114
+ neutral, success → jade, warning → amber, failure → red, and general → blue.
115
+ Use numbered roles directly, such as `bg-color:primary-200 text-color:primary-950`.
116
+ Official adds structure without background/hover/foreground color aliases.
82
117
 
83
- ```ts
84
- import { cn, pluginStandard } from "@teacss/preset-standard/merge";
118
+ The CSS entry registers the selectable built-in physical palettes:
85
119
 
86
- cn("p:4 d:flex", "p:8"); // "d:flex p:8"
87
- cn("p:4", "p:invalid"); // "p:invalid"
120
+ ```css
121
+ @presets "standard,official";
122
+ @primary "gray,gold,red,blue";
123
+ @neutral "sage,slate";
124
+ @focused "gray,blue";
125
+ @success "jade,green";
126
+ @warning "amber,orange";
127
+ @failure "red,ruby";
128
+ @general "blue,cyan";
129
+ @teacss;
88
130
  ```
89
131
 
90
- The `/merge` entry also exports `createStandardMerger()`. Merge uses token
91
- shape and does not validate values. Combine preset plugins for a wider merger:
132
+ Repeated/imported lists union and sort. They enable choices without changing
133
+ defaults; removing every list for a role clears its choices. Only Standard's
134
+ original built-in physical palette names are candidates. Overrides through
135
+ `@custom` or `theme.colors` keep that identity; custom names remain available to
136
+ ordinary color utilities but cannot become role candidates. Enabled palettes
137
+ need all 12 effective steps and no direct/transitive role references, including
138
+ mode overrides, `preflightBase`, and variable fallbacks. Candidate registration
139
+ has no public Theme field; programmatic consumers load the CSS entry with
140
+ `resolveEntryConfig()`.
141
+
142
+ ```html
143
+ <html data-css-primary="blue" data-css-neutral="slate" data-css-scheme="dark">
144
+ <body><p class="text-color:primary-900">Global blue / slate / dark</p></body>
145
+ </html>
146
+ ```
147
+
148
+ Only html role attributes, `data-css-scheme` and configured mode aliases select
149
+ colors. Descendants inherit; the same markers on descendants have no effect.
150
+ Missing, empty, unknown or undeclared role values use configured defaults.
151
+ Focused defaults to final global neutral while preserving explicit default
152
+ step overrides. Valid root focused selection chooses an independent palette.
153
+ Changing root attributes switches registered candidates without regenerating CSS.
154
+
155
+ `@dark` / `@light` inspect html for every final target, including pseudo-elements.
156
+ Without a valid explicit mode, neither condition activates, even when `defaultMode` is
157
+ dark; `defaultMode` names the base table. OS conditions remain independent media
158
+ queries. `modeSelectors: { dark: ".night", light: ".day" }` adds optional aliases
159
+ on html. Canonical `data-css-scheme` wins even when empty/invalid; conflicting
160
+ aliases select neither mode. Aliases are never implicit. Mode names preserve
161
+ case, spaces and punctuation; empty names, NUL and unpaired surrogates are invalid.
162
+
163
+ Theme output uses zero-specificity ordinary html selectors: base variables once,
164
+ mode differences, then independent role mappings. Each role/candidate mapping is
165
+ emitted once, without multiplying it by modes or other roles. `preflightRoot`
166
+ adds explicit re-declaration targets that always use html selections; it does not
167
+ enable local colors. On-demand preflight retains the consumed dependency closure
168
+ through all registered candidates and effective modes. With preflight disabled,
169
+ root mode conditions still work but the application supplies variables.
170
+
171
+ Global `@custom` sets scales and colors; `@custom dark` changes colors only.
172
+ Whole-theme variants and role scheme blocks are unsupported. Color selection
173
+ never resets inherited spacing or changes radius/shadow geometry.
174
+
175
+ ### Spacing scaling
176
+
177
+ The default chain is `--scaling → --spacing → default 1x…9x`:
178
+
179
+ ```css
180
+ --spacing: calc(0.25rem * var(--scaling, 1));
181
+ --spacing-1x: var(--spacing);
182
+ --spacing-5x: calc(var(--spacing) * 6);
183
+ ```
184
+
185
+ Set the existing variable utility on html, such as `$scaling:0.5@sm`, to halve
186
+ numeric and default named spacing at the configured `sm` breakpoint (768px by
187
+ default). Named multipliers remain `1,2,3,4,6,8,10,12,16`. Only the base formula
188
+ reads scaling; no extra multiplier or default `--scaling` declaration is emitted.
189
+
190
+ A root override of `--spacing` replaces the base formula and also changes default
191
+ named steps. Explicit named overrides remain final values; reference `--spacing`
192
+ to make a custom step follow the chain. Fixed lengths and unrelated scales are
193
+ unchanged. Variables resolve where declared, so a descendant-only scaling change
194
+ does not recompute inherited root spacing. Existing `preflightRoot` follows normal
195
+ CSS re-declaration semantics. No density configuration or additional rule is needed.
196
+
197
+ ### Relationship markers
198
+
199
+ `data-css-group` enables anonymous ancestor conditions such as `@group-hover`;
200
+ `data-css-peer` enables preceding-sibling conditions such as `@peer-checked`.
201
+ Named values are ASCII-whitespace-separated lists: `data-css-group="card panel"`
202
+ also enables `@group-hover/card` and `@group-hover/panel`. Presence always
203
+ matches anonymous conditions; an empty value enables only anonymous ones.
204
+ Names are case-sensitive. Group remains descendant matching, peer uses `~`.
205
+
206
+ ## Root language conditions
207
+
208
+ ```html
209
+ <html lang="zh">
210
+ <body><p lang="en" class="p:4 p:10@lang-zh">...</p></body>
211
+ </html>
212
+ ```
213
+
214
+ `@lang-<tag>` compares the complete root `html:root[lang]` value, ignoring ASCII
215
+ case without trimming. Here `@lang-zh` matches and `@lang-en` does not.
216
+ `zh`, `zh-CN`, and `zh-Hans` are independent: `@lang-zh` does not match a root
217
+ value of `zh-CN`. Local `lang` and descendant color markers do not override the root
218
+ language.
219
+ Root elements, descendants, targets, and pseudo-elements share this condition.
220
+
221
+ Use BCP 47 tags: `zh`, `zh-CN`, `zh-Hans`, `zh-Hans-CN`, `es-419`,
222
+ `de-1996`, and `en-u-ca-gregory`. Extlang, private-use (`x-project`), and
223
+ grandfathered (`i-klingon`) forms are also supported. Validation checks structure,
224
+ not registry membership; it does not canonicalize aliases or infer parent tags.
225
+ Tag case is unrestricted: `@lang-zh-CN` and `@lang-zh-cn` match identically.
226
+ Non-ASCII characters, malformed subtags, underscores, whitespace, wildcards,
227
+ and escapes are unmatched. The lowercase `lang-` prefix is reserved: rename custom
228
+ breakpoint keys using it, including invalid language forms. Existing `@max-<name>`
229
+ syntax is unchanged.
230
+
231
+ `@!lang-en` also matches missing/empty root language. Conditions compose with
232
+ states, relations, queries, modes, targets, shortcuts, and `@apply` using AND.
233
+ Conflicting languages never match; repetition follows ordinary suffix behavior.
234
+ The language guard contributes `0,1,0` specificity before existing wrappers;
235
+ `space-*` / `divide-*` keep their zero-specificity selectors.
236
+
237
+ Changing root `lang` updates generated CSS without runtime listeners or
238
+ regeneration, including with preflight disabled. Keep complete tokens in scanned
239
+ sources or safelists; do not escape `@` in HTML/JSX class strings. Each HTML iframe
240
+ uses its own root; propagation across Shadow DOM or independent XML documents
241
+ is unsupported. Applications own translation, `dir`, and SSR's initial language.
242
+
243
+ ## Class merging
92
244
 
93
245
  ```ts
94
- import { createMerger } from "@teacss/classes";
95
- import { pluginIcon } from "@teacss/preset-icons/merge";
96
- import { pluginStandard } from "@teacss/preset-standard/merge";
246
+ import { cn } from "@teacss/classes";
97
247
 
98
- const cn = createMerger({ plugins: [pluginStandard, pluginIcon] });
248
+ cn("p:4 d:flex", "p:8"); // "d:flex p:8"
249
+ cn("p:4", "p:invalid"); // "p:invalid"
250
+ cn("p:2@lang-en", "p:4@lang-en"); // "p:4@lang-en"
251
+ cn("p:2@lang-ZH", "p:4@lang-zh"); // "p:4@lang-zh"
99
252
  ```
100
253
 
254
+ `cn` uses fixed Standard and Icons rules. Install and import `@teacss/classes`
255
+ directly for runtime class composition.
256
+ Merge uses prefix shape and ordered conditions, ignoring ASCII language-tag
257
+ case while preserving each winning token's spelling. It does not validate values
258
+ or condition support: malformed suffixes can merge but emit no CSS.
259
+ Unknown declarations merge
260
+ only by their own prefix; application shortcuts have no cross-prefix footprint.
261
+
101
262
  Native shorthands are emitted before their component overrides. For example,
102
263
  `cn("border:[1px_solid_red]", "border-t-width:4")` retains both classes and
103
264
  produces a 4px top border. Reversing those arguments leaves only the shorthand.
265
+ The same ordering covers place/gap/columns, text families and corner shapes;
266
+ explicit display and overflow can override `line-clamp`'s corresponding declarations.
104
267
 
105
268
  ## Value and composition boundaries
106
269
 
107
270
  - Logical border width/style pairs accept two arbitrary components, such as
108
- `border-a-width:[1px_2px]`; physical x/y and single-edge forms accept one.
271
+ `border-inline-width:[1px_2px]`; physical x/y and single-edge forms accept one.
109
272
  - `[…]` keeps structurally valid arbitrary CSS, including
110
273
  `animation-name:[var(--name)]`. It does not guarantee browser support.
274
+ - Custom-variable values and `font-palette` use the shared structural checks;
275
+ failed bracket/variable decoding cannot fall back to unchecked raw CSS.
276
+ - A configured `DEFAULT` key references its unsuffixed variable: `p:DEFAULT`
277
+ reads `--spacing`, including through negative spacing. Applications supply
278
+ these scale variables when preflight is disabled.
279
+ - Named shadows use global templates and support local color overrides.
280
+ `shadow:$shadow-card` reads a complete raw variable without recoloring;
281
+ `box-shadow:[…]` replaces the whole composed surface.
282
+ - Named animations quote their decoded CSS names to avoid shorthand keyword
283
+ ambiguity. Numeric zero iteration counts remain zero. `animation:spin` rotates
284
+ at `1s linear infinite`; `animation:spinner` fades a spinner leaf from opacity
285
+ `1` to `.25` at `800ms linear infinite`. Duration, timing, and iteration
286
+ utilities override these defaults. Gate decorative motion with `@motion-safe`
287
+ or stop it with `animation:none@motion-reduce`.
111
288
  - Bare background/mask sizes cannot be negative.
112
289
  - Border-spacing axis variables do not inherit into nested tables.
113
290
  - Gradient properties are registered on demand, retaining shared fallbacks
114
291
  and neutral additive-mask layers without registering unrelated families.
115
292
 
116
- ## Bare utilities
293
+ ## Explicit activators
117
294
 
118
- The closed built-in bare-token inventory is:
295
+ Standard utilities all use `property:value`. The following activators accept
296
+ exactly `on`, with ordinary importance and suffix conditions:
119
297
 
120
298
  ```txt
121
- mask-g-linear mask-g-radial mask-g-conic
122
- divide-x divide-y
123
- space-x-reverse space-y-reverse space-a-reverse space-c-reverse
299
+ mask-g-linear:on mask-g-radial:on mask-g-conic:on
300
+ space-x-reverse:on space-y-reverse:on space-inline-reverse:on space-block-reverse:on
124
301
  ```
125
302
 
126
- All other Standard utilities use `property:value`. Values are prefix-specific
127
- and may support theme references, arbitrary values, CSS-wide keywords, `!`, and
128
- trailing conditions.
303
+ Use `divide-x-width:1` / `divide-y-width:1` for 1px child dividers. The former
304
+ nine bare spellings emit nothing; bare names are reserved for registered
305
+ application or Official shortcuts. Removing an activator restores its default;
306
+ `off`, `true`, variable, arbitrary, and CSS-wide values are unsupported.
129
307
 
130
308
  Pre-1.0. Keep tests and documentation aligned when changing vocabulary.
package/dist/index.d.ts CHANGED
@@ -74,7 +74,7 @@ interface ThemeAnimation {
74
74
  interface Theme {
75
75
  /** Named color palette; each color is a 12-step `100...950` scale. */
76
76
  colors?: ColorPalette;
77
- /** Semantic color roles such as `background`, `foreground`, `border`, and `emphasis`. */
77
+ /** Application semantic colors. Presets supply an empty namespace. */
78
78
  semanticColors?: SemanticColors;
79
79
  breakpoint?: Record<string, string>;
80
80
  container?: Record<string, string>;
@@ -100,8 +100,8 @@ interface Theme {
100
100
  /**
101
101
  * Non-default mode color overrides. `theme.colors` and
102
102
  * `theme.semanticColors` are the default mode; each entry here (e.g. `dark`)
103
- * overrides color variables under the mode's class ancestor (`.<mode>`, or the
104
- * configured `dark`/`light` selector). Only declare values that differ. OS
103
+ * contributes to the complete mapping for its `data-css-scheme` on html (or a
104
+ * configured `dark`/`light` alias). Only declare values that differ. OS
105
105
  * preference uses `@os-dark` / `@os-light`.
106
106
  */
107
107
  modes?: Record<string, {
@@ -110,38 +110,19 @@ interface Theme {
110
110
  }>;
111
111
  /** The mode whose palette is `theme.colors` (need not appear in `modes`). @default "light" */
112
112
  defaultMode?: string;
113
- /**
114
- * Named theme variants (`@custom theme <name>`): subtree-scoped variable
115
- * overrides emitted under `:where(.theme-<name>)` after the base and mode
116
- * blocks. The bare `theme-<name>` class activates one. A variant may only
117
- * override values the base theme declares — `@teacss/config` enforces that
118
- * contract for entry-declared variants.
119
- */
120
- themes?: Record<string, ThemeVariant>;
121
- /** Root selector(s) used when emitting preflight CSS custom properties */
113
+ /** Additional declaration points that re-declare the complete theme selected on html. */
122
114
  preflightRoot?: Arrayable<string>;
123
115
  /** Additional CSS custom properties merged after the default theme-derived preflight variables */
124
116
  preflightBase?: Record<string, string | number>;
125
117
  }
126
- /**
127
- * One named theme variant: the scalar scales plus color-only mode overrides
128
- * (entry-authored variants carry only `dark`). Structural records, mode
129
- * bookkeeping, and preflight options stay top-level-theme-only.
130
- */
131
- interface ThemeVariant extends Omit<Theme, "animation" | "modes" | "defaultMode" | "themes" | "preflightRoot" | "preflightBase"> {
132
- modes?: Record<string, {
133
- colors?: ColorPalette;
134
- semanticColors?: SemanticColors;
135
- }>;
136
- }
137
118
  type CustomRule = Rule<Theme>;
138
- /** Ancestor selectors for the class-triggered `dark` / `light` modes. @default `.dark` / `.light` */
119
+ /** Optional html selector aliases for `dark` / `light`; canonical `data-css-scheme` takes precedence. */
139
120
  interface ModeSelectors {
140
121
  dark?: string;
141
122
  light?: string;
142
123
  }
143
124
  interface PresetStandardOptions extends PresetOptions {
144
- /** Override the `dark` / `light` ancestor selectors, e.g. `{ dark: "[data-theme=dark]" }`. */
125
+ /** Add `dark` / `light` html aliases, e.g. `{ dark: ".night" }`; no aliases are enabled by default. */
145
126
  modeSelectors?: ModeSelectors;
146
127
  /**
147
128
  * Container sizes for the `@container-*` conditions, merged over the default