@expressive/dom 0.8.1 → 0.9.0

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
@@ -54,7 +54,7 @@ const unmount = render(
54
54
 
55
55
  `style` on a component automatically reaches its rendered host root, including through component, fragment, provider, portal, and collection boundaries. A fragment applies it to each host root. Forwarded style overrides the root's own, with the outermost caller winning. A component which reads its `style` prop while rendering owns placement, and nothing is forwarded. It receives a frozen object of the caller's inline declarations - spread, pluck or merge it freely; the caller's classes travel hidden with it. `className` applies to elements only.
56
56
 
57
- A component may register immutable maps with `style(Component, map)`. A `_name` entry is a rule, applied by a truthy `_name` attribute or a matching host tag and emitted as one class named after its source; nested inside a rule it opens a descendant scope. Component names never match - they do not survive minification. Bare keys are declarations, or macro calls where a macro owns the name, and those at the top of a map form a base rule applied to each of the component's host roots. Macros are defined only by `macro()` - within a map, call a plain function instead. `$name` is reserved. `_` attributes never reach the DOM, and `0` or `''` leaves a rule off. A map never reaches inside a child component; only the class chain inherits.
57
+ A component may register immutable maps with `style(Component, map)`. A `_name` entry is a rule, applied by a truthy `_name` attribute or a matching host tag and emitted as one class named after its source; nested inside a rule it opens a descendant scope. Component names never match - they do not survive minification. Bare keys are declarations, or macro calls where a macro owns the name, and those at the top of a map form a base rule applied to each of the component's host roots. Macros are methods of a `Style` subclass, whose `use()` returns the `style` resolving them; a function inside a map is a value, not a definition. `$name` is reserved. `_` attributes never reach the DOM, and `0` or `''` leaves a rule off. A map never reaches inside a child component; only the class chain inherits.
58
58
 
59
59
  ```tsx
60
60
  function Button({ active }: { active: boolean }) {
@@ -67,7 +67,7 @@ style(Button, {
67
67
  });
68
68
  ```
69
69
 
70
- Global maps use `macro(map)` and can live in side-effect imports. Register macros and styles before the first relevant render. A key resolves at its topmost definition; a macro returning its own name falls to the next definition down, then through any `'*'` handler. Unhandled keys reach the host, which joins arrays and rejects functions and objects - units belong to a macro, never a guess.
70
+ Register styles before the component's first render. A key resolves at its topmost definition, the subclass first; a macro returning its own name falls to the next definition down, then through any `'*'` method. Unhandled keys reach the host, which joins arrays and rejects functions and objects - units belong to a macro, never a guess.
71
71
 
72
72
  Inline style always beats classes; among classes, a caller's rule beats the callee's, and a rule carried through more component `style` props wins - independent of render order. `false`, `null`, and `undefined` omit an entry; `0` remains a macro argument.
73
73
 
package/dist/index.d.ts CHANGED
@@ -5,28 +5,11 @@ import { Component, Context, Model } from "@expressive/mvc";
5
5
  //#region src/style/stylesheet.d.ts
6
6
  type Member = Extract<keyof CSSStyleDeclaration, string>;
7
7
  type Settable = { [K in Member]-?: CSSStyleDeclaration[K] extends Function ? never : K }[Member];
8
- type Key = style.Property | keyof macro$1.Registry | `--${string}` | `_${string}` | style.Condition;
9
- type Argument<K extends keyof macro$1.Registry> = macro$1.Registry[K] extends ((value: infer A, ...rest: any[]) => any) ? A : never;
10
- declare namespace macro$1 {
11
- /**
12
- * Macros visible to a style map. A pack augments this interface to declare
13
- * what it registers with `macro()`.
14
- */
15
- interface Registry {}
16
- /**
17
- * Registry entries for the macros in a pack, so one line declares them all:
18
- * `interface Registry extends macro.From<typeof pack> {}`.
19
- */
20
- type From<T> = { [K in keyof T as K extends `_${string}` | `$${string}` | '*' ? never : K]: T[K] };
21
- /** Maps one argument to style, or to keys which resolve further. */
22
- type Fn = (value: any, key: string) => unknown;
23
- /**
24
- * Body of a `macro()` map. A name declared in {@link Registry} must match its
25
- * declaration; an undeclared one is accepted, and becomes checkable at call
26
- * sites once a module augments `Registry` with it.
27
- */
28
- type Map = Partial<Registry> & { [K in `_${string}`]?: style.Map } & Record<string, Fn | style.Map | undefined>;
29
- }
8
+ type Macro<T> = Extract<Exclude<{ [K in keyof T]-?: T[K] extends ((...args: any[]) => unknown) ? K : never }[keyof T], '*'>, string>;
9
+ type Argument<F> = F extends ((...args: infer P) => any) ? P extends [] ? true : P[0] | (undefined extends P[0] ? true : never) : never;
10
+ type Key<T> = style.Property | Macro<T> | `--${string}` | `_${string}` | style.Condition;
11
+ type Layers<T> = readonly (style.Map<T> | Layers<T> | false | null | undefined)[] & { [K in style.Property | Macro<T>]?: unknown };
12
+ type Body<T> = style.Map<T> | Layers<T>;
30
13
  declare namespace style {
31
14
  /** CSS property names, minus the CSSOM's own members. */
32
15
  type Property = Exclude<Settable, 'length' | 'parentRule' | 'cssText'>;
@@ -38,33 +21,40 @@ declare namespace style {
38
21
  /** What a declaration or macro argument may be; never a plain object. */
39
22
  type Value = string | number | boolean | null | undefined | readonly Value[];
40
23
  /**
41
- * Body of a `style()` map. Bare keys are declarations or macro calls,
42
- * `_name` opens a rule or descendant scope, `:state` and `@media …` apply
43
- * their body conditionally, and `$name` is reserved.
24
+ * Body of a `style()` map. Bare keys are declarations or calls to a macro
25
+ * of `T`, `_name` opens a rule or descendant scope, `:state` and `@media …`
26
+ * apply their body conditionally, and `$name` is reserved. A rule or
27
+ * condition body may be an array of maps, merged in order.
44
28
  */
45
- type Map = { [K in Key]?: K extends `_${string}` | Condition ? Map : K extends keyof macro$1.Registry ? Argument<K> | (undefined extends Argument<K> ? true : never) : Value };
29
+ type Map<T = {}> = { [K in Key<T>]?: K extends `_${string}` | Condition ? Body<T> : K extends Macro<T> ? Argument<T[K]> : Value };
30
+ /** A `style()` whose maps may call the macros of `T`. */
31
+ interface Apply<T> {
32
+ <C extends object>(type: C, ...maps: (Map<T> | false | null | undefined)[]): C;
33
+ }
34
+ }
35
+ /**
36
+ * Base class for a macro pack. Each method is a macro, layered over the class
37
+ * it extends; `'*'` handles any key no macro owns.
38
+ */
39
+ declare class Style {
40
+ /** The `style()` for this pack, created once per class. */
41
+ static use<T extends Style>(this: new () => T): style.Apply<T>;
46
42
  }
47
43
  declare function style<T extends object>(type: T, ...maps: (style.Map | false | null | undefined)[]): T;
48
- declare function macro$1(rules: macro$1.Map): macro$1.Map;
49
44
  //#endregion
50
45
  //#region src/style/css.d.ts
51
46
  /**
52
- * Web macro pack. Register with `macro(css)` to opt into pixel units for
53
- * numbers and the `size` shorthand.
47
+ * Web macro pack - pixel units for numbers and the `size` shorthand. Extend
48
+ * it, or use it as is with `Css.use()`.
54
49
  */
55
- declare const css: {
56
- '*': (value: unknown, key: string) => {
57
- [x: string]: unknown;
50
+ declare class Css extends Style {
51
+ '*'(value: unknown, key: string): {
52
+ [key]: unknown;
58
53
  };
59
- size: (value: style.Value) => {
54
+ size(value: style.Value): {
60
55
  width: any;
61
56
  height: any;
62
57
  };
63
- };
64
- declare module '@expressive/dom' {
65
- namespace macro {
66
- interface Registry extends macro.From<typeof css> {}
67
- }
68
58
  }
69
59
  //#endregion
70
60
  //#region src/style/units.d.ts
@@ -73,6 +63,7 @@ declare const em: (...values: number[]) => string;
73
63
  declare const px: (...values: number[]) => string;
74
64
  //#endregion
75
65
  //#region src/style/media.d.ts
66
+ declare const order: readonly ["minWidth", "maxWidth", "minHeight", "maxHeight", "orientation", "hover", "pointer", "prefersColorScheme", "prefersReducedMotion"];
76
67
  interface Query {
77
68
  minWidth?: number | string;
78
69
  maxWidth?: number | string;
@@ -84,7 +75,13 @@ interface Query {
84
75
  prefersColorScheme?: 'light' | 'dark';
85
76
  prefersReducedMotion?: 'reduce' | 'no-preference';
86
77
  }
87
- declare function media(query: Query): `@media ${string}`;
78
+ type Kebab<K extends string> = K extends `${infer A}${infer B}` ? A extends Uppercase<A> ? `-${Lowercase<A>}${Kebab<B>}` : `${A}${Kebab<B>}` : K;
79
+ type Unit<V> = V extends number ? `${V}px` : V & string;
80
+ type Features<Q, O extends readonly string[]> = O extends readonly [infer K extends string, ...infer R extends readonly string[]] ? K extends keyof Q ? Q[K] extends undefined ? Features<Q, R> : [`(${Kebab<K>}: ${Unit<Q[K]>})`, ...Features<Q, R>] : Features<Q, R> : [];
81
+ type Join<T extends readonly string[]> = T extends readonly [infer H extends string, ...infer R extends readonly string[]] ? R extends [] ? H : `${H} and ${Join<R>}` : '';
82
+ type Optional<Q> = { [K in keyof Q]-?: Q[K] extends undefined ? never : undefined extends Q[K] ? K : never }[keyof Q];
83
+ type Media<Q extends Query> = [Optional<Q>] extends [never] ? `@media ${Join<Features<Q, typeof order>>}` : `@media ${string}`;
84
+ declare function media<const Q extends Query>(query: Q): Media<Q>;
88
85
  //#endregion
89
86
  //#region src/render/fiber.d.ts
90
87
  type Container = Element | DocumentFragment;
@@ -92,5 +89,5 @@ type Container = Element | DocumentFragment;
92
89
  //#region src/render/render.d.ts
93
90
  declare function render(node: Node, container: Container): () => void;
94
91
  //#endregion
95
- export { Fragment, type JSX, Portal, createElement, css, em, macro$1 as macro, media, px, rem, render, style };
92
+ export { Css, Fragment, type JSX, Portal, Style, createElement, em, media, px, rem, render, style };
96
93
  //# sourceMappingURL=index.d.ts.map