diff --git a/e2e/components/Slug/Slug-test.avt.e2e.js b/e2e/components/AILabel/Slug-test.avt.e2e.js similarity index 81% rename from e2e/components/Slug/Slug-test.avt.e2e.js rename to e2e/components/AILabel/Slug-test.avt.e2e.js index 7da0e7057c96..10db0cd80729 100644 --- a/e2e/components/Slug/Slug-test.avt.e2e.js +++ b/e2e/components/AILabel/Slug-test.avt.e2e.js @@ -1,5 +1,5 @@ /** - * Copyright IBM Corp. 2016, 2023 + * Copyright IBM Corp. 2016, 2024 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. @@ -10,22 +10,22 @@ const { expect, test } = require('@playwright/test'); const { visitStory } = require('../../test-utils/storybook'); -test.describe('@avt Slug', async () => { +test.describe('@avt AILabel', () => { test('@avt-default-state', async ({ page }) => { await visitStory(page, { - component: 'Slug', - id: 'experimental-unstable-slug--default', + component: 'AILabel', + id: 'components-ailabel--default', globals: { theme: 'white', }, }); - await expect(page).toHaveNoACViolations('Slug'); + await expect(page).toHaveNoACViolations('AILabel'); }); test.slow('@avt-advanced-states open state', async ({ page }) => { await visitStory(page, { - component: 'Slug', - id: 'experimental-unstable-slug--default', + component: 'AILabel', + id: 'components-ailabel--default', globals: { theme: 'white', }, @@ -34,24 +34,24 @@ test.describe('@avt Slug', async () => { await page.keyboard.press('Tab'); await page.keyboard.press('Tab'); await page.keyboard.press('Enter'); - await expect(page).toHaveNoACViolations('Slug-open'); + await expect(page).toHaveNoACViolations('AILabel-open'); }); test.slow('@avt-advanced-states ai form', async ({ page }) => { await visitStory(page, { - component: 'Slug', - id: 'experimental-unstable-slug-form--form-example', + component: 'AILabel', + id: 'components-form--with-ai-label', globals: { theme: 'white', }, }); - await expect(page).toHaveNoACViolations('Slug-form'); + await expect(page).toHaveNoACViolations('AILabel-form'); }); test('@avt-keyboard-nav - slug', async ({ page }) => { await visitStory(page, { component: 'Search', - id: 'experimental-unstable-slug--callout', + id: 'components-ailabel--callout', globals: { theme: 'white', }, @@ -63,7 +63,7 @@ test.describe('@avt Slug', async () => { await expect(slug).toBeVisible(); await expect(callout).toBeVisible(); - // Tab to the Slug + // Tab to the AILabel await page.keyboard.press('Tab'); await expect(slug).toBeFocused(); diff --git a/e2e/components/Slug/Slug-test.e2e.js b/e2e/components/AILabel/Slug-test.e2e.js similarity index 52% rename from e2e/components/Slug/Slug-test.e2e.js rename to e2e/components/AILabel/Slug-test.e2e.js index 31ada475cb88..ac94f60eb1d6 100644 --- a/e2e/components/Slug/Slug-test.e2e.js +++ b/e2e/components/AILabel/Slug-test.e2e.js @@ -1,5 +1,5 @@ /** - * Copyright IBM Corp. 2016, 2023 + * Copyright IBM Corp. 2016, 2024 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. @@ -11,53 +11,53 @@ const { test } = require('@playwright/test'); // eslint-disable-line const { themes } = require('../../test-utils/env'); const { snapshotStory } = require('../../test-utils/storybook'); // eslint-disable-line -test.describe('Slug', () => { +test.describe('AILabel', () => { themes.forEach((theme) => { test.describe(theme, () => { test('default @vrt', async ({ page }) => { await snapshotStory(page, { - component: 'Slug', - id: 'experimental-unstable-slug--default', + component: 'AILabel', + id: 'components-ailabel--default', theme, }); }); - test('slug callout @vrt', async ({ page }) => { + test('AILabel callout @vrt', async ({ page }) => { await snapshotStory(page, { - component: 'Slug', - id: 'experimental-unstable-slug--callout', + component: 'AILabel', + id: 'components-ailabel--callout', theme, }); }); - test('slug inside form @vrt', async ({ page }) => { + test('AILabel inside form @vrt', async ({ page }) => { await snapshotStory(page, { - component: 'Slug', - id: 'experimental-unstable-slug-form--form-example', + component: 'AILabel', + id: 'components-form--with-ai-label', theme, }); }); - test('slug inside DataTable column @vrt', async ({ page }) => { + test('AILabel inside DataTable column @vrt', async ({ page }) => { await snapshotStory(page, { - component: 'Slug', - id: 'experimental-unstable-slug-datatable--column-slug-sort', + component: 'AILabel', + id: 'components-datatable-withailabel--column-ai-label-sort', theme, }); }); - test('slug inside DataTable row @vrt', async ({ page }) => { + test('AILabel inside DataTable row @vrt', async ({ page }) => { await snapshotStory(page, { - component: 'Slug', - id: 'experimental-unstable-slug-datatable--slug-with-selection-and-expansion', + component: 'AILabel', + id: 'components-datatable-withailabel--ai-label-with-selection-and-expansion', theme, }); }); - test('slug inside Tile @vrt', async ({ page }) => { + test('AILabel inside Tile @vrt', async ({ page }) => { await snapshotStory(page, { - component: 'Slug', - id: 'experimental-unstable-slug-examples--tile', + component: 'AILabel', + id: 'components-tile--with-ai-label', theme, }); }); diff --git a/packages/carbon-components-react/scss/components/ai-label/_ai-label.scss b/packages/carbon-components-react/scss/components/ai-label/_ai-label.scss new file mode 100644 index 000000000000..49e0bd5dc557 --- /dev/null +++ b/packages/carbon-components-react/scss/components/ai-label/_ai-label.scss @@ -0,0 +1,9 @@ +// Code generated by carbon-components-react. DO NOT EDIT. +// +// Copyright IBM Corp. 2018, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@forward '@carbon/styles/scss/components/ai-label/ai-label'; diff --git a/packages/carbon-components-react/scss/components/ai-label/_index.scss b/packages/carbon-components-react/scss/components/ai-label/_index.scss new file mode 100644 index 000000000000..3f0e9203e36b --- /dev/null +++ b/packages/carbon-components-react/scss/components/ai-label/_index.scss @@ -0,0 +1,9 @@ +// Code generated by carbon-components-react. DO NOT EDIT. +// +// Copyright IBM Corp. 2018, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@forward '@carbon/styles/scss/components/ai-label'; diff --git a/packages/carbon-components/scss/components/ai-label/_ai-label.scss b/packages/carbon-components/scss/components/ai-label/_ai-label.scss new file mode 100644 index 000000000000..03f1cc5d2bd5 --- /dev/null +++ b/packages/carbon-components/scss/components/ai-label/_ai-label.scss @@ -0,0 +1,9 @@ +// Code generated by carbon-components. DO NOT EDIT. +// +// Copyright IBM Corp. 2018, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@forward '@carbon/styles/scss/components/ai-label/ai-label'; diff --git a/packages/carbon-components/scss/components/ai-label/_index.scss b/packages/carbon-components/scss/components/ai-label/_index.scss new file mode 100644 index 000000000000..181113e5b055 --- /dev/null +++ b/packages/carbon-components/scss/components/ai-label/_index.scss @@ -0,0 +1,9 @@ +// Code generated by carbon-components. DO NOT EDIT. +// +// Copyright IBM Corp. 2018, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@forward '@carbon/styles/scss/components/ai-label'; diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index d4d657b13b23..d8115901c241 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -2,6 +2,154 @@ exports[`Public API should only change with a semver change 1`] = ` Map { + "AILabel" => Object { + "$$typeof": Symbol(react.forward_ref), + "propTypes": Object { + "AILabelContent": Object { + "type": "node", + }, + "aiText": Object { + "type": "string", + }, + "aiTextLabel": [Function], + "align": Object { + "args": Array [ + Array [ + "top", + "top-left", + "top-start", + "top-right", + "top-end", + "bottom", + "bottom-left", + "bottom-start", + "bottom-right", + "bottom-end", + "left", + "left-bottom", + "left-end", + "left-top", + "left-start", + "right", + "right-bottom", + "right-end", + "right-top", + "right-start", + ], + ], + "type": "oneOf", + }, + "aria-label": Object { + "type": "string", + }, + "autoAlign": Object { + "type": "bool", + }, + "children": Object { + "type": "node", + }, + "className": Object { + "type": "string", + }, + "kind": Object { + "args": Array [ + Array [ + "default", + "inline", + ], + ], + "type": "oneOf", + }, + "onRevertClick": Object { + "type": "func", + }, + "revertActive": Object { + "type": "bool", + }, + "revertLabel": Object { + "type": "string", + }, + "size": Object { + "args": Array [ + Array [ + "mini", + "2xs", + "xs", + "sm", + "md", + "lg", + "xl", + ], + ], + "type": "oneOf", + }, + "slugLabel": [Function], + "textLabel": Object { + "type": "string", + }, + }, + "render": [Function], + }, + "AILabelActions" => Object { + "$$typeof": Symbol(react.forward_ref), + "propTypes": Object { + "children": Object { + "type": "node", + }, + "className": Object { + "type": "string", + }, + }, + "render": [Function], + }, + "AILabelContent" => Object { + "$$typeof": Symbol(react.forward_ref), + "propTypes": Object { + "children": Object { + "type": "node", + }, + "className": Object { + "type": "string", + }, + }, + "render": [Function], + }, + "AISkeletonIcon" => Object { + "propTypes": Object { + "className": Object { + "type": "string", + }, + "style": Object { + "type": "object", + }, + }, + }, + "AISkeletonPlaceholder" => Object { + "propTypes": Object { + "className": Object { + "type": "string", + }, + }, + }, + "AISkeletonText" => Object { + "propTypes": Object { + "className": Object { + "type": "string", + }, + "heading": Object { + "type": "bool", + }, + "lineCount": Object { + "type": "number", + }, + "paragraph": Object { + "type": "bool", + }, + "width": Object { + "type": "string", + }, + }, + }, "Accordion" => Object { "propTypes": Object { "align": Object { @@ -10758,12 +10906,13 @@ Map { "unstable__Slug" => Object { "$$typeof": Symbol(react.forward_ref), "propTypes": Object { - "aiText": Object { - "type": "string", + "AILabelContent": Object { + "type": "node", }, - "aiTextLabel": Object { + "aiText": Object { "type": "string", }, + "aiTextLabel": [Function], "align": Object { "args": Array [ Array [ @@ -10791,6 +10940,9 @@ Map { ], "type": "oneOf", }, + "aria-label": Object { + "type": "string", + }, "autoAlign": Object { "type": "bool", }, @@ -10832,10 +10984,8 @@ Map { ], "type": "oneOf", }, - "slugContent": Object { - "type": "node", - }, - "slugLabel": Object { + "slugLabel": [Function], + "textLabel": Object { "type": "string", }, }, diff --git a/packages/react/scss/components/ai-label/_ai-label.scss b/packages/react/scss/components/ai-label/_ai-label.scss new file mode 100644 index 000000000000..849ed4ecaeb1 --- /dev/null +++ b/packages/react/scss/components/ai-label/_ai-label.scss @@ -0,0 +1,9 @@ +// Code generated by @carbon/react. DO NOT EDIT. +// +// Copyright IBM Corp. 2018, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@forward '@carbon/styles/scss/components/ai-label/ai-label'; diff --git a/packages/react/scss/components/ai-label/_index.scss b/packages/react/scss/components/ai-label/_index.scss new file mode 100644 index 000000000000..df5d8475569c --- /dev/null +++ b/packages/react/scss/components/ai-label/_index.scss @@ -0,0 +1,9 @@ +// Code generated by @carbon/react. DO NOT EDIT. +// +// Copyright IBM Corp. 2018, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@forward '@carbon/styles/scss/components/ai-label'; diff --git a/packages/react/src/__tests__/index-test.js b/packages/react/src/__tests__/index-test.js index 3a00bffc61d0..f83f5635a36a 100644 --- a/packages/react/src/__tests__/index-test.js +++ b/packages/react/src/__tests__/index-test.js @@ -15,6 +15,12 @@ describe('Carbon Components React', () => { it('should export components', () => { expect(Object.keys(Carbon).sort()).toMatchInlineSnapshot(` Array [ + "AILabel", + "AILabelActions", + "AILabelContent", + "AISkeletonIcon", + "AISkeletonPlaceholder", + "AISkeletonText", "Accordion", "AccordionItem", "AccordionSkeleton", diff --git a/packages/react/src/components/AILabel/AILabel.mdx b/packages/react/src/components/AILabel/AILabel.mdx new file mode 100644 index 000000000000..6859d7765a53 --- /dev/null +++ b/packages/react/src/components/AILabel/AILabel.mdx @@ -0,0 +1,158 @@ +import { ArgsTable, Canvas, Story } from '@storybook/blocks'; +import { AILabel, AILabelContent, AILabelActions } from '.'; +import * as AILabelStories from './AILabel.stories'; + +# AILabel + +[Source code](https://github.com/carbon-design-system/carbon/tree/main/packages/react/src/components/Slug) +| +[AILabel release status](https://airtable.com/appCAqlGVN8tRUbAp/shr71ZyLlIGORz3Vh/tblHqPusgkK8hIeHo) +| +[Using AI-enhanced components in V10](https://github.com/carbon-design-system/carbon-for-ai/blob/main/docs/support-for-carbon-v10.md) + +## Table of Contents + +- [Overview](#overview) +- [AILabel anatomy](#ailabel-anatomy) +- [Component API](#component-api) + - [AILabel `aiText`](#ailabel-aitext) + - [AILabel `aiTextLabel`](#ailabel-aitextlabel) + - [AILabel `kind`](#ailabel-kind) + - [AILabel `revertActive` and `onRevertClick`](#ailabel-revertactive-and-onrevertclick) +- [Feedback](#feedback) + +## Overview + +The AI Label is intended for any scenario where something is being generated by +(or with) AI to reinforce AI transparency, accountability, and explainability at +any interface level. This also enables more effective recognition and recall of +AI instances in a way that is identifiable across any IBM product. + + + + + +## AILabel anatomy + +The `AILabel` itself is a button that acts as a `Toggletip` trigger. To +construct the contents of the `AILabel` callout, you can place the desired +elements as a child of `AILabel` in `AILabelContent`, like so: + +```jsx + + + {Content Here} + + +``` + +The `AILabel` also supports the rendering of an action bar at the bottom of the +callout. To achieve this, you can pass in `AILabelActions` as a child of +`AILabel`, placed inside the `AILabelContent` + +```jsx + + + {Content Here} + {Optional AILabel action bar} + + + + + + + + + + + + + + +``` + +## Component API + + + +### AILabel `aiText` + +If needed, you can change the text inside the `AILabel` when translating to +different languages. + + + Explanation of AI generated content + + +```jsx + + Explanation of AI-generated content + +``` + +### AILabel `aiTextLabel` + +When using the `inline` variant, you can add text adjacent to the AI label with +the `aiTextLabel` prop. + + + Explanation of AI generated content + +
+ + Explanation of AI generated content + + +```jsx + + Explanation of AI generated content + + + + Explanation of AI generated content + +``` + +### AILabel `kind` + +The `AILabel` component has two variants, `default` and `inline`. + + + AI was used to generate this content + + +```jsx + + AI was used to generate this content + +``` + +The `inline` `AILabel` with the standard icon can also trigger the AI +explainability callout. + + + Explanation of AI generated content + + +```jsx + + Explanation of AI-generated content + +``` + +### AILabel `revertActive` and `onRevertClick` + +`revertActive` is a boolean prop that can be set on `AILabel` that transforms +the `AILabel` into a revert action button. This is useful if a user edits an +AI-generated input to show that the element has been modified. This can be used +in conjunction with the `onRevertClick` callback to handle restoring the element +to the AI-generated state. For an example, please take a look at the +[Revert Test story](https://react.carbondesignsystem.com/?path=/story/experimental-unstable-slug-form--revert-test) +or take a look at the example story +[source code](https://github.com/carbon-design-system/carbon/blob/main/packages/react/src/components/Slug/Slug-form.stories.js#L96). + +## Feedback + +Help us improve this component by providing feedback, asking questions on Slack, +or updating this file on +[GitHub](https://github.com/carbon-design-system/carbon/edit/main/packages/react/src/components/Slug/Slug.mdx). diff --git a/packages/react/src/components/Slug/Slug.stories.js b/packages/react/src/components/AILabel/AILabel.stories.js similarity index 74% rename from packages/react/src/components/Slug/Slug.stories.js rename to packages/react/src/components/AILabel/AILabel.stories.js index c8d80183a84d..c4172e8ea939 100644 --- a/packages/react/src/components/Slug/Slug.stories.js +++ b/packages/react/src/components/AILabel/AILabel.stories.js @@ -1,24 +1,22 @@ /** - * Copyright IBM Corp. 2016, 2023 + * Copyright IBM Corp. 2016, 2024 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ -/* eslint-disable no-console */ - import React from 'react'; -import { Slug, SlugContent, SlugActions } from '.'; +import { AILabel, AILabelContent, AILabelActions } from '.'; import { View, FolderOpen, Folders } from '@carbon/icons-react'; import Button from '../Button'; import { IconButton } from '../IconButton'; -import mdx from './Slug.mdx'; -import './slug-story.scss'; +import mdx from './AILabel.mdx'; +import './ailabel-story.scss'; export default { - title: 'Experimental/unstable__Slug', - component: Slug, + title: 'Components/AILabel', + component: AILabel, parameters: { docs: { page: mdx, @@ -44,16 +42,16 @@ const aiContent = ( export const Default = () => ( <>
- - {aiContent} - - - {aiContent} - - - + + {aiContent} + + + {aiContent} + + + {aiContent} - + @@ -64,13 +62,13 @@ export const Default = () => ( - - - - - + + + + + {aiContent} - + @@ -81,13 +79,13 @@ export const Default = () => ( - - - - - + + + + + {aiContent} - + @@ -98,13 +96,13 @@ export const Default = () => ( - - - - - + + + + + {aiContent} - + @@ -115,13 +113,13 @@ export const Default = () => ( - - - - - + + + + + {aiContent} - + @@ -132,15 +130,15 @@ export const Default = () => ( - - - + + +
- - + + {aiContent} - + @@ -151,13 +149,13 @@ export const Default = () => ( - - - - - + + + + + {aiContent} - + @@ -168,13 +166,13 @@ export const Default = () => ( - - - - - + + + + + {aiContent} - + @@ -185,15 +183,15 @@ export const Default = () => ( - - - + + +
- - + + {aiContent} - + @@ -204,13 +202,13 @@ export const Default = () => ( - - - - - + + + + + {aiContent} - + @@ -221,13 +219,13 @@ export const Default = () => ( - - - - - + + + + + {aiContent} - + @@ -238,9 +236,9 @@ export const Default = () => ( - - - + + +
); @@ -250,8 +248,8 @@ export const Callout = (args) => { return (
- - + + {' '}

AI Explained

@@ -267,7 +265,7 @@ export const Callout = (args) => {

Foundation model

{showSlugActions && ( - + @@ -278,10 +276,10 @@ export const Callout = (args) => { - + )} -
-
+ +
); }; @@ -318,6 +316,11 @@ Callout.argTypes = { disable: true, }, }, + AILabelContent: { + table: { + disable: true, + }, + }, aiText: { table: { disable: true, @@ -373,6 +376,11 @@ Callout.argTypes = { disable: true, }, }, + textLabel: { + table: { + disable: true, + }, + }, }; export const Playground = (args) => { @@ -393,7 +401,7 @@ export const Playground = (args) => {

Foundation model

{showSlugActions && ( - + @@ -404,7 +412,7 @@ export const Playground = (args) => { - + )} ); @@ -412,9 +420,9 @@ export const Playground = (args) => { return ( <>
- - {renderedContent} - + + {renderedContent} +
@@ -449,4 +457,34 @@ Playground.argTypes = { ], control: { type: 'select' }, }, + AILabelContent: { + table: { + disable: true, + }, + }, + children: { + table: { + disable: true, + }, + }, + className: { + table: { + disable: true, + }, + }, + onRevertClick: { + table: { + disable: true, + }, + }, + revertActive: { + table: { + disable: true, + }, + }, + revertLabel: { + table: { + disable: true, + }, + }, }; diff --git a/packages/react/src/components/Slug/SlugDatatable.mdx b/packages/react/src/components/AILabel/AILabelDatatable.mdx similarity index 62% rename from packages/react/src/components/Slug/SlugDatatable.mdx rename to packages/react/src/components/AILabel/AILabelDatatable.mdx index fe6a4551d06c..0fb68621debd 100644 --- a/packages/react/src/components/Slug/SlugDatatable.mdx +++ b/packages/react/src/components/AILabel/AILabelDatatable.mdx @@ -1,20 +1,20 @@ -import { ArgsTable, Canvas, Story } from '@storybook/blocks'; -import { Slug, SlugContent, SlugActions } from '.'; -import * as SlugStories from '../DataTable/stories/DataTable-slug.stories'; +import { Story, ArgsTable, Canvas, Meta } from '@storybook/blocks'; +import { AILabel, AILabelContent, AILabelActions } from '.'; +import * as AILabelStories from '../DataTable/stories/DataTable-ai-label.stories'; -# Slug +# AILabel [Source code](https://github.com/carbon-design-system/carbon/tree/main/packages/react/src/components/Slug) | -[Slug release status](https://airtable.com/appCAqlGVN8tRUbAp/shr71ZyLlIGORz3Vh/tblHqPusgkK8hIeHo) +[AILabel release status](https://airtable.com/appCAqlGVN8tRUbAp/shr71ZyLlIGORz3Vh/tblHqPusgkK8hIeHo) | [Using AI-enhanced components in V10](https://github.com/carbon-design-system/carbon-for-ai/blob/main/docs/support-for-carbon-v10.md) ## Table of Contents - [Overview](#overview) -- [Slug anatomy](#slug-anatomy) -- [Using Slug in DataTable](#using-slug-in-datatable) +- [AILabel anatomy](#ailabel-anatomy) +- [Using AILabel in DataTable](#using-ailabel-in-datatable) - [Using as a column header](#using-as-a-column-header) - [Using in a row](#using-in-a-row) - [Feedback](#feedback) @@ -24,34 +24,37 @@ import * as SlugStories from '../DataTable/stories/DataTable-slug.stories'; The `DataTable` supports placing a `slug` in both the column header and row. - - + -## Slug anatomy + + + + +## AILabel anatomy -The `Slug` itself is a button that acts as a `Toggletip` trigger. To construct -the contents of the `Slug` callout, you can place the desired elements as a -child of `Slug` in `SlugContent`, like so: +The `AILabel` itself is a button that acts as a `Toggletip` trigger. To +construct the contents of the `AILabel` callout, you can place the desired +elements as a child of `AILabel` in `AILabelContent`, like so: ```jsx - - + + {Content Here} - - + + ``` -The `Slug` also supports the rendering of an action bar at the bottom of the -callout. To achieve this, you can pass in `SlugActions` as a child of `Slug`, -placed inside the `SlugContent` +The `AILabel` also supports the rendering of an action bar at the bottom of the +callout. To achieve this, you can pass in `AILabelActions` as a child of +`AILabel`, placed inside the `AILabelContent` ```jsx - - + + {Content Here} {Optional Slug action bar} - + @@ -62,20 +65,20 @@ placed inside the `SlugContent` - - - + + + ``` -## Using `slug` in `DataTable` +## Using `AILabel` in `DataTable` ### Using as a column header -To use a `Slug` inside a column header, you'll need to add a `slug` to the +To use an `AILabel` inside a column header, you'll need to add a `slug` to the appropriate column data. ```jsx -const columnSlugHeaders = [ +const columnAILabelHeaders = [ { key: 'name', header: 'Name', @@ -84,8 +87,11 @@ const columnSlugHeaders = [ key: 'attached_groups', header: 'Attached groups', slug: ( - - + +

AI Explained

84%

@@ -99,7 +105,7 @@ const columnSlugHeaders = [

Model type

Foundation model

- + @@ -110,9 +116,9 @@ const columnSlugHeaders = [ - -
-
+ + + ), }, ]; @@ -129,8 +135,8 @@ To ensure the table cells are styled appropriately, you'll need to use the new ### Using in a row -To use a `Slug` inside a `DataTable` row, you'll need to pass in your `Slug` -component to `TableSlugRow`: +To use an `AILabel` inside a `DataTable` row, you'll need to pass in your +`AILabel` component to `TableSlugRow`: ```jsx diff --git a/packages/react/src/components/Slug/__tests__/Slug-test.js b/packages/react/src/components/AILabel/__tests__/AILabel-test.js similarity index 61% rename from packages/react/src/components/Slug/__tests__/Slug-test.js rename to packages/react/src/components/AILabel/__tests__/AILabel-test.js index 7b8fd1d7d137..43d24cb46d6b 100644 --- a/packages/react/src/components/Slug/__tests__/Slug-test.js +++ b/packages/react/src/components/AILabel/__tests__/AILabel-test.js @@ -1,20 +1,20 @@ /** - * Copyright IBM Corp. 2016, 2023 + * Copyright IBM Corp. 2016, 2024 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ import React from 'react'; -import { Slug } from '../../Slug'; +import { AILabel } from '../'; import { render, screen } from '@testing-library/react'; const prefix = 'cds'; -describe('Slug', () => { +describe('AILabel', () => { describe('renders as expected - Component API', () => { it('should spread extra props onto the popover element', () => { - const { container } = render(); + const { container } = render(); expect(container.firstChild.firstChild).toHaveAttribute( 'data-testid', @@ -23,32 +23,45 @@ describe('Slug', () => { }); it('should render children as expected', () => { - render(Children test); + render(Children test); expect(screen.getByText('Children test')).toBeInTheDocument(); }); it('should support a custom `className` prop on the outermost element', () => { - const { container } = render(); + const { container } = render(); expect(container.firstChild).toHaveClass('custom-class'); }); it('should respect aiText prop', () => { - render(); + render(); expect(screen.getByText('IA')).toBeInTheDocument(); }); - it('should respect aiTextLabel prop', () => { - render(); + it('should respect textLabel prop when kind is inline', () => { + const wrapper = render(); - expect(screen.getByText('Test text')).toBeInTheDocument(); + const additionalTextSpan = wrapper.container.querySelector( + `.${prefix}--slug__additional-text` + ); + expect(additionalTextSpan).toBeInTheDocument(); + expect(additionalTextSpan).toHaveTextContent('Test text'); + }); + + it('should not populate textLabel prop when kind is not inline', () => { + const wrapper = render(); + + const additionalTextSpan = wrapper.container.querySelector( + `.${prefix}--slug__additional-text` + ); + expect(additionalTextSpan).not.toBeInTheDocument(); }); it('should respect align prop when autoAlign is false', () => { render( - + ); expect(screen.getByTestId('test')).not.toHaveClass( @@ -60,7 +73,7 @@ describe('Slug', () => { }); it('should apply align prop classes even when autoAlign is true', () => { - render(); + render(); expect(screen.getByTestId('test')).toHaveClass( `${prefix}--popover--auto-align` @@ -71,7 +84,7 @@ describe('Slug', () => { }); it('should respect kind prop', () => { - render(); + render(); expect(screen.getByRole('button')).toHaveClass( `${prefix}--slug__button--inline` @@ -79,7 +92,7 @@ describe('Slug', () => { }); it('should respect revertActive prop', () => { - const { container } = render(); + const { container } = render(); expect(container.firstChild).toHaveClass(`${prefix}--slug--revert`); expect(container.firstChild.firstChild).toHaveClass( @@ -88,13 +101,13 @@ describe('Slug', () => { }); it('should respect revertLabel prop', () => { - render(); + render(); expect(screen.getByText('Test revert label')).toBeInTheDocument(); }); it('should respect size prop', () => { - render(); + render(); expect(screen.getByRole('button')).toHaveClass( `${prefix}--slug__button--xl` diff --git a/packages/react/src/components/Slug/slug-story.scss b/packages/react/src/components/AILabel/ailabel-story.scss similarity index 95% rename from packages/react/src/components/Slug/slug-story.scss rename to packages/react/src/components/AILabel/ailabel-story.scss index 6af2dee0b80d..181c2edd6123 100644 --- a/packages/react/src/components/Slug/slug-story.scss +++ b/packages/react/src/components/AILabel/ailabel-story.scss @@ -1,3 +1,10 @@ +/** + * Copyright IBM Corp. 2016, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + @use '@carbon/styles/scss/type'; @use '@carbon/styles/scss/theme'; @use '@carbon/react/scss/components/tile'; diff --git a/packages/react/src/components/Slug/index.js b/packages/react/src/components/AILabel/index.js similarity index 64% rename from packages/react/src/components/Slug/index.js rename to packages/react/src/components/AILabel/index.js index 8a87f418bc46..0ef644a03c3e 100644 --- a/packages/react/src/components/Slug/index.js +++ b/packages/react/src/components/AILabel/index.js @@ -1,5 +1,5 @@ /** - * Copyright IBM Corp. 2016, 2023 + * Copyright IBM Corp. 2016, 2024 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. @@ -19,31 +19,32 @@ import { import { IconButton } from '../IconButton'; import { Undo } from '@carbon/icons-react'; import { useId } from '../../internal/useId'; +import deprecate from '../../prop-types/deprecate'; -export const SlugContent = React.forwardRef(function SlugContent( +export const AILabelContent = React.forwardRef(function AILabelContent( { children, className }, ref ) { const prefix = usePrefix(); - const hasSlugActions = React.Children.toArray(children).some( - (child) => child.type?.displayName === 'SlugActions' + const hasAILabelActions = React.Children.toArray(children).some( + (child) => child.type?.displayName === 'AILabelActions' ); - const slugContentClasses = cx(className, { + const aiLabelContentClasses = cx(className, { [`${prefix}--slug-content`]: true, - [`${prefix}--slug-content--with-actions`]: hasSlugActions, + [`${prefix}--slug-content--with-actions`]: hasAILabelActions, }); return ( - + {children} ); }); -SlugContent.displayName = 'SlugContent'; -SlugContent.propTypes = { +AILabelContent.displayName = 'AILabelContent'; +AILabelContent.propTypes = { /** * Specify the content you want rendered inside the slug ToggleTip */ @@ -55,25 +56,25 @@ SlugContent.propTypes = { className: PropTypes.string, }; -export const SlugActions = React.forwardRef(function SlugActions( +export const AILabelActions = React.forwardRef(function AILabelActions( { children, className }, ref ) { const prefix = usePrefix(); - const slugActionBarClasses = cx(className, { + const aiLabelActionsClasses = cx(className, { [`${prefix}--slug-actions`]: true, }); return ( - + {children} ); }); -SlugActions.displayName = 'SlugActions'; -SlugActions.propTypes = { +AILabelActions.displayName = 'AILabelActions'; +AILabelActions.propTypes = { /** * Specify the content you want rendered inside the slug callout toolbar */ @@ -85,10 +86,11 @@ SlugActions.propTypes = { className: PropTypes.string, }; -export const Slug = React.forwardRef(function Slug( +export const AILabel = React.forwardRef(function AILabel( { aiText = 'AI', aiTextLabel, + textLabel, align, autoAlign = true, children, @@ -98,25 +100,26 @@ export const Slug = React.forwardRef(function Slug( revertActive, revertLabel = 'Revert to AI input', slugLabel = 'Show information', + ['aria-label']: ariaLabel = 'Show information', size = 'xs', ...rest }, ref ) { const prefix = usePrefix(); - const id = useId('slug'); + const id = useId('AILabel'); - const slugClasses = cx(className, { + const aiLabelClasses = cx(className, { [`${prefix}--slug`]: true, [`${prefix}--slug--revert`]: revertActive, }); - const slugButtonClasses = cx({ + const aiLabelButtonClasses = cx({ [`${prefix}--slug__button`]: true, [`${prefix}--slug__button--${size}`]: size, [`${prefix}--slug__button--${kind}`]: kind, [`${prefix}--slug__button--inline-with-content`]: - kind === 'inline' && aiTextLabel, + kind === 'inline' && (aiTextLabel || textLabel), }); const handleOnRevertClick = (evt) => { @@ -125,12 +128,13 @@ export const Slug = React.forwardRef(function Slug( } }; - const ariaLabel = !aiTextLabel - ? `${aiText} - ${slugLabel}` - : `${aiText} - ${aiTextLabel}`; + const ariaLabelText = + !aiTextLabel && !textLabel + ? `${aiText} - ${slugLabel || ariaLabel}` + : `${aiText} - ${aiTextLabel || textLabel}`; return ( -
+
{revertActive ? ( ) : ( - + {aiText} - {aiTextLabel && ( + {kind === 'inline' && (aiTextLabel || textLabel) && ( - {aiTextLabel} + {aiTextLabel || textLabel} )} @@ -157,17 +163,26 @@ export const Slug = React.forwardRef(function Slug( ); }); -Slug.displayName = 'Slug'; -Slug.propTypes = { +AILabel.displayName = 'AILabel'; +AILabel.propTypes = { + /** + * Specify the content you want rendered inside the `AILabel` ToggleTip + */ + AILabelContent: PropTypes.node, + /** * Specify the correct translation of the AI text */ aiText: PropTypes.string, /** + * @deprecated * Specify additional text to be rendered next to the AI label in the inline variant */ - aiTextLabel: PropTypes.string, + aiTextLabel: deprecate( + PropTypes.string, + '`aiTextLabel` on `AILabel` has been deprecated - Please use the `textLabel` prop instead' + ), /** * Specify how the popover should align with the button @@ -198,23 +213,28 @@ Slug.propTypes = { 'right-start', ]), + /** + * Specify the text that will be provided to the aria-label of the `AILabel` button + */ + 'aria-label': PropTypes.string, + /** * Will auto-align the popover. This prop is currently experimental and is subject to future changes. */ autoAlign: PropTypes.bool, /** - * Specify the content you want rendered inside the slug ToggleTip + * Specify the content you want rendered inside the `AILabel` ToggleTip */ children: PropTypes.node, /** - * Specify an optional className to be added to the AI slug + * Specify an optional className to be added to the `AILabel` */ className: PropTypes.string, /** - * Specify the type of Slug, from the following list of types: + * Specify the type of `AILabel`, from the following list of types: */ kind: PropTypes.oneOf(['default', 'inline']), @@ -239,12 +259,16 @@ Slug.propTypes = { size: PropTypes.oneOf(['mini', '2xs', 'xs', 'sm', 'md', 'lg', 'xl']), /** - * Specify the content you want rendered inside the slug ToggleTip + * @deprecated + * Specify the text that will be provided to the aria-label of the `AILabel` button */ - slugContent: PropTypes.node, + slugLabel: deprecate( + PropTypes.string, + '`slugLabel` on `AILabel` has been deprecated - Please use the `ariaLabel` prop instead' + ), /** - * Specify the text that will be provided to the aria-label of the `Slug` button + * Specify additional text to be rendered next to the AI label in the inline variant */ - slugLabel: PropTypes.string, + textLabel: PropTypes.string, }; diff --git a/packages/react/src/components/AiSkeleton/AiSkeletonIcon.stories.js b/packages/react/src/components/AISkeleton/AISkeletonIcon.stories.js similarity index 63% rename from packages/react/src/components/AiSkeleton/AiSkeletonIcon.stories.js rename to packages/react/src/components/AISkeleton/AISkeletonIcon.stories.js index 0c435924623e..1d7b7ab68fad 100644 --- a/packages/react/src/components/AiSkeleton/AiSkeletonIcon.stories.js +++ b/packages/react/src/components/AISkeleton/AISkeletonIcon.stories.js @@ -9,11 +9,11 @@ import React from 'react'; -import AiSkeletonIcon from './AiSkeletonIcon'; +import AISkeletonIcon from './AISkeletonIcon'; export default { - title: 'Experimental/unstable__AiSkeleton/AiSkeletonIcon', - component: AiSkeletonIcon, + title: 'Components/Skeleton/AISkeleton', + component: AISkeletonIcon, }; const propsSkeleton = { @@ -30,9 +30,9 @@ const propsSkeleton2 = { }, }; -export const Default = () => ( +export const _AISkeletonIcon = () => ( <> - - + + ); diff --git a/packages/react/src/components/AiSkeleton/AiSkeletonIcon.tsx b/packages/react/src/components/AISkeleton/AISkeletonIcon.tsx similarity index 73% rename from packages/react/src/components/AiSkeleton/AiSkeletonIcon.tsx rename to packages/react/src/components/AISkeleton/AISkeletonIcon.tsx index e85843607273..7fc8a43cdba3 100644 --- a/packages/react/src/components/AiSkeleton/AiSkeletonIcon.tsx +++ b/packages/react/src/components/AISkeleton/AISkeletonIcon.tsx @@ -11,7 +11,7 @@ import classNames from 'classnames'; import { usePrefix } from '../../internal/usePrefix'; import { SkeletonIcon } from '../SkeletonIcon'; -interface AiSkeletonIconProps { +interface AISkeletonIconProps { /** * Specify an optional className to add. */ @@ -23,16 +23,16 @@ interface AiSkeletonIconProps { style?: React.CSSProperties; } -const AiSkeletonIcon = ({ className, ...rest }: AiSkeletonIconProps) => { +const AISkeletonIcon = ({ className, ...rest }: AISkeletonIconProps) => { const prefix = usePrefix(); - const AiSkeletonIconClasses = classNames(className, { + const AISkeletonIconClasses = classNames(className, { [`${prefix}--skeleton__icon--ai`]: true, }); - return ; + return ; }; -AiSkeletonIcon.propTypes = { +AISkeletonIcon.propTypes = { /** * Specify an optional className to add. */ @@ -44,4 +44,4 @@ AiSkeletonIcon.propTypes = { style: PropTypes.object, }; -export default AiSkeletonIcon; +export default AISkeletonIcon; diff --git a/packages/react/src/components/AiSkeleton/AiSkeletonPlaceholder.stories.js b/packages/react/src/components/AISkeleton/AISkeletonPlaceholder.stories.js similarity index 52% rename from packages/react/src/components/AiSkeleton/AiSkeletonPlaceholder.stories.js rename to packages/react/src/components/AISkeleton/AISkeletonPlaceholder.stories.js index 5a6b323c50bf..1ff7389fd211 100644 --- a/packages/react/src/components/AiSkeleton/AiSkeletonPlaceholder.stories.js +++ b/packages/react/src/components/AISkeleton/AISkeletonPlaceholder.stories.js @@ -9,11 +9,13 @@ import React from 'react'; -import AiSkeletonPlaceholder from './AiSkeletonPlaceholder'; +import AISkeletonPlaceholder from './AISkeletonPlaceholder'; export default { - title: 'Experimental/unstable__AiSkeleton/AiSkeletonPlaceholder', - component: AiSkeletonPlaceholder, + title: 'Components/Skeleton/AISkeleton', + component: AISkeletonPlaceholder, }; -export const Default = () => ; +export const _AISkeletonPlaceholder = () => ( + +); diff --git a/packages/react/src/components/AiSkeleton/AiSkeletonPlaceholder.tsx b/packages/react/src/components/AISkeleton/AISkeletonPlaceholder.tsx similarity index 72% rename from packages/react/src/components/AiSkeleton/AiSkeletonPlaceholder.tsx rename to packages/react/src/components/AISkeleton/AISkeletonPlaceholder.tsx index cc5e849a4fb9..300c76a36b16 100644 --- a/packages/react/src/components/AiSkeleton/AiSkeletonPlaceholder.tsx +++ b/packages/react/src/components/AISkeleton/AISkeletonPlaceholder.tsx @@ -11,29 +11,29 @@ import classNames from 'classnames'; import { usePrefix } from '../../internal/usePrefix'; import { SkeletonPlaceholder } from '../SkeletonPlaceholder'; -export interface AiSkeletonPlaceholderProps { +export interface AISkeletonPlaceholderProps { /** * Add a custom class to the component to set the height and width */ className?: string; } -const AiSkeletonPlaceholder = ({ +const AISkeletonPlaceholder = ({ className, ...other -}: AiSkeletonPlaceholderProps) => { +}: AISkeletonPlaceholderProps) => { const prefix = usePrefix(); - const AiSkeletonPlaceholderClasses = classNames( + const AISkeletonPlaceholderClasses = classNames( { className, [`${prefix}--skeleton__placeholder--ai`]: true }, className ); return ( - + ); }; -AiSkeletonPlaceholder.propTypes = { +AISkeletonPlaceholder.propTypes = { /** * Add a custom class to the component * to set the height and width @@ -41,4 +41,4 @@ AiSkeletonPlaceholder.propTypes = { className: PropTypes.string, }; -export default AiSkeletonPlaceholder; +export default AISkeletonPlaceholder; diff --git a/packages/react/src/components/AISkeleton/AISkeletonText.stories.js b/packages/react/src/components/AISkeleton/AISkeletonText.stories.js new file mode 100644 index 000000000000..972200aeab5a --- /dev/null +++ b/packages/react/src/components/AISkeleton/AISkeletonText.stories.js @@ -0,0 +1,19 @@ +/** + * Copyright IBM Corp. 2016, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/* eslint-disable no-console */ + +import React from 'react'; + +import AISkeletonText from './AISkeletonText'; + +export default { + title: 'Components/Skeleton/AISkeleton', + component: AISkeletonText, +}; + +export const _AISkeletonText = () => ; diff --git a/packages/react/src/components/AiSkeleton/AiSkeletonText.tsx b/packages/react/src/components/AISkeleton/AISkeletonText.tsx similarity index 91% rename from packages/react/src/components/AiSkeleton/AiSkeletonText.tsx rename to packages/react/src/components/AISkeleton/AISkeletonText.tsx index 69a1b3a085e1..c17fb6030b48 100644 --- a/packages/react/src/components/AiSkeleton/AiSkeletonText.tsx +++ b/packages/react/src/components/AISkeleton/AISkeletonText.tsx @@ -11,7 +11,7 @@ import classNames from 'classnames'; import { usePrefix } from '../../internal/usePrefix'; import { SkeletonText } from '../SkeletonText'; -interface AiSkeletonTextProps { +interface AISkeletonTextProps { /** * Specify an optional className to be applied to the container node. */ @@ -38,7 +38,7 @@ interface AiSkeletonTextProps { width?: string; } -const AiSkeletonText = ({ className, ...rest }: AiSkeletonTextProps) => { +const AISkeletonText = ({ className, ...rest }: AISkeletonTextProps) => { const prefix = usePrefix(); const aiSkeletonTextClasses = classNames(className, { [`${prefix}--skeleton__text--ai`]: true, @@ -47,7 +47,7 @@ const AiSkeletonText = ({ className, ...rest }: AiSkeletonTextProps) => { return ; }; -AiSkeletonText.propTypes = { +AISkeletonText.propTypes = { /** * Specify an optional className to be applied to the container node */ @@ -70,4 +70,4 @@ AiSkeletonText.propTypes = { width: PropTypes.string, }; -export default AiSkeletonText; +export default AISkeletonText; diff --git a/packages/react/src/components/AISkeleton/index.tsx b/packages/react/src/components/AISkeleton/index.tsx new file mode 100644 index 000000000000..14a464b122be --- /dev/null +++ b/packages/react/src/components/AISkeleton/index.tsx @@ -0,0 +1,12 @@ +/** + * Copyright IBM Corp. 2016, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import AISkeletonPlaceholder from './AISkeletonPlaceholder'; +import AISkeletonIcon from './AISkeletonIcon'; +import AISkeletonText from './AISkeletonText'; + +export { AISkeletonText, AISkeletonIcon, AISkeletonPlaceholder }; diff --git a/packages/react/src/components/AiSkeleton/AiSkeletonText.stories.js b/packages/react/src/components/AiSkeleton/AiSkeletonText.stories.js deleted file mode 100644 index 5f75ea23a228..000000000000 --- a/packages/react/src/components/AiSkeleton/AiSkeletonText.stories.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright IBM Corp. 2016, 2024 - * - * This source code is licensed under the Apache-2.0 license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* eslint-disable no-console */ - -import React from 'react'; - -import AiSkeletonText from './AiSkeletonText'; - -export default { - title: 'Experimental/unstable__AiSkeleton/AiSkeletonText', - component: AiSkeletonText, -}; - -export const Default = () => ; - -export const Playground = (args) => ; - -Playground.args = { - heading: false, - paragraph: false, - width: '100%', - lineCount: 3, -}; - -Playground.argTypes = { - className: { - control: false, - }, - heading: { - control: { - type: 'boolean', - }, - }, - paragraph: { - control: { - type: 'boolean', - }, - }, - width: { - control: { - type: 'text', - }, - }, - lineCount: { - control: { - type: 'number', - }, - }, -}; diff --git a/packages/react/src/components/AiSkeleton/index.tsx b/packages/react/src/components/AiSkeleton/index.tsx deleted file mode 100644 index 439f4ce25736..000000000000 --- a/packages/react/src/components/AiSkeleton/index.tsx +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright IBM Corp. 2016, 2024 - * - * This source code is licensed under the Apache-2.0 license found in the - * LICENSE file in the root directory of this source tree. - */ - -import AiSkeletonPlaceholder from './AiSkeletonPlaceholder'; -import AiSkeletonIcon from './AiSkeletonIcon'; -import AiSkeletonText from './AiSkeletonText'; - -export { AiSkeletonText, AiSkeletonIcon, AiSkeletonPlaceholder }; diff --git a/packages/react/src/components/Checkbox/Checkbox.stories.js b/packages/react/src/components/Checkbox/Checkbox.stories.js index c556daff677b..40cd2e5bea5e 100644 --- a/packages/react/src/components/Checkbox/Checkbox.stories.js +++ b/packages/react/src/components/Checkbox/Checkbox.stories.js @@ -6,9 +6,14 @@ */ import React from 'react'; +import '../AILabel/ailabel-story.scss'; import { default as Checkbox, CheckboxSkeleton } from './'; import mdx from './Checkbox.mdx'; import CheckboxGroup from '../CheckboxGroup'; +import Button from '../Button'; +import { AILabel, AILabelContent, AILabelActions } from '../AILabel'; +import { IconButton } from '../IconButton'; +import { View, FolderOpen, Folders } from '@carbon/icons-react'; const checkboxEvents = { className: 'some-class', @@ -86,6 +91,75 @@ export const Single = () => { export const Skeleton = () => ; +const slugFunc = (kind) => ( + + +
+

AI Explained

+

84%

+

Confidence score

+

+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

+
+

Model type

+

Foundation model

+
+ + + + + + + + + + + + +
+
+); + +export const withAILabel = () => ( +
+ + + + + + + + + + + + + + + + + +
+); + export const Playground = (args) => ( { defaultChecked labelText="Checkbox label" id="checkbox-label-1" - slug={} + slug={} /> ); diff --git a/packages/react/src/components/CheckboxGroup/CheckboxGroup-test.js b/packages/react/src/components/CheckboxGroup/CheckboxGroup-test.js index 3426a611efe3..48daafcba87c 100644 --- a/packages/react/src/components/CheckboxGroup/CheckboxGroup-test.js +++ b/packages/react/src/components/CheckboxGroup/CheckboxGroup-test.js @@ -9,7 +9,7 @@ import React from 'react'; import CheckboxGroup from '../CheckboxGroup'; import Checkbox from '../Checkbox/Checkbox'; import { render, screen } from '@testing-library/react'; -import { Slug } from '../Slug'; +import { AILabel } from '../AILabel'; const prefix = 'cds'; @@ -155,7 +155,7 @@ describe('CheckboxGroup', () => { } + slug={} /> ); diff --git a/packages/react/src/components/CheckboxGroup/CheckboxGroup.tsx b/packages/react/src/components/CheckboxGroup/CheckboxGroup.tsx index d7cfc299cfba..f03104bfa542 100644 --- a/packages/react/src/components/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/react/src/components/CheckboxGroup/CheckboxGroup.tsx @@ -76,7 +76,7 @@ const CheckboxGroup: React.FC = ({ let normalizedSlug; if ( React.isValidElement(slug) && - (slug['type'] as any)?.displayName === 'Slug' + (slug['type'] as any)?.displayName === 'AILabel' ) { normalizedSlug = React.cloneElement(slug, { size: 'mini', diff --git a/packages/react/src/components/ComboBox/ComboBox-test.js b/packages/react/src/components/ComboBox/ComboBox-test.js index 726d7a23f0fa..53b6f51164ee 100644 --- a/packages/react/src/components/ComboBox/ComboBox-test.js +++ b/packages/react/src/components/ComboBox/ComboBox-test.js @@ -18,7 +18,7 @@ import { waitForPosition, } from '../ListBox/test-helpers'; import ComboBox from '../ComboBox'; -import { Slug } from '../Slug'; +import { AILabel } from '../AILabel'; const findInputNode = () => screen.getByRole('combobox'); const openMenu = async () => { @@ -224,7 +224,9 @@ describe('ComboBox', () => { }); it('should respect slug prop', async () => { - const { container } = render(} />); + const { container } = render( + } /> + ); await waitForPosition(); expect(container.firstChild).toHaveClass( `${prefix}--list-box__wrapper--slug` diff --git a/packages/react/src/components/ComboBox/ComboBox.stories.js b/packages/react/src/components/ComboBox/ComboBox.stories.js index 916f7777baae..87fd1290a310 100644 --- a/packages/react/src/components/ComboBox/ComboBox.stories.js +++ b/packages/react/src/components/ComboBox/ComboBox.stories.js @@ -10,6 +10,10 @@ import React from 'react'; import { WithLayer } from '../../../.storybook/templates/WithLayer'; import ComboBox from '../ComboBox'; +import Button from '../Button'; +import { AILabel, AILabelContent, AILabelActions } from '../AILabel'; +import { IconButton } from '../IconButton'; +import { View, FolderOpen, Folders } from '@carbon/icons-react'; import mdx from './ComboBox.mdx'; const items = [ @@ -129,6 +133,51 @@ export const _WithLayer = () => ( ); +const aiLabel = ( + + +
+

AI Explained

+

84%

+

Confidence score

+

+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

+
+

Model type

+

Foundation model

+
+ + + + + + + + + + + + +
+
+); + +export const withAILabel = () => ( +
+ {}} + id="carbon-combobox" + items={items} + itemToString={(item) => (item ? item.text : '')} + titleText="ComboBox title" + helperText="Combobox helper text" + slug={aiLabel} + /> +
+); + export const Playground = (args) => (
, { size: 'mini', }); diff --git a/packages/react/src/components/ComposedModal/ComposedModal-test.js b/packages/react/src/components/ComposedModal/ComposedModal-test.js index ec93a9137786..759785da02be 100644 --- a/packages/react/src/components/ComposedModal/ComposedModal-test.js +++ b/packages/react/src/components/ComposedModal/ComposedModal-test.js @@ -14,7 +14,7 @@ import ComposedModal, { ModalBody } from './ComposedModal'; import { ModalHeader } from './ModalHeader'; import { ModalFooter } from './ModalFooter'; import { TextInput } from '../../'; -import { Slug } from '../Slug'; +import { AILabel } from '../AILabel'; const prefix = 'cds'; @@ -235,7 +235,7 @@ describe('ComposedModal', () => { it('should respect slug prop', () => { const { container } = render( - }> + }> Modal header This is the modal body content { ); }; +const aiLabel = ( + + +
+

AI Explained

+

84%

+

Confidence score

+

+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

+
+

Model type

+

Foundation model

+
+ + + + + + + + + + + + +
+
+); + +export const _withAILabel = { + render: () => { + const [open, setOpen] = useState(true); // eslint-disable-line + return ( +
+ + setOpen(false)} + slug={aiLabel}> + + +

+ Custom domains direct requests for your apps in this Cloud Foundry + organization to a URL that you own. A custom domain can be a + shared domain, a shared subdomain, or a shared domain and host. +

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus + eu nibh odio. Nunc a consequat est, id porttitor sapien. Proin + vitae leo vitae orci tincidunt auctor eget eget libero. Ut + tincidunt ultricies fringilla. Aliquam erat volutpat. Aenean arcu + odio, elementum vel vehicula vitae, porttitor ac lorem. Sed + viverra elit ac risus tincidunt fermentum. Ut sollicitudin nibh id + risus ornare ornare. Etiam gravida orci ut lectus dictum, quis + ultricies felis mollis. Mauris nec commodo est, nec faucibus nibh. + Nunc commodo ante quis pretium consectetur. Ut ac nisl vitae mi + mattis vulputate a at elit. Nullam porttitor ex eget mi feugiat + mattis. Nunc non sodales magna. Proin ornare tellus quis hendrerit + egestas. Donec pharetra leo nec molestie sollicitudin. +

+ + + +

+ Custom domains direct requests for your apps in this Cloud Foundry + organization to a URL that you own. A custom domain can be a + shared domain, a shared subdomain, or a shared domain and host. +

+ +
+ + +
+
+ ); + }, +}; + export const Playground = (args) => { const [open, setOpen] = useState(true); return ( diff --git a/packages/react/src/components/ComposedModal/ComposedModal.tsx b/packages/react/src/components/ComposedModal/ComposedModal.tsx index a624067e627a..338a072cbeb8 100644 --- a/packages/react/src/components/ComposedModal/ComposedModal.tsx +++ b/packages/react/src/components/ComposedModal/ComposedModal.tsx @@ -410,7 +410,7 @@ const ComposedModal = React.forwardRef( // Slug is always size `sm` let normalizedSlug; - if (slug && slug['type']?.displayName === 'Slug') { + if (slug && slug['type']?.displayName === 'AILabel') { normalizedSlug = React.cloneElement(slug as React.ReactElement, { size: 'sm', }); diff --git a/packages/react/src/components/DataTable/stories/DataTable-slug.stories.js b/packages/react/src/components/DataTable/stories/DataTable-ai-label.stories.js similarity index 90% rename from packages/react/src/components/DataTable/stories/DataTable-slug.stories.js rename to packages/react/src/components/DataTable/stories/DataTable-ai-label.stories.js index daed3c32ba2c..b319cf0a1152 100644 --- a/packages/react/src/components/DataTable/stories/DataTable-slug.stories.js +++ b/packages/react/src/components/DataTable/stories/DataTable-ai-label.stories.js @@ -22,15 +22,15 @@ import DataTable, { TableExpandedRow, } from '..'; import { rows, headers } from './shared'; -import mdx from '../../Slug/SlugDatatable.mdx'; +import mdx from '../../AILabel/AILabelDatatable.mdx'; import Button from '../../Button'; import { IconButton } from '../../IconButton'; import { View, FolderOpen, Folders } from '@carbon/icons-react'; -import { Slug, SlugContent, SlugActions } from '../../Slug'; +import { AILabel, AILabelContent, AILabelActions } from '../../AILabel'; import './datatable-story.scss'; export default { - title: 'Experimental/unstable__Slug/DataTable', + title: 'Components/DataTable/WithAILabel', component: DataTable, subcomponents: { TableSelectAll, @@ -51,7 +51,7 @@ export default { }, }; -const columnSlugHeaders = [ +const columnAILabelHeaders = [ { key: 'name', header: 'Name', @@ -72,8 +72,11 @@ const columnSlugHeaders = [ key: 'attached_groups', header: 'Attached groups', slug: ( - - + +

AI Explained

84%

@@ -87,7 +90,7 @@ const columnSlugHeaders = [

Model type

Foundation model

- + @@ -98,9 +101,9 @@ const columnSlugHeaders = [ - -
-
+ + + ), }, { @@ -109,9 +112,9 @@ const columnSlugHeaders = [ }, ]; -const slug = ( - - +const aiLabel = ( + +

AI Explained

84%

@@ -124,7 +127,7 @@ const slug = (

Model type

Foundation model

- + @@ -135,12 +138,12 @@ const slug = ( - -
-
+ + + ); -export const SlugWithSelection = () => ( +export const AILabelWithSelection = () => ( {({ rows, @@ -171,7 +174,7 @@ export const SlugWithSelection = () => ( {rows.map((row, i) => ( {row.cells.map((cell) => ( @@ -186,7 +189,7 @@ export const SlugWithSelection = () => ( ); -export const SlugWithRadioSelection = () => ( +export const AILabelWithRadioSelection = () => ( {({ rows, @@ -217,7 +220,7 @@ export const SlugWithRadioSelection = () => ( {rows.map((row, i) => ( {row.cells.map((cell) => ( @@ -232,7 +235,7 @@ export const SlugWithRadioSelection = () => ( ); -export const SlugWithSelectionAndExpansion = () => ( +export const AILabelWithSelectionAndExpansion = () => ( {({ rows, @@ -270,7 +273,7 @@ export const SlugWithSelectionAndExpansion = () => ( {row.cells.map((cell) => ( @@ -293,7 +296,7 @@ export const SlugWithSelectionAndExpansion = () => ( ); -export const SlugWithExpansion = () => ( +export const AILabelWithExpansion = () => ( {({ rows, @@ -329,7 +332,7 @@ export const SlugWithExpansion = () => ( {row.cells.map((cell) => ( {cell.value} @@ -351,8 +354,8 @@ export const SlugWithExpansion = () => ( ); -export const ColumnSlugWithSelectionAndExpansion = () => ( - +export const ColumnAILabelWithSelectionAndExpansion = () => ( + {({ rows, headers, @@ -420,8 +423,8 @@ export const ColumnSlugWithSelectionAndExpansion = () => ( ); -export const ColumnSlugSort = () => ( - +export const ColumnAILabelSort = () => ( + {({ rows, headers, diff --git a/packages/react/src/components/DatePicker/DatePicker-test.js b/packages/react/src/components/DatePicker/DatePicker-test.js index 9e6604577537..f9f73570e4a2 100644 --- a/packages/react/src/components/DatePicker/DatePicker-test.js +++ b/packages/react/src/components/DatePicker/DatePicker-test.js @@ -10,7 +10,7 @@ import DatePicker from './DatePicker'; import DatePickerInput from '../DatePickerInput'; import { render, screen, fireEvent } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { Slug } from '../Slug'; +import { AILabel } from '../AILabel'; const prefix = 'cds'; @@ -203,7 +203,7 @@ describe('DatePicker', () => { placeholder="mm/dd/yyyy" labelText="Date Picker label" data-testid="input-value" - slug={} + slug={} /> ); diff --git a/packages/react/src/components/DatePicker/DatePicker.stories.js b/packages/react/src/components/DatePicker/DatePicker.stories.js index 3616c49fbecb..6581c877b137 100644 --- a/packages/react/src/components/DatePicker/DatePicker.stories.js +++ b/packages/react/src/components/DatePicker/DatePicker.stories.js @@ -12,6 +12,11 @@ import { WithLayer } from '../../../.storybook/templates/WithLayer'; import DatePicker from './DatePicker'; import DatePickerSkeleton from './DatePicker.Skeleton'; import DatePickerInput from '../DatePickerInput'; +import Button from '../Button'; +import { AILabel, AILabelContent, AILabelActions } from '../AILabel'; +import { IconButton } from '../IconButton'; +import { View, FolderOpen, Folders } from '@carbon/icons-react'; + import mdx from './DatePicker.mdx'; export default { @@ -128,6 +133,51 @@ export const RangeWithCalendarWithLayer = () => ( export const Skeleton = () => ; +const aiLabel = ( + + +
+

AI Explained

+

84%

+

Confidence score

+

+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

+
+

Model type

+

Foundation model

+
+ + + + + + + + + + + + +
+
+); + +export const withAILabel = () => ( +
+ + + +
+); + export const Playground = ({ readOnly, ...args }) => { return ( diff --git a/packages/react/src/components/DatePickerInput/DatePickerInput.tsx b/packages/react/src/components/DatePickerInput/DatePickerInput.tsx index 60db66408a76..2a230263a17b 100644 --- a/packages/react/src/components/DatePickerInput/DatePickerInput.tsx +++ b/packages/react/src/components/DatePickerInput/DatePickerInput.tsx @@ -217,7 +217,7 @@ const DatePickerInput = React.forwardRef(function DatePickerInput( // Slug is always size `mini` let normalizedSlug; - if (slug && slug['type']?.displayName === 'Slug') { + if (slug && slug['type']?.displayName === 'AILabel') { normalizedSlug = React.cloneElement(slug as React.ReactElement, { size: 'mini', }); diff --git a/packages/react/src/components/Dropdown/Dropdown-test.js b/packages/react/src/components/Dropdown/Dropdown-test.js index b2b6f9c90fb2..fa0b52467a82 100644 --- a/packages/react/src/components/Dropdown/Dropdown-test.js +++ b/packages/react/src/components/Dropdown/Dropdown-test.js @@ -18,7 +18,7 @@ import { } from '../ListBox/test-helpers'; import Dropdown from '../Dropdown'; import DropdownSkeleton from '../Dropdown/Dropdown.Skeleton'; -import { Slug } from '../Slug'; +import { AILabel } from '../AILabel'; const prefix = 'cds'; @@ -202,7 +202,9 @@ describe('Dropdown', () => { }); it('should respect slug prop', async () => { - const { container } = render(} />); + const { container } = render( + } /> + ); await waitForPosition(); expect(container.firstChild).toHaveClass( `${prefix}--list-box__wrapper--slug` diff --git a/packages/react/src/components/Dropdown/Dropdown.stories.js b/packages/react/src/components/Dropdown/Dropdown.stories.js index ef1cc98ef4ce..d029063aa3f4 100644 --- a/packages/react/src/components/Dropdown/Dropdown.stories.js +++ b/packages/react/src/components/Dropdown/Dropdown.stories.js @@ -10,6 +10,10 @@ import React from 'react'; import { WithLayer } from '../../../.storybook/templates/WithLayer'; import { default as Dropdown, DropdownSkeleton } from './'; +import Button from '../Button'; +import { AILabel, AILabelContent, AILabelActions } from '../AILabel'; +import { IconButton } from '../IconButton'; +import { View, FolderOpen, Folders } from '@carbon/icons-react'; import mdx from './Dropdown.mdx'; export default { @@ -248,3 +252,49 @@ export const Skeleton = () => (
); + +const aiLabel = ( + + +
+

AI Explained

+

84%

+

Confidence score

+

+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

+
+

Model type

+

Foundation model

+
+ + + + + + + + + + + + +
+
+); + +export const withAILabel = () => ( +
+ (item ? item.text : '')} + slug={aiLabel} + /> +
+); diff --git a/packages/react/src/components/Dropdown/Dropdown.tsx b/packages/react/src/components/Dropdown/Dropdown.tsx index 7441a55b0c4c..bc92afc4f96d 100644 --- a/packages/react/src/components/Dropdown/Dropdown.tsx +++ b/packages/react/src/components/Dropdown/Dropdown.tsx @@ -495,7 +495,7 @@ const Dropdown = React.forwardRef( // Slug is always size `mini` let normalizedSlug; - if (slug && slug['type']?.displayName === 'Slug') { + if (slug && slug['type']?.displayName === 'AILabel') { normalizedSlug = React.cloneElement(slug as React.ReactElement, { size: 'mini', }); diff --git a/packages/react/src/components/Form/Form.stories.js b/packages/react/src/components/Form/Form.stories.js index 13456e9f6aa0..981a602bdf27 100644 --- a/packages/react/src/components/Form/Form.stories.js +++ b/packages/react/src/components/Form/Form.stories.js @@ -20,6 +20,26 @@ import SelectItem from '../SelectItem'; import TextArea from '../TextArea'; import TextInput from '../TextInput'; import { Stack } from '../Stack'; +import ComboBox from '../ComboBox'; +import Dropdown from '../Dropdown'; +import DatePicker from '../DatePicker'; +import DatePickerInput from '../DatePickerInput'; +import { MultiSelect, FilterableMultiSelect } from '../MultiSelect'; +import FluidComboBox from '../FluidComboBox'; +import FluidForm from '../FluidForm'; +import FluidNumberInput from '../FluidNumberInput'; +import FluidDatePicker from '../FluidDatePicker'; +import FluidDatePickerInput from '../FluidDatePickerInput'; +import FluidDropdown from '../FluidDropdown'; +import FluidMultiSelect from '../FluidMultiSelect'; +import FluidSelect from '../FluidSelect'; +import FluidTextArea from '../FluidTextArea'; +import FluidTextInput from '../FluidTextInput'; +import { IconButton } from '../IconButton'; +import { View, FolderOpen, Folders } from '@carbon/icons-react'; +import { AILabel, AILabelContent, AILabelActions } from '../AILabel'; +import '../AILabel/ailabel-story.scss'; + import mdx from './Form.mdx'; const checkboxEvents = { @@ -220,3 +240,311 @@ export const Default = () => ( ); + +const items = [ + { + id: 'option-0', + text: 'Lorem, ipsum dolor sit amet consectetur adipisicing elit.', + }, + { + id: 'option-1', + text: 'Option 1', + }, + { + id: 'option-2', + text: 'Option 2', + }, + { + id: 'option-3', + text: 'Option 3 - a disabled item', + disabled: true, + }, + { + id: 'option-4', + text: 'Option 4', + }, + { + id: 'option-5', + text: 'Option 5', + }, +]; + +export const withAILabel = (args) => { + const { revertActive, ...rest } = args; + const aiLabel = ( + + +
+

AI Explained

+

84%

+

Confidence score

+

+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed + do eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

+
+

Model type

+

Foundation model

+
+ + + + + + + + + + + + +
+
+ ); + + return ( + +
+ + + + + + +