@innovui/react-native 0.2.0 → 0.3.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.
Files changed (31) hide show
  1. package/README.md +1 -0
  2. package/dist/components/_shared/media-icons.js +125 -0
  3. package/dist/components/_shared/media-icons.js.map +1 -0
  4. package/dist/components/_shared/media.js +114 -0
  5. package/dist/components/_shared/media.js.map +1 -0
  6. package/dist/components/audio-player/audio-player.d.ts +34 -0
  7. package/dist/components/audio-player/audio-player.js +89 -0
  8. package/dist/components/audio-player/audio-player.js.map +1 -0
  9. package/dist/components/audio-player/index.d.ts +2 -0
  10. package/dist/components/carousel/carousel.d.ts +34 -0
  11. package/dist/components/carousel/carousel.js +110 -0
  12. package/dist/components/carousel/carousel.js.map +1 -0
  13. package/dist/components/carousel/index.d.ts +2 -0
  14. package/dist/components/gallery/gallery.d.ts +21 -0
  15. package/dist/components/gallery/gallery.js +54 -0
  16. package/dist/components/gallery/gallery.js.map +1 -0
  17. package/dist/components/gallery/index.d.ts +2 -0
  18. package/dist/components/lightbox/lightbox.d.ts +30 -0
  19. package/dist/components/lightbox/lightbox.js +147 -0
  20. package/dist/components/lightbox/lightbox.js.map +1 -0
  21. package/dist/components/video-player/index.d.ts +2 -0
  22. package/dist/components/video-player/video-player.d.ts +37 -0
  23. package/dist/components/video-player/video-player.js +178 -0
  24. package/dist/components/video-player/video-player.js.map +1 -0
  25. package/dist/index.d.ts +10 -1
  26. package/dist/index.js +6 -1
  27. package/dist/tokens/generated.d.ts +8 -0
  28. package/dist/tokens/generated.js +10 -2
  29. package/dist/tokens/generated.js.map +1 -1
  30. package/package.json +1 -1
  31. package/theme.css +8 -0
