From d715e768a02bbd51e5241e8fb80a0527f2a7c5aa Mon Sep 17 00:00:00 2001 From: Miguel Date: Fri, 27 Jun 2025 14:07:26 -0600 Subject: [PATCH 1/7] feat(#2302): popover - add table/filter contextual example --- src/examples/popover/PopoverPageExamples.tsx | 461 ++++++++++++++++++ .../popover/popover-page-examples.css | 5 + src/routes/components/Popover.tsx | 11 +- 3 files changed, 473 insertions(+), 4 deletions(-) create mode 100644 src/examples/popover/PopoverPageExamples.tsx create mode 100644 src/examples/popover/popover-page-examples.css diff --git a/src/examples/popover/PopoverPageExamples.tsx b/src/examples/popover/PopoverPageExamples.tsx new file mode 100644 index 000000000..d8c759043 --- /dev/null +++ b/src/examples/popover/PopoverPageExamples.tsx @@ -0,0 +1,461 @@ +import { useContext } from "react"; +import { Sandbox } from "@components/sandbox"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { + GoabBadge, + GoabFormItem, + GoabRadioGroup, + GoabRadioItem, + GoabButton, + GoabPopover, + GoabTable +} from "@abgov/react-components"; +import "./popover-page-examples.css"; +import { GoabBadgeType } from "@abgov/ui-components-common"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; + +export const PopoverPageExamples = () => { + const noop = () => {} + const { version } = useContext(LanguageVersionContext); + const target = ( + + Filter + + ); + const popoverValues = [ + { + key: 1, + type: "success", + status: "Open", + }, + { + key: 2, + type: "midtone", + status: "Closed", + }, + { + key: 3, + type: "midtone", + status: "Closed", + }, + { + key: 4, + type: "midtone", + status: "Closed", + }, + { + key: 5, + type: "success", + status: "Open", + }, + { + key: 6, + type: "midtone", + status: "Closed", + }, + ]; + return ( + <> + + + + {/*============= React code ==============*/} + {version === "old" && ( + + Filter + + ); + + const popoverValues = [ + { + key: 1, + type: "success", + status: "Open", + }, + { + key: 2, + type: "midtone", + status: "Closed", + }, + { + key: 3, + type: "midtone", + status: "Closed", + }, + { + key: 4, + type: "midtone", + status: "Closed", + }, + { + key: 5, + type: "success", + status: "Open", + }, + { + key: 6, + type: "midtone", + status: "Closed", + }, + ]; + `} + /> + )} + + {version === "new" && ( + + Filter + + ); + + const popoverValues = [ + { + key: 1, + type: "success", + status: "Open", + }, + { + key: 2, + type: "midtone", + status: "Closed", + }, + { + key: 3, + type: "midtone", + status: "Closed", + }, + { + key: 4, + type: "midtone", + status: "Closed", + }, + { + key: 5, + type: "success", + status: "Open", + }, + { + key: 6, + type: "midtone", + status: "Closed", + }, + ]; + `} + /> + )} + + {version === "old" && ( + +

Table with a filter

+ +
+ + + + + + + Remove filter +
+
+ + + + + Status + Text + Number + Action + + + + {popoverValues.map(u => ( + + + Lorem ipsum + 1234567890 + Action + + ))} + + + `} + /> + )} + + {version === "new" && ( + +

Table with a filter

+ +
+ + + + + + + Remove filter +
+
+ + + + + Status + Text + Number + Action + + + + {popoverValues.map(u => ( + + + Lorem ipsum + 1234567890 + Action + + ))} + + + `} + /> + )} + + {/*================ Angular code ==================*/} + {version === "old" && ( + + )} + + {version === "new" && ( + + )} + + {version === "old" && ( + +

Table with a filter

+ +
+ + + + + + + Remove filter +
+
+ Filter +
+
+ + + + + Status + Text + Number + Action + + + + + Lorem ipsum + 1234567890 + Action + + + + `} + /> + )} + + {version === "new" && ( + +

Table with a filter

+ +
+ + + + + + + Remove filter +
+
+ Filter +
+
+ + + + + Status + Text + Number + Action + + + + + Lorem ipsum + 1234567890 + Action + + + + `} + /> + )} +
+

Table with a filter

