danielgm-ui 0.4.1 → 0.4.3
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/dist/context-menu.d.ts +3 -1
- package/dist/context-menu.js +4 -3
- package/dist/data-table.d.ts +3 -1
- package/dist/data-table.js +2 -2
- package/dist/dropdown-menu.d.ts +5 -1
- package/dist/dropdown-menu.js +4 -3
- package/dist/internal/menu-item-focus.d.ts +5 -0
- package/dist/internal/menu-item-focus.js +11 -0
- package/dist/navigation-menu.d.ts +3 -1
- package/dist/navigation-menu.js +2 -2
- package/dist/slider.d.ts +2 -0
- package/dist/slider.js +11 -3
- package/dist/styles.css +38 -14
- package/package.json +1 -1
package/dist/context-menu.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export interface ContextMenuProps {
|
|
|
8
8
|
children: ReactElement;
|
|
9
9
|
/** Acciones y separadores con IDs únicos. Los atajos son leyendas, no se registran. */
|
|
10
10
|
items: readonly ContextMenuItem[];
|
|
11
|
+
/** Apariencia de las opciones; no modifica el panel. @defaultValue 'default' */
|
|
12
|
+
itemVariant?: 'default' | 'ghost';
|
|
11
13
|
/** Encabezado visible y nombre accesible del menú. */
|
|
12
14
|
label: string;
|
|
13
15
|
/** Desactiva únicamente el menú personalizado y conserva el menú nativo. @defaultValue false */
|
|
@@ -18,4 +20,4 @@ export interface ContextMenuProps {
|
|
|
18
20
|
className?: string;
|
|
19
21
|
}
|
|
20
22
|
/** Clic derecho, pulsación prolongada o Shift+F10. El clic izquierdo conserva la acción del hijo. */
|
|
21
|
-
export declare function ContextMenu({ children, items, label, disabled, onOpenChange, className, }: ContextMenuProps): ReactElement;
|
|
23
|
+
export declare function ContextMenu({ children, items, itemVariant, label, disabled, onOpenChange, className, }: ContextMenuProps): ReactElement;
|
package/dist/context-menu.js
CHANGED
|
@@ -3,11 +3,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
/** Menú contextual sobre una zona concreta. Radix gestiona el anclaje al puntero y la navegación. */
|
|
4
4
|
import { useId, useRef, useState } from 'react';
|
|
5
5
|
import * as Primitive from '@radix-ui/react-context-menu';
|
|
6
|
+
import { menuItemFocusProps } from './internal/menu-item-focus.js';
|
|
6
7
|
import { restoreFocus } from './internal/focus.js';
|
|
7
8
|
import { OverlayLayerProvider, useOverlayLayer } from './internal/overlay-layer.js';
|
|
8
9
|
import { cx } from './utils.js';
|
|
9
10
|
/** Clic derecho, pulsación prolongada o Shift+F10. El clic izquierdo conserva la acción del hijo. */
|
|
10
|
-
export function ContextMenu({ children, items, label, disabled = false, onOpenChange, className, }) {
|
|
11
|
+
export function ContextMenu({ children, items, itemVariant = 'default', label, disabled = false, onOpenChange, className, }) {
|
|
11
12
|
const { depth, style: layerStyle } = useOverlayLayer();
|
|
12
13
|
const trigger = useRef(null);
|
|
13
14
|
const outside = useRef(false);
|
|
@@ -34,7 +35,7 @@ export function ContextMenu({ children, items, label, disabled = false, onOpenCh
|
|
|
34
35
|
clientX: rect.left + 8,
|
|
35
36
|
clientY: rect.bottom,
|
|
36
37
|
}));
|
|
37
|
-
}, children: children }), _jsx(Primitive.Portal, { children: _jsxs(Primitive.Content, { style: layerStyle, id: menuId, "aria-label": label, collisionPadding: 12, className: cx('dgm-dropdown', 'dgm-context-menu', className), onContextMenu: (event) => {
|
|
38
|
+
}, children: children }), _jsx(Primitive.Portal, { children: _jsxs(Primitive.Content, { ...menuItemFocusProps, style: layerStyle, id: menuId, "aria-label": label, collisionPadding: 12, className: cx('dgm-dropdown', 'dgm-context-menu', className), onContextMenu: (event) => {
|
|
38
39
|
// El panel ya es el menú contextual: evita superponer el del navegador
|
|
39
40
|
// o propagar el gesto a otra zona contextual a través del portal.
|
|
40
41
|
event.preventDefault();
|
|
@@ -46,5 +47,5 @@ export function ContextMenu({ children, items, label, disabled = false, onOpenCh
|
|
|
46
47
|
if (!outside.current && trigger.current?.isConnected)
|
|
47
48
|
restoreFocus(trigger.current);
|
|
48
49
|
outside.current = false;
|
|
49
|
-
}, children: [_jsx(Primitive.Label, { className: "dgm-dropdown-label", children: label }), items.map((item) => item.type === 'separator' ? (_jsx(Primitive.Separator, { className: "dgm-dropdown-separator" }, item.id)) : (_jsxs(Primitive.Item, { textValue: item.label, disabled: item.disabled, onSelect: item.onSelect, className: cx('dgm-dropdown-item', item.danger && 'dgm-dropdown-item--danger'), children: [item.icon && (_jsx("span", { className: "dgm-option-icon", "aria-hidden": "true", children: item.icon })), _jsx("span", { className: "dgm-dropdown-text", children: item.label }), item.shortcut && (_jsx("span", { className: "dgm-dropdown-shortcut", "aria-hidden": "true", children: item.shortcut }))] }, item.id)))] }) })] }) }));
|
|
50
|
+
}, children: [_jsx(Primitive.Label, { className: "dgm-dropdown-label", children: label }), items.map((item) => item.type === 'separator' ? (_jsx(Primitive.Separator, { className: "dgm-dropdown-separator" }, item.id)) : (_jsxs(Primitive.Item, { textValue: item.label, disabled: item.disabled, onSelect: item.onSelect, className: cx('dgm-dropdown-item', (item.variant ?? itemVariant) === 'ghost' && 'dgm-dropdown-item--ghost', item.danger && 'dgm-dropdown-item--danger'), children: [item.icon && (_jsx("span", { className: "dgm-option-icon", "aria-hidden": "true", children: item.icon })), _jsx("span", { className: "dgm-dropdown-text", children: item.label }), item.shortcut && (_jsx("span", { className: "dgm-dropdown-shortcut", "aria-hidden": "true", children: item.shortcut }))] }, item.id)))] }) })] }) }));
|
|
50
51
|
}
|
package/dist/data-table.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export interface DataTableProps<T extends object> {
|
|
|
40
40
|
searchPlaceholder?: string;
|
|
41
41
|
/** Registros por página. @defaultValue 10 */
|
|
42
42
|
pageSize?: number;
|
|
43
|
+
/** Oculta solo los controles con cero o una página de resultados filtrados. @defaultValue false */
|
|
44
|
+
hidePaginationOnSinglePage?: boolean;
|
|
43
45
|
/** Página controlada, comenzando en 1. */
|
|
44
46
|
page?: number;
|
|
45
47
|
onPageChange?: (page: number) => void;
|
|
@@ -56,4 +58,4 @@ export interface DataTableProps<T extends object> {
|
|
|
56
58
|
className?: string;
|
|
57
59
|
}
|
|
58
60
|
/** Paginación y selección conservan IDs reales. El filtrado devuelve a la primera página. */
|
|
59
|
-
export declare function DataTable<T extends object>({ data, columns, getRowId, caption, sorting, sortable, manualSorting, defaultSorting, onSortingChange, searchable, searchPlaceholder, pageSize, page, onPageChange, selectable, selection, defaultSelection, onSelectionChange, loading, emptyMessage, locale, className, }: DataTableProps<T>): ReactElement;
|
|
61
|
+
export declare function DataTable<T extends object>({ data, columns, getRowId, caption, sorting, sortable, manualSorting, defaultSorting, onSortingChange, searchable, searchPlaceholder, pageSize, hidePaginationOnSinglePage, page, onPageChange, selectable, selection, defaultSelection, onSelectionChange, loading, emptyMessage, locale, className, }: DataTableProps<T>): ReactElement;
|
package/dist/data-table.js
CHANGED
|
@@ -20,7 +20,7 @@ const features = tableFeatures({
|
|
|
20
20
|
filterFns: { includesString: filterFn_includesString },
|
|
21
21
|
});
|
|
22
22
|
/** Paginación y selección conservan IDs reales. El filtrado devuelve a la primera página. */
|
|
23
|
-
export function DataTable({ data, columns, getRowId, caption, sorting, sortable = true, manualSorting = false, defaultSorting = [], onSortingChange, searchable = true, searchPlaceholder, pageSize = 10, page, onPageChange, selectable = false, selection, defaultSelection = [], onSelectionChange, loading = false, emptyMessage, locale = 'en', className, }) {
|
|
23
|
+
export function DataTable({ data, columns, getRowId, caption, sorting, sortable = true, manualSorting = false, defaultSorting = [], onSortingChange, searchable = true, searchPlaceholder, pageSize = 10, hidePaginationOnSinglePage = false, page, onPageChange, selectable = false, selection, defaultSelection = [], onSelectionChange, loading = false, emptyMessage, locale = 'en', className, }) {
|
|
24
24
|
const [sort, changeSort] = useControllable(sorting, defaultSorting, onSortingChange);
|
|
25
25
|
const [currentPage, changePage] = useControllable(page, 1, onPageChange);
|
|
26
26
|
const [selected, changeSelection] = useControllable(selection, defaultSelection, onSelectionChange ? (next) => onSelectionChange([...next]) : undefined);
|
|
@@ -117,5 +117,5 @@ export function DataTable({ data, columns, getRowId, caption, sorting, sortable
|
|
|
117
117
|
? es
|
|
118
118
|
? 'Cargando…'
|
|
119
119
|
: 'Loading…'
|
|
120
|
-
: `${filtered.length} ${es ? 'resultados' : 'results'}${selectable ? ` · ${selectedCount} ${es ? 'seleccionados' : 'selected'}` : ''}` }), _jsx(Pagination, { page: current, pageCount: pageCount, onPageChange: changePage, disabled: loading, locale: locale })] })] }));
|
|
120
|
+
: `${filtered.length} ${es ? 'resultados' : 'results'}${selectable ? ` · ${selectedCount} ${es ? 'seleccionados' : 'selected'}` : ''}` }), (!hidePaginationOnSinglePage || pageCount > 1) && (_jsx(Pagination, { page: current, pageCount: pageCount, onPageChange: changePage, disabled: loading, locale: locale }))] })] }));
|
|
121
121
|
}
|
package/dist/dropdown-menu.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export type DropdownMenuItem = {
|
|
|
14
14
|
/** Leyenda visual: no registra por sí misma un atajo de teclado. */
|
|
15
15
|
shortcut?: string;
|
|
16
16
|
disabled?: boolean;
|
|
17
|
+
/** Apariencia de esta opción; hereda itemVariant del menú. */
|
|
18
|
+
variant?: 'default' | 'ghost';
|
|
17
19
|
/** Resalta acciones destructivas sin ejecutarlas automáticamente. */
|
|
18
20
|
danger?: boolean;
|
|
19
21
|
/** Se ejecuta con puntero o teclado. preventDefault mantiene abierto el menú. */
|
|
@@ -24,6 +26,8 @@ export interface DropdownMenuProps {
|
|
|
24
26
|
children: ReactElement;
|
|
25
27
|
/** Acciones y separadores en orden de lectura. IDs únicos. */
|
|
26
28
|
items: readonly DropdownMenuItem[];
|
|
29
|
+
/** Apariencia de las opciones; no modifica el panel. @defaultValue 'default' */
|
|
30
|
+
itemVariant?: 'default' | 'ghost';
|
|
27
31
|
/** Encabezado opcional del menú. */
|
|
28
32
|
label?: string;
|
|
29
33
|
/** Apertura controlada, junto con onOpenChange. */
|
|
@@ -44,4 +48,4 @@ export interface DropdownMenuProps {
|
|
|
44
48
|
className?: string;
|
|
45
49
|
}
|
|
46
50
|
/** El menú no bloquea el scroll de la página y devuelve el foco sin desplazarla. */
|
|
47
|
-
export declare function DropdownMenu({ children, items, label, open, defaultOpen, onOpenChange, side, align, sideOffset, disabled, className, }: DropdownMenuProps): ReactElement;
|
|
51
|
+
export declare function DropdownMenu({ children, items, itemVariant, label, open, defaultOpen, onOpenChange, side, align, sideOffset, disabled, className, }: DropdownMenuProps): ReactElement;
|
package/dist/dropdown-menu.js
CHANGED
|
@@ -3,15 +3,16 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
/** Menú de acciones: Radix gestiona teclado, búsqueda por letras, portal y foco. */
|
|
4
4
|
import { useRef } from 'react';
|
|
5
5
|
import * as Primitive from '@radix-ui/react-dropdown-menu';
|
|
6
|
+
import { menuItemFocusProps } from './internal/menu-item-focus.js';
|
|
6
7
|
import { restoreFocus } from './internal/focus.js';
|
|
7
8
|
import { OverlayLayerProvider, useOverlayLayer } from './internal/overlay-layer.js';
|
|
8
9
|
import { cx } from './utils.js';
|
|
9
10
|
/** El menú no bloquea el scroll de la página y devuelve el foco sin desplazarla. */
|
|
10
|
-
export function DropdownMenu({ children, items, label, open, defaultOpen, onOpenChange, side = 'bottom', align = 'start', sideOffset = 6, disabled, className, }) {
|
|
11
|
+
export function DropdownMenu({ children, items, itemVariant = 'default', label, open, defaultOpen, onOpenChange, side = 'bottom', align = 'start', sideOffset = 6, disabled, className, }) {
|
|
11
12
|
const { depth, style: layerStyle } = useOverlayLayer();
|
|
12
13
|
const trigger = useRef(null);
|
|
13
14
|
const interactedOutside = useRef(false);
|
|
14
|
-
return (_jsx(OverlayLayerProvider, { depth: depth, children: _jsxs(Primitive.Root, { open: open, defaultOpen: defaultOpen, onOpenChange: onOpenChange, modal: false, children: [_jsx(Primitive.Trigger, { asChild: true, ref: trigger, disabled: disabled, children: children }), _jsx(Primitive.Portal, { children: _jsxs(Primitive.Content, { style: layerStyle, side: side, align: align, sideOffset: sideOffset, collisionPadding: 12, className: cx('dgm-dropdown', className), onInteractOutside: () => {
|
|
15
|
+
return (_jsx(OverlayLayerProvider, { depth: depth, children: _jsxs(Primitive.Root, { open: open, defaultOpen: defaultOpen, onOpenChange: onOpenChange, modal: false, children: [_jsx(Primitive.Trigger, { asChild: true, ref: trigger, disabled: disabled, children: children }), _jsx(Primitive.Portal, { children: _jsxs(Primitive.Content, { ...menuItemFocusProps, style: layerStyle, side: side, align: align, sideOffset: sideOffset, collisionPadding: 12, className: cx('dgm-dropdown', className), onInteractOutside: () => {
|
|
15
16
|
interactedOutside.current = true;
|
|
16
17
|
}, onCloseAutoFocus: (event) => {
|
|
17
18
|
// Un clic fuera conserva su destino; Escape o una acción vuelven al botón.
|
|
@@ -20,5 +21,5 @@ export function DropdownMenu({ children, items, label, open, defaultOpen, onOpen
|
|
|
20
21
|
restoreFocus(trigger.current);
|
|
21
22
|
}
|
|
22
23
|
interactedOutside.current = false;
|
|
23
|
-
}, children: [label && _jsx(Primitive.Label, { className: "dgm-dropdown-label", children: label }), items.map((item) => item.type === 'separator' ? (_jsx(Primitive.Separator, { className: "dgm-dropdown-separator" }, item.id)) : (_jsxs(Primitive.Item, { textValue: item.label, disabled: item.disabled, onSelect: item.onSelect, className: cx('dgm-dropdown-item', item.danger && 'dgm-dropdown-item--danger'), children: [item.icon && (_jsx("span", { className: "dgm-option-icon", "aria-hidden": "true", children: item.icon })), _jsx("span", { className: "dgm-dropdown-text", children: item.label }), item.shortcut && (_jsx("span", { className: "dgm-dropdown-shortcut", "aria-hidden": "true", children: item.shortcut }))] }, item.id)))] }) })] }) }));
|
|
24
|
+
}, children: [label && _jsx(Primitive.Label, { className: "dgm-dropdown-label", children: label }), items.map((item) => item.type === 'separator' ? (_jsx(Primitive.Separator, { className: "dgm-dropdown-separator" }, item.id)) : (_jsxs(Primitive.Item, { textValue: item.label, disabled: item.disabled, onSelect: item.onSelect, className: cx('dgm-dropdown-item', (item.variant ?? itemVariant) === 'ghost' && 'dgm-dropdown-item--ghost', item.danger && 'dgm-dropdown-item--danger'), children: [item.icon && (_jsx("span", { className: "dgm-option-icon", "aria-hidden": "true", children: item.icon })), _jsx("span", { className: "dgm-dropdown-text", children: item.label }), item.shortcut && (_jsx("span", { className: "dgm-dropdown-shortcut", "aria-hidden": "true", children: item.shortcut }))] }, item.id)))] }) })] }) }));
|
|
24
25
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const menuItemFocusProps: {
|
|
2
|
+
onPointerMoveCapture(event: import("react").PointerEvent<HTMLDivElement>): void;
|
|
3
|
+
onPointerDownCapture(event: import("react").PointerEvent<HTMLDivElement>): void;
|
|
4
|
+
onKeyDownCapture(event: import("react").KeyboardEvent<HTMLDivElement>): void;
|
|
5
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const menuItemFocusProps = {
|
|
2
|
+
onPointerMoveCapture(event) {
|
|
3
|
+
event.currentTarget.dataset.inputMode = 'pointer';
|
|
4
|
+
},
|
|
5
|
+
onPointerDownCapture(event) {
|
|
6
|
+
event.currentTarget.dataset.inputMode = 'pointer';
|
|
7
|
+
},
|
|
8
|
+
onKeyDownCapture(event) {
|
|
9
|
+
event.currentTarget.dataset.inputMode = 'keyboard';
|
|
10
|
+
},
|
|
11
|
+
};
|
|
@@ -17,10 +17,12 @@ export interface NavigationMenuProps {
|
|
|
17
17
|
items: readonly NavigationMenuItem[];
|
|
18
18
|
/** href activo exacto; el consumidor conoce la ruta actual. */
|
|
19
19
|
currentHref?: string;
|
|
20
|
+
/** Apariencia de enlaces y disparadores. @defaultValue 'default' */
|
|
21
|
+
variant?: 'default' | 'ghost';
|
|
20
22
|
/** Adaptador para routers: devuelve un único enlace que acepte props y ref. */
|
|
21
23
|
renderLink?: (item: NavigationLink) => ReactElement;
|
|
22
24
|
delayDuration?: number;
|
|
23
25
|
className?: string;
|
|
24
26
|
}
|
|
25
27
|
/** En móvil los elementos se distribuyen en filas y los paneles permanecen dentro del ancho disponible. */
|
|
26
|
-
export declare function NavigationMenu({ label, items, currentHref, renderLink, delayDuration, className, }: NavigationMenuProps): ReactElement;
|
|
28
|
+
export declare function NavigationMenu({ label, items, currentHref, variant, renderLink, delayDuration, className, }: NavigationMenuProps): ReactElement;
|
package/dist/navigation-menu.js
CHANGED
|
@@ -18,10 +18,10 @@ function NavigationPanel({ label, children }) {
|
|
|
18
18
|
return (_jsxs(_Fragment, { children: [_jsxs(Primitive.Trigger, { ref: trigger, className: "dgm-navigation-trigger", children: [label, _jsx(ChevronIcon, {})] }), _jsx(Primitive.Content, { ref: contentRef, className: "dgm-navigation-content", children: children })] }));
|
|
19
19
|
}
|
|
20
20
|
/** En móvil los elementos se distribuyen en filas y los paneles permanecen dentro del ancho disponible. */
|
|
21
|
-
export function NavigationMenu({ label, items, currentHref, renderLink, delayDuration = 150, className, }) {
|
|
21
|
+
export function NavigationMenu({ label, items, currentHref, variant = 'default', renderLink, delayDuration = 150, className, }) {
|
|
22
22
|
function link(item) {
|
|
23
23
|
const active = currentHref === item.href;
|
|
24
24
|
return (_jsx(Primitive.Link, { asChild: true, active: active, "aria-current": active ? 'page' : undefined, className: "dgm-navigation-link", children: renderLink ? (renderLink(item)) : (_jsxs("a", { href: item.href, children: [item.icon && _jsx("span", { "aria-hidden": "true", children: item.icon }), _jsxs("span", { children: [item.label, item.description && _jsx("small", { children: item.description })] })] })) }, item.id));
|
|
25
25
|
}
|
|
26
|
-
return (_jsx(Primitive.Root, { "aria-label": label, delayDuration: delayDuration, className: cx('dgm-navigation', className), children: _jsx(Primitive.List, { className: "dgm-navigation-list", children: items.map((item) => (_jsx(Primitive.Item, { className: "dgm-navigation-item", children: 'items' in item ? (_jsx(NavigationPanel, { label: item.label, children: _jsx("ul", { children: item.items.map((child) => (_jsx("li", { children: link(child) }, child.id))) }) })) : (link(item)) }, item.id))) }) }));
|
|
26
|
+
return (_jsx(Primitive.Root, { "aria-label": label, delayDuration: delayDuration, className: cx('dgm-navigation', `dgm-navigation--${variant}`, className), children: _jsx(Primitive.List, { className: "dgm-navigation-list", children: items.map((item) => (_jsx(Primitive.Item, { className: "dgm-navigation-item", children: 'items' in item ? (_jsx(NavigationPanel, { label: item.label, children: _jsx("ul", { children: item.items.map((child) => (_jsx("li", { children: link(child) }, child.id))) }) })) : (link(item)) }, item.id))) }) }));
|
|
27
27
|
}
|
package/dist/slider.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export interface SliderBaseProps {
|
|
|
10
10
|
step?: number;
|
|
11
11
|
disabled?: boolean;
|
|
12
12
|
name?: string;
|
|
13
|
+
/** Visibilidad visual de los extremos en Slider y RangeSlider; conserva foco y accesibilidad. @defaultValue 'always' */
|
|
14
|
+
thumbVisibility?: 'always' | 'interaction';
|
|
13
15
|
/** Valor visible y aria-valuetext; útil para porcentajes, unidades o precios. */
|
|
14
16
|
formatValue?: (value: number) => string;
|
|
15
17
|
/** Marcas informativas, sin interacción propia. Deben estar entre min y max. */
|
package/dist/slider.js
CHANGED
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
/** Radix mantiene teclado, gestos táctiles y valores de formulario; la librería aporta etiquetas y estilo. */
|
|
4
|
-
import { useId } from 'react';
|
|
4
|
+
import { useId, useState, useEffect } from 'react';
|
|
5
5
|
import * as Primitive from '@radix-ui/react-slider';
|
|
6
6
|
import { useControllable } from './internal/state.js';
|
|
7
7
|
import { cx, hasContent } from './utils.js';
|
|
8
8
|
/** Infraestructura interna; cada API pública mantiene un número fijo de controles. */
|
|
9
|
-
function SliderControl({ label, description, error, min = 0, max = 100, step = 1, disabled, name, formatValue = String, marks = [], className, id, values, change, commit, thumbLabels, }) {
|
|
9
|
+
function SliderControl({ label, description, error, min = 0, max = 100, step = 1, disabled, name, thumbVisibility = 'always', formatValue = String, marks = [], className, id, values, change, commit, thumbLabels, }) {
|
|
10
10
|
const generated = useId();
|
|
11
|
+
const [activePointer, setActivePointer] = useState(null);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (disabled)
|
|
14
|
+
setActivePointer(null);
|
|
15
|
+
}, [disabled]);
|
|
11
16
|
const controlId = id ?? `dgm-slider-${generated}`;
|
|
12
17
|
if (![min, max, step].every(Number.isFinite) || min >= max || step <= 0) {
|
|
13
18
|
throw new RangeError('Slider requires finite min < max and step > 0.');
|
|
14
19
|
}
|
|
15
20
|
const describedBy = cx(hasContent(description) && `${controlId}-description`, hasContent(error) && `${controlId}-error`) || undefined;
|
|
16
|
-
return (_jsxs("div", { className: cx('dgm-field', 'dgm-slider-field', className), id: controlId, children: [_jsxs("div", { className: "dgm-slider-heading", children: [_jsx("span", { className: "dgm-label", id: `${controlId}-label`, children: label }), _jsx("span", { className: "dgm-description", "aria-hidden": "true", children: values.map(formatValue).join(' – ') })] }), _jsxs(Primitive.Root, { className: "dgm-slider",
|
|
21
|
+
return (_jsxs("div", { className: cx('dgm-field', 'dgm-slider-field', className), id: controlId, children: [_jsxs("div", { className: "dgm-slider-heading", children: [_jsx("span", { className: "dgm-label", id: `${controlId}-label`, children: label }), _jsx("span", { className: "dgm-description", "aria-hidden": "true", children: values.map(formatValue).join(' – ') })] }), _jsxs(Primitive.Root, { className: "dgm-slider", "data-thumb-visibility": thumbVisibility, "data-dragging": !disabled && activePointer !== null ? '' : undefined, onPointerDownCapture: (event) => {
|
|
22
|
+
if (!disabled && event.button === 0)
|
|
23
|
+
setActivePointer(event.pointerId);
|
|
24
|
+
}, onPointerUpCapture: () => setActivePointer(null), onPointerCancelCapture: () => setActivePointer(null), onLostPointerCapture: () => setActivePointer(null), value: values, onValueChange: change, onValueCommit: commit, min: min, max: max, step: step, disabled: disabled, name: name, children: [_jsx(Primitive.Track, { className: "dgm-slider-track", children: _jsx(Primitive.Range, { className: "dgm-slider-range" }) }), values.map((value, index) => (_jsx(Primitive.Thumb, { name: name, className: "dgm-slider-thumb", "aria-labelledby": `${controlId}-label${thumbLabels ? ` ${controlId}-thumb-${index}` : ''}`, "aria-describedby": describedBy, "aria-invalid": hasContent(error) || undefined, "aria-valuetext": formatValue(value) }, index)))] }), thumbLabels?.map((text, index) => (_jsx("span", { id: `${controlId}-thumb-${index}`, className: "dgm-visually-hidden", children: text }, index))), marks.length > 0 && (_jsx("div", { className: "dgm-slider-marks", "aria-hidden": "true", children: marks
|
|
17
25
|
.filter((mark) => mark.value >= min && mark.value <= max)
|
|
18
26
|
.map((mark) => (_jsx("span", { style: { left: `${(100 * (mark.value - min)) / (max - min)}%` }, children: mark.label ?? formatValue(mark.value) }, mark.value))) })), hasContent(description) && (_jsx("span", { id: `${controlId}-description`, className: "dgm-description", children: description })), hasContent(error) && (_jsx("span", { id: `${controlId}-error`, className: "dgm-error", children: error }))] }));
|
|
19
27
|
}
|
package/dist/styles.css
CHANGED
|
@@ -1609,7 +1609,10 @@ button.dgm-step:hover:not(:disabled),
|
|
|
1609
1609
|
cursor: pointer;
|
|
1610
1610
|
transition: var(--dgm-hover-transition);
|
|
1611
1611
|
}
|
|
1612
|
-
.
|
|
1612
|
+
/* Ghost distingue el foco de teclado del foco que Radix mueve con el puntero. */
|
|
1613
|
+
.dgm-dropdown-item:not(.dgm-dropdown-item--ghost)[data-highlighted]:not([data-disabled]),
|
|
1614
|
+
.dgm-dropdown:not([data-input-mode='pointer'])
|
|
1615
|
+
.dgm-dropdown-item--ghost:focus-visible:not([data-disabled]) {
|
|
1613
1616
|
outline: 2px solid var(--dgm-primary);
|
|
1614
1617
|
outline-offset: -2px;
|
|
1615
1618
|
}
|
|
@@ -2775,7 +2778,7 @@ button.dgm-step:hover:not(:disabled),
|
|
|
2775
2778
|
}
|
|
2776
2779
|
.dgm-table-sort-icon {
|
|
2777
2780
|
position: absolute;
|
|
2778
|
-
inset-inline-end: 0;
|
|
2781
|
+
inset-inline-end: 0.5625rem;
|
|
2779
2782
|
top: 50%;
|
|
2780
2783
|
width: 0.875rem;
|
|
2781
2784
|
height: 0.875rem;
|
|
@@ -2793,22 +2796,13 @@ button.dgm-step:hover:not(:disabled),
|
|
|
2793
2796
|
opacity: 1;
|
|
2794
2797
|
transform: translateY(-50%) scale(1);
|
|
2795
2798
|
}
|
|
2796
|
-
.dgm-data-table th
|
|
2797
|
-
.dgm-data-table th[data-align='end'] .dgm-table-sort[data-sorted] .dgm-table-sort-label {
|
|
2799
|
+
.dgm-data-table th .dgm-table-sort[data-sorted] .dgm-table-sort-label {
|
|
2798
2800
|
transform: translateX(-0.5625rem);
|
|
2799
2801
|
}
|
|
2800
|
-
.dgm-data-table th[data-align='center'] .dgm-table-sort-icon,
|
|
2801
|
-
.dgm-data-table th[data-align='end'] .dgm-table-sort-icon {
|
|
2802
|
-
inset-inline-end: 0.5625rem;
|
|
2803
|
-
}
|
|
2804
2802
|
.dgm-data-table th[data-align='start'] .dgm-table-sort {
|
|
2805
2803
|
margin-inline-start: calc(-1 * var(--dgm-table-sort-space));
|
|
2806
2804
|
}
|
|
2807
|
-
[dir='rtl']
|
|
2808
|
-
.dgm-data-table
|
|
2809
|
-
th:not([data-align='start'])
|
|
2810
|
-
.dgm-table-sort[data-sorted]
|
|
2811
|
-
.dgm-table-sort-label {
|
|
2805
|
+
[dir='rtl'] .dgm-data-table th .dgm-table-sort[data-sorted] .dgm-table-sort-label {
|
|
2812
2806
|
transform: translateX(0.5625rem);
|
|
2813
2807
|
}
|
|
2814
2808
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -3139,6 +3133,22 @@ button.dgm-step:disabled {
|
|
|
3139
3133
|
box-shadow: 0 2px 5px #0002;
|
|
3140
3134
|
cursor: grab;
|
|
3141
3135
|
}
|
|
3136
|
+
/* Opacidad conserva la geometría, el área táctil y los controles accesibles. */
|
|
3137
|
+
.dgm-slider[data-thumb-visibility='interaction'] .dgm-slider-thumb {
|
|
3138
|
+
opacity: 0;
|
|
3139
|
+
transition: opacity 0.15s ease;
|
|
3140
|
+
}
|
|
3141
|
+
.dgm-slider[data-thumb-visibility='interaction']:not([data-disabled]):focus-within
|
|
3142
|
+
.dgm-slider-thumb,
|
|
3143
|
+
.dgm-slider[data-thumb-visibility='interaction']:not([data-disabled])[data-dragging]
|
|
3144
|
+
.dgm-slider-thumb {
|
|
3145
|
+
opacity: 1;
|
|
3146
|
+
}
|
|
3147
|
+
@media (hover: hover) {
|
|
3148
|
+
.dgm-slider[data-thumb-visibility='interaction']:not([data-disabled]):hover .dgm-slider-thumb {
|
|
3149
|
+
opacity: 1;
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3142
3152
|
.dgm-slider-thumb::after {
|
|
3143
3153
|
content: '';
|
|
3144
3154
|
position: absolute;
|
|
@@ -3331,6 +3341,19 @@ button.dgm-step:disabled {
|
|
|
3331
3341
|
.dgm-navigation-trigger[data-state='open'] {
|
|
3332
3342
|
background: var(--dgm-subtle);
|
|
3333
3343
|
}
|
|
3344
|
+
/* Conserva la geometría y el foco compartidos, también dentro de los submenús. */
|
|
3345
|
+
.dgm-navigation--ghost .dgm-navigation-trigger,
|
|
3346
|
+
.dgm-navigation--ghost .dgm-navigation-link {
|
|
3347
|
+
background: transparent;
|
|
3348
|
+
border-color: transparent;
|
|
3349
|
+
}
|
|
3350
|
+
.dgm-navigation--ghost .dgm-navigation-link[data-active],
|
|
3351
|
+
.dgm-navigation--ghost .dgm-navigation-trigger[data-state='open'],
|
|
3352
|
+
.dgm-navigation--ghost .dgm-navigation-trigger:hover:not(:disabled),
|
|
3353
|
+
.dgm-navigation--ghost .dgm-navigation-link:hover:not([aria-disabled='true']) {
|
|
3354
|
+
background: var(--dgm-hover);
|
|
3355
|
+
color: var(--dgm-on-hover);
|
|
3356
|
+
}
|
|
3334
3357
|
.dgm-navigation-content {
|
|
3335
3358
|
/* Misma separación inicial que Popover y los selectores que lo componen. */
|
|
3336
3359
|
--dgm-navigation-gap: 8px;
|
|
@@ -3584,7 +3607,8 @@ button.dgm-step:disabled {
|
|
|
3584
3607
|
.dgm-navigation-content {
|
|
3585
3608
|
animation: none;
|
|
3586
3609
|
}
|
|
3587
|
-
.dgm-toggle-item
|
|
3610
|
+
.dgm-toggle-item,
|
|
3611
|
+
.dgm-slider[data-thumb-visibility='interaction'] .dgm-slider-thumb {
|
|
3588
3612
|
transition: none;
|
|
3589
3613
|
}
|
|
3590
3614
|
}
|