ajo-ui 0.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/LICENSE +15 -0
- package/README.md +126 -0
- package/dist/accordion.js +130 -0
- package/dist/avatar.js +54 -0
- package/dist/calendar.js +2 -0
- package/dist/carousel.js +239 -0
- package/dist/chart.js +790 -0
- package/dist/checkbox-group.js +70 -0
- package/dist/checkbox.js +77 -0
- package/dist/chunks/bar-CVafh6C1.js +99 -0
- package/dist/chunks/calendar-q8jZ8Cxr.js +1923 -0
- package/dist/chunks/collection-DtRB63U4.js +111 -0
- package/dist/chunks/data-table-DpkWv4y4.js +1039 -0
- package/dist/chunks/menu-B45IyHHC.js +704 -0
- package/dist/chunks/native-BJdhd9XJ.js +20 -0
- package/dist/chunks/popup-C8Bb3l_g.js +459 -0
- package/dist/chunks/popup-surface-BDCgtVU0.js +18 -0
- package/dist/chunks/position-D6_i_SRn.js +434 -0
- package/dist/chunks/virtual-list-B7hjGkjk.js +413 -0
- package/dist/collapsible.js +106 -0
- package/dist/command.js +263 -0
- package/dist/context-menu.js +112 -0
- package/dist/data-table.js +5 -0
- package/dist/dialog.js +207 -0
- package/dist/direction.js +22 -0
- package/dist/drawer.js +139 -0
- package/dist/field.js +26 -0
- package/dist/index.js +38 -0
- package/dist/input-date.js +994 -0
- package/dist/input-group.js +52 -0
- package/dist/input-otp.js +179 -0
- package/dist/menu.js +2 -0
- package/dist/menubar.js +236 -0
- package/dist/message-scroller.js +446 -0
- package/dist/navigation-menu.js +330 -0
- package/dist/popover.js +307 -0
- package/dist/progress.js +39 -0
- package/dist/radio-group.js +107 -0
- package/dist/resizable.js +172 -0
- package/dist/select.js +961 -0
- package/dist/sidebar.js +343 -0
- package/dist/slider.js +259 -0
- package/dist/switch.js +53 -0
- package/dist/tabs.js +182 -0
- package/dist/toast.js +492 -0
- package/dist/toggle-group.js +111 -0
- package/dist/toggle.js +52 -0
- package/dist/toolbar.js +127 -0
- package/dist/tooltip.js +196 -0
- package/dist/utils.js +104 -0
- package/dist/virtual-list.js +2 -0
- package/package.json +250 -0
- package/src/accordion.tsx +261 -0
- package/src/availability.ts +261 -0
- package/src/avatar.tsx +99 -0
- package/src/bar.ts +156 -0
- package/src/calendar.tsx +1441 -0
- package/src/carousel.tsx +424 -0
- package/src/chart.tsx +1194 -0
- package/src/checkbox-group.tsx +132 -0
- package/src/checkbox.tsx +130 -0
- package/src/collapsible.tsx +188 -0
- package/src/collection.ts +154 -0
- package/src/command.tsx +511 -0
- package/src/context-menu.tsx +233 -0
- package/src/data-table-contract.ts +143 -0
- package/src/data-table-model.ts +760 -0
- package/src/data-table.tsx +475 -0
- package/src/dialog.tsx +393 -0
- package/src/direction.tsx +45 -0
- package/src/drawer.tsx +251 -0
- package/src/field.tsx +61 -0
- package/src/index.ts +37 -0
- package/src/input-date.tsx +1539 -0
- package/src/input-group.tsx +142 -0
- package/src/input-otp.tsx +324 -0
- package/src/menu-cluster.ts +124 -0
- package/src/menu.tsx +1095 -0
- package/src/menubar.tsx +459 -0
- package/src/message-scroller.tsx +732 -0
- package/src/native.ts +26 -0
- package/src/navigation-menu.tsx +578 -0
- package/src/popover.tsx +519 -0
- package/src/popup-surface.tsx +31 -0
- package/src/popup.ts +569 -0
- package/src/position.ts +523 -0
- package/src/progress.tsx +70 -0
- package/src/radio-group.tsx +186 -0
- package/src/resizable.tsx +310 -0
- package/src/segments.ts +922 -0
- package/src/select.tsx +1501 -0
- package/src/sidebar.tsx +683 -0
- package/src/slider.tsx +424 -0
- package/src/switch.tsx +104 -0
- package/src/tabs.tsx +314 -0
- package/src/toast.tsx +923 -0
- package/src/toggle-group.tsx +249 -0
- package/src/toggle.tsx +91 -0
- package/src/toolbar.tsx +212 -0
- package/src/tooltip.tsx +359 -0
- package/src/utils.ts +204 -0
- package/src/virtual-list.tsx +205 -0
- package/src/virtual.ts +385 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { callHandler } from "ajo-cloves";
|
|
2
|
+
import { jsx } from "ajo/jsx-runtime";
|
|
3
|
+
//#region packages/ajo-ui/src/input-group.tsx
|
|
4
|
+
/** Unstyled host that groups a control with addons and actions. */
|
|
5
|
+
var InputGroup = ({ children, disabled, role = "group", ...attrs }) => /* @__PURE__ */ jsx("div", {
|
|
6
|
+
...attrs,
|
|
7
|
+
"data-disabled": disabled ? "true" : void 0,
|
|
8
|
+
"data-slot": "input-group",
|
|
9
|
+
role,
|
|
10
|
+
children
|
|
11
|
+
});
|
|
12
|
+
/** Unstyled addon that forwards non-button clicks to the grouped control. */
|
|
13
|
+
var InputGroupAddon = ({ align = "inline-start", children, role = "group", "set:onclick": onclick, ...attrs }) => /* @__PURE__ */ jsx("div", {
|
|
14
|
+
...attrs,
|
|
15
|
+
"data-align": align,
|
|
16
|
+
"data-slot": "input-group-addon",
|
|
17
|
+
role,
|
|
18
|
+
"set:onclick": (event) => {
|
|
19
|
+
callHandler(onclick, event);
|
|
20
|
+
if (event.target.closest("button")) return;
|
|
21
|
+
const parent = event.currentTarget.parentElement;
|
|
22
|
+
(parent?.querySelector("[data-slot=\"input-group-control\"]") ?? parent?.querySelector("input,textarea"))?.focus();
|
|
23
|
+
},
|
|
24
|
+
children
|
|
25
|
+
});
|
|
26
|
+
/** Unstyled button rendered inside an InputGroup. */
|
|
27
|
+
var InputGroupButton = ({ children, "data-slot": slot = "input-group-button", type = "button", ...attrs }) => /* @__PURE__ */ jsx("button", {
|
|
28
|
+
...attrs,
|
|
29
|
+
"data-slot": slot,
|
|
30
|
+
type,
|
|
31
|
+
children
|
|
32
|
+
});
|
|
33
|
+
/** Unstyled supporting text rendered inside an InputGroup. */
|
|
34
|
+
var InputGroupText = ({ children, ...attrs }) => /* @__PURE__ */ jsx("span", {
|
|
35
|
+
...attrs,
|
|
36
|
+
"data-slot": "input-group-text",
|
|
37
|
+
children
|
|
38
|
+
});
|
|
39
|
+
/** Unstyled native input carrying the InputGroup control slot. */
|
|
40
|
+
var InputGroupInput = ({ "data-slot": slot = "input-group-control", type = "text", ...attrs }) => /* @__PURE__ */ jsx("input", {
|
|
41
|
+
...attrs,
|
|
42
|
+
"data-slot": slot,
|
|
43
|
+
type
|
|
44
|
+
});
|
|
45
|
+
/** Unstyled native textarea carrying the InputGroup control slot. */
|
|
46
|
+
var InputGroupTextarea = ({ children, "data-slot": slot = "input-group-control", ...attrs }) => /* @__PURE__ */ jsx("textarea", {
|
|
47
|
+
...attrs,
|
|
48
|
+
"data-slot": slot,
|
|
49
|
+
children
|
|
50
|
+
});
|
|
51
|
+
//#endregion
|
|
52
|
+
export { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea };
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { callHandler, callRef, clamp, controlled, dom } from "ajo-cloves";
|
|
2
|
+
import { context } from "ajo/context";
|
|
3
|
+
import { Fragment, jsx, jsxs } from "ajo/jsx-runtime";
|
|
4
|
+
//#region packages/ajo-ui/src/input-otp.tsx
|
|
5
|
+
/** Built-in InputOTP pattern accepting one or more ASCII digits. */
|
|
6
|
+
var REGEXP_ONLY_DIGITS = /^[0-9]+$/;
|
|
7
|
+
/** Built-in InputOTP pattern accepting one or more ASCII letters or digits. */
|
|
8
|
+
var REGEXP_ONLY_DIGITS_AND_CHARS = /^[a-zA-Z0-9]+$/;
|
|
9
|
+
var InputOTPContext = context(null);
|
|
10
|
+
var isRegExp = (value) => Object.prototype.toString.call(value) === "[object RegExp]";
|
|
11
|
+
var accepts = (pattern, char) => {
|
|
12
|
+
if (!pattern) return true;
|
|
13
|
+
if (isRegExp(pattern)) {
|
|
14
|
+
pattern.lastIndex = 0;
|
|
15
|
+
return pattern.test(char);
|
|
16
|
+
}
|
|
17
|
+
return new RegExp(pattern).test(char);
|
|
18
|
+
};
|
|
19
|
+
var clean = (value, maxLength, pattern) => String(value ?? "").split("").filter((char) => accepts(pattern, char)).slice(0, Math.max(1, maxLength)).join("");
|
|
20
|
+
var inputPattern = (pattern) => isRegExp(pattern) ? pattern.source : pattern;
|
|
21
|
+
var nextSelection = (input, fallback) => Math.min(input?.selectionStart ?? fallback, Math.max(0, input?.value.length ?? fallback));
|
|
22
|
+
var completionState = (value, maxLength) => value.length === maxLength ? "complete" : "incomplete";
|
|
23
|
+
var InputOTPRoot = function* ({ defaultValue = "", maxLength = 6, pattern, value }) {
|
|
24
|
+
let input = null;
|
|
25
|
+
const initial = clean(value ?? defaultValue, maxLength, pattern);
|
|
26
|
+
let active = Math.min(initial.length, Math.max(0, maxLength - 1));
|
|
27
|
+
let onValueChange;
|
|
28
|
+
let onComplete;
|
|
29
|
+
let previousComplete = initial.length === maxLength ? initial : "";
|
|
30
|
+
const emit = (next, event) => {
|
|
31
|
+
onValueChange?.(next, event);
|
|
32
|
+
if (next.length === maxLength && next !== previousComplete) {
|
|
33
|
+
previousComplete = next;
|
|
34
|
+
onComplete?.(next, event);
|
|
35
|
+
} else if (next.length !== maxLength) previousComplete = "";
|
|
36
|
+
};
|
|
37
|
+
const state = controlled(this, {
|
|
38
|
+
fallback: initial,
|
|
39
|
+
onChange: (next, event) => emit(next, event)
|
|
40
|
+
});
|
|
41
|
+
const setValue = (next, args, nextActive = next.length, event) => {
|
|
42
|
+
const length = args.maxLength ?? maxLength;
|
|
43
|
+
const parsed = clean(next, length, args.pattern);
|
|
44
|
+
active = Math.min(nextActive, Math.max(0, length - 1));
|
|
45
|
+
if (input) input.value = parsed;
|
|
46
|
+
state.accept(parsed, event);
|
|
47
|
+
};
|
|
48
|
+
const focus = (index) => {
|
|
49
|
+
active = clamp(index, 0, Math.max(0, maxLength - 1));
|
|
50
|
+
input?.focus();
|
|
51
|
+
input?.setSelectionRange(active, active);
|
|
52
|
+
this.next();
|
|
53
|
+
};
|
|
54
|
+
for (const args of this) {
|
|
55
|
+
const { children, class: _class, defaultValue: _defaultValue, inputClass, inputRef, maxLength: _maxLength, onValueChange: change, onComplete: complete, pattern, value, "set:onblur": onBlur, "set:onfocus": onFocus, "set:oninput": onInput, "set:onkeyup": onKeyUp, "set:onpaste": onPaste, ...inputAttrs } = args;
|
|
56
|
+
maxLength = _maxLength ?? 6;
|
|
57
|
+
onValueChange = change;
|
|
58
|
+
onComplete = complete;
|
|
59
|
+
state.sync(value != null ? clean(value, maxLength, pattern) : void 0);
|
|
60
|
+
if (!state.controlled) {
|
|
61
|
+
const parsed = clean(state.value, maxLength, pattern);
|
|
62
|
+
if (parsed !== state.value) state.init(parsed);
|
|
63
|
+
}
|
|
64
|
+
active = Math.min(active, Math.max(0, maxLength - 1));
|
|
65
|
+
if (dom(this)) this.dataset.state = completionState(state.value, maxLength);
|
|
66
|
+
InputOTPContext({
|
|
67
|
+
active,
|
|
68
|
+
disabled: Boolean(inputAttrs.disabled),
|
|
69
|
+
focus,
|
|
70
|
+
maxLength,
|
|
71
|
+
value: state.value
|
|
72
|
+
});
|
|
73
|
+
yield /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("input", {
|
|
74
|
+
...inputAttrs,
|
|
75
|
+
"aria-label": inputAttrs["aria-label"] ?? "One-time password",
|
|
76
|
+
autocomplete: inputAttrs.autocomplete ?? "one-time-code",
|
|
77
|
+
class: inputClass,
|
|
78
|
+
"data-slot": "input-otp-input",
|
|
79
|
+
"data-state": completionState(state.value, maxLength),
|
|
80
|
+
inputmode: inputAttrs.inputmode ?? "numeric",
|
|
81
|
+
maxLength,
|
|
82
|
+
pattern: inputPattern(pattern),
|
|
83
|
+
ref: (element) => {
|
|
84
|
+
input = element;
|
|
85
|
+
callRef(inputRef, element);
|
|
86
|
+
},
|
|
87
|
+
type: inputAttrs.type ?? "text",
|
|
88
|
+
"set:onblur": (event) => {
|
|
89
|
+
callHandler(onBlur, event);
|
|
90
|
+
this.next(() => active = -1);
|
|
91
|
+
},
|
|
92
|
+
"set:onfocus": (event) => {
|
|
93
|
+
callHandler(onFocus, event);
|
|
94
|
+
this.next(() => active = Math.min(state.value.length, Math.max(0, maxLength - 1)));
|
|
95
|
+
},
|
|
96
|
+
"set:oninput": (event) => {
|
|
97
|
+
callHandler(onInput, event);
|
|
98
|
+
const control = event.currentTarget;
|
|
99
|
+
setValue(control.value, args, nextSelection(control, control.value.length), event);
|
|
100
|
+
},
|
|
101
|
+
"set:onkeyup": (event) => {
|
|
102
|
+
callHandler(onKeyUp, event);
|
|
103
|
+
this.next(() => {
|
|
104
|
+
active = nextSelection(event.currentTarget, active);
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
"set:onpaste": (event) => {
|
|
108
|
+
callHandler(onPaste, event);
|
|
109
|
+
if (event.defaultPrevented) return;
|
|
110
|
+
const pasted = event.clipboardData?.getData("text") ?? "";
|
|
111
|
+
if (!pasted) return;
|
|
112
|
+
event.preventDefault();
|
|
113
|
+
setValue(pasted, args, pasted.length, event);
|
|
114
|
+
},
|
|
115
|
+
"set:value": state.value
|
|
116
|
+
}), children] });
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
/** Unstyled one-time password input with visible slot context. */
|
|
120
|
+
var InputOTP = ({ children, class: classes, disabled, ref, ...attrs }) => {
|
|
121
|
+
const maxLength = attrs.maxLength ?? 6;
|
|
122
|
+
const state = completionState(clean(attrs.value ?? attrs.defaultValue, maxLength, attrs.pattern), maxLength);
|
|
123
|
+
return /* @__PURE__ */ jsx(InputOTPRoot, {
|
|
124
|
+
...attrs,
|
|
125
|
+
disabled,
|
|
126
|
+
inputRef: ref,
|
|
127
|
+
"attr:class": classes,
|
|
128
|
+
"attr:data-disabled": disabled ? "true" : void 0,
|
|
129
|
+
"attr:data-slot": "input-otp",
|
|
130
|
+
"attr:data-state": state,
|
|
131
|
+
children
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
/** Unstyled visual group for adjacent OTP slots. */
|
|
135
|
+
var InputOTPGroup = ({ children, "data-slot": slot = "input-otp-group", ...attrs }) => /* @__PURE__ */ jsx("div", {
|
|
136
|
+
...attrs,
|
|
137
|
+
"data-slot": slot,
|
|
138
|
+
children
|
|
139
|
+
});
|
|
140
|
+
/** Unstyled OTP slot synchronized with the nearest OTP input. */
|
|
141
|
+
var InputOTPSlot = ({ caretClass, caretMarkClass, children, index, role = "presentation", "set:onclick": onClick, ...attrs }) => {
|
|
142
|
+
const context = InputOTPContext();
|
|
143
|
+
if (!context) throw new Error("InputOTPSlot must be used within an <InputOTP />");
|
|
144
|
+
const char = context.value[index];
|
|
145
|
+
const active = context.active === index;
|
|
146
|
+
const caret = active && !char && !context.disabled;
|
|
147
|
+
const state = active ? "active" : "inactive";
|
|
148
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
149
|
+
...attrs,
|
|
150
|
+
"aria-hidden": "true",
|
|
151
|
+
"data-active": active ? "true" : "false",
|
|
152
|
+
"data-disabled": context.disabled ? "true" : void 0,
|
|
153
|
+
"data-slot": "input-otp-slot",
|
|
154
|
+
"data-state": state,
|
|
155
|
+
role,
|
|
156
|
+
"set:onclick": (event) => {
|
|
157
|
+
callHandler(onClick, event);
|
|
158
|
+
if (!event.defaultPrevented && !context.disabled) context.focus(index);
|
|
159
|
+
},
|
|
160
|
+
children: [children ?? char, caret && /* @__PURE__ */ jsx("div", {
|
|
161
|
+
"aria-hidden": "true",
|
|
162
|
+
class: caretClass,
|
|
163
|
+
"data-slot": "input-otp-caret",
|
|
164
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
165
|
+
class: caretMarkClass,
|
|
166
|
+
"data-slot": "input-otp-caret-mark"
|
|
167
|
+
})
|
|
168
|
+
})]
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
/** Unstyled separator between OTP slot groups. */
|
|
172
|
+
var InputOTPSeparator = ({ children, role = "separator", "data-slot": slot = "input-otp-separator", ...attrs }) => /* @__PURE__ */ jsx("div", {
|
|
173
|
+
...attrs,
|
|
174
|
+
"data-slot": slot,
|
|
175
|
+
role,
|
|
176
|
+
children
|
|
177
|
+
});
|
|
178
|
+
//#endregion
|
|
179
|
+
export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, REGEXP_ONLY_DIGITS, REGEXP_ONLY_DIGITS_AND_CHARS };
|
package/dist/menu.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as MenuItem, c as MenuRadioItem, d as MenuSub, f as MenuSubContent, i as MenuGroup, l as MenuSeparator, m as MenuTrigger, n as MenuCheckboxItem, o as MenuLabel, p as MenuSubTrigger, r as MenuContent, s as MenuRadioGroup, t as Menu, u as MenuShortcut } from "./chunks/menu-B45IyHHC.js";
|
|
2
|
+
export { Menu, MenuCheckboxItem, MenuContent, MenuGroup, MenuItem, MenuLabel, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuShortcut, MenuSub, MenuSubContent, MenuSubTrigger, MenuTrigger };
|
package/dist/menubar.js
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { text, withSlot } from "./utils.js";
|
|
2
|
+
import { a as MenuItem, c as MenuRadioItem, d as MenuSub, f as MenuSubContent, i as MenuGroup, l as MenuSeparator, m as MenuTrigger, n as MenuCheckboxItem, o as MenuLabel, p as MenuSubTrigger, r as MenuContent, s as MenuRadioGroup, t as Menu, u as MenuShortcut, v as provideMenubarComposition } from "./chunks/menu-B45IyHHC.js";
|
|
3
|
+
import { t as bar } from "./chunks/bar-CVafh6C1.js";
|
|
4
|
+
import { callHandler, callRef, id, listen, statefulRootAttrs } from "ajo-cloves";
|
|
5
|
+
import { context } from "ajo/context";
|
|
6
|
+
import { Fragment, jsx } from "ajo/jsx-runtime";
|
|
7
|
+
//#region packages/ajo-ui/src/menubar.tsx
|
|
8
|
+
var MenubarContext = context(null);
|
|
9
|
+
var MenubarMenuContext = context(null);
|
|
10
|
+
var order = (root) => Array.from(root.querySelectorAll("[data-menubar-trigger=\"true\"]")).filter((trigger) => !trigger.disabled && trigger.offsetParent !== null && trigger.closest("[data-slot=\"menubar\"]") === root);
|
|
11
|
+
var MenubarRoot = function* ({ defaultValue, value }) {
|
|
12
|
+
const triggers = /* @__PURE__ */ new Map();
|
|
13
|
+
let disabled = false;
|
|
14
|
+
let entering = false;
|
|
15
|
+
let loop = true;
|
|
16
|
+
let onValueChange;
|
|
17
|
+
let pendingFocus = "";
|
|
18
|
+
let queued = false;
|
|
19
|
+
const state = bar(this, {
|
|
20
|
+
triggers: () => order(this),
|
|
21
|
+
initialValue: String(value ?? defaultValue ?? ""),
|
|
22
|
+
disabled: () => disabled,
|
|
23
|
+
loop: () => loop,
|
|
24
|
+
onValueChange: (next, event) => onValueChange?.(next, event)
|
|
25
|
+
});
|
|
26
|
+
const rerender = () => {
|
|
27
|
+
if (queued) return;
|
|
28
|
+
queued = true;
|
|
29
|
+
queueMicrotask(() => {
|
|
30
|
+
queued = false;
|
|
31
|
+
this.next();
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
const register = (itemValue, element) => {
|
|
35
|
+
if (element) {
|
|
36
|
+
if (triggers.get(itemValue) === element) return;
|
|
37
|
+
triggers.set(itemValue, element);
|
|
38
|
+
rerender();
|
|
39
|
+
} else if (triggers.delete(itemValue)) {
|
|
40
|
+
if (state.focused === itemValue) state.adopt("");
|
|
41
|
+
rerender();
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const close = (event) => {
|
|
45
|
+
pendingFocus = "";
|
|
46
|
+
state.close(event);
|
|
47
|
+
};
|
|
48
|
+
const focus = (next, event) => {
|
|
49
|
+
if (!entering) pendingFocus = "";
|
|
50
|
+
state.focus(next, event);
|
|
51
|
+
};
|
|
52
|
+
const follow = (next, event) => {
|
|
53
|
+
if (!entering) pendingFocus = "";
|
|
54
|
+
state.follow(next, event);
|
|
55
|
+
};
|
|
56
|
+
const open = (next, event) => {
|
|
57
|
+
pendingFocus = "";
|
|
58
|
+
state.setValue(next, event);
|
|
59
|
+
};
|
|
60
|
+
const enter = (next, event) => {
|
|
61
|
+
pendingFocus = next;
|
|
62
|
+
entering = true;
|
|
63
|
+
try {
|
|
64
|
+
state.follow(next, event);
|
|
65
|
+
} finally {
|
|
66
|
+
entering = false;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const ackFocus = (next) => {
|
|
70
|
+
if (!next || pendingFocus !== next) return false;
|
|
71
|
+
pendingFocus = "";
|
|
72
|
+
return true;
|
|
73
|
+
};
|
|
74
|
+
listen(this, "keydown", (event) => {
|
|
75
|
+
if (event.defaultPrevented) return;
|
|
76
|
+
const target = event.target;
|
|
77
|
+
if (target?.closest("[data-slot=\"menubar\"]") !== this) return;
|
|
78
|
+
if (event.key === "Tab") {
|
|
79
|
+
close(event);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (target?.closest("[data-menubar-trigger=\"true\"]")) {
|
|
83
|
+
if (event.key === "Escape") pendingFocus = "";
|
|
84
|
+
const transfer = Boolean(pendingFocus);
|
|
85
|
+
if (transfer) entering = true;
|
|
86
|
+
try {
|
|
87
|
+
if (state.handle(event) && transfer) pendingFocus = state.value;
|
|
88
|
+
} finally {
|
|
89
|
+
if (transfer) entering = false;
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (state.value && (event.key === "ArrowLeft" || event.key === "ArrowRight") && target?.closest("[data-menu-content=\"true\"]")) {
|
|
94
|
+
if (event.key === "ArrowRight" && target.closest("[data-menu-sub-trigger=\"true\"]")) return;
|
|
95
|
+
if (target.closest("[data-menu-sub-content=\"true\"]")) return;
|
|
96
|
+
const row = order(this);
|
|
97
|
+
const index = row.findIndex((trigger) => trigger.dataset.value === state.value);
|
|
98
|
+
if (index < 0) return;
|
|
99
|
+
const step = event.key === "ArrowRight" ? 1 : -1;
|
|
100
|
+
const next = row[index + step] ?? (loop ? row[(index + step + row.length) % row.length] : void 0);
|
|
101
|
+
if (!next || next === row[index]) return;
|
|
102
|
+
event.preventDefault();
|
|
103
|
+
enter(next.dataset.value ?? "", event);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
for (const args of this) {
|
|
107
|
+
disabled = Boolean(args.disabled);
|
|
108
|
+
loop = args.loop !== false;
|
|
109
|
+
onValueChange = args.onValueChange;
|
|
110
|
+
state.sync(args.value != null ? String(args.value ?? "") : void 0);
|
|
111
|
+
MenubarContext({
|
|
112
|
+
ackFocus,
|
|
113
|
+
close,
|
|
114
|
+
disabled,
|
|
115
|
+
focus,
|
|
116
|
+
follow,
|
|
117
|
+
gap: args.gap,
|
|
118
|
+
isTabbable: state.isTabbable,
|
|
119
|
+
open,
|
|
120
|
+
placement: args.placement,
|
|
121
|
+
register,
|
|
122
|
+
value: state.value
|
|
123
|
+
});
|
|
124
|
+
yield /* @__PURE__ */ jsx(Fragment, { children: args.children });
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
/** Persistent horizontal menu bar. */
|
|
128
|
+
var Menubar = ({ children, class: classes, defaultValue, disabled, gap, loop, onValueChange, placement, value, ...attrs }) => /* @__PURE__ */ jsx(MenubarRoot, {
|
|
129
|
+
...statefulRootAttrs(attrs),
|
|
130
|
+
defaultValue,
|
|
131
|
+
disabled,
|
|
132
|
+
gap,
|
|
133
|
+
loop,
|
|
134
|
+
onValueChange,
|
|
135
|
+
placement,
|
|
136
|
+
value,
|
|
137
|
+
"attr:aria-orientation": "horizontal",
|
|
138
|
+
"attr:class": classes,
|
|
139
|
+
"attr:data-slot": "menubar",
|
|
140
|
+
"attr:role": "menubar",
|
|
141
|
+
children
|
|
142
|
+
});
|
|
143
|
+
var MenubarMenuRoot = function* ({ value }) {
|
|
144
|
+
const fallback = id("menubar-menu");
|
|
145
|
+
let bar = null;
|
|
146
|
+
let itemValue = String(value ?? fallback);
|
|
147
|
+
const ackFocus = () => bar?.ackFocus(itemValue) ?? false;
|
|
148
|
+
for (const args of this) {
|
|
149
|
+
bar = MenubarContext();
|
|
150
|
+
itemValue = String(args.value ?? value ?? fallback);
|
|
151
|
+
const disabled = Boolean(args.disabled ?? bar?.disabled);
|
|
152
|
+
MenubarMenuContext({
|
|
153
|
+
disabled,
|
|
154
|
+
value: itemValue
|
|
155
|
+
});
|
|
156
|
+
if (bar) provideMenubarComposition(ackFocus);
|
|
157
|
+
yield /* @__PURE__ */ jsx(Menu, {
|
|
158
|
+
disabled,
|
|
159
|
+
gap: bar?.gap,
|
|
160
|
+
onOpenChange: (open, event) => open ? bar?.open(itemValue, event) : bar?.close(event),
|
|
161
|
+
open: bar ? bar.value === itemValue : void 0,
|
|
162
|
+
placement: bar?.placement,
|
|
163
|
+
children: args.children
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
/** Top-level Menubar menu. */
|
|
168
|
+
var MenubarMenu = ({ children, class: classes, disabled, value, ...attrs }) => /* @__PURE__ */ jsx(MenubarMenuRoot, {
|
|
169
|
+
...statefulRootAttrs(attrs),
|
|
170
|
+
disabled,
|
|
171
|
+
value,
|
|
172
|
+
"attr:class": classes,
|
|
173
|
+
"attr:data-slot": "menubar-menu",
|
|
174
|
+
children
|
|
175
|
+
});
|
|
176
|
+
/** Top-level trigger inside a Menubar. */
|
|
177
|
+
var MenubarTrigger = ({ children, class: classes, disabled, ref, textValue, "set:onfocus": onFocus, "set:onmouseenter": onMouseEnter, ...attrs }) => {
|
|
178
|
+
const bar = MenubarContext();
|
|
179
|
+
const menu = MenubarMenuContext();
|
|
180
|
+
const itemValue = menu?.value ?? "";
|
|
181
|
+
const disabledFlag = Boolean(disabled ?? menu?.disabled ?? bar?.disabled);
|
|
182
|
+
const label = textValue ?? text(children);
|
|
183
|
+
const reference = (element) => {
|
|
184
|
+
if (itemValue) bar?.register(itemValue, element);
|
|
185
|
+
callRef(ref, element);
|
|
186
|
+
};
|
|
187
|
+
return /* @__PURE__ */ jsx(MenuTrigger, {
|
|
188
|
+
...attrs,
|
|
189
|
+
class: classes,
|
|
190
|
+
"data-label": bar ? label : void 0,
|
|
191
|
+
"data-menubar-trigger": bar ? "true" : void 0,
|
|
192
|
+
"data-slot": "menubar-trigger",
|
|
193
|
+
"data-value": bar ? itemValue : void 0,
|
|
194
|
+
disabled: disabledFlag,
|
|
195
|
+
ref: reference,
|
|
196
|
+
role: bar ? "menuitem" : void 0,
|
|
197
|
+
"set:onfocus": (event) => {
|
|
198
|
+
callHandler(onFocus, event);
|
|
199
|
+
if (event.defaultPrevented || disabledFlag) return;
|
|
200
|
+
bar?.focus(itemValue, event);
|
|
201
|
+
},
|
|
202
|
+
"set:onmouseenter": (event) => {
|
|
203
|
+
callHandler(onMouseEnter, event);
|
|
204
|
+
if (event.defaultPrevented || disabledFlag) return;
|
|
205
|
+
bar?.follow(itemValue, event);
|
|
206
|
+
},
|
|
207
|
+
tabindex: bar ? bar.isTabbable(itemValue) ? 0 : -1 : void 0,
|
|
208
|
+
children
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
/** Popover content for a top-level Menubar menu. */
|
|
212
|
+
var MenubarContent = withSlot(MenuContent, "menubar-content");
|
|
213
|
+
/** Standard menubar action item. */
|
|
214
|
+
var MenubarItem = withSlot(MenuItem, "menubar-item");
|
|
215
|
+
/** Checkable menubar item. */
|
|
216
|
+
var MenubarCheckboxItem = withSlot(MenuCheckboxItem, "menubar-checkbox-item");
|
|
217
|
+
/** Radio group inside a menubar menu. */
|
|
218
|
+
var MenubarRadioGroup = withSlot(MenuRadioGroup, "menubar-radio-group");
|
|
219
|
+
/** Radio item inside a menubar radio group. */
|
|
220
|
+
var MenubarRadioItem = withSlot(MenuRadioItem, "menubar-radio-item");
|
|
221
|
+
/** Group of menubar items. */
|
|
222
|
+
var MenubarGroup = withSlot(MenuGroup, "menubar-group");
|
|
223
|
+
/** Non-interactive label inside a menubar menu. */
|
|
224
|
+
var MenubarLabel = withSlot(MenuLabel, "menubar-label");
|
|
225
|
+
/** Visual separator between menubar groups. */
|
|
226
|
+
var MenubarSeparator = withSlot(MenuSeparator, "menubar-separator");
|
|
227
|
+
/** Right-aligned shortcut hint inside a menubar item. */
|
|
228
|
+
var MenubarShortcut = withSlot(MenuShortcut, "menubar-shortcut");
|
|
229
|
+
/** Root provider for a menubar submenu. */
|
|
230
|
+
var MenubarSub = withSlot(MenuSub, "menubar-sub");
|
|
231
|
+
/** Trigger item that opens a menubar submenu. */
|
|
232
|
+
var MenubarSubTrigger = withSlot(MenuSubTrigger, "menubar-sub-trigger");
|
|
233
|
+
/** Content for a menubar submenu. */
|
|
234
|
+
var MenubarSubContent = withSlot(MenuSubContent, "menubar-sub-content");
|
|
235
|
+
//#endregion
|
|
236
|
+
export { Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger };
|