@returnless/focus-ui 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +23 -0
- package/dist/focus-ui.es.js +33 -0
- package/dist/types/components/Accordion/Accordion.vue.d.ts +32 -0
- package/dist/types/components/Accordion/AccordionItem.vue.d.ts +2 -0
- package/dist/types/components/Accordion/index.d.ts +2 -0
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/index.d.ts +7 -0
- package/package.json +53 -0
- package/src/build-utils/generate-component-meta.ts +76 -0
- package/src/build-utils/update-component-list.js +31 -0
- package/src/build-utils/update-component-list.ts +32 -0
- package/src/components/Accordion/Accordion.vue +20 -0
- package/src/components/Accordion/AccordionContent.vue +14 -0
- package/src/components/Accordion/AccordionItem.vue +18 -0
- package/src/components/Accordion/AccordionTrigger.vue +35 -0
- package/src/components/Accordion/README.md +56 -0
- package/src/components/Accordion/index.ts +4 -0
- package/src/components/Alert/Alert.vue +55 -0
- package/src/components/Alert/AlertDescription.vue +8 -0
- package/src/components/Alert/AlertTitle.vue +11 -0
- package/src/components/Alert/DismissableAlertButton.vue +34 -0
- package/src/components/Alert/README.md +121 -0
- package/src/components/Alert/index.ts +3 -0
- package/src/components/AlertDialog/AlertDialog.vue +45 -0
- package/src/components/AlertDialog/AlertDialogActionButton.vue +9 -0
- package/src/components/AlertDialog/AlertDialogCancelButton.vue +15 -0
- package/src/components/AlertDialog/AlertDialogContent.vue +8 -0
- package/src/components/AlertDialog/AlertDialogDescription.vue +11 -0
- package/src/components/AlertDialog/AlertDialogFooter.vue +11 -0
- package/src/components/AlertDialog/AlertDialogHeader.vue +8 -0
- package/src/components/AlertDialog/AlertDialogTitle.vue +7 -0
- package/src/components/AlertDialog/README.md +85 -0
- package/src/components/AlertDialog/index.ts +8 -0
- package/src/components/Avatar/Avatar.vue +78 -0
- package/src/components/Avatar/README.md +122 -0
- package/src/components/Avatar/index.ts +1 -0
- package/src/components/Badge/Badge.vue +51 -0
- package/src/components/Badge/BadgeContent.vue +9 -0
- package/src/components/Badge/BadgeIcon.vue +7 -0
- package/src/components/Badge/README.md +131 -0
- package/src/components/Badge/index.ts +3 -0
- package/src/components/Button/Button.vue +63 -0
- package/src/components/Button/ButtonContent.vue +7 -0
- package/src/components/Button/ButtonIcon.vue +7 -0
- package/src/components/Button/README.md +228 -0
- package/src/components/Button/index.ts +3 -0
- package/src/components/ButtonGroup/ButtonGroup.vue +7 -0
- package/src/components/ButtonGroup/README.md +42 -0
- package/src/components/ButtonGroup/index.ts +1 -0
- package/src/components/Card/Card.vue +7 -0
- package/src/components/Card/CardDescription.vue +11 -0
- package/src/components/Card/CardFooter.vue +7 -0
- package/src/components/Card/CardHeader.vue +7 -0
- package/src/components/Card/CardSection.vue +7 -0
- package/src/components/Card/CardTitle.vue +8 -0
- package/src/components/Card/README.md +69 -0
- package/src/components/Card/index.ts +6 -0
- package/src/components/CategoryBar/CategoryBar.vue +25 -0
- package/src/components/CategoryBar/CategoryBarItem.vue +34 -0
- package/src/components/CategoryBar/README.md +17 -0
- package/src/components/CategoryBar/index.ts +2 -0
- package/src/components/Checkbox/Checkbox.vue +49 -0
- package/src/components/Checkbox/README.md +82 -0
- package/src/components/Checkbox/index.ts +1 -0
- package/src/components/Collapsible/README.md +25 -0
- package/src/components/DataTable/README.md +56 -0
- package/src/components/DatePicker/DatePicker.vue +140 -0
- package/src/components/DatePicker/DatePickerCard.vue +9 -0
- package/src/components/DatePicker/README.md +59 -0
- package/src/components/DatePicker/index.ts +2 -0
- package/src/components/DescriptionList/DescriptionList.vue +18 -0
- package/src/components/DescriptionList/DescriptionListDescription.vue +8 -0
- package/src/components/DescriptionList/DescriptionListItem.vue +21 -0
- package/src/components/DescriptionList/DescriptionListTerm.vue +11 -0
- package/src/components/DescriptionList/README.md +159 -0
- package/src/components/DescriptionList/index.ts +4 -0
- package/src/components/EmptyState/EmptyState.vue +13 -0
- package/src/components/EmptyState/EmptyStateActions.vue +11 -0
- package/src/components/EmptyState/EmptyStateContent.vue +7 -0
- package/src/components/EmptyState/EmptyStateDescription.vue +11 -0
- package/src/components/EmptyState/EmptyStateTitle.vue +7 -0
- package/src/components/EmptyState/README.md +102 -0
- package/src/components/EmptyState/index.ts +5 -0
- package/src/components/Feed/Feed.vue +7 -0
- package/src/components/Feed/FeedItem.vue +16 -0
- package/src/components/Feed/FeedItemBlock.vue +8 -0
- package/src/components/Feed/FeedItemDateIndicator.vue +11 -0
- package/src/components/Feed/FeedItemIcon.vue +26 -0
- package/src/components/Feed/FeedItemSimple.vue +8 -0
- package/src/components/Feed/README.md +115 -0
- package/src/components/Feed/index.ts +6 -0
- package/src/components/Form/Form.vue +30 -0
- package/src/components/Form/README.md +52 -0
- package/src/components/Form/index.ts +1 -0
- package/src/components/FormLayout/FormLayout.vue +7 -0
- package/src/components/FormLayout/README.md +59 -0
- package/src/components/FormLayout/index.ts +1 -0
- package/src/components/InputLabel/InputLabel.vue +32 -0
- package/src/components/InputLabel/index.ts +1 -0
- package/src/components/Link/Link.vue +38 -0
- package/src/components/Link/README.md +119 -0
- package/src/components/Link/index.ts +1 -0
- package/src/components/MetricCard/MetricCard.vue +11 -0
- package/src/components/MetricCard/MetricCardHeader.vue +7 -0
- package/src/components/MetricCard/MetricCardLabel.vue +9 -0
- package/src/components/MetricCard/MetricCardSection.vue +11 -0
- package/src/components/MetricCard/MetricCardValue.vue +8 -0
- package/src/components/MetricCard/README.md +53 -0
- package/src/components/MetricCard/index.ts +5 -0
- package/src/components/Navigation/Navigation.vue +8 -0
- package/src/components/Navigation/NavigationItem.vue +43 -0
- package/src/components/Navigation/NavigationSection.vue +27 -0
- package/src/components/Navigation/README.md +88 -0
- package/src/components/Navigation/index.ts +3 -0
- package/src/components/Page/Page.vue +38 -0
- package/src/components/Page/PageDescription.vue +11 -0
- package/src/components/Page/PageHeader.vue +34 -0
- package/src/components/Page/PageTitle.vue +9 -0
- package/src/components/Page/README.md +220 -0
- package/src/components/Page/index.ts +4 -0
- package/src/components/Pagination/Pagination.vue +8 -0
- package/src/components/Pagination/PaginationNextButton.vue +10 -0
- package/src/components/Pagination/PaginationPreviousButton.vue +10 -0
- package/src/components/Pagination/README.md +45 -0
- package/src/components/Pagination/index.ts +3 -0
- package/src/components/PinInput/PinInput.vue +169 -0
- package/src/components/PinInput/README.md +35 -0
- package/src/components/PinInput/index.ts +1 -0
- package/src/components/Popover/README.md +51 -0
- package/src/components/ProgressBar/ProgressBar.vue +33 -0
- package/src/components/ProgressBar/ProgressBarIndicator.vue +7 -0
- package/src/components/ProgressBar/README.md +98 -0
- package/src/components/ProgressBar/index.ts +2 -0
- package/src/components/RadioButton/README.md +111 -0
- package/src/components/RadioButton/RadioButton.vue +48 -0
- package/src/components/RadioButton/index.ts +1 -0
- package/src/components/Select/README.md +74 -0
- package/src/components/Select/Select.vue +91 -0
- package/src/components/Select/SelectGroup.vue +12 -0
- package/src/components/Select/SelectOption.vue +12 -0
- package/src/components/Select/index.ts +3 -0
- package/src/components/Separator/README.md +35 -0
- package/src/components/Separator/Separator.vue +7 -0
- package/src/components/Separator/index.ts +1 -0
- package/src/components/Spinner/README.md +53 -0
- package/src/components/Spinner/Spinner.vue +58 -0
- package/src/components/Spinner/index.ts +1 -0
- package/src/components/StatusIndicator/README.md +51 -0
- package/src/components/StatusIndicator/StatusIndicator.vue +38 -0
- package/src/components/StatusIndicator/index.ts +1 -0
- package/src/components/Tabs/README.md +53 -0
- package/src/components/Tabs/TabTrigger.vue +43 -0
- package/src/components/Tabs/Tabs.vue +13 -0
- package/src/components/Tabs/index.ts +2 -0
- package/src/components/Tag/README.md +27 -0
- package/src/components/TextField/README.md +317 -0
- package/src/components/TextField/TextField.vue +115 -0
- package/src/components/TextField/TextFieldPasswordIcon.vue +28 -0
- package/src/components/TextField/TextFieldSearchIcon.vue +11 -0
- package/src/components/TextField/index.ts +1 -0
- package/src/components/TextStyle/README.md +39 -0
- package/src/components/TextStyle/TextStyle.vue +24 -0
- package/src/components/TextStyle/index.ts +1 -0
- package/src/components/Toast/DismissToastAction.vue +34 -0
- package/src/components/Toast/README.md +167 -0
- package/src/components/Toast/Toast.vue +39 -0
- package/src/components/Toast/ToastGroup.vue +9 -0
- package/src/components/Toast/index.ts +2 -0
- package/src/components/Toggle/README.md +66 -0
- package/src/components/Toggle/Toggle.vue +86 -0
- package/src/components/Toggle/index.ts +1 -0
- package/src/components/Tooltip/README.md +51 -0
- package/src/components/Tooltip/Tooltip.vue +50 -0
- package/src/components/Tooltip/index.ts +1 -0
- package/src/components/TopBar/README.md +43 -0
- package/src/components/TopBar/TopBar.vue +7 -0
- package/src/components/TopBar/TopBarLogo.vue +8 -0
- package/src/components/TopBar/TopBarNavigation.vue +7 -0
- package/src/components/TopBar/TopBarNavigationItem.vue +13 -0
- package/src/components/TopBar/TopBarSearch.vue +15 -0
- package/src/components/TopBar/TopBarUserMenu.vue +20 -0
- package/src/components/TopBar/index.ts +6 -0
- package/src/components/VisuallyHidden/README.md +19 -0
- package/src/components/VisuallyHidden/VisuallyHidden.vue +25 -0
- package/src/components/VisuallyHidden/index.ts +1 -0
- package/src/components/index.ts +141 -0
- package/src/composables/index.ts +7 -0
- package/src/composables/useTailwindColor.ts +17 -0
- package/src/composables/useTheme.ts +29 -0
- package/src/composables/useToastNotifications.ts +55 -0
- package/src/composables/useUniqueId.ts +5 -0
- package/src/index.css +20 -0
- package/src/index.ts +12 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { Badge, BadgeContent, BadgeIcon } from '../../src/components';
|
|
3
|
+
import { ArrowTrendingUpIcon, ArrowTrendingDownIcon } from '@heroicons/vue/16/solid';
|
|
4
|
+
import api from '../component-meta/Badge.json';
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
# Badge
|
|
8
|
+
|
|
9
|
+
Badges are used to inform users of the tone of an object or of an action that's been taken.
|
|
10
|
+
|
|
11
|
+
<ComponentApi :api="api" />
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
<ComponentWrapper>
|
|
16
|
+
<ComponentGrid>
|
|
17
|
+
<Badge color="slate">Fulfilled</Badge>
|
|
18
|
+
<Badge color="blue">Draft</Badge>
|
|
19
|
+
<Badge color="green">Active</Badge>
|
|
20
|
+
<Badge color="yellow">Open</Badge>
|
|
21
|
+
<Badge color="red">Action required</Badge>
|
|
22
|
+
</ComponentGrid>
|
|
23
|
+
</ComponentWrapper>
|
|
24
|
+
|
|
25
|
+
```js-vue
|
|
26
|
+
<script lang="ts" setup>
|
|
27
|
+
import { Badge } from 'focus-ui';
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<Badge color="slate">Fulfilled</Badge>
|
|
32
|
+
<Badge color="blue">Draft</Badge>
|
|
33
|
+
<Badge color="green">Active</Badge>
|
|
34
|
+
<Badge color="yellow">Open</Badge>
|
|
35
|
+
<Badge color="red">Action required</Badge>
|
|
36
|
+
</template>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Badges with icons
|
|
40
|
+
|
|
41
|
+
Badges can include icons to help users quickly identify the tone of an object or action.
|
|
42
|
+
|
|
43
|
+
<ComponentWrapper>
|
|
44
|
+
<ComponentGrid>
|
|
45
|
+
<Badge color="green">
|
|
46
|
+
<BadgetContent>+ 25%</BadgetContent>
|
|
47
|
+
<BadgeIcon>
|
|
48
|
+
<ArrowTrendingUpIcon />
|
|
49
|
+
</BadgeIcon>
|
|
50
|
+
</Badge>
|
|
51
|
+
<Badge color="red">
|
|
52
|
+
<BadgeIcon>
|
|
53
|
+
<ArrowTrendingDownIcon />
|
|
54
|
+
</BadgeIcon>
|
|
55
|
+
<BadgetContent>- 25%</BadgetContent>
|
|
56
|
+
</Badge>
|
|
57
|
+
</ComponentGrid>
|
|
58
|
+
</ComponentWrapper>
|
|
59
|
+
|
|
60
|
+
```js-vue
|
|
61
|
+
<script lang="ts" setup>
|
|
62
|
+
import { Badge, BadgetContent, BadgeIcon } from 'focus-ui';
|
|
63
|
+
import { ArrowTrendingUpIcon, ArrowTrendingDownIcon } from '@heroicons/vue/16/solid';
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<template>
|
|
67
|
+
<Badge color="green">
|
|
68
|
+
<BadgetContent>+ 25%</BadgetContent>
|
|
69
|
+
<BadgeIcon>
|
|
70
|
+
<ArrowTrendingUpIcon />
|
|
71
|
+
</BadgeIcon>
|
|
72
|
+
</Badge>
|
|
73
|
+
<Badge color="red">
|
|
74
|
+
<BadgeIcon>
|
|
75
|
+
<ArrowTrendingDownIcon />
|
|
76
|
+
</BadgeIcon>
|
|
77
|
+
<BadgetContent>- 25%</BadgetContent>
|
|
78
|
+
</Badge>
|
|
79
|
+
</template>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Badge sizes
|
|
83
|
+
|
|
84
|
+
Badges come in three sizes: small, medium, and large.
|
|
85
|
+
|
|
86
|
+
<ComponentWrapper>
|
|
87
|
+
<ComponentGrid>
|
|
88
|
+
<Badge color="slate" size="sm">sm badge</Badge>
|
|
89
|
+
<Badge color="slate" size="md">md badge</Badge>
|
|
90
|
+
<Badge color="slate" size="lg">lg badge</Badge>
|
|
91
|
+
<Badge color="green">
|
|
92
|
+
<BadgeIcon>
|
|
93
|
+
<ArrowTrendingUpIcon />
|
|
94
|
+
</BadgeIcon>
|
|
95
|
+
<BadgetContent>sm with icon</BadgetContent>
|
|
96
|
+
</Badge>
|
|
97
|
+
<Badge color="blue" size="md">
|
|
98
|
+
<BadgeIcon>
|
|
99
|
+
<ArrowTrendingUpIcon />
|
|
100
|
+
</BadgeIcon>
|
|
101
|
+
<BadgetContent>md with icon</BadgetContent>
|
|
102
|
+
</Badge>
|
|
103
|
+
<Badge color="red" size="lg">
|
|
104
|
+
<BadgeIcon>
|
|
105
|
+
<ArrowTrendingDownIcon />
|
|
106
|
+
</BadgeIcon>
|
|
107
|
+
<BadgetContent>lg with icon</BadgetContent>
|
|
108
|
+
</Badge>
|
|
109
|
+
</ComponentGrid>
|
|
110
|
+
</ComponentWrapper>
|
|
111
|
+
|
|
112
|
+
## Best practices
|
|
113
|
+
|
|
114
|
+
Badges benefit users by:
|
|
115
|
+
|
|
116
|
+
- Using established color patterns so that users can quickly identify their tone or importance level.
|
|
117
|
+
- Being clearly labeled with short, scannable text.
|
|
118
|
+
- Being positioned to clearly identify the object they're informing or labelling.
|
|
119
|
+
|
|
120
|
+
## Content guidelines
|
|
121
|
+
|
|
122
|
+
Badge labels should:
|
|
123
|
+
|
|
124
|
+
- Use a single word to describe the tone of an object.
|
|
125
|
+
- Only use two words if you need to describe a complex state. For example "Partially refunded" and "Partially paid".
|
|
126
|
+
- Always describe the tone in the past tense. For example, refunded not refund.
|
|
127
|
+
|
|
128
|
+
## Accessibility
|
|
129
|
+
|
|
130
|
+
Badges that convey information with icons or color include text provided by the `visually hidden component`. The text is
|
|
131
|
+
read out by assistive technologies so that users with vision issues can access meaning of the badge in context.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
import { Spinner } from '../';
|
|
4
|
+
import { useTheme } from '../../composables';
|
|
5
|
+
|
|
6
|
+
const props = withDefaults(defineProps<{
|
|
7
|
+
/** Whether the button is disabled. */
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
|
|
10
|
+
/** Whether the button should open the link in a new tab. */
|
|
11
|
+
external?: boolean;
|
|
12
|
+
|
|
13
|
+
/** The URL the button should navigate to. */
|
|
14
|
+
href?: string | null;
|
|
15
|
+
|
|
16
|
+
/** Whether the button is in a loading state. */
|
|
17
|
+
loading?: boolean;
|
|
18
|
+
|
|
19
|
+
/** The variant of the button. */
|
|
20
|
+
variant?: 'primary' | 'secondary' | 'destructive' | 'outline' | 'ghost';
|
|
21
|
+
}>(), {
|
|
22
|
+
disabled: false,
|
|
23
|
+
external: false,
|
|
24
|
+
href: null,
|
|
25
|
+
loading: false,
|
|
26
|
+
variant: 'primary',
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const classList = computed(() => {
|
|
30
|
+
return [
|
|
31
|
+
{ 'bg-brand-500 hover:bg-brand-600 text-white border-brand-500': props.variant === 'primary' },
|
|
32
|
+
{ 'bg-slate-200 hover:bg-slate-300 border-slate-100': props.variant === 'secondary' },
|
|
33
|
+
{ 'bg-red-500 hover:bg-red-600 text-white border-red-500': props.variant === 'destructive' },
|
|
34
|
+
{ 'border-slate-300 hover:bg-slate-100': props.variant === 'outline' },
|
|
35
|
+
{ 'border-transparent hover:bg-slate-200': props.variant === 'ghost' },
|
|
36
|
+
|
|
37
|
+
{ 'opacity-50 cursor-not-allowed': props.disabled },
|
|
38
|
+
{ 'pointer-events-none opacity-75': props.loading },
|
|
39
|
+
|
|
40
|
+
...useTheme('focus'),
|
|
41
|
+
];
|
|
42
|
+
});
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<button
|
|
47
|
+
class="inline-flex items-center justify-center rounded border px-4 py-3 text-sm font-medium leading-none active:opacity-80 active:shadow-inner"
|
|
48
|
+
:class="classList"
|
|
49
|
+
:disabled="disabled || loading"
|
|
50
|
+
>
|
|
51
|
+
<span
|
|
52
|
+
class="inline-flex items-center justify-center space-x-4"
|
|
53
|
+
:class="{ 'invisible': loading }"
|
|
54
|
+
>
|
|
55
|
+
<slot />
|
|
56
|
+
</span>
|
|
57
|
+
|
|
58
|
+
<Spinner
|
|
59
|
+
v-if="loading"
|
|
60
|
+
class="absolute"
|
|
61
|
+
/>
|
|
62
|
+
</button>
|
|
63
|
+
</template>
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { Button, ButtonIcon, ButtonContent } from '../../src/components';
|
|
3
|
+
import api from '../component-meta/Button.json';
|
|
4
|
+
import { ArrowDownTrayIcon } from '@heroicons/vue/16/solid';
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
# Button
|
|
8
|
+
|
|
9
|
+
Buttons are used primarily for actions, such as “Add”, “Close”, “Cancel”, or “Save”. Plain buttons, which look similar
|
|
10
|
+
to links, are used for less important or less commonly used actions, such as “view shipping settings”.
|
|
11
|
+
|
|
12
|
+
<ComponentApi :api="api" />
|
|
13
|
+
|
|
14
|
+
## Variants
|
|
15
|
+
|
|
16
|
+
### Primary
|
|
17
|
+
|
|
18
|
+
Use to highlight the most important actions in any experience. Don’t use more than one primary button in a section or
|
|
19
|
+
screen to avoid overwhelming users.
|
|
20
|
+
|
|
21
|
+
<ComponentWrapper>
|
|
22
|
+
<Button variant="primary">Primary</Button>
|
|
23
|
+
</ComponentWrapper>
|
|
24
|
+
|
|
25
|
+
```js-vue
|
|
26
|
+
<script lang="ts" setup>
|
|
27
|
+
import { Button } from 'focus-ui';
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<Button variant="primary">Primary</Button>
|
|
32
|
+
</template>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Secondary
|
|
36
|
+
|
|
37
|
+
Used most in the interface. Only use another style if a button requires more or less visual weight.
|
|
38
|
+
|
|
39
|
+
<ComponentWrapper>
|
|
40
|
+
<Button variant="secondary">Secondary</Button>
|
|
41
|
+
</ComponentWrapper>
|
|
42
|
+
|
|
43
|
+
```js-vue
|
|
44
|
+
<script lang="ts" setup>
|
|
45
|
+
import { Button } from 'focus-ui';
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<template>
|
|
49
|
+
<Button variant="secondary">Primary</Button>
|
|
50
|
+
</template>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Destructive
|
|
54
|
+
|
|
55
|
+
Used when the action will delete user data or be otherwise difficult to recover from. Destructive buttons should
|
|
56
|
+
trigger a confirmation dialog before the action is completed. Be thoughtful about using destructive buttons because
|
|
57
|
+
they can feel stressful for users.
|
|
58
|
+
|
|
59
|
+
<ComponentWrapper>
|
|
60
|
+
<Button variant="destructive">Destructive</Button>
|
|
61
|
+
</ComponentWrapper>
|
|
62
|
+
|
|
63
|
+
```js-vue
|
|
64
|
+
<script lang="ts" setup>
|
|
65
|
+
import { Button } from 'focus-ui';
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
<template>
|
|
69
|
+
<Button variant="destructive">Destructive</Button>
|
|
70
|
+
</template>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Outline
|
|
74
|
+
|
|
75
|
+
Used for actions that are less important than primary or secondary actions.
|
|
76
|
+
|
|
77
|
+
<ComponentWrapper>
|
|
78
|
+
<Button variant="outline">Outline</Button>
|
|
79
|
+
</ComponentWrapper>
|
|
80
|
+
|
|
81
|
+
```js-vue
|
|
82
|
+
<script lang="ts" setup>
|
|
83
|
+
import { Button } from 'focus-ui';
|
|
84
|
+
</script>
|
|
85
|
+
|
|
86
|
+
<template>
|
|
87
|
+
<Button variant="outline">Outline</Button>
|
|
88
|
+
</template>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Ghost
|
|
92
|
+
|
|
93
|
+
Used for less important or less commonly used actions. Ghost buttons are less prominent than other button styles,
|
|
94
|
+
|
|
95
|
+
<ComponentWrapper>
|
|
96
|
+
<Button variant="ghost">Ghost</Button>
|
|
97
|
+
</ComponentWrapper>
|
|
98
|
+
|
|
99
|
+
```js-vue
|
|
100
|
+
<script lang="ts" setup>
|
|
101
|
+
import { Button } from 'focus-ui';
|
|
102
|
+
</script>
|
|
103
|
+
|
|
104
|
+
<template>
|
|
105
|
+
<Button variant="ghost">Ghost</Button>
|
|
106
|
+
</template>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Loading
|
|
110
|
+
|
|
111
|
+
Use when a button has been pressed and the associated action is in progress.
|
|
112
|
+
|
|
113
|
+
<ComponentWrapper>
|
|
114
|
+
<Button variant="secondary" loading>
|
|
115
|
+
Loading button
|
|
116
|
+
</Button>
|
|
117
|
+
</ComponentWrapper>
|
|
118
|
+
|
|
119
|
+
```js-vue
|
|
120
|
+
<script lang="ts" setup>
|
|
121
|
+
import { Button } from 'focus-ui';
|
|
122
|
+
</script>
|
|
123
|
+
|
|
124
|
+
<template>
|
|
125
|
+
<Button variant="secondary" loading>
|
|
126
|
+
Loading button
|
|
127
|
+
</Button>
|
|
128
|
+
</template>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Button with icon
|
|
132
|
+
|
|
133
|
+
Use when a button needs to be paired with an icon to help convey its purpose.
|
|
134
|
+
|
|
135
|
+
<ComponentWrapper>
|
|
136
|
+
<Button variant="primary">
|
|
137
|
+
<ButtonIcon>
|
|
138
|
+
<ArrowDownTrayIcon />
|
|
139
|
+
</ButtonIcon>
|
|
140
|
+
<ButtonContent>Button with icon</ButtonContent>
|
|
141
|
+
</Button>
|
|
142
|
+
</ComponentWrapper>
|
|
143
|
+
|
|
144
|
+
## Best practices
|
|
145
|
+
|
|
146
|
+
Buttons should:
|
|
147
|
+
|
|
148
|
+
- Be clearly and accurately labeled.
|
|
149
|
+
- Lead with a strong, actionable verb.
|
|
150
|
+
- Use established button colors appropriately. For example, only use a red button for an action that's difficult or
|
|
151
|
+
impossible to undo.
|
|
152
|
+
- Prioritize the most important actions. Too many calls to action can cause confusion and make users unsure of what
|
|
153
|
+
to do next.
|
|
154
|
+
- Be positioned in consistent locations in the interface.
|
|
155
|
+
|
|
156
|
+
### Buttons versus links
|
|
157
|
+
|
|
158
|
+
Buttons are used primarily for actions, such as "Add", "Close", "Cancel", or "Save". Plain buttons, which look
|
|
159
|
+
similar to links, are used for less important or less commonly used actions, such as "view shipping settings".
|
|
160
|
+
|
|
161
|
+
Links are used primarily for navigation, and usually appear within or directly following a sentence.
|
|
162
|
+
|
|
163
|
+
The HTML that renders for the `Button` and `Link` components carriers meaning. Using these components intentionally
|
|
164
|
+
and consistently results in:
|
|
165
|
+
|
|
166
|
+
- A more inclusive experience for assistive technology users.
|
|
167
|
+
- A more cohesive visual experience for sighted users.
|
|
168
|
+
- Products that are easier to maintain at scale.
|
|
169
|
+
|
|
170
|
+
## Content guidelines
|
|
171
|
+
|
|
172
|
+
Buttons need to be clear and predictable. Users should be able to anticipate what will happen when they select a
|
|
173
|
+
button. Never mislead someone by mislabeling a button.
|
|
174
|
+
|
|
175
|
+
Buttons should always lead with a strong verb that encourages action. To provide enough context to users, use the
|
|
176
|
+
{verb} + {noun} content formula on buttons except in the case of common actions like "Done", "Close", "Cancel", or "OK".
|
|
177
|
+
|
|
178
|
+
Always write button text in sentence case, which means the first word is capitalized and the rest are lowercase
|
|
179
|
+
(unless a term is a proper noun).
|
|
180
|
+
|
|
181
|
+
Avoid unnecessary words and articles such as "the", "an", or "a" to keep button text short and actionable.
|
|
182
|
+
|
|
183
|
+
## Accessibility
|
|
184
|
+
|
|
185
|
+
Buttons can have different states that are visually and programmatically conveyed to users.
|
|
186
|
+
|
|
187
|
+
- Use the `ariaControls` prop to add an `aria-controls` attribute to the button. Use the attribute to point to the
|
|
188
|
+
unique `id` of the content that the button manages.
|
|
189
|
+
- If a button expands or collapses adjacent content, then use the `ariaExpanded` prop to add the `aria-expanded`
|
|
190
|
+
attribute to the button. Set the value to convey the current expanded (`true`) or collapsed (`false`) state of the
|
|
191
|
+
content.
|
|
192
|
+
- Use the `disabled` prop to set the `disabled` state of the button. This prevents users from being able to interact
|
|
193
|
+
with the button, and conveys its inactive state to assistive technologies.
|
|
194
|
+
- Use the `pressed` prop to add an `aria-pressed` attribute to the button.
|
|
195
|
+
|
|
196
|
+
### Navigation
|
|
197
|
+
|
|
198
|
+
Users generally expect buttons to submit data or take action, and for links to navigate. If navigation is required
|
|
199
|
+
for the button component, use the `href` prop. The control will output an anchor styled as a button, instead of a
|
|
200
|
+
button in HTML, to help convey this difference.
|
|
201
|
+
|
|
202
|
+
### Labeling
|
|
203
|
+
|
|
204
|
+
THe `accessibilityLabel` prop adds an `aria-label` attribute to the button, which can be accessed by assistive
|
|
205
|
+
technologies like screen readers. Typically, this label text replaces the visible text on the button for users who
|
|
206
|
+
use assistive technologies.
|
|
207
|
+
|
|
208
|
+
Use `accessibilityLabel` for a button if:
|
|
209
|
+
|
|
210
|
+
- The button's visible text does not adequately convey the purpose of the button to non-visual users.
|
|
211
|
+
- The button has no text and relies on an icon alone to convey its purpose.
|
|
212
|
+
|
|
213
|
+
To help support users who use speech activation software as well as sighted screen reader users, make sure that the
|
|
214
|
+
`aria-label` text includes any button text that's visible. Mismatches between visible and programmatic labeling can
|
|
215
|
+
cause confusion, and might prevent voice recognition commands from working.
|
|
216
|
+
|
|
217
|
+
When possible, give the button visible text that clearly conveys its purpose without the user of
|
|
218
|
+
`accessibilityLabel`. When no additional content is needed, duplication the button text with `accessibilityLabel`
|
|
219
|
+
isn't necessary.
|
|
220
|
+
|
|
221
|
+
### External links
|
|
222
|
+
|
|
223
|
+
When you use the button component to create a link to an external resource:
|
|
224
|
+
|
|
225
|
+
- Use the `external` prop to make the link open in a new tab (or window, depending on the user's browser settings).
|
|
226
|
+
- Use the `icon` prop to add the `external` icon to the button.
|
|
227
|
+
- Use the `accessibilityLabel` prop to include the warning about opening a new tab in the button text for non-visual
|
|
228
|
+
screen reader users.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { Button, ButtonGroup } from '../../src/components';
|
|
3
|
+
import api from '../component-meta/ButtonGroup.json';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
# Button Group
|
|
7
|
+
|
|
8
|
+
Button group displays multiple related actions stacked or in a horizontal row to help with arrangement and spacing.
|
|
9
|
+
|
|
10
|
+
<ComponentApi :api="api" />
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
<ComponentWrapper>
|
|
15
|
+
<ButtonGroup>
|
|
16
|
+
<Button variant="secondary">Cancel</Button>
|
|
17
|
+
<Button variant="primary">Save</Button>
|
|
18
|
+
</ButtonGroup>
|
|
19
|
+
</ComponentWrapper>
|
|
20
|
+
|
|
21
|
+
```js-vue
|
|
22
|
+
<script lang="ts" setup>
|
|
23
|
+
import { Button, ButtonGroup } from 'focus-ui';
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<template>
|
|
27
|
+
<ButtonGroup>
|
|
28
|
+
<Button variant="secondary">Cancel</Button>
|
|
29
|
+
<Button variant="primary">Save</Button>
|
|
30
|
+
</ButtonGroup>
|
|
31
|
+
</template>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Best practices
|
|
35
|
+
|
|
36
|
+
Button groups should:
|
|
37
|
+
|
|
38
|
+
- Only use buttons that follow the best practices outlined in the button component.
|
|
39
|
+
- Group together calls to action that have a relationship.
|
|
40
|
+
- Be used with consideration that too many calls to action can cause users to be unsure of what to do next.
|
|
41
|
+
- Be thoughtful about how multiple buttons will look and work on small screens.
|
|
42
|
+
- Only be used in groups of up to six buttons if the buttons contain an icon with no text.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as ButtonGroup } from './ButtonGroup.vue';
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { Button, Card, CardSection, CardDescription, CardFooter, CardHeader, CardTitle } from '../../src/components';
|
|
3
|
+
import api from '../component-meta/Card.json';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
# Card
|
|
7
|
+
|
|
8
|
+
Cards are used to group similar concepts and tasks together for users to scan, read, and get things done. It displays
|
|
9
|
+
content in a familiar and recognizable style.
|
|
10
|
+
|
|
11
|
+
<ComponentApi :api="api" />
|
|
12
|
+
|
|
13
|
+
## Variants
|
|
14
|
+
|
|
15
|
+
<ComponentWrapper>
|
|
16
|
+
<Card>
|
|
17
|
+
<CardHeader>
|
|
18
|
+
<CardTitle>Notifications</CardTitle>
|
|
19
|
+
<CardDescription>You have 3 unread messages.</CardDescription>
|
|
20
|
+
</CardHeader>
|
|
21
|
+
<CardSection>
|
|
22
|
+
<div>Card content</div>
|
|
23
|
+
</CardSection>
|
|
24
|
+
<CardFooter>
|
|
25
|
+
<Button variant="primary">Button</Button>
|
|
26
|
+
</CardFooter>
|
|
27
|
+
</Card>
|
|
28
|
+
</ComponentWrapper>
|
|
29
|
+
|
|
30
|
+
```js-vue
|
|
31
|
+
<script lang="ts" setup>
|
|
32
|
+
import {
|
|
33
|
+
Button,
|
|
34
|
+
Card,
|
|
35
|
+
CardSection,
|
|
36
|
+
CardDescription,
|
|
37
|
+
CardFooter,
|
|
38
|
+
CardHeader,
|
|
39
|
+
CardTitle,
|
|
40
|
+
} from 'focus-ui';
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<template>
|
|
44
|
+
<Card>
|
|
45
|
+
<CardHeader>
|
|
46
|
+
<CardTitle>Notifications</CardTitle>
|
|
47
|
+
<CardDescription>You have 3 unread messages.</CardDescription>
|
|
48
|
+
</CardHeader>
|
|
49
|
+
<CardSection>
|
|
50
|
+
<div>Card content</div>
|
|
51
|
+
</CardSection>
|
|
52
|
+
<CardFooter>
|
|
53
|
+
<Button variant="primary">Button</Button>
|
|
54
|
+
</CardFooter>
|
|
55
|
+
</Card>
|
|
56
|
+
</template>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Best practices
|
|
60
|
+
|
|
61
|
+
Cards should:
|
|
62
|
+
|
|
63
|
+
- Group related information.
|
|
64
|
+
- Display information in a way that prioritizes what the user needs to know most first.
|
|
65
|
+
- Use headings that set clear expectations about the card's purpose.
|
|
66
|
+
- Stick to single user flows or break more complicated flows into multiple sections.
|
|
67
|
+
- Avoid too many call-to-action buttons or links and only one primary call to action per card.
|
|
68
|
+
- Use calls to action on bottom of the card for next steps and use the space in the upper right corner of the card
|
|
69
|
+
for persistent, option actions (such as Edit).
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default as Card } from './Card.vue';
|
|
2
|
+
export { default as CardSection } from './CardSection.vue';
|
|
3
|
+
export { default as CardDescription } from './CardDescription.vue';
|
|
4
|
+
export { default as CardFooter } from './CardFooter.vue';
|
|
5
|
+
export { default as CardHeader } from './CardHeader.vue';
|
|
6
|
+
export { default as CardTitle } from './CardTitle.vue';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { computed, provide, useSlots, VNode } from 'vue';
|
|
3
|
+
|
|
4
|
+
const slots = useSlots();
|
|
5
|
+
|
|
6
|
+
const totalCategoryBarWidth = computed((): number => {
|
|
7
|
+
if (!slots.default) {
|
|
8
|
+
return 0;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const slotValues = slots.default().map((slot: VNode) => {
|
|
12
|
+
return slot.props!.value;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
return slotValues.reduce((acc: number, value: number) => acc + value, 0);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
provide('totalCategoryBarWidth', totalCategoryBarWidth);
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<template>
|
|
22
|
+
<div class="flex w-full space-x-0.5">
|
|
23
|
+
<slot />
|
|
24
|
+
</div>
|
|
25
|
+
</template>
|