diff --git a/playbook-website/app/views/guides/getting_started/dependencies.md b/playbook-website/app/views/guides/getting_started/dependencies.md new file mode 100644 index 0000000000..3323271988 --- /dev/null +++ b/playbook-website/app/views/guides/getting_started/dependencies.md @@ -0,0 +1,52 @@ +--- +title: Dependencies +icon: code +description: Some of our kits require additional libraries to run properly. +--- + +## Unbundled Dependencies + +These kits require you to install additional libraries to get full functionality. + +To install them add them to your project using `yarn add`, `npm install`, or manually add them to your `package.json` file. + +| Kit | Kit Link | NPM Link(s) | Dependency(s) | +|---------------------|-----------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------|---------------------------------------------| +| **Icon** | [Icon](https://playbook.powerapp.cloud/kits/icon/react) | [fontawesome-free](https://www.npmjs.com/package/fontawesome-free) | fontawesome-free | +| **Icon Circle** | [Icon Circle](https://playbook.powerapp.cloud/kits/icon_circle/react) | [fontawesome-free](https://www.npmjs.com/package/fontawesome-free) | fontawesome-free | +| **Icon Stat Value** | [Icon Stat Value](https://playbook.powerapp.cloud/kits/icon_stat_value/react) | [fontawesome-free](https://www.npmjs.com/package/fontawesome-free) | fontawesome-free | +| **Icon Value** | [Icon Value](https://playbook.powerapp.cloud/kits/icon_value/react) | [fontawesome-free](https://www.npmjs.com/package/fontawesome-free) | fontawesome-free | +| **Map** | [Map](https://playbook.powerapp.cloud/kits/map/react) | [maplibre-gl](https://www.npmjs.com/package/maplibre-gl) | maplibre-gl | +| **Rich Text Editor**
(TipTap Editor) | [Rich Text Editor](https://playbook.powerapp.cloud/kits/rich_text_editor/react) | - [@tiptap/core](https://www.npmjs.com/package/@tiptap/core)
- [@tiptap/react](https://www.npmjs.com/package/@tiptap/react)
- [@tiptap/starter-kit](https://www.npmjs.com/package/@tiptap/starter-kit)
- [@tiptap/extension-document](https://www.npmjs.com/package/@tiptap/extension-document)
- [@tiptap/extension-highlight](https://www.npmjs.com/package/@tiptap/extension-highlight)
- [@tiptap/extension-horizontal-rule](https://www.npmjs.com/package/@tiptap/extension-horizontal-rule)
- [@tiptap/extension-link](https://www.npmjs.com/package/@tiptap/extension-link)
- [@tiptap/extension-paragraph](https://www.npmjs.com/package/@tiptap/extension-paragraph)
- [@tiptap/extension-text](https://www.npmjs.com/package/@tiptap/extension-text)
- [@tiptap/pm](https://www.npmjs.com/package/@tiptap/pm) | - @tiptap/core
- @tiptap/react
- @tiptap/starter-kit
- @tiptap/extension-document
- @tiptap/extension-highlight
- @tiptap/extension-horizontal-rule
- @tiptap/extension-link
- @tiptap/extension-paragraph
- @tiptap/extension-text
- @tiptap/pm | + +## Bundled Dependencies + +These kits use dependencies that are bundled with them; no additional installation is required. + +| Kit | Kit Link | NPM Link(s) | Dependency(s) | +|------------------------|-----------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|-----------------------------------------| +| **Advanced Table** | [Advanced Table](https://playbook.powerapp.cloud/kits/advanced_table/react) | [@tanstack/react-table](https://www.npmjs.com/package/@tanstack/react-table) | @tanstack/react-table | +| **Bar Graph** | [Bar Graph](https://playbook.powerapp.cloud/kits/bar_graph/react) | [highcharts](https://www.npmjs.com/package/highcharts),
[highcharts-react-official](https://www.npmjs.com/package/highcharts-react-official) | highcharts,
highcharts-react-official | +| **Circle Chart** | [Circle Chart](https://playbook.powerapp.cloud/kits/circle_chart/react) | [highcharts](https://www.npmjs.com/package/highcharts),
[highcharts-react-official](https://www.npmjs.com/package/highcharts-react-official) | highcharts,
highcharts-react-official | +| **Date Picker** | [Date Picker](https://playbook.powerapp.cloud/kits/date_picker/react) | [flatpickr](https://www.npmjs.com/package/flatpickr) | flatpickr | +| **Dialog** | [Dialog](https://playbook.powerapp.cloud/kits/dialog/react) | [react-modal](https://www.npmjs.com/package/react-modal) | react-modal | +| **File Upload** | [File Upload](https://playbook.powerapp.cloud/kits/file_upload/react) | [react-dropzone](https://www.npmjs.com/package/react-dropzone) | react-dropzone | +| **Filter** | [Filter](https://playbook.powerapp.cloud/kits/filter/react) | [react-popper](https://www.npmjs.com/package/react-popper) | react-popper | +| **Gauge** | [Gauge](https://playbook.powerapp.cloud/kits/gauge/react) | [highcharts](https://www.npmjs.com/package/highcharts),
[highcharts-react-official](https://www.npmjs.com/package/highcharts-react-official) | highcharts,
highcharts-react-official | +| **Highlight** | [Highlight](https://playbook.powerapp.cloud/kits/highlight/react) | [react-highlight-words](https://www.npmjs.com/package/react-highlight-words) | react-highlight-words | +| **LightBox** | [LightBox](https://playbook.powerapp.cloud/kits/lightbox/react) | [react-zoom-pan-pinch](https://www.npmjs.com/package/react-zoom-pan-pinch) | react-zoom-pan-pinch | +| **Line Graph** | [Line Graph](https://playbook.powerapp.cloud/kits/line_graph/react) | [highcharts](https://www.npmjs.com/package/highcharts),
[highcharts-react-official](https://www.npmjs.com/package/highcharts-react-official) | highcharts,
highcharts-react-official | +| **Multi Level Select** | [Multi Level Select](https://playbook.powerapp.cloud/kits/multi_level_select/react) | [lodash](https://www.npmjs.com/package/lodash) | lodash | +| **Passphrase** | [Passphrase](https://playbook.powerapp.cloud/kits/passphrase/react) | [react-popper](https://www.npmjs.com/package/react-popper) | react-popper | +| **Phone Number Input** | [Phone Number Input](https://playbook.powerapp.cloud/kits/phone_number_input/react) | [intl-tel-input](https://www.npmjs.com/package/intl-tel-input) | intl-tel-input | +| **Popover** | [Popover](https://playbook.powerapp.cloud/kits/popover/react) | [lodash](https://www.npmjs.com/package/lodash),
[react-popper](https://www.npmjs.com/package/react-popper) | lodash,
react-popper | +| **Rich Text Editor**
(Trix Editor) | [Rich Text Editor](https://playbook.powerapp.cloud/kits/rich_text_editor/react) | [trix](https://www.npmjs.com/package/trix),
[react-trix](https://www.npmjs.com/package/react-trix) | trix,
react-trix | +| **Tooltip** | [Tooltip](https://playbook.powerapp.cloud/kits/tooltip/react) | [@floating-ui/react](https://www.npmjs.com/package/@floating-ui/react) | @floating-ui/react | +| **Treemap Chart** | [Treemap Chart](https://playbook.powerapp.cloud/kits/treemap_chart/react) | [highcharts](https://www.npmjs.com/package/highcharts),
[highcharts-react-official](https://www.npmjs.com/package/highcharts-react-official) | highcharts,
highcharts-react-official | +| **Typeahead** | [Typeahead](https://playbook.powerapp.cloud/kits/typeahead/react) | [react-select](https://www.npmjs.com/package/react-select),
[lodash](https://www.npmjs.com/package/lodash) | react-select,
lodash | +| **Walkthrough** | [Walkthrough](https://playbook.powerapp.cloud/kits/walkthrough/react) | [react-joyride](https://www.npmjs.com/package/react-joyride) | react-joyride | + +## Notes +**Rich Text Editor**: This kit supports two different editors: +**TipTap Editor**: Requires manual installation of `tiptap` and various `@tiptap/*` extensions (listed above under Unbundled Dependencies). +**Trix Editor**: Dependencies (`trix` and `react-trix`) are bundled with the kit; no extra installation is needed. diff --git a/playbook-website/app/views/guides/getting_started/font_awesome.md b/playbook-website/app/views/guides/getting_started/font_awesome.md new file mode 100644 index 0000000000..732a79757b --- /dev/null +++ b/playbook-website/app/views/guides/getting_started/font_awesome.md @@ -0,0 +1,73 @@ +--- +title: Font Awesome Setup +description: Playbook seamlessly integrates with Font Awesome, a leading icon library known for its extensive collection of high-quality, scalable icons. This integration not only enhances the visual appeal of websites and applications but also improves overall usability. +icon: font-awesome +--- + +Playbook seamlessly integrates with [Font Awesome](https://fontawesome.com/), a leading icon library known for its extensive collection of high-quality, scalable icons. This integration not only enhances the visual appeal of websites and applications but also improves overall usability. + +Some Font Awesome benefits: + +**1. Wide Range of Icons:** Font Awesome offers a vast selection of icons to suit a variety of needs. You can easily find the perfect icon for your project through their [icon search](https://fontawesome.com/search). +**2. Ease of Use:** The icons are straightforward to implement. With just a few lines of code, you can quickly and easily add visual elements to your web projects. Note, a Pro subscription is required for access to a wider range of icons beyond the [Free set](https://fontawesome.com/search?o=r&m=free&s=regular). +**3. Visual Appeal:** Incorporating these icons can improve the aesthetic of your site or application, making it more attractive to users. With Playbook, you have the flexibility to customize color, size, and animations. +**4. User-Friendliness:** Icons can help users navigate and understand your website or application more efficiently, enhancing their overall experience. Font Awesome icons are web fonts compatible with most browsers and are optimized for performance and accessibility. + +Integrating Font Awesome with Playbook ensures that you have access to these benefits, making your projects more polished and professional. + +![fontawesome](https://github.com/user-attachments/assets/638b63ad-56d3-4819-8e05-fcbb175bedc7) + +## Ruby on Rails Setup (default with asset pipeline) + +**Make sure you are on Rails 7 or higher.** + +**1.** Follow the [Ruby on Rails Setup getting started page](/guides/getting_started/ruby_on_rails_setup) to setup Playbook with your Rails project. + +**2.** Setup Pro or Free Font Awesome to use our Icon Component. + +**Pro:** + +```rb +# app/assets/stylesheets/application.scss + @import "font-awesome-pro"; + @import "font-awesome-pro/solid"; + @import "font-awesome-pro/regular"; + @import "playbook"; +``` + +```rb +# app/Gemfile + source "https://token:TOKEN@dl.fontawesome.com/basic/fontawesome-pro/ruby/" do + gem "font-awesome-pro-sass", "6.2.0" + end +``` + +**Free:** + +*Currently only [Free Regular](https://fontawesome.com/search?o=r&m=free&s=regular) icons are supported in our icon component structure.* + +```rb +# app/assets/stylesheets/application.scss + @import "font-awesome"; +``` + +```rb +# app/Gemfile + source "https://token:TOKEN@dl.fontawesome.com/basic/fontawesome-pro/ruby/" do + gem "font-awesome-pro-sass", "6.2.0" + end +``` + +**3.** Bundle all the things! + +```sh +bundle install +``` + +**4.** **Go build awesome stuff!** + +Refer to our [Icon kit](/kits/icon) to get started with Font Awesome icons in Playbook. + +```rb +<%= pb_rails("icon", props: { icon: "font-awesome", fixed_width: true }) %> +``` diff --git a/playbook-website/config/initializers/global_variables.rb b/playbook-website/config/initializers/global_variables.rb index 68052286d5..c88293355d 100644 --- a/playbook-website/config/initializers/global_variables.rb +++ b/playbook-website/config/initializers/global_variables.rb @@ -69,10 +69,11 @@ ], } -# Move HTML figma to the end +# Move these pages to the end of the Getting Started page +page_names = ["HTML&_CSS", "figma_setup", "how_to_theme", "dependencies", "font_awesome"] -move_pages = navigation[:getting_started][:pages].select { |page| ["HTML&_CSS", "figma_setup", "how_to_theme"].include?(page[:page_id]) } -navigation[:getting_started][:pages].reject! { |page| ["HTML&_CSS", "figma_setup", "how_to_theme"].include?(page[:page_id]) } +move_pages = navigation[:getting_started][:pages].select { |page| page_names.include?(page[:page_id]) } +navigation[:getting_started][:pages].reject! { |page| page_names.include?(page[:page_id]) } navigation[:getting_started][:pages].concat(move_pages) DOCS = navigation diff --git a/playbook/app/pb_kits/playbook/pb_form_pill/_form_pill.scss b/playbook/app/pb_kits/playbook/pb_form_pill/_form_pill.scss index 87f00ef302..2541ef05f8 100644 --- a/playbook/app/pb_kits/playbook/pb_form_pill/_form_pill.scss +++ b/playbook/app/pb_kits/playbook/pb_form_pill/_form_pill.scss @@ -142,7 +142,9 @@ $form_pill_colors: map-merge($status_color_text, map-merge($data_colors, $produc height: 12px !important; width: 12px !important; padding-right: $space_xs; - + .pb_form_pill_text, + .pb_form_pill_tag { + + .pb_form_pill_text, + .pb_form_pill_tag, + + .pb_tooltip_kit .pb_form_pill_text, + .pb_tooltip_kit .pb_form_pill_tag, + + div .pb_form_pill_text, + div .pb_form_pill_tag { padding-left: 0; } } @@ -169,7 +171,9 @@ $form_pill_colors: map-merge($status_color_text, map-merge($data_colors, $produc } .pb_form_pill_icon { padding-right: $space_xxs; - + .pb_form_pill_text, + .pb_form_pill_tag { + + .pb_form_pill_text, + .pb_form_pill_tag, + + .pb_tooltip_kit .pb_form_pill_text, + .pb_tooltip_kit .pb_form_pill_tag, + + div .pb_form_pill_text, + div .pb_form_pill_tag { padding-left: 0; } } diff --git a/playbook/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx b/playbook/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx index 9cbff71a4c..0ea0f7d02b 100644 --- a/playbook/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx +++ b/playbook/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx @@ -3,6 +3,7 @@ import classnames from 'classnames' import Title from '../pb_title/_title' import Icon from '../pb_icon/_icon' import Avatar from '../pb_avatar/_avatar' +import Tooltip from '../pb_tooltip/_tooltip' import { globalProps, GlobalProps } from '../utilities/globalProps' import { buildDataProps, buildHtmlProps } from '../utilities/props' @@ -62,6 +63,30 @@ const FormPill = (props: FormPillProps): React.ReactElement => { const dataProps = buildDataProps(data) const htmlProps = buildHtmlProps(htmlOptions) + const renderTitle = (content: string, className: string) => { + const titleComponent = ( + + ) + if (props.truncate) { + return ( + <Tooltip + interaction + placement="top" + position="fixed" + text={content} + > + {titleComponent} + </Tooltip> + ) + } + return titleComponent + } + return ( <div className={css} id={id} @@ -77,12 +102,7 @@ const FormPill = (props: FormPillProps): React.ReactElement => { size="xxs" status={null} /> - <Title - className="pb_form_pill_text" - size={4} - text={name} - truncate={props.truncate} - /> + {renderTitle(name, "pb_form_pill_text")} </> )} {((name && icon && !text) || (name && icon && text)) && ( @@ -93,12 +113,7 @@ const FormPill = (props: FormPillProps): React.ReactElement => { size="xxs" status={null} /> - <Title - className="pb_form_pill_text" - size={4} - text={name} - truncate={props.truncate} - /> + {renderTitle(name, "pb_form_pill_text")} <Icon className="pb_form_pill_icon" color={color} @@ -113,22 +128,10 @@ const FormPill = (props: FormPillProps): React.ReactElement => { color={color} icon={icon} /> - <Title - className="pb_form_pill_tag" - size={4} - text={text} - truncate={props.truncate} - /> + {renderTitle(text, "pb_form_pill_tag")} </> )} - {(!name && !icon && text) && ( - <Title - className="pb_form_pill_tag" - size={4} - text={text} - truncate={props.truncate} - /> - )} + {(!name && !icon && text) && renderTitle(text, "pb_form_pill_tag")} <div className="pb_form_pill_close" onClick={onClick} @@ -143,4 +146,5 @@ const FormPill = (props: FormPillProps): React.ReactElement => { </div> ) } + export default FormPill diff --git a/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.html.erb b/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.html.erb index 3e66bb7446..a298f19a09 100644 --- a/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.html.erb +++ b/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.html.erb @@ -13,7 +13,30 @@ id: "typeahead-form-pill", is_multi: true, options: names, - label: "Names", + label: "Truncation Within Typeahead", pills: true, truncate: 1, }) %> + +<%= pb_rails("caption", props: { text: "Form Pill Truncation" }) %> +<%= pb_rails("card", props: { max_width: "xs" }) do %> + <%= pb_rails("form_pill", props: { + name: "Princess Amelia Mignonette Grimaldi Thermopolis Renaldo", + avatar_url: "https://randomuser.me/api/portraits/women/44.jpg", + tabindex: 0, + truncate: 1, + id: "truncation-1" + }) %> + <%= pb_rails("form_pill", props: { + icon: "badge-check", + text: "icon and a very long tag to show truncation", + tabindex: 0, + truncate: 1, + id: "truncation-2" + }) %> + <%= pb_rails("form_pill", props: { + text: "form pill long tag no tooltip show truncation", + tabindex: 0, + truncate: 1, + }) %> +<% end %> \ No newline at end of file diff --git a/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.jsx b/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.jsx index b599017782..51a8a3e2a5 100644 --- a/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.jsx +++ b/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.jsx @@ -1,5 +1,5 @@ import React from 'react' -import Typeahead from '../../pb_typeahead/_typeahead' +import { Card, Caption, FormPill, Typeahead } from 'playbook-ui' const names = [ { label: 'Alexander Nathaniel Montgomery', value: 'Alexander Nathaniel Montgomery' }, @@ -15,11 +15,34 @@ const FormPillTruncatedText = (props) => { <Typeahead htmlOptions={{ style: { maxWidth: "240px" }}} isMulti - label="Names" + label="Truncation Within Typeahead" options={names} truncate={1} {...props} /> + <Caption text="Form Pill Truncation"/> + <Card maxWidth="xs"> + <FormPill + avatarUrl="https://randomuser.me/api/portraits/women/44.jpg" + name="Princess Amelia Mignonette Grimaldi Thermopolis Renaldo" + onClick={() => alert('Click!')} + tabIndex={0} + truncate={1} + /> + <FormPill + icon="badge-check" + onClick={() => {alert('Click!')}} + tabIndex={0} + text="icon and a very long tag to show truncation" + truncate={1} + /> + <FormPill + onClick={() => {alert('Click!')}} + tabIndex={0} + text="form pill with a very long tag to show truncation" + truncate={1} + /> + </Card> </> ) } diff --git a/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.md b/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.md deleted file mode 100644 index e960dc2deb..0000000000 --- a/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.md +++ /dev/null @@ -1 +0,0 @@ -For pills with longer text, the `truncate` global prop can be used to truncate the label within each Form Pill. See [here](https://playbook.powerapp.cloud/visual_guidelines/truncate) for more information on the truncate global prop. \ No newline at end of file diff --git a/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text_rails.md b/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text_rails.md new file mode 100644 index 0000000000..fc0593464e --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text_rails.md @@ -0,0 +1,3 @@ +For Form Pills with longer text, the truncate global prop can be used to truncate the label within each Form Pill. See [here](https://playbook.powerapp.cloud/visual_guidelines/truncate) for more information on the truncate global prop. + +__NOTE__: For Rails Form Pills (not ones embedded within a React-rendered Typeahead or MultiLevelSelect), a unique `id` is required to enable the Tooltip functionality displaying the text or tag section of the Form Pill. \ No newline at end of file diff --git a/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text_react.md b/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text_react.md new file mode 100644 index 0000000000..5b35756d8c --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text_react.md @@ -0,0 +1 @@ +For Form Pills with longer text, the `truncate` global prop can be used to truncate the label within each Form Pill. Hover over the truncated Form Pill and a Tooltip containing the text or tag section of the Form Pill will appear. See [here](https://playbook.powerapp.cloud/visual_guidelines/truncate) for more information on the truncate global prop. \ No newline at end of file diff --git a/playbook/app/pb_kits/playbook/pb_form_pill/form_pill.html.erb b/playbook/app/pb_kits/playbook/pb_form_pill/form_pill.html.erb index b9ddf68b86..4e42ddabb6 100644 --- a/playbook/app/pb_kits/playbook/pb_form_pill/form_pill.html.erb +++ b/playbook/app/pb_kits/playbook/pb_form_pill/form_pill.html.erb @@ -1,19 +1,57 @@ <%= content_tag(:div, id: object.id, data: object.data, class: object.classname + object.size_class, tabindex: object.tabindex, **combined_html_options) do %> <% if object.name.present? %> <%= pb_rails("avatar", props: { name: object.name, image_url: object.avatar_url, size: "xxs" }) %> - <%= pb_rails("title", props: { text: object.name, size: 4, classname: "pb_form_pill_text" }) %> + <% if object.truncate %> + <div> + <%= pb_rails("title", props: { + classname: "pb_form_pill_text truncate_#{object.truncate}", + id: object.id, + size: 4, + text: object.name, + }) %> + <% if object.id.present? %> + <%= pb_rails("tooltip", props: { + position: "top", + tooltip_id: "tooltip-#{object.id}", + trigger_element_selector: "##{object.id}" + }) do %> + <%= object.name %> + <% end %> + <% end %> + </div> + <% else %> + <%= pb_rails("title", props: { classname: "pb_form_pill_text", id: object.id, size: 4, text: object.name }) %> + <% end %> <% if object.icon.present? %> <%= pb_rails("icon", props: { classname: "pb_form_pill_icon", color: object.color, icon: object.icon }) %> <% end %> <% elsif object.text.present? %> - <% if object.icon.present? %> - <%= pb_rails("icon", props: { classname: "pb_form_pill_icon", color: object.color, icon: object.icon }) %> - <% end %> - <% if object.text.present? %> - <%= pb_rails("title", props: { text: object.text, size: 4, classname: "pb_form_pill_tag" }) %> - <% end %> + <% if object.icon.present? %> + <%= pb_rails("icon", props: { classname: "pb_form_pill_icon", color: object.color, icon: object.icon }) %> + <% end %> + <% if object.truncate %> + <div> + <%= pb_rails("title", props: { + classname: "pb_form_pill_tag truncate_#{object.truncate}", + id: object.id, + size: 4, + text: object.text, + }) %> + <% if object.id.present? %> + <%= pb_rails("tooltip", props: { + position: "top", + tooltip_id: "tooltip-#{object.id}", + trigger_element_selector: "##{object.id}" + }) do %> + <%= object.text %> + <% end %> + <% end %> + </div> + <% else %> + <%= pb_rails("title", props: { classname: "pb_form_pill_tag", id: object.id, size: 4, text: object.text, }) %> + <% end %> <% end %> <%= pb_rails("body", props: { classname: "pb_form_pill_close" }) do %> <%= pb_rails("icon", props: { icon: 'times', fixed_width: true, size: object.close_icon_size }) %> <% end %> -<% end %> +<% end %> \ No newline at end of file diff --git a/playbook/app/pb_kits/playbook/pb_timeline/_item.tsx b/playbook/app/pb_kits/playbook/pb_timeline/_item.tsx index 3d6ef9eafd..f5aa0d6d2b 100644 --- a/playbook/app/pb_kits/playbook/pb_timeline/_item.tsx +++ b/playbook/app/pb_kits/playbook/pb_timeline/_item.tsx @@ -1,12 +1,15 @@ import React from 'react' import classnames from 'classnames' - import { buildCss, buildHtmlProps } from '../utilities/props' -import { globalProps, GlobalProps } from "../utilities/globalProps"; +import { globalProps, GlobalProps } from "../utilities/globalProps" import DateStacked from '../pb_date_stacked/_date_stacked' import IconCircle from '../pb_icon_circle/_icon_circle' +import TimelineLabel from './subcomponents/Label' +import TimelineStep from './subcomponents/Step' +import TimelineDetail from './subcomponents/Detail' + type ItemProps = { className?: string, children?: React.ReactNode[] | React.ReactNode, @@ -17,6 +20,13 @@ type ItemProps = { lineStyle?: 'solid' | 'dotted', } & GlobalProps +function isElementOfType<P>( + element: React.ReactNode, + component: React.ComponentType<P> +): element is React.ReactElement<P> { + return React.isValidElement<P>(element) && element.type === component +} + const TimelineItem = ({ className, children, @@ -31,31 +41,57 @@ const TimelineItem = ({ const htmlProps = buildHtmlProps(htmlOptions) + const childrenArray = React.Children.toArray(children) + + const labelChild = childrenArray.find( + (child): child is React.ReactElement => isElementOfType(child, TimelineLabel) + ) + + const stepChild = childrenArray.find( + (child): child is React.ReactElement => isElementOfType(child, TimelineStep) + ) + + const detailChild = childrenArray.find( + (child): child is React.ReactElement => isElementOfType(child, TimelineDetail) + ) + + const otherChildren = childrenArray.filter( + (child) => + !isElementOfType(child, TimelineLabel) && + !isElementOfType(child, TimelineStep) && + !isElementOfType(child, TimelineDetail) + ) + return ( - <div + <div {...htmlProps} className={classnames(timelineItemCss, globalProps(props), className)} > - <div className="pb_timeline_item_left_block"> - {date && - <DateStacked - align="center" - date={date} - size="sm" - /> - } - </div> - <div className="pb_timeline_item_step"> - <IconCircle - icon={icon} - size="xs" - variant={iconColor} - /> - <div className="pb_timeline_item_connector" /> - </div> - <div className="pb_timeline_item_right_block"> - {children} - </div> + {labelChild || ( + <div className="pb_timeline_item_left_block"> + {date && ( + <DateStacked + align="center" + date={date} + size="sm" + /> + )} + </div> + )} + {stepChild || ( + <div className="pb_timeline_item_step"> + <IconCircle icon={icon} + size="xs" + variant={iconColor} + /> + <div className="pb_timeline_item_connector" /> + </div> + )} + {detailChild || ( + <div className="pb_timeline_item_right_block"> + { otherChildren } + </div> + )} </div> ) } diff --git a/playbook/app/pb_kits/playbook/pb_timeline/_timeline.tsx b/playbook/app/pb_kits/playbook/pb_timeline/_timeline.tsx index e58d9f8acb..a0e3f53af6 100644 --- a/playbook/app/pb_kits/playbook/pb_timeline/_timeline.tsx +++ b/playbook/app/pb_kits/playbook/pb_timeline/_timeline.tsx @@ -5,6 +5,11 @@ import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../uti import { GlobalProps, globalProps } from '../utilities/globalProps' import TimelineItem from './_item' +import { + TimelineStep, + TimelineLabel, + TimelineDetail, +} from './subcomponents' type TimelineProps = { aria?: { [key: string]: string }, @@ -47,5 +52,8 @@ const Timeline = ({ } Timeline.Item = TimelineItem +Timeline.Step = TimelineStep +Timeline.Label = TimelineLabel +Timeline.Detail = TimelineDetail export default Timeline diff --git a/playbook/app/pb_kits/playbook/pb_timeline/detail.html.erb b/playbook/app/pb_kits/playbook/pb_timeline/detail.html.erb new file mode 100644 index 0000000000..919544cc91 --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_timeline/detail.html.erb @@ -0,0 +1,3 @@ +<%= pb_content_tag do %> + <%= content.presence %> +<% end %> diff --git a/playbook/app/pb_kits/playbook/pb_timeline/detail.rb b/playbook/app/pb_kits/playbook/pb_timeline/detail.rb new file mode 100644 index 0000000000..810248dae4 --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_timeline/detail.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Playbook + module PbTimeline + class Detail < Playbook::KitBase + def classname + generate_classname("pb_timeline_item_right_block") + end + end + end +end diff --git a/playbook/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.html.erb b/playbook/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.html.erb new file mode 100644 index 0000000000..1725989c17 --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.html.erb @@ -0,0 +1,43 @@ +<%= pb_rails("timeline", props: {orientation: "horizontal", show_date: true}) do %> + <%= pb_rails("timeline/item", props: { line_style: "solid"}) do |item| %> + + <% item.label do %> + <%= pb_rails("timeline/label") do %> + <%= pb_rails("title", props: { text: "Any Kit Here", size: 2 }) %> + <% end %> + <% end %> + + <% item.step do %> + <%= pb_rails("timeline/step", props: { icon: 'check', icon_color: 'teal' }) %> + <% end %> + + <% item.detail do %> + <%= pb_rails("title_detail", props: { + title: "Jackson Heights", + detail: "37-27 74th Street" + }) %> + <% end %> + <% end %> + <%= pb_rails("timeline/item", props: { line_style: "dotted"}) do |item| %> + + <% item.step do %> + <%= pb_rails("timeline/step") do %> + <%= pb_rails("pill", props: { text: "Any Kit" , variant: "success" }) %> + <% end %> + <% end %> + + <% item.detail do %> + <%= pb_rails("title_detail", props: { + title: "Greenpoint", + detail: "81 Gate St Brooklyn" + }) %> + <% end %> + <% end %> + + <%= pb_rails("timeline/item", props: {icon: "map-marker-alt", icon_color: "purple", date: Date.today+1 }) do |item| %> + <%= pb_rails("title_detail", props: { + title: "Society Hill", + detail: "72 E St Astoria" + }) %> + <% end %> +<% end %> diff --git a/playbook/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.jsx b/playbook/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.jsx new file mode 100644 index 0000000000..c426fbc066 --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.jsx @@ -0,0 +1,68 @@ +import React from 'react' + +import Timeline from '../_timeline' +import Title from '../../pb_title/_title' +import Pill from '../../pb_pill/_pill' + +import TitleDetail from '../../pb_title_detail/_title_detail' + +const TimelineWithChildren = (props) => ( + <div> + <Timeline orientation="horizontal" + showDate + {...props} + > + <Timeline.Item lineStyle="solid" + {...props} + > + <Timeline.Label> + <Title size={2} + text='Any Kit Here' + /> + </Timeline.Label> + <Timeline.Step icon="user" + iconColor="royal" + /> + <Timeline.Detail> + <TitleDetail detail="37-27 74th Street" + title="Jackson Heights" + {...props} + /> + </Timeline.Detail> + </Timeline.Item> + + <Timeline.Item lineStyle="dotted" + {...props} + > + <Timeline.Step> + <Pill text="Any Kit" + variant="success" + /> + </Timeline.Step> + <Timeline.Detail> + <TitleDetail detail="81 Gate St Brooklyn" + title="Greenpoint" + {...props} + /> + </Timeline.Detail> + </Timeline.Item> + + <Timeline.Item lineStyle="solid" + {...props} + > + <Timeline.Label date={new Date(new Date().setDate(new Date().getDate() + 1))} /> + <Timeline.Step icon="map-marker-alt" + iconColor="purple" + /> + <Timeline.Detail> + <TitleDetail detail="72 E St Astoria" + title="Society Hill" + {...props} + /> + </Timeline.Detail> + </Timeline.Item> + </Timeline> + </div> +) + +export default TimelineWithChildren diff --git a/playbook/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.md b/playbook/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.md new file mode 100644 index 0000000000..dc0264dd9e --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.md @@ -0,0 +1,2 @@ +Any kit can be used inside of our compound components of label, step, or detail. Expand the code snippet below to see how to use these children elements. + diff --git a/playbook/app/pb_kits/playbook/pb_timeline/docs/example.yml b/playbook/app/pb_kits/playbook/pb_timeline/docs/example.yml index 2cf2a99a73..1cd961b5d5 100644 --- a/playbook/app/pb_kits/playbook/pb_timeline/docs/example.yml +++ b/playbook/app/pb_kits/playbook/pb_timeline/docs/example.yml @@ -4,10 +4,11 @@ examples: - timeline_default: Default - timeline_vertical: Vertical - timeline_with_date: With Date + - timeline_with_children: With Children react: - timeline_default: Default - timeline_vertical: Vertical - timeline_with_date: With Date - + - timeline_with_children: With Children diff --git a/playbook/app/pb_kits/playbook/pb_timeline/docs/index.js b/playbook/app/pb_kits/playbook/pb_timeline/docs/index.js index 35398d22d6..8da0d1e1f0 100644 --- a/playbook/app/pb_kits/playbook/pb_timeline/docs/index.js +++ b/playbook/app/pb_kits/playbook/pb_timeline/docs/index.js @@ -1,3 +1,4 @@ export { default as TimelineDefault } from './_timeline_default.jsx' export { default as TimelineVertical } from './_timeline_vertical.jsx' export { default as TimelineWithDate } from './_timeline_with_date.jsx' +export { default as TimelineWithChildren } from './_timeline_with_children.jsx' diff --git a/playbook/app/pb_kits/playbook/pb_timeline/item.html.erb b/playbook/app/pb_kits/playbook/pb_timeline/item.html.erb index cb815cb6e2..8f7153b22b 100644 --- a/playbook/app/pb_kits/playbook/pb_timeline/item.html.erb +++ b/playbook/app/pb_kits/playbook/pb_timeline/item.html.erb @@ -1,25 +1,21 @@ <%= pb_content_tag do %> + <% if label %> + <%= label %> + <% else %> + <%= pb_rails("timeline/label", props: { date: date }) %> + <% end %> - <div class="pb_timeline_item_left_block"> - <% if object.date.present? %> - <%= pb_rails("date_stacked", props: { - date: object.date, - size: "sm", - align: "center" - }) %> - <% end %> - </div> - - <div class="pb_timeline_item_step"> - <%= pb_rails("icon_circle", props: { - icon: object.icon, - variant: object.icon_color, - size: "xs" - }) %> - <div class="pb_timeline_item_connector"></div> - </div> + <% if step %> + <%= step %> + <% else %> + <%= pb_rails("timeline/step", props: { icon: icon, icon_color: icon_color }) %> + <% end %> - <div class="pb_timeline_item_right_block"> - <%= content.presence %> - </div> + <% if detail%> + <%= detail%> + <% else %> + <%= pb_rails("timeline/detail") do %> + <%= content %> + <% end %> + <% end %> <% end %> diff --git a/playbook/app/pb_kits/playbook/pb_timeline/item.rb b/playbook/app/pb_kits/playbook/pb_timeline/item.rb index f5c5830777..9a954cc413 100644 --- a/playbook/app/pb_kits/playbook/pb_timeline/item.rb +++ b/playbook/app/pb_kits/playbook/pb_timeline/item.rb @@ -13,6 +13,10 @@ class Item < Playbook::KitBase values: %w[solid dotted], default: "solid" + renders_one :label + renders_one :step + renders_one :detail + def classname generate_classname("pb_timeline_item_kit", line_style) end diff --git a/playbook/app/pb_kits/playbook/pb_timeline/label.html.erb b/playbook/app/pb_kits/playbook/pb_timeline/label.html.erb new file mode 100644 index 0000000000..c7b4b3b18b --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_timeline/label.html.erb @@ -0,0 +1,12 @@ +<%= pb_content_tag do %> + <% if object.date.present? %> + <%= pb_rails("date_stacked", props: { + date: object.date, + size: "sm", + align: "center" + }) %> + <% else %> + <%= content.presence %> + <% end %> +<% end %> + diff --git a/playbook/app/pb_kits/playbook/pb_timeline/label.rb b/playbook/app/pb_kits/playbook/pb_timeline/label.rb new file mode 100644 index 0000000000..bfb74a469f --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_timeline/label.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Playbook + module PbTimeline + class Label < Playbook::KitBase + prop :date + + def classname + generate_classname("pb_timeline_item_left_block") + end + end + end +end diff --git a/playbook/app/pb_kits/playbook/pb_timeline/step.html.erb b/playbook/app/pb_kits/playbook/pb_timeline/step.html.erb new file mode 100644 index 0000000000..533e1cb383 --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_timeline/step.html.erb @@ -0,0 +1,14 @@ +<%= pb_content_tag do %> + <% if object.icon.present? %> + <%= pb_rails("icon_circle", props: { + icon: object.icon, + variant: object.icon_color, + size: "xs" + }) %> + <% else %> + <%= content.presence %> + <% end %> + <div class="pb_timeline_item_connector"></div> +<% end %> + + diff --git a/playbook/app/pb_kits/playbook/pb_timeline/step.rb b/playbook/app/pb_kits/playbook/pb_timeline/step.rb new file mode 100644 index 0000000000..a80d28d51a --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_timeline/step.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Playbook + module PbTimeline + class Step < Playbook::KitBase + prop :icon, type: Playbook::Props::String + prop :icon_color, type: Playbook::Props::Enum, + values: %w[default royal blue purple teal red yellow green], + default: "default" + + def classname + generate_classname("pb_timeline_item_step") + end + end + end +end diff --git a/playbook/app/pb_kits/playbook/pb_timeline/subcomponents/Detail.tsx b/playbook/app/pb_kits/playbook/pb_timeline/subcomponents/Detail.tsx new file mode 100644 index 0000000000..0365376132 --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_timeline/subcomponents/Detail.tsx @@ -0,0 +1,29 @@ +import React from 'react' +import classnames from 'classnames' +import { buildHtmlProps } from '../../utilities/props' +import { globalProps, GlobalProps } from "../../utilities/globalProps" + +type TimelineDetailProps = { + children?: React.ReactNode, + className?: string, + htmlOptions?: { [key: string]: any }, +} & GlobalProps + +const TimelineDetail: React.FC<TimelineDetailProps> = ({ + children, + className, + htmlOptions = {}, + ...props +}) => { + const htmlProps = buildHtmlProps(htmlOptions) + return ( + <div + {...htmlProps} + className={classnames('pb_timeline_item_right_block', globalProps(props), className)} + > + {children} + </div> + ) +} + +export default TimelineDetail diff --git a/playbook/app/pb_kits/playbook/pb_timeline/subcomponents/Label.tsx b/playbook/app/pb_kits/playbook/pb_timeline/subcomponents/Label.tsx new file mode 100644 index 0000000000..717e92aeaf --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_timeline/subcomponents/Label.tsx @@ -0,0 +1,38 @@ +import React from 'react' +import classnames from 'classnames' +import { buildHtmlProps } from '../../utilities/props' +import { globalProps, GlobalProps } from "../../utilities/globalProps" +import DateStacked from '../../pb_date_stacked/_date_stacked' + +type TimelineLabelProps = { + date?: Date, + children?: React.ReactNode, + className?: string, + htmlOptions?: { [key: string]: any }, +} & GlobalProps + +const TimelineLabel: React.FC<TimelineLabelProps> = ({ + date, + children, + className, + htmlOptions = {}, + ...props +}) => { + const htmlProps = buildHtmlProps(htmlOptions) + return ( + <div + {...htmlProps} + className={classnames('pb_timeline_item_left_block', globalProps(props), className)} + > + {children} + {date && ( + <DateStacked align="center" + date={date} + size="sm" + /> + )} + </div> + ) +} + +export default TimelineLabel diff --git a/playbook/app/pb_kits/playbook/pb_timeline/subcomponents/Step.tsx b/playbook/app/pb_kits/playbook/pb_timeline/subcomponents/Step.tsx new file mode 100644 index 0000000000..648c1d9b0a --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_timeline/subcomponents/Step.tsx @@ -0,0 +1,42 @@ +import React from 'react' +import classnames from 'classnames' +import { buildHtmlProps } from '../../utilities/props' +import { globalProps, GlobalProps } from "../../utilities/globalProps" +import IconCircle from '../../pb_icon_circle/_icon_circle' + +type TimelineStepProps = { + icon?: string, + iconColor?: 'default' | 'royal' | 'blue' | 'purple' | 'teal' | 'red' | 'yellow' | 'green', + children?: React.ReactNode, + className?: string, + htmlOptions?: { [key: string]: any }, +} & GlobalProps + +const TimelineStep: React.FC<TimelineStepProps> = ({ + icon = 'user', + iconColor = 'default', + children, + className, + htmlOptions = {}, + ...props +}) => { + const htmlProps = buildHtmlProps(htmlOptions) + return ( + <div + {...htmlProps} + className={classnames('pb_timeline_item_step', globalProps(props), className)} + > + {children ? ( + children + ) : ( + <IconCircle icon={icon} + size="xs" + variant={iconColor} + /> + )} + <div className="pb_timeline_item_connector" /> + </div> + ) +} + +export default TimelineStep diff --git a/playbook/app/pb_kits/playbook/pb_timeline/subcomponents/index.tsx b/playbook/app/pb_kits/playbook/pb_timeline/subcomponents/index.tsx new file mode 100644 index 0000000000..693e027a7d --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_timeline/subcomponents/index.tsx @@ -0,0 +1,3 @@ +export { default as TimelineLabel } from './Label'; +export { default as TimelineDetail } from './Detail'; +export { default as TimelineStep } from './Step'; diff --git a/playbook/app/pb_kits/playbook/pb_timeline/timeline.test.js b/playbook/app/pb_kits/playbook/pb_timeline/timeline.test.js index fa71db5bad..9468e2070d 100644 --- a/playbook/app/pb_kits/playbook/pb_timeline/timeline.test.js +++ b/playbook/app/pb_kits/playbook/pb_timeline/timeline.test.js @@ -2,6 +2,10 @@ import React from 'react' import { render, screen } from '../utilities/test-utils' import Timeline from './_timeline' +import TimelineItem from './_item' +import TimelineLabel from './subcomponents/Label' +import TimelineStep from './subcomponents/Step' +import TimelineDetail from './subcomponents/Detail' import TitleDetail from '../pb_title_detail/_title_detail' const testId = 'timeline' @@ -43,18 +47,91 @@ const TimelineDefault = (props) => ( </> ) +const TimelineWithChildren = (props) => ( + <> + <Timeline + className={className} + data={{ testid: testId }} + orientation="horizontal" + showDate + {...props} + > + <TimelineItem lineStyle="solid" + {...props} + > + <TimelineLabel date={new Date()} /> + <TimelineStep icon="user" + iconColor="royal" + /> + <TimelineDetail> + <TitleDetail + detail="37-27 74th Street" + title="Jackson Heights" + {...props} + /> + </TimelineDetail> + </TimelineItem> + + <TimelineItem lineStyle="dotted" + {...props} + > + <TimelineStep icon="check" + iconColor="teal" + /> + <TimelineDetail> + <TitleDetail + detail="81 Gate St Brooklyn" + title="Greenpoint" + {...props} + /> + </TimelineDetail> + </TimelineItem> + + <TimelineItem lineStyle="solid" + {...props} + > + <TimelineLabel + date={new Date(new Date().setDate(new Date().getDate() + 1))} + /> + <TimelineStep icon="map-marker-alt" + iconColor="purple" + /> + <TimelineDetail> + <TitleDetail + detail="72 E St Astoria" + title="Society Hill" + {...props} + /> + </TimelineDetail> + </TimelineItem> + </Timeline> + </> +) + test('should pass data prop', () => { render(<TimelineDefault />) const kit = screen.getByTestId(testId) expect(kit).toBeInTheDocument() }) +test('should pass data prop using children', () => { + render(<TimelineWithChildren />) + const kit = screen.getByTestId(testId) + expect(kit).toBeInTheDocument() +}) + test('should pass className prop', () => { render(<TimelineDefault />) const kit = screen.getByTestId(testId) expect(kit).toHaveClass(className) }) +test('should pass className prop with children', () => { + render(<TimelineWithChildren />) + const kit = screen.getByTestId(testId) + expect(kit).toHaveClass(className) +}) + test('should pass aria prop', () => { render(<TimelineDefault />) const kit = screen.getByTestId(testId) @@ -86,3 +163,10 @@ test('should pass showDate prop', () => { const kit = screen.getByTestId(testId) expect(kit).toHaveClass('pb_timeline_kit__horizontal__with_date') }) + +test('should pass showDate prop with Children', () => { + const props = { showDate: true } + render(<TimelineWithChildren {...props} />) + const kit = screen.getByTestId(testId) + expect(kit).toHaveClass('pb_timeline_kit__horizontal__with_date') +}) diff --git a/playbook/spec/pb_kits/playbook/kits/timeline_detail_spec.rb b/playbook/spec/pb_kits/playbook/kits/timeline_detail_spec.rb new file mode 100644 index 0000000000..fc77b24b5c --- /dev/null +++ b/playbook/spec/pb_kits/playbook/kits/timeline_detail_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require_relative "../../../../app/pb_kits/playbook/pb_timeline/detail" + +RSpec.describe Playbook::PbTimeline::Detail do + subject { Playbook::PbTimeline::Detail } + + describe "#classname" do + it "returns the correct class name" do + expect(subject.new({}).classname).to eq "pb_timeline_item_right_block" + end + end +end diff --git a/playbook/spec/pb_kits/playbook/kits/timeline_label_spec.rb b/playbook/spec/pb_kits/playbook/kits/timeline_label_spec.rb new file mode 100644 index 0000000000..555837360d --- /dev/null +++ b/playbook/spec/pb_kits/playbook/kits/timeline_label_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require_relative "../../../../app/pb_kits/playbook/pb_timeline/label" + +RSpec.describe Playbook::PbTimeline::Label do + subject { Playbook::PbTimeline::Label } + + it { is_expected.to define_prop(:date) } + + describe "#classname" do + it "returns the correct class name" do + expect(subject.new.classname).to eq "pb_timeline_item_left_block" + end + end +end diff --git a/playbook/spec/pb_kits/playbook/kits/timeline_step_spec.rb b/playbook/spec/pb_kits/playbook/kits/timeline_step_spec.rb new file mode 100644 index 0000000000..ecbe365c72 --- /dev/null +++ b/playbook/spec/pb_kits/playbook/kits/timeline_step_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require_relative "../../../../app/pb_kits/playbook/pb_timeline/step" + +RSpec.describe Playbook::PbTimeline::Step do + subject { Playbook::PbTimeline::Step } + + it { is_expected.to define_prop(:icon) } + + it { + is_expected.to define_enum_prop(:icon_color) + .with_default("default") + .with_values("default", "royal", "blue", "purple", "teal", "red", "yellow", "green") + } + + describe "#classname" do + it "returns the correct class name" do + expect(subject.new.classname).to eq "pb_timeline_item_step" + end + end +end