@situaction/traquiste-mobile 1.0.0-next.2
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/.eslintrc.js +5 -0
- package/.releaserc +12 -0
- package/CLAUDE.md +25 -0
- package/README.md +124 -0
- package/app.json +5 -0
- package/bitbucket-pipelines.yml +81 -0
- package/build/components/Button/Button.d.ts +31 -0
- package/build/components/Button/Button.d.ts.map +1 -0
- package/build/components/Button/Button.js +67 -0
- package/build/components/Button/Button.js.map +1 -0
- package/build/components/Button/Button.stories.d.ts +19 -0
- package/build/components/Button/Button.stories.d.ts.map +1 -0
- package/build/components/Button/Button.stories.js +95 -0
- package/build/components/Button/Button.stories.js.map +1 -0
- package/build/components/Button/index.d.ts +3 -0
- package/build/components/Button/index.d.ts.map +1 -0
- package/build/components/Button/index.js +2 -0
- package/build/components/Button/index.js.map +1 -0
- package/build/components/ButtonAction/ButtonAction.d.ts +21 -0
- package/build/components/ButtonAction/ButtonAction.d.ts.map +1 -0
- package/build/components/ButtonAction/ButtonAction.js +35 -0
- package/build/components/ButtonAction/ButtonAction.js.map +1 -0
- package/build/components/ButtonAction/ButtonAction.stories.d.ts +13 -0
- package/build/components/ButtonAction/ButtonAction.stories.d.ts.map +1 -0
- package/build/components/ButtonAction/ButtonAction.stories.js +51 -0
- package/build/components/ButtonAction/ButtonAction.stories.js.map +1 -0
- package/build/components/ButtonAction/index.d.ts +3 -0
- package/build/components/ButtonAction/index.d.ts.map +1 -0
- package/build/components/ButtonAction/index.js +2 -0
- package/build/components/ButtonAction/index.js.map +1 -0
- package/build/components/ButtonMap/ButtonMap.d.ts +18 -0
- package/build/components/ButtonMap/ButtonMap.d.ts.map +1 -0
- package/build/components/ButtonMap/ButtonMap.js +17 -0
- package/build/components/ButtonMap/ButtonMap.js.map +1 -0
- package/build/components/ButtonMap/ButtonMap.stories.d.ts +12 -0
- package/build/components/ButtonMap/ButtonMap.stories.d.ts.map +1 -0
- package/build/components/ButtonMap/ButtonMap.stories.js +36 -0
- package/build/components/ButtonMap/ButtonMap.stories.js.map +1 -0
- package/build/components/ButtonMap/index.d.ts +3 -0
- package/build/components/ButtonMap/index.d.ts.map +1 -0
- package/build/components/ButtonMap/index.js +2 -0
- package/build/components/ButtonMap/index.js.map +1 -0
- package/build/components/ButtonMenu/ButtonMenu.d.ts +21 -0
- package/build/components/ButtonMenu/ButtonMenu.d.ts.map +1 -0
- package/build/components/ButtonMenu/ButtonMenu.js +56 -0
- package/build/components/ButtonMenu/ButtonMenu.js.map +1 -0
- package/build/components/ButtonMenu/ButtonMenu.stories.d.ts +15 -0
- package/build/components/ButtonMenu/ButtonMenu.stories.d.ts.map +1 -0
- package/build/components/ButtonMenu/ButtonMenu.stories.js +52 -0
- package/build/components/ButtonMenu/ButtonMenu.stories.js.map +1 -0
- package/build/components/ButtonMenu/index.d.ts +3 -0
- package/build/components/ButtonMenu/index.d.ts.map +1 -0
- package/build/components/ButtonMenu/index.js +2 -0
- package/build/components/ButtonMenu/index.js.map +1 -0
- package/build/components/FilterChip/FilterChip.d.ts +28 -0
- package/build/components/FilterChip/FilterChip.d.ts.map +1 -0
- package/build/components/FilterChip/FilterChip.js +66 -0
- package/build/components/FilterChip/FilterChip.js.map +1 -0
- package/build/components/FilterChip/FilterChip.stories.d.ts +15 -0
- package/build/components/FilterChip/FilterChip.stories.d.ts.map +1 -0
- package/build/components/FilterChip/FilterChip.stories.js +55 -0
- package/build/components/FilterChip/FilterChip.stories.js.map +1 -0
- package/build/components/FilterChip/index.d.ts +3 -0
- package/build/components/FilterChip/index.d.ts.map +1 -0
- package/build/components/FilterChip/index.js +2 -0
- package/build/components/FilterChip/index.js.map +1 -0
- package/build/constants/colors.d.ts +2 -0
- package/build/constants/colors.d.ts.map +1 -0
- package/build/constants/colors.js +3 -0
- package/build/constants/colors.js.map +1 -0
- package/build/context/ThemeContext.d.ts +30 -0
- package/build/context/ThemeContext.d.ts.map +1 -0
- package/build/context/ThemeContext.js +34 -0
- package/build/context/ThemeContext.js.map +1 -0
- package/build/index.d.ts +7 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +8 -0
- package/build/index.js.map +1 -0
- package/build/theme/index.d.ts +5 -0
- package/build/theme/index.d.ts.map +1 -0
- package/build/theme/index.js +6 -0
- package/build/theme/index.js.map +1 -0
- package/build/theme/tokens/dark.d.ts +8 -0
- package/build/theme/tokens/dark.d.ts.map +1 -0
- package/build/theme/tokens/dark.js +146 -0
- package/build/theme/tokens/dark.js.map +1 -0
- package/build/theme/tokens/light.d.ts +8 -0
- package/build/theme/tokens/light.d.ts.map +1 -0
- package/build/theme/tokens/light.js +152 -0
- package/build/theme/tokens/light.js.map +1 -0
- package/build/theme/type.d.ts +75 -0
- package/build/theme/type.d.ts.map +1 -0
- package/build/theme/type.js +7 -0
- package/build/theme/type.js.map +1 -0
- package/docs/README.md +73 -0
- package/docs/eslint.config.js +22 -0
- package/docs/index.html +16 -0
- package/docs/package-lock.json +5578 -0
- package/docs/package.json +37 -0
- package/docs/public/favicon.svg +1 -0
- package/docs/public/icons.svg +24 -0
- package/docs/src/App.css +184 -0
- package/docs/src/App.tsx +38 -0
- package/docs/src/assets/hero.png +0 -0
- package/docs/src/assets/react.svg +1 -0
- package/docs/src/assets/vite.svg +1 -0
- package/docs/src/components/Layout.tsx +108 -0
- package/docs/src/components/LiveEditor.tsx +294 -0
- package/docs/src/components/PropsTable.tsx +101 -0
- package/docs/src/components/Sidebar.tsx +103 -0
- package/docs/src/components/TableOfContents.tsx +75 -0
- package/docs/src/context/ColorModeContext.tsx +34 -0
- package/docs/src/index.css +76 -0
- package/docs/src/lib/createComponentPage.tsx +270 -0
- package/docs/src/main.tsx +13 -0
- package/docs/src/pages/Examples.tsx +273 -0
- package/docs/src/pages/Home.tsx +70 -0
- package/docs/src/pages/components/button-action.ts +88 -0
- package/docs/src/pages/components/button-map.ts +67 -0
- package/docs/src/pages/components/button-menu.ts +90 -0
- package/docs/src/pages/components/button.ts +158 -0
- package/docs/src/pages/components/filter-chip.ts +109 -0
- package/docs/tsconfig.app.json +32 -0
- package/docs/tsconfig.json +7 -0
- package/docs/tsconfig.node.json +24 -0
- package/docs/vite.config.ts +18 -0
- package/ios/.xcode.env +11 -0
- package/ios/Podfile +63 -0
- package/ios/Podfile.properties.json +4 -0
- package/ios/situactiontraquistemobile/AppDelegate.swift +69 -0
- package/ios/situactiontraquistemobile/Images.xcassets/AppIcon.appiconset/Contents.json +13 -0
- package/ios/situactiontraquistemobile/Images.xcassets/Contents.json +6 -0
- package/ios/situactiontraquistemobile/Images.xcassets/SplashScreenLegacy.imageset/Contents.json +21 -0
- package/ios/situactiontraquistemobile/Images.xcassets/SplashScreenLegacy.imageset/SplashScreenLegacy.png +0 -0
- package/ios/situactiontraquistemobile/Info.plist +53 -0
- package/ios/situactiontraquistemobile/SplashScreen.storyboard +47 -0
- package/ios/situactiontraquistemobile/Supporting/Expo.plist +6 -0
- package/ios/situactiontraquistemobile/situactiontraquistemobile-Bridging-Header.h +3 -0
- package/ios/situactiontraquistemobile.xcodeproj/project.pbxproj +432 -0
- package/ios/situactiontraquistemobile.xcodeproj/xcshareddata/xcschemes/situactiontraquistemobile.xcscheme +88 -0
- package/jest.config.js +197 -0
- package/package.json +90 -0
- package/src/components/.gitkeep +0 -0
- package/src/components/Button/Button.stories.tsx +123 -0
- package/src/components/Button/Button.tsx +128 -0
- package/src/components/Button/index.ts +2 -0
- package/src/components/ButtonAction/ButtonAction.stories.tsx +67 -0
- package/src/components/ButtonAction/ButtonAction.tsx +67 -0
- package/src/components/ButtonAction/index.ts +2 -0
- package/src/components/ButtonMap/ButtonMap.stories.tsx +49 -0
- package/src/components/ButtonMap/ButtonMap.tsx +40 -0
- package/src/components/ButtonMap/index.ts +2 -0
- package/src/components/ButtonMenu/ButtonMenu.stories.tsx +68 -0
- package/src/components/ButtonMenu/ButtonMenu.tsx +97 -0
- package/src/components/ButtonMenu/index.ts +2 -0
- package/src/components/FilterChip/FilterChip.stories.tsx +71 -0
- package/src/components/FilterChip/FilterChip.tsx +124 -0
- package/src/components/FilterChip/index.ts +2 -0
- package/src/constants/colors.ts +2 -0
- package/src/context/ThemeContext.tsx +84 -0
- package/src/index.ts +23 -0
- package/src/theme/index.ts +20 -0
- package/src/theme/tokens/dark.ts +160 -0
- package/src/theme/tokens/light.ts +166 -0
- package/src/theme/type.ts +122 -0
- package/src/types/.gitkeep +0 -0
- package/src/utils/.gitkeep +0 -0
- package/tsconfig.json +9 -0
package/.eslintrc.js
ADDED
package/.releaserc
ADDED
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Instructions Claude Code — traquiste-mobile
|
|
2
|
+
|
|
3
|
+
## Stack
|
|
4
|
+
Expo + TypeScript strict + StyleSheet natif. Zéro lib externe de styling.
|
|
5
|
+
|
|
6
|
+
## Conventions
|
|
7
|
+
- Commentaires en anglais, style concis
|
|
8
|
+
- /** Description composant */ en haut de chaque fichier
|
|
9
|
+
- Props documentées inline /** description */
|
|
10
|
+
|
|
11
|
+
## Commits
|
|
12
|
+
Convention semantic-release : feat / fix / chore / docs / test
|
|
13
|
+
|
|
14
|
+
## Tests
|
|
15
|
+
Jest + @testing-library/react-native.
|
|
16
|
+
Fichiers de test colocalisés : `ComponentName.test.tsx` dans le même dossier que le composant.
|
|
17
|
+
Lancer : `npm test -- --watchAll=false`
|
|
18
|
+
|
|
19
|
+
## Storybook
|
|
20
|
+
Local uniquement. Stories générées depuis le code du composant.
|
|
21
|
+
Format : même argTypes que traquiste-web (radio pour unions, boolean pour booléens).
|
|
22
|
+
|
|
23
|
+
## Doc Next.js
|
|
24
|
+
Une page par composant dans docs/pages/components/.
|
|
25
|
+
Playground interactif + éditeur code live bidirectionnel + props table.
|
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
|
|
2
|
+
# @situaction/traquiste-mobile
|
|
3
|
+
|
|
4
|
+
React Native UI component library for Traquiste — built with Expo + TypeScript strict + native StyleSheet.
|
|
5
|
+
|
|
6
|
+
## Requirements
|
|
7
|
+
|
|
8
|
+
- Node.js >= 18
|
|
9
|
+
- Xcode (iOS)
|
|
10
|
+
- CocoaPods
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
npm install @situaction/traquiste-mobile
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Peer dependencies required in your project:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npm install expo react react-native
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Development
|
|
27
|
+
|
|
28
|
+
### 1. Clone and install
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
git clone git@bitbucket.org:situaction/traquiste-mobile.git
|
|
32
|
+
cd traquiste-mobile
|
|
33
|
+
npm install
|
|
34
|
+
cd example && npm install --legacy-peer-deps && cd ..
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. Build the library
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
npm run build
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 3. First time — build the native binary
|
|
44
|
+
|
|
45
|
+
The `example/ios/` directory is not committed and must be generated locally.
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
cd example
|
|
49
|
+
|
|
50
|
+
# iOS simulator
|
|
51
|
+
npx expo run:ios
|
|
52
|
+
|
|
53
|
+
# iOS device (connect via USB)
|
|
54
|
+
npx expo run:ios --device
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
> Rebuild required each time a native dependency is added.
|
|
58
|
+
|
|
59
|
+
### 4. Run tests
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
npm test
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Tests run with Jest + `@testing-library/react-native`. Use `--watchAll=false` for a single run (e.g. in CI):
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
npm test -- --watchAll=false
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Test files live in `src/` alongside their components: `ComponentName.test.tsx`.
|
|
72
|
+
|
|
73
|
+
### 5. Run Storybook
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
npm run storybook
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Storybook runs directly on the simulator/device — not in a browser. Open the `TraquisteMobileExample` app on your device to see the Storybook UI.
|
|
80
|
+
|
|
81
|
+
Any change in `src/` is reflected instantly via hot reload.
|
|
82
|
+
|
|
83
|
+
> If port 8081 is already in use, Metro will prompt to use another port. Update the bundle location in the app dev menu (shake device → **Change Bundle Location**).
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Scripts
|
|
88
|
+
|
|
89
|
+
| Command | Description |
|
|
90
|
+
| -------- | ----------- |
|
|
91
|
+
| `npm run build` | Compile TypeScript to `build/` |
|
|
92
|
+
| `npm run lint` | Type-check without emitting |
|
|
93
|
+
| `npm test` | Run Jest tests |
|
|
94
|
+
| `npm run storybook` | Start Storybook on simulator/device |
|
|
95
|
+
|
|
96
|
+
## Versioning
|
|
97
|
+
|
|
98
|
+
Releases are automated via [semantic-release](https://semantic-release.gitbook.io/) on push to `master` and `develop`.
|
|
99
|
+
|
|
100
|
+
Commit convention:
|
|
101
|
+
|
|
102
|
+
| Prefix | Effect |
|
|
103
|
+
| ------ | ------- |
|
|
104
|
+
| `feat:` | Minor release (1.x.0) |
|
|
105
|
+
| `fix:` | Patch release (1.0.x) |
|
|
106
|
+
| `feat!:` / `BREAKING CHANGE` | Major release (x.0.0) |
|
|
107
|
+
| `chore:` / `docs:` / `test:` | No release |
|
|
108
|
+
|
|
109
|
+
Branches:
|
|
110
|
+
|
|
111
|
+
- `master` → published as `latest` on npm
|
|
112
|
+
- `develop` → published as `next` on npm (prerelease)
|
|
113
|
+
|
|
114
|
+
## Stack
|
|
115
|
+
|
|
116
|
+
- Expo SDK 55 / React Native 0.83.6 / React 19.2
|
|
117
|
+
- TypeScript strict
|
|
118
|
+
- Storybook React Native v10
|
|
119
|
+
- semantic-release + Bitbucket Pipelines
|
|
120
|
+
- Zero external styling libraries
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
MIT
|
package/app.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
image: node:22
|
|
2
|
+
|
|
3
|
+
definitions:
|
|
4
|
+
caches:
|
|
5
|
+
npm: ~/.npm
|
|
6
|
+
|
|
7
|
+
steps:
|
|
8
|
+
- step: &build
|
|
9
|
+
name: Build
|
|
10
|
+
caches: [npm]
|
|
11
|
+
script:
|
|
12
|
+
- npm ci --ignore-scripts
|
|
13
|
+
- npm run build
|
|
14
|
+
artifacts:
|
|
15
|
+
- build/**
|
|
16
|
+
|
|
17
|
+
- step: &test
|
|
18
|
+
name: Test
|
|
19
|
+
caches: [npm]
|
|
20
|
+
script:
|
|
21
|
+
- npm ci --ignore-scripts
|
|
22
|
+
- npm test -- --ci --passWithNoTests
|
|
23
|
+
|
|
24
|
+
- step: &build-docs
|
|
25
|
+
name: Build Docs
|
|
26
|
+
caches: [npm]
|
|
27
|
+
script:
|
|
28
|
+
- npm ci --ignore-scripts
|
|
29
|
+
- cd docs && npm ci --ignore-scripts && npm run build
|
|
30
|
+
artifacts:
|
|
31
|
+
- docs/dist/**
|
|
32
|
+
|
|
33
|
+
- step: &deploy-docs
|
|
34
|
+
name: Deploy Docs
|
|
35
|
+
clone:
|
|
36
|
+
enabled: false
|
|
37
|
+
script:
|
|
38
|
+
- pipe: atlassian/aws-s3-deploy:1.6.0
|
|
39
|
+
variables:
|
|
40
|
+
AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
|
|
41
|
+
AWS_SECRET_ACCESS_KEY: $AWS_SECRET_KEY
|
|
42
|
+
AWS_DEFAULT_REGION: "eu-west-3"
|
|
43
|
+
S3_BUCKET: $DOCS_S3_BUCKET
|
|
44
|
+
LOCAL_PATH: 'docs/dist'
|
|
45
|
+
DELETE_FLAG: 'true'
|
|
46
|
+
- pipe: atlassian/aws-cloudfront-invalidate:0.6.0
|
|
47
|
+
variables:
|
|
48
|
+
AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
|
|
49
|
+
AWS_SECRET_ACCESS_KEY: $AWS_SECRET_KEY
|
|
50
|
+
AWS_DEFAULT_REGION: "eu-west-3"
|
|
51
|
+
DISTRIBUTION_ID: $CLOUDFRONT_DISTRIBUTION_ID
|
|
52
|
+
|
|
53
|
+
- step: &publish
|
|
54
|
+
name: Publish
|
|
55
|
+
trigger: manual
|
|
56
|
+
script:
|
|
57
|
+
- npm ci --ignore-scripts
|
|
58
|
+
- npx semantic-release
|
|
59
|
+
|
|
60
|
+
pipelines:
|
|
61
|
+
pull-requests:
|
|
62
|
+
'**':
|
|
63
|
+
- step: *build
|
|
64
|
+
- step: *test
|
|
65
|
+
|
|
66
|
+
branches:
|
|
67
|
+
master:
|
|
68
|
+
- step: *build
|
|
69
|
+
- step: *test
|
|
70
|
+
- step:
|
|
71
|
+
<<: *build-docs
|
|
72
|
+
deployment: Production
|
|
73
|
+
- step:
|
|
74
|
+
<<: *deploy-docs
|
|
75
|
+
deployment: Production_AWS
|
|
76
|
+
- step: *publish
|
|
77
|
+
|
|
78
|
+
develop:
|
|
79
|
+
- step: *build
|
|
80
|
+
- step: *test
|
|
81
|
+
- step: *publish
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Button component for Traq[UI]ste Mobile.
|
|
3
|
+
* Supports four variants, four sizes and three content layouts.
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
7
|
+
export type ButtonVariant = 'primary' | 'tertiary' | 'ghost' | 'destructive';
|
|
8
|
+
export type ButtonSize = 'S' | 'M' | 'L' | 'XL';
|
|
9
|
+
export type ButtonContent = 'icon-only' | 'icon-only-rounded' | 'icon-both';
|
|
10
|
+
export interface ButtonProps {
|
|
11
|
+
/** Button visual variant */
|
|
12
|
+
variant?: ButtonVariant;
|
|
13
|
+
/** Button size */
|
|
14
|
+
size?: ButtonSize;
|
|
15
|
+
/** Content layout */
|
|
16
|
+
content?: ButtonContent;
|
|
17
|
+
/** Label text — required when content is 'icon-both' */
|
|
18
|
+
label?: string;
|
|
19
|
+
/** Left icon component (Phosphor icon) */
|
|
20
|
+
iconLeft?: React.ReactElement;
|
|
21
|
+
/** Right icon component (Phosphor icon) */
|
|
22
|
+
iconRight?: React.ReactElement;
|
|
23
|
+
/** Disabled state */
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
/** Press handler */
|
|
26
|
+
onPress?: () => void;
|
|
27
|
+
/** Additional container styles */
|
|
28
|
+
style?: StyleProp<ViewStyle>;
|
|
29
|
+
}
|
|
30
|
+
export declare function Button({ variant, size, content, label, iconLeft, iconRight, disabled, onPress, style, }: ButtonProps): React.JSX.Element;
|
|
31
|
+
//# sourceMappingURL=Button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,GAAG,aAAa,CAAC;AAC7E,MAAM,MAAM,UAAU,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC;AAChD,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,mBAAmB,GAAG,WAAW,CAAC;AAE5E,MAAM,WAAW,WAAW;IAC1B,4BAA4B;IAC5B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,kBAAkB;IAClB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,qBAAqB;IACrB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;IAC9B,2CAA2C;IAC3C,SAAS,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;IAC/B,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,kCAAkC;IAClC,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAaD,wBAAgB,MAAM,CAAC,EACrB,OAAmB,EACnB,IAAU,EACV,OAAqB,EACrB,KAAK,EACL,QAAQ,EACR,SAAS,EACT,QAAgB,EAChB,OAAO,EACP,KAAK,GACN,EAAE,WAAW,qBAwEb"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Button component for Traq[UI]ste Mobile.
|
|
3
|
+
* Supports four variants, four sizes and three content layouts.
|
|
4
|
+
*/
|
|
5
|
+
import React, { useState } from 'react';
|
|
6
|
+
import { Pressable, Text } from 'react-native';
|
|
7
|
+
import { useTheme } from '../../context/ThemeContext';
|
|
8
|
+
// --- Size tokens (static, theme-independent) ---
|
|
9
|
+
const SIZE_TOKENS = {
|
|
10
|
+
S: { height: 36, paddingVertical: 10, paddingHorizontal: 10, gap: 8, borderRadius: 8, iconSize: 16, fontSize: 12, lineHeight: 16 },
|
|
11
|
+
M: { height: 40, paddingVertical: 10, paddingHorizontal: 16, gap: 4, borderRadius: 8, iconSize: 18, fontSize: 14, lineHeight: 20 },
|
|
12
|
+
L: { height: 48, paddingVertical: 12, paddingHorizontal: 12, gap: 10, borderRadius: 8, iconSize: 20, fontSize: 16, lineHeight: 24 },
|
|
13
|
+
XL: { height: 60, paddingVertical: 16, paddingHorizontal: 32, gap: 12, borderRadius: 8, iconSize: 24, fontSize: 18, lineHeight: 26 },
|
|
14
|
+
};
|
|
15
|
+
// --- Component ---
|
|
16
|
+
export function Button({ variant = 'primary', size = 'M', content = 'icon-both', label, iconLeft, iconRight, disabled = false, onPress, style, }) {
|
|
17
|
+
const [pressed, setPressed] = useState(false);
|
|
18
|
+
const { colors } = useTheme();
|
|
19
|
+
const sizeTokens = SIZE_TOKENS[size];
|
|
20
|
+
const state = disabled ? 'disabled' : pressed ? 'pressed' : 'default';
|
|
21
|
+
const colorTokens = colors.button[variant][state];
|
|
22
|
+
const isIconOnly = content === 'icon-only' || content === 'icon-only-rounded';
|
|
23
|
+
const borderRadius = content === 'icon-only-rounded' ? 9999 : sizeTokens.borderRadius;
|
|
24
|
+
const hasBorder = colorTokens.border !== 'transparent';
|
|
25
|
+
const containerStyle = {
|
|
26
|
+
height: sizeTokens.height,
|
|
27
|
+
paddingVertical: isIconOnly ? undefined : sizeTokens.paddingVertical,
|
|
28
|
+
paddingHorizontal: isIconOnly ? undefined : sizeTokens.paddingHorizontal,
|
|
29
|
+
width: isIconOnly ? sizeTokens.height : undefined,
|
|
30
|
+
borderRadius,
|
|
31
|
+
gap: sizeTokens.gap,
|
|
32
|
+
backgroundColor: colorTokens.background,
|
|
33
|
+
borderWidth: hasBorder ? 1 : undefined,
|
|
34
|
+
borderColor: hasBorder ? colorTokens.border : undefined,
|
|
35
|
+
alignItems: 'center',
|
|
36
|
+
justifyContent: 'center',
|
|
37
|
+
flexDirection: 'row',
|
|
38
|
+
};
|
|
39
|
+
const textStyle = {
|
|
40
|
+
color: colorTokens.text,
|
|
41
|
+
fontSize: sizeTokens.fontSize,
|
|
42
|
+
lineHeight: sizeTokens.lineHeight,
|
|
43
|
+
fontFamily: 'Urbanist',
|
|
44
|
+
fontWeight: '500',
|
|
45
|
+
};
|
|
46
|
+
// Clone icon elements to inject size and color from active theme state
|
|
47
|
+
const cloneIcon = (icon) => {
|
|
48
|
+
if (!icon)
|
|
49
|
+
return null;
|
|
50
|
+
return React.cloneElement(icon, {
|
|
51
|
+
size: sizeTokens.iconSize,
|
|
52
|
+
color: colorTokens.icon,
|
|
53
|
+
...icon.props,
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
if (isIconOnly) {
|
|
57
|
+
return (<Pressable pointerEvents={disabled ? 'none' : 'auto'} onPressIn={() => setPressed(true)} onPressOut={() => setPressed(false)} onPress={disabled ? undefined : onPress} style={[containerStyle, style]}>
|
|
58
|
+
{cloneIcon(iconLeft)}
|
|
59
|
+
</Pressable>);
|
|
60
|
+
}
|
|
61
|
+
return (<Pressable pointerEvents={disabled ? 'none' : 'auto'} onPressIn={() => setPressed(true)} onPressOut={() => setPressed(false)} onPress={disabled ? undefined : onPress} style={[containerStyle, style]}>
|
|
62
|
+
{cloneIcon(iconLeft)}
|
|
63
|
+
{label != null && <Text style={textStyle}>{label}</Text>}
|
|
64
|
+
{cloneIcon(iconRight)}
|
|
65
|
+
</Pressable>);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=Button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.js","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * Button component for Traq[UI]ste Mobile.\n * Supports four variants, four sizes and three content layouts.\n */\nimport React, { useState } from 'react';\nimport { Pressable, Text } from 'react-native';\nimport type { StyleProp, ViewStyle } from 'react-native';\nimport { useTheme } from '../../context/ThemeContext';\n\nexport type ButtonVariant = 'primary' | 'tertiary' | 'ghost' | 'destructive';\nexport type ButtonSize = 'S' | 'M' | 'L' | 'XL';\nexport type ButtonContent = 'icon-only' | 'icon-only-rounded' | 'icon-both';\n\nexport interface ButtonProps {\n /** Button visual variant */\n variant?: ButtonVariant;\n /** Button size */\n size?: ButtonSize;\n /** Content layout */\n content?: ButtonContent;\n /** Label text — required when content is 'icon-both' */\n label?: string;\n /** Left icon component (Phosphor icon) */\n iconLeft?: React.ReactElement;\n /** Right icon component (Phosphor icon) */\n iconRight?: React.ReactElement;\n /** Disabled state */\n disabled?: boolean;\n /** Press handler */\n onPress?: () => void;\n /** Additional container styles */\n style?: StyleProp<ViewStyle>;\n}\n\n// --- Size tokens (static, theme-independent) ---\n\nconst SIZE_TOKENS = {\n S: { height: 36, paddingVertical: 10, paddingHorizontal: 10, gap: 8, borderRadius: 8, iconSize: 16, fontSize: 12, lineHeight: 16 },\n M: { height: 40, paddingVertical: 10, paddingHorizontal: 16, gap: 4, borderRadius: 8, iconSize: 18, fontSize: 14, lineHeight: 20 },\n L: { height: 48, paddingVertical: 12, paddingHorizontal: 12, gap: 10, borderRadius: 8, iconSize: 20, fontSize: 16, lineHeight: 24 },\n XL: { height: 60, paddingVertical: 16, paddingHorizontal: 32, gap: 12, borderRadius: 8, iconSize: 24, fontSize: 18, lineHeight: 26 },\n} as const;\n\n// --- Component ---\n\nexport function Button({\n variant = 'primary',\n size = 'M',\n content = 'icon-both',\n label,\n iconLeft,\n iconRight,\n disabled = false,\n onPress,\n style,\n}: ButtonProps) {\n const [pressed, setPressed] = useState(false);\n const { colors } = useTheme();\n\n const sizeTokens = SIZE_TOKENS[size];\n const state = disabled ? 'disabled' : pressed ? 'pressed' : 'default';\n const colorTokens = colors.button[variant][state];\n\n const isIconOnly = content === 'icon-only' || content === 'icon-only-rounded';\n const borderRadius = content === 'icon-only-rounded' ? 9999 : sizeTokens.borderRadius;\n const hasBorder = colorTokens.border !== 'transparent';\n\n const containerStyle: ViewStyle = {\n height: sizeTokens.height,\n paddingVertical: isIconOnly ? undefined : sizeTokens.paddingVertical,\n paddingHorizontal: isIconOnly ? undefined : sizeTokens.paddingHorizontal,\n width: isIconOnly ? sizeTokens.height : undefined,\n borderRadius,\n gap: sizeTokens.gap,\n backgroundColor: colorTokens.background,\n borderWidth: hasBorder ? 1 : undefined,\n borderColor: hasBorder ? colorTokens.border : undefined,\n alignItems: 'center',\n justifyContent: 'center',\n flexDirection: 'row',\n };\n\n const textStyle = {\n color: colorTokens.text,\n fontSize: sizeTokens.fontSize,\n lineHeight: sizeTokens.lineHeight,\n fontFamily: 'Urbanist',\n fontWeight: '500' as const,\n };\n\n // Clone icon elements to inject size and color from active theme state\n const cloneIcon = (icon: React.ReactElement | undefined) => {\n if (!icon) return null;\n return React.cloneElement(icon, {\n size: sizeTokens.iconSize,\n color: colorTokens.icon,\n ...(icon.props as Record<string, unknown>),\n } as object);\n };\n\n if (isIconOnly) {\n return (\n <Pressable\n pointerEvents={disabled ? 'none' : 'auto'}\n onPressIn={() => setPressed(true)}\n onPressOut={() => setPressed(false)}\n onPress={disabled ? undefined : onPress}\n style={[containerStyle, style]}\n >\n {cloneIcon(iconLeft)}\n </Pressable>\n );\n }\n\n return (\n <Pressable\n pointerEvents={disabled ? 'none' : 'auto'}\n onPressIn={() => setPressed(true)}\n onPressOut={() => setPressed(false)}\n onPress={disabled ? undefined : onPress}\n style={[containerStyle, style]}\n >\n {cloneIcon(iconLeft)}\n {label != null && <Text style={textStyle}>{label}</Text>}\n {cloneIcon(iconRight)}\n </Pressable>\n );\n}"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-native';
|
|
2
|
+
import { type ButtonProps } from './Button';
|
|
3
|
+
type StoryArgs = ButtonProps & {
|
|
4
|
+
colorScheme: 'light' | 'dark';
|
|
5
|
+
};
|
|
6
|
+
declare const meta: Meta<StoryArgs>;
|
|
7
|
+
export default meta;
|
|
8
|
+
type Story = StoryObj<StoryArgs>;
|
|
9
|
+
export declare const Primary: Story;
|
|
10
|
+
export declare const Tertiary: Story;
|
|
11
|
+
export declare const Ghost: Story;
|
|
12
|
+
export declare const Destructive: Story;
|
|
13
|
+
export declare const WithIconLeft: Story;
|
|
14
|
+
export declare const WithIconRight: Story;
|
|
15
|
+
export declare const WithIconBoth: Story;
|
|
16
|
+
export declare const IconOnly: Story;
|
|
17
|
+
export declare const AllSizes: Story;
|
|
18
|
+
export declare const Disabled: Story;
|
|
19
|
+
//# sourceMappingURL=Button.stories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.stories.d.ts","sourceRoot":"","sources":["../../../src/components/Button/Button.stories.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAG9D,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAEpD,KAAK,SAAS,GAAG,WAAW,GAAG;IAAE,WAAW,EAAE,OAAO,GAAG,MAAM,CAAA;CAAE,CAAC;AAEjE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,SAAS,CA+BzB,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;AAEjC,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAEtB,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,KAEnB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAEzB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAS1B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAO3B,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAO1B,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAStB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAStB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAStB,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/** Storybook stories for the Button component */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { View } from 'react-native';
|
|
4
|
+
import { ArrowRight, Check, Trash, Plus, X, MagnifyingGlass } from 'phosphor-react-native';
|
|
5
|
+
import { Button } from './Button';
|
|
6
|
+
const meta = {
|
|
7
|
+
title: 'Components/Button',
|
|
8
|
+
component: Button,
|
|
9
|
+
render: ({ colorScheme: _colorScheme, ...args }) => <Button {...args}/>,
|
|
10
|
+
argTypes: {
|
|
11
|
+
colorScheme: {
|
|
12
|
+
control: { type: 'radio' },
|
|
13
|
+
options: ['light', 'dark'],
|
|
14
|
+
},
|
|
15
|
+
variant: {
|
|
16
|
+
control: { type: 'radio' },
|
|
17
|
+
options: ['primary', 'tertiary', 'ghost', 'destructive'],
|
|
18
|
+
},
|
|
19
|
+
size: {
|
|
20
|
+
control: { type: 'radio' },
|
|
21
|
+
options: ['S', 'M', 'L', 'XL'],
|
|
22
|
+
},
|
|
23
|
+
content: {
|
|
24
|
+
control: { type: 'radio' },
|
|
25
|
+
options: ['icon-only', 'icon-only-rounded', 'icon-both'],
|
|
26
|
+
},
|
|
27
|
+
disabled: { control: { type: 'boolean' } },
|
|
28
|
+
},
|
|
29
|
+
args: {
|
|
30
|
+
colorScheme: 'light',
|
|
31
|
+
label: 'Button',
|
|
32
|
+
variant: 'primary',
|
|
33
|
+
size: 'M',
|
|
34
|
+
content: 'icon-both',
|
|
35
|
+
disabled: false,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
export default meta;
|
|
39
|
+
export const Primary = {
|
|
40
|
+
args: { variant: 'primary', label: 'Primary' },
|
|
41
|
+
};
|
|
42
|
+
export const Tertiary = {
|
|
43
|
+
args: { variant: 'tertiary', label: 'Tertiary' },
|
|
44
|
+
};
|
|
45
|
+
export const Ghost = {
|
|
46
|
+
args: { variant: 'ghost', label: 'Ghost' },
|
|
47
|
+
};
|
|
48
|
+
export const Destructive = {
|
|
49
|
+
args: { variant: 'destructive', label: 'Destructive' },
|
|
50
|
+
};
|
|
51
|
+
export const WithIconLeft = {
|
|
52
|
+
render: () => (<View style={{ gap: 12, padding: 16, alignItems: 'flex-start' }}>
|
|
53
|
+
<Button variant="primary" label="Rechercher" iconLeft={<MagnifyingGlass />}/>
|
|
54
|
+
<Button variant="tertiary" label="Ajouter" iconLeft={<Plus />}/>
|
|
55
|
+
<Button variant="ghost" label="Confirmer" iconLeft={<Check />}/>
|
|
56
|
+
<Button variant="destructive" label="Supprimer" iconLeft={<Trash />}/>
|
|
57
|
+
</View>),
|
|
58
|
+
};
|
|
59
|
+
export const WithIconRight = {
|
|
60
|
+
render: () => (<View style={{ gap: 12, padding: 16, alignItems: 'flex-start' }}>
|
|
61
|
+
<Button variant="primary" label="Suivant" iconRight={<ArrowRight />}/>
|
|
62
|
+
<Button variant="tertiary" label="Fermer" iconRight={<X />}/>
|
|
63
|
+
</View>),
|
|
64
|
+
};
|
|
65
|
+
export const WithIconBoth = {
|
|
66
|
+
render: () => (<View style={{ gap: 12, padding: 16, alignItems: 'flex-start' }}>
|
|
67
|
+
<Button variant="primary" label="Rechercher" iconLeft={<MagnifyingGlass />} iconRight={<ArrowRight />}/>
|
|
68
|
+
<Button variant="tertiary" label="Supprimer" iconLeft={<Trash />} iconRight={<X />}/>
|
|
69
|
+
</View>),
|
|
70
|
+
};
|
|
71
|
+
export const IconOnly = {
|
|
72
|
+
render: () => (<View style={{ flexDirection: 'row', gap: 12, padding: 16 }}>
|
|
73
|
+
<Button variant="primary" content="icon-only" iconLeft={<Plus />}/>
|
|
74
|
+
<Button variant="tertiary" content="icon-only" iconLeft={<MagnifyingGlass />}/>
|
|
75
|
+
<Button variant="ghost" content="icon-only" iconLeft={<X />}/>
|
|
76
|
+
<Button variant="destructive" content="icon-only-rounded" iconLeft={<Trash />}/>
|
|
77
|
+
</View>),
|
|
78
|
+
};
|
|
79
|
+
export const AllSizes = {
|
|
80
|
+
render: () => (<View style={{ gap: 12, padding: 16, alignItems: 'flex-start' }}>
|
|
81
|
+
<Button variant="primary" size="S" label="Small" iconLeft={<Check />}/>
|
|
82
|
+
<Button variant="primary" size="M" label="Medium" iconLeft={<Check />}/>
|
|
83
|
+
<Button variant="primary" size="L" label="Large" iconLeft={<Check />}/>
|
|
84
|
+
<Button variant="primary" size="XL" label="XLarge" iconLeft={<Check />}/>
|
|
85
|
+
</View>),
|
|
86
|
+
};
|
|
87
|
+
export const Disabled = {
|
|
88
|
+
render: () => (<View style={{ gap: 12, padding: 16, alignItems: 'flex-start' }}>
|
|
89
|
+
<Button variant="primary" disabled label="Primary" iconLeft={<Check />}/>
|
|
90
|
+
<Button variant="tertiary" disabled label="Tertiary" iconLeft={<Check />}/>
|
|
91
|
+
<Button variant="ghost" disabled label="Ghost" iconLeft={<Check />}/>
|
|
92
|
+
<Button variant="destructive" disabled label="Destructive" iconLeft={<Trash />}/>
|
|
93
|
+
</View>),
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=Button.stories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.stories.js","sourceRoot":"","sources":["../../../src/components/Button/Button.stories.tsx"],"names":[],"mappings":"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","sourcesContent":["/** Storybook stories for the Button component */\nimport React from 'react';\nimport type { Meta, StoryObj } from '@storybook/react-native';\nimport { View } from 'react-native';\nimport { ArrowRight, Check, Trash, Plus, X, MagnifyingGlass } from 'phosphor-react-native';\nimport { Button, type ButtonProps } from './Button';\n\ntype StoryArgs = ButtonProps & { colorScheme: 'light' | 'dark' };\n\nconst meta: Meta<StoryArgs> = {\n title: 'Components/Button',\n component: Button,\n render: ({ colorScheme: _colorScheme, ...args }) => <Button {...args} />,\n argTypes: {\n colorScheme: {\n control: { type: 'radio' },\n options: ['light', 'dark'],\n },\n variant: {\n control: { type: 'radio' },\n options: ['primary', 'tertiary', 'ghost', 'destructive'],\n },\n size: {\n control: { type: 'radio' },\n options: ['S', 'M', 'L', 'XL'],\n },\n content: {\n control: { type: 'radio' },\n options: ['icon-only', 'icon-only-rounded', 'icon-both'],\n },\n disabled: { control: { type: 'boolean' } },\n },\n args: {\n colorScheme: 'light',\n label: 'Button',\n variant: 'primary',\n size: 'M',\n content: 'icon-both',\n disabled: false,\n },\n};\n\nexport default meta;\n\ntype Story = StoryObj<StoryArgs>;\n\nexport const Primary: Story = {\n args: { variant: 'primary', label: 'Primary' },\n};\n\nexport const Tertiary: Story = {\n args: { variant: 'tertiary', label: 'Tertiary' },\n};\n\nexport const Ghost: Story = {\n args: { variant: 'ghost', label: 'Ghost' },\n};\n\nexport const Destructive: Story = {\n args: { variant: 'destructive', label: 'Destructive' },\n};\n\nexport const WithIconLeft: Story = {\n render: () => (\n <View style={{ gap: 12, padding: 16, alignItems: 'flex-start' }}>\n <Button variant=\"primary\" label=\"Rechercher\" iconLeft={<MagnifyingGlass />} />\n <Button variant=\"tertiary\" label=\"Ajouter\" iconLeft={<Plus />} />\n <Button variant=\"ghost\" label=\"Confirmer\" iconLeft={<Check />} />\n <Button variant=\"destructive\" label=\"Supprimer\" iconLeft={<Trash />} />\n </View>\n ),\n};\n\nexport const WithIconRight: Story = {\n render: () => (\n <View style={{ gap: 12, padding: 16, alignItems: 'flex-start' }}>\n <Button variant=\"primary\" label=\"Suivant\" iconRight={<ArrowRight />} />\n <Button variant=\"tertiary\" label=\"Fermer\" iconRight={<X />} />\n </View>\n ),\n};\n\nexport const WithIconBoth: Story = {\n render: () => (\n <View style={{ gap: 12, padding: 16, alignItems: 'flex-start' }}>\n <Button variant=\"primary\" label=\"Rechercher\" iconLeft={<MagnifyingGlass />} iconRight={<ArrowRight />} />\n <Button variant=\"tertiary\" label=\"Supprimer\" iconLeft={<Trash />} iconRight={<X />} />\n </View>\n ),\n};\n\nexport const IconOnly: Story = {\n render: () => (\n <View style={{ flexDirection: 'row', gap: 12, padding: 16 }}>\n <Button variant=\"primary\" content=\"icon-only\" iconLeft={<Plus />} />\n <Button variant=\"tertiary\" content=\"icon-only\" iconLeft={<MagnifyingGlass />} />\n <Button variant=\"ghost\" content=\"icon-only\" iconLeft={<X />} />\n <Button variant=\"destructive\" content=\"icon-only-rounded\" iconLeft={<Trash />} />\n </View>\n ),\n};\n\nexport const AllSizes: Story = {\n render: () => (\n <View style={{ gap: 12, padding: 16, alignItems: 'flex-start' }}>\n <Button variant=\"primary\" size=\"S\" label=\"Small\" iconLeft={<Check />} />\n <Button variant=\"primary\" size=\"M\" label=\"Medium\" iconLeft={<Check />} />\n <Button variant=\"primary\" size=\"L\" label=\"Large\" iconLeft={<Check />} />\n <Button variant=\"primary\" size=\"XL\" label=\"XLarge\" iconLeft={<Check />} />\n </View>\n ),\n};\n\nexport const Disabled: Story = {\n render: () => (\n <View style={{ gap: 12, padding: 16, alignItems: 'flex-start' }}>\n <Button variant=\"primary\" disabled label=\"Primary\" iconLeft={<Check />} />\n <Button variant=\"tertiary\" disabled label=\"Tertiary\" iconLeft={<Check />} />\n <Button variant=\"ghost\" disabled label=\"Ghost\" iconLeft={<Check />} />\n <Button variant=\"destructive\" disabled label=\"Destructive\" iconLeft={<Trash />} />\n </View>\n ),\n};"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Button/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/Button/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC","sourcesContent":["export { Button } from './Button';\nexport type { ButtonProps, ButtonVariant, ButtonSize, ButtonContent } from './Button';"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ButtonAction component — bare icon-only pressable with no background or border.
|
|
3
|
+
* Extends Button size range with XS and XXL sizes.
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
7
|
+
export type ButtonActionSize = 'XS' | 'S' | 'M' | 'L' | 'XL' | 'XXL';
|
|
8
|
+
export interface ButtonActionProps {
|
|
9
|
+
/** Icon component (Phosphor Duotone) */
|
|
10
|
+
icon: React.ReactElement;
|
|
11
|
+
/** Icon size */
|
|
12
|
+
size?: ButtonActionSize;
|
|
13
|
+
/** Disabled state */
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
/** Press handler */
|
|
16
|
+
onPress?: () => void;
|
|
17
|
+
/** Additional container styles */
|
|
18
|
+
style?: StyleProp<ViewStyle>;
|
|
19
|
+
}
|
|
20
|
+
export declare function ButtonAction({ icon, size, disabled, onPress, style, }: ButtonActionProps): React.JSX.Element;
|
|
21
|
+
//# sourceMappingURL=ButtonAction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ButtonAction.d.ts","sourceRoot":"","sources":["../../../src/components/ButtonAction/ButtonAction.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzD,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,KAAK,CAAC;AAErE,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,IAAI,EAAE,KAAK,CAAC,YAAY,CAAC;IACzB,gBAAgB;IAChB,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,kCAAkC;IAClC,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAWD,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,IAAU,EACV,QAAgB,EAChB,OAAO,EACP,KAAK,GACN,EAAE,iBAAiB,qBA2BnB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ButtonAction component — bare icon-only pressable with no background or border.
|
|
3
|
+
* Extends Button size range with XS and XXL sizes.
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { Pressable } from 'react-native';
|
|
7
|
+
import { useTheme } from '../../context/ThemeContext';
|
|
8
|
+
const ICON_SIZE = {
|
|
9
|
+
XS: 12,
|
|
10
|
+
S: 16,
|
|
11
|
+
M: 20,
|
|
12
|
+
L: 24,
|
|
13
|
+
XL: 28,
|
|
14
|
+
XXL: 32,
|
|
15
|
+
};
|
|
16
|
+
export function ButtonAction({ icon, size = 'M', disabled = false, onPress, style, }) {
|
|
17
|
+
const { colors } = useTheme();
|
|
18
|
+
const iconPx = ICON_SIZE[size];
|
|
19
|
+
const containerStyle = {
|
|
20
|
+
width: iconPx,
|
|
21
|
+
height: iconPx,
|
|
22
|
+
opacity: disabled ? 0.5 : 1,
|
|
23
|
+
alignItems: 'center',
|
|
24
|
+
justifyContent: 'center',
|
|
25
|
+
};
|
|
26
|
+
const clonedIcon = React.cloneElement(icon, {
|
|
27
|
+
size: iconPx,
|
|
28
|
+
color: colors.text.primary,
|
|
29
|
+
...icon.props,
|
|
30
|
+
});
|
|
31
|
+
return (<Pressable pointerEvents={disabled ? 'none' : 'auto'} onPress={disabled ? undefined : onPress} style={[containerStyle, style]}>
|
|
32
|
+
{clonedIcon}
|
|
33
|
+
</Pressable>);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=ButtonAction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ButtonAction.js","sourceRoot":"","sources":["../../../src/components/ButtonAction/ButtonAction.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAiBtD,MAAM,SAAS,GAAqC;IAClD,EAAE,EAAG,EAAE;IACP,CAAC,EAAI,EAAE;IACP,CAAC,EAAI,EAAE;IACP,CAAC,EAAI,EAAE;IACP,EAAE,EAAG,EAAE;IACP,GAAG,EAAE,EAAE;CACR,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,EAC3B,IAAI,EACJ,IAAI,GAAG,GAAG,EACV,QAAQ,GAAG,KAAK,EAChB,OAAO,EACP,KAAK,GACa;IAClB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAE/B,MAAM,cAAc,GAAc;QAChC,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3B,UAAU,EAAE,QAAQ;QACpB,cAAc,EAAE,QAAQ;KACzB,CAAC;IAEF,MAAM,UAAU,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE;QAC1C,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO;QAC1B,GAAI,IAAI,CAAC,KAAiC;KACjC,CAAC,CAAC;IAEb,OAAO,CACL,CAAC,SAAS,CACR,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAC1C,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CACxC,KAAK,CAAC,CAAC,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC,CAE/B;MAAA,CAAC,UAAU,CACb;IAAA,EAAE,SAAS,CAAC,CACb,CAAC;AACJ,CAAC","sourcesContent":["/**\n * ButtonAction component — bare icon-only pressable with no background or border.\n * Extends Button size range with XS and XXL sizes.\n */\nimport React from 'react';\nimport { Pressable } from 'react-native';\nimport type { StyleProp, ViewStyle } from 'react-native';\nimport { useTheme } from '../../context/ThemeContext';\n\nexport type ButtonActionSize = 'XS' | 'S' | 'M' | 'L' | 'XL' | 'XXL';\n\nexport interface ButtonActionProps {\n /** Icon component (Phosphor Duotone) */\n icon: React.ReactElement;\n /** Icon size */\n size?: ButtonActionSize;\n /** Disabled state */\n disabled?: boolean;\n /** Press handler */\n onPress?: () => void;\n /** Additional container styles */\n style?: StyleProp<ViewStyle>;\n}\n\nconst ICON_SIZE: Record<ButtonActionSize, number> = {\n XS: 12,\n S: 16,\n M: 20,\n L: 24,\n XL: 28,\n XXL: 32,\n};\n\nexport function ButtonAction({\n icon,\n size = 'M',\n disabled = false,\n onPress,\n style,\n}: ButtonActionProps) {\n const { colors } = useTheme();\n const iconPx = ICON_SIZE[size];\n\n const containerStyle: ViewStyle = {\n width: iconPx,\n height: iconPx,\n opacity: disabled ? 0.5 : 1,\n alignItems: 'center',\n justifyContent: 'center',\n };\n\n const clonedIcon = React.cloneElement(icon, {\n size: iconPx,\n color: colors.text.primary,\n ...(icon.props as Record<string, unknown>),\n } as object);\n\n return (\n <Pressable\n pointerEvents={disabled ? 'none' : 'auto'}\n onPress={disabled ? undefined : onPress}\n style={[containerStyle, style]}\n >\n {clonedIcon}\n </Pressable>\n );\n}"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-native';
|
|
2
|
+
import { type ButtonActionProps } from './ButtonAction';
|
|
3
|
+
type StoryArgs = ButtonActionProps & {
|
|
4
|
+
colorScheme: 'light' | 'dark';
|
|
5
|
+
};
|
|
6
|
+
declare const meta: Meta<StoryArgs>;
|
|
7
|
+
export default meta;
|
|
8
|
+
type Story = StoryObj<StoryArgs>;
|
|
9
|
+
export declare const Default: Story;
|
|
10
|
+
export declare const Disabled: Story;
|
|
11
|
+
export declare const AllSizes: Story;
|
|
12
|
+
export declare const AllIcons: Story;
|
|
13
|
+
//# sourceMappingURL=ButtonAction.stories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ButtonAction.stories.d.ts","sourceRoot":"","sources":["../../../src/components/ButtonAction/ButtonAction.stories.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAG9D,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEtE,KAAK,SAAS,GAAG,iBAAiB,GAAG;IAAE,WAAW,EAAE,OAAO,GAAG,MAAM,CAAA;CAAE,CAAC;AAEvE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,SAAS,CAsBzB,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;AAEjC,eAAO,MAAM,OAAO,EAAE,KAAU,CAAC;AAEjC,eAAO,MAAM,QAAQ,EAAE,KAEtB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAWtB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAUtB,CAAC"}
|