chore(storybook): upgrade storybook to 7.3 (#17078)

* feat(kea): typegen path cleanup and delete unused files

* bump

* 3.2.2

* typegen upgrade to 3.3.0

* storybook 7.3

* upgrade storybook to 7.3

* try using #storybook-root instead of #root

* try using #storybook-root instead of #root (2)

* try using #storybook-root instead of #root (3)

* try using #storybook-root instead of #root (4)

* switch out argTypes.defaultValue with args

* Update UI snapshots for `chromium` (1)

* Update UI snapshots for `chromium` (2)

* Update UI snapshots for `chromium` (1)

* Update UI snapshots for `chromium` (1)

---------

Co-authored-by: Thomas Obermüller <thomas.obermueller@gmail.com>
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Marius Andra
2023-08-21 09:32:49 +02:00
committed by GitHub
parent 64583fe038
commit 8075e42879
136 changed files with 5375 additions and 7064 deletions

View File

@@ -1,24 +1,20 @@
import type { StorybookConfig } from '@storybook/react/types'
import { createEntry } from '../webpack.config'
import { StorybookConfig } from '@storybook/react-webpack5'
const config: StorybookConfig = {
stories: ['../frontend/src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
addons: [
{
name: '@storybook/addon-docs',
options: {
sourceLoaderOptions: {
injectStoryParameters: false,
},
},
},
'@storybook/addon-docs',
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-storysource',
'@storybook/addon-a11y',
'storybook-addon-pseudo-states',
],
staticDirs: ['public'],
webpackFinal: (config) => {
const mainConfig = createEntry('main')
return {
@@ -32,23 +28,21 @@ const config: StorybookConfig = {
...config.module,
rules: [
...mainConfig.module.rules,
...config.module!.rules.filter((rule) => rule.test!.toString().includes('.mdx')),
{
test: /\.stories\.tsx?$/,
use: [
{
loader: require.resolve('@storybook/source-loader'),
options: { parser: 'typescript' },
},
],
enforce: 'pre',
},
...(config.module?.rules?.filter(
(rule: any) => 'test' in rule && rule.test.toString().includes('.mdx')
) ?? []),
],
},
}
},
features: {
postcss: false,
framework: {
name: '@storybook/react-webpack5',
options: {},
},
docs: {
autodocs: 'tag',
},
}

View File

@@ -1,6 +1,7 @@
import '~/styles'
import './storybook.scss'
import type { Meta, Parameters } from '@storybook/react'
import type { Meta, Parameters, Preview } from '@storybook/react'
import { Title, Subtitle, Description, Primary, Controls, Stories } from '@storybook/blocks'
import { worker } from '~/mocks/browser'
import { loadPostHogJS } from '~/loadPostHogJS'
import { getStorybookAppContext } from './app-context'
@@ -75,3 +76,29 @@ export const decorators: Meta['decorators'] = [
// Allow us to easily set feature flags in stories.
withFeatureFlags,
]
const preview: Preview = {
parameters: {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
docs: {
page: () => (
<>
<Title />
<Subtitle />
<Description />
<Primary />
<Controls />
<Stories />
</>
),
},
},
}
export default preview

View File

@@ -1,17 +1,16 @@
import { toMatchImageSnapshot } from 'jest-image-snapshot'
import { OptionsParameter } from '@storybook/addons'
import { getStoryContext, TestRunnerConfig, TestContext } from '@storybook/test-runner'
import type { Locator, Page, LocatorScreenshotOptions } from 'playwright-core'
import type { Mocks } from '~/mocks/utils'
import { StoryContext } from '@storybook/react'
type StoryContext = ReturnType<typeof getStoryContext> extends Promise<infer T> ? T : never
// 'firefox' is technically supported too, but as of June 2023 it has memory usage issues that make is unusable
type SupportedBrowserName = 'chromium' | 'webkit'
// Extend Storybook interface `Parameters` with Chromatic parameters
declare module '@storybook/react' {
interface Parameters {
options?: OptionsParameter
options?: any
layout?: 'padded' | 'fullscreen' | 'centered'
testOptions?: {
/**
@@ -146,10 +145,10 @@ async function expectStoryToMatchComponentSnapshot(
page: Page,
context: TestContext,
browser: SupportedBrowserName,
targetSelector: string = '#root'
targetSelector: string = '#storybook-root'
): Promise<void> {
await page.evaluate(() => {
const rootEl = document.getElementById('root')
const rootEl = document.getElementById('storybook-root')
if (!rootEl) {
throw new Error('Could not find root element')
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

After

Width:  |  Height:  |  Size: 223 KiB

View File

@@ -1,13 +1,15 @@
import { useEffect } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { Exporter } from './Exporter'
import { dashboard } from '~/exporter/__mocks__/Exporter.mocks'
import { ExportType } from '~/exporter/types'
export default {
type Story = StoryObj<typeof Exporter>
const meta: Meta<typeof Exporter> = {
title: 'Exporter/Exporter',
component: Exporter,
args: {
type: 'embed',
type: ExportType.Embed,
whitelabel: false,
noHeader: false,
legend: false,
@@ -19,9 +21,11 @@ export default {
mockDate: '2023-02-01',
viewMode: 'story',
},
} as ComponentMeta<typeof Exporter>
}
const Template: ComponentStory<typeof Exporter> = (props) => {
export default meta
const Template: StoryFn<typeof Exporter> = (props) => {
useEffect(() => {
document.body.className = ''
document.documentElement.className = `export-type-${props.type}`
@@ -33,84 +37,84 @@ const Template: ComponentStory<typeof Exporter> = (props) => {
)
}
export const TrendsLineInsight = Template.bind({})
export const TrendsLineInsight: Story = Template.bind({})
TrendsLineInsight.args = { insight: require('../scenes/insights/__mocks__/trendsLine.json') }
export const TrendsLineBreakdownInsight = Template.bind({})
export const TrendsLineBreakdownInsight: Story = Template.bind({})
TrendsLineBreakdownInsight.args = { insight: require('../scenes/insights/__mocks__/trendsLineBreakdown.json') }
export const TrendsBarInsight = Template.bind({})
export const TrendsBarInsight: Story = Template.bind({})
TrendsBarInsight.args = { insight: require('../scenes/insights/__mocks__/trendsBar.json') }
export const TrendsBarBreakdownInsight = Template.bind({})
export const TrendsBarBreakdownInsight: Story = Template.bind({})
TrendsBarBreakdownInsight.args = { insight: require('../scenes/insights/__mocks__/trendsBarBreakdown.json') }
export const TrendsValueInsight = Template.bind({})
export const TrendsValueInsight: Story = Template.bind({})
TrendsValueInsight.args = { insight: require('../scenes/insights/__mocks__/trendsValue.json') }
export const TrendsValueBreakdownInsight = Template.bind({})
export const TrendsValueBreakdownInsight: Story = Template.bind({})
TrendsValueBreakdownInsight.args = { insight: require('../scenes/insights/__mocks__/trendsValueBreakdown.json') }
export const TrendsAreaInsight = Template.bind({})
export const TrendsAreaInsight: Story = Template.bind({})
TrendsAreaInsight.args = { insight: require('../scenes/insights/__mocks__/trendsArea.json') }
export const TrendsAreaBreakdownInsight = Template.bind({})
export const TrendsAreaBreakdownInsight: Story = Template.bind({})
TrendsAreaBreakdownInsight.args = { insight: require('../scenes/insights/__mocks__/trendsAreaBreakdown.json') }
export const TrendsNumberInsight = Template.bind({})
export const TrendsNumberInsight: Story = Template.bind({})
TrendsNumberInsight.args = { insight: require('../scenes/insights/__mocks__/trendsNumber.json') }
export const TrendsTableInsight = Template.bind({})
export const TrendsTableInsight: Story = Template.bind({})
TrendsTableInsight.args = { insight: require('../scenes/insights/__mocks__/trendsTable.json') }
export const TrendsTableBreakdownInsight = Template.bind({})
export const TrendsTableBreakdownInsight: Story = Template.bind({})
TrendsTableBreakdownInsight.args = { insight: require('../scenes/insights/__mocks__/trendsTableBreakdown.json') }
export const TrendsPieInsight = Template.bind({})
export const TrendsPieInsight: Story = Template.bind({})
TrendsPieInsight.args = { insight: require('../scenes/insights/__mocks__/trendsPie.json') }
export const TrendsPieBreakdownInsight = Template.bind({})
export const TrendsPieBreakdownInsight: Story = Template.bind({})
TrendsPieBreakdownInsight.args = { insight: require('../scenes/insights/__mocks__/trendsPieBreakdown.json') }
export const TrendsWorldMapInsight = Template.bind({})
export const TrendsWorldMapInsight: Story = Template.bind({})
TrendsWorldMapInsight.args = { insight: require('../scenes/insights/__mocks__/trendsWorldMap.json') }
export const FunnelLeftToRightInsight = Template.bind({})
export const FunnelLeftToRightInsight: Story = Template.bind({})
FunnelLeftToRightInsight.args = { insight: require('../scenes/insights/__mocks__/funnelLeftToRight.json') }
export const FunnelLeftToRightBreakdownInsight = Template.bind({})
export const FunnelLeftToRightBreakdownInsight: Story = Template.bind({})
FunnelLeftToRightBreakdownInsight.args = {
insight: require('../scenes/insights/__mocks__/funnelLeftToRightBreakdown.json'),
}
export const FunnelTopToBottomInsight = Template.bind({})
export const FunnelTopToBottomInsight: Story = Template.bind({})
FunnelTopToBottomInsight.args = { insight: require('../scenes/insights/__mocks__/funnelTopToBottom.json') }
export const FunnelTopToBottomBreakdownInsight = Template.bind({})
export const FunnelTopToBottomBreakdownInsight: Story = Template.bind({})
FunnelTopToBottomBreakdownInsight.args = {
insight: require('../scenes/insights/__mocks__/funnelTopToBottomBreakdown.json'),
}
export const FunnelHistoricalTrendsInsight = Template.bind({})
export const FunnelHistoricalTrendsInsight: Story = Template.bind({})
FunnelHistoricalTrendsInsight.args = { insight: require('../scenes/insights/__mocks__/funnelHistoricalTrends.json') }
export const FunnelTimeToConvertInsight = Template.bind({})
export const FunnelTimeToConvertInsight: Story = Template.bind({})
FunnelTimeToConvertInsight.args = { insight: require('../scenes/insights/__mocks__/funnelTimeToConvert.json') }
export const RetentionInsight = Template.bind({})
export const RetentionInsight: Story = Template.bind({})
RetentionInsight.args = { insight: require('../scenes/insights/__mocks__/retention.json') }
export const RetentionBreakdownInsight = Template.bind({})
export const RetentionBreakdownInsight: Story = Template.bind({})
RetentionBreakdownInsight.args = { insight: require('../scenes/insights/__mocks__/retentionBreakdown.json') }
export const LifecycleInsight = Template.bind({})
export const LifecycleInsight: Story = Template.bind({})
LifecycleInsight.args = { insight: require('../scenes/insights/__mocks__/lifecycle.json') }
export const StickinessInsight = Template.bind({})
export const StickinessInsight: Story = Template.bind({})
StickinessInsight.args = { insight: require('../scenes/insights/__mocks__/stickiness.json') }
export const UserPathsInsight = Template.bind({})
export const UserPathsInsight: Story = Template.bind({})
UserPathsInsight.args = { insight: require('../scenes/insights/__mocks__/userPaths.json') }
export const Dashboard = Template.bind({})
export const Dashboard: Story = Template.bind({})
Dashboard.args = { dashboard }

View File

@@ -1,26 +1,28 @@
import { Meta, StoryFn } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { FeaturePreviewsModal as FeaturePreviewsModalComponent } from './FeaturePreviewsModal'
import { useFeatureFlags, useStorybookMocks } from '~/mocks/browser'
import { EarlyAccessFeature } from 'posthog-js'
import { CONSTRAINED_PREVIEWS } from './featurePreviewsLogic'
import { FeatureFlagKey } from 'lib/constants'
export default {
interface StoryProps {
earlyAccessFeatures: EarlyAccessFeature[]
enabledFeatureFlags: string[]
}
type Story = StoryObj<(props: StoryProps) => JSX.Element>
const meta: Meta<(props: StoryProps) => JSX.Element> = {
title: 'Layout/Feature Previews Modal',
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
},
} as Meta
}
export default meta
CONSTRAINED_PREVIEWS.add('constrained-test-1' as FeatureFlagKey)
CONSTRAINED_PREVIEWS.add('constrained-test-2' as FeatureFlagKey)
const Template: StoryFn<{ earlyAccessFeatures: EarlyAccessFeature[]; enabledFeatureFlags: string[] }> = ({
earlyAccessFeatures,
enabledFeatureFlags,
}) => {
const Template: StoryFn<StoryProps> = ({ earlyAccessFeatures, enabledFeatureFlags }) => {
useStorybookMocks({
get: {
'https://app.posthog.com/api/early_access_features/': { earlyAccessFeatures },
@@ -35,7 +37,7 @@ const Template: StoryFn<{ earlyAccessFeatures: EarlyAccessFeature[]; enabledFeat
)
}
export const Basic = Template.bind({})
export const Basic: Story = Template.bind({})
Basic.args = {
earlyAccessFeatures: [
{
@@ -50,7 +52,7 @@ Basic.args = {
enabledFeatureFlags: ['data-warehouse'],
}
export const WithConstrainedFeature = Template.bind({})
export const WithConstrainedFeature: Story = Template.bind({})
WithConstrainedFeature.args = {
earlyAccessFeatures: [
{
@@ -79,7 +81,7 @@ WithConstrainedFeature.args = {
enabledFeatureFlags: ['constrained-test-1-preview', 'constrained-test-1', 'constrained-test-2'],
}
export const Empty = Template.bind({})
export const Empty: Story = Template.bind({})
Empty.args = {
earlyAccessFeatures: [],
enabledFeatureFlags: [],

View File

@@ -9,7 +9,7 @@ import { useActions } from 'kea'
import { themeLogic } from './themeLogic'
import { with3000 } from 'storybook/decorators/with3000'
export default {
const meta: Meta = {
title: 'PostHog 3000/Navigation',
decorators: [
mswDecorator({
@@ -25,12 +25,11 @@ export default {
],
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
mockDate: '2023-02-01',
},
} as Meta
}
export default meta
export function LightMode(): JSX.Element {
const { overrideTheme } = useActions(themeLogic)
useEffect(() => {

View File

@@ -12,31 +12,32 @@ export interface NavbarButtonProps {
active?: boolean
}
export const NavbarButton: FunctionComponent<NavbarButtonProps> = React.forwardRef<HTMLElement, NavbarButtonProps>(
({ identifier, title, onClick, persistentTooltip, ...buttonProps }, ref): JSX.Element => {
const [hasBeenClicked, setHasBeenClicked] = useState(false)
export const NavbarButton: FunctionComponent<NavbarButtonProps> = React.forwardRef<
HTMLButtonElement,
NavbarButtonProps
>(({ identifier, title, onClick, persistentTooltip, ...buttonProps }, ref): JSX.Element => {
const [hasBeenClicked, setHasBeenClicked] = useState(false)
return (
<li>
<Tooltip
title={title}
placement="right"
delayMs={0}
visible={!persistentTooltip && hasBeenClicked ? false : undefined} // Force-hide tooltip after button click
>
<LemonButton
ref={ref}
data-attr={`menu-item-${identifier.toString().toLowerCase()}`}
onMouseEnter={() => setHasBeenClicked(false)}
onClick={() => {
setHasBeenClicked(true)
onClick?.()
}}
{...buttonProps}
/>
</Tooltip>
</li>
)
}
)
return (
<li>
<Tooltip
title={title}
placement="right"
delayMs={0}
visible={!persistentTooltip && hasBeenClicked ? false : undefined} // Force-hide tooltip after button click
>
<LemonButton
ref={ref}
data-attr={`menu-item-${identifier.toString().toLowerCase()}`}
onMouseEnter={() => setHasBeenClicked(false)}
onClick={() => {
setHasBeenClicked(true)
onClick?.()
}}
{...buttonProps}
/>
</Tooltip>
</li>
)
})
NavbarButton.displayName = 'NavbarButton'

View File

@@ -10,17 +10,16 @@ import dashboardsJson from '../../../scenes/dashboard/__mocks__/dashboards.json'
import { with3000 } from 'storybook/decorators/with3000'
import { SidebarNavbarItem } from '../types'
export default {
const meta: Meta = {
title: 'PostHog 3000/Sidebar',
parameters: {
mockDate: '2023-02-01',
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
},
decorators: [with3000],
} as Meta
}
export default meta
/** featureFlagsJson * 6 to fill the sidebar up more. */
const multipliedFeatureFlagsJson = {
...featureFlagsJson,

View File

@@ -7,15 +7,14 @@ import { useActions } from 'kea'
import { navigationLogic } from './navigationLogic'
import { useEffect } from 'react'
export default {
const meta: Meta = {
title: 'Layout/Navigation',
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
},
} as Meta
}
export default meta
function BaseAppPage(): JSX.Element {
return (
<>

View File

@@ -4,11 +4,11 @@ import {
personActivityResponseJson,
} from 'lib/components/ActivityLog/__mocks__/activityLogMocks'
import { mswDecorator } from '~/mocks/browser'
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { ActivityLog } from 'lib/components/ActivityLog/ActivityLog'
import { ActivityScope } from 'lib/components/ActivityLog/humanizeActivity'
export default {
const meta: Meta<typeof ActivityLog> = {
title: 'Components/ActivityLog',
component: ActivityLog,
parameters: { testOptions: { skip: true } }, // FIXME: Currently disabled as the Timeout story is flaky
@@ -39,7 +39,8 @@ export default {
},
}),
],
} as ComponentMeta<typeof ActivityLog>
}
export default meta
export function FeatureFlagActivity(): JSX.Element {
return <ActivityLog scope={ActivityScope.FEATURE_FLAG} id={7} />

View File

@@ -1,17 +1,19 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { SentenceList, SentenceListProps } from './SentenceList'
export default {
type Story = StoryObj<typeof SentenceList>
const meta: Meta<typeof SentenceList> = {
title: 'Components/SentenceList',
component: SentenceList,
parameters: {},
} as ComponentMeta<typeof SentenceList>
}
export default meta
const Template: ComponentStory<typeof SentenceList> = (props: SentenceListProps) => {
const Template: StoryFn<typeof SentenceList> = (props: SentenceListProps) => {
return <SentenceList {...props} />
}
export const FullSentence = Template.bind({})
export const FullSentence: Story = Template.bind({})
FullSentence.args = {
prefix: 'Bob',
suffix: 'on feature flag cool-flag',
@@ -22,13 +24,13 @@ FullSentence.args = {
],
}
export const OneAction = Template.bind({})
export const OneAction: Story = Template.bind({})
OneAction.args = { listParts: ['changed description to "something cool"'] }
export const TwoActions = Template.bind({})
export const TwoActions: Story = Template.bind({})
TwoActions.args = { listParts: ['changed description to "something cool"', 'changed name to "woop"'] }
export const ThreeActions = Template.bind({})
export const ThreeActions: Story = Template.bind({})
ThreeActions.args = {
listParts: [
'changed description to "something cool"',

View File

@@ -1,8 +1,9 @@
import { AnimationType } from 'lib/animations/animations'
import { ComponentStory, Meta } from '@storybook/react'
import { StoryFn, Meta, StoryObj } from '@storybook/react'
import { Animation } from 'lib/components/Animation/Animation'
export default {
type Story = StoryObj<typeof Animation>
const meta: Meta<typeof Animation> = {
title: 'Layout/Animations',
parameters: {
docs: {
@@ -24,11 +25,13 @@ export default {
control: { type: 'radio' },
},
},
} as Meta<Animation>
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof Animation> = ({ size, type }): JSX.Element => {
const Template: StoryFn<typeof Animation> = ({ size, type }): JSX.Element => {
return <Animation type={type} size={size} />
}
export const Animations = Template.bind({})
export const Animations: Story = Template.bind({})
Animations.args = { size: 'large' }

View File

@@ -31,7 +31,7 @@ const examples = [
EXAMPLE_DATA_TABLE_NODE_EVENTS_QUERY,
] as unknown as InsightModel[]
export default {
const meta: Meta = {
title: 'Components/Cards/Insight Card',
component: InsightCardComponent,
parameters: {
@@ -41,11 +41,9 @@ export default {
argTypes: {
insightName: {
control: { type: 'text' },
defaultValue: 'Insight title (edit in story controls)',
},
insightDescription: {
control: { type: 'text' },
defaultValue: 'Insight description (edit in story controls)',
},
loading: {
control: { type: 'boolean' },
@@ -60,8 +58,8 @@ export default {
control: { type: 'boolean' },
},
},
} as Meta
}
export default meta
export const InsightCard: Story = (args) => {
const [insightColor, setInsightColor] = useState<InsightColor | null>(null)
const [wasItemRemoved, setWasItemRemoved] = useState(false)

View File

@@ -2,12 +2,12 @@ import { Meta, Story } from '@storybook/react'
import { DashboardTile, InsightColor } from '~/types'
import { TextCard } from './TextCard'
export default {
const meta: Meta = {
title: 'Components/Cards/Text Card',
component: TextCard,
parameters: {},
} as Meta
}
export default meta
const makeTextTile = (body: string, color: InsightColor | null = null): DashboardTile => {
return {
id: 1,

View File

@@ -1,11 +1,11 @@
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { CompactList } from './CompactList'
import { urls } from 'scenes/urls'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { PersonDisplay } from 'scenes/persons/PersonDisplay'
export default {
const meta: Meta<typeof CompactList> = {
title: 'Components/Compact List',
component: CompactList,
argTypes: {
@@ -15,7 +15,8 @@ export default {
},
},
},
} as ComponentMeta<typeof CompactList>
}
export default meta
export function CompactList_({ loading }: { loading: boolean }): JSX.Element {
return (

View File

@@ -1,13 +1,14 @@
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { EditableField as EditableFieldComponent } from './EditableField'
import { PageHeader } from '../PageHeader'
import { useState } from 'react'
export default {
const meta: Meta<typeof EditableFieldComponent> = {
title: 'Components/Editable Field',
component: EditableFieldComponent,
} as ComponentMeta<typeof EditableFieldComponent>
}
export default meta
export function EditableField_(): JSX.Element {
const [savedTitle, setSavedTitle] = useState('Foo')

View File

@@ -1,11 +1,12 @@
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { EmptyMessage } from './EmptyMessage'
export default {
const meta: Meta<typeof EmptyMessage> = {
title: 'Components/Empty Message',
component: EmptyMessage,
} as ComponentMeta<typeof EmptyMessage>
}
export default meta
export function EmptyMessage_(): JSX.Element {
return (

View File

@@ -1,11 +1,12 @@
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { ErrorDisplay } from 'lib/components/Errors/ErrorDisplay'
import { EventType, RecordingEventType } from '~/types'
export default {
const meta: Meta<typeof ErrorDisplay> = {
title: 'Components/Errors/Error Display',
component: ErrorDisplay,
} as ComponentMeta<typeof ErrorDisplay>
}
export default meta
function errorEvent(properties: Record<string, any>): EventType | RecordingEventType {
return {

View File

@@ -21,7 +21,7 @@ const eventDefinitions = [
},
]
export default {
const meta: Meta = {
title: 'Filters',
decorators: [
mswDecorator({
@@ -37,8 +37,8 @@ export default {
}),
],
parameters: {},
} as Meta
}
export default meta
export function EventSelect_(): JSX.Element {
const [selectedEvents, setSelectedEvents] = useState<string[]>([])

View File

@@ -1,11 +1,12 @@
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { ElementType } from '~/types'
import { HTMLElementsDisplay } from './HTMLElementsDisplay'
export default {
const meta: Meta<typeof HTMLElementsDisplay> = {
title: 'Components/Html Elements Display',
component: HTMLElementsDisplay,
} as ComponentMeta<typeof HTMLElementsDisplay>
}
export default meta
export function EmptyDisplay(): JSX.Element {
return <HTMLElementsDisplay elements={[] as ElementType[]} />

View File

@@ -1,15 +1,16 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn } from '@storybook/react'
import { HedgehogBuddy } from './HedgehogBuddy'
export default {
const meta: Meta<typeof HedgehogBuddy> = {
title: 'Components/Hedgehog Buddy',
component: HedgehogBuddy,
parameters: {
testOptions: { skip: true }, // Hedgehogs aren't particularly snapshotable
},
} as ComponentMeta<typeof HedgehogBuddy>
}
export default meta
export const TheHedgehog: ComponentStory<typeof HedgehogBuddy> = () => {
export const TheHedgehog: StoryFn<typeof HedgehogBuddy> = () => {
return (
// eslint-disable-next-line react/forbid-dom-props
<div style={{ height: 200 }}>

View File

@@ -1,27 +1,29 @@
import { ComponentStory, Meta } from '@storybook/react'
import { StoryFn, Meta, StoryObj } from '@storybook/react'
import { HogQLEditor } from './HogQLEditor'
import { useState } from 'react'
export default {
type Story = StoryObj<typeof HogQLEditor>
const meta: Meta<typeof HogQLEditor> = {
title: 'Components/HogQLEditor',
component: HogQLEditor,
} as Meta<typeof HogQLEditor>
}
export default meta
const Template: ComponentStory<typeof HogQLEditor> = (props): JSX.Element => {
const Template: StoryFn<typeof HogQLEditor> = (props): JSX.Element => {
const [value, onChange] = useState(props.value ?? "countIf(properties.$browser = 'Chrome')")
return <HogQLEditor {...props} value={value} onChange={onChange} />
}
export const HogQLEditor_ = Template.bind({})
export const HogQLEditor_: Story = Template.bind({})
HogQLEditor_.args = {}
export const NoValue = Template.bind({})
export const NoValue: Story = Template.bind({})
NoValue.args = {
value: '',
disableAutoFocus: true,
}
export const NoValuePersonPropertiesDisabled = Template.bind({})
export const NoValuePersonPropertiesDisabled: Story = Template.bind({})
NoValuePersonPropertiesDisabled.args = {
disablePersonProperties: true,
value: '',

View File

@@ -1,15 +1,17 @@
import { ComponentStory, ComponentMeta } from '@storybook/react'
import { StoryFn, Meta, StoryObj } from '@storybook/react'
import { NotFound } from './index'
export default {
type Story = StoryObj<typeof NotFound>
const meta: Meta<typeof NotFound> = {
title: 'Components/Not Found',
component: NotFound,
} as ComponentMeta<typeof NotFound>
}
export default meta
const Template: ComponentStory<typeof NotFound> = (args) => <NotFound {...args} />
const Template: StoryFn<typeof NotFound> = (args) => <NotFound {...args} />
export const NotFound_ = Template.bind({})
export const NotFound_: Story = Template.bind({})
NotFound_.args = {
object: 'Person',
}

View File

@@ -1,17 +1,20 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { StoryFn, Meta, StoryObj } from '@storybook/react'
import { ObjectTags, ObjectTagsProps } from './ObjectTags'
export default {
type Story = StoryObj<typeof ObjectTags>
const meta: Meta<typeof ObjectTags> = {
title: 'Lemon UI/Object Tags',
component: ObjectTags,
} as ComponentMeta<typeof ObjectTags>
tags: ['autodocs'],
}
export default meta
const BasicTemplate: ComponentStory<typeof ObjectTags> = (props: Partial<ObjectTagsProps>) => {
const BasicTemplate: StoryFn<typeof ObjectTags> = (props: Partial<ObjectTagsProps>) => {
return <ObjectTags tags={['one', 'two', 'three']} {...props} />
}
export const Default = BasicTemplate.bind({})
export const Default: Story = BasicTemplate.bind({})
Default.args = {}
export const StaticOnly = BasicTemplate.bind({})
export const StaticOnly: Story = BasicTemplate.bind({})
StaticOnly.args = { staticOnly: true }

View File

@@ -1,15 +1,17 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { useState } from 'react'
import { PathCleaningFilter } from '~/types'
import { PathCleanFilters, PathCleanFiltersProps } from './PathCleanFilters'
export default {
type Story = StoryObj<typeof PathCleanFilters>
const meta: Meta<typeof PathCleanFilters> = {
title: 'Filters/PathCleanFilters',
component: PathCleanFilters,
} as ComponentMeta<typeof PathCleanFilters>
}
export default meta
const Template: ComponentStory<typeof PathCleanFilters> = (props: Partial<PathCleanFiltersProps>) => {
const Template: StoryFn<typeof PathCleanFilters> = (props: Partial<PathCleanFiltersProps>) => {
const [filters, setFilters] = useState<PathCleaningFilter[]>([
{ alias: 'insights', regex: '/insights/w+/dashboard$' },
{ regex: '/feature_flags/d+$' },
@@ -18,5 +20,5 @@ const Template: ComponentStory<typeof PathCleanFilters> = (props: Partial<PathCl
return <PathCleanFilters filters={filters} setFilters={setFilters} {...props} />
}
export const Default = Template.bind({})
export const Default: Story = Template.bind({})
Default.args = {}

View File

@@ -1,9 +1,10 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { useState } from 'react'
import { mswDecorator } from '~/mocks/browser'
import { PersonPropertySelect, PersonPropertySelectProps } from './PersonPropertySelect'
export default {
type Story = StoryObj<typeof PersonPropertySelect>
const meta: Meta<typeof PersonPropertySelect> = {
title: 'Filters/Person Property Select',
component: PersonPropertySelect,
decorators: [
@@ -25,9 +26,10 @@ export default {
},
}),
],
} as ComponentMeta<typeof PersonPropertySelect>
}
export default meta
const Template: ComponentStory<typeof PersonPropertySelect> = (props: Partial<PersonPropertySelectProps>) => {
const Template: StoryFn<typeof PersonPropertySelect> = (props: Partial<PersonPropertySelectProps>) => {
const [selectedProperties, setSelectProperties] = useState<string[]>([
'$initial_geoip_postal_code',
'$initial_geoip_latitude',
@@ -59,10 +61,10 @@ const Template: ComponentStory<typeof PersonPropertySelect> = (props: Partial<Pe
)
}
export const Default = Template.bind({})
export const Default: Story = Template.bind({})
Default.args = {}
export const Sortable = Template.bind({})
export const Sortable: Story = Template.bind({})
Sortable.args = {
sortable: true,
}

View File

@@ -1,11 +1,12 @@
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { ProductIntroduction } from './ProductIntroduction'
import { ProductKey } from '~/types'
export default {
const meta: Meta<typeof ProductIntroduction> = {
title: 'Components/Product Empty State',
component: ProductIntroduction,
} as ComponentMeta<typeof ProductIntroduction>
}
export default meta
export function ProductIntroduction_(): JSX.Element {
return (

View File

@@ -1,14 +1,15 @@
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { MOCK_TEAM_ID } from 'lib/api.mock'
import { useStorybookMocks } from '~/mocks/browser'
import { ChartDisplayType, PersonActorType } from '~/types'
import { PropertiesTimeline } from '.'
import { RawPropertiesTimelineResult } from './propertiesTimelineLogic'
export default {
const meta: Meta<typeof PropertiesTimeline> = {
title: 'Components/Properties Timeline',
component: PropertiesTimeline,
} as ComponentMeta<typeof PropertiesTimeline>
}
export default meta
const EXAMPLE_PERSON: Omit<PersonActorType, 'id' | 'uuid'> = {
type: 'person',

View File

@@ -1,12 +1,13 @@
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { PropertyFilters } from 'lib/components/PropertyFilters/PropertyFilters'
import { AnyPropertyFilter, PropertyOperator } from '~/types'
import PropertyFiltersDisplay from 'lib/components/PropertyFilters/components/PropertyFiltersDisplay'
export default {
const meta: Meta<typeof PropertyFilters> = {
title: 'Filters/PropertyFilters',
component: PropertyFilters,
} as ComponentMeta<typeof PropertyFilters>
}
export default meta
const propertyFilters = [
{

View File

@@ -1,14 +1,15 @@
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import {
OperatorValueSelect,
OperatorValueSelectProps,
} from 'lib/components/PropertyFilters/components/OperatorValueSelect'
import { PropertyDefinition, PropertyType } from '~/types'
export default {
const meta: Meta<typeof OperatorValueSelect> = {
title: 'Filters/PropertyFilters/OperatorValueSelect',
Component: OperatorValueSelect,
} as ComponentMeta<typeof OperatorValueSelect>
component: OperatorValueSelect,
}
export default meta
const makePropertyDefinition = (name: string, propertyType: PropertyType | undefined): PropertyDefinition => ({
id: name,

View File

@@ -1,15 +1,16 @@
import { useState } from 'react'
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { FilterLogicalOperator, FilterType, AnyPropertyFilter, PropertyGroupFilter, PropertyOperator } from '~/types'
import { useMountedLogic } from 'kea'
import { PropertyGroupFilters } from './PropertyGroupFilters'
import { TaxonomicFilterGroupType } from '../TaxonomicFilter/types'
import { cohortsModel } from '~/models/cohortsModel'
export default {
const meta: Meta<typeof PropertyGroupFilters> = {
title: 'Filters/PropertyGroupFilters',
component: PropertyGroupFilters,
} as ComponentMeta<typeof PropertyGroupFilters>
}
export default meta
const propertyFilters = [
{

View File

@@ -1,17 +1,20 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { PROPERTIES_ICON_MAP, PropertyIcon } from 'lib/components/PropertyIcon'
import { LemonTable } from 'lib/lemon-ui/LemonTable'
import { countryCodeToName } from 'scenes/insights/views/WorldMap'
export default {
type Story = StoryObj<typeof PropertyIcon>
const meta: Meta<typeof PropertyIcon> = {
title: 'Lemon UI/Icons/Property Icon',
component: PropertyIcon,
parameters: {
testOptions: { skip: true }, // There are too many icons, the snapshots are huge in table form
},
} as ComponentMeta<typeof PropertyIcon>
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof PropertyIcon> = (args) => {
const Template: StoryFn<typeof PropertyIcon> = (args) => {
if (args.value) {
return <PropertyIcon {...args} />
}
@@ -52,28 +55,28 @@ const Template: ComponentStory<typeof PropertyIcon> = (args) => {
)
}
export const Default_ = Template.bind({})
export const Default_: Story = Template.bind({})
Default_.args = {
property: '$browser',
value: 'Chrome',
}
export const Browser_ = Template.bind({})
export const Browser_: Story = Template.bind({})
Browser_.args = {
property: '$browser',
}
export const DeviceType_ = Template.bind({})
export const DeviceType_: Story = Template.bind({})
DeviceType_.args = {
property: '$device_type',
}
export const OS_ = Template.bind({})
export const OS_: Story = Template.bind({})
OS_.args = {
property: '$os',
}
export const Country_ = Template.bind({})
export const Country_: Story = Template.bind({})
Country_.args = {
property: '$geoip_country_code',
}

View File

@@ -1,13 +1,15 @@
import { ComponentStory, ComponentMeta } from '@storybook/react'
import { StoryFn, Meta, StoryObj } from '@storybook/react'
import { PropertyKeyInfo } from './PropertyKeyInfo'
export default {
type Story = StoryObj<typeof PropertyKeyInfo>
const meta: Meta<typeof PropertyKeyInfo> = {
title: 'Components/Property Key Info',
component: PropertyKeyInfo,
} as ComponentMeta<typeof PropertyKeyInfo>
}
export default meta
const Template: ComponentStory<typeof PropertyKeyInfo> = (args) => {
const Template: StoryFn<typeof PropertyKeyInfo> = (args) => {
return args.value ? (
<PropertyKeyInfo {...args} />
) : (
@@ -28,7 +30,7 @@ const Template: ComponentStory<typeof PropertyKeyInfo> = (args) => {
)
}
export const PropertyKeyInfo_ = Template.bind({})
export const PropertyKeyInfo_: Story = Template.bind({})
PropertyKeyInfo_.args = {
value: undefined,
type: 'event',

View File

@@ -1,5 +1,5 @@
import { useState } from 'react'
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { SharingModal, SharingModalProps } from './SharingModal'
import { AvailableFeature, InsightModel, InsightShortId, InsightType } from '~/types'
import { useStorybookMocks } from '~/mocks/browser'
@@ -12,15 +12,15 @@ const fakeInsight: Partial<InsightModel> = {
filters: { insight: InsightType.TRENDS },
}
export default {
const meta: Meta<typeof SharingModal> = {
title: 'Components/Sharing',
component: SharingModal,
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
},
} as ComponentMeta<typeof SharingModal>
}
export default meta
const Template = (args: Partial<SharingModalProps> & { licensed?: boolean }): JSX.Element => {
const { licensed = false, ...props } = args

View File

@@ -1,5 +1,5 @@
import { useRef, useState } from 'react'
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { SubscriptionsModal, SubscriptionsModalProps } from './SubscriptionsModal'
import { AvailableFeature, InsightShortId, Realm } from '~/types'
import preflightJson from '~/mocks/fixtures/_preflight.json'
@@ -9,16 +9,16 @@ import { useStorybookMocks } from '~/mocks/browser'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { createMockSubscription, mockIntegration, mockSlackChannels } from '~/test/mocks'
export default {
const meta: Meta<typeof SubscriptionsModal> = {
title: 'Components/Subscriptions',
component: SubscriptionsModal,
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
mockDate: '2023-01-31 12:00:00',
},
} as ComponentMeta<typeof SubscriptionsModal>
}
export default meta
const Template = (
args: Partial<SubscriptionsModalProps> & { noIntegrations?: boolean; featureAvailable?: boolean }

View File

@@ -5,20 +5,21 @@ import { useActions, useMountedLogic } from 'kea'
import { actionsModel } from '~/models/actionsModel'
import { useEffect } from 'react'
import { infiniteListLogic } from './infiniteListLogic'
import { ComponentMeta, ComponentStoryFn } from '@storybook/react'
import { Meta, StoryFn } from '@storybook/react'
import { useAvailableFeatures } from '~/mocks/features'
import { AvailableFeature } from '~/types'
export default {
const meta: Meta<typeof TaxonomicFilter> = {
title: 'Filters/Taxonomic Filter',
component: TaxonomicFilter,
decorators: [taxonomicFilterMocksDecorator],
parameters: {
testOptions: { waitForLoadersToDisappear: '.definition-popover' },
},
} as ComponentMeta<typeof TaxonomicFilter>
}
export default meta
export const EventsFree: ComponentStoryFn<typeof TaxonomicFilter> = (args) => {
export const EventsFree: StoryFn<typeof TaxonomicFilter> = (args) => {
useMountedLogic(actionsModel)
const { setIndex } = useActions(
infiniteListLogic({
@@ -43,7 +44,7 @@ EventsFree.args = {
taxonomicGroupTypes: [TaxonomicFilterGroupType.Events, TaxonomicFilterGroupType.Actions],
}
export const EventsPremium: ComponentStoryFn<typeof TaxonomicFilter> = (args) => {
export const EventsPremium: StoryFn<typeof TaxonomicFilter> = (args) => {
useAvailableFeatures([AvailableFeature.INGESTION_TAXONOMY])
return <EventsFree {...args} />
}
@@ -52,7 +53,7 @@ EventsPremium.args = {
taxonomicGroupTypes: [TaxonomicFilterGroupType.Events, TaxonomicFilterGroupType.Actions],
}
export const Actions: ComponentStoryFn<typeof TaxonomicFilter> = (args) => {
export const Actions: StoryFn<typeof TaxonomicFilter> = (args) => {
useMountedLogic(actionsModel)
const { setIndex } = useActions(
infiniteListLogic({
@@ -77,7 +78,7 @@ Actions.args = {
taxonomicGroupTypes: [TaxonomicFilterGroupType.Actions],
}
export const Properties: ComponentStoryFn<typeof TaxonomicFilter> = (args) => {
export const Properties: StoryFn<typeof TaxonomicFilter> = (args) => {
return (
<div className="w-fit border rounded p-2 bg-bg-light">
<TaxonomicFilter {...args} />

View File

@@ -5,13 +5,14 @@ import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types'
import { PropertyKeyInfo } from 'lib/components/PropertyKeyInfo'
import { useMountedLogic } from 'kea'
import { taxonomicFilterMocksDecorator } from 'lib/components/TaxonomicFilter/__mocks__/taxonomicFilterMocksDecorator'
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
export default {
const meta: Meta<typeof TaxonomicPopover> = {
title: 'Filters/TaxonomicPopover',
component: TaxonomicPopover,
decorators: [taxonomicFilterMocksDecorator],
} as ComponentMeta<typeof TaxonomicPopover>
}
export default meta
export function TaxonomicStringPopoverOneCategory(): JSX.Element {
useMountedLogic(cohortsModel)

View File

@@ -12,10 +12,9 @@ const allHedgehogs: HedgehogDefinition[] = Object.entries(hedgehogs).map(([key,
hedgehog: Hedgehog,
}))
export default {
const meta: Meta = {
title: 'Lemon UI/Hog illustrations',
parameters: {
options: { showPanel: false },
testOptions: { skip: true }, // Not valuable to take snapshots of these hedgehogs
docs: {
description: {
@@ -38,8 +37,9 @@ she will get to it dependant on work load.
},
},
},
} as Meta
tags: ['autodocs'],
}
export default meta
export function Library(): JSX.Element {
return (
<div className="space-y-2">

View File

@@ -1,4 +1,4 @@
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { Field, PureField } from './Field'
import { LemonButton, LemonCheckbox, LemonInput, LemonSelect, LemonTextArea } from '@posthog/lemon-ui'
import { kea, path, useAllValues } from 'kea'
@@ -6,7 +6,7 @@ import { Form, forms } from 'kea-forms'
import type { formLogicType } from './Field.storiesType'
export default {
const meta: Meta<typeof PureField> = {
title: 'Lemon UI/Forms and Fields',
component: PureField,
parameters: {
@@ -23,7 +23,9 @@ They can be used in a kea-forms controlled way via \`Field\` or a pure way via \
},
},
},
} as ComponentMeta<typeof PureField>
tags: ['autodocs'],
}
export default meta
export const _PureFields = (): JSX.Element => {
return (

View File

@@ -1,23 +1,26 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonBadge } from './LemonBadge'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { IconPlusMini } from 'lib/lemon-ui/icons'
export default {
type Story = StoryObj<typeof LemonBadge>
const meta: Meta<typeof LemonBadge> = {
title: 'Lemon UI/Lemon Badge/Lemon Badge',
component: LemonBadge,
} as ComponentMeta<typeof LemonBadge>
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof LemonBadge> = (props) => (
const Template: StoryFn<typeof LemonBadge> = (props) => (
<div className="flex">
<LemonBadge {...props} />
</div>
)
export const Standard = Template.bind({})
export const Standard: Story = Template.bind({})
Standard.args = { content: '@' }
export const Positioning: ComponentStory<typeof LemonBadge> = () => {
export const Positioning: StoryFn<typeof LemonBadge> = () => {
return (
<div className="space-y-4 m-2">
<LemonButton type="secondary">
@@ -43,7 +46,7 @@ export const Positioning: ComponentStory<typeof LemonBadge> = () => {
)
}
export const Sizes: ComponentStory<typeof LemonBadge> = () => {
export const Sizes: StoryFn<typeof LemonBadge> = () => {
return (
<div className="flex space-x-2 items-center">
<span>small:</span>
@@ -56,7 +59,7 @@ export const Sizes: ComponentStory<typeof LemonBadge> = () => {
)
}
export const Status: ComponentStory<typeof LemonBadge> = () => {
export const Status: StoryFn<typeof LemonBadge> = () => {
return (
<div className="flex space-x-2 items-center">
<span>primary:</span>
@@ -69,7 +72,7 @@ export const Status: ComponentStory<typeof LemonBadge> = () => {
)
}
export const Active: ComponentStory<typeof LemonBadge> = () => {
export const Active: StoryFn<typeof LemonBadge> = () => {
return (
<div className="flex space-x-2 items-center my-1 mr-1">
<span>inactive:</span>

View File

@@ -1,14 +1,17 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonBadge, LemonBadgeNumberProps } from './LemonBadge'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
export default {
type Story = StoryObj<typeof LemonBadge.Number>
const meta: Meta<typeof LemonBadge.Number> = {
title: 'Lemon UI/Lemon Badge/Lemon Badge Number',
component: LemonBadge.Number,
} as ComponentMeta<typeof LemonBadge.Number>
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof LemonBadge.Number> = ({ count, ...props }: LemonBadgeNumberProps) => {
const Template: StoryFn<typeof LemonBadge.Number> = ({ count, ...props }: LemonBadgeNumberProps) => {
const [countOverride, setCount] = useState(count)
return (
@@ -30,11 +33,11 @@ const Template: ComponentStory<typeof LemonBadge.Number> = ({ count, ...props }:
)
}
export const Standard = Template.bind({})
export const Standard: Story = Template.bind({})
Standard.args = { count: 1 }
export const MultipleDigits = Template.bind({})
export const MultipleDigits: Story = Template.bind({})
MultipleDigits.args = { count: 975, maxDigits: 3 }
export const ShowZero = Template.bind({})
export const ShowZero: Story = Template.bind({})
ShowZero.args = { count: 0, showZero: true }

View File

@@ -1,41 +1,43 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonBanner, LemonBannerProps } from './LemonBanner'
export default {
type Story = StoryObj<typeof LemonBanner>
const meta: Meta<typeof LemonBanner> = {
title: 'Lemon UI/Lemon Banner',
component: LemonBanner,
tags: ['autodocs'],
parameters: {
actions: {
// See https://github.com/storybookjs/addon-smart-knobs/issues/63#issuecomment-995798227
argTypesRegex: null,
},
},
} as ComponentMeta<typeof LemonBanner>
const Template: ComponentStory<typeof LemonBanner> = (props: LemonBannerProps) => {
}
export default meta
const Template: StoryFn<typeof LemonBanner> = (props: LemonBannerProps) => {
return <LemonBanner {...props} />
}
export const Info = Template.bind({})
export const Info: Story = Template.bind({})
Info.args = { type: 'info', children: 'PSA: Every dish can be improved by adding more garlic.' }
export const Warning = Template.bind({})
export const Warning: Story = Template.bind({})
Warning.args = { type: 'warning', children: 'This spacecraft is about to explode. Please evacuate immediately.' }
export const Error = Template.bind({})
export const Error: Story = Template.bind({})
Error.args = { type: 'error', children: 'This spacecraft has exploded. Too late...' }
export const Success = Template.bind({})
export const Success: Story = Template.bind({})
Success.args = { type: 'success', children: 'This spacecraft has recovered. Phew!' }
export const Closable = Template.bind({})
export const Closable: Story = Template.bind({})
Closable.args = {
type: 'info',
children: 'This is a one-time message. Acknowledge it and move on with your life.',
onClose: () => alert('👋'),
}
export const Dismissable = Template.bind({})
export const Dismissable: Story = Template.bind({})
Dismissable.args = {
type: 'info',
children: 'If you dismiss this message, it will be gone forever. (Clear the localstorage key to get it back)',

View File

@@ -1,4 +1,4 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import {
LemonButton,
LemonButtonProps,
@@ -12,32 +12,34 @@ import { LemonDivider } from 'lib/lemon-ui/LemonDivider'
import { capitalizeFirstLetter, delay, range } from 'lib/utils'
import { urls } from 'scenes/urls'
import { Link } from '@posthog/lemon-ui'
import { LemonBanner } from '../LemonBanner'
import { useAsyncHandler } from 'lib/hooks/useAsyncHandler'
import clsx from 'clsx'
import { LemonBanner } from 'lib/lemon-ui/LemonBanner'
const statuses: LemonButtonProps['status'][] = ['primary', 'danger', 'primary-alt', 'muted']
const types: LemonButtonProps['type'][] = ['primary', 'secondary', 'tertiary']
export default {
type Story = StoryObj<typeof LemonButton>
const meta: Meta<typeof LemonButton> = {
title: 'Lemon UI/Lemon Button',
component: LemonButton,
tags: ['autodocs'],
argTypes: {
icon: {
defaultValue: <IconCalculate />,
},
children: {
defaultValue: 'Click me',
type: 'function',
},
},
} as ComponentMeta<typeof LemonButton>
const BasicTemplate: ComponentStory<typeof LemonButton> = (props: LemonButtonProps) => {
}
export default meta
const BasicTemplate: StoryFn<typeof LemonButton> = (props: LemonButtonProps) => {
return <LemonButton {...props} />
}
export const Default = BasicTemplate.bind({})
Default.args = {}
export const Default: Story = BasicTemplate.bind({})
Default.args = {
icon: <IconCalculate />,
children: 'Click me',
}
const StatusesTemplate = ({
noText,
@@ -55,7 +57,7 @@ const StatusesTemplate = ({
)
}
const TypesAndStatusesTemplate: ComponentStory<typeof LemonButton> = (props) => {
const TypesAndStatusesTemplate: StoryFn<typeof LemonButton> = (props) => {
return (
<div className="space-y-2">
{types.map((type) => (
@@ -68,10 +70,11 @@ const TypesAndStatusesTemplate: ComponentStory<typeof LemonButton> = (props) =>
)
}
export const TypesAndStatuses = TypesAndStatusesTemplate.bind({})
TypesAndStatuses.args = {}
export const TypesAndStatuses: Story = TypesAndStatusesTemplate.bind({})
TypesAndStatuses.args = { ...Default.args }
const PopoverTemplate: ComponentStory<typeof LemonButtonWithDropdown> = (props: LemonButtonWithDropdownProps) => {
type PopoverStory = StoryObj<typeof LemonButtonWithDropdown>
const PopoverTemplate: StoryFn<typeof LemonButtonWithDropdown> = (props: LemonButtonWithDropdownProps) => {
return <LemonButtonWithDropdown {...props} />
}
@@ -261,8 +264,9 @@ export const AsLinks = (): JSX.Element => {
)
}
export const WithDropdownToTheRight = PopoverTemplate.bind({})
export const WithDropdownToTheRight: PopoverStory = PopoverTemplate.bind({})
WithDropdownToTheRight.args = {
...Default.args,
dropdown: {
overlay: (
<>
@@ -284,8 +288,9 @@ WithDropdownToTheRight.args = {
},
}
export const WithDropdownToTheBottom = PopoverTemplate.bind({})
export const WithDropdownToTheBottom: PopoverStory = PopoverTemplate.bind({})
WithDropdownToTheBottom.args = {
...Default.args,
dropdown: {
overlay: (
<>
@@ -308,8 +313,9 @@ WithDropdownToTheBottom.args = {
},
}
export const WithVeryLongPopoverToTheBottom = PopoverTemplate.bind({})
export const WithVeryLongPopoverToTheBottom: PopoverStory = PopoverTemplate.bind({})
WithVeryLongPopoverToTheBottom.args = {
...Default.args,
dropdown: {
overlay: (
<>
@@ -325,8 +331,9 @@ WithVeryLongPopoverToTheBottom.args = {
},
}
export const WithTooltip = BasicTemplate.bind({})
export const WithTooltip: Story = BasicTemplate.bind({})
WithTooltip.args = {
...Default.args,
tooltip: 'The flux capacitor will be reloaded. This might take up to 14 hours.',
}

View File

@@ -73,7 +73,7 @@ export interface LemonButtonProps extends LemonButtonPropsBase {
}
/** Styled button. */
export const LemonButton: React.FunctionComponent<LemonButtonProps & React.RefAttributes<HTMLElement>> =
export const LemonButton: React.FunctionComponent<LemonButtonProps & React.RefAttributes<HTMLButtonElement>> =
React.forwardRef(
(
{
@@ -225,7 +225,7 @@ export interface LemonButtonWithSideActionProps extends LemonButtonPropsBase {
* We can't use `LemonRow`'s `sideIcon` prop because putting `onClick` on it clashes with the parent`s `onClick`.
*/
export const LemonButtonWithSideAction: React.FunctionComponent<
LemonButtonWithSideActionProps & React.RefAttributes<HTMLElement>
LemonButtonWithSideActionProps & React.RefAttributes<HTMLButtonElement>
> = React.forwardRef(({ sideAction, children, ...buttonProps }, ref) => {
const { dropdown: sideDropdown, divider = !buttonProps.fullWidth, ...sideActionRest } = sideAction
const SideComponent = sideDropdown ? LemonButtonWithDropdown : LemonButton

View File

@@ -1,36 +1,37 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonCalendar, LemonCalendarProps } from './LemonCalendar'
import { dayjs } from 'lib/dayjs'
export default {
type Story = StoryObj<typeof LemonCalendar>
const meta: Meta<typeof LemonCalendar> = {
title: 'Lemon UI/Lemon Calendar/Lemon Calendar',
component: LemonCalendar,
argTypes: {
onClick: {
defaultValue: (date: dayjs.Dayjs) => {
// eslint-disable-next-line no-console
console.log(`Clicked: ${date}`)
},
args: {
onDateClick: (date: dayjs.Dayjs) => {
// eslint-disable-next-line no-console
console.log(`Clicked: ${date}`)
},
},
parameters: {
mockDate: '2023-01-26',
},
} as ComponentMeta<typeof LemonCalendar>
tags: ['autodocs'],
}
export default meta
const BasicTemplate: ComponentStory<typeof LemonCalendar> = (props: LemonCalendarProps) => {
const BasicTemplate: StoryFn<typeof LemonCalendar> = (props: LemonCalendarProps) => {
return <LemonCalendar {...props} />
}
export const Default = BasicTemplate.bind({})
export const Default: Story = BasicTemplate.bind({})
Default.args = {}
export const MultipleMonths = BasicTemplate.bind({})
export const MultipleMonths: Story = BasicTemplate.bind({})
MultipleMonths.args = {
months: 3,
}
export const CustomStyles = BasicTemplate.bind({})
export const CustomStyles: Story = BasicTemplate.bind({})
CustomStyles.args = {
getLemonButtonProps: ({ date, props }) => {
return {
@@ -42,37 +43,37 @@ CustomStyles.args = {
},
}
export const MondayFirst = BasicTemplate.bind({})
export const MondayFirst: Story = BasicTemplate.bind({})
MondayFirst.args = {
weekStart: 1,
}
export const TuesdayFirst = BasicTemplate.bind({})
export const TuesdayFirst: Story = BasicTemplate.bind({})
TuesdayFirst.args = {
weekStart: 2,
}
export const WednesdayFirst = BasicTemplate.bind({})
export const WednesdayFirst: Story = BasicTemplate.bind({})
WednesdayFirst.args = {
weekStart: 3,
}
export const ThursdayFirst = BasicTemplate.bind({})
export const ThursdayFirst: Story = BasicTemplate.bind({})
ThursdayFirst.args = {
weekStart: 4,
}
export const FridayFirst = BasicTemplate.bind({})
export const FridayFirst: Story = BasicTemplate.bind({})
FridayFirst.args = {
weekStart: 5,
}
export const SaturdayFirst = BasicTemplate.bind({})
export const SaturdayFirst: Story = BasicTemplate.bind({})
SaturdayFirst.args = {
weekStart: 6,
}
export const SundayFirst = BasicTemplate.bind({})
export const SundayFirst: Story = BasicTemplate.bind({})
SundayFirst.args = {
weekStart: 0,
}

View File

@@ -1,20 +1,23 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonCalendarSelect, LemonCalendarSelectProps } from 'lib/lemon-ui/LemonCalendar/LemonCalendarSelect'
import { Popover } from 'lib/lemon-ui/Popover/Popover'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { dayjs } from 'lib/dayjs'
import { formatDate } from 'lib/utils'
export default {
type Story = StoryObj<typeof LemonCalendarSelect>
const meta: Meta<typeof LemonCalendarSelect> = {
title: 'Lemon UI/Lemon Calendar/Lemon Calendar Select',
component: LemonCalendarSelect,
parameters: {
mockDate: '2023-01-26',
},
} as ComponentMeta<typeof LemonCalendarSelect>
tags: ['autodocs'],
}
export default meta
const BasicTemplate: ComponentStory<typeof LemonCalendarSelect> = (props: LemonCalendarSelectProps) => {
const BasicTemplate: StoryFn<typeof LemonCalendarSelect> = (props: LemonCalendarSelectProps) => {
const [value, setValue] = useState(dayjs().subtract(10, 'day'))
const [visible, setVisible] = useState(true)
@@ -45,5 +48,5 @@ const BasicTemplate: ComponentStory<typeof LemonCalendarSelect> = (props: LemonC
)
}
export const LemonCalendarSelect_ = BasicTemplate.bind({})
export const LemonCalendarSelect_: Story = BasicTemplate.bind({})
LemonCalendarSelect_.args = {}

View File

@@ -1,20 +1,23 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonCalendarRange, LemonCalendarRangeProps } from 'lib/lemon-ui/LemonCalendarRange/LemonCalendarRange'
import { Popover } from 'lib/lemon-ui/Popover/Popover'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { dayjs } from 'lib/dayjs'
import { formatDateRange } from 'lib/utils'
export default {
type Story = StoryObj<typeof LemonCalendarRange>
const meta: Meta<typeof LemonCalendarRange> = {
title: 'Lemon UI/Lemon Calendar/Lemon Calendar Range',
component: LemonCalendarRange,
parameters: {
mockDate: '2023-01-26',
},
} as ComponentMeta<typeof LemonCalendarRange>
tags: ['autodocs'],
}
export default meta
const BasicTemplate: ComponentStory<typeof LemonCalendarRange> = (props: LemonCalendarRangeProps) => {
const BasicTemplate: StoryFn<typeof LemonCalendarRange> = (props: LemonCalendarRangeProps) => {
const [value, setValue] = useState([dayjs('2022-08-11'), dayjs('2022-08-26')] as LemonCalendarRangeProps['value'])
const [visible, setVisible] = useState(true)
@@ -45,5 +48,5 @@ const BasicTemplate: ComponentStory<typeof LemonCalendarRange> = (props: LemonCa
)
}
export const LemonCalendarRange_ = BasicTemplate.bind({})
export const LemonCalendarRange_: Story = BasicTemplate.bind({})
LemonCalendarRange_.args = {}

View File

@@ -1,19 +1,22 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonCalendarRangeProps } from 'lib/lemon-ui/LemonCalendarRange/LemonCalendarRange'
import { dayjs } from 'lib/dayjs'
import { formatDateRange } from 'lib/utils'
import { LemonCalendarRangeInline } from './LemonCalendarRangeInline'
export default {
type Story = StoryObj<typeof LemonCalendarRangeInline>
const meta: Meta<typeof LemonCalendarRangeInline> = {
title: 'Lemon UI/Lemon Calendar/Lemon Calendar Range Inline',
component: LemonCalendarRangeInline,
parameters: {
mockDate: '2023-01-26',
},
} as ComponentMeta<typeof LemonCalendarRangeInline>
tags: ['autodocs'],
}
export default meta
const BasicTemplate: ComponentStory<typeof LemonCalendarRangeInline> = (props: LemonCalendarRangeProps) => {
const BasicTemplate: StoryFn<typeof LemonCalendarRangeInline> = (props: LemonCalendarRangeProps) => {
const [value, setValue] = useState([dayjs('2022-08-11'), dayjs('2022-08-26')] as [dayjs.Dayjs, dayjs.Dayjs] | null)
return (
@@ -31,5 +34,5 @@ const BasicTemplate: ComponentStory<typeof LemonCalendarRangeInline> = (props: L
)
}
export const LemonCalendarRangeInline_ = BasicTemplate.bind({})
export const LemonCalendarRangeInline_: Story = BasicTemplate.bind({})
LemonCalendarRangeInline_.args = {}

View File

@@ -1,16 +1,19 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonCheckbox, LemonCheckboxProps } from './LemonCheckbox'
export default {
type Story = StoryObj<typeof LemonCheckbox>
const meta: Meta<typeof LemonCheckbox> = {
title: 'Lemon UI/Lemon Checkbox',
component: LemonCheckbox,
} as ComponentMeta<typeof LemonCheckbox>
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof LemonCheckbox> = (props: LemonCheckboxProps) => {
const Template: StoryFn<typeof LemonCheckbox> = (props: LemonCheckboxProps) => {
return <LemonCheckbox {...props} />
}
export const Basic = Template.bind({})
export const Basic: Story = Template.bind({})
Basic.args = {
label: 'Check this out',
}
@@ -32,22 +35,22 @@ export const Overview = (): JSX.Element => {
)
}
export const Disabled = Template.bind({})
export const Disabled: Story = Template.bind({})
Disabled.args = {
label: "You can't check this out",
disabled: true,
}
export const DisabledWithReason = Template.bind({})
export const DisabledWithReason: Story = Template.bind({})
DisabledWithReason.args = {
label: "You can't check this out",
disabledReason: 'This is not the way to Amarillo',
}
export const NoLabel = Template.bind({})
export const NoLabel: Story = Template.bind({})
NoLabel.args = {}
export const Bordered = Template.bind({})
export const Bordered: Story = Template.bind({})
Bordered.args = {
label: 'A border makes for good visual separation if there is other content neighboring a checkbox. Probably not used as part of a form.',
bordered: true,

View File

@@ -1,33 +1,34 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonCollapse as LemonCollapseComponent } from './LemonCollapse'
export default {
type Story = StoryObj<typeof LemonCollapseComponent>
const meta: Meta<typeof LemonCollapseComponent> = {
title: 'Lemon UI/Lemon Collapse',
component: LemonCollapseComponent,
argTypes: {
panels: {
defaultValue: [
{
key: '1',
header: 'Panel 1',
content: <span>Panel 1 content</span>,
},
{
key: '2',
header: 'Panel 2',
content: <span>Panel 2 content</span>,
},
],
},
args: {
panels: [
{
key: '1',
header: 'Panel 1',
content: <span>Panel 1 content</span>,
},
{
key: '2',
header: 'Panel 2',
content: <span>Panel 2 content</span>,
},
],
},
} as ComponentMeta<typeof LemonCollapseComponent>
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof LemonCollapseComponent> = (props) => {
const Template: StoryFn<typeof LemonCollapseComponent> = (props) => {
return <LemonCollapseComponent {...props} />
}
export const Single = Template.bind({})
export const Single: Story = Template.bind({})
Single.args = { defaultActiveKey: '1' }
export const Multiple = Template.bind({})
export const Multiple: Story = Template.bind({})
Multiple.args = { defaultActiveKeys: ['1', '2'], multiple: true }

View File

@@ -1,9 +1,10 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonDialog, LemonDialogProps } from './LemonDialog'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { Link } from '@posthog/lemon-ui'
export default {
type Story = StoryObj<typeof LemonDialog>
const meta: Meta<typeof LemonDialog> = {
title: 'Lemon UI/Lemon Dialog',
component: LemonDialog,
args: {
@@ -40,9 +41,11 @@ Dialogs are opened imperatively (i.e. calling \`LemonDialog.open()\`) whereas Mo
},
},
},
} as ComponentMeta<typeof LemonDialog>
tags: ['autodocs'],
}
export default meta
export const Template: ComponentStory<typeof LemonDialog> = (props: LemonDialogProps) => {
export const Template: StoryFn<typeof LemonDialog> = (props: LemonDialogProps) => {
const onClick = (): void => {
LemonDialog.open(props)
}
@@ -58,7 +61,7 @@ export const Template: ComponentStory<typeof LemonDialog> = (props: LemonDialogP
)
}
export const Minimal = Template.bind({})
export const Minimal: Story = Template.bind({})
Minimal.args = {
title: 'Notice',
description: undefined,
@@ -67,7 +70,7 @@ Minimal.args = {
tertiaryButton: undefined,
}
export const Customised = Template.bind({})
export const Customised: Story = Template.bind({})
Customised.args = {
title: 'Are you sure you want to delete “FakeOrganization”?',
description: (

View File

@@ -1,16 +1,19 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonDivider, LemonDividerProps } from './LemonDivider'
import { LemonRow } from 'lib/lemon-ui/LemonRow'
import { Lettermark, LettermarkColor } from '../Lettermark/Lettermark'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { ProfileBubbles } from '../ProfilePicture'
export default {
type Story = StoryObj<typeof LemonDivider>
const meta: Meta<typeof LemonDivider> = {
title: 'Lemon UI/Lemon Divider',
component: LemonDivider,
} as ComponentMeta<typeof LemonDivider>
tags: ['autodocs'],
}
export default meta
const HorizontalTemplate: ComponentStory<typeof LemonDivider> = (props: LemonDividerProps) => {
const HorizontalTemplate: StoryFn<typeof LemonDivider> = (props: LemonDividerProps) => {
return (
<>
<LemonRow icon={<Lettermark name={1} color={LettermarkColor.Gray} />}>
@@ -24,7 +27,7 @@ const HorizontalTemplate: ComponentStory<typeof LemonDivider> = (props: LemonDiv
)
}
const VerticalTemplate: ComponentStory<typeof LemonDivider> = (props: LemonDividerProps) => {
const VerticalTemplate: StoryFn<typeof LemonDivider> = (props: LemonDividerProps) => {
return (
<div className="flex items-center">
<ProfileBubbles
@@ -44,17 +47,17 @@ const VerticalTemplate: ComponentStory<typeof LemonDivider> = (props: LemonDivid
}
VerticalTemplate.args = { vertical: true }
export const Default = HorizontalTemplate.bind({})
export const Default: Story = HorizontalTemplate.bind({})
Default.args = {}
export const Large = HorizontalTemplate.bind({})
export const Large: Story = HorizontalTemplate.bind({})
Large.args = { className: 'my-6' }
export const ThickDashed = HorizontalTemplate.bind({})
export const ThickDashed: Story = HorizontalTemplate.bind({})
ThickDashed.args = { thick: true, dashed: true }
export const Vertical = VerticalTemplate.bind({})
export const Vertical: Story = VerticalTemplate.bind({})
Vertical.args = { ...VerticalTemplate.args }
export const VerticalDashed = VerticalTemplate.bind({})
export const VerticalDashed: Story = VerticalTemplate.bind({})
VerticalDashed.args = { ...VerticalTemplate.args, dashed: true }

View File

@@ -1,17 +1,24 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonFileInput } from 'lib/lemon-ui/LemonFileInput/LemonFileInput'
import { createRef, useState } from 'react'
export default {
type Story = StoryObj<typeof LemonFileInput>
const meta: Meta<typeof LemonFileInput> = {
title: 'Lemon UI/Lemon File Input',
component: LemonFileInput,
tags: ['autodocs'],
argTypes: {
loading: { type: 'boolean', defaultValue: false },
accept: { type: 'string', defaultValue: '.json' },
loading: { type: 'boolean' },
accept: { type: 'string' },
},
} as ComponentMeta<typeof LemonFileInput>
args: {
loading: false,
accept: '.json',
},
}
export default meta
const Template: ComponentStory<typeof LemonFileInput> = (props) => {
const Template: StoryFn<typeof LemonFileInput> = (props) => {
const [singleValue, setSingleValue] = useState([] as any[])
const [multipleValue, setMultipleValue] = useState([] as any[])
const [extraTargetValue, setExtraTargetValue] = useState([] as any[])
@@ -58,4 +65,4 @@ const Template: ComponentStory<typeof LemonFileInput> = (props) => {
)
}
export const Default = Template.bind({})
export const Default: Story = Template.bind({})

View File

@@ -1,27 +1,30 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonInput } from './LemonInput'
import { IconArrowDropDown, IconCalendar } from 'lib/lemon-ui/icons'
import { LemonButtonWithDropdown } from 'lib/lemon-ui/LemonButton'
export default {
type Story = StoryObj<typeof LemonInput>
const meta: Meta<typeof LemonInput> = {
title: 'Lemon UI/Lemon Input',
component: LemonInput,
argTypes: {
value: { defaultValue: 'Foo' },
tags: ['autodocs'],
args: {
value: 'Foo',
},
} as ComponentMeta<typeof LemonInput>
}
export default meta
const Template: ComponentStory<typeof LemonInput> = (props) => {
const Template: StoryFn<typeof LemonInput> = (props) => {
const [value, setValue] = useState(props.value)
// @ts-expect-error union variant inference around the `type` prop doesn't work here as `type` comes from above
return <LemonInput {...props} value={value} onChange={(newValue) => setValue(newValue)} />
}
export const Basic = Template.bind({})
export const Basic: Story = Template.bind({})
export const WithPrefixAndSuffixAction = Template.bind({})
export const WithPrefixAndSuffixAction: Story = Template.bind({})
WithPrefixAndSuffixAction.args = {
prefix: <IconCalendar />,
suffix: (
@@ -36,23 +39,23 @@ WithPrefixAndSuffixAction.args = {
),
}
export const Search = Template.bind({})
export const Search: Story = Template.bind({})
Search.args = { type: 'search', placeholder: 'Search your soul' }
export const Password = Template.bind({})
export const Password: Story = Template.bind({})
Password.args = { type: 'password', placeholder: 'Enter your password' }
export const Disabled = Template.bind({})
export const Disabled: Story = Template.bind({})
Disabled.args = { disabled: true }
export const DangerStatus = Template.bind({})
export const DangerStatus: Story = Template.bind({})
DangerStatus.args = { status: 'danger' }
export const Clearable = Template.bind({})
export const Clearable: Story = Template.bind({})
Clearable.args = { allowClear: true }
export const Numeric = Template.bind({})
export const Numeric: Story = Template.bind({})
Numeric.args = { type: 'number', min: 0, step: 1, value: 3 }
export const Small = Template.bind({})
export const Small: Story = Template.bind({})
Small.args = { allowClear: true, size: 'small' }

View File

@@ -1,29 +1,34 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonLabel, LemonLabelProps } from './LemonLabel'
import { LemonModal } from '@posthog/lemon-ui'
export default {
type Story = StoryObj<typeof LemonLabel>
const meta: Meta<typeof LemonLabel> = {
title: 'Lemon UI/Lemon Label',
component: LemonLabel,
docs: {
description: {
component: `
parameters: {
docs: {
description: {
component: `
[Related Figma area](https://www.figma.com/file/Y9G24U4r04nEjIDGIEGuKI/PostHog-Design-System-One?node-id=3139%3A1388)
Lemon Labels provide common styling and options for labeling form elements. They can be used directly but most commonly should be used via the \`Field\` component.
`,
},
},
},
} as ComponentMeta<typeof LemonLabel>
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof LemonLabel> = (props: LemonLabelProps) => {
const Template: StoryFn<typeof LemonLabel> = (props: LemonLabelProps) => {
return <LemonLabel {...props} />
}
export const Basic = Template.bind({})
export const Basic: Story = Template.bind({})
Basic.args = {
info: 'This field is optional',
showOptional: true,

View File

@@ -1,4 +1,4 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import {
LemonMenuOverlay as LemonMenuOverlayComponent,
LemonMenuOverlayProps,
@@ -7,7 +7,8 @@ import {
} from './LemonMenu'
import { Splotch, SplotchColor } from '../Splotch'
export default {
type Story = StoryObj<typeof LemonMenuOverlayComponent>
const meta: Meta<typeof LemonMenuOverlayComponent> = {
title: 'Lemon UI/Lemon Menu',
component: LemonMenuOverlayComponent,
parameters: {
@@ -21,18 +22,18 @@ This enables intuitive preview of the component, along with snapshotting, but in
},
},
},
argTypes: {
items: {
defaultValue: [
{ label: 'Alert', onClick: () => alert('Hello there.') },
{ label: 'Do nothing' },
{ label: 'Do nothing, with a highlight', active: true },
] as LemonMenuItems,
},
args: {
items: [
{ label: 'Alert', onClick: () => alert('Hello there.') },
{ label: 'Do nothing' },
{ label: 'Do nothing, with a highlight', active: true },
] as LemonMenuItems,
},
} as ComponentMeta<typeof LemonMenuOverlayComponent>
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof LemonMenuOverlayComponent> = (props: LemonMenuOverlayProps) => {
const Template: StoryFn<typeof LemonMenuOverlayComponent> = (props: LemonMenuOverlayProps) => {
return (
<div className="Popover">
<div
@@ -49,10 +50,10 @@ const Template: ComponentStory<typeof LemonMenuOverlayComponent> = (props: Lemon
)
}
export const Flat = Template.bind({})
export const Flat: Story = Template.bind({})
Flat.args = {}
export const SectionedItems = Template.bind({})
export const SectionedItems: Story = Template.bind({})
SectionedItems.args = {
items: [
{
@@ -79,7 +80,7 @@ SectionedItems.args = {
] as LemonMenuSection[],
}
export const NestedMenu = Template.bind({})
export const NestedMenu: Story = Template.bind({})
NestedMenu.args = {
items: [
{

View File

@@ -1,14 +1,16 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn } from '@storybook/react'
import { LemonModal, LemonModalProps } from './LemonModal'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
export default {
const meta: Meta<typeof LemonModal> = {
title: 'Lemon UI/Lemon Modal',
component: LemonModal,
} as ComponentMeta<typeof LemonModal>
tags: ['autodocs'],
}
export default meta
export const _LemonModal: ComponentStory<typeof LemonModal> = (props: LemonModalProps) => {
export const _LemonModal: StoryFn<typeof LemonModal> = (props: LemonModalProps) => {
const [isOpen, setIsOpen] = useState(false)
return (
<>
@@ -59,7 +61,7 @@ export const _LemonModal: ComponentStory<typeof LemonModal> = (props: LemonModal
)
}
export const WithoutContent: ComponentStory<typeof LemonModal> = (props: LemonModalProps) => {
export const WithoutContent: StoryFn<typeof LemonModal> = (props: LemonModalProps) => {
const [isOpen, setIsOpen] = useState(false)
return (
<>
@@ -86,7 +88,7 @@ export const WithoutContent: ComponentStory<typeof LemonModal> = (props: LemonMo
)
}
export const Inline: ComponentStory<typeof LemonModal> = () => {
export const Inline: StoryFn<typeof LemonModal> = () => {
const [isOpen, setIsOpen] = useState(false)
return (
<div className="bg-default p-4">
@@ -109,7 +111,7 @@ export const Inline: ComponentStory<typeof LemonModal> = () => {
)
}
export const WithCustomContent: ComponentStory<typeof LemonModal> = () => {
export const WithCustomContent: StoryFn<typeof LemonModal> = () => {
const [isOpen, setIsOpen] = useState(false)
return (
<div className="bg-default p-4">

View File

@@ -1,104 +1,117 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { IconInfo, IconPremium } from 'lib/lemon-ui/icons'
import { LemonRow, LemonRowProps } from './LemonRow'
export default {
type Story = StoryObj<typeof LemonRow>
const meta: Meta<typeof LemonRow> = {
title: 'Lemon UI/Lemon Row',
component: LemonRow,
argTypes: {
icon: {
defaultValue: <IconPremium />,
},
children: {
defaultValue: 'Information',
},
},
} as ComponentMeta<typeof LemonRow>
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof LemonRow> = (props: LemonRowProps<keyof JSX.IntrinsicElements>) => {
const Template: StoryFn<typeof LemonRow> = (props: LemonRowProps<keyof JSX.IntrinsicElements>) => {
return <LemonRow {...props} />
}
export const Default = Template.bind({})
Default.args = {}
export const Default: Story = Template.bind({})
Default.args = {
children: 'Information',
icon: <IconPremium />,
}
export const TextOnly = Template.bind({})
export const TextOnly: Story = Template.bind({})
TextOnly.args = {
...Default.args,
icon: null,
}
export const IconOnly = Template.bind({})
export const IconOnly: Story = Template.bind({})
IconOnly.args = {
...Default.args,
children: null,
}
export const Outlined = Template.bind({})
export const Outlined: Story = Template.bind({})
Outlined.args = {
...Default.args,
outlined: true,
}
export const Success = Template.bind({})
export const Success: Story = Template.bind({})
Success.args = {
...Default.args,
status: 'success',
}
export const Warning = Template.bind({})
export const Warning: Story = Template.bind({})
Warning.args = {
...Default.args,
status: 'warning',
}
export const Danger = Template.bind({})
export const Danger: Story = Template.bind({})
Danger.args = {
...Default.args,
status: 'danger',
}
export const Disabled = Template.bind({})
export const Disabled: Story = Template.bind({})
Disabled.args = {
...Default.args,
disabled: true,
}
export const Loading = Template.bind({})
export const Loading: Story = Template.bind({})
Loading.args = {
...Default.args,
loading: true,
}
export const Small = Template.bind({})
export const Small: Story = Template.bind({})
Small.args = {
...Default.args,
outlined: true,
size: 'small',
}
export const Tall = Template.bind({})
export const Tall: Story = Template.bind({})
Tall.args = {
...Default.args,
outlined: true,
size: 'tall',
}
export const Large = Template.bind({})
export const Large: Story = Template.bind({})
Large.args = {
...Default.args,
outlined: true,
size: 'large',
}
export const FullWidth = Template.bind({})
export const FullWidth: Story = Template.bind({})
FullWidth.args = {
...Default.args,
outlined: true,
fullWidth: true,
}
export const WithSideIcon = Template.bind({})
export const WithSideIcon: Story = Template.bind({})
WithSideIcon.args = {
...Default.args,
sideIcon: <IconInfo />,
}
export const WithTooltip = Template.bind({})
export const WithTooltip: Story = Template.bind({})
WithTooltip.args = {
...Default.args,
tooltip:
'The lifespan of kangaroos averages at six years in the wild to in excess of 20 years in captivity, varying by the species.',
}
export const WithExtendedContent = Template.bind({})
export const WithExtendedContent: Story = Template.bind({})
WithExtendedContent.args = {
...Default.args,
type: 'stealth',
extendedContent: "This is some extra info about this particular item. Hopefully it's helpful.",
}

View File

@@ -1,9 +1,10 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { useState } from 'react'
import { IconCalculate, IconCalendar, IconLightBulb, IconSettings } from '../icons'
import { LemonSegmentedButton, LemonSegmentedButtonOption, LemonSegmentedButtonProps } from './LemonSegmentedButton'
export default {
type Story = StoryObj<typeof LemonSegmentedButton>
const meta: Meta<typeof LemonSegmentedButton> = {
title: 'Lemon UI/Lemon Segmented Button',
component: LemonSegmentedButton,
argTypes: {
@@ -11,25 +12,29 @@ export default {
control: {
type: 'object',
},
defaultValue: [
{ value: 'calendar', label: 'Calendar', icon: <IconCalendar /> },
{ value: 'calculator', label: 'Calculator', icon: <IconCalculate /> },
{
value: 'banana',
label: 'Banana',
icon: <IconLightBulb />,
disabledReason: 'Bananas are not allowed on these premises.',
},
{ value: 'settings', label: 'Settings', icon: <IconSettings /> },
] as LemonSegmentedButtonOption<string>[],
},
// Show value and onChange, but disable editing as they're handled by the template
value: { control: { disable: true } },
onChange: { control: { disable: true } },
},
} as ComponentMeta<typeof LemonSegmentedButton>
args: {
options: [
{ value: 'calendar', label: 'Calendar', icon: <IconCalendar /> },
{ value: 'calculator', label: 'Calculator', icon: <IconCalculate /> },
{
value: 'banana',
label: 'Banana',
icon: <IconLightBulb />,
disabledReason: 'Bananas are not allowed on these premises.',
},
{ value: 'settings', label: 'Settings', icon: <IconSettings /> },
] as LemonSegmentedButtonOption<string>[],
},
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof LemonSegmentedButton> = (
const Template: StoryFn<typeof LemonSegmentedButton> = (
props: Omit<LemonSegmentedButtonProps<any>, 'value' | 'onChange'>
) => {
const [value, setValue] = useState(props.options[1]?.value)
@@ -37,10 +42,10 @@ const Template: ComponentStory<typeof LemonSegmentedButton> = (
return <LemonSegmentedButton {...props} value={value} onChange={(newValue) => setValue(newValue)} />
}
export const Default = Template.bind({})
export const Default: Story = Template.bind({})
Default.args = {}
export const Small = Template.bind({})
export const Small: Story = Template.bind({})
Small.args = {
size: 'small',
}

View File

@@ -1,22 +1,23 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonSelect, LemonSelectOptions, LemonSelectProps } from './LemonSelect'
import { capitalizeFirstLetter } from 'lib/utils'
export default {
type Story = StoryObj<typeof LemonSelect>
const meta: Meta<typeof LemonSelect> = {
title: 'Lemon UI/Lemon Select',
component: LemonSelect,
argTypes: {
options: {
defaultValue: [
{ value: 'husky', label: 'Husky' },
{ value: 'poodle', label: 'Poodle' },
{ value: 'labrador', label: 'Labrador' },
] as LemonSelectOptions<string>,
},
args: {
options: [
{ value: 'husky', label: 'Husky' },
{ value: 'poodle', label: 'Poodle' },
{ value: 'labrador', label: 'Labrador' },
] as LemonSelectOptions<string>,
},
} as ComponentMeta<typeof LemonSelect>
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof LemonSelect> = (props: LemonSelectProps<any>) => {
const Template: StoryFn<typeof LemonSelect> = (props: LemonSelectProps<any>) => {
return (
<div className="flex flex-row items-center w-full border p-4 gap-2">
{(['small', undefined] as const).map((size, index) => (
@@ -29,10 +30,10 @@ const Template: ComponentStory<typeof LemonSelect> = (props: LemonSelectProps<an
)
}
export const Flat = Template.bind({})
export const Flat: Story = Template.bind({})
Flat.args = {}
export const SectionedOptions = Template.bind({})
export const SectionedOptions: Story = Template.bind({})
SectionedOptions.args = {
dropdownMatchSelectWidth: false,
options: [
@@ -71,7 +72,7 @@ SectionedOptions.args = {
] as LemonSelectOptions<string>,
}
export const MixedValuesTypes = Template.bind({})
export const MixedValuesTypes: Story = Template.bind({})
MixedValuesTypes.args = {
dropdownMatchSelectWidth: false,
options: [
@@ -84,7 +85,7 @@ MixedValuesTypes.args = {
] as LemonSelectOptions<string | number>,
}
export const NestedSelect = Template.bind({})
export const NestedSelect: Story = Template.bind({})
NestedSelect.args = {
dropdownMatchSelectWidth: false,
options: [
@@ -99,17 +100,17 @@ NestedSelect.args = {
] as LemonSelectOptions<string | number>,
}
export const Clearable = Template.bind({})
export const Clearable: Story = Template.bind({})
Clearable.args = { allowClear: true, value: 'poodle' }
export const LongOptions = Template.bind({})
export const LongOptions: Story = Template.bind({})
LongOptions.args = {
allowClear: true,
value: '1',
options: [...Array(100)].map((_, x) => ({ value: `${x}`, label: `${x}` })),
}
export const CustomElement = Template.bind({})
export const CustomElement: Story = Template.bind({})
CustomElement.args = {
value: 1,
options: [
@@ -126,7 +127,7 @@ CustomElement.args = {
],
}
export const FullWidth: ComponentStory<typeof LemonSelect> = (props: LemonSelectProps<any>) => {
export const FullWidth: StoryFn<typeof LemonSelect> = (props: LemonSelectProps<any>) => {
return (
<div className="items-center w-full border p-4 gap-2">
<LemonSelect {...props} fullWidth={true} allowClear={true} value={'poodle'} />

View File

@@ -1,71 +1,72 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonSelectMultiple, LemonSelectMultipleProps } from './LemonSelectMultiple'
import { ProfilePicture } from '../ProfilePicture'
import { capitalizeFirstLetter } from 'lib/utils'
export default {
type Story = StoryObj<typeof LemonSelectMultiple>
const meta: Meta<typeof LemonSelectMultiple> = {
title: 'Lemon UI/Lemon SelectMultiple',
component: LemonSelectMultiple,
argTypes: {
options: {
defaultValue: ['ben', 'marius', 'paul', 'tiina', 'li'].reduce(
(acc, x, i) => ({
...acc,
[`user-${i}`]: {
labelComponent: (
<span className="flex gap-2 items-center">
<ProfilePicture name={x} email={`${x}@posthog.com`} size="sm" />
<span>
{capitalizeFirstLetter(x)} <b>{`<${x}@posthog.com>`}</b>
</span>
args: {
options: ['ben', 'marius', 'paul', 'tiina', 'li'].reduce(
(acc, x, i) => ({
...acc,
[`user-${i}`]: {
labelComponent: (
<span className="flex gap-2 items-center">
<ProfilePicture name={x} email={`${x}@posthog.com`} size="sm" />
<span>
{capitalizeFirstLetter(x)} <b>{`<${x}@posthog.com>`}</b>
</span>
),
label: `${x} ${x}@posthog.com>`,
},
}),
{}
),
},
</span>
),
label: `${x} ${x}@posthog.com>`,
},
}),
{}
),
},
} as ComponentMeta<typeof LemonSelectMultiple>
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof LemonSelectMultiple> = (props: LemonSelectMultipleProps) => {
const Template: StoryFn<typeof LemonSelectMultiple> = (props: LemonSelectMultipleProps) => {
const [value, setValue] = useState(props.value || [])
return <LemonSelectMultiple {...props} value={value} onChange={setValue} />
}
export const Default = Template.bind({})
export const Default: Story = Template.bind({})
Default.args = {
placeholder: 'Pick one email',
}
export const MultipleSelect = Template.bind({})
export const MultipleSelect: Story = Template.bind({})
MultipleSelect.args = {
placeholder: 'Enter emails...',
mode: 'multiple',
}
export const MultipleSelectWithCustom = Template.bind({})
export const MultipleSelectWithCustom: Story = Template.bind({})
MultipleSelectWithCustom.args = {
placeholder: 'Enter any email...',
mode: 'multiple-custom',
}
export const Disabled = Template.bind({})
export const Disabled: Story = Template.bind({})
Disabled.args = {
placeholder: 'Disabled...',
disabled: true,
}
export const Loading = Template.bind({})
export const Loading: Story = Template.bind({})
Loading.args = {
placeholder: 'Loading...',
options: [],
loading: true,
}
export const NoOptions = Template.bind({})
export const NoOptions: Story = Template.bind({})
NoOptions.args = {
mode: 'multiple-custom',
placeholder: 'No options...',

View File

@@ -1,10 +1,10 @@
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { LemonSkeleton } from './LemonSkeleton'
import { LemonLabel } from 'lib/lemon-ui/LemonLabel/LemonLabel'
import { LemonModal } from 'lib/lemon-ui/LemonModal'
export default {
const meta: Meta<typeof LemonSkeleton> = {
title: 'Lemon UI/Lemon Skeleton',
component: LemonSkeleton,
parameters: {
@@ -17,7 +17,9 @@ Skeleton screens are used to indicate that a screen is loading, are perceived as
},
},
},
} as ComponentMeta<typeof LemonSkeleton>
tags: ['autodocs'],
}
export default meta
export function Default(): JSX.Element {
return <LemonSkeleton />

View File

@@ -1,22 +1,23 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonSnack, LemonSnackProps } from './LemonSnack'
import { ProfilePicture } from '../ProfilePicture'
export default {
type Story = StoryObj<typeof LemonSnack>
const meta: Meta<typeof LemonSnack> = {
title: 'Lemon UI/Lemon Snack',
component: LemonSnack,
argTypes: {
children: {
defaultValue: 'Tasty snacks',
},
args: {
children: 'Tasty snacks',
},
} as ComponentMeta<typeof LemonSnack>
tags: ['autodocs'],
}
export default meta
const BasicTemplate: ComponentStory<typeof LemonSnack> = (props: LemonSnackProps) => {
const BasicTemplate: StoryFn<typeof LemonSnack> = (props: LemonSnackProps) => {
return <LemonSnack {...props} />
}
export const Default = BasicTemplate.bind({})
export const Default: Story = BasicTemplate.bind({})
Default.args = {
onClose: null as any,
}
@@ -38,7 +39,7 @@ export const Pill = (): JSX.Element => {
)
}
export const ComplexContent = BasicTemplate.bind({})
export const ComplexContent: Story = BasicTemplate.bind({})
ComplexContent.args = {
children: (
<span className="flex gap-2 items-center">

View File

@@ -1,29 +1,30 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonSwitch as RawLemonSwitch, LemonSwitchProps } from './LemonSwitch'
import { IconGlobeLock } from 'lib/lemon-ui/icons'
export default {
title: 'Lemon UI/Lemon Switch',
component: RawLemonSwitch,
argTypes: {
label: {
defaultValue: 'Switch this!',
},
},
} as ComponentMeta<typeof LemonSwitch>
const LemonSwitch = ({ checked, ...props }: Partial<LemonSwitchProps>): JSX.Element => {
const [isChecked, setIsChecked] = useState(checked || false)
return <RawLemonSwitch {...props} checked={isChecked} onChange={setIsChecked} />
}
const Template: ComponentStory<typeof RawLemonSwitch> = (props: LemonSwitchProps) => {
type Story = StoryObj<typeof RawLemonSwitch>
const meta: Meta<typeof LemonSwitch> = {
title: 'Lemon UI/Lemon Switch',
component: LemonSwitch,
args: {
label: 'Switch this!',
},
tags: ['autodocs'],
}
export default meta
const Template: StoryFn<typeof RawLemonSwitch> = (props: LemonSwitchProps) => {
return <LemonSwitch {...props} />
}
export const Basic = Template.bind({})
export const Basic: Story = Template.bind({})
Basic.args = {}
export const Overview = (): JSX.Element => {
@@ -42,11 +43,11 @@ export const Overview = (): JSX.Element => {
)
}
export const Standalone = Template.bind({})
export const Standalone: Story = Template.bind({})
Standalone.args = { label: undefined }
export const Bordered = Template.bind({})
export const Bordered: Story = Template.bind({})
Bordered.args = { bordered: true }
export const Disabled = Template.bind({})
export const Disabled: Story = Template.bind({})
Disabled.args = { disabled: true }

View File

@@ -1,12 +1,15 @@
import { ComponentMeta, ComponentStory, Story } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonTable, LemonTableProps } from './LemonTable'
import { LemonButton } from '../LemonButton'
import { useEffect } from 'react'
export default {
type Story = StoryObj<typeof LemonTable>
const meta: Meta<typeof LemonTable> = {
title: 'Lemon UI/Lemon Table',
component: LemonTable,
} as ComponentMeta<typeof LemonTable>
tags: ['autodocs'],
}
export default meta
interface MockPerson {
name: string
@@ -19,7 +22,7 @@ interface MockFunnelSeries {
}
// @ts-expect-error
const GroupedTemplate: ComponentStory<typeof LemonTable> = (props: LemonTableProps<MockFunnelSeries>) => {
const GroupedTemplate: StoryFn<typeof LemonTable> = (props: LemonTableProps<MockFunnelSeries>) => {
return (
<LemonTable
{...props}
@@ -89,7 +92,7 @@ const GroupedTemplate: ComponentStory<typeof LemonTable> = (props: LemonTablePro
}
// @ts-expect-error
const BasicTemplate: ComponentStory<typeof LemonTable> = (props: LemonTableProps<MockPerson>) => {
const BasicTemplate: StoryFn<typeof LemonTable> = (props: LemonTableProps<MockPerson>) => {
return (
<LemonTable
{...props}
@@ -134,7 +137,7 @@ const BasicTemplate: ComponentStory<typeof LemonTable> = (props: LemonTableProps
)
}
const EmptyTemplate: ComponentStory<typeof LemonTable> = (props: LemonTableProps<Record<string, any>>) => {
const EmptyTemplate: StoryFn<typeof LemonTable> = (props: LemonTableProps<Record<string, any>>) => {
return (
<LemonTable
{...props}
@@ -147,19 +150,19 @@ const EmptyTemplate: ComponentStory<typeof LemonTable> = (props: LemonTableProps
)
}
export const Basic = BasicTemplate.bind({})
export const Basic: Story = BasicTemplate.bind({})
Basic.args = {}
export const Grouped = GroupedTemplate.bind({})
export const Grouped: Story = GroupedTemplate.bind({})
Grouped.args = {}
export const Empty = EmptyTemplate.bind({})
export const Empty: Story = EmptyTemplate.bind({})
Empty.args = {}
export const PaginatedAutomatically = BasicTemplate.bind({})
export const PaginatedAutomatically: Story = BasicTemplate.bind({})
PaginatedAutomatically.args = { nouns: ['person', 'people'], pagination: { pageSize: 3 } }
export const WithExpandableRows = BasicTemplate.bind({})
export const WithExpandableRows: Story = BasicTemplate.bind({})
WithExpandableRows.args = {
expandable: {
rowExpandable: (record) => record.occupation !== 'Retired',
@@ -169,34 +172,34 @@ WithExpandableRows.args = {
},
}
export const Small = BasicTemplate.bind({})
export const Small: Story = BasicTemplate.bind({})
Small.args = { size: 'small' }
export const XSmall = BasicTemplate.bind({})
export const XSmall: Story = BasicTemplate.bind({})
XSmall.args = { size: 'xs' }
export const Embedded = BasicTemplate.bind({})
export const Embedded: Story = BasicTemplate.bind({})
Embedded.args = { embedded: true }
export const BorderlessRows = BasicTemplate.bind({})
export const BorderlessRows: Story = BasicTemplate.bind({})
BorderlessRows.args = { borderedRows: false }
export const Loading = BasicTemplate.bind({})
export const Loading: Story = BasicTemplate.bind({})
Loading.args = { loading: true }
export const EmptyLoading = EmptyTemplate.bind({})
export const EmptyLoading: Story = EmptyTemplate.bind({})
EmptyLoading.args = { loading: true }
export const EmptyLoadingWithManySkeletonRows = EmptyTemplate.bind({})
export const EmptyLoadingWithManySkeletonRows: Story = EmptyTemplate.bind({})
EmptyLoadingWithManySkeletonRows.args = { loading: true, loadingSkeletonRows: 10 }
export const WithoutHeader = BasicTemplate.bind({})
export const WithoutHeader: Story = BasicTemplate.bind({})
WithoutHeader.args = { showHeader: false }
export const WithoutUppercasingInHeader = BasicTemplate.bind({})
export const WithoutUppercasingInHeader: Story = BasicTemplate.bind({})
WithoutUppercasingInHeader.args = { uppercaseHeader: false }
export const WithFooter = BasicTemplate.bind({})
export const WithFooter: Story = BasicTemplate.bind({})
WithFooter.args = {
footer: (
<>
@@ -209,7 +212,7 @@ WithFooter.args = {
),
}
export const WithColorCodedRows = BasicTemplate.bind({})
export const WithColorCodedRows: Story = BasicTemplate.bind({})
WithColorCodedRows.args = {
rowRibbonColor: ({ occupation }) =>
occupation === 'Engineer'
@@ -221,15 +224,15 @@ WithColorCodedRows.args = {
: null,
}
export const WithHighlightedRows = BasicTemplate.bind({})
export const WithHighlightedRows: Story = BasicTemplate.bind({})
WithHighlightedRows.args = {
rowStatus: ({ occupation }) => (['Retired', 'Body-builder'].includes(occupation) ? 'highlighted' : null),
}
export const WithMandatorySorting = BasicTemplate.bind({})
export const WithMandatorySorting: Story = BasicTemplate.bind({})
WithMandatorySorting.args = { defaultSorting: { columnKey: 'name', order: 1 }, noSortingCancellation: true }
export const WithStickyFirstColumn: Story = () => {
export const WithStickyFirstColumn = (): JSX.Element => {
useEffect(() => {
const scrollableInner = document.querySelector(
'#story--lemon-ui-lemon-table--with-sticky-first-column .scrollable__inner'

View File

@@ -1,8 +1,9 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { useState } from 'react'
import { LemonTab, LemonTabs as LemonTabsComponent } from './LemonTabs'
export default {
type Story = StoryObj<typeof LemonTabsComponent>
const meta: Meta<typeof LemonTabsComponent> = {
title: 'Lemon UI/Lemon Tabs',
component: LemonTabsComponent,
argTypes: {
@@ -10,41 +11,43 @@ export default {
control: {
type: 'object',
},
defaultValue: [
{
key: 'calendar',
label: 'Calendar',
content: <div>Imagine some calendar here. 🗓</div>,
},
{
key: 'calculator',
label: 'Calculator',
tooltip: 'Calculate 2+2, as well as 1/0.',
content: <div>Imagine some calculator here. 🔢</div>,
},
{
key: 'banana',
label: 'Banana',
content: <div>Imagine some banana here. 🍌</div>,
},
{
key: 'settings',
label: 'Settings',
content: <div>Imagine some settings here. </div>,
},
] as LemonTab<'calendar' | 'calculator' | 'banana' | 'settings'>[],
},
// Show value and onChange, but disable editing as they're handled by the template
value: { control: { disable: true } },
onChange: { control: { disable: true } },
},
} as ComponentMeta<typeof LemonTabsComponent>
tags: ['autodocs'],
args: {
tabs: [
{
key: 'calendar',
label: 'Calendar',
content: <div>Imagine some calendar here. 🗓</div>,
},
{
key: 'calculator',
label: 'Calculator',
tooltip: 'Calculate 2+2, as well as 1/0.',
content: <div>Imagine some calculator here. 🔢</div>,
},
{
key: 'banana',
label: 'Banana',
content: <div>Imagine some banana here. 🍌</div>,
},
{
key: 'settings',
label: 'Settings',
content: <div>Imagine some settings here. </div>,
},
] as LemonTab<'calendar' | 'calculator' | 'banana' | 'settings'>[],
},
}
export default meta
const Template: ComponentStory<typeof LemonTabsComponent> = (props) => {
const Template: StoryFn<typeof LemonTabsComponent> = (props) => {
const [activeKey, setActiveKey] = useState((props.tabs[0] as LemonTab<string | number>).key)
return <LemonTabsComponent {...props} activeKey={activeKey} onChange={(newValue) => setActiveKey(newValue)} />
}
export const LemonTabs = Template.bind({})
export const LemonTabs: Story = Template.bind({})
LemonTabs.args = {}

View File

@@ -1,10 +1,13 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonTag as LemonTagComponent, LemonTagType } from './LemonTag'
export default {
type Story = StoryObj<typeof LemonTagComponent>
const meta: Meta<typeof LemonTagComponent> = {
title: 'Lemon UI/Lemon Tag',
component: LemonTagComponent,
} as ComponentMeta<typeof LemonTagComponent>
tags: ['autodocs'],
}
export default meta
const ALL_COLORS: LemonTagType[] = [
'primary',
@@ -18,7 +21,7 @@ const ALL_COLORS: LemonTagType[] = [
'none',
]
const Template: ComponentStory<typeof LemonTagComponent> = (props) => {
const Template: StoryFn<typeof LemonTagComponent> = (props) => {
return (
<div className="flex gap-1 flex-wrap">
{ALL_COLORS.map((type) => (
@@ -30,5 +33,5 @@ const Template: ComponentStory<typeof LemonTagComponent> = (props) => {
)
}
export const LemonTag = Template.bind({})
export const LemonTag: Story = Template.bind({})
LemonTag.args = {}

View File

@@ -1,31 +1,31 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory, Story } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonTextArea, LemonTextAreaProps, LemonTextMarkdown as _LemonTextMarkdown } from './LemonTextArea'
export default {
type Story = StoryObj<typeof LemonTextArea>
const meta: Meta<typeof LemonTextArea> = {
title: 'Lemon UI/Lemon Text Area',
component: LemonTextArea,
argTypes: {
value: {
defaultValue:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
},
args: {
value: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
},
} as ComponentMeta<typeof LemonTextArea>
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof LemonTextArea> = (props: LemonTextAreaProps) => {
const Template: StoryFn<typeof LemonTextArea> = (props: LemonTextAreaProps) => {
const [value, setValue] = useState(props.value)
return <LemonTextArea {...props} value={value} onChange={(newValue) => setValue(newValue)} />
}
export const Basic = Template.bind({})
export const Basic: Story = Template.bind({})
Basic.args = {}
export const Disabled = Template.bind({})
export const Disabled: Story = Template.bind({})
Disabled.args = { disabled: true }
export const LemonTextMarkdown: Story = () => {
export const LemonTextMarkdown = (): JSX.Element => {
const [value, setValue] = useState('# Title\n\n**bold** _italic_')
return <_LemonTextMarkdown value={value} onChange={(newValue) => setValue(newValue)} />
}

View File

@@ -1,8 +1,9 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { Lettermark, LettermarkColor, LettermarkProps } from './Lettermark'
import { range } from 'lib/utils'
export default {
type Story = StoryObj<typeof Lettermark>
const meta: Meta<typeof Lettermark> = {
title: 'Lemon UI/Lettermark',
component: Lettermark,
parameters: {
@@ -13,13 +14,15 @@ export default {
},
},
},
} as ComponentMeta<typeof Lettermark>
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof Lettermark> = (props: LettermarkProps) => {
const Template: StoryFn<typeof Lettermark> = (props: LettermarkProps) => {
return <Lettermark {...props} />
}
export const Base = Template.bind({})
export const Base: Story = Template.bind({})
Base.args = { name: 'Athena' }
export const Overview = (): JSX.Element => {
@@ -47,14 +50,14 @@ export const Overview = (): JSX.Element => {
)
}
export const String = Template.bind({})
export const String: Story = Template.bind({})
String.args = { name: 'Athena' }
export const Number = Template.bind({})
export const Number: Story = Template.bind({})
Number.args = { name: 42 }
export const Unknown = Template.bind({})
export const Unknown: Story = Template.bind({})
Unknown.args = { name: null }
export const Gray = Template.bind({})
export const Gray: Story = Template.bind({})
Gray.args = { name: 5, color: LettermarkColor.Gray }

View File

@@ -1,30 +1,31 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { Link, LinkProps } from './Link'
import { urls } from 'scenes/urls'
export default {
type Story = StoryObj<typeof Link>
const meta: Meta<typeof Link> = {
title: 'Lemon UI/Link',
component: Link,
argTypes: {
children: {
defaultValue: 'Click me',
},
args: {
children: 'Click me',
},
} as ComponentMeta<typeof Link>
tags: ['autodocs'],
}
export default meta
const BasicTemplate: ComponentStory<typeof Link> = (props: LinkProps) => {
const BasicTemplate: StoryFn<typeof Link> = (props: LinkProps) => {
return <Link {...props} />
}
export const Default = BasicTemplate.bind({})
export const Default: Story = BasicTemplate.bind({})
Default.args = {}
export const ToLink = BasicTemplate.bind({})
export const ToLink: Story = BasicTemplate.bind({})
ToLink.args = {
to: urls.projectHomepage(),
}
export const DisabledWithReason = BasicTemplate.bind({})
export const DisabledWithReason: Story = BasicTemplate.bind({})
DisabledWithReason.args = {
disabledReason: 'Not allowed',
}

View File

@@ -1,17 +1,20 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { PaginationControl, PaginationControlProps } from './PaginationControl'
import { usePagination } from './usePagination'
export default {
type Story = StoryObj<typeof PaginationControl>
const meta: Meta<typeof PaginationControl> = {
title: 'Lemon UI/Pagination Control',
component: PaginationControl,
} as ComponentMeta<typeof PaginationControl>
tags: ['autodocs'],
}
export default meta
const DATA_SOURCE = Array(43)
.fill(null)
.map((_, index) => index)
const Template: ComponentStory<typeof PaginationControl> = (props: Partial<PaginationControlProps<any>>) => {
const Template: StoryFn<typeof PaginationControl> = (props: Partial<PaginationControlProps<any>>) => {
const state = usePagination(DATA_SOURCE, { pageSize: 10 })
return <PaginationControl {...state} {...props} />
}
@@ -19,5 +22,5 @@ const Template: ComponentStory<typeof PaginationControl> = (props: Partial<Pagin
export const PaginationControl_ = Template.bind({})
PaginationControl_.args = {}
export const Bordered = Template.bind({})
export const Bordered: Story = Template.bind({})
Bordered.args = { bordered: true }

View File

@@ -1,9 +1,10 @@
import { ComponentStory, ComponentMeta } from '@storybook/react'
import { StoryFn, Meta, StoryObj } from '@storybook/react'
import { Popover } from './Popover'
import { IconArrowDropDown } from 'lib/lemon-ui/icons'
export default {
type Story = StoryObj<typeof Popover>
const meta: Meta<typeof Popover> = {
title: 'Lemon UI/Popover',
component: Popover,
parameters: {
@@ -11,11 +12,13 @@ export default {
skip: true, // FIXME: This story needs a play test for the popup to show up in snapshots
},
},
} as ComponentMeta<typeof Popover>
tags: ['autodocs'],
}
export default meta
const Template: ComponentStory<typeof Popover> = (args) => <Popover {...args} />
const Template: StoryFn<typeof Popover> = (args) => <Popover {...args} />
export const Popover_ = Template.bind({})
export const Popover_: Story = Template.bind({})
Popover_.args = {
visible: true,
children: (

View File

@@ -1,5 +1,5 @@
import { ProfileBubbles as ProfileBubblesComponent, ProfileBubblesProps } from './ProfileBubbles'
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { alphabet, range } from 'lib/utils'
const DUMMIES: ProfileBubblesProps['people'] = [
@@ -9,15 +9,15 @@ const DUMMIES: ProfileBubblesProps['people'] = [
{ email: 'joe@posthog.com', name: 'Joe' },
]
export default {
const meta: Meta<typeof ProfileBubblesComponent> = {
title: 'Lemon UI/Profile Bubbles',
component: ProfileBubblesComponent,
argTypes: {
people: {
defaultValue: DUMMIES,
},
args: {
people: DUMMIES,
},
} as ComponentMeta<typeof ProfileBubblesComponent>
tags: ['autodocs'],
}
export default meta
export function OneBubble(props: any): JSX.Element {
return <ProfileBubblesComponent {...props} people={DUMMIES.slice(0, 1)} />

View File

@@ -1,12 +1,14 @@
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import { Spinner as Spinner, SpinnerOverlay } from './Spinner'
import { LemonButton } from '@posthog/lemon-ui'
export default {
const meta: Meta<typeof Spinner> = {
title: 'Lemon UI/Spinner',
component: Spinner,
} as ComponentMeta<typeof Spinner>
tags: ['autodocs'],
}
export default meta
export function Default(): JSX.Element {
return <Spinner />

View File

@@ -1,16 +1,16 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn } from '@storybook/react'
import { Splotch, SplotchColor, SplotchProps } from './Splotch'
export default {
const meta: Meta<typeof Splotch> = {
title: 'Lemon UI/Splotch',
component: Splotch,
argTypes: {
color: {
defaultValue: SplotchColor.Purple,
},
args: {
color: SplotchColor.Purple,
},
} as ComponentMeta<typeof Splotch>
tags: ['autodocs'],
}
export default meta
export const _Splotch: ComponentStory<typeof Splotch> = (props: SplotchProps) => {
export const _Splotch: StoryFn<typeof Splotch> = (props: SplotchProps) => {
return <Splotch {...props} />
}

View File

@@ -2,18 +2,18 @@ import { Meta } from '@storybook/react'
import { Popover } from './Popover/Popover'
import { useState } from 'react'
export default {
const meta: Meta = {
title: 'Lemon UI/Colors',
parameters: {
options: { showPanel: false },
docs: {
description: {
component: 'Colors can be used in a variety of ways',
},
},
},
} as Meta
tags: ['autodocs'],
}
export default meta
const colorGroups = {
primary: ['primary-highlight', 'primary-light', 'primary', 'primary-dark'],
danger: ['danger-highlight', 'danger-light', 'danger', 'danger-dark'],

View File

@@ -1,16 +1,15 @@
import * as React from 'react'
import * as icons from './icons'
import { Meta, Story } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { LemonTable } from 'lib/lemon-ui/LemonTable'
import { LemonCheckbox } from 'lib/lemon-ui/LemonCheckbox'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
const { IconGauge, IconWithCount } = icons
export default {
const meta: Meta = {
title: 'Lemon UI/Icons',
parameters: {
options: { showPanel: false },
docs: {
description: {
component: `
@@ -28,7 +27,9 @@ When adding new icons from Figma please make sure to:
},
},
},
} as Meta
tags: ['autodocs'],
}
export default meta
interface IconDefinition {
name: string
@@ -40,7 +41,8 @@ const allIcons: IconDefinition[] = Object.entries(icons)
.map(([key, Icon]) => ({ name: key, icon: Icon }))
.sort((a, b) => a.name.localeCompare(b.name))
const LibraryTemplate: Story<{ letter?: string | null }> = ({ letter }) => {
type LibraryType = StoryObj<{ letter?: string | null }>
const LibraryTemplate: StoryFn<{ letter?: string | null }> = ({ letter }) => {
const [showBorder, setShowBorder] = React.useState(true)
const filteredIcons =
letter === undefined
@@ -101,90 +103,90 @@ const LibraryTemplate: Story<{ letter?: string | null }> = ({ letter }) => {
}
// This is for actual Storybook users
export const Library = LibraryTemplate.bind({})
export const Library: LibraryType = LibraryTemplate.bind({})
Library.parameters = { testOptions: { skip: true } }
// These are just for snapshots. As opposed to the full library, the stories below are segmented by the first letter
// of the icon name, which greatly optimizes both the UX and storage aspects of diffing snapshots.
export const ShelfA = LibraryTemplate.bind({})
export const ShelfA: LibraryType = LibraryTemplate.bind({})
ShelfA.args = { letter: 'a' }
ShelfA.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfB = LibraryTemplate.bind({})
export const ShelfB: LibraryType = LibraryTemplate.bind({})
ShelfB.args = { letter: 'b' }
ShelfB.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfC = LibraryTemplate.bind({})
export const ShelfC: LibraryType = LibraryTemplate.bind({})
ShelfC.args = { letter: 'c' }
ShelfC.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfD = LibraryTemplate.bind({})
export const ShelfD: LibraryType = LibraryTemplate.bind({})
ShelfD.args = { letter: 'd' }
ShelfD.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfE = LibraryTemplate.bind({})
export const ShelfE: LibraryType = LibraryTemplate.bind({})
ShelfE.args = { letter: 'e' }
ShelfE.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfF = LibraryTemplate.bind({})
export const ShelfF: LibraryType = LibraryTemplate.bind({})
ShelfF.args = { letter: 'f' }
ShelfF.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfG = LibraryTemplate.bind({})
export const ShelfG: LibraryType = LibraryTemplate.bind({})
ShelfG.args = { letter: 'g' }
ShelfG.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfH = LibraryTemplate.bind({})
export const ShelfH: LibraryType = LibraryTemplate.bind({})
ShelfH.args = { letter: 'h' }
ShelfH.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfI = LibraryTemplate.bind({})
export const ShelfI: LibraryType = LibraryTemplate.bind({})
ShelfI.args = { letter: 'i' }
ShelfI.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfJ = LibraryTemplate.bind({})
export const ShelfJ: LibraryType = LibraryTemplate.bind({})
ShelfJ.args = { letter: 'j' }
ShelfJ.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfK = LibraryTemplate.bind({})
export const ShelfK: LibraryType = LibraryTemplate.bind({})
ShelfK.args = { letter: 'k' }
ShelfK.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfL = LibraryTemplate.bind({})
export const ShelfL: LibraryType = LibraryTemplate.bind({})
ShelfL.args = { letter: 'l' }
ShelfL.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfM = LibraryTemplate.bind({})
export const ShelfM: LibraryType = LibraryTemplate.bind({})
ShelfM.args = { letter: 'm' }
ShelfM.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfN = LibraryTemplate.bind({})
export const ShelfN: LibraryType = LibraryTemplate.bind({})
ShelfN.args = { letter: 'n' }
ShelfN.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfO = LibraryTemplate.bind({})
export const ShelfO: LibraryType = LibraryTemplate.bind({})
ShelfO.args = { letter: 'o' }
ShelfO.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfP = LibraryTemplate.bind({})
export const ShelfP: LibraryType = LibraryTemplate.bind({})
ShelfP.args = { letter: 'p' }
ShelfP.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfQ = LibraryTemplate.bind({})
export const ShelfQ: LibraryType = LibraryTemplate.bind({})
ShelfQ.args = { letter: 'q' }
ShelfQ.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfR = LibraryTemplate.bind({})
export const ShelfR: LibraryType = LibraryTemplate.bind({})
ShelfR.args = { letter: 'r' }
ShelfR.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfS = LibraryTemplate.bind({})
export const ShelfS: LibraryType = LibraryTemplate.bind({})
ShelfS.args = { letter: 's' }
ShelfS.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfT = LibraryTemplate.bind({})
export const ShelfT: LibraryType = LibraryTemplate.bind({})
ShelfT.args = { letter: 't' }
ShelfT.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfU = LibraryTemplate.bind({})
export const ShelfU: LibraryType = LibraryTemplate.bind({})
ShelfU.args = { letter: 'u' }
ShelfU.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfV = LibraryTemplate.bind({})
export const ShelfV: LibraryType = LibraryTemplate.bind({})
ShelfV.args = { letter: 'v' }
ShelfV.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfW = LibraryTemplate.bind({})
export const ShelfW: LibraryType = LibraryTemplate.bind({})
ShelfW.args = { letter: 'w' }
ShelfW.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfX = LibraryTemplate.bind({})
export const ShelfX: LibraryType = LibraryTemplate.bind({})
ShelfX.args = { letter: 'x' }
ShelfX.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfY = LibraryTemplate.bind({})
export const ShelfY: LibraryType = LibraryTemplate.bind({})
ShelfY.args = { letter: 'y' }
ShelfY.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfZ = LibraryTemplate.bind({})
export const ShelfZ: LibraryType = LibraryTemplate.bind({})
ShelfZ.args = { letter: 'z' }
ShelfZ.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }
export const ShelfOther = LibraryTemplate.bind({})
export const ShelfOther: LibraryType = LibraryTemplate.bind({})
ShelfOther.args = { letter: null }
ShelfOther.parameters = { testOptions: { snapshotTargetSelector: '.LemonTable tbody' } }

View File

@@ -5,11 +5,11 @@ import { ModalPrompt, PopupPrompt, Prompt } from './Prompt'
import { promptLogic } from './promptLogic'
import BlankDashboardHog from 'public/blank-dashboard-hog.png'
export default {
const meta: Meta = {
title: 'Components/Prompts',
component: Prompt,
} as Meta
}
export default meta
export function ModalPrompt_(): JSX.Element {
// Ideally we'd instead mock the feature flag and payload but I couldn't get that to work
const payload = {

View File

@@ -1,14 +1,14 @@
import { rest, setupWorker } from 'msw'
import { handlers } from '~/mocks/handlers'
import { Mocks, mocksToHandlers } from '~/mocks/utils'
import { DecoratorFunction } from '@storybook/addons'
import { DecoratorFunction } from '@storybook/types'
// Default handlers ensure no request is unhandled by msw
export const worker = setupWorker(...handlers)
export const useStorybookMocks = (mocks: Mocks): void => worker.use(...mocksToHandlers(mocks))
export const mswDecorator = (mocks: Mocks): DecoratorFunction<JSX.Element> => {
export const mswDecorator = (mocks: Mocks): DecoratorFunction<any> => {
return function StoryMock(Story, { parameters }): JSX.Element {
// merge the default mocks provided in `preview.tsx` with any provided by the story
// allow the story to override defaults

View File

@@ -1,22 +1,19 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { examples } from '~/queries/examples'
import { mswDecorator } from '~/mocks/browser'
import events from './__mocks__/EventsNode.json'
import persons from './__mocks__/PersonsNode.json'
import { Query } from '~/queries/Query/Query'
export default {
type Story = StoryObj<typeof Query>
const meta: Meta<typeof Query> = {
title: 'Queries/DataNode',
component: Query,
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
testOptions: { skip: true },
},
argTypes: {
query: { defaultValue: {} },
},
decorators: [
mswDecorator({
get: {
@@ -25,12 +22,13 @@ export default {
},
}),
],
} as ComponentMeta<typeof Query>
}
export default meta
const QueryTemplate: ComponentStory<typeof Query> = (args) => <Query {...args} context={{ showQueryEditor: true }} />
const QueryTemplate: StoryFn<typeof Query> = (args) => <Query {...args} context={{ showQueryEditor: true }} />
export const Events = QueryTemplate.bind({})
export const Events: Story = QueryTemplate.bind({})
Events.args = { query: examples['Events'] }
export const Persons = QueryTemplate.bind({})
export const Persons: Story = QueryTemplate.bind({})
Persons.args = { query: examples['Persons'] }

View File

@@ -1,22 +1,19 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { Query } from '~/queries/Query/Query'
import { examples } from './DataTable.examples'
import { mswDecorator } from '~/mocks/browser'
import events from '../DataNode/__mocks__/EventsNode.json'
import persons from '../DataNode/__mocks__/PersonsNode.json'
export default {
type Story = StoryObj<typeof Query>
const meta: Meta<typeof Query> = {
title: 'Queries/DataTable',
component: Query,
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
testOptions: { skip: true },
},
argTypes: {
query: { defaultValue: {} },
},
decorators: [
mswDecorator({
get: {
@@ -25,30 +22,31 @@ export default {
},
}),
],
} as ComponentMeta<typeof Query>
}
export default meta
const QueryTemplate: ComponentStory<typeof Query> = (args) => <Query {...args} context={{ showQueryEditor: true }} />
const QueryTemplate: StoryFn<typeof Query> = (args) => <Query {...args} context={{ showQueryEditor: true }} />
export const AllDefaults = QueryTemplate.bind({})
export const AllDefaults: Story = QueryTemplate.bind({})
AllDefaults.args = { query: examples['AllDefaults'] }
export const Minimalist = QueryTemplate.bind({})
export const Minimalist: Story = QueryTemplate.bind({})
Minimalist.args = { query: examples['Minimalist'] }
export const ManyColumns = QueryTemplate.bind({})
export const ManyColumns: Story = QueryTemplate.bind({})
ManyColumns.args = { query: examples['ManyColumns'] }
export const ShowFilters = QueryTemplate.bind({})
export const ShowFilters: Story = QueryTemplate.bind({})
ShowFilters.args = { query: examples['ShowFilters'] }
export const ShowTools = QueryTemplate.bind({})
export const ShowTools: Story = QueryTemplate.bind({})
ShowTools.args = { query: examples['ShowTools'] }
export const ShowAllTheThings = QueryTemplate.bind({})
export const ShowAllTheThings: Story = QueryTemplate.bind({})
ShowAllTheThings.args = { query: examples['ShowAllTheThings'] }
export const Persons = QueryTemplate.bind({})
export const Persons: Story = QueryTemplate.bind({})
Persons.args = { query: examples['Persons'] }
export const PersonsTable = QueryTemplate.bind({})
export const PersonsTable: Story = QueryTemplate.bind({})
PersonsTable.args = { query: examples['PersonsTable'] }

View File

@@ -1,10 +1,11 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { FilterLogicalOperator } from '~/types'
import { AndOrFilterSelect } from './AndOrFilterSelect'
export default {
type Story = StoryObj<typeof AndOrFilterSelect>
const meta: Meta<typeof AndOrFilterSelect> = {
title: 'Filters/PropertyGroupFilters (Data Exploration)/AndOrFilterSelect',
component: AndOrFilterSelect,
argTypes: {
@@ -18,11 +19,12 @@ export default {
args: {
value: FilterLogicalOperator.And,
},
} as ComponentMeta<typeof AndOrFilterSelect>
}
export default meta
const Template: ComponentStory<typeof AndOrFilterSelect> = (args) => {
const Template: StoryFn<typeof AndOrFilterSelect> = (args) => {
const [value, setValue] = useState(args.value)
return <AndOrFilterSelect {...args} value={value} onChange={setValue} />
}
export const Default = Template.bind({})
export const Default: Story = Template.bind({})

View File

@@ -2,13 +2,12 @@ import { Meta } from '@storybook/react'
import { PreflightCheck } from './PreflightCheck'
export default {
const meta: Meta = {
title: 'Scenes-Other/Preflight',
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
},
} as Meta
}
export default meta
export const Preflight = (): JSX.Element => <PreflightCheck />

View File

@@ -2,13 +2,12 @@ import { Meta } from '@storybook/react'
import { Unsubscribe } from './Unsubscribe'
export default {
const meta: Meta = {
title: 'Scenes-Other/Unsubscribe',
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
},
} as Meta
}
export default meta
export const UnsubscribeScene = (): JSX.Element => <Unsubscribe />

View File

@@ -6,11 +6,10 @@ import { urls } from 'scenes/urls'
import { mswDecorator } from '~/mocks/browser'
import annotations from './__mocks__/annotations.json'
export default {
const meta: Meta = {
title: 'Scenes-App/Annotations',
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
testOptions: {
excludeNavigationFromSnapshot: true,
},
@@ -28,8 +27,8 @@ export default {
},
}),
],
} as Meta
}
export default meta
export const Annotations = (): JSX.Element => {
useEffect(() => {
router.actions.push(urls.annotations())

View File

@@ -8,11 +8,10 @@ import { urls } from 'scenes/urls'
import { AvailableFeature } from '~/types'
import { useAvailableFeatures } from '~/mocks/features'
export default {
const meta: Meta = {
title: 'Scenes-App/Apps/App Metrics',
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
testOptions: {
excludeNavigationFromSnapshot: true,
},
@@ -81,8 +80,8 @@ export default {
},
}),
],
} as Meta
}
export default meta
export const AppMetrics: Story = () => {
useAvailableFeatures([AvailableFeature.APP_METRICS])
useEffect(() => {

View File

@@ -6,11 +6,10 @@ import preflightJson from '~/mocks/fixtures/_preflight.json'
import { InviteSignup } from './InviteSignup'
import { inviteSignupLogic } from './inviteSignupLogic'
export default {
const meta: Meta = {
title: 'Scenes-Other/InviteSignup',
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
},
decorators: [
@@ -33,8 +32,8 @@ export default {
},
}),
],
} as Meta
}
export default meta
export const SelfHosted = (): JSX.Element => {
useStorybookMocks({
get: {

View File

@@ -9,11 +9,10 @@ import { urls } from 'scenes/urls'
import { loginLogic } from './loginLogic'
import { Login2FA } from './Login2FA'
export default {
const meta: Meta = {
title: 'Scenes-Other/Login',
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
},
decorators: [
@@ -23,8 +22,8 @@ export default {
},
}),
],
} as Meta
}
export default meta
export const Cloud = (): JSX.Element => {
useStorybookMocks({
get: {

View File

@@ -7,15 +7,14 @@ import preflightJson from '~/mocks/fixtures/_preflight.json'
import { passwordResetLogic } from 'scenes/authentication/passwordResetLogic'
// some metadata and optional parameters
export default {
const meta: Meta = {
title: 'Scenes-Other/Password Reset',
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
},
} as Meta
}
export default meta
// export more stories with different state
export const NoSMTP = (): JSX.Element => {
useStorybookMocks({

View File

@@ -7,15 +7,14 @@ import { urls } from 'scenes/urls'
import { useStorybookMocks } from '~/mocks/browser'
// some metadata and optional parameters
export default {
const meta: Meta = {
title: 'Scenes-Other/Password Reset Complete',
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
},
} as Meta
}
export default meta
// export more stories with different state
export const Default = (): JSX.Element => {
useStorybookMocks({

View File

@@ -6,11 +6,10 @@ import { userLogic } from 'scenes/userLogic'
import preflightJson from '~/mocks/fixtures/_preflight.json'
import { SignupContainer } from './SignupContainer'
export default {
const meta: Meta = {
title: 'Scenes-Other/Signup',
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
},
decorators: [
@@ -19,8 +18,8 @@ export default {
post: { '/api/signup': (_, __, ctx) => [ctx.delay(1000), ctx.status(200), ctx.json({ success: true })] },
}),
],
} as Meta
}
export default meta
export const SelfHosted = (): JSX.Element => {
useStorybookMocks({
get: {

View File

@@ -4,15 +4,14 @@ import { useEffect } from 'react'
import { VerifyEmail } from './VerifyEmail'
import { verifyEmailLogic } from './verifyEmailLogic'
export default {
const meta: Meta = {
title: 'Scenes-Other/Verify Email',
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
},
} as Meta
}
export default meta
export const VerifyEmailPending: Story = () => {
useEffect(() => {
verifyEmailLogic.actions.setView('pending')

View File

@@ -5,11 +5,10 @@ import preflightJson from '~/mocks/fixtures/_preflight.json'
import billingJson from '~/mocks/fixtures/_billing_v2.json'
import billingJsonWithDiscount from '~/mocks/fixtures/_billing_v2_with_discount.json'
export default {
const meta: Meta = {
title: 'Scenes-Other/Billing v2',
parameters: {
layout: 'fullscreen',
options: { showPanel: false },
viewMode: 'story',
mockDate: '2023-05-25',
},
@@ -24,8 +23,8 @@ export default {
},
}),
],
} as Meta
}
export default meta
export const _BillingV2 = (): JSX.Element => {
useStorybookMocks({
get: {

View File

@@ -1,5 +1,5 @@
import { useState } from 'react'
import { ComponentMeta } from '@storybook/react'
import { Meta } from '@storybook/react'
import {
CohortCriteriaRowBuilder,
CohortCriteriaRowBuilderProps,
@@ -13,11 +13,12 @@ import { BehavioralEventType } from '~/types'
import { Form } from 'kea-forms'
import { cohortEditLogic } from 'scenes/cohorts/cohortEditLogic'
export default {
const meta: Meta<typeof CohortCriteriaRowBuilder> = {
title: 'Filters/Cohort Filters/Row Builder',
component: CohortCriteriaRowBuilder,
decorators: [taxonomicFilterMocksDecorator],
} as ComponentMeta<typeof CohortCriteriaRowBuilder>
}
export default meta
export function _CohortCriteriaRowBuilder(props: CohortCriteriaRowBuilderProps): JSX.Element {
useMountedLogic(actionsModel)

View File

@@ -1,17 +1,19 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { CohortNumberField } from './CohortField'
import { renderField } from 'scenes/cohorts/CohortFilters/constants'
import { CohortNumberFieldProps, FilterType } from 'scenes/cohorts/CohortFilters/types'
import { useMountedLogic } from 'kea'
import { cohortEditLogic } from 'scenes/cohorts/cohortEditLogic'
export default {
type Story = StoryObj<typeof CohortNumberField>
const meta: Meta<typeof CohortNumberField> = {
title: 'Filters/Cohort Filters/Fields/Number',
component: CohortNumberField,
} as ComponentMeta<typeof CohortNumberField>
}
export default meta
const Template: ComponentStory<typeof CohortNumberField> = (props: CohortNumberFieldProps) => {
const Template: StoryFn<typeof CohortNumberField> = (props: CohortNumberFieldProps) => {
useMountedLogic(cohortEditLogic({ id: 1 }))
const [value, setValue] = useState<number>(30)
return renderField[FilterType.Number]({
@@ -24,5 +26,5 @@ const Template: ComponentStory<typeof CohortNumberField> = (props: CohortNumberF
})
}
export const Basic = Template.bind({})
export const Basic: Story = Template.bind({})
Basic.args = {}

View File

@@ -1,18 +1,18 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { CohortPersonPropertiesValuesField } from './CohortField'
import { renderField } from 'scenes/cohorts/CohortFilters/constants'
import { CohortPersonPropertiesValuesFieldProps, FilterType } from 'scenes/cohorts/CohortFilters/types'
import { PropertyOperator } from '~/types'
export default {
type Story = StoryObj<typeof CohortPersonPropertiesValuesField>
const meta: Meta<typeof CohortPersonPropertiesValuesField> = {
title: 'Filters/Cohort Filters/Fields/Person Properties',
component: CohortPersonPropertiesValuesField,
} as ComponentMeta<typeof CohortPersonPropertiesValuesField>
}
export default meta
const Template: ComponentStory<typeof CohortPersonPropertiesValuesField> = (
props: CohortPersonPropertiesValuesFieldProps
) => {
const Template: StoryFn<typeof CohortPersonPropertiesValuesField> = (props: CohortPersonPropertiesValuesFieldProps) => {
const [value, setValue] = useState<string | undefined>('Chrome')
return renderField[FilterType.PersonPropertyValues]({
...props,
@@ -23,5 +23,5 @@ const Template: ComponentStory<typeof CohortPersonPropertiesValuesField> = (
})
}
export const Basic = Template.bind({})
export const Basic: Story = Template.bind({})
Basic.args = {}

View File

@@ -1,14 +1,16 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { CohortSelectorField } from './CohortField'
import { CohortSelectorFieldProps, FieldOptionsType } from 'scenes/cohorts/CohortFilters/types'
export default {
type Story = StoryObj<typeof CohortSelectorField>
const meta: Meta<typeof CohortSelectorField> = {
title: 'Filters/Cohort Filters/Fields/Select',
component: CohortSelectorField,
} as ComponentMeta<typeof CohortSelectorField>
}
export default meta
const Template: ComponentStory<typeof CohortSelectorField> = (props: CohortSelectorFieldProps) => {
const Template: StoryFn<typeof CohortSelectorField> = (props: CohortSelectorFieldProps) => {
const [value, setValue] = useState<string | undefined>(
Object.keys(props.fieldOptionGroupTypes?.[0] ?? {})?.[0] ?? null
)
@@ -22,19 +24,19 @@ const Template: ComponentStory<typeof CohortSelectorField> = (props: CohortSelec
)
}
export const AggregationSelector = Template.bind({})
export const AggregationSelector: Story = Template.bind({})
AggregationSelector.args = {
fieldOptionGroupTypes: [FieldOptionsType.EventAggregation, FieldOptionsType.PropertyAggregation],
placeholder: 'Choose',
}
export const ActorsSelector = Template.bind({})
export const ActorsSelector: Story = Template.bind({})
ActorsSelector.args = {
fieldOptionGroupTypes: [FieldOptionsType.Actors],
placeholder: 'Choose',
}
export const BehavioralSelector = Template.bind({})
export const BehavioralSelector: Story = Template.bind({})
BehavioralSelector.args = {
fieldOptionGroupTypes: [
FieldOptionsType.EventBehavioral,
@@ -45,25 +47,25 @@ BehavioralSelector.args = {
placeholder: 'Choose',
}
export const TimeUnitSelector = Template.bind({})
export const TimeUnitSelector: Story = Template.bind({})
TimeUnitSelector.args = {
fieldOptionGroupTypes: [FieldOptionsType.TimeUnits],
placeholder: 'Choose',
}
export const DateOperatorSelector = Template.bind({})
export const DateOperatorSelector: Story = Template.bind({})
DateOperatorSelector.args = {
fieldOptionGroupTypes: [FieldOptionsType.DateOperators],
placeholder: 'Choose',
}
export const MathOperatorSelector = Template.bind({})
export const MathOperatorSelector: Story = Template.bind({})
MathOperatorSelector.args = {
fieldOptionGroupTypes: [FieldOptionsType.MathOperators],
placeholder: 'Choose',
}
export const ValueOptionSelector = Template.bind({})
export const ValueOptionSelector: Story = Template.bind({})
ValueOptionSelector.args = {
fieldOptionGroupTypes: [FieldOptionsType.ValueOptions],
placeholder: 'Choose',

View File

@@ -1,5 +1,5 @@
import { useState } from 'react'
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { CohortTaxonomicField } from './CohortField'
import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types'
import { taxonomicFilterMocksDecorator } from 'lib/components/TaxonomicFilter/__mocks__/taxonomicFilterMocksDecorator'
@@ -8,13 +8,15 @@ import { actionsModel } from '~/models/actionsModel'
import { renderField } from 'scenes/cohorts/CohortFilters/constants'
import { CohortTaxonomicFieldProps, FilterType } from 'scenes/cohorts/CohortFilters/types'
export default {
type Story = StoryObj<typeof CohortTaxonomicField>
const meta: Meta<typeof CohortTaxonomicField> = {
title: 'Filters/Cohort Filters/Fields/Taxonomic',
component: CohortTaxonomicField,
decorators: [taxonomicFilterMocksDecorator],
} as ComponentMeta<typeof CohortTaxonomicField>
}
export default meta
const Template: ComponentStory<typeof CohortTaxonomicField> = (props: CohortTaxonomicFieldProps) => {
const Template: StoryFn<typeof CohortTaxonomicField> = (props: CohortTaxonomicFieldProps) => {
useMountedLogic(actionsModel)
const [value, setValue] = useState<string | undefined>('')
const type =
@@ -33,13 +35,13 @@ const Template: ComponentStory<typeof CohortTaxonomicField> = (props: CohortTaxo
})
}
export const EventsAndActions = Template.bind({})
export const EventsAndActions: Story = Template.bind({})
EventsAndActions.args = {
taxonomicGroupTypes: [TaxonomicFilterGroupType.Events, TaxonomicFilterGroupType.Actions],
placeholder: 'Choose event or action',
}
export const PersonProperties = Template.bind({})
export const PersonProperties: Story = Template.bind({})
PersonProperties.args = {
taxonomicGroupTypes: [TaxonomicFilterGroupType.PersonProperties],
placeholder: 'Choose person property',

View File

@@ -1,19 +1,21 @@
import { ComponentMeta, ComponentStory } from '@storybook/react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
import { CohortTextField } from './CohortField'
import { renderField } from 'scenes/cohorts/CohortFilters/constants'
import { CohortTextFieldProps, FilterType } from 'scenes/cohorts/CohortFilters/types'
export default {
type Story = StoryObj<typeof CohortTextField>
const meta: Meta<typeof CohortTextField> = {
title: 'Filters/Cohort Filters/Fields/Text',
component: CohortTextField,
} as ComponentMeta<typeof CohortTextField>
}
export default meta
const Template: ComponentStory<typeof CohortTextField> = (props: CohortTextFieldProps) => {
const Template: StoryFn<typeof CohortTextField> = (props: CohortTextFieldProps) => {
return renderField[FilterType.Text]({
...props,
value: 'in the last',
})
}
export const Basic = Template.bind({})
export const Basic: Story = Template.bind({})
Basic.args = {}

Some files were not shown because too many files have changed in this diff Show More