@kanso-protocol/table-toolbar 0.1.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.
@@ -0,0 +1,358 @@
1
+ import * as i0 from '@angular/core';
2
+ import { EventEmitter, Output, Input, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { KpButtonComponent } from '@kanso-protocol/button';
4
+ import { KpBadgeComponent } from '@kanso-protocol/badge';
5
+ import { KpIconComponent } from '@kanso-protocol/icon';
6
+ import { KpSearchBarComponent } from '@kanso-protocol/search-bar';
7
+
8
+ /**
9
+ * Kanso Protocol — TableToolbar
10
+ *
11
+ * Panel that sits above a data table. Two modes:
12
+ * - `default` — search + filter/sort + right-side actions (density, columns,
13
+ * export, create).
14
+ * - `bulk-select` — swaps to a selection summary with bulk actions
15
+ * (export / tag / move / delete).
16
+ *
17
+ * Composes SearchBar, Button, Badge. Action slots are boolean toggles so
18
+ * you can dial the toolbar from minimal ("search + create") up to a full
19
+ * admin bar without touching templates.
20
+ *
21
+ * @example
22
+ * <kp-table-toolbar
23
+ * [showFilter]="true"
24
+ * [activeFilterCount]="2"
25
+ * (createClick)="openCreate()">
26
+ * </kp-table-toolbar>
27
+ */
28
+ class KpTableToolbarComponent {
29
+ mode = 'default';
30
+ showSearch = true;
31
+ searchPlaceholder = 'Search…';
32
+ searchValue = '';
33
+ showFilter = true;
34
+ activeFilterCount = 0;
35
+ showSort = false;
36
+ showDensity = false;
37
+ density = 'comfortable';
38
+ showColumnPicker = false;
39
+ showExport = false;
40
+ showCreate = true;
41
+ createLabel = 'Create new';
42
+ selectedCount = 0;
43
+ searchChange = new EventEmitter();
44
+ filterClick = new EventEmitter();
45
+ sortClick = new EventEmitter();
46
+ densityChange = new EventEmitter();
47
+ columnsClick = new EventEmitter();
48
+ exportClick = new EventEmitter();
49
+ createClick = new EventEmitter();
50
+ clearSelection = new EventEmitter();
51
+ bulkExport = new EventEmitter();
52
+ bulkTag = new EventEmitter();
53
+ bulkMove = new EventEmitter();
54
+ bulkDelete = new EventEmitter();
55
+ get hasRightActions() {
56
+ return this.showDensity || this.showColumnPicker || this.showExport;
57
+ }
58
+ get hostClasses() {
59
+ return `kp-tt kp-tt--${this.mode}`;
60
+ }
61
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: KpTableToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
62
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: KpTableToolbarComponent, isStandalone: true, selector: "kp-table-toolbar", inputs: { mode: "mode", showSearch: "showSearch", searchPlaceholder: "searchPlaceholder", searchValue: "searchValue", showFilter: "showFilter", activeFilterCount: "activeFilterCount", showSort: "showSort", showDensity: "showDensity", density: "density", showColumnPicker: "showColumnPicker", showExport: "showExport", showCreate: "showCreate", createLabel: "createLabel", selectedCount: "selectedCount" }, outputs: { searchChange: "searchChange", filterClick: "filterClick", sortClick: "sortClick", densityChange: "densityChange", columnsClick: "columnsClick", exportClick: "exportClick", createClick: "createClick", clearSelection: "clearSelection", bulkExport: "bulkExport", bulkTag: "bulkTag", bulkMove: "bulkMove", bulkDelete: "bulkDelete" }, host: { properties: { "class": "hostClasses" } }, ngImport: i0, template: `
63
+ @if (mode === 'default') {
64
+ <div class="kp-tt__left">
65
+ @if (showSearch) {
66
+ <kp-search-bar
67
+ variant="inline"
68
+ size="sm"
69
+ [placeholder]="searchPlaceholder"
70
+ [value]="searchValue"
71
+ (valueChange)="searchChange.emit($event)"
72
+ />
73
+ }
74
+
75
+ @if (showFilter) {
76
+ <kp-button variant="outline" size="sm" (click)="filterClick.emit()">
77
+ <kp-icon kpButtonIconLeft name="filter" />
78
+ <span>Filters</span>
79
+ @if (activeFilterCount > 0) {
80
+ <kp-badge size="xs" color="primary" appearance="subtle">{{ activeFilterCount }}</kp-badge>
81
+ }
82
+ </kp-button>
83
+ }
84
+
85
+ @if (showSort) {
86
+ <kp-button variant="outline" size="sm" (click)="sortClick.emit()">
87
+ <kp-icon kpButtonIconLeft name="arrows-up-down" />
88
+ <span>Sort</span>
89
+ </kp-button>
90
+ }
91
+ </div>
92
+
93
+ <div class="kp-tt__right">
94
+ @if (showDensity) {
95
+ <div class="kp-tt__density" role="group" aria-label="Row density">
96
+ <button
97
+ type="button"
98
+ class="kp-tt__density-btn"
99
+ [class.kp-tt__density-btn--active]="density === 'compact'"
100
+ (click)="densityChange.emit('compact')"
101
+ aria-label="Compact">
102
+ <kp-icon name="layout-list" />
103
+ </button>
104
+ <button
105
+ type="button"
106
+ class="kp-tt__density-btn"
107
+ [class.kp-tt__density-btn--active]="density === 'comfortable'"
108
+ (click)="densityChange.emit('comfortable')"
109
+ aria-label="Comfortable">
110
+ <kp-icon name="layout-rows" />
111
+ </button>
112
+ <button
113
+ type="button"
114
+ class="kp-tt__density-btn"
115
+ [class.kp-tt__density-btn--active]="density === 'spacious'"
116
+ (click)="densityChange.emit('spacious')"
117
+ aria-label="Spacious">
118
+ <kp-icon name="layout-grid" />
119
+ </button>
120
+ </div>
121
+ }
122
+
123
+ @if (showColumnPicker) {
124
+ <kp-button variant="outline" size="sm" [iconOnly]="true" aria-label="Columns" (click)="columnsClick.emit()">
125
+ <kp-icon kpButtonIconLeft name="layout-columns" />
126
+ </kp-button>
127
+ }
128
+
129
+ @if (showExport) {
130
+ <kp-button variant="ghost" size="sm" (click)="exportClick.emit()">
131
+ <kp-icon kpButtonIconLeft name="download" />
132
+ <span>Export</span>
133
+ </kp-button>
134
+ }
135
+
136
+ @if (hasRightActions && showCreate) {
137
+ <span class="kp-tt__divider" aria-hidden="true"></span>
138
+ }
139
+
140
+ @if (showCreate) {
141
+ <kp-button variant="default" color="primary" size="sm" (click)="createClick.emit()">
142
+ <kp-icon kpButtonIconLeft name="plus" />
143
+ <span>{{ createLabel }}</span>
144
+ </kp-button>
145
+ }
146
+ </div>
147
+ } @else {
148
+ <div class="kp-tt__left">
149
+ <span class="kp-tt__selected">
150
+ <strong>{{ selectedCount }}</strong> {{ selectedCount === 1 ? 'item' : 'items' }} selected
151
+ </span>
152
+ <kp-button variant="ghost" size="sm" (click)="clearSelection.emit()">
153
+ <kp-icon kpButtonIconLeft name="x" />
154
+ <span>Clear selection</span>
155
+ </kp-button>
156
+ </div>
157
+
158
+ <div class="kp-tt__right">
159
+ <kp-button variant="outline" size="sm" (click)="bulkExport.emit()">
160
+ <kp-icon kpButtonIconLeft name="download" />
161
+ <span>Export selected</span>
162
+ </kp-button>
163
+ <kp-button variant="outline" size="sm" (click)="bulkTag.emit()">
164
+ <kp-icon kpButtonIconLeft name="tag" />
165
+ <span>Tag</span>
166
+ </kp-button>
167
+ <kp-button variant="outline" size="sm" (click)="bulkMove.emit()">
168
+ <kp-icon kpButtonIconLeft name="folder" />
169
+ <span>Move to…</span>
170
+ </kp-button>
171
+ <span class="kp-tt__divider" aria-hidden="true"></span>
172
+ <kp-button variant="outline" color="danger" size="sm" (click)="bulkDelete.emit()">
173
+ <kp-icon kpButtonIconLeft name="trash" />
174
+ <span>Delete</span>
175
+ </kp-button>
176
+ </div>
177
+ }
178
+ `, isInline: true, styles: [":host{box-sizing:border-box;display:flex;width:100%;max-width:100%;min-width:0;overflow:hidden;align-items:center;flex-wrap:wrap;gap:12px;row-gap:8px;padding:12px 16px;background:var(--kp-color-white, var(--kp-color-white));border-bottom:1px solid var(--kp-color-gray-200, var(--kp-color-gray-200));font-family:var(--kp-font-family-sans, \"Onest\", system-ui, sans-serif)}.kp-tt__left{display:flex;align-items:center;flex-wrap:wrap;gap:12px;row-gap:8px;flex:1 1 auto;min-width:0}.kp-tt__right{display:flex;align-items:center;flex-wrap:wrap;gap:8px;row-gap:8px;flex:0 1 auto;justify-content:flex-end;margin-inline-start:auto}:host kp-search-bar{display:flex!important;flex:1 1 240px;min-width:0;max-width:320px}:host kp-search-bar ::ng-deep .kp-search-bar__wrap{width:100%!important;min-width:0}.kp-tt__divider{width:1px;height:24px;background:var(--kp-color-gray-200, var(--kp-color-gray-200));margin:0 4px}.kp-tt__selected{font-size:13px;color:var(--kp-color-gray-700, var(--kp-color-gray-700))}.kp-tt__selected strong{color:var(--kp-color-gray-900, var(--kp-color-gray-900));font-weight:600}.kp-tt__density{display:inline-flex;padding:2px;border:1px solid var(--kp-color-gray-200, var(--kp-color-gray-200));border-radius:6px;background:var(--kp-color-gray-50, var(--kp-color-gray-50))}.kp-tt__density-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:24px;padding:0;border:none;background:transparent;border-radius:4px;color:var(--kp-color-gray-600, var(--kp-color-gray-600));cursor:pointer;font:inherit}.kp-tt__density-btn:hover{color:var(--kp-color-gray-900, var(--kp-color-gray-900))}.kp-tt__density-btn--active{background:var(--kp-color-white, var(--kp-color-white));color:var(--kp-color-gray-900, var(--kp-color-gray-900));box-shadow:var(--kp-elevation-raised)}.kp-tt__density-btn .ti{font-size:14px;line-height:1}:host .ti{font-size:14px;line-height:1}\n"], dependencies: [{ kind: "component", type: KpButtonComponent, selector: "kp-button", inputs: ["size", "variant", "color", "disabled", "loading", "iconOnly", "forceState"] }, { kind: "component", type: KpBadgeComponent, selector: "kp-badge", inputs: ["size", "appearance", "color", "pill", "showLeadingDot", "closable"], outputs: ["close"] }, { kind: "component", type: KpIconComponent, selector: "kp-icon", inputs: ["name", "size"] }, { kind: "component", type: KpSearchBarComponent, selector: "kp-search-bar", inputs: ["variant", "size", "placeholder", "value", "showShortcutHint", "shortcutHint", "groups"], outputs: ["valueChange", "search", "itemClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
179
+ }
180
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: KpTableToolbarComponent, decorators: [{
181
+ type: Component,
182
+ args: [{ selector: 'kp-table-toolbar', imports: [KpButtonComponent, KpBadgeComponent, KpIconComponent, KpSearchBarComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class]': 'hostClasses' }, template: `
183
+ @if (mode === 'default') {
184
+ <div class="kp-tt__left">
185
+ @if (showSearch) {
186
+ <kp-search-bar
187
+ variant="inline"
188
+ size="sm"
189
+ [placeholder]="searchPlaceholder"
190
+ [value]="searchValue"
191
+ (valueChange)="searchChange.emit($event)"
192
+ />
193
+ }
194
+
195
+ @if (showFilter) {
196
+ <kp-button variant="outline" size="sm" (click)="filterClick.emit()">
197
+ <kp-icon kpButtonIconLeft name="filter" />
198
+ <span>Filters</span>
199
+ @if (activeFilterCount > 0) {
200
+ <kp-badge size="xs" color="primary" appearance="subtle">{{ activeFilterCount }}</kp-badge>
201
+ }
202
+ </kp-button>
203
+ }
204
+
205
+ @if (showSort) {
206
+ <kp-button variant="outline" size="sm" (click)="sortClick.emit()">
207
+ <kp-icon kpButtonIconLeft name="arrows-up-down" />
208
+ <span>Sort</span>
209
+ </kp-button>
210
+ }
211
+ </div>
212
+
213
+ <div class="kp-tt__right">
214
+ @if (showDensity) {
215
+ <div class="kp-tt__density" role="group" aria-label="Row density">
216
+ <button
217
+ type="button"
218
+ class="kp-tt__density-btn"
219
+ [class.kp-tt__density-btn--active]="density === 'compact'"
220
+ (click)="densityChange.emit('compact')"
221
+ aria-label="Compact">
222
+ <kp-icon name="layout-list" />
223
+ </button>
224
+ <button
225
+ type="button"
226
+ class="kp-tt__density-btn"
227
+ [class.kp-tt__density-btn--active]="density === 'comfortable'"
228
+ (click)="densityChange.emit('comfortable')"
229
+ aria-label="Comfortable">
230
+ <kp-icon name="layout-rows" />
231
+ </button>
232
+ <button
233
+ type="button"
234
+ class="kp-tt__density-btn"
235
+ [class.kp-tt__density-btn--active]="density === 'spacious'"
236
+ (click)="densityChange.emit('spacious')"
237
+ aria-label="Spacious">
238
+ <kp-icon name="layout-grid" />
239
+ </button>
240
+ </div>
241
+ }
242
+
243
+ @if (showColumnPicker) {
244
+ <kp-button variant="outline" size="sm" [iconOnly]="true" aria-label="Columns" (click)="columnsClick.emit()">
245
+ <kp-icon kpButtonIconLeft name="layout-columns" />
246
+ </kp-button>
247
+ }
248
+
249
+ @if (showExport) {
250
+ <kp-button variant="ghost" size="sm" (click)="exportClick.emit()">
251
+ <kp-icon kpButtonIconLeft name="download" />
252
+ <span>Export</span>
253
+ </kp-button>
254
+ }
255
+
256
+ @if (hasRightActions && showCreate) {
257
+ <span class="kp-tt__divider" aria-hidden="true"></span>
258
+ }
259
+
260
+ @if (showCreate) {
261
+ <kp-button variant="default" color="primary" size="sm" (click)="createClick.emit()">
262
+ <kp-icon kpButtonIconLeft name="plus" />
263
+ <span>{{ createLabel }}</span>
264
+ </kp-button>
265
+ }
266
+ </div>
267
+ } @else {
268
+ <div class="kp-tt__left">
269
+ <span class="kp-tt__selected">
270
+ <strong>{{ selectedCount }}</strong> {{ selectedCount === 1 ? 'item' : 'items' }} selected
271
+ </span>
272
+ <kp-button variant="ghost" size="sm" (click)="clearSelection.emit()">
273
+ <kp-icon kpButtonIconLeft name="x" />
274
+ <span>Clear selection</span>
275
+ </kp-button>
276
+ </div>
277
+
278
+ <div class="kp-tt__right">
279
+ <kp-button variant="outline" size="sm" (click)="bulkExport.emit()">
280
+ <kp-icon kpButtonIconLeft name="download" />
281
+ <span>Export selected</span>
282
+ </kp-button>
283
+ <kp-button variant="outline" size="sm" (click)="bulkTag.emit()">
284
+ <kp-icon kpButtonIconLeft name="tag" />
285
+ <span>Tag</span>
286
+ </kp-button>
287
+ <kp-button variant="outline" size="sm" (click)="bulkMove.emit()">
288
+ <kp-icon kpButtonIconLeft name="folder" />
289
+ <span>Move to…</span>
290
+ </kp-button>
291
+ <span class="kp-tt__divider" aria-hidden="true"></span>
292
+ <kp-button variant="outline" color="danger" size="sm" (click)="bulkDelete.emit()">
293
+ <kp-icon kpButtonIconLeft name="trash" />
294
+ <span>Delete</span>
295
+ </kp-button>
296
+ </div>
297
+ }
298
+ `, styles: [":host{box-sizing:border-box;display:flex;width:100%;max-width:100%;min-width:0;overflow:hidden;align-items:center;flex-wrap:wrap;gap:12px;row-gap:8px;padding:12px 16px;background:var(--kp-color-white, var(--kp-color-white));border-bottom:1px solid var(--kp-color-gray-200, var(--kp-color-gray-200));font-family:var(--kp-font-family-sans, \"Onest\", system-ui, sans-serif)}.kp-tt__left{display:flex;align-items:center;flex-wrap:wrap;gap:12px;row-gap:8px;flex:1 1 auto;min-width:0}.kp-tt__right{display:flex;align-items:center;flex-wrap:wrap;gap:8px;row-gap:8px;flex:0 1 auto;justify-content:flex-end;margin-inline-start:auto}:host kp-search-bar{display:flex!important;flex:1 1 240px;min-width:0;max-width:320px}:host kp-search-bar ::ng-deep .kp-search-bar__wrap{width:100%!important;min-width:0}.kp-tt__divider{width:1px;height:24px;background:var(--kp-color-gray-200, var(--kp-color-gray-200));margin:0 4px}.kp-tt__selected{font-size:13px;color:var(--kp-color-gray-700, var(--kp-color-gray-700))}.kp-tt__selected strong{color:var(--kp-color-gray-900, var(--kp-color-gray-900));font-weight:600}.kp-tt__density{display:inline-flex;padding:2px;border:1px solid var(--kp-color-gray-200, var(--kp-color-gray-200));border-radius:6px;background:var(--kp-color-gray-50, var(--kp-color-gray-50))}.kp-tt__density-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:24px;padding:0;border:none;background:transparent;border-radius:4px;color:var(--kp-color-gray-600, var(--kp-color-gray-600));cursor:pointer;font:inherit}.kp-tt__density-btn:hover{color:var(--kp-color-gray-900, var(--kp-color-gray-900))}.kp-tt__density-btn--active{background:var(--kp-color-white, var(--kp-color-white));color:var(--kp-color-gray-900, var(--kp-color-gray-900));box-shadow:var(--kp-elevation-raised)}.kp-tt__density-btn .ti{font-size:14px;line-height:1}:host .ti{font-size:14px;line-height:1}\n"] }]
299
+ }], propDecorators: { mode: [{
300
+ type: Input
301
+ }], showSearch: [{
302
+ type: Input
303
+ }], searchPlaceholder: [{
304
+ type: Input
305
+ }], searchValue: [{
306
+ type: Input
307
+ }], showFilter: [{
308
+ type: Input
309
+ }], activeFilterCount: [{
310
+ type: Input
311
+ }], showSort: [{
312
+ type: Input
313
+ }], showDensity: [{
314
+ type: Input
315
+ }], density: [{
316
+ type: Input
317
+ }], showColumnPicker: [{
318
+ type: Input
319
+ }], showExport: [{
320
+ type: Input
321
+ }], showCreate: [{
322
+ type: Input
323
+ }], createLabel: [{
324
+ type: Input
325
+ }], selectedCount: [{
326
+ type: Input
327
+ }], searchChange: [{
328
+ type: Output
329
+ }], filterClick: [{
330
+ type: Output
331
+ }], sortClick: [{
332
+ type: Output
333
+ }], densityChange: [{
334
+ type: Output
335
+ }], columnsClick: [{
336
+ type: Output
337
+ }], exportClick: [{
338
+ type: Output
339
+ }], createClick: [{
340
+ type: Output
341
+ }], clearSelection: [{
342
+ type: Output
343
+ }], bulkExport: [{
344
+ type: Output
345
+ }], bulkTag: [{
346
+ type: Output
347
+ }], bulkMove: [{
348
+ type: Output
349
+ }], bulkDelete: [{
350
+ type: Output
351
+ }] } });
352
+
353
+ /**
354
+ * Generated bundle index. Do not edit.
355
+ */
356
+
357
+ export { KpTableToolbarComponent };
358
+ //# sourceMappingURL=kanso-protocol-table-toolbar.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kanso-protocol-table-toolbar.mjs","sources":["../../../../../packages/patterns/table-toolbar/src/table-toolbar.component.ts","../../../../../packages/patterns/table-toolbar/src/kanso-protocol-table-toolbar.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n Input,\n Output,\n} from '@angular/core';\nimport { KpButtonComponent } from '@kanso-protocol/button';\nimport { KpBadgeComponent } from '@kanso-protocol/badge';\nimport { KpIconComponent } from '@kanso-protocol/icon';\nimport { KpSearchBarComponent } from '@kanso-protocol/search-bar';\n\nexport type KpTableToolbarMode = 'default' | 'bulk-select';\nexport type KpTableToolbarDensity = 'compact' | 'comfortable' | 'spacious';\n\n/**\n * Kanso Protocol — TableToolbar\n *\n * Panel that sits above a data table. Two modes:\n * - `default` — search + filter/sort + right-side actions (density, columns,\n * export, create).\n * - `bulk-select` — swaps to a selection summary with bulk actions\n * (export / tag / move / delete).\n *\n * Composes SearchBar, Button, Badge. Action slots are boolean toggles so\n * you can dial the toolbar from minimal (\"search + create\") up to a full\n * admin bar without touching templates.\n *\n * @example\n * <kp-table-toolbar\n * [showFilter]=\"true\"\n * [activeFilterCount]=\"2\"\n * (createClick)=\"openCreate()\">\n * </kp-table-toolbar>\n */\n@Component({\n selector: 'kp-table-toolbar',\n imports: [KpButtonComponent, KpBadgeComponent, KpIconComponent, KpSearchBarComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { '[class]': 'hostClasses' },\n template: `\n @if (mode === 'default') {\n <div class=\"kp-tt__left\">\n @if (showSearch) {\n <kp-search-bar\n variant=\"inline\"\n size=\"sm\"\n [placeholder]=\"searchPlaceholder\"\n [value]=\"searchValue\"\n (valueChange)=\"searchChange.emit($event)\"\n />\n }\n\n @if (showFilter) {\n <kp-button variant=\"outline\" size=\"sm\" (click)=\"filterClick.emit()\">\n <kp-icon kpButtonIconLeft name=\"filter\" />\n <span>Filters</span>\n @if (activeFilterCount > 0) {\n <kp-badge size=\"xs\" color=\"primary\" appearance=\"subtle\">{{ activeFilterCount }}</kp-badge>\n }\n </kp-button>\n }\n\n @if (showSort) {\n <kp-button variant=\"outline\" size=\"sm\" (click)=\"sortClick.emit()\">\n <kp-icon kpButtonIconLeft name=\"arrows-up-down\" />\n <span>Sort</span>\n </kp-button>\n }\n </div>\n\n <div class=\"kp-tt__right\">\n @if (showDensity) {\n <div class=\"kp-tt__density\" role=\"group\" aria-label=\"Row density\">\n <button\n type=\"button\"\n class=\"kp-tt__density-btn\"\n [class.kp-tt__density-btn--active]=\"density === 'compact'\"\n (click)=\"densityChange.emit('compact')\"\n aria-label=\"Compact\">\n <kp-icon name=\"layout-list\" />\n </button>\n <button\n type=\"button\"\n class=\"kp-tt__density-btn\"\n [class.kp-tt__density-btn--active]=\"density === 'comfortable'\"\n (click)=\"densityChange.emit('comfortable')\"\n aria-label=\"Comfortable\">\n <kp-icon name=\"layout-rows\" />\n </button>\n <button\n type=\"button\"\n class=\"kp-tt__density-btn\"\n [class.kp-tt__density-btn--active]=\"density === 'spacious'\"\n (click)=\"densityChange.emit('spacious')\"\n aria-label=\"Spacious\">\n <kp-icon name=\"layout-grid\" />\n </button>\n </div>\n }\n\n @if (showColumnPicker) {\n <kp-button variant=\"outline\" size=\"sm\" [iconOnly]=\"true\" aria-label=\"Columns\" (click)=\"columnsClick.emit()\">\n <kp-icon kpButtonIconLeft name=\"layout-columns\" />\n </kp-button>\n }\n\n @if (showExport) {\n <kp-button variant=\"ghost\" size=\"sm\" (click)=\"exportClick.emit()\">\n <kp-icon kpButtonIconLeft name=\"download\" />\n <span>Export</span>\n </kp-button>\n }\n\n @if (hasRightActions && showCreate) {\n <span class=\"kp-tt__divider\" aria-hidden=\"true\"></span>\n }\n\n @if (showCreate) {\n <kp-button variant=\"default\" color=\"primary\" size=\"sm\" (click)=\"createClick.emit()\">\n <kp-icon kpButtonIconLeft name=\"plus\" />\n <span>{{ createLabel }}</span>\n </kp-button>\n }\n </div>\n } @else {\n <div class=\"kp-tt__left\">\n <span class=\"kp-tt__selected\">\n <strong>{{ selectedCount }}</strong> {{ selectedCount === 1 ? 'item' : 'items' }} selected\n </span>\n <kp-button variant=\"ghost\" size=\"sm\" (click)=\"clearSelection.emit()\">\n <kp-icon kpButtonIconLeft name=\"x\" />\n <span>Clear selection</span>\n </kp-button>\n </div>\n\n <div class=\"kp-tt__right\">\n <kp-button variant=\"outline\" size=\"sm\" (click)=\"bulkExport.emit()\">\n <kp-icon kpButtonIconLeft name=\"download\" />\n <span>Export selected</span>\n </kp-button>\n <kp-button variant=\"outline\" size=\"sm\" (click)=\"bulkTag.emit()\">\n <kp-icon kpButtonIconLeft name=\"tag\" />\n <span>Tag</span>\n </kp-button>\n <kp-button variant=\"outline\" size=\"sm\" (click)=\"bulkMove.emit()\">\n <kp-icon kpButtonIconLeft name=\"folder\" />\n <span>Move to…</span>\n </kp-button>\n <span class=\"kp-tt__divider\" aria-hidden=\"true\"></span>\n <kp-button variant=\"outline\" color=\"danger\" size=\"sm\" (click)=\"bulkDelete.emit()\">\n <kp-icon kpButtonIconLeft name=\"trash\" />\n <span>Delete</span>\n </kp-button>\n </div>\n }\n `,\n styles: [`\n :host {\n box-sizing: border-box;\n display: flex;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: hidden;\n align-items: center;\n flex-wrap: wrap;\n gap: 12px;\n row-gap: 8px;\n padding: 12px 16px;\n background: var(--kp-color-white, var(--kp-color-white));\n border-bottom: 1px solid var(--kp-color-gray-200, var(--kp-color-gray-200));\n font-family: var(--kp-font-family-sans, 'Onest', system-ui, sans-serif);\n }\n\n .kp-tt__left {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 12px;\n row-gap: 8px;\n flex: 1 1 auto;\n min-width: 0;\n }\n\n .kp-tt__right {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px;\n row-gap: 8px;\n flex: 0 1 auto;\n justify-content: flex-end;\n margin-inline-start: auto;\n }\n\n /* Let SearchBar shrink inside the toolbar when the viewport is narrow.\n Need !important — SearchBar's own :host { display: inline-block }\n wins on specificity otherwise. */\n :host kp-search-bar {\n display: flex !important;\n flex: 1 1 240px;\n min-width: 0;\n max-width: 320px;\n }\n :host kp-search-bar ::ng-deep .kp-search-bar__wrap {\n width: 100% !important;\n min-width: 0;\n }\n\n .kp-tt__divider {\n width: 1px;\n height: 24px;\n background: var(--kp-color-gray-200, var(--kp-color-gray-200));\n margin: 0 4px;\n }\n\n .kp-tt__selected {\n font-size: 13px;\n color: var(--kp-color-gray-700, var(--kp-color-gray-700));\n }\n .kp-tt__selected strong {\n color: var(--kp-color-gray-900, var(--kp-color-gray-900));\n font-weight: 600;\n }\n\n /* Density toggle — compact segmented look */\n .kp-tt__density {\n display: inline-flex;\n padding: 2px;\n border: 1px solid var(--kp-color-gray-200, var(--kp-color-gray-200));\n border-radius: 6px;\n background: var(--kp-color-gray-50, var(--kp-color-gray-50));\n }\n .kp-tt__density-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 24px;\n padding: 0;\n border: none;\n background: transparent;\n border-radius: 4px;\n color: var(--kp-color-gray-600, var(--kp-color-gray-600));\n cursor: pointer;\n font: inherit;\n }\n .kp-tt__density-btn:hover { color: var(--kp-color-gray-900, var(--kp-color-gray-900)); }\n .kp-tt__density-btn--active {\n background: var(--kp-color-white, var(--kp-color-white));\n color: var(--kp-color-gray-900, var(--kp-color-gray-900));\n box-shadow: var(--kp-elevation-raised);\n }\n .kp-tt__density-btn .ti { font-size: 14px; line-height: 1; }\n\n /* Inline icons inside buttons */\n :host .ti { font-size: 14px; line-height: 1; }\n `],\n})\nexport class KpTableToolbarComponent {\n @Input() mode: KpTableToolbarMode = 'default';\n\n @Input() showSearch = true;\n @Input() searchPlaceholder = 'Search…';\n @Input() searchValue = '';\n\n @Input() showFilter = true;\n @Input() activeFilterCount = 0;\n\n @Input() showSort = false;\n @Input() showDensity = false;\n @Input() density: KpTableToolbarDensity = 'comfortable';\n\n @Input() showColumnPicker = false;\n @Input() showExport = false;\n @Input() showCreate = true;\n @Input() createLabel = 'Create new';\n\n @Input() selectedCount = 0;\n\n @Output() searchChange = new EventEmitter<string>();\n @Output() filterClick = new EventEmitter<void>();\n @Output() sortClick = new EventEmitter<void>();\n @Output() densityChange = new EventEmitter<KpTableToolbarDensity>();\n @Output() columnsClick = new EventEmitter<void>();\n @Output() exportClick = new EventEmitter<void>();\n @Output() createClick = new EventEmitter<void>();\n\n @Output() clearSelection = new EventEmitter<void>();\n @Output() bulkExport = new EventEmitter<void>();\n @Output() bulkTag = new EventEmitter<void>();\n @Output() bulkMove = new EventEmitter<void>();\n @Output() bulkDelete = new EventEmitter<void>();\n\n get hasRightActions(): boolean {\n return this.showDensity || this.showColumnPicker || this.showExport;\n }\n\n get hostClasses(): string {\n return `kp-tt kp-tt--${this.mode}`;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@kanso-protocol/table-toolbar",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "peerDependencies": {
6
+ "@angular/core": "^18.0.0",
7
+ "@angular/common": "^18.0.0",
8
+ "@kanso-protocol/core": "^0.0.1",
9
+ "@kanso-protocol/button": ">=0.1.0",
10
+ "@kanso-protocol/badge": ">=0.1.0",
11
+ "@kanso-protocol/search-bar": ">=0.1.0"
12
+ },
13
+ "description": "Kanso Protocol — table-toolbar (pattern).",
14
+ "author": "GregNBlack",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/GregNBlack/kanso-protocol.git",
18
+ "directory": "packages/patterns/table-toolbar"
19
+ },
20
+ "homepage": "https://gregnblack.github.io/kanso-protocol/?path=/docs/patterns-tabletoolbar--docs",
21
+ "bugs": "https://github.com/GregNBlack/kanso-protocol/issues",
22
+ "keywords": [
23
+ "design-system",
24
+ "angular",
25
+ "kanso",
26
+ "table-toolbar"
27
+ ],
28
+ "sideEffects": false,
29
+ "module": "fesm2022/kanso-protocol-table-toolbar.mjs",
30
+ "typings": "types/kanso-protocol-table-toolbar.d.ts",
31
+ "exports": {
32
+ "./package.json": {
33
+ "default": "./package.json"
34
+ },
35
+ ".": {
36
+ "types": "./types/kanso-protocol-table-toolbar.d.ts",
37
+ "default": "./fesm2022/kanso-protocol-table-toolbar.mjs"
38
+ }
39
+ },
40
+ "type": "module",
41
+ "dependencies": {
42
+ "tslib": "^2.3.0"
43
+ }
44
+ }
@@ -0,0 +1,60 @@
1
+ import * as i0 from '@angular/core';
2
+ import { EventEmitter } from '@angular/core';
3
+
4
+ type KpTableToolbarMode = 'default' | 'bulk-select';
5
+ type KpTableToolbarDensity = 'compact' | 'comfortable' | 'spacious';
6
+ /**
7
+ * Kanso Protocol — TableToolbar
8
+ *
9
+ * Panel that sits above a data table. Two modes:
10
+ * - `default` — search + filter/sort + right-side actions (density, columns,
11
+ * export, create).
12
+ * - `bulk-select` — swaps to a selection summary with bulk actions
13
+ * (export / tag / move / delete).
14
+ *
15
+ * Composes SearchBar, Button, Badge. Action slots are boolean toggles so
16
+ * you can dial the toolbar from minimal ("search + create") up to a full
17
+ * admin bar without touching templates.
18
+ *
19
+ * @example
20
+ * <kp-table-toolbar
21
+ * [showFilter]="true"
22
+ * [activeFilterCount]="2"
23
+ * (createClick)="openCreate()">
24
+ * </kp-table-toolbar>
25
+ */
26
+ declare class KpTableToolbarComponent {
27
+ mode: KpTableToolbarMode;
28
+ showSearch: boolean;
29
+ searchPlaceholder: string;
30
+ searchValue: string;
31
+ showFilter: boolean;
32
+ activeFilterCount: number;
33
+ showSort: boolean;
34
+ showDensity: boolean;
35
+ density: KpTableToolbarDensity;
36
+ showColumnPicker: boolean;
37
+ showExport: boolean;
38
+ showCreate: boolean;
39
+ createLabel: string;
40
+ selectedCount: number;
41
+ searchChange: EventEmitter<string>;
42
+ filterClick: EventEmitter<void>;
43
+ sortClick: EventEmitter<void>;
44
+ densityChange: EventEmitter<KpTableToolbarDensity>;
45
+ columnsClick: EventEmitter<void>;
46
+ exportClick: EventEmitter<void>;
47
+ createClick: EventEmitter<void>;
48
+ clearSelection: EventEmitter<void>;
49
+ bulkExport: EventEmitter<void>;
50
+ bulkTag: EventEmitter<void>;
51
+ bulkMove: EventEmitter<void>;
52
+ bulkDelete: EventEmitter<void>;
53
+ get hasRightActions(): boolean;
54
+ get hostClasses(): string;
55
+ static ɵfac: i0.ɵɵFactoryDeclaration<KpTableToolbarComponent, never>;
56
+ static ɵcmp: i0.ɵɵComponentDeclaration<KpTableToolbarComponent, "kp-table-toolbar", never, { "mode": { "alias": "mode"; "required": false; }; "showSearch": { "alias": "showSearch"; "required": false; }; "searchPlaceholder": { "alias": "searchPlaceholder"; "required": false; }; "searchValue": { "alias": "searchValue"; "required": false; }; "showFilter": { "alias": "showFilter"; "required": false; }; "activeFilterCount": { "alias": "activeFilterCount"; "required": false; }; "showSort": { "alias": "showSort"; "required": false; }; "showDensity": { "alias": "showDensity"; "required": false; }; "density": { "alias": "density"; "required": false; }; "showColumnPicker": { "alias": "showColumnPicker"; "required": false; }; "showExport": { "alias": "showExport"; "required": false; }; "showCreate": { "alias": "showCreate"; "required": false; }; "createLabel": { "alias": "createLabel"; "required": false; }; "selectedCount": { "alias": "selectedCount"; "required": false; }; }, { "searchChange": "searchChange"; "filterClick": "filterClick"; "sortClick": "sortClick"; "densityChange": "densityChange"; "columnsClick": "columnsClick"; "exportClick": "exportClick"; "createClick": "createClick"; "clearSelection": "clearSelection"; "bulkExport": "bulkExport"; "bulkTag": "bulkTag"; "bulkMove": "bulkMove"; "bulkDelete": "bulkDelete"; }, never, never, true, never>;
57
+ }
58
+
59
+ export { KpTableToolbarComponent };
60
+ export type { KpTableToolbarDensity, KpTableToolbarMode };