From 7e787dedc0247a9417588f7b6b33116846d1277a Mon Sep 17 00:00:00 2001 From: JC Franco Date: Tue, 4 Jun 2024 13:23:12 -0700 Subject: [PATCH] revert: refactor: add simpler componentFocusable util (deprecates LoadableComponent) --- .../calcite-components/src/components.d.ts | 98 +++++++++++++++++++ .../src/utils/component.spec.ts | 49 +--------- .../calcite-components/src/utils/component.ts | 38 ------- .../calcite-components/src/utils/loadable.ts | 30 +++--- 4 files changed, 111 insertions(+), 104 deletions(-) diff --git a/packages/calcite-components/src/components.d.ts b/packages/calcite-components/src/components.d.ts index 14d5926eb0e..b0ea2d37b6c 100644 --- a/packages/calcite-components/src/components.d.ts +++ b/packages/calcite-components/src/components.d.ts @@ -8,84 +8,182 @@ import { HTMLStencilElement, JSXBase } from "@stencil/core/internal"; import { Alignment, Appearance, Columns, FlipContext, Kind, Layout, LogicalFlowPosition, Position, Scale, SelectionAppearance as SelectionAppearance1, SelectionMode, Status, Width } from "./components/interfaces"; import { RequestedItem } from "./components/accordion/interfaces"; import { RequestedItem as RequestedItem1 } from "./components/accordion-item/interfaces"; +import { ActionMessages } from "./components/action/assets/action/t9n"; import { EffectivePlacement, LogicalPlacement, MenuPlacement, OverlayPositioning, ReferenceElement } from "./utils/floating-ui"; +import { ActionBarMessages } from "./components/action-bar/assets/action-bar/t9n"; +import { ActionGroupMessages } from "./components/action-group/assets/action-group/t9n"; +import { ActionPadMessages } from "./components/action-pad/assets/action-pad/t9n"; import { AlertDuration, Sync } from "./components/alert/interfaces"; import { NumberingSystem } from "./utils/locale"; +import { AlertMessages } from "./components/alert/assets/alert/t9n"; import { HeadingLevel } from "./components/functional/Heading"; +import { BlockMessages } from "./components/block/assets/block/t9n"; import { BlockSectionToggleDisplay } from "./components/block-section/interfaces"; +import { BlockSectionMessages } from "./components/block-section/assets/block-section/t9n"; import { ButtonAlignment, DropdownIconType } from "./components/button/interfaces"; +import { ButtonMessages } from "./components/button/assets/button/t9n"; +import { CardMessages } from "./components/card/assets/card/t9n"; import { ArrowType, AutoplayType } from "./components/carousel/interfaces"; +import { CarouselMessages } from "./components/carousel/assets/carousel/t9n"; import { MutableValidityState } from "./utils/form"; +import { ChipMessages } from "./components/chip/assets/chip/t9n"; import { ColorValue, InternalColor } from "./components/color-picker/interfaces"; import { Format } from "./components/color-picker/utils"; +import { ColorPickerMessages } from "./components/color-picker/assets/color-picker/t9n"; import { ComboboxChildElement, SelectionDisplay } from "./components/combobox/interfaces"; +import { ComboboxMessages } from "./components/combobox/assets/combobox/t9n"; +import { DatePickerMessages } from "./components/date-picker/assets/date-picker/t9n"; import { DateLocaleData } from "./components/date-picker/utils"; import { HoverRange } from "./utils/date"; import { RequestedItem as RequestedItem2 } from "./components/dropdown-group/interfaces"; import { ItemKeyboardEvent } from "./components/dropdown/interfaces"; +import { FilterMessages } from "./components/filter/assets/filter/t9n"; import { FlowItemLikeElement } from "./components/flow/interfaces"; +import { FlowItemMessages } from "./components/flow-item/assets/flow-item/t9n"; import { ColorStop, DataSeries } from "./components/graph/interfaces"; +import { HandleMessages } from "./components/handle/assets/handle/t9n"; import { HandleChange, HandleNudge } from "./components/handle/interfaces"; +import { InlineEditableMessages } from "./components/inline-editable/assets/inline-editable/t9n"; import { InputPlacement } from "./components/input/interfaces"; +import { InputMessages } from "./components/input/assets/input/t9n"; +import { InputDatePickerMessages } from "./components/input-date-picker/assets/input-date-picker/t9n"; +import { InputNumberMessages } from "./components/input-number/assets/input-number/t9n"; +import { InputTextMessages } from "./components/input-text/assets/input-text/t9n"; +import { InputTimePickerMessages } from "./components/input-time-picker/assets/input-time-picker/t9n"; +import { TimePickerMessages } from "./components/time-picker/assets/time-picker/t9n"; +import { InputTimeZoneMessages } from "./components/input-time-zone/assets/input-time-zone/t9n"; import { TimeZoneMode } from "./components/input-time-zone/interfaces"; import { ListDragDetail } from "./components/list/interfaces"; import { ItemData } from "./components/list-item/interfaces"; +import { ListMessages } from "./components/list/assets/list/t9n"; import { SelectionAppearance } from "./components/list/resources"; +import { ListItemMessages } from "./components/list-item/assets/list-item/t9n"; +import { MenuMessages } from "./components/menu/assets/menu/t9n"; +import { MenuItemMessages } from "./components/menu-item/assets/menu-item/t9n"; import { MenuItemCustomEvent } from "./components/menu-item/interfaces"; import { MeterLabelType } from "./components/meter/interfaces"; +import { ModalMessages } from "./components/modal/assets/modal/t9n"; +import { NoticeMessages } from "./components/notice/assets/notice/t9n"; +import { PaginationMessages } from "./components/pagination/assets/pagination/t9n"; +import { PanelMessages } from "./components/panel/assets/panel/t9n"; import { ItemData as ItemData1, ListFocusId } from "./components/pick-list/shared-list-logic"; import { ICON_TYPES } from "./components/pick-list/resources"; +import { PickListItemMessages } from "./components/pick-list-item/assets/pick-list-item/t9n"; +import { PopoverMessages } from "./components/popover/assets/popover/t9n"; +import { RatingMessages } from "./components/rating/assets/rating/t9n"; +import { ScrimMessages } from "./components/scrim/assets/scrim/t9n"; import { DisplayMode } from "./components/sheet/interfaces"; import { DisplayMode as DisplayMode1 } from "./components/shell-panel/interfaces"; +import { ShellPanelMessages } from "./components/shell-panel/assets/shell-panel/t9n"; import { DragDetail } from "./utils/sortableComponent"; import { StepperItemChangeEventDetail, StepperItemEventDetail, StepperItemKeyEventDetail, StepperLayout } from "./components/stepper/interfaces"; +import { StepperMessages } from "./components/stepper/assets/stepper/t9n"; +import { StepperItemMessages } from "./components/stepper-item/assets/stepper-item/t9n"; import { TabID, TabLayout, TabPosition } from "./components/tabs/interfaces"; +import { TabNavMessages } from "./components/tab-nav/assets/tab-nav/t9n"; import { TabChangeEventDetail, TabCloseEventDetail } from "./components/tab/interfaces"; +import { TabTitleMessages } from "./components/tab-title/assets/tab-title/t9n"; import { RowType, TableInteractionMode, TableLayout, TableRowFocusEvent, TableSelectionDisplay } from "./components/table/interfaces"; +import { TableMessages } from "./components/table/assets/table/t9n"; +import { TableCellMessages } from "./components/table-cell/assets/table-cell/t9n"; +import { TableHeaderMessages } from "./components/table-header/assets/table-header/t9n"; +import { TextAreaMessages } from "./components/text-area/assets/text-area/t9n"; import { TileSelectType } from "./components/tile-select/interfaces"; import { TileSelectGroupLayout } from "./components/tile-select-group/interfaces"; +import { TipMessages } from "./components/tip/assets/tip/t9n"; +import { TipManagerMessages } from "./components/tip-manager/assets/tip-manager/t9n"; import { TreeItemSelectDetail } from "./components/tree-item/interfaces"; +import { ValueListMessages } from "./components/value-list/assets/value-list/t9n"; import { ListItemAndHandle } from "./components/value-list-item/interfaces"; export { Alignment, Appearance, Columns, FlipContext, Kind, Layout, LogicalFlowPosition, Position, Scale, SelectionAppearance as SelectionAppearance1, SelectionMode, Status, Width } from "./components/interfaces"; export { RequestedItem } from "./components/accordion/interfaces"; export { RequestedItem as RequestedItem1 } from "./components/accordion-item/interfaces"; +export { ActionMessages } from "./components/action/assets/action/t9n"; export { EffectivePlacement, LogicalPlacement, MenuPlacement, OverlayPositioning, ReferenceElement } from "./utils/floating-ui"; +export { ActionBarMessages } from "./components/action-bar/assets/action-bar/t9n"; +export { ActionGroupMessages } from "./components/action-group/assets/action-group/t9n"; +export { ActionPadMessages } from "./components/action-pad/assets/action-pad/t9n"; export { AlertDuration, Sync } from "./components/alert/interfaces"; export { NumberingSystem } from "./utils/locale"; +export { AlertMessages } from "./components/alert/assets/alert/t9n"; export { HeadingLevel } from "./components/functional/Heading"; +export { BlockMessages } from "./components/block/assets/block/t9n"; export { BlockSectionToggleDisplay } from "./components/block-section/interfaces"; +export { BlockSectionMessages } from "./components/block-section/assets/block-section/t9n"; export { ButtonAlignment, DropdownIconType } from "./components/button/interfaces"; +export { ButtonMessages } from "./components/button/assets/button/t9n"; +export { CardMessages } from "./components/card/assets/card/t9n"; export { ArrowType, AutoplayType } from "./components/carousel/interfaces"; +export { CarouselMessages } from "./components/carousel/assets/carousel/t9n"; export { MutableValidityState } from "./utils/form"; +export { ChipMessages } from "./components/chip/assets/chip/t9n"; export { ColorValue, InternalColor } from "./components/color-picker/interfaces"; export { Format } from "./components/color-picker/utils"; +export { ColorPickerMessages } from "./components/color-picker/assets/color-picker/t9n"; export { ComboboxChildElement, SelectionDisplay } from "./components/combobox/interfaces"; +export { ComboboxMessages } from "./components/combobox/assets/combobox/t9n"; +export { DatePickerMessages } from "./components/date-picker/assets/date-picker/t9n"; export { DateLocaleData } from "./components/date-picker/utils"; export { HoverRange } from "./utils/date"; export { RequestedItem as RequestedItem2 } from "./components/dropdown-group/interfaces"; export { ItemKeyboardEvent } from "./components/dropdown/interfaces"; +export { FilterMessages } from "./components/filter/assets/filter/t9n"; export { FlowItemLikeElement } from "./components/flow/interfaces"; +export { FlowItemMessages } from "./components/flow-item/assets/flow-item/t9n"; export { ColorStop, DataSeries } from "./components/graph/interfaces"; +export { HandleMessages } from "./components/handle/assets/handle/t9n"; export { HandleChange, HandleNudge } from "./components/handle/interfaces"; +export { InlineEditableMessages } from "./components/inline-editable/assets/inline-editable/t9n"; export { InputPlacement } from "./components/input/interfaces"; +export { InputMessages } from "./components/input/assets/input/t9n"; +export { InputDatePickerMessages } from "./components/input-date-picker/assets/input-date-picker/t9n"; +export { InputNumberMessages } from "./components/input-number/assets/input-number/t9n"; +export { InputTextMessages } from "./components/input-text/assets/input-text/t9n"; +export { InputTimePickerMessages } from "./components/input-time-picker/assets/input-time-picker/t9n"; +export { TimePickerMessages } from "./components/time-picker/assets/time-picker/t9n"; +export { InputTimeZoneMessages } from "./components/input-time-zone/assets/input-time-zone/t9n"; export { TimeZoneMode } from "./components/input-time-zone/interfaces"; export { ListDragDetail } from "./components/list/interfaces"; export { ItemData } from "./components/list-item/interfaces"; +export { ListMessages } from "./components/list/assets/list/t9n"; export { SelectionAppearance } from "./components/list/resources"; +export { ListItemMessages } from "./components/list-item/assets/list-item/t9n"; +export { MenuMessages } from "./components/menu/assets/menu/t9n"; +export { MenuItemMessages } from "./components/menu-item/assets/menu-item/t9n"; export { MenuItemCustomEvent } from "./components/menu-item/interfaces"; export { MeterLabelType } from "./components/meter/interfaces"; +export { ModalMessages } from "./components/modal/assets/modal/t9n"; +export { NoticeMessages } from "./components/notice/assets/notice/t9n"; +export { PaginationMessages } from "./components/pagination/assets/pagination/t9n"; +export { PanelMessages } from "./components/panel/assets/panel/t9n"; export { ItemData as ItemData1, ListFocusId } from "./components/pick-list/shared-list-logic"; export { ICON_TYPES } from "./components/pick-list/resources"; +export { PickListItemMessages } from "./components/pick-list-item/assets/pick-list-item/t9n"; +export { PopoverMessages } from "./components/popover/assets/popover/t9n"; +export { RatingMessages } from "./components/rating/assets/rating/t9n"; +export { ScrimMessages } from "./components/scrim/assets/scrim/t9n"; export { DisplayMode } from "./components/sheet/interfaces"; export { DisplayMode as DisplayMode1 } from "./components/shell-panel/interfaces"; +export { ShellPanelMessages } from "./components/shell-panel/assets/shell-panel/t9n"; export { DragDetail } from "./utils/sortableComponent"; export { StepperItemChangeEventDetail, StepperItemEventDetail, StepperItemKeyEventDetail, StepperLayout } from "./components/stepper/interfaces"; +export { StepperMessages } from "./components/stepper/assets/stepper/t9n"; +export { StepperItemMessages } from "./components/stepper-item/assets/stepper-item/t9n"; export { TabID, TabLayout, TabPosition } from "./components/tabs/interfaces"; +export { TabNavMessages } from "./components/tab-nav/assets/tab-nav/t9n"; export { TabChangeEventDetail, TabCloseEventDetail } from "./components/tab/interfaces"; +export { TabTitleMessages } from "./components/tab-title/assets/tab-title/t9n"; export { RowType, TableInteractionMode, TableLayout, TableRowFocusEvent, TableSelectionDisplay } from "./components/table/interfaces"; +export { TableMessages } from "./components/table/assets/table/t9n"; +export { TableCellMessages } from "./components/table-cell/assets/table-cell/t9n"; +export { TableHeaderMessages } from "./components/table-header/assets/table-header/t9n"; +export { TextAreaMessages } from "./components/text-area/assets/text-area/t9n"; export { TileSelectType } from "./components/tile-select/interfaces"; export { TileSelectGroupLayout } from "./components/tile-select-group/interfaces"; +export { TipMessages } from "./components/tip/assets/tip/t9n"; +export { TipManagerMessages } from "./components/tip-manager/assets/tip-manager/t9n"; export { TreeItemSelectDetail } from "./components/tree-item/interfaces"; +export { ValueListMessages } from "./components/value-list/assets/value-list/t9n"; export { ListItemAndHandle } from "./components/value-list-item/interfaces"; export namespace Components { interface CalciteAccordion { diff --git a/packages/calcite-components/src/utils/component.spec.ts b/packages/calcite-components/src/utils/component.spec.ts index d9eff1c9cff..1da2e509873 100644 --- a/packages/calcite-components/src/utils/component.spec.ts +++ b/packages/calcite-components/src/utils/component.spec.ts @@ -1,7 +1,6 @@ import { HTMLStencilElement } from "@stencil/core/internal"; import { html } from "../../support/formatting"; -import * as componentUtils from "./component"; -const { componentFocusable, componentOnReady, getIconScale } = componentUtils; +import { componentOnReady, getIconScale } from "./component"; describe("getIconScale", () => { it('should return "m" when input is "l"', () => { @@ -19,7 +18,7 @@ describe("componentOnReady", () => { let fakeComponent: HTMLElement; beforeEach(() => { - document.body.innerHTML = html` `; + document.body.innerHTML = html` `; fakeComponent = document.querySelector("fake-component"); const originalRaf = globalThis.requestAnimationFrame; @@ -50,47 +49,3 @@ describe("componentOnReady", () => { expect(requestAnimationFrameSpy).toHaveBeenCalled(); }); }); - -describe("componentFocusable", () => { - let componentOnReadyStub: jest.SpyInstance; - let fakeComponent: HTMLStencilElement; - let forceUpdateSpy: jest.SpyInstance; - let requestAnimationFrameSpy: jest.SpyInstance; - let componentOnReadyResolver: (el: HTMLStencilElement) => void; - - beforeEach(async () => { - document.body.innerHTML = html` `; - fakeComponent = document.querySelector("fake-component"); - - const componentOnReadyPromise = new Promise( - (resolve: (el: HTMLStencilElement) => void) => (componentOnReadyResolver = resolve), - ); - componentOnReadyStub = fakeComponent.componentOnReady = jest.fn(() => componentOnReadyPromise); - forceUpdateSpy = jest.spyOn(componentUtils, "forceUpdate").mockImplementation(jest.fn()); - - const originalRaf = globalThis.requestAnimationFrame; - requestAnimationFrameSpy = jest - .spyOn(globalThis, "requestAnimationFrame") - .mockImplementation((callback) => originalRaf(callback)); - }); - - afterEach(() => { - requestAnimationFrameSpy.mockRestore(); - forceUpdateSpy.mockRestore(); - }); - - it("should resolve when ready and rendered", async () => { - const promise = componentFocusable(fakeComponent); - expect(promise).toBeInstanceOf(Promise); - - expect(componentOnReadyStub).toHaveBeenCalled(); - expect(requestAnimationFrameSpy).not.toHaveBeenCalled(); - expect(forceUpdateSpy).not.toHaveBeenCalled(); - - componentOnReadyResolver(fakeComponent); - await promise; - - expect(forceUpdateSpy).toHaveBeenCalled(); - expect(requestAnimationFrameSpy).toHaveBeenCalled(); - }); -}); diff --git a/packages/calcite-components/src/utils/component.ts b/packages/calcite-components/src/utils/component.ts index 62afbfd1aa4..160b4d3cf4d 100644 --- a/packages/calcite-components/src/utils/component.ts +++ b/packages/calcite-components/src/utils/component.ts @@ -1,4 +1,3 @@ -import { Build, forceUpdate as stencilForceUpdate } from "@stencil/core"; import { HTMLStencilElement } from "@stencil/core/internal"; import { Scale } from "../components/interfaces"; @@ -22,40 +21,3 @@ export async function componentOnReady(el: HTMLElement): Promise { function isStencilEl(el: HTMLElement): el is HTMLStencilElement { return typeof (el as HTMLStencilElement).componentOnReady === "function"; } - -/** - * Exported for testing purposes only. - * - * @internal - */ -export const forceUpdate = Build.isTesting - ? stencilForceUpdate - : () => { - /* noop */ - }; - -/** - * This helper util can be used to ensuring the component is loaded and rendered by the browser (The "componentDidLoad" Stencil lifecycle method has been called and any internal elements are focusable). - * - * A component developer can await this method before proceeding with any logic that requires a component to be loaded first and then an internal element be focused. - * - * ``` - * async setFocus(): Promise { - * await componentFocusable(this); - * this.internalElement?.focus(); - * } - * ``` - * - * @param el the component's host element - * @returns Promise - */ -export async function componentFocusable(el: HTMLElement): Promise { - await componentOnReady(el); - - if (!Build.isBrowser && !Build.isTesting) { - return; - } - - forceUpdate(el); - return new Promise((resolve) => requestAnimationFrame(() => resolve())); -} diff --git a/packages/calcite-components/src/utils/loadable.ts b/packages/calcite-components/src/utils/loadable.ts index d72c194019b..00f2f774408 100644 --- a/packages/calcite-components/src/utils/loadable.ts +++ b/packages/calcite-components/src/utils/loadable.ts @@ -1,4 +1,4 @@ -import { componentFocusable as componentFocusableReplacement } from "./component"; +import { Build, forceUpdate } from "@stencil/core"; /** * This helper adds support for knowing when a component has been loaded. @@ -37,22 +37,15 @@ import { componentFocusable as componentFocusableReplacement } from "./component * await componentLoaded(this); * } * ``` - * - * @deprecated use `componentOnReady` from `components.ts` instead. */ export interface LoadableComponent { - /** - * The host element. - */ - el: HTMLElement; - /** * Stencil lifecycle method. * https://stenciljs.com/docs/component-lifecycle#componentwillload * * Called once just after the component is first connected to the DOM. Since this method is only called once, it's a good place to load data asynchronously and to setup the state without triggering extra re-renders. */ - componentWillLoad?: () => Promise | void; + componentWillLoad: () => Promise | void; /** * Stencil lifecycle method. @@ -60,7 +53,7 @@ export interface LoadableComponent { * * Called once just after the component is fully loaded and the first render() occurs. */ - componentDidLoad?: () => Promise | void; + componentDidLoad: () => Promise | void; } const resolveMap = new WeakMap) => void>(); @@ -79,8 +72,6 @@ const promiseMap = new WeakMap>(); * ``` * * @param component - * - * @deprecated use `componentOnReady` from `components.ts` instead. */ export function setUpLoadableComponent(component: LoadableComponent): void { promiseMap.set(component, new Promise((resolve) => resolveMap.set(component, resolve))); @@ -98,8 +89,6 @@ export function setUpLoadableComponent(component: LoadableComponent): void { * ``` * * @param component - * - * @deprecated use `componentOnReady` from `components.ts` instead. */ export function setComponentLoaded(component: LoadableComponent): void { resolveMap.get(component)(); @@ -120,8 +109,6 @@ export function setComponentLoaded(component: LoadableComponent): void { * * @param component * @returns Promise - * - * @deprecated use `componentOnReady` from `components.ts` instead. */ export function componentLoaded(component: LoadableComponent): Promise { return promiseMap.get(component); @@ -143,9 +130,14 @@ export function componentLoaded(component: LoadableComponent): Promise { * * @param component * @returns Promise - * - * @deprecated use `componentFocusable` from `components.ts` instead. */ export async function componentFocusable(component: LoadableComponent): Promise { - await componentFocusableReplacement(component.el); + await componentLoaded(component); + + if (!Build.isBrowser) { + return; + } + + forceUpdate(component); + return new Promise((resolve) => requestAnimationFrame(() => resolve())); }