@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 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"]}
@@ -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 };
@@ -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
@@ -0,0 +1,2 @@
1
+ export { Button } from "./components/Button";
2
+ export type { ButtonProps } from "./components/Button";