@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.
Files changed (194) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +23 -0
  3. package/dist/focus-ui.es.js +33 -0
  4. package/dist/types/components/Accordion/Accordion.vue.d.ts +32 -0
  5. package/dist/types/components/Accordion/AccordionItem.vue.d.ts +2 -0
  6. package/dist/types/components/Accordion/index.d.ts +2 -0
  7. package/dist/types/components/index.d.ts +1 -0
  8. package/dist/types/index.d.ts +7 -0
  9. package/package.json +53 -0
  10. package/src/build-utils/generate-component-meta.ts +76 -0
  11. package/src/build-utils/update-component-list.js +31 -0
  12. package/src/build-utils/update-component-list.ts +32 -0
  13. package/src/components/Accordion/Accordion.vue +20 -0
  14. package/src/components/Accordion/AccordionContent.vue +14 -0
  15. package/src/components/Accordion/AccordionItem.vue +18 -0
  16. package/src/components/Accordion/AccordionTrigger.vue +35 -0
  17. package/src/components/Accordion/README.md +56 -0
  18. package/src/components/Accordion/index.ts +4 -0
  19. package/src/components/Alert/Alert.vue +55 -0
  20. package/src/components/Alert/AlertDescription.vue +8 -0
  21. package/src/components/Alert/AlertTitle.vue +11 -0
  22. package/src/components/Alert/DismissableAlertButton.vue +34 -0
  23. package/src/components/Alert/README.md +121 -0
  24. package/src/components/Alert/index.ts +3 -0
  25. package/src/components/AlertDialog/AlertDialog.vue +45 -0
  26. package/src/components/AlertDialog/AlertDialogActionButton.vue +9 -0
  27. package/src/components/AlertDialog/AlertDialogCancelButton.vue +15 -0
  28. package/src/components/AlertDialog/AlertDialogContent.vue +8 -0
  29. package/src/components/AlertDialog/AlertDialogDescription.vue +11 -0
  30. package/src/components/AlertDialog/AlertDialogFooter.vue +11 -0
  31. package/src/components/AlertDialog/AlertDialogHeader.vue +8 -0
  32. package/src/components/AlertDialog/AlertDialogTitle.vue +7 -0
  33. package/src/components/AlertDialog/README.md +85 -0
  34. package/src/components/AlertDialog/index.ts +8 -0
  35. package/src/components/Avatar/Avatar.vue +78 -0
  36. package/src/components/Avatar/README.md +122 -0
  37. package/src/components/Avatar/index.ts +1 -0
  38. package/src/components/Badge/Badge.vue +51 -0
  39. package/src/components/Badge/BadgeContent.vue +9 -0
  40. package/src/components/Badge/BadgeIcon.vue +7 -0
  41. package/src/components/Badge/README.md +131 -0
  42. package/src/components/Badge/index.ts +3 -0
  43. package/src/components/Button/Button.vue +63 -0
  44. package/src/components/Button/ButtonContent.vue +7 -0
  45. package/src/components/Button/ButtonIcon.vue +7 -0
  46. package/src/components/Button/README.md +228 -0
  47. package/src/components/Button/index.ts +3 -0
  48. package/src/components/ButtonGroup/ButtonGroup.vue +7 -0
  49. package/src/components/ButtonGroup/README.md +42 -0
  50. package/src/components/ButtonGroup/index.ts +1 -0
  51. package/src/components/Card/Card.vue +7 -0
  52. package/src/components/Card/CardDescription.vue +11 -0
  53. package/src/components/Card/CardFooter.vue +7 -0
  54. package/src/components/Card/CardHeader.vue +7 -0
  55. package/src/components/Card/CardSection.vue +7 -0
  56. package/src/components/Card/CardTitle.vue +8 -0
  57. package/src/components/Card/README.md +69 -0
  58. package/src/components/Card/index.ts +6 -0
  59. package/src/components/CategoryBar/CategoryBar.vue +25 -0
  60. package/src/components/CategoryBar/CategoryBarItem.vue +34 -0
  61. package/src/components/CategoryBar/README.md +17 -0
  62. package/src/components/CategoryBar/index.ts +2 -0
  63. package/src/components/Checkbox/Checkbox.vue +49 -0
  64. package/src/components/Checkbox/README.md +82 -0
  65. package/src/components/Checkbox/index.ts +1 -0
  66. package/src/components/Collapsible/README.md +25 -0
  67. package/src/components/DataTable/README.md +56 -0
  68. package/src/components/DatePicker/DatePicker.vue +140 -0
  69. package/src/components/DatePicker/DatePickerCard.vue +9 -0
  70. package/src/components/DatePicker/README.md +59 -0
  71. package/src/components/DatePicker/index.ts +2 -0
  72. package/src/components/DescriptionList/DescriptionList.vue +18 -0
  73. package/src/components/DescriptionList/DescriptionListDescription.vue +8 -0
  74. package/src/components/DescriptionList/DescriptionListItem.vue +21 -0
  75. package/src/components/DescriptionList/DescriptionListTerm.vue +11 -0
  76. package/src/components/DescriptionList/README.md +159 -0
  77. package/src/components/DescriptionList/index.ts +4 -0
  78. package/src/components/EmptyState/EmptyState.vue +13 -0
  79. package/src/components/EmptyState/EmptyStateActions.vue +11 -0
  80. package/src/components/EmptyState/EmptyStateContent.vue +7 -0
  81. package/src/components/EmptyState/EmptyStateDescription.vue +11 -0
  82. package/src/components/EmptyState/EmptyStateTitle.vue +7 -0
  83. package/src/components/EmptyState/README.md +102 -0
  84. package/src/components/EmptyState/index.ts +5 -0
  85. package/src/components/Feed/Feed.vue +7 -0
  86. package/src/components/Feed/FeedItem.vue +16 -0
  87. package/src/components/Feed/FeedItemBlock.vue +8 -0
  88. package/src/components/Feed/FeedItemDateIndicator.vue +11 -0
  89. package/src/components/Feed/FeedItemIcon.vue +26 -0
  90. package/src/components/Feed/FeedItemSimple.vue +8 -0
  91. package/src/components/Feed/README.md +115 -0
  92. package/src/components/Feed/index.ts +6 -0
  93. package/src/components/Form/Form.vue +30 -0
  94. package/src/components/Form/README.md +52 -0
  95. package/src/components/Form/index.ts +1 -0
  96. package/src/components/FormLayout/FormLayout.vue +7 -0
  97. package/src/components/FormLayout/README.md +59 -0
  98. package/src/components/FormLayout/index.ts +1 -0
  99. package/src/components/InputLabel/InputLabel.vue +32 -0
  100. package/src/components/InputLabel/index.ts +1 -0
  101. package/src/components/Link/Link.vue +38 -0
  102. package/src/components/Link/README.md +119 -0
  103. package/src/components/Link/index.ts +1 -0
  104. package/src/components/MetricCard/MetricCard.vue +11 -0
  105. package/src/components/MetricCard/MetricCardHeader.vue +7 -0
  106. package/src/components/MetricCard/MetricCardLabel.vue +9 -0
  107. package/src/components/MetricCard/MetricCardSection.vue +11 -0
  108. package/src/components/MetricCard/MetricCardValue.vue +8 -0
  109. package/src/components/MetricCard/README.md +53 -0
  110. package/src/components/MetricCard/index.ts +5 -0
  111. package/src/components/Navigation/Navigation.vue +8 -0
  112. package/src/components/Navigation/NavigationItem.vue +43 -0
  113. package/src/components/Navigation/NavigationSection.vue +27 -0
  114. package/src/components/Navigation/README.md +88 -0
  115. package/src/components/Navigation/index.ts +3 -0
  116. package/src/components/Page/Page.vue +38 -0
  117. package/src/components/Page/PageDescription.vue +11 -0
  118. package/src/components/Page/PageHeader.vue +34 -0
  119. package/src/components/Page/PageTitle.vue +9 -0
  120. package/src/components/Page/README.md +220 -0
  121. package/src/components/Page/index.ts +4 -0
  122. package/src/components/Pagination/Pagination.vue +8 -0
  123. package/src/components/Pagination/PaginationNextButton.vue +10 -0
  124. package/src/components/Pagination/PaginationPreviousButton.vue +10 -0
  125. package/src/components/Pagination/README.md +45 -0
  126. package/src/components/Pagination/index.ts +3 -0
  127. package/src/components/PinInput/PinInput.vue +169 -0
  128. package/src/components/PinInput/README.md +35 -0
  129. package/src/components/PinInput/index.ts +1 -0
  130. package/src/components/Popover/README.md +51 -0
  131. package/src/components/ProgressBar/ProgressBar.vue +33 -0
  132. package/src/components/ProgressBar/ProgressBarIndicator.vue +7 -0
  133. package/src/components/ProgressBar/README.md +98 -0
  134. package/src/components/ProgressBar/index.ts +2 -0
  135. package/src/components/RadioButton/README.md +111 -0
  136. package/src/components/RadioButton/RadioButton.vue +48 -0
  137. package/src/components/RadioButton/index.ts +1 -0
  138. package/src/components/Select/README.md +74 -0
  139. package/src/components/Select/Select.vue +91 -0
  140. package/src/components/Select/SelectGroup.vue +12 -0
  141. package/src/components/Select/SelectOption.vue +12 -0
  142. package/src/components/Select/index.ts +3 -0
  143. package/src/components/Separator/README.md +35 -0
  144. package/src/components/Separator/Separator.vue +7 -0
  145. package/src/components/Separator/index.ts +1 -0
  146. package/src/components/Spinner/README.md +53 -0
  147. package/src/components/Spinner/Spinner.vue +58 -0
  148. package/src/components/Spinner/index.ts +1 -0
  149. package/src/components/StatusIndicator/README.md +51 -0
  150. package/src/components/StatusIndicator/StatusIndicator.vue +38 -0
  151. package/src/components/StatusIndicator/index.ts +1 -0
  152. package/src/components/Tabs/README.md +53 -0
  153. package/src/components/Tabs/TabTrigger.vue +43 -0
  154. package/src/components/Tabs/Tabs.vue +13 -0
  155. package/src/components/Tabs/index.ts +2 -0
  156. package/src/components/Tag/README.md +27 -0
  157. package/src/components/TextField/README.md +317 -0
  158. package/src/components/TextField/TextField.vue +115 -0
  159. package/src/components/TextField/TextFieldPasswordIcon.vue +28 -0
  160. package/src/components/TextField/TextFieldSearchIcon.vue +11 -0
  161. package/src/components/TextField/index.ts +1 -0
  162. package/src/components/TextStyle/README.md +39 -0
  163. package/src/components/TextStyle/TextStyle.vue +24 -0
  164. package/src/components/TextStyle/index.ts +1 -0
  165. package/src/components/Toast/DismissToastAction.vue +34 -0
  166. package/src/components/Toast/README.md +167 -0
  167. package/src/components/Toast/Toast.vue +39 -0
  168. package/src/components/Toast/ToastGroup.vue +9 -0
  169. package/src/components/Toast/index.ts +2 -0
  170. package/src/components/Toggle/README.md +66 -0
  171. package/src/components/Toggle/Toggle.vue +86 -0
  172. package/src/components/Toggle/index.ts +1 -0
  173. package/src/components/Tooltip/README.md +51 -0
  174. package/src/components/Tooltip/Tooltip.vue +50 -0
  175. package/src/components/Tooltip/index.ts +1 -0
  176. package/src/components/TopBar/README.md +43 -0
  177. package/src/components/TopBar/TopBar.vue +7 -0
  178. package/src/components/TopBar/TopBarLogo.vue +8 -0
  179. package/src/components/TopBar/TopBarNavigation.vue +7 -0
  180. package/src/components/TopBar/TopBarNavigationItem.vue +13 -0
  181. package/src/components/TopBar/TopBarSearch.vue +15 -0
  182. package/src/components/TopBar/TopBarUserMenu.vue +20 -0
  183. package/src/components/TopBar/index.ts +6 -0
  184. package/src/components/VisuallyHidden/README.md +19 -0
  185. package/src/components/VisuallyHidden/VisuallyHidden.vue +25 -0
  186. package/src/components/VisuallyHidden/index.ts +1 -0
  187. package/src/components/index.ts +141 -0
  188. package/src/composables/index.ts +7 -0
  189. package/src/composables/useTailwindColor.ts +17 -0
  190. package/src/composables/useTheme.ts +29 -0
  191. package/src/composables/useToastNotifications.ts +55 -0
  192. package/src/composables/useUniqueId.ts +5 -0
  193. package/src/index.css +20 -0
  194. 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,3 @@
