@scalably/ui 0.2.0 → 0.2.1

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/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # Scalably UI Component Library
2
2
 
3
3
  ![npm version](https://img.shields.io/npm/v/@scalably/ui)
4
- ![build status](https://github.com/quangnle/scalably-components/actions/workflows/pr-checks.yml/badge.svg?branch=main)
5
4
  ![license](https://img.shields.io/npm/l/@scalably/ui)
6
5
 
7
6
  A modern, accessible, and fully isolated React component library built with TypeScript and Tailwind CSS. Designed to work seamlessly across multiple projects without style conflicts.
@@ -24,19 +23,11 @@ npm install @scalably/ui
24
23
 
25
24
  ## 🎨 Usage
26
25
 
27
- ### 1. Import the CSS
26
+ ### 1. Use Components (Styles Auto-Injected)
28
27
 
29
- Add the component library styles to your main entry point:
28
+ The `ScalablyUIProvider` automatically injects styles into `document.head`, so you don't need to manually import CSS. This ensures styles work correctly in portals (modals, tooltips, etc.). No wrapper or scope class is required—just wrap your app once.
30
29
 
31
30
  ```tsx
32
- // In your main.tsx, App.tsx, or index.tsx
33
- import "@scalably/ui/styles";
34
- ```
35
-
36
- ### 2. Use Components
37
-
38
- ```tsx
39
- import "@scalably/ui/styles";
40
31
  import { ScalablyUIProvider, Form, FormField, Input, Button, ToastContainer, Toast } from "@scalably/ui";
41
32
 
42
33
  export default function App() {
@@ -59,30 +50,40 @@ export default function App() {
59
50
  }
60
51
  ```
61
52
 
62
- Note: Toasts in this library are intentionally declarative. Render a `Toast` inside a `ToastContainer` when you want it visible (e.g., based on component state). This avoids hidden globals and keeps UI state predictable. If you prefer an imperative API, you can wrap your own tiny helper around local state to toggle a `Toast` component.
63
-
64
- ### 3. Add the provider once (recommended)
53
+ ### 2. Optional: Manual CSS Import
65
54
 
66
- Instead of adding the `sui-scope` class manually, wrap your app with the provider:
55
+ If you prefer to import CSS manually (e.g., for better control or SSR optimization), you can disable automatic injection:
67
56
 
68
57
  ```tsx
58
+ // In your main.tsx, App.tsx, or index.tsx
69
59
  import "@scalably/ui/styles";
70
60
  import { ScalablyUIProvider } from "@scalably/ui";
71
61
 
72
62
  export default function App() {
73
- return <ScalablyUIProvider>{/* your app */}</ScalablyUIProvider>;
63
+ return (
64
+ <ScalablyUIProvider injectStyles={false}>
65
+ {/* your app */}
66
+ </ScalablyUIProvider>
67
+ );
74
68
  }
75
69
  ```
76
70
 
77
- Optional no extra DOM element:
71
+ ### 3. Portal Support
72
+
73
+ Styles automatically work in portaled components (modals, tooltips, popovers, etc.) because:
74
+ - Styles are injected globally into `document.head`
75
+ - CSS variables propagate to all elements
76
+ - No parent selector dependencies
78
77
 
79
78
  ```tsx
80
- <ScalablyUIProvider asChild>
81
- <main>{/* your app */}</main>
82
- {/* merges the scope onto <main> */}
83
- </ScalablyUIProvider>
79
+ // Tooltips, modals, and other portaled components work automatically
80
+ <Tooltip content="This works in portals!" portal>
81
+ <Button>Hover me</Button>
82
+ </Tooltip>
84
83
  ```
85
84
 
85
+ Note: Toasts in this library are intentionally declarative. Render a `Toast` inside a `ToastContainer` when you want it visible (e.g., based on component state). This avoids hidden globals and keeps UI state predictable. If you prefer an imperative API, you can wrap your own tiny helper around local state to toggle a `Toast` component.
86
+
86
87
  ### 4. React import guidance
87
88
 
88
89
  If you reference the React namespace (e.g., `React.useState`, `React.forwardRef`, `React.SVGProps`) add an explicit import to avoid UMD global errors:
@@ -151,12 +152,10 @@ All components use prefixed Tailwind classes (`sui-*`) to ensure complete style
151
152
 
152
153
  ```tsx
153
154
  // ✅ Correct - components are properly isolated
154
- <div className="sui-scope">
155
- <Button>Isolated Button</Button>
156
- </div>
155
+ <Button>Isolated Button</Button>
157
156
 
158
157
  // ✅ Your global styles won't break the components
159
- <div className="p-4 bg-red-500"> {/* These global classes won't affect the button's styles */}
158
+ <div className="p-4 bg-red-500">
160
159
  <Button>Isolated Button</Button>
161
160
  </div>
162
161
  ```
@@ -249,10 +248,12 @@ Visit our Storybook documentation for:
249
248
 
250
249
  The library uses a custom Tailwind configuration with:
251
250
 
252
- - **Prefix**: `sui-` for all utility classes
253
- - **Important**: `.sui-scope` for style isolation
251
+ - **Prefix**: `sui-` for all utility classes (provides style isolation)
252
+ - **Global Styles**: Automatically injected via `ScalablyUIProvider`
253
+ - **CSS Variables**: Design tokens available globally for theming
254
254
  - **Custom Colors**: Brand-specific color palette
255
255
  - **Custom Shadows**: Soft, medium, and strong shadow variants
256
+ - **Portal Support**: Styles work in portaled components (modals, tooltips, etc.)
256
257
 
257
258
  ### Build Configuration
258
259
 
package/dist/index.d.cts CHANGED
@@ -3,7 +3,6 @@ import { ReactNode } from 'react';
3
3
  import * as class_variance_authority_types from 'class-variance-authority/types';
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
- import { ClassValue } from 'clsx';
7
6
  import * as date_fns from 'date-fns';
8
7
  export { addMonths, endOfMonth, isSameDay, startOfMonth } from 'date-fns';
9
8
 
@@ -142,7 +141,7 @@ interface StatusBadgeProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "
142
141
  declare const StatusBadge: react.ForwardRefExoticComponent<StatusBadgeProps & react.RefAttributes<HTMLSpanElement>>;
143
142
 
144
143
  declare const buttonVariants: (props?: ({
145
- variant?: "default" | "link" | "text" | "outline" | "destructive" | "secondary" | null | undefined;
144
+ variant?: "link" | "text" | "outline" | "default" | "destructive" | "secondary" | null | undefined;
146
145
  size?: "icon" | "md" | "lg" | null | undefined;
147
146
  } & class_variance_authority_types.ClassProp) | undefined) => string;
148
147
  type ButtonVariant = VariantProps<typeof buttonVariants>["variant"];
@@ -750,6 +749,13 @@ interface FileUploadProps {
750
749
  * This runs after internal type/size validation.
751
750
  */
752
751
  onValidateFile?: (file: File) => FileUploadError | null | undefined;
752
+ /** Enable video thumbnail capture UI via modal when a video file is selected. */
753
+ enableVideoThumbnail?: boolean;
754
+ /**
755
+ * Called when a thumbnail is captured from the selected video's current frame.
756
+ * Provides the Blob (image/jpeg) and a data URL for immediate preview.
757
+ */
758
+ onThumbnailCapture?: (thumbnail: Blob, dataUrl: string, file: FileUploadFile) => void;
753
759
  }
754
760
  /**
755
761
  * File upload component with drag-and-drop, validation, previews, and accessibility support.
@@ -1569,29 +1575,55 @@ declare const ViewToggle: React.FC<ViewToggleProps>;
1569
1575
 
1570
1576
  interface ScalablyUIProviderProps {
1571
1577
  children: React.ReactNode;
1578
+ /**
1579
+ * @deprecated `className` is no longer needed. Styles are applied globally.
1580
+ */
1572
1581
  className?: string;
1573
1582
  /**
1574
- * When true, merges the scope class onto the single child instead of adding an extra wrapper div.
1583
+ * @deprecated `asChild` is no longer needed. Styles are applied globally.
1575
1584
  */
1576
1585
  asChild?: boolean;
1586
+ /**
1587
+ * When true, automatically injects the component library styles into document.head.
1588
+ * This ensures styles work in portals (modals, tooltips, etc.) without requiring
1589
+ * manual CSS imports. Defaults to true.
1590
+ */
1591
+ injectStyles?: boolean;
1577
1592
  }
1578
1593
  /**
1579
1594
  * ScalablyUIProvider
1580
1595
  *
1581
- * Adds the required `sui-scope` wrapper so prefixed Tailwind styles apply.
1596
+ * Provides the Scalably UI component library context and automatically injects styles.
1597
+ * All classes are globally prefixed (`sui-*`), so no wrapper element is required.
1598
+ *
1599
+ * Features:
1600
+ * - Automatically injects CSS into document.head (prevents double-injection)
1601
+ * - Works with SSR (only injects on client-side)
1602
+ * - Ensures styles are available for portaled components
1603
+ * - Maintains style isolation via 'sui-' prefix
1582
1604
  *
1583
1605
  * Usage:
1606
+ * ```tsx
1584
1607
  * <ScalablyUIProvider>
1585
1608
  * <App />
1586
1609
  * </ScalablyUIProvider>
1610
+ * ```
1587
1611
  *
1588
- * Or to avoid an extra DOM node:
1589
- * <ScalablyUIProvider asChild>
1590
- * <main />
1612
+ * To disable automatic style injection (if you import CSS manually):
1613
+ * ```tsx
1614
+ * <ScalablyUIProvider injectStyles={false}>
1615
+ * <App />
1591
1616
  * </ScalablyUIProvider>
1617
+ * ```
1592
1618
  */
1593
1619
  declare const ScalablyUIProvider: React.FC<ScalablyUIProviderProps>;
1594
1620
 
1621
+ /**
1622
+ * Type for class values accepted by clsx
1623
+ */
1624
+ type ClassValue = ClassArray | ClassDictionary | string | number | bigint | null | boolean | undefined;
1625
+ type ClassDictionary = Record<string, unknown>;
1626
+ type ClassArray = ClassValue[];
1595
1627
  /**
1596
1628
  * Utility function to merge Tailwind CSS classes intelligently
1597
1629
  * Combines clsx for conditional classes and tailwind-merge for conflict resolution
package/dist/index.d.ts CHANGED
@@ -3,7 +3,6 @@ import { ReactNode } from 'react';
3
3
  import * as class_variance_authority_types from 'class-variance-authority/types';
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
- import { ClassValue } from 'clsx';
7
6
  import * as date_fns from 'date-fns';
8
7
  export { addMonths, endOfMonth, isSameDay, startOfMonth } from 'date-fns';
9
8
 
@@ -142,7 +141,7 @@ interface StatusBadgeProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "
142
141
  declare const StatusBadge: react.ForwardRefExoticComponent<StatusBadgeProps & react.RefAttributes<HTMLSpanElement>>;
143
142
 
144
143
  declare const buttonVariants: (props?: ({
145
- variant?: "default" | "link" | "text" | "outline" | "destructive" | "secondary" | null | undefined;
144
+ variant?: "link" | "text" | "outline" | "default" | "destructive" | "secondary" | null | undefined;
146
145
  size?: "icon" | "md" | "lg" | null | undefined;
147
146
  } & class_variance_authority_types.ClassProp) | undefined) => string;
148
147
  type ButtonVariant = VariantProps<typeof buttonVariants>["variant"];
@@ -750,6 +749,13 @@ interface FileUploadProps {
750
749
  * This runs after internal type/size validation.
751
750
  */
752
751
  onValidateFile?: (file: File) => FileUploadError | null | undefined;
752
+ /** Enable video thumbnail capture UI via modal when a video file is selected. */
753
+ enableVideoThumbnail?: boolean;
754
+ /**
755
+ * Called when a thumbnail is captured from the selected video's current frame.
756
+ * Provides the Blob (image/jpeg) and a data URL for immediate preview.
757
+ */
758
+ onThumbnailCapture?: (thumbnail: Blob, dataUrl: string, file: FileUploadFile) => void;
753
759
  }
754
760
  /**
755
761
  * File upload component with drag-and-drop, validation, previews, and accessibility support.
@@ -1569,29 +1575,55 @@ declare const ViewToggle: React.FC<ViewToggleProps>;
1569
1575
 
1570
1576
  interface ScalablyUIProviderProps {
1571
1577
  children: React.ReactNode;
1578
+ /**
1579
+ * @deprecated `className` is no longer needed. Styles are applied globally.
1580
+ */
1572
1581
  className?: string;
1573
1582
  /**
1574
- * When true, merges the scope class onto the single child instead of adding an extra wrapper div.
1583
+ * @deprecated `asChild` is no longer needed. Styles are applied globally.
1575
1584
  */
1576
1585
  asChild?: boolean;
1586
+ /**
1587
+ * When true, automatically injects the component library styles into document.head.
1588
+ * This ensures styles work in portals (modals, tooltips, etc.) without requiring
1589
+ * manual CSS imports. Defaults to true.
1590
+ */
1591
+ injectStyles?: boolean;
1577
1592
  }
