模拟 :hover、:active 和 :focus 状态来测试样式

问题描述 投票:0回答:1

我正在为某个组件库构建重新样式以实施公司设计系统。我希望能够 渲染组件的样式,就好像它们悬停/按下/聚焦一样 以便能够显示和测试当组件处于这些状态之一时应用的样式。

AFAICS 无法实际模拟这些元素状态。类似的问题通常与模拟相应的事件有关,这与我无关,因为它无法实际模拟

:hover
/
:active
/
:focus
styling。其他人建议在样式中使用
className
而不是伪类,这在无法[完全]控制相关样式时不适用。

我使用 Emotion 进行样式设置,因此我不直接创建样式。它们自动生成为文档头中的许多

<style>
节点。

css typescript dom
1个回答
0
投票

我能够通过操作生成的

<style>
节点、复制 CSS 选择器的相关部分来实现所需的结果,这样对于使用
:hover
/
:active
/
:focus
的每个选择器,我添加了它的副本改为应用类选择器。然后,当我需要显示特定的状态样式时,我应用了相同的类。

export enum StateClass {
  Hover = '__demo-hover',
  Focus = '__demo-focus',
  Active = '__demo-active'
}

const simulateStatesInRule = (rule: CSSRule) => {
  if (rule instanceof CSSMediaRule) {
    Array.from(rule.cssRules).forEach(simulateStatesInRule);
    return;
  }

  if (!(rule instanceof CSSStyleRule) || !rule.selectorText) return;

  rule.selectorText = rule.selectorText.split(',').flatMap((part) => {
    if (/\.(?:hover|focus|active)/.test(part)) return []; // don't keep adding selectors forever
    if (/:(?:hover|focus|active)/.test(part))
      return [
        part,
        part
          .replace(/:hover/g, `.${StateClass.Hover}`)
          .replace(/:focus/g, `.${StateClass.Focus}`)
          .replace(/:active/g, `.${StateClass.Active}`)
      ];
    return [part];
  }).join(',');
};

const simulateStatesInStyle = (style: HTMLStyleElement) =>
  Array.from(style.sheet?.cssRules ?? []).forEach(simulateStatesInRule);

export const simulateStatesUsingClasses () => {
  const observer = new MutationObserver((mutations) =>
    mutations.forEach(({ addedNodes }) =>
      Array.from(addedNodes)
        .filter((node) => node instanceof HTMLStyleElement)
        .forEach(simulateStatesInStyle)
    )
   );

   observer.observe(document.head, { childList: true });
   document.head.querySelectorAll('style').forEach(simulateStatesInStyle);

   return () => {
    observer.disconnect();
  };
}
© www.soinside.com 2019 - 2024. All rights reserved.