@returnless/focus-ui 0.0.2 → 0.0.3

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 (186) hide show
  1. package/dist/focus-ui.js +10851 -0
  2. package/dist/focus-ui.umd.cjs +26 -0
  3. package/dist/style.css +1 -0
  4. package/package.json +11 -7
  5. package/src/build-utils/generate-component-meta.ts +5 -1
  6. package/src/build-utils/update-component-list.ts +1 -1
  7. package/src/components/Accordion/AccordionContent.vue +34 -5
  8. package/src/components/Accordion/AccordionItem.vue +5 -2
  9. package/src/components/Accordion/AccordionTrigger.vue +5 -2
  10. package/src/components/Accordion/README.md +1 -1
  11. package/src/components/ActionList/ActionList.vue +9 -0
  12. package/src/components/ActionList/ActionListBody.vue +11 -0
  13. package/src/components/ActionList/ActionListItem.vue +37 -0
  14. package/src/components/ActionList/ActionListSection.vue +7 -0
  15. package/src/components/ActionList/ActionListTrigger.vue +9 -0
  16. package/src/components/ActionList/README.md +113 -0
  17. package/src/components/ActionList/index.ts +5 -0
  18. package/src/components/Alert/Alert.vue +23 -10
  19. package/src/components/Alert/AlertDescription.vue +13 -1
  20. package/src/components/Alert/AlertTitle.vue +1 -1
  21. package/src/components/Alert/DismissableAlertButton.vue +6 -4
  22. package/src/components/Alert/README.md +31 -2
  23. package/src/components/Alert/index.ts +2 -0
  24. package/src/components/Alert/types.ts +1 -0
  25. package/src/components/AlertDialog/AlertDialog.vue +10 -1
  26. package/src/components/AlertDialog/AlertDialogActionButton.vue +9 -2
  27. package/src/components/AlertDialog/AlertDialogCancelButton.vue +1 -1
  28. package/src/components/AlertDialog/AlertDialogDescription.vue +7 -1
  29. package/src/components/AlertDialog/AlertDialogTitle.vue +11 -3
  30. package/src/components/AlertDialog/README.md +15 -16
  31. package/src/components/AspectRatio/AspectRatio.vue +19 -0
  32. package/src/components/AspectRatio/README.md +36 -0
  33. package/src/components/AspectRatio/index.ts +1 -0
  34. package/src/components/Avatar/Avatar.vue +57 -13
  35. package/src/components/Avatar/README.md +3 -9
  36. package/src/components/Badge/Badge.vue +1 -1
  37. package/src/components/Badge/README.md +9 -9
  38. package/src/components/BarChart/BarChart.vue +80 -0
  39. package/src/components/{MetricCard/MetricCardHeader.vue → BarChart/BarChartContainer.vue} +1 -1
  40. package/src/components/BarChart/BarChartStacked.vue +93 -0
  41. package/src/components/BarChart/README.md +83 -0
  42. package/src/components/BarChart/index.ts +3 -0
  43. package/src/components/Breadcrumbs/Breadcrumb.vue +7 -0
  44. package/src/components/Breadcrumbs/BreadcrumbEllipsis.vue +12 -0
  45. package/src/components/{MetricCard/MetricCardValue.vue → Breadcrumbs/BreadcrumbItem.vue} +2 -2
  46. package/src/components/Breadcrumbs/BreadcrumbLink.vue +13 -0
  47. package/src/components/Breadcrumbs/BreadcrumbList.vue +8 -0
  48. package/src/components/Breadcrumbs/BreadcrumbPage.vue +13 -0
  49. package/src/components/Breadcrumbs/BreadcrumbSeparator.vue +12 -0
  50. package/src/components/Breadcrumbs/README.md +91 -0
  51. package/src/components/Breadcrumbs/index.ts +7 -0
  52. package/src/components/Button/Button.vue +53 -41
  53. package/src/components/Button/ButtonContent.vue +1 -1
  54. package/src/components/Button/ButtonIcon.vue +28 -3
  55. package/src/components/Button/README.md +32 -29
  56. package/src/components/Button/index.ts +2 -0
  57. package/src/components/Button/types.ts +30 -0
  58. package/src/components/ButtonGroup/README.md +1 -1
  59. package/src/components/Card/CardHelp.vue +23 -0
  60. package/src/components/Card/CardSection.vue +17 -2
  61. package/src/components/Card/CardTitle.vue +6 -3
  62. package/src/components/Card/README.md +97 -10
  63. package/src/components/Card/index.ts +2 -1
  64. package/src/components/Checkbox/Checkbox.vue +29 -5
  65. package/src/components/Checkbox/README.md +34 -5
  66. package/src/components/DatePicker/DatePicker.vue +7 -27
  67. package/src/components/DatePicker/README.md +1 -1
  68. package/src/components/DescriptionList/DescriptionList.vue +1 -1
  69. package/src/components/DescriptionList/DescriptionListItem.vue +1 -1
  70. package/src/components/DescriptionList/README.md +2 -2
  71. package/src/components/Dialog/README.md +2 -0
  72. package/src/components/Dialog/index.ts +0 -0
  73. package/src/components/DropZone/DropZone.vue +105 -0
  74. package/src/components/DropZone/README.md +48 -0
  75. package/src/components/DropZone/index.ts +1 -0
  76. package/src/components/EmptyState/README.md +1 -1
  77. package/src/components/Feed/FeedItem.vue +4 -1
  78. package/src/components/Feed/FeedItemBlock.vue +4 -1
  79. package/src/components/Feed/README.md +1 -1
  80. package/src/components/FileUploadButton/FileUploadButton.vue +62 -0
  81. package/src/components/FileUploadButton/index.ts +1 -0
  82. package/src/components/Form/Form.vue +7 -2
  83. package/src/components/Form/README.md +1 -1
  84. package/src/components/FormLayout/FormLayout.vue +20 -2
  85. package/src/components/FormLayout/README.md +39 -1
  86. package/src/components/Heading/Heading.vue +32 -0
  87. package/src/components/Heading/index.ts +3 -0
  88. package/src/components/Heading/types.ts +3 -0
  89. package/src/components/Image/Image.vue +30 -0
  90. package/src/components/Image/index.ts +1 -0
  91. package/src/components/InertiaLink/InertiaLink.vue +11 -0
  92. package/src/components/InertiaLink/index.ts +1 -0
  93. package/src/components/InlineError/InlineError.vue +21 -0
  94. package/src/components/InlineError/README.md +63 -0
  95. package/src/components/InlineError/index.ts +1 -0
  96. package/src/components/KPICard/KPICard.vue +28 -0
  97. package/src/components/KPICard/KPICardSection.vue +30 -0
  98. package/src/components/KPICard/README.md +124 -0
  99. package/src/components/KPICard/index.ts +2 -0
  100. package/src/components/Legend/Legend.vue +7 -0
  101. package/src/components/Legend/LegendItem.vue +34 -0
  102. package/src/components/Legend/README.md +32 -0
  103. package/src/components/Legend/index.ts +2 -0
  104. package/src/components/Link/Link.vue +4 -4
  105. package/src/components/Link/README.md +1 -1
  106. package/src/components/Navigation/Navigation.vue +2 -2
  107. package/src/components/Navigation/NavigationItem.vue +14 -10
  108. package/src/components/Navigation/NavigationSecondarySection.vue +12 -0
  109. package/src/components/Navigation/NavigationSection.vue +1 -1
  110. package/src/components/Navigation/README.md +10 -15
  111. package/src/components/Navigation/index.ts +1 -0
  112. package/src/components/Page/Page.vue +2 -33
  113. package/src/components/Page/PageBody.vue +36 -0
  114. package/src/components/Page/PageTitle.vue +6 -3
  115. package/src/components/Page/README.md +45 -39
  116. package/src/components/Page/index.ts +1 -0
  117. package/src/components/Pagination/README.md +1 -1
  118. package/src/components/PinInput/README.md +1 -1
  119. package/src/components/Popover/Popover.vue +18 -0
  120. package/src/components/Popover/PopoverBody.vue +11 -0
  121. package/src/components/Popover/PopoverTrigger.vue +9 -0
  122. package/src/components/Popover/README.md +34 -6
  123. package/src/components/Popover/index.ts +3 -0
  124. package/src/components/Popper/Popper.vue +91 -0
  125. package/src/components/Popper/PopperBody.vue +19 -0
  126. package/src/components/Popper/PopperTrigger.vue +14 -0
  127. package/src/components/Popper/README.md +42 -0
  128. package/src/components/Popper/index.ts +3 -0
  129. package/src/components/ProgressBar/ProgressBar.vue +24 -6
  130. package/src/components/RadioButton/README.md +1 -1
  131. package/src/components/RadioButton/RadioButton.vue +3 -2
  132. package/src/components/ResourceList/README.md +160 -0
  133. package/src/components/ResourceList/ResourceList.vue +7 -0
  134. package/src/components/ResourceList/ResourceListItem.vue +7 -0
  135. package/src/components/ResourceList/ResourceListItemContent.vue +7 -0
  136. package/src/components/ResourceList/index.ts +3 -0
  137. package/src/components/Select/README.md +1 -1
  138. package/src/components/Select/Select.vue +1 -1
  139. package/src/components/Separator/README.md +5 -1
  140. package/src/components/Separator/Separator.vue +20 -3
  141. package/src/components/Spinner/README.md +1 -1
  142. package/src/components/Spinner/Spinner.vue +10 -4
  143. package/src/components/StatusIndicator/README.md +2 -2
  144. package/src/components/StatusIndicator/StatusIndicator.vue +11 -5
  145. package/src/components/Stepper/README.md +38 -0
  146. package/src/components/Stepper/Stepper.vue +104 -0
  147. package/src/components/Stepper/index.ts +1 -0
  148. package/src/components/Tabs/README.md +1 -1
  149. package/src/components/Tabs/TabTrigger.vue +5 -4
  150. package/src/components/Tabs/Tabs.vue +4 -1
  151. package/src/components/Tag/Tag.vue +45 -0
  152. package/src/components/Tag/index.ts +1 -0
  153. package/src/components/TextField/README.md +24 -6
  154. package/src/components/TextField/TextField.vue +25 -5
  155. package/src/components/TextField/TextFieldIcon.vue +19 -0
  156. package/src/components/TextStyle/README.md +1 -1
  157. package/src/components/TextStyle/TextStyle.vue +1 -1
  158. package/src/components/Toast/DismissToastAction.vue +1 -1
  159. package/src/components/Toast/README.md +1 -1
  160. package/src/components/Toggle/README.md +1 -1
  161. package/src/components/Toggle/Toggle.vue +8 -5
  162. package/src/components/Tooltip/README.md +1 -1
  163. package/src/components/Tooltip/Tooltip.vue +15 -41
  164. package/src/components/TopBar/TopBarSearch.vue +2 -2
  165. package/src/components/index.ts +68 -12
  166. package/src/components/types.ts +5 -0
  167. package/src/composables/useTheme.ts +13 -1
  168. package/src/composables/useToastNotifications.ts +1 -1
  169. package/src/composables/useUniqueId.ts +4 -3
  170. package/src/index.css +17 -13
  171. package/src/index.ts +0 -11
  172. package/dist/focus-ui.es.js +0 -33
  173. package/dist/types/components/Accordion/Accordion.vue.d.ts +0 -32
  174. package/dist/types/components/Accordion/AccordionItem.vue.d.ts +0 -2
  175. package/dist/types/components/Accordion/index.d.ts +0 -2
  176. package/dist/types/components/index.d.ts +0 -1
  177. package/dist/types/index.d.ts +0 -7
  178. package/src/components/CategoryBar/CategoryBar.vue +0 -25
  179. package/src/components/CategoryBar/CategoryBarItem.vue +0 -34
  180. package/src/components/CategoryBar/README.md +0 -17
  181. package/src/components/CategoryBar/index.ts +0 -2
  182. package/src/components/MetricCard/MetricCard.vue +0 -11
  183. package/src/components/MetricCard/MetricCardLabel.vue +0 -9
  184. package/src/components/MetricCard/MetricCardSection.vue +0 -11
  185. package/src/components/MetricCard/README.md +0 -53
  186. package/src/components/MetricCard/index.ts +0 -5
