Skip to content

Commit

Permalink
Merge branch 'main' into example-text-docs
Browse files Browse the repository at this point in the history
  • Loading branch information
nkrantz authored Nov 27, 2024
2 parents 28a6a6d + 36bd1e3 commit 222e9f3
Show file tree
Hide file tree
Showing 45 changed files with 6,134 additions and 42 deletions.
5 changes: 5 additions & 0 deletions .changeset/dull-horses-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@twilio-paste/codemods": minor
---

[Blockquote]: Add new component
6 changes: 6 additions & 0 deletions .changeset/dull-panthers-develop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@twilio-paste/icons": minor
"@twilio-page/core": minor
---

[Icon]: Add Blockquote icon.
6 changes: 6 additions & 0 deletions .changeset/nervous-rabbits-love.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@twilio-paste/progress-steps": patch
"@twilio-paste/core": patch
---

[ProgressSteps] fixed an issue where progress steps was rerendering unnecessarily
6 changes: 6 additions & 0 deletions .changeset/quiet-windows-poke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@twilio-paste/box": minor
"@twilio-paste/core": minor
---

[Box]: Add cite prop for use with Blockquote
6 changes: 6 additions & 0 deletions .changeset/slow-jokes-matter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@twilio-paste/keyboard-key": patch
"@twilio-paste/core": patch
---

[KeyboardKey] fixed issue with shift key being captured as capitals on subsequesnt key presses
6 changes: 6 additions & 0 deletions .changeset/tough-dolphins-decide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@twilio-paste/blockquote": major
"@twilio-paste/core": minor
---

