@skdx/react-blocks 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +9 -0
- package/dist/dashboard-layout/DashboardLayout.cjs +2 -0
- package/dist/dashboard-layout/DashboardLayout.d.cts +20 -0
- package/dist/dashboard-layout/DashboardLayout.d.ts +20 -0
- package/dist/dashboard-layout/DashboardLayout.js +2 -0
- package/dist/dashboard-layout/index.d.cts +2 -0
- package/dist/dashboard-layout/index.d.ts +2 -0
- package/dist/dashboard-layout/types.d.cts +76 -0
- package/dist/dashboard-layout/types.d.ts +76 -0
- package/dist/index.cjs +2 -0
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/internal/part.d.cts +22 -0
- package/dist/internal/part.d.ts +22 -0
- package/dist/internal/useControllableState.d.cts +9 -0
- package/dist/internal/useControllableState.d.ts +9 -0
- package/dist/page-container/PageContainer.cjs +2 -0
- package/dist/page-container/PageContainer.d.cts +21 -0
- package/dist/page-container/PageContainer.d.ts +21 -0
- package/dist/page-container/PageContainer.js +2 -0
- package/dist/page-container/index.d.cts +2 -0
- package/dist/page-container/index.d.ts +2 -0
- package/dist/page-container/types.d.cts +46 -0
- package/dist/page-container/types.d.ts +46 -0
- package/dist/sign-in-page/SignInPage.cjs +2 -0
- package/dist/sign-in-page/SignInPage.d.cts +21 -0
- package/dist/sign-in-page/SignInPage.d.ts +21 -0
- package/dist/sign-in-page/SignInPage.js +2 -0
- package/dist/sign-in-page/index.d.cts +2 -0
- package/dist/sign-in-page/index.d.ts +2 -0
- package/dist/sign-in-page/types.d.cts +68 -0
- package/dist/sign-in-page/types.d.ts +68 -0
- package/package.json +107 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SkandaDX
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @skdx/react-blocks
|
|
2
|
+
|
|
3
|
+
React blocks for the SkandaDX design system — page-level compositions of `@skdx/react` styled by `@skdx/skins`.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
pnpm add @skdx/react-blocks @skdx/react
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Documentation: <https://github.com/SkandaDX/ui.skdx/tree/main/packages/react-blocks#readme>
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
"use strict";var R=Object.create;var u=Object.defineProperty;var T=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var S=Object.getPrototypeOf,I=Object.prototype.hasOwnProperty;var $=(t,a)=>{for(var o in a)u(t,o,{get:a[o],enumerable:!0})},f=(t,a,o,r)=>{if(a&&typeof a=="object"||typeof a=="function")for(let d of L(a))!I.call(t,d)&&d!==o&&u(t,d,{get:()=>a[d],enumerable:!(r=T(a,d))||r.enumerable});return t};var p=(t,a,o)=>(o=t!=null?R(S(t)):{},f(a||!t||!t.__esModule?u(o,"default",{value:t,enumerable:!0}):o,t)),A=t=>f(u({},"__esModule",{value:!0}),t);var C={};$(C,{DashboardLayout:()=>c});module.exports=A(C);var k=p(require("react"),1),x=require("@skdx/react");function O(...t){let a="";for(let o of t)o&&(a=a?`${a} ${o}`:o);return a}function e(t,a,o){let r=a==="root",d=r?`skdx-${t}`:`skdx-${t}__${a}`,s={className:O(d,o),"data-part":a};return r&&(s["data-skdx-component"]=t),s}var g=p(require("react"),1);function m(t,a,o){let[r,d]=g.useState(a),s=t!==void 0;return[s?t:r,i=>{s||d(i),o?.(i)}]}var n=require("react/jsx-runtime");function N({items:t}){return(0,n.jsx)("ul",{...e("dashboard-layout","nav-list"),children:t.map((a,o)=>{let r=a.kind??"item";return r==="divider"?(0,n.jsx)("li",{role:"separator",...e("dashboard-layout","nav-divider")},o):r==="header"?(0,n.jsx)("li",{...e("dashboard-layout","nav-header"),children:a.label},o):(0,n.jsxs)("li",{children:[a.href===void 0?(0,n.jsx)("span",{...e("dashboard-layout","nav-item"),children:a.label}):(0,n.jsx)("a",{href:a.href,"aria-current":a.current?"page":void 0,...e("dashboard-layout","nav-item"),children:a.label}),a.children&&a.children.length>0?(0,n.jsx)(N,{items:a.children}):null]},o)})})}var c=({title:t,navigation:a,navOpen:o,defaultNavOpen:r=!0,navLabel:d="Main navigation",navToggleLabel:s="Toggle navigation",onNavOpenChange:b,branding:v,actions:i,children:D,...h})=>{let y=k.useId(),[l,P]=m(o,r,b);return(0,n.jsxs)("div",{"data-nav-open":l?"":void 0,...h,...e("dashboard-layout","root",h.className),children:[(0,n.jsxs)("header",{...e("dashboard-layout","app-bar"),children:[(0,n.jsx)(x.Button,{iconOnly:!0,"aria-expanded":l,"aria-controls":y,"aria-label":s,onClick:()=>{P(!l)},...e("dashboard-layout","nav-toggle"),children:"\u2630"}),(0,n.jsx)("div",{...e("dashboard-layout","branding"),children:v}),t?(0,n.jsx)("span",{...e("dashboard-layout","title"),children:t}):null,(0,n.jsx)("div",{...e("dashboard-layout","actions"),children:i})]}),(0,n.jsxs)("div",{...e("dashboard-layout","body"),children:[(0,n.jsx)("nav",{id:y,"aria-label":d,hidden:!l,...e("dashboard-layout","nav"),children:(0,n.jsx)(N,{items:a})}),(0,n.jsx)("main",{...e("dashboard-layout","content"),children:D})]})]})};c.displayName="DashboardLayout";0&&(module.exports={DashboardLayout});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { DashboardLayoutProps } from './types.cjs';
|
|
3
|
+
/**
|
|
4
|
+
* Application shell block: an app bar with a navigation toggle, branding, title
|
|
5
|
+
* and actions; a collapsible side `<nav>`; and a `<main>` content region.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* <DashboardLayout
|
|
10
|
+
* title="Acme"
|
|
11
|
+
* navigation={[{ label: 'Overview', href: '/', current: true }]}
|
|
12
|
+
* >
|
|
13
|
+
* <p>Content.</p>
|
|
14
|
+
* </DashboardLayout>
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare const DashboardLayout: {
|
|
18
|
+
({ title, navigation, navOpen: navOpenProp, defaultNavOpen, navLabel, navToggleLabel, onNavOpenChange, branding, actions, children, ...props }: DashboardLayoutProps): React.ReactNode;
|
|
19
|
+
displayName: string;
|
|
20
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { DashboardLayoutProps } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Application shell block: an app bar with a navigation toggle, branding, title
|
|
5
|
+
* and actions; a collapsible side `<nav>`; and a `<main>` content region.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* <DashboardLayout
|
|
10
|
+
* title="Acme"
|
|
11
|
+
* navigation={[{ label: 'Overview', href: '/', current: true }]}
|
|
12
|
+
* >
|
|
13
|
+
* <p>Content.</p>
|
|
14
|
+
* </DashboardLayout>
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare const DashboardLayout: {
|
|
18
|
+
({ title, navigation, navOpen: navOpenProp, defaultNavOpen, navLabel, navToggleLabel, onNavOpenChange, branding, actions, children, ...props }: DashboardLayoutProps): React.ReactNode;
|
|
19
|
+
displayName: string;
|
|
20
|
+
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import*as p from"react";import{Button as D}from"@skdx/react";function N(...o){let a="";for(let n of o)n&&(a=a?`${a} ${n}`:n);return a}function t(o,a,n){let r=a==="root",s=r?`skdx-${o}`:`skdx-${o}__${a}`,d={className:N(s,n),"data-part":a};return r&&(d["data-skdx-component"]=o),d}import*as y from"react";function f(o,a,n){let[r,s]=y.useState(a),d=o!==void 0;return[d?o:r,i=>{d||s(i),n?.(i)}]}import{jsx as e,jsxs as u}from"react/jsx-runtime";function g({items:o}){return e("ul",{...t("dashboard-layout","nav-list"),children:o.map((a,n)=>{let r=a.kind??"item";return r==="divider"?e("li",{role:"separator",...t("dashboard-layout","nav-divider")},n):r==="header"?e("li",{...t("dashboard-layout","nav-header"),children:a.label},n):u("li",{children:[a.href===void 0?e("span",{...t("dashboard-layout","nav-item"),children:a.label}):e("a",{href:a.href,"aria-current":a.current?"page":void 0,...t("dashboard-layout","nav-item"),children:a.label}),a.children&&a.children.length>0?e(g,{items:a.children}):null]},n)})})}var m=({title:o,navigation:a,navOpen:n,defaultNavOpen:r=!0,navLabel:s="Main navigation",navToggleLabel:d="Toggle navigation",onNavOpenChange:c,branding:b,actions:i,children:k,...v})=>{let h=p.useId(),[l,x]=f(n,r,c);return u("div",{"data-nav-open":l?"":void 0,...v,...t("dashboard-layout","root",v.className),children:[u("header",{...t("dashboard-layout","app-bar"),children:[e(D,{iconOnly:!0,"aria-expanded":l,"aria-controls":h,"aria-label":d,onClick:()=>{x(!l)},...t("dashboard-layout","nav-toggle"),children:"\u2630"}),e("div",{...t("dashboard-layout","branding"),children:b}),o?e("span",{...t("dashboard-layout","title"),children:o}):null,e("div",{...t("dashboard-layout","actions"),children:i})]}),u("div",{...t("dashboard-layout","body"),children:[e("nav",{id:h,"aria-label":s,hidden:!l,...t("dashboard-layout","nav"),children:e(g,{items:a})}),e("main",{...t("dashboard-layout","content"),children:k})]})]})};m.displayName="DashboardLayout";export{m as DashboardLayout};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
/** What one {@link DashboardNavigationItem} renders as inside the side navigation. */
|
|
3
|
+
export type DashboardNavigationKind = 'item' | 'header' | 'divider';
|
|
4
|
+
/** One entry of {@link DashboardLayoutProps.navigation} — a navigation entry, a group label or a separator. */
|
|
5
|
+
export interface DashboardNavigationItem {
|
|
6
|
+
/**
|
|
7
|
+
* Whether this entry renders as a navigation entry, a group label, or a separator.
|
|
8
|
+
* @default 'item'
|
|
9
|
+
*/
|
|
10
|
+
kind?: DashboardNavigationKind | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Text rendered inside the entry; a divider renders no text of its own.
|
|
13
|
+
* @default undefined — nothing is rendered inside the entry.
|
|
14
|
+
*/
|
|
15
|
+
label?: string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Destination of the entry's link; omitted, the entry renders as plain text.
|
|
18
|
+
* @default undefined — rendered as a non-navigable label.
|
|
19
|
+
*/
|
|
20
|
+
href?: string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Marks this entry as the page the user is on, emitting `aria-current="page"`.
|
|
23
|
+
* @default false
|
|
24
|
+
*/
|
|
25
|
+
current?: boolean | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Nested entries, rendered as a list below this entry's label.
|
|
28
|
+
* @default undefined — the entry has no nested list.
|
|
29
|
+
*/
|
|
30
|
+
children?: DashboardNavigationItem[] | undefined;
|
|
31
|
+
}
|
|
32
|
+
/** Props for the {@link DashboardLayout} block. */
|
|
33
|
+
export interface DashboardLayoutProps extends React.ComponentPropsWithRef<'div'> {
|
|
34
|
+
/**
|
|
35
|
+
* Application title shown in the app bar after the branding.
|
|
36
|
+
* @default undefined — no title renders.
|
|
37
|
+
*/
|
|
38
|
+
title?: string | undefined;
|
|
39
|
+
/** The side navigation, in render order, one entry per link, group label or separator. */
|
|
40
|
+
navigation: DashboardNavigationItem[];
|
|
41
|
+
/**
|
|
42
|
+
* Whether the side navigation is shown, for controlled usage paired with `onNavOpenChange`.
|
|
43
|
+
* @default undefined — uncontrolled, seeded from `defaultNavOpen`.
|
|
44
|
+
*/
|
|
45
|
+
navOpen?: boolean | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Whether the side navigation starts shown, used only while uncontrolled.
|
|
48
|
+
* @default true
|
|
49
|
+
*/
|
|
50
|
+
defaultNavOpen?: boolean | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Accessible name written to the side `<nav>` landmark, telling it apart from other navigation.
|
|
53
|
+
* @default 'Main navigation'
|
|
54
|
+
*/
|
|
55
|
+
navLabel?: string | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Accessible name of the icon-only button that shows and hides the navigation.
|
|
58
|
+
* @default 'Toggle navigation'
|
|
59
|
+
*/
|
|
60
|
+
navToggleLabel?: string | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Fires with the new open state whenever the navigation toggle is activated.
|
|
63
|
+
* @default undefined — no-op if omitted.
|
|
64
|
+
*/
|
|
65
|
+
onNavOpenChange?: ((open: boolean) => void) | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Logo or product mark rendered at the start of the app bar.
|
|
68
|
+
* @default undefined — the branding region renders empty.
|
|
69
|
+
*/
|
|
70
|
+
branding?: React.ReactNode | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Controls rendered at the end of the app bar, such as a profile menu.
|
|
73
|
+
* @default undefined — the actions region renders empty.
|
|
74
|
+
*/
|
|
75
|
+
actions?: React.ReactNode | undefined;
|
|
76
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
/** What one {@link DashboardNavigationItem} renders as inside the side navigation. */
|
|
3
|
+
export type DashboardNavigationKind = 'item' | 'header' | 'divider';
|
|
4
|
+
/** One entry of {@link DashboardLayoutProps.navigation} — a navigation entry, a group label or a separator. */
|
|
5
|
+
export interface DashboardNavigationItem {
|
|
6
|
+
/**
|
|
7
|
+
* Whether this entry renders as a navigation entry, a group label, or a separator.
|
|
8
|
+
* @default 'item'
|
|
9
|
+
*/
|
|
10
|
+
kind?: DashboardNavigationKind | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Text rendered inside the entry; a divider renders no text of its own.
|
|
13
|
+
* @default undefined — nothing is rendered inside the entry.
|
|
14
|
+
*/
|
|
15
|
+
label?: string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Destination of the entry's link; omitted, the entry renders as plain text.
|
|
18
|
+
* @default undefined — rendered as a non-navigable label.
|
|
19
|
+
*/
|
|
20
|
+
href?: string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Marks this entry as the page the user is on, emitting `aria-current="page"`.
|
|
23
|
+
* @default false
|
|
24
|
+
*/
|
|
25
|
+
current?: boolean | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Nested entries, rendered as a list below this entry's label.
|
|
28
|
+
* @default undefined — the entry has no nested list.
|
|
29
|
+
*/
|
|
30
|
+
children?: DashboardNavigationItem[] | undefined;
|
|
31
|
+
}
|
|
32
|
+
/** Props for the {@link DashboardLayout} block. */
|
|
33
|
+
export interface DashboardLayoutProps extends React.ComponentPropsWithRef<'div'> {
|
|
34
|
+
/**
|
|
35
|
+
* Application title shown in the app bar after the branding.
|
|
36
|
+
* @default undefined — no title renders.
|
|
37
|
+
*/
|
|
38
|
+
title?: string | undefined;
|
|
39
|
+
/** The side navigation, in render order, one entry per link, group label or separator. */
|
|
40
|
+
navigation: DashboardNavigationItem[];
|
|
41
|
+
/**
|
|
42
|
+
* Whether the side navigation is shown, for controlled usage paired with `onNavOpenChange`.
|
|
43
|
+
* @default undefined — uncontrolled, seeded from `defaultNavOpen`.
|
|
44
|
+
*/
|
|
45
|
+
navOpen?: boolean | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Whether the side navigation starts shown, used only while uncontrolled.
|
|
48
|
+
* @default true
|
|
49
|
+
*/
|
|
50
|
+
defaultNavOpen?: boolean | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Accessible name written to the side `<nav>` landmark, telling it apart from other navigation.
|
|
53
|
+
* @default 'Main navigation'
|
|
54
|
+
*/
|
|
55
|
+
navLabel?: string | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Accessible name of the icon-only button that shows and hides the navigation.
|
|
58
|
+
* @default 'Toggle navigation'
|
|
59
|
+
*/
|
|
60
|
+
navToggleLabel?: string | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Fires with the new open state whenever the navigation toggle is activated.
|
|
63
|
+
* @default undefined — no-op if omitted.
|
|
64
|
+
*/
|
|
65
|
+
onNavOpenChange?: ((open: boolean) => void) | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Logo or product mark rendered at the start of the app bar.
|
|
68
|
+
* @default undefined — the branding region renders empty.
|
|
69
|
+
*/
|
|
70
|
+
branding?: React.ReactNode | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Controls rendered at the end of the app bar, such as a profile menu.
|
|
73
|
+
* @default undefined — the actions region renders empty.
|
|
74
|
+
*/
|
|
75
|
+
actions?: React.ReactNode | undefined;
|
|
76
|
+
}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
"use strict";var n=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var d=Object.prototype.hasOwnProperty;var s=(e,a)=>{for(var r in a)n(e,r,{get:a[r],enumerable:!0})},b=(e,a,r,i)=>{if(a&&typeof a=="object"||typeof a=="function")for(let o of P(a))!d.call(e,o)&&o!==r&&n(e,o,{get:()=>a[o],enumerable:!(i=y(a,o))||i.enumerable});return e};var m=e=>b(n({},"__esModule",{value:!0}),e);var D={};s(D,{DashboardLayout:()=>p.DashboardLayout,PageContainer:()=>g.PageContainer,SignInPage:()=>t.SignInPage,defaultProviderLabel:()=>t.defaultProviderLabel});module.exports=m(D);var p=require("./dashboard-layout/DashboardLayout.cjs"),g=require("./page-container/PageContainer.cjs"),t=require("./sign-in-page/SignInPage.cjs");0&&(module.exports={DashboardLayout,PageContainer,SignInPage,defaultProviderLabel});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { DashboardLayout, type DashboardLayoutProps, type DashboardNavigationItem, type DashboardNavigationKind, } from './dashboard-layout/index.cjs';
|
|
2
|
+
export { PageContainer, type PageContainerProps, type PageContainerBreadcrumb, } from './page-container/index.cjs';
|
|
3
|
+
export { SignInPage, defaultProviderLabel, type SignInPageProps, type SignInProvider, type SignInDetail, } from './sign-in-page/index.cjs';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { DashboardLayout, type DashboardLayoutProps, type DashboardNavigationItem, type DashboardNavigationKind, } from './dashboard-layout/index.js';
|
|
2
|
+
export { PageContainer, type PageContainerProps, type PageContainerBreadcrumb, } from './page-container/index.js';
|
|
3
|
+
export { SignInPage, defaultProviderLabel, type SignInPageProps, type SignInProvider, type SignInDetail, } from './sign-in-page/index.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import{DashboardLayout as o}from"./dashboard-layout/DashboardLayout.js";import{PageContainer as t}from"./page-container/PageContainer.js";import{SignInPage as i,defaultProviderLabel as p}from"./sign-in-page/SignInPage.js";export{o as DashboardLayout,t as PageContainer,i as SignInPage,p as defaultProviderLabel};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Joins the truthy class-name values with single spaces, skipping the rest.
|
|
3
|
+
*
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export declare function cx(...values: Array<string | false | null | undefined>): string;
|
|
7
|
+
/** The attribute bag {@link skdxPart} returns, spread onto a part's root element. @internal */
|
|
8
|
+
export interface SkdxPartAttributes {
|
|
9
|
+
className: string;
|
|
10
|
+
'data-part': string;
|
|
11
|
+
'data-skdx-component'?: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Builds the class and `data-*` hooks for one part of one block; spread after the consumer's `{...props}` so the merged `className` wins instead of being silently deleted.
|
|
15
|
+
*
|
|
16
|
+
* @param component - Family name in kebab-case, e.g. `'page-container'`. Becomes the `skdx-` class stem and, on the root, `data-skdx-component`.
|
|
17
|
+
* @param part - Part name from the family's `styling.cssParts`, or `'root'`.
|
|
18
|
+
* @param className - The consumer's `className`, merged in. Pass `props.className`.
|
|
19
|
+
*
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export declare function skdxPart(component: string, part: string, className?: string): SkdxPartAttributes;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Joins the truthy class-name values with single spaces, skipping the rest.
|
|
3
|
+
*
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export declare function cx(...values: Array<string | false | null | undefined>): string;
|
|
7
|
+
/** The attribute bag {@link skdxPart} returns, spread onto a part's root element. @internal */
|
|
8
|
+
export interface SkdxPartAttributes {
|
|
9
|
+
className: string;
|
|
10
|
+
'data-part': string;
|
|
11
|
+
'data-skdx-component'?: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Builds the class and `data-*` hooks for one part of one block; spread after the consumer's `{...props}` so the merged `className` wins instead of being silently deleted.
|
|
15
|
+
*
|
|
16
|
+
* @param component - Family name in kebab-case, e.g. `'page-container'`. Becomes the `skdx-` class stem and, on the root, `data-skdx-component`.
|
|
17
|
+
* @param part - Part name from the family's `styling.cssParts`, or `'root'`.
|
|
18
|
+
* @param className - The consumer's `className`, merged in. Pass `props.className`.
|
|
19
|
+
*
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export declare function skdxPart(component: string, part: string, className?: string): SkdxPartAttributes;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Controlled/uncontrolled pattern: mirrors `prop` once it is defined, otherwise tracks its own state, calling `onChange` with the new value either way.
|
|
3
|
+
*
|
|
4
|
+
* The core `useControllableState` is not part of the public `@skdx/react`
|
|
5
|
+
* surface; this is the value-only subset the blocks need.
|
|
6
|
+
*
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export declare function useControllableState<T>(prop: T | undefined, defaultProp: T, onChange?: (value: T) => void): readonly [T, (next: T) => void];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Controlled/uncontrolled pattern: mirrors `prop` once it is defined, otherwise tracks its own state, calling `onChange` with the new value either way.
|
|
3
|
+
*
|
|
4
|
+
* The core `useControllableState` is not part of the public `@skdx/react`
|
|
5
|
+
* surface; this is the value-only subset the blocks need.
|
|
6
|
+
*
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export declare function useControllableState<T>(prop: T | undefined, defaultProp: T, onChange?: (value: T) => void): readonly [T, (next: T) => void];
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
"use strict";var P=Object.create;var c=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var k=Object.getPrototypeOf,y=Object.prototype.hasOwnProperty;var C=(e,t)=>{for(var a in t)c(e,a,{get:t[a],enumerable:!0})},u=(e,t,a,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of b(t))!y.call(e,r)&&r!==a&&c(e,r,{get:()=>t[r],enumerable:!(i=x(t,r))||i.enumerable});return e};var $=(e,t,a)=>(a=e!=null?P(k(e)):{},u(t||!e||!e.__esModule?c(a,"default",{value:e,enumerable:!0}):a,e)),h=e=>u(c({},"__esModule",{value:!0}),e);var N={};C(N,{PageContainer:()=>g});module.exports=h(N);var m=$(require("react"),1),s=require("@skdx/react");function v(...e){let t="";for(let a of e)a&&(t=t?`${t} ${a}`:a);return t}function o(e,t,a){let i=t==="root",r=i?`skdx-${e}`:`skdx-${e}__${t}`,d={className:v(r,a),"data-part":t};return i&&(d["data-skdx-component"]=e),d}var n=require("react/jsx-runtime"),g=({title:e,headingLevel:t=1,breadcrumbs:a,breadcrumbLabel:i="Breadcrumb",actionsLabel:r="Page actions",actions:d,children:f,...l})=>{let p=m.useId();return(0,n.jsxs)("section",{"aria-labelledby":p,...l,...o("page-container","root",l.className),children:[(0,n.jsxs)("header",{...o("page-container","header"),children:[a?(0,n.jsx)(s.Breadcrumb,{label:i,items:[...a],...o("page-container","breadcrumbs")}):null,(0,n.jsxs)("div",{...o("page-container","heading-row"),children:[(0,n.jsx)(s.Heading,{as:`h${t}`,id:p,...o("page-container","title"),children:e}),d?(0,n.jsx)(s.Toolbar,{"aria-label":r,...o("page-container","actions"),children:d}):null]})]}),(0,n.jsx)("div",{...o("page-container","content"),children:f})]})};g.displayName="PageContainer";0&&(module.exports={PageContainer});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { PageContainerProps } from './types.cjs';
|
|
3
|
+
/**
|
|
4
|
+
* Page header block: breadcrumbs, a heading and page-level actions above the
|
|
5
|
+
* page content, rendered as a `<section>` named by its own heading.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* <PageContainer
|
|
10
|
+
* title="Invoices"
|
|
11
|
+
* breadcrumbs={[{ label: 'Home', href: '/' }, { label: 'Invoices' }]}
|
|
12
|
+
* actions={<Button>New invoice</Button>}
|
|
13
|
+
* >
|
|
14
|
+
* <InvoiceTable />
|
|
15
|
+
* </PageContainer>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare const PageContainer: {
|
|
19
|
+
({ title, headingLevel, breadcrumbs, breadcrumbLabel, actionsLabel, actions, children, ...props }: PageContainerProps): React.ReactNode;
|
|
20
|
+
displayName: string;
|
|
21
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { PageContainerProps } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Page header block: breadcrumbs, a heading and page-level actions above the
|
|
5
|
+
* page content, rendered as a `<section>` named by its own heading.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* <PageContainer
|
|
10
|
+
* title="Invoices"
|
|
11
|
+
* breadcrumbs={[{ label: 'Home', href: '/' }, { label: 'Invoices' }]}
|
|
12
|
+
* actions={<Button>New invoice</Button>}
|
|
13
|
+
* >
|
|
14
|
+
* <InvoiceTable />
|
|
15
|
+
* </PageContainer>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare const PageContainer: {
|
|
19
|
+
({ title, headingLevel, breadcrumbs, breadcrumbLabel, actionsLabel, actions, children, ...props }: PageContainerProps): React.ReactNode;
|
|
20
|
+
displayName: string;
|
|
21
|
+
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import*as l from"react";import{Breadcrumb as f,Heading as P,Toolbar as x}from"@skdx/react";function m(...r){let e="";for(let t of r)t&&(e=e?`${e} ${t}`:t);return e}function a(r,e,t){let o=e==="root",s=o?`skdx-${r}`:`skdx-${r}__${e}`,n={className:m(s,t),"data-part":e};return o&&(n["data-skdx-component"]=r),n}import{jsx as i,jsxs as d}from"react/jsx-runtime";var p=({title:r,headingLevel:e=1,breadcrumbs:t,breadcrumbLabel:o="Breadcrumb",actionsLabel:s="Page actions",actions:n,children:u,...c})=>{let g=l.useId();return d("section",{"aria-labelledby":g,...c,...a("page-container","root",c.className),children:[d("header",{...a("page-container","header"),children:[t?i(f,{label:o,items:[...t],...a("page-container","breadcrumbs")}):null,d("div",{...a("page-container","heading-row"),children:[i(P,{as:`h${e}`,id:g,...a("page-container","title"),children:r}),n?i(x,{"aria-label":s,...a("page-container","actions"),children:n}):null]})]}),i("div",{...a("page-container","content"),children:u})]})};p.displayName="PageContainer";export{p as PageContainer};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
/** One entry of {@link PageContainerProps.breadcrumbs} — a crumb in the trail above the heading. */
|
|
3
|
+
export interface PageContainerBreadcrumb {
|
|
4
|
+
/** Text rendered inside the crumb, as a link or as the current page. */
|
|
5
|
+
label: string;
|
|
6
|
+
/**
|
|
7
|
+
* Destination of the crumb's link; omitted, the crumb renders as the current, non-navigable page.
|
|
8
|
+
* @default undefined — rendered as the current page.
|
|
9
|
+
*/
|
|
10
|
+
href?: string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Marks a link crumb as the current page, emitting `aria-current="page"` on it.
|
|
13
|
+
* @default false
|
|
14
|
+
*/
|
|
15
|
+
current?: boolean | undefined;
|
|
16
|
+
}
|
|
17
|
+
/** Props for the {@link PageContainer} block. */
|
|
18
|
+
export interface PageContainerProps extends React.ComponentPropsWithRef<'section'> {
|
|
19
|
+
/** The page heading text, rendered into a derived Heading that also names the section. */
|
|
20
|
+
title: string;
|
|
21
|
+
/**
|
|
22
|
+
* Outline level of the derived heading, from a page's own `1` down to `6` inside a larger outline.
|
|
23
|
+
* @default 1
|
|
24
|
+
*/
|
|
25
|
+
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6 | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Trail rendered into a derived Breadcrumb above the heading row.
|
|
28
|
+
* @default undefined — no breadcrumb region renders.
|
|
29
|
+
*/
|
|
30
|
+
breadcrumbs?: ReadonlyArray<PageContainerBreadcrumb> | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Accessible name written to the derived breadcrumb `<nav>` landmark.
|
|
33
|
+
* @default 'Breadcrumb'
|
|
34
|
+
*/
|
|
35
|
+
breadcrumbLabel?: string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Accessible name written to the derived actions Toolbar beside the heading.
|
|
38
|
+
* @default 'Page actions'
|
|
39
|
+
*/
|
|
40
|
+
actionsLabel?: string | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Controls rendered inside the derived Toolbar beside the page heading.
|
|
43
|
+
* @default undefined — no toolbar renders.
|
|
44
|
+
*/
|
|
45
|
+
actions?: React.ReactNode | undefined;
|
|
46
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
/** One entry of {@link PageContainerProps.breadcrumbs} — a crumb in the trail above the heading. */
|
|
3
|
+
export interface PageContainerBreadcrumb {
|
|
4
|
+
/** Text rendered inside the crumb, as a link or as the current page. */
|
|
5
|
+
label: string;
|
|
6
|
+
/**
|
|
7
|
+
* Destination of the crumb's link; omitted, the crumb renders as the current, non-navigable page.
|
|
8
|
+
* @default undefined — rendered as the current page.
|
|
9
|
+
*/
|
|
10
|
+
href?: string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Marks a link crumb as the current page, emitting `aria-current="page"` on it.
|
|
13
|
+
* @default false
|
|
14
|
+
*/
|
|
15
|
+
current?: boolean | undefined;
|
|
16
|
+
}
|
|
17
|
+
/** Props for the {@link PageContainer} block. */
|
|
18
|
+
export interface PageContainerProps extends React.ComponentPropsWithRef<'section'> {
|
|
19
|
+
/** The page heading text, rendered into a derived Heading that also names the section. */
|
|
20
|
+
title: string;
|
|
21
|
+
/**
|
|
22
|
+
* Outline level of the derived heading, from a page's own `1` down to `6` inside a larger outline.
|
|
23
|
+
* @default 1
|
|
24
|
+
*/
|
|
25
|
+
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6 | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Trail rendered into a derived Breadcrumb above the heading row.
|
|
28
|
+
* @default undefined — no breadcrumb region renders.
|
|
29
|
+
*/
|
|
30
|
+
breadcrumbs?: ReadonlyArray<PageContainerBreadcrumb> | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Accessible name written to the derived breadcrumb `<nav>` landmark.
|
|
33
|
+
* @default 'Breadcrumb'
|
|
34
|
+
*/
|
|
35
|
+
breadcrumbLabel?: string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Accessible name written to the derived actions Toolbar beside the heading.
|
|
38
|
+
* @default 'Page actions'
|
|
39
|
+
*/
|
|
40
|
+
actionsLabel?: string | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Controls rendered inside the derived Toolbar beside the page heading.
|
|
43
|
+
* @default undefined — no toolbar renders.
|
|
44
|
+
*/
|
|
45
|
+
actions?: React.ReactNode | undefined;
|
|
46
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
"use strict";var E=Object.create;var g=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var T=Object.getPrototypeOf,q=Object.prototype.hasOwnProperty;var _=(e,t)=>{for(var i in t)g(e,i,{get:t[i],enumerable:!0})},k=(e,t,i,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let l of N(t))!q.call(e,l)&&l!==i&&g(e,l,{get:()=>t[l],enumerable:!(o=$(t,l))||o.enumerable});return e};var B=(e,t,i)=>(i=e!=null?E(T(e)):{},k(t||!e||!e.__esModule?g(i,"default",{value:e,enumerable:!0}):i,e)),H=e=>k(g({},"__esModule",{value:!0}),e);var M={};_(M,{SignInPage:()=>c,defaultProviderLabel:()=>m});module.exports=H(M);var v=B(require("react"),1),n=require("@skdx/react"),R=require("@skdx/react/primitives/text-field");function L(...e){let t="";for(let i of e)i&&(t=t?`${t} ${i}`:i);return t}function s(e,t,i){let o=t==="root",l=o?`skdx-${e}`:`skdx-${e}__${t}`,d={className:L(l,i),"data-part":t};return o&&(d["data-skdx-component"]=e),d}var r=require("react/jsx-runtime"),y=new Set(["credentials","magic-link"]),m=e=>`Sign in with ${e.name}`;function F(e,t){let i=e.get(t);return typeof i=="string"?i:""}function C({label:e}){return(0,r.jsx)(n.Field,{label:e,required:!0,...s("sign-in-page","field"),children:(0,r.jsx)(n.TextField,{name:"email",required:!0,children:(0,r.jsx)(R.TextFieldInput,{type:"email",autoComplete:"email"})})})}var c=({title:e="Sign in",providers:t,error:i,emailLabel:o="Email",passwordLabel:l="Password",submitLabel:d="Sign in",magicLinkLabel:D="Send magic link",getProviderLabel:h=m,onSignIn:p,children:w,...f})=>{let S=v.useId(),u=t.filter(a=>!y.has(a.id)),P=t.filter(a=>y.has(a.id)),A=a=>b=>{b.preventDefault();let x=new FormData(b.currentTarget),I={providerId:a,email:F(x,"email")};a==="credentials"&&(I.password=F(x,"password")),p?.(I)};return(0,r.jsx)("section",{"aria-labelledby":S,...f,...s("sign-in-page","root",f.className),children:(0,r.jsxs)("div",{...s("sign-in-page","panel"),children:[(0,r.jsx)(n.Heading,{as:"h1",id:S,...s("sign-in-page","title"),children:e}),i?(0,r.jsx)(n.Alert,{status:"danger",...s("sign-in-page","error"),children:i}):null,u.length>0?(0,r.jsx)("div",{...s("sign-in-page","providers"),children:u.map(a=>(0,r.jsx)(n.Button,{type:"button","data-provider":a.id,onClick:()=>{p?.({providerId:a.id})},...s("sign-in-page","provider"),children:h(a)},a.id))}):null,u.length>0&&P.length>0?(0,r.jsx)(n.Divider,{...s("sign-in-page","divider")}):null,P.map(a=>(0,r.jsxs)(n.Form,{"data-provider":a.id,onSubmit:A(a.id),...s("sign-in-page","form"),children:[(0,r.jsx)(C,{label:o}),a.id==="credentials"?(0,r.jsx)(n.Field,{label:l,required:!0,...s("sign-in-page","field"),children:(0,r.jsx)(n.PasswordInput,{name:"password",required:!0})}):null,(0,r.jsx)(n.Button,{type:"submit",...s("sign-in-page","submit"),children:a.id==="credentials"?d:D})]},a.id)),w]})})};c.displayName="SignInPage";0&&(module.exports={SignInPage,defaultProviderLabel});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { SignInPageProps, SignInProvider } from './types.cjs';
|
|
3
|
+
/** Default wording of a provider button, reading "Sign in with Google". */
|
|
4
|
+
export declare const defaultProviderLabel: (provider: SignInProvider) => string;
|
|
5
|
+
/**
|
|
6
|
+
* Sign-in block: an error alert, one button per OAuth provider, and the
|
|
7
|
+
* credentials and magic-link forms, all reporting through `onSignIn`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <SignInPage
|
|
12
|
+
* providers={[{ id: 'google', name: 'Google' }, { id: 'credentials', name: 'Email' }]}
|
|
13
|
+
* error={error}
|
|
14
|
+
* onSignIn={(detail) => void signIn(detail)}
|
|
15
|
+
* />
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare const SignInPage: {
|
|
19
|
+
({ title, providers, error, emailLabel, passwordLabel, submitLabel, magicLinkLabel, getProviderLabel, onSignIn, children, ...props }: SignInPageProps): React.ReactNode;
|
|
20
|
+
displayName: string;
|
|
21
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { SignInPageProps, SignInProvider } from './types.js';
|
|
3
|
+
/** Default wording of a provider button, reading "Sign in with Google". */
|
|
4
|
+
export declare const defaultProviderLabel: (provider: SignInProvider) => string;
|
|
5
|
+
/**
|
|
6
|
+
* Sign-in block: an error alert, one button per OAuth provider, and the
|
|
7
|
+
* credentials and magic-link forms, all reporting through `onSignIn`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <SignInPage
|
|
12
|
+
* providers={[{ id: 'google', name: 'Google' }, { id: 'credentials', name: 'Email' }]}
|
|
13
|
+
* error={error}
|
|
14
|
+
* onSignIn={(detail) => void signIn(detail)}
|
|
15
|
+
* />
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare const SignInPage: {
|
|
19
|
+
({ title, providers, error, emailLabel, passwordLabel, submitLabel, magicLinkLabel, getProviderLabel, onSignIn, children, ...props }: SignInPageProps): React.ReactNode;
|
|
20
|
+
displayName: string;
|
|
21
|
+
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import*as k from"react";import{Alert as E,Button as P,Divider as $,Field as y,Form as N,Heading as T,PasswordInput as q,TextField as _}from"@skdx/react";import{TextFieldInput as B}from"@skdx/react/primitives/text-field";function A(...t){let i="";for(let r of t)r&&(i=i?`${i} ${r}`:r);return i}function a(t,i,r){let s=i==="root",o=s?`skdx-${t}`:`skdx-${t}__${i}`,l={className:A(o,r),"data-part":i};return s&&(l["data-skdx-component"]=t),l}import{jsx as n,jsxs as I}from"react/jsx-runtime";var b=new Set(["credentials","magic-link"]),F=t=>`Sign in with ${t.name}`;function x(t,i){let r=t.get(i);return typeof r=="string"?r:""}function H({label:t}){return n(y,{label:t,required:!0,...a("sign-in-page","field"),children:n(_,{name:"email",required:!0,children:n(B,{type:"email",autoComplete:"email"})})})}var v=({title:t="Sign in",providers:i,error:r,emailLabel:s="Email",passwordLabel:o="Password",submitLabel:l="Sign in",magicLinkLabel:R="Send magic link",getProviderLabel:D=F,onSignIn:g,children:h,...u})=>{let m=k.useId(),d=i.filter(e=>!b.has(e.id)),c=i.filter(e=>b.has(e.id)),w=e=>p=>{p.preventDefault();let f=new FormData(p.currentTarget),S={providerId:e,email:x(f,"email")};e==="credentials"&&(S.password=x(f,"password")),g?.(S)};return n("section",{"aria-labelledby":m,...u,...a("sign-in-page","root",u.className),children:I("div",{...a("sign-in-page","panel"),children:[n(T,{as:"h1",id:m,...a("sign-in-page","title"),children:t}),r?n(E,{status:"danger",...a("sign-in-page","error"),children:r}):null,d.length>0?n("div",{...a("sign-in-page","providers"),children:d.map(e=>n(P,{type:"button","data-provider":e.id,onClick:()=>{g?.({providerId:e.id})},...a("sign-in-page","provider"),children:D(e)},e.id))}):null,d.length>0&&c.length>0?n($,{...a("sign-in-page","divider")}):null,c.map(e=>I(N,{"data-provider":e.id,onSubmit:w(e.id),...a("sign-in-page","form"),children:[n(H,{label:s}),e.id==="credentials"?n(y,{label:o,required:!0,...a("sign-in-page","field"),children:n(q,{name:"password",required:!0})}):null,n(P,{type:"submit",...a("sign-in-page","submit"),children:e.id==="credentials"?l:R})]},e.id)),h]})})};v.displayName="SignInPage";export{v as SignInPage,F as defaultProviderLabel};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
/** One entry of {@link SignInPageProps.providers} — a way to sign in. */
|
|
3
|
+
export interface SignInProvider {
|
|
4
|
+
/** Identifier reported back to the consumer; `'credentials'` and `'magic-link'` render forms. */
|
|
5
|
+
id: string;
|
|
6
|
+
/** Human-readable provider name, worded into the button by `getProviderLabel`. */
|
|
7
|
+
name: string;
|
|
8
|
+
}
|
|
9
|
+
/** What {@link SignInPageProps.onSignIn} is called with when a provider or a form is used. */
|
|
10
|
+
export interface SignInDetail {
|
|
11
|
+
/** The `id` of the provider the user chose. */
|
|
12
|
+
providerId: string;
|
|
13
|
+
/**
|
|
14
|
+
* Email submitted by the credentials or magic-link form.
|
|
15
|
+
* @default undefined — a provider button carries no field values.
|
|
16
|
+
*/
|
|
17
|
+
email?: string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Password submitted by the credentials form.
|
|
20
|
+
* @default undefined — every other provider carries no password.
|
|
21
|
+
*/
|
|
22
|
+
password?: string | undefined;
|
|
23
|
+
}
|
|
24
|
+
/** Props for the {@link SignInPage} block. */
|
|
25
|
+
export interface SignInPageProps extends React.ComponentPropsWithRef<'section'> {
|
|
26
|
+
/**
|
|
27
|
+
* Heading text, rendered into a derived `<h1>` that names the section.
|
|
28
|
+
* @default 'Sign in'
|
|
29
|
+
*/
|
|
30
|
+
title?: string | undefined;
|
|
31
|
+
/** The ways to sign in, in render order, each rendering a button or one of the two forms. */
|
|
32
|
+
providers: SignInProvider[];
|
|
33
|
+
/**
|
|
34
|
+
* Message rendered into a derived error Alert above the providers; the block never clears it.
|
|
35
|
+
* @default undefined — no error region renders.
|
|
36
|
+
*/
|
|
37
|
+
error?: string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Label of the email field in the credentials and magic-link forms.
|
|
40
|
+
* @default 'Email'
|
|
41
|
+
*/
|
|
42
|
+
emailLabel?: string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Label of the password field in the credentials form.
|
|
45
|
+
* @default 'Password'
|
|
46
|
+
*/
|
|
47
|
+
passwordLabel?: string | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Text of the credentials form's submit button.
|
|
50
|
+
* @default 'Sign in'
|
|
51
|
+
*/
|
|
52
|
+
submitLabel?: string | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Text of the magic-link form's submit button.
|
|
55
|
+
* @default 'Send magic link'
|
|
56
|
+
*/
|
|
57
|
+
magicLinkLabel?: string | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Words a provider button's text from its entry, replacing the built-in wording.
|
|
60
|
+
* @default defaultProviderLabel — reads "Sign in with Google".
|
|
61
|
+
*/
|
|
62
|
+
getProviderLabel?: ((provider: SignInProvider) => string) | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Fires when a provider button is activated or a form is submitted with valid fields.
|
|
65
|
+
* @default undefined — no-op if omitted.
|
|
66
|
+
*/
|
|
67
|
+
onSignIn?: ((detail: SignInDetail) => void) | undefined;
|
|
68
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
/** One entry of {@link SignInPageProps.providers} — a way to sign in. */
|
|
3
|
+
export interface SignInProvider {
|
|
4
|
+
/** Identifier reported back to the consumer; `'credentials'` and `'magic-link'` render forms. */
|
|
5
|
+
id: string;
|
|
6
|
+
/** Human-readable provider name, worded into the button by `getProviderLabel`. */
|
|
7
|
+
name: string;
|
|
8
|
+
}
|
|
9
|
+
/** What {@link SignInPageProps.onSignIn} is called with when a provider or a form is used. */
|
|
10
|
+
export interface SignInDetail {
|
|
11
|
+
/** The `id` of the provider the user chose. */
|
|
12
|
+
providerId: string;
|
|
13
|
+
/**
|
|
14
|
+
* Email submitted by the credentials or magic-link form.
|
|
15
|
+
* @default undefined — a provider button carries no field values.
|
|
16
|
+
*/
|
|
17
|
+
email?: string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Password submitted by the credentials form.
|
|
20
|
+
* @default undefined — every other provider carries no password.
|
|
21
|
+
*/
|
|
22
|
+
password?: string | undefined;
|
|
23
|
+
}
|
|
24
|
+
/** Props for the {@link SignInPage} block. */
|
|
25
|
+
export interface SignInPageProps extends React.ComponentPropsWithRef<'section'> {
|
|
26
|
+
/**
|
|
27
|
+
* Heading text, rendered into a derived `<h1>` that names the section.
|
|
28
|
+
* @default 'Sign in'
|
|
29
|
+
*/
|
|
30
|
+
title?: string | undefined;
|
|
31
|
+
/** The ways to sign in, in render order, each rendering a button or one of the two forms. */
|
|
32
|
+
providers: SignInProvider[];
|
|
33
|
+
/**
|
|
34
|
+
* Message rendered into a derived error Alert above the providers; the block never clears it.
|
|
35
|
+
* @default undefined — no error region renders.
|
|
36
|
+
*/
|
|
37
|
+
error?: string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Label of the email field in the credentials and magic-link forms.
|
|
40
|
+
* @default 'Email'
|
|
41
|
+
*/
|
|
42
|
+
emailLabel?: string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Label of the password field in the credentials form.
|
|
45
|
+
* @default 'Password'
|
|
46
|
+
*/
|
|
47
|
+
passwordLabel?: string | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Text of the credentials form's submit button.
|
|
50
|
+
* @default 'Sign in'
|
|
51
|
+
*/
|
|
52
|
+
submitLabel?: string | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Text of the magic-link form's submit button.
|
|
55
|
+
* @default 'Send magic link'
|
|
56
|
+
*/
|
|
57
|
+
magicLinkLabel?: string | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Words a provider button's text from its entry, replacing the built-in wording.
|
|
60
|
+
* @default defaultProviderLabel — reads "Sign in with Google".
|
|
61
|
+
*/
|
|
62
|
+
getProviderLabel?: ((provider: SignInProvider) => string) | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Fires when a provider button is activated or a form is submitted with valid fields.
|
|
65
|
+
* @default undefined — no-op if omitted.
|
|
66
|
+
*/
|
|
67
|
+
onSignIn?: ((detail: SignInDetail) => void) | undefined;
|
|
68
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@skdx/react-blocks",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React blocks for the SkandaDX design system — page-level compositions of @skdx/react styled by @skdx/skins",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/SkandaDX/ui.skdx/tree/main/packages/react-blocks#readme",
|
|
10
|
+
"repository": {
|
|
11
|
+
"directory": "packages/react-blocks",
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/SkandaDX/ui.skdx.git"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/SkandaDX/ui.skdx/issues"
|
|
17
|
+
},
|
|
18
|
+
"type": "module",
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=18.18.0"
|
|
21
|
+
},
|
|
22
|
+
"main": "./dist/index.cjs",
|
|
23
|
+
"module": "./dist/index.js",
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"import": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"default": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"require": {
|
|
32
|
+
"types": "./dist/index.d.cts",
|
|
33
|
+
"default": "./dist/index.cjs"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"./dashboard-layout": {
|
|
37
|
+
"import": {
|
|
38
|
+
"types": "./dist/dashboard-layout/index.d.ts",
|
|
39
|
+
"default": "./dist/dashboard-layout/DashboardLayout.js"
|
|
40
|
+
},
|
|
41
|
+
"require": {
|
|
42
|
+
"types": "./dist/dashboard-layout/index.d.cts",
|
|
43
|
+
"default": "./dist/dashboard-layout/DashboardLayout.cjs"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"./page-container": {
|
|
47
|
+
"import": {
|
|
48
|
+
"types": "./dist/page-container/index.d.ts",
|
|
49
|
+
"default": "./dist/page-container/PageContainer.js"
|
|
50
|
+
},
|
|
51
|
+
"require": {
|
|
52
|
+
"types": "./dist/page-container/index.d.cts",
|
|
53
|
+
"default": "./dist/page-container/PageContainer.cjs"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"./sign-in-page": {
|
|
57
|
+
"import": {
|
|
58
|
+
"types": "./dist/sign-in-page/index.d.ts",
|
|
59
|
+
"default": "./dist/sign-in-page/SignInPage.js"
|
|
60
|
+
},
|
|
61
|
+
"require": {
|
|
62
|
+
"types": "./dist/sign-in-page/index.d.cts",
|
|
63
|
+
"default": "./dist/sign-in-page/SignInPage.cjs"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"./package.json": "./package.json"
|
|
67
|
+
},
|
|
68
|
+
"files": [
|
|
69
|
+
"dist",
|
|
70
|
+
"!dist/**/*.md",
|
|
71
|
+
"!dist/**/*.map",
|
|
72
|
+
"!dist/**/*.test.*"
|
|
73
|
+
],
|
|
74
|
+
"sideEffects": false,
|
|
75
|
+
"peerDependencies": {
|
|
76
|
+
"react": "^19.0.0",
|
|
77
|
+
"react-dom": "^19.0.0",
|
|
78
|
+
"@skdx/react": "^0.33.0"
|
|
79
|
+
},
|
|
80
|
+
"devDependencies": {
|
|
81
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
82
|
+
"@testing-library/react": "^16.3.2",
|
|
83
|
+
"@testing-library/user-event": "^14.6.1",
|
|
84
|
+
"@types/node": "^26.1.0",
|
|
85
|
+
"@types/react": "^19.2.17",
|
|
86
|
+
"@types/react-dom": "^19.2.3",
|
|
87
|
+
"@vitejs/plugin-react": "^6.0.3",
|
|
88
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
89
|
+
"axe-core": "^4.12.1",
|
|
90
|
+
"jsdom": "^29.1.1",
|
|
91
|
+
"react": "^19.2.7",
|
|
92
|
+
"react-dom": "^19.2.7",
|
|
93
|
+
"tsup": "^8.5.1",
|
|
94
|
+
"typescript": "^6.0.3",
|
|
95
|
+
"vitest": "^4.1.10",
|
|
96
|
+
"@skdx/react": "0.33.0"
|
|
97
|
+
},
|
|
98
|
+
"scripts": {
|
|
99
|
+
"lint": "eslint . --cache --cache-location node_modules/.cache/eslint/",
|
|
100
|
+
"build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsup && tsc --emitDeclarationOnly -p tsconfig.build.json && node ../../scripts/declarations-cjs.mjs",
|
|
101
|
+
"dev": "tsup --watch",
|
|
102
|
+
"typecheck": "tsc --noEmit --incremental --tsBuildInfoFile node_modules/.cache/tsc/typecheck.tsbuildinfo",
|
|
103
|
+
"test": "vitest run",
|
|
104
|
+
"test:watch": "vitest",
|
|
105
|
+
"test:coverage": "vitest run --coverage"
|
|
106
|
+
}
|
|
107
|
+
}
|