From 31d1248c73d652d7f3fc9aac486dcf1f225be627 Mon Sep 17 00:00:00 2001 From: Cole Bemis Date: Thu, 29 Sep 2022 22:41:47 -0700 Subject: [PATCH 1/7] Add async story --- src/TreeView/TreeView.stories.tsx | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/TreeView/TreeView.stories.tsx b/src/TreeView/TreeView.stories.tsx index cad45fa2a2c..35464ced989 100644 --- a/src/TreeView/TreeView.stories.tsx +++ b/src/TreeView/TreeView.stories.tsx @@ -296,4 +296,54 @@ function TreeItem({ ) } +async function wait(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)) +} + +async function loadItems(responseTime: number) { + await wait(responseTime) + return ['Avatar.tsx', 'Button.tsx', 'Checkbox.tsx'] +} + +export const Async: Story = args => { + const [isLoading, setIsLoading] = React.useState(false) + const [asyncItems, setAsyncItems] = React.useState([]) + + return ( + + + + ) +} + +Async.args = { + responseTime: 2000 +} + export default meta From b948a2e5453dbe5c09ff00e2d33e5db7abee3a5c Mon Sep 17 00:00:00 2001 From: Cole Bemis Date: Fri, 30 Sep 2022 10:30:44 -0700 Subject: [PATCH 2/7] Create TreeView.LoadingItem --- src/TreeView/TreeView.stories.tsx | 20 ++++++++++++++------ src/TreeView/TreeView.tsx | 26 ++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/TreeView/TreeView.stories.tsx b/src/TreeView/TreeView.stories.tsx index 3d2cedd7c8b..c5e5652938d 100644 --- a/src/TreeView/TreeView.stories.tsx +++ b/src/TreeView/TreeView.stories.tsx @@ -1,12 +1,12 @@ -import React from 'react' import {DiffAddedIcon, DiffModifiedIcon, DiffRemovedIcon, DiffRenamedIcon, FileIcon} from '@primer/octicons-react' import {Meta, Story} from '@storybook/react' +import React from 'react' +import {ActionList} from '../ActionList' +import {ActionMenu} from '../ActionMenu' import Box from '../Box' +import {Button} from '../Button' import StyledOcticon from '../StyledOcticon' import {TreeView} from './TreeView' -import {Button} from '../Button' -import {ActionMenu} from '../ActionMenu' -import {ActionList} from '../ActionList' const meta: Meta = { title: 'Components/TreeView', @@ -436,11 +436,19 @@ export const Async: Story = args => { } }} > + + + Directory with async items - {isLoading ? Loading... : null} + {isLoading ? : null} {asyncItems.map(item => ( - {item} + + + + + {item} + ))} diff --git a/src/TreeView/TreeView.tsx b/src/TreeView/TreeView.tsx index 5aea8195772..b9b816bb363 100644 --- a/src/TreeView/TreeView.tsx +++ b/src/TreeView/TreeView.tsx @@ -8,8 +8,9 @@ import {useSSRSafeId} from '@react-aria/ssr' import React from 'react' import styled from 'styled-components' import Box from '../Box' -import StyledOcticon from '../StyledOcticon' import {useControllableState} from '../hooks/useControllableState' +import Spinner from '../Spinner' +import StyledOcticon from '../StyledOcticon' import sx, {SxProp} from '../sx' import Text from '../Text' import {Theme} from '../ThemeProvider' @@ -282,7 +283,6 @@ const Item: React.FC = ({ > {slots => ( - // QUESTION: How should leading and trailing visuals impact the aria-label? <> {slots.LeadingVisual} = ({href, onSelect, ...props}) = ) } +// ---------------------------------------------------------------------------- +// TreeView.LoadingItem + +const LoadingItem: React.FC = () => { + return ( + // TODO: What aria attributes do we need to add here? + + + + + Loading... + + ) +} + +LoadingItem.displayName = 'TreeView.LoadingItem' + // ---------------------------------------------------------------------------- // TreeView.SubTree @@ -417,7 +434,7 @@ const LeadingVisual: React.FC = props => { const children = typeof props.children === 'function' ? props.children({isExpanded}) : props.children return ( - {children} + {children} ) } @@ -427,7 +444,7 @@ const TrailingVisual: React.FC = props => { const children = typeof props.children === 'function' ? props.children({isExpanded}) : props.children return ( - {children} + {children} ) } @@ -448,6 +465,7 @@ const DirectoryIcon = () => { export const TreeView = Object.assign(Root, { Item, LinkItem, + LoadingItem, SubTree, LeadingVisual, TrailingVisual, From ee26ce86102beda67b9315f1e8da00eaedb00bd8 Mon Sep 17 00:00:00 2001 From: Cole Bemis Date: Fri, 30 Sep 2022 10:54:04 -0700 Subject: [PATCH 3/7] Create async error story --- src/TreeView/TreeView.stories.tsx | 91 ++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/src/TreeView/TreeView.stories.tsx b/src/TreeView/TreeView.stories.tsx index c5e5652938d..bb01a7a88fd 100644 --- a/src/TreeView/TreeView.stories.tsx +++ b/src/TreeView/TreeView.stories.tsx @@ -5,6 +5,7 @@ import {ActionList} from '../ActionList' import {ActionMenu} from '../ActionMenu' import Box from '../Box' import {Button} from '../Button' +import {ConfirmationDialog} from '../Dialog/ConfirmationDialog' import StyledOcticon from '../StyledOcticon' import {TreeView} from './TreeView' @@ -413,7 +414,7 @@ async function loadItems(responseTime: number) { return ['Avatar.tsx', 'Button.tsx', 'Checkbox.tsx'] } -export const Async: Story = args => { +export const AsyncSuccess: Story = args => { const [isLoading, setIsLoading] = React.useState(false) const [asyncItems, setAsyncItems] = React.useState([]) @@ -458,7 +459,93 @@ export const Async: Story = args => { ) } -Async.args = { +AsyncSuccess.args = { + responseTime: 2000 +} + +async function alwaysFails(responseTime: number) { + await wait(responseTime) + throw new Error('Failed to load items') + return [] +} + +export const AsyncError: Story = args => { + const [isLoading, setIsLoading] = React.useState(false) + const [isExpanded, setIsExpanded] = React.useState(false) + const [asyncItems, setAsyncItems] = React.useState([]) + const [error, setError] = React.useState(null) + + async function loadItems() { + if (asyncItems.length === 0) { + // Show loading indicator after a short delay + const timeout = setTimeout(() => setIsLoading(true), 500) + try { + // Try to load items + const items = await alwaysFails(args.responseTime) + setAsyncItems(items) + } catch (error) { + setError(error as Error) + } finally { + clearTimeout(timeout) + setIsLoading(false) + } + } + } + + return ( + + + + ) +} + +AsyncError.args = { responseTime: 2000 } From cf810708b94f01a43fcd751de393b1ea31fb0c3e Mon Sep 17 00:00:00 2001 From: Cole Bemis Date: Fri, 30 Sep 2022 11:28:24 -0700 Subject: [PATCH 4/7] Create breezy-bobcats-explain.md --- .changeset/breezy-bobcats-explain.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/breezy-bobcats-explain.md diff --git a/.changeset/breezy-bobcats-explain.md b/.changeset/breezy-bobcats-explain.md new file mode 100644 index 00000000000..541de9f31d6 --- /dev/null +++ b/.changeset/breezy-bobcats-explain.md @@ -0,0 +1,5 @@ +--- +"@primer/react": patch +--- + +TreeView: Add `TreeView.LoadingItem` component From 1da8a2f88e29576c4e5c13619d71bd0fa559a342 Mon Sep 17 00:00:00 2001 From: Cole Bemis Date: Fri, 30 Sep 2022 12:19:59 -0700 Subject: [PATCH 5/7] Update docs --- docs/content/TreeView.mdx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/content/TreeView.mdx b/docs/content/TreeView.mdx index 931faf43bb1..3769af40964 100644 --- a/docs/content/TreeView.mdx +++ b/docs/content/TreeView.mdx @@ -181,6 +181,10 @@ Since stateful directory icons are a common use case for TreeView, we provide a ``` +### With asynchronously loaded items + +See [storybook](https://primer.style/react/storybook?path=/story/components-treeview--async-success) for examples with asynchronously loaded items. + ## Props ### TreeView @@ -266,6 +270,10 @@ Since stateful directory icons are a common use case for TreeView, we provide a {/* */} +### TreeView.LoadingItem + +{/* */} + ### TreeView.SubTree @@ -299,8 +307,6 @@ Since stateful directory icons are a common use case for TreeView, we provide a {/* */} - - ## Status Date: Mon, 3 Oct 2022 13:14:05 -0700 Subject: [PATCH 6/7] Reduce loading item delay in stories --- src/TreeView/TreeView.stories.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TreeView/TreeView.stories.tsx b/src/TreeView/TreeView.stories.tsx index bb01a7a88fd..366260ada50 100644 --- a/src/TreeView/TreeView.stories.tsx +++ b/src/TreeView/TreeView.stories.tsx @@ -426,7 +426,7 @@ export const AsyncSuccess: Story = args => { onExpandedChange={async isExpanded => { if (asyncItems.length === 0 && isExpanded) { // Show loading indicator after a short delay - const timeout = setTimeout(() => setIsLoading(true), 500) + const timeout = setTimeout(() => setIsLoading(true), 300) // Load items const items = await loadItems(args.responseTime) @@ -478,7 +478,7 @@ export const AsyncError: Story = args => { async function loadItems() { if (asyncItems.length === 0) { // Show loading indicator after a short delay - const timeout = setTimeout(() => setIsLoading(true), 500) + const timeout = setTimeout(() => setIsLoading(true), 300) try { // Try to load items const items = await alwaysFails(args.responseTime) From 948dd2a98669118696a946e52ac55136658d7140 Mon Sep 17 00:00:00 2001 From: Cole Bemis Date: Mon, 3 Oct 2022 13:16:05 -0700 Subject: [PATCH 7/7] Update docs/content/TreeView.mdx --- docs/content/TreeView.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/TreeView.mdx b/docs/content/TreeView.mdx index 3769af40964..0c0250368c5 100644 --- a/docs/content/TreeView.mdx +++ b/docs/content/TreeView.mdx @@ -183,7 +183,7 @@ Since stateful directory icons are a common use case for TreeView, we provide a ### With asynchronously loaded items -See [storybook](https://primer.style/react/storybook?path=/story/components-treeview--async-success) for examples with asynchronously loaded items. +See [Storybook](https://primer.style/react/storybook?path=/story/components-treeview--async-success) for examples with asynchronously loaded items. ## Props