Skip to content

Commit e521255

Browse files
feat(react,js): improve ActiveBlock TS type (#683)
* feat(react,js): improve ActiveBlock TS type * feat: docs and stuff --------- Co-authored-by: Ondřej Pešička <77627332+OPesicka@users.noreply.github.com>
1 parent f144bef commit e521255

4 files changed

Lines changed: 89 additions & 13 deletions

File tree

workspaces/js/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
export type {
22
Action,
33
ActiveBlock,
4+
ComponentActiveBlock,
5+
TourComponentActiveBlock,
6+
SurveyActiveBlock,
47
BlockState,
58
FlowsProperties,
69
StateMemory,

workspaces/react/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
export type {
22
Action,
33
ActiveBlock,
4+
ComponentActiveBlock,
5+
TourComponentActiveBlock,
6+
SurveyActiveBlock,
47
BlockState,
58
FlowsProperties,
69
StateMemory,

workspaces/react/src/lib/active-block.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export const blockToActiveBlock = ({
8484

8585
const activeBlock: ActiveBlock = {
8686
id: block.id,
87-
type: block.type as ActiveBlock["type"],
87+
type: block.type,
8888
component: block.componentType,
8989
props,
9090
};

workspaces/shared/src/types/active-block.ts

Lines changed: 82 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,97 @@
1-
import { type FlowsProperties } from "./components";
1+
import type {
2+
FlowsProperties,
3+
ComponentProps,
4+
SurveyComponentProps,
5+
TourComponentProps,
6+
} from "./components";
27

3-
export interface ActiveBlock {
8+
type ActiveBlockBase<T extends string, P extends { __flows: FlowsProperties }> = {
49
/**
5-
* Unique identifier of the block, useful for stable key during rendering. Keep in mind each workflow version will have a different id for each block.
10+
* Unique identifier of the block. Useful as a stable `key` during rendering.
11+
*
12+
* Note: each workflow version assigns different ids to each block, so this value changes on workflow publish.
613
*/
714
id: string;
815
/**
9-
* Unique identifier of the tour block this tour-component belongs to. Keep in mind each workflow version will have a different id for each block.
16+
* Discriminant that identifies the block variant. Use this to narrow the type and access type-safe `props`.
17+
*
18+
* - `"component"` — a standalone workflow block
19+
* - `"tour-component"` — a single step within a tour
20+
* - `"survey"` — a survey block
1021
*/
11-
tourBlockId?: string;
22+
type: T;
1223
/**
13-
* Type of the block, either "component" or "tour-component" or "survey".
24+
* The key of the registered UI component used to render this block.
25+
* Must match a key registered in `FlowsProvider` (React) or `init` (JS).
1426
*/
15-
type: "component" | "tour-component" | "survey";
27+
component: string;
1628
/**
17-
* The UI Component used to render this block.
29+
* Props to pass to the component. The exact shape depends on the block `type`:
30+
*
31+
* - `"component"` → `ComponentProps`
32+
* - `"tour-component"` → `TourComponentProps` — includes `continue`, `previous?`, and `cancel`
33+
* - `"survey"` → `SurveyComponentProps` — includes `survey`, `complete`, and `cancel`
1834
*/
19-
component: string;
35+
props: P;
36+
};
37+
38+
/**
39+
* An `ActiveBlock` representing a standalone workflow component block.
40+
*
41+
* Narrow to this type by checking `block.type === "component"`.
42+
*/
43+
export type ComponentActiveBlock = ActiveBlockBase<
44+
"component",
45+
ComponentProps<Record<string, unknown>>
46+
>;
47+
48+
/**
49+
* An `ActiveBlock` representing a single step within a tour.
50+
*
51+
* Narrow to this type by checking `block.type === "tour-component"`.
52+
*/
53+
export type TourComponentActiveBlock = ActiveBlockBase<
54+
"tour-component",
55+
TourComponentProps<Record<string, unknown>>
56+
> & {
2057
/**
21-
* Props to be passed to the component including both data and exit node methods.
58+
* Unique identifier of the parent tour block this step belongs to. Useful as a stable `key` during rendering.
59+
*
60+
* Prefer this over `id` when rendering tour steps — reusing the same key across steps lets the browser
61+
* reuse the DOM element rather than unmounting and remounting it between individual steps.
62+
*
63+
* Note: each workflow version assigns different ids to each block, so this value changes on workflow publish.
2264
*/
23-
props: { __flows: FlowsProperties } & Record<string, unknown>;
24-
}
65+
tourBlockId?: string;
66+
};
67+
68+
/**
69+
* An `ActiveBlock` representing a survey block.
70+
*
71+
* Narrow to this type by checking `block.type === "survey"`.
72+
*/
73+
export type SurveyActiveBlock = ActiveBlockBase<
74+
"survey",
75+
SurveyComponentProps<Record<string, unknown>>
76+
>;
77+
78+
/**
79+
* A block that is currently active and ready to render.
80+
*
81+
* Use `block.type` to narrow to a specific variant and access type-safe `props`:
82+
*
83+
* ```ts
84+
* if (block.type === "tour-component") {
85+
* // props is TourComponentProps — includes continue, previous?, cancel
86+
* block.props.continue();
87+
* }
88+
* ```
89+
*
90+
* @see {@link ComponentActiveBlock} for `"component"` blocks
91+
* @see {@link TourComponentActiveBlock} for `"tour-component"` blocks
92+
* @see {@link SurveyActiveBlock} for `"survey"` blocks
93+
*/
94+
export type ActiveBlock = ComponentActiveBlock | TourComponentActiveBlock | SurveyActiveBlock;
2595

2696
export const createActiveBlockProxy = (
2797
block: ActiveBlock,

0 commit comments

Comments
 (0)