Skip to content

Commit

Permalink
Add responsive toggling of feature lists in pricing options component (
Browse files Browse the repository at this point in the history
…#646)

* add responsive toggling of feature lists in pricing options component

* Create green-beers-perform.md

* update snapshots

* remove unused import

* revise logic for accordion toggling
  • Loading branch information
rezrah authored Jul 15, 2024
1 parent fba1a41 commit 81e983e
Show file tree
Hide file tree
Showing 22 changed files with 411 additions and 56 deletions.
15 changes: 15 additions & 0 deletions .changeset/green-beers-perform.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@primer/react-brand": patch
---

Adds responsive toggling of feature lists in the `PricingOptions` component.

`PricingOptions.FeatureList` can now be collapsed at regular and wide viewports.

```jsx
<PricingOptions>
<PricingOptions.Item>
<PricingOptions.FeatureList expanded={{narrow: true, regular: true, wide: true}} />
</PricingOptions.Item>
</PricingOptions>
```
8 changes: 5 additions & 3 deletions apps/docs/content/components/PricingOptions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -525,9 +525,11 @@ One item per pricing plan to be displayed. Maximum of 3 items.

### PricingOptions.FeatureList

| Name | Type | Default | required | Description |
| :--------- | :--------------------------------------------------------------------------------------------- | :---------: | :------: | :------------------- |
| `children` | <PropTableValues values={['PricingOptions.Heading', 'PricingOptions.Item', ]} addLineBreaks /> | `undefined` | `true` | The list of features |
| Name | Type | Default | required | Description |
| :----------- | :--------------------------------------------------------------------------------------------- | :---------: | :------: | :---------------------------------------------------------------------------------------------------------- |
| `children` | <PropTableValues values={['PricingOptions.Heading', 'PricingOptions.Item', ]} addLineBreaks /> | `undefined` | `true` | The list of features |
| `expanded` | `boolean` | `true` | `false` | Controls visibility of feature items. Accepts Object type for granular control at different viewport sizes. |
| `hasDivider` | `boolean` | `true` | `false` | Controls visibility of a visual border between feature lists and adjacent actions |

### PricingOptions.FeatureListHeading

Expand Down
2 changes: 1 addition & 1 deletion apps/docs/scripts/components-with-animation.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export const supportedComponents = [
'Pillar',
'SectionIntro',
'Stack',
'Statistic',
'Testimonial',
'Text',
'Statistic',
'Timeline',
'Animate',
'River',
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 19 additions & 4 deletions packages/react/src/Accordion/Accordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type AccordionRootProps = BaseProps<HTMLDetailsElement> & {
children: React.ReactElement<AccordionHeadingProps | AccordionContentProps>[]
variant?: 'default' | 'emphasis'
ref?: React.RefObject<HTMLDetailsElement>
handleOpen?: (boolean) => void
} & React.HTMLAttributes<HTMLDetailsElement>

type ValidRootChildren = {
Expand All @@ -27,7 +28,7 @@ type ValidRootChildren = {
}

export const AccordionRoot = forwardRef<HTMLDetailsElement, AccordionRootProps>(
({children, className, open = false, variant = 'default', ...rest}, ref) => {
({children, className, open = false, variant = 'default', handleOpen, ...rest}, ref) => {
const detailsRef = useProvidedRefOrCreate(ref as React.RefObject<HTMLDetailsElement>)
const [isOpen, setIsOpen] = React.useState(open)

Expand All @@ -39,15 +40,22 @@ export const AccordionRoot = forwardRef<HTMLDetailsElement, AccordionRootProps>(
if (child.type === AccordionContent) {
acc.AccordionContent = React.cloneElement(child as React.ReactElement<AccordionContentProps>, {
open: isOpen,
handleOpen: (newValue: boolean) => setIsOpen(newValue),
handleOpen: (newValue: boolean) => {
setIsOpen(newValue)
},
parentRef: detailsRef,
}) as React.ReactElement<AccordionContentProps>
}
if (child.type === AccordionHeading) {
acc.AccordionHeading = React.cloneElement(child as React.ReactElement, {
variant,
open: isOpen,
handleOpen: (newValue: boolean) => setIsOpen(newValue),
handleOpen: (newValue: boolean) => {
if (handleOpen) {
handleOpen(newValue)
}
setIsOpen(newValue)
},
parentRef: detailsRef,
}) as React.ReactElement<AccordionHeadingProps>
}
Expand All @@ -57,6 +65,10 @@ export const AccordionRoot = forwardRef<HTMLDetailsElement, AccordionRootProps>(
{AccordionHeading: null, AccordionContent: null},
)

useEffect(() => {
setIsOpen(open)
}, [open])

return (
<details
className={clsx(styles.Accordion, styles[`Accordion--${variant}`], className)}
Expand Down Expand Up @@ -89,7 +101,10 @@ export const AccordionHeading = forwardRef<HTMLHeadingElement, AccordionHeadingP
const handleClick = useCallback(
(event: React.MouseEvent<HTMLDetailsElement, MouseEvent>) => {
event.preventDefault()
if (handleOpen) handleOpen(!open)

if (handleOpen) {
handleOpen(!open)
}
},
[handleOpen, open],
)
Expand Down
219 changes: 219 additions & 0 deletions packages/react/src/PricingOptions/PricingOptions.features.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react'
import {StoryFn, Meta} from '@storybook/react'
import {INITIAL_VIEWPORTS} from '@storybook/addon-viewport'

import {PricingOptions} from '.'
import {Box, Grid, Stack} from '..'
import imageExample from '../fixtures/images/bento/3.png'
Expand Down Expand Up @@ -27,6 +29,11 @@ export default {
title: 'Components/PricingOptions/Features',
component: PricingOptions,
decorators: [decorators],
parameters: {
viewport: {
viewports: INITIAL_VIEWPORTS,
},
},
} as Meta<typeof PricingOptions>

export const DefaultVariant: StoryFn<typeof PricingOptions> = () => {
Expand Down Expand Up @@ -588,3 +595,215 @@ export const WithoutFeatures: StoryFn<typeof PricingOptions> = () => {
</PricingOptions>
)
}

export const CollapsedFeatures: StoryFn<typeof PricingOptions> = () => {
return (
<PricingOptions>
<PricingOptions.Item>
<PricingOptions.Heading>Copilot Individual</PricingOptions.Heading>
<PricingOptions.Description>
Code completions, Chat, and more for indie developers and freelancers.
</PricingOptions.Description>
<PricingOptions.Price trailingText="per month / $100 per year">10</PricingOptions.Price>
<PricingOptions.FeatureList expanded={false}>
<PricingOptions.FeatureListItem>Code completions</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Chat in IDE and Mobile</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>CLI assistance</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Security vulnerability filter</PricingOptions.FeatureListItem>
</PricingOptions.FeatureList>
<PricingOptions.Footnote>
Free for verified students, teachers, and maintainers of popular open source projects.
</PricingOptions.Footnote>
<PricingOptions.PrimaryAction as="a" href="#">
Start a free trial
</PricingOptions.PrimaryAction>
</PricingOptions.Item>

<PricingOptions.Item>
<PricingOptions.Label>Recommended</PricingOptions.Label>
<PricingOptions.Heading>Copilot Business</PricingOptions.Heading>
<PricingOptions.Description>Copilot personalized to your organization.</PricingOptions.Description>
<PricingOptions.Price trailingText="per user / month">19</PricingOptions.Price>
<PricingOptions.PrimaryAction as="a" href="#">
Buy now
</PricingOptions.PrimaryAction>
<PricingOptions.SecondaryAction as="a" href="#">
Contact sales
</PricingOptions.SecondaryAction>

<PricingOptions.FeatureList expanded={false}>
<PricingOptions.FeatureListItem>Everything in Copilot Individual plus:</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Chat in IDE and Mobile</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>CLI assistance</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Security vulnerability filter</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Code referencing</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Public code filter</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>IP indemnity</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>
Enterprise-grade security, safety, and privacy
</PricingOptions.FeatureListItem>
</PricingOptions.FeatureList>
</PricingOptions.Item>

<PricingOptions.Item>
<PricingOptions.Label>Available Feb 2024</PricingOptions.Label>
<PricingOptions.Heading>Copilot Enterprise</PricingOptions.Heading>
<PricingOptions.Description>
Copilot personalized to your organization throughout the software development lifecycle. Requires GitHub
Enterprise Cloud.
</PricingOptions.Description>
<PricingOptions.Price trailingText="per user / month">39</PricingOptions.Price>
<PricingOptions.FeatureList expanded={false}>
<PricingOptions.FeatureListItem>Everything in Copilot Business plus:</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Chat in IDE and Mobile</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>CLI assistance</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Code completions</PricingOptions.FeatureListItem>
</PricingOptions.FeatureList>
<PricingOptions.PrimaryAction as="a" href="#">
Join waitlist
</PricingOptions.PrimaryAction>
</PricingOptions.Item>
</PricingOptions>
)
}

export const CollapsedFeaturesNoDividers: StoryFn<typeof PricingOptions> = () => {
return (
<PricingOptions>
<PricingOptions.Item>
<PricingOptions.Heading>Copilot Individual</PricingOptions.Heading>
<PricingOptions.Description>
Code completions, Chat, and more for indie developers and freelancers.
</PricingOptions.Description>
<PricingOptions.Price trailingText="per month / $100 per year">10</PricingOptions.Price>
<PricingOptions.FeatureList expanded={false} hasDivider={false}>
<PricingOptions.FeatureListItem>Code completions</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Chat in IDE and Mobile</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>CLI assistance</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Security vulnerability filter</PricingOptions.FeatureListItem>
</PricingOptions.FeatureList>
<PricingOptions.Footnote>
Free for verified students, teachers, and maintainers of popular open source projects.
</PricingOptions.Footnote>
<PricingOptions.PrimaryAction as="a" href="#">
Start a free trial
</PricingOptions.PrimaryAction>
</PricingOptions.Item>

<PricingOptions.Item>
<PricingOptions.Label>Recommended</PricingOptions.Label>
<PricingOptions.Heading>Copilot Business</PricingOptions.Heading>
<PricingOptions.Description>Copilot personalized to your organization.</PricingOptions.Description>
<PricingOptions.Price trailingText="per user / month">19</PricingOptions.Price>
<PricingOptions.PrimaryAction as="a" href="#">
Buy now
</PricingOptions.PrimaryAction>

<PricingOptions.FeatureList expanded={false} hasDivider={false}>
<PricingOptions.FeatureListItem>Everything in Copilot Individual plus:</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Chat in IDE and Mobile</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>CLI assistance</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Security vulnerability filter</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Code referencing</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Public code filter</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>IP indemnity</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>
Enterprise-grade security, safety, and privacy
</PricingOptions.FeatureListItem>
</PricingOptions.FeatureList>
</PricingOptions.Item>

<PricingOptions.Item>
<PricingOptions.Label>Available Feb 2024</PricingOptions.Label>
<PricingOptions.Heading>Copilot Enterprise</PricingOptions.Heading>
<PricingOptions.Description>
Copilot personalized to your organization throughout the software development lifecycle. Requires GitHub
Enterprise Cloud.
</PricingOptions.Description>
<PricingOptions.Price trailingText="per user / month">39</PricingOptions.Price>
<PricingOptions.FeatureList expanded={false} hasDivider={false}>
<PricingOptions.FeatureListItem>Everything in Copilot Business plus:</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Chat in IDE and Mobile</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>CLI assistance</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Code completions</PricingOptions.FeatureListItem>
</PricingOptions.FeatureList>
<PricingOptions.PrimaryAction as="a" href="#">
Join waitlist
</PricingOptions.PrimaryAction>
</PricingOptions.Item>
</PricingOptions>
)
}

export const ExpandedNarrow: StoryFn<typeof PricingOptions> = () => {
return (
<PricingOptions>
<PricingOptions.Item>
<PricingOptions.Heading>Copilot Individual</PricingOptions.Heading>
<PricingOptions.Description>
Code completions, Chat, and more for indie developers and freelancers.
</PricingOptions.Description>
<PricingOptions.Price trailingText="per month / $100 per year">10</PricingOptions.Price>
<PricingOptions.FeatureList expanded={{narrow: true, regular: true, wide: true}}>
<PricingOptions.FeatureListItem>Code completions</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Chat in IDE and Mobile</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>CLI assistance</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Security vulnerability filter</PricingOptions.FeatureListItem>
</PricingOptions.FeatureList>
<PricingOptions.Footnote>
Free for verified students, teachers, and maintainers of popular open source projects.
</PricingOptions.Footnote>
<PricingOptions.PrimaryAction as="a" href="#">
Start a free trial
</PricingOptions.PrimaryAction>
</PricingOptions.Item>

<PricingOptions.Item>
<PricingOptions.Label>Recommended</PricingOptions.Label>
<PricingOptions.Heading>Copilot Business</PricingOptions.Heading>
<PricingOptions.Description>Copilot personalized to your organization.</PricingOptions.Description>
<PricingOptions.Price trailingText="per user / month">19</PricingOptions.Price>
<PricingOptions.PrimaryAction as="a" href="#">
Buy now
</PricingOptions.PrimaryAction>

<PricingOptions.FeatureList expanded={{narrow: true, regular: true, wide: true}}>
<PricingOptions.FeatureListItem>Everything in Copilot Individual plus:</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Chat in IDE and Mobile</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>CLI assistance</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Security vulnerability filter</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Code referencing</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Public code filter</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>IP indemnity</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>
Enterprise-grade security, safety, and privacy
</PricingOptions.FeatureListItem>
</PricingOptions.FeatureList>
</PricingOptions.Item>

<PricingOptions.Item>
<PricingOptions.Label>Available Feb 2024</PricingOptions.Label>
<PricingOptions.Heading>Copilot Enterprise</PricingOptions.Heading>
<PricingOptions.Description>
Copilot personalized to your organization throughout the software development lifecycle. Requires GitHub
Enterprise Cloud.
</PricingOptions.Description>
<PricingOptions.Price trailingText="per user / month">39</PricingOptions.Price>
<PricingOptions.FeatureList expanded={{narrow: true, regular: true, wide: true}}>
<PricingOptions.FeatureListItem>Everything in Copilot Business plus:</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Chat in IDE and Mobile</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>CLI assistance</PricingOptions.FeatureListItem>
<PricingOptions.FeatureListItem>Code completions</PricingOptions.FeatureListItem>
</PricingOptions.FeatureList>
<PricingOptions.PrimaryAction as="a" href="#">
Join waitlist
</PricingOptions.PrimaryAction>
</PricingOptions.Item>
</PricingOptions>
)
}
ExpandedNarrow.parameters = {
viewport: {
defaultViewport: 'iphonexr',
},
}
Loading

0 comments on commit 81e983e

Please sign in to comment.