css-in-props 3.5.1 → 3.6.1

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 ADDED
@@ -0,0 +1,68 @@
1
+ # css-in-props
2
+
3
+ CSS properties as component props for DOMQL elements. Transforms design-system-aware props into CSS classes via Emotion.
4
+
5
+ ## What it does
6
+
7
+ - Transforms component props (`theme`, `color`, `background`, `border`, `shadow`, etc.) into resolved CSS
8
+ - Resolves design system tokens (colors, spacing, typography, themes) from `@symbo.ls/scratch`
9
+ - Handles media queries (`@dark`, `@mobileS`, etc.) and pseudo selectors (`:hover`, `:focus`) as prop prefixes
10
+ - Generates Emotion CSS classes for optimized rendering
11
+
12
+ ## Theme prop
13
+
14
+ The `theme` prop resolves theme definitions into CSS variables. Theme switching is handled entirely by CSS — no DOMQL re-renders needed.
15
+
16
+ ```javascript
17
+ const Card = {
18
+ theme: 'primary', // uses --theme-primary-* CSS vars
19
+ // themeModifier: 'dark', // optional: force a specific scheme on this component
20
+ }
21
+ ```
22
+
23
+ When `globalTheme` is `'auto'` (default), CSS variables switch automatically via `prefers-color-scheme` media queries and `[data-theme]` selectors.
24
+
25
+ ## Props reference
26
+
27
+ | Category | Props |
28
+ |----------|-------|
29
+ | Theme | `theme`, `color`, `background`, `backgroundColor`, `borderColor` |
30
+ | Border | `border`, `borderLeft`, `borderTop`, `borderRight`, `borderBottom`, `outline` |
31
+ | Shadow | `shadow`, `boxShadow`, `textShadow` |
32
+ | Text | `textStroke` |
33
+ | Image | `backgroundImage` |
34
+ | Layout | `outlineOffset` |
35
+
36
+ ## Media and selector props
37
+
38
+ Props can be prefixed with media queries or selectors:
39
+
40
+ ```javascript
41
+ const Button = {
42
+ background: 'blue',
43
+ ':hover': { background: 'darkblue' },
44
+ '@mobileS': { padding: 'A' },
45
+ '.active': { background: 'green' }
46
+ }
47
+ ```
48
+
49
+ ### `transformersByPrefix`
50
+
51
+ The prefix-to-handler registry that powers media queries, selectors, conditionals, and variables. Each key is a single-character prefix that triggers a specific transformer when found at the start of a prop key:
52
+
53
+ | Prefix | Handler | Example |
54
+ |--------|---------|---------|
55
+ | `@` | Media query | `@mobileS`, `@dark`, `@print` |
56
+ | `:` | Pseudo selector | `:hover`, `:focus`, `:first-child` |
57
+ | `[` | Attribute selector | `[disabled]`, `[data-active]` |
58
+ | `>` | Child combinator | `> .child` |
59
+ | `&` | Self selector | `&.active` |
60
+ | `$` | Case conditional | `$isActive` |
61
+ | `.` | Truthy conditional | `.visible` |
62
+ | `!` | Falsy conditional | `!hidden` |
63
+ | `-` | CSS variable | `--my-var` |
64
+ | `*`, `+`, `~` | CSS combinators | `* div`, `+ .sibling`, `~ .general` |
65
+
66
+ ```javascript
67
+ import { transformersByPrefix } from 'css-in-props'
68
+ ```
@@ -18,63 +18,13 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var transform_exports = {};
20
20
  __export(transform_exports, {
21
- extractCSSfromProps: () => extractCSSfromProps,
22
21
  transformClassname: () => transformClassname
23
22
  });
24
23
  module.exports = __toCommonJS(transform_exports);
25
24
  var import_utils = require("@domql/utils");
