Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions packages/__docs__/versioned-components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import * as V11_6 from '@instructure/ui/v11_6'
import * as V11_7 from '@instructure/ui/v11_7'
import * as V11_8 from '@instructure/ui/v11_8'
// eslint-disable-next-line no-restricted-imports
import { Guidelines } from './src/Guidelines'
// eslint-disable-next-line no-restricted-imports
Expand All @@ -33,20 +34,24 @@ import { ToggleBlockquote } from './src/ToggleBlockquote'
// eslint-disable-next-line no-restricted-imports
import { V12ChangelogTable } from './src/V12ChangelogTable'

const docsComponents = { Guidelines, Figure, ToggleBlockquote, V12ChangelogTable }
const docsComponents = {
Guidelines,
Figure,
ToggleBlockquote,
V12ChangelogTable
}

const versions: Record<string, Record<string, any>> = {
v11_6: { ...V11_6, ...docsComponents } as any,
v11_7: { ...V11_7, ...docsComponents } as any,
v11_8: { ...V11_8, ...docsComponents } as any
}

/**
* Returns the full component map for a given library version.
* Version exports are merged with docs-specific components (Guidelines,
* Figure, ToggleBlockquote, V12ChangelogTable). Defaults to v11_6.
*/
export function getComponentsForVersion(
version?: string
): Record<string, any> {
export function getComponentsForVersion(version?: string): Record<string, any> {
return versions[version ?? 'v11_6'] ?? versions['v11_6']
}
19 changes: 13 additions & 6 deletions packages/ui-pill/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@instructure/console": "workspace:*",
"@instructure/emotion": "workspace:*",
"@instructure/shared-types": "workspace:*",
"@instructure/ui-icons": "workspace:*",
"@instructure/ui-react-utils": "workspace:*",
"@instructure/ui-themes": "workspace:*",
"@instructure/ui-tooltip": "workspace:*",
Expand All @@ -38,7 +39,6 @@
"@instructure/ui-axe-check": "workspace:*",
"@instructure/ui-babel-preset": "workspace:*",
"@instructure/ui-color-utils": "workspace:*",
"@instructure/ui-icons": "workspace:*",
"@instructure/ui-scripts": "workspace:*",
"vitest": "^5.0.0"
},
Expand Down Expand Up @@ -76,12 +76,19 @@
"require": "./lib/exports/b.js",
"default": "./es/exports/b.js"
},
"./v11_8": {
"src": "./src/exports/c.ts",
"types": "./types/exports/c.d.ts",
"import": "./es/exports/c.js",
"require": "./lib/exports/c.js",
"default": "./es/exports/c.js"
},
"./latest": {
"src": "./src/exports/b.ts",
"types": "./types/exports/b.d.ts",
"import": "./es/exports/b.js",
"require": "./lib/exports/b.js",
"default": "./es/exports/b.js"
"src": "./src/exports/c.ts",
"types": "./types/exports/c.d.ts",
"import": "./es/exports/c.js",
"require": "./lib/exports/c.js",
"default": "./es/exports/c.js"
}
}
}
62 changes: 19 additions & 43 deletions packages/ui-pill/src/Pill/__tests__/Pill.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,11 @@
*/

import { render } from 'vitest-browser-react'
import { page, userEvent } from 'vitest/browser'
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { describe, it, expect, vi } from 'vitest'

import { runAxeCheck } from '@instructure/ui-axe-check'
import { Pill } from '@instructure/ui-pill/latest'
import { IconEyeLine } from '@instructure/ui-icons'
import { IconEyeLine, CheckInstUIIcon } from '@instructure/ui-icons'

