musae 0.2.9 → 0.2.10

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.
Files changed (30) hide show
  1. package/dist/components/badge/badge.d.ts +1 -1
  2. package/dist/components/badge/badge.js +45 -7
  3. package/dist/components/badge/types.d.ts +18 -2
  4. package/dist/components/clock/clock.js +2 -1
  5. package/dist/components/dialog/dialog.js +1 -1
  6. package/dist/components/dialog/popup.js +1 -1
  7. package/dist/components/drawer/popup.js +1 -1
  8. package/dist/components/highlight/highlight.d.ts +4 -0
  9. package/dist/components/highlight/index.d.ts +2 -0
  10. package/dist/components/highlight/types.d.ts +11 -0
  11. package/dist/components/notification/notification.js +16 -4
  12. package/dist/components/otp-input/otp-input.js +6 -6
  13. package/dist/components/picker/picker.js +14 -14
  14. package/dist/components/picker/types.d.ts +1 -1
  15. package/dist/components/popover/popover.js +11 -4
  16. package/dist/components/popper/dropdown.d.ts +3 -2
  17. package/dist/components/popper/dropdown.js +24 -23
  18. package/dist/components/popper/popper.d.ts +1 -1
  19. package/dist/components/popper/popper.js +4 -4
  20. package/dist/components/tree/hooks.d.ts +8 -2
  21. package/dist/components/tree/hooks.js +11 -12
  22. package/dist/components/tree/node.js +8 -2
  23. package/dist/components/tree/tree.d.ts +1 -1
  24. package/dist/components/tree/tree.js +16 -4
  25. package/dist/components/tree/types.d.ts +36 -0
  26. package/dist/stylex.css +6 -0
  27. package/package.json +2 -2
  28. package/dist/components/picker/hooks.d.ts +0 -12
  29. package/dist/components/picker/hooks.js +0 -23
  30. /package/dist/node_modules/.pnpm/{@aiszlab_relax@1.2.59_react-dom@18.3.1_react@18.3.1__react@18.3.1 → @aiszlab_relax@1.2.64_react-dom@18.3.1_react@18.3.1__react@18.3.1}/node_modules/@aiszlab/relax/dist/dom/contains.js +0 -0
@@ -1,4 +1,4 @@
1
1
  import React from "react";
2
2
  import type { BadgeProps } from "./types";
3
- declare const Badge: ({ className, style, children, content }: BadgeProps) => React.JSX.Element;
3
+ declare const Badge: ({ className, style, children, content, invisible, placement }: BadgeProps) => React.JSX.Element;
4
4
  export default Badge;
@@ -4,6 +4,7 @@ import { ComponentToken, BadgeClassToken } from '../../utils/class-name.js';
4
4
  import _stylex from '../../node_modules/.pnpm/@stylexjs_stylex@0.7.5/node_modules/@stylexjs/stylex/lib/es/stylex.js';
5
5
  import clsx from 'clsx';
6
6
  import { typography } from '../theme/theme.js';
7
+ import { sizes } from '../theme/tokens.stylex.js';
7
8
  import { useTheme } from '../theme/hooks.js';
8
9
  import { ColorToken } from '../../utils/colors.js';
9
10
  import { isVoid } from '@aiszlab/relax';
