@qld-gov-au/qgds-bootstrap5 2.1.10 → 2.1.12
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.
- package/.esbuild/plugins/qgds-plugin-clean-output-folders.js +2 -2
- package/.esbuild/plugins/qgds-plugin-story-list-builder.js +112 -0
- package/.storybook/DocumentationTemplate.mdx +47 -0
- package/.storybook/addons/qgds-multi-code-panels/components/Panel.tsx +231 -0
- package/.storybook/addons/qgds-multi-code-panels/constants.js +8 -0
- package/.storybook/addons/qgds-multi-code-panels/manager.tsx +15 -0
- package/.storybook/addons/qgds-multi-code-panels/preset.js +12 -0
- package/.storybook/codeRefsDecorator.js +87 -0
- package/.storybook/customMDXComponents.jsx +284 -0
- package/.storybook/main.mjs +16 -11
- package/.storybook/manager.js +2 -2
- package/.storybook/preview.js +39 -1
- package/dist/assets/components/bs5/directionLinks/directionLinks.hbs +0 -1
- package/dist/assets/components/bs5/head/head.hbs +1 -1
- package/dist/assets/components/bs5/pagination/pagination.hbs +0 -7
- package/dist/assets/components/bs5/searchInput/searchInput.hbs +1 -1
- package/dist/assets/css/qld.bootstrap.css +2 -2
- package/dist/assets/css/qld.bootstrap.css.map +3 -3
- package/dist/assets/css/qld.bootstrap.legacy.css +2 -2
- package/dist/assets/css/qld.bootstrap.legacy.css.map +3 -3
- package/dist/assets/js/handlebars.helpers.bundle.js +1 -1
- package/dist/assets/js/handlebars.helpers.bundle.js.map +2 -2
- package/dist/assets/js/handlebars.init.min.js +4 -12
- package/dist/assets/js/handlebars.init.min.js.map +2 -2
- package/dist/assets/js/handlebars.partials.js +4 -12
- package/dist/assets/js/handlebars.partials.js.map +2 -2
- package/dist/assets/js/qld.bootstrap.min.js +1 -1
- package/dist/assets/node/handlebars.init.min.js +3 -11
- package/dist/assets/node/handlebars.init.min.js.map +2 -2
- package/dist/components/bs5/directionLinks/directionLinks.hbs +0 -1
- package/dist/components/bs5/head/head.hbs +1 -1
- package/dist/components/bs5/pagination/pagination.hbs +0 -7
- package/dist/components/bs5/searchInput/searchInput.hbs +1 -1
- package/dist/package.json +6 -6
- package/esbuild.js +2 -0
- package/package.json +6 -6
- package/src/components/bs5/accordion/accordion.stories.js +6 -13
- package/src/components/bs5/accordion/metadata.json +15 -0
- package/src/components/bs5/backToTop/backToTop.stories.js +10 -14
- package/src/components/bs5/backToTop/manifest.json +15 -0
- package/src/components/bs5/backToTop/metadata.json +15 -0
- package/src/components/bs5/banner/banner.stories.js +16 -1
- package/src/components/bs5/banner/metadata.json +16 -0
- package/src/components/bs5/blockquote/blockquote.stories.js +20 -11
- package/src/components/bs5/blockquote/metadata.json +15 -0
- package/src/components/bs5/breadcrumbs/breadcrumbs.stories.js +6 -4
- package/src/components/bs5/breadcrumbs/metadata.json +16 -0
- package/src/components/bs5/button/button.stories.js +13 -5
- package/src/components/bs5/button/metadata.json +15 -0
- package/src/components/bs5/callToAction/callToAction.stories.js +6 -5
- package/src/components/bs5/callToAction/metadata.json +15 -0
- package/src/components/bs5/callout/callout.stories.js +6 -5
- package/src/components/bs5/callout/metadata.json +16 -0
- package/src/components/bs5/card/card--icon-list-footer.stories.js +4 -4
- package/src/components/bs5/card/card--multi-action.stories.js +6 -0
- package/src/components/bs5/card/card--no-action.stories.js +7 -0
- package/src/components/bs5/card/card--single-action.stories.js +7 -0
- package/src/components/bs5/card/metadata.json +15 -0
- package/src/components/bs5/containerLayout/containerLayout.stories.js +6 -0
- package/src/components/bs5/containerLayout/metadata.json +1 -0
- package/src/components/bs5/contentFooter/contentFooter.stories.js +26 -20
- package/src/components/bs5/contentFooter/metadata.json +15 -0
- package/src/components/bs5/correctincorrect/correctincorrect.stories.js +53 -38
- package/src/components/bs5/correctincorrect/metadata.json +14 -0
- package/src/components/bs5/dateinput/Dateinput.stories.js +6 -0
- package/src/components/bs5/dateinput/metadata.json +14 -0
- package/src/components/bs5/directionLinks/directionLinks.hbs +0 -1
- package/src/components/bs5/directionLinks/directionLinks.stories.js +4 -4
- package/src/components/bs5/directionLinks/metadata.json +16 -0
- package/src/components/bs5/footer/footer.stories.js +7 -1
- package/src/components/bs5/footer/metadata.json +15 -0
- package/src/components/bs5/formcheck/metadata.json +15 -0
- package/src/components/bs5/formcheck/stories/checkbox/checkbox.stories.js +5 -1
- package/src/components/bs5/formcheck/stories/radio/radio.stories.js +12 -1
- package/src/components/bs5/globalAlert/globalAlert.stories.js +9 -0
- package/src/components/bs5/globalAlert/metadata.json +15 -0
- package/src/components/bs5/head/head.stories.js +33 -14
- package/src/components/bs5/header/header.stories.js +10 -0
- package/src/components/bs5/header/metadata.json +15 -0
- package/src/components/bs5/icons/icons.stories.js +5 -0
- package/src/components/bs5/icons/metadata.json +15 -0
- package/src/components/bs5/image/image.stories.js +9 -0
- package/src/components/bs5/image/metadata.json +15 -0
- package/src/components/bs5/inpageAlert/inpageAlert.stories.js +9 -2
- package/src/components/bs5/inpageAlert/metadata.json +15 -0
- package/src/components/bs5/inpagenav/inpagenav.stories.js +8 -1
- package/src/components/bs5/inpagenav/metadata.json +15 -0
- package/src/components/bs5/link/link.stories.js +5 -5
- package/src/components/bs5/link/metadata.json +15 -0
- package/src/components/bs5/linkColumns/linkColumns.stories.js +4 -4
- package/src/components/bs5/linkColumns/metadata.json +15 -0
- package/src/components/bs5/logo/logo.stories.js +40 -5
- package/src/components/bs5/logo/metadata.json +16 -0
- package/src/components/bs5/metaDcTerms/metaDcTerms.stories.js +14 -9
- package/src/components/bs5/metaOpenGraph/metaOpenGraph.stories.js +14 -9
- package/src/components/bs5/modal/metadata.json +15 -0
- package/src/components/bs5/modal/modal.stories.js +64 -60
- package/src/components/bs5/navbar/metadata.json +15 -0
- package/src/components/bs5/navbar/navbar.stories.js +9 -4
- package/src/components/bs5/pageLayout/metadata.json +1 -0
- package/src/components/bs5/pageLayout/pageLayout.stories.js +1 -0
- package/src/components/bs5/pagination/metadata.json +15 -0
- package/src/components/bs5/pagination/pagination.hbs +0 -7
- package/src/components/bs5/pagination/pagination.stories.js +5 -0
- package/src/components/bs5/promotionalPanel/metadata.json +15 -0
- package/src/components/bs5/promotionalPanel/promotionalPanel.stories.js +4 -4
- package/src/components/bs5/quickexit/metadata.json +15 -0
- package/src/components/bs5/quickexit/quickexit.stories.js +7 -0
- package/src/components/bs5/searchInput/__snapshots__/searchInput.test.js.snap +4 -4
- package/src/components/bs5/searchInput/metadata.json +15 -0
- package/src/components/bs5/searchInput/searchInput.hbs +1 -1
- package/src/components/bs5/searchInput/searchInput.scss +88 -5
- package/src/components/bs5/searchInput/searchInput.stories.js +5 -0
- package/src/components/bs5/select/Select.stories.js +8 -1
- package/src/components/bs5/select/metadata.json +15 -0
- package/src/components/bs5/sidenav/metadata.json +15 -0
- package/src/components/bs5/sidenav/sidenav.stories.js +5 -0
- package/src/components/bs5/skiplinks/skipLinks.stories.js +5 -0
- package/src/components/bs5/spinner/Spinner.stories.js +8 -0
- package/src/components/bs5/spinner/metadata.json +15 -0
- package/src/components/bs5/table/metadata.json +15 -0
- package/src/components/bs5/table/table.stories.js +139 -61
- package/src/components/bs5/tabs/metadata.json +15 -0
- package/src/components/bs5/tabs/tabs.stories.js +8 -0
- package/src/components/bs5/tag/metadata.json +15 -0
- package/src/components/bs5/tag/tag--large.stories.js +7 -0
- package/src/components/bs5/tag/tag--standard.stories.js +12 -5
- package/src/components/bs5/tag/tag--status.stories.js +4 -0
- package/src/components/bs5/tag/tag.stories.js +10 -0
- package/src/components/bs5/textarea/Textarea.stories.js +8 -1
- package/src/components/bs5/textarea/metadata.json +15 -0
- package/src/components/bs5/textbox/Textbox.stories.js +11 -1
- package/src/components/bs5/textbox/metadata.json +15 -0
- package/src/components/bs5/typography/metadata.json +1 -0
- package/src/components/bs5/typography/typography.stories.js +4 -0
- package/src/components/bs5/video/metadata.json +15 -0
- package/src/components/bs5/video/video.stories.js +5 -5
- package/src/components/common/focus-styles/focusStyles.stories.js +13 -9
- package/src/js/QGDSComponent.js +0 -1
- package/src/js/handlebars.helpers.js +1 -0
- package/src/stories/Introduction/development.mdx +136 -0
- package/src/stories/Introduction/how-to-use.mdx +272 -0
- package/src/stories/Introduction.mdx +95 -13
- package/src/{components/bs5/accordion/Accordion.mdx → stories/archive/__Accordion.mdx} +3 -3
- package/src/stories/archive/__Blockquote.mdx +13 -0
- package/src/stories/archive/__BlockquoteCanvas.mdx +47 -0
- package/src/stories/archive/__backToTop.orig.mdx +13 -0
- package/src/stories/archive/__blockquote.stories.bak.js +132 -0
- package/src/stories/component-list.json +627 -0
- package/src/templates/data/component.metadata.template.json +15 -0
- package/src/templates/index.html +40 -37
- /package/src/{components/bs5/banner/Banner.mdx → stories/archive/__Banner.mdx} +0 -0
- /package/src/{components/bs5/blockquote/Blockquote.mdx → stories/archive/__Blockquote.bak.mdx} +0 -0
- /package/src/{components/bs5/breadcrumbs/Breadcrumbs.mdx → stories/archive/__Breadcrumbs.mdx} +0 -0
- /package/src/{components/bs5/button/Button.mdx → stories/archive/__Button.mdx} +0 -0
- /package/src/{components/bs5/callout/Callout.mdx → stories/archive/__Callout.mdx} +0 -0
- /package/src/{components/bs5/card/Card.mdx → stories/archive/__Card.mdx} +0 -0
- /package/src/{components/bs5/formcheck/stories/checkbox/Checkbox.mdx → stories/archive/__Checkbox.mdx} +0 -0
- /package/src/{components/bs5/dateinput/Dateinput.mdx → stories/archive/__Dateinput.mdx} +0 -0
- /package/src/{components/bs5/directionLinks/DirectionLinks.mdx → stories/archive/__DirectionLinks.mdx} +0 -0
- /package/src/{components/bs5/footer/Footer.mdx → stories/archive/__Footer.mdx} +0 -0
- /package/src/{components/bs5/globalAlert/GlobalAlert.mdx → stories/archive/__GlobalAlert.mdx} +0 -0
- /package/src/{components/bs5/header/Header.mdx → stories/archive/__Header.mdx} +0 -0
- /package/src/{components/bs5/image/Image.mdx → stories/archive/__Image.mdx} +0 -0
- /package/src/{components/bs5/inpageAlert/InpageAlert.mdx → stories/archive/__InpageAlert.mdx} +0 -0
- /package/src/{components/bs5/inpagenav/Inpagenav.mdx → stories/archive/__Inpagenav.mdx} +0 -0
- /package/src/{components/bs5/logo/Logo.mdx → stories/archive/__Logo.mdx} +0 -0
- /package/src/{components/bs5/modal/Modal.mdx → stories/archive/__Modal.mdx} +0 -0
- /package/src/{components/bs5/pagination/Pagination.mdx → stories/archive/__Pagination.mdx} +0 -0
- /package/src/{components/bs5/promotionalPanel/PromotionalPanel.mdx → stories/archive/__PromotionalPanel.mdx} +0 -0
- /package/src/{components/bs5/formcheck/stories/radio/Radio.mdx → stories/archive/__Radio.mdx} +0 -0
- /package/src/{components/bs5/searchInput/SearchInput.mdx → stories/archive/__SearchInput.mdx} +0 -0
- /package/src/{components/bs5/sidenav/Sidenav.mdx → stories/archive/__Sidenav.mdx} +0 -0
- /package/src/{components/bs5/skiplinks/SkipLinks.mdx → stories/archive/__SkipLinks.mdx} +0 -0
- /package/src/{components/bs5/table/Table.mdx → stories/archive/__Table.mdx} +0 -0
- /package/src/{components/bs5/tabs/Tabs.mdx → stories/archive/__Tabs.mdx} +0 -0
- /package/src/{components/bs5/tag/Tag.mdx → stories/archive/__Tag.mdx} +0 -0
- /package/src/{components/bs5/typography/Typography.mdx → stories/archive/__Typography.mdx} +0 -0
- /package/src/{components/bs5/video/Video.mdx → stories/archive/__Video.mdx} +0 -0
- /package/src/{components/bs5/backToTop/backToTop.mdx → stories/archive/__backToTop.mdx} +0 -0
- /package/src/{components/bs5/callToAction/callToAction.mdx → stories/archive/__callToAction.mdx} +0 -0
- /package/src/{components/bs5/accordion/mdx/_designResources.mdx → stories/archive/__designResources.mdx} +0 -0
- /package/src/{components/bs5/link/link.mdx → stories/archive/__link.mdx} +0 -0
- /package/src/{components/bs5/linkColumns/linkColumns.mdx → stories/archive/__linkColumns.mdx} +0 -0
- /package/src/{components/bs5/accordion/mdx/_usageInstructions.mdx → stories/archive/__usageInstructions.mdx} +0 -0
|
@@ -13,11 +13,11 @@ export default function cleanFoldersPlugin() {
|
|
|
13
13
|
const { outdir, outfile } = build.initialOptions;
|
|
14
14
|
|
|
15
15
|
if (outdir && fs.existsSync(outdir)) {
|
|
16
|
-
fs.rmSync(outdir, { recursive: true });
|
|
16
|
+
fs.rmSync(outdir, { recursive: true, force: true, maxRetries: 3 });
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
if (outfile && fs.existsSync(outfile)) {
|
|
20
|
-
fs.rmSync(outfile);
|
|
20
|
+
fs.rmSync(outfile, { force: true });
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
// // Clean the docs folder
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// qgds-plugin-story-list-builder.js
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
|
|
9
|
+
const COMPONENTS_DIR = path.resolve(__dirname, "./../../src/components/bs5");
|
|
10
|
+
const STORY_LIST_FILE = path.resolve(
|
|
11
|
+
__dirname,
|
|
12
|
+
"../../src/stories/component-list.json",
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
function getAllMetadataFiles(dirPath, arrayOfFiles) {
|
|
16
|
+
const files = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
17
|
+
|
|
18
|
+
arrayOfFiles = arrayOfFiles || [];
|
|
19
|
+
|
|
20
|
+
files.forEach((file) => {
|
|
21
|
+
if (file.isDirectory()) {
|
|
22
|
+
arrayOfFiles = getAllMetadataFiles(
|
|
23
|
+
path.join(dirPath, file.name),
|
|
24
|
+
arrayOfFiles,
|
|
25
|
+
);
|
|
26
|
+
} else if (file.isFile() && file.name === "metadata.json") {
|
|
27
|
+
arrayOfFiles.push(path.join(dirPath, file.name));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return arrayOfFiles;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function readMetadata(filePath) {
|
|
35
|
+
try {
|
|
36
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
37
|
+
const metadata = JSON.parse(content);
|
|
38
|
+
|
|
39
|
+
// Try to find corresponding .stories.js file
|
|
40
|
+
const componentDir = path.dirname(filePath);
|
|
41
|
+
const componentName = path.basename(componentDir);
|
|
42
|
+
const storyFiles = fs
|
|
43
|
+
.readdirSync(componentDir)
|
|
44
|
+
.filter((f) => f.endsWith(".stories.js"));
|
|
45
|
+
|
|
46
|
+
let storyTitle = null;
|
|
47
|
+
if (storyFiles.length > 0) {
|
|
48
|
+
const storyPath = path.join(componentDir, storyFiles[0]);
|
|
49
|
+
const storyContent = fs.readFileSync(storyPath, "utf8");
|
|
50
|
+
const titleMatch = storyContent.match(/title:\s*["']([^"']+)["']/);
|
|
51
|
+
storyTitle = titleMatch ? titleMatch[1] : null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
id: metadata.id,
|
|
56
|
+
title: metadata.title,
|
|
57
|
+
title_uikit: metadata.title_uikit,
|
|
58
|
+
type: metadata.type,
|
|
59
|
+
scope: metadata.scope,
|
|
60
|
+
group: metadata.group || "Components",
|
|
61
|
+
status: metadata.status,
|
|
62
|
+
description: metadata.description,
|
|
63
|
+
refs: metadata.refs,
|
|
64
|
+
storyTitle: storyTitle,
|
|
65
|
+
storyPath: storyTitle
|
|
66
|
+
? `/docs/${storyTitle.toLowerCase().replace(/\s+/g, "-").replace(/\//g, "-").replace(/\./g, "")}`
|
|
67
|
+
: null,
|
|
68
|
+
};
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error(`Error reading ${filePath}:`, error);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export default function QGDSStoryListBuilderPlugin() {
|
|
76
|
+
return {
|
|
77
|
+
name: "story-list-builder",
|
|
78
|
+
setup(build) {
|
|
79
|
+
build.onStart(async () => {
|
|
80
|
+
const files = getAllMetadataFiles(COMPONENTS_DIR);
|
|
81
|
+
// Sort files alphabetically to ensure deterministic ordering
|
|
82
|
+
files.sort((a, b) =>
|
|
83
|
+
path
|
|
84
|
+
.basename(path.dirname(a))
|
|
85
|
+
.localeCompare(path.basename(path.dirname(b))),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const componentList = [];
|
|
89
|
+
|
|
90
|
+
for (const file of files) {
|
|
91
|
+
const metadata = readMetadata(file);
|
|
92
|
+
if (metadata && metadata.status === "Published") {
|
|
93
|
+
componentList.push(metadata);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
//Sort component list by title
|
|
98
|
+
componentList.sort((a, b) => a.title.localeCompare(b.title));
|
|
99
|
+
|
|
100
|
+
// Write as JSON for easy import
|
|
101
|
+
fs.writeFileSync(
|
|
102
|
+
STORY_LIST_FILE,
|
|
103
|
+
JSON.stringify(componentList, null, 2),
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
console.log(
|
|
107
|
+
`${componentList.length} components found and written to ${STORY_LIST_FILE}`,
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Meta,
|
|
3
|
+
Title,
|
|
4
|
+
Primary,
|
|
5
|
+
Canvas,
|
|
6
|
+
Controls,
|
|
7
|
+
Stories,
|
|
8
|
+
Source,
|
|
9
|
+
useOf,
|
|
10
|
+
} from "@storybook/addon-docs/blocks";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
ComponentMeta,
|
|
14
|
+
CodeReferencesInstructions,
|
|
15
|
+
DesignResources,
|
|
16
|
+
Notes,
|
|
17
|
+
} from "./customMDXComponents.jsx";
|
|
18
|
+
|
|
19
|
+
<Meta isTemplate />
|
|
20
|
+
|
|
21
|
+
<div
|
|
22
|
+
style={{
|
|
23
|
+
display: "flex",
|
|
24
|
+
flexDirection: "row",
|
|
25
|
+
justifyContent: "space-between",
|
|
26
|
+
gap: "1rem",
|
|
27
|
+
marginBottom: "2rem",
|
|
28
|
+
}}
|
|
29
|
+
>
|
|
30
|
+
|
|
31
|
+
<Title />
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<div>
|
|
35
|
+
<ComponentMeta />
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
## Example
|
|
39
|
+
|
|
40
|
+
<Primary />
|
|
41
|
+
|
|
42
|
+
<Notes title="Notes" />
|
|
43
|
+
|
|
44
|
+
<Stories title="Variants" includePrimary={false} />
|
|
45
|
+
|
|
46
|
+
<DesignResources title="Design resources" />
|
|
47
|
+
<CodeReferencesInstructions title="How to use" />
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import React, { memo, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import prettier from "prettier/standalone";
|
|
4
|
+
import parserHtml from "prettier/parser-html";
|
|
5
|
+
import {
|
|
6
|
+
AddonPanel,
|
|
7
|
+
TabsState,
|
|
8
|
+
P,
|
|
9
|
+
SyntaxHighlighter,
|
|
10
|
+
} from "storybook/internal/components";
|
|
11
|
+
import { useChannel, useStorybookApi } from "storybook/manager-api";
|
|
12
|
+
import { useTheme } from "storybook/theming";
|
|
13
|
+
|
|
14
|
+
interface PanelProps {
|
|
15
|
+
active?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface ShowTabs {
|
|
19
|
+
template?: boolean;
|
|
20
|
+
json?: boolean;
|
|
21
|
+
htmlstory?: boolean;
|
|
22
|
+
htmlcomponent?: boolean;
|
|
23
|
+
howtouse?: boolean;
|
|
24
|
+
notes?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Single interface for both incoming data and state
|
|
28
|
+
interface PanelContent {
|
|
29
|
+
template: string;
|
|
30
|
+
htmlstory: string;
|
|
31
|
+
htmlcomponent: string;
|
|
32
|
+
json: any;
|
|
33
|
+
notes: string;
|
|
34
|
+
name: string;
|
|
35
|
+
partialname: string;
|
|
36
|
+
showPanel: boolean;
|
|
37
|
+
showTabs: ShowTabs;
|
|
38
|
+
metadata: any;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let lastCodeRefs: PanelContent | null = null;
|
|
42
|
+
|
|
43
|
+
// Format code with Prettier
|
|
44
|
+
const formatCode = async (code: string): Promise<string> => {
|
|
45
|
+
if (!code) return "";
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
return await prettier.format(code, {
|
|
49
|
+
parser: "html",
|
|
50
|
+
plugins: [parserHtml],
|
|
51
|
+
printWidth: 120,
|
|
52
|
+
tabWidth: 2,
|
|
53
|
+
useTabs: false,
|
|
54
|
+
htmlWhitespaceSensitivity: "ignore",
|
|
55
|
+
});
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.warn("Failed to format:", error);
|
|
58
|
+
return code;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const Panel: React.FC<PanelProps> = memo(function MyPanel({ active }) {
|
|
63
|
+
const api = useStorybookApi();
|
|
64
|
+
const storyId = api.getCurrentStoryData()?.id || "N/A";
|
|
65
|
+
|
|
66
|
+
const theme = useTheme();
|
|
67
|
+
const [content, setContent] = useState<PanelContent | null>(lastCodeRefs);
|
|
68
|
+
|
|
69
|
+
useChannel({
|
|
70
|
+
CODEREFS_UPDATE: async (data: PanelContent) => {
|
|
71
|
+
// If showPanel is false or no showTabs defined, clear the content
|
|
72
|
+
if (!data.showPanel || !data.showTabs) {
|
|
73
|
+
setContent(null);
|
|
74
|
+
lastCodeRefs = null;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const [formattedTemplate, formattedHtmlStory, formattedHtmlComponent] =
|
|
79
|
+
await Promise.all([
|
|
80
|
+
formatCode(data.template),
|
|
81
|
+
formatCode(data.htmlstory),
|
|
82
|
+
formatCode(data.htmlcomponent),
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
const newContent = {
|
|
86
|
+
template: formattedTemplate,
|
|
87
|
+
htmlstory: formattedHtmlStory,
|
|
88
|
+
htmlcomponent: formattedHtmlComponent,
|
|
89
|
+
json: data.json,
|
|
90
|
+
notes: data.notes,
|
|
91
|
+
name: data.name,
|
|
92
|
+
partialname: data.partialname,
|
|
93
|
+
metadata: data.metadata,
|
|
94
|
+
showPanel: data.showPanel,
|
|
95
|
+
showTabs: data.showTabs,
|
|
96
|
+
};
|
|
97
|
+
setContent(newContent);
|
|
98
|
+
lastCodeRefs = newContent;
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Build visible tabs array
|
|
103
|
+
const buildTabs = () => {
|
|
104
|
+
if (!content) return [];
|
|
105
|
+
|
|
106
|
+
const tabs: React.ReactElement[] = [];
|
|
107
|
+
|
|
108
|
+
if (content.showTabs.htmlstory !== false) {
|
|
109
|
+
tabs.push(
|
|
110
|
+
<div
|
|
111
|
+
key="htmlstory"
|
|
112
|
+
id="htmlstory"
|
|
113
|
+
title="HTML (Story)"
|
|
114
|
+
color={theme.color.defaultText}
|
|
115
|
+
>
|
|
116
|
+
<div style={{ padding: "20px" }}>
|
|
117
|
+
<SyntaxHighlighter language="html" copyable={true}>
|
|
118
|
+
{content.htmlstory}
|
|
119
|
+
</SyntaxHighlighter>
|
|
120
|
+
</div>
|
|
121
|
+
</div>,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (content.showTabs.htmlcomponent !== false) {
|
|
126
|
+
tabs.push(
|
|
127
|
+
<div
|
|
128
|
+
key="htmlcomponent"
|
|
129
|
+
id="htmlcomponent"
|
|
130
|
+
title="HTML (Component)"
|
|
131
|
+
color={theme.color.defaultText}
|
|
132
|
+
>
|
|
133
|
+
<div style={{ padding: "20px" }}>
|
|
134
|
+
<SyntaxHighlighter language="html" copyable={true}>
|
|
135
|
+
{content.htmlcomponent}
|
|
136
|
+
</SyntaxHighlighter>
|
|
137
|
+
</div>
|
|
138
|
+
</div>,
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (content.showTabs.template !== false) {
|
|
143
|
+
tabs.push(
|
|
144
|
+
<div
|
|
145
|
+
key="template"
|
|
146
|
+
id="template"
|
|
147
|
+
title="Handlebars"
|
|
148
|
+
color={theme.color.defaultText}
|
|
149
|
+
>
|
|
150
|
+
<div style={{ padding: "20px" }}>
|
|
151
|
+
<SyntaxHighlighter language="html" copyable={true}>
|
|
152
|
+
{content.template}
|
|
153
|
+
</SyntaxHighlighter>
|
|
154
|
+
</div>
|
|
155
|
+
</div>,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (content.showTabs.json !== false) {
|
|
160
|
+
tabs.push(
|
|
161
|
+
<div
|
|
162
|
+
key="params"
|
|
163
|
+
id="params"
|
|
164
|
+
title="Data"
|
|
165
|
+
color={theme.color.defaultText}
|
|
166
|
+
>
|
|
167
|
+
<div style={{ padding: "20px" }}>
|
|
168
|
+
<SyntaxHighlighter language="json" copyable={true}>
|
|
169
|
+
{JSON.stringify(content.json, null, 2)}
|
|
170
|
+
</SyntaxHighlighter>
|
|
171
|
+
</div>
|
|
172
|
+
</div>,
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (content.showTabs.notes) {
|
|
177
|
+
tabs.push(
|
|
178
|
+
<div
|
|
179
|
+
key="notes"
|
|
180
|
+
id="notes"
|
|
181
|
+
title="Notes"
|
|
182
|
+
color={theme.color.defaultText}
|
|
183
|
+
>
|
|
184
|
+
<div style={{ padding: "20px" }}>
|
|
185
|
+
<P>{content.notes}</P>
|
|
186
|
+
</div>
|
|
187
|
+
</div>,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (content.showTabs.howtouse) {
|
|
192
|
+
tabs.push(
|
|
193
|
+
<div
|
|
194
|
+
key="howtouse"
|
|
195
|
+
id="howtouse"
|
|
196
|
+
title="Use"
|
|
197
|
+
color={theme.color.defaultText}
|
|
198
|
+
>
|
|
199
|
+
<div style={{ padding: "20px" }}>
|
|
200
|
+
<SyntaxHighlighter language="typescript" copyable={true}>
|
|
201
|
+
{`const data = ${JSON.stringify(content.json, undefined, 2)}; \n\nconst html = Handlebars.compile(\`{{> ${content.partialname} }}\`)(data);`}
|
|
202
|
+
</SyntaxHighlighter>
|
|
203
|
+
</div>
|
|
204
|
+
</div>,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return tabs;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const tabs = buildTabs();
|
|
212
|
+
const initialTab = tabs.length > 0 ? tabs[0].props.id : "template";
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
<AddonPanel active={active ?? false}>
|
|
216
|
+
{content === null || tabs.length === 0 ? (
|
|
217
|
+
<div style={{ padding: "20px", color: "#999" }}>
|
|
218
|
+
Code references are disabled for this story.
|
|
219
|
+
</div>
|
|
220
|
+
) : (
|
|
221
|
+
<TabsState
|
|
222
|
+
initial={initialTab}
|
|
223
|
+
backgroundColor={theme.background.hoverable}
|
|
224
|
+
key={`story-codetabs-${storyId}`}
|
|
225
|
+
>
|
|
226
|
+
{tabs}
|
|
227
|
+
</TabsState>
|
|
228
|
+
)}
|
|
229
|
+
</AddonPanel>
|
|
230
|
+
);
|
|
231
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { addons, types } from "storybook/manager-api";
|
|
3
|
+
import { ADDON_ID, PANEL_ID } from "./constants";
|
|
4
|
+
import { Panel } from "./components/Panel";
|
|
5
|
+
|
|
6
|
+
// Register the addon
|
|
7
|
+
addons.register(ADDON_ID, (api) => {
|
|
8
|
+
// Register a panel on each story view
|
|
9
|
+
addons.add(PANEL_ID, {
|
|
10
|
+
type: types.PANEL,
|
|
11
|
+
title: "Code References",
|
|
12
|
+
match: ({ viewMode }) => viewMode === "story",
|
|
13
|
+
render: ({ active }) => active && <Panel active={active} />,
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// This file is loaded during Storybook's Node.js configuration phase
|
|
2
|
+
// It must not contain JSX or browser-only code
|
|
3
|
+
|
|
4
|
+
import { join, dirname } from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
9
|
+
|
|
10
|
+
export function managerEntries(entry = []) {
|
|
11
|
+
return [...entry, join(__dirname, "./manager.tsx")];
|
|
12
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useEffect } from "storybook/preview-api";
|
|
2
|
+
import { addons } from "storybook/preview-api";
|
|
3
|
+
import Handlebars from "handlebars";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Channel Communication Decorator
|
|
7
|
+
*
|
|
8
|
+
* Establishes a channel connection between the Storybook preview (inner iframe)
|
|
9
|
+
* and Storybook manager (outer frame) to send coderefs data to the
|
|
10
|
+
* "Code References" panel whenever a story is rendered or updated.
|
|
11
|
+
*
|
|
12
|
+
* @fires CODEREFS_UPDATE - Emits payload to manager with template, json, html, name, notes, and metadata
|
|
13
|
+
*/
|
|
14
|
+
export const withCodeRefs = (Story, context) => {
|
|
15
|
+
const { args, parameters } = context;
|
|
16
|
+
|
|
17
|
+
const coderefs = parameters.coderefs || {};
|
|
18
|
+
const metadata = coderefs?.metadata || {};
|
|
19
|
+
const storyArgs = coderefs?.args || args;
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
const channel = addons.getChannel();
|
|
23
|
+
|
|
24
|
+
// If coderefs.show is explicitly false, send "hide" signal and exit
|
|
25
|
+
if (coderefs.show === false) {
|
|
26
|
+
channel.emit("CODEREFS_UPDATE", { showPanel: false });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Default tabs to show
|
|
31
|
+
const showtabs = {
|
|
32
|
+
htmlstory: coderefs.tabs?.htmlstory !== false,
|
|
33
|
+
htmlcomponent: coderefs.tabs?.htmlcomponent !== false,
|
|
34
|
+
json: coderefs.tabs?.json !== false,
|
|
35
|
+
template: coderefs.tabs?.template !== false,
|
|
36
|
+
howtouse: coderefs.tabs?.howtouse !== false,
|
|
37
|
+
notes: coderefs.tabs?.notes !== undefined,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Check if any tabs are visible
|
|
41
|
+
const hasVisibleTabs = Object.values(showtabs).some(Boolean);
|
|
42
|
+
|
|
43
|
+
// If no tabs to show, send "hide" signal and exit
|
|
44
|
+
if (!hasVisibleTabs) {
|
|
45
|
+
channel.emit("CODEREFS_UPDATE", { showPanel: false });
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Get the story's rendered HTML
|
|
50
|
+
|
|
51
|
+
// Full Story HTML
|
|
52
|
+
const htmlstoryContent = Story(args, context);
|
|
53
|
+
|
|
54
|
+
// Component only HTML
|
|
55
|
+
const hbspartial = Handlebars.partials[coderefs.partialname] || false;
|
|
56
|
+
|
|
57
|
+
if (!hbspartial) {
|
|
58
|
+
console.warn(
|
|
59
|
+
`[CODEREFS] Partial "${coderefs.partialname}" not found in Handlebars partials.`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const htmlcomponentContent =
|
|
64
|
+
typeof hbspartial === "string"
|
|
65
|
+
? Handlebars.compile(hbspartial)(args)
|
|
66
|
+
: "Missing partialname in story config, or component does use a handlebars template.";
|
|
67
|
+
|
|
68
|
+
// Data we're sending from preview frame to manager frame
|
|
69
|
+
const payload = {
|
|
70
|
+
showPanel: true,
|
|
71
|
+
showTabs: showtabs,
|
|
72
|
+
template: hbspartial || "No template available",
|
|
73
|
+
json: storyArgs,
|
|
74
|
+
htmlstory: htmlstoryContent,
|
|
75
|
+
htmlcomponent: htmlcomponentContent,
|
|
76
|
+
notes: coderefs.tabs?.notes || "Nil",
|
|
77
|
+
name: context.name || "Unknown",
|
|
78
|
+
partialname: coderefs.partialname || "Unknown",
|
|
79
|
+
metadata: metadata,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
console.log("[PREVIEW] Sending CODEREFS_UPDATE:", payload);
|
|
83
|
+
channel.emit("CODEREFS_UPDATE", payload);
|
|
84
|
+
}, [args, parameters.coderefs]);
|
|
85
|
+
|
|
86
|
+
return Story();
|
|
87
|
+
};
|