@kanso-protocol/search-bar 1.0.1 → 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
- <kp-button
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
- </kp-button>
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: "kp-button", inputs: ["size", "variant", "color", "disabled", "loading", "iconOnly", "forceState"] }, { kind: "component", type: KpIconComponent, selector: "kp-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
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
- <kp-button
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
- </kp-button>
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": "1.0.1",
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": ">=1.0.1",
9
- "@kanso-protocol/button": ">=1.0.1",
10
- "@kanso-protocol/i18n": ">=1.0.1"
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",