slice-machine-ui 1.15.1-dev-next-release.0 → 1.15.1-dev-next-release.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/.storybook/preview.tsx +1 -5
  2. package/components/Forms/CreateCustomTypeModal/CreateCustomTypeModal.tsx +3 -0
  3. package/lib/builders/SliceBuilder/Header/SimulatorButton/index.tsx +3 -2
  4. package/out/404.html +1 -1
  5. package/out/[lib]/[sliceName]/[variation]/screenshot.html +1 -1
  6. package/out/[lib]/[sliceName]/[variation]/simulator.html +1 -1
  7. package/out/[lib]/[sliceName]/[variation].html +1 -1
  8. package/out/_next/static/chunks/113-34b6cf41a62f08ce.js +3 -0
  9. package/out/_next/static/chunks/{740-d0642219804fa9f0.js → 125-84464edfe25651eb.js} +3 -3
  10. package/out/_next/static/chunks/18539003-1bb05c8aa7db2bc2.js +97 -0
  11. package/out/_next/static/chunks/{377-870ca4414847069f.js → 377-3caacee3c3ffdc25.js} +1 -1
  12. package/out/_next/static/chunks/{573-aaae870d20e5f86c.js → 573-e92018662d1f6c26.js} +1 -1
  13. package/out/_next/static/chunks/746-2ca4784811bde7c1.js +8 -0
  14. package/out/_next/static/chunks/{799-5ea3393033a9f617.js → 799-5c13484e9f945e5d.js} +1 -1
  15. package/out/_next/static/chunks/809-d1f83d7413864f03.js +1 -0
  16. package/out/_next/static/chunks/840-d84a2655185995ce.js +1 -0
  17. package/out/_next/static/chunks/pages/[lib]/[sliceName]/[variation]/{simulator-4dcf33735c45c344.js → simulator-c608e0470a8f6099.js} +1 -1
  18. package/out/_next/static/chunks/pages/[lib]/[sliceName]/[variation]-36ba0bde8415ad8b.js +1 -0
  19. package/out/_next/static/chunks/pages/{_app-2e696c5146b70244.js → _app-0e270aca89a6033d.js} +98 -95
  20. package/out/_next/static/chunks/pages/{changelog-877e16d5731e1966.js → changelog-11c9e241f5a8a4cb.js} +1 -1
  21. package/out/_next/static/chunks/pages/{changes-b85f5f8b616f683f.js → changes-8338c9d0723a7033.js} +1 -1
  22. package/out/_next/static/chunks/pages/custom-types/{[customTypeId]-4fe86acfed194773.js → [customTypeId]-868f09f50fd3039a.js} +1 -1
  23. package/out/_next/static/chunks/pages/custom-types-78e57821222c9603.js +1 -0
  24. package/out/_next/static/chunks/pages/index-d3da65c8b508c26e.js +1 -0
  25. package/out/_next/static/chunks/pages/page-types/{[pageTypeId]-87f5f9704f2c3f2d.js → [pageTypeId]-b6552cab363f7fbf.js} +1 -1
  26. package/out/_next/static/chunks/pages/{slices-53cb97d901d15d93.js → slices-afa4b34df8f8e1c3.js} +1 -1
  27. package/out/_next/static/css/{d6e6d21ff661397d.css → 26b51745402a92af.css} +1 -1
  28. package/out/_next/static/css/66b3836ab88b0c5c.css +1 -0
  29. package/out/_next/static/css/{2d1eda18406a9ff4.css → b6bfe1e0ef76c2b1.css} +1 -1
  30. package/out/_next/static/z-OmqvYWKjvP9W4MN_LBy/_buildManifest.js +1 -0
  31. package/out/changelog.html +1 -1
  32. package/out/changes.html +1 -1
  33. package/out/custom-types/[customTypeId].html +1 -1
  34. package/out/custom-types.html +1 -1
  35. package/out/index.html +1 -1
  36. package/out/page-types/[pageTypeId].html +1 -1
  37. package/out/slices.html +1 -1
  38. package/package.json +8 -8
  39. package/pages/_app.tsx +37 -5
  40. package/pages/index.tsx +8 -0
  41. package/src/components/BaseHoverCard/BaseHoverCard.stories.tsx +1 -0
  42. package/src/components/Card/Card.css.ts +182 -0
  43. package/src/components/Card/Card.stories.tsx +166 -0
  44. package/src/components/Card/Card.tsx +171 -0
  45. package/src/components/Card/index.ts +1 -0
  46. package/src/components/HoverCard/HoverCard.stories.tsx +4 -0
  47. package/src/components/Table/Table.tsx +4 -14
  48. package/src/components/TextLink/TextLink.stories.tsx +2 -5
  49. package/src/components/Window/Window.tsx +8 -4
  50. package/src/features/customTypes/PageTypeOnboarding.tsx +60 -0
  51. package/src/features/customTypes/customTypesBuilder/SliceZoneBlankSlate.tsx +2 -2
  52. package/src/features/slices/sliceBuilder/FloatingBackButton.tsx +3 -13
  53. package/src/hooks/useIsEmptyProject.ts +24 -0
  54. package/src/icons/AddPhotoAlternateIcon.tsx +19 -0
  55. package/src/icons/ArrowDropDownIcon.tsx +14 -0
  56. package/src/icons/BlankPageIcon.tsx +58 -0
  57. package/src/icons/SliceMachinePrinterIcon.tsx +69 -0
  58. package/src/icons/SyncAltIcon.tsx +19 -0
  59. package/test/components/CreateCustomTypeModal.test.tsx +1 -0
  60. package/out/_next/static/WBN_4NBm93_gAe6XjcmpE/_buildManifest.js +0 -1
  61. package/out/_next/static/chunks/18539003-a714ba731c9448b9.js +0 -101
  62. package/out/_next/static/chunks/323-841ea6a21954aa7e.js +0 -1
  63. package/out/_next/static/chunks/482-cb5b635a7b32f4b0.js +0 -1
  64. package/out/_next/static/chunks/746-1d8d106d76d9a63e.js +0 -8
  65. package/out/_next/static/chunks/780-643ae720f13fb3dc.js +0 -1
  66. package/out/_next/static/chunks/pages/[lib]/[sliceName]/[variation]-e1c66b10113d656e.js +0 -1
  67. package/out/_next/static/chunks/pages/custom-types-abb8c8c92880120e.js +0 -1
  68. package/out/_next/static/chunks/pages/index-f382c8090bd21628.js +0 -1
  69. package/out/_next/static/css/fe2a2a1cbf3b4092.css +0 -1
  70. package/src/icons/LightningIcon3D.tsx +0 -49
  71. /package/out/_next/static/{WBN_4NBm93_gAe6XjcmpE → z-OmqvYWKjvP9W4MN_LBy}/_ssgManifest.js +0 -0
