@sublimee/auth-ui 0.1.1 → 0.1.13

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/index.mjs CHANGED
@@ -1,4 +1,7 @@
1
1
  // src/oauth-button.tsx
2
+ import { forwardRef as forwardRef2 } from "react";
3
+
4
+ // src/base-button.tsx
2
5
  import { forwardRef } from "react";
3
6
  import { Button } from "@base-ui/react/button";
4
7
 
@@ -7,7 +10,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
7
10
  function getSafeSize(size, defaultSize = 24) {
8
11
  return Math.max(1, size ?? defaultSize);
9
12
  }
10
- function GoogleIcon({ size }) {
13
+ function GoogleIcon({ size, className }) {
11
14
  const safeSize = getSafeSize(size);
12
15
  return /* @__PURE__ */ jsxs(
13
16
  "svg",
@@ -18,6 +21,7 @@ function GoogleIcon({ size }) {
18
21
  fill: "none",
19
22
  xmlns: "http://www.w3.org/2000/svg",
20
23
  "aria-hidden": "true",
24
+ className,
21
25
  children: [
22
26
  /* @__PURE__ */ jsx(
23
27
  "path",
@@ -51,7 +55,7 @@ function GoogleIcon({ size }) {
51
55
  }
52
56
  );
53
57
  }
54
- function DiscordIcon({ size }) {
58
+ function DiscordIcon({ size, className }) {
55
59
  const safeSize = getSafeSize(size);
56
60
  return /* @__PURE__ */ jsx(
57
61
  "svg",
@@ -62,6 +66,7 @@ function DiscordIcon({ size }) {
62
66
  fill: "none",
63
67
  xmlns: "http://www.w3.org/2000/svg",
64
68
  "aria-hidden": "true",
69
+ className,
65
70
  children: /* @__PURE__ */ jsx(
66
71
  "path",
67
72
  {
@@ -72,7 +77,7 @@ function DiscordIcon({ size }) {
72
77
  }
73
78
  );
74
79
  }
75
- function SpinnerIcon({ size }) {
80
+ function SpinnerIcon({ size, className }) {
76
81
  const safeSize = getSafeSize(size, 20);
77
82
  return /* @__PURE__ */ jsxs(
78
83
  "svg",
@@ -83,39 +88,26 @@ function SpinnerIcon({ size }) {
83
88
  fill: "none",
84
89
  xmlns: "http://www.w3.org/2000/svg",
85
90
  "aria-hidden": "true",
91
+ className,
86
92
  children: [
87
93
  /* @__PURE__ */ jsx(
88
94
  "circle",
89
95
  {
90
96
  cx: "12",
91
97
  cy: "12",
92
- r: "10",
98
+ r: "9",
93
99
  stroke: "currentColor",
94
- strokeWidth: "4",
95
- strokeLinecap: "round",
96
- strokeDasharray: "60",
97
- strokeDashoffset: "20",
98
- opacity: "0.25"
100
+ strokeWidth: "3",
101
+ opacity: "0.22"
99
102
  }
100
103
  ),
101
104
  /* @__PURE__ */ jsx(
102
105
  "path",
103
106
  {
104
- d: "M12 2C6.477 2 2 6.477 2 12",
107
+ d: "M12 3a9 9 0 0 1 9 9",
105
108
  stroke: "currentColor",
106
- strokeWidth: "4",
107
- strokeLinecap: "round",
108
- children: /* @__PURE__ */ jsx(
109
- "animateTransform",
110
- {
111
- attributeName: "transform",
112
- type: "rotate",
113
- from: "0 12 12",
114
- to: "360 12 12",
115
- dur: "1s",
116
- repeatCount: "indefinite"
117
- }
118
- )
109
+ strokeWidth: "3",
110
+ strokeLinecap: "round"
119
111
  }
120
112
  )
121
113
  ]
@@ -123,8 +115,408 @@ function SpinnerIcon({ size }) {
123
115
  );
124
116
  }
125
117
 
118
+ // src/button-loading-indicator.tsx
119
+ import { jsx as jsx2 } from "react/jsx-runtime";
120
+ function SpinnerLoadingIndicator({ size }) {
121
+ return /* @__PURE__ */ jsx2(SpinnerIcon, { size, className: "sublime-button__spinner" });
122
+ }
123
+ var LOADING_INDICATORS = {
124
+ spinner: SpinnerLoadingIndicator
125
+ };
126
+ function ButtonLoadingIndicator({
127
+ animation = "spinner",
128
+ size = 18
129
+ }) {
130
+ const LoadingIndicator = LOADING_INDICATORS[animation];
131
+ return /* @__PURE__ */ jsx2(LoadingIndicator, { size });
132
+ }
133
+
134
+ // src/use-button-animation.ts
135
+ import { useCallback, useEffect, useRef, useState } from "react";
136
+ var PRESS_RELEASE_DURATION = 180;
137
+ function useButtonAnimation(animation = "press") {
138
+ const [phase, setPhase] = useState("idle");
139
+ const timeoutRef = useRef(null);
140
+ const clearExistingTimeout = useCallback(() => {
141
+ if (timeoutRef.current) {
142
+ clearTimeout(timeoutRef.current);
143
+ timeoutRef.current = null;
144
+ }
145
+ }, []);
146
+ useEffect(() => {
147
+ return () => {
148
+ clearExistingTimeout();
149
+ };
150
+ }, [clearExistingTimeout]);
151
+ const handlePressStart = useCallback(() => {
152
+ if (!animation) {
153
+ return;
154
+ }
155
+ clearExistingTimeout();
156
+ setPhase("pressed");
157
+ }, [animation, clearExistingTimeout]);
158
+ const handlePressEnd = useCallback(() => {
159
+ if (!animation || phase !== "pressed") {
160
+ return;
161
+ }
162
+ setPhase("releasing");
163
+ timeoutRef.current = setTimeout(() => {
164
+ setPhase("idle");
165
+ }, PRESS_RELEASE_DURATION);
166
+ }, [animation, phase]);
167
+ const handleBlur = useCallback(() => {
168
+ clearExistingTimeout();
169
+ setPhase("idle");
170
+ }, [clearExistingTimeout]);
171
+ const handleKeyDown = useCallback(
172
+ (event) => {
173
+ if (event.repeat) {
174
+ return;
175
+ }
176
+ if (event.key === " " || event.key === "Enter") {
177
+ handlePressStart();
178
+ }
179
+ },
180
+ [handlePressStart]
181
+ );
182
+ const handleKeyUp = useCallback(
183
+ (event) => {
184
+ if (event.key === " " || event.key === "Enter") {
185
+ handlePressEnd();
186
+ }
187
+ },
188
+ [handlePressEnd]
189
+ );
190
+ const getAnimationClass = () => {
191
+ if (!animation) {
192
+ return "";
193
+ }
194
+ if (phase === "pressed") {
195
+ return "sublime-button-pressed";
196
+ }
197
+ if (phase === "releasing") {
198
+ return "animate-sublime-button-press-release";
199
+ }
200
+ return "";
201
+ };
202
+ return {
203
+ animationClassName: getAnimationClass(),
204
+ eventHandlers: {
205
+ onBlur: handleBlur,
206
+ onKeyDown: handleKeyDown,
207
+ onKeyUp: handleKeyUp,
208
+ onMouseDown: handlePressStart,
209
+ onMouseLeave: handlePressEnd,
210
+ onMouseUp: handlePressEnd,
211
+ onTouchEnd: handlePressEnd,
212
+ onTouchStart: handlePressStart
213
+ }
214
+ };
215
+ }
216
+
217
+ // src/runtime-styles.ts
218
+ import { useInsertionEffect } from "react";
219
+ var AUTH_UI_RUNTIME_STYLE_ID = "sublime-auth-ui-runtime-styles";
220
+ var AUTH_UI_RUNTIME_STYLES = `
221
+ .sublime-button {
222
+ --sublime-button-gap: var(--sublime-space-3, 0.75rem);
223
+ --sublime-button-padding-x: var(--sublime-space-button-x, 1rem);
224
+ --sublime-button-padding-y: var(--sublime-space-button-y, 0.75rem);
225
+ --sublime-button-height: var(--sublime-size-button-height-md, 2.75rem);
226
+ --sublime-button-radius: var(--sublime-radius-button, 0.875rem);
227
+ --sublime-button-font-family: var(--sublime-font-family-sans, ui-sans-serif, system-ui, sans-serif);
228
+ --sublime-button-font-size: var(--sublime-font-size-sm, 0.875rem);
229
+ --sublime-button-font-weight: var(--sublime-font-weight-medium, 500);
230
+ --sublime-button-line-height: var(--sublime-line-height-tight, 1.15);
231
+ --sublime-button-visual-size: 1.25rem;
232
+ --sublime-button-transition: var(--sublime-transition-button, background-color 160ms cubic-bezier(0.4, 0, 0.2, 1), border-color 160ms cubic-bezier(0.4, 0, 0.2, 1), box-shadow 160ms cubic-bezier(0.4, 0, 0.2, 1), color 160ms cubic-bezier(0.4, 0, 0.2, 1), transform 160ms cubic-bezier(0.4, 0, 0.2, 1));
233
+ --sublime-button-bg: var(--sublime-color-surface-1, #ffffff);
234
+ --sublime-button-bg-hover: var(--sublime-color-surface-1-hover, #f8fafc);
235
+ --sublime-button-bg-active: var(--sublime-color-surface-1-active, #eef2f7);
236
+ --sublime-button-color: var(--sublime-color-text-primary, #111827);
237
+ --sublime-button-color-hover: var(--sublime-color-text-primary, #111827);
238
+ --sublime-button-border: var(--sublime-color-border-primary, #d1d5db);
239
+ --sublime-button-border-hover: var(--sublime-color-border-primary-hover, #9ca3af);
240
+ --sublime-button-border-active: var(--sublime-color-border-primary-active, #6b7280);
241
+ --sublime-button-shadow: var(--sublime-shadow-button, 0 1px 2px rgb(15 23 42 / 0.08));
242
+ --sublime-button-shadow-hover: var(--sublime-shadow-button-hover, 0 8px 20px rgb(15 23 42 / 0.12));
243
+ --sublime-button-shadow-active: var(--sublime-shadow-button-active, inset 0 1px 2px rgb(15 23 42 / 0.14));
244
+ --sublime-button-focus-ring: var(--sublime-color-focus-ring, var(--sublime-color-interactive-accent, #2563eb));
245
+ --sublime-button-focus-ring-offset: var(--sublime-color-focus-ring-offset, var(--sublime-color-surface-0, #ffffff));
246
+ position: relative;
247
+ display: inline-flex;
248
+ min-height: var(--sublime-button-height);
249
+ align-items: center;
250
+ justify-content: center;
251
+ gap: var(--sublime-button-gap);
252
+ padding: var(--sublime-button-padding-y) var(--sublime-button-padding-x);
253
+ border: 1px solid var(--sublime-button-border);
254
+ border-radius: var(--sublime-button-radius);
255
+ background: var(--sublime-button-bg);
256
+ color: var(--sublime-button-color);
257
+ box-shadow: var(--sublime-button-shadow);
258
+ font-family: var(--sublime-button-font-family);
259
+ font-size: var(--sublime-button-font-size);
260
+ font-weight: var(--sublime-button-font-weight);
261
+ line-height: var(--sublime-button-line-height);
262
+ cursor: pointer;
263
+ user-select: none;
264
+ text-decoration: none;
265
+ white-space: nowrap;
266
+ vertical-align: middle;
267
+ isolation: isolate;
268
+ overflow: hidden;
269
+ appearance: none;
270
+ -webkit-tap-highlight-color: transparent;
271
+ transition: var(--sublime-button-transition);
272
+ }
273
+
274
+ .sublime-button:hover:not(:disabled) {
275
+ background: var(--sublime-button-bg-hover);
276
+ color: var(--sublime-button-color-hover);
277
+ border-color: var(--sublime-button-border-hover);
278
+ box-shadow: var(--sublime-button-shadow-hover);
279
+ }
280
+
281
+ .sublime-button:active:not(:disabled) {
282
+ background: var(--sublime-button-bg-active);
283
+ border-color: var(--sublime-button-border-active);
284
+ box-shadow: var(--sublime-button-shadow-active);
285
+ }
286
+
287
+ .sublime-button:focus {
288
+ outline: none;
289
+ }
290
+
291
+ .sublime-button:focus-visible {
292
+ box-shadow:
293
+ 0 0 0 2px var(--sublime-button-focus-ring-offset),
294
+ 0 0 0 4px var(--sublime-button-focus-ring),
295
+ var(--sublime-button-shadow-hover);
296
+ }
297
+
298
+ .sublime-button:disabled {
299
+ cursor: not-allowed;
300
+ opacity: 0.6;
301
+ box-shadow: none;
302
+ }
303
+
304
+ .sublime-button[data-loading='true'] {
305
+ cursor: progress;
306
+ }
307
+
308
+ .sublime-button[data-loading='true']:disabled {
309
+ opacity: 0.78;
310
+ }
311
+
312
+ .sublime-button[data-icon-only='true'] {
313
+ min-width: var(--sublime-button-height);
314
+ padding-inline: calc(var(--sublime-button-padding-y) + 0.125rem);
315
+ }
316
+
317
+ .sublime-button__content {
318
+ display: inline-flex;
319
+ width: 100%;
320
+ align-items: center;
321
+ justify-content: center;
322
+ gap: inherit;
323
+ }
324
+
325
+ .sublime-button__visual,
326
+ .sublime-button__label {
327
+ display: inline-flex;
328
+ align-items: center;
329
+ }
330
+
331
+ .sublime-button__visual {
332
+ flex-shrink: 0;
333
+ justify-content: center;
334
+ min-width: var(--sublime-button-visual-size);
335
+ }
336
+
337
+ .sublime-button__visual svg {
338
+ display: block;
339
+ }
340
+
341
+ .sublime-button__label {
342
+ min-width: 0;
343
+ }
344
+
345
+ .sublime-button--primary {
346
+ --sublime-button-bg: var(--sublime-color-interactive-primary, #111827);
347
+ --sublime-button-bg-hover: var(--sublime-color-interactive-primary-hover, #1f2937);
348
+ --sublime-button-bg-active: var(--sublime-color-interactive-primary-active, #0f172a);
349
+ --sublime-button-color: var(--sublime-color-interactive-primary-text, #f9fafb);
350
+ --sublime-button-color-hover: var(--sublime-color-interactive-primary-text, #f9fafb);
351
+ --sublime-button-border: var(--sublime-color-interactive-primary, #111827);
352
+ --sublime-button-border-hover: var(--sublime-color-interactive-primary-hover, #1f2937);
353
+ --sublime-button-border-active: var(--sublime-color-interactive-primary-active, #0f172a);
354
+ }
355
+
356
+ .sublime-button--secondary {
357
+ --sublime-button-bg: var(--sublime-color-surface-1, #ffffff);
358
+ --sublime-button-bg-hover: var(--sublime-color-surface-1-hover, #f8fafc);
359
+ --sublime-button-bg-active: var(--sublime-color-surface-1-active, #eef2f7);
360
+ --sublime-button-color: var(--sublime-color-text-primary, #111827);
361
+ --sublime-button-color-hover: var(--sublime-color-text-primary, #111827);
362
+ --sublime-button-border: var(--sublime-color-border-primary, #d1d5db);
363
+ --sublime-button-border-hover: var(--sublime-color-border-primary-hover, #9ca3af);
364
+ --sublime-button-border-active: var(--sublime-color-border-primary-active, #6b7280);
365
+ }
366
+
367
+ .sublime-auth-button[data-provider='discord'] .sublime-button__visual {
368
+ color: #5865f2;
369
+ }
370
+
371
+ .sublime-auth-button[data-loading='true'] .sublime-button__visual {
372
+ color: currentColor;
373
+ }
374
+
375
+ @keyframes sublime-button-press-release {
376
+ 0% {
377
+ transform: translateY(1px) scale(0.985);
378
+ box-shadow: var(--sublime-button-shadow-active);
379
+ }
380
+ 100% {
381
+ transform: translateY(0) scale(1);
382
+ box-shadow: var(--sublime-button-shadow);
383
+ }
384
+ }
385
+
386
+ @keyframes sublime-button-spinner {
387
+ from {
388
+ transform: rotate(0deg);
389
+ }
390
+ to {
391
+ transform: rotate(360deg);
392
+ }
393
+ }
394
+
395
+ .sublime-button-pressed {
396
+ transform: translateY(1px) scale(0.985);
397
+ box-shadow: var(--sublime-button-shadow-active);
398
+ }
399
+
400
+ .animate-sublime-button-press-release {
401
+ animation: sublime-button-press-release 180ms var(--sublime-ease-out, cubic-bezier(0, 0, 0.2, 1));
402
+ }
403
+
404
+ .sublime-button__spinner {
405
+ animation: sublime-button-spinner 720ms linear infinite;
406
+ transform-origin: center;
407
+ }
408
+
409
+ @media (prefers-reduced-motion: reduce) {
410
+ .sublime-button,
411
+ .animate-sublime-button-press-release {
412
+ animation-duration: 0.01ms !important;
413
+ animation-iteration-count: 1 !important;
414
+ transition-duration: 0.01ms !important;
415
+ }
416
+
417
+ .sublime-button__spinner {
418
+ animation-duration: 1.6s !important;
419
+ }
420
+ }
421
+ `;
422
+ function useAuthUiRuntimeStyles() {
423
+ useInsertionEffect(() => {
424
+ if (typeof document === "undefined") {
425
+ return;
426
+ }
427
+ if (document.getElementById(AUTH_UI_RUNTIME_STYLE_ID)) {
428
+ return;
429
+ }
430
+ const styleElement = document.createElement("style");
431
+ styleElement.id = AUTH_UI_RUNTIME_STYLE_ID;
432
+ styleElement.textContent = AUTH_UI_RUNTIME_STYLES;
433
+ document.head.prepend(styleElement);
434
+ }, []);
435
+ }
436
+
437
+ // src/base-button.tsx
438
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
439
+ function mergeClassNames(...classNames) {
440
+ return classNames.filter(Boolean).join(" ");
441
+ }
442
+ function composeEventHandlers(internalHandler, externalHandler) {
443
+ if (!internalHandler) {
444
+ return externalHandler;
445
+ }
446
+ if (!externalHandler) {
447
+ return internalHandler;
448
+ }
449
+ return (event) => {
450
+ internalHandler(event);
451
+ externalHandler(event);
452
+ };
453
+ }
454
+ var BaseButton = forwardRef(
455
+ function BaseButton2(props, forwardedRef) {
456
+ const {
457
+ animation = "press",
458
+ "aria-busy": ariaBusy,
459
+ children,
460
+ className,
461
+ disabled = false,
462
+ isIconOnly = false,
463
+ leadingVisual,
464
+ loading = false,
465
+ loadingAnimation = "spinner",
466
+ type = "button",
467
+ variant = "secondary",
468
+ onBlur,
469
+ onKeyDown,
470
+ onKeyUp,
471
+ onMouseDown,
472
+ onMouseLeave,
473
+ onMouseUp,
474
+ onTouchEnd,
475
+ onTouchStart,
476
+ ...otherProps
477
+ } = props;
478
+ useAuthUiRuntimeStyles();
479
+ const { animationClassName, eventHandlers } = useButtonAnimation(
480
+ disabled || loading ? null : animation
481
+ );
482
+ const mergedClassName = mergeClassNames(
483
+ "sublime-button",
484
+ `sublime-button--${variant}`,
485
+ animationClassName,
486
+ className
487
+ );
488
+ const visualContent = loading ? /* @__PURE__ */ jsx3(ButtonLoadingIndicator, { animation: loadingAnimation, size: 18 }) : leadingVisual ?? (isIconOnly ? children : void 0);
489
+ const labelContent = isIconOnly ? null : children;
490
+ return /* @__PURE__ */ jsx3(
491
+ Button,
492
+ {
493
+ ref: forwardedRef,
494
+ type,
495
+ disabled: disabled || loading,
496
+ className: mergedClassName,
497
+ "data-icon-only": isIconOnly ? "true" : void 0,
498
+ "data-loading": loading ? "true" : void 0,
499
+ "aria-busy": loading ? true : ariaBusy,
500
+ ...otherProps,
501
+ onBlur: composeEventHandlers(eventHandlers.onBlur, onBlur),
502
+ onKeyDown: composeEventHandlers(eventHandlers.onKeyDown, onKeyDown),
503
+ onKeyUp: composeEventHandlers(eventHandlers.onKeyUp, onKeyUp),
504
+ onMouseDown: composeEventHandlers(eventHandlers.onMouseDown, onMouseDown),
505
+ onMouseLeave: composeEventHandlers(eventHandlers.onMouseLeave, onMouseLeave),
506
+ onMouseUp: composeEventHandlers(eventHandlers.onMouseUp, onMouseUp),
507
+ onTouchEnd: composeEventHandlers(eventHandlers.onTouchEnd, onTouchEnd),
508
+ onTouchStart: composeEventHandlers(eventHandlers.onTouchStart, onTouchStart),
509
+ children: /* @__PURE__ */ jsxs2("span", { className: "sublime-button__content", children: [
510
+ visualContent ? /* @__PURE__ */ jsx3("span", { className: "sublime-button__visual", children: visualContent }) : null,
511
+ labelContent !== null && labelContent !== void 0 ? /* @__PURE__ */ jsx3("span", { className: "sublime-button__label", children: labelContent }) : null
512
+ ] })
513
+ }
514
+ );
515
+ }
516
+ );
517
+
126
518
  // src/oauth-button.tsx
127
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
519
+ import { jsx as jsx4 } from "react/jsx-runtime";
128
520
  var PROVIDER_NAMES = {
129
521
  google: "Google",
130
522
  discord: "Discord"
@@ -133,51 +525,46 @@ var PROVIDER_ICONS = {
133
525
  google: GoogleIcon,
134
526
  discord: DiscordIcon
135
527
  };
136
- var SENSIBLE_DEFAULTS = ["cursor-pointer"];
137
- function mergeButtonClasses(userClassName, isDisabled) {
138
- const userClasses = userClassName?.trim() ?? "";
139
- const neededDefaults = SENSIBLE_DEFAULTS.filter(
140
- (defaultClass) => !userClasses.includes(defaultClass)
141
- );
142
- if (isDisabled && !userClasses.includes("cursor-not-allowed")) {
143
- neededDefaults.push("cursor-not-allowed");
144
- }
145
- if (neededDefaults.length === 0) {
146
- return userClasses;
147
- }
148
- return `${neededDefaults.join(" ")} ${userClasses}`.trim();
528
+ function mergeClassNames2(...classNames) {
529
+ return classNames.filter(Boolean).join(" ");
149
530
  }
150
- var OAuthButton = forwardRef(
531
+ var OAuthButton = forwardRef2(
151
532
  function OAuthButton2(props, forwardedRef) {
152
533
  const {
534
+ "aria-label": ariaLabel,
153
535
  provider,
154
536
  onClick,
155
537
  loading = false,
538
+ loadingAnimation = "spinner",
539
+ disabled = false,
540
+ variant = "secondary",
541
+ animation = "press",
156
542
  className,
157
543
  children,
158
- disabled = false,
159
544
  ...otherProps
160
545
  } = props;
161
- const isDisabled = disabled || loading;
546
+ const isIconOnly = children === null;
162
547
  const Icon = PROVIDER_ICONS[provider];
163
548
  const defaultText = `Continuar con ${PROVIDER_NAMES[provider]}`;
164
- const mergedClassName = mergeButtonClasses(className, isDisabled);
165
- return /* @__PURE__ */ jsx2(
166
- Button,
549
+ const buttonLabel = loading ? children ?? "Conectando..." : children ?? defaultText;
550
+ const resolvedAriaLabel = ariaLabel ?? (isIconOnly ? defaultText : void 0);
551
+ return /* @__PURE__ */ jsx4(
552
+ BaseButton,
167
553
  {
168
554
  ref: forwardedRef,
169
555
  onClick,
170
- disabled: isDisabled,
171
- "aria-busy": loading,
172
- className: mergedClassName,
556
+ disabled,
557
+ animation,
558
+ variant,
559
+ loading,
560
+ loadingAnimation,
561
+ isIconOnly,
562
+ leadingVisual: /* @__PURE__ */ jsx4(Icon, { size: 20 }),
563
+ className: mergeClassNames2("sublime-auth-button", className),
564
+ "data-provider": provider,
565
+ "aria-label": resolvedAriaLabel,
173
566
  ...otherProps,
174
- children: loading ? /* @__PURE__ */ jsxs2(Fragment, { children: [
175
- /* @__PURE__ */ jsx2(SpinnerIcon, {}),
176
- children !== null && /* @__PURE__ */ jsx2("span", { children: children ?? "Conectando..." })
177
- ] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
178
- /* @__PURE__ */ jsx2(Icon, {}),
179
- children !== null && /* @__PURE__ */ jsx2("span", { children: children ?? defaultText })
180
- ] })
567
+ children: buttonLabel
181
568
  }
182
569
  );
183
570
  }
@@ -186,5 +573,5 @@ export {
186
573
  DiscordIcon,
187
574
  GoogleIcon,
188
575
  OAuthButton,
189
- SpinnerIcon
576
+ useButtonAnimation
190
577
  };
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@sublimee/auth-ui",
3
- "version": "0.1.1",
4
- "description": "Headless authentication UI components for Sublime",
3
+ "version": "0.1.13",
4
+ "description": "Production-ready authentication UI components for Sublime",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",
8
8
  "files": [
9
9
  "dist",
10
- "src"
10
+ "src",
11
+ "AI_INDEX.md"
11
12
  ],
12
13
  "exports": {
13
14
  ".": {
@@ -15,6 +16,7 @@
15
16
  "import": "./dist/index.mjs",
16
17
  "require": "./dist/index.js"
17
18
  },
19
+ "./animations.css": "./dist/animations.css",
18
20
  "./package.json": "./package.json"
19
21
  },
20
22
  "publishConfig": {
@@ -31,14 +33,15 @@
31
33
  "oauth",
32
34
  "ui",
33
35
  "components",
34
- "headless",
36
+ "semantic",
35
37
  "base-ui"
36
38
  ],
37
39
  "author": "Sublime Team",
38
40
  "license": "MIT",
39
41
  "peerDependencies": {
40
42
  "react": "^19.0.0",
41
- "react-dom": "^19.0.0"
43
+ "react-dom": "^19.0.0",
44
+ "@sublimee/tokens": "0.1.11"
42
45
  },
43
46
  "dependencies": {
44
47
  "@base-ui/react": "^1.0.0"
@@ -50,7 +53,7 @@
50
53
  "typescript": "^5"
51
54
  },
52
55
  "scripts": {
53
- "build": "tsup src/index.ts --format cjs,esm --dts --clean",
56
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean && cp src/animations.css dist/animations.css",
54
57
  "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
55
58
  "typecheck": "tsc --noEmit"
56
59
  }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @sublimee/auth-ui runtime animations
3
+ *
4
+ * Optional legacy export.
5
+ * Most consumers should not need to import this file because auth-ui now
6
+ * injects its runtime button styles automatically.
7
+ */
8
+
9
+ @keyframes sublime-button-press-release {
10
+ 0% {
11
+ transform: translateY(1px) scale(0.985);
12
+ box-shadow: var(--sublime-button-shadow-active);
13
+ }
14
+ 100% {
15
+ transform: translateY(0) scale(1);
16
+ box-shadow: var(--sublime-button-shadow);
17
+ }
18
+ }
19
+
20
+ @keyframes sublime-button-spinner {
21
+ from {
22
+ transform: rotate(0deg);
23
+ }
24
+ to {
25
+ transform: rotate(360deg);
26
+ }
27
+ }
28
+
29
+ .sublime-button-pressed {
30
+ transform: translateY(1px) scale(0.985);
31
+ box-shadow: var(--sublime-button-shadow-active);
32
+ }
33
+
34
+ .animate-sublime-button-press-release {
35
+ animation: sublime-button-press-release 180ms var(--sublime-ease-out, cubic-bezier(0, 0, 0.2, 1));
36
+ }
37
+
38
+ .sublime-button__spinner {
39
+ animation: sublime-button-spinner 720ms linear infinite;
40
+ transform-origin: center;
41
+ }
42
+
43
+ @media (prefers-reduced-motion: reduce) {
44
+ .animate-sublime-button-press-release {
45
+ animation-duration: 0.01ms !important;
46
+ animation-iteration-count: 1 !important;
47
+ }
48
+
49
+ .sublime-button__spinner {
50
+ animation-duration: 1.6s !important;
51
+ }
52
+ }