Skip to content

Commit

Permalink
feat: hds-copy-snippet (#2157)
Browse files Browse the repository at this point in the history
  • Loading branch information
thiskevinwang authored Sep 6, 2023
1 parent 6f27c33 commit c1350c5
Show file tree
Hide file tree
Showing 3 changed files with 283 additions and 0 deletions.
128 changes: 128 additions & 0 deletions src/components/hds-copy-snippet/copy-snippet.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
.hds-copy-snippet {
position: relative;
outline-style: solid;
outline-color: transparent;
isolation: isolate;
display: flex;
gap: 8px;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 6px 4px;
white-space: normal;
text-align: left;
overflow-wrap: anywhere;
border: 1px solid transparent;
border-radius: 5px;
cursor: pointer;

&::before {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: -1;
border-radius: 5px;
content: '';
}

&.mock-focus::before,
&:focus::before {
box-shadow: var(--token-focus-ring-action-box-shadow);
}

&:focus:not(:focus-visible)::before {
box-shadow: none;
}

&:focus-visible::before {
box-shadow: var(--token-focus-ring-action-box-shadow);
}

&.mock-focus.mock-active::before,
&:focus:active::before {
box-shadow: none;
}
}

.hds-copy-snippet--color-primary {
color: var(--token-color-foreground-action);
background-color: var(--token-color-surface-interactive);

&.mock-hover,
&:hover {
color: var(--token-color-foreground-action-hover);
border-color: var(--token-color-border-strong);
}

&.mock-active,
&:active {
color: var(--token-color-foreground-action-active);
background-color: var(--token-color-surface-interactive-active);
border-color: var(--token-color-border-strong);
}
}

.hds-copy-snippet--color-secondary {
color: var(--token-color-foreground-primary);
background-color: var(--token-color-surface-interactive);

&.mock-hover,
&:hover {
border-color: var(--token-color-border-strong);
}

&.mock-active,
&:active {
background-color: var(--token-color-surface-interactive-active);
border-color: var(--token-color-border-strong);
}

& .hds-copy-snippet__icon {
color: var(--token-color-foreground-action);

&:hover {
color: var(--token-color-foreground-action-hover);
}

&:active {
color: var(--token-color-foreground-action-active);
}

&:focus {
color: var(--token-color-foreground-action);
}
}
}

.hds-copy-snippet--status-success .hds-copy-snippet__icon {
color: var(--token-color-foreground-success);
}

.hds-copy-snippet--status-error .hds-copy-snippet__icon {
color: var(--token-color-foreground-critical);
}

.hds-copy-snippet__text {
flex: 1 0 0;
max-width: calc(100% - 24px);
}

.hds-copy-snippet__icon {
flex: none;
}

.hds-copy-snippet--width-full {
justify-content: center;

& .hds-copy-snippet__text {
flex: 0 0 auto;
}
}

.hds-copy-snippet__text--truncated {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
60 changes: 60 additions & 0 deletions src/components/hds-copy-snippet/docs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
componentName: CopySnippet
---

https://helios.hashicorp.design/components/copy/snippet

## Overview

A button that enables users to copy a snippet of code

### Basic Usage

<LiveComponent>
{`<div
style={{
marginTop: 20,
padding: 20,
background: '#eee',
}}>
<CopySnippet
textToCopy={"user_04f349fb-b868-4399-a210-1a407099dfdc"}
/>
</div>`}
</LiveComponent>

### Other props

<LiveComponent>
{`<div
style={{
marginTop: 20,
padding: 20,
background: '#eee',
}}>
<CopySnippet
textToCopy={"user_04f349fb-b868-4399-a210-1a407099dfdc"}
color="secondary"
isFullWidth
/>
</div>`}
</LiveComponent>

<LiveComponent>
{`<div
style={{
marginTop: 20,
padding: 20,
background: '#eee',
}}>
<div
style={{maxWidth: '10em'}}
>
<CopySnippet
textToCopy={"user_04f349fb-b868-4399-a210-1a407099dfdc"}
color="secondary"
isTruncated
/>
</div>
</div>`}
</LiveComponent>
95 changes: 95 additions & 0 deletions src/components/hds-copy-snippet/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { useState, useEffect } from 'react'
import { IconClipboardCopy16 } from '@hashicorp/flight-icons/svg-react/clipboard-copy-16'
import { IconClipboardChecked16 } from '@hashicorp/flight-icons/svg-react/clipboard-checked-16'
import { IconClipboardX16 } from '@hashicorp/flight-icons/svg-react/clipboard-x-16'

import cn from 'classnames'
import s from './copy-snippet.module.css'

interface CopySnippetProps {
/**
* @default primary
*/
color?: 'primary' | 'secondary'
/**
* Indicates that the component should take up the full width of the parent container.
* @default false
*/
isFullWidth?: boolean
/** String value or action that returns a string to be copied. */
textToCopy: string
/**
* Selector string or element object of containing element, typically used in conjunction with modals; set the focused element as the container value.
*/
container?: string
/**
* Constrains text to one line and truncates it based on available width. Text will only be truncated if it does not fit within the available space.
*
* @default false
*/
isTruncated?: boolean
}

/**
* @see https://helios.hashicorp.design/components/copy/snippet
*/
export default function CopySnippet({
textToCopy,
color = 'primary',
isFullWidth = false,
isTruncated = false,
}: CopySnippetProps) {
// note: error exists in the original HDS css but
// is not yet used in this component
const [status, setStatus] = useState<'idle' | 'success' | 'error'>('idle')

const handleClick = () => {
setStatus('success')
navigator.clipboard.writeText(textToCopy)
}
useEffect(() => {
if (status !== 'idle') {
const timeout = setTimeout(() => {
setStatus('idle')
}, 3000)
return () => {
clearTimeout(timeout)
}
}
}, [status])

return (
<button
className={cn(s['hds-copy-snippet'], {
[s['hds-copy-snippet--color-primary']]: color === 'primary',
[s['hds-copy-snippet--color-secondary']]: color === 'secondary',
[s['hds-copy-snippet--width-full']]: isFullWidth,
[s['hds-copy-snippet--status-success']]: status === 'success',
[s['hds-copy-snippet--status-error']]: status === 'error',
})}
type="button"
onClick={handleClick}
>
<span
className={cn(
s['hds-copy-snippet__text'],
'hds-typography-code-100', // global
{
[s['hds-copy-snippet__text--truncated']]: isTruncated,
}
)}
>
{textToCopy}
</span>
{status == 'idle' && (
<IconClipboardCopy16 className={s['hds-copy-snippet__icon']} />
)}
{status == 'success' && (
<IconClipboardChecked16 className={s['hds-copy-snippet__icon']} />
)}
{status == 'error' && (
<IconClipboardX16 className={s['hds-copy-snippet__icon']} />
)}
</button>
)
}

1 comment on commit c1350c5

@vercel
Copy link

@vercel vercel bot commented on c1350c5 Sep 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.