[Blockquote]: Added a new Blockquote component to library to act as a stylized text wrapper for a quotation and source.
1 change: 1 addition & 0 deletions .codesandbox/ci.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"/packages/paste-core/components/avatar",
"/packages/paste-core/components/badge",
"/packages/paste-core/components/base-radio-checkbox",
"/packages/paste-core/components/blockquote",
"/packages/paste-core/primitives/box",
"/packages/paste-core/components/breadcrumb",
"/packages/paste-core/components/button",
Expand Down
3 changes: 3 additions & 0 deletions cypress/integration/sitemap-vrt/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ export const SITEMAP = [
"/components/input/",
"/components/input/api",
"/components/input/changelog",
"components/keyboard-key",
"components/keyboard-key/api",
"components/keyboard-key/changelog",
"/components/label/",
"/components/label/api",
"/components/label/changelog",
Expand Down
7 changes: 7 additions & 0 deletions internal-docs/engineering/gotchas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Gotchas

The purpose of this document is to keep a list of niche issues that have arisen over the lifetime of the product that we do not want to re-introduce. This can be related to our coded or third party libraries.

## Emotion Library

* If you pass a prop of the component into `styled.div` be sure to wrap it in useMemo as this librabry causes unnecessary re-renders otherwise.
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 @@ -33,6 +33,9 @@
"BaseRadioCheckboxHelpText": "@twilio-paste/core/base-radio-checkbox",
"BaseRadioCheckboxLabel": "@twilio-paste/core/base-radio-checkbox",
"BaseRadioCheckboxLabelText": "@twilio-paste/core/base-radio-checkbox",
"Blockquote": "@twilio-paste/core/blockquote",
"BlockquoteCitation": "@twilio-paste/core/blockquote",
"BlockquoteContent": "@twilio-paste/core/blockquote",
"Breadcrumb": "@twilio-paste/core/breadcrumb",
"BreadcrumbItem": "@twilio-paste/core/breadcrumb",
"Button": "@twilio-paste/core/button",
Expand Down
Empty file.
88 changes: 88 additions & 0 deletions packages/paste-core/components/blockquote/__tests__/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { render, screen } from "@testing-library/react";
import * as React from "react";

import { Blockquote, BlockquoteCitation, BlockquoteContent } from "../src";

describe("Blockquote", () => {
it("should render", () => {
render(
<Blockquote url="#" data-testid="blockquote">
<BlockquoteContent>This is some text.</BlockquoteContent>
<BlockquoteCitation author="Google" source="People + AI Guidebook" />
</Blockquote>,
);

const blockquote = screen.getByTestId("blockquote");
expect(blockquote).toBeDefined();
const text = screen.getByText("This is some text.");
expect(text.nodeName).toBe("BLOCKQUOTE");
expect(text).toHaveAttribute("cite", "#");
expect(blockquote.querySelector(`[data-paste-element='BLOCKQUOTE_CITATION_ANCHOR']`)).toBeTruthy();
});

it("should render without a url", () => {
render(
<Blockquote data-testid="blockquote">
<BlockquoteContent>This is some text.</BlockquoteContent>
<BlockquoteCitation author="Google" source="People + AI Guidebook" />
</Blockquote>,
);

const blockquote = screen.getByTestId("blockquote");
expect(blockquote.querySelector(`[data-paste-element='BLOCKQUOTE_CITATION_CITE']`)).toBeTruthy();
expect(blockquote.querySelector("a")).toBeNull();
expect(screen.getByText("This is some text.")).not.toHaveAttribute("cite");
});

it("should render without a source", () => {
render(
<Blockquote data-testid="blockquote">
<BlockquoteContent>This is some text.</BlockquoteContent>
<BlockquoteCitation author="Google" />
</Blockquote>,
);

const blockquote = screen.getByTestId("blockquote");
expect(blockquote).toBeDefined();
expect(blockquote.querySelector(`[data-paste-element='BLOCKQUOTE_CITATION_CITE']`)).toBeFalsy();
expect(screen.getByText("This is some text.")).not.toHaveAttribute("cite");
});
});

describe("Customization", () => {
it("should set element data attribute", () => {
const { getByTestId } = render(
<Blockquote url="#" data-testid="blockquote">
<BlockquoteContent>This is some text.</BlockquoteContent>
<BlockquoteCitation author="Google" source="People + AI Guidebook" />
</Blockquote>,
);

expect(getByTestId("blockquote").getAttribute("data-paste-element")).toEqual("BLOCKQUOTE");
expect(getByTestId("blockquote").querySelector(`[data-paste-element='BLOCKQUOTE_ICON']`)).toBeTruthy();
expect(getByTestId("blockquote").querySelector(`[data-paste-element='INNER_BLOCKQUOTE']`)).toBeTruthy();
expect(getByTestId("blockquote").querySelector(`[data-paste-element='BLOCKQUOTE_CONTENT']`)).toBeTruthy();
expect(getByTestId("blockquote").querySelector(`[data-paste-element='BLOCKQUOTE_CITATION']`)).toBeTruthy();
expect(getByTestId("blockquote").querySelector(`[data-paste-element='BLOCKQUOTE_CITATION_AUTHOR']`)).toBeTruthy();
expect(getByTestId("blockquote").querySelector(`[data-paste-element='BLOCKQUOTE_CITATION_CITE']`)).toBeTruthy();
expect(getByTestId("blockquote").querySelector(`[data-paste-element='BLOCKQUOTE_CITATION_ANCHOR']`)).toBeTruthy();
});

it("should set custom element data attribute", () => {
const { getByTestId } = render(
<Blockquote url="#" data-testid="blockquote" element="CUSTOMIZED">
<BlockquoteContent element="CUSTOMIZED_CONTENT">This is some text.</BlockquoteContent>
<BlockquoteCitation author="Google" source="People + AI Guidebook" element="CUSTOMIZED_SOURCE" />
</Blockquote>,
);
screen.debug();
expect(getByTestId("blockquote").getAttribute("data-paste-element")).toEqual("CUSTOMIZED");
expect(getByTestId("blockquote").querySelector(`[data-paste-element='CUSTOMIZED_ICON']`)).toBeTruthy();
expect(getByTestId("blockquote").querySelector(`[data-paste-element='INNER_CUSTOMIZED']`)).toBeTruthy();
expect(getByTestId("blockquote").querySelector(`[data-paste-element='CUSTOMIZED_CONTENT']`)).toBeTruthy();
expect(getByTestId("blockquote").querySelector(`[data-paste-element='CUSTOMIZED_SOURCE']`)).toBeTruthy();
expect(getByTestId("blockquote").querySelector(`[data-paste-element='CUSTOMIZED_SOURCE_AUTHOR']`)).toBeTruthy();
expect(getByTestId("blockquote").querySelector(`[data-paste-element='CUSTOMIZED_SOURCE_CITE']`)).toBeTruthy();
expect(getByTestId("blockquote").querySelector(`[data-paste-element='CUSTOMIZED_SOURCE_ANCHOR']`)).toBeTruthy();
});
});
3 changes: 3 additions & 0 deletions packages/paste-core/components/blockquote/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"));
75 changes: 75 additions & 0 deletions packages/paste-core/components/blockquote/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
"name": "@twilio-paste/blockquote",
"version": "0.0.0",
"category": "layout",
"status": "production",
"description": "A Blockquote is a stylized text wrapper for a quotation and source.",
"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/anchor": "^12.0.0",
"@twilio-paste/animation-library": "^2.0.0",
"@twilio-paste/box": "^10.0.0",
"@twilio-paste/button": "^14.0.0",
"@twilio-paste/color-contrast-utils": "^5.0.0",
"@twilio-paste/customization": "^8.0.0",
"@twilio-paste/design-tokens": "^10.0.0",
"@twilio-paste/icons": "^12.0.0",
"@twilio-paste/screen-reader-only": "^13.0.0",
"@twilio-paste/spinner": "^14.0.0",
"@twilio-paste/stack": "^8.0.0",
"@twilio-paste/style-props": "^9.0.0",
"@twilio-paste/styling-library": "^3.0.0",
"@twilio-paste/text": "^10.0.0",
"@twilio-paste/theme": "^11.0.0",
"@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/anchor": "^12.0.0",
"@twilio-paste/animation-library": "^2.0.0",
"@twilio-paste/box": "^10.1.0",
"@twilio-paste/button": "^14.1.0",
"@twilio-paste/color-contrast-utils": "^5.0.0",
"@twilio-paste/customization": "^8.1.0",
"@twilio-paste/design-tokens": "^10.9.0",
"@twilio-paste/icons": "^12.2.0",
"@twilio-paste/screen-reader-only": "^13.1.0",
"@twilio-paste/spinner": "^14.0.0",
"@twilio-paste/stack": "^8.0.0",
"@twilio-paste/style-props": "^9.1.0",
"@twilio-paste/styling-library": "^3.0.0",
"@twilio-paste/text": "^10.1.0",
"@twilio-paste/theme": "^11.0.0",
"@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"
}
}
48 changes: 48 additions & 0 deletions packages/paste-core/components/blockquote/src/Blockquote.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Box, safelySpreadBoxProps } from "@twilio-paste/box";
import type { BoxProps } from "@twilio-paste/box";
import { BlockquoteIcon } from "@twilio-paste/icons/esm/BlockquoteIcon";
import type { HTMLPasteProps } from "@twilio-paste/types";
import React from "react";