@@ -0,0 +1,54 @@
1
+ import { cn } from "../../utils/cn.js";
2
+ import { useToken } from "../_shared/use-token.js";
3
+ import { ExpandIcon } from "../_shared/media-icons.js";
4
+ import { Lightbox } from "../lightbox/lightbox.js";
5
+ import { useState } from "react";
6
+ import { Image, Pressable, View, useWindowDimensions } from "react-native";
7
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
+ //#region src/components/gallery/gallery.tsx
9
+ const GAP = 8;
10
+ const TABLET = 768;
11
+ /** Grade de miniaturas que abre a foto ampliada no `Lightbox`. */
12
+ function Gallery({ className, items, columns, openLabel = (item, i) => `Ampliar foto ${i + 1}: ${item.alt}`, lightboxLabel, ...props }) {
13
+ const { width: screen } = useWindowDimensions();
14
+ const [width, setWidth] = useState(0);
15
+ const [opened, setOpened] = useState(null);
16
+ const overlayColor = useToken("--color-media-on-surface");
17
+ const cols = columns ?? (screen >= TABLET ? 3 : 2);
18
+ const size = (width - GAP * (cols - 1)) / cols;
19
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(View, {
20
+ className: cn("flex-row flex-wrap gap-2", className),
21
+ onLayout: (event) => setWidth(event.nativeEvent.layout.width),
22
+ ...props,
23
+ children: items.map((item, i) => /* @__PURE__ */ jsx(Pressable, {
24
+ accessibilityRole: "imagebutton",
25
+ accessibilityLabel: openLabel(item, i),
26
+ onPress: () => setOpened(i),
27
+ className: "overflow-hidden rounded-md bg-bg-skeleton",
28
+ style: {
29
+ width: size,
30
+ aspectRatio: 4 / 3
31
+ },
32
+ children: ({ pressed }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Image, {
33
+ source: { uri: item.thumbSrc ?? item.src },
34
+ className: "size-full",
35
+ resizeMode: "cover"
36
+ }), pressed && /* @__PURE__ */ jsx(View, {
37
+ pointerEvents: "none",
38
+ className: "absolute inset-0 items-center justify-center bg-media-surface/50",
39
+ children: /* @__PURE__ */ jsx(ExpandIcon, { color: overlayColor })
40
+ })] })
41
+ }, item.src))
42
+ }), /* @__PURE__ */ jsx(Lightbox, {
43
+ items,
44
+ label: lightboxLabel,
45
+ open: opened !== null,
46
+ onOpenChange: (open) => !open && setOpened(null),
47
+ index: opened ?? 0,
48
+ onIndexChange: setOpened
49
+ })] });
50
+ }
51
+ //#endregion
52
+ export { Gallery };
53
+
54
+ //# sourceMappingURL=gallery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gallery.js","names":[],"sources":["../../../src/components/gallery/gallery.tsx"],"sourcesContent":["/// <reference types=\"uniwind/types\" />\n\nimport { useState } from 'react'\nimport {\n Image,\n type LayoutChangeEvent,\n Pressable,\n useWindowDimensions,\n View,\n type ViewProps,\n} from 'react-native'\nimport { cn } from '../../utils/cn'\nimport { ExpandIcon } from '../_shared/media-icons'\nimport { useToken } from '../_shared/use-token'\nimport { Lightbox, type LightboxItem } from '../lightbox'\n\nconst GAP = 8\nconst TABLET = 768\n\nexport type GalleryItem = LightboxItem & {\n /** Imagem menor para a grade; sem ela, a grade usa `src`. */\n thumbSrc?: string\n}\n\nexport type GalleryProps = Omit<ViewProps, 'children' | 'style'> & {\n className?: string\n items: GalleryItem[]\n /** Colunas da grade. Padrão: 2 no celular e 3 a partir de 768px de tela. */\n columns?: number\n /** Nome acessível do botão de cada miniatura. Padrão: \"Ampliar foto N: descrição\". */\n openLabel?: (item: GalleryItem, index: number) => string\n /** Nome acessível do visualizador ampliado. */\n lightboxLabel?: string\n}\n\n/** Grade de miniaturas que abre a foto ampliada no `Lightbox`. */\nexport function Gallery({\n className,\n items,\n columns,\n openLabel = (item, i) => `Ampliar foto ${i + 1}: ${item.alt}`,\n lightboxLabel,\n ...props\n}: GalleryProps) {\n const { width: screen } = useWindowDimensions()\n const [width, setWidth] = useState(0)\n const [opened, setOpened] = useState<number | null>(null)\n const overlayColor = useToken('--color-media-on-surface')\n const cols = columns ?? (screen >= TABLET ? 3 : 2)\n const size = (width - GAP * (cols - 1)) / cols\n\n return (\n <>\n <View\n className={cn('flex-row flex-wrap gap-2', className)}\n onLayout={(event: LayoutChangeEvent) => setWidth(event.nativeEvent.layout.width)}\n {...props}\n >\n {items.map((item, i) => (\n <Pressable\n key={item.src}\n accessibilityRole=\"imagebutton\"\n accessibilityLabel={openLabel(item, i)}\n onPress={() => setOpened(i)}\n className=\"overflow-hidden rounded-md bg-bg-skeleton\"\n style={{ width: size, aspectRatio: 4 / 3 }}\n >\n {({ pressed }) => (\n <>\n <Image\n source={{ uri: item.thumbSrc ?? item.src }}\n className=\"size-full\"\n resizeMode=\"cover\"\n />\n {pressed && (\n <View\n pointerEvents=\"none\"\n className=\"absolute inset-0 items-center justify-center bg-media-surface/50\"\n >\n <ExpandIcon color={overlayColor} />\n </View>\n )}\n </>\n )}\n </Pressable>\n ))}\n </View>\n <Lightbox\n items={items}\n label={lightboxLabel}\n open={opened !== null}\n onOpenChange={(open) => !open && setOpened(null)}\n index={opened ?? 0}\n onIndexChange={setOpened}\n />\n </>\n )\n}\n"],"mappings":";;;;;;;;AAgBA,MAAM,MAAM;AACZ,MAAM,SAAS;;AAmBf,SAAgB,QAAQ,EACtB,WACA,OACA,SACA,aAAa,MAAM,MAAM,gBAAgB,IAAI,EAAE,IAAI,KAAK,OACxD,eACA,GAAG,SACY;CACf,MAAM,EAAE,OAAO,WAAW,oBAAoB;CAC9C,MAAM,CAAC,OAAO,YAAY,SAAS,CAAC;CACpC,MAAM,CAAC,QAAQ,aAAa,SAAwB,IAAI;CACxD,MAAM,eAAe,SAAS,0BAA0B;CACxD,MAAM,OAAO,YAAY,UAAU,SAAS,IAAI;CAChD,MAAM,QAAQ,QAAQ,OAAO,OAAO,MAAM;CAE1C,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,MAAD;EACE,WAAW,GAAG,4BAA4B,SAAS;EACnD,WAAW,UAA6B,SAAS,MAAM,YAAY,OAAO,KAAK;EAC/E,GAAI;EAEH,UAAA,MAAM,KAAK,MAAM,MAChB,oBAAC,WAAD;GAEE,mBAAkB;GAClB,oBAAoB,UAAU,MAAM,CAAC;GACrC,eAAe,UAAU,CAAC;GAC1B,WAAU;GACV,OAAO;IAAE,OAAO;IAAM,aAAa,IAAI;GAAE;GAEvC,WAAA,EAAE,cACF,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,OAAD;IACE,QAAQ,EAAE,KAAK,KAAK,YAAY,KAAK,IAAI;IACzC,WAAU;IACV,YAAW;GACZ,CAAA,GACA,WACC,oBAAC,MAAD;IACE,eAAc;IACd,WAAU;IAEV,UAAA,oBAAC,YAAD,EAAY,OAAO,aAAe,CAAA;GAC9B,CAAA,CAER,EAAA,CAAA;EAEK,GAxBJ,KAAK,GAwBD,CACZ;CACG,CAAA,GACN,oBAAC,UAAD;EACS;EACP,OAAO;EACP,MAAM,WAAW;EACjB,eAAe,SAAS,CAAC,QAAQ,UAAU,IAAI;EAC/C,OAAO,UAAU;EACjB,eAAe;CAChB,CAAA,CACD,EAAA,CAAA;AAEN"}
@@ -0,0 +1,2 @@
1
+ import { Gallery, GalleryItem, GalleryProps } from "./gallery.js";
2
+ export { Gallery, type GalleryItem, type GalleryProps };
@@ -0,0 +1,30 @@
1
+ //#region src/components/lightbox/lightbox.d.ts
2
+ export type LightboxItem = {
3
+ /** Endereço da imagem ampliada. */
4
+ src: string;
5
+ /** Descrição da imagem para leitores de tela. */
6
+ alt: string;
7
+ };
8
+ export type LightboxProps = {
9
+ items: LightboxItem[];
10
+ open?: boolean;
11
+ defaultOpen?: boolean;
12
+ onOpenChange?: (open: boolean) => void;
13
+ /** Índice da imagem exibida (modo controlado). */
14
+ index?: number;
15
+ defaultIndex?: number;
16
+ onIndexChange?: (index: number) => void;
17
+ /** Nome acessível do visualizador. */
18
+ label?: string;
19
+ closeLabel?: string;
20
+ previousLabel?: string;
21
+ nextLabel?: string;
22
+ testID?: string;
23
+ };
24
+ /**
25
+ * Imagem ampliada sobre um fundo escurecido, com contador (`1 / 6`), setas e fechar. Deslize para
26
+ * os lados para trocar de foto; as setas dão a volta (da última vai para a primeira).
27
+ */
28
+ export declare function Lightbox({ items, open, defaultOpen, onOpenChange, index, defaultIndex, onIndexChange, label, closeLabel, previousLabel, nextLabel, testID }: LightboxProps): import("react").JSX.Element;
29
+ //#endregion
30
+ //# sourceMappingURL=lightbox.d.ts.map
@@ -0,0 +1,147 @@
1
+ import { CloseIcon } from "../_shared/status.js";
2
+ import { useToken } from "../_shared/use-token.js";
3
+ import { IconButton } from "../icon-button/icon-button.js";
4
+ import { NextIcon, PreviousIcon } from "../_shared/media-icons.js";
5
+ import { useTransition } from "../_shared/use-transition.js";
6
+ import { Backdrop } from "../_shared/backdrop.js";
7
+ import { useOpenState } from "../_shared/overlay-state.js";
8
+ import { useEffect, useRef, useState } from "react";
9
+ import { Animated, FlatList, Image, Modal, StyleSheet, Text, View, useWindowDimensions } from "react-native";
10
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
+ //#region src/components/lightbox/lightbox.tsx
12
+ const roundButton = "rounded-full border-border-default bg-surface-elevated active:bg-bg-secondary";
13
+ /**
14
+ * Imagem ampliada sobre um fundo escurecido, com contador (`1 / 6`), setas e fechar. Deslize para
15
+ * os lados para trocar de foto; as setas dão a volta (da última vai para a primeira).
16
+ */
17
+ function Lightbox({ items, open, defaultOpen, onOpenChange, index, defaultIndex = 0, onIndexChange, label = "Visualizador de imagens", closeLabel = "Fechar", previousLabel = "Foto anterior", nextLabel = "Próxima foto", testID }) {
18
+ const [isOpen, setOpen] = useOpenState({
19
+ open,
20
+ defaultOpen,
21
+ onOpenChange
22
+ });
23
+ const { mounted, progress } = useTransition(isOpen);
24
+ const { width, height } = useWindowDimensions();
25
+ const iconColor = useToken("--color-text-primary");
26
+ const list = useRef(null);
27
+ const [inner, setInner] = useState(defaultIndex);
28
+ const count = items.length;
29
+ const current = Math.min(Math.max(index ?? inner, 0), Math.max(count - 1, 0));
30
+ const shown = useRef(current);
31
+ function show(next) {
32
+ shown.current = next;
33
+ if (index === void 0) setInner(next);
34
+ onIndexChange?.(next);
35
+ }
36
+ function go(next) {
37
+ const wrapped = (next + count) % count;
38
+ list.current?.scrollToIndex({
39
+ index: wrapped,
40
+ animated: true
41
+ });
42
+ show(wrapped);
43
+ }
44
+ useEffect(() => {
45
+ if (!mounted || shown.current === current) return;
46
+ shown.current = current;
47
+ list.current?.scrollToIndex({
48
+ index: current,
49
+ animated: false
50
+ });
51
+ }, [current, mounted]);
52
+ function onMomentumScrollEnd(event) {
53
+ const next = Math.round(event.nativeEvent.contentOffset.x / width);
54
+ if (next !== shown.current && next >= 0 && next < count) show(next);
55
+ }
56
+ return /* @__PURE__ */ jsx(Modal, {
57
+ transparent: true,
58
+ statusBarTranslucent: true,
59
+ animationType: "none",
60
+ visible: mounted,
61
+ onRequestClose: () => setOpen(false),
62
+ children: /* @__PURE__ */ jsxs(View, {
63
+ className: "flex-1",
64
+ accessibilityViewIsModal: true,
65
+ accessibilityLabel: label,
66
+ testID,
67
+ children: [/* @__PURE__ */ jsx(Animated.View, {
68
+ pointerEvents: "box-none",
69
+ style: [StyleSheet.absoluteFill, { opacity: progress }],
70
+ children: /* @__PURE__ */ jsx(Backdrop, { onPress: () => setOpen(false) })
71
+ }), /* @__PURE__ */ jsxs(Animated.View, {
72
+ pointerEvents: "box-none",
73
+ style: [StyleSheet.absoluteFill, {
74
+ opacity: progress,
75
+ justifyContent: "center"
76
+ }],
77
+ children: [
78
+ /* @__PURE__ */ jsx(FlatList, {
79
+ ref: list,
80
+ data: items,
81
+ horizontal: true,
82
+ pagingEnabled: true,
83
+ showsHorizontalScrollIndicator: false,
84
+ keyExtractor: (item) => item.src,
85
+ initialScrollIndex: current,
86
+ getItemLayout: (_, i) => ({
87
+ length: width,
88
+ offset: width * i,
89
+ index: i
90
+ }),
91
+ onMomentumScrollEnd,
92
+ renderItem: ({ item }) => /* @__PURE__ */ jsx(View, {
93
+ style: {
94
+ width,
95
+ height: height * .7,
96
+ paddingHorizontal: 16
97
+ },
98
+ children: /* @__PURE__ */ jsx(Image, {
99
+ source: { uri: item.src },
100
+ accessibilityLabel: item.alt,
101
+ resizeMode: "contain",
102
+ className: "size-full"
103
+ })
104
+ })
105
+ }),
106
+ count > 1 && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(View, {
107
+ pointerEvents: "box-none",
108
+ className: "absolute inset-x-3 flex-row justify-between",
109
+ style: { top: height / 2 - 22 },
110
+ children: [/* @__PURE__ */ jsx(IconButton, {
111
+ accessibilityLabel: previousLabel,
112
+ variant: "tertiary",
113
+ className: roundButton,
114
+ onPress: () => go(shown.current - 1),
115
+ children: /* @__PURE__ */ jsx(PreviousIcon, { color: iconColor })
116
+ }), /* @__PURE__ */ jsx(IconButton, {
117
+ accessibilityLabel: nextLabel,
118
+ variant: "tertiary",
119
+ className: roundButton,
120
+ onPress: () => go(shown.current + 1),
121
+ children: /* @__PURE__ */ jsx(NextIcon, { color: iconColor })
122
+ })]
123
+ }), /* @__PURE__ */ jsxs(Text, {
124
+ accessibilityLiveRegion: "polite",
125
+ className: "absolute bottom-12 self-center text-sm font-medium leading-5 text-media-on-surface",
126
+ children: [
127
+ current + 1,
128
+ " / ",
129
+ count
130
+ ]
131
+ })] }),
132
+ /* @__PURE__ */ jsx(IconButton, {
133
+ accessibilityLabel: closeLabel,
134
+ variant: "tertiary",
135
+ className: `absolute right-4 top-12 ${roundButton}`,
136
+ onPress: () => setOpen(false),
137
+ children: /* @__PURE__ */ jsx(CloseIcon, { color: iconColor })
138
+ })
139
+ ]
140
+ })]
141
+ })
142
+ });
143
+ }
144
+ //#endregion
145
+ export { Lightbox };
146
+
147
+ //# sourceMappingURL=lightbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lightbox.js","names":["RNModal"],"sources":["../../../src/components/lightbox/lightbox.tsx"],"sourcesContent":["/// <reference types=\"uniwind/types\" />\n\nimport { useEffect, useRef, useState } from 'react'\nimport {\n Animated,\n FlatList,\n Image,\n type NativeScrollEvent,\n type NativeSyntheticEvent,\n Modal as RNModal,\n StyleSheet,\n Text,\n useWindowDimensions,\n View,\n} from 'react-native'\nimport { Backdrop } from '../_shared/backdrop'\nimport { NextIcon, PreviousIcon } from '../_shared/media-icons'\nimport { useOpenState } from '../_shared/overlay-state'\nimport { CloseIcon } from '../_shared/status'\nimport { useToken } from '../_shared/use-token'\nimport { useTransition } from '../_shared/use-transition'\nimport { IconButton } from '../icon-button'\n\nexport type LightboxItem = {\n /** Endereço da imagem ampliada. */\n src: string\n /** Descrição da imagem para leitores de tela. */\n alt: string\n}\n\nexport type LightboxProps = {\n items: LightboxItem[]\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n /** Índice da imagem exibida (modo controlado). */\n index?: number\n defaultIndex?: number\n onIndexChange?: (index: number) => void\n /** Nome acessível do visualizador. */\n label?: string\n closeLabel?: string\n previousLabel?: string\n nextLabel?: string\n testID?: string\n}\n\nconst roundButton = 'rounded-full border-border-default bg-surface-elevated active:bg-bg-secondary'\n\n/**\n * Imagem ampliada sobre um fundo escurecido, com contador (`1 / 6`), setas e fechar. Deslize para\n * os lados para trocar de foto; as setas dão a volta (da última vai para a primeira).\n */\nexport function Lightbox({\n items,\n open,\n defaultOpen,\n onOpenChange,\n index,\n defaultIndex = 0,\n onIndexChange,\n label = 'Visualizador de imagens',\n closeLabel = 'Fechar',\n previousLabel = 'Foto anterior',\n nextLabel = 'Próxima foto',\n testID,\n}: LightboxProps) {\n const [isOpen, setOpen] = useOpenState({ open, defaultOpen, onOpenChange })\n const { mounted, progress } = useTransition(isOpen)\n const { width, height } = useWindowDimensions()\n const iconColor = useToken('--color-text-primary')\n const list = useRef<FlatList<LightboxItem>>(null)\n const [inner, setInner] = useState(defaultIndex)\n const count = items.length\n const current = Math.min(Math.max(index ?? inner, 0), Math.max(count - 1, 0))\n // índice em que a lista está de fato, para só rolar quando o pai troca `index` por fora\n const shown = useRef(current)\n\n function show(next: number) {\n shown.current = next\n if (index === undefined) setInner(next)\n onIndexChange?.(next)\n }\n\n function go(next: number) {\n const wrapped = (next + count) % count\n list.current?.scrollToIndex({ index: wrapped, animated: true })\n show(wrapped)\n }\n\n useEffect(() => {\n if (!mounted || shown.current === current) return\n shown.current = current\n list.current?.scrollToIndex({ index: current, animated: false })\n }, [current, mounted])\n\n function onMomentumScrollEnd(event: NativeSyntheticEvent<NativeScrollEvent>) {\n const next = Math.round(event.nativeEvent.contentOffset.x / width)\n if (next !== shown.current && next >= 0 && next < count) show(next)\n }\n\n return (\n <RNModal\n transparent\n statusBarTranslucent\n animationType=\"none\"\n visible={mounted}\n onRequestClose={() => setOpen(false)}\n >\n <View className=\"flex-1\" accessibilityViewIsModal accessibilityLabel={label} testID={testID}>\n <Animated.View\n pointerEvents=\"box-none\"\n style={[StyleSheet.absoluteFill, { opacity: progress }]}\n >\n <Backdrop onPress={() => setOpen(false)} />\n </Animated.View>\n <Animated.View\n pointerEvents=\"box-none\"\n style={[StyleSheet.absoluteFill, { opacity: progress, justifyContent: 'center' }]}\n >\n <FlatList\n ref={list}\n data={items}\n horizontal\n pagingEnabled\n showsHorizontalScrollIndicator={false}\n keyExtractor={(item) => item.src}\n initialScrollIndex={current}\n getItemLayout={(_, i) => ({ length: width, offset: width * i, index: i })}\n onMomentumScrollEnd={onMomentumScrollEnd}\n renderItem={({ item }) => (\n <View style={{ width, height: height * 0.7, paddingHorizontal: 16 }}>\n <Image\n source={{ uri: item.src }}\n accessibilityLabel={item.alt}\n resizeMode=\"contain\"\n className=\"size-full\"\n />\n </View>\n )}\n />\n {count > 1 && (\n <>\n <View\n pointerEvents=\"box-none\"\n className=\"absolute inset-x-3 flex-row justify-between\"\n style={{ top: height / 2 - 22 }}\n >\n <IconButton\n accessibilityLabel={previousLabel}\n variant=\"tertiary\"\n className={roundButton}\n onPress={() => go(shown.current - 1)}\n >\n <PreviousIcon color={iconColor} />\n </IconButton>\n <IconButton\n accessibilityLabel={nextLabel}\n variant=\"tertiary\"\n className={roundButton}\n onPress={() => go(shown.current + 1)}\n >\n <NextIcon color={iconColor} />\n </IconButton>\n </View>\n <Text\n accessibilityLiveRegion=\"polite\"\n className=\"absolute bottom-12 self-center text-sm font-medium leading-5 text-media-on-surface\"\n >\n {current + 1} / {count}\n </Text>\n </>\n )}\n <IconButton\n accessibilityLabel={closeLabel}\n variant=\"tertiary\"\n className={`absolute right-4 top-12 ${roundButton}`}\n onPress={() => setOpen(false)}\n >\n <CloseIcon color={iconColor} />\n </IconButton>\n </Animated.View>\n </View>\n </RNModal>\n )\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { VideoPlayer, VideoPlayerProps } from "./video-player.js";
2
+ export { VideoPlayer, type VideoPlayerProps };
@@ -0,0 +1,37 @@
1
+ import { ReactNode } from "react";
2
+ import { ViewProps } from "react-native";
3
+ //#region src/components/video-player/video-player.d.ts
4
+ export type VideoPlayerProps = Omit<ViewProps, 'style'> & {
5
+ className?: string;
6
+ /** A superfície de vídeo (ex.: o `VideoView` do `expo-video`), que preenche o player. */
7
+ children: ReactNode;
8
+ /** Nome acessível do player. */
9
+ label?: string;
10
+ /** Tocando agora: mostra o botão de pausar e esconde o play central. */
11
+ playing?: boolean;
12
+ /** Posição atual, em segundos. */
13
+ position?: number;
14
+ /** Duração total, em segundos. */
15
+ duration?: number;
16
+ /** Sem som: mostra o ícone de volume cortado. */
17
+ muted?: boolean;
18
+ /** Em tela cheia: mostra o ícone de sair. Só vale com `onToggleFullscreen`. */
19
+ fullscreen?: boolean;
20
+ onPlayPause?: () => void;
21
+ /** Chamado com a posição (em segundos) tocada ou arrastada na barra. */
22
+ onSeek?: (seconds: number) => void;
23
+ onToggleMute?: () => void;
24
+ /** Sem ele, o botão de tela cheia não aparece. */
25
+ onToggleFullscreen?: () => void;
26
+ /** Tempo sem interação, em ms, até esconder os controles durante a reprodução. Padrão: 2500. */
27
+ hideControlsAfter?: number;
28
+ };
29
+ /**
30
+ * Casca de player de vídeo: play central, posição, tempo, mudo e tela cheia sobre o seu vídeo.
31
+ * Não toca nada: quem usa guarda o estado (por exemplo com `expo-video`) e o passa por props,
32
+ * ligando os `on…` ao player de verdade. Tocar no vídeo alterna play/pause e mostra os controles,
33
+ * que somem depois de um tempo sem toques enquanto toca (com leitor de tela ligado, ficam).
34
+ */
35
+ export declare function VideoPlayer({ className, children, label, playing, position, duration, muted, fullscreen, onPlayPause, onSeek, onToggleMute, onToggleFullscreen, hideControlsAfter, ...props }: VideoPlayerProps): import("react").JSX.Element;
36
+ //#endregion
37
+ //# sourceMappingURL=video-player.d.ts.map
@@ -0,0 +1,178 @@
1
+ import { cn } from "../../utils/cn.js";
2
+ import { useToken } from "../_shared/use-token.js";
3
+ import { formatTime, useSeek } from "../_shared/media.js";
4
+ import { MaximizeIcon, MinimizeIcon, PauseIcon, PlayIcon, VolumeIcon, VolumeMutedIcon } from "../_shared/media-icons.js";
5
+ import { useCallback, useEffect, useRef, useState } from "react";
6
+ import { AccessibilityInfo, Pressable, StyleSheet, Text, View } from "react-native";
7
+ import Svg, { Defs, LinearGradient, Rect, Stop } from "react-native-svg";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ //#region src/components/video-player/video-player.tsx
10
+ const button = "size-9 shrink-0 items-center justify-center rounded-full active:bg-media-on-surface/15";
11
+ /**
12
+ * Casca de player de vídeo: play central, posição, tempo, mudo e tela cheia sobre o seu vídeo.
13
+ * Não toca nada: quem usa guarda o estado (por exemplo com `expo-video`) e o passa por props,
14
+ * ligando os `on…` ao player de verdade. Tocar no vídeo alterna play/pause e mostra os controles,
15
+ * que somem depois de um tempo sem toques enquanto toca (com leitor de tela ligado, ficam).
16
+ */
17
+ function VideoPlayer({ className, children, label = "Vídeo", playing = false, position = 0, duration = 0, muted = false, fullscreen = false, onPlayPause, onSeek, onToggleMute, onToggleFullscreen, hideControlsAfter = 2500, ...props }) {
18
+ const [active, setActive] = useState(true);
19
+ const [screenReader, setScreenReader] = useState(false);
20
+ const timer = useRef(void 0);
21
+ const onSurface = useToken("--color-media-on-surface");
22
+ const accent = useToken("--color-interactive-primary");
23
+ const scrim = useToken("--color-media-surface") ?? "#000000";
24
+ const seek = useSeek({
25
+ position,
26
+ duration,
27
+ label: "Posição do vídeo",
28
+ onSeek
29
+ });
30
+ const visible = active || !playing || screenReader;
31
+ const progress = duration ? Math.min(position / duration, 1) * 100 : 0;
32
+ useEffect(() => {
33
+ AccessibilityInfo.isScreenReaderEnabled().then(setScreenReader);
34
+ const subscription = AccessibilityInfo.addEventListener("screenReaderChanged", setScreenReader);
35
+ return () => subscription.remove();
36
+ }, []);
37
+ const show = useCallback(() => {
38
+ setActive(true);
39
+ clearTimeout(timer.current);
40
+ timer.current = setTimeout(() => setActive(false), hideControlsAfter);
41
+ }, [hideControlsAfter]);
42
+ useEffect(() => {
43
+ if (playing) show();
44
+ else setActive(true);
45
+ return () => clearTimeout(timer.current);
46
+ }, [playing, show]);
47
+ return /* @__PURE__ */ jsxs(View, {
48
+ accessibilityLabel: label,
49
+ className: cn("aspect-video w-full overflow-hidden rounded-lg bg-media-surface shadow-lg", className),
50
+ ...props,
51
+ children: [
52
+ /* @__PURE__ */ jsx(View, {
53
+ pointerEvents: "none",
54
+ className: "absolute inset-0",
55
+ children
56
+ }),
57
+ /* @__PURE__ */ jsx(Pressable, {
58
+ accessible: false,
59
+ onPress: () => {
60
+ onPlayPause?.();
61
+ show();
62
+ },
63
+ className: "absolute inset-0",
64
+ children: !playing && /* @__PURE__ */ jsx(View, {
65
+ pointerEvents: "none",
66
+ className: "absolute inset-0 bg-media-surface/30"
67
+ })
68
+ }),
69
+ !playing && /* @__PURE__ */ jsx(View, {
70
+ pointerEvents: "box-none",
71
+ className: "absolute inset-0 items-center justify-center",
72
+ children: /* @__PURE__ */ jsx(Pressable, {
73
+ accessible: false,
74
+ importantForAccessibility: "no",
75
+ onPress: onPlayPause,
76
+ className: "size-16 items-center justify-center rounded-full bg-media-on-surface shadow-lg",
77
+ children: /* @__PURE__ */ jsx(PlayIcon, {
78
+ filled: true,
79
+ size: 28,
80
+ color: accent
81
+ })
82
+ })
83
+ }),
84
+ /* @__PURE__ */ jsxs(View, {
85
+ pointerEvents: visible ? "box-none" : "none",
86
+ importantForAccessibility: visible ? "auto" : "no-hide-descendants",
87
+ accessibilityElementsHidden: !visible,
88
+ className: cn("absolute inset-x-0 bottom-0 px-4 pb-3 pt-[30px]", !visible && "opacity-0"),
89
+ children: [
90
+ /* @__PURE__ */ jsxs(Svg, {
91
+ pointerEvents: "none",
92
+ style: StyleSheet.absoluteFill,
93
+ preserveAspectRatio: "none",
94
+ children: [/* @__PURE__ */ jsx(Defs, { children: /* @__PURE__ */ jsxs(LinearGradient, {
95
+ id: "scrim",
96
+ x1: "0",
97
+ y1: "1",
98
+ x2: "0",
99
+ y2: "0",
100
+ children: [/* @__PURE__ */ jsx(Stop, {
101
+ offset: "0",
102
+ stopColor: scrim,
103
+ stopOpacity: .65
104
+ }), /* @__PURE__ */ jsx(Stop, {
105
+ offset: "1",
106
+ stopColor: scrim,
107
+ stopOpacity: 0
108
+ })]
109
+ }) }), /* @__PURE__ */ jsx(Rect, {
110
+ width: "100%",
111
+ height: "100%",
112
+ fill: "url(#scrim)"
113
+ })]
114
+ }),
115
+ /* @__PURE__ */ jsx(View, {
116
+ ...seek.props,
117
+ className: "mb-1 h-4 w-full justify-center",
118
+ children: /* @__PURE__ */ jsx(View, {
119
+ pointerEvents: "none",
120
+ className: "h-1 w-full rounded-full bg-media-on-surface/30",
121
+ children: /* @__PURE__ */ jsx(View, {
122
+ className: "h-full rounded-full bg-media-accent",
123
+ style: { width: `${progress}%` }
124
+ })
125
+ })
126
+ }),
127
+ /* @__PURE__ */ jsxs(View, {
128
+ className: "h-9 flex-row items-center justify-between",
129
+ children: [/* @__PURE__ */ jsxs(View, {
130
+ className: "flex-row items-center gap-2",
131
+ children: [/* @__PURE__ */ jsx(Pressable, {
132
+ accessibilityRole: "button",
133
+ accessibilityLabel: playing ? "Pausar" : "Reproduzir",
134
+ onPress: () => {
135
+ onPlayPause?.();
136
+ show();
137
+ },
138
+ className: button,
139
+ children: playing ? /* @__PURE__ */ jsx(PauseIcon, { color: onSurface }) : /* @__PURE__ */ jsx(PlayIcon, { color: onSurface })
140
+ }), /* @__PURE__ */ jsxs(Text, {
141
+ accessible: false,
142
+ className: "text-xs font-medium leading-4 text-media-on-surface",
143
+ style: { fontVariant: ["tabular-nums"] },
144
+ children: [
145
+ formatTime(position),
146
+ " / ",
147
+ formatTime(duration)
148
+ ]
149
+ })]
150
+ }), /* @__PURE__ */ jsxs(View, {
151
+ className: "flex-row items-center gap-2",
152
+ children: [/* @__PURE__ */ jsx(Pressable, {
153
+ accessibilityRole: "button",
154
+ accessibilityLabel: muted ? "Ativar o som" : "Silenciar",
155
+ onPress: () => {
156
+ onToggleMute?.();
157
+ show();
158
+ },
159
+ className: button,
160
+ children: muted ? /* @__PURE__ */ jsx(VolumeMutedIcon, { color: onSurface }) : /* @__PURE__ */ jsx(VolumeIcon, { color: onSurface })
161
+ }), onToggleFullscreen && /* @__PURE__ */ jsx(Pressable, {
162
+ accessibilityRole: "button",
163
+ accessibilityLabel: fullscreen ? "Sair da tela cheia" : "Tela cheia",
164
+ onPress: onToggleFullscreen,
165
+ className: button,
166
+ children: fullscreen ? /* @__PURE__ */ jsx(MinimizeIcon, { color: onSurface }) : /* @__PURE__ */ jsx(MaximizeIcon, { color: onSurface })
167
+ })]
168
+ })]
169
+ })
170
+ ]
171
+ })
172
+ ]
173
+ });
174
+ }
175
+ //#endregion
176
+ export { VideoPlayer };
177
+
178
+ //# sourceMappingURL=video-player.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-player.js","names":[],"sources":["../../../src/components/video-player/video-player.tsx"],"sourcesContent":["/// <reference types=\"uniwind/types\" />\n\nimport { type ReactNode, useCallback, useEffect, useRef, useState } from 'react'\nimport { AccessibilityInfo, Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native'\nimport Svg, { Defs, LinearGradient, Rect, Stop } from 'react-native-svg'\nimport { cn } from '../../utils/cn'\nimport { formatTime, useSeek } from '../_shared/media'\nimport {\n MaximizeIcon,\n MinimizeIcon,\n PauseIcon,\n PlayIcon,\n VolumeIcon,\n VolumeMutedIcon,\n} from '../_shared/media-icons'\nimport { useToken } from '../_shared/use-token'\n\nexport type VideoPlayerProps = Omit<ViewProps, 'style'> & {\n className?: string\n /** A superfície de vídeo (ex.: o `VideoView` do `expo-video`), que preenche o player. */\n children: ReactNode\n /** Nome acessível do player. */\n label?: string\n /** Tocando agora: mostra o botão de pausar e esconde o play central. */\n playing?: boolean\n /** Posição atual, em segundos. */\n position?: number\n /** Duração total, em segundos. */\n duration?: number\n /** Sem som: mostra o ícone de volume cortado. */\n muted?: boolean\n /** Em tela cheia: mostra o ícone de sair. Só vale com `onToggleFullscreen`. */\n fullscreen?: boolean\n onPlayPause?: () => void\n /** Chamado com a posição (em segundos) tocada ou arrastada na barra. */\n onSeek?: (seconds: number) => void\n onToggleMute?: () => void\n /** Sem ele, o botão de tela cheia não aparece. */\n onToggleFullscreen?: () => void\n /** Tempo sem interação, em ms, até esconder os controles durante a reprodução. Padrão: 2500. */\n hideControlsAfter?: number\n}\n\nconst button =\n 'size-9 shrink-0 items-center justify-center rounded-full active:bg-media-on-surface/15'\n\n/**\n * Casca de player de vídeo: play central, posição, tempo, mudo e tela cheia sobre o seu vídeo.\n * Não toca nada: quem usa guarda o estado (por exemplo com `expo-video`) e o passa por props,\n * ligando os `on…` ao player de verdade. Tocar no vídeo alterna play/pause e mostra os controles,\n * que somem depois de um tempo sem toques enquanto toca (com leitor de tela ligado, ficam).\n */\nexport function VideoPlayer({\n className,\n children,\n label = 'Vídeo',\n playing = false,\n position = 0,\n duration = 0,\n muted = false,\n fullscreen = false,\n onPlayPause,\n onSeek,\n onToggleMute,\n onToggleFullscreen,\n hideControlsAfter = 2500,\n ...props\n}: VideoPlayerProps) {\n const [active, setActive] = useState(true)\n const [screenReader, setScreenReader] = useState(false)\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n const onSurface = useToken('--color-media-on-surface')\n const accent = useToken('--color-interactive-primary')\n const scrim = useToken('--color-media-surface') ?? '#000000'\n const seek = useSeek({ position, duration, label: 'Posição do vídeo', onSeek })\n const visible = active || !playing || screenReader\n const progress = duration ? Math.min(position / duration, 1) * 100 : 0\n\n useEffect(() => {\n AccessibilityInfo.isScreenReaderEnabled().then(setScreenReader)\n const subscription = AccessibilityInfo.addEventListener('screenReaderChanged', setScreenReader)\n return () => subscription.remove()\n }, [])\n\n const show = useCallback(() => {\n setActive(true)\n clearTimeout(timer.current)\n timer.current = setTimeout(() => setActive(false), hideControlsAfter)\n }, [hideControlsAfter])\n\n useEffect(() => {\n if (playing) show()\n else setActive(true)\n return () => clearTimeout(timer.current)\n }, [playing, show])\n\n return (\n <View\n accessibilityLabel={label}\n className={cn(\n 'aspect-video w-full overflow-hidden rounded-lg bg-media-surface shadow-lg',\n className,\n )}\n {...props}\n >\n <View pointerEvents=\"none\" className=\"absolute inset-0\">\n {children}\n </View>\n <Pressable\n accessible={false}\n onPress={() => {\n onPlayPause?.()\n show()\n }}\n className=\"absolute inset-0\"\n >\n {!playing && <View pointerEvents=\"none\" className=\"absolute inset-0 bg-media-surface/30\" />}\n </Pressable>\n {!playing && (\n <View pointerEvents=\"box-none\" className=\"absolute inset-0 items-center justify-center\">\n <Pressable\n accessible={false}\n importantForAccessibility=\"no\"\n onPress={onPlayPause}\n className=\"size-16 items-center justify-center rounded-full bg-media-on-surface shadow-lg\"\n >\n <PlayIcon filled size={28} color={accent} />\n </Pressable>\n </View>\n )}\n <View\n pointerEvents={visible ? 'box-none' : 'none'}\n importantForAccessibility={visible ? 'auto' : 'no-hide-descendants'}\n accessibilityElementsHidden={!visible}\n className={cn('absolute inset-x-0 bottom-0 px-4 pb-3 pt-[30px]', !visible && 'opacity-0')}\n >\n <Svg pointerEvents=\"none\" style={StyleSheet.absoluteFill} preserveAspectRatio=\"none\">\n <Defs>\n <LinearGradient id=\"scrim\" x1=\"0\" y1=\"1\" x2=\"0\" y2=\"0\">\n <Stop offset=\"0\" stopColor={scrim} stopOpacity={0.65} />\n <Stop offset=\"1\" stopColor={scrim} stopOpacity={0} />\n </LinearGradient>\n </Defs>\n <Rect width=\"100%\" height=\"100%\" fill=\"url(#scrim)\" />\n </Svg>\n <View {...seek.props} className=\"mb-1 h-4 w-full justify-center\">\n {/* Filhos ignoram toques para que `locationX` seja sempre relativo à barra. */}\n <View pointerEvents=\"none\" className=\"h-1 w-full rounded-full bg-media-on-surface/30\">\n <View\n className=\"h-full rounded-full bg-media-accent\"\n style={{ width: `${progress}%` }}\n />\n </View>\n </View>\n <View className=\"h-9 flex-row items-center justify-between\">\n <View className=\"flex-row items-center gap-2\">\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={playing ? 'Pausar' : 'Reproduzir'}\n onPress={() => {\n onPlayPause?.()\n show()\n }}\n className={button}\n >\n {playing ? <PauseIcon color={onSurface} /> : <PlayIcon color={onSurface} />}\n </Pressable>\n <Text\n accessible={false}\n className=\"text-xs font-medium leading-4 text-media-on-surface\"\n style={{ fontVariant: ['tabular-nums'] }}\n >\n {formatTime(position)} / {formatTime(duration)}\n </Text>\n </View>\n <View className=\"flex-row items-center gap-2\">\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={muted ? 'Ativar o som' : 'Silenciar'}\n onPress={() => {\n onToggleMute?.()\n show()\n }}\n className={button}\n >\n {muted ? <VolumeMutedIcon color={onSurface} /> : <VolumeIcon color={onSurface} />}\n </Pressable>\n {onToggleFullscreen && (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={fullscreen ? 'Sair da tela cheia' : 'Tela cheia'}\n onPress={onToggleFullscreen}\n className={button}\n >\n {fullscreen ? (\n <MinimizeIcon color={onSurface} />\n ) : (\n <MaximizeIcon color={onSurface} />\n )}\n </Pressable>\n )}\n </View>\n </View>\n </View>\n </View>\n )\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ import { Accordion, AccordionItem, AccordionItemProps, AccordionProps } from "./
2
2
  import "./components/accordion/index.js";