@@ -0,0 +1,160 @@
1
+ <script lang="ts" setup>
2
+ import {
3
+ Avatar,
4
+ Button,
5
+ Card,
6
+ CardSection,
7
+ CardHelp,
8
+ CardHeader,
9
+ CardTitle,
10
+ CardFooter,
11
+ CardDescription,
12
+ ResourceList,
13
+ ResourceListItem,
14
+ ResourceListItemContent,
15
+ TextStyle,
16
+ StatusIndicator,
17
+ } from '../../src/components';
18
+ import api from '../component-meta/ResourceList.json';
19
+ </script>
20
+
21
+ # Resource List
22
+
23
+ A resource list displays a collection of objects of the same type, like products or customers. The main job of a
24
+ resource list is to help users find an object and navigate to a full-page representation of it or open a modal to
25
+ view more details.
26
+
27
+ <ComponentApi :api="api" />
28
+
29
+ ## Examples
30
+
31
+ ### List of available orders
32
+
33
+ <ComponentWrapper>
34
+ <div style="width: 400px;">
35
+ <Card>
36
+ <CardHeader>
37
+ <CardTitle>
38
+ Orders
39
+ <CardHelp href="/help">Learn more</CardHelp>
40
+ </CardTitle>
41
+ </CardHeader>
42
+ <CardSection flush>
43
+ <ResourceList>
44
+ <ResourceListItem>
45
+ <Avatar
46
+ initials="Shopify"
47
+ size="md"
48
+ source="https://assets.returnless.co/f905e00c-366c-45be-9114-65d29e832027/img/integrations/shopify-plus-logo.svg"
49
+ />
50
+ <ResourceListItemContent>
51
+ <TextStyle variant="strong">
52
+ 6246980452684
53
+ </TextStyle>
54
+ <p>
55
+ <TextStyle variant="subdued">
56
+ 2024-06-23 10:11:12
57
+ </TextStyle>
58
+ </p>
59
+ </ResourceListItemContent>
60
+ </ResourceListItem>
61
+ <ResourceListItem>
62
+ <Avatar
63
+ initials="WICS"
64
+ size="md"
65
+ source="https://assets.returnless.co/f905e00c-366c-45be-9114-65d29e832027/img/integrations/shopify-logo.svg"
66
+ />
67
+ <ResourceListItemContent>
68
+ <TextStyle variant="strong">
69
+ 1273329
70
+ </TextStyle>
71
+ <p>
72
+ <TextStyle variant="subdued">
73
+ 2024-06-23 10:11:12
74
+ </TextStyle>
75
+ </p>
76
+ </ResourceListItemContent>
77
+ </ResourceListItem>
78
+ </ResourceList>
79
+ </CardSection>
80
+ </Card>
81
+ </div>
82
+ </ComponentWrapper>
83
+
84
+ ### List of active shipments
85
+
86
+ <ComponentWrapper>
87
+ <div style="width: 400px;">
88
+ <Card>
89
+ <CardHeader>
90
+ <CardTitle>
91
+ Shipments
92
+ <CardHelp href="/help">Learn more</CardHelp>
93
+ </CardTitle>
94
+ </CardHeader>
95
+ <CardSection flush>
96
+ <ResourceList>
97
+ <ResourceListItem>
98
+ <Avatar
99
+ initials="DHL"
100
+ size="md"
101
+ source="https://assets.returnless.co/f905e00c-366c-45be-9114-65d29e832027/img/carriers/dhl.svg"
102
+ />
103
+ <ResourceListItemContent>
104
+ <StatusIndicator color="slate">Announced</StatusIndicator>
105
+ <p class="text-xs">
106
+ <TextStyle variant="subdued">
107
+ DHLForYou Drop Off
108
+ </TextStyle>
109
+ </p>
110
+ </ResourceListItemContent>
111
+ </ResourceListItem>
112
+ <ResourceListItem>
113
+ <Avatar
114
+ initials="DHL"
115
+ size="md"
116
+ source="https://assets.returnless.co/f905e00c-366c-45be-9114-65d29e832027/img/carriers/dhl.svg"
117
+ />
118
+ <ResourceListItemContent>
119
+ <StatusIndicator color="blue">En-route</StatusIndicator>
120
+ <p class="text-xs">
121
+ <TextStyle variant="subdued">
122
+ DHLForYou Drop Off
123
+ </TextStyle>
124
+ </p>
125
+ </ResourceListItemContent>
126
+ </ResourceListItem>
127
+ <ResourceListItem>
128
+ <Avatar
129
+ initials="DHL"
130
+ size="md"
131
+ source="https://assets.returnless.co/f905e00c-366c-45be-9114-65d29e832027/img/carriers/dhl.svg"
132
+ />
133
+ <ResourceListItemContent>
134
+ <StatusIndicator color="green">Dropped-off</StatusIndicator>
135
+ <p class="text-xs">
136
+ <TextStyle variant="subdued">
137
+ DHLForYou Drop Off
138
+ </TextStyle>
139
+ </p>
140
+ </ResourceListItemContent>
141
+ </ResourceListItem>
142
+ </ResourceList>
143
+ </CardSection>
144
+ <CardFooter>
145
+ <Button variant="secondary">Create new shipment</Button>
146
+ </CardFooter>
147
+ </Card>
148
+ </div>
149
+ </ComponentWrapper>
150
+
151
+ ## Best practices
152
+
153
+ Resource list can live in many places in Returnless. You could include a short resource list in a card summarizing
154
+ recent orders, or you could also dedicate a full page to a resource list of all orders. Here are some best practices:
155
+
156
+ Resource lists should:
157
+
158
+ - Have items that perform an action when clicked. The action should navigate to the resource's details page or
159
+ otherwise provide more detail about the item.
160
+ - Customize the content and layout of their ist items to support users' needs.
@@ -0,0 +1,7 @@
1
+ <script lang="ts" setup></script>
2
+
3
+ <template>
4
+ <ul aria-live="polite">
5
+ <slot />
6
+ </ul>
7
+ </template>
@@ -0,0 +1,7 @@
1
+ <script lang="ts" setup></script>
2
+
3
+ <template>
4
+ <li class="flex items-center space-x-4 hover:bg-slate-100 px-6 py-3 cursor-pointer">
5
+ <slot />
6
+ </li>
7
+ </template>
@@ -0,0 +1,7 @@
1
+ <script lang="ts" setup></script>
2
+
3
+ <template>
4
+ <div>
5
+ <slot />
6
+ </div>
7
+ </template>
@@ -0,0 +1,3 @@
1
+ export { default as ResourceList } from './ResourceList.vue';
2
+ export { default as ResourceListItem } from './ResourceListItem.vue';
3
+ export { default as ResourceListItemContent } from './ResourceListItemContent.vue';
@@ -26,7 +26,7 @@ cluttering the interface.
26
26
 
