@jotis-me/react 0.0.0-stage → 0.2.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/README.md +77 -2
- package/dist/components/ActivityFeed.d.ts +29 -0
- package/dist/components/ActivityFeed.js +10 -0
- package/dist/components/Alert.d.ts +34 -0
- package/dist/components/Alert.js +27 -0
- package/dist/components/AppIcon.d.ts +27 -0
- package/dist/components/AppIcon.js +9 -0
- package/dist/components/Avatar.d.ts +20 -0
- package/dist/components/Avatar.js +27 -0
- package/dist/components/AvatarGroup.d.ts +10 -0
- package/dist/components/AvatarGroup.js +7 -0
- package/dist/components/AvatarLabel.d.ts +10 -0
- package/dist/components/AvatarLabel.js +7 -0
- package/dist/components/BackgroundPattern.d.ts +35 -0
- package/dist/components/BackgroundPattern.js +73 -0
- package/dist/components/Badge.d.ts +38 -0
- package/dist/components/Badge.js +82 -0
- package/dist/components/Banner.d.ts +48 -0
- package/dist/components/Banner.js +60 -0
- package/dist/components/BarChart.d.ts +25 -0
- package/dist/components/BarChart.js +30 -0
- package/dist/components/Breadcrumbs.d.ts +19 -0
- package/dist/components/Breadcrumbs.js +14 -0
- package/dist/components/BrowserFrame.d.ts +18 -0
- package/dist/components/BrowserFrame.js +15 -0
- package/dist/components/Button.d.ts +51 -0
- package/dist/components/Button.js +54 -0
- package/dist/components/ButtonGroup.d.ts +21 -0
- package/dist/components/ButtonGroup.js +14 -0
- package/dist/components/CalendarView.d.ts +30 -0
- package/dist/components/CalendarView.js +43 -0
- package/dist/components/CamFrame.d.ts +21 -0
- package/dist/components/CamFrame.js +11 -0
- package/dist/components/CardHeader.d.ts +32 -0
- package/dist/components/CardHeader.js +12 -0
- package/dist/components/ChannelBanner.d.ts +24 -0
- package/dist/components/ChannelBanner.js +13 -0
- package/dist/components/ChannelPanel.d.ts +36 -0
- package/dist/components/ChannelPanel.js +12 -0
- package/dist/components/ChartLegend.d.ts +12 -0
- package/dist/components/ChartLegend.js +7 -0
- package/dist/components/ChatBadge.d.ts +15 -0
- package/dist/components/ChatBadge.js +39 -0
- package/dist/components/ChatBox.d.ts +42 -0
- package/dist/components/ChatBox.js +35 -0
- package/dist/components/Checkbox.d.ts +17 -0
- package/dist/components/Checkbox.js +26 -0
- package/dist/components/CloseButton.d.ts +7 -0
- package/dist/components/CloseButton.js +8 -0
- package/dist/components/CodeSnippet.d.ts +23 -0
- package/dist/components/CodeSnippet.js +75 -0
- package/dist/components/ColorPicker.d.ts +17 -0
- package/dist/components/ColorPicker.js +42 -0
- package/dist/components/CommandMenu.d.ts +72 -0
- package/dist/components/CommandMenu.js +102 -0
- package/dist/components/ContentDivider.d.ts +17 -0
- package/dist/components/ContentDivider.js +13 -0
- package/dist/components/CreditCard.d.ts +28 -0
- package/dist/components/CreditCard.js +63 -0
- package/dist/components/DatePicker.d.ts +48 -0
- package/dist/components/DatePicker.js +105 -0
- package/dist/components/Dropdown.d.ts +39 -0
- package/dist/components/Dropdown.js +39 -0
- package/dist/components/EmptyState.d.ts +18 -0
- package/dist/components/EmptyState.js +7 -0
- package/dist/components/FeaturedIcon.d.ts +17 -0
- package/dist/components/FeaturedIcon.js +32 -0
- package/dist/components/FileUpload.d.ts +39 -0
- package/dist/components/FileUpload.js +50 -0
- package/dist/components/FilterBar.d.ts +46 -0
- package/dist/components/FilterBar.js +24 -0
- package/dist/components/Icon.d.ts +5 -0
- package/dist/components/Icon.js +9 -0
- package/dist/components/InlineCTA.d.ts +19 -0
- package/dist/components/InlineCTA.js +7 -0
- package/dist/components/Input.d.ts +16 -0
- package/dist/components/Input.js +10 -0
- package/dist/components/LineChart.d.ts +25 -0
- package/dist/components/LineChart.js +23 -0
- package/dist/components/Message.d.ts +22 -0
- package/dist/components/Message.js +10 -0
- package/dist/components/MessageInput.d.ts +17 -0
- package/dist/components/MessageInput.js +25 -0
- package/dist/components/MetricCard.d.ts +28 -0
- package/dist/components/MetricCard.js +11 -0
- package/dist/components/Modal.d.ts +45 -0
- package/dist/components/Modal.js +15 -0
- package/dist/components/Notification.d.ts +15 -0
- package/dist/components/Notification.js +33 -0
- package/dist/components/NowPlaying.d.ts +25 -0
- package/dist/components/NowPlaying.js +16 -0
- package/dist/components/PageHeader.d.ts +22 -0
- package/dist/components/PageHeader.js +8 -0
- package/dist/components/Pagination.d.ts +29 -0
- package/dist/components/Pagination.js +33 -0
- package/dist/components/PieChart.d.ts +32 -0
- package/dist/components/PieChart.js +30 -0
- package/dist/components/ProgressBar.d.ts +11 -0
- package/dist/components/ProgressBar.js +8 -0
- package/dist/components/Radio.d.ts +15 -0
- package/dist/components/Radio.js +10 -0
- package/dist/components/RadioGroup.d.ts +26 -0
- package/dist/components/RadioGroup.js +9 -0
- package/dist/components/SectionFooter.d.ts +12 -0
- package/dist/components/SectionFooter.js +7 -0
- package/dist/components/SectionHeader.d.ts +24 -0
- package/dist/components/SectionHeader.js +7 -0
- package/dist/components/Select.d.ts +22 -0
- package/dist/components/Select.js +14 -0
- package/dist/components/SidebarNav.d.ts +38 -0
- package/dist/components/SidebarNav.js +26 -0
- package/dist/components/Skeleton.d.ts +15 -0
- package/dist/components/Skeleton.js +10 -0
- package/dist/components/Slideout.d.ts +28 -0
- package/dist/components/Slideout.js +15 -0
- package/dist/components/Slider.d.ts +15 -0
- package/dist/components/Slider.js +17 -0
- package/dist/components/Spinner.d.ts +11 -0
- package/dist/components/Spinner.js +12 -0
- package/dist/components/StreamAlert.d.ts +34 -0
- package/dist/components/StreamAlert.js +10 -0
- package/dist/components/StreamCountdown.d.ts +30 -0
- package/dist/components/StreamCountdown.js +44 -0
- package/dist/components/StreamEvents.d.ts +40 -0
- package/dist/components/StreamEvents.js +20 -0
- package/dist/components/StreamGoal.d.ts +22 -0
- package/dist/components/StreamGoal.js +21 -0
- package/dist/components/StreamScene.d.ts +35 -0
- package/dist/components/StreamScene.js +33 -0
- package/dist/components/StreamStatus.d.ts +28 -0
- package/dist/components/StreamStatus.js +26 -0
- package/dist/components/Table.d.ts +36 -0
- package/dist/components/Table.js +15 -0
- package/dist/components/Tabs.d.ts +38 -0
- package/dist/components/Tabs.js +34 -0
- package/dist/components/Tag.d.ts +18 -0
- package/dist/components/Tag.js +15 -0
- package/dist/components/TextEditor.d.ts +37 -0
- package/dist/components/TextEditor.js +103 -0
- package/dist/components/Textarea.d.ts +6 -0
- package/dist/components/Textarea.js +10 -0
- package/dist/components/Toggle.d.ts +22 -0
- package/dist/components/Toggle.js +12 -0
- package/dist/components/Tooltip.d.ts +15 -0
- package/dist/components/Tooltip.js +27 -0
- package/dist/components/TreeView.d.ts +33 -0
- package/dist/components/TreeView.js +48 -0
- package/dist/components/VideoPlayer.d.ts +25 -0
- package/dist/components/VideoPlayer.js +52 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +76 -0
- package/dist/internal/chart.d.ts +38 -0
- package/dist/internal/chart.js +33 -0
- package/dist/internal/choice.d.ts +18 -0
- package/dist/internal/choice.js +17 -0
- package/dist/internal/cx.d.ts +3 -0
- package/dist/internal/cx.js +26 -0
- package/dist/internal/field.d.ts +29 -0
- package/dist/internal/field.js +23 -0
- package/dist/internal/format.d.ts +12 -0
- package/dist/internal/format.js +40 -0
- package/dist/internal/kbd.d.ts +6 -0
- package/dist/internal/kbd.js +6 -0
- package/dist/internal/layer.d.ts +21 -0
- package/dist/internal/layer.js +27 -0
- package/dist/internal/line.d.ts +2 -0
- package/dist/internal/line.js +5 -0
- package/dist/internal/overlay.d.ts +2 -0
- package/dist/internal/overlay.js +4 -0
- package/dist/internal/stream-stage.d.ts +18 -0
- package/dist/internal/stream-stage.js +38 -0
- package/dist/internal/stream.d.ts +56 -0
- package/dist/internal/stream.js +112 -0
- package/dist/internal/strings.d.ts +101 -0
- package/dist/internal/strings.js +103 -0
- package/dist/internal/use-controllable.d.ts +5 -0
- package/dist/internal/use-controllable.js +17 -0
- package/package.json +66 -5
- package/styles.css +7 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { CSSProperties } from "react";
|
|
2
|
+
import type { IconName } from "../components/Icon.js";
|
|
3
|
+
/**
|
|
4
|
+
* Raíz de cada componente de Stream: siempre en oscuro. `dark-mode` redefine los tokens en su subárbol (el
|
|
5
|
+
* `data-theme="dark"` del bundle), así que se ve igual dentro de una página clara (`.jm-st` del bundle).
|
|
6
|
+
*/
|
|
7
|
+
export declare const STREAM_ROOT = "dark-mode font-body text-primary antialiased";
|
|
8
|
+
/** Cifras de reloj y contadores: Geist con números tabulares, para que no bailen al cambiar. */
|
|
9
|
+
export declare const TABULAR = "font-body tabular-nums";
|
|
10
|
+
export type StreamMotion = "enter" | "exit";
|
|
11
|
+
/**
|
|
12
|
+
* Entrada y salida, la excepción acotada a "sin animaciones decorativas" (guía, Stream · Movimiento).
|
|
13
|
+
* Entra en 250 ms con fundido y 8px de subida; sale en 200 ms subiendo 8px. Con `prefers-reduced-motion`,
|
|
14
|
+
* solo fundido. Sin keyframes: la entrada es una transición desde `@starting-style` (variante `starting:`), así
|
|
15
|
+
* que se ve al montar el elemento; la salida, una transición al cambiar `state` a `exit`. Curvas del bundle.
|
|
16
|
+
* Con menos movimiento solo se anima `opacity` y el desplazamiento se queda en 0 (sin saltos).
|
|
17
|
+
*/
|
|
18
|
+
export declare function streamMotion(state: StreamMotion | undefined): string | undefined;
|
|
19
|
+
export type StreamEventType = "follow" | "sub" | "resub" | "gift" | "raid" | "bits" | "donation";
|
|
20
|
+
/** Icono y etiqueta de cada tipo de evento, compartidos por StreamAlert y StreamEvents. */
|
|
21
|
+
export declare const STREAM_EVENTS: Record<StreamEventType, {
|
|
22
|
+
icon: IconName;
|
|
23
|
+
label: string;
|
|
24
|
+
}>;
|
|
25
|
+
export interface StreamEventData {
|
|
26
|
+
amount?: number;
|
|
27
|
+
months?: number;
|
|
28
|
+
tier?: number | string;
|
|
29
|
+
}
|
|
30
|
+
/** Texto por defecto de una alerta, con la voz de la suite (`stDetail` del bundle). */
|
|
31
|
+
export declare function streamDetail(type: StreamEventType, e: StreamEventData): string;
|
|
32
|
+
/** Línea corta de un evento en una lista: "Donación · 5,00 €", "Raid entrante · 1.284" (`stShort`). */
|
|
33
|
+
export declare function streamShort(type: StreamEventType, e: StreamEventData): string;
|
|
34
|
+
/**
|
|
35
|
+
* Claves estables para listas que crecen por un extremo (StreamEvents, ChatBox): `id` si lo hay y, si no, el
|
|
36
|
+
* contenido, con un contador para los repetidos. Con la posición como clave, al entrar un elemento nuevo con la
|
|
37
|
+
* lista llena no se monta nada y la entrada (`starting:`) no se ve.
|
|
38
|
+
*/
|
|
39
|
+
export declare function stableKeys<T>(items: T[], content: (item: T) => string): string[];
|
|
40
|
+
/** Texto de un nodo para derivar una clave: solo cadenas y números. */
|
|
41
|
+
export declare const keyText: (node: unknown) => string;
|
|
42
|
+
/** Fecha de StreamCountdown y StreamScene: `Date`, texto ISO o milisegundos. */
|
|
43
|
+
export type StreamTime = Date | string | number;
|
|
44
|
+
/** Segundos que quedan (nunca negativos): hasta `target` desde `now` (o la hora actual), o `seconds`. */
|
|
45
|
+
export declare function secondsLeft(p: {
|
|
46
|
+
seconds?: number;
|
|
47
|
+
target?: StreamTime;
|
|
48
|
+
now?: StreamTime;
|
|
49
|
+
}): number;
|
|
50
|
+
/** `90` → `01:30`; `3725` → `1:02:05` (h:mm:ss si pasa de una hora). */
|
|
51
|
+
export declare function streamClock(total: number): string;
|
|
52
|
+
/**
|
|
53
|
+
* Rejilla de `border-secondary` desvanecida hacia los bordes (`.jm-st-grid` del bundle): StreamScene la usa cada
|
|
54
|
+
* 96px con elipse 70 % × 65 %; ChannelBanner, cada 80px con 80 % × 90 %.
|
|
55
|
+
*/
|
|
56
|
+
export declare function streamGrid(size: number, ellipse: string): CSSProperties;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { formatCurrency, formatNumber } from "./format.js";
|
|
2
|
+
/**
|
|
3
|
+
* Raíz de cada componente de Stream: siempre en oscuro. `dark-mode` redefine los tokens en su subárbol (el
|
|
4
|
+
* `data-theme="dark"` del bundle), así que se ve igual dentro de una página clara (`.jm-st` del bundle).
|
|
5
|
+
*/
|
|
6
|
+
export const STREAM_ROOT = "dark-mode font-body text-primary antialiased";
|
|
7
|
+
/** Cifras de reloj y contadores: Geist con números tabulares, para que no bailen al cambiar. */
|
|
8
|
+
export const TABULAR = "font-body tabular-nums";
|
|
9
|
+
/**
|
|
10
|
+
* Entrada y salida, la excepción acotada a "sin animaciones decorativas" (guía, Stream · Movimiento).
|
|
11
|
+
* Entra en 250 ms con fundido y 8px de subida; sale en 200 ms subiendo 8px. Con `prefers-reduced-motion`,
|
|
12
|
+
* solo fundido. Sin keyframes: la entrada es una transición desde `@starting-style` (variante `starting:`), así
|
|
13
|
+
* que se ve al montar el elemento; la salida, una transición al cambiar `state` a `exit`. Curvas del bundle.
|
|
14
|
+
* Con menos movimiento solo se anima `opacity` y el desplazamiento se queda en 0 (sin saltos).
|
|
15
|
+
*/
|
|
16
|
+
export function streamMotion(state) {
|
|
17
|
+
if (state === "enter")
|
|
18
|
+
return "transition-[opacity,translate] duration-250 ease-[cubic-bezier(.2,.7,.2,1)] starting:translate-y-2 starting:opacity-0 motion-reduce:transition-opacity motion-reduce:starting:translate-y-0";
|
|
19
|
+
if (state === "exit")
|
|
20
|
+
return "-translate-y-2 opacity-0 transition-[opacity,translate] duration-200 ease-in motion-reduce:translate-y-0 motion-reduce:transition-opacity";
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
/** Icono y etiqueta de cada tipo de evento, compartidos por StreamAlert y StreamEvents. */
|
|
24
|
+
export const STREAM_EVENTS = {
|
|
25
|
+
follow: { icon: "user-plus-01", label: "Nuevo seguidor" },
|
|
26
|
+
sub: { icon: "star-01", label: "Nueva suscripción" },
|
|
27
|
+
resub: { icon: "refresh-cw-01", label: "Suscripción renovada" },
|
|
28
|
+
gift: { icon: "stars-02", label: "Suscripciones regaladas" },
|
|
29
|
+
raid: { icon: "users-01", label: "Raid entrante" },
|
|
30
|
+
bits: { icon: "zap", label: "Bits" },
|
|
31
|
+
donation: { icon: "currency-euro", label: "Donación" },
|
|
32
|
+
};
|
|
33
|
+
/** Texto por defecto de una alerta, con la voz de la suite (`stDetail` del bundle). */
|
|
34
|
+
export function streamDetail(type, e) {
|
|
35
|
+
switch (type) {
|
|
36
|
+
case "follow":
|
|
37
|
+
return "Ya no hay vuelta atrás.";
|
|
38
|
+
case "sub":
|
|
39
|
+
return e.tier ? `Suscripción de nivel ${e.tier}.` : "Gracias por el apoyo.";
|
|
40
|
+
case "resub":
|
|
41
|
+
return e.months ? `Lleva ${e.months} meses por aquí.` : "Sigue por aquí.";
|
|
42
|
+
case "gift": {
|
|
43
|
+
const n = e.amount ?? 1;
|
|
44
|
+
return `${formatNumber(n)} ${n === 1 ? "suscripción regalada" : "suscripciones regaladas"} al chat.`;
|
|
45
|
+
}
|
|
46
|
+
case "raid":
|
|
47
|
+
return `${formatNumber(e.amount ?? 0)} espectadores acaban de aterrizar.`;
|
|
48
|
+
case "bits":
|
|
49
|
+
return `${formatNumber(e.amount ?? 0)} bits.`;
|
|
50
|
+
case "donation":
|
|
51
|
+
return typeof e.amount === "number" ? formatCurrency(e.amount) : "";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** Línea corta de un evento en una lista: "Donación · 5,00 €", "Raid entrante · 1.284" (`stShort`). */
|
|
55
|
+
export function streamShort(type, e) {
|
|
56
|
+
let extra = "";
|
|
57
|
+
if (type === "donation" && typeof e.amount === "number")
|
|
58
|
+
extra = formatCurrency(e.amount);
|
|
59
|
+
else if (type === "resub" && e.months)
|
|
60
|
+
extra = `${e.months} meses`;
|
|
61
|
+
else if ((type === "bits" || type === "raid" || type === "gift") && e.amount != null)
|
|
62
|
+
extra = formatNumber(e.amount);
|
|
63
|
+
return STREAM_EVENTS[type].label + (extra ? ` · ${extra}` : "");
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Claves estables para listas que crecen por un extremo (StreamEvents, ChatBox): `id` si lo hay y, si no, el
|
|
67
|
+
* contenido, con un contador para los repetidos. Con la posición como clave, al entrar un elemento nuevo con la
|
|
68
|
+
* lista llena no se monta nada y la entrada (`starting:`) no se ve.
|
|
69
|
+
*/
|
|
70
|
+
export function stableKeys(items, content) {
|
|
71
|
+
const seen = new Map();
|
|
72
|
+
return items.map((it) => {
|
|
73
|
+
const id = it.id;
|
|
74
|
+
const base = id != null ? `id:${id}` : content(it);
|
|
75
|
+
const n = seen.get(base) ?? 0;
|
|
76
|
+
seen.set(base, n + 1);
|
|
77
|
+
return `${base}#${n}`;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/** Texto de un nodo para derivar una clave: solo cadenas y números. */
|
|
81
|
+
export const keyText = (node) => typeof node === "string" || typeof node === "number" ? String(node) : "";
|
|
82
|
+
const ms = (t) => new Date(t).getTime();
|
|
83
|
+
/** Segundos que quedan (nunca negativos): hasta `target` desde `now` (o la hora actual), o `seconds`. */
|
|
84
|
+
export function secondsLeft(p) {
|
|
85
|
+
if (p.target != null)
|
|
86
|
+
return Math.max(0, Math.round((ms(p.target) - (p.now != null ? ms(p.now) : Date.now())) / 1000));
|
|
87
|
+
return Math.max(0, Math.floor(p.seconds ?? 0));
|
|
88
|
+
}
|
|
89
|
+
/** `90` → `01:30`; `3725` → `1:02:05` (h:mm:ss si pasa de una hora). */
|
|
90
|
+
export function streamClock(total) {
|
|
91
|
+
const t = Math.max(0, Math.floor(total));
|
|
92
|
+
const h = Math.floor(t / 3600);
|
|
93
|
+
const m = Math.floor((t % 3600) / 60);
|
|
94
|
+
const s = t % 60;
|
|
95
|
+
const z = (n) => String(n).padStart(2, "0");
|
|
96
|
+
return `${h ? `${h}:${z(m)}` : z(m)}:${z(s)}`;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Rejilla de `border-secondary` desvanecida hacia los bordes (`.jm-st-grid` del bundle): StreamScene la usa cada
|
|
100
|
+
* 96px con elipse 70 % × 65 %; ChannelBanner, cada 80px con 80 % × 90 %.
|
|
101
|
+
*/
|
|
102
|
+
export function streamGrid(size, ellipse) {
|
|
103
|
+
// color-fijo: máscara de desvanecido (solo cuenta el alfa), como BackgroundPattern
|
|
104
|
+
const mask = `radial-gradient(ellipse ${ellipse} at 50% 50%, black, transparent)`;
|
|
105
|
+
return {
|
|
106
|
+
backgroundImage: "linear-gradient(to right, var(--border-secondary) 1px, transparent 1px), linear-gradient(to bottom, var(--border-secondary) 1px, transparent 1px)",
|
|
107
|
+
backgroundSize: `${size}px ${size}px`,
|
|
108
|
+
backgroundPosition: "center",
|
|
109
|
+
maskImage: mask,
|
|
110
|
+
WebkitMaskImage: mask,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export declare const defaultStrings: {
|
|
2
|
+
readonly close: "Cerrar";
|
|
3
|
+
readonly remove: "Quitar";
|
|
4
|
+
readonly online: "En línea";
|
|
5
|
+
readonly offline: "Desconectado";
|
|
6
|
+
readonly loading: "Cargando…";
|
|
7
|
+
readonly previous: "Anterior";
|
|
8
|
+
readonly next: "Siguiente";
|
|
9
|
+
readonly page: "Página";
|
|
10
|
+
readonly pagination: "Paginación";
|
|
11
|
+
readonly breadcrumbs: "Migas de pan";
|
|
12
|
+
readonly mainNav: "Principal";
|
|
13
|
+
readonly logout: "Cerrar sesión";
|
|
14
|
+
readonly view: "Vista";
|
|
15
|
+
readonly options: "Opciones";
|
|
16
|
+
readonly commandMenu: "Menú de comandos";
|
|
17
|
+
readonly searchCommands: "Buscar comandos";
|
|
18
|
+
readonly commandPlaceholder: "Busca o escribe un comando";
|
|
19
|
+
readonly tryAnother: "Prueba con otra palabra.";
|
|
20
|
+
readonly toMove: "moverse";
|
|
21
|
+
readonly toOpen: "abrir";
|
|
22
|
+
readonly toClose: "cerrar";
|
|
23
|
+
readonly dismiss: "Descartar";
|
|
24
|
+
readonly closeNotice: "Cerrar aviso";
|
|
25
|
+
readonly notice: "Aviso";
|
|
26
|
+
readonly yourEmail: "Tu correo";
|
|
27
|
+
readonly subscribe: "Suscribirme";
|
|
28
|
+
readonly moreOptions: "Más opciones";
|
|
29
|
+
readonly rising: "Sube";
|
|
30
|
+
readonly falling: "Baja";
|
|
31
|
+
readonly unread: "Sin leer";
|
|
32
|
+
readonly typing: "Escribiendo";
|
|
33
|
+
readonly you: "Tú";
|
|
34
|
+
readonly copyCode: "Copiar código";
|
|
35
|
+
readonly code: "código";
|
|
36
|
+
readonly weekdaysMin: readonly ["Lu", "Ma", "Mi", "Ju", "Vi", "Sá", "Do"];
|
|
37
|
+
readonly more: "Más acciones";
|
|
38
|
+
readonly search: "Buscar";
|
|
39
|
+
readonly clearAll: "Limpiar todo";
|
|
40
|
+
readonly filters: "Filtros";
|
|
41
|
+
readonly apply: "Aplicar";
|
|
42
|
+
readonly cancel: "Cancelar";
|
|
43
|
+
readonly send: "Enviar";
|
|
44
|
+
readonly message: "Mensaje";
|
|
45
|
+
readonly writeMessage: "Escribe un mensaje";
|
|
46
|
+
readonly savedColors: "Colores guardados";
|
|
47
|
+
readonly hex: "Hex";
|
|
48
|
+
readonly hue: "Tono";
|
|
49
|
+
readonly formatting: "Formato";
|
|
50
|
+
readonly bold: "Negrita";
|
|
51
|
+
readonly italic: "Cursiva";
|
|
52
|
+
readonly underline: "Subrayado";
|
|
53
|
+
readonly list: "Lista";
|
|
54
|
+
readonly link: "Enlace";
|
|
55
|
+
readonly linkPrompt: "Dirección del enlace";
|
|
56
|
+
readonly alignLeft: "Alinear a la izquierda";
|
|
57
|
+
readonly alignCenter: "Centrar";
|
|
58
|
+
readonly alignRight: "Alinear a la derecha";
|
|
59
|
+
readonly writeHere: "Escribe aquí…";
|
|
60
|
+
readonly text: "Texto";
|
|
61
|
+
readonly attach: "Adjuntar archivo";
|
|
62
|
+
readonly copy: "Copiar";
|
|
63
|
+
readonly copied: "Copiado";
|
|
64
|
+
readonly today: "Hoy";
|
|
65
|
+
readonly pickDate: "Elegir fecha";
|
|
66
|
+
readonly pickDates: "Elegir fechas";
|
|
67
|
+
readonly datePicker: "Selector de fecha";
|
|
68
|
+
readonly calendar: "Calendario";
|
|
69
|
+
readonly previousMonth: "Mes anterior";
|
|
70
|
+
readonly nextMonth: "Mes siguiente";
|
|
71
|
+
readonly noResults: "Sin resultados";
|
|
72
|
+
readonly required: "obligatorio";
|
|
73
|
+
readonly upload: "Haz clic para subir";
|
|
74
|
+
readonly orDrag: "o arrastra y suelta";
|
|
75
|
+
readonly uploadComplete: "Completado";
|
|
76
|
+
readonly uploading: "Subiendo…";
|
|
77
|
+
readonly uploadFailed: "No se pudo subir";
|
|
78
|
+
readonly play: "Reproducir";
|
|
79
|
+
readonly pause: "Pausar";
|
|
80
|
+
readonly mute: "Silenciar";
|
|
81
|
+
readonly unmute: "Activar sonido";
|
|
82
|
+
readonly fullscreen: "Pantalla completa";
|
|
83
|
+
readonly removeFile: (name: string) => string;
|
|
84
|
+
readonly uploadProgress: (name: string) => string;
|
|
85
|
+
readonly showMore: (n: number) => string;
|
|
86
|
+
readonly streamLive: "En directo";
|
|
87
|
+
readonly streamRerun: "Reemisión";
|
|
88
|
+
readonly streamOffline: "Sin directo";
|
|
89
|
+
readonly viewers: "espectadores";
|
|
90
|
+
readonly onAir: "en emisión";
|
|
91
|
+
readonly latestEvents: "Últimos eventos";
|
|
92
|
+
readonly streamChat: "Chat del directo";
|
|
93
|
+
readonly goal: "Meta";
|
|
94
|
+
readonly goalDone: "Meta conseguida. Toca poner otra.";
|
|
95
|
+
readonly goalRemaining: (missing: string) => string;
|
|
96
|
+
readonly nowPlaying: "Suena ahora";
|
|
97
|
+
readonly paused: "En pausa";
|
|
98
|
+
readonly songProgress: "Progreso de la canción";
|
|
99
|
+
readonly charactersLeft: (n: number) => string;
|
|
100
|
+
};
|
|
101
|
+
export type Strings = typeof defaultStrings;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// Textos que traen los componentes. Castellano de España, tuteo, mayúscula solo al principio.
|
|
2
|
+
// Cada componente acepta por props el texto que quieras poner en su lugar.
|
|
3
|
+
export const defaultStrings = {
|
|
4
|
+
close: "Cerrar",
|
|
5
|
+
remove: "Quitar",
|
|
6
|
+
online: "En línea",
|
|
7
|
+
offline: "Desconectado",
|
|
8
|
+
loading: "Cargando…",
|
|
9
|
+
previous: "Anterior",
|
|
10
|
+
next: "Siguiente",
|
|
11
|
+
page: "Página",
|
|
12
|
+
pagination: "Paginación",
|
|
13
|
+
breadcrumbs: "Migas de pan",
|
|
14
|
+
mainNav: "Principal",
|
|
15
|
+
logout: "Cerrar sesión",
|
|
16
|
+
view: "Vista",
|
|
17
|
+
options: "Opciones",
|
|
18
|
+
commandMenu: "Menú de comandos",
|
|
19
|
+
searchCommands: "Buscar comandos",
|
|
20
|
+
commandPlaceholder: "Busca o escribe un comando",
|
|
21
|
+
tryAnother: "Prueba con otra palabra.",
|
|
22
|
+
toMove: "moverse",
|
|
23
|
+
toOpen: "abrir",
|
|
24
|
+
toClose: "cerrar",
|
|
25
|
+
dismiss: "Descartar",
|
|
26
|
+
closeNotice: "Cerrar aviso",
|
|
27
|
+
notice: "Aviso",
|
|
28
|
+
yourEmail: "Tu correo",
|
|
29
|
+
subscribe: "Suscribirme",
|
|
30
|
+
moreOptions: "Más opciones",
|
|
31
|
+
rising: "Sube",
|
|
32
|
+
falling: "Baja",
|
|
33
|
+
unread: "Sin leer",
|
|
34
|
+
typing: "Escribiendo",
|
|
35
|
+
you: "Tú",
|
|
36
|
+
copyCode: "Copiar código",
|
|
37
|
+
code: "código",
|
|
38
|
+
weekdaysMin: ["Lu", "Ma", "Mi", "Ju", "Vi", "Sá", "Do"],
|
|
39
|
+
more: "Más acciones",
|
|
40
|
+
search: "Buscar",
|
|
41
|
+
clearAll: "Limpiar todo",
|
|
42
|
+
filters: "Filtros",
|
|
43
|
+
apply: "Aplicar",
|
|
44
|
+
cancel: "Cancelar",
|
|
45
|
+
send: "Enviar",
|
|
46
|
+
message: "Mensaje",
|
|
47
|
+
writeMessage: "Escribe un mensaje",
|
|
48
|
+
savedColors: "Colores guardados",
|
|
49
|
+
hex: "Hex",
|
|
50
|
+
hue: "Tono",
|
|
51
|
+
formatting: "Formato",
|
|
52
|
+
bold: "Negrita",
|
|
53
|
+
italic: "Cursiva",
|
|
54
|
+
underline: "Subrayado",
|
|
55
|
+
list: "Lista",
|
|
56
|
+
link: "Enlace",
|
|
57
|
+
linkPrompt: "Dirección del enlace",
|
|
58
|
+
alignLeft: "Alinear a la izquierda",
|
|
59
|
+
alignCenter: "Centrar",
|
|
60
|
+
alignRight: "Alinear a la derecha",
|
|
61
|
+
writeHere: "Escribe aquí…",
|
|
62
|
+
text: "Texto",
|
|
63
|
+
attach: "Adjuntar archivo",
|
|
64
|
+
copy: "Copiar",
|
|
65
|
+
copied: "Copiado",
|
|
66
|
+
today: "Hoy",
|
|
67
|
+
pickDate: "Elegir fecha",
|
|
68
|
+
pickDates: "Elegir fechas",
|
|
69
|
+
datePicker: "Selector de fecha",
|
|
70
|
+
calendar: "Calendario",
|
|
71
|
+
previousMonth: "Mes anterior",
|
|
72
|
+
nextMonth: "Mes siguiente",
|
|
73
|
+
noResults: "Sin resultados",
|
|
74
|
+
required: "obligatorio",
|
|
75
|
+
upload: "Haz clic para subir",
|
|
76
|
+
orDrag: "o arrastra y suelta",
|
|
77
|
+
uploadComplete: "Completado",
|
|
78
|
+
uploading: "Subiendo…",
|
|
79
|
+
uploadFailed: "No se pudo subir",
|
|
80
|
+
play: "Reproducir",
|
|
81
|
+
pause: "Pausar",
|
|
82
|
+
mute: "Silenciar",
|
|
83
|
+
unmute: "Activar sonido",
|
|
84
|
+
fullscreen: "Pantalla completa",
|
|
85
|
+
removeFile: (name) => `Quitar ${name}`,
|
|
86
|
+
uploadProgress: (name) => `Progreso de ${name}`,
|
|
87
|
+
showMore: (n) => `${n} más…`,
|
|
88
|
+
streamLive: "En directo",
|
|
89
|
+
streamRerun: "Reemisión",
|
|
90
|
+
streamOffline: "Sin directo",
|
|
91
|
+
viewers: "espectadores",
|
|
92
|
+
onAir: "en emisión",
|
|
93
|
+
latestEvents: "Últimos eventos",
|
|
94
|
+
streamChat: "Chat del directo",
|
|
95
|
+
goal: "Meta",
|
|
96
|
+
goalDone: "Meta conseguida. Toca poner otra.",
|
|
97
|
+
goalRemaining: (missing) => `Faltan ${missing} para la meta.`,
|
|
98
|
+
nowPlaying: "Suena ahora",
|
|
99
|
+
paused: "En pausa",
|
|
100
|
+
songProgress: "Progreso de la canción",
|
|
101
|
+
// Como en la vista previa de TextEditor: "421 caracteres restantes"
|
|
102
|
+
charactersLeft: (n) => (n === 1 ? "1 carácter restante" : `${n} caracteres restantes`),
|
|
103
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Estado controlado o no controlado, como un `<input>`: si llega `value`, manda el padre;
|
|
3
|
+
* si no, el componente guarda el suyo empezando por `defaultValue`.
|
|
4
|
+
*/
|
|
5
|
+
export declare function useControllable<T>(value: T | undefined, defaultValue: T, onChange?: (next: T) => void): [T, (next: T) => void];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useCallback, useRef, useState } from "react";
|
|
3
|
+
/**
|
|
4
|
+
* Estado controlado o no controlado, como un `<input>`: si llega `value`, manda el padre;
|
|
5
|
+
* si no, el componente guarda el suyo empezando por `defaultValue`.
|
|
6
|
+
*/
|
|
7
|
+
export function useControllable(value, defaultValue, onChange) {
|
|
8
|
+
const [inner, setInner] = useState(defaultValue);
|
|
9
|
+
const controlled = useRef(value !== undefined).current;
|
|
10
|
+
const current = controlled ? value : inner;
|
|
11
|
+
const set = useCallback((next) => {
|
|
12
|
+
if (!controlled)
|
|
13
|
+
setInner(next);
|
|
14
|
+
onChange?.(next);
|
|
15
|
+
}, [controlled, onChange]);
|
|
16
|
+
return [current, set];
|
|
17
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,67 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@jotis-me/react",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Componentes React de la suite jotis.me para Next.js y Astro, con Tailwind CSS v4.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Jotis1/regula.git",
|
|
10
|
+
"directory": "packages/react"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://regula.jotis.me",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"styles.css"
|
|
16
|
+
],
|
|
17
|
+
"sideEffects": [
|
|
18
|
+
"**/*.css"
|
|
19
|
+
],
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"default": "./dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./styles.css": "./styles.css",
|
|
28
|
+
"./package.json": "./package.json"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc -p tsconfig.build.json",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"typecheck": "tsc --noEmit",
|
|
34
|
+
"check:colors": "bun run scripts/check-colors.ts src",
|
|
35
|
+
"check:package": "publint && attw --pack . --profile esm-only --exclude-entrypoints ./styles.css",
|
|
36
|
+
"check:size": "bun run scripts/check-size.ts"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@internationalized/date": "^3.12.4",
|
|
40
|
+
"@jotis-me/icons": "0.2.0",
|
|
41
|
+
"@jotis-me/tokens": "0.2.0",
|
|
42
|
+
"clsx": "^2.1.1",
|
|
43
|
+
"react-aria-components": "^1.22.1",
|
|
44
|
+
"tailwind-merge": "^3.7.0"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"react": "^19.3.1",
|
|
48
|
+
"react-dom": "^19.3.1",
|
|
49
|
+
"tailwindcss": "^4.3.3"
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
56
|
+
"@tailwindcss/node": "^4.3.3",
|
|
57
|
+
"@testing-library/react": "^16.3.3",
|
|
58
|
+
"@testing-library/user-event": "^14.6.8",
|
|
59
|
+
"@types/node": "^26.6.6",
|
|
60
|
+
"@types/react": "^19.3.0",
|
|
61
|
+
"@types/react-dom": "^19.3.0",
|
|
62
|
+
"axe-core": "^4.14.0",
|
|
63
|
+
"jsdom": "^30.1.3",
|
|
64
|
+
"publint": "^0.3.25",
|
|
65
|
+
"vitest": "^5"
|
|
66
|
+
}
|
|
67
|
+
}
|
package/styles.css
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/* Importa esto después de `@import "tailwindcss";` en la hoja principal de la app. */
|
|
2
|
+
@import "@jotis-me/tokens/fonts.css";
|
|
3
|
+
@import "@jotis-me/tokens/tokens.css";
|
|
4
|
+
@import "@jotis-me/tokens/theme.css";
|
|
5
|
+
|
|
6
|
+
/* Que el Tailwind de la app genere también las clases que usan los componentes */
|
|
7
|
+
@source "./dist";
|