@solostylist/ui-kit-native 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +5 -0
- package/dist/hooks/use-count-down.d.ts +74 -0
- package/dist/hooks/use-count-down.d.ts.map +1 -0
- package/dist/hooks/use-count-down.js +204 -0
- package/dist/hooks/use-is-passed-position.d.ts +20 -0
- package/dist/hooks/use-is-passed-position.d.ts.map +1 -0
- package/dist/hooks/use-is-passed-position.js +31 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -0
- package/dist/s-avatar/index.d.ts +3 -0
- package/dist/s-avatar/index.d.ts.map +1 -0
- package/dist/s-avatar/index.js +1 -0
- package/dist/s-avatar/s-avatar.d.ts +47 -0
- package/dist/s-avatar/s-avatar.d.ts.map +1 -0
- package/dist/s-avatar/s-avatar.js +112 -0
- package/dist/s-button/index.d.ts +3 -0
- package/dist/s-button/index.d.ts.map +1 -0
- package/dist/s-button/index.js +1 -0
- package/dist/s-button/s-button.d.ts +57 -0
- package/dist/s-button/s-button.d.ts.map +1 -0
- package/dist/s-button/s-button.js +158 -0
- package/dist/s-button-link/index.d.ts +2 -0
- package/dist/s-button-link/index.d.ts.map +1 -0
- package/dist/s-button-link/index.js +1 -0
- package/dist/s-button-link/s-button-link.d.ts +45 -0
- package/dist/s-button-link/s-button-link.d.ts.map +1 -0
- package/dist/s-button-link/s-button-link.js +64 -0
- package/dist/s-chat-input/index.d.ts +2 -0
- package/dist/s-chat-input/index.d.ts.map +1 -0
- package/dist/s-chat-input/index.js +1 -0
- package/dist/s-chat-input/s-chat-input.d.ts +41 -0
- package/dist/s-chat-input/s-chat-input.d.ts.map +1 -0
- package/dist/s-chat-input/s-chat-input.js +66 -0
- package/dist/s-chat-message/index.d.ts +3 -0
- package/dist/s-chat-message/index.d.ts.map +1 -0
- package/dist/s-chat-message/index.js +2 -0
- package/dist/s-chat-message/s-chat-message.d.ts +63 -0
- package/dist/s-chat-message/s-chat-message.d.ts.map +1 -0
- package/dist/s-chat-message/s-chat-message.js +207 -0
- package/dist/s-checkbox/index.d.ts +3 -0
- package/dist/s-checkbox/index.d.ts.map +1 -0
- package/dist/s-checkbox/index.js +1 -0
- package/dist/s-checkbox/s-checkbox.d.ts +34 -0
- package/dist/s-checkbox/s-checkbox.d.ts.map +1 -0
- package/dist/s-checkbox/s-checkbox.js +59 -0
- package/dist/s-chip/index.d.ts +3 -0
- package/dist/s-chip/index.d.ts.map +1 -0
- package/dist/s-chip/index.js +1 -0
- package/dist/s-chip/s-chip.d.ts +54 -0
- package/dist/s-chip/s-chip.d.ts.map +1 -0
- package/dist/s-chip/s-chip.js +170 -0
- package/dist/s-code-block/index.d.ts +3 -0
- package/dist/s-code-block/index.d.ts.map +1 -0
- package/dist/s-code-block/index.js +2 -0
- package/dist/s-code-block/s-code-block.d.ts +42 -0
- package/dist/s-code-block/s-code-block.d.ts.map +1 -0
- package/dist/s-code-block/s-code-block.js +81 -0
- package/dist/s-comment-message/index.d.ts +3 -0
- package/dist/s-comment-message/index.d.ts.map +1 -0
- package/dist/s-comment-message/index.js +2 -0
- package/dist/s-comment-message/s-comment-message.d.ts +56 -0
- package/dist/s-comment-message/s-comment-message.d.ts.map +1 -0
- package/dist/s-comment-message/s-comment-message.js +222 -0
- package/dist/s-copyable-text/index.d.ts +3 -0
- package/dist/s-copyable-text/index.d.ts.map +1 -0
- package/dist/s-copyable-text/index.js +1 -0
- package/dist/s-copyable-text/s-copyable-text.d.ts +26 -0
- package/dist/s-copyable-text/s-copyable-text.d.ts.map +1 -0
- package/dist/s-copyable-text/s-copyable-text.js +77 -0
- package/dist/s-countdown/index.d.ts +8 -0
- package/dist/s-countdown/index.d.ts.map +1 -0
- package/dist/s-countdown/index.js +7 -0
- package/dist/s-countdown/s-count-box.d.ts +42 -0
- package/dist/s-countdown/s-count-box.d.ts.map +1 -0
- package/dist/s-countdown/s-count-box.js +126 -0
- package/dist/s-countdown/s-countdown.d.ts +69 -0
- package/dist/s-countdown/s-countdown.d.ts.map +1 -0
- package/dist/s-countdown/s-countdown.js +93 -0
- package/dist/s-data-table/index.d.ts +3 -0
- package/dist/s-data-table/index.d.ts.map +1 -0
- package/dist/s-data-table/index.js +2 -0
- package/dist/s-data-table/s-data-table.d.ts +67 -0
- package/dist/s-data-table/s-data-table.d.ts.map +1 -0
- package/dist/s-data-table/s-data-table.js +98 -0
- package/dist/s-date-picker/index.d.ts +3 -0
- package/dist/s-date-picker/index.d.ts.map +1 -0
- package/dist/s-date-picker/index.js +2 -0
- package/dist/s-date-picker/s-date-picker.d.ts +43 -0
- package/dist/s-date-picker/s-date-picker.d.ts.map +1 -0
- package/dist/s-date-picker/s-date-picker.js +220 -0
- package/dist/s-date-time-picker/index.d.ts +3 -0
- package/dist/s-date-time-picker/index.d.ts.map +1 -0
- package/dist/s-date-time-picker/index.js +2 -0
- package/dist/s-date-time-picker/s-date-time-picker.d.ts +49 -0
- package/dist/s-date-time-picker/s-date-time-picker.d.ts.map +1 -0
- package/dist/s-date-time-picker/s-date-time-picker.js +390 -0
- package/dist/s-file-dropzone/index.d.ts +3 -0
- package/dist/s-file-dropzone/index.d.ts.map +1 -0
- package/dist/s-file-dropzone/index.js +2 -0
- package/dist/s-file-dropzone/s-file-dropzone.d.ts +98 -0
- package/dist/s-file-dropzone/s-file-dropzone.d.ts.map +1 -0
- package/dist/s-file-dropzone/s-file-dropzone.js +189 -0
- package/dist/s-file-icon/index.d.ts +3 -0
- package/dist/s-file-icon/index.d.ts.map +1 -0
- package/dist/s-file-icon/index.js +2 -0
- package/dist/s-file-icon/s-file-icon.d.ts +25 -0
- package/dist/s-file-icon/s-file-icon.d.ts.map +1 -0
- package/dist/s-file-icon/s-file-icon.js +87 -0
- package/dist/s-image-comparison/index.d.ts +2 -0
- package/dist/s-image-comparison/index.d.ts.map +1 -0
- package/dist/s-image-comparison/index.js +1 -0
- package/dist/s-image-comparison/s-image-comparison.d.ts +37 -0
- package/dist/s-image-comparison/s-image-comparison.d.ts.map +1 -0
- package/dist/s-image-comparison/s-image-comparison.js +138 -0
- package/dist/s-label/index.d.ts +3 -0
- package/dist/s-label/index.d.ts.map +1 -0
- package/dist/s-label/index.js +1 -0
- package/dist/s-label/s-label.d.ts +25 -0
- package/dist/s-label/s-label.d.ts.map +1 -0
- package/dist/s-label/s-label.js +35 -0
- package/dist/s-language-switcher/index.d.ts +4 -0
- package/dist/s-language-switcher/index.d.ts.map +1 -0
- package/dist/s-language-switcher/index.js +2 -0
- package/dist/s-language-switcher/s-language-switcher.d.ts +56 -0
- package/dist/s-language-switcher/s-language-switcher.d.ts.map +1 -0
- package/dist/s-language-switcher/s-language-switcher.js +68 -0
- package/dist/s-lazy-image/index.d.ts +3 -0
- package/dist/s-lazy-image/index.d.ts.map +1 -0
- package/dist/s-lazy-image/index.js +1 -0
- package/dist/s-lazy-image/s-lazy-image.d.ts +45 -0
- package/dist/s-lazy-image/s-lazy-image.d.ts.map +1 -0
- package/dist/s-lazy-image/s-lazy-image.js +71 -0
- package/dist/s-moving-border/index.d.ts +2 -0
- package/dist/s-moving-border/index.d.ts.map +1 -0
- package/dist/s-moving-border/index.js +1 -0
- package/dist/s-moving-border/s-moving-border.d.ts +40 -0
- package/dist/s-moving-border/s-moving-border.d.ts.map +1 -0
- package/dist/s-moving-border/s-moving-border.js +158 -0
- package/dist/s-multi-select/index.d.ts +2 -0
- package/dist/s-multi-select/index.d.ts.map +1 -0
- package/dist/s-multi-select/index.js +1 -0
- package/dist/s-multi-select/s-multi-select.d.ts +55 -0
- package/dist/s-multi-select/s-multi-select.d.ts.map +1 -0
- package/dist/s-multi-select/s-multi-select.js +201 -0
- package/dist/s-pagination/index.d.ts +3 -0
- package/dist/s-pagination/index.d.ts.map +1 -0
- package/dist/s-pagination/index.js +2 -0
- package/dist/s-pagination/s-pagination.d.ts +43 -0
- package/dist/s-pagination/s-pagination.d.ts.map +1 -0
- package/dist/s-pagination/s-pagination.js +121 -0
- package/dist/s-rating/index.d.ts +3 -0
- package/dist/s-rating/index.d.ts.map +1 -0
- package/dist/s-rating/index.js +1 -0
- package/dist/s-rating/s-rating.d.ts +57 -0
- package/dist/s-rating/s-rating.d.ts.map +1 -0
- package/dist/s-rating/s-rating.js +155 -0
- package/dist/s-review/index.d.ts +3 -0
- package/dist/s-review/index.d.ts.map +1 -0
- package/dist/s-review/index.js +1 -0
- package/dist/s-review/s-review.d.ts +57 -0
- package/dist/s-review/s-review.d.ts.map +1 -0
- package/dist/s-review/s-review.js +235 -0
- package/dist/s-scroll-to-top/index.d.ts +3 -0
- package/dist/s-scroll-to-top/index.d.ts.map +1 -0
- package/dist/s-scroll-to-top/index.js +2 -0
- package/dist/s-scroll-to-top/s-scroll-to-top.d.ts +38 -0
- package/dist/s-scroll-to-top/s-scroll-to-top.d.ts.map +1 -0
- package/dist/s-scroll-to-top/s-scroll-to-top.js +76 -0
- package/dist/s-select/s-select.d.ts.map +1 -1
- package/dist/s-select/s-select.js +8 -8
- package/dist/s-select-list/index.d.ts +3 -0
- package/dist/s-select-list/index.d.ts.map +1 -0
- package/dist/s-select-list/index.js +2 -0
- package/dist/s-select-list/s-select-list.d.ts +36 -0
- package/dist/s-select-list/s-select-list.d.ts.map +1 -0
- package/dist/s-select-list/s-select-list.js +129 -0
- package/dist/s-text-shimmer/index.d.ts +2 -0
- package/dist/s-text-shimmer/index.d.ts.map +1 -0
- package/dist/s-text-shimmer/index.js +1 -0
- package/dist/s-text-shimmer/s-text-shimmer.d.ts +36 -0
- package/dist/s-text-shimmer/s-text-shimmer.d.ts.map +1 -0
- package/dist/s-text-shimmer/s-text-shimmer.js +120 -0
- package/dist/s-text-truncation/index.d.ts +2 -0
- package/dist/s-text-truncation/index.d.ts.map +1 -0
- package/dist/s-text-truncation/index.js +1 -0
- package/dist/s-text-truncation/s-text-truncation.d.ts +45 -0
- package/dist/s-text-truncation/s-text-truncation.d.ts.map +1 -0
- package/dist/s-text-truncation/s-text-truncation.js +48 -0
- package/dist/s-tip/index.d.ts +3 -0
- package/dist/s-tip/index.d.ts.map +1 -0
- package/dist/s-tip/index.js +1 -0
- package/dist/s-tip/s-tip.d.ts +18 -0
- package/dist/s-tip/s-tip.d.ts.map +1 -0
- package/dist/s-tip/s-tip.js +32 -0
- package/dist/s-zoom-image/index.d.ts +3 -0
- package/dist/s-zoom-image/index.d.ts.map +1 -0
- package/dist/s-zoom-image/index.js +1 -0
- package/dist/s-zoom-image/s-zoom-image.d.ts +40 -0
- package/dist/s-zoom-image/s-zoom-image.d.ts.map +1 -0
- package/dist/s-zoom-image/s-zoom-image.js +154 -0
- package/dist/utils/bytes-to-size.d.ts +10 -0
- package/dist/utils/bytes-to-size.d.ts.map +1 -0
- package/dist/utils/bytes-to-size.js +18 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +174 -5
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type StyleProp, type ViewStyle } from 'react-native';
|
|
3
|
+
/**
|
|
4
|
+
* Props interface for SLabel component
|
|
5
|
+
*/
|
|
6
|
+
export interface SLabelProps {
|
|
7
|
+
/** Main label text or element to display prominently */
|
|
8
|
+
label?: string | React.ReactNode;
|
|
9
|
+
/** Child elements to render below the label, typically form controls */
|
|
10
|
+
children?: React.ReactNode;
|
|
11
|
+
/** Tooltip hint text shown on hover/press of the help icon */
|
|
12
|
+
hint?: string;
|
|
13
|
+
/** Custom styles for the container */
|
|
14
|
+
style?: StyleProp<ViewStyle>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* An enhanced label component that provides structured labeling with optional hints and tooltips.
|
|
18
|
+
* Synced with web SLabel from @solostylist/ui-kit for cross-platform consistency.
|
|
19
|
+
*/
|
|
20
|
+
export declare const SLabel: {
|
|
21
|
+
({ label, children, hint, style }: SLabelProps): React.JSX.Element;
|
|
22
|
+
displayName: string;
|
|
23
|
+
};
|
|
24
|
+
export default SLabel;
|
|
25
|
+
//# sourceMappingURL=s-label.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s-label.d.ts","sourceRoot":"","sources":["../../src/s-label/s-label.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAoB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAIhF;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;IACjC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED;;;GAGG;AACH,eAAO,MAAM,MAAM;uCAAsC,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO;;CAwCvF,CAAC;AAIF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { MaterialIcons } from '@expo/vector-icons';
|
|
3
|
+
import { StyleSheet, View } from 'react-native';
|
|
4
|
+
import { Text, Tooltip } from 'react-native-paper';
|
|
5
|
+
import { useSTheme } from '../theme';
|
|
6
|
+
/**
|
|
7
|
+
* An enhanced label component that provides structured labeling with optional hints and tooltips.
|
|
8
|
+
* Synced with web SLabel from @solostylist/ui-kit for cross-platform consistency.
|
|
9
|
+
*/
|
|
10
|
+
export const SLabel = ({ label, children, hint, style }) => {
|
|
11
|
+
const { theme } = useSTheme();
|
|
12
|
+
const styles = StyleSheet.create({
|
|
13
|
+
container: {
|
|
14
|
+
width: '100%',
|
|
15
|
+
},
|
|
16
|
+
labelRow: {
|
|
17
|
+
flexDirection: 'row',
|
|
18
|
+
alignItems: 'center',
|
|
19
|
+
marginBottom: 8, // 8px matches the 1 spacing unit from MUI theme
|
|
20
|
+
},
|
|
21
|
+
labelText: {
|
|
22
|
+
fontSize: 14, // 0.875rem * 16px = 14px
|
|
23
|
+
fontWeight: '500',
|
|
24
|
+
lineHeight: 14 * 1.57, // lineHeight from web version
|
|
25
|
+
color: theme.colors.text.secondary,
|
|
26
|
+
fontFamily: theme.typography.fontFamily,
|
|
27
|
+
},
|
|
28
|
+
helpIcon: {
|
|
29
|
+
marginLeft: 4,
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
return (_jsxs(View, { style: [styles.container, style], children: [_jsxs(View, { style: styles.labelRow, children: [typeof label === 'string' ? _jsx(Text, { style: styles.labelText, children: label }) : label, hint ? (_jsx(Tooltip, { title: hint, children: _jsx(MaterialIcons, { name: "help-outline", size: 16, color: theme.colors.text.secondary, style: styles.helpIcon }) })) : null] }), children] }));
|
|
33
|
+
};
|
|
34
|
+
SLabel.displayName = 'SLabel';
|
|
35
|
+
export default SLabel;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/s-language-switcher/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACnE,YAAY,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACrF,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type StyleProp, type ViewStyle } from 'react-native';
|
|
3
|
+
/**
|
|
4
|
+
* Language option interface
|
|
5
|
+
* Synced with web SLanguageSwitcher from @solostylist/ui-kit
|
|
6
|
+
*/
|
|
7
|
+
export interface SLanguageOption {
|
|
8
|
+
/** Language code (e.g., 'en', 'vi') */
|
|
9
|
+
code: string;
|
|
10
|
+
/** Display label (e.g., 'English', 'Vietnamese') */
|
|
11
|
+
label: string;
|
|
12
|
+
/** ISO 3166-1 alpha-2 country code for flag (e.g., 'GB', 'VN', 'US') */
|
|
13
|
+
countryCode: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Props interface for SLanguageSwitcher component
|
|
17
|
+
* Synced with web SLanguageSwitcher from @solostylist/ui-kit
|
|
18
|
+
*/
|
|
19
|
+
export interface SLanguageSwitcherProps {
|
|
20
|
+
/** Custom language options to display (default: English & Vietnamese) */
|
|
21
|
+
languages?: SLanguageOption[];
|
|
22
|
+
/** Callback when language changes */
|
|
23
|
+
onLanguageChange: (languageCode: string) => void;
|
|
24
|
+
/** Current language code */
|
|
25
|
+
currentLanguage: string;
|
|
26
|
+
/** Size of the flag icon in the button (default: 20) */
|
|
27
|
+
buttonFlagSize?: number;
|
|
28
|
+
/** Size of the flag icon in the menu items (default: 24) */
|
|
29
|
+
menuFlagSize?: number;
|
|
30
|
+
/** Width of the language menu dropdown (default: 220) */
|
|
31
|
+
menuWidth?: number;
|
|
32
|
+
/** Additional styles for the icon button container */
|
|
33
|
+
style?: StyleProp<ViewStyle>;
|
|
34
|
+
/** Additional styles for the menu */
|
|
35
|
+
menuStyle?: StyleProp<ViewStyle>;
|
|
36
|
+
/** Whether the component is disabled */
|
|
37
|
+
disabled?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Default language options
|
|
41
|
+
*/
|
|
42
|
+
export declare const defaultLanguageOptions: SLanguageOption[];
|
|
43
|
+
/**
|
|
44
|
+
* A language switcher component with flag icons and dropdown menu.
|
|
45
|
+
* Built on React Native Paper with consistent theming.
|
|
46
|
+
* Synced with web SLanguageSwitcher from @solostylist/ui-kit for cross-platform consistency.
|
|
47
|
+
*
|
|
48
|
+
* For react-i18next integration, create a wrapper component that uses the useTranslation hook
|
|
49
|
+
* and passes currentLanguage and onLanguageChange props.
|
|
50
|
+
*/
|
|
51
|
+
export declare const SLanguageSwitcher: {
|
|
52
|
+
({ languages, onLanguageChange, currentLanguage, buttonFlagSize, menuFlagSize, menuWidth, style, menuStyle, disabled, }: SLanguageSwitcherProps): React.JSX.Element;
|
|
53
|
+
displayName: string;
|
|
54
|
+
};
|
|
55
|
+
export default SLanguageSwitcher;
|
|
56
|
+
//# sourceMappingURL=s-language-switcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s-language-switcher.d.ts","sourceRoot":"","sources":["../../src/s-language-switcher/s-language-switcher.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAC9D,OAAO,EAAoB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAKhF;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,yEAAyE;IACzE,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,qCAAqC;IACrC,gBAAgB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,4BAA4B;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,qCAAqC;IACrC,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,eAAe,EAGnD,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB;6HAU3B,sBAAsB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO;;CAuF5C,CAAC;AAIF,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
3
|
+
import { StyleSheet, View } from 'react-native';
|
|
4
|
+
import CountryFlag from 'react-native-country-flag';
|
|
5
|
+
import { IconButton, Menu } from 'react-native-paper';
|
|
6
|
+
import { useSTheme } from '../theme';
|
|
7
|
+
/**
|
|
8
|
+
* Default language options
|
|
9
|
+
*/
|
|
10
|
+
export const defaultLanguageOptions = [
|
|
11
|
+
{ code: 'en', label: 'English', countryCode: 'GB' },
|
|
12
|
+
{ code: 'vi', label: 'Vietnamese', countryCode: 'VN' },
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* A language switcher component with flag icons and dropdown menu.
|
|
16
|
+
* Built on React Native Paper with consistent theming.
|
|
17
|
+
* Synced with web SLanguageSwitcher from @solostylist/ui-kit for cross-platform consistency.
|
|
18
|
+
*
|
|
19
|
+
* For react-i18next integration, create a wrapper component that uses the useTranslation hook
|
|
20
|
+
* and passes currentLanguage and onLanguageChange props.
|
|
21
|
+
*/
|
|
22
|
+
export const SLanguageSwitcher = ({ languages = defaultLanguageOptions, onLanguageChange, currentLanguage, buttonFlagSize = 20, menuFlagSize = 24, menuWidth = 220, style, menuStyle, disabled = false, }) => {
|
|
23
|
+
const { theme } = useSTheme();
|
|
24
|
+
const [menuVisible, setMenuVisible] = useState(false);
|
|
25
|
+
const currentOption = languages.find((lang) => lang.code === currentLanguage) || languages[0];
|
|
26
|
+
// Menu visibility handlers
|
|
27
|
+
const openMenu = useCallback(() => {
|
|
28
|
+
if (!disabled) {
|
|
29
|
+
setMenuVisible(true);
|
|
30
|
+
}
|
|
31
|
+
}, [disabled]);
|
|
32
|
+
const closeMenu = useCallback(() => {
|
|
33
|
+
setMenuVisible(false);
|
|
34
|
+
}, []);
|
|
35
|
+
// Language change handler
|
|
36
|
+
const handleLanguageChange = useCallback((languageCode) => {
|
|
37
|
+
closeMenu();
|
|
38
|
+
onLanguageChange(languageCode);
|
|
39
|
+
}, [onLanguageChange, closeMenu]);
|
|
40
|
+
// Compute styles
|
|
41
|
+
const menuBgColor = theme.colors.background.paper;
|
|
42
|
+
const selectedItemBg = theme.dark ? theme.colors.primary[800] : theme.colors.primary[100];
|
|
43
|
+
const itemTextColor = theme.colors.text.primary;
|
|
44
|
+
const styles = useMemo(() => StyleSheet.create({
|
|
45
|
+
menu: {
|
|
46
|
+
width: menuWidth,
|
|
47
|
+
backgroundColor: menuBgColor,
|
|
48
|
+
borderRadius: theme.borderRadius.md,
|
|
49
|
+
},
|
|
50
|
+
menuItem: {
|
|
51
|
+
backgroundColor: 'transparent',
|
|
52
|
+
},
|
|
53
|
+
menuItemSelected: {
|
|
54
|
+
backgroundColor: selectedItemBg,
|
|
55
|
+
},
|
|
56
|
+
flagContainer: {
|
|
57
|
+
width: menuFlagSize * 1.5,
|
|
58
|
+
alignItems: 'center',
|
|
59
|
+
justifyContent: 'center',
|
|
60
|
+
},
|
|
61
|
+
}), [theme, menuFlagSize, menuWidth, menuBgColor, selectedItemBg]);
|
|
62
|
+
return (_jsx(Menu, { visible: menuVisible, onDismiss: closeMenu, anchor: _jsx(IconButton, { icon: () => _jsx(CountryFlag, { isoCode: currentOption?.countryCode || 'GB', size: buttonFlagSize }), onPress: openMenu, disabled: disabled, style: style }), contentStyle: [styles.menu, menuStyle], children: languages.map((lang) => {
|
|
63
|
+
const isSelected = lang.code === currentLanguage;
|
|
64
|
+
return (_jsx(Menu.Item, { onPress: () => handleLanguageChange(lang.code), title: lang.label, leadingIcon: () => (_jsx(View, { style: styles.flagContainer, children: _jsx(CountryFlag, { isoCode: lang.countryCode, size: menuFlagSize }) })), style: [styles.menuItem, isSelected && styles.menuItemSelected], titleStyle: { color: itemTextColor } }, lang.code));
|
|
65
|
+
}) }));
|
|
66
|
+
};
|
|
67
|
+
SLanguageSwitcher.displayName = 'SLanguageSwitcher';
|
|
68
|
+
export default SLanguageSwitcher;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/s-lazy-image/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACrD,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SLazyImage, default } from './s-lazy-image';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type ImageProps, type ImageStyle, type StyleProp, type ViewStyle } from 'react-native';
|
|
3
|
+
/**
|
|
4
|
+
* Skeleton variant types matching web SLazyImage
|
|
5
|
+
*/
|
|
6
|
+
export type SLazyImageVariant = 'circular' | 'rectangular' | 'rounded' | 'text';
|
|
7
|
+
/**
|
|
8
|
+
* Props for the SLazyImage component
|
|
9
|
+
* Synced with web SLazyImage from @solostylist/ui-kit
|
|
10
|
+
*/
|
|
11
|
+
export interface SLazyImageProps extends Omit<ImageProps, 'source' | 'onLoad' | 'onError' | 'height' | 'width'> {
|
|
12
|
+
/** Image source URL */
|
|
13
|
+
src: string;
|
|
14
|
+
/** Skeleton variant while loading */
|
|
15
|
+
variant?: SLazyImageVariant;
|
|
16
|
+
/** Image height */
|
|
17
|
+
height?: number | string;
|
|
18
|
+
/** Image width */
|
|
19
|
+
width?: number | string;
|
|
20
|
+
/** Minimum width constraint */
|
|
21
|
+
minWidth?: number | string;
|
|
22
|
+
/** Minimum height constraint */
|
|
23
|
+
minHeight?: number | string;
|
|
24
|
+
/** Additional styles for the container */
|
|
25
|
+
containerStyle?: StyleProp<ViewStyle>;
|
|
26
|
+
/** Additional styles for the image */
|
|
27
|
+
imageStyle?: StyleProp<ImageStyle>;
|
|
28
|
+
/** Additional styles for the skeleton placeholder */
|
|
29
|
+
skeletonStyle?: StyleProp<ViewStyle>;
|
|
30
|
+
/** Callback fired when the image loads successfully */
|
|
31
|
+
onLoad?: (event: any) => void;
|
|
32
|
+
/** Callback fired when the image fails to load */
|
|
33
|
+
onError?: (error: any) => void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A lazy-loading image component with skeleton placeholder.
|
|
37
|
+
* Built on React Native Image with loading state management.
|
|
38
|
+
* Synced with web SLazyImage from @solostylist/ui-kit for cross-platform consistency.
|
|
39
|
+
*/
|
|
40
|
+
export declare const SLazyImage: {
|
|
41
|
+
({ src, variant, height, width, minWidth, minHeight, containerStyle, imageStyle, skeletonStyle, onLoad, onError, style, ...props }: SLazyImageProps): React.JSX.Element;
|
|
42
|
+
displayName: string;
|
|
43
|
+
};
|
|
44
|
+
export default SLazyImage;
|
|
45
|
+
//# sourceMappingURL=s-lazy-image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s-lazy-image.d.ts","sourceRoot":"","sources":["../../src/s-lazy-image/s-lazy-image.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AACjD,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAItB;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,aAAa,GAAG,SAAS,GAAG,MAAM,CAAC;AAEhF;;;GAGG;AACH,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,UAAU,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC7G,uBAAuB;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,qCAAqC;IACrC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,mBAAmB;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,0CAA0C;IAC1C,cAAc,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,sCAAsC;IACtC,UAAU,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC;IACnC,qDAAqD;IACrD,aAAa,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACrC,uDAAuD;IACvD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC9B,kDAAkD;IAClD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;CAChC;AAED;;;;GAIG;AACH,eAAO,MAAM,UAAU;wIAcpB,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO;;CA2FrC,CAAC;AAIF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useState } from 'react';
|
|
3
|
+
import { Image, StyleSheet, View, } from 'react-native';
|
|
4
|
+
import { ActivityIndicator } from 'react-native-paper';
|
|
5
|
+
import { useSTheme } from '../theme';
|
|
6
|
+
/**
|
|
7
|
+
* A lazy-loading image component with skeleton placeholder.
|
|
8
|
+
* Built on React Native Image with loading state management.
|
|
9
|
+
* Synced with web SLazyImage from @solostylist/ui-kit for cross-platform consistency.
|
|
10
|
+
*/
|
|
11
|
+
export const SLazyImage = ({ src, variant = 'rounded', height = 200, width = '100%', minWidth, minHeight, containerStyle, imageStyle, skeletonStyle, onLoad, onError, style, ...props }) => {
|
|
12
|
+
const { theme } = useSTheme();
|
|
13
|
+
const [imageLoaded, setImageLoaded] = useState(false);
|
|
14
|
+
const [imageError, setImageError] = useState(false);
|
|
15
|
+
const getBorderRadius = () => {
|
|
16
|
+
switch (variant) {
|
|
17
|
+
case 'circular':
|
|
18
|
+
return 9999; // Large number for circular
|
|
19
|
+
case 'rounded':
|
|
20
|
+
return theme.borderRadius.md;
|
|
21
|
+
case 'rectangular':
|
|
22
|
+
case 'text':
|
|
23
|
+
default:
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const borderRadius = getBorderRadius();
|
|
28
|
+
const skeletonBgColor = theme.dark ? theme.colors.secondary[700] : theme.colors.secondary[300];
|
|
29
|
+
const styles = useMemo(() => StyleSheet.create({
|
|
30
|
+
container: {
|
|
31
|
+
position: 'relative',
|
|
32
|
+
width: typeof width === 'number' ? width : undefined,
|
|
33
|
+
height: typeof height === 'number' ? height : undefined,
|
|
34
|
+
minWidth: typeof minWidth === 'number' ? minWidth : undefined,
|
|
35
|
+
minHeight: typeof minHeight === 'number' ? minHeight : undefined,
|
|
36
|
+
overflow: 'hidden',
|
|
37
|
+
},
|
|
38
|
+
skeleton: {
|
|
39
|
+
position: 'absolute',
|
|
40
|
+
top: 0,
|
|
41
|
+
left: 0,
|
|
42
|
+
right: 0,
|
|
43
|
+
bottom: 0,
|
|
44
|
+
backgroundColor: skeletonBgColor,
|
|
45
|
+
borderRadius,
|
|
46
|
+
justifyContent: 'center',
|
|
47
|
+
alignItems: 'center',
|
|
48
|
+
},
|
|
49
|
+
image: {
|
|
50
|
+
width: '100%',
|
|
51
|
+
height: '100%',
|
|
52
|
+
borderRadius,
|
|
53
|
+
},
|
|
54
|
+
hidden: {
|
|
55
|
+
opacity: 0,
|
|
56
|
+
},
|
|
57
|
+
}), [width, height, minWidth, minHeight, borderRadius, skeletonBgColor]);
|
|
58
|
+
const handleLoad = (event) => {
|
|
59
|
+
setImageLoaded(true);
|
|
60
|
+
setImageError(false);
|
|
61
|
+
onLoad?.(event);
|
|
62
|
+
};
|
|
63
|
+
const handleError = (error) => {
|
|
64
|
+
setImageError(true);
|
|
65
|
+
setImageLoaded(false);
|
|
66
|
+
onError?.(error);
|
|
67
|
+
};
|
|
68
|
+
return (_jsxs(View, { style: [styles.container, containerStyle], children: [!imageLoaded && !imageError && (_jsx(View, { style: [styles.skeleton, skeletonStyle], children: _jsx(ActivityIndicator, { size: "small", color: theme.dark ? theme.colors.primary[300] : theme.colors.primary[500] }) })), !imageError && (_jsx(Image, { source: { uri: src }, style: [styles.image, imageStyle, style, !imageLoaded && styles.hidden], onLoad: handleLoad, onError: handleError, ...props })), imageError && _jsx(View, { style: [styles.skeleton, skeletonStyle] })] }));
|
|
69
|
+
};
|
|
70
|
+
SLazyImage.displayName = 'SLazyImage';
|
|
71
|
+
export default SLazyImage;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/s-moving-border/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SMovingBorder } from './s-moving-border';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type ViewStyle } from 'react-native';
|
|
3
|
+
/**
|
|
4
|
+
* Props interface for SMovingBorder component
|
|
5
|
+
* Synced with web SMovingBorder from @solostylist/ui-kit
|
|
6
|
+
*/
|
|
7
|
+
export interface SMovingBorderProps {
|
|
8
|
+
/** Duration of one complete animation cycle in milliseconds (default: 6000) */
|
|
9
|
+
duration?: number;
|
|
10
|
+
/** Color of the glow effect (supports theme colors or hex) */
|
|
11
|
+
glowColor?: string;
|
|
12
|
+
/** Size of the glow effect in pixels (default: 250) */
|
|
13
|
+
glowSize?: number;
|
|
14
|
+
/** Content to render inside the moving border container */
|
|
15
|
+
children: React.ReactNode;
|
|
16
|
+
/** Border radius for rounded corners (default: 0) */
|
|
17
|
+
borderRadius?: number;
|
|
18
|
+
/** Additional styles for the container */
|
|
19
|
+
style?: ViewStyle;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* An animated border effect component that creates smooth moving light effects around the element perimeter.
|
|
23
|
+
* Synced with web SMovingBorder from @solostylist/ui-kit.
|
|
24
|
+
*
|
|
25
|
+
* Web implementation details:
|
|
26
|
+
* - Uses framer-motion for smooth SVG path animations
|
|
27
|
+
* - Uses SVG rect paths with getPointAtLength() for precise positioning
|
|
28
|
+
* - Two glow elements with 180° phase offset for continuous effect
|
|
29
|
+
*
|
|
30
|
+
* React Native implementation:
|
|
31
|
+
* - Uses Animated API for performant animations
|
|
32
|
+
* - Calculates path positions manually for rectangular borders
|
|
33
|
+
* - Maintains same visual appearance and timing as web version
|
|
34
|
+
*/
|
|
35
|
+
export declare const SMovingBorder: {
|
|
36
|
+
({ duration, glowColor, glowSize, children, borderRadius, style, }: SMovingBorderProps): React.JSX.Element;
|
|
37
|
+
displayName: string;
|
|
38
|
+
};
|
|
39
|
+
export default SMovingBorder;
|
|
40
|
+
//# sourceMappingURL=s-moving-border.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s-moving-border.d.ts","sourceRoot":"","sources":["../../src/s-moving-border/s-moving-border.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AACpE,OAAO,EAAyD,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAMrG;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,qDAAqD;IACrD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAkJD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,aAAa;wEAOvB,kBAAkB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO;;CAsExC,CAAC;AAIF,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { Animated, Easing, StyleSheet, View } from 'react-native';
|
|
4
|
+
import { useSTheme } from '../theme';
|
|
5
|
+
/** Default glow size in pixels */
|
|
6
|
+
const GLOW_SIZE = 250;
|
|
7
|
+
/**
|
|
8
|
+
* Calculates a point on a rectangular path given a progress value (0-1)
|
|
9
|
+
*
|
|
10
|
+
* The path follows: top edge → right edge → bottom edge → left edge
|
|
11
|
+
*
|
|
12
|
+
* @param progress - Animation progress (0-1)
|
|
13
|
+
* @param width - Container width
|
|
14
|
+
* @param height - Container height
|
|
15
|
+
* @returns {x, y} coordinates on the path
|
|
16
|
+
*/
|
|
17
|
+
const getPointOnPath = (progress, width, height) => {
|
|
18
|
+
// Normalize progress to 0-1 range
|
|
19
|
+
const normalizedProgress = progress % 1;
|
|
20
|
+
// Calculate perimeter (simplified - not accounting for rounded corners arc length)
|
|
21
|
+
const perimeter = 2 * (width + height);
|
|
22
|
+
const distance = normalizedProgress * perimeter;
|
|
23
|
+
// Top edge (left to right)
|
|
24
|
+
if (distance <= width) {
|
|
25
|
+
return { x: distance, y: 0 };
|
|
26
|
+
}
|
|
27
|
+
// Right edge (top to bottom)
|
|
28
|
+
if (distance <= width + height) {
|
|
29
|
+
return { x: width, y: distance - width };
|
|
30
|
+
}
|
|
31
|
+
// Bottom edge (right to left)
|
|
32
|
+
if (distance <= 2 * width + height) {
|
|
33
|
+
return { x: width - (distance - width - height), y: height };
|
|
34
|
+
}
|
|
35
|
+
// Left edge (bottom to top)
|
|
36
|
+
return { x: 0, y: height - (distance - 2 * width - height) };
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Internal component that handles a single animated glow element
|
|
40
|
+
*/
|
|
41
|
+
const MovingGlow = ({ duration, phase = 0, glowSize, glowColor, containerWidth, containerHeight, }) => {
|
|
42
|
+
const [animProgress] = useState(() => new Animated.Value(phase));
|
|
43
|
+
const isActiveRef = useRef(true);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (containerWidth === 0 || containerHeight === 0)
|
|
46
|
+
return;
|
|
47
|
+
isActiveRef.current = true;
|
|
48
|
+
const animate = () => {
|
|
49
|
+
if (!isActiveRef.current)
|
|
50
|
+
return;
|
|
51
|
+
animProgress.setValue(phase);
|
|
52
|
+
Animated.timing(animProgress, {
|
|
53
|
+
toValue: phase + 1,
|
|
54
|
+
duration: duration,
|
|
55
|
+
easing: Easing.linear,
|
|
56
|
+
useNativeDriver: true,
|
|
57
|
+
}).start(({ finished }) => {
|
|
58
|
+
if (finished && isActiveRef.current) {
|
|
59
|
+
animate();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
animate();
|
|
64
|
+
return () => {
|
|
65
|
+
isActiveRef.current = false;
|
|
66
|
+
animProgress.stopAnimation();
|
|
67
|
+
};
|
|
68
|
+
}, [duration, phase, containerWidth, containerHeight, animProgress]);
|
|
69
|
+
// We need to use a listener to update position since we can't use
|
|
70
|
+
// interpolate with custom functions in React Native
|
|
71
|
+
const [position, setPosition] = useState({ x: 0, y: 0 });
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
const listenerId = animProgress.addListener(({ value }) => {
|
|
74
|
+
const point = getPointOnPath(value, containerWidth, containerHeight);
|
|
75
|
+
setPosition(point);
|
|
76
|
+
});
|
|
77
|
+
return () => {
|
|
78
|
+
animProgress.removeListener(listenerId);
|
|
79
|
+
};
|
|
80
|
+
}, [animProgress, containerWidth, containerHeight]);
|
|
81
|
+
return (_jsxs(View, { style: {
|
|
82
|
+
position: 'absolute',
|
|
83
|
+
left: position.x - glowSize / 2,
|
|
84
|
+
top: position.y - glowSize / 2,
|
|
85
|
+
width: glowSize,
|
|
86
|
+
height: glowSize,
|
|
87
|
+
borderRadius: glowSize / 2,
|
|
88
|
+
backgroundColor: glowColor,
|
|
89
|
+
opacity: 0.5,
|
|
90
|
+
}, children: [_jsx(View, { style: {
|
|
91
|
+
position: 'absolute',
|
|
92
|
+
top: '10%',
|
|
93
|
+
left: '10%',
|
|
94
|
+
right: '10%',
|
|
95
|
+
bottom: '10%',
|
|
96
|
+
borderRadius: glowSize / 2,
|
|
97
|
+
backgroundColor: glowColor,
|
|
98
|
+
opacity: 0.3,
|
|
99
|
+
} }), _jsx(View, { style: {
|
|
100
|
+
position: 'absolute',
|
|
101
|
+
top: '20%',
|
|
102
|
+
left: '20%',
|
|
103
|
+
right: '20%',
|
|
104
|
+
bottom: '20%',
|
|
105
|
+
borderRadius: glowSize / 2,
|
|
106
|
+
backgroundColor: glowColor,
|
|
107
|
+
opacity: 0.2,
|
|
108
|
+
} })] }));
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* An animated border effect component that creates smooth moving light effects around the element perimeter.
|
|
112
|
+
* Synced with web SMovingBorder from @solostylist/ui-kit.
|
|
113
|
+
*
|
|
114
|
+
* Web implementation details:
|
|
115
|
+
* - Uses framer-motion for smooth SVG path animations
|
|
116
|
+
* - Uses SVG rect paths with getPointAtLength() for precise positioning
|
|
117
|
+
* - Two glow elements with 180° phase offset for continuous effect
|
|
118
|
+
*
|
|
119
|
+
* React Native implementation:
|
|
120
|
+
* - Uses Animated API for performant animations
|
|
121
|
+
* - Calculates path positions manually for rectangular borders
|
|
122
|
+
* - Maintains same visual appearance and timing as web version
|
|
123
|
+
*/
|
|
124
|
+
export const SMovingBorder = ({ duration = 6000, glowColor, glowSize = GLOW_SIZE, children, borderRadius = 0, style, }) => {
|
|
125
|
+
const { theme } = useSTheme();
|
|
126
|
+
const [containerSize, setContainerSize] = useState({ width: 0, height: 0 });
|
|
127
|
+
// Default glow color to theme primary.main (500 shade matches web)
|
|
128
|
+
const effectiveGlowColor = glowColor || theme.colors.primary[500];
|
|
129
|
+
const handleLayout = (event) => {
|
|
130
|
+
const { width, height } = event.nativeEvent.layout;
|
|
131
|
+
if (width > 0 && height > 0) {
|
|
132
|
+
setContainerSize({ width, height });
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const styles = useMemo(() => StyleSheet.create({
|
|
136
|
+
container: {
|
|
137
|
+
position: 'relative',
|
|
138
|
+
overflow: 'hidden',
|
|
139
|
+
width: '100%',
|
|
140
|
+
height: '100%',
|
|
141
|
+
},
|
|
142
|
+
animationLayer: {
|
|
143
|
+
position: 'absolute',
|
|
144
|
+
top: 0,
|
|
145
|
+
left: 0,
|
|
146
|
+
right: 0,
|
|
147
|
+
bottom: 0,
|
|
148
|
+
pointerEvents: 'none',
|
|
149
|
+
},
|
|
150
|
+
contentLayer: {
|
|
151
|
+
position: 'relative',
|
|
152
|
+
zIndex: 1,
|
|
153
|
+
},
|
|
154
|
+
}), []);
|
|
155
|
+
return (_jsxs(View, { style: [styles.container, { borderRadius }, style], onLayout: handleLayout, children: [containerSize.width > 0 && containerSize.height > 0 && (_jsxs(View, { style: styles.animationLayer, children: [_jsx(MovingGlow, { duration: duration, phase: 0, glowSize: glowSize, glowColor: effectiveGlowColor, containerWidth: containerSize.width, containerHeight: containerSize.height }), _jsx(MovingGlow, { duration: duration, phase: 0.5, glowSize: glowSize, glowColor: effectiveGlowColor, containerWidth: containerSize.width, containerHeight: containerSize.height })] })), _jsx(View, { style: styles.contentLayer, children: children })] }));
|
|
156
|
+
};
|
|
157
|
+
SMovingBorder.displayName = 'SMovingBorder';
|
|
158
|
+
export default SMovingBorder;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/s-multi-select/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SMultiSelect } from './s-multi-select';
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props interface for SMultiSelect component
|
|
4
|
+
* Synced with web SMultiSelect from @solostylist/ui-kit
|
|
5
|
+
* @template T - Type of the option values (string, number, or boolean)
|
|
6
|
+
*/
|
|
7
|
+
export interface SMultiSelectProps<T = string> {
|
|
8
|
+
/** Label text displayed above the select field */
|
|
9
|
+
label: string;
|
|
10
|
+
/** Callback fired when the selection changes */
|
|
11
|
+
onChange?: (value: T[]) => void;
|
|
12
|
+
/** Array of options with label and value pairs */
|
|
13
|
+
options: readonly {
|
|
14
|
+
label: string;
|
|
15
|
+
value: T;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
}[];
|
|
18
|
+
/** Currently selected values */
|
|
19
|
+
value: T[];
|
|
20
|
+
/** Placeholder text shown when no option is selected */
|
|
21
|
+
placeholder?: string;
|
|
22
|
+
/** Visual style variant */
|
|
23
|
+
variant?: 'outlined' | 'flat';
|
|
24
|
+
/** Enable search/filter functionality in the dropdown */
|
|
25
|
+
searchable?: boolean;
|
|
26
|
+
/** Placeholder text for the search input */
|
|
27
|
+
searchPlaceholder?: string;
|
|
28
|
+
/** Whether the field is disabled */
|
|
29
|
+
disabled?: boolean;
|
|
30
|
+
/** Input size variant */
|
|
31
|
+
size?: 'small' | 'medium';
|
|
32
|
+
/** Error message to display below the field */
|
|
33
|
+
error?: string;
|
|
34
|
+
/** Whether the field is required (shows asterisk in label) */
|
|
35
|
+
required?: boolean;
|
|
36
|
+
/** Help text shown below the input */
|
|
37
|
+
hint?: string;
|
|
38
|
+
/** Color variant for the chips */
|
|
39
|
+
chipColor?: 'default' | 'primary' | 'secondary' | 'success' | 'error' | 'info' | 'warning';
|
|
40
|
+
/** Variant for the chips */
|
|
41
|
+
chipVariant?: 'filled' | 'outlined';
|
|
42
|
+
/** Size for the chips */
|
|
43
|
+
chipSize?: 'small' | 'medium';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A multi-selection dropdown component that displays selected items as chips.
|
|
47
|
+
* Unlike SSelect with multiple mode, this doesn't show checkboxes - just toggleable menu items.
|
|
48
|
+
* Synced with web SMultiSelect from @solostylist/ui-kit and matches SSelect styling.
|
|
49
|
+
*/
|
|
50
|
+
export declare function SMultiSelect<T = string>({ label, onChange, options, value, placeholder, variant, searchable, searchPlaceholder, disabled, size, error, required, hint, chipColor, chipVariant, chipSize, }: SMultiSelectProps<T>): React.JSX.Element;
|
|
51
|
+
export declare namespace SMultiSelect {
|
|
52
|
+
var displayName: string;
|
|
53
|
+
}
|
|
54
|
+
export default SMultiSelect;
|
|
55
|
+
//# sourceMappingURL=s-multi-select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s-multi-select.d.ts","sourceRoot":"","sources":["../../src/s-multi-select/s-multi-select.tsx"],"names":[],"mappings":"AACA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAQtE;;;;GAIG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC,GAAG,MAAM;IAC3C,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;IAChC,kDAAkD;IAClD,OAAO,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IACpE,gCAAgC;IAChC,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAC9B,yDAAyD;IACzD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,4CAA4C;IAC5C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yBAAyB;IACzB,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC1B,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IAC3F,4BAA4B;IAC5B,WAAW,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IACpC,yBAAyB;IACzB,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC/B;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,GAAG,MAAM,EAAE,EACvC,KAAK,EACL,QAAQ,EACR,OAAO,EACP,KAAU,EACV,WAAyB,EACzB,OAAoB,EACpB,UAAkB,EAClB,iBAA+B,EAC/B,QAAgB,EAChB,IAAe,EACf,KAAK,EACL,QAAgB,EAChB,IAAI,EACJ,SAAqB,EACrB,WAAsB,EACtB,QAAkB,GACnB,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAwT1C;yBAzUe,YAAY;;;AA6U5B,eAAe,YAAY,CAAC"}
|