27
27
  ```js-vue
28
28
  <script lang="ts" setup>
29
- import { Select, SelectGroup, SelectOption } from 'focus-ui';
29
+ import { Select, SelectGroup, SelectOption } from '@returnless/focus-ui';
30
30
  </script>
31
31
 
32
32
  <template>
@@ -66,7 +66,7 @@ const elementId = props.id || useUniqueId('select');
66
66
  :disabled="disabled"
67
67
  :name="name"
68
68
  :readonly="readonly"
69
- class="inline-flex w-full appearance-none rounded-md border px-4 py-3 leading-none"
69
+ class="inline-flex w-full appearance-none rounded-md border bg-white px-4 py-3 leading-none"
70
70
  v-bind="$attrs"
71
71
  >
72
72
  <option
@@ -15,13 +15,15 @@ Use to separate or group content.
15
15
  Card section content
16
16
  <Separator />
17
17
  Card section content
18
+ <Separator label="With separator label" />
19
+ Card section content
18
20
  </CardSection>
19
21
  </Card>
20
22
  </ComponentWrapper>
21
23
 
22
24
  ```js-vue
23
25
  <script lang="ts" setup>
24
- import { Card, CardSection, Separator } from 'focus-ui';
26
+ import { Card, CardSection, Separator } from '@returnless/focus-ui';
25
27
  </script>
