diff --git a/src/components/alert/alert.stories.js b/src/components/alert/alert.stories.js index f474523b8..fd503ce55 100644 --- a/src/components/alert/alert.stories.js +++ b/src/components/alert/alert.stories.js @@ -1,6 +1,8 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import template from './alert.twig'; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Alert', argTypes: { class: { @@ -18,7 +20,7 @@ export default { type: 'boolean', description: 'Adds a close button to the right of the message.', table: { - defaultValue: { summary: false }, + defaultValue: { summary: 'false' }, }, }, icon: { @@ -41,7 +43,7 @@ export default { type: 'boolean', description: 'Adds a light border and shadow for a floating effect.', table: { - defaultValue: { summary: false }, + defaultValue: { summary: 'false' }, }, }, tag_name: { @@ -59,7 +61,7 @@ export default { type: 'boolean', description: 'Adds a `hidden` attribute to the root element.', table: { - defaultValue: { summary: false }, + defaultValue: { summary: 'false' }, }, }, role: { @@ -70,10 +72,14 @@ export default { render: (args) => template(args), }; +export default meta; + +/** @type {StoryObj} */ export const Basic = { args: { message: 'Your comment is awaiting moderation.' }, }; +/** @type {StoryObj} */ export const Dismissable = { args: { message: 'Your action was completed successfully! 🎉', @@ -81,6 +87,7 @@ export const Dismissable = { }, }; +/** @type {StoryObj} */ export const FullWidth = { name: 'Full width', args: { @@ -92,6 +99,7 @@ export const FullWidth = { }, }; +/** @type {StoryObj} */ export const Icon = { args: { message: 'Your action was completed successfully! 🎉', @@ -99,6 +107,7 @@ export const Icon = { }, }; +/** @type {StoryObj} */ export const Error = { args: { message: 'Oops! Something went wrong.', @@ -108,6 +117,7 @@ export const Error = { }, }; +/** @type {StoryObj} */ export const Floating = { args: { message: 'You appear to be offline. 🤔', @@ -117,6 +127,7 @@ export const Floating = { }, }; +/** @type {StoryObj} */ export const ThemedFloating = { name: 'Themed Floating', args: { diff --git a/src/components/author/author.stories.js b/src/components/author/author.stories.js index 85fab9953..e26bdd6d1 100644 --- a/src/components/author/author.stories.js +++ b/src/components/author/author.stories.js @@ -1,3 +1,4 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import template from './author.twig'; const allAuthors = [ { @@ -30,7 +31,8 @@ const authorsWithNoLink = (count = 1) => })) .slice(0, count); -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Author', argTypes: { count: { @@ -46,6 +48,9 @@ export default { }, }; +export default meta; + +/** @type {StoryObj} */ export const BasicUsage = { name: 'Basic usage', args: { count: 1 }, @@ -55,6 +60,7 @@ export const BasicUsage = { }), }; +/** @type {StoryObj} */ export const WithLink = { name: 'With link', args: { count: 1 }, @@ -65,6 +71,7 @@ export const WithLink = { }), }; +/** @type {StoryObj} */ export const RemoveLink = { name: 'Remove link', args: { count: 1 }, @@ -75,6 +82,7 @@ export const RemoveLink = { }), }; +/** @type {StoryObj} */ export const WithMetaContent = { name: 'With meta content', args: { count: 1 }, @@ -85,6 +93,7 @@ export const WithMetaContent = { }), }; +/** @type {StoryObj} */ export const WithDateContent = { name: 'With date content', args: { count: 1 }, @@ -95,6 +104,7 @@ export const WithDateContent = { }), }; +/** @type {StoryObj} */ export const ShortDateFormat = { name: 'Short date format', args: { count: 1 }, @@ -106,6 +116,7 @@ export const ShortDateFormat = { }), }; +/** @type {StoryObj} */ export const MultipleAuthors = { name: 'Multiple authors', args: { count: 3 }, diff --git a/src/components/avatar/avatar.stories.js b/src/components/avatar/avatar.stories.js index 318f9059a..51d2407f4 100644 --- a/src/components/avatar/avatar.stories.js +++ b/src/components/avatar/avatar.stories.js @@ -1,3 +1,4 @@ +/** @import { Args, Meta, StoryObj } from '@storybook/html' */ import template from './avatar.twig'; import { avatarArgTypes } from './demo/arg-types.js'; import demoImageMedium from './demo/tyler-335.png'; @@ -8,6 +9,7 @@ const demoImageSrcset = [ `${demoImageMedium} 335w`, `${demoImageLarge} 768w`, ].join(', '); +/** @param {Args} args */ const avatarStory = (args) => { // Don't bother with the size option if it is the default if (args.size === 'medium') { @@ -20,7 +22,8 @@ const avatarStory = (args) => { return template(args); }; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Avatar', args: { size: 'medium', @@ -29,13 +32,18 @@ export default { render: avatarStory.bind({}), }; +export default meta; + +/** @type {StoryObj} */ export const Empty = {}; +/** @type {StoryObj} */ export const WithImage = { name: 'With Image', args: { src: demoImageSmall, srcset: demoImageSrcset, sizes: '60px' }, }; +/** @type {StoryObj} */ export const SmallEmpty = { name: 'Small (Empty)', args: { @@ -43,6 +51,7 @@ export const SmallEmpty = { }, }; +/** @type {StoryObj} */ export const SmallWithImage = { name: 'Small (With Image)', args: { @@ -53,6 +62,7 @@ export const SmallWithImage = { }, }; +/** @type {StoryObj} */ export const FullWidth = { name: 'Full Width', args: { @@ -63,10 +73,12 @@ export const FullWidth = { }, }; +/** @type {StoryObj} */ export const Square = { args: { shape: 'square' }, }; +/** @type {StoryObj} */ export const Squircle = { args: { shape: 'squircle' }, }; diff --git a/src/components/avatar/demo/arg-types.js b/src/components/avatar/demo/arg-types.js index 8cd7fb74f..52e9a07ef 100644 --- a/src/components/avatar/demo/arg-types.js +++ b/src/components/avatar/demo/arg-types.js @@ -1,3 +1,5 @@ +/** @import { ArgTypes } from '@storybook/html' */ +/** @type {Partial} */ export const avatarArgTypes = { src: { type: { name: 'string' } }, srcset: { type: { name: 'string' } }, diff --git a/src/components/badge/badge.stories.js b/src/components/badge/badge.stories.js index af902231d..3b3510b2b 100644 --- a/src/components/badge/badge.stories.js +++ b/src/components/badge/badge.stories.js @@ -1,4 +1,6 @@ +/** @import { Args, Meta, StoryObj } from '@storybook/html' */ import template from './badge.twig'; +/** @param {Args} args */ const badgeStory = (args) => { // Don't bother with the inline options if they don't exist or are defaults if (args.icon === '') { @@ -7,7 +9,8 @@ const badgeStory = (args) => { return template(args); }; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Badge', argTypes: { label: { type: { name: 'string' } }, @@ -24,15 +27,20 @@ export default { render: (args) => badgeStory(args), }; +export default meta; + +/** @type {StoryObj} */ export const Basic = { args: { label: 'Hello' }, }; +/** @type {StoryObj} */ export const WithIcon = { name: 'With icon', args: { icon: 'check', label: 'Verified' }, }; +/** @type {StoryObj} */ export const Linked = { args: { icon: 'paperclip', label: 'Attachment', href: '#', rel: 'tag' }, }; diff --git a/src/components/button-swap/button-swap.stories.js b/src/components/button-swap/button-swap.stories.js index 5ab38b529..1162df842 100644 --- a/src/components/button-swap/button-swap.stories.js +++ b/src/components/button-swap/button-swap.stories.js @@ -1,8 +1,10 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import { makeTwigInclude } from '../../make-twig-include.js'; import buttonSwap from './button-swap.twig'; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Button Swap', argTypes: { content_start_icon: { @@ -18,6 +20,9 @@ export default { render: (args) => buttonSwap(args), }; +export default meta; + +/** @type {StoryObj} */ export const Default = { args: { initial_label: 'Notifications have been turned off.', diff --git a/src/components/button/button.stories.js b/src/components/button/button.stories.js index e45738efd..36ddd5210 100644 --- a/src/components/button/button.stories.js +++ b/src/components/button/button.stories.js @@ -1,3 +1,4 @@ +/** @import { ArgTypes, Args, Meta, StoryObj } from '@storybook/html' */ import button from './button.twig'; import iconButtonCustomDemo from './demo/icon-button-custom-demo.twig'; import iconButtonCustomDemoSource from './demo/icon-button-custom-demo.twig?raw'; @@ -5,6 +6,7 @@ import slashedIconButtonCustomDemo from './demo/slashed-icon-button-custom-demo. import slashedIconButtonCustomDemoSource from './demo/slashed-icon-button-custom-demo.twig?raw'; import stylesDemo from './demo/styles.twig'; import stylesDemoSource from './demo/styles.twig?raw'; +/** @type {ArgTypes[string]} */ const iconControlConfig = { options: [ '', @@ -20,6 +22,7 @@ const iconControlConfig = { type: 'select', }, }; +/** @param {Args} args */ const buttonStory = (args) => { // Don't bother with the inline options if they don't exist or are defaults if (args.content_start_icon === '') { @@ -37,7 +40,8 @@ const buttonStory = (args) => { return button(args); }; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Button', args: { type: 'button', @@ -47,7 +51,7 @@ export default { href: { type: { name: 'string' } }, type: { options: ['button', 'submit'], - type: { name: 'enum' }, + type: { name: 'enum', value: ['button', 'submit'] }, control: { type: 'inline-radio' }, }, disabled: { type: { name: 'boolean' } }, @@ -56,23 +60,29 @@ export default { }, }; +export default meta; + +/** @type {StoryObj} */ export const ButtonElement = { name: 'Button Element', args: { label: 'Button', href: false }, render: (args) => buttonStory(args), }; +/** @type {StoryObj} */ export const LinkElement = { name: 'Link Element', args: { label: 'Link', tagName: 'a' }, render: (args) => buttonStory(args), }; +/** @type {StoryObj} */ export const Styles = { parameters: { docs: { source: { code: stylesDemoSource } } }, render: (args) => stylesDemo(args), }; +/** @type {StoryObj} */ export const StylesDark = { name: 'Styles (Dark)', parameters: { @@ -82,6 +92,7 @@ export const StylesDark = { render: (args) => stylesDemo(args), }; +/** @type {StoryObj} */ export const Icon = { args: { content_start_icon: 'bell', @@ -90,6 +101,7 @@ export const Icon = { render: (args) => buttonStory(args), }; +/** @type {StoryObj} */ export const CustomIcon = { name: 'Custom Icon', parameters: { @@ -98,22 +110,26 @@ export const CustomIcon = { render: (args) => iconButtonCustomDemo(args), }; +/** @type {StoryObj} */ export const Disabled = { args: { label: 'Disabled', disabled: true }, render: (args) => buttonStory(args), }; +/** @type {StoryObj} */ export const ARIADisabled = { name: 'ARIA Disabled', args: { label: 'ARIA Disabled', aria_disabled: 'true' }, render: (args) => buttonStory(args), }; +/** @type {StoryObj} */ export const Loading = { args: { label: 'Loading', class: 'is-loading' }, render: (args) => buttonStory(args), }; +/** @type {StoryObj} */ export const SlashedIcon = { name: 'Slashed Icon', args: { @@ -122,6 +138,7 @@ export const SlashedIcon = { render: (args) => buttonStory(args), }; +/** @type {StoryObj} */ export const SecondaryButtonWithSlashedIcon = { name: 'Secondary Button with Slashed Icon', args: { @@ -130,6 +147,7 @@ export const SecondaryButtonWithSlashedIcon = { render: (args) => buttonStory(args), }; +/** @type {StoryObj} */ export const TertiaryButtonWithSlashedIcon = { name: 'Tertiary Button with Slashed Icon', args: { @@ -138,6 +156,7 @@ export const TertiaryButtonWithSlashedIcon = { render: (args) => buttonStory(args), }; +/** @type {StoryObj} */ export const SlashedCustomIcon = { name: 'Slashed Custom Icon', parameters: { diff --git a/src/components/calendar-date/calendar-date.stories.js b/src/components/calendar-date/calendar-date.stories.js index 5d6c0f349..290fc35f9 100644 --- a/src/components/calendar-date/calendar-date.stories.js +++ b/src/components/calendar-date/calendar-date.stories.js @@ -1,6 +1,8 @@ +/** @import { ArgTypes, Meta, StoryObj } from '@storybook/html' */ import template from './calendar-date.twig'; import seasonsDemo from './demo/seasons.twig'; import './demo/styles.scss'; +/** @type {Partial} */ const argTypes = { datetime: { control: { type: 'date' }, @@ -8,10 +10,14 @@ const argTypes = { note: { type: { name: 'string' } }, }; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Calendar Date', }; +export default meta; + +/** @type {StoryObj} */ export const Basic = { args: { datetime: Date.now() }, argTypes, @@ -19,6 +25,7 @@ export const Basic = { template({ datetime: new Date(datetime), note }), }; +/** @type {StoryObj} */ export const WithNote = { name: 'With Note', args: { datetime: Date.now(), note: '3-day event' }, @@ -27,6 +34,7 @@ export const WithNote = { template({ datetime: new Date(datetime), note }), }; +/** @type {StoryObj} */ export const Seasons = { parameters: { docs: { diff --git a/src/components/card/card.stories.js b/src/components/card/card.stories.js index a8a04d634..e9c7e55da 100644 --- a/src/components/card/card.stories.js +++ b/src/components/card/card.stories.js @@ -1,7 +1,13 @@ +/** @import { Args, Meta, StoryContext, StoryObj } from '@storybook/html' */ import cloudyDemo from './demo/cloudy.twig'; import cloudyDemoSource from './demo/cloudy.twig?raw'; import singleDemo from './demo/single.twig'; +/** + * @param {Args} args + * @param {string} [storyId] + */ const singleDemoProps = (args = {}, storyId) => { + /** @type {Record} */ const props = { heading_id: args.heading_id || `${storyId}-heading`, href: args.href, @@ -28,6 +34,7 @@ const singleDemoProps = (args = {}, storyId) => { } return props; }; +/** @param {Args} args */ const singleDemoStory = (args) => { const props = singleDemoProps(args); if (args.show && args.show.length > 0) { @@ -37,6 +44,7 @@ const singleDemoStory = (args) => { } return singleDemo(props); }; +/** @type {Record} */ const singleDemoBlockExamples = { heading: 'Lorem ipsum dolor sit amet', eyebrow: `{% include '@cloudfour/components/logo/logo.twig' with { } only %}`, @@ -45,7 +53,12 @@ const singleDemoBlockExamples = { footer: `

{{'now'|date('M j, Y')}}

`, }; // Custom function for generating story source from args given +/** + * @param {string} _src + * @param {StoryContext} storyContext + */ const singleDemoTransformSource = (_src, storyContext) => { + /** @type {Args} */ const args = storyContext.args || storyContext.initialArgs; const props = singleDemoProps(args, storyContext.id); const propsString = @@ -53,7 +66,7 @@ const singleDemoTransformSource = (_src, storyContext) => { ? ` with ${JSON.stringify(props, null, 2)}` : ''; const blocks = (args.show || []).map( - (blockName) => + (/** @type {string} */ blockName) => `{% block ${blockName} %}${singleDemoBlockExamples[blockName]}{% endblock %}`, ); return `{% embed '@cloudfour/components/card/card.twig'${propsString} only %} @@ -61,7 +74,8 @@ const singleDemoTransformSource = (_src, storyContext) => { {% endembed %}`; }; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Card', args: { show: ['heading', 'cover', 'content', 'footer'], @@ -96,6 +110,9 @@ export default { }, }; +export default meta; + +/** @type {StoryObj} */ export const ContentBlocks = { name: 'Content Blocks', args: { @@ -104,6 +121,7 @@ export const ContentBlocks = { render: singleDemoStory.bind({}), }; +/** @type {StoryObj} */ export const Link = { args: { href: '#', @@ -112,12 +130,14 @@ export const Link = { render: singleDemoStory.bind({}), }; +/** @type {StoryObj} */ export const CoverImage = { name: 'Cover Image', args: { href: '#' }, render: singleDemoStory.bind({}), }; +/** @type {StoryObj} */ export const Eyebrow = { args: { href: '#', @@ -127,28 +147,33 @@ export const Eyebrow = { render: singleDemoStory.bind({}), }; +/** @type {StoryObj} */ export const Horizontal = { args: { href: '#', horizontal: '@m' }, render: singleDemoStory.bind({}), }; +/** @type {StoryObj} */ export const CircularCoverImage = { name: 'Circular Cover Image', args: { class: 'c-card--circle-cover', href: '#', horizontal: '@m' }, render: singleDemoStory.bind({}), }; +/** @type {StoryObj} */ export const Contained = { args: { href: '#', horizontal: '@m', contained: true }, render: singleDemoStory.bind({}), }; +/** @type {StoryObj} */ export const Themed = { args: { href: '#', horizontal: '@m', contained: true, theme: 'light' }, parameters: { theme: 't-dark' }, render: singleDemoStory.bind({}), }; +/** @type {StoryObj} */ export const Cloudy = { parameters: { docs: { diff --git a/src/components/checkbox/checkbox.stories.js b/src/components/checkbox/checkbox.stories.js index 2d2e59a31..666213d26 100644 --- a/src/components/checkbox/checkbox.stories.js +++ b/src/components/checkbox/checkbox.stories.js @@ -1,7 +1,9 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import withLabelDemo from './demo/with-label.twig'; import './demo/styles.scss'; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Checkbox', argTypes: { disabled: { type: { name: 'boolean' } }, @@ -9,6 +11,9 @@ export default { render: (args) => withLabelDemo(args), }; +export default meta; + +/** @type {StoryObj} */ export const Enabled = { args: { disabled: false }, parameters: { @@ -27,6 +32,7 @@ export const Enabled = { }, }; +/** @type {StoryObj} */ export const Disabled = { args: { disabled: true }, parameters: { diff --git a/src/components/cloud-cover/cloud-cover.stories.js b/src/components/cloud-cover/cloud-cover.stories.js index 91ccbcee9..8f629a7c0 100644 --- a/src/components/cloud-cover/cloud-cover.stories.js +++ b/src/components/cloud-cover/cloud-cover.stories.js @@ -1,3 +1,4 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import { useEffect } from 'storybook/preview-api'; import contentDemo from './demo/content.twig'; @@ -6,7 +7,8 @@ import flagImage from './demo/flag.svg'; import robotImage from './demo/robot.svg'; import sceneDemo from './demo/scene.twig'; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Cloud Cover', parameters: { docs: { story: { inline: false } }, @@ -15,6 +17,9 @@ export default { }, }; +export default meta; + +/** @type {StoryObj} */ export const Content = { parameters: { docs: { @@ -41,6 +46,7 @@ export const Content = { render: () => contentDemo(), }; +/** @type {StoryObj} */ export const Scene = { parameters: { docs: { @@ -74,6 +80,7 @@ export const Scene = { render: () => sceneDemo({ image: robotImage }), }; +/** @type {StoryObj} */ export const HorizonScene = { name: 'Horizon Scene', parameters: { @@ -112,6 +119,7 @@ export const HorizonScene = { }), }; +/** @type {StoryObj} */ export const ExtraContent = { name: 'Extra Content', parameters: { @@ -146,6 +154,7 @@ export const ExtraContent = { render: () => extraDemo(), }; +/** @type {StoryObj} */ export const FullHeight = { name: 'Full Height', parameters: { @@ -182,7 +191,10 @@ export const FullHeight = { // Set this story's `body` element to full-height document.body.style.height = '100%'; // Prevent Storybook's container from affecting this layout - document.querySelector('#storybook-root').style.display = 'contents'; + const root = /** @type {HTMLElement | null} */ ( + document.querySelector('#storybook-root') + ); + if (root) root.style.display = 'contents'; }); return sceneDemo({ class: 'c-cloud-cover--full-height', diff --git a/src/components/comment-form/comment-form.stories.js b/src/components/comment-form/comment-form.stories.js index a0b0b4354..e0600a47b 100644 --- a/src/components/comment-form/comment-form.stories.js +++ b/src/components/comment-form/comment-form.stories.js @@ -1,7 +1,8 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import { useEffect } from 'storybook/preview-api'; import { makeTwigInclude } from '../../make-twig-include.js'; -import { createElasticTextArea } from '../input/elastic-textarea.ts'; +import { createElasticTextArea } from '../input/elastic-textarea'; import template from './comment-form.twig'; const tyler = { @@ -9,7 +10,8 @@ const tyler = { link: 'https://cloudfour.com/is/tyler', }; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Comment Form', args: { isLoggedIn: false, @@ -25,6 +27,9 @@ export default { }, }; +export default meta; + +/** @type {StoryObj} */ export const Default = { args: { isReply: false }, parameters: { @@ -42,9 +47,11 @@ export const Default = { }, render: ({ isLoggedIn, isReply }) => { useEffect(() => { - const { destroy } = createElasticTextArea( - document.querySelector('.js-elastic-textarea'), + const textarea = /** @type {HTMLTextAreaElement | null} */ ( + document.querySelector('.js-elastic-textarea') ); + if (!textarea) return; + const { destroy } = createElasticTextArea(textarea); return destroy; }); return template({ @@ -57,6 +64,7 @@ export const Default = { }, }; +/** @type {StoryObj} */ export const Reply = { args: { isReply: true, isLoggedIn: true }, parameters: { @@ -80,9 +88,11 @@ export const Reply = { }, render: ({ isLoggedIn, isReply }) => { useEffect(() => { - const { destroy } = createElasticTextArea( - document.querySelector('.js-elastic-textarea'), + const textarea = /** @type {HTMLTextAreaElement | null} */ ( + document.querySelector('.js-elastic-textarea') ); + if (!textarea) return; + const { destroy } = createElasticTextArea(textarea); return destroy; }); return template({ diff --git a/src/components/comment/comment.stories.js b/src/components/comment/comment.stories.js index bfc478d40..547db2a47 100644 --- a/src/components/comment/comment.stories.js +++ b/src/components/comment/comment.stories.js @@ -1,13 +1,14 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import { useEffect } from 'storybook/preview-api'; import { makeTwigInclude } from '../../make-twig-include.js'; -import { createElasticTextArea } from '../input/elastic-textarea.ts'; +import { createElasticTextArea } from '../input/elastic-textarea'; -import { initCommentReplyForm } from './comment.ts'; +import { initCommentReplyForm } from './comment'; import template from './comment.twig'; import authorDemo from './demo/author.twig'; import authorDemoSource from './demo/author.twig?raw'; -import { makeComment } from './demo/data.ts'; +import { makeComment } from './demo/data'; import memberDemo from './demo/member.twig'; import memberDemoSource from './demo/member.twig?raw'; const tyler = { @@ -15,9 +16,11 @@ const tyler = { link: 'https://cloudfour.com/is/tyler', }; const initCommentReplyForms = () => { - const textAreaEl = document.querySelector('.js-elastic-textarea'); - const commentReplyFormEl = document.querySelector( - '.js-comment-with-reply-form', + const textAreaEl = /** @type {HTMLTextAreaElement | null} */ ( + document.querySelector('.js-elastic-textarea') + ); + const commentReplyFormEl = /** @type {HTMLElement | null} */ ( + document.querySelector('.js-comment-with-reply-form') ); if (textAreaEl && commentReplyFormEl) { const textareaInstance = createElasticTextArea(textAreaEl); @@ -34,6 +37,7 @@ const initCommentReplyForms = () => { // The page would freeze up. Now, we create a random set of comments ahead of // time and just reference them in the stories. const totalRandomComments = 5; +/** @type {ReturnType[]} */ const randomComments = []; for (let i = 0; i < totalRandomComments; i++) { randomComments.push(makeComment()); @@ -41,7 +45,8 @@ for (let i = 0; i < totalRandomComments; i++) { const randomCommentWithReply = makeComment({ replies: 2 }); const randomNotApprovedComment = makeComment({ approved: false }); -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Comment', args: { isLoggedIn: false, @@ -57,6 +62,9 @@ export default { }, }; +export default meta; + +/** @type {StoryObj} */ export const Single = { parameters: { docs: { @@ -78,6 +86,7 @@ export const Single = { }, }; +/** @type {StoryObj} */ export const RoleAuthor = { name: 'Role: Author', parameters: { @@ -97,6 +106,7 @@ export const RoleAuthor = { }, }; +/** @type {StoryObj} */ export const RoleCloudFour = { name: 'Role: Cloud Four', parameters: { @@ -118,6 +128,7 @@ export const RoleCloudFour = { }, }; +/** @type {StoryObj} */ export const Unapproved = { parameters: { docs: { @@ -139,6 +150,7 @@ export const Unapproved = { }, }; +/** @type {StoryObj} */ export const WithSource = { name: 'With source', parameters: { @@ -169,6 +181,7 @@ export const WithSource = { }, }; +/** @type {StoryObj} */ export const WithReplyButton = { name: 'With reply button', args: { allowReplies: true, isLoggedIn: true }, @@ -195,6 +208,7 @@ export const WithReplyButton = { }, }; +/** @type {StoryObj} */ export const WithReplyThread = { name: 'With reply thread', parameters: { diff --git a/src/components/dot-leader/dot-leader.stories.js b/src/components/dot-leader/dot-leader.stories.js index aad59cccb..24105e4f1 100644 --- a/src/components/dot-leader/dot-leader.stories.js +++ b/src/components/dot-leader/dot-leader.stories.js @@ -1,7 +1,9 @@ +/** @import { ArgTypes, Meta, StoryObj } from '@storybook/html' */ import listDemo from './demo/list.twig'; import listDemoSource from './demo/list.twig?raw'; import topics from './demo/topics.json'; import template from './dot-leader.twig'; +/** @type {Partial} */ const argTypes = { label: { type: { name: 'string' } }, count: { type: { name: 'number' } }, @@ -16,16 +18,21 @@ const argDefaults = { count_noun_plural: 'articles', }; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Dot Leader', }; +export default meta; + +/** @type {StoryObj} */ export const Single = { args: argDefaults, argTypes, render: (args) => template(args), }; +/** @type {StoryObj} */ export const Link = { args: { href: 'https://cloudfour.com/topics/design-systems/', @@ -35,6 +42,7 @@ export const Link = { render: (args) => template(args), }; +/** @type {StoryObj} */ export const List = { parameters: { docs: { diff --git a/src/components/event-log/event-log.stories.js b/src/components/event-log/event-log.stories.js index b4e30eb31..347d691de 100644 --- a/src/components/event-log/event-log.stories.js +++ b/src/components/event-log/event-log.stories.js @@ -1,13 +1,19 @@ +/** @import { Args, Meta, StoryObj } from '@storybook/html' */ import events from './demo/events.json'; import eventsDemo from './demo/events.twig'; import eventsDemoSource from './demo/events.twig?raw'; +/** @param {Args} args */ const eventsDemoStory = (args) => eventsDemo({ items: events, ...args }); -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Event Log', render: eventsDemoStory.bind({}), }; +export default meta; + +/** @type {StoryObj} */ export const Example = { parameters: { docs: { diff --git a/src/components/footnote-group/footnote-group.stories.js b/src/components/footnote-group/footnote-group.stories.js index 834569489..10c659eb4 100644 --- a/src/components/footnote-group/footnote-group.stories.js +++ b/src/components/footnote-group/footnote-group.stories.js @@ -1,6 +1,8 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import template from './footnote-group.twig'; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Footnote/Footnote Group', argTypes: { compact: { type: { name: 'boolean' } }, @@ -13,8 +15,12 @@ export default { }), }; +export default meta; + +/** @type {StoryObj} */ export const Basic = {}; +/** @type {StoryObj} */ export const Compact = { args: { compact: true, diff --git a/src/components/footnote-link/footnote-link.stories.js b/src/components/footnote-link/footnote-link.stories.js index 6bdd53d47..42bbc427c 100644 --- a/src/components/footnote-link/footnote-link.stories.js +++ b/src/components/footnote-link/footnote-link.stories.js @@ -1,7 +1,9 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import template from './demo/demo.twig'; import footnoteLinkSource from './demo/demo.twig?raw'; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Footnote/Footnote Link', argTypes: { count: { type: { name: 'number' } }, @@ -10,6 +12,9 @@ export default { render: (args) => template(args), }; +export default meta; + +/** @type {StoryObj} */ export const Basic = { args: { count: 1 }, parameters: { diff --git a/src/components/footnote/footnote.stories.js b/src/components/footnote/footnote.stories.js index 9a3693237..bf50af8cb 100644 --- a/src/components/footnote/footnote.stories.js +++ b/src/components/footnote/footnote.stories.js @@ -1,7 +1,9 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import template from './demo/demo.twig'; import demoSource from './demo/demo.twig?raw'; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Footnote/Footnote', argTypes: { count: { type: { name: 'number' } }, @@ -11,6 +13,9 @@ export default { render: (args) => template(args), }; +export default meta; + +/** @type {StoryObj} */ export const Basic = { args: { count: 1, diff --git a/src/components/ground-nav/ground-nav-args.js b/src/components/ground-nav/ground-nav-args.js index c7cd58f73..834727596 100644 --- a/src/components/ground-nav/ground-nav-args.js +++ b/src/components/ground-nav/ground-nav-args.js @@ -1,3 +1,4 @@ +/** @import { ArgTypes, Args } from '@storybook/html' */ // eslint-disable-next-line import/order import skyNavMenu from '../sky-nav/demo/menu.json'; import groundNavMenu from './demo/menu.json'; @@ -38,6 +39,7 @@ export const defaultArgs = { /** * Storybook arg types for the defaultArgs */ +/** @type {Partial} */ export const defaultArgTypes = { alternate: { control: { type: 'boolean' } }, feature_count: { control: { type: 'number', min: 0, max: 2 } }, @@ -62,7 +64,10 @@ export const defaultArgTypes = { * * Takes the flat args object and structures it as the template expects. * - * @param {defaultArgs} args + * Storybook hands stories a loose args record rather than the exact shape of + * `defaultArgs`, so accept that and read the keys this builds from. + * + * @param {Args} args */ export const generateGroundNavProps = (args) => ({ menu, diff --git a/src/components/ground-nav/ground-nav.stories.js b/src/components/ground-nav/ground-nav.stories.js index eeeff0317..644691d83 100644 --- a/src/components/ground-nav/ground-nav.stories.js +++ b/src/components/ground-nav/ground-nav.stories.js @@ -1,3 +1,4 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import template from './demo/ground-nav-demo.twig'; import { defaultArgTypes, @@ -8,12 +9,16 @@ import { // Inline stories disabled so media queries will behave as expected within // embedded examples. -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Ground Nav', parameters: { docs: { story: { inline: false } }, layout: 'fullscreen' }, render: (args) => template(generateGroundNavProps(args)), }; +export default meta; + +/** @type {StoryObj} */ export const CloudFour = { name: 'Cloud Four', args: defaultArgs, @@ -24,6 +29,7 @@ export const CloudFour = { }, }; +/** @type {StoryObj} */ export const OneFeature = { name: 'One Feature', args: { @@ -37,6 +43,7 @@ export const OneFeature = { }, }; +/** @type {StoryObj} */ export const NoFeatures = { name: 'No Features', args: { @@ -50,6 +57,7 @@ export const NoFeatures = { }, }; +/** @type {StoryObj} */ export const Alternate = { args: { ...defaultArgs, diff --git a/src/components/heading/heading.stories.js b/src/components/heading/heading.stories.js index 6954883ef..15120899b 100644 --- a/src/components/heading/heading.stories.js +++ b/src/components/heading/heading.stories.js @@ -1,8 +1,10 @@ +/** @import { Meta, StoryContext, StoryObj } from '@storybook/html' */ import { makeTwigEmbedIfHtml } from '../../make-twig-include.js'; import demo from './demo/demo.twig'; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Heading', argTypes: { content: { @@ -54,7 +56,10 @@ export default { parameters: { docs: { source: { - transform: (_code, storyContext) => + transform: ( + /** @type {string} */ _code, + /** @type {StoryContext} */ storyContext, + ) => makeTwigEmbedIfHtml( '@cloudfour/components/heading/heading.twig', storyContext.args || storyContext.initialArgs || {}, @@ -66,60 +71,74 @@ export default { render: (args) => demo(args), }; +export default meta; + +/** @type {StoryObj} */ export const Example = { args: { content: 'Hello world', level: 1 }, }; +/** @type {StoryObj} */ export const LevelMinus2 = { name: 'Level Minus 2', args: { level: -2, content: 'Level -2' }, }; +/** @type {StoryObj} */ export const LevelMinus1 = { name: 'Level Minus 1', args: { level: -1, content: 'Level -1' }, }; +/** @type {StoryObj} */ export const Level0 = { name: 'Level 0', args: { level: 0, content: 'Level 0' }, }; +/** @type {StoryObj} */ export const Level1 = { name: 'Level 1', args: { level: 1, content: 'Level 1' }, }; +/** @type {StoryObj} */ export const Level2 = { name: 'Level 2', args: { level: 2, content: 'Level 2' }, }; +/** @type {StoryObj} */ export const Level3 = { name: 'Level 3', args: { level: 3, content: 'Level 3' }, }; +/** @type {StoryObj} */ export const Level4 = { name: 'Level 4', args: { level: 4, content: 'Level 4' }, }; +/** @type {StoryObj} */ export const Level5 = { name: 'Level 5', args: { level: 5, content: 'Level 5' }, }; +/** @type {StoryObj} */ export const Level6 = { name: 'Level 6', args: { level: 6, content: 'Level 6' }, }; +/** @type {StoryObj} */ export const DefaultWeight = { name: 'Default weight', args: { level: 1, content: 'Default weight' }, }; +/** @type {StoryObj} */ export const MediumWeight = { name: 'Medium weight', args: { @@ -129,6 +148,7 @@ export const MediumWeight = { }, }; +/** @type {StoryObj} */ export const LightWeight = { name: 'Light weight', args: { @@ -138,6 +158,7 @@ export const LightWeight = { }, }; +/** @type {StoryObj} */ export const Permalink = { args: { content: 'Hello world', @@ -147,6 +168,7 @@ export const Permalink = { }, }; +/** @type {StoryObj} */ export const Subheading = { args: { level: 1, diff --git a/src/components/icon/icon.stories.js b/src/components/icon/icon.stories.js index 1228fced4..5da841158 100644 --- a/src/components/icon/icon.stories.js +++ b/src/components/icon/icon.stories.js @@ -1,8 +1,10 @@ +/** @import { ArgTypes, Args, Meta, StoryObj } from '@storybook/html' */ import a11yDemo from './demo/a11y.twig'; import a11yDemoSource from './demo/a11y.twig?raw'; import inlineDemo from './demo/inline.twig'; import inlineDemoSource from './demo/inline.twig?raw'; import template from './icon.twig'; +/** @param {Args} args */ const iconStory = (args) => { // Don't bother with the inline option if it is the default if (args.inline === false) { @@ -10,6 +12,7 @@ const iconStory = (args) => { } return template(args); }; +/** @type {Partial} */ const defaultArgs = { name: { type: 'string' }, fallback: { type: 'string' }, @@ -20,10 +23,14 @@ const defaultArgs = { size: { type: 'string' }, }; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Icon', }; +export default meta; + +/** @type {StoryObj} */ export const Basic = { args: { name: 'heart', @@ -33,6 +40,7 @@ export const Basic = { render: (args) => iconStory(args), }; +/** @type {StoryObj} */ export const Muted = { args: { name: 'heart', @@ -43,6 +51,7 @@ export const Muted = { render: (args) => iconStory(args), }; +/** @type {StoryObj} */ export const MediumSize = { name: 'Medium Size', args: { @@ -53,6 +62,7 @@ export const MediumSize = { render: (args) => iconStory(args), }; +/** @type {StoryObj} */ export const LargeSize = { name: 'Large Size', args: { @@ -63,6 +73,7 @@ export const LargeSize = { render: (args) => iconStory(args), }; +/** @type {StoryObj} */ export const XLargeSize = { name: 'X-Large Size', args: { @@ -73,11 +84,13 @@ export const XLargeSize = { render: (args) => iconStory(args), }; +/** @type {StoryObj} */ export const Accessibility = { parameters: { docs: { source: { code: a11yDemoSource } } }, render: a11yDemo, }; +/** @type {StoryObj} */ export const Inline = { parameters: { docs: { source: { code: inlineDemoSource } } }, render: inlineDemo, diff --git a/src/components/input/input.stories.js b/src/components/input/input.stories.js index 6dd974f3b..c1f2284a0 100644 --- a/src/components/input/input.stories.js +++ b/src/components/input/input.stories.js @@ -1,3 +1,4 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import { useEffect } from 'storybook/preview-api'; import { makeTwigInclude } from '../../make-twig-include.js'; @@ -5,7 +6,7 @@ import { makeTwigInclude } from '../../make-twig-include.js'; import selectDemo from './demo/select.twig'; import selectDemoSource from './demo/select.twig?raw'; import './demo/styles.scss'; -import { createElasticTextArea } from './elastic-textarea.ts'; +import { createElasticTextArea } from './elastic-textarea'; import input from './input.twig'; const elasticTextAreaConfig = { @@ -21,11 +22,15 @@ const elasticTextAreaConfig = { // Inline stories disabled because when the same input element is rendered with // different settings within the same file, React syncs all their properties. -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Input', parameters: { docs: { story: { inline: false } } }, }; +export default meta; + +/** @type {StoryObj} */ export const TextElements = { name: 'Text Elements', args: { @@ -52,6 +57,7 @@ export const TextElements = { render: (args) => input(args), }; +/** @type {StoryObj} */ export const SelectElement = { name: 'Select Element', args: { @@ -66,6 +72,7 @@ export const SelectElement = { render: (args) => selectDemo(args), }; +/** @type {StoryObj} */ export const ElasticTextarea = { name: 'Elastic Textarea', args: elasticTextAreaConfig, @@ -88,7 +95,10 @@ export const ElasticTextarea = { // Use storybook hooks to trigger JS after story renders // @see https://github.com/storybookjs/storybook/issues/7786 useEffect(() => { - createElasticTextArea(document.querySelector('.js-elastic-textarea')); + const textarea = /** @type {HTMLTextAreaElement | null} */ ( + document.querySelector('.js-elastic-textarea') + ); + if (textarea) createElasticTextArea(textarea); }); return input(args); }, diff --git a/src/components/logo/logo.stories.js b/src/components/logo/logo.stories.js index 993936aba..8a8cad91c 100644 --- a/src/components/logo/logo.stories.js +++ b/src/components/logo/logo.stories.js @@ -1,3 +1,4 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import alignmentDemo from './demo/alignment.twig'; import logoTemplate from './logo.twig'; import './demo/alignment.scss'; @@ -9,11 +10,15 @@ const alignOptions = ['start', 'center', 'end']; // // @see https://github.com/aknuds1/html-to-react/issues/144 -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Logo', parameters: { docs: { story: { inline: false } } }, }; +export default meta; + +/** @type {StoryObj} */ export const BasicOptions = { name: 'Basic Options', args: { @@ -41,11 +46,13 @@ export const BasicOptions = { render: (args) => logoTemplate(args), }; +/** @type {StoryObj} */ export const BeforeAlignment = { name: 'Before Alignment', render: alignmentDemo.bind({}), }; +/** @type {StoryObj} */ export const AfterAlignment = { name: 'After Alignment', args: { align: true }, diff --git a/src/components/media-link/media-link.stories.js b/src/components/media-link/media-link.stories.js index 86f00157e..d40d8b88f 100644 --- a/src/components/media-link/media-link.stories.js +++ b/src/components/media-link/media-link.stories.js @@ -1,7 +1,9 @@ +/** @import { ArgTypes, Meta, StoryObj } from '@storybook/html' */ import { mediaArgTypes } from '../../objects/media/demo/arg-types.js'; import { avatarArgTypes } from '../avatar/demo/arg-types.js'; import template from './media-link.twig'; +/** @type {Partial} */ const mediaLinkArgTypes = { ...mediaArgTypes, label: { @@ -45,12 +47,16 @@ const mediaLinkArgTypes = { avatar_shape: avatarArgTypes.shape, }; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Media Link', argTypes: mediaLinkArgTypes, render: (args) => template(args), }; +export default meta; + +/** @type {StoryObj} */ export const Basic = { args: { href: 'https://cloudfour.com/thinks/performance-is-an-issue-of-equity/', diff --git a/src/components/media-summary/media-summary.stories.js b/src/components/media-summary/media-summary.stories.js index 931081f12..91fb78917 100644 --- a/src/components/media-summary/media-summary.stories.js +++ b/src/components/media-summary/media-summary.stories.js @@ -1,17 +1,23 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import bookDemo from './demo/book.twig'; import bookDemoSource from './demo/book.twig?raw'; import eventDemo from './demo/event.twig'; import eventDemoSource from './demo/event.twig?raw'; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Media Summary', }; +export default meta; + +/** @type {StoryObj} */ export const Event = { parameters: { docs: { source: { code: eventDemoSource } } }, render: (args) => eventDemo(args), }; +/** @type {StoryObj} */ export const Book = { parameters: { docs: { source: { code: bookDemoSource } } }, render: (args) => bookDemo(args), diff --git a/src/components/pagination/pagination.stories.js b/src/components/pagination/pagination.stories.js index 828d20ba2..fdfa0624f 100644 --- a/src/components/pagination/pagination.stories.js +++ b/src/components/pagination/pagination.stories.js @@ -1,11 +1,16 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import mockPaginationData from './demo/mock-pagination-data.js'; import template from './pagination.twig'; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Pagination', render: (args) => template({ pagination: mockPaginationData(args) }), }; +export default meta; + +/** @type {StoryObj} */ export const Example = { args: { current: 2, diff --git a/src/components/radio/radio.stories.js b/src/components/radio/radio.stories.js index 536387421..802dcc166 100644 --- a/src/components/radio/radio.stories.js +++ b/src/components/radio/radio.stories.js @@ -1,7 +1,9 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import withLabelDemo from './demo/with-label.twig'; import './demo/styles.scss'; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Radio', argTypes: { disabled: { type: { name: 'boolean' } }, @@ -9,6 +11,9 @@ export default { render: (args) => withLabelDemo(args), }; +export default meta; + +/** @type {StoryObj} */ export const Enabled = { parameters: { docs: { @@ -23,6 +28,7 @@ export const Enabled = { }, }; +/** @type {StoryObj} */ export const Disabled = { args: { disabled: true }, parameters: { diff --git a/src/components/sky-nav/sky-nav.stories.js b/src/components/sky-nav/sky-nav.stories.js index 8c5147275..1a75ccc9f 100644 --- a/src/components/sky-nav/sky-nav.stories.js +++ b/src/components/sky-nav/sky-nav.stories.js @@ -1,9 +1,10 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import { useEffect } from 'storybook/preview-api'; import { makeTwigInclude } from '../../make-twig-include.js'; import menu from './demo/menu.json'; -import { initSkyNav } from './sky-nav.ts'; +import { initSkyNav } from './sky-nav'; import template from './sky-nav.twig'; const basicStoryArgs = { include_main_demo: true, @@ -13,15 +14,18 @@ const basicStoryArgs = { // Inline stories disabled so media queries will behave as expected within // embedded examples. -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Sky Nav', parameters: { docs: { story: { inline: false } } }, decorators: [ (story) => { useEffect(() => { - const { destroy } = initSkyNav( - document.querySelector('.js-sky-nav-menu-toggle'), + const toggle = /** @type {HTMLButtonElement | null} */ ( + document.querySelector('.js-sky-nav-menu-toggle') ); + if (!toggle) return; + const { destroy } = initSkyNav(toggle); return destroy; }); return story(); @@ -29,6 +33,9 @@ export default { ], }; +export default meta; + +/** @type {StoryObj} */ export const Dark = { parameters: { layout: 'fullscreen', @@ -50,6 +57,7 @@ export const Dark = { }), }; +/** @type {StoryObj} */ export const Light = { parameters: { layout: 'fullscreen', diff --git a/src/components/subscribe/subscribe.stories.js b/src/components/subscribe/subscribe.stories.js index b9ee900de..751500827 100644 --- a/src/components/subscribe/subscribe.stories.js +++ b/src/components/subscribe/subscribe.stories.js @@ -1,22 +1,29 @@ +/** @import { Args, Meta, StoryObj } from '@storybook/html' */ import { useEffect } from 'storybook/preview-api'; import { makeTwigInclude } from '../../make-twig-include.js'; import template from './demo/storybook-demo.twig'; -import { createSubscribe } from './subscribe.ts'; +import { createSubscribe } from './subscribe'; // Helper function to initialize toggling button JS +/** @param {Args} args */ const templateStory = (args) => { useEffect(() => { - // Initialize the component - const subscribeComponent = createSubscribe( - document.querySelector('.js-subscribe'), + const container = /** @type {HTMLElement | null} */ ( + document.querySelector('.js-subscribe') ); - subscribeComponent.init(); - // Set up the demo destroy button + // Set up the demo destroy and init buttons const destroyBtn = document.querySelector('.js-destroy-button'); - destroyBtn.addEventListener('click', subscribeComponent.destroy); - // Set up the demo init button const initBtn = document.querySelector('.js-init-button'); + if (!container || !destroyBtn || !initBtn) return; + + // Initialize the component. `createSubscribe` returns nothing if the markup it + // needs is not there, in which case there is no demo to wire up. + const subscribeComponent = createSubscribe(container); + if (!subscribeComponent) return; + + subscribeComponent.init(); + destroyBtn.addEventListener('click', subscribeComponent.destroy); initBtn.addEventListener('click', subscribeComponent.init); return () => { // Make sure to cleanup @@ -28,7 +35,8 @@ const templateStory = (args) => { return template(args); }; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Subscribe', argTypes: { form_id: { @@ -68,7 +76,7 @@ export default { description: 'Sets the heading level. If `heading_tag`, is specified, `heading_level` will override only visual styles.', table: { - defaultValue: { summary: 2 }, + defaultValue: { summary: '2' }, }, control: { type: 'range', @@ -195,6 +203,9 @@ export default { render: (args) => templateStory(args), }; +export default meta; + +/** @type {StoryObj} */ export const Default = { args: { form_id: 'example-demo', diff --git a/src/components/table/table.stories.js b/src/components/table/table.stories.js index 9a5abcac9..bca786366 100644 --- a/src/components/table/table.stories.js +++ b/src/components/table/table.stories.js @@ -1,5 +1,7 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import basicDemo from './demo/basic.twig'; import data from './demo/data.json'; +/** @param {string} [tableClass] */ const basicTableCodeExample = (tableClass) => { const withArgs = tableClass ? ` with { table_class: '${tableClass}' }` : ''; return `{% embed '@cloudfour/components/table/table.twig'${withArgs} only %} @@ -23,7 +25,8 @@ const basicTableCodeExample = (tableClass) => { {% endembed %}`; }; -export default { +/** @type {Meta} */ +const meta = { title: 'Components/Table', args: { hasHeader: true, @@ -62,10 +65,14 @@ export default { render: (args) => basicDemo({ ...args, tableData: data }), }; +export default meta; + +/** @type {StoryObj} */ export const Basic = { parameters: { docs: { source: { code: basicTableCodeExample() } } }, }; +/** @type {StoryObj} */ export const Ruled = { args: { isRuled: true }, parameters: { @@ -73,6 +80,7 @@ export const Ruled = { }, }; +/** @type {StoryObj} */ export const Striped = { args: { isStriped: true }, parameters: { @@ -80,6 +88,7 @@ export const Striped = { }, }; +/** @type {StoryObj} */ export const NumericData = { name: 'Numeric Data', args: { numericData: true }, diff --git a/src/design/brand.stories.js b/src/design/brand.stories.js index a5cfb588b..e3f1be662 100644 --- a/src/design/brand.stories.js +++ b/src/design/brand.stories.js @@ -1,8 +1,13 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import logoSrc from '../assets/brand/logo.svg'; -export default { +/** @type {Meta} */ +const meta = { title: 'Design/Brand', render: () => `Cloud Four`, }; +export default meta; + +/** @type {StoryObj} */ export const Logo = {}; diff --git a/src/design/defaults.stories.js b/src/design/defaults.stories.js index 52c7d4c15..8705fc8fe 100644 --- a/src/design/defaults.stories.js +++ b/src/design/defaults.stories.js @@ -1,39 +1,50 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import figureImage from './demo/tiny-web-stacks.png'; -export default { +/** @type {Meta} */ +const meta = { title: 'Design/Defaults', }; +export default meta; + +/** @type {StoryObj} */ export const HeadingLevel1 = { name: 'Heading level 1', render: () => `

Heading level 1

`, }; +/** @type {StoryObj} */ export const HeadingLevel2 = { name: 'Heading level 2', render: () => `

Heading level 2

`, }; +/** @type {StoryObj} */ export const HeadingLevel3 = { name: 'Heading level 3', render: () => `

Heading level 3

`, }; +/** @type {StoryObj} */ export const HeadingLevel4 = { name: 'Heading level 4', render: () => `

Heading level 4

`, }; +/** @type {StoryObj} */ export const HeadingLevel5 = { name: 'Heading level 5', render: () => `
Heading level 5
`, }; +/** @type {StoryObj} */ export const HeadingLevel6 = { name: 'Heading level 6', render: () => `
Heading level 6
`, }; +/** @type {StoryObj} */ export const InlineElements = { name: 'Inline elements', render: () => `

@@ -41,6 +52,7 @@ export const InlineElements = {

`, }; +/** @type {StoryObj} */ export const Blockquote = { render: () => `

CSS Grid Layout excels at dividing a page into major regions or defining the relationship in terms of size, position, and layer, between parts of a control built from HTML primitives.

@@ -51,6 +63,7 @@ export const Blockquote = {
`, }; +/** @type {StoryObj} */ export const UnorderedList = { name: 'Unordered list', render: () => `
    @@ -66,6 +79,7 @@ export const UnorderedList = {
`, }; +/** @type {StoryObj} */ export const OrderedList = { name: 'Ordered list', render: () => `
    @@ -81,6 +95,7 @@ export const OrderedList = {
`, }; +/** @type {StoryObj} */ export const DescriptionList = { name: 'Description list', render: () => `
@@ -93,6 +108,7 @@ export const DescriptionList = {
`, }; +/** @type {StoryObj} */ export const Figure = { render: () => `
pancakes @@ -100,6 +116,7 @@ export const Figure = {
`, }; +/** @type {StoryObj} */ export const CodeBlock = { name: 'Code block', render: () => { @@ -110,6 +127,7 @@ export const CodeBlock = { }, }; +/** @type {StoryObj} */ export const HorizontalRule = { name: 'Horizontal rule', render: () => `

…and so ends this topic.

@@ -117,6 +135,7 @@ export const HorizontalRule = {

Shifting our focus to something else entirely…

`, }; +/** @type {StoryObj} */ export const DetailsSummary = { name: 'Details/Summary', render: () => `
diff --git a/src/design/favicons.stories.js b/src/design/favicons.stories.js index 38e2402ec..8da3b5ecf 100644 --- a/src/design/favicons.stories.js +++ b/src/design/favicons.stories.js @@ -1,12 +1,17 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import faviconApps from './demo/favicon-apps.twig'; import faviconTabs from './demo/favicon-tabs.twig'; import './demo/favicon-apps.scss'; import './demo/favicon-tabs.scss'; -export default { +/** @type {Meta} */ +const meta = { title: 'Design/Favicons', }; +export default meta; + +/** @type {StoryObj} */ export const Favicons = { parameters: { layout: 'fullscreen', @@ -20,6 +25,7 @@ export const Favicons = { render: faviconTabs, }; +/** @type {StoryObj} */ export const FaviconsDev = { name: 'Favicons (Dev)', parameters: { @@ -34,6 +40,7 @@ export const FaviconsDev = { render: () => faviconTabs({ dev: true }), }; +/** @type {StoryObj} */ export const Android = { parameters: { docs: { @@ -60,6 +67,7 @@ export const Android = { render: faviconApps, }; +/** @type {StoryObj} */ export const Apple = { parameters: { docs: { diff --git a/src/design/illustrations.stories.js b/src/design/illustrations.stories.js index 0698c56ea..a10cb8c67 100644 --- a/src/design/illustrations.stories.js +++ b/src/design/illustrations.stories.js @@ -1,3 +1,4 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import avatarDefaultSrc from '../assets/illustrations/avatar/default.svg'; import avatarTransparentSrc from '../assets/illustrations/avatar/transparent.svg'; import responsiveImage from '../assets/illustrations/responsive-fallback.svg'; @@ -17,23 +18,25 @@ const featureImages = import.meta.glob( const featureImageData = Object.entries(featureImages) .map(([filePath, src]) => ({ - name: filePath - .split('/') - .pop() - .replace(/\.svg$/, ''), + name: (filePath.split('/').pop() ?? '').replace(/\.svg$/, ''), src, })) .toSorted((a, b) => a.name.localeCompare(b.name)); -export default { +/** @type {Meta} */ +const meta = { title: 'Design/Illustrations', }; +export default meta; + +/** @type {StoryObj} */ export const FeatureImages = { name: 'Feature images', render: () => imageDeck({ images: featureImageData }), }; +/** @type {StoryObj} */ export const ResponsiveFallbackImage = { name: 'Responsive fallback image', render: () => @@ -43,18 +46,23 @@ export const ResponsiveFallbackImage = { }), }; +/** @type {StoryObj} */ export const DefaultAvatar = { name: 'Default avatar', render: () => `Default avatar`, }; +/** @type {StoryObj} */ export const TransparentAvatar = { name: 'Transparent avatar', parameters: { docs: { // The checkerboard is only there to show the transparency, so keep it out of // the source snippet. - source: { transform: (code) => code.replaceAll(/ style="([^"]+)"/g, '') }, + source: { + transform: (/** @type {string} */ code) => + code.replaceAll(/ style="([^"]+)"/g, ''), + }, }, }, render: () => diff --git a/src/design/themes.stories.js b/src/design/themes.stories.js index 034a94904..b9d1ffcce 100644 --- a/src/design/themes.stories.js +++ b/src/design/themes.stories.js @@ -1,23 +1,31 @@ +/** @import { Args, Meta, StoryObj } from '@storybook/html' */ import alternateDemo from './demo/theme-alternate.twig'; import demo from './demo/theme.twig'; +/** @param {Args} args */ const demoStory = (args) => demo(args); -export default { +/** @type {Meta} */ +const meta = { title: 'Design/Themes', }; +export default meta; + +/** @type {StoryObj} */ export const Light = { args: { theme: 'light' }, parameters: { theme: 't-light' }, render: demoStory.bind({}), }; +/** @type {StoryObj} */ export const Dark = { args: { theme: 'dark' }, parameters: { theme: 't-dark' }, render: demoStory.bind({}), }; +/** @type {StoryObj} */ export const AlternateWithLight = { name: 'Alternate with Light', args: { theme: 'light' }, @@ -25,6 +33,7 @@ export const AlternateWithLight = { render: (args) => alternateDemo(args), }; +/** @type {StoryObj} */ export const AlternateWithDark = { name: 'Alternate with Dark', args: { theme: 'dark' }, diff --git a/src/objects/article-header/article-header.stories.js b/src/objects/article-header/article-header.stories.js index ee822123b..2b16e4bb7 100644 --- a/src/objects/article-header/article-header.stories.js +++ b/src/objects/article-header/article-header.stories.js @@ -1,11 +1,16 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import exampleDemo from './demo/example.twig'; import exampleDemoSource from './demo/example.twig?raw'; -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Article Header', render: () => exampleDemo(), }; +export default meta; + +/** @type {StoryObj} */ export const Example = { parameters: { docs: { diff --git a/src/objects/bio/bio.stories.js b/src/objects/bio/bio.stories.js index ef07def75..41d9aa518 100644 --- a/src/objects/bio/bio.stories.js +++ b/src/objects/bio/bio.stories.js @@ -1,11 +1,16 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import defaultDemo from './demo/demo.twig'; import defaultDemoSource from './demo/demo.twig?raw'; -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Bio', render: defaultDemo, }; +export default meta; + +/** @type {StoryObj} */ export const Default = { parameters: { docs: { diff --git a/src/objects/bunch/bunch.stories.js b/src/objects/bunch/bunch.stories.js index 7641eb0cd..fb73d80ae 100644 --- a/src/objects/bunch/bunch.stories.js +++ b/src/objects/bunch/bunch.stories.js @@ -1,3 +1,4 @@ +/** @import { Args, Meta, StoryObj } from '@storybook/html' */ import { shuffle } from 'lodash'; import avatarsDemo from './demo/avatars.twig'; @@ -6,6 +7,7 @@ const demoImages = import.meta.glob('./demo/*.png', { import: 'default', }); const demoImageSrcs = Object.values(demoImages); +/** @param {Args} args */ const avatarsDemoStory = (args) => { const srcs = shuffle(demoImageSrcs).slice(0, args.count); return avatarsDemo({ srcs }); @@ -18,7 +20,8 @@ const avatarsDemoSrc = `{% embed '@cloudfour/objects/bunch/bunch.twig' only %} {% endblock %} {% endembed %}`; -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Bunch', args: { count: 3, @@ -38,6 +41,9 @@ export default { render: avatarsDemoStory.bind({}), }; +export default meta; + +/** @type {StoryObj} */ export const OfAvatars = { name: 'Of avatars', parameters: { diff --git a/src/objects/button-group/button-group.stories.js b/src/objects/button-group/button-group.stories.js index 2fe247ca3..65a5d4d0e 100644 --- a/src/objects/button-group/button-group.stories.js +++ b/src/objects/button-group/button-group.stories.js @@ -1,6 +1,8 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import demo from './demo/demo.twig'; -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Button Group', args: { grow: false, @@ -25,6 +27,9 @@ export default { render: (args) => demo(args), }; +export default meta; + +/** @type {StoryObj} */ export const Default = { parameters: { docs: { @@ -44,6 +49,7 @@ export const Default = { }, }; +/** @type {StoryObj} */ export const Grow = { args: { count: 5, grow: true }, parameters: { diff --git a/src/objects/container/container.stories.js b/src/objects/container/container.stories.js index 5be68a3e8..1a80f41b2 100644 --- a/src/objects/container/container.stories.js +++ b/src/objects/container/container.stories.js @@ -1,6 +1,8 @@ +/** @import { Args, Meta, StoryObj } from '@storybook/html' */ import basicDemo from './demo/basic.twig'; import fillDemo from './demo/fill.twig'; import fillDemoSource from './demo/fill.twig?raw'; +/** @param {Args} args */ const basicDemoStory = (args) => { const modifiers = []; if (args.prose) { @@ -21,7 +23,8 @@ const padOptions = ['block', 'inline']; // Inline stories disabled so media queries will behave as expected within // embedded examples. -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Container', argTypes: { prose: { @@ -40,6 +43,9 @@ export default { }, }; +export default meta; + +/** @type {StoryObj} */ export const Basic = { args: { prose: false, pad: padOptions }, parameters: { @@ -59,6 +65,7 @@ export const Basic = { render: basicDemoStory.bind({}), }; +/** @type {StoryObj} */ export const Prose = { args: { prose: true, pad: padOptions }, parameters: { @@ -78,6 +85,7 @@ export const Prose = { render: basicDemoStory.bind({}), }; +/** @type {StoryObj} */ export const Fill = { argTypes: {}, parameters: { diff --git a/src/objects/deck/deck.stories.js b/src/objects/deck/deck.stories.js index 785faa873..58ac9f0c7 100644 --- a/src/objects/deck/deck.stories.js +++ b/src/objects/deck/deck.stories.js @@ -1,10 +1,18 @@ +/** @import { Args, Meta, StoryContext, StoryObj } from '@storybook/html' */ import alignmentDemo from './demo/alignment.twig'; import articles from './demo/articles.json'; import articlesDemo from './demo/articles.twig'; +/** @param {Args} args */ const articlesStory = (args) => articlesDemo({ items: articles, ...args }); +/** @param {Args} args */ const alignmentStory = (args) => alignmentDemo({ items: articles, ...args }); // Custom function for generating story source from args given +/** + * @param {string} _src + * @param {StoryContext} storyContext + */ const articlesTemplateSource = (_src, storyContext) => { + /** @type {Args} */ const args = storyContext.args || storyContext.initialArgs || {}; let twigArgs = ''; if ( @@ -23,13 +31,16 @@ const articlesTemplateSource = (_src, storyContext) => { {% endblock %} {% endembed %}`; }; -const alignmentClasses = { - None: '', - Full: 'alignfull', - Wide: 'alignwide', +// Keyed by value rather than label: `options` is the list of values, and +// `control.labels` maps each one to what the select shows. +const alignmentLabels = { + '': 'None', + alignfull: 'Full', + alignwide: 'Wide', }; -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Deck', args: { columns: 3, @@ -40,8 +51,8 @@ export default { argTypes: { class: { type: { name: 'string' } }, alignment: { - options: alignmentClasses, - control: { type: 'select' }, + options: Object.keys(alignmentLabels), + control: { type: 'select', labels: alignmentLabels }, }, columns: { control: { @@ -87,11 +98,15 @@ export default { }, }; +export default meta; + +/** @type {StoryObj} */ export const Basic = { parameters: { docs: { story: { iframeHeight: '400px' } } }, render: articlesStory.bind({}), }; +/** @type {StoryObj} */ export const Alignment = { parameters: { docs: { story: { iframeHeight: '200px' } } }, args: { @@ -102,6 +117,7 @@ export const Alignment = { render: alignmentStory.bind({}), }; +/** @type {StoryObj} */ export const Columns = { parameters: { docs: { story: { iframeHeight: '400px' } } }, args: { @@ -111,6 +127,7 @@ export const Columns = { render: articlesStory.bind({}), }; +/** @type {StoryObj} */ export const HorizontalCard = { parameters: { docs: { story: { iframeHeight: '500px' } } }, name: 'Horizontal Card', diff --git a/src/objects/embed/embed.stories.js b/src/objects/embed/embed.stories.js index 86a9888cd..70807fc85 100644 --- a/src/objects/embed/embed.stories.js +++ b/src/objects/embed/embed.stories.js @@ -1,3 +1,4 @@ +/** @import { ArgTypes, Meta, StoryContext, StoryObj } from '@storybook/html' */ import tokens from '../../compiled/tokens/js/tokens.js'; import roundedDemoSrc from './demo/avatar.png'; @@ -13,6 +14,7 @@ const modifierClasses = [ '', ...Object.keys(aspectRatioTokens).map((key) => `o-embed--${key}`), ]; +/** @type {Partial} */ const defaultArgTypes = { class: { options: modifierClasses, @@ -25,6 +27,10 @@ const defaultArgs = { class: 'o-embed--wide', }; // Custom embed source function to preserve args in source code examples +/** + * @param {string} _src + * @param {StoryContext} storyContext + */ const embedTransformSource = (_src, storyContext) => { const args = storyContext.args || storyContext.initialArgs || {}; const argsString = @@ -38,17 +44,22 @@ const embedTransformSource = (_src, storyContext) => { {% endembed %}`; }; -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Embed', parameters: { docs: { source: { transform: embedTransformSource } } }, }; +export default meta; + +/** @type {StoryObj} */ export const Image = { args: defaultArgs, argTypes: defaultArgTypes, render: (args) => imageDemo({ ...args, src: imageDemoImgSrc }), }; +/** @type {StoryObj} */ export const Picture = { args: defaultArgs, argTypes: defaultArgTypes, @@ -60,12 +71,14 @@ export const Picture = { }), }; +/** @type {StoryObj} */ export const Video = { args: defaultArgs, argTypes: defaultArgTypes, render: (args) => videoDemo(args), }; +/** @type {StoryObj} */ export const Rounded = { args: { class: 'u-rounded-full', @@ -78,6 +91,7 @@ export const Rounded = { }), }; +/** @type {StoryObj} */ export const Responsive = { args: { class: 'o-embed--full@s o-embed--wide@m o-embed--cinema@l', diff --git a/src/objects/feature-group/feature-group.stories.js b/src/objects/feature-group/feature-group.stories.js index bb9944ffb..78c6f11d8 100644 --- a/src/objects/feature-group/feature-group.stories.js +++ b/src/objects/feature-group/feature-group.stories.js @@ -1,12 +1,17 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import defaultDemo from './demo/demo.twig'; import defaultDemoSource from './demo/demo.twig?raw'; -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Feature Group', parameters: { docs: { story: { inline: false } } }, render: defaultDemo, }; +export default meta; + +/** @type {StoryObj} */ export const Default = { parameters: { docs: { diff --git a/src/objects/form-group/form-group.stories.js b/src/objects/form-group/form-group.stories.js index f5f979022..241342d83 100644 --- a/src/objects/form-group/form-group.stories.js +++ b/src/objects/form-group/form-group.stories.js @@ -1,17 +1,23 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import badgeDemo from './demo/badge.twig'; import badgeDemoSource from './demo/badge.twig?raw'; import basicDemo from './demo/input.twig'; import basicDemoSource from './demo/input.twig?raw'; -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Form Group', }; +export default meta; + +/** @type {StoryObj} */ export const Basic = { parameters: { docs: { source: { code: basicDemoSource } } }, render: () => basicDemo(), }; +/** @type {StoryObj} */ export const WithBadge = { name: 'With badge', parameters: { docs: { source: { code: badgeDemoSource } } }, diff --git a/src/objects/hype-group/hype-group.stories.js b/src/objects/hype-group/hype-group.stories.js index 9e0a59ec7..525d0fd3c 100644 --- a/src/objects/hype-group/hype-group.stories.js +++ b/src/objects/hype-group/hype-group.stories.js @@ -1,3 +1,4 @@ +/** @import { Args, Meta, StoryContext, StoryObj } from '@storybook/html' */ import multipleDemo from './demo/multiple.twig'; import singleDemo from './demo/single.twig'; const defaultArgs = { @@ -7,6 +8,10 @@ const defaultArgs = { example_object_img_src: '/media/feature-ozzie-wide.jpg', example_object_img_size: 480, }; +/** + * @param {Args} args + * @param {boolean} [multiple] + */ const demoStory = (args, multiple) => { args = { ...defaultArgs, ...args }; if (args.object_shape === 'square') { @@ -14,6 +19,10 @@ const demoStory = (args, multiple) => { } return multiple ? multipleDemo(args) : singleDemo(args); }; +/** + * @param {string} _src + * @param {StoryContext} storyContext + */ const singleTransformSource = (_src, storyContext) => { const args = storyContext.args || storyContext.initialArgs || {}; if (args.object_shape === 'square') { @@ -41,11 +50,15 @@ const singleTransformSource = (_src, storyContext) => { {% endembed %}`; }; -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Hype Group', argTypes: { reverse: { type: 'boolean' }, - object_shape: { type: 'select', options: ['circle', 'square'] }, + object_shape: { + options: ['circle', 'square'], + control: { type: 'select' }, + }, object_outline: { type: 'boolean' }, class: { type: 'string' }, intro_class: { type: 'string' }, @@ -68,6 +81,9 @@ export default { }, }; +export default meta; + +/** @type {StoryObj} */ export const Single = { args: defaultArgs, parameters: { @@ -79,6 +95,7 @@ export const Single = { render: (args) => demoStory(args), }; +/** @type {StoryObj} */ export const WithOptions = { name: 'With options', args: { @@ -96,6 +113,7 @@ export const WithOptions = { render: (args) => demoStory(args), }; +/** @type {StoryObj} */ export const Multiple = { parameters: { docs: { story: { iframeHeight: '640px' } } }, args: { diff --git a/src/objects/input-group/input-group.stories.js b/src/objects/input-group/input-group.stories.js index 78adb416b..689ca08fb 100644 --- a/src/objects/input-group/input-group.stories.js +++ b/src/objects/input-group/input-group.stories.js @@ -1,7 +1,9 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import inputGroupDemo from './demo/input-group-demo.twig'; import inputGroupDemoSource from './demo/input-group-demo.twig?raw'; -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Input Group', argTypes: { class: { @@ -17,6 +19,9 @@ export default { render: (args) => inputGroupDemo(args), }; +export default meta; + +/** @type {StoryObj} */ export const Example = { parameters: { docs: { diff --git a/src/objects/list/list.stories.js b/src/objects/list/list.stories.js index 3c13f4ee4..06f8fa90c 100644 --- a/src/objects/list/list.stories.js +++ b/src/objects/list/list.stories.js @@ -1,3 +1,4 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import template from './list.twig'; const defaultItems = [ 'Design Tokens', @@ -9,7 +10,8 @@ const defaultItems = [ ]; const tagNames = ['ul', 'ol']; -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/List', args: { items: defaultItems, @@ -17,10 +19,10 @@ export default { }, argTypes: { class: { type: { name: 'string' } }, - items: { type: { name: 'array' } }, + items: { type: { name: 'array', value: { name: 'string' } } }, tag_name: { options: tagNames, - type: { name: 'enum' }, + type: { name: 'enum', value: tagNames }, control: { type: 'inline-radio' }, }, }, @@ -28,14 +30,19 @@ export default { render: (args) => template(args), }; +export default meta; + +/** @type {StoryObj} */ export const Default = { parameters: { docs: { story: { iframeHeight: '200px' } } }, }; +/** @type {StoryObj} */ export const Inline = { args: { class: 'o-list--inline' }, }; +/** @type {StoryObj} */ export const Column = { args: { class: 'o-list--3-column@l' }, }; diff --git a/src/objects/logo-group/logo-group.stories.js b/src/objects/logo-group/logo-group.stories.js index 9c383e912..3428ecd73 100644 --- a/src/objects/logo-group/logo-group.stories.js +++ b/src/objects/logo-group/logo-group.stories.js @@ -1,6 +1,11 @@ +/** @import { Args, Meta, StoryContext, StoryObj } from '@storybook/html' */ import demo from './demo/demo.twig'; import logos from './demo/logos.json'; const justifyOptions = ['start', 'center', 'end']; +/** + * @param {string} _src + * @param {StoryContext} storyContext + */ const demoTemplateSource = (_src, storyContext) => { const args = storyContext.args || storyContext.initialArgs; const twigArgs = @@ -13,9 +18,11 @@ const demoTemplateSource = (_src, storyContext) => { {% endblock %} {% endembed %}`; }; +/** @param {Args} args */ const demoStory = (args) => demo({ ...args, logos }); -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Logo Group', argTypes: { justify: { @@ -34,8 +41,12 @@ export default { render: (args) => demoStory(args), }; +export default meta; + +/** @type {StoryObj} */ export const Default = {}; +/** @type {StoryObj} */ export const CenteredWithPadding = { name: 'Centered with padding', args: { diff --git a/src/objects/media/demo/arg-types.js b/src/objects/media/demo/arg-types.js index 338e7b36b..3696d23e2 100644 --- a/src/objects/media/demo/arg-types.js +++ b/src/objects/media/demo/arg-types.js @@ -1,3 +1,5 @@ +/** @import { ArgTypes } from '@storybook/html' */ +/** @type {Partial} */ export const mediaArgTypes = { tag_name: { type: { name: 'string' }, diff --git a/src/objects/media/media.stories.js b/src/objects/media/media.stories.js index 7f7fb1abf..44c0b2fb6 100644 --- a/src/objects/media/media.stories.js +++ b/src/objects/media/media.stories.js @@ -1,3 +1,4 @@ +/** @import { Meta, StoryContext, StoryObj } from '@storybook/html' */ import { mediaArgTypes } from './demo/arg-types.js'; import calendarDateDemo from './demo/calendar-date.twig'; import calendarDateDemoSource from './demo/calendar-date.twig?raw'; @@ -9,6 +10,10 @@ const exampleText = 'One of the things that is really clear to us (and that we hear often from our clients) is that the way we engage with our clients is unique. In fact, bringing clients in early and often to our process is one of our specialties at Cloud Four.'; // We define a source transform for the image demo since it needs to // respond to args more dynamically than other demos. +/** + * @param {string} _src + * @param {StoryContext} storyContext + */ const imageDemoTransformSource = (_src, storyContext) => { const { args } = storyContext; const withStr = args?.reverse @@ -28,7 +33,8 @@ const imageDemoTransformSource = (_src, storyContext) => { {% endembed %}`; }; -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Media', args: { imgSrc: meganProfileImage, @@ -42,6 +48,9 @@ export default { }, }; +export default meta; + +/** @type {StoryObj} */ export const Image = { parameters: { docs: { @@ -51,6 +60,7 @@ export const Image = { render: (args) => imageDemo(args), }; +/** @type {StoryObj} */ export const GenerousSpacing = { name: 'Generous Spacing', args: { generous: true }, @@ -62,6 +72,7 @@ export const GenerousSpacing = { render: (args) => imageDemo(args), }; +/** @type {StoryObj} */ export const ImageReversed = { name: 'Image Reversed', args: { reverse: true }, @@ -73,6 +84,7 @@ export const ImageReversed = { render: (args) => imageDemo(args), }; +/** @type {StoryObj} */ export const RelativeSize = { name: 'Relative Size', args: { class: 'o-media--1-by-3' }, @@ -84,18 +96,21 @@ export const RelativeSize = { render: (args) => imageDemo(args), }; +/** @type {StoryObj} */ export const CheckboxLabel = { name: 'Checkbox Label', parameters: { docs: { source: { code: checkboxDemoSource } } }, render: checkboxDemo, }; +/** @type {StoryObj} */ export const EventSummary = { name: 'Event Summary', parameters: { docs: { source: { code: calendarDateDemoSource } } }, render: calendarDateDemo, }; +/** @type {StoryObj} */ export const Jaunty = { args: { jaunty: true }, parameters: { @@ -106,6 +121,7 @@ export const Jaunty = { render: (args) => imageDemo(args), }; +/** @type {StoryObj} */ export const AlignDefault = { name: 'Align Default', args: { @@ -119,6 +135,7 @@ export const AlignDefault = { render: (args) => imageDemo(args), }; +/** @type {StoryObj} */ export const AlignStart = { name: 'Align Start', args: { diff --git a/src/objects/overview/overview.stories.js b/src/objects/overview/overview.stories.js index 9919c9539..7fd304376 100644 --- a/src/objects/overview/overview.stories.js +++ b/src/objects/overview/overview.stories.js @@ -1,3 +1,4 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import topics from '../../components/dot-leader/demo/topics.json'; import advancedDemo from './demo/advanced.twig'; @@ -8,11 +9,15 @@ import basicDemoSource from './demo/basic.twig?raw'; // Inline stories disabled so media queries will behave as expected within // embedded examples. -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Overview', parameters: { docs: { story: { inline: false } } }, }; +export default meta; + +/** @type {StoryObj} */ export const Basic = { parameters: { docs: { @@ -25,6 +30,7 @@ export const Basic = { render: () => basicDemo(), }; +/** @type {StoryObj} */ export const AdvancedUsage = { name: 'Advanced Usage', parameters: { diff --git a/src/objects/page/page.stories.js b/src/objects/page/page.stories.js index 3cea5bfc5..fddcefc6d 100644 --- a/src/objects/page/page.stories.js +++ b/src/objects/page/page.stories.js @@ -1,3 +1,4 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import { useEffect } from 'storybook/preview-api'; import exampleDemoWithAlert from './demo/example-with-alert.twig'; @@ -5,7 +6,8 @@ import exampleDemoWithAlertSource from './demo/example-with-alert.twig?raw'; import exampleDemo from './demo/example.twig'; import exampleDemoSource from './demo/example.twig?raw'; -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Page', parameters: { docs: { story: { inline: false } }, layout: 'fullscreen' }, decorators: [ @@ -14,13 +16,19 @@ export default { // Set this story's `body` element to full-height document.body.style.height = '100%'; // Prevent Storybook's container from affecting this layout - document.querySelector('#storybook-root').style.display = 'contents'; + const root = /** @type {HTMLElement | null} */ ( + document.querySelector('#storybook-root') + ); + if (root) root.style.display = 'contents'; }); return story(); }, ], }; +export default meta; + +/** @type {StoryObj} */ export const Example = { parameters: { layout: 'fullscreen', @@ -32,6 +40,7 @@ export const Example = { render: () => exampleDemo(), }; +/** @type {StoryObj} */ export const ExampleWithAlert = { name: 'Example with Alert', parameters: { diff --git a/src/objects/rhythm/rhythm.stories.js b/src/objects/rhythm/rhythm.stories.js index 14ed26692..1081ec801 100644 --- a/src/objects/rhythm/rhythm.stories.js +++ b/src/objects/rhythm/rhythm.stories.js @@ -1,12 +1,18 @@ +/** @import { ArgTypes, Meta, StoryContext, StoryObj } from '@storybook/html' */ import demo from './demo/example.twig'; import nestingDemo from './demo/nesting.twig'; import nestingDemoSource from './demo/nesting.twig?raw'; +/** @param {StoryContext} storyContext */ const argsStringFromStoryContext = (storyContext) => { const args = storyContext.args || storyContext.initialArgs || {}; return Object.keys(args).length > 0 ? ` with ${JSON.stringify(args, null, 2)}` : ''; }; +/** + * @param {string} _src + * @param {StoryContext} storyContext + */ const demoTransformSource = (_src, storyContext) => { const argsString = argsStringFromStoryContext(storyContext); return `{% embed '@cloudfour/objects/rhythm/rhythm.twig'${argsString} only %} @@ -15,6 +21,10 @@ const demoTransformSource = (_src, storyContext) => { {% endblock %} {% endembed %}`; }; +/** + * @param {string} _src + * @param {StoryContext} storyContext + */ const nestingDemoTransformSource = (_src, storyContext) => { const argsString = argsStringFromStoryContext(storyContext); return nestingDemoSource.replace(".twig' %}", `.twig'${argsString} only %}`); @@ -27,17 +37,18 @@ const amountOptions = [ 'generous', 'lavish', ]; +/** @type {Partial} */ const argTypes = { amount: { options: amountOptions, - type: { name: 'enum' }, + type: { name: 'enum', value: amountOptions }, control: { type: 'select' }, description: 'Amount of vertical space to apply between adjacent elements as a keyword.', }, heading_amount: { options: ['', 'generous', 'lavish'], - type: { name: 'enum' }, + type: { name: 'enum', value: ['', 'generous', 'lavish'] }, control: { type: 'select' }, description: 'Amount of vertical space to apply before headings as a keyword.', @@ -57,7 +68,8 @@ const argTypes = { }, }; -export default { +/** @type {Meta} */ +const meta = { title: 'Objects/Rhythm', argTypes, parameters: { @@ -65,28 +77,34 @@ export default { }, }; +export default meta; + +/** @type {StoryObj} */ export const Example = { render: (args) => demo(args), }; +/** @type {StoryObj} */ export const Amount = { args: { amount: 'condensed' }, render: (args) => demo(args), }; +/** @type {StoryObj} */ export const HeadingAmount = { name: 'Heading Amount', args: { amount: 'condensed', heading_amount: 'generous' }, render: (args) => demo(args), }; +/** @type {StoryObj} */ export const Nesting = { args: { amount: 'condensed' }, argTypes: { ...argTypes, nested_amount: { options: amountOptions, - type: { name: 'enum' }, + type: { name: 'enum', value: amountOptions }, control: { type: 'select' }, }, }, diff --git a/src/utilities/border/border.stories.js b/src/utilities/border/border.stories.js index 60be67b1c..872e891a9 100644 --- a/src/utilities/border/border.stories.js +++ b/src/utilities/border/border.stories.js @@ -1,3 +1,5 @@ +/** @import { Args, Meta, StoryObj } from '@storybook/html' */ +/** @param {Args} args */ const borderStory = (args) => { const classNames = [args.width || '']; if (args.color) { @@ -9,30 +11,37 @@ const borderStory = (args) => { return `
${className}
`; }; -export default { +/** @type {Meta} */ +const meta = { title: 'Utilities/Border', argTypes: { width: { options: ['small', 'medium', 'large', 'none'], - type: { name: 'enum' }, + type: { name: 'enum', value: ['small', 'medium', 'large', 'none'] }, control: { type: 'inline-radio' }, }, }, render: (args) => borderStory(args), }; +export default meta; + +/** @type {StoryObj} */ export const SmallDefault = { name: 'Small (Default)', }; +/** @type {StoryObj} */ export const Medium = { args: { width: 'medium' }, }; +/** @type {StoryObj} */ export const Large = { args: { width: 'large' }, }; +/** @type {StoryObj} */ export const None = { args: { width: 'none' }, }; diff --git a/src/utilities/display/display.stories.js b/src/utilities/display/display.stories.js index 14044154f..e1bf08741 100644 --- a/src/utilities/display/display.stories.js +++ b/src/utilities/display/display.stories.js @@ -1,15 +1,21 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import clearfixDemo from './demo/clearfix.twig'; import hiddenVisuallyDemo from './demo/hidden-visually.twig'; -export default { +/** @type {Meta} */ +const meta = { title: 'Utilities/Display', }; +export default meta; + +/** @type {StoryObj} */ export const HiddenVisually = { name: 'Hidden Visually', render: hiddenVisuallyDemo, }; +/** @type {StoryObj} */ export const Clearfix = { render: clearfixDemo, }; diff --git a/src/utilities/float/float.stories.js b/src/utilities/float/float.stories.js index 06360dc0c..ab4bc8aa2 100644 --- a/src/utilities/float/float.stories.js +++ b/src/utilities/float/float.stories.js @@ -1,6 +1,8 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import floatDemo from './demo/float.twig'; -export default { +/** @type {Meta} */ +const meta = { title: 'Utilities/Float', argTypes: { float: { @@ -19,6 +21,9 @@ export default { render: (args) => floatDemo(args), }; +export default meta; + +/** @type {StoryObj} */ export const Direction = { args: { float: 'inline-end' }, }; diff --git a/src/utilities/rounded/rounded.stories.js b/src/utilities/rounded/rounded.stories.js index ddad3eccd..e747f6f82 100644 --- a/src/utilities/rounded/rounded.stories.js +++ b/src/utilities/rounded/rounded.stories.js @@ -1,9 +1,14 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import sizesDemo from './demo/sizes.twig'; import './demo/styles.scss'; -export default { +/** @type {Meta} */ +const meta = { title: 'Utilities/Rounded Corners', render: () => sizesDemo(), }; +export default meta; + +/** @type {StoryObj} */ export const Sizes = {}; diff --git a/src/utilities/size/size.stories.js b/src/utilities/size/size.stories.js index e88a8d626..76bd95220 100644 --- a/src/utilities/size/size.stories.js +++ b/src/utilities/size/size.stories.js @@ -1,22 +1,29 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import blockSizeDemo from './demo/block-size.twig'; import inlineSizeDemo from './demo/inline-size.twig'; import responsiveDemo from './demo/responsive.twig'; import './demo/styles.scss'; -export default { +/** @type {Meta} */ +const meta = { title: 'Utilities/Size', }; +export default meta; + +/** @type {StoryObj} */ export const InlineSizeWidth = { name: 'Inline size (Width)', render: () => inlineSizeDemo(), }; +/** @type {StoryObj} */ export const BlockSizeHeight = { name: 'Block size (Height)', render: () => blockSizeDemo(), }; +/** @type {StoryObj} */ export const Responsive = { render: () => responsiveDemo(), }; diff --git a/src/utilities/spacing/spacing.stories.js b/src/utilities/spacing/spacing.stories.js index e6dfd16c0..03d3faa1d 100644 --- a/src/utilities/spacing/spacing.stories.js +++ b/src/utilities/spacing/spacing.stories.js @@ -1,3 +1,4 @@ +/** @import { ArgTypes, Meta, StoryObj } from '@storybook/html' */ import tokens from '../../compiled/tokens/js/tokens.js'; import directionsDemo from './demo/directions.twig'; @@ -6,6 +7,7 @@ import './demo/styles.scss'; const minimumStep = tokens.number.scale.modular.minimum_step.value; const maximumStep = tokens.number.scale.modular.maximum_step.value; +/** @type {Partial} */ const defaultArgTypes = { step: { type: { name: 'number' }, @@ -16,22 +18,28 @@ const defaultArgs = { step: 1, }; -export default { +/** @type {Meta} */ +const meta = { title: 'Utilities/Spacing', }; +export default meta; + +/** @type {StoryObj} */ export const Padding = { args: defaultArgs, argTypes: defaultArgTypes, render: (args) => directionsDemo({ name: 'pad', ...args }), }; +/** @type {StoryObj} */ export const Margin = { args: defaultArgs, argTypes: defaultArgTypes, render: (args) => directionsDemo({ name: 'space', ...args }), }; +/** @type {StoryObj} */ export const NegativeMargin = { name: 'Negative Margin', render: () => @@ -41,6 +49,7 @@ export const NegativeMargin = { }), }; +/** @type {StoryObj} */ export const Responsive = { render: () => responsiveDemo(), }; diff --git a/src/utilities/text/text.stories.js b/src/utilities/text/text.stories.js index ee12719bc..c626e4869 100644 --- a/src/utilities/text/text.stories.js +++ b/src/utilities/text/text.stories.js @@ -1,3 +1,4 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import colorDemo from './demo/color.twig'; import colorDemoSource from './demo/color.twig?raw'; import noWrapDemo from './demo/nowrap.twig'; @@ -7,28 +8,35 @@ import sizeDemoSource from './demo/size.twig?raw'; import textAlignDemo from './demo/text-align.twig'; import textAlignDemoSource from './demo/text-align.twig?raw'; -export default { +/** @type {Meta} */ +const meta = { title: 'Utilities/Text', }; +export default meta; + +/** @type {StoryObj} */ export const WhiteSpaceNowrap = { name: 'White-space nowrap', parameters: { docs: { source: { code: noWrapDemoSource } } }, render: (args) => noWrapDemo(args), }; +/** @type {StoryObj} */ export const ActionText = { name: 'Action text', parameters: { docs: { source: { code: colorDemoSource } } }, render: (args) => colorDemo(args), }; +/** @type {StoryObj} */ export const TextAlignCenter = { name: 'Text-align center', parameters: { docs: { source: { code: textAlignDemoSource } } }, render: (args) => textAlignDemo(args), }; +/** @type {StoryObj} */ export const BigAndSmall = { name: 'Big and small', parameters: { docs: { source: { code: sizeDemoSource } } }, diff --git a/src/vendor/highlight/highlight.stories.js b/src/vendor/highlight/highlight.stories.js index ac026013b..78956e0d8 100644 --- a/src/vendor/highlight/highlight.stories.js +++ b/src/vendor/highlight/highlight.stories.js @@ -1,6 +1,8 @@ -import { availableSamples, highlightDemo } from './demo/demo.ts'; +/** @import { Meta, StoryObj } from '@storybook/html' */ +import { availableSamples, highlightDemo } from './demo/demo'; -export default { +/** @type {Meta} */ +const meta = { title: 'Vendor/Highlight', argTypes: { language: { @@ -13,13 +15,16 @@ export default { }, parameters: { docs: { - source: { transform: (code) => code }, + source: { transform: (/** @type {string} */ code) => code }, }, layout: 'fullscreen', }, render: highlightDemo.bind({}), }; +export default meta; + +/** @type {StoryObj} */ export const Theme = { args: { language: 'html' }, }; diff --git a/src/vendor/lite-youtube/light-youtube.stories.js b/src/vendor/lite-youtube/light-youtube.stories.js index ce310b327..b6d6fc45b 100644 --- a/src/vendor/lite-youtube/light-youtube.stories.js +++ b/src/vendor/lite-youtube/light-youtube.stories.js @@ -1,6 +1,8 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import fallbackDemo from './demo/fallback.twig'; -export default { +/** @type {Meta} */ +const meta = { title: 'Vendor/lite-youtube', argTypes: { aspect_ratio: { @@ -12,4 +14,7 @@ export default { render: (args) => fallbackDemo(args), }; +export default meta; + +/** @type {StoryObj} */ export const Default = {}; diff --git a/src/vendor/mailchimp/mailchimp.stories.js b/src/vendor/mailchimp/mailchimp.stories.js index aadce92ad..4d16f6ded 100644 --- a/src/vendor/mailchimp/mailchimp.stories.js +++ b/src/vendor/mailchimp/mailchimp.stories.js @@ -1,6 +1,8 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import signupDemo from './demo/signup.twig'; -export default { +/** @type {Meta} */ +const meta = { title: 'Vendor/Mailchimp', parameters: { layout: 'fullscreen', @@ -8,6 +10,9 @@ export default { render: signupDemo.bind(this), }; +export default meta; + +/** @type {StoryObj} */ export const SignupForm = { name: 'Signup Form', argTypes: { diff --git a/src/vendor/shcb/shcb.stories.js b/src/vendor/shcb/shcb.stories.js index 49fa16ae3..cecae710d 100644 --- a/src/vendor/shcb/shcb.stories.js +++ b/src/vendor/shcb/shcb.stories.js @@ -1,5 +1,7 @@ +/** @import { ArgTypes, Meta, StoryObj } from '@storybook/html' */ import baseDemo from './demo/base.twig'; import codeTableDemo from './demo/code-table.twig'; +/** @type {Partial} */ const argTypes = { class: { type: 'string', @@ -11,19 +13,22 @@ const argTypes = { }, }; -export default { +/** @type {Meta} */ +const meta = { title: 'Vendor/Syntax-Highlighting Code Block', argTypes, parameters: { docs: { - source: { transform: (code) => code }, + source: { transform: (/** @type {string} */ code) => code }, }, layout: 'fullscreen', }, decorators: [ (story) => { const result = story(); - if (result.includes('wp-block-code')) { + // A story can render to a DOM node rather than a string; only the string form + // can be wrapped by concatenating markup around it. + if (typeof result === 'string' && result.includes('wp-block-code')) { return `
${result}
`; } return result; @@ -31,10 +36,14 @@ export default { ], }; +export default meta; + +/** @type {StoryObj} */ export const Basic = { render: (args) => baseDemo(args), }; +/** @type {StoryObj} */ export const MoreFeatures = { name: 'More Features', args: { lineNumbers: true, wrapLines: true }, diff --git a/src/vendor/wordpress/core-blocks.stories.js b/src/vendor/wordpress/core-blocks.stories.js index ffa48faa8..17fedc6cd 100644 --- a/src/vendor/wordpress/core-blocks.stories.js +++ b/src/vendor/wordpress/core-blocks.stories.js @@ -1,3 +1,4 @@ +/** @import { ArgTypes, Meta, StoryObj } from '@storybook/html' */ import blockCodeDemo from './demo/code.twig'; import blockDetailsDemo from './demo/details.twig'; import blockEmbedSpeakerDeckDemo from './demo/embed/speakerdeck.twig'; @@ -8,53 +9,81 @@ import blockMediaTextDemo from './demo/media-text.twig'; import blockPullQuoteDemo from './demo/pullquote.twig'; import blockQuoteDemo from './demo/quote.twig'; import blockTableDemo from './demo/table.twig'; +/** @type {Partial} */ const blockEmbedDemoArgTypes = { alignment: { - options: { - None: '', - Left: 'alignleft', - Center: 'aligncenter', - Right: 'alignright', - Full: 'alignfull', - Wide: 'alignwide', + options: [ + '', + 'alignleft', + 'aligncenter', + 'alignright', + 'alignfull', + 'alignwide', + ], + control: { + type: 'select', + labels: { + '': 'None', + alignleft: 'Left', + aligncenter: 'Center', + alignright: 'Right', + alignfull: 'Full', + alignwide: 'Wide', + }, }, - control: { type: 'select' }, }, ratio: { - options: { - '21:9': '21-9', - '18:9': '18-9', - '16:9': '16-9', - '4:3': '4-3', - '1:1': '1-1', - '9:16': '9-16', - '1:2': '1-2', + options: ['21-9', '18-9', '16-9', '4-3', '1-1', '9-16', '1-2'], + control: { + type: 'select', + labels: { + '21-9': '21:9', + '18-9': '18:9', + '16-9': '16:9', + '4-3': '4:3', + '1-1': '1:1', + '9-16': '9:16', + '1-2': '1:2', + }, }, - control: { type: 'select' }, }, caption: { control: { type: 'text' }, }, }; +/** @type {Partial} */ const blockMediaTextDemoArgTypes = { alignment: { - options: { - None: '', - Left: 'alignleft', - Center: 'aligncenter', - Right: 'alignright', - Full: 'alignfull', - Wide: 'alignwide', + options: [ + '', + 'alignleft', + 'aligncenter', + 'alignright', + 'alignfull', + 'alignwide', + ], + control: { + type: 'select', + labels: { + '': 'None', + alignleft: 'Left', + aligncenter: 'Center', + alignright: 'Right', + alignfull: 'Full', + alignwide: 'Wide', + }, }, - control: { type: 'select' }, }, vertical_alignment: { - options: { - Top: 'top', - Center: 'center', - Bottom: 'bottom', + options: ['top', 'center', 'bottom'], + control: { + type: 'select', + labels: { + top: 'Top', + center: 'Center', + bottom: 'Bottom', + }, }, - control: { type: 'select' }, }, has_media_on_the_right: { control: { type: 'boolean' }, @@ -73,10 +102,14 @@ const blockMediaTextDemoArgTypes = { }, }; -export default { +/** @type {Meta} */ +const meta = { title: 'Vendor/WordPress/Core Blocks', }; +export default meta; + +/** @type {StoryObj} */ export const Audio = { render: () => `
@@ -86,6 +119,7 @@ export const Audio = { `, }; +/** @type {StoryObj} */ export const Button = { render: () => ``, }; +/** @type {StoryObj} */ export const Buttons = { render: () => `
@@ -109,10 +144,12 @@ export const Buttons = {
`, }; +/** @type {StoryObj} */ export const Code = { render: () => blockCodeDemo(), }; +/** @type {StoryObj} */ export const Columns = { render: () => `
@@ -139,6 +176,7 @@ export const Columns = {
`, }; +/** @type {StoryObj} */ export const Cover = { render: () => `
`, }; +/** @type {StoryObj} */ export const CoverVideo = { name: 'Cover (Video)', render: () => `
@@ -174,6 +213,7 @@ export const CoverVideo = {
`, }; +/** @type {StoryObj} */ export const Details = { argTypes: { open: { @@ -187,6 +227,7 @@ export const Details = { render: (args) => blockDetailsDemo(args), }; +/** @type {StoryObj} */ export const EmbedYouTube = { name: 'Embed (YouTube)', args: { @@ -200,6 +241,7 @@ export const EmbedYouTube = { render: (args) => blockEmbedYouTubeDemo(args), }; +/** @type {StoryObj} */ export const EmbedSpeakerDeck = { name: 'Embed (Speaker Deck)', args: { @@ -213,6 +255,7 @@ export const EmbedSpeakerDeck = { render: (args) => blockEmbedSpeakerDeckDemo(args), }; +/** @type {StoryObj} */ export const File = { render: () => `
`, }; +/** @type {StoryObj} */ export const Gallery = { render: () => ``, }; +/** @type {StoryObj} */ export const Group = { argTypes: { background: { - options: { - None: '', - Gray: 'has-gray-lighter-background-color has-background', + options: ['', 'has-gray-lighter-background-color has-background'], + control: { + type: 'select', + labels: { + '': 'None', + 'has-gray-lighter-background-color has-background': 'Gray', + }, }, - control: { type: 'select' }, }, }, render: (args) => blockGroupDemo({ class: args.background }), }; +/** @type {StoryObj} */ export const Image = { args: { alignment: '', @@ -292,28 +341,42 @@ export const Image = { }, argTypes: { alignment: { - options: { - None: '', - Left: 'alignleft', - Center: 'aligncenter', - Right: 'alignright', - Full: 'alignfull', - Wide: 'alignwide', + options: [ + '', + 'alignleft', + 'aligncenter', + 'alignright', + 'alignfull', + 'alignwide', + ], + control: { + type: 'select', + labels: { + '': 'None', + alignleft: 'Left', + aligncenter: 'Center', + alignright: 'Right', + alignfull: 'Full', + alignwide: 'Wide', + }, }, - control: { type: 'select' }, }, style: { - options: { - None: 'is-style-default', - Outlined: 'is-style-outlined', + options: ['is-style-default', 'is-style-outlined'], + control: { + type: 'select', + labels: { + 'is-style-default': 'None', + 'is-style-outlined': 'Outlined', + }, }, - control: { type: 'select' }, }, }, render: (args) => blockImageDemo({ alignment: args.alignment, style: args.style }), }; +/** @type {StoryObj} */ export const MediaText = { name: 'Media-Text', args: { @@ -325,6 +388,7 @@ export const MediaText = { render: (args) => blockMediaTextDemo(args), }; +/** @type {StoryObj} */ export const Preformatted = { render: () => String.raw`
        ___________________________
@@ -338,6 +402,7 @@ export const Preformatted = {
       
`, }; +/** @type {StoryObj} */ export const Quote = { args: { show_citation: true, @@ -362,6 +427,7 @@ export const Quote = { render: (args) => blockQuoteDemo(args), }; +/** @type {StoryObj} */ export const Pullquote = { args: { show_citation: true, @@ -385,6 +451,7 @@ export const Pullquote = { render: (args) => blockPullQuoteDemo(args), }; +/** @type {StoryObj} */ export const Separator = { args: { style: 'default' }, argTypes: { @@ -398,6 +465,7 @@ export const Separator = { render: (args) => `
`, }; +/** @type {StoryObj} */ export const Spacer = { render: () => `

Content before spacer.

Content after spacer.

`, }; +/** @type {StoryObj} */ export const Table = { args: { show_header: true, @@ -417,12 +486,12 @@ export const Table = { argTypes: { block_style: { options: ['', 'stripes', 'ruled', 'numeric'], - type: { name: 'enum' }, + type: { name: 'enum', value: ['', 'stripes', 'ruled', 'numeric'] }, control: { type: 'select' }, }, column_alignment: { options: ['', 'center', 'right'], - type: { name: 'enum' }, + type: { name: 'enum', value: ['', 'center', 'right'] }, control: { type: 'select' }, }, fixed_layout: { @@ -441,6 +510,7 @@ export const Table = { render: (args) => blockTableDemo(args), }; +/** @type {StoryObj} */ export const Verse = { render: () => `
WHAT was he doing, the great god Pan,
Down in the reeds by the river?
Spreading ruin and scattering ban,
Splashing and paddling with hoofs of a goat,
And breaking the golden lilies afloat
With the dragon-fly on the river.
`, diff --git a/src/vendor/wordpress/core-element-comparison.stories.js b/src/vendor/wordpress/core-element-comparison.stories.js index c36275c4c..68c607a3f 100644 --- a/src/vendor/wordpress/core-element-comparison.stories.js +++ b/src/vendor/wordpress/core-element-comparison.stories.js @@ -1,24 +1,32 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import CommentDemo from './demo/compare-comment.twig'; import GutenbergDemo from './demo/compare-gutenberg.twig'; import HTMLDemo from './demo/compare-html.twig'; import MarkdownDemo from './demo/compare-markdown.twig'; -export default { +/** @type {Meta} */ +const meta = { title: 'Vendor/WordPress/Core Element Comparison', }; +export default meta; + +/** @type {StoryObj} */ export const Markdown = { render: () => MarkdownDemo(), }; +/** @type {StoryObj} */ export const HTML = { render: () => HTMLDemo(), }; +/** @type {StoryObj} */ export const Gutenberg = { render: () => GutenbergDemo(), }; +/** @type {StoryObj} */ export const Comments = { render: () => CommentDemo(), }; diff --git a/src/vendor/wordpress/jetpack-blocks.stories.js b/src/vendor/wordpress/jetpack-blocks.stories.js index 0ab95317d..64b3d7e8e 100644 --- a/src/vendor/wordpress/jetpack-blocks.stories.js +++ b/src/vendor/wordpress/jetpack-blocks.stories.js @@ -1,10 +1,15 @@ +/** @import { Meta, StoryObj } from '@storybook/html' */ import contactFormDemo from './demo/contact-form/form.twig'; import contactFormSuccessDemo from './demo/contact-form/success.twig'; -export default { +/** @type {Meta} */ +const meta = { title: 'Vendor/WordPress/Jetpack Blocks', }; +export default meta; + +/** @type {StoryObj} */ export const Markdown = { render: () => `

@@ -19,12 +24,14 @@ export const Markdown = {

`, }; +/** @type {StoryObj} */ export const ContactForm = { name: 'Contact Form', parameters: { layout: 'fullscreen' }, render: contactFormDemo, }; +/** @type {StoryObj} */ export const ContactFormSuccess = { name: 'Contact Form Success', parameters: { layout: 'fullscreen' }, diff --git a/src/vendor/wordpress/utilities.stories.js b/src/vendor/wordpress/utilities.stories.js index 1c923a504..caec619e4 100644 --- a/src/vendor/wordpress/utilities.stories.js +++ b/src/vendor/wordpress/utilities.stories.js @@ -1,3 +1,4 @@ +/** @import { ArgTypes, Meta, StoryObj } from '@storybook/html' */ import { kebabCase } from 'lodash'; import tokens from '../../compiled/tokens/js/tokens.js'; @@ -6,33 +7,39 @@ import alignmentDemo from './demo/alignment.twig'; import colorDemo from './demo/color.twig'; import fontSizeDemo from './demo/font-size.twig'; const baseColorTokenKeys = Object.keys(tokens.color.base).map(kebabCase); +/** @type {ArgTypes[string]} */ const colorControlConfig = { options: ['', ...baseColorTokenKeys], type: { name: 'string' }, control: { type: 'select' }, }; +/** @type {ArgTypes[string]} */ const fontSizeControlConfig = { + // `options` is a sibling of `control`, not a member of it -- matching + // `colorControlConfig` above. Storybook reads the option list off the arg type. + options: [ + '', + 'big', + 'small', + 'heading-n-2', + 'heading-n-1', + 'heading-0', + 'heading-1', + 'heading-2', + 'heading-3', + ], type: { name: 'string' }, - control: { - type: 'select', - options: [ - '', - 'big', - 'small', - 'heading-n-2', - 'heading-n-1', - 'heading-0', - 'heading-1', - 'heading-2', - 'heading-3', - ], - }, + control: { type: 'select' }, }; -export default { +/** @type {Meta} */ +const meta = { title: 'Vendor/WordPress/Utilities', }; +export default meta; + +/** @type {StoryObj} */ export const Color = { args: { color: 'fuchsia-lighter', @@ -48,6 +55,7 @@ export const Color = { render: (args) => colorDemo(args), }; +/** @type {StoryObj} */ export const FontSize = { name: 'Font Size', args: { @@ -59,6 +67,7 @@ export const FontSize = { render: (args) => fontSizeDemo(args), }; +/** @type {StoryObj} */ export const Alignment = { args: { alignment: 'alignwide' }, argTypes: { diff --git a/tsconfig.json b/tsconfig.json index 74af31df5..de3b55de6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -36,10 +36,6 @@ "src/prototypes", "src/vendor/highlight/demo/samples", "src/tokens", - "src/compiled", - // Stories are demo code and are not part of the published package. They were not - // type-checked while they lived in .stories.mdx either, so this keeps the previous - // coverage rather than widening it as part of the Storybook migration. - "src/**/*.stories.js" + "src/compiled" ] }