@simplysm/solid 13.0.53 → 13.0.56
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 +6 -2
- package/dist/components/data/crud-detail/CrudDetail.d.ts +14 -0
- package/dist/components/data/crud-detail/CrudDetail.d.ts.map +1 -0
- package/dist/components/data/crud-detail/CrudDetail.js +348 -0
- package/dist/components/data/crud-detail/CrudDetail.js.map +6 -0
- package/dist/components/data/crud-detail/CrudDetailAfter.d.ts +7 -0
- package/dist/components/data/crud-detail/CrudDetailAfter.d.ts.map +1 -0
- package/dist/components/data/crud-detail/CrudDetailAfter.js +14 -0
- package/dist/components/data/crud-detail/CrudDetailAfter.js.map +6 -0
- package/dist/components/data/crud-detail/CrudDetailBefore.d.ts +7 -0
- package/dist/components/data/crud-detail/CrudDetailBefore.d.ts.map +1 -0
- package/dist/components/data/crud-detail/CrudDetailBefore.js +14 -0
- package/dist/components/data/crud-detail/CrudDetailBefore.js.map +6 -0
- package/dist/components/data/crud-detail/CrudDetailTools.d.ts +7 -0
- package/dist/components/data/crud-detail/CrudDetailTools.d.ts.map +1 -0
- package/dist/components/data/crud-detail/CrudDetailTools.js +14 -0
- package/dist/components/data/crud-detail/CrudDetailTools.js.map +6 -0
- package/dist/components/data/crud-detail/types.d.ts +45 -0
- package/dist/components/data/crud-detail/types.d.ts.map +1 -0
- package/dist/components/data/crud-detail/types.js +1 -0
- package/dist/components/data/crud-detail/types.js.map +6 -0
- package/dist/components/data/crud-sheet/CrudSheet.d.ts +17 -0
- package/dist/components/data/crud-sheet/CrudSheet.d.ts.map +1 -0
- package/dist/components/data/crud-sheet/CrudSheet.js +679 -0
- package/dist/components/data/crud-sheet/CrudSheet.js.map +6 -0
- package/dist/components/data/crud-sheet/CrudSheetColumn.d.ts +5 -0
- package/dist/components/data/crud-sheet/CrudSheetColumn.d.ts.map +1 -0
- package/dist/components/data/crud-sheet/CrudSheetColumn.js +29 -0
- package/dist/components/data/crud-sheet/CrudSheetColumn.js.map +6 -0
- package/dist/components/data/crud-sheet/CrudSheetFilter.d.ts +7 -0
- package/dist/components/data/crud-sheet/CrudSheetFilter.d.ts.map +1 -0
- package/dist/components/data/crud-sheet/CrudSheetFilter.js +14 -0
- package/dist/components/data/crud-sheet/CrudSheetFilter.js.map +6 -0
- package/dist/components/data/crud-sheet/CrudSheetHeader.d.ts +7 -0
- package/dist/components/data/crud-sheet/CrudSheetHeader.d.ts.map +1 -0
- package/dist/components/data/crud-sheet/CrudSheetHeader.js +14 -0
- package/dist/components/data/crud-sheet/CrudSheetHeader.js.map +6 -0
- package/dist/components/data/crud-sheet/CrudSheetTools.d.ts +7 -0
- package/dist/components/data/crud-sheet/CrudSheetTools.d.ts.map +1 -0
- package/dist/components/data/crud-sheet/CrudSheetTools.js +14 -0
- package/dist/components/data/crud-sheet/CrudSheetTools.js.map +6 -0
- package/dist/components/data/crud-sheet/types.d.ts +109 -0
- package/dist/components/data/crud-sheet/types.d.ts.map +1 -0
- package/dist/components/data/crud-sheet/types.js +1 -0
- package/dist/components/data/crud-sheet/types.js.map +6 -0
- package/dist/components/data/kanban/Kanban.d.ts.map +1 -1
- package/dist/components/data/kanban/Kanban.js +137 -138
- package/dist/components/data/kanban/Kanban.js.map +2 -2
- package/dist/components/data/kanban/KanbanContext.d.ts +5 -1
- package/dist/components/data/kanban/KanbanContext.d.ts.map +1 -1
- package/dist/components/data/kanban/KanbanContext.js.map +1 -1
- package/dist/components/data/list/ListItem.d.ts.map +1 -1
- package/dist/components/data/list/ListItem.js +109 -99
- package/dist/components/data/list/ListItem.js.map +2 -2
- package/dist/components/data/sheet/DataSheet.css +28 -10
- package/dist/components/data/sheet/DataSheet.js +1 -1
- package/dist/components/data/sheet/DataSheet.js.map +2 -2
- package/dist/components/data/sheet/DataSheet.styles.d.ts.map +1 -1
- package/dist/components/data/sheet/DataSheet.styles.js +1 -1
- package/dist/components/data/sheet/DataSheet.styles.js.map +1 -1
- package/dist/components/disclosure/Dialog.d.ts +16 -10
- package/dist/components/disclosure/Dialog.d.ts.map +1 -1
- package/dist/components/disclosure/Dialog.js +126 -91
- package/dist/components/disclosure/Dialog.js.map +2 -2
- package/dist/components/disclosure/DialogContext.d.ts +2 -4
- package/dist/components/disclosure/DialogContext.d.ts.map +1 -1
- package/dist/components/disclosure/DialogContext.js.map +1 -1
- package/dist/components/disclosure/DialogProvider.d.ts.map +1 -1
- package/dist/components/disclosure/DialogProvider.js +14 -9
- package/dist/components/disclosure/DialogProvider.js.map +2 -2
- package/dist/components/disclosure/Dropdown.d.ts +46 -22
- package/dist/components/disclosure/Dropdown.d.ts.map +1 -1
- package/dist/components/disclosure/Dropdown.js +100 -65
- package/dist/components/disclosure/Dropdown.js.map +2 -2
- package/dist/components/feedback/notification/NotificationBanner.d.ts.map +1 -1
- package/dist/components/feedback/notification/NotificationBanner.js +3 -3
- package/dist/components/feedback/notification/NotificationBanner.js.map +1 -1
- package/dist/components/feedback/notification/NotificationBell.d.ts.map +1 -1
- package/dist/components/feedback/notification/NotificationBell.js +84 -84
- package/dist/components/feedback/notification/NotificationBell.js.map +2 -2
- package/dist/components/form-control/Invalid.js +1 -1
- package/dist/components/form-control/combobox/Combobox.d.ts +6 -3
- package/dist/components/form-control/combobox/Combobox.d.ts.map +1 -1
- package/dist/components/form-control/combobox/Combobox.js +150 -168
- package/dist/components/form-control/combobox/Combobox.js.map +2 -2
- package/dist/components/form-control/combobox/ComboboxContext.d.ts +3 -0
- package/dist/components/form-control/combobox/ComboboxContext.d.ts.map +1 -1
- package/dist/components/form-control/combobox/ComboboxContext.js.map +1 -1
- package/dist/components/form-control/date-range-picker/DateRangePicker.d.ts +0 -2
- package/dist/components/form-control/date-range-picker/DateRangePicker.d.ts.map +1 -1
- package/dist/components/form-control/date-range-picker/DateRangePicker.js +9 -17
- package/dist/components/form-control/date-range-picker/DateRangePicker.js.map +2 -2
- package/dist/components/form-control/field/DatePicker.d.ts.map +1 -1
- package/dist/components/form-control/field/DatePicker.js +3 -2
- package/dist/components/form-control/field/DatePicker.js.map +2 -2
- package/dist/components/form-control/field/DateTimePicker.d.ts.map +1 -1
- package/dist/components/form-control/field/DateTimePicker.js +3 -2
- package/dist/components/form-control/field/DateTimePicker.js.map +2 -2
- package/dist/components/form-control/field/Field.styles.d.ts.map +1 -1
- package/dist/components/form-control/field/Field.styles.js +2 -1
- package/dist/components/form-control/field/Field.styles.js.map +1 -1
- package/dist/components/form-control/field/NumberInput.d.ts +15 -5
- package/dist/components/form-control/field/NumberInput.d.ts.map +1 -1
- package/dist/components/form-control/field/NumberInput.js +181 -141
- package/dist/components/form-control/field/NumberInput.js.map +2 -2
- package/dist/components/form-control/field/TextInput.d.ts +9 -5
- package/dist/components/form-control/field/TextInput.d.ts.map +1 -1
- package/dist/components/form-control/field/TextInput.js +199 -154
- package/dist/components/form-control/field/TextInput.js.map +2 -2
- package/dist/components/form-control/field/TimePicker.d.ts.map +1 -1
- package/dist/components/form-control/field/TimePicker.js +3 -2
- package/dist/components/form-control/field/TimePicker.js.map +2 -2
- package/dist/components/form-control/select/Select.d.ts +3 -3
- package/dist/components/form-control/select/Select.d.ts.map +1 -1
- package/dist/components/form-control/select/Select.js +116 -100
- package/dist/components/form-control/select/Select.js.map +2 -2
- package/dist/components/form-control/select/SelectContext.d.ts +9 -1
- package/dist/components/form-control/select/SelectContext.d.ts.map +1 -1
- package/dist/components/form-control/select/SelectContext.js.map +1 -1
- package/dist/components/form-control/select/SelectItem.d.ts.map +1 -1
- package/dist/components/form-control/select/SelectItem.js +77 -67
- package/dist/components/form-control/select/SelectItem.js.map +2 -2
- package/dist/components/form-control/state-preset/StatePreset.d.ts.map +1 -1
- package/dist/components/form-control/state-preset/StatePreset.js +1 -1
- package/dist/components/form-control/state-preset/StatePreset.js.map +1 -1
- package/dist/components/layout/topbar/Topbar.d.ts +2 -0
- package/dist/components/layout/topbar/Topbar.d.ts.map +1 -1
- package/dist/components/layout/topbar/Topbar.js +2 -0
- package/dist/components/layout/topbar/Topbar.js.map +2 -2
- package/dist/components/layout/topbar/TopbarActions.d.ts +3 -0
- package/dist/components/layout/topbar/TopbarActions.d.ts.map +1 -0
- package/dist/components/layout/topbar/TopbarActions.js +17 -0
- package/dist/components/layout/topbar/TopbarActions.js.map +6 -0
- package/dist/components/layout/topbar/TopbarContainer.d.ts +1 -1
- package/dist/components/layout/topbar/TopbarContainer.d.ts.map +1 -1
- package/dist/components/layout/topbar/TopbarContainer.js +21 -12
- package/dist/components/layout/topbar/TopbarContainer.js.map +2 -2
- package/dist/components/layout/topbar/TopbarContext.d.ts +9 -0
- package/dist/components/layout/topbar/TopbarContext.d.ts.map +1 -0
- package/dist/components/layout/topbar/TopbarContext.js +29 -0
- package/dist/components/layout/topbar/TopbarContext.js.map +6 -0
- package/dist/components/layout/topbar/TopbarMenu.d.ts.map +1 -1
- package/dist/components/layout/topbar/TopbarMenu.js +63 -57
- package/dist/components/layout/topbar/TopbarMenu.js.map +2 -2
- package/dist/components/layout/topbar/TopbarUser.d.ts.map +1 -1
- package/dist/components/layout/topbar/TopbarUser.js +53 -54
- package/dist/components/layout/topbar/TopbarUser.js.map +2 -2
- package/dist/hooks/createControllableStore.d.ts +29 -0
- package/dist/hooks/createControllableStore.d.ts.map +1 -0
- package/dist/hooks/createControllableStore.js +19 -0
- package/dist/hooks/createControllableStore.js.map +6 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/styles/patterns.styles.d.ts.map +1 -1
- package/dist/styles/patterns.styles.js +7 -1
- package/dist/styles/patterns.styles.js.map +1 -1
- package/docs/data-components.md +428 -0
- package/docs/disclosure.md +65 -35
- package/docs/form-controls.md +18 -3
- package/docs/helpers.md +0 -39
- package/docs/hooks.md +39 -0
- package/docs/layout.md +70 -1
- package/package.json +4 -3
- package/src/components/data/crud-detail/CrudDetail.tsx +346 -0
- package/src/components/data/crud-detail/CrudDetailAfter.tsx +19 -0
- package/src/components/data/crud-detail/CrudDetailBefore.tsx +19 -0
- package/src/components/data/crud-detail/CrudDetailTools.tsx +19 -0
- package/src/components/data/crud-detail/types.ts +58 -0
- package/src/components/data/crud-sheet/CrudSheet.tsx +628 -0
- package/src/components/data/crud-sheet/CrudSheetColumn.tsx +34 -0
- package/src/components/data/crud-sheet/CrudSheetFilter.tsx +21 -0
- package/src/components/data/crud-sheet/CrudSheetHeader.tsx +19 -0
- package/src/components/data/crud-sheet/CrudSheetTools.tsx +21 -0
- package/src/components/data/crud-sheet/types.ts +133 -0
- package/src/components/data/kanban/Kanban.tsx +72 -65
- package/src/components/data/kanban/KanbanContext.ts +7 -1
- package/src/components/data/list/ListItem.tsx +31 -18
- package/src/components/data/sheet/DataSheet.css +28 -10
- package/src/components/data/sheet/DataSheet.styles.ts +1 -1
- package/src/components/data/sheet/DataSheet.tsx +1 -1
- package/src/components/disclosure/Dialog.tsx +143 -105
- package/src/components/disclosure/DialogContext.ts +2 -4
- package/src/components/disclosure/DialogProvider.tsx +4 -2
- package/src/components/disclosure/Dropdown.tsx +174 -86
- package/src/components/feedback/notification/NotificationBanner.tsx +3 -9
- package/src/components/feedback/notification/NotificationBell.tsx +51 -57
- package/src/components/form-control/Invalid.tsx +1 -1
- package/src/components/form-control/combobox/Combobox.tsx +109 -133
- package/src/components/form-control/combobox/ComboboxContext.ts +4 -1
- package/src/components/form-control/date-range-picker/DateRangePicker.tsx +6 -16
- package/src/components/form-control/field/DatePicker.tsx +4 -1
- package/src/components/form-control/field/DateTimePicker.tsx +3 -0
- package/src/components/form-control/field/Field.styles.ts +1 -0
- package/src/components/form-control/field/NumberInput.tsx +131 -86
- package/src/components/form-control/field/TextInput.tsx +139 -88
- package/src/components/form-control/field/TimePicker.tsx +3 -0
- package/src/components/form-control/select/Select.tsx +85 -67
- package/src/components/form-control/select/SelectContext.ts +12 -1
- package/src/components/form-control/select/SelectItem.tsx +39 -18
- package/src/components/form-control/state-preset/StatePreset.tsx +1 -0
- package/src/components/layout/topbar/Topbar.tsx +3 -0
- package/src/components/layout/topbar/TopbarActions.tsx +8 -0
- package/src/components/layout/topbar/TopbarContainer.tsx +9 -5
- package/src/components/layout/topbar/TopbarContext.ts +36 -0
- package/src/components/layout/topbar/TopbarMenu.tsx +52 -55
- package/src/components/layout/topbar/TopbarUser.tsx +28 -31
- package/src/hooks/createControllableStore.ts +47 -0
- package/src/index.ts +6 -1
- package/src/styles/patterns.styles.ts +7 -1
- package/tailwind.css +4 -0
- package/dist/helpers/splitSlots.d.ts +0 -25
- package/dist/helpers/splitSlots.d.ts.map +0 -1
- package/dist/helpers/splitSlots.js +0 -25
- package/dist/helpers/splitSlots.js.map +0 -6
- package/dist/hooks/createItemTemplate.d.ts +0 -17
- package/dist/hooks/createItemTemplate.d.ts.map +0 -1
- package/dist/hooks/createItemTemplate.js +0 -40
- package/dist/hooks/createItemTemplate.js.map +0 -6
- package/src/helpers/splitSlots.ts +0 -51
- package/src/hooks/createItemTemplate.tsx +0 -42
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
For,
|
|
6
6
|
type JSX,
|
|
7
7
|
type ParentComponent,
|
|
8
|
+
onCleanup,
|
|
8
9
|
Show,
|
|
9
10
|
splitProps,
|
|
10
11
|
} from "solid-js";
|
|
@@ -15,17 +16,18 @@ import { Icon } from "../../display/Icon";
|
|
|
15
16
|
import { Dropdown } from "../../disclosure/Dropdown";
|
|
16
17
|
import { List } from "../../data/list/List";
|
|
17
18
|
import { SelectContext, type SelectContextValue } from "./SelectContext";
|
|
19
|
+
import { useSelectContext } from "./SelectContext";
|
|
18
20
|
import { SelectItem } from "./SelectItem";
|
|
19
21
|
import { ripple } from "../../../directives/ripple";
|
|
20
|
-
import { splitSlots } from "../../../helpers/splitSlots";
|
|
21
22
|
import { borderDefault, type ComponentSize, textMuted } from "../../../styles/tokens.styles";
|
|
22
23
|
import { createControllableSignal } from "../../../hooks/createControllableSignal";
|
|
23
|
-
import { createItemTemplate } from "../../../hooks/createItemTemplate";
|
|
24
24
|
import { chevronWrapperClass, getTriggerClass } from "../DropdownTrigger.styles";
|
|
25
25
|
import { Invalid } from "../Invalid";
|
|
26
26
|
|
|
27
27
|
void ripple;
|
|
28
28
|
|
|
29
|
+
type SlotAccessor = (() => JSX.Element) | undefined;
|
|
30
|
+
|
|
29
31
|
// Select 전용 스타일
|
|
30
32
|
const multiTagClass = clsx("rounded", "bg-base-200 px-1", "dark:bg-base-600");
|
|
31
33
|
const selectedValueClass = clsx("flex-1", "whitespace-nowrap");
|
|
@@ -37,8 +39,9 @@ interface SelectActionProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement>
|
|
|
37
39
|
|
|
38
40
|
const SelectAction: ParentComponent<SelectActionProps> = (props) => {
|
|
39
41
|
const [local, rest] = splitProps(props, ["children", "class"]);
|
|
42
|
+
const ctx = useSelectContext();
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
ctx.setAction(() => (
|
|
42
45
|
<button
|
|
43
46
|
{...rest}
|
|
44
47
|
type="button"
|
|
@@ -63,17 +66,31 @@ const SelectAction: ParentComponent<SelectActionProps> = (props) => {
|
|
|
63
66
|
>
|
|
64
67
|
{local.children}
|
|
65
68
|
</button>
|
|
66
|
-
);
|
|
69
|
+
));
|
|
70
|
+
onCleanup(() => ctx.setAction(undefined));
|
|
71
|
+
return null;
|
|
67
72
|
};
|
|
68
73
|
|
|
69
74
|
/**
|
|
70
75
|
* 드롭다운 상단 커스텀 영역 서브 컴포넌트
|
|
71
76
|
*/
|
|
72
|
-
const SelectHeader: ParentComponent = (props) =>
|
|
77
|
+
const SelectHeader: ParentComponent = (props) => {
|
|
78
|
+
const ctx = useSelectContext();
|
|
79
|
+
// eslint-disable-next-line solid/reactivity -- 슬롯 accessor로 저장, JSX tracked scope에서 호출됨
|
|
80
|
+
ctx.setHeader(() => props.children);
|
|
81
|
+
onCleanup(() => ctx.setHeader(undefined));
|
|
82
|
+
return null;
|
|
83
|
+
};
|
|
73
84
|
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
85
|
+
const SelectItemTemplate = <TArgs extends unknown[]>(props: {
|
|
86
|
+
children: (...args: TArgs) => JSX.Element;
|
|
87
|
+
}) => {
|
|
88
|
+
const ctx = useSelectContext();
|
|
89
|
+
// eslint-disable-next-line solid/reactivity -- 렌더 함수를 signal에 저장, JSX tracked scope에서 호출됨
|
|
90
|
+
ctx.setItemTemplate(props.children as (...args: unknown[]) => JSX.Element);
|
|
91
|
+
onCleanup(() => ctx.setItemTemplate(undefined));
|
|
92
|
+
return null;
|
|
93
|
+
};
|
|
77
94
|
|
|
78
95
|
// Props 정의
|
|
79
96
|
|
|
@@ -214,8 +231,6 @@ export const Select: SelectComponent = <T,>(props: SelectProps<T>) => {
|
|
|
214
231
|
"touchMode",
|
|
215
232
|
]);
|
|
216
233
|
|
|
217
|
-
let triggerRef!: HTMLDivElement;
|
|
218
|
-
|
|
219
234
|
const [open, setOpen] = createSignal(false);
|
|
220
235
|
|
|
221
236
|
// 선택된 값 관리 (controlled/uncontrolled 패턴)
|
|
@@ -256,18 +271,26 @@ export const Select: SelectComponent = <T,>(props: SelectProps<T>) => {
|
|
|
256
271
|
setOpen(false);
|
|
257
272
|
};
|
|
258
273
|
|
|
274
|
+
// 슬롯 signals
|
|
275
|
+
const [header, _setHeader] = createSignal<SlotAccessor>();
|
|
276
|
+
const setHeader = (content: SlotAccessor) => _setHeader(() => content);
|
|
277
|
+
const [action, _setAction] = createSignal<SlotAccessor>();
|
|
278
|
+
const setAction = (content: SlotAccessor) => _setAction(() => content);
|
|
279
|
+
const [itemTemplate, _setItemTemplate] = createSignal<
|
|
280
|
+
((...args: unknown[]) => JSX.Element) | undefined
|
|
281
|
+
>();
|
|
282
|
+
const setItemTemplate = (fn: ((...args: unknown[]) => JSX.Element) | undefined) =>
|
|
283
|
+
_setItemTemplate(() => fn);
|
|
284
|
+
|
|
259
285
|
// Context 값
|
|
260
286
|
const contextValue: SelectContextValue<T> = {
|
|
261
287
|
multiple: () => local.multiple ?? false,
|
|
262
288
|
isSelected,
|
|
263
289
|
toggleValue,
|
|
264
290
|
closeDropdown,
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
const handleTriggerClick = () => {
|
|
269
|
-
if (local.disabled) return;
|
|
270
|
-
setOpen((v) => !v);
|
|
291
|
+
setHeader,
|
|
292
|
+
setAction,
|
|
293
|
+
setItemTemplate,
|
|
271
294
|
};
|
|
272
295
|
|
|
273
296
|
// 트리거 키보드 처리 (Enter/Space만 처리, ArrowUp/Down은 Dropdown이 처리)
|
|
@@ -297,32 +320,26 @@ export const Select: SelectComponent = <T,>(props: SelectProps<T>) => {
|
|
|
297
320
|
class: local.class,
|
|
298
321
|
});
|
|
299
322
|
|
|
300
|
-
// 내부 컴포넌트: Provider 안에서 children을 resolve
|
|
323
|
+
// 내부 컴포넌트: Provider 안에서 children을 resolve하여 슬롯 등록을 트리거
|
|
301
324
|
const SelectInner: ParentComponent = (innerProps) => {
|
|
325
|
+
// children() resolve로 서브 컴포넌트 등록 트리거 (Header, Action, ItemTemplate은 null 반환)
|
|
302
326
|
const resolved = children(() => innerProps.children);
|
|
303
|
-
const [slots, items] = splitSlots(resolved, [
|
|
304
|
-
"selectHeader",
|
|
305
|
-
"selectAction",
|
|
306
|
-
"selectItemTemplate",
|
|
307
|
-
] as const);
|
|
308
327
|
|
|
309
328
|
// itemTemplate 함수 추출
|
|
310
329
|
const getItemTemplate = ():
|
|
311
330
|
| ((item: T, index: number, depth: number) => JSX.Element)
|
|
312
331
|
| undefined => {
|
|
313
|
-
return
|
|
314
|
-
| ((item: T, index: number, depth: number) => JSX.Element)
|
|
315
|
-
| undefined;
|
|
332
|
+
return itemTemplate() as ((item: T, index: number, depth: number) => JSX.Element) | undefined;
|
|
316
333
|
};
|
|
317
334
|
|
|
318
335
|
// items 재귀 렌더링
|
|
319
336
|
const renderItems = (itemList: T[], depth: number): JSX.Element => {
|
|
320
|
-
const
|
|
337
|
+
const tpl = getItemTemplate();
|
|
321
338
|
return (
|
|
322
339
|
<For each={itemList}>
|
|
323
340
|
{(item, index) => (
|
|
324
341
|
<SelectItem value={item}>
|
|
325
|
-
{
|
|
342
|
+
{tpl ? tpl(item, index(), depth) : String(item)}
|
|
326
343
|
<Show when={local.getChildren?.(item, index(), depth)} keyed>
|
|
327
344
|
{(itemChildren) => (
|
|
328
345
|
<Show when={itemChildren.length > 0}>
|
|
@@ -343,9 +360,9 @@ export const Select: SelectComponent = <T,>(props: SelectProps<T>) => {
|
|
|
343
360
|
if (local.renderValue) {
|
|
344
361
|
return local.renderValue(value);
|
|
345
362
|
}
|
|
346
|
-
const
|
|
347
|
-
if (
|
|
348
|
-
return
|
|
363
|
+
const tpl = getItemTemplate();
|
|
364
|
+
if (tpl) {
|
|
365
|
+
return tpl(value, 0, 0);
|
|
349
366
|
}
|
|
350
367
|
return <>{String(value)}</>;
|
|
351
368
|
};
|
|
@@ -372,33 +389,43 @@ export const Select: SelectComponent = <T,>(props: SelectProps<T>) => {
|
|
|
372
389
|
|
|
373
390
|
return (
|
|
374
391
|
<div {...rest} data-select class={clsx("group", local.inset ? "flex" : "inline-flex")}>
|
|
375
|
-
<
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
392
|
+
<Dropdown disabled={local.disabled} open={open()} onOpenChange={setOpen} keyboardNav>
|
|
393
|
+
<Dropdown.Trigger>
|
|
394
|
+
<div
|
|
395
|
+
use:ripple={!local.disabled}
|
|
396
|
+
role="combobox"
|
|
397
|
+
aria-haspopup="listbox"
|
|
398
|
+
aria-expanded={open()}
|
|
399
|
+
aria-disabled={local.disabled || undefined}
|
|
400
|
+
aria-required={local.required || undefined}
|
|
401
|
+
tabIndex={local.disabled ? -1 : 0}
|
|
402
|
+
class={twMerge(
|
|
403
|
+
getTriggerClassName(),
|
|
404
|
+
action() !== undefined &&
|
|
405
|
+
clsx(
|
|
406
|
+
"rounded-r-none border-r-0",
|
|
407
|
+
"group-focus-within:border-primary-400 dark:group-focus-within:border-primary-400",
|
|
408
|
+
),
|
|
409
|
+
)}
|
|
410
|
+
style={local.style}
|
|
411
|
+
onKeyDown={handleTriggerKeyDown}
|
|
412
|
+
>
|
|
413
|
+
<div class={selectedValueClass}>{renderSelectedValue()}</div>
|
|
414
|
+
<div class={chevronWrapperClass}>
|
|
415
|
+
<Icon icon={IconChevronDown} size="1em" />
|
|
416
|
+
</div>
|
|
417
|
+
</div>
|
|
418
|
+
</Dropdown.Trigger>
|
|
419
|
+
<Dropdown.Content>
|
|
420
|
+
<Show when={header()}>{header()!()}</Show>
|
|
421
|
+
<List inset role="listbox">
|
|
422
|
+
<Show when={local.items} fallback={resolved()}>
|
|
423
|
+
{renderItems(local.items!, 0)}
|
|
424
|
+
</Show>
|
|
425
|
+
</List>
|
|
426
|
+
</Dropdown.Content>
|
|
427
|
+
</Dropdown>
|
|
428
|
+
<Show when={action()}>
|
|
402
429
|
<div
|
|
403
430
|
class={clsx(
|
|
404
431
|
"contents",
|
|
@@ -406,18 +433,9 @@ export const Select: SelectComponent = <T,>(props: SelectProps<T>) => {
|
|
|
406
433
|
"[&>[data-select-action]+[data-select-action]]:-ml-px",
|
|
407
434
|
)}
|
|
408
435
|
>
|
|
409
|
-
{
|
|
436
|
+
{action()!()}
|
|
410
437
|
</div>
|
|
411
438
|
</Show>
|
|
412
|
-
|
|
413
|
-
<Dropdown triggerRef={() => triggerRef} open={open()} onOpenChange={setOpen} keyboardNav>
|
|
414
|
-
<Show when={slots().selectHeader.length > 0}>{slots().selectHeader.single()}</Show>
|
|
415
|
-
<List inset role="listbox">
|
|
416
|
-
<Show when={local.items} fallback={items()}>
|
|
417
|
-
{renderItems(local.items!, 0)}
|
|
418
|
-
</Show>
|
|
419
|
-
</List>
|
|
420
|
-
</Dropdown>
|
|
421
439
|
</div>
|
|
422
440
|
);
|
|
423
441
|
};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { createContext, useContext, type Accessor } from "solid-js";
|
|
1
|
+
import { createContext, useContext, type Accessor, type JSX } from "solid-js";
|
|
2
|
+
|
|
3
|
+
type SlotAccessor = (() => JSX.Element) | undefined;
|
|
2
4
|
|
|
3
5
|
export interface SelectContextValue<TValue = unknown> {
|
|
4
6
|
/** 다중 선택 모드 여부 */
|
|
@@ -12,6 +14,15 @@ export interface SelectContextValue<TValue = unknown> {
|
|
|
12
14
|
|
|
13
15
|
/** 드롭다운 닫기 */
|
|
14
16
|
closeDropdown: () => void;
|
|
17
|
+
|
|
18
|
+
/** 헤더 슬롯 등록 */
|
|
19
|
+
setHeader: (content: SlotAccessor) => void;
|
|
20
|
+
|
|
21
|
+
/** 액션 슬롯 등록 */
|
|
22
|
+
setAction: (content: SlotAccessor) => void;
|
|
23
|
+
|
|
24
|
+
/** 아이템 템플릿 등록 */
|
|
25
|
+
setItemTemplate: (fn: ((...args: unknown[]) => JSX.Element) | undefined) => void;
|
|
15
26
|
}
|
|
16
27
|
|
|
17
28
|
export const SelectContext = createContext<SelectContextValue>();
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
createSignal,
|
|
4
|
+
type JSX,
|
|
5
|
+
onCleanup,
|
|
6
|
+
type ParentComponent,
|
|
7
|
+
Show,
|
|
8
|
+
splitProps,
|
|
9
|
+
useContext,
|
|
10
|
+
} from "solid-js";
|
|
2
11
|
import { twMerge } from "tailwind-merge";
|
|
3
12
|
import { IconCheck } from "@tabler/icons-solidjs";
|
|
4
13
|
import { Icon } from "../../display/Icon";
|
|
@@ -6,7 +15,6 @@ import { useSelectContext } from "./SelectContext";
|
|
|
6
15
|
import { ripple } from "../../../directives/ripple";
|
|
7
16
|
import { List } from "../../data/list/List";
|
|
8
17
|
import { Collapse } from "../../disclosure/Collapse";
|
|
9
|
-
import { splitSlots } from "../../../helpers/splitSlots";
|
|
10
18
|
import {
|
|
11
19
|
listItemBaseClass,
|
|
12
20
|
listItemSelectedClass,
|
|
@@ -18,17 +26,24 @@ import {
|
|
|
18
26
|
|
|
19
27
|
void ripple;
|
|
20
28
|
|
|
29
|
+
type SlotAccessor = (() => JSX.Element) | undefined;
|
|
30
|
+
|
|
31
|
+
interface SelectItemSlotsContextValue {
|
|
32
|
+
setChildren: (content: SlotAccessor) => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const SelectItemSlotsContext = createContext<SelectItemSlotsContextValue>();
|
|
36
|
+
|
|
21
37
|
/**
|
|
22
38
|
* 중첩 아이템을 담는 서브 컴포넌트
|
|
23
39
|
*/
|
|
24
|
-
const SelectItemChildren: ParentComponent = (props) =>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
);
|
|
40
|
+
const SelectItemChildren: ParentComponent = (props) => {
|
|
41
|
+
const ctx = useContext(SelectItemSlotsContext)!;
|
|
42
|
+
// eslint-disable-next-line solid/reactivity -- slot accessor: children is lazily read at render time
|
|
43
|
+
ctx.setChildren(() => props.children);
|
|
44
|
+
onCleanup(() => ctx.setChildren(undefined));
|
|
45
|
+
return null;
|
|
46
|
+
};
|
|
32
47
|
|
|
33
48
|
export interface SelectItemProps<TValue = unknown> extends Omit<
|
|
34
49
|
JSX.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
@@ -68,10 +83,9 @@ export const SelectItem: SelectItemComponent = <T,>(
|
|
|
68
83
|
|
|
69
84
|
const context = useSelectContext<T>();
|
|
70
85
|
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
const hasChildren = () => slots().selectItemChildren.length > 0;
|
|
86
|
+
const [childrenSlot, _setChildrenSlot] = createSignal<SlotAccessor>();
|
|
87
|
+
const setChildrenSlot = (content: SlotAccessor) => _setChildrenSlot(() => content);
|
|
88
|
+
const hasChildren = () => childrenSlot() !== undefined;
|
|
75
89
|
const isSelected = () => context.isSelected(local.value);
|
|
76
90
|
const useRipple = () => !local.disabled;
|
|
77
91
|
|
|
@@ -97,7 +111,7 @@ export const SelectItem: SelectItemComponent = <T,>(
|
|
|
97
111
|
const getCheckIconClass = () => getListItemSelectedIconClass(isSelected());
|
|
98
112
|
|
|
99
113
|
return (
|
|
100
|
-
|
|
114
|
+
<SelectItemSlotsContext.Provider value={{ setChildren: setChildrenSlot }}>
|
|
101
115
|
<button
|
|
102
116
|
{...rest}
|
|
103
117
|
type="button"
|
|
@@ -114,12 +128,19 @@ export const SelectItem: SelectItemComponent = <T,>(
|
|
|
114
128
|
<Show when={context.multiple() && !hasChildren()}>
|
|
115
129
|
<Icon icon={IconCheck} class={getCheckIconClass()} />
|
|
116
130
|
</Show>
|
|
117
|
-
<span class={listItemContentClass}>{
|
|
131
|
+
<span class={listItemContentClass}>{local.children}</span>
|
|
118
132
|
</button>
|
|
119
133
|
<Show when={hasChildren()}>
|
|
120
|
-
<Collapse open={true}>
|
|
134
|
+
<Collapse open={true}>
|
|
135
|
+
<div class="flex">
|
|
136
|
+
<div class={listItemIndentGuideClass} />
|
|
137
|
+
<List inset class="flex-1">
|
|
138
|
+
{childrenSlot()!()}
|
|
139
|
+
</List>
|
|
140
|
+
</div>
|
|
141
|
+
</Collapse>
|
|
121
142
|
</Show>
|
|
122
|
-
|
|
143
|
+
</SelectItemSlotsContext.Provider>
|
|
123
144
|
);
|
|
124
145
|
};
|
|
125
146
|
|
|
@@ -289,6 +289,7 @@ function StatePresetInner<TValue>(props: StatePresetProps<TValue>): JSX.Element
|
|
|
289
289
|
type="text"
|
|
290
290
|
class={resolvedInputClass()}
|
|
291
291
|
placeholder="이름..."
|
|
292
|
+
autocomplete="one-time-code"
|
|
292
293
|
value={inputValue()}
|
|
293
294
|
onInput={(e) => setInputValue(e.currentTarget.value)}
|
|
294
295
|
onKeyDown={handleInputKeyDown}
|
|
@@ -5,6 +5,7 @@ import { Icon } from "../../display/Icon";
|
|
|
5
5
|
import { twMerge } from "tailwind-merge";
|
|
6
6
|
import { Button } from "../../form-control/Button";
|
|
7
7
|
import { useSidebarContextOptional } from "../sidebar/SidebarContext";
|
|
8
|
+
import { TopbarActions } from "./TopbarActions";
|
|
8
9
|
import { TopbarContainer } from "./TopbarContainer";
|
|
9
10
|
import { TopbarMenu } from "./TopbarMenu";
|
|
10
11
|
import { TopbarUser } from "./TopbarUser";
|
|
@@ -58,6 +59,7 @@ export interface TopbarProps extends JSX.HTMLAttributes<HTMLElement> {
|
|
|
58
59
|
* ```
|
|
59
60
|
*/
|
|
60
61
|
interface TopbarComponent extends ParentComponent<TopbarProps> {
|
|
62
|
+
Actions: typeof TopbarActions;
|
|
61
63
|
Container: typeof TopbarContainer;
|
|
62
64
|
Menu: typeof TopbarMenu;
|
|
63
65
|
User: typeof TopbarUser;
|
|
@@ -88,6 +90,7 @@ const TopbarBase: ParentComponent<TopbarProps> = (props) => {
|
|
|
88
90
|
};
|
|
89
91
|
|
|
90
92
|
export const Topbar = TopbarBase as TopbarComponent;
|
|
93
|
+
Topbar.Actions = TopbarActions;
|
|
91
94
|
Topbar.Container = TopbarContainer;
|
|
92
95
|
Topbar.Menu = TopbarMenu;
|
|
93
96
|
Topbar.User = TopbarUser;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Component, useContext } from "solid-js";
|
|
2
|
+
import { TopbarContext } from "./TopbarContext";
|
|
3
|
+
|
|
4
|
+
export const TopbarActions: Component = () => {
|
|
5
|
+
const context = useContext(TopbarContext);
|
|
6
|
+
|
|
7
|
+
return <span data-topbar-actions>{context?.actions()}</span>;
|
|
8
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { type JSX, type ParentComponent, splitProps } from "solid-js";
|
|
1
|
+
import { type JSX, type ParentComponent, splitProps, createSignal } from "solid-js";
|
|
2
2
|
import clsx from "clsx";
|
|
3
3
|
import { twMerge } from "tailwind-merge";
|
|
4
|
+
import { TopbarContext } from "./TopbarContext";
|
|
4
5
|
|
|
5
6
|
const containerClass = clsx("flex h-full flex-col");
|
|
6
7
|
|
|
@@ -13,7 +14,7 @@ export interface TopbarContainerProps extends JSX.HTMLAttributes<HTMLDivElement>
|
|
|
13
14
|
*
|
|
14
15
|
* @remarks
|
|
15
16
|
* - `flex flex-col h-full` 구조로 Topbar와 콘텐츠를 수직 배치
|
|
16
|
-
* -
|
|
17
|
+
* - TopbarContext.Provider로 actions 상태 공유
|
|
17
18
|
* - 부모 요소에 높이가 지정되어야 함
|
|
18
19
|
*
|
|
19
20
|
* @example
|
|
@@ -29,12 +30,15 @@ export interface TopbarContainerProps extends JSX.HTMLAttributes<HTMLDivElement>
|
|
|
29
30
|
*/
|
|
30
31
|
export const TopbarContainer: ParentComponent<TopbarContainerProps> = (props) => {
|
|
31
32
|
const [local, rest] = splitProps(props, ["children", "class"]);
|
|
33
|
+
const [actions, setActions] = createSignal<JSX.Element | undefined>(undefined);
|
|
32
34
|
|
|
33
35
|
const getClassName = () => twMerge(containerClass, local.class);
|
|
34
36
|
|
|
35
37
|
return (
|
|
36
|
-
<
|
|
37
|
-
{
|
|
38
|
-
|
|
38
|
+
<TopbarContext.Provider value={{ actions, setActions }}>
|
|
39
|
+
<div {...rest} data-topbar-container class={getClassName()}>
|
|
40
|
+
{local.children}
|
|
41
|
+
</div>
|
|
42
|
+
</TopbarContext.Provider>
|
|
39
43
|
);
|
|
40
44
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
onCleanup,
|
|
5
|
+
type Accessor,
|
|
6
|
+
type JSX,
|
|
7
|
+
type Setter,
|
|
8
|
+
} from "solid-js";
|
|
9
|
+
|
|
10
|
+
export interface TopbarContextValue {
|
|
11
|
+
actions: Accessor<JSX.Element | undefined>;
|
|
12
|
+
setActions: Setter<JSX.Element | undefined>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const TopbarContext = createContext<TopbarContextValue>();
|
|
16
|
+
|
|
17
|
+
export function useTopbarActionsAccessor(): Accessor<JSX.Element | undefined> {
|
|
18
|
+
const context = useContext(TopbarContext);
|
|
19
|
+
if (!context) {
|
|
20
|
+
throw new Error("useTopbarActionsAccessor는 Topbar.Container 내부에서만 사용할 수 있습니다");
|
|
21
|
+
}
|
|
22
|
+
return context.actions;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function createTopbarActions(accessor: () => JSX.Element): void {
|
|
26
|
+
const context = useContext(TopbarContext);
|
|
27
|
+
if (!context) {
|
|
28
|
+
throw new Error("createTopbarActions는 Topbar.Container 내부에서만 사용할 수 있습니다");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
context.setActions(() => accessor());
|
|
32
|
+
|
|
33
|
+
onCleanup(() => {
|
|
34
|
+
context.setActions(undefined);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -63,7 +63,6 @@ export interface TopbarMenuProps extends Omit<JSX.HTMLAttributes<HTMLElement>, "
|
|
|
63
63
|
export const TopbarMenu: Component<TopbarMenuProps> = (props) => {
|
|
64
64
|
const [local, rest] = splitProps(props, ["menus", "class"]);
|
|
65
65
|
const [mobileMenuOpen, setMobileMenuOpen] = createSignal(false);
|
|
66
|
-
let mobileButtonRef: HTMLButtonElement | undefined;
|
|
67
66
|
|
|
68
67
|
return (
|
|
69
68
|
<>
|
|
@@ -74,28 +73,26 @@ export const TopbarMenu: Component<TopbarMenuProps> = (props) => {
|
|
|
74
73
|
|
|
75
74
|
{/* 모바일 햄버거 (640px 미만에서만 표시) */}
|
|
76
75
|
<div class={mobileWrapperClass}>
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
</For>
|
|
98
|
-
</List>
|
|
76
|
+
<Dropdown open={mobileMenuOpen()} onOpenChange={setMobileMenuOpen}>
|
|
77
|
+
<Dropdown.Trigger>
|
|
78
|
+
<Button
|
|
79
|
+
variant="ghost"
|
|
80
|
+
aria-label="메뉴"
|
|
81
|
+
aria-haspopup="menu"
|
|
82
|
+
aria-expanded={mobileMenuOpen()}
|
|
83
|
+
>
|
|
84
|
+
<Icon icon={IconDotsVertical} size="1.25em" />
|
|
85
|
+
</Button>
|
|
86
|
+
</Dropdown.Trigger>
|
|
87
|
+
<Dropdown.Content>
|
|
88
|
+
<List inset>
|
|
89
|
+
<For each={local.menus}>
|
|
90
|
+
{(menu) => (
|
|
91
|
+
<TopbarMenuDropdownItem menu={menu} onClose={() => setMobileMenuOpen(false)} />
|
|
92
|
+
)}
|
|
93
|
+
</For>
|
|
94
|
+
</List>
|
|
95
|
+
</Dropdown.Content>
|
|
99
96
|
</Dropdown>
|
|
100
97
|
</div>
|
|
101
98
|
</>
|
|
@@ -111,7 +108,6 @@ const TopbarMenuButton: Component<TopbarMenuButtonProps> = (props) => {
|
|
|
111
108
|
const navigate = useNavigate();
|
|
112
109
|
|
|
113
110
|
const [open, setOpen] = createSignal(false);
|
|
114
|
-
let buttonRef: HTMLButtonElement | undefined;
|
|
115
111
|
|
|
116
112
|
const hasChildren = () => props.menu.children !== undefined && props.menu.children.length > 0;
|
|
117
113
|
const isExternalLink = () => props.menu.href?.includes("://") ?? false;
|
|
@@ -133,10 +129,8 @@ const TopbarMenuButton: Component<TopbarMenuButtonProps> = (props) => {
|
|
|
133
129
|
return false;
|
|
134
130
|
});
|
|
135
131
|
|
|
136
|
-
const
|
|
137
|
-
if (
|
|
138
|
-
setOpen((v) => !v);
|
|
139
|
-
} else if (props.menu.href !== undefined) {
|
|
132
|
+
const handleNavigate = () => {
|
|
133
|
+
if (props.menu.href !== undefined) {
|
|
140
134
|
if (isExternalLink()) {
|
|
141
135
|
window.open(props.menu.href, "_blank", "noopener,noreferrer");
|
|
142
136
|
} else {
|
|
@@ -145,39 +139,42 @@ const TopbarMenuButton: Component<TopbarMenuButtonProps> = (props) => {
|
|
|
145
139
|
}
|
|
146
140
|
};
|
|
147
141
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
</Show>
|
|
162
|
-
<span>{props.menu.title}</span>
|
|
163
|
-
<Show when={hasChildren()}>
|
|
164
|
-
<Icon
|
|
165
|
-
icon={IconChevronDown}
|
|
166
|
-
size="1em"
|
|
167
|
-
class={clsx("transition-transform", open() && "rotate-180")}
|
|
168
|
-
/>
|
|
169
|
-
</Show>
|
|
170
|
-
</Button>
|
|
142
|
+
const buttonContent = () => (
|
|
143
|
+
<Button
|
|
144
|
+
variant={isSelected() ? "solid" : "ghost"}
|
|
145
|
+
theme={isSelected() ? "primary" : "base"}
|
|
146
|
+
class={menuButtonContentClass}
|
|
147
|
+
aria-haspopup={hasChildren() ? "menu" : undefined}
|
|
148
|
+
aria-expanded={hasChildren() ? open() : undefined}
|
|
149
|
+
onClick={hasChildren() ? undefined : handleNavigate}
|
|
150
|
+
>
|
|
151
|
+
<Show when={props.menu.icon}>
|
|
152
|
+
<Icon icon={props.menu.icon!} />
|
|
153
|
+
</Show>
|
|
154
|
+
<span>{props.menu.title}</span>
|
|
171
155
|
<Show when={hasChildren()}>
|
|
172
|
-
<
|
|
156
|
+
<Icon
|
|
157
|
+
icon={IconChevronDown}
|
|
158
|
+
size="1em"
|
|
159
|
+
class={clsx("transition-transform", open() && "rotate-180")}
|
|
160
|
+
/>
|
|
161
|
+
</Show>
|
|
162
|
+
</Button>
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<Show when={hasChildren()} fallback={buttonContent()}>
|
|
167
|
+
<Dropdown open={open()} onOpenChange={setOpen}>
|
|
168
|
+
<Dropdown.Trigger>{buttonContent()}</Dropdown.Trigger>
|
|
169
|
+
<Dropdown.Content>
|
|
173
170
|
<List inset>
|
|
174
171
|
<For each={props.menu.children}>
|
|
175
172
|
{(child) => <TopbarMenuDropdownItem menu={child} onClose={() => setOpen(false)} />}
|
|
176
173
|
</For>
|
|
177
174
|
</List>
|
|
178
|
-
</Dropdown>
|
|
179
|
-
</
|
|
180
|
-
|
|
175
|
+
</Dropdown.Content>
|
|
176
|
+
</Dropdown>
|
|
177
|
+
</Show>
|
|
181
178
|
);
|
|
182
179
|
};
|
|
183
180
|
|