Saltar al contenido principal
Neural Nativev0.1.0-beta.1Documentación

Importación

component.ts
import { NeuUploaderComponent } from '@neural-ui/native/uploader';

Ejemplos

Importa ExampleComponent en su padre y coloca <app-example /> dentro del neu-theme raíz de tu aplicación. El preview aporta el marco y las zonas seguras; utiliza la estructura raíz de Instalación en tu app.

Todo lo que necesita tu proyecto

Elige un archivo pequeño, prueba la subida local, reintenta un fallo provocado y elimina archivos. Conecta el transporte real documentado más abajo en tu aplicación.

Ver y copiar el ejemplo completo
basic.component.ts
import { Component, signal } from '@angular/core';
import { NeuSwitchComponent } from '@neural-ui/native/switch';
import { NeuUploaderComponent } from '@neural-ui/native/uploader';
import { View, Text, ScrollView } from '@ng-native/components';
import type { NeuUpload, NeuUploadItem } from '@neural-ui/native';

@Component({
  selector: 'app-example',
  imports: [NeuSwitchComponent, NeuUploaderComponent, View, Text, ScrollView],
  template: `
    <scroll-view class="product-scroll" keyboardShouldPersistTaps="handled" [showsVerticalScrollIndicator]="true"><view class="product-stack"><view class="product-section"><text class="product-title" accessibilityRole="header">Todo lo que necesita tu proyecto</text><text class="product-caption">Reúne el briefing y los documentos de apoyo</text></view>
    <view class="product-surface"><neu-uploader [stateLabels]="{ selected: 'Archivo seleccionado', uploading: 'Subiendo', complete: 'Subida completada', error: 'Error de subida' }" label="Documentos del proyecto" chooseLabel="Elegir documentos" uploadLabel="Subir" removeLabel="Eliminar" [(files)]="files" [upload]="upload" [maxFiles]="3" [maxBytes]="5000000" [types]="types" /></view>
    <neu-switch label="Hacer fallar la próxima subida simulada" [(checked)]="failNext" />
    <text class="product-caption">Simulación local · No se envían archivos a un servidor. Elimina un archivo activo para cancelar; reintenta después de un error.</text></view></scroll-view>
  `,
  styles: `
.actions { gap: 12px; align-items: flex-start; } text { color: var(--neu-text, #172033); font-size: 16px; }

:host { flex: 1; flex-shrink: 1; min-height: 0; }
.product-scroll { flex: 1; flex-shrink: 1; height: 0px; min-height: 0; }
.product-stack { gap: 24px; padding-bottom: 20px; }
.product-section { gap: 12px; }
.product-row { flex-direction: row; align-items: center; gap: 12px; }
.product-copy { flex: 1; min-width: 0; gap: 4px; }
.product-title { color: var(--neu-text, #172033); font-size: 24px; line-height: 30px; font-weight: 600; }
.product-heading { color: var(--neu-text, #172033); font-size: 17px; line-height: 23px; font-weight: 600; }
.product-caption { color: var(--neu-muted, #596477); font-size: 14px; line-height: 20px; }
.product-actions { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px; }
.product-surface { gap: 16px; padding: 16px; border-radius: 16px; background-color: var(--neu-surface, #ffffff); border-width: 1px; border-color: var(--neu-border, #a5afbf); }

  `,
})
export class ExampleComponent {
  readonly files = signal<readonly NeuUploadItem[]>([]);
  readonly types = ['application/pdf', 'image/*', 'text/plain'];
  readonly failNext = signal(false);
  readonly upload: NeuUpload = async (_file, progress, signal) => {
    const fail = this.failNext(); this.failNext.set(false);
    for (const percent of [25, 60, 100]) {
      await this.pause(signal);
      if (fail && percent === 60) throw new Error('Error de conexión simulado. Inténtalo de nuevo.');
      progress(percent);
    }
  };
  private pause(signal: AbortSignal): Promise<void> {
    return new Promise((resolve, reject) => {
      if (signal.aborted) { reject(new Error('Cancelled')); return; }
      const abort = () => { clearTimeout(timer); signal.removeEventListener('abort', abort); reject(new Error('Cancelled')); };
      const timer = setTimeout(() => { signal.removeEventListener('abort', abort); resolve(); }, 350);
      signal.addEventListener('abort', abort, { once: true });
    });
  }
}
Playground interactivo

