@just-web/css 0.6.1 → 0.8.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 (114) hide show
  1. package/cjs/index.cjs +394 -0
  2. package/cjs/index.cjs.map +1 -0
  3. package/cjs/index.d.cts +412 -0
  4. package/cjs/index.d.cts.map +1 -0
  5. package/esm/index.d.mts +412 -0
  6. package/esm/index.d.mts.map +1 -0
  7. package/esm/index.mjs +378 -0
  8. package/esm/index.mjs.map +1 -0
  9. package/package.json +36 -35
  10. package/src/convertors/px_2_num.ts +17 -0
  11. package/src/index.ts +6 -2
  12. package/src/{css-properties/css-properties.ts → properties/css_properties.ts} +6 -2
  13. package/{cjs/css-properties/css-properties.d.ts → src/properties/properties.ts} +9 -4
  14. package/src/{css-properties → properties}/to_dom_style.ts +1 -1
  15. package/src/props/class-name.ts +1 -1
  16. package/src/props/style.ts +3 -3
  17. package/cjs/convertors/px_2_rem.d.ts +0 -21
  18. package/cjs/convertors/px_2_rem.js +0 -17
  19. package/cjs/convertors/rem_2_px.d.ts +0 -21
  20. package/cjs/convertors/rem_2_px.js +0 -17
  21. package/cjs/css-properties/css-properties.js +0 -9
  22. package/cjs/css-properties/to_dom_style.d.ts +0 -19
  23. package/cjs/css-properties/to_dom_style.js +0 -14
  24. package/cjs/globals.ctx.d.ts +0 -5
  25. package/cjs/globals.ctx.js +0 -18
  26. package/cjs/index.d.ts +0 -12
  27. package/cjs/index.js +0 -137
  28. package/cjs/package.json +0 -1
  29. package/cjs/props/class-name.d.ts +0 -11
  30. package/cjs/props/class-name.js +0 -1
  31. package/cjs/props/style.d.ts +0 -7
  32. package/cjs/props/style.js +0 -1
  33. package/cjs/tailwind.css +0 -1
  34. package/cjs/testing/log-panel.d.ts +0 -4
  35. package/cjs/testing/log-panel.js +0 -19
  36. package/cjs/testing/toggle-attribute-button.d.ts +0 -4
  37. package/cjs/testing/toggle-attribute-button.js +0 -28
  38. package/cjs/theme/class-name.d.ts +0 -41
  39. package/cjs/theme/class-name.js +0 -32
  40. package/cjs/theme/data-attribute.d.ts +0 -83
  41. package/cjs/theme/data-attribute.js +0 -33
  42. package/cjs/utils/attribute.d.ts +0 -36
  43. package/cjs/utils/attribute.js +0 -25
  44. package/cjs/utils/data-attribute.d.ts +0 -23
  45. package/cjs/utils/data-attribute.js +0 -15
  46. package/cjs/utils/get-css-prop-values.d.ts +0 -16
  47. package/cjs/utils/get-css-prop-values.js +0 -13
  48. package/cjs/utils/prefers-color-scheme.d.ts +0 -33
  49. package/cjs/utils/prefers-color-scheme.js +0 -29
  50. package/esm/convertors/px_2_rem.d.ts +0 -22
  51. package/esm/convertors/px_2_rem.d.ts.map +0 -1
  52. package/esm/convertors/px_2_rem.js +0 -26
  53. package/esm/convertors/px_2_rem.js.map +0 -1
  54. package/esm/convertors/rem_2_px.d.ts +0 -22
  55. package/esm/convertors/rem_2_px.d.ts.map +0 -1
  56. package/esm/convertors/rem_2_px.js +0 -26
  57. package/esm/convertors/rem_2_px.js.map +0 -1
  58. package/esm/css-properties/css-properties.d.ts +0 -27
  59. package/esm/css-properties/css-properties.d.ts.map +0 -1
  60. package/esm/css-properties/css-properties.js +0 -20
  61. package/esm/css-properties/css-properties.js.map +0 -1
  62. package/esm/css-properties/to_dom_style.d.ts +0 -20
  63. package/esm/css-properties/to_dom_style.d.ts.map +0 -1
  64. package/esm/css-properties/to_dom_style.js +0 -27
  65. package/esm/css-properties/to_dom_style.js.map +0 -1
  66. package/esm/globals.ctx.d.ts +0 -6
  67. package/esm/globals.ctx.d.ts.map +0 -1
  68. package/esm/globals.ctx.js +0 -13
  69. package/esm/globals.ctx.js.map +0 -1
  70. package/esm/index.d.ts +0 -13
  71. package/esm/index.d.ts.map +0 -1
  72. package/esm/index.js +0 -13
  73. package/esm/index.js.map +0 -1
  74. package/esm/props/class-name.d.ts +0 -12
  75. package/esm/props/class-name.d.ts.map +0 -1
  76. package/esm/props/class-name.js +0 -6
  77. package/esm/props/class-name.js.map +0 -1
  78. package/esm/props/style.d.ts +0 -8
  79. package/esm/props/style.d.ts.map +0 -1
  80. package/esm/props/style.js +0 -2
  81. package/esm/props/style.js.map +0 -1
  82. package/esm/testing/log-panel.d.ts +0 -5
  83. package/esm/testing/log-panel.d.ts.map +0 -1
  84. package/esm/testing/log-panel.js +0 -5
  85. package/esm/testing/log-panel.js.map +0 -1
  86. package/esm/testing/toggle-attribute-button.d.ts +0 -5
  87. package/esm/testing/toggle-attribute-button.d.ts.map +0 -1
  88. package/esm/testing/toggle-attribute-button.js +0 -19
  89. package/esm/testing/toggle-attribute-button.js.map +0 -1
  90. package/esm/theme/class-name.d.ts +0 -42
  91. package/esm/theme/class-name.d.ts.map +0 -1
  92. package/esm/theme/class-name.js +0 -56
  93. package/esm/theme/class-name.js.map +0 -1
  94. package/esm/theme/data-attribute.d.ts +0 -84
  95. package/esm/theme/data-attribute.d.ts.map +0 -1
  96. package/esm/theme/data-attribute.js +0 -27
  97. package/esm/theme/data-attribute.js.map +0 -1
  98. package/esm/utils/attribute.d.ts +0 -37
  99. package/esm/utils/attribute.d.ts.map +0 -1
  100. package/esm/utils/attribute.js +0 -53
  101. package/esm/utils/attribute.js.map +0 -1
  102. package/esm/utils/data-attribute.d.ts +0 -24
  103. package/esm/utils/data-attribute.d.ts.map +0 -1
  104. package/esm/utils/data-attribute.js +0 -30
  105. package/esm/utils/data-attribute.js.map +0 -1
  106. package/esm/utils/get-css-prop-values.d.ts +0 -17
  107. package/esm/utils/get-css-prop-values.d.ts.map +0 -1
  108. package/esm/utils/get-css-prop-values.js +0 -8
  109. package/esm/utils/get-css-prop-values.js.map +0 -1
  110. package/esm/utils/prefers-color-scheme.d.ts +0 -34
  111. package/esm/utils/prefers-color-scheme.d.ts.map +0 -1
  112. package/esm/utils/prefers-color-scheme.js +0 -54
  113. package/esm/utils/prefers-color-scheme.js.map +0 -1
  114. package/src/tailwind.css +0 -3
