@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,98 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { ProgressBar, ProgressBarIndicator } from '../../src/components';
|
|
3
|
+
import api from '../component-meta/ProgressBar.json';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
# Progress bar
|
|
7
|
+
|
|
8
|
+
The progress component is used to visually represent the completion of a task or operation. It shows how much of the
|
|
9
|
+
task has been completed and how much is still left.
|
|
10
|
+
|
|
11
|
+
<ComponentApi :api="api" />
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
<ComponentWrapper>
|
|
16
|
+
<ProgressBar :value="33" />
|
|
17
|
+
</ComponentWrapper>
|
|
18
|
+
|
|
19
|
+
```js-vue
|
|
20
|
+
<script lang="ts" setup>
|
|
21
|
+
import { ProgressBar } from 'focus-ui';
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<ProgressBar :value="33" />
|
|
26
|
+
</template>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### With progress indicator above
|
|
30
|
+
|
|
31
|
+
Using the `indicator-position` prop, you can position the progress indicator above or below the progress bar.
|
|
32
|
+
|
|
33
|
+
<ComponentWrapper>
|
|
34
|
+
<ProgressBar :value="33" indicator-position="above">
|
|
35
|
+
<ProgressBarIndicator align="right">33% completed</ProgressBarIndicator>
|
|
36
|
+
</ProgressBar>
|
|
37
|
+
</ComponentWrapper>
|
|
38
|
+
|
|
39
|
+
```js-vue
|
|
40
|
+
<script lang="ts" setup>
|
|
41
|
+
import { ProgressBar, ProgressBarIndicator } from 'focus-ui';
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<template>
|
|
45
|
+
<ProgressBar :value="33" indicator-position="above">
|
|
46
|
+
<ProgressBarIndicator align="right">33% completed</ProgressBarIndicator>
|
|
47
|
+
</ProgressBar>
|
|
48
|
+
</template>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### With progress indicator below
|
|
52
|
+
|
|
53
|
+
<ComponentWrapper>
|
|
54
|
+
<ProgressBar :value="33" indicator-position="below">
|
|
55
|
+
<ProgressBarIndicator align="right">33% completed</ProgressBarIndicator>
|
|
56
|
+
</ProgressBar>
|
|
57
|
+
</ComponentWrapper>
|
|
58
|
+
|
|
59
|
+
```js-vue
|
|
60
|
+
<script lang="ts" setup>
|
|
61
|
+
import { ProgressBar, ProgressBarIndicator } from 'focus-ui';
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<template>
|
|
65
|
+
<ProgressBar :value="33" indicator-position="below">
|
|
66
|
+
<ProgressBarIndicator align="right">33% completed</ProgressBarIndicator>
|
|
67
|
+
</ProgressBar>
|
|
68
|
+
</template>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Progress indicator alignment
|
|
72
|
+
|
|
73
|
+
Using the `align` prop, you can align the progress indicator to the left, center, or right.
|
|
74
|
+
|
|
75
|
+
<ComponentWrapper>
|
|
76
|
+
<ProgressBar :value="33" indicator-position="below">
|
|
77
|
+
<ProgressBarIndicator align="left">33% completed</ProgressBarIndicator>
|
|
78
|
+
</ProgressBar>
|
|
79
|
+
</ComponentWrapper>
|
|
80
|
+
|
|
81
|
+
```js-vue
|
|
82
|
+
<script lang="ts" setup>
|
|
83
|
+
import { ProgressBar, ProgressBarIndicator } from 'focus-ui';
|
|
84
|
+
</script>
|
|
85
|
+
|
|
86
|
+
<template>
|
|
87
|
+
<ProgressBar :value="33" indicator-position="below">
|
|
88
|
+
<ProgressBarIndicator align="left">33% completed</ProgressBarIndicator>
|
|
89
|
+
</ProgressBar>
|
|
90
|
+
</template>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Best practices
|
|
94
|
+
|
|
95
|
+
Progress components should:
|
|
96
|
+
|
|
97
|
+
- Give users an indication of how much of the task has completed and how much is left.
|
|
98
|
+
- Not be used for entire page loads. In this case, use the `Skeleton page` component.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { FormLayout, RadioButton } from '../../src/components';
|
|
3
|
+
import api from '../component-meta/RadioButton.json';
|
|
4
|
+
import { ref } from "vue";
|
|
5
|
+
|
|
6
|
+
const test = ref<string | null>(null);
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
# Radio button
|
|
10
|
+
|
|
11
|
+
Use radio buttons to present each item in a list of options where users must make a single selection.
|
|
12
|
+
|
|
13
|
+
<ComponentApi :api="api" />
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
<ComponentWrapper>
|
|
18
|
+
<FormLayout>
|
|
19
|
+
<RadioButton
|
|
20
|
+
v-model="test"
|
|
21
|
+
value="comments"
|
|
22
|
+
label="Comments"
|
|
23
|
+
help-text="Get notified when someones posts a comment on a posting." />
|
|
24
|
+
<RadioButton
|
|
25
|
+
v-model="test"
|
|
26
|
+
value="candidates"
|
|
27
|
+
label="Candidates"
|
|
28
|
+
help-text="Get notified when a candidate applies for a job." />
|
|
29
|
+
<RadioButton
|
|
30
|
+
v-model="test"
|
|
31
|
+
value="offers"
|
|
32
|
+
label="Offers"
|
|
33
|
+
help-text="Get notified when a candidate accepts or rejects an offer." />
|
|
34
|
+
</FormLayout>
|
|
35
|
+
<pre class="mt-4">{{ test }}</pre>
|
|
36
|
+
</ComponentWrapper>
|
|
37
|
+
|
|
38
|
+
```js-vue
|
|
39
|
+
<script lang="ts" setup>
|
|
40
|
+
import { RadioButton } from 'focus-ui';
|
|
41
|
+
|
|
42
|
+
const radioButtonModel = ref<string | null>(null);
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<FormLayout>
|
|
47
|
+
<RadioButton
|
|
48
|
+
v-model="radioButtonModel"
|
|
49
|
+
value="comments"
|
|
50
|
+
label="Comments"
|
|
51
|
+
help-text="Get notified when someones posts a comment on a posting." />
|
|
52
|
+
<RadioButton
|
|
53
|
+
v-model="radioButtonModel"
|
|
54
|
+
value="candidates"
|
|
55
|
+
label="Candidates"
|
|
56
|
+
help-text="Get notified when a candidate applies for a job." />
|
|
57
|
+
<RadioButton
|
|
58
|
+
v-model="radioButtonModel"
|
|
59
|
+
value="offers"
|
|
60
|
+
label="Offers"
|
|
61
|
+
help-text="Get notified when a candidate accepts or rejects an offer." />
|
|
62
|
+
</FormLayout>
|
|
63
|
+
<pre class="mt-4">{{ radioButtonModel }}</pre>
|
|
64
|
+
</template>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Best practices
|
|
68
|
+
|
|
69
|
+
Radio buttons should:
|
|
70
|
+
|
|
71
|
+
- Always be used with an associated label component.
|
|
72
|
+
- Be part of list of radio buttons that:
|
|
73
|
+
- Include at least two or more choices.
|
|
74
|
+
- Are used to have users select only one option from a list of options.
|
|
75
|
+
- Include mutually exclusive options - this means that each option must be independent of every other option in the
|
|
76
|
+
list. For example: Red, Blue, Green, and Yellow are mutually exclusive. Read, blue, yellow, red/blue are not
|
|
77
|
+
mutually exclusive.
|
|
78
|
+
- List options in a rational order that makes logical sense.
|
|
79
|
+
- Have a default option selected whenever possible.
|
|
80
|
+
|
|
81
|
+
## Content guidelines
|
|
82
|
+
|
|
83
|
+
### Radio button labels
|
|
84
|
+
|
|
85
|
+
Radio button labels should:
|
|
86
|
+
|
|
87
|
+
- Be introduced with a colon or a heading.
|
|
88
|
+
- Start with a capital letter.
|
|
89
|
+
- Not end in punctuation if it's a single sentence, word, or a fragment.
|
|
90
|
+
|
|
91
|
+
## Accessibility
|
|
92
|
+
|
|
93
|
+
Screen readers convey the state of the radio button automatically.
|
|
94
|
+
|
|
95
|
+
- Use the `disabled` prop to apply the HTML `disabled` attribute to the radio button `<input>`. This prevents users
|
|
96
|
+
from being able to interact with the radio button, and conveys its inactive state to assistive technologies.
|
|
97
|
+
- Use the `id` prop to provide a unique `id` attribute value for the radio button. If an `id` isn't provided, then
|
|
98
|
+
the component generates one. All radio buttons must have unique `id` values to work correctly with assistive
|
|
99
|
+
technologies.
|
|
100
|
+
|
|
101
|
+
### Labelling
|
|
102
|
+
|
|
103
|
+
- The required `label` prop conveys the purpose of the radio button to all users.
|
|
104
|
+
- Use the `labelHidden` prop to visually hide the label but make it available to assistive technologies.
|
|
105
|
+
- When you provide help text via the `helpText` prop or an inline error message via the `error` prop, the help or
|
|
106
|
+
error content is conveyed to screen reader users with the `aria-describedBy` attribute.
|
|
107
|
+
|
|
108
|
+
### Keyboard support
|
|
109
|
+
|
|
110
|
+
- Move focus to the radio button group using the tab key (or shift + tab when tabbing backwards).
|
|
111
|
+
- Use the up and down arrow keys to change which radio button is selected.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { InputLabel } from '../InputLabel';
|
|
3
|
+
import { useUniqueId } from '../../composables';
|
|
4
|
+
import { TextStyle } from '../TextStyle';
|
|
5
|
+
|
|
6
|
+
const props = withDefaults(defineProps<{
|
|
7
|
+
/** The help text to display with the radioButton. */
|
|
8
|
+
helpText?: string | null;
|
|
9
|
+
|
|
10
|
+
/** The ID of the radioButton. */
|
|
11
|
+
id?: string | null;
|
|
12
|
+
|
|
13
|
+
/** The label for the radioButton. */
|
|
14
|
+
label: string;
|
|
15
|
+
|
|
16
|
+
/** The value of the radioButton. */
|
|
17
|
+
value: any;
|
|
18
|
+
}>(), {
|
|
19
|
+
id: null,
|
|
20
|
+
helpText: null,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const model = defineModel<boolean>();
|
|
24
|
+
|
|
25
|
+
const elementId = props.id || useUniqueId('radioButton');
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<template>
|
|
29
|
+
<div class="flex items-start space-x-2">
|
|
30
|
+
<input
|
|
31
|
+
:id="elementId"
|
|
32
|
+
v-model="model"
|
|
33
|
+
:value="value"
|
|
34
|
+
class="appearance-none border-slate-400 shadow-sm border bg-white h-4 w-4 rounded-full text-brand-500 focus:ring-indigo-600"
|
|
35
|
+
type="radio"
|
|
36
|
+
>
|
|
37
|
+
<div class="-mt-[2px] space-y-1">
|
|
38
|
+
<InputLabel
|
|
39
|
+
:label="label"
|
|
40
|
+
:label-for="elementId"
|
|
41
|
+
/>
|
|
42
|
+
|
|
43
|
+
<TextStyle variant="subdued">
|
|
44
|
+
{{ helpText }}
|
|
45
|
+
</TextStyle>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</template>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as RadioButton } from './RadioButton.vue';
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { Select, SelectGroup, SelectOption } from '../../src/components';
|
|
3
|
+
import api from '../component-meta/Select.json';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
# Select
|
|
7
|
+
|
|
8
|
+
Select lets users choose one option from an options' menu. Consider select when you have 4 or more options, to void
|
|
9
|
+
cluttering the interface.
|
|
10
|
+
|
|
11
|
+
<ComponentApi :api="api" />
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
<ComponentWrapper>
|
|
16
|
+
<Select label="Select a fruit" placeholder="Select a fruit">
|
|
17
|
+
<SelectOption>Apple</SelectOption>
|
|
18
|
+
<SelectOption>Banana</SelectOption>
|
|
19
|
+
<SelectGroup label="Other fruits">
|
|
20
|
+
<SelectOption>Blueberry</SelectOption>
|
|
21
|
+
<SelectOption>Grapes</SelectOption>
|
|
22
|
+
<SelectOption>Pineapple</SelectOption>
|
|
23
|
+
</SelectGroup>
|
|
24
|
+
</Select>
|
|
25
|
+
</ComponentWrapper>
|
|
26
|
+
|
|
27
|
+
```js-vue
|
|
28
|
+
<script lang="ts" setup>
|
|
29
|
+
import { Select, SelectGroup, SelectOption } from 'focus-ui';
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<template>
|
|
33
|
+
<Select label="Select a fruit" placeholder="Select a fruit">
|
|
34
|
+
<SelectOption>Apple</SelectOption>
|
|
35
|
+
<SelectOption>Banana</SelectOption>
|
|
36
|
+
<SelectGroup label="Other fruits">
|
|
37
|
+
<SelectOption>Blueberry</SelectOption>
|
|
38
|
+
<SelectOption>Grapes</SelectOption>
|
|
39
|
+
<SelectOption>Pineapple</SelectOption>
|
|
40
|
+
</SelectGroup>
|
|
41
|
+
</Select>
|
|
42
|
+
</template>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Best practices
|
|
46
|
+
|
|
47
|
+
The select component should:
|
|
48
|
+
|
|
49
|
+
- Be used for selecting between 4 or more pre-defined options.
|
|
50
|
+
- Have a default option selected whenever possible.
|
|
51
|
+
- Use "Select" as a placeholder option only if there's no logical default option.
|
|
52
|
+
|
|
53
|
+
## Content guidelines
|
|
54
|
+
|
|
55
|
+
### Select label
|
|
56
|
+
|
|
57
|
+
Label should:
|
|
58
|
+
|
|
59
|
+
- Given a short description (1-3 words) of the requested input.
|
|
60
|
+
- Be written in sentence case (the first word capitalized, the rest lowercase).
|
|
61
|
+
- Avoid punctuation and articles ("the", "an", "a").
|
|
62
|
+
- Be independent sentences. To support internationalization, they should not act as the first part of a sentence
|
|
63
|
+
that is finished by the component's options.
|
|
64
|
+
- Be descriptive, not instructional. If the selection needs more explanation, use help text below the field.
|
|
65
|
+
|
|
66
|
+
### Select options
|
|
67
|
+
|
|
68
|
+
Options should:
|
|
69
|
+
|
|
70
|
+
- Start with "Select" as a placeholder if there isn't a default option.
|
|
71
|
+
- Be listed alphabetically or in another logical order so users can easily find the option they need.
|
|
72
|
+
- Be written sentence case (the first word capitalized, the rest lowercase) and avoid using commas or semicolons at
|
|
73
|
+
the end of each option.
|
|
74
|
+
- Be clearly labelled based on what the option will do.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { InputLabel } from '../InputLabel';
|
|
3
|
+
import { useUniqueId, useTheme } from '../../composables';
|
|
4
|
+
import { ChevronUpDownIcon } from '@heroicons/vue/16/solid';
|
|
5
|
+
|
|
6
|
+
const props = withDefaults(defineProps<{
|
|
7
|
+
/** Whether the input is disabled. */
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
|
|
10
|
+
/** The help text to display below the input. */
|
|
11
|
+
helpText?: string | null;
|
|
12
|
+
|
|
13
|
+
/** The ID of the input the label is associated with. */
|
|
14
|
+
id?: string | null;
|
|
15
|
+
|
|
16
|
+
/** The label text. */
|
|
17
|
+
label: string;
|
|
18
|
+
|
|
19
|
+
/** Whether the label is hidden. */
|
|
20
|
+
labelHidden?: boolean;
|
|
21
|
+
|
|
22
|
+
/** The name of the input. */
|
|
23
|
+
name: string;
|
|
24
|
+
|
|
25
|
+
/** The placeholder text. */
|
|
26
|
+
placeholder?: string | null;
|
|
27
|
+
|
|
28
|
+
/** Whether the input is read-only. */
|
|
29
|
+
readonly?: boolean;
|
|
30
|
+
|
|
31
|
+
/** Whether the input is required. */
|
|
32
|
+
required?: boolean;
|
|
33
|
+
}>(), {
|
|
34
|
+
disabled: false,
|
|
35
|
+
helpText: null,
|
|
36
|
+
id: null,
|
|
37
|
+
labelHidden: false,
|
|
38
|
+
placeholder: null,
|
|
39
|
+
readonly: false,
|
|
40
|
+
required: false,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const model = defineModel<string | null>();
|
|
44
|
+
|
|
45
|
+
const elementId = props.id || useUniqueId('select');
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<template>
|
|
49
|
+
<div class="w-full space-y-2">
|
|
50
|
+
<InputLabel
|
|
51
|
+
:id="`${elementId}-label`"
|
|
52
|
+
:label="label"
|
|
53
|
+
:label-for="elementId"
|
|
54
|
+
:label-hidden="labelHidden"
|
|
55
|
+
/>
|
|
56
|
+
|
|
57
|
+
<div class="relative">
|
|
58
|
+
<select
|
|
59
|
+
:id="elementId"
|
|
60
|
+
v-model="model"
|
|
61
|
+
:aria-disabled="disabled"
|
|
62
|
+
:aria-labelledby="`${elementId}-label`"
|
|
63
|
+
:aria-readonly="readonly"
|
|
64
|
+
:aria-required="required"
|
|
65
|
+
:class="useTheme('focus')"
|
|
66
|
+
:disabled="disabled"
|
|
67
|
+
:name="name"
|
|
68
|
+
:readonly="readonly"
|
|
69
|
+
class="inline-flex w-full appearance-none rounded-md border px-4 py-3 leading-none"
|
|
70
|
+
v-bind="$attrs"
|
|
71
|
+
>
|
|
72
|
+
<option
|
|
73
|
+
v-if="placeholder"
|
|
74
|
+
:value="null"
|
|
75
|
+
disabled
|
|
76
|
+
selected
|
|
77
|
+
>
|
|
78
|
+
{{ placeholder }}
|
|
79
|
+
</option>
|
|
80
|
+
|
|
81
|
+
<slot />
|
|
82
|
+
</select>
|
|
83
|
+
|
|
84
|
+
<div
|
|
85
|
+
class="absolute top-3 right-4 h-4 w-4"
|
|
86
|
+
>
|
|
87
|
+
<ChevronUpDownIcon />
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
</template>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { Card, CardSection, Separator } from '../../src/components';
|
|
3
|
+
import api from '../component-meta/Separator.json';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
# Separator
|
|
7
|
+
|
|
8
|
+
Use to separate or group content.
|
|
9
|
+
|
|
10
|
+
<ComponentApi :api="api" />
|
|
11
|
+
|
|
12
|
+
<ComponentWrapper>
|
|
13
|
+
<Card>
|
|
14
|
+
<CardSection>
|
|
15
|
+
Card section content
|
|
16
|
+
<Separator />
|
|
17
|
+
Card section content
|
|
18
|
+
</CardSection>
|
|
19
|
+
</Card>
|
|
20
|
+
</ComponentWrapper>
|
|
21
|
+
|
|
22
|
+
```js-vue
|
|
23
|
+
<script lang="ts" setup>
|
|
24
|
+
import { Card, CardSection, Separator } from 'focus-ui';
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<template>
|
|
28
|
+
<Card>
|
|
29
|
+
<CardSection>
|
|
30
|
+
Card section content
|
|
31
|
+
<Separator />
|
|
32
|
+
Card section content
|
|
33
|
+
</CardSection>
|
|
34
|
+
</Card>
|
|
35
|
+
</template>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Separator } from './Separator.vue';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { Spinner } from '../../src/components';
|
|
3
|
+
import api from '../component-meta/Spinner.json';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
# Spinner
|
|
7
|
+
|
|
8
|
+
Spinners are used to notify users that their action is being processed. For loading state, spinners should only be used
|
|
9
|
+
for content that can't be represented with skeleton loading components, like for data charts.
|
|
10
|
+
|
|
11
|
+
<ComponentApi :api="api" />
|
|
12
|
+
|
|
13
|
+
## Variants
|
|
14
|
+
|
|
15
|
+
### Default
|
|
16
|
+
|
|
17
|
+
<ComponentWrapper>
|
|
18
|
+
<Spinner />
|
|
19
|
+
</ComponentWrapper>
|
|
20
|
+
|
|
21
|
+
```js-vue
|
|
22
|
+
<script lang="ts" setup>
|
|
23
|
+
import { Spinner } from 'focus-ui';
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<template>
|
|
27
|
+
<Spinner />
|
|
28
|
+
</template>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Accessibility
|
|
32
|
+
|
|
33
|
+
SVGs are often conveyed inconsistently to assistive technologies. The `Spinner` component's accessibility is also
|
|
34
|
+
highly contextual. When the parent component is focusable, you'll need to set the `hasFocusableParent` prop for the
|
|
35
|
+
appropriate `role` attribute to be applied.
|
|
36
|
+
|
|
37
|
+
For optimal user experience, use the `accessibilityLabel` prop to let assistive technology users know the purpose of
|
|
38
|
+
the spinner.
|
|
39
|
+
|
|
40
|
+
## Best practices
|
|
41
|
+
|
|
42
|
+
The spinner component should:
|
|
43
|
+
|
|
44
|
+
- Notify users that their request has been received and the action will soon complete.
|
|
45
|
+
- Not be used to give feedback for an entire page load.
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## Content guidelines
|
|
49
|
+
|
|
50
|
+
Spinner accessibility labels should:
|
|
51
|
+
|
|
52
|
+
- Accurately explain the state of the requested action. For example, "Loading", "Submitting", or "Processing".
|
|
53
|
+
- Use as few words to describe the state as possible.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
withDefaults(defineProps<{
|
|
3
|
+
/** Accessible label for the spinner. */
|
|
4
|
+
accessibilityLabel?: string | null;
|
|
5
|
+
|
|
6
|
+
/** Allows the component to apply the correct accessibility roles based on focus. */
|
|
7
|
+
hasFocusableParent?: boolean;
|
|
8
|
+
}>(), {
|
|
9
|
+
accessibilityLabel: null,
|
|
10
|
+
hasFocusableParent: false,
|
|
11
|
+
});
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<div
|
|
16
|
+
:aria-label="accessibilityLabel"
|
|
17
|
+
:role="(!hasFocusableParent && 'status')"
|
|
18
|
+
class="spinner"
|
|
19
|
+
>
|
|
20
|
+
<svg
|
|
21
|
+
width="20"
|
|
22
|
+
height="20"
|
|
23
|
+
stroke-width="15"
|
|
24
|
+
viewBox="-3.00 -3.00 106.00 106.00"
|
|
25
|
+
>
|
|
26
|
+
<path
|
|
27
|
+
class="head"
|
|
28
|
+
d="M 50,50 m 0, -45 a 45, 45 0 1 1 0,90 a 45,45 0 1 1 0,-90"
|
|
29
|
+
pathLength="600"
|
|
30
|
+
stroke-dasharray="280 280"
|
|
31
|
+
/>
|
|
32
|
+
</svg>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<style scoped>
|
|
37
|
+
.spinner {
|
|
38
|
+
display: inline-flex;
|
|
39
|
+
animation: spinner 0.75s linear infinite;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
path {
|
|
43
|
+
fill-opacity: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.head {
|
|
47
|
+
stroke: black;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@keyframes spinner {
|
|
51
|
+
0% {
|
|
52
|
+
transform: rotate(0deg);
|
|
53
|
+
}
|
|
54
|
+
to {
|
|
55
|
+
transform: rotate(1turn);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Spinner } from './Spinner.vue';
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { StatusIndicator } from '../../src/components';
|
|
3
|
+
import api from '../component-meta/StatusIndicator.json';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
# Status indicator
|
|
7
|
+
|
|
8
|
+
Status indicator is a component that shows the status of a given entity. It can be used to show the status of a
|
|
9
|
+
services, shipment, a user, etc.
|
|
10
|
+
|
|
11
|
+
<ComponentApi :api="api" />
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
<ComponentWrapper>
|
|
16
|
+
<ComponentGrid>
|
|
17
|
+
<StatusIndicator>In transit</StatusIndicator>
|
|
18
|
+
<StatusIndicator color="red">Request rejected</StatusIndicator>
|
|
19
|
+
<StatusIndicator color="blue">Announced</StatusIndicator>
|
|
20
|
+
<StatusIndicator color="green">Return approved</StatusIndicator>
|
|
21
|
+
</ComponentGrid>
|
|
22
|
+
</ComponentWrapper>
|
|
23
|
+
|
|
24
|
+
```js-vue
|
|
25
|
+
<script lang="ts" setup>
|
|
26
|
+
import { StatusIndicator } from 'focus-ui';
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<StatusIndicator>In Transit</StatusIndicator>
|
|
31
|
+
<StatusIndicator color="red">Request rejected</StatusIndicator>
|
|
32
|
+
<StatusIndicator color="blue">Announced</StatusIndicator>
|
|
33
|
+
<StatusIndicator color="green">Return approved</StatusIndicator>
|
|
34
|
+
</template>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Best practices
|
|
38
|
+
|
|
39
|
+
Status indicators benefit users by:
|
|
40
|
+
|
|
41
|
+
- Using established color patterns so that users can quickly identify their tone or importance level.
|
|
42
|
+
- Being clearly labeled with short, scannable text.
|
|
43
|
+
- Being positioned to clearly identify the object they're informing or labelling.
|
|
44
|
+
|
|
45
|
+
## Content guidelines
|
|
46
|
+
|
|
47
|
+
Status indicator labels should:
|
|
48
|
+
|
|
49
|
+
- Use a single word to describe the tone of an object.
|
|
50
|
+
- Only use two words if you need to describe a complex state. For example "Partially refunded" and "Partially paid".
|
|
51
|
+
- Always describe the tone in the past tense. For example, refunded not refund.
|