ant-design-vue/components/vc-util/Dom/dynamicCSS.ts

100 lines
2.4 KiB
TypeScript
Raw Normal View History

Feat css var (#5327) * style: affix & util * feat(alert): add customIcon slot * feat(anchor): ts type * style: auto-complete * feat: avatar add crossOrigin & maxPopoverTrigger * style(backTop): v-show instead v-if * style: badge * style: breadcrumb * feat: button add global size * feat: update i18n * feat: picker add disabledTime * test: update snap * doc: update img url * style: fix Card tabs of left position * doc: update cascader doc * feat: collapse * style: comment * style: configprovider * feat: date-picker add soem icon slot * style: update descriptions style * feat: add divider orientationMargin * doc: update drawer * feat: dropdown add destroyPopupOnHide & loading * style: update empty * feat: form add labelWrap * style: update grid * test: update grid snap * fix: image ts error * fix: mentions cannot select, close #5233 * doc: update pagination change info, close #5293 * fix: table dynamic expand error, close #5295 * style: remove not use * release 3.0.0-beta.11 * doc: update typo * feat: input add showCount * feat: inputNumber add prefix slot * style: update layout * style: update list * feat: add locale i18 * style: update locale ts * style: update mentions * feat: menu divider add dashed * perf: menu * perf: menu animate * feat: modal method add wrapClassName * style: update pageheader * feat: update pagination ts * feat: confirm add showCancel & promise * doc: update popover * style: update progress * style: radio * style: update rate、result、row * feat: select add fieldNames * feat: add skeleton button & input * feat: spin tip support slot * style: slider & space * stype: update steps ts type * style: update switch * feat: table add tree filter * test: update input sanp * feat: table add filterMode... * fix: tree autoExpandParent bug * test: update input snap * doc: tabs add destroyInactiveTabPane * style: update tag * style: update timeline & time-picker * fix: Tooltip arrowPointAtCenter 1px shift bug * feat: typography add enterEnterIcon triggerType * doc: update tree-select * fix: deps and TypeScript types * style: udpate transfer * style: update style * doc: add colorScheme * chore: add css var builg * doc: sort api * style: lint code * doc: add css var * test: update snap * chore: add pre script * chore: update lint * perf: collapse animate * perf: collapse tree * perf: typography shaking when edit * doc: update auto-complete demo * fix: table tree not have animate * feat: deprecated dropdown center placement * feat: deprecated dropdown center placement * test: update snap
2022-03-12 01:56:32 +00:00
import canUseDom from '../../_util/canUseDom';
const MARK_KEY = `vc-util-key` as any;
function getMark({ mark }: Options = {}) {
if (mark) {
return mark.startsWith('data-') ? mark : `data-${mark}`;
}
return MARK_KEY;
}
interface Options {
attachTo?: Element;
csp?: { nonce?: string };
prepend?: boolean;
mark?: string;
}
function getContainer(option: Options) {
if (option.attachTo) {
return option.attachTo;
}
const head = document.querySelector('head');
return head || document.body;
}
export function injectCSS(css: string, option: Options = {}) {
if (!canUseDom()) {
return null;
}
const styleNode = document.createElement('style');
if (option.csp?.nonce) {
styleNode.nonce = option.csp?.nonce;
}
styleNode.innerHTML = css;
const container = getContainer(option);
const { firstChild } = container;
if (option.prepend && container.prepend) {
// Use `prepend` first
container.prepend(styleNode);
} else if (option.prepend && firstChild) {
// Fallback to `insertBefore` like IE not support `prepend`
container.insertBefore(styleNode, firstChild);
} else {
container.appendChild(styleNode);
}
return styleNode;
}
const containerCache = new Map<Element, Node & ParentNode>();
function findExistNode(key: string, option: Options = {}) {
const container = getContainer(option);
return Array.from(containerCache.get(container).children).find(
node => node.tagName === 'STYLE' && node.getAttribute(getMark(option)) === key,
) as HTMLStyleElement;
}
export function removeCSS(key: string, option: Options = {}) {
const existNode = findExistNode(key, option);
existNode?.parentNode?.removeChild(existNode);
}
export function updateCSS(css: string, key: string, option: Options = {}) {
const container = getContainer(option);
// Get real parent
if (!containerCache.has(container)) {
const placeholderStyle = injectCSS('', option);
const { parentNode } = placeholderStyle;
containerCache.set(container, parentNode);
parentNode.removeChild(placeholderStyle);
}
const existNode = findExistNode(key, option);
if (existNode) {
if (option.csp?.nonce && existNode.nonce !== option.csp?.nonce) {
existNode.nonce = option.csp?.nonce;
}
if (existNode.innerHTML !== css) {
existNode.innerHTML = css;
}
return existNode;
}
const newNode = injectCSS(css, option);
newNode.setAttribute(getMark(option), key);
return newNode;
}