@just-web/css 0.2.0 → 0.4.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.
Files changed (41) hide show
  1. package/cjs/css-properties/css-properties.d.ts +26 -0
  2. package/cjs/css-properties/css-properties.js +9 -0
  3. package/cjs/css-properties/to_dom_style.d.ts +19 -0
  4. package/cjs/css-properties/to_dom_style.js +14 -0
  5. package/cjs/globals.ctx.d.ts +5 -0
  6. package/cjs/globals.ctx.js +18 -0
  7. package/cjs/index.d.ts +10 -0
  8. package/cjs/index.js +115 -0
  9. package/cjs/package.json +1 -0
  10. package/cjs/props/class-name.d.ts +11 -0
  11. package/cjs/props/class-name.js +1 -0
  12. package/cjs/props/style.d.ts +7 -0
  13. package/cjs/props/style.js +1 -0
  14. package/cjs/tailwind.css +1 -0
  15. package/cjs/testing/log-panel.d.ts +4 -0
  16. package/cjs/testing/log-panel.js +19 -0
  17. package/cjs/testing/toggle-attribute-button.d.ts +4 -0
  18. package/cjs/testing/toggle-attribute-button.js +28 -0
  19. package/cjs/theme/class-name.d.ts +41 -0
  20. package/cjs/theme/class-name.js +32 -0
  21. package/cjs/theme/data-attribute.d.ts +67 -0
  22. package/cjs/theme/data-attribute.js +30 -0
  23. package/cjs/utils/attribute.d.ts +36 -0
  24. package/cjs/utils/attribute.js +25 -0
  25. package/cjs/utils/data-attribute.d.ts +23 -0
  26. package/cjs/utils/data-attribute.js +15 -0
  27. package/cjs/utils/get-css-prop-values.d.ts +16 -0
  28. package/cjs/utils/get-css-prop-values.js +13 -0
  29. package/cjs/utils/prefers-color-scheme.d.ts +33 -0
  30. package/cjs/utils/prefers-color-scheme.js +29 -0
  31. package/esm/css-properties/to_dom_style.d.ts +20 -0
  32. package/esm/css-properties/to_dom_style.d.ts.map +1 -0
  33. package/esm/css-properties/to_dom_style.js +27 -0
  34. package/esm/css-properties/to_dom_style.js.map +1 -0
  35. package/esm/index.d.ts +1 -0
  36. package/esm/index.d.ts.map +1 -1
  37. package/esm/index.js +1 -0
  38. package/esm/index.js.map +1 -1
  39. package/package.json +7 -1
  40. package/src/css-properties/to_dom_style.ts +30 -0
  41. package/src/index.ts +1 -0
