@seed-design/react-collapsible 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,156 @@
1
+ 'use client';
2
+ var jsxRuntime = require('react/jsx-runtime');
3
+ var reactComposeRefs = require('@radix-ui/react-compose-refs');
4
+ var domUtils = require('@seed-design/dom-utils');
5
+ var reactPrimitive = require('@seed-design/react-primitive');
6
+ var react = require('react');
7
+ var reactUseControllableState = require('@radix-ui/react-use-controllable-state');
8
+ var reactUseLayoutEffect = require('@radix-ui/react-use-layout-effect');
9
+
10
+ const getContentId = (id)=>`collapsible:${id}:content`;
11
+
12
+ function useCollapsibleState(props) {
13
+ const [open, setOpen] = reactUseControllableState.useControllableState({
14
+ prop: props.open,
15
+ defaultProp: props.defaultOpen ?? false,
16
+ onChange: props.onOpenChange
17
+ });
18
+ return react.useMemo(()=>({
19
+ open,
20
+ setOpen
21
+ }), [
22
+ open,
23
+ setOpen
24
+ ]);
25
+ }
26
+ function useCollapsible(props) {
27
+ const { open, setOpen } = useCollapsibleState(props);
28
+ const { disabled } = props;
29
+ const id = react.useId();
30
+ const contentId = getContentId(id);
31
+ const contentRef = react.useRef(null);
32
+ const [height, setHeight] = react.useState(undefined);
33
+ const [visible, setVisible] = react.useState(open);
34
+ const hidden = !open && !visible;
35
+ reactUseLayoutEffect.useLayoutEffect(()=>{
36
+ if (!contentRef.current) return;
37
+ const updateHeight = ()=>{
38
+ if (!contentRef.current) return;
39
+ setHeight(contentRef.current.offsetHeight);
40
+ };
41
+ updateHeight();
42
+ const observer = new ResizeObserver(updateHeight);
43
+ observer.observe(contentRef.current);
44
+ return ()=>observer.disconnect();
45
+ }, []);
46
+ react.useEffect(()=>{
47
+ if (!open) return;
48
+ // When expanded, immediately show to allow transition
49
+ setVisible(true);
50
+ }, [
51
+ open
52
+ ]);
53
+ const panelHeight = open ? `${height}px` : "0px";
54
+ const stateProps = react.useMemo(()=>domUtils.elementProps({
55
+ "data-collapsible": "",
56
+ "data-open": domUtils.dataAttr(open),
57
+ "data-disabled": domUtils.dataAttr(disabled)
58
+ }), [
59
+ open,
60
+ disabled
61
+ ]);
62
+ return react.useMemo(()=>({
63
+ open,
64
+ setOpen,
65
+ disabled,
66
+ stateProps,
67
+ triggerAriaProps: domUtils.elementProps({
68
+ "aria-expanded": open,
69
+ "aria-controls": contentId,
70
+ "aria-disabled": disabled
71
+ }),
72
+ triggerHandlers: domUtils.elementProps({
73
+ onClick: (event)=>{
74
+ if (event.defaultPrevented) return;
75
+ if (disabled) return;
76
+ setOpen((prev)=>!prev);
77
+ }
78
+ }),
79
+ contentProps: domUtils.elementProps({
80
+ ...stateProps,
81
+ id: contentId,
82
+ hidden,
83
+ style: {
84
+ "--collapsible-content-height": height !== undefined ? panelHeight : undefined
85
+ },
86
+ onTransitionEnd: (event)=>{
87
+ if (event.propertyName !== "height") return;
88
+ if (open) return;
89
+ setVisible(false);
90
+ }
91
+ }),
92
+ refs: {
93
+ content: contentRef
94
+ }
95
+ }), [
96
+ open,
97
+ setOpen,
98
+ disabled,
99
+ stateProps,
100
+ contentId,
101
+ hidden,
102
+ height,
103
+ panelHeight
104
+ ]);
105
+ }
106
+
107
+ const CollapsibleContext = /*#__PURE__*/ react.createContext(null);
108
+ const CollapsibleProvider = CollapsibleContext.Provider;
109
+ function useCollapsibleContext({ strict = true } = {}) {
110
+ const context = react.useContext(CollapsibleContext);
111
+ if (!context && strict) {
112
+ throw new Error("useCollapsibleContext must be used within a CollapsibleRoot");
113
+ }
114
+ return context;
115
+ }
116
+
117
+ const CollapsibleRoot = /*#__PURE__*/ react.forwardRef((props, ref)=>{
118
+ const { open, defaultOpen, onOpenChange, disabled, ...otherProps } = props;
119
+ const api = useCollapsible({
120
+ open,
121
+ defaultOpen,
122
+ onOpenChange,
123
+ disabled
124
+ });
125
+ return /*#__PURE__*/ jsxRuntime.jsx(CollapsibleProvider, {
126
+ value: api,
127
+ children: /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
128
+ ref: ref,
129
+ ...domUtils.mergeProps(api.stateProps, otherProps)
130
+ })
131
+ });
132
+ });
133
+ CollapsibleRoot.displayName = "CollapsibleRoot";
134
+ const CollapsibleTrigger = /*#__PURE__*/ react.forwardRef((props, ref)=>{
135
+ const api = useCollapsibleContext();
136
+ return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.button, {
137
+ ref: ref,
138
+ ...domUtils.mergeProps(api.stateProps, api.triggerAriaProps, api.triggerHandlers, props)
139
+ });
140
+ });
141
+ CollapsibleTrigger.displayName = "CollapsibleTrigger";
142
+ const CollapsibleContent = /*#__PURE__*/ react.forwardRef((props, ref)=>{
143
+ const api = useCollapsibleContext();
144
+ return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
145
+ ref: reactComposeRefs.composeRefs(ref, api.refs.content),
146
+ ...domUtils.mergeProps(api.contentProps, props)
147
+ });
148
+ });
149
+ CollapsibleContent.displayName = "CollapsibleContent";
150
+
151
+ exports.CollapsibleContent = CollapsibleContent;
152
+ exports.CollapsibleProvider = CollapsibleProvider;
153
+ exports.CollapsibleRoot = CollapsibleRoot;
154
+ exports.CollapsibleTrigger = CollapsibleTrigger;
155
+ exports.useCollapsible = useCollapsible;
156
+ exports.useCollapsibleContext = useCollapsibleContext;
@@ -0,0 +1,151 @@
1
+ 'use client';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { composeRefs } from '@radix-ui/react-compose-refs';
4
+ import { elementProps, dataAttr, mergeProps } from '@seed-design/dom-utils';
5
+ import { Primitive } from '@seed-design/react-primitive';
6
+ import { useId, useRef, useState, useEffect, useMemo, createContext, useContext, forwardRef } from 'react';
7
+ import { useControllableState } from '@radix-ui/react-use-controllable-state';
8
+ import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';
9
+
10
+ const getContentId = (id)=>`collapsible:${id}:content`;
11
+
12
+ function useCollapsibleState(props) {
13
+ const [open, setOpen] = useControllableState({
14
+ prop: props.open,
15
+ defaultProp: props.defaultOpen ?? false,
16
+ onChange: props.onOpenChange
17
+ });
18
+ return useMemo(()=>({
19
+ open,
20
+ setOpen
21
+ }), [
22
+ open,
23
+ setOpen
24
+ ]);
25
+ }
26
+ function useCollapsible(props) {
27
+ const { open, setOpen } = useCollapsibleState(props);
28
+ const { disabled } = props;
29
+ const id = useId();
30
+ const contentId = getContentId(id);
31
+ const contentRef = useRef(null);
32
+ const [height, setHeight] = useState(undefined);
33
+ const [visible, setVisible] = useState(open);
34
+ const hidden = !open && !visible;
35
+ useLayoutEffect(()=>{
36
+ if (!contentRef.current) return;
37
+ const updateHeight = ()=>{
38
+ if (!contentRef.current) return;
39
+ setHeight(contentRef.current.offsetHeight);
40
+ };
41
+ updateHeight();
42
+ const observer = new ResizeObserver(updateHeight);
43
+ observer.observe(contentRef.current);
44
+ return ()=>observer.disconnect();
45
+ }, []);
46
+ useEffect(()=>{
47
+ if (!open) return;
48
+ // When expanded, immediately show to allow transition
49
+ setVisible(true);
50
+ }, [
51
+ open
52
+ ]);
53
+ const panelHeight = open ? `${height}px` : "0px";
54
+ const stateProps = useMemo(()=>elementProps({
55
+ "data-collapsible": "",
56
+ "data-open": dataAttr(open),
57
+ "data-disabled": dataAttr(disabled)
58
+ }), [
59
+ open,
60
+ disabled
61
+ ]);
62
+ return useMemo(()=>({
63
+ open,
64
+ setOpen,
65
+ disabled,
66
+ stateProps,
67
+ triggerAriaProps: elementProps({
68
+ "aria-expanded": open,
69
+ "aria-controls": contentId,
70
+ "aria-disabled": disabled
71
+ }),
72
+ triggerHandlers: elementProps({
73
+ onClick: (event)=>{
74
+ if (event.defaultPrevented) return;
75
+ if (disabled) return;
76
+ setOpen((prev)=>!prev);
77
+ }
78
+ }),
79
+ contentProps: elementProps({
80
+ ...stateProps,
81
+ id: contentId,
82
+ hidden,
83
+ style: {
84
+ "--collapsible-content-height": height !== undefined ? panelHeight : undefined
85
+ },
86
+ onTransitionEnd: (event)=>{
87
+ if (event.propertyName !== "height") return;
88
+ if (open) return;
89
+ setVisible(false);
90
+ }
91
+ }),
92
+ refs: {
93
+ content: contentRef
94
+ }
95
+ }), [
96
+ open,
97
+ setOpen,
98
+ disabled,
99
+ stateProps,
100
+ contentId,
101
+ hidden,
102
+ height,
103
+ panelHeight
104
+ ]);
105
+ }
106
+
107
+ const CollapsibleContext = /*#__PURE__*/ createContext(null);
108
+ const CollapsibleProvider = CollapsibleContext.Provider;
109
+ function useCollapsibleContext({ strict = true } = {}) {
110
+ const context = useContext(CollapsibleContext);
111
+ if (!context && strict) {
112
+ throw new Error("useCollapsibleContext must be used within a CollapsibleRoot");
113
+ }
114
+ return context;
115
+ }
116
+
117
+ const CollapsibleRoot = /*#__PURE__*/ forwardRef((props, ref)=>{
118
+ const { open, defaultOpen, onOpenChange, disabled, ...otherProps } = props;
119
+ const api = useCollapsible({
120
+ open,
121
+ defaultOpen,
122
+ onOpenChange,
123
+ disabled
124
+ });
125
+ return /*#__PURE__*/ jsx(CollapsibleProvider, {
126
+ value: api,
127
+ children: /*#__PURE__*/ jsx(Primitive.div, {
128
+ ref: ref,
129
+ ...mergeProps(api.stateProps, otherProps)
130
+ })
131
+ });
132
+ });
133
+ CollapsibleRoot.displayName = "CollapsibleRoot";
134
+ const CollapsibleTrigger = /*#__PURE__*/ forwardRef((props, ref)=>{
135
+ const api = useCollapsibleContext();
136
+ return /*#__PURE__*/ jsx(Primitive.button, {
137
+ ref: ref,
138
+ ...mergeProps(api.stateProps, api.triggerAriaProps, api.triggerHandlers, props)
139
+ });
140
+ });
141
+ CollapsibleTrigger.displayName = "CollapsibleTrigger";
142
+ const CollapsibleContent = /*#__PURE__*/ forwardRef((props, ref)=>{
143
+ const api = useCollapsibleContext();
144
+ return /*#__PURE__*/ jsx(Primitive.div, {
145
+ ref: composeRefs(ref, api.refs.content),
146
+ ...mergeProps(api.contentProps, props)
147
+ });
148
+ });
149
+ CollapsibleContent.displayName = "CollapsibleContent";
150
+
151
+ export { CollapsibleContent as C, CollapsibleRoot as a, CollapsibleTrigger as b, CollapsibleProvider as c, useCollapsible as d, useCollapsibleContext as u };
package/lib/index.cjs ADDED
@@ -0,0 +1,16 @@
1
+ var Collapsible12s = require('./Collapsible-12s-B5Klt2JP.cjs');
2
+
3
+ var Collapsible_namespace = {
4
+ __proto__: null,
5
+ Content: Collapsible12s.CollapsibleContent,
6
+ Root: Collapsible12s.CollapsibleRoot,
7
+ Trigger: Collapsible12s.CollapsibleTrigger
8
+ };
9
+
10
+ exports.CollapsibleContent = Collapsible12s.CollapsibleContent;
11
+ exports.CollapsibleProvider = Collapsible12s.CollapsibleProvider;
12
+ exports.CollapsibleRoot = Collapsible12s.CollapsibleRoot;
13
+ exports.CollapsibleTrigger = Collapsible12s.CollapsibleTrigger;
14
+ exports.useCollapsible = Collapsible12s.useCollapsible;
15
+ exports.useCollapsibleContext = Collapsible12s.useCollapsibleContext;
16
+ exports.Collapsible = Collapsible_namespace;