import { BlockquoteContext } from "./BlockquoteContext";

export interface BlockquoteProps extends HTMLPasteProps<"div"> {
children?: React.ReactNode;
/**
* Overrides the default element name to apply unique styles with the Customization Provider
* @default 'BLOCKQUOTE'
* @type {BoxProps['element']}
* @memberof BlockquoteProps
*/
element?: BoxProps["element"];
/**
* The URL to the source of the quote
* @type {string}
* @memberof BlockquoteProps
*/
url?: string;
}

export const Blockquote = React.forwardRef<HTMLDivElement, BlockquoteProps>(
({ children, element = "BLOCKQUOTE", url, ...props }, ref) => {
return (
<Box
{...safelySpreadBoxProps(props)}
ref={ref}
display="flex"
columnGap="space50"
alignItems="flex-start"
lineHeight="lineHeight30"
fontSize="fontSize30"
element={element}
>
<BlockquoteIcon element={`${element}_ICON`} decorative={true} color="colorTextIcon" />
<BlockquoteContext.Provider value={{ url }}>
<Box element={`INNER_${element}`}>{children}</Box>
</BlockquoteContext.Provider>
</Box>
);
},
);

Blockquote.displayName = "Blockquote";
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Anchor } from "@twilio-paste/anchor";
import { Box, safelySpreadBoxProps } from "@twilio-paste/box";
import type { BoxProps } from "@twilio-paste/box";
import { Text } from "@twilio-paste/text";
import type { HTMLPasteProps } from "@twilio-paste/types";
import React from "react";

import { BlockquoteContext } from "./BlockquoteContext";

export interface BlockquoteCitationProps extends HTMLPasteProps<"div"> {
/**
* Overrides the default element name to apply unique styles with the Customization Provider
* @default 'BLOCKQUOTE_CITATION'
* @type {BoxProps['element']}
* @memberof BlockquoteCitationProps
*/
element?: BoxProps["element"];

/**
* The author of the quote
* @type {string}
* @memberof BlockquoteCitationProps
*/
author: string;

/**
* The source of the quote
* @type {string}
* @memberof BlockquoteCitationProps
*/
source?: string;
}

export const BlockquoteCitation = React.forwardRef<HTMLDivElement, BlockquoteCitationProps>(
({ element = "BLOCKQUOTE_CITATION", author, source, ...props }, ref) => {
const { url } = React.useContext(BlockquoteContext);

return (
<Box
{...safelySpreadBoxProps(props)}
marginTop="space30"
marginBottom="space0"
as="p"
element={element}
ref={ref}
>
{" "}
<Text as="span" fontWeight="fontWeightSemibold" element={`${element}_AUTHOR`}>
{author}
</Text>
{source ? (
<>
,{" "}
<Box as="cite" fontStyle="normal" element={`${element}_CITE`}>
{url ? (
<Anchor href={url} showExternal element={`${element}_ANCHOR`}>
{source}
</Anchor>
) : (
<Text as="span" element={`${element}_TEXT`}>
{source}
</Text>
)}
</Box>
</>
) : null}
</Box>
);
},
);

BlockquoteCitation.displayName = "BlockquoteCitation";
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Box, type BoxProps, safelySpreadBoxProps } from "@twilio-paste/box";
import type { HTMLPasteProps } from "@twilio-paste/types";
import React from "react";

import { BlockquoteContext } from "./BlockquoteContext";

export interface BlockquoteContentProps extends HTMLPasteProps<"blockquote"> {
children?: React.ReactNode;
/**
* Overrides the default element name to apply unique styles with the Customization Provider
* @default 'BLOCKQUOTE_CONTENT'
* @type {BoxProps['element']}
* @memberof BlockquoteContentProps
*/
element?: BoxProps["element"];
}

export const BlockquoteContent = React.forwardRef<HTMLQuoteElement, BlockquoteContentProps>(
({ children, element = "BLOCKQUOTE_CONTENT", ...props }, ref) => {
const { url } = React.useContext(BlockquoteContext);

return (
<Box {...safelySpreadBoxProps(props)} as="blockquote" margin="space0" ref={ref} element={element} cite={url}>
{children}
</Box>
);
},
);

BlockquoteContent.displayName = "BlockquoteContent";
Loading

0 comments on commit 222e9f3

Please sign in to comment.