@consumidor-positivo/aurora 1.0.0 → 1.1.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.
|
@@ -33,6 +33,12 @@ export type SpecialButtonProps = {
|
|
|
33
33
|
* swipe gesture).
|
|
34
34
|
*/
|
|
35
35
|
knobAriaLabel?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Slider only — helper text shown below the button after an incomplete
|
|
38
|
+
* drag, guiding the user to slide all the way to the end.
|
|
39
|
+
* @default 'Arraste até o final para confirmar ação'
|
|
40
|
+
*/
|
|
41
|
+
incompleteHint?: ReactNode;
|
|
36
42
|
'data-testid'?: string;
|
|
37
43
|
};
|
|
38
44
|
export declare const SpecialButton: ({ type, ...props }: SpecialButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -9,7 +9,8 @@ import { IconSlash } from "../icons/IconSlash/index.es.js";
|
|
|
9
9
|
import { Conditional } from "../Conditional/index.es.js";
|
|
10
10
|
import './styles.css';const KNOB_SIZE = 40;
|
|
11
11
|
const TRACK_PADDING = 4;
|
|
12
|
-
const CONFIRM_THRESHOLD = 0.
|
|
12
|
+
const CONFIRM_THRESHOLD = 0.7;
|
|
13
|
+
const COMPLETE_ANIMATION_MS = 400;
|
|
13
14
|
const _PressButton = ({
|
|
14
15
|
children = "Hold to confirm",
|
|
15
16
|
onConfirm,
|
|
@@ -99,15 +100,20 @@ const _SliderButton = ({
|
|
|
99
100
|
success = false,
|
|
100
101
|
skeleton = false,
|
|
101
102
|
knobAriaLabel = "Arraste para confirmar",
|
|
103
|
+
incompleteHint = "Arraste até o final para confirmar ação",
|
|
102
104
|
"data-testid": dataTestId
|
|
103
105
|
}) => {
|
|
104
106
|
const containerRef = useRef(null);
|
|
105
107
|
const startXRef = useRef(0);
|
|
108
|
+
const completeTimerRef = useRef();
|
|
106
109
|
const [dragging, setDragging] = useState(false);
|
|
107
110
|
const [dragX, setDragX] = useState(0);
|
|
111
|
+
const [completing, setCompleting] = useState(false);
|
|
112
|
+
const [showHint, setShowHint] = useState(false);
|
|
108
113
|
const [confirmed, setConfirmed] = useState(false);
|
|
109
114
|
const isSuccess = success || confirmed;
|
|
110
|
-
const isInteractive = !disabled && !loading && !isSuccess && !skeleton;
|
|
115
|
+
const isInteractive = !disabled && !loading && !isSuccess && !skeleton && !completing;
|
|
116
|
+
useEffect(() => () => window.clearTimeout(completeTimerRef.current), []);
|
|
111
117
|
function _maxDrag() {
|
|
112
118
|
const container = containerRef.current;
|
|
113
119
|
if (!container) return 0;
|
|
@@ -117,6 +123,17 @@ const _SliderButton = ({
|
|
|
117
123
|
setConfirmed(true);
|
|
118
124
|
if (onConfirm) onConfirm();
|
|
119
125
|
}
|
|
126
|
+
function _complete() {
|
|
127
|
+
setDragging(false);
|
|
128
|
+
setCompleting(true);
|
|
129
|
+
setShowHint(false);
|
|
130
|
+
setDragX(_maxDrag());
|
|
131
|
+
completeTimerRef.current = window.setTimeout(() => {
|
|
132
|
+
setCompleting(false);
|
|
133
|
+
setDragX(0);
|
|
134
|
+
_confirm();
|
|
135
|
+
}, COMPLETE_ANIMATION_MS);
|
|
136
|
+
}
|
|
120
137
|
function handlePointerDown(event) {
|
|
121
138
|
var _a, _b;
|
|
122
139
|
if (!isInteractive) return;
|
|
@@ -126,14 +143,16 @@ const _SliderButton = ({
|
|
|
126
143
|
}
|
|
127
144
|
function handlePointerMove(event) {
|
|
128
145
|
if (!dragging) return;
|
|
146
|
+
const max = _maxDrag();
|
|
129
147
|
const delta = event.clientX - startXRef.current;
|
|
130
|
-
|
|
148
|
+
const next = Math.min(Math.max(delta, 0), max);
|
|
149
|
+
setDragX(next);
|
|
150
|
+
if (max > 0 && next >= max * CONFIRM_THRESHOLD) _complete();
|
|
131
151
|
}
|
|
132
152
|
function handlePointerEnd() {
|
|
133
153
|
if (!dragging) return;
|
|
134
154
|
setDragging(false);
|
|
135
|
-
|
|
136
|
-
if (max > 0 && dragX >= max * CONFIRM_THRESHOLD) _confirm();
|
|
155
|
+
if (dragX > 0) setShowHint(true);
|
|
137
156
|
setDragX(0);
|
|
138
157
|
}
|
|
139
158
|
function handleKeyDown(event) {
|
|
@@ -149,6 +168,7 @@ const _SliderButton = ({
|
|
|
149
168
|
{
|
|
150
169
|
[`au-special-button--variant-${variant}`]: !!variant,
|
|
151
170
|
"au-special-button--dragging": dragging,
|
|
171
|
+
"au-special-button--completing": completing,
|
|
152
172
|
"au-special-button--disabled": disabled,
|
|
153
173
|
"au-special-button--loading": loading,
|
|
154
174
|
"au-special-button--success": isSuccess,
|
|
@@ -160,27 +180,43 @@ const _SliderButton = ({
|
|
|
160
180
|
if (disabled) return /* @__PURE__ */ jsx(IconSlash, { "aria-hidden": "true" });
|
|
161
181
|
return /* @__PURE__ */ jsx(IconArrowRight, { "aria-hidden": "true" });
|
|
162
182
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
"
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
183
|
+
const maxDrag = _maxDrag();
|
|
184
|
+
const dragProgress = maxDrag > 0 ? dragX / maxDrag : 0;
|
|
185
|
+
return /* @__PURE__ */ jsxs("div", { className: "au-special-button-wrapper", children: [
|
|
186
|
+
/* @__PURE__ */ jsxs(
|
|
187
|
+
"div",
|
|
188
|
+
{
|
|
189
|
+
ref: containerRef,
|
|
190
|
+
className: classes,
|
|
191
|
+
style: {
|
|
192
|
+
"--au-special-button-progress": dragProgress
|
|
193
|
+
},
|
|
194
|
+
"data-testid": dataTestId,
|
|
195
|
+
children: [
|
|
196
|
+
loading && /* @__PURE__ */ jsx(IconLoader, {}),
|
|
197
|
+
!loading && !skeleton && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
198
|
+
/* @__PURE__ */ jsx("span", { className: "au-special-button__label", children }),
|
|
199
|
+
/* @__PURE__ */ jsx(
|
|
200
|
+
"button",
|
|
201
|
+
{
|
|
202
|
+
type: "button",
|
|
203
|
+
className: "au-special-button__knob",
|
|
204
|
+
"aria-label": knobAriaLabel,
|
|
205
|
+
disabled,
|
|
206
|
+
style: dragX > 0 ? { transform: `translateX(${dragX}px)` } : void 0,
|
|
207
|
+
onPointerDown: handlePointerDown,
|
|
208
|
+
onPointerMove: handlePointerMove,
|
|
209
|
+
onPointerUp: handlePointerEnd,
|
|
210
|
+
onPointerCancel: handlePointerEnd,
|
|
211
|
+
onKeyDown: handleKeyDown,
|
|
212
|
+
children: _renderKnobIcon()
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
] })
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
),
|
|
219
|
+
showHint && !isSuccess && /* @__PURE__ */ jsx("span", { className: "au-special-button__hint", role: "status", children: incompleteHint })
|
|
184
220
|
] });
|
|
185
221
|
};
|
|
186
222
|
const SpecialButton = ({ type = "press", ...props }) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.es.js","sources":["../../../lib/components/SpecialButton/index.tsx"],"sourcesContent":["import classNames from 'classnames'\nimport React, { ReactNode, useEffect, useRef, useState } from 'react'\nimport {\n IconArrowRight,\n IconCheck,\n IconLoader,\n IconSlash,\n} from '../icons/default'\nimport { Conditional } from '../misc/Conditional'\nimport './styles.scss'\n\nconst KNOB_SIZE = 40\nconst TRACK_PADDING = 4\nconst CONFIRM_THRESHOLD = 0.85\n\nexport type SpecialButtonProps = {\n /**\n * Interaction mode: 'press' is hold-to-confirm (Figma: Press Button),\n * 'slider' is swipe-to-confirm (Figma: Swipe Button).\n * @default 'press'\n */\n type?: 'press' | 'slider'\n children?: ReactNode\n /** Called once when the interaction completes (hold finished / knob dragged to the end). */\n onConfirm?: () => void\n disabled?: boolean\n loading?: boolean\n /**\n * Controlled success state. The component also enters success on its own\n * right after a completed interaction.\n */\n success?: boolean\n /**\n * Press only — time in milliseconds the user must keep pressing to confirm.\n * @default 1500\n */\n holdDuration?: number\n /** Press only — stretches the button to fill the container width. */\n expand?: 'x'\n /** Slider only — visual variant (Figma: Swipe Button, ◇ Type Primary | Secondary). */\n variant?: 'primary' | 'secondary'\n /** Slider only — renders an empty skeleton placeholder. */\n skeleton?: boolean\n /**\n * Slider only — accessible label for the draggable knob. Pressing Enter or\n * Space on the focused knob confirms directly (keyboard alternative to the\n * swipe gesture).\n */\n knobAriaLabel?: string\n 'data-testid'?: string\n}\n\nconst _PressButton = ({\n children = 'Hold to confirm',\n onConfirm,\n holdDuration = 1500,\n disabled = false,\n loading = false,\n success = false,\n expand,\n 'data-testid': dataTestId,\n}: SpecialButtonProps) => {\n const [holding, setHolding] = useState(false)\n const [confirmed, setConfirmed] = useState(false)\n const timerRef = useRef<number>()\n\n const isSuccess = success || confirmed\n const isInteractive = !disabled && !loading && !isSuccess\n\n useEffect(() => () => window.clearTimeout(timerRef.current), [])\n\n function _startHold() {\n if (!isInteractive || holding) return\n setHolding(true)\n timerRef.current = window.setTimeout(() => {\n setHolding(false)\n setConfirmed(true)\n if (onConfirm) onConfirm()\n }, holdDuration)\n }\n\n function _cancelHold() {\n if (!holding) return\n window.clearTimeout(timerRef.current)\n setHolding(false)\n }\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLButtonElement>) {\n if ((event.key === 'Enter' || event.key === ' ') && !event.repeat) {\n event.preventDefault()\n _startHold()\n }\n }\n\n function handleKeyUp(event: React.KeyboardEvent<HTMLButtonElement>) {\n if (event.key === 'Enter' || event.key === ' ') _cancelHold()\n }\n\n const classes = classNames('au-special-button', 'au-special-button--type-press', {\n 'au-special-button--holding': holding,\n 'au-special-button--disabled': disabled,\n 'au-special-button--loading': loading,\n 'au-special-button--success': isSuccess,\n [`au-special-button--expand-${expand}`]: !!expand,\n })\n\n return (\n <button\n type=\"button\"\n className={classes}\n style={\n {\n '--au-special-button-duration': `${holdDuration}ms`,\n } as React.CSSProperties\n }\n disabled={disabled || loading}\n aria-busy={loading}\n onPointerDown={_startHold}\n onPointerUp={_cancelHold}\n onPointerLeave={_cancelHold}\n onPointerCancel={_cancelHold}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n data-testid={dataTestId}>\n <span className=\"au-special-button__fill\" aria-hidden=\"true\" />\n <Conditional\n condition={loading}\n renderIf={<IconLoader />}\n renderElse={\n <span className=\"au-special-button__label\">\n {disabled && <IconSlash aria-hidden=\"true\" />}\n {children}\n </span>\n }\n />\n </button>\n )\n}\n\nconst _SliderButton = ({\n children = 'Slide to action',\n onConfirm,\n variant = 'primary',\n disabled = false,\n loading = false,\n success = false,\n skeleton = false,\n knobAriaLabel = 'Arraste para confirmar',\n 'data-testid': dataTestId,\n}: SpecialButtonProps) => {\n const containerRef = useRef<HTMLDivElement>(null)\n const startXRef = useRef(0)\n const [dragging, setDragging] = useState(false)\n const [dragX, setDragX] = useState(0)\n const [confirmed, setConfirmed] = useState(false)\n\n const isSuccess = success || confirmed\n const isInteractive = !disabled && !loading && !isSuccess && !skeleton\n\n function _maxDrag() {\n const container = containerRef.current\n if (!container) return 0\n return container.clientWidth - KNOB_SIZE - TRACK_PADDING * 2\n }\n\n function _confirm() {\n setConfirmed(true)\n if (onConfirm) onConfirm()\n }\n\n function handlePointerDown(event: React.PointerEvent<HTMLButtonElement>) {\n if (!isInteractive) return\n setDragging(true)\n startXRef.current = event.clientX\n event.currentTarget.setPointerCapture?.(event.pointerId)\n }\n\n function handlePointerMove(event: React.PointerEvent<HTMLButtonElement>) {\n if (!dragging) return\n const delta = event.clientX - startXRef.current\n setDragX(Math.min(Math.max(delta, 0), _maxDrag()))\n }\n\n function handlePointerEnd() {\n if (!dragging) return\n setDragging(false)\n const max = _maxDrag()\n if (max > 0 && dragX >= max * CONFIRM_THRESHOLD) _confirm()\n setDragX(0)\n }\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLButtonElement>) {\n if (!isInteractive) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n _confirm()\n }\n }\n\n const classes = classNames(\n 'au-special-button',\n 'au-special-button--type-slider',\n {\n [`au-special-button--variant-${variant}`]: !!variant,\n 'au-special-button--dragging': dragging,\n 'au-special-button--disabled': disabled,\n 'au-special-button--loading': loading,\n 'au-special-button--success': isSuccess,\n 'au-special-button--skeleton': skeleton,\n },\n )\n\n function _renderKnobIcon() {\n if (isSuccess) return <IconCheck aria-hidden=\"true\" />\n if (disabled) return <IconSlash aria-hidden=\"true\" />\n return <IconArrowRight aria-hidden=\"true\" />\n }\n\n return (\n <div ref={containerRef} className={classes} data-testid={dataTestId}>\n {loading && <IconLoader />}\n {!loading && !skeleton && (\n <>\n <span className=\"au-special-button__label\">{children}</span>\n <button\n type=\"button\"\n className=\"au-special-button__knob\"\n aria-label={knobAriaLabel}\n disabled={disabled}\n style={\n dragX > 0 ? { transform: `translateX(${dragX}px)` } : undefined\n }\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerEnd}\n onPointerCancel={handlePointerEnd}\n onKeyDown={handleKeyDown}>\n {_renderKnobIcon()}\n </button>\n </>\n )}\n </div>\n )\n}\n\nexport const SpecialButton = ({ type = 'press', ...props }: SpecialButtonProps) => {\n if (type === 'slider') return <_SliderButton {...props} />\n return <_PressButton {...props} />\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.es.js","sources":["../../../lib/components/SpecialButton/index.tsx"],"sourcesContent":["import classNames from 'classnames'\nimport React, { ReactNode, useEffect, useRef, useState } from 'react'\nimport {\n IconArrowRight,\n IconCheck,\n IconLoader,\n IconSlash,\n} from '../icons/default'\nimport { Conditional } from '../misc/Conditional'\nimport './styles.scss'\n\nconst KNOB_SIZE = 40\nconst TRACK_PADDING = 4\n// Figma (Behavior): a partir de ~70% do trajeto a ação já conta como\n// confirmada e o botão se completa sozinho.\nconst CONFIRM_THRESHOLD = 0.7\nconst COMPLETE_ANIMATION_MS = 400\n\nexport type SpecialButtonProps = {\n /**\n * Interaction mode: 'press' is hold-to-confirm (Figma: Press Button),\n * 'slider' is swipe-to-confirm (Figma: Swipe Button).\n * @default 'press'\n */\n type?: 'press' | 'slider'\n children?: ReactNode\n /** Called once when the interaction completes (hold finished / knob dragged to the end). */\n onConfirm?: () => void\n disabled?: boolean\n loading?: boolean\n /**\n * Controlled success state. The component also enters success on its own\n * right after a completed interaction.\n */\n success?: boolean\n /**\n * Press only — time in milliseconds the user must keep pressing to confirm.\n * @default 1500\n */\n holdDuration?: number\n /** Press only — stretches the button to fill the container width. */\n expand?: 'x'\n /** Slider only — visual variant (Figma: Swipe Button, ◇ Type Primary | Secondary). */\n variant?: 'primary' | 'secondary'\n /** Slider only — renders an empty skeleton placeholder. */\n skeleton?: boolean\n /**\n * Slider only — accessible label for the draggable knob. Pressing Enter or\n * Space on the focused knob confirms directly (keyboard alternative to the\n * swipe gesture).\n */\n knobAriaLabel?: string\n /**\n * Slider only — helper text shown below the button after an incomplete\n * drag, guiding the user to slide all the way to the end.\n * @default 'Arraste até o final para confirmar ação'\n */\n incompleteHint?: ReactNode\n 'data-testid'?: string\n}\n\nconst _PressButton = ({\n children = 'Hold to confirm',\n onConfirm,\n holdDuration = 1500,\n disabled = false,\n loading = false,\n success = false,\n expand,\n 'data-testid': dataTestId,\n}: SpecialButtonProps) => {\n const [holding, setHolding] = useState(false)\n const [confirmed, setConfirmed] = useState(false)\n const timerRef = useRef<number>()\n\n const isSuccess = success || confirmed\n const isInteractive = !disabled && !loading && !isSuccess\n\n useEffect(() => () => window.clearTimeout(timerRef.current), [])\n\n function _startHold() {\n if (!isInteractive || holding) return\n setHolding(true)\n timerRef.current = window.setTimeout(() => {\n setHolding(false)\n setConfirmed(true)\n if (onConfirm) onConfirm()\n }, holdDuration)\n }\n\n function _cancelHold() {\n if (!holding) return\n window.clearTimeout(timerRef.current)\n setHolding(false)\n }\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLButtonElement>) {\n if ((event.key === 'Enter' || event.key === ' ') && !event.repeat) {\n event.preventDefault()\n _startHold()\n }\n }\n\n function handleKeyUp(event: React.KeyboardEvent<HTMLButtonElement>) {\n if (event.key === 'Enter' || event.key === ' ') _cancelHold()\n }\n\n const classes = classNames('au-special-button', 'au-special-button--type-press', {\n 'au-special-button--holding': holding,\n 'au-special-button--disabled': disabled,\n 'au-special-button--loading': loading,\n 'au-special-button--success': isSuccess,\n [`au-special-button--expand-${expand}`]: !!expand,\n })\n\n return (\n <button\n type=\"button\"\n className={classes}\n style={\n {\n '--au-special-button-duration': `${holdDuration}ms`,\n } as React.CSSProperties\n }\n disabled={disabled || loading}\n aria-busy={loading}\n onPointerDown={_startHold}\n onPointerUp={_cancelHold}\n onPointerLeave={_cancelHold}\n onPointerCancel={_cancelHold}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n data-testid={dataTestId}>\n <span className=\"au-special-button__fill\" aria-hidden=\"true\" />\n <Conditional\n condition={loading}\n renderIf={<IconLoader />}\n renderElse={\n <span className=\"au-special-button__label\">\n {disabled && <IconSlash aria-hidden=\"true\" />}\n {children}\n </span>\n }\n />\n </button>\n )\n}\n\nconst _SliderButton = ({\n children = 'Slide to action',\n onConfirm,\n variant = 'primary',\n disabled = false,\n loading = false,\n success = false,\n skeleton = false,\n knobAriaLabel = 'Arraste para confirmar',\n incompleteHint = 'Arraste até o final para confirmar ação',\n 'data-testid': dataTestId,\n}: SpecialButtonProps) => {\n const containerRef = useRef<HTMLDivElement>(null)\n const startXRef = useRef(0)\n const completeTimerRef = useRef<number>()\n const [dragging, setDragging] = useState(false)\n const [dragX, setDragX] = useState(0)\n const [completing, setCompleting] = useState(false)\n const [showHint, setShowHint] = useState(false)\n const [confirmed, setConfirmed] = useState(false)\n\n const isSuccess = success || confirmed\n const isInteractive =\n !disabled && !loading && !isSuccess && !skeleton && !completing\n\n useEffect(() => () => window.clearTimeout(completeTimerRef.current), [])\n\n function _maxDrag() {\n const container = containerRef.current\n if (!container) return 0\n return container.clientWidth - KNOB_SIZE - TRACK_PADDING * 2\n }\n\n function _confirm() {\n setConfirmed(true)\n if (onConfirm) onConfirm()\n }\n\n function _complete() {\n setDragging(false)\n setCompleting(true)\n setShowHint(false)\n setDragX(_maxDrag())\n completeTimerRef.current = window.setTimeout(() => {\n setCompleting(false)\n setDragX(0)\n _confirm()\n }, COMPLETE_ANIMATION_MS)\n }\n\n function handlePointerDown(event: React.PointerEvent<HTMLButtonElement>) {\n if (!isInteractive) return\n setDragging(true)\n startXRef.current = event.clientX\n event.currentTarget.setPointerCapture?.(event.pointerId)\n }\n\n function handlePointerMove(event: React.PointerEvent<HTMLButtonElement>) {\n if (!dragging) return\n const max = _maxDrag()\n const delta = event.clientX - startXRef.current\n const next = Math.min(Math.max(delta, 0), max)\n setDragX(next)\n if (max > 0 && next >= max * CONFIRM_THRESHOLD) _complete()\n }\n\n function handlePointerEnd() {\n if (!dragging) return\n setDragging(false)\n if (dragX > 0) setShowHint(true)\n setDragX(0)\n }\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLButtonElement>) {\n if (!isInteractive) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n _confirm()\n }\n }\n\n const classes = classNames(\n 'au-special-button',\n 'au-special-button--type-slider',\n {\n [`au-special-button--variant-${variant}`]: !!variant,\n 'au-special-button--dragging': dragging,\n 'au-special-button--completing': completing,\n 'au-special-button--disabled': disabled,\n 'au-special-button--loading': loading,\n 'au-special-button--success': isSuccess,\n 'au-special-button--skeleton': skeleton,\n },\n )\n\n function _renderKnobIcon() {\n if (isSuccess) return <IconCheck aria-hidden=\"true\" />\n if (disabled) return <IconSlash aria-hidden=\"true\" />\n return <IconArrowRight aria-hidden=\"true\" />\n }\n\n const maxDrag = _maxDrag()\n const dragProgress = maxDrag > 0 ? dragX / maxDrag : 0\n\n return (\n <div className=\"au-special-button-wrapper\">\n <div\n ref={containerRef}\n className={classes}\n style={\n {\n '--au-special-button-progress': dragProgress,\n } as React.CSSProperties\n }\n data-testid={dataTestId}>\n {loading && <IconLoader />}\n {!loading && !skeleton && (\n <>\n <span className=\"au-special-button__label\">{children}</span>\n <button\n type=\"button\"\n className=\"au-special-button__knob\"\n aria-label={knobAriaLabel}\n disabled={disabled}\n style={\n dragX > 0 ? { transform: `translateX(${dragX}px)` } : undefined\n }\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerEnd}\n onPointerCancel={handlePointerEnd}\n onKeyDown={handleKeyDown}>\n {_renderKnobIcon()}\n </button>\n </>\n )}\n </div>\n {showHint && !isSuccess && (\n <span className=\"au-special-button__hint\" role=\"status\">\n {incompleteHint}\n </span>\n )}\n </div>\n )\n}\n\nexport const SpecialButton = ({ type = 'press', ...props }: SpecialButtonProps) => {\n if (type === 'slider') return <_SliderButton {...props} />\n return <_PressButton {...props} />\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.au-special-button{position:relative;display:flex;align-items:center;justify-content:center;height:48px;border-radius:48px;overflow:hidden;background-color:#0048db;color:#fff;font-family:"Source Sans 3",sans-serif;font-size:16px;font-weight:600;-webkit-user-select:none;user-select:none}.au-special-button--type-press{display:inline-flex;gap:8px;padding:8px 16px;border:none;text-align:center;cursor:pointer;touch-action:none;-webkit-tap-highlight-color:transparent}.au-special-button--type-press .au-icon,.au-special-button--type-press .au-icon>svg{width:20px;height:20px;color:#fff}.au-special-button__fill{position:absolute;top:0;left:0;bottom:0;width:0;background-color:#18256c;transition:width .2s ease}.au-special-button__label{position:relative;display:inline-flex;align-items:center;gap:8px}.au-special-button--holding .au-special-button__fill{width:100%;transition:width var(--au-special-button-duration, 1.5s) linear}.au-special-button--type-press.au-special-button--success .au-special-button__fill,.au-special-button--type-press.au-special-button--loading .au-special-button__fill{width:100%;transition:width .3s ease}.au-special-button--type-press.au-special-button--disabled{background-color:#e2e4e9;color:#c4c9d4;cursor:not-allowed}.au-special-button--type-press.au-special-button--disabled .au-icon,.au-special-button--type-press.au-special-button--disabled .au-icon>svg{width:16px;height:16px;color:#c4c9d4}.au-special-button--type-press.au-special-button--loading{cursor:progress}.au-special-button--type-press.au-special-button--loading .au-icon{position:relative;animation:au-special-button-spin 1s infinite linear}.au-special-button--expand-x{width:100%}.au-special-button__knob{position:absolute;top:4px;left:4px;display:flex;align-items:center;justify-content:center;width:40px;height:40px;padding:0;border:none;border-radius:50%;background-color:#fff;box-shadow:0 24px 56px #7686ad14,0 12px 12px #0048db0a;cursor:grab;touch-action:none;transition:transform .2s ease}.au-special-button__knob .au-icon,.au-special-button__knob .au-icon>svg{width:24px;height:24px;color:#0048db}.au-special-button--dragging .au-special-button__knob{cursor:grabbing;transition:none}.au-special-button--type-slider .au-special-button__label{padding:8px 48px}.au-special-button--variant-secondary{background-color:#fff;border:1px solid #0048db;color:#0048db}.au-special-button--type-slider.au-special-button--disabled{background-color:#f6f7fa;border:none;color:#c4c9d4}.au-special-button--type-slider.au-special-button--disabled .au-special-button__knob{background-color:#e2e4e9;box-shadow:none;cursor:not-allowed}.au-special-button--type-slider.au-special-button--disabled .au-special-button__knob .au-icon,.au-special-button--type-slider.au-special-button--disabled .au-special-button__knob .au-icon>svg{color:#c4c9d4}.au-special-button--type-slider.au-special-button--success{background-color:#138040;border:none;color:#fff}.au-special-button--type-slider.au-special-button--success .au-special-button__knob{left:auto;right:4px;cursor:default}.au-special-button--type-slider.au-special-button--success .au-special-button__knob .au-icon,.au-special-button--type-slider.au-special-button--success .au-special-button__knob .au-icon>svg{color:#138040}.au-special-button--variant-secondary.au-special-button--success{background-color:#fff;border:1px solid #10593b;color:#10593b}.au-special-button--variant-secondary.au-special-button--success .au-special-button__knob .au-icon,.au-special-button--variant-secondary.au-special-button--success .au-special-button__knob .au-icon>svg{color:#10593b}.au-special-button--type-slider.au-special-button--loading{background-color:#10593b;border:none;cursor:progress}.au-special-button--type-slider.au-special-button--loading .au-icon{animation:au-special-button-spin 1s infinite linear}.au-special-button--type-slider.au-special-button--loading .au-icon,.au-special-button--type-slider.au-special-button--loading .au-icon>svg{width:20px;height:20px;color:#fff}.au-special-button--skeleton{background-color:#f6f7fa;border:none;animation:au-special-button-pulse 1.5s ease-in-out infinite}@keyframes au-special-button-spin{to{transform:rotate(360deg)}}@keyframes au-special-button-pulse{0%,to{opacity:1}50%{opacity:.6}}
|
|
1
|
+
.au-special-button{position:relative;display:flex;align-items:center;justify-content:center;height:48px;border-radius:48px;overflow:hidden;background-color:#0048db;color:#fff;font-family:"Source Sans 3",sans-serif;font-size:16px;font-weight:600;-webkit-user-select:none;user-select:none}.au-special-button--type-press{display:inline-flex;gap:8px;padding:8px 16px;border:none;text-align:center;cursor:pointer;touch-action:none;-webkit-tap-highlight-color:transparent}.au-special-button--type-press .au-icon,.au-special-button--type-press .au-icon>svg{width:20px;height:20px;color:#fff}.au-special-button__fill{position:absolute;top:0;left:0;bottom:0;width:0;background-color:#18256c;transition:width .2s ease}.au-special-button__label{position:relative;display:inline-flex;align-items:center;gap:8px}.au-special-button--holding .au-special-button__fill{width:100%;transition:width var(--au-special-button-duration, 1.5s) linear}.au-special-button--type-press.au-special-button--success .au-special-button__fill,.au-special-button--type-press.au-special-button--loading .au-special-button__fill{width:100%;transition:width .3s ease}.au-special-button--type-press.au-special-button--disabled{background-color:#e2e4e9;color:#c4c9d4;cursor:not-allowed}.au-special-button--type-press.au-special-button--disabled .au-icon,.au-special-button--type-press.au-special-button--disabled .au-icon>svg{width:16px;height:16px;color:#c4c9d4}.au-special-button--type-press.au-special-button--loading{cursor:progress}.au-special-button--type-press.au-special-button--loading .au-icon{position:relative;animation:au-special-button-spin 1s infinite linear}.au-special-button--expand-x{width:100%}.au-special-button__knob{position:absolute;top:4px;left:4px;display:flex;align-items:center;justify-content:center;width:40px;height:40px;padding:0;border:none;border-radius:50%;background-color:#fff;box-shadow:0 24px 56px #7686ad14,0 12px 12px #0048db0a;cursor:grab;touch-action:none;transition:transform .2s ease}.au-special-button__knob .au-icon,.au-special-button__knob .au-icon>svg{width:24px;height:24px;color:#0048db}.au-special-button--dragging .au-special-button__knob{cursor:grabbing;transition:none}.au-special-button--completing .au-special-button__knob{cursor:default;transition:transform .4s ease-out}.au-special-button--type-slider .au-special-button__label{padding:8px 48px;opacity:calc(1 - var(--au-special-button-progress, 0) * 1.4);transition:opacity .1s linear}.au-special-button--variant-secondary{background-color:#fff;border:1px solid #0048db;color:#0048db}.au-special-button--type-slider.au-special-button--disabled{background-color:#f6f7fa;border:none;color:#c4c9d4}.au-special-button--type-slider.au-special-button--disabled .au-special-button__knob{background-color:#e2e4e9;box-shadow:none;cursor:not-allowed}.au-special-button--type-slider.au-special-button--disabled .au-special-button__knob .au-icon,.au-special-button--type-slider.au-special-button--disabled .au-special-button__knob .au-icon>svg{color:#c4c9d4}.au-special-button--type-slider.au-special-button--success{background-color:#138040;border:none;color:#fff}.au-special-button--type-slider.au-special-button--success .au-special-button__label{opacity:0}.au-special-button--type-slider.au-special-button--success .au-special-button__knob{left:auto;right:4px;cursor:default}.au-special-button--type-slider.au-special-button--success .au-special-button__knob .au-icon,.au-special-button--type-slider.au-special-button--success .au-special-button__knob .au-icon>svg{color:#138040}.au-special-button--variant-secondary.au-special-button--success{background-color:#fff;border:1px solid #10593b;color:#10593b}.au-special-button--variant-secondary.au-special-button--success .au-special-button__knob .au-icon,.au-special-button--variant-secondary.au-special-button--success .au-special-button__knob .au-icon>svg{color:#10593b}.au-special-button--type-slider.au-special-button--loading{background-color:#10593b;border:none;cursor:progress}.au-special-button--type-slider.au-special-button--loading .au-icon{animation:au-special-button-spin 1s infinite linear}.au-special-button--type-slider.au-special-button--loading .au-icon,.au-special-button--type-slider.au-special-button--loading .au-icon>svg{width:20px;height:20px;color:#fff}.au-special-button--skeleton{background-color:#f6f7fa;border:none;animation:au-special-button-pulse 1.5s ease-in-out infinite}.au-special-button__hint{display:block;margin-top:8px;text-align:center;font-family:"Source Sans 3",sans-serif;font-size:12px;font-weight:400;color:#313131}.au-special-button-wrapper{width:100%}@keyframes au-special-button-spin{to{transform:rotate(360deg)}}@keyframes au-special-button-pulse{0%,to{opacity:1}50%{opacity:.6}}
|
package/dist/main.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export { Tabs } from './components/Tabs';
|
|
|
26
26
|
export type { TabsProps, TabItemProps } from './components/Tabs';
|
|
27
27
|
export { Skeleton } from './components/Skeleton';
|
|
28
28
|
export { Spinner } from './components/Spinner';
|
|
29
|
-
export { Image } from '
|
|
29
|
+
export { Image } from './components/Image';
|
|
30
30
|
export { ProgressBar } from './components/ProgressBar';
|
|
31
31
|
export { Modal } from './components/Modal';
|
|
32
32
|
export { Tooltip } from './components/Tooltip';
|