@korsolutions/ui 0.0.12 → 0.0.13

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.
Files changed (36) hide show
  1. package/dist/components/index.d.mts +38 -3
  2. package/dist/components/index.mjs +171 -7
  3. package/dist/{index-Dafk8ZGv.d.mts → index-_E4x_kNB.d.mts} +95 -6
  4. package/dist/index.d.mts +3 -3
  5. package/dist/primitives/index.d.mts +2 -2
  6. package/dist/primitives/index.mjs +2 -2
  7. package/dist/{primitives-C2enZ5Ku.mjs → primitives-DQMWXbuX.mjs} +121 -4
  8. package/package.json +7 -4
  9. package/src/components/avatar/avatar.tsx +23 -0
  10. package/src/components/avatar/variants/default.tsx +30 -0
  11. package/src/components/avatar/variants/index.ts +5 -0
  12. package/src/components/button/variants/default.tsx +7 -1
  13. package/src/components/button/variants/index.ts +2 -0
  14. package/src/components/button/variants/secondary.tsx +58 -0
  15. package/src/components/empty/empty.tsx +26 -0
  16. package/src/components/empty/variants/default.tsx +35 -0
  17. package/src/components/empty/variants/index.ts +5 -0
  18. package/src/components/index.ts +2 -0
  19. package/src/primitives/avatar/avatar-fallback.tsx +16 -0
  20. package/src/primitives/avatar/avatar-image.tsx +17 -0
  21. package/src/primitives/avatar/avatar-root.tsx +21 -0
  22. package/src/primitives/avatar/context.ts +16 -0
  23. package/src/primitives/avatar/index.ts +14 -0
  24. package/src/primitives/avatar/types.ts +9 -0
  25. package/src/primitives/button/button-root.tsx +9 -4
  26. package/src/primitives/button/types.ts +1 -1
  27. package/src/primitives/empty/context.ts +16 -0
  28. package/src/primitives/empty/empty-description.tsx +16 -0
  29. package/src/primitives/empty/empty-media.tsx +16 -0
  30. package/src/primitives/empty/empty-root.tsx +21 -0
  31. package/src/primitives/empty/empty-title.tsx +16 -0
  32. package/src/primitives/empty/index.ts +17 -0
  33. package/src/primitives/empty/types.ts +11 -0
  34. package/src/primitives/index.ts +2 -0
  35. package/src/utils/hsla-utils.ts +26 -0
  36. package/tsconfig.json +1 -0
@@ -1,10 +1,11 @@
1
- import { E as InputStyles, f as SelectStyles, k as FieldStyles, r as CardStyles, u as SelectRootBaseProps, w as InputPrimitiveBaseProps, x as ButtonStyles } from "../index-Dafk8ZGv.mjs";
1
+ import { B as FieldStyles, C as SelectStyles, F as InputPrimitiveBaseProps, L as InputStyles, M as ButtonStyles, c as EmptyStyles, m as CardStyles, r as AvatarStyles, x as SelectRootBaseProps } from "../index-_E4x_kNB.mjs";
2
2
  import React from "react";
3
- import { TextProps, TextStyle } from "react-native";
3
+ import { ImageSource, TextProps, TextStyle } from "react-native";
4
4
 
5
5
  //#region src/components/button/variants/index.d.ts
6
6
  declare const ButtonVariants: {
7
7
  default: () => ButtonStyles;
8
+ secondary: () => ButtonStyles;
8
9
  };
9
10
  //#endregion
10
11
  //#region src/components/button/button.d.ts
@@ -131,4 +132,38 @@ interface LinkProps extends TextProps {
131
132
  }
132
133
  declare function Link(props: LinkProps): React.JSX.Element;
133
134
  //#endregion
134
- export { Button, Card, Field, FieldProps, Input, Link, LinkProps, Select, SelectOption, SelectProps, Typography, TypographyProps };
135
+ //#region src/components/empty/variants/default.d.ts
136
+ declare function useEmptyVariantDefault(): EmptyStyles;
137
+ //#endregion
138
+ //#region src/components/empty/variants/index.d.ts
139
+ declare const EmptyVariants: {
140
+ default: typeof useEmptyVariantDefault;
141
+ };
142
+ //#endregion
143
+ //#region src/components/empty/empty.d.ts
144
+ interface EmptyProps {
145
+ children?: React.ReactNode;
146
+ media?: React.ReactNode;
147
+ title: string;
148
+ description?: string;
149
+ variant?: keyof typeof EmptyVariants;
150
+ }
151
+ declare function Empty(props: EmptyProps): React.JSX.Element;
152
+ //#endregion
153
+ //#region src/components/avatar/variants/default.d.ts
154
+ declare function useAvatarVariantDefault(): AvatarStyles;
155
+ //#endregion
156
+ //#region src/components/avatar/variants/index.d.ts
157
+ declare const AvatarVariants: {
158
+ default: typeof useAvatarVariantDefault;
159
+ };
160
+ //#endregion
161
+ //#region src/components/avatar/avatar.d.ts
162
+ interface AvatarProps {
163
+ source?: ImageSource;
164
+ fallback: string;
165
+ variant?: keyof typeof AvatarVariants;
166
+ }
167
+ declare function Avatar(props: AvatarProps): React.JSX.Element;
168
+ //#endregion
169
+ export { Avatar, AvatarProps, Button, Card, Empty, EmptyProps, Field, FieldProps, Input, Link, LinkProps, Select, SelectOption, SelectProps, Typography, TypographyProps };
@@ -1,10 +1,29 @@
1
1
  import { n as useTheme } from "../themes-DXcjBdO2.mjs";
2
2
  import "../portal-DoPaAohb.mjs";
3
- import { a as FieldPrimitive, i as InputPrimitive, n as SelectPrimitive, r as ButtonPrimitive, t as CardPrimitive } from "../primitives-C2enZ5Ku.mjs";
4
- import React from "react";
3
+ import { a as ButtonPrimitive, i as SelectPrimitive, n as EmptyPrimitive, o as InputPrimitive, r as CardPrimitive, s as FieldPrimitive, t as AvatarPrimitive } from "../primitives-DQMWXbuX.mjs";
4
+ import React, { useState } from "react";
5
5
  import { Linking, Text } from "react-native";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
 
8
+ //#region src/utils/hsla-utils.ts
9
+ const hslaSetLightness = (hsla, lightness) => {
10
+ const parts = hsla.replace(/^hsla?\(|\s+|\)$/g, "").split(",");
11
+ if (parts.length < 3) throw new Error("Invalid HSLA color format");
12
+ return `hsla(${parseInt(parts[0], 10)}, ${parseInt(parts[1], 10)}%, ${lightness}%, ${parts[3] ? parseFloat(parts[3]) : 1})`;
13
+ };
14
+ const hslaGetLightness = (hsla) => {
15
+ const parts = hsla.replace(/^hsla?\(|\s+|\)$/g, "").split(",");
16
+ if (parts.length < 3) throw new Error("Invalid HSLA color format");
17
+ return parseInt(parts[2], 10);
18
+ };
19
+ const hslaSetRelativeLightness = (hsla, delta) => {
20
+ let newLightness = hslaGetLightness(hsla) + delta;
21
+ if (newLightness > 100) newLightness = 100;
22
+ if (newLightness < 0) newLightness = 0;
23
+ return hslaSetLightness(hsla, newLightness);
24
+ };
25
+
26
+ //#endregion
8
27
  //#region src/utils/use-themed-styles.ts