3
3
  import { Alert, AlertProps } from "./components/alert/alert.js";
4
4
  import "./components/alert/index.js";
5
+ import { AudioPlayer, AudioPlayerProps } from "./components/audio-player/audio-player.js";
6
+ import "./components/audio-player/index.js";
5
7
  import { Avatar, AvatarProps } from "./components/avatar/avatar.js";
6
8
  import "./components/avatar/index.js";
7
9
  import { Badge, BadgeProps } from "./components/badge/badge.js";
@@ -14,6 +16,8 @@ import { Button, ButtonProps } from "./components/button/button.js";
14
16
  import "./components/button/index.js";
15
17
  import { Card, CardProps } from "./components/card/card.js";
16
18
  import "./components/card/index.js";
19
+ import { Carousel, CarouselItem, CarouselProps } from "./components/carousel/carousel.js";
20
+ import "./components/carousel/index.js";
17
21
  import { Checkbox, CheckboxProps } from "./components/checkbox/checkbox.js";
18
22
  import "./components/checkbox/index.js";
19
23
  import { Combobox, ComboboxOption, ComboboxProps } from "./components/combobox/combobox.js";
@@ -32,6 +36,9 @@ import { Drawer, DrawerClose, DrawerProps } from "./components/drawer/drawer.js"
32
36
  import "./components/drawer/index.js";