@@ -0,0 +1,26 @@
1
+ import type { Properties } from 'csstype';
2
+ /**
3
+ * Extends CSS properties to include custom properties.
4
+ * Allows for string or number values for standard properties,
5
+ * and string values for custom properties with '--' prefix.
6
+ */
7
+ export interface CSSProperties extends Properties<string | number> {
8
+ [k: `--${string}`]: string;
9
+ }
10
+ /**
11
+ * Defines CSS properties including custom properties.
12
+ * This function is used to properly type CSS properties when defining styles,
13
+ * especially when using CSS custom properties (variables).
14
+ *
15
+ * @param style - CSS properties object that can include both standard and custom properties
16
+ * @returns The same style object with proper typing
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * defineCSSProperties({
21
+ * color: 'red',
22
+ * '--custom-color': '#ff0000'
23
+ * })
24
+ * ```
25
+ */
26
+ export declare function defineCSSProperties(style: CSSProperties): any;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.defineCSSProperties = defineCSSProperties;
7
+ function defineCSSProperties(style) {
8
+ return style;
9
+ }
@@ -0,0 +1,19 @@
1
+ import type { CSSProperties } from './css-properties.ts';
2
+ /**
3
+ * Converts React-style CSS properties to DOM style properties.
4
+ * This function handles both standard CSS properties and custom properties,
5
+ * ensuring proper formatting for DOM style application.
6
+ *
7
+ * @param style - React-style CSS properties object
8
+ * @returns CSSStyleDeclaration compatible object for DOM style application
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const domStyle = toDOMStyle({
13
+ * backgroundColor: 'red',
14
+ * '--custom-color': '#ff0000'
15
+ * })
16
+ * element.style = domStyle
17
+ * ```
18
+ */
19
+ export declare function toDOMStyle(style: CSSProperties | undefined): Partial<CSSStyleDeclaration> | undefined;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.toDOMStyle = toDOMStyle;
7
+ function toDOMStyle(style) {
8
+ if (style === void 0) return void 0;
9
+ const result = {};
10
+ for (const [key, value] of Object.entries(style)) {
11
+ result[key.startsWith("--") ? key : key.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`)] = value;
12
+ }
13
+ return result;
14
+ }
@@ -0,0 +1,5 @@
1
+ export declare const ctx: {
2
+ matchMedia(query: string): MediaQueryList;
3
+ getDocumentElement(): HTMLElement;
4
+ _reset(): void;
5
+ };
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ctx = void 0;
7
+ const ctx = exports.ctx = {
8
+ matchMedia(query) {
9
+ return globalThis.matchMedia(query);
10
+ },
11
+ getDocumentElement() {
12
+ return globalThis.document.documentElement;
13
+ },
14
+ _reset() {
15
+ this.matchMedia = globalThis.matchMedia;
16
+ this.getDocumentElement = () => globalThis.document.documentElement;
17
+ }
18
+ };
package/cjs/index.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ export * from './css-properties/css-properties.ts';
2
+ export * from './css-properties/to_dom_style.ts';
3
+ export * from './props/class-name.ts';
4
+ export * from './props/style.ts';
5
+ export * from './theme/class-name.ts';
6
+ export * from './theme/data-attribute.ts';
7
+ export * from './utils/attribute.ts';
8
+ export * from './utils/data-attribute.ts';
9
+ export * from './utils/get-css-prop-values.ts';
10
+ export * from './utils/prefers-color-scheme.ts';
package/cjs/index.js ADDED
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _cssProperties = require("./css-properties/css-properties.ts");
7
+ Object.keys(_cssProperties).forEach(function (key) {
8
+ if (key === "default" || key === "__esModule") return;
9
+ if (key in exports && exports[key] === _cssProperties[key]) return;
10
+ Object.defineProperty(exports, key, {
11
+ enumerable: true,
12
+ get: function () {
13
+ return _cssProperties[key];
14
+ }
15
+ });
16
+ });
17
+ var _to_dom_style = require("./css-properties/to_dom_style.ts");
18
+ Object.keys(_to_dom_style).forEach(function (key) {
19
+ if (key === "default" || key === "__esModule") return;
20
+ if (key in exports && exports[key] === _to_dom_style[key]) return;
21
+ Object.defineProperty(exports, key, {
22
+ enumerable: true,
23
+ get: function () {
24
+ return _to_dom_style[key];
25
+ }
26
+ });
27
+ });
28
+ var _className = require("./props/class-name.ts");
29
+ Object.keys(_className).forEach(function (key) {
30
+ if (key === "default" || key === "__esModule") return;
31
+ if (key in exports && exports[key] === _className[key]) return;
32
+ Object.defineProperty(exports, key, {
33
+ enumerable: true,
34
+ get: function () {
35
+ return _className[key];
36
+ }
37
+ });
38
+ });
39
+ var _style = require("./props/style.ts");
40
+ Object.keys(_style).forEach(function (key) {
41
+ if (key === "default" || key === "__esModule") return;
42
+ if (key in exports && exports[key] === _style[key]) return;
43
+ Object.defineProperty(exports, key, {
44
+ enumerable: true,
45
+ get: function () {
46
+ return _style[key];
47
+ }
48
+ });
49
+ });
50
+ var _className2 = require("./theme/class-name.ts");
51
+ Object.keys(_className2).forEach(function (key) {
52
+ if (key === "default" || key === "__esModule") return;
53
+ if (key in exports && exports[key] === _className2[key]) return;
54
+ Object.defineProperty(exports, key, {
55
+ enumerable: true,
56
+ get: function () {
57
+ return _className2[key];
58
+ }
59
+ });
60
+ });
61
+ var _dataAttribute = require("./theme/data-attribute.ts");
62
+ Object.keys(_dataAttribute).forEach(function (key) {
63
+ if (key === "default" || key === "__esModule") return;
64
+ if (key in exports && exports[key] === _dataAttribute[key]) return;
65
+ Object.defineProperty(exports, key, {
66
+ enumerable: true,
67
+ get: function () {
68
+ return _dataAttribute[key];
69
+ }
70
+ });
71
+ });
72
+ var _attribute = require("./utils/attribute.ts");
73
+ Object.keys(_attribute).forEach(function (key) {
74
+ if (key === "default" || key === "__esModule") return;
75
+ if (key in exports && exports[key] === _attribute[key]) return;
76
+ Object.defineProperty(exports, key, {
77
+ enumerable: true,
78
+ get: function () {
79
+ return _attribute[key];
80
+ }
81
+ });
82
+ });
83
+ var _dataAttribute2 = require("./utils/data-attribute.ts");
84
+ Object.keys(_dataAttribute2).forEach(function (key) {
85
+ if (key === "default" || key === "__esModule") return;
86
+ if (key in exports && exports[key] === _dataAttribute2[key]) return;
87
+ Object.defineProperty(exports, key, {
88
+ enumerable: true,
89
+ get: function () {
90
+ return _dataAttribute2[key];
91
+ }
92
+ });
93
+ });
94
+ var _getCssPropValues = require("./utils/get-css-prop-values.ts");
95
+ Object.keys(_getCssPropValues).forEach(function (key) {
96
+ if (key === "default" || key === "__esModule") return;
97
+ if (key in exports && exports[key] === _getCssPropValues[key]) return;
98
+ Object.defineProperty(exports, key, {
99
+ enumerable: true,
100
+ get: function () {
101
+ return _getCssPropValues[key];
102
+ }
103
+ });
104
+ });
105
+ var _prefersColorScheme = require("./utils/prefers-color-scheme.ts");
106
+ Object.keys(_prefersColorScheme).forEach(function (key) {
107
+ if (key === "default" || key === "__esModule") return;
108
+ if (key in exports && exports[key] === _prefersColorScheme[key]) return;
109
+ Object.defineProperty(exports, key, {
110
+ enumerable: true,
111
+ get: function () {
112
+ return _prefersColorScheme[key];
113
+ }
114
+ });
115
+ });
@@ -0,0 +1 @@
1
+ { "type": "commonjs" }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Note that `className` could be specific to ReactJS.
3
+ * So this type may be misplaced in this package.
4
+ */
5
+ /**
6
+ * Interface for component props that include a className property.
7
+ * The className property accepts a string value for CSS class names.
8
+ */
9
+ export interface ClassNameProps {
10
+ className?: string | undefined;
11
+ }
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,7 @@
1
+ import type { CSSProperties } from '../css-properties/css-properties.ts';
2
+ /**
3
+ * Interface for component props that include a style property.
4
+ */
5
+ export interface StyleProps {
6
+ style?: CSSProperties | undefined;
7
+ }
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1 @@
1
+ @import "tailwindcss";
@@ -0,0 +1,4 @@
1
+ export declare function LogPanel({ title, log }: {
2
+ title: string;
3
+ log: string[];
4
+ }): import("react").JSX.Element;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.LogPanel = LogPanel;
7
+ function LogPanel({
8
+ title,
9
+ log
10
+ }) {
11
+ return /* @__PURE__ */React.createElement("div", {
12
+ className: "bg-neutral-100 p-4 rounded overflow-y-auto"
13
+ }, /* @__PURE__ */React.createElement("h4", {
14
+ className: "mb-2"
15
+ }, title), log.map((entry, i) => /* @__PURE__ */React.createElement("pre", {
16
+ key: i,
17
+ className: "font-mono"
18
+ }, entry)));
19
+ }
@@ -0,0 +1,4 @@
1
+ export declare const ToggleAttributeButton: import("react").ForwardRefExoticComponent<{
2
+ attribute: string;
3
+ values?: string[];
4
+ } & import("react").RefAttributes<HTMLElement>>;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ToggleAttributeButton = void 0;
7
+ var _react = require("react");
8
+ const ToggleAttributeButton = exports.ToggleAttributeButton = (0, _react.forwardRef)(({
9
+ attribute,
10
+ values = ["test-value"]
11
+ }, ref) => {
12
+ const handleAttributeChange = (0, _react.useCallback)(attr => {
13
+ const target = (ref && "current" in ref ? ref.current : null) ?? document.documentElement;
14
+ const currentValue = target.getAttribute(attr);
15
+ const nextIndex = currentValue ? values.indexOf(currentValue) + 1 : 0;
16
+ const newValue = nextIndex < values.length ? values[nextIndex] : null;
17
+ if (newValue === null) {
18
+ target.removeAttribute(attr);
19
+ } else {
20
+ target.setAttribute(attr, newValue);
21
+ }
22
+ }, [ref, values]);
23
+ return /* @__PURE__ */React.createElement("button", {
24
+ key: attribute,
25
+ className: "bg-cyan-700 text-white px-4 py-2 rounded-md shadow-md active:bg-cyan-800",
26
+ onClick: () => handleAttributeChange(attribute)
27
+ }, "Toggle ", attribute);
28
+ });
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Gets the current theme by checking element class names against a themes map.
3
+ *
4
+ * @param options - Configuration options
5
+ * @param options.themes - Record mapping theme keys to their class name values
6
+ * @param options.defaultTheme - Fallback theme key if no matching class is found
7
+ * @param options.element - Element to check classes on (defaults to document.documentElement)
8
+ * @returns The matching theme key or defaultTheme if no match found
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const themes = {
13
+ * light: 'theme-light',
14
+ * dark: 'theme-dark'
15
+ * }
16
+ *
17
+ * // Get current theme from document.documentElement
18
+ * const theme = getThemeByClassName({
19
+ * themes,
20
+ * defaultTheme: 'light'
21
+ * })
22
+ *
23
+ * // Get theme from specific element
24
+ * const theme = getThemeByClassName({
25
+ * themes,
26
+ * element: myElement,
27
+ * defaultTheme: 'light'
28
+ * })
29
+ * ```
30
+ */
31
+ export declare function getThemeByClassName<Themes extends Record<string, string>>(options: {
32
+ themes: Themes;
33
+ defaultTheme?: keyof Themes | undefined;
34
+ element?: Element | undefined;
35
+ }): keyof Themes | undefined;
36
+ export declare function observeThemeByClassName<Themes extends Record<string, string>>(options: {
37
+ themes: Themes;
38
+ handler: (value: string | undefined) => void;
39
+ defaultTheme?: keyof Themes | undefined;
40
+ element?: Element | undefined;
41
+ }): MutationObserver;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getThemeByClassName = getThemeByClassName;
7
+ exports.observeThemeByClassName = observeThemeByClassName;
8
+ var _typePlus = require("type-plus");
9
+ var _globalsCtx = require("../globals.ctx.ts");
10
+ var _attribute = require("../utils/attribute.ts");
11
+ function getThemeByClassName(options) {
12
+ const element = options.element ?? _globalsCtx.ctx.getDocumentElement();
13
+ const className = element.className;
14
+ const theme = (0, _typePlus.findKey)(options.themes, theme2 => className.includes(options.themes[theme2]));
15
+ return theme ?? options.defaultTheme;
16
+ }
17
+ function observeThemeByClassName(options) {
18
+ return (0, _attribute.observeAttributes)({
19
+ class: value => {
20
+ if (value === null) {
21
+ options.handler(options.defaultTheme);
22
+ return;
23
+ }
24
+ for (const name in options.themes) {
25
+ if (value.includes(options.themes[name])) {
26
+ options.handler(name);
27
+ break;
28
+ }
29
+ }
30
+ }
31
+ }, options.element);
32
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Gets the theme based on a data attribute value.
3
+ *
4
+ * @param options - Configuration options
5
+ * @param options.themes - Record mapping theme keys to their data attribute values
6
+ * @param options.defaultTheme - Fallback theme key if attribute value doesn't match any theme
7
+ * @param options.attributeName - Name of the data attribute to check (must start with 'data-')
8
+ * @returns The matching theme key, or defaultTheme if no match found
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const themes = {
13
+ * light: 'light',
14
+ * dark: 'dark',
15
+ * system: 'system'
16
+ * }
17
+ *
18
+ * // Get theme from data-theme attribute
19
+ * const theme = getThemeByDataAttribute({
20
+ * themes,
21
+ * defaultTheme: 'system',
22
+ * attributeName: 'data-theme'
23
+ * })
24
+ * ```
25
+ */
26
+ export declare function getThemeByDataAttribute<Themes extends Record<string, string>>(options: {
27
+ themes: Themes;
28
+ defaultTheme?: keyof Themes | undefined;
29
+ attributeName: `data-${string}`;
30
+ element?: Element | undefined;
31
+ }): keyof Themes | undefined;
32
+ /**
33
+ * Observes changes to a theme data attribute and calls a handler when it changes.
34
+ *
35
+ * @param options - Configuration options
36
+ * @param options.themes - Record mapping theme keys to their data attribute values
37
+ * @param options.handler - Callback function called with the new theme value or null when removed
38
+ * @param options.defaultTheme - Fallback theme key if attribute value doesn't match any theme
39
+ * @param options.attributeName - Name of the data attribute to observe (must start with 'data-')
40
+ * @returns A MutationObserver that can be disconnected to stop observing
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * const themes = {
45
+ * light: 'light',
46
+ * dark: 'dark'
47
+ * }
48
+ *
49
+ * // Observe data-theme attribute changes
50
+ * const observer = observeThemeByDataAttributes({
51
+ * themes,
52
+ * handler: (theme) => console.log('Theme changed to:', theme),
53
+ * defaultTheme: 'light',
54
+ * attributeName: 'data-theme'
55
+ * })
56
+ *
57
+ * // Stop observing
58
+ * observer.disconnect()
59
+ * ```
60
+ */
61
+ export declare function observeThemeByDataAttributes<Themes extends Record<string, string>>(options: {
62
+ attributeName: `data-${string}`;
63
+ themes: Themes;
64
+ handler: (value: string | null) => void;
65
+ defaultTheme?: keyof Themes | undefined;
66
+ element?: Element | undefined;
67
+ }): MutationObserver;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getThemeByDataAttribute = getThemeByDataAttribute;
7
+ exports.observeThemeByDataAttributes = observeThemeByDataAttributes;
8
+ var _typePlus = require("type-plus");
9
+ var _dataAttribute = require("../utils/data-attribute.ts");
10
+ function getThemeByDataAttribute(options) {
11
+ const value = (0, _dataAttribute.getDataAttribute)(options.attributeName, options.element);
12
+ const theme = (0, _typePlus.findKey)(options.themes, theme2 => options.themes[theme2] === value);
13
+ return theme ?? options.defaultTheme;
14
+ }
15
+ function observeThemeByDataAttributes(options) {
16
+ return (0, _dataAttribute.observeDataAttributes)({
17
+ [options.attributeName]: value => {
18
+ if (value === null) {
19
+ options.handler(options.defaultTheme ?? null);
20
+ return;
21
+ }
22
+ for (const name in options.themes) {
23
+ if (options.themes[name] === value) {
24
+ options.handler(name);
25
+ break;
26
+ }
27
+ }
28
+ }
29
+ }, options.element);
30
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Gets the value of an attribute from an element.
3
+ *
4
+ * @param qualifiedName - The name of the attribute to get
5
+ * @param element - The element to get the attribute from. Defaults to `document.documentElement`
6
+ * @returns The attribute value cast to type T, or null if the attribute doesn't exist
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * // Get theme from document root
11
+ * const theme = getAttribute('data-theme')
12
+ *
13
+ * // Get data-testid from a specific element
14
+ * const testId = getAttribute('data-testid', element)
15
+ * ```
16
+ */
17
+ export declare function getAttribute<T extends string>(qualifiedName: T, element?: Element | undefined): T | null;
18
+ /**
19
+ * Observes attributes changes on an element and calls corresponding handlers.
20
+ *
21
+ * @param handlers - An object mapping attribute names to handler functions.
22
+ * @param element - The element to observe. Defaults to `document.documentElement`.
23
+ * @returns {MutationObserver} The observer instance, which can be used to disconnect the observer.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const observer = observeAttributes({
28
+ * 'data-theme': (attr, value) => console.log(`Theme changed to: ${value}`),
29
+ * 'class': (attr, value) => console.log(`class changed to: ${value}`)
30
+ * });
31
+ *
32
+ * // Later, to stop observing:
33
+ * observer.disconnect();
34
+ * ```
35
+ */
36
+ export declare function observeAttributes<T extends string>(handlers: Record<string, (value: T | null) => void>, element?: Element | undefined): MutationObserver;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getAttribute = getAttribute;
7
+ exports.observeAttributes = observeAttributes;
8
+ var _globalsCtx = require("../globals.ctx.ts");
9
+ function getAttribute(qualifiedName, element = _globalsCtx.ctx.getDocumentElement()) {
10
+ return element?.getAttribute(qualifiedName);
11
+ }
12
+ function observeAttributes(handlers, element = _globalsCtx.ctx.getDocumentElement()) {
13
+ const observer = new MutationObserver(mutations => {
14
+ for (const mutation of mutations) {
15
+ const attribute = mutation.attributeName;
16
+ const value = element.getAttribute(attribute);
17
+ handlers[attribute]?.(value);
18
+ }
19
+ });
20
+ observer.observe(element, {
21
+ attributes: true,
22
+ attributeFilter: Object.keys(handlers)
23
+ });
24
+ return observer;
25
+ }
@@ -0,0 +1,23 @@
1
+ export declare function getDataAttribute<T extends `data-${string}`>(qualifiedName: T, element?: Element | undefined): T | null;
2
+ /**
3
+ * Observes changes to `data-*` attributes on an element and calls corresponding handlers.
4
+ *
5
+ * @param options - Configuration options
6
+ * @param options.handlers - An object mapping `data-*` attribute names to handler functions.
7
+ * @param options.element - The element to observe. Defaults to `document.documentElement`
8
+ * @returns {MutationObserver} The observer instance, which can be used to disconnect the observer
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const observer = observeDataAttributes({
13
+ * handlers: {
14
+ * 'data-theme': (value) => console.log(`Theme changed to: ${value}`),
15
+ * 'data-mode': (value) => console.log(`Mode changed to: ${value}`)
16
+ * }
17
+ * });
18
+ *
19
+ * // Later, to stop observing:
20
+ * observer.disconnect();
21
+ * ```
22
+ */
23
+ export declare function observeDataAttributes<T extends string, K extends `data-${string}`>(handlers: Record<K, (value: T | null) => void>, element?: Element | undefined): MutationObserver;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getDataAttribute = getDataAttribute;
7
+ exports.observeDataAttributes = observeDataAttributes;
8
+ var _globalsCtx = require("../globals.ctx.ts");
9
+ var _attribute = require("./attribute.ts");
10
+ function getDataAttribute(qualifiedName, element = _globalsCtx.ctx.getDocumentElement()) {
11
+ return (0, _attribute.getAttribute)(qualifiedName, element);
12
+ }
13
+ function observeDataAttributes(handlers, element) {
14
+ return (0, _attribute.observeAttributes)(handlers, element);
15
+ }
@@ -0,0 +1,16 @@
1
+ import type { CreateTuple } from 'type-plus';
2
+ /**
3
+ * Retrieves CSS custom property values from the specified element.
4
+ *
5
+ * @param element - The HTML element to get property values from
6
+ * @param props - CSS custom property names to retrieve, must be in the format `--property-name`
7
+ * @returns Array of property values corresponding to the requested custom properties
8
+ */
9
+ export declare function getCSSPropValues<Props extends Array<`--${string}`>>(element: HTMLElement, ...props: Props): CreateTuple<Props['length'], string>;
10
+ /**
11
+ * Retrieves CSS custom property values from `document.body`.
12
+ *
13
+ * @param props - CSS custom property names to retrieve, must be in the format `--property-name`
14
+ * @returns Array of property values corresponding to the requested custom properties
15
+ */
16
+ export declare function getCSSPropValues<Props extends Array<`--${string}`>>(...props: Props): CreateTuple<Props['length'], string>;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getCSSPropValues = getCSSPropValues;
7
+ function getCSSPropValues(element, ...props) {
8
+ if (typeof element === "string") {
9
+ return getCSSPropValues(globalThis.document.body, element, ...props);
10
+ }
11
+ const style = globalThis.getComputedStyle(element);
12
+ return props.map(v => style.getPropertyValue(v));
13
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Observes system color scheme preference changes and calls handlers when they occur.
3
+ *
4
+ * @param themes - An object mapping theme names to handler functions that are called when that theme is activated
5
+ * @returns A cleanup function that removes all event listeners
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * // Observe light/dark mode changes
10
+ * const cleanup = observePrefersColorScheme({
11
+ * light: (theme) => console.log('Light mode activated'),
12
+ * dark: (theme) => console.log('Dark mode activated')
13
+ * })
14
+ *
15
+ * // Later, to stop observing:
16
+ * cleanup()
17
+ * ```
18
+ */
19
+ export declare function observePrefersColorScheme<T extends string>(themes: Record<T, (value: T | null) => void>): () => void;
20
+ /**
21
+ * Gets the current preferred color theme from the system settings.
22
+ *
23
+ * @param themes - A list of theme names to check against the system preference
24
+ * @returns The first matching theme from the provided list, or null if none match
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * // Check if system prefers light or dark mode
29
+ * const theme = getPrefersColorTheme('light', 'dark')
30
+ * // Returns 'light', 'dark', or null
31
+ * ```
32
+ */
33
+ export declare function getPrefersColorTheme<T extends string>(...themes: T[]): any;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getPrefersColorTheme = getPrefersColorTheme;
7
+ exports.observePrefersColorScheme = observePrefersColorScheme;
8
+ var _typePlus = require("type-plus");
9
+ var _globalsCtx = require("../globals.ctx.ts");
10
+ function observePrefersColorScheme(themes) {
11
+ const removers = (0, _typePlus.mapKey)(themes, t => {
12
+ const m = _globalsCtx.ctx.matchMedia(`(prefers-color-scheme: ${t})`);
13
+ const listener = event => {
14
+ if (event.matches) {
15
+ themes[t]?.(t);
16
+ }
17
+ };
18
+ m.addEventListener("change", listener);
19
+ return () => m.removeEventListener("change", listener);
20
+ });
21
+ return () => {
22
+ for (const remover of removers) {
23
+ remover();
24
+ }
25
+ };
26
+ }
27
+ function getPrefersColorTheme(...themes) {
28
+ return themes.find(theme => _globalsCtx.ctx.matchMedia(`(prefers-color-scheme: ${theme})`).matches) ?? null;
29
+ }
@@ -0,0 +1,20 @@
1
+ import type { CSSProperties } from './css-properties.ts';
2
+ /**
3
+ * Converts React-style CSS properties to DOM style properties.
4
+ * This function handles both standard CSS properties and custom properties,
5
+ * ensuring proper formatting for DOM style application.
6
+ *
7
+ * @param style - React-style CSS properties object
8
+ * @returns CSSStyleDeclaration compatible object for DOM style application
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const domStyle = toDOMStyle({
13
+ * backgroundColor: 'red',
14
+ * '--custom-color': '#ff0000'
15
+ * })
16
+ * element.style = domStyle
17
+ * ```
18
+ */
19
+ export declare function toDOMStyle(style: CSSProperties | undefined): Partial<CSSStyleDeclaration> | undefined;
20
+ //# sourceMappingURL=to_dom_style.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"to_dom_style.d.ts","sourceRoot":"","sources":["../../src/css-properties/to_dom_style.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAExD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC,mBAAmB,CAAC,GAAG,SAAS,CAUrG"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Converts React-style CSS properties to DOM style properties.
3
+ * This function handles both standard CSS properties and custom properties,
4
+ * ensuring proper formatting for DOM style application.
5
+ *
6
+ * @param style - React-style CSS properties object
7
+ * @returns CSSStyleDeclaration compatible object for DOM style application
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const domStyle = toDOMStyle({
12
+ * backgroundColor: 'red',
13
+ * '--custom-color': '#ff0000'
14
+ * })
15
+ * element.style = domStyle
16
+ * ```
17
+ */
18
+ export function toDOMStyle(style) {
19
+ if (style === undefined)
20
+ return undefined;
21
+ const result = {};
22
+ for (const [key, value] of Object.entries(style)) {
23
+ result[key.startsWith('--') ? key : key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`)] = value;
24
+ }
25
+ return result;
26
+ }
27
+ //# sourceMappingURL=to_dom_style.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"to_dom_style.js","sourceRoot":"","sources":["../../src/css-properties/to_dom_style.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,UAAU,CAAC,KAAgC;IAC1D,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAEzC,MAAM,MAAM,GAAG,EAAS,CAAA;IAExB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAA;IACzG,CAAC;IAED,OAAO,MAAM,CAAA;AACd,CAAC"}
package/esm/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './css-properties/css-properties.ts';
2
+ export * from './css-properties/to_dom_style.ts';
2
3
  export * from './props/class-name.ts';
3
4
  export * from './props/style.ts';
4
5
  export * from './theme/class-name.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oCAAoC,CAAA;AAClD,cAAc,uBAAuB,CAAA;AACrC,cAAc,kBAAkB,CAAA;AAChC,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,sBAAsB,CAAA;AACpC,cAAc,2BAA2B,CAAA;AACzC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oCAAoC,CAAA;AAClD,cAAc,kCAAkC,CAAA;AAChD,cAAc,uBAAuB,CAAA;AACrC,cAAc,kBAAkB,CAAA;AAChC,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,sBAAsB,CAAA;AACpC,cAAc,2BAA2B,CAAA;AACzC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA"}
package/esm/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./css-properties/css-properties.js";
2
+ export * from "./css-properties/to_dom_style.js";
2
3
  export * from "./props/class-name.js";
3
4
  export * from "./props/style.js";
4
5
  export * from "./theme/class-name.js";
package/esm/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oCAAoC,CAAA;AAClD,cAAc,uBAAuB,CAAA;AACrC,cAAc,kBAAkB,CAAA;AAChC,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,sBAAsB,CAAA;AACpC,cAAc,2BAA2B,CAAA;AACzC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oCAAoC,CAAA;AAClD,cAAc,kCAAkC,CAAA;AAChD,cAAc,uBAAuB,CAAA;AACrC,cAAc,kBAAkB,CAAA;AAChC,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,sBAAsB,CAAA;AACpC,cAAc,2BAA2B,CAAA;AACzC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@just-web/css",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "CSS types and utilities",
5
5
  "type": "module",
6
6
  "exports": {
@@ -10,7 +10,10 @@
10
10
  },
11
11
  "./package.json": "./package.json"
12
12
  },
13
+ "main": "./cjs/index.js",
14
+ "types": "./cjs/index.d.ts",
13
15
  "files": [
16
+ "cjs",
14
17
  "esm",
15
18
  "src",
16
19
  "!**/*.{spec,test,unit,accept,integrate,system,stories}.*",
@@ -38,6 +41,7 @@
38
41
  "@vitest/browser": "^3.1.3",
39
42
  "@vitest/coverage-v8": "^3.1.3",
40
43
  "dedent": "^1.6.0",
44
+ "ncp": "^2.0.0",
41
45
  "playwright": "^1.52.0",
42
46
  "react": "^18.3.1",
43
47
  "react-dom": "^18.3.1",
@@ -49,6 +53,7 @@
49
53
  "storybook-dark-mode": "^4.0.2",
50
54
  "tailwindcss": "^4.1.6",
51
55
  "typescript": "^5.8.3",
56
+ "unbuild": "^3.5.0",
52
57
  "vite": "^6.3.5",
53
58
  "vitest": "^3.1.3",
54
59
  "vitest-browser-react": "^0.1.1",
@@ -57,6 +62,7 @@
57
62
  "scripts": {
58
63
  "build": "run-p build:*",
59
64
  "build-doc": "storybook build -o ../../docs/css",
65
+ "build:cjs": "unbuild && ncp ../../tools/ts/package.cjs.json ./cjs/package.json",
60
66
  "build:esm": "tsc -p tsconfig.esm.json",
61
67
  "clean": "rimraf .turbo esm *.tsbuildinfo",
62
68
  "cov": "vitest run --coverage",
@@ -0,0 +1,30 @@
1
+ import type { CSSProperties } from './css-properties.ts'
2
+
3
+ /**
4
+ * Converts React-style CSS properties to DOM style properties.
5
+ * This function handles both standard CSS properties and custom properties,
6
+ * ensuring proper formatting for DOM style application.
7
+ *
8
+ * @param style - React-style CSS properties object
9
+ * @returns CSSStyleDeclaration compatible object for DOM style application
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const domStyle = toDOMStyle({
14
+ * backgroundColor: 'red',
15
+ * '--custom-color': '#ff0000'
16
+ * })
17
+ * element.style = domStyle
18
+ * ```
19
+ */
20
+ export function toDOMStyle(style: CSSProperties | undefined): Partial<CSSStyleDeclaration> | undefined {
21
+ if (style === undefined) return undefined
22
+
23
+ const result = {} as any
24
+
25
+ for (const [key, value] of Object.entries(style)) {
26
+ result[key.startsWith('--') ? key : key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`)] = value
27
+ }
28
+
29
+ return result
30
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './css-properties/css-properties.ts'
2
+ export * from './css-properties/to_dom_style.ts'
2
3
  export * from './props/class-name.ts'
3
4
  export * from './props/style.ts'
4
5
  export * from './theme/class-name.ts'