Skip to content

Commit

Permalink
Merge pull request #54 from atomicjolt/sc/build-fixes
Browse files Browse the repository at this point in the history
Fixed TS builds
  • Loading branch information
seanrcollings authored Dec 3, 2024
2 parents cf6954d + 61be30c commit 4a25158
Show file tree
Hide file tree
Showing 69 changed files with 1,148 additions and 590 deletions.
5 changes: 5 additions & 0 deletions .changeset/curvy-pans-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@atomicjolt/atomic-elements": major
---

Implemented a Composition API for the Calendar component
5 changes: 5 additions & 0 deletions .changeset/dull-wolves-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@atomicjolt/atomic-elements": major
---

Implemented ChipGroupField using the new Collections API & re-implemented ChipGroup & Chip on top of that base
4 changes: 1 addition & 3 deletions packages/atomic-elements/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,11 @@ $ yarn add @atomicjolt/atomic-elements
Include the following in your project

```js
import { LoadFonts, CssVariables, CssGlobalDefaults } from "@atomicjolt/atomic-elements";
import { CssVariables } from "@atomicjolt/atomic-elements";

const App = () => (
<>
<LoadFonts />
<CssVariables />
<CssGlobalDefaults />
<YourApp />
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useRef } from "react";
import { useAnnouncer } from "../LiveAnnouncer";
import { useContextPropsV2 } from "@hooks/useContextProps";
import { useContextProps } from "@hooks/useContextProps";
import { LiveMessageContext } from "./LiveMessage.context";

export interface LiveMessageProps {
Expand All @@ -19,7 +19,7 @@ export interface LiveMessageProps {
*/
export function LiveMessage(props: LiveMessageProps) {
let ref = useRef<HTMLDivElement>(null);
[props, ref] = useContextPropsV2(LiveMessageContext, props, ref);
[props, ref] = useContextProps(LiveMessageContext, props, ref);

const { message, polite = true, assertive = false, timeout } = props;
const { announceAssertive, announcePolite } = useAnnouncer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { mergeProps, useObjectRef } from "@react-aria/utils";
import { SpinnerLoader } from "../../Loaders/SpinnerLoader";
import {
ExtendedSize,
HasIcon,
HasVariant,
LoadingProps,
RenderBaseProps,
Expand All @@ -14,9 +13,10 @@ import {
import { useFocusRing } from "@hooks/useFocusRing";
import { useRenderProps } from "@hooks/useRenderProps";
import { useButtonLink } from "@hooks/useButtonLink";
import { useContextPropsV2 } from "@hooks/useContextProps";
import { useContextProps } from "@hooks/useContextProps";
import { StyledButton } from "./Button.styles";
import { ButtonContext } from "./Button.context";
import { SlotProps } from "@hooks/useSlottedContext";

export type ButtonVariants = SuggestStrings<
| "primary"
Expand All @@ -41,7 +41,8 @@ export interface ButtonProps
extends AriaButtonOptions<"button">,
LoadingProps,
RenderBaseProps<ButtonRenderProps>,
HasVariant<ButtonVariants> {
HasVariant<ButtonVariants>,
SlotProps {
as?: "button" | "a";
size?: ExtendedSize;
}
Expand All @@ -52,12 +53,7 @@ export interface ButtonProps
*/
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
function Button(props, forwardedRef) {
[props, forwardedRef] = useContextPropsV2(
ButtonContext,
// Button doesn't have Icon props, but the context does
props as ButtonProps & HasIcon,
forwardedRef
);
[props, forwardedRef] = useContextProps(ButtonContext, props, forwardedRef);

const ref = useObjectRef(forwardedRef);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React from "react";
import { ButtonProps } from ".";
import { createComponentContext } from "@utils/index";
import { HasIcon } from '../../../types';
import { CanHaveIcon } from '../../../types';

export const ButtonContext = createComponentContext<
ButtonProps & HasIcon
ButtonProps & CanHaveIcon
>();
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { HasIcon } from "../../../types";
import { MaterialIcon } from "../../Icons/MaterialIcon";
import { StyledIconButton } from "./IconButton.styles";
import { ButtonProps } from "../Button";
import { useContextPropsV2 } from "@hooks/useContextProps";
import { useContextProps } from "@hooks/useContextProps";
import { ButtonContext } from "../Button/Button.context";

export interface IconButtonProps
Expand All @@ -17,8 +17,8 @@ export interface IconButtonProps
* */
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
function IconButton(props, forwardedRef) {
[props, forwardedRef] = useContextPropsV2(
ButtonContext,
[props, forwardedRef] = useContextProps(
ButtonContext as any,
props,
forwardedRef
);
Expand Down
150 changes: 91 additions & 59 deletions packages/atomic-elements/src/components/Chips/Chip/Chip.component.tsx
Original file line number Diff line number Diff line change
@@ -1,98 +1,130 @@
import React from "react";
import classNames from "classnames";
import type { ItemProps } from "react-stately";
import { PressEvent, PressProps } from "@react-aria/interactions";
import { AriaButtonProps } from "@react-aria/button";
import { mergeProps } from "@react-aria/utils";
import React, { useContext } from "react";
import { filterDOMProps, mergeProps, useObjectRef } from "@react-aria/utils";
import { useTag } from "@react-aria/tag";
import { createLeafComponent } from "@react-aria/collections";

import { copyStaticProperties } from "@utils/clone";
import { useVariantClass } from "@hooks/variants";
import { Item } from "@components/Collection";
import { IconButton } from "@components/Buttons/IconButton";
import { useConditionalPress } from "@hooks/useConditionalPress";
import { useFocusRing } from "@hooks/useFocusRing";
import { useContextProps } from "@hooks/useContextProps";
import { useRenderProps } from "@hooks";
import { ChipGroupStateContext } from "@components/Fields/ChipGroupField/ChipGroupField.context";

import { ChipArgs, ChipGroupChipProps, ChipInternalProps } from "./Chip.types";
import { ChipContent, ChipWrapper } from "./Chip.styles";
import { SuggestStrings, HasClassName } from "../../../types";
import { ChipContext } from "./Chip.context";

type ChipVariants = SuggestStrings<
"default" | "warning" | "success" | "danger"
>;
export function ChipLeaf<T>(...args: ChipArgs<T>) {
const [props, ref] = useContextProps(ChipContext, args[0], args[1]);

export interface ChipProps<T> extends ItemProps<T>, PressProps, HasClassName {
children: React.ReactNode;
variant?: ChipVariants;
/** Handler that is called when the user
* clicks the remove button for the chip */
onRemove?: (e: PressEvent) => void;
isDisabled?: boolean;
}
// We're being rendered standalone
if (args.length === 2) {
return (
<ChipInternal {...props} ref={ref} allowsRemoving={!!props.onRemove} />
);
}

/** Chip component */
export function Chip<T>(props: ChipProps<T>) {
return <ChipInternal {...props} allowsRemoving={!!props.onRemove} />;
// We're being rendered as part of a collection (i.e ChipGroup)
const item = args[2];
return <ChipGroupChip item={item} itemRef={ref} {...props} />;
}

copyStaticProperties(Item, Chip);
/**
* Chip component. Can be used stand-alone, or within a parent
* `ChipGroup`
*/
export const Chip = createLeafComponent("item", ChipLeaf);

function ChipGroupChip<T>(props: ChipGroupChipProps<T>) {
const { item } = props;
const ref = useObjectRef<HTMLDivElement>(props.itemRef);
const state = useContext(ChipGroupStateContext)!;
const {
rowProps,
gridCellProps,
removeButtonProps,
allowsRemoving,
isFocused,
isSelected,
} = useTag(props, state, ref);

const { focusProps, isFocusVisible } = useFocusRing({ within: true });

const isDisabled = state.disabledKeys.has(item.key);

interface ChipInternalProps<T> extends ChipProps<T> {
wrapperProps?: React.DOMAttributes<HTMLDivElement>;
contentProps?: React.DOMAttributes<HTMLDivElement>;
removeButtonProps?: AriaButtonProps<"button">;
allowsRemoving?: boolean;
const renderProps = useRenderProps({
componentClassName: "aje-chip",
values: {
isSelected,
isFocusVisible,
isFocused,
},
...props,
});

return (
<ChipWrapper
ref={ref}
{...mergeProps(rowProps, focusProps)}
{...renderProps}
>
<ChipContent {...gridCellProps}>
{renderProps.children}
{allowsRemoving && (
<IconButton
icon="close"
size="small"
variant="chip"
{...mergeProps(removeButtonProps, { isDisabled })}
/>
)}
</ChipContent>
</ChipWrapper>
);
}

export const ChipInternal = React.forwardRef<
HTMLDivElement,
ChipInternalProps<any>
>(function ChipInternal<T>(
export const ChipInternal = React.forwardRef(function ChipInternal<T>(
props: ChipInternalProps<T>,
ref: React.Ref<HTMLDivElement>
) {
const {
className,
variant = "default",
variant,
onRemove,
isDisabled,
children,
wrapperProps = {},
contentProps = {},
removeButtonProps = {},
allowsRemoving = false,
...rest
} = props;

const variantClass = useVariantClass("aje-chip", variant);
const { pressProps } = useConditionalPress(rest);

const allWrapperProps = [
wrapperProps,
{ "aria-disabled": isDisabled || undefined },
];

if (!isDisabled) {
allWrapperProps.push(pressProps);
}
const renderProps = useRenderProps({
componentClassName: "aje-chip",
values: {
isSelected: false,
isFocusVisible: false,
isFocused: false,
},
...props,
});

return (
<ChipWrapper
className={classNames("aje-chip", variantClass, className)}
ref={ref}
{...mergeProps(...allWrapperProps)}
{...mergeProps({ "aria-disabled": isDisabled || undefined }, pressProps)}
{...renderProps}
{...filterDOMProps(props as any)}
>
<ChipContent {...contentProps}>
{children}

<ChipContent>
{renderProps.children}
{allowsRemoving && (
<IconButton
icon="close"
size="small"
variant="chip"
{...mergeProps(
{
isDisabled,
onPress: onRemove,
},
removeButtonProps
)}
isDisabled={isDisabled}
onPress={onRemove}
/>
)}
</ChipContent>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { createComponentContext } from "@utils/index";
import { ChipProps } from "./Chip.types";

export const ChipContext = createComponentContext<ChipProps<any>>();
11 changes: 9 additions & 2 deletions packages/atomic-elements/src/components/Chips/Chip/Chip.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { render } from "@testing-library/react";
import { expect, describe, test } from "vitest";
import { fireEvent, render, screen } from "@testing-library/react";
import { expect, describe, test, vi } from "vitest";
import { Chip } from ".";

describe("Chip", () => {
test("matches snapshot", () => {
const result = render(<Chip>Item</Chip>);
expect(result.asFragment()).toMatchSnapshot();
});

test("onRemove", () => {
const onRemove = vi.fn();
render(<Chip onRemove={onRemove}>Item</Chip>);
fireEvent.click(screen.getByRole("button"));
expect(onRemove).toHaveBeenCalledOnce();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ export default {
category: "Events",
},
},
onAction: {
table: {
disable: true,
},
},
},
} as Meta<typeof Chip>;

Expand Down
29 changes: 29 additions & 0 deletions packages/atomic-elements/src/components/Chips/Chip/Chip.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Node } from "react-stately";
import { AriaLabelProps, DomProps, SuggestStrings } from "../../../types";
import { PressEvent, PressProps } from "@react-aria/interactions";
import { ItemProps } from "../../Collection";

type ChipVariants = SuggestStrings<
"default" | "warning" | "success" | "danger"
>;

export interface ChipProps<T> extends ItemProps, PressProps {
variant?: ChipVariants;
/** Handler that is called when the user
* clicks the remove button for the chip */
onRemove?: (e: PressEvent) => void;
isDisabled?: boolean;
}

export type ChipArgs<T> =
| [ChipProps<T>, React.ForwardedRef<HTMLDivElement>]
| [ChipProps<T>, React.ForwardedRef<HTMLDivElement>, Node<T>];

export interface ChipGroupChipProps<T> extends ChipProps<T> {
item: Node<T>;
itemRef: React.ForwardedRef<HTMLDivElement>;
}

export interface ChipInternalProps<T> extends ChipProps<T> {
allowsRemoving?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
exports[`Chip > matches snapshot 1`] = `
<DocumentFragment>
<div
class="sc-keTIit ia-dvfO aje-chip aje-chip--default"
class="sc-keTIit ia-dvfO aje-chip"
>
<div
class="sc-dstKZu gTCzyn"
Expand Down
4 changes: 2 additions & 2 deletions packages/atomic-elements/src/components/Chips/Chip/index.tsx
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { Chip, ChipInternal } from "./Chip.component";
export type { ChipProps } from "./Chip.component";
export { Chip, ChipLeaf } from "./Chip.component";
export type { ChipProps } from "./Chip.types";
Loading

0 comments on commit 4a25158

Please sign in to comment.