@impulse-ui-native/accordion 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +45 -0
- package/dist/components/accordion.d.mts +13 -0
- package/dist/components/accordion.js +14 -0
- package/dist/components/accordion.js.map +1 -0
- package/dist/components/content.d.mts +8 -0
- package/dist/components/content.js +78 -0
- package/dist/components/content.js.map +1 -0
- package/dist/components/index.d.mts +5 -0
- package/dist/components/index.js +5 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/item.d.mts +8 -0
- package/dist/components/item.js +37 -0
- package/dist/components/item.js.map +1 -0
- package/dist/components/root.d.mts +8 -0
- package/dist/components/root.js +130 -0
- package/dist/components/root.js.map +1 -0
- package/dist/components/trigger.d.mts +8 -0
- package/dist/components/trigger.js +145 -0
- package/dist/components/trigger.js.map +1 -0
- package/dist/contexts/accordion.context.d.mts +30 -0
- package/dist/contexts/accordion.context.js +30 -0
- package/dist/contexts/accordion.context.js.map +1 -0
- package/dist/contexts/index.d.mts +4 -0
- package/dist/contexts/index.js +2 -0
- package/dist/contexts/index.js.map +1 -0
- package/dist/hooks/accordion-animation.types.d.mts +6 -0
- package/dist/hooks/accordion-animation.types.js +1 -0
- package/dist/hooks/accordion-animation.types.js.map +1 -0
- package/dist/hooks/index.d.mts +6 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/use-accordion-animation-progress.hook.d.mts +6 -0
- package/dist/hooks/use-accordion-animation-progress.hook.js +26 -0
- package/dist/hooks/use-accordion-animation-progress.hook.js.map +1 -0
- package/dist/hooks/use-accordion-content-animation.hook.d.mts +12 -0
- package/dist/hooks/use-accordion-content-animation.hook.js +28 -0
- package/dist/hooks/use-accordion-content-animation.hook.js.map +1 -0
- package/dist/hooks/use-accordion-indicator-animation.hook.d.mts +10 -0
- package/dist/hooks/use-accordion-indicator-animation.hook.js +16 -0
- package/dist/hooks/use-accordion-indicator-animation.hook.js.map +1 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/types/accordion.types.d.mts +40 -0
- package/dist/types/accordion.types.js +1 -0
- package/dist/types/accordion.types.js.map +1 -0
- package/dist/types/index.d.mts +3 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/accordion.utils.d.mts +5 -0
- package/dist/utils/accordion.utils.js +16 -0
- package/dist/utils/accordion.utils.js.map +1 -0
- package/dist/utils/index.d.mts +1 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ImpulseUI Native contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# @impulse-ui-native/accordion
|
|
2
|
+
|
|
3
|
+
Accessible compound accordion and collapsible sections for React Native and React Native Web.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pnpm add @impulse-ui-native/accordion react-native-reanimated react-native-worklets
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Render the component inside `ThemeProvider` from `@impulse-ui-native/theme` and configure Reanimated for your host application.
|
|
12
|
+
|
|
13
|
+
## Main exports
|
|
14
|
+
|
|
15
|
+
- `Accordion.Root` manages controlled or uncontrolled single/multiple expansion.
|
|
16
|
+
- `Accordion.Item` provides an independently disabled disclosure item.
|
|
17
|
+
- `Accordion.Trigger` exposes expanded state and keyboard navigation.
|
|
18
|
+
- `Accordion.Content` animates measured height while keeping nested content mounted.
|
|
19
|
+
- Public prop types are available for every compound part.
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { Accordion } from "@impulse-ui-native/accordion";
|
|
25
|
+
import { Typography } from "@impulse-ui-native/primitives";
|
|
26
|
+
|
|
27
|
+
export function FrequentlyAskedQuestions() {
|
|
28
|
+
return (
|
|
29
|
+
<Accordion.Root defaultValue="shipping">
|
|
30
|
+
<Accordion.Item value="shipping">
|
|
31
|
+
<Accordion.Trigger>How long does shipping take?</Accordion.Trigger>
|
|
32
|
+
<Accordion.Content>
|
|
33
|
+
<Typography.Body>
|
|
34
|
+
Standard shipping normally arrives in three to five business days.
|
|
35
|
+
</Typography.Body>
|
|
36
|
+
</Accordion.Content>
|
|
37
|
+
</Accordion.Item>
|
|
38
|
+
</Accordion.Root>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Set `type="multiple"` and use string arrays for `value`, `defaultValue`, and `onValueChange` when several items may be open. Single accordions collapse an open item by default; use `collapsible={false}` when one item must remain open.
|
|
44
|
+
|
|
45
|
+
Triggers support Enter and Space activation through the native pressable behavior. Arrow Up/Down and Home/End move focus between enabled triggers. Content remains mounted during collapse, which preserves local and nested component state. Reduced-motion preferences disable the height and indicator duration.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { AccordionContentProps, AccordionItemProps, AccordionRootProps, AccordionTriggerProps } from '../types/accordion.types.mjs';
|
|
4
|
+
import 'react-native';
|
|
5
|
+
|
|
6
|
+
declare const Accordion: {
|
|
7
|
+
Content: react.MemoExoticComponent<({ children, onLayout, style, ...props }: AccordionContentProps) => react_jsx_runtime.JSX.Element>;
|
|
8
|
+
Item: react.MemoExoticComponent<({ children, disabled, style, value, ...props }: AccordionItemProps) => react_jsx_runtime.JSX.Element>;
|
|
9
|
+
Root: react.MemoExoticComponent<({ children, collapsible, defaultValue, disabled, onValueChange, style, type, value, ...props }: AccordionRootProps) => react_jsx_runtime.JSX.Element>;
|
|
10
|
+
Trigger: react.MemoExoticComponent<({ accessibilityState, onBlur, children, disabled, hideIndicator, indicator, onFocus, onKeyDown, onPress, style, ...props }: AccordionTriggerProps) => react_jsx_runtime.JSX.Element>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export { Accordion };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AccordionContent } from "./content";
|
|
2
|
+
import { AccordionItem } from "./item";
|
|
3
|
+
import { AccordionRoot } from "./root";
|
|
4
|
+
import { AccordionTrigger } from "./trigger";
|
|
5
|
+
const Accordion = {
|
|
6
|
+
Content: AccordionContent,
|
|
7
|
+
Item: AccordionItem,
|
|
8
|
+
Root: AccordionRoot,
|
|
9
|
+
Trigger: AccordionTrigger
|
|
10
|
+
};
|
|
11
|
+
export {
|
|
12
|
+
Accordion
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=accordion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/accordion.ts"],"sourcesContent":["import { AccordionContent } from \"./content\";\nimport { AccordionItem } from \"./item\";\nimport { AccordionRoot } from \"./root\";\nimport { AccordionTrigger } from \"./trigger\";\n\nexport const Accordion = {\n Content: AccordionContent,\n Item: AccordionItem,\n Root: AccordionRoot,\n Trigger: AccordionTrigger,\n};\n"],"mappings":"AAAA,SAAS,wBAAwB;AACjC,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AAE1B,MAAM,YAAY;AAAA,EACvB,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AACX;","names":[]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { AccordionContentProps } from '../types/accordion.types.mjs';
|
|
4
|
+
import 'react-native';
|
|
5
|
+
|
|
6
|
+
declare const AccordionContent: react.MemoExoticComponent<({ children, onLayout, style, ...props }: AccordionContentProps) => react_jsx_runtime.JSX.Element>;
|
|
7
|
+
|
|
8
|
+
export { AccordionContent };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { memo, useMemo } from "react";
|
|
3
|
+
import { StyleSheet } from "react-native";
|
|
4
|
+
import Animated from "react-native-reanimated";
|
|
5
|
+
import { useEventCallback } from "@impulse-ui-native/core";
|
|
6
|
+
import { View } from "@impulse-ui-native/primitives";
|
|
7
|
+
import { useComponentsTokens } from "@impulse-ui-native/theme";
|
|
8
|
+
import { useAccordionItemContext } from "../contexts";
|
|
9
|
+
import { useAccordionContentAnimation } from "../hooks";
|
|
10
|
+
const AccordionContent = memo(function AccordionContent2({
|
|
11
|
+
children,
|
|
12
|
+
onLayout,
|
|
13
|
+
style,
|
|
14
|
+
...props
|
|
15
|
+
}) {
|
|
16
|
+
const item = useAccordionItemContext();
|
|
17
|
+
const tokens = useComponentsTokens().accordion;
|
|
18
|
+
const { contentStyle, setContentHeight } = useAccordionContentAnimation({
|
|
19
|
+
duration: tokens.animationDuration,
|
|
20
|
+
open: item.open
|
|
21
|
+
});
|
|
22
|
+
const viewportStyle = useMemo(
|
|
23
|
+
() => [styles.viewport, contentStyle],
|
|
24
|
+
[contentStyle]
|
|
25
|
+
);
|
|
26
|
+
const innerStyle = useMemo(
|
|
27
|
+
() => [
|
|
28
|
+
styles.content,
|
|
29
|
+
{
|
|
30
|
+
paddingBottom: tokens.content.paddingBottom,
|
|
31
|
+
paddingHorizontal: tokens.content.paddingHorizontal
|
|
32
|
+
},
|
|
33
|
+
style
|
|
34
|
+
],
|
|
35
|
+
[style, tokens.content.paddingBottom, tokens.content.paddingHorizontal]
|
|
36
|
+
);
|
|
37
|
+
const handleLayout = useEventCallback((event) => {
|
|
38
|
+
setContentHeight(event.nativeEvent.layout.height);
|
|
39
|
+
onLayout?.(event);
|
|
40
|
+
});
|
|
41
|
+
return /* @__PURE__ */ jsx(
|
|
42
|
+
Animated.View,
|
|
43
|
+
{
|
|
44
|
+
"aria-hidden": !item.open,
|
|
45
|
+
accessibilityElementsHidden: !item.open,
|
|
46
|
+
importantForAccessibility: item.open ? "auto" : "no-hide-descendants",
|
|
47
|
+
pointerEvents: item.open ? "auto" : "none",
|
|
48
|
+
style: viewportStyle,
|
|
49
|
+
children: /* @__PURE__ */ jsx(
|
|
50
|
+
View,
|
|
51
|
+
{
|
|
52
|
+
...props,
|
|
53
|
+
"aria-labelledby": item.triggerId,
|
|
54
|
+
accessibilityLabelledBy: item.triggerId,
|
|
55
|
+
nativeID: item.contentId,
|
|
56
|
+
onLayout: handleLayout,
|
|
57
|
+
style: innerStyle,
|
|
58
|
+
children
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
const styles = StyleSheet.create({
|
|
65
|
+
content: {
|
|
66
|
+
left: 0,
|
|
67
|
+
position: "absolute",
|
|
68
|
+
right: 0,
|
|
69
|
+
top: 0
|
|
70
|
+
},
|
|
71
|
+
viewport: {
|
|
72
|
+
overflow: "hidden"
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
export {
|
|
76
|
+
AccordionContent
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/content.tsx"],"sourcesContent":["import type { LayoutChangeEvent } from \"react-native\";\nimport { memo, useMemo } from \"react\";\nimport { StyleSheet } from \"react-native\";\nimport Animated from \"react-native-reanimated\";\n\nimport { useEventCallback } from \"@impulse-ui-native/core\";\nimport { View } from \"@impulse-ui-native/primitives\";\nimport { useComponentsTokens } from \"@impulse-ui-native/theme\";\n\nimport type { AccordionContentProps } from \"../types\";\nimport { useAccordionItemContext } from \"../contexts\";\nimport { useAccordionContentAnimation } from \"../hooks\";\n\nexport const AccordionContent = memo(function AccordionContent({\n children,\n onLayout,\n style,\n ...props\n}: AccordionContentProps) {\n const item = useAccordionItemContext();\n const tokens = useComponentsTokens().accordion;\n const { contentStyle, setContentHeight } = useAccordionContentAnimation({\n duration: tokens.animationDuration,\n open: item.open,\n });\n\n const viewportStyle = useMemo(\n () => [styles.viewport, contentStyle],\n [contentStyle],\n );\n const innerStyle = useMemo(\n () => [\n styles.content,\n {\n paddingBottom: tokens.content.paddingBottom,\n paddingHorizontal: tokens.content.paddingHorizontal,\n },\n style,\n ],\n [style, tokens.content.paddingBottom, tokens.content.paddingHorizontal],\n );\n\n const handleLayout = useEventCallback((event: LayoutChangeEvent) => {\n setContentHeight(event.nativeEvent.layout.height);\n onLayout?.(event);\n });\n\n return (\n <Animated.View\n aria-hidden={!item.open}\n accessibilityElementsHidden={!item.open}\n importantForAccessibility={item.open ? \"auto\" : \"no-hide-descendants\"}\n pointerEvents={item.open ? \"auto\" : \"none\"}\n style={viewportStyle}\n >\n <View\n {...props}\n aria-labelledby={item.triggerId}\n accessibilityLabelledBy={item.triggerId}\n nativeID={item.contentId}\n onLayout={handleLayout}\n style={innerStyle}\n >\n {children}\n </View>\n </Animated.View>\n );\n});\n\nconst styles = StyleSheet.create({\n content: {\n left: 0,\n position: \"absolute\",\n right: 0,\n top: 0,\n },\n viewport: {\n overflow: \"hidden\",\n },\n});\n"],"mappings":"AAuDM;AAtDN,SAAS,MAAM,eAAe;AAC9B,SAAS,kBAAkB;AAC3B,OAAO,cAAc;AAErB,SAAS,wBAAwB;AACjC,SAAS,YAAY;AACrB,SAAS,2BAA2B;AAGpC,SAAS,+BAA+B;AACxC,SAAS,oCAAoC;AAEtC,MAAM,mBAAmB,KAAK,SAASA,kBAAiB;AAAA,EAC7D;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA0B;AACxB,QAAM,OAAO,wBAAwB;AACrC,QAAM,SAAS,oBAAoB,EAAE;AACrC,QAAM,EAAE,cAAc,iBAAiB,IAAI,6BAA6B;AAAA,IACtE,UAAU,OAAO;AAAA,IACjB,MAAM,KAAK;AAAA,EACb,CAAC;AAED,QAAM,gBAAgB;AAAA,IACpB,MAAM,CAAC,OAAO,UAAU,YAAY;AAAA,IACpC,CAAC,YAAY;AAAA,EACf;AACA,QAAM,aAAa;AAAA,IACjB,MAAM;AAAA,MACJ,OAAO;AAAA,MACP;AAAA,QACE,eAAe,OAAO,QAAQ;AAAA,QAC9B,mBAAmB,OAAO,QAAQ;AAAA,MACpC;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,OAAO,OAAO,QAAQ,eAAe,OAAO,QAAQ,iBAAiB;AAAA,EACxE;AAEA,QAAM,eAAe,iBAAiB,CAAC,UAA6B;AAClE,qBAAiB,MAAM,YAAY,OAAO,MAAM;AAChD,eAAW,KAAK;AAAA,EAClB,CAAC;AAED,SACE;AAAA,IAAC,SAAS;AAAA,IAAT;AAAA,MACC,eAAa,CAAC,KAAK;AAAA,MACnB,6BAA6B,CAAC,KAAK;AAAA,MACnC,2BAA2B,KAAK,OAAO,SAAS;AAAA,MAChD,eAAe,KAAK,OAAO,SAAS;AAAA,MACpC,OAAO;AAAA,MAEP;AAAA,QAAC;AAAA;AAAA,UACE,GAAG;AAAA,UACJ,mBAAiB,KAAK;AAAA,UACtB,yBAAyB,KAAK;AAAA,UAC9B,UAAU,KAAK;AAAA,UACf,UAAU;AAAA,UACV,OAAO;AAAA,UAEN;AAAA;AAAA,MACH;AAAA;AAAA,EACF;AAEJ,CAAC;AAED,MAAM,SAAS,WAAW,OAAO;AAAA,EAC/B,SAAS;AAAA,IACP,MAAM;AAAA,IACN,UAAU;AAAA,IACV,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,UAAU;AAAA,IACR,UAAU;AAAA,EACZ;AACF,CAAC;","names":["AccordionContent"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/index.ts"],"sourcesContent":["export { Accordion } from \"./accordion\";\n"],"mappings":"AAAA,SAAS,iBAAiB;","names":[]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { AccordionItemProps } from '../types/accordion.types.mjs';
|
|
4
|
+
import 'react-native';
|
|
5
|
+
|
|
6
|
+
declare const AccordionItem: react.MemoExoticComponent<({ children, disabled, style, value, ...props }: AccordionItemProps) => react_jsx_runtime.JSX.Element>;
|
|
7
|
+
|
|
8
|
+
export { AccordionItem };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { memo, useId, useMemo } from "react";
|
|
3
|
+
import { View } from "@impulse-ui-native/primitives";
|
|
4
|
+
import { useComponentsTokens } from "@impulse-ui-native/theme";
|
|
5
|
+
import { AccordionItemProvider, useAccordionContext } from "../contexts";
|
|
6
|
+
const AccordionItem = memo(function AccordionItem2({
|
|
7
|
+
children,
|
|
8
|
+
disabled = false,
|
|
9
|
+
style,
|
|
10
|
+
value,
|
|
11
|
+
...props
|
|
12
|
+
}) {
|
|
13
|
+
const accordion = useAccordionContext();
|
|
14
|
+
const tokens = useComponentsTokens().accordion;
|
|
15
|
+
const reactId = useId().replaceAll(":", "");
|
|
16
|
+
const resolvedDisabled = accordion.disabled || disabled;
|
|
17
|
+
const open = accordion.expandedValues.includes(value);
|
|
18
|
+
const context = useMemo(
|
|
19
|
+
() => ({
|
|
20
|
+
contentId: `accordion-content-${reactId}`,
|
|
21
|
+
disabled: resolvedDisabled,
|
|
22
|
+
open,
|
|
23
|
+
triggerId: `accordion-trigger-${reactId}`,
|
|
24
|
+
value
|
|
25
|
+
}),
|
|
26
|
+
[open, reactId, resolvedDisabled, value]
|
|
27
|
+
);
|
|
28
|
+
const itemStyle = useMemo(
|
|
29
|
+
() => [{ backgroundColor: tokens.backgroundColor }, style],
|
|
30
|
+
[style, tokens.backgroundColor]
|
|
31
|
+
);
|
|
32
|
+
return /* @__PURE__ */ jsx(AccordionItemProvider, { value: context, children: /* @__PURE__ */ jsx(View, { ...props, style: itemStyle, children }) });
|
|
33
|
+
});
|
|
34
|
+
export {
|
|
35
|
+
AccordionItem
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=item.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/item.tsx"],"sourcesContent":["import { memo, useId, useMemo } from \"react\";\n\nimport { View } from \"@impulse-ui-native/primitives\";\nimport { useComponentsTokens } from \"@impulse-ui-native/theme\";\n\nimport type { AccordionItemContextData } from \"../contexts\";\nimport type { AccordionItemProps } from \"../types\";\nimport { AccordionItemProvider, useAccordionContext } from \"../contexts\";\n\nexport const AccordionItem = memo(function AccordionItem({\n children,\n disabled = false,\n style,\n value,\n ...props\n}: AccordionItemProps) {\n const accordion = useAccordionContext();\n const tokens = useComponentsTokens().accordion;\n const reactId = useId().replaceAll(\":\", \"\");\n const resolvedDisabled = accordion.disabled || disabled;\n const open = accordion.expandedValues.includes(value);\n\n const context = useMemo<AccordionItemContextData>(\n () => ({\n contentId: `accordion-content-${reactId}`,\n disabled: resolvedDisabled,\n open,\n triggerId: `accordion-trigger-${reactId}`,\n value,\n }),\n [open, reactId, resolvedDisabled, value],\n );\n const itemStyle = useMemo(\n () => [{ backgroundColor: tokens.backgroundColor }, style],\n [style, tokens.backgroundColor],\n );\n\n return (\n <AccordionItemProvider value={context}>\n <View {...props} style={itemStyle}>\n {children}\n </View>\n </AccordionItemProvider>\n );\n});\n"],"mappings":"AAuCM;AAvCN,SAAS,MAAM,OAAO,eAAe;AAErC,SAAS,YAAY;AACrB,SAAS,2BAA2B;AAIpC,SAAS,uBAAuB,2BAA2B;AAEpD,MAAM,gBAAgB,KAAK,SAASA,eAAc;AAAA,EACvD;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAuB;AACrB,QAAM,YAAY,oBAAoB;AACtC,QAAM,SAAS,oBAAoB,EAAE;AACrC,QAAM,UAAU,MAAM,EAAE,WAAW,KAAK,EAAE;AAC1C,QAAM,mBAAmB,UAAU,YAAY;AAC/C,QAAM,OAAO,UAAU,eAAe,SAAS,KAAK;AAEpD,QAAM,UAAU;AAAA,IACd,OAAO;AAAA,MACL,WAAW,qBAAqB,OAAO;AAAA,MACvC,UAAU;AAAA,MACV;AAAA,MACA,WAAW,qBAAqB,OAAO;AAAA,MACvC;AAAA,IACF;AAAA,IACA,CAAC,MAAM,SAAS,kBAAkB,KAAK;AAAA,EACzC;AACA,QAAM,YAAY;AAAA,IAChB,MAAM,CAAC,EAAE,iBAAiB,OAAO,gBAAgB,GAAG,KAAK;AAAA,IACzD,CAAC,OAAO,OAAO,eAAe;AAAA,EAChC;AAEA,SACE,oBAAC,yBAAsB,OAAO,SAC5B,8BAAC,QAAM,GAAG,OAAO,OAAO,WACrB,UACH,GACF;AAEJ,CAAC;","names":["AccordionItem"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { AccordionRootProps } from '../types/accordion.types.mjs';
|
|
4
|
+
import 'react-native';
|
|
5
|
+
|
|
6
|
+
declare const AccordionRoot: react.MemoExoticComponent<({ children, collapsible, defaultValue, disabled, onValueChange, style, type, value, ...props }: AccordionRootProps) => react_jsx_runtime.JSX.Element>;
|
|
7
|
+
|
|
8
|
+
export { AccordionRoot };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { memo, useCallback, useMemo, useRef } from "react";
|
|
3
|
+
import { StyleSheet } from "react-native";
|
|
4
|
+
import {
|
|
5
|
+
useControllableState,
|
|
6
|
+
useEventCallback
|
|
7
|
+
} from "@impulse-ui-native/core";
|
|
8
|
+
import { View } from "@impulse-ui-native/primitives";
|
|
9
|
+
import { useComponentsTokens } from "@impulse-ui-native/theme";
|
|
10
|
+
import { AccordionProvider } from "../contexts";
|
|
11
|
+
import { normalizeAccordionValue } from "../utils";
|
|
12
|
+
const AccordionRoot = memo(function AccordionRoot2({
|
|
13
|
+
children,
|
|
14
|
+
collapsible = true,
|
|
15
|
+
defaultValue,
|
|
16
|
+
disabled = false,
|
|
17
|
+
onValueChange,
|
|
18
|
+
style,
|
|
19
|
+
type = "single",
|
|
20
|
+
value,
|
|
21
|
+
...props
|
|
22
|
+
}) {
|
|
23
|
+
const tokens = useComponentsTokens().accordion;
|
|
24
|
+
const triggerRegistry = useRef([]);
|
|
25
|
+
const notifyValueChange = useEventCallback(
|
|
26
|
+
(nextValues) => {
|
|
27
|
+
if (type === "multiple") {
|
|
28
|
+
onValueChange?.([
|
|
29
|
+
...nextValues
|
|
30
|
+
]);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
onValueChange?.(
|
|
34
|
+
nextValues[0]
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
const normalizedValue = useMemo(
|
|
39
|
+
() => value === void 0 ? void 0 : normalizeAccordionValue(value),
|
|
40
|
+
[value]
|
|
41
|
+
);
|
|
42
|
+
const normalizedDefaultValue = useMemo(
|
|
43
|
+
() => normalizeAccordionValue(defaultValue),
|
|
44
|
+
[defaultValue]
|
|
45
|
+
);
|
|
46
|
+
const [expandedValues, setExpandedValues] = useControllableState({
|
|
47
|
+
prop: normalizedValue,
|
|
48
|
+
defaultProp: normalizedDefaultValue,
|
|
49
|
+
onChange: notifyValueChange
|
|
50
|
+
});
|
|
51
|
+
const registerTrigger = useCallback((registration) => {
|
|
52
|
+
triggerRegistry.current = [...triggerRegistry.current, registration];
|
|
53
|
+
return () => {
|
|
54
|
+
triggerRegistry.current = triggerRegistry.current.filter(
|
|
55
|
+
(candidate) => candidate !== registration
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
}, []);
|
|
59
|
+
const focusTrigger = useCallback(
|
|
60
|
+
(currentValue, direction) => {
|
|
61
|
+
const enabledTriggers = triggerRegistry.current.filter(
|
|
62
|
+
(trigger) => !trigger.disabled
|
|
63
|
+
);
|
|
64
|
+
const currentIndex = enabledTriggers.findIndex(
|
|
65
|
+
(trigger) => trigger.value === currentValue
|
|
66
|
+
);
|
|
67
|
+
if (enabledTriggers.length === 0) return;
|
|
68
|
+
let nextIndex = currentIndex;
|
|
69
|
+
if (direction === "first") nextIndex = 0;
|
|
70
|
+
if (direction === "last") nextIndex = enabledTriggers.length - 1;
|
|
71
|
+
if (direction === "next") {
|
|
72
|
+
nextIndex = (currentIndex + 1) % enabledTriggers.length;
|
|
73
|
+
}
|
|
74
|
+
if (direction === "previous") {
|
|
75
|
+
nextIndex = (currentIndex - 1 + enabledTriggers.length) % enabledTriggers.length;
|
|
76
|
+
}
|
|
77
|
+
enabledTriggers[nextIndex]?.ref.current?.focus();
|
|
78
|
+
},
|
|
79
|
+
[]
|
|
80
|
+
);
|
|
81
|
+
const toggleItem = useCallback(
|
|
82
|
+
(itemValue) => {
|
|
83
|
+
setExpandedValues((currentValues) => {
|
|
84
|
+
const isOpen = currentValues.includes(itemValue);
|
|
85
|
+
if (type === "multiple") {
|
|
86
|
+
return isOpen ? currentValues.filter((current) => current !== itemValue) : [...currentValues, itemValue];
|
|
87
|
+
}
|
|
88
|
+
if (isOpen) {
|
|
89
|
+
return collapsible ? [] : currentValues;
|
|
90
|
+
}
|
|
91
|
+
return [itemValue];
|
|
92
|
+
});
|
|
93
|
+
},
|
|
94
|
+
[collapsible, setExpandedValues, type]
|
|
95
|
+
);
|
|
96
|
+
const context = useMemo(
|
|
97
|
+
() => ({
|
|
98
|
+
disabled,
|
|
99
|
+
expandedValues,
|
|
100
|
+
focusTrigger,
|
|
101
|
+
registerTrigger,
|
|
102
|
+
toggleItem
|
|
103
|
+
}),
|
|
104
|
+
[disabled, expandedValues, focusTrigger, registerTrigger, toggleItem]
|
|
105
|
+
);
|
|
106
|
+
const rootStyle = useMemo(
|
|
107
|
+
() => [
|
|
108
|
+
styles.root,
|
|
109
|
+
{
|
|
110
|
+
backgroundColor: tokens.dividerColor,
|
|
111
|
+
borderColor: tokens.borderColor,
|
|
112
|
+
borderRadius: tokens.borderRadius,
|
|
113
|
+
borderWidth: tokens.borderWidth,
|
|
114
|
+
gap: tokens.dividerWidth
|
|
115
|
+
},
|
|
116
|
+
style
|
|
117
|
+
],
|
|
118
|
+
[style, tokens]
|
|
119
|
+
);
|
|
120
|
+
return /* @__PURE__ */ jsx(AccordionProvider, { value: context, children: /* @__PURE__ */ jsx(View, { ...props, style: rootStyle, children }) });
|
|
121
|
+
});
|
|
122
|
+
const styles = StyleSheet.create({
|
|
123
|
+
root: {
|
|
124
|
+
overflow: "hidden"
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
export {
|
|
128
|
+
AccordionRoot
|
|
129
|
+
};
|
|
130
|
+
//# sourceMappingURL=root.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/root.tsx"],"sourcesContent":["import { memo, useCallback, useMemo, useRef } from \"react\";\nimport { StyleSheet } from \"react-native\";\n\nimport {\n useControllableState,\n useEventCallback,\n} from \"@impulse-ui-native/core\";\nimport { View } from \"@impulse-ui-native/primitives\";\nimport { useComponentsTokens } from \"@impulse-ui-native/theme\";\n\nimport type { AccordionContextData } from \"../contexts\";\nimport type {\n AccordionMultipleRootProps,\n AccordionRootProps,\n AccordionSingleRootProps,\n} from \"../types\";\nimport { AccordionProvider } from \"../contexts\";\nimport { normalizeAccordionValue } from \"../utils\";\n\ntype TriggerRegistration = Parameters<\n AccordionContextData[\"registerTrigger\"]\n>[0];\n\nexport const AccordionRoot = memo(function AccordionRoot({\n children,\n collapsible = true,\n defaultValue,\n disabled = false,\n onValueChange,\n style,\n type = \"single\",\n value,\n ...props\n}: AccordionRootProps) {\n const tokens = useComponentsTokens().accordion;\n const triggerRegistry = useRef<TriggerRegistration[]>([]);\n\n const notifyValueChange = useEventCallback(\n (nextValues: readonly string[]) => {\n if (type === \"multiple\") {\n (onValueChange as AccordionMultipleRootProps[\"onValueChange\"])?.([\n ...nextValues,\n ]);\n return;\n }\n\n (onValueChange as AccordionSingleRootProps[\"onValueChange\"])?.(\n nextValues[0],\n );\n },\n );\n const normalizedValue = useMemo(\n () => (value === undefined ? undefined : normalizeAccordionValue(value)),\n [value],\n );\n const normalizedDefaultValue = useMemo(\n () => normalizeAccordionValue(defaultValue),\n [defaultValue],\n );\n const [expandedValues, setExpandedValues] = useControllableState<\n readonly string[]\n >({\n prop: normalizedValue,\n defaultProp: normalizedDefaultValue,\n onChange: notifyValueChange,\n });\n\n const registerTrigger = useCallback((registration: TriggerRegistration) => {\n triggerRegistry.current = [...triggerRegistry.current, registration];\n\n return () => {\n triggerRegistry.current = triggerRegistry.current.filter(\n (candidate) => candidate !== registration,\n );\n };\n }, []);\n\n const focusTrigger = useCallback<AccordionContextData[\"focusTrigger\"]>(\n (currentValue, direction) => {\n const enabledTriggers = triggerRegistry.current.filter(\n (trigger) => !trigger.disabled,\n );\n const currentIndex = enabledTriggers.findIndex(\n (trigger) => trigger.value === currentValue,\n );\n\n if (enabledTriggers.length === 0) return;\n\n let nextIndex = currentIndex;\n\n if (direction === \"first\") nextIndex = 0;\n if (direction === \"last\") nextIndex = enabledTriggers.length - 1;\n if (direction === \"next\") {\n nextIndex = (currentIndex + 1) % enabledTriggers.length;\n }\n if (direction === \"previous\") {\n nextIndex =\n (currentIndex - 1 + enabledTriggers.length) % enabledTriggers.length;\n }\n\n enabledTriggers[nextIndex]?.ref.current?.focus();\n },\n [],\n );\n\n const toggleItem = useCallback(\n (itemValue: string) => {\n setExpandedValues((currentValues) => {\n const isOpen = currentValues.includes(itemValue);\n\n if (type === \"multiple\") {\n return isOpen\n ? currentValues.filter((current) => current !== itemValue)\n : [...currentValues, itemValue];\n }\n\n if (isOpen) {\n return collapsible ? [] : currentValues;\n }\n\n return [itemValue];\n });\n },\n [collapsible, setExpandedValues, type],\n );\n\n const context = useMemo<AccordionContextData>(\n () => ({\n disabled,\n expandedValues,\n focusTrigger,\n registerTrigger,\n toggleItem,\n }),\n [disabled, expandedValues, focusTrigger, registerTrigger, toggleItem],\n );\n const rootStyle = useMemo(\n () => [\n styles.root,\n {\n backgroundColor: tokens.dividerColor,\n borderColor: tokens.borderColor,\n borderRadius: tokens.borderRadius,\n borderWidth: tokens.borderWidth,\n gap: tokens.dividerWidth,\n },\n style,\n ],\n [style, tokens],\n );\n\n return (\n <AccordionProvider value={context}>\n <View {...props} style={rootStyle}>\n {children}\n </View>\n </AccordionProvider>\n );\n});\n\nconst styles = StyleSheet.create({\n root: {\n overflow: \"hidden\",\n },\n});\n"],"mappings":"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","names":["AccordionRoot"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { AccordionTriggerProps } from '../types/accordion.types.mjs';
|
|
4
|
+
import 'react-native';
|
|
5
|
+
|
|
6
|
+
declare const AccordionTrigger: react.MemoExoticComponent<({ accessibilityState, onBlur, children, disabled, hideIndicator, indicator, onFocus, onKeyDown, onPress, style, ...props }: AccordionTriggerProps) => react_jsx_runtime.JSX.Element>;
|
|
7
|
+
|
|
8
|
+
export { AccordionTrigger };
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { Platform, StyleSheet } from "react-native";
|
|
4
|
+
import Animated from "react-native-reanimated";
|
|
5
|
+
import { useEventCallback } from "@impulse-ui-native/core";
|
|
6
|
+
import { Icon } from "@impulse-ui-native/icon/components/icon";
|
|
7
|
+
import { CaretDownIcon } from "@impulse-ui-native/icon/icons/caret-down";
|
|
8
|
+
import { Pressable, Typography, View } from "@impulse-ui-native/primitives";
|
|
9
|
+
import { useComponentsTokens } from "@impulse-ui-native/theme";
|
|
10
|
+
import { useAccordionContext, useAccordionItemContext } from "../contexts";
|
|
11
|
+
import { useAccordionIndicatorAnimation } from "../hooks";
|
|
12
|
+
import { getAccordionFocusDirection } from "../utils";
|
|
13
|
+
const AccordionTrigger = memo(function AccordionTrigger2({
|
|
14
|
+
accessibilityState,
|
|
15
|
+
onBlur,
|
|
16
|
+
children,
|
|
17
|
+
disabled,
|
|
18
|
+
hideIndicator = false,
|
|
19
|
+
indicator,
|
|
20
|
+
onFocus,
|
|
21
|
+
onKeyDown,
|
|
22
|
+
onPress,
|
|
23
|
+
style,
|
|
24
|
+
...props
|
|
25
|
+
}) {
|
|
26
|
+
const { focusTrigger, registerTrigger, toggleItem } = useAccordionContext();
|
|
27
|
+
const item = useAccordionItemContext();
|
|
28
|
+
const tokens = useComponentsTokens().accordion;
|
|
29
|
+
const [focused, setFocused] = useState(false);
|
|
30
|
+
const triggerRef = useRef(null);
|
|
31
|
+
const resolvedDisabled = item.disabled || disabled === true;
|
|
32
|
+
const indicatorStyle = useAccordionIndicatorAnimation({
|
|
33
|
+
duration: tokens.animationDuration,
|
|
34
|
+
open: item.open
|
|
35
|
+
});
|
|
36
|
+
const resolvedAccessibilityState = useMemo(
|
|
37
|
+
() => ({
|
|
38
|
+
...accessibilityState,
|
|
39
|
+
disabled: resolvedDisabled,
|
|
40
|
+
expanded: item.open
|
|
41
|
+
}),
|
|
42
|
+
[accessibilityState, item.open, resolvedDisabled]
|
|
43
|
+
);
|
|
44
|
+
const titleStyle = useMemo(
|
|
45
|
+
() => ({
|
|
46
|
+
color: resolvedDisabled ? tokens.disabledColor : tokens.titleColor
|
|
47
|
+
}),
|
|
48
|
+
[resolvedDisabled, tokens.disabledColor, tokens.titleColor]
|
|
49
|
+
);
|
|
50
|
+
const triggerStyle = useCallback(
|
|
51
|
+
({ pressed }) => [
|
|
52
|
+
styles.trigger,
|
|
53
|
+
{
|
|
54
|
+
backgroundColor: focused ? tokens.focusBackgroundColor : "transparent",
|
|
55
|
+
gap: tokens.trigger.gap,
|
|
56
|
+
minHeight: tokens.trigger.minHeight,
|
|
57
|
+
opacity: resolvedDisabled ? tokens.disabledOpacity : pressed ? tokens.pressedOpacity : 1,
|
|
58
|
+
paddingHorizontal: tokens.trigger.paddingHorizontal,
|
|
59
|
+
paddingVertical: tokens.trigger.paddingVertical
|
|
60
|
+
},
|
|
61
|
+
typeof style === "function" ? style({ pressed }) : style
|
|
62
|
+
],
|
|
63
|
+
[focused, resolvedDisabled, style, tokens]
|
|
64
|
+
);
|
|
65
|
+
const handleBlur = useEventCallback(
|
|
66
|
+
(event) => {
|
|
67
|
+
setFocused(false);
|
|
68
|
+
onBlur?.(event);
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
const handleFocus = useEventCallback(
|
|
72
|
+
(event) => {
|
|
73
|
+
setFocused(true);
|
|
74
|
+
onFocus?.(event);
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
const handlePress = useEventCallback((event) => {
|
|
78
|
+
toggleItem(item.value);
|
|
79
|
+
onPress?.(event);
|
|
80
|
+
});
|
|
81
|
+
const handleKeyDown = useEventCallback((event) => {
|
|
82
|
+
onKeyDown?.(event);
|
|
83
|
+
if (event.isDefaultPrevented()) return;
|
|
84
|
+
const direction = getAccordionFocusDirection(event.nativeEvent.key);
|
|
85
|
+
if (direction) {
|
|
86
|
+
event.preventDefault();
|
|
87
|
+
focusTrigger(item.value, direction);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
const webInteractionProps = useMemo(
|
|
91
|
+
() => Platform.OS === "web" ? {
|
|
92
|
+
"aria-controls": item.contentId,
|
|
93
|
+
onKeyDown: handleKeyDown
|
|
94
|
+
} : void 0,
|
|
95
|
+
[handleKeyDown, item.contentId]
|
|
96
|
+
);
|
|
97
|
+
useEffect(
|
|
98
|
+
() => registerTrigger({
|
|
99
|
+
disabled: resolvedDisabled,
|
|
100
|
+
ref: triggerRef,
|
|
101
|
+
value: item.value
|
|
102
|
+
}),
|
|
103
|
+
[item.value, registerTrigger, resolvedDisabled]
|
|
104
|
+
);
|
|
105
|
+
return /* @__PURE__ */ jsxs(
|
|
106
|
+
Pressable,
|
|
107
|
+
{
|
|
108
|
+
...props,
|
|
109
|
+
...webInteractionProps,
|
|
110
|
+
ref: triggerRef,
|
|
111
|
+
"aria-expanded": item.open,
|
|
112
|
+
accessibilityRole: "button",
|
|
113
|
+
accessibilityState: resolvedAccessibilityState,
|
|
114
|
+
disabled: resolvedDisabled,
|
|
115
|
+
focusable: !resolvedDisabled,
|
|
116
|
+
nativeID: item.triggerId,
|
|
117
|
+
onBlur: handleBlur,
|
|
118
|
+
onFocus: handleFocus,
|
|
119
|
+
onPress: handlePress,
|
|
120
|
+
style: triggerStyle,
|
|
121
|
+
children: [
|
|
122
|
+
/* @__PURE__ */ jsx(View, { flex: 1, pointerEvents: "none", children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsx(Typography.Label, { style: titleStyle, children }) : children }),
|
|
123
|
+
hideIndicator ? null : /* @__PURE__ */ jsx(Animated.View, { pointerEvents: "none", style: indicatorStyle, children: indicator ?? /* @__PURE__ */ jsx(
|
|
124
|
+
Icon,
|
|
125
|
+
{
|
|
126
|
+
color: resolvedDisabled ? tokens.disabledColor : tokens.iconColor,
|
|
127
|
+
icon: CaretDownIcon,
|
|
128
|
+
size: tokens.iconSize
|
|
129
|
+
}
|
|
130
|
+
) })
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
const styles = StyleSheet.create({
|
|
136
|
+
trigger: {
|
|
137
|
+
alignItems: "center",
|
|
138
|
+
flexDirection: "row",
|
|
139
|
+
justifyContent: "space-between"
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
export {
|
|
143
|
+
AccordionTrigger
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=trigger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/trigger.tsx"],"sourcesContent":["import type { ComponentRef } from \"react\";\nimport type {\n GestureResponderEvent,\n PressableProps,\n PressableStateCallbackType,\n StyleProp,\n ViewStyle,\n} from \"react-native\";\nimport { memo, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Platform, StyleSheet } from \"react-native\";\nimport Animated from \"react-native-reanimated\";\n\nimport { useEventCallback } from \"@impulse-ui-native/core\";\nimport { Icon } from \"@impulse-ui-native/icon/components/icon\";\nimport { CaretDownIcon } from \"@impulse-ui-native/icon/icons/caret-down\";\nimport { Pressable, Typography, View } from \"@impulse-ui-native/primitives\";\nimport { useComponentsTokens } from \"@impulse-ui-native/theme\";\n\nimport type { AccordionKeyDownEvent, AccordionTriggerProps } from \"../types\";\nimport { useAccordionContext, useAccordionItemContext } from \"../contexts\";\nimport { useAccordionIndicatorAnimation } from \"../hooks\";\nimport { getAccordionFocusDirection } from \"../utils\";\n\nexport const AccordionTrigger = memo(function AccordionTrigger({\n accessibilityState,\n onBlur,\n children,\n disabled,\n hideIndicator = false,\n indicator,\n onFocus,\n onKeyDown,\n onPress,\n style,\n ...props\n}: AccordionTriggerProps) {\n const { focusTrigger, registerTrigger, toggleItem } = useAccordionContext();\n const item = useAccordionItemContext();\n const tokens = useComponentsTokens().accordion;\n const [focused, setFocused] = useState(false);\n // The host ref is required for roving keyboard focus between triggers.\n const triggerRef = useRef<ComponentRef<typeof Pressable>>(null);\n const resolvedDisabled = item.disabled || disabled === true;\n const indicatorStyle = useAccordionIndicatorAnimation({\n duration: tokens.animationDuration,\n open: item.open,\n });\n\n const resolvedAccessibilityState = useMemo(\n () => ({\n ...accessibilityState,\n disabled: resolvedDisabled,\n expanded: item.open,\n }),\n [accessibilityState, item.open, resolvedDisabled],\n );\n const titleStyle = useMemo(\n () => ({\n color: resolvedDisabled ? tokens.disabledColor : tokens.titleColor,\n }),\n [resolvedDisabled, tokens.disabledColor, tokens.titleColor],\n );\n\n const triggerStyle = useCallback(\n ({ pressed }: PressableStateCallbackType): StyleProp<ViewStyle> => [\n styles.trigger,\n {\n backgroundColor: focused ? tokens.focusBackgroundColor : \"transparent\",\n gap: tokens.trigger.gap,\n minHeight: tokens.trigger.minHeight,\n opacity: resolvedDisabled\n ? tokens.disabledOpacity\n : pressed\n ? tokens.pressedOpacity\n : 1,\n paddingHorizontal: tokens.trigger.paddingHorizontal,\n paddingVertical: tokens.trigger.paddingVertical,\n },\n typeof style === \"function\" ? style({ pressed }) : style,\n ],\n [focused, resolvedDisabled, style, tokens],\n );\n\n const handleBlur = useEventCallback<NonNullable<PressableProps[\"onBlur\"]>>(\n (event) => {\n setFocused(false);\n onBlur?.(event);\n },\n );\n\n const handleFocus = useEventCallback<NonNullable<PressableProps[\"onFocus\"]>>(\n (event) => {\n setFocused(true);\n onFocus?.(event);\n },\n );\n\n const handlePress = useEventCallback((event: GestureResponderEvent) => {\n toggleItem(item.value);\n onPress?.(event);\n });\n\n const handleKeyDown = useEventCallback((event: AccordionKeyDownEvent) => {\n onKeyDown?.(event);\n\n if (event.isDefaultPrevented()) return;\n\n const direction = getAccordionFocusDirection(event.nativeEvent.key);\n\n if (direction) {\n event.preventDefault();\n focusTrigger(item.value, direction);\n }\n });\n\n const webInteractionProps = useMemo(\n () =>\n Platform.OS === \"web\"\n ? ({\n \"aria-controls\": item.contentId,\n onKeyDown: handleKeyDown,\n } as PressableProps)\n : undefined,\n [handleKeyDown, item.contentId],\n );\n\n useEffect(\n () =>\n registerTrigger({\n disabled: resolvedDisabled,\n ref: triggerRef,\n value: item.value,\n }),\n [item.value, registerTrigger, resolvedDisabled],\n );\n\n return (\n <Pressable\n {...props}\n {...webInteractionProps}\n ref={triggerRef}\n aria-expanded={item.open}\n accessibilityRole=\"button\"\n accessibilityState={resolvedAccessibilityState}\n disabled={resolvedDisabled}\n focusable={!resolvedDisabled}\n nativeID={item.triggerId}\n onBlur={handleBlur}\n onFocus={handleFocus}\n onPress={handlePress}\n style={triggerStyle}\n >\n <View flex={1} pointerEvents=\"none\">\n {typeof children === \"string\" || typeof children === \"number\" ? (\n <Typography.Label style={titleStyle}>{children}</Typography.Label>\n ) : (\n children\n )}\n </View>\n\n {hideIndicator ? null : (\n <Animated.View pointerEvents=\"none\" style={indicatorStyle}>\n {indicator ?? (\n <Icon\n color={resolvedDisabled ? tokens.disabledColor : tokens.iconColor}\n icon={CaretDownIcon}\n size={tokens.iconSize}\n />\n )}\n </Animated.View>\n )}\n </Pressable>\n );\n});\n\nconst styles = StyleSheet.create({\n trigger: {\n alignItems: \"center\",\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n },\n});\n"],"mappings":"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","names":["AccordionTrigger"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { RefObject, ComponentRef } from 'react';
|
|
3
|
+
import { Pressable } from '@impulse-ui-native/primitives';
|
|
4
|
+
import { AccordionFocusDirection } from '../utils/accordion.utils.mjs';
|
|
5
|
+
|
|
6
|
+
interface AccordionTriggerRegistration {
|
|
7
|
+
disabled: boolean;
|
|
8
|
+
ref: RefObject<ComponentRef<typeof Pressable> | null>;
|
|
9
|
+
value: string;
|
|
10
|
+
}
|
|
11
|
+
interface AccordionContextData {
|
|
12
|
+
disabled: boolean;
|
|
13
|
+
expandedValues: readonly string[];
|
|
14
|
+
focusTrigger: (value: string, direction: AccordionFocusDirection) => void;
|
|
15
|
+
registerTrigger: (registration: AccordionTriggerRegistration) => () => void;
|
|
16
|
+
toggleItem: (value: string) => void;
|
|
17
|
+
}
|
|
18
|
+
interface AccordionItemContextData {
|
|
19
|
+
contentId: string;
|
|
20
|
+
disabled: boolean;
|
|
21
|
+
open: boolean;
|
|
22
|
+
triggerId: string;
|
|
23
|
+
value: string;
|
|
24
|
+
}
|
|
25
|
+
declare const AccordionProvider: react.Provider<AccordionContextData | undefined>;
|
|
26
|
+
declare const AccordionItemProvider: react.Provider<AccordionItemContextData | undefined>;
|
|
27
|
+
declare function useAccordionContext(): AccordionContextData;
|
|
28
|
+
declare function useAccordionItemContext(): AccordionItemContextData;
|
|
29
|
+
|
|
30
|
+
export { type AccordionContextData, type AccordionItemContextData, AccordionItemProvider, AccordionProvider, useAccordionContext, useAccordionItemContext };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
const AccordionContext = createContext(
|
|
3
|
+
void 0
|
|
4
|
+
);
|
|
5
|
+
const AccordionItemContext = createContext(void 0);
|
|
6
|
+
const AccordionProvider = AccordionContext.Provider;
|
|
7
|
+
const AccordionItemProvider = AccordionItemContext.Provider;
|
|
8
|
+
function useAccordionContext() {
|
|
9
|
+
const context = useContext(AccordionContext);
|
|
10
|
+
if (!context) {
|
|
11
|
+
throw new Error("Accordion parts must be used within Accordion.Root");
|
|
12
|
+
}
|
|
13
|
+
return context;
|
|
14
|
+
}
|
|
15
|
+
function useAccordionItemContext() {
|
|
16
|
+
const context = useContext(AccordionItemContext);
|
|
17
|
+
if (!context) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
"Accordion.Trigger and Accordion.Content must be used within Accordion.Item"
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
return context;
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
AccordionItemProvider,
|
|
26
|
+
AccordionProvider,
|
|
27
|
+
useAccordionContext,
|
|
28
|
+
useAccordionItemContext
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=accordion.context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/contexts/accordion.context.ts"],"sourcesContent":["import type { ComponentRef, RefObject } from \"react\";\nimport { createContext, useContext } from \"react\";\n\nimport type { Pressable } from \"@impulse-ui-native/primitives\";\n\nimport type { AccordionFocusDirection } from \"../utils\";\n\ninterface AccordionTriggerRegistration {\n disabled: boolean;\n ref: RefObject<ComponentRef<typeof Pressable> | null>;\n value: string;\n}\n\nexport interface AccordionContextData {\n disabled: boolean;\n expandedValues: readonly string[];\n focusTrigger: (value: string, direction: AccordionFocusDirection) => void;\n registerTrigger: (registration: AccordionTriggerRegistration) => () => void;\n toggleItem: (value: string) => void;\n}\n\nexport interface AccordionItemContextData {\n contentId: string;\n disabled: boolean;\n open: boolean;\n triggerId: string;\n value: string;\n}\n\nconst AccordionContext = createContext<AccordionContextData | undefined>(\n undefined,\n);\nconst AccordionItemContext = createContext<\n AccordionItemContextData | undefined\n>(undefined);\n\nexport const AccordionProvider = AccordionContext.Provider;\nexport const AccordionItemProvider = AccordionItemContext.Provider;\n\nexport function useAccordionContext() {\n const context = useContext(AccordionContext);\n\n if (!context) {\n throw new Error(\"Accordion parts must be used within Accordion.Root\");\n }\n\n return context;\n}\n\nexport function useAccordionItemContext() {\n const context = useContext(AccordionItemContext);\n\n if (!context) {\n throw new Error(\n \"Accordion.Trigger and Accordion.Content must be used within Accordion.Item\",\n );\n }\n\n return context;\n}\n"],"mappings":"AACA,SAAS,eAAe,kBAAkB;AA4B1C,MAAM,mBAAmB;AAAA,EACvB;AACF;AACA,MAAM,uBAAuB,cAE3B,MAAS;AAEJ,MAAM,oBAAoB,iBAAiB;AAC3C,MAAM,wBAAwB,qBAAqB;AAEnD,SAAS,sBAAsB;AACpC,QAAM,UAAU,WAAW,gBAAgB;AAE3C,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AAEA,SAAO;AACT;AAEO,SAAS,0BAA0B;AACxC,QAAM,UAAU,WAAW,oBAAoB;AAE/C,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { AccordionContextData, AccordionItemContextData, AccordionItemProvider, AccordionProvider, useAccordionContext, useAccordionItemContext } from './accordion.context.mjs';
|
|
2
|
+
import 'react';
|
|
3
|
+
import '@impulse-ui-native/primitives';
|
|
4
|
+
import '../utils/accordion.utils.mjs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/contexts/index.ts"],"sourcesContent":["export * from \"./accordion.context\";\n"],"mappings":"AAAA,cAAc;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=accordion-animation.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { useAccordionAnimationProgress } from './use-accordion-animation-progress.hook.mjs';
|
|
2
|
+
export { useAccordionContentAnimation } from './use-accordion-content-animation.hook.mjs';
|
|
3
|
+
export { useAccordionIndicatorAnimation } from './use-accordion-indicator-animation.hook.mjs';
|
|
4
|
+
import 'react-native-reanimated';
|
|
5
|
+
import './accordion-animation.types.mjs';
|
|
6
|
+
import 'react-native-reanimated/lib/typescript/hook/commonTypes';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/index.ts"],"sourcesContent":["export * from \"./use-accordion-animation-progress.hook\";\nexport * from \"./use-accordion-content-animation.hook\";\nexport * from \"./use-accordion-indicator-animation.hook\";\n"],"mappings":"AAAA,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as react_native_reanimated from 'react-native-reanimated';
|
|
2
|
+
import { AccordionAnimationOptions } from './accordion-animation.types.mjs';
|
|
3
|
+
|
|
4
|
+
declare function useAccordionAnimationProgress({ duration, open, }: AccordionAnimationOptions): react_native_reanimated.SharedValue<number>;
|
|
5
|
+
|
|
6
|
+
export { useAccordionAnimationProgress };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Easing,
|
|
4
|
+
useReducedMotion,
|
|
5
|
+
useSharedValue,
|
|
6
|
+
withTiming
|
|
7
|
+
} from "react-native-reanimated";
|
|
8
|
+
const accordionEasing = Easing.out(Easing.cubic);
|
|
9
|
+
function useAccordionAnimationProgress({
|
|
10
|
+
duration,
|
|
11
|
+
open
|
|
12
|
+
}) {
|
|
13
|
+
const reduceMotion = useReducedMotion();
|
|
14
|
+
const progress = useSharedValue(open ? 1 : 0);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
progress.value = withTiming(open ? 1 : 0, {
|
|
17
|
+
duration: reduceMotion ? 0 : duration,
|
|
18
|
+
easing: accordionEasing
|
|
19
|
+
});
|
|
20
|
+
}, [duration, open, progress, reduceMotion]);
|
|
21
|
+
return progress;
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
useAccordionAnimationProgress
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=use-accordion-animation-progress.hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/use-accordion-animation-progress.hook.ts"],"sourcesContent":["import { useEffect } from \"react\";\nimport {\n Easing,\n useReducedMotion,\n useSharedValue,\n withTiming,\n} from \"react-native-reanimated\";\n\nimport type { AccordionAnimationOptions } from \"./accordion-animation.types\";\n\nconst accordionEasing = Easing.out(Easing.cubic);\n\nexport function useAccordionAnimationProgress({\n duration,\n open,\n}: AccordionAnimationOptions) {\n const reduceMotion = useReducedMotion();\n const progress = useSharedValue(open ? 1 : 0);\n\n useEffect(() => {\n progress.value = withTiming(open ? 1 : 0, {\n duration: reduceMotion ? 0 : duration,\n easing: accordionEasing,\n });\n }, [duration, open, progress, reduceMotion]);\n\n return progress;\n}\n"],"mappings":"AAAA,SAAS,iBAAiB;AAC1B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAIP,MAAM,kBAAkB,OAAO,IAAI,OAAO,KAAK;AAExC,SAAS,8BAA8B;AAAA,EAC5C;AAAA,EACA;AACF,GAA8B;AAC5B,QAAM,eAAe,iBAAiB;AACtC,QAAM,WAAW,eAAe,OAAO,IAAI,CAAC;AAE5C,YAAU,MAAM;AACd,aAAS,QAAQ,WAAW,OAAO,IAAI,GAAG;AAAA,MACxC,UAAU,eAAe,IAAI;AAAA,MAC7B,QAAQ;AAAA,IACV,CAAC;AAAA,EACH,GAAG,CAAC,UAAU,MAAM,UAAU,YAAY,CAAC;AAE3C,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as react_native_reanimated_lib_typescript_hook_commonTypes from 'react-native-reanimated/lib/typescript/hook/commonTypes';
|
|
2
|
+
import { AccordionAnimationOptions } from './accordion-animation.types.mjs';
|
|
3
|
+
|
|
4
|
+
declare function useAccordionContentAnimation({ duration, open, }: AccordionAnimationOptions): {
|
|
5
|
+
contentStyle: react_native_reanimated_lib_typescript_hook_commonTypes.AnimatedStyleHandle<{
|
|
6
|
+
height: number;
|
|
7
|
+
opacity: number;
|
|
8
|
+
}>;
|
|
9
|
+
setContentHeight: (height: number) => void;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export { useAccordionContentAnimation };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useCallback, useMemo } from "react";
|
|
2
|
+
import { useAnimatedStyle, useSharedValue } from "react-native-reanimated";
|
|
3
|
+
import { useAccordionAnimationProgress } from "./use-accordion-animation-progress.hook";
|
|
4
|
+
function useAccordionContentAnimation({
|
|
5
|
+
duration,
|
|
6
|
+
open
|
|
7
|
+
}) {
|
|
8
|
+
const measuredHeight = useSharedValue(0);
|
|
9
|
+
const progress = useAccordionAnimationProgress({ duration, open });
|
|
10
|
+
const contentStyle = useAnimatedStyle(() => ({
|
|
11
|
+
height: measuredHeight.value * progress.value,
|
|
12
|
+
opacity: progress.value
|
|
13
|
+
}));
|
|
14
|
+
const setContentHeight = useCallback(
|
|
15
|
+
(height) => {
|
|
16
|
+
measuredHeight.value = height;
|
|
17
|
+
},
|
|
18
|
+
[measuredHeight]
|
|
19
|
+
);
|
|
20
|
+
return useMemo(
|
|
21
|
+
() => ({ contentStyle, setContentHeight }),
|
|
22
|
+
[contentStyle, setContentHeight]
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
useAccordionContentAnimation
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=use-accordion-content-animation.hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/use-accordion-content-animation.hook.ts"],"sourcesContent":["import { useCallback, useMemo } from \"react\";\nimport { useAnimatedStyle, useSharedValue } from \"react-native-reanimated\";\n\nimport type { AccordionAnimationOptions } from \"./accordion-animation.types\";\nimport { useAccordionAnimationProgress } from \"./use-accordion-animation-progress.hook\";\n\nexport function useAccordionContentAnimation({\n duration,\n open,\n}: AccordionAnimationOptions) {\n const measuredHeight = useSharedValue(0);\n const progress = useAccordionAnimationProgress({ duration, open });\n\n const contentStyle = useAnimatedStyle(() => ({\n height: measuredHeight.value * progress.value,\n opacity: progress.value,\n }));\n\n const setContentHeight = useCallback(\n (height: number) => {\n measuredHeight.value = height;\n },\n [measuredHeight],\n );\n\n return useMemo(\n () => ({ contentStyle, setContentHeight }),\n [contentStyle, setContentHeight],\n );\n}\n"],"mappings":"AAAA,SAAS,aAAa,eAAe;AACrC,SAAS,kBAAkB,sBAAsB;AAGjD,SAAS,qCAAqC;AAEvC,SAAS,6BAA6B;AAAA,EAC3C;AAAA,EACA;AACF,GAA8B;AAC5B,QAAM,iBAAiB,eAAe,CAAC;AACvC,QAAM,WAAW,8BAA8B,EAAE,UAAU,KAAK,CAAC;AAEjE,QAAM,eAAe,iBAAiB,OAAO;AAAA,IAC3C,QAAQ,eAAe,QAAQ,SAAS;AAAA,IACxC,SAAS,SAAS;AAAA,EACpB,EAAE;AAEF,QAAM,mBAAmB;AAAA,IACvB,CAAC,WAAmB;AAClB,qBAAe,QAAQ;AAAA,IACzB;AAAA,IACA,CAAC,cAAc;AAAA,EACjB;AAEA,SAAO;AAAA,IACL,OAAO,EAAE,cAAc,iBAAiB;AAAA,IACxC,CAAC,cAAc,gBAAgB;AAAA,EACjC;AACF;","names":[]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as react_native_reanimated_lib_typescript_hook_commonTypes from 'react-native-reanimated/lib/typescript/hook/commonTypes';
|
|
2
|
+
import { AccordionAnimationOptions } from './accordion-animation.types.mjs';
|
|
3
|
+
|
|
4
|
+
declare function useAccordionIndicatorAnimation({ duration, open, }: AccordionAnimationOptions): react_native_reanimated_lib_typescript_hook_commonTypes.AnimatedStyleHandle<{
|
|
5
|
+
transform: {
|
|
6
|
+
rotate: string;
|
|
7
|
+
}[];
|
|
8
|
+
}>;
|
|
9
|
+
|
|
10
|
+
export { useAccordionIndicatorAnimation };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useAnimatedStyle } from "react-native-reanimated";
|
|
2
|
+
import { useAccordionAnimationProgress } from "./use-accordion-animation-progress.hook";
|
|
3
|
+
function useAccordionIndicatorAnimation({
|
|
4
|
+
duration,
|
|
5
|
+
open
|
|
6
|
+
}) {
|
|
7
|
+
const progress = useAccordionAnimationProgress({ duration, open });
|
|
8
|
+
const indicatorStyle = useAnimatedStyle(() => ({
|
|
9
|
+
transform: [{ rotate: `${progress.value * 180}deg` }]
|
|
10
|
+
}));
|
|
11
|
+
return indicatorStyle;
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
useAccordionIndicatorAnimation
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=use-accordion-indicator-animation.hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/use-accordion-indicator-animation.hook.ts"],"sourcesContent":["import { useAnimatedStyle } from \"react-native-reanimated\";\n\nimport type { AccordionAnimationOptions } from \"./accordion-animation.types\";\nimport { useAccordionAnimationProgress } from \"./use-accordion-animation-progress.hook\";\n\nexport function useAccordionIndicatorAnimation({\n duration,\n open,\n}: AccordionAnimationOptions) {\n const progress = useAccordionAnimationProgress({ duration, open });\n\n const indicatorStyle = useAnimatedStyle(() => ({\n transform: [{ rotate: `${progress.value * 180}deg` }],\n }));\n\n return indicatorStyle;\n}\n"],"mappings":"AAAA,SAAS,wBAAwB;AAGjC,SAAS,qCAAqC;AAEvC,SAAS,+BAA+B;AAAA,EAC7C;AAAA,EACA;AACF,GAA8B;AAC5B,QAAM,WAAW,8BAA8B,EAAE,UAAU,KAAK,CAAC;AAEjE,QAAM,iBAAiB,iBAAiB,OAAO;AAAA,IAC7C,WAAW,CAAC,EAAE,QAAQ,GAAG,SAAS,QAAQ,GAAG,MAAM,CAAC;AAAA,EACtD,EAAE;AAEF,SAAO;AACT;","names":[]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Accordion } from './components/accordion.mjs';
|
|
2
|
+
export { AccordionContentProps, AccordionItemProps, AccordionKeyDownEvent, AccordionMultipleRootProps, AccordionRootProps, AccordionSingleRootProps, AccordionTriggerProps } from './types/accordion.types.mjs';
|
|
3
|
+
import 'react';
|
|
4
|
+
import 'react/jsx-runtime';
|
|
5
|
+
import 'react-native';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./components\";\nexport * from \"./types\";\n"],"mappings":"AAAA,cAAc;AACd,cAAc;","names":[]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ViewProps, PressableProps, NativeSyntheticEvent } from 'react-native';
|
|
3
|
+
|
|
4
|
+
interface AccordionRootCommonProps extends ViewProps {
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
collapsible?: boolean;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface AccordionSingleRootProps extends AccordionRootCommonProps {
|
|
10
|
+
defaultValue?: string;
|
|
11
|
+
onValueChange?: (value: string | undefined) => void;
|
|
12
|
+
type?: "single";
|
|
13
|
+
value?: string;
|
|
14
|
+
}
|
|
15
|
+
interface AccordionMultipleRootProps extends AccordionRootCommonProps {
|
|
16
|
+
defaultValue?: string[];
|
|
17
|
+
onValueChange?: (value: string[]) => void;
|
|
18
|
+
type: "multiple";
|
|
19
|
+
value?: string[];
|
|
20
|
+
}
|
|
21
|
+
type AccordionRootProps = AccordionSingleRootProps | AccordionMultipleRootProps;
|
|
22
|
+
interface AccordionItemProps extends ViewProps {
|
|
23
|
+
children?: ReactNode;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
value: string;
|
|
26
|
+
}
|
|
27
|
+
interface AccordionTriggerProps extends Omit<PressableProps, "accessibilityRole" | "children"> {
|
|
28
|
+
children?: ReactNode;
|
|
29
|
+
hideIndicator?: boolean;
|
|
30
|
+
indicator?: ReactNode;
|
|
31
|
+
onKeyDown?: (event: AccordionKeyDownEvent) => void;
|
|
32
|
+
}
|
|
33
|
+
type AccordionKeyDownEvent = NativeSyntheticEvent<{
|
|
34
|
+
key: string;
|
|
35
|
+
}>;
|
|
36
|
+
interface AccordionContentProps extends ViewProps {
|
|
37
|
+
children?: ReactNode;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type { AccordionContentProps, AccordionItemProps, AccordionKeyDownEvent, AccordionMultipleRootProps, AccordionRootProps, AccordionSingleRootProps, AccordionTriggerProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=accordion.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types/index.ts"],"sourcesContent":["export * from \"./accordion.types\";\n"],"mappings":"AAAA,cAAc;","names":[]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
type AccordionFocusDirection = "first" | "last" | "next" | "previous";
|
|
2
|
+
declare function getAccordionFocusDirection(key: string): AccordionFocusDirection | undefined;
|
|
3
|
+
declare function normalizeAccordionValue(value: string | readonly string[] | undefined): readonly string[];
|
|
4
|
+
|
|
5
|
+
export { type AccordionFocusDirection, getAccordionFocusDirection, normalizeAccordionValue };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function getAccordionFocusDirection(key) {
|
|
2
|
+
if (key === "ArrowDown") return "next";
|
|
3
|
+
if (key === "ArrowUp") return "previous";
|
|
4
|
+
if (key === "Home") return "first";
|
|
5
|
+
if (key === "End") return "last";
|
|
6
|
+
return void 0;
|
|
7
|
+
}
|
|
8
|
+
function normalizeAccordionValue(value) {
|
|
9
|
+
if (value === void 0) return [];
|
|
10
|
+
return typeof value === "string" ? [value] : value;
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
getAccordionFocusDirection,
|
|
14
|
+
normalizeAccordionValue
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=accordion.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/accordion.utils.ts"],"sourcesContent":["export type AccordionFocusDirection = \"first\" | \"last\" | \"next\" | \"previous\";\n\nexport function getAccordionFocusDirection(\n key: string,\n): AccordionFocusDirection | undefined {\n if (key === \"ArrowDown\") return \"next\";\n if (key === \"ArrowUp\") return \"previous\";\n if (key === \"Home\") return \"first\";\n if (key === \"End\") return \"last\";\n return undefined;\n}\n\nexport function normalizeAccordionValue(\n value: string | readonly string[] | undefined,\n): readonly string[] {\n if (value === undefined) return [];\n return typeof value === \"string\" ? [value] : value;\n}\n"],"mappings":"AAEO,SAAS,2BACd,KACqC;AACrC,MAAI,QAAQ,YAAa,QAAO;AAChC,MAAI,QAAQ,UAAW,QAAO;AAC9B,MAAI,QAAQ,OAAQ,QAAO;AAC3B,MAAI,QAAQ,MAAO,QAAO;AAC1B,SAAO;AACT;AAEO,SAAS,wBACd,OACmB;AACnB,MAAI,UAAU,OAAW,QAAO,CAAC;AACjC,SAAO,OAAO,UAAU,WAAW,CAAC,KAAK,IAAI;AAC/C;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AccordionFocusDirection, getAccordionFocusDirection, normalizeAccordionValue } from './accordion.utils.mjs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/index.ts"],"sourcesContent":["export * from \"./accordion.utils\";\n"],"mappings":"AAAA,cAAc;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@impulse-ui-native/accordion",
|
|
3
|
+
"version": "2.8.0",
|
|
4
|
+
"description": "Accessible animated accordion components for ImpulseUI Native applications.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react-native",
|
|
7
|
+
"accordion",
|
|
8
|
+
"collapsible",
|
|
9
|
+
"disclosure",
|
|
10
|
+
"components",
|
|
11
|
+
"impulse-ui-native"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"source": "src/index.ts",
|
|
15
|
+
"module": "dist/index.js",
|
|
16
|
+
"types": "dist/index.d.mts",
|
|
17
|
+
"react-native": "src/index.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.mts",
|
|
21
|
+
"react-native": "./src/index.ts",
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"sideEffects": false,
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@impulse-ui-native/core": "2.8.0",
|
|
33
|
+
"@impulse-ui-native/icon": "2.8.0",
|
|
34
|
+
"@impulse-ui-native/primitives": "2.8.0",
|
|
35
|
+
"@impulse-ui-native/theme": "2.8.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/react": "~19.2.14",
|
|
39
|
+
"eslint": "^9.38.0",
|
|
40
|
+
"prettier": "^3.6.2",
|
|
41
|
+
"react": "19.2.3",
|
|
42
|
+
"react-native": "0.86.2",
|
|
43
|
+
"react-native-reanimated": "4.5.1",
|
|
44
|
+
"react-native-worklets": "0.10.1",
|
|
45
|
+
"typescript": "~6.0.3",
|
|
46
|
+
"@impulse-ui-native/prettier-config": "1.0.0",
|
|
47
|
+
"@impulse-ui-native/eslint-config": "1.0.0",
|
|
48
|
+
"@impulse-ui-native/tsconfig": "1.0.0"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"react": ">=18",
|
|
52
|
+
"react-native": ">=0.73",
|
|
53
|
+
"react-native-reanimated": ">=3.6.0",
|
|
54
|
+
"react-native-worklets": ">=0.5"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"prettier": "@impulse-ui-native/prettier-config",
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "tsup --config tsup.config.ts",
|
|
62
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
63
|
+
"lint": "pnpm exec eslint . --fix",
|
|
64
|
+
"format": "prettier --write \"./**/*.{ts,tsx,js,jsx,json,md}\" --ignore-path ../../.prettierignore"
|
|
65
|
+
}
|
|
66
|
+
}
|