1578
1593
  /**
1579
1594
  * ScalablyUIProvider
1580
1595
  *
1581
- * Adds the required `sui-scope` wrapper so prefixed Tailwind styles apply.
1596
+ * Provides the Scalably UI component library context and automatically injects styles.
1597
+ * All classes are globally prefixed (`sui-*`), so no wrapper element is required.
1598
+ *
1599
+ * Features:
1600
+ * - Automatically injects CSS into document.head (prevents double-injection)
1601
+ * - Works with SSR (only injects on client-side)
1602
+ * - Ensures styles are available for portaled components
1603
+ * - Maintains style isolation via 'sui-' prefix
1582
1604
  *
1583
1605
  * Usage:
1606
+ * ```tsx
1584
1607
  * <ScalablyUIProvider>
1585
1608
  * <App />
1586
1609
  * </ScalablyUIProvider>
1610
+ * ```
1587
1611
  *
1588
- * Or to avoid an extra DOM node:
1589
- * <ScalablyUIProvider asChild>
1590
- * <main />
1612
+ * To disable automatic style injection (if you import CSS manually):
1613
+ * ```tsx
1614
+ * <ScalablyUIProvider injectStyles={false}>
1615
+ * <App />
1591
1616
  * </ScalablyUIProvider>
1617
+ * ```
1592
1618
  */
1593
1619
  declare const ScalablyUIProvider: React.FC<ScalablyUIProviderProps>;
1594
1620
 
1621
+ /**
1622
+ * Type for class values accepted by clsx
1623
+ */
1624
+ type ClassValue = ClassArray | ClassDictionary | string | number | bigint | null | boolean | undefined;
1625
+ type ClassDictionary = Record<string, unknown>;
1626
+ type ClassArray = ClassValue[];
1595
1627
  /**
1596
1628
  * Utility function to merge Tailwind CSS classes intelligently
1597
1629
  * Combines clsx for conditional classes and tailwind-merge for conflict resolution