@tokis/core 1.0.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 +21 -0
- package/README.md +41 -0
- package/dist/a11y/aria-helpers.d.ts +19 -0
- package/dist/a11y/aria-helpers.d.ts.map +1 -0
- package/dist/a11y/aria-helpers.js +40 -0
- package/dist/a11y/aria-helpers.js.map +1 -0
- package/dist/a11y/id-generator.d.ts +18 -0
- package/dist/a11y/id-generator.d.ts.map +1 -0
- package/dist/a11y/id-generator.js +25 -0
- package/dist/a11y/id-generator.js.map +1 -0
- package/dist/cjs/a11y/aria-helpers.js +51 -0
- package/dist/cjs/a11y/id-generator.js +28 -0
- package/dist/cjs/focus/focus-trap.js +30 -0
- package/dist/cjs/focus/roving-tabindex.js +36 -0
- package/dist/cjs/focus/use-focus-visible.js +42 -0
- package/dist/cjs/index.js +24 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/primitives/button/button.machine.js +13 -0
- package/dist/cjs/primitives/button/button.types.js +2 -0
- package/dist/cjs/primitives/button/index.js +18 -0
- package/dist/cjs/state/controllable-state.js +22 -0
- package/dist/cjs/state/create-machine.js +27 -0
- package/dist/focus/focus-trap.d.ts +2 -0
- package/dist/focus/focus-trap.d.ts.map +1 -0
- package/dist/focus/focus-trap.js +28 -0
- package/dist/focus/focus-trap.js.map +1 -0
- package/dist/focus/roving-tabindex.d.ts +4 -0
- package/dist/focus/roving-tabindex.d.ts.map +1 -0
- package/dist/focus/roving-tabindex.js +34 -0
- package/dist/focus/roving-tabindex.js.map +1 -0
- package/dist/focus/use-focus-visible.d.ts +7 -0
- package/dist/focus/use-focus-visible.d.ts.map +1 -0
- package/dist/focus/use-focus-visible.js +40 -0
- package/dist/focus/use-focus-visible.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/primitives/button/button.machine.d.ts +5 -0
- package/dist/primitives/button/button.machine.d.ts.map +1 -0
- package/dist/primitives/button/button.machine.js +11 -0
- package/dist/primitives/button/button.machine.js.map +1 -0
- package/dist/primitives/button/button.types.d.ts +9 -0
- package/dist/primitives/button/button.types.d.ts.map +1 -0
- package/dist/primitives/button/button.types.js +2 -0
- package/dist/primitives/button/button.types.js.map +1 -0
- package/dist/primitives/button/index.d.ts +3 -0
- package/dist/primitives/button/index.d.ts.map +1 -0
- package/dist/primitives/button/index.js +3 -0
- package/dist/primitives/button/index.js.map +1 -0
- package/dist/state/controllable-state.d.ts +15 -0
- package/dist/state/controllable-state.d.ts.map +1 -0
- package/dist/state/controllable-state.js +19 -0
- package/dist/state/controllable-state.js.map +1 -0
- package/dist/state/create-machine.d.ts +29 -0
- package/dist/state/create-machine.d.ts.map +1 -0
- package/dist/state/create-machine.js +23 -0
- package/dist/state/create-machine.js.map +1 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Tokis Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# /core
|
|
2
|
+
|
|
3
|
+
Framework-agnostic headless primitives for the Tokis design system — state machines, accessibility helpers, and focus management. Zero dependencies.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install /core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
> Or install everything at once: `npm install tokis`
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import {
|
|
17
|
+
createFocusTrap,
|
|
18
|
+
rovingTabIndex,
|
|
19
|
+
generateId,
|
|
20
|
+
createMachine,
|
|
21
|
+
} from '/core';
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## What's Included
|
|
25
|
+
|
|
26
|
+
- **Focus Management** — `createFocusTrap`, `rovingTabIndex`, `useFocusVisible`
|
|
27
|
+
- **Accessibility** — ARIA attribute helpers, unique ID generation
|
|
28
|
+
- **State Machines** — Lightweight `createMachine` for component behavior
|
|
29
|
+
- **Controllable State** — Unified controlled/uncontrolled state pattern
|
|
30
|
+
|
|
31
|
+
## Why Use This?
|
|
32
|
+
|
|
33
|
+
`/core` contains no React, no DOM assumptions, and no CSS. Use it to build your own component library on top of Tokis's battle-tested accessibility and state management layer — in React, Vue, Svelte, or vanilla JS.
|
|
34
|
+
|
|
35
|
+
## Documentation
|
|
36
|
+
|
|
37
|
+
Visit [tokis.dev](https://tokis.dev) for the full documentation.
|
|
38
|
+
|
|
39
|
+
## License
|
|
40
|
+
|
|
41
|
+
MIT
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ARIA attribute helpers.
|
|
3
|
+
* Imperative setters for use in non-framework environments.
|
|
4
|
+
* Framework adapters should use the corresponding prop-object helpers instead.
|
|
5
|
+
*/
|
|
6
|
+
export declare function setAriaLabelledBy(element: HTMLElement, id: string): void;
|
|
7
|
+
export declare function setAriaDescribedBy(element: HTMLElement, id: string): void;
|
|
8
|
+
export declare function setAriaExpanded(element: HTMLElement, expanded: boolean): void;
|
|
9
|
+
export declare function setAriaHidden(element: HTMLElement, hidden: boolean): void;
|
|
10
|
+
export declare function setAriaControls(element: HTMLElement, id: string): void;
|
|
11
|
+
export declare function ariaLabelledByProps(id: string): Record<string, string>;
|
|
12
|
+
export declare function ariaDescribedByProps(id: string): Record<string, string>;
|
|
13
|
+
export declare function ariaExpandedProps(expanded: boolean): Record<string, string>;
|
|
14
|
+
export declare function ariaHiddenProps(hidden: boolean): Record<string, string>;
|
|
15
|
+
/** @deprecated Use setAriaLabelledBy instead */
|
|
16
|
+
export declare const ariaLabelledBy: typeof setAriaLabelledBy;
|
|
17
|
+
/** @deprecated Use setAriaDescribedBy instead */
|
|
18
|
+
export declare const ariaDescribedBy: typeof setAriaDescribedBy;
|
|
19
|
+
//# sourceMappingURL=aria-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aria-helpers.d.ts","sourceRoot":"","sources":["../../src/a11y/aria-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAExE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAEzE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAE7E;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAEzE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAEtE;AAID,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAEtE;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAEvE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAE3E;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAEvE;AAGD,gDAAgD;AAChD,eAAO,MAAM,cAAc,0BAAoB,CAAC;AAChD,iDAAiD;AACjD,eAAO,MAAM,eAAe,2BAAqB,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ARIA attribute helpers.
|
|
3
|
+
* Imperative setters for use in non-framework environments.
|
|
4
|
+
* Framework adapters should use the corresponding prop-object helpers instead.
|
|
5
|
+
*/
|
|
6
|
+
// --- Imperative setters ---
|
|
7
|
+
export function setAriaLabelledBy(element, id) {
|
|
8
|
+
element.setAttribute('aria-labelledby', id);
|
|
9
|
+
}
|
|
10
|
+
export function setAriaDescribedBy(element, id) {
|
|
11
|
+
element.setAttribute('aria-describedby', id);
|
|
12
|
+
}
|
|
13
|
+
export function setAriaExpanded(element, expanded) {
|
|
14
|
+
element.setAttribute('aria-expanded', String(expanded));
|
|
15
|
+
}
|
|
16
|
+
export function setAriaHidden(element, hidden) {
|
|
17
|
+
element.setAttribute('aria-hidden', String(hidden));
|
|
18
|
+
}
|
|
19
|
+
export function setAriaControls(element, id) {
|
|
20
|
+
element.setAttribute('aria-controls', id);
|
|
21
|
+
}
|
|
22
|
+
// --- Prop-object helpers (framework-agnostic, usable in React/Vue/etc.) ---
|
|
23
|
+
export function ariaLabelledByProps(id) {
|
|
24
|
+
return { 'aria-labelledby': id };
|
|
25
|
+
}
|
|
26
|
+
export function ariaDescribedByProps(id) {
|
|
27
|
+
return { 'aria-describedby': id };
|
|
28
|
+
}
|
|
29
|
+
export function ariaExpandedProps(expanded) {
|
|
30
|
+
return { 'aria-expanded': String(expanded) };
|
|
31
|
+
}
|
|
32
|
+
export function ariaHiddenProps(hidden) {
|
|
33
|
+
return { 'aria-hidden': String(hidden) };
|
|
34
|
+
}
|
|
35
|
+
// Keep legacy exports for backward compatibility
|
|
36
|
+
/** @deprecated Use setAriaLabelledBy instead */
|
|
37
|
+
export const ariaLabelledBy = setAriaLabelledBy;
|
|
38
|
+
/** @deprecated Use setAriaDescribedBy instead */
|
|
39
|
+
export const ariaDescribedBy = setAriaDescribedBy;
|
|
40
|
+
//# sourceMappingURL=aria-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aria-helpers.js","sourceRoot":"","sources":["../../src/a11y/aria-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,6BAA6B;AAE7B,MAAM,UAAU,iBAAiB,CAAC,OAAoB,EAAE,EAAU;IAChE,OAAO,CAAC,YAAY,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAoB,EAAE,EAAU;IACjE,OAAO,CAAC,YAAY,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAoB,EAAE,QAAiB;IACrE,OAAO,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAoB,EAAE,MAAe;IACjE,OAAO,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAoB,EAAE,EAAU;IAC9D,OAAO,CAAC,YAAY,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED,6EAA6E;AAE7E,MAAM,UAAU,mBAAmB,CAAC,EAAU;IAC5C,OAAO,EAAE,iBAAiB,EAAE,EAAE,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,EAAU;IAC7C,OAAO,EAAE,kBAAkB,EAAE,EAAE,EAAE,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAiB;IACjD,OAAO,EAAE,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAe;IAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;AAC3C,CAAC;AAED,iDAAiD;AACjD,gDAAgD;AAChD,MAAM,CAAC,MAAM,cAAc,GAAG,iBAAiB,CAAC;AAChD,iDAAiD;AACjD,MAAM,CAAC,MAAM,eAAe,GAAG,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a globally unique, incrementing ID with an optional prefix.
|
|
3
|
+
* SSR Note: IDs generated server-side and client-side may differ.
|
|
4
|
+
* Prefer `createIdScope` for component-level ID generation.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateId(prefix?: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Creates a scoped ID generator for a component instance.
|
|
9
|
+
* All IDs within a scope share the same numeric suffix,
|
|
10
|
+
* making them predictably related (e.g., label-1 / input-1).
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const scope = createIdScope('field');
|
|
14
|
+
* scope('label'); // → 'field-label-1'
|
|
15
|
+
* scope('input'); // → 'field-input-1'
|
|
16
|
+
*/
|
|
17
|
+
export declare function createIdScope(componentName: string): (part: string) => string;
|
|
18
|
+
//# sourceMappingURL=id-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id-generator.d.ts","sourceRoot":"","sources":["../../src/a11y/id-generator.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,SAAU,GAAG,MAAM,CAGnD;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAG7E"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
let globalCounter = 0;
|
|
2
|
+
/**
|
|
3
|
+
* Generates a globally unique, incrementing ID with an optional prefix.
|
|
4
|
+
* SSR Note: IDs generated server-side and client-side may differ.
|
|
5
|
+
* Prefer `createIdScope` for component-level ID generation.
|
|
6
|
+
*/
|
|
7
|
+
export function generateId(prefix = 'tokis') {
|
|
8
|
+
globalCounter += 1;
|
|
9
|
+
return `${prefix}-${globalCounter}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Creates a scoped ID generator for a component instance.
|
|
13
|
+
* All IDs within a scope share the same numeric suffix,
|
|
14
|
+
* making them predictably related (e.g., label-1 / input-1).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* const scope = createIdScope('field');
|
|
18
|
+
* scope('label'); // → 'field-label-1'
|
|
19
|
+
* scope('input'); // → 'field-input-1'
|
|
20
|
+
*/
|
|
21
|
+
export function createIdScope(componentName) {
|
|
22
|
+
const id = generateId(componentName);
|
|
23
|
+
return (part) => `${id}-${part}`;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=id-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id-generator.js","sourceRoot":"","sources":["../../src/a11y/id-generator.ts"],"names":[],"mappings":"AAAA,IAAI,aAAa,GAAG,CAAC,CAAC;AAEtB;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,MAAM,GAAG,OAAO;IACzC,aAAa,IAAI,CAAC,CAAC;IACnB,OAAO,GAAG,MAAM,IAAI,aAAa,EAAE,CAAC;AACtC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAAC,aAAqB;IACjD,MAAM,EAAE,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IACrC,OAAO,CAAC,IAAY,EAAE,EAAE,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ARIA attribute helpers.
|
|
4
|
+
* Imperative setters for use in non-framework environments.
|
|
5
|
+
* Framework adapters should use the corresponding prop-object helpers instead.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.ariaDescribedBy = exports.ariaLabelledBy = void 0;
|
|
9
|
+
exports.setAriaLabelledBy = setAriaLabelledBy;
|
|
10
|
+
exports.setAriaDescribedBy = setAriaDescribedBy;
|
|
11
|
+
exports.setAriaExpanded = setAriaExpanded;
|
|
12
|
+
exports.setAriaHidden = setAriaHidden;
|
|
13
|
+
exports.setAriaControls = setAriaControls;
|
|
14
|
+
exports.ariaLabelledByProps = ariaLabelledByProps;
|
|
15
|
+
exports.ariaDescribedByProps = ariaDescribedByProps;
|
|
16
|
+
exports.ariaExpandedProps = ariaExpandedProps;
|
|
17
|
+
exports.ariaHiddenProps = ariaHiddenProps;
|
|
18
|
+
// --- Imperative setters ---
|
|
19
|
+
function setAriaLabelledBy(element, id) {
|
|
20
|
+
element.setAttribute('aria-labelledby', id);
|
|
21
|
+
}
|
|
22
|
+
function setAriaDescribedBy(element, id) {
|
|
23
|
+
element.setAttribute('aria-describedby', id);
|
|
24
|
+
}
|
|
25
|
+
function setAriaExpanded(element, expanded) {
|
|
26
|
+
element.setAttribute('aria-expanded', String(expanded));
|
|
27
|
+
}
|
|
28
|
+
function setAriaHidden(element, hidden) {
|
|
29
|
+
element.setAttribute('aria-hidden', String(hidden));
|
|
30
|
+
}
|
|
31
|
+
function setAriaControls(element, id) {
|
|
32
|
+
element.setAttribute('aria-controls', id);
|
|
33
|
+
}
|
|
34
|
+
// --- Prop-object helpers (framework-agnostic, usable in React/Vue/etc.) ---
|
|
35
|
+
function ariaLabelledByProps(id) {
|
|
36
|
+
return { 'aria-labelledby': id };
|
|
37
|
+
}
|
|
38
|
+
function ariaDescribedByProps(id) {
|
|
39
|
+
return { 'aria-describedby': id };
|
|
40
|
+
}
|
|
41
|
+
function ariaExpandedProps(expanded) {
|
|
42
|
+
return { 'aria-expanded': String(expanded) };
|
|
43
|
+
}
|
|
44
|
+
function ariaHiddenProps(hidden) {
|
|
45
|
+
return { 'aria-hidden': String(hidden) };
|
|
46
|
+
}
|
|
47
|
+
// Keep legacy exports for backward compatibility
|
|
48
|
+
/** @deprecated Use setAriaLabelledBy instead */
|
|
49
|
+
exports.ariaLabelledBy = setAriaLabelledBy;
|
|
50
|
+
/** @deprecated Use setAriaDescribedBy instead */
|
|
51
|
+
exports.ariaDescribedBy = setAriaDescribedBy;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateId = generateId;
|
|
4
|
+
exports.createIdScope = createIdScope;
|
|
5
|
+
let globalCounter = 0;
|
|
6
|
+
/**
|
|
7
|
+
* Generates a globally unique, incrementing ID with an optional prefix.
|
|
8
|
+
* SSR Note: IDs generated server-side and client-side may differ.
|
|
9
|
+
* Prefer `createIdScope` for component-level ID generation.
|
|
10
|
+
*/
|
|
11
|
+
function generateId(prefix = 'tokis') {
|
|
12
|
+
globalCounter += 1;
|
|
13
|
+
return `${prefix}-${globalCounter}`;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Creates a scoped ID generator for a component instance.
|
|
17
|
+
* All IDs within a scope share the same numeric suffix,
|
|
18
|
+
* making them predictably related (e.g., label-1 / input-1).
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* const scope = createIdScope('field');
|
|
22
|
+
* scope('label'); // → 'field-label-1'
|
|
23
|
+
* scope('input'); // → 'field-input-1'
|
|
24
|
+
*/
|
|
25
|
+
function createIdScope(componentName) {
|
|
26
|
+
const id = generateId(componentName);
|
|
27
|
+
return (part) => `${id}-${part}`;
|
|
28
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.trapFocus = trapFocus;
|
|
4
|
+
function trapFocus(element) {
|
|
5
|
+
const focusableSelectors = 'a[href], button, textarea, input, select, [tabindex]:not([tabindex="-1"])';
|
|
6
|
+
const focusable = Array.from(element.querySelectorAll(focusableSelectors));
|
|
7
|
+
if (!focusable.length)
|
|
8
|
+
return;
|
|
9
|
+
const first = focusable[0];
|
|
10
|
+
const last = focusable[focusable.length - 1];
|
|
11
|
+
const handleKeyDown = (e) => {
|
|
12
|
+
if (e.key !== 'Tab')
|
|
13
|
+
return;
|
|
14
|
+
if (e.shiftKey) {
|
|
15
|
+
if (document.activeElement === first) {
|
|
16
|
+
e.preventDefault();
|
|
17
|
+
last.focus();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
if (document.activeElement === last) {
|
|
22
|
+
e.preventDefault();
|
|
23
|
+
first.focus();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
element.addEventListener('keydown', handleKeyDown);
|
|
28
|
+
// Return cleanup function
|
|
29
|
+
return () => element.removeEventListener('keydown', handleKeyDown);
|
|
30
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rovingTabIndex = rovingTabIndex;
|
|
4
|
+
function rovingTabIndex(container, options) {
|
|
5
|
+
const focusable = Array.from(container.querySelectorAll('button:not([disabled]), [role="button"], a[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'));
|
|
6
|
+
let activeIndex = options?.activeIndex ?? 0;
|
|
7
|
+
const setActive = (index) => {
|
|
8
|
+
activeIndex = index;
|
|
9
|
+
focusable.forEach((el, i) => {
|
|
10
|
+
el.setAttribute('tabindex', i === index ? '0' : '-1');
|
|
11
|
+
});
|
|
12
|
+
focusable[index]?.focus();
|
|
13
|
+
};
|
|
14
|
+
if (focusable.length > 0) {
|
|
15
|
+
setActive(activeIndex);
|
|
16
|
+
}
|
|
17
|
+
const handleKeyDown = (e) => {
|
|
18
|
+
if (!['ArrowRight', 'ArrowLeft', 'ArrowDown', 'ArrowUp', 'Home', 'End'].includes(e.key))
|
|
19
|
+
return;
|
|
20
|
+
e.preventDefault();
|
|
21
|
+
if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {
|
|
22
|
+
setActive((activeIndex + 1) % focusable.length);
|
|
23
|
+
}
|
|
24
|
+
else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {
|
|
25
|
+
setActive((activeIndex - 1 + focusable.length) % focusable.length);
|
|
26
|
+
}
|
|
27
|
+
else if (e.key === 'Home') {
|
|
28
|
+
setActive(0);
|
|
29
|
+
}
|
|
30
|
+
else if (e.key === 'End') {
|
|
31
|
+
setActive(focusable.length - 1);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
container.addEventListener('keydown', handleKeyDown);
|
|
35
|
+
return () => container.removeEventListener('keydown', handleKeyDown);
|
|
36
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useFocusVisible = useFocusVisible;
|
|
4
|
+
/**
|
|
5
|
+
* Tracks whether focus was triggered via keyboard input and applies
|
|
6
|
+
* the `focus-visible` class accordingly — matching the CSS :focus-visible spec.
|
|
7
|
+
* Returns a cleanup function to remove all listeners.
|
|
8
|
+
*/
|
|
9
|
+
function useFocusVisible(element) {
|
|
10
|
+
let hadKeyboardEvent = false;
|
|
11
|
+
const onPointerDown = () => {
|
|
12
|
+
hadKeyboardEvent = false;
|
|
13
|
+
};
|
|
14
|
+
const onKeyDown = (e) => {
|
|
15
|
+
// Ignore modifier-only keypresses
|
|
16
|
+
if (!['Tab', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Enter', ' '].includes(e.key))
|
|
17
|
+
return;
|
|
18
|
+
hadKeyboardEvent = true;
|
|
19
|
+
};
|
|
20
|
+
const onFocus = (e) => {
|
|
21
|
+
const target = e.target;
|
|
22
|
+
if (target && hadKeyboardEvent) {
|
|
23
|
+
target.classList.add('focus-visible');
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const onBlur = (e) => {
|
|
27
|
+
const target = e.target;
|
|
28
|
+
if (target) {
|
|
29
|
+
target.classList.remove('focus-visible');
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
element.addEventListener('pointerdown', onPointerDown, true);
|
|
33
|
+
element.addEventListener('keydown', onKeyDown, true);
|
|
34
|
+
element.addEventListener('focus', onFocus, true);
|
|
35
|
+
element.addEventListener('blur', onBlur, true);
|
|
36
|
+
return () => {
|
|
37
|
+
element.removeEventListener('pointerdown', onPointerDown, true);
|
|
38
|
+
element.removeEventListener('keydown', onKeyDown, true);
|
|
39
|
+
element.removeEventListener('focus', onFocus, true);
|
|
40
|
+
element.removeEventListener('blur', onBlur, true);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./primitives/button/index"), exports);
|
|
18
|
+
__exportStar(require("./focus/focus-trap"), exports);
|
|
19
|
+
__exportStar(require("./focus/roving-tabindex"), exports);
|
|
20
|
+
__exportStar(require("./focus/use-focus-visible"), exports);
|
|
21
|
+
__exportStar(require("./a11y/aria-helpers"), exports);
|
|
22
|
+
__exportStar(require("./a11y/id-generator"), exports);
|
|
23
|
+
__exportStar(require("./state/controllable-state"), exports);
|
|
24
|
+
__exportStar(require("./state/create-machine"), exports);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buttonMachine = void 0;
|
|
4
|
+
const create_machine_js_1 = require("../../state/create-machine");
|
|
5
|
+
exports.buttonMachine = (0, create_machine_js_1.createMachine)({
|
|
6
|
+
id: 'button',
|
|
7
|
+
initial: 'idle',
|
|
8
|
+
context: { disabled: false },
|
|
9
|
+
states: {
|
|
10
|
+
idle: { PRESS: 'pressed' },
|
|
11
|
+
pressed: { RELEASE: 'idle' },
|
|
12
|
+
},
|
|
13
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./button.machine"), exports);
|
|
18
|
+
__exportStar(require("./button.types"), exports);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isControlled = isControlled;
|
|
4
|
+
exports.resolveInitialState = resolveInitialState;
|
|
5
|
+
/**
|
|
6
|
+
* Determines whether a value is controlled (externally managed) or uncontrolled.
|
|
7
|
+
* Returns the resolved value and a no-op setter indicator for framework adapters.
|
|
8
|
+
*
|
|
9
|
+
* Framework adapters (e.g. react/) are responsible for implementing
|
|
10
|
+
* useControllableState using this utility as a type helper.
|
|
11
|
+
*/
|
|
12
|
+
function isControlled(value) {
|
|
13
|
+
return typeof value !== 'undefined';
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the initial state for an uncontrolled component.
|
|
17
|
+
* If `controlled` is defined, returns it directly.
|
|
18
|
+
* Otherwise returns `defaultValue`.
|
|
19
|
+
*/
|
|
20
|
+
function resolveInitialState(controlled, defaultValue) {
|
|
21
|
+
return isControlled(controlled) ? controlled : defaultValue;
|
|
22
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Lightweight state machine factory — no external dependencies.
|
|
4
|
+
* A minimal alternative to XState for simple state transitions.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.createMachine = createMachine;
|
|
8
|
+
exports.assign = assign;
|
|
9
|
+
exports.setup = setup;
|
|
10
|
+
function createMachine(config) {
|
|
11
|
+
return {
|
|
12
|
+
id: config.id,
|
|
13
|
+
initialState: config.initial,
|
|
14
|
+
initialContext: config.context,
|
|
15
|
+
transition(state, event) {
|
|
16
|
+
return config.states[state]?.[event] ?? state;
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** No-op assign helper for API compatibility */
|
|
21
|
+
function assign(updater) {
|
|
22
|
+
return updater;
|
|
23
|
+
}
|
|
24
|
+
/** No-op setup helper for API compatibility */
|
|
25
|
+
function setup(_config) {
|
|
26
|
+
return { createMachine };
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus-trap.d.ts","sourceRoot":"","sources":["../../src/focus/focus-trap.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,4BAyB7C"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function trapFocus(element) {
|
|
2
|
+
const focusableSelectors = 'a[href], button, textarea, input, select, [tabindex]:not([tabindex="-1"])';
|
|
3
|
+
const focusable = Array.from(element.querySelectorAll(focusableSelectors));
|
|
4
|
+
if (!focusable.length)
|
|
5
|
+
return;
|
|
6
|
+
const first = focusable[0];
|
|
7
|
+
const last = focusable[focusable.length - 1];
|
|
8
|
+
const handleKeyDown = (e) => {
|
|
9
|
+
if (e.key !== 'Tab')
|
|
10
|
+
return;
|
|
11
|
+
if (e.shiftKey) {
|
|
12
|
+
if (document.activeElement === first) {
|
|
13
|
+
e.preventDefault();
|
|
14
|
+
last.focus();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
if (document.activeElement === last) {
|
|
19
|
+
e.preventDefault();
|
|
20
|
+
first.focus();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
element.addEventListener('keydown', handleKeyDown);
|
|
25
|
+
// Return cleanup function
|
|
26
|
+
return () => element.removeEventListener('keydown', handleKeyDown);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=focus-trap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus-trap.js","sourceRoot":"","sources":["../../src/focus/focus-trap.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS,CAAC,OAAoB;IAC5C,MAAM,kBAAkB,GAAG,2EAAoF,CAAC;IAChH,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAkB,CAAC;IAC5F,IAAI,CAAC,SAAS,CAAC,MAAM;QAAE,OAAO;IAC9B,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE7C,MAAM,aAAa,GAAG,CAAC,CAAgB,EAAE,EAAE;QACzC,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK;YAAE,OAAO;QAC5B,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;YACf,IAAI,QAAQ,CAAC,aAAa,KAAK,KAAK,EAAE,CAAC;gBACrC,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,QAAQ,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;gBACpC,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CAAC,gBAAgB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACnD,0BAA0B;IAC1B,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roving-tabindex.d.ts","sourceRoot":"","sources":["../../src/focus/roving-tabindex.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,cAqCxF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export function rovingTabIndex(container, options) {
|
|
2
|
+
const focusable = Array.from(container.querySelectorAll('button:not([disabled]), [role="button"], a[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'));
|
|
3
|
+
let activeIndex = options?.activeIndex ?? 0;
|
|
4
|
+
const setActive = (index) => {
|
|
5
|
+
activeIndex = index;
|
|
6
|
+
focusable.forEach((el, i) => {
|
|
7
|
+
el.setAttribute('tabindex', i === index ? '0' : '-1');
|
|
8
|
+
});
|
|
9
|
+
focusable[index]?.focus();
|
|
10
|
+
};
|
|
11
|
+
if (focusable.length > 0) {
|
|
12
|
+
setActive(activeIndex);
|
|
13
|
+
}
|
|
14
|
+
const handleKeyDown = (e) => {
|
|
15
|
+
if (!['ArrowRight', 'ArrowLeft', 'ArrowDown', 'ArrowUp', 'Home', 'End'].includes(e.key))
|
|
16
|
+
return;
|
|
17
|
+
e.preventDefault();
|
|
18
|
+
if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {
|
|
19
|
+
setActive((activeIndex + 1) % focusable.length);
|
|
20
|
+
}
|
|
21
|
+
else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {
|
|
22
|
+
setActive((activeIndex - 1 + focusable.length) % focusable.length);
|
|
23
|
+
}
|
|
24
|
+
else if (e.key === 'Home') {
|
|
25
|
+
setActive(0);
|
|
26
|
+
}
|
|
27
|
+
else if (e.key === 'End') {
|
|
28
|
+
setActive(focusable.length - 1);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
container.addEventListener('keydown', handleKeyDown);
|
|
32
|
+
return () => container.removeEventListener('keydown', handleKeyDown);
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=roving-tabindex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roving-tabindex.js","sourceRoot":"","sources":["../../src/focus/roving-tabindex.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,cAAc,CAAC,SAAsB,EAAE,OAAkC;IACvF,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAC1B,SAAS,CAAC,gBAAgB,CACxB,4JAA4J,CAC7J,CACF,CAAC;IACF,IAAI,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,CAAC,CAAC;IAE5C,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,EAAE;QAClC,WAAW,GAAG,KAAK,CAAC;QACpB,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;YAC1B,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QACH,SAAS,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC,CAAC;IAEF,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,SAAS,CAAC,WAAW,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,aAAa,GAAG,CAAC,CAAgB,EAAE,EAAE;QACzC,IAAI,CAAC,CAAC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;YAAE,OAAO;QAChG,CAAC,CAAC,cAAc,EAAE,CAAC;QAEnB,IAAI,CAAC,CAAC,GAAG,KAAK,YAAY,IAAI,CAAC,CAAC,GAAG,KAAK,WAAW,EAAE,CAAC;YACpD,SAAS,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAClD,CAAC;aAAM,IAAI,CAAC,CAAC,GAAG,KAAK,WAAW,IAAI,CAAC,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YACxD,SAAS,CAAC,CAAC,WAAW,GAAG,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QACrE,CAAC;aAAM,IAAI,CAAC,CAAC,GAAG,KAAK,MAAM,EAAE,CAAC;YAC5B,SAAS,CAAC,CAAC,CAAC,CAAC;QACf,CAAC;aAAM,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK,EAAE,CAAC;YAC3B,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAClC,CAAC;IACH,CAAC,CAAC;IAEF,SAAS,CAAC,gBAAgB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACrD,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,mBAAmB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracks whether focus was triggered via keyboard input and applies
|
|
3
|
+
* the `focus-visible` class accordingly — matching the CSS :focus-visible spec.
|
|
4
|
+
* Returns a cleanup function to remove all listeners.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useFocusVisible(element: HTMLElement): () => void;
|
|
7
|
+
//# sourceMappingURL=use-focus-visible.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-focus-visible.d.ts","sourceRoot":"","sources":["../../src/focus/use-focus-visible.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,IAAI,CAsChE"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracks whether focus was triggered via keyboard input and applies
|
|
3
|
+
* the `focus-visible` class accordingly — matching the CSS :focus-visible spec.
|
|
4
|
+
* Returns a cleanup function to remove all listeners.
|
|
5
|
+
*/
|
|
6
|
+
export function useFocusVisible(element) {
|
|
7
|
+
let hadKeyboardEvent = false;
|
|
8
|
+
const onPointerDown = () => {
|
|
9
|
+
hadKeyboardEvent = false;
|
|
10
|
+
};
|
|
11
|
+
const onKeyDown = (e) => {
|
|
12
|
+
// Ignore modifier-only keypresses
|
|
13
|
+
if (!['Tab', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Enter', ' '].includes(e.key))
|
|
14
|
+
return;
|
|
15
|
+
hadKeyboardEvent = true;
|
|
16
|
+
};
|
|
17
|
+
const onFocus = (e) => {
|
|
18
|
+
const target = e.target;
|
|
19
|
+
if (target && hadKeyboardEvent) {
|
|
20
|
+
target.classList.add('focus-visible');
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const onBlur = (e) => {
|
|
24
|
+
const target = e.target;
|
|
25
|
+
if (target) {
|
|
26
|
+
target.classList.remove('focus-visible');
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
element.addEventListener('pointerdown', onPointerDown, true);
|
|
30
|
+
element.addEventListener('keydown', onKeyDown, true);
|
|
31
|
+
element.addEventListener('focus', onFocus, true);
|
|
32
|
+
element.addEventListener('blur', onBlur, true);
|
|
33
|
+
return () => {
|
|
34
|
+
element.removeEventListener('pointerdown', onPointerDown, true);
|
|
35
|
+
element.removeEventListener('keydown', onKeyDown, true);
|
|
36
|
+
element.removeEventListener('focus', onFocus, true);
|
|
37
|
+
element.removeEventListener('blur', onBlur, true);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=use-focus-visible.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-focus-visible.js","sourceRoot":"","sources":["../../src/focus/use-focus-visible.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,OAAoB;IAClD,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAE7B,MAAM,aAAa,GAAG,GAAG,EAAE;QACzB,gBAAgB,GAAG,KAAK,CAAC;IAC3B,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,CAAC,CAAgB,EAAE,EAAE;QACrC,kCAAkC;QAClC,IAAI,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;YAAE,OAAO;QACtG,gBAAgB,GAAG,IAAI,CAAC;IAC1B,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,CAAC,CAAa,EAAE,EAAE;QAChC,MAAM,MAAM,GAAG,CAAC,CAAC,MAA4B,CAAC;QAC9C,IAAI,MAAM,IAAI,gBAAgB,EAAE,CAAC;YAC/B,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QACxC,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,CAAC,CAAa,EAAE,EAAE;QAC/B,MAAM,MAAM,GAAG,CAAC,CAAC,MAA4B,CAAC;QAC9C,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,EAAE,IAAI,CAAC,CAAC;IAC7D,OAAO,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IACrD,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACjD,OAAO,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAE/C,OAAO,GAAG,EAAE;QACV,OAAO,CAAC,mBAAmB,CAAC,aAAa,EAAE,aAAa,EAAE,IAAI,CAAC,CAAC;QAChE,OAAO,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QACxD,OAAO,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QACpD,OAAO,CAAC,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './primitives/button/index.js';
|
|
2
|
+
export * from './focus/focus-trap.js';
|
|
3
|
+
export * from './focus/roving-tabindex.js';
|
|
4
|
+
export * from './focus/use-focus-visible.js';
|
|
5
|
+
export * from './a11y/aria-helpers.js';
|
|
6
|
+
export * from './a11y/id-generator.js';
|
|
7
|
+
export * from './state/controllable-state.js';
|
|
8
|
+
export * from './state/create-machine.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,2BAA2B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './primitives/button/index.js';
|
|
2
|
+
export * from './focus/focus-trap.js';
|
|
3
|
+
export * from './focus/roving-tabindex.js';
|
|
4
|
+
export * from './focus/use-focus-visible.js';
|
|
5
|
+
export * from './a11y/aria-helpers.js';
|
|
6
|
+
export * from './a11y/id-generator.js';
|
|
7
|
+
export * from './state/controllable-state.js';
|
|
8
|
+
export * from './state/create-machine.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ButtonContext } from './button.types.js';
|
|
2
|
+
type ButtonState = 'idle' | 'pressed';
|
|
3
|
+
export declare const buttonMachine: import("../../state/create-machine.js").MachineInstance<ButtonState, "PRESS" | "RELEASE", ButtonContext>;
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=button.machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.machine.d.ts","sourceRoot":"","sources":["../../../src/primitives/button/button.machine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,mBAAmB,CAAC;AAEpE,KAAK,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;AAGtC,eAAO,MAAM,aAAa,0GAQxB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createMachine } from '../../state/create-machine.js';
|
|
2
|
+
export const buttonMachine = createMachine({
|
|
3
|
+
id: 'button',
|
|
4
|
+
initial: 'idle',
|
|
5
|
+
context: { disabled: false },
|
|
6
|
+
states: {
|
|
7
|
+
idle: { PRESS: 'pressed' },
|
|
8
|
+
pressed: { RELEASE: 'idle' },
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
//# sourceMappingURL=button.machine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.machine.js","sourceRoot":"","sources":["../../../src/primitives/button/button.machine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAM9D,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAA8C;IACtF,EAAE,EAAE,QAAQ;IACZ,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE;IAC5B,MAAM,EAAE;QACN,IAAI,EAAK,EAAE,KAAK,EAAE,SAAS,EAAE;QAC7B,OAAO,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;KAC7B;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.types.d.ts","sourceRoot":"","sources":["../../../src/primitives/button/button.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.types.js","sourceRoot":"","sources":["../../../src/primitives/button/button.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/primitives/button/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/primitives/button/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Determines whether a value is controlled (externally managed) or uncontrolled.
|
|
3
|
+
* Returns the resolved value and a no-op setter indicator for framework adapters.
|
|
4
|
+
*
|
|
5
|
+
* Framework adapters (e.g. react/) are responsible for implementing
|
|
6
|
+
* useControllableState using this utility as a type helper.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isControlled<T>(value: T | undefined): value is T;
|
|
9
|
+
/**
|
|
10
|
+
* Resolves the initial state for an uncontrolled component.
|
|
11
|
+
* If `controlled` is defined, returns it directly.
|
|
12
|
+
* Otherwise returns `defaultValue`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveInitialState<T>(controlled: T | undefined, defaultValue: T): T;
|
|
15
|
+
//# sourceMappingURL=controllable-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controllable-state.d.ts","sourceRoot":"","sources":["../../src/state/controllable-state.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,KAAK,IAAI,CAAC,CAEhE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,GAAG,SAAS,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC,CAEpF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Determines whether a value is controlled (externally managed) or uncontrolled.
|
|
3
|
+
* Returns the resolved value and a no-op setter indicator for framework adapters.
|
|
4
|
+
*
|
|
5
|
+
* Framework adapters (e.g. react/) are responsible for implementing
|
|
6
|
+
* useControllableState using this utility as a type helper.
|
|
7
|
+
*/
|
|
8
|
+
export function isControlled(value) {
|
|
9
|
+
return typeof value !== 'undefined';
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Resolves the initial state for an uncontrolled component.
|
|
13
|
+
* If `controlled` is defined, returns it directly.
|
|
14
|
+
* Otherwise returns `defaultValue`.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveInitialState(controlled, defaultValue) {
|
|
17
|
+
return isControlled(controlled) ? controlled : defaultValue;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=controllable-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controllable-state.js","sourceRoot":"","sources":["../../src/state/controllable-state.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAI,KAAoB;IAClD,OAAO,OAAO,KAAK,KAAK,WAAW,CAAC;AACtC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAI,UAAyB,EAAE,YAAe;IAC/E,OAAO,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight state machine factory — no external dependencies.
|
|
3
|
+
* A minimal alternative to XState for simple state transitions.
|
|
4
|
+
*/
|
|
5
|
+
export type Transition<S extends string, E extends string> = {
|
|
6
|
+
[state in S]?: {
|
|
7
|
+
[event in E]?: S;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
export interface MachineConfig<S extends string, E extends string, C> {
|
|
11
|
+
id: string;
|
|
12
|
+
initial: S;
|
|
13
|
+
context: C;
|
|
14
|
+
states: Transition<S, E>;
|
|
15
|
+
}
|
|
16
|
+
export interface MachineInstance<S extends string, E extends string, C> {
|
|
17
|
+
id: string;
|
|
18
|
+
initialState: S;
|
|
19
|
+
initialContext: C;
|
|
20
|
+
transition: (state: S, event: E) => S;
|
|
21
|
+
}
|
|
22
|
+
export declare function createMachine<S extends string, E extends string, C>(config: MachineConfig<S, E, C>): MachineInstance<S, E, C>;
|
|
23
|
+
/** No-op assign helper for API compatibility */
|
|
24
|
+
export declare function assign<C>(updater: Partial<C> | ((ctx: C) => Partial<C>)): typeof updater;
|
|
25
|
+
/** No-op setup helper for API compatibility */
|
|
26
|
+
export declare function setup<_T>(_config: _T): {
|
|
27
|
+
createMachine: typeof createMachine;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=create-machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-machine.d.ts","sourceRoot":"","sources":["../../src/state/create-machine.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,IAAI;KAC1D,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE;SAAG,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;KAAE;CACpC,CAAC;AAEF,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC;IACpE,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,CAAC,CAAC;IAChB,cAAc,EAAE,CAAC,CAAC;IAClB,UAAU,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;CACvC;AAED,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,EACjE,MAAM,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAC7B,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAS1B;AAED,gDAAgD;AAChD,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,OAAO,CAExF;AAED,+CAA+C;AAC/C,wBAAgB,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,GAAG;IAAE,aAAa,EAAE,OAAO,aAAa,CAAA;CAAE,CAE9E"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight state machine factory — no external dependencies.
|
|
3
|
+
* A minimal alternative to XState for simple state transitions.
|
|
4
|
+
*/
|
|
5
|
+
export function createMachine(config) {
|
|
6
|
+
return {
|
|
7
|
+
id: config.id,
|
|
8
|
+
initialState: config.initial,
|
|
9
|
+
initialContext: config.context,
|
|
10
|
+
transition(state, event) {
|
|
11
|
+
return config.states[state]?.[event] ?? state;
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/** No-op assign helper for API compatibility */
|
|
16
|
+
export function assign(updater) {
|
|
17
|
+
return updater;
|
|
18
|
+
}
|
|
19
|
+
/** No-op setup helper for API compatibility */
|
|
20
|
+
export function setup(_config) {
|
|
21
|
+
return { createMachine };
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=create-machine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-machine.js","sourceRoot":"","sources":["../../src/state/create-machine.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoBH,MAAM,UAAU,aAAa,CAC3B,MAA8B;IAE9B,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,YAAY,EAAE,MAAM,CAAC,OAAO;QAC5B,cAAc,EAAE,MAAM,CAAC,OAAO;QAC9B,UAAU,CAAC,KAAQ,EAAE,KAAQ;YAC3B,OAAQ,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAmB,IAAI,KAAK,CAAC;QACnE,CAAC;KACF,CAAC;AACJ,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,MAAM,CAAI,OAA8C;IACtE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,KAAK,CAAK,OAAW;IACnC,OAAO,EAAE,aAAa,EAAE,CAAC;AAC3B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tokis/core",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Framework-agnostic headless primitives for Tokis — state machines, accessibility helpers, and focus management. Zero dependencies.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/cjs/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"require": "./dist/cjs/index.js",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc && tsc -p tsconfig.cjs.json && node ../../scripts/stamp-cjs.js",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"prepack": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"tokis",
|
|
29
|
+
"design-system",
|
|
30
|
+
"headless",
|
|
31
|
+
"headless-ui",
|
|
32
|
+
"accessibility",
|
|
33
|
+
"a11y",
|
|
34
|
+
"aria",
|
|
35
|
+
"wcag",
|
|
36
|
+
"state-machine",
|
|
37
|
+
"focus-management",
|
|
38
|
+
"focus-trap",
|
|
39
|
+
"roving-tabindex",
|
|
40
|
+
"framework-agnostic",
|
|
41
|
+
"typescript",
|
|
42
|
+
"zero-dependencies"
|
|
43
|
+
],
|
|
44
|
+
"author": "Tokis Contributors",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/tokis-design/tokis.git",
|
|
49
|
+
"directory": "packages/core"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://tokis.dev",
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/tokis-design/tokis/issues"
|
|
54
|
+
},
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public",
|
|
57
|
+
"registry": "https://registry.npmjs.org/"
|
|
58
|
+
}
|
|
59
|
+
}
|