@scripso-homepad/ui 0.2.1 → 0.3.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/README.md CHANGED
@@ -92,11 +92,41 @@ export function Example() {
92
92
 
93
93
  ### `Button`
94
94
 
95
- | Prop | Type | Required | Default | Description |
96
- | ---------- | ------------ | -------- | ------- | -------------------- |
97
- | `title` | `string` | Yes | — | Button label text |
98
- | `onPress` | `() => void` | Yes | — | Press handler |
99
- | `disabled` | `boolean` | No | `false` | Disables interaction |
95
+ | Prop | Type | Required | Default | Description |
96
+ | --------------- | ---------------------- | -------- | ------- | -------------------------------------------------------- |
97
+ | `title` | `string` | Yes | — | Button label text |
98
+ | `onPress` | `() => void` | Yes | — | Press handler |
99
+ | `disabled` | `boolean` | No | `false` | Disables interaction |
100
+ | `style` | `StyleProp<ViewStyle>` | No | — | Extra container styles (web + native) |
101
+ | `textStyle` | `StyleProp<TextStyle>` | No | — | Extra label styles (web + native) |
102
+ | `className` | `string` | No | — | CSS/Tailwind classes for container (web / NativeWind) |
103
+ | `textClassName` | `string` | No | — | CSS/Tailwind classes for label (web / NativeWind) |
104
+
105
+ #### Custom styles (React Native `style`)
106
+
107
+ ```tsx
108
+ <Button
109
+ title="Save"
110
+ onPress={handleSave}
111
+ style={{ backgroundColor: "#dc2626", borderRadius: 999 }}
112
+ textStyle={{ fontSize: 14, textTransform: "uppercase" }}
113
+ />
114
+ ```
115
+
116
+ #### Tailwind classes (React web)
117
+
118
+ On web, `className` is applied to real DOM elements (`<button>` / `<span>`), so Tailwind utilities work with Vite or Next.js:
119
+
120
+ ```tsx
121
+ <Button
122
+ title="Save"
123
+ onPress={handleSave}
124
+ className="rounded-full bg-violet-600 px-8 shadow-lg"
125
+ textClassName="text-sm font-bold uppercase"
126
+ />
127
+ ```
128
+
129
+ > **Note:** `react-native-web` does not forward `className` to the DOM by default. This package renders native HTML elements on web so Tailwind classes appear in the DOM. On React Native, use `style` or [NativeWind](https://www.nativewind.dev/) with `cssInterop`.
100
130
 
101
131
  ## Development
102
132
 
@@ -125,7 +155,7 @@ npm run build-storybook
125
155
 
126
156
  ## Publishing
127
157
 
128
- See [PUBLISHING.md](./PUBLISHING.md) for release workflow details.
158
+ Push to `main` — CI auto-bumps the patch version and publishes to npm. See [PUBLISHING.md](./PUBLISHING.md).
129
159
 
130
160
  ## Architecture
131
161
 
package/dist/index.cjs CHANGED
@@ -1,20 +1,54 @@
1
1
  'use strict';
2
2
 
3
+ var react = require('react');
3
4
  var reactNative = require('react-native');
4
5
  var jsxRuntime = require('react/jsx-runtime');
5
6
 
6
7
  // src/components/Button.tsx
7
- function Button({ title, onPress, disabled = false }) {
8
+ function Button({
9
+ title,
10
+ onPress,
11
+ disabled = false,
12
+ style,
13
+ textStyle,
14
+ className,
15
+ textClassName
16
+ }) {
17
+ const containerStyle = [styles.button, disabled && styles.buttonDisabled, style];
18
+ const labelStyle = [styles.text, disabled && styles.textDisabled, textStyle];
19
+ if (reactNative.Platform.OS === "web") {
20
+ return react.createElement(
21
+ "button",
22
+ {
23
+ type: "button",
24
+ className,
25
+ style: reactNative.StyleSheet.flatten(containerStyle),
26
+ disabled,
27
+ onClick: (event) => {
28
+ onPress(event);
29
+ },
30
+ "aria-disabled": disabled
31
+ },
32
+ react.createElement(
33
+ "span",
34
+ {
35
+ className: textClassName,
36
+ style: reactNative.StyleSheet.flatten(labelStyle)
37
+ },
38
+ title
39
+ )
40
+ );
41
+ }
8
42
  return /* @__PURE__ */ jsxRuntime.jsx(
9
43
  reactNative.TouchableOpacity,
10
44
  {
11
- style: [styles.button, disabled && styles.buttonDisabled],
45
+ style: containerStyle,
12
46
  onPress,
13
47
  disabled,
14
48
  activeOpacity: 0.7,
15
49
  accessibilityRole: "button",
16
50
  accessibilityState: { disabled },
17
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.text, disabled && styles.textDisabled], children: title })
51
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: labelStyle, children: title })
18
52
  }
