css-calipers 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +36 -1
  2. package/dist/cjs/libraryHelpers/vanilla-extract.js +7 -0
  3. package/dist/cjs/mediaQueries/factory.js +162 -0
  4. package/dist/cjs/mediaQueries/helpers.js +97 -0
  5. package/dist/cjs/mediaQueries/index.js +22 -0
  6. package/dist/cjs/mediaQueries/linting/core.js +19 -0
  7. package/dist/cjs/mediaQueries/linting/resolution.js +11 -0
  8. package/dist/cjs/mediaQueries/linting.js +24 -0
  9. package/dist/cjs/mediaQueries/mediaQueries.js +51 -0
  10. package/dist/cjs/mediaQueries/mediaQueryFactory.js +120 -0
  11. package/dist/cjs/mediaQueries/moduleRegistry.js +5 -0
  12. package/dist/cjs/mediaQueries/modules/custom.js +26 -0
  13. package/dist/cjs/mediaQueries/modules/dimensions.js +59 -0
  14. package/dist/cjs/mediaQueries/modules/display.js +20 -0
  15. package/dist/cjs/mediaQueries/modules/environment.js +20 -0
  16. package/dist/cjs/mediaQueries/modules/index.js +23 -0
  17. package/dist/cjs/mediaQueries/modules/interaction.js +26 -0
  18. package/dist/cjs/mediaQueries/modules/preferences.js +26 -0
  19. package/dist/cjs/mediaQueries/modules/resolution.js +29 -0
  20. package/dist/cjs/mediaQueries/types.js +2 -0
  21. package/dist/cjs/mediaQueries/validation.js +133 -0
  22. package/dist/esm/libraryHelpers/vanilla-extract.d.ts +3 -0
  23. package/dist/esm/libraryHelpers/vanilla-extract.d.ts.map +1 -0
  24. package/dist/esm/libraryHelpers/vanilla-extract.js +3 -0
  25. package/dist/esm/mediaQueries/factory.d.ts +29 -0
  26. package/dist/esm/mediaQueries/factory.d.ts.map +1 -0
  27. package/dist/esm/mediaQueries/factory.js +158 -0
  28. package/dist/esm/mediaQueries/helpers.d.ts +40 -0
  29. package/dist/esm/mediaQueries/helpers.d.ts.map +1 -0
  30. package/dist/esm/mediaQueries/helpers.js +87 -0
  31. package/dist/esm/mediaQueries/index.d.ts +7 -0
  32. package/dist/esm/mediaQueries/index.d.ts.map +1 -0
  33. package/dist/esm/mediaQueries/index.js +6 -0
  34. package/dist/esm/mediaQueries/linting/core.d.ts +5 -0
  35. package/dist/esm/mediaQueries/linting/core.d.ts.map +1 -0
  36. package/dist/esm/mediaQueries/linting/core.js +14 -0
  37. package/dist/esm/mediaQueries/linting/resolution.d.ts +3 -0
  38. package/dist/esm/mediaQueries/linting/resolution.d.ts.map +1 -0
  39. package/dist/esm/mediaQueries/linting/resolution.js +7 -0
  40. package/dist/esm/mediaQueries/linting.d.ts +4 -0
  41. package/dist/esm/mediaQueries/linting.d.ts.map +1 -0
  42. package/dist/esm/mediaQueries/linting.js +20 -0
  43. package/dist/esm/mediaQueries/mediaQueries.d.ts +21 -0
  44. package/dist/esm/mediaQueries/mediaQueries.d.ts.map +1 -0
  45. package/dist/esm/mediaQueries/mediaQueries.js +46 -0
  46. package/dist/esm/mediaQueries/moduleRegistry.d.ts +27 -0
  47. package/dist/esm/mediaQueries/moduleRegistry.d.ts.map +1 -0
  48. package/dist/esm/mediaQueries/moduleRegistry.js +1 -0
  49. package/dist/esm/mediaQueries/modules/custom.d.ts +10 -0
  50. package/dist/esm/mediaQueries/modules/custom.d.ts.map +1 -0
  51. package/dist/esm/mediaQueries/modules/custom.js +22 -0
  52. package/dist/esm/mediaQueries/modules/dimensions.d.ts +17 -0
  53. package/dist/esm/mediaQueries/modules/dimensions.d.ts.map +1 -0
  54. package/dist/esm/mediaQueries/modules/dimensions.js +55 -0
  55. package/dist/esm/mediaQueries/modules/display.d.ts +9 -0
  56. package/dist/esm/mediaQueries/modules/display.d.ts.map +1 -0
  57. package/dist/esm/mediaQueries/modules/display.js +16 -0
  58. package/dist/esm/mediaQueries/modules/environment.d.ts +9 -0
  59. package/dist/esm/mediaQueries/modules/environment.d.ts.map +1 -0
  60. package/dist/esm/mediaQueries/modules/environment.js +16 -0
  61. package/dist/esm/mediaQueries/modules/index.d.ts +8 -0
  62. package/dist/esm/mediaQueries/modules/index.d.ts.map +1 -0
  63. package/dist/esm/mediaQueries/modules/index.js +7 -0
  64. package/dist/esm/mediaQueries/modules/interaction.d.ts +11 -0
  65. package/dist/esm/mediaQueries/modules/interaction.d.ts.map +1 -0
  66. package/dist/esm/mediaQueries/modules/interaction.js +22 -0
  67. package/dist/esm/mediaQueries/modules/preferences.d.ts +11 -0
  68. package/dist/esm/mediaQueries/modules/preferences.d.ts.map +1 -0
  69. package/dist/esm/mediaQueries/modules/preferences.js +22 -0
  70. package/dist/esm/mediaQueries/modules/resolution.d.ts +10 -0
  71. package/dist/esm/mediaQueries/modules/resolution.d.ts.map +1 -0
  72. package/dist/esm/mediaQueries/modules/resolution.js +25 -0
  73. package/dist/esm/mediaQueries/types.d.ts +117 -0
  74. package/dist/esm/mediaQueries/types.d.ts.map +1 -0
  75. package/dist/esm/mediaQueries/types.js +1 -0
  76. package/dist/esm/mediaQueries/validation.d.ts +14 -0
  77. package/dist/esm/mediaQueries/validation.d.ts.map +1 -0
  78. package/dist/esm/mediaQueries/validation.js +122 -0
  79. package/package.json +27 -9
