@kanso-protocol/search-bar 1.0.0 → 2.0.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.
|
@@ -75,7 +75,7 @@ class KpSearchBarComponent {
|
|
|
75
75
|
[attr.aria-label]="resolvedPlaceholder"
|
|
76
76
|
/>
|
|
77
77
|
@if (value) {
|
|
78
|
-
<
|
|
78
|
+
<button kpButton
|
|
79
79
|
size="xs"
|
|
80
80
|
variant="ghost"
|
|
81
81
|
color="neutral"
|
|
@@ -84,7 +84,7 @@ class KpSearchBarComponent {
|
|
|
84
84
|
(click)="clear()"
|
|
85
85
|
>
|
|
86
86
|
<svg kpButtonIconLeft viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg>
|
|
87
|
-
</
|
|
87
|
+
</button>
|
|
88
88
|
} @else if (showShortcutHint) {
|
|
89
89
|
<kbd class="kp-search-bar__shortcut">{{ resolvedShortcutHint }}</kbd>
|
|
90
90
|
}
|
|
@@ -136,7 +136,7 @@ class KpSearchBarComponent {
|
|
|
136
136
|
</div>
|
|
137
137
|
</div>
|
|
138
138
|
}
|
|
139
|
-
`, isInline: true, styles: [":host{display:inline-block;font-family:var(--kp-font-family-sans, \"Onest\", system-ui, sans-serif)}:host(.kp-search-bar--command-palette){display:block;width:640px;max-width:100%}.kp-search-bar__wrap{display:inline-flex;align-items:center;gap:8px;width:var(--kp-search-w, 400px);height:var(--kp-search-h, 36px);padding:0 10px;border:1px solid var(--kp-color-input-border-rest);border-radius:var(--kp-search-radius, 12px);background:var(--kp-color-input-bg-default);transition:background var(--kp-motion-duration-fast) ease,border-color .12s ease,box-shadow .12s ease}.kp-search-bar__wrap--focused,.kp-search-bar__wrap:focus-within{border-color:var(--kp-color-input-border-focus);box-shadow:0 0 0 3px var(--kp-color-overlay-focus-ring)}:host(.kp-search-bar--sm){--kp-search-w: 320px;--kp-search-h: 32px;--kp-search-fs: 13px;--kp-search-radius: 10px}:host(.kp-search-bar--md){--kp-search-w: 400px;--kp-search-h: 36px;--kp-search-fs: 14px;--kp-search-radius: 12px}:host(.kp-search-bar--lg){--kp-search-w: 480px;--kp-search-h: 44px;--kp-search-fs: 15px;--kp-search-radius: 14px}.kp-search-bar__leading{flex:0 0 auto;font-size:18px;color:var(--kp-color-text-muted)}.kp-search-bar__input{all:unset;flex:1 1 auto;min-width:0;height:100%;font-size:var(--kp-search-fs, 14px);color:var(--kp-color-text-strong)}.kp-search-bar__input::placeholder{color:var(--kp-color-text-muted)}.kp-search-bar__input::-webkit-search-cancel-button{display:none}.kp-search-bar__shortcut{display:inline-flex;align-items:center;padding:2px 6px;border:1px solid var(--kp-color-border-default);border-radius:4px;background:var(--kp-color-surface-base);color:var(--kp-color-text-muted);font-family:inherit;font-size:11px;font-weight:500}.kp-search-bar__palette{display:flex;flex-direction:column;border-radius:12px;border:1px solid var(--kp-color-search-palette-border);background:var(--kp-color-search-palette-bg);box-shadow:var(--kp-elevation-floating);overflow:hidden}.kp-search-bar__palette-header{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--kp-color-search-palette-border)}.kp-search-bar__palette-header .kp-search-bar__leading{font-size:20px}.kp-search-bar__palette-input{all:unset;flex:1 1 auto;font-size:16px;color:var(--kp-color-text-strong)}.kp-search-bar__palette-input::placeholder{color:var(--kp-color-text-muted)}.kp-search-bar__groups{padding:8px;max-height:420px;overflow-y:auto}.kp-search-bar__group{display:flex;flex-direction:column}.kp-search-bar__group+.kp-search-bar__group{margin-top:8px}.kp-search-bar__group-label{padding:8px 12px 4px;font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;color:var(--kp-color-search-palette-group-label)}.kp-search-bar__item{all:unset;display:flex;align-items:center;gap:10px;padding:8px 12px;border-radius:6px;font-size:13px;color:var(--kp-color-text-default);cursor:pointer;transition:background var(--kp-motion-duration-fast) ease,color .12s ease}.kp-search-bar__item:hover{background:var(--kp-color-surface-muted);color:var(--kp-color-text-strong)}.kp-search-bar__item-icon{font-size:16px;color:var(--kp-color-text-muted)}.kp-search-bar__item:hover .kp-search-bar__item-icon{color:var(--kp-color-text-strong)}.kp-search-bar__item-label{flex:1 1 auto}.kp-search-bar__footer{display:flex;align-items:center;gap:16px;padding:8px 14px;border-top:1px solid var(--kp-color-search-palette-border);background:var(--kp-color-surface-subtle);font-size:11px;color:var(--kp-color-text-muted)}.kp-search-bar__footer kbd{display:inline-flex;align-items:center;padding:1px 5px;margin-inline-end:2px;border:1px solid var(--kp-color-border-default);border-radius:3px;background:var(--kp-color-surface-base);color:var(--kp-color-text-muted);font-family:inherit;font-size:10px}.kp-search-bar__footer-brand{margin-inline-start:auto;color:var(--kp-color-text-disabled)}\n"], dependencies: [{ kind: "component", type: KpButtonComponent, selector: "
|
|
139
|
+
`, isInline: true, styles: [":host{display:inline-block;font-family:var(--kp-font-family-sans, \"Onest\", system-ui, sans-serif)}:host(.kp-search-bar--command-palette){display:block;width:640px;max-width:100%}.kp-search-bar__wrap{display:inline-flex;align-items:center;gap:8px;width:var(--kp-search-w, 400px);height:var(--kp-search-h, 36px);padding:0 10px;border:1px solid var(--kp-color-input-border-rest);border-radius:var(--kp-search-radius, 12px);background:var(--kp-color-input-bg-default);transition:background var(--kp-motion-duration-fast) ease,border-color .12s ease,box-shadow .12s ease}.kp-search-bar__wrap--focused,.kp-search-bar__wrap:focus-within{border-color:var(--kp-color-input-border-focus);box-shadow:0 0 0 3px var(--kp-color-overlay-focus-ring)}:host(.kp-search-bar--sm){--kp-search-w: 320px;--kp-search-h: 32px;--kp-search-fs: 13px;--kp-search-radius: 10px}:host(.kp-search-bar--md){--kp-search-w: 400px;--kp-search-h: 36px;--kp-search-fs: 14px;--kp-search-radius: 12px}:host(.kp-search-bar--lg){--kp-search-w: 480px;--kp-search-h: 44px;--kp-search-fs: 15px;--kp-search-radius: 14px}.kp-search-bar__leading{flex:0 0 auto;font-size:18px;color:var(--kp-color-text-muted)}.kp-search-bar__input{all:unset;flex:1 1 auto;min-width:0;height:100%;font-size:var(--kp-search-fs, 14px);color:var(--kp-color-text-strong)}.kp-search-bar__input::placeholder{color:var(--kp-color-text-muted)}.kp-search-bar__input::-webkit-search-cancel-button{display:none}.kp-search-bar__shortcut{display:inline-flex;align-items:center;padding:2px 6px;border:1px solid var(--kp-color-border-default);border-radius:4px;background:var(--kp-color-surface-base);color:var(--kp-color-text-muted);font-family:inherit;font-size:11px;font-weight:500}.kp-search-bar__palette{display:flex;flex-direction:column;border-radius:12px;border:1px solid var(--kp-color-search-palette-border);background:var(--kp-color-search-palette-bg);box-shadow:var(--kp-elevation-floating);overflow:hidden}.kp-search-bar__palette-header{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--kp-color-search-palette-border)}.kp-search-bar__palette-header .kp-search-bar__leading{font-size:20px}.kp-search-bar__palette-input{all:unset;flex:1 1 auto;font-size:16px;color:var(--kp-color-text-strong)}.kp-search-bar__palette-input::placeholder{color:var(--kp-color-text-muted)}.kp-search-bar__groups{padding:8px;max-height:420px;overflow-y:auto}.kp-search-bar__group{display:flex;flex-direction:column}.kp-search-bar__group+.kp-search-bar__group{margin-top:8px}.kp-search-bar__group-label{padding:8px 12px 4px;font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;color:var(--kp-color-search-palette-group-label)}.kp-search-bar__item{all:unset;display:flex;align-items:center;gap:10px;padding:8px 12px;border-radius:6px;font-size:13px;color:var(--kp-color-text-default);cursor:pointer;transition:background var(--kp-motion-duration-fast) ease,color .12s ease}.kp-search-bar__item:hover{background:var(--kp-color-surface-muted);color:var(--kp-color-text-strong)}.kp-search-bar__item-icon{font-size:16px;color:var(--kp-color-text-muted)}.kp-search-bar__item:hover .kp-search-bar__item-icon{color:var(--kp-color-text-strong)}.kp-search-bar__item-label{flex:1 1 auto}.kp-search-bar__footer{display:flex;align-items:center;gap:16px;padding:8px 14px;border-top:1px solid var(--kp-color-search-palette-border);background:var(--kp-color-surface-subtle);font-size:11px;color:var(--kp-color-text-muted)}.kp-search-bar__footer kbd{display:inline-flex;align-items:center;padding:1px 5px;margin-inline-end:2px;border:1px solid var(--kp-color-border-default);border-radius:3px;background:var(--kp-color-surface-base);color:var(--kp-color-text-muted);font-family:inherit;font-size:10px}.kp-search-bar__footer-brand{margin-inline-start:auto;color:var(--kp-color-text-disabled)}\n"], dependencies: [{ kind: "component", type: KpButtonComponent, selector: "button[kpButton]", inputs: ["type", "size", "variant", "color", "disabled", "loading", "iconOnly", "forceState"] }, { kind: "component", type: KpIconComponent, selector: "kp-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
140
140
|
}
|
|
141
141
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: KpSearchBarComponent, decorators: [{
|
|
142
142
|
type: Component,
|
|
@@ -155,7 +155,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
155
155
|
[attr.aria-label]="resolvedPlaceholder"
|
|
156
156
|
/>
|
|
157
157
|
@if (value) {
|
|
158
|
-
<
|
|
158
|
+
<button kpButton
|
|
159
159
|
size="xs"
|
|
160
160
|
variant="ghost"
|
|
161
161
|
color="neutral"
|
|
@@ -164,7 +164,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
164
164
|
(click)="clear()"
|
|
165
165
|
>
|
|
166
166
|
<svg kpButtonIconLeft viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg>
|
|
167
|
-
</
|
|
167
|
+
</button>
|
|
168
168
|
} @else if (showShortcutHint) {
|
|
169
169
|
<kbd class="kp-search-bar__shortcut">{{ resolvedShortcutHint }}</kbd>
|
|
170
170
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kanso-protocol-search-bar.mjs","sources":["../../../../../packages/patterns/search-bar/src/search-bar.component.ts","../../../../../packages/patterns/search-bar/src/kanso-protocol-search-bar.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n Input,\n Output,\n} from '@angular/core';\nimport { KpButtonComponent } from '@kanso-protocol/button';\nimport { KpIconComponent } from '@kanso-protocol/icon';\nimport { injectKpStrings } from '@kanso-protocol/i18n';\n\nexport type KpSearchBarVariant = 'inline' | 'command-palette';\nexport type KpSearchBarSize = 'sm' | 'md' | 'lg';\n\nexport interface KpSearchResultItem {\n id: string;\n label: string;\n icon?: string; // Tabler icon name (without 'ti-' prefix)\n shortcut?: string; // e.g. \"⌘1\"\n}\n\nexport interface KpSearchResultGroup {\n label: string; // \"RECENT\", \"ACTIONS\", \"PAGES\"\n items: KpSearchResultItem[];\n}\n\n/**\n * Kanso Protocol — SearchBar\n *\n * Two variants:\n * - `inline` — a simple search input with optional ⌘K shortcut hint,\n * good for header search or page filters.\n * - `command-palette` — a self-contained panel: input + grouped\n * results with shortcuts + footer helper keys. Typically rendered\n * inside a Dialog/Overlay.\n *\n * The component is presentational; filtering results, opening the\n * palette via ⌘K, and committing selection are all consumer\n * responsibilities.\n *\n * @example\n * <!-- Inline in Header -->\n * <kp-search-bar variant=\"inline\" size=\"md\" [showShortcutHint]=\"true\" (search)=\"onSearch($event)\"/>\n *\n * <!-- Command Palette (inside a Dialog) -->\n * <kp-search-bar variant=\"command-palette\" [groups]=\"results\" (itemClick)=\"run($event)\"/>\n */\n@Component({\n selector: 'kp-search-bar',\n imports: [KpButtonComponent, KpIconComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { '[class]': 'hostClasses' },\n template: `\n @if (variant === 'inline') {\n <div class=\"kp-search-bar__wrap\" [class.kp-search-bar__wrap--focused]=\"focused\">\n <kp-icon name=\"search\" class=\"kp-search-bar__leading\" />\n <input\n class=\"kp-search-bar__input\"\n type=\"search\"\n [placeholder]=\"resolvedPlaceholder\"\n [value]=\"value\"\n (input)=\"handleInput($event)\"\n (focus)=\"focused = true\"\n (blur)=\"focused = false\"\n [attr.aria-label]=\"resolvedPlaceholder\"\n />\n @if (value) {\n <kp-button\n size=\"xs\"\n variant=\"ghost\"\n color=\"neutral\"\n [iconOnly]=\"true\"\n aria-label=\"Clear\"\n (click)=\"clear()\"\n >\n <svg kpButtonIconLeft viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.75\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M18 6 6 18M6 6l12 12\"/></svg>\n </kp-button>\n } @else if (showShortcutHint) {\n <kbd class=\"kp-search-bar__shortcut\">{{ resolvedShortcutHint }}</kbd>\n }\n </div>\n } @else {\n <div class=\"kp-search-bar__palette\">\n <div class=\"kp-search-bar__palette-header\">\n <kp-icon name=\"search\" class=\"kp-search-bar__leading\" />\n <input\n class=\"kp-search-bar__palette-input\"\n type=\"search\"\n [placeholder]=\"resolvedPlaceholder\"\n [attr.aria-label]=\"resolvedPlaceholder\"\n [value]=\"value\"\n (input)=\"handleInput($event)\"\n autofocus\n />\n </div>\n\n <div class=\"kp-search-bar__groups\" role=\"listbox\">\n @for (group of groups; track group.label) {\n <div class=\"kp-search-bar__group\">\n <div class=\"kp-search-bar__group-label\">{{ group.label }}</div>\n @for (item of group.items; track item.id) {\n <button\n type=\"button\"\n role=\"option\"\n class=\"kp-search-bar__item\"\n (click)=\"itemClick.emit(item)\"\n >\n @if (item.icon) {\n <kp-icon [name]=\"item.icon\" class=\"kp-search-bar__item-icon\" />\n }\n <span class=\"kp-search-bar__item-label\">{{ item.label }}</span>\n @if (item.shortcut) {\n <kbd class=\"kp-search-bar__shortcut\">{{ item.shortcut }}</kbd>\n }\n </button>\n }\n </div>\n }\n </div>\n\n <div class=\"kp-search-bar__footer\">\n <span><kbd>↑</kbd><kbd>↓</kbd> navigate</span>\n <span><kbd>↵</kbd> select</span>\n <span><kbd>esc</kbd> close</span>\n <span class=\"kp-search-bar__footer-brand\">Powered by Kanso</span>\n </div>\n </div>\n }\n `,\n styles: [`\n :host {\n display: inline-block;\n font-family: var(--kp-font-family-sans, 'Onest', system-ui, sans-serif);\n }\n :host(.kp-search-bar--command-palette) { display: block; width: 640px; max-width: 100%; }\n\n /* --- inline variant ---\n SearchBar IS an input, so the chrome — radius, bg, border —\n follows the Input contract directly. Sizes mirror Input\n sm / md / lg radius scale (10 / 12 / 14 px). */\n .kp-search-bar__wrap {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n width: var(--kp-search-w, 400px);\n height: var(--kp-search-h, 36px);\n padding: 0 10px;\n border: 1px solid var(--kp-color-input-border-rest);\n border-radius: var(--kp-search-radius, 12px);\n background: var(--kp-color-input-bg-default);\n transition: background var(--kp-motion-duration-fast) ease, border-color 120ms ease, box-shadow 120ms ease;\n }\n .kp-search-bar__wrap--focused,\n .kp-search-bar__wrap:focus-within {\n border-color: var(--kp-color-input-border-focus);\n box-shadow: 0 0 0 3px var(--kp-color-overlay-focus-ring);\n }\n\n :host(.kp-search-bar--sm) { --kp-search-w: 320px; --kp-search-h: 32px; --kp-search-fs: 13px; --kp-search-radius: 10px; }\n :host(.kp-search-bar--md) { --kp-search-w: 400px; --kp-search-h: 36px; --kp-search-fs: 14px; --kp-search-radius: 12px; }\n :host(.kp-search-bar--lg) { --kp-search-w: 480px; --kp-search-h: 44px; --kp-search-fs: 15px; --kp-search-radius: 14px; }\n\n .kp-search-bar__leading {\n flex: 0 0 auto;\n font-size: 18px;\n color: var(--kp-color-text-muted);\n }\n\n .kp-search-bar__input {\n all: unset;\n flex: 1 1 auto;\n min-width: 0;\n height: 100%;\n font-size: var(--kp-search-fs, 14px);\n color: var(--kp-color-text-strong);\n }\n .kp-search-bar__input::placeholder { color: var(--kp-color-text-muted); }\n .kp-search-bar__input::-webkit-search-cancel-button { display: none; }\n\n\n .kp-search-bar__shortcut {\n display: inline-flex;\n align-items: center;\n padding: 2px 6px;\n border: 1px solid var(--kp-color-border-default);\n border-radius: 4px;\n background: var(--kp-color-surface-base);\n color: var(--kp-color-text-muted);\n font-family: inherit;\n font-size: 11px;\n font-weight: 500;\n }\n\n /* --- command palette variant --- */\n .kp-search-bar__palette {\n display: flex;\n flex-direction: column;\n border-radius: 12px;\n border: 1px solid var(--kp-color-search-palette-border);\n background: var(--kp-color-search-palette-bg);\n box-shadow: var(--kp-elevation-floating);\n overflow: hidden;\n }\n\n .kp-search-bar__palette-header {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 14px 16px;\n border-bottom: 1px solid var(--kp-color-search-palette-border);\n }\n .kp-search-bar__palette-header .kp-search-bar__leading { font-size: 20px; }\n .kp-search-bar__palette-input {\n all: unset;\n flex: 1 1 auto;\n font-size: 16px;\n color: var(--kp-color-text-strong);\n }\n .kp-search-bar__palette-input::placeholder { color: var(--kp-color-text-muted); }\n\n .kp-search-bar__groups {\n padding: 8px;\n max-height: 420px;\n overflow-y: auto;\n }\n .kp-search-bar__group { display: flex; flex-direction: column; }\n .kp-search-bar__group + .kp-search-bar__group { margin-top: 8px; }\n .kp-search-bar__group-label {\n padding: 8px 12px 4px;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.5px;\n text-transform: uppercase;\n color: var(--kp-color-search-palette-group-label);\n }\n\n .kp-search-bar__item {\n all: unset;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 12px;\n border-radius: 6px;\n font-size: 13px;\n color: var(--kp-color-text-default);\n cursor: pointer;\n transition: background var(--kp-motion-duration-fast) ease, color 120ms ease;\n }\n .kp-search-bar__item:hover { background: var(--kp-color-surface-muted); color: var(--kp-color-text-strong); }\n .kp-search-bar__item-icon { font-size: 16px; color: var(--kp-color-text-muted); }\n .kp-search-bar__item:hover .kp-search-bar__item-icon { color: var(--kp-color-text-strong); }\n .kp-search-bar__item-label { flex: 1 1 auto; }\n\n .kp-search-bar__footer {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 8px 14px;\n border-top: 1px solid var(--kp-color-search-palette-border);\n background: var(--kp-color-surface-subtle);\n font-size: 11px;\n color: var(--kp-color-text-muted);\n }\n .kp-search-bar__footer kbd {\n display: inline-flex;\n align-items: center;\n padding: 1px 5px;\n margin-inline-end: 2px;\n border: 1px solid var(--kp-color-border-default);\n border-radius: 3px;\n background: var(--kp-color-surface-base);\n color: var(--kp-color-text-muted);\n font-family: inherit;\n font-size: 10px;\n }\n .kp-search-bar__footer-brand { margin-inline-start: auto; color: var(--kp-color-text-disabled); }\n `],\n})\nexport class KpSearchBarComponent {\n @Input() variant: KpSearchBarVariant = 'inline';\n @Input() size: KpSearchBarSize = 'md';\n @Input() placeholder: string | null = null;\n @Input() value = '';\n @Input() showShortcutHint = true;\n @Input() shortcutHint: string | null = null;\n /** Result groups — only rendered in `command-palette` variant */\n @Input() groups: KpSearchResultGroup[] = [];\n\n @Output() valueChange = new EventEmitter<string>();\n @Output() search = new EventEmitter<string>();\n @Output() itemClick = new EventEmitter<KpSearchResultItem>();\n\n focused = false;\n\n readonly strings = injectKpStrings();\n\n get resolvedPlaceholder(): string {\n return this.placeholder ?? this.strings.searchPlaceholder;\n }\n\n get resolvedShortcutHint(): string {\n return this.shortcutHint ?? this.strings.commandPaletteHint;\n }\n\n get hostClasses(): string {\n return `kp-search-bar kp-search-bar--${this.variant} kp-search-bar--${this.size}`;\n }\n\n handleInput(event: Event): void {\n const target = event.target as HTMLInputElement;\n this.value = target.value;\n this.valueChange.emit(this.value);\n this.search.emit(this.value);\n }\n\n clear(): void {\n this.value = '';\n this.valueChange.emit('');\n this.search.emit('');\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"kanso-protocol-search-bar.mjs","sources":["../../../../../packages/patterns/search-bar/src/search-bar.component.ts","../../../../../packages/patterns/search-bar/src/kanso-protocol-search-bar.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n Input,\n Output,\n} from '@angular/core';\nimport { KpButtonComponent } from '@kanso-protocol/button';\nimport { KpIconComponent } from '@kanso-protocol/icon';\nimport { injectKpStrings } from '@kanso-protocol/i18n';\n\nexport type KpSearchBarVariant = 'inline' | 'command-palette';\nexport type KpSearchBarSize = 'sm' | 'md' | 'lg';\n\nexport interface KpSearchResultItem {\n id: string;\n label: string;\n icon?: string; // Tabler icon name (without 'ti-' prefix)\n shortcut?: string; // e.g. \"⌘1\"\n}\n\nexport interface KpSearchResultGroup {\n label: string; // \"RECENT\", \"ACTIONS\", \"PAGES\"\n items: KpSearchResultItem[];\n}\n\n/**\n * Kanso Protocol — SearchBar\n *\n * Two variants:\n * - `inline` — a simple search input with optional ⌘K shortcut hint,\n * good for header search or page filters.\n * - `command-palette` — a self-contained panel: input + grouped\n * results with shortcuts + footer helper keys. Typically rendered\n * inside a Dialog/Overlay.\n *\n * The component is presentational; filtering results, opening the\n * palette via ⌘K, and committing selection are all consumer\n * responsibilities.\n *\n * @example\n * <!-- Inline in Header -->\n * <kp-search-bar variant=\"inline\" size=\"md\" [showShortcutHint]=\"true\" (search)=\"onSearch($event)\"/>\n *\n * <!-- Command Palette (inside a Dialog) -->\n * <kp-search-bar variant=\"command-palette\" [groups]=\"results\" (itemClick)=\"run($event)\"/>\n */\n@Component({\n selector: 'kp-search-bar',\n imports: [KpButtonComponent, KpIconComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { '[class]': 'hostClasses' },\n template: `\n @if (variant === 'inline') {\n <div class=\"kp-search-bar__wrap\" [class.kp-search-bar__wrap--focused]=\"focused\">\n <kp-icon name=\"search\" class=\"kp-search-bar__leading\" />\n <input\n class=\"kp-search-bar__input\"\n type=\"search\"\n [placeholder]=\"resolvedPlaceholder\"\n [value]=\"value\"\n (input)=\"handleInput($event)\"\n (focus)=\"focused = true\"\n (blur)=\"focused = false\"\n [attr.aria-label]=\"resolvedPlaceholder\"\n />\n @if (value) {\n <button kpButton\n size=\"xs\"\n variant=\"ghost\"\n color=\"neutral\"\n [iconOnly]=\"true\"\n aria-label=\"Clear\"\n (click)=\"clear()\"\n >\n <svg kpButtonIconLeft viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.75\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M18 6 6 18M6 6l12 12\"/></svg>\n </button>\n } @else if (showShortcutHint) {\n <kbd class=\"kp-search-bar__shortcut\">{{ resolvedShortcutHint }}</kbd>\n }\n </div>\n } @else {\n <div class=\"kp-search-bar__palette\">\n <div class=\"kp-search-bar__palette-header\">\n <kp-icon name=\"search\" class=\"kp-search-bar__leading\" />\n <input\n class=\"kp-search-bar__palette-input\"\n type=\"search\"\n [placeholder]=\"resolvedPlaceholder\"\n [attr.aria-label]=\"resolvedPlaceholder\"\n [value]=\"value\"\n (input)=\"handleInput($event)\"\n autofocus\n />\n </div>\n\n <div class=\"kp-search-bar__groups\" role=\"listbox\">\n @for (group of groups; track group.label) {\n <div class=\"kp-search-bar__group\">\n <div class=\"kp-search-bar__group-label\">{{ group.label }}</div>\n @for (item of group.items; track item.id) {\n <button\n type=\"button\"\n role=\"option\"\n class=\"kp-search-bar__item\"\n (click)=\"itemClick.emit(item)\"\n >\n @if (item.icon) {\n <kp-icon [name]=\"item.icon\" class=\"kp-search-bar__item-icon\" />\n }\n <span class=\"kp-search-bar__item-label\">{{ item.label }}</span>\n @if (item.shortcut) {\n <kbd class=\"kp-search-bar__shortcut\">{{ item.shortcut }}</kbd>\n }\n </button>\n }\n </div>\n }\n </div>\n\n <div class=\"kp-search-bar__footer\">\n <span><kbd>↑</kbd><kbd>↓</kbd> navigate</span>\n <span><kbd>↵</kbd> select</span>\n <span><kbd>esc</kbd> close</span>\n <span class=\"kp-search-bar__footer-brand\">Powered by Kanso</span>\n </div>\n </div>\n }\n `,\n styles: [`\n :host {\n display: inline-block;\n font-family: var(--kp-font-family-sans, 'Onest', system-ui, sans-serif);\n }\n :host(.kp-search-bar--command-palette) { display: block; width: 640px; max-width: 100%; }\n\n /* --- inline variant ---\n SearchBar IS an input, so the chrome — radius, bg, border —\n follows the Input contract directly. Sizes mirror Input\n sm / md / lg radius scale (10 / 12 / 14 px). */\n .kp-search-bar__wrap {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n width: var(--kp-search-w, 400px);\n height: var(--kp-search-h, 36px);\n padding: 0 10px;\n border: 1px solid var(--kp-color-input-border-rest);\n border-radius: var(--kp-search-radius, 12px);\n background: var(--kp-color-input-bg-default);\n transition: background var(--kp-motion-duration-fast) ease, border-color 120ms ease, box-shadow 120ms ease;\n }\n .kp-search-bar__wrap--focused,\n .kp-search-bar__wrap:focus-within {\n border-color: var(--kp-color-input-border-focus);\n box-shadow: 0 0 0 3px var(--kp-color-overlay-focus-ring);\n }\n\n :host(.kp-search-bar--sm) { --kp-search-w: 320px; --kp-search-h: 32px; --kp-search-fs: 13px; --kp-search-radius: 10px; }\n :host(.kp-search-bar--md) { --kp-search-w: 400px; --kp-search-h: 36px; --kp-search-fs: 14px; --kp-search-radius: 12px; }\n :host(.kp-search-bar--lg) { --kp-search-w: 480px; --kp-search-h: 44px; --kp-search-fs: 15px; --kp-search-radius: 14px; }\n\n .kp-search-bar__leading {\n flex: 0 0 auto;\n font-size: 18px;\n color: var(--kp-color-text-muted);\n }\n\n .kp-search-bar__input {\n all: unset;\n flex: 1 1 auto;\n min-width: 0;\n height: 100%;\n font-size: var(--kp-search-fs, 14px);\n color: var(--kp-color-text-strong);\n }\n .kp-search-bar__input::placeholder { color: var(--kp-color-text-muted); }\n .kp-search-bar__input::-webkit-search-cancel-button { display: none; }\n\n\n .kp-search-bar__shortcut {\n display: inline-flex;\n align-items: center;\n padding: 2px 6px;\n border: 1px solid var(--kp-color-border-default);\n border-radius: 4px;\n background: var(--kp-color-surface-base);\n color: var(--kp-color-text-muted);\n font-family: inherit;\n font-size: 11px;\n font-weight: 500;\n }\n\n /* --- command palette variant --- */\n .kp-search-bar__palette {\n display: flex;\n flex-direction: column;\n border-radius: 12px;\n border: 1px solid var(--kp-color-search-palette-border);\n background: var(--kp-color-search-palette-bg);\n box-shadow: var(--kp-elevation-floating);\n overflow: hidden;\n }\n\n .kp-search-bar__palette-header {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 14px 16px;\n border-bottom: 1px solid var(--kp-color-search-palette-border);\n }\n .kp-search-bar__palette-header .kp-search-bar__leading { font-size: 20px; }\n .kp-search-bar__palette-input {\n all: unset;\n flex: 1 1 auto;\n font-size: 16px;\n color: var(--kp-color-text-strong);\n }\n .kp-search-bar__palette-input::placeholder { color: var(--kp-color-text-muted); }\n\n .kp-search-bar__groups {\n padding: 8px;\n max-height: 420px;\n overflow-y: auto;\n }\n .kp-search-bar__group { display: flex; flex-direction: column; }\n .kp-search-bar__group + .kp-search-bar__group { margin-top: 8px; }\n .kp-search-bar__group-label {\n padding: 8px 12px 4px;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.5px;\n text-transform: uppercase;\n color: var(--kp-color-search-palette-group-label);\n }\n\n .kp-search-bar__item {\n all: unset;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 12px;\n border-radius: 6px;\n font-size: 13px;\n color: var(--kp-color-text-default);\n cursor: pointer;\n transition: background var(--kp-motion-duration-fast) ease, color 120ms ease;\n }\n .kp-search-bar__item:hover { background: var(--kp-color-surface-muted); color: var(--kp-color-text-strong); }\n .kp-search-bar__item-icon { font-size: 16px; color: var(--kp-color-text-muted); }\n .kp-search-bar__item:hover .kp-search-bar__item-icon { color: var(--kp-color-text-strong); }\n .kp-search-bar__item-label { flex: 1 1 auto; }\n\n .kp-search-bar__footer {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 8px 14px;\n border-top: 1px solid var(--kp-color-search-palette-border);\n background: var(--kp-color-surface-subtle);\n font-size: 11px;\n color: var(--kp-color-text-muted);\n }\n .kp-search-bar__footer kbd {\n display: inline-flex;\n align-items: center;\n padding: 1px 5px;\n margin-inline-end: 2px;\n border: 1px solid var(--kp-color-border-default);\n border-radius: 3px;\n background: var(--kp-color-surface-base);\n color: var(--kp-color-text-muted);\n font-family: inherit;\n font-size: 10px;\n }\n .kp-search-bar__footer-brand { margin-inline-start: auto; color: var(--kp-color-text-disabled); }\n `],\n})\nexport class KpSearchBarComponent {\n @Input() variant: KpSearchBarVariant = 'inline';\n @Input() size: KpSearchBarSize = 'md';\n @Input() placeholder: string | null = null;\n @Input() value = '';\n @Input() showShortcutHint = true;\n @Input() shortcutHint: string | null = null;\n /** Result groups — only rendered in `command-palette` variant */\n @Input() groups: KpSearchResultGroup[] = [];\n\n @Output() valueChange = new EventEmitter<string>();\n @Output() search = new EventEmitter<string>();\n @Output() itemClick = new EventEmitter<KpSearchResultItem>();\n\n focused = false;\n\n readonly strings = injectKpStrings();\n\n get resolvedPlaceholder(): string {\n return this.placeholder ?? this.strings.searchPlaceholder;\n }\n\n get resolvedShortcutHint(): string {\n return this.shortcutHint ?? this.strings.commandPaletteHint;\n }\n\n get hostClasses(): string {\n return `kp-search-bar kp-search-bar--${this.variant} kp-search-bar--${this.size}`;\n }\n\n handleInput(event: Event): void {\n const target = event.target as HTMLInputElement;\n this.value = target.value;\n this.valueChange.emit(this.value);\n this.search.emit(this.value);\n }\n\n clear(): void {\n this.value = '';\n this.valueChange.emit('');\n this.search.emit('');\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
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanso-protocol/search-bar",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"@angular/core": ">=21.0.0",
|
|
7
7
|
"@angular/common": ">=21.0.0",
|
|
8
|
-
"@kanso-protocol/core": ">=
|
|
9
|
-
"@kanso-protocol/button": ">=
|
|
10
|
-
"@kanso-protocol/i18n": ">=
|
|
8
|
+
"@kanso-protocol/core": ">=2.0.0",
|
|
9
|
+
"@kanso-protocol/button": ">=2.0.0",
|
|
10
|
+
"@kanso-protocol/i18n": ">=2.0.0"
|
|
11
11
|
},
|
|
12
12
|
"description": "Kanso Protocol — search-bar (pattern).",
|
|
13
13
|
"author": "GregNBlack",
|