@innovui/react-native 0.3.1 → 0.3.2

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.
@@ -60,7 +60,7 @@ function AudioPlayer({ className, label = "Áudio", playing = false, position =
60
60
  className: cn("h-[34px] min-w-0 justify-center", stacked ? "w-full" : "flex-1"),
61
61
  children: /* @__PURE__ */ jsx(View, {
62
62
  pointerEvents: "none",
63
- className: "h-full flex-row items-center gap-0.5",
63
+ className: "h-full flex-row items-center gap-0.5 overflow-hidden",
64
64
  children: peaks.map((peak, i) => /* @__PURE__ */ jsx(View, {
65
65
  className: cn("min-w-0.5 flex-1 rounded-full", i < played ? "bg-button-primary-bg" : "bg-media-wave-rest"),
66
66
  style: { height: BAR_MIN + peak * BAR_RANGE }
@@ -1 +1 @@
1
- {"version":3,"file":"audio-player.js","names":[],"sources":["../../../src/components/audio-player/audio-player.tsx"],"sourcesContent":["/// <reference types=\"uniwind/types\" />\n\nimport { useState } from 'react'\nimport { Pressable, Text, View, type ViewProps } from 'react-native'\nimport { cn } from '../../utils/cn'\nimport { DEFAULT_WAVEFORM, formatTime, resamplePeaks, useSeek } from '../_shared/media'\nimport { PauseIcon, PlayIcon } from '../_shared/media-icons'\nimport { useToken } from '../_shared/use-token'\n\n// Alturas das barras no Figma: de 6px (silêncio) a 34px (pico).\nconst BAR_MIN = 6\nconst BAR_RANGE = 28\n\nexport type AudioPlayerProps = Omit<ViewProps, 'children' | 'style'> & {\n className?: string\n /** Nome acessível do player. */\n label?: string\n /** Tocando agora: mostra o botão de pausar. */\n playing?: boolean\n /** Posição atual, em segundos. */\n position?: number\n /** Duração total, em segundos. */\n duration?: number\n /** Velocidade atual (controlado). Sem ela, o player guarda a escolhida. */\n rate?: number\n /** Velocidades do botão (cada toque passa para a próxima). Padrão: 1x, 1.5x e 2x. */\n speeds?: number[]\n /** Picos da onda, de 0 a 1. Sem eles, usa uma onda padrão. */\n waveform?: number[]\n /** Quantidade de barras da onda. Padrão: 52. */\n bars?: number\n onPlayPause?: () => void\n /** Chamado com a posição (em segundos) tocada ou arrastada na onda. */\n onSeek?: (seconds: number) => void\n /** Chamado com a nova velocidade quando o botão é tocado. */\n onRateChange?: (rate: number) => void\n}\n\n/**\n * Casca de player de áudio: botão, onda, tempo e velocidade. Não toca nada: quem usa guarda o\n * estado (por exemplo com `expo-audio`) e o passa por props, ligando `onPlayPause`, `onSeek` e\n * `onRateChange` ao player de verdade.\n */\nexport function AudioPlayer({\n className,\n label = 'Áudio',\n playing = false,\n position = 0,\n duration = 0,\n rate,\n speeds = [1, 1.5, 2],\n waveform,\n bars = 52,\n onPlayPause,\n onSeek,\n onRateChange,\n onLayout,\n ...props\n}: AudioPlayerProps) {\n const [chosen, setChosen] = useState(speeds[0] ?? 1)\n const [cardWidth, setCardWidth] = useState(0)\n // abaixo de 416px (26rem) o tempo desce para baixo da onda, que ganha a largura toda\n const stacked = cardWidth > 0 && cardWidth < 416\n const speed = rate ?? chosen\n const iconColor = useToken('--color-media-on-surface')\n const seek = useSeek({ position, duration, label: 'Posição do áudio', onSeek })\n // Em telas estreitas a onda perde barras (2px + 2px de espaço), em vez de invadir o tempo.\n const shown = seek.width ? Math.min(bars, Math.max(1, Math.floor((seek.width + 2) / 4))) : bars\n const peaks = resamplePeaks(waveform ?? DEFAULT_WAVEFORM, shown)\n const played = duration ? Math.round((position / duration) * shown) : 0\n\n function nextSpeed() {\n const next = speeds[(speeds.indexOf(speed) + 1) % speeds.length] ?? 1\n setChosen(next)\n onRateChange?.(next)\n }\n\n return (\n <View\n accessibilityLabel={label}\n onLayout={(event) => {\n setCardWidth(event.nativeEvent.layout.width)\n onLayout?.(event)\n }}\n className={cn(\n 'w-full max-w-[480px] flex-row items-center gap-3 rounded-lg border border-border-default bg-surface-elevated p-4 shadow-sm',\n className,\n )}\n {...props}\n >\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={playing ? 'Pausar' : 'Reproduzir'}\n onPress={onPlayPause}\n className=\"size-11 shrink-0 items-center justify-center rounded-full bg-button-primary-bg active:bg-button-primary-bg-active\"\n >\n {playing ? <PauseIcon color={iconColor} /> : <PlayIcon color={iconColor} />}\n </Pressable>\n <View\n className={cn(\n 'min-w-0 flex-1',\n stacked ? 'flex-col items-stretch gap-1' : 'flex-row items-center gap-2',\n )}\n >\n <View\n {...seek.props}\n className={cn('h-[34px] min-w-0 justify-center', stacked ? 'w-full' : 'flex-1')}\n >\n {/* Filhos ignoram toques para que `locationX` seja sempre relativo à onda. */}\n <View pointerEvents=\"none\" className=\"h-full flex-row items-center gap-0.5\">\n {peaks.map((peak, i) => (\n <View\n // biome-ignore lint/suspicious/noArrayIndexKey: as barras são posicionais e fixas\n key={i}\n className={cn(\n 'min-w-0.5 flex-1 rounded-full',\n i < played ? 'bg-button-primary-bg' : 'bg-media-wave-rest',\n )}\n style={{ height: BAR_MIN + peak * BAR_RANGE }}\n />\n ))}\n </View>\n </View>\n <Text\n accessible={false}\n className=\"shrink-0 text-xs font-medium leading-4 text-text-secondary\"\n style={{ fontVariant: ['tabular-nums'] }}\n >\n {formatTime(position)} / {formatTime(duration)}\n </Text>\n </View>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={`Velocidade de reprodução: ${speed}x`}\n onPress={nextSpeed}\n className=\"h-8 w-16 shrink-0 items-center justify-center rounded-full border border-border-default bg-surface-elevated active:bg-bg-tertiary\"\n >\n <Text className=\"text-sm font-medium leading-5 text-text-secondary\">{speed}x</Text>\n </Pressable>\n </View>\n )\n}\n"],"mappings":";;;;;;;;AAUA,MAAM,UAAU;AAChB,MAAM,YAAY;;;;;;AAgClB,SAAgB,YAAY,EAC1B,WACA,QAAQ,SACR,UAAU,OACV,WAAW,GACX,WAAW,GACX,MACA,SAAS;CAAC;CAAG;CAAK;AAAC,GACnB,UACA,OAAO,IACP,aACA,QACA,cACA,UACA,GAAG,SACgB;CACnB,MAAM,CAAC,QAAQ,aAAa,SAAS,OAAO,MAAM,CAAC;CACnD,MAAM,CAAC,WAAW,gBAAgB,SAAS,CAAC;CAE5C,MAAM,UAAU,YAAY,KAAK,YAAY;CAC7C,MAAM,QAAQ,QAAQ;CACtB,MAAM,YAAY,SAAS,0BAA0B;CACrD,MAAM,OAAO,QAAQ;EAAE;EAAU;EAAU,OAAO;EAAoB;CAAO,CAAC;CAE9E,MAAM,QAAQ,KAAK,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,QAAQ,KAAK,CAAC,CAAC,CAAC,IAAI;CAC3F,MAAM,QAAQ,cAAc,YAAY,kBAAkB,KAAK;CAC/D,MAAM,SAAS,WAAW,KAAK,MAAO,WAAW,WAAY,KAAK,IAAI;CAEtE,SAAS,YAAY;EACnB,MAAM,OAAO,QAAQ,OAAO,QAAQ,KAAK,IAAI,KAAK,OAAO,WAAW;EACpE,UAAU,IAAI;EACd,eAAe,IAAI;CACrB;CAEA,OACE,qBAAC,MAAD;EACE,oBAAoB;EACpB,WAAW,UAAU;GACnB,aAAa,MAAM,YAAY,OAAO,KAAK;GAC3C,WAAW,KAAK;EAClB;EACA,WAAW,GACT,8HACA,SACF;EACA,GAAI;EAVN,UAAA;GAYE,oBAAC,WAAD;IACE,mBAAkB;IAClB,oBAAoB,UAAU,WAAW;IACzC,SAAS;IACT,WAAU;IAET,UAAA,UAAU,oBAAC,WAAD,EAAW,OAAO,UAAY,CAAA,IAAI,oBAAC,UAAD,EAAU,OAAO,UAAY,CAAA;GACjE,CAAA;GACX,qBAAC,MAAD;IACE,WAAW,GACT,kBACA,UAAU,iCAAiC,6BAC7C;IAJF,UAAA,CAME,oBAAC,MAAD;KACE,GAAI,KAAK;KACT,WAAW,GAAG,mCAAmC,UAAU,WAAW,QAAQ;KAG9E,UAAA,oBAAC,MAAD;MAAM,eAAc;MAAO,WAAU;MAClC,UAAA,MAAM,KAAK,MAAM,MAChB,oBAAC,MAAD;OAGE,WAAW,GACT,iCACA,IAAI,SAAS,yBAAyB,oBACxC;OACA,OAAO,EAAE,QAAQ,UAAU,OAAO,UAAU;MAC7C,GANM,CAMN,CACF;KACG,CAAA;IACF,CAAA,GACN,qBAAC,MAAD;KACE,YAAY;KACZ,WAAU;KACV,OAAO,EAAE,aAAa,CAAC,cAAc,EAAE;KAHzC,UAAA;MAKG,WAAW,QAAQ;MAAE;MAAI,WAAW,QAAQ;KACzC;IACF,CAAA,CAAA;;GACN,oBAAC,WAAD;IACE,mBAAkB;IAClB,oBAAoB,6BAA6B,MAAM;IACvD,SAAS;IACT,WAAU;IAEV,UAAA,qBAAC,MAAD;KAAM,WAAU;KAAhB,UAAA,CAAqE,OAAM,GAAO;;GACzE,CAAA;EACP;;AAEV"}
1
+ {"version":3,"file":"audio-player.js","names":[],"sources":["../../../src/components/audio-player/audio-player.tsx"],"sourcesContent":["/// <reference types=\"uniwind/types\" />\n\nimport { useState } from 'react'\nimport { Pressable, Text, View, type ViewProps } from 'react-native'\nimport { cn } from '../../utils/cn'\nimport { DEFAULT_WAVEFORM, formatTime, resamplePeaks, useSeek } from '../_shared/media'\nimport { PauseIcon, PlayIcon } from '../_shared/media-icons'\nimport { useToken } from '../_shared/use-token'\n\n// Alturas das barras no Figma: de 6px (silêncio) a 34px (pico).\nconst BAR_MIN = 6\nconst BAR_RANGE = 28\n\nexport type AudioPlayerProps = Omit<ViewProps, 'children' | 'style'> & {\n className?: string\n /** Nome acessível do player. */\n label?: string\n /** Tocando agora: mostra o botão de pausar. */\n playing?: boolean\n /** Posição atual, em segundos. */\n position?: number\n /** Duração total, em segundos. */\n duration?: number\n /** Velocidade atual (controlado). Sem ela, o player guarda a escolhida. */\n rate?: number\n /** Velocidades do botão (cada toque passa para a próxima). Padrão: 1x, 1.5x e 2x. */\n speeds?: number[]\n /** Picos da onda, de 0 a 1. Sem eles, usa uma onda padrão. */\n waveform?: number[]\n /** Quantidade de barras da onda. Padrão: 52. */\n bars?: number\n onPlayPause?: () => void\n /** Chamado com a posição (em segundos) tocada ou arrastada na onda. */\n onSeek?: (seconds: number) => void\n /** Chamado com a nova velocidade quando o botão é tocado. */\n onRateChange?: (rate: number) => void\n}\n\n/**\n * Casca de player de áudio: botão, onda, tempo e velocidade. Não toca nada: quem usa guarda o\n * estado (por exemplo com `expo-audio`) e o passa por props, ligando `onPlayPause`, `onSeek` e\n * `onRateChange` ao player de verdade.\n */\nexport function AudioPlayer({\n className,\n label = 'Áudio',\n playing = false,\n position = 0,\n duration = 0,\n rate,\n speeds = [1, 1.5, 2],\n waveform,\n bars = 52,\n onPlayPause,\n onSeek,\n onRateChange,\n onLayout,\n ...props\n}: AudioPlayerProps) {\n const [chosen, setChosen] = useState(speeds[0] ?? 1)\n const [cardWidth, setCardWidth] = useState(0)\n // abaixo de 416px (26rem) o tempo desce para baixo da onda, que ganha a largura toda\n const stacked = cardWidth > 0 && cardWidth < 416\n const speed = rate ?? chosen\n const iconColor = useToken('--color-media-on-surface')\n const seek = useSeek({ position, duration, label: 'Posição do áudio', onSeek })\n // Em telas estreitas a onda perde barras (2px + 2px de espaço), em vez de invadir o tempo.\n const shown = seek.width ? Math.min(bars, Math.max(1, Math.floor((seek.width + 2) / 4))) : bars\n const peaks = resamplePeaks(waveform ?? DEFAULT_WAVEFORM, shown)\n const played = duration ? Math.round((position / duration) * shown) : 0\n\n function nextSpeed() {\n const next = speeds[(speeds.indexOf(speed) + 1) % speeds.length] ?? 1\n setChosen(next)\n onRateChange?.(next)\n }\n\n return (\n <View\n accessibilityLabel={label}\n onLayout={(event) => {\n setCardWidth(event.nativeEvent.layout.width)\n onLayout?.(event)\n }}\n className={cn(\n 'w-full max-w-[480px] flex-row items-center gap-3 rounded-lg border border-border-default bg-surface-elevated p-4 shadow-sm',\n className,\n )}\n {...props}\n >\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={playing ? 'Pausar' : 'Reproduzir'}\n onPress={onPlayPause}\n className=\"size-11 shrink-0 items-center justify-center rounded-full bg-button-primary-bg active:bg-button-primary-bg-active\"\n >\n {playing ? <PauseIcon color={iconColor} /> : <PlayIcon color={iconColor} />}\n </Pressable>\n <View\n className={cn(\n 'min-w-0 flex-1',\n stacked ? 'flex-col items-stretch gap-1' : 'flex-row items-center gap-2',\n )}\n >\n <View\n {...seek.props}\n className={cn('h-[34px] min-w-0 justify-center', stacked ? 'w-full' : 'flex-1')}\n >\n {/* Filhos ignoram toques para que `locationX` seja sempre relativo à onda. */}\n <View\n pointerEvents=\"none\"\n className=\"h-full flex-row items-center gap-0.5 overflow-hidden\"\n >\n {peaks.map((peak, i) => (\n <View\n // biome-ignore lint/suspicious/noArrayIndexKey: as barras são posicionais e fixas\n key={i}\n className={cn(\n 'min-w-0.5 flex-1 rounded-full',\n i < played ? 'bg-button-primary-bg' : 'bg-media-wave-rest',\n )}\n style={{ height: BAR_MIN + peak * BAR_RANGE }}\n />\n ))}\n </View>\n </View>\n <Text\n accessible={false}\n className=\"shrink-0 text-xs font-medium leading-4 text-text-secondary\"\n style={{ fontVariant: ['tabular-nums'] }}\n >\n {formatTime(position)} / {formatTime(duration)}\n </Text>\n </View>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={`Velocidade de reprodução: ${speed}x`}\n onPress={nextSpeed}\n className=\"h-8 w-16 shrink-0 items-center justify-center rounded-full border border-border-default bg-surface-elevated active:bg-bg-tertiary\"\n >\n <Text className=\"text-sm font-medium leading-5 text-text-secondary\">{speed}x</Text>\n </Pressable>\n </View>\n )\n}\n"],"mappings":";;;;;;;;AAUA,MAAM,UAAU;AAChB,MAAM,YAAY;;;;;;AAgClB,SAAgB,YAAY,EAC1B,WACA,QAAQ,SACR,UAAU,OACV,WAAW,GACX,WAAW,GACX,MACA,SAAS;CAAC;CAAG;CAAK;AAAC,GACnB,UACA,OAAO,IACP,aACA,QACA,cACA,UACA,GAAG,SACgB;CACnB,MAAM,CAAC,QAAQ,aAAa,SAAS,OAAO,MAAM,CAAC;CACnD,MAAM,CAAC,WAAW,gBAAgB,SAAS,CAAC;CAE5C,MAAM,UAAU,YAAY,KAAK,YAAY;CAC7C,MAAM,QAAQ,QAAQ;CACtB,MAAM,YAAY,SAAS,0BAA0B;CACrD,MAAM,OAAO,QAAQ;EAAE;EAAU;EAAU,OAAO;EAAoB;CAAO,CAAC;CAE9E,MAAM,QAAQ,KAAK,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,QAAQ,KAAK,CAAC,CAAC,CAAC,IAAI;CAC3F,MAAM,QAAQ,cAAc,YAAY,kBAAkB,KAAK;CAC/D,MAAM,SAAS,WAAW,KAAK,MAAO,WAAW,WAAY,KAAK,IAAI;CAEtE,SAAS,YAAY;EACnB,MAAM,OAAO,QAAQ,OAAO,QAAQ,KAAK,IAAI,KAAK,OAAO,WAAW;EACpE,UAAU,IAAI;EACd,eAAe,IAAI;CACrB;CAEA,OACE,qBAAC,MAAD;EACE,oBAAoB;EACpB,WAAW,UAAU;GACnB,aAAa,MAAM,YAAY,OAAO,KAAK;GAC3C,WAAW,KAAK;EAClB;EACA,WAAW,GACT,8HACA,SACF;EACA,GAAI;EAVN,UAAA;GAYE,oBAAC,WAAD;IACE,mBAAkB;IAClB,oBAAoB,UAAU,WAAW;IACzC,SAAS;IACT,WAAU;IAET,UAAA,UAAU,oBAAC,WAAD,EAAW,OAAO,UAAY,CAAA,IAAI,oBAAC,UAAD,EAAU,OAAO,UAAY,CAAA;GACjE,CAAA;GACX,qBAAC,MAAD;IACE,WAAW,GACT,kBACA,UAAU,iCAAiC,6BAC7C;IAJF,UAAA,CAME,oBAAC,MAAD;KACE,GAAI,KAAK;KACT,WAAW,GAAG,mCAAmC,UAAU,WAAW,QAAQ;KAG9E,UAAA,oBAAC,MAAD;MACE,eAAc;MACd,WAAU;MAET,UAAA,MAAM,KAAK,MAAM,MAChB,oBAAC,MAAD;OAGE,WAAW,GACT,iCACA,IAAI,SAAS,yBAAyB,oBACxC;OACA,OAAO,EAAE,QAAQ,UAAU,OAAO,UAAU;MAC7C,GANM,CAMN,CACF;KACG,CAAA;IACF,CAAA,GACN,qBAAC,MAAD;KACE,YAAY;KACZ,WAAU;KACV,OAAO,EAAE,aAAa,CAAC,cAAc,EAAE;KAHzC,UAAA;MAKG,WAAW,QAAQ;MAAE;MAAI,WAAW,QAAQ;KACzC;IACF,CAAA,CAAA;;GACN,oBAAC,WAAD;IACE,mBAAkB;IAClB,oBAAoB,6BAA6B,MAAM;IACvD,SAAS;IACT,WAAU;IAEV,UAAA,qBAAC,MAAD;KAAM,WAAU;KAAhB,UAAA,CAAqE,OAAM,GAAO;;GACzE,CAAA;EACP;;AAEV"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@innovui/react-native",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Componentes React Native do design system InnovUI.",
5
5
  "type": "module",
6
6
  "license": "MIT",