UNPKG

tss-react

Version:

Type safe CSS-in-JS API heavily inspired by react-jss

265 lines (264 loc) 14.5 kB
"use strict"; /* eslint-disable @typescript-eslint/ban-types */ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createTss = void 0; const makeStyles_1 = require("./makeStyles"); const cssAndCx_1 = require("./cssAndCx"); const assert_1 = require("./tools/assert"); const Object_fromEntries_1 = require("./tools/polyfills/Object.fromEntries"); const objectKeys_1 = require("./tools/objectKeys"); const typeGuard_1 = require("./tools/typeGuard"); const getDependencyArrayRef_1 = require("./tools/getDependencyArrayRef"); const mergeClasses_1 = require("./mergeClasses"); const isSSR_1 = require("./tools/isSSR"); function createTss(params) { counter = 0; nestedSelectorUsageTrackRecord.splice(0, nestedSelectorUsageTrackRecord.length); const { useContext, usePlugin, cache: cacheProvidedAtInception } = params; const { useCache } = (0, makeStyles_1.createUseCache)({ cacheProvidedAtInception }); const { useCssAndCx } = (0, cssAndCx_1.createUseCssAndCx)({ useCache }); const usePluginDefault = ({ classes, cx, css }) => ({ classes, cx, css }); const tss = createTss_internal({ useContext, useCache, useCssAndCx, "usePlugin": usePlugin !== null && usePlugin !== void 0 ? usePlugin : usePluginDefault, "name": undefined, "doesUseNestedSelectors": false }); return { tss }; } exports.createTss = createTss; let counter = 0; const nestedSelectorUsageTrackRecord = []; function createTss_internal(params) { const { useContext, useCache, useCssAndCx, usePlugin, name, doesUseNestedSelectors } = params; return { "withParams": () => createTss_internal(Object.assign({}, params)), "withName": nameOrWrappedName => createTss_internal(Object.assign(Object.assign({}, params), { "name": typeof nameOrWrappedName !== "object" ? nameOrWrappedName : Object.keys(nameOrWrappedName)[0] })), "withNestedSelectors": () => createTss_internal(Object.assign(Object.assign({}, params), { "doesUseNestedSelectors": true })), "create": (cssObjectByRuleNameOrGetCssObjectByRuleName) => { // NOTE: Not isomorphic. Not guaranteed to be the same on client and server. // Do not attempt to 'simplify' the code without taking this fact into account. const idOfUseStyles = `x${counter++}`; // NOTE: Cleanup for hot module reloading. if (name !== undefined) { // eslint-disable-next-line no-constant-condition while (true) { const wrap = nestedSelectorUsageTrackRecord.find(wrap => wrap.name === name); if (wrap === undefined) { break; } nestedSelectorUsageTrackRecord.splice(nestedSelectorUsageTrackRecord.indexOf(wrap), 1); } } const getCssObjectByRuleName = typeof cssObjectByRuleNameOrGetCssObjectByRuleName === "function" ? cssObjectByRuleNameOrGetCssObjectByRuleName : () => cssObjectByRuleNameOrGetCssObjectByRuleName; return function useStyles(params) { var _a, _b, _c; const _d = (params !== null && params !== void 0 ? params : {}), { classesOverrides } = _d, paramsAndPluginParams = __rest(_d, ["classesOverrides"]); const context = useContext(); const { css, cx } = useCssAndCx(); const cache = useCache(); const getClasses = () => { const refClassesCache = {}; // @ts-expect-error: Type safety non achievable. const cssObjectByRuleName = getCssObjectByRuleName(Object.assign(Object.assign(Object.assign({}, params), context), (!doesUseNestedSelectors ? {} : { "classes": typeof Proxy === "undefined" ? {} : new Proxy({}, { "get": (_target, ruleName) => { /* prettier-ignore */ if (typeof ruleName === "symbol") { (0, assert_1.assert)(false); } if (isSSR_1.isSSR && name === undefined) { throw new Error([ `tss-react: In SSR setups, in order to use nested selectors, you must also give a unique name to the useStyle function.`, `Solution: Use tss.withName("ComponentName").withNestedSelectors<...>()... to set a name.` ].join("\n")); } update_nested_selector_usage_track_record: { if (name === undefined) { break update_nested_selector_usage_track_record; } /* prettier-ignore */ let wrap = nestedSelectorUsageTrackRecord.find(wrap => wrap.name === name && wrap.idOfUseStyles === idOfUseStyles); /* prettier-ignore */ if (wrap === undefined) { /* prettier-ignore */ wrap = { name, idOfUseStyles, "nestedSelectorRuleNames": new Set() }; /* prettier-ignore */ nestedSelectorUsageTrackRecord.push(wrap); } /* prettier-ignore */ wrap.nestedSelectorRuleNames.add(ruleName); } detect_potential_conflicts: { if (name === undefined) { break detect_potential_conflicts; } const hasPotentialConflict = nestedSelectorUsageTrackRecord.find(wrap => wrap.name === name && wrap.idOfUseStyles !== idOfUseStyles && wrap.nestedSelectorRuleNames.has(ruleName)) !== undefined; if (!hasPotentialConflict) { break detect_potential_conflicts; } throw new Error([ `tss-react: There are in your codebase two different useStyles named "${name}" that`, `both use use the nested selector ${ruleName}.\n`, `This may lead to CSS class name collisions, causing nested selectors to target elements outside of the intended scope.\n`, `Solution: Ensure each useStyles using nested selectors has a unique name.\n`, `Use: tss.withName("UniqueName").withNestedSelectors<...>()...` ].join(" ")); } /* prettier-ignore */ return (refClassesCache[ruleName] = `${cache.key}-${name !== undefined ? name : idOfUseStyles}-${ruleName}-ref`); } }) }))); let classes = (0, Object_fromEntries_1.objectFromEntries)((0, objectKeys_1.objectKeys)(cssObjectByRuleName).map(ruleName => { const cssObject = cssObjectByRuleName[ruleName]; if (!cssObject.label) { cssObject.label = `${name !== undefined ? `${name}-` : ""}${ruleName}`; } return [ ruleName, `${css(cssObject)}${(0, typeGuard_1.typeGuard)(ruleName, ruleName in refClassesCache) ? ` ${refClassesCache[ruleName]}` : ""}` ]; })); (0, objectKeys_1.objectKeys)(refClassesCache).forEach(ruleName => { if (ruleName in classes) { return; } classes[ruleName] = refClassesCache[ruleName]; }); classes = (0, mergeClasses_1.mergeClasses)(classes, classesOverrides, cx); return classes; }; const classes = runGetClassesOrUseCache({ cache, cssObjectByRuleNameOrGetCssObjectByRuleName, "classesOverridesRef": (0, getDependencyArrayRef_1.getDependencyArrayRef)(classesOverrides), "paramsAndPluginParamsRef": (0, getDependencyArrayRef_1.getDependencyArrayRef)(paramsAndPluginParams), idOfUseStyles, context, getClasses }); // @ts-expect-error: Type safety non achievable. const pluginResultWrap = usePlugin(Object.assign(Object.assign({ classes, css, cx, idOfUseStyles, name }, context), paramsAndPluginParams)); return Object.assign({ "classes": (_a = pluginResultWrap.classes) !== null && _a !== void 0 ? _a : classes, "css": (_b = pluginResultWrap.css) !== null && _b !== void 0 ? _b : css, "cx": (_c = pluginResultWrap.cx) !== null && _c !== void 0 ? _c : cx }, context); }; } }; } const mapCache = new WeakMap(); function runGetClassesOrUseCache(params) { const { cache, cssObjectByRuleNameOrGetCssObjectByRuleName, classesOverridesRef, paramsAndPluginParamsRef, idOfUseStyles, context, getClasses } = params; use_cache: { const mapCache_in = mapCache.get(cache); if (mapCache_in === undefined) { break use_cache; } const mapCache_in_in = mapCache_in.get(cssObjectByRuleNameOrGetCssObjectByRuleName); if (mapCache_in_in === undefined) { break use_cache; } const mapCache_in_in_in = mapCache_in_in.get(classesOverridesRef); if (mapCache_in_in_in === undefined) { break use_cache; } const arr = mapCache_in_in_in.get(paramsAndPluginParamsRef); if (arr === undefined) { break use_cache; } const entry = arr.find(({ context: context_i }) => { if (context_i === context) { return true; } if ((0, objectKeys_1.objectKeys)(context_i).length !== (0, objectKeys_1.objectKeys)(context).length) { return false; } for (const key in context_i) { if ((0, getDependencyArrayRef_1.getDependencyArrayRef)(context_i[key]) !== (0, getDependencyArrayRef_1.getDependencyArrayRef)(context[key])) { return false; } } return true; }); if (entry === undefined) { break use_cache; } if ((entry === null || entry === void 0 ? void 0 : entry.idOfUseStyles) !== idOfUseStyles) { arr.splice(arr.indexOf(entry), 1); break use_cache; } return entry.result; } const result = getClasses(); { if (!mapCache.has(cache)) { mapCache.set(cache, new WeakMap()); } const mapCache_in = mapCache.get(cache); (0, assert_1.assert)(mapCache_in !== undefined); if (!mapCache_in.has(cssObjectByRuleNameOrGetCssObjectByRuleName)) { mapCache_in.set(cssObjectByRuleNameOrGetCssObjectByRuleName, new Map()); } const mapCache_in_in = mapCache_in.get(cssObjectByRuleNameOrGetCssObjectByRuleName); (0, assert_1.assert)(mapCache_in_in !== undefined); if (!mapCache_in_in.has(classesOverridesRef)) { if (mapCache_in_in.size > 200) { mapCache_in_in.clear(); } mapCache_in_in.set(classesOverridesRef, new Map()); } const mapCache_in_in_in = mapCache_in_in.get(classesOverridesRef); (0, assert_1.assert)(mapCache_in_in_in !== undefined); if (!mapCache_in_in_in.has(paramsAndPluginParamsRef)) { clear_cache: { const threshold = typeof paramsAndPluginParamsRef === "string" ? 257 : 5; if (mapCache_in_in_in.size < threshold) { break clear_cache; } mapCache_in_in_in.clear(); } mapCache_in_in_in.set(paramsAndPluginParamsRef, []); } let arr = mapCache_in_in_in.get(paramsAndPluginParamsRef); (0, assert_1.assert)(arr !== undefined); if (arr.length > 5) { arr = []; } arr.push({ idOfUseStyles, context, result }); } return result; }