oncss
Version:
A CSS framework for modern web development.
317 lines (313 loc) • 12.2 kB
JavaScript
;
var youid = require('youid');
// const _global: any = typeof window !== 'undefined' ? window : global;
// _global.Factory = _global.Factory || new Map<string, CSSFactoryType>();
// export const CSSFactory = _global.Factory as Map<string, CSSFactoryType>
const caches = new Map();
const ONCSS_CACHE = {
set(cacheId, cachekey, value) {
let cache = caches.get(cacheId);
if (!cache) {
cache = new Map();
caches.set(cacheId, cache);
}
cache.set(cachekey, value);
},
get(cacheId, cachekey) {
let cache = caches.get(cacheId);
if (cache) {
return cache.get(cachekey);
}
},
has(cacheId, cachekey) {
let cache = caches.get(cacheId);
if (cache) {
return cache.has(cachekey);
}
return false;
},
delete(cacheId, cachekey) {
let cache = caches.get(cacheId);
if (cache) {
cache.delete(cachekey);
}
},
caches() {
return caches;
}
};
const number_val_props = [
"fontWeight",
"font-weight",
"lineHeight",
"line-height",
"opacity",
"zIndex",
"z-index",
"flex",
"order",
"flexGrow",
"flex-grow",
"flexShrink",
"flex-shrink",
"flexBasis",
"flex-basis",
"columns",
"perspective",
"stroke-dashoffset"
];
const formatCSSProp = (prop) => prop.split(/(?=[A-Z])/).join("-").toLowerCase();
const formatCSSValue = (prop, val) => typeof val === 'number' && !number_val_props.includes(prop) ? `${val}px` : val;
const PREFIXES = ['webkit', 'moz', 'ms', 'o'];
let _declaration;
const PREFIXCACHE = new Map();
const cssPrefix = (prop, value) => {
value = formatCSSValue(prop, value);
prop = formatCSSProp(prop);
if (typeof window === 'undefined') {
return { prop, value };
}
const declaration = _declaration || (_declaration = document.createElement("div").style);
value = value === null || value === void 0 ? void 0 : value.toString();
// Check if the property and value work as is
if (declaration.setProperty(prop, value), declaration.getPropertyValue(prop) === value) {
return { prop, value };
}
// Check cached property and value prefix
const cached = PREFIXCACHE.get(prop);
if (cached) {
return { prop: cached._prop, value: `${cached._vprefix}${value}` };
}
let _prop = prop;
let _value = value;
let _vprefix = '';
// Try property prefixes
const camelCaseProp = prop.includes('-') ? prop.replace(/-([a-z])/g, (_, c) => c.toUpperCase()) : prop;
for (const prefix of PREFIXES) {
if (declaration[`${prefix}${camelCaseProp}`] !== undefined) {
_prop = `-${prefix}-${prop}`;
break;
}
}
// Check if prefixed property works with the value
declaration.setProperty(_prop, value);
if (!declaration.getPropertyValue(_prop)) {
for (const prefix of PREFIXES) {
const prefixedValue = `-${prefix}-${value}`;
if (declaration.setProperty(_prop, prefixedValue), declaration.getPropertyValue(_prop) === prefixedValue) {
_value = prefixedValue;
_vprefix = `-${prefix}-`;
break;
}
}
}
PREFIXCACHE.set(prop, { _prop, _vprefix });
return { prop: _prop, value: _value };
};
const resolveStyleContainer = (input) => {
if (typeof window === 'undefined') {
return {
document: undefined,
container: undefined
};
}
// Default → current document
if (!input) {
return {
document,
container: document.head,
};
}
// If input is a Document (works across iframes)
if ("nodeType" in input && input.nodeType === 9) {
return {
document: input,
container: input.head || input.getElementsByTagName("head")[0],
};
}
// If input is an HTMLElement → use its owner document
if ("ownerDocument" in input && input instanceof HTMLElement) {
return {
document: input.ownerDocument,
container: input,
};
}
throw new Error("Invalid input: must be Document or HTMLElement");
};
const style = (_css, cls, opt, dept = 1) => {
var _a, _b, _c;
let cachekey;
let classname = cls;
const cacheId = (opt === null || opt === void 0 ? void 0 : opt.cacheId) || "global";
if (!cls) {
cachekey = ((_a = opt === null || opt === void 0 ? void 0 : opt.selector) !== null && _a !== void 0 ? _a : "") + JSON.stringify(_css, (_key, value) => typeof value === "function" ? value.toString() : value);
const has = ONCSS_CACHE.get(cacheId, cachekey);
if (has) {
has.cache = true;
return has;
}
classname = `${(opt === null || opt === void 0 ? void 0 : opt.classPrefix) || ""}x${youid(cachekey)}`;
}
else if (typeof cls !== 'string') {
throw new Error(`Invalid class name: ${cls}`);
}
let stack = [`${classname}{`];
let medias = {};
let skiped = {};
for (let prop in _css) {
let val = _css[prop];
let firstChar = prop.charAt(0);
if (firstChar === '&') {
let ncls = prop.replace(/&/g, classname);
const r = style(val, ncls, opt, dept + 1);
if (opt === null || opt === void 0 ? void 0 : opt.skipProps) {
skiped = Object.assign(Object.assign({}, skiped), r.skiped);
}
stack.push(r.stack);
}
else if (firstChar === '@') {
if (prop.startsWith("@global") || prop.startsWith("@keyframes")) {
let _css = '';
for (let selector in val) {
let r = style(val[selector], selector, opt, dept + 1);
_css += r.stack;
if (opt === null || opt === void 0 ? void 0 : opt.skipProps) {
skiped = Object.assign(Object.assign({}, skiped), r.skiped);
}
}
if (prop.startsWith("@keyframes")) {
stack.push(`${prop}{${_css}}`);
}
else {
stack.push(_css);
}
}
else {
let r = style(val, classname, opt, dept + 1);
const atcss = prop + "{" + r.stack + "}";
stack.push(atcss);
if (opt === null || opt === void 0 ? void 0 : opt.skipProps) {
skiped = Object.assign(Object.assign({}, skiped), r.skiped);
}
}
}
else {
if ((opt === null || opt === void 0 ? void 0 : opt.skipProps) && opt.skipProps(prop, val, dept)) {
if (!(classname in skiped))
skiped[classname] = [];
skiped[classname].push(prop);
continue;
}
if (typeof val === 'function' || Array.isArray(val)) {
continue;
}
if (typeof val === 'object') {
for (let media in val) {
if (typeof val[media] === 'object' || typeof val[media] === 'function' || Array.isArray(val[media])) {
throw new Error(`Invalid css value: ${val[media]}`);
}
let breakpoint = media;
let isNumber = !isNaN(parseInt(breakpoint));
if (!isNumber) {
if ((opt === null || opt === void 0 ? void 0 : opt.breakpoints) && !isNaN(parseInt(opt.breakpoints[media]))) {
breakpoint = opt.breakpoints[media].toString();
}
else {
throw new Error(`Invalid breakpoint prop: ${media}`);
}
}
let _css = { [prop]: val[media] };
let r = style(_css, classname, opt, dept);
let _style = r.stack;
let mediakey = `@media (min-width: ${breakpoint}px)`;
medias[mediakey] = medias[mediakey] ? medias[mediakey] + _style : _style;
if (opt === null || opt === void 0 ? void 0 : opt.skipProps) {
skiped = Object.assign(Object.assign({}, skiped), r.skiped);
}
}
}
else {
if (opt === null || opt === void 0 ? void 0 : opt.getProps) {
let _props = opt.getProps(prop, val, _css, dept);
if (_props) {
let r = style(_props, classname, Object.assign(Object.assign({}, opt), { getProps: undefined }));
if (opt === null || opt === void 0 ? void 0 : opt.skipProps) {
skiped = Object.assign(Object.assign({}, skiped), r.skiped);
}
stack.push(r.stack);
continue;
}
}
if ((opt === null || opt === void 0 ? void 0 : opt.aliases) && opt.aliases[prop]) {
let _props = opt.aliases[prop](val);
if (_props) {
let r = style(_props, classname, Object.assign(Object.assign({}, opt), { aliases: undefined }), dept);
r.stack = r.stack.replace(`${classname}{`, '').replace(`}`, '');
stack[0] += r.stack;
continue;
}
}
if (opt === null || opt === void 0 ? void 0 : opt.getValue) {
val = opt.getValue(prop, val, _css, dept);
}
let p = cssPrefix(prop, val);
stack[0] += `${p.prop}:${p.value};`;
}
}
}
stack[0] += "}";
if (stack[0] === `${classname}{}`) {
stack[0] = "";
}
stack = stack.join('');
for (let media in medias) {
stack += `${media}{${medias[media].replace(new RegExp(`}\\${classname}\\{`, 'g'), '')}}`;
}
if (cachekey) {
const d = resolveStyleContainer(opt === null || opt === void 0 ? void 0 : opt.container);
const selector = (_b = opt === null || opt === void 0 ? void 0 : opt.selector) !== null && _b !== void 0 ? _b : ".";
stack = stack.replace(new RegExp(classname, 'g'), `${selector}${classname}`);
const r = {
cache: false,
cachekey,
selector,
classname: classname,
css: stack,
cssraw: _css,
skiped,
cacheId,
getStyleTag: () => { var _a; return (_a = d.container) === null || _a === void 0 ? void 0 : _a.querySelector(`style[data-href="${classname}"]`); },
deleteStyle: () => {
const tag = r.getStyleTag();
tag && tag.remove();
},
inject: () => {
var _a, _b;
const tag = r.getStyleTag() || ((_a = d.document) === null || _a === void 0 ? void 0 : _a.createElement("style"));
if (tag && !(tag === null || tag === void 0 ? void 0 : tag.innerHTML)) {
tag.innerHTML = r.css;
tag.setAttribute(`data-href`, classname);
(_b = d.container) === null || _b === void 0 ? void 0 : _b.appendChild(tag);
}
return tag;
},
refresh: () => {
r.deleteStyle();
return r.inject();
}
};
ONCSS_CACHE.set(cacheId, cachekey, r);
let inject = (_c = opt === null || opt === void 0 ? void 0 : opt.injectStyle) !== null && _c !== void 0 ? _c : true;
if (inject && d.document) {
r.inject();
}
return r;
}
return { stack, skiped };
};
exports.ONCSS_CACHE = ONCSS_CACHE;
exports.cssPrefix = cssPrefix;
exports.formatCSSProp = formatCSSProp;
exports.formatCSSValue = formatCSSValue;
exports.style = style;
//# sourceMappingURL=core.cjs.map