@@ -19,11 +20,6 @@ const styles = {
19
20
  tail: {
20
21
  default: props => [{
21
22
  position: "musae-10l6tqk",
22
- top: "musae-13vifvy",
23
- right: "musae-3m8u43",
24
- insetInlineStart: null,
25
- insetInlineEnd: null,
26
- transform: "musae-rycbv3",
27
23
  borderRadius: "musae-iipnba",
28
24
  borderStartStartRadius: null,
29
25
  borderStartEndRadius: null,
@@ -35,15 +31,55 @@ const styles = {
35
31
  borderBottomRightRadius: null,
36
32
  minWidth: "musae-70jws7",
37
33
  textAlign: "musae-2b8uid",
34
+ boxShadow: "musae-igitpm",
38
35
  backgroundColor: "musae-q1mx2j",
39
36
  color: "musae-19dipnz",
40
37
  $$css: true
41
38
  }, {
39
+ "--boxShadow": `0 0 0 ${sizes.smallest} ${props.color}` != null ? `0 0 0 ${sizes.smallest} ${props.color}` : "initial",
42
40
  "--backgroundColor": props.backgroundColor != null ? props.backgroundColor : "initial",
43
41
  "--color": props.color != null ? props.color : "initial"
44
42
  }],
45
43
  dot: {
46
44
  minWidth: null,
45
+ width: "musae-2jq81",
46
+ height: "musae-1v3ox18",
47
+ $$css: true
48
+ },
49
+ invisible: {
50
+ display: "musae-1s85apg",
51
+ $$css: true
52
+ },
53
+ "top-right": {
54
+ top: "musae-13vifvy",
55
+ right: "musae-3m8u43",
56
+ insetInlineStart: null,
57
+ insetInlineEnd: null,
58
+ transform: "musae-rycbv3",
59
+ $$css: true
60
+ },
61
+ "top-left": {
62
+ top: "musae-13vifvy",
63
+ left: "musae-u96u03",
64
+ insetInlineStart: null,
65
+ insetInlineEnd: null,
66
+ transform: "musae-1i3z1r0",
67
+ $$css: true
68
+ },
69
+ "bottom-right": {
70
+ bottom: "musae-1ey2m1c",
71
+ right: "musae-3m8u43",
72
+ insetInlineStart: null,
73
+ insetInlineEnd: null,
74
+ transform: "musae-1vfo23u",
75
+ $$css: true
76
+ },
77
+ "bottom-left": {
78
+ bottom: "musae-1ey2m1c",
79
+ left: "musae-u96u03",
80
+ insetInlineStart: null,
81
+ insetInlineEnd: null,
82
+ transform: "musae-itovws",
47
83
  $$css: true
48
84
  }
49
85
  }
@@ -52,7 +88,9 @@ const Badge = ({
52
88
  className,
53
89
  style,
54
90
  children,
55
- content
91
+ content,
92
+ invisible = false,
93
+ placement = "top-right"
56
94
  }) => {
57
95
  const classNames = useClassNames(ComponentToken.Badge);
58
96
  const theme = useTheme();
@@ -62,7 +100,7 @@ const Badge = ({
62
100
  tail: _stylex.props(styles.tail.default({
63
101
  backgroundColor: theme.colors[ColorToken.Primary],
64
102
  color: theme.colors[ColorToken.OnPrimary]
65
- }), isDot && styles.tail.dot, typography.label.small)
103
+ }), isDot && styles.tail.dot, typography.label.small, invisible && styles.tail.invisible, styles.tail[placement])
66
104
  };
67
105
  return React.createElement("span", {
68
106
  className: clsx(classNames[BadgeClassToken.Badge], className, styled.badge.className),
@@ -1,5 +1,6 @@
1
- import { ReactNode } from "react";
2
- import { ComponentProps } from "../../types/element";
1
+ import type { ReactNode } from "react";
2
+ import type { ComponentProps } from "../../types/element";
3
+ type Placement = "top-right" | "top-left" | "bottom-right" | "bottom-left";
3
4
  /**
4
5
  * @description
5
6
  * badge props
@@ -8,11 +9,26 @@ export type BadgeProps = ComponentProps & {
8
9
  /**
9
10
  * @description
10
11
  * children
12
+ * @requires
11
13
  */
12
14
  children: ReactNode;
13
15
  /**
14
16
  * @description
15
17
  * content
18
+ * @default void 0
16
19
  */
17
20
  content?: ReactNode;
21
+ /**
22
+ * @description
23
+ * invisible
24
+ * @default false
25
+ */
26
+ invisible?: boolean;
27
+ /**
28
+ * @description
29
+ * placement
30
+ * @default "top-right"
31
+ */
32
+ placement?: Placement;
18
33
  };
34
+ export {};
@@ -31,7 +31,8 @@ const Clock = ({
31
31
  }));
32
32
  }
33
33
  }), index === columns.length - 1 ? null : React.createElement(Divider, {
34
- type: "vertical"
34
+ type: "vertical",
35
+ key: `${unit}-divider`
35
36
  })];
36
37
  }));
37
38
  };
@@ -13,7 +13,7 @@ const Dialog = ({ open, closable = true, ...props }) => {
13
13
  // eslint-disable-next-line react-hooks/exhaustive-deps
14
14
  }, [open]);
15
15
  return (React.createElement(Portal, { open: open || _isVisible, lockable: true },
16
- React.createElement(Popup, { ...props, closable: true, open: open, onClosed: turnOff })));
16
+ React.createElement(Popup, { ...props, closable: closable, open: open, onClosed: turnOff })));
17
17
  };
18
18
  var Dialog$1 = Dialog;
19
19
 
@@ -9,7 +9,7 @@ import { ColorToken } from '../../utils/colors.js';
9
9
  import { typography } from '../theme/theme.js';
10
10
  import clsx from 'clsx';
11
11
  import { useClosable } from '../../hooks/use-closable.js';
12
- import { contains } from '../../node_modules/.pnpm/@aiszlab_relax@1.2.59_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@aiszlab/relax/dist/dom/contains.js';
12
+ import { contains } from '../../node_modules/.pnpm/@aiszlab_relax@1.2.64_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@aiszlab/relax/dist/dom/contains.js';
13
13
 
