@sublimee/auth-ui 0.1.13 → 0.1.15

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/AI_INDEX.md CHANGED
@@ -11,12 +11,13 @@ Token-efficient entry point for AI agents reading the installed npm package.
11
11
  ## First Move
12
12
 
13
13
  ```tsx
14
- import "@sublimee/tokens/tokens.css";
15
14
  import { OAuthButton } from "@sublimee/auth-ui";
16
15
 
17
16
  <OAuthButton provider="google" />
18
17
  ```
19
18
 
19
+ Import `@sublimee/tokens/tokens.css` only when you want shared app-wide theming.
20
+
20
21
  ## Current Public Surface
21
22
 
22
23
  - `OAuthButton`
package/README.md CHANGED
@@ -13,13 +13,18 @@ If you are an AI agent reading the installed npm package directly, start with [A
13
13
  ## First Move
14
14
 
15
15
  ```tsx
16
- import "@sublimee/tokens/tokens.css";
17
16
  import { OAuthButton } from "@sublimee/auth-ui";
18
17
 
19
18
  <OAuthButton provider="google" />
20
19
  ```
21
20
 
22
- The package injects its runtime button styles automatically. No extra component stylesheet import is required for the normal path.
21
+ The package injects its runtime button styles automatically. No extra component stylesheet import or `@sublimee/tokens` install is required for the normal path.
22
+
23
+ If you want shared Sublime theming across your app, install `@sublimee/tokens` and import its CSS once:
24
+
25
+ ```tsx
26
+ import "@sublimee/tokens/tokens.css";
27
+ ```
23
28
 
24
29
  ## Current Public Surface
25
30
 
@@ -94,7 +99,7 @@ The package injects its runtime button styles automatically. No extra component
94
99
  ## Customization Order
95
100
 
96
101
  Use this order:
97
- 1. import tokens
102
+ 1. install and import `@sublimee/tokens` when you want shared app-wide theming
98
103
  2. override semantic CSS custom properties
99
104
  3. use props like `variant`, `loading`, and `disabled`
100
105
  4. use `className` only for edge-case local adjustments
@@ -118,6 +123,7 @@ For this package, zero-setup means:
118
123
  - the button should look like a button on first render,
119
124
  - provider icon and layout should be built in,
120
125
  - the consumer should not rebuild spacing, border, focus, or interaction states,
126
+ - the consumer should not need `@sublimee/tokens` for a usable default render,
121
127
  - customization should extend the component rather than complete it.
122
128
 
123
129
  ## Notes
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ "use client";
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -245,7 +246,7 @@ function useButtonAnimation(animation = "press") {
245
246
 
246
247
  // src/runtime-styles.ts
247
248
  var import_react2 = require("react");
248
- var AUTH_UI_RUNTIME_STYLE_ID = "sublime-auth-ui-runtime-styles";
249
+ var AUTH_UI_RUNTIME_STYLE_HREF = "sublime-auth-ui-runtime-styles";
249
250
  var AUTH_UI_RUNTIME_STYLES = `
250
251
  .sublime-button {
251
252
  --sublime-button-gap: var(--sublime-space-3, 0.75rem);
@@ -393,6 +394,35 @@ var AUTH_UI_RUNTIME_STYLES = `
393
394
  --sublime-button-border-active: var(--sublime-color-border-primary-active, #6b7280);
394
395
  }
395
396
 
397
+ .dark .sublime-button,
398
+ [data-theme='dark'] .sublime-button {
399
+ --sublime-button-focus-ring-offset: var(--sublime-color-focus-ring-offset, #0f172a);
400
+ }
401
+
402
+ .dark .sublime-button--primary,
403
+ [data-theme='dark'] .sublime-button--primary {
404
+ --sublime-button-bg: var(--sublime-color-interactive-primary, #f8fafc);
405
+ --sublime-button-bg-hover: var(--sublime-color-interactive-primary-hover, #e2e8f0);
406
+ --sublime-button-bg-active: var(--sublime-color-interactive-primary-active, #cbd5e1);
407
+ --sublime-button-color: var(--sublime-color-interactive-primary-text, #0f172a);
408
+ --sublime-button-color-hover: var(--sublime-color-interactive-primary-text, #0f172a);
409
+ --sublime-button-border: var(--sublime-color-interactive-primary, #f8fafc);
410
+ --sublime-button-border-hover: var(--sublime-color-interactive-primary-hover, #e2e8f0);
411
+ --sublime-button-border-active: var(--sublime-color-interactive-primary-active, #cbd5e1);
412
+ }
413
+
414
+ .dark .sublime-button--secondary,
415
+ [data-theme='dark'] .sublime-button--secondary {
416
+ --sublime-button-bg: var(--sublime-color-surface-1, #171717);
417
+ --sublime-button-bg-hover: var(--sublime-color-surface-1-hover, #262626);
418
+ --sublime-button-bg-active: var(--sublime-color-surface-1-active, #404040);
419
+ --sublime-button-color: var(--sublime-color-text-primary, #fafafa);
420
+ --sublime-button-color-hover: var(--sublime-color-text-primary, #fafafa);
421
+ --sublime-button-border: var(--sublime-color-border-primary, #404040);
422
+ --sublime-button-border-hover: var(--sublime-color-border-primary-hover, #525252);
423
+ --sublime-button-border-active: var(--sublime-color-border-primary-active, #737373);
424
+ }
425
+
396
426
  .sublime-auth-button[data-provider='discord'] .sublime-button__visual {
397
427
  color: #5865f2;
398
428
  }
@@ -447,20 +477,44 @@ var AUTH_UI_RUNTIME_STYLES = `
447
477
  animation-duration: 1.6s !important;
448
478
  }
449
479
  }
480
+
481
+ @media (prefers-color-scheme: dark) {
482
+ :root:not([data-theme='light']):not(.light) .sublime-button {
483
+ --sublime-button-focus-ring-offset: var(--sublime-color-focus-ring-offset, #0f172a);
484
+ }
485
+
486
+ :root:not([data-theme='light']):not(.light) .sublime-button--primary {
487
+ --sublime-button-bg: var(--sublime-color-interactive-primary, #f8fafc);
488
+ --sublime-button-bg-hover: var(--sublime-color-interactive-primary-hover, #e2e8f0);
489
+ --sublime-button-bg-active: var(--sublime-color-interactive-primary-active, #cbd5e1);
490
+ --sublime-button-color: var(--sublime-color-interactive-primary-text, #0f172a);
491
+ --sublime-button-color-hover: var(--sublime-color-interactive-primary-text, #0f172a);
492
+ --sublime-button-border: var(--sublime-color-interactive-primary, #f8fafc);
493
+ --sublime-button-border-hover: var(--sublime-color-interactive-primary-hover, #e2e8f0);
494
+ --sublime-button-border-active: var(--sublime-color-interactive-primary-active, #cbd5e1);
495
+ }
496
+
497
+ :root:not([data-theme='light']):not(.light) .sublime-button--secondary {
498
+ --sublime-button-bg: var(--sublime-color-surface-1, #171717);
499
+ --sublime-button-bg-hover: var(--sublime-color-surface-1-hover, #262626);
500
+ --sublime-button-bg-active: var(--sublime-color-surface-1-active, #404040);
501
+ --sublime-button-color: var(--sublime-color-text-primary, #fafafa);
502
+ --sublime-button-color-hover: var(--sublime-color-text-primary, #fafafa);
503
+ --sublime-button-border: var(--sublime-color-border-primary, #404040);
504
+ --sublime-button-border-hover: var(--sublime-color-border-primary-hover, #525252);
505
+ --sublime-button-border-active: var(--sublime-color-border-primary-active, #737373);
506
+ }
507
+ }
450
508
  `;
451
- function useAuthUiRuntimeStyles() {
452
- (0, import_react2.useInsertionEffect)(() => {
453
- if (typeof document === "undefined") {
454
- return;
455
- }
456
- if (document.getElementById(AUTH_UI_RUNTIME_STYLE_ID)) {
457
- return;
458
- }
459
- const styleElement = document.createElement("style");
460
- styleElement.id = AUTH_UI_RUNTIME_STYLE_ID;
461
- styleElement.textContent = AUTH_UI_RUNTIME_STYLES;
462
- document.head.prepend(styleElement);
463
- }, []);
509
+ function AuthUiRuntimeStyles() {
510
+ return (0, import_react2.createElement)(
511
+ "style",
512
+ {
513
+ href: AUTH_UI_RUNTIME_STYLE_HREF,
514
+ precedence: "medium"
515
+ },
516
+ AUTH_UI_RUNTIME_STYLES
517
+ );
464
518
  }
465
519
 
466
520
  // src/base-button.tsx
@@ -504,7 +558,6 @@ var BaseButton = (0, import_react3.forwardRef)(
504
558
  onTouchStart,
505
559
  ...otherProps
506
560
  } = props;
507
- useAuthUiRuntimeStyles();
508
561
  const { animationClassName, eventHandlers } = useButtonAnimation(
509
562
  disabled || loading ? null : animation
510
563
  );
@@ -516,31 +569,34 @@ var BaseButton = (0, import_react3.forwardRef)(
516
569
  );
517
570
  const visualContent = loading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ButtonLoadingIndicator, { animation: loadingAnimation, size: 18 }) : leadingVisual ?? (isIconOnly ? children : void 0);
518
571
  const labelContent = isIconOnly ? null : children;
519
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
520
- import_button.Button,
521
- {
522
- ref: forwardedRef,
523
- type,
524
- disabled: disabled || loading,
525
- className: mergedClassName,
526
- "data-icon-only": isIconOnly ? "true" : void 0,
527
- "data-loading": loading ? "true" : void 0,
528
- "aria-busy": loading ? true : ariaBusy,
529
- ...otherProps,
530
- onBlur: composeEventHandlers(eventHandlers.onBlur, onBlur),
531
- onKeyDown: composeEventHandlers(eventHandlers.onKeyDown, onKeyDown),
532
- onKeyUp: composeEventHandlers(eventHandlers.onKeyUp, onKeyUp),
533
- onMouseDown: composeEventHandlers(eventHandlers.onMouseDown, onMouseDown),
534
- onMouseLeave: composeEventHandlers(eventHandlers.onMouseLeave, onMouseLeave),
535
- onMouseUp: composeEventHandlers(eventHandlers.onMouseUp, onMouseUp),
536
- onTouchEnd: composeEventHandlers(eventHandlers.onTouchEnd, onTouchEnd),
537
- onTouchStart: composeEventHandlers(eventHandlers.onTouchStart, onTouchStart),
538
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "sublime-button__content", children: [
539
- visualContent ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "sublime-button__visual", children: visualContent }) : null,
540
- labelContent !== null && labelContent !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "sublime-button__label", children: labelContent }) : null
541
- ] })
542
- }
543
- );
572
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
573
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AuthUiRuntimeStyles, {}),
574
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
575
+ import_button.Button,
576
+ {
577
+ ref: forwardedRef,
578
+ type,
579
+ disabled: disabled || loading,
580
+ className: mergedClassName,
581
+ "data-icon-only": isIconOnly ? "true" : void 0,
582
+ "data-loading": loading ? "true" : void 0,
583
+ "aria-busy": loading ? true : ariaBusy,
584
+ ...otherProps,
585
+ onBlur: composeEventHandlers(eventHandlers.onBlur, onBlur),
586
+ onKeyDown: composeEventHandlers(eventHandlers.onKeyDown, onKeyDown),
587
+ onKeyUp: composeEventHandlers(eventHandlers.onKeyUp, onKeyUp),
588
+ onMouseDown: composeEventHandlers(eventHandlers.onMouseDown, onMouseDown),
589
+ onMouseLeave: composeEventHandlers(eventHandlers.onMouseLeave, onMouseLeave),
590
+ onMouseUp: composeEventHandlers(eventHandlers.onMouseUp, onMouseUp),
591
+ onTouchEnd: composeEventHandlers(eventHandlers.onTouchEnd, onTouchEnd),
592
+ onTouchStart: composeEventHandlers(eventHandlers.onTouchStart, onTouchStart),
593
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "sublime-button__content", children: [
594
+ visualContent ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "sublime-button__visual", children: visualContent }) : null,
595
+ labelContent !== null && labelContent !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "sublime-button__label", children: labelContent }) : null
596
+ ] })
597
+ }
598
+ )
599
+ ] });
544
600
  }