26
28
 
27
29
  <template>
@@ -30,6 +32,8 @@ import { Card, CardSection, Separator } from 'focus-ui';
30
32
  Card section content
31
33
  <Separator />
32
34
  Card section content
35
+ <Separator label="With separator label" />
36
+ Card section content
33
37
  </CardSection>
34
38
  </Card>
35
39
  </template>
@@ -1,7 +1,24 @@
1
- <script lang="ts" setup></script>
1
+ <script lang="ts" setup>
2
+ import { TextStyle } from '../TextStyle';
3
+
4
+ withDefaults(defineProps<{
5
+ /** The label to display in the separator. */
6
+ label?: string | null;
7
+ }>(), {
8
+ label: null,
9
+ });
10
+ </script>
2
11
 
3
12
  <template>
4
- <div class="h-12 flex items-center">
5
- <div class="h-[1px] w-full shrink-0 bg-border" />
13
+ <div class="relative flex h-12 items-center">
14
+ <div class="w-full shrink-0 h-[1px] bg-border" />
15
+ <span
16
+ v-if="label"
17
+ class="absolute left-1/2 -translate-x-1/2 bg-white px-4"
18
+ >
19
+ <TextStyle variant="subdued">
20
+ {{ label }}
21
+ </TextStyle>
22
+ </span>
6
23
  </div>