14
14
  const styles = {
15
15
  header: {
@@ -9,7 +9,7 @@ import { ColorToken } from '../../utils/colors.js';
9
9
  import clsx from 'clsx';
10
10
  import { typography } from '../theme/theme.js';
11
11
  import { useClosable } from '../../hooks/use-closable.js';
12
- import { contains } from '../../node_modules/.pnpm/@aiszlab_relax@1.2.59_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@aiszlab/relax/dist/dom/contains.js';
12
+ import { contains } from '../../node_modules/.pnpm/@aiszlab_relax@1.2.64_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@aiszlab/relax/dist/dom/contains.js';
13
13
 
14
14
  const styles = {
15
15
  popup: {
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import type { HighlightProps } from "./types";
3
+ declare const Highlight: ({ children }: HighlightProps) => React.JSX.Element;
4
+ export default Highlight;
@@ -0,0 +1,2 @@
1
+ import Highlight from "./highlight";
2
+ export { Highlight };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @description
3
+ * highlight props
4
+ */
5
+ export type HighlightProps = {
6
+ /**
7
+ * @description
8
+ * children
9
+ */
10
+ children: string;
11
+ };
@@ -174,10 +174,22 @@ const Notification = ({
174
174
  const classNames = useClassNames(ComponentToken.Notification);
175
175
  // after duration, `Notification` will auto destroy
176
176
  useTimeout(async () => {
177
- await animate(scope.current, {
178
- opacity: 0,
179
- marginTop: scope.current.getBoundingClientRect().height * -1
180
- });
177
+ switch (placement) {
178
+ case "bottom":
179
+ case "bottomLeft":
180
+ case "bottomRight":
181
+ await animate(scope.current, {
182
+ opacity: 0,
183
+ marginBottom: (scope.current.getBoundingClientRect().height + 12) * -1
184
+ });
185
+ break;
186
+ default:
187
+ await animate(scope.current, {
188
+ opacity: 0,
189
+ marginTop: (scope.current.getBoundingClientRect().height + 12) * -1
190
+ });
191
+ break;
192
+ }
181
193
  onClose?.();
182
194
  }, duration);
183
195
  const styled = {
@@ -20,12 +20,12 @@ const OtpInput = ({
20
20
  length
21
21
  }).fill(null));
22
22
  const [focusedAt, setFocusedAt] = useState(0);
23
- const refocus = useEvent(foucsAt => {
24
- const _foucsAt = clamp(foucsAt, 0, length - 1);
25
- // handle input
26
- inputRefs.current[_foucsAt]?.focus?.();
27
- inputRefs.current[_foucsAt]?.select?.();
28
- setFocusedAt(_foucsAt);
23
+ const refocus = useEvent(_foucsAt => {
24
+ const foucsAt = clamp(_foucsAt, 0, length - 1);
25
+ // handle input, only select when prev input
26
+ inputRefs.current[foucsAt]?.focus?.();
27
+ _foucsAt < length && inputRefs.current[foucsAt]?.select?.();
28
+ setFocusedAt(foucsAt);
29
29
  });
30
30
  const changeValue = useEvent(value => {
31
31
  _change(focusedAt, value);
@@ -1,7 +1,6 @@
1
1
  import React, { forwardRef, useRef, useCallback, useImperativeHandle } from 'react';
2
2
  import Popper from '../popper/popper.js';
3
- import { useBoolean, chain, useFocus } from '@aiszlab/relax';
4
- import { useEvents } from './hooks.js';
3
+ import { useBoolean, useEvent, useFocus } from '@aiszlab/relax';
5
4
  import { ComponentToken, PickerClassToken } from '../../utils/class-name.js';
6
5
  import { useClassNames } from '../../hooks/use-class-names.js';
7
6
  import { props } from '../../node_modules/.pnpm/@stylexjs_stylex@0.7.5/node_modules/@stylexjs/stylex/lib/es/stylex.js';
@@ -42,7 +41,6 @@ const Picker = forwardRef(({
42
41
  const classNames = useClassNames(ComponentToken.Picker);
43
42
  const theme = useTheme();
44
43
  const pickableRef = useRef(null);
45
- const onDropdownClick = useCallback(e => e.preventDefault(), []);
46
44
  const getDropdownWidth = useCallback(() => {
47
45
  if (!popupWidth) return void 0;
48
46
  if (!trigger.current) return void 0;
@@ -51,17 +49,19 @@ const Picker = forwardRef(({
51
49
  useImperativeHandle(ref, () => ({
52
50
  close
53
51
  }));
54
- /// events
55
- const {
56
- blur,
57
- click
58
- } = useEvents({
59
- onBlur: close,
60
- onClick: chain(onClick, toggle)
52
+ const click = useEvent(event => {
53
+ event.stopPropagation();
54
+ toggle();
55
+ onClick?.(event);
56
+ });
57
+ const onBlur = useEvent(e => {
58
+ e.stopPropagation();
59
+ close();
61
60
  });
62
61
  const [isFocused, focusProps] = useFocus({
63
- onBlur: blur
62
+ onBlur
64
63
  });
64
+ const onDropdownClick = useCallback(e => e.preventDefault(), []);
65
65
  const styled = {
66
66
  picker: props(typography.body.medium, styles$1.wrapper({
67
67
  outlineColor: theme.colors[ColorToken.Outline]
@@ -94,11 +94,11 @@ const Picker = forwardRef(({
94
94
  trigger: trigger.current,
95
95
  open: isOpen,
96
96
  className: classNames[PickerClassToken.Dropdown],
97
- // click on popper, keep select focused
98
- onMouseDown: onDropdownClick,
99
97
  onEntered: onPopperEntered,
100
98
  onExit: onPopperExite,
101
- onExited: onPopperExited
99
+ onExited: onPopperExited,
100
+ // click on popper, keep select focused
101
+ onMouseDown: onDropdownClick
102
102
  }, React.createElement("div", {
103
103
  ref: pickableRef,
104
104
  className: clsx(pickableClassName, styled.pickable.className),
@@ -35,7 +35,7 @@ export interface PickerProps extends ComponentProps {
35
35
  * @description
36
36
  * click handler
37
37
  */
38
- onClick?: MouseEventHandler<HTMLDivElement>;
38
+ onClick?: MouseEventHandler<HTMLSpanElement>;
39
39
  /**
40
40
  * @description
41
41
  * pickable
@@ -1,4 +1,4 @@
1
- import { useBoolean, toArray, useRefs, useEvent, useHover, chain, useFocus } from '@aiszlab/relax';
1
+ import { useBoolean, toArray, useRefs, useEvent, useHover, chain, useFocus, useClickAway } from '@aiszlab/relax';
2
2
  import React, { useRef, useMemo, cloneElement } from 'react';
3
3
  import Popper from '../popper/popper.js';
4
4
  import _stylex from '../../node_modules/.pnpm/@stylexjs_stylex@0.7.5/node_modules/@stylexjs/stylex/lib/es/stylex.js';
@@ -31,16 +31,19 @@ const Popover = ({
31
31
  const _ref = useRef(null);
32
32
  const [_isOpen, {
33
33
  toggle,
34
- turnOn
34
+ turnOn,
35
+ turnOff
35
36
  }] = useBoolean(false);
36
37
  const triggerBy = useMemo(() => new Set(toArray(_triggerBy)), [_triggerBy]);
37
38
  const classNames = useClassNames(ComponentToken.Popover);
38
39
  const childRef = useRefs(_ref, _children.props.ref);
40
+ const popperRef = useRef(null);
39
41
  const onClick = useEvent(e => {
40
42
  e.stopPropagation();
41
43
  toggle();
42
44
  });
43
- const onContextMenu = useEvent(() => {
45
+ const onContextMenu = useEvent(e => {
46
+ e.preventDefault();
44
47
  turnOn();
45
48
  });
46
49
  const [isHovered, hoverProps] = useHover({
@@ -77,6 +80,9 @@ const Popover = ({
77
80
  const leavePopper = useEvent(e => {
78
81
  hoverProps.onPointerLeave(e);
79
82
  });
83
+ useClickAway(() => {
84
+ turnOff();
85
+ }, popperRef);
80
86
  const styled = {
81
87
  popover: _stylex.props(styles.popover, typography.body.medium),
82
88
  title: _stylex.props(styles.title, typography.title.medium)
@@ -89,7 +95,8 @@ const Popover = ({
89
95
  onPointerEnter: enterPopper,
90
96
  onPointerLeave: leavePopper
91
97
  }),
92
- placement: placement
98
+ placement: placement,
99
+ ref: popperRef
93
100
  }, React.createElement("div", {
94
101
  className: clsx(classNames[PopoverClassToken.Popover], className, styled.popover.className),
95
102
  style: {
@@ -1,4 +1,5 @@
1
1
  import React from "react";
2
- import type { DropdownProps } from "./types";
3
- declare const Dropdown: ({ open, children, placement, style, className, onExit, onExited, onEntered, trigger: _trigger, offset: _offset, overlay, arrow: arrowable, ...props }: DropdownProps) => React.JSX.Element;
2
+ declare const Dropdown: React.ForwardRefExoticComponent<Omit<import("./types").PopperProps, "placement" | "portal"> & {
3
+ placement: import("@floating-ui/dom").Placement;
4
+ } & React.RefAttributes<HTMLDivElement>>;
4
5
  export default Dropdown;
@@ -1,9 +1,9 @@
1
- import React, { useRef, useMemo, useEffect } from 'react';
1
+ import React, { forwardRef, useRef, useMemo, useLayoutEffect } from 'react';
2
2
  import { ComponentToken, PopperClassToken } from '../../utils/class-name.js';
3
3
  import { useClassNames } from '../../hooks/use-class-names.js';
4
4
  import { props } from '../../node_modules/.pnpm/@stylexjs_stylex@0.7.5/node_modules/@stylexjs/stylex/lib/es/stylex.js';
5
5
  import clsx from 'clsx';
6
- import { isFunction } from '@aiszlab/relax';
6
+ import { useRefs, isFunction } from '@aiszlab/relax';
7
7
  import { autoUpdate, computePosition, flip, offset, arrow } from '@floating-ui/dom';
8
8
  import { useOffsets } from './hooks.js';
9
9
  import { useTheme } from '../theme/hooks.js';
@@ -54,7 +54,7 @@ const styles = {
54
54
  }]
55
55
  }
56
56
  };
57
- const Dropdown = ({
57
+ const Dropdown = forwardRef(({
58
58
  open,
59
59
  children,
60
60
  placement,
@@ -68,11 +68,12 @@ const Dropdown = ({
68
68
  overlay = false,
69
69
  arrow: arrowable = false,
70
70
  ...props$1
71
- }) => {
72
- const [floatable, animate] = useAnimate();
71
+ }, ref) => {
72
+ const [_floatable, animate] = useAnimate();
73
73
  const arrowRef = useRef(null);
74
74
  const classNames = useClassNames(ComponentToken.Popper);
75
75
  const theme = useTheme();
76
+ const floatable = useRefs(_floatable, ref);
76
77
  /// how to get trigger
77
78
  const trigger = useMemo(() => {
78
79
  if (!open) return null;
@@ -86,10 +87,10 @@ const Dropdown = ({
86
87
  });
87
88
  /// auto update: calc trigger dom to get position
88
89
  /// if trigger changed, re-relate
89
- useEffect(() => {
90
+ useLayoutEffect(() => {
90
91
  if (!trigger) return;
91
- const cleanup = autoUpdate(trigger, floatable.current, () => {
92
- computePosition(trigger, floatable.current, {
92
+ const cleanup = autoUpdate(trigger, _floatable.current, () => {
93
+ computePosition(trigger, _floatable.current, {
93
94
  placement: placement,
94
95
  middleware: [flip(), offset(offsets), arrowable && !!arrowRef.current && arrow({
95
96
  element: arrowRef.current,
@@ -103,7 +104,7 @@ const Dropdown = ({
103
104
  }) => {
104
105
  const [side] = _placement.split("-");
105
106
  // set float element styles
106
- floatable.current.style.translate = `${x}px ${y}px`;
107
+ _floatable.current.style.translate = `${x}px ${y}px`;
107
108
  // set arrwo styles
108
109
  if (middlewareData.arrow && !!arrowRef.current) {
109
110
  const offsetY = `${middlewareData.arrow.y ?? 0 - 8}px`;
@@ -119,19 +120,11 @@ const Dropdown = ({
119
120
  };
120
121
  // eslint-disable-next-line react-hooks/exhaustive-deps
121
122
  }, [placement, trigger, offsets, arrowable]);
122
- const styled = {
123
- dropdown: props(styles.dropdown.default({
124
- backgroundColor: theme.colors[ColorToken.SurfaceContainer]
125
- }), overlay && styles.dropdown.overlay),
126
- arrow: props(styles.arrow.default({
127
- backgroundColor: theme.colors[ColorToken.SurfaceContainer]
128
- }))
129
- };
130
- useEffect(() => {
123
+ useLayoutEffect(() => {
131
124
  (async () => {
132
125
  if (open) {
133
- floatable.current.style.display = "";
134
- await animate(floatable.current, {
126
+ _floatable.current.style.display = "";
127
+ await animate(_floatable.current, {
135
128
  opacity: 1,
136
129
  transform: "scale(1, 1)"
137
130
  }, {
@@ -141,19 +134,27 @@ const Dropdown = ({
141
134
  await onEntered?.();
142
135
  return;
143
136
  }
144
- await Promise.all([onExit?.(), animate(floatable.current, {
137
+ await Promise.all([onExit?.(), animate(_floatable.current, {
145
138
  opacity: 0,
146
139
  transform: "scale(0, 0)"
147
140
  }, {
148
141
  delay: 0.1,
149
142
  duration: 0.2
150
143
  }).then(() => {
151
- floatable.current.style.display = "none";
144
+ _floatable.current.style.display = "none";
152
145
  })]);
153
146
  onExited?.();
154
147
  })();
155
148
  // eslint-disable-next-line react-hooks/exhaustive-deps
156
149
  }, [open]);
150
+ const styled = {
151
+ dropdown: props(styles.dropdown.default({
152
+ backgroundColor: theme.colors[ColorToken.SurfaceContainer]
153
+ }), overlay && styles.dropdown.overlay),
154
+ arrow: props(styles.arrow.default({
155
+ backgroundColor: theme.colors[ColorToken.SurfaceContainer]
156
+ }))
157
+ };
157
158
  return React.createElement("div", {
158
159
  ref: floatable,
159
160
  ...props$1,
@@ -167,6 +168,6 @@ const Dropdown = ({
167
168
  className: styled.arrow.className,
168
169
  style: styled.arrow.style
169
170
  }));
170
- };
171
+ });
171
172
 
172
173
  export { Dropdown as default };
@@ -1,4 +1,4 @@
1
1
  import React from "react";
2
2
  import type { PopperProps } from "./types";
3
- declare const Popper: ({ destroyable, placement, ...props }: PopperProps) => React.JSX.Element;
3
+ declare const Popper: React.ForwardRefExoticComponent<PopperProps & React.RefAttributes<HTMLDivElement>>;
4
4
  export default Popper;
@@ -1,10 +1,10 @@
1
- import React from 'react';
1
+ import React, { forwardRef } from 'react';
2
2
  import Portal from '../portal/portal.js';
3
3
  import Dropdown from './dropdown.js';
4
4
 
5
- const Popper = ({ destroyable, placement = "bottom-start", ...props }) => {
5
+ const Popper = forwardRef(({ destroyable, placement = "bottom-start", ...props }, ref) => {
6
6
  return (React.createElement(Portal, { open: props.open, destroyable: destroyable },
7
- React.createElement(Dropdown, { ...props, placement: placement })));
8
- };
7
+ React.createElement(Dropdown, { ...props, placement: placement, ref: ref })));
8
+ });
9
9
 
10
10
  export { Popper as default };
@@ -4,7 +4,11 @@ import type { TreeProps } from "./types";
4
4
  * @description
5
5
  * expanded keys
6
6
  */
7
- export declare const useExpandedKeys: ([expandedKeys, onExpand]: [TreeProps["expandedKeys"], TreeProps["onExpand"]]) => {
7
+ export declare const useExpandedKeys: ({ expandedKeys, onExpand, defaultExpandedKeys, }: {
8
+ expandedKeys?: Key[];
9
+ onExpand: TreeProps["onExpand"];
10
+ defaultExpandedKeys: Key[];
11
+ }) => {
8
12
  expandedKeys: Set<Key>;
9
13
  toggle: (key: Key) => void;
10
14
  };
@@ -12,8 +16,10 @@ export declare const useExpandedKeys: ([expandedKeys, onExpand]: [TreeProps["exp
12
16
  * @description
13
17
  * selected keys
14
18
  */
15
- export declare const useSelectedKeys: ({ selectedKeys: _selectedKeys }: {
19
+ export declare const useSelectedKeys: ({ selectedKeys: _selectedKeys, defaultSelectedKeys, onSelect, }: {
16
20
  selectedKeys?: Key[];
21
+ defaultSelectedKeys: Key[];
22
+ onSelect?: (key: Key) => void;
17
23
  }) => {
18
24
  selectedKeys: Set<Key>;
19
25
  toggle: (key: Key) => void;
@@ -5,14 +5,14 @@ import { useMemo, useCallback } from 'react';
5
5
  * @description
6
6
  * expanded keys
7
7
  */
8
- const useExpandedKeys = ([expandedKeys, onExpand]) => {
9
- const [_expandedKeys, _setExpandedKeys] = useControlledState(expandedKeys);
8
+ const useExpandedKeys = ({ expandedKeys, onExpand, defaultExpandedKeys, }) => {
9
+ const [_expandedKeys, _setExpandedKeys] = useControlledState(expandedKeys, { defaultState: defaultExpandedKeys });
10
10
  const readableExpandedKeys = useMemo(() => new Set(_expandedKeys), [_expandedKeys]);
11
11
  const toggle = useCallback((key) => {
12
12
  // deal expanding key
13
- const readableExpandingKeys = new Set(_expandedKeys);
14
- readableExpandingKeys.has(key) ? readableExpandingKeys.delete(key) : readableExpandingKeys.add(key);
15
- const expandingKeys = Array.from(readableExpandingKeys);
13
+ const _keys = new Set(_expandedKeys);
14
+ _keys.has(key) ? _keys.delete(key) : _keys.add(key);
15
+ const expandingKeys = Array.from(_keys);
16
16
  // change inner state
17
17
  // emit change handler
18
18
  _setExpandedKeys(expandingKeys);
@@ -27,16 +27,15 @@ const useExpandedKeys = ([expandedKeys, onExpand]) => {
27
27
  * @description
28
28
  * selected keys
29
29
  */
30
- const useSelectedKeys = ({ selectedKeys: _selectedKeys }) => {
31
- const [selectedKeys, setSelectedKeys] = useControlledState(_selectedKeys);
32
- const __selectedKeys = useMemo(() => new Set(selectedKeys), [selectedKeys]);
30
+ const useSelectedKeys = ({ selectedKeys: _selectedKeys, defaultSelectedKeys, onSelect, }) => {
31
+ const [selectedKeys, setSelectedKeys] = useControlledState(_selectedKeys, { defaultState: defaultSelectedKeys });
32
+ const readableSelectedKeys = useMemo(() => new Set(selectedKeys), [selectedKeys]);
33
33
  const toggle = useEvent((key) => {
34
- setSelectedKeys(() => {
35
- return Array.from([key]);
36
- });
34
+ setSelectedKeys(() => [key]);
35
+ onSelect?.(key);
37
36
  });
38
37
  return {
39
- selectedKeys: __selectedKeys,
38
+ selectedKeys: readableSelectedKeys,
40
39
  toggle,
41
40
  };
42
41
  };
@@ -41,6 +41,7 @@ const styles = {
41
41
  transitionProperty: null,
42
42
  transitionTimingFunction: null,
43
43
  transform: "musae-1v0jg1i",
44
+ userSelect: "musae-87ps6o",
44
45
  $$css: true
45
46
  }, {
46
47
  "--transform": (props.isExpanded ? "rotate(90deg)" : null) != null ? props.isExpanded ? "rotate(90deg)" : null : "initial"
@@ -62,12 +63,17 @@ const styles = {
62
63
  borderBottomRightRadius: null,
63
64
  backgroundColor: "musae-8hsaj5 musae-rl4t6d",
64
65
  color: "musae-19dipnz",
66
+ cursor: "musae-t0e3qv",
65
67
  $$css: true
66
68
  }, {
67
69
  "--bcbnzo": (props.isSelected ? props.backgroundColor : null) != null ? props.isSelected ? props.backgroundColor : null : "initial",
68
70
  "--1e2mv7m": props.hoveredBackgroundColor != null ? props.hoveredBackgroundColor : "initial",
69
71
  "--color": (props.isSelected ? props.color : null) != null ? props.isSelected ? props.color : null : "initial"
70
- }]
72
+ }],
73
+ selectable: {
74
+ cursor: "musae-1ypdohk",
75
+ $$css: true
76
+ }
71
77
  };
72
78
  const Node = ({
73
79
  value,
@@ -98,7 +104,7 @@ const Node = ({
98
104
  backgroundColor: theme.colors[ColorToken.SurfaceContainer],
99
105
  hoveredBackgroundColor: theme.colors[ColorToken.SurfaceContainer],
100
106
  color: theme.colors[ColorToken.Primary]
101
- })),
107
+ }), selectable && styles.selectable),
102
108
  expander: props(styles.expander({
103
109
  isExpanded
104
110
  }))
@@ -1,4 +1,4 @@
1
1
  import React from "react";
2
2
  import type { TreeProps } from "./types";
3
- declare const Tree: ({ expandedKeys: _expandedKeys, onExpand, className, style, nodes, selectable, selectedKeys: _selectedKeys, }: TreeProps) => React.JSX.Element;
3
+ declare const Tree: ({ className, style, nodes, selectable, expandedKeys: _expandedKeys, selectedKeys: _selectedKeys, checkedKeys: _checkedKeys, defaultExpandedKeys, defaultSelectedKeys, defaultCheckedKeys, onExpand, onSelect, onCheck, }: TreeProps) => React.JSX.Element;
4
4
  export default Tree;
@@ -4,10 +4,22 @@ import Context from './context.js';
4
4
  import { useTogglable } from '@aiszlab/relax';
5
5
  import { useExpandedKeys, useSelectedKeys } from './hooks.js';
6
6
 
7
- const Tree = ({ expandedKeys: _expandedKeys, onExpand, className, style, nodes, selectable = true, selectedKeys: _selectedKeys, }) => {
8
- const { toggledKeys: checkedKeys, toggle: check } = useTogglable(nodes);
9
- const { expandedKeys, toggle: expand } = useExpandedKeys([_expandedKeys, onExpand]);
10
- const { selectedKeys, toggle: select } = useSelectedKeys({ selectedKeys: _selectedKeys });
7
+ const Tree = ({ className, style, nodes, selectable = true, expandedKeys: _expandedKeys, selectedKeys: _selectedKeys, checkedKeys: _checkedKeys, defaultExpandedKeys = [], defaultSelectedKeys = [], defaultCheckedKeys = [], onExpand, onSelect, onCheck, }) => {
8
+ const { toggledKeys: checkedKeys, toggle: check } = useTogglable(nodes, {
9
+ defaultToggledKeys: defaultCheckedKeys,
10
+ toggledKeys: _checkedKeys,
11
+ onToggle: onCheck,
12
+ });
13
+ const { expandedKeys, toggle: expand } = useExpandedKeys({
14
+ expandedKeys: _expandedKeys,
15
+ onExpand,
16
+ defaultExpandedKeys,
17
+ });
18
+ const { selectedKeys, toggle: select } = useSelectedKeys({
19
+ selectedKeys: _selectedKeys,
20
+ defaultSelectedKeys,
21
+ onSelect,
22
+ });
11
23
  const contextValue = useMemo(() => {
12
24
  return {
13
25
  checkedKeys,
@@ -38,6 +38,12 @@ export type TreeProps = ComponentProps & {
38
38
  * @default void 0
39
39
  */
40
40
  expandedKeys?: Key[];
41
+ /**
42
+ * @description
43
+ * default expanded keys
44
+ * @default []
45
+ */
46
+ defaultExpandedKeys?: Key[];
41
47
  /**
42
48
  * @description
43
49
  * expand handler
@@ -56,6 +62,36 @@ export type TreeProps = ComponentProps & {
56
62
  * @default void 0
57
63
  */
58
64
  selectedKeys?: Key[];
65
+ /**
66
+ * @description
67
+ * default selected keys
68
+ * @default []
69
+ */
70
+ defaultSelectedKeys?: Key[];
71
+ /**
72
+ * @description
73
+ * select handler
74
+ * @default void 0
75
+ */
76
+ onSelect?: (key: Key) => void;
77
+ /**
78
+ * @description
79
+ * checked keys
80
+ * @default void 0
81
+ */
82
+ checkedKeys?: Key[];
83
+ /**
84
+ * @description
85
+ * default checked keys
86
+ * @default []
87
+ */
88
+ defaultCheckedKeys?: Key[];
89
+ /**
90
+ * @description
91
+ * check handler
92
+ * @default void 0
93
+ */
94
+ onCheck?: (keys: Key[]) => void;
59
95
  };
60
96
  /**
61
97
  * @description
package/dist/stylex.css CHANGED
@@ -120,6 +120,7 @@
120
120
  .musae-1om1yv4:not(#\#):not(#\#):not(#\#){column-gap:var(--musae-h30iw9)}
121
121
  .musae-1ef45qx:not(#\#):not(#\#):not(#\#){column-gap:var(--musae-qk2ac7)}
122
122
  .musae-18jba3g:not(#\#):not(#\#):not(#\#){column-gap:var(--musae-vk5id6)}
123
+ .musae-t0e3qv:not(#\#):not(#\#):not(#\#){cursor:default}
123
124
  .musae-mper1u:not(#\#):not(#\#):not(#\#){cursor:inherit}
124
125
  .musae-1h6gzvc:not(#\#):not(#\#):not(#\#){cursor:not-allowed}
125
126
  .musae-1ypdohk:not(#\#):not(#\#):not(#\#){cursor:pointer}
@@ -231,7 +232,10 @@ html[dir='rtl'] .musae-p4054r:not(#\#):not(#\#):not(#\#){text-align:left}
231
232
  .musae-1158fpu:not(#\#):not(#\#):not(#\#){transform:rotate(45deg)}
232
233
  .musae-1iffjtl:not(#\#):not(#\#):not(#\#){transform:rotate(90deg)}
233
234
  .musae-11lhmoz:not(#\#):not(#\#):not(#\#){transform:translate(-50%,-50%)}
235
+ .musae-1i3z1r0:not(#\#):not(#\#):not(#\#){transform:translateX(-50%) translateY(-50%)}
236
+ .musae-itovws:not(#\#):not(#\#):not(#\#){transform:translateX(-50%) translateY(50%)}
234
237
  .musae-rycbv3:not(#\#):not(#\#):not(#\#){transform:translateX(50%) translateY(-50%)}
238
+ .musae-1vfo23u:not(#\#):not(#\#):not(#\#){transform:translateX(50%) translateY(50%)}
235
239
  .musae-1v0jg1i:not(#\#):not(#\#):not(#\#){transform:var(--transform,revert)}
236
240
  .musae-1g2r6go:not(#\#):not(#\#):not(#\#){transition-duration:.1s}
237
241
  .musae-13dflua:not(#\#):not(#\#):not(#\#){transition-duration:.2s}
@@ -306,6 +310,7 @@ html[dir='rtl'] .musae-p4054r:not(#\#):not(#\#):not(#\#){text-align:left}
306
310
  .musae-1ajdkb8:not(#\#):not(#\#):not(#\#):not(#\#){height:var(--musae-2h23ia)}
307
311
  .musae-1cj5796:not(#\#):not(#\#):not(#\#):not(#\#){height:var(--musae-70uu0v)}
308
312
  .musae-7kkngq:not(#\#):not(#\#):not(#\#):not(#\#){height:var(--musae-cftog7)}
313
+ .musae-1v3ox18:not(#\#):not(#\#):not(#\#):not(#\#){height:var(--musae-fwu7zn)}
309
314
  .musae-kzsoxx:not(#\#):not(#\#):not(#\#):not(#\#){height:var(--musae-jdzqnm)}
310
315
  .musae-was1v5:not(#\#):not(#\#):not(#\#):not(#\#){height:var(--musae-laggmb)}
311
316
  .musae-1gfonl1:not(#\#):not(#\#):not(#\#):not(#\#){height:var(--musae-oohzsl)}
@@ -372,6 +377,7 @@ html[dir='rtl'] .musae-p4054r:not(#\#):not(#\#):not(#\#){text-align:left}
372
377
  .musae-fx4e2q:not(#\#):not(#\#):not(#\#):not(#\#){width:var(--musae-2h23ia)}
373
378
  .musae-1gn8jaj:not(#\#):not(#\#):not(#\#):not(#\#){width:var(--musae-70uu0v)}
374
379
  .musae-1sgo4cp:not(#\#):not(#\#):not(#\#):not(#\#){width:var(--musae-cftog7)}
380
+ .musae-2jq81:not(#\#):not(#\#):not(#\#):not(#\#){width:var(--musae-fwu7zn)}
375
381
  .musae-1wmt73o:not(#\#):not(#\#):not(#\#):not(#\#){width:var(--musae-laggmb)}
376
382
  .musae-r8isjd:not(#\#):not(#\#):not(#\#):not(#\#){width:var(--musae-oohzsl)}
377
383
  .musae-145rzd9:not(#\#):not(#\#):not(#\#):not(#\#){width:var(--musae-rlgvtq)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musae",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "description": "musae-ui",
5
5
  "author": "tutu@fantufantu.com",
6
6
  "license": "MIT",
@@ -27,7 +27,7 @@
27
27
  "pnpm": ">=9"
28
28
  },
29
29
  "dependencies": {
30
- "@aiszlab/relax": "^1.2.59",
30
+ "@aiszlab/relax": "^1.2.64",
31
31
  "@dnd-kit/core": "^6.1.0",
32
32
  "@dnd-kit/modifiers": "^7.0.0",
33
33
  "@floating-ui/dom": "^1.6.5",
@@ -1,12 +0,0 @@
1
- import { type FocusEventHandler, type MouseEventHandler } from "react";
2
- /**
3
- * @description
4
- * use events for input
5
- */
6
- export declare const useEvents: ({ onBlur, onClick, }: {
7
- onBlur: FocusEventHandler<HTMLDivElement>;
8
- onClick: MouseEventHandler<HTMLDivElement>;
9
- }) => {
10
- blur: FocusEventHandler<HTMLDivElement>;
11
- click: MouseEventHandler<HTMLDivElement>;
12
- };
@@ -1,23 +0,0 @@
1
- import { useCallback } from 'react';
2
-
3
- /**
4
- * @description
5
- * use events for input
6
- */
7
- const useEvents = ({ onBlur, onClick, }) => {
8
- const blur = useCallback((e) => {
9
- onBlur?.(e);
10
- e.stopPropagation();
11
- }, [onBlur]);
12
- /// click handler
13
- const click = useCallback((e) => {
14
- onClick?.(e);
15
- e.stopPropagation();
16
- }, [onClick]);
17
- return {
18
- blur,
19
- click,
20
- };
21
- };
22
-
23
- export { useEvents };