33
37
  import { Field, FieldProps } from "./components/field/field.js";
34
38
  import "./components/field/index.js";
39
+ import { Lightbox, LightboxItem, LightboxProps } from "./components/lightbox/lightbox.js";
40
+ import { Gallery, GalleryItem, GalleryProps } from "./components/gallery/gallery.js";
41
+ import "./components/gallery/index.js";
35
42
  import { Grid, GridItem, GridItemProps, GridProps } from "./components/grid/grid.js";
36
43
  import "./components/grid/index.js";
37
44
  import { IconButton, IconButtonProps } from "./components/icon-button/icon-button.js";
@@ -82,6 +89,8 @@ import { Tooltip, TooltipProps } from "./components/tooltip/tooltip.js";
82
89
  import "./components/tooltip/index.js";
83
90
  import { Upload, UploadFile, UploadFileStatus, UploadProps } from "./components/upload/upload.js";
84
91
  import "./components/upload/index.js";
92
+ import { VideoPlayer, VideoPlayerProps } from "./components/video-player/video-player.js";
93
+ import "./components/video-player/index.js";
85
94
  import { darkColors, lightColors, overlayOpacity, palette, radius, typography } from "./tokens/generated.js";
86
95
  import { cn } from "./utils/cn.js";
87
- export { Accordion, AccordionItem, type AccordionItemProps, type AccordionProps, Alert, type AlertProps, Avatar, type AvatarProps, Badge, type BadgeProps, Banner, type BannerProps, Breadcrumb, BreadcrumbItem, type BreadcrumbItemProps, type BreadcrumbProps, Button, type ButtonProps, Calendar, type CalendarProps, Card, type CardProps, Checkbox, type CheckboxProps, Combobox, type ComboboxOption, type ComboboxProps, Container, type ContainerProps, DatePicker, type DatePickerProps, type DatePreset, type DateRange, DateRangePicker, type DateRangePickerProps, Divider, type DividerProps, Drawer, DrawerClose, type DrawerProps, Field, type FieldProps, Grid, GridItem, type GridItemProps, type GridProps, IconButton, type IconButtonProps, Input, type InputProps, Link, type LinkProps, List, ListItem, type ListItemProps, type ListProps, Menu, MenuItem, type MenuItemProps, MenuLabel, type MenuLabelProps, type MenuProps, MenuSeparator, type MenuSeparatorProps, Modal, ModalClose, type ModalProps, Pagination, type PaginationProps, Popover, PopoverClose, type PopoverProps, Radio, type RadioProps, SegmentedControl, type SegmentedControlProps, SegmentedItem, type SegmentedItemProps, Select, SelectOption, type SelectOptionProps, type SelectProps, Skeleton, type SkeletonProps, Slider, type SliderProps, Spinner, type SpinnerProps, Stack, type StackProps, Step, type StepProps, Stepper, type StepperProps, Switch, type SwitchProps, Tab, TabList, type TabListProps, TabPanel, type TabPanelProps, type TabProps, Table, TableBody, type TableBodyProps, TableCaption, type TableCaptionProps, TableCell, type TableCellProps, TableHead, type TableHeadProps, TableHeader, type TableHeaderProps, type TableProps, TableRow, type TableRowProps, Tabs, type TabsProps, Tag, type TagProps, Textarea, type TextareaProps, type ToastOptions, ToastProvider, type ToastProviderProps, Tooltip, type TooltipProps, Upload, type UploadFile, type UploadFileStatus, type UploadProps, cn, darkColors, getDatePresets, lightColors, overlayOpacity, palette, radius, typography, useToast };
96
+ export { Accordion, AccordionItem, type AccordionItemProps, type AccordionProps, Alert, type AlertProps, AudioPlayer, type AudioPlayerProps, Avatar, type AvatarProps, Badge, type BadgeProps, Banner, type BannerProps, Breadcrumb, BreadcrumbItem, type BreadcrumbItemProps, type BreadcrumbProps, Button, type ButtonProps, Calendar, type CalendarProps, Card, type CardProps, Carousel, CarouselItem, type CarouselProps, Checkbox, type CheckboxProps, Combobox, type ComboboxOption, type ComboboxProps, Container, type ContainerProps, DatePicker, type DatePickerProps, type DatePreset, type DateRange, DateRangePicker, type DateRangePickerProps, Divider, type DividerProps, Drawer, DrawerClose, type DrawerProps, Field, type FieldProps, Gallery, type GalleryItem, type GalleryProps, Grid, GridItem, type GridItemProps, type GridProps, IconButton, type IconButtonProps, Input, type InputProps, Lightbox, type LightboxItem, type LightboxProps, Link, type LinkProps, List, ListItem, type ListItemProps, type ListProps, Menu, MenuItem, type MenuItemProps, MenuLabel, type MenuLabelProps, type MenuProps, MenuSeparator, type MenuSeparatorProps, Modal, ModalClose, type ModalProps, Pagination, type PaginationProps, Popover, PopoverClose, type PopoverProps, Radio, type RadioProps, SegmentedControl, type SegmentedControlProps, SegmentedItem, type SegmentedItemProps, Select, SelectOption, type SelectOptionProps, type SelectProps, Skeleton, type SkeletonProps, Slider, type SliderProps, Spinner, type SpinnerProps, Stack, type StackProps, Step, type StepProps, Stepper, type StepperProps, Switch, type SwitchProps, Tab, TabList, type TabListProps, TabPanel, type TabPanelProps, type TabProps, Table, TableBody, type TableBodyProps, TableCaption, type TableCaptionProps, TableCell, type TableCellProps, TableHead, type TableHeadProps, TableHeader, type TableHeaderProps, type TableProps, TableRow, type TableRowProps, Tabs, type TabsProps, Tag, type TagProps, Textarea, type TextareaProps, type ToastOptions, ToastProvider, type ToastProviderProps, Tooltip, type TooltipProps, Upload, type UploadFile, type UploadFileStatus, type UploadProps, VideoPlayer, type VideoPlayerProps, cn, darkColors, getDatePresets, lightColors, overlayOpacity, palette, radius, typography, useToast };
package/dist/index.js CHANGED
@@ -3,12 +3,14 @@ import { Accordion, AccordionItem } from "./components/accordion/accordion.js";
3
3
  import { Spinner } from "./components/spinner/spinner.js";
