Compare commits

..

4 Commits

Author SHA1 Message Date
c841c49e1e v3.69.0
Some checks failed
Default (tags) / security (push) Failing after 1s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-04-08 08:58:05 +00:00
2595d822d0 feat(dees-heading): add numeric aliases for horizontal rule heading levels and refine heading spacing styles 2026-04-08 08:58:05 +00:00
3ae0541065 v3.68.0
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-04-08 08:05:53 +00:00
4b735b768a feat(dees-simple-appdash): add nested sidebar subviews and preserve submit labels from slotted text 2026-04-08 08:05:53 +00:00
8 changed files with 209 additions and 43 deletions

View File

@@ -1,5 +1,18 @@
# Changelog
## 2026-04-08 - 3.69.0 - feat(dees-heading)
add numeric aliases for horizontal rule heading levels and refine heading spacing styles
- Support level="7" as an alias for "hr" and level="8" as an alias for "hr-small".
- Update heading and hr variant styles to use design tokens for spacing and colors, with per-level margin tuning.
- Extend the demo to show both named and numeric hr heading level variants.
## 2026-04-08 - 3.68.0 - feat(dees-simple-appdash)
add nested sidebar subviews and preserve submit labels from slotted text
- support grouped navigation items with expandable subviews and parent-to-first-subview fallback in the app dashboard
- allow dees-form-submit to derive its button text from light DOM content when no explicit text property is set
## 2026-04-07 - 3.67.1 - fix(repo)
no changes to commit

View File

@@ -1,6 +1,6 @@
{
"name": "@design.estate/dees-catalog",
"version": "3.67.1",
"version": "3.69.0",
"private": false,
"description": "A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.",
"main": "dist_ts_web/index.js",

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@design.estate/dees-catalog',
version: '3.67.1',
version: '3.69.0',
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
}

View File

@@ -75,12 +75,23 @@ export class DeesFormSubmit extends DeesElement {
.text=${this.text}
?disabled=${this.disabled}
@clicked=${this.submit}
>
<slot></slot>
</dees-button>
></dees-button>
`;
}
public async firstUpdated() {
// Capture light DOM text content as the button label. dees-button wipes
// its own light DOM during extractLightDom(), so we cannot simply forward
// a <slot> into it — we have to hoist the text onto the .text property
// ourselves before handing it to dees-button.
if (!this.text) {
const slotText = this.textContent?.trim();
if (slotText) {
this.text = slotText;
}
}
}
public async submit() {
if (this.disabled) {
return;

View File

@@ -8,7 +8,9 @@ export function demoFunc() {
<dees-heading level="4">This is a H4 heading</dees-heading>
<dees-heading level="5">This is a H5 heading</dees-heading>
<dees-heading level="6">This is a H6 heading</dees-heading>
<dees-heading level="hr">This is an hr heading</dees-heading>
<dees-heading level="hr-small">This is an hr small heading</dees-heading>
<dees-heading level="hr">This is an hr heading (level="hr")</dees-heading>
<dees-heading level="7">This is an hr heading (level="7")</dees-heading>
<dees-heading level="hr-small">This is an hr-small heading (level="hr-small")</dees-heading>
<dees-heading level="8">This is an hr-small heading (level="8")</dees-heading>
`;
}

View File