9
28
  const useThemedStyles = (callback) => {
10
29
  const theme = useTheme();
@@ -24,16 +43,19 @@ const useButtonVariantDefault = () => {
24
43
  root: {
25
44
  default: {
26
45
  flexDirection: "row",
27
- backgroundColor: colors.primary,
28
46
  paddingVertical: 12,
29
47
  paddingHorizontal: 16,
30
48
  borderRadius: radius,
31
49
  gap: 8,
32
50
  alignItems: "center",
33
- justifyContent: "center"
51
+ justifyContent: "center",
52
+ backgroundColor: colors.primary,
53
+ borderWidth: 1,
54
+ borderColor: colors.border
34
55
  },
35
56
  disabled: { opacity: .5 },
36
- loading: { opacity: .8 }
57
+ loading: { opacity: .8 },
58
+ hovered: { backgroundColor: hslaSetRelativeLightness(colors.primary, -10) }
37
59
  },
38
60
  label: {
39
61
  default: {
@@ -53,9 +75,51 @@ const useButtonVariantDefault = () => {
53
75
  }));
54
76
  };
55
77
 
78
+ //#endregion
79
+ //#region src/components/button/variants/secondary.tsx
80
+ const useButtonVariantSecondary = () => {
81
+ return useThemedStyles(({ colors, radius, fontFamily, fontSize }) => ({
82
+ root: {
83
+ default: {
84
+ flexDirection: "row",
85
+ paddingVertical: 12,
86
+ paddingHorizontal: 16,
87
+ borderRadius: radius,
88
+ gap: 8,
89
+ alignItems: "center",
90
+ justifyContent: "center",
91
+ borderWidth: 1,
92
+ borderColor: colors.border,
93
+ backgroundColor: colors.secondary
94
+ },
95
+ disabled: { opacity: .5 },
96
+ loading: { opacity: .8 },
97
+ hovered: { backgroundColor: hslaSetRelativeLightness(colors.secondary, -1) }
98
+ },
99
+ label: {
100
+ default: {
101
+ color: colors.foreground,
102
+ fontSize,
103
+ fontWeight: "bold",
104
+ fontFamily
105
+ },
106
+ disabled: { color: colors.mutedForeground },
107
+ loading: { color: colors.mutedForeground }
108
+ },
109
+ spinner: {
110
+ default: { color: colors.primaryForeground },
111
+ disabled: { color: colors.mutedForeground },
112
+ loading: { color: colors.mutedForeground }
113
+ }
114
+ }));
115
+ };
116
+
56
117
  //#endregion
57
118
  //#region src/components/button/variants/index.ts
58
- const ButtonVariants = { default: useButtonVariantDefault };
119
+ const ButtonVariants = {
120
+ default: useButtonVariantDefault,
121
+ secondary: useButtonVariantSecondary
122
+ };
59
123
 
60
124
  //#endregion
61
125
  //#region src/components/button/button.tsx
@@ -417,4 +481,104 @@ function Link(props) {
417
481
  }
418
482
 
419
483
  //#endregion
420
- export { Button, Card, Field, Input, Link, Select, Typography };
484
+ //#region src/components/empty/variants/default.tsx
485
+ function useEmptyVariantDefault() {
486
+ return useThemedStyles(({ colors, fontFamily, fontSize }) => ({
487
+ root: {
488
+ alignItems: "center",
489
+ padding: 32,
490
+ gap: 32
491
+ },
492
+ media: {
493
+ backgroundColor: colors.muted,
494
+ width: 64,
495
+ height: 64,
496
+ borderRadius: "50%",
497
+ alignItems: "center",
498
+ justifyContent: "center"
499
+ },
500
+ title: {
501
+ fontFamily,
502
+ fontSize,
503
+ color: colors.foreground,
504
+ textAlign: "center",
505
+ fontWeight: "600"
506
+ },
507
+ description: {
508
+ fontFamily,
509
+ fontSize: fontSize * .875,
510
+ color: colors.mutedForeground,
511
+ textAlign: "center"
512
+ }
513
+ }));
514
+ }
515
+
516
+ //#endregion
517
+ //#region src/components/empty/variants/index.ts
518
+ const EmptyVariants = { default: useEmptyVariantDefault };
519
+
520
+ //#endregion
521
+ //#region src/components/empty/empty.tsx
522
+ function Empty(props) {
523
+ const useVariantStyles = EmptyVariants[props.variant || "default"];
524
+ const styles = useVariantStyles();
525
+ return /* @__PURE__ */ jsxs(EmptyPrimitive.Root, {
526
+ styles,
527
+ children: [
528
+ !!props.media && /* @__PURE__ */ jsx(EmptyPrimitive.Media, { children: props.media }),
529
+ /* @__PURE__ */ jsx(EmptyPrimitive.Title, { children: props.title }),
530
+ props.description && /* @__PURE__ */ jsx(EmptyPrimitive.Description, { children: props.description }),
531
+ props.children
532
+ ]
533
+ });
534
+ }
535
+
536
+ //#endregion
537
+ //#region src/components/avatar/variants/default.tsx
538
+ function useAvatarVariantDefault() {
539
+ return useThemedStyles(({ colors, fontFamily, fontSize }) => ({
540
+ root: {
541
+ backgroundColor: colors.surface,
542
+ borderRadius: "50%",
543
+ overflow: "hidden",
544
+ width: 64,
545
+ height: 64,
546
+ alignItems: "center",
547
+ justifyContent: "center"
548
+ },
549
+ image: {
550
+ width: "100%",
551
+ height: "100%",
552
+ resizeMode: "cover"
553
+ },
554
+ fallback: {
555
+ fontFamily,
556
+ fontSize,
557
+ color: colors.foreground,
558
+ textAlign: "center",
559
+ verticalAlign: "middle"
560
+ }
561
+ }));
562
+ }
563
+
564
+ //#endregion
565
+ //#region src/components/avatar/variants/index.ts
566
+ const AvatarVariants = { default: useAvatarVariantDefault };
567
+
568
+ //#endregion
569
+ //#region src/components/avatar/avatar.tsx
570
+ function Avatar(props) {
571
+ const useVariantStyles = AvatarVariants[props.variant || "default"];
572
+ const styles = useVariantStyles();
573
+ const [imageError, setImageError] = useState(false);
574
+ return /* @__PURE__ */ jsxs(AvatarPrimitive.Root, {
575
+ styles,
576
+ children: [props.source && /* @__PURE__ */ jsx(AvatarPrimitive.Image, {
577
+ source: props.source,
578
+ onError: () => setImageError(true)
579
+ }), (!props.source || imageError) && /* @__PURE__ */ jsx(AvatarPrimitive.Fallback, { children: props.fallback })]
580
+ });
581
+ }
582
+
583
+ //#endregion
584
+ export { Avatar, Button, Card, Empty, Field, Input, Link, Select, Typography };
@@ -1,6 +1,6 @@
1
- import * as react2 from "react";
1
+ import * as react0 from "react";
2
2
  import React$1 from "react";
3
- import { StyleProp, TextInputProps, TextProps, TextStyle, ViewStyle } from "react-native";
3
+ import { ImageSource, ImageStyle, StyleProp, TextInputProps, TextProps, TextStyle, ViewStyle } from "react-native";
4
4
 
5
5
  //#region src/primitives/field/field-label.d.ts
6
6
  interface FieldLabelProps {
@@ -65,7 +65,7 @@ interface InputPrimitiveProps extends InputPrimitiveBaseProps {
65
65
  render?: (props: InputPrimitiveProps) => React.ReactNode;
66
66
  styles?: InputStyles;
67
67
  }
68
- declare function InputPrimitive(props: InputPrimitiveProps): react2.JSX.Element;
68
+ declare function InputPrimitive(props: InputPrimitiveProps): react0.JSX.Element;
69
69
  //#endregion
70
70
  //#region src/primitives/button/button-label.d.ts
71
71
  interface ButtonPrimitiveLabelProps {
@@ -76,7 +76,7 @@ interface ButtonPrimitiveLabelProps {
76
76
  declare function ButtonLabel(props: ButtonPrimitiveLabelProps): React$1.JSX.Element;
77
77
  //#endregion
78
78
  //#region src/primitives/button/types.d.ts
79
- type ButtonState = "default" | "disabled" | "loading";
79
+ type ButtonState = "default" | "disabled" | "loading" | "hovered";
80
80
  interface ButtonStyles {
81
81
  root?: Partial<Record<ButtonState, ButtonPrimitiveRootProps["style"]>>;
82
82
  label?: Partial<Record<ButtonState, ButtonPrimitiveLabelProps["style"]>>;
@@ -152,7 +152,7 @@ interface SelectOptionProps {
152
152
  render?: (props: SelectOptionProps) => React.ReactElement;
153
153
  style?: StyleProp<TextStyle>;
154
154
  }
155
- declare function SelectOption(props: SelectOptionProps): react2.JSX.Element;
155
+ declare function SelectOption(props: SelectOptionProps): react0.JSX.Element;
156
156
  //#endregion
157
157
  //#region src/primitives/select/types.d.ts
158
158
  type SelectState = "default" | "disabled";
@@ -262,4 +262,93 @@ declare const CardPrimitive: {
262
262
  Footer: typeof CardFooter;
263
263
  };
264
264
  //#endregion
265
- export { FieldErrorProps as A, InputPrimitive as C, FieldPrimitive as D, InputStyles as E, FieldLabelProps as M, FieldPrimitiveRootProps as O, ButtonPrimitiveLabelProps as S, InputPrimitiveProps as T, SelectTriggerProps as _, CardBodyProps as a, ButtonState as b, SelectPrimitive as c, SelectRootProps as d, SelectStyles as f, SelectValueProps as g, SelectOverlayProps as h, CardFooterProps as i, FieldDescriptionProps as j, FieldStyles as k, SelectPortalProps as l, SelectContentProps as m, CardRootProps as n, CardTitleProps as o, SelectOptionProps as p, CardStyles as r, CardHeaderProps as s, CardPrimitive as t, SelectRootBaseProps as u, ButtonPrimitive as v, InputPrimitiveBaseProps as w, ButtonStyles as x, ButtonPrimitiveRootProps as y };
265
+ //#region src/primitives/empty/empty-description.d.ts
266
+ interface EmptyDescriptionProps {
267
+ children: string;
268
+ render?: (props: EmptyDescriptionProps) => React$1.ReactNode;
269
+ style?: StyleProp<TextStyle>;
270
+ }
271
+ declare function EmptyDescription(props: EmptyDescriptionProps): React$1.JSX.Element;
272
+ //#endregion
273
+ //#region src/primitives/empty/empty-media.d.ts
274
+ interface EmptyMediaProps {
275
+ children: React$1.ReactNode;
276
+ render?: (props: EmptyMediaProps) => React$1.ReactNode;
277
+ style?: StyleProp<ViewStyle>;
278
+ }
279
+ declare function EmptyMedia(props: EmptyMediaProps): React$1.JSX.Element;
280
+ //#endregion
281
+ //#region src/primitives/empty/empty-title.d.ts
282
+ interface EmptyTitleProps {
283
+ children: string;
284
+ render?: (props: EmptyTitleProps) => React$1.ReactNode;
285
+ style?: StyleProp<TextStyle>;
286
+ }
287
+ declare function EmptyTitle(props: EmptyTitleProps): React$1.JSX.Element;
288
+ //#endregion
289
+ //#region src/primitives/empty/types.d.ts
290
+ type EmptyStyles = {
291
+ root?: EmptyRootProps["style"];
292
+ media?: EmptyMediaProps["style"];
293
+ title?: EmptyTitleProps["style"];
294
+ description?: EmptyDescriptionProps["style"];
295
+ };
296
+ //#endregion
297
+ //#region src/primitives/empty/empty-root.d.ts
298
+ interface EmptyRootProps {
299
+ children: React$1.ReactNode;
300
+ render?: (props: EmptyRootProps) => React$1.ReactNode;
301
+ style?: StyleProp<ViewStyle>;
302
+ styles?: EmptyStyles;
303
+ }
304
+ declare function EmptyRoot(props: EmptyRootProps): React$1.JSX.Element;
305
+ //#endregion
306
+ //#region src/primitives/empty/index.d.ts
307
+ declare const EmptyPrimitive: {
308
+ Root: typeof EmptyRoot;
309
+ Media: typeof EmptyMedia;
310
+ Title: typeof EmptyTitle;
311
+ Description: typeof EmptyDescription;
312
+ };
313
+ //#endregion
314
+ //#region src/primitives/avatar/avatar-fallback.d.ts
315
+ interface AvatarFallbackProps {
316
+ children: string;
317
+ render?: (props: AvatarFallbackProps) => React$1.ReactNode;
318
+ style?: StyleProp<TextStyle>;
319
+ }
320
+ declare function AvatarFallback(props: AvatarFallbackProps): React$1.JSX.Element;
321
+ //#endregion
322
+ //#region src/primitives/avatar/avatar-image.d.ts
323
+ interface AvatarImageProps {
324
+ source: ImageSource;
325
+ onError: () => void;
326
+ render?: (props: AvatarImageProps) => React$1.ReactNode;
327
+ style?: StyleProp<ImageStyle>;
328
+ }
329
+ declare function AvatarImage(props: AvatarImageProps): React$1.JSX.Element;
330
+ //#endregion
331
+ //#region src/primitives/avatar/types.d.ts
332
+ type AvatarStyles = {
333
+ root?: AvatarRootProps["style"];
334
+ image?: AvatarImageProps["style"];
335
+ fallback?: AvatarFallbackProps["style"];
336
+ };
337
+ //#endregion
338
+ //#region src/primitives/avatar/avatar-root.d.ts
339
+ interface AvatarRootProps {
340
+ children: React$1.ReactNode;
341
+ render?: (props: AvatarRootProps) => React$1.ReactNode;
342
+ style?: StyleProp<ViewStyle>;
343
+ styles?: AvatarStyles;
344
+ }
345
+ declare function AvatarRoot(props: AvatarRootProps): React$1.JSX.Element;
346
+ //#endregion
347
+ //#region src/primitives/avatar/index.d.ts
348
+ declare const AvatarPrimitive: {
349
+ Root: typeof AvatarRoot;
350
+ Image: typeof AvatarImage;
351
+ Fallback: typeof AvatarFallback;
352
+ };
353
+ //#endregion
354
+ export { ButtonPrimitiveRootProps as A, FieldStyles as B, SelectStyles as C, SelectValueProps as D, SelectOverlayProps as E, InputPrimitiveBaseProps as F, FieldDescriptionProps as H, InputPrimitiveProps as I, InputStyles as L, ButtonStyles as M, ButtonPrimitiveLabelProps as N, SelectTriggerProps as O, InputPrimitive as P, FieldPrimitive as R, SelectRootProps as S, SelectContentProps as T, FieldLabelProps as U, FieldErrorProps as V, CardTitleProps as _, AvatarFallbackProps as a, SelectPortalProps as b, EmptyStyles as c, EmptyDescriptionProps as d, CardPrimitive as f, CardBodyProps as g, CardFooterProps as h, AvatarImageProps as i, ButtonState as j, ButtonPrimitive as k, EmptyTitleProps as l, CardStyles as m, AvatarRootProps as n, EmptyPrimitive as o, CardRootProps as p, AvatarStyles as r, EmptyRootProps as s, AvatarPrimitive as t, EmptyMediaProps as u, CardHeaderProps as v, SelectOptionProps as w, SelectRootBaseProps as x, SelectPrimitive as y, FieldPrimitiveRootProps as z };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import * as react0 from "react";
1
+ import * as react2 from "react";
2
2
 
3
3
  //#region src/themes/types.d.ts
4
4
  type ThemeName = "default";
@@ -37,7 +37,7 @@ interface ThemeContext {
37
37
  setTheme: (themeName: ThemeName) => void;
38
38
  themeName: ThemeName;
39
39
  }
40
- declare const ThemeContext: react0.Context<ThemeContext | null>;
40
+ declare const ThemeContext: react2.Context<ThemeContext | null>;
41
41
  declare const useTheme: () => ThemeContext;
42
42
  //#endregion
43
43
  //#region src/index.d.ts
@@ -45,6 +45,6 @@ declare const UniversalUIProvider: ({
45
45
  children
46
46
  }: {
47
47
  children: React.ReactNode;
48
- }) => react0.JSX.Element;
48
+ }) => react2.JSX.Element;
49
49
  //#endregion
50
50
  export { UniversalUIProvider, useTheme };
@@ -1,2 +1,2 @@
1
- import { A as FieldErrorProps, C as InputPrimitive, D as FieldPrimitive, E as InputStyles, M as FieldLabelProps, O as FieldPrimitiveRootProps, S as ButtonPrimitiveLabelProps, T as InputPrimitiveProps, _ as SelectTriggerProps, a as CardBodyProps, b as ButtonState, c as SelectPrimitive, d as SelectRootProps, f as SelectStyles, g as SelectValueProps, h as SelectOverlayProps, i as CardFooterProps, j as FieldDescriptionProps, k as FieldStyles, l as SelectPortalProps, m as SelectContentProps, n as CardRootProps, o as CardTitleProps, p as SelectOptionProps, r as CardStyles, s as CardHeaderProps, t as CardPrimitive, u as SelectRootBaseProps, v as ButtonPrimitive, w as InputPrimitiveBaseProps, x as ButtonStyles, y as ButtonPrimitiveRootProps } from "../index-Dafk8ZGv.mjs";
2
- export { ButtonPrimitive, ButtonPrimitiveLabelProps, ButtonPrimitiveRootProps, ButtonState, ButtonStyles, CardBodyProps, CardFooterProps, CardHeaderProps, CardPrimitive, CardRootProps, CardStyles, CardTitleProps, FieldDescriptionProps, FieldErrorProps, FieldLabelProps, FieldPrimitive, FieldPrimitiveRootProps, FieldStyles, InputPrimitive, InputPrimitiveBaseProps, InputPrimitiveProps, InputStyles, SelectContentProps, SelectOptionProps, SelectOverlayProps, SelectPortalProps, SelectPrimitive, SelectRootBaseProps, SelectRootProps, SelectStyles, SelectTriggerProps, SelectValueProps };
1
+ import { A as ButtonPrimitiveRootProps, B as FieldStyles, C as SelectStyles, D as SelectValueProps, E as SelectOverlayProps, F as InputPrimitiveBaseProps, H as FieldDescriptionProps, I as InputPrimitiveProps, L as InputStyles, M as ButtonStyles, N as ButtonPrimitiveLabelProps, O as SelectTriggerProps, P as InputPrimitive, R as FieldPrimitive, S as SelectRootProps, T as SelectContentProps, U as FieldLabelProps, V as FieldErrorProps, _ as CardTitleProps, a as AvatarFallbackProps, b as SelectPortalProps, c as EmptyStyles, d as EmptyDescriptionProps, f as CardPrimitive, g as CardBodyProps, h as CardFooterProps, i as AvatarImageProps, j as ButtonState, k as ButtonPrimitive, l as EmptyTitleProps, m as CardStyles, n as AvatarRootProps, o as EmptyPrimitive, p as CardRootProps, r as AvatarStyles, s as EmptyRootProps, t as AvatarPrimitive, u as EmptyMediaProps, v as CardHeaderProps, w as SelectOptionProps, x as SelectRootBaseProps, y as SelectPrimitive, z as FieldPrimitiveRootProps } from "../index-_E4x_kNB.mjs";
2
+ export { AvatarFallbackProps, AvatarImageProps, AvatarPrimitive, AvatarRootProps, AvatarStyles, ButtonPrimitive, ButtonPrimitiveLabelProps, ButtonPrimitiveRootProps, ButtonState, ButtonStyles, CardBodyProps, CardFooterProps, CardHeaderProps, CardPrimitive, CardRootProps, CardStyles, CardTitleProps, EmptyDescriptionProps, EmptyMediaProps, EmptyPrimitive, EmptyRootProps, EmptyStyles, EmptyTitleProps, FieldDescriptionProps, FieldErrorProps, FieldLabelProps, FieldPrimitive, FieldPrimitiveRootProps, FieldStyles, InputPrimitive, InputPrimitiveBaseProps, InputPrimitiveProps, InputStyles, SelectContentProps, SelectOptionProps, SelectOverlayProps, SelectPortalProps, SelectPrimitive, SelectRootBaseProps, SelectRootProps, SelectStyles, SelectTriggerProps, SelectValueProps };
@@ -1,4 +1,4 @@
1
1
  import "../portal-DoPaAohb.mjs";
2
- import { a as FieldPrimitive, i as InputPrimitive, n as SelectPrimitive, r as ButtonPrimitive, t as CardPrimitive } from "../primitives-C2enZ5Ku.mjs";
2
+ import { a as ButtonPrimitive, i as SelectPrimitive, n as EmptyPrimitive, o as InputPrimitive, r as CardPrimitive, s as FieldPrimitive, t as AvatarPrimitive } from "../primitives-DQMWXbuX.mjs";
3
3
 
4
- export { ButtonPrimitive, CardPrimitive, FieldPrimitive, InputPrimitive, SelectPrimitive };
4
+ export { AvatarPrimitive, ButtonPrimitive, CardPrimitive, EmptyPrimitive, FieldPrimitive, InputPrimitive, SelectPrimitive };
@@ -1,6 +1,6 @@
1
1
  import { t as Portal } from "./portal-DoPaAohb.mjs";
2
2
  import React, { createContext, useContext, useEffect, useState } from "react";
3
- import { ActivityIndicator, Pressable, StyleSheet, Text, TextInput, View } from "react-native";
3
+ import { ActivityIndicator, Image, Pressable, StyleSheet, Text, TextInput, View } from "react-native";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
 
6
6
  //#region src/primitives/field/context.ts
@@ -113,13 +113,15 @@ const useButtonPrimitive = () => {
113
113
 
114
114
  //#endregion
115
115
  //#region src/primitives/button/button-root.tsx
116
- const calculateState$2 = (props) => {
116
+ const calculateState$2 = (props, isHovered) => {
117
117
  if (props.isDisabled) return "disabled";
118
118
  if (props.isLoading) return "loading";
119
+ if (isHovered) return "hovered";
119
120
  return "default";
120
121
  };
121
122
  function ButtonRoot(props) {
122
- const state = calculateState$2(props);
123
+ const [isHovered, setIsHovered] = useState(false);
124
+ const state = calculateState$2(props, isHovered);
123
125
  const calculatedStyle = [
124
126
  props.styles?.root?.default,
125
127
  props.styles?.root?.[state],
@@ -134,6 +136,8 @@ function ButtonRoot(props) {
134
136
  },
135
137
  children: /* @__PURE__ */ jsx(Container, {
136
138
  ...props,
139
+ onHoverIn: () => setIsHovered(true),
140
+ onHoverOut: () => setIsHovered(false),
137
141
  style: calculatedStyle
138
142
  })
139
143
  });
@@ -438,4 +442,117 @@ const CardPrimitive = {
438
442
  };
439
443
 
440
444
  //#endregion
441
- export { FieldPrimitive as a, InputPrimitive as i, SelectPrimitive as n, ButtonPrimitive as r, CardPrimitive as t };
445
+ //#region src/primitives/empty/context.ts
446
+ const EmptyContext = createContext({});
447
+ const useEmpty = () => {
448
+ const context = useContext(EmptyContext);
449
+ if (!context) throw new Error("useEmptyContext must be used within a EmptyProvider");
450
+ return context;
451
+ };
452
+
453
+ //#endregion
454
+ //#region src/primitives/empty/empty-root.tsx
455
+ function EmptyRoot(props) {
456
+ const composedStyles = [props.styles?.root, props.style];
457
+ const Component = props.render ?? View;
458
+ return /* @__PURE__ */ jsx(EmptyContext.Provider, {
459
+ value: { styles: props.styles },
460
+ children: /* @__PURE__ */ jsx(Component, {
461
+ ...props,
462
+ style: composedStyles
463
+ })
464
+ });
465
+ }
466
+
467
+ //#endregion
468
+ //#region src/primitives/empty/empty-media.tsx
469
+ function EmptyMedia(props) {
470
+ const composedStyles = [useEmpty().styles?.media, props.style];
471
+ return /* @__PURE__ */ jsx(props.render ?? View, {
472
+ ...props,
473
+ style: composedStyles
474
+ });
475
+ }
476
+
477
+ //#endregion
478
+ //#region src/primitives/empty/empty-title.tsx
479
+ function EmptyTitle(props) {
480
+ const composedStyles = [useEmpty().styles?.title, props.style];
481
+ return /* @__PURE__ */ jsx(props.render ?? Text, {
482
+ ...props,
483
+ style: composedStyles
484
+ });
485
+ }
486
+
487
+ //#endregion
488
+ //#region src/primitives/empty/empty-description.tsx
489
+ function EmptyDescription(props) {
490
+ const composedStyles = [useEmpty().styles?.description, props.style];
491
+ return /* @__PURE__ */ jsx(props.render ?? Text, {
492
+ ...props,
493
+ style: composedStyles
494
+ });
495
+ }
496
+
497
+ //#endregion
498
+ //#region src/primitives/empty/index.ts
499
+ const EmptyPrimitive = {
500
+ Root: EmptyRoot,
501
+ Media: EmptyMedia,
502
+ Title: EmptyTitle,
503
+ Description: EmptyDescription
504
+ };
505
+
506
+ //#endregion
507
+ //#region src/primitives/avatar/context.ts
508
+ const AvatarContext = createContext(void 0);
509
+ const useAvatar = () => {
510
+ const context = useContext(AvatarContext);
511
+ if (!context) throw new Error("useAvatarContext must be used within a AvatarProvider");
512
+ return context;
513
+ };
514
+
515
+ //#endregion
516
+ //#region src/primitives/avatar/avatar-root.tsx
517
+ function AvatarRoot(props) {
518
+ const composedStyles = [props.styles?.root, props.style];
519
+ const Component = props.render ?? View;
520
+ return /* @__PURE__ */ jsx(AvatarContext.Provider, {
521
+ value: { styles: props.styles },
522
+ children: /* @__PURE__ */ jsx(Component, {
523
+ ...props,
524
+ style: composedStyles
525
+ })
526
+ });
527
+ }
528
+
529
+ //#endregion
530
+ //#region src/primitives/avatar/avatar-fallback.tsx
531
+ function AvatarFallback(props) {
532
+ const composedStyles = [useAvatar().styles?.fallback, props.style];
533
+ return /* @__PURE__ */ jsx(props.render ?? View, {
534
+ ...props,
535
+ style: composedStyles
536
+ });
537
+ }
538
+
539
+ //#endregion
540
+ //#region src/primitives/avatar/avatar-image.tsx
541
+ function AvatarImage(props) {
542
+ const composedStyles = [useAvatar().styles?.image, props.style];
543
+ return /* @__PURE__ */ jsx(props.render ?? Image, {
544
+ ...props,
545
+ style: composedStyles
546
+ });
547
+ }
548
+
549
+ //#endregion
550
+ //#region src/primitives/avatar/index.ts
551
+ const AvatarPrimitive = {
552
+ Root: AvatarRoot,
553
+ Image: AvatarImage,
554
+ Fallback: AvatarFallback
555
+ };
556
+
557
+ //#endregion
558
+ export { ButtonPrimitive as a, SelectPrimitive as i, EmptyPrimitive as n, InputPrimitive as o, CardPrimitive as r, FieldPrimitive as s, AvatarPrimitive as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@korsolutions/ui",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.mjs",
6
6
  "module": "dist/index.mjs",
@@ -8,15 +8,18 @@
8
8
  "exports": {
9
9
  ".": {
10
10
  "default": "./dist/index.mjs",
11
- "types": "./dist/index.d.mts"
11
+ "types": "./dist/index.d.mts",
12
+ "dev-source": "./src/index.ts"
12
13
  },
13
14
  "./primitives": {
14
15
  "default": "./dist/primitives/index.mjs",
15
- "types": "./dist/primitives/index.d.mts"
16
+ "types": "./dist/primitives/index.d.mts",
17
+ "dev-source": "./src/primitives/index.ts"
16
18
  },
17
19
  "./components": {
18
20
  "default": "./dist/components/index.mjs",
19
- "types": "./dist/components/index.d.mts"
21
+ "types": "./dist/components/index.d.mts",
22
+ "dev-source": "./src/components/index.ts"
20
23
  }
21
24
  },
22
25
  "scripts": {
@@ -0,0 +1,23 @@
1
+ import { AvatarPrimitive } from "@/primitives";
2
+ import React, { useState } from "react";
3
+ import { ImageSource } from "react-native";
4
+ import { AvatarVariants } from "./variants";
5
+
6
+ export interface AvatarProps {
7
+ source?: ImageSource;
8
+ fallback: string;
9
+
10
+ variant?: keyof typeof AvatarVariants;
11
+ }
12
+
13
+ export function Avatar(props: AvatarProps) {
14
+ const useVariantStyles = AvatarVariants[props.variant || "default"];
15
+ const styles = useVariantStyles();
16
+ const [imageError, setImageError] = useState(false);
17
+ return (
18
+ <AvatarPrimitive.Root styles={styles}>
19
+ {props.source && <AvatarPrimitive.Image source={props.source} onError={() => setImageError(true)} />}
20
+ {(!props.source || imageError) && <AvatarPrimitive.Fallback>{props.fallback}</AvatarPrimitive.Fallback>}
21
+ </AvatarPrimitive.Root>
22
+ );
23
+ }
@@ -0,0 +1,30 @@
1
+ import { AvatarStyles } from "@/primitives";
2
+ import { useThemedStyles } from "@/utils/use-themed-styles";
3
+
4
+ export function useAvatarVariantDefault(): AvatarStyles {
5
+ return useThemedStyles(
6
+ ({ colors, fontFamily, fontSize }): AvatarStyles => ({
7
+ root: {
8
+ backgroundColor: colors.surface,
9
+ borderRadius: "50%",
10
+ overflow: "hidden",
11
+ width: 64,
12
+ height: 64,
13
+ alignItems: "center",
14
+ justifyContent: "center",
15
+ },
16
+ image: {
17
+ width: "100%",
18
+ height: "100%",
19
+ resizeMode: "cover",
20
+ },
21
+ fallback: {
22
+ fontFamily,
23
+ fontSize,
24
+ color: colors.foreground,
25
+ textAlign: "center",
26
+ verticalAlign: "middle",
27
+ },
28
+ })
29
+ );
30
+ }
@@ -0,0 +1,5 @@
1
+ import { useAvatarVariantDefault } from "./default";
2
+
3
+ export const AvatarVariants = {
4
+ default: useAvatarVariantDefault,
5
+ };
@@ -1,4 +1,5 @@
1
1
  import { ButtonStyles } from "@/primitives";
2
+ import { hslaSetRelativeLightness } from "@/utils/hsla-utils";
2
3
  import { useThemedStyles } from "@/utils/use-themed-styles";
3
4
 
4
5
  export const useButtonVariantDefault = (): ButtonStyles => {
@@ -7,13 +8,15 @@ export const useButtonVariantDefault = (): ButtonStyles => {
7
8
  root: {
8
9
  default: {
9
10
  flexDirection: "row",
10
- backgroundColor: colors.primary,
11
11
  paddingVertical: 12,
12
12
  paddingHorizontal: 16,
13
13
  borderRadius: radius,
14
14
  gap: 8,
15
15
  alignItems: "center",
16
16
  justifyContent: "center",
17
+ backgroundColor: colors.primary,
18
+ borderWidth: 1,
19
+ borderColor: colors.border,
17
20
  },
18
21
  disabled: {
19
22
  opacity: 0.5,
@@ -21,6 +24,9 @@ export const useButtonVariantDefault = (): ButtonStyles => {
21
24
  loading: {
22
25
  opacity: 0.8,
23
26
  },
27
+ hovered: {
28
+ backgroundColor: hslaSetRelativeLightness(colors.primary, -10),
29
+ },
24
30
  },
25
31
  label: {
26
32
  default: {
@@ -1,5 +1,7 @@
1
1
  import { useButtonVariantDefault } from "./default";
2
+ import { useButtonVariantSecondary } from "./secondary";
2
3
 
3
4
  export const ButtonVariants = {
4
5
  default: useButtonVariantDefault,
6
+ secondary: useButtonVariantSecondary,
5
7
  };
@@ -0,0 +1,58 @@
1
+ import { ButtonStyles } from "@/primitives";
2
+ import { hslaSetRelativeLightness } from "@/utils/hsla-utils";
3
+ import { useThemedStyles } from "@/utils/use-themed-styles";
4
+
5
+ export const useButtonVariantSecondary = (): ButtonStyles => {
6
+ return useThemedStyles(
7
+ ({ colors, radius, fontFamily, fontSize }): ButtonStyles => ({
8
+ root: {
9
+ default: {
10
+ flexDirection: "row",
11
+ paddingVertical: 12,
12
+ paddingHorizontal: 16,
13
+ borderRadius: radius,
14
+ gap: 8,
15
+ alignItems: "center",
16
+ justifyContent: "center",
17
+ borderWidth: 1,
18
+ borderColor: colors.border,
19
+ backgroundColor: colors.secondary,
20
+ },
21
+ disabled: {
22
+ opacity: 0.5,
23
+ },
24
+ loading: {
25
+ opacity: 0.8,
26
+ },
27
+ hovered: {
28
+ backgroundColor: hslaSetRelativeLightness(colors.secondary, -1),
29
+ },
30
+ },
31
+ label: {
32
+ default: {
33
+ color: colors.foreground,
34
+ fontSize,
35
+ fontWeight: "bold",
36
+ fontFamily,
37
+ },
38
+ disabled: {
39
+ color: colors.mutedForeground,
40
+ },
41
+ loading: {
42
+ color: colors.mutedForeground,
43
+ },
44
+ },
45
+ spinner: {
46
+ default: {
47
+ color: colors.primaryForeground,
48
+ },
49
+ disabled: {
50
+ color: colors.mutedForeground,
51
+ },
52
+ loading: {
53
+ color: colors.mutedForeground,
54
+ },
55
+ },
56
+ })
57
+ );
58
+ };
@@ -0,0 +1,26 @@
1
+ import { EmptyPrimitive } from "@/primitives";
2
+ import React from "react";
3
+ import { EmptyVariants } from "./variants";
4
+
5
+ export interface EmptyProps {
6
+ children?: React.ReactNode;
7
+ media?: React.ReactNode;
8
+ title: string;
9
+ description?: string;
10
+
11
+ variant?: keyof typeof EmptyVariants;
12
+ }
13
+
14
+ export function Empty(props: EmptyProps) {
15
+ const useVariantStyles = EmptyVariants[props.variant || "default"];
16
+ const styles = useVariantStyles();
17
+
18
+ return (
19
+ <EmptyPrimitive.Root styles={styles}>
20
+ {!!props.media && <EmptyPrimitive.Media>{props.media}</EmptyPrimitive.Media>}
21
+ <EmptyPrimitive.Title>{props.title}</EmptyPrimitive.Title>
22
+ {props.description && <EmptyPrimitive.Description>{props.description}</EmptyPrimitive.Description>}
23
+ {props.children}
24
+ </EmptyPrimitive.Root>
25
+ );
26
+ }
@@ -0,0 +1,35 @@
1
+ import { EmptyStyles } from "@/primitives";
2
+ import { useThemedStyles } from "@/utils/use-themed-styles";
3
+
4
+ export function useEmptyVariantDefault(): EmptyStyles {
5
+ return useThemedStyles(
6
+ ({ colors, fontFamily, fontSize }): EmptyStyles => ({
7
+ root: {
8
+ alignItems: "center",
9
+ padding: 32,
10
+ gap: 32,
11
+ },
12
+ media: {
13
+ backgroundColor: colors.muted,
14
+ width: 64,
15
+ height: 64,
16
+ borderRadius: "50%",
17
+ alignItems: "center",
18
+ justifyContent: "center",
19
+ },
20
+ title: {
21
+ fontFamily: fontFamily,
22
+ fontSize: fontSize,
23
+ color: colors.foreground,
24
+ textAlign: "center",
25
+ fontWeight: "600",
26
+ },
27
+ description: {
28
+ fontFamily: fontFamily,
29
+ fontSize: fontSize * 0.875,
30
+ color: colors.mutedForeground,
31
+ textAlign: "center",
32
+ },
33
+ })
34
+ );
35
+ }
@@ -0,0 +1,5 @@
1
+ import { useEmptyVariantDefault } from "./default";
2
+
3
+ export const EmptyVariants = {
4
+ default: useEmptyVariantDefault,
5
+ };
@@ -5,3 +5,5 @@ export * from "./field/field";
5
5
  export * from "./select/select";
6
6
  export * from "./typography/typography";
7
7
  export * from "./link/link";
8
+ export * from "./empty/empty";
9
+ export * from "./avatar/avatar";
@@ -0,0 +1,16 @@
1
+ import React from "react";
2
+ import { StyleProp, TextStyle, View } from "react-native";
3
+ import { useAvatar } from "./context";
4
+
5
+ export interface AvatarFallbackProps {
6
+ children: string;
7
+ render?: (props: AvatarFallbackProps) => React.ReactNode;
8
+ style?: StyleProp<TextStyle>;
9
+ }
10
+
11
+ export function AvatarFallback(props: AvatarFallbackProps) {
12
+ const avatar = useAvatar();
13
+ const composedStyles = [avatar.styles?.fallback, props.style];
14
+ const Component = props.render ?? View;
15
+ return <Component {...props} style={composedStyles} />;
16
+ }
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ import { Image, ImageSource, ImageStyle, StyleProp } from "react-native";
3
+ import { useAvatar } from "./context";
4
+
5
+ export interface AvatarImageProps {
6
+ source: ImageSource;
7
+ onError: () => void;
8
+ render?: (props: AvatarImageProps) => React.ReactNode;
9
+ style?: StyleProp<ImageStyle>;
10
+ }
11
+
12
+ export function AvatarImage(props: AvatarImageProps) {
13
+ const avatar = useAvatar();
14
+ const composedStyles = [avatar.styles?.image, props.style];
15
+ const Component = props.render ?? Image;
16
+ return <Component {...props} style={composedStyles} />;
17
+ }
@@ -0,0 +1,21 @@
1
+ import React from "react";
2
+ import { StyleProp, View, ViewStyle } from "react-native";
3
+ import { AvatarContext } from "./context";
4
+ import { AvatarStyles } from "./types";
5
+
6
+ export interface AvatarRootProps {
7
+ children: React.ReactNode;
8
+ render?: (props: AvatarRootProps) => React.ReactNode;
9
+ style?: StyleProp<ViewStyle>;
10
+ styles?: AvatarStyles;
11
+ }
12
+
13
+ export function AvatarRoot(props: AvatarRootProps) {
14
+ const composedStyles = [props.styles?.root, props.style];
15
+ const Component = props.render ?? View;
16
+ return (
17
+ <AvatarContext.Provider value={{ styles: props.styles }}>
18
+ <Component {...props} style={composedStyles} />
19
+ </AvatarContext.Provider>
20
+ );
21
+ }
@@ -0,0 +1,16 @@
1
+ import { createContext, useContext } from "react";
2
+ import { AvatarStyles } from "./types";
3
+
4
+ export interface AvatarContext {
5
+ styles?: AvatarStyles;
6
+ }
7
+
8
+ export const AvatarContext = createContext<AvatarContext | undefined>(undefined);
9
+
10
+ export const useAvatar = () => {
11
+ const context = useContext(AvatarContext);
12
+ if (!context) {
13
+ throw new Error("useAvatarContext must be used within a AvatarProvider");
14
+ }
15
+ return context;
16
+ };
@@ -0,0 +1,14 @@
1
+ import { AvatarRoot } from "./avatar-root";
2
+ import { AvatarFallback } from "./avatar-fallback";
3
+ import { AvatarImage } from "./avatar-image";
4
+
5
+ export const AvatarPrimitive = {
6
+ Root: AvatarRoot,
7
+ Image: AvatarImage,
8
+ Fallback: AvatarFallback,
9
+ };
10
+
11
+ export type { AvatarRootProps } from "./avatar-root";
12
+ export type { AvatarFallbackProps } from "./avatar-fallback";
13
+ export type { AvatarImageProps } from "./avatar-image";
14
+ export type { AvatarStyles } from "./types";
@@ -0,0 +1,9 @@
1
+ import { AvatarFallbackProps } from "./avatar-fallback";
2
+ import { AvatarImageProps } from "./avatar-image";
3
+ import { AvatarRootProps } from "./avatar-root";
4
+
5
+ export type AvatarStyles = {
6
+ root?: AvatarRootProps["style"];
7
+ image?: AvatarImageProps["style"];
8
+ fallback?: AvatarFallbackProps["style"];
9
+ };
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { useState } from "react";
2
2
  import { Pressable, StyleProp, ViewStyle } from "react-native";
3
3
  import { ButtonStyles, ButtonState } from "./types";
4
4
  import { ButtonPrimitiveContext } from "./button-context";
@@ -17,25 +17,30 @@ export interface ButtonPrimitiveRootProps {
17
17
  render?: (props: this) => React.ReactElement;
18
18
  }
19
19
 
20
- const calculateState = (props: ButtonPrimitiveRootProps): ButtonState => {
20
+ const calculateState = (props: ButtonPrimitiveRootProps, isHovered: boolean): ButtonState => {
21
21
  if (props.isDisabled) {
22
22
  return "disabled";
23
23
  }
24
24
  if (props.isLoading) {
25
25
  return "loading";
26
26
  }
27
+ if (isHovered) {
28
+ return "hovered";
29
+ }
27
30
  return "default";
28
31
  };
29
32
 
30
33
  export function ButtonRoot(props: ButtonPrimitiveRootProps) {
31
- const state = calculateState(props);
34
+ const [isHovered, setIsHovered] = useState(false);
35
+
36
+ const state = calculateState(props, isHovered);
32
37
 
33
38
  const calculatedStyle = [props.styles?.root?.default, props.styles?.root?.[state], props.style];
34
39
 
35
40
  const Container = props.render ?? Pressable;
36
41
  return (
37
42
  <ButtonPrimitiveContext.Provider value={{ disabled: props.isDisabled, state, styles: props.styles }}>
38
- <Container {...props} style={calculatedStyle} />
43
+ <Container {...props} onHoverIn={() => setIsHovered(true)} onHoverOut={() => setIsHovered(false)} style={calculatedStyle} />
39
44
  </ButtonPrimitiveContext.Provider>
40
45
  );
41
46
  }
@@ -1,7 +1,7 @@
1
1
  import { ButtonPrimitiveRootProps } from "./button-root";
2
2
  import { ButtonPrimitiveLabelProps } from "./button-label";
3
3
 
4
- export type ButtonState = "default" | "disabled" | "loading";
4
+ export type ButtonState = "default" | "disabled" | "loading" | "hovered";
5
5
 
6
6
  export interface ButtonStyles {
7
7
  root?: Partial<Record<ButtonState, ButtonPrimitiveRootProps["style"]>>;
@@ -0,0 +1,16 @@
1
+ import { createContext, useContext } from "react";
2
+ import { EmptyStyles } from "./types";
3
+
4
+ export interface EmptyContext {
5
+ styles?: EmptyStyles;
6
+ }
7
+
8
+ export const EmptyContext = createContext<EmptyContext>({});
9
+
10
+ export const useEmpty = () => {
11
+ const context = useContext(EmptyContext);
12
+ if (!context) {
13
+ throw new Error("useEmptyContext must be used within a EmptyProvider");
14
+ }
15
+ return context;
16
+ };
@@ -0,0 +1,16 @@
1
+ import React from "react";
2
+ import { StyleProp, Text, TextStyle } from "react-native";
3
+ import { useEmpty } from "./context";
4
+
5
+ export interface EmptyDescriptionProps {
6
+ children: string;
7
+ render?: (props: EmptyDescriptionProps) => React.ReactNode;
8
+ style?: StyleProp<TextStyle>;
9
+ }
10
+
11
+ export function EmptyDescription(props: EmptyDescriptionProps) {
12
+ const empty = useEmpty();
13
+ const composedStyles = [empty.styles?.description, props.style];
14
+ const Component = props.render ?? Text;
15
+ return <Component {...props} style={composedStyles} />;
16
+ }
@@ -0,0 +1,16 @@
1
+ import React from "react";
2
+ import { StyleProp, View, ViewStyle } from "react-native";
3
+ import { useEmpty } from "./context";
4
+
5
+ export interface EmptyMediaProps {
6
+ children: React.ReactNode;
7
+ render?: (props: EmptyMediaProps) => React.ReactNode;
8
+ style?: StyleProp<ViewStyle>;
9
+ }
10
+
11
+ export function EmptyMedia(props: EmptyMediaProps) {
12
+ const empty = useEmpty();
13
+ const composedStyles = [empty.styles?.media, props.style];
14
+ const Component = props.render ?? View;
15
+ return <Component {...props} style={composedStyles} />;
16
+ }
@@ -0,0 +1,21 @@
1
+ import React from "react";
2
+ import { StyleProp, View, ViewStyle } from "react-native";
3
+ import { EmptyContext } from "./context";
4
+ import { EmptyStyles } from "./types";
5
+
6
+ export interface EmptyRootProps {
7
+ children: React.ReactNode;
8
+ render?: (props: EmptyRootProps) => React.ReactNode;
9
+ style?: StyleProp<ViewStyle>;
10
+ styles?: EmptyStyles;
11
+ }
12
+
13
+ export function EmptyRoot(props: EmptyRootProps) {
14
+ const composedStyles = [props.styles?.root, props.style];
15
+ const Component = props.render ?? View;
16
+ return (
17
+ <EmptyContext.Provider value={{ styles: props.styles }}>
18
+ <Component {...props} style={composedStyles} />
19
+ </EmptyContext.Provider>
20
+ );
21
+ }
@@ -0,0 +1,16 @@
1
+ import React from "react";
2
+ import { useEmpty } from "./context";
3
+ import { StyleProp, Text, TextStyle } from "react-native";
4
+
5
+ export interface EmptyTitleProps {
6
+ children: string;
7
+ render?: (props: EmptyTitleProps) => React.ReactNode;
8
+ style?: StyleProp<TextStyle>;
9
+ }
10
+
11
+ export function EmptyTitle(props: EmptyTitleProps) {
12
+ const empty = useEmpty();
13
+ const composedStyles = [empty.styles?.title, props.style];
14
+ const Component = props.render ?? Text;
15
+ return <Component {...props} style={composedStyles} />;
16
+ }
@@ -0,0 +1,17 @@
1
+ import { EmptyRoot } from "./empty-root";
2
+ import { EmptyMedia } from "./empty-media";
3
+ import { EmptyTitle } from "./empty-title";
4
+ import { EmptyDescription } from "./empty-description";
5
+
6
+ export const EmptyPrimitive = {
7
+ Root: EmptyRoot,
8
+ Media: EmptyMedia,
9
+ Title: EmptyTitle,
10
+ Description: EmptyDescription,
11
+ };
12
+
13
+ export type { EmptyRootProps } from "./empty-root";
14
+ export type { EmptyMediaProps } from "./empty-media";
15
+ export type { EmptyTitleProps } from "./empty-title";
16
+ export type { EmptyDescriptionProps } from "./empty-description";
17
+ export type { EmptyStyles } from "./types";
@@ -0,0 +1,11 @@
1
+ import { EmptyDescriptionProps } from "./empty-description";
2
+ import { EmptyMediaProps } from "./empty-media";
3
+ import { EmptyRootProps } from "./empty-root";
4
+ import { EmptyTitleProps } from "./empty-title";
5
+
6
+ export type EmptyStyles = {
7
+ root?: EmptyRootProps["style"];
8
+ media?: EmptyMediaProps["style"];
9
+ title?: EmptyTitleProps["style"];
10
+ description?: EmptyDescriptionProps["style"];
11
+ };
@@ -3,3 +3,5 @@ export * from "./input";
3
3
  export * from "./button";
4
4
  export * from "./select";
5
5
  export * from "./card";
6
+ export * from "./empty";
7
+ export * from "./avatar";
@@ -8,3 +8,29 @@ export const hslaSetAlpha = (hsla: string, alpha: number): string => {
8
8
  const l = parseInt(parts[2], 10);
9
9
  return `hsla(${h}, ${s}%, ${l}%, ${alpha})`;
10
10
  };
11
+
12
+ export const hslaSetLightness = (hsla: string, lightness: number): string => {
13
+ const parts = hsla.replace(/^hsla?\(|\s+|\)$/g, "").split(",");
14
+ if (parts.length < 3) {
15
+ throw new Error("Invalid HSLA color format");
16
+ }
17
+ const h = parseInt(parts[0], 10);
18
+ const s = parseInt(parts[1], 10);
19
+ return `hsla(${h}, ${s}%, ${lightness}%, ${parts[3] ? parseFloat(parts[3]) : 1})`;
20
+ };
21
+
22
+ export const hslaGetLightness = (hsla: string): number => {
23
+ const parts = hsla.replace(/^hsla?\(|\s+|\)$/g, "").split(",");
24
+ if (parts.length < 3) {
25
+ throw new Error("Invalid HSLA color format");
26
+ }
27
+ return parseInt(parts[2], 10);
28
+ };
29
+
30
+ export const hslaSetRelativeLightness = (hsla: string, delta: number): string => {
31
+ const currentLightness = hslaGetLightness(hsla);
32
+ let newLightness = currentLightness + delta;
33
+ if (newLightness > 100) newLightness = 100;
34
+ if (newLightness < 0) newLightness = 0;
35
+ return hslaSetLightness(hsla, newLightness);
36
+ };
package/tsconfig.json CHANGED
@@ -4,6 +4,7 @@
4
4
  "strict": true,
5
5
  "noUnusedLocals": true,
6
6
  "noUnusedParameters": true,
7
+ "customConditions": ["dev-source"],
7
8
  "paths": {
8
9
  "@/*": ["./src/*"]
9
10
  }