@sit-onyx/headless 0.1.0-alpha.0 → 0.1.0-alpha.2
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/README.md +11 -47
- package/package.json +13 -7
- package/src/composables/comboBox/createComboBox.ts +5 -5
- package/src/composables/listbox/createListbox.ts +59 -0
- package/src/index.ts +2 -0
- package/src/utils/builder.ts +1 -17
- package/src/utils/id.ts +4 -0
package/README.md
CHANGED
|
@@ -1,57 +1,21 @@
|
|
|
1
|
-
<
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
</
|
|
7
|
-
</
|
|
1
|
+
<div align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/SchwarzIT/onyx/main/.github/onyx-logo-light.svg">
|
|
4
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/SchwarzIT/onyx/main/.github/onyx-logo-dark.svg">
|
|
5
|
+
<img alt="onyx logo" src="https://raw.githubusercontent.com/SchwarzIT/onyx/main/.github/onyx-logo-dark.svg" width="160px">
|
|
6
|
+
</picture>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<br>
|
|
8
10
|
|
|
9
11
|
# onyx Headless
|
|
10
12
|
|
|
11
13
|
A composable headless library for Vue created by [Schwarz IT](https://it.schwarz).
|
|
12
14
|
|
|
13
|
-
Inspired by [Melt UI](https://melt-ui.com/).
|
|
14
|
-
|
|
15
15
|
> **Work in progress**: This library is currently in early / active development.
|
|
16
16
|
|
|
17
17
|
<br />
|
|
18
18
|
|
|
19
|
-
##
|
|
20
|
-
|
|
21
|
-
Install the npm package with your corresponding package manager:
|
|
22
|
-
|
|
23
|
-
### pnpm
|
|
24
|
-
|
|
25
|
-
```sh
|
|
26
|
-
pnpm add @sit-onyx/headless
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### npm
|
|
30
|
-
|
|
31
|
-
```sh
|
|
32
|
-
npm install @sit-onyx/headless
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### yarn
|
|
36
|
-
|
|
37
|
-
```sh
|
|
38
|
-
yarn install @sit-onyx/headless
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Composables are now ready to be used, e.g.:
|
|
42
|
-
|
|
43
|
-
```vue
|
|
44
|
-
<script lang="ts" setup>
|
|
45
|
-
import { createCombobox } from "@sit-onyx/headless";
|
|
46
|
-
|
|
47
|
-
const {
|
|
48
|
-
elements: {
|
|
49
|
-
...
|
|
50
|
-
}
|
|
51
|
-
} = createCombobox();
|
|
52
|
-
</script>
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
<br />
|
|
19
|
+
## Documentation
|
|
56
20
|
|
|
57
|
-
|
|
21
|
+
You can find our documentation [here](https://onyx.schwarz/development/packages/headless.html).
|
package/package.json
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sit-onyx/headless",
|
|
3
3
|
"description": "Headless composables for Vue",
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
4
|
+
"version": "0.1.0-alpha.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Schwarz IT KG",
|
|
7
7
|
"license": "Apache-2.0",
|
|
8
8
|
"files": [
|
|
9
9
|
"src"
|
|
10
10
|
],
|
|
11
|
+
"types": "./src/index.ts",
|
|
11
12
|
"exports": {
|
|
12
|
-
".":
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
".": "./src/index.ts",
|
|
14
|
+
"./playwright": "./src/playwright.ts"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://onyx.schwarz/development/packages/headless.html",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/SchwarzIT/onyx",
|
|
20
|
+
"directory": "packages/headless"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/SchwarzIT/onyx/issues"
|
|
18
24
|
},
|
|
19
25
|
"peerDependencies": {
|
|
20
26
|
"typescript": ">= 5",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { computed, ref, type Ref } from "vue";
|
|
2
|
+
import { createBuilder } from "../../utils/builder";
|
|
2
3
|
import { createId } from "../../utils/id";
|
|
3
|
-
import { createBuilder, computeIterated } from "../../utils/builder";
|
|
4
4
|
|
|
5
5
|
// TODO: https://w3c.github.io/aria/#aria-autocomplete
|
|
6
6
|
// TODO: https://www.w3.org/WAI/ARIA/apg/patterns/combobox/
|
|
@@ -92,16 +92,16 @@ export const createComboBox = createBuilder(
|
|
|
92
92
|
role: "listbox",
|
|
93
93
|
id: controlsId,
|
|
94
94
|
})),
|
|
95
|
-
option:
|
|
96
|
-
({ key, label, disabled }) => ({
|
|
95
|
+
option: computed(() => {
|
|
96
|
+
return ({ key, label, disabled }: { key: string; label: string; disabled: boolean }) => ({
|
|
97
97
|
role: "option",
|
|
98
98
|
id: getOptionId(key),
|
|
99
99
|
"aria-selected": activeKey.value === key,
|
|
100
100
|
"aria-label": label,
|
|
101
101
|
"aria-disabled": disabled,
|
|
102
102
|
onClick: () => onSelect(key),
|
|
103
|
-
})
|
|
104
|
-
),
|
|
103
|
+
});
|
|
104
|
+
}),
|
|
105
105
|
/**
|
|
106
106
|
* An input that controls another element, that can dynamically pop-up to help the user set the value of the input.
|
|
107
107
|
* The input MAY be either a single-line text field that supports editing and typing or an element that only displays the current value of the combobox.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { computed, unref, type MaybeRef } from "vue";
|
|
2
|
+
import { createBuilder } from "../../utils/builder";
|
|
3
|
+
|
|
4
|
+
export type CreateListboxOptions = {
|
|
5
|
+
/**
|
|
6
|
+
* Aria label for the listbox.
|
|
7
|
+
*/
|
|
8
|
+
label: MaybeRef<string>;
|
|
9
|
+
/**
|
|
10
|
+
* Whether the listbox is multiselect.
|
|
11
|
+
*/
|
|
12
|
+
multiselect?: MaybeRef<boolean | undefined>;
|
|
13
|
+
/**
|
|
14
|
+
* Hook when an option is selected.
|
|
15
|
+
*/
|
|
16
|
+
onSelect?: (id: ListboxValue) => void;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type ListboxValue = string | number | boolean;
|
|
20
|
+
|
|
21
|
+
export const createListbox = createBuilder((options: CreateListboxOptions) => {
|
|
22
|
+
const isMultiselect = computed(() => unref(options.multiselect) ?? false);
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
elements: {
|
|
26
|
+
listbox: computed(() => ({
|
|
27
|
+
role: "listbox",
|
|
28
|
+
"aria-multiselectable": isMultiselect.value,
|
|
29
|
+
"aria-label": unref(options.label),
|
|
30
|
+
tabindex: "0",
|
|
31
|
+
})),
|
|
32
|
+
group: computed(() => {
|
|
33
|
+
return (options: { label: string }) => ({
|
|
34
|
+
role: "group",
|
|
35
|
+
"aria-label": options.label,
|
|
36
|
+
});
|
|
37
|
+
}),
|
|
38
|
+
option: computed(() => {
|
|
39
|
+
return (data: {
|
|
40
|
+
label: string;
|
|
41
|
+
id: ListboxValue;
|
|
42
|
+
selected?: boolean;
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
}) => {
|
|
45
|
+
const isSelected = data.selected ?? false;
|
|
46
|
+
return {
|
|
47
|
+
role: "option",
|
|
48
|
+
"aria-label": data.label,
|
|
49
|
+
"aria-checked": isMultiselect.value ? isSelected : undefined,
|
|
50
|
+
"aria-selected": !isMultiselect.value ? isSelected : undefined,
|
|
51
|
+
"aria-disabled": data.disabled,
|
|
52
|
+
onClick: () => options.onSelect?.(data.id),
|
|
53
|
+
} as const;
|
|
54
|
+
};
|
|
55
|
+
}),
|
|
56
|
+
},
|
|
57
|
+
state: {},
|
|
58
|
+
};
|
|
59
|
+
});
|
package/src/index.ts
CHANGED
package/src/utils/builder.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ComputedRef, HtmlHTMLAttributes, Ref } from "vue";
|
|
2
2
|
|
|
3
3
|
export type IteratedHeadlessElementFunc<T extends Record<string, unknown>> = (
|
|
4
4
|
opts: T,
|
|
@@ -25,19 +25,3 @@ export type HeadlessComposable<Elements extends HeadlessElements, State extends
|
|
|
25
25
|
export const createBuilder = <P, Elements extends HeadlessElements, State extends HeadlessState>(
|
|
26
26
|
builder: (props: P) => HeadlessComposable<Elements, State>,
|
|
27
27
|
) => builder;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Shorthand function for creating a typed IteratedHeadlessElementFunction
|
|
31
|
-
* @example
|
|
32
|
-
* ```ts
|
|
33
|
-
* {
|
|
34
|
-
* option: computeIterated<{ key: string; label: string; disabled: boolean }>(
|
|
35
|
-
* ({ key, label, disabled }) => ({
|
|
36
|
-
* // Do something with the typed props
|
|
37
|
-
* }),
|
|
38
|
-
* }
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
export const computeIterated = <P extends Record<string, unknown>>(
|
|
42
|
-
iteratedFunc: IteratedHeadlessElementFunc<P>,
|
|
43
|
-
) => computed(() => iteratedFunc);
|
package/src/utils/id.ts
CHANGED