@returnless/focus-ui 0.0.1 → 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.
- package/dist/focus-ui.js +10851 -0
- package/dist/focus-ui.umd.cjs +26 -0
- package/dist/style.css +1 -0
- package/package.json +13 -8
- package/src/build-utils/generate-component-meta.ts +5 -1
- package/src/build-utils/update-component-list.ts +1 -1
- package/src/components/Accordion/AccordionContent.vue +34 -5
- package/src/components/Accordion/AccordionItem.vue +5 -2
- package/src/components/Accordion/AccordionTrigger.vue +5 -2
- package/src/components/Accordion/README.md +1 -1
- package/src/components/ActionList/ActionList.vue +9 -0
- package/src/components/ActionList/ActionListBody.vue +11 -0
- package/src/components/ActionList/ActionListItem.vue +37 -0
- package/src/components/ActionList/ActionListSection.vue +7 -0
- package/src/components/ActionList/ActionListTrigger.vue +9 -0
- package/src/components/ActionList/README.md +113 -0
- package/src/components/ActionList/index.ts +5 -0
- package/src/components/Alert/Alert.vue +23 -10
- package/src/components/Alert/AlertDescription.vue +13 -1
- package/src/components/Alert/AlertTitle.vue +1 -1
- package/src/components/Alert/DismissableAlertButton.vue +6 -4
- package/src/components/Alert/README.md +31 -2
- package/src/components/Alert/index.ts +2 -0
- package/src/components/Alert/types.ts +1 -0
- package/src/components/AlertDialog/AlertDialog.vue +10 -1
- package/src/components/AlertDialog/AlertDialogActionButton.vue +9 -2
- package/src/components/AlertDialog/AlertDialogCancelButton.vue +1 -1
- package/src/components/AlertDialog/AlertDialogDescription.vue +7 -1
- package/src/components/AlertDialog/AlertDialogTitle.vue +11 -3
- package/src/components/AlertDialog/README.md +15 -16
- package/src/components/AspectRatio/AspectRatio.vue +19 -0
- package/src/components/AspectRatio/README.md +36 -0
- package/src/components/AspectRatio/index.ts +1 -0
- package/src/components/Avatar/Avatar.vue +57 -13
- package/src/components/Avatar/README.md +3 -9
- package/src/components/Badge/Badge.vue +1 -1
- package/src/components/Badge/README.md +9 -9
- package/src/components/BarChart/BarChart.vue +80 -0
- package/src/components/{MetricCard/MetricCardHeader.vue → BarChart/BarChartContainer.vue} +1 -1
- package/src/components/BarChart/BarChartStacked.vue +93 -0
- package/src/components/BarChart/README.md +83 -0
- package/src/components/BarChart/index.ts +3 -0
- package/src/components/Breadcrumbs/Breadcrumb.vue +7 -0
- package/src/components/Breadcrumbs/BreadcrumbEllipsis.vue +12 -0
- package/src/components/{MetricCard/MetricCardValue.vue → Breadcrumbs/BreadcrumbItem.vue} +2 -2
- package/src/components/Breadcrumbs/BreadcrumbLink.vue +13 -0
- package/src/components/Breadcrumbs/BreadcrumbList.vue +8 -0
- package/src/components/Breadcrumbs/BreadcrumbPage.vue +13 -0
- package/src/components/Breadcrumbs/BreadcrumbSeparator.vue +12 -0
- package/src/components/Breadcrumbs/README.md +91 -0
- package/src/components/Breadcrumbs/index.ts +7 -0
- package/src/components/Button/Button.vue +53 -41
- package/src/components/Button/ButtonContent.vue +1 -1
- package/src/components/Button/ButtonIcon.vue +28 -3
- package/src/components/Button/README.md +32 -29
- package/src/components/Button/index.ts +2 -0
- package/src/components/Button/types.ts +30 -0
- package/src/components/ButtonGroup/README.md +1 -1
- package/src/components/Card/CardHelp.vue +23 -0
- package/src/components/Card/CardSection.vue +17 -2
- package/src/components/Card/CardTitle.vue +6 -3
- package/src/components/Card/README.md +97 -10
- package/src/components/Card/index.ts +2 -1
- package/src/components/Checkbox/Checkbox.vue +29 -5
- package/src/components/Checkbox/README.md +34 -5
- package/src/components/DatePicker/DatePicker.vue +7 -27
- package/src/components/DatePicker/README.md +1 -1
- package/src/components/DescriptionList/DescriptionList.vue +1 -1
- package/src/components/DescriptionList/DescriptionListItem.vue +1 -1
- package/src/components/DescriptionList/README.md +2 -2
- package/src/components/Dialog/README.md +2 -0
- package/src/components/Dialog/index.ts +0 -0
- package/src/components/DropZone/DropZone.vue +105 -0
- package/src/components/DropZone/README.md +48 -0
- package/src/components/DropZone/index.ts +1 -0
- package/src/components/EmptyState/README.md +1 -1
- package/src/components/Feed/FeedItem.vue +4 -1
- package/src/components/Feed/FeedItemBlock.vue +4 -1
- package/src/components/Feed/README.md +1 -1
- package/src/components/FileUploadButton/FileUploadButton.vue +62 -0
- package/src/components/FileUploadButton/index.ts +1 -0
- package/src/components/Form/Form.vue +7 -2
- package/src/components/Form/README.md +1 -1
- package/src/components/FormLayout/FormLayout.vue +20 -2
- package/src/components/FormLayout/README.md +39 -1
- package/src/components/Heading/Heading.vue +32 -0
- package/src/components/Heading/index.ts +3 -0
- package/src/components/Heading/types.ts +3 -0
- package/src/components/Image/Image.vue +30 -0
- package/src/components/Image/index.ts +1 -0
- package/src/components/InertiaLink/InertiaLink.vue +11 -0
- package/src/components/InertiaLink/index.ts +1 -0
- package/src/components/InlineError/InlineError.vue +21 -0
- package/src/components/InlineError/README.md +63 -0
- package/src/components/InlineError/index.ts +1 -0
- package/src/components/KPICard/KPICard.vue +28 -0
- package/src/components/KPICard/KPICardSection.vue +30 -0
- package/src/components/KPICard/README.md +124 -0
- package/src/components/KPICard/index.ts +2 -0
- package/src/components/Legend/Legend.vue +7 -0
- package/src/components/Legend/LegendItem.vue +34 -0
- package/src/components/Legend/README.md +32 -0
- package/src/components/Legend/index.ts +2 -0
- package/src/components/Link/Link.vue +4 -4
- package/src/components/Link/README.md +1 -1
- package/src/components/Navigation/Navigation.vue +2 -2
- package/src/components/Navigation/NavigationItem.vue +14 -10
- package/src/components/Navigation/NavigationSecondarySection.vue +12 -0
- package/src/components/Navigation/NavigationSection.vue +1 -1
- package/src/components/Navigation/README.md +10 -15
- package/src/components/Navigation/index.ts +1 -0
- package/src/components/Page/Page.vue +2 -33
- package/src/components/Page/PageBody.vue +36 -0
- package/src/components/Page/PageTitle.vue +6 -3
- package/src/components/Page/README.md +45 -39
- package/src/components/Page/index.ts +1 -0
- package/src/components/Pagination/README.md +1 -1
- package/src/components/PinInput/README.md +1 -1
- package/src/components/Popover/Popover.vue +18 -0
- package/src/components/Popover/PopoverBody.vue +11 -0
- package/src/components/Popover/PopoverTrigger.vue +9 -0
- package/src/components/Popover/README.md +34 -6
- package/src/components/Popover/index.ts +3 -0
- package/src/components/Popper/Popper.vue +91 -0
- package/src/components/Popper/PopperBody.vue +19 -0
- package/src/components/Popper/PopperTrigger.vue +14 -0
- package/src/components/Popper/README.md +42 -0
- package/src/components/Popper/index.ts +3 -0
- package/src/components/ProgressBar/ProgressBar.vue +24 -6
- package/src/components/RadioButton/README.md +1 -1
- package/src/components/RadioButton/RadioButton.vue +3 -2
- package/src/components/ResourceList/README.md +160 -0
- package/src/components/ResourceList/ResourceList.vue +7 -0
- package/src/components/ResourceList/ResourceListItem.vue +7 -0
- package/src/components/ResourceList/ResourceListItemContent.vue +7 -0
- package/src/components/ResourceList/index.ts +3 -0
- package/src/components/Select/README.md +1 -1
- package/src/components/Select/Select.vue +1 -1
- package/src/components/Separator/README.md +5 -1
- package/src/components/Separator/Separator.vue +20 -3
- package/src/components/Spinner/README.md +1 -1
- package/src/components/Spinner/Spinner.vue +10 -4
- package/src/components/StatusIndicator/README.md +2 -2
- package/src/components/StatusIndicator/StatusIndicator.vue +11 -5
- package/src/components/Stepper/README.md +38 -0
- package/src/components/Stepper/Stepper.vue +104 -0
- package/src/components/Stepper/index.ts +1 -0
- package/src/components/Tabs/README.md +1 -1
- package/src/components/Tabs/TabTrigger.vue +5 -4
- package/src/components/Tabs/Tabs.vue +4 -1
- package/src/components/Tag/Tag.vue +45 -0
- package/src/components/Tag/index.ts +1 -0
- package/src/components/TextField/README.md +24 -6
- package/src/components/TextField/TextField.vue +25 -5
- package/src/components/TextField/TextFieldIcon.vue +19 -0
- package/src/components/TextStyle/README.md +1 -1
- package/src/components/TextStyle/TextStyle.vue +1 -1
- package/src/components/Toast/DismissToastAction.vue +1 -1
- package/src/components/Toast/README.md +1 -1
- package/src/components/Toggle/README.md +1 -1
- package/src/components/Toggle/Toggle.vue +8 -5
- package/src/components/Tooltip/README.md +1 -1
- package/src/components/Tooltip/Tooltip.vue +15 -41
- package/src/components/TopBar/TopBarSearch.vue +2 -2
- package/src/components/index.ts +68 -12
- package/src/components/types.ts +5 -0
- package/src/composables/useTheme.ts +13 -1
- package/src/composables/useToastNotifications.ts +1 -1
- package/src/composables/useUniqueId.ts +4 -3
- package/src/index.css +17 -13
- package/src/index.ts +0 -11
- package/dist/focus-ui.es.js +0 -33
- package/dist/types/components/Accordion/Accordion.vue.d.ts +0 -32
- package/dist/types/components/Accordion/AccordionItem.vue.d.ts +0 -2
- package/dist/types/components/Accordion/index.d.ts +0 -2
- package/dist/types/components/index.d.ts +0 -1
- package/dist/types/index.d.ts +0 -7
- package/src/components/CategoryBar/CategoryBar.vue +0 -25
- package/src/components/CategoryBar/CategoryBarItem.vue +0 -34
- package/src/components/CategoryBar/README.md +0 -17
- package/src/components/CategoryBar/index.ts +0 -2
- package/src/components/MetricCard/MetricCard.vue +0 -11
- package/src/components/MetricCard/MetricCardLabel.vue +0 -9
- package/src/components/MetricCard/MetricCardSection.vue +0 -11
- package/src/components/MetricCard/README.md +0 -53
- package/src/components/MetricCard/index.ts +0 -5
package/dist/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._visuallyHidden_o6qmb_6{position:absolute!important;width:1px!important;height:1px!important;margin:0!important;padding:0!important;overflow:hidden!important;clip-path:inset(50%)!important;border:0!important;white-space:nowrap!important}.spinner[data-v-07df7777]{display:inline-flex;animation:spinner-07df7777 .75s linear infinite}path[data-v-07df7777]{fill-opacity:0}.head[data-v-07df7777]{stroke:#000}@keyframes spinner-07df7777{0%{transform:rotate(0)}to{transform:rotate(1turn)}}input[type=number][data-v-7be10f19]::-webkit-inner-spin-button,input[type=number][data-v-7be10f19]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}
|
package/package.json
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@returnless/focus-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
4
6
|
"scripts": {
|
|
5
|
-
"build": "rimraf dist && vue-tsc && vite build",
|
|
7
|
+
"build": "rimraf dist && vue-tsc --emitDeclarationOnly && vite build",
|
|
6
8
|
"docs:dev": "npm run docs:generate-component-list && npm run docs:generate-component-meta && vitepress dev docs",
|
|
7
9
|
"docs:generate-component-list": "npx tsx ./src/build-utils/update-component-list.ts",
|
|
8
10
|
"docs:generate-component-meta": "npx tsx ./src/build-utils/generate-component-meta.ts",
|
|
9
11
|
"docs:build": "npm run docs:generate-component-list && npm run docs:generate-component-meta && vitepress build docs",
|
|
10
|
-
"docs:preview": "vitepress preview docs"
|
|
12
|
+
"docs:preview": "vitepress preview docs",
|
|
13
|
+
"tsc-lint": "vue-tsc; npx eslint . --fix-dry-run --ext .vue"
|
|
11
14
|
},
|
|
12
15
|
"peerDependencies": {
|
|
13
16
|
"vue": "^3.3.4"
|
|
@@ -23,6 +26,7 @@
|
|
|
23
26
|
"@vitejs/plugin-vue": "^5.0.5",
|
|
24
27
|
"@vueuse/core": "^10.11.0",
|
|
25
28
|
"autoprefixer": "^10.4.19",
|
|
29
|
+
"collect.js": "^4.36.1",
|
|
26
30
|
"dayjs": "^1.11.11",
|
|
27
31
|
"eslint": "^8.57.0",
|
|
28
32
|
"eslint-plugin-vue": "^9.26.0",
|
|
@@ -39,15 +43,16 @@
|
|
|
39
43
|
"src",
|
|
40
44
|
"dist"
|
|
41
45
|
],
|
|
42
|
-
"module": "./dist/focus-ui.
|
|
46
|
+
"module": "./dist/focus-ui.js",
|
|
43
47
|
"exports": {
|
|
44
48
|
".": {
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
}
|
|
49
|
+
"import": "./dist/focus-ui.js",
|
|
50
|
+
"require": "./dist/focus-ui.umd.cjs"
|
|
51
|
+
},
|
|
52
|
+
"./style.css": "./dist/style.css"
|
|
48
53
|
},
|
|
49
54
|
"repository": {
|
|
50
55
|
"type": "git",
|
|
51
|
-
"url": "git+https://github.com/
|
|
56
|
+
"url": "git+https://github.com/Returnless-com/focus-ui.git"
|
|
52
57
|
}
|
|
53
58
|
}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import fs, { existsSync, mkdirSync } from 'fs';
|
|
2
|
-
import { join, parse, resolve } from 'path';
|
|
2
|
+
import { dirname, join, parse, resolve } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
3
4
|
import fg from 'fast-glob';
|
|
4
5
|
import type { ComponentMeta, MetaCheckerOptions } from 'vue-component-meta';
|
|
5
6
|
import { createComponentMetaChecker } from 'vue-component-meta';
|
|
6
7
|
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
|
|
7
11
|
export interface ComponentApiProps {
|
|
8
12
|
name: ComponentMeta['props'][number]['name'];
|
|
9
13
|
description: ComponentMeta['props'][number]['description'];
|
|
@@ -22,7 +22,7 @@ const componentsFileContent = `\
|
|
|
22
22
|
* Generated on: ${new Date().toDateString()}
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
export default [
|
|
26
26
|
${componentList
|
|
27
27
|
.map((component: string) => ` { text: '${component}', link: 'components/${component}' },`)
|
|
28
28
|
.join('\n')}
|
|
@@ -2,13 +2,42 @@
|
|
|
2
2
|
import { inject } from 'vue';
|
|
3
3
|
|
|
4
4
|
const accordionItemActive = inject<boolean>('accordionItemActive');
|
|
5
|
+
const accordionItemId = inject<string>('accordionItemId')!;
|
|
6
|
+
|
|
7
|
+
function beforeEnter(element: Element): void {
|
|
8
|
+
(element as HTMLElement).style.height = '0';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function enter(element: Element): void {
|
|
12
|
+
(element as HTMLElement).style.height = element.scrollHeight + 'px';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function beforeLeave(element: Element): void {
|
|
16
|
+
(element as HTMLElement).style.height = element.scrollHeight + 'px';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function leave(element: Element): void {
|
|
20
|
+
(element as HTMLElement).style.height = '0';
|
|
21
|
+
}
|
|
5
22
|
</script>
|
|
6
23
|
|
|
7
24
|
<template>
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
25
|
+
<transition
|
|
26
|
+
name="accordion"
|
|
27
|
+
@enter="enter"
|
|
28
|
+
@leave="leave"
|
|
29
|
+
@before-enter="beforeEnter"
|
|
30
|
+
@before-leave="beforeLeave"
|
|
11
31
|
>
|
|
12
|
-
<
|
|
13
|
-
|
|
32
|
+
<div
|
|
33
|
+
v-show="accordionItemActive"
|
|
34
|
+
:id="accordionItemId"
|
|
35
|
+
class="transition-all duration-200 ease-in-out overflow-hidden"
|
|
36
|
+
role="region"
|
|
37
|
+
>
|
|
38
|
+
<div class="py-3">
|
|
39
|
+
<slot />
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</transition>
|
|
14
43
|
</template>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { computed, inject, provide, Ref } from 'vue';
|
|
3
3
|
import { useUniqueId } from '../../composables';
|
|
4
4
|
|
|
5
|
-
const accordionItemId = useUniqueId('
|
|
5
|
+
const accordionItemId = useUniqueId('accordionItem');
|
|
6
6
|
const activeAccordionItem = inject<Ref<string>>('activeAccordionItem')!;
|
|
7
7
|
|
|
8
8
|
const accordionItemActive = computed((): boolean => activeAccordionItem.value === accordionItemId);
|
|
@@ -12,7 +12,10 @@ provide('accordionItemActive', accordionItemActive);
|
|
|
12
12
|
</script>
|
|
13
13
|
|
|
14
14
|
<template>
|
|
15
|
-
<div
|
|
15
|
+
<div
|
|
16
|
+
class="border-b"
|
|
17
|
+
:aria-expanded="accordionItemActive"
|
|
18
|
+
>
|
|
16
19
|
<slot />
|
|
17
20
|
</div>
|
|
18
21
|
</template>
|
|
@@ -3,17 +3,20 @@ import { inject, Ref } from 'vue';
|
|
|
3
3
|
import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/vue/16/solid';
|
|
4
4
|
import { TextStyle } from '../TextStyle';
|
|
5
5
|
|
|
6
|
-
const activeAccordionItem = inject<Ref<string>>('activeAccordionItem')!;
|
|
6
|
+
const activeAccordionItem = inject<Ref<string | null>>('activeAccordionItem')!;
|
|
7
7
|
const accordionItemId = inject<string>('accordionItemId')!;
|
|
8
8
|
const accordionItemActive = inject<boolean>('accordionItemActive');
|
|
9
9
|
|
|
10
10
|
function toggleAccordionItem(): void {
|
|
11
|
-
activeAccordionItem.value = accordionItemId
|
|
11
|
+
activeAccordionItem.value = activeAccordionItem.value !== accordionItemId
|
|
12
|
+
? accordionItemId
|
|
13
|
+
: null;
|
|
12
14
|
}
|
|
13
15
|
</script>
|
|
14
16
|
|
|
15
17
|
<template>
|
|
16
18
|
<button
|
|
19
|
+
:aria-controls="accordionItemId"
|
|
17
20
|
class="w-full flex flex-1 items-center justify-between group"
|
|
18
21
|
@click="toggleAccordionItem"
|
|
19
22
|
>
|
|
@@ -34,7 +34,7 @@ Use to display a list of questions and answers. The user can click on a question
|
|
|
34
34
|
|
|
35
35
|
```js-vue
|
|
36
36
|
<script lang="ts" setup>
|
|
37
|
-
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from 'focus-ui';
|
|
37
|
+
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '@returnless/focus-ui';
|
|
38
38
|
</script>
|
|
39
39
|
|
|
40
40
|
<template>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { Button, ButtonContent, ButtonVariant } from '../Button';
|
|
3
|
+
|
|
4
|
+
withDefaults(defineProps<{
|
|
5
|
+
/** Whether the action list item is active. */
|
|
6
|
+
active?: boolean;
|
|
7
|
+
|
|
8
|
+
/** The icon to display next to the action list item. */
|
|
9
|
+
icon: () => void | null;
|
|
10
|
+
|
|
11
|
+
variant?: ButtonVariant;
|
|
12
|
+
}>(), {
|
|
13
|
+
active: false,
|
|
14
|
+
variant: 'ghost',
|
|
15
|
+
});
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<li class="block">
|
|
20
|
+
<Button
|
|
21
|
+
:active="active"
|
|
22
|
+
:variant="variant"
|
|
23
|
+
full-width
|
|
24
|
+
role="menuitem"
|
|
25
|
+
size="small"
|
|
26
|
+
>
|
|
27
|
+
<component
|
|
28
|
+
:is="icon"
|
|
29
|
+
v-if="icon"
|
|
30
|
+
class="w-4 h-4"
|
|
31
|
+
/>
|
|
32
|
+
<ButtonContent>
|
|
33
|
+
<slot />
|
|
34
|
+
</ButtonContent>
|
|
35
|
+
</Button>
|
|
36
|
+
</li>
|
|
37
|
+
</template>
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import {
|
|
3
|
+
ActionList,
|
|
4
|
+
ActionListBody,
|
|
5
|
+
ActionListItem,
|
|
6
|
+
ActionListSection,
|
|
7
|
+
ActionListTrigger,
|
|
8
|
+
Button,
|
|
9
|
+
} from '../../src/components';
|
|
10
|
+
import { Link } from '@inertiajs/vue3';
|
|
11
|
+
import api from '../component-meta/ActionList.json';
|
|
12
|
+
import { TrashIcon, PencilIcon, ArrowUpTrayIcon, ArrowDownTrayIcon } from '@heroicons/vue/16/solid';
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
# Action list
|
|
16
|
+
|
|
17
|
+
Action lists render a list of actions or selectable options. This component is usually placed inside a popover container
|
|
18
|
+
to create a dropdown menu or let users select from a list of options.
|
|
19
|
+
|
|
20
|
+
<ComponentApi :api="api" />
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
<ComponentWrapper>
|
|
25
|
+
<ActionList>
|
|
26
|
+
<ActionListTrigger>
|
|
27
|
+
<Button disclosure variant="ghost">Action trigger</Button>
|
|
28
|
+
</ActionListTrigger>
|
|
29
|
+
<ActionListBody>
|
|
30
|
+
<ActionListSection label="File options">
|
|
31
|
+
<ActionListItem :icon="ArrowDownTrayIcon" href="#" as="link">
|
|
32
|
+
Import file
|
|
33
|
+
</ActionListItem>
|
|
34
|
+
<ActionListItem :icon="ArrowUpTrayIcon" active as="button">
|
|
35
|
+
Export file
|
|
36
|
+
</ActionListItem>
|
|
37
|
+
</ActionListSection>
|
|
38
|
+
<ActionListSection label="Bulk actions">
|
|
39
|
+
<ActionListItem :icon="PencilIcon" as="button">
|
|
40
|
+
Edit
|
|
41
|
+
</ActionListItem>
|
|
42
|
+
<ActionListItem :icon="TrashIcon" as="button" variant="destructive">
|
|
43
|
+
Delete
|
|
44
|
+
</ActionListItem>
|
|
45
|
+
</ActionListSection>
|
|
46
|
+
</ActionListBody>
|
|
47
|
+
</ActionList>
|
|
48
|
+
</ComponentWrapper>
|
|
49
|
+
|
|
50
|
+
```js-vue
|
|
51
|
+
<script lang="ts" setup>
|
|
52
|
+
import {
|
|
53
|
+
ActionList,
|
|
54
|
+
ActionListBody,
|
|
55
|
+
ActionListItem,
|
|
56
|
+
ActionListSection,
|
|
57
|
+
ActionListTrigger,
|
|
58
|
+
Button,
|
|
59
|
+
} from '@returnless/focus-ui';
|
|
60
|
+
import { TrashIcon, PencilIcon, ArrowUpTrayIcon, ArrowDownTrayIcon } from '@heroicons/vue/16/solid';
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<template>
|
|
64
|
+
<ActionList>
|
|
65
|
+
<ActionListTrigger>
|
|
66
|
+
<Button disclosure variant="ghost">Action trigger</Button>
|
|
67
|
+
</ActionListTrigger>
|
|
68
|
+
<ActionListBody>
|
|
69
|
+
<ActionListSection label="File options">
|
|
70
|
+
<ActionListItem :icon="ArrowDownTrayIcon" href="#" as="link">
|
|
71
|
+
Import file
|
|
72
|
+
</ActionListItem>
|
|
73
|
+
<ActionListItem :icon="ArrowUpTrayIcon" active as="button">
|
|
74
|
+
Export file
|
|
75
|
+
</ActionListItem>
|
|
76
|
+
</ActionListSection>
|
|
77
|
+
<ActionListSection label="Bulk actions">
|
|
78
|
+
<ActionListItem :icon="PencilIcon" as="button">
|
|
79
|
+
Edit
|
|
80
|
+
</ActionListItem>
|
|
81
|
+
<ActionListItem :icon="TrashIcon" as="button" variant="destructive">
|
|
82
|
+
Delete
|
|
83
|
+
</ActionListItem>
|
|
84
|
+
</ActionListSection>
|
|
85
|
+
</ActionListBody>
|
|
86
|
+
</ActionList>
|
|
87
|
+
</template>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Best practices
|
|
91
|
+
|
|
92
|
+
Action lists should:
|
|
93
|
+
|
|
94
|
+
- Be used for secondary or less important information and actions since they're hidden until users expose them by
|
|
95
|
+
opening a popover
|
|
96
|
+
- Contain actions that are related to each other
|
|
97
|
+
|
|
98
|
+
## Content guidelines
|
|
99
|
+
|
|
100
|
+
### Action lists
|
|
101
|
+
|
|
102
|
+
Each item in an action list should be clear and predictable. Users should be able to anticipate what will happen
|
|
103
|
+
when they click on an action.
|
|
104
|
+
|
|
105
|
+
Each item in an action list should always lead with a strong verb that encourages action. To provide enough context
|
|
106
|
+
use the {verb}+{noun} format unless the action is clear with a single verb.
|
|
107
|
+
|
|
108
|
+
Each item in an action list should be scannable avoiding unnecessary words and articles such as "the", "an", or "a".
|
|
109
|
+
|
|
110
|
+
## Accessibility
|
|
111
|
+
|
|
112
|
+
Items in an action list are organized as list items (`<li>`) in an unordered list (`<ul>`) and are conveyed as a
|
|
113
|
+
group of related elements to assistive technology users. Each item is implemented as a button.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as ActionList } from './ActionList.vue';
|
|
2
|
+
export { default as ActionListBody } from './ActionListBody.vue';
|
|
3
|
+
export { default as ActionListItem } from './ActionListItem.vue';
|
|
4
|
+
export { default as ActionListSection } from './ActionListSection.vue';
|
|
5
|
+
export { default as ActionListTrigger } from './ActionListTrigger.vue';
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { computed, ref } from 'vue';
|
|
3
|
-
import
|
|
2
|
+
import { computed, provide, ref } from 'vue';
|
|
3
|
+
import { AlertVariant } from './types';
|
|
4
|
+
import DismissibleAlertButton from './DismissableAlertButton.vue';
|
|
4
5
|
|
|
5
6
|
const props = withDefaults(defineProps<{
|
|
7
|
+
/** Whether the alert is flush to the borders. */
|
|
8
|
+
flush?: boolean;
|
|
9
|
+
|
|
6
10
|
/** Whether the alert can be dismissed. */
|
|
7
11
|
dismissible?: boolean;
|
|
8
12
|
|
|
9
13
|
/** The variant of the alert. */
|
|
10
|
-
variant?:
|
|
14
|
+
variant?: AlertVariant;
|
|
11
15
|
}>(), {
|
|
16
|
+
flush: false,
|
|
12
17
|
dismissible: true,
|
|
13
18
|
variant: 'default',
|
|
14
19
|
});
|
|
@@ -18,16 +23,23 @@ const emits = defineEmits<{
|
|
|
18
23
|
dismiss: [];
|
|
19
24
|
}>();
|
|
20
25
|
|
|
26
|
+
provide('alertVariant', props.variant);
|
|
27
|
+
|
|
21
28
|
const alertDismissed = ref(false);
|
|
22
29
|
|
|
23
|
-
const classList = computed(() => {
|
|
24
|
-
return
|
|
25
|
-
'
|
|
26
|
-
'text-
|
|
27
|
-
|
|
30
|
+
const classList = computed((): Record<string, boolean>[] => {
|
|
31
|
+
return [
|
|
32
|
+
{ 'bg-white': props.variant === 'default' },
|
|
33
|
+
{ 'bg-red-50 border-red-500/40 text-red-800': props.variant === 'destructive' },
|
|
34
|
+
{ 'bg-yellow-50 border-yellow-500/40 text-yellow-800': props.variant === 'warning' },
|
|
35
|
+
|
|
36
|
+
{ 'border rounded px-4 py-3': !props.flush },
|
|
37
|
+
{ 'border-y px-6 py-3 mt-6': props.flush },
|
|
38
|
+
];
|
|
28
39
|
});
|
|
29
40
|
|
|
30
41
|
const role = computed(() => props.variant === 'destructive' ? 'alert' : 'status');
|
|
42
|
+
const liveRegion = computed(() => props.variant === 'destructive' ? 'assertive' : 'polite');
|
|
31
43
|
|
|
32
44
|
function dismissAlert(): void {
|
|
33
45
|
emits('dismiss');
|
|
@@ -41,12 +53,13 @@ function dismissAlert(): void {
|
|
|
41
53
|
v-if="! alertDismissed"
|
|
42
54
|
:class="classList"
|
|
43
55
|
:role="role"
|
|
44
|
-
|
|
56
|
+
:aria-live="liveRegion"
|
|
57
|
+
class="relative shadow-sm"
|
|
45
58
|
tabindex="0"
|
|
46
59
|
>
|
|
47
60
|
<slot />
|
|
48
61
|
|
|
49
|
-
<
|
|
62
|
+
<DismissibleAlertButton
|
|
50
63
|
v-if="dismissible"
|
|
51
64
|
:variant="variant"
|
|
52
65
|
@dismiss="dismissAlert"
|
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { computed, inject } from 'vue';
|
|
3
|
+
import { AlertVariant } from './types';
|
|
4
|
+
|
|
5
|
+
const alertVariant = inject<AlertVariant>('alertVariant');
|
|
6
|
+
|
|
7
|
+
const classList = computed((): Record<string, boolean> => {
|
|
8
|
+
return {
|
|
9
|
+
'text-red-900/80': alertVariant === 'destructive',
|
|
10
|
+
'text-yellow-900/80': alertVariant === 'warning',
|
|
11
|
+
'text-gray-900/80': alertVariant === 'default',
|
|
12
|
+
};
|
|
13
|
+
});
|
|
2
14
|
</script>
|
|
3
15
|
|
|
4
16
|
<template>
|
|
5
|
-
<div>
|
|
17
|
+
<div :class="classList">
|
|
6
18
|
<slot />
|
|
7
19
|
</div>
|
|
8
20
|
</template>
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { XMarkIcon } from '@heroicons/vue/16/solid';
|
|
3
3
|
import { computed } from 'vue';
|
|
4
|
+
import { AlertVariant } from './types';
|
|
4
5
|
|
|
5
6
|
const props = withDefaults(defineProps<{
|
|
6
7
|
/** The variant of the alert. */
|
|
7
|
-
variant?:
|
|
8
|
+
variant?: AlertVariant;
|
|
8
9
|
}>(), {
|
|
9
10
|
variant: 'default',
|
|
10
11
|
});
|
|
@@ -13,9 +14,10 @@ defineEmits<{
|
|
|
13
14
|
dismiss: [];
|
|
14
15
|
}>();
|
|
15
16
|
|
|
16
|
-
const classList = computed(() => {
|
|
17
|
+
const classList = computed((): Record<string, boolean> => {
|
|
17
18
|
return {
|
|
18
|
-
'hover:bg-red-
|
|
19
|
+
'hover:bg-red-900/20': props.variant === 'destructive',
|
|
20
|
+
'hover:bg-yellow-900/20': props.variant === 'warning',
|
|
19
21
|
'hover:bg-slate-200': props.variant === 'default',
|
|
20
22
|
};
|
|
21
23
|
});
|
|
@@ -23,9 +25,9 @@ const classList = computed(() => {
|
|
|
23
25
|
|
|
24
26
|
<template>
|
|
25
27
|
<button
|
|
28
|
+
:class="classList"
|
|
26
29
|
aria-label="Dismiss notification"
|
|
27
30
|
class="absolute top-2 right-2 flex h-5 w-5 items-center justify-center rounded"
|
|
28
|
-
:class="classList"
|
|
29
31
|
type="button"
|
|
30
32
|
@click="$emit('dismiss')"
|
|
31
33
|
>
|
|
@@ -29,7 +29,7 @@ for users feedback. Default alerts contain lower priority information and should
|
|
|
29
29
|
|
|
30
30
|
```js-vue
|
|
31
31
|
<script lang="ts" setup>
|
|
32
|
-
import { Alert, AlertDescription, AlertTitle } from 'focus-ui';
|
|
32
|
+
import { Alert, AlertDescription, AlertTitle } from '@returnless/focus-ui';
|
|
33
33
|
</script>
|
|
34
34
|
|
|
35
35
|
<template>
|
|
@@ -58,7 +58,7 @@ alert that warns users about a critical system failure. Destructive alerts conta
|
|
|
58
58
|
|
|
59
59
|
```js-vue
|
|
60
60
|
<script lang="ts" setup>
|
|
61
|
-
import { Alert, AlertDescription, AlertTitle } from 'focus-ui';
|
|
61
|
+
import { Alert, AlertDescription, AlertTitle } from '@returnless/focus-ui';
|
|
62
62
|
</script>
|
|
63
63
|
|
|
64
64
|
<template>
|
|
@@ -71,6 +71,35 @@ import { Alert, AlertDescription, AlertTitle } from 'focus-ui';
|
|
|
71
71
|
</template>
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
+
### Warning
|
|
75
|
+
|
|
76
|
+
Use to display information that needs attention or that user need to take action on. Seeing these banners can be
|
|
77
|
+
stressful for user so be cautious about using them.
|
|
78
|
+
|
|
79
|
+
<ComponentWrapper>
|
|
80
|
+
<Alert variant="warning">
|
|
81
|
+
<AlertTitle>Before you can purchase a shipping label, this change needs to be made:</AlertTitle>
|
|
82
|
+
<AlertDescription>
|
|
83
|
+
The name of the city you’re shipping to has characters that aren’t allowed. City name can only include spaces and hyphens.
|
|
84
|
+
</AlertDescription>
|
|
85
|
+
</Alert>
|
|
86
|
+
</ComponentWrapper>
|
|
87
|
+
|
|
88
|
+
```js-vue
|
|
89
|
+
<script lang="ts" setup>
|
|
90
|
+
import { Alert, AlertDescription, AlertTitle } from '@returnless/focus-ui';
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<template>
|
|
94
|
+
<Alert variant="warning">
|
|
95
|
+
<AlertTitle>Before you can purchase a shipping label, this change needs to be made:</AlertTitle>
|
|
96
|
+
<AlertDescription>
|
|
97
|
+
The name of the city you’re shipping to has characters that aren’t allowed. City name can only include spaces and hyphens.
|
|
98
|
+
</AlertDescription>
|
|
99
|
+
</Alert>
|
|
100
|
+
</template>
|
|
101
|
+
```
|
|
102
|
+
|
|
74
103
|
## Best practices
|
|
75
104
|
|
|
76
105
|
Alerts should:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type AlertVariant = 'default' | 'destructive' | 'warning';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { onMounted, onUnmounted, provide } from 'vue';
|
|
3
|
+
import { useUniqueId } from '../../composables';
|
|
3
4
|
|
|
4
5
|
withDefaults(defineProps<{
|
|
5
6
|
/** Whether the alert dialog is open. */
|
|
@@ -30,13 +31,21 @@ onUnmounted((): void => {
|
|
|
30
31
|
document.removeEventListener('keydown', onKeyDown);
|
|
31
32
|
});
|
|
32
33
|
|
|
34
|
+
const alertDialogLabelledBy = useUniqueId('alertDialogLabel');
|
|
35
|
+
const alertDialogDescribedBy = useUniqueId('alertDialogDescription');
|
|
36
|
+
|
|
33
37
|
provide('cancelAlertDialog', cancelAlertDialog);
|
|
38
|
+
provide('alertDialogLabelledBy', alertDialogLabelledBy);
|
|
39
|
+
provide('alertDialogDescribedBy', alertDialogDescribedBy);
|
|
34
40
|
</script>
|
|
35
41
|
|
|
36
42
|
<template>
|
|
37
43
|
<div
|
|
38
44
|
v-if="open"
|
|
39
|
-
|
|
45
|
+
:aria-describedby="alertDialogDescribedBy"
|
|
46
|
+
:aria-labelledby="alertDialogLabelledBy"
|
|
47
|
+
class="fixed top-0 left-0 z-10 h-screen w-screen bg-slate-500/50 px-2 text-sm"
|
|
48
|
+
role="alertdialog"
|
|
40
49
|
>
|
|
41
50
|
<div class="flex min-h-full items-center justify-center">
|
|
42
51
|
<slot />
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { Button } from '../Button';
|
|
2
|
+
import { type ButtonVariant, Button } from '../Button';
|
|
3
|
+
|
|
4
|
+
withDefaults(defineProps<{
|
|
5
|
+
/** The variant of the button. */
|
|
6
|
+
variant?: ButtonVariant;
|
|
7
|
+
}>(), {
|
|
8
|
+
variant: 'primary',
|
|
9
|
+
});
|
|
3
10
|
</script>
|
|
4
11
|
|
|
5
12
|
<template>
|
|
6
|
-
<Button variant="
|
|
13
|
+
<Button :variant="variant">
|
|
7
14
|
<slot />
|
|
8
15
|
</Button>
|
|
9
16
|
</template>
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { TextStyle } from '../TextStyle';
|
|
3
|
+
import { inject } from 'vue';
|
|
4
|
+
|
|
5
|
+
const alertDialogDescribedBy = inject<string>('alertDialogLabelledBy')!;
|
|
3
6
|
</script>
|
|
4
7
|
|
|
5
8
|
<template>
|
|
6
9
|
<p>
|
|
7
|
-
<TextStyle
|
|
10
|
+
<TextStyle
|
|
11
|
+
:id="alertDialogDescribedBy"
|
|
12
|
+
variant="subdued"
|
|
13
|
+
>
|
|
8
14
|
<slot />
|
|
9
15
|
</TextStyle>
|
|
10
16
|
</p>
|