diff --git a/.changeset/rare-gifts-wash.md b/.changeset/rare-gifts-wash.md new file mode 100644 index 0000000000..a13d1a1e7e --- /dev/null +++ b/.changeset/rare-gifts-wash.md @@ -0,0 +1,6 @@ +--- +"@twilio-paste/blockquote": minor +"@twilio-paste/core": minor +--- + +[Blockquote] add default bottom margin of space-70 to Blockquote, add marginBottom prop for the option to remove bottom margin when necessary. diff --git a/cypress/integration/sitemap-vrt/constants.ts b/cypress/integration/sitemap-vrt/constants.ts index e9754f6749..8e2a1b4188 100644 --- a/cypress/integration/sitemap-vrt/constants.ts +++ b/cypress/integration/sitemap-vrt/constants.ts @@ -48,6 +48,9 @@ export const SITEMAP = [ "/components/badge/", "/components/badge/api", "/components/badge/changelog", + "/components/blockquote/", + "/components/blockquote/api", + "/components/blockquote/changelog", "/components/callout/", "/components/callout/api", "/components/callout/changelog", @@ -87,6 +90,9 @@ export const SITEMAP = [ "/components/disclosure/", "/components/disclosure/api", "/components/disclosure/changelog", + "/components/example-text/", + "/components/example-text/api", + "/components/example-text/changelog", "/components/button/", "/components/button/api", "/components/button/changelog", diff --git a/packages/paste-core/components/blockquote/src/Blockquote.tsx b/packages/paste-core/components/blockquote/src/Blockquote.tsx index 30503f80f0..f2e72e3c04 100644 --- a/packages/paste-core/components/blockquote/src/Blockquote.tsx +++ b/packages/paste-core/components/blockquote/src/Blockquote.tsx @@ -21,10 +21,16 @@ export interface BlockquoteProps extends HTMLPasteProps<"div"> { * @memberof BlockquoteProps */ url?: string; + /** + * Remove the bottom margin + * @type {"space0" | "space70"} + * @memberof BlockquoteProps + */ + marginBottom?: "space0" | "space70"; } export const Blockquote = React.forwardRef( - ({ children, element = "BLOCKQUOTE", url, ...props }, ref) => { + ({ children, element = "BLOCKQUOTE", url, marginBottom = "space70", ...props }, ref) => { return ( ( alignItems="flex-start" lineHeight="lineHeight30" fontSize="fontSize30" + marginBottom={marginBottom} element={element} > diff --git a/packages/paste-core/components/blockquote/stories/index.stories.tsx b/packages/paste-core/components/blockquote/stories/index.stories.tsx index d067207007..87f9bd7bde 100644 --- a/packages/paste-core/components/blockquote/stories/index.stories.tsx +++ b/packages/paste-core/components/blockquote/stories/index.stories.tsx @@ -48,6 +48,29 @@ export const WithoutSource: StoryFn = () => ( ); +export const BottomMargin: StoryFn = () => ( + + +
+ + With AI-driven products, the design process is no longer just about aesthetics. It’s about designing for the + human experience as a whole. + + +
+
+ +
+ + With AI-driven products, the design process is no longer just about aesthetics. It’s about designing for the + human experience as a whole. + + +
+
+
+); + export const CustomizationBlockquote: StoryFn = (_args, { parameters: { isTestEnvironment } }) => { const currentTheme = useTheme(); return ( diff --git a/packages/paste-core/components/blockquote/type-docs.json b/packages/paste-core/components/blockquote/type-docs.json index dee22d235d..35bec78bee 100644 --- a/packages/paste-core/components/blockquote/type-docs.json +++ b/packages/paste-core/components/blockquote/type-docs.json @@ -495,6 +495,13 @@ "required": false, "externalProp": true }, + "marginBottom": { + "type": "\"space0\" | \"space70\"", + "defaultValue": null, + "required": false, + "externalProp": false, + "description": "Remove the bottom margin" + }, "nonce": { "type": "string", "defaultValue": null, diff --git a/packages/paste-core/core-bundle/blockquote/package.json b/packages/paste-core/core-bundle/blockquote/package.json new file mode 100644 index 0000000000..786bb3794c --- /dev/null +++ b/packages/paste-core/core-bundle/blockquote/package.json @@ -0,0 +1,8 @@ +{ + "name": "@twilio-paste-core/blockquote", + "version": "0.0.0", + "private": true, + "sideEffects": false, + "main": "../dist/blockquote.js", + "types": "../dist/blockquote.d.ts" +} \ No newline at end of file diff --git a/packages/paste-website/package.json b/packages/paste-website/package.json index 3839473171..5ee55b5e1f 100644 --- a/packages/paste-website/package.json +++ b/packages/paste-website/package.json @@ -43,6 +43,7 @@ "@twilio-paste/avatar": "^9.1.0", "@twilio-paste/badge": "^8.3.1", "@twilio-paste/base-radio-checkbox": "^13.1.0", + "@twilio-paste/blockquote": "^0.0.0", "@twilio-paste/box": "^10.3.0", "@twilio-paste/breadcrumb": "^11.1.1", "@twilio-paste/button": "^14.1.2", @@ -70,6 +71,7 @@ "@twilio-paste/display-heading": "^4.1.0", "@twilio-paste/display-pill-group": "^8.0.1", "@twilio-paste/dropdown-library": "^3.0.0", + "@twilio-paste/example-text": "^0.0.0", "@twilio-paste/file-picker": "^4.1.0", "@twilio-paste/file-uploader": "^4.1.0", "@twilio-paste/flex": "^8.1.0", diff --git a/packages/paste-website/src/pages/components/blockquote/api.mdx b/packages/paste-website/src/pages/components/blockquote/api.mdx new file mode 100644 index 0000000000..e32f70e9aa --- /dev/null +++ b/packages/paste-website/src/pages/components/blockquote/api.mdx @@ -0,0 +1,65 @@ +import Changelog from '@twilio-paste/blockquote/CHANGELOG.md'; // I don't know why this is needed but if you remove it the page fails to render +import packageJson from '@twilio-paste/blockquote/package.json'; + +import {SidebarCategoryRoutes} from '../../../constants'; +import ComponentPageLayout from '../../../layouts/ComponentPageLayout'; +import {getFeature, getNavigationData, getComponentApi} from '../../../utils/api'; + +export const meta = { + title: 'Blockquote - Components', + package: '@twilio-paste/blockquote', + description: packageJson.description, + slug: '/components/blockquote/api', +}; + +export default ComponentPageLayout; + +export const getStaticProps = async () => { + const navigationData = await getNavigationData(); + const feature = await getFeature('Blockquote'); + const {componentApi, componentApiTocData} = getComponentApi('@twilio-paste/blockquote'); + return { + props: { + data: { + ...packageJson, + ...feature, + }, + componentApi, + mdxHeadings: [...mdxHeadings, ...componentApiTocData], + navigationData, + pageHeaderData: { + categoryRoute: SidebarCategoryRoutes.COMPONENTS, + githubUrl: 'https://github.com/twilio-labs/paste/tree/main/packages/paste-core/components/blockquote', + storybookUrl: '/?path=/story/components-blockquote--default', + }, + }, + }; +}; + +## Installation + +```bash +yarn add @twilio-paste/blockquote - or - yarn add @twilio-paste/core +``` + +## Usage + +```jsx +import { Blockquote, BlockquoteContent, BlockquoteCitation } from '@twilio-paste/core/blockquote'; + +const BlockquoteExample = () => { + return ( +
+ + With AI-driven products, the design process is no longer just about aesthetics. It’s about designing for the + human experience as a whole. + + +
+ ); +}; +``` + +## Props + + diff --git a/packages/paste-website/src/pages/components/blockquote/changelog.mdx b/packages/paste-website/src/pages/components/blockquote/changelog.mdx new file mode 100644 index 0000000000..96407d27f8 --- /dev/null +++ b/packages/paste-website/src/pages/components/blockquote/changelog.mdx @@ -0,0 +1,36 @@ +import {SidebarCategoryRoutes} from '../../../constants'; +import Changelog from '@twilio-paste/blockquote/CHANGELOG.md'; +import packageJson from '@twilio-paste/blockquote/package.json'; +import ComponentPageLayout from '../../../layouts/ComponentPageLayout'; +import {getFeature, getNavigationData} from '../../../utils/api'; + +export const meta = { + title: 'Blockquote - Components', + package: '@twilio-paste/blockquote', + description: packageJson.description, + slug: '/components/blockquote/changelog', +}; + +export default ComponentPageLayout; + +export const getStaticProps = async () => { + const navigationData = await getNavigationData(); + const feature = await getFeature('Blockquote'); + return { + props: { + data: { + ...packageJson, + ...feature, + }, + navigationData, + mdxHeadings, + pageHeaderData: { + categoryRoute: SidebarCategoryRoutes.COMPONENTS, + githubUrl: 'https://github.com/twilio-labs/paste/tree/main/packages/paste-core/components/blockquote', + storybookUrl: '/?path=/story/components-blockquote--default', + }, + }, + }; +}; + + diff --git a/packages/paste-website/src/pages/components/blockquote/index.mdx b/packages/paste-website/src/pages/components/blockquote/index.mdx new file mode 100644 index 0000000000..5c70cbcf85 --- /dev/null +++ b/packages/paste-website/src/pages/components/blockquote/index.mdx @@ -0,0 +1,217 @@ +import {Blockquote, BlockquoteContent, BlockquoteCitation} from '@twilio-paste/blockquote'; +import packageJson from '@twilio-paste/blockquote/package.json'; +import { ExampleText } from '@twilio-paste/example-text'; +import {CodeBlock} from '@twilio-paste/code-block' +import {InlineCode} from '@twilio-paste/inline-code' +import {Label} from '@twilio-paste/label' +import {Input} from '@twilio-paste/input' +import {HelpText} from '@twilio-paste/help-text' +import {Callout, CalloutHeading, CalloutText} from '@twilio-paste/callout' +import {Box} from "@twilio-paste/box" +import {Paragraph} from "@twilio-paste/paragraph" +import {Table, THead, Tr, Th, TBody, Td} from '@twilio-paste/table'; +import {Anchor} from '@twilio-paste/anchor' + +import {SidebarCategoryRoutes} from '../../../constants'; +import ComponentPageLayout from '../../../layouts/ComponentPageLayout'; +import {getFeature, getNavigationData} from '../../../utils/api'; +import {DoDont, Do, Dont} from '../../../components/DoDont'; + +export const meta = { + title: 'Blockquote - Components', + package: '@twilio-paste/blockquote', + description: packageJson.description, + slug: '/components/blockquote/', +}; + +export default ComponentPageLayout; + +export const getStaticProps = async () => { + const navigationData = await getNavigationData(); + const feature = await getFeature('Blockquote'); + return { + props: { + data: { + ...packageJson, + ...feature, + }, + navigationData, + mdxHeadings, + pageHeaderData: { + categoryRoute: SidebarCategoryRoutes.COMPONENTS, + githubUrl: 'https://github.com/twilio-labs/paste/tree/main/packages/paste-core/components/blockquote', + storybookUrl: '/?path=/story/components-blockquote--default', + }, + }, + }; +}; + + + {`
+ + With AI-driven products, the design process is no longer just about aesthetics. It’s about designing for the human experience as a whole. + + +
`} +
+ +## Guidelines + +### About Blockquote + +A Blockquote is a stylized text format used to highlight a text excerpt or quote, usually sourced from articles, blog posts or customer feedback. It makes it easier for users to recognize a quote or reference. + +### Accessibility + +- When using the Blockquote component, ensure that the cite attribute provides a valid URL or reference to the source of the quoted content. This attribute allows assistive technologies, such as screen readers, to convey the source of the quote to users. +- Avoid using Blockquote purely for visual formatting, such as creating indents or styling text. This markup carries semantic meaning, indicating that the text is a quotation. Using it for styling purposes can confuse screen readers, misrepresenting the content's structure and meaning. + +### How to decide which components to use to make your text stand out + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ComponentUsageExample
BlockquoteUse to highlight quotations from an external source or customer feedback. +
This is a Blockquote pulled from an outside source.
+
Example TextUse when you want to provide contextual examples of user input. + This is an Example Text that guides users on how to respond to a system +
CalloutUse a Callout to highlight any other important information. + Heads up!This is some information you need to know. +
+
+ +## Examples + +### Blockquote + +Use a default Blockquote when you want to highlight a quote from an external source, but there is no specific need for URL and the context is clear. + + + {`
+ + With AI-driven products, the design process is no longer just about aesthetics. It’s about designing for the human experience as a whole. + + +
`} +
+ +### Blockquote without URL + +Use Blockquote without URL when you have the actual source of the quote but are unable to provide a URL to redirect the user. + + + {`
+ + If I must die
+ let it bring hope
+ let it be a tale +
+ +
`} +
+ +### Blockquote with author only + +Use a Blockquote with only author attribution when you want to highlight a quote from an external source, but there is no specific need for source or the source is unavailable. + +Example use cases: +- When quoting a well-known individual, where the author’s name provides enough context for the audience. +- When quoting from a source that is hard to trace or not directly accessible (e.g., a verbal interview or a widely repeated saying without a specific source) + + + {`
+ + When you light a candle, you also cast a shadow. + + +
`} +
+ +## Composition notes + +- Whenever possible, include a URL to the original source to allow users to access additional context or details +- Always provide context before and after the Blockquote to connect the information to the surrounding content +- Use **capital case** for author’s name. For example: Jane Doe +- Use **sentence case**, with only the first word and proper nouns capitalized for the source and its URL + + + {`<> + Avoid being too heavy-handed with communicating how a feature has been built or changed with AI since introducing new interaction patterns and unnecessary messaging can distract from the customer’s goals. +
+ + With AI-driven products, there can be a temptation to communicate the “newness” or “magic” of the system’s predictions through its UI metaphors. However, unfamiliar UI touchpoints can make it harder for users to learn to use your system, potentially leading to degraded understanding of, or trust in, your product…Instead, anchor new users with familiar UI patterns and features. + + +
+ With AI features, there’s also a higher chance for things to go wrong. + `} +
+ + +## Dos and Don'ts + + + + + + + + +
+ + With AI-driven products, there can be a temptation to communicate the “newness” or “magic” of the system’s predictions through its UI metaphors. However, unfamiliar UI touchpoints can make it harder for users to learn to use your system, potentially leading to degraded understanding of, or trust in, your product…Instead, anchor new users with familiar UI patterns and features. + + +
+
+
+ + +
+ + To create your account, provide your full name, a valid email address, and a secure password. Your password must contain at least eight characters, including uppercase letters, lowercase letters, numbers, and a special character. + +
+
+
+
+ + diff --git a/packages/paste-website/src/pages/components/example-text/api.mdx b/packages/paste-website/src/pages/components/example-text/api.mdx new file mode 100644 index 0000000000..475eeb07c0 --- /dev/null +++ b/packages/paste-website/src/pages/components/example-text/api.mdx @@ -0,0 +1,59 @@ +import Changelog from '@twilio-paste/example-text/CHANGELOG.md'; // I don't know why this is needed but if you remove it the page fails to render +import packageJson from '@twilio-paste/example-text/package.json'; + +import {SidebarCategoryRoutes} from '../../../constants'; +import ComponentPageLayout from '../../../layouts/ComponentPageLayout'; +import {getFeature, getNavigationData, getComponentApi} from '../../../utils/api'; + +export const meta = { + title: 'Example Text - Components', + package: '@twilio-paste/example-text', + description: packageJson.description, + slug: '/components/example-text/api', +}; + +export default ComponentPageLayout; + +export const getStaticProps = async () => { + const navigationData = await getNavigationData(); + const feature = await getFeature('Example Text'); + const {componentApi, componentApiTocData} = getComponentApi('@twilio-paste/example-text'); + return { + props: { + data: { + ...packageJson, + ...feature, + }, + componentApi, + mdxHeadings: [...mdxHeadings, ...componentApiTocData], + navigationData, + pageHeaderData: { + categoryRoute: SidebarCategoryRoutes.COMPONENTS, + githubUrl: 'https://github.com/twilio-labs/paste/tree/main/packages/paste-core/components/example-text', + storybookUrl: '/?path=/story/components-example-text--default', + }, + }, + }; +}; + +## Installation + +```bash +yarn add @twilio-paste/example-text - or - yarn add @twilio-paste/core +``` + +## Usage + +```jsx +import { ExampleText } from '@twilio-paste/core/example-text'; + +const ExampleTextExample = () => { + return ( + Example text + ); +}; +``` + +## Props + + diff --git a/packages/paste-website/src/pages/components/example-text/changelog.mdx b/packages/paste-website/src/pages/components/example-text/changelog.mdx new file mode 100644 index 0000000000..e8dcddb1ea --- /dev/null +++ b/packages/paste-website/src/pages/components/example-text/changelog.mdx @@ -0,0 +1,36 @@ +import {SidebarCategoryRoutes} from '../../../constants'; +import Changelog from '@twilio-paste/example-text/CHANGELOG.md'; +import packageJson from '@twilio-paste/example-text/package.json'; +import ComponentPageLayout from '../../../layouts/ComponentPageLayout'; +import {getFeature, getNavigationData} from '../../../utils/api'; + +export const meta = { + title: 'Example Text - Components', + package: '@twilio-paste/example-text', + description: packageJson.description, + slug: '/components/example-text/changelog', +}; + +export default ComponentPageLayout; + +export const getStaticProps = async () => { + const navigationData = await getNavigationData(); + const feature = await getFeature('Example Text'); + return { + props: { + data: { + ...packageJson, + ...feature, + }, + navigationData, + mdxHeadings, + pageHeaderData: { + categoryRoute: SidebarCategoryRoutes.COMPONENTS, + githubUrl: 'https://github.com/twilio-labs/paste/tree/main/packages/paste-core/components/example-text', + storybookUrl: '/?path=/story/components-example-text--default', + }, + }, + }; +}; + + diff --git a/packages/paste-website/src/pages/components/example-text/index.mdx b/packages/paste-website/src/pages/components/example-text/index.mdx new file mode 100644 index 0000000000..05c431210c --- /dev/null +++ b/packages/paste-website/src/pages/components/example-text/index.mdx @@ -0,0 +1,163 @@ +import { ExampleText } from '@twilio-paste/example-text'; +import packageJson from '@twilio-paste/example-text/package.json'; +import {CodeBlock} from '@twilio-paste/code-block' +import {InlineCode} from '@twilio-paste/inline-code' +import {Label} from '@twilio-paste/label' +import {Input} from '@twilio-paste/input' +import {HelpText} from '@twilio-paste/help-text' +import {Callout, CalloutHeading, CalloutText} from '@twilio-paste/callout' +import {Paragraph} from '@twilio-paste/paragraph' +import {Blockquote, BlockquoteCitation, BlockquoteContent} from '@twilio-paste/blockquote' +import {Table, THead, Tr, Th, TBody, Td} from '@twilio-paste/table'; +import {Anchor} from '@twilio-paste/anchor' +import {Box} from '@twilio-paste/box' + +import {SidebarCategoryRoutes} from '../../../constants'; +import ComponentPageLayout from '../../../layouts/ComponentPageLayout'; +import {getFeature, getNavigationData} from '../../../utils/api'; +import {DoDont, Do, Dont} from '../../../components/DoDont'; + +export const meta = { + title: 'Example Text - Components', + package: '@twilio-paste/example-text', + description: packageJson.description, + slug: '/components/example-text/', +}; + +export default ComponentPageLayout; + +export const getStaticProps = async () => { + const navigationData = await getNavigationData(); + const feature = await getFeature('Example Text'); + return { + props: { + data: { + ...packageJson, + ...feature, + }, + navigationData, + mdxHeadings, + pageHeaderData: { + categoryRoute: SidebarCategoryRoutes.COMPONENTS, + githubUrl: 'https://github.com/twilio-labs/paste/tree/main/packages/paste-core/components/example-text', + storybookUrl: '/?path=/story/components-example-text--default', + }, + }, + }; +}; + + + {`<> + When submitting feedback about your experience, provide specific details to help us understand your needs and improve our offerings. For example: + The service was quick and efficient, but I would like more options in the menu. +`} + + +## Guidelines + +### About Example Text + +Example Text represents contextual examples that guide users on what type of information to enter or how to respond within a system. + +Use Example Text so users can easily differentiate between examples and regular text or code blocks. It also reduces the chances of users overlooking important examples. + +### How to decide which components to use to make your text stand out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ComponentUsageExample
Example TextUse when you want to provide contextual examples of user input. + This is an Example Text that guides users on how to respond to a system +
BlockquoteUse to highlight quotations from an external source or customer feedback. +
This is a Blockquote pulled from an outside source.
+
Code BlockUse when you need to display blocks of code and when the user needs to copy a command to put it into a CLI. + +
Inline CodeUse to emphasize short, inline pieces of computer code such as variable names and function calls. + console.log(mySustainabilityGoals) +
Help TextUse below a form field to help users prevent an error and describe what makes the form field successful. + <>{}} required/>Use your work email address. +
CalloutUse a Callout to highlight any other important information. + Heads up!This is some information you need to know. +
+
+ +## Examples + +### Example Text + +Use Example Text to show examples of user input, especially in instructions, or to help users fill out forms. + + + {`<> + When submitting feedback about your experience, provide specific details to help us understand your needs and improve our offerings. For example: + The service was quick and efficient, but I would like more options in the menu. +`} + + +### Inline Example Text + +Example Text can also be used inline in a [Paragraph](/components/paragraph) in cases where the example supports the sentence but isn’t the primary focus, maintaining the conversational tone. + + + {`To create your account, provide your full name, a valid email address, and a secure password. Your password must contain at least eight characters, including uppercase letters, lowercase letters, numbers, and a special character. For example, !Password@123. You may be asked to verify your email address by clicking a link sent to your inbox.`} + + +## Dos and Don'ts + + + + + + + + + + + diff --git a/yarn.lock b/yarn.lock index 1c254da49f..447c7f6139 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16128,6 +16128,7 @@ __metadata: "@twilio-paste/avatar": ^9.1.0 "@twilio-paste/badge": ^8.3.1 "@twilio-paste/base-radio-checkbox": ^13.1.0 + "@twilio-paste/blockquote": ^0.0.0 "@twilio-paste/box": ^10.3.0 "@twilio-paste/breadcrumb": ^11.1.1 "@twilio-paste/button": ^14.1.2 @@ -16155,6 +16156,7 @@ __metadata: "@twilio-paste/display-heading": ^4.1.0 "@twilio-paste/display-pill-group": ^8.0.1 "@twilio-paste/dropdown-library": ^3.0.0 + "@twilio-paste/example-text": ^0.0.0 "@twilio-paste/file-picker": ^4.1.0 "@twilio-paste/file-uploader": ^4.1.0 "@twilio-paste/flex": ^8.1.0