@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,129 @@
|
|
|
1
|
+
import { Directive } from '@angular/core';
|
|
2
|
+
import { classes } from '../../../utils/src';
|
|
3
|
+
|
|
4
|
+
@Directive({
|
|
5
|
+
selector: 'div[hlmTableContainer]',
|
|
6
|
+
host: { 'data-slot': 'table-container' },
|
|
7
|
+
})
|
|
8
|
+
export class HlmTableContainer {
|
|
9
|
+
constructor() {
|
|
10
|
+
classes(() => 'relative w-full overflow-x-auto');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Directive to apply Shadcn-like styling to a <table> element.
|
|
16
|
+
*/
|
|
17
|
+
@Directive({
|
|
18
|
+
selector: 'table[hlmTable]',
|
|
19
|
+
host: { 'data-slot': 'table' },
|
|
20
|
+
})
|
|
21
|
+
export class HlmTable {
|
|
22
|
+
constructor() {
|
|
23
|
+
classes(() => 'w-full caption-bottom text-sm');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Directive to apply Shadcn-like styling to a <thead> element
|
|
29
|
+
* within an HlmTable context.
|
|
30
|
+
*/
|
|
31
|
+
@Directive({
|
|
32
|
+
selector: 'thead[hlmTHead],thead[hlmTableHeader]',
|
|
33
|
+
host: { 'data-slot': 'table-header' },
|
|
34
|
+
})
|
|
35
|
+
export class HlmTHead {
|
|
36
|
+
constructor() {
|
|
37
|
+
classes(() => '[&_tr]:border-b');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Directive to apply Shadcn-like styling to a <tbody> element
|
|
43
|
+
* within an HlmTable context.
|
|
44
|
+
*/
|
|
45
|
+
@Directive({
|
|
46
|
+
selector: 'tbody[hlmTBody],tbody[hlmTableBody]',
|
|
47
|
+
host: { 'data-slot': 'table-body' },
|
|
48
|
+
})
|
|
49
|
+
export class HlmTBody {
|
|
50
|
+
constructor() {
|
|
51
|
+
classes(() => '[&_tr:last-child]:border-0');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Directive to apply Shadcn-like styling to a <tfoot> element
|
|
57
|
+
* within an HlmTable context.
|
|
58
|
+
*/
|
|
59
|
+
@Directive({
|
|
60
|
+
selector: 'tfoot[hlmTFoot],tfoot[hlmTableFooter]',
|
|
61
|
+
host: { 'data-slot': 'table-footer' },
|
|
62
|
+
})
|
|
63
|
+
export class HlmTFoot {
|
|
64
|
+
constructor() {
|
|
65
|
+
classes(() => 'bg-muted/50 border-t font-medium [&>tr]:last:border-b-0');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Directive to apply Shadcn-like styling to a <tr> element
|
|
71
|
+
* within an HlmTable context.
|
|
72
|
+
*/
|
|
73
|
+
@Directive({
|
|
74
|
+
selector: 'tr[hlmTr],tr[hlmTableRow]',
|
|
75
|
+
host: { 'data-slot': 'table-row' },
|
|
76
|
+
})
|
|
77
|
+
export class HlmTr {
|
|
78
|
+
constructor() {
|
|
79
|
+
classes(
|
|
80
|
+
() =>
|
|
81
|
+
'hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors has-aria-expanded:bg-muted/50',
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Directive to apply Shadcn-like styling to a <th> element
|
|
88
|
+
* within an HlmTable context.
|
|
89
|
+
*/
|
|
90
|
+
@Directive({
|
|
91
|
+
selector: 'th[hlmTh],th[hlmTableHead]',
|
|
92
|
+
host: { 'data-slot': 'table-head' },
|
|
93
|
+
})
|
|
94
|
+
export class HlmTh {
|
|
95
|
+
constructor() {
|
|
96
|
+
classes(
|
|
97
|
+
() =>
|
|
98
|
+
'text-foreground h-10 px-2 text-start align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pe-0',
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Directive to apply Shadcn-like styling to a <td> element
|
|
105
|
+
* within an HlmTable context.
|
|
106
|
+
*/
|
|
107
|
+
@Directive({
|
|
108
|
+
selector: 'td[hlmTd],td[hlmTableCell]',
|
|
109
|
+
host: { 'data-slot': 'table-cell' },
|
|
110
|
+
})
|
|
111
|
+
export class HlmTd {
|
|
112
|
+
constructor() {
|
|
113
|
+
classes(() => 'p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pe-0');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Directive to apply Shadcn-like styling to a <caption> element
|
|
119
|
+
* within an HlmTable context.
|
|
120
|
+
*/
|
|
121
|
+
@Directive({
|
|
122
|
+
selector: 'caption[hlmCaption],caption[hlmTableCaption]',
|
|
123
|
+
host: { 'data-slot': 'table-caption' },
|
|
124
|
+
})
|
|
125
|
+
export class HlmCaption {
|
|
126
|
+
constructor() {
|
|
127
|
+
classes(() => 'text-muted-foreground mt-4 text-sm');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/angular';
|
|
2
|
+
import { argsToTemplate, moduleMetadata } from '@storybook/angular';
|
|
3
|
+
import { HlmTextarea, HlmTextareaImports } from '..';
|
|
4
|
+
import { textareaContract } from '@surfnet/curve-contracts';
|
|
5
|
+
import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<HlmTextarea> = {
|
|
8
|
+
title: 'Components/Textarea',
|
|
9
|
+
component: HlmTextarea,
|
|
10
|
+
decorators: [
|
|
11
|
+
moduleMetadata({
|
|
12
|
+
imports: [HlmTextareaImports, ReactiveFormsModule],
|
|
13
|
+
}),
|
|
14
|
+
],
|
|
15
|
+
parameters: {
|
|
16
|
+
docs: {
|
|
17
|
+
description: {
|
|
18
|
+
component: textareaContract.docs.description,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
argTypes: {
|
|
23
|
+
placeholder: { control: 'text' },
|
|
24
|
+
disabled: { control: 'boolean' },
|
|
25
|
+
},
|
|
26
|
+
args: {
|
|
27
|
+
placeholder: 'Type something…',
|
|
28
|
+
disabled: false,
|
|
29
|
+
},
|
|
30
|
+
} as Meta<HlmTextarea>;
|
|
31
|
+
|
|
32
|
+
export default meta;
|
|
33
|
+
type Story = StoryObj<HlmTextarea>;
|
|
34
|
+
|
|
35
|
+
/** Default textarea — auto-sizes to content. */
|
|
36
|
+
export const Default: Story = {
|
|
37
|
+
render: (args) => ({
|
|
38
|
+
props: args,
|
|
39
|
+
template: `
|
|
40
|
+
<textarea hlmTextarea ${argsToTemplate(args)}></textarea>
|
|
41
|
+
`,
|
|
42
|
+
}),
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/** Disabled state. */
|
|
46
|
+
export const Disabled: Story = {
|
|
47
|
+
render: (args) => ({
|
|
48
|
+
props: { ...args, disabled: true, placeholder: 'Cannot type here' },
|
|
49
|
+
template: `
|
|
50
|
+
<textarea hlmTextarea ${argsToTemplate(args)}></textarea>
|
|
51
|
+
`,
|
|
52
|
+
}),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/** Invalid state (e.g. after failed form validation). Touch the field to test the minimum of 8 characters. */
|
|
56
|
+
export const Invalid: Story = {
|
|
57
|
+
render: () => ({
|
|
58
|
+
props: {
|
|
59
|
+
placeholder: 'This field has an error',
|
|
60
|
+
form: new FormGroup({
|
|
61
|
+
test: new FormControl('', { validators: [Validators.required, Validators.minLength(8)] }),
|
|
62
|
+
}),
|
|
63
|
+
},
|
|
64
|
+
template: `
|
|
65
|
+
<form [formGroup]="form" class="w-full max-w-md">
|
|
66
|
+
<div hlmField>
|
|
67
|
+
<textarea hlmTextarea formControlName="test" [placeholder]="placeholder"></textarea>
|
|
68
|
+
</div>
|
|
69
|
+
</form>
|
|
70
|
+
`,
|
|
71
|
+
}),
|
|
72
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Directive } from '@angular/core';
|
|
2
|
+
import { BrnFieldControlDescribedBy } from '@spartan-ng/brain/field';
|
|
3
|
+
import { BrnTextarea } from '@spartan-ng/brain/textarea';
|
|
4
|
+
import { classes } from '../../../utils/src';
|
|
5
|
+
|
|
6
|
+
@Directive({
|
|
7
|
+
selector: '[hlmTextarea]',
|
|
8
|
+
hostDirectives: [
|
|
9
|
+
{ directive: BrnTextarea, inputs: ['id', 'forceInvalid'] },
|
|
10
|
+
BrnFieldControlDescribedBy,
|
|
11
|
+
],
|
|
12
|
+
host: { 'data-slot': 'textarea' },
|
|
13
|
+
})
|
|
14
|
+
export class HlmTextarea {
|
|
15
|
+
constructor() {
|
|
16
|
+
classes(
|
|
17
|
+
() =>
|
|
18
|
+
'border-input dark:bg-input/30 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 bg-transparent px-2.5 py-2 text-base shadow-xs transition-[color,box-shadow] focus-visible:ring-3 data-[matches-spartan-invalid=true]:ring-3 md:text-sm placeholder:text-muted-foreground flex field-sizing-content min-h-16 w-full outline-none disabled:cursor-not-allowed disabled:opacity-50',
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Directive } from '@angular/core';
|
|
2
|
+
import {
|
|
3
|
+
BrnTooltip,
|
|
4
|
+
BrnTooltipPosition,
|
|
5
|
+
provideBrnTooltipDefaultOptions,
|
|
6
|
+
} from '@spartan-ng/brain/tooltip';
|
|
7
|
+
import { hlm } from '../../../utils/src';
|
|
8
|
+
import { cva } from 'class-variance-authority';
|
|
9
|
+
|
|
10
|
+
export const DEFAULT_TOOLTIP_SVG_CLASS =
|
|
11
|
+
'bg-foreground fill-foreground z-50 block size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px]';
|
|
12
|
+
|
|
13
|
+
export const DEFAULT_TOOLTIP_CONTENT_CLASSES = hlm(
|
|
14
|
+
'data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 rounded-md px-3 py-1.5 text-xs bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) text-balance',
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
export const tooltipPositionVariants = cva('absolute', {
|
|
18
|
+
variants: {
|
|
19
|
+
position: {
|
|
20
|
+
top: 'bottom-0 left-[calc(50%-5px)] translate-y-full',
|
|
21
|
+
bottom: '-top-2.5 left-[calc(50%-5px)] translate-y-0 rotate-180',
|
|
22
|
+
left: '-end-2.5 top-[calc(50%-5px)] translate-y-0 rotate-270 rtl:-rotate-270',
|
|
23
|
+
right: '-start-2.5 top-[calc(50%-5px)] translate-y-0 rotate-90 rtl:-rotate-90',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
@Directive({
|
|
29
|
+
selector: '[hlmTooltip]',
|
|
30
|
+
providers: [
|
|
31
|
+
provideBrnTooltipDefaultOptions({
|
|
32
|
+
svgClasses: DEFAULT_TOOLTIP_SVG_CLASS,
|
|
33
|
+
tooltipContentClasses: DEFAULT_TOOLTIP_CONTENT_CLASSES,
|
|
34
|
+
arrowClasses: (position: BrnTooltipPosition) => hlm(tooltipPositionVariants({ position })),
|
|
35
|
+
}),
|
|
36
|
+
],
|
|
37
|
+
hostDirectives: [
|
|
38
|
+
{
|
|
39
|
+
directive: BrnTooltip,
|
|
40
|
+
inputs: ['brnTooltip: hlmTooltip', 'position', 'hideDelay', 'showDelay', 'tooltipDisabled'],
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
})
|
|
44
|
+
export class HlmTooltip {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './lib/hlm';
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
2
|
+
import {
|
|
3
|
+
DestroyRef,
|
|
4
|
+
effect,
|
|
5
|
+
ElementRef,
|
|
6
|
+
HostAttributeToken,
|
|
7
|
+
inject,
|
|
8
|
+
Injector,
|
|
9
|
+
PLATFORM_ID,
|
|
10
|
+
runInInjectionContext,
|
|
11
|
+
} from '@angular/core';
|
|
12
|
+
import { type ClassValue, clsx } from 'clsx';
|
|
13
|
+
import { twMerge } from 'tailwind-merge';
|
|
14
|
+
|
|
15
|
+
export function hlm(...inputs: ClassValue[]) {
|
|
16
|
+
return twMerge(clsx(inputs));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Global map to track class managers per element
|
|
20
|
+
const elementClassManagers = new WeakMap<HTMLElement, ElementClassManager>();
|
|
21
|
+
// Global mutation observer for all elements
|
|
22
|
+
let globalObserver: MutationObserver | null = null;
|
|
23
|
+
const observedElements = new Set<HTMLElement>();
|
|
24
|
+
|
|
25
|
+
interface ElementClassManager {
|
|
26
|
+
element: HTMLElement;
|
|
27
|
+
sources: Map<number, { classes: Set<string>; order: number }>;
|
|
28
|
+
baseClasses: Set<string>;
|
|
29
|
+
isUpdating: boolean;
|
|
30
|
+
nextOrder: number;
|
|
31
|
+
hasInitialized: boolean;
|
|
32
|
+
restoreRafId: number | null;
|
|
33
|
+
/** Transitions are suppressed until the first effect writes correct classes */
|
|
34
|
+
transitionsSuppressed: boolean;
|
|
35
|
+
/** Original inline transition value to restore after suppression (empty string = none was set) */
|
|
36
|
+
previousTransition: string;
|
|
37
|
+
/** Original inline transition priority to preserve !important when restoring */
|
|
38
|
+
previousTransitionPriority: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let sourceCounter = 0;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* This function dynamically adds and removes classes for a given element without requiring
|
|
45
|
+
* the a class binding (e.g. `[class]="..."`) which may interfere with other class bindings.
|
|
46
|
+
*
|
|
47
|
+
* 1. This will merge the existing classes on the element with the new classes.
|
|
48
|
+
* 2. It will also remove any classes that were previously added by this function but are no longer present in the new classes.
|
|
49
|
+
* 3. Multiple calls to this function on the same element will be merged efficiently.
|
|
50
|
+
*/
|
|
51
|
+
export function classes(computed: () => ClassValue[] | string, options: ClassesOptions = {}) {
|
|
52
|
+
runInInjectionContext(options.injector ?? inject(Injector), () => {
|
|
53
|
+
const elementRef = options.elementRef ?? inject(ElementRef);
|
|
54
|
+
const platformId = inject(PLATFORM_ID);
|
|
55
|
+
const destroyRef = inject(DestroyRef);
|
|
56
|
+
const baseClasses = inject(new HostAttributeToken('class'), { optional: true });
|
|
57
|
+
|
|
58
|
+
const element = elementRef.nativeElement;
|
|
59
|
+
|
|
60
|
+
// Create unique identifier for this source
|
|
61
|
+
const sourceId = sourceCounter++;
|
|
62
|
+
|
|
63
|
+
// Get or create the class manager for this element
|
|
64
|
+
let manager = elementClassManagers.get(element);
|
|
65
|
+
|
|
66
|
+
if (!manager) {
|
|
67
|
+
// Initialize base classes from variation (host attribute 'class')
|
|
68
|
+
const initialBaseClasses = new Set<string>();
|
|
69
|
+
|
|
70
|
+
if (baseClasses) {
|
|
71
|
+
toClassList(baseClasses).forEach((cls) => initialBaseClasses.add(cls));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
manager = {
|
|
75
|
+
element,
|
|
76
|
+
sources: new Map(),
|
|
77
|
+
baseClasses: initialBaseClasses,
|
|
78
|
+
isUpdating: false,
|
|
79
|
+
nextOrder: 0,
|
|
80
|
+
hasInitialized: false,
|
|
81
|
+
restoreRafId: null,
|
|
82
|
+
transitionsSuppressed: false,
|
|
83
|
+
previousTransition: '',
|
|
84
|
+
previousTransitionPriority: '',
|
|
85
|
+
};
|
|
86
|
+
elementClassManagers.set(element, manager);
|
|
87
|
+
|
|
88
|
+
// Setup global observer if needed and register this element
|
|
89
|
+
setupGlobalObserver(platformId);
|
|
90
|
+
observedElements.add(element);
|
|
91
|
+
|
|
92
|
+
// Suppress transitions until the first effect writes correct classes and
|
|
93
|
+
// the browser has painted them. This prevents CSS transition animations
|
|
94
|
+
// during hydration when classes change from SSR state to client state.
|
|
95
|
+
if (isPlatformBrowser(platformId)) {
|
|
96
|
+
manager.previousTransition = element.style.getPropertyValue('transition');
|
|
97
|
+
manager.previousTransitionPriority = element.style.getPropertyPriority('transition');
|
|
98
|
+
element.style.setProperty('transition', 'none', 'important');
|
|
99
|
+
manager.transitionsSuppressed = true;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Assign order once at registration time
|
|
104
|
+
const sourceOrder = manager.nextOrder++;
|
|
105
|
+
|
|
106
|
+
function updateClasses(): void {
|
|
107
|
+
// Get the new classes from the computed function
|
|
108
|
+
const newClasses = toClassList(computed());
|
|
109
|
+
|
|
110
|
+
// Update this source's classes, keeping the original order
|
|
111
|
+
manager!.sources.set(sourceId, {
|
|
112
|
+
classes: new Set(newClasses),
|
|
113
|
+
order: sourceOrder,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Update the element
|
|
117
|
+
updateElement(manager!);
|
|
118
|
+
|
|
119
|
+
// Re-enable transitions after the first effect writes correct classes.
|
|
120
|
+
// Deferred to next animation frame so the browser paints the class change
|
|
121
|
+
// with transitions disabled first, then re-enables them.
|
|
122
|
+
if (manager!.transitionsSuppressed) {
|
|
123
|
+
manager!.transitionsSuppressed = false;
|
|
124
|
+
manager!.restoreRafId = requestAnimationFrame(() => {
|
|
125
|
+
manager!.restoreRafId = null;
|
|
126
|
+
restoreTransitionSuppression(manager!);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Register cleanup with DestroyRef
|
|
132
|
+
destroyRef.onDestroy(() => {
|
|
133
|
+
if (manager!.restoreRafId !== null) {
|
|
134
|
+
cancelAnimationFrame(manager!.restoreRafId);
|
|
135
|
+
manager!.restoreRafId = null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (manager!.transitionsSuppressed) {
|
|
139
|
+
manager!.transitionsSuppressed = false;
|
|
140
|
+
restoreTransitionSuppression(manager!);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Remove this source from the manager
|
|
144
|
+
manager!.sources.delete(sourceId);
|
|
145
|
+
|
|
146
|
+
// If no more sources, clean up the manager
|
|
147
|
+
if (manager!.sources.size === 0) {
|
|
148
|
+
cleanupManager(element);
|
|
149
|
+
} else {
|
|
150
|
+
// Update element without this source's classes
|
|
151
|
+
updateElement(manager!);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* We need this effect to track changes to the computed classes. Ideally, we would use
|
|
157
|
+
* afterRenderEffect here, but that doesn't run in SSR contexts, so we use a standard
|
|
158
|
+
* effect which works in both browser and SSR.
|
|
159
|
+
*/
|
|
160
|
+
effect(updateClasses);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function restoreTransitionSuppression(manager: ElementClassManager): void {
|
|
165
|
+
const prev = manager.previousTransition;
|
|
166
|
+
if (prev) {
|
|
167
|
+
manager.element.style.setProperty(
|
|
168
|
+
'transition',
|
|
169
|
+
prev,
|
|
170
|
+
manager.previousTransitionPriority || undefined,
|
|
171
|
+
);
|
|
172
|
+
} else {
|
|
173
|
+
manager.element.style.removeProperty('transition');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// eslint-disable-next-line @typescript-eslint/no-wrapper-object-types
|
|
178
|
+
function setupGlobalObserver(platformId: Object): void {
|
|
179
|
+
if (isPlatformBrowser(platformId) && !globalObserver) {
|
|
180
|
+
// Create single global observer that watches the entire document
|
|
181
|
+
globalObserver = new MutationObserver((mutations) => {
|
|
182
|
+
for (const mutation of mutations) {
|
|
183
|
+
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
|
|
184
|
+
const element = mutation.target as HTMLElement;
|
|
185
|
+
const manager = elementClassManagers.get(element);
|
|
186
|
+
|
|
187
|
+
// Only process elements we're managing
|
|
188
|
+
if (manager && observedElements.has(element)) {
|
|
189
|
+
if (manager.isUpdating) continue; // Ignore changes we're making
|
|
190
|
+
|
|
191
|
+
// Update base classes to include any externally added classes
|
|
192
|
+
const currentClasses = toClassList(element.className);
|
|
193
|
+
const allSourceClasses = new Set<string>();
|
|
194
|
+
|
|
195
|
+
// Collect all classes from all sources
|
|
196
|
+
for (const source of manager.sources.values()) {
|
|
197
|
+
for (const className of source.classes) {
|
|
198
|
+
allSourceClasses.add(className);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Any classes not from sources become new base classes
|
|
203
|
+
manager.baseClasses.clear();
|
|
204
|
+
|
|
205
|
+
for (const className of currentClasses) {
|
|
206
|
+
if (!allSourceClasses.has(className)) {
|
|
207
|
+
manager.baseClasses.add(className);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
updateElement(manager);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Start observing the entire document for class attribute changes
|
|
218
|
+
globalObserver.observe(document, {
|
|
219
|
+
attributes: true,
|
|
220
|
+
attributeFilter: ['class'],
|
|
221
|
+
subtree: true, // Watch all descendants
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function updateElement(manager: ElementClassManager): void {
|
|
227
|
+
if (manager.isUpdating) return; // Prevent recursive updates
|
|
228
|
+
|
|
229
|
+
manager.isUpdating = true;
|
|
230
|
+
|
|
231
|
+
// Handle initialization: capture base classes after first source registration
|
|
232
|
+
if (!manager.hasInitialized && manager.sources.size > 0) {
|
|
233
|
+
// Get current classes on element (may include SSR classes)
|
|
234
|
+
const currentClasses = toClassList(manager.element.className);
|
|
235
|
+
|
|
236
|
+
// Get all classes that will be applied by sources
|
|
237
|
+
const allSourceClasses = new Set<string>();
|
|
238
|
+
for (const source of manager.sources.values()) {
|
|
239
|
+
source.classes.forEach((className) => allSourceClasses.add(className));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Only consider classes as "base" if they're not produced by any source
|
|
243
|
+
// This prevents SSR-rendered classes from being preserved as base classes
|
|
244
|
+
currentClasses.forEach((className) => {
|
|
245
|
+
if (!allSourceClasses.has(className)) {
|
|
246
|
+
manager.baseClasses.add(className);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
manager.hasInitialized = true;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Get classes from all sources, sorted by registration order (later takes precedence)
|
|
254
|
+
const sortedSources = Array.from(manager.sources.entries()).sort(
|
|
255
|
+
([, a], [, b]) => a.order - b.order,
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
const allSourceClasses: string[] = [];
|
|
259
|
+
for (const [, source] of sortedSources) {
|
|
260
|
+
allSourceClasses.push(...source.classes);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Combine base classes with all source classes, ensuring base classes take precedence
|
|
264
|
+
const classesToApply =
|
|
265
|
+
allSourceClasses.length > 0 || manager.baseClasses.size > 0
|
|
266
|
+
? hlm([...allSourceClasses, ...manager.baseClasses])
|
|
267
|
+
: '';
|
|
268
|
+
|
|
269
|
+
// Apply the classes to the element
|
|
270
|
+
if (manager.element.className !== classesToApply) {
|
|
271
|
+
manager.element.className = classesToApply;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
manager.isUpdating = false;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function cleanupManager(element: HTMLElement): void {
|
|
278
|
+
// Remove from global tracking
|
|
279
|
+
observedElements.delete(element);
|
|
280
|
+
elementClassManagers.delete(element);
|
|
281
|
+
|
|
282
|
+
// If no more elements being tracked, cleanup global observer
|
|
283
|
+
if (observedElements.size === 0 && globalObserver) {
|
|
284
|
+
globalObserver.disconnect();
|
|
285
|
+
globalObserver = null;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
interface ClassesOptions {
|
|
290
|
+
elementRef?: ElementRef<HTMLElement>;
|
|
291
|
+
injector?: Injector;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Cache for parsed class lists to avoid repeated string operations
|
|
295
|
+
const classListCache = new Map<string, string[]>();
|
|
296
|
+
|
|
297
|
+
function toClassList(className: string | ClassValue[]): string[] {
|
|
298
|
+
// For simple string inputs, use cache to avoid repeated parsing
|
|
299
|
+
if (typeof className === 'string' && classListCache.has(className)) {
|
|
300
|
+
return classListCache.get(className)!;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const result = clsx(className)
|
|
304
|
+
.split(' ')
|
|
305
|
+
.filter((c) => c.length > 0);
|
|
306
|
+
|
|
307
|
+
// Cache string results, but limit cache size to prevent memory growth
|
|
308
|
+
if (typeof className === 'string' && classListCache.size < 1000) {
|
|
309
|
+
classListCache.set(className, result);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return result;
|
|
313
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Public API surface of @surfnet/curve-angular.
|
|
3
|
+
* Re-export each helm component (and the shared utils) added via the Spartan CLI.
|
|
4
|
+
* NOTE: there are a few components that we don't export: [icon, sheet, skeleton, tooltip],
|
|
5
|
+
* because these are out of scope for now. They are included in the code because the
|
|
6
|
+
* components that we do export depend on them (and they can't be consumed from a package).
|
|
7
|
+
*/
|
|
8
|
+
export * from './lib/ui/avatar/src';
|
|
9
|
+
export * from './lib/ui/breadcrumb/src';
|
|
10
|
+
export * from './lib/ui/button/src';
|
|
11
|
+
export * from './lib/ui/card/src';
|
|
12
|
+
export * from './lib/ui/checkbox/src';
|
|
13
|
+
export * from './lib/ui/data-table/src';
|
|
14
|
+
export * from './lib/ui/dropdown-menu/src';
|
|
15
|
+
export * from './lib/ui/field/src';
|
|
16
|
+
export * from './lib/ui/input/src';
|
|
17
|
+
export * from './lib/ui/input-group/src';
|
|
18
|
+
export * from './lib/ui/label/src';
|
|
19
|
+
export * from './lib/ui/select/src';
|
|
20
|
+
export * from './lib/ui/separator/src';
|
|
21
|
+
export * from './lib/ui/sidebar/src';
|
|
22
|
+
export * from './lib/ui/table/src';
|
|
23
|
+
export * from './lib/ui/textarea/src';
|
|
24
|
+
export * from './lib/ui/utils/src';
|
package/src/styles.css
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
@layer theme, base, components, utilities;
|
|
2
|
+
@import 'tailwindcss/theme.css' layer(theme);
|
|
3
|
+
@import 'tailwindcss/preflight.css' layer(base);
|
|
4
|
+
@import 'tailwindcss/utilities.css';
|
|
5
|
+
|
|
6
|
+
@import '@spartan-ng/brain/hlm-tailwind-preset.css';
|
|
7
|
+
@import '@surfnet/curve-tokens/tokens.css';
|
|
8
|
+
@import '@fontsource-variable/geist';
|
|
9
|
+
|
|
10
|
+
/* Scan the library's component sources so a standalone Tailwind build (build:css)
|
|
11
|
+
emits every utility the components reference. Path is relative to this file. */
|
|
12
|
+
@source '.';
|
|
13
|
+
/* You can add global styles to this file, and also import other style files */
|
|
14
|
+
|
|
15
|
+
/* The Spartan preset maps the standard token set to --color-* utilities but not
|
|
16
|
+
the --link token, so expose it here (matches the React package's mapping). */
|
|
17
|
+
@theme inline {
|
|
18
|
+
--color-link: var(--link);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
:root {
|
|
22
|
+
color-scheme: light;
|
|
23
|
+
|
|
24
|
+
--radius: 0.625rem;
|
|
25
|
+
|
|
26
|
+
--font-sans: 'Geist Variable', sans-serif;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
:root.dark {
|
|
30
|
+
color-scheme: dark;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@layer base {
|
|
34
|
+
* {
|
|
35
|
+
@apply border-border outline-ring/50;
|
|
36
|
+
}
|
|
37
|
+
body {
|
|
38
|
+
@apply bg-background text-foreground;
|
|
39
|
+
}
|
|
40
|
+
html {
|
|
41
|
+
@apply font-sans;
|
|
42
|
+
}
|
|
43
|
+
}
|