Ajusta la configuración y prueba el resultado.

Capturas del dispositivo en inglés.

Uploader · android · native capture
AndroidCaptura nativa
Uploader · ios · native capture
iOSCaptura nativa

Conecta una subida real

Elegir un archivo no lo sube. Aporta upload para enviarlo a tu backend o almacenamiento. Este ejemplo nativo utiliza una URL PUT temporal que proporciona tu backend autenticado y Expo FileSystem para leer el archivo elegido.

terminal
npx expo install expo-file-system

Crea estos dos archivos, importa ProjectFilesComponent en su padre y colócalo dentro del neu-theme raíz. Sustituye api.example.com por tu endpoint y añade la autenticación de tu aplicación. El backend debe validar permisos, tipo MIME y tamaño y devolver una URL HTTPS específica para ese archivo; los límites del cliente solo orientan al usuario.

src/app/upload-transport.ts
import { File } from 'expo-file-system';
import { fetch as expoFetch } from 'expo/fetch';
import type { NeuFile, NeuUpload } from '@neural-ui/native';

type UploadTarget = { url: string; headers?: Record<string, string> };
// Ask your authenticated backend for a short-lived, file-specific PUT URL.
type ResolveTarget = (file: NeuFile, signal: AbortSignal) => Promise<UploadTarget>;

export function createUpload(resolveTarget: ResolveTarget): NeuUpload {
  return async (file, progress, signal) => {
    if (signal.aborted) throw new Error('Upload cancelled');
    progress(0);
    const target = await resolveTarget(file, signal);
    if (signal.aborted) throw new Error('Upload cancelled');
    const response = await expoFetch(target.url, {
      method: 'PUT', signal,
      headers: { 'Content-Type': file.mimeType || 'application/octet-stream', ...target.headers },
      body: new File(file.uri),
    });
    if (!response.ok) throw new Error('Could not upload. Try again.');
    if (signal.aborted) throw new Error('Upload cancelled');
    progress(100);
  };
}
src/app/project-files.component.ts
import { Component, signal } from '@angular/core';
import { NeuUploaderComponent } from '@neural-ui/native/uploader';
import type { NeuUploadItem } from '@neural-ui/native';
import { createUpload } from './upload-transport';

@Component({
  selector: 'app-project-files',
  imports: [NeuUploaderComponent],
  template: `<neu-uploader label="Project documents" chooseLabel="Choose documents"
    uploadLabel="Upload" removeLabel="Remove" [(files)]="files"
    [upload]="upload" [types]="types" [maxFiles]="3" [maxBytes]="5000000" />`,
})
export class ProjectFilesComponent {
  readonly files = signal<readonly NeuUploadItem[]>([]);
  readonly types = ['application/pdf', 'image/*'];
  readonly upload = createUpload(async (file, signal) => {
    // Replace this endpoint and add your application's authentication.
    const response = await fetch('https://api.example.com/uploads/target', {
      method: 'POST', signal,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: file.name, size: file.size, type: file.mimeType }),
    });
    if (!response.ok) throw new Error('Could not prepare the upload. Try again.');
    const target: unknown = await response.json();
    if (!target || typeof target !== 'object' || !('url' in target) || typeof target.url !== 'string') {
      throw new Error('Invalid upload destination');
    }
    const url = new URL(target.url);
    if (url.protocol !== 'https:') throw new Error('An HTTPS upload destination is required');
    return { url: url.href };
  });
}

El callback recibe el archivo, una función de progreso y un AbortSignal. Resuelve solo tras una respuesta correcta del servidor; lanza un error si falla para que Uploader muestre el mensaje y permita reintentar. Eliminar un archivo activo o destruir Uploader cancela la señal. Pásala a todas las peticiones de red.

Este transporte fetch comunica 0 y 100; no mide los bytes enviados durante la petición. Utiliza un transporte con eventos de progreso si necesitas porcentajes intermedios. Eliminar un elemento ya subido solo lo quita de la interfaz: borrar el objeto remoto requiere la API de tu aplicación. La demo web simula la subida localmente y no envía archivos a un servicio externo.

Expo: subir archivos con fetch ↗

Referencia API

Inputs