describe('<Pill />', () => {
it('should render', async () => {
Expand Down Expand Up @@ -78,45 +77,22 @@ describe('<Pill />', () => {
expect(axeCheck).toBe(true)
})

describe('Component tests', () => {
// the real cursor stays where the previous test left it, which can keep a
// Tooltip open: park it off-component before each test
beforeEach(async () => {
const parkingSpot = document.createElement('div')
parkingSpot.style.cssText =
'position:fixed;right:0;bottom:0;width:20px;height:20px'
document.body.appendChild(parkingSpot)
await userEvent.hover(parkingSpot)
parkingSpot.remove()
})

it('should render without a Tooltip when text does not overflow max-width', async () => {
await render(<Pill>hello</Pill>)

await page.getByText('hello').hover()

expect(document.querySelector('span[role="tooltip"]')).toBeNull()
})

it('should render a Tooltip when text overflows max-width', async () => {
const text =
'some really super incredibly long text that will force overflow'
await render(<Pill>{text}</Pill>)
const trigger = document.querySelector<HTMLElement>(
'span[data-popover-trigger="true"]'
)!
const tooltip = () =>
document.querySelector<HTMLElement>('span[role="tooltip"]')!

expect(trigger).toMatchTextContent(text)
expect(tooltip()).not.toBeVisible()

await userEvent.hover(trigger)

await vi.waitFor(() => {
expect(tooltip()).toBeVisible()
})
expect(tooltip()).toMatchTextContent(text)
})
it('should accept an icon component reference', async () => {
const { container } = await render(
<Pill renderIcon={CheckInstUIIcon}>Overdue</Pill>
)

expect(container.querySelector('svg')).toBeInTheDocument()
})

it('should provide a ref to the root element', async () => {
const elementRef = vi.fn()
const { container } = await render(
<Pill elementRef={elementRef}>Overdue</Pill>
)

expect(elementRef).toHaveBeenCalledWith(
container.querySelector('[data-cid="Pill"]')
)
})
})
6 changes: 3 additions & 3 deletions packages/ui-pill/src/Pill/v2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@

import { Component } from 'react'

import { View } from '@instructure/ui-view/latest'
import { View } from '@instructure/ui-view/v11_7'
import { passthroughProps } from '@instructure/ui-react-utils'
import { Tooltip } from '@instructure/ui-tooltip/latest'
import type { TooltipRenderChildrenArgs } from '@instructure/ui-tooltip/latest'
import { Tooltip } from '@instructure/ui-tooltip/v11_7'
import type { TooltipRenderChildrenArgs } from '@instructure/ui-tooltip/v11_7'

import { withStyleNew } from '@instructure/emotion'

Expand Down
122 changes: 122 additions & 0 deletions packages/ui-pill/src/Pill/v3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
---
describes: Pill
---

Displays short, contextual information about an item. Set the color via the
`color` prop and the size via the `size` prop. Use the `margin` prop to add space
around the component. Use the `renderIcon` prop to add an icon before the text.
Additionally, you can use the `statusLabel` prop to add a label before the main text.

```js
---
type: example
---
<div>
<Pill
margin="general.spaceSm"
>
Excused
</Pill>
<Pill
statusLabel="Status"
color="info"
margin="general.spaceSm"
>
Draft
</Pill>
<Pill
statusLabel="Status"
renderIcon={DiamondInstUIIcon}
color="success"
margin="general.spaceSm"
>
Checked In
</Pill>
<Pill
renderIcon={Clock4InstUIIcon}
color="warning"
margin="general.spaceSm"
>
Late
</Pill>
<Pill
renderIcon={MailInstUIIcon}
color="error"
margin="general.spaceSm"
>
Notification
</Pill>
</div>
```

### Sizes

The `size` prop accepts `x-small`, `small` (default), `medium`, and `large`.
InstUI icons passed to `renderIcon` are sized to match.

```js
---
type: example
---
<div>
<Pill size="x-small" renderIcon={DiamondInstUIIcon} margin="general.spaceSm">
x-small
</Pill>
<Pill size="small" renderIcon={DiamondInstUIIcon} margin="general.spaceSm">
small
</Pill>
<Pill size="medium" renderIcon={DiamondInstUIIcon} margin="general.spaceSm">
medium
</Pill>
<Pill size="large" renderIcon={DiamondInstUIIcon} margin="general.spaceSm">
large
</Pill>
</div>
```

### Colors

The status colors (`primary`, `info`, `success`, `warning`, `error`) convey meaning.
`primary` is the neutral Pill in the design files. The accent colors (`stone`, `sky`,
`orange`, `aurora`, `plum`, `violet`, `sea`) are for categorization and carry no
status meaning.

```js
---
type: example
---
<div>
<Pill color="primary" margin="general.spaceSm">primary</Pill>
<Pill color="info" margin="general.spaceSm">info</Pill>
<Pill color="success" margin="general.spaceSm">success</Pill>
<Pill color="warning" margin="general.spaceSm">warning</Pill>
<Pill color="error" margin="general.spaceSm">error</Pill>
<br />
<Pill color="stone" margin="general.spaceSm">stone</Pill>
<Pill color="sky" margin="general.spaceSm">sky</Pill>
<Pill color="orange" margin="general.spaceSm">orange</Pill>
<Pill color="aurora" margin="general.spaceSm">aurora</Pill>
<Pill color="plum" margin="general.spaceSm">plum</Pill>
<Pill color="violet" margin="general.spaceSm">violet</Pill>
<Pill color="sea" margin="general.spaceSm">sea</Pill>
</div>
```

The Pill always shows its full text on a single line, so keep the text short.

### Guidelines

```js
---
type: embed
---
<Guidelines>
<Figure recommendation="no" title="Don't">
<Figure.Item>Use more than 2 words for the main text</Figure.Item>
<Figure.Item>Use more than 2 words for the statusLabel</Figure.Item>
<Figure.Item>Use for dismissible items (use a <Link href="/#Tag">Tag</Link> instead)</Figure.Item>
<Figure.Item>Use for counts (use a <Link href="/#Badge">Badge</Link> instead)</Figure.Item>
<Figure.Item>Put actions next to the text</Figure.Item>
</Figure>
</Guidelines>
```
102 changes: 102 additions & 0 deletions packages/ui-pill/src/Pill/v3/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 - present Instructure, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

import { View } from '@instructure/ui-view/latest'
import { passthroughProps } from '@instructure/ui-react-utils'
import { renderIconWithProps } from '@instructure/ui-icons'

import { useStyleNew } from '@instructure/emotion'

import generateStyle from './styles.js'

import type { PillProps } from './props'
import { pillSizeToIconSize } from './props.js'

/**
---
category: components
---
**/
const Pill = (props: PillProps) => {
const {
as,
children,
color = 'primary',
size = 'small',
elementRef,
margin,
statusLabel,
renderIcon,
themeOverride,
...rest
} = props

const styles = useStyleNew({
generateStyle,
themeOverride,
params: { color, size },
componentId: 'Pill',
displayName: 'Pill'
})

return (
<View
{...passthroughProps(rest)}
as={as}
elementRef={elementRef}
margin={margin}
padding="0"
background="transparent"
borderRadius="pill"
borderWidth="0"
display="inline-block"
position="relative"
data-cid="Pill"
>
<div css={styles?.pill}>
{renderIcon && (
<div css={styles?.icon}>
{renderIconWithProps(
renderIcon,
pillSizeToIconSize[size],
undefined
)}
</div>
)}
<div css={styles?.text}>
{statusLabel && (
<span css={styles?.status}>{statusLabel.concat(':')}</span>
)}
{children}
</div>
</div>
</View>
)
}

Pill.displayName = 'Pill'

export default Pill
export { Pill }
export type { PillProps }
Loading
Loading