@codecademy/gamut-styles
17.13.117.13.2-alpha.bf4dbb.0
dist/utilities/elementDir.js+
dist/utilities/elementDir.jsNew file+59
Index: package/dist/utilities/elementDir.js
===================================================================
--- package/dist/utilities/elementDir.js
+++ package/dist/utilities/elementDir.js
@@ -0,0 +1,59 @@
+import { useEffect, useLayoutEffect, useReducer } from 'react';
+
+/** Resolved HTML `dir` keyword: effective writing direction after `dir`, then CSS `direction`, then document root. */
+
+/**
+ * Resolves the effective `dir` for an element (`rtl` or `ltr`), including JSDOM where
+ * `getComputedStyle(el).direction` is often empty while `dir` is set on the root.
+ */
+export function elementDir(el) {
+ const ownDir = el.getAttribute('dir');
+ if (ownDir === 'rtl') return 'rtl';
+ if (ownDir === 'ltr') return 'ltr';
+ const {
+ direction
+ } = getComputedStyle(el);
+ if (direction === 'rtl' || direction === 'ltr') {
+ return direction;
+ }
+ return document.documentElement.getAttribute('dir') === 'rtl' ? 'rtl' : 'ltr';
+}
+
+/**
+ * Ref whose `current` may be any DOM {@link Element} subclass (`HTMLElement`, `SVGElement`,
+ * `HTMLButtonElement`, etc.). For structural/minimal types (e.g. tests), intersect with
+ * `Element` so `current` is still typed as an `Element` (e.g. `Pick<HTMLAnchorElement, 'id'> & Element`).
+ */
+
+function resolveElement(elementRef) {
+ return elementRef?.current instanceof Element ? elementRef.current : document.documentElement;
+}
+
+/**
+ * Returns the effective `dir` for the resolved element (`rtl` or `ltr`), and updates when `dir`
+ * changes on the document subtree or after layout (so `ref.current` is current).
+ * Resolution uses {@link elementDir}.
+ *
+ * @param elementRef - Optional ref; when missing or `current` is not an `Element`, uses `document.documentElement`.
+ */
+export function useElementDir(elementRef) {
+ const [, bump] = useReducer(n => n + 1, 0);
+ useLayoutEffect(() => {
+ bump();
+ }, [elementRef]);
+ useEffect(() => {
+ const observer = new MutationObserver(() => {
+ bump();
+ });
+ observer.observe(document.documentElement, {
+ attributeFilter: ['dir'],
+ attributes: true,
+ subtree: true
+ });
+ return () => observer.disconnect();
+ }, []);
+ if (typeof document === 'undefined') {
+ return 'ltr';
+ }
+ return elementDir(resolveElement(elementRef));
+}
\ No newline at end of file