@archbase/components 4.4.0 → 4.6.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/dist/archbase-components-4.6.0.tgz +0 -0
- package/dist/buttons/ArchbaseSlideToConfirm.d.ts +37 -0
- package/dist/buttons/index.d.ts +2 -0
- package/dist/display/ArchbaseDeviceFrame.d.ts +41 -0
- package/dist/display/ArchbaseGlowingCards.d.ts +46 -0
- package/dist/display/index.d.ts +4 -0
- package/dist/feedback/ArchbaseStickyTopBar.d.ts +51 -0
- package/dist/feedback/index.d.ts +2 -0
- package/dist/index.js +10470 -9763
- package/dist/list/ArchbaseReorderList.d.ts +52 -0
- package/dist/list/index.d.ts +2 -0
- package/dist/navigation/ArchbaseMagnifyDock.d.ts +49 -0
- package/dist/navigation/index.d.ts +2 -0
- package/package.json +4 -4
- package/src/buttons/ArchbaseSlideToConfirm.tsx +250 -0
- package/src/buttons/index.ts +6 -0
- package/src/display/ArchbaseDeviceFrame.tsx +172 -0
- package/src/display/ArchbaseGlowingCards.tsx +204 -0
- package/src/display/index.ts +9 -0
- package/src/feedback/ArchbaseStickyTopBar.tsx +160 -0
- package/src/feedback/index.ts +3 -1
- package/src/list/ArchbaseReorderList.tsx +249 -0
- package/src/list/index.ts +3 -0
- package/src/navigation/ArchbaseMagnifyDock.tsx +198 -0
- package/src/navigation/index.ts +3 -1
- package/dist/archbase-components-4.4.0.tgz +0 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { useCallback, useRef, type ReactNode } from 'react';
|
|
2
|
+
import { Badge, Box, Tooltip, useMantineColorScheme } from '@mantine/core';
|
|
3
|
+
import { useReducedMotion } from '@mantine/hooks';
|
|
4
|
+
import { motion, useMotionValue, useSpring, useTransform, type MotionValue } from 'framer-motion';
|
|
5
|
+
|
|
6
|
+
export interface ArchbaseMagnifyDockItem {
|
|
7
|
+
id: string;
|
|
8
|
+
/** Icone do item. */
|
|
9
|
+
icon: ReactNode;
|
|
10
|
+
/** Nome acessivel e texto da dica. Obrigatorio: item so com icone e mudo. */
|
|
11
|
+
label: string;
|
|
12
|
+
onClick?: () => void;
|
|
13
|
+
/** Contador exibido no canto. Zero ou ausente nao mostra nada. */
|
|
14
|
+
badge?: number;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ArchbaseMagnifyDockProps {
|
|
19
|
+
items: ArchbaseMagnifyDockItem[];
|
|
20
|
+
/** Tamanho do item em repouso, em pixels. */
|
|
21
|
+
baseSize?: number;
|
|
22
|
+
/** Tamanho maximo sob o ponteiro. */
|
|
23
|
+
magnification?: number;
|
|
24
|
+
/** Alcance da magnificacao, em pixels. */
|
|
25
|
+
distance?: number;
|
|
26
|
+
spring?: { mass: number; stiffness: number; damping: number };
|
|
27
|
+
className?: string;
|
|
28
|
+
'aria-label'?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const MOLA_PADRAO = { mass: 0.1, stiffness: 150, damping: 12 };
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Barra de icones com magnificacao sob o ponteiro, no estilo do dock do macOS.
|
|
35
|
+
*
|
|
36
|
+
* Adaptado de Lightswind UI (MIT, Muhilan / codewithMUHILAN).
|
|
37
|
+
*
|
|
38
|
+
* Nao confundir com `ArchbaseDockLayout`, que e layout de paineis acoplaveis —
|
|
39
|
+
* conceitos distintos que a palavra "dock" une por acidente.
|
|
40
|
+
*
|
|
41
|
+
* Correcoes em relacao ao original:
|
|
42
|
+
*
|
|
43
|
+
* - Os itens eram `div` com `role="button"` e `tabIndex={0}`, mas **sem
|
|
44
|
+
* tratador de teclado**: recebiam foco e nao faziam nada com Enter ou Espaco.
|
|
45
|
+
* Aqui sao `<button>` de verdade, e o comportamento vem do navegador.
|
|
46
|
+
* - Item so com icone nao tinha nome acessivel — o leitor anunciava "botao" e
|
|
47
|
+
* nada mais. `label` agora e obrigatorio e vira o nome.
|
|
48
|
+
* - O original marcava `aria-haspopup="true"` em todos, o que promete um menu
|
|
49
|
+
* que nao existe.
|
|
50
|
+
* - A magnificacao e desligada sob `prefers-reduced-motion`; a barra continua
|
|
51
|
+
* inteiramente utilizavel, apenas sem o efeito.
|
|
52
|
+
*/
|
|
53
|
+
export function ArchbaseMagnifyDock({
|
|
54
|
+
items,
|
|
55
|
+
baseSize = 44,
|
|
56
|
+
magnification = 68,
|
|
57
|
+
distance = 140,
|
|
58
|
+
spring = MOLA_PADRAO,
|
|
59
|
+
className,
|
|
60
|
+
'aria-label': ariaLabel = 'Atalhos',
|
|
61
|
+
}: ArchbaseMagnifyDockProps) {
|
|
62
|
+
const movimentoReduzido = useReducedMotion();
|
|
63
|
+
// Fora do alcance: em repouso nenhum item cresce.
|
|
64
|
+
const ponteiroX = useMotionValue(Number.POSITIVE_INFINITY);
|
|
65
|
+
|
|
66
|
+
const aoMover = useCallback(
|
|
67
|
+
(evento: React.PointerEvent<HTMLDivElement>) => {
|
|
68
|
+
if (movimentoReduzido) return;
|
|
69
|
+
ponteiroX.set(evento.clientX);
|
|
70
|
+
},
|
|
71
|
+
[ponteiroX, movimentoReduzido],
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const aoSair = useCallback(() => {
|
|
75
|
+
ponteiroX.set(Number.POSITIVE_INFINITY);
|
|
76
|
+
}, [ponteiroX]);
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<Box
|
|
80
|
+
component="div"
|
|
81
|
+
role="toolbar"
|
|
82
|
+
aria-label={ariaLabel}
|
|
83
|
+
aria-orientation="horizontal"
|
|
84
|
+
className={className}
|
|
85
|
+
onPointerMove={aoMover}
|
|
86
|
+
onPointerLeave={aoSair}
|
|
87
|
+
style={{
|
|
88
|
+
display: 'inline-flex',
|
|
89
|
+
alignItems: 'flex-end',
|
|
90
|
+
gap: 8,
|
|
91
|
+
padding: 8,
|
|
92
|
+
borderRadius: 16,
|
|
93
|
+
background: 'var(--mantine-color-default)',
|
|
94
|
+
border: '1px solid var(--mantine-color-default-border)',
|
|
95
|
+
boxShadow: 'var(--mantine-shadow-md)',
|
|
96
|
+
}}
|
|
97
|
+
>
|
|
98
|
+
{items.map((item) => (
|
|
99
|
+
<ItemDoDock
|
|
100
|
+
key={item.id}
|
|
101
|
+
item={item}
|
|
102
|
+
ponteiroX={ponteiroX}
|
|
103
|
+
baseSize={baseSize}
|
|
104
|
+
magnification={movimentoReduzido ? baseSize : magnification}
|
|
105
|
+
distance={distance}
|
|
106
|
+
spring={spring}
|
|
107
|
+
/>
|
|
108
|
+
))}
|
|
109
|
+
</Box>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
interface ItemProps {
|
|
114
|
+
item: ArchbaseMagnifyDockItem;
|
|
115
|
+
ponteiroX: MotionValue<number>;
|
|
116
|
+
baseSize: number;
|
|
117
|
+
magnification: number;
|
|
118
|
+
distance: number;
|
|
119
|
+
spring: { mass: number; stiffness: number; damping: number };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function ItemDoDock({
|
|
123
|
+
item,
|
|
124
|
+
ponteiroX,
|
|
125
|
+
baseSize,
|
|
126
|
+
magnification,
|
|
127
|
+
distance,
|
|
128
|
+
spring,
|
|
129
|
+
}: ItemProps) {
|
|
130
|
+
const referencia = useRef<HTMLButtonElement>(null);
|
|
131
|
+
const { colorScheme } = useMantineColorScheme();
|
|
132
|
+
|
|
133
|
+
const distanciaDoCentro = useTransform(ponteiroX, (valor) => {
|
|
134
|
+
if (typeof valor !== 'number' || Number.isNaN(valor)) return 0;
|
|
135
|
+
const caixa = referencia.current?.getBoundingClientRect();
|
|
136
|
+
if (!caixa) return 0;
|
|
137
|
+
return valor - caixa.x - caixa.width / 2;
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const tamanhoAlvo = useTransform(
|
|
141
|
+
distanciaDoCentro,
|
|
142
|
+
[-distance, 0, distance],
|
|
143
|
+
[baseSize, magnification, baseSize],
|
|
144
|
+
);
|
|
145
|
+
const tamanho = useSpring(tamanhoAlvo, spring);
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<Tooltip label={item.label} position="top" withArrow openDelay={120} events={{ hover: true, focus: true, touch: false }}>
|
|
149
|
+
{/* `motion.button` direto, e nao `UnstyledButton` polimorfico: o tipo de
|
|
150
|
+
`style` do Mantine nao aceita `MotionValue`, e o reset de botao sao
|
|
151
|
+
tres linhas. */}
|
|
152
|
+
<motion.button
|
|
153
|
+
ref={referencia}
|
|
154
|
+
type="button"
|
|
155
|
+
onClick={item.onClick}
|
|
156
|
+
disabled={item.disabled}
|
|
157
|
+
// O nome acessivel vem do rotulo: item so com icone seria anunciado
|
|
158
|
+
// apenas como "botao".
|
|
159
|
+
aria-label={item.label}
|
|
160
|
+
style={{
|
|
161
|
+
width: tamanho,
|
|
162
|
+
height: tamanho,
|
|
163
|
+
position: 'relative',
|
|
164
|
+
display: 'inline-flex',
|
|
165
|
+
alignItems: 'center',
|
|
166
|
+
justifyContent: 'center',
|
|
167
|
+
borderRadius: '50%',
|
|
168
|
+
background:
|
|
169
|
+
colorScheme === 'dark'
|
|
170
|
+
? 'var(--mantine-color-dark-5)'
|
|
171
|
+
: 'var(--mantine-color-gray-0)',
|
|
172
|
+
border: '1px solid var(--mantine-color-default-border)',
|
|
173
|
+
cursor: item.disabled ? 'not-allowed' : 'pointer',
|
|
174
|
+
opacity: item.disabled ? 0.5 : 1,
|
|
175
|
+
padding: 0,
|
|
176
|
+
font: 'inherit',
|
|
177
|
+
color: 'inherit',
|
|
178
|
+
}}
|
|
179
|
+
>
|
|
180
|
+
{item.icon}
|
|
181
|
+
|
|
182
|
+
{item.badge !== undefined && item.badge > 0 && (
|
|
183
|
+
<Badge
|
|
184
|
+
size="xs"
|
|
185
|
+
circle
|
|
186
|
+
color="red"
|
|
187
|
+
style={{ position: 'absolute', top: -2, right: -2 }}
|
|
188
|
+
// O contador ja e anunciado no rotulo do botao pelo consumidor, se
|
|
189
|
+
// fizer sentido; aqui ele e decorativo para nao duplicar a fala.
|
|
190
|
+
aria-hidden
|
|
191
|
+
>
|
|
192
|
+
{item.badge > 99 ? '99+' : item.badge}
|
|
193
|
+
</Badge>
|
|
194
|
+
)}
|
|
195
|
+
</motion.button>
|
|
196
|
+
</Tooltip>
|
|
197
|
+
);
|
|
198
|
+
}
|
package/src/navigation/index.ts
CHANGED
|
@@ -48,4 +48,6 @@ export type {
|
|
|
48
48
|
UseArchbaseRegisterShortcutOptions,
|
|
49
49
|
UseArchbaseShortcutScopeReturn,
|
|
50
50
|
ArchbaseShortcutHintProps,
|
|
51
|
-
} from './ArchbaseKeyboardShortcuts';
|
|
51
|
+
} from './ArchbaseKeyboardShortcuts';
|
|
52
|
+
export { ArchbaseMagnifyDock } from './ArchbaseMagnifyDock';
|
|
53
|
+
export type { ArchbaseMagnifyDockProps, ArchbaseMagnifyDockItem } from './ArchbaseMagnifyDock';
|
|
Binary file
|