package/esm/index.mjs ADDED
@@ -0,0 +1,378 @@
1
+ import { findKey, mapKey } from "type-plus";
2
+
3
+ //#region src/convertors/px_2_num.ts
4
+ /**
5
+ * Converts pixel values to numbers.
6
+ *
7
+ * @param px - The pixel value to convert. Can be a number or string (e.g. '16px' or '16')
8
+ * @returns The numeric value
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * px2num(16) // 16
13
+ * px2num('32px') // 32
14
+ * px2num('12.5px') // 12.5
15
+ * px2num('0px') // 0
16
+ * ```
17
+ */
18
+ function px2num(px) {
19
+ return typeof px === "string" ? Number.parseFloat(px.replace(/px$/, "")) : Number(px);
20
+ }
21
+
22
+ //#endregion
23
+ //#region src/convertors/px_2_rem.ts
24
+ /**
25
+ * Converts pixel values to rem units.
26
+ *
27
+ * @param px - The pixel value to convert. Can be a number or string (e.g. '16px' or '16')
28
+ * @param options - Optional configuration
29
+ * @param options.base - Base pixel value to calculate rem units from. Defaults to 16
30
+ * @param options.precision - Number of decimal places in the output. Defaults to 4
31
+ * @returns The converted value as a string with 'rem' units
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * px2rem(16) // '1.0000'
36
+ * px2rem('32px') // '2.0000'
37
+ * px2rem(20, { base: 20 }) // '1.0000'
38
+ * px2rem(13, { precision: 2 }) // '0.81'
39
+ * ```
40
+ */
41
+ function px2rem(px, options) {
42
+ const { base = 16, precision = 4 } = options ?? {};
43
+ if (typeof px === "string") {
44
+ px = px.replace(/px$/, "");
45
+ px = Number.parseFloat(px);
46
+ }
47
+ return Number((px / base).toFixed(precision));
48
+ }
49
+
50
+ //#endregion
51
+ //#region src/convertors/rem_2_px.ts
52
+ /**
53
+ * Converts rem values to pixel units.
54
+ *
55
+ * @param rem - The rem value to convert. Can be a number or string (e.g. '1rem' or '1')
56
+ * @param options - Optional configuration
57
+ * @param options.base - Base pixel value to calculate pixels from. Defaults to 16
58
+ * @param options.precision - Number of decimal places in the output. Defaults to 4
59
+ * @returns The converted value as a string with 'px' units
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * rem2px(1) // '16.0000'
64
+ * rem2px('2rem') // '32.0000'
65
+ * rem2px(1, { base: 20 }) // '20.0000'
66
+ * rem2px(0.8125, { precision: 2 }) // '13.00'
67
+ * ```
68
+ */
69
+ function rem2px(rem, options) {
70
+ const { base = 16, precision = 4 } = options ?? {};
71
+ if (typeof rem === "string") {
72
+ rem = rem.replace(/rem$/, "");
73
+ rem = Number.parseFloat(rem);
74
+ }
75
+ return Number((rem * base).toFixed(precision));
76
+ }
77
+
78
+ //#endregion
79
+ //#region src/properties/css_properties.ts
80
+ /**
81
+ * Defines CSS properties including custom properties.
82
+ * This function is used to properly type CSS properties when defining styles,
83
+ * especially when using CSS custom properties (variables).
84
+ *
85
+ * @deprecated Use `defineProperties` instead.
86
+ *
87
+ * @param style - CSS properties object that can include both standard and custom properties
88
+ * @returns The same style object with proper typing
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * defineCSSProperties({
93
+ * color: 'red',
94
+ * '--custom-color': '#ff0000'
95
+ * })
96
+ * ```
97
+ */
98
+ function defineCSSProperties(style) {
99
+ return style;
100
+ }
101
+
102
+ //#endregion
103
+ //#region src/properties/properties.ts
104
+ /**
105
+ * Defines CSS properties including custom properties.
106
+ * This function is used to properly type CSS properties when defining styles,
107
+ * especially when using CSS custom properties (variables).
108
+ *
109
+ * @param style - CSS properties object that can include both standard and custom properties
110
+ * @returns The same style object with proper typing
111
+ *
112
+ * @example
113
+ * ```ts
114
+ * defineCSSProperties({
115
+ * color: 'red',
116
+ * '--custom-color': '#ff0000'
117
+ * })
118
+ * ```
119
+ */
120
+ function defineProperties(style) {
121
+ return style;
122
+ }
123
+
124
+ //#endregion
125
+ //#region src/properties/to_dom_style.ts
126
+ /**
127
+ * Converts React-style CSS properties to DOM style properties.
128
+ * This function handles both standard CSS properties and custom properties,
129
+ * ensuring proper formatting for DOM style application.
130
+ *
131
+ * @param style - React-style CSS properties object
132
+ * @returns CSSStyleDeclaration compatible object for DOM style application
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * const domStyle = toDOMStyle({
137
+ * backgroundColor: 'red',
138
+ * '--custom-color': '#ff0000'
139
+ * })
140
+ * element.style = domStyle
141
+ * ```
142
+ */
143
+ function toDOMStyle(style) {
144
+ if (style === void 0) return void 0;
145
+ const result = {};
146
+ for (const [key, value] of Object.entries(style)) result[key.startsWith("--") ? key : key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`)] = value;
147
+ return result;
148
+ }
149
+
150
+ //#endregion
151
+ //#region src/globals.ctx.ts
152
+ const ctx = {
153
+ matchMedia(query) {
154
+ return globalThis.matchMedia(query);
155
+ },
156
+ getDocumentElement() {
157
+ return globalThis.document.documentElement;
158
+ },
159
+ _reset() {
160
+ this.matchMedia = globalThis.matchMedia;
161
+ this.getDocumentElement = () => globalThis.document.documentElement;
162
+ }
163
+ };
164
+
165
+ //#endregion
166
+ //#region src/utils/attribute.ts
167
+ /**
168
+ * Gets the value of an attribute from an element.
169
+ *
170
+ * @param qualifiedName - The name of the attribute to get
171
+ * @param element - The element to get the attribute from. Defaults to `document.documentElement`
172
+ * @returns The attribute value cast to type T, or null if the attribute doesn't exist
173
+ *
174
+ * @example
175
+ * ```ts
176
+ * // Get theme from document root
177
+ * const theme = getAttribute('data-theme')
178
+ *
179
+ * // Get data-testid from a specific element
180
+ * const testId = getAttribute('data-testid', element)
181
+ * ```
182
+ */
183
+ function getAttribute(qualifiedName, element = ctx.getDocumentElement()) {
184
+ return element?.getAttribute(qualifiedName);
185
+ }
186
+ /**
187
+ * Observes attributes changes on an element and calls corresponding handlers.
188
+ *
189
+ * @param handlers - An object mapping attribute names to handler functions.
190
+ * @param element - The element to observe. Defaults to `document.documentElement`.
191
+ * @returns {MutationObserver} The observer instance, which can be used to disconnect the observer.
192
+ *
193
+ * @example
194
+ * ```ts
195
+ * const observer = observeAttributes({
196
+ * 'data-theme': (attr, value) => console.log(`Theme changed to: ${value}`),
197
+ * 'class': (attr, value) => console.log(`class changed to: ${value}`)
198
+ * });
199
+ *
200
+ * // Later, to stop observing:
201
+ * observer.disconnect();
202
+ * ```
203
+ */
204
+ function observeAttributes(handlers, element = ctx.getDocumentElement()) {
205
+ const observer = new MutationObserver((mutations) => {
206
+ for (const mutation of mutations) {
207
+ const attribute = mutation.attributeName;
208
+ const value = element.getAttribute(attribute);
209
+ handlers[attribute]?.(value);
210
+ }
211
+ });
212
+ observer.observe(element, {
213
+ attributes: true,
214
+ attributeFilter: Object.keys(handlers)
215
+ });
216
+ return observer;
217
+ }
218
+
219
+ //#endregion
220
+ //#region src/theme/class-name.ts
221
+ /**
222
+ * Gets the current theme by checking element class names against a themes map.
223
+ *
224
+ * @param options - Configuration options
225
+ * @param options.themes - Record mapping theme keys to their class name values
226
+ * @param options.defaultTheme - Fallback theme key if no matching class is found
227
+ * @param options.element - Element to check classes on (defaults to document.documentElement)
228
+ * @returns The matching theme key or defaultTheme if no match found
229
+ *
230
+ * @example
231
+ * ```ts
232
+ * const themes = {
233
+ * light: 'theme-light',
234
+ * dark: 'theme-dark'
235
+ * }
236
+ *
237
+ * // Get current theme from document.documentElement
238
+ * const theme = getThemeByClassName({
239
+ * themes,
240
+ * defaultTheme: 'light'
241
+ * })
242
+ *
243
+ * // Get theme from specific element
244
+ * const theme = getThemeByClassName({
245
+ * themes,
246
+ * element: myElement,
247
+ * defaultTheme: 'light'
248
+ * })
249
+ * ```
250
+ */
251
+ function getThemeByClassName(options) {
252
+ const className = (options.element ?? ctx.getDocumentElement()).className;
253
+ return findKey(options.themes, (theme) => className.includes(options.themes[theme])) ?? options.defaultTheme;
254
+ }
255
+ function observeThemeByClassName(options) {
256
+ return observeAttributes({ class: (value) => {
257
+ if (value === null) {
258
+ options.handler(options.defaultTheme);
259
+ return;
260
+ }
261
+ for (const name in options.themes) if (value.includes(options.themes[name])) {
262
+ options.handler(name);
263
+ break;
264
+ }
265
+ } }, options.element);
266
+ }
267
+
268
+ //#endregion
269
+ //#region src/utils/data-attribute.ts
270
+ function getDataAttribute(qualifiedName, element = ctx.getDocumentElement()) {
271
+ return getAttribute(qualifiedName, element);
272
+ }
273
+ /**
274
+ * Observes changes to `data-*` attributes on an element and calls corresponding handlers.
275
+ *
276
+ * @param options - Configuration options
277
+ * @param options.handlers - An object mapping `data-*` attribute names to handler functions.
278
+ * @param options.element - The element to observe. Defaults to `document.documentElement`
279
+ * @returns {MutationObserver} The observer instance, which can be used to disconnect the observer
280
+ *
281
+ * @example
282
+ * ```ts
283
+ * const observer = observeDataAttributes({
284
+ * handlers: {
285
+ * 'data-theme': (value) => console.log(`Theme changed to: ${value}`),
286
+ * 'data-mode': (value) => console.log(`Mode changed to: ${value}`)
287
+ * }
288
+ * });
289
+ *
290
+ * // Later, to stop observing:
291
+ * observer.disconnect();
292
+ * ```
293
+ */
294
+ function observeDataAttributes(handlers, element) {
295
+ return observeAttributes(handlers, element);
296
+ }
297
+
298
+ //#endregion
299
+ //#region src/theme/data-attribute.ts
300
+ function getThemeByDataAttribute(options) {
301
+ const value = getDataAttribute(options.attributeName, options.element) ?? void 0;
302
+ return findKey(options.themes, (theme) => options.themes[theme] === value) ?? options.defaultTheme ?? (options.allowCustom ? value : void 0);
303
+ }
304
+ function observeThemeByDataAttributes(options) {
305
+ return observeDataAttributes({ [options.attributeName]: (value) => {
306
+ if (value === null) {
307
+ options.handler(options.defaultTheme ?? null);
308
+ return;
309
+ }
310
+ for (const name in options.themes) if (options.themes[name] === value) {
311
+ options.handler(name);
312
+ return;
313
+ }
314
+ if (options.allowCustom) options.handler(value);
315
+ } }, options.element);
316
+ }
317
+
318
+ //#endregion
319
+ //#region src/utils/get-css-prop-values.ts
320
+ function getCSSPropValues(element, ...props) {
321
+ if (typeof element === "string") return getCSSPropValues(globalThis.document.body, element, ...props);
322
+ const style = globalThis.getComputedStyle(element);
323
+ return props.map((v) => style.getPropertyValue(v));
324
+ }
325
+
326
+ //#endregion
327
+ //#region src/utils/prefers-color-scheme.ts
328
+ /**
329
+ * Observes system color scheme preference changes and calls handlers when they occur.
330
+ *
331
+ * @param themes - An object mapping theme names to handler functions that are called when that theme is activated
332
+ * @returns A cleanup function that removes all event listeners
333
+ *
334
+ * @example
335
+ * ```ts
336
+ * // Observe light/dark mode changes
337
+ * const cleanup = observePrefersColorScheme({
338
+ * light: (theme) => console.log('Light mode activated'),
339
+ * dark: (theme) => console.log('Dark mode activated')
340
+ * })
341
+ *
342
+ * // Later, to stop observing:
343
+ * cleanup()
344
+ * ```
345
+ */
346
+ function observePrefersColorScheme(themes) {
347
+ const removers = mapKey(themes, (t) => {
348
+ const m = ctx.matchMedia(`(prefers-color-scheme: ${t})`);
349
+ const listener = (event) => {
350
+ if (event.matches) themes[t]?.(t);
351
+ };
352
+ m.addEventListener("change", listener);
353
+ return () => m.removeEventListener("change", listener);
354
+ });
355
+ return () => {
356
+ for (const remover of removers) remover();
357
+ };
358
+ }
359
+ /**
360
+ * Gets the current preferred color theme from the system settings.
361
+ *
362
+ * @param themes - A list of theme names to check against the system preference
363
+ * @returns The first matching theme from the provided list, or null if none match
364
+ *
365
+ * @example
366
+ * ```ts
367
+ * // Check if system prefers light or dark mode
368
+ * const theme = getPrefersColorTheme('light', 'dark')
369
+ * // Returns 'light', 'dark', or null
370
+ * ```
371
+ */
372
+ function getPrefersColorTheme(...themes) {
373
+ return themes.find((theme) => ctx.matchMedia(`(prefers-color-scheme: ${theme})`).matches) ?? null;
374
+ }
375
+
376
+ //#endregion
377
+ export { defineCSSProperties, defineProperties, getAttribute, getCSSPropValues, getDataAttribute, getPrefersColorTheme, getThemeByClassName, getThemeByDataAttribute, observeAttributes, observeDataAttributes, observePrefersColorScheme, observeThemeByClassName, observeThemeByDataAttributes, px2num, px2rem, rem2px, toDOMStyle };
378
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/convertors/px_2_num.ts","../src/convertors/px_2_rem.ts","../src/convertors/rem_2_px.ts","../src/properties/css_properties.ts","../src/properties/properties.ts","../src/properties/to_dom_style.ts","../src/globals.ctx.ts","../src/utils/attribute.ts","../src/theme/class-name.ts","../src/utils/data-attribute.ts","../src/theme/data-attribute.ts","../src/utils/get-css-prop-values.ts","../src/utils/prefers-color-scheme.ts"],"sourcesContent":["/**\n * Converts pixel values to numbers.\n *\n * @param px - The pixel value to convert. Can be a number or string (e.g. '16px' or '16')\n * @returns The numeric value\n *\n * @example\n * ```ts\n * px2num(16) // 16\n * px2num('32px') // 32\n * px2num('12.5px') // 12.5\n * px2num('0px') // 0\n * ```\n */\nexport function px2num(px: number | string | undefined): number {\n\treturn typeof px === 'string' ? Number.parseFloat(px.replace(/px$/, '')) : Number(px)\n}\n","/**\n * Converts pixel values to rem units.\n *\n * @param px - The pixel value to convert. Can be a number or string (e.g. '16px' or '16')\n * @param options - Optional configuration\n * @param options.base - Base pixel value to calculate rem units from. Defaults to 16\n * @param options.precision - Number of decimal places in the output. Defaults to 4\n * @returns The converted value as a string with 'rem' units\n *\n * @example\n * ```ts\n * px2rem(16) // '1.0000'\n * px2rem('32px') // '2.0000'\n * px2rem(20, { base: 20 }) // '1.0000'\n * px2rem(13, { precision: 2 }) // '0.81'\n * ```\n */\nexport function px2rem(\n\tpx: number | string,\n\toptions?: { base?: number | undefined; precision?: number | undefined },\n): number {\n\tconst { base = 16, precision = 4 } = options ?? {}\n\n\tif (typeof px === 'string') {\n\t\tpx = px.replace(/px$/, '')\n\t\tpx = Number.parseFloat(px)\n\t}\n\n\treturn Number((px / base).toFixed(precision))\n}\n","/**\n * Converts rem values to pixel units.\n *\n * @param rem - The rem value to convert. Can be a number or string (e.g. '1rem' or '1')\n * @param options - Optional configuration\n * @param options.base - Base pixel value to calculate pixels from. Defaults to 16\n * @param options.precision - Number of decimal places in the output. Defaults to 4\n * @returns The converted value as a string with 'px' units\n *\n * @example\n * ```ts\n * rem2px(1) // '16.0000'\n * rem2px('2rem') // '32.0000'\n * rem2px(1, { base: 20 }) // '20.0000'\n * rem2px(0.8125, { precision: 2 }) // '13.00'\n * ```\n */\nexport function rem2px(\n\trem: number | string,\n\toptions?: { base?: number | undefined; precision?: number | undefined },\n): number {\n\tconst { base = 16, precision = 4 } = options ?? {}\n\n\tif (typeof rem === 'string') {\n\t\trem = rem.replace(/rem$/, '')\n\t\trem = Number.parseFloat(rem)\n\t}\n\n\treturn Number((rem * base).toFixed(precision))\n}\n","import type { Properties as CSSTypeProperties } from 'csstype'\n\n/**\n * Extends CSS properties to include custom properties.\n * Allows for string or number values for standard properties,\n * and string values for custom properties with '--' prefix.\n *\n * @deprecated Use `Properties` instead.\n */\nexport interface CSSProperties extends CSSTypeProperties<string | number> {\n\t[k: `--${string}`]: string\n}\n\n/**\n * Defines CSS properties including custom properties.\n * This function is used to properly type CSS properties when defining styles,\n * especially when using CSS custom properties (variables).\n *\n * @deprecated Use `defineProperties` instead.\n *\n * @param style - CSS properties object that can include both standard and custom properties\n * @returns The same style object with proper typing\n *\n * @example\n * ```ts\n * defineCSSProperties({\n * color: 'red',\n * '--custom-color': '#ff0000'\n * })\n * ```\n */\nexport function defineCSSProperties(style: CSSProperties) {\n\treturn style as any\n}\n","import type { Properties as CSSTypeProperties } from 'csstype'\n\n/**\n * Extends CSS properties to include custom properties.\n * Allows for string or number values for standard properties,\n * and string values for custom properties with '--' prefix.\n */\nexport interface Properties<TLength = 0 | (string & {}), TTime = string & {}>\n\textends CSSTypeProperties<TLength, TTime> {\n\t[k: `--${string}`]: string\n}\n\n/**\n * Defines CSS properties including custom properties.\n * This function is used to properly type CSS properties when defining styles,\n * especially when using CSS custom properties (variables).\n *\n * @param style - CSS properties object that can include both standard and custom properties\n * @returns The same style object with proper typing\n *\n * @example\n * ```ts\n * defineCSSProperties({\n * color: 'red',\n * '--custom-color': '#ff0000'\n * })\n * ```\n */\nexport function defineProperties<TLength = 0 | (string & {}), TTime = string & {}>(style: Properties<TLength, TTime>) {\n\treturn style as Properties\n}\n","import type { CSSProperties } from './css_properties.ts'\n\n/**\n * Converts React-style CSS properties to DOM style properties.\n * This function handles both standard CSS properties and custom properties,\n * ensuring proper formatting for DOM style application.\n *\n * @param style - React-style CSS properties object\n * @returns CSSStyleDeclaration compatible object for DOM style application\n *\n * @example\n * ```ts\n * const domStyle = toDOMStyle({\n * backgroundColor: 'red',\n * '--custom-color': '#ff0000'\n * })\n * element.style = domStyle\n * ```\n */\nexport function toDOMStyle(style: CSSProperties | undefined): Partial<CSSStyleDeclaration> | undefined {\n\tif (style === undefined) return undefined\n\n\tconst result = {} as any\n\n\tfor (const [key, value] of Object.entries(style)) {\n\t\tresult[key.startsWith('--') ? key : key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`)] = value\n\t}\n\n\treturn result\n}\n","export const ctx = {\n\tmatchMedia(query: string) {\n\t\treturn globalThis.matchMedia(query)\n\t},\n\tgetDocumentElement() {\n\t\treturn globalThis.document.documentElement\n\t},\n\t_reset() {\n\t\tthis.matchMedia = globalThis.matchMedia\n\t\tthis.getDocumentElement = () => globalThis.document.documentElement\n\t},\n}\n","import { ctx } from '../globals.ctx.ts'\n\n/**\n * Gets the value of an attribute from an element.\n *\n * @param qualifiedName - The name of the attribute to get\n * @param element - The element to get the attribute from. Defaults to `document.documentElement`\n * @returns The attribute value cast to type T, or null if the attribute doesn't exist\n *\n * @example\n * ```ts\n * // Get theme from document root\n * const theme = getAttribute('data-theme')\n *\n * // Get data-testid from a specific element\n * const testId = getAttribute('data-testid', element)\n * ```\n */\nexport function getAttribute<T extends string>(\n\tqualifiedName: T,\n\telement: Element | undefined = ctx.getDocumentElement(),\n) {\n\treturn element?.getAttribute(qualifiedName)\n}\n\n/**\n * Observes attributes changes on an element and calls corresponding handlers.\n *\n * @param handlers - An object mapping attribute names to handler functions.\n * @param element - The element to observe. Defaults to `document.documentElement`.\n * @returns {MutationObserver} The observer instance, which can be used to disconnect the observer.\n *\n * @example\n * ```ts\n * const observer = observeAttributes({\n * 'data-theme': (attr, value) => console.log(`Theme changed to: ${value}`),\n * 'class': (attr, value) => console.log(`class changed to: ${value}`)\n * });\n *\n * // Later, to stop observing:\n * observer.disconnect();\n * ```\n */\nexport function observeAttributes<T extends string>(\n\thandlers: Record<string, (value: T | null) => void>,\n\telement: Element | undefined = ctx.getDocumentElement(),\n) {\n\tconst observer = new MutationObserver((mutations) => {\n\t\tfor (const mutation of mutations) {\n\t\t\tconst attribute = mutation.attributeName!\n\t\t\tconst value = element.getAttribute(attribute) as T | null\n\t\t\thandlers[attribute]?.(value)\n\t\t}\n\t})\n\tobserver.observe(element, {\n\t\tattributes: true,\n\t\tattributeFilter: Object.keys(handlers),\n\t})\n\treturn observer\n}\n","import { findKey } from 'type-plus'\nimport { ctx } from '../globals.ctx.ts'\nimport { observeAttributes } from '../utils/attribute.ts'\n\n/**\n * Gets the current theme by checking element class names against a themes map.\n *\n * @param options - Configuration options\n * @param options.themes - Record mapping theme keys to their class name values\n * @param options.defaultTheme - Fallback theme key if no matching class is found\n * @param options.element - Element to check classes on (defaults to document.documentElement)\n * @returns The matching theme key or defaultTheme if no match found\n *\n * @example\n * ```ts\n * const themes = {\n * light: 'theme-light',\n * dark: 'theme-dark'\n * }\n *\n * // Get current theme from document.documentElement\n * const theme = getThemeByClassName({\n * themes,\n * defaultTheme: 'light'\n * })\n *\n * // Get theme from specific element\n * const theme = getThemeByClassName({\n * themes,\n * element: myElement,\n * defaultTheme: 'light'\n * })\n * ```\n */\nexport function getThemeByClassName<Themes extends Record<string, string>>(options: {\n\tthemes: Themes\n\tdefaultTheme?: keyof Themes | undefined\n\telement?: Element | undefined\n}): keyof Themes | undefined {\n\tconst element = options.element ?? ctx.getDocumentElement()\n\tconst className = element.className\n\tconst theme = findKey(options.themes, (theme) => className.includes(options.themes[theme]!))\n\treturn theme ?? options.defaultTheme\n}\n\nexport function observeThemeByClassName<Themes extends Record<string, string>>(options: {\n\tthemes: Themes\n\thandler: (value: string | undefined) => void\n\tdefaultTheme?: keyof Themes | undefined\n\telement?: Element | undefined\n}) {\n\treturn observeAttributes(\n\t\t{\n\t\t\tclass: (value: string | null) => {\n\t\t\t\tif (value === null) {\n\t\t\t\t\toptions.handler(options.defaultTheme as string)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tfor (const name in options.themes) {\n\t\t\t\t\tif (value.includes(options.themes[name]!)) {\n\t\t\t\t\t\toptions.handler(name)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\toptions.element,\n\t)\n}\n","import { ctx } from '../globals.ctx.ts'\nimport { getAttribute, observeAttributes } from './attribute.ts'\n\nexport function getDataAttribute<T extends `data-${string}`>(\n\tqualifiedName: T,\n\telement: Element | undefined = ctx.getDocumentElement(),\n) {\n\treturn getAttribute(qualifiedName, element)\n}\n\n/**\n * Observes changes to `data-*` attributes on an element and calls corresponding handlers.\n *\n * @param options - Configuration options\n * @param options.handlers - An object mapping `data-*` attribute names to handler functions.\n * @param options.element - The element to observe. Defaults to `document.documentElement`\n * @returns {MutationObserver} The observer instance, which can be used to disconnect the observer\n *\n * @example\n * ```ts\n * const observer = observeDataAttributes({\n * handlers: {\n * 'data-theme': (value) => console.log(`Theme changed to: ${value}`),\n * 'data-mode': (value) => console.log(`Mode changed to: ${value}`)\n * }\n * });\n *\n * // Later, to stop observing:\n * observer.disconnect();\n * ```\n */\nexport function observeDataAttributes<T extends string, K extends `data-${string}`>(\n\thandlers: Record<K, (value: T | null) => void>,\n\telement?: Element | undefined,\n) {\n\treturn observeAttributes(handlers, element)\n}\n","import { findKey } from 'type-plus'\nimport { getDataAttribute, observeDataAttributes } from '../utils/data-attribute.ts'\n\n/**\n * Gets the theme based on a data attribute value.\n *\n * @param options - Configuration options\n * @param options.themes - Record mapping theme keys to their data attribute values\n * @param options.defaultTheme - Fallback theme key if attribute value doesn't match any theme\n * @param options.attributeName - Name of the data attribute to check (must start with 'data-')\n * @param options.allowCustom - Whether to allow custom themes value\n * @returns The matching theme key, or defaultTheme if no match found\n *\n * @example\n * ```ts\n * const themes = {\n * light: 'light',\n * dark: 'dark',\n * system: 'system'\n * }\n *\n * // Get theme from data-theme attribute\n * const theme = getThemeByDataAttribute({\n * themes,\n * defaultTheme: 'system',\n * attributeName: 'data-theme'\n * })\n * ```\n */\nexport function getThemeByDataAttribute<Themes extends Record<string, string>>(options: {\n\tattributeName: `data-${string}`\n\tdefaultTheme?: keyof Themes | undefined\n\tthemes: Themes\n\telement?: Element | undefined\n}): keyof Themes | undefined\nexport function getThemeByDataAttribute<Themes extends Record<string, string>>(options: {\n\tattributeName: `data-${string}`\n\tallowCustom: true | undefined\n\tdefaultTheme?: keyof Themes | undefined\n\tthemes: Themes\n\telement?: Element | undefined\n}): string | undefined\nexport function getThemeByDataAttribute<Themes extends Record<string, string>>(options: {\n\tattributeName: `data-${string}`\n\tallowCustom?: boolean | undefined\n\tdefaultTheme?: keyof Themes | undefined\n\tthemes: Themes\n\telement?: Element | undefined\n}): keyof Themes | undefined {\n\tconst value = getDataAttribute(options.attributeName, options.element) ?? undefined\n\tconst theme = findKey(options.themes, (theme) => options.themes[theme] === value)\n\n\treturn theme ?? options.defaultTheme ?? (options.allowCustom ? value : undefined)\n}\n\n/**\n * Observes changes to a theme data attribute and calls a handler when it changes.\n *\n * @param options - Configuration options\n * @param options.themes - Record mapping theme keys to their data attribute values\n * @param options.handler - Callback function called with the new theme value or null when removed\n * @param options.defaultTheme - Fallback theme key if attribute value doesn't match any theme\n * @param options.attributeName - Name of the data attribute to observe (must start with 'data-')\n * @returns A MutationObserver that can be disconnected to stop observing\n *\n * @example\n * ```ts\n * const themes = {\n * light: 'light',\n * dark: 'dark'\n * }\n *\n * // Observe data-theme attribute changes\n * const observer = observeThemeByDataAttributes({\n * themes,\n * handler: (theme) => console.log('Theme changed to:', theme),\n * defaultTheme: 'light',\n * attributeName: 'data-theme'\n * })\n *\n * // Stop observing\n * observer.disconnect()\n * ```\n */\nexport function observeThemeByDataAttributes<Themes extends Record<string, string>>(options: {\n\tattributeName: `data-${string}`\n\tthemes: Themes\n\thandler: (value: string | null) => void\n\tdefaultTheme?: keyof Themes | undefined\n\telement?: Element | undefined\n}): MutationObserver\nexport function observeThemeByDataAttributes<Themes extends Record<string, string>>(options: {\n\tattributeName: `data-${string}`\n\tthemes: Themes\n\thandler: (value: string | null) => void\n\tallowCustom: true | undefined\n\tdefaultTheme?: keyof Themes | undefined\n\telement?: Element | undefined\n}): MutationObserver\nexport function observeThemeByDataAttributes<Themes extends Record<string, string>>(options: {\n\tattributeName: `data-${string}`\n\tthemes: Themes\n\thandler: (value: string | null) => void\n\tallowCustom?: boolean | undefined\n\tdefaultTheme?: keyof Themes | undefined\n\telement?: Element | undefined\n}): MutationObserver {\n\treturn observeDataAttributes(\n\t\t{\n\t\t\t[options.attributeName]: (value: string | null) => {\n\t\t\t\tif (value === null) {\n\t\t\t\t\toptions.handler((options.defaultTheme as string) ?? null)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tfor (const name in options.themes) {\n\t\t\t\t\tif (options.themes[name] === value) {\n\t\t\t\t\t\toptions.handler(name)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (options.allowCustom) {\n\t\t\t\t\toptions.handler(value)\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\toptions.element,\n\t)\n}\n","import type { CreateTuple } from 'type-plus'\n\n/**\n * Retrieves CSS custom property values from the specified element.\n *\n * @param element - The HTML element to get property values from\n * @param props - CSS custom property names to retrieve, must be in the format `--property-name`\n * @returns Array of property values corresponding to the requested custom properties\n */\nexport function getCSSPropValues<Props extends Array<`--${string}`>>(\n\telement: HTMLElement,\n\t...props: Props\n): CreateTuple<Props['length'], string>\n/**\n * Retrieves CSS custom property values from `document.body`.\n *\n * @param props - CSS custom property names to retrieve, must be in the format `--property-name`\n * @returns Array of property values corresponding to the requested custom properties\n */\nexport function getCSSPropValues<Props extends Array<`--${string}`>>(\n\t...props: Props\n): CreateTuple<Props['length'], string>\nexport function getCSSPropValues<Props extends Array<`--${string}`>>(element: unknown, ...props: Props) {\n\tif (typeof element === 'string') {\n\t\treturn getCSSPropValues(globalThis.document.body, element as `--${string}`, ...props)\n\t}\n\tconst style = globalThis.getComputedStyle(element as HTMLElement)\n\treturn props.map((v) => style.getPropertyValue(v)) as any\n}\n","import { mapKey } from 'type-plus'\nimport { ctx } from '../globals.ctx.ts'\n\n/**\n * Observes system color scheme preference changes and calls handlers when they occur.\n *\n * @param themes - An object mapping theme names to handler functions that are called when that theme is activated\n * @returns A cleanup function that removes all event listeners\n *\n * @example\n * ```ts\n * // Observe light/dark mode changes\n * const cleanup = observePrefersColorScheme({\n * light: (theme) => console.log('Light mode activated'),\n * dark: (theme) => console.log('Dark mode activated')\n * })\n *\n * // Later, to stop observing:\n * cleanup()\n * ```\n */\nexport function observePrefersColorScheme<T extends string>(themes: Record<T, (value: T | null) => void>) {\n\tconst removers = mapKey(themes, (t) => {\n\t\tconst m = ctx.matchMedia(`(prefers-color-scheme: ${t as string})`)\n\t\tconst listener = (event: MediaQueryListEvent) => {\n\t\t\tif (event.matches) {\n\t\t\t\tthemes[t]?.(t)\n\t\t\t}\n\t\t}\n\n\t\tm.addEventListener('change', listener)\n\t\treturn () => m.removeEventListener('change', listener)\n\t})\n\n\treturn () => {\n\t\tfor (const remover of removers) {\n\t\t\tremover()\n\t\t}\n\t}\n}\n\n/**\n * Gets the current preferred color theme from the system settings.\n *\n * @param themes - A list of theme names to check against the system preference\n * @returns The first matching theme from the provided list, or null if none match\n *\n * @example\n * ```ts\n * // Check if system prefers light or dark mode\n * const theme = getPrefersColorTheme('light', 'dark')\n * // Returns 'light', 'dark', or null\n * ```\n */\nexport function getPrefersColorTheme<T extends string>(...themes: T[]) {\n\treturn themes.find((theme) => ctx.matchMedia(`(prefers-color-scheme: ${theme})`).matches) ?? null\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAcA,SAAgB,OAAO,IAAyC;AAC/D,QAAO,OAAO,OAAO,WAAW,OAAO,WAAW,GAAG,QAAQ,OAAO,GAAG,CAAC,GAAG,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;ACEtF,SAAgB,OACf,IACA,SACS;CACT,MAAM,EAAE,OAAO,IAAI,YAAY,MAAM,WAAW,EAAE;AAElD,KAAI,OAAO,OAAO,UAAU;AAC3B,OAAK,GAAG,QAAQ,OAAO,GAAG;AAC1B,OAAK,OAAO,WAAW,GAAG;;AAG3B,QAAO,QAAQ,KAAK,MAAM,QAAQ,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;ACX9C,SAAgB,OACf,KACA,SACS;CACT,MAAM,EAAE,OAAO,IAAI,YAAY,MAAM,WAAW,EAAE;AAElD,KAAI,OAAO,QAAQ,UAAU;AAC5B,QAAM,IAAI,QAAQ,QAAQ,GAAG;AAC7B,QAAM,OAAO,WAAW,IAAI;;AAG7B,QAAO,QAAQ,MAAM,MAAM,QAAQ,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;ACG/C,SAAgB,oBAAoB,OAAsB;AACzD,QAAO;;;;;;;;;;;;;;;;;;;;;ACJR,SAAgB,iBAAmE,OAAmC;AACrH,QAAO;;;;;;;;;;;;;;;;;;;;;;ACVR,SAAgB,WAAW,OAA4E;AACtG,KAAI,UAAU,OAAW,QAAO;CAEhC,MAAM,SAAS,EAAE;AAEjB,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,CAC/C,QAAO,IAAI,WAAW,KAAK,GAAG,MAAM,IAAI,QAAQ,WAAW,UAAU,IAAI,MAAM,aAAa,GAAG,IAAI;AAGpG,QAAO;;;;;AC5BR,MAAa,MAAM;CAClB,WAAW,OAAe;AACzB,SAAO,WAAW,WAAW,MAAM;;CAEpC,qBAAqB;AACpB,SAAO,WAAW,SAAS;;CAE5B,SAAS;AACR,OAAK,aAAa,WAAW;AAC7B,OAAK,2BAA2B,WAAW,SAAS;;CAErD;;;;;;;;;;;;;;;;;;;;ACOD,SAAgB,aACf,eACA,UAA+B,IAAI,oBAAoB,EACtD;AACD,QAAO,SAAS,aAAa,cAAc;;;;;;;;;;;;;;;;;;;;AAqB5C,SAAgB,kBACf,UACA,UAA+B,IAAI,oBAAoB,EACtD;CACD,MAAM,WAAW,IAAI,kBAAkB,cAAc;AACpD,OAAK,MAAM,YAAY,WAAW;GACjC,MAAM,YAAY,SAAS;GAC3B,MAAM,QAAQ,QAAQ,aAAa,UAAU;AAC7C,YAAS,aAAa,MAAM;;GAE5B;AACF,UAAS,QAAQ,SAAS;EACzB,YAAY;EACZ,iBAAiB,OAAO,KAAK,SAAS;EACtC,CAAC;AACF,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxBR,SAAgB,oBAA2D,SAI9C;CAE5B,MAAM,aADU,QAAQ,WAAW,IAAI,oBAAoB,EACjC;AAE1B,QADc,QAAQ,QAAQ,SAAS,UAAU,UAAU,SAAS,QAAQ,OAAO,OAAQ,CAAC,IAC5E,QAAQ;;AAGzB,SAAgB,wBAA+D,SAK5E;AACF,QAAO,kBACN,EACC,QAAQ,UAAyB;AAChC,MAAI,UAAU,MAAM;AACnB,WAAQ,QAAQ,QAAQ,aAAuB;AAC/C;;AAGD,OAAK,MAAM,QAAQ,QAAQ,OAC1B,KAAI,MAAM,SAAS,QAAQ,OAAO,MAAO,EAAE;AAC1C,WAAQ,QAAQ,KAAK;AACrB;;IAIH,EACD,QAAQ,QACR;;;;;ACjEF,SAAgB,iBACf,eACA,UAA+B,IAAI,oBAAoB,EACtD;AACD,QAAO,aAAa,eAAe,QAAQ;;;;;;;;;;;;;;;;;;;;;;;AAwB5C,SAAgB,sBACf,UACA,SACC;AACD,QAAO,kBAAkB,UAAU,QAAQ;;;;;ACO5C,SAAgB,wBAA+D,SAMlD;CAC5B,MAAM,QAAQ,iBAAiB,QAAQ,eAAe,QAAQ,QAAQ,IAAI;AAG1E,QAFc,QAAQ,QAAQ,SAAS,UAAU,QAAQ,OAAO,WAAW,MAAM,IAEjE,QAAQ,iBAAiB,QAAQ,cAAc,QAAQ;;AA+CxE,SAAgB,6BAAoE,SAO/D;AACpB,QAAO,sBACN,GACE,QAAQ,iBAAiB,UAAyB;AAClD,MAAI,UAAU,MAAM;AACnB,WAAQ,QAAS,QAAQ,gBAA2B,KAAK;AACzD;;AAGD,OAAK,MAAM,QAAQ,QAAQ,OAC1B,KAAI,QAAQ,OAAO,UAAU,OAAO;AACnC,WAAQ,QAAQ,KAAK;AACrB;;AAIF,MAAI,QAAQ,YACX,SAAQ,QAAQ,MAAM;IAGxB,EACD,QAAQ,QACR;;;;;AC1GF,SAAgB,iBAAqD,SAAkB,GAAG,OAAc;AACvG,KAAI,OAAO,YAAY,SACtB,QAAO,iBAAiB,WAAW,SAAS,MAAM,SAA0B,GAAG,MAAM;CAEtF,MAAM,QAAQ,WAAW,iBAAiB,QAAuB;AACjE,QAAO,MAAM,KAAK,MAAM,MAAM,iBAAiB,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;ACNnD,SAAgB,0BAA4C,QAA8C;CACzG,MAAM,WAAW,OAAO,SAAS,MAAM;EACtC,MAAM,IAAI,IAAI,WAAW,0BAA0B,EAAY,GAAG;EAClE,MAAM,YAAY,UAA+B;AAChD,OAAI,MAAM,QACT,QAAO,KAAK,EAAE;;AAIhB,IAAE,iBAAiB,UAAU,SAAS;AACtC,eAAa,EAAE,oBAAoB,UAAU,SAAS;GACrD;AAEF,cAAa;AACZ,OAAK,MAAM,WAAW,SACrB,UAAS;;;;;;;;;;;;;;;;AAkBZ,SAAgB,qBAAuC,GAAG,QAAa;AACtE,QAAO,OAAO,MAAM,UAAU,IAAI,WAAW,0BAA0B,MAAM,GAAG,CAAC,QAAQ,IAAI"}
package/package.json CHANGED
@@ -1,17 +1,28 @@
1
1
  {
2
2
  "name": "@just-web/css",
3
- "version": "0.6.1",
3
+ "version": "0.8.0",
4
4
  "description": "CSS types and utilities",
5
+ "homepage": "https://github.com/justland/just-web-foundation/tree/main/libs/css",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/justland/just-web-foundation.git",
9
+ "directory": "libs/css"
10
+ },
11
+ "license": "MIT",
12
+ "author": "Unional <homawong@gmail.com>",
5
13
  "type": "module",
14
+ "imports": {
15
+ "#just-web/css": "./src/index.ts"
16
+ },
6
17
  "exports": {
7
18
  ".": {
8
- "types": "./esm/index.d.ts",
9
- "default": "./esm/index.js"
19
+ "types": "./esm/index.d.mts",
20
+ "default": "./esm/index.mjs"
10
21
  },
11
22
  "./package.json": "./package.json"
12
23
  },
13
- "main": "./cjs/index.js",
14
- "types": "./cjs/index.d.ts",
24
+ "main": "./cjs/index.cjs",
25
+ "types": "./cjs/index.d.cts",
15
26
  "files": [
16
27
  "cjs",
17
28
  "esm",
@@ -24,47 +35,37 @@
24
35
  "type-plus": "8.0.0-beta.7"
25
36
  },
26
37
  "devDependencies": {
27
- "@repobuddy/storybook": "^0.12.0",
28
- "@repobuddy/vitest": "^1.2.2",
29
- "@storybook/addon-essentials": "^8.6.12",
30
- "@storybook/addon-storysource": "^8.6.12",
31
- "@storybook/blocks": "^8.6.12",
32
- "@storybook/experimental-addon-test": "^8.6.12",
33
- "@storybook/manager-api": "^8.6.12",
34
- "@storybook/preview-api": "^8.6.12",
35
- "@storybook/react": "^8.6.12",
36
- "@storybook/react-vite": "^8.6.12",
37
- "@storybook/test": "^8.6.12",
38
- "@storybook/theming": "^8.6.12",
38
+ "@repobuddy/storybook": "^2.1.2",
39
+ "@repobuddy/vitest": "^2.1.1",
40
+ "@storybook-community/storybook-dark-mode": "^7.0.3",
41
+ "@storybook/addon-docs": "^10.1.10",
42
+ "@storybook/addon-vitest": "^10.1.10",
43
+ "@storybook/react-vite": "^10.1.10",
39
44
  "@tailwindcss/cli": "^4.1.6",
40
45
  "@tailwindcss/vite": "^4.1.6",
41
- "@vitest/browser": "^3.1.3",
42
- "@vitest/coverage-v8": "^3.1.3",
46
+ "@vitest/browser": "^4.0.16",
47
+ "@vitest/browser-playwright": "^4.0.16",
48
+ "@vitest/coverage-v8": "^4.0.16",
43
49
  "dedent": "^1.6.0",
44
- "ncp": "^2.0.0",
45
- "playwright": "^1.52.0",
46
50
  "react": "^18.3.1",
47
51
  "react-dom": "^18.3.1",
48
52
  "rimraf": "^6.0.1",
49
- "storybook": "^8.6.12",
50
- "storybook-addon-code-editor": "^4.1.1",
51
- "storybook-addon-tag-badges": "^1.4.0",
52
- "storybook-addon-vis": "^0.19.4",
53
- "storybook-dark-mode": "^4.0.2",
54
- "tailwindcss": "^4.1.6",
53
+ "storybook": "^10.1.10",
54
+ "storybook-addon-code-editor": "^6.1.1",
55
+ "storybook-addon-tag-badges": "^3.0.4",
56
+ "storybook-addon-vis": "^3.1.2",
57
+ "tailwindcss": "^4.1.18",
58
+ "tsdown": "^0.18.3",
55
59
  "typescript": "^5.8.3",
56
- "unbuild": "^3.5.0",
57
- "vite": "^6.3.5",
58
- "vitest": "^3.1.3",
59
- "vitest-browser-react": "^0.1.1",
60
+ "vite": "^7.3.0",
61
+ "vitest": "^4.0.16",
62
+ "vitest-browser-react": "^2.0.2",
60
63
  "@tools/typescript": "^0.0.1"
61
64
  },
62
65
  "scripts": {
63
- "build": "run-p build:*",
66
+ "build": "tsdown",
64
67
  "build-doc": "storybook build -o ../../docs/css",
65
- "build:cjs": "unbuild && ncp ../../tools/ts/package.cjs.json ./cjs/package.json",
66
- "build:esm": "tsc -p tsconfig.esm.json",
67
- "clean": "rimraf .turbo esm *.tsbuildinfo",
68
+ "clean": "rimraf .turbo cjs esm *.tsbuildinfo dist",
68
69
  "cov": "vitest run --coverage",
69
70
  "inspect:css": "tailwindcss -i ./src/tailwind.css -o ./styles.css",
70
71
  "nuke": "rimraf node_modules",
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Converts pixel values to numbers.
3
+ *
4
+ * @param px - The pixel value to convert. Can be a number or string (e.g. '16px' or '16')
5
+ * @returns The numeric value
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * px2num(16) // 16
10
+ * px2num('32px') // 32
11
+ * px2num('12.5px') // 12.5
12
+ * px2num('0px') // 0
13
+ * ```
14
+ */
15
+ export function px2num(px: number | string | undefined): number {
16
+ return typeof px === 'string' ? Number.parseFloat(px.replace(/px$/, '')) : Number(px)
17
+ }
package/src/index.ts CHANGED
@@ -1,7 +1,11 @@
1
+ export type * from 'csstype'
2
+ export * from './convertors/px_2_num.ts'
1
3
  export * from './convertors/px_2_rem.ts'
2
4
  export * from './convertors/rem_2_px.ts'
3
- export * from './css-properties/css-properties.ts'
4
- export * from './css-properties/to_dom_style.ts'
5
+ export * from './properties/css_properties.ts'
6
+ export { defineProperties } from './properties/properties.ts'
7
+ export type { Properties } from './properties/properties.ts'
8
+ export * from './properties/to_dom_style.ts'
5
9
  export * from './props/class-name.ts'
6
10
  export * from './props/style.ts'
7
11
  export * from './theme/class-name.ts'
@@ -1,11 +1,13 @@
1
- import type { Properties } from 'csstype'
1
+ import type { Properties as CSSTypeProperties } from 'csstype'
2
2
 
3
3
  /**
4
4
  * Extends CSS properties to include custom properties.
5
5
  * Allows for string or number values for standard properties,
6
6
  * and string values for custom properties with '--' prefix.
7
+ *
8
+ * @deprecated Use `Properties` instead.
7
9
  */
8
- export interface CSSProperties extends Properties<string | number> {
10
+ export interface CSSProperties extends CSSTypeProperties<string | number> {
9
11
  [k: `--${string}`]: string
10
12
  }
11
13
 
@@ -14,6 +16,8 @@ export interface CSSProperties extends Properties<string | number> {
14
16
  * This function is used to properly type CSS properties when defining styles,
15
17
  * especially when using CSS custom properties (variables).
16
18
  *
19
+ * @deprecated Use `defineProperties` instead.
20
+ *
17
21
  * @param style - CSS properties object that can include both standard and custom properties
18
22
  * @returns The same style object with proper typing
19
23
  *
@@ -1,12 +1,15 @@
1
- import type { Properties } from 'csstype';
1
+ import type { Properties as CSSTypeProperties } from 'csstype'
2
+
2
3
  /**
3
4
  * Extends CSS properties to include custom properties.
4
5
  * Allows for string or number values for standard properties,
5
6
  * and string values for custom properties with '--' prefix.
6
7
  */
7
- export interface CSSProperties extends Properties<string | number> {
8
- [k: `--${string}`]: string;
8
+ export interface Properties<TLength = 0 | (string & {}), TTime = string & {}>
9
+ extends CSSTypeProperties<TLength, TTime> {
10
+ [k: `--${string}`]: string
9
11
  }
12
+
10
13
  /**
11
14
  * Defines CSS properties including custom properties.
12
15
  * This function is used to properly type CSS properties when defining styles,
@@ -23,4 +26,6 @@ export interface CSSProperties extends Properties<string | number> {
23
26
  * })
24
27
  * ```
25
28
  */
26
- export declare function defineCSSProperties(style: CSSProperties): any;
29
+ export function defineProperties<TLength = 0 | (string & {}), TTime = string & {}>(style: Properties<TLength, TTime>) {
30
+ return style as Properties
31
+ }
@@ -1,4 +1,4 @@
1
- import type { CSSProperties } from './css-properties.ts'
1
+ import type { CSSProperties } from './css_properties.ts'
2
2
 
3
3
  /**
4
4
  * Converts React-style CSS properties to DOM style properties.
@@ -7,6 +7,6 @@
7
7
  * Interface for component props that include a className property.
8
8
  * The className property accepts a string value for CSS class names.
9
9
  */
10
- export interface ClassNameProps {
10
+ export type ClassNameProps = {
11
11
  className?: string | undefined
12
12
  }
@@ -1,8 +1,8 @@
1
- import type { CSSProperties } from '../css-properties/css-properties.ts'
1
+ import type { Properties } from '../properties/properties.ts'
2
2
 
3
3
  /**
4
4
  * Interface for component props that include a style property.
5
5
  */
6
- export interface StyleProps {
7
- style?: CSSProperties | undefined
6
+ export type StyleProps<TLength = 0 | (string & {}), TTime = string & {}> = {
7
+ style?: Properties<TLength, TTime> | undefined
8
8
  }
@@ -1,21 +0,0 @@
1
- /**
2
- * Converts pixel values to rem units.
3
- *
4
- * @param px - The pixel value to convert. Can be a number or string (e.g. '16px' or '16')
5
- * @param options - Optional configuration
6
- * @param options.base - Base pixel value to calculate rem units from. Defaults to 16
7
- * @param options.precision - Number of decimal places in the output. Defaults to 4
8
- * @returns The converted value as a string with 'rem' units
9
- *
10
- * @example
11
- * ```ts
12
- * px2rem(16) // '1.0000'
13
- * px2rem('32px') // '2.0000'
14
- * px2rem(20, { base: 20 }) // '1.0000'
15
- * px2rem(13, { precision: 2 }) // '0.81'
16
- * ```
17
- */
18
- export declare function px2rem(px: number | string, options?: {
19
- base?: number | undefined;
20
- precision?: number | undefined;
21
- }): number;