4
4
  import { IconButton } from "./components/icon-button/icon-button.js";
5
5
  import { Alert } from "./components/alert/alert.js";
6
+ import { AudioPlayer } from "./components/audio-player/audio-player.js";
6
7
  import { Avatar } from "./components/avatar/avatar.js";
7
8
  import { Badge } from "./components/badge/badge.js";
8
9
  import { Banner } from "./components/banner/banner.js";
9
10
  import { Breadcrumb, BreadcrumbItem } from "./components/breadcrumb/breadcrumb.js";
10
11
  import { Button } from "./components/button/button.js";
11
12
  import { Card } from "./components/card/card.js";
13
+ import { Carousel, CarouselItem } from "./components/carousel/carousel.js";
12
14
  import { Checkbox } from "./components/checkbox/checkbox.js";
13
15
  import { Combobox } from "./components/combobox/combobox.js";
14
16
  import { Container } from "./components/container/container.js";
@@ -20,6 +22,8 @@ import { DateRangePicker } from "./components/date-picker/date-range-picker.js";
20
22
  import { Divider } from "./components/divider/divider.js";
21
23
  import { Drawer, DrawerClose } from "./components/drawer/drawer.js";
22
24
  import { Field } from "./components/field/field.js";
25
+ import { Lightbox } from "./components/lightbox/lightbox.js";
26
+ import { Gallery } from "./components/gallery/gallery.js";
23
27
  import { Grid, GridItem } from "./components/grid/grid.js";
