@innovui/react-native 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +57 -2
- package/dist/components/_shared/anchored-overlay.js +74 -0
- package/dist/components/_shared/anchored-overlay.js.map +1 -0
- package/dist/components/_shared/backdrop.js +25 -0
- package/dist/components/_shared/backdrop.js.map +1 -0
- package/dist/components/_shared/overlay-anchor.js +31 -0
- package/dist/components/_shared/overlay-anchor.js.map +1 -0
- package/dist/components/_shared/overlay-state.js +31 -0
- package/dist/components/_shared/overlay-state.js.map +1 -0
- package/dist/components/_shared/status.d.ts +5 -0
- package/dist/components/_shared/status.js +98 -0
- package/dist/components/_shared/status.js.map +1 -0
- package/dist/components/_shared/use-token.js +15 -0
- package/dist/components/_shared/use-token.js.map +1 -0
- package/dist/components/accordion/accordion.d.ts +43 -0
- package/dist/components/accordion/accordion.js +90 -0
- package/dist/components/accordion/accordion.js.map +1 -0
- package/dist/components/accordion/index.d.ts +2 -0
- package/dist/components/alert/alert.d.ts +25 -0
- package/dist/components/alert/alert.js +61 -0
- package/dist/components/alert/alert.js.map +1 -0
- package/dist/components/alert/index.d.ts +2 -0
- package/dist/components/avatar/avatar.d.ts +17 -0
- package/dist/components/avatar/avatar.js +51 -0
- package/dist/components/avatar/avatar.js.map +1 -0
- package/dist/components/avatar/index.d.ts +2 -0
- package/dist/components/badge/badge.d.ts +16 -0
- package/dist/components/badge/badge.js +57 -0
- package/dist/components/badge/badge.js.map +1 -0
- package/dist/components/badge/index.d.ts +2 -0
- package/dist/components/banner/banner.d.ts +23 -0
- package/dist/components/banner/banner.js +50 -0
- package/dist/components/banner/banner.js.map +1 -0
- package/dist/components/banner/index.d.ts +2 -0
- package/dist/components/breadcrumb/breadcrumb.d.ts +22 -0
- package/dist/components/breadcrumb/breadcrumb.js +54 -0
- package/dist/components/breadcrumb/breadcrumb.js.map +1 -0
- package/dist/components/breadcrumb/index.d.ts +2 -0
- package/dist/components/button/button.d.ts +21 -0
- package/dist/components/button/button.js +89 -0
- package/dist/components/button/button.js.map +1 -0
- package/dist/components/button/index.d.ts +2 -0
- package/dist/components/card/card.d.ts +17 -0
- package/dist/components/card/card.js +28 -0
- package/dist/components/card/card.js.map +1 -0
- package/dist/components/card/index.d.ts +2 -0
- package/dist/components/checkbox/checkbox.d.ts +18 -0
- package/dist/components/checkbox/checkbox.js +64 -0
- package/dist/components/checkbox/checkbox.js.map +1 -0
- package/dist/components/checkbox/index.d.ts +2 -0
- package/dist/components/combobox/combobox.d.ts +40 -0
- package/dist/components/combobox/combobox.js +101 -0
- package/dist/components/combobox/combobox.js.map +1 -0
- package/dist/components/combobox/index.d.ts +2 -0
- package/dist/components/container/container.d.ts +17 -0
- package/dist/components/container/container.js +42 -0
- package/dist/components/container/container.js.map +1 -0
- package/dist/components/container/index.d.ts +2 -0
- package/dist/components/date-picker/calendar.d.ts +38 -0
- package/dist/components/date-picker/calendar.js +137 -0
- package/dist/components/date-picker/calendar.js.map +1 -0
- package/dist/components/date-picker/date-picker.d.ts +24 -0
- package/dist/components/date-picker/date-picker.js +52 -0
- package/dist/components/date-picker/date-picker.js.map +1 -0
- package/dist/components/date-picker/date-presets.d.ts +15 -0
- package/dist/components/date-picker/date-presets.js +52 -0
- package/dist/components/date-picker/date-presets.js.map +1 -0
- package/dist/components/date-picker/date-range-picker.d.ts +24 -0
- package/dist/components/date-picker/date-range-picker.js +78 -0
- package/dist/components/date-picker/date-range-picker.js.map +1 -0
- package/dist/components/date-picker/date-sheet.js +33 -0
- package/dist/components/date-picker/date-sheet.js.map +1 -0
- package/dist/components/date-picker/date-trigger.js +14 -0
- package/dist/components/date-picker/date-trigger.js.map +1 -0
- package/dist/components/date-picker/dates.d.ts +8 -0
- package/dist/components/date-picker/dates.js +40 -0
- package/dist/components/date-picker/dates.js.map +1 -0
- package/dist/components/date-picker/index.d.ts +6 -0
- package/dist/components/divider/divider.d.ts +11 -0
- package/dist/components/divider/divider.js +16 -0
- package/dist/components/divider/divider.js.map +1 -0
- package/dist/components/divider/index.d.ts +2 -0
- package/dist/components/drawer/drawer.d.ts +34 -0
- package/dist/components/drawer/drawer.js +144 -0
- package/dist/components/drawer/drawer.js.map +1 -0
- package/dist/components/drawer/index.d.ts +2 -0
- package/dist/components/field/field.d.ts +31 -0
- package/dist/components/field/field.js +52 -0
- package/dist/components/field/field.js.map +1 -0
- package/dist/components/field/index.d.ts +2 -0
- package/dist/components/grid/grid.d.ts +35 -0
- package/dist/components/grid/grid.js +64 -0
- package/dist/components/grid/grid.js.map +1 -0
- package/dist/components/grid/index.d.ts +2 -0
- package/dist/components/icon-button/icon-button.d.ts +23 -0
- package/dist/components/icon-button/icon-button.js +48 -0
- package/dist/components/icon-button/icon-button.js.map +1 -0
- package/dist/components/icon-button/index.d.ts +2 -0
- package/dist/components/input/index.d.ts +2 -0
- package/dist/components/input/input.d.ts +22 -0
- package/dist/components/input/input.js +86 -0
- package/dist/components/input/input.js.map +1 -0
- package/dist/components/link/index.d.ts +2 -0
- package/dist/components/link/link.d.ts +13 -0
- package/dist/components/link/link.js +20 -0
- package/dist/components/link/link.js.map +1 -0
- package/dist/components/list/index.d.ts +2 -0
- package/dist/components/list/list.d.ts +26 -0
- package/dist/components/list/list.js +45 -0
- package/dist/components/list/list.js.map +1 -0
- package/dist/components/menu/index.d.ts +2 -0
- package/dist/components/menu/menu.d.ts +47 -0
- package/dist/components/menu/menu.js +81 -0
- package/dist/components/menu/menu.js.map +1 -0
- package/dist/components/modal/index.d.ts +2 -0
- package/dist/components/modal/modal.d.ts +41 -0
- package/dist/components/modal/modal.js +92 -0
- package/dist/components/modal/modal.js.map +1 -0
- package/dist/components/pagination/index.d.ts +2 -0
- package/dist/components/pagination/pagination.d.ts +21 -0
- package/dist/components/pagination/pagination.js +99 -0
- package/dist/components/pagination/pagination.js.map +1 -0
- package/dist/components/popover/index.d.ts +2 -0
- package/dist/components/popover/popover.d.ts +29 -0
- package/dist/components/popover/popover.js +54 -0
- package/dist/components/popover/popover.js.map +1 -0
- package/dist/components/radio/index.d.ts +2 -0
- package/dist/components/radio/radio.d.ts +16 -0
- package/dist/components/radio/radio.js +37 -0
- package/dist/components/radio/radio.js.map +1 -0
- package/dist/components/segmented-control/index.d.ts +2 -0
- package/dist/components/segmented-control/segmented-control.d.ts +23 -0
- package/dist/components/segmented-control/segmented-control.js +53 -0
- package/dist/components/segmented-control/segmented-control.js.map +1 -0
- package/dist/components/select/field-trigger.d.ts +6 -0
- package/dist/components/select/field-trigger.js +90 -0
- package/dist/components/select/field-trigger.js.map +1 -0
- package/dist/components/select/index.d.ts +2 -0
- package/dist/components/select/select.d.ts +35 -0
- package/dist/components/select/select.js +98 -0
- package/dist/components/select/select.js.map +1 -0
- package/dist/components/skeleton/index.d.ts +2 -0
- package/dist/components/skeleton/skeleton.d.ts +17 -0
- package/dist/components/skeleton/skeleton.js +53 -0
- package/dist/components/skeleton/skeleton.js.map +1 -0
- package/dist/components/slider/index.d.ts +2 -0
- package/dist/components/slider/slider.d.ts +26 -0
- package/dist/components/slider/slider.js +102 -0
- package/dist/components/slider/slider.js.map +1 -0
- package/dist/components/spinner/index.d.ts +2 -0
- package/dist/components/spinner/spinner.d.ts +13 -0
- package/dist/components/spinner/spinner.js +47 -0
- package/dist/components/spinner/spinner.js.map +1 -0
- package/dist/components/stack/index.d.ts +2 -0
- package/dist/components/stack/stack.d.ts +17 -0
- package/dist/components/stack/stack.js +60 -0
- package/dist/components/stack/stack.js.map +1 -0
- package/dist/components/stepper/index.d.ts +2 -0
- package/dist/components/stepper/stepper.d.ts +20 -0
- package/dist/components/stepper/stepper.js +61 -0
- package/dist/components/stepper/stepper.js.map +1 -0
- package/dist/components/switch/index.d.ts +2 -0
- package/dist/components/switch/switch.d.ts +15 -0
- package/dist/components/switch/switch.js +51 -0
- package/dist/components/switch/switch.js.map +1 -0
- package/dist/components/table/index.d.ts +2 -0
- package/dist/components/table/table.d.ts +42 -0
- package/dist/components/table/table.js +83 -0
- package/dist/components/table/table.js.map +1 -0
- package/dist/components/tabs/index.d.ts +2 -0
- package/dist/components/tabs/tabs.d.ts +35 -0
- package/dist/components/tabs/tabs.js +82 -0
- package/dist/components/tabs/tabs.js.map +1 -0
- package/dist/components/tag/index.d.ts +2 -0
- package/dist/components/tag/tag.d.ts +18 -0
- package/dist/components/tag/tag.js +37 -0
- package/dist/components/tag/tag.js.map +1 -0
- package/dist/components/textarea/index.d.ts +2 -0
- package/dist/components/textarea/textarea.d.ts +16 -0
- package/dist/components/textarea/textarea.js +46 -0
- package/dist/components/textarea/textarea.js.map +1 -0
- package/dist/components/toast/index.d.ts +2 -0
- package/dist/components/toast/toast.d.ts +41 -0
- package/dist/components/toast/toast.js +167 -0
- package/dist/components/toast/toast.js.map +1 -0
- package/dist/components/tooltip/index.d.ts +2 -0
- package/dist/components/tooltip/tooltip.d.ts +28 -0
- package/dist/components/tooltip/tooltip.js +62 -0
- package/dist/components/tooltip/tooltip.js.map +1 -0
- package/dist/components/upload/index.d.ts +2 -0
- package/dist/components/upload/upload.d.ts +65 -0
- package/dist/components/upload/upload.js +130 -0
- package/dist/components/upload/upload.js.map +1 -0
- package/dist/index.d.ts +87 -0
- package/dist/index.js +46 -0
- package/dist/tokens/generated.d.ts +371 -0
- package/dist/tokens/generated.js +373 -0
- package/dist/tokens/generated.js.map +1 -0
- package/dist/utils/cn.d.ts +6 -0
- package/dist/utils/cn.js +11 -0
- package/dist/utils/cn.js.map +1 -0
- package/package.json +61 -3
- package/theme.css +191 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field.js","names":[],"sources":["../../../src/components/field/field.tsx"],"sourcesContent":["/// <reference types=\"uniwind/types\" />\n\nimport { cloneElement, type ReactElement, type ReactNode } from 'react'\nimport { Text, View } from 'react-native'\nimport { cn } from '../../utils/cn'\nimport { StatusIcon } from '../_shared/status'\nimport { useToken } from '../_shared/use-token'\n\nexport type FieldProps = {\n /** Texto do rótulo. */\n label: string\n /** Exibe um asterisco vermelho após o rótulo. */\n required?: boolean\n /** Propaga vermelho para rótulo, borda do controle e texto de apoio. */\n error?: boolean\n disabled?: boolean\n /** Propaga somente leitura ao controle. */\n readOnly?: boolean\n /** Tamanho do rótulo e do controle (o `sm` usa rótulo de 12px). */\n size?: 'sm' | 'md' | 'lg'\n /** Instrução (estado normal) ou mensagem de erro (estado error). */\n supportingText?: ReactNode\n /** O controle: Input, Textarea ou Select. Recebe disabled/error/size e o nome acessível. */\n children: ReactElement<{\n disabled?: boolean\n readOnly?: boolean\n size?: 'sm' | 'md' | 'lg'\n error?: boolean\n accessibilityLabel?: string\n accessibilityHint?: string\n }>\n className?: string\n}\n\n/** Combina rótulo + controle + texto de apoio — o jeito certo de montar um campo de formulário. */\nexport function Field({\n label,\n required,\n error,\n disabled,\n readOnly,\n size,\n supportingText,\n children,\n className,\n}: FieldProps) {\n const errorColor = useToken('--color-status-error-text')\n\n return (\n <View className={cn('gap-1', className)}>\n <Text\n className={cn(\n 'font-medium text-field-text-label',\n size === 'sm' ? 'text-xs leading-4' : 'text-sm',\n error && 'text-status-error-text',\n )}\n >\n {label}\n {required ? (\n // Sem `htmlFor` no native: o nome acessível vai por accessibilityLabel no controle,\n // então o asterisco fica escondido do leitor de tela.\n <Text\n className=\"text-status-error-text\"\n accessibilityElementsHidden\n importantForAccessibility=\"no\"\n >\n {' *'}\n </Text>\n ) : null}\n </Text>\n {cloneElement(children, {\n disabled: disabled ?? children.props.disabled,\n readOnly: readOnly ?? children.props.readOnly,\n size: size ?? children.props.size,\n error: error ?? children.props.error,\n accessibilityLabel: children.props.accessibilityLabel ?? label,\n accessibilityHint:\n children.props.accessibilityHint ??\n (typeof supportingText === 'string' ? supportingText : undefined),\n })}\n {supportingText ? (\n <View\n className=\"flex-row items-center gap-1\"\n // Mensagem de erro é anunciada assim que aparece.\n accessibilityLiveRegion={error ? 'polite' : undefined}\n >\n {error ? (\n <StatusIcon status=\"error\" color={errorColor} style={{ width: 16, height: 16 }} />\n ) : null}\n {typeof supportingText === 'string' ? (\n <Text\n className={cn(\n 'shrink text-xs leading-4 text-field-text-label',\n error && 'text-status-error-text',\n )}\n >\n {supportingText}\n </Text>\n ) : (\n supportingText\n )}\n </View>\n ) : null}\n </View>\n )\n}\n"],"mappings":";;;;;;;;AAmCA,SAAgB,MAAM,EACpB,OACA,UACA,OACA,UACA,UACA,MACA,gBACA,UACA,aACa;CACb,MAAM,aAAa,SAAS,2BAA2B;CAEvD,OACE,qBAAC,MAAD;EAAM,WAAW,GAAG,SAAS,SAAS;EAAtC,UAAA;GACE,qBAAC,MAAD;IACE,WAAW,GACT,qCACA,SAAS,OAAO,sBAAsB,WACtC,SAAS,wBACX;IALF,UAAA,CAOG,OACA,WAGC,oBAAC,MAAD;KACE,WAAU;KACV,6BAAA;KACA,2BAA0B;KAEzB,UAAA;IACG,CAAA,IACJ,IACA;;GACL,aAAa,UAAU;IACtB,UAAU,YAAY,SAAS,MAAM;IACrC,UAAU,YAAY,SAAS,MAAM;IACrC,MAAM,QAAQ,SAAS,MAAM;IAC7B,OAAO,SAAS,SAAS,MAAM;IAC/B,oBAAoB,SAAS,MAAM,sBAAsB;IACzD,mBACE,SAAS,MAAM,sBACd,OAAO,mBAAmB,WAAW,iBAAiB,KAAA;GAC3D,CAAC;GACA,iBACC,qBAAC,MAAD;IACE,WAAU;IAEV,yBAAyB,QAAQ,WAAW,KAAA;IAH9C,UAAA,CAKG,QACC,oBAAC,YAAD;KAAY,QAAO;KAAQ,OAAO;KAAY,OAAO;MAAE,OAAO;MAAI,QAAQ;KAAG;IAAI,CAAA,IAC/E,MACH,OAAO,mBAAmB,WACzB,oBAAC,MAAD;KACE,WAAW,GACT,kDACA,SAAS,wBACX;KAEC,UAAA;IACG,CAAA,IAEN,cAEE;GACJ,CAAA,IAAA;EACA;;AAEV"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ViewProps } from "react-native";
|
|
2
|
+
//#region src/components/grid/grid.d.ts
|
|
3
|
+
declare const gapPx: {
|
|
4
|
+
readonly 0: 0;
|
|
5
|
+
readonly 1: 4;
|
|
6
|
+
readonly 2: 8;
|
|
7
|
+
readonly 3: 12;
|
|
8
|
+
readonly 4: 16;
|
|
9
|
+
readonly 6: 24;
|
|
10
|
+
readonly 8: 32;
|
|
11
|
+
};
|
|
12
|
+
type Columns = 'responsive' | 1 | 2 | 3 | 4 | 6 | 12;
|
|
13
|
+
type Gap = keyof typeof gapPx;
|
|
14
|
+
export type GridProps = ViewProps & {
|
|
15
|
+
className?: string;
|
|
16
|
+
/** `responsive` segue o grid do DS: 4 colunas, 8 a partir de 768px e 12 a partir de 1440px. */
|
|
17
|
+
columns?: Columns;
|
|
18
|
+
/** Espaçamento entre células, na escala do DS (px = valor x 4). */
|
|
19
|
+
gap?: Gap;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Grid de colunas iguais. Não há CSS grid no RN: a largura de cada `GridItem` é calculada a
|
|
23
|
+
* partir da largura medida do Grid (`onLayout`) e as células quebram linha com `flex-wrap`.
|
|
24
|
+
* Antes da primeira medição, usa porcentagem (sem descontar o gap).
|
|
25
|
+
*/
|
|
26
|
+
export declare function Grid({ className, columns, gap, onLayout, children, ...props }: GridProps): import("react").JSX.Element;
|
|
27
|
+
export type GridItemProps = ViewProps & {
|
|
28
|
+
className?: string;
|
|
29
|
+
/** Quantas colunas a célula ocupa (`full` ocupa a linha toda). Padrão: 1. */
|
|
30
|
+
span?: 1 | 2 | 3 | 4 | 6 | 8 | 12 | 'full';
|
|
31
|
+
};
|
|
32
|
+
/** Célula do Grid que ocupa `span` colunas (limitado ao total de colunas atual). */
|
|
33
|
+
export declare function GridItem({ className, span, style, ...props }: GridItemProps): import("react").JSX.Element;
|
|
34
|
+
//#endregion
|
|
35
|
+
//# sourceMappingURL=grid.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { cn } from "../../utils/cn.js";
|
|
2
|
+
import { createContext, useContext, useState } from "react";
|
|
3
|
+
import { View, useWindowDimensions } from "react-native";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/grid/grid.tsx
|
|
6
|
+
const TABLET_MIN_WIDTH = 768;
|
|
7
|
+
const DESKTOP_MIN_WIDTH = 1440;
|
|
8
|
+
const gapPx = {
|
|
9
|
+
0: 0,
|
|
10
|
+
1: 4,
|
|
11
|
+
2: 8,
|
|
12
|
+
3: 12,
|
|
13
|
+
4: 16,
|
|
14
|
+
6: 24,
|
|
15
|
+
8: 32
|
|
16
|
+
};
|
|
17
|
+
const GridContext = createContext({
|
|
18
|
+
columns: 1,
|
|
19
|
+
gap: 0,
|
|
20
|
+
width: 0
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* Grid de colunas iguais. Não há CSS grid no RN: a largura de cada `GridItem` é calculada a
|
|
24
|
+
* partir da largura medida do Grid (`onLayout`) e as células quebram linha com `flex-wrap`.
|
|
25
|
+
* Antes da primeira medição, usa porcentagem (sem descontar o gap).
|
|
26
|
+
*/
|
|
27
|
+
function Grid({ className, columns = "responsive", gap = 4, onLayout, children, ...props }) {
|
|
28
|
+
const { width: windowWidth } = useWindowDimensions();
|
|
29
|
+
const [width, setWidth] = useState(0);
|
|
30
|
+
const count = columns === "responsive" ? windowWidth >= DESKTOP_MIN_WIDTH ? 12 : windowWidth >= TABLET_MIN_WIDTH ? 8 : 4 : columns;
|
|
31
|
+
const handleLayout = (event) => {
|
|
32
|
+
setWidth(event.nativeEvent.layout.width);
|
|
33
|
+
onLayout?.(event);
|
|
34
|
+
};
|
|
35
|
+
return /* @__PURE__ */ jsx(GridContext.Provider, {
|
|
36
|
+
value: {
|
|
37
|
+
columns: count,
|
|
38
|
+
gap: gapPx[gap],
|
|
39
|
+
width
|
|
40
|
+
},
|
|
41
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
42
|
+
className: cn("flex-row flex-wrap", className),
|
|
43
|
+
style: { gap: gapPx[gap] },
|
|
44
|
+
onLayout: handleLayout,
|
|
45
|
+
...props,
|
|
46
|
+
children
|
|
47
|
+
})
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/** Célula do Grid que ocupa `span` colunas (limitado ao total de colunas atual). */
|
|
51
|
+
function GridItem({ className, span = 1, style, ...props }) {
|
|
52
|
+
const { columns, gap, width } = useContext(GridContext);
|
|
53
|
+
const n = span === "full" ? columns : Math.min(span, columns);
|
|
54
|
+
const itemWidth = width > 0 ? (width - gap * (columns - 1)) * (n / columns) + gap * (n - 1) : `${n / columns * 100}%`;
|
|
55
|
+
return /* @__PURE__ */ jsx(View, {
|
|
56
|
+
className: cn(className),
|
|
57
|
+
style: [{ width: itemWidth }, style],
|
|
58
|
+
...props
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
export { Grid, GridItem };
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=grid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grid.js","names":[],"sources":["../../../src/components/grid/grid.tsx"],"sourcesContent":["/// <reference types=\"uniwind/types\" />\n\nimport { createContext, useContext, useState } from 'react'\nimport { type LayoutChangeEvent, useWindowDimensions, View, type ViewProps } from 'react-native'\nimport { cn } from '../../utils/cn'\n\nconst TABLET_MIN_WIDTH = 768\nconst DESKTOP_MIN_WIDTH = 1440\n\n// escala de gap do DS (base 4): chave -> px\nconst gapPx = { 0: 0, 1: 4, 2: 8, 3: 12, 4: 16, 6: 24, 8: 32 } as const\n\ntype Columns = 'responsive' | 1 | 2 | 3 | 4 | 6 | 12\ntype Gap = keyof typeof gapPx\n\ntype GridContextValue = { columns: number; gap: number; width: number }\nconst GridContext = createContext<GridContextValue>({ columns: 1, gap: 0, width: 0 })\n\nexport type GridProps = ViewProps & {\n className?: string\n /** `responsive` segue o grid do DS: 4 colunas, 8 a partir de 768px e 12 a partir de 1440px. */\n columns?: Columns\n /** Espaçamento entre células, na escala do DS (px = valor x 4). */\n gap?: Gap\n}\n\n/**\n * Grid de colunas iguais. Não há CSS grid no RN: a largura de cada `GridItem` é calculada a\n * partir da largura medida do Grid (`onLayout`) e as células quebram linha com `flex-wrap`.\n * Antes da primeira medição, usa porcentagem (sem descontar o gap).\n */\nexport function Grid({\n className,\n columns = 'responsive',\n gap = 4,\n onLayout,\n children,\n ...props\n}: GridProps) {\n const { width: windowWidth } = useWindowDimensions()\n const [width, setWidth] = useState(0)\n\n const count =\n columns === 'responsive'\n ? windowWidth >= DESKTOP_MIN_WIDTH\n ? 12\n : windowWidth >= TABLET_MIN_WIDTH\n ? 8\n : 4\n : columns\n\n const handleLayout = (event: LayoutChangeEvent) => {\n setWidth(event.nativeEvent.layout.width)\n onLayout?.(event)\n }\n\n return (\n <GridContext.Provider value={{ columns: count, gap: gapPx[gap], width }}>\n <View\n className={cn('flex-row flex-wrap', className)}\n style={{ gap: gapPx[gap] }}\n onLayout={handleLayout}\n {...props}\n >\n {children}\n </View>\n </GridContext.Provider>\n )\n}\n\nexport type GridItemProps = ViewProps & {\n className?: string\n /** Quantas colunas a célula ocupa (`full` ocupa a linha toda). Padrão: 1. */\n span?: 1 | 2 | 3 | 4 | 6 | 8 | 12 | 'full'\n}\n\n/** Célula do Grid que ocupa `span` colunas (limitado ao total de colunas atual). */\nexport function GridItem({ className, span = 1, style, ...props }: GridItemProps) {\n const { columns, gap, width } = useContext(GridContext)\n const n = span === 'full' ? columns : Math.min(span, columns)\n\n const itemWidth =\n width > 0\n ? (width - gap * (columns - 1)) * (n / columns) + gap * (n - 1)\n : `${(n / columns) * 100}%`\n\n return (\n <View className={cn(className)} style={[{ width: itemWidth as number }, style]} {...props} />\n )\n}\n"],"mappings":";;;;;AAMA,MAAM,mBAAmB;AACzB,MAAM,oBAAoB;AAG1B,MAAM,QAAQ;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;CAAG,GAAG;CAAI,GAAG;CAAI,GAAG;CAAI,GAAG;AAAG;AAM7D,MAAM,cAAc,cAAgC;CAAE,SAAS;CAAG,KAAK;CAAG,OAAO;AAAE,CAAC;;;;;;AAepF,SAAgB,KAAK,EACnB,WACA,UAAU,cACV,MAAM,GACN,UACA,UACA,GAAG,SACS;CACZ,MAAM,EAAE,OAAO,gBAAgB,oBAAoB;CACnD,MAAM,CAAC,OAAO,YAAY,SAAS,CAAC;CAEpC,MAAM,QACJ,YAAY,eACR,eAAe,oBACb,KACA,eAAe,mBACb,IACA,IACJ;CAEN,MAAM,gBAAgB,UAA6B;EACjD,SAAS,MAAM,YAAY,OAAO,KAAK;EACvC,WAAW,KAAK;CAClB;CAEA,OACE,oBAAC,YAAY,UAAb;EAAsB,OAAO;GAAE,SAAS;GAAO,KAAK,MAAM;GAAM;EAAM;EACpE,UAAA,oBAAC,MAAD;GACE,WAAW,GAAG,sBAAsB,SAAS;GAC7C,OAAO,EAAE,KAAK,MAAM,KAAK;GACzB,UAAU;GACV,GAAI;GAEH;EACG,CAAA;CACc,CAAA;AAE1B;;AASA,SAAgB,SAAS,EAAE,WAAW,OAAO,GAAG,OAAO,GAAG,SAAwB;CAChF,MAAM,EAAE,SAAS,KAAK,UAAU,WAAW,WAAW;CACtD,MAAM,IAAI,SAAS,SAAS,UAAU,KAAK,IAAI,MAAM,OAAO;CAE5D,MAAM,YACJ,QAAQ,KACH,QAAQ,OAAO,UAAU,OAAO,IAAI,WAAW,OAAO,IAAI,KAC3D,GAAI,IAAI,UAAW,IAAI;CAE7B,OACE,oBAAC,MAAD;EAAM,WAAW,GAAG,SAAS;EAAG,OAAO,CAAC,EAAE,OAAO,UAAoB,GAAG,KAAK;EAAG,GAAI;CAAQ,CAAA;AAEhG"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { PressableProps } from "react-native";
|
|
3
|
+
import { VariantProps } from "class-variance-authority";
|
|
4
|
+
//#region src/components/icon-button/icon-button.d.ts
|
|
5
|
+
declare const iconButtonVariants: (props?: ({
|
|
6
|
+
variant?: "destructive" | "ghost" | "primary" | "secondary" | "tertiary" | null | undefined;
|
|
7
|
+
size?: "lg" | "md" | "sm" | null | undefined;
|
|
8
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
9
|
+
export type IconButtonProps = Omit<PressableProps, 'children' | 'style' | 'accessibilityLabel'> & VariantProps<typeof iconButtonVariants> & {
|
|
10
|
+
className?: string;
|
|
11
|
+
/** Obrigatório: sem texto visível, é o nome acessível do botão. */
|
|
12
|
+
accessibilityLabel: string;
|
|
13
|
+
/**
|
|
14
|
+
* O ícone. No native a cor não é herdada: passe `color` ao ícone (ex.: lida com `useCSSVariable`, do uniwind).
|
|
15
|
+
* O tamanho do ícone também fica por conta de quem passa (24/20/16 por `size`).
|
|
16
|
+
*/
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
/** Estado de carregamento: troca o ícone por um spinner e desabilita o botão. */
|
|
19
|
+
loading?: boolean;
|
|
20
|
+
};
|
|
21
|
+
export declare function IconButton({ className, variant, size, loading, disabled, children, accessibilityState, ...props }: IconButtonProps): import("react").JSX.Element;
|
|
22
|
+
//#endregion
|
|
23
|
+
//# sourceMappingURL=icon-button.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { cn } from "../../utils/cn.js";
|
|
2
|
+
import { Spinner } from "../spinner/spinner.js";
|
|
3
|
+
import { Pressable } from "react-native";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { cva } from "class-variance-authority";
|
|
6
|
+
//#region src/components/icon-button/icon-button.tsx
|
|
7
|
+
const iconButtonVariants = cva("shrink-0 items-center justify-center rounded-full", {
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
primary: "bg-button-primary-bg active:bg-button-primary-bg-active disabled:bg-button-disabled-bg",
|
|
11
|
+
secondary: "bg-button-secondary-bg active:bg-button-secondary-bg-hover disabled:bg-button-disabled-bg",
|
|
12
|
+
tertiary: "border border-button-tertiary-border bg-transparent active:bg-bg-secondary",
|
|
13
|
+
ghost: "bg-transparent active:bg-button-secondary-bg-hover",
|
|
14
|
+
destructive: "bg-button-destructive-bg active:bg-button-destructive-bg-active disabled:bg-button-disabled-bg"
|
|
15
|
+
},
|
|
16
|
+
size: {
|
|
17
|
+
lg: "size-14",
|
|
18
|
+
md: "size-11",
|
|
19
|
+
sm: "size-9"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
defaultVariants: {
|
|
23
|
+
variant: "primary",
|
|
24
|
+
size: "md"
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
function IconButton({ className, variant, size, loading = false, disabled, children, accessibilityState, ...props }) {
|
|
28
|
+
const isDisabled = Boolean(disabled || loading);
|
|
29
|
+
return /* @__PURE__ */ jsx(Pressable, {
|
|
30
|
+
accessibilityRole: "button",
|
|
31
|
+
accessibilityState: {
|
|
32
|
+
...accessibilityState,
|
|
33
|
+
disabled: isDisabled,
|
|
34
|
+
busy: loading
|
|
35
|
+
},
|
|
36
|
+
disabled: isDisabled,
|
|
37
|
+
className: cn(iconButtonVariants({
|
|
38
|
+
variant,
|
|
39
|
+
size
|
|
40
|
+
}), className),
|
|
41
|
+
...props,
|
|
42
|
+
children: loading ? /* @__PURE__ */ jsx(Spinner, { size: size ?? "md" }) : children
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { IconButton };
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=icon-button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icon-button.js","names":[],"sources":["../../../src/components/icon-button/icon-button.tsx"],"sourcesContent":["/// <reference types=\"uniwind/types\" />\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport type { ReactNode } from 'react'\nimport { Pressable, type PressableProps } from 'react-native'\nimport { cn } from '../../utils/cn'\nimport { Spinner } from '../spinner/spinner'\n\n// Mesmos estilos do Button (não exportados de lá). Quadrado 1:1 nas alturas 56/44/36.\nconst iconButtonVariants = cva('shrink-0 items-center justify-center rounded-full', {\n variants: {\n variant: {\n primary:\n 'bg-button-primary-bg active:bg-button-primary-bg-active disabled:bg-button-disabled-bg',\n secondary:\n 'bg-button-secondary-bg active:bg-button-secondary-bg-hover disabled:bg-button-disabled-bg',\n tertiary: 'border border-button-tertiary-border bg-transparent active:bg-bg-secondary',\n ghost: 'bg-transparent active:bg-button-secondary-bg-hover',\n destructive:\n 'bg-button-destructive-bg active:bg-button-destructive-bg-active disabled:bg-button-disabled-bg',\n },\n size: {\n lg: 'size-14',\n md: 'size-11',\n sm: 'size-9',\n },\n },\n defaultVariants: { variant: 'primary', size: 'md' },\n})\n\nexport type IconButtonProps = Omit<PressableProps, 'children' | 'style' | 'accessibilityLabel'> &\n VariantProps<typeof iconButtonVariants> & {\n className?: string\n /** Obrigatório: sem texto visível, é o nome acessível do botão. */\n accessibilityLabel: string\n /**\n * O ícone. No native a cor não é herdada: passe `color` ao ícone (ex.: lida com `useCSSVariable`, do uniwind).\n * O tamanho do ícone também fica por conta de quem passa (24/20/16 por `size`).\n */\n children: ReactNode\n /** Estado de carregamento: troca o ícone por um spinner e desabilita o botão. */\n loading?: boolean\n }\n\nexport function IconButton({\n className,\n variant,\n size,\n loading = false,\n disabled,\n children,\n accessibilityState,\n ...props\n}: IconButtonProps) {\n const isDisabled = Boolean(disabled || loading)\n\n return (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityState={{ ...accessibilityState, disabled: isDisabled, busy: loading }}\n disabled={isDisabled}\n className={cn(iconButtonVariants({ variant, size }), className)}\n {...props}\n >\n {loading ? <Spinner size={size ?? 'md'} /> : children}\n </Pressable>\n )\n}\n"],"mappings":";;;;;;AASA,MAAM,qBAAqB,IAAI,qDAAqD;CAClF,UAAU;EACR,SAAS;GACP,SACE;GACF,WACE;GACF,UAAU;GACV,OAAO;GACP,aACE;EACJ;EACA,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;EACN;CACF;CACA,iBAAiB;EAAE,SAAS;EAAW,MAAM;CAAK;AACpD,CAAC;AAgBD,SAAgB,WAAW,EACzB,WACA,SACA,MACA,UAAU,OACV,UACA,UACA,oBACA,GAAG,SACe;CAClB,MAAM,aAAa,QAAQ,YAAY,OAAO;CAE9C,OACE,oBAAC,WAAD;EACE,mBAAkB;EAClB,oBAAoB;GAAE,GAAG;GAAoB,UAAU;GAAY,MAAM;EAAQ;EACjF,UAAU;EACV,WAAW,GAAG,mBAAmB;GAAE;GAAS;EAAK,CAAC,GAAG,SAAS;EAC9D,GAAI;EAEH,UAAA,UAAU,oBAAC,SAAD,EAAS,MAAM,QAAQ,KAAO,CAAA,IAAI;CACpC,CAAA;AAEf"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { TextInputProps } from "react-native";
|
|
3
|
+
import { VariantProps } from "class-variance-authority";
|
|
4
|
+
//#region src/components/input/input.d.ts
|
|
5
|
+
/** Estilo do campo, compartilhado com o Textarea (não faz parte da API pública). */
|
|
6
|
+
export declare const inputVariants: (props?: ({
|
|
7
|
+
size?: "lg" | "md" | "sm" | null | undefined;
|
|
8
|
+
error?: boolean | null | undefined;
|
|
9
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
10
|
+
export type InputProps = Omit<TextInputProps, 'style' | 'editable'> & Omit<VariantProps<typeof inputVariants>, 'error'> & {
|
|
11
|
+
className?: string;
|
|
12
|
+
/** Borda e foco em vermelho. */
|
|
13
|
+
error?: boolean;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
/** Ícone antes do texto (o consumidor define a cor; o slot tem 24px). */
|
|
16
|
+
leadingIcon?: ReactNode;
|
|
17
|
+
/** Ícone depois do texto (o consumidor define a cor; o slot tem 24px). */
|
|
18
|
+
trailingIcon?: ReactNode;
|
|
19
|
+
};
|
|
20
|
+
export declare function Input({ className, size, error, disabled, readOnly, leadingIcon, trailingIcon, accessibilityState, ...props }: InputProps): import("react").JSX.Element;
|
|
21
|
+
//#endregion
|
|
22
|
+
//# sourceMappingURL=input.d.ts.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { cn } from "../../utils/cn.js";
|
|
2
|
+
import { useToken } from "../_shared/use-token.js";
|
|
3
|
+
import { TextInput, View } from "react-native";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { cva } from "class-variance-authority";
|
|
6
|
+
//#region src/components/input/input.tsx
|
|
7
|
+
/** Estilo do campo, compartilhado com o Textarea (não faz parte da API pública). */
|
|
8
|
+
const inputVariants = cva("w-full rounded-md border border-field-border bg-field-bg py-0 text-field-text focus:border-field-focus-ring", {
|
|
9
|
+
variants: {
|
|
10
|
+
size: {
|
|
11
|
+
lg: "h-14 px-4 text-base",
|
|
12
|
+
md: "h-12 px-3 text-base",
|
|
13
|
+
sm: "h-10 px-2 text-sm"
|
|
14
|
+
},
|
|
15
|
+
error: {
|
|
16
|
+
true: "border-field-border-error focus:border-field-border-error",
|
|
17
|
+
false: ""
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
size: "md",
|
|
22
|
+
error: false
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
const iconSlot = {
|
|
26
|
+
lg: {
|
|
27
|
+
icon: "w-5",
|
|
28
|
+
left: "left-4",
|
|
29
|
+
right: "right-4",
|
|
30
|
+
padL: "pl-11",
|
|
31
|
+
padR: "pr-11"
|
|
32
|
+
},
|
|
33
|
+
md: {
|
|
34
|
+
icon: "w-6",
|
|
35
|
+
left: "left-3",
|
|
36
|
+
right: "right-3",
|
|
37
|
+
padL: "pl-11",
|
|
38
|
+
padR: "pr-11"
|
|
39
|
+
},
|
|
40
|
+
sm: {
|
|
41
|
+
icon: "w-6",
|
|
42
|
+
left: "left-2",
|
|
43
|
+
right: "right-2",
|
|
44
|
+
padL: "pl-9",
|
|
45
|
+
padR: "pr-9"
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
function Input({ className, size, error = false, disabled = false, readOnly = false, leadingIcon, trailingIcon, accessibilityState, ...props }) {
|
|
49
|
+
const placeholderColor = useToken("--color-field-text-placeholder");
|
|
50
|
+
const slot = iconSlot[size ?? "md"];
|
|
51
|
+
const input = /* @__PURE__ */ jsx(TextInput, {
|
|
52
|
+
editable: !disabled && !readOnly,
|
|
53
|
+
readOnly,
|
|
54
|
+
placeholderTextColor: placeholderColor,
|
|
55
|
+
accessibilityState: {
|
|
56
|
+
...accessibilityState,
|
|
57
|
+
disabled
|
|
58
|
+
},
|
|
59
|
+
className: cn(inputVariants({
|
|
60
|
+
size,
|
|
61
|
+
error
|
|
62
|
+
}), disabled && "border-field-border-disabled bg-field-bg-disabled text-field-text-disabled focus:border-field-border-disabled", readOnly && !disabled && "border-transparent bg-field-bg-disabled focus:border-transparent", leadingIcon && slot.padL, trailingIcon && slot.padR, className),
|
|
63
|
+
...props
|
|
64
|
+
});
|
|
65
|
+
if (!leadingIcon && !trailingIcon) return input;
|
|
66
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
67
|
+
className: "justify-center",
|
|
68
|
+
children: [
|
|
69
|
+
leadingIcon ? /* @__PURE__ */ jsx(View, {
|
|
70
|
+
pointerEvents: "none",
|
|
71
|
+
className: cn("absolute inset-y-0 z-10 items-center justify-center", slot.icon, slot.left),
|
|
72
|
+
children: leadingIcon
|
|
73
|
+
}) : null,
|
|
74
|
+
input,
|
|
75
|
+
trailingIcon ? /* @__PURE__ */ jsx(View, {
|
|
76
|
+
pointerEvents: "none",
|
|
77
|
+
className: cn("absolute inset-y-0 z-10 items-center justify-center", slot.icon, slot.right),
|
|
78
|
+
children: trailingIcon
|
|
79
|
+
}) : null
|
|
80
|
+
]
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
export { Input, inputVariants };
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.js","names":[],"sources":["../../../src/components/input/input.tsx"],"sourcesContent":["/// <reference types=\"uniwind/types\" />\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport type { ReactNode } from 'react'\nimport { TextInput, type TextInputProps, View } from 'react-native'\nimport { cn } from '../../utils/cn'\nimport { useToken } from '../_shared/use-token'\n\n/** Estilo do campo, compartilhado com o Textarea (não faz parte da API pública). */\nexport const inputVariants = cva(\n 'w-full rounded-md border border-field-border bg-field-bg py-0 text-field-text focus:border-field-focus-ring',\n {\n variants: {\n size: {\n lg: 'h-14 px-4 text-base',\n md: 'h-12 px-3 text-base',\n sm: 'h-10 px-2 text-sm',\n },\n error: {\n true: 'border-field-border-error focus:border-field-border-error',\n false: '',\n },\n },\n defaultVariants: { size: 'md', error: false },\n },\n)\n\n// Posição do ícone e recuo do texto por tamanho (Figma: padding + ícone 24/20/24 + gap 8/8/4).\nconst iconSlot = {\n lg: { icon: 'w-5', left: 'left-4', right: 'right-4', padL: 'pl-11', padR: 'pr-11' },\n md: { icon: 'w-6', left: 'left-3', right: 'right-3', padL: 'pl-11', padR: 'pr-11' },\n sm: { icon: 'w-6', left: 'left-2', right: 'right-2', padL: 'pl-9', padR: 'pr-9' },\n}\n\nexport type InputProps = Omit<TextInputProps, 'style' | 'editable'> &\n Omit<VariantProps<typeof inputVariants>, 'error'> & {\n className?: string\n /** Borda e foco em vermelho. */\n error?: boolean\n disabled?: boolean\n /** Ícone antes do texto (o consumidor define a cor; o slot tem 24px). */\n leadingIcon?: ReactNode\n /** Ícone depois do texto (o consumidor define a cor; o slot tem 24px). */\n trailingIcon?: ReactNode\n }\n\nexport function Input({\n className,\n size,\n error = false,\n disabled = false,\n readOnly = false,\n leadingIcon,\n trailingIcon,\n accessibilityState,\n ...props\n}: InputProps) {\n const placeholderColor = useToken('--color-field-text-placeholder')\n const slot = iconSlot[size ?? 'md']\n\n const input = (\n <TextInput\n editable={!disabled && !readOnly}\n readOnly={readOnly}\n placeholderTextColor={placeholderColor}\n accessibilityState={{ ...accessibilityState, disabled }}\n className={cn(\n inputVariants({ size, error }),\n disabled &&\n 'border-field-border-disabled bg-field-bg-disabled text-field-text-disabled focus:border-field-border-disabled',\n readOnly && !disabled && 'border-transparent bg-field-bg-disabled focus:border-transparent',\n leadingIcon && slot.padL,\n trailingIcon && slot.padR,\n className,\n )}\n {...props}\n />\n )\n\n if (!leadingIcon && !trailingIcon) return input\n\n return (\n <View className=\"justify-center\">\n {leadingIcon ? (\n <View\n pointerEvents=\"none\"\n className={cn(\n 'absolute inset-y-0 z-10 items-center justify-center',\n slot.icon,\n slot.left,\n )}\n >\n {leadingIcon}\n </View>\n ) : null}\n {input}\n {trailingIcon ? (\n <View\n pointerEvents=\"none\"\n className={cn(\n 'absolute inset-y-0 z-10 items-center justify-center',\n slot.icon,\n slot.right,\n )}\n >\n {trailingIcon}\n </View>\n ) : null}\n </View>\n )\n}\n"],"mappings":";;;;;;;AASA,MAAa,gBAAgB,IAC3B,+GACA;CACE,UAAU;EACR,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;EACN;EACA,OAAO;GACL,MAAM;GACN,OAAO;EACT;CACF;CACA,iBAAiB;EAAE,MAAM;EAAM,OAAO;CAAM;AAC9C,CACF;AAGA,MAAM,WAAW;CACf,IAAI;EAAE,MAAM;EAAO,MAAM;EAAU,OAAO;EAAW,MAAM;EAAS,MAAM;CAAQ;CAClF,IAAI;EAAE,MAAM;EAAO,MAAM;EAAU,OAAO;EAAW,MAAM;EAAS,MAAM;CAAQ;CAClF,IAAI;EAAE,MAAM;EAAO,MAAM;EAAU,OAAO;EAAW,MAAM;EAAQ,MAAM;CAAO;AAClF;AAcA,SAAgB,MAAM,EACpB,WACA,MACA,QAAQ,OACR,WAAW,OACX,WAAW,OACX,aACA,cACA,oBACA,GAAG,SACU;CACb,MAAM,mBAAmB,SAAS,gCAAgC;CAClE,MAAM,OAAO,SAAS,QAAQ;CAE9B,MAAM,QACJ,oBAAC,WAAD;EACE,UAAU,CAAC,YAAY,CAAC;EACd;EACV,sBAAsB;EACtB,oBAAoB;GAAE,GAAG;GAAoB;EAAS;EACtD,WAAW,GACT,cAAc;GAAE;GAAM;EAAM,CAAC,GAC7B,YACE,iHACF,YAAY,CAAC,YAAY,oEACzB,eAAe,KAAK,MACpB,gBAAgB,KAAK,MACrB,SACF;EACA,GAAI;CACL,CAAA;CAGH,IAAI,CAAC,eAAe,CAAC,cAAc,OAAO;CAE1C,OACE,qBAAC,MAAD;EAAM,WAAU;EAAhB,UAAA;GACG,cACC,oBAAC,MAAD;IACE,eAAc;IACd,WAAW,GACT,uDACA,KAAK,MACL,KAAK,IACP;IAEC,UAAA;GACG,CAAA,IACJ;GACH;GACA,eACC,oBAAC,MAAD;IACE,eAAc;IACd,WAAW,GACT,uDACA,KAAK,MACL,KAAK,KACP;IAEC,UAAA;GACG,CAAA,IACJ;EACA;;AAEV"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { TextProps } from "react-native";
|
|
2
|
+
//#region src/components/link/link.d.ts
|
|
3
|
+
export type LinkProps = Omit<TextProps, 'style' | 'onPress'> & {
|
|
4
|
+
className?: string;
|
|
5
|
+
/** URL aberta com `Linking.openURL` ao tocar (depois de `onPress`). */
|
|
6
|
+
href?: string;
|
|
7
|
+
/** Para navegar com o seu roteador, use só `onPress` (sem `href`). */
|
|
8
|
+
onPress?: TextProps['onPress'];
|
|
9
|
+
};
|
|
10
|
+
/** Link de texto na cor da marca, sempre sublinhado (a cor sozinha não distingue o link do texto). */
|
|
11
|
+
export declare function Link({ className, href, onPress, ...props }: LinkProps): import("react").JSX.Element;
|
|
12
|
+
//#endregion
|
|
13
|
+
//# sourceMappingURL=link.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { cn } from "../../utils/cn.js";
|
|
2
|
+
import { Linking, Text } from "react-native";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/link/link.tsx
|
|
5
|
+
/** Link de texto na cor da marca, sempre sublinhado (a cor sozinha não distingue o link do texto). */
|
|
6
|
+
function Link({ className, href, onPress, ...props }) {
|
|
7
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
8
|
+
accessibilityRole: "link",
|
|
9
|
+
onPress: (event) => {
|
|
10
|
+
onPress?.(event);
|
|
11
|
+
if (href) Linking.openURL(href).catch(() => {});
|
|
12
|
+
},
|
|
13
|
+
className: cn("text-text-brand underline active:text-interactive-primary-hover", className),
|
|
14
|
+
...props
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { Link };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.js","names":[],"sources":["../../../src/components/link/link.tsx"],"sourcesContent":["/// <reference types=\"uniwind/types\" />\n\nimport { Linking, Text, type TextProps } from 'react-native'\nimport { cn } from '../../utils/cn'\n\nexport type LinkProps = Omit<TextProps, 'style' | 'onPress'> & {\n className?: string\n /** URL aberta com `Linking.openURL` ao tocar (depois de `onPress`). */\n href?: string\n /** Para navegar com o seu roteador, use só `onPress` (sem `href`). */\n onPress?: TextProps['onPress']\n}\n\n/** Link de texto na cor da marca, sempre sublinhado (a cor sozinha não distingue o link do texto). */\nexport function Link({ className, href, onPress, ...props }: LinkProps) {\n return (\n <Text\n accessibilityRole=\"link\"\n onPress={(event) => {\n onPress?.(event)\n // URL inválida/sem app para abrir não deve virar rejeição não tratada\n if (href) Linking.openURL(href).catch(() => {})\n }}\n className={cn('text-text-brand underline active:text-interactive-primary-hover', className)}\n {...props}\n />\n )\n}\n"],"mappings":";;;;;AAcA,SAAgB,KAAK,EAAE,WAAW,MAAM,SAAS,GAAG,SAAoB;CACtE,OACE,oBAAC,MAAD;EACE,mBAAkB;EAClB,UAAU,UAAU;GAClB,UAAU,KAAK;GAEf,IAAI,MAAM,QAAQ,QAAQ,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC;EAChD;EACA,WAAW,GAAG,mEAAmE,SAAS;EAC1F,GAAI;CACL,CAAA;AAEL"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { ViewProps } from "react-native";
|
|
3
|
+
//#region src/components/list/list.d.ts
|
|
4
|
+
export type ListProps = ViewProps & {
|
|
5
|
+
className?: string;
|
|
6
|
+
/** Linha entre os itens. */
|
|
7
|
+
divided?: boolean;
|
|
8
|
+
};
|
|
9
|
+
/** Lista vertical de itens com o mesmo formato (contatos, arquivos, configurações). */
|
|
10
|
+
export declare function List({ className, divided, children, ...props }: ListProps): import("react").JSX.Element;
|
|
11
|
+
export type ListItemProps = Omit<ViewProps, 'children'> & {
|
|
12
|
+
className?: string;
|
|
13
|
+
/** Título do item. */
|
|
14
|
+
title: string;
|
|
15
|
+
/** Texto de apoio abaixo do título. */
|
|
16
|
+
description?: string;
|
|
17
|
+
/** Elemento antes do texto (Avatar, ícone). */
|
|
18
|
+
leading?: ReactNode;
|
|
19
|
+
/** Elemento no fim da linha (Badge, Menu, botão). */
|
|
20
|
+
trailing?: ReactNode;
|
|
21
|
+
/** Conteúdo extra abaixo da descrição. */
|
|
22
|
+
children?: ReactNode;
|
|
23
|
+
};
|
|
24
|
+
export declare function ListItem({ className, title, description, leading, trailing, children, ...props }: ListItemProps): import("react").JSX.Element;
|
|
25
|
+
//#endregion
|
|
26
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { cn } from "../../utils/cn.js";
|
|
2
|
+
import { Divider } from "../divider/divider.js";
|
|
3
|
+
import { Children, Fragment } from "react";
|
|
4
|
+
import { Text, View } from "react-native";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/components/list/list.tsx
|
|
7
|
+
/** Lista vertical de itens com o mesmo formato (contatos, arquivos, configurações). */
|
|
8
|
+
function List({ className, divided = false, children, ...props }) {
|
|
9
|
+
const items = Children.toArray(children);
|
|
10
|
+
return /* @__PURE__ */ jsx(View, {
|
|
11
|
+
accessibilityRole: "list",
|
|
12
|
+
className: cn(className),
|
|
13
|
+
...props,
|
|
14
|
+
children: divided ? items.map((child, i) => /* @__PURE__ */ jsxs(Fragment, { children: [i > 0 && /* @__PURE__ */ jsx(Divider, {}), child] }, i)) : children
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function ListItem({ className, title, description, leading, trailing, children, ...props }) {
|
|
18
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
19
|
+
role: "listitem",
|
|
20
|
+
className: cn("flex-row items-center gap-3 py-3", className),
|
|
21
|
+
...props,
|
|
22
|
+
children: [
|
|
23
|
+
leading,
|
|
24
|
+
/* @__PURE__ */ jsxs(View, {
|
|
25
|
+
className: "min-w-0 flex-1",
|
|
26
|
+
children: [
|
|
27
|
+
/* @__PURE__ */ jsx(Text, {
|
|
28
|
+
className: "text-sm font-medium leading-5 text-text-primary",
|
|
29
|
+
children: title
|
|
30
|
+
}),
|
|
31
|
+
description ? /* @__PURE__ */ jsx(Text, {
|
|
32
|
+
className: "text-sm leading-5 text-text-secondary",
|
|
33
|
+
children: description
|
|
34
|
+
}) : null,
|
|
35
|
+
children
|
|
36
|
+
]
|
|
37
|
+
}),
|
|
38
|
+
trailing
|
|
39
|
+
]
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { List, ListItem };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","names":[],"sources":["../../../src/components/list/list.tsx"],"sourcesContent":["/// <reference types=\"uniwind/types\" />\n\nimport { Children, Fragment, type ReactNode } from 'react'\nimport { Text, View, type ViewProps } from 'react-native'\nimport { cn } from '../../utils/cn'\nimport { Divider } from '../divider/divider'\n\nexport type ListProps = ViewProps & {\n className?: string\n /** Linha entre os itens. */\n divided?: boolean\n}\n\n/** Lista vertical de itens com o mesmo formato (contatos, arquivos, configurações). */\nexport function List({ className, divided = false, children, ...props }: ListProps) {\n // sem `divide-y` no native: intercala um Divider entre os filhos\n const items = Children.toArray(children)\n\n return (\n <View accessibilityRole=\"list\" className={cn(className)} {...props}>\n {divided\n ? items.map((child, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: lista estática de filhos já com key própria\n <Fragment key={i}>\n {i > 0 && <Divider />}\n {child}\n </Fragment>\n ))\n : children}\n </View>\n )\n}\n\nexport type ListItemProps = Omit<ViewProps, 'children'> & {\n className?: string\n /** Título do item. */\n title: string\n /** Texto de apoio abaixo do título. */\n description?: string\n /** Elemento antes do texto (Avatar, ícone). */\n leading?: ReactNode\n /** Elemento no fim da linha (Badge, Menu, botão). */\n trailing?: ReactNode\n /** Conteúdo extra abaixo da descrição. */\n children?: ReactNode\n}\n\nexport function ListItem({\n className,\n title,\n description,\n leading,\n trailing,\n children,\n ...props\n}: ListItemProps) {\n return (\n <View role=\"listitem\" className={cn('flex-row items-center gap-3 py-3', className)} {...props}>\n {leading}\n <View className=\"min-w-0 flex-1\">\n <Text className=\"text-sm font-medium leading-5 text-text-primary\">{title}</Text>\n {description ? (\n <Text className=\"text-sm leading-5 text-text-secondary\">{description}</Text>\n ) : null}\n {children}\n </View>\n {trailing}\n </View>\n )\n}\n"],"mappings":";;;;;;;AAcA,SAAgB,KAAK,EAAE,WAAW,UAAU,OAAO,UAAU,GAAG,SAAoB;CAElF,MAAM,QAAQ,SAAS,QAAQ,QAAQ;CAEvC,OACE,oBAAC,MAAD;EAAM,mBAAkB;EAAO,WAAW,GAAG,SAAS;EAAG,GAAI;EAC1D,UAAA,UACG,MAAM,KAAK,OAAO,MAEhB,qBAAC,UAAD,EAAA,UAAA,CACG,IAAI,KAAK,oBAAC,SAAD,CAAU,CAAA,GACnB,KACO,EAAA,GAHK,CAGL,CACX,IACD;CACA,CAAA;AAEV;AAgBA,SAAgB,SAAS,EACvB,WACA,OACA,aACA,SACA,UACA,UACA,GAAG,SACa;CAChB,OACE,qBAAC,MAAD;EAAM,MAAK;EAAW,WAAW,GAAG,oCAAoC,SAAS;EAAG,GAAI;EAAxF,UAAA;GACG;GACD,qBAAC,MAAD;IAAM,WAAU;IAAhB,UAAA;KACE,oBAAC,MAAD;MAAM,WAAU;MAAmD,UAAA;KAAY,CAAA;KAC9E,cACC,oBAAC,MAAD;MAAM,WAAU;MAAyC,UAAA;KAAkB,CAAA,IACzE;KACH;IACG;;GACL;EACG;;AAEV"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { PressableProps } from "react-native";
|
|
3
|
+
//#region src/components/menu/menu.d.ts
|
|
4
|
+
export type MenuProps = {
|
|
5
|
+
open?: boolean;
|
|
6
|
+
defaultOpen?: boolean;
|
|
7
|
+
onOpenChange?: (open: boolean) => void;
|
|
8
|
+
/** Lado do gatilho em que o menu abre; inverte se não couber. Padrão: `bottom`. */
|
|
9
|
+
side?: 'top' | 'bottom';
|
|
10
|
+
/** Elemento que abre o menu (ex.: um `<Button>`); recebe `onPress`. */
|
|
11
|
+
trigger: ReactNode;
|
|
12
|
+
/** Os `MenuItem`, `MenuLabel` e `MenuSeparator` do menu. */
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
className?: string;
|
|
15
|
+
testID?: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Menu de ações aberto por um botão, ancorado nele. Tocar num item o executa e fecha o menu;
|
|
19
|
+
* tocar fora ou o botão voltar do Android também fecha. Diferenças do web: sem navegação por
|
|
20
|
+
* teclado, sem `align` (alinha à esquerda do gatilho) e sem lados `left`/`right`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function Menu({ open, defaultOpen, onOpenChange, side, trigger, children, className, testID }: MenuProps): import("react").JSX.Element;
|
|
23
|
+
export type MenuItemProps = Omit<PressableProps, 'children' | 'style'> & {
|
|
24
|
+
/** Chamado ao escolher o item (antes de o menu fechar). Equivale ao `onSelect` do web. */
|
|
25
|
+
onSelect?: () => void;
|
|
26
|
+
/** Ícone à esquerda do rótulo (16px). */
|
|
27
|
+
icon?: ReactNode;
|
|
28
|
+
/** Ação que desfaz dados (excluir, remover): texto em vermelho. */
|
|
29
|
+
destructive?: boolean;
|
|
30
|
+
children: string;
|
|
31
|
+
className?: string;
|
|
32
|
+
};
|
|
33
|
+
/** Uma ação do menu. Usa `onSelect` (como o web); `onPress` também é chamado. */
|
|
34
|
+
export declare function MenuItem({ className, icon, destructive, disabled, onSelect, onPress, children, accessibilityState, ...props }: MenuItemProps): import("react").JSX.Element;
|
|
35
|
+
export type MenuLabelProps = {
|
|
36
|
+
children: string;
|
|
37
|
+
className?: string;
|
|
38
|
+
};
|
|
39
|
+
/** Título de um grupo de itens. */
|
|
40
|
+
export declare function MenuLabel({ className, children }: MenuLabelProps): import("react").JSX.Element;
|
|
41
|
+
export type MenuSeparatorProps = {
|
|
42
|
+
className?: string;
|
|
43
|
+
};
|
|
44
|
+
/** Linha entre grupos de itens. */
|
|
45
|
+
export declare function MenuSeparator({ className }: MenuSeparatorProps): import("react").JSX.Element;
|
|
46
|
+
//#endregion
|
|
47
|
+
//# sourceMappingURL=menu.d.ts.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { cn } from "../../utils/cn.js";
|
|
2
|
+
import { AnchoredOverlay } from "../_shared/anchored-overlay.js";
|
|
3
|
+
import { useOpenState } from "../_shared/overlay-state.js";
|
|
4
|
+
import { AnchorTrigger, useControlledAnchor } from "../_shared/overlay-anchor.js";
|
|
5
|
+
import { createContext, useContext } from "react";
|
|
6
|
+
import { Pressable, Text, View } from "react-native";
|
|
7
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
//#region src/components/menu/menu.tsx
|
|
9
|
+
const CloseContext = createContext(null);
|
|
10
|
+
/**
|
|
11
|
+
* Menu de ações aberto por um botão, ancorado nele. Tocar num item o executa e fecha o menu;
|
|
12
|
+
* tocar fora ou o botão voltar do Android também fecha. Diferenças do web: sem navegação por
|
|
13
|
+
* teclado, sem `align` (alinha à esquerda do gatilho) e sem lados `left`/`right`.
|
|
14
|
+
*/
|
|
15
|
+
function Menu({ open, defaultOpen, onOpenChange, side = "bottom", trigger, children, className, testID }) {
|
|
16
|
+
const [isOpen, setOpen] = useOpenState({
|
|
17
|
+
open,
|
|
18
|
+
defaultOpen,
|
|
19
|
+
onOpenChange
|
|
20
|
+
});
|
|
21
|
+
const { ref, rect } = useControlledAnchor(isOpen);
|
|
22
|
+
const close = () => setOpen(false);
|
|
23
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(AnchorTrigger, {
|
|
24
|
+
anchorRef: ref,
|
|
25
|
+
event: "onPress",
|
|
26
|
+
onTrigger: () => setOpen(!isOpen),
|
|
27
|
+
children: trigger
|
|
28
|
+
}), /* @__PURE__ */ jsx(AnchoredOverlay, {
|
|
29
|
+
visible: isOpen,
|
|
30
|
+
rect,
|
|
31
|
+
onRequestClose: close,
|
|
32
|
+
placement: side,
|
|
33
|
+
testID,
|
|
34
|
+
className: cn("min-w-[180px] rounded-md border border-border-default bg-surface-elevated p-1 shadow-md", className),
|
|
35
|
+
children: /* @__PURE__ */ jsx(CloseContext.Provider, {
|
|
36
|
+
value: close,
|
|
37
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
38
|
+
accessibilityRole: "menu",
|
|
39
|
+
children
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
})] });
|
|
43
|
+
}
|
|
44
|
+
/** Uma ação do menu. Usa `onSelect` (como o web); `onPress` também é chamado. */
|
|
45
|
+
function MenuItem({ className, icon, destructive = false, disabled, onSelect, onPress, children, accessibilityState, ...props }) {
|
|
46
|
+
const close = useContext(CloseContext);
|
|
47
|
+
return /* @__PURE__ */ jsxs(Pressable, {
|
|
48
|
+
accessibilityRole: "menuitem",
|
|
49
|
+
accessibilityState: {
|
|
50
|
+
...accessibilityState,
|
|
51
|
+
disabled: Boolean(disabled)
|
|
52
|
+
},
|
|
53
|
+
disabled,
|
|
54
|
+
onPress: (event) => {
|
|
55
|
+
onPress?.(event);
|
|
56
|
+
onSelect?.();
|
|
57
|
+
close?.();
|
|
58
|
+
},
|
|
59
|
+
className: cn("flex-row items-center gap-2 rounded-sm px-3 py-2 active:bg-bg-tertiary", className),
|
|
60
|
+
...props,
|
|
61
|
+
children: [icon, /* @__PURE__ */ jsx(Text, {
|
|
62
|
+
className: cn("text-sm leading-5", disabled ? "text-text-disabled" : destructive ? "text-status-error-text" : "text-text-primary"),
|
|
63
|
+
children
|
|
64
|
+
})]
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/** Título de um grupo de itens. */
|
|
68
|
+
function MenuLabel({ className, children }) {
|
|
69
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
70
|
+
className: cn("px-3 py-1.5 text-xs font-medium leading-4 text-text-secondary", className),
|
|
71
|
+
children
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/** Linha entre grupos de itens. */
|
|
75
|
+
function MenuSeparator({ className }) {
|
|
76
|
+
return /* @__PURE__ */ jsx(View, { className: cn("-mx-1 my-1 h-px bg-border-default", className) });
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
export { Menu, MenuItem, MenuLabel, MenuSeparator };
|
|
80
|
+
|
|
81
|
+
//# sourceMappingURL=menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu.js","names":[],"sources":["../../../src/components/menu/menu.tsx"],"sourcesContent":["/// <reference types=\"uniwind/types\" />\n\nimport { createContext, type ReactNode, useContext } from 'react'\nimport { Pressable, type PressableProps, Text, View } from 'react-native'\nimport { cn } from '../../utils/cn'\nimport { AnchoredOverlay } from '../_shared/anchored-overlay'\nimport { AnchorTrigger, useControlledAnchor } from '../_shared/overlay-anchor'\nimport { useOpenState } from '../_shared/overlay-state'\n\nconst CloseContext = createContext<(() => void) | null>(null)\n\nexport type MenuProps = {\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n /** Lado do gatilho em que o menu abre; inverte se não couber. Padrão: `bottom`. */\n side?: 'top' | 'bottom'\n /** Elemento que abre o menu (ex.: um `<Button>`); recebe `onPress`. */\n trigger: ReactNode\n /** Os `MenuItem`, `MenuLabel` e `MenuSeparator` do menu. */\n children: ReactNode\n className?: string\n testID?: string\n}\n\n/**\n * Menu de ações aberto por um botão, ancorado nele. Tocar num item o executa e fecha o menu;\n * tocar fora ou o botão voltar do Android também fecha. Diferenças do web: sem navegação por\n * teclado, sem `align` (alinha à esquerda do gatilho) e sem lados `left`/`right`.\n */\nexport function Menu({\n open,\n defaultOpen,\n onOpenChange,\n side = 'bottom',\n trigger,\n children,\n className,\n testID,\n}: MenuProps) {\n const [isOpen, setOpen] = useOpenState({ open, defaultOpen, onOpenChange })\n const { ref, rect } = useControlledAnchor(isOpen)\n const close = () => setOpen(false)\n\n return (\n <>\n <AnchorTrigger anchorRef={ref} event=\"onPress\" onTrigger={() => setOpen(!isOpen)}>\n {trigger}\n </AnchorTrigger>\n <AnchoredOverlay\n visible={isOpen}\n rect={rect}\n onRequestClose={close}\n placement={side}\n testID={testID}\n className={cn(\n 'min-w-[180px] rounded-md border border-border-default bg-surface-elevated p-1 shadow-md',\n className,\n )}\n >\n <CloseContext.Provider value={close}>\n <View accessibilityRole=\"menu\">{children}</View>\n </CloseContext.Provider>\n </AnchoredOverlay>\n </>\n )\n}\n\nexport type MenuItemProps = Omit<PressableProps, 'children' | 'style'> & {\n /** Chamado ao escolher o item (antes de o menu fechar). Equivale ao `onSelect` do web. */\n onSelect?: () => void\n /** Ícone à esquerda do rótulo (16px). */\n icon?: ReactNode\n /** Ação que desfaz dados (excluir, remover): texto em vermelho. */\n destructive?: boolean\n children: string\n className?: string\n}\n\n/** Uma ação do menu. Usa `onSelect` (como o web); `onPress` também é chamado. */\nexport function MenuItem({\n className,\n icon,\n destructive = false,\n disabled,\n onSelect,\n onPress,\n children,\n accessibilityState,\n ...props\n}: MenuItemProps) {\n const close = useContext(CloseContext)\n\n return (\n <Pressable\n accessibilityRole=\"menuitem\"\n accessibilityState={{ ...accessibilityState, disabled: Boolean(disabled) }}\n disabled={disabled}\n onPress={(event) => {\n onPress?.(event)\n onSelect?.()\n close?.()\n }}\n className={cn(\n 'flex-row items-center gap-2 rounded-sm px-3 py-2 active:bg-bg-tertiary',\n className,\n )}\n {...props}\n >\n {icon}\n <Text\n className={cn(\n 'text-sm leading-5',\n disabled\n ? 'text-text-disabled'\n : destructive\n ? 'text-status-error-text'\n : 'text-text-primary',\n )}\n >\n {children}\n </Text>\n </Pressable>\n )\n}\n\nexport type MenuLabelProps = { children: string; className?: string }\n\n/** Título de um grupo de itens. */\nexport function MenuLabel({ className, children }: MenuLabelProps) {\n return (\n <Text\n className={cn('px-3 py-1.5 text-xs font-medium leading-4 text-text-secondary', className)}\n >\n {children}\n </Text>\n )\n}\n\nexport type MenuSeparatorProps = { className?: string }\n\n/** Linha entre grupos de itens. */\nexport function MenuSeparator({ className }: MenuSeparatorProps) {\n return <View className={cn('-mx-1 my-1 h-px bg-border-default', className)} />\n}\n"],"mappings":";;;;;;;;AASA,MAAM,eAAe,cAAmC,IAAI;;;;;;AAqB5D,SAAgB,KAAK,EACnB,MACA,aACA,cACA,OAAO,UACP,SACA,UACA,WACA,UACY;CACZ,MAAM,CAAC,QAAQ,WAAW,aAAa;EAAE;EAAM;EAAa;CAAa,CAAC;CAC1E,MAAM,EAAE,KAAK,SAAS,oBAAoB,MAAM;CAChD,MAAM,cAAc,QAAQ,KAAK;CAEjC,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,eAAD;EAAe,WAAW;EAAK,OAAM;EAAU,iBAAiB,QAAQ,CAAC,MAAM;EAC5E,UAAA;CACY,CAAA,GACf,oBAAC,iBAAD;EACE,SAAS;EACH;EACN,gBAAgB;EAChB,WAAW;EACH;EACR,WAAW,GACT,2FACA,SACF;EAEA,UAAA,oBAAC,aAAa,UAAd;GAAuB,OAAO;GAC5B,UAAA,oBAAC,MAAD;IAAM,mBAAkB;IAAQ;GAAe,CAAA;EAC1B,CAAA;CACR,CAAA,CACjB,EAAA,CAAA;AAEN;;AAcA,SAAgB,SAAS,EACvB,WACA,MACA,cAAc,OACd,UACA,UACA,SACA,UACA,oBACA,GAAG,SACa;CAChB,MAAM,QAAQ,WAAW,YAAY;CAErC,OACE,qBAAC,WAAD;EACE,mBAAkB;EAClB,oBAAoB;GAAE,GAAG;GAAoB,UAAU,QAAQ,QAAQ;EAAE;EAC/D;EACV,UAAU,UAAU;GAClB,UAAU,KAAK;GACf,WAAW;GACX,QAAQ;EACV;EACA,WAAW,GACT,0EACA,SACF;EACA,GAAI;EAbN,UAAA,CAeG,MACD,oBAAC,MAAD;GACE,WAAW,GACT,qBACA,WACI,uBACA,cACE,2BACA,mBACR;GAEC;EACG,CAAA,CACG;;AAEf;;AAKA,SAAgB,UAAU,EAAE,WAAW,YAA4B;CACjE,OACE,oBAAC,MAAD;EACE,WAAW,GAAG,iEAAiE,SAAS;EAEvF;CACG,CAAA;AAEV;;AAKA,SAAgB,cAAc,EAAE,aAAiC;CAC/D,OAAO,oBAAC,MAAD,EAAM,WAAW,GAAG,qCAAqC,SAAS,EAAI,CAAA;AAC/E"}
|