@surfnet/curve-angular 0.2.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/.postcssrc.json +7 -0
- package/.storybook/main.ts +9 -0
- package/.storybook/manager.ts +3 -0
- package/.storybook/preview.ts +28 -0
- package/.storybook/tsconfig.json +8 -0
- package/.turbo/turbo-build.log +32 -0
- package/CHANGELOG.md +29 -0
- package/angular.json +52 -0
- package/components.json +5 -0
- package/dist/fesm2022/surfnet-curve-angular.mjs +4237 -0
- package/dist/fesm2022/surfnet-curve-angular.mjs.map +1 -0
- package/dist/files/geist-cyrillic-ext-wght-italic.woff2 +0 -0
- package/dist/files/geist-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/files/geist-cyrillic-wght-italic.woff2 +0 -0
- package/dist/files/geist-cyrillic-wght-normal.woff2 +0 -0
- package/dist/files/geist-latin-ext-wght-italic.woff2 +0 -0
- package/dist/files/geist-latin-ext-wght-normal.woff2 +0 -0
- package/dist/files/geist-latin-wght-italic.woff2 +0 -0
- package/dist/files/geist-latin-wght-normal.woff2 +0 -0
- package/dist/files/geist-vietnamese-wght-italic.woff2 +0 -0
- package/dist/files/geist-vietnamese-wght-normal.woff2 +0 -0
- package/dist/styles.css +2 -0
- package/dist/types/surfnet-curve-angular.d.ts +1017 -0
- package/ng-package.json +20 -0
- package/package.json +73 -0
- package/scripts/copy-font-files.ts +15 -0
- package/scripts/rewrite-helm-imports.ts +60 -0
- package/src/foundations/design-tokens.stories.ts +198 -0
- package/src/lib/ui/avatar/src/index.ts +22 -0
- package/src/lib/ui/avatar/src/lib/hlm-avatar-badge.ts +19 -0
- package/src/lib/ui/avatar/src/lib/hlm-avatar-fallback.ts +20 -0
- package/src/lib/ui/avatar/src/lib/hlm-avatar-group-count.ts +17 -0
- package/src/lib/ui/avatar/src/lib/hlm-avatar-group.ts +17 -0
- package/src/lib/ui/avatar/src/lib/hlm-avatar-image.ts +19 -0
- package/src/lib/ui/avatar/src/lib/hlm-avatar.stories.ts +107 -0
- package/src/lib/ui/avatar/src/lib/hlm-avatar.ts +32 -0
- package/src/lib/ui/breadcrumb/src/index.ts +30 -0
- package/src/lib/ui/breadcrumb/src/lib/hlm-breadcrumb-ellipsis.ts +36 -0
- package/src/lib/ui/breadcrumb/src/lib/hlm-breadcrumb-item.ts +14 -0
- package/src/lib/ui/breadcrumb/src/lib/hlm-breadcrumb-link.ts +36 -0
- package/src/lib/ui/breadcrumb/src/lib/hlm-breadcrumb-list.ts +17 -0
- package/src/lib/ui/breadcrumb/src/lib/hlm-breadcrumb-page.ts +17 -0
- package/src/lib/ui/breadcrumb/src/lib/hlm-breadcrumb-separator.ts +27 -0
- package/src/lib/ui/breadcrumb/src/lib/hlm-breadcrumb.stories.ts +81 -0
- package/src/lib/ui/breadcrumb/src/lib/hlm-breadcrumb.ts +13 -0
- package/src/lib/ui/button/src/index.ts +6 -0
- package/src/lib/ui/button/src/lib/hlm-button.stories.ts +170 -0
- package/src/lib/ui/button/src/lib/hlm-button.token.ts +22 -0
- package/src/lib/ui/button/src/lib/hlm-button.ts +76 -0
- package/src/lib/ui/card/src/index.ts +25 -0
- package/src/lib/ui/card/src/lib/hlm-card-action.ts +12 -0
- package/src/lib/ui/card/src/lib/hlm-card-content.ts +12 -0
- package/src/lib/ui/card/src/lib/hlm-card-description.ts +12 -0
- package/src/lib/ui/card/src/lib/hlm-card-footer.ts +14 -0
- package/src/lib/ui/card/src/lib/hlm-card-header.ts +15 -0
- package/src/lib/ui/card/src/lib/hlm-card-title.ts +12 -0
- package/src/lib/ui/card/src/lib/hlm-card.stories.ts +105 -0
- package/src/lib/ui/card/src/lib/hlm-card.token.ts +19 -0
- package/src/lib/ui/card/src/lib/hlm-card.ts +22 -0
- package/src/lib/ui/checkbox/src/index.ts +5 -0
- package/src/lib/ui/checkbox/src/lib/hlm-checkbox.stories.ts +78 -0
- package/src/lib/ui/checkbox/src/lib/hlm-checkbox.ts +160 -0
- package/src/lib/ui/data-table/src/index.ts +14 -0
- package/src/lib/ui/data-table/src/lib/hlm-data-table-content.ts +87 -0
- package/src/lib/ui/data-table/src/lib/hlm-data-table-pagination.ts +62 -0
- package/src/lib/ui/data-table/src/lib/hlm-data-table-toolbar.ts +16 -0
- package/src/lib/ui/data-table/src/lib/hlm-data-table.stories.ts +479 -0
- package/src/lib/ui/data-table/src/lib/inject-data-table.ts +86 -0
- package/src/lib/ui/dropdown-menu/src/index.ts +45 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu-checkbox-indicator.ts +20 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu-checkbox.ts +36 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu-group.ts +16 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu-item-sub-indicator.ts +17 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu-item.ts +41 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu-label.ts +20 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu-radio-indicator.ts +20 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu-radio.ts +36 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu-separator.ts +14 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu-shortcut.ts +14 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu-sub.ts +58 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu-token.ts +26 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu-trigger.ts +49 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu.stories.ts +125 -0
- package/src/lib/ui/dropdown-menu/src/lib/hlm-dropdown-menu.ts +62 -0
- package/src/lib/ui/field/src/index.ts +34 -0
- package/src/lib/ui/field/src/lib/hlm-field-content.ts +12 -0
- package/src/lib/ui/field/src/lib/hlm-field-description.ts +53 -0
- package/src/lib/ui/field/src/lib/hlm-field-error.ts +100 -0
- package/src/lib/ui/field/src/lib/hlm-field-group.ts +15 -0
- package/src/lib/ui/field/src/lib/hlm-field-label.ts +17 -0
- package/src/lib/ui/field/src/lib/hlm-field-legend.ts +17 -0
- package/src/lib/ui/field/src/lib/hlm-field-separator.ts +24 -0
- package/src/lib/ui/field/src/lib/hlm-field-set.ts +15 -0
- package/src/lib/ui/field/src/lib/hlm-field-title.ts +15 -0
- package/src/lib/ui/field/src/lib/hlm-field.stories.ts +117 -0
- package/src/lib/ui/field/src/lib/hlm-field.ts +49 -0
- package/src/lib/ui/icon/src/index.ts +7 -0
- package/src/lib/ui/icon/src/lib/hlm-icon.token.ts +20 -0
- package/src/lib/ui/icon/src/lib/hlm-icon.ts +42 -0
- package/src/lib/ui/input/src/index.ts +5 -0
- package/src/lib/ui/input/src/lib/hlm-input.stories.ts +94 -0
- package/src/lib/ui/input/src/lib/hlm-input.ts +20 -0
- package/src/lib/ui/input-group/src/index.ts +22 -0
- package/src/lib/ui/input-group/src/lib/hlm-input-group-addon.ts +40 -0
- package/src/lib/ui/input-group/src/lib/hlm-input-group-button.ts +47 -0
- package/src/lib/ui/input-group/src/lib/hlm-input-group-input.ts +17 -0
- package/src/lib/ui/input-group/src/lib/hlm-input-group-text.ts +14 -0
- package/src/lib/ui/input-group/src/lib/hlm-input-group-textarea.ts +17 -0
- package/src/lib/ui/input-group/src/lib/hlm-input-group.stories.ts +133 -0
- package/src/lib/ui/input-group/src/lib/hlm-input-group.ts +18 -0
- package/src/lib/ui/label/src/index.ts +5 -0
- package/src/lib/ui/label/src/lib/hlm-label.stories.ts +55 -0
- package/src/lib/ui/label/src/lib/hlm-label.ts +17 -0
- package/src/lib/ui/select/src/index.ts +52 -0
- package/src/lib/ui/select/src/lib/hlm-select-content.ts +44 -0
- package/src/lib/ui/select/src/lib/hlm-select-group.ts +14 -0
- package/src/lib/ui/select/src/lib/hlm-select-item.ts +36 -0
- package/src/lib/ui/select/src/lib/hlm-select-label.ts +14 -0
- package/src/lib/ui/select/src/lib/hlm-select-multiple.ts +45 -0
- package/src/lib/ui/select/src/lib/hlm-select-placeholder.ts +17 -0
- package/src/lib/ui/select/src/lib/hlm-select-portal.ts +8 -0
- package/src/lib/ui/select/src/lib/hlm-select-scroll-down.ts +22 -0
- package/src/lib/ui/select/src/lib/hlm-select-scroll-up.ts +22 -0
- package/src/lib/ui/select/src/lib/hlm-select-separator.ts +14 -0
- package/src/lib/ui/select/src/lib/hlm-select-trigger.ts +59 -0
- package/src/lib/ui/select/src/lib/hlm-select-value-template.ts +5 -0
- package/src/lib/ui/select/src/lib/hlm-select-value.ts +18 -0
- package/src/lib/ui/select/src/lib/hlm-select-values-content.ts +9 -0
- package/src/lib/ui/select/src/lib/hlm-select-values.ts +5 -0
- package/src/lib/ui/select/src/lib/hlm-select.stories.ts +105 -0
- package/src/lib/ui/select/src/lib/hlm-select.ts +45 -0
- package/src/lib/ui/separator/src/index.ts +5 -0
- package/src/lib/ui/separator/src/lib/hlm-separator.stories.ts +88 -0
- package/src/lib/ui/separator/src/lib/hlm-separator.ts +19 -0
- package/src/lib/ui/sheet/src/index.ts +34 -0
- package/src/lib/ui/sheet/src/lib/hlm-sheet-close.ts +9 -0
- package/src/lib/ui/sheet/src/lib/hlm-sheet-content.ts +66 -0
- package/src/lib/ui/sheet/src/lib/hlm-sheet-description.ts +14 -0
- package/src/lib/ui/sheet/src/lib/hlm-sheet-footer.ts +12 -0
- package/src/lib/ui/sheet/src/lib/hlm-sheet-header.ts +12 -0
- package/src/lib/ui/sheet/src/lib/hlm-sheet-overlay.ts +27 -0
- package/src/lib/ui/sheet/src/lib/hlm-sheet-portal.ts +8 -0
- package/src/lib/ui/sheet/src/lib/hlm-sheet-title.ts +14 -0
- package/src/lib/ui/sheet/src/lib/hlm-sheet-trigger.ts +9 -0
- package/src/lib/ui/sheet/src/lib/hlm-sheet.ts +29 -0
- package/src/lib/ui/sidebar/src/index.ts +75 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-content.ts +18 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-footer.ts +15 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-group-action.ts +18 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-group-content.ts +15 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-group-label.ts +18 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-group.ts +15 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-header.ts +15 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-input.ts +17 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-inset.ts +15 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-menu-action.ts +24 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-menu-badge.ts +18 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-menu-button.ts +97 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-menu-item.ts +15 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-menu-skeleton.ts +33 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-menu-sub-button.ts +41 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-menu-sub-item.ts +15 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-menu-sub.ts +18 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-menu.ts +15 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-rail.ts +34 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-separator.ts +17 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-trigger.ts +35 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar-wrapper.ts +24 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar.service.ts +136 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar.stories.ts +177 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar.token.ts +33 -0
- package/src/lib/ui/sidebar/src/lib/hlm-sidebar.ts +139 -0
- package/src/lib/ui/skeleton/src/index.ts +5 -0
- package/src/lib/ui/skeleton/src/lib/hlm-skeleton.ts +14 -0
- package/src/lib/ui/table/src/index.ts +25 -0
- package/src/lib/ui/table/src/lib/hlm-table.stories.ts +70 -0
- package/src/lib/ui/table/src/lib/hlm-table.ts +129 -0
- package/src/lib/ui/textarea/src/index.ts +5 -0
- package/src/lib/ui/textarea/src/lib/hlm-textarea.stories.ts +72 -0
- package/src/lib/ui/textarea/src/lib/hlm-textarea.ts +21 -0
- package/src/lib/ui/tooltip/src/index.ts +5 -0
- package/src/lib/ui/tooltip/src/lib/hlm-tooltip.ts +44 -0
- package/src/lib/ui/utils/src/index.ts +1 -0
- package/src/lib/ui/utils/src/lib/hlm.ts +313 -0
- package/src/public-api.ts +24 -0
- package/src/styles.css +43 -0
- package/tsconfig.json +45 -0
- package/tsconfig.lib.json +11 -0
- package/tsconfig.lib.prod.json +9 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
|
|
2
|
+
import { NgIcon, provideIcons } from '@ng-icons/core';
|
|
3
|
+
import { phosphorDotsThree } from '@ng-icons/phosphor-icons/regular';
|
|
4
|
+
import { HlmIcon } from '../../../icon/src';
|
|
5
|
+
import { hlm } from '../../../utils/src';
|
|
6
|
+
import type { ClassValue } from 'clsx';
|
|
7
|
+
|
|
8
|
+
@Component({
|
|
9
|
+
selector: 'hlm-breadcrumb-ellipsis',
|
|
10
|
+
imports: [NgIcon, HlmIcon],
|
|
11
|
+
providers: [provideIcons({ phosphorDotsThree })],
|
|
12
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
13
|
+
template: `
|
|
14
|
+
<span
|
|
15
|
+
data-slot="breadcrumb-ellipsis"
|
|
16
|
+
role="presentation"
|
|
17
|
+
aria-hidden="true"
|
|
18
|
+
[class]="_computedClass()"
|
|
19
|
+
>
|
|
20
|
+
<ng-icon hlm size="sm" name="phosphorDotsThree" />
|
|
21
|
+
<span class="sr-only">{{ srOnlyText() }}</span>
|
|
22
|
+
</span>
|
|
23
|
+
`,
|
|
24
|
+
})
|
|
25
|
+
export class HlmBreadcrumbEllipsis {
|
|
26
|
+
public readonly userClass = input<ClassValue>('', { alias: 'class' });
|
|
27
|
+
/** Screen reader only text for the ellipsis */
|
|
28
|
+
public readonly srOnlyText = input<string>('More');
|
|
29
|
+
|
|
30
|
+
protected readonly _computedClass = computed(() =>
|
|
31
|
+
hlm(
|
|
32
|
+
'size-5 [&>ng-icon]:text-[calc(var(--spacing)*4)] flex items-center justify-center',
|
|
33
|
+
this.userClass(),
|
|
34
|
+
),
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Directive } from '@angular/core';
|
|
2
|
+
import { classes } from '../../../utils/src';
|
|
3
|
+
|
|
4
|
+
@Directive({
|
|
5
|
+
selector: '[hlmBreadcrumbItem]',
|
|
6
|
+
host: {
|
|
7
|
+
'data-slot': 'breadcrumb-item',
|
|
8
|
+
},
|
|
9
|
+
})
|
|
10
|
+
export class HlmBreadcrumbItem {
|
|
11
|
+
constructor() {
|
|
12
|
+
classes(() => 'gap-1.5 inline-flex items-center');
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Directive, input } from '@angular/core';
|
|
2
|
+
import { RouterLink } from '@angular/router';
|
|
3
|
+
import { classes } from '../../../utils/src';
|
|
4
|
+
|
|
5
|
+
@Directive({
|
|
6
|
+
selector: '[hlmBreadcrumbLink]',
|
|
7
|
+
hostDirectives: [
|
|
8
|
+
{
|
|
9
|
+
directive: RouterLink,
|
|
10
|
+
inputs: [
|
|
11
|
+
'target',
|
|
12
|
+
'queryParams',
|
|
13
|
+
'fragment',
|
|
14
|
+
'queryParamsHandling',
|
|
15
|
+
'state',
|
|
16
|
+
'info',
|
|
17
|
+
'relativeTo',
|
|
18
|
+
'preserveFragment',
|
|
19
|
+
'skipLocationChange',
|
|
20
|
+
'replaceUrl',
|
|
21
|
+
'routerLink: link',
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
host: {
|
|
26
|
+
'data-slot': 'breadcrumb-link',
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
export class HlmBreadcrumbLink {
|
|
30
|
+
/** The link to navigate to the page. */
|
|
31
|
+
public readonly link = input<RouterLink['routerLink']>();
|
|
32
|
+
|
|
33
|
+
constructor() {
|
|
34
|
+
classes(() => 'hover:text-foreground transition-colors');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Directive } from '@angular/core';
|
|
2
|
+
import { classes } from '../../../utils/src';
|
|
3
|
+
|
|
4
|
+
@Directive({
|
|
5
|
+
selector: '[hlmBreadcrumbList]',
|
|
6
|
+
host: {
|
|
7
|
+
'data-slot': 'breadcrumb-list',
|
|
8
|
+
},
|
|
9
|
+
})
|
|
10
|
+
export class HlmBreadcrumbList {
|
|
11
|
+
constructor() {
|
|
12
|
+
classes(
|
|
13
|
+
() =>
|
|
14
|
+
'text-muted-foreground gap-1.5 text-sm sm:gap-2.5 flex flex-wrap items-center wrap-break-word',
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Directive } from '@angular/core';
|
|
2
|
+
import { classes } from '../../../utils/src';
|
|
3
|
+
|
|
4
|
+
@Directive({
|
|
5
|
+
selector: '[hlmBreadcrumbPage]',
|
|
6
|
+
host: {
|
|
7
|
+
'data-slot': 'breadcrumb-page',
|
|
8
|
+
role: 'link',
|
|
9
|
+
'aria-disabled': 'true',
|
|
10
|
+
'aria-current': 'page',
|
|
11
|
+
},
|
|
12
|
+
})
|
|
13
|
+
export class HlmBreadcrumbPage {
|
|
14
|
+
constructor() {
|
|
15
|
+
classes(() => 'text-foreground font-normal');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
2
|
+
import { NgIcon, provideIcons } from '@ng-icons/core';
|
|
3
|
+
import { phosphorCaretRight } from '@ng-icons/phosphor-icons/regular';
|
|
4
|
+
import { classes } from '../../../utils/src';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
// eslint-disable-next-line @angular-eslint/component-selector
|
|
8
|
+
selector: '[hlmBreadcrumbSeparator]',
|
|
9
|
+
imports: [NgIcon],
|
|
10
|
+
providers: [provideIcons({ phosphorCaretRight })],
|
|
11
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
12
|
+
host: {
|
|
13
|
+
'data-slot': 'breadcrumb-separator',
|
|
14
|
+
role: 'presentation',
|
|
15
|
+
'aria-hidden': 'true',
|
|
16
|
+
},
|
|
17
|
+
template: `
|
|
18
|
+
<ng-content>
|
|
19
|
+
<ng-icon name="phosphorCaretRight" />
|
|
20
|
+
</ng-content>
|
|
21
|
+
`,
|
|
22
|
+
})
|
|
23
|
+
export class HlmBreadcrumbSeparator {
|
|
24
|
+
constructor() {
|
|
25
|
+
classes(() => '[&>ng-icon]:text-[calc(var(--spacing)*3.5)] [&>ng-icon]:flex');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { applicationConfig, moduleMetadata } from '@storybook/angular';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/angular';
|
|
3
|
+
import { breadcrumbContract } from '@surfnet/curve-contracts';
|
|
4
|
+
import { HlmBreadcrumb, HlmBreadcrumbImports } from '..';
|
|
5
|
+
import { provideRouter } from '@angular/router';
|
|
6
|
+
import { provideLocationMocks } from '@angular/common/testing';
|
|
7
|
+
|
|
8
|
+
const meta: Meta<HlmBreadcrumb> = {
|
|
9
|
+
title: 'Components/Breadcrumb',
|
|
10
|
+
component: HlmBreadcrumb,
|
|
11
|
+
decorators: [
|
|
12
|
+
moduleMetadata({
|
|
13
|
+
imports: [HlmBreadcrumbImports],
|
|
14
|
+
}),
|
|
15
|
+
applicationConfig({
|
|
16
|
+
providers: [
|
|
17
|
+
provideRouter([
|
|
18
|
+
{ path: '', component: HlmBreadcrumb },
|
|
19
|
+
{ path: '**', redirectTo: '' },
|
|
20
|
+
]),
|
|
21
|
+
provideLocationMocks(),
|
|
22
|
+
],
|
|
23
|
+
}),
|
|
24
|
+
],
|
|
25
|
+
parameters: {
|
|
26
|
+
docs: {
|
|
27
|
+
description: {
|
|
28
|
+
component: breadcrumbContract.docs.description,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default meta;
|
|
35
|
+
type Story = StoryObj<HlmBreadcrumb>;
|
|
36
|
+
|
|
37
|
+
/** A typical trail ending on the current page. */
|
|
38
|
+
export const Default: Story = {
|
|
39
|
+
render: () => ({
|
|
40
|
+
template: `
|
|
41
|
+
<nav hlmBreadcrumb>
|
|
42
|
+
<ol hlmBreadcrumbList>
|
|
43
|
+
<li hlmBreadcrumbItem>
|
|
44
|
+
<a hlmBreadcrumbLink link="/home">Home</a>
|
|
45
|
+
</li>
|
|
46
|
+
<li hlmBreadcrumbSeparator></li>
|
|
47
|
+
<li hlmBreadcrumbItem>
|
|
48
|
+
<a hlmBreadcrumbLink link="/components">Apps</a>
|
|
49
|
+
</li>
|
|
50
|
+
<li hlmBreadcrumbSeparator></li>
|
|
51
|
+
<li hlmBreadcrumbItem>
|
|
52
|
+
<span hlmBreadcrumbPage>App catalog</span>
|
|
53
|
+
</li>
|
|
54
|
+
</ol>
|
|
55
|
+
</nav>
|
|
56
|
+
`,
|
|
57
|
+
}),
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/** A long trail collapsed with an ellipsis. */
|
|
61
|
+
export const WithEllipsis: Story = {
|
|
62
|
+
render: () => ({
|
|
63
|
+
template: `
|
|
64
|
+
<nav hlmBreadcrumb>
|
|
65
|
+
<ol hlmBreadcrumbList>
|
|
66
|
+
<li hlmBreadcrumbItem>
|
|
67
|
+
<a hlmBreadcrumbLink link="/home">Home</a>
|
|
68
|
+
</li>
|
|
69
|
+
<li hlmBreadcrumbSeparator></li>
|
|
70
|
+
<li hlmBreadcrumbItem>
|
|
71
|
+
<hlm-breadcrumb-ellipsis />
|
|
72
|
+
</li>
|
|
73
|
+
<li hlmBreadcrumbSeparator></li>
|
|
74
|
+
<li hlmBreadcrumbItem>
|
|
75
|
+
<span hlmBreadcrumbPage>App catalog</span>
|
|
76
|
+
</li>
|
|
77
|
+
</ol>
|
|
78
|
+
</nav>
|
|
79
|
+
`,
|
|
80
|
+
}),
|
|
81
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Directive, input } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Directive({
|
|
4
|
+
selector: '[hlmBreadcrumb]',
|
|
5
|
+
host: {
|
|
6
|
+
'data-slot': 'breadcrumb',
|
|
7
|
+
role: 'navigation',
|
|
8
|
+
'[attr.aria-label]': 'ariaLabel()',
|
|
9
|
+
},
|
|
10
|
+
})
|
|
11
|
+
export class HlmBreadcrumb {
|
|
12
|
+
public readonly ariaLabel = input<string>('breadcrumb', { alias: 'aria-label' });
|
|
13
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { NgIcon, provideIcons } from '@ng-icons/core';
|
|
2
|
+
import { phosphorArrowRight, phosphorPlus } from '@ng-icons/phosphor-icons/regular';
|
|
3
|
+
import { argsToTemplate, moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
|
|
4
|
+
import { buttonContract } from '@surfnet/curve-contracts';
|
|
5
|
+
|
|
6
|
+
import { HlmButton, HlmButtonImports } from '..';
|
|
7
|
+
import { Component, Input } from '@angular/core';
|
|
8
|
+
|
|
9
|
+
// `disabled` is contributed by the BrnButton host directive rather than HlmButton
|
|
10
|
+
// itself, so widen the story args to expose it as a control.
|
|
11
|
+
type ButtonArgs = HlmButton & { disabled: boolean };
|
|
12
|
+
|
|
13
|
+
const meta: Meta<ButtonArgs> = {
|
|
14
|
+
title: 'Components/Button',
|
|
15
|
+
component: HlmButton,
|
|
16
|
+
decorators: [
|
|
17
|
+
moduleMetadata({
|
|
18
|
+
imports: [HlmButton, NgIcon],
|
|
19
|
+
providers: [provideIcons({ phosphorPlus, phosphorArrowRight })],
|
|
20
|
+
}),
|
|
21
|
+
],
|
|
22
|
+
parameters: {
|
|
23
|
+
docs: {
|
|
24
|
+
description: {
|
|
25
|
+
component: buttonContract.docs.description,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
argTypes: {
|
|
30
|
+
variant: {
|
|
31
|
+
control: 'select',
|
|
32
|
+
options: [...buttonContract.props.variants],
|
|
33
|
+
description: 'Visual style of the button.',
|
|
34
|
+
table: {
|
|
35
|
+
type: {
|
|
36
|
+
summary: buttonContract.props.variants.join(' | '),
|
|
37
|
+
},
|
|
38
|
+
defaultValue: { summary: buttonContract.defaults.variants },
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
size: {
|
|
42
|
+
control: 'select',
|
|
43
|
+
options: [...buttonContract.props.sizes],
|
|
44
|
+
description: 'Size of the button.',
|
|
45
|
+
table: {
|
|
46
|
+
type: {
|
|
47
|
+
summary: buttonContract.props.sizes.join(' | '),
|
|
48
|
+
},
|
|
49
|
+
defaultValue: { summary: buttonContract.defaults.sizes },
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
args: {
|
|
54
|
+
variant: buttonContract.defaults.variants,
|
|
55
|
+
size: buttonContract.defaults.sizes,
|
|
56
|
+
disabled: false,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export default meta;
|
|
61
|
+
|
|
62
|
+
type Story = StoryObj<ButtonArgs>;
|
|
63
|
+
|
|
64
|
+
/** The default button — rendered with the default args; tweak them via the controls. */
|
|
65
|
+
export const Default: Story = {
|
|
66
|
+
args: { disabled: false },
|
|
67
|
+
render: (args) => ({
|
|
68
|
+
props: args,
|
|
69
|
+
template: `<button hlmBtn ${argsToTemplate(args)}>Button</button>`,
|
|
70
|
+
}),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
@Component({
|
|
74
|
+
selector: 'button-variants',
|
|
75
|
+
imports: [HlmButtonImports],
|
|
76
|
+
template: `
|
|
77
|
+
<div class="flex flex-wrap items-center gap-3">
|
|
78
|
+
@for (variant of buttonContract.props.variants; track variant) {
|
|
79
|
+
<button hlmBtn [variant]="variant" [title]="buttonContract.docs.variants[variant]">
|
|
80
|
+
{{ variant.charAt(0).toUpperCase() + variant.slice(1) }}
|
|
81
|
+
</button>
|
|
82
|
+
}
|
|
83
|
+
</div>
|
|
84
|
+
`,
|
|
85
|
+
})
|
|
86
|
+
class ButtonVariants {
|
|
87
|
+
@Input() buttonContract!: typeof buttonContract;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Every visual variant side by side. */
|
|
91
|
+
export const Variants: Story = {
|
|
92
|
+
render: () => ({
|
|
93
|
+
moduleMetadata: {
|
|
94
|
+
imports: [ButtonVariants],
|
|
95
|
+
},
|
|
96
|
+
props: { buttonContract: buttonContract },
|
|
97
|
+
template: '<button-variants [buttonContract]="buttonContract"></button-variants>',
|
|
98
|
+
}),
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/** Text sizes from extra-small to large. */
|
|
102
|
+
export const Sizes: Story = {
|
|
103
|
+
render: () => ({
|
|
104
|
+
template: `
|
|
105
|
+
<div class="flex flex-wrap items-center gap-3">
|
|
106
|
+
<button hlmBtn size="xs">Extra small</button>
|
|
107
|
+
<button hlmBtn size="sm">Small</button>
|
|
108
|
+
<button hlmBtn size="default">Default</button>
|
|
109
|
+
<button hlmBtn size="lg">Large</button>
|
|
110
|
+
</div>`,
|
|
111
|
+
}),
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Square icon-only sizes. Drop a Phosphor icon (`@ng-icons/phosphor-icons/regular`) inside the button —
|
|
116
|
+
* the button's CSS auto-sizes the SVG per size, so no `size-*` class is needed.
|
|
117
|
+
*/
|
|
118
|
+
export const IconSizes: Story = {
|
|
119
|
+
render: () => ({
|
|
120
|
+
template: `
|
|
121
|
+
<div class="flex flex-wrap items-center gap-3">
|
|
122
|
+
<button hlmBtn size="icon-xs" aria-label="Add"><ng-icon name="phosphorPlus" /></button>
|
|
123
|
+
<button hlmBtn size="icon-sm" aria-label="Add"><ng-icon name="phosphorPlus" /></button>
|
|
124
|
+
<button hlmBtn size="icon" aria-label="Add"><ng-icon name="phosphorPlus" /></button>
|
|
125
|
+
<button hlmBtn size="icon-lg" aria-label="Add"><ng-icon name="phosphorPlus" /></button>
|
|
126
|
+
</div>`,
|
|
127
|
+
}),
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Icons alongside text. Tag the icon with `data-icon="inline-start"` or
|
|
132
|
+
* `data-icon="inline-end"` so the button tightens the padding on that side.
|
|
133
|
+
*/
|
|
134
|
+
export const WithIcon: Story = {
|
|
135
|
+
render: () => ({
|
|
136
|
+
template: `
|
|
137
|
+
<div class="flex flex-wrap items-center gap-3">
|
|
138
|
+
<button hlmBtn>
|
|
139
|
+
<ng-icon name="phosphorPlus" data-icon="inline-start" />
|
|
140
|
+
Add item
|
|
141
|
+
</button>
|
|
142
|
+
<button hlmBtn variant="secondary">
|
|
143
|
+
Continue
|
|
144
|
+
<ng-icon name="phosphorArrowRight" data-icon="inline-end" />
|
|
145
|
+
</button>
|
|
146
|
+
</div>`,
|
|
147
|
+
}),
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/** Disabled state across the main variants. */
|
|
151
|
+
export const Disabled: Story = {
|
|
152
|
+
render: () => ({
|
|
153
|
+
template: `
|
|
154
|
+
<div class="flex flex-wrap items-center gap-3">
|
|
155
|
+
<button hlmBtn disabled>Default</button>
|
|
156
|
+
<button hlmBtn variant="outline" disabled>Outline</button>
|
|
157
|
+
<button hlmBtn variant="destructive" disabled>Destructive</button>
|
|
158
|
+
</div>`,
|
|
159
|
+
}),
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Base UI's polymorphic `render` prop swaps the underlying element while keeping
|
|
164
|
+
* the button styling — here the button renders as an anchor.
|
|
165
|
+
*/
|
|
166
|
+
export const AsLink: Story = {
|
|
167
|
+
render: () => ({
|
|
168
|
+
template: `<a hlmBtn variant="link" href="https://www.surf.nl">Visit SURF</a>`,
|
|
169
|
+
}),
|
|
170
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { InjectionToken, type ValueProvider, inject } from '@angular/core';
|
|
2
|
+
import type { ButtonVariants } from './hlm-button';
|
|
3
|
+
|
|
4
|
+
export interface BrnButtonConfig {
|
|
5
|
+
variant: ButtonVariants['variant'];
|
|
6
|
+
size: ButtonVariants['size'];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const defaultConfig: BrnButtonConfig = {
|
|
10
|
+
variant: 'default',
|
|
11
|
+
size: 'default',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const BrnButtonConfigToken = new InjectionToken<BrnButtonConfig>('BrnButtonConfig');
|
|
15
|
+
|
|
16
|
+
export function provideBrnButtonConfig(config: Partial<BrnButtonConfig>): ValueProvider {
|
|
17
|
+
return { provide: BrnButtonConfigToken, useValue: { ...defaultConfig, ...config } };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function injectBrnButtonConfig(): BrnButtonConfig {
|
|
21
|
+
return inject(BrnButtonConfigToken, { optional: true }) ?? defaultConfig;
|
|
22
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Directive, input, signal } from '@angular/core';
|
|
2
|
+
import { BrnButton } from '@spartan-ng/brain/button';
|
|
3
|
+
import { classes } from '../../../utils/src';
|
|
4
|
+
import type { ButtonSizeName, ButtonVariantName } from '@surfnet/curve-contracts';
|
|
5
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
6
|
+
import type { ClassValue } from 'clsx';
|
|
7
|
+
import { injectBrnButtonConfig } from './hlm-button.token';
|
|
8
|
+
|
|
9
|
+
const variantClasses = {
|
|
10
|
+
default: 'bg-primary text-primary-foreground hover:bg-primary/80',
|
|
11
|
+
outline:
|
|
12
|
+
'border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground shadow-xs',
|
|
13
|
+
secondary:
|
|
14
|
+
'bg-secondary text-secondary-foreground aria-expanded:bg-secondary aria-expanded:text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)]',
|
|
15
|
+
ghost:
|
|
16
|
+
'hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground',
|
|
17
|
+
destructive:
|
|
18
|
+
'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',
|
|
19
|
+
link: 'text-link underline-offset-4 hover:underline',
|
|
20
|
+
} satisfies Record<ButtonVariantName, string>;
|
|
21
|
+
|
|
22
|
+
const sizeClasses = {
|
|
23
|
+
default:
|
|
24
|
+
'h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
|
|
25
|
+
xs: "h-6 gap-1 rounded-[min(var(--radius-md),8px)] px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_ng-icon:not([class*='text-'])]:text-[calc(var(--spacing)*3)]",
|
|
26
|
+
sm: 'h-8 gap-1 rounded-[min(var(--radius-md),10px)] px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5',
|
|
27
|
+
lg: 'h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
|
|
28
|
+
icon: 'size-9',
|
|
29
|
+
'icon-xs':
|
|
30
|
+
"size-6 rounded-[min(var(--radius-md),8px)] in-data-[slot=button-group]:rounded-md [&_ng-icon:not([class*='text-'])]:text-[calc(var(--spacing)*3)]",
|
|
31
|
+
'icon-sm': 'size-8 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-md',
|
|
32
|
+
'icon-lg': 'size-10',
|
|
33
|
+
} satisfies Record<ButtonSizeName, string>;
|
|
34
|
+
|
|
35
|
+
export const buttonVariants = cva(
|
|
36
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 data-[matches-spartan-invalid=true]:ring-destructive/20 dark:data-[matches-spartan-invalid=true]:ring-destructive/40 data-[matches-spartan-invalid=true]:border-destructive dark:data-[matches-spartan-invalid=true]:border-destructive/50 rounded-md border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-3 active:not-aria-[haspopup]:translate-y-px data-[matches-spartan-invalid=true]:ring-3 [&_ng-icon:not([class*='text-'])]:text-[calc(var(--spacing)*4)] group/button inline-flex shrink-0 items-center justify-center whitespace-nowrap transition-all outline-none select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_ng-icon]:pointer-events-none [&_ng-icon]:shrink-0",
|
|
37
|
+
{
|
|
38
|
+
variants: {
|
|
39
|
+
variant: variantClasses,
|
|
40
|
+
size: sizeClasses,
|
|
41
|
+
},
|
|
42
|
+
defaultVariants: {
|
|
43
|
+
variant: 'default',
|
|
44
|
+
size: 'default',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
export type ButtonVariants = VariantProps<typeof buttonVariants>;
|
|
50
|
+
|
|
51
|
+
@Directive({
|
|
52
|
+
selector: 'button[hlmBtn], a[hlmBtn]',
|
|
53
|
+
exportAs: 'hlmBtn',
|
|
54
|
+
hostDirectives: [{ directive: BrnButton, inputs: ['disabled'] }],
|
|
55
|
+
host: { 'data-slot': 'button' },
|
|
56
|
+
})
|
|
57
|
+
export class HlmButton {
|
|
58
|
+
private readonly _config = injectBrnButtonConfig();
|
|
59
|
+
|
|
60
|
+
private readonly _additionalClasses = signal<ClassValue>('');
|
|
61
|
+
|
|
62
|
+
public readonly variant = input<ButtonVariants['variant']>(this._config.variant);
|
|
63
|
+
|
|
64
|
+
public readonly size = input<ButtonVariants['size']>(this._config.size);
|
|
65
|
+
|
|
66
|
+
constructor() {
|
|
67
|
+
classes(() => [
|
|
68
|
+
buttonVariants({ variant: this.variant(), size: this.size() }),
|
|
69
|
+
this._additionalClasses(),
|
|
70
|
+
]);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
setClass(classes: string): void {
|
|
74
|
+
this._additionalClasses.set(classes);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { HlmCard } from './lib/hlm-card';
|
|
2
|
+
import { HlmCardAction } from './lib/hlm-card-action';
|
|
3
|
+
import { HlmCardContent } from './lib/hlm-card-content';
|
|
4
|
+
import { HlmCardDescription } from './lib/hlm-card-description';
|
|
5
|
+
import { HlmCardFooter } from './lib/hlm-card-footer';
|
|
6
|
+
import { HlmCardHeader } from './lib/hlm-card-header';
|
|
7
|
+
import { HlmCardTitle } from './lib/hlm-card-title';
|
|
8
|
+
|
|
9
|
+
export * from './lib/hlm-card';
|
|
10
|
+
export * from './lib/hlm-card-action';
|
|
11
|
+
export * from './lib/hlm-card-content';
|
|
12
|
+
export * from './lib/hlm-card-description';
|
|
13
|
+
export * from './lib/hlm-card-footer';
|
|
14
|
+
export * from './lib/hlm-card-header';
|
|
15
|
+
export * from './lib/hlm-card-title';
|
|
16
|
+
|
|
17
|
+
export const HlmCardImports = [
|
|
18
|
+
HlmCard,
|
|
19
|
+
HlmCardAction,
|
|
20
|
+
HlmCardContent,
|
|
21
|
+
HlmCardDescription,
|
|
22
|
+
HlmCardFooter,
|
|
23
|
+
HlmCardHeader,
|
|
24
|
+
HlmCardTitle,
|
|
25
|
+
] as const;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Directive } from '@angular/core';
|
|
2
|
+
import { classes } from '../../../utils/src';
|
|
3
|
+
|
|
4
|
+
@Directive({
|
|
5
|
+
selector: '[hlmCardAction]',
|
|
6
|
+
host: { 'data-slot': 'card-action' },
|
|
7
|
+
})
|
|
8
|
+
export class HlmCardAction {
|
|
9
|
+
constructor() {
|
|
10
|
+
classes(() => 'col-start-2 row-span-2 row-start-1 self-start justify-self-end');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Directive } from '@angular/core';
|
|
2
|
+
import { classes } from '../../../utils/src';
|
|
3
|
+
|
|
4
|
+
@Directive({
|
|
5
|
+
selector: '[hlmCardContent]',
|
|
6
|
+
host: { 'data-slot': 'card-content' },
|
|
7
|
+
})
|
|
8
|
+
export class HlmCardContent {
|
|
9
|
+
constructor() {
|
|
10
|
+
classes(() => 'px-(--card-spacing)');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Directive } from '@angular/core';
|
|
2
|
+
import { classes } from '../../../utils/src';
|
|
3
|
+
|
|
4
|
+
@Directive({
|
|
5
|
+
selector: '[hlmCardDescription]',
|
|
6
|
+
host: { 'data-slot': 'card-description' },
|
|
7
|
+
})
|
|
8
|
+
export class HlmCardDescription {
|
|
9
|
+
constructor() {
|
|
10
|
+
classes(() => 'text-muted-foreground text-sm');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Directive } from '@angular/core';
|
|
2
|
+
import { classes } from '../../../utils/src';
|
|
3
|
+
|
|
4
|
+
@Directive({
|
|
5
|
+
selector: '[hlmCardFooter],hlm-card-footer',
|
|
6
|
+
host: { 'data-slot': 'card-footer' },
|
|
7
|
+
})
|
|
8
|
+
export class HlmCardFooter {
|
|
9
|
+
constructor() {
|
|
10
|
+
classes(
|
|
11
|
+
() => 'rounded-b-xl px-(--card-spacing) [.border-t]:pt-(--card-spacing) flex items-center',
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Directive } from '@angular/core';
|
|
2
|
+
import { classes } from '../../../utils/src';
|
|
3
|
+
|
|
4
|
+
@Directive({
|
|
5
|
+
selector: '[hlmCardHeader],hlm-card-header',
|
|
6
|
+
host: { 'data-slot': 'card-header' },
|
|
7
|
+
})
|
|
8
|
+
export class HlmCardHeader {
|
|
9
|
+
constructor() {
|
|
10
|
+
classes(
|
|
11
|
+
() =>
|
|
12
|
+
'gap-1 rounded-t-xl px-(--card-spacing) [.border-b]:pb-(--card-spacing) group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]',
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Directive } from '@angular/core';
|
|
2
|
+
import { classes } from '../../../utils/src';
|
|
3
|
+
|
|
4
|
+
@Directive({
|
|
5
|
+
selector: '[hlmCardTitle]',
|
|
6
|
+
host: { 'data-slot': 'card-title' },
|
|
7
|
+
})
|
|
8
|
+
export class HlmCardTitle {
|
|
9
|
+
constructor() {
|
|
10
|
+
classes(() => 'text-base leading-normal font-medium group-data-[size=sm]/card:text-sm');
|
|
11
|
+
}
|
|
12
|
+
}
|