diff --git a/packages/calcite-components/conventions/README.md b/packages/calcite-components/conventions/README.md index dfaa995009a..04afc996982 100644 --- a/packages/calcite-components/conventions/README.md +++ b/packages/calcite-components/conventions/README.md @@ -373,9 +373,9 @@ This generates a `hydrate` directory which exposes `renderToString()` (for the s Since many of the same lifecycle methods are called on the client and server you may need to differentiate any code that relies on browser APIs like so: ```ts -import { Build } from "@stencil/core"; +import { isBrowser } from "../utils/browser"; -if (Build.isBrowser) { +if (isBrowser()) { // client side } else { // server side diff --git a/packages/calcite-components/src/components/action/action.tsx b/packages/calcite-components/src/components/action/action.tsx index 2586fb051c0..f68e5515f88 100644 --- a/packages/calcite-components/src/components/action/action.tsx +++ b/packages/calcite-components/src/components/action/action.tsx @@ -1,5 +1,4 @@ import { - Build, Component, Element, forceUpdate, @@ -38,6 +37,7 @@ import { } from "../../utils/t9n"; import { Alignment, Appearance, Scale } from "../interfaces"; import { IconName } from "../icon/interfaces"; +import { isBrowser } from "../../utils/browser"; import { ActionMessages } from "./assets/action/t9n"; import { CSS, SLOTS } from "./resources"; @@ -182,7 +182,7 @@ export class Action async componentWillLoad(): Promise { setUpLoadableComponent(this); - if (Build.isBrowser) { + if (isBrowser()) { await setUpMessages(this); } } diff --git a/packages/calcite-components/src/components/button/button.tsx b/packages/calcite-components/src/components/button/button.tsx index 7c433f30177..d655278282a 100644 --- a/packages/calcite-components/src/components/button/button.tsx +++ b/packages/calcite-components/src/components/button/button.tsx @@ -1,5 +1,4 @@ import { - Build, Component, Element, forceUpdate, @@ -38,6 +37,7 @@ import { import { Appearance, FlipContext, Kind, Scale, Width } from "../interfaces"; import { toAriaBoolean } from "../../utils/dom"; import { IconName } from "../icon/interfaces"; +import { isBrowser } from "../../utils/browser"; import { ButtonMessages } from "./assets/button/t9n"; import { ButtonAlignment } from "./interfaces"; import { CSS } from "./resources"; @@ -226,7 +226,7 @@ export class Button async componentWillLoad(): Promise { setUpLoadableComponent(this); - if (Build.isBrowser) { + if (isBrowser()) { this.updateHasContent(); await setUpMessages(this); } diff --git a/packages/calcite-components/src/components/chip/chip.tsx b/packages/calcite-components/src/components/chip/chip.tsx index b7f6b674408..4a6cdaab93b 100644 --- a/packages/calcite-components/src/components/chip/chip.tsx +++ b/packages/calcite-components/src/components/chip/chip.tsx @@ -1,5 +1,4 @@ import { - Build, Component, Element, Event, @@ -39,6 +38,7 @@ import { connectLocalized, disconnectLocalized, LocalizedComponent } from "../.. import { isActivationKey } from "../../utils/key"; import { getIconScale } from "../../utils/component"; import { IconName } from "../icon/interfaces"; +import { isBrowser } from "../../utils/browser"; import { ChipMessages } from "./assets/chip/t9n"; import { CSS, SLOTS, ICONS } from "./resources"; @@ -230,7 +230,7 @@ export class Chip async componentWillLoad(): Promise { setUpLoadableComponent(this); - if (Build.isBrowser) { + if (isBrowser()) { await setUpMessages(this); this.updateHasText(); } diff --git a/packages/calcite-components/src/components/combobox/utils.ts b/packages/calcite-components/src/components/combobox/utils.ts index 5c92b929dc2..6d2f08895f4 100644 --- a/packages/calcite-components/src/components/combobox/utils.ts +++ b/packages/calcite-components/src/components/combobox/utils.ts @@ -1,5 +1,5 @@ -import { Build } from "@stencil/core"; import { nodeListToArray } from "../../utils/dom"; +import { isBrowser } from "../../utils/browser"; import { ComboboxChildElement } from "./interfaces"; import { ComboboxChildSelector } from "./resources"; import { Combobox } from "./combobox"; @@ -26,7 +26,7 @@ export function hasActiveChildren(node: HTMLCalciteComboboxItemElement): boolean } export function getDepth(element: HTMLElement): number { - if (!Build.isBrowser) { + if (!isBrowser()) { return 0; } diff --git a/packages/calcite-components/src/components/date-picker/date-picker.tsx b/packages/calcite-components/src/components/date-picker/date-picker.tsx index c2a1157c3b4..179ed394473 100644 --- a/packages/calcite-components/src/components/date-picker/date-picker.tsx +++ b/packages/calcite-components/src/components/date-picker/date-picker.tsx @@ -1,5 +1,4 @@ import { - Build, Component, Element, Event, @@ -42,6 +41,7 @@ import { updateMessages, } from "../../utils/t9n"; import { HeadingLevel } from "../functional/Heading"; +import { isBrowser } from "../../utils/browser"; import { DatePickerMessages } from "./assets/date-picker/t9n"; import { DATE_PICKER_FORMAT_OPTIONS, HEADING_LEVEL } from "./resources"; import { DateLocaleData, getLocaleData, getValueAsDateRange } from "./utils"; @@ -347,7 +347,7 @@ export class DatePicker implements LocalizedComponent, LoadableComponent, T9nCom @Watch("effectiveLocale") private async loadLocaleData(): Promise { - if (!Build.isBrowser) { + if (!isBrowser()) { return; } diff --git a/packages/calcite-components/src/components/icon/icon.tsx b/packages/calcite-components/src/components/icon/icon.tsx index aa2404dece0..44f11c4ac70 100644 --- a/packages/calcite-components/src/components/icon/icon.tsx +++ b/packages/calcite-components/src/components/icon/icon.tsx @@ -1,8 +1,9 @@ import { CalciteIconPath, CalciteMultiPathEntry } from "@esri/calcite-ui-icons"; -import { Build, Component, Element, h, Host, Prop, State, VNode, Watch } from "@stencil/core"; +import { Component, Element, h, Host, Prop, State, VNode, Watch } from "@stencil/core"; import { getElementDir, toAriaBoolean } from "../../utils/dom"; import { createObserver } from "../../utils/observers"; import { Scale } from "../interfaces"; +import { isBrowser } from "../../utils/browser"; import { CSS } from "./resources"; import { fetchIcon, getCachedIconData, scaleToPx } from "./utils"; import { IconName } from "./interfaces"; @@ -137,7 +138,7 @@ export class Icon { private async loadIconPathData(): Promise { const { icon, scale, visible } = this; - if (!Build.isBrowser || !icon || !visible) { + if (!isBrowser() || !icon || !visible) { return; } diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx index 3be23598643..7516cf3a0be 100644 --- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx +++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx @@ -1,5 +1,4 @@ import { - Build, Component, Element, Event, @@ -90,6 +89,7 @@ import { Status } from "../interfaces"; import { Validation } from "../functional/Validation"; import { IconName } from "../icon/interfaces"; import { syncHiddenFormInput } from "../input/common/input"; +import { isBrowser } from "../../utils/browser"; import { normalizeToCurrentCentury, isTwoDigitYear } from "./utils"; import { InputDatePickerMessages } from "./assets/input-date-picker/t9n"; import { CSS } from "./resources"; @@ -984,7 +984,7 @@ export class InputDatePicker }; private async loadLocaleData(): Promise { - if (!Build.isBrowser) { + if (!isBrowser()) { return; } numberStringFormatter.numberFormatOptions = { diff --git a/packages/calcite-components/src/components/list-item/utils.ts b/packages/calcite-components/src/components/list-item/utils.ts index 30e5f444ab4..5b7a2365070 100644 --- a/packages/calcite-components/src/components/list-item/utils.ts +++ b/packages/calcite-components/src/components/list-item/utils.ts @@ -1,4 +1,4 @@ -import { Build } from "@stencil/core"; +import { isBrowser } from "../../utils/browser"; const listSelector = "calcite-list"; const listItemGroupSelector = "calcite-list-item-group"; @@ -38,7 +38,7 @@ export function updateListItemChildren(listItemChildren: HTMLCalciteListItemElem } export function getDepth(element: HTMLElement, includeGroup = false): number { - if (!Build.isBrowser) { + if (!isBrowser()) { return 0; } diff --git a/packages/calcite-components/src/components/segmented-control/segmented-control.tsx b/packages/calcite-components/src/components/segmented-control/segmented-control.tsx index 1b7989e3e81..dd1638dbd4f 100644 --- a/packages/calcite-components/src/components/segmented-control/segmented-control.tsx +++ b/packages/calcite-components/src/components/segmented-control/segmented-control.tsx @@ -1,5 +1,4 @@ import { - Build, Component, Element, Event, @@ -39,6 +38,7 @@ import { Appearance, Layout, Scale, Status, Width } from "../interfaces"; import { createObserver } from "../../utils/observers"; import { Validation } from "../functional/Validation"; import { IconName } from "../icon/interfaces"; +import { isBrowser } from "../../utils/browser"; import { CSS } from "./resources"; /** @@ -390,7 +390,7 @@ export class SegmentedControl }); this.selectedItem = match; - if (Build.isBrowser && match) { + if (isBrowser() && match) { match.focus(); } } diff --git a/packages/calcite-components/src/components/tab-title/tab-title.tsx b/packages/calcite-components/src/components/tab-title/tab-title.tsx index 8d79c1d504d..d0bd9d0456f 100644 --- a/packages/calcite-components/src/components/tab-title/tab-title.tsx +++ b/packages/calcite-components/src/components/tab-title/tab-title.tsx @@ -1,5 +1,4 @@ import { - Build, Component, Element, Event, @@ -36,6 +35,7 @@ import { } from "../../utils/t9n"; import { getIconScale } from "../../utils/component"; import { IconName } from "../icon/interfaces"; +import { isBrowser } from "../../utils/browser"; import { TabTitleMessages } from "./assets/tab-title/t9n"; import { CSS, ICONS } from "./resources"; @@ -172,7 +172,7 @@ export class TabTitle implements InteractiveComponent, LocalizedComponent, T9nCo async componentWillLoad(): Promise { await setUpMessages(this); - if (Build.isBrowser) { + if (isBrowser()) { this.updateHasText(); } if (this.tab && this.selected) { diff --git a/packages/calcite-components/src/utils/browser.ts b/packages/calcite-components/src/utils/browser.ts index 2e6ba14cb54..701af28924c 100644 --- a/packages/calcite-components/src/utils/browser.ts +++ b/packages/calcite-components/src/utils/browser.ts @@ -1,5 +1,14 @@ import { Build } from "@stencil/core"; +export const isBrowser = (): boolean => + Build.isBrowser && + typeof navigator !== "undefined" && + typeof window !== "undefined" && + typeof location !== "undefined" && + typeof document !== "undefined" && + window.location === location && + window.document === document; + interface NavigatorUAData { brands: Array<{ brand: string; version: string }>; mobile: boolean; @@ -11,7 +20,7 @@ function getUserAgentData(): NavigatorUAData | undefined { } export function getUserAgentString(): string { - if (!Build.isBrowser) { + if (!isBrowser()) { return ""; } diff --git a/packages/calcite-components/src/utils/floating-ui.ts b/packages/calcite-components/src/utils/floating-ui.ts index 532fcd2a0d2..b24277546c6 100644 --- a/packages/calcite-components/src/utils/floating-ui.ts +++ b/packages/calcite-components/src/utils/floating-ui.ts @@ -14,15 +14,15 @@ import { Strategy, VirtualElement, } from "@floating-ui/dom"; -import { Build } from "@stencil/core"; import { debounce, DebouncedFunc } from "lodash-es"; import { offsetParent } from "composed-offset-position"; import { Layout } from "../components/interfaces"; import { DEBOUNCE } from "./resources"; import { getElementDir } from "./dom"; +import { isBrowser } from "./browser"; (function setUpFloatingUiForShadowDomPositioning(): void { - if (Build.isBrowser) { + if (isBrowser()) { const originalGetOffsetParent = platform.getOffsetParent; platform.getOffsetParent = (element: Element) => originalGetOffsetParent(element, offsetParent); } @@ -499,7 +499,7 @@ async function runAutoUpdate( return; } - const effectiveAutoUpdate = Build.isBrowser + const effectiveAutoUpdate = isBrowser() ? autoUpdate : (_refEl: HTMLElement, _floatingEl: HTMLElement, updateCallback: () => void): (() => void) => { updateCallback(); diff --git a/packages/calcite-components/src/utils/globalScript.ts b/packages/calcite-components/src/utils/globalScript.ts index bead6265c2e..0bb783bce0c 100644 --- a/packages/calcite-components/src/utils/globalScript.ts +++ b/packages/calcite-components/src/utils/globalScript.ts @@ -1,5 +1,6 @@ import { initModeChangeEvent } from "./mode"; import { stampVersion } from "./config"; +import { isBrowser } from "./browser"; /** * This file is imported in Stencil's `globalScript` config option. @@ -7,14 +8,7 @@ import { stampVersion } from "./config"; * @see {@link https://stenciljs.com/docs/config#globalscript} */ export default function (): void { - const isBrowser = - typeof window !== "undefined" && - typeof location !== "undefined" && - typeof document !== "undefined" && - window.location === location && - window.document === document; - - if (isBrowser) { + if (isBrowser()) { if (document.readyState === "interactive") { initModeChangeEvent(); } else { diff --git a/packages/calcite-components/src/utils/loadable.ts b/packages/calcite-components/src/utils/loadable.ts index 00f2f774408..3b7e7874a8c 100644 --- a/packages/calcite-components/src/utils/loadable.ts +++ b/packages/calcite-components/src/utils/loadable.ts @@ -1,4 +1,5 @@ -import { Build, forceUpdate } from "@stencil/core"; +import { forceUpdate } from "@stencil/core"; +import { isBrowser } from "./browser"; /** * This helper adds support for knowing when a component has been loaded. @@ -134,7 +135,7 @@ export function componentLoaded(component: LoadableComponent): Promise { export async function componentFocusable(component: LoadableComponent): Promise { await componentLoaded(component); - if (!Build.isBrowser) { + if (!isBrowser()) { return; } diff --git a/packages/calcite-components/src/utils/observers.ts b/packages/calcite-components/src/utils/observers.ts index 5cd14d9ec81..46e2ed4a163 100644 --- a/packages/calcite-components/src/utils/observers.ts +++ b/packages/calcite-components/src/utils/observers.ts @@ -1,4 +1,4 @@ -import { Build } from "@stencil/core"; +import { isBrowser } from "./browser"; export interface ExtendedMutationObserver extends MutationObserver { new: () => ExtendedMutationObserver; @@ -50,7 +50,7 @@ export function createObserver( callback: ObserverCallbackType, options?: ObserverOptions, ): ObserverInstanceType | undefined { - if (!Build.isBrowser) { + if (!isBrowser()) { return undefined; } diff --git a/packages/calcite-components/src/utils/t9n.ts b/packages/calcite-components/src/utils/t9n.ts index b91f08cac86..8852048b80c 100644 --- a/packages/calcite-components/src/utils/t9n.ts +++ b/packages/calcite-components/src/utils/t9n.ts @@ -1,5 +1,6 @@ -import { Build, getAssetPath } from "@stencil/core"; +import { getAssetPath } from "@stencil/core"; import { getSupportedLocale, LocalizedComponent } from "./locale"; +import { isBrowser } from "./browser"; export type MessageBundle = Record; @@ -50,7 +51,7 @@ export async function setUpMessages(component: T9nComponent): Promise { } async function fetchMessages(component: T9nComponent, lang: string): Promise { - if (!Build.isBrowser) { + if (!isBrowser()) { return {}; }