package/README.md CHANGED
@@ -7,6 +7,13 @@ CSS-Calipers is a tiny layer for typed CSS measurements. Stop parsing CSS
7
7
  strings and concatenating units. Do your math on real numbers, get
8
8
  compile-time unit safety, and output CSS only at the edges.
9
9
 
10
+ This README is a general overview. Deeper module guides live in their own files.
11
+
12
+ Module guides:
13
+
14
+ - Measurements core: README_MEASUREMENT.md
15
+ - Media queries: README_MEDIAQUERIES.md
16
+
10
17
  At a glance:
11
18
 
12
19
  - Create measurements with `m` from a number and a unit; if you omit the unit, it defaults to `px` and is typed as the px measurement type.
@@ -54,6 +61,34 @@ If you prefer, you can also import unit helpers from dedicated subpaths. For exa
54
61
 
55
62
  ---
56
63
 
64
+ ## Media queries
65
+
66
+ ```ts
67
+ import { m } from "css-calipers";
68
+ import { mediaQueryFactory } from "css-calipers/mediaQueries";
69
+
70
+ const media = mediaQueryFactory({
71
+ queries: {
72
+ mobile: { maxWidth: m(639) },
73
+ desktop: { minWidth: m(640) },
74
+ },
75
+ config: {
76
+ label: "layout",
77
+ },
78
+ });
79
+
80
+ const styles = {
81
+ ...media({
82
+ mobile: { gridTemplateColumns: "1fr" },
83
+ desktop: { gridTemplateColumns: "repeat(4, 1fr)" },
84
+ }),
85
+ };
86
+ ```
87
+
88
+ See README_MEDIAQUERIES.md for the full media queries guide.
89
+
90
+ ---
91
+
57
92
  ## Features
58
93
 
59
94
  - **Compile-time unit validation.** Prevents mixing incompatible units.
@@ -105,7 +140,7 @@ It’s probably overkill if:
105
140
  import { m, mPercent, mVw, mVh, assertCondition } from "css-calipers";
106
141
 
107
142
  // Token-style measurements (px by default)
108
- const spacing = m(8); // Defaults to px and is typed as a PxMeasurement; equivalent to mPx(8)
143
+ const spacing = m(8); // Defaults to px and is typed as a PxMeasurement
109
144
  const cardPadding = spacing.multiply(2); // 16px
110
145
  const gutter = spacing.multiply(1.5); // 12px
111
146
 
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mediaQueryOutputVanillaExtract = void 0;
4
+ const mediaQueryOutputVanillaExtract = (media) => ({
5
+ '&': media,
6
+ });
7
+ exports.mediaQueryOutputVanillaExtract = mediaQueryOutputVanillaExtract;
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mediaQueryFactory = void 0;
4
+ const helpers_1 = require("./helpers");
5
+ const mediaQueries_1 = require("./mediaQueries");
6
+ const modules_1 = require("./modules");
7
+ const ALL_MEDIA_QUERY_MODULES = [
8
+ 'core',
9
+ 'dimensions',
10
+ 'resolution',
11
+ 'interaction',
12
+ 'preferences',
13
+ 'display',
14
+ 'environment',
15
+ 'custom',
16
+ ];
17
+ const MODULE_KEYS = {
18
+ core: ['type', 'minWidth', 'maxWidth'],
19
+ dimensions: [
20
+ 'width',
21
+ 'height',
22
+ 'minHeight',
23
+ 'maxHeight',
24
+ 'aspectRatio',
25
+ 'minAspectRatio',
26
+ 'maxAspectRatio',
27
+ 'orientation',
28
+ ],
29
+ resolution: ['resolutionValue', 'minResolution', 'maxResolution'],
30
+ interaction: ['hover', 'anyHover', 'pointer', 'anyPointer', 'update'],
31
+ preferences: [
32
+ 'colorScheme',
33
+ 'reducedMotion',
34
+ 'reducedData',
35
+ 'contrast',
36
+ 'forcedColors',
37
+ ],
38
+ display: ['colorGamut', 'dynamicRange', 'invertedColors'],
39
+ environment: ['scripting', 'overflowBlock', 'overflowInline'],
40
+ custom: ['customFeatures'],
41
+ };
42
+ const MODULE_EMITTERS = {
43
+ core: mediaQueries_1.emitCoreFeatures,
44
+ dimensions: modules_1.emitDimensionsFeatures,
45
+ resolution: modules_1.emitResolutionFeatures,
46
+ interaction: modules_1.emitInteractionFeatures,
47
+ preferences: modules_1.emitPreferencesFeatures,
48
+ display: modules_1.emitDisplayFeatures,
49
+ environment: modules_1.emitEnvironmentFeatures,
50
+ custom: modules_1.emitCustomFeatures,
51
+ };
52
+ const ALL_MODULE_KEYS = MODULE_KEYS;
53
+ const KEY_TO_MODULE = Object.fromEntries(Object.keys(ALL_MODULE_KEYS).flatMap((moduleId) => ALL_MODULE_KEYS[moduleId].map((key) => [key, moduleId])));
54
+ const guardUnsupportedProps = (props, modules, config, label) => {
55
+ const allowed = new Set();
56
+ modules.forEach((moduleId) => {
57
+ ALL_MODULE_KEYS[moduleId].forEach((key) => {
58
+ allowed.add(key);
59
+ });
60
+ });
61
+ Object.keys(props).forEach((key) => {
62
+ var _a, _b;
63
+ if (props[key] === undefined)
64
+ return;
65
+ if (allowed.has(key))
66
+ return;
67
+ const mode = (_b = (_a = config.errorHandling) === null || _a === void 0 ? void 0 : _a.invalidValueMode) !== null && _b !== void 0 ? _b : 'throw';
68
+ const moduleHint = KEY_TO_MODULE[key];
69
+ const moduleSuffix = moduleHint
70
+ ? ` Add "${moduleHint}" to modules.`
71
+ : '';
72
+ const message = `Media query factory "${label}" received unsupported feature "${key}".${moduleSuffix}`;
73
+ if (mode === 'log') {
74
+ console.warn(message);
75
+ return;
76
+ }
77
+ if (mode === 'allow')
78
+ return;
79
+ throw new Error(message);
80
+ });
81
+ };
82
+ const normalizeCustomResult = (result) => {
83
+ if (result === undefined || result === null)
84
+ return { valid: true };
85
+ if (typeof result === 'boolean')
86
+ return { valid: result };
87
+ if (typeof result === 'string') {
88
+ return result ? { valid: false, message: result } : { valid: true };
89
+ }
90
+ return result;
91
+ };
92
+ const runCustomValidator = (props, config) => {
93
+ var _a, _b;
94
+ const custom = config.custom;
95
+ if (!(custom === null || custom === void 0 ? void 0 : custom.validator))
96
+ return;
97
+ const normalized = normalizeCustomResult(custom.validator(props));
98
+ if (normalized.valid)
99
+ return;
100
+ const mode = (_b = (_a = config.errorHandling) === null || _a === void 0 ? void 0 : _a.invalidValueMode) !== null && _b !== void 0 ? _b : 'throw';
101
+ const suffix = normalized.message ? `: ${normalized.message}` : '';
102
+ const message = `Media query factory "${config.label}" custom validator "${custom.key}" failed${suffix}`;
103
+ if (mode === 'log') {
104
+ console.warn(message);
105
+ return;
106
+ }
107
+ if (mode === 'allow')
108
+ return;
109
+ throw new Error(message);
110
+ };
111
+ const runCustomLinter = (props, config) => {
112
+ var _a, _b;
113
+ const custom = config.custom;
114
+ if (!(custom === null || custom === void 0 ? void 0 : custom.linter))
115
+ return;
116
+ const normalized = normalizeCustomResult(custom.linter(props));
117
+ if (normalized.valid)
118
+ return;
119
+ const mode = (_b = (_a = config.errorHandling) === null || _a === void 0 ? void 0 : _a.lintingMode) !== null && _b !== void 0 ? _b : 'throw';
120
+ const suffix = normalized.message ? `: ${normalized.message}` : '';
121
+ const message = `Media query factory "${config.label}" custom linter "${custom.key}" flagged${suffix}`;
122
+ if (mode === 'log') {
123
+ console.warn(message);
124
+ return;
125
+ }
126
+ if (mode === 'allow')
127
+ return;
128
+ throw new Error(message);
129
+ };
130
+ const mediaQueryFactory = (options) => {
131
+ var _a;
132
+ const modules = (_a = options.config.modules) !== null && _a !== void 0 ? _a : ALL_MEDIA_QUERY_MODULES;
133
+ const buildMediaQuery = (0, helpers_1.createMediaQueryBuilder)({
134
+ emitBase: (props, helpers) => {
135
+ guardUnsupportedProps(props, modules, options.config, options.config.label);
136
+ runCustomValidator(props, options.config);
137
+ runCustomLinter(props, options.config);
138
+ modules.forEach((moduleId) => {
139
+ MODULE_EMITTERS[moduleId](props, helpers);
140
+ });
141
+ },
142
+ resolveType: (props) => props.type,
143
+ config: options.config,
144
+ });
145
+ return (stylesByQuery) => {
146
+ const result = {};
147
+ Object.keys(stylesByQuery).forEach((key) => {
148
+ const styles = stylesByQuery[key];
149
+ const props = options.queries[key];
150
+ if (!styles || !props)
151
+ return;
152
+ result[buildMediaQuery(props)] = styles;
153
+ });
154
+ const mediaQuery = {
155
+ '@media': result,
156
+ };
157
+ return options.config.output
158
+ ? options.config.output(mediaQuery)
159
+ : mediaQuery;
160
+ };
161
+ };
162
+ exports.mediaQueryFactory = mediaQueryFactory;
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildMediaQueryFromFeatures = exports.applyMediaQueryValidation = exports.createMediaQueryBuilder = exports.createMediaQueryFeatureEmitterWithTracking = exports.createMediaQueryFeatureEmitter = exports.buildMediaQueryStringFromParts = exports.formatMediaQueryValue = void 0;
4
+ const core_1 = require("../core");
5
+ const formatMediaQueryValue = (value) => ((0, core_1.hasCssMethod)(value) ? value.css() : String(value));
6
+ exports.formatMediaQueryValue = formatMediaQueryValue;
7
+ const buildMediaQueryStringFromParts = (mediaType, parts) => (parts.length ? `${mediaType} and ${parts.join(' and ')}` : mediaType);
8
+ exports.buildMediaQueryStringFromParts = buildMediaQueryStringFromParts;
9
+ const createMediaQueryFeatureEmitter = (parts) => (name, value) => {
10
+ parts.push(`(${name}: ${(0, exports.formatMediaQueryValue)(value)})`);
11
+ };
12
+ exports.createMediaQueryFeatureEmitter = createMediaQueryFeatureEmitter;
13
+ const createMediaQueryFeatureEmitterWithTracking = (parts, options = {}) => {
14
+ const { emitted, lintingMode = 'throw' } = options;
15
+ return (name, value) => {
16
+ if (emitted === null || emitted === void 0 ? void 0 : emitted.has(name)) {
17
+ if (lintingMode === 'throw') {
18
+ throw new Error(`Media query feature "${name}" was emitted more than once.`);
19
+ }
20
+ if (lintingMode === 'log') {
21
+ console.warn(`Media query feature "${name}" was emitted more than once; using the latest value.`);
22
+ }
23
+ }
24
+ emitted === null || emitted === void 0 ? void 0 : emitted.add(name);
25
+ parts.push(`(${name}: ${(0, exports.formatMediaQueryValue)(value)})`);
26
+ };
27
+ };
28
+ exports.createMediaQueryFeatureEmitterWithTracking = createMediaQueryFeatureEmitterWithTracking;
29
+ const createMediaQueryBuilder = (options) => {
30
+ return (config) => {
31
+ var _a, _b, _c, _d, _e, _f, _g;
32
+ const parts = [];
33
+ const emittedFeatures = new Set();
34
+ const helpers = {
35
+ addFeature: (0, exports.createMediaQueryFeatureEmitterWithTracking)(parts, {
36
+ emitted: emittedFeatures,
37
+ lintingMode: (_c = (_b = (_a = options.config) === null || _a === void 0 ? void 0 : _a.errorHandling) === null || _b === void 0 ? void 0 : _b.lintingMode) !== null && _c !== void 0 ? _c : 'throw',
38
+ }),
39
+ config: (_d = options.config) !== null && _d !== void 0 ? _d : {},
40
+ };
41
+ options.emitBase(config, helpers);
42
+ (_e = options.emitExtensions) === null || _e === void 0 ? void 0 : _e.call(options, config, helpers);
43
+ const mediaType = (_g = (_f = options.resolveType) === null || _f === void 0 ? void 0 : _f.call(options, config)) !== null && _g !== void 0 ? _g : 'screen';
44
+ return (0, exports.buildMediaQueryStringFromParts)(mediaType, parts);
45
+ };
46
+ };
47
+ exports.createMediaQueryBuilder = createMediaQueryBuilder;
48
+ const normalizeValidationResult = (result) => {
49
+ if (result === undefined || result === null)
50
+ return { valid: true };
51
+ if (typeof result === 'boolean')
52
+ return { valid: result };
53
+ if (typeof result === 'string') {
54
+ return result ? { valid: false, message: result } : { valid: true };
55
+ }
56
+ return result;
57
+ };
58
+ const applyMediaQueryValidation = (config, helpers, validator, context) => {
59
+ var _a, _b;
60
+ if (!validator)
61
+ return true;
62
+ const normalized = normalizeValidationResult(validator(config));
63
+ if (normalized.valid)
64
+ return true;
65
+ const mode = (_b = (_a = helpers.config.errorHandling) === null || _a === void 0 ? void 0 : _a.invalidValueMode) !== null && _b !== void 0 ? _b : 'throw';
66
+ if (mode === 'log') {
67
+ const suffix = normalized.message ? `: ${normalized.message}` : '';
68
+ const prefix = context
69
+ ? `Media query ${context} validation failed`
70
+ : 'Media query validation failed';
71
+ console.warn(`${prefix}${suffix}`);
72
+ }
73
+ if (mode === 'allow')
74
+ return true;
75
+ if (mode === 'log')
76
+ return true;
77
+ const suffix = normalized.message ? `: ${normalized.message}` : '';
78
+ const prefix = context
79
+ ? `Media query ${context} validation failed`
80
+ : 'Media query validation failed';
81
+ throw new Error(`${prefix}${suffix}`);
82
+ };
83
+ exports.applyMediaQueryValidation = applyMediaQueryValidation;
84
+ const buildMediaQueryFromFeatures = (features, mediaType = 'screen') => {
85
+ const parts = [];
86
+ const addFeature = (0, exports.createMediaQueryFeatureEmitterWithTracking)(parts, {
87
+ emitted: new Set(),
88
+ lintingMode: 'throw',
89
+ });
90
+ Object.entries(features).forEach(([name, value]) => {
91
+ if (value === undefined || value === null)
92
+ return;
93
+ addFeature(name, value);
94
+ });
95
+ return (0, exports.buildMediaQueryStringFromParts)(mediaType, parts);
96
+ };
97
+ exports.buildMediaQueryFromFeatures = buildMediaQueryFromFeatures;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./types"), exports);
18
+ __exportStar(require("./helpers"), exports);
19
+ __exportStar(require("./factory"), exports);
20
+ __exportStar(require("./mediaQueries"), exports);
21
+ __exportStar(require("./modules"), exports);
22
+ __exportStar(require("./moduleRegistry"), exports);
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.lintHeightRedundancy = exports.lintWidthRedundancy = void 0;
4
+ const lintWidthRedundancy = (props) => {
5
+ if (!props.width)
6
+ return;
7
+ if (props.minWidth || props.maxWidth) {
8
+ throw new Error('width should not be combined with minWidth or maxWidth');
9
+ }
10
+ };
11
+ exports.lintWidthRedundancy = lintWidthRedundancy;
12
+ const lintHeightRedundancy = (props) => {
13
+ if (!props.height)
14
+ return;
15
+ if (props.minHeight || props.maxHeight) {
16
+ throw new Error('height should not be combined with minHeight or maxHeight');
17
+ }
18
+ };
19
+ exports.lintHeightRedundancy = lintHeightRedundancy;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.lintResolutionRedundancy = void 0;
4
+ const lintResolutionRedundancy = (props) => {
5
+ if (!props.resolutionValue)
6
+ return;
7
+ if (props.minResolution || props.maxResolution) {
8
+ throw new Error('resolution should not be combined with minResolution or maxResolution');
9
+ }
10
+ };
11
+ exports.lintResolutionRedundancy = lintResolutionRedundancy;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runMediaQueryLint = void 0;
4
+ const runMediaQueryLint = (config, helpers, check, message = 'Media query lint failed') => {
5
+ var _a, _b;
6
+ if (!check)
7
+ return true;
8
+ const mode = (_b = (_a = helpers.config.errorHandling) === null || _a === void 0 ? void 0 : _a.lintingMode) !== null && _b !== void 0 ? _b : 'throw';
9
+ if (mode === 'allow')
10
+ return true;
11
+ if (mode === 'log') {
12
+ try {
13
+ check(config);
14
+ return true;
15
+ }
16
+ catch {
17
+ console.warn(message);
18
+ return true;
19
+ }
20
+ }
21
+ check(config);
22
+ return true;
23
+ };
24
+ exports.runMediaQueryLint = runMediaQueryLint;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeMediaQueryStyle = exports.buildMediaQueryString = exports.emitCoreFeatures = void 0;
4
+ const helpers_1 = require("./helpers");
5
+ const validation_1 = require("./validation");
6
+ const modules_1 = require("./modules");
7
+ const emitCoreFeatures = (props, helpers) => {
8
+ if (!(0, validation_1.runMediaQueryValidation)(props, helpers, validation_1.validateMinMaxWidth, "core", "minWidth must be less than or equal to maxWidth")) {
9
+ return;
10
+ }
11
+ if (!(0, validation_1.runMediaQueryValidation)(props, helpers, validation_1.validateWidthValuesPositive, "core", "width values must be greater than 0")) {
12
+ return;
13
+ }
14
+ const { addFeature } = helpers;
15
+ if (props.minWidth) {
16
+ addFeature("min-width", props.minWidth);
17
+ }
18
+ if (props.maxWidth) {
19
+ addFeature("max-width", props.maxWidth);
20
+ }
21
+ };
22
+ exports.emitCoreFeatures = emitCoreFeatures;
23
+ const emitBaseFeatures = (props, helpers) => {
24
+ (0, exports.emitCoreFeatures)(props, helpers);
25
+ (0, modules_1.emitDimensionsFeatures)(props, helpers);
26
+ (0, modules_1.emitResolutionFeatures)(props, helpers);
27
+ (0, modules_1.emitInteractionFeatures)(props, helpers);
28
+ (0, modules_1.emitPreferencesFeatures)(props, helpers);
29
+ (0, modules_1.emitDisplayFeatures)(props, helpers);
30
+ (0, modules_1.emitEnvironmentFeatures)(props, helpers);
31
+ (0, modules_1.emitCustomFeatures)(props, helpers);
32
+ };
33
+ exports.buildMediaQueryString = (0, helpers_1.createMediaQueryBuilder)({
34
+ emitBase: emitBaseFeatures,
35
+ resolveType: (props) => props.type,
36
+ });
37
+ const makeMediaQueryStyle = (queries) => (stylesByQuery) => {
38
+ const result = {};
39
+ Object.keys(stylesByQuery).forEach((key) => {
40
+ const styles = stylesByQuery[key];
41
+ const props = queries[key];
42
+ if (!styles || !props)
43
+ return;
44
+ result[(0, exports.buildMediaQueryString)(props)] = styles;
45
+ });
46
+ const mediaQuery = {
47
+ "@media": result,
48
+ };
49
+ return mediaQuery;
50
+ };
51
+ exports.makeMediaQueryStyle = makeMediaQueryStyle;
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.queriesToStrings = queriesToStrings;
4
+ exports.useMediaQuery = useMediaQuery;
5
+ exports.useMediaFromMap = useMediaFromMap;
6
+ exports.makeClientFns = makeClientFns;
7
+ const react_1 = require("react");
8
+ const mediaQueries_1 = require("./mediaQueries");
9
+ function toQueryString(q) {
10
+ return (0, mediaQueries_1.buildMediaQueryString)(q);
11
+ }
12
+ function queriesToStrings(queries) {
13
+ return Object.fromEntries(Object.entries(queries).map(([k, v,]) => [
14
+ k,
15
+ typeof v === 'string' ? v : toQueryString(v),
16
+ ]));
17
+ }
18
+ // ---------- Core hooks ----------
19
+ /**
20
+ * SSR-safe: undefined on server, boolean on client; subscribes to
21
+ * changes.
22
+ */
23
+ function useMediaQuery(queryString) {
24
+ const [matches, setMatches,] = (0, react_1.useState)(undefined);
25
+ (0, react_1.useEffect)(() => {
26
+ var _a;
27
+ if (typeof window === 'undefined')
28
+ return;
29
+ const mql = window.matchMedia(queryString);
30
+ const onChange = () => setMatches(mql.matches);
31
+ const frameId = requestAnimationFrame(() => {
32
+ setMatches(mql.matches);
33
+ });
34
+ (_a = mql.addEventListener) === null || _a === void 0 ? void 0 : _a.call(mql, 'change', onChange);
35
+ return () => {
36
+ var _a;
37
+ (_a = mql.removeEventListener) === null || _a === void 0 ? void 0 : _a.call(mql, 'change', onChange);
38
+ cancelAnimationFrame(frameId);
39
+ };
40
+ }, [
41
+ queryString,
42
+ ]);
43
+ return matches;
44
+ }
45
+ // Aggregate hook with guarded updates to avoid loops
46
+ function useMediaFromMap(strings) {
47
+ const shallowEqual = (0, react_1.useCallback)((a, b) => {
48
+ const ak = Object.keys(a);
49
+ const bk = Object.keys(b);
50
+ if (ak.length !== bk.length)
51
+ return false;
52
+ for (const k of ak)
53
+ if (a[k] !== b[k])
54
+ return false;
55
+ return true;
56
+ }, []);
57
+ // Stable, sorted list of [key, queryString]
58
+ const entries = (0, react_1.useMemo)(() => {
59
+ const e = Object.entries(strings);
60
+ e.sort((a, b) => a[0].localeCompare(b[0]));
61
+ return e;
62
+ }, [
63
+ strings,
64
+ ]);
65
+ const [matches, setMatches,] = (0, react_1.useState)(() => Object.create(null));
66
+ (0, react_1.useEffect)(() => {
67
+ if (typeof window === 'undefined')
68
+ return;
69
+ const mqls = entries.map(([k, qs,]) => [
70
+ k,
71
+ window.matchMedia(qs),
72
+ ]);
73
+ // Initial snapshot — only set if changed
74
+ const initial = Object.fromEntries(mqls.map(([k, mql,]) => [
75
+ k,
76
+ mql.matches,
77
+ ]));
78
+ const frameId = requestAnimationFrame(() => {
79
+ setMatches((prev) => shallowEqual(prev, initial) ? prev : initial);
80
+ });
81
+ // Subscribe with guarded setState
82
+ const handlers = mqls.map(([k, mql,]) => {
83
+ var _a;
84
+ const onChange = () => setMatches((prev) => {
85
+ const next = {
86
+ ...prev,
87
+ [k]: mql.matches,
88
+ };
89
+ return shallowEqual(prev, next) ? prev : next;
90
+ });
91
+ (_a = mql.addEventListener) === null || _a === void 0 ? void 0 : _a.call(mql, 'change', onChange);
92
+ return [
93
+ mql,
94
+ onChange,
95
+ ];
96
+ });
97
+ return () => {
98
+ var _a;
99
+ cancelAnimationFrame(frameId);
100
+ for (const [mql, onChange,] of handlers) {
101
+ (_a = mql.removeEventListener) === null || _a === void 0 ? void 0 : _a.call(mql, 'change', onChange);
102
+ }
103
+ };
104
+ }, [
105
+ entries,
106
+ shallowEqual,
107
+ ]);
108
+ return matches;
109
+ }
110
+ // ---------- Client-only predicates ----------
111
+ /** For event handlers/effects only; don't call in SSR render paths. */
112
+ function makeClientFns(strings) {
113
+ const out = {};
114
+ Object.keys(strings).forEach((k) => {
115
+ out[k] = () => typeof window !== 'undefined'
116
+ ? window.matchMedia(strings[k]).matches
117
+ : false;
118
+ });
119
+ return out;
120
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defineMediaQueryModules = void 0;
4
+ const defineMediaQueryModules = (...modules) => modules;
5
+ exports.defineMediaQueryModules = defineMediaQueryModules;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.emitCustomFeatures = void 0;
4
+ const core_1 = require("../../core");
5
+ const helpers_1 = require("../helpers");
6
+ const emitCustomFeatures = (props, helpers, validate) => {
7
+ if (!(0, helpers_1.applyMediaQueryValidation)(props, helpers, validate, 'custom')) {
8
+ return;
9
+ }
10
+ const { addFeature } = helpers;
11
+ if (!props.customFeatures)
12
+ return;
13
+ Object.entries(props.customFeatures).forEach(([name, value]) => {
14
+ if (value === undefined || value === null)
15
+ return;
16
+ const trimmedName = name.trim();
17
+ if (!trimmedName) {
18
+ throw new Error('Custom feature name must be non-empty.');
19
+ }
20
+ if (typeof value === 'object' && !(0, core_1.hasCssMethod)(value)) {
21
+ throw new Error(`Custom feature "${trimmedName}" must be a primitive or a measurement.`);
22
+ }
23
+ addFeature(trimmedName, value);
24
+ });
25
+ };
26
+ exports.emitCustomFeatures = emitCustomFeatures;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.emitDimensionsFeatures = void 0;
4
+ const helpers_1 = require("../helpers");
5
+ const validation_1 = require("../validation");
6
+ const linting_1 = require("../linting");
7
+ const core_1 = require("../linting/core");
8
+ const emitDimensionsFeatures = (props, helpers, validate) => {
9
+ if (!(0, validation_1.runMediaQueryValidation)(props, helpers, validation_1.validateMinMaxHeight, 'dimensions', 'minHeight must be less than or equal to maxHeight')) {
10
+ return;
11
+ }
12
+ if (!(0, validation_1.runMediaQueryValidation)(props, helpers, validation_1.validateHeightValuesPositive, 'dimensions', 'height values must be greater than 0')) {
13
+ return;
14
+ }
15
+ if (!(0, linting_1.runMediaQueryLint)(props, helpers, core_1.lintWidthRedundancy, 'width should not be combined with minWidth or maxWidth')) {
16
+ return;
17
+ }
18
+ if (!(0, linting_1.runMediaQueryLint)(props, helpers, core_1.lintHeightRedundancy, 'height should not be combined with minHeight or maxHeight')) {
19
+ return;
20
+ }
21
+ if (!(0, validation_1.runMediaQueryValidation)(props, helpers, validation_1.validateWidthValuesPositive, 'dimensions', 'width values must be greater than 0')) {
22
+ return;
23
+ }
24
+ if (!(0, validation_1.runMediaQueryValidation)(props, helpers, validation_1.validateMinMaxAspectRatio, 'dimensions', 'minAspectRatio must be less than or equal to maxAspectRatio')) {
25
+ return;
26
+ }
27
+ if (!(0, validation_1.runMediaQueryValidation)(props, helpers, validation_1.validateAspectRatioValuesPositive, 'dimensions', 'aspect ratio values must be greater than 0')) {
28
+ return;
29
+ }
30
+ if (!(0, helpers_1.applyMediaQueryValidation)(props, helpers, validate, 'dimensions')) {
31
+ return;
32
+ }
33
+ const { addFeature } = helpers;
34
+ if (props.width) {
35
+ addFeature('width', props.width);
36
+ }
37
+ if (props.height) {
38
+ addFeature('height', props.height);
39
+ }
40
+ if (props.minHeight) {
41
+ addFeature('min-height', props.minHeight);
42
+ }
43
+ if (props.maxHeight) {
44
+ addFeature('max-height', props.maxHeight);
45
+ }
46
+ if (props.aspectRatio) {
47
+ addFeature('aspect-ratio', props.aspectRatio);
48
+ }
49
+ if (props.minAspectRatio) {
50
+ addFeature('min-aspect-ratio', props.minAspectRatio);
51
+ }
52
+ if (props.maxAspectRatio) {
53
+ addFeature('max-aspect-ratio', props.maxAspectRatio);
54
+ }
55
+ if (props.orientation) {
56
+ addFeature('orientation', props.orientation);
57
+ }
58
+ };
59
+ exports.emitDimensionsFeatures = emitDimensionsFeatures;