26
- var import_atoms = require("@symbo.ls/atoms");
27
- var import_props = require("./props");
28
- var import_defaults = require("./props/defaults");
29
- const transformClassname = (element, restProps = {}) => {
30
- const classCss = {};
31
- const { props, classlist: elementClass } = element;
25
+ var import_transform = require("./transform");
26
+ const transformClassname = (element) => {
27
+ const { props } = element;
32
28
  if (!(0, import_utils.isObject)(props)) return;
33
- for (const key in props) {
34
- const setter = import_atoms.keySetters[key.slice(0, 1)];
35
- const hasCSS = elementClass[key];
36
- if (setter) setter(key, props[key], classCss, element, true);
37
- else if ((0, import_utils.isFunction)(hasCSS)) {
38
- const stack = hasCSS(element, element.state, element.context);
39
- const exec = (0, import_utils.isArray)(stack) ? stack.reduce((a, c) => {
40
- return (0, import_utils.merge)(a, c);
41
- }, {}) : stack;
42
- (0, import_utils.deepMerge)(classCss, exec);
43
- } else if (key === "style") {
44
- (0, import_utils.deepMerge)(classCss, props[key]);
45
- } else restProps[key] = props[key];
46
- }
47
- return classCss;
48
- };
49
- const extractCSSfromProps = (element) => {
50
- const { props: defProps } = element;
51
- const css = {};
52
- const props = {};
53
- for (const key in defProps) {
54
- const val = defProps[key];
55
- const mediaProp = import_atoms.keySetters[key.slice(0, 1)];
56
- if (mediaProp) {
57
- mediaProp(key, defProps[key], css, element, true);
58
- continue;
59
- }
60
- const preprop = import_props.CSS_PROPS_REGISTRY[key];
61
- if (preprop) {
62
- const stack = preprop(element, element.state, element.context);
63
- const exec = (0, import_utils.isArray)(stack) ? stack.reduce((a, c) => {
64
- return (0, import_utils.merge)(a, c);
65
- }, {}) : stack;
66
- (0, import_utils.deepMerge)(css, exec);
67
- continue;
68
- }
69
- if (key === "style") {
70
- (0, import_utils.deepMerge)(css, defProps[key]);
71
- continue;
72
- }
73
- if (import_defaults.DEFAULT_CSS_PROPERTIES_LIST.has(key)) {
74
- css[key] = val;
75
- continue;
76
- }
77
- props[key] = val;
78
- }
79
- return { css, props };
29
+ return (0, import_transform.useCssInProps)(props, element);
80
30
  };
@@ -31,16 +31,11 @@ const getSystemGlobalTheme = ({ context, state }) => {
31
31
  const THEME_PROPS = {
32
32
  theme: (val, element) => {
33
33
  const { props } = element;
34
- const globalTheme = getSystemGlobalTheme(element);
35
34
  if (!val) return;
36
- const hasSubtheme = val.includes(" ") && !val.includes("@");
37
- const globalThemeForced = `@${props.themeModifier || globalTheme}`;
38
- if (hasSubtheme) {
39
- const themeAppliedInVal = val.split(" ");
40
- themeAppliedInVal.splice(1, 0, globalThemeForced);
41
- return (0, import_scratch.getMediaTheme)(themeAppliedInVal);
42
- } else if (val.includes("@{globalTheme}")) val.replace("@{globalTheme}", globalThemeForced);
43
- return (0, import_scratch.getMediaTheme)(val, `@${props.themeModifier || globalTheme}`);
35
+ if (props.themeModifier) {
36
+ return (0, import_scratch.getMediaTheme)(val, `@${props.themeModifier}`);
37
+ }
38
+ return (0, import_scratch.getMediaTheme)(val);
44
39
  },
45
40
  color: (val, element) => {
46
41
  const globalTheme = getSystemGlobalTheme(element);
@@ -16,3 +16,4 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
16
16
  var transform_exports = {};
17
17
  module.exports = __toCommonJS(transform_exports);
18
18
  __reExport(transform_exports, require("./executors"), module.exports);
19
+ __reExport(transform_exports, require("./transformers"), module.exports);
@@ -1,60 +1,10 @@
1
- import { merge, deepMerge, isFunction, isObject, isArray } from "@domql/utils";
2
- import { keySetters } from "@symbo.ls/atoms";
3
- import { CSS_PROPS_REGISTRY } from "./props";
4
- import { DEFAULT_CSS_PROPERTIES_LIST } from "./props/defaults";
5
- const transformClassname = (element, restProps = {}) => {
6
- const classCss = {};
7
- const { props, classlist: elementClass } = element;
1
+ import { isObject } from "@domql/utils";
2
+ import { useCssInProps } from "./transform";
3
+ const transformClassname = (element) => {
4
+ const { props } = element;
8
5
  if (!isObject(props)) return;
9
- for (const key in props) {
10
- const setter = keySetters[key.slice(0, 1)];
11
- const hasCSS = elementClass[key];
12
- if (setter) setter(key, props[key], classCss, element, true);
13
- else if (isFunction(hasCSS)) {
14
- const stack = hasCSS(element, element.state, element.context);
15
- const exec = isArray(stack) ? stack.reduce((a, c) => {
16
- return merge(a, c);
17
- }, {}) : stack;
18
- deepMerge(classCss, exec);
19
- } else if (key === "style") {
20
- deepMerge(classCss, props[key]);
21
- } else restProps[key] = props[key];
22
- }
23
- return classCss;
24
- };
25
- const extractCSSfromProps = (element) => {
26
- const { props: defProps } = element;
27
- const css = {};
28
- const props = {};
29
- for (const key in defProps) {
30
- const val = defProps[key];
31
- const mediaProp = keySetters[key.slice(0, 1)];
32
- if (mediaProp) {
33
- mediaProp(key, defProps[key], css, element, true);
34
- continue;
35
- }
36
- const preprop = CSS_PROPS_REGISTRY[key];
37
- if (preprop) {
38
- const stack = preprop(element, element.state, element.context);
39
- const exec = isArray(stack) ? stack.reduce((a, c) => {
40
- return merge(a, c);
41
- }, {}) : stack;
42
- deepMerge(css, exec);
43
- continue;
44
- }
45
- if (key === "style") {
46
- deepMerge(css, defProps[key]);
47
- continue;
48
- }
49
- if (DEFAULT_CSS_PROPERTIES_LIST.has(key)) {
50
- css[key] = val;
51
- continue;
52
- }
53
- props[key] = val;
54
- }
55
- return { css, props };
6
+ return useCssInProps(props, element);
56
7
  };
57
8
  export {
58
- extractCSSfromProps,
59
9
  transformClassname
60
10
  };
@@ -17,16 +17,11 @@ const getSystemGlobalTheme = ({ context, state }) => {
17
17
  const THEME_PROPS = {
18
18
  theme: (val, element) => {
19
19
  const { props } = element;
20
- const globalTheme = getSystemGlobalTheme(element);
21
20
  if (!val) return;
22
- const hasSubtheme = val.includes(" ") && !val.includes("@");
23
- const globalThemeForced = `@${props.themeModifier || globalTheme}`;
24
- if (hasSubtheme) {
25
- const themeAppliedInVal = val.split(" ");
26
- themeAppliedInVal.splice(1, 0, globalThemeForced);
27
- return getMediaTheme(themeAppliedInVal);
28
- } else if (val.includes("@{globalTheme}")) val.replace("@{globalTheme}", globalThemeForced);
29
- return getMediaTheme(val, `@${props.themeModifier || globalTheme}`);
21
+ if (props.themeModifier) {
22
+ return getMediaTheme(val, `@${props.themeModifier}`);
23
+ }
24
+ return getMediaTheme(val);
30
25
  },
31
26
  color: (val, element) => {
32
27
  const globalTheme = getSystemGlobalTheme(element);
@@ -1 +1,2 @@
1
1
  export * from "./executors";
2
+ export * from "./transformers";
@@ -38,9 +38,11 @@ var CssInProps = (() => {
38
38
  POSITION_PROPS: () => POSITION_PROPS,
39
39
  THEME_PROPS: () => THEME_PROPS,
40
40
  TIMING_PROPS: () => TIMING_PROPS,
41
+ applyTrueProps: () => applyTrueProps,
41
42
  exetuteClassPerComponent: () => exetuteClassPerComponent,
42
43
  getSystemGlobalTheme: () => getSystemGlobalTheme,
43
44
  transformEmotion: () => transformEmotion,
45
+ transformersByPrefix: () => transformersByPrefix,
44
46
  useCssInProps: () => useCssInProps,
45
47
  usePropsAsCSS: () => usePropsAsCSS,
46
48
  useSelectorsAsCSS: () => useSelectorsAsCSS
@@ -376,16 +378,11 @@ var CssInProps = (() => {
376
378
  var THEME_PROPS = {
377
379
  theme: (val, element) => {
378
380
  const { props } = element;
379
- const globalTheme = getSystemGlobalTheme(element);
380
381
  if (!val) return;
381
- const hasSubtheme = val.includes(" ") && !val.includes("@");
382
- const globalThemeForced = `@${props.themeModifier || globalTheme}`;
383
- if (hasSubtheme) {
384
- const themeAppliedInVal = val.split(" ");
385
- themeAppliedInVal.splice(1, 0, globalThemeForced);
386
- return (0, import_scratch5.getMediaTheme)(themeAppliedInVal);
387
- } else if (val.includes("@{globalTheme}")) val.replace("@{globalTheme}", globalThemeForced);
388
- return (0, import_scratch5.getMediaTheme)(val, `@${props.themeModifier || globalTheme}`);
382
+ if (props.themeModifier) {
383
+ return (0, import_scratch5.getMediaTheme)(val, `@${props.themeModifier}`);
384
+ }
385
+ return (0, import_scratch5.getMediaTheme)(val);
389
386
  },
390
387
  color: (val, element) => {
391
388
  const globalTheme = getSystemGlobalTheme(element);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "css-in-props",
3
3
  "description": "Utilize props as CSS methods",
4
4
  "author": "symbo.ls",
5
- "version": "3.5.1",
5
+ "version": "3.6.1",
6
6
  "repository": "https://github.com/symbo-ls/smbls",
7
7
  "type": "module",
8
8
  "module": "./dist/esm/index.js",
@@ -12,13 +12,15 @@
12
12
  "exports": {
13
13
  ".": {
14
14
  "import": "./dist/esm/index.js",
15
- "require": "./dist/cjs/index.js",
16
- "browser": "./dist/esm/index.js",
17
- "default": "./dist/esm/index.js"
18
- }
15
+ "require": "./dist/cjs/index.js"
16
+ },
17
+ "./src/*": "./src/*.js",
18
+ "./src/props": "./src/props/index.js"
19
19
  },
20
20
  "source": "src/index.js",
21
- "publishConfig": {},
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
22
24
  "scripts": {
23
25
  "copy:package:cjs": "cp ../../build/package-cjs.json dist/cjs/package.json",
24
26
  "build:esm": "cross-env NODE_ENV=$NODE_ENV esbuild $(find src -name '*.js') --target=es2020 --format=esm --outdir=dist/esm --define:process.env.NODE_ENV=process.env.NODE_ENV",
@@ -33,11 +35,9 @@
33
35
  "src"
34
36
  ],
35
37
  "dependencies": {
36
- "@domql/utils": "^3.5.1",
37
- "@symbo.ls/atoms": "^3.5.1",
38
- "@symbo.ls/emotion": "^3.5.1",
39
- "@symbo.ls/scratch": "^3.5.1",
40
- "smbls": "^3.5.1"
38
+ "@domql/utils": "^3.6.1",
39
+ "@symbo.ls/emotion": "^3.6.1",
40
+ "@symbo.ls/scratch": "^3.6.1"
41
41
  },
42
42
  "gitHead": "9fc1b79b41cdc725ca6b24aec64920a599634681",
43
43
  "browser": "./dist/esm/index.js",
package/src/_transform.js CHANGED
@@ -1,79 +1,10 @@
1
1
  'use strict'
2
2
 
3
- import { merge, deepMerge, isFunction, isObject, isArray } from '@domql/utils'
4
- import { keySetters } from '@symbo.ls/atoms'
5
-
6
- import { CSS_PROPS_REGISTRY } from './props'
7
- import { DEFAULT_CSS_PROPERTIES_LIST } from './props/defaults'
8
-
9
- export const transformClassname = (
10
- element,
11
- restProps = {}
12
- ) => {
13
- const classCss = {}
14
- const { props, classlist: elementClass } = element
3
+ import { isObject } from '@domql/utils'
4
+ import { useCssInProps } from './transform'
15
5
 
6
+ export const transformClassname = (element) => {
7
+ const { props } = element
16
8
  if (!isObject(props)) return
17
-
18
- for (const key in props) {
19
- const setter = keySetters[key.slice(0, 1)]
20
- const hasCSS = elementClass[key]
21
-
22
- if (setter) setter(key, props[key], classCss, element, true)
23
- else if (isFunction(hasCSS)) {
24
- const stack = hasCSS(element, element.state, element.context)
25
- const exec = isArray(stack)
26
- ? stack.reduce((a, c) => {
27
- return merge(a, c)
28
- }, {})
29
- : stack
30
- deepMerge(classCss, exec)
31
- } else if (key === 'style') {
32
- deepMerge(classCss, props[key])
33
- } else restProps[key] = props[key]
34
- }
35
-
36
- return classCss
37
- }
38
-
39
- export const extractCSSfromProps = (element) => {
40
- const { props: defProps } = element
41
- const css = {}
42
- const props = {}
43
-
44
- for (const key in defProps) {
45
- const val = defProps[key]
46
-
47
- const mediaProp = keySetters[key.slice(0, 1)]
48
- if (mediaProp) {
49
- mediaProp(key, defProps[key], css, element, true)
50
- continue
51
- }
52
-
53
- const preprop = CSS_PROPS_REGISTRY[key]
54
- if (preprop) {
55
- const stack = preprop(element, element.state, element.context)
56
- const exec = isArray(stack)
57
- ? stack.reduce((a, c) => {
58
- return merge(a, c)
59
- }, {})
60
- : stack
61
- deepMerge(css, exec)
62
- continue
63
- }
64
-
65
- if (key === 'style') {
66
- deepMerge(css, defProps[key])
67
- continue
68
- }
69
-
70
- if (DEFAULT_CSS_PROPERTIES_LIST.has(key)) {
71
- css[key] = val
72
- continue
73
- }
74
-
75
- props[key] = val
76
- }
77
-
78
- return { css, props }
9
+ return useCssInProps(props, element)
79
10
  }
@@ -22,16 +22,15 @@ export const getSystemGlobalTheme = ({ context, state }) => {
22
22
  export const THEME_PROPS = {
23
23
  theme: (val, element) => {
24
24
  const { props } = element
25
- const globalTheme = getSystemGlobalTheme(element)
26
25
  if (!val) return
27
- const hasSubtheme = val.includes(' ') && !val.includes('@')
28
- const globalThemeForced = `@${props.themeModifier || globalTheme}`
29
- if (hasSubtheme) {
30
- const themeAppliedInVal = val.split(' ')
31
- themeAppliedInVal.splice(1, 0, globalThemeForced)
32
- return getMediaTheme(themeAppliedInVal)
33
- } else if (val.includes('@{globalTheme}')) val.replace('@{globalTheme}', globalThemeForced)
34
- return getMediaTheme(val, `@${props.themeModifier || globalTheme}`)
26
+
27
+ // themeModifier explicitly forces a scheme on this component
28
+ if (props.themeModifier) {
29
+ return getMediaTheme(val, `@${props.themeModifier}`)
30
+ }
31
+
32
+ // CSS vars handle dark/light switching — no modifier needed, no DOMQL re-render
33
+ return getMediaTheme(val)
35
34
  },
36
35
 
37
36
  color: (val, element) => {
@@ -1,3 +1,4 @@
1
1
  'use strict'
2
2
 
3
3
  export * from './executors'
4
+ export * from './transformers'
@@ -1,39 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
- var registry_exports = {};
30
- __export(registry_exports, {
31
- CSS_PREPROCS_DEFAULTS: () => CSS_PREPROCS_DEFAULTS,
32
- CSS_PROPS_REGISTRY: () => CSS_PROPS_REGISTRY
33
- });
34
- module.exports = __toCommonJS(registry_exports);
35
- var import_utils = require("@domql/utils");
36
- var preprocs = __toESM(require("./props"), 1);
37
- var import_atoms = require("@symbo.ls/atoms");
38
- const CSS_PROPS_REGISTRY = (0, import_utils.mergeArray)([import_atoms.Text]).class;
39
- const CSS_PREPROCS_DEFAULTS = (0, import_utils.mergeArray)(Object.values(preprocs));
@@ -1,9 +0,0 @@
1
- import { mergeArray } from "@domql/utils";
2
- import * as preprocs from "./props";
3
- import { Text } from "@symbo.ls/atoms";
4
- const CSS_PROPS_REGISTRY = mergeArray([Text]).class;
5
- const CSS_PREPROCS_DEFAULTS = mergeArray(Object.values(preprocs));
6
- export {
7
- CSS_PREPROCS_DEFAULTS,
8
- CSS_PROPS_REGISTRY
9
- };
package/src/registry.js DELETED
@@ -1,10 +0,0 @@
1
- 'use strict'
2
-
3
- import { mergeArray } from '@domql/utils'
4
- import * as preprocs from './props'
5
-
6
- import { Text } from '@symbo.ls/atoms'
7
-
8
- // TODO: due to recent updates inherit from BOX instead
9
- export const CSS_PROPS_REGISTRY = mergeArray([Text]).class
10
- export const CSS_PREPROCS_DEFAULTS = mergeArray(Object.values(preprocs))