@neut/ui 0.0.10 → 0.0.11
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/dist/components/switch/Switch.styles.js +1 -1
- package/dist/components/switch/Switch.styles.js.map +1 -1
- package/dist/components/tabs/Tabs/Tabs.context.d.ts +47 -0
- package/dist/components/tabs/Tabs/Tabs.context.js +54 -0
- package/dist/components/tabs/Tabs/Tabs.context.js.map +1 -0
- package/dist/components/tabs/Tabs/Tabs.d.ts +2 -0
- package/dist/components/tabs/Tabs/Tabs.js +71 -0
- package/dist/components/tabs/Tabs/Tabs.js.map +1 -0
- package/dist/components/tabs/Tabs/Tabs.types.d.ts +16 -0
- package/dist/components/tabs/Tabs/call-event-handler.d.ts +5 -0
- package/dist/components/tabs/Tabs/call-event-handler.js +9 -0
- package/dist/components/tabs/Tabs/call-event-handler.js.map +1 -0
- package/dist/components/tabs/Tabs/index.d.ts +2 -0
- package/dist/components/tabs/Tabs/useTabsKeyboard.d.ts +18 -0
- package/dist/components/tabs/Tabs/useTabsKeyboard.js +49 -0
- package/dist/components/tabs/Tabs/useTabsKeyboard.js.map +1 -0
- package/dist/components/tabs/TabsContent/TabsContent.d.ts +3 -0
- package/dist/components/tabs/TabsContent/TabsContent.js +52 -0
- package/dist/components/tabs/TabsContent/TabsContent.js.map +1 -0
- package/dist/components/tabs/TabsContent/TabsContent.types.d.ts +6 -0
- package/dist/components/tabs/TabsContent/index.d.ts +2 -0
- package/dist/components/tabs/TabsList/TabsList.context.d.ts +7 -0
- package/dist/components/tabs/TabsList/TabsList.context.js +11 -0
- package/dist/components/tabs/TabsList/TabsList.context.js.map +1 -0
- package/dist/components/tabs/TabsList/TabsList.d.ts +2 -0
- package/dist/components/tabs/TabsList/TabsList.js +48 -0
- package/dist/components/tabs/TabsList/TabsList.js.map +1 -0
- package/dist/components/tabs/TabsList/TabsList.styles.d.ts +3 -0
- package/dist/components/tabs/TabsList/TabsList.styles.js +13 -0
- package/dist/components/tabs/TabsList/TabsList.styles.js.map +1 -0
- package/dist/components/tabs/TabsList/TabsList.types.d.ts +7 -0
- package/dist/components/tabs/TabsList/index.d.ts +2 -0
- package/dist/components/tabs/TabsTrigger/TabsTrigger.d.ts +2 -0
- package/dist/components/tabs/TabsTrigger/TabsTrigger.js +71 -0
- package/dist/components/tabs/TabsTrigger/TabsTrigger.js.map +1 -0
- package/dist/components/tabs/TabsTrigger/TabsTrigger.styles.d.ts +1 -0
- package/dist/components/tabs/TabsTrigger/TabsTrigger.styles.js +7 -0
- package/dist/components/tabs/TabsTrigger/TabsTrigger.styles.js.map +1 -0
- package/dist/components/tabs/TabsTrigger/TabsTrigger.types.d.ts +6 -0
- package/dist/components/tabs/TabsTrigger/index.d.ts +2 -0
- package/dist/components/tabs/index.d.ts +4 -0
- package/dist/components/tabs/index.js +5 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +10 -6
- package/dist/ui.css +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { clsx as e } from "../../utils/clsx.js";
|
|
2
2
|
//#region src/components/switch/Switch.styles.ts
|
|
3
3
|
var t = {
|
|
4
|
-
switch: e("peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=md]:h-[18.4px] data-[size=md]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-[checked=true]:bg-primary data-[checked=false]:bg-input dark:data-[checked=false]:bg-input/80 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50"),
|
|
4
|
+
switch: e("peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=md]:h-[18.4px] data-[size=md]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-[checked=true]:bg-primary data-[checked=false]:bg-input dark:data-[checked=false]:bg-input/80 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50 data-[disabled=true]:pointer-events-none"),
|
|
5
5
|
thumb: e("pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=md]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=md]/switch:data-[checked=true]:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-[checked=true]:translate-x-[calc(100%-2px)] dark:data-[checked=true]:bg-primary-foreground group-data-[size=md]/switch:data-[checked=false]:translate-x-0 group-data-[size=sm]/switch:data-[checked=false]:translate-x-0 dark:data-[checked=false]:bg-foreground")
|
|
6
6
|
};
|
|
7
7
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Switch.styles.js","names":[],"sources":["../../../src/components/switch/Switch.styles.ts"],"sourcesContent":["import { clsx } from \"~/utils\";\n\nexport const classes = {\n switch: clsx(\n // \"relative inline-flex shrink-0 items-center after:absolute after:-inset-x-3 after:-inset-y-2\",\n // \"rounded-full border border-transparent focus-visible:border-neutral-400 dark:focus-visible:border-neutral-500 aria-invalid:border-red-600 dark:aria-invalid:border-red-400/50\",\n // \"focus-visible:ring-neutral-400/50 dark:focus-visible:ring-neutral-500/50 aria-invalid:ring-red-600/20 dark:aria-invalid:ring-red-400/40 data-[checked=true]:bg-neutral-900 dark:data-[checked=true]:bg-neutral-200 data-[checked=false]:bg-neutral-200 dark:data-[checked=false]:bg-white/12\",\n // \"data-[size=md]:h-[18.4px] data-[size=md]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6\",\n // \"peer group/switch transition-all outline-none focus-visible:ring-3 aria-invalid:ring-3 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50 data-[disabled=true]:pointer-events-none\",\n \"peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=md]:h-[18.4px] data-[size=md]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-[checked=true]:bg-primary data-[checked=false]:bg-input dark:data-[checked=false]:bg-input/80 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50\",\n ),\n thumb: clsx(\n // \"pointer-events-none\",\n // \"block\",\n // \"rounded-full\",\n // \"ring-0\",\n // \"transition-transform\",\n // \"group-data-[size=md]/switch:size-4 group-data-[size=sm]/switch:size-3\",\n // \"group-data-[size=md]/switch:data-[checked=true]:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-[checked=true]:translate-x-[calc(100%-2px)] group-data-[size=md]/switch:data-[checked=false]:translate-x-0 group-data-[size=sm]/switch:data-[checked=false]:translate-x-0\",\n // \"bg-white dark:bg-neutral-950 dark:data-[checked=true]:bg-neutral-900 dark:data-[checked=false]:bg-neutral-50\",\n \"pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=md]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=md]/switch:data-[checked=true]:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-[checked=true]:translate-x-[calc(100%-2px)] dark:data-[checked=true]:bg-primary-foreground group-data-[size=md]/switch:data-[checked=false]:translate-x-0 group-data-[size=sm]/switch:data-[checked=false]:translate-x-0 dark:data-[checked=false]:bg-foreground\",\n ),\n} as const;\n"],"mappings":";;AAEA,IAAa,IAAU;CACrB,QAAQ,EAMN
|
|
1
|
+
{"version":3,"file":"Switch.styles.js","names":[],"sources":["../../../src/components/switch/Switch.styles.ts"],"sourcesContent":["import { clsx } from \"~/utils\";\n\nexport const classes = {\n switch: clsx(\n // \"relative inline-flex shrink-0 items-center after:absolute after:-inset-x-3 after:-inset-y-2\",\n // \"rounded-full border border-transparent focus-visible:border-neutral-400 dark:focus-visible:border-neutral-500 aria-invalid:border-red-600 dark:aria-invalid:border-red-400/50\",\n // \"focus-visible:ring-neutral-400/50 dark:focus-visible:ring-neutral-500/50 aria-invalid:ring-red-600/20 dark:aria-invalid:ring-red-400/40 data-[checked=true]:bg-neutral-900 dark:data-[checked=true]:bg-neutral-200 data-[checked=false]:bg-neutral-200 dark:data-[checked=false]:bg-white/12\",\n // \"data-[size=md]:h-[18.4px] data-[size=md]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6\",\n // \"peer group/switch transition-all outline-none focus-visible:ring-3 aria-invalid:ring-3 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50 data-[disabled=true]:pointer-events-none\",\n \"peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=md]:h-[18.4px] data-[size=md]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-[checked=true]:bg-primary data-[checked=false]:bg-input dark:data-[checked=false]:bg-input/80 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50 data-[disabled=true]:pointer-events-none\",\n ),\n thumb: clsx(\n // \"pointer-events-none\",\n // \"block\",\n // \"rounded-full\",\n // \"ring-0\",\n // \"transition-transform\",\n // \"group-data-[size=md]/switch:size-4 group-data-[size=sm]/switch:size-3\",\n // \"group-data-[size=md]/switch:data-[checked=true]:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-[checked=true]:translate-x-[calc(100%-2px)] group-data-[size=md]/switch:data-[checked=false]:translate-x-0 group-data-[size=sm]/switch:data-[checked=false]:translate-x-0\",\n // \"bg-white dark:bg-neutral-950 dark:data-[checked=true]:bg-neutral-900 dark:data-[checked=false]:bg-neutral-50\",\n \"pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=md]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=md]/switch:data-[checked=true]:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-[checked=true]:translate-x-[calc(100%-2px)] dark:data-[checked=true]:bg-primary-foreground group-data-[size=md]/switch:data-[checked=false]:translate-x-0 group-data-[size=sm]/switch:data-[checked=false]:translate-x-0 dark:data-[checked=false]:bg-foreground\",\n ),\n} as const;\n"],"mappings":";;AAEA,IAAa,IAAU;CACrB,QAAQ,EAMN,wsBACF;CACA,OAAO,EASL,ugBACF;AACF"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Accessor, ParentProps } from 'solid-js';
|
|
2
|
+
import { TabsValue } from './Tabs.types';
|
|
3
|
+
interface TriggerEntry {
|
|
4
|
+
value: TabsValue;
|
|
5
|
+
/** accessor,支持运行时 disabled 翻转 */
|
|
6
|
+
disabled: () => boolean;
|
|
7
|
+
element: HTMLElement;
|
|
8
|
+
}
|
|
9
|
+
export interface TabsContextValue {
|
|
10
|
+
/** 当前激活值(受控优先,否则内部状态) */
|
|
11
|
+
value: Accessor<TabsValue | undefined>;
|
|
12
|
+
setValue: (value: TabsValue) => void;
|
|
13
|
+
isSelected: (value: TabsValue) => boolean;
|
|
14
|
+
orientation: Accessor<"horizontal" | "vertical">;
|
|
15
|
+
dir: Accessor<"ltr" | "rtl" | "auto">;
|
|
16
|
+
loop: Accessor<boolean>;
|
|
17
|
+
/**
|
|
18
|
+
* 当前焦点高亮 tab,与激活值分离:
|
|
19
|
+
* 默认(activateOnFocus=false)聚焦/键盘导航只更新高亮,不激活;
|
|
20
|
+
* 激活只发生在点击(click)时。与 base-ui 的 highlighted/active 语义一致。
|
|
21
|
+
*/
|
|
22
|
+
highlightedValue: Accessor<TabsValue | undefined>;
|
|
23
|
+
setHighlightedValue: (value: TabsValue) => void;
|
|
24
|
+
/** 按挂载顺序注册 trigger,返回注销函数;仅用于渲染期推导与键盘导航 */
|
|
25
|
+
registerTrigger: (entry: TriggerEntry) => () => void;
|
|
26
|
+
/** 已注册的 trigger 列表(挂载顺序) */
|
|
27
|
+
getTriggers: () => TriggerEntry[];
|
|
28
|
+
/** 无高亮时,该 value 是否为第一个可用 trigger(键盘 tabindex 起点) */
|
|
29
|
+
isFirstEnabled: (value: TabsValue) => boolean;
|
|
30
|
+
/** 该 value 对应的 trigger 当前是否可用(已注册且未 disabled) */
|
|
31
|
+
isUsable: (value: TabsValue) => boolean;
|
|
32
|
+
/** value -> triggerId / contentId 交叉注册,供 aria-controls / aria-labelledby 使用 */
|
|
33
|
+
setTriggerId: (value: TabsValue, id: string) => void;
|
|
34
|
+
getTriggerId: (value: TabsValue) => string | undefined;
|
|
35
|
+
setContentId: (value: TabsValue, id: string) => void;
|
|
36
|
+
getContentId: (value: TabsValue) => string | undefined;
|
|
37
|
+
}
|
|
38
|
+
export declare function TabsProvider(props: ParentProps & {
|
|
39
|
+
defaultValue?: TabsValue;
|
|
40
|
+
value?: TabsValue;
|
|
41
|
+
onValueChange?: (value: TabsValue) => void;
|
|
42
|
+
orientation: "horizontal" | "vertical";
|
|
43
|
+
dir: "ltr" | "rtl" | "auto";
|
|
44
|
+
loop: boolean;
|
|
45
|
+
}): import("solid-js").JSX.Element;
|
|
46
|
+
export declare const useTabsContext: () => TabsContextValue;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { createComponent as e } from "solid-js/web";
|
|
2
|
+
import { createContext as t, createEffect as n, createSignal as r, useContext as i } from "solid-js";
|
|
3
|
+
import { createStore as a } from "solid-js/store";
|
|
4
|
+
//#region src/components/tabs/Tabs/Tabs.context.tsx
|
|
5
|
+
var o = t();
|
|
6
|
+
function s(t) {
|
|
7
|
+
let [i, s] = r(t.defaultValue), [c, l] = r(), [u, d] = r([]), [f, p] = a({
|
|
8
|
+
trigger: {},
|
|
9
|
+
content: {}
|
|
10
|
+
}), m = () => t.value ?? i(), h = (e) => {
|
|
11
|
+
if (t.value !== void 0) {
|
|
12
|
+
t.onValueChange?.(e);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
s(e), t.onValueChange?.(e);
|
|
16
|
+
}, g = (e) => m() === e;
|
|
17
|
+
n(() => {
|
|
18
|
+
let e = m();
|
|
19
|
+
e !== void 0 && document.activeElement?.getAttribute("role") !== "tab" && l(e);
|
|
20
|
+
});
|
|
21
|
+
let _ = {
|
|
22
|
+
value: m,
|
|
23
|
+
setValue: h,
|
|
24
|
+
isSelected: g,
|
|
25
|
+
orientation: () => t.orientation,
|
|
26
|
+
dir: () => t.dir,
|
|
27
|
+
loop: () => t.loop,
|
|
28
|
+
highlightedValue: c,
|
|
29
|
+
setHighlightedValue: l,
|
|
30
|
+
registerTrigger: (e) => (d((t) => [...t, e]), () => d((t) => t.filter((t) => t.value !== e.value))),
|
|
31
|
+
getTriggers: () => u(),
|
|
32
|
+
isFirstEnabled: (e) => u().find((e) => !e.disabled())?.value === e,
|
|
33
|
+
isUsable: (e) => u().some((t) => t.value === e && !t.disabled()),
|
|
34
|
+
setTriggerId: (e, t) => p("trigger", String(e), t),
|
|
35
|
+
getTriggerId: (e) => f.trigger[String(e)],
|
|
36
|
+
setContentId: (e, t) => p("content", String(e), t),
|
|
37
|
+
getContentId: (e) => f.content[String(e)]
|
|
38
|
+
};
|
|
39
|
+
return e(o.Provider, {
|
|
40
|
+
value: _,
|
|
41
|
+
get children() {
|
|
42
|
+
return t.children;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
var c = () => {
|
|
47
|
+
let e = i(o);
|
|
48
|
+
if (!e) throw Error("useTabsContext must be used within a <Tabs> component");
|
|
49
|
+
return e;
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
52
|
+
export { s as TabsProvider, c as useTabsContext };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=Tabs.context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tabs.context.js","names":["createContext","createEffect","createSignal","Accessor","ParentProps","useContext","createStore","TabsValue","TriggerEntry","value","disabled","element","HTMLElement","TabsContextValue","setValue","isSelected","orientation","dir","loop","highlightedValue","setHighlightedValue","registerTrigger","entry","getTriggers","isFirstEnabled","isUsable","setTriggerId","id","getTriggerId","setContentId","getContentId","TabsContext","TabsProvider","props","defaultValue","onValueChange","internalValue","setInternalValue","triggerOrder","setTriggerOrder","ids","setIds","trigger","Record","content","next","undefined","v","current","active","document","activeElement","getAttribute","prev","filter","t","first","find","some","String","contextValue","_$createComponent","Provider","children","useTabsContext","context","Error"],"sources":["../../../../src/components/tabs/Tabs/Tabs.context.tsx"],"sourcesContent":["import {\n createContext,\n createEffect,\n createSignal,\n type Accessor,\n type ParentProps,\n useContext,\n} from \"solid-js\";\nimport { createStore } from \"solid-js/store\";\nimport type { TabsValue } from \"./Tabs.types\";\n\ninterface TriggerEntry {\n value: TabsValue;\n /** accessor,支持运行时 disabled 翻转 */\n disabled: () => boolean;\n element: HTMLElement;\n}\n\nexport interface TabsContextValue {\n /** 当前激活值(受控优先,否则内部状态) */\n value: Accessor<TabsValue | undefined>;\n setValue: (value: TabsValue) => void;\n isSelected: (value: TabsValue) => boolean;\n orientation: Accessor<\"horizontal\" | \"vertical\">;\n dir: Accessor<\"ltr\" | \"rtl\" | \"auto\">;\n loop: Accessor<boolean>;\n /**\n * 当前焦点高亮 tab,与激活值分离:\n * 默认(activateOnFocus=false)聚焦/键盘导航只更新高亮,不激活;\n * 激活只发生在点击(click)时。与 base-ui 的 highlighted/active 语义一致。\n */\n highlightedValue: Accessor<TabsValue | undefined>;\n setHighlightedValue: (value: TabsValue) => void;\n /** 按挂载顺序注册 trigger,返回注销函数;仅用于渲染期推导与键盘导航 */\n registerTrigger: (entry: TriggerEntry) => () => void;\n /** 已注册的 trigger 列表(挂载顺序) */\n getTriggers: () => TriggerEntry[];\n /** 无高亮时,该 value 是否为第一个可用 trigger(键盘 tabindex 起点) */\n isFirstEnabled: (value: TabsValue) => boolean;\n /** 该 value 对应的 trigger 当前是否可用(已注册且未 disabled) */\n isUsable: (value: TabsValue) => boolean;\n /** value -> triggerId / contentId 交叉注册,供 aria-controls / aria-labelledby 使用 */\n setTriggerId: (value: TabsValue, id: string) => void;\n getTriggerId: (value: TabsValue) => string | undefined;\n setContentId: (value: TabsValue, id: string) => void;\n getContentId: (value: TabsValue) => string | undefined;\n}\n\nconst TabsContext = createContext<TabsContextValue>();\n\nexport function TabsProvider(\n props: ParentProps & {\n defaultValue?: TabsValue;\n value?: TabsValue;\n onValueChange?: (value: TabsValue) => void;\n orientation: \"horizontal\" | \"vertical\";\n dir: \"ltr\" | \"rtl\" | \"auto\";\n loop: boolean;\n },\n) {\n const [internalValue, setInternalValue] = createSignal<TabsValue | undefined>(\n props.defaultValue,\n );\n const [highlightedValue, setHighlightedValue] = createSignal<\n TabsValue | undefined\n >();\n const [triggerOrder, setTriggerOrder] = createSignal<TriggerEntry[]>([]);\n const [ids, setIds] = createStore<{\n trigger: Record<string, string>;\n content: Record<string, string>;\n }>({ trigger: {}, content: {} });\n\n // 受控优先:props.value 存在时读外部值,否则读内部状态\n const value = (): TabsValue | undefined => props.value ?? internalValue();\n\n const setValue = (next: TabsValue) => {\n // 受控模式:只通知外部,不改本地状态\n if (props.value !== undefined) {\n props.onValueChange?.(next);\n return;\n }\n setInternalValue(next);\n props.onValueChange?.(next);\n };\n\n const isSelected = (v: TabsValue) => value() === v;\n\n // 对齐 base-ui:激活值变化时,若焦点不在 tab 上,将高亮同步到激活 tab\n // (键盘 roving focus 过程中不覆盖,保持相对当前位置导航)\n createEffect(() => {\n const current = value();\n if (current === undefined) return;\n const active = document.activeElement as HTMLElement | null;\n if (active?.getAttribute(\"role\") !== \"tab\") {\n setHighlightedValue(current);\n }\n });\n\n const registerTrigger = (entry: TriggerEntry) => {\n setTriggerOrder((prev) => [...prev, entry]);\n return () =>\n setTriggerOrder((prev) => prev.filter((t) => t.value !== entry.value));\n };\n\n const isFirstEnabled = (v: TabsValue) => {\n const first = triggerOrder().find((t) => !t.disabled());\n return first?.value === v;\n };\n\n const isUsable = (v: TabsValue) =>\n triggerOrder().some((t) => t.value === v && !t.disabled());\n\n const setTriggerId = (v: TabsValue, id: string) =>\n setIds(\"trigger\", String(v), id);\n const getTriggerId = (v: TabsValue) => ids.trigger[String(v)];\n const setContentId = (v: TabsValue, id: string) =>\n setIds(\"content\", String(v), id);\n const getContentId = (v: TabsValue) => ids.content[String(v)];\n\n const contextValue: TabsContextValue = {\n value,\n setValue,\n isSelected,\n orientation: () => props.orientation,\n dir: () => props.dir,\n loop: () => props.loop,\n highlightedValue,\n setHighlightedValue,\n registerTrigger,\n getTriggers: () => triggerOrder(),\n isFirstEnabled,\n isUsable,\n setTriggerId,\n getTriggerId,\n setContentId,\n getContentId,\n };\n\n return (\n <TabsContext.Provider value={contextValue}>\n {props.children}\n </TabsContext.Provider>\n );\n}\n\nexport const useTabsContext = () => {\n const context = useContext(TabsContext);\n if (!context)\n throw new Error(\"useTabsContext must be used within a <Tabs> component\");\n return context;\n};\n"],"mappings":";;;;AAgDA,IAAM+B,IAAc/B,EAAgC;AAEpD,SAAgBgC,EACdC,GAQA;CACA,IAAM,CAACG,GAAeC,KAAoBnC,EACxC+B,EAAMC,YACR,GACM,CAACf,GAAkBC,KAAuBlB,EAE9C,GACI,CAACoC,GAAcC,KAAmBrC,EAA6B,CAAA,CAAE,GACjE,CAACsC,GAAKC,KAAUnC,EAGnB;EAAEoC,SAAS,CAAC;EAAGE,SAAS,CAAC;CAAE,CAAC,GAGzBnC,UAAqCwB,EAAMxB,SAAS2B,EAAc,GAElEtB,KAAY+B,MAAoB;EAEpC,IAAIZ,EAAMxB,UAAUqC,KAAAA,GAAW;GAC7Bb,EAAME,gBAAgBU,CAAI;GAC1B;EACF;EAEAZ,AADAI,EAAiBQ,CAAI,GACrBZ,EAAME,gBAAgBU,CAAI;CAC5B,GAEM9B,KAAcgC,MAAiBtC,EAAM,MAAMsC;CAIjD9C,QAAmB;EACjB,IAAM+C,IAAUvC,EAAM;EAClBuC,MAAYF,KAAAA,KACDI,SAASC,eACZC,aAAa,MAAM,MAAM,SACnChC,EAAoB4B,CAAO;CAE/B,CAAC;CAuBD,IAAMY,IAAiC;EACrCnD;EACAK;EACAC;EACAC,mBAAmBiB,EAAMjB;EACzBC,WAAWgB,EAAMhB;EACjBC,YAAYe,EAAMf;EAClBC;EACAC;EACAC,kBA9BuBC,OACvBiB,GAAiBc,MAAS,CAAC,GAAGA,GAAM/B,CAAK,CAAC,SAExCiB,GAAiBc,MAASA,EAAKC,QAAQC,MAAMA,EAAE9C,UAAUa,EAAMb,KAAK,CAAC;EA4BvEc,mBAAmBe,EAAa;EAChCd,iBA1BsBuB,MACRT,EAAa,CAAC,CAACmB,MAAMF,MAAM,CAACA,EAAE7C,SAAS,CAC9C8C,CAAAA,EAAO/C,UAAUsC;EAyBxBtB,WAtBgBsB,MAChBT,EAAa,CAAC,CAACoB,MAAMH,MAAMA,EAAE9C,UAAUsC,KAAK,CAACQ,EAAE7C,SAAS,CAAC;EAsBzDgB,eApBoBqB,GAAcpB,MAClCc,EAAO,WAAWkB,OAAOZ,CAAC,GAAGpB,CAAE;EAoB/BC,eAnBoBmB,MAAiBP,EAAIE,QAAQiB,OAAOZ,CAAC;EAoBzDlB,eAnBoBkB,GAAcpB,MAClCc,EAAO,WAAWkB,OAAOZ,CAAC,GAAGpB,CAAE;EAmB/BG,eAlBoBiB,MAAiBP,EAAII,QAAQe,OAAOZ,CAAC;CAmB3D;CAEA,OAAAc,EACG9B,EAAY+B,UAAQ;EAACrD,OAAOmD;EAAY,IAAAG,WAAA;GAAA,OACtC9B,EAAM8B;EAAQ;CAAA,CAAA;AAGrB;AAEA,IAAaC,UAAuB;CAClC,IAAMC,IAAU5D,EAAW0B,CAAW;CACtC,IAAI,CAACkC,GACH,MAAUC,MAAM,uDAAuD;CACzE,OAAOD;AACT"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { clsx as e } from "../../../utils/clsx.js";
|
|
2
|
+
import { TabsProvider as t } from "./Tabs.context.js";
|
|
3
|
+
import { createComponent as n, insert as r, mergeProps as i, spread as a, template as o } from "solid-js/web";
|
|
4
|
+
import { mergeProps as s, splitProps as c } from "solid-js";
|
|
5
|
+
//#region src/components/tabs/Tabs/Tabs.tsx
|
|
6
|
+
var l = /*#__PURE__*/ o("<div data-slot=tabs>"), u = (o) => {
|
|
7
|
+
let u = s({
|
|
8
|
+
orientation: "horizontal",
|
|
9
|
+
loop: !0,
|
|
10
|
+
dir: "ltr"
|
|
11
|
+
}, o), [d, f] = c(u, [
|
|
12
|
+
"defaultValue",
|
|
13
|
+
"value",
|
|
14
|
+
"onValueChange",
|
|
15
|
+
"orientation",
|
|
16
|
+
"loop",
|
|
17
|
+
"dir",
|
|
18
|
+
"class",
|
|
19
|
+
"classList",
|
|
20
|
+
"children"
|
|
21
|
+
]), p = () => d.orientation === "vertical";
|
|
22
|
+
return (() => {
|
|
23
|
+
var o = l();
|
|
24
|
+
return a(o, i({
|
|
25
|
+
get "data-orientation"() {
|
|
26
|
+
return d.orientation;
|
|
27
|
+
},
|
|
28
|
+
get "data-vertical"() {
|
|
29
|
+
return p() ? "" : null;
|
|
30
|
+
},
|
|
31
|
+
get "data-horizontal"() {
|
|
32
|
+
return p() ? null : "";
|
|
33
|
+
},
|
|
34
|
+
get dir() {
|
|
35
|
+
return d.dir;
|
|
36
|
+
},
|
|
37
|
+
get class() {
|
|
38
|
+
return e("group/tabs flex gap-2 data-[orientation=horizontal]:flex-col", d.class);
|
|
39
|
+
},
|
|
40
|
+
get classList() {
|
|
41
|
+
return d.classList;
|
|
42
|
+
}
|
|
43
|
+
}, f), !1, !0), r(o, n(t, {
|
|
44
|
+
get defaultValue() {
|
|
45
|
+
return d.defaultValue;
|
|
46
|
+
},
|
|
47
|
+
get value() {
|
|
48
|
+
return d.value;
|
|
49
|
+
},
|
|
50
|
+
get onValueChange() {
|
|
51
|
+
return d.onValueChange;
|
|
52
|
+
},
|
|
53
|
+
get orientation() {
|
|
54
|
+
return d.orientation;
|
|
55
|
+
},
|
|
56
|
+
get dir() {
|
|
57
|
+
return d.dir;
|
|
58
|
+
},
|
|
59
|
+
get loop() {
|
|
60
|
+
return d.loop;
|
|
61
|
+
},
|
|
62
|
+
get children() {
|
|
63
|
+
return d.children;
|
|
64
|
+
}
|
|
65
|
+
})), o;
|
|
66
|
+
})();
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
export { u as Tabs };
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=Tabs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tabs.js","names":["mergeProps","splitProps","TabsProps","clsx","TabsProvider","Tabs","props","merged","orientation","loop","dir","const","local","others","isVertical","_el$","_tmpl$","_$spread","_$mergeProps","data-orientation","data-vertical","data-horizontal","class","classList","_$insert","_$createComponent","defaultValue","value","onValueChange","children"],"sources":["../../../../src/components/tabs/Tabs/Tabs.tsx"],"sourcesContent":["import { mergeProps, splitProps } from \"solid-js\";\nimport type { TabsProps } from \"./Tabs.types\";\nimport { clsx } from \"~/utils\";\nimport { TabsProvider } from \"./Tabs.context\";\n\nexport const Tabs = (props: TabsProps) => {\n const merged = mergeProps(\n {\n orientation: \"horizontal\",\n loop: true,\n dir: \"ltr\",\n } as const,\n props,\n );\n const [local, others] = splitProps(merged, [\n \"defaultValue\",\n \"value\",\n \"onValueChange\",\n \"orientation\",\n \"loop\",\n \"dir\",\n \"class\",\n \"classList\",\n \"children\",\n ]);\n\n const isVertical = () => local.orientation === \"vertical\";\n\n return (\n <div\n data-slot=\"tabs\"\n data-orientation={local.orientation}\n // 现有样式依赖 group-data-vertical/tabs 与 group-data-horizontal/tabs,\n // 需要根元素上的 data-vertical / data-horizontal 属性才能生效\n data-vertical={isVertical() ? \"\" : null}\n data-horizontal={isVertical() ? null : \"\"}\n dir={local.dir}\n class={clsx(\n \"group/tabs flex gap-2 data-[orientation=horizontal]:flex-col\",\n local.class,\n )}\n classList={local.classList}\n {...others}\n >\n <TabsProvider\n defaultValue={local.defaultValue}\n value={local.value}\n onValueChange={local.onValueChange}\n orientation={local.orientation}\n dir={local.dir}\n loop={local.loop}\n >\n {local.children}\n </TabsProvider>\n </div>\n );\n};\n"],"mappings":";;;;;iDAKaK,KAAQC,MAAqB;CACxC,IAAMC,IAASP,EACb;EACEQ,aAAa;EACbC,MAAM;EACNC,KAAK;CACP,GACAJ,CACF,GACM,CAACM,GAAOC,KAAUZ,EAAWM,GAAQ;EACzC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAAU,CACX,GAEKO,UAAmBF,EAAMJ,gBAAgB;CAE/C,cAAA;EAAA,IAAAO,IAAAC,EAAA;EAwBqB,OAxBrBC,EAAAF,GAAAG,EAAA;GAAA,IAAA,qBAAA;IAAA,OAGsBN,EAAMJ;GAAW;GAAA,IAAA,kBAAA;IAAA,OAGpBM,EAAW,IAAI,KAAK;GAAI;GAAA,IAAA,oBAAA;IAAA,OACtBA,EAAW,IAAI,OAAO;GAAE;GAAA,IACzCJ,MAAG;IAAA,OAAEE,EAAMF;GAAG;GAAA,IAAA,QAAA;IAAA,OACPP,EACL,gEACAS,EAAMU,KACR;GAAC;GAAA,IACDC,YAAS;IAAA,OAAEX,EAAMW;GAAS;EAAA,GACtBV,CAAM,GAAA,IAAA,EAAA,GAAAW,EAAAT,GAAAU,EAETrB,GAAY;GAAA,IACXsB,eAAY;IAAA,OAAEd,EAAMc;GAAY;GAAA,IAChCC,QAAK;IAAA,OAAEf,EAAMe;GAAK;GAAA,IAClBC,gBAAa;IAAA,OAAEhB,EAAMgB;GAAa;GAAA,IAClCpB,cAAW;IAAA,OAAEI,EAAMJ;GAAW;GAAA,IAC9BE,MAAG;IAAA,OAAEE,EAAMF;GAAG;GAAA,IACdD,OAAI;IAAA,OAAEG,EAAMH;GAAI;GAAA,IAAAoB,WAAA;IAAA,OAEfjB,EAAMiB;GAAQ;EAAA,CAAA,CAAA,GAAAd;CAAA,EAAA,CAAA;AAIvB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseProps, PolymorphicProps } from '../../../types';
|
|
2
|
+
export type TabsValue = string | number;
|
|
3
|
+
interface BaseTabsProps extends BaseProps {
|
|
4
|
+
/** 非受控模式:初始激活值 */
|
|
5
|
+
defaultValue?: TabsValue;
|
|
6
|
+
/** 受控模式:激活值(提供后组件不再自管状态) */
|
|
7
|
+
value?: TabsValue;
|
|
8
|
+
/** 值变化回调(受控与非受控都会触发) */
|
|
9
|
+
onValueChange?: (value: TabsValue) => void;
|
|
10
|
+
/** 布局方向,默认 "horizontal" */
|
|
11
|
+
orientation?: "horizontal" | "vertical";
|
|
12
|
+
/** 方向键是否循环,默认 true */
|
|
13
|
+
loop?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export type TabsProps = PolymorphicProps<"div", BaseTabsProps, false>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/components/tabs/Tabs/call-event-handler.ts
|
|
2
|
+
function e(e, t) {
|
|
3
|
+
let n = Array.isArray(e) ? e : [e];
|
|
4
|
+
for (let e of n) typeof e == "function" && e(t);
|
|
5
|
+
}
|
|
6
|
+
//#endregion
|
|
7
|
+
export { e as callEventHandler };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=call-event-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-event-handler.js","names":[],"sources":["../../../../src/components/tabs/Tabs/call-event-handler.ts"],"sourcesContent":["/**\n * 调用用户传入的事件处理器(兼容 Solid 的函数或函数数组形式)。\n * splitProps restKeys 提取出的事件类型是 EventHandlerUnion,不能直接调用。\n */\nexport function callEventHandler<E extends Event>(\n handler: unknown,\n event: E,\n): void {\n const list = Array.isArray(handler) ? handler : [handler];\n for (const h of list) {\n if (typeof h === \"function\") (h as (e: E) => void)(event);\n }\n}\n"],"mappings":";AAIA,SAAgB,EACd,GACA,GACM;CACN,IAAM,IAAO,MAAM,QAAQ,CAAO,IAAI,IAAU,CAAC,CAAO;CACxD,KAAK,IAAM,KAAK,GACd,AAAI,OAAO,KAAM,cAAY,EAAsB,CAAK;AAE5D"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { TabsContextValue } from './Tabs.context';
|
|
2
|
+
/**
|
|
3
|
+
* tablist 的 roving focus 键盘导航(纯逻辑,可在事件中独立单测)
|
|
4
|
+
*
|
|
5
|
+
* 方向映射:
|
|
6
|
+
* - horizontal + ltr: ArrowRight → next, ArrowLeft → prev
|
|
7
|
+
* - horizontal + rtl: 左右反转
|
|
8
|
+
* - vertical: ArrowDown → next, ArrowUp → prev
|
|
9
|
+
* - Home → 第一个,End → 最后一个
|
|
10
|
+
* - loop=true 环绕,false 边界停止;跳过 disabled 的 trigger
|
|
11
|
+
*
|
|
12
|
+
* 与 base-ui 一致:方向键只移动焦点(触发 onFocus 更新高亮),不激活;
|
|
13
|
+
* 激活靠点击(Enter/Space 触发 button 的 click)。activateOnFocus 时的
|
|
14
|
+
* 聚焦激活由 TabsTrigger 的 onFocus 处理,这里不做。
|
|
15
|
+
*/
|
|
16
|
+
export declare function useTabsKeyboard(ctx: TabsContextValue): {
|
|
17
|
+
handleKeyDown: (e: KeyboardEvent) => void;
|
|
18
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//#region src/components/tabs/Tabs/useTabsKeyboard.ts
|
|
2
|
+
var e = /* @__PURE__ */ new Set([
|
|
3
|
+
"ArrowLeft",
|
|
4
|
+
"ArrowRight",
|
|
5
|
+
"ArrowUp",
|
|
6
|
+
"ArrowDown",
|
|
7
|
+
"Home",
|
|
8
|
+
"End"
|
|
9
|
+
]);
|
|
10
|
+
function t(t) {
|
|
11
|
+
return { handleKeyDown: (n) => {
|
|
12
|
+
if (!e.has(n.key)) return;
|
|
13
|
+
let r = document.activeElement;
|
|
14
|
+
if (r?.getAttribute("role") !== "tab") return;
|
|
15
|
+
let i = t.getTriggers().filter((e) => !e.disabled());
|
|
16
|
+
if (i.length === 0) return;
|
|
17
|
+
let a = i.findIndex((e) => e.element === r);
|
|
18
|
+
if (a === -1) return;
|
|
19
|
+
let o = t.orientation() === "vertical", s = t.dir(), c = s === "rtl" || s === "auto" && typeof document < "u" && document.documentElement.dir === "rtl", l;
|
|
20
|
+
switch (n.key) {
|
|
21
|
+
case "Home":
|
|
22
|
+
l = 0;
|
|
23
|
+
break;
|
|
24
|
+
case "End":
|
|
25
|
+
l = i.length - 1;
|
|
26
|
+
break;
|
|
27
|
+
case "ArrowLeft":
|
|
28
|
+
if (o) return;
|
|
29
|
+
l = a + (c ? 1 : -1);
|
|
30
|
+
break;
|
|
31
|
+
case "ArrowRight":
|
|
32
|
+
if (o) return;
|
|
33
|
+
l = a + (c ? -1 : 1);
|
|
34
|
+
break;
|
|
35
|
+
case "ArrowUp":
|
|
36
|
+
if (!o) return;
|
|
37
|
+
l = a - 1;
|
|
38
|
+
break;
|
|
39
|
+
case "ArrowDown":
|
|
40
|
+
if (!o) return;
|
|
41
|
+
l = a + 1;
|
|
42
|
+
}
|
|
43
|
+
l !== void 0 && (n.preventDefault(), l = t.loop() ? (l + i.length) % i.length : Math.min(i.length - 1, Math.max(0, l)), i[l].element.focus());
|
|
44
|
+
} };
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { t as useTabsKeyboard };
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=useTabsKeyboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTabsKeyboard.js","names":[],"sources":["../../../../src/components/tabs/Tabs/useTabsKeyboard.ts"],"sourcesContent":["import type { TabsContextValue } from \"./Tabs.context\";\n\nconst NAV_KEYS = new Set([\n \"ArrowLeft\",\n \"ArrowRight\",\n \"ArrowUp\",\n \"ArrowDown\",\n \"Home\",\n \"End\",\n]);\n\n/**\n * tablist 的 roving focus 键盘导航(纯逻辑,可在事件中独立单测)\n *\n * 方向映射:\n * - horizontal + ltr: ArrowRight → next, ArrowLeft → prev\n * - horizontal + rtl: 左右反转\n * - vertical: ArrowDown → next, ArrowUp → prev\n * - Home → 第一个,End → 最后一个\n * - loop=true 环绕,false 边界停止;跳过 disabled 的 trigger\n *\n * 与 base-ui 一致:方向键只移动焦点(触发 onFocus 更新高亮),不激活;\n * 激活靠点击(Enter/Space 触发 button 的 click)。activateOnFocus 时的\n * 聚焦激活由 TabsTrigger 的 onFocus 处理,这里不做。\n */\nexport function useTabsKeyboard(ctx: TabsContextValue) {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (!NAV_KEYS.has(e.key)) return;\n\n const activeEl = document.activeElement as HTMLElement | null;\n // 只有焦点在 tab 上时才接管键盘\n if (activeEl?.getAttribute(\"role\") !== \"tab\") return;\n\n const tabs = ctx.getTriggers().filter((t) => !t.disabled());\n if (tabs.length === 0) return;\n\n const currentIndex = tabs.findIndex((t) => t.element === activeEl);\n if (currentIndex === -1) return;\n\n const isVertical = ctx.orientation() === \"vertical\";\n // dir=auto 时回退到文档实际方向\n const dir = ctx.dir();\n const isRTL =\n dir === \"rtl\" ||\n (dir === \"auto\" &&\n typeof document !== \"undefined\" &&\n document.documentElement.dir === \"rtl\");\n\n let nextIndex: number | undefined;\n switch (e.key) {\n case \"Home\":\n nextIndex = 0;\n break;\n case \"End\":\n nextIndex = tabs.length - 1;\n break;\n case \"ArrowLeft\":\n if (isVertical) return;\n nextIndex = currentIndex + (isRTL ? 1 : -1);\n break;\n case \"ArrowRight\":\n if (isVertical) return;\n nextIndex = currentIndex + (isRTL ? -1 : 1);\n break;\n case \"ArrowUp\":\n if (!isVertical) return;\n nextIndex = currentIndex - 1;\n break;\n case \"ArrowDown\":\n if (!isVertical) return;\n nextIndex = currentIndex + 1;\n break;\n }\n\n if (nextIndex === undefined) return;\n\n // 方向键与当前布局匹配,接管默认滚动行为\n e.preventDefault();\n\n if (ctx.loop()) {\n nextIndex = (nextIndex + tabs.length) % tabs.length;\n } else {\n nextIndex = Math.min(tabs.length - 1, Math.max(0, nextIndex));\n }\n\n // focus 触发 trigger 的 onFocus → 更新高亮(及 activateOnFocus 时激活)\n tabs[nextIndex].element.focus();\n };\n\n return { handleKeyDown };\n}\n"],"mappings":";AAEA,IAAM,oBAAW,IAAI,IAAI;CACvB;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAgBD,SAAgB,EAAgB,GAAuB;CAgErD,OAAO,EAAE,gBA/Dc,MAAqB;EAC1C,IAAI,CAAC,EAAS,IAAI,EAAE,GAAG,GAAG;EAE1B,IAAM,IAAW,SAAS;EAE1B,IAAI,GAAU,aAAa,MAAM,MAAM,OAAO;EAE9C,IAAM,IAAO,EAAI,YAAY,CAAC,CAAC,QAAQ,MAAM,CAAC,EAAE,SAAS,CAAC;EAC1D,IAAI,EAAK,WAAW,GAAG;EAEvB,IAAM,IAAe,EAAK,WAAW,MAAM,EAAE,YAAY,CAAQ;EACjE,IAAI,MAAiB,IAAI;EAEzB,IAAM,IAAa,EAAI,YAAY,MAAM,YAEnC,IAAM,EAAI,IAAI,GACd,IACJ,MAAQ,SACP,MAAQ,UACP,OAAO,WAAa,OACpB,SAAS,gBAAgB,QAAQ,OAEjC;EACJ,QAAQ,EAAE,KAAV;GACE,KAAK;IACH,IAAY;IACZ;GACF,KAAK;IACH,IAAY,EAAK,SAAS;IAC1B;GACF,KAAK;IACH,IAAI,GAAY;IAChB,IAAY,KAAgB,IAAQ,IAAI;IACxC;GACF,KAAK;IACH,IAAI,GAAY;IAChB,IAAY,KAAgB,IAAQ,KAAK;IACzC;GACF,KAAK;IACH,IAAI,CAAC,GAAY;IACjB,IAAY,IAAe;IAC3B;GACF,KAAK;IACH,IAAI,CAAC,GAAY;IACjB,IAAY,IAAe;EAE/B;EAEI,MAAc,KAAA,MAGlB,EAAE,eAAe,GAEjB,AAGE,IAHE,EAAI,KAAK,KACE,IAAY,EAAK,UAAU,EAAK,SAEjC,KAAK,IAAI,EAAK,SAAS,GAAG,KAAK,IAAI,GAAG,CAAS,CAAC,GAI9D,EAAK,EAAU,CAAC,QAAQ,MAAM;CAChC,EAEuB;AACzB"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { clsx as e } from "../../../utils/clsx.js";
|
|
2
|
+
import { useTabsContext as t } from "../Tabs/Tabs.context.js";
|
|
3
|
+
import { createComponent as n, memo as r, mergeProps as i, setAttribute as a, spread as o, template as s } from "solid-js/web";
|
|
4
|
+
import { Show as c, createUniqueId as l, onMount as u, splitProps as d } from "solid-js";
|
|
5
|
+
//#region src/components/tabs/TabsContent/TabsContent.tsx
|
|
6
|
+
var f = /*#__PURE__*/ s("<div role=tabpanel data-slot=tabs-content tabindex=0>"), p = (s) => {
|
|
7
|
+
let [p, m] = d(s, [
|
|
8
|
+
"value",
|
|
9
|
+
"forceMount",
|
|
10
|
+
"class",
|
|
11
|
+
"classList",
|
|
12
|
+
"style"
|
|
13
|
+
]), h = t(), g = `tabs-content-${l()}`;
|
|
14
|
+
u(() => h.setContentId(p.value, g));
|
|
15
|
+
let _ = () => h.isSelected(p.value), v = () => _() || !!p.forceMount, y = () => _() || !p.forceMount ? p.style : {
|
|
16
|
+
...p.style,
|
|
17
|
+
display: "none"
|
|
18
|
+
};
|
|
19
|
+
return n(c, {
|
|
20
|
+
get when() {
|
|
21
|
+
return v();
|
|
22
|
+
},
|
|
23
|
+
get children() {
|
|
24
|
+
var t = f();
|
|
25
|
+
return a(t, "id", g), o(t, i({
|
|
26
|
+
get "aria-labelledby"() {
|
|
27
|
+
return h.getTriggerId(p.value);
|
|
28
|
+
},
|
|
29
|
+
get "data-active"() {
|
|
30
|
+
return _() ? "" : null;
|
|
31
|
+
},
|
|
32
|
+
get class() {
|
|
33
|
+
return e("flex-1 text-sm outline-none", p.class);
|
|
34
|
+
},
|
|
35
|
+
get classList() {
|
|
36
|
+
return p.classList;
|
|
37
|
+
}
|
|
38
|
+
}, m, {
|
|
39
|
+
get hidden() {
|
|
40
|
+
return r(() => !_())() && !!p.forceMount;
|
|
41
|
+
},
|
|
42
|
+
get style() {
|
|
43
|
+
return y();
|
|
44
|
+
}
|
|
45
|
+
}), !1, !1), t;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
//#endregion
|
|
50
|
+
export { p as TabsContent };
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=TabsContent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TabsContent.js","names":["createUniqueId","onMount","Show","splitProps","JSX","clsx","useTabsContext","TabsContentProps","TabsContent","props","local","others","ctx","id","contentId","setContentId","value","selected","isSelected","mounted","forceMount","style","CSSProperties","display","_$createComponent","when","children","_el$","_tmpl$","_$setAttribute","_$spread","_$mergeProps","aria-labelledby","getTriggerId","data-active","class","classList","hidden","_$memo"],"sources":["../../../../src/components/tabs/TabsContent/TabsContent.tsx"],"sourcesContent":["import { createUniqueId, onMount, Show, splitProps } from \"solid-js\";\nimport type { JSX } from \"solid-js\";\nimport { clsx } from \"~/utils\";\nimport { useTabsContext } from \"../Tabs/Tabs.context\";\nimport type { TabsContentProps } from \"./TabsContent.types\";\n\nexport const TabsContent = (props: TabsContentProps) => {\n const [local, others] = splitProps(props, [\n \"value\",\n \"forceMount\",\n \"class\",\n \"classList\",\n \"style\",\n ]);\n const ctx = useTabsContext();\n\n const id = createUniqueId();\n const contentId = `tabs-content-${id}`;\n\n onMount(() => ctx.setContentId(local.value, contentId));\n\n const selected = () => ctx.isSelected(local.value);\n const mounted = () => selected() || !!local.forceMount;\n\n // flex-1 的 display:flex 会覆盖 UA 的 [hidden] 规则,forceMount 隐藏必须显式 display:none\n const style = (): JSX.CSSProperties | undefined => {\n if (selected() || !local.forceMount) return local.style;\n return { ...local.style, display: \"none\" };\n };\n\n return (\n <Show when={mounted()}>\n <div\n id={contentId}\n role=\"tabpanel\"\n data-slot=\"tabs-content\"\n aria-labelledby={ctx.getTriggerId(local.value)}\n tabindex=\"0\"\n data-active={selected() ? \"\" : null}\n class={clsx(\"flex-1 text-sm outline-none\", local.class)}\n classList={local.classList}\n {...others}\n hidden={!selected() && !!local.forceMount}\n style={style()}\n />\n </Show>\n );\n};\n"],"mappings":";;;;;kFAMaQ,KAAeC,MAA4B;CACtD,IAAM,CAACC,GAAOC,KAAUR,EAAWM,GAAO;EACxC;EACA;EACA;EACA;EACA;CAAO,CACR,GACKG,IAAMN,EAAe,GAGrBQ,IAAY,gBADPd,EACuBa;CAElCZ,QAAcW,EAAIG,aAAaL,EAAMM,OAAOF,CAAS,CAAC;CAEtD,IAAMG,UAAiBL,EAAIM,WAAWR,EAAMM,KAAK,GAC3CG,UAAgBF,EAAS,KAAK,CAAC,CAACP,EAAMU,YAGtCC,UACAJ,EAAS,KAAK,CAACP,EAAMU,aAAmBV,EAAMW,QAC3C;EAAE,GAAGX,EAAMW;EAAOE,SAAS;CAAO;CAG3C,OAAAC,EACGtB,GAAI;EAAA,IAACuB,OAAI;GAAA,OAAEN,EAAQ;EAAC;EAAA,IAAAO,WAAA;GAAA,IAAAC,IAAAC,EAAA;GAYH,OAZGC,EAAAF,GAAA,MAEbb,CAAS,GAAAgB,EAAAH,GAAAI,EAAA;IAAA,IAAA,oBAAA;KAAA,OAGInB,EAAIqB,aAAavB,EAAMM,KAAK;IAAC;IAAA,IAAA,gBAAA;KAAA,OAEjCC,EAAS,IAAI,KAAK;IAAI;IAAA,IAAA,QAAA;KAAA,OAC5BZ,EAAK,+BAA+BK,EAAMyB,KAAK;IAAC;IAAA,IACvDC,YAAS;KAAA,OAAE1B,EAAM0B;IAAS;GAAA,GACtBzB,GAAM;IAAA,IACV0B,SAAM;KAAA,OAAEC,QAAA,CAACrB,EAAS,CAAC,CAAA,CAAA,KAAI,CAAC,CAACP,EAAMU;IAAU;IAAA,IACzCC,QAAK;KAAA,OAAEA,EAAM;IAAC;GAAA,CAAA,GAAA,IAAA,EAAA,GAAAM;EAAA;CAAA,CAAA;AAItB"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface TabsListContextValue {
|
|
2
|
+
/** 聚焦是否激活 tab(base-ui 语义,默认 false:聚焦只高亮,点击才激活) */
|
|
3
|
+
activateOnFocus: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare const TabsListContext: import('solid-js').Context<TabsListContextValue | undefined>;
|
|
6
|
+
export declare const useTabsListContext: () => TabsListContextValue;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createContext as e, useContext as t } from "solid-js";
|
|
2
|
+
//#region src/components/tabs/TabsList/TabsList.context.ts
|
|
3
|
+
var n = e(), r = () => {
|
|
4
|
+
let e = t(n);
|
|
5
|
+
if (!e) throw Error("useTabsListContext must be used within a <TabsList> component");
|
|
6
|
+
return e;
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
9
|
+
export { n as TabsListContext, r as useTabsListContext };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=TabsList.context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TabsList.context.js","names":[],"sources":["../../../../src/components/tabs/TabsList/TabsList.context.ts"],"sourcesContent":["import { createContext, useContext } from \"solid-js\";\n\ninterface TabsListContextValue {\n /** 聚焦是否激活 tab(base-ui 语义,默认 false:聚焦只高亮,点击才激活) */\n activateOnFocus: boolean;\n}\n\nexport const TabsListContext = createContext<TabsListContextValue>();\n\nexport const useTabsListContext = () => {\n const context = useContext(TabsListContext);\n if (!context)\n throw new Error(\n \"useTabsListContext must be used within a <TabsList> component\",\n );\n return context;\n};\n"],"mappings":";;AAOA,IAAa,IAAkB,EAAoC,GAEtD,UAA2B;CACtC,IAAM,IAAU,EAAW,CAAe;CAC1C,IAAI,CAAC,GACH,MAAU,MACR,+DACF;CACF,OAAO;AACT"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { clsx as e } from "../../../utils/clsx.js";
|
|
2
|
+
import { useTabsContext as t } from "../Tabs/Tabs.context.js";
|
|
3
|
+
import { tabsListVariants as n } from "./TabsList.styles.js";
|
|
4
|
+
import { useTabsKeyboard as r } from "../Tabs/useTabsKeyboard.js";
|
|
5
|
+
import { callEventHandler as i } from "../Tabs/call-event-handler.js";
|
|
6
|
+
import { TabsListContext as a } from "./TabsList.context.js";
|
|
7
|
+
import { createComponent as o, mergeProps as s, spread as c, template as l } from "solid-js/web";
|
|
8
|
+
import { mergeProps as u, splitProps as d } from "solid-js";
|
|
9
|
+
//#region src/components/tabs/TabsList/TabsList.tsx
|
|
10
|
+
var f = /*#__PURE__*/ l("<div role=tablist data-slot=tabs-list>"), p = (l) => {
|
|
11
|
+
let p = u({
|
|
12
|
+
variant: "secondary",
|
|
13
|
+
activateOnFocus: !1
|
|
14
|
+
}, l), [m, h, g] = d(p, [
|
|
15
|
+
"variant",
|
|
16
|
+
"class",
|
|
17
|
+
"classList",
|
|
18
|
+
"activateOnFocus"
|
|
19
|
+
], ["onKeyDown"]), _ = t(), { handleKeyDown: v } = r(_);
|
|
20
|
+
return o(a.Provider, {
|
|
21
|
+
get value() {
|
|
22
|
+
return { activateOnFocus: m.activateOnFocus };
|
|
23
|
+
},
|
|
24
|
+
get children() {
|
|
25
|
+
var t = f();
|
|
26
|
+
return c(t, s({
|
|
27
|
+
get "data-variant"() {
|
|
28
|
+
return m.variant;
|
|
29
|
+
},
|
|
30
|
+
get "aria-orientation"() {
|
|
31
|
+
return _.orientation() === "vertical" ? "vertical" : void 0;
|
|
32
|
+
},
|
|
33
|
+
get class() {
|
|
34
|
+
return e(n({ variant: m.variant }), m.class);
|
|
35
|
+
},
|
|
36
|
+
get classList() {
|
|
37
|
+
return m.classList;
|
|
38
|
+
}
|
|
39
|
+
}, g, { onKeyDown: (e) => {
|
|
40
|
+
v(e), i(h.onKeyDown, e);
|
|
41
|
+
} }), !1, !1), t;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
export { p as TabsList };
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=TabsList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TabsList.js","names":["mergeProps","splitProps","TabsListProps","clsx","tabsListVariants","useTabsContext","useTabsKeyboard","callEventHandler","TabsListContext","TabsList","props","merged","variant","activateOnFocus","const","local","events","others","ctx","handleKeyDown","_$createComponent","Provider","value","children","_el$","_tmpl$","_$spread","_$mergeProps","data-variant","aria-orientation","orientation","undefined","class","classList","e","onKeyDown"],"sources":["../../../../src/components/tabs/TabsList/TabsList.tsx"],"sourcesContent":["import { mergeProps, splitProps } from \"solid-js\";\nimport type { TabsListProps } from \"./TabsList.types\";\nimport { clsx } from \"~/utils\";\nimport { tabsListVariants } from \"./TabsList.styles\";\nimport { useTabsContext } from \"../Tabs/Tabs.context\";\nimport { useTabsKeyboard } from \"../Tabs/useTabsKeyboard\";\nimport { callEventHandler } from \"../Tabs/call-event-handler\";\nimport { TabsListContext } from \"./TabsList.context\";\n\nexport const TabsList = (props: TabsListProps) => {\n const merged = mergeProps(\n { variant: \"secondary\", activateOnFocus: false } as const,\n props,\n );\n const [local, events, others] = splitProps(\n merged,\n [\"variant\", \"class\", \"classList\", \"activateOnFocus\"],\n [\"onKeyDown\"],\n );\n\n const ctx = useTabsContext();\n const { handleKeyDown } = useTabsKeyboard(ctx);\n\n return (\n <TabsListContext.Provider\n value={{ activateOnFocus: local.activateOnFocus }}\n >\n <div\n role=\"tablist\"\n data-slot=\"tabs-list\"\n data-variant={local.variant}\n aria-orientation={\n ctx.orientation() === \"vertical\" ? \"vertical\" : undefined\n }\n class={clsx(tabsListVariants({ variant: local.variant }), local.class)}\n classList={local.classList}\n {...others}\n onKeyDown={(e) => {\n handleKeyDown(e);\n callEventHandler(events.onKeyDown, e);\n }}\n />\n </TabsListContext.Provider>\n );\n};\n"],"mappings":";;;;;;;;;mEASaS,KAAYC,MAAyB;CAChD,IAAMC,IAASX,EACb;EAAEY,SAAS;EAAaC,iBAAiB;CAAM,GAC/CH,CACF,GACM,CAACK,GAAOC,GAAQC,KAAUhB,EAC9BU,GACA;EAAC;EAAW;EAAS;EAAa;CAAiB,GACnD,CAAC,WAAW,CACd,GAEMO,IAAMb,EAAe,GACrB,EAAEc,qBAAkBb,EAAgBY,CAAG;CAE7C,OAAAE,EACGZ,EAAgBa,UAAQ;EAAA,IACvBC,QAAK;GAAA,OAAE,EAAET,iBAAiBE,EAAMF,gBAAgB;EAAC;EAAA,IAAAU,WAAA;GAAA,IAAAC,IAAAC,EAAA;GAe9C,OAf8CC,EAAAF,GAAAG,EAAA;IAAA,IAAA,iBAAA;KAAA,OAKjCZ,EAAMH;IAAO;IAAA,IAAA,qBAAA;KAAA,OAEzBM,EAAIY,YAAY,MAAM,aAAa,aAAaC,KAAAA;IAAS;IAAA,IAAA,QAAA;KAAA,OAEpD5B,EAAKC,EAAiB,EAAEQ,SAASG,EAAMH,QAAQ,CAAC,GAAGG,EAAMiB,KAAK;IAAC;IAAA,IACtEC,YAAS;KAAA,OAAElB,EAAMkB;IAAS;GAAA,GACtBhB,GAAM,EAAA,YACEiB,MAAM;IAEhB3B,AADAY,EAAce,CAAC,GACf3B,EAAiBS,EAAOmB,WAAWD,CAAC;GACtC,EAAC,CAAA,GAAA,IAAA,EAAA,GAAAV;EAAA;CAAA,CAAA;AAIT"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { cva as e } from "class-variance-authority";
|
|
2
|
+
//#region src/components/tabs/TabsList/TabsList.styles.ts
|
|
3
|
+
var t = e("group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-0.75 text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none", {
|
|
4
|
+
variants: { variant: {
|
|
5
|
+
secondary: "bg-muted",
|
|
6
|
+
line: "gap-1 bg-transparent"
|
|
7
|
+
} },
|
|
8
|
+
defaultVariants: { variant: "secondary" }
|
|
9
|
+
});
|
|
10
|
+
//#endregion
|
|
11
|
+
export { t as tabsListVariants };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=TabsList.styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TabsList.styles.js","names":[],"sources":["../../../../src/components/tabs/TabsList/TabsList.styles.ts"],"sourcesContent":["import { cva } from \"class-variance-authority\";\n\nexport const tabsListVariants = cva(\n \"group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-0.75 text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none\",\n {\n variants: {\n variant: {\n secondary: \"bg-muted\",\n line: \"gap-1 bg-transparent\",\n },\n },\n defaultVariants: {\n variant: \"secondary\",\n },\n },\n);\n"],"mappings":";;AAEA,IAAa,IAAmB,EAC9B,0OACA;CACE,UAAU,EACR,SAAS;EACP,WAAW;EACX,MAAM;CACR,EACF;CACA,iBAAiB,EACf,SAAS,YACX;AACF,CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { VariantProps } from 'class-variance-authority';
|
|
2
|
+
import { BaseProps, PolymorphicProps } from '../../../types';
|
|
3
|
+
import { tabsListVariants } from './TabsList.styles';
|
|
4
|
+
export type TabsListProps = PolymorphicProps<"div", BaseProps & VariantProps<typeof tabsListVariants> & {
|
|
5
|
+
/** 聚焦 tab 时是否同时激活,默认 false(与 base-ui 一致) */
|
|
6
|
+
activateOnFocus?: boolean;
|
|
7
|
+
}, false>;
|