7
24
  </template>
@@ -20,7 +20,7 @@ for content that can't be represented with skeleton loading components, like for
20
20
 
21
21
  ```js-vue
22
22
  <script lang="ts" setup>
23
- import { Spinner } from 'focus-ui';
23
+ import { Spinner } from '@returnless/focus-ui';
24
24
  </script>
25
25
 
26
26
  <template>
@@ -1,20 +1,26 @@
1
1
  <script lang="ts" setup>
2
- withDefaults(defineProps<{
2
+ import { computed } from 'vue';
3
+
4
+ const props = withDefaults(defineProps<{
3
5
  /** Accessible label for the spinner. */
4
- accessibilityLabel?: string | null;
6
+ accessibilityLabel?: string;
5
7
 
6
8
  /** Allows the component to apply the correct accessibility roles based on focus. */
7
9
  hasFocusableParent?: boolean;
8
10
  }>(), {
9
- accessibilityLabel: null,
11
+ accessibilityLabel: undefined,
10
12
  hasFocusableParent: false,
11
13
  });
14
+
15
+ const accessibilityRole = computed((): string | undefined => {
16
+ return props.hasFocusableParent ? 'status' : undefined;
17
+ });
12
18
  </script>
13
19
 
14
20
  <template>
15
21
  <div
16
22
  :aria-label="accessibilityLabel"
17
- :role="(!hasFocusableParent && 'status')"
23
+ :role="accessibilityRole"
18
24
  class="spinner"
19
25
  >
20
26
  <svg
@@ -14,7 +14,7 @@ services, shipment, a user, etc.
14
14
 
15
15
  <ComponentWrapper>
16
16
  <ComponentGrid>
17
- <StatusIndicator>In transit</StatusIndicator>
17
+ <StatusIndicator color="yellow">In transit</StatusIndicator>
18
18
  <StatusIndicator color="red">Request rejected</StatusIndicator>
19
19
  <StatusIndicator color="blue">Announced</StatusIndicator>
20
20
  <StatusIndicator color="green">Return approved</StatusIndicator>
@@ -23,7 +23,7 @@ services, shipment, a user, etc.
23
23
 
24
24
  ```js-vue
