@getgreenline/blaze-ui 1.0.2 → 1.0.3-3.0-beta
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/components/accordion.d.ts +8 -0
- package/dist/components/accordion.d.ts.map +1 -0
- package/dist/components/accordion.js +19 -0
- package/dist/components/alert-dialog.d.ts +18 -0
- package/dist/components/alert-dialog.d.ts.map +1 -0
- package/dist/components/alert-dialog.js +41 -0
- package/dist/components/alert.d.ts +10 -0
- package/dist/components/alert.d.ts.map +1 -0
- package/dist/components/alert.js +26 -0
- package/dist/components/aspect-ratio.d.ts +4 -0
- package/dist/components/aspect-ratio.d.ts.map +1 -0
- package/dist/components/aspect-ratio.js +8 -0
- package/dist/components/avatar.d.ts +7 -0
- package/dist/components/avatar.d.ts.map +1 -0
- package/dist/components/avatar.js +15 -0
- package/dist/components/badge.d.ts +10 -0
- package/dist/components/badge.d.ts.map +1 -0
- package/dist/components/badge.js +24 -0
- package/dist/components/breadcrumb.d.ts +12 -0
- package/dist/components/breadcrumb.d.ts.map +1 -0
- package/dist/components/breadcrumb.js +29 -0
- package/dist/components/button-group.d.ts +12 -0
- package/dist/components/button-group.d.ts.map +1 -0
- package/dist/components/button-group.js +29 -0
- package/dist/components/button.d.ts +16 -0
- package/dist/components/button.d.ts.map +1 -0
- package/dist/components/button.js +37 -0
- package/dist/components/card.d.ts +10 -0
- package/dist/components/card.d.ts.map +1 -0
- package/dist/components/card.js +26 -0
- package/dist/components/carousel.d.ts +20 -0
- package/dist/components/carousel.d.ts.map +1 -0
- package/dist/components/carousel.js +92 -0
- package/dist/components/chart.d.ts +41 -0
- package/dist/components/chart.d.ts.map +1 -0
- package/dist/components/chart.js +133 -0
- package/dist/components/checkbox.d.ts +5 -0
- package/dist/components/checkbox.d.ts.map +1 -0
- package/dist/components/checkbox.js +10 -0
- package/dist/components/collapsible.d.ts +6 -0
- package/dist/components/collapsible.d.ts.map +1 -0
- package/dist/components/collapsible.js +14 -0
- package/dist/components/command.d.ts +19 -0
- package/dist/components/command.d.ts.map +1 -0
- package/dist/components/command.js +35 -0
- package/dist/components/context-menu.d.ts +26 -0
- package/dist/components/context-menu.d.ts.map +1 -0
- package/dist/components/context-menu.js +52 -0
- package/dist/components/data-table.d.ts +83 -0
- package/dist/components/data-table.d.ts.map +1 -0
- package/dist/components/data-table.js +357 -0
- package/dist/components/dialog.d.ts +16 -0
- package/dist/components/dialog.d.ts.map +1 -0
- package/dist/components/dialog.js +37 -0
- package/dist/components/drawer.d.ts +14 -0
- package/dist/components/drawer.d.ts.map +1 -0
- package/dist/components/drawer.js +36 -0
- package/dist/components/dropdown-menu.d.ts +26 -0
- package/dist/components/dropdown-menu.d.ts.map +1 -0
- package/dist/components/dropdown-menu.js +52 -0
- package/dist/components/empty.d.ts +12 -0
- package/dist/components/empty.d.ts.map +1 -0
- package/dist/components/empty.js +35 -0
- package/dist/components/field.d.ts +25 -0
- package/dist/components/field.d.ts.map +1 -0
- package/dist/components/field.js +74 -0
- package/dist/components/form.d.ts +25 -0
- package/dist/components/form.d.ts.map +1 -0
- package/dist/components/form.js +60 -0
- package/dist/components/header-app-switcher.d.ts +50 -0
- package/dist/components/header-app-switcher.d.ts.map +1 -0
- package/dist/components/header-app-switcher.js +154 -0
- package/dist/components/hierarchical-select.d.ts +21 -0
- package/dist/components/hierarchical-select.d.ts.map +1 -0
- package/dist/components/hierarchical-select.js +96 -0
- package/dist/components/hover-card.d.ts +7 -0
- package/dist/components/hover-card.d.ts.map +1 -0
- package/dist/components/hover-card.js +15 -0
- package/dist/components/input-group.d.ts +17 -0
- package/dist/components/input-group.d.ts.map +1 -0
- package/dist/components/input-group.js +64 -0
- package/dist/components/input-otp.d.ts +12 -0
- package/dist/components/input-otp.d.ts.map +1 -0
- package/dist/components/input-otp.js +22 -0
- package/dist/components/input.d.ts +4 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/input.js +8 -0
- package/dist/components/item.d.ts +24 -0
- package/dist/components/item.d.ts.map +1 -0
- package/dist/components/item.js +68 -0
- package/dist/components/kbd.d.ts +4 -0
- package/dist/components/kbd.d.ts.map +1 -0
- package/dist/components/kbd.js +11 -0
- package/dist/components/label.d.ts +8 -0
- package/dist/components/label.d.ts.map +1 -0
- package/dist/components/label.js +9 -0
- package/dist/components/login-screen.d.ts +4 -0
- package/dist/components/login-screen.d.ts.map +1 -0
- package/dist/components/login-screen.js +300 -0
- package/dist/components/login-screen.types.d.ts +82 -0
- package/dist/components/login-screen.types.d.ts.map +1 -0
- package/dist/components/login-screen.views.d.ts +114 -0
- package/dist/components/login-screen.views.d.ts.map +1 -0
- package/dist/components/login-screen.views.js +53 -0
- package/dist/components/menubar.d.ts +27 -0
- package/dist/components/menubar.d.ts.map +1 -0
- package/dist/components/menubar.js +55 -0
- package/dist/components/navigation-menu.d.ts +15 -0
- package/dist/components/navigation-menu.d.ts.map +1 -0
- package/dist/components/navigation-menu.js +33 -0
- package/dist/components/pagination.d.ts +14 -0
- package/dist/components/pagination.d.ts.map +1 -0
- package/dist/components/pagination.js +31 -0
- package/dist/components/popover.d.ts +8 -0
- package/dist/components/popover.d.ts.map +1 -0
- package/dist/components/popover.js +18 -0
- package/dist/components/progress.d.ts +5 -0
- package/dist/components/progress.d.ts.map +1 -0
- package/dist/components/progress.js +9 -0
- package/dist/components/radio-group.d.ts +6 -0
- package/dist/components/radio-group.d.ts.map +1 -0
- package/dist/components/radio-group.js +13 -0
- package/dist/components/resizable.d.ts +9 -0
- package/dist/components/resizable.d.ts.map +1 -0
- package/dist/components/resizable.js +16 -0
- package/dist/components/scroll-area.d.ts +6 -0
- package/dist/components/scroll-area.d.ts.map +1 -0
- package/dist/components/scroll-area.js +14 -0
- package/dist/components/search-bar.d.ts +15 -0
- package/dist/components/search-bar.d.ts.map +1 -0
- package/dist/components/search-bar.js +25 -0
- package/dist/components/segmented-control.d.ts +24 -0
- package/dist/components/segmented-control.d.ts.map +1 -0
- package/dist/components/segmented-control.js +88 -0
- package/dist/components/select.d.ts +16 -0
- package/dist/components/select.d.ts.map +1 -0
- package/dist/components/select.js +39 -0
- package/dist/components/selection-panel.d.ts +29 -0
- package/dist/components/selection-panel.d.ts.map +1 -0
- package/dist/components/selection-panel.js +255 -0
- package/dist/components/separator.d.ts +5 -0
- package/dist/components/separator.d.ts.map +1 -0
- package/dist/components/separator.js +9 -0
- package/dist/components/sheet.d.ts +17 -0
- package/dist/components/sheet.d.ts.map +1 -0
- package/dist/components/sheet.js +42 -0
- package/dist/components/sidebar.d.ts +70 -0
- package/dist/components/sidebar.d.ts.map +1 -0
- package/dist/components/sidebar.js +213 -0
- package/dist/components/skeleton.d.ts +3 -0
- package/dist/components/skeleton.d.ts.map +1 -0
- package/dist/components/skeleton.js +8 -0
- package/dist/components/slider.d.ts +5 -0
- package/dist/components/slider.d.ts.map +1 -0
- package/dist/components/slider.js +15 -0
- package/dist/components/sonner.d.ts +4 -0
- package/dist/components/sonner.d.ts.map +1 -0
- package/dist/components/sonner.js +22 -0
- package/dist/components/spinner.d.ts +3 -0
- package/dist/components/spinner.d.ts.map +1 -0
- package/dist/components/spinner.js +9 -0
- package/dist/components/switch.d.ts +5 -0
- package/dist/components/switch.d.ts.map +1 -0
- package/dist/components/switch.js +9 -0
- package/dist/components/table.d.ts +11 -0
- package/dist/components/table.d.ts.map +1 -0
- package/dist/components/table.js +29 -0
- package/dist/components/tabs.d.ts +8 -0
- package/dist/components/tabs.d.ts.map +1 -0
- package/dist/components/tabs.js +18 -0
- package/dist/components/textarea.d.ts +4 -0
- package/dist/components/textarea.d.ts.map +1 -0
- package/dist/components/textarea.js +8 -0
- package/dist/components/toggle-group.d.ts +8 -0
- package/dist/components/toggle-group.d.ts.map +1 -0
- package/dist/components/toggle-group.js +22 -0
- package/dist/components/toggle.d.ts +10 -0
- package/dist/components/toggle.d.ts.map +1 -0
- package/dist/components/toggle.js +27 -0
- package/dist/components/tooltip.d.ts +8 -0
- package/dist/components/tooltip.d.ts.map +1 -0
- package/dist/components/tooltip.js +18 -0
- package/dist/components/visually-hidden.d.ts +16 -0
- package/dist/components/visually-hidden.d.ts.map +1 -0
- package/dist/components/visually-hidden.js +22 -0
- package/dist/globals.css +646 -0
- package/dist/hooks/use-mobile.d.ts +2 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/hooks/use-mobile.js +18 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/lib/portal-wrapper.d.ts +32 -0
- package/dist/lib/portal-wrapper.d.ts.map +1 -0
- package/dist/lib/portal-wrapper.js +34 -0
- package/dist/lib/utils.js +8 -0
- package/dist/svgs/blaze-dispatch-logo.d.ts +5 -0
- package/dist/svgs/blaze-dispatch-logo.d.ts.map +1 -0
- package/dist/svgs/blaze-dispatch-logo.js +7 -0
- package/dist/svgs/blaze-ecom-logo.d.ts +7 -0
- package/dist/svgs/blaze-ecom-logo.d.ts.map +1 -0
- package/dist/svgs/blaze-ecom-logo.js +7 -0
- package/dist/svgs/blaze-insights-logo.d.ts +5 -0
- package/dist/svgs/blaze-insights-logo.d.ts.map +1 -0
- package/dist/svgs/blaze-insights-logo.js +7 -0
- package/dist/svgs/blaze-lighthouse-logo.d.ts +6 -0
- package/dist/svgs/blaze-lighthouse-logo.d.ts.map +1 -0
- package/dist/svgs/blaze-lighthouse-logo.js +7 -0
- package/dist/svgs/blaze-pay-logo.d.ts +5 -0
- package/dist/svgs/blaze-pay-logo.d.ts.map +1 -0
- package/dist/svgs/blaze-pay-logo.js +7 -0
- package/dist/svgs/blaze-pos-logo.d.ts +5 -0
- package/dist/svgs/blaze-pos-logo.d.ts.map +1 -0
- package/dist/svgs/blaze-pos-logo.js +7 -0
- package/dist/svgs/blaze-retail-logo.d.ts +7 -0
- package/dist/svgs/blaze-retail-logo.d.ts.map +1 -0
- package/dist/svgs/blaze-retail-logo.js +7 -0
- package/dist/svgs/blaze-sites-logo.d.ts +5 -0
- package/dist/svgs/blaze-sites-logo.d.ts.map +1 -0
- package/dist/svgs/blaze-sites-logo.js +7 -0
- package/package.json +86 -21
- package/build/components/button.d.ts +0 -12
- package/build/components/button.d.ts.map +0 -1
- package/build/components/button.js +0 -106
- package/build/components/button.js.map +0 -1
- package/build/index.d.ts +0 -4
- package/build/index.d.ts.map +0 -1
- package/build/index.js +0 -11
- package/build/index.js.map +0 -1
- package/build/lib/utils.js +0 -9
- package/build/lib/utils.js.map +0 -1
- package/build/styles/blaze-ui.css +0 -157
- package/build/styles/styles.d.ts +0 -3
- package/build/styles/styles.d.ts.map +0 -1
- package/build/styles/styles.js +0 -8
- package/build/styles/styles.js.map +0 -1
- package/src/styles/blaze-ui.css +0 -157
- package/src/styles/styles.ts +0 -5
- /package/{build → dist}/lib/utils.d.ts +0 -0
- /package/{build → dist}/lib/utils.d.ts.map +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { cva } from 'class-variance-authority';
|
|
3
|
+
import { cn } from '../lib/utils.js';
|
|
4
|
+
import { Button } from './button.js';
|
|
5
|
+
import { Input } from './input.js';
|
|
6
|
+
import { Textarea } from './textarea.js';
|
|
7
|
+
|
|
8
|
+
function InputGroup({ className, ...props }) {
|
|
9
|
+
return (jsx("div", { "data-slot": "input-group", role: "group", className: cn("group/input-group tw:border-input dark:tw:bg-input/30 tw:relative tw:flex tw:w-full tw:items-center tw:rounded-md tw:border tw:shadow-xs tw:transition-[color,box-shadow] tw:outline-none", "tw:h-9 tw:min-w-0 has-[>textarea]:tw:h-auto",
|
|
10
|
+
// Variants based on alignment.
|
|
11
|
+
"has-[>[data-align=inline-start]]:[&>input]:tw:pl-2", "has-[>[data-align=inline-end]]:[&>input]:tw:pr-2", "has-[>[data-align=block-start]]:tw:h-auto has-[>[data-align=block-start]]:tw:flex-col has-[>[data-align=block-start]]:[&>input]:tw:pb-3", "has-[>[data-align=block-end]]:tw:h-auto has-[>[data-align=block-end]]:tw:flex-col has-[>[data-align=block-end]]:[&>input]:tw:pt-3",
|
|
12
|
+
// Focus state.
|
|
13
|
+
"has-[[data-slot=input-group-control]:focus-visible]:tw:border-ring has-[[data-slot=input-group-control]:focus-visible]:tw:ring-ring/50 has-[[data-slot=input-group-control]:focus-visible]:tw:ring-[3px]",
|
|
14
|
+
// Error state.
|
|
15
|
+
"has-[[data-slot][aria-invalid=true]]:tw:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:tw:border-destructive dark:has-[[data-slot][aria-invalid=true]]:tw:ring-destructive/40", className), ...props }));
|
|
16
|
+
}
|
|
17
|
+
const inputGroupAddonVariants = cva("tw:text-muted-foreground tw:flex tw:h-auto tw:cursor-text tw:items-center tw:justify-center tw:gap-2 tw:py-1.5 tw:text-sm tw:font-medium tw:select-none [&>svg:not([class*='size-'])]:tw:size-4 [&>kbd]:tw:rounded-[calc(var(--radius)-5px)] group-data-[disabled=true]/input-group:tw:opacity-50", {
|
|
18
|
+
variants: {
|
|
19
|
+
align: {
|
|
20
|
+
"inline-start": "tw:order-first tw:pl-3 has-[>button]:tw:ml-[-0.45rem] has-[>kbd]:tw:ml-[-0.35rem]",
|
|
21
|
+
"inline-end": "tw:order-last tw:pr-3 has-[>button]:tw:mr-[-0.45rem] has-[>kbd]:tw:mr-[-0.35rem]",
|
|
22
|
+
"block-start": "tw:order-first tw:w-full tw:justify-start tw:px-3 tw:pt-3 [.tw:border-b]:tw:pb-3 group-has-[>input]/input-group:tw:pt-2.5",
|
|
23
|
+
"block-end": "tw:order-last tw:w-full tw:justify-start tw:px-3 tw:pb-3 [.tw:border-t]:tw:pt-3 group-has-[>input]/input-group:tw:pb-2.5",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
defaultVariants: {
|
|
27
|
+
align: "inline-start",
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
function InputGroupAddon({ className, align = "inline-start", ...props }) {
|
|
31
|
+
return (jsx("div", { role: "group", "data-slot": "input-group-addon", "data-align": align, className: cn(inputGroupAddonVariants({ align }), className), onClick: (e) => {
|
|
32
|
+
if (e.target.closest("button")) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
e.currentTarget.parentElement?.querySelector("input")?.focus();
|
|
36
|
+
}, ...props }));
|
|
37
|
+
}
|
|
38
|
+
const inputGroupButtonVariants = cva("tw:text-sm tw:shadow-none tw:flex tw:gap-2 tw:items-center", {
|
|
39
|
+
variants: {
|
|
40
|
+
size: {
|
|
41
|
+
xs: "tw:h-6 tw:gap-1 tw:px-2 tw:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:tw:size-3.5 has-[>svg]:tw:px-2",
|
|
42
|
+
sm: "tw:h-8 tw:px-2.5 tw:gap-1.5 tw:rounded-md has-[>svg]:tw:px-2.5",
|
|
43
|
+
"icon-xs": "tw:size-6 tw:rounded-[calc(var(--radius)-5px)] tw:p-0 has-[>svg]:tw:p-0",
|
|
44
|
+
"icon-sm": "tw:size-8 tw:p-0 has-[>svg]:tw:p-0",
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
defaultVariants: {
|
|
48
|
+
size: "xs",
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
function InputGroupButton({ className, type = "button", variant = "ghost", size = "xs", ...props }) {
|
|
52
|
+
return (jsx(Button, { type: type, "data-size": size, variant: variant, className: cn(inputGroupButtonVariants({ size }), className), ...props }));
|
|
53
|
+
}
|
|
54
|
+
function InputGroupText({ className, ...props }) {
|
|
55
|
+
return (jsx("span", { className: cn("tw:text-muted-foreground tw:flex tw:items-center tw:gap-2 tw:text-sm [&_svg]:tw:pointer-events-none [&_svg:not([class*='size-'])]:tw:size-4", className), ...props }));
|
|
56
|
+
}
|
|
57
|
+
function InputGroupInput({ className, ...props }) {
|
|
58
|
+
return (jsx(Input, { "data-slot": "input-group-control", className: cn("tw:flex-1 tw:rounded-none tw:border-0 tw:bg-transparent tw:shadow-none focus-visible:tw:ring-0 dark:tw:bg-transparent", className), ...props }));
|
|
59
|
+
}
|
|
60
|
+
function InputGroupTextarea({ className, ...props }) {
|
|
61
|
+
return (jsx(Textarea, { "data-slot": "input-group-control", className: cn("tw:flex-1 tw:resize-none tw:rounded-none tw:border-0 tw:bg-transparent tw:py-3 tw:shadow-none focus-visible:tw:ring-0 dark:tw:bg-transparent", className), ...props }));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { OTPInput } from "input-otp";
|
|
3
|
+
declare function InputOTP({ className, containerClassName, ...props }: React.ComponentProps<typeof OTPInput> & {
|
|
4
|
+
containerClassName?: string;
|
|
5
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
declare function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
declare function InputOTPSlot({ index, className, ...props }: React.ComponentProps<"div"> & {
|
|
8
|
+
index: number;
|
|
9
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
declare function InputOTPSeparator({ ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
|
|
12
|
+
//# sourceMappingURL=input-otp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-otp.d.ts","sourceRoot":"","sources":["../../src/components/input-otp.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,QAAQ,EAAmB,MAAM,WAAW,CAAA;AAKrD,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,kBAAkB,EAClB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,QAAQ,CAAC,GAAG;IACzC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B,2CAYA;AAED,iBAAS,aAAa,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQ1E;AAED,iBAAS,YAAY,CAAC,EACpB,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAA;CACd,2CAsBA;AAED,iBAAS,iBAAiB,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAMnE;AAED,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { OTPInput, OTPInputContext } from 'input-otp';
|
|
4
|
+
import { MinusIcon } from 'lucide-react';
|
|
5
|
+
import { cn } from '../lib/utils.js';
|
|
6
|
+
|
|
7
|
+
function InputOTP({ className, containerClassName, ...props }) {
|
|
8
|
+
return (jsx(OTPInput, { "data-slot": "input-otp", containerClassName: cn("tw:flex tw:items-center tw:gap-2 tw:has-disabled:opacity-50", containerClassName), className: cn("tw:disabled:cursor-not-allowed", className), ...props }));
|
|
9
|
+
}
|
|
10
|
+
function InputOTPGroup({ className, ...props }) {
|
|
11
|
+
return (jsx("div", { "data-slot": "input-otp-group", className: cn("tw:flex tw:items-center", className), ...props }));
|
|
12
|
+
}
|
|
13
|
+
function InputOTPSlot({ index, className, ...props }) {
|
|
14
|
+
const inputOTPContext = React.useContext(OTPInputContext);
|
|
15
|
+
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
|
|
16
|
+
return (jsxs("div", { "data-slot": "input-otp-slot", "data-active": isActive, className: cn("tw:data-[active=true]:border-ring tw:data-[active=true]:ring-ring/50 tw:data-[active=true]:aria-invalid:ring-destructive/20 tw:dark:data-[active=true]:aria-invalid:ring-destructive/40 tw:aria-invalid:border-destructive tw:data-[active=true]:aria-invalid:border-destructive tw:dark:bg-input/30 tw:border-input tw:relative tw:flex tw:h-9 tw:w-9 tw:items-center tw:justify-center tw:border-y tw:border-r tw:text-sm tw:shadow-xs tw:transition-all tw:outline-none tw:first:rounded-l-md tw:first:border-l tw:last:rounded-r-md tw:data-[active=true]:z-10 tw:data-[active=true]:ring-[3px]", className), ...props, children: [char, hasFakeCaret && (jsx("div", { className: "tw:pointer-events-none tw:absolute tw:inset-0 tw:flex tw:items-center tw:justify-center", children: jsx("div", { className: "tw:animate-caret-blink tw:bg-foreground tw:h-4 tw:w-px tw:duration-1000" }) }))] }));
|
|
17
|
+
}
|
|
18
|
+
function InputOTPSeparator({ ...props }) {
|
|
19
|
+
return (jsx("div", { "data-slot": "input-otp-separator", role: "separator", ...props, children: jsx(MinusIcon, {}) }));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/components/input.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,iBAAS,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,2CAc1E;AAED,OAAO,EAAE,KAAK,EAAE,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { cn } from '../lib/utils.js';
|
|
3
|
+
|
|
4
|
+
function Input({ className, type, ...props }) {
|
|
5
|
+
return (jsx("input", { type: type, "data-slot": "input", className: cn("tw:file:text-foreground tw:placeholder:text-muted-foreground tw:selection:bg-primary tw:selection:text-primary-foreground tw:dark:bg-input/30 tw:border-input tw:h-10 tw:w-full tw:min-w-0 tw:rounded-md tw:border tw:bg-transparent tw:px-3 tw:py-1 tw:text-base tw:shadow-xs tw:transition-[color,box-shadow] tw:outline-none tw:file:inline-flex tw:file:h-7 tw:file:border-0 tw:file:bg-transparent tw:file:text-sm tw:file:font-medium tw:disabled:pointer-events-none tw:disabled:cursor-not-allowed tw:disabled:opacity-50 tw:md:text-sm", "tw:focus-visible:border-ring tw:focus-visible:ring-ring/50 tw:focus-visible:ring-[3px]", "tw:aria-invalid:ring-destructive/20 tw:dark:aria-invalid:ring-destructive/40 tw:aria-invalid:border-destructive", className), ...props }));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export { Input };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
import { Separator } from "../components/separator";
|
|
4
|
+
declare function ItemGroup({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
declare function ItemSeparator({ className, ...props }: React.ComponentProps<typeof Separator>): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
declare const itemVariants: (props?: ({
|
|
7
|
+
variant?: "default" | "outline" | "muted" | null | undefined;
|
|
8
|
+
size?: "default" | "sm" | null | undefined;
|
|
9
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
10
|
+
declare function Item({ className, variant, size, asChild, ...props }: React.ComponentProps<"div"> & VariantProps<typeof itemVariants> & {
|
|
11
|
+
asChild?: boolean;
|
|
12
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
declare const itemMediaVariants: (props?: ({
|
|
14
|
+
variant?: "default" | "icon" | "image" | null | undefined;
|
|
15
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
16
|
+
declare function ItemMedia({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps<typeof itemMediaVariants>): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
declare function ItemContent({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
declare function ItemTitle({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
declare function ItemDescription({ className, ...props }: React.ComponentProps<"p">): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
declare function ItemActions({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
declare function ItemHeader({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
declare function ItemFooter({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
export { Item, ItemMedia, ItemContent, ItemActions, ItemGroup, ItemSeparator, ItemTitle, ItemDescription, ItemHeader, ItemFooter, };
|
|
24
|
+
//# sourceMappingURL=item.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"item.d.ts","sourceRoot":"","sources":["../../src/components/item.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAGjE,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAEnD,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAStE;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,SAAS,CAAC,2CASxC;AAED,QAAA,MAAM,YAAY;;;8EAmBjB,CAAA;AAED,iBAAS,IAAI,CAAC,EACZ,SAAS,EACT,OAAmB,EACnB,IAAgB,EAChB,OAAe,EACf,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAC5B,YAAY,CAAC,OAAO,YAAY,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,2CAW1D;AAED,QAAA,MAAM,iBAAiB;;8EAetB,CAAA;AAED,iBAAS,SAAS,CAAC,EACjB,SAAS,EACT,OAAmB,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,OAAO,iBAAiB,CAAC,2CAStE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAWxE;AAED,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAWtE;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,2CAY1E;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQxE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAWvE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAWvE;AAED,OAAO,EACL,IAAI,EACJ,SAAS,EACT,WAAW,EACX,WAAW,EACX,SAAS,EACT,aAAa,EACb,SAAS,EACT,eAAe,EACf,UAAU,EACV,UAAU,GACX,CAAA"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
3
|
+
import { cva } from 'class-variance-authority';
|
|
4
|
+
import { cn } from '../lib/utils.js';
|
|
5
|
+
import { Separator } from './separator.js';
|
|
6
|
+
|
|
7
|
+
function ItemGroup({ className, ...props }) {
|
|
8
|
+
return (jsx("div", { role: "list", "data-slot": "item-group", className: cn("group/item-group tw:flex tw:flex-col", className), ...props }));
|
|
9
|
+
}
|
|
10
|
+
function ItemSeparator({ className, ...props }) {
|
|
11
|
+
return (jsx(Separator, { "data-slot": "item-separator", orientation: "horizontal", className: cn("tw:my-0", className), ...props }));
|
|
12
|
+
}
|
|
13
|
+
const itemVariants = cva("group/item tw:flex tw:items-center tw:border tw:border-transparent tw:text-sm tw:rounded-md tw:transition-colors [a]:hover:tw:bg-accent/50 [a]:tw:transition-colors tw:duration-100 tw:flex-wrap tw:outline-none focus-visible:tw:border-ring focus-visible:tw:ring-ring/50 focus-visible:tw:ring-[3px]", {
|
|
14
|
+
variants: {
|
|
15
|
+
variant: {
|
|
16
|
+
default: "tw:bg-transparent",
|
|
17
|
+
outline: "tw:border-border",
|
|
18
|
+
muted: "tw:bg-muted/50",
|
|
19
|
+
},
|
|
20
|
+
size: {
|
|
21
|
+
default: "tw:p-4 tw:gap-4 ",
|
|
22
|
+
sm: "tw:py-3 tw:px-4 tw:gap-2.5",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
defaultVariants: {
|
|
26
|
+
variant: "default",
|
|
27
|
+
size: "default",
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
function Item({ className, variant = "default", size = "default", asChild = false, ...props }) {
|
|
31
|
+
const Comp = asChild ? Slot : "div";
|
|
32
|
+
return (jsx(Comp, { "data-slot": "item", "data-variant": variant, "data-size": size, className: cn(itemVariants({ variant, size, className })), ...props }));
|
|
33
|
+
}
|
|
34
|
+
const itemMediaVariants = cva("tw:flex tw:shrink-0 tw:items-center tw:justify-center tw:gap-2 group-has-[[data-slot=item-description]]/item:tw:self-start [&_svg]:tw:pointer-events-none group-has-[[data-slot=item-description]]/item:tw:translate-y-0.5", {
|
|
35
|
+
variants: {
|
|
36
|
+
variant: {
|
|
37
|
+
default: "tw:bg-transparent",
|
|
38
|
+
icon: "tw:size-8 tw:border tw:rounded-sm tw:bg-muted [&_svg:not([class*='size-'])]:tw:size-4",
|
|
39
|
+
image: "tw:size-10 tw:rounded-sm tw:overflow-hidden [&_img]:tw:size-full [&_img]:tw:object-cover",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
defaultVariants: {
|
|
43
|
+
variant: "default",
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
function ItemMedia({ className, variant = "default", ...props }) {
|
|
47
|
+
return (jsx("div", { "data-slot": "item-media", "data-variant": variant, className: cn(itemMediaVariants({ variant, className })), ...props }));
|
|
48
|
+
}
|
|
49
|
+
function ItemContent({ className, ...props }) {
|
|
50
|
+
return (jsx("div", { "data-slot": "item-content", className: cn("tw:flex tw:flex-1 tw:flex-col tw:gap-1 [&+[data-slot=item-content]]:tw:flex-none", className), ...props }));
|
|
51
|
+
}
|
|
52
|
+
function ItemTitle({ className, ...props }) {
|
|
53
|
+
return (jsx("div", { "data-slot": "item-title", className: cn("tw:flex tw:w-fit tw:items-center tw:gap-2 tw:text-sm tw:leading-snug tw:font-medium", className), ...props }));
|
|
54
|
+
}
|
|
55
|
+
function ItemDescription({ className, ...props }) {
|
|
56
|
+
return (jsx("p", { "data-slot": "item-description", className: cn("tw:text-muted-foreground tw:line-clamp-2 tw:text-sm tw:leading-normal tw:font-normal tw:text-balance", "[&>a:hover]:tw:text-primary [&>a]:tw:underline [&>a]:tw:underline-offset-4", className), ...props }));
|
|
57
|
+
}
|
|
58
|
+
function ItemActions({ className, ...props }) {
|
|
59
|
+
return (jsx("div", { "data-slot": "item-actions", className: cn("tw:flex tw:items-center tw:gap-2", className), ...props }));
|
|
60
|
+
}
|
|
61
|
+
function ItemHeader({ className, ...props }) {
|
|
62
|
+
return (jsx("div", { "data-slot": "item-header", className: cn("tw:flex tw:basis-full tw:items-center tw:justify-between tw:gap-2", className), ...props }));
|
|
63
|
+
}
|
|
64
|
+
function ItemFooter({ className, ...props }) {
|
|
65
|
+
return (jsx("div", { "data-slot": "item-footer", className: cn("tw:flex tw:basis-full tw:items-center tw:justify-between tw:gap-2", className), ...props }));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
declare function Kbd({ className, ...props }: React.ComponentProps<"kbd">): import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
declare function KbdGroup({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
export { Kbd, KbdGroup };
|
|
4
|
+
//# sourceMappingURL=kbd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kbd.d.ts","sourceRoot":"","sources":["../../src/components/kbd.tsx"],"names":[],"mappings":"AAEA,iBAAS,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAahE;AAED,iBAAS,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQrE;AAED,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { cn } from '../lib/utils.js';
|
|
3
|
+
|
|
4
|
+
function Kbd({ className, ...props }) {
|
|
5
|
+
return (jsx("kbd", { "data-slot": "kbd", className: cn("tw:bg-muted tw:text-muted-foreground tw:pointer-events-none tw:inline-flex tw:h-5 tw:w-fit tw:min-w-5 tw:items-center tw:justify-center tw:gap-1 tw:rounded-sm tw:px-1 tw:font-sans tw:text-xs tw:font-medium tw:select-none", "tw:[&_svg:not([class*='size-'])]:size-3", "tw:[[data-slot=tooltip-content]_&]:bg-background/20 tw:[[data-slot=tooltip-content]_&]:text-background tw:dark:[[data-slot=tooltip-content]_&]:bg-background/10", className), ...props }));
|
|
6
|
+
}
|
|
7
|
+
function KbdGroup({ className, ...props }) {
|
|
8
|
+
return (jsx("kbd", { "data-slot": "kbd-group", className: cn("tw:inline-flex tw:items-center tw:gap-1", className), ...props }));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export { Kbd, KbdGroup };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
3
|
+
interface LabelProps extends React.ComponentProps<typeof LabelPrimitive.Root> {
|
|
4
|
+
isRequired?: boolean;
|
|
5
|
+
}
|
|
6
|
+
declare function Label({ className, isRequired, children, ...props }: LabelProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export { Label };
|
|
8
|
+
//# sourceMappingURL=label.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../src/components/label.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAA;AAIvD,UAAU,UAAW,SAAQ,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,IAAI,CAAC;IAC3E,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,iBAAS,KAAK,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,2CAmBvE;AAED,OAAO,EAAE,KAAK,EAAE,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
3
|
+
import { cn } from '../lib/utils.js';
|
|
4
|
+
|
|
5
|
+
function Label({ className, isRequired, children, ...props }) {
|
|
6
|
+
return (jsxs(LabelPrimitive.Root, { "data-slot": "label", className: cn("tw:flex tw:items-center tw:gap-2 tw:text-sm tw:leading-none tw:font-medium tw:select-none tw:group-data-[disabled=true]:pointer-events-none tw:group-data-[disabled=true]:opacity-50 tw:peer-disabled:cursor-not-allowed tw:peer-disabled:opacity-50", className), "aria-required": isRequired, ...props, children: [children, isRequired && (jsx("span", { className: "tw:text-destructive", "aria-hidden": "true", children: "*" }))] }));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { Label };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { LoginScreenProps } from "./login-screen.types";
|
|
2
|
+
export type { LoginScreenIdentifierMode, LoginScreenTab, LoginScreenFooterLink, LoginScreenSubmitPayload, LoginScreenTestimonial, LoginScreenProps, } from "./login-screen.types";
|
|
3
|
+
export declare function LoginScreen({ className, splitLayout, splitImageWidthPercent, imageSrc, imageAlt, imageOverlayContent, testimonial, imageOverlayOpacity, logo, title, description, tabs, defaultTabId, tabId, onTabChange, identifierMode, identifierLabel, identifierPlaceholder, passwordLabel, passwordPlaceholder, rememberMeLabel, forgotPasswordLabel, forgotPasswordTitle, forgotPasswordDescription, forgotPasswordEmailLabel, forgotPasswordEmailPlaceholder, forgotPasswordSubmitLabel, forgotPasswordBackLabel, forgotPasswordSentTitle, forgotPasswordSentDescriptionPrefix, forgotPasswordSentInstructions, forgotPasswordResendLabel, forgotPasswordResendDelaySeconds, submitLabel, submitLoadingLabel, ssoLabel, ssoButtonLabel, ssoEmailTitle, ssoEmailDescription, ssoEmailLabel, ssoEmailPlaceholder, ssoEmailSubmitLabel, ssoEmailHint, ssoEmailBackAriaLabel, legalNotice, footerLinks, isSubmitting, isForgotPasswordSubmitting, isSsoSubmitting, onSubmit, onForgotPasswordSubmit, onSsoClick, onSsoSubmit, }: LoginScreenProps): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
//# sourceMappingURL=login-screen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login-screen.d.ts","sourceRoot":"","sources":["../../src/components/login-screen.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAEV,gBAAgB,EAGjB,MAAM,sBAAsB,CAAA;AAE7B,YAAY,EACV,yBAAyB,EACzB,cAAc,EACd,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,sBAAsB,CAAA;AAwF7B,wBAAgB,WAAW,CAAC,EAC1B,SAAS,EACT,WAAkB,EAClB,sBAA2B,EAC3B,QAA0B,EAC1B,QAA6B,EAC7B,mBAAmB,EACnB,WAAiC,EACjC,mBAA0B,EAC1B,IAAI,EACJ,KAA0B,EAC1B,WAAoD,EACpD,IAAS,EACT,YAAY,EACZ,KAAK,EACL,WAAW,EACX,cAAwB,EACxB,eAAe,EACf,qBAAqB,EACrB,aAA0B,EAC1B,mBAA2C,EAC3C,eAA+B,EAC/B,mBAAwC,EACxC,mBAA2C,EAC3C,yBAAmF,EACnF,wBAAkC,EAClC,8BAA2D,EAC3D,yBAA6C,EAC7C,uBAA2C,EAC3C,uBAA4C,EAC5C,mCAAwE,EACxE,8BAAmI,EACnI,yBAA0C,EAC1C,gCAAqC,EACrC,WAAsB,EACtB,kBAAoC,EACpC,QAAe,EACf,cAA+C,EAC/C,aAAkC,EAClC,mBAAyF,EACzF,aAA+B,EAC/B,mBAAwC,EACxC,mBAAgC,EAChC,YAAkF,EAClF,qBAAiC,EACjC,WAAW,EACX,WAAkC,EAClC,YAAoB,EACpB,0BAAkC,EAClC,eAAuB,EACvB,QAAQ,EACR,sBAAsB,EACtB,UAAU,EACV,WAAW,GACZ,EAAE,gBAAgB,2CA+clB"}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { cn } from '../lib/utils.js';
|
|
4
|
+
import { SignInView, ForgotPasswordView, ForgotPasswordSentView, SsoEmailView, FooterLinks, SplitMediaPane } from './login-screen.views.js';
|
|
5
|
+
|
|
6
|
+
const DEFAULT_FOOTER_LINKS = [
|
|
7
|
+
{ label: "Help", href: "#" },
|
|
8
|
+
{ label: "Privacy", href: "#" },
|
|
9
|
+
{ label: "Terms", href: "#" },
|
|
10
|
+
];
|
|
11
|
+
const DEFAULT_TESTIMONIAL = {
|
|
12
|
+
quote: '"BLAZE has completely transformed how we manage our dispensary. The platform is intuitive, fast, and our team loves it."',
|
|
13
|
+
authorName: "Sarah Johnson",
|
|
14
|
+
authorTitle: "Operations Director, Green Valley Dispensary",
|
|
15
|
+
};
|
|
16
|
+
const DEFAULT_LEGAL_NOTICE = (jsxs(Fragment, { children: ["By continuing, you agree to our", " ", jsx("a", { href: "#", className: "tw:underline tw:hover:text-foreground", children: "Terms of Service" }), " ", "and", " ", jsx("a", { href: "#", className: "tw:underline tw:hover:text-foreground", children: "Privacy Policy" })] }));
|
|
17
|
+
function clampPercent(value) {
|
|
18
|
+
if (Number.isNaN(value)) {
|
|
19
|
+
return 40;
|
|
20
|
+
}
|
|
21
|
+
return Math.min(100, Math.max(0, value));
|
|
22
|
+
}
|
|
23
|
+
function clampOpacity(value) {
|
|
24
|
+
if (Number.isNaN(value)) {
|
|
25
|
+
return 0.35;
|
|
26
|
+
}
|
|
27
|
+
return Math.min(1, Math.max(0, value));
|
|
28
|
+
}
|
|
29
|
+
function getIdentifierInputType(mode) {
|
|
30
|
+
if (mode === "phone") {
|
|
31
|
+
return "tel";
|
|
32
|
+
}
|
|
33
|
+
if (mode === "email-or-phone") {
|
|
34
|
+
return "text";
|
|
35
|
+
}
|
|
36
|
+
return "email";
|
|
37
|
+
}
|
|
38
|
+
function getIdentifierDefaults(mode) {
|
|
39
|
+
if (mode === "phone") {
|
|
40
|
+
return {
|
|
41
|
+
label: "Phone number",
|
|
42
|
+
placeholder: "Enter your phone number",
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (mode === "email-or-phone") {
|
|
46
|
+
return {
|
|
47
|
+
label: "Email or phone",
|
|
48
|
+
placeholder: "Enter your email or phone number",
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
label: "Email",
|
|
53
|
+
placeholder: "Enter your email address",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function LoginScreen({ className, splitLayout = true, splitImageWidthPercent = 40, imageSrc = "/login-bg.jpg", imageAlt = "Login background", imageOverlayContent, testimonial = DEFAULT_TESTIMONIAL, imageOverlayOpacity = 0.35, logo, title = "Welcome to Blaze", description = "Sign in with your email and password", tabs = [], defaultTabId, tabId, onTabChange, identifierMode = "email", identifierLabel, identifierPlaceholder, passwordLabel = "Password", passwordPlaceholder = "Enter your password", rememberMeLabel = "Remember Me", forgotPasswordLabel = "Forgot Password?", forgotPasswordTitle = "Reset your password", forgotPasswordDescription = "Enter your email and we will send reset instructions.", forgotPasswordEmailLabel = "Email", forgotPasswordEmailPlaceholder = "Enter your email address", forgotPasswordSubmitLabel = "Send Reset Link", forgotPasswordBackLabel = "Back to sign in", forgotPasswordSentTitle = "Check your email", forgotPasswordSentDescriptionPrefix = "We sent a password reset link to", forgotPasswordSentInstructions = "Click the link in the email to reset your password. If you don't see it, check your spam folder.", forgotPasswordResendLabel = "Resend email", forgotPasswordResendDelaySeconds = 60, submitLabel = "Log In", submitLoadingLabel = "Signing in...", ssoLabel = "Or", ssoButtonLabel = "Continue with Enterprise SSO", ssoEmailTitle = "Enter your email", ssoEmailDescription = "We'll check if you have an existing account or need to create one", ssoEmailLabel = "Email address", ssoEmailPlaceholder = "name@company.com", ssoEmailSubmitLabel = "Continue", ssoEmailHint = "Enterprise users will be redirected to their company's SSO portal", ssoEmailBackAriaLabel = "Go back", legalNotice, footerLinks = DEFAULT_FOOTER_LINKS, isSubmitting = false, isForgotPasswordSubmitting = false, isSsoSubmitting = false, onSubmit, onForgotPasswordSubmit, onSsoClick, onSsoSubmit, }) {
|
|
57
|
+
const id = React.useId();
|
|
58
|
+
const identifierId = `${id}-identifier`;
|
|
59
|
+
const passwordId = `${id}-password`;
|
|
60
|
+
const rememberId = `${id}-remember`;
|
|
61
|
+
const forgotEmailId = `${id}-forgot-email`;
|
|
62
|
+
const ssoEmailId = `${id}-sso-email`;
|
|
63
|
+
const [mode, setMode] = React.useState("sign-in");
|
|
64
|
+
const [identifier, setIdentifier] = React.useState("");
|
|
65
|
+
const [password, setPassword] = React.useState("");
|
|
66
|
+
const [forgotEmail, setForgotEmail] = React.useState("");
|
|
67
|
+
const [ssoEmail, setSsoEmail] = React.useState("");
|
|
68
|
+
const [rememberMe, setRememberMe] = React.useState(false);
|
|
69
|
+
const [showPassword, setShowPassword] = React.useState(false);
|
|
70
|
+
const [isResending, setIsResending] = React.useState(false);
|
|
71
|
+
const [imageLoadError, setImageLoadError] = React.useState(false);
|
|
72
|
+
const [logoLoadError, setLogoLoadError] = React.useState(false);
|
|
73
|
+
const [isSplitViewport, setIsSplitViewport] = React.useState(true);
|
|
74
|
+
const [forgotPasswordError, setForgotPasswordError] = React.useState(null);
|
|
75
|
+
const tabListRef = React.useRef(null);
|
|
76
|
+
const resendDelaySeconds = React.useMemo(() => {
|
|
77
|
+
if (Number.isNaN(forgotPasswordResendDelaySeconds)) {
|
|
78
|
+
return 60;
|
|
79
|
+
}
|
|
80
|
+
return Math.max(0, Math.floor(forgotPasswordResendDelaySeconds));
|
|
81
|
+
}, [forgotPasswordResendDelaySeconds]);
|
|
82
|
+
const [resendCountdown, setResendCountdown] = React.useState(resendDelaySeconds);
|
|
83
|
+
const firstTabId = tabs[0]?.id ?? null;
|
|
84
|
+
const [internalTabId, setInternalTabId] = React.useState(defaultTabId ?? firstTabId);
|
|
85
|
+
React.useEffect(() => {
|
|
86
|
+
if (tabId !== undefined) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (!internalTabId && firstTabId) {
|
|
90
|
+
setInternalTabId(firstTabId);
|
|
91
|
+
}
|
|
92
|
+
}, [firstTabId, internalTabId, tabId]);
|
|
93
|
+
React.useEffect(() => {
|
|
94
|
+
setImageLoadError(false);
|
|
95
|
+
}, [imageSrc]);
|
|
96
|
+
React.useEffect(() => {
|
|
97
|
+
const handleResize = () => {
|
|
98
|
+
setIsSplitViewport(window.innerWidth >= 768);
|
|
99
|
+
};
|
|
100
|
+
handleResize();
|
|
101
|
+
window.addEventListener("resize", handleResize);
|
|
102
|
+
return () => {
|
|
103
|
+
window.removeEventListener("resize", handleResize);
|
|
104
|
+
};
|
|
105
|
+
}, []);
|
|
106
|
+
const activeTabId = tabId ?? internalTabId ?? firstTabId;
|
|
107
|
+
const shouldShowSplitPane = splitLayout && isSplitViewport;
|
|
108
|
+
const hasSplitImage = Boolean(imageSrc) && !imageLoadError;
|
|
109
|
+
const imageWidth = clampPercent(splitImageWidthPercent);
|
|
110
|
+
const overlayOpacity = clampOpacity(imageOverlayOpacity);
|
|
111
|
+
const resolvedTestimonial = testimonial === null
|
|
112
|
+
? null
|
|
113
|
+
: {
|
|
114
|
+
quote: testimonial?.quote || DEFAULT_TESTIMONIAL.quote,
|
|
115
|
+
authorName: testimonial?.authorName || DEFAULT_TESTIMONIAL.authorName,
|
|
116
|
+
authorTitle: testimonial?.authorTitle === undefined
|
|
117
|
+
? DEFAULT_TESTIMONIAL.authorTitle
|
|
118
|
+
: testimonial.authorTitle,
|
|
119
|
+
};
|
|
120
|
+
const identifierDefaults = React.useMemo(() => getIdentifierDefaults(identifierMode), [identifierMode]);
|
|
121
|
+
const resolvedIdentifierLabel = identifierLabel ?? identifierDefaults.label;
|
|
122
|
+
const resolvedIdentifierPlaceholder = identifierPlaceholder ?? identifierDefaults.placeholder;
|
|
123
|
+
const setTabSelection = React.useCallback((tab) => {
|
|
124
|
+
if (tab.disabled) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (tabId === undefined) {
|
|
128
|
+
setInternalTabId(tab.id);
|
|
129
|
+
}
|
|
130
|
+
onTabChange?.(tab.id);
|
|
131
|
+
}, [onTabChange, tabId]);
|
|
132
|
+
const handleTabClick = React.useCallback((tab, options = {}) => {
|
|
133
|
+
if (tab.disabled) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
setTabSelection(tab);
|
|
137
|
+
if (tab.onSelect) {
|
|
138
|
+
tab.onSelect(tab.id);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (options.allowNavigation === false ||
|
|
142
|
+
!tab.href ||
|
|
143
|
+
typeof window === "undefined") {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (tab.external) {
|
|
147
|
+
window.open(tab.href, "_blank", "noopener,noreferrer");
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
window.location.assign(tab.href);
|
|
151
|
+
}, [setTabSelection]);
|
|
152
|
+
const handleTabKeyDown = React.useCallback((event, currentIndex) => {
|
|
153
|
+
const enabledTabIndices = tabs.reduce((acc, tab, index) => {
|
|
154
|
+
if (!tab.disabled) {
|
|
155
|
+
acc.push(index);
|
|
156
|
+
}
|
|
157
|
+
return acc;
|
|
158
|
+
}, []);
|
|
159
|
+
if (enabledTabIndices.length === 0) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const isPrev = event.key === "ArrowLeft" || event.key === "ArrowUp";
|
|
163
|
+
const isNext = event.key === "ArrowRight" || event.key === "ArrowDown";
|
|
164
|
+
const isHome = event.key === "Home";
|
|
165
|
+
const isEnd = event.key === "End";
|
|
166
|
+
if (!isPrev && !isNext && !isHome && !isEnd) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
event.preventDefault();
|
|
170
|
+
let nextIndex = currentIndex;
|
|
171
|
+
if (isHome) {
|
|
172
|
+
nextIndex = enabledTabIndices[0] ?? currentIndex;
|
|
173
|
+
}
|
|
174
|
+
else if (isEnd) {
|
|
175
|
+
nextIndex =
|
|
176
|
+
enabledTabIndices[enabledTabIndices.length - 1] ?? currentIndex;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
const enabledPosition = enabledTabIndices.indexOf(currentIndex);
|
|
180
|
+
const currentEnabledPosition = enabledPosition === -1 ? 0 : enabledPosition;
|
|
181
|
+
const delta = isNext ? 1 : -1;
|
|
182
|
+
const nextEnabledPosition = (currentEnabledPosition + delta + enabledTabIndices.length) %
|
|
183
|
+
enabledTabIndices.length;
|
|
184
|
+
nextIndex = enabledTabIndices[nextEnabledPosition] ?? currentIndex;
|
|
185
|
+
}
|
|
186
|
+
const nextTab = tabs[nextIndex];
|
|
187
|
+
if (!nextTab) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
handleTabClick(nextTab, { allowNavigation: false });
|
|
191
|
+
const tabButtons = tabListRef.current?.querySelectorAll('[role="tab"]');
|
|
192
|
+
tabButtons?.[nextIndex]?.focus();
|
|
193
|
+
}, [handleTabClick, tabs]);
|
|
194
|
+
const handleSignInSubmit = async (event) => {
|
|
195
|
+
event.preventDefault();
|
|
196
|
+
const nextIdentifier = identifier.trim();
|
|
197
|
+
const nextPassword = password.trim();
|
|
198
|
+
if (!nextIdentifier || !nextPassword) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
await onSubmit?.({
|
|
202
|
+
identifier: nextIdentifier,
|
|
203
|
+
password: nextPassword,
|
|
204
|
+
rememberMe,
|
|
205
|
+
tabId: activeTabId,
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
const handleForgotPasswordClick = () => {
|
|
209
|
+
if (identifier.includes("@")) {
|
|
210
|
+
setForgotEmail(identifier.trim());
|
|
211
|
+
}
|
|
212
|
+
setForgotPasswordError(null);
|
|
213
|
+
setMode("forgot-password");
|
|
214
|
+
};
|
|
215
|
+
const handleBackToSignIn = () => {
|
|
216
|
+
setForgotPasswordError(null);
|
|
217
|
+
setMode("sign-in");
|
|
218
|
+
};
|
|
219
|
+
const handleForgotPasswordSubmit = async (event) => {
|
|
220
|
+
event.preventDefault();
|
|
221
|
+
const nextForgotEmail = forgotEmail.trim();
|
|
222
|
+
if (!nextForgotEmail) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
setForgotPasswordError(null);
|
|
226
|
+
try {
|
|
227
|
+
await onForgotPasswordSubmit?.(nextForgotEmail);
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
const message = error instanceof Error && error.message
|
|
231
|
+
? error.message
|
|
232
|
+
: "Failed to send reset email. Please try again.";
|
|
233
|
+
setForgotPasswordError(message);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
setResendCountdown(resendDelaySeconds);
|
|
237
|
+
setMode("forgot-password-sent");
|
|
238
|
+
};
|
|
239
|
+
const handleSsoClick = async () => {
|
|
240
|
+
if (onSsoClick) {
|
|
241
|
+
await onSsoClick();
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (identifier.includes("@")) {
|
|
245
|
+
setSsoEmail(identifier.trim());
|
|
246
|
+
}
|
|
247
|
+
setMode("sso-email");
|
|
248
|
+
};
|
|
249
|
+
const handleSsoEmailSubmit = async (event) => {
|
|
250
|
+
event.preventDefault();
|
|
251
|
+
const nextSsoEmail = ssoEmail.trim();
|
|
252
|
+
if (!nextSsoEmail) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
await onSsoSubmit?.(nextSsoEmail);
|
|
256
|
+
};
|
|
257
|
+
const handleResendEmail = async () => {
|
|
258
|
+
const nextForgotEmail = forgotEmail.trim();
|
|
259
|
+
if (!nextForgotEmail) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
setForgotPasswordError(null);
|
|
263
|
+
setIsResending(true);
|
|
264
|
+
try {
|
|
265
|
+
await onForgotPasswordSubmit?.(nextForgotEmail);
|
|
266
|
+
setResendCountdown(resendDelaySeconds);
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
const message = error instanceof Error && error.message
|
|
270
|
+
? error.message
|
|
271
|
+
: "Failed to resend reset email. Please try again.";
|
|
272
|
+
setForgotPasswordError(message);
|
|
273
|
+
}
|
|
274
|
+
finally {
|
|
275
|
+
setIsResending(false);
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
React.useEffect(() => {
|
|
279
|
+
if (mode !== "forgot-password-sent") {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (resendCountdown <= 0) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const timeoutId = window.setTimeout(() => {
|
|
286
|
+
setResendCountdown((previous) => Math.max(0, previous - 1));
|
|
287
|
+
}, 1000);
|
|
288
|
+
return () => {
|
|
289
|
+
window.clearTimeout(timeoutId);
|
|
290
|
+
};
|
|
291
|
+
}, [mode, resendCountdown]);
|
|
292
|
+
const modeView = mode === "sign-in" ? (jsx(SignInView, { tabs: tabs, activeTabId: activeTabId, tabListRef: tabListRef, onTabClick: (tab) => handleTabClick(tab), onTabKeyDown: handleTabKeyDown, identifierId: identifierId, identifierLabel: resolvedIdentifierLabel, identifierType: getIdentifierInputType(identifierMode), identifierPlaceholder: resolvedIdentifierPlaceholder, identifier: identifier, onIdentifierChange: setIdentifier, passwordId: passwordId, passwordLabel: passwordLabel, passwordPlaceholder: passwordPlaceholder, password: password, onPasswordChange: setPassword, showPassword: showPassword, onTogglePassword: () => setShowPassword((previous) => !previous), rememberId: rememberId, rememberMe: rememberMe, onRememberMeChange: setRememberMe, rememberMeLabel: rememberMeLabel, forgotPasswordLabel: forgotPasswordLabel, onForgotPasswordClick: handleForgotPasswordClick, isSubmitting: isSubmitting, submitLabel: submitLabel, submitLoadingLabel: submitLoadingLabel, onSubmit: handleSignInSubmit, ssoLabel: ssoLabel, ssoButtonLabel: ssoButtonLabel, onSsoClick: handleSsoClick, legalNotice: legalNotice ?? DEFAULT_LEGAL_NOTICE, logo: logo, logoLoadError: logoLoadError, onLogoError: () => setLogoLoadError(true), title: title, description: description, autoCompleteIdentifier: identifierMode === "phone" ? "tel" : "email" })) : mode === "forgot-password" ? (jsx(ForgotPasswordView, { title: forgotPasswordTitle, description: forgotPasswordDescription, emailId: forgotEmailId, emailLabel: forgotPasswordEmailLabel, email: forgotEmail, onEmailChange: setForgotEmail, emailPlaceholder: forgotPasswordEmailPlaceholder, submitLabel: forgotPasswordSubmitLabel, backLabel: forgotPasswordBackLabel, isSubmitting: isForgotPasswordSubmitting, onSubmit: handleForgotPasswordSubmit, onBack: handleBackToSignIn, error: forgotPasswordError })) : mode === "forgot-password-sent" ? (jsx(ForgotPasswordSentView, { backAriaLabel: ssoEmailBackAriaLabel, onBack: handleBackToSignIn, title: forgotPasswordSentTitle, descriptionPrefix: forgotPasswordSentDescriptionPrefix, email: forgotEmail, instructions: forgotPasswordSentInstructions, resendLabel: forgotPasswordResendLabel, resendCountdown: resendCountdown, onResend: handleResendEmail, isResending: isResending, error: forgotPasswordError, backLabel: forgotPasswordBackLabel })) : (jsx(SsoEmailView, { backAriaLabel: ssoEmailBackAriaLabel, onBack: () => setMode("sign-in"), title: ssoEmailTitle, description: ssoEmailDescription, emailId: ssoEmailId, emailLabel: ssoEmailLabel, email: ssoEmail, onEmailChange: setSsoEmail, emailPlaceholder: ssoEmailPlaceholder, submitLabel: ssoEmailSubmitLabel, isSubmitting: isSsoSubmitting, onSubmit: handleSsoEmailSubmit, hint: ssoEmailHint }));
|
|
293
|
+
const content = (jsxs("div", { className: "tw:w-full tw:max-w-md", children: [jsx("div", { className: "tw:rounded-xl tw:border tw:border-border tw:bg-card tw:p-6 tw:shadow-sm sm:tw:p-8", children: jsx("div", { className: "tw:flex tw:flex-col tw:gap-8", children: modeView }) }), jsx(FooterLinks, { links: footerLinks })] }));
|
|
294
|
+
if (!splitLayout) {
|
|
295
|
+
return (jsx("div", { className: cn("tw:min-h-svh tw:w-full tw:bg-background", className), children: jsx("div", { className: "tw:flex tw:min-h-svh tw:w-full tw:items-center tw:justify-center tw:p-6 sm:tw:p-12", children: content }) }));
|
|
296
|
+
}
|
|
297
|
+
return (jsx("div", { className: cn("tw:min-h-svh tw:w-full tw:bg-background", className), children: jsxs("div", { className: "tw:flex tw:min-h-svh tw:w-full", children: [shouldShowSplitPane ? (jsx(SplitMediaPane, { widthPercent: imageWidth, hasSplitImage: hasSplitImage, imageSrc: imageSrc, imageAlt: imageAlt, onImageError: () => setImageLoadError(true), overlayOpacity: overlayOpacity, imageOverlayContent: imageOverlayContent, testimonial: resolvedTestimonial })) : null, jsx("div", { className: cn("tw:flex tw:w-full tw:items-center tw:justify-center tw:p-6 sm:tw:p-12", shouldShowSplitPane && "tw:flex-1"), children: content })] }) }));
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export { LoginScreen };
|