+ +
+ + + + + + + Remove filter +
+
+
+ + + + Status + Text + Number + Action + + + + {popoverValues.map(u => ( + + + Lorem ipsum + 1234567890 + Action + + ))} + + +
+ + ); +} diff --git a/src/examples/popover/popover-page-examples.css b/src/examples/popover/popover-page-examples.css new file mode 100644 index 000000000..7d441361f --- /dev/null +++ b/src/examples/popover/popover-page-examples.css @@ -0,0 +1,5 @@ +.goa-table-heading-container { + display: flex; + justify-content: space-between; + align-items: center; +} \ No newline at end of file diff --git a/src/routes/components/Popover.tsx b/src/routes/components/Popover.tsx index f2e254328..c92e0f1f9 100644 --- a/src/routes/components/Popover.tsx +++ b/src/routes/components/Popover.tsx @@ -1,11 +1,12 @@ import { useContext, useState } from "react"; import { ComponentBinding, Sandbox } from "@components/sandbox"; +import { Link } from "react-router-dom"; import { ComponentProperties, ComponentProperty, } from "@components/component-properties/ComponentProperties.tsx"; import { Category, ComponentHeader } from "@components/component-header/ComponentHeader.tsx"; -import { GoabBadge, GoabButton, GoabPopover, GoabTab, GoabTabs } from "@abgov/react-components"; +import { GoabBadge, GoabButton, GoabCallout, GoabPopover, GoabSpacer, GoabTab, GoabTabs } from "@abgov/react-components"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { propsToString } from "@components/sandbox/BaseSerializer.ts"; import { ComponentContent } from "@components/component-content/ComponentContent"; @@ -16,8 +17,8 @@ import { TestIdProperty } from "@components/component-properties/common-properties.ts"; import { DesignEmpty } from "@components/empty-states/design-empty/DesignEmpty.tsx"; +import { PopoverPageExamples } from "@examples/popover/PopoverPageExamples.tsx"; import { AccessibilityEmpty } from "@components/empty-states/accessibility-empty/AccessibilityEmpty.tsx"; -import { ExamplesEmpty } from "@components/empty-states/examples-empty/ExamplesEmpty.tsx"; const FIGMA_LINK = "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=27301-302109"; @@ -283,6 +284,8 @@ export default function PopoverPage() { It can be used for a number of different contexts. + + Popovers are used as a base layer in other components like tooltips, and dropdown menus. @@ -290,11 +293,11 @@ export default function PopoverPage() { heading={ <> Examples - + } > - + From c69d41c20f3a54366e6d26492b5aeb0919536a31 Mon Sep 17 00:00:00 2001 From: Miguel Date: Mon, 7 Jul 2025 15:32:40 -0600 Subject: [PATCH 2/7] Adjusted Popover imports. --- src/routes/components/Popover.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/routes/components/Popover.tsx b/src/routes/components/Popover.tsx index ed5129a6e..dd4364312 100644 --- a/src/routes/components/Popover.tsx +++ b/src/routes/components/Popover.tsx @@ -18,7 +18,6 @@ import { TestIdProperty, } from "@components/component-properties/common-properties.ts"; import { DesignEmpty } from "@components/empty-states/design-empty/DesignEmpty.tsx"; -import { PopoverPageExamples } from "@examples/popover/PopoverPageExamples.tsx"; import { AccessibilityEmpty } from "@components/empty-states/accessibility-empty/AccessibilityEmpty.tsx"; //import { ExamplesEmpty } from "@components/empty-states/examples-empty/ExamplesEmpty.tsx"; import { PopoverExamples } from "@examples/popover/PopoverExamples"; From d514554cbf553e83d69183189376c0edce68e5f3 Mon Sep 17 00:00:00 2001 From: Miguel Date: Mon, 7 Jul 2025 15:34:42 -0600 Subject: [PATCH 3/7] Adjust TablePopover import. --- src/examples/popover/TablePopover.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/examples/popover/TablePopover.tsx b/src/examples/popover/TablePopover.tsx index 85aebf0bd..a8cdc0c76 100644 --- a/src/examples/popover/TablePopover.tsx +++ b/src/examples/popover/TablePopover.tsx @@ -13,7 +13,6 @@ import { import "./popover-page-examples.css"; import { GoabBadgeType } from "@abgov/ui-components-common"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export const TablePopover = () => { const noop = () => {} From 5d5bfc526483768c76488e7907214258bd5bb489 Mon Sep 17 00:00:00 2001 From: Miguel Date: Fri, 25 Jul 2025 14:04:32 -0600 Subject: [PATCH 4/7] feat(#2302): popover - adding in filter option for table example (IN PROGESS) --- src/examples/popover/TablePopover.tsx | 87 +++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 13 deletions(-) diff --git a/src/examples/popover/TablePopover.tsx b/src/examples/popover/TablePopover.tsx index a8cdc0c76..d0d8725db 100644 --- a/src/examples/popover/TablePopover.tsx +++ b/src/examples/popover/TablePopover.tsx @@ -1,27 +1,26 @@ -import { useContext } from "react"; +import { useContext, useState, useEffect, useCallback } from "react"; import { Sandbox } from "@components/sandbox"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { GoabBadge, + GoabFilterChip, GoabFormItem, GoabRadioGroup, GoabRadioItem, GoabButton, GoabPopover, - GoabTable + GoabTable, + GoabText } from "@abgov/react-components"; import "./popover-page-examples.css"; import { GoabBadgeType } from "@abgov/ui-components-common"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { GoabRadioGroupOnChangeDetail } from "@abgov/ui-components-common"; export const TablePopover = () => { - const noop = () => {} const { version } = useContext(LanguageVersionContext); - const target = ( - - Filter - - ); + const [selectedChips, setSelectedChips] = useState([]); + const [filter, setFilter] = useState('All'); const popoverValues = [ { key: 1, @@ -54,6 +53,49 @@ export const TablePopover = () => { status: "Closed", }, ]; + + const [dataFiltered, setDataFiltered] = useState(popoverValues); + + const target = ( + + Filter + + ); + + function radioGroupOnChange(event: GoabRadioGroupOnChangeDetail) { + setSelectedChips([...selectedChips, event.value]); + return; + }; + + const checkNested = useCallback((obj: object, chip: string): boolean => { + return Object.values(obj).some(value => + typeof value === "object" && value !== null + ? checkNested(value, chip) + : typeof value === "string" && value.toLowerCase().includes(chip.toLowerCase()) + ); + }, []); + + const removeFilter = (chip: string) => { + setSelectedChips(selectedChips.filter(c => c !== chip)); + }; + + const getFilteredData = useCallback ((selectedChips: string[]) => { + if (selectedChips.length === 0) { + return popoverValues; + } + const filteredData = popoverValues.filter((item: object) => + selectedChips.every(chip => checkNested(item, chip)) + ); + + return filteredData; + }, + [checkNested, popoverValues] + ); + + useEffect(() => { + setDataFiltered(getFilteredData(selectedChips)); + }, [getFilteredData, selectedChips]); + return ( <> @@ -421,15 +463,34 @@ export const TablePopover = () => {
- - - + + + - Remove filter
+ {selectedChips.length > 0 && ( +
+ + Filter: + + {selectedChips.length > 0 && + selectedChips.map((selectedChip, index) => ( + removeFilter(selectedChip)} + /> + ))} + setSelectedChips([])}> + Clear all + +
+ )} @@ -440,7 +501,7 @@ export const TablePopover = () => { - {popoverValues.map(u => ( + {dataFiltered.map(u => ( Lorem ipsum From 0473b17ca52763bae04f93d60c161eca5faa63e4 Mon Sep 17 00:00:00 2001 From: Miguel Date: Fri, 25 Jul 2025 14:12:56 -0600 Subject: [PATCH 5/7] feat(#2302): popover - adding in filter option for table example (IN PROGESS) --- src/examples/popover/TablePopover.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/examples/popover/TablePopover.tsx b/src/examples/popover/TablePopover.tsx index d0d8725db..5aa3c3f5e 100644 --- a/src/examples/popover/TablePopover.tsx +++ b/src/examples/popover/TablePopover.tsx @@ -20,7 +20,7 @@ import { GoabRadioGroupOnChangeDetail } from "@abgov/ui-components-common"; export const TablePopover = () => { const { version } = useContext(LanguageVersionContext); const [selectedChips, setSelectedChips] = useState([]); - const [filter, setFilter] = useState('All'); + const [filter] = useState('All'); const popoverValues = [ { key: 1, @@ -77,6 +77,7 @@ export const TablePopover = () => { const removeFilter = (chip: string) => { setSelectedChips(selectedChips.filter(c => c !== chip)); + return; }; const getFilteredData = useCallback ((selectedChips: string[]) => { From 1d3785c609e7f960e267475dd713515b03065de6 Mon Sep 17 00:00:00 2001 From: Miguel Date: Thu, 18 Sep 2025 13:21:18 -0600 Subject: [PATCH 6/7] feat(#2302): popover - adjusted Table Filter example --- src/examples/popover/PopoverExamples.tsx | 5 +- src/examples/popover/TablePopover.tsx | 536 +++++++++-------------- 2 files changed, 210 insertions(+), 331 deletions(-) diff --git a/src/examples/popover/PopoverExamples.tsx b/src/examples/popover/PopoverExamples.tsx index 0ae830eba..fd4f6eb8d 100644 --- a/src/examples/popover/PopoverExamples.tsx +++ b/src/examples/popover/PopoverExamples.tsx @@ -1,3 +1,4 @@ +import { GoabSpacer } from "@abgov/react-components"; import { ButtonClosePopover } from "@examples/popover/ButtonClosePopover"; import { LinkClosePopover } from "@examples/popover/LinkClosePopover"; import { IconButtonClosePopover } from "@examples/popover/IconButtonClosePopover"; @@ -11,9 +12,7 @@ export const PopoverExamples = () => { const { version, language } = useContext(LanguageVersionContext); return ( <> - {version === "old" && ( - - )} + {/*Popover Example - close using a button*/} diff --git a/src/examples/popover/TablePopover.tsx b/src/examples/popover/TablePopover.tsx index 5aa3c3f5e..45179eace 100644 --- a/src/examples/popover/TablePopover.tsx +++ b/src/examples/popover/TablePopover.tsx @@ -1,4 +1,4 @@ -import { useContext, useState, useEffect, useCallback } from "react"; +import { useContext, useState } from "react"; import { Sandbox } from "@components/sandbox"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { @@ -19,236 +19,94 @@ import { GoabRadioGroupOnChangeDetail } from "@abgov/ui-components-common"; export const TablePopover = () => { const { version } = useContext(LanguageVersionContext); - const [selectedChips, setSelectedChips] = useState([]); - const [filter] = useState('All'); + const [selectedFilter, setSelectedFilter] = useState(null); + const popoverValues = [ - { - key: 1, - type: "success", - status: "Open", - }, - { - key: 2, - type: "midtone", - status: "Closed", - }, - { - key: 3, - type: "midtone", - status: "Closed", - }, - { - key: 4, - type: "midtone", - status: "Closed", - }, - { - key: 5, - type: "success", - status: "Open", - }, - { - key: 6, - type: "midtone", - status: "Closed", - }, + { key: 1, type: "success", status: "Open" }, + { key: 2, type: "midtone", status: "Closed" }, + { key: 3, type: "midtone", status: "Closed" }, + { key: 4, type: "midtone", status: "Closed" }, + { key: 5, type: "success", status: "Open" }, + { key: 6, type: "midtone", status: "Closed" }, ]; - const [dataFiltered, setDataFiltered] = useState(popoverValues); - const target = ( - + Filter ); function radioGroupOnChange(event: GoabRadioGroupOnChangeDetail) { - setSelectedChips([...selectedChips, event.value]); - return; - }; - - const checkNested = useCallback((obj: object, chip: string): boolean => { - return Object.values(obj).some(value => - typeof value === "object" && value !== null - ? checkNested(value, chip) - : typeof value === "string" && value.toLowerCase().includes(chip.toLowerCase()) - ); - }, []); + setSelectedFilter(event.value); + } - const removeFilter = (chip: string) => { - setSelectedChips(selectedChips.filter(c => c !== chip)); - return; - }; - - const getFilteredData = useCallback ((selectedChips: string[]) => { - if (selectedChips.length === 0) { - return popoverValues; - } - const filteredData = popoverValues.filter((item: object) => - selectedChips.every(chip => checkNested(item, chip)) - ); - - return filteredData; - }, - [checkNested, popoverValues] - ); + const filteredData = selectedFilter ? popoverValues.filter((item) => + item.status === selectedFilter + ) : popoverValues; - useEffect(() => { - setDataFiltered(getFilteredData(selectedChips)); - }, [getFilteredData, selectedChips]); - return ( <> {/*============= React code ==============*/} - {version === "old" && ( + + {version === "new" && ( - Filter - - ); + const [selectedFilter, setSelectedFilter] = useState(null); const popoverValues = [ { key: 1, type: "success", - status: "Open", + status: "Open" }, { key: 2, type: "midtone", - status: "Closed", + status: "Closed" }, { key: 3, type: "midtone", - status: "Closed", + status: "Closed" }, { key: 4, type: "midtone", - status: "Closed", + status: "Closed" }, { key: 5, type: "success", - status: "Open", + status: "Open" }, { key: 6, type: "midtone", - status: "Closed", + status: "Closed" }, ]; - `} - /> - )} - - {version === "new" && ( - + Filter ); - const popoverValues = [ - { - key: 1, - type: "success", - status: "Open", - }, - { - key: 2, - type: "midtone", - status: "Closed", - }, - { - key: 3, - type: "midtone", - status: "Closed", - }, - { - key: 4, - type: "midtone", - status: "Closed", - }, - { - key: 5, - type: "success", - status: "Open", - }, - { - key: 6, - type: "midtone", - status: "Closed", - }, - ]; - `} - /> - )} - - {version === "old" && ( - -

Table with a filter

- -
- - - - - - - Remove filter -
-
- - - - - Status - Text - Number - Action - - - - {popoverValues.map(u => ( - - - Lorem ipsum - 1234567890 - Action - - ))} - - + function radioGroupOnChange(event: GoabRadioGroupOnChangeDetail) { + setSelectedFilter(event.value); + } + + const filteredData = selectedFilter ? popoverValues.filter((item) => + item.status === selectedFilter + ) : popoverValues; `} /> )} - + {version === "new" && ( {
- - - + + + - Remove filter + setSelectedFilter(null)} + aria-label="Remove filter" + > + Remove filter +
+ {selectedFilter && ( +
+ + Filter: + + setSelectedFilter(null)} + /> + setSelectedFilter(null)} + > + Clear all + +
+ )} + - Status - Text - Number - Action + Status + Text + Number + Action - {popoverValues.map(u => ( - - + {filteredData.map((u) => ( + + + + Lorem ipsum 1234567890 - Action - + + Action + + ))} `} /> )} - + {/*================ Angular code ==================*/} - {version === "old" && ( - - )} - {version === "new" && ( - )} - - {version === "old" && ( - -

Table with a filter

- -
- - - - - - - Remove filter -
-
- Filter -
-
- - - - - Status - Text - Number - Action - - - - - Lorem ipsum - 1234567890 - Action - - - + @Component({ + selector: 'app-table-popover', + templateUrl: './table-popover.component.html', + }) + + export class TablePopoverComponent { + selectedFilter = new FormControl(null); + + popoverValues: PopoverValue[] = [ + { + key: 1, + type: 'success', + status: 'Open' + }, + { + key: 2, + type: 'midtone', + status: 'Closed' + }, + { + key: 3, + type: 'midtone', + status: 'Closed' + }, + { + key: 4, + type: 'midtone', + status: 'Closed' + }, + { + key: 5, + type: 'success', + status: 'Open' + }, + { + key: 6, + type: 'midtone', + status: 'Closed' + }, + ]; + + get filteredData(): PopoverValue[] { + const filter = this.selectedFilter.value; + return filter + ? this.popoverValues.filter(item => item.status === filter) + : this.popoverValues; + } + + clearFilter() { + this.selectedFilter.setValue(null); + } + } `} /> )} - + {version === "new" && ( { code={`

Table with a filter

- +
- - - + + + Remove filter
-
- Filter -
+ + + Filter + +
+ +
+ + Filter: + + + + Clear all + +
+ @@ -459,39 +324,50 @@ export const TablePopover = () => { `} /> )} +

Table with a filter

- - - + + + + setSelectedFilter(null)} + > + Remove filter +
- {selectedChips.length > 0 && ( + {selectedFilter && (
- - Filter: - - {selectedChips.length > 0 && - selectedChips.map((selectedChip, index) => ( + + Filter: + removeFilter(selectedChip)} + onClick={() => setSelectedFilter(null)} /> - ))} - setSelectedChips([])}> - Clear all - + setSelectedFilter(null)} + aria-label="Clear all filters" + > + Clear all +
)} + @@ -502,17 +378,21 @@ export const TablePopover = () => { - {dataFiltered.map(u => ( - - + {filteredData.map((u) => ( + + + + Lorem ipsum 1234567890 - Action - + + Action + + ))}
); -} +}; From 342c7ad3b65d99f7437129b9f27122b4afd21127 Mon Sep 17 00:00:00 2001 From: Miguel Date: Thu, 18 Sep 2025 13:25:10 -0600 Subject: [PATCH 7/7] feat(#2302): popover - removed "Remove Filter" button --- src/examples/popover/TablePopover.tsx | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/examples/popover/TablePopover.tsx b/src/examples/popover/TablePopover.tsx index 45179eace..b6d2ebcba 100644 --- a/src/examples/popover/TablePopover.tsx +++ b/src/examples/popover/TablePopover.tsx @@ -123,14 +123,6 @@ export const TablePopover = () => { - setSelectedFilter(null)} - aria-label="Remove filter" - > - Remove filter - @@ -270,7 +262,6 @@ export const TablePopover = () => { - Remove filter { - setSelectedFilter(null)} - > - Remove filter -