@fluixi-ui/fx 0.1.0-alpha.2 → 0.1.0-alpha.4

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.
Files changed (41) hide show
  1. package/README.md +57 -3
  2. package/dist/index.d.ts +7 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +9 -0
  5. package/dist/lib/animations.d.ts +55 -0
  6. package/dist/lib/animations.d.ts.map +1 -0
  7. package/dist/lib/animations.js +73 -0
  8. package/dist/lib/keyframes.d.ts +70 -0
  9. package/dist/lib/keyframes.d.ts.map +1 -0
  10. package/dist/lib/keyframes.js +63 -0
  11. package/dist/lib/merge.d.ts +1 -1
  12. package/dist/lib/merge.js +1 -1
  13. package/dist/lib/presets.d.ts +67 -0
  14. package/dist/lib/presets.d.ts.map +1 -0
  15. package/dist/lib/presets.js +111 -0
  16. package/dist/lib/resolve.d.ts.map +1 -1
  17. package/dist/lib/resolve.js +23 -0
  18. package/dist/lib/scales.d.ts.map +1 -1
  19. package/dist/lib/scales.js +9 -1
  20. package/dist/lib/selectors.d.ts +9 -0
  21. package/dist/lib/selectors.d.ts.map +1 -1
  22. package/dist/lib/selectors.js +4 -0
  23. package/dist/lib/sheet.d.ts +7 -0
  24. package/dist/lib/sheet.d.ts.map +1 -1
  25. package/dist/lib/sheet.js +30 -1
  26. package/dist/lib/slots.d.ts +19 -0
  27. package/dist/lib/slots.d.ts.map +1 -0
  28. package/dist/lib/slots.js +29 -0
  29. package/dist/lib/types.d.ts +13 -1
  30. package/dist/lib/types.d.ts.map +1 -1
  31. package/dist/lib/utilities.d.ts +98 -0
  32. package/dist/lib/utilities.d.ts.map +1 -0
  33. package/dist/lib/utilities.js +114 -0
  34. package/dist/lib/variants.d.ts +41 -0
  35. package/dist/lib/variants.d.ts.map +1 -0
  36. package/dist/lib/variants.js +16 -0
  37. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  38. package/dist/vite.d.ts +41 -0
  39. package/dist/vite.d.ts.map +1 -0
  40. package/dist/vite.js +182 -0
  41. package/package.json +12 -2
