@countermeasure-platform/web-components 1.3.5 → 1.3.6-dev.37.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{component-D5sRm1fq.js → component-D_asjmrt.js} +5 -3
- package/dist/component-D_asjmrt.js.map +1 -0
- package/dist/components/brand/index.d.ts.map +1 -1
- package/dist/components/brand/index.js +11 -5
- package/dist/components/brand/index.js.map +1 -1
- package/dist/components/brand/types.d.ts +2 -0
- package/dist/components/brand/types.d.ts.map +1 -1
- package/dist/icons/index.d.ts +7 -2
- package/dist/icons/index.d.ts.map +1 -1
- package/dist/icons/index.js +7 -2
- package/dist/icons/index.js.map +1 -1
- package/dist/icons/lucide.d.ts +3 -0
- package/dist/icons/lucide.d.ts.map +1 -1
- package/dist/icons/lucide.js +3 -0
- package/dist/icons/lucide.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +126 -125
- package/dist/layout/app-shell.d.ts +7 -0
- package/dist/layout/app-shell.d.ts.map +1 -1
- package/dist/layout/app-shell.js +24 -6
- package/dist/layout/app-shell.js.map +1 -1
- package/dist/layout/core-app-chrome.d.ts.map +1 -1
- package/dist/layout/core-app-chrome.js +8 -5
- package/dist/layout/core-app-chrome.js.map +1 -1
- package/dist/layout/core-app-library-dashboard.d.ts +72 -0
- package/dist/layout/core-app-library-dashboard.d.ts.map +1 -0
- package/dist/layout/core-app-library-dashboard.js +160 -0
- package/dist/layout/core-app-library-dashboard.js.map +1 -0
- package/dist/layout/index.d.ts +2 -0
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +38 -37
- package/dist/layout/index.js.map +1 -1
- package/dist/react/brand/index.d.ts +3 -1
- package/dist/react/brand/index.d.ts.map +1 -1
- package/dist/react/brand.js +19 -13
- package/dist/react/brand.js.map +1 -1
- package/dist/react/layout/core-app-library-dashboard.d.ts +13 -0
- package/dist/react/layout/core-app-library-dashboard.d.ts.map +1 -0
- package/dist/react/layout/core-app-library-dashboard.js +27 -0
- package/dist/react/layout/core-app-library-dashboard.js.map +1 -0
- package/dist/react/layout/index.d.ts +1 -0
- package/dist/react/layout/index.d.ts.map +1 -1
- package/dist/react/layout/index.js +3 -2
- package/dist/react/primitives/alert.d.ts +1 -1
- package/dist/react/primitives/toast.d.ts +1 -1
- package/dist/react/sidebar.js +1 -1
- package/dist/react.js +97 -96
- package/dist/sidebar/component.d.ts.map +1 -1
- package/dist/sidebar/index.js +1 -1
- package/dist/sidebar/types.d.ts +7 -0
- package/dist/sidebar/types.d.ts.map +1 -1
- package/dist/styles/components/brand.css +22 -0
- package/dist/styles/layout.css +577 -0
- package/dist/styles/sidebar.css +26 -0
- package/package.json +11 -1
- package/src/components/brand/index.ts +22 -4
- package/src/components/brand/types.ts +2 -0
- package/src/icons/icons.test.ts +1 -1
- package/src/icons/index.ts +7 -2
- package/src/icons/lucide.ts +4 -0
- package/src/index.ts +2 -0
- package/src/layout/app-shell.test.ts +76 -0
- package/src/layout/app-shell.ts +38 -7
- package/src/layout/core-app-chrome.test.ts +17 -5
- package/src/layout/core-app-chrome.ts +8 -3
- package/src/layout/core-app-library-dashboard.test.ts +397 -0
- package/src/layout/core-app-library-dashboard.ts +519 -0
- package/src/layout/index.ts +18 -0
- package/src/react/brand/index.test.tsx +10 -0
- package/src/react/brand/index.tsx +25 -4
- package/src/react/layout/core-app-chrome.test.tsx +2 -2
- package/src/react/layout/core-app-library-dashboard.test.tsx +42 -0
- package/src/react/layout/core-app-library-dashboard.tsx +56 -0
- package/src/react/layout/index.ts +6 -0
- package/src/sidebar/component.test.ts +21 -1
- package/src/sidebar/component.ts +14 -8
- package/src/sidebar/types.ts +7 -0
- package/src/styles/components/brand.css +22 -0
- package/src/styles/layout.css +577 -0
- package/src/styles/sidebar.css +26 -0
- package/dist/component-D5sRm1fq.js.map +0 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
mountCoreAppLibraryDashboard,
|
|
5
|
+
type CoreAppLibraryDashboardData,
|
|
6
|
+
type CoreAppLibraryDashboardMount,
|
|
7
|
+
type CoreAppLibraryDashboardMountOptions,
|
|
8
|
+
} from '../../layout/core-app-library-dashboard'
|
|
9
|
+
import { cn } from '../primitives/utils'
|
|
10
|
+
|
|
11
|
+
export interface CoreAppLibraryDashboardProps {
|
|
12
|
+
data?: CoreAppLibraryDashboardData
|
|
13
|
+
className?: string
|
|
14
|
+
dashboardClassName?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type { CoreAppLibraryDashboardData, CoreAppLibraryDashboardMount }
|
|
18
|
+
|
|
19
|
+
function CoreAppLibraryDashboard({
|
|
20
|
+
data,
|
|
21
|
+
className,
|
|
22
|
+
dashboardClassName,
|
|
23
|
+
}: CoreAppLibraryDashboardProps) {
|
|
24
|
+
const containerRef = React.useRef<HTMLDivElement>(null)
|
|
25
|
+
const mountRef = React.useRef<CoreAppLibraryDashboardMount | null>(null)
|
|
26
|
+
const latestDataRef = React.useRef<CoreAppLibraryDashboardData | undefined>(data)
|
|
27
|
+
latestDataRef.current = data
|
|
28
|
+
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
const container = containerRef.current
|
|
31
|
+
if (container === null) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const mountOptions: CoreAppLibraryDashboardMountOptions = { container }
|
|
36
|
+
if (latestDataRef.current !== undefined) mountOptions.data = latestDataRef.current
|
|
37
|
+
if (dashboardClassName !== undefined) mountOptions.className = dashboardClassName
|
|
38
|
+
|
|
39
|
+
mountRef.current = mountCoreAppLibraryDashboard(mountOptions)
|
|
40
|
+
|
|
41
|
+
return () => {
|
|
42
|
+
mountRef.current?.destroy()
|
|
43
|
+
mountRef.current = null
|
|
44
|
+
}
|
|
45
|
+
}, [dashboardClassName])
|
|
46
|
+
|
|
47
|
+
React.useEffect(() => {
|
|
48
|
+
mountRef.current?.update(data ?? {})
|
|
49
|
+
}, [data])
|
|
50
|
+
|
|
51
|
+
return <div ref={containerRef} data-slot="core-app-library-dashboard" className={cn(className)} />
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
CoreAppLibraryDashboard.displayName = 'CoreAppLibraryDashboard'
|
|
55
|
+
|
|
56
|
+
export { CoreAppLibraryDashboard }
|
|
@@ -7,6 +7,12 @@ export {
|
|
|
7
7
|
type CoreAppSidebarPresetOptions,
|
|
8
8
|
type CoreAppTopbarPresetOptions,
|
|
9
9
|
} from './core-app-chrome'
|
|
10
|
+
export {
|
|
11
|
+
CoreAppLibraryDashboard,
|
|
12
|
+
type CoreAppLibraryDashboardData,
|
|
13
|
+
type CoreAppLibraryDashboardMount,
|
|
14
|
+
type CoreAppLibraryDashboardProps,
|
|
15
|
+
} from './core-app-library-dashboard'
|
|
10
16
|
export { DetailHeader, type DetailHeaderProps } from './detail-header'
|
|
11
17
|
export { PageHeader, type PageHeaderProps } from './page-header'
|
|
12
18
|
export { SubNav, type SubNavItem, type SubNavProps } from './sub-nav'
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
2
3
|
|
|
3
4
|
import { SidebarComponent } from './component'
|
|
4
5
|
|
|
6
|
+
const sidebarCss = readFileSync('src/styles/sidebar.css', 'utf8')
|
|
7
|
+
|
|
5
8
|
function createContainer(): HTMLElement {
|
|
6
9
|
const container = document.createElement('div')
|
|
7
10
|
container.style.height = '320px'
|
|
@@ -20,7 +23,7 @@ describe('SidebarComponent', () => {
|
|
|
20
23
|
const sidebar = new SidebarComponent({
|
|
21
24
|
container,
|
|
22
25
|
variant: 'product',
|
|
23
|
-
brand: { label: 'CounterMeasure' },
|
|
26
|
+
brand: { label: 'CounterMeasure', subtitle: 'Platform', wordmarkCase: 'title' },
|
|
24
27
|
collapsible: true,
|
|
25
28
|
collapseButtonVisible: true,
|
|
26
29
|
sections: [
|
|
@@ -44,6 +47,12 @@ describe('SidebarComponent', () => {
|
|
|
44
47
|
expect(container.querySelector('.sidebar')?.getAttribute('data-sidebar')).toBe('product')
|
|
45
48
|
expect(container.querySelector('.sidebar')?.getAttribute('data-open')).toBe('false')
|
|
46
49
|
expect(container.querySelector('.sidebar__header .cmm-brand-lockup')).toBeTruthy()
|
|
50
|
+
expect(
|
|
51
|
+
container.querySelector('.sidebar__header .cmm-brand-lockup__counter')?.textContent
|
|
52
|
+
).toBe('Counter')
|
|
53
|
+
expect(
|
|
54
|
+
container.querySelector('.sidebar__header .cmm-brand-lockup__subtitle')?.textContent
|
|
55
|
+
).toBe('Platform')
|
|
47
56
|
expect(container.querySelector('.sidebar__body .sidebar__section')).toBeTruthy()
|
|
48
57
|
expect(container.querySelector('.sidebar__badge--amber')?.textContent).toBe('3')
|
|
49
58
|
expect(container.querySelector('.sidebar__item')?.getAttribute('data-badge-visible')).toBe(
|
|
@@ -97,6 +106,17 @@ describe('SidebarComponent', () => {
|
|
|
97
106
|
container.remove()
|
|
98
107
|
})
|
|
99
108
|
|
|
109
|
+
it('keeps collapsed brand lockups mark-only while restoring full copy on mobile', () => {
|
|
110
|
+
expect(sidebarCss).toContain('.sidebar--collapsed .cmm-brand-lockup__copy')
|
|
111
|
+
expect(sidebarCss).toContain('.sidebar--collapsed .cmm-brand-lockup__wordmark')
|
|
112
|
+
expect(sidebarCss).toMatch(
|
|
113
|
+
/\.sidebar--collapsed \.cmm-brand-lockup__copy,\s*\.sidebar--collapsed \.cmm-brand-lockup__wordmark\s*{\s*display: none;/s
|
|
114
|
+
)
|
|
115
|
+
expect(sidebarCss).toMatch(
|
|
116
|
+
/\.sidebar--collapsed \.cmm-brand-lockup__copy,\s*\.sidebar--collapsed \.cmm-brand-lockup__wordmark\s*{\s*display: inline-flex;/s
|
|
117
|
+
)
|
|
118
|
+
})
|
|
119
|
+
|
|
100
120
|
it('reflects controlled mobile open state without changing desktop collapse state', () => {
|
|
101
121
|
const container = createContainer()
|
|
102
122
|
const sidebar = new SidebarComponent({
|
package/src/sidebar/component.ts
CHANGED
|
@@ -389,14 +389,20 @@ export class SidebarComponent {
|
|
|
389
389
|
brandEl.addEventListener('click', brand.onClick)
|
|
390
390
|
}
|
|
391
391
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
392
|
+
const lockupConfig = {
|
|
393
|
+
label: brand.label ?? 'CounterMeasure',
|
|
394
|
+
markSize: brand.markSize ?? 22,
|
|
395
|
+
showWordmark: brand.showWordmark ?? true,
|
|
396
|
+
decorative: brand.decorative ?? false,
|
|
397
|
+
}
|
|
398
|
+
if (brand.subtitle !== undefined) {
|
|
399
|
+
Object.assign(lockupConfig, { subtitle: brand.subtitle })
|
|
400
|
+
}
|
|
401
|
+
if (brand.wordmarkCase !== undefined) {
|
|
402
|
+
Object.assign(lockupConfig, { wordmarkCase: brand.wordmarkCase })
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
brandEl.appendChild(createBrandLockupElement(lockupConfig))
|
|
400
406
|
|
|
401
407
|
row.appendChild(brandEl)
|
|
402
408
|
header.appendChild(row)
|
package/src/sidebar/types.ts
CHANGED
|
@@ -145,6 +145,13 @@ export interface SidebarFooterAction {
|
|
|
145
145
|
export interface SidebarBrandConfig {
|
|
146
146
|
/** Accessible brand label. */
|
|
147
147
|
label?: string
|
|
148
|
+
/** Optional short subtitle rendered beneath the wordmark. */
|
|
149
|
+
subtitle?: string
|
|
150
|
+
/**
|
|
151
|
+
* Wordmark text treatment.
|
|
152
|
+
* @default 'uppercase'
|
|
153
|
+
*/
|
|
154
|
+
wordmarkCase?: 'uppercase' | 'title'
|
|
148
155
|
/** Brand mark size. */
|
|
149
156
|
markSize?: BrandSize | number
|
|
150
157
|
/**
|
|
@@ -104,6 +104,13 @@
|
|
|
104
104
|
vertical-align: middle;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
.cmm-brand-lockup__copy {
|
|
108
|
+
display: inline-flex;
|
|
109
|
+
min-width: 0;
|
|
110
|
+
flex-direction: column;
|
|
111
|
+
gap: 0.1875rem;
|
|
112
|
+
}
|
|
113
|
+
|
|
107
114
|
.cmm-brand-lockup__wordmark {
|
|
108
115
|
display: inline-flex;
|
|
109
116
|
align-items: baseline;
|
|
@@ -117,6 +124,11 @@
|
|
|
117
124
|
letter-spacing: 0.08em;
|
|
118
125
|
}
|
|
119
126
|
|
|
127
|
+
.cmm-brand-lockup--title .cmm-brand-lockup__wordmark {
|
|
128
|
+
font-size: 0.875rem;
|
|
129
|
+
letter-spacing: 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
120
132
|
.cmm-brand-lockup__counter {
|
|
121
133
|
color: currentColor;
|
|
122
134
|
}
|
|
@@ -125,6 +137,16 @@
|
|
|
125
137
|
color: var(--color-orange-500, hsl(var(--primary)));
|
|
126
138
|
}
|
|
127
139
|
|
|
140
|
+
.cmm-brand-lockup__subtitle {
|
|
141
|
+
overflow: hidden;
|
|
142
|
+
color: var(--color-text-dim, hsl(var(--muted-foreground)));
|
|
143
|
+
font: var(--type-caption, 600 0.625rem/1 var(--font-sans, sans-serif));
|
|
144
|
+
letter-spacing: 0.16em;
|
|
145
|
+
text-overflow: ellipsis;
|
|
146
|
+
text-transform: uppercase;
|
|
147
|
+
white-space: nowrap;
|
|
148
|
+
}
|
|
149
|
+
|
|
128
150
|
.cmm-connector-logo {
|
|
129
151
|
--cmm-connector-logo-bg: #475569;
|
|
130
152
|
|