@tokis/core 1.0.1 → 1.1.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/README.md +5 -5
- package/dist/__tests__/accordion.test.d.ts +2 -0
- package/dist/__tests__/accordion.test.d.ts.map +1 -0
- package/dist/__tests__/accordion.test.js +127 -0
- package/dist/__tests__/accordion.test.js.map +1 -0
- package/dist/__tests__/create-machine.test.d.ts +2 -0
- package/dist/__tests__/create-machine.test.d.ts.map +1 -0
- package/dist/__tests__/create-machine.test.js +79 -0
- package/dist/__tests__/create-machine.test.js.map +1 -0
- package/dist/__tests__/dialog.test.d.ts +2 -0
- package/dist/__tests__/dialog.test.d.ts.map +1 -0
- package/dist/__tests__/dialog.test.js +74 -0
- package/dist/__tests__/dialog.test.js.map +1 -0
- package/dist/__tests__/menu.test.d.ts +2 -0
- package/dist/__tests__/menu.test.d.ts.map +1 -0
- package/dist/__tests__/menu.test.js +177 -0
- package/dist/__tests__/menu.test.js.map +1 -0
- package/dist/__tests__/tabs.test.d.ts +2 -0
- package/dist/__tests__/tabs.test.d.ts.map +1 -0
- package/dist/__tests__/tabs.test.js +147 -0
- package/dist/__tests__/tabs.test.js.map +1 -0
- package/dist/cjs/__tests__/accordion.test.js +128 -0
- package/dist/cjs/__tests__/create-machine.test.js +80 -0
- package/dist/cjs/__tests__/dialog.test.js +75 -0
- package/dist/cjs/__tests__/menu.test.js +178 -0
- package/dist/cjs/__tests__/tabs.test.js +148 -0
- package/dist/cjs/index.js +9 -0
- package/dist/cjs/primitives/accordion/accordion.machine.js +109 -0
- package/dist/cjs/primitives/accordion/accordion.types.js +6 -0
- package/dist/cjs/primitives/accordion/index.js +18 -0
- package/dist/cjs/primitives/dialog/dialog.machine.js +62 -0
- package/dist/cjs/primitives/dialog/dialog.types.js +6 -0
- package/dist/cjs/primitives/dialog/index.js +18 -0
- package/dist/cjs/primitives/menu/index.js +18 -0
- package/dist/cjs/primitives/menu/menu.machine.js +135 -0
- package/dist/cjs/primitives/menu/menu.types.js +6 -0
- package/dist/cjs/primitives/popover/index.js +18 -0
- package/dist/cjs/primitives/popover/popover.machine.js +87 -0
- package/dist/cjs/primitives/popover/popover.types.js +7 -0
- package/dist/cjs/primitives/tabs/index.js +18 -0
- package/dist/cjs/primitives/tabs/tabs.machine.js +124 -0
- package/dist/cjs/primitives/tabs/tabs.types.js +6 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/primitives/accordion/accordion.machine.d.ts +22 -0
- package/dist/primitives/accordion/accordion.machine.d.ts.map +1 -0
- package/dist/primitives/accordion/accordion.machine.js +103 -0
- package/dist/primitives/accordion/accordion.machine.js.map +1 -0
- package/dist/primitives/accordion/accordion.types.d.ts +28 -0
- package/dist/primitives/accordion/accordion.types.d.ts.map +1 -0
- package/dist/primitives/accordion/accordion.types.js +6 -0
- package/dist/primitives/accordion/accordion.types.js.map +1 -0
- package/dist/primitives/accordion/index.d.ts +3 -0
- package/dist/primitives/accordion/index.d.ts.map +1 -0
- package/dist/primitives/accordion/index.js +3 -0
- package/dist/primitives/accordion/index.js.map +1 -0
- package/dist/primitives/dialog/dialog.machine.d.ts +23 -0
- package/dist/primitives/dialog/dialog.machine.d.ts.map +1 -0
- package/dist/primitives/dialog/dialog.machine.js +58 -0
- package/dist/primitives/dialog/dialog.machine.js.map +1 -0
- package/dist/primitives/dialog/dialog.types.d.ts +25 -0
- package/dist/primitives/dialog/dialog.types.d.ts.map +1 -0
- package/dist/primitives/dialog/dialog.types.js +6 -0
- package/dist/primitives/dialog/dialog.types.js.map +1 -0
- package/dist/primitives/dialog/index.d.ts +3 -0
- package/dist/primitives/dialog/index.d.ts.map +1 -0
- package/dist/primitives/dialog/index.js +3 -0
- package/dist/primitives/dialog/index.js.map +1 -0
- package/dist/primitives/menu/index.d.ts +3 -0
- package/dist/primitives/menu/index.d.ts.map +1 -0
- package/dist/primitives/menu/index.js +3 -0
- package/dist/primitives/menu/index.js.map +1 -0
- package/dist/primitives/menu/menu.machine.d.ts +25 -0
- package/dist/primitives/menu/menu.machine.d.ts.map +1 -0
- package/dist/primitives/menu/menu.machine.js +129 -0
- package/dist/primitives/menu/menu.machine.js.map +1 -0
- package/dist/primitives/menu/menu.types.d.ts +30 -0
- package/dist/primitives/menu/menu.types.d.ts.map +1 -0
- package/dist/primitives/menu/menu.types.js +6 -0
- package/dist/primitives/menu/menu.types.js.map +1 -0
- package/dist/primitives/popover/index.d.ts +3 -0
- package/dist/primitives/popover/index.d.ts.map +1 -0
- package/dist/primitives/popover/index.js +3 -0
- package/dist/primitives/popover/index.js.map +1 -0
- package/dist/primitives/popover/popover.machine.d.ts +30 -0
- package/dist/primitives/popover/popover.machine.d.ts.map +1 -0
- package/dist/primitives/popover/popover.machine.js +80 -0
- package/dist/primitives/popover/popover.machine.js.map +1 -0
- package/dist/primitives/popover/popover.types.d.ts +34 -0
- package/dist/primitives/popover/popover.types.d.ts.map +1 -0
- package/dist/primitives/popover/popover.types.js +7 -0
- package/dist/primitives/popover/popover.types.js.map +1 -0
- package/dist/primitives/tabs/index.d.ts +3 -0
- package/dist/primitives/tabs/index.d.ts.map +1 -0
- package/dist/primitives/tabs/index.js +3 -0
- package/dist/primitives/tabs/index.js.map +1 -0
- package/dist/primitives/tabs/tabs.machine.d.ts +25 -0
- package/dist/primitives/tabs/tabs.machine.d.ts.map +1 -0
- package/dist/primitives/tabs/tabs.machine.js +117 -0
- package/dist/primitives/tabs/tabs.machine.js.map +1 -0
- package/dist/primitives/tabs/tabs.types.d.ts +34 -0
- package/dist/primitives/tabs/tabs.types.d.ts.map +1 -0
- package/dist/primitives/tabs/tabs.types.js +6 -0
- package/dist/primitives/tabs/tabs.types.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { createMachine } from '../../state/create-machine.js';
|
|
2
|
+
/**
|
|
3
|
+
* Menu state machine.
|
|
4
|
+
*
|
|
5
|
+
* Transition table:
|
|
6
|
+
* closed + OPEN → open
|
|
7
|
+
* closed + TOGGLE → open
|
|
8
|
+
* open + CLOSE → closed
|
|
9
|
+
* open + TOGGLE → closed
|
|
10
|
+
* open + SELECT_ITEM → closed
|
|
11
|
+
* (all other events keep current state, context mutated via helpers)
|
|
12
|
+
*/
|
|
13
|
+
export const menuMachine = createMachine({
|
|
14
|
+
id: 'menu',
|
|
15
|
+
initial: 'closed',
|
|
16
|
+
context: {
|
|
17
|
+
triggerId: 'menu-trigger',
|
|
18
|
+
items: [],
|
|
19
|
+
activeItemId: null,
|
|
20
|
+
searchBuffer: '',
|
|
21
|
+
loop: true,
|
|
22
|
+
},
|
|
23
|
+
states: {
|
|
24
|
+
closed: {
|
|
25
|
+
OPEN: 'open',
|
|
26
|
+
TOGGLE: 'open',
|
|
27
|
+
},
|
|
28
|
+
open: {
|
|
29
|
+
CLOSE: 'closed',
|
|
30
|
+
TOGGLE: 'closed',
|
|
31
|
+
SELECT_ITEM: 'closed',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
// ─── Pure context helpers ──────────────────────────────────────────────────
|
|
36
|
+
function enabledItems(items) {
|
|
37
|
+
return items.filter((i) => !i.disabled);
|
|
38
|
+
}
|
|
39
|
+
function getActiveIndex(ctx) {
|
|
40
|
+
if (!ctx.activeItemId)
|
|
41
|
+
return -1;
|
|
42
|
+
return enabledItems(ctx.items).findIndex((i) => i.id === ctx.activeItemId);
|
|
43
|
+
}
|
|
44
|
+
/** Handles navigation and search events, returning updated context fields. */
|
|
45
|
+
export function reduceMenuContext(ctx, event, payload) {
|
|
46
|
+
const enabled = enabledItems(ctx.items);
|
|
47
|
+
switch (event) {
|
|
48
|
+
case 'OPEN': {
|
|
49
|
+
// Focus first item on open
|
|
50
|
+
const first = enabled[0];
|
|
51
|
+
return { activeItemId: first?.id ?? null, searchBuffer: '' };
|
|
52
|
+
}
|
|
53
|
+
case 'CLOSE':
|
|
54
|
+
case 'TOGGLE': {
|
|
55
|
+
return { activeItemId: null, searchBuffer: '' };
|
|
56
|
+
}
|
|
57
|
+
case 'FOCUS_ITEM': {
|
|
58
|
+
return { activeItemId: payload?.itemId ?? null };
|
|
59
|
+
}
|
|
60
|
+
case 'SELECT_ITEM': {
|
|
61
|
+
return { activeItemId: null, searchBuffer: '' };
|
|
62
|
+
}
|
|
63
|
+
case 'NEXT_ITEM': {
|
|
64
|
+
const idx = getActiveIndex(ctx);
|
|
65
|
+
let next = idx + 1;
|
|
66
|
+
if (next >= enabled.length)
|
|
67
|
+
next = ctx.loop ? 0 : enabled.length - 1;
|
|
68
|
+
return { activeItemId: enabled[next]?.id ?? null };
|
|
69
|
+
}
|
|
70
|
+
case 'PREV_ITEM': {
|
|
71
|
+
const idx = getActiveIndex(ctx);
|
|
72
|
+
let prev = idx - 1;
|
|
73
|
+
if (prev < 0)
|
|
74
|
+
prev = ctx.loop ? enabled.length - 1 : 0;
|
|
75
|
+
return { activeItemId: enabled[prev]?.id ?? null };
|
|
76
|
+
}
|
|
77
|
+
case 'FIRST_ITEM': {
|
|
78
|
+
return { activeItemId: enabled[0]?.id ?? null };
|
|
79
|
+
}
|
|
80
|
+
case 'LAST_ITEM': {
|
|
81
|
+
return { activeItemId: enabled[enabled.length - 1]?.id ?? null };
|
|
82
|
+
}
|
|
83
|
+
case 'SEARCH': {
|
|
84
|
+
const char = (payload?.char ?? '').toLowerCase();
|
|
85
|
+
if (!char)
|
|
86
|
+
return {};
|
|
87
|
+
// Accumulate typeahead buffer (cleared by timeout in adapter)
|
|
88
|
+
const buffer = ctx.searchBuffer + char;
|
|
89
|
+
const currentIdx = getActiveIndex(ctx);
|
|
90
|
+
// Find next item starting with buffer, searching from after current
|
|
91
|
+
const startIdx = currentIdx + 1;
|
|
92
|
+
const rotated = [...enabled.slice(startIdx), ...enabled.slice(0, startIdx)];
|
|
93
|
+
const match = rotated.find((i) => i.label.toLowerCase().startsWith(buffer));
|
|
94
|
+
return {
|
|
95
|
+
searchBuffer: buffer,
|
|
96
|
+
activeItemId: match?.id ?? ctx.activeItemId,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
default:
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** ARIA attributes for the menu trigger button. */
|
|
104
|
+
export function getMenuTriggerAriaProps(state, ctx, menuId) {
|
|
105
|
+
return {
|
|
106
|
+
'aria-haspopup': 'menu',
|
|
107
|
+
'aria-expanded': state === 'open',
|
|
108
|
+
'aria-controls': menuId,
|
|
109
|
+
id: ctx.triggerId,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/** ARIA attributes for the menu container (ul element). */
|
|
113
|
+
export function getMenuAriaProps(ctx, menuId) {
|
|
114
|
+
return {
|
|
115
|
+
role: 'menu',
|
|
116
|
+
id: menuId,
|
|
117
|
+
'aria-labelledby': ctx.triggerId,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/** ARIA attributes for a single menu item. */
|
|
121
|
+
export function getMenuItemAriaProps(ctx, item) {
|
|
122
|
+
return {
|
|
123
|
+
role: 'menuitem',
|
|
124
|
+
id: item.id,
|
|
125
|
+
'aria-disabled': item.disabled ?? false,
|
|
126
|
+
tabIndex: ctx.activeItemId === item.id ? 0 : -1,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=menu.machine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu.machine.js","sourceRoot":"","sources":["../../../src/primitives/menu/menu.machine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Menu / DropdownMenu state machine types.
|
|
3
|
+
* Implements the WAI-ARIA Menu Button pattern.
|
|
4
|
+
*/
|
|
5
|
+
export type MenuState = 'closed' | 'open';
|
|
6
|
+
export type MenuEventType = 'OPEN' | 'CLOSE' | 'TOGGLE' | 'FOCUS_ITEM' | 'NEXT_ITEM' | 'PREV_ITEM' | 'FIRST_ITEM' | 'LAST_ITEM' | 'SELECT_ITEM' | 'SEARCH';
|
|
7
|
+
export interface MenuEvent {
|
|
8
|
+
type: MenuEventType;
|
|
9
|
+
itemId?: string;
|
|
10
|
+
/** For SEARCH: the character typed */
|
|
11
|
+
char?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface MenuItemDescriptor {
|
|
14
|
+
id: string;
|
|
15
|
+
label: string;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface MenuContext {
|
|
19
|
+
/** Trigger element id (for aria-labelledby on the menu) */
|
|
20
|
+
triggerId: string;
|
|
21
|
+
/** All menu item descriptors in display order */
|
|
22
|
+
items: MenuItemDescriptor[];
|
|
23
|
+
/** Id of the currently focused item (-1 when none) */
|
|
24
|
+
activeItemId: string | null;
|
|
25
|
+
/** Accumulated typeahead search string */
|
|
26
|
+
searchBuffer: string;
|
|
27
|
+
/** Loop from last item back to first */
|
|
28
|
+
loop: boolean;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=menu.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu.types.d.ts","sourceRoot":"","sources":["../../../src/primitives/menu/menu.types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,SAAS,GACjB,QAAQ,GACR,MAAM,CAAC;AAEX,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,OAAO,GACP,QAAQ,GACR,YAAY,GACZ,WAAW,GACX,WAAW,GACX,YAAY,GACZ,WAAW,GACX,aAAa,GACb,QAAQ,CAAC;AAEb,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,sDAAsD;IACtD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,IAAI,EAAE,OAAO,CAAC;CACf"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu.types.js","sourceRoot":"","sources":["../../../src/primitives/menu/menu.types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/primitives/popover/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/primitives/popover/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PopoverContext, PopoverState, PopoverEventType } from './popover.types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Popover state machine.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the Dialog machine's animated open/close cycle but without
|
|
6
|
+
* modal focus trapping — the popover is non-modal by default.
|
|
7
|
+
*
|
|
8
|
+
* Transition table:
|
|
9
|
+
* closed + OPEN → opening (animated) | open (instant)
|
|
10
|
+
* opening + ANIMATION_END → open
|
|
11
|
+
* opening + CLOSE → closed (cancel open)
|
|
12
|
+
* open + CLOSE → closing (animated) | closed (instant)
|
|
13
|
+
* open + TOGGLE → closing (animated) | closed (instant)
|
|
14
|
+
* closing + ANIMATION_END → closed
|
|
15
|
+
* closing + OPEN → opening (re-open mid-close)
|
|
16
|
+
* closing + TOGGLE → opening (re-open mid-close)
|
|
17
|
+
* closed + TOGGLE → opening (animated) | open (instant)
|
|
18
|
+
*/
|
|
19
|
+
export declare const popoverMachine: import("../../state/create-machine.js").MachineInstance<PopoverState, PopoverEventType, PopoverContext>;
|
|
20
|
+
/** Whether the popover DOM node should be present (mounted). */
|
|
21
|
+
export declare function isPopoverMounted(state: PopoverState): boolean;
|
|
22
|
+
/** Whether the popover is visible (aria-expanded). */
|
|
23
|
+
export declare function isPopoverOpen(state: PopoverState): boolean;
|
|
24
|
+
/** `data-state` attribute value for CSS animation hooks. */
|
|
25
|
+
export declare function getPopoverDataState(state: PopoverState): 'open' | 'closed';
|
|
26
|
+
/** ARIA attributes for the trigger element. */
|
|
27
|
+
export declare function getPopoverTriggerAriaProps(state: PopoverState, ctx: PopoverContext): Record<string, string | boolean>;
|
|
28
|
+
/** ARIA attributes for the popover container element. */
|
|
29
|
+
export declare function getPopoverAriaProps(ctx: PopoverContext): Record<string, string>;
|
|
30
|
+
//# sourceMappingURL=popover.machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popover.machine.d.ts","sourceRoot":"","sources":["../../../src/primitives/popover/popover.machine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEzF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,cAAc,yGA8BzB,CAAC;AAIH,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAE7D;AAED,sDAAsD;AACtD,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAE1D;AAED,4DAA4D;AAC5D,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,QAAQ,CAE1E;AAED,+CAA+C;AAC/C,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,cAAc,GAClB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAOlC;AAED,yDAAyD;AACzD,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,cAAc,GAClB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMxB"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { createMachine } from '../../state/create-machine.js';
|
|
2
|
+
/**
|
|
3
|
+
* Popover state machine.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the Dialog machine's animated open/close cycle but without
|
|
6
|
+
* modal focus trapping — the popover is non-modal by default.
|
|
7
|
+
*
|
|
8
|
+
* Transition table:
|
|
9
|
+
* closed + OPEN → opening (animated) | open (instant)
|
|
10
|
+
* opening + ANIMATION_END → open
|
|
11
|
+
* opening + CLOSE → closed (cancel open)
|
|
12
|
+
* open + CLOSE → closing (animated) | closed (instant)
|
|
13
|
+
* open + TOGGLE → closing (animated) | closed (instant)
|
|
14
|
+
* closing + ANIMATION_END → closed
|
|
15
|
+
* closing + OPEN → opening (re-open mid-close)
|
|
16
|
+
* closing + TOGGLE → opening (re-open mid-close)
|
|
17
|
+
* closed + TOGGLE → opening (animated) | open (instant)
|
|
18
|
+
*/
|
|
19
|
+
export const popoverMachine = createMachine({
|
|
20
|
+
id: 'popover',
|
|
21
|
+
initial: 'closed',
|
|
22
|
+
context: {
|
|
23
|
+
id: 'popover',
|
|
24
|
+
triggerId: 'popover-trigger',
|
|
25
|
+
placement: 'bottom',
|
|
26
|
+
closeOnClickOutside: true,
|
|
27
|
+
closeOnEscape: true,
|
|
28
|
+
animated: true,
|
|
29
|
+
},
|
|
30
|
+
states: {
|
|
31
|
+
closed: {
|
|
32
|
+
OPEN: 'opening',
|
|
33
|
+
TOGGLE: 'opening',
|
|
34
|
+
},
|
|
35
|
+
opening: {
|
|
36
|
+
ANIMATION_END: 'open',
|
|
37
|
+
CLOSE: 'closed',
|
|
38
|
+
},
|
|
39
|
+
open: {
|
|
40
|
+
CLOSE: 'closing',
|
|
41
|
+
TOGGLE: 'closing',
|
|
42
|
+
},
|
|
43
|
+
closing: {
|
|
44
|
+
ANIMATION_END: 'closed',
|
|
45
|
+
OPEN: 'opening',
|
|
46
|
+
TOGGLE: 'opening',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
// ─── Derived state helpers ─────────────────────────────────────────────────
|
|
51
|
+
/** Whether the popover DOM node should be present (mounted). */
|
|
52
|
+
export function isPopoverMounted(state) {
|
|
53
|
+
return state === 'open' || state === 'opening' || state === 'closing';
|
|
54
|
+
}
|
|
55
|
+
/** Whether the popover is visible (aria-expanded). */
|
|
56
|
+
export function isPopoverOpen(state) {
|
|
57
|
+
return state === 'open' || state === 'opening';
|
|
58
|
+
}
|
|
59
|
+
/** `data-state` attribute value for CSS animation hooks. */
|
|
60
|
+
export function getPopoverDataState(state) {
|
|
61
|
+
return isPopoverOpen(state) ? 'open' : 'closed';
|
|
62
|
+
}
|
|
63
|
+
/** ARIA attributes for the trigger element. */
|
|
64
|
+
export function getPopoverTriggerAriaProps(state, ctx) {
|
|
65
|
+
return {
|
|
66
|
+
id: ctx.triggerId,
|
|
67
|
+
'aria-expanded': isPopoverOpen(state),
|
|
68
|
+
'aria-controls': ctx.id,
|
|
69
|
+
'aria-haspopup': 'dialog',
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** ARIA attributes for the popover container element. */
|
|
73
|
+
export function getPopoverAriaProps(ctx) {
|
|
74
|
+
return {
|
|
75
|
+
id: ctx.id,
|
|
76
|
+
role: 'dialog',
|
|
77
|
+
'aria-labelledby': ctx.triggerId,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=popover.machine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popover.machine.js","sourceRoot":"","sources":["../../../src/primitives/popover/popover.machine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAG9D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,aAAa,CAAiD;IAC1F,EAAE,EAAE,SAAS;IACb,OAAO,EAAE,QAAQ;IACjB,OAAO,EAAE;QACP,EAAE,EAAE,SAAS;QACb,SAAS,EAAE,iBAAiB;QAC5B,SAAS,EAAE,QAAQ;QACnB,mBAAmB,EAAE,IAAI;QACzB,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,IAAI;KACf;IACD,MAAM,EAAE;QACN,MAAM,EAAE;YACN,IAAI,EAAI,SAAS;YACjB,MAAM,EAAE,SAAS;SAClB;QACD,OAAO,EAAE;YACP,aAAa,EAAE,MAAM;YACrB,KAAK,EAAU,QAAQ;SACxB;QACD,IAAI,EAAE;YACJ,KAAK,EAAG,SAAS;YACjB,MAAM,EAAE,SAAS;SAClB;QACD,OAAO,EAAE;YACP,aAAa,EAAE,QAAQ;YACvB,IAAI,EAAW,SAAS;YACxB,MAAM,EAAS,SAAS;SACzB;KACF;CACF,CAAC,CAAC;AAEH,8EAA8E;AAE9E,gEAAgE;AAChE,MAAM,UAAU,gBAAgB,CAAC,KAAmB;IAClD,OAAO,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,CAAC;AACxE,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,aAAa,CAAC,KAAmB;IAC/C,OAAO,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,SAAS,CAAC;AACjD,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,mBAAmB,CAAC,KAAmB;IACrD,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClD,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,0BAA0B,CACxC,KAAmB,EACnB,GAAmB;IAEnB,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,SAAS;QACjB,eAAe,EAAE,aAAa,CAAC,KAAK,CAAC;QACrC,eAAe,EAAE,GAAG,CAAC,EAAE;QACvB,eAAe,EAAE,QAAQ;KAC1B,CAAC;AACJ,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,mBAAmB,CACjC,GAAmB;IAEnB,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,iBAAiB,EAAE,GAAG,CAAC,SAAS;KACjC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Popover state machine types.
|
|
3
|
+
* Implements the WAI-ARIA Disclosure / Popover pattern.
|
|
4
|
+
* Also used by Tooltip, ColorPicker, and floating panel variants.
|
|
5
|
+
*/
|
|
6
|
+
export type PopoverState = 'closed' | 'opening' | 'open' | 'closing';
|
|
7
|
+
export type PopoverEventType = 'OPEN' | 'CLOSE' | 'TOGGLE' | 'ANIMATION_END';
|
|
8
|
+
export interface PopoverEvent {
|
|
9
|
+
type: PopoverEventType;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Placement follows the Floating UI / Popper.js convention:
|
|
13
|
+
* "top" | "top-start" | "top-end" | "bottom" | "bottom-start" | "bottom-end" |
|
|
14
|
+
* "left" | "left-start" | "left-end" | "right" | "right-start" | "right-end"
|
|
15
|
+
*/
|
|
16
|
+
export type PopoverPlacement = 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end';
|
|
17
|
+
export interface PopoverContext {
|
|
18
|
+
/** Unique id; popover element gets this id, trigger gets aria-controls=id */
|
|
19
|
+
id: string;
|
|
20
|
+
/** Id of the trigger element */
|
|
21
|
+
triggerId: string;
|
|
22
|
+
/** Desired placement relative to the trigger */
|
|
23
|
+
placement: PopoverPlacement;
|
|
24
|
+
/** Close when a click occurs outside the popover + trigger */
|
|
25
|
+
closeOnClickOutside: boolean;
|
|
26
|
+
/** Close when Escape key is pressed */
|
|
27
|
+
closeOnEscape: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Whether the popover uses CSS enter/leave animations.
|
|
30
|
+
* When false, opening/closing states are skipped.
|
|
31
|
+
*/
|
|
32
|
+
animated: boolean;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=popover.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popover.types.d.ts","sourceRoot":"","sources":["../../../src/primitives/popover/popover.types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,YAAY,GACpB,QAAQ,GACR,SAAS,GACT,MAAM,GACN,SAAS,CAAC;AAEd,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,OAAO,GACP,QAAQ,GACR,eAAe,CAAC;AAEpB,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,gBAAgB,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GACxB,KAAK,GAAG,WAAW,GAAG,SAAS,GAC/B,QAAQ,GAAG,cAAc,GAAG,YAAY,GACxC,MAAM,GAAG,YAAY,GAAG,UAAU,GAClC,OAAO,GAAG,aAAa,GAAG,WAAW,CAAC;AAE1C,MAAM,WAAW,cAAc;IAC7B,6EAA6E;IAC7E,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,SAAS,EAAE,gBAAgB,CAAC;IAC5B,8DAA8D;IAC9D,mBAAmB,EAAE,OAAO,CAAC;IAC7B,uCAAuC;IACvC,aAAa,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popover.types.js","sourceRoot":"","sources":["../../../src/primitives/popover/popover.types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/primitives/tabs/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/primitives/tabs/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { TabsContext, TabsEventType } from './tabs.types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Tabs state machine.
|
|
4
|
+
*
|
|
5
|
+
* The macro-state is always 'idle' — active/focused tab is tracked via context.
|
|
6
|
+
* Pure helper functions below handle context transitions and are designed to
|
|
7
|
+
* work with `useState` / `useReducer` in framework adapters.
|
|
8
|
+
*/
|
|
9
|
+
export declare const tabsMachine: import("../../state/create-machine.js").MachineInstance<"idle", TabsEventType, TabsContext>;
|
|
10
|
+
/** Returns the next tab id in the ordered list, with optional looping. */
|
|
11
|
+
export declare function getNextTabId(ctx: TabsContext): string;
|
|
12
|
+
/** Returns the previous tab id in the ordered list, with optional looping. */
|
|
13
|
+
export declare function getPrevTabId(ctx: TabsContext): string;
|
|
14
|
+
/**
|
|
15
|
+
* Reduces a tabs event into a new partial context.
|
|
16
|
+
* Framework adapters call this and merge the result into their state.
|
|
17
|
+
*/
|
|
18
|
+
export declare function reduceTabsContext(ctx: TabsContext, event: TabsEventType, payload?: {
|
|
19
|
+
tabId?: string;
|
|
20
|
+
}): Partial<TabsContext>;
|
|
21
|
+
/** Returns the ARIA attributes for a tab element. */
|
|
22
|
+
export declare function getTabAriaProps(ctx: TabsContext, tabId: string, panelId: string): Record<string, string | boolean | number>;
|
|
23
|
+
/** Returns the ARIA attributes for a tab panel element. */
|
|
24
|
+
export declare function getTabPanelAriaProps(ctx: TabsContext, panelId: string, tabId: string): Record<string, string | boolean | number>;
|
|
25
|
+
//# sourceMappingURL=tabs.machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tabs.machine.d.ts","sourceRoot":"","sources":["../../../src/primitives/tabs/tabs.machine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAa,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE7E;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,6FAetB,CAAC;AAIH,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAOrD;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAOrD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,aAAa,EACpB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3B,OAAO,CAAC,WAAW,CAAC,CAuCtB;AAED,qDAAqD;AACrD,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,CAQ3C;AAED,2DAA2D;AAC3D,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,CAQ3C"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { createMachine } from '../../state/create-machine.js';
|
|
2
|
+
/**
|
|
3
|
+
* Tabs state machine.
|
|
4
|
+
*
|
|
5
|
+
* The macro-state is always 'idle' — active/focused tab is tracked via context.
|
|
6
|
+
* Pure helper functions below handle context transitions and are designed to
|
|
7
|
+
* work with `useState` / `useReducer` in framework adapters.
|
|
8
|
+
*/
|
|
9
|
+
export const tabsMachine = createMachine({
|
|
10
|
+
id: 'tabs',
|
|
11
|
+
initial: 'idle',
|
|
12
|
+
context: {
|
|
13
|
+
tabIds: [],
|
|
14
|
+
activeTabId: '',
|
|
15
|
+
focusedTabId: '',
|
|
16
|
+
activationMode: 'automatic',
|
|
17
|
+
orientation: 'horizontal',
|
|
18
|
+
loop: true,
|
|
19
|
+
},
|
|
20
|
+
states: {
|
|
21
|
+
// All events stay in idle; context manipulation is done via helpers below.
|
|
22
|
+
idle: {},
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
// ─── Pure context helpers ──────────────────────────────────────────────────
|
|
26
|
+
/** Returns the next tab id in the ordered list, with optional looping. */
|
|
27
|
+
export function getNextTabId(ctx) {
|
|
28
|
+
const { tabIds, focusedTabId, loop } = ctx;
|
|
29
|
+
const idx = tabIds.indexOf(focusedTabId);
|
|
30
|
+
if (idx === -1)
|
|
31
|
+
return tabIds[0] ?? focusedTabId;
|
|
32
|
+
const next = idx + 1;
|
|
33
|
+
if (next >= tabIds.length)
|
|
34
|
+
return loop ? (tabIds[0] ?? focusedTabId) : (tabIds[tabIds.length - 1] ?? focusedTabId);
|
|
35
|
+
return tabIds[next] ?? focusedTabId;
|
|
36
|
+
}
|
|
37
|
+
/** Returns the previous tab id in the ordered list, with optional looping. */
|
|
38
|
+
export function getPrevTabId(ctx) {
|
|
39
|
+
const { tabIds, focusedTabId, loop } = ctx;
|
|
40
|
+
const idx = tabIds.indexOf(focusedTabId);
|
|
41
|
+
if (idx === -1)
|
|
42
|
+
return tabIds[tabIds.length - 1] ?? focusedTabId;
|
|
43
|
+
const prev = idx - 1;
|
|
44
|
+
if (prev < 0)
|
|
45
|
+
return loop ? (tabIds[tabIds.length - 1] ?? focusedTabId) : (tabIds[0] ?? focusedTabId);
|
|
46
|
+
return tabIds[prev] ?? focusedTabId;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Reduces a tabs event into a new partial context.
|
|
50
|
+
* Framework adapters call this and merge the result into their state.
|
|
51
|
+
*/
|
|
52
|
+
export function reduceTabsContext(ctx, event, payload) {
|
|
53
|
+
switch (event) {
|
|
54
|
+
case 'SELECT_TAB': {
|
|
55
|
+
const id = payload?.tabId ?? ctx.focusedTabId;
|
|
56
|
+
return { activeTabId: id, focusedTabId: id };
|
|
57
|
+
}
|
|
58
|
+
case 'FOCUS_TAB': {
|
|
59
|
+
const id = payload?.tabId ?? ctx.focusedTabId;
|
|
60
|
+
const changes = { focusedTabId: id };
|
|
61
|
+
if (ctx.activationMode === 'automatic')
|
|
62
|
+
changes.activeTabId = id;
|
|
63
|
+
return changes;
|
|
64
|
+
}
|
|
65
|
+
case 'NEXT_TAB': {
|
|
66
|
+
const id = getNextTabId(ctx);
|
|
67
|
+
const changes = { focusedTabId: id };
|
|
68
|
+
if (ctx.activationMode === 'automatic')
|
|
69
|
+
changes.activeTabId = id;
|
|
70
|
+
return changes;
|
|
71
|
+
}
|
|
72
|
+
case 'PREV_TAB': {
|
|
73
|
+
const id = getPrevTabId(ctx);
|
|
74
|
+
const changes = { focusedTabId: id };
|
|
75
|
+
if (ctx.activationMode === 'automatic')
|
|
76
|
+
changes.activeTabId = id;
|
|
77
|
+
return changes;
|
|
78
|
+
}
|
|
79
|
+
case 'FIRST_TAB': {
|
|
80
|
+
const id = ctx.tabIds[0] ?? ctx.focusedTabId;
|
|
81
|
+
const changes = { focusedTabId: id };
|
|
82
|
+
if (ctx.activationMode === 'automatic')
|
|
83
|
+
changes.activeTabId = id;
|
|
84
|
+
return changes;
|
|
85
|
+
}
|
|
86
|
+
case 'LAST_TAB': {
|
|
87
|
+
const id = ctx.tabIds[ctx.tabIds.length - 1] ?? ctx.focusedTabId;
|
|
88
|
+
const changes = { focusedTabId: id };
|
|
89
|
+
if (ctx.activationMode === 'automatic')
|
|
90
|
+
changes.activeTabId = id;
|
|
91
|
+
return changes;
|
|
92
|
+
}
|
|
93
|
+
default:
|
|
94
|
+
return {};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** Returns the ARIA attributes for a tab element. */
|
|
98
|
+
export function getTabAriaProps(ctx, tabId, panelId) {
|
|
99
|
+
return {
|
|
100
|
+
role: 'tab',
|
|
101
|
+
id: tabId,
|
|
102
|
+
'aria-controls': panelId,
|
|
103
|
+
'aria-selected': ctx.activeTabId === tabId,
|
|
104
|
+
tabIndex: ctx.activeTabId === tabId ? 0 : -1,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/** Returns the ARIA attributes for a tab panel element. */
|
|
108
|
+
export function getTabPanelAriaProps(ctx, panelId, tabId) {
|
|
109
|
+
return {
|
|
110
|
+
role: 'tabpanel',
|
|
111
|
+
id: panelId,
|
|
112
|
+
'aria-labelledby': tabId,
|
|
113
|
+
tabIndex: 0,
|
|
114
|
+
hidden: ctx.activeTabId !== tabId,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=tabs.machine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tabs.machine.js","sourceRoot":"","sources":["../../../src/primitives/tabs/tabs.machine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tabs state machine types.
|
|
3
|
+
* Implements the WAI-ARIA Tabs pattern (role="tablist" / role="tab" / role="tabpanel").
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* The tabs machine itself has a single macro-state; per-tab active state is
|
|
7
|
+
* captured in context rather than as discrete machine states so that the
|
|
8
|
+
* number of states doesn't balloon with the number of tabs.
|
|
9
|
+
*/
|
|
10
|
+
export type TabsState = 'idle';
|
|
11
|
+
export type TabsEventType = 'SELECT_TAB' | 'FOCUS_TAB' | 'NEXT_TAB' | 'PREV_TAB' | 'FIRST_TAB' | 'LAST_TAB';
|
|
12
|
+
export interface TabsEvent {
|
|
13
|
+
type: TabsEventType;
|
|
14
|
+
/** Tab id for SELECT_TAB / FOCUS_TAB events */
|
|
15
|
+
tabId?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface TabsContext {
|
|
18
|
+
/** Ordered list of tab ids */
|
|
19
|
+
tabIds: string[];
|
|
20
|
+
/** Currently active (selected) tab id */
|
|
21
|
+
activeTabId: string;
|
|
22
|
+
/** Keyboard-focused tab id (may differ from active in manual activation mode) */
|
|
23
|
+
focusedTabId: string;
|
|
24
|
+
/**
|
|
25
|
+
* 'automatic' — arrow keys both focus AND activate.
|
|
26
|
+
* 'manual' — arrow keys only move focus; Enter/Space activates.
|
|
27
|
+
*/
|
|
28
|
+
activationMode: 'automatic' | 'manual';
|
|
29
|
+
/** Layout axis for arrow key handling */
|
|
30
|
+
orientation: 'horizontal' | 'vertical';
|
|
31
|
+
/** Loop from last tab to first (and vice versa) */
|
|
32
|
+
loop: boolean;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=tabs.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tabs.types.d.ts","sourceRoot":"","sources":["../../../src/primitives/tabs/tabs.types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAE/B,MAAM,MAAM,aAAa,GACrB,YAAY,GACZ,WAAW,GACX,UAAU,GACV,UAAU,GACV,WAAW,GACX,UAAU,CAAC;AAEf,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,aAAa,CAAC;IACpB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,8BAA8B;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,cAAc,EAAE,WAAW,GAAG,QAAQ,CAAC;IACvC,yCAAyC;IACzC,WAAW,EAAE,YAAY,GAAG,UAAU,CAAC;IACvC,mDAAmD;IACnD,IAAI,EAAE,OAAO,CAAC;CACf"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tabs.types.js","sourceRoot":"","sources":["../../../src/primitives/tabs/tabs.types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokis/core",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Framework-agnostic headless primitives for Tokis — state machines, accessibility helpers, and focus management. Zero dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|