diff --git a/.changeset/lemon-starfishes-trade.md b/.changeset/lemon-starfishes-trade.md new file mode 100644 index 000000000..4347ab4f9 --- /dev/null +++ b/.changeset/lemon-starfishes-trade.md @@ -0,0 +1,5 @@ +--- +"@hopper-ui/components": patch +--- + +Updated TagGroup's API. Removed TagList since it's now used internally. Added label, description and errorMessage props instead of being used as slots. diff --git a/apps/docs/content/components/collections/TagGroup.mdx b/apps/docs/content/components/collections/TagGroup.mdx index ce6e2eb6e..1b87a8518 100644 --- a/apps/docs/content/components/collections/TagGroup.mdx +++ b/apps/docs/content/components/collections/TagGroup.mdx @@ -1,7 +1,7 @@ --- title: TagGroup description: The TagGroup is a dynamic UI component that encapsulates a collection of tags. - Each tag, representing a label, category, keyword, or filter, is designed to be used within a TagList for groupings. + Each tag represents a label, category, keyword, or filter, and can be used for various groupings category: "collections" links: source: https://github.com/gsoft-inc/wl-hopper/blob/main/packages/components/src/tag/src/TagGroup.tsx @@ -34,19 +34,19 @@ links: A `TagGroup` uses the following components. - + ## Usage ### Label -A tag group can contain a label to provide more context to the user. +A tag group can use the `label` prop to provide more context to the user. ### Description -A tag group can contain a description to provide more information to the user. +A tag group can use a `description` prop to provide more information to the user. @@ -111,7 +111,7 @@ A tag can vary in style using the `variant` prop. Using the `renderEmptyState` prop, you can customize the empty state message when there are no tags. - + ### Invalid @@ -176,10 +176,6 @@ A tag can be rendered as a react router link when using the `href` prop and sett -### TagList - - - ### Tag @@ -190,10 +186,6 @@ A tag can be rendered as a react router link when using the `href` prop and sett -### TagList - - - ### Tag diff --git a/apps/docs/examples/Preview.ts b/apps/docs/examples/Preview.ts index 908d98b62..80d766db6 100644 --- a/apps/docs/examples/Preview.ts +++ b/apps/docs/examples/Preview.ts @@ -191,8 +191,8 @@ export const Previews: Record = { "tag/docs/tag/variants": { component: lazy(() => import("@/../../packages/components/src/tag/docs/tag/variants.tsx")) }, - "tag/docs/tagList/empty": { - component: lazy(() => import("@/../../packages/components/src/tag/docs/tagList/empty.tsx")) + "tag/docs/tagGroup/empty": { + component: lazy(() => import("@/../../packages/components/src/tag/docs/tagGroup/empty.tsx")) }, "tag/docs/tag/invalid": { component: lazy(() => import("@/../../packages/components/src/tag/docs/tag/invalid.tsx")) diff --git a/packages/components/src/Form/tests/chromatic/Form.stories.tsx b/packages/components/src/Form/tests/chromatic/Form.stories.tsx index aaf5aca35..5b0f4c9be 100644 --- a/packages/components/src/Form/tests/chromatic/Form.stories.tsx +++ b/packages/components/src/Form/tests/chromatic/Form.stories.tsx @@ -5,7 +5,6 @@ import { ComboBox, ComboBoxItem, Inline, - Label, Radio, RadioGroup, Select, @@ -13,7 +12,6 @@ import { Stack, Tag, TagGroup, - TagList, TextArea, TextField } from "@hopper-ui/components"; @@ -67,12 +65,9 @@ const Template = () => { Cat Frog - - - - Canada - US - + + Canada + US ); diff --git a/packages/components/src/tag/docs/TagGroup.stories.tsx b/packages/components/src/tag/docs/TagGroup.stories.tsx index a50a25346..a78c34895 100644 --- a/packages/components/src/tag/docs/TagGroup.stories.tsx +++ b/packages/components/src/tag/docs/TagGroup.stories.tsx @@ -6,16 +6,12 @@ import { useState } from "react"; import { RouterProvider, createMemoryRouter, useNavigate } from "react-router-dom"; import { Badge } from "../../Badge/index.ts"; -import { ErrorMessage } from "../../ErrorMessage/index.ts"; -import { HelperMessage } from "../../HelperMessage/index.ts"; import { HopperProvider } from "../../HopperProvider/index.ts"; import { IconList } from "../../IconList/index.ts"; import { Stack } from "../../layout/index.ts"; -import { Label } from "../../typography/Label/index.ts"; import { Text } from "../../typography/Text/index.ts"; import { Tag } from "../src/Tag.tsx"; import { TagGroup } from "../src/TagGroup.tsx"; -import { TagList } from "../src/TagList.tsx"; /** * The TagGroup is a dynamic UI component that encapsulates a collection of tags. @@ -49,11 +45,9 @@ type Story = StoryObj; export const Default = { render: props => ( - - Tag 1 - Tag 2 - Tag 3 - + Tag 1 + Tag 2 + Tag 3 ) } satisfies Story; @@ -77,11 +71,9 @@ export const RemovableTags = { export const LoadingTags = { render: props => ( - - Tag 1 - Tag 2 - Tag 3 - + Tag 1 + Tag 2 + Tag 3 ), args: { @@ -92,18 +84,15 @@ export const LoadingTags = { } satisfies Story; /** - * A TagGroup can have a Label to provide more context to the user. + * A TagGroup can have a label to provide more context to the user. */ export const LabelStory = { name: "Label", render: props => ( - - - Tag 1 - Tag 2 - Tag 3 - - + + Tag 1 + Tag 2 + Tag 3 ) } satisfies Story; @@ -115,25 +104,19 @@ export const Sizes = { render: props => ( - - Tag 1 - Tag 2 - Tag 3 - + Tag 1 + Tag 2 + Tag 3 - - Tag 1 - Tag 2 - Tag 3 - + Tag 1 + Tag 2 + Tag 3 - - Tag 1 - Tag 2 - Tag 3 - + Tag 1 + Tag 2 + Tag 3 ), @@ -150,49 +133,22 @@ export const Sizes = { export const Variants = { render: props => ( - - - Neutral - - - Subdued - - - Progress - - - Positive - - - Caution - - - Negative - - - Option 1 - - - Option 2 - - - Option 3 - - - Option 4 - - - Option 5 - - - Option 6 - - + Neutral + Subdued + Progress + Positive + Caution + Negative + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + Option 6 ) } satisfies Story; - /** * Tags can have icons. */ @@ -200,52 +156,46 @@ export const Icons = { render: props => ( - - + + + Developer + + + Designer + + - Developer - - - Designer - - - - - - - + + + - - + + + Developer + + + Designer + + - Developer - - - Designer - - - - - - - + + + - - + + + Developer + + + Designer + + - Developer - - - Designer - - - - - - - + + + ), @@ -256,7 +206,6 @@ export const Icons = { } } satisfies Story; - /** * Tags can also have a count using the `Badge` component. */ @@ -264,40 +213,34 @@ export const Count = { render: props => ( - - - Designer - 12 - - - Developer - 100 - - + + Designer + 12 + + + Developer + 100 + - - - Designer - 12 - - - Developer - 100 - - + + Designer + 12 + + + Developer + 100 + - - - 12 - Designer - - - Developer - 100 - - + + 12 + Designer + + + Developer + 100 + ) @@ -308,14 +251,10 @@ export const Count = { */ export const Description = { render: props => ( - - - - Earth - Mars - Jupiter - - The planets in this list are in no particular order. + + Earth + Mars + Jupiter ), args: { @@ -327,8 +266,6 @@ export const Description = { /** * Tags can be selected using the `selectionMode` prop. - * Use `defaultSelectedKeys` for initial selected items (uncontrolled) and `selectedKeys` to manage selected items (controlled). - * The selected keys should match the item's id prop. */ export const SelectableTags = { ...Description, @@ -340,7 +277,7 @@ export const SelectableTags = { } satisfies Story; /** - * Tags can be disabled using the `disabledKeys` prop or the `isDisabled` prop on the Tag component. + * Tags can be disabled using the `disabledKeys` prop. */ export const DisabledTags = { ...Description, @@ -351,8 +288,7 @@ export const DisabledTags = { } satisfies Story; /** - * If a TagGroup is invalid, it will display an error message. Displaying this error message will hide the helper message. - * A individual Tag can also be set as invalid using the `isInvalid` prop. + * If a TagGroup is invalid, it will display an error message. */ export const Validation = { args: { @@ -371,23 +307,15 @@ export const Validation = { return ( - - Unselect all to show the error message - Select a tag and the description will appear - - Tag 1 - Tag 2 - Tag 3 - - + + Tag 1 + Tag 2 + Tag 3 - - - - Tag 1 - Tag 2 - Tag 3 - + + Tag 1 + Tag 2 + Tag 3 ); @@ -400,32 +328,26 @@ export const Validation = { export const EmptyState = { render: props => ( - "No tags available"} - > - {[]} - + No tags available ) } satisfies Story; /** - * Tags can be links by using the `href` prop on the Tag component. Tags with an `href` are not selectable. + * Tags can be links by using the `href` prop on the Tag component. */ export const Links = { render: props => ( - - Google - Bing - Yahoo - + Google + Bing + Yahoo ) } satisfies Story; /** - * A Tag can be rendered as a react router link when using the href property, and setting the navigate property on the HopperProvider + * A Tag can be rendered as a react router link when using the href property, and setting the navigate property on the HopperProvider. */ export const ReactRouterLink: Story = { render: props => { @@ -435,30 +357,32 @@ export const ReactRouterLink: Story = { return ( - - Page 1 - Page 2 - Page 3 - + Page 1 + Page 2 + Page 3 ); }, decorators: [ Story => { - const router = createMemoryRouter([{ - path: "/123", - element:
Navigated Successfully to page 1!
- }, { - path: "/456", - element:
Navigated Successfully to page 2!
- }, { - path: "/789", - element:
Navigated Successfully to page 3!
- }, { - path: "*", - element: - } + const router = createMemoryRouter([ + { + path: "/123", + element:
Navigated Successfully to page 1!
+ }, + { + path: "/456", + element:
Navigated Successfully to page 2!
+ }, + { + path: "/789", + element:
Navigated Successfully to page 3!
+ }, + { + path: "*", + element: + } ]); return ( @@ -468,4 +392,3 @@ export const ReactRouterLink: Story = { ] }; - diff --git a/packages/components/src/tag/docs/migration-notes-tag-group.md b/packages/components/src/tag/docs/migration-notes-tag-group.md index 487866a28..63b000fbe 100644 --- a/packages/components/src/tag/docs/migration-notes-tag-group.md +++ b/packages/components/src/tag/docs/migration-notes-tag-group.md @@ -1,5 +1,4 @@ Coming from Orbiter, you should be aware of the following changes: -- `TagGroup` was renamed `TagList`. - `onClear` is not supported. - `validationState` is not supported. Use `isInvalid` instead, diff --git a/packages/components/src/tag/docs/migration-notes-tag-list.md b/packages/components/src/tag/docs/migration-notes-tag-list.md deleted file mode 100644 index 48afdf121..000000000 --- a/packages/components/src/tag/docs/migration-notes-tag-list.md +++ /dev/null @@ -1,3 +0,0 @@ -Coming from Orbiter, you should be aware of the following changes: - -- This is not the same as the previous TagList and should be treated as a new component. \ No newline at end of file diff --git a/packages/components/src/tag/docs/preview.tsx b/packages/components/src/tag/docs/preview.tsx index ce92e7a51..8f05d5edd 100644 --- a/packages/components/src/tag/docs/preview.tsx +++ b/packages/components/src/tag/docs/preview.tsx @@ -1,13 +1,11 @@ -import { Tag, TagGroup, TagList } from "@hopper-ui/components"; +import { Tag, TagGroup } from "@hopper-ui/components"; export default function Example() { return ( - - Designer - Developer - Manager - + Designer + Developer + Manager ); } diff --git a/packages/components/src/tag/docs/tag/avatar.tsx b/packages/components/src/tag/docs/tag/avatar.tsx index 87a351a97..65340efca 100644 --- a/packages/components/src/tag/docs/tag/avatar.tsx +++ b/packages/components/src/tag/docs/tag/avatar.tsx @@ -1,22 +1,20 @@ -import { TagGroup, Tag, TagList, Text, Avatar } from "@hopper-ui/components"; +import { Avatar, Tag, TagGroup, Text } from "@hopper-ui/components"; export default function Example() { return ( - - - - Frodo Baggin - - - - Karen Smith - - - John Smith - - - + + + Frodo Baggin + + + + Karen Smith + + + John Smith + + ); } diff --git a/packages/components/src/tag/docs/tag/count.tsx b/packages/components/src/tag/docs/tag/count.tsx index bcb379fb3..674b15795 100644 --- a/packages/components/src/tag/docs/tag/count.tsx +++ b/packages/components/src/tag/docs/tag/count.tsx @@ -1,22 +1,20 @@ -import { Badge, Tag, TagGroup, TagList, Text } from "@hopper-ui/components"; +import { Badge, Tag, TagGroup, Text } from "@hopper-ui/components"; export default function Example() { return ( - - - Designer - 12 - - - Developer - 100 - - - Manager - 99+ - - + + Designer + 12 + + + Developer + 100 + + + Manager + 99+ + ); } diff --git a/packages/components/src/tag/docs/tag/disabled.tsx b/packages/components/src/tag/docs/tag/disabled.tsx index fa5283aa5..e83b9f239 100644 --- a/packages/components/src/tag/docs/tag/disabled.tsx +++ b/packages/components/src/tag/docs/tag/disabled.tsx @@ -1,19 +1,17 @@ -import { Tag, TagGroup, TagList } from "@hopper-ui/components"; +import { Tag, TagGroup } from "@hopper-ui/components"; export default function Example() { return ( - - + Designer - - + + Designer - - + + Manager - - + ); } diff --git a/packages/components/src/tag/docs/tag/icons.tsx b/packages/components/src/tag/docs/tag/icons.tsx index 42d308fc5..bedd8f536 100644 --- a/packages/components/src/tag/docs/tag/icons.tsx +++ b/packages/components/src/tag/docs/tag/icons.tsx @@ -1,31 +1,29 @@ -import { IconList, Tag, TagGroup, TagList, Text } from "@hopper-ui/components"; +import { IconList, Tag, TagGroup, Text } from "@hopper-ui/components"; import { SparklesIcon } from "@hopper-ui/icons"; export default function Example() { return ( - - + + + Developer + + + Designer + - Developer - - - Designer - - - - - - - - Manager - - - - - - - + + + + + + Manager + + + + + + ); } diff --git a/packages/components/src/tag/docs/tag/invalid.tsx b/packages/components/src/tag/docs/tag/invalid.tsx index 849dbe255..fe426f034 100644 --- a/packages/components/src/tag/docs/tag/invalid.tsx +++ b/packages/components/src/tag/docs/tag/invalid.tsx @@ -1,19 +1,17 @@ -import { Tag, TagGroup, TagList } from "@hopper-ui/components"; +import { Tag, TagGroup } from "@hopper-ui/components"; export default function Example() { return ( - - + Designer - - + + Designer - - + + Manager - - + ); } diff --git a/packages/components/src/tag/docs/tag/links.tsx b/packages/components/src/tag/docs/tag/links.tsx index 654150b19..ac6a42510 100644 --- a/packages/components/src/tag/docs/tag/links.tsx +++ b/packages/components/src/tag/docs/tag/links.tsx @@ -1,13 +1,11 @@ -import { TagGroup, Tag, TagList } from "@hopper-ui/components"; +import { Tag, TagGroup } from "@hopper-ui/components"; export default function Example() { return ( - - Google - Bing - Yahoo - + Google + Bing + Yahoo ); } diff --git a/packages/components/src/tag/docs/tag/loading.tsx b/packages/components/src/tag/docs/tag/loading.tsx index c2d79c9c8..60f408882 100644 --- a/packages/components/src/tag/docs/tag/loading.tsx +++ b/packages/components/src/tag/docs/tag/loading.tsx @@ -1,4 +1,4 @@ -import { Tag, TagGroup, TagList, type Selection } from "@hopper-ui/components"; +import { Tag, TagGroup, type Selection } from "@hopper-ui/components"; export default function Example() { return ( @@ -8,11 +8,9 @@ export default function Example() { alert(`Remove: ${[...ids]}`); }} > - - Manager - Developer - Designer - + Manager + Developer + Designer
); } diff --git a/packages/components/src/tag/docs/tag/reactRouterLinks.tsx b/packages/components/src/tag/docs/tag/reactRouterLinks.tsx index bc87cd243..91cb4ff4b 100644 --- a/packages/components/src/tag/docs/tag/reactRouterLinks.tsx +++ b/packages/components/src/tag/docs/tag/reactRouterLinks.tsx @@ -1,4 +1,4 @@ -import { TagGroup, Tag, TagList, HopperProvider } from "@hopper-ui/components"; +import { HopperProvider, Tag, TagGroup } from "@hopper-ui/components"; import { createMemoryRouter, RouterProvider, useNavigate } from "react-router-dom"; export default function App() { @@ -25,10 +25,8 @@ function Example() { return ( - - Page 1 - Page 2 - + Page 1 + Page 2 ); diff --git a/packages/components/src/tag/docs/tag/sizes.tsx b/packages/components/src/tag/docs/tag/sizes.tsx index a00b61868..7efe05c44 100644 --- a/packages/components/src/tag/docs/tag/sizes.tsx +++ b/packages/components/src/tag/docs/tag/sizes.tsx @@ -1,13 +1,11 @@ -import { Tag, TagGroup, TagList } from "@hopper-ui/components"; +import { Tag, TagGroup } from "@hopper-ui/components"; export default function Example() { return ( - - Designer - Developer - Manager - + Designer + Developer + Manager ); } diff --git a/packages/components/src/tag/docs/tag/variants.tsx b/packages/components/src/tag/docs/tag/variants.tsx index a3c4351f2..3e8fe772a 100644 --- a/packages/components/src/tag/docs/tag/variants.tsx +++ b/packages/components/src/tag/docs/tag/variants.tsx @@ -1,47 +1,45 @@ -import { TagGroup, Tag, TagList, Div } from "@hopper-ui/components"; +import { Div, Tag, TagGroup } from "@hopper-ui/components"; export default function Example() { return (
- - + Neutral - - + + Subdued - - + + Progress - - + + Positive - - + + Caution - - + + Negative - - + + Option 1 - - + + Option 2 - - + + Option 3 - - + + Option 4 - - + + Option 5 - - + + Option 6 - - +
); diff --git a/packages/components/src/tag/docs/tagGroup/description.tsx b/packages/components/src/tag/docs/tagGroup/description.tsx index 47fd1a085..2eee93bd1 100644 --- a/packages/components/src/tag/docs/tagGroup/description.tsx +++ b/packages/components/src/tag/docs/tagGroup/description.tsx @@ -1,14 +1,11 @@ -import { HelperMessage, Tag, TagGroup, TagList } from "@hopper-ui/components"; +import { Tag, TagGroup } from "@hopper-ui/components"; export default function Example() { return ( - - - Designer - Developer - Manager - - The jobs in this list are in no particular order. + + Designer + Developer + Manager ); -} +} \ No newline at end of file diff --git a/packages/components/src/tag/docs/tagGroup/disabled.tsx b/packages/components/src/tag/docs/tagGroup/disabled.tsx index 3196baa4f..a89428503 100644 --- a/packages/components/src/tag/docs/tagGroup/disabled.tsx +++ b/packages/components/src/tag/docs/tagGroup/disabled.tsx @@ -1,13 +1,11 @@ -import { Tag, TagGroup, TagList } from "@hopper-ui/components"; +import { Tag, TagGroup } from "@hopper-ui/components"; export default function Example() { return ( - - Designer - Developer - Manager - + Designer + Developer + Manager ); } diff --git a/packages/components/src/tag/docs/tagGroup/empty.tsx b/packages/components/src/tag/docs/tagGroup/empty.tsx new file mode 100644 index 000000000..75fd08153 --- /dev/null +++ b/packages/components/src/tag/docs/tagGroup/empty.tsx @@ -0,0 +1,9 @@ +import { TagGroup } from "@hopper-ui/components"; + +export default function Example() { + return ( + "No jobs posting available"}> + {[]} + + ); +} diff --git a/packages/components/src/tag/docs/tagGroup/invalid.tsx b/packages/components/src/tag/docs/tagGroup/invalid.tsx index 3a39bfec0..2b1d7ed26 100644 --- a/packages/components/src/tag/docs/tagGroup/invalid.tsx +++ b/packages/components/src/tag/docs/tagGroup/invalid.tsx @@ -1,4 +1,4 @@ -import { ErrorMessage, HelperMessage, Tag, TagGroup, TagList, type Selection } from "@hopper-ui/components"; +import { Tag, TagGroup, type Selection } from "@hopper-ui/components"; import { useState } from "react"; export default function Example() { @@ -12,14 +12,17 @@ export default function Example() { } return ( - - - Designer - Developer - Manager - - Unselect all to show the error message - Select a job and the description will appear + + Designer + Developer + Manager ); } diff --git a/packages/components/src/tag/docs/tagGroup/label.tsx b/packages/components/src/tag/docs/tagGroup/label.tsx index d8c8270ac..d98a4127a 100644 --- a/packages/components/src/tag/docs/tagGroup/label.tsx +++ b/packages/components/src/tag/docs/tagGroup/label.tsx @@ -1,14 +1,11 @@ -import { Label, Tag, TagGroup, TagList } from "@hopper-ui/components"; +import { Tag, TagGroup } from "@hopper-ui/components"; export default function Example() { return ( - - - - Designer - Developer - Manager - + + Designer + Developer + Manager ); -} +} \ No newline at end of file diff --git a/packages/components/src/tag/docs/tagGroup/removable.tsx b/packages/components/src/tag/docs/tagGroup/removable.tsx index 12297d094..a73751770 100644 --- a/packages/components/src/tag/docs/tagGroup/removable.tsx +++ b/packages/components/src/tag/docs/tagGroup/removable.tsx @@ -1,4 +1,4 @@ -import { Tag, TagGroup, TagList, type Selection } from "@hopper-ui/components"; +import { Tag, TagGroup, type Selection } from "@hopper-ui/components"; export default function Example() { return ( @@ -8,11 +8,9 @@ export default function Example() { alert(`Remove: ${[...ids]}`); }} > - - Designer - Developer - Manager - + Designer + Developer + Manager ); } diff --git a/packages/components/src/tag/docs/tagGroup/selectable.tsx b/packages/components/src/tag/docs/tagGroup/selectable.tsx index 3cbf90338..6a6130434 100644 --- a/packages/components/src/tag/docs/tagGroup/selectable.tsx +++ b/packages/components/src/tag/docs/tagGroup/selectable.tsx @@ -1,13 +1,11 @@ -import { Tag, TagGroup, TagList } from "@hopper-ui/components"; +import { Tag, TagGroup } from "@hopper-ui/components"; export default function Example() { return ( - - Designer - Developer - Manager - + Designer + Developer + Manager ); } diff --git a/packages/components/src/tag/docs/tagGroup/sizes.tsx b/packages/components/src/tag/docs/tagGroup/sizes.tsx index b63d6b79f..b727aa56a 100644 --- a/packages/components/src/tag/docs/tagGroup/sizes.tsx +++ b/packages/components/src/tag/docs/tagGroup/sizes.tsx @@ -1,4 +1,4 @@ -import { Stack, Tag, TagGroup, TagList, type Selection } from "@hopper-ui/components"; +import { Stack, Tag, TagGroup, type Selection } from "@hopper-ui/components"; export default function Example() { const props = { @@ -7,13 +7,10 @@ export default function Example() { }, "aria-label": "Jobs", children: [ - ( - - Designer - Developer - Manager - - )] + Designer, + Developer, + Manager + ] }; return ( @@ -23,4 +20,4 @@ export default function Example() { ); -} +} \ No newline at end of file diff --git a/packages/components/src/tag/docs/tagGroup/variants.tsx b/packages/components/src/tag/docs/tagGroup/variants.tsx index 3ab4adf48..20f0e10ad 100644 --- a/packages/components/src/tag/docs/tagGroup/variants.tsx +++ b/packages/components/src/tag/docs/tagGroup/variants.tsx @@ -1,13 +1,11 @@ -import { Tag, TagGroup, TagList } from "@hopper-ui/components"; +import { Tag, TagGroup } from "@hopper-ui/components"; export default function Example() { return ( - - Designer - Developer - Manager - + Designer + Developer + Manager ); } diff --git a/packages/components/src/tag/docs/tagList/empty.tsx b/packages/components/src/tag/docs/tagList/empty.tsx deleted file mode 100644 index ab20e0055..000000000 --- a/packages/components/src/tag/docs/tagList/empty.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { TagGroup, TagList } from "@hopper-ui/components"; - -export default function Example() { - return ( - - "No jobs posting available"}> - {[]} - - - ); -} diff --git a/packages/components/src/tag/src/TagGroup.tsx b/packages/components/src/tag/src/TagGroup.tsx index 2a99a6128..9e2ec9f1f 100644 --- a/packages/components/src/tag/src/TagGroup.tsx +++ b/packages/components/src/tag/src/TagGroup.tsx @@ -5,42 +5,47 @@ import { useStyledSystem } from "@hopper-ui/styled-system"; import clsx from "clsx"; -import { type CSSProperties, type ForwardedRef, forwardRef } from "react"; +import { type CSSProperties, type ForwardedRef, forwardRef, type NamedExoticComponent } from "react"; import { + composeRenderProps, FieldErrorContext as RACFieldErrorContext, TagGroup as RACTagGroup, type TagGroupProps as RACTagGroupProps, + type TagListProps as RACTagListProps, + TagList, useContextProps } from "react-aria-components"; -import { ErrorMessageContext } from "../../ErrorMessage/index.ts"; -import { HelperMessageContext } from "../../HelperMessage/index.ts"; -import { LabelContext } from "../../typography/Label/index.ts"; -import { type NecessityIndicator, SlotProvider, cssModule } from "../../utils/index.ts"; +import { ErrorMessage } from "../../ErrorMessage/index.ts"; +import { HelperMessage } from "../../HelperMessage/index.ts"; +import { Label } from "../../typography/Label/index.ts"; +import { composeClassnameRenderProps, cssModule, type FieldProps, SlotProvider } from "../../utils/index.ts"; import type { TagSize, TagVariant } from "./Tag.tsx"; import { TagContext } from "./TagContext.ts"; import { TagGroupContext } from "./TagGroupContext.ts"; -import { TagListContext } from "./TagListContext.ts"; import styles from "./TagGroup.module.css"; export const GlobalTagGroupCssSelector = "hop-TagGroup"; -export interface TagGroupProps extends StyledComponentProps { +type ListProps = "items" | "children" | "renderEmptyState"; +export type TagListProps = StyledComponentProps, ListProps>>; + +export interface TagGroupProps extends StyledComponentProps>, Pick, ListProps>, Omit { /** * Whether the tags are invalid or not. */ isInvalid?: boolean; - /** - * Whether the required state should be shown as an asterisk or a label, which would display (Optional) on all non required field labels. - */ - necessityIndicator?: NecessityIndicator; /** * A tag can vary in size. * @default "md" */ size?: ResponsiveProp; + /** + * The tag list props + */ + tagListProps?: TagListProps; /** * The visual style of the TagGroup. * @default "neutral" @@ -48,21 +53,34 @@ export interface TagGroupProps extends StyledComponentProps { variant?: TagVariant; } -function TagGroup(props: TagGroupProps, ref: ForwardedRef) { +function TagGroup(props: TagGroupProps, ref: ForwardedRef) { [props, ref] = useContextProps(props, ref, TagGroupContext); const { stylingProps, ...ownProps } = useStyledSystem(props); const { className, children, + description, + errorMessage, isInvalid = false, + items, + label, necessityIndicator, + renderEmptyState, style: styleProp, size: sizeProp, + tagListProps, variant, ...otherProps } = ownProps; const size = useResponsiveValue(sizeProp) ?? "md"; + + const { stylingProps: tagListStylingProps, ...tagListOwnProps } = useStyledSystem(tagListProps ?? {}); + const { + className: tagListClassName, + style: tagListStyleProp, + ...otherTagListProps + } = tagListOwnProps; const classNames = clsx( className, @@ -75,35 +93,38 @@ function TagGroup(props: TagGroupProps, ref: ForwardedRef) { ) ); + const tagListClassNames = composeClassnameRenderProps( + tagListClassName, + cssModule( + styles, + "hop-TagGroup__list", + size + ), + tagListStylingProps.className + ); + const style: CSSProperties = { ...stylingProps.style, ...styleProp }; + const tagListStyle = composeRenderProps(tagListStyleProp, prev => { + return { + ...tagListStylingProps.style, + ...prev + }; + }); + + return ( ) { style={style} {...otherProps} > - {children} + {label && } + + {children} + + {description && {description}} + {errorMessage} ); @@ -128,7 +160,9 @@ function TagGroup(props: TagGroupProps, ref: ForwardedRef) { * * [View Documentation](TODO) */ -const _TagGroup = forwardRef(TagGroup); -_TagGroup.displayName = "TagGroup"; +const _TagGroup = forwardRef(TagGroup) as ( + props: TagGroupProps & { ref?: ForwardedRef } +) => ReturnType; +(_TagGroup as NamedExoticComponent).displayName = "TagGroup"; export { _TagGroup as TagGroup }; diff --git a/packages/components/src/tag/src/TagGroupContext.ts b/packages/components/src/tag/src/TagGroupContext.ts index 210755901..2150b59d5 100644 --- a/packages/components/src/tag/src/TagGroupContext.ts +++ b/packages/components/src/tag/src/TagGroupContext.ts @@ -3,6 +3,8 @@ import type { ContextValue } from "react-aria-components"; import type { TagGroupProps } from "./TagGroup.tsx"; -export const TagGroupContext = createContext>({}); +// any is used in spectrum +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const TagGroupContext = createContext, HTMLDivElement>>({}); TagGroupContext.displayName = "TagGroupContext"; diff --git a/packages/components/src/tag/src/TagList.tsx b/packages/components/src/tag/src/TagList.tsx deleted file mode 100644 index bec8c80ca..000000000 --- a/packages/components/src/tag/src/TagList.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { type StyledComponentProps, useStyledSystem } from "@hopper-ui/styled-system"; -import { type ForwardedRef, forwardRef } from "react"; -import { TagList as RACTagList, type TagListProps as RACTagListProps, composeRenderProps, useContextProps } from "react-aria-components"; - -import { composeClassnameRenderProps } from "../../utils/index.ts"; - -import { TagListContext } from "./TagListContext.ts"; - -export const GlobalTagListCssSelector = "hop-TagList"; - -export interface TagListProps extends StyledComponentProps> {} - -function TagList(props: TagListProps, ref: ForwardedRef) { - [props, ref] = useContextProps(props, ref, TagListContext); - const { stylingProps, ...ownProps } = useStyledSystem(props); - const { - className, - children, - style: styleProp, - ...otherProps - } = ownProps; - - const classNames = composeClassnameRenderProps( - className, - GlobalTagListCssSelector, - "hop-TagList", - stylingProps.className - ); - - const style = composeRenderProps(styleProp, prev => { - return { - ...stylingProps.style, - ...prev - }; - }); - - return ( - - {children} - - ); -} - -/** - * A versatile TagList component for categorizing items in a TagListList, equipped with a remove button for easy management. - * - * [View Documentation](TODO) - */ -const _TagList = forwardRef>(TagList); -_TagList.displayName = "TagList"; - -export { _TagList as TagList }; diff --git a/packages/components/src/tag/src/TagListContext.ts b/packages/components/src/tag/src/TagListContext.ts deleted file mode 100644 index 9fad1252c..000000000 --- a/packages/components/src/tag/src/TagListContext.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { createContext } from "react"; -import type { ContextValue } from "react-aria-components"; - -import type { TagListProps } from "./TagList.tsx"; - -export const TagListContext = createContext, HTMLDivElement>>({}); - -TagListContext.displayName = "TagListContext"; diff --git a/packages/components/src/tag/src/index.ts b/packages/components/src/tag/src/index.ts index d7732e432..728a115a8 100644 --- a/packages/components/src/tag/src/index.ts +++ b/packages/components/src/tag/src/index.ts @@ -1,6 +1,5 @@ export * from "./Tag.tsx"; -export * from "./TagList.tsx"; -export * from "./TagGroup.tsx"; export * from "./TagContext.ts"; -export * from "./TagListContext.ts"; +export * from "./TagGroup.tsx"; export * from "./TagGroupContext.ts"; + diff --git a/packages/components/src/tag/tests/chromatic/TagGroup.stories.tsx b/packages/components/src/tag/tests/chromatic/TagGroup.stories.tsx index 718e43654..e56d301d5 100644 --- a/packages/components/src/tag/tests/chromatic/TagGroup.stories.tsx +++ b/packages/components/src/tag/tests/chromatic/TagGroup.stories.tsx @@ -7,8 +7,8 @@ import { Avatar } from "../../../Avatar/index.ts"; import { Badge } from "../../../Badge/index.ts"; import { IconList } from "../../../IconList/index.ts"; import { Stack } from "../../../layout/index.ts"; -import { Label, Text } from "../../../typography/index.ts"; -import { Tag, TagGroup, TagList, type TagGroupProps } from "../../src/index.ts"; +import { Text } from "../../../typography/index.ts"; +import { Tag, TagGroup, type TagGroupProps } from "../../src/index.ts"; const meta = { title: "Components/TagGroup", @@ -23,31 +23,22 @@ export const Default = { render: props => { return ( - - - - Tag 1 - Tag 2 - Tag 3 with long text - + + Tag 1 + Tag 2 + Tag 3 with long text - - - - Tag 1 - Tag 2 - Tag 3 with long text - + + Tag 1 + Tag 2 + Tag 3 with long text - - - - Tag 1 - Tag 2 - Tag 3 with long text - + + Tag 1 + Tag 2 + Tag 3 with long text ); @@ -58,80 +49,71 @@ export const Icons = { render: props => { return ( - - - - + + + + Developer + + + Designer + + + + + + + + Executive Officer + - Developer - - - Designer - - - - - - - - Executive Officer - - - - - - - + + + + - - - - + + + + Developer + + + Designer + + - Developer - - - Designer - - - - - - - - Executive Officer - - - - - - - + + + + + Executive Officer + + + + + + - - - - + + + + Developer + + + Designer + + + + + + + + Executive Officer + - Developer - - - Designer - - - - - - - - Executive Officer - - - - - - - + + + + ); @@ -143,56 +125,47 @@ export const AvatarStory = { render: props => { return ( - - - - - - Frodo Baggin - - - - Karen Smith - - - John Smith - - - + + + + Frodo Baggin + + + + Karen Smith + + + John Smith + + - - - - - - Frodo Baggin - - - - Karen Smith - - - John Smith - - - + + + + Frodo Baggin + + + + Karen Smith + + + John Smith + + - - - - - - Frodo Baggin - - - - Karen Smith - - - John Smith - - - + + + + Frodo Baggin + + + + Karen Smith + + + John Smith + + ); @@ -203,263 +176,53 @@ export const Count = { render: props => { return ( - - - - - 12 - Developer - - - Designer - 99+ - - - Executive Officer - 100 - - - - - - - - 12 - Developer - - - Designer - 99+ - - - Executive Officer - 100 - - - - - - - - 12 - Developer - - - Designer - 99+ - - - Executive Officer - 100 - - - - - ); - }, - args: { - selectionMode: "multiple" - } -} satisfies Story; - -export const Loading = { - render: props => { - return ( - - - - - Neutral - - 99+ - - - Subdued - - 99+ - - - Progress - - 99+ - - - Positive - - 99+ - - - Caution - - 99+ - - - Negative - - 99+ - - - Option1 - - 99+ + + + 12 + Developer - - Option2 - - 99+ - - - Option3 - - 99+ - - - Option4 - - 99+ - - - Option5 - + + Designer 99+ - - Option6 - - 99+ + + Executive Officer + 100 - - - - - Neutral - - 99+ - - - Subdued - - 99+ - - - Progress - - 99+ - - - Positive - - 99+ + + + 12 + Developer - - Caution - - 99+ - - - Negative - - 99+ - - - Option1 - - 99+ - - - Option2 - - 99+ - - - Option3 - - 99+ - - - Option4 - - 99+ - - - Option5 - + + Designer 99+ - - Option6 - - 99+ + + Executive Officer + 100 - - - - - Neutral - - 99+ + + + 12 + Developer - - Subdued - + + Designer 99+ - - Progress - - 99+ - - - Positive - - 99+ - - - Caution - - 99+ - - - Negative - - 99+ - - - Option1 - - 99+ - - - Option2 - - 99+ - - - Option3 - - 99+ - - - Option4 - - 99+ + + Executive Officer + 100 - - Option5 - - 99+ - - - Option6 - - 99+ - - ); + }, + args: { + selectionMode: "multiple" } } satisfies Story; @@ -467,113 +230,86 @@ export const Invalid = { render: props => { return ( - - - - Developer - Designer - + + Developer + Designer - - - - Developer - Designer - + + Developer + Designer - - - - Developer - Designer - + + Developer + Designer ); } } satisfies Story; -export const Removable = { - ...Default, - args: { - onRemove: (ids: Selection) => { - alert(`Remove: ${[...ids]}`); - } - } -} satisfies Story; - export const Everything = { render: props => { return ( - - - - - - 12 - - Frodo Baggins - - - - Karen Smith - - 99+ - - - - John Smith - - 100 - - + + + + 12 + + Frodo Baggins + + + + Karen Smith + + 99+ + + + + John Smith + + 100 + - - - - - - 12 - - Frodo Baggins - - - - Karen Smith - - 99+ - - - - John Smith - - 100 - - + + + + 12 + + Frodo Baggins + + + + Karen Smith + + 99+ + + + + John Smith + + 100 + - - - - - - 12 - - Frodo Baggins - - - - Karen Smith - - 99+ - - - - John Smith - - 100 - - + + + + 12 + + Frodo Baggins + + + + Karen Smith + + 99+ + + + + John Smith + + 100 + ); @@ -585,71 +321,69 @@ export const Everything = { } } satisfies Story; -const StateTemplate = (args: Partial) => ( +const StateTemplate = (args: Partial>) => ( - - - Neutral - - 99+ - - - Subdued - - 99+ - - - Progress - - 99+ - - - Positive - - 99+ - - - Caution - - 99+ - - - Negative - - 99+ - - - Option1 - - 99+ - - - Option2 - - 99+ - - - Option3 - - 99+ - - - Option4 - - 99+ - - - Option5 - - 99+ - - - Option6 - - 99+ - - + + Neutral + + 99+ + + + Subdued + + 99+ + + + Progress + + 99+ + + + Positive + + 99+ + + + Caution + + 99+ + + + Negative + + 99+ + + + Option1 + + 99+ + + + Option2 + + 99+ + + + Option3 + + 99+ + + + Option4 + + 99+ + + + Option5 + + 99+ + + + Option6 + + 99+ + ); @@ -661,7 +395,7 @@ export const DefaultStates: Story = { tagGroups.forEach(tagGroup => { const tags = tagGroup.querySelectorAll(".hop-Tag"); tags.forEach(tag => { - if (!tag.getAttribute("data-disabled")) { // don't try and force states on a disabled tags + if (!tag.getAttribute("data-disabled")) { if (tagGroup.getAttribute("data-chromatic-force-focus")) { tag.setAttribute("data-focus-visible", "true"); } @@ -707,4 +441,4 @@ export const DefaultStates: Story = { }, selectionMode: "multiple" } -}; +}; \ No newline at end of file diff --git a/packages/components/src/tag/tests/jest/TagGroup.ssr.test.tsx b/packages/components/src/tag/tests/jest/TagGroup.ssr.test.tsx index 5f4728df8..55d35b452 100644 --- a/packages/components/src/tag/tests/jest/TagGroup.ssr.test.tsx +++ b/packages/components/src/tag/tests/jest/TagGroup.ssr.test.tsx @@ -3,18 +3,16 @@ */ import { renderToString } from "react-dom/server"; -import { Tag, TagGroup, TagList } from "../../index.ts"; +import { Tag, TagGroup } from "../../index.ts"; describe("TagGroup", () => { it("should render on the server", () => { const renderOnServer = () => renderToString( - - Tag 1 - Tag 2 - Tag 3 - + Tag 1 + Tag 2 + Tag 3 ); diff --git a/packages/components/src/tag/tests/jest/TagGroup.test.tsx b/packages/components/src/tag/tests/jest/TagGroup.test.tsx index 8be967ce9..21d8edf4e 100644 --- a/packages/components/src/tag/tests/jest/TagGroup.test.tsx +++ b/packages/components/src/tag/tests/jest/TagGroup.test.tsx @@ -1,18 +1,18 @@ import { render, screen } from "@hopper-ui/test-utils"; import { createRef } from "react"; -import { Tag, TagGroupContext, TagList, TagGroup } from "../../src/index.ts"; +import { Tag, TagGroup, TagGroupContext } from "../../src/index.ts"; describe("Tag", () => { it("should render with default class", () => { - render(option 1); + render(option 1); const element = screen.getByTestId("tag-group"); expect(element).toHaveClass("hop-TagGroup"); }); it("should support custom class", () => { - render(option 1); + render(option 1); const element = screen.getByTestId("tag-group"); expect(element).toHaveClass("hop-TagGroup"); @@ -20,14 +20,14 @@ describe("Tag", () => { }); it("should support custom style", () => { - render(option 1); + render(option 1); const element = screen.getByTestId("tag-group"); expect(element).toHaveStyle({ marginTop: "var(--hop-space-stack-sm)", marginBottom: "13px" }); }); it("should support DOM props", () => { - render(option 1); + render(option 1); const element = screen.getByTestId("tag-group"); expect(element).toHaveAttribute("data-foo", "bar"); @@ -36,12 +36,16 @@ describe("Tag", () => { it("should support slots", () => { render( - option 1 + + option 1 + ); const element = screen.getByTestId("tag-group"); - const tagList = screen.getByTestId("tag-list"); + const tagList = screen.getByRole("grid"); expect(element).toHaveAttribute("slot", "test"); expect(tagList).toHaveAttribute("aria-label", "test"); @@ -49,23 +53,29 @@ describe("Tag", () => { it("should support refs", () => { const ref = createRef(); - render(option 1); + render( + option 1 + ); expect(ref.current).not.toBeNull(); expect(ref.current instanceof HTMLDivElement).toBeTruthy(); }); - it("should set the size class name and pass the size to the radio and radio field.", () => { - const testId = "radio-field"; - render( - + it("should set the size class name and pass the size to the tag.", () => { + const testId = "tag-option"; + render( + option 1 - - ); + + ); const element = screen.getByTestId("tag-group"); - const radio = screen.getByTestId(testId); + const tag = screen.getByTestId(testId); expect(element).toHaveClass("hop-TagGroup--lg"); - expect(radio).toHaveClass("hop-Tag--lg"); + expect(tag).toHaveClass("hop-Tag--lg"); }); -}); +}); \ No newline at end of file