19
53
  );
20
54
  }
@@ -26,7 +60,8 @@ var styles = reactNative.StyleSheet.create({
26
60
  borderRadius: 8,
27
61
  alignItems: "center",
28
62
  justifyContent: "center",
29
- minWidth: 120
63
+ minWidth: 120,
64
+ borderWidth: 0
30
65
  },
31
66
  buttonDisabled: {
32
67
  backgroundColor: "#93c5fd",
@@ -1 +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"]}
1
+ {"version":3,"sources":["../src/components/Button.tsx"],"names":["Platform","createElement","StyleSheet","jsx","TouchableOpacity","Text"],"mappings":";;;;;;;AAkCO,SAAS,MAAA,CAAO;AAAA,EACrB,KAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,KAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAAgB;AACd,EAAA,MAAM,iBAAiB,CAAC,MAAA,CAAO,QAAQ,QAAA,IAAY,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAC/E,EAAA,MAAM,aAAa,CAAC,MAAA,CAAO,MAAM,QAAA,IAAY,MAAA,CAAO,cAAc,SAAS,CAAA;AAE3E,EAAA,IAAIA,oBAAA,CAAS,OAAO,KAAA,EAAO;AACzB,IAAA,OAAOC,mBAAA;AAAA,MACL,QAAA;AAAA,MACA;AAAA,QACE,IAAA,EAAM,QAAA;AAAA,QACN,SAAA;AAAA,QACA,KAAA,EAAOC,sBAAA,CAAW,OAAA,CAAQ,cAAc,CAAA;AAAA,QACxC,QAAA;AAAA,QACA,OAAA,EAAS,CAAC,KAAA,KAA+C;AACvD,UAAA,OAAA,CAAQ,KAAyC,CAAA;AAAA,QACnD,CAAA;AAAA,QACA,eAAA,EAAiB;AAAA,OACnB;AAAA,MACAD,mBAAA;AAAA,QACE,MAAA;AAAA,QACA;AAAA,UACE,SAAA,EAAW,aAAA;AAAA,UACX,KAAA,EAAOC,sBAAA,CAAW,OAAA,CAAQ,UAAU;AAAA,SACtC;AAAA,QACA;AAAA;AACF,KACF;AAAA,EACF;AAEA,EAAA,uBACEC,cAAA;AAAA,IAACC,4BAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,cAAA;AAAA,MACP,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,UAAA,EAAa,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA,GAClC;AAEJ;AAEA,IAAM,MAAA,GAASH,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,GAAA;AAAA,IACV,WAAA,EAAa;AAAA,GACf;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 React, { createElement } from \"react\";\nimport {\n Platform,\n StyleSheet,\n Text,\n TouchableOpacity,\n type GestureResponderEvent,\n type StyleProp,\n type TextStyle,\n type ViewStyle,\n} from \"react-native\";\n\nexport interface ButtonProps {\n title: string;\n onPress: (event: GestureResponderEvent) => void;\n disabled?: boolean;\n /** Additional container styles (works on web and native). */\n style?: StyleProp<ViewStyle>;\n /** Additional label styles (works on web and native). */\n textStyle?: StyleProp<TextStyle>;\n /**\n * CSS class names for the container.\n * On web: applied to the underlying `<button>` element (Tailwind works).\n * On native: ignored unless using NativeWind with cssInterop.\n */\n className?: string;\n /**\n * CSS class names for the label.\n * On web: applied to the underlying `<span>` element (Tailwind works).\n * On native: ignored unless using NativeWind with cssInterop.\n */\n textClassName?: string;\n}\n\nexport function Button({\n title,\n onPress,\n disabled = false,\n style,\n textStyle,\n className,\n textClassName,\n}: ButtonProps) {\n const containerStyle = [styles.button, disabled && styles.buttonDisabled, style];\n const labelStyle = [styles.text, disabled && styles.textDisabled, textStyle];\n\n if (Platform.OS === \"web\") {\n return createElement(\n \"button\",\n {\n type: \"button\",\n className,\n style: StyleSheet.flatten(containerStyle),\n disabled,\n onClick: (event: React.MouseEvent<HTMLButtonElement>) => {\n onPress(event as unknown as GestureResponderEvent);\n },\n \"aria-disabled\": disabled,\n },\n createElement(\n \"span\",\n {\n className: textClassName,\n style: StyleSheet.flatten(labelStyle),\n },\n title,\n ),\n );\n }\n\n return (\n <TouchableOpacity\n style={containerStyle}\n onPress={onPress}\n disabled={disabled}\n activeOpacity={0.7}\n accessibilityRole=\"button\"\n accessibilityState={{ disabled }}\n >\n <Text style={labelStyle}>{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 borderWidth: 0,\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 CHANGED
@@ -1,11 +1,27 @@
1
- import * as react from 'react';
2
- import { GestureResponderEvent } from 'react-native';
1
+ import React from 'react';
2
+ import { GestureResponderEvent, StyleProp, ViewStyle, TextStyle } from 'react-native';
3
3
 
4
4
  interface ButtonProps {
5
5
  title: string;
6
6
  onPress: (event: GestureResponderEvent) => void;
7
7
  disabled?: boolean;
8
+ /** Additional container styles (works on web and native). */
9
+ style?: StyleProp<ViewStyle>;
10
+ /** Additional label styles (works on web and native). */
11
+ textStyle?: StyleProp<TextStyle>;
12
+ /**
13
+ * CSS class names for the container.
14
+ * On web: applied to the underlying `<button>` element (Tailwind works).
15
+ * On native: ignored unless using NativeWind with cssInterop.
16
+ */
17
+ className?: string;
18
+ /**
19
+ * CSS class names for the label.
20
+ * On web: applied to the underlying `<span>` element (Tailwind works).
21
+ * On native: ignored unless using NativeWind with cssInterop.
22
+ */
23
+ textClassName?: string;
8
24
  }
9
- declare function Button({ title, onPress, disabled }: ButtonProps): react.JSX.Element;
25
+ declare function Button({ title, onPress, disabled, style, textStyle, className, textClassName, }: ButtonProps): React.JSX.Element;
10
26
 
11
27
  export { Button, type ButtonProps };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,27 @@
1
- import * as react from 'react';
2
- import { GestureResponderEvent } from 'react-native';
1
+ import React from 'react';
2
+ import { GestureResponderEvent, StyleProp, ViewStyle, TextStyle } from 'react-native';
3
3
 
4
4
  interface ButtonProps {
5
5
  title: string;
6
6
  onPress: (event: GestureResponderEvent) => void;
7
7
  disabled?: boolean;
8
+ /** Additional container styles (works on web and native). */
9
+ style?: StyleProp<ViewStyle>;
10
+ /** Additional label styles (works on web and native). */
11
+ textStyle?: StyleProp<TextStyle>;
12
+ /**
13
+ * CSS class names for the container.
14
+ * On web: applied to the underlying `<button>` element (Tailwind works).
15
+ * On native: ignored unless using NativeWind with cssInterop.
16
+ */
17
+ className?: string;
18
+ /**
19
+ * CSS class names for the label.
20
+ * On web: applied to the underlying `<span>` element (Tailwind works).
21
+ * On native: ignored unless using NativeWind with cssInterop.
22
+ */
23
+ textClassName?: string;
8
24
  }
9
- declare function Button({ title, onPress, disabled }: ButtonProps): react.JSX.Element;
25
+ declare function Button({ title, onPress, disabled, style, textStyle, className, textClassName, }: ButtonProps): React.JSX.Element;
10
26
 
11
27
  export { Button, type ButtonProps };
package/dist/index.js CHANGED
@@ -1,18 +1,52 @@
1
- import { StyleSheet, TouchableOpacity, Text } from 'react-native';
1
+ import { createElement } from 'react';
2
+ import { StyleSheet, Platform, TouchableOpacity, Text } from 'react-native';
2
3
  import { jsx } from 'react/jsx-runtime';
3
4
 
4
5
  // src/components/Button.tsx
5
- function Button({ title, onPress, disabled = false }) {
6
+ function Button({
7
+ title,
8
+ onPress,
9
+ disabled = false,
10
+ style,
11
+ textStyle,
12
+ className,
13
+ textClassName
14
+ }) {
15
+ const containerStyle = [styles.button, disabled && styles.buttonDisabled, style];
16
+ const labelStyle = [styles.text, disabled && styles.textDisabled, textStyle];
17
+ if (Platform.OS === "web") {
18
+ return createElement(
19
+ "button",
20
+ {
21
+ type: "button",
22
+ className,
23
+ style: StyleSheet.flatten(containerStyle),
24
+ disabled,
25
+ onClick: (event) => {
26
+ onPress(event);
27
+ },
28
+ "aria-disabled": disabled
29
+ },
30
+ createElement(
31
+ "span",
32
+ {
33
+ className: textClassName,
34
+ style: StyleSheet.flatten(labelStyle)
35
+ },
36
+ title
37
+ )
38
+ );
39
+ }
6
40
  return /* @__PURE__ */ jsx(
7
41
  TouchableOpacity,
8
42
  {
9
- style: [styles.button, disabled && styles.buttonDisabled],
43
+ style: containerStyle,
10
44
  onPress,
11
45
  disabled,
12
46
  activeOpacity: 0.7,
13
47
  accessibilityRole: "button",
14
48
  accessibilityState: { disabled },
15
- children: /* @__PURE__ */ jsx(Text, { style: [styles.text, disabled && styles.textDisabled], children: title })
49
+ children: /* @__PURE__ */ jsx(Text, { style: labelStyle, children: title })
16
50
  }
17
51
  );
18
52
  }
@@ -24,7 +58,8 @@ var styles = StyleSheet.create({
24
58
  borderRadius: 8,
25
59
  alignItems: "center",
26
60
  justifyContent: "center",
27
- minWidth: 120
61
+ minWidth: 120,
62
+ borderWidth: 0
28
63
  },
29
64
  buttonDisabled: {
30
65
  backgroundColor: "#93c5fd",
package/dist/index.js.map CHANGED
@@ -1 +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"]}
1
+ {"version":3,"sources":["../src/components/Button.tsx"],"names":[],"mappings":";;;;;AAkCO,SAAS,MAAA,CAAO;AAAA,EACrB,KAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,KAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAAgB;AACd,EAAA,MAAM,iBAAiB,CAAC,MAAA,CAAO,QAAQ,QAAA,IAAY,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAC/E,EAAA,MAAM,aAAa,CAAC,MAAA,CAAO,MAAM,QAAA,IAAY,MAAA,CAAO,cAAc,SAAS,CAAA;AAE3E,EAAA,IAAI,QAAA,CAAS,OAAO,KAAA,EAAO;AACzB,IAAA,OAAO,aAAA;AAAA,MACL,QAAA;AAAA,MACA;AAAA,QACE,IAAA,EAAM,QAAA;AAAA,QACN,SAAA;AAAA,QACA,KAAA,EAAO,UAAA,CAAW,OAAA,CAAQ,cAAc,CAAA;AAAA,QACxC,QAAA;AAAA,QACA,OAAA,EAAS,CAAC,KAAA,KAA+C;AACvD,UAAA,OAAA,CAAQ,KAAyC,CAAA;AAAA,QACnD,CAAA;AAAA,QACA,eAAA,EAAiB;AAAA,OACnB;AAAA,MACA,aAAA;AAAA,QACE,MAAA;AAAA,QACA;AAAA,UACE,SAAA,EAAW,aAAA;AAAA,UACX,KAAA,EAAO,UAAA,CAAW,OAAA,CAAQ,UAAU;AAAA,SACtC;AAAA,QACA;AAAA;AACF,KACF;AAAA,EACF;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,gBAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,cAAA;AAAA,MACP,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,UAAA,EAAa,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA,GAClC;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,GAAA;AAAA,IACV,WAAA,EAAa;AAAA,GACf;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 React, { createElement } from \"react\";\nimport {\n Platform,\n StyleSheet,\n Text,\n TouchableOpacity,\n type GestureResponderEvent,\n type StyleProp,\n type TextStyle,\n type ViewStyle,\n} from \"react-native\";\n\nexport interface ButtonProps {\n title: string;\n onPress: (event: GestureResponderEvent) => void;\n disabled?: boolean;\n /** Additional container styles (works on web and native). */\n style?: StyleProp<ViewStyle>;\n /** Additional label styles (works on web and native). */\n textStyle?: StyleProp<TextStyle>;\n /**\n * CSS class names for the container.\n * On web: applied to the underlying `<button>` element (Tailwind works).\n * On native: ignored unless using NativeWind with cssInterop.\n */\n className?: string;\n /**\n * CSS class names for the label.\n * On web: applied to the underlying `<span>` element (Tailwind works).\n * On native: ignored unless using NativeWind with cssInterop.\n */\n textClassName?: string;\n}\n\nexport function Button({\n title,\n onPress,\n disabled = false,\n style,\n textStyle,\n className,\n textClassName,\n}: ButtonProps) {\n const containerStyle = [styles.button, disabled && styles.buttonDisabled, style];\n const labelStyle = [styles.text, disabled && styles.textDisabled, textStyle];\n\n if (Platform.OS === \"web\") {\n return createElement(\n \"button\",\n {\n type: \"button\",\n className,\n style: StyleSheet.flatten(containerStyle),\n disabled,\n onClick: (event: React.MouseEvent<HTMLButtonElement>) => {\n onPress(event as unknown as GestureResponderEvent);\n },\n \"aria-disabled\": disabled,\n },\n createElement(\n \"span\",\n {\n className: textClassName,\n style: StyleSheet.flatten(labelStyle),\n },\n title,\n ),\n );\n }\n\n return (\n <TouchableOpacity\n style={containerStyle}\n onPress={onPress}\n disabled={disabled}\n activeOpacity={0.7}\n accessibilityRole=\"button\"\n accessibilityState={{ disabled }}\n >\n <Text style={labelStyle}>{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 borderWidth: 0,\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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scripso-homepad/ui",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "description": "Cross-platform UI components for Homepad (React Web + React Native)",
6
6
  "license": "MIT",
@@ -35,18 +35,13 @@
35
35
  "clean": "rm -rf dist",
36
36
  "storybook": "storybook dev -p 6006",
37
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"
38
+ "prepublishOnly": "npm run build"
42
39
  },
43
40
  "peerDependencies": {
44
41
  "react": ">=18",
45
42
  "react-native": ">=0.74"
46
43
  },
47
44
  "devDependencies": {
48
- "@changesets/changelog-github": "^0.5.0",
49
- "@changesets/cli": "^2.27.10",
50
45
  "@eslint/js": "^9.17.0",
51
46
  "@storybook/addon-essentials": "^8.4.7",
52
47
  "@storybook/addon-interactions": "^8.4.7",
@@ -32,3 +32,35 @@ export const LongLabel: Story = {
32
32
  title: "Continue to next step",
33
33
  },
34
34
  };
35
+
36
+ export const CustomStyle: Story = {
37
+ args: {
38
+ title: "Custom styles",
39
+ style: {
40
+ backgroundColor: "#dc2626",
41
+ borderRadius: 999,
42
+ paddingHorizontal: 32,
43
+ },
44
+ textStyle: {
45
+ fontSize: 14,
46
+ letterSpacing: 1,
47
+ textTransform: "uppercase",
48
+ },
49
+ },
50
+ };
51
+
52
+ export const WithClassName: Story = {
53
+ args: {
54
+ title: "Tailwind classes",
55
+ className: "rounded-full bg-violet-600 px-8 shadow-lg",
56
+ textClassName: "text-sm font-bold uppercase tracking-wide",
57
+ },
58
+ parameters: {
59
+ docs: {
60
+ description: {
61
+ story:
62
+ "Pass Tailwind utility classes via className. Requires Tailwind in your web app (or NativeWind on native).",
63
+ },
64
+ },
65
+ },
66
+ };
@@ -1,27 +1,83 @@
1
+ import React, { createElement } from "react";
1
2
  import {
3
+ Platform,
2
4
  StyleSheet,
3
5
  Text,
4
6
  TouchableOpacity,
5
7
  type GestureResponderEvent,
8
+ type StyleProp,
9
+ type TextStyle,
10
+ type ViewStyle,
6
11
  } from "react-native";
7
12
 
8
13
  export interface ButtonProps {
9
14
  title: string;
10
15
  onPress: (event: GestureResponderEvent) => void;
11
16
  disabled?: boolean;
17
+ /** Additional container styles (works on web and native). */
18
+ style?: StyleProp<ViewStyle>;
19
+ /** Additional label styles (works on web and native). */
20
+ textStyle?: StyleProp<TextStyle>;
21
+ /**
22
+ * CSS class names for the container.
23
+ * On web: applied to the underlying `<button>` element (Tailwind works).
24
+ * On native: ignored unless using NativeWind with cssInterop.
25
+ */
26
+ className?: string;
27
+ /**
28
+ * CSS class names for the label.
29
+ * On web: applied to the underlying `<span>` element (Tailwind works).
30
+ * On native: ignored unless using NativeWind with cssInterop.
31
+ */
32
+ textClassName?: string;
12
33
  }
13
34
 
14
- export function Button({ title, onPress, disabled = false }: ButtonProps) {
35
+ export function Button({
36
+ title,
37
+ onPress,
38
+ disabled = false,
39
+ style,
40
+ textStyle,
41
+ className,
42
+ textClassName,
43
+ }: ButtonProps) {
44
+ const containerStyle = [styles.button, disabled && styles.buttonDisabled, style];
45
+ const labelStyle = [styles.text, disabled && styles.textDisabled, textStyle];
46
+
47
+ if (Platform.OS === "web") {
48
+ return createElement(
49
+ "button",
50
+ {
51
+ type: "button",
52
+ className,
53
+ style: StyleSheet.flatten(containerStyle),
54
+ disabled,
55
+ onClick: (event: React.MouseEvent<HTMLButtonElement>) => {
56
+ onPress(event as unknown as GestureResponderEvent);
57
+ },
58
+ "aria-disabled": disabled,
59
+ },
60
+ createElement(
61
+ "span",
62
+ {
63
+ className: textClassName,
64
+ style: StyleSheet.flatten(labelStyle),
65
+ },
66
+ title,
67
+ ),
68
+ );
69
+ }
70
+
15
71
  return (
16
72
  <TouchableOpacity
17
- style={[styles.button, disabled && styles.buttonDisabled]}
73
+ style={containerStyle}
18
74
  onPress={onPress}
19
75
  disabled={disabled}
20
76
  activeOpacity={0.7}
21
77
  accessibilityRole="button"
22
78
  accessibilityState={{ disabled }}
23
79
  >
24
- <Text style={[styles.text, disabled && styles.textDisabled]}>{title}</Text>
80
+ <Text style={labelStyle}>{title}</Text>
25
81
  </TouchableOpacity>
26
82
  );
27
83
  }
@@ -35,6 +91,7 @@ const styles = StyleSheet.create({
35
91
  alignItems: "center",
36
92
  justifyContent: "center",
37
93
  minWidth: 120,
94
+ borderWidth: 0,
38
95
  },
39
96
  buttonDisabled: {
40
97
  backgroundColor: "#93c5fd",