@@ -27,68 +27,91 @@ export class DeesHeading extends DeesElement {
// properties
/**
* Heading level: 1-6 for h1-h6, or 'hr' for horizontal rule style
* Heading level:
* '1'-'6' → <h1>..<h6>
* '7'|'hr' → horizontal-rule style heading
* '8'|'hr-small' → small horizontal-rule style heading
*/
@property({ type: String, reflect: true })
accessor level: '1' | '2' | '3' | '4' | '5' | '6' | 'hr' | 'hr-small' = '1';
accessor level: '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | 'hr' | 'hr-small' = '1';
// STATIC STYLES
public static styles: CSSResult[] = [
themeDefaultStyles,
cssManager.defaultStyles,
css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host {
display: block;
}
/* Heading styles */
h1, h2, h3, h4, h5, h6 {
margin: 16px 0 8px;
font-weight: 600;
color: ${cssManager.bdTheme('#000', '#fff')};
color: var(--dees-color-text-primary);
}
h1 { font-size: 32px; font-family: ${cssCalSansFontFamily}; letter-spacing: 0.025em;}
h2 { font-size: 28px; }
h3 { font-size: 24px; }
h4 { font-size: 20px; }
h5 { font-size: 16px; }
h6 { font-size: 14px; }
/* Per-level typography + spacing.
* Margin scales with importance: h1 gets the most breathing room,
* h6 the least. Top margin > bottom margin so headings group with
* the content that follows them. */
h1 {
font-size: 32px;
font-family: ${cssCalSansFontFamily};
letter-spacing: 0.025em;
margin: var(--dees-spacing-2xl) 0 var(--dees-spacing-lg);
}
h2 {
font-size: 28px;
margin: var(--dees-spacing-xl) 0 var(--dees-spacing-md);
}
h3 {
font-size: 24px;
margin: var(--dees-spacing-xl) 0 var(--dees-spacing-md);
}
h4 {
font-size: 20px;
margin: var(--dees-spacing-lg) 0 var(--dees-spacing-sm);
}
h5 {
font-size: 16px;
margin: var(--dees-spacing-md) 0 var(--dees-spacing-sm);
}
h6 {
font-size: 14px;
margin: var(--dees-spacing-md) 0 var(--dees-spacing-xs);
}
/* Horizontal rule style heading */
.heading-hr {
display: flex;
align-items: center;
text-align: center;
margin: 16px 0;
color: ${cssManager.bdTheme('#999', '#555')};
margin: var(--dees-spacing-lg) 0;
color: var(--dees-color-text-muted);
}
/* Fade lines toward and away from text for hr style */
.heading-hr::before {
content: '';
flex: 1;
height: 1px;
/* fade in toward center */
background: ${cssManager.bdTheme(
'linear-gradient(to right, transparent, #ccc)',
'linear-gradient(to right, transparent, #333)'
)};
margin: 0 8px;
background: linear-gradient(to right, transparent, var(--dees-color-border-strong));
margin: 0 var(--dees-spacing-sm);
}
.heading-hr::after {
content: '';
flex: 1;
height: 1px;
/* fade out away from center */
background: ${cssManager.bdTheme(
'linear-gradient(to right, #ccc, transparent)',
'linear-gradient(to right, #333, transparent)'
)};
margin: 0 8px;
background: linear-gradient(to right, var(--dees-color-border-strong), transparent);
margin: 0 var(--dees-spacing-sm);
}
/* Small hr variant with reduced margins */
.heading-hr.heading-hr-small {
margin: 8px 0;
margin: var(--dees-spacing-sm) 0;
font-size: 12px;
}
.heading-hr.heading-hr-small::before,
.heading-hr.heading-hr-small::after {
margin: 0 8px;
margin: 0 var(--dees-spacing-sm);
}
`,
];
@@ -109,8 +132,10 @@ export class DeesHeading extends DeesElement {
return html`<h5><slot></slot></h5>`;
case '6':
return html`<h6><slot></slot></h6>`;
case '7':
case 'hr':
return html`<div class="heading-hr"><slot></slot></div>`;
case '8':
case 'hr-small':
return html`<div class="heading-hr heading-hr-small"><slot></slot></div>`;
default:

View File

@@ -353,12 +353,35 @@ export const demoFunc = () => html`
name: 'Analytics',
iconName: 'lucide:lineChart',
element: DemoViewAnalytics,
subViews: [
{
name: 'Overview',
iconName: 'lucide:activity',
element: DemoViewAnalytics,
},
{
name: 'Reports',
iconName: 'lucide:fileText',
element: DemoViewDashboard,
},
],
},
{
name: 'Settings',
iconName: 'lucide:settings',
element: DemoViewSettings,
}
subViews: [
{
name: 'Profile',
iconName: 'lucide:user',
element: DemoViewSettings,
},
{
name: 'Billing',
iconName: 'lucide:creditCard',
element: DemoViewSettings,
},
],
},
] as IView[]}
@logout=${() => {
console.log('Logout event triggered');

View File

@@ -26,7 +26,8 @@ declare global {
export interface IView {
name: string;
iconName?: string;
element: DeesElement['constructor']['prototype'];
element?: DeesElement['constructor']['prototype'];
subViews?: IView[];
}
export type TGlobalMessageType = 'info' | 'success' | 'warning' | 'error';
@@ -250,6 +251,55 @@ export class DeesSimpleAppDash extends DeesElement {
white-space: nowrap;
}
.viewTab .chevron {
flex: 0 0 auto;
font-size: 14px;
opacity: 0.5;
transform: rotate(-90deg);
transition: transform 0.2s ease, opacity 0.15s ease;
}
.viewTab.hasSubs:hover .chevron {
opacity: 0.75;
}
.viewTab.hasSubs.groupActive .chevron {
transform: rotate(0deg);
opacity: 0.9;
}
.subViews {
display: flex;
flex-direction: column;
gap: 2px;
margin: 2px 0 4px 12px;
padding-left: 12px;
position: relative;
}
.subViews::before {
content: '';
position: absolute;
left: 0;
top: 4px;
bottom: 4px;
width: 1px;
background: var(--dees-color-border-default);
}
.viewTab.sub {
padding: 8px 12px;
font-size: 12px;
}
.viewTab.sub dees-icon {
font-size: 14px;
}
.viewTab.sub.selected::before {
left: -12px;
}
.appActions {
padding: 12px 8px;
border-top: 1px solid var(--dees-color-border-default);
@@ -563,10 +613,12 @@ export class DeesSimpleAppDash extends DeesElement {
<div class="viewTabs-container">
<div class="section-label">Navigation</div>
<div class="viewTabs">
${this.viewTabs.map(
(view) => html`
${this.viewTabs.map((view) => {
const hasSubs = !!view.subViews?.length;
const groupActive = hasSubs && this.isGroupActive(view);
return html`
<div
class="viewTab ${this.selectedView === view ? 'selected' : ''}"
class="viewTab ${this.selectedView === view ? 'selected' : ''} ${hasSubs ? 'hasSubs' : ''} ${groupActive ? 'groupActive' : ''}"
@click=${() => this.loadView(view)}
>
${view.iconName ? html`
@@ -575,9 +627,34 @@ export class DeesSimpleAppDash extends DeesElement {
<dees-icon .icon="${'lucide:file'}"></dees-icon>
`}
<span>${view.name}</span>
${hasSubs ? html`
<dees-icon class="chevron" .icon="${'lucide:chevronDown'}"></dees-icon>
` : ''}
</div>
`
)}
${hasSubs && groupActive ? html`
<div class="subViews">
${view.subViews!.map(
(sub) => html`
<div
class="viewTab sub ${this.selectedView === sub ? 'selected' : ''}"
@click=${(e: Event) => {
e.stopPropagation();
this.loadView(sub);
}}
>
${sub.iconName ? html`
<dees-icon .icon="${sub.iconName.includes(':') ? sub.iconName : `lucide:${sub.iconName}`}"></dees-icon>
` : html`
<dees-icon .icon="${'lucide:dot'}"></dees-icon>
`}
<span>${sub.name}</span>
</div>
`
)}
</div>
` : ''}
`;
})}
</div>
</div>
<div class="appActions">
@@ -771,8 +848,23 @@ export class DeesSimpleAppDash extends DeesElement {
}
private isGroupActive(view: IView): boolean {
if (this.selectedView === view) return true;
return view.subViews?.some((sv) => sv === this.selectedView) ?? false;
}
private currentView!: DeesElement;
public async loadView(viewArg: IView) {
// Group-only parent: resolve to first sub view with an element
if (!viewArg.element && viewArg.subViews?.length) {
const firstNavigable = viewArg.subViews.find((sv) => sv.element);
if (firstNavigable) {
return this.loadView(firstNavigable);
}
return; // nothing navigable — ignore click
}
if (!viewArg.element) return; // safety: no element and no subs → no-op
const appcontent = this.shadowRoot!.querySelector('.appcontent')!;
const view = new viewArg.element();
if (this.currentView) {
@@ -781,7 +873,7 @@ export class DeesSimpleAppDash extends DeesElement {
appcontent.appendChild(view);
this.currentView = view;
this.selectedView = viewArg;
// Emit view-select event
this.dispatchEvent(new CustomEvent('view-select', {
detail: { view: viewArg },