@@ -0,0 +1,182 @@
1
+ import { colors, selectors, sprinkles, vars } from "@prismicio/editor-ui";
2
+ import { style, styleVariants } from "@vanilla-extract/css";
3
+ import { calc } from "@vanilla-extract/css-utils";
4
+
5
+ const flex = sprinkles({ all: "unset", display: "flex" });
6
+
7
+ const column = style([flex, sprinkles({ flexDirection: "column" })]);
8
+
9
+ export const root = style([
10
+ column,
11
+ sprinkles({
12
+ borderColor: colors.grey6,
13
+ borderRadius: 6,
14
+ borderStyle: "solid",
15
+ borderWidth: 1,
16
+ boxSizing: "border-box",
17
+ overflowX: "hidden",
18
+ position: "relative",
19
+ }),
20
+ ]);
21
+
22
+ export const size = styleVariants({
23
+ small: { height: "240px" },
24
+ medium: { height: "320px" },
25
+ });
26
+
27
+ export const variant = styleVariants({
28
+ solid: [sprinkles({ backgroundColor: colors.grey3 })],
29
+ outlined: [sprinkles({ backgroundColor: colors.grey2 })],
30
+ });
31
+
32
+ export const interactive = style({
33
+ ":focus-visible": { boxShadow: "0px 0px 0px 4px hsla(251, 63%, 63%, 0.1)" },
34
+ selectors: {
35
+ "&[data-disabled]": { opacity: vars.opacity["50%"] },
36
+ "&:not([data-disabled])": { cursor: vars.cursor.pointer },
37
+ },
38
+ });
39
+
40
+ export const interactiveVariant = {
41
+ solid: sprinkles({
42
+ backgroundColor: selectors.focusVisible(colors.grey5),
43
+ borderColor: {
44
+ ...selectors.checked(colors.purple10),
45
+ ...selectors.focusVisible(colors.purple10),
46
+ },
47
+ }),
48
+ outlined: sprinkles({
49
+ backgroundColor: {
50
+ ...selectors.active(colors.grey4),
51
+ ...selectors.focusVisible(colors.grey1),
52
+ ...selectors.hover(colors.grey4),
53
+ },
54
+ borderColor: {
55
+ ...selectors.active(colors.purple9),
56
+ ...selectors.checked(colors.purple8),
57
+ ...selectors.focusVisible(colors.purple8),
58
+ },
59
+ }),
60
+ };
61
+
62
+ export const media = style([
63
+ column,
64
+ sprinkles({ flexBasis: 0, flexGrow: 1, minHeight: 0, position: "relative" }),
65
+ {
66
+ order: 0,
67
+ selectors: {
68
+ [`${variant.solid} > &`]: {
69
+ padding: calc.subtract(vars.space[32], vars.borderWidth[1]),
70
+ },
71
+ [`${variant.outlined} > &`]: {
72
+ backgroundColor: vars.color.greyLight3,
73
+ marginInline: calc.subtract(vars.space[16], vars.borderWidth[1]),
74
+ marginTop: calc.subtract(vars.space[16], vars.borderWidth[1]),
75
+ padding: vars.space[16],
76
+ },
77
+ },
78
+ },
79
+ ]);
80
+
81
+ const grid = sprinkles({ all: "unset", display: "grid" });
82
+
83
+ export const mediaComponent = styleVariants({
84
+ div: [grid, sprinkles({ flexGrow: 1 })],
85
+ img: [
86
+ sprinkles({ height: "100%", objectFit: "contain" }),
87
+ { selectors: { "&:not([src])": { visibility: "hidden" } } },
88
+ ],
89
+ });
90
+
91
+ export const mediaOverlay = style([
92
+ grid,
93
+ sprinkles({ inset: 0, position: "absolute", visibility: "hidden" }),
94
+ {
95
+ "::before": {
96
+ backgroundColor: vars.color.greyLight12,
97
+ content: "",
98
+ inset: vars.space[0],
99
+ opacity: vars.opacity["10%"],
100
+ position: "absolute",
101
+ },
102
+ selectors: {
103
+ [`${interactive}:focus-visible &, ${interactive}:not([data-disabled]) ${media}:hover > &`]:
104
+ { visibility: "visible" },
105
+ [`${interactive}:not([data-disabled]) &:has(:focus-visible)`]: {
106
+ visibility: "visible",
107
+ },
108
+ },
109
+ },
110
+ ]);
111
+
112
+ const nonMedia = style([
113
+ flex,
114
+ sprinkles({
115
+ alignItems: "center",
116
+ boxSizing: "border-box",
117
+ flexDirection: "row",
118
+ }),
119
+ {
120
+ selectors: {
121
+ [`${variant.solid} > &`]: { backgroundColor: vars.color.greyLight1 },
122
+ [`${variant.solid} > &:not(:first-child)`]: {
123
+ borderTopColor: vars.color.greyLight6,
124
+ borderTopStyle: "inherit",
125
+ borderTopWidth: "inherit",
126
+ },
127
+ },
128
+ },
129
+ ]);
130
+
131
+ export const actions = style([
132
+ nonMedia,
133
+ sprinkles({ height: 48, justifyContent: "space-between" }),
134
+ {
135
+ order: 1,
136
+ selectors: {
137
+ [`${variant.solid} > &`]: {
138
+ paddingLeft: calc.subtract(vars.space[12], vars.borderWidth[1]),
139
+ paddingRight: calc.subtract(vars.space[8], vars.borderWidth[1]),
140
+ },
141
+ [`${variant.outlined} > &`]: {
142
+ paddingInline: calc.subtract(vars.space[16], vars.borderWidth[1]),
143
+ },
144
+ },
145
+ },
146
+ ]);
147
+
148
+ export const footer = style([
149
+ nonMedia,
150
+ sprinkles({ gap: 8, height: 60 }),
151
+ {
152
+ order: 2,
153
+ selectors: {
154
+ [`${variant.solid} > &`]: {
155
+ paddingInline: calc.subtract(vars.space[12], vars.borderWidth[1]),
156
+ },
157
+ [`${variant.outlined} > &`]: {
158
+ paddingInline: calc.subtract(vars.space[16], vars.borderWidth[1]),
159
+ },
160
+ },
161
+ },
162
+ ]);
163
+
164
+ export const footerTexts = style([
165
+ column,
166
+ sprinkles({ flexBasis: 0, flexGrow: 1, minWidth: 0 }),
167
+ // Offset `title` and `subtitle` so that they are centered vertically despite
168
+ // having different line heights.
169
+ { marginBottom: `calc((${24 / 16}rem - ${16 / 16}rem) / 2)` },
170
+ ]);
171
+
172
+ export const status = style([
173
+ column,
174
+ sprinkles({
175
+ height: 24,
176
+ insetInline: 0,
177
+ justifyContent: "center",
178
+ paddingInline: 8,
179
+ position: "absolute",
180
+ }),
181
+ { backgroundColor: "hsl(251, 91%, 95%)", color: "hsl(250, 43%, 48%)" },
182
+ ]);
@@ -0,0 +1,166 @@
1
+ import {
2
+ Badge,
3
+ Box,
4
+ Button,
5
+ Checkbox,
6
+ IconButton,
7
+ Text,
8
+ tokens,
9
+ } from "@prismicio/editor-ui";
10
+ import type { Meta, StoryObj } from "@storybook/react";
11
+
12
+ import { AddPhotoAlternateIcon } from "@src/icons/AddPhotoAlternateIcon";
13
+ import { ArrowDropDownIcon } from "@src/icons/ArrowDropDownIcon";
14
+ import { SyncAltIcon } from "@src/icons/SyncAltIcon";
15
+
16
+ import { Card, CardActions, CardFooter, CardMedia, CardStatus } from "./Card";
17
+
18
+ type Story = StoryObj<typeof meta>;
19
+
20
+ const meta = {
21
+ component: Card,
22
+ argTypes: {
23
+ checked: { if: { arg: "interactive" } },
24
+ children: { control: { disable: true } },
25
+ component: { control: { disable: true }, if: { arg: "interactive" } },
26
+ disabled: { if: { arg: "interactive" } },
27
+ href: { if: { arg: "interactive" } },
28
+ onClick: { if: { arg: "interactive" } },
29
+ size: { control: "select", options: ["small", "medium"] },
30
+ variant: { control: "select", options: ["solid", "outlined"] },
31
+ },
32
+ } satisfies Meta<typeof Card>;
33
+
34
+ export default meta;
35
+
36
+ export const Default = {
37
+ args: {
38
+ children: (
39
+ <>
40
+ <CardMedia overlay={<></>} />
41
+ <CardActions />
42
+ <CardFooter
43
+ action={<Button variant="secondary">Action</Button>}
44
+ subtitle="Subtitle"
45
+ title="Title"
46
+ />
47
+ <CardStatus />
48
+ </>
49
+ ),
50
+ interactive: false,
51
+ size: "medium",
52
+ variant: "solid",
53
+ },
54
+ } satisfies Story;
55
+
56
+ export const SolidWithImg = {
57
+ args: {
58
+ ...Default.args,
59
+ children: (
60
+ <>
61
+ <CardMedia
62
+ overlay={
63
+ <Box alignItems="center" justifyContent="center">
64
+ <Button
65
+ renderStartIcon={() => (
66
+ <AddPhotoAlternateIcon color={tokens.color.greyLight11} />
67
+ )}
68
+ variant="secondary"
69
+ >
70
+ Update screenshot
71
+ </Button>
72
+ </Box>
73
+ }
74
+ src="https://images.unsplash.com/photo-1588315029754-2dd089d39a1a?w=512"
75
+ />
76
+ <CardFooter
77
+ action={<IconButton icon="close" />}
78
+ subtitle="Default • Edited 19 minutes ago"
79
+ title="Hello"
80
+ />
81
+ <CardStatus>Missing screenshot</CardStatus>
82
+ </>
83
+ ),
84
+ interactive: true,
85
+ style: { width: "448px" },
86
+ },
87
+ parameters: { controls: { hideNoControlsWarning: true, include: [] } },
88
+ } satisfies Story;
89
+
90
+ export const SolidWithDiv = {
91
+ args: {
92
+ ...SolidWithImg.args,
93
+ children: (
94
+ <>
95
+ <CardMedia component="div">
96
+ <Box alignItems="center" justifyContent="center">
97
+ <Text color="grey11" component="span">
98
+ No screenshot available
99
+ </Text>
100
+ </Box>
101
+ </CardMedia>
102
+ <CardActions>
103
+ <Badge color="purple" title="Legacy Slice" />
104
+ <Button
105
+ renderEndIcon={() => (
106
+ <ArrowDropDownIcon color={tokens.color.greyLight11} />
107
+ )}
108
+ renderStartIcon={() => (
109
+ <SyncAltIcon color={tokens.color.greyLight11} />
110
+ )}
111
+ variant="secondary"
112
+ >
113
+ Turn into shared Slice
114
+ </Button>
115
+ </CardActions>
116
+ <CardFooter subtitle="Default • Edited 19 minutes ago" title="Hello" />
117
+ </>
118
+ ),
119
+ interactive: false,
120
+ },
121
+ parameters: SolidWithImg.parameters,
122
+ } satisfies Story;
123
+
124
+ export const OutlinedWithImg = {
125
+ args: {
126
+ ...Default.args,
127
+ children: (
128
+ <>
129
+ <CardMedia src="https://images.unsplash.com/photo-1588315029754-2dd089d39a1a?w=512" />
130
+ <CardFooter
131
+ action={<Checkbox />}
132
+ subtitle="Library • Edited 19 minutes ago"
133
+ title="Name"
134
+ />
135
+ </>
136
+ ),
137
+ interactive: true,
138
+ size: "small",
139
+ style: { width: "320px" },
140
+ variant: "outlined",
141
+ },
142
+ parameters: { controls: { hideNoControlsWarning: true, include: [] } },
143
+ } satisfies Story;
144
+
145
+ export const OutlinedWithDiv = {
146
+ args: {
147
+ ...OutlinedWithImg.args,
148
+ children: (
149
+ <>
150
+ <CardMedia component="div">
151
+ <Box alignItems="center" justifyContent="center">
152
+ <Text color="grey11" component="span">
153
+ No screenshot available
154
+ </Text>
155
+ </Box>
156
+ </CardMedia>
157
+ <CardFooter
158
+ action={<Checkbox />}
159
+ subtitle="Library • Edited 19 minutes ago"
160
+ title="Name"
161
+ />
162
+ </>
163
+ ),
164
+ },
165
+ parameters: OutlinedWithImg.parameters,
166
+ } satisfies Story;
@@ -0,0 +1,171 @@
1
+ import { findFocusableAncestor } from "@prismicio/editor-support/DOM";
2
+ import { Text } from "@prismicio/editor-ui";
3
+ import { clsx } from "clsx";
4
+ import type { UrlObject } from "node:url";
5
+ import {
6
+ type CSSProperties,
7
+ type FC,
8
+ type HTMLAttributes,
9
+ type ImgHTMLAttributes,
10
+ type MouseEvent,
11
+ type PropsWithChildren,
12
+ type ReactNode,
13
+ createElement,
14
+ } from "react";
15
+
16
+ import * as styles from "./Card.css";
17
+
18
+ type CardProps = PropsWithChildren<
19
+ {
20
+ size?: keyof typeof styles.size;
21
+ style?: CSSProperties;
22
+ variant?: keyof typeof styles.variant;
23
+ } & (
24
+ | { interactive?: false }
25
+ | ({ interactive: true; href: string } & {
26
+ component?: "a" | FC<LinkProps>;
27
+ })
28
+ | ({ interactive: true; href?: undefined } & {
29
+ checked?: boolean;
30
+ disabled?: boolean;
31
+ onClick?: (event: MouseEvent) => void;
32
+ })
33
+ )
34
+ >;
35
+
36
+ type LinkProps = {
37
+ href: string | UrlObject;
38
+ onClick?: (event: MouseEvent) => void;
39
+ };
40
+
41
+ export const Card: FC<CardProps> = (props) => {
42
+ const { size = "medium", variant = "solid" } = props;
43
+ const elementProps = {
44
+ className: clsx(styles.root, styles.size[size], styles.variant[variant], {
45
+ [styles.interactive]: props.interactive,
46
+ [styles.interactiveVariant[variant]]: props.interactive,
47
+ }),
48
+ };
49
+ if (props.interactive === true && props.href === undefined) {
50
+ const {
51
+ size: _size,
52
+ variant: _variant,
53
+ interactive: _interactive,
54
+ checked,
55
+ disabled,
56
+ onClick,
57
+ ...otherProps
58
+ } = props;
59
+ return (
60
+ <div
61
+ {...otherProps}
62
+ {...elementProps}
63
+ // TODO: add missing ARIA attributes and keyboard event handlers.
64
+ data-disabled={disabled === true ? "" : undefined}
65
+ data-state={checked === true ? "checked" : undefined}
66
+ onClick={(event) => {
67
+ if (disabled === true || onClick === undefined) return;
68
+ const target = event.target as HTMLElement;
69
+ if (findFocusableAncestor(target) === event.currentTarget) {
70
+ onClick(event);
71
+ }
72
+ }}
73
+ tabIndex={disabled === true ? undefined : 0}
74
+ />
75
+ );
76
+ } else if (props.interactive === true) {
77
+ const {
78
+ size: _size,
79
+ variant: _variant,
80
+ interactive: _interactive,
81
+ component = "a",
82
+ ...otherProps
83
+ } = props;
84
+ return createElement(component, {
85
+ ...otherProps,
86
+ ...elementProps,
87
+ onClick: (event) => {
88
+ const target = event.target as HTMLElement;
89
+ if (findFocusableAncestor(target) !== event.currentTarget) {
90
+ event.preventDefault();
91
+ }
92
+ },
93
+ });
94
+ } else {
95
+ const {
96
+ size: _size,
97
+ variant: _variant,
98
+ interactive: _interactive,
99
+ ...otherProps
100
+ } = props;
101
+ return <div {...otherProps} {...elementProps} />;
102
+ }
103
+ };
104
+
105
+ type CardMediaProps = { overlay?: ReactNode } & (
106
+ | ({ component?: "img" } & ImgHTMLAttributes<HTMLImageElement>)
107
+ | ({ component: "div" } & HTMLAttributes<HTMLDivElement>)
108
+ );
109
+
110
+ export const CardMedia: FC<CardMediaProps> = ({
111
+ className,
112
+ component = "img",
113
+ overlay,
114
+ ...otherProps
115
+ }) => (
116
+ <div className={styles.media}>
117
+ {createElement(component, {
118
+ ...otherProps,
119
+ className: clsx(styles.mediaComponent[component], className),
120
+ })}
121
+ {Boolean(overlay) ? (
122
+ <div className={styles.mediaOverlay}>{overlay}</div>
123
+ ) : undefined}
124
+ </div>
125
+ );
126
+
127
+ export const CardActions: FC<PropsWithChildren> = (props) => (
128
+ <div {...props} className={styles.actions} />
129
+ );
130
+
131
+ type CardFooterProps = {
132
+ action?: ReactNode;
133
+ subtitle?: ReactNode;
134
+ title?: ReactNode;
135
+ };
136
+
137
+ export const CardFooter: FC<CardFooterProps> = ({
138
+ action,
139
+ subtitle,
140
+ title,
141
+ ...otherProps
142
+ }) => (
143
+ <div {...otherProps} className={styles.footer}>
144
+ <div className={styles.footerTexts}>
145
+ <Text component="span" noWrap variant="bold">
146
+ {title}
147
+ </Text>
148
+ <Text color="grey11" component="span" noWrap variant="small">
149
+ {subtitle}
150
+ </Text>
151
+ </div>
152
+ {action}
153
+ </div>
154
+ );
155
+
156
+ export const CardStatus: FC<PropsWithChildren> = ({
157
+ children,
158
+ ...otherProps
159
+ }) => (
160
+ <div {...otherProps} className={styles.status}>
161
+ <Text
162
+ align="center"
163
+ color="inherit"
164
+ component="span"
165
+ noWrap
166
+ variant="smallBold"
167
+ >
168
+ {children}
169
+ </Text>
170
+ </div>
171
+ );
@@ -0,0 +1 @@
1
+ export { Card, CardActions, CardFooter, CardMedia, CardStatus } from "./Card";
@@ -10,6 +10,10 @@ import { Button } from "@prismicio/editor-ui";
10
10
 
