@umituz/web-dashboard 6.3.0 → 6.5.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/package.json +22 -21
- package/src/domains/layouts/components/PageHeader.test.tsx +13 -0
- package/src/domains/layouts/components/PageHeader.tsx +13 -1
- package/src/domains/layouts/components/SectionHeader.test.tsx +29 -0
- package/src/domains/layouts/components/SectionHeader.tsx +33 -0
- package/src/domains/layouts/components/index.ts +2 -0
- package/src/styles/chrome.css +2575 -0
- package/src/styles/dashboard.contract.test.ts +9 -3
- package/src/styles/dashboard.css +1 -2526
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/web-dashboard",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.5.0",
|
|
4
4
|
"description": "Installable app skeleton for the fleet — layouts, analytics (dependency-free SVG charts), calendar, onboarding flow, i18n via @umituz/web-localization, permissions/module registry; udb-* stylesheet on design-system tokens",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -10,35 +10,36 @@
|
|
|
10
10
|
],
|
|
11
11
|
"exports": {
|
|
12
12
|
".": "./src/index.ts",
|
|
13
|
-
"./styles.css": "./src/styles/dashboard.css",
|
|
14
|
-
"./permissions": "./src/domains/permissions/index.ts",
|
|
15
|
-
"./modules": "./src/domains/modules/index.ts",
|
|
16
|
-
"./layouts": "./src/domains/layouts/index.ts",
|
|
17
|
-
"./layouts/components": "./src/domains/layouts/components/index.ts",
|
|
18
|
-
"./layouts/hooks": "./src/domains/layouts/hooks/index.ts",
|
|
19
|
-
"./layouts/utils": "./src/domains/layouts/utils/index.ts",
|
|
20
|
-
"./layouts/types": "./src/domains/layouts/types/index.ts",
|
|
21
|
-
"./layouts/theme": "./src/domains/layouts/theme/index.ts",
|
|
22
|
-
"./settings": "./src/domains/settings/index.ts",
|
|
23
|
-
"./settings/components": "./src/domains/settings/components/index.ts",
|
|
24
|
-
"./settings/hooks": "./src/domains/settings/hooks/index.ts",
|
|
25
|
-
"./settings/utils": "./src/domains/settings/utils/index.ts",
|
|
26
|
-
"./settings/types": "./src/domains/settings/types/index.ts",
|
|
27
13
|
"./analytics": "./src/domains/analytics/index.ts",
|
|
28
14
|
"./analytics/components": "./src/domains/analytics/components/index.ts",
|
|
29
15
|
"./analytics/hooks": "./src/domains/analytics/hooks/index.ts",
|
|
30
|
-
"./analytics/utils": "./src/domains/analytics/utils/index.ts",
|
|
31
|
-
"./analytics/types": "./src/domains/analytics/types/index.ts",
|
|
32
16
|
"./analytics/services": "./src/domains/analytics/services/index.ts",
|
|
17
|
+
"./analytics/types": "./src/domains/analytics/types/index.ts",
|
|
18
|
+
"./analytics/utils": "./src/domains/analytics/utils/index.ts",
|
|
33
19
|
"./calendar": "./src/domains/calendar/index.ts",
|
|
34
|
-
"./calendar/types": "./src/domains/calendar/types/calendar.types.ts",
|
|
35
|
-
"./calendar/services": "./src/domains/calendar/services/index.ts",
|
|
36
20
|
"./calendar/hooks": "./src/domains/calendar/hooks/index.ts",
|
|
21
|
+
"./calendar/services": "./src/domains/calendar/services/index.ts",
|
|
22
|
+
"./calendar/types": "./src/domains/calendar/types/calendar.types.ts",
|
|
37
23
|
"./calendar/utils": "./src/domains/calendar/utils/index.ts",
|
|
24
|
+
"./charts": "./src/domains/charts/index.ts",
|
|
25
|
+
"./chrome.css": "./src/styles/chrome.css",
|
|
38
26
|
"./config": "./src/config/index.ts",
|
|
27
|
+
"./layouts": "./src/domains/layouts/index.ts",
|
|
28
|
+
"./layouts/components": "./src/domains/layouts/components/index.ts",
|
|
29
|
+
"./layouts/hooks": "./src/domains/layouts/hooks/index.ts",
|
|
30
|
+
"./layouts/theme": "./src/domains/layouts/theme/index.ts",
|
|
31
|
+
"./layouts/types": "./src/domains/layouts/types/index.ts",
|
|
32
|
+
"./layouts/utils": "./src/domains/layouts/utils/index.ts",
|
|
33
|
+
"./modules": "./src/domains/modules/index.ts",
|
|
34
|
+
"./onboarding": "./src/domains/onboarding/index.ts",
|
|
39
35
|
"./package.json": "./package.json",
|
|
40
|
-
"./
|
|
41
|
-
"./
|
|
36
|
+
"./permissions": "./src/domains/permissions/index.ts",
|
|
37
|
+
"./settings": "./src/domains/settings/index.ts",
|
|
38
|
+
"./settings/components": "./src/domains/settings/components/index.ts",
|
|
39
|
+
"./settings/hooks": "./src/domains/settings/hooks/index.ts",
|
|
40
|
+
"./settings/types": "./src/domains/settings/types/index.ts",
|
|
41
|
+
"./settings/utils": "./src/domains/settings/utils/index.ts",
|
|
42
|
+
"./styles.css": "./src/styles/dashboard.css"
|
|
42
43
|
},
|
|
43
44
|
"files": [
|
|
44
45
|
"src",
|
|
@@ -29,4 +29,17 @@ describe('PageHeader markup smoke', () => {
|
|
|
29
29
|
expect(html).toContain('udb-pageheader__actions');
|
|
30
30
|
expect(html).toContain('New claim');
|
|
31
31
|
});
|
|
32
|
+
|
|
33
|
+
it('renders meta under the title block and omits it when undefined', () => {
|
|
34
|
+
const html = renderToString(
|
|
35
|
+
<PageHeader title="Policy AC-123" meta={<span>Renews 2027-01-15</span>} />,
|
|
36
|
+
);
|
|
37
|
+
const metaAt = html.indexOf('udb-pageheader__meta');
|
|
38
|
+
expect(metaAt).toBeGreaterThan(-1);
|
|
39
|
+
expect(html.indexOf('udb-pageheader__subtitle')).toBe(-1);
|
|
40
|
+
expect(html).toContain('Renews 2027-01-15');
|
|
41
|
+
|
|
42
|
+
const bare = renderToString(<PageHeader title="Policy AC-123" />);
|
|
43
|
+
expect(bare).not.toContain('udb-pageheader__meta');
|
|
44
|
+
});
|
|
32
45
|
});
|
|
@@ -10,6 +10,8 @@ export interface PageHeaderProps {
|
|
|
10
10
|
title?: ReactNode;
|
|
11
11
|
subtitle?: ReactNode;
|
|
12
12
|
description?: ReactNode;
|
|
13
|
+
/** Small facts row (dates, counts, IDs…) under the title block. */
|
|
14
|
+
meta?: ReactNode;
|
|
13
15
|
breadcrumbs?: ReactNode | readonly PageHeaderCrumb[];
|
|
14
16
|
actions?: ReactNode;
|
|
15
17
|
className?: string;
|
|
@@ -18,7 +20,16 @@ export interface PageHeaderProps {
|
|
|
18
20
|
const isCrumbList = (value: ReactNode | readonly PageHeaderCrumb[]): value is readonly PageHeaderCrumb[] =>
|
|
19
21
|
Array.isArray(value) && value.every((item) => typeof item === "object" && item !== null && "label" in item);
|
|
20
22
|
|
|
21
|
-
export const PageHeader = ({
|
|
23
|
+
export const PageHeader = ({
|
|
24
|
+
kicker,
|
|
25
|
+
title,
|
|
26
|
+
subtitle,
|
|
27
|
+
description,
|
|
28
|
+
meta,
|
|
29
|
+
breadcrumbs,
|
|
30
|
+
actions,
|
|
31
|
+
className,
|
|
32
|
+
}: PageHeaderProps) => {
|
|
22
33
|
const crumbNode =
|
|
23
34
|
breadcrumbs === undefined
|
|
24
35
|
? undefined
|
|
@@ -38,6 +49,7 @@ export const PageHeader = ({ kicker, title, subtitle, description, breadcrumbs,
|
|
|
38
49
|
{(subtitle ?? description) !== undefined && (
|
|
39
50
|
<p className="udb-pageheader__subtitle">{subtitle ?? description}</p>
|
|
40
51
|
)}
|
|
52
|
+
{meta !== undefined && <div className="udb-pageheader__meta">{meta}</div>}
|
|
41
53
|
</div>
|
|
42
54
|
{actions !== undefined && <div className="udb-pageheader__actions">{actions}</div>}
|
|
43
55
|
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { renderToString } from 'react-dom/server';
|
|
3
|
+
import { SectionHeader } from './SectionHeader';
|
|
4
|
+
|
|
5
|
+
describe('SectionHeader markup smoke', () => {
|
|
6
|
+
it('renders an h2 title with optional kicker before it', () => {
|
|
7
|
+
const html = renderToString(
|
|
8
|
+
<SectionHeader kicker="This week" title="Reading" subtitle="Long-form practice" />,
|
|
9
|
+
);
|
|
10
|
+
const kickerAt = html.indexOf('udb-sectionheader__kicker');
|
|
11
|
+
const titleAt = html.indexOf('<h2 class="udb-sectionheader__title"');
|
|
12
|
+
expect(kickerAt).toBeGreaterThan(-1);
|
|
13
|
+
expect(kickerAt).toBeLessThan(titleAt);
|
|
14
|
+
expect(html).toContain('Long-form practice');
|
|
15
|
+
|
|
16
|
+
const bare = renderToString(<SectionHeader title="Reading" />);
|
|
17
|
+
expect(bare).not.toContain('udb-sectionheader__kicker');
|
|
18
|
+
expect(bare).not.toContain('udb-sectionheader__subtitle');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('renders actions in their slot and accepts description as subtitle alias', () => {
|
|
22
|
+
const html = renderToString(
|
|
23
|
+
<SectionHeader title="Writing" description="Timed tasks" actions={<button type="button">New</button>} />,
|
|
24
|
+
);
|
|
25
|
+
expect(html).toContain('udb-sectionheader__actions');
|
|
26
|
+
expect(html).toContain('udb-sectionheader__subtitle');
|
|
27
|
+
expect(html).toContain('New');
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
export interface SectionHeaderProps {
|
|
4
|
+
/** Small uppercase label above the title. */
|
|
5
|
+
kicker?: ReactNode;
|
|
6
|
+
title?: ReactNode;
|
|
7
|
+
subtitle?: ReactNode;
|
|
8
|
+
description?: ReactNode;
|
|
9
|
+
actions?: ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Section-level heading (h2) with an optional actions row — the in-page
|
|
14
|
+
* counterpart to PageHeader for stacked dashboard sections. */
|
|
15
|
+
export const SectionHeader = ({
|
|
16
|
+
kicker,
|
|
17
|
+
title,
|
|
18
|
+
subtitle,
|
|
19
|
+
description,
|
|
20
|
+
actions,
|
|
21
|
+
className,
|
|
22
|
+
}: SectionHeaderProps) => (
|
|
23
|
+
<div className={`udb-sectionheader${className ? ` ${className}` : ""}`}>
|
|
24
|
+
<div className="udb-sectionheader__main">
|
|
25
|
+
{kicker !== undefined && <p className="udb-sectionheader__kicker">{kicker}</p>}
|
|
26
|
+
{title !== undefined && <h2 className="udb-sectionheader__title">{title}</h2>}
|
|
27
|
+
{(subtitle ?? description) !== undefined && (
|
|
28
|
+
<p className="udb-sectionheader__subtitle">{subtitle ?? description}</p>
|
|
29
|
+
)}
|
|
30
|
+
</div>
|
|
31
|
+
{actions !== undefined && <div className="udb-sectionheader__actions">{actions}</div>}
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
@@ -4,3 +4,5 @@ export { DashboardSidebar } from './DashboardSidebar';
|
|
|
4
4
|
export { BrandLogo } from './BrandLogo';
|
|
5
5
|
export { PageHeader } from './PageHeader';
|
|
6
6
|
export type { PageHeaderProps, PageHeaderCrumb } from './PageHeader';
|
|
7
|
+
export { SectionHeader } from './SectionHeader';
|
|
8
|
+
export type { SectionHeaderProps } from './SectionHeader';
|