@ecohouse/ui 0.1.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 +58 -0
- package/dist/index.cjs +502 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +309 -0
- package/dist/index.d.ts +309 -0
- package/dist/index.js +480 -0
- package/dist/index.js.map +1 -0
- package/package.json +121 -0
- package/src/components/Button.stories.tsx +135 -0
- package/src/components/Button.tsx +232 -0
- package/src/css.d.ts +1 -0
- package/src/icons/ArrowUpRightIcon.tsx +29 -0
- package/src/icons/ArrowUpRightIcon.web.tsx +35 -0
- package/src/icons/arrowUpRightPath.ts +1 -0
- package/src/index.ts +23 -0
- package/src/theme/tokens.test.ts +10 -0
- package/src/theme/tokens.ts +286 -0
- package/src/utils/useApplyWebClassName.ts +83 -0
- package/src/web/styles/typography.css +99 -0
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# eco-cottage-ui (`@ecohouse/ui`)
|
|
2
|
+
|
|
3
|
+
Presentation-only universal UI package for EcoHouse customer web and mobile.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Reusable design tokens and cross-platform components built with **React Native primitives** + **React Native Web**, documented in Storybook.
|
|
8
|
+
|
|
9
|
+
## Package rules (MUST)
|
|
10
|
+
|
|
11
|
+
This package is **presentation-only**:
|
|
12
|
+
|
|
13
|
+
- No backend API clients
|
|
14
|
+
- No application secrets
|
|
15
|
+
- No provider SDKs
|
|
16
|
+
- No EcoHouse booking / domain business logic
|
|
17
|
+
|
|
18
|
+
Application routes, API calls, and booking logic stay in `eco-cottage-web` and `eco-cottage-mobile`. Consumers install published npm versions only (exact pin in `package-lock.json`).
|
|
19
|
+
|
|
20
|
+
## Stack (Architecture v1.4 §§4.4, 5)
|
|
21
|
+
|
|
22
|
+
| Area | Technology |
|
|
23
|
+
| ------------- | ----------------------------------------- |
|
|
24
|
+
| Package | TypeScript, tsup |
|
|
25
|
+
| UI | React Native primitives, React Native Web |
|
|
26
|
+
| Docs | Storybook |
|
|
27
|
+
| Lint / format | ESLint, Prettier |
|
|
28
|
+
| Tests | Vitest |
|
|
29
|
+
| Commits | Conventional Commits (commitlint + husky) |
|
|
30
|
+
|
|
31
|
+
## Current exports
|
|
32
|
+
|
|
33
|
+
| Export | Description |
|
|
34
|
+
| ------------------ | --------------------------------------------------------- |
|
|
35
|
+
| `Button` | Primary actions with variants, sizes, optional icon badge |
|
|
36
|
+
| Design tokens | `colors`, typography, spacing, radii, shadows |
|
|
37
|
+
| `ArrowUpRightIcon` | Default button badge icon |
|
|
38
|
+
|
|
39
|
+
## Scripts
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm ci
|
|
43
|
+
npm run lint
|
|
44
|
+
npm run format:check
|
|
45
|
+
npm run typecheck
|
|
46
|
+
npm test
|
|
47
|
+
npm run build
|
|
48
|
+
npm run storybook
|
|
49
|
+
npm run build-storybook
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Branch model
|
|
53
|
+
|
|
54
|
+
`feature/*` (or ticket branches such as `E0-1-ui/bootstrap-repo`) → `development` → `staging` → `main`
|
|
55
|
+
|
|
56
|
+
## Out of scope for E0-1
|
|
57
|
+
|
|
58
|
+
npm publishing / semantic-release / consumer update PRs (E0-3-ui), full component set, consumer app integration.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var reactNative = require('react-native');
|
|
5
|
+
var Svg = require('react-native-svg');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var Svg__default = /*#__PURE__*/_interopDefault(Svg);
|
|
11
|
+
|
|
12
|
+
// src/components/Button.tsx
|
|
13
|
+
|
|
14
|
+
// src/icons/arrowUpRightPath.ts
|
|
15
|
+
var ARROW_UP_RIGHT_PATH = "M14.1667 14.1668V5.8335H5.83333M14.1667 5.8335L5.83333 14.1668";
|
|
16
|
+
function ArrowUpRightIcon({
|
|
17
|
+
size = 20,
|
|
18
|
+
color = "#082640",
|
|
19
|
+
strokeWidth = 2
|
|
20
|
+
}) {
|
|
21
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Svg__default.default, { width: size, height: size, viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
22
|
+
Svg.Path,
|
|
23
|
+
{
|
|
24
|
+
d: ARROW_UP_RIGHT_PATH,
|
|
25
|
+
stroke: color,
|
|
26
|
+
strokeWidth,
|
|
27
|
+
strokeLinecap: "round",
|
|
28
|
+
strokeLinejoin: "round"
|
|
29
|
+
}
|
|
30
|
+
) });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/theme/tokens.ts
|
|
34
|
+
var stormGray = {
|
|
35
|
+
"0": "#fbfcfc",
|
|
36
|
+
"0.5": "#eceef0",
|
|
37
|
+
"1": "#dadde0",
|
|
38
|
+
"1.5": "#c7cdd1",
|
|
39
|
+
"2": "#b5bcc1",
|
|
40
|
+
"3": "#8f9aa3",
|
|
41
|
+
"4": "#6a7984",
|
|
42
|
+
"5": "#455765",
|
|
43
|
+
"6": "#374651",
|
|
44
|
+
"7": "#29343d",
|
|
45
|
+
"8": "#1c2328",
|
|
46
|
+
"8.5": "#151a1e"
|
|
47
|
+
};
|
|
48
|
+
var navy = {
|
|
49
|
+
"0": "#f6fafe",
|
|
50
|
+
"0.5": "#dee5eb",
|
|
51
|
+
"1": "#c6d0d8",
|
|
52
|
+
"1.5": "#afbac5",
|
|
53
|
+
"2": "#97a5b2",
|
|
54
|
+
"3": "#677b8c",
|
|
55
|
+
"4": "#385066",
|
|
56
|
+
"5": "#082640",
|
|
57
|
+
"6": "#061e33",
|
|
58
|
+
"7": "#051726",
|
|
59
|
+
"8": "#030f1a",
|
|
60
|
+
"8.5": "#020b13"
|
|
61
|
+
};
|
|
62
|
+
var rubyRed = {
|
|
63
|
+
"0": "#fff5f6",
|
|
64
|
+
"0.5": "#f7dddf",
|
|
65
|
+
"1": "#efc4c8",
|
|
66
|
+
"1.5": "#e7acb1",
|
|
67
|
+
"2": "#df939a",
|
|
68
|
+
"3": "#ce626d",
|
|
69
|
+
"4": "#be313f",
|
|
70
|
+
"5": "#ae0011",
|
|
71
|
+
"6": "#8b000e",
|
|
72
|
+
"7": "#68000a",
|
|
73
|
+
"8": "#460007",
|
|
74
|
+
"8.5": "#340005"
|
|
75
|
+
};
|
|
76
|
+
var emeraldGreen = {
|
|
77
|
+
"0": "#f0fbf5",
|
|
78
|
+
"0.5": "#dcf2e5",
|
|
79
|
+
"1": "#c8e8d5",
|
|
80
|
+
"1.5": "#b4dfc5",
|
|
81
|
+
"2": "#a0d5b5",
|
|
82
|
+
"3": "#77c394",
|
|
83
|
+
"4": "#4fb074",
|
|
84
|
+
"5": "#279d54",
|
|
85
|
+
"6": "#1f7e43",
|
|
86
|
+
"7": "#175e32",
|
|
87
|
+
"8": "#103f22",
|
|
88
|
+
"8.5": "#0c2f19"
|
|
89
|
+
};
|
|
90
|
+
var brand = {
|
|
91
|
+
slateBlue: "#182e3c",
|
|
92
|
+
stormGray: stormGray["5"],
|
|
93
|
+
navy: navy["5"],
|
|
94
|
+
rubyRed: rubyRed["5"],
|
|
95
|
+
emeraldGreen: emeraldGreen["5"]
|
|
96
|
+
};
|
|
97
|
+
var colors = {
|
|
98
|
+
// Brand colors
|
|
99
|
+
slateBlue: brand.slateBlue,
|
|
100
|
+
// Emerald Green — Figma scale + brand swatch
|
|
101
|
+
emeraldGreen0: emeraldGreen["0"],
|
|
102
|
+
emeraldGreen50: emeraldGreen["0.5"],
|
|
103
|
+
emeraldGreen100: emeraldGreen["1"],
|
|
104
|
+
emeraldGreen150: emeraldGreen["1.5"],
|
|
105
|
+
emeraldGreen200: emeraldGreen["2"],
|
|
106
|
+
emeraldGreen300: emeraldGreen["3"],
|
|
107
|
+
emeraldGreen400: emeraldGreen["4"],
|
|
108
|
+
emeraldGreen500: emeraldGreen["5"],
|
|
109
|
+
emeraldGreen600: emeraldGreen["6"],
|
|
110
|
+
emeraldGreen700: emeraldGreen["7"],
|
|
111
|
+
emeraldGreen800: emeraldGreen["8"],
|
|
112
|
+
emeraldGreen850: emeraldGreen["8.5"],
|
|
113
|
+
/** Primary brand emerald green — Figma Emerald Green 5 */
|
|
114
|
+
emeraldGreen: brand.emeraldGreen,
|
|
115
|
+
// Ruby Red — Figma scale + brand swatch
|
|
116
|
+
rubyRed0: rubyRed["0"],
|
|
117
|
+
rubyRed50: rubyRed["0.5"],
|
|
118
|
+
rubyRed100: rubyRed["1"],
|
|
119
|
+
rubyRed150: rubyRed["1.5"],
|
|
120
|
+
rubyRed200: rubyRed["2"],
|
|
121
|
+
rubyRed300: rubyRed["3"],
|
|
122
|
+
rubyRed400: rubyRed["4"],
|
|
123
|
+
rubyRed500: rubyRed["5"],
|
|
124
|
+
rubyRed600: rubyRed["6"],
|
|
125
|
+
rubyRed700: rubyRed["7"],
|
|
126
|
+
rubyRed800: rubyRed["8"],
|
|
127
|
+
rubyRed850: rubyRed["8.5"],
|
|
128
|
+
/** Primary brand ruby red — Figma Ruby Red 5 */
|
|
129
|
+
rubyRed: brand.rubyRed,
|
|
130
|
+
// Navy — Figma scale + brand swatch
|
|
131
|
+
navy0: navy["0"],
|
|
132
|
+
navy50: navy["0.5"],
|
|
133
|
+
navy100: navy["1"],
|
|
134
|
+
navy150: navy["1.5"],
|
|
135
|
+
navy200: navy["2"],
|
|
136
|
+
navy300: navy["3"],
|
|
137
|
+
navy400: navy["4"],
|
|
138
|
+
navy500: navy["5"],
|
|
139
|
+
navy600: navy["6"],
|
|
140
|
+
navy700: navy["7"],
|
|
141
|
+
navy800: navy["8"],
|
|
142
|
+
navy850: navy["8.5"],
|
|
143
|
+
/** Primary brand navy — Figma Navy 5 */
|
|
144
|
+
navy: brand.navy,
|
|
145
|
+
// Storm Gray — Figma scale + brand swatch
|
|
146
|
+
stormGray0: stormGray["0"],
|
|
147
|
+
stormGray50: stormGray["0.5"],
|
|
148
|
+
stormGray100: stormGray["1"],
|
|
149
|
+
stormGray150: stormGray["1.5"],
|
|
150
|
+
stormGray200: stormGray["2"],
|
|
151
|
+
stormGray300: stormGray["3"],
|
|
152
|
+
stormGray400: stormGray["4"],
|
|
153
|
+
stormGray500: stormGray["5"],
|
|
154
|
+
/** Figma brand swatch "Storm Gray" — same as `stormGray500` */
|
|
155
|
+
stormGrayBrand: brand.stormGray,
|
|
156
|
+
stormGray600: stormGray["6"],
|
|
157
|
+
stormGray700: stormGray["7"],
|
|
158
|
+
stormGray800: stormGray["8"],
|
|
159
|
+
stormGray850: stormGray["8.5"],
|
|
160
|
+
/** @deprecated Use `stormGray0` */
|
|
161
|
+
storm0: stormGray["0"],
|
|
162
|
+
/** @deprecated Use `stormGray50` */
|
|
163
|
+
storm50: stormGray["0.5"],
|
|
164
|
+
/** @deprecated Use `stormGray200` */
|
|
165
|
+
storm200: stormGray["2"],
|
|
166
|
+
/** @deprecated Use `stormGray300` */
|
|
167
|
+
storm300: stormGray["3"],
|
|
168
|
+
/** @deprecated Use `stormGray500` */
|
|
169
|
+
storm500: stormGray["5"],
|
|
170
|
+
/** @deprecated Use `stormGray700` */
|
|
171
|
+
storm700: stormGray["7"],
|
|
172
|
+
/** @deprecated Use `stormGray850` */
|
|
173
|
+
storm900: stormGray["8.5"],
|
|
174
|
+
countrySelectorSelectedBg: `${stormGray["0.5"]}99`,
|
|
175
|
+
white: "#ffffff",
|
|
176
|
+
error: "#dc2626",
|
|
177
|
+
errorDark: "#b3261e",
|
|
178
|
+
errorLight: "#fee2e2",
|
|
179
|
+
/** @deprecated Use `rubyRed` */
|
|
180
|
+
inputError: brand.rubyRed,
|
|
181
|
+
inputOutlineFocus: navy["0.5"],
|
|
182
|
+
inputOutlineError: rubyRed["0.5"],
|
|
183
|
+
warning: "#92400e",
|
|
184
|
+
warningBg: "#fef3c7",
|
|
185
|
+
success: "#28a745",
|
|
186
|
+
successMuted: "#9fd4a8",
|
|
187
|
+
/** @deprecated Use `emeraldGreen` */
|
|
188
|
+
green: brand.emeraldGreen,
|
|
189
|
+
transparent: "transparent"
|
|
190
|
+
};
|
|
191
|
+
var radii = {
|
|
192
|
+
sm: 8,
|
|
193
|
+
md: 12,
|
|
194
|
+
lg: 16,
|
|
195
|
+
xl: 20,
|
|
196
|
+
full: 9999
|
|
197
|
+
};
|
|
198
|
+
var spacing = {
|
|
199
|
+
xs: 4,
|
|
200
|
+
sm: 8,
|
|
201
|
+
md: 12,
|
|
202
|
+
lg: 16,
|
|
203
|
+
xl: 24,
|
|
204
|
+
xxl: 32
|
|
205
|
+
};
|
|
206
|
+
var fontSize = {
|
|
207
|
+
xs: 11,
|
|
208
|
+
sm: 12,
|
|
209
|
+
md: 14,
|
|
210
|
+
base: 16,
|
|
211
|
+
lg: 18,
|
|
212
|
+
xl: 24,
|
|
213
|
+
xxl: 32
|
|
214
|
+
};
|
|
215
|
+
var typographyScale = {
|
|
216
|
+
12: { fontSize: 12, lineHeight: 16 },
|
|
217
|
+
14: { fontSize: 14, lineHeight: 19 },
|
|
218
|
+
18: { fontSize: 18, lineHeight: 24 },
|
|
219
|
+
20: { fontSize: 20, lineHeight: 27 },
|
|
220
|
+
24: { fontSize: 24, lineHeight: 25 },
|
|
221
|
+
32: { fontSize: 32, lineHeight: 34 }
|
|
222
|
+
};
|
|
223
|
+
var fontWeight = {
|
|
224
|
+
regular: "400",
|
|
225
|
+
medium: "500",
|
|
226
|
+
semibold: "600",
|
|
227
|
+
bold: "700"
|
|
228
|
+
};
|
|
229
|
+
var fonts = {
|
|
230
|
+
sans: "Noto Sans Armenian"
|
|
231
|
+
};
|
|
232
|
+
var labelTypography = {
|
|
233
|
+
fontFamily: fonts.sans,
|
|
234
|
+
fontSize: typographyScale[12].fontSize,
|
|
235
|
+
fontWeight: fontWeight.medium,
|
|
236
|
+
lineHeight: typographyScale[12].lineHeight,
|
|
237
|
+
letterSpacing: 0
|
|
238
|
+
};
|
|
239
|
+
var buttonTypography = {
|
|
240
|
+
lg: {
|
|
241
|
+
fontFamily: fonts.sans,
|
|
242
|
+
fontSize: typographyScale[14].fontSize,
|
|
243
|
+
fontWeight: fontWeight.semibold,
|
|
244
|
+
lineHeight: typographyScale[14].lineHeight,
|
|
245
|
+
letterSpacing: 0
|
|
246
|
+
},
|
|
247
|
+
sm: {
|
|
248
|
+
fontFamily: fonts.sans,
|
|
249
|
+
fontSize: typographyScale[12].fontSize,
|
|
250
|
+
fontWeight: fontWeight.semibold,
|
|
251
|
+
lineHeight: typographyScale[12].lineHeight,
|
|
252
|
+
letterSpacing: 0
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
var shadows = {
|
|
256
|
+
card: {
|
|
257
|
+
shadowColor: colors.navy,
|
|
258
|
+
shadowOffset: { width: 0, height: 4 },
|
|
259
|
+
shadowOpacity: 0.05,
|
|
260
|
+
shadowRadius: 20,
|
|
261
|
+
elevation: 2
|
|
262
|
+
},
|
|
263
|
+
cardLg: {
|
|
264
|
+
shadowColor: colors.navy,
|
|
265
|
+
shadowOffset: { width: 0, height: 4 },
|
|
266
|
+
shadowOpacity: 0.1,
|
|
267
|
+
shadowRadius: 20,
|
|
268
|
+
elevation: 4
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
function hasClassList(node) {
|
|
272
|
+
return typeof node === "object" && node !== null && "classList" in node && typeof node.classList?.add === "function";
|
|
273
|
+
}
|
|
274
|
+
function resolveWebElement(ref) {
|
|
275
|
+
const node = ref.current;
|
|
276
|
+
if (!node) return null;
|
|
277
|
+
if (hasClassList(node)) return node;
|
|
278
|
+
const host = node;
|
|
279
|
+
if (hasClassList(host._touchableNode)) return host._touchableNode;
|
|
280
|
+
if (typeof host.getScrollableNode === "function") {
|
|
281
|
+
const scrollNode = host.getScrollableNode();
|
|
282
|
+
if (hasClassList(scrollNode)) return scrollNode;
|
|
283
|
+
}
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
function useApplyWebClassName(ref, className, enabled = true) {
|
|
287
|
+
react.useLayoutEffect(() => {
|
|
288
|
+
if (!enabled || reactNative.Platform.OS !== "web" || !className?.trim()) return;
|
|
289
|
+
let cancelled = false;
|
|
290
|
+
let rafId = 0;
|
|
291
|
+
let appliedElement = null;
|
|
292
|
+
const classes = className.trim().split(/\s+/);
|
|
293
|
+
const apply = () => {
|
|
294
|
+
if (cancelled) return;
|
|
295
|
+
const element = resolveWebElement(ref);
|
|
296
|
+
if (!element) {
|
|
297
|
+
rafId = requestAnimationFrame(apply);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
appliedElement = element;
|
|
301
|
+
element.classList.add(...classes);
|
|
302
|
+
};
|
|
303
|
+
apply();
|
|
304
|
+
return () => {
|
|
305
|
+
cancelled = true;
|
|
306
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
307
|
+
appliedElement?.classList.remove(...classes);
|
|
308
|
+
};
|
|
309
|
+
}, [ref, className, enabled]);
|
|
310
|
+
}
|
|
311
|
+
var variantConfig = {
|
|
312
|
+
white: {
|
|
313
|
+
backgroundColor: colors.white,
|
|
314
|
+
textColor: colors.slateBlue,
|
|
315
|
+
iconBadgeBackgroundColor: colors.stormGray150,
|
|
316
|
+
iconColor: colors.navy
|
|
317
|
+
},
|
|
318
|
+
primary: {
|
|
319
|
+
backgroundColor: colors.navy,
|
|
320
|
+
textColor: colors.stormGray0,
|
|
321
|
+
iconBadgeBackgroundColor: colors.white,
|
|
322
|
+
iconColor: colors.navy
|
|
323
|
+
},
|
|
324
|
+
green: {
|
|
325
|
+
backgroundColor: colors.green,
|
|
326
|
+
textColor: colors.stormGray0,
|
|
327
|
+
iconBadgeBackgroundColor: colors.white,
|
|
328
|
+
iconColor: colors.green
|
|
329
|
+
},
|
|
330
|
+
gray: {
|
|
331
|
+
backgroundColor: colors.stormGray50,
|
|
332
|
+
textColor: colors.slateBlue,
|
|
333
|
+
iconBadgeBackgroundColor: colors.stormGray150,
|
|
334
|
+
iconColor: colors.navy
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
var sizeConfig = {
|
|
338
|
+
lg: {
|
|
339
|
+
/** Matches Tailwind `h-13` so size stays stable before web classNames attach. */
|
|
340
|
+
minHeight: 52,
|
|
341
|
+
borderRadius: 16,
|
|
342
|
+
paddingTop: 8,
|
|
343
|
+
paddingRight: 8,
|
|
344
|
+
paddingBottom: 8,
|
|
345
|
+
paddingLeft: 24,
|
|
346
|
+
paddingHorizontalCentered: 24,
|
|
347
|
+
text: buttonTypography.lg,
|
|
348
|
+
iconContainerSize: 36,
|
|
349
|
+
iconContainerRadius: 12,
|
|
350
|
+
iconContainerPadding: 8,
|
|
351
|
+
iconSize: 20
|
|
352
|
+
},
|
|
353
|
+
sm: {
|
|
354
|
+
minHeight: 40,
|
|
355
|
+
borderRadius: 12,
|
|
356
|
+
paddingTop: 8,
|
|
357
|
+
paddingRight: 8,
|
|
358
|
+
paddingBottom: 8,
|
|
359
|
+
paddingLeft: 16,
|
|
360
|
+
paddingHorizontalCentered: 16,
|
|
361
|
+
text: buttonTypography.sm,
|
|
362
|
+
iconContainerSize: 32,
|
|
363
|
+
iconContainerRadius: 8,
|
|
364
|
+
iconContainerPadding: 8,
|
|
365
|
+
iconSize: 16
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
function Button({
|
|
369
|
+
title,
|
|
370
|
+
children,
|
|
371
|
+
onPress,
|
|
372
|
+
disabled = false,
|
|
373
|
+
variant = "primary",
|
|
374
|
+
size = "lg",
|
|
375
|
+
showIcon = false,
|
|
376
|
+
icon,
|
|
377
|
+
style,
|
|
378
|
+
textStyle,
|
|
379
|
+
className,
|
|
380
|
+
textClassName
|
|
381
|
+
}) {
|
|
382
|
+
const containerRef = react.useRef(null);
|
|
383
|
+
const textRef = react.useRef(null);
|
|
384
|
+
const preset = variantConfig[variant];
|
|
385
|
+
const metrics = sizeConfig[size];
|
|
386
|
+
const label = typeof children !== "undefined" ? children : title;
|
|
387
|
+
const hasCustomChildren = typeof children !== "undefined";
|
|
388
|
+
const customIcon = icon != null && typeof icon !== "boolean" ? icon : void 0;
|
|
389
|
+
const hasIcon = showIcon || icon === true || customIcon != null;
|
|
390
|
+
const resolvedContainerClassName = [reactNative.Platform.OS === "web" ? "max-md:px-4!" : "", className].filter(Boolean).join(" ");
|
|
391
|
+
useApplyWebClassName(containerRef, resolvedContainerClassName || void 0);
|
|
392
|
+
useApplyWebClassName(textRef, textClassName);
|
|
393
|
+
const iconNode = customIcon ?? /* @__PURE__ */ jsxRuntime.jsx(ArrowUpRightIcon, { size: metrics.iconSize, color: preset.iconColor });
|
|
394
|
+
const containerStyle = [
|
|
395
|
+
styles.base,
|
|
396
|
+
{
|
|
397
|
+
minHeight: metrics.minHeight,
|
|
398
|
+
borderRadius: metrics.borderRadius,
|
|
399
|
+
backgroundColor: preset.backgroundColor,
|
|
400
|
+
paddingTop: metrics.paddingTop,
|
|
401
|
+
paddingBottom: metrics.paddingBottom,
|
|
402
|
+
paddingLeft: hasIcon ? metrics.paddingLeft : metrics.paddingHorizontalCentered,
|
|
403
|
+
paddingRight: hasIcon ? metrics.paddingRight : metrics.paddingHorizontalCentered
|
|
404
|
+
},
|
|
405
|
+
hasIcon ? styles.withIcon : styles.centered,
|
|
406
|
+
disabled && styles.disabled,
|
|
407
|
+
style
|
|
408
|
+
];
|
|
409
|
+
const labelStyle = [
|
|
410
|
+
styles.label,
|
|
411
|
+
metrics.text,
|
|
412
|
+
{ color: preset.textColor },
|
|
413
|
+
reactNative.Platform.OS === "android" ? styles.labelAndroid : null,
|
|
414
|
+
!hasIcon && styles.labelCentered,
|
|
415
|
+
hasIcon && styles.labelWithIcon,
|
|
416
|
+
textStyle
|
|
417
|
+
];
|
|
418
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
419
|
+
reactNative.TouchableOpacity,
|
|
420
|
+
{
|
|
421
|
+
ref: containerRef,
|
|
422
|
+
style: containerStyle,
|
|
423
|
+
onPress,
|
|
424
|
+
disabled,
|
|
425
|
+
activeOpacity: 0.7,
|
|
426
|
+
accessibilityRole: "button",
|
|
427
|
+
accessibilityState: { disabled },
|
|
428
|
+
children: [
|
|
429
|
+
hasCustomChildren ? children : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { ref: textRef, style: labelStyle, children: label }),
|
|
430
|
+
hasIcon ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
431
|
+
reactNative.View,
|
|
432
|
+
{
|
|
433
|
+
style: [
|
|
434
|
+
styles.iconContainer,
|
|
435
|
+
{
|
|
436
|
+
width: metrics.iconContainerSize,
|
|
437
|
+
height: metrics.iconContainerSize,
|
|
438
|
+
borderRadius: metrics.iconContainerRadius,
|
|
439
|
+
padding: metrics.iconContainerPadding,
|
|
440
|
+
backgroundColor: preset.iconBadgeBackgroundColor
|
|
441
|
+
}
|
|
442
|
+
],
|
|
443
|
+
children: iconNode
|
|
444
|
+
}
|
|
445
|
+
) : null
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
var styles = reactNative.StyleSheet.create({
|
|
451
|
+
base: {
|
|
452
|
+
flexDirection: "row",
|
|
453
|
+
alignItems: "center",
|
|
454
|
+
borderWidth: 0
|
|
455
|
+
},
|
|
456
|
+
centered: {
|
|
457
|
+
justifyContent: "center"
|
|
458
|
+
},
|
|
459
|
+
withIcon: {
|
|
460
|
+
justifyContent: "space-between"
|
|
461
|
+
},
|
|
462
|
+
disabled: {
|
|
463
|
+
opacity: 0.6
|
|
464
|
+
},
|
|
465
|
+
label: {},
|
|
466
|
+
labelAndroid: {
|
|
467
|
+
includeFontPadding: false
|
|
468
|
+
},
|
|
469
|
+
labelCentered: {
|
|
470
|
+
textAlign: "center"
|
|
471
|
+
},
|
|
472
|
+
labelWithIcon: {
|
|
473
|
+
flex: 1,
|
|
474
|
+
flexShrink: 1,
|
|
475
|
+
marginRight: 8
|
|
476
|
+
},
|
|
477
|
+
iconContainer: {
|
|
478
|
+
alignItems: "center",
|
|
479
|
+
justifyContent: "center",
|
|
480
|
+
flexShrink: 0
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
exports.ArrowUpRightIcon = ArrowUpRightIcon;
|
|
485
|
+
exports.Button = Button;
|
|
486
|
+
exports.brand = brand;
|
|
487
|
+
exports.buttonTypography = buttonTypography;
|
|
488
|
+
exports.colors = colors;
|
|
489
|
+
exports.emeraldGreen = emeraldGreen;
|
|
490
|
+
exports.fontSize = fontSize;
|
|
491
|
+
exports.fontWeight = fontWeight;
|
|
492
|
+
exports.fonts = fonts;
|
|
493
|
+
exports.labelTypography = labelTypography;
|
|
494
|
+
exports.navy = navy;
|
|
495
|
+
exports.radii = radii;
|
|
496
|
+
exports.rubyRed = rubyRed;
|
|
497
|
+
exports.shadows = shadows;
|
|
498
|
+
exports.spacing = spacing;
|
|
499
|
+
exports.stormGray = stormGray;
|
|
500
|
+
exports.typographyScale = typographyScale;
|
|
501
|
+
//# sourceMappingURL=index.cjs.map
|
|
502
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/icons/arrowUpRightPath.ts","../src/icons/ArrowUpRightIcon.tsx","../src/theme/tokens.ts","../src/utils/useApplyWebClassName.ts","../src/components/Button.tsx"],"names":["jsx","Svg","Path","useLayoutEffect","Platform","useRef","jsxs","TouchableOpacity","Text","View","StyleSheet"],"mappings":"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","file":"index.cjs","sourcesContent":["export const ARROW_UP_RIGHT_PATH = \"M14.1667 14.1668V5.8335H5.83333M14.1667 5.8335L5.83333 14.1668\";\n","import Svg, { Path } from \"react-native-svg\";\nimport { ARROW_UP_RIGHT_PATH } from \"./arrowUpRightPath\";\n\nexport { ARROW_UP_RIGHT_PATH } from \"./arrowUpRightPath\";\n\ninterface ArrowUpRightIconProps {\n size?: number;\n color?: string;\n strokeWidth?: number;\n}\n\n/** Native — react-native-svg (peer dependency). */\nexport function ArrowUpRightIcon({\n size = 20,\n color = \"#082640\",\n strokeWidth = 2,\n}: ArrowUpRightIconProps) {\n return (\n <Svg width={size} height={size} viewBox=\"0 0 20 20\" fill=\"none\">\n <Path\n d={ARROW_UP_RIGHT_PATH}\n stroke={color}\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </Svg>\n );\n}\n","/**\n * EcoHouse design tokens — aligned with the shared design system\n * (navy / storm gray / slate-blue palette).\n */\n\n/** Storm Gray scale — Figma steps 0 → 8.5 */\nexport const stormGray = {\n \"0\": \"#fbfcfc\",\n \"0.5\": \"#eceef0\",\n \"1\": \"#dadde0\",\n \"1.5\": \"#c7cdd1\",\n \"2\": \"#b5bcc1\",\n \"3\": \"#8f9aa3\",\n \"4\": \"#6a7984\",\n \"5\": \"#455765\",\n \"6\": \"#374651\",\n \"7\": \"#29343d\",\n \"8\": \"#1c2328\",\n \"8.5\": \"#151a1e\",\n} as const;\n\nexport type StormGrayStep = keyof typeof stormGray;\n\n/** Navy scale — Figma steps 0 → 8.5 */\nexport const navy = {\n \"0\": \"#f6fafe\",\n \"0.5\": \"#dee5eb\",\n \"1\": \"#c6d0d8\",\n \"1.5\": \"#afbac5\",\n \"2\": \"#97a5b2\",\n \"3\": \"#677b8c\",\n \"4\": \"#385066\",\n \"5\": \"#082640\",\n \"6\": \"#061e33\",\n \"7\": \"#051726\",\n \"8\": \"#030f1a\",\n \"8.5\": \"#020b13\",\n} as const;\n\nexport type NavyStep = keyof typeof navy;\n\n/** Ruby Red scale — Figma steps 0 → 8.5 */\nexport const rubyRed = {\n \"0\": \"#fff5f6\",\n \"0.5\": \"#f7dddf\",\n \"1\": \"#efc4c8\",\n \"1.5\": \"#e7acb1\",\n \"2\": \"#df939a\",\n \"3\": \"#ce626d\",\n \"4\": \"#be313f\",\n \"5\": \"#ae0011\",\n \"6\": \"#8b000e\",\n \"7\": \"#68000a\",\n \"8\": \"#460007\",\n \"8.5\": \"#340005\",\n} as const;\n\nexport type RubyRedStep = keyof typeof rubyRed;\n\n/** Emerald Green scale — Figma steps 0 → 8.5 */\nexport const emeraldGreen = {\n \"0\": \"#f0fbf5\",\n \"0.5\": \"#dcf2e5\",\n \"1\": \"#c8e8d5\",\n \"1.5\": \"#b4dfc5\",\n \"2\": \"#a0d5b5\",\n \"3\": \"#77c394\",\n \"4\": \"#4fb074\",\n \"5\": \"#279d54\",\n \"6\": \"#1f7e43\",\n \"7\": \"#175e32\",\n \"8\": \"#103f22\",\n \"8.5\": \"#0c2f19\",\n} as const;\n\nexport type EmeraldGreenStep = keyof typeof emeraldGreen;\n\n/** Figma brand palette — primary swatch per color family */\nexport const brand = {\n slateBlue: \"#182e3c\",\n stormGray: stormGray[\"5\"],\n navy: navy[\"5\"],\n rubyRed: rubyRed[\"5\"],\n emeraldGreen: emeraldGreen[\"5\"],\n} as const;\n\nexport const colors = {\n // Brand colors\n slateBlue: brand.slateBlue,\n\n // Emerald Green — Figma scale + brand swatch\n emeraldGreen0: emeraldGreen[\"0\"],\n emeraldGreen50: emeraldGreen[\"0.5\"],\n emeraldGreen100: emeraldGreen[\"1\"],\n emeraldGreen150: emeraldGreen[\"1.5\"],\n emeraldGreen200: emeraldGreen[\"2\"],\n emeraldGreen300: emeraldGreen[\"3\"],\n emeraldGreen400: emeraldGreen[\"4\"],\n emeraldGreen500: emeraldGreen[\"5\"],\n emeraldGreen600: emeraldGreen[\"6\"],\n emeraldGreen700: emeraldGreen[\"7\"],\n emeraldGreen800: emeraldGreen[\"8\"],\n emeraldGreen850: emeraldGreen[\"8.5\"],\n\n /** Primary brand emerald green — Figma Emerald Green 5 */\n emeraldGreen: brand.emeraldGreen,\n\n // Ruby Red — Figma scale + brand swatch\n rubyRed0: rubyRed[\"0\"],\n rubyRed50: rubyRed[\"0.5\"],\n rubyRed100: rubyRed[\"1\"],\n rubyRed150: rubyRed[\"1.5\"],\n rubyRed200: rubyRed[\"2\"],\n rubyRed300: rubyRed[\"3\"],\n rubyRed400: rubyRed[\"4\"],\n rubyRed500: rubyRed[\"5\"],\n rubyRed600: rubyRed[\"6\"],\n rubyRed700: rubyRed[\"7\"],\n rubyRed800: rubyRed[\"8\"],\n rubyRed850: rubyRed[\"8.5\"],\n\n /** Primary brand ruby red — Figma Ruby Red 5 */\n rubyRed: brand.rubyRed,\n\n // Navy — Figma scale + brand swatch\n navy0: navy[\"0\"],\n navy50: navy[\"0.5\"],\n navy100: navy[\"1\"],\n navy150: navy[\"1.5\"],\n navy200: navy[\"2\"],\n navy300: navy[\"3\"],\n navy400: navy[\"4\"],\n navy500: navy[\"5\"],\n navy600: navy[\"6\"],\n navy700: navy[\"7\"],\n navy800: navy[\"8\"],\n navy850: navy[\"8.5\"],\n\n /** Primary brand navy — Figma Navy 5 */\n navy: brand.navy,\n\n // Storm Gray — Figma scale + brand swatch\n stormGray0: stormGray[\"0\"],\n stormGray50: stormGray[\"0.5\"],\n stormGray100: stormGray[\"1\"],\n stormGray150: stormGray[\"1.5\"],\n stormGray200: stormGray[\"2\"],\n stormGray300: stormGray[\"3\"],\n stormGray400: stormGray[\"4\"],\n stormGray500: stormGray[\"5\"],\n /** Figma brand swatch \"Storm Gray\" — same as `stormGray500` */\n stormGrayBrand: brand.stormGray,\n stormGray600: stormGray[\"6\"],\n stormGray700: stormGray[\"7\"],\n stormGray800: stormGray[\"8\"],\n stormGray850: stormGray[\"8.5\"],\n\n /** @deprecated Use `stormGray0` */\n storm0: stormGray[\"0\"],\n /** @deprecated Use `stormGray50` */\n storm50: stormGray[\"0.5\"],\n /** @deprecated Use `stormGray200` */\n storm200: stormGray[\"2\"],\n /** @deprecated Use `stormGray300` */\n storm300: stormGray[\"3\"],\n /** @deprecated Use `stormGray500` */\n storm500: stormGray[\"5\"],\n /** @deprecated Use `stormGray700` */\n storm700: stormGray[\"7\"],\n /** @deprecated Use `stormGray850` */\n storm900: stormGray[\"8.5\"],\n\n countrySelectorSelectedBg: `${stormGray[\"0.5\"]}99`,\n\n white: \"#ffffff\",\n error: \"#dc2626\",\n errorDark: \"#b3261e\",\n errorLight: \"#fee2e2\",\n /** @deprecated Use `rubyRed` */\n inputError: brand.rubyRed,\n inputOutlineFocus: navy[\"0.5\"],\n inputOutlineError: rubyRed[\"0.5\"],\n warning: \"#92400e\",\n warningBg: \"#fef3c7\",\n success: \"#28a745\",\n successMuted: \"#9fd4a8\",\n /** @deprecated Use `emeraldGreen` */\n green: brand.emeraldGreen,\n transparent: \"transparent\",\n} as const;\n\nexport const radii = {\n sm: 8,\n md: 12,\n lg: 16,\n xl: 20,\n full: 9999,\n} as const;\n\nexport const spacing = {\n xs: 4,\n sm: 8,\n md: 12,\n lg: 16,\n xl: 24,\n xxl: 32,\n} as const;\n\nexport const fontSize = {\n xs: 11,\n sm: 12,\n md: 14,\n base: 16,\n lg: 18,\n xl: 24,\n xxl: 32,\n} as const;\n\n/**\n * Canonical Homepad type scale (matches `.typography-*` in `src/web/styles/typography.css`).\n * font-size / line-height pairs:\n * 12/16 · 14/19 · 18/24 · 20/27 · 24/25 · 32/34\n */\nexport const typographyScale = {\n 12: { fontSize: 12, lineHeight: 16 },\n 14: { fontSize: 14, lineHeight: 19 },\n 18: { fontSize: 18, lineHeight: 24 },\n 20: { fontSize: 20, lineHeight: 27 },\n 24: { fontSize: 24, lineHeight: 25 },\n 32: { fontSize: 32, lineHeight: 34 },\n} as const;\n\nexport const fontWeight = {\n regular: \"400\" as const,\n medium: \"500\" as const,\n semibold: \"600\" as const,\n bold: \"700\" as const,\n};\n\nexport const fonts = {\n sans: \"Noto Sans Armenian\",\n} as const;\n\n/** Input label typography — Medium, typography-12 scale. */\nexport const labelTypography = {\n fontFamily: fonts.sans,\n fontSize: typographyScale[12].fontSize,\n fontWeight: fontWeight.medium,\n lineHeight: typographyScale[12].lineHeight,\n letterSpacing: 0,\n} as const;\n\n/** Button label typography — SemiBold. */\nexport const buttonTypography = {\n lg: {\n fontFamily: fonts.sans,\n fontSize: typographyScale[14].fontSize,\n fontWeight: fontWeight.semibold,\n lineHeight: typographyScale[14].lineHeight,\n letterSpacing: 0,\n },\n sm: {\n fontFamily: fonts.sans,\n fontSize: typographyScale[12].fontSize,\n fontWeight: fontWeight.semibold,\n lineHeight: typographyScale[12].lineHeight,\n letterSpacing: 0,\n },\n} as const;\n\nexport const shadows = {\n card: {\n shadowColor: colors.navy,\n shadowOffset: { width: 0, height: 4 },\n shadowOpacity: 0.05,\n shadowRadius: 20,\n elevation: 2,\n },\n cardLg: {\n shadowColor: colors.navy,\n shadowOffset: { width: 0, height: 4 },\n shadowOpacity: 0.1,\n shadowRadius: 20,\n elevation: 4,\n },\n} as const;\n","import { useLayoutEffect } from \"react\";\nimport { Platform } from \"react-native\";\n\ninterface ClassListElement {\n classList: {\n add: (...classes: string[]) => void;\n remove: (...classes: string[]) => void;\n };\n}\n\nfunction hasClassList(node: unknown): node is ClassListElement {\n return (\n typeof node === \"object\" &&\n node !== null &&\n \"classList\" in node &&\n typeof (node as ClassListElement).classList?.add === \"function\"\n );\n}\n\nfunction resolveWebElement(ref: React.RefObject<unknown>): ClassListElement | null {\n const node = ref.current;\n if (!node) return null;\n\n if (hasClassList(node)) return node;\n\n const host = node as {\n _touchableNode?: unknown;\n getScrollableNode?: () => unknown;\n };\n\n if (hasClassList(host._touchableNode)) return host._touchableNode;\n\n if (typeof host.getScrollableNode === \"function\") {\n const scrollNode = host.getScrollableNode();\n if (hasClassList(scrollNode)) return scrollNode;\n }\n\n return null;\n}\n\n/**\n * Applies CSS class names to the underlying DOM node on web.\n * Keeps TouchableOpacity/Text as the render path so default RN styles stay intact.\n *\n * Retries via rAF when the host node is not ready yet — otherwise classes like\n * `h-13` / `w-full` would only land after a later re-render (e.g. typing in a form),\n * which visibly changes button size.\n */\nexport function useApplyWebClassName(\n ref: React.RefObject<unknown>,\n className?: string,\n enabled = true,\n): void {\n useLayoutEffect(() => {\n if (!enabled || Platform.OS !== \"web\" || !className?.trim()) return;\n\n let cancelled = false;\n let rafId = 0;\n let appliedElement: ClassListElement | null = null;\n const classes = className.trim().split(/\\s+/);\n\n const apply = () => {\n if (cancelled) return;\n\n const element = resolveWebElement(ref);\n if (!element) {\n rafId = requestAnimationFrame(apply);\n return;\n }\n\n appliedElement = element;\n element.classList.add(...classes);\n };\n\n apply();\n\n return () => {\n cancelled = true;\n if (rafId) cancelAnimationFrame(rafId);\n appliedElement?.classList.remove(...classes);\n };\n }, [ref, className, enabled]);\n}\n","import { useRef, type ComponentRef, type ReactNode } from \"react\";\nimport {\n Platform,\n StyleSheet,\n Text,\n TouchableOpacity,\n View,\n type GestureResponderEvent,\n type StyleProp,\n type TextStyle,\n type ViewStyle,\n} from \"react-native\";\nimport { ArrowUpRightIcon } from \"../icons/ArrowUpRightIcon\";\nimport { colors, buttonTypography } from \"../theme/tokens\";\nimport { useApplyWebClassName } from \"../utils/useApplyWebClassName\";\n\nexport type ButtonVariant = \"white\" | \"primary\" | \"green\" | \"gray\";\nexport type ButtonSize = \"lg\" | \"sm\";\n\nexport interface ButtonProps {\n title?: string;\n children?: ReactNode;\n onPress: (event: GestureResponderEvent) => void;\n disabled?: boolean;\n variant?: ButtonVariant;\n size?: ButtonSize;\n showIcon?: boolean;\n /** Custom icon inside the badge. Defaults to `ArrowUpRightIcon` when `showIcon` is true. */\n icon?: ReactNode;\n style?: StyleProp<ViewStyle>;\n textStyle?: StyleProp<TextStyle>;\n className?: string;\n textClassName?: string;\n}\n\ntype VariantStyleSet = {\n backgroundColor: string;\n textColor: string;\n iconBadgeBackgroundColor: string;\n iconColor: string;\n};\n\nconst variantConfig: Record<ButtonVariant, VariantStyleSet> = {\n white: {\n backgroundColor: colors.white,\n textColor: colors.slateBlue,\n iconBadgeBackgroundColor: colors.stormGray150,\n iconColor: colors.navy,\n },\n primary: {\n backgroundColor: colors.navy,\n textColor: colors.stormGray0,\n iconBadgeBackgroundColor: colors.white,\n iconColor: colors.navy,\n },\n green: {\n backgroundColor: colors.green,\n textColor: colors.stormGray0,\n iconBadgeBackgroundColor: colors.white,\n iconColor: colors.green,\n },\n gray: {\n backgroundColor: colors.stormGray50,\n textColor: colors.slateBlue,\n iconBadgeBackgroundColor: colors.stormGray150,\n iconColor: colors.navy,\n },\n};\n\nconst sizeConfig = {\n lg: {\n /** Matches Tailwind `h-13` so size stays stable before web classNames attach. */\n minHeight: 52,\n borderRadius: 16,\n paddingTop: 8,\n paddingRight: 8,\n paddingBottom: 8,\n paddingLeft: 24,\n paddingHorizontalCentered: 24,\n text: buttonTypography.lg,\n iconContainerSize: 36,\n iconContainerRadius: 12,\n iconContainerPadding: 8,\n iconSize: 20,\n },\n sm: {\n minHeight: 40,\n borderRadius: 12,\n paddingTop: 8,\n paddingRight: 8,\n paddingBottom: 8,\n paddingLeft: 16,\n paddingHorizontalCentered: 16,\n text: buttonTypography.sm,\n iconContainerSize: 32,\n iconContainerRadius: 8,\n iconContainerPadding: 8,\n iconSize: 16,\n },\n} as const;\n\nexport function Button({\n title,\n children,\n onPress,\n disabled = false,\n variant = \"primary\",\n size = \"lg\",\n showIcon = false,\n icon,\n style,\n textStyle,\n className,\n textClassName,\n}: ButtonProps) {\n const containerRef = useRef<ComponentRef<typeof TouchableOpacity>>(null);\n const textRef = useRef<ComponentRef<typeof Text>>(null);\n const preset = variantConfig[variant];\n const metrics = sizeConfig[size];\n\n const label = typeof children !== \"undefined\" ? children : title;\n const hasCustomChildren = typeof children !== \"undefined\";\n const customIcon = icon != null && typeof icon !== \"boolean\" ? icon : undefined;\n const hasIcon = showIcon || icon === true || customIcon != null;\n const resolvedContainerClassName = [Platform.OS === \"web\" ? \"max-md:px-4!\" : \"\", className]\n .filter(Boolean)\n .join(\" \");\n\n useApplyWebClassName(containerRef, resolvedContainerClassName || undefined);\n useApplyWebClassName(textRef, textClassName);\n\n const iconNode = customIcon ?? (\n <ArrowUpRightIcon size={metrics.iconSize} color={preset.iconColor} />\n );\n\n const containerStyle = [\n styles.base,\n {\n minHeight: metrics.minHeight,\n borderRadius: metrics.borderRadius,\n backgroundColor: preset.backgroundColor,\n paddingTop: metrics.paddingTop,\n paddingBottom: metrics.paddingBottom,\n paddingLeft: hasIcon ? metrics.paddingLeft : metrics.paddingHorizontalCentered,\n paddingRight: hasIcon ? metrics.paddingRight : metrics.paddingHorizontalCentered,\n },\n hasIcon ? styles.withIcon : styles.centered,\n disabled && styles.disabled,\n style,\n ];\n\n const labelStyle = [\n styles.label,\n metrics.text,\n { color: preset.textColor },\n Platform.OS === \"android\" ? styles.labelAndroid : null,\n !hasIcon && styles.labelCentered,\n hasIcon && styles.labelWithIcon,\n textStyle,\n ];\n\n return (\n <TouchableOpacity\n ref={containerRef}\n style={containerStyle}\n onPress={onPress}\n disabled={disabled}\n activeOpacity={0.7}\n accessibilityRole=\"button\"\n accessibilityState={{ disabled }}\n >\n {hasCustomChildren ? (\n children\n ) : (\n <Text ref={textRef} style={labelStyle}>\n {label}\n </Text>\n )}\n\n {hasIcon ? (\n <View\n style={[\n styles.iconContainer,\n {\n width: metrics.iconContainerSize,\n height: metrics.iconContainerSize,\n borderRadius: metrics.iconContainerRadius,\n padding: metrics.iconContainerPadding,\n backgroundColor: preset.iconBadgeBackgroundColor,\n },\n ]}\n >\n {iconNode}\n </View>\n ) : null}\n </TouchableOpacity>\n );\n}\n\nconst styles = StyleSheet.create({\n base: {\n flexDirection: \"row\",\n alignItems: \"center\",\n borderWidth: 0,\n },\n centered: {\n justifyContent: \"center\",\n },\n withIcon: {\n justifyContent: \"space-between\",\n },\n disabled: {\n opacity: 0.6,\n },\n label: {},\n labelAndroid: {\n includeFontPadding: false,\n },\n labelCentered: {\n textAlign: \"center\",\n },\n labelWithIcon: {\n flex: 1,\n flexShrink: 1,\n marginRight: 8,\n },\n iconContainer: {\n alignItems: \"center\",\n justifyContent: \"center\",\n flexShrink: 0,\n },\n});\n"]}
|