24
28
  import { Input } from "./components/input/input.js";
25
29
  import { Link } from "./components/link/link.js";
@@ -43,4 +47,5 @@ import { Textarea } from "./components/textarea/textarea.js";
43
47
  import { ToastProvider, useToast } from "./components/toast/toast.js";
44
48
  import { Tooltip } from "./components/tooltip/tooltip.js";
45
49
  import { Upload } from "./components/upload/upload.js";
46
- export { Accordion, AccordionItem, Alert, Avatar, Badge, Banner, Breadcrumb, BreadcrumbItem, Button, Calendar, Card, Checkbox, Combobox, Container, DatePicker, DateRangePicker, Divider, Drawer, DrawerClose, Field, Grid, GridItem, IconButton, Input, Link, List, ListItem, Menu, MenuItem, MenuLabel, MenuSeparator, Modal, ModalClose, Pagination, Popover, PopoverClose, Radio, SegmentedControl, SegmentedItem, Select, SelectOption, Skeleton, Slider, Spinner, Stack, Step, Stepper, Switch, Tab, TabList, TabPanel, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Tabs, Tag, Textarea, ToastProvider, Tooltip, Upload, cn, darkColors, getDatePresets, lightColors, overlayOpacity, palette, radius, typography, useToast };
50
+ import { VideoPlayer } from "./components/video-player/video-player.js";
51
+ export { Accordion, AccordionItem, Alert, AudioPlayer, Avatar, Badge, Banner, Breadcrumb, BreadcrumbItem, Button, Calendar, Card, Carousel, CarouselItem, Checkbox, Combobox, Container, DatePicker, DateRangePicker, Divider, Drawer, DrawerClose, Field, Gallery, Grid, GridItem, IconButton, Input, Lightbox, Link, List, ListItem, Menu, MenuItem, MenuLabel, MenuSeparator, Modal, ModalClose, Pagination, Popover, PopoverClose, Radio, SegmentedControl, SegmentedItem, Select, SelectOption, Skeleton, Slider, Spinner, Stack, Step, Stepper, Switch, Tab, TabList, TabPanel, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Tabs, Tag, Textarea, ToastProvider, Tooltip, Upload, VideoPlayer, cn, darkColors, getDatePresets, lightColors, overlayOpacity, palette, radius, typography, useToast };
@@ -172,6 +172,10 @@ export declare const lightColors: {
172
172
  readonly selectionToggleTrackOff: "#ccd5e2";
173
173
  readonly selectionToggleTrackOffHover: "#96a3b9";
174
174
  readonly selectionToggleTrackOnHover: "#7b24d1";
175
+ readonly mediaWaveRest: "#ccd5e2";
176
+ readonly mediaSurface: "#000000";
177
+ readonly mediaOnSurface: "#ffffff";
178
+ readonly mediaAccent: "#bd84ff";
175
179
  };
