@storybook/addon-onboarding 10.1.0-alpha.13 → 10.1.0-alpha.14

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.
@@ -0,0 +1,35 @@
1
+ import {
2
+ IntentSurvey
3
+ } from "./chunk-BTSM33XX.js";
4
+ import {
5
+ ADDON_ONBOARDING_CHANNEL
6
+ } from "./chunk-VFOIHBP2.js";
7
+ import "./chunk-ZYVL3X5E.js";
8
+
9
+ // src/Survey.tsx
10
+ import React, { useCallback } from "react";
11
+ import { ThemeProvider, convert } from "storybook/theming";
12
+ var theme = convert();
13
+ function Survey({ api }) {
14
+ let userAgent = globalThis?.navigator?.userAgent, disableOnboarding = useCallback(() => {
15
+ let url = new URL(window.location.href);
16
+ url.searchParams.set("onboarding", "false"), history.replaceState({}, "", url.href), api.setQueryParams({ onboarding: "false" });
17
+ }, [api]), complete = useCallback(
18
+ (answers) => {
19
+ api.emit(ADDON_ONBOARDING_CHANNEL, {
20
+ answers,
21
+ type: "survey",
22
+ userAgent
23
+ }), disableOnboarding();
24
+ },
25
+ [api, disableOnboarding, userAgent]
26
+ ), dismiss = useCallback(() => {
27
+ api.emit(ADDON_ONBOARDING_CHANNEL, {
28
+ type: "dismissSurvey"
29
+ }), disableOnboarding();
30
+ }, [api, disableOnboarding]);
31
+ return React.createElement(ThemeProvider, { theme }, React.createElement(IntentSurvey, { onComplete: complete, onDismiss: dismiss }));
32
+ }
33
+ export {
34
+ Survey as default
35
+ };
@@ -0,0 +1,181 @@
1
+ // src/features/IntentSurvey/IntentSurvey.tsx
2
+ import React, { Fragment, useState } from "react";
3
+ import { Button, Form, Modal } from "storybook/internal/components";
4
+ import { styled } from "storybook/theming";
5
+
6
+ // ../../.storybook/isChromatic.ts
7
+ function isChromatic(windowArg) {
8
+ let windowToCheck = windowArg || typeof window < "u" && window;
9
+ return !!(windowToCheck && (windowToCheck.navigator.userAgent.match(/Chromatic/) || windowToCheck.location.href.match(/chromatic=true/)));
10
+ }
11
+
12
+ // src/features/IntentSurvey/IntentSurvey.tsx
13
+ var Content = styled(Modal.Content)(({ theme }) => ({
14
+ fontSize: theme.typography.size.s2,
15
+ color: theme.color.defaultText,
16
+ gap: 8
17
+ })), Row = styled.div({
18
+ display: "grid",
19
+ gridTemplateColumns: "1fr 1fr",
20
+ gap: 14,
21
+ marginBottom: 8
22
+ }), Question = styled.div(({ theme }) => ({
23
+ marginTop: 8,
24
+ marginBottom: 2,
25
+ fontWeight: theme.typography.weight.bold
26
+ })), Label = styled.label({
27
+ display: "flex",
28
+ gap: 8,
29
+ '&:has(input[type="checkbox"]:not(:disabled), input[type="radio"]:not(:disabled))': {
30
+ cursor: "pointer"
31
+ }
32
+ }), Actions = styled(Modal.Actions)({
33
+ marginTop: 8
34
+ }), Checkbox = styled(Form.Checkbox)({
35
+ margin: 2
36
+ }), IntentSurvey = ({
37
+ onComplete,
38
+ onDismiss
39
+ }) => {
40
+ let [isSubmitting, setIsSubmitting] = useState(!1), [formFields, setFormFields] = useState({
41
+ building: {
42
+ label: "What are you building?",
43
+ type: "checkbox",
44
+ required: !0,
45
+ options: shuffleObject({
46
+ "design-system": { label: "Design system" },
47
+ "application-ui": { label: "Application UI" }
48
+ }),
49
+ values: {
50
+ "design-system": !1,
51
+ "application-ui": !1
52
+ }
53
+ },
54
+ interest: {
55
+ label: "Which of these are you interested in?",
56
+ type: "checkbox",
57
+ required: !0,
58
+ options: shuffleObject({
59
+ "ui-documentation": { label: "Generating UI docs" },
60
+ "functional-testing": { label: "Functional testing" },
61
+ "accessibility-testing": { label: "Accessibility testing" },
62
+ "visual-testing": { label: "Visual testing" },
63
+ "ai-augmented-development": { label: "Building UI with AI" },
64
+ "team-collaboration": { label: "Team collaboration" },
65
+ "design-handoff": { label: "Design handoff" }
66
+ }),
67
+ values: {
68
+ "ui-documentation": !1,
69
+ "functional-testing": !1,
70
+ "accessibility-testing": !1,
71
+ "visual-testing": !1,
72
+ "ai-augmented-development": !1,
73
+ "team-collaboration": !1,
74
+ "design-handoff": !1
75
+ }
76
+ },
77
+ referrer: {
78
+ label: "How did you discover Storybook?",
79
+ type: "select",
80
+ required: !0,
81
+ options: shuffleObject({
82
+ "we-use-it-at-work": { label: "We use it at work" },
83
+ "via-friend-or-colleague": { label: "Via friend or colleague" },
84
+ "via-social-media": { label: "Via social media" },
85
+ youtube: { label: "YouTube" },
86
+ "web-search": { label: "Web Search" },
87
+ "ai-agent": { label: "AI Agent (e.g. ChatGPT)" }
88
+ }),
89
+ values: {
90
+ "we-use-it-at-work": !1,
91
+ "via-friend-or-colleague": !1,
92
+ "via-social-media": !1,
93
+ youtube: !1,
94
+ "web-search": !1,
95
+ "ai-agent": !1
96
+ }
97
+ }
98
+ }), updateFormData = (key, optionOrValue, value) => {
99
+ let field = formFields[key];
100
+ setFormFields((fields) => {
101
+ if (field.type === "checkbox") {
102
+ let values = { ...field.values, [optionOrValue]: !!value };
103
+ return { ...fields, [key]: { ...field, values } };
104
+ }
105
+ if (field.type === "select") {
106
+ let values = Object.fromEntries(
107
+ Object.entries(field.values).map(([opt]) => [opt, opt === optionOrValue])
108
+ );
109
+ return { ...fields, [key]: { ...field, values } };
110
+ }
111
+ return fields;
112
+ });
113
+ }, isValid = Object.values(formFields).every((field) => field.required ? Object.values(field.values).some((value) => value === !0) : !0);
114
+ return React.createElement(
115
+ Modal,
116
+ {
117
+ ariaLabel: "Storybook user survey",
118
+ defaultOpen: !0,
119
+ width: 420,
120
+ onOpenChange: (isOpen) => {
121
+ isOpen || onDismiss();
122
+ }
123
+ },
124
+ React.createElement(Form, { onSubmit: (e) => {
125
+ isValid && (e.preventDefault(), setIsSubmitting(!0), onComplete(
126
+ Object.fromEntries(Object.entries(formFields).map(([key, field]) => [key, field.values]))
127
+ ));
128
+ }, id: "intent-survey-form" }, React.createElement(Content, null, React.createElement(Modal.Header, { onClose: onDismiss }, React.createElement(Modal.Title, null, "Help improve Storybook")), Object.keys(formFields).map((key) => {
129
+ let field = formFields[key];
130
+ return React.createElement(Fragment, { key }, React.createElement(Question, null, field.label), field.type === "checkbox" && React.createElement(Row, null, Object.entries(field.options).map(([opt, option]) => {
131
+ let id = `${key}:${opt}`;
132
+ return React.createElement("div", { key: id }, React.createElement(Label, { htmlFor: id }, React.createElement(
133
+ Checkbox,
134
+ {
135
+ name: id,
136
+ id,
137
+ checked: field.values[opt],
138
+ disabled: isSubmitting,
139
+ onChange: (e) => updateFormData(key, opt, e.target.checked)
140
+ }
141
+ ), option.label));
142
+ })), field.type === "select" && React.createElement(
143
+ Form.Select,
144
+ {
145
+ name: key,
146
+ id: key,
147
+ value: Object.entries(field.values).find(([, isSelected]) => isSelected)?.[0] || "",
148
+ required: field.required,
149
+ disabled: isSubmitting,
150
+ onChange: (e) => updateFormData(key, e.target.value)
151
+ },
152
+ React.createElement("option", { disabled: !0, hidden: !0, value: "" }, "Select an option..."),
153
+ Object.entries(field.options).map(([opt, option]) => React.createElement("option", { key: opt, value: opt }, option.label))
154
+ ));
155
+ }), React.createElement(Actions, null, React.createElement(
156
+ Button,
157
+ {
158
+ ariaLabel: !1,
159
+ disabled: isSubmitting || !isValid,
160
+ size: "medium",
161
+ type: "submit",
162
+ variant: "solid"
163
+ },
164
+ "Submit"
165
+ ))))
166
+ );
167
+ };
168
+ function shuffle(array) {
169
+ for (let i = array.length - 1; i > 0; i--) {
170
+ let j = Math.floor(Math.random() * (i + 1));
171
+ [array[i], array[j]] = [array[j], array[i]];
172
+ }
173
+ return array;
174
+ }
175
+ function shuffleObject(object) {
176
+ return isChromatic() ? object : Object.fromEntries(shuffle(Object.entries(object)));
177
+ }
178
+
179
+ export {
180
+ IntentSurvey
181
+ };
@@ -0,0 +1,8 @@
1
+ // src/constants.ts
2
+ var ADDON_ID = "storybook/onboarding", ADDON_ONBOARDING_CHANNEL = `${ADDON_ID}/channel`, ADDON_CONTROLS_ID = "addon-controls";
3
+
4
+ export {
5
+ ADDON_ID,
6
+ ADDON_ONBOARDING_CHANNEL,
7
+ ADDON_CONTROLS_ID
8
+ };
package/dist/manager.js CHANGED
@@ -1,30 +1,32 @@
1
1
  import {
2
- ADDON_CONTROLS_ID
3
- } from "./_browser-chunks/chunk-BG2SBT4L.js";
2
+ ADDON_CONTROLS_ID,
3
+ ADDON_ID
4
+ } from "./_browser-chunks/chunk-VFOIHBP2.js";
4
5
  import "./_browser-chunks/chunk-ZYVL3X5E.js";
