From 3cf51f4d88e8e91faa6ab5d1f2c5f8c8e505ae89 Mon Sep 17 00:00:00 2001 From: Kyle McLean Date: Mon, 30 Jan 2023 16:37:03 -0700 Subject: [PATCH] Improve compatibility for browsers that do not support `ResizeObserver` or `:where` selector (#5265) * Add fallback for default styles when `:where` selector is not supported * Add polyfill for ResizeObserver * Add changeset --- .changeset/witty-tips-work.md | 5 +++++ packages/slate-react/package.json | 1 + .../slate-react/src/components/editable.tsx | 11 +++++----- packages/slate-react/src/components/leaf.tsx | 8 +++++-- .../src/utils/where-if-supported.ts | 22 +++++++++++++++++++ yarn.lock | 8 +++++++ 6 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 .changeset/witty-tips-work.md create mode 100644 packages/slate-react/src/utils/where-if-supported.ts diff --git a/.changeset/witty-tips-work.md b/.changeset/witty-tips-work.md new file mode 100644 index 0000000000..ea02ff2b17 --- /dev/null +++ b/.changeset/witty-tips-work.md @@ -0,0 +1,5 @@ +--- +'slate-react': patch +--- + +Improve compatibility for browsers that do not support ResizeObserver or :where selector diff --git a/packages/slate-react/package.json b/packages/slate-react/package.json index 8cbe696b1b..37fd8415c5 100644 --- a/packages/slate-react/package.json +++ b/packages/slate-react/package.json @@ -14,6 +14,7 @@ "dist/" ], "dependencies": { + "@juggle/resize-observer": "^3.4.0", "@types/is-hotkey": "^0.1.1", "@types/lodash": "^4.14.149", "direction": "^1.0.3", diff --git a/packages/slate-react/src/components/editable.tsx b/packages/slate-react/src/components/editable.tsx index 09d6598a9f..adad6b3dd6 100644 --- a/packages/slate-react/src/components/editable.tsx +++ b/packages/slate-react/src/components/editable.tsx @@ -66,6 +66,7 @@ import { NODE_TO_ELEMENT, PLACEHOLDER_SYMBOL, } from '../utils/weak-maps' +import { whereIfSupported } from '../utils/where-if-supported' import { RestoreDOM } from './restore-dom/restore-dom' import { useAndroidInputManager } from '../hooks/android-input-manager/use-android-input-manager' import { useTrackUserInput } from '../hooks/use-track-user-input' @@ -812,9 +813,8 @@ export const Editable = (props: EditableProps) => { // Set global default styles for editors. const defaultStylesElement = document.createElement('style') defaultStylesElement.setAttribute('data-slate-default-styles', 'true') - defaultStylesElement.innerHTML = - // :where is used to give these rules lower specificity so user stylesheets can override them. - `:where([data-slate-editor]) {` + + const selector = '[data-slate-editor]' + const defaultStyles = // Allow positioning relative to the editable element. `position: relative;` + // Prevent the default outline styles. @@ -822,8 +822,9 @@ export const Editable = (props: EditableProps) => { // Preserve adjacent whitespace and new lines. `white-space: pre-wrap;` + // Allow words to break if they are too long. - `word-wrap: break-word;` + - `}` + `word-wrap: break-word;` + defaultStylesElement.innerHTML = whereIfSupported(selector, defaultStyles) + document.head.appendChild(defaultStylesElement) } diff --git a/packages/slate-react/src/components/leaf.tsx b/packages/slate-react/src/components/leaf.tsx index 823a56c9b7..bdf2c55757 100644 --- a/packages/slate-react/src/components/leaf.tsx +++ b/packages/slate-react/src/components/leaf.tsx @@ -1,5 +1,6 @@ import React, { useRef, useEffect } from 'react' import { Element, Text } from 'slate' +import { ResizeObserver as ResizeObserverPolyfill } from '@juggle/resize-observer' import String from './string' import { PLACEHOLDER_SYMBOL, @@ -8,6 +9,7 @@ import { } from '../utils/weak-maps' import { RenderLeafProps, RenderPlaceholderProps } from './editable' import { useSlateStatic } from '../hooks/use-slate-static' +import { whereIfSupported } from '../utils/where-if-supported' /** * Individual leaves in a text node with unique formatting. @@ -59,12 +61,14 @@ const Leaf = (props: { placeholderResizeObserver.current.observe(placeholderEl) } else if (placeholderEl) { // Create a new observer and observe the placeholder element. + const ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill placeholderResizeObserver.current = new ResizeObserver(([{ target }]) => { const styleElement = EDITOR_TO_STYLE_ELEMENT.get(editor) if (styleElement) { // Make the min-height the height of the placeholder. - const minHeight = `${target.clientHeight}px` - styleElement.innerHTML = `:where([data-slate-editor-id="${editor.id}"]) { min-height: ${minHeight}; }` + const selector = `[data-slate-editor-id="${editor.id}"]` + const styles = `min-height: ${target.clientHeight}px;` + styleElement.innerHTML = whereIfSupported(selector, styles) } }) diff --git a/packages/slate-react/src/utils/where-if-supported.ts b/packages/slate-react/src/utils/where-if-supported.ts new file mode 100644 index 0000000000..df6ae7b72b --- /dev/null +++ b/packages/slate-react/src/utils/where-if-supported.ts @@ -0,0 +1,22 @@ +/** + * Returns a set of rules that use the `:where` selector if it is supported, + * otherwise it falls back to the provided selector on its own. + * + * The `:where` selector is used to give a selector a lower specificity, + * allowing the rule to be overridden by a user-defined stylesheet. + * + * Older browsers do not support the `:where` selector. + * If it is not supported, the selector will be used without `:where`, + * which means that the rule will have a higher specificity and a user-defined + * stylesheet will not be able to override it easily. + */ +export function whereIfSupported(selector: string, styles: string): string { + return ( + `@supports (selector(:where(${selector}))) {` + + `:where(${selector}) { ${styles} }` + + `}` + + `@supports not (selector(:where(${selector}))) {` + + `${selector} { ${styles} }` + + `}` + ) +} diff --git a/yarn.lock b/yarn.lock index 663298006c..c393a3c5ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2268,6 +2268,13 @@ __metadata: languageName: node linkType: hard +"@juggle/resize-observer@npm:^3.4.0": + version: 3.4.0 + resolution: "@juggle/resize-observer@npm:3.4.0" + checksum: 2505028c05cc2e17639fcad06218b1c4b60f932a4ebb4b41ab546ef8c157031ae377e3f560903801f6d01706dbefd4943b6c4704bf19ed86dfa1c62f1473a570 + languageName: node + linkType: hard + "@lerna/add@npm:3.21.0": version: 3.21.0 resolution: "@lerna/add@npm:3.21.0" @@ -13904,6 +13911,7 @@ resolve@^2.0.0-next.3: resolution: "slate-react@workspace:packages/slate-react" dependencies: "@babel/runtime": ^7.7.4 + "@juggle/resize-observer": ^3.4.0 "@types/is-hotkey": ^0.1.1 "@types/jest": ^27.4.1 "@types/jsdom": ^16.2.14