@scripso-homepad/ui 0.2.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/README.md +101 -0
- package/dist/index.cjs +47 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/package.json +78 -0
- package/src/components/Button.stories.tsx +34 -0
- package/src/components/Button.tsx +51 -0
- package/src/index.ts +2 -0
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# @scripso-homepad/ui
|
|
2
|
+
|
|
3
|
+
Cross-platform UI component library for Homepad. Components use React Native primitives and work in both **React Web** (via [react-native-web](https://necolas.github.io/react-native-web/)) and **React Native** (Expo).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @scripso-homepad/ui react react-native
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### React Web (Next.js)
|
|
12
|
+
|
|
13
|
+
Also install `react-native-web` and alias `react-native` → `react-native-web` in your bundler:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install react-native-web
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
// next.config.js
|
|
21
|
+
module.exports = {
|
|
22
|
+
transpilePackages: ["@scripso-homepad/ui", "react-native", "react-native-web"],
|
|
23
|
+
webpack: (config) => {
|
|
24
|
+
config.resolve.alias = {
|
|
25
|
+
...config.resolve.alias,
|
|
26
|
+
"react-native$": "react-native-web",
|
|
27
|
+
};
|
|
28
|
+
return config;
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### React Native (Expo)
|
|
34
|
+
|
|
35
|
+
Install from npm — no extra config needed:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install @scripso-homepad/ui
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { Button } from "@scripso-homepad/ui";
|
|
45
|
+
|
|
46
|
+
export function Example() {
|
|
47
|
+
return (
|
|
48
|
+
<Button
|
|
49
|
+
title="Press me"
|
|
50
|
+
onPress={() => console.log("pressed")}
|
|
51
|
+
disabled={false}
|
|
52
|
+
/>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## API
|
|
58
|
+
|
|
59
|
+
### `Button`
|
|
60
|
+
|
|
61
|
+
| Prop | Type | Required | Default | Description |
|
|
62
|
+
| ---------- | ------------ | -------- | ------- | -------------------- |
|
|
63
|
+
| `title` | `string` | Yes | — | Button label text |
|
|
64
|
+
| `onPress` | `() => void` | Yes | — | Press handler |
|
|
65
|
+
| `disabled` | `boolean` | No | `false` | Disables interaction |
|
|
66
|
+
|
|
67
|
+
## Development
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm install
|
|
71
|
+
npm run build
|
|
72
|
+
npm run typecheck
|
|
73
|
+
npm run lint
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Storybook
|
|
77
|
+
|
|
78
|
+
Preview components in the browser with hot reload:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm run storybook
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Opens at [http://localhost:6006](http://localhost:6006). Components render via `react-native-web`.
|
|
85
|
+
|
|
86
|
+
Build a static Storybook site:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npm run build-storybook
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Publishing
|
|
93
|
+
|
|
94
|
+
See [PUBLISHING.md](./PUBLISHING.md) for release workflow details.
|
|
95
|
+
|
|
96
|
+
## Architecture
|
|
97
|
+
|
|
98
|
+
- **Single shared implementation** — no `.web.tsx` / `.native.tsx` split
|
|
99
|
+
- **React Native primitives** — `TouchableOpacity`, `Text`, `StyleSheet`
|
|
100
|
+
- **Web via react-native-web** — consumers alias `react-native` at build time
|
|
101
|
+
- **Metro source resolution** — `"react-native"` export points to TypeScript source for native bundlers
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var reactNative = require('react-native');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
|
|
6
|
+
// src/components/Button.tsx
|
|
7
|
+
function Button({ title, onPress, disabled = false }) {
|
|
8
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9
|
+
reactNative.TouchableOpacity,
|
|
10
|
+
{
|
|
11
|
+
style: [styles.button, disabled && styles.buttonDisabled],
|
|
12
|
+
onPress,
|
|
13
|
+
disabled,
|
|
14
|
+
activeOpacity: 0.7,
|
|
15
|
+
accessibilityRole: "button",
|
|
16
|
+
accessibilityState: { disabled },
|
|
17
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.text, disabled && styles.textDisabled], children: title })
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
var styles = reactNative.StyleSheet.create({
|
|
22
|
+
button: {
|
|
23
|
+
backgroundColor: "#2563eb",
|
|
24
|
+
paddingVertical: 12,
|
|
25
|
+
paddingHorizontal: 24,
|
|
26
|
+
borderRadius: 8,
|
|
27
|
+
alignItems: "center",
|
|
28
|
+
justifyContent: "center",
|
|
29
|
+
minWidth: 120
|
|
30
|
+
},
|
|
31
|
+
buttonDisabled: {
|
|
32
|
+
backgroundColor: "#93c5fd",
|
|
33
|
+
opacity: 0.7
|
|
34
|
+
},
|
|
35
|
+
text: {
|
|
36
|
+
color: "#ffffff",
|
|
37
|
+
fontSize: 16,
|
|
38
|
+
fontWeight: "600"
|
|
39
|
+
},
|
|
40
|
+
textDisabled: {
|
|
41
|
+
color: "#e5e7eb"
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
exports.Button = Button;
|
|
46
|
+
//# sourceMappingURL=index.cjs.map
|
|
47
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Button.tsx"],"names":["jsx","TouchableOpacity","Text","StyleSheet"],"mappings":";;;;;;AAaO,SAAS,OAAO,EAAE,KAAA,EAAO,OAAA,EAAS,QAAA,GAAW,OAAM,EAAgB;AACxE,EAAA,uBACEA,cAAA;AAAA,IAACC,4BAAA;AAAA,IAAA;AAAA,MACC,OAAO,CAAC,MAAA,CAAO,MAAA,EAAQ,QAAA,IAAY,OAAO,cAAc,CAAA;AAAA,MACxD,OAAA;AAAA,MACA,QAAA;AAAA,MACA,aAAA,EAAe,GAAA;AAAA,MACf,iBAAA,EAAkB,QAAA;AAAA,MAClB,kBAAA,EAAoB,EAAE,QAAA,EAAS;AAAA,MAE/B,QAAA,kBAAAD,cAAA,CAACE,gBAAA,EAAA,EAAK,KAAA,EAAO,CAAC,MAAA,CAAO,MAAM,QAAA,IAAY,MAAA,CAAO,YAAY,CAAA,EAAI,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA,GACtE;AAEJ;AAEA,IAAM,MAAA,GAASC,uBAAW,MAAA,CAAO;AAAA,EAC/B,MAAA,EAAQ;AAAA,IACN,eAAA,EAAiB,SAAA;AAAA,IACjB,eAAA,EAAiB,EAAA;AAAA,IACjB,iBAAA,EAAmB,EAAA;AAAA,IACnB,YAAA,EAAc,CAAA;AAAA,IACd,UAAA,EAAY,QAAA;AAAA,IACZ,cAAA,EAAgB,QAAA;AAAA,IAChB,QAAA,EAAU;AAAA,GACZ;AAAA,EACA,cAAA,EAAgB;AAAA,IACd,eAAA,EAAiB,SAAA;AAAA,IACjB,OAAA,EAAS;AAAA,GACX;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,KAAA,EAAO,SAAA;AAAA,IACP,QAAA,EAAU,EAAA;AAAA,IACV,UAAA,EAAY;AAAA,GACd;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,KAAA,EAAO;AAAA;AAEX,CAAC,CAAA","file":"index.cjs","sourcesContent":["import {\n StyleSheet,\n Text,\n TouchableOpacity,\n type GestureResponderEvent,\n} from \"react-native\";\n\nexport interface ButtonProps {\n title: string;\n onPress: (event: GestureResponderEvent) => void;\n disabled?: boolean;\n}\n\nexport function Button({ title, onPress, disabled = false }: ButtonProps) {\n return (\n <TouchableOpacity\n style={[styles.button, disabled && styles.buttonDisabled]}\n onPress={onPress}\n disabled={disabled}\n activeOpacity={0.7}\n accessibilityRole=\"button\"\n accessibilityState={{ disabled }}\n >\n <Text style={[styles.text, disabled && styles.textDisabled]}>{title}</Text>\n </TouchableOpacity>\n );\n}\n\nconst styles = StyleSheet.create({\n button: {\n backgroundColor: \"#2563eb\",\n paddingVertical: 12,\n paddingHorizontal: 24,\n borderRadius: 8,\n alignItems: \"center\",\n justifyContent: \"center\",\n minWidth: 120,\n },\n buttonDisabled: {\n backgroundColor: \"#93c5fd\",\n opacity: 0.7,\n },\n text: {\n color: \"#ffffff\",\n fontSize: 16,\n fontWeight: \"600\",\n },\n textDisabled: {\n color: \"#e5e7eb\",\n },\n});\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { GestureResponderEvent } from 'react-native';
|
|
3
|
+
|
|
4
|
+
interface ButtonProps {
|
|
5
|
+
title: string;
|
|
6
|
+
onPress: (event: GestureResponderEvent) => void;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare function Button({ title, onPress, disabled }: ButtonProps): react.JSX.Element;
|
|
10
|
+
|
|
11
|
+
export { Button, type ButtonProps };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { GestureResponderEvent } from 'react-native';
|
|
3
|
+
|
|
4
|
+
interface ButtonProps {
|
|
5
|
+
title: string;
|
|
6
|
+
onPress: (event: GestureResponderEvent) => void;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare function Button({ title, onPress, disabled }: ButtonProps): react.JSX.Element;
|
|
10
|
+
|
|
11
|
+
export { Button, type ButtonProps };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { StyleSheet, TouchableOpacity, Text } from 'react-native';
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
// src/components/Button.tsx
|
|
5
|
+
function Button({ title, onPress, disabled = false }) {
|
|
6
|
+
return /* @__PURE__ */ jsx(
|
|
7
|
+
TouchableOpacity,
|
|
8
|
+
{
|
|
9
|
+
style: [styles.button, disabled && styles.buttonDisabled],
|
|
10
|
+
onPress,
|
|
11
|
+
disabled,
|
|
12
|
+
activeOpacity: 0.7,
|
|
13
|
+
accessibilityRole: "button",
|
|
14
|
+
accessibilityState: { disabled },
|
|
15
|
+
children: /* @__PURE__ */ jsx(Text, { style: [styles.text, disabled && styles.textDisabled], children: title })
|
|
16
|
+
}
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
var styles = StyleSheet.create({
|
|
20
|
+
button: {
|
|
21
|
+
backgroundColor: "#2563eb",
|
|
22
|
+
paddingVertical: 12,
|
|
23
|
+
paddingHorizontal: 24,
|
|
24
|
+
borderRadius: 8,
|
|
25
|
+
alignItems: "center",
|
|
26
|
+
justifyContent: "center",
|
|
27
|
+
minWidth: 120
|
|
28
|
+
},
|
|
29
|
+
buttonDisabled: {
|
|
30
|
+
backgroundColor: "#93c5fd",
|
|
31
|
+
opacity: 0.7
|
|
32
|
+
},
|
|
33
|
+
text: {
|
|
34
|
+
color: "#ffffff",
|
|
35
|
+
fontSize: 16,
|
|
36
|
+
fontWeight: "600"
|
|
37
|
+
},
|
|
38
|
+
textDisabled: {
|
|
39
|
+
color: "#e5e7eb"
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export { Button };
|
|
44
|
+
//# sourceMappingURL=index.js.map
|
|
45
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Button.tsx"],"names":[],"mappings":";;;;AAaO,SAAS,OAAO,EAAE,KAAA,EAAO,OAAA,EAAS,QAAA,GAAW,OAAM,EAAgB;AACxE,EAAA,uBACE,GAAA;AAAA,IAAC,gBAAA;AAAA,IAAA;AAAA,MACC,OAAO,CAAC,MAAA,CAAO,MAAA,EAAQ,QAAA,IAAY,OAAO,cAAc,CAAA;AAAA,MACxD,OAAA;AAAA,MACA,QAAA;AAAA,MACA,aAAA,EAAe,GAAA;AAAA,MACf,iBAAA,EAAkB,QAAA;AAAA,MAClB,kBAAA,EAAoB,EAAE,QAAA,EAAS;AAAA,MAE/B,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAO,CAAC,MAAA,CAAO,MAAM,QAAA,IAAY,MAAA,CAAO,YAAY,CAAA,EAAI,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA,GACtE;AAEJ;AAEA,IAAM,MAAA,GAAS,WAAW,MAAA,CAAO;AAAA,EAC/B,MAAA,EAAQ;AAAA,IACN,eAAA,EAAiB,SAAA;AAAA,IACjB,eAAA,EAAiB,EAAA;AAAA,IACjB,iBAAA,EAAmB,EAAA;AAAA,IACnB,YAAA,EAAc,CAAA;AAAA,IACd,UAAA,EAAY,QAAA;AAAA,IACZ,cAAA,EAAgB,QAAA;AAAA,IAChB,QAAA,EAAU;AAAA,GACZ;AAAA,EACA,cAAA,EAAgB;AAAA,IACd,eAAA,EAAiB,SAAA;AAAA,IACjB,OAAA,EAAS;AAAA,GACX;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,KAAA,EAAO,SAAA;AAAA,IACP,QAAA,EAAU,EAAA;AAAA,IACV,UAAA,EAAY;AAAA,GACd;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,KAAA,EAAO;AAAA;AAEX,CAAC,CAAA","file":"index.js","sourcesContent":["import {\n StyleSheet,\n Text,\n TouchableOpacity,\n type GestureResponderEvent,\n} from \"react-native\";\n\nexport interface ButtonProps {\n title: string;\n onPress: (event: GestureResponderEvent) => void;\n disabled?: boolean;\n}\n\nexport function Button({ title, onPress, disabled = false }: ButtonProps) {\n return (\n <TouchableOpacity\n style={[styles.button, disabled && styles.buttonDisabled]}\n onPress={onPress}\n disabled={disabled}\n activeOpacity={0.7}\n accessibilityRole=\"button\"\n accessibilityState={{ disabled }}\n >\n <Text style={[styles.text, disabled && styles.textDisabled]}>{title}</Text>\n </TouchableOpacity>\n );\n}\n\nconst styles = StyleSheet.create({\n button: {\n backgroundColor: \"#2563eb\",\n paddingVertical: 12,\n paddingHorizontal: 24,\n borderRadius: 8,\n alignItems: \"center\",\n justifyContent: \"center\",\n minWidth: 120,\n },\n buttonDisabled: {\n backgroundColor: \"#93c5fd\",\n opacity: 0.7,\n },\n text: {\n color: \"#ffffff\",\n fontSize: 16,\n fontWeight: \"600\",\n },\n textDisabled: {\n color: \"#e5e7eb\",\n },\n});\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@scripso-homepad/ui",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Cross-platform UI components for Homepad (React Web + React Native)",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Homepad",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/Home-Pad/homepad-ui.git"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"module": "./dist/index.mjs",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"react-native": "./src/index.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"react-native": "./src/index.ts",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.mjs",
|
|
24
|
+
"require": "./dist/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"src"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsup",
|
|
33
|
+
"typecheck": "tsc --noEmit",
|
|
34
|
+
"lint": "eslint .",
|
|
35
|
+
"clean": "rm -rf dist",
|
|
36
|
+
"storybook": "storybook dev -p 6006",
|
|
37
|
+
"build-storybook": "storybook build",
|
|
38
|
+
"prepublishOnly": "npm run build",
|
|
39
|
+
"changeset": "changeset",
|
|
40
|
+
"version-packages": "changeset version",
|
|
41
|
+
"release": "npm run build && changeset publish"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"react": ">=18",
|
|
45
|
+
"react-native": ">=0.74"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@changesets/changelog-github": "^0.5.0",
|
|
49
|
+
"@changesets/cli": "^2.27.10",
|
|
50
|
+
"@eslint/js": "^9.17.0",
|
|
51
|
+
"@storybook/addon-essentials": "^8.4.7",
|
|
52
|
+
"@storybook/addon-interactions": "^8.4.7",
|
|
53
|
+
"@storybook/react-vite": "^8.4.7",
|
|
54
|
+
"@types/react": "^18.3.18",
|
|
55
|
+
"eslint": "^9.17.0",
|
|
56
|
+
"eslint-plugin-react-hooks": "^5.1.0",
|
|
57
|
+
"globals": "^15.14.0",
|
|
58
|
+
"react": "^18.3.1",
|
|
59
|
+
"react-dom": "^18.3.1",
|
|
60
|
+
"react-native": "^0.76.5",
|
|
61
|
+
"react-native-web": "^0.19.13",
|
|
62
|
+
"storybook": "^8.4.7",
|
|
63
|
+
"tsup": "^8.3.5",
|
|
64
|
+
"typescript": "^5.7.2",
|
|
65
|
+
"typescript-eslint": "^8.18.2",
|
|
66
|
+
"vite": "^5.4.11"
|
|
67
|
+
},
|
|
68
|
+
"keywords": [
|
|
69
|
+
"homepad",
|
|
70
|
+
"react",
|
|
71
|
+
"react-native",
|
|
72
|
+
"ui",
|
|
73
|
+
"components"
|
|
74
|
+
],
|
|
75
|
+
"engines": {
|
|
76
|
+
"node": ">=20"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { fn } from "@storybook/test";
|
|
3
|
+
import { Button } from "./Button";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: "Components/Button",
|
|
7
|
+
component: Button,
|
|
8
|
+
args: {
|
|
9
|
+
title: "Press me",
|
|
10
|
+
onPress: fn(),
|
|
11
|
+
disabled: false,
|
|
12
|
+
},
|
|
13
|
+
argTypes: {
|
|
14
|
+
onPress: { action: "pressed" },
|
|
15
|
+
},
|
|
16
|
+
} satisfies Meta<typeof Button>;
|
|
17
|
+
|
|
18
|
+
export default meta;
|
|
19
|
+
type Story = StoryObj<typeof meta>;
|
|
20
|
+
|
|
21
|
+
export const Default: Story = {};
|
|
22
|
+
|
|
23
|
+
export const Disabled: Story = {
|
|
24
|
+
args: {
|
|
25
|
+
disabled: true,
|
|
26
|
+
title: "Disabled",
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const LongLabel: Story = {
|
|
31
|
+
args: {
|
|
32
|
+
title: "Continue to next step",
|
|
33
|
+
},
|
|
34
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
StyleSheet,
|
|
3
|
+
Text,
|
|
4
|
+
TouchableOpacity,
|
|
5
|
+
type GestureResponderEvent,
|
|
6
|
+
} from "react-native";
|
|
7
|
+
|
|
8
|
+
export interface ButtonProps {
|
|
9
|
+
title: string;
|
|
10
|
+
onPress: (event: GestureResponderEvent) => void;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function Button({ title, onPress, disabled = false }: ButtonProps) {
|
|
15
|
+
return (
|
|
16
|
+
<TouchableOpacity
|
|
17
|
+
style={[styles.button, disabled && styles.buttonDisabled]}
|
|
18
|
+
onPress={onPress}
|
|
19
|
+
disabled={disabled}
|
|
20
|
+
activeOpacity={0.7}
|
|
21
|
+
accessibilityRole="button"
|
|
22
|
+
accessibilityState={{ disabled }}
|
|
23
|
+
>
|
|
24
|
+
<Text style={[styles.text, disabled && styles.textDisabled]}>{title}</Text>
|
|
25
|
+
</TouchableOpacity>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const styles = StyleSheet.create({
|
|
30
|
+
button: {
|
|
31
|
+
backgroundColor: "#2563eb",
|
|
32
|
+
paddingVertical: 12,
|
|
33
|
+
paddingHorizontal: 24,
|
|
34
|
+
borderRadius: 8,
|
|
35
|
+
alignItems: "center",
|
|
36
|
+
justifyContent: "center",
|
|
37
|
+
minWidth: 120,
|
|
38
|
+
},
|
|
39
|
+
buttonDisabled: {
|
|
40
|
+
backgroundColor: "#93c5fd",
|
|
41
|
+
opacity: 0.7,
|
|
42
|
+
},
|
|
43
|
+
text: {
|
|
44
|
+
color: "#ffffff",
|
|
45
|
+
fontSize: 16,
|
|
46
|
+
fontWeight: "600",
|
|
47
|
+
},
|
|
48
|
+
textDisabled: {
|
|
49
|
+
color: "#e5e7eb",
|
|
50
|
+
},
|
|
51
|
+
});
|
package/src/index.ts
ADDED