5
6
 
6
7
  // src/manager.tsx
7
8
  import React, { Suspense, lazy } from "react";
8
- import ReactDOM from "react-dom";
9
+ import { createRoot } from "react-dom/client";
9
10
  import { STORY_SPECIFIED } from "storybook/internal/core-events";
10
- import { addons } from "storybook/manager-api";
11
- var Onboarding = lazy(() => import("./_browser-chunks/Onboarding-WWQZBI4C.js"));
12
- addons.register("@storybook/addon-onboarding", async (api) => {
13
- let urlState = api.getUrlState(), isOnboarding = urlState.path === "/onboarding" || urlState.queryParams.onboarding === "true";
14
- api.once(STORY_SPECIFIED, () => {
15
- if (!(!!api.getData("example-button--primary") || !!document.getElementById("example-button--primary"))) {
16
- console.warn(
17
- "[@storybook/addon-onboarding] It seems like you have finished the onboarding experience in Storybook! Therefore this addon is not necessary anymore and will not be loaded. You are free to remove it from your project. More info: https://github.com/storybookjs/storybook/tree/next/code/addons/onboarding#uninstalling"
18
- );
19
- return;
20
- }
21
- if (!isOnboarding || window.innerWidth < 730)
22
- return;
23
- api.togglePanel(!0), api.togglePanelPosition("bottom"), api.setSelectedPanel(ADDON_CONTROLS_ID);
24
- let domNode = document.createElement("div");
25
- domNode.id = "storybook-addon-onboarding", document.body.appendChild(domNode), ReactDOM.render(
26
- React.createElement(Suspense, { fallback: React.createElement("div", null) }, React.createElement(Onboarding, { api })),
27
- domNode
28
- );
11
+ import { addons, internal_universalChecklistStore as checklistStore } from "storybook/manager-api";
12
+ var Onboarding = lazy(() => import("./_browser-chunks/Onboarding-4UKVZPT6.js")), Survey = lazy(() => import("./_browser-chunks/Survey-RTIK67MQ.js")), root = null, render = (node) => {
13
+ let container = document.getElementById("storybook-addon-onboarding");
14
+ container || (container = document.createElement("div"), container.id = "storybook-addon-onboarding", document.body.appendChild(container)), root = root ?? createRoot(container), root.render(React.createElement(Suspense, { fallback: React.createElement("div", null) }, node));
15
+ };
16
+ addons.register(ADDON_ID, async (api) => {
17
+ let { path, queryParams } = api.getUrlState(), isOnboarding = path === "/onboarding" || queryParams.onboarding === "true", isSurvey = queryParams.onboarding === "survey", hasCompletedSurvey = await new Promise((resolve) => {
18
+ let unsubscribe = checklistStore.onStateChange(({ loaded, items }) => {
19
+ loaded && (unsubscribe(), resolve(items.onboardingSurvey.status === "accepted"));
20
+ });
29
21
  });
22
+ if (isSurvey)
23
+ return hasCompletedSurvey ? null : render(React.createElement(Survey, { api }));
24
+ if (await new Promise((resolve) => api.once(STORY_SPECIFIED, resolve)), !(!!api.getData("example-button--primary") || !!document.getElementById("example-button--primary"))) {
25
+ console.warn(
26
+ "[@storybook/addon-onboarding] It seems like you have finished the onboarding experience in Storybook! Therefore this addon is not necessary anymore and will not be loaded. You are free to remove it from your project. More info: https://github.com/storybookjs/storybook/tree/next/code/addons/onboarding#uninstalling"
27
+ );
28
+ return;
29
+ }
30
+ if (!(!isOnboarding || window.innerWidth < 730))
31
+ return api.togglePanel(!0), api.togglePanelPosition("bottom"), api.setSelectedPanel(ADDON_CONTROLS_ID), render(React.createElement(Onboarding, { api, hasCompletedSurvey }));
30
32
  });
package/dist/preset.js CHANGED
@@ -1,10 +1,10 @@
1
- import CJS_COMPAT_NODE_URL_uzlqfwkq0p from 'node:url';
2
- import CJS_COMPAT_NODE_PATH_uzlqfwkq0p from 'node:path';
3
- import CJS_COMPAT_NODE_MODULE_uzlqfwkq0p from "node:module";
1
+ import CJS_COMPAT_NODE_URL_cky4rmco7i6 from 'node:url';
2
+ import CJS_COMPAT_NODE_PATH_cky4rmco7i6 from 'node:path';
3
+ import CJS_COMPAT_NODE_MODULE_cky4rmco7i6 from "node:module";
4
4
 
5
- var __filename = CJS_COMPAT_NODE_URL_uzlqfwkq0p.fileURLToPath(import.meta.url);
6
- var __dirname = CJS_COMPAT_NODE_PATH_uzlqfwkq0p.dirname(__filename);
7
- var require = CJS_COMPAT_NODE_MODULE_uzlqfwkq0p.createRequire(import.meta.url);
5
+ var __filename = CJS_COMPAT_NODE_URL_cky4rmco7i6.fileURLToPath(import.meta.url);
6
+ var __dirname = CJS_COMPAT_NODE_PATH_cky4rmco7i6.dirname(__filename);
7
+ var require = CJS_COMPAT_NODE_MODULE_cky4rmco7i6.createRequire(import.meta.url);
8
8
 
9
9
  // ------------------------------------------------------------
10
10
  // end of CJS compatibility banner, injected by Storybook's esbuild configuration
@@ -14,15 +14,15 @@ var require = CJS_COMPAT_NODE_MODULE_uzlqfwkq0p.createRequire(import.meta.url);
14
14
  import { telemetry } from "storybook/internal/telemetry";
15
15
 
16
16
  // package.json
17
- var version = "10.1.0-alpha.13";
17
+ var version = "10.1.0-alpha.14";
18
18
 
19
19
  // src/constants.ts
20
- var STORYBOOK_ADDON_ONBOARDING_CHANNEL = "STORYBOOK_ADDON_ONBOARDING_CHANNEL";
20
+ var ADDON_ID = "storybook/onboarding", ADDON_ONBOARDING_CHANNEL = `${ADDON_ID}/channel`;
21
21
 
22
22
  // src/preset.ts
23
23
  var experimental_serverChannel = async (channel, options) => {
24
24
  let { disableTelemetry } = await options.presets.apply("core", {});
25
- return disableTelemetry || channel.on(STORYBOOK_ADDON_ONBOARDING_CHANNEL, ({ type, ...event }) => {
25
+ return disableTelemetry || channel.on(ADDON_ONBOARDING_CHANNEL, ({ type, ...event }) => {
26
26
  type === "telemetry" ? telemetry("addon-onboarding", { ...event, addonVersion: version }) : type === "survey" && telemetry("onboarding-survey", { ...event, addonVersion: version });
27
27
  }), channel;
28
28
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storybook/addon-onboarding",
3
- "version": "10.1.0-alpha.13",
3
+ "version": "10.1.0-alpha.14",
4
4
  "description": "Storybook Onboarding: Help new users learn how to write stories",
5
5
  "keywords": [
6
6
  "storybook",
@@ -59,7 +59,7 @@
59
59
  "typescript": "^5.8.3"
60
60
  },
61
61
  "peerDependencies": {
62
- "storybook": "^10.1.0-alpha.13"
62
+ "storybook": "^10.1.0-alpha.14"
63
63
  },
64
64
  "publishConfig": {
65
65
  "access": "public"
@@ -1,7 +0,0 @@
1
- // src/constants.ts
2
- var STORYBOOK_ADDON_ONBOARDING_CHANNEL = "STORYBOOK_ADDON_ONBOARDING_CHANNEL", ADDON_CONTROLS_ID = "addon-controls";
3
-
4
- export {
5
- STORYBOOK_ADDON_ONBOARDING_CHANNEL,
6
- ADDON_CONTROLS_ID
7
- };