@@ -118,6 +118,10 @@ export const PROP_SCALE = (() => {
118
118
  map['fontFamily'] = 'fontFamily';
119
119
  map['transitionDuration'] = 'duration';
120
120
  map['animationDuration'] = 'duration';
121
+ // Delays are the same kind of value as durations — without this a bare `100` would
122
+ // serialize unitless, which CSS drops.
123
+ map['transitionDelay'] = 'duration';
124
+ map['animationDelay'] = 'duration';
121
125
  map['transitionTimingFunction'] = 'easing';
122
126
  map['animationTimingFunction'] = 'easing';
123
127
  map['opacity'] = 'opacity';
@@ -218,5 +222,9 @@ export function resolveValue(property, value) {
218
222
  export function cssProperty(name) {
219
223
  if (name.startsWith('--'))
220
224
  return name;
221
- return name.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
225
+ // A vendor prefix keeps its leading dash: `webkitLineClamp` is `-webkit-line-clamp`,
226
+ // and camel-to-kebab alone would emit `webkit-line-clamp`, which no browser reads.
227
+ return name
228
+ .replace(/^(webkit|moz|ms|o)(?=[A-Z])/, '-$1')
229
+ .replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
222
230
  }
@@ -63,6 +63,15 @@ export declare const SELECTORS: {
63
63
  _selection: {
64
64
  selector: string;
65
65
  };
66
+ _scrollbar: {
67
+ selector: string;
68
+ };
69
+ _scrollbarThumb: {
70
+ selector: string;
71
+ };
72
+ _scrollbarTrack: {
73
+ selector: string;
74
+ };
66
75
  _first: {
67
76
  selector: string;
68
77
  };
@@ -1 +1 @@
1
- {"version":3,"file":"selectors.d.ts","sourceRoot":"","sources":["../../src/lib/selectors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtE;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCmB,CAAC;AAE1C,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,SAAS,CAAC;AAEjD,KAAK,MAAM,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;AAEhC;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,SAAS,WAAW,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC;AAEtF,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,IAAI,WAAW,CAE7D;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,GAAG,aAAa,CAE7D;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAe3D;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAO3E"}
1
+ {"version":3,"file":"selectors.d.ts","sourceRoot":"","sources":["../../src/lib/selectors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtE;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuCmB,CAAC;AAE1C,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,SAAS,CAAC;AAEjD,KAAK,MAAM,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;AAEhC;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,SAAS,WAAW,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC;AAEtF,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,IAAI,WAAW,CAE7D;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,GAAG,aAAa,CAE7D;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAe3D;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAO3E"}
@@ -22,6 +22,10 @@ export const SELECTORS = {
22
22
  _after: { selector: '&::after' },
23
23
  _placeholder: { selector: '&::placeholder' },
24
24
  _selection: { selector: '&::selection' },
25
+ // Scrollbar styling has no standard selector, and the closed set is the only way in.
26
+ _scrollbar: { selector: '&::-webkit-scrollbar' },
27
+ _scrollbarThumb: { selector: '&::-webkit-scrollbar-thumb' },
28
+ _scrollbarTrack: { selector: '&::-webkit-scrollbar-track' },
25
29
  _first: { selector: '&:first-child' },
26
30
  _last: { selector: '&:last-child' },
27
31
  _odd: { selector: '&:nth-child(odd)' },
@@ -4,6 +4,13 @@ import type { FxResult } from './types.js';
4
4
  * fitted entirely inline never reach the stylesheet at all.
5
5
  */
6
6
  export declare function insertFx(result: FxResult): void;
7
+ /**
8
+ * Register an `@keyframes` rule. Kept apart from the per-render rules because it has a
9
+ * different lifetime: `keyframes()` is called once at module scope, while `insertFx`
10
+ * runs per element. Held in a map so a server that resets between requests still emits
11
+ * the animation — see `resetFx`.
12
+ */
13
+ export declare function registerKeyframes(name: string, body: string): void;
7
14
  /**
8
15
  * Everything inserted so far, for a server render to emit into `<head>`. Render
9
16
  * the result as `<style data-fx-sheet data-fx-tokens="…">`; the client adopts it.
@@ -1 +1 @@
1
- {"version":3,"file":"sheet.d.ts","sourceRoot":"","sources":["../../src/lib/sheet.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAmC3C;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAgB/C;AAMD;;;GAGG;AACH,wBAAgB,SAAS,IAAI;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAK3D;AAED,uFAAuF;AACvF,wBAAgB,OAAO,IAAI,IAAI,CAK9B"}
1
+ {"version":3,"file":"sheet.d.ts","sourceRoot":"","sources":["../../src/lib/sheet.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAoC3C;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAgB/C;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAelE;AAMD;;;GAGG;AACH,wBAAgB,SAAS,IAAI;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAO3D;AAED,uFAAuF;AACvF,wBAAgB,OAAO,IAAI,IAAI,CAQ9B"}
package/dist/lib/sheet.js CHANGED
@@ -3,6 +3,7 @@ const SHEET_ATTRIBUTE = 'data-fx-sheet';
3
3
  const TOKENS_ATTRIBUTE = 'data-fx-tokens';
4
4
  const inserted = new Set();
5
5
  const collected = [];
6
+ const keyframeRules = new Map();
6
7
  let sheet = null;
7
8
  /**
8
9
  * Find or create the sheet. A server-rendered sheet is adopted rather than
@@ -51,6 +52,28 @@ export function insertFx(result) {
51
52
  element.appendChild(document.createTextNode(wrap(result.rules)));
52
53
  element.setAttribute(TOKENS_ATTRIBUTE, [...inserted].join(','));
53
54
  }
55
+ /**
56
+ * Register an `@keyframes` rule. Kept apart from the per-render rules because it has a
57
+ * different lifetime: `keyframes()` is called once at module scope, while `insertFx`
58
+ * runs per element. Held in a map so a server that resets between requests still emits
59
+ * the animation — see `resetFx`.
60
+ */
61
+ export function registerKeyframes(name, body) {
62
+ if (keyframeRules.has(name))
63
+ return;
64
+ keyframeRules.set(name, `@keyframes ${name}{${body}}`);
65
+ if (typeof document === 'undefined') {
66
+ inserted.add(name);
67
+ return;
68
+ }
69
+ // Adopt first: the server sheet's token list may already name this animation.
70
+ const element = styleElement();
71
+ if (inserted.has(name))
72
+ return;
73
+ inserted.add(name);
74
+ element.appendChild(document.createTextNode(wrap(keyframeRules.get(name))));
75
+ element.setAttribute(TOKENS_ATTRIBUTE, [...inserted].join(','));
76
+ }
54
77
  function wrap(rules) {
55
78
  return `@layer flx.fx{${rules}}`;
56
79
  }
@@ -59,8 +82,10 @@ function wrap(rules) {
59
82
  * the result as `<style data-fx-sheet data-fx-tokens="…">`; the client adopts it.
60
83
  */
61
84
  export function collectFx() {
85
+ const animations = [...keyframeRules.values()].map(wrap).join('');
86
+ const body = `${animations}${collected.join('')}`;
62
87
  return {
63
- css: collected.length ? `${LAYER_ORDER}${collected.join('')}` : '',
88
+ css: body ? `${LAYER_ORDER}${body}` : '',
64
89
  tokens: [...inserted].join(','),
65
90
  };
66
91
  }
@@ -68,6 +93,10 @@ export function collectFx() {
68
93
  export function resetFx() {
69
94
  inserted.clear();
70
95
  collected.length = 0;
96
+ // Keyframes survive: they are registered once at module scope, so dropping them
97
+ // would leave every request after the first naming an animation nobody emits.
98
+ for (const name of keyframeRules.keys())
99
+ inserted.add(name);
71
100
  if (sheet && sheet.isConnected)
72
101
  sheet.remove();
73
102
  sheet = null;
@@ -0,0 +1,19 @@
1
+ import type { FxProp } from './types.js';
2
+ /**
3
+ * Reaching a compound component's parts.
4
+ *
5
+ * `sp={{ header: { sticky: true, fx: { gap: 2 } } }}` a part's full props
6
+ * `fx={{ p: 4, sp: { header: { gap: 2 } } }}` only its styles
7
+ *
8
+ * `fx.sp` keeps styling a whole component in one object; `sp` is the general
9
+ * channel, since a part takes props and styling is one of them.
10
+ */
11
+ /** The styles `fx.sp` addresses to one part. */
12
+ export declare function slotFx(fx: FxProp, slot: string): FxProp;
13
+ /**
14
+ * What a part is spread with: its `sp` entry, with the `fx.sp` shorthand merged
15
+ * under its own `fx`. `sp.<part>.fx` wins — it names the part exactly. A
16
+ * component's own defaults merge in at the call site.
17
+ */
18
+ export declare function slot(name: string, fx: FxProp, sp: object | undefined): Record<string, unknown>;
19
+ //# sourceMappingURL=slots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../src/lib/slots.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,YAAY,CAAC;AAElD;;;;;;;;GAQG;AAEH,gDAAgD;AAChD,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAO9F"}
@@ -0,0 +1,29 @@
1
+ import { mergeFx } from './merge.js';
2
+ /**
3
+ * Reaching a compound component's parts.
4
+ *
5
+ * `sp={{ header: { sticky: true, fx: { gap: 2 } } }}` a part's full props
6
+ * `fx={{ p: 4, sp: { header: { gap: 2 } } }}` only its styles
7
+ *
8
+ * `fx.sp` keeps styling a whole component in one object; `sp` is the general
9
+ * channel, since a part takes props and styling is one of them.
10
+ */
11
+ /** The styles `fx.sp` addresses to one part. */
12
+ export function slotFx(fx, slot) {
13
+ const slots = mergeFx(fx).sp;
14
+ return slots?.[slot];
15
+ }
16
+ /**
17
+ * What a part is spread with: its `sp` entry, with the `fx.sp` shorthand merged
18
+ * under its own `fx`. `sp.<part>.fx` wins — it names the part exactly. A
19
+ * component's own defaults merge in at the call site.
20
+ */
21
+ export function slot(name, fx, sp) {
22
+ // A slots type is an interface of named optional parts, not a Record, so it is read
23
+ // positionally. The user-facing typing is on the component's own `sp` prop.
24
+ const own = sp?.[name];
25
+ const shorthand = slotFx(fx, name);
26
+ if (!shorthand)
27
+ return own ?? {};
28
+ return { ...own, fx: mergeFx(shorthand, own?.['fx']) };
29
+ }
@@ -21,7 +21,7 @@ export type RadiusValue = RadiusToken | number | Raw;
21
21
  export type ShadowValue = ShadowToken | Raw;
22
22
  export type BorderWidthValue = BorderWidthToken | number | Raw;
23
23
  /** The value type a property accepts, decided by the scale it belongs to. */
24
- type ValueFor<K> = K extends SpaceProp ? SpaceValue : K extends SizeProp ? SizeValue : K extends ColorProp ? ColorValue : K extends RadiusProp ? RadiusValue : K extends BorderWidthProp ? BorderWidthValue : K extends UnitlessProp ? number | Raw : K extends 'boxShadow' ? ShadowValue : K extends 'fontSize' ? FontSizeToken | number | Raw : K extends 'fontWeight' ? FontWeightToken | number | Raw : K extends 'lineHeight' ? LineHeightToken | number | Raw : K extends 'letterSpacing' ? LetterSpacingToken | number | Raw : K extends 'fontFamily' ? FontFamilyToken | Raw : K extends 'transitionDuration' | 'animationDuration' ? DurationToken | number | Raw : K extends 'transitionTimingFunction' | 'animationTimingFunction' ? EasingToken | Raw : K extends 'opacity' ? OpacityToken | number | Raw : K extends 'zIndex' ? ZIndexToken | number | Raw : string | number;
24
+ type ValueFor<K> = K extends SpaceProp ? SpaceValue : K extends SizeProp ? SizeValue : K extends ColorProp ? ColorValue : K extends RadiusProp ? RadiusValue : K extends BorderWidthProp ? BorderWidthValue : K extends UnitlessProp ? number | Raw : K extends 'boxShadow' ? ShadowValue : K extends 'fontSize' ? FontSizeToken | number | Raw : K extends 'fontWeight' ? FontWeightToken | number | Raw : K extends 'lineHeight' ? LineHeightToken | number | Raw : K extends 'letterSpacing' ? LetterSpacingToken | number | Raw : K extends 'fontFamily' ? FontFamilyToken | Raw : K extends 'transitionDuration' | 'animationDuration' | 'transitionDelay' | 'animationDelay' ? DurationToken | number | Raw : K extends 'transitionTimingFunction' | 'animationTimingFunction' ? EasingToken | Raw : K extends 'opacity' ? OpacityToken | number | Raw : K extends 'zIndex' ? ZIndexToken | number | Raw : string | number;
25
25
  /**
26
26
  * Every writable CSS property, taken from `CSSStyleDeclaration` — the string-valued
27
27
  * members are exactly the properties, which drops its methods and `length`.
@@ -75,11 +75,23 @@ export type ContainerQuery = {
75
75
  } & {
76
76
  [K in `(${string}`]?: FxObject;
77
77
  };
78
+ /**
79
+ * Styles for a compound component's parts, keyed by the slot names that component
80
+ * documents. It carries styles only — a part's other props go through the `sp` prop.
81
+ */
82
+ export type FxSlots = {
83
+ [slot: string]: FxProp;
84
+ };
78
85
  /** A style object: declarations plus nested selector blocks, arbitrarily deep. */
79
86
  export type FxObject = FxDeclarations & {
80
87
  [K in SelectorKey]?: FxObject;
81
88
  } & {
82
89
  _container?: ContainerQuery;
90
+ /**
91
+ * Styles addressed to a compound component's parts, so one `fx` can dress the
92
+ * whole thing. Stripped before resolution — it never reaches CSS.
93
+ */
94
+ sp?: FxSlots;
83
95
  };
84
96
  /**
85
97
  * What an `fx` prop accepts. The array form composes conditionally
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ import type { FxObject } from './types.js';
2
+ /**
3
+ * Everyday `fx` objects, ready to import and merge.
4
+ *
5
+ * An `fx` value is a plain object, so a utility is just a named one — nothing is
6
+ * generated, nothing is resolved until it reaches an element, and anything merged
7
+ * after it wins:
8
+ *
9
+ * fx={mergeFx(flexBetween, gapped(3), { p: 4 })}
10
+ * fx={{ ...card, ...muted }}
11
+ *
12
+ * The line for including one: it's typed several times a week, or it carries a
13
+ * decision — a token, a browser trap, the `min-width: 0` that flex needs before
14
+ * text will truncate. `{ display: 'flex' }` is here because it's typed constantly;
15
+ * a name for every CSS property is not, since that's a second vocabulary for the
16
+ * same thing.
17
+ *
18
+ * Multi-declaration recipes live next door in `presets` (`truncate`, `lineClamp`,
19
+ * `visuallyHidden`, `stack`, `scrollY`, …).
20
+ */
21
+ export declare const flex: FxObject;
22
+ export declare const inlineFlex: FxObject;
23
+ export declare const grid: FxObject;
24
+ export declare const block: FxObject;
25
+ export declare const inlineBlock: FxObject;
26
+ export declare const hidden: FxObject;
27
+ /** Out of sight but still laid out — unlike `hidden`, which collapses the box. */
28
+ export declare const invisible: FxObject;
29
+ export declare const flexRow: FxObject;
30
+ export declare const flexColumn: FxObject;
31
+ export declare const flexWrap: FxObject;
32
+ export declare const flexCenter: FxObject;
33
+ export declare const flexBetween: FxObject;
34
+ export declare const flexEnd: FxObject;
35
+ export declare const flexStart: FxObject;
36
+ export declare const alignCenter: FxObject;
37
+ /**
38
+ * Take the free space. `minWidth: 0` because a flex child defaults to `min-width:
39
+ * auto`, which refuses to shrink below its content — the reason a long string blows
40
+ * out a row instead of truncating.
41
+ */
42
+ export declare const flexFill: FxObject;
43
+ /** The same shrink fix on its own, for a child you don't want to grow. */
44
+ export declare const minW0: FxObject;
45
+ /** Hold your size while siblings take the space. */
46
+ export declare const flexNone: FxObject;
47
+ export declare const fullWidth: FxObject;
48
+ export declare const fullHeight: FxObject;
49
+ export declare const fullSize: FxObject;
50
+ export declare const fillViewport: FxObject;
51
+ export declare const relative: FxObject;
52
+ export declare const absolute: FxObject;
53
+ export declare const fixed: FxObject;
54
+ /** Sticks to the top of its scroll container, above the content it passes. */
55
+ export declare const stickyTop: FxObject;
56
+ export declare const textCenter: FxObject;
57
+ export declare const textStart: FxObject;
58
+ export declare const textEnd: FxObject;
59
+ export declare const nowrap: FxObject;
60
+ export declare const medium: FxObject;
61
+ export declare const semibold: FxObject;
62
+ export declare const bold: FxObject;
63
+ export declare const uppercase: FxObject;
64
+ export declare const capitalize: FxObject;
65
+ /** Secondary text, on the token rather than a hand-picked grey. */
66
+ export declare const muted: FxObject;
67
+ /** Break anywhere rather than let a URL or an ID push the layout wide. */
68
+ export declare const breakWords: FxObject;
69
+ /**
70
+ * Fixed-width digits, so numbers in a column line up and a live counter stops
71
+ * jittering as its digits change.
72
+ */
73
+ export declare const tabularNums: FxObject;
74
+ export declare const bordered: FxObject;
75
+ export declare const borderTop: FxObject;
76
+ export declare const borderBottom: FxObject;
77
+ export declare const rounded: FxObject;
78
+ export declare const pill: FxObject;
79
+ export declare const circle: FxObject;
80
+ /** A full-window scrim, at the layer overlays expect. */
81
+ export declare const scrim: FxObject;
82
+ export declare const pointer: FxObject;
83
+ export declare const notAllowed: FxObject;
84
+ /** Nothing here reacts — clicks pass through to whatever is behind. */
85
+ export declare const inert: FxObject;
86
+ /**
87
+ * The clickable-but-not-a-button recipe: pointer, no text selection on a
88
+ * double-click, and no grey flash on iOS.
89
+ */
90
+ export declare const clickable: FxObject;
91
+ /**
92
+ * The library's focus ring, for something you've made focusable yourself.
93
+ * `:focus-visible`, so a mouse click doesn't ring it — only keyboard focus does.
94
+ */
95
+ export declare const focusRing: FxObject;
96
+ /** Reads as unavailable and stops responding, without the `disabled` attribute. */
97
+ export declare const disabled: FxObject;
98
+ //# sourceMappingURL=utilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../../src/lib/utilities.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Everyday `fx` objects, ready to import and merge.
3
+ *
4
+ * An `fx` value is a plain object, so a utility is just a named one — nothing is
5
+ * generated, nothing is resolved until it reaches an element, and anything merged
6
+ * after it wins:
7
+ *
8
+ * fx={mergeFx(flexBetween, gapped(3), { p: 4 })}
9
+ * fx={{ ...card, ...muted }}
10
+ *
11
+ * The line for including one: it's typed several times a week, or it carries a
12
+ * decision — a token, a browser trap, the `min-width: 0` that flex needs before
13
+ * text will truncate. `{ display: 'flex' }` is here because it's typed constantly;
14
+ * a name for every CSS property is not, since that's a second vocabulary for the
15
+ * same thing.
16
+ *
17
+ * Multi-declaration recipes live next door in `presets` (`truncate`, `lineClamp`,
18
+ * `visuallyHidden`, `stack`, `scrollY`, …).
19
+ */
20
+ /* Display */
21
+ export const flex = { display: 'flex' };
22
+ export const inlineFlex = { display: 'inline-flex' };
23
+ export const grid = { display: 'grid' };
24
+ export const block = { display: 'block' };
25
+ export const inlineBlock = { display: 'inline-block' };
26
+ export const hidden = { display: 'none' };
27
+ /** Out of sight but still laid out — unlike `hidden`, which collapses the box. */
28
+ export const invisible = { visibility: 'hidden' };
29
+ /* Flex arrangement */
30
+ export const flexRow = { display: 'flex', flexDirection: 'row' };
31
+ export const flexColumn = { display: 'flex', flexDirection: 'column' };
32
+ export const flexWrap = { display: 'flex', flexWrap: 'wrap' };
33
+ export const flexCenter = { display: 'flex', alignItems: 'center', justifyContent: 'center' };
34
+ export const flexBetween = { display: 'flex', alignItems: 'center', justifyContent: 'space-between' };
35
+ export const flexEnd = { display: 'flex', alignItems: 'center', justifyContent: 'flex-end' };
36
+ export const flexStart = { display: 'flex', alignItems: 'flex-start' };
37
+ export const alignCenter = { alignItems: 'center' };
38
+ /**
39
+ * Take the free space. `minWidth: 0` because a flex child defaults to `min-width:
40
+ * auto`, which refuses to shrink below its content — the reason a long string blows
41
+ * out a row instead of truncating.
42
+ */
43
+ export const flexFill = { flexGrow: 1, flexBasis: 0, minWidth: 0 };
44
+ /** The same shrink fix on its own, for a child you don't want to grow. */
45
+ export const minW0 = { minWidth: 0 };
46
+ /** Hold your size while siblings take the space. */
47
+ export const flexNone = { flexShrink: 0 };
48
+ /* Size */
49
+ export const fullWidth = { width: '100%' };
50
+ export const fullHeight = { height: '100%' };
51
+ export const fullSize = { width: '100%', height: '100%' };
52
+ export const fillViewport = { minHeight: '100dvh' };
53
+ /* Position */
54
+ export const relative = { position: 'relative' };
55
+ export const absolute = { position: 'absolute' };
56
+ export const fixed = { position: 'fixed' };
57
+ /** Sticks to the top of its scroll container, above the content it passes. */
58
+ export const stickyTop = { position: 'sticky', top: 0, zIndex: 'sticky' };
59
+ /* Text */
60
+ export const textCenter = { textAlign: 'center' };
61
+ export const textStart = { textAlign: 'start' };
62
+ export const textEnd = { textAlign: 'end' };
63
+ export const nowrap = { whiteSpace: 'nowrap' };
64
+ export const medium = { fontWeight: 'medium' };
65
+ export const semibold = { fontWeight: 'semibold' };
66
+ export const bold = { fontWeight: 'bold' };
67
+ export const uppercase = { textTransform: 'uppercase' };
68
+ export const capitalize = { textTransform: 'capitalize' };
69
+ /** Secondary text, on the token rather than a hand-picked grey. */
70
+ export const muted = { color: 'fgMuted' };
71
+ /** Break anywhere rather than let a URL or an ID push the layout wide. */
72
+ export const breakWords = { overflowWrap: 'anywhere', wordBreak: 'break-word' };
73
+ /**
74
+ * Fixed-width digits, so numbers in a column line up and a live counter stops
75
+ * jittering as its digits change.
76
+ */
77
+ export const tabularNums = { fontVariantNumeric: 'tabular-nums' };
78
+ /* Surface */
79
+ export const bordered = { borderWidth: 'thin', borderStyle: 'solid', borderColor: 'border' };
80
+ export const borderTop = { borderTopWidth: 'thin', borderTopStyle: 'solid', borderTopColor: 'border' };
81
+ export const borderBottom = { borderBottomWidth: 'thin', borderBottomStyle: 'solid', borderBottomColor: 'border' };
82
+ export const rounded = { borderRadius: 'md' };
83
+ export const pill = { borderRadius: 'full' };
84
+ export const circle = { borderRadius: 'full', aspectRatio: '1' };
85
+ /** A full-window scrim, at the layer overlays expect. */
86
+ export const scrim = { position: 'fixed', inset: 0, backgroundColor: 'overlay', zIndex: 'overlay' };
87
+ /* Interaction */
88
+ export const pointer = { cursor: 'pointer' };
89
+ export const notAllowed = { cursor: 'not-allowed' };
90
+ /** Nothing here reacts — clicks pass through to whatever is behind. */
91
+ export const inert = { pointerEvents: 'none' };
92
+ /**
93
+ * The clickable-but-not-a-button recipe: pointer, no text selection on a
94
+ * double-click, and no grey flash on iOS.
95
+ */
96
+ export const clickable = {
97
+ cursor: 'pointer',
98
+ userSelect: 'none',
99
+ webkitTapHighlightColor: 'transparent',
100
+ };
101
+ /**
102
+ * The library's focus ring, for something you've made focusable yourself.
103
+ * `:focus-visible`, so a mouse click doesn't ring it — only keyboard focus does.
104
+ */
105
+ export const focusRing = {
106
+ _focusVisible: {
107
+ outlineWidth: 'thick',
108
+ outlineStyle: 'solid',
109
+ outlineColor: 'focusRing',
110
+ outlineOffset: '2px',
111
+ },
112
+ };
113
+ /** Reads as unavailable and stops responding, without the `disabled` attribute. */
114
+ export const disabled = { opacity: 0.5, pointerEvents: 'none', cursor: 'not-allowed' };
@@ -0,0 +1,41 @@
1
+ import type { FxObject, FxProp } from './types.js';
2
+ /**
3
+ * Map a component's props to `fx`.
4
+ *
5
+ * A component with a `tone` and a `size` ends up writing the same lookup by hand every
6
+ * time, usually as a ternary chain that is hard to extend and easy to get out of sync
7
+ * with the prop type. This is that lookup, once:
8
+ *
9
+ * const panel = variants({
10
+ * base: { p: 3, radius: 'md' },
11
+ * variants: {
12
+ * tone: { neutral: { bg: 'surface' }, danger: { bg: 'dangerSubtle' } },
13
+ * size: { sm: { p: 2 }, lg: { p: 4 } },
14
+ * },
15
+ * defaults: { tone: 'neutral' },
16
+ * });
17
+ *
18
+ * panel({ tone: 'danger' }); // FxObject
19
+ *
20
+ * Later groups win over earlier ones, and `base` loses to all of them — declaration
21
+ * order in the config is the precedence. The result is an ordinary `FxObject`, so a
22
+ * caller's own `fx` still merges over it at the element.
23
+ */
24
+ /** A group of mutually exclusive options, e.g. `{ sm: …, md: … }`. */
25
+ export type VariantGroup = Record<string, FxProp>;
26
+ export interface VariantConfig<G extends Record<string, VariantGroup>> {
27
+ /** Applied first, under every selected variant. */
28
+ base?: FxProp;
29
+ /** The groups themselves, in precedence order. */
30
+ variants: G;
31
+ /** Used for any group the caller leaves out. */
32
+ defaults?: {
33
+ [K in keyof G]?: keyof G[K] & string;
34
+ };
35
+ }
36
+ /** What a variant function accepts: one option per group, or nothing. */
37
+ export type VariantSelection<G extends Record<string, VariantGroup>> = {
38
+ [K in keyof G]?: (keyof G[K] & string) | false | null | undefined;
39
+ };
40
+ export declare function variants<G extends Record<string, VariantGroup>>(config: VariantConfig<G>): (selection?: VariantSelection<G>) => FxObject;
41
+ //# sourceMappingURL=variants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variants.d.ts","sourceRoot":"","sources":["../../src/lib/variants.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,sEAAsE;AACtE,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAElD,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC;IACnE,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,QAAQ,EAAE,CAAC,CAAC;IACZ,gDAAgD;IAChD,QAAQ,CAAC,EAAE;SAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM;KAAE,CAAC;CACrD;AAED,yEAAyE;AACzE,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,IAAI;KACpE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS;CAClE,CAAC;AAEF,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,EAC7D,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GACvB,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,QAAQ,CAgB/C"}
@@ -0,0 +1,16 @@
1
+ import { mergeFx } from './merge.js';
2
+ export function variants(config) {
3
+ const groups = Object.keys(config.variants);
4
+ return (selection) => {
5
+ const parts = [config.base];
6
+ for (const group of groups) {
7
+ const chosen = selection?.[group] ?? config.defaults?.[group];
8
+ // `false` selects nothing on purpose — it is how a caller turns a defaulted
9
+ // group off without knowing which option the default was.
10
+ if (chosen == null || chosen === false)
11
+ continue;
12
+ parts.push(config.variants[group][chosen]);
13
+ }
14
+ return mergeFx(...parts);
15
+ };
16
+ }