NombreTipoPredeterminadoEnlaceDescripción
labelstring'Files'InputNombre legible del control, acción o grupo.
disabledbooleanfalseInputDesactiva la interacción del usuario. La aplicación puede seguir proporcionando valores.
typesreadonly string[]['*/*']InputTipos MIME de archivos admitidos que se pasan al selector y a las comprobaciones de aceptación.
multiplebooleantrueInputPermite varias opciones o archivos cuando se admite; consulta el tipo declarado del model.
maxFilesnumber10InputCantidad máxima de archivos admitidos por el uploader.
maxBytesnumber10 * 1024 * 1024InputTamaño máximo admitido por archivo, en bytes.
chooseLabelstring'Choose files'InputTexto o nombre accesible utilizado para elegir archivos. No ejecuta la acción por sí solo.
uploadLabelstring'Upload'InputTexto o nombre accesible utilizado para subir archivos. No ejecuta la acción por sí solo.
removeLabelstring'Remove'InputTexto o nombre accesible utilizado para eliminar. No ejecuta la acción por sí solo.
stateLabelsReadonly<Record<"selected" | "uploading" | "complete" | "error", string>>{ selected: 'File selected', uploading: 'Uploading', complete: 'Upload complete', error: 'Upload failed', }InputMensajes visibles para selected, uploading, complete y error. Aporta las cuatro claves en el idioma de tu aplicación; los IDs de estado en files no cambian.
uploadNeuUpload | undefinedundefinedInputCallback de subida de tu aplicación. Recibe el archivo, una función de progreso y un AbortSignal; seleccionar archivos no exige un transporte.

Models

NombreTipoPredeterminadoEnlaceDescripción
filesreadonly NeuUploadItem[][]Model · bidireccionalArchivos actuales, incluido su estado de subida y progreso. Enlaza una signal escribible mediante [(files)].

Outputs

NombrePayloadCuándo se emite
filesChangereadonly NeuUploadItem[]Emite el valor actualizado de files. [(files)] enlaza este output junto con su input model.
selectedreadonly NeuFile[]Emite los archivos aceptados por el selector; es independiente de la finalización de la subida.
completedNeuFileEmite el archivo cuyo callback de subida terminó correctamente.
rejectedstringEmite el mensaje de rechazo de un archivo que no superó las comprobaciones de aceptación.

Estado de los models

Enlaza la signal con [(nombreModel)] sin llamarla. Utiliza nombreModel() para leer su valor.

model-fields.ts
import { signal } from '@angular/core';
import type { NeuUploadItem } from '@neural-ui/native';

// Fields inside your component class
readonly files = signal<readonly NeuUploadItem[]>([]);

Tipos e interfaces de datos

Utiliza los imports en tu aplicación. Las definiciones siguientes se muestran como referencia.

NeuFile

NeuFile.ts
import type { NeuFile } from '@neural-ui/native';

// Public definition for reference only. Import this type; do not redeclare it.
export interface NeuFile {
    readonly uri: string;
    readonly name: string;
    readonly size?: number;
    readonly mimeType?: string;
}
CampoTipoRequisitoSignificado
uristringObligatorioURI nativa de imagen o archivo.
namestringObligatorioNombre de archivo proporcionado por el selector.
sizenumberOpcionalTamaño en bytes, cuando lo proporciona el selector.
mimeTypestringOpcionalTipo MIME del archivo, si está disponible.

NeuUploadItem

NeuUploadItem.ts
import type { NeuUploadItem } from '@neural-ui/native';
import type { NeuFile } from '@neural-ui/native';

// Public definition for reference only. Import this type; do not redeclare it.
export interface NeuUploadItem {
    readonly id: string;
    readonly file: NeuFile;
    readonly state: 'selected' | 'uploading' | 'complete' | 'error';
    readonly progress: number;
    readonly error?: string;
}
CampoTipoRequisitoSignificado
idstringObligatorioIdentificador estable y único para seguimiento y selección.
fileNeuFileObligatorioDatos del archivo seleccionado con el contrato NeuFile.
state'selected' | 'uploading' | 'complete' | 'error'ObligatorioFase de subida: selected, uploading, complete o error.
progressnumberObligatorioProgreso de la subida como porcentaje.
errorstringOpcionalMensaje de error de subida opcional.

NeuUpload

NeuUpload.ts
import type { NeuUpload } from '@neural-ui/native';
import type { NeuFile } from '@neural-ui/native';

// Public definition for reference only. Import this type; do not redeclare it.
export type NeuUpload = (file: NeuFile, progress: (percent: number) => void, signal: AbortSignal) => Promise<void>;