545
601
  );
546
602
 
package/dist/index.mjs CHANGED
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  // src/oauth-button.tsx
2
4
  import { forwardRef as forwardRef2 } from "react";
3
5
 
@@ -215,8 +217,8 @@ function useButtonAnimation(animation = "press") {
215
217
  }
216
218
 
217
219
  // src/runtime-styles.ts
218
- import { useInsertionEffect } from "react";
219
- var AUTH_UI_RUNTIME_STYLE_ID = "sublime-auth-ui-runtime-styles";
220
+ import { createElement } from "react";
221
+ var AUTH_UI_RUNTIME_STYLE_HREF = "sublime-auth-ui-runtime-styles";
220
222
  var AUTH_UI_RUNTIME_STYLES = `
221
223
  .sublime-button {
222
224
  --sublime-button-gap: var(--sublime-space-3, 0.75rem);
@@ -364,6 +366,35 @@ var AUTH_UI_RUNTIME_STYLES = `
364
366
  --sublime-button-border-active: var(--sublime-color-border-primary-active, #6b7280);
365
367
  }
366
368
 
369
+ .dark .sublime-button,
370
+ [data-theme='dark'] .sublime-button {
371
+ --sublime-button-focus-ring-offset: var(--sublime-color-focus-ring-offset, #0f172a);
372
+ }
373
+
374
+ .dark .sublime-button--primary,
375
+ [data-theme='dark'] .sublime-button--primary {
376
+ --sublime-button-bg: var(--sublime-color-interactive-primary, #f8fafc);
377
+ --sublime-button-bg-hover: var(--sublime-color-interactive-primary-hover, #e2e8f0);
378
+ --sublime-button-bg-active: var(--sublime-color-interactive-primary-active, #cbd5e1);
379
+ --sublime-button-color: var(--sublime-color-interactive-primary-text, #0f172a);
380
+ --sublime-button-color-hover: var(--sublime-color-interactive-primary-text, #0f172a);
381
+ --sublime-button-border: var(--sublime-color-interactive-primary, #f8fafc);
382
+ --sublime-button-border-hover: var(--sublime-color-interactive-primary-hover, #e2e8f0);
383
+ --sublime-button-border-active: var(--sublime-color-interactive-primary-active, #cbd5e1);
384
+ }
385
+
386
+ .dark .sublime-button--secondary,
387
+ [data-theme='dark'] .sublime-button--secondary {
388
+ --sublime-button-bg: var(--sublime-color-surface-1, #171717);
389
+ --sublime-button-bg-hover: var(--sublime-color-surface-1-hover, #262626);
390
+ --sublime-button-bg-active: var(--sublime-color-surface-1-active, #404040);
391
+ --sublime-button-color: var(--sublime-color-text-primary, #fafafa);
392
+ --sublime-button-color-hover: var(--sublime-color-text-primary, #fafafa);
393
+ --sublime-button-border: var(--sublime-color-border-primary, #404040);
394
+ --sublime-button-border-hover: var(--sublime-color-border-primary-hover, #525252);
395
+ --sublime-button-border-active: var(--sublime-color-border-primary-active, #737373);
396
+ }
397
+
367
398
  .sublime-auth-button[data-provider='discord'] .sublime-button__visual {
368
399
  color: #5865f2;
369
400
  }
@@ -418,24 +449,48 @@ var AUTH_UI_RUNTIME_STYLES = `
418
449
  animation-duration: 1.6s !important;
419
450
  }
420
451
  }
452
+
453
+ @media (prefers-color-scheme: dark) {
454
+ :root:not([data-theme='light']):not(.light) .sublime-button {
455
+ --sublime-button-focus-ring-offset: var(--sublime-color-focus-ring-offset, #0f172a);
456
+ }
457
+
458
+ :root:not([data-theme='light']):not(.light) .sublime-button--primary {
459
+ --sublime-button-bg: var(--sublime-color-interactive-primary, #f8fafc);
460
+ --sublime-button-bg-hover: var(--sublime-color-interactive-primary-hover, #e2e8f0);
461
+ --sublime-button-bg-active: var(--sublime-color-interactive-primary-active, #cbd5e1);
462
+ --sublime-button-color: var(--sublime-color-interactive-primary-text, #0f172a);
463
+ --sublime-button-color-hover: var(--sublime-color-interactive-primary-text, #0f172a);
464
+ --sublime-button-border: var(--sublime-color-interactive-primary, #f8fafc);
465
+ --sublime-button-border-hover: var(--sublime-color-interactive-primary-hover, #e2e8f0);
466
+ --sublime-button-border-active: var(--sublime-color-interactive-primary-active, #cbd5e1);
467
+ }
468
+
469
+ :root:not([data-theme='light']):not(.light) .sublime-button--secondary {
470
+ --sublime-button-bg: var(--sublime-color-surface-1, #171717);
471
+ --sublime-button-bg-hover: var(--sublime-color-surface-1-hover, #262626);
472
+ --sublime-button-bg-active: var(--sublime-color-surface-1-active, #404040);
473
+ --sublime-button-color: var(--sublime-color-text-primary, #fafafa);
474
+ --sublime-button-color-hover: var(--sublime-color-text-primary, #fafafa);
475
+ --sublime-button-border: var(--sublime-color-border-primary, #404040);
476
+ --sublime-button-border-hover: var(--sublime-color-border-primary-hover, #525252);
477
+ --sublime-button-border-active: var(--sublime-color-border-primary-active, #737373);
478
+ }
479
+ }
421
480
  `;
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
- }, []);
481
+ function AuthUiRuntimeStyles() {
482
+ return createElement(
483
+ "style",
484
+ {
485
+ href: AUTH_UI_RUNTIME_STYLE_HREF,
486
+ precedence: "medium"
487
+ },
488
+ AUTH_UI_RUNTIME_STYLES
489
+ );
435
490
  }
436
491
 
437
492
  // src/base-button.tsx
438
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
493
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
439
494
  function mergeClassNames(...classNames) {
440
495
  return classNames.filter(Boolean).join(" ");
441
496
  }
@@ -475,7 +530,6 @@ var BaseButton = forwardRef(
475
530
  onTouchStart,
476
531
  ...otherProps
477
532
  } = props;
478
- useAuthUiRuntimeStyles();
479
533
  const { animationClassName, eventHandlers } = useButtonAnimation(
480
534
  disabled || loading ? null : animation
481
535
  );
@@ -487,31 +541,34 @@ var BaseButton = forwardRef(
487
541
  );
488
542
  const visualContent = loading ? /* @__PURE__ */ jsx3(ButtonLoadingIndicator, { animation: loadingAnimation, size: 18 }) : leadingVisual ?? (isIconOnly ? children : void 0);
489
543
  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
- );
544
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
545
+ /* @__PURE__ */ jsx3(AuthUiRuntimeStyles, {}),
546
+ /* @__PURE__ */ jsx3(
547
+ Button,
548
+ {
549
+ ref: forwardedRef,
550
+ type,
551
+ disabled: disabled || loading,
552
+ className: mergedClassName,
553
+ "data-icon-only": isIconOnly ? "true" : void 0,
554
+ "data-loading": loading ? "true" : void 0,
555
+ "aria-busy": loading ? true : ariaBusy,
556
+ ...otherProps,
557
+ onBlur: composeEventHandlers(eventHandlers.onBlur, onBlur),
558
+ onKeyDown: composeEventHandlers(eventHandlers.onKeyDown, onKeyDown),
559
+ onKeyUp: composeEventHandlers(eventHandlers.onKeyUp, onKeyUp),
560
+ onMouseDown: composeEventHandlers(eventHandlers.onMouseDown, onMouseDown),
561
+ onMouseLeave: composeEventHandlers(eventHandlers.onMouseLeave, onMouseLeave),
562
+ onMouseUp: composeEventHandlers(eventHandlers.onMouseUp, onMouseUp),
563
+ onTouchEnd: composeEventHandlers(eventHandlers.onTouchEnd, onTouchEnd),
564
+ onTouchStart: composeEventHandlers(eventHandlers.onTouchStart, onTouchStart),
565
+ children: /* @__PURE__ */ jsxs2("span", { className: "sublime-button__content", children: [
566
+ visualContent ? /* @__PURE__ */ jsx3("span", { className: "sublime-button__visual", children: visualContent }) : null,
567
+ labelContent !== null && labelContent !== void 0 ? /* @__PURE__ */ jsx3("span", { className: "sublime-button__label", children: labelContent }) : null
568
+ ] })
569
+ }
570
+ )
571
+ ] });
515
572
  }
516
573
  );
517
574
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sublimee/auth-ui",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Production-ready authentication UI components for Sublime",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -41,7 +41,12 @@
41
41
  "peerDependencies": {
42
42
  "react": "^19.0.0",
43
43
  "react-dom": "^19.0.0",
44
- "@sublimee/tokens": "0.1.11"
44
+ "@sublimee/tokens": "0.1.13"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "@sublimee/tokens": {
48
+ "optional": true
49
+ }
45
50
  },
46
51
  "dependencies": {
47
52
  "@base-ui/react": "^1.0.0"
@@ -6,7 +6,7 @@ import type { ButtonHTMLAttributes, ReactNode } from 'react';
6
6
 
7
7
  import { ButtonLoadingIndicator } from './button-loading-indicator';
8
8
  import { useButtonAnimation } from './use-button-animation';
9
- import { useAuthUiRuntimeStyles } from './runtime-styles';
9
+ import { AuthUiRuntimeStyles } from './runtime-styles';
10
10
  import type {
11
11
  ButtonAnimation,
12
12
  ButtonLoadingAnimation,
@@ -72,8 +72,6 @@ export const BaseButton = forwardRef<HTMLButtonElement, BaseButtonProps>(
72
72
  ...otherProps
73
73
  } = props;
74
74
 
75
- useAuthUiRuntimeStyles();
76
-
77
75
  const { animationClassName, eventHandlers } = useButtonAnimation(
78
76
  disabled || loading ? null : animation
79
77
  );
@@ -92,33 +90,36 @@ export const BaseButton = forwardRef<HTMLButtonElement, BaseButtonProps>(
92
90
  const labelContent = isIconOnly ? null : children;
93
91
 
94
92
  return (
95
- <Button
96
- ref={forwardedRef}
97
- type={type}
98
- disabled={disabled || loading}
99
- className={mergedClassName}
100
- data-icon-only={isIconOnly ? 'true' : undefined}
101
- data-loading={loading ? 'true' : undefined}
102
- aria-busy={loading ? true : ariaBusy}
103
- {...otherProps}
104
- onBlur={composeEventHandlers(eventHandlers.onBlur, onBlur)}
105
- onKeyDown={composeEventHandlers(eventHandlers.onKeyDown, onKeyDown)}
106
- onKeyUp={composeEventHandlers(eventHandlers.onKeyUp, onKeyUp)}
107
- onMouseDown={composeEventHandlers(eventHandlers.onMouseDown, onMouseDown)}
108
- onMouseLeave={composeEventHandlers(eventHandlers.onMouseLeave, onMouseLeave)}
109
- onMouseUp={composeEventHandlers(eventHandlers.onMouseUp, onMouseUp)}
110
- onTouchEnd={composeEventHandlers(eventHandlers.onTouchEnd, onTouchEnd)}
111
- onTouchStart={composeEventHandlers(eventHandlers.onTouchStart, onTouchStart)}
112
- >
113
- <span className="sublime-button__content">
114
- {visualContent ? (
115
- <span className="sublime-button__visual">{visualContent}</span>
116
- ) : null}
117
- {labelContent !== null && labelContent !== undefined ? (
118
- <span className="sublime-button__label">{labelContent}</span>
119
- ) : null}
120
- </span>
121
- </Button>
93
+ <>
94
+ <AuthUiRuntimeStyles />
95
+ <Button
96
+ ref={forwardedRef}
97
+ type={type}
98
+ disabled={disabled || loading}
99
+ className={mergedClassName}
100
+ data-icon-only={isIconOnly ? 'true' : undefined}
101
+ data-loading={loading ? 'true' : undefined}
102
+ aria-busy={loading ? true : ariaBusy}
103
+ {...otherProps}
104
+ onBlur={composeEventHandlers(eventHandlers.onBlur, onBlur)}
105
+ onKeyDown={composeEventHandlers(eventHandlers.onKeyDown, onKeyDown)}
106
+ onKeyUp={composeEventHandlers(eventHandlers.onKeyUp, onKeyUp)}
107
+ onMouseDown={composeEventHandlers(eventHandlers.onMouseDown, onMouseDown)}
108
+ onMouseLeave={composeEventHandlers(eventHandlers.onMouseLeave, onMouseLeave)}
109
+ onMouseUp={composeEventHandlers(eventHandlers.onMouseUp, onMouseUp)}
110
+ onTouchEnd={composeEventHandlers(eventHandlers.onTouchEnd, onTouchEnd)}
111
+ onTouchStart={composeEventHandlers(eventHandlers.onTouchStart, onTouchStart)}
112
+ >
113
+ <span className="sublime-button__content">
114
+ {visualContent ? (
115
+ <span className="sublime-button__visual">{visualContent}</span>
116
+ ) : null}
117
+ {labelContent !== null && labelContent !== undefined ? (
118
+ <span className="sublime-button__label">{labelContent}</span>
119
+ ) : null}
120
+ </span>
121
+ </Button>
122
+ </>
122
123
  );
123
124
  }
124
- );
125
+ );
package/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  /**
2
4
  * @sublimee/auth-ui
3
5
  * Ready-to-use authentication UI components for Sublime.
@@ -11,7 +13,6 @@
11
13
  * Quick Start:
12
14
  * -----------
13
15
  * ```tsx
14
- * import '@sublimee/tokens/tokens.css';
15
16
  * import { OAuthButton } from '@sublimee/auth-ui';
16
17
  *
17
18
  * <OAuthButton provider="google" />
@@ -19,7 +20,8 @@
19
20
  * ```
20
21
  *
21
22
  * The package injects its runtime button styles automatically so the
22
- * default experience stays zero-setup for consumers.
23
+ * default experience stays zero-setup for consumers. Install and import
24
+ * `@sublimee/tokens/tokens.css` only when you want shared app-wide theming.
23
25
  *
24
26
  * @packageDocumentation
25
27
  */
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
- import { useInsertionEffect } from 'react';
3
+ import { createElement } from 'react';
4
4
 
5
- const AUTH_UI_RUNTIME_STYLE_ID = 'sublime-auth-ui-runtime-styles';
5
+ const AUTH_UI_RUNTIME_STYLE_HREF = 'sublime-auth-ui-runtime-styles';
6
6
 
7
7
  const AUTH_UI_RUNTIME_STYLES = `
8
8
  .sublime-button {
@@ -151,6 +151,35 @@ const AUTH_UI_RUNTIME_STYLES = `
151
151
  --sublime-button-border-active: var(--sublime-color-border-primary-active, #6b7280);
152
152
  }
153
153
 
154
+ .dark .sublime-button,
155
+ [data-theme='dark'] .sublime-button {
156
+ --sublime-button-focus-ring-offset: var(--sublime-color-focus-ring-offset, #0f172a);
157
+ }
158
+
159
+ .dark .sublime-button--primary,
160
+ [data-theme='dark'] .sublime-button--primary {
161
+ --sublime-button-bg: var(--sublime-color-interactive-primary, #f8fafc);
162
+ --sublime-button-bg-hover: var(--sublime-color-interactive-primary-hover, #e2e8f0);
163
+ --sublime-button-bg-active: var(--sublime-color-interactive-primary-active, #cbd5e1);
164
+ --sublime-button-color: var(--sublime-color-interactive-primary-text, #0f172a);
165
+ --sublime-button-color-hover: var(--sublime-color-interactive-primary-text, #0f172a);
166
+ --sublime-button-border: var(--sublime-color-interactive-primary, #f8fafc);
167
+ --sublime-button-border-hover: var(--sublime-color-interactive-primary-hover, #e2e8f0);
168
+ --sublime-button-border-active: var(--sublime-color-interactive-primary-active, #cbd5e1);
169
+ }
170
+
171
+ .dark .sublime-button--secondary,
172
+ [data-theme='dark'] .sublime-button--secondary {
173
+ --sublime-button-bg: var(--sublime-color-surface-1, #171717);
174
+ --sublime-button-bg-hover: var(--sublime-color-surface-1-hover, #262626);
175
+ --sublime-button-bg-active: var(--sublime-color-surface-1-active, #404040);
176
+ --sublime-button-color: var(--sublime-color-text-primary, #fafafa);
177
+ --sublime-button-color-hover: var(--sublime-color-text-primary, #fafafa);
178
+ --sublime-button-border: var(--sublime-color-border-primary, #404040);
179
+ --sublime-button-border-hover: var(--sublime-color-border-primary-hover, #525252);
180
+ --sublime-button-border-active: var(--sublime-color-border-primary-active, #737373);
181
+ }
182
+
154
183
  .sublime-auth-button[data-provider='discord'] .sublime-button__visual {
155
184
  color: #5865f2;
156
185
  }
@@ -205,21 +234,43 @@ const AUTH_UI_RUNTIME_STYLES = `
205
234
  animation-duration: 1.6s !important;
206
235
  }
207
236
  }
237
+
238
+ @media (prefers-color-scheme: dark) {
239
+ :root:not([data-theme='light']):not(.light) .sublime-button {
240
+ --sublime-button-focus-ring-offset: var(--sublime-color-focus-ring-offset, #0f172a);
241
+ }
242
+
243
+ :root:not([data-theme='light']):not(.light) .sublime-button--primary {
244
+ --sublime-button-bg: var(--sublime-color-interactive-primary, #f8fafc);
245
+ --sublime-button-bg-hover: var(--sublime-color-interactive-primary-hover, #e2e8f0);
246
+ --sublime-button-bg-active: var(--sublime-color-interactive-primary-active, #cbd5e1);
247
+ --sublime-button-color: var(--sublime-color-interactive-primary-text, #0f172a);
248
+ --sublime-button-color-hover: var(--sublime-color-interactive-primary-text, #0f172a);
249
+ --sublime-button-border: var(--sublime-color-interactive-primary, #f8fafc);
250
+ --sublime-button-border-hover: var(--sublime-color-interactive-primary-hover, #e2e8f0);
251
+ --sublime-button-border-active: var(--sublime-color-interactive-primary-active, #cbd5e1);
252
+ }
253
+
254
+ :root:not([data-theme='light']):not(.light) .sublime-button--secondary {
255
+ --sublime-button-bg: var(--sublime-color-surface-1, #171717);
256
+ --sublime-button-bg-hover: var(--sublime-color-surface-1-hover, #262626);
257
+ --sublime-button-bg-active: var(--sublime-color-surface-1-active, #404040);
258
+ --sublime-button-color: var(--sublime-color-text-primary, #fafafa);
259
+ --sublime-button-color-hover: var(--sublime-color-text-primary, #fafafa);
260
+ --sublime-button-border: var(--sublime-color-border-primary, #404040);
261
+ --sublime-button-border-hover: var(--sublime-color-border-primary-hover, #525252);
262
+ --sublime-button-border-active: var(--sublime-color-border-primary-active, #737373);
263
+ }
264
+ }
208
265
  `;
209
266
 
210
- export function useAuthUiRuntimeStyles() {
211
- useInsertionEffect(() => {
212
- if (typeof document === 'undefined') {
213
- return;
214
- }
215
-
216
- if (document.getElementById(AUTH_UI_RUNTIME_STYLE_ID)) {
217
- return;
218
- }
219
-
220
- const styleElement = document.createElement('style');
221
- styleElement.id = AUTH_UI_RUNTIME_STYLE_ID;
222
- styleElement.textContent = AUTH_UI_RUNTIME_STYLES;
223
- document.head.prepend(styleElement);
224
- }, []);
225
- }
267
+ export function AuthUiRuntimeStyles() {
268
+ return createElement(
269
+ 'style',
270
+ {
271
+ href: AUTH_UI_RUNTIME_STYLE_HREF,
272
+ precedence: 'medium',
273
+ },
274
+ AUTH_UI_RUNTIME_STYLES
275
+ );
276
+ }