environment manager (#1784)
This PR extracts the environment manager from #1778. ### Change Type - [x] `major` — Breaking change ### Release Notes - [editor] Move environment flags to environment manager
This commit is contained in:
parent
79fae186e4
commit
c478d75117
8 changed files with 69 additions and 54 deletions
|
@ -630,6 +630,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
duplicateShapes(ids: TLShapeId[], offset?: VecLike): this;
|
duplicateShapes(ids: TLShapeId[], offset?: VecLike): this;
|
||||||
get editingShapeId(): null | TLShapeId;
|
get editingShapeId(): null | TLShapeId;
|
||||||
|
readonly environment: EnvironmentManager;
|
||||||
get erasingShapeIds(): TLShapeId[];
|
get erasingShapeIds(): TLShapeId[];
|
||||||
get erasingShapeIdsSet(): Set<TLShapeId>;
|
get erasingShapeIdsSet(): Set<TLShapeId>;
|
||||||
// @internal (undocumented)
|
// @internal (undocumented)
|
||||||
|
@ -805,12 +806,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
||||||
isAncestorSelected(id: TLShapeId): boolean;
|
isAncestorSelected(id: TLShapeId): boolean;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
isAncestorSelected(shape: TLShape): boolean;
|
isAncestorSelected(shape: TLShape): boolean;
|
||||||
readonly isAndroid: boolean;
|
|
||||||
readonly isChromeForIos: boolean;
|
|
||||||
readonly isFirefox: boolean;
|
|
||||||
isIn(path: string): boolean;
|
isIn(path: string): boolean;
|
||||||
isInAny(...paths: string[]): boolean;
|
isInAny(...paths: string[]): boolean;
|
||||||
readonly isIos: boolean;
|
|
||||||
get isMenuOpen(): boolean;
|
get isMenuOpen(): boolean;
|
||||||
isPointInShape(shape: TLShape, point: VecLike, opts?: {
|
isPointInShape(shape: TLShape, point: VecLike, opts?: {
|
||||||
margin?: number;
|
margin?: number;
|
||||||
|
@ -821,7 +818,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
||||||
margin?: number;
|
margin?: number;
|
||||||
hitInside?: boolean;
|
hitInside?: boolean;
|
||||||
}): boolean;
|
}): boolean;
|
||||||
readonly isSafari: boolean;
|
|
||||||
isShapeInPage(shape: TLShape, pageId?: TLPageId): boolean;
|
isShapeInPage(shape: TLShape, pageId?: TLPageId): boolean;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
isShapeInPage(shapeId: TLShapeId, pageId?: TLPageId): boolean;
|
isShapeInPage(shapeId: TLShapeId, pageId?: TLPageId): boolean;
|
||||||
|
|
|
@ -103,6 +103,7 @@ import { arrowBindingsIndex } from './derivations/arrowBindingsIndex'
|
||||||
import { parentsToChildren } from './derivations/parentsToChildren'
|
import { parentsToChildren } from './derivations/parentsToChildren'
|
||||||
import { deriveShapeIdsInCurrentPage } from './derivations/shapeIdsInCurrentPage'
|
import { deriveShapeIdsInCurrentPage } from './derivations/shapeIdsInCurrentPage'
|
||||||
import { ClickManager } from './managers/ClickManager'
|
import { ClickManager } from './managers/ClickManager'
|
||||||
|
import { EnvironmentManager } from './managers/EnvironmentManager'
|
||||||
import { HistoryManager } from './managers/HistoryManager'
|
import { HistoryManager } from './managers/HistoryManager'
|
||||||
import { SnapManager } from './managers/SnapManager'
|
import { SnapManager } from './managers/SnapManager'
|
||||||
import { TextManager } from './managers/TextManager'
|
import { TextManager } from './managers/TextManager'
|
||||||
|
@ -239,19 +240,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
||||||
this.root.children![Tool.id] = new Tool(this, this.root)
|
this.root.children![Tool.id] = new Tool(this, this.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof window !== 'undefined' && 'navigator' in window) {
|
this.environment = new EnvironmentManager(this)
|
||||||
this.isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
|
|
||||||
this.isIos = !!navigator.userAgent.match(/iPad/i) || !!navigator.userAgent.match(/iPhone/i)
|
|
||||||
this.isChromeForIos = /crios.*safari/i.test(navigator.userAgent)
|
|
||||||
this.isFirefox = /firefox/i.test(navigator.userAgent)
|
|
||||||
this.isAndroid = /android/i.test(navigator.userAgent)
|
|
||||||
} else {
|
|
||||||
this.isSafari = false
|
|
||||||
this.isIos = false
|
|
||||||
this.isChromeForIos = false
|
|
||||||
this.isFirefox = false
|
|
||||||
this.isAndroid = false
|
|
||||||
}
|
|
||||||
|
|
||||||
this.store.onBeforeDelete = (record) => {
|
this.store.onBeforeDelete = (record) => {
|
||||||
if (record.typeName === 'shape') {
|
if (record.typeName === 'shape') {
|
||||||
|
@ -412,39 +401,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
||||||
readonly textMeasure: TextManager
|
readonly textMeasure: TextManager
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the editor is running in Safari.
|
* A manager for the editor's environment.
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
readonly isSafari: boolean
|
readonly environment: EnvironmentManager
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the editor is running on iOS.
|
|
||||||
*
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
readonly isIos: boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the editor is running on iOS.
|
|
||||||
*
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
readonly isChromeForIos: boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the editor is running on Firefox.
|
|
||||||
*
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
readonly isFirefox: boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the editor is running on Android.
|
|
||||||
*
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
readonly isAndroid: boolean
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current HTML element containing the editor.
|
* The current HTML element containing the editor.
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { Editor } from '../Editor'
|
||||||
|
|
||||||
|
export class EnvironmentManager {
|
||||||
|
constructor(public editor: Editor) {
|
||||||
|
if (typeof window !== 'undefined' && 'navigator' in window) {
|
||||||
|
this.isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
|
||||||
|
this.isIos = !!navigator.userAgent.match(/iPad/i) || !!navigator.userAgent.match(/iPhone/i)
|
||||||
|
this.isChromeForIos = /crios.*safari/i.test(navigator.userAgent)
|
||||||
|
this.isFirefox = /firefox/i.test(navigator.userAgent)
|
||||||
|
this.isAndroid = /android/i.test(navigator.userAgent)
|
||||||
|
} else {
|
||||||
|
this.isSafari = false
|
||||||
|
this.isIos = false
|
||||||
|
this.isChromeForIos = false
|
||||||
|
this.isFirefox = false
|
||||||
|
this.isAndroid = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the editor is running in Safari.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
readonly isSafari: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the editor is running on iOS.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
readonly isIos: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the editor is running on iOS.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
readonly isChromeForIos: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the editor is running on Firefox.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
readonly isFirefox: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the editor is running on Android.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
readonly isAndroid: boolean
|
||||||
|
}
|
|
@ -7,7 +7,11 @@ export function useCoarsePointer() {
|
||||||
// This is a workaround for a Firefox bug where we don't correctly
|
// This is a workaround for a Firefox bug where we don't correctly
|
||||||
// detect coarse VS fine pointer. For now, let's assume that you have a fine
|
// detect coarse VS fine pointer. For now, let's assume that you have a fine
|
||||||
// pointer if you're on Firefox on desktop.
|
// pointer if you're on Firefox on desktop.
|
||||||
if (editor.isFirefox && !editor.isAndroid && !editor.isIos) {
|
if (
|
||||||
|
editor.environment.isFirefox &&
|
||||||
|
!editor.environment.isAndroid &&
|
||||||
|
!editor.environment.isIos
|
||||||
|
) {
|
||||||
editor.updateInstanceState({ isCoarsePointer: false })
|
editor.updateInstanceState({ isCoarsePointer: false })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -495,7 +495,7 @@ export class ArrowShapeUtil extends ShapeUtil<TLArrowShape> {
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
const changeIndex = React.useMemo<number>(() => {
|
const changeIndex = React.useMemo<number>(() => {
|
||||||
return this.editor.isSafari ? (globalRenderIndex += 1) : 0
|
return this.editor.environment.isSafari ? (globalRenderIndex += 1) : 0
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [shape])
|
}, [shape])
|
||||||
|
|
||||||
|
|
|
@ -250,7 +250,7 @@ function PatternFillDefForCanvas() {
|
||||||
const { defs, isReady } = usePattern()
|
const { defs, isReady } = usePattern()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isReady && editor.isSafari) {
|
if (isReady && editor.environment.isSafari) {
|
||||||
const htmlLayer = findHtmlLayerParent(containerRef.current!)
|
const htmlLayer = findHtmlLayerParent(containerRef.current!)
|
||||||
if (htmlLayer) {
|
if (htmlLayer) {
|
||||||
// Wait for `patternContext` to be picked up
|
// Wait for `patternContext` to be picked up
|
||||||
|
|
|
@ -379,7 +379,7 @@ export const PageMenu = function PageMenu() {
|
||||||
item={page}
|
item={page}
|
||||||
listSize={pages.length}
|
listSize={pages.length}
|
||||||
onRename={() => {
|
onRename={() => {
|
||||||
if (editor.isIos) {
|
if (editor.environment.isIos) {
|
||||||
const name = window.prompt('Rename page', page.name)
|
const name = window.prompt('Rename page', page.name)
|
||||||
if (name && name !== page.name) {
|
if (name && name !== page.name) {
|
||||||
editor.renamePage(page.id, name)
|
editor.renamePage(page.id, name)
|
||||||
|
|
|
@ -156,10 +156,10 @@ export function usePrint() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function triggerPrint() {
|
function triggerPrint() {
|
||||||
if (editor.isChromeForIos) {
|
if (editor.environment.isChromeForIos) {
|
||||||
beforePrintHandler()
|
beforePrintHandler()
|
||||||
window.print()
|
window.print()
|
||||||
} else if (editor.isSafari) {
|
} else if (editor.environment.isSafari) {
|
||||||
beforePrintHandler()
|
beforePrintHandler()
|
||||||
document.execCommand('print', false)
|
document.execCommand('print', false)
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue