@hawiyah/vue 0.0.0-stage → 0.2.0
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 +73 -0
- package/NOTICE +19 -0
- package/PORTAL.md +70 -0
- package/README.md +388 -2
- package/dist/calendar.d.ts +183 -0
- package/dist/calendar.d.ts.map +1 -0
- package/dist/calendar.js +448 -0
- package/dist/calendar.js.map +1 -0
- package/dist/content-navigation.d.ts +61 -0
- package/dist/content-navigation.d.ts.map +1 -0
- package/dist/content-navigation.js +31 -0
- package/dist/content-navigation.js.map +1 -0
- package/dist/content.d.ts +392 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +305 -0
- package/dist/content.js.map +1 -0
- package/dist/controls.d.ts +657 -0
- package/dist/controls.d.ts.map +1 -0
- package/dist/controls.js +679 -0
- package/dist/controls.js.map +1 -0
- package/dist/display.d.ts +387 -0
- package/dist/display.d.ts.map +1 -0
- package/dist/display.js +293 -0
- package/dist/display.js.map +1 -0
- package/dist/expansion-interactive.d.ts +476 -0
- package/dist/expansion-interactive.d.ts.map +1 -0
- package/dist/expansion-interactive.js +613 -0
- package/dist/expansion-interactive.js.map +1 -0
- package/dist/file-upload-list.d.ts +54 -0
- package/dist/file-upload-list.d.ts.map +1 -0
- package/dist/file-upload-list.js +21 -0
- package/dist/file-upload-list.js.map +1 -0
- package/dist/forms.d.ts +388 -0
- package/dist/forms.d.ts.map +1 -0
- package/dist/forms.js +156 -0
- package/dist/forms.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/interactive.d.ts +240 -0
- package/dist/interactive.d.ts.map +1 -0
- package/dist/interactive.js +341 -0
- package/dist/interactive.js.map +1 -0
- package/dist/layout.d.ts +755 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +101 -0
- package/dist/layout.js.map +1 -0
- package/dist/mobile-top-bar.d.ts +47 -0
- package/dist/mobile-top-bar.d.ts.map +1 -0
- package/dist/mobile-top-bar.js +18 -0
- package/dist/mobile-top-bar.js.map +1 -0
- package/dist/native-attributes.d.ts +38 -0
- package/dist/native-attributes.d.ts.map +1 -0
- package/dist/native-attributes.js +27 -0
- package/dist/native-attributes.js.map +1 -0
- package/dist/navigation-drawer.d.ts +87 -0
- package/dist/navigation-drawer.d.ts.map +1 -0
- package/dist/navigation-drawer.js +56 -0
- package/dist/navigation-drawer.js.map +1 -0
- package/dist/patterns.d.ts +455 -0
- package/dist/patterns.d.ts.map +1 -0
- package/dist/patterns.js +355 -0
- package/dist/patterns.js.map +1 -0
- package/dist/portal.d.ts +174 -0
- package/dist/portal.d.ts.map +1 -0
- package/dist/portal.js +36 -0
- package/dist/portal.js.map +1 -0
- package/dist/search-field.d.ts +87 -0
- package/dist/search-field.d.ts.map +1 -0
- package/dist/search-field.js +123 -0
- package/dist/search-field.js.map +1 -0
- package/dist/shared.d.ts +46 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +40 -0
- package/dist/shared.js.map +1 -0
- package/dist/site-verification.d.ts +63 -0
- package/dist/site-verification.d.ts.map +1 -0
- package/dist/site-verification.js +34 -0
- package/dist/site-verification.js.map +1 -0
- package/package.json +53 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export { Button, Checkbox, Radio, Switch, TextField, Textarea, Select, FileUpload, IconButton, PasswordField, SearchField, NumberField, Slider, PinInput, TagInput, MultiSelect, FileDropzone, Combobox, DatePicker, NavigationDrawer } from './native-attributes.js';
|
|
2
|
+
export { Field } from './forms.js';
|
|
3
|
+
export { Tabs, Dialog, Tooltip } from './interactive.js';
|
|
4
|
+
export type { TabItem } from './interactive.js';
|
|
5
|
+
export { Accordion, Card, Badge, Alert, Table, Pagination, Breadcrumb, Progress, Skeleton, Spinner, Avatar, Divider, Stepper, EmptyState } from './display.js';
|
|
6
|
+
export type { AccordionItem, TableColumn, BreadcrumbItem, StepItem, Tone } from './display.js';
|
|
7
|
+
export type { FieldDecoration, RenderContent } from './shared.js';
|
|
8
|
+
export { InputGroup, RangeSlider, Rating, RatingDisplay } from './controls.js';
|
|
9
|
+
export { Calendar } from './calendar.js';
|
|
10
|
+
export { ToggleGroup, Popover, Menu, Drawer, ToastRegion, Collapsible, TreeView, Carousel } from './expansion-interactive.js';
|
|
11
|
+
export type { MenuItem, ToastMessage, TreeNode, CarouselSlide } from './expansion-interactive.js';
|
|
12
|
+
export { Link, ButtonGroup, Chip, DescriptionList, Stat, Timeline, Meter, AvatarGroup, DataTable } from './content.js';
|
|
13
|
+
export type { DescriptionItem, TimelineItem, AvatarItem, DataColumn } from './content.js';
|
|
14
|
+
export { ServiceCard, ServiceDetails, PortalHeader, PortalFooter, Feedback, CookieConsent, NotificationList } from './patterns.js';
|
|
15
|
+
export type { PortalLink, PortalFooterLink, PortalFooterGroup, FeedbackValue, NotificationItem } from './patterns.js';
|
|
16
|
+
export { Container, Stack, Inline, Grid, Columns, Sidebar, Center, Spacer, AspectRatio, Section, AppShell, PageHeader } from './layout.js';
|
|
17
|
+
export { SecondaryNav, PortalLayout } from './portal.js';
|
|
18
|
+
export type { LayoutProps, Responsive } from '@hawiyah/core';
|
|
19
|
+
export type { SecondaryNavItem } from './portal.js';
|
|
20
|
+
export { MobileTopBar } from './mobile-top-bar.js';
|
|
21
|
+
export type { NavigationDrawerItem } from './navigation-drawer.js';
|
|
22
|
+
export { SiteVerification } from './site-verification.js';
|
|
23
|
+
export { ContentNavigation } from './content-navigation.js';
|
|
24
|
+
export type { ContentNavigationItem } from './content-navigation.js';
|
|
25
|
+
export { FileUploadList } from './file-upload-list.js';
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACtQ,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACzD,YAAY,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/J,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAC/F,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC9H,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAClG,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACvH,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACnI,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtH,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC3I,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE7D,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,YAAY,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAErE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { Button, Checkbox, Radio, Switch, TextField, Textarea, Select, FileUpload, IconButton, PasswordField, SearchField, NumberField, Slider, PinInput, TagInput, MultiSelect, FileDropzone, Combobox, DatePicker, NavigationDrawer } from './native-attributes.js';
|
|
2
|
+
export { Field } from './forms.js';
|
|
3
|
+
export { Tabs, Dialog, Tooltip } from './interactive.js';
|
|
4
|
+
export { Accordion, Card, Badge, Alert, Table, Pagination, Breadcrumb, Progress, Skeleton, Spinner, Avatar, Divider, Stepper, EmptyState } from './display.js';
|
|
5
|
+
export { InputGroup, RangeSlider, Rating, RatingDisplay } from './controls.js';
|
|
6
|
+
export { Calendar } from './calendar.js';
|
|
7
|
+
export { ToggleGroup, Popover, Menu, Drawer, ToastRegion, Collapsible, TreeView, Carousel } from './expansion-interactive.js';
|
|
8
|
+
export { Link, ButtonGroup, Chip, DescriptionList, Stat, Timeline, Meter, AvatarGroup, DataTable } from './content.js';
|
|
9
|
+
export { ServiceCard, ServiceDetails, PortalHeader, PortalFooter, Feedback, CookieConsent, NotificationList } from './patterns.js';
|
|
10
|
+
export { Container, Stack, Inline, Grid, Columns, Sidebar, Center, Spacer, AspectRatio, Section, AppShell, PageHeader } from './layout.js';
|
|
11
|
+
export { SecondaryNav, PortalLayout } from './portal.js';
|
|
12
|
+
export { MobileTopBar } from './mobile-top-bar.js';
|
|
13
|
+
export { SiteVerification } from './site-verification.js';
|
|
14
|
+
export { ContentNavigation } from './content-navigation.js';
|
|
15
|
+
export { FileUploadList } from './file-upload-list.js';
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACtQ,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/J,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAE9H,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEvH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEnI,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC3I,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAInD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import type { PropType, VNodeChild } from 'vue';
|
|
2
|
+
import type { Option, Orientation } from '@hawiyah/core';
|
|
3
|
+
export interface TabItem {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
content?: VNodeChild;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare const Tabs: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
10
|
+
items: {
|
|
11
|
+
type: PropType<readonly TabItem[]>;
|
|
12
|
+
required: true;
|
|
13
|
+
};
|
|
14
|
+
label: {
|
|
15
|
+
type: StringConstructor;
|
|
16
|
+
required: true;
|
|
17
|
+
};
|
|
18
|
+
modelValue: StringConstructor;
|
|
19
|
+
defaultValue: StringConstructor;
|
|
20
|
+
orientation: {
|
|
21
|
+
type: PropType<Orientation>;
|
|
22
|
+
default: string;
|
|
23
|
+
};
|
|
24
|
+
activationMode: {
|
|
25
|
+
type: PropType<"automatic" | "manual">;
|
|
26
|
+
default: string;
|
|
27
|
+
};
|
|
28
|
+
overflow: {
|
|
29
|
+
type: PropType<"menu" | "scroll">;
|
|
30
|
+
default: string;
|
|
31
|
+
};
|
|
32
|
+
overflowLabel: {
|
|
33
|
+
type: StringConstructor;
|
|
34
|
+
default: string;
|
|
35
|
+
};
|
|
36
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
37
|
+
[key: string]: any;
|
|
38
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
39
|
+
'update:modelValue': (_value: string) => true;
|
|
40
|
+
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
41
|
+
items: {
|
|
42
|
+
type: PropType<readonly TabItem[]>;
|
|
43
|
+
required: true;
|
|
44
|
+
};
|
|
45
|
+
label: {
|
|
46
|
+
type: StringConstructor;
|
|
47
|
+
required: true;
|
|
48
|
+
};
|
|
49
|
+
modelValue: StringConstructor;
|
|
50
|
+
defaultValue: StringConstructor;
|
|
51
|
+
orientation: {
|
|
52
|
+
type: PropType<Orientation>;
|
|
53
|
+
default: string;
|
|
54
|
+
};
|
|
55
|
+
activationMode: {
|
|
56
|
+
type: PropType<"automatic" | "manual">;
|
|
57
|
+
default: string;
|
|
58
|
+
};
|
|
59
|
+
overflow: {
|
|
60
|
+
type: PropType<"menu" | "scroll">;
|
|
61
|
+
default: string;
|
|
62
|
+
};
|
|
63
|
+
overflowLabel: {
|
|
64
|
+
type: StringConstructor;
|
|
65
|
+
default: string;
|
|
66
|
+
};
|
|
67
|
+
}>> & Readonly<{
|
|
68
|
+
"onUpdate:modelValue"?: ((_value: string) => any) | undefined;
|
|
69
|
+
}>, {
|
|
70
|
+
orientation: Orientation;
|
|
71
|
+
activationMode: "automatic" | "manual";
|
|
72
|
+
overflow: "scroll" | "menu";
|
|
73
|
+
overflowLabel: string;
|
|
74
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
75
|
+
export declare const Dialog: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
76
|
+
open: {
|
|
77
|
+
type: BooleanConstructor;
|
|
78
|
+
default: undefined;
|
|
79
|
+
};
|
|
80
|
+
defaultOpen: BooleanConstructor;
|
|
81
|
+
title: {
|
|
82
|
+
type: StringConstructor;
|
|
83
|
+
required: true;
|
|
84
|
+
};
|
|
85
|
+
description: StringConstructor;
|
|
86
|
+
closeLabel: {
|
|
87
|
+
type: StringConstructor;
|
|
88
|
+
default: string;
|
|
89
|
+
};
|
|
90
|
+
closeOnBackdrop: {
|
|
91
|
+
type: BooleanConstructor;
|
|
92
|
+
default: boolean;
|
|
93
|
+
};
|
|
94
|
+
}>, () => (import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
95
|
+
[key: string]: any;
|
|
96
|
+
}> | import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
97
|
+
[key: string]: any;
|
|
98
|
+
}>[] | undefined)[], {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
99
|
+
'update:open': (_open: boolean) => true;
|
|
100
|
+
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
101
|
+
open: {
|
|
102
|
+
type: BooleanConstructor;
|
|
103
|
+
default: undefined;
|
|
104
|
+
};
|
|
105
|
+
defaultOpen: BooleanConstructor;
|
|
106
|
+
title: {
|
|
107
|
+
type: StringConstructor;
|
|
108
|
+
required: true;
|
|
109
|
+
};
|
|
110
|
+
description: StringConstructor;
|
|
111
|
+
closeLabel: {
|
|
112
|
+
type: StringConstructor;
|
|
113
|
+
default: string;
|
|
114
|
+
};
|
|
115
|
+
closeOnBackdrop: {
|
|
116
|
+
type: BooleanConstructor;
|
|
117
|
+
default: boolean;
|
|
118
|
+
};
|
|
119
|
+
}>> & Readonly<{
|
|
120
|
+
"onUpdate:open"?: ((_open: boolean) => any) | undefined;
|
|
121
|
+
}>, {
|
|
122
|
+
defaultOpen: boolean;
|
|
123
|
+
open: boolean;
|
|
124
|
+
closeLabel: string;
|
|
125
|
+
closeOnBackdrop: boolean;
|
|
126
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
127
|
+
export declare const Combobox: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
128
|
+
options: {
|
|
129
|
+
type: PropType<readonly Option[]>;
|
|
130
|
+
required: true;
|
|
131
|
+
};
|
|
132
|
+
modelValue: StringConstructor;
|
|
133
|
+
defaultValue: {
|
|
134
|
+
type: StringConstructor;
|
|
135
|
+
default: string;
|
|
136
|
+
};
|
|
137
|
+
disabled: BooleanConstructor;
|
|
138
|
+
readonly: BooleanConstructor;
|
|
139
|
+
emptyMessage: {
|
|
140
|
+
type: StringConstructor;
|
|
141
|
+
default: string;
|
|
142
|
+
};
|
|
143
|
+
resultsMessage: {
|
|
144
|
+
type: PropType<(count: number) => string>;
|
|
145
|
+
default: (count: number) => string;
|
|
146
|
+
};
|
|
147
|
+
requiredMessage: {
|
|
148
|
+
type: StringConstructor;
|
|
149
|
+
default: string;
|
|
150
|
+
};
|
|
151
|
+
label: StringConstructor;
|
|
152
|
+
hint: StringConstructor;
|
|
153
|
+
error: StringConstructor;
|
|
154
|
+
required: {
|
|
155
|
+
readonly type: BooleanConstructor;
|
|
156
|
+
readonly default: undefined;
|
|
157
|
+
};
|
|
158
|
+
}>, () => string | number | boolean | void | import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
159
|
+
[key: string]: any;
|
|
160
|
+
}> | import("vue").VNodeArrayChildren | null, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
161
|
+
'update:modelValue': (_value: string) => true;
|
|
162
|
+
'update:open': (_open: boolean) => true;
|
|
163
|
+
'update:query': (_query: string) => true;
|
|
164
|
+
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
165
|
+
options: {
|
|
166
|
+
type: PropType<readonly Option[]>;
|
|
167
|
+
required: true;
|
|
168
|
+
};
|
|
169
|
+
modelValue: StringConstructor;
|
|
170
|
+
defaultValue: {
|
|
171
|
+
type: StringConstructor;
|
|
172
|
+
default: string;
|
|
173
|
+
};
|
|
174
|
+
disabled: BooleanConstructor;
|
|
175
|
+
readonly: BooleanConstructor;
|
|
176
|
+
emptyMessage: {
|
|
177
|
+
type: StringConstructor;
|
|
178
|
+
default: string;
|
|
179
|
+
};
|
|
180
|
+
resultsMessage: {
|
|
181
|
+
type: PropType<(count: number) => string>;
|
|
182
|
+
default: (count: number) => string;
|
|
183
|
+
};
|
|
184
|
+
requiredMessage: {
|
|
185
|
+
type: StringConstructor;
|
|
186
|
+
default: string;
|
|
187
|
+
};
|
|
188
|
+
label: StringConstructor;
|
|
189
|
+
hint: StringConstructor;
|
|
190
|
+
error: StringConstructor;
|
|
191
|
+
required: {
|
|
192
|
+
readonly type: BooleanConstructor;
|
|
193
|
+
readonly default: undefined;
|
|
194
|
+
};
|
|
195
|
+
}>> & Readonly<{
|
|
196
|
+
"onUpdate:modelValue"?: ((_value: string) => any) | undefined;
|
|
197
|
+
"onUpdate:open"?: ((_open: boolean) => any) | undefined;
|
|
198
|
+
"onUpdate:query"?: ((_query: string) => any) | undefined;
|
|
199
|
+
}>, {
|
|
200
|
+
disabled: boolean;
|
|
201
|
+
required: boolean;
|
|
202
|
+
defaultValue: string;
|
|
203
|
+
readonly: boolean;
|
|
204
|
+
emptyMessage: string;
|
|
205
|
+
resultsMessage: (count: number) => string;
|
|
206
|
+
requiredMessage: string;
|
|
207
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
208
|
+
export declare const Tooltip: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
209
|
+
content: {
|
|
210
|
+
type: StringConstructor;
|
|
211
|
+
required: true;
|
|
212
|
+
};
|
|
213
|
+
placement: {
|
|
214
|
+
type: PropType<"top" | "bottom" | "start" | "end">;
|
|
215
|
+
default: string;
|
|
216
|
+
};
|
|
217
|
+
align: {
|
|
218
|
+
type: PropType<"start" | "center" | "end">;
|
|
219
|
+
default: string;
|
|
220
|
+
};
|
|
221
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
222
|
+
[key: string]: any;
|
|
223
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
224
|
+
content: {
|
|
225
|
+
type: StringConstructor;
|
|
226
|
+
required: true;
|
|
227
|
+
};
|
|
228
|
+
placement: {
|
|
229
|
+
type: PropType<"top" | "bottom" | "start" | "end">;
|
|
230
|
+
default: string;
|
|
231
|
+
};
|
|
232
|
+
align: {
|
|
233
|
+
type: PropType<"start" | "center" | "end">;
|
|
234
|
+
default: string;
|
|
235
|
+
};
|
|
236
|
+
}>> & Readonly<{}>, {
|
|
237
|
+
placement: "top" | "bottom" | "start" | "end";
|
|
238
|
+
align: "start" | "end" | "center";
|
|
239
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
240
|
+
//# sourceMappingURL=interactive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAEhD,OAAO,KAAK,EAAiB,MAAM,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAIxE,MAAM,WAAW,OAAO;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE;AACnG,eAAO,MAAM,IAAI;;cAEkB,QAAQ,CAAC,SAAS,OAAO,EAAE,CAAC;;;;;;;;;;cAC5B,QAAQ,CAAC,WAAW,CAAC;;;;cAA6D,QAAQ,CAAC,WAAW,GAAG,QAAQ,CAAC;;;;cACtH,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC;;;;;;;;;;kCACjB,MAAM;;;cAHZ,QAAQ,CAAC,SAAS,OAAO,EAAE,CAAC;;;;;;;;;;cAC5B,QAAQ,CAAC,WAAW,CAAC;;;;cAA6D,QAAQ,CAAC,WAAW,GAAG,QAAQ,CAAC;;;;cACtH,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC;;;;;;;;;;;;;;4EA8DxD,CAAC;AAEH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;2BAGe,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;4EA0CvC,CAAC;AAEH,eAAO,MAAM,QAAQ;;cAEoC,QAAQ,CAAC,SAAS,MAAM,EAAE,CAAC;;;;;;;;;;;;;;;cACiB,QAAQ,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;yBAAmB,MAAM;;;;;;;;;;;;;;;;kCACxH,MAAM;2BAAkC,OAAO;6BAAoC,MAAM;;;cAFzE,QAAQ,CAAC,SAAS,MAAM,EAAE,CAAC;;;;;;;;;;;;;;;cACiB,QAAQ,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;yBAAmB,MAAM;;;;;;;;;;;;;;;;;;;;;;;4BAA3C,MAAM,KAAK,MAAM;;4EAqFrI,CAAC;AAEH,eAAO,MAAM,OAAO;;;;;;cACsG,QAAQ,CAAC,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;;;;cAA2C,QAAQ,CAAC,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;;;;;;;;;;;cAA3H,QAAQ,CAAC,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;;;;cAA2C,QAAQ,CAAC,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;;;;;;4EA6CnP,CAAC"}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { cloneVNode, computed, defineComponent, h, isVNode, mergeProps, nextTick, onBeforeUnmount, onMounted, ref, useId, watch, watchEffect } from 'vue';
|
|
2
|
+
import { createComboboxState, getComboboxOptions, getDirection, getNextEnabledIndex, isDisabled, observeTabOverflow, restoreFocus, transitionCombobox } from '@hawiyah/core';
|
|
3
|
+
import { Button, decorate } from './forms.js';
|
|
4
|
+
import { decorationProps, joinIds, useField, useFormReset, useValue } from './shared.js';
|
|
5
|
+
export const Tabs = defineComponent({
|
|
6
|
+
name: 'HwTabs', inheritAttrs: false,
|
|
7
|
+
props: { items: { type: Array, required: true }, label: { type: String, required: true }, modelValue: String, defaultValue: String,
|
|
8
|
+
orientation: { type: String, default: 'horizontal' }, activationMode: { type: String, default: 'automatic' },
|
|
9
|
+
overflow: { type: String, default: 'menu' }, overflowLabel: { type: String, default: 'المزيد من التبويبات' } },
|
|
10
|
+
emits: { 'update:modelValue': (_value) => true },
|
|
11
|
+
setup(props, { attrs, slots, emit }) {
|
|
12
|
+
const id = `hw-${useId()}`;
|
|
13
|
+
const model = useValue(() => props.modelValue, props.defaultValue ?? props.items.find(item => !item.disabled)?.value ?? '', value => emit('update:modelValue', value));
|
|
14
|
+
const focused = ref();
|
|
15
|
+
const active = computed(() => props.items.find(item => item.value === model.value.value && !item.disabled)?.value ?? props.items.find(item => !item.disabled)?.value);
|
|
16
|
+
const buttons = new Map();
|
|
17
|
+
const bar = ref();
|
|
18
|
+
const disclosure = ref();
|
|
19
|
+
const hidden = ref([]);
|
|
20
|
+
let observer;
|
|
21
|
+
let alive = true;
|
|
22
|
+
const visible = computed(() => props.items.filter((item, index) => !hidden.value.includes(index) && !item.disabled));
|
|
23
|
+
const focusValue = computed(() => visible.value.find(item => item.value === focused.value)?.value ?? visible.value.find(item => item.value === active.value)?.value ?? visible.value[0]?.value);
|
|
24
|
+
const close = () => { if (disclosure.value)
|
|
25
|
+
disclosure.value.open = false; };
|
|
26
|
+
const outside = (event) => { if (!bar.value?.contains(event.target))
|
|
27
|
+
close(); };
|
|
28
|
+
onMounted(() => {
|
|
29
|
+
const node = bar.value;
|
|
30
|
+
observer = observeTabOverflow({ container: node, tabs: () => props.items.map(item => buttons.get(item.value)).filter(Boolean), enabled: () => props.overflow === 'menu' && props.orientation === 'horizontal', onChange: next => {
|
|
31
|
+
const focusedElement = node.ownerDocument.activeElement;
|
|
32
|
+
const menuValue = focusedElement?.dataset.hwOverflowValue;
|
|
33
|
+
const itemIndex = props.items.findIndex(item => item.value === menuValue);
|
|
34
|
+
const toMenu = menuValue !== undefined && itemIndex >= 0 && next.includes(itemIndex);
|
|
35
|
+
const toOriginal = menuValue !== undefined && itemIndex >= 0 && !toMenu;
|
|
36
|
+
const toSummary = next.some(index => buttons.get(props.items[index]?.value ?? '') === focusedElement) || (!toMenu && !toOriginal && !!next.length && !!disclosure.value?.contains(focusedElement));
|
|
37
|
+
const toTab = !next.length && disclosure.value?.contains(focusedElement);
|
|
38
|
+
if (!toMenu)
|
|
39
|
+
close();
|
|
40
|
+
hidden.value = next;
|
|
41
|
+
void nextTick(() => { if (!alive)
|
|
42
|
+
return; if (toMenu)
|
|
43
|
+
[...(disclosure.value?.querySelectorAll('[data-hw-overflow-value]') ?? [])].find(button => button.dataset.hwOverflowValue === menuValue)?.focus();
|
|
44
|
+
else if (toOriginal)
|
|
45
|
+
buttons.get(menuValue)?.focus();
|
|
46
|
+
else if (toSummary)
|
|
47
|
+
disclosure.value?.querySelector('summary')?.focus();
|
|
48
|
+
else if (toTab && focusValue.value)
|
|
49
|
+
buttons.get(focusValue.value)?.focus(); });
|
|
50
|
+
} });
|
|
51
|
+
node.ownerDocument.addEventListener('click', outside);
|
|
52
|
+
});
|
|
53
|
+
watch(() => [props.items, props.overflow, props.orientation], () => { observer?.refresh(); const focusedElement = bar.value?.ownerDocument.activeElement; if (focusedElement?.getAttribute('data-hw-overflow-hidden') === 'true' && bar.value?.contains(focusedElement))
|
|
54
|
+
disclosure.value?.querySelector('summary')?.focus(); }, { deep: true, flush: 'post' });
|
|
55
|
+
watch(active, close);
|
|
56
|
+
onBeforeUnmount(() => { alive = false; observer?.destroy(); bar.value?.ownerDocument.removeEventListener('click', outside); });
|
|
57
|
+
return () => h('div', mergeProps(attrs, { class: 'hw-tabs' }), [
|
|
58
|
+
h('div', { class: 'hw-tab-bar', ref: bar, 'data-hw-overflow': props.overflow, 'data-orientation': props.orientation }, [
|
|
59
|
+
h('div', { class: 'hw-tab-list', 'data-hw-overflow': props.overflow, role: 'tablist', 'aria-label': props.label, 'aria-orientation': props.orientation, 'aria-hidden': hidden.value.length === props.items.length || undefined }, props.items.map((item, index) => h('button', {
|
|
60
|
+
key: item.value, ref: (element) => { if (element)
|
|
61
|
+
buttons.set(item.value, element);
|
|
62
|
+
else
|
|
63
|
+
buttons.delete(item.value); },
|
|
64
|
+
class: 'hw-tab', type: 'button', role: 'tab', id: `${id}-tab-${index}`, 'aria-controls': `${id}-panel-${index}`, 'aria-selected': active.value === item.value,
|
|
65
|
+
'data-hw-overflow-hidden': hidden.value.includes(index) ? 'true' : undefined, 'aria-hidden': hidden.value.includes(index) || undefined,
|
|
66
|
+
tabindex: !hidden.value.includes(index) && focusValue.value === item.value ? 0 : -1, disabled: item.disabled,
|
|
67
|
+
onFocus: () => { focused.value = item.value; }, onClick: () => { if (!item.disabled)
|
|
68
|
+
model.set(item.value); },
|
|
69
|
+
onKeydown: (event) => {
|
|
70
|
+
if (event.altKey || event.ctrlKey || event.metaKey || event.isComposing)
|
|
71
|
+
return;
|
|
72
|
+
const keys = props.orientation === 'vertical' ? ['ArrowDown', 'ArrowUp', 'Home', 'End'] : ['ArrowLeft', 'ArrowRight', 'Home', 'End'];
|
|
73
|
+
if (!keys.includes(event.key))
|
|
74
|
+
return;
|
|
75
|
+
event.preventDefault();
|
|
76
|
+
const next = props.items[getNextEnabledIndex(index, event.key, props.items.map((candidate, i) => ({ disabled: candidate.disabled || hidden.value.includes(i) })), getDirection(event.currentTarget), props.orientation)];
|
|
77
|
+
if (!next)
|
|
78
|
+
return;
|
|
79
|
+
focused.value = next.value;
|
|
80
|
+
buttons.get(next.value)?.focus();
|
|
81
|
+
if (props.activationMode === 'automatic')
|
|
82
|
+
model.set(next.value);
|
|
83
|
+
},
|
|
84
|
+
}, slots[`tab:${item.value}`]?.({ item }) ?? item.label))),
|
|
85
|
+
h('details', { class: 'hw-tabs-overflow', ref: disclosure, hidden: !hidden.value.length, onKeydown: (event) => { if (event.key === 'Escape' && disclosure.value?.open) {
|
|
86
|
+
event.preventDefault();
|
|
87
|
+
close();
|
|
88
|
+
disclosure.value.querySelector('summary')?.focus();
|
|
89
|
+
} } }, [
|
|
90
|
+
h('summary', { class: 'hw-tab-overflow-trigger', 'aria-label': props.overflowLabel, 'data-active': hidden.value.some(index => props.items[index]?.value === active.value) ? 'true' : undefined }, '…'),
|
|
91
|
+
h('div', { class: 'hw-tab-overflow-menu' }, hidden.value.map(index => { const item = props.items[index]; return item && h('button', { key: item.value, type: 'button', class: 'hw-tab-overflow-item', 'data-hw-overflow-value': item.value, disabled: item.disabled, 'aria-pressed': item.value === active.value, onClick: () => { if (item.disabled)
|
|
92
|
+
return; model.set(item.value); close(); disclosure.value?.querySelector('summary')?.focus(); } }, slots[`tab:${item.value}`]?.({ item }) ?? item.label); })),
|
|
93
|
+
]),
|
|
94
|
+
]),
|
|
95
|
+
...props.items.map((item, index) => h('section', { key: item.value, class: 'hw-tab-panel', id: `${id}-panel-${index}`, role: 'tabpanel', 'aria-labelledby': `${id}-tab-${index}`, tabindex: 0, hidden: active.value !== item.value }, [slots[item.value]?.() ?? item.content])),
|
|
96
|
+
]);
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
export const Dialog = defineComponent({
|
|
100
|
+
name: 'HwDialog', inheritAttrs: false,
|
|
101
|
+
props: { open: { type: Boolean, default: undefined }, defaultOpen: Boolean, title: { type: String, required: true }, description: String, closeLabel: { type: String, default: 'Close' }, closeOnBackdrop: { type: Boolean, default: true } },
|
|
102
|
+
emits: { 'update:open': (_open) => true },
|
|
103
|
+
setup(props, { attrs, slots, emit, expose }) {
|
|
104
|
+
const id = `hw-${useId()}`;
|
|
105
|
+
const element = ref();
|
|
106
|
+
const model = useValue(() => props.open, props.defaultOpen, value => emit('update:open', value));
|
|
107
|
+
let previousFocus = null;
|
|
108
|
+
let backdropStarted = false;
|
|
109
|
+
const close = () => { backdropStarted = false; model.set(false); };
|
|
110
|
+
const show = () => { backdropStarted = false; model.set(true); };
|
|
111
|
+
watchEffect(() => {
|
|
112
|
+
const dialog = element.value;
|
|
113
|
+
if (!dialog)
|
|
114
|
+
return;
|
|
115
|
+
if (model.value.value && !dialog.open) {
|
|
116
|
+
backdropStarted = false;
|
|
117
|
+
previousFocus = dialog.ownerDocument.activeElement;
|
|
118
|
+
dialog.showModal();
|
|
119
|
+
}
|
|
120
|
+
else if (!model.value.value && dialog.open) {
|
|
121
|
+
backdropStarted = false;
|
|
122
|
+
dialog.close();
|
|
123
|
+
restoreFocus(previousFocus);
|
|
124
|
+
}
|
|
125
|
+
}, { flush: 'post' });
|
|
126
|
+
onBeforeUnmount(() => { if (element.value?.open) {
|
|
127
|
+
element.value.close();
|
|
128
|
+
restoreFocus(previousFocus);
|
|
129
|
+
} });
|
|
130
|
+
expose({ element, show, close });
|
|
131
|
+
return () => [slots.trigger?.({ open: show }), h('dialog', mergeProps(attrs, {
|
|
132
|
+
ref: element, class: 'hw-dialog', 'aria-labelledby': attrs['aria-labelledby'] ?? `${id}-title`, 'aria-describedby': attrs['aria-describedby'] ?? (props.description ? `${id}-description` : undefined),
|
|
133
|
+
onCancel: (event) => { backdropStarted = false; if (!event.defaultPrevented) {
|
|
134
|
+
event.preventDefault();
|
|
135
|
+
close();
|
|
136
|
+
} },
|
|
137
|
+
onClose: () => { backdropStarted = false; if (model.value.value)
|
|
138
|
+
close(); restoreFocus(previousFocus); },
|
|
139
|
+
onPointerdown: (event) => {
|
|
140
|
+
const bounds = element.value.getBoundingClientRect();
|
|
141
|
+
backdropStarted = !event.defaultPrevented && event.button === 0 && event.target === event.currentTarget &&
|
|
142
|
+
(event.clientX < bounds.left || event.clientX > bounds.right || event.clientY < bounds.top || event.clientY > bounds.bottom);
|
|
143
|
+
},
|
|
144
|
+
onPointercancel: () => { backdropStarted = false; },
|
|
145
|
+
onClick: (event) => {
|
|
146
|
+
const started = backdropStarted;
|
|
147
|
+
backdropStarted = false;
|
|
148
|
+
if (event.defaultPrevented || !props.closeOnBackdrop || !started || event.target !== event.currentTarget)
|
|
149
|
+
return;
|
|
150
|
+
const bounds = element.value.getBoundingClientRect();
|
|
151
|
+
if (event.clientX < bounds.left || event.clientX > bounds.right || event.clientY < bounds.top || event.clientY > bounds.bottom)
|
|
152
|
+
close();
|
|
153
|
+
},
|
|
154
|
+
}), [
|
|
155
|
+
h('header', { class: 'hw-dialog-header' }, [h('h2', { id: `${id}-title` }, props.title), h(Button, { variant: 'ghost', 'aria-label': props.closeLabel, onClick: close }, () => '×')]),
|
|
156
|
+
h('div', { class: 'hw-dialog-body' }, [props.description && h('p', { id: `${id}-description` }, props.description), slots.default?.({ close })]),
|
|
157
|
+
slots.footer && h('footer', { class: 'hw-dialog-footer' }, slots.footer({ close })),
|
|
158
|
+
])];
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
export const Combobox = defineComponent({
|
|
162
|
+
name: 'HwCombobox', inheritAttrs: false,
|
|
163
|
+
props: { ...decorationProps, options: { type: Array, required: true }, modelValue: String, defaultValue: { type: String, default: '' }, disabled: Boolean, readonly: Boolean,
|
|
164
|
+
emptyMessage: { type: String, default: 'No options found' }, resultsMessage: { type: Function, default: (count) => `${count} results available` }, requiredMessage: { type: String, default: 'Choose an option from the list.' } },
|
|
165
|
+
emits: { 'update:modelValue': (_value) => true, 'update:open': (_open) => true, 'update:query': (_query) => true },
|
|
166
|
+
setup(props, { attrs, emit, expose }) {
|
|
167
|
+
const field = useField(props, attrs);
|
|
168
|
+
const element = ref();
|
|
169
|
+
const root = ref();
|
|
170
|
+
const state = ref(createComboboxState(props.options, props.modelValue ?? props.defaultValue));
|
|
171
|
+
const ancestorDisabled = ref(false);
|
|
172
|
+
const blocked = () => props.disabled || props.readonly || !!(element.value && isDisabled(element.value));
|
|
173
|
+
let disabledObserver;
|
|
174
|
+
onMounted(() => {
|
|
175
|
+
const input = element.value;
|
|
176
|
+
if (!input)
|
|
177
|
+
return;
|
|
178
|
+
const refresh = () => { ancestorDisabled.value = isDisabled(input); };
|
|
179
|
+
const Observer = input.ownerDocument.defaultView?.MutationObserver;
|
|
180
|
+
if (Observer)
|
|
181
|
+
disabledObserver = new Observer(refresh);
|
|
182
|
+
for (let ancestor = input.parentElement; ancestor; ancestor = ancestor.parentElement) {
|
|
183
|
+
if (ancestor.localName === 'fieldset')
|
|
184
|
+
disabledObserver?.observe(ancestor, { attributes: true, attributeFilter: ['disabled'] });
|
|
185
|
+
}
|
|
186
|
+
refresh();
|
|
187
|
+
});
|
|
188
|
+
onBeforeUnmount(() => disabledObserver?.disconnect());
|
|
189
|
+
watch(() => props.disabled || props.readonly || ancestorDisabled.value, unavailable => {
|
|
190
|
+
if (unavailable)
|
|
191
|
+
state.value = { ...state.value, open: false, activeIndex: -1 };
|
|
192
|
+
});
|
|
193
|
+
const effective = computed(() => ({ ...state.value, value: props.modelValue ?? state.value.value,
|
|
194
|
+
query: props.modelValue !== undefined && props.modelValue !== state.value.value ? createComboboxState(props.options, props.modelValue).query : state.value.query,
|
|
195
|
+
open: !props.disabled && !ancestorDisabled.value && !props.readonly && state.value.open }));
|
|
196
|
+
const results = computed(() => getComboboxOptions(effective.value, props.options));
|
|
197
|
+
let lastEmitted;
|
|
198
|
+
function dispatch(event) {
|
|
199
|
+
if (blocked() && event.type !== 'close' && event.type !== 'reset')
|
|
200
|
+
return;
|
|
201
|
+
const previous = effective.value;
|
|
202
|
+
const next = transitionCombobox(previous, event, props.options);
|
|
203
|
+
state.value = next;
|
|
204
|
+
if (next.value !== previous.value) {
|
|
205
|
+
lastEmitted = next.value;
|
|
206
|
+
emit('update:modelValue', next.value);
|
|
207
|
+
}
|
|
208
|
+
if (next.open !== previous.open)
|
|
209
|
+
emit('update:open', next.open);
|
|
210
|
+
}
|
|
211
|
+
watch(() => props.modelValue, value => {
|
|
212
|
+
if (value === undefined)
|
|
213
|
+
return;
|
|
214
|
+
if (value === lastEmitted) {
|
|
215
|
+
lastEmitted = undefined;
|
|
216
|
+
state.value = { ...state.value, value };
|
|
217
|
+
}
|
|
218
|
+
else
|
|
219
|
+
state.value = { ...createComboboxState(props.options, value), open: state.value.open };
|
|
220
|
+
});
|
|
221
|
+
watch(() => props.options, options => {
|
|
222
|
+
if (effective.value.value)
|
|
223
|
+
state.value = { ...createComboboxState(options, effective.value.value), open: state.value.open };
|
|
224
|
+
});
|
|
225
|
+
watchEffect(() => element.value?.setCustomValidity(field.controlAttrs.value.required && !effective.value.value ? props.requiredMessage : ''));
|
|
226
|
+
useFormReset(element, () => dispatch({ type: 'reset', value: props.defaultValue }));
|
|
227
|
+
const outside = (event) => { if (!root.value?.contains(event.target))
|
|
228
|
+
dispatch({ type: 'close' }); };
|
|
229
|
+
onMounted(() => element.value?.ownerDocument.addEventListener('pointerdown', outside));
|
|
230
|
+
onBeforeUnmount(() => element.value?.ownerDocument.removeEventListener('pointerdown', outside));
|
|
231
|
+
expose({ element, focus: () => element.value?.focus(), close: () => dispatch({ type: 'close' }) });
|
|
232
|
+
return () => {
|
|
233
|
+
const { name, form, ...inputAttrs } = attrs;
|
|
234
|
+
const listId = `${field.id.value}-listbox`;
|
|
235
|
+
const active = results.value[state.value.activeIndex];
|
|
236
|
+
const open = effective.value.open;
|
|
237
|
+
const query = effective.value.query;
|
|
238
|
+
return decorate(props, field.id.value, h('div', { ref: root, class: 'hw-combobox', onFocusout: (event) => { if (!root.value?.contains(event.relatedTarget))
|
|
239
|
+
dispatch({ type: 'close' }); } }, [
|
|
240
|
+
h('input', mergeProps(inputAttrs, field.controlAttrs.value, { ref: element, form, disabled: props.disabled, readonly: props.readonly, class: 'hw-input', type: 'text', role: 'combobox', autocomplete: 'off', 'aria-autocomplete': 'list', 'aria-readonly': props.readonly || undefined, 'aria-expanded': open, 'aria-controls': listId,
|
|
241
|
+
'aria-activedescendant': open && active && !active.disabled ? `${field.id.value}-option-${state.value.activeIndex}` : undefined, value: query,
|
|
242
|
+
onInput: (event) => { const input = event.target; if (blocked()) {
|
|
243
|
+
input.value = query;
|
|
244
|
+
return;
|
|
245
|
+
} const nextQuery = input.value; dispatch({ type: 'input', query: nextQuery }); emit('update:query', nextQuery); },
|
|
246
|
+
onFocus: (event) => { if (!event.defaultPrevented)
|
|
247
|
+
dispatch({ type: 'open' }); },
|
|
248
|
+
onClick: (event) => { if (!event.defaultPrevented && !open)
|
|
249
|
+
dispatch({ type: 'open' }); },
|
|
250
|
+
onKeydown: (event) => {
|
|
251
|
+
if (event.defaultPrevented || event.isComposing || blocked())
|
|
252
|
+
return;
|
|
253
|
+
if (['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) {
|
|
254
|
+
if (!open && (event.key === 'Home' || event.key === 'End'))
|
|
255
|
+
return;
|
|
256
|
+
event.preventDefault();
|
|
257
|
+
dispatch({ type: 'navigate', key: event.key });
|
|
258
|
+
}
|
|
259
|
+
else if (event.key === 'Enter' && open && active && !active.disabled) {
|
|
260
|
+
event.preventDefault();
|
|
261
|
+
dispatch({ type: 'select', value: active.value });
|
|
262
|
+
}
|
|
263
|
+
else if (event.key === 'Escape' && open) {
|
|
264
|
+
event.preventDefault();
|
|
265
|
+
event.stopPropagation();
|
|
266
|
+
dispatch({ type: 'close' });
|
|
267
|
+
}
|
|
268
|
+
else if (event.key === 'Tab')
|
|
269
|
+
dispatch({ type: 'close' });
|
|
270
|
+
},
|
|
271
|
+
})),
|
|
272
|
+
h('input', { type: 'hidden', name, form, disabled: props.disabled, value: effective.value.value }),
|
|
273
|
+
h('ul', { id: listId, role: 'listbox', class: 'hw-listbox', 'aria-label': attrs['aria-label'], 'aria-labelledby': field.controlAttrs.value['aria-labelledby'], hidden: !open }, [
|
|
274
|
+
...results.value.map((option, index) => h('li', { key: option.value, id: `${field.id.value}-option-${index}`, role: 'option', class: 'hw-option', 'aria-selected': effective.value.value === option.value, 'aria-disabled': option.disabled || undefined,
|
|
275
|
+
'data-active': state.value.activeIndex === index ? 'true' : undefined, 'data-state': state.value.activeIndex === index ? 'active' : undefined,
|
|
276
|
+
onPointerdown: (event) => event.preventDefault(), onClick: () => { if (!option.disabled) {
|
|
277
|
+
dispatch({ type: 'select', value: option.value });
|
|
278
|
+
element.value?.focus();
|
|
279
|
+
} }, }, option.label)), !results.value.length && h('li', { role: 'presentation', class: 'hw-hint' }, props.emptyMessage),
|
|
280
|
+
]),
|
|
281
|
+
h('span', { class: 'hw-sr-only', role: 'status', 'aria-live': 'polite', 'aria-atomic': 'true' }, open ? props.resultsMessage(results.value.length) : ''),
|
|
282
|
+
]));
|
|
283
|
+
};
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
export const Tooltip = defineComponent({
|
|
287
|
+
name: 'HwTooltip', inheritAttrs: false, props: { content: { type: String, required: true }, placement: { type: String, default: 'top' }, align: { type: String, default: 'start' } },
|
|
288
|
+
setup(props, { attrs, slots }) {
|
|
289
|
+
const id = `hw-${useId()}`;
|
|
290
|
+
const open = ref(false);
|
|
291
|
+
const root = ref();
|
|
292
|
+
let hovered = false, focused = false;
|
|
293
|
+
let hideTimer;
|
|
294
|
+
const show = () => { clearTimeout(hideTimer); open.value = true; };
|
|
295
|
+
const hide = () => { clearTimeout(hideTimer); open.value = false; };
|
|
296
|
+
const leave = () => {
|
|
297
|
+
hovered = false;
|
|
298
|
+
if (!focused)
|
|
299
|
+
hideTimer = setTimeout(hide, 120);
|
|
300
|
+
};
|
|
301
|
+
const escape = (event) => {
|
|
302
|
+
if (!open.value || event.key !== 'Escape' || event.defaultPrevented)
|
|
303
|
+
return;
|
|
304
|
+
event.preventDefault();
|
|
305
|
+
event.stopPropagation();
|
|
306
|
+
hide();
|
|
307
|
+
};
|
|
308
|
+
watch(open, (visible, _, cleanup) => {
|
|
309
|
+
const element = root.value;
|
|
310
|
+
if (!visible || !element)
|
|
311
|
+
return;
|
|
312
|
+
const doc = element.ownerDocument;
|
|
313
|
+
const outside = (event) => { if (!element.contains(event.target))
|
|
314
|
+
hide(); };
|
|
315
|
+
doc.addEventListener('keydown', escape);
|
|
316
|
+
doc.addEventListener('pointerdown', outside);
|
|
317
|
+
cleanup(() => { doc.removeEventListener('keydown', escape); doc.removeEventListener('pointerdown', outside); });
|
|
318
|
+
}, { flush: 'sync' });
|
|
319
|
+
onBeforeUnmount(() => clearTimeout(hideTimer));
|
|
320
|
+
return () => {
|
|
321
|
+
const children = slots.default?.() ?? [];
|
|
322
|
+
return h('span', mergeProps(attrs, {
|
|
323
|
+
ref: root, 'data-hw': 'tooltip',
|
|
324
|
+
onMouseenter: () => { hovered = true; show(); }, onMouseleave: leave,
|
|
325
|
+
onFocusin: () => { focused = true; show(); },
|
|
326
|
+
onFocusout: (event) => {
|
|
327
|
+
if (root.value?.contains(event.relatedTarget))
|
|
328
|
+
return;
|
|
329
|
+
focused = false;
|
|
330
|
+
if (!hovered)
|
|
331
|
+
hide();
|
|
332
|
+
},
|
|
333
|
+
onKeydown: escape,
|
|
334
|
+
}), [
|
|
335
|
+
...children.map(child => isVNode(child) ? cloneVNode(child, { 'aria-describedby': joinIds(child.props?.['aria-describedby'], id) }) : child),
|
|
336
|
+
h('span', { id, role: 'tooltip', class: 'hw-tooltip', 'data-placement': props.placement, 'data-align': props.align, hidden: !open.value }, props.content),
|
|
337
|
+
]);
|
|
338
|
+
};
|
|
339
|
+
},
|
|
340
|
+
});
|
|
341
|
+
//# sourceMappingURL=interactive.js.map
|