1
+ export { default as Badge } from './Badge.vue';
2
+ export { default as BadgeContent } from './BadgeContent.vue';
3
+ export { default as BadgeIcon } from './BadgeIcon.vue';
@@ -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,7 @@
1
+ <script lang="ts" setup></script>
2
+
3
+ <template>
4
+ <span>
5
+ <slot />
6
+ </span>
7
+ </template>
@@ -0,0 +1,7 @@
1
+ <script lang="ts" setup></script>
2
+
3
+ <template>
4
+ <div class="h-4 w-4 -mt-0.5 -mb-0.5">
5
+ <slot />
6
+ </div>
7
+ </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,3 @@
1
+ export { default as Button } from './Button.vue';
2
+ export { default as ButtonContent } from './ButtonContent.vue';
3
+ export { default as ButtonIcon } from './ButtonIcon.vue';
@@ -0,0 +1,7 @@
1
+ <script lang="ts" setup></script>
2
+
3
+ <template>
4
+ <div class="space-x-2">
5
+ <slot />
6
+ </div>
7
+ </template>
@@ -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,7 @@
1
+ <script lang="ts" setup></script>
2
+
3
+ <template>
4
+ <div class="border bg-white rounded-lg overflow-auto shadow-sm">
5
+ <slot />
6
+ </div>
7
+ </template>
@@ -0,0 +1,11 @@
1
+ <script lang="ts" setup>
2
+ import { TextStyle } from '../TextStyle';
3
+ </script>
4
+
5
+ <template>
6
+ <p>
7
+ <TextStyle variant="subdued">
8
+ <slot />
9
+ </TextStyle>
10
+ </p>
11
+ </template>
@@ -0,0 +1,7 @@
1
+ <script lang="ts" setup></script>
2
+
3
+ <template>
4
+ <div class="flex items-center justify-end bg-slate-100 px-4 py-3">
5
+ <slot />
6
+ </div>
7
+ </template>
@@ -0,0 +1,7 @@
1
+ <script lang="ts" setup></script>
2
+
3
+ <template>
4
+ <div class="flex flex-col space-y-1.5 p-6 pb-0">
5
+ <slot />
6
+ </div>
7
+ </template>
@@ -0,0 +1,7 @@
1
+ <script lang="ts" setup></script>
2
+
3
+ <template>
4
+ <div class="p-6">
5
+ <slot />
6
+ </div>
7
+ </template>
@@ -0,0 +1,8 @@
1
+ <script lang="ts" setup>
2
+ </script>
3
+
4
+ <template>
5
+ <div class="text-xl font-semibold leading-none">
6
+ <slot />
7
+ </div>
8
+ </template>
@@ -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>