11
11
  const meta = {
12
12
  component: HoverCard,
13
+ argTypes: {
14
+ children: { control: { disable: true } },
15
+ trigger: { control: { disable: true } },
16
+ },
13
17
  parameters: { layout: "fullscreen" },
14
18
  } satisfies Meta<typeof HoverCard>;
15
19
 
@@ -1,3 +1,4 @@
1
+ import { findFocusableAncestor } from "@prismicio/editor-support/DOM";
1
2
  import {
2
3
  type FC,
3
4
  type MouseEventHandler,
@@ -45,31 +46,20 @@ type TableRowProps = PropsWithChildren<{
45
46
  onClick?: MouseEventHandler<HTMLTableRowElement>;
46
47
  }>;
47
48
 
48
- const tableRowTag = "prismicTableRow";
49
-
50
49
  export const TableRow: FC<TableRowProps> = ({ children, onClick }) => {
51
50
  const section = useTableSection();
52
51
 
53
52
  return (
54
53
  <tr
55
- data-tag={tableRowTag}
56
54
  className={clsx(styles.row, {
57
55
  [styles.rowClickable]: !!onClick,
58
56
  [styles.bodyRow]: section === "body",
59
57
  })}
60
58
  onClick={(event) => {
61
- if (!onClick) {
62
- return;
63
- }
64
-
59
+ if (!onClick) return;
65
60
  const target = event.target as HTMLElement;
66
- const isClickOnTableRow = !!target.closest(
67
- `tr[data-tag=${tableRowTag}]`
68
- );
69
-
70
- // Prevent a click event propagation from outside of the table DOM structure
71
- // E.g.: Dropdown menu item selection that will trigger this onClick function
72
- if (isClickOnTableRow) {
61
+ const focusableAncestor = findFocusableAncestor(target);
62
+ if (focusableAncestor?.contains(event.currentTarget) ?? true) {
73
63
  onClick(event);
74
64
  }
75
65
  }}
@@ -8,13 +8,10 @@ type Story = StoryObj<typeof meta>;
8
8
  const meta = {
9
9
  component: TextLink,
10
10
  argTypes: {
11
- color: {
12
- control: { type: "select" },
13
- options: ["primary", "secondary"],
14
- },
11
+ color: { control: "select", options: ["primary", "secondary"] },
15
12
  endIcon: { control: { disable: true } },
16
13
  textVariant: {
17
- control: { type: "select" },
14
+ control: "select",
18
15
  options: ["normal", "smallBold", "inherit"],
19
16
  },
20
17
  },
@@ -1,3 +1,4 @@
1
+ import { findFocusableAncestor } from "@prismicio/editor-support/DOM";
1
2
  import {
2
3
  DropdownMenu,
3
4
  DropdownMenuContent,
@@ -64,10 +65,13 @@ export const WindowTabsTrigger: FC<WindowTabsTriggerProps> = ({
64
65
  {...otherProps}
65
66
  asChild
66
67
  onMouseDown={(event) => {
67
- let target = event.target as HTMLElement | null;
68
- while (target !== null && target !== event.currentTarget) {
69
- if (target.tabIndex >= 0) event.preventDefault();
70
- target = target.parentElement;
68
+ const target = event.target as HTMLElement;
69
+ const focusableAncestor = findFocusableAncestor(target);
70
+ if (
71
+ focusableAncestor !== event.currentTarget &&
72
+ focusableAncestor !== event.currentTarget.parentElement
73
+ ) {
74
+ event.preventDefault();
71
75
  }
72
76
  if (target === event.currentTarget) {
73
77
  target.scrollIntoView({
@@ -0,0 +1,60 @@
1
+ import { useEffect, useState } from "react";
2
+ import { useSelector } from "react-redux";
3
+ import { Box, Button, Text } from "@prismicio/editor-ui";
4
+
5
+ import { CreateCustomTypeModal } from "@components/Forms/CreateCustomTypeModal";
6
+ import { SliceMachineStoreType } from "@src/redux/type";
7
+ import useSliceMachineActions from "@src/modules/useSliceMachineActions";
8
+ import { LoadingKeysEnum } from "@src/modules/loading/types";
9
+ import { isLoading } from "@src/modules/loading";
10
+ import { BlankPageIcon } from "@src/icons/BlankPageIcon";
11
+
12
+ export function PageTypeOnboarding() {
13
+ const { openCreateCustomTypeModal } = useSliceMachineActions();
14
+ const { isCreatingCustomType } = useSelector(
15
+ (store: SliceMachineStoreType) => ({
16
+ isCreatingCustomType: isLoading(
17
+ store,
18
+ LoadingKeysEnum.CREATE_CUSTOM_TYPE
19
+ ),
20
+ })
21
+ );
22
+ // State to ensure button loader is still visible while redirecting
23
+ const [isButtonLoading, setIsButtonLoading] = useState(false);
24
+
25
+ useEffect(() => {
26
+ if (isCreatingCustomType) {
27
+ setIsButtonLoading(true);
28
+ }
29
+ }, [isCreatingCustomType]);
30
+
31
+ return (
32
+ <Box
33
+ display="flex"
34
+ justifyContent="center"
35
+ height="100vh"
36
+ alignItems="center"
37
+ backgroundColor="grey2"
38
+ >
39
+ <Box
40
+ display="flex"
41
+ flexDirection="column"
42
+ alignItems="center"
43
+ width={384}
44
+ >
45
+ <BlankPageIcon />
46
+ <Text variant="h3" align="center" sx={{ marginTop: 16 }}>
47
+ Blank page
48
+ </Text>
49
+ <Text color="grey11" align="center" sx={{ marginBottom: 16 }}>
50
+ Welcome to Slice Machine. Your journey starts with your first page
51
+ type — the model that you will use to create pages for your website.
52
+ </Text>
53
+ <Button onClick={openCreateCustomTypeModal} loading={isButtonLoading}>
54
+ Create a page type
55
+ </Button>
56
+ <CreateCustomTypeModal format="page" origin="onboarding" />
57
+ </Box>
58
+ </Box>
59
+ );
60
+ }
@@ -8,7 +8,7 @@ import {
8
8
  BlankSlateDescription,
9
9
  BlankSlateTitle,
10
10
  } from "@src/components/BlankSlate";
11
- import { LightningIcon3D } from "@src/icons/LightningIcon3D";
11
+ import { SliceMachinePrinterIcon } from "@src/icons/SliceMachinePrinterIcon";
12
12
 
13
13
  export type SliceZoneBlankSlateProps = {
14
14
  openUpdateSliceZoneModal: () => void;
@@ -30,7 +30,7 @@ export const SliceZoneBlankSlate: FC<SliceZoneBlankSlateProps> = ({
30
30
  <BlankSlate backgroundImage="/blank-slate-slice-zone.png">
31
31
  <BlankSlateContent>
32
32
  <Box justifyContent="center" padding={{ bottom: 16 }}>
33
- <LightningIcon3D />
33
+ <SliceMachinePrinterIcon />
34
34
  </Box>
35
35
  <BlankSlateTitle>Add slices</BlankSlateTitle>
36
36
  <BlankSlateDescription>