176
180
  export declare const darkColors: {
177
181
  readonly textPrimary: "#f8fafc";
@@ -264,6 +268,10 @@ export declare const darkColors: {
264
268
  readonly selectionToggleTrackOff: "#49556a";
265
269
  readonly selectionToggleTrackOffHover: "#96a3b9";
266
270
  readonly selectionToggleTrackOnHover: "#d6b4ff";
271
+ readonly mediaWaveRest: "#66748c";
272
+ readonly mediaSurface: "#000000";
273
+ readonly mediaOnSurface: "#ffffff";
274
+ readonly mediaAccent: "#bd84ff";
267
275
  };
268
276
  export declare const radius: {
269
277
  readonly none: 0;
@@ -171,7 +171,11 @@ const lightColors = {
171
171
  "selectionTextDisabled": "#ccd5e2",
172
172
  "selectionToggleTrackOff": "#ccd5e2",
173
173
  "selectionToggleTrackOffHover": "#96a3b9",
174
- "selectionToggleTrackOnHover": "#7b24d1"
174
+ "selectionToggleTrackOnHover": "#7b24d1",
175
+ "mediaWaveRest": "#ccd5e2",
176
+ "mediaSurface": "#000000",
177
+ "mediaOnSurface": "#ffffff",
178
+ "mediaAccent": "#bd84ff"
175
179
  };
176
180
  const darkColors = {
177
181
  "textPrimary": "#f8fafc",
@@ -263,7 +267,11 @@ const darkColors = {
263
267
  "selectionTextDisabled": "#49556a",
264
268
  "selectionToggleTrackOff": "#49556a",
265
269
  "selectionToggleTrackOffHover": "#96a3b9",
266
- "selectionToggleTrackOnHover": "#d6b4ff"
270
+ "selectionToggleTrackOnHover": "#d6b4ff",
271
+ "mediaWaveRest": "#66748c",
272
+ "mediaSurface": "#000000",
273
+ "mediaOnSurface": "#ffffff",
274
+ "mediaAccent": "#bd84ff"
267
275
  };
268
276
  const radius = {
269
277
  "none": 0,