From e5936f837fab086b63cf2fc9347030c542d60c9b Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Tue, 16 May 2023 13:41:49 -0400 Subject: [PATCH 1/6] [core] fix: backwards-compatibility of Toaster type --- packages/core/src/components/toast/toaster.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/src/components/toast/toaster.tsx b/packages/core/src/components/toast/toaster.tsx index 0ddc83e720d..1986b84c531 100644 --- a/packages/core/src/components/toast/toaster.tsx +++ b/packages/core/src/components/toast/toaster.tsx @@ -275,8 +275,9 @@ export class OverlayToaster /** @deprecated use the new, more specific component name `OverlayToaster` instead (forwards-compatible with v5) */ export const Toaster = OverlayToaster; /** @deprecated use the new, more specific type `ToasterInstance` instead (forwards-compatible with v5) */ +// N.B. we use the type of the whole OverlayToaster class instead of only ToasterInstance here, for backcompat // eslint-disable-next-line @typescript-eslint/no-redeclare -export type Toaster = ToasterInstance; +export type Toaster = typeof OverlayToaster; // eslint-disable-next-line deprecation/deprecation Toaster.displayName = `${DISPLAYNAME_PREFIX}.Toaster`; /** @deprecated use `OverlayToasterProps` instead */ From 6b5d4236f532eb654a80dce44cac2d6c9f4627e7 Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Tue, 16 May 2023 14:20:10 -0400 Subject: [PATCH 2/6] adjust type --- packages/core/src/components/toast/toaster.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/components/toast/toaster.tsx b/packages/core/src/components/toast/toaster.tsx index 1986b84c531..b301b30f7da 100644 --- a/packages/core/src/components/toast/toaster.tsx +++ b/packages/core/src/components/toast/toaster.tsx @@ -277,7 +277,7 @@ export const Toaster = OverlayToaster; /** @deprecated use the new, more specific type `ToasterInstance` instead (forwards-compatible with v5) */ // N.B. we use the type of the whole OverlayToaster class instead of only ToasterInstance here, for backcompat // eslint-disable-next-line @typescript-eslint/no-redeclare -export type Toaster = typeof OverlayToaster; +export type Toaster = AbstractPureComponent2 & ToasterInstance; // eslint-disable-next-line deprecation/deprecation Toaster.displayName = `${DISPLAYNAME_PREFIX}.Toaster`; /** @deprecated use `OverlayToasterProps` instead */ From 891552a7b935ae84442c121e2097b3d56c40934a Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Tue, 16 May 2023 23:54:17 -0400 Subject: [PATCH 3/6] adjust type again, add regresison test --- packages/core/src/components/toast/toaster.tsx | 3 +-- packages/core/test/toast/toasterTests.tsx | 10 +++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/core/src/components/toast/toaster.tsx b/packages/core/src/components/toast/toaster.tsx index b301b30f7da..69bfd3c678c 100644 --- a/packages/core/src/components/toast/toaster.tsx +++ b/packages/core/src/components/toast/toaster.tsx @@ -275,9 +275,8 @@ export class OverlayToaster /** @deprecated use the new, more specific component name `OverlayToaster` instead (forwards-compatible with v5) */ export const Toaster = OverlayToaster; /** @deprecated use the new, more specific type `ToasterInstance` instead (forwards-compatible with v5) */ -// N.B. we use the type of the whole OverlayToaster class instead of only ToasterInstance here, for backcompat // eslint-disable-next-line @typescript-eslint/no-redeclare -export type Toaster = AbstractPureComponent2 & ToasterInstance; +export type Toaster = OverlayToaster; // eslint-disable-next-line deprecation/deprecation Toaster.displayName = `${DISPLAYNAME_PREFIX}.Toaster`; /** @deprecated use `OverlayToasterProps` instead */ diff --git a/packages/core/test/toast/toasterTests.tsx b/packages/core/test/toast/toasterTests.tsx index c3b83bdb78a..0e90a3d2895 100644 --- a/packages/core/test/toast/toasterTests.tsx +++ b/packages/core/test/toast/toasterTests.tsx @@ -22,7 +22,7 @@ import { spy } from "sinon"; import { expectPropValidationError } from "@blueprintjs/test-commons"; -import { Classes, OverlayToaster, ToasterInstance } from "../../src"; +import { Classes, OverlayToaster, Toaster, ToasterInstance } from "../../src"; import { TOASTER_CREATE_NULL, TOASTER_MAX_TOASTS_INVALID } from "../../src/common/errors"; describe("OverlayToaster", () => { @@ -187,4 +187,12 @@ describe("OverlayToaster", () => { } mount(React.createElement(LifecycleToaster)); }); + + // this type compatibility test can be removed in Blueprint v5.0 + it("ref is backwards-compatible with (deprecated) Toaster type", () => { + // N.B. without `export type Toaster = ...`, the following `Toaster` reference will be invalid + const deprecatedToasterRef = React.createRef(); + // N.B. `Toaster` type needs to be identical to the `OverlayToaster` type for this ref to type check properly + mount(); + }); }); From 4824b2e9e5fcce97895a84c2f0d2cff1eab6bd0f Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Wed, 17 May 2023 00:19:43 -0400 Subject: [PATCH 4/6] distinguish between ref callbacks and objects --- packages/core/src/components/toast/toast.md | 2 +- packages/core/src/components/toast/toaster.tsx | 4 +--- packages/core/test/toast/toasterTests.tsx | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/core/src/components/toast/toast.md b/packages/core/src/components/toast/toast.md index 7f56dfac68f..0b7b9205b7f 100644 --- a/packages/core/src/components/toast/toast.md +++ b/packages/core/src/components/toast/toast.md @@ -32,7 +32,7 @@ There are three ways to use __OverlayToaster__: 1. `OverlayToaster.create(props)` static method returns a new `ToasterInstance` instance. Use the instance method `toaster.show()` to manipulate this instance. __(recommended)__ 1. `...`: Render a `` element with React `children`. -1. ` ref.show({ ...toast })} />`: Render a `` element and use the `ref` prop to access its instance methods. +1. ` ref.show({ ...toast })} />`: Render a `` element and use a `ref` callback to access its instance methods. Note that if you use a ref object, you will have to use the more specific `OverlayToaster` type (e.g. `const myToaster = React.createRef()`).
Working with multiple toasters
diff --git a/packages/core/src/components/toast/toaster.tsx b/packages/core/src/components/toast/toaster.tsx index 69bfd3c678c..8ca6db42b9c 100644 --- a/packages/core/src/components/toast/toaster.tsx +++ b/packages/core/src/components/toast/toaster.tsx @@ -145,7 +145,7 @@ export class OverlayToaster const toaster = ReactDOM.render( , containerElement, - ) as OverlayToaster; + ) as OverlayToaster as ToasterInstance; if (toaster == null) { throw new Error(TOASTER_CREATE_NULL); } @@ -277,7 +277,5 @@ export const Toaster = OverlayToaster; /** @deprecated use the new, more specific type `ToasterInstance` instead (forwards-compatible with v5) */ // eslint-disable-next-line @typescript-eslint/no-redeclare export type Toaster = OverlayToaster; -// eslint-disable-next-line deprecation/deprecation -Toaster.displayName = `${DISPLAYNAME_PREFIX}.Toaster`; /** @deprecated use `OverlayToasterProps` instead */ export type IToasterProps = OverlayToasterProps; diff --git a/packages/core/test/toast/toasterTests.tsx b/packages/core/test/toast/toasterTests.tsx index 0e90a3d2895..af2845430f2 100644 --- a/packages/core/test/toast/toasterTests.tsx +++ b/packages/core/test/toast/toasterTests.tsx @@ -188,6 +188,24 @@ describe("OverlayToaster", () => { mount(React.createElement(LifecycleToaster)); }); + it("ref callback is assignable to ToasterInstance", () => { + const handleToasterRef = (_toaster: ToasterInstance | null) => { + /* no-op */ + }; + const refSpy = spy(handleToasterRef); + mount(); + assert.isTrue(refSpy.calledOnce); + }); + + it("ref object is assignable to OverlayToaster", () => { + const toasterInstance = React.createRef(); + const overlayToaster = React.createRef(); + // @ts-expect-error + const invalidToaster = ; + mount(); + assert.isDefined(overlayToaster.current); + }); + // this type compatibility test can be removed in Blueprint v5.0 it("ref is backwards-compatible with (deprecated) Toaster type", () => { // N.B. without `export type Toaster = ...`, the following `Toaster` reference will be invalid From 8015fa8e84d51b1236a77b6e9c82a9d3eea3d045 Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Wed, 17 May 2023 00:34:59 -0400 Subject: [PATCH 5/6] update docs --- packages/core/src/components/toast/toast.md | 32 +++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/packages/core/src/components/toast/toast.md b/packages/core/src/components/toast/toast.md index 0b7b9205b7f..02e8b911e54 100644 --- a/packages/core/src/components/toast/toast.md +++ b/packages/core/src/components/toast/toast.md @@ -23,16 +23,38 @@ You can also apply the same visual intent styles to `Toast`s that you can to [`B @### OverlayToaster -The __OverlayToaster__ component is a stateful container for a single list of toasts. Internally, it -uses the [Overlay](#core/components/overlay) component to manage children and transitions. It can be vertically +The __OverlayToaster__ component (previously named __Toaster__) is a stateful container for a single list of toasts. +Internally, it uses [__Overlay__](#core/components/overlay) to manage children and transitions. It can be vertically aligned along the top or bottom edge of its container (new toasts will slide in from that edge) and horizontally aligned along the left edge, center, or right edge of its container. There are three ways to use __OverlayToaster__: -1. `OverlayToaster.create(props)` static method returns a new `ToasterInstance` instance. Use the instance method `toaster.show()` to manipulate this instance. __(recommended)__ -1. `...`: Render a `` element with React `children`. -1. ` ref.show({ ...toast })} />`: Render a `` element and use a `ref` callback to access its instance methods. Note that if you use a ref object, you will have to use the more specific `OverlayToaster` type (e.g. `const myToaster = React.createRef()`). +1. __Recommended__: use the `OverlayToaster.create()` static method to access a new `ToasterInstance`: + ```ts + const myToaster: ToasterInstance = OverlayToaster.create({ position: "bottom" }); + myToaster.show({ ...toastOptions }); + ``` +2. Render an `` with `` children: + ```ts + render( + + + , + targetElement, + ); + ``` +3. Use a ref callback or object to access toaster instance methods. + - Example with ref callback: + ```ts + render( ref.show({ ...toastOptions })} />, targetElement); + ``` + - Example with ref object (note that React type constraints require us to use the more specific `OverlayToaster` type): + ```ts + const myToaster = React.createRef(); + render(, targetElement); + myToaster.current?.show({ ...toastOptions }); + ```
Working with multiple toasters
From 132e1a56905b69b4bbdafc09d03bc344e201ad79 Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Wed, 17 May 2023 00:41:26 -0400 Subject: [PATCH 6/6] fix code example, add one test --- packages/core/src/components/toast/toast.md | 2 +- packages/core/test/toast/toasterTests.tsx | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/core/src/components/toast/toast.md b/packages/core/src/components/toast/toast.md index 02e8b911e54..abf1612d67f 100644 --- a/packages/core/src/components/toast/toast.md +++ b/packages/core/src/components/toast/toast.md @@ -47,7 +47,7 @@ There are three ways to use __OverlayToaster__: 3. Use a ref callback or object to access toaster instance methods. - Example with ref callback: ```ts - render( ref.show({ ...toastOptions })} />, targetElement); + render( ref?.show({ ...toastOptions })} />, targetElement); ``` - Example with ref object (note that React type constraints require us to use the more specific `OverlayToaster` type): ```ts diff --git a/packages/core/test/toast/toasterTests.tsx b/packages/core/test/toast/toasterTests.tsx index af2845430f2..927b64f8a7e 100644 --- a/packages/core/test/toast/toasterTests.tsx +++ b/packages/core/test/toast/toasterTests.tsx @@ -207,10 +207,21 @@ describe("OverlayToaster", () => { }); // this type compatibility test can be removed in Blueprint v5.0 - it("ref is backwards-compatible with (deprecated) Toaster type", () => { + it(" ref callback is backwards-compatible with (deprecated) Toaster type", () => { // N.B. without `export type Toaster = ...`, the following `Toaster` reference will be invalid const deprecatedToasterRef = React.createRef(); // N.B. `Toaster` type needs to be identical to the `OverlayToaster` type for this ref to type check properly mount(); }); + + // this type compatibility test can be removed in Blueprint v5.0 + it(" ref callback is compatible with ToasterInstance type", () => { + mount( + { + /* no-op */ + }} + />, + ); + }); });