25
25
  <script lang="ts" setup>
26
- import { StatusIndicator } from 'focus-ui';
26
+ import { StatusIndicator } from '@returnless/focus-ui';
27
27
  </script>
28
28
 
29
29
  <template>
@@ -1,6 +1,6 @@
1
1
  <script lang="ts" setup>
2
2
  import { computed, CSSProperties } from 'vue';
3
- import { TailwindColor, useTailwindColor } from '../../composables';
3
+ import { TailwindColor, useTailwindColor, useUniqueId } from '../../composables';
4
4
  import { TextStyle } from '../TextStyle';
5
5
 
6
6
  const props = withDefaults(defineProps<{
@@ -11,9 +11,10 @@ const props = withDefaults(defineProps<{
11
11
  color: TailwindColor;
12
12
  }>(), {
13
13
  accessibilityLabel: null,
14
- color: 'yellow',
15
14
  });
16
15
 
16
+ const statusLabelId = useUniqueId('statusLabel');
17
+
17
18
  const colorValues = computed((): CSSProperties => {
18
19
  return {
19
20
  backgroundColor: useTailwindColor(props.color, '300'),
@@ -24,15 +25,20 @@ const colorValues = computed((): CSSProperties => {
24
25
 
25
26
  <template>
26
27
  <div
27
- class="px-3 py-1 inline-flex items-center space-x-2"
28
+ :aria-labelledby="statusLabelId"
28
29
  :style="{ color: colorValues.color }"
30
+ aria-live="polite"
31
+ class="inline-flex items-center space-x-2"
32
+ role="status"
29
33
  >
30
34
  <div
31
- class="w-4 h-4 rounded-full"
35
+ class="w-3 h-3 rounded-full"
32
36
  :style="{ backgroundColor: colorValues.backgroundColor }"
33
37
  />
34
38
  <TextStyle variant="strong">
35
- <slot />
39
+ <span :id="statusLabelId">
40
+ <slot />
41
+ </span>
36
42
  </TextStyle>
37
43
  </div>
38
44
  </template>
@@ -0,0 +1,38 @@
1
+ <script lang="ts" setup>
2
+ import { Stepper } from '../../src/components';
3
+ import api from '../component-meta/Stepper.json';
4
+ import { ref } from "vue";
5
+
6
+ const stepperNumber = ref(0);
7
+ </script>
8
+
9
+ # Stepper
10
+
11
+ <ComponentApi :api="api" />
12
+
13
+ ## Usage
14
+
15
+ <ComponentWrapper>
16
+ <Stepper
17
+ v-model="stepperNumber"
18
+ :min="0"
19
+ :max="5"
20
+ label="QTY Received"
21
+ />
22
+ </ComponentWrapper>
23
+
24
+ ```js-vue
25
+ <script lang="ts" setup>
26
+ import { Stepper } from '@returnless/focus-ui';
27
+
28
+ const stepperNumber = ref(0);
29
+ </script>
30
+
31
+ <template>
32
+ <Stepper
33
+ v-model="stepperNumber"
34
+ :max="5"
35
+ label="QTY Received"
36
+ />
37
+ </template>
38
+ ```
@@ -0,0 +1,104 @@
1
+ <script lang="ts" setup>
2
+ import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/vue/16/solid';
3
+ import { TextStyle } from '../TextStyle';
4
+ import { useTheme } from '../../composables';
5
+
6
+ const props = withDefaults(defineProps<{
7
+ /** The label for the stepper. */
8
+ label: string;
9
+
10
+ /** The maximum value of the stepper. */
11
+ max: number;
12
+
13
+ /** The minimum value of the stepper. */
14
+ min: number;
15
+ }>(), {
16
+ min: undefined,
17
+ max: undefined,
18
+ });
19
+
20
+ const model = defineModel<number>();
21
+
22
+ function decrement(): void {
23
+ if (model.value! <= props.min) {
24
+ return;
25
+ }
26
+
27
+ model.value!--;
28
+ }
29
+
30
+ function increment(): void {
31
+ if (model.value! >= props.max) {
32
+ return;
33
+ }
34
+
35
+ model.value!++;
36
+ }
37
+
38
+ function handleFocus(event: Event): void {
39
+ (event.target as HTMLInputElement).select();
40
+ }
41
+
42
+ function handleInput(event: InputEvent | Event): void {
43
+ const target = event.target as HTMLInputElement;
44
+ let value = Number(target.value);
45
+
46
+ if (value > props.max) {
47
+ value = props.max;
48
+ }
49
+
50
+ if (value < props.min) {
51
+ value = props.min;
52
+ }
53
+
54
+ model.value = value;
55
+ target.valueAsNumber = value;
56
+ }
57
+ </script>
58
+
59
+ <template>
60
+ <div class="inline-flex select-none flex-col space-y-2">
61
+ <div class="inline-flex items-stretch rounded border shadow-sm">
62
+ <button
63
+ :class="useTheme('focus')"
64
+ :disabled="model === props.min"
65
+ class="rounded-l bg-white px-3 hover:bg-slate-100 focus:z-10 disabled:pointer-events-none disabled:opacity-20"
66
+ type="button"
67
+ @click="decrement"
68
+ >
69
+ <ChevronLeftIcon class="h-4 w-4" />
70
+ </button>
71
+ <input
72
+ :class="useTheme('focus')"
73
+ :value="model"
74
+ class="relative w-12 appearance-none border-x bg-slate-100 py-2 text-center"
75
+ inputmode="numeric"
76
+ type="number"
77
+ @focus="handleFocus"
78
+ @input="handleInput"
79
+ >
80
+ <button
81
+ :class="useTheme('focus')"
82
+ :disabled="model === props.max"
83
+ class="rounded-r bg-white px-3 hover:bg-slate-100 focus:z-10 disabled:pointer-events-none disabled:opacity-20"
84
+ type="button"
85
+ @click="increment"
86
+ >
87
+ <ChevronRightIcon class="h-4 w-4" />
88
+ </button>
89
+ </div>
90
+ <div class="select-text text-center text-xs">
91
+ <TextStyle variant="subdued">
92
+ {{ label }}
93
+ </TextStyle>
94
+ </div>
95
+ </div>
96
+ </template>
97
+
98
+ <style scoped>
99
+ input[type="number"]::-webkit-inner-spin-button,
100
+ input[type="number"]::-webkit-outer-spin-button {
101
+ -webkit-appearance: none;
102
+ margin: 0;
103
+ }
104
+ </style>
@@ -0,0 +1 @@
1
+ export { default as Stepper } from './Stepper.vue';
@@ -21,7 +21,7 @@ Use to alternate among related views within the same context.
21
21
 
22
22
  ```js-vue
23
23
  <script lang="ts" setup>
24
- import { Tabs, TabTrigger } from 'focus-ui';
24
+ import { Tabs, TabTrigger } from '@returnless/focus-ui';
25
25
  </script>
26
26
 
27
27
  <template>
@@ -10,10 +10,10 @@ const props = withDefaults(defineProps<{
10
10
  active: false,
11
11
  });
12
12
 
13
- const tabItemId = useUniqueId('tab-item');
13
+ const tabItemId = useUniqueId('tabItem');
14
14
  const activeTabItem = inject<Ref<string>>('activeTabItem')!;
15
15
 
16
- onMounted(() => {
16
+ onMounted((): void => {
17
17
  if (props.active) {
18
18
  activeTabItem.value = tabItemId;
19
19
  }
@@ -23,7 +23,7 @@ function toggleTabItem(): void {
23
23
  activeTabItem.value = tabItemId;
24
24
  }
25
25
 
26
- const classList = computed(() => {
26
+ const classList = computed((): Record<string, boolean>[] => {
27
27
  return [
28
28
  { 'bg-white shadow': activeTabItem.value === tabItemId },
29
29
  ];
@@ -32,8 +32,9 @@ const classList = computed(() => {
32
32
 
33
33
  <template>
34
34
  <button
35
- class="rounded px-3 py-2"
36
35
  :class="classList"
36
+ class="rounded px-3 py-2"
37
+ role="tab"
37
38
  @click="toggleTabItem"
38
39
  >
39
40
  <TextStyle variant="strong">
@@ -7,7 +7,10 @@ provide('activeTabItem', activeTabItem);
7
7
  </script>
8
8
 
9
9
  <template>
10
- <div class="inline-flex rounded-md bg-slate-200 p-1">
10
+ <div
11
+ class="inline-flex rounded-md bg-slate-200 p-1"
12
+ role="tablist"
13
+ >
11
14
  <slot />
12
15
  </div>
13
16
  </template>
@@ -0,0 +1,45 @@
1
+ <script lang="ts" setup>
2
+ import { TailwindColor, useTailwindColor } from '../../composables';
3
+ import { computed, CSSProperties } from 'vue';
4
+ import { TextStyle } from '../TextStyle';
5
+ import { VisuallyHidden } from '../VisuallyHidden';
6
+ import { XMarkIcon } from '@heroicons/vue/16/solid';
7
+
8
+ const props = withDefaults(defineProps<{
9
+ /** Accessible label for the avatar image. */
10
+ accessibilityLabel?: string | null;
11
+
12
+ /** The color of the badge. */
13
+ color: TailwindColor;
14
+ }>(), {
15
+ accessibilityLabel: null,
16
+ });
17
+
18
+ const colorValues = computed((): CSSProperties => {
19
+ return {
20
+ backgroundColor: useTailwindColor(props.color, '200'),
21
+ color: useTailwindColor(props.color, '900'),
22
+ };
23
+ });
24
+ </script>
25
+
26
+ <template>
27
+ <span
28
+ class="text-xs px-2 py-1 inline-flex items-center rounded bg-slate-200"
29
+ :style="colorValues"
30
+ >
31
+ <TextStyle variant="strong">
32
+ <div class="flex items-center space-x-2">
33
+ <slot />
34
+ </div>
35
+ </TextStyle>
36
+
37
+ <span
38
+ class="rounded flex items-center cursor-pointer ml-1"
39
+ >
40
+ <XMarkIcon class="w-4 h-4" />
41
+ </span>
42
+
43
+ <VisuallyHidden v-if="accessibilityLabel">{{ accessibilityLabel }}</VisuallyHidden>
44
+ </span>
45
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Tag } from './Tag.vue';