@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,121 @@
1
+ <script lang="ts" setup>
2
+ import { Alert, AlertTitle, AlertDescription } from '../../src/components';
3
+ import api from '../component-meta/Alert.json';
4
+ </script>
5
+
6
+ # Alert
7
+
8
+ Informs users about important changes or persistent conditions. Use this component if you need to communicate to
9
+ users in a prominent way. Alerts are placed at the top of the page or section they apply to, and below the page or
10
+ section header.
11
+
12
+ <ComponentApi :api="api" />
13
+
14
+ ## Variants
15
+
16
+ ### Default
17
+
18
+ Use to convey general information or actions that aren't critical. For example, you might show an alert that asks
19
+ for users feedback. Default alerts contain lower priority information and should always be dismissable.
20
+
21
+ <ComponentWrapper>
22
+ <Alert>
23
+ <AlertTitle>Heads up!</AlertTitle>
24
+ <AlertDescription>
25
+ You can add components to your app using the cli.
26
+ </AlertDescription>
27
+ </Alert>
28
+ </ComponentWrapper>
29
+
30
+ ```js-vue
31
+ <script lang="ts" setup>
32
+ import { Alert, AlertDescription, AlertTitle } from 'focus-ui';
33
+ </script>
34
+
35
+ <template>
36
+ <Alert>
37
+ <AlertTitle>Heads up!</AlertTitle>
38
+ <AlertDescription>
39
+ You can add components to your app using the cli.
40
+ </AlertDescription>
41
+ </Alert>
42
+ </template>
43
+ ```
44
+
45
+ ### Destructive
46
+
47
+ Use to communicate critical information or actions that require immediate attention. For example, you might show an
48
+ alert that warns users about a critical system failure. Destructive alerts contain higher priority information.
49
+
50
+ <ComponentWrapper>
51
+ <Alert variant="destructive">
52
+ <AlertTitle>Error</AlertTitle>
53
+ <AlertDescription>
54
+ Your session has expired. Please log in again.
55
+ </AlertDescription>
56
+ </Alert>
57
+ </ComponentWrapper>
58
+
59
+ ```js-vue
60
+ <script lang="ts" setup>
61
+ import { Alert, AlertDescription, AlertTitle } from 'focus-ui';
62
+ </script>
63
+
64
+ <template>
65
+ <Alert variant="destructive">
66
+ <AlertTitle>Error</AlertTitle>
67
+ <AlertDescription>
68
+ Your session has expired. Please log in again.
69
+ </AlertDescription>
70
+ </Alert>
71
+ </template>
72
+ ```
73
+
74
+ ## Best practices
75
+
76
+ Alerts should:
77
+
78
+ - Be used thoughtfully and sparingly for only the most important information.
79
+ - Not be used to call attention to what a user needs to do in the UI instead of making the action clear in the UI
80
+ itself.
81
+ - Not be the primary entry point of information or actions users need on a regular basis.
82
+ - Be dismissible unless they contain critical information or an important step users need to take.
83
+
84
+ ### Placement
85
+
86
+ Alerts should be placed in the appropriate context:
87
+
88
+ - Alerts relevant to an entire page should be placed at the top of that page, below the page header. They should
89
+ occupy the full width of the content area.
90
+ - Alerts related to a section of a page (like a card, popover, or modal) should be placed inside that section, below
91
+ any section heading.
92
+ - Alerts related to an element more specific that a section should be placed immediately above or below that element.
93
+
94
+ ## Content guidelines
95
+
96
+ Alerts should:
97
+
98
+ - Focus on a single theme, piece of information, or required action to avoid overwhelming users.
99
+ - Be concise and scannable - users shouldn't need to spend a lot of time figuring out what the alert is trying to
100
+ communicate.
101
+ - Be limited to a few important calls to action with no more than one primary action.
102
+
103
+ ### Body content
104
+
105
+ Body content should:
106
+
107
+ - Be concise: keep the content to 1 or 2 sentences where possible.
108
+ - Clarify the benefit of the main task.
109
+ - Be written in sentence case and use appropriate punctuation.
110
+ - Avoid repeating the heading.
111
+ - Explain how to resolve the issue, particularly for destructive alerts.
112
+
113
+ ## Accessibility
114
+
115
+ Alerts provide context and assist workflows for users with disabilities.
116
+
117
+ - Destructive alerts have a `role="alert"` attribute and are announced by assistive technologies when they appear.
118
+ - All other alerts have a `role="status"` attribute and are read after any critical announcements.
119
+ - Alert containers have a `tabindex="0"` attribute and display a visible keyboard focus indicator. Because of this,
120
+ merchants can discover banners while tabbing through forms or other interactions, and developers can programmatically
121
+ move focus to banners.
@@ -0,0 +1,3 @@
1
+ export { default as Alert } from './Alert.vue';
2
+ export { default as AlertDescription } from './AlertDescription.vue';
3
+ export { default as AlertTitle } from './AlertTitle.vue';
@@ -0,0 +1,45 @@
1
+ <script lang="ts" setup>
2
+ import { onMounted, onUnmounted, provide } from 'vue';
3
+
4
+ withDefaults(defineProps<{
5
+ /** Whether the alert dialog is open. */
6
+ open?: boolean;
7
+ }>(), {
8
+ open: false,
9
+ });
10
+
11
+ const emits = defineEmits<{
12
+ cancel: [];
13
+ }>();
14
+
15
+ function cancelAlertDialog(): void {
16
+ emits('cancel');
17
+ }
18
+
19
+ function onKeyDown(e: KeyboardEvent): void {
20
+ if (e.key === 'Escape') {
21
+ cancelAlertDialog();
22
+ }
23
+ }
24
+
25
+ onMounted((): void => {
26
+ document.addEventListener('keydown', onKeyDown);
27
+ });
28
+
29
+ onUnmounted((): void => {
30
+ document.removeEventListener('keydown', onKeyDown);
31
+ });
32
+
33
+ provide('cancelAlertDialog', cancelAlertDialog);
34
+ </script>
35
+
36
+ <template>
37
+ <div
38
+ v-if="open"
39
+ class="fixed top-0 left-0 z-10 h-screen w-screen bg-slate-500/50 text-sm"
40
+ >
41
+ <div class="flex min-h-full items-center justify-center">
42
+ <slot />
43
+ </div>
44
+ </div>
45
+ </template>
@@ -0,0 +1,9 @@
1
+ <script lang="ts" setup>
2
+ import { Button } from '../Button';
3
+ </script>
4
+
5
+ <template>
6
+ <Button variant="primary">
7
+ <slot />
8
+ </Button>
9
+ </template>
@@ -0,0 +1,15 @@
1
+ <script lang="ts" setup>
2
+ import { Button } from '../Button';
3
+ import { inject } from 'vue';
4
+
5
+ const cancelAlertDialog = inject('cancelAlertDialog');
6
+ </script>
7
+
8
+ <template>
9
+ <Button
10
+ variant="secondary"
11
+ @click="cancelAlertDialog"
12
+ >
13
+ <slot />
14
+ </Button>
15
+ </template>
@@ -0,0 +1,8 @@
1
+ <script lang="ts" setup>
2
+ </script>
3
+
4
+ <template>
5
+ <div class="bg-white rounded-lg shadow-2xl max-w-lg overflow-hidden">
6
+ <slot />
7
+ </div>
8
+ </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,11 @@
1
+ <script lang="ts" setup>
2
+ import { ButtonGroup } from '../ButtonGroup';
3
+ </script>
4
+
5
+ <template>
6
+ <div class="bg-slate-100 px-4 py-3 flex items-center justify-end">
7
+ <ButtonGroup>
8
+ <slot />
9
+ </ButtonGroup>
10
+ </div>
11
+ </template>
@@ -0,0 +1,8 @@
1
+ <script lang="ts" setup>
2
+ </script>
3
+
4
+ <template>
5
+ <div class="flex flex-col space-y-4 p-6">
6
+ <slot />
7
+ </div>
8
+ </template>
@@ -0,0 +1,7 @@
1
+ <script lang="ts" setup></script>
2
+
3
+ <template>
4
+ <h2 class="text-xl font-semibold leading-none">
5
+ <slot />
6
+ </h2>
7
+ </template>
@@ -0,0 +1,85 @@
1
+ <script lang="ts" setup>
2
+ import { ref } from "vue";
3
+ import {
4
+ AlertDialog,
5
+ AlertDialogActionButton,
6
+ AlertDialogCancelButton,
7
+ AlertDialogContent,
8
+ AlertDialogDescription,
9
+ AlertDialogFooter,
10
+ AlertDialogHeader,
11
+ AlertDialogTitle,
12
+ Button,
13
+ } from '../../src/components';
14
+ import api from '../component-meta/AlertDialog.json';
15
+
16
+ const alertDialogOpen = ref(false);
17
+ </script>
18
+
19
+ # Alert Dialog
20
+
21
+ A modal dialog that interrupts the user with important content and expects a response.
22
+
23
+ <ComponentApi :api="api" />
24
+
25
+ ## Usage
26
+
27
+ <ComponentWrapper>
28
+ <Button @click="alertDialogOpen = true">
29
+ Open Dialog
30
+ </Button>
31
+
32
+ <AlertDialog :open="alertDialogOpen" @cancel="alertDialogOpen = false">
33
+ <AlertDialogContent>
34
+ <AlertDialogHeader>
35
+ <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
36
+ <AlertDialogDescription>
37
+ This action cannot be undone. This will permanently delete your account and remove your data from our servers.
38
+ </AlertDialogDescription>
39
+ </AlertDialogHeader>
40
+ <AlertDialogFooter>
41
+ <AlertDialogCancelButton>Cancel</AlertDialogCancelButton>
42
+ <AlertDialogActionButton>Continue</AlertDialogActionButton>
43
+ </AlertDialogFooter>
44
+ </AlertDialogContent>
45
+ </AlertDialog>
46
+ </ComponentWrapper>
47
+
48
+ ```js-vue
49
+ <script lang="ts" setup>
50
+ import {
51
+ AlertDialog,
52
+ AlertDialogActionButton,
53
+ AlertDialogCancelButton,
54
+ AlertDialogContent,
55
+ AlertDialogDescription,
56
+ AlertDialogFooter,
57
+ AlertDialogHeader,
58
+ AlertDialogTitle,
59
+ Button,
60
+ } from 'focus-ui';
61
+
62
+ const alertDialogOpen = ref(false);
63
+ </script>
64
+
65
+ <template>
66
+ <Button v-on:click="alertDialogOpen = true">
67
+ Open Dialog
68
+ </Button>
69
+
70
+ <AlertDialog :open="alertDialogOpen" v-on:cancel="alertDialogOpen = false">
71
+ <AlertDialogContent>
72
+ <AlertDialogHeader>
73
+ <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
74
+ <AlertDialogDescription>
75
+ This action cannot be undone. This will permanently delete your account and remove your data from our servers.
76
+ </AlertDialogDescription>
77
+ </AlertDialogHeader>
78
+ <AlertDialogFooter>
79
+ <AlertDialogCancelButton>Cancel</AlertDialogCancelButton>
80
+ <AlertDialogActionButton>Continue</AlertDialogActionButton>
81
+ </AlertDialogFooter>
82
+ </AlertDialogContent>
83
+ </AlertDialog>
84
+ </template>
85
+ ```
@@ -0,0 +1,8 @@
1
+ export { default as AlertDialog } from './AlertDialog.vue';
2
+ export { default as AlertDialogActionButton } from './AlertDialogActionButton.vue';
3
+ export { default as AlertDialogCancelButton } from './AlertDialogCancelButton.vue';
4
+ export { default as AlertDialogContent } from './AlertDialogContent.vue';
5
+ export { default as AlertDialogDescription } from './AlertDialogDescription.vue';
6
+ export { default as AlertDialogFooter } from './AlertDialogFooter.vue';
7
+ export { default as AlertDialogHeader } from './AlertDialogHeader.vue';
8
+ export { default as AlertDialogTitle } from './AlertDialogTitle.vue';
@@ -0,0 +1,78 @@
1
+ <script lang="ts" setup>
2
+ import { UserIcon } from '@heroicons/vue/16/solid';
3
+ import { computed } from 'vue';
4
+
5
+ const props = withDefaults(defineProps<{
6
+ /** The size of the avatar */
7
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
8
+
9
+ /** The name of the person, company or entity */
10
+ name?: string | null;
11
+
12
+ /** Initials of person to display. */
13
+ initials?: string | null;
14
+
15
+ /** URL of the avatar image which falls back to initials if the image fails to load. */
16
+ source?: string | null;
17
+
18
+ /** Accessible label for the avatar image. */
19
+ accessibilityLabel?: string | null;
20
+ }>(), {
21
+ size: 'md',
22
+ name: null,
23
+ initials: null,
24
+ source: null,
25
+ accessibilityLabel: null,
26
+ });
27
+
28
+ const classList = computed(() => {
29
+ return [
30
+ { 'w-4 h-4': props.size === 'xs' },
31
+ { 'w-6 h-6': props.size === 'sm' },
32
+ { 'w-8 h-8': props.size === 'md' },
33
+ { 'w-10 h-10': props.size === 'lg' },
34
+ { 'w-12 h-12': props.size === 'xl' },
35
+ ];
36
+ });
37
+
38
+ const iconSize = computed(() => {
39
+ return [
40
+ { 'w-3 h-3': props.size === 'xs' },
41
+ ];
42
+ });
43
+
44
+ const textSize = computed(() => {
45
+ return [
46
+ { 'text-xs': props.size === 'xs' },
47
+ { 'text-xs': props.size === 'sm' },
48
+ { 'text-md': props.size === 'md' },
49
+ { 'text-lg': props.size === 'lg' },
50
+ { 'text-lg': props.size === 'xl' },
51
+ ];
52
+ });
53
+
54
+ function renderInitials(initials: string): string {
55
+ return props.size === 'xs'
56
+ ? initials?.slice(0, 1)
57
+ : initials;
58
+ }
59
+ </script>
60
+
61
+ <template>
62
+ <div
63
+ class="relative flex items-center justify-center rounded bg-slate-200"
64
+ :class="classList"
65
+ >
66
+ <UserIcon
67
+ v-if="!initials"
68
+ role="img"
69
+ :class="iconSize"
70
+ />
71
+ <span
72
+ class="font-semibold"
73
+ :class="textSize"
74
+ >
75
+ {{ renderInitials(initials) }}
76
+ </span>
77
+ </div>
78
+ </template>
@@ -0,0 +1,122 @@
1
+ <script lang="ts" setup>
2
+ import { Avatar } from '../../src/components';
3
+ import api from '../component-meta/Avatar.json';
4
+ </script>
5
+
6
+ # Avatar
7
+
8
+ Avatars are used to show a thumbnail representation of an individual or business in the interface.
9
+
10
+ <ComponentApi :api="api" />
11
+
12
+ ## Usage
13
+
14
+ <ComponentWrapper>
15
+ <Avatar name="John Doe" />
16
+ </ComponentWrapper>
17
+
18
+ ```js-vue
19
+ <script lang="ts" setup>
20
+ import { Avatar } from 'focus-ui';
21
+ </script>
22
+
23
+ <template>
24
+ <Avatar name="John Doe" />
25
+ </template>
26
+ ```
27
+
28
+ ## Variants
29
+
30
+ ### With initials
31
+
32
+ <ComponentWrapper>
33
+ <Avatar name="John Doe" initials="JD" />
34
+ </ComponentWrapper>
35
+
36
+ ```js-vue
37
+ <script lang="ts" setup>
38
+ import { Avatar } from 'focus-ui';
39
+ </script>
40
+
41
+ <template>
42
+ <Avatar name="John Doe" initials="JD" />
43
+ </template>
44
+ ```
45
+
46
+ ### Sizes
47
+
48
+ <ComponentWrapper>
49
+ <ComponentGrid>
50
+ <ComponentGrid>
51
+ <Avatar name="John Doe" size="xs" />
52
+ <Avatar name="John Doe" size="sm" />
53
+ <Avatar name="John Doe" size="md" />
54
+ <Avatar name="John Doe" size="lg" />
55
+ <Avatar name="John Doe" size="xl" />
56
+ </ComponentGrid>
57
+ <ComponentGrid>
58
+ <Avatar name="John Doe" size="xs" initials="JD" />
59
+ <Avatar name="John Doe" size="sm" initials="JD" />
60
+ <Avatar name="John Doe" size="md" initials="JD" />
61
+ <Avatar name="John Doe" size="lg" initials="JD" />
62
+ <Avatar name="John Doe" size="xl" initials="JD" />
63
+ </ComponentGrid>
64
+ </ComponentGrid>
65
+ </ComponentWrapper>
66
+
67
+ ```js-vue
68
+ <script lang="ts" setup>
69
+ import { Avatar } from 'focus-ui';
70
+ </script>
71
+
72
+ <template>
73
+ <Avatar name="John Doe" size="xs" />
74
+ <Avatar name="John Doe" size="sm" />
75
+ <Avatar name="John Doe" size="md" />
76
+ <Avatar name="John Doe" size="lg" />
77
+ <Avatar name="John Doe" size="xl" />
78
+
79
+ // Or with initials...
80
+ <Avatar name="John Doe" size="xs" initials="JD" />
81
+ <Avatar name="John Doe" size="sm" initials="JD" />
82
+ <Avatar name="John Doe" size="md" initials="JD" />
83
+ <Avatar name="John Doe" size="lg" initials="JD" />
84
+ <Avatar name="John Doe" size="xl" initials="JD" />
85
+ </template>
86
+ ```
87
+
88
+ ## Best practices
89
+
90
+ Avatars should be one of 5 sizes:
91
+
92
+ - Extra-small (20 x 20 px): use in tightly condensed layouts
93
+ - Small (24 × 24 px): use when the medium size is too big for the layout, or when the avatar has less importance
94
+ - Medium (28 × 28 px): use as the default size
95
+ - Large (32 × 32 px): use when an avatar is a focal point, such as on a single customer card
96
+ - Extra large (40 × 40 px): use when an avatar is a focal point, such as on a single customer card
97
+
98
+ ## Content guidelines
99
+
100
+ Any time you use an image to communicate a concept in the interface, it's important to use descriptive alt text.
101
+ Doing this is important for accessibility because it allows screen readers to describe what's in the image to people
102
+ who may not be able to see it.
103
+
104
+ For avatars, we recommend using a format that describes what will show in the image:
105
+
106
+ - `alt=Person's name"` if the avatar represents a person
107
+ - `alt=Company name"` if the avatar represents a business
108
+ - `alt=""` if the name of the person/business appears next to the avatar as text
109
+
110
+ ## Accessibility
111
+
112
+ ### Structure
113
+
114
+ The avatar component uses a generated scalable vector graphics (SVG) file, which can cause challenges for users that
115
+ use assistive technologies. To create a standard experience, the `<img>` is hidden from assistive technologies by
116
+ using an empty `alt` attribute, and replaced with a `<span>` that has `role="img"`.
117
+
118
+ ### Labeling
119
+
120
+ The avatar component represents content, and should have a text equivalent for users using assistive technologies.
121
+ By default, the value of the `name` prop is used for the alternative text. If different text would be more accurate,
122
+ use the `accessibilityLabel` prop to replace the value provided by `name`.
@@ -0,0 +1 @@
1
+ export { default as Avatar } from './Avatar.vue';
@@ -0,0 +1,51 @@
1
+ <script lang="ts" setup>
2
+ import { computed, CSSProperties } from 'vue';
3
+ import { VisuallyHidden } from '../VisuallyHidden';
4
+ import { TextStyle } from '../TextStyle';
5
+ import { TailwindColor, useTailwindColor } from '../../composables';
6
+
7
+ const props = withDefaults(defineProps<{
8
+ /** Accessible label for the avatar image. */
9
+ accessibilityLabel?: string | null;
10
+
11
+ /** The color of the badge. */
12
+ color: TailwindColor;
13
+
14
+ /** The size of the badge */
15
+ size?: 'sm' | 'md' | 'lg' | 'xl';
16
+ }>(), {
17
+ accessibilityLabel: null,
18
+ size: 'sm',
19
+ });
20
+
21
+ const colorValues = computed((): CSSProperties => {
22
+ return {
23
+ backgroundColor: useTailwindColor(props.color, '200'),
24
+ color: useTailwindColor(props.color, '900'),
25
+ };
26
+ });
27
+
28
+ const classList = computed(() => {
29
+ return [
30
+ { 'text-xs px-2 py-1': props.size === 'sm' },
31
+ { 'text-sm px-3 py-1.5': props.size === 'md' },
32
+ { 'text-md px-4 py-2': props.size === 'lg' },
33
+ ];
34
+ });
35
+ </script>
36
+
37
+ <template>
38
+ <span
39
+ class="inline-flex rounded bg-slate-200"
40
+ :class="classList"
41
+ :style="colorValues"
42
+ >
43
+ <TextStyle variant="strong">
44
+ <div class="flex items-center space-x-2">
45
+ <slot />
46
+ </div>
47
+ </TextStyle>
48
+
49
+ <VisuallyHidden v-if="accessibilityLabel">{{ accessibilityLabel }}</VisuallyHidden>
50
+ </span>
51
+ </template>
@@ -0,0 +1,9 @@
1
+ <script lang="ts" setup>
2
+ import { TextStyle } from '../TextStyle';
3
+ </script>
4
+
5
+ <template>
6
+ <TextStyle variant="strong">
7
+ <slot />
8
+ </TextStyle>
9
+ </template>
@@ -0,0 +1,7 @@
1
+ <script lang="ts" setup></script>
2
+
3
+ <template>
4
+ <div class="w-4 h-4">
5
+ <slot />
6
+ </div>
7
+ </template>