From 127b7a6296b15249d490feacbe079bf797efe80e Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Thu, 27 Apr 2023 12:58:49 -0400 Subject: [PATCH 01/29] Update FilteredActionList to use non-deprecated ActionList. --- src/ActionList/shared.ts | 2 +- .../FilteredActionList.stories.tsx | 37 +++++++++++-------- src/FilteredActionList/FilteredActionList.tsx | 24 +++++++----- src/FilteredActionList/index.ts | 2 +- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/ActionList/shared.ts b/src/ActionList/shared.ts index ff77e7975b8..710410ddbf8 100644 --- a/src/ActionList/shared.ts +++ b/src/ActionList/shared.ts @@ -39,7 +39,7 @@ export type ActionListItemProps = { /** * id to attach to the root element of the Item */ - id?: string + id?: string | number /** * Private API for use internally only. Used by LinkItem to wrap contents in an anchor */ diff --git a/src/FilteredActionList/FilteredActionList.stories.tsx b/src/FilteredActionList/FilteredActionList.stories.tsx index 1b8d938c500..3553e2bbdce 100644 --- a/src/FilteredActionList/FilteredActionList.stories.tsx +++ b/src/FilteredActionList/FilteredActionList.stories.tsx @@ -1,7 +1,8 @@ import {Meta} from '@storybook/react' import React from 'react' import {ThemeProvider} from '..' -import {FilteredActionList} from '../FilteredActionList' +import {FilteredActionList, ItemInput} from '../FilteredActionList' +import {ActionList} from '../ActionList' import BaseStyles from '../BaseStyles' import Box from '../Box' @@ -26,20 +27,18 @@ const meta: Meta = { export default meta function getColorCircle(color: string) { - return function () { - return ( - - ) - } + return ( + + ) } const items = [ @@ -50,7 +49,7 @@ const items = [ {leadingVisual: getColorCircle('#ff0000'), text: 'blocker', id: 5}, {leadingVisual: getColorCircle('#a4f287'), text: 'backend', id: 6}, {leadingVisual: getColorCircle('#8dc6fc'), text: 'frontend', id: 7}, -] +] as ItemInput[] export function Default(): JSX.Element { const [filter, setFilter] = React.useState('') @@ -65,6 +64,12 @@ export function Default(): JSX.Element { items={filteredItems} onFilterChange={setFilter} sx={{border: '1px solid', padding: '8px'}} + renderFn={({id, leadingVisual, text}) => ( + + {leadingVisual && {leadingVisual}} + {text} + + )} /> ) diff --git a/src/FilteredActionList/FilteredActionList.tsx b/src/FilteredActionList/FilteredActionList.tsx index 7a6cf8ef007..257091de027 100644 --- a/src/FilteredActionList/FilteredActionList.tsx +++ b/src/FilteredActionList/FilteredActionList.tsx @@ -1,8 +1,7 @@ import React, {KeyboardEventHandler, useCallback, useEffect, useRef} from 'react' -import {GroupedListProps, ListPropsBase} from '../deprecated/ActionList/List' import TextInput, {TextInputProps} from '../TextInput' import Box from '../Box' -import {ActionList} from '../deprecated/ActionList' +import {ActionList, ActionListProps, ActionListItemProps} from '../ActionList' import Spinner from '../Spinner' import {useFocusZone} from '../hooks/useFocusZone' import {useProvidedStateOrCreate} from '../hooks/useProvidedStateOrCreate' @@ -17,16 +16,20 @@ import {useId} from '../hooks/useId' const menuScrollMargins: ScrollIntoViewOptions = {startMargin: 0, endMargin: 8} -export interface FilteredActionListProps - extends Partial>, - ListPropsBase, - SxProp { +export type ItemInput = Partial & { + leadingVisual?: React.ReactElement + text: string +} + +export interface FilteredActionListProps extends ActionListProps, SxProp { loading?: boolean placeholderText: string filterValue?: string onFilterChange: (value: string, e: React.ChangeEvent) => void textInputProps?: Partial> inputRef?: React.RefObject + items: ItemInput[] + renderFn: (props: ItemInput) => React.ReactElement } const StyledHeader = styled.div` @@ -40,6 +43,7 @@ export function FilteredActionList({ filterValue: externalFilterValue, onFilterChange, items, + renderFn, textInputProps, inputRef: providedInputRef, sx, @@ -56,7 +60,7 @@ export function FilteredActionList({ ) const scrollContainerRef = useRef(null) - const listContainerRef = useRef(null) + const listContainerRef = useRef(null) const inputRef = useProvidedRefOrCreate(providedInputRef) const activeDescendantRef = useRef() const listId = useId() @@ -82,7 +86,7 @@ export function FilteredActionList({ return !(element instanceof HTMLInputElement) }, activeDescendantFocus: inputRef, - onActiveDescendantChanged: (current, previous, directlyActivated) => { + onActiveDescendantChanged: (current, _previous, directlyActivated) => { activeDescendantRef.current = current if (current && scrollContainerRef.current && directlyActivated) { @@ -128,7 +132,9 @@ export function FilteredActionList({ ) : ( - + + {items.map(i => renderFn(i))} + )} diff --git a/src/FilteredActionList/index.ts b/src/FilteredActionList/index.ts index 3f8176fe71c..8a96b74fd6f 100644 --- a/src/FilteredActionList/index.ts +++ b/src/FilteredActionList/index.ts @@ -1,2 +1,2 @@ export {FilteredActionList} from './FilteredActionList' -export type {FilteredActionListProps} from './FilteredActionList' +export type {FilteredActionListProps, ItemInput} from './FilteredActionList' From 0ee48c68f9be8b410e69509a95079cd3966ba9ab Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 3 May 2023 09:25:16 -0400 Subject: [PATCH 02/29] Use non-deprecated ActionList in FilteredActionList. --- src/ActionList/shared.ts | 2 +- .../FilteredActionList.stories.tsx | 14 ++--- src/FilteredActionList/FilteredActionList.tsx | 15 +++-- src/SelectPanel/SelectPanel.stories.tsx | 55 ++++++++++--------- src/SelectPanel/SelectPanel.tsx | 13 ++--- .../__snapshots__/themePreval.test.ts.snap | 4 +- src/drafts/MarkdownEditor/_SavedReplies.tsx | 46 ++++++++++++++++ 7 files changed, 102 insertions(+), 47 deletions(-) diff --git a/src/ActionList/shared.ts b/src/ActionList/shared.ts index 710410ddbf8..ff77e7975b8 100644 --- a/src/ActionList/shared.ts +++ b/src/ActionList/shared.ts @@ -39,7 +39,7 @@ export type ActionListItemProps = { /** * id to attach to the root element of the Item */ - id?: string | number + id?: string /** * Private API for use internally only. Used by LinkItem to wrap contents in an anchor */ diff --git a/src/FilteredActionList/FilteredActionList.stories.tsx b/src/FilteredActionList/FilteredActionList.stories.tsx index 3553e2bbdce..e77ac9bcee4 100644 --- a/src/FilteredActionList/FilteredActionList.stories.tsx +++ b/src/FilteredActionList/FilteredActionList.stories.tsx @@ -42,13 +42,13 @@ function getColorCircle(color: string) { } const items = [ - {leadingVisual: getColorCircle('#a2eeef'), text: 'enhancement', id: 1}, - {leadingVisual: getColorCircle('#d73a4a'), text: 'bug', id: 2}, - {leadingVisual: getColorCircle('#0cf478'), text: 'good first issue', id: 3}, - {leadingVisual: getColorCircle('#ffd78e'), text: 'design', id: 4}, - {leadingVisual: getColorCircle('#ff0000'), text: 'blocker', id: 5}, - {leadingVisual: getColorCircle('#a4f287'), text: 'backend', id: 6}, - {leadingVisual: getColorCircle('#8dc6fc'), text: 'frontend', id: 7}, + {leadingVisual: getColorCircle('#a2eeef'), text: 'enhancement', id: '1'}, + {leadingVisual: getColorCircle('#d73a4a'), text: 'bug', id: '2'}, + {leadingVisual: getColorCircle('#0cf478'), text: 'good first issue', id: '3'}, + {leadingVisual: getColorCircle('#ffd78e'), text: 'design', id: '4'}, + {leadingVisual: getColorCircle('#ff0000'), text: 'blocker', id: '5'}, + {leadingVisual: getColorCircle('#a4f287'), text: 'backend', id: '6'}, + {leadingVisual: getColorCircle('#8dc6fc'), text: 'frontend', id: '7'}, ] as ItemInput[] export function Default(): JSX.Element { diff --git a/src/FilteredActionList/FilteredActionList.tsx b/src/FilteredActionList/FilteredActionList.tsx index 257091de027..e40c7d54377 100644 --- a/src/FilteredActionList/FilteredActionList.tsx +++ b/src/FilteredActionList/FilteredActionList.tsx @@ -16,10 +16,17 @@ import {useId} from '../hooks/useId' const menuScrollMargins: ScrollIntoViewOptions = {startMargin: 0, endMargin: 8} -export type ItemInput = Partial & { - leadingVisual?: React.ReactElement - text: string -} +export type ItemInput = Partial< + ActionListItemProps & { + description?: string + descriptionVariant?: string + leadingVisual?: JSX.Element + onAction?: (itemFromAction: ItemInput, event: React.MouseEvent) => void + selected?: boolean + text?: string + trailingVisual?: string + } +> export interface FilteredActionListProps extends ActionListProps, SxProp { loading?: boolean diff --git a/src/SelectPanel/SelectPanel.stories.tsx b/src/SelectPanel/SelectPanel.stories.tsx index 6b08629ce38..32d38ce7984 100644 --- a/src/SelectPanel/SelectPanel.stories.tsx +++ b/src/SelectPanel/SelectPanel.stories.tsx @@ -3,9 +3,10 @@ import {ComponentMeta} from '@storybook/react' import {TriangleDownIcon} from '@primer/octicons-react' import {Button} from '../Button' -import {ItemInput} from '../deprecated/ActionList/List' import {SelectPanel} from '../SelectPanel' import Box from '../Box' +import {ActionList} from '../ActionList' +import {ItemInput} from '../FilteredActionList' export default { title: 'Components/SelectPanel', @@ -13,32 +14,30 @@ export default { } as ComponentMeta function getColorCircle(color: string) { - return function () { - return ( - - ) - } + return ( + + ) } const items = [ - {leadingVisual: getColorCircle('#a2eeef'), text: 'enhancement', id: 1}, - {leadingVisual: getColorCircle('#d73a4a'), text: 'bug', id: 2}, - {leadingVisual: getColorCircle('#0cf478'), text: 'good first issue', id: 3}, - {leadingVisual: getColorCircle('#ffd78e'), text: 'design', id: 4}, - {leadingVisual: getColorCircle('#ff0000'), text: 'blocker', id: 5}, - {leadingVisual: getColorCircle('#a4f287'), text: 'backend', id: 6}, - {leadingVisual: getColorCircle('#8dc6fc'), text: 'frontend', id: 7}, + {leadingVisual: getColorCircle('#a2eeef'), text: 'enhancement', id: '1'}, + {leadingVisual: getColorCircle('#d73a4a'), text: 'bug', id: '2'}, + {leadingVisual: getColorCircle('#0cf478'), text: 'good first issue', id: '3'}, + {leadingVisual: getColorCircle('#ffd78e'), text: 'design', id: '4'}, + {leadingVisual: getColorCircle('#ff0000'), text: 'blocker', id: '5'}, + {leadingVisual: getColorCircle('#a4f287'), text: 'backend', id: '6'}, + {leadingVisual: getColorCircle('#8dc6fc'), text: 'frontend', id: '7'}, ] export const Default = () => { @@ -46,6 +45,12 @@ export const Default = () => { const [filter, setFilter] = React.useState('') const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) const [open, setOpen] = useState(false) + const renderFn = (props: ItemInput) => ( + + {!!props.leadingVisual && {props.leadingVisual}} + {props.text} + + ) return ( <> @@ -61,10 +66,10 @@ export const Default = () => { open={open} onOpenChange={setOpen} items={filteredItems} + renderFn={renderFn} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} - showItemDividers={true} overlayProps={{width: 'small', height: 'xsmall'}} /> diff --git a/src/SelectPanel/SelectPanel.tsx b/src/SelectPanel/SelectPanel.tsx index b0d53fc760c..2ddb6f6bb13 100644 --- a/src/SelectPanel/SelectPanel.tsx +++ b/src/SelectPanel/SelectPanel.tsx @@ -1,10 +1,9 @@ import React, {useCallback, useMemo} from 'react' -import {FilteredActionList, FilteredActionListProps} from '../FilteredActionList' +import {FilteredActionList, FilteredActionListProps, ItemInput} from '../FilteredActionList' import {OverlayProps} from '../Overlay' -import {ItemInput} from '../deprecated/ActionList/List' import {FocusZoneHookSettings} from '../hooks/useFocusZone' import {DropdownButton} from '../deprecated/DropdownMenu' -import {ItemProps} from '../deprecated/ActionList' +import {ActionListItemProps} from '../ActionList' import {AnchoredOverlay, AnchoredOverlayProps} from '../AnchoredOverlay' import {TextInputProps} from '../TextInput' import {useProvidedStateOrCreate} from '../hooks/useProvidedStateOrCreate' @@ -61,6 +60,7 @@ export function SelectPanel({ textInputProps, overlayProps, sx, + renderFn, ...listProps }: SelectPanelProps): JSX.Element { const [filterValue, setInternalFilterValue] = useProvidedStateOrCreate(externalFilterValue, undefined, '') @@ -107,9 +107,7 @@ export function SelectPanel({ ...item, role: 'option', selected: 'selected' in item && item.selected === undefined ? undefined : isItemSelected, - onAction: (itemFromAction, event) => { - item.onAction?.(itemFromAction, event) - + onSelect: (event: React.MouseEvent | React.KeyboardEvent) => { if (event.defaultPrevented) { return } @@ -128,7 +126,7 @@ export function SelectPanel({ singleSelectOnChange(item === selected ? undefined : item) onClose('selection') }, - } as ItemProps + } as ActionListItemProps }) }, [onClose, onSelectedChange, items, selected]) @@ -164,6 +162,7 @@ export function SelectPanel({ aria-multiselectable={isMultiSelectVariant(selected) ? 'true' : 'false'} selectionVariant={isMultiSelectVariant(selected) ? 'multiple' : 'single'} items={itemsToRender} + renderFn={renderFn} textInputProps={extendedTextInputProps} inputRef={inputRef} // inheriting height and maxHeight ensures that the FilteredActionList is never taller diff --git a/src/__tests__/__snapshots__/themePreval.test.ts.snap b/src/__tests__/__snapshots__/themePreval.test.ts.snap index d489068d9d5..4fd687d02ab 100644 --- a/src/__tests__/__snapshots__/themePreval.test.ts.snap +++ b/src/__tests__/__snapshots__/themePreval.test.ts.snap @@ -3,8 +3,6 @@ exports[`snapshot theme-preval.js 1`] = ` "'use strict'; -var _commonjsHelpers = require('./_virtual/_commonjsHelpers.js'); - // this file was prevaled // This file needs to be a JavaScript file using CommonJS to be compatible with preval // Cache bust: 2023-04-04 12:00:00 GMT (This file is cached by our deployment tooling, update this timestamp to rebuild this file) @@ -4620,7 +4618,7 @@ var themePreval = { } }; -var theme = /*@__PURE__*/_commonjsHelpers.getDefaultExportFromCjs(themePreval); +var theme = themePreval; module.exports = theme; " diff --git a/src/drafts/MarkdownEditor/_SavedReplies.tsx b/src/drafts/MarkdownEditor/_SavedReplies.tsx index d10b4b4ee5f..3e115f4f845 100644 --- a/src/drafts/MarkdownEditor/_SavedReplies.tsx +++ b/src/drafts/MarkdownEditor/_SavedReplies.tsx @@ -8,8 +8,14 @@ import React, { useImperativeHandle, useState, } from 'react' +import {get} from '../../constants' import {SelectPanel, SelectPanelProps} from '../../SelectPanel' +import {ItemInput} from '../../FilteredActionList' +import {ActionList} from '../../ActionList' +import Box from '../../Box' import {ToolbarButton} from './Toolbar' +import Truncate from '../../Truncate' +import {useId} from '../../hooks/useId' export type SavedReply = { name: string @@ -33,6 +39,44 @@ type Item = SelectPanelProps['items'][number] // on every render. If it was provided in the MarkdownEditorContext, it would cause the whole editor to rerender on every render. export const SavedRepliesContext = createContext(null) +const renderFn = ({ + description, + descriptionVariant, + id, + sx, + text, + trailingVisual, + onSelect, +}: ItemInput): React.ReactElement => { + return ( + + + {text ? ( + + {text} + + ) : null} + {description ? ( + + {descriptionVariant === 'block' ? ( + description + ) : ( + + {description} + + )} + + ) : null} + + {!!trailingVisual && {trailingVisual}} + + ) +} + export const SavedRepliesButton = () => { const context = useContext(SavedRepliesContext) @@ -66,6 +110,7 @@ export const SavedRepliesButton = () => { maxWidth: '100%', }, }, + id: i.toString(), }), ) @@ -97,6 +142,7 @@ export const SavedRepliesButton = () => { open={open} onOpenChange={setOpen} items={items} + renderFn={renderFn} filterValue={filter} onFilterChange={setFilter} placeholderText="Search saved replies" From 55582643c52dda8b2947b243d0fd90c4c548e43c Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 3 May 2023 09:38:42 -0400 Subject: [PATCH 03/29] Fix a11y issues in FilteredActionList story. --- src/FilteredActionList/FilteredActionList.stories.tsx | 4 ++-- src/FilteredActionList/FilteredActionList.tsx | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/FilteredActionList/FilteredActionList.stories.tsx b/src/FilteredActionList/FilteredActionList.stories.tsx index e77ac9bcee4..e3aec4a9fa7 100644 --- a/src/FilteredActionList/FilteredActionList.stories.tsx +++ b/src/FilteredActionList/FilteredActionList.stories.tsx @@ -53,7 +53,7 @@ const items = [ export function Default(): JSX.Element { const [filter, setFilter] = React.useState('') - const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) + const filteredItems = items.filter(item => item.text?.toLowerCase().startsWith(filter.toLowerCase())) return ( <> @@ -65,7 +65,7 @@ export function Default(): JSX.Element { onFilterChange={setFilter} sx={{border: '1px solid', padding: '8px'}} renderFn={({id, leadingVisual, text}) => ( - + {leadingVisual && {leadingVisual}} {text} diff --git a/src/FilteredActionList/FilteredActionList.tsx b/src/FilteredActionList/FilteredActionList.tsx index e40c7d54377..0d59274059a 100644 --- a/src/FilteredActionList/FilteredActionList.tsx +++ b/src/FilteredActionList/FilteredActionList.tsx @@ -139,7 +139,13 @@ export function FilteredActionList({ ) : ( - + {items.map(i => renderFn(i))} )} From 4525416b9b2aaf66c853586aca837fdc68471747 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 3 May 2023 11:29:29 -0400 Subject: [PATCH 04/29] Add prop to hide selection component if needed. --- src/ActionList/Item.tsx | 3 ++- src/ActionList/shared.ts | 4 ++++ src/SelectPanel/SelectPanel.tsx | 7 ++++--- src/drafts/MarkdownEditor/_SavedReplies.tsx | 3 ++- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/ActionList/Item.tsx b/src/ActionList/Item.tsx index 60126e3528a..0fbc62bed08 100644 --- a/src/ActionList/Item.tsx +++ b/src/ActionList/Item.tsx @@ -27,6 +27,7 @@ export const Item = React.forwardRef( sx: sxProp = defaultSxProp, id, role, + hideSelection, _PrivateItemWrapper, ...props }, @@ -194,7 +195,7 @@ export const Item = React.forwardRef( (styles, sxProp)} {...containerProps} {...props}> - + {!!hideSelection && } {slots.leadingVisual} & Pick & AnchoredOverlayWrapperAnchorProps & - (SelectPanelSingleSelection | SelectPanelMultiSelection) + (SelectPanelSingleSelection | SelectPanelMultiSelection) & {hideSelection?: boolean} function isMultiSelectVariant( selected: SelectPanelSingleSelection['selected'] | SelectPanelMultiSelection['selected'], @@ -57,6 +57,7 @@ export function SelectPanel({ filterValue: externalFilterValue, onFilterChange: externalOnFilterChange, items, + hideSelection, textInputProps, overlayProps, sx, @@ -159,8 +160,8 @@ export function SelectPanel({ onFilterChange={onFilterChange} {...listProps} role="listbox" - aria-multiselectable={isMultiSelectVariant(selected) ? 'true' : 'false'} - selectionVariant={isMultiSelectVariant(selected) ? 'multiple' : 'single'} + aria-multiselectable={hideSelection ? undefined : isMultiSelectVariant(selected) ? 'true' : 'false'} + selectionVariant={hideSelection ? undefined : isMultiSelectVariant(selected) ? 'multiple' : 'single'} items={itemsToRender} renderFn={renderFn} textInputProps={extendedTextInputProps} diff --git a/src/drafts/MarkdownEditor/_SavedReplies.tsx b/src/drafts/MarkdownEditor/_SavedReplies.tsx index 3e115f4f845..0c6282d7edb 100644 --- a/src/drafts/MarkdownEditor/_SavedReplies.tsx +++ b/src/drafts/MarkdownEditor/_SavedReplies.tsx @@ -46,10 +46,11 @@ const renderFn = ({ sx, text, trailingVisual, + hideSelection, onSelect, }: ItemInput): React.ReactElement => { return ( - + {text ? ( From f67e7db075076142b64a42b180b7d8f94d5f05cf Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 3 May 2023 11:56:20 -0400 Subject: [PATCH 05/29] Remove unused hook import. --- src/drafts/MarkdownEditor/_SavedReplies.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/drafts/MarkdownEditor/_SavedReplies.tsx b/src/drafts/MarkdownEditor/_SavedReplies.tsx index 0c6282d7edb..9409e857379 100644 --- a/src/drafts/MarkdownEditor/_SavedReplies.tsx +++ b/src/drafts/MarkdownEditor/_SavedReplies.tsx @@ -15,7 +15,6 @@ import {ActionList} from '../../ActionList' import Box from '../../Box' import {ToolbarButton} from './Toolbar' import Truncate from '../../Truncate' -import {useId} from '../../hooks/useId' export type SavedReply = { name: string From c7e1ffd81559543f3277eb85991cab2c72ab84bd Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 3 May 2023 12:04:55 -0400 Subject: [PATCH 06/29] Get SavedReplies to look as it did with deprecated ActionList. --- src/drafts/MarkdownEditor/_SavedReplies.tsx | 36 ++++++++------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/src/drafts/MarkdownEditor/_SavedReplies.tsx b/src/drafts/MarkdownEditor/_SavedReplies.tsx index 9409e857379..79d4731228f 100644 --- a/src/drafts/MarkdownEditor/_SavedReplies.tsx +++ b/src/drafts/MarkdownEditor/_SavedReplies.tsx @@ -50,28 +50,18 @@ const renderFn = ({ }: ItemInput): React.ReactElement => { return ( - - {text ? ( - - {text} - - ) : null} - {description ? ( - - {descriptionVariant === 'block' ? ( - description - ) : ( - - {description} - - )} - - ) : null} - + {text ? text : null} + {description ? ( + + {descriptionVariant === 'block' ? ( + description + ) : ( + + {description} + + )} + + ) : null} {!!trailingVisual && {trailingVisual}} ) @@ -98,7 +88,7 @@ export const SavedRepliesButton = () => { (reply, i): Item => ({ text: reply.name, description: reply.content, - descriptionVariant: 'block', + descriptionVariant: 'inline', trailingVisual: i < 9 ? `Ctrl + ${i + 1}` : undefined, sx: { // hide the leading visual container since we don't use the checkboxes From b4238fb1bd2093dfcb11154cf9d6d02b52876452 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 3 May 2023 12:15:42 -0400 Subject: [PATCH 07/29] Fix failing test. --- src/ActionList/Item.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ActionList/Item.tsx b/src/ActionList/Item.tsx index 0fbc62bed08..cc9623f2d9b 100644 --- a/src/ActionList/Item.tsx +++ b/src/ActionList/Item.tsx @@ -27,7 +27,7 @@ export const Item = React.forwardRef( sx: sxProp = defaultSxProp, id, role, - hideSelection, + hideSelection = false, _PrivateItemWrapper, ...props }, @@ -195,7 +195,7 @@ export const Item = React.forwardRef( (styles, sxProp)} {...containerProps} {...props}> - {!!hideSelection && } + {!hideSelection && } {slots.leadingVisual} Date: Wed, 3 May 2023 12:20:33 -0400 Subject: [PATCH 08/29] Create weak-jokes-chew.md --- .changeset/weak-jokes-chew.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/weak-jokes-chew.md diff --git a/.changeset/weak-jokes-chew.md b/.changeset/weak-jokes-chew.md new file mode 100644 index 00000000000..5bc46b3494a --- /dev/null +++ b/.changeset/weak-jokes-chew.md @@ -0,0 +1,5 @@ +--- +"@primer/react": patch +--- + +FilteredActionList now uses new ActionList as a base. From 6f4fc1441301589ff165e6e8f7aca3ed22bf8df8 Mon Sep 17 00:00:00 2001 From: radglob Date: Wed, 3 May 2023 16:22:26 +0000 Subject: [PATCH 09/29] Update generated/components.json --- generated/components.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generated/components.json b/generated/components.json index 9cfa427c3d3..e6162c1d514 100644 --- a/generated/components.json +++ b/generated/components.json @@ -3563,7 +3563,7 @@ "stories": [ { "id": "components-selectpanel--default", - "code": "() => {\n const [selected, setSelected] = React.useState([\n items[0],\n items[1],\n ])\n const [filter, setFilter] = React.useState('')\n const filteredItems = items.filter((item) =>\n item.text.toLowerCase().startsWith(filter.toLowerCase()),\n )\n const [open, setOpen] = useState(false)\n return (\n <>\n

Multi Select Panel

\n
Please select labels that describe your issue:
\n (\n \n {children ?? 'Select Labels'}\n \n )}\n placeholderText=\"Filter Labels\"\n open={open}\n onOpenChange={setOpen}\n items={filteredItems}\n selected={selected}\n onSelectedChange={setSelected}\n onFilterChange={setFilter}\n showItemDividers={true}\n overlayProps={{\n width: 'small',\n height: 'xsmall',\n }}\n />\n \n )\n}" + "code": "() => {\n const [selected, setSelected] = React.useState([\n items[0],\n items[1],\n ])\n const [filter, setFilter] = React.useState('')\n const filteredItems = items.filter((item) =>\n item.text.toLowerCase().startsWith(filter.toLowerCase()),\n )\n const [open, setOpen] = useState(false)\n const renderFn = (props: ItemInput) => (\n \n {!!props.leadingVisual && (\n \n {props.leadingVisual}\n \n )}\n {props.text}\n \n )\n return (\n <>\n

Multi Select Panel

\n
Please select labels that describe your issue:
\n (\n \n {children ?? 'Select Labels'}\n \n )}\n placeholderText=\"Filter Labels\"\n open={open}\n onOpenChange={setOpen}\n items={filteredItems}\n renderFn={renderFn}\n selected={selected}\n onSelectedChange={setSelected}\n onFilterChange={setFilter}\n overlayProps={{\n width: 'small',\n height: 'xsmall',\n }}\n />\n \n )\n}" } ], "props": [ From adefbbefe10e5e259f8340f72859ae1e9e6226bc Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 3 May 2023 13:23:59 -0400 Subject: [PATCH 10/29] Fix themePreval snapshot. --- src/__tests__/__snapshots__/themePreval.test.ts.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__tests__/__snapshots__/themePreval.test.ts.snap b/src/__tests__/__snapshots__/themePreval.test.ts.snap index 4fd687d02ab..5734f0d0fcf 100644 --- a/src/__tests__/__snapshots__/themePreval.test.ts.snap +++ b/src/__tests__/__snapshots__/themePreval.test.ts.snap @@ -4618,7 +4618,7 @@ var themePreval = { } }; -var theme = themePreval; +var theme = /*@__PURE__*/_commonjsHelpers.getDefaultExportFromCjs(themePreval); module.exports = theme; " From 30839b0bb978450c5acbfa8d655fe0ac5e926079 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 3 May 2023 13:32:41 -0400 Subject: [PATCH 11/29] Linting fixes. --- src/drafts/MarkdownEditor/_SavedReplies.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/drafts/MarkdownEditor/_SavedReplies.tsx b/src/drafts/MarkdownEditor/_SavedReplies.tsx index 79d4731228f..7bafd0d689d 100644 --- a/src/drafts/MarkdownEditor/_SavedReplies.tsx +++ b/src/drafts/MarkdownEditor/_SavedReplies.tsx @@ -8,11 +8,9 @@ import React, { useImperativeHandle, useState, } from 'react' -import {get} from '../../constants' import {SelectPanel, SelectPanelProps} from '../../SelectPanel' import {ItemInput} from '../../FilteredActionList' import {ActionList} from '../../ActionList' -import Box from '../../Box' import {ToolbarButton} from './Toolbar' import Truncate from '../../Truncate' From 6fb05d07a203de8cdc5c11968aa143b16b879875 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 3 May 2023 13:48:20 -0400 Subject: [PATCH 12/29] Fix type-check errors. --- src/FilteredActionList/FilteredActionList.tsx | 4 +- .../SelectPanel.features.stories.tsx | 50 ++++++++----------- src/SelectPanel/SelectPanel.test.tsx | 2 +- 3 files changed, 23 insertions(+), 33 deletions(-) diff --git a/src/FilteredActionList/FilteredActionList.tsx b/src/FilteredActionList/FilteredActionList.tsx index 0d59274059a..cb64d45b26f 100644 --- a/src/FilteredActionList/FilteredActionList.tsx +++ b/src/FilteredActionList/FilteredActionList.tsx @@ -36,7 +36,7 @@ export interface FilteredActionListProps extends ActionListProps, SxProp { textInputProps?: Partial> inputRef?: React.RefObject items: ItemInput[] - renderFn: (props: ItemInput) => React.ReactElement + renderFn?: (props: ItemInput) => React.ReactElement } const StyledHeader = styled.div` @@ -146,7 +146,7 @@ export function FilteredActionList({ id={listId} aria-label={`${placeholderText} options`} > - {items.map(i => renderFn(i))} + {items.map(i => renderFn?.(i))}
)}
diff --git a/src/SelectPanel/SelectPanel.features.stories.tsx b/src/SelectPanel/SelectPanel.features.stories.tsx index 42b4f6ccf24..d0b00db3988 100644 --- a/src/SelectPanel/SelectPanel.features.stories.tsx +++ b/src/SelectPanel/SelectPanel.features.stories.tsx @@ -3,7 +3,7 @@ import {ComponentMeta} from '@storybook/react' import Box from '../Box' import {Button} from '../Button' -import {ItemInput} from '../deprecated/ActionList/List' +import {ItemInput} from '../FilteredActionList' import {SelectPanel} from './SelectPanel' import {TriangleDownIcon} from '@primer/octicons-react' import type {OverlayProps} from '../Overlay' @@ -14,30 +14,28 @@ export default { } as ComponentMeta function getColorCircle(color: string) { - return function () { - return ( - - ) - } + return ( + + ) } const items = [ - {leadingVisual: getColorCircle('#a2eeef'), text: 'enhancement', id: 1}, - {leadingVisual: getColorCircle('#d73a4a'), text: 'bug', id: 2}, - {leadingVisual: getColorCircle('#0cf478'), text: 'good first issue', id: 3}, - {leadingVisual: getColorCircle('#ffd78e'), text: 'design', id: 4}, - {leadingVisual: getColorCircle('#ff0000'), text: 'blocker', id: 5}, - {leadingVisual: getColorCircle('#a4f287'), text: 'backend', id: 6}, - {leadingVisual: getColorCircle('#8dc6fc'), text: 'frontend', id: 7}, + {leadingVisual: getColorCircle('#a2eeef'), text: 'enhancement', id: '1'}, + {leadingVisual: getColorCircle('#d73a4a'), text: 'bug', id: '2'}, + {leadingVisual: getColorCircle('#0cf478'), text: 'good first issue', id: '3'}, + {leadingVisual: getColorCircle('#ffd78e'), text: 'design', id: '4'}, + {leadingVisual: getColorCircle('#ff0000'), text: 'blocker', id: '5'}, + {leadingVisual: getColorCircle('#a4f287'), text: 'backend', id: '6'}, + {leadingVisual: getColorCircle('#8dc6fc'), text: 'frontend', id: '7'}, ] export const SingleSelectStory = () => { @@ -63,7 +61,6 @@ export const SingleSelectStory = () => { selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} - showItemDividers={true} overlayProps={{width: 'small', height: 'xsmall'}} /> @@ -94,7 +91,6 @@ export const ExternalAnchorStory = () => { selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} - showItemDividers={true} overlayProps={{width: 'small', height: 'xsmall'}} /> @@ -125,7 +121,6 @@ export const SelectPanelHeightInitialWithOverflowingItemsStory = () => { selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} - showItemDividers={true} overlayProps={{width: 'small', height: 'initial', maxHeight: 'xsmall'}} /> @@ -157,7 +152,6 @@ export const SelectPanelHeightInitialWithUnderflowingItemsStory = () => { selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} - showItemDividers={true} overlayProps={{width: 'small', height: 'initial', maxHeight: 'xsmall'}} /> @@ -202,7 +196,6 @@ export const SelectPanelHeightInitialWithUnderflowingItemsAfterFetch = () => { selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} - showItemDividers={true} overlayProps={{width: 'small', height, maxHeight: 'xsmall'}} /> @@ -234,7 +227,6 @@ export const SelectPanelAboveTallBody = () => { selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} - showItemDividers={true} overlayProps={{width: 'small', height: 'xsmall'}} />
{ selected={selectedA} onSelectedChange={setSelectedA} onFilterChange={setFilter} - showItemDividers={true} overlayProps={{height: 'medium'}} />

With height:auto, maxheight:medium

@@ -293,7 +284,6 @@ export const SelectPanelHeightAndScroll = () => { selected={selectedB} onSelectedChange={setSelectedB} onFilterChange={setFilter} - showItemDividers={true} overlayProps={{ height: 'auto', maxHeight: 'medium', diff --git a/src/SelectPanel/SelectPanel.test.tsx b/src/SelectPanel/SelectPanel.test.tsx index 05332623326..551d742aaa3 100644 --- a/src/SelectPanel/SelectPanel.test.tsx +++ b/src/SelectPanel/SelectPanel.test.tsx @@ -5,7 +5,7 @@ import theme from '../theme' import {SelectPanel} from '../SelectPanel' import {behavesAsComponent, checkExports} from '../utils/testing' import {BaseStyles, SSRProvider, ThemeProvider} from '..' -import {ItemInput} from '../deprecated/ActionList/List' +import {ItemInput} from '../FilteredActionList' expect.extend(toHaveNoViolations) From 470e250ebb7a73d2b125396817bd81e463041c11 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 3 May 2023 14:24:05 -0400 Subject: [PATCH 13/29] Update themePreval snapshot again. --- src/__tests__/__snapshots__/themePreval.test.ts.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__tests__/__snapshots__/themePreval.test.ts.snap b/src/__tests__/__snapshots__/themePreval.test.ts.snap index 5734f0d0fcf..4fd687d02ab 100644 --- a/src/__tests__/__snapshots__/themePreval.test.ts.snap +++ b/src/__tests__/__snapshots__/themePreval.test.ts.snap @@ -4618,7 +4618,7 @@ var themePreval = { } }; -var theme = /*@__PURE__*/_commonjsHelpers.getDefaultExportFromCjs(themePreval); +var theme = themePreval; module.exports = theme; " From 3da704fca53509495258884fdf218bf8824f2671 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 3 May 2023 14:46:13 -0400 Subject: [PATCH 14/29] Fix themePreval snapshot to match origin. Unsure why it's not generating the same way. --- src/__tests__/__snapshots__/themePreval.test.ts.snap | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/__tests__/__snapshots__/themePreval.test.ts.snap b/src/__tests__/__snapshots__/themePreval.test.ts.snap index 4fd687d02ab..d489068d9d5 100644 --- a/src/__tests__/__snapshots__/themePreval.test.ts.snap +++ b/src/__tests__/__snapshots__/themePreval.test.ts.snap @@ -3,6 +3,8 @@ exports[`snapshot theme-preval.js 1`] = ` "'use strict'; +var _commonjsHelpers = require('./_virtual/_commonjsHelpers.js'); + // this file was prevaled // This file needs to be a JavaScript file using CommonJS to be compatible with preval // Cache bust: 2023-04-04 12:00:00 GMT (This file is cached by our deployment tooling, update this timestamp to rebuild this file) @@ -4618,7 +4620,7 @@ var themePreval = { } }; -var theme = themePreval; +var theme = /*@__PURE__*/_commonjsHelpers.getDefaultExportFromCjs(themePreval); module.exports = theme; " From 069e747313241ab73007b9becbfb5b9b7bee411d Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 3 May 2023 15:20:52 -0400 Subject: [PATCH 15/29] Hide selections in MarkdownEditor saved replies. --- src/drafts/MarkdownEditor/_SavedReplies.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/drafts/MarkdownEditor/_SavedReplies.tsx b/src/drafts/MarkdownEditor/_SavedReplies.tsx index 7bafd0d689d..d2cf95f95ae 100644 --- a/src/drafts/MarkdownEditor/_SavedReplies.tsx +++ b/src/drafts/MarkdownEditor/_SavedReplies.tsx @@ -99,6 +99,7 @@ export const SavedRepliesButton = () => { }, }, id: i.toString(), + hideSelection: true, }), ) From 19b3674ebc071ba52c73a83953999a81242b2cc1 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 10 May 2023 11:59:31 -0400 Subject: [PATCH 16/29] Remove hideSelection prop and add defaultRenderFn to FilteredActionList so these don't have to be defined manually everywhere. --- src/ActionList/Item.tsx | 3 +- src/FilteredActionList/FilteredActionList.tsx | 35 +++++++++++++++++-- src/SelectPanel/SelectPanel.tsx | 7 ++-- src/drafts/MarkdownEditor/_SavedReplies.tsx | 33 ----------------- 4 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/ActionList/Item.tsx b/src/ActionList/Item.tsx index 940ddbf5e78..8064ff2f1c1 100644 --- a/src/ActionList/Item.tsx +++ b/src/ActionList/Item.tsx @@ -28,7 +28,6 @@ export const Item = React.forwardRef( sx: sxProp = defaultSxProp, id, role, - hideSelection = false, _PrivateItemWrapper, ...props }, @@ -199,7 +198,7 @@ export const Item = React.forwardRef( (styles, sxProp)} {...containerProps} {...props}> - {!hideSelection && } + {slots.leadingVisual} { + return ( + + {!!leadingVisual && {leadingVisual}} + {text ? text : null} + {description ? ( + + {descriptionVariant === 'block' ? ( + description + ) : ( + + {description} + + )} + + ) : null} + {!!trailingVisual && {trailingVisual}} + + ) +} + export function FilteredActionList({ loading = false, placeholderText, filterValue: externalFilterValue, onFilterChange, items, - renderFn, + renderFn = defaultRenderFn, textInputProps, inputRef: providedInputRef, sx, @@ -146,7 +177,7 @@ export function FilteredActionList({ id={listId} aria-label={`${placeholderText} options`} > - {items.map(i => renderFn?.(i))} + {items.map(i => renderFn(i))} )} diff --git a/src/SelectPanel/SelectPanel.tsx b/src/SelectPanel/SelectPanel.tsx index b1eb31d812b..2ddb6f6bb13 100644 --- a/src/SelectPanel/SelectPanel.tsx +++ b/src/SelectPanel/SelectPanel.tsx @@ -33,7 +33,7 @@ export type SelectPanelProps = SelectPanelBaseProps & Omit & Pick & AnchoredOverlayWrapperAnchorProps & - (SelectPanelSingleSelection | SelectPanelMultiSelection) & {hideSelection?: boolean} + (SelectPanelSingleSelection | SelectPanelMultiSelection) function isMultiSelectVariant( selected: SelectPanelSingleSelection['selected'] | SelectPanelMultiSelection['selected'], @@ -57,7 +57,6 @@ export function SelectPanel({ filterValue: externalFilterValue, onFilterChange: externalOnFilterChange, items, - hideSelection, textInputProps, overlayProps, sx, @@ -160,8 +159,8 @@ export function SelectPanel({ onFilterChange={onFilterChange} {...listProps} role="listbox" - aria-multiselectable={hideSelection ? undefined : isMultiSelectVariant(selected) ? 'true' : 'false'} - selectionVariant={hideSelection ? undefined : isMultiSelectVariant(selected) ? 'multiple' : 'single'} + aria-multiselectable={isMultiSelectVariant(selected) ? 'true' : 'false'} + selectionVariant={isMultiSelectVariant(selected) ? 'multiple' : 'single'} items={itemsToRender} renderFn={renderFn} textInputProps={extendedTextInputProps} diff --git a/src/drafts/MarkdownEditor/_SavedReplies.tsx b/src/drafts/MarkdownEditor/_SavedReplies.tsx index d2cf95f95ae..5232ac30f56 100644 --- a/src/drafts/MarkdownEditor/_SavedReplies.tsx +++ b/src/drafts/MarkdownEditor/_SavedReplies.tsx @@ -9,10 +9,7 @@ import React, { useState, } from 'react' import {SelectPanel, SelectPanelProps} from '../../SelectPanel' -import {ItemInput} from '../../FilteredActionList' -import {ActionList} from '../../ActionList' import {ToolbarButton} from './Toolbar' -import Truncate from '../../Truncate' export type SavedReply = { name: string @@ -36,35 +33,6 @@ type Item = SelectPanelProps['items'][number] // on every render. If it was provided in the MarkdownEditorContext, it would cause the whole editor to rerender on every render. export const SavedRepliesContext = createContext(null) -const renderFn = ({ - description, - descriptionVariant, - id, - sx, - text, - trailingVisual, - hideSelection, - onSelect, -}: ItemInput): React.ReactElement => { - return ( - - {text ? text : null} - {description ? ( - - {descriptionVariant === 'block' ? ( - description - ) : ( - - {description} - - )} - - ) : null} - {!!trailingVisual && {trailingVisual}} - - ) -} - export const SavedRepliesButton = () => { const context = useContext(SavedRepliesContext) @@ -131,7 +99,6 @@ export const SavedRepliesButton = () => { open={open} onOpenChange={setOpen} items={items} - renderFn={renderFn} filterValue={filter} onFilterChange={setFilter} placeholderText="Search saved replies" From dc8b1bb5fe686c3474b61d1fe4ed459fcfd1289b Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 10 May 2023 12:58:06 -0400 Subject: [PATCH 17/29] Fix selection rendering (needed explicit selected boolean) and fix SelectPanel docs. --- docs/content/SelectPanel.mdx | 26 +++++++++---------- src/FilteredActionList/FilteredActionList.tsx | 3 ++- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/docs/content/SelectPanel.mdx b/docs/content/SelectPanel.mdx index 0134547dccc..b07b87c8731 100644 --- a/docs/content/SelectPanel.mdx +++ b/docs/content/SelectPanel.mdx @@ -12,20 +12,18 @@ A `SelectPanel` provides an anchor that will open an overlay with a list of sele ```javascript live noinline function getColorCircle(color) { - return function () { - return ( - - ) - } + return ( + + ) } const items = [ diff --git a/src/FilteredActionList/FilteredActionList.tsx b/src/FilteredActionList/FilteredActionList.tsx index 55253910037..8c96d0276a0 100644 --- a/src/FilteredActionList/FilteredActionList.tsx +++ b/src/FilteredActionList/FilteredActionList.tsx @@ -54,9 +54,10 @@ const defaultRenderFn = ({ trailingVisual, leadingVisual, onSelect, + selected, }: ItemInput): React.ReactElement => { return ( - + {!!leadingVisual && {leadingVisual}} {text ? text : null} {description ? ( From 61694c6de6689ca4a4aae852ab0643754b879748 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Wed, 10 May 2023 13:10:37 -0400 Subject: [PATCH 18/29] Pass selectionVariant illegally to SelectPanel in src/MarkdownEditor/_SavedReplies.tsx so Selection components don't render. --- src/SelectPanel/SelectPanel.tsx | 2 +- src/drafts/MarkdownEditor/_SavedReplies.tsx | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/SelectPanel/SelectPanel.tsx b/src/SelectPanel/SelectPanel.tsx index 2ddb6f6bb13..d288745b8bc 100644 --- a/src/SelectPanel/SelectPanel.tsx +++ b/src/SelectPanel/SelectPanel.tsx @@ -157,10 +157,10 @@ export function SelectPanel({ { onSelectItem(Array.isArray(selection) ? selection[0] : selection) }} overlayProps={{width: 'small', maxHeight: 'small', anchorSide: 'outside-right', onKeyDown}} + // @ts-ignore this is bad because SelectPanel does not accept selectionVariant in the public API + // but it does pass it down to FilteredActionList underneath. + // SavedReplies should not use SelectPanel and override it's semantics, it should instead + // use the building blocks of SelectPanel to build a new component + selectionVariant={undefined} + aria-multiselectable={undefined} /> ) : ( <> From 99281c28c428fcc064b454fb30b0b908ca47c7fb Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Thu, 11 May 2023 11:17:02 -0400 Subject: [PATCH 19/29] Remove remaining references of hideSelection prop. --- src/ActionList/shared.ts | 4 ---- src/drafts/MarkdownEditor/_SavedReplies.tsx | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/ActionList/shared.ts b/src/ActionList/shared.ts index 5225591b01e..ff77e7975b8 100644 --- a/src/ActionList/shared.ts +++ b/src/ActionList/shared.ts @@ -40,10 +40,6 @@ export type ActionListItemProps = { * id to attach to the root element of the Item */ id?: string - /** - * boolean to hide selection subcomponent - */ - hideSelection?: boolean /** * Private API for use internally only. Used by LinkItem to wrap contents in an anchor */ diff --git a/src/drafts/MarkdownEditor/_SavedReplies.tsx b/src/drafts/MarkdownEditor/_SavedReplies.tsx index 8f3934dcd31..cd8f0b9a37a 100644 --- a/src/drafts/MarkdownEditor/_SavedReplies.tsx +++ b/src/drafts/MarkdownEditor/_SavedReplies.tsx @@ -54,7 +54,7 @@ export const SavedRepliesButton = () => { (reply, i): Item => ({ text: reply.name, description: reply.content, - descriptionVariant: 'inline', + descriptionVariant: 'block', trailingVisual: i < 9 ? `Ctrl + ${i + 1}` : undefined, sx: { // hide the leading visual container since we don't use the checkboxes @@ -67,7 +67,6 @@ export const SavedRepliesButton = () => { }, }, id: i.toString(), - hideSelection: true, }), ) From 83bdd995f527eb9c603d90456282fd0f3b6696f6 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Thu, 11 May 2023 11:17:23 -0400 Subject: [PATCH 20/29] Update changeset to reflect that changes impact SelectPanel. --- .changeset/weak-jokes-chew.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/weak-jokes-chew.md b/.changeset/weak-jokes-chew.md index 5bc46b3494a..1c2445cec20 100644 --- a/.changeset/weak-jokes-chew.md +++ b/.changeset/weak-jokes-chew.md @@ -2,4 +2,4 @@ "@primer/react": patch --- -FilteredActionList now uses new ActionList as a base. +FilteredActionList now uses new ActionList as a base, and SelectPanel reflects those changes. From 2021aabd3fdaf8a1d8ea27aac6b4f402f9849de9 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Thu, 11 May 2023 11:17:56 -0400 Subject: [PATCH 21/29] Remove renderFn prop from SelectPanel and use default for FilteredActionList, which seems to cover most cases. --- .../FilteredActionList.stories.tsx | 7 ------- src/FilteredActionList/FilteredActionList.tsx | 15 ++------------- src/SelectPanel/SelectPanel.stories.tsx | 7 ------- src/SelectPanel/SelectPanel.tsx | 2 -- 4 files changed, 2 insertions(+), 29 deletions(-) diff --git a/src/FilteredActionList/FilteredActionList.stories.tsx b/src/FilteredActionList/FilteredActionList.stories.tsx index e3aec4a9fa7..ab1dbcc1b60 100644 --- a/src/FilteredActionList/FilteredActionList.stories.tsx +++ b/src/FilteredActionList/FilteredActionList.stories.tsx @@ -2,7 +2,6 @@ import {Meta} from '@storybook/react' import React from 'react' import {ThemeProvider} from '..' import {FilteredActionList, ItemInput} from '../FilteredActionList' -import {ActionList} from '../ActionList' import BaseStyles from '../BaseStyles' import Box from '../Box' @@ -64,12 +63,6 @@ export function Default(): JSX.Element { items={filteredItems} onFilterChange={setFilter} sx={{border: '1px solid', padding: '8px'}} - renderFn={({id, leadingVisual, text}) => ( - - {leadingVisual && {leadingVisual}} - {text} - - )} /> ) diff --git a/src/FilteredActionList/FilteredActionList.tsx b/src/FilteredActionList/FilteredActionList.tsx index 8c96d0276a0..888af72d05e 100644 --- a/src/FilteredActionList/FilteredActionList.tsx +++ b/src/FilteredActionList/FilteredActionList.tsx @@ -2,7 +2,6 @@ import React, {KeyboardEventHandler, useCallback, useEffect, useRef} from 'react import TextInput, {TextInputProps} from '../TextInput' import Box from '../Box' import {ActionList, ActionListProps, ActionListItemProps} from '../ActionList' -import Truncate from '../Truncate' import Spinner from '../Spinner' import {useFocusZone} from '../hooks/useFocusZone' import {useProvidedStateOrCreate} from '../hooks/useProvidedStateOrCreate' @@ -20,7 +19,7 @@ const menuScrollMargins: ScrollIntoViewOptions = {startMargin: 0, endMargin: 8} export type ItemInput = Partial< ActionListItemProps & { description?: string - descriptionVariant?: string + descriptionVariant?: 'inline' | 'block' leadingVisual?: JSX.Element onAction?: (itemFromAction: ItemInput, event: React.MouseEvent) => void selected?: boolean @@ -60,17 +59,7 @@ const defaultRenderFn = ({ {!!leadingVisual && {leadingVisual}} {text ? text : null} - {description ? ( - - {descriptionVariant === 'block' ? ( - description - ) : ( - - {description} - - )} - - ) : null} + {description ? {description} : null} {!!trailingVisual && {trailingVisual}} ) diff --git a/src/SelectPanel/SelectPanel.stories.tsx b/src/SelectPanel/SelectPanel.stories.tsx index 32d38ce7984..fd65f768a73 100644 --- a/src/SelectPanel/SelectPanel.stories.tsx +++ b/src/SelectPanel/SelectPanel.stories.tsx @@ -45,12 +45,6 @@ export const Default = () => { const [filter, setFilter] = React.useState('') const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) const [open, setOpen] = useState(false) - const renderFn = (props: ItemInput) => ( - - {!!props.leadingVisual && {props.leadingVisual}} - {props.text} - - ) return ( <> @@ -66,7 +60,6 @@ export const Default = () => { open={open} onOpenChange={setOpen} items={filteredItems} - renderFn={renderFn} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} diff --git a/src/SelectPanel/SelectPanel.tsx b/src/SelectPanel/SelectPanel.tsx index d288745b8bc..dfd9224ae2f 100644 --- a/src/SelectPanel/SelectPanel.tsx +++ b/src/SelectPanel/SelectPanel.tsx @@ -60,7 +60,6 @@ export function SelectPanel({ textInputProps, overlayProps, sx, - renderFn, ...listProps }: SelectPanelProps): JSX.Element { const [filterValue, setInternalFilterValue] = useProvidedStateOrCreate(externalFilterValue, undefined, '') @@ -162,7 +161,6 @@ export function SelectPanel({ selectionVariant={isMultiSelectVariant(selected) ? 'multiple' : 'single'} {...listProps} items={itemsToRender} - renderFn={renderFn} textInputProps={extendedTextInputProps} inputRef={inputRef} // inheriting height and maxHeight ensures that the FilteredActionList is never taller From dca5ee7ec7d36261f9fd086009197f8d44a6f644 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Thu, 11 May 2023 11:57:00 -0400 Subject: [PATCH 22/29] Fix truncation in SavedReplies descriptions. --- src/FilteredActionList/FilteredActionList.tsx | 4 ++-- src/drafts/MarkdownEditor/_SavedReplies.tsx | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/FilteredActionList/FilteredActionList.tsx b/src/FilteredActionList/FilteredActionList.tsx index 888af72d05e..4bbd6ff73ec 100644 --- a/src/FilteredActionList/FilteredActionList.tsx +++ b/src/FilteredActionList/FilteredActionList.tsx @@ -18,7 +18,7 @@ const menuScrollMargins: ScrollIntoViewOptions = {startMargin: 0, endMargin: 8} export type ItemInput = Partial< ActionListItemProps & { - description?: string + description?: string | React.ReactElement descriptionVariant?: 'inline' | 'block' leadingVisual?: JSX.Element onAction?: (itemFromAction: ItemInput, event: React.MouseEvent) => void @@ -58,7 +58,7 @@ const defaultRenderFn = ({ return ( {!!leadingVisual && {leadingVisual}} - {text ? text : null} + {text ? text : null} {description ? {description} : null} {!!trailingVisual && {trailingVisual}} diff --git a/src/drafts/MarkdownEditor/_SavedReplies.tsx b/src/drafts/MarkdownEditor/_SavedReplies.tsx index cd8f0b9a37a..7d2895b4bf5 100644 --- a/src/drafts/MarkdownEditor/_SavedReplies.tsx +++ b/src/drafts/MarkdownEditor/_SavedReplies.tsx @@ -10,6 +10,7 @@ import React, { } from 'react' import {SelectPanel, SelectPanelProps} from '../../SelectPanel' import {ToolbarButton} from './Toolbar' +import Truncate from '../../Truncate' export type SavedReply = { name: string @@ -53,7 +54,11 @@ export const SavedRepliesButton = () => { .map( (reply, i): Item => ({ text: reply.name, - description: reply.content, + description: ( + + {reply.content} + + ), descriptionVariant: 'block', trailingVisual: i < 9 ? `Ctrl + ${i + 1}` : undefined, sx: { From 936b08c769796e9e57778de50de2225b5356678d Mon Sep 17 00:00:00 2001 From: radglob Date: Thu, 11 May 2023 15:58:56 +0000 Subject: [PATCH 23/29] Update generated/components.json --- generated/components.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generated/components.json b/generated/components.json index 11c56a6d330..3200722eb88 100644 --- a/generated/components.json +++ b/generated/components.json @@ -3563,7 +3563,7 @@ "stories": [ { "id": "components-selectpanel--default", - "code": "() => {\n const [selected, setSelected] = React.useState([\n items[0],\n items[1],\n ])\n const [filter, setFilter] = React.useState('')\n const filteredItems = items.filter((item) =>\n item.text.toLowerCase().startsWith(filter.toLowerCase()),\n )\n const [open, setOpen] = useState(false)\n const renderFn = (props: ItemInput) => (\n \n {!!props.leadingVisual && (\n \n {props.leadingVisual}\n \n )}\n {props.text}\n \n )\n return (\n <>\n

Multi Select Panel

\n
Please select labels that describe your issue:
\n (\n \n {children ?? 'Select Labels'}\n \n )}\n placeholderText=\"Filter Labels\"\n open={open}\n onOpenChange={setOpen}\n items={filteredItems}\n renderFn={renderFn}\n selected={selected}\n onSelectedChange={setSelected}\n onFilterChange={setFilter}\n overlayProps={{\n width: 'small',\n height: 'xsmall',\n }}\n />\n \n )\n}" + "code": "() => {\n const [selected, setSelected] = React.useState([\n items[0],\n items[1],\n ])\n const [filter, setFilter] = React.useState('')\n const filteredItems = items.filter((item) =>\n item.text.toLowerCase().startsWith(filter.toLowerCase()),\n )\n const [open, setOpen] = useState(false)\n return (\n <>\n

Multi Select Panel

\n
Please select labels that describe your issue:
\n (\n \n {children ?? 'Select Labels'}\n \n )}\n placeholderText=\"Filter Labels\"\n open={open}\n onOpenChange={setOpen}\n items={filteredItems}\n selected={selected}\n onSelectedChange={setSelected}\n onFilterChange={setFilter}\n overlayProps={{\n width: 'small',\n height: 'xsmall',\n }}\n />\n \n )\n}" } ], "props": [ From 626efc4507602797b6f72ecd17ccf00204d9f691 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Thu, 11 May 2023 12:02:44 -0400 Subject: [PATCH 24/29] Fix linting error. --- src/SelectPanel/SelectPanel.stories.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SelectPanel/SelectPanel.stories.tsx b/src/SelectPanel/SelectPanel.stories.tsx index fd65f768a73..44603c9f4c6 100644 --- a/src/SelectPanel/SelectPanel.stories.tsx +++ b/src/SelectPanel/SelectPanel.stories.tsx @@ -5,7 +5,6 @@ import {TriangleDownIcon} from '@primer/octicons-react' import {Button} from '../Button' import {SelectPanel} from '../SelectPanel' import Box from '../Box' -import {ActionList} from '../ActionList' import {ItemInput} from '../FilteredActionList' export default { From 47968e09a5c613abc34a96e3e73dbbb3aac55812 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Fri, 12 May 2023 09:40:07 -0400 Subject: [PATCH 25/29] Don't make renderFn a prop (if we need to make this configurable, we can expose it later. Use maxWidth 100% for SavedReplies truncation. --- src/FilteredActionList/FilteredActionList.tsx | 4 +--- src/drafts/MarkdownEditor/_SavedReplies.tsx | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/FilteredActionList/FilteredActionList.tsx b/src/FilteredActionList/FilteredActionList.tsx index 4bbd6ff73ec..13054b58b9f 100644 --- a/src/FilteredActionList/FilteredActionList.tsx +++ b/src/FilteredActionList/FilteredActionList.tsx @@ -36,7 +36,6 @@ export interface FilteredActionListProps extends ActionListProps, SxProp { textInputProps?: Partial> inputRef?: React.RefObject items: ItemInput[] - renderFn?: (props: ItemInput) => React.ReactElement } const StyledHeader = styled.div` @@ -44,7 +43,7 @@ const StyledHeader = styled.div` z-index: 1; ` -const defaultRenderFn = ({ +const renderFn = ({ description, descriptionVariant, id, @@ -71,7 +70,6 @@ export function FilteredActionList({ filterValue: externalFilterValue, onFilterChange, items, - renderFn = defaultRenderFn, textInputProps, inputRef: providedInputRef, sx, diff --git a/src/drafts/MarkdownEditor/_SavedReplies.tsx b/src/drafts/MarkdownEditor/_SavedReplies.tsx index 7d2895b4bf5..b1804c906a8 100644 --- a/src/drafts/MarkdownEditor/_SavedReplies.tsx +++ b/src/drafts/MarkdownEditor/_SavedReplies.tsx @@ -55,7 +55,7 @@ export const SavedRepliesButton = () => { (reply, i): Item => ({ text: reply.name, description: ( - + {reply.content} ), From 13e256ba6dad84fb05e12a016817225ad06a1518 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Fri, 12 May 2023 11:33:14 -0400 Subject: [PATCH 26/29] Use showDividers prop in SelectPanel story. --- src/SelectPanel/SelectPanel.features.stories.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SelectPanel/SelectPanel.features.stories.tsx b/src/SelectPanel/SelectPanel.features.stories.tsx index d0b00db3988..c431adb4e70 100644 --- a/src/SelectPanel/SelectPanel.features.stories.tsx +++ b/src/SelectPanel/SelectPanel.features.stories.tsx @@ -61,6 +61,7 @@ export const SingleSelectStory = () => { selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} + showDividers={true} overlayProps={{width: 'small', height: 'xsmall'}} /> From e3edf33dced8102b366692a1c3a3dfcce9592720 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Tue, 16 May 2023 15:56:19 -0400 Subject: [PATCH 27/29] Formatting. --- .github/workflows/release-schedule.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release-schedule.yml b/.github/workflows/release-schedule.yml index 01573daf083..921fc7c20e4 100644 --- a/.github/workflows/release-schedule.yml +++ b/.github/workflows/release-schedule.yml @@ -72,7 +72,7 @@ jobs: const previousMonday = require('date-fns/previousMonday'); const { RELEASE_CONDUCTOR } = process.env; - + core.info(`Release conductor: ${RELEASE_CONDUCTOR}`); // Current schedule @@ -87,12 +87,12 @@ jobs: // Issue IDs const id = `primer-release-schedule:${format(start, 'yyyy-MM-dd')}`; const previousId = `primer-release-schedule:${format(previousStart, 'yyyy-M-dd')}`; - + core.startGroup(`Previous schedule: ${previousId}`); core.info(`Start: ${previousStart}`); core.info(`End: ${previousEnd}`) core.endGroup(); - + core.startGroup(`Current schedule: ${id}`); core.info(`Start: ${start}`); core.info(`End: ${end}`) @@ -174,7 +174,7 @@ jobs: }); return; } - + core.info(`Found release issue: ${releaseIssue.html_url}`); // We already have an issue open for the current release From c3616500c9f7f4665a06e514fafd7f6c797cfdd8 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Tue, 23 May 2023 09:53:57 -0400 Subject: [PATCH 28/29] Add temporary support for showItemDividers prop to SelectPanel to keep backwards compatibility. --- src/SelectPanel/SelectPanel.features.stories.tsx | 1 + src/SelectPanel/SelectPanel.tsx | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/SelectPanel/SelectPanel.features.stories.tsx b/src/SelectPanel/SelectPanel.features.stories.tsx index c431adb4e70..b833a8bb614 100644 --- a/src/SelectPanel/SelectPanel.features.stories.tsx +++ b/src/SelectPanel/SelectPanel.features.stories.tsx @@ -62,6 +62,7 @@ export const SingleSelectStory = () => { onSelectedChange={setSelected} onFilterChange={setFilter} showDividers={true} + showItemDividers={true} overlayProps={{width: 'small', height: 'xsmall'}} /> diff --git a/src/SelectPanel/SelectPanel.tsx b/src/SelectPanel/SelectPanel.tsx index dfd9224ae2f..04e48284651 100644 --- a/src/SelectPanel/SelectPanel.tsx +++ b/src/SelectPanel/SelectPanel.tsx @@ -33,7 +33,8 @@ export type SelectPanelProps = SelectPanelBaseProps & Omit & Pick & AnchoredOverlayWrapperAnchorProps & - (SelectPanelSingleSelection | SelectPanelMultiSelection) + // TODO: 23-05-23 - Remove showItemDividers after next-major release + (SelectPanelSingleSelection | SelectPanelMultiSelection) & {showItemDividers?: boolean} function isMultiSelectVariant( selected: SelectPanelSingleSelection['selected'] | SelectPanelMultiSelection['selected'], From 794faf4b1f74d5f2a51d0eac3e96452dd0b71931 Mon Sep 17 00:00:00 2001 From: Jeremy Neal Date: Thu, 25 May 2023 16:40:35 -0400 Subject: [PATCH 29/29] Support passing deprecated showItemDividers prop in ActionList. --- src/ActionList/List.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ActionList/List.tsx b/src/ActionList/List.tsx index 9d0c1a8ba7c..f9a779c6f56 100644 --- a/src/ActionList/List.tsx +++ b/src/ActionList/List.tsx @@ -69,7 +69,8 @@ export const List = React.forwardRef( value={{ variant, selectionVariant: selectionVariant || containerSelectionVariant, - showDividers, + // @ts-ignore showItemDividers may be passed by some components until next major. + showDividers: showDividers || !!props.showItemDividers, role: role || listRole, headingId, }}