@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 +36 -6
- package/dist/index.cjs +39 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -3
- package/dist/index.d.ts +19 -3
- package/dist/index.js +40 -5
- package/dist/index.js.map +1 -1
- package/package.json +2 -7
- package/src/components/Button.stories.tsx +32 -0
- package/src/components/Button.tsx +60 -3
package/README.md
CHANGED
|
@@ -92,11 +92,41 @@ export function Example() {
|
|
|
92
92
|
|
|
93
93
|
### `Button`
|
|
94
94
|
|
|
95
|
-
| Prop
|
|
96
|
-
|
|
|
97
|
-
| `title`
|
|
98
|
-
| `onPress`
|
|
99
|
-
| `disabled`
|
|
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)
|
|
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({
|
|
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:
|
|
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:
|
|
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",
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Button.tsx"],"names":["jsx","TouchableOpacity","Text"
|
|
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
|
|
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):
|
|
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
|
|
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):
|
|
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 {
|
|
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({
|
|
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:
|
|
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:
|
|
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":"
|
|
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.
|
|
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({
|
|
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={
|
|
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={
|
|
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",
|