Skip to content

Commit

Permalink
feat(corner-ornament): adds new component for corner ornament (#4009)
Browse files Browse the repository at this point in the history
* feat(corner-ornament): initial WIP

* feat(corner-ornament): refactor of masking paths in element

* feat(corner-ornament): updated stories

* feat(corner-ornament): tweaks

* feat(corner-ornament): stories ad size mappings

* feat(corner-ornament): stories

* feat(corner-ornament): tests

* feat(corner-ornament): refactor masks for string

* feat(corner-ornament): lint & typedoc

* feat(corner-ornament): changeset

* feat(corner-ornament): changeset

* feat(corner-ornament): remove unused assets

* feat(corner-ornament): types update

* feat(corner-ornament): update package description

* feat(corner-ornament): yarn lock

* Update packages/paste-core/components/corner-ornament/package.json

Co-authored-by: Nora Krantz <75342690+nkrantz@users.noreply.github.com>

* feat(corner-ornament): pr comments

* feat(corner-ornament): mappings refactor

* feat(corner-ornament): mapping tweaks

* feat(corner-ornament): mapping tweaks

* feat(corner-ornament): codemods

* feat(corner-ornament): formatter

* feat(corner-ornament): linting

* feat(corner-ornament): remove unused files

* feat(corner-ornament): corner ornament rename

* feat(corner-ornament): typedocs

* feat(tokens): added
colorTextIconNotification

* feat(icons): added
NotificationOrnamentIcon

* feat(type-docs): updated component typedocs to change in design token

* feat(corner-ornament): updated dot for icon

* feat(corner-ornament): initial WIP

* feat(corner-ornament): refactor of masking paths in element

* feat(corner-ornament): updated stories

* feat(corner-ornament): tweaks

* feat(corner-ornament): stories ad size mappings

* feat(corner-ornament): stories

* feat(corner-ornament): tests

* feat(corner-ornament): refactor masks for string

* feat(corner-ornament): lint & typedoc

* feat(corner-ornament): changeset

* feat(corner-ornament): changeset

* feat(corner-ornament): remove unused assets

* feat(corner-ornament): types update

* feat(corner-ornament): update package description

* feat(corner-ornament): yarn lock

* Update packages/paste-core/components/corner-ornament/package.json

Co-authored-by: Nora Krantz <75342690+nkrantz@users.noreply.github.com>

* feat(corner-ornament): pr comments

* feat(corner-ornament): mappings refactor

* feat(corner-ornament): mapping tweaks

* feat(corner-ornament): mapping tweaks

* feat(corner-ornament): codemods

* feat(corner-ornament): formatter

* feat(corner-ornament): linting

* feat(corner-ornament): remove unused files

* feat(corner-ornament): corner ornament rename

* feat(corner-ornament): typedocs

* feat(tokens): added
colorTextIconNotification

* feat(icons): added
NotificationOrnamentIcon

* feat(type-docs): updated component typedocs to change in design token

* feat(corner-ornament): updated dot for icon

* feat(icons): added
NotificationOrnamentIcon

* feat(corner-ornament): pr issues

* fix(corner-ornament): formatting issue

* fix(corner-ornament): icon tests

* Update packages/paste-core/components/corner-ornament/src/CornerOrnament.tsx

Co-authored-by: Sarah <sali@twilio.com>

* feat(corner-ornament): new path mappings

* feat(corner-ornament): updated ornament positions

* feat(corner-ornament): final impl

* feat(corner-ornament): avatar mapping fix

* feat(corner-ornament): story type and badge base to icon

---------

Co-authored-by: Nora Krantz <75342690+nkrantz@users.noreply.github.com>
Co-authored-by: Sarah <sali@twilio.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
4 people committed Aug 6, 2024
1 parent 300c6c2 commit d3d74e5
Show file tree
Hide file tree
Showing 37 changed files with 6,461 additions and 6 deletions.
6 changes: 6 additions & 0 deletions .changeset/giant-spiders-remember.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@twilio-paste/core": minor
"@twilio-paste/design-tokens": minor
---

[Design Tokens] added a new text color for notification icons "colorTextIconNotification"
6 changes: 6 additions & 0 deletions .changeset/sharp-sloths-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@twilio-paste/core": minor
"@twilio-paste/icons": minor
---

[Icons] Added new Icon NotificationOrnamentIcon for use in Corner Ornament Component
5 changes: 5 additions & 0 deletions .changeset/smart-berries-play.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@twilio-paste/codemods": minor
---

[Corner Ornament] Release a new component that controls the posiitoning of another elements in relation to a parent component to be displayed as a corner ornament
6 changes: 6 additions & 0 deletions .changeset/warm-snakes-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@twilio-paste/corner-ornament": major
"@twilio-paste/core": minor
---

[Corner Ornament] Release a new component that controls the posiitoning of another elements in relation to a parent component to be displayed as a corner ornament
1 change: 1 addition & 0 deletions .codesandbox/ci.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"/packages/paste-color-contrast-utils",
"/packages/paste-core/components/combobox",
"/packages/paste-core/primitives/combobox",
"/packages/paste-core/components/corner-ornament",
"/packages/paste-customization",
"/packages/paste-core/components/data-grid",
"/packages/paste-libraries/data-visualization",
Expand Down
5 changes: 5 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ module.exports = {
"error_counter",
"neutral_counter",
"notification_counter",
// these are position names we use as keys in style objects
"top_end",
"top_start",
"bottom_end",
"bottom_start",
// unstable props are allowed
"^unstable_",
// this is a temporary prop, if the console patch is removed from components this can be removed too
Expand Down
3 changes: 3 additions & 0 deletions packages/paste-codemods/tools/.cache/mappings.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@
"MultiselectCombobox": "@twilio-paste/core/combobox",
"useCombobox": "@twilio-paste/core/combobox",
"useMultiselectCombobox": "@twilio-paste/core/combobox",
"CornerOrnament": "@twilio-paste/core/corner-ornament",
"CornerOrnamentBase": "@twilio-paste/core/corner-ornament",
"CornerOrnamentContainer": "@twilio-paste/core/corner-ornament",
"DataGrid": "@twilio-paste/core/data-grid",
"DataGridBody": "@twilio-paste/core/data-grid",
"DataGridCell": "@twilio-paste/core/data-grid",
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { render } from "@testing-library/react";
import { Avatar } from "@twilio-paste/avatar";
import { Box } from "@twilio-paste/box";
import { LogoTwilioIcon } from "@twilio-paste/icons/esm/LogoTwilioIcon";
import { IconSizeOptions } from "@twilio-paste/style-props";
import * as React from "react";

import { CornerOrnament, CornerOrnamentBase, CornerOrnamentContainer } from "../src";
import { CornerOrnamentType } from "../src/types";

const ExampleCornerOrnament: React.FC<{
size?: IconSizeOptions;
type?: CornerOrnamentType;
element?: string;
}> = ({ size, type, element }) => (
<CornerOrnamentContainer
data-testid="cornerOrnamentContainer"
cornerOrnamentType={type || "icon"}
size={size || "sizeIcon50"}
element={element ? `${element}_CORNER_ORNAMENT_CONTAINER` : undefined}
>
<CornerOrnamentBase
data-testid="cornerOrnamentBase"
element={element ? `${element}_CORNER_ORNAMENT_BASE` : undefined}
>
<Avatar data-testid="ornament-element" size="sizeIcon50" src="./avatars/avatar8.png" name="GitHub avatar" />
</CornerOrnamentBase>
<CornerOrnament data-testid="cornerOrnament" element={element ? `${element}_CORNER_ORNAMENT` : undefined}>
<Box data-testid="ornament">
<LogoTwilioIcon decorative size="sizeIcon40" />
</Box>
</CornerOrnament>
</CornerOrnamentContainer>
);

describe("CornerOrnament", () => {
it("should render", () => {
const { getByTestId } = render(<ExampleCornerOrnament />);
expect(getByTestId("ornament-element")).toBeDefined();
expect(getByTestId("ornament")).toBeDefined();
});

it("should throw errors for unsupported size and type combinations", () => {
expect(() => {
render(<ExampleCornerOrnament size="sizeIcon10" type="icon" />);
}).toThrow();
});

describe("Customization", () => {
it("should set element data attribute", () => {
const { getByTestId } = render(<ExampleCornerOrnament />);
expect(getByTestId("cornerOrnamentContainer").getAttribute("data-paste-element")).toEqual(
"CORNER_ORNAMENT_CONTAINER",
);
expect(getByTestId("cornerOrnamentBase").getAttribute("data-paste-element")).toEqual("CORNER_ORNAMENT_BASE");
expect(getByTestId("cornerOrnament").getAttribute("data-paste-element")).toEqual("CORNER_ORNAMENT");
});

it("should set custom element data attribute", () => {
const { getByTestId } = render(<ExampleCornerOrnament element="CUSTOMIZED" />);
expect(getByTestId("cornerOrnamentContainer").getAttribute("data-paste-element")).toEqual(
"CUSTOMIZED_CORNER_ORNAMENT_CONTAINER",
);
expect(getByTestId("cornerOrnamentBase").getAttribute("data-paste-element")).toEqual(
"CUSTOMIZED_CORNER_ORNAMENT_BASE",
);
expect(getByTestId("cornerOrnament").getAttribute("data-paste-element")).toEqual("CUSTOMIZED_CORNER_ORNAMENT");
});
});
});
3 changes: 3 additions & 0 deletions packages/paste-core/components/corner-ornament/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const { build } = require("../../../../tools/build/esbuild");

build(require("./package.json"));
61 changes: 61 additions & 0 deletions packages/paste-core/components/corner-ornament/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"name": "@twilio-paste/corner-ornament",
"version": "0.0.0",
"category": "data display",
"status": "production",
"description": "Corner Ornament is a container used to apply a cutout to a base component and position another element as its ornament.",
"author": "Twilio Inc.",
"license": "MIT",
"main:dev": "src/index.tsx",
"main": "dist/index.js",
"module": "dist/index.es.js",
"types": "dist/index.d.ts",
"sideEffects": false,
"publishConfig": {
"access": "public"
},
"files": [
"dist"
],
"scripts": {
"build": "yarn clean && NODE_ENV=production node build.js && tsc",
"build:js": "NODE_ENV=development node build.js",
"build:typedocs": "tsx ../../../../tools/build/generate-type-docs",
"clean": "rm -rf ./dist",
"tsc": "tsc"
},
"peerDependencies": {
"@twilio-paste/animation-library": "^2.0.0",
"@twilio-paste/box": "^10.2.0",
"@twilio-paste/color-contrast-utils": "^5.0.0",
"@twilio-paste/customization": "^8.1.1",
"@twilio-paste/design-tokens": "^10.3.0",
"@twilio-paste/style-props": "^9.1.1",
"@twilio-paste/styling-library": "^3.0.0",
"@twilio-paste/theme": "^11.0.1",
"@twilio-paste/types": "^6.0.0",
"@twilio-paste/uid-library": "^2.0.0",
"@types/react": "^16.8.6 || ^17.0.2 || ^18.0.27",
"@types/react-dom": "^16.8.6 || ^17.0.2 || ^18.0.10",
"react": "^16.8.6 || ^17.0.2 || ^18.0.0",
"react-dom": "^16.8.6 || ^17.0.2 || ^18.0.0"
},
"devDependencies": {
"@twilio-paste/animation-library": "^2.0.0",
"@twilio-paste/box": "^10.2.0",
"@twilio-paste/color-contrast-utils": "^5.0.0",
"@twilio-paste/customization": "^8.1.1",
"@twilio-paste/design-tokens": "^10.3.0",
"@twilio-paste/style-props": "^9.1.1",
"@twilio-paste/styling-library": "^3.0.0",
"@twilio-paste/theme": "^11.0.1",
"@twilio-paste/types": "^6.0.0",
"@twilio-paste/uid-library": "^2.0.0",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"tsx": "^4.0.0",
"typescript": "^4.9.4"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Box, safelySpreadBoxProps } from "@twilio-paste/box";
import * as React from "react";

import { useCornerOrnamentContext } from "./CornerOrnamentContext";
import { OrnamentPositionStyleMappings } from "./mappings";
import { CornerOrnamentProps } from "./types";

export const CornerOrnament = React.forwardRef<HTMLDivElement, CornerOrnamentProps>(
({ element = "CORNER_ORNAMENT", ...props }, ref) => {
const { cornerOrnamentType, size, position } = useCornerOrnamentContext();

if (!OrnamentPositionStyleMappings[cornerOrnamentType][position][size]) {
throw new Error(
"[Paste: CornerOrnament] the size/position/type combination you have chosen is not currently supported. Please refer to the guidelines in our docs or raise a new discussion to get this supported at https://github.com/twilio-labs/paste/discussions.",
);
}

return (
<Box
{...safelySpreadBoxProps(props)}
position="absolute"
element={element}
ref={ref}
{...OrnamentPositionStyleMappings[cornerOrnamentType][position][size]}
>
{props.children}
</Box>
);
},
);

CornerOrnament.displayName = "CornerOrnament";
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Box, safelySpreadBoxProps } from "@twilio-paste/box";
import { useUID } from "@twilio-paste/uid-library";
import * as React from "react";

import { useCornerOrnamentContext } from "./CornerOrnamentContext";
import { ClipPathMappings } from "./mappings";
import { CornerOrnamentBaseProps } from "./types";

export const CornerOrnamentBase = React.forwardRef<HTMLDivElement, CornerOrnamentBaseProps>(
({ padding, element = "CORNER_ORNAMENT_BASE", ...props }, ref) => {
const id = useUID();
const { cornerOrnamentType, position, size } = useCornerOrnamentContext();

return (
<Box
{...safelySpreadBoxProps(props)}
style={{
clipPath: `url("#${id}")`,
}}
element={element}
ref={ref}
size={size}
>
<Box padding={padding || "space0"}>{props.children}</Box>
<Box as="svg" size={0} position="absolute" top={0} left={0}>
<defs>
<clipPath id={id} clipPathUnits="objectBoundingBox">
{<path d={ClipPathMappings[cornerOrnamentType][position]} />}
</clipPath>
</defs>
</Box>
</Box>
);
},
);

CornerOrnamentBase.displayName = "CornerOrnamentBase";
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Box, safelySpreadBoxProps } from "@twilio-paste/box";
import * as React from "react";

import { CornerOrnamentContext } from "./CornerOrnamentContext";
import { CornerOrnamentContainerProps } from "./types";

export const CornerOrnamentContainer = React.forwardRef<HTMLDivElement, CornerOrnamentContainerProps>(
({ size, cornerOrnamentType, position = "bottom_end", element = "CORNER_ORNAMENT_CONTAINER", ...props }, ref) => {
return (
<CornerOrnamentContext.Provider value={{ size, cornerOrnamentType, position }}>
<Box {...safelySpreadBoxProps(props)} position="relative" element={element} ref={ref}>
{props.children}
</Box>
</CornerOrnamentContext.Provider>
);
},
);

CornerOrnamentContainer.displayName = "CornerOrnamentContainer";
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from "react";

import { CornerOrnamentContextInterface } from "./types";

export const CornerOrnamentContext = React.createContext<CornerOrnamentContextInterface | null>(null);

export const useCornerOrnamentContext = (): CornerOrnamentContextInterface => {
const context = React.useContext(CornerOrnamentContext);
if (!context) {
throw new Error("Corner Ornaments components must be used within CornerOrnamentContainer");
}
return context;
};
8 changes: 8 additions & 0 deletions packages/paste-core/components/corner-ornament/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export { CornerOrnament } from "./CornerOrnament";
export { CornerOrnamentContainer } from "./CornerOrnamentContainer";
export { CornerOrnamentBase } from "./CornerOrnamentBase";
export type {
CornerOrnamentBaseProps,
CornerOrnamentContainerProps,
CornerOrnamentProps,
} from "./types";
Loading

0 comments on commit d3d74e5

Please sign in to comment.