@ship-ui/core 0.22.4 → 0.22.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -3
- package/assets/mcp/components.json +32 -32
- package/bin/ship-fg-scanner +0 -0
- package/fesm2022/ship-ui-core-ship-kbd.mjs +96 -0
- package/fesm2022/ship-ui-core-ship-kbd.mjs.map +1 -0
- package/fesm2022/ship-ui-core-ship-list.mjs +2 -2
- package/fesm2022/ship-ui-core-ship-list.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-spotlight.mjs +590 -0
- package/fesm2022/ship-ui-core-ship-spotlight.mjs.map +1 -0
- package/package.json +9 -1
- package/types/ship-ui-core-ship-kbd.d.ts +19 -0
- package/types/ship-ui-core-ship-spotlight.d.ts +83 -0
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ npm i -S @ship-ui/core
|
|
|
20
20
|
### Add styles inside your src/styles.scss
|
|
21
21
|
|
|
22
22
|
```scss
|
|
23
|
-
@use 'ship-ui/core/styles';
|
|
23
|
+
@use '@ship-ui/core/styles';
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
### Inside your angular.json file
|
|
@@ -32,7 +32,7 @@ you need to add the ship assets to your assets array this is to add the ship def
|
|
|
32
32
|
"src/assets",
|
|
33
33
|
{
|
|
34
34
|
"glob": "**/*",
|
|
35
|
-
"input": "./node_modules
|
|
35
|
+
"input": "./node_modules/@ship-ui/core/assets",
|
|
36
36
|
"output": "./ship-ui-assets/"
|
|
37
37
|
}
|
|
38
38
|
]
|
|
@@ -73,6 +73,51 @@ You now wanna add when to build the font and when to watch so it works well toge
|
|
|
73
73
|
}
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
+
## AI & Developer Experience
|
|
77
|
+
|
|
78
|
+
ShipUI comes with built-in tools to enhance your development workflow through AI and IDE integrations.
|
|
79
|
+
|
|
80
|
+
### Model Context Protocol (MCP)
|
|
81
|
+
|
|
82
|
+
ShipUI includes an MCP server that allows AI agents (like Cursor, Claude Desktop, or custom tools) to understand and correctly use ShipUI components.
|
|
83
|
+
|
|
84
|
+
#### Setup in Editors
|
|
85
|
+
|
|
86
|
+
To use ShipUI with your favorite AI-powered editor, add the following configuration:
|
|
87
|
+
|
|
88
|
+
**Command:** `npx @ship-ui/core ship-mcp`
|
|
89
|
+
|
|
90
|
+
- **Cursor**:
|
|
91
|
+
1. Go to **Settings** > **Models** > **MCP**.
|
|
92
|
+
2. Click **+ Add new MCP server**.
|
|
93
|
+
3. Name: `ShipUI`, Type: `command`, Command: `npx @ship-ui/core ship-mcp`.
|
|
94
|
+
- **Antigravity**:
|
|
95
|
+
1. Open your workspace or global configuration.
|
|
96
|
+
2. Add `@ship-ui/core` to your `mcpServers` list or run with `npx @ship-ui/core ship-mcp`.
|
|
97
|
+
- **Claude Desktop**:
|
|
98
|
+
Add to your `claude_desktop_config.json`:
|
|
99
|
+
```json
|
|
100
|
+
"mcpServers": {
|
|
101
|
+
"ship-ui": {
|
|
102
|
+
"command": "npx",
|
|
103
|
+
"args": ["-y", "@ship-ui/core", "ship-mcp"]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
To manually verify the server is working:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
npx @ship-ui/core ship-mcp
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### VS Code Snippets
|
|
115
|
+
|
|
116
|
+
The library includes high-quality TextMate snippets for all components, including "full" versions with choices for colors, variants, and sizes.
|
|
117
|
+
|
|
118
|
+
To use them in VS Code, you can add a link to the snippets file in your `.vscode/settings.json` or copy the content to your project's snippets. The file is located at:
|
|
119
|
+
`./node_modules/@ship-ui/core/snippets/ship-ui.code-snippets`
|
|
120
|
+
|
|
76
121
|
## Follow our progress
|
|
77
122
|
|
|
78
123
|
We have a [todos](documents/todos.md) file where we try keep track of features/bugs/blockers currently in pipeline etc
|
|
@@ -81,7 +126,6 @@ We have a [todos](documents/todos.md) file where we try keep track of features/b
|
|
|
81
126
|
|
|
82
127
|
- <strike>There was raised thoughts on separating out the icon utility the decision are for now not to since this package are depended on those icons for now, we can open up a new debate about it if some comes with a solid argument for it</strike>
|
|
83
128
|
- <strike>For safari `<18` the selects does not support using options so you must use `<sh-option>` instead of `<option>` (this is fixed in the next select version currently suffixed with `-new`)</strike> (We circumvent this by using a templates instead of options)
|
|
84
|
-
- Known issues for selects when having two selects editing the same value and it is a multi select and searchable they clear out when opened also when selecting a new item they clear the rest of the list - not a very likely scenario but it is something to keep in mind (Your UI probably should not allow this scenario write an issue if you think it should be possible with a good explanation and example)
|
|
85
129
|
|
|
86
130
|
## Contributors
|
|
87
131
|
|
|
@@ -1,12 +1,37 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
|
-
"name": "
|
|
4
|
-
"selector": "
|
|
5
|
-
"path": "core/projects/ship-ui/src/lib/
|
|
3
|
+
"name": "ChildComponent",
|
|
4
|
+
"selector": "app-child",
|
|
5
|
+
"path": "core/projects/ship-ui/src/lib/utilities/create-input-example.component.ts",
|
|
6
6
|
"description": "",
|
|
7
7
|
"keywords": [],
|
|
8
8
|
"inputs": [],
|
|
9
9
|
"outputs": [],
|
|
10
|
+
"methods": [
|
|
11
|
+
{
|
|
12
|
+
"name": "toggleTextInput",
|
|
13
|
+
"parameters": "",
|
|
14
|
+
"returnType": "any",
|
|
15
|
+
"description": ""
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"cssVariables": [],
|
|
19
|
+
"examples": []
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"name": "ShipFileDragDrop",
|
|
23
|
+
"selector": "[shDragDrop]",
|
|
24
|
+
"path": "core/projects/ship-ui/src/lib/directives/ship-file-drag-drop.directive.ts",
|
|
25
|
+
"description": "",
|
|
26
|
+
"keywords": [],
|
|
27
|
+
"inputs": [],
|
|
28
|
+
"outputs": [
|
|
29
|
+
{
|
|
30
|
+
"name": "filesDropped",
|
|
31
|
+
"type": "FileList",
|
|
32
|
+
"description": ""
|
|
33
|
+
}
|
|
34
|
+
],
|
|
10
35
|
"methods": [],
|
|
11
36
|
"cssVariables": [],
|
|
12
37
|
"examples": []
|
|
@@ -43,24 +68,6 @@
|
|
|
43
68
|
"cssVariables": [],
|
|
44
69
|
"examples": []
|
|
45
70
|
},
|
|
46
|
-
{
|
|
47
|
-
"name": "ShipFileDragDrop",
|
|
48
|
-
"selector": "[shDragDrop]",
|
|
49
|
-
"path": "core/projects/ship-ui/src/lib/directives/ship-file-drag-drop.directive.ts",
|
|
50
|
-
"description": "",
|
|
51
|
-
"keywords": [],
|
|
52
|
-
"inputs": [],
|
|
53
|
-
"outputs": [
|
|
54
|
-
{
|
|
55
|
-
"name": "filesDropped",
|
|
56
|
-
"type": "FileList",
|
|
57
|
-
"description": ""
|
|
58
|
-
}
|
|
59
|
-
],
|
|
60
|
-
"methods": [],
|
|
61
|
-
"cssVariables": [],
|
|
62
|
-
"examples": []
|
|
63
|
-
},
|
|
64
71
|
{
|
|
65
72
|
"name": "ShipTooltipWrapper",
|
|
66
73
|
"selector": "ship-tooltip-wrapper",
|
|
@@ -129,21 +136,14 @@
|
|
|
129
136
|
"examples": []
|
|
130
137
|
},
|
|
131
138
|
{
|
|
132
|
-
"name": "
|
|
133
|
-
"selector": "
|
|
134
|
-
"path": "core/projects/ship-ui/src/lib/
|
|
139
|
+
"name": "ShipPreventWheel",
|
|
140
|
+
"selector": "[shPreventWheel]",
|
|
141
|
+
"path": "core/projects/ship-ui/src/lib/directives/ship-prevent-wheel.directive.ts",
|
|
135
142
|
"description": "",
|
|
136
143
|
"keywords": [],
|
|
137
144
|
"inputs": [],
|
|
138
145
|
"outputs": [],
|
|
139
|
-
"methods": [
|
|
140
|
-
{
|
|
141
|
-
"name": "toggleTextInput",
|
|
142
|
-
"parameters": "",
|
|
143
|
-
"returnType": "any",
|
|
144
|
-
"description": ""
|
|
145
|
-
}
|
|
146
|
-
],
|
|
146
|
+
"methods": [],
|
|
147
147
|
"cssVariables": [],
|
|
148
148
|
"examples": []
|
|
149
149
|
},
|
package/bin/ship-fg-scanner
CHANGED
|
Binary file
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, PLATFORM_ID, input, booleanAttribute, computed, Component } from '@angular/core';
|
|
3
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
4
|
+
|
|
5
|
+
class ShipKbd {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.#platformId = inject(PLATFORM_ID);
|
|
8
|
+
this.meta = input(false, { ...(ngDevMode ? { debugName: "meta" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
9
|
+
this.shift = input(false, { ...(ngDevMode ? { debugName: "shift" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
10
|
+
this.alt = input(false, { ...(ngDevMode ? { debugName: "alt" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
11
|
+
this.ctrl = input(false, { ...(ngDevMode ? { debugName: "ctrl" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
12
|
+
this.enter = input(false, { ...(ngDevMode ? { debugName: "enter" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
13
|
+
this.escape = input(false, { ...(ngDevMode ? { debugName: "escape" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
14
|
+
this.backspace = input(false, { ...(ngDevMode ? { debugName: "backspace" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
15
|
+
this.isMac = computed(() => {
|
|
16
|
+
if (!isPlatformBrowser(this.#platformId))
|
|
17
|
+
return false;
|
|
18
|
+
return navigator.userAgent.toLowerCase().includes('mac');
|
|
19
|
+
}, /* @ts-ignore */
|
|
20
|
+
...(ngDevMode ? [{ debugName: "isMac" }] : /* istanbul ignore next */ []));
|
|
21
|
+
this.hasContent = computed(() => {
|
|
22
|
+
// If there is any content, it will be projected. We just need to render the separator
|
|
23
|
+
// if there are modifiers before it. Angular ng-content always renders if projected,
|
|
24
|
+
// so we assume true if they use the component with innerHTML (which we can't easily check
|
|
25
|
+
// statically, but we can assume if it's used as a wrapper, there's content).
|
|
26
|
+
// Actually, we can check if any modifiers exist to prepend.
|
|
27
|
+
return true;
|
|
28
|
+
}, /* @ts-ignore */
|
|
29
|
+
...(ngDevMode ? [{ debugName: "hasContent" }] : /* istanbul ignore next */ []));
|
|
30
|
+
this.displayKeys = computed(() => {
|
|
31
|
+
const keys = [];
|
|
32
|
+
const mac = this.isMac();
|
|
33
|
+
if (this.meta())
|
|
34
|
+
keys.push(mac ? '⌘' : 'Win');
|
|
35
|
+
if (this.ctrl())
|
|
36
|
+
keys.push(mac ? '⌃' : 'Ctrl');
|
|
37
|
+
if (this.alt())
|
|
38
|
+
keys.push(mac ? '⌥' : 'Alt');
|
|
39
|
+
if (this.shift())
|
|
40
|
+
keys.push(mac ? '⇧' : 'Shift');
|
|
41
|
+
if (this.enter())
|
|
42
|
+
keys.push(mac ? '↵' : 'Enter');
|
|
43
|
+
if (this.escape())
|
|
44
|
+
keys.push(mac ? '⎋' : 'Esc');
|
|
45
|
+
if (this.backspace())
|
|
46
|
+
keys.push(mac ? '⌫' : 'Backspace');
|
|
47
|
+
// Remove duplicates if they specify both meta and ctrl on windows (which both map to Ctrl)
|
|
48
|
+
return Array.from(new Set(keys));
|
|
49
|
+
}, /* @ts-ignore */
|
|
50
|
+
...(ngDevMode ? [{ debugName: "displayKeys" }] : /* istanbul ignore next */ []));
|
|
51
|
+
}
|
|
52
|
+
#platformId;
|
|
53
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ShipKbd, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
54
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: ShipKbd, isStandalone: true, selector: "sh-kbd, [sh-kbd]", inputs: { meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, shift: { classPropertyName: "shift", publicName: "shift", isSignal: true, isRequired: false, transformFunction: null }, alt: { classPropertyName: "alt", publicName: "alt", isSignal: true, isRequired: false, transformFunction: null }, ctrl: { classPropertyName: "ctrl", publicName: "ctrl", isSignal: true, isRequired: false, transformFunction: null }, enter: { classPropertyName: "enter", publicName: "enter", isSignal: true, isRequired: false, transformFunction: null }, escape: { classPropertyName: "escape", publicName: "escape", isSignal: true, isRequired: false, transformFunction: null }, backspace: { classPropertyName: "backspace", publicName: "backspace", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
55
|
+
@for (key of displayKeys(); track $index) {
|
|
56
|
+
<span class="key-part">{{ key }}</span>
|
|
57
|
+
@if (!isMac() && !$last) {
|
|
58
|
+
<span class="separator">+</span>
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
@if (hasContent()) {
|
|
62
|
+
@if (!isMac() && displayKeys().length > 0) {
|
|
63
|
+
<span class="separator">+</span>
|
|
64
|
+
}
|
|
65
|
+
<span class="content">
|
|
66
|
+
<ng-content></ng-content>
|
|
67
|
+
</span>
|
|
68
|
+
}
|
|
69
|
+
`, isInline: true, styles: [":host{display:inline-flex;align-items:center;font-family:inherit;background:rgb(from var(--base-2) r g b/80%);border:1px solid rgb(from var(--base-4) r g b/60%);padding:.0625rem .25rem;border-radius:var(--shape-1);font-weight:700;color:var(--base-11);gap:.125rem;font-size:.9em}:host .separator{color:var(--base-8);font-weight:400;margin:0 .125rem}:host .content{text-transform:uppercase}\n"] }); }
|
|
70
|
+
}
|
|
71
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ShipKbd, decorators: [{
|
|
72
|
+
type: Component,
|
|
73
|
+
args: [{ selector: 'sh-kbd, [sh-kbd]', standalone: true, template: `
|
|
74
|
+
@for (key of displayKeys(); track $index) {
|
|
75
|
+
<span class="key-part">{{ key }}</span>
|
|
76
|
+
@if (!isMac() && !$last) {
|
|
77
|
+
<span class="separator">+</span>
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
@if (hasContent()) {
|
|
81
|
+
@if (!isMac() && displayKeys().length > 0) {
|
|
82
|
+
<span class="separator">+</span>
|
|
83
|
+
}
|
|
84
|
+
<span class="content">
|
|
85
|
+
<ng-content></ng-content>
|
|
86
|
+
</span>
|
|
87
|
+
}
|
|
88
|
+
`, styles: [":host{display:inline-flex;align-items:center;font-family:inherit;background:rgb(from var(--base-2) r g b/80%);border:1px solid rgb(from var(--base-4) r g b/60%);padding:.0625rem .25rem;border-radius:var(--shape-1);font-weight:700;color:var(--base-11);gap:.125rem;font-size:.9em}:host .separator{color:var(--base-8);font-weight:400;margin:0 .125rem}:host .content{text-transform:uppercase}\n"] }]
|
|
89
|
+
}], propDecorators: { meta: [{ type: i0.Input, args: [{ isSignal: true, alias: "meta", required: false }] }], shift: [{ type: i0.Input, args: [{ isSignal: true, alias: "shift", required: false }] }], alt: [{ type: i0.Input, args: [{ isSignal: true, alias: "alt", required: false }] }], ctrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "ctrl", required: false }] }], enter: [{ type: i0.Input, args: [{ isSignal: true, alias: "enter", required: false }] }], escape: [{ type: i0.Input, args: [{ isSignal: true, alias: "escape", required: false }] }], backspace: [{ type: i0.Input, args: [{ isSignal: true, alias: "backspace", required: false }] }] } });
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Generated bundle index. Do not edit.
|
|
93
|
+
*/
|
|
94
|
+
|
|
95
|
+
export { ShipKbd };
|
|
96
|
+
//# sourceMappingURL=ship-ui-core-ship-kbd.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ship-ui-core-ship-kbd.mjs","sources":["../../../projects/ship-ui/ship-kbd/ship-kbd.ts","../../../projects/ship-ui/ship-kbd/ship-ui-core-ship-kbd.ts"],"sourcesContent":["import { booleanAttribute, Component, computed, inject, input, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\n@Component({\n selector: 'sh-kbd, [sh-kbd]',\n standalone: true,\n template: `\n @for (key of displayKeys(); track $index) {\n <span class=\"key-part\">{{ key }}</span>\n @if (!isMac() && !$last) {\n <span class=\"separator\">+</span>\n }\n }\n @if (hasContent()) {\n @if (!isMac() && displayKeys().length > 0) {\n <span class=\"separator\">+</span>\n }\n <span class=\"content\">\n <ng-content></ng-content>\n </span>\n }\n `,\n styleUrl: './ship-kbd.scss',\n})\nexport class ShipKbd {\n #platformId = inject(PLATFORM_ID);\n\n meta = input<boolean, string | boolean>(false, { transform: booleanAttribute });\n shift = input<boolean, string | boolean>(false, { transform: booleanAttribute });\n alt = input<boolean, string | boolean>(false, { transform: booleanAttribute });\n ctrl = input<boolean, string | boolean>(false, { transform: booleanAttribute });\n enter = input<boolean, string | boolean>(false, { transform: booleanAttribute });\n escape = input<boolean, string | boolean>(false, { transform: booleanAttribute });\n backspace = input<boolean, string | boolean>(false, { transform: booleanAttribute });\n\n isMac = computed(() => {\n if (!isPlatformBrowser(this.#platformId)) return false;\n return navigator.userAgent.toLowerCase().includes('mac');\n });\n\n hasContent = computed(() => {\n // If there is any content, it will be projected. We just need to render the separator\n // if there are modifiers before it. Angular ng-content always renders if projected,\n // so we assume true if they use the component with innerHTML (which we can't easily check\n // statically, but we can assume if it's used as a wrapper, there's content).\n // Actually, we can check if any modifiers exist to prepend. \n return true; \n });\n\n displayKeys = computed(() => {\n const keys: string[] = [];\n const mac = this.isMac();\n\n if (this.meta()) keys.push(mac ? '⌘' : 'Win');\n if (this.ctrl()) keys.push(mac ? '⌃' : 'Ctrl');\n if (this.alt()) keys.push(mac ? '⌥' : 'Alt');\n if (this.shift()) keys.push(mac ? '⇧' : 'Shift');\n if (this.enter()) keys.push(mac ? '↵' : 'Enter');\n if (this.escape()) keys.push(mac ? '⎋' : 'Esc');\n if (this.backspace()) keys.push(mac ? '⌫' : 'Backspace');\n\n // Remove duplicates if they specify both meta and ctrl on windows (which both map to Ctrl)\n return Array.from(new Set(keys));\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -5,13 +5,13 @@ class ShipList {
|
|
|
5
5
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ShipList, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6
6
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.0", type: ShipList, isStandalone: true, selector: "sh-list", ngImport: i0, template: `
|
|
7
7
|
<ng-content />
|
|
8
|
-
`, isInline: true, styles: ["sh-list{--list-s: var(--shape-2);--list-active-bg: var(--base-1);--list-color: var(--base-9);--list-active-bs: none;--list-item-b: 1px solid transparent;--list-item-active-b: 1px solid --list-active-bg;--list-p: 1.25rem 1rem;--list-item-p: .5rem .75rem;--list-item-gap: .5rem;width:100%;padding:var(--list-p);gap:.5rem;display:flex;flex-direction:column}sh-list.base-1{--list-active-bg: var(--base-1);--list-active-bs: var(--box-shadow-20)}sh-list.outlined{--list-active-bg: transparent;--list-active-bs: none;--list-item-b: 1px solid transparent;--list-item-active-b: 1px solid var(--primary-8)}sh-list:empty{padding:0}sh-list>[title]{color:var(--base-8);margin:0 .75rem;font:var(--paragraph-30);line-height:1.5rem}sh-list[shsortable] [item]:active{transform:scale(1)}sh-list>[action],sh-list>[item]{border-radius:var(--list-s);padding:var(--list-item-p);font:var(--paragraph-30B);color:var(--list-color);border:var(--list-item-b);display:flex;align-items:center;gap:var(--list-item-gap);width:100%;-webkit-user-select:none;user-select:none;appearance:none;border:0;text-align:left;text-wrap:balance;background-color:transparent;text-decoration:none;transition:transform 125ms linear,box-shadow 125ms linear;transform:scale(1)}sh-list>[action]:active,sh-list>[item]:active{--list-active-bs: var(--box-shadow-10);transform:scale(.98)}sh-list>[action]:focus,sh-list>[item]:focus{outline:none}sh-list>[action]:focus-visible,sh-list>[item]:focus-visible{outline:2px solid var(--primary-8);outline-offset:2px}sh-list>[action] [suffix],sh-list>[item] [suffix]{margin-left:auto;color:var(--base-8)}sh-list :has(input),sh-list>[action]{cursor:pointer}sh-list>[item]:has(input:checked),sh-list>[action]:has(input:checked),sh-list>[action].active,sh-list>[action].selected{--list-color: var(--base-12);background-color:var(--list-active-bg);box-shadow:var(--list-active-bs);border:var(--list-item-active-b)}sh-list.primary>[item]:has(input:checked) sh-icon:first-child,sh-list.primary>[action]:has(input:checked) sh-icon:first-child,sh-list.primary>[action].active sh-icon:first-child,sh-list.primary>[action].selected sh-icon:first-child{color:var(--primary-8)}sh-list.accent>[item]:has(input:checked) sh-icon:first-child,sh-list.accent>[action]:has(input:checked) sh-icon:first-child,sh-list.accent>[action].active sh-icon:first-child,sh-list.accent>[action].selected sh-icon:first-child{color:var(--accent-8)}sh-list.warn>[item]:has(input:checked) sh-icon:first-child,sh-list.warn>[action]:has(input:checked) sh-icon:first-child,sh-list.warn>[action].active sh-icon:first-child,sh-list.warn>[action].selected sh-icon:first-child{color:var(--warn-8)}sh-list.error>[item]:has(input:checked) sh-icon:first-child,sh-list.error>[action]:has(input:checked) sh-icon:first-child,sh-list.error>[action].active sh-icon:first-child,sh-list.error>[action].selected sh-icon:first-child{color:var(--error-8)}sh-list.success>[item]:has(input:checked) sh-icon:first-child,sh-list.success>[action]:has(input:checked) sh-icon:first-child,sh-list.success>[action].active sh-icon:first-child,sh-list.success>[action].selected sh-icon:first-child{color:var(--success-8)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
8
|
+
`, isInline: true, styles: ["sh-list{--list-s: var(--shape-2);--list-active-bg: var(--base-1);--list-color: var(--base-9);--list-active-bs: none;--list-item-b: 1px solid transparent;--list-item-active-b: 1px solid --list-active-bg;--list-p: 1.25rem 1rem;--list-item-p: .5rem .75rem;--list-item-gap: .5rem;width:100%;padding:var(--list-p);gap:.5rem;display:flex;flex-direction:column}sh-list.base-1{--list-active-bg: var(--base-1);--list-active-bs: var(--box-shadow-20)}sh-list.outlined{--list-active-bg: transparent;--list-active-bs: none;--list-item-b: 1px solid transparent;--list-item-active-b: 1px solid var(--primary-8)}sh-list.type-b{--list-p: 0;--list-item-p: .625rem .75rem;--list-item-gap: .75rem;--list-s: var(--shape-2)}sh-list.type-b>[action],sh-list.type-b>[item]{color:var(--base-10)}sh-list.type-b>[action].active,sh-list.type-b>[action].selected,sh-list.type-b>[item].active,sh-list.type-b>[item].selected{background:rgb(from var(--base-3) r g b/90%);color:var(--base-12)}sh-list.type-b>[action].active sh-icon:first-child,sh-list.type-b>[action].selected sh-icon:first-child,sh-list.type-b>[item].active sh-icon:first-child,sh-list.type-b>[item].selected sh-icon:first-child{color:var(--primary-8)}sh-list.type-b>[action].active .description,sh-list.type-b>[action].selected .description,sh-list.type-b>[item].active .description,sh-list.type-b>[item].selected .description{color:var(--base-9)}sh-list.type-b>[action] sh-icon:first-child,sh-list.type-b>[item] sh-icon:first-child{font-size:1.125rem;color:var(--base-7);transition:color .15s ease}sh-list.type-b>[action] .text-group,sh-list.type-b>[item] .text-group{display:flex;flex-direction:column;flex:1}sh-list.type-b>[action] .label,sh-list.type-b>[item] .label{font:var(--paragraph-30B)}sh-list.type-b>[action] .description,sh-list.type-b>[item] .description{font:var(--paragraph-40);color:var(--base-7);transition:color .15s ease}sh-list.type-b>[action] .shortcut,sh-list.type-b>[item] .shortcut{display:flex;gap:.25rem}sh-list.type-b>[action] .shortcut kbd,sh-list.type-b>[item] .shortcut kbd{font-family:inherit;background:rgb(from var(--base-3) r g b/80%);border:1px solid rgb(from var(--base-4) r g b/60%);color:var(--base-8);border-radius:var(--shape-1);padding:.125rem .375rem;font-size:.6875rem;line-height:1;box-shadow:0 1px #0000001a}sh-list:empty{padding:0}sh-list>[title]{color:var(--base-8);margin:0 .75rem;font:var(--paragraph-30);line-height:1.5rem}sh-list[shsortable] [item]:active{transform:scale(1)}sh-list>[action],sh-list>[item]{border-radius:var(--list-s);padding:var(--list-item-p);font:var(--paragraph-30B);color:var(--list-color);border:var(--list-item-b);display:flex;align-items:center;gap:var(--list-item-gap);width:100%;-webkit-user-select:none;user-select:none;appearance:none;border:0;text-align:left;text-wrap:balance;background-color:transparent;text-decoration:none;transition:transform 125ms linear,box-shadow 125ms linear;transform:scale(1)}sh-list>[action]:active,sh-list>[item]:active{--list-active-bs: var(--box-shadow-10);transform:scale(.98)}sh-list>[action]:focus,sh-list>[item]:focus{outline:none}sh-list>[action]:focus-visible,sh-list>[item]:focus-visible{outline:2px solid var(--primary-8);outline-offset:2px}sh-list>[action] [suffix],sh-list>[item] [suffix]{margin-left:auto;color:var(--base-8)}sh-list :has(input),sh-list>[action]{cursor:pointer}sh-list>[item]:has(input:checked),sh-list>[action]:has(input:checked),sh-list>[action].active,sh-list>[action].selected{--list-color: var(--base-12);background-color:var(--list-active-bg);box-shadow:var(--list-active-bs);border:var(--list-item-active-b)}sh-list.primary>[item]:has(input:checked) sh-icon:first-child,sh-list.primary>[action]:has(input:checked) sh-icon:first-child,sh-list.primary>[action].active sh-icon:first-child,sh-list.primary>[action].selected sh-icon:first-child{color:var(--primary-8)}sh-list.accent>[item]:has(input:checked) sh-icon:first-child,sh-list.accent>[action]:has(input:checked) sh-icon:first-child,sh-list.accent>[action].active sh-icon:first-child,sh-list.accent>[action].selected sh-icon:first-child{color:var(--accent-8)}sh-list.warn>[item]:has(input:checked) sh-icon:first-child,sh-list.warn>[action]:has(input:checked) sh-icon:first-child,sh-list.warn>[action].active sh-icon:first-child,sh-list.warn>[action].selected sh-icon:first-child{color:var(--warn-8)}sh-list.error>[item]:has(input:checked) sh-icon:first-child,sh-list.error>[action]:has(input:checked) sh-icon:first-child,sh-list.error>[action].active sh-icon:first-child,sh-list.error>[action].selected sh-icon:first-child{color:var(--error-8)}sh-list.success>[item]:has(input:checked) sh-icon:first-child,sh-list.success>[action]:has(input:checked) sh-icon:first-child,sh-list.success>[action].active sh-icon:first-child,sh-list.success>[action].selected sh-icon:first-child{color:var(--success-8)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
9
9
|
}
|
|
10
10
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ShipList, decorators: [{
|
|
11
11
|
type: Component,
|
|
12
12
|
args: [{ selector: 'sh-list', encapsulation: ViewEncapsulation.None, imports: [], template: `
|
|
13
13
|
<ng-content />
|
|
14
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: ["sh-list{--list-s: var(--shape-2);--list-active-bg: var(--base-1);--list-color: var(--base-9);--list-active-bs: none;--list-item-b: 1px solid transparent;--list-item-active-b: 1px solid --list-active-bg;--list-p: 1.25rem 1rem;--list-item-p: .5rem .75rem;--list-item-gap: .5rem;width:100%;padding:var(--list-p);gap:.5rem;display:flex;flex-direction:column}sh-list.base-1{--list-active-bg: var(--base-1);--list-active-bs: var(--box-shadow-20)}sh-list.outlined{--list-active-bg: transparent;--list-active-bs: none;--list-item-b: 1px solid transparent;--list-item-active-b: 1px solid var(--primary-8)}sh-list:empty{padding:0}sh-list>[title]{color:var(--base-8);margin:0 .75rem;font:var(--paragraph-30);line-height:1.5rem}sh-list[shsortable] [item]:active{transform:scale(1)}sh-list>[action],sh-list>[item]{border-radius:var(--list-s);padding:var(--list-item-p);font:var(--paragraph-30B);color:var(--list-color);border:var(--list-item-b);display:flex;align-items:center;gap:var(--list-item-gap);width:100%;-webkit-user-select:none;user-select:none;appearance:none;border:0;text-align:left;text-wrap:balance;background-color:transparent;text-decoration:none;transition:transform 125ms linear,box-shadow 125ms linear;transform:scale(1)}sh-list>[action]:active,sh-list>[item]:active{--list-active-bs: var(--box-shadow-10);transform:scale(.98)}sh-list>[action]:focus,sh-list>[item]:focus{outline:none}sh-list>[action]:focus-visible,sh-list>[item]:focus-visible{outline:2px solid var(--primary-8);outline-offset:2px}sh-list>[action] [suffix],sh-list>[item] [suffix]{margin-left:auto;color:var(--base-8)}sh-list :has(input),sh-list>[action]{cursor:pointer}sh-list>[item]:has(input:checked),sh-list>[action]:has(input:checked),sh-list>[action].active,sh-list>[action].selected{--list-color: var(--base-12);background-color:var(--list-active-bg);box-shadow:var(--list-active-bs);border:var(--list-item-active-b)}sh-list.primary>[item]:has(input:checked) sh-icon:first-child,sh-list.primary>[action]:has(input:checked) sh-icon:first-child,sh-list.primary>[action].active sh-icon:first-child,sh-list.primary>[action].selected sh-icon:first-child{color:var(--primary-8)}sh-list.accent>[item]:has(input:checked) sh-icon:first-child,sh-list.accent>[action]:has(input:checked) sh-icon:first-child,sh-list.accent>[action].active sh-icon:first-child,sh-list.accent>[action].selected sh-icon:first-child{color:var(--accent-8)}sh-list.warn>[item]:has(input:checked) sh-icon:first-child,sh-list.warn>[action]:has(input:checked) sh-icon:first-child,sh-list.warn>[action].active sh-icon:first-child,sh-list.warn>[action].selected sh-icon:first-child{color:var(--warn-8)}sh-list.error>[item]:has(input:checked) sh-icon:first-child,sh-list.error>[action]:has(input:checked) sh-icon:first-child,sh-list.error>[action].active sh-icon:first-child,sh-list.error>[action].selected sh-icon:first-child{color:var(--error-8)}sh-list.success>[item]:has(input:checked) sh-icon:first-child,sh-list.success>[action]:has(input:checked) sh-icon:first-child,sh-list.success>[action].active sh-icon:first-child,sh-list.success>[action].selected sh-icon:first-child{color:var(--success-8)}\n"] }]
|
|
14
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: ["sh-list{--list-s: var(--shape-2);--list-active-bg: var(--base-1);--list-color: var(--base-9);--list-active-bs: none;--list-item-b: 1px solid transparent;--list-item-active-b: 1px solid --list-active-bg;--list-p: 1.25rem 1rem;--list-item-p: .5rem .75rem;--list-item-gap: .5rem;width:100%;padding:var(--list-p);gap:.5rem;display:flex;flex-direction:column}sh-list.base-1{--list-active-bg: var(--base-1);--list-active-bs: var(--box-shadow-20)}sh-list.outlined{--list-active-bg: transparent;--list-active-bs: none;--list-item-b: 1px solid transparent;--list-item-active-b: 1px solid var(--primary-8)}sh-list.type-b{--list-p: 0;--list-item-p: .625rem .75rem;--list-item-gap: .75rem;--list-s: var(--shape-2)}sh-list.type-b>[action],sh-list.type-b>[item]{color:var(--base-10)}sh-list.type-b>[action].active,sh-list.type-b>[action].selected,sh-list.type-b>[item].active,sh-list.type-b>[item].selected{background:rgb(from var(--base-3) r g b/90%);color:var(--base-12)}sh-list.type-b>[action].active sh-icon:first-child,sh-list.type-b>[action].selected sh-icon:first-child,sh-list.type-b>[item].active sh-icon:first-child,sh-list.type-b>[item].selected sh-icon:first-child{color:var(--primary-8)}sh-list.type-b>[action].active .description,sh-list.type-b>[action].selected .description,sh-list.type-b>[item].active .description,sh-list.type-b>[item].selected .description{color:var(--base-9)}sh-list.type-b>[action] sh-icon:first-child,sh-list.type-b>[item] sh-icon:first-child{font-size:1.125rem;color:var(--base-7);transition:color .15s ease}sh-list.type-b>[action] .text-group,sh-list.type-b>[item] .text-group{display:flex;flex-direction:column;flex:1}sh-list.type-b>[action] .label,sh-list.type-b>[item] .label{font:var(--paragraph-30B)}sh-list.type-b>[action] .description,sh-list.type-b>[item] .description{font:var(--paragraph-40);color:var(--base-7);transition:color .15s ease}sh-list.type-b>[action] .shortcut,sh-list.type-b>[item] .shortcut{display:flex;gap:.25rem}sh-list.type-b>[action] .shortcut kbd,sh-list.type-b>[item] .shortcut kbd{font-family:inherit;background:rgb(from var(--base-3) r g b/80%);border:1px solid rgb(from var(--base-4) r g b/60%);color:var(--base-8);border-radius:var(--shape-1);padding:.125rem .375rem;font-size:.6875rem;line-height:1;box-shadow:0 1px #0000001a}sh-list:empty{padding:0}sh-list>[title]{color:var(--base-8);margin:0 .75rem;font:var(--paragraph-30);line-height:1.5rem}sh-list[shsortable] [item]:active{transform:scale(1)}sh-list>[action],sh-list>[item]{border-radius:var(--list-s);padding:var(--list-item-p);font:var(--paragraph-30B);color:var(--list-color);border:var(--list-item-b);display:flex;align-items:center;gap:var(--list-item-gap);width:100%;-webkit-user-select:none;user-select:none;appearance:none;border:0;text-align:left;text-wrap:balance;background-color:transparent;text-decoration:none;transition:transform 125ms linear,box-shadow 125ms linear;transform:scale(1)}sh-list>[action]:active,sh-list>[item]:active{--list-active-bs: var(--box-shadow-10);transform:scale(.98)}sh-list>[action]:focus,sh-list>[item]:focus{outline:none}sh-list>[action]:focus-visible,sh-list>[item]:focus-visible{outline:2px solid var(--primary-8);outline-offset:2px}sh-list>[action] [suffix],sh-list>[item] [suffix]{margin-left:auto;color:var(--base-8)}sh-list :has(input),sh-list>[action]{cursor:pointer}sh-list>[item]:has(input:checked),sh-list>[action]:has(input:checked),sh-list>[action].active,sh-list>[action].selected{--list-color: var(--base-12);background-color:var(--list-active-bg);box-shadow:var(--list-active-bs);border:var(--list-item-active-b)}sh-list.primary>[item]:has(input:checked) sh-icon:first-child,sh-list.primary>[action]:has(input:checked) sh-icon:first-child,sh-list.primary>[action].active sh-icon:first-child,sh-list.primary>[action].selected sh-icon:first-child{color:var(--primary-8)}sh-list.accent>[item]:has(input:checked) sh-icon:first-child,sh-list.accent>[action]:has(input:checked) sh-icon:first-child,sh-list.accent>[action].active sh-icon:first-child,sh-list.accent>[action].selected sh-icon:first-child{color:var(--accent-8)}sh-list.warn>[item]:has(input:checked) sh-icon:first-child,sh-list.warn>[action]:has(input:checked) sh-icon:first-child,sh-list.warn>[action].active sh-icon:first-child,sh-list.warn>[action].selected sh-icon:first-child{color:var(--warn-8)}sh-list.error>[item]:has(input:checked) sh-icon:first-child,sh-list.error>[action]:has(input:checked) sh-icon:first-child,sh-list.error>[action].active sh-icon:first-child,sh-list.error>[action].selected sh-icon:first-child{color:var(--error-8)}sh-list.success>[item]:has(input:checked) sh-icon:first-child,sh-list.success>[action]:has(input:checked) sh-icon:first-child,sh-list.success>[action].active sh-icon:first-child,sh-list.success>[action].selected sh-icon:first-child{color:var(--success-8)}\n"] }]
|
|
15
15
|
}] });
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ship-ui-core-ship-list.mjs","sources":["../../../projects/ship-ui/ship-list/ship-list.ts","../../../projects/ship-ui/ship-list/ship-ui-core-ship-list.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n selector: 'sh-list',\n styleUrl: './ship-list.scss',\n encapsulation: ViewEncapsulation.None,\n imports: [],\n template: `\n <ng-content />\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ShipList {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;MAYa,QAAQ,CAAA;8GAAR,QAAQ,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAR,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,QAAQ,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EALT;;AAET,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,
|
|
1
|
+
{"version":3,"file":"ship-ui-core-ship-list.mjs","sources":["../../../projects/ship-ui/ship-list/ship-list.ts","../../../projects/ship-ui/ship-list/ship-ui-core-ship-list.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n selector: 'sh-list',\n styleUrl: './ship-list.scss',\n encapsulation: ViewEncapsulation.None,\n imports: [],\n template: `\n <ng-content />\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ShipList {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;MAYa,QAAQ,CAAA;8GAAR,QAAQ,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAR,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,QAAQ,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EALT;;AAET,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,wuJAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA,CAAA;;2FAGU,QAAQ,EAAA,UAAA,EAAA,CAAA;kBAVpB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,SAAS,iBAEJ,iBAAiB,CAAC,IAAI,EAAA,OAAA,EAC5B,EAAE,EAAA,QAAA,EACD;;GAET,EAAA,eAAA,EACgB,uBAAuB,CAAC,MAAM,EAAA,MAAA,EAAA,CAAA,wuJAAA,CAAA,EAAA;;;ACVjD;;AAEG;;;;"}
|
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, viewChild, input, model, output, computed, signal, effect, ChangeDetectionStrategy, ViewEncapsulation, Component, inject, DOCUMENT, DestroyRef, Injectable } from '@angular/core';
|
|
3
|
+
import { ShipIcon } from '@ship-ui/core/ship-icon';
|
|
4
|
+
import { ShipList } from '@ship-ui/core/ship-list';
|
|
5
|
+
import { ShipKbd } from '@ship-ui/core/ship-kbd';
|
|
6
|
+
import { ShipDialogService } from '@ship-ui/core/ship-dialog';
|
|
7
|
+
|
|
8
|
+
const SHIP_SPOTLIGHT_CONFIG = new InjectionToken('SHIP_SPOTLIGHT_CONFIG');
|
|
9
|
+
function provideShipSpotlight(config) {
|
|
10
|
+
return {
|
|
11
|
+
provide: SHIP_SPOTLIGHT_CONFIG,
|
|
12
|
+
useValue: config,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
class ShipSpotlight {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.inputRef = viewChild('inputRef', /* @ts-ignore */
|
|
18
|
+
...(ngDevMode ? [{ debugName: "inputRef" }] : /* istanbul ignore next */ []));
|
|
19
|
+
this.resultsRef = viewChild('resultsRef', /* @ts-ignore */
|
|
20
|
+
...(ngDevMode ? [{ debugName: "resultsRef" }] : /* istanbul ignore next */ []));
|
|
21
|
+
// Input config passed from ShipDialogService
|
|
22
|
+
this.data = input(/* @ts-ignore */
|
|
23
|
+
...(ngDevMode ? [undefined, { debugName: "data" }] : /* istanbul ignore next */ []));
|
|
24
|
+
// Standard inputs (fallback)
|
|
25
|
+
this.items = input([], /* @ts-ignore */
|
|
26
|
+
...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
27
|
+
this.placeholder = input('Search actions, settings, or pages...', /* @ts-ignore */
|
|
28
|
+
...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
29
|
+
this.customFilter = input(false, /* @ts-ignore */
|
|
30
|
+
...(ngDevMode ? [{ debugName: "customFilter" }] : /* istanbul ignore next */ []));
|
|
31
|
+
this.searchQuery = model('', /* @ts-ignore */
|
|
32
|
+
...(ngDevMode ? [{ debugName: "searchQuery" }] : /* istanbul ignore next */ []));
|
|
33
|
+
this.itemSelected = output();
|
|
34
|
+
this.closed = output();
|
|
35
|
+
// Merged config properties
|
|
36
|
+
this.mergedItems = computed(() => this.data()?.items ?? this.items(), /* @ts-ignore */
|
|
37
|
+
...(ngDevMode ? [{ debugName: "mergedItems" }] : /* istanbul ignore next */ []));
|
|
38
|
+
this.mergedPlaceholder = computed(() => this.data()?.placeholder ?? this.placeholder(), /* @ts-ignore */
|
|
39
|
+
...(ngDevMode ? [{ debugName: "mergedPlaceholder" }] : /* istanbul ignore next */ []));
|
|
40
|
+
this.mergedCustomFilter = computed(() => this.data()?.customFilter ?? this.customFilter(), /* @ts-ignore */
|
|
41
|
+
...(ngDevMode ? [{ debugName: "mergedCustomFilter" }] : /* istanbul ignore next */ []));
|
|
42
|
+
this.activeOptionIndex = signal(0, /* @ts-ignore */
|
|
43
|
+
...(ngDevMode ? [{ debugName: "activeOptionIndex" }] : /* istanbul ignore next */ []));
|
|
44
|
+
// Computes the scored and filtered flat list of items
|
|
45
|
+
this.flatFilteredItems = computed(() => {
|
|
46
|
+
const query = this.searchQuery().toLowerCase().trim();
|
|
47
|
+
const allItems = this.mergedItems();
|
|
48
|
+
if (this.mergedCustomFilter() || !query) {
|
|
49
|
+
return allItems;
|
|
50
|
+
}
|
|
51
|
+
const scored = allItems
|
|
52
|
+
.map((item) => {
|
|
53
|
+
const labelScore = this.#calculateMatchScore(item.label.toLowerCase(), query);
|
|
54
|
+
const descScore = item.description ? this.#calculateMatchScore(item.description.toLowerCase(), query) : 0;
|
|
55
|
+
return { item, score: Math.max(labelScore, descScore) };
|
|
56
|
+
})
|
|
57
|
+
.filter((x) => x.score > 0)
|
|
58
|
+
.sort((a, b) => b.score - a.score);
|
|
59
|
+
return scored.map((x) => x.item);
|
|
60
|
+
}, /* @ts-ignore */
|
|
61
|
+
...(ngDevMode ? [{ debugName: "flatFilteredItems" }] : /* istanbul ignore next */ []));
|
|
62
|
+
// Groups flat list of items by category and precomputes flat indices
|
|
63
|
+
this.groupedFilteredItems = computed(() => {
|
|
64
|
+
const flat = this.flatFilteredItems();
|
|
65
|
+
const groups = [];
|
|
66
|
+
let currentFlatIndex = 0;
|
|
67
|
+
flat.forEach((item) => {
|
|
68
|
+
const cat = item.category || 'Actions';
|
|
69
|
+
let group = groups.find((g) => g.category === cat);
|
|
70
|
+
if (!group) {
|
|
71
|
+
group = { category: cat, items: [] };
|
|
72
|
+
groups.push(group);
|
|
73
|
+
}
|
|
74
|
+
group.items.push({ item, flatIndex: currentFlatIndex++ });
|
|
75
|
+
});
|
|
76
|
+
return groups;
|
|
77
|
+
}, /* @ts-ignore */
|
|
78
|
+
...(ngDevMode ? [{ debugName: "groupedFilteredItems" }] : /* istanbul ignore next */ []));
|
|
79
|
+
this.validateItemsEffect = effect(() => {
|
|
80
|
+
const items = this.mergedItems();
|
|
81
|
+
for (const item of items) {
|
|
82
|
+
if (item.shortcut) {
|
|
83
|
+
this.#validateShortcut(item.shortcut);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}, /* @ts-ignore */
|
|
87
|
+
...(ngDevMode ? [{ debugName: "validateItemsEffect" }] : /* istanbul ignore next */ []));
|
|
88
|
+
// Sync initial search query if provided in dialog data
|
|
89
|
+
effect(() => {
|
|
90
|
+
const initialQuery = this.data()?.searchQuery;
|
|
91
|
+
if (initialQuery !== undefined) {
|
|
92
|
+
this.searchQuery.set(initialQuery);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
// Auto-focus input when the view is initialized
|
|
96
|
+
effect(() => {
|
|
97
|
+
const inputEl = this.inputRef()?.nativeElement;
|
|
98
|
+
if (inputEl && typeof inputEl.focus === 'function') {
|
|
99
|
+
setTimeout(() => inputEl.focus(), 50);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
// Scroll active item into view
|
|
103
|
+
effect(() => {
|
|
104
|
+
const index = this.activeOptionIndex();
|
|
105
|
+
if (index > -1) {
|
|
106
|
+
queueMicrotask(() => this.scrollToActiveItem());
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
onSearchInput(event) {
|
|
111
|
+
const val = event.target.value;
|
|
112
|
+
this.searchQuery.set(val);
|
|
113
|
+
this.activeOptionIndex.set(0);
|
|
114
|
+
}
|
|
115
|
+
clearSearch() {
|
|
116
|
+
this.searchQuery.set('');
|
|
117
|
+
const inputEl = this.inputRef()?.nativeElement;
|
|
118
|
+
if (inputEl) {
|
|
119
|
+
inputEl.value = '';
|
|
120
|
+
if (typeof inputEl.focus === 'function') {
|
|
121
|
+
inputEl.focus();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
this.activeOptionIndex.set(0);
|
|
125
|
+
}
|
|
126
|
+
onKeyDown(event) {
|
|
127
|
+
// Check if the event matches any item shortcut
|
|
128
|
+
const allItems = this.mergedItems();
|
|
129
|
+
const shortcutMatch = allItems.find((item) => item.shortcut && this.#checkShortcutMatch(event, item.shortcut));
|
|
130
|
+
if (shortcutMatch) {
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
event.stopPropagation();
|
|
133
|
+
// Delay selection to ensure the browser honors preventDefault before the DOM node is potentially destroyed
|
|
134
|
+
setTimeout(() => this.selectItem(shortcutMatch), 10);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const flat = this.flatFilteredItems();
|
|
138
|
+
if (flat.length === 0)
|
|
139
|
+
return;
|
|
140
|
+
if (event.key === 'ArrowDown') {
|
|
141
|
+
event.preventDefault();
|
|
142
|
+
const nextIdx = (this.activeOptionIndex() + 1) % flat.length;
|
|
143
|
+
this.activeOptionIndex.set(nextIdx);
|
|
144
|
+
}
|
|
145
|
+
else if (event.key === 'ArrowUp') {
|
|
146
|
+
event.preventDefault();
|
|
147
|
+
const prevIdx = (this.activeOptionIndex() - 1 + flat.length) % flat.length;
|
|
148
|
+
this.activeOptionIndex.set(prevIdx);
|
|
149
|
+
}
|
|
150
|
+
else if (event.key === 'Tab') {
|
|
151
|
+
event.preventDefault();
|
|
152
|
+
if (event.shiftKey) {
|
|
153
|
+
const prevIdx = (this.activeOptionIndex() - 1 + flat.length) % flat.length;
|
|
154
|
+
this.activeOptionIndex.set(prevIdx);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
const nextIdx = (this.activeOptionIndex() + 1) % flat.length;
|
|
158
|
+
this.activeOptionIndex.set(nextIdx);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else if (event.key === 'Enter') {
|
|
162
|
+
event.preventDefault();
|
|
163
|
+
const selected = flat[this.activeOptionIndex()];
|
|
164
|
+
if (selected) {
|
|
165
|
+
this.selectItem(selected);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
selectItem(item) {
|
|
170
|
+
this.itemSelected.emit(item);
|
|
171
|
+
this.closed.emit();
|
|
172
|
+
}
|
|
173
|
+
scrollToActiveItem() {
|
|
174
|
+
const resultsEl = this.resultsRef()?.nativeElement;
|
|
175
|
+
if (!resultsEl)
|
|
176
|
+
return;
|
|
177
|
+
const activeEl = resultsEl.querySelector('[action].active');
|
|
178
|
+
if (activeEl && typeof activeEl.scrollIntoView === 'function') {
|
|
179
|
+
activeEl.scrollIntoView({ block: 'nearest' });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
parseShortcutKeys(shortcut) {
|
|
183
|
+
if (!shortcut)
|
|
184
|
+
return [];
|
|
185
|
+
return shortcut.split('+').map((s) => s.trim().toLowerCase());
|
|
186
|
+
}
|
|
187
|
+
#validateShortcut(shortcut) {
|
|
188
|
+
const normalized = shortcut
|
|
189
|
+
.toLowerCase()
|
|
190
|
+
.split('+')
|
|
191
|
+
.map((k) => k.trim())
|
|
192
|
+
.join('+');
|
|
193
|
+
const reserved = [
|
|
194
|
+
'meta+n', 'ctrl+n',
|
|
195
|
+
'meta+t', 'ctrl+t',
|
|
196
|
+
'meta+w', 'ctrl+w',
|
|
197
|
+
'meta+q', 'ctrl+q',
|
|
198
|
+
'meta+r', 'ctrl+r',
|
|
199
|
+
'meta+l', 'ctrl+l',
|
|
200
|
+
'meta+shift+n', 'ctrl+shift+n',
|
|
201
|
+
'meta+shift+t', 'ctrl+shift+t',
|
|
202
|
+
'meta+shift+w', 'ctrl+shift+w',
|
|
203
|
+
'cmd+n', 'cmd+t', 'cmd+w', 'cmd+q', 'cmd+r', 'cmd+l',
|
|
204
|
+
'cmd+shift+n', 'cmd+shift+t', 'cmd+shift+w',
|
|
205
|
+
];
|
|
206
|
+
if (reserved.includes(normalized)) {
|
|
207
|
+
throw new Error(`[ShipUI Error] The shortcut "${shortcut}" uses a reserved browser hotkey that cannot be reliably prevented (e.g. New Window, New Tab). Please choose a different shortcut.`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
#checkShortcutMatch(event, shortcut) {
|
|
211
|
+
if (!shortcut)
|
|
212
|
+
return false;
|
|
213
|
+
const keys = this.parseShortcutKeys(shortcut);
|
|
214
|
+
const needsMeta = keys.includes('meta') || keys.includes('cmd') || keys.includes('command');
|
|
215
|
+
const needsCtrl = keys.includes('ctrl') || keys.includes('control');
|
|
216
|
+
const needsAlt = keys.includes('alt') || keys.includes('option');
|
|
217
|
+
const needsShift = keys.includes('shift');
|
|
218
|
+
if (event.metaKey !== needsMeta)
|
|
219
|
+
return false;
|
|
220
|
+
if (event.ctrlKey !== needsCtrl)
|
|
221
|
+
return false;
|
|
222
|
+
if (event.altKey !== needsAlt)
|
|
223
|
+
return false;
|
|
224
|
+
if (event.shiftKey !== needsShift)
|
|
225
|
+
return false;
|
|
226
|
+
const mainKeys = keys.filter((k) => !['meta', 'cmd', 'command', 'ctrl', 'control', 'alt', 'option', 'shift'].includes(k));
|
|
227
|
+
if (mainKeys.length === 1) {
|
|
228
|
+
return event.key.toLowerCase() === mainKeys[0].toLowerCase();
|
|
229
|
+
}
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
#calculateMatchScore(option, input) {
|
|
233
|
+
if (!input)
|
|
234
|
+
return 0;
|
|
235
|
+
let score = 0;
|
|
236
|
+
let lastIndex = -1;
|
|
237
|
+
let matchCount = 0;
|
|
238
|
+
let inSequence = true;
|
|
239
|
+
for (let i = 0; i < input.length; i++) {
|
|
240
|
+
const char = input[i];
|
|
241
|
+
if (option.length > lastIndex + 1 && option[lastIndex + 1] === char) {
|
|
242
|
+
score += i === 0 ? 100 : 150;
|
|
243
|
+
lastIndex++;
|
|
244
|
+
matchCount++;
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
const charIndex = option.indexOf(char, lastIndex + 1);
|
|
248
|
+
if (i > 0) {
|
|
249
|
+
inSequence = false;
|
|
250
|
+
}
|
|
251
|
+
if (charIndex === -1) {
|
|
252
|
+
return 0;
|
|
253
|
+
}
|
|
254
|
+
score += 100;
|
|
255
|
+
lastIndex = charIndex;
|
|
256
|
+
matchCount++;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (inSequence && input.length === matchCount) {
|
|
260
|
+
score += 1000;
|
|
261
|
+
}
|
|
262
|
+
score += matchCount * 20;
|
|
263
|
+
return score;
|
|
264
|
+
}
|
|
265
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ShipSpotlight, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
266
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: ShipSpotlight, isStandalone: true, selector: "sh-spotlight", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, customFilter: { classPropertyName: "customFilter", publicName: "customFilter", isSignal: true, isRequired: false, transformFunction: null }, searchQuery: { classPropertyName: "searchQuery", publicName: "searchQuery", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { searchQuery: "searchQueryChange", itemSelected: "itemSelected", closed: "closed" }, viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["inputRef"], descendants: true, isSignal: true }, { propertyName: "resultsRef", first: true, predicate: ["resultsRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
267
|
+
<div class="sh-spotlight-container">
|
|
268
|
+
<div class="sh-spotlight-search-bar">
|
|
269
|
+
<sh-icon class="sh-spotlight-search-icon">magnifying-glass</sh-icon>
|
|
270
|
+
<input
|
|
271
|
+
#inputRef
|
|
272
|
+
type="text"
|
|
273
|
+
class="sh-spotlight-input"
|
|
274
|
+
[placeholder]="mergedPlaceholder()"
|
|
275
|
+
[value]="searchQuery()"
|
|
276
|
+
(input)="onSearchInput($event)"
|
|
277
|
+
(keydown)="onKeyDown($event)" />
|
|
278
|
+
@if (searchQuery()) {
|
|
279
|
+
<button class="sh-spotlight-clear-btn" (click)="clearSearch()">
|
|
280
|
+
<sh-icon>x-bold</sh-icon>
|
|
281
|
+
</button>
|
|
282
|
+
}
|
|
283
|
+
</div>
|
|
284
|
+
|
|
285
|
+
<div #resultsRef class="sh-spotlight-results">
|
|
286
|
+
@if (groupedFilteredItems().length > 0) {
|
|
287
|
+
@for (group of groupedFilteredItems(); track group.category) {
|
|
288
|
+
<div class="sh-spotlight-category">
|
|
289
|
+
<div class="sh-spotlight-category-title">{{ group.category }}</div>
|
|
290
|
+
<sh-list class="type-b">
|
|
291
|
+
@for (itemWithIdx of group.items; track itemWithIdx.item.id) {
|
|
292
|
+
<button
|
|
293
|
+
action
|
|
294
|
+
type="button"
|
|
295
|
+
[class.active]="itemWithIdx.flatIndex === activeOptionIndex()"
|
|
296
|
+
(mouseenter)="activeOptionIndex.set(itemWithIdx.flatIndex)"
|
|
297
|
+
(click)="selectItem(itemWithIdx.item)">
|
|
298
|
+
@if (itemWithIdx.item.icon) {
|
|
299
|
+
<sh-icon>{{ itemWithIdx.item.icon }}</sh-icon>
|
|
300
|
+
}
|
|
301
|
+
<div class="text-group">
|
|
302
|
+
<span class="label">{{ itemWithIdx.item.label }}</span>
|
|
303
|
+
@if (itemWithIdx.item.description) {
|
|
304
|
+
<span class="description">{{ itemWithIdx.item.description }}</span>
|
|
305
|
+
}
|
|
306
|
+
</div>
|
|
307
|
+
@if (itemWithIdx.item.shortcut) {
|
|
308
|
+
<span class="shortcut">
|
|
309
|
+
@for (key of parseShortcutKeys(itemWithIdx.item.shortcut); track key) {
|
|
310
|
+
<sh-kbd
|
|
311
|
+
[meta]="key === 'meta' || key === 'cmd' || key === 'command'"
|
|
312
|
+
[shift]="key === 'shift'"
|
|
313
|
+
[alt]="key === 'alt' || key === 'option'"
|
|
314
|
+
[ctrl]="key === 'ctrl' || key === 'control'"
|
|
315
|
+
[enter]="key === 'enter' || key === 'return'"
|
|
316
|
+
[escape]="key === 'escape' || key === 'esc'"
|
|
317
|
+
[backspace]="key === 'backspace'"
|
|
318
|
+
>
|
|
319
|
+
@if (!['meta', 'cmd', 'command', 'shift', 'alt', 'option', 'ctrl', 'control', 'enter', 'return', 'escape', 'esc', 'backspace'].includes(key)) {
|
|
320
|
+
{{ key }}
|
|
321
|
+
}
|
|
322
|
+
</sh-kbd>
|
|
323
|
+
}
|
|
324
|
+
</span>
|
|
325
|
+
}
|
|
326
|
+
</button>
|
|
327
|
+
}
|
|
328
|
+
</sh-list>
|
|
329
|
+
</div>
|
|
330
|
+
}
|
|
331
|
+
} @else {
|
|
332
|
+
<div class="sh-spotlight-no-results">
|
|
333
|
+
<sh-icon class="sh-spotlight-no-results-icon">warning-octagon</sh-icon>
|
|
334
|
+
<span class="sh-spotlight-no-results-text">No results found for "{{ searchQuery() }}"</span>
|
|
335
|
+
</div>
|
|
336
|
+
}
|
|
337
|
+
</div>
|
|
338
|
+
|
|
339
|
+
<div class="sh-spotlight-footer">
|
|
340
|
+
<span class="sh-spotlight-footer-tip">
|
|
341
|
+
<sh-kbd>↓</sh-kbd> <sh-kbd>↑</sh-kbd>
|
|
342
|
+
to navigate
|
|
343
|
+
</span>
|
|
344
|
+
<span class="sh-spotlight-footer-tip">
|
|
345
|
+
<sh-kbd enter></sh-kbd>
|
|
346
|
+
to select
|
|
347
|
+
</span>
|
|
348
|
+
<span class="sh-spotlight-footer-tip">
|
|
349
|
+
<sh-kbd escape></sh-kbd>
|
|
350
|
+
to close
|
|
351
|
+
</span>
|
|
352
|
+
</div>
|
|
353
|
+
</div>
|
|
354
|
+
`, isInline: true, styles: ["sh-spotlight{display:block;width:100%}sh-spotlight .sh-spotlight-container{display:flex;flex-direction:column;width:100%;overflow:hidden}sh-spotlight .sh-spotlight-search-bar{display:flex;align-items:center;padding:1rem;border-bottom:1px solid rgb(from var(--base-4) r g b/30%);gap:.75rem}sh-spotlight .sh-spotlight-search-icon{font-size:1.25rem;color:var(--base-8)}sh-spotlight .sh-spotlight-input{flex:1;background:transparent;border:none;outline:none;font:var(--paragraph-20);color:var(--base-12)}sh-spotlight .sh-spotlight-input::placeholder{color:var(--base-7)}sh-spotlight .sh-spotlight-clear-btn{background:transparent;border:none;padding:.25rem;cursor:pointer;color:var(--base-7);display:flex;align-items:center;justify-content:center;border-radius:var(--shape-1)}sh-spotlight .sh-spotlight-clear-btn:hover{background:var(--base-3);color:var(--base-10)}sh-spotlight .sh-spotlight-clear-btn sh-icon{font-size:.875rem}sh-spotlight .sh-spotlight-results{max-height:21.875rem;padding:.5rem;display:flex;flex-direction:column;gap:.5rem;outline:none;overflow-x:hidden;overflow-y:auto;-webkit-overflow-scrolling:auto}sh-spotlight .sh-spotlight-category-title{font:var(--paragraph-40B);color:var(--base-7);padding:.5rem .75rem .25rem;text-transform:uppercase;letter-spacing:.0625rem}sh-spotlight .sh-spotlight-no-results{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:2.5rem 1.25rem;color:var(--base-7);gap:.75rem}sh-spotlight .sh-spotlight-no-results-icon{font-size:2rem;color:var(--base-6)}sh-spotlight .sh-spotlight-no-results-text{font:var(--paragraph-30)}sh-spotlight .sh-spotlight-footer{display:flex;align-items:center;padding:.75rem 1rem;background:rgb(from var(--base-1) r g b/90%);border-top:1px solid rgb(from var(--base-4) r g b/30%);gap:1rem;font-size:.6875rem;color:var(--base-7)}sh-spotlight .sh-spotlight-footer .sh-spotlight-footer-tip{display:flex;align-items:center;gap:.25rem}\n"], dependencies: [{ kind: "component", type: ShipIcon, selector: "sh-icon", inputs: ["color", "size"] }, { kind: "component", type: ShipList, selector: "sh-list" }, { kind: "component", type: ShipKbd, selector: "sh-kbd, [sh-kbd]", inputs: ["meta", "shift", "alt", "ctrl", "enter", "escape", "backspace"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
355
|
+
}
|
|
356
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ShipSpotlight, decorators: [{
|
|
357
|
+
type: Component,
|
|
358
|
+
args: [{ selector: 'sh-spotlight', encapsulation: ViewEncapsulation.None, imports: [ShipIcon, ShipList, ShipKbd], template: `
|
|
359
|
+
<div class="sh-spotlight-container">
|
|
360
|
+
<div class="sh-spotlight-search-bar">
|
|
361
|
+
<sh-icon class="sh-spotlight-search-icon">magnifying-glass</sh-icon>
|
|
362
|
+
<input
|
|
363
|
+
#inputRef
|
|
364
|
+
type="text"
|
|
365
|
+
class="sh-spotlight-input"
|
|
366
|
+
[placeholder]="mergedPlaceholder()"
|
|
367
|
+
[value]="searchQuery()"
|
|
368
|
+
(input)="onSearchInput($event)"
|
|
369
|
+
(keydown)="onKeyDown($event)" />
|
|
370
|
+
@if (searchQuery()) {
|
|
371
|
+
<button class="sh-spotlight-clear-btn" (click)="clearSearch()">
|
|
372
|
+
<sh-icon>x-bold</sh-icon>
|
|
373
|
+
</button>
|
|
374
|
+
}
|
|
375
|
+
</div>
|
|
376
|
+
|
|
377
|
+
<div #resultsRef class="sh-spotlight-results">
|
|
378
|
+
@if (groupedFilteredItems().length > 0) {
|
|
379
|
+
@for (group of groupedFilteredItems(); track group.category) {
|
|
380
|
+
<div class="sh-spotlight-category">
|
|
381
|
+
<div class="sh-spotlight-category-title">{{ group.category }}</div>
|
|
382
|
+
<sh-list class="type-b">
|
|
383
|
+
@for (itemWithIdx of group.items; track itemWithIdx.item.id) {
|
|
384
|
+
<button
|
|
385
|
+
action
|
|
386
|
+
type="button"
|
|
387
|
+
[class.active]="itemWithIdx.flatIndex === activeOptionIndex()"
|
|
388
|
+
(mouseenter)="activeOptionIndex.set(itemWithIdx.flatIndex)"
|
|
389
|
+
(click)="selectItem(itemWithIdx.item)">
|
|
390
|
+
@if (itemWithIdx.item.icon) {
|
|
391
|
+
<sh-icon>{{ itemWithIdx.item.icon }}</sh-icon>
|
|
392
|
+
}
|
|
393
|
+
<div class="text-group">
|
|
394
|
+
<span class="label">{{ itemWithIdx.item.label }}</span>
|
|
395
|
+
@if (itemWithIdx.item.description) {
|
|
396
|
+
<span class="description">{{ itemWithIdx.item.description }}</span>
|
|
397
|
+
}
|
|
398
|
+
</div>
|
|
399
|
+
@if (itemWithIdx.item.shortcut) {
|
|
400
|
+
<span class="shortcut">
|
|
401
|
+
@for (key of parseShortcutKeys(itemWithIdx.item.shortcut); track key) {
|
|
402
|
+
<sh-kbd
|
|
403
|
+
[meta]="key === 'meta' || key === 'cmd' || key === 'command'"
|
|
404
|
+
[shift]="key === 'shift'"
|
|
405
|
+
[alt]="key === 'alt' || key === 'option'"
|
|
406
|
+
[ctrl]="key === 'ctrl' || key === 'control'"
|
|
407
|
+
[enter]="key === 'enter' || key === 'return'"
|
|
408
|
+
[escape]="key === 'escape' || key === 'esc'"
|
|
409
|
+
[backspace]="key === 'backspace'"
|
|
410
|
+
>
|
|
411
|
+
@if (!['meta', 'cmd', 'command', 'shift', 'alt', 'option', 'ctrl', 'control', 'enter', 'return', 'escape', 'esc', 'backspace'].includes(key)) {
|
|
412
|
+
{{ key }}
|
|
413
|
+
}
|
|
414
|
+
</sh-kbd>
|
|
415
|
+
}
|
|
416
|
+
</span>
|
|
417
|
+
}
|
|
418
|
+
</button>
|
|
419
|
+
}
|
|
420
|
+
</sh-list>
|
|
421
|
+
</div>
|
|
422
|
+
}
|
|
423
|
+
} @else {
|
|
424
|
+
<div class="sh-spotlight-no-results">
|
|
425
|
+
<sh-icon class="sh-spotlight-no-results-icon">warning-octagon</sh-icon>
|
|
426
|
+
<span class="sh-spotlight-no-results-text">No results found for "{{ searchQuery() }}"</span>
|
|
427
|
+
</div>
|
|
428
|
+
}
|
|
429
|
+
</div>
|
|
430
|
+
|
|
431
|
+
<div class="sh-spotlight-footer">
|
|
432
|
+
<span class="sh-spotlight-footer-tip">
|
|
433
|
+
<sh-kbd>↓</sh-kbd> <sh-kbd>↑</sh-kbd>
|
|
434
|
+
to navigate
|
|
435
|
+
</span>
|
|
436
|
+
<span class="sh-spotlight-footer-tip">
|
|
437
|
+
<sh-kbd enter></sh-kbd>
|
|
438
|
+
to select
|
|
439
|
+
</span>
|
|
440
|
+
<span class="sh-spotlight-footer-tip">
|
|
441
|
+
<sh-kbd escape></sh-kbd>
|
|
442
|
+
to close
|
|
443
|
+
</span>
|
|
444
|
+
</div>
|
|
445
|
+
</div>
|
|
446
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: ["sh-spotlight{display:block;width:100%}sh-spotlight .sh-spotlight-container{display:flex;flex-direction:column;width:100%;overflow:hidden}sh-spotlight .sh-spotlight-search-bar{display:flex;align-items:center;padding:1rem;border-bottom:1px solid rgb(from var(--base-4) r g b/30%);gap:.75rem}sh-spotlight .sh-spotlight-search-icon{font-size:1.25rem;color:var(--base-8)}sh-spotlight .sh-spotlight-input{flex:1;background:transparent;border:none;outline:none;font:var(--paragraph-20);color:var(--base-12)}sh-spotlight .sh-spotlight-input::placeholder{color:var(--base-7)}sh-spotlight .sh-spotlight-clear-btn{background:transparent;border:none;padding:.25rem;cursor:pointer;color:var(--base-7);display:flex;align-items:center;justify-content:center;border-radius:var(--shape-1)}sh-spotlight .sh-spotlight-clear-btn:hover{background:var(--base-3);color:var(--base-10)}sh-spotlight .sh-spotlight-clear-btn sh-icon{font-size:.875rem}sh-spotlight .sh-spotlight-results{max-height:21.875rem;padding:.5rem;display:flex;flex-direction:column;gap:.5rem;outline:none;overflow-x:hidden;overflow-y:auto;-webkit-overflow-scrolling:auto}sh-spotlight .sh-spotlight-category-title{font:var(--paragraph-40B);color:var(--base-7);padding:.5rem .75rem .25rem;text-transform:uppercase;letter-spacing:.0625rem}sh-spotlight .sh-spotlight-no-results{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:2.5rem 1.25rem;color:var(--base-7);gap:.75rem}sh-spotlight .sh-spotlight-no-results-icon{font-size:2rem;color:var(--base-6)}sh-spotlight .sh-spotlight-no-results-text{font:var(--paragraph-30)}sh-spotlight .sh-spotlight-footer{display:flex;align-items:center;padding:.75rem 1rem;background:rgb(from var(--base-1) r g b/90%);border-top:1px solid rgb(from var(--base-4) r g b/30%);gap:1rem;font-size:.6875rem;color:var(--base-7)}sh-spotlight .sh-spotlight-footer .sh-spotlight-footer-tip{display:flex;align-items:center;gap:.25rem}\n"] }]
|
|
447
|
+
}], ctorParameters: () => [], propDecorators: { inputRef: [{ type: i0.ViewChild, args: ['inputRef', { isSignal: true }] }], resultsRef: [{ type: i0.ViewChild, args: ['resultsRef', { isSignal: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], customFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "customFilter", required: false }] }], searchQuery: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchQuery", required: false }] }, { type: i0.Output, args: ["searchQueryChange"] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
|
|
448
|
+
|
|
449
|
+
class ShipSpotlightService {
|
|
450
|
+
#document;
|
|
451
|
+
#dialogService;
|
|
452
|
+
#config;
|
|
453
|
+
#nextId;
|
|
454
|
+
#registries;
|
|
455
|
+
#globalItemSelected;
|
|
456
|
+
#isShortcutsEnabled;
|
|
457
|
+
#aggregatedItems;
|
|
458
|
+
constructor() {
|
|
459
|
+
this.#document = inject(DOCUMENT);
|
|
460
|
+
this.#dialogService = inject(ShipDialogService);
|
|
461
|
+
this.#config = inject(SHIP_SPOTLIGHT_CONFIG, { optional: true });
|
|
462
|
+
this.#nextId = 0;
|
|
463
|
+
this.#registries = signal([], /* @ts-ignore */
|
|
464
|
+
...(ngDevMode ? [{ debugName: "#registries" }] : /* istanbul ignore next */ []));
|
|
465
|
+
this.#globalItemSelected = signal(null, /* @ts-ignore */
|
|
466
|
+
...(ngDevMode ? [{ debugName: "#globalItemSelected" }] : /* istanbul ignore next */ []));
|
|
467
|
+
this.globalItemSelected = this.#globalItemSelected.asReadonly();
|
|
468
|
+
this.#isShortcutsEnabled = signal(false, /* @ts-ignore */
|
|
469
|
+
...(ngDevMode ? [{ debugName: "#isShortcutsEnabled" }] : /* istanbul ignore next */ []));
|
|
470
|
+
this.isShortcutsEnabled = this.#isShortcutsEnabled.asReadonly();
|
|
471
|
+
this.#aggregatedItems = computed(() => {
|
|
472
|
+
const registries = this.#registries();
|
|
473
|
+
const defaults = this.#config?.defaultItems ?? [];
|
|
474
|
+
let aggregated = [...defaults];
|
|
475
|
+
for (const entry of registries) {
|
|
476
|
+
if (entry.overwrite) {
|
|
477
|
+
aggregated = [...entry.items];
|
|
478
|
+
}
|
|
479
|
+
else {
|
|
480
|
+
aggregated.push(...entry.items);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return aggregated;
|
|
484
|
+
}, /* @ts-ignore */
|
|
485
|
+
...(ngDevMode ? [{ debugName: "#aggregatedItems" }] : /* istanbul ignore next */ []));
|
|
486
|
+
this.hasOverwriteItems = computed(() => this.#registries().some((r) => r.overwrite), /* @ts-ignore */
|
|
487
|
+
...(ngDevMode ? [{ debugName: "hasOverwriteItems" }] : /* istanbul ignore next */ []));
|
|
488
|
+
this.#contextualRegistryId = null;
|
|
489
|
+
this.#globalShortcutListener = null;
|
|
490
|
+
this.#globalShortcutOptions = null;
|
|
491
|
+
if (this.#config?.enableShortcuts !== false) {
|
|
492
|
+
this.enableGlobalShortcuts();
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
registerItems(items, overwrite = false) {
|
|
496
|
+
const id = this.#nextId++;
|
|
497
|
+
this.#registries.update((regs) => [...regs, { id, items, overwrite }]);
|
|
498
|
+
const cleanup = () => {
|
|
499
|
+
this.#registries.update((regs) => regs.filter((r) => r.id !== id));
|
|
500
|
+
};
|
|
501
|
+
try {
|
|
502
|
+
const destroyRef = inject(DestroyRef);
|
|
503
|
+
destroyRef.onDestroy(cleanup);
|
|
504
|
+
}
|
|
505
|
+
catch {
|
|
506
|
+
// Ignore if not called in injection context
|
|
507
|
+
}
|
|
508
|
+
return cleanup;
|
|
509
|
+
}
|
|
510
|
+
#contextualRegistryId;
|
|
511
|
+
setContextualItems(items, overwrite = false) {
|
|
512
|
+
if (this.#contextualRegistryId !== null) {
|
|
513
|
+
const oldId = this.#contextualRegistryId;
|
|
514
|
+
this.#registries.update((regs) => regs.filter((r) => r.id !== oldId));
|
|
515
|
+
}
|
|
516
|
+
const id = this.#nextId++;
|
|
517
|
+
this.#contextualRegistryId = id;
|
|
518
|
+
this.#registries.update((regs) => [...regs, { id, items, overwrite }]);
|
|
519
|
+
}
|
|
520
|
+
clearContextualItems() {
|
|
521
|
+
if (this.#contextualRegistryId !== null) {
|
|
522
|
+
const oldId = this.#contextualRegistryId;
|
|
523
|
+
this.#registries.update((regs) => regs.filter((r) => r.id !== oldId));
|
|
524
|
+
this.#contextualRegistryId = null;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
#globalShortcutListener;
|
|
528
|
+
#globalShortcutOptions;
|
|
529
|
+
enableGlobalShortcuts(options) {
|
|
530
|
+
if (this.#globalShortcutListener) {
|
|
531
|
+
this.disableGlobalShortcuts();
|
|
532
|
+
}
|
|
533
|
+
if (options) {
|
|
534
|
+
this.#globalShortcutOptions = options;
|
|
535
|
+
}
|
|
536
|
+
this.#isShortcutsEnabled.set(true);
|
|
537
|
+
this.#globalShortcutListener = (event) => {
|
|
538
|
+
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'k') {
|
|
539
|
+
event.preventDefault();
|
|
540
|
+
const instance = this.open(this.#globalShortcutOptions || undefined);
|
|
541
|
+
const sub = instance.itemSelected.subscribe((item) => {
|
|
542
|
+
this.#globalItemSelected.set(item);
|
|
543
|
+
});
|
|
544
|
+
instance.closed.subscribe(() => sub.unsubscribe());
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
this.#document.addEventListener('keydown', this.#globalShortcutListener);
|
|
548
|
+
}
|
|
549
|
+
disableGlobalShortcuts() {
|
|
550
|
+
if (this.#globalShortcutListener) {
|
|
551
|
+
this.#document.removeEventListener('keydown', this.#globalShortcutListener);
|
|
552
|
+
this.#globalShortcutListener = null;
|
|
553
|
+
}
|
|
554
|
+
this.#isShortcutsEnabled.set(false);
|
|
555
|
+
}
|
|
556
|
+
open(options) {
|
|
557
|
+
const finalOptions = {
|
|
558
|
+
...options,
|
|
559
|
+
items: options?.items ?? this.#aggregatedItems(),
|
|
560
|
+
};
|
|
561
|
+
const dialogRef = this.#dialogService.open(ShipSpotlight, {
|
|
562
|
+
data: finalOptions,
|
|
563
|
+
class: 'spotlight-dialog',
|
|
564
|
+
closeOnOutsideClick: true,
|
|
565
|
+
closeOnEsc: true,
|
|
566
|
+
width: '600px',
|
|
567
|
+
maxWidth: '90vw',
|
|
568
|
+
});
|
|
569
|
+
return {
|
|
570
|
+
close: () => dialogRef.close(),
|
|
571
|
+
itemSelected: dialogRef.component.itemSelected,
|
|
572
|
+
closed: dialogRef.closed,
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ShipSpotlightService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
576
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ShipSpotlightService, providedIn: 'root' }); }
|
|
577
|
+
}
|
|
578
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ShipSpotlightService, decorators: [{
|
|
579
|
+
type: Injectable,
|
|
580
|
+
args: [{
|
|
581
|
+
providedIn: 'root',
|
|
582
|
+
}]
|
|
583
|
+
}], ctorParameters: () => [] });
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Generated bundle index. Do not edit.
|
|
587
|
+
*/
|
|
588
|
+
|
|
589
|
+
export { SHIP_SPOTLIGHT_CONFIG, ShipSpotlight, ShipSpotlightService, provideShipSpotlight };
|
|
590
|
+
//# sourceMappingURL=ship-ui-core-ship-spotlight.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ship-ui-core-ship-spotlight.mjs","sources":["../../../projects/ship-ui/ship-spotlight/ship-spotlight.ts","../../../projects/ship-ui/ship-spotlight/ship-spotlight.service.ts","../../../projects/ship-ui/ship-spotlight/ship-ui-core-ship-spotlight.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n ElementRef,\n input,\n model,\n output,\n signal,\n viewChild,\n ViewEncapsulation,\n InjectionToken,\n Provider,\n} from '@angular/core';\nimport { ShipIcon } from '@ship-ui/core/ship-icon';\nimport { ShipList } from '@ship-ui/core/ship-list';\nimport { ShipKbd } from '@ship-ui/core/ship-kbd';\n\nexport interface ShipSpotlightItem {\n id: string;\n label: string;\n category?: string;\n description?: string;\n icon?: string;\n shortcut?: string;\n data?: any;\n}\n\nexport interface ShipSpotlightServiceOptions {\n items?: ShipSpotlightItem[];\n placeholder?: string;\n shortcut?: string;\n customFilter?: boolean;\n searchQuery?: string;\n}\n\nexport interface ShipSpotlightConfig {\n defaultItems?: ShipSpotlightItem[];\n enableShortcuts?: boolean;\n}\n\nexport const SHIP_SPOTLIGHT_CONFIG = new InjectionToken<ShipSpotlightConfig>('SHIP_SPOTLIGHT_CONFIG');\n\nexport function provideShipSpotlight(config: ShipSpotlightConfig): Provider {\n return {\n provide: SHIP_SPOTLIGHT_CONFIG,\n useValue: config,\n };\n}\n\n@Component({\n selector: 'sh-spotlight',\n styleUrl: './ship-spotlight.scss',\n encapsulation: ViewEncapsulation.None,\n imports: [ShipIcon, ShipList, ShipKbd],\n template: `\n <div class=\"sh-spotlight-container\">\n <div class=\"sh-spotlight-search-bar\">\n <sh-icon class=\"sh-spotlight-search-icon\">magnifying-glass</sh-icon>\n <input\n #inputRef\n type=\"text\"\n class=\"sh-spotlight-input\"\n [placeholder]=\"mergedPlaceholder()\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($event)\"\n (keydown)=\"onKeyDown($event)\" />\n @if (searchQuery()) {\n <button class=\"sh-spotlight-clear-btn\" (click)=\"clearSearch()\">\n <sh-icon>x-bold</sh-icon>\n </button>\n }\n </div>\n\n <div #resultsRef class=\"sh-spotlight-results\">\n @if (groupedFilteredItems().length > 0) {\n @for (group of groupedFilteredItems(); track group.category) {\n <div class=\"sh-spotlight-category\">\n <div class=\"sh-spotlight-category-title\">{{ group.category }}</div>\n <sh-list class=\"type-b\">\n @for (itemWithIdx of group.items; track itemWithIdx.item.id) {\n <button\n action\n type=\"button\"\n [class.active]=\"itemWithIdx.flatIndex === activeOptionIndex()\"\n (mouseenter)=\"activeOptionIndex.set(itemWithIdx.flatIndex)\"\n (click)=\"selectItem(itemWithIdx.item)\">\n @if (itemWithIdx.item.icon) {\n <sh-icon>{{ itemWithIdx.item.icon }}</sh-icon>\n }\n <div class=\"text-group\">\n <span class=\"label\">{{ itemWithIdx.item.label }}</span>\n @if (itemWithIdx.item.description) {\n <span class=\"description\">{{ itemWithIdx.item.description }}</span>\n }\n </div>\n @if (itemWithIdx.item.shortcut) {\n <span class=\"shortcut\">\n @for (key of parseShortcutKeys(itemWithIdx.item.shortcut); track key) {\n <sh-kbd\n [meta]=\"key === 'meta' || key === 'cmd' || key === 'command'\"\n [shift]=\"key === 'shift'\"\n [alt]=\"key === 'alt' || key === 'option'\"\n [ctrl]=\"key === 'ctrl' || key === 'control'\"\n [enter]=\"key === 'enter' || key === 'return'\"\n [escape]=\"key === 'escape' || key === 'esc'\"\n [backspace]=\"key === 'backspace'\"\n >\n @if (!['meta', 'cmd', 'command', 'shift', 'alt', 'option', 'ctrl', 'control', 'enter', 'return', 'escape', 'esc', 'backspace'].includes(key)) {\n {{ key }}\n }\n </sh-kbd>\n }\n </span>\n }\n </button>\n }\n </sh-list>\n </div>\n }\n } @else {\n <div class=\"sh-spotlight-no-results\">\n <sh-icon class=\"sh-spotlight-no-results-icon\">warning-octagon</sh-icon>\n <span class=\"sh-spotlight-no-results-text\">No results found for \"{{ searchQuery() }}\"</span>\n </div>\n }\n </div>\n\n <div class=\"sh-spotlight-footer\">\n <span class=\"sh-spotlight-footer-tip\">\n <sh-kbd>↓</sh-kbd> <sh-kbd>↑</sh-kbd>\n to navigate\n </span>\n <span class=\"sh-spotlight-footer-tip\">\n <sh-kbd enter></sh-kbd>\n to select\n </span>\n <span class=\"sh-spotlight-footer-tip\">\n <sh-kbd escape></sh-kbd>\n to close\n </span>\n </div>\n </div>\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ShipSpotlight {\n inputRef = viewChild<ElementRef<HTMLInputElement>>('inputRef');\n resultsRef = viewChild<ElementRef<HTMLDivElement>>('resultsRef');\n\n // Input config passed from ShipDialogService\n data = input<ShipSpotlightServiceOptions>();\n\n // Standard inputs (fallback)\n items = input<ShipSpotlightItem[]>([]);\n placeholder = input<string>('Search actions, settings, or pages...');\n customFilter = input<boolean>(false);\n searchQuery = model<string>('');\n\n itemSelected = output<ShipSpotlightItem>();\n closed = output<void>();\n\n // Merged config properties\n mergedItems = computed(() => this.data()?.items ?? this.items());\n mergedPlaceholder = computed(() => this.data()?.placeholder ?? this.placeholder());\n mergedCustomFilter = computed(() => this.data()?.customFilter ?? this.customFilter());\n\n activeOptionIndex = signal<number>(0);\n\n // Computes the scored and filtered flat list of items\n flatFilteredItems = computed(() => {\n const query = this.searchQuery().toLowerCase().trim();\n const allItems = this.mergedItems();\n\n if (this.mergedCustomFilter() || !query) {\n return allItems;\n }\n\n const scored = allItems\n .map((item) => {\n const labelScore = this.#calculateMatchScore(item.label.toLowerCase(), query);\n const descScore = item.description ? this.#calculateMatchScore(item.description.toLowerCase(), query) : 0;\n return { item, score: Math.max(labelScore, descScore) };\n })\n .filter((x) => x.score > 0)\n .sort((a, b) => b.score - a.score);\n\n return scored.map((x) => x.item);\n });\n\n // Groups flat list of items by category and precomputes flat indices\n groupedFilteredItems = computed(() => {\n const flat = this.flatFilteredItems();\n const groups: { category: string; items: { item: ShipSpotlightItem; flatIndex: number }[] }[] = [];\n let currentFlatIndex = 0;\n\n flat.forEach((item) => {\n const cat = item.category || 'Actions';\n let group = groups.find((g) => g.category === cat);\n if (!group) {\n group = { category: cat, items: [] };\n groups.push(group);\n }\n group.items.push({ item, flatIndex: currentFlatIndex++ });\n });\n\n return groups;\n });\n\n constructor() {\n // Sync initial search query if provided in dialog data\n effect(() => {\n const initialQuery = this.data()?.searchQuery;\n if (initialQuery !== undefined) {\n this.searchQuery.set(initialQuery);\n }\n });\n\n // Auto-focus input when the view is initialized\n effect(() => {\n const inputEl = this.inputRef()?.nativeElement;\n if (inputEl && typeof inputEl.focus === 'function') {\n setTimeout(() => inputEl.focus(), 50);\n }\n });\n\n // Scroll active item into view\n effect(() => {\n const index = this.activeOptionIndex();\n if (index > -1) {\n queueMicrotask(() => this.scrollToActiveItem());\n }\n });\n }\n\n validateItemsEffect = effect(() => {\n const items = this.mergedItems();\n for (const item of items) {\n if (item.shortcut) {\n this.#validateShortcut(item.shortcut);\n }\n }\n });\n\n onSearchInput(event: Event) {\n const val = (event.target as HTMLInputElement).value;\n this.searchQuery.set(val);\n this.activeOptionIndex.set(0);\n }\n\n clearSearch() {\n this.searchQuery.set('');\n const inputEl = this.inputRef()?.nativeElement;\n if (inputEl) {\n inputEl.value = '';\n if (typeof inputEl.focus === 'function') {\n inputEl.focus();\n }\n }\n this.activeOptionIndex.set(0);\n }\n\n onKeyDown(event: KeyboardEvent) {\n // Check if the event matches any item shortcut\n const allItems = this.mergedItems();\n const shortcutMatch = allItems.find((item) => item.shortcut && this.#checkShortcutMatch(event, item.shortcut));\n\n if (shortcutMatch) {\n event.preventDefault();\n event.stopPropagation();\n // Delay selection to ensure the browser honors preventDefault before the DOM node is potentially destroyed\n setTimeout(() => this.selectItem(shortcutMatch), 10);\n return;\n }\n\n const flat = this.flatFilteredItems();\n if (flat.length === 0) return;\n\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n const nextIdx = (this.activeOptionIndex() + 1) % flat.length;\n this.activeOptionIndex.set(nextIdx);\n } else if (event.key === 'ArrowUp') {\n event.preventDefault();\n const prevIdx = (this.activeOptionIndex() - 1 + flat.length) % flat.length;\n this.activeOptionIndex.set(prevIdx);\n } else if (event.key === 'Tab') {\n event.preventDefault();\n if (event.shiftKey) {\n const prevIdx = (this.activeOptionIndex() - 1 + flat.length) % flat.length;\n this.activeOptionIndex.set(prevIdx);\n } else {\n const nextIdx = (this.activeOptionIndex() + 1) % flat.length;\n this.activeOptionIndex.set(nextIdx);\n }\n } else if (event.key === 'Enter') {\n event.preventDefault();\n const selected = flat[this.activeOptionIndex()];\n if (selected) {\n this.selectItem(selected);\n }\n }\n }\n\n selectItem(item: ShipSpotlightItem) {\n this.itemSelected.emit(item);\n this.closed.emit();\n }\n\n scrollToActiveItem() {\n const resultsEl = this.resultsRef()?.nativeElement;\n if (!resultsEl) return;\n\n const activeEl = resultsEl.querySelector('[action].active') as HTMLElement;\n if (activeEl && typeof activeEl.scrollIntoView === 'function') {\n activeEl.scrollIntoView({ block: 'nearest' });\n }\n }\n\n parseShortcutKeys(shortcut: string): string[] {\n if (!shortcut) return [];\n return shortcut.split('+').map((s) => s.trim().toLowerCase());\n }\n\n #validateShortcut(shortcut: string) {\n const normalized = shortcut\n .toLowerCase()\n .split('+')\n .map((k) => k.trim())\n .join('+');\n\n const reserved = [\n 'meta+n', 'ctrl+n',\n 'meta+t', 'ctrl+t',\n 'meta+w', 'ctrl+w',\n 'meta+q', 'ctrl+q',\n 'meta+r', 'ctrl+r',\n 'meta+l', 'ctrl+l',\n 'meta+shift+n', 'ctrl+shift+n',\n 'meta+shift+t', 'ctrl+shift+t',\n 'meta+shift+w', 'ctrl+shift+w',\n 'cmd+n', 'cmd+t', 'cmd+w', 'cmd+q', 'cmd+r', 'cmd+l',\n 'cmd+shift+n', 'cmd+shift+t', 'cmd+shift+w',\n ];\n\n if (reserved.includes(normalized)) {\n throw new Error(\n `[ShipUI Error] The shortcut \"${shortcut}\" uses a reserved browser hotkey that cannot be reliably prevented (e.g. New Window, New Tab). Please choose a different shortcut.`\n );\n }\n }\n\n #checkShortcutMatch(event: KeyboardEvent, shortcut: string): boolean {\n if (!shortcut) return false;\n const keys = this.parseShortcutKeys(shortcut);\n\n const needsMeta = keys.includes('meta') || keys.includes('cmd') || keys.includes('command');\n const needsCtrl = keys.includes('ctrl') || keys.includes('control');\n const needsAlt = keys.includes('alt') || keys.includes('option');\n const needsShift = keys.includes('shift');\n\n if (event.metaKey !== needsMeta) return false;\n if (event.ctrlKey !== needsCtrl) return false;\n if (event.altKey !== needsAlt) return false;\n if (event.shiftKey !== needsShift) return false;\n\n const mainKeys = keys.filter(\n (k) => !['meta', 'cmd', 'command', 'ctrl', 'control', 'alt', 'option', 'shift'].includes(k),\n );\n\n if (mainKeys.length === 1) {\n return event.key.toLowerCase() === mainKeys[0].toLowerCase();\n }\n\n return false;\n }\n\n #calculateMatchScore(option: string, input: string): number {\n if (!input) return 0;\n\n let score = 0;\n let lastIndex = -1;\n let matchCount = 0;\n let inSequence = true;\n\n for (let i = 0; i < input.length; i++) {\n const char = input[i];\n if (option.length > lastIndex + 1 && option[lastIndex + 1] === char) {\n score += i === 0 ? 100 : 150;\n lastIndex++;\n matchCount++;\n } else {\n const charIndex = option.indexOf(char, lastIndex + 1);\n\n if (i > 0) {\n inSequence = false;\n }\n\n if (charIndex === -1) {\n return 0;\n }\n\n score += 100;\n lastIndex = charIndex;\n matchCount++;\n }\n }\n\n if (inSequence && input.length === matchCount) {\n score += 1000;\n }\n\n score += matchCount * 20;\n return score;\n }\n}\n","import { computed, DOCUMENT, inject, Injectable, OutputEmitterRef, signal, DestroyRef } from '@angular/core';\nimport { ShipDialogService } from '@ship-ui/core/ship-dialog';\nimport { ShipSpotlight, ShipSpotlightItem, ShipSpotlightServiceOptions, SHIP_SPOTLIGHT_CONFIG } from './ship-spotlight';\n\nexport interface ShipSpotlightInstance {\n close: () => void;\n itemSelected: OutputEmitterRef<ShipSpotlightItem>;\n closed: OutputEmitterRef<any>;\n}\n\ninterface SpotlightItemRegistryEntry {\n id: number;\n items: ShipSpotlightItem[];\n overwrite: boolean;\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ShipSpotlightService {\n #document = inject(DOCUMENT);\n #dialogService = inject(ShipDialogService);\n #config = inject(SHIP_SPOTLIGHT_CONFIG, { optional: true });\n\n #nextId = 0;\n #registries = signal<SpotlightItemRegistryEntry[]>([]);\n\n #globalItemSelected = signal<ShipSpotlightItem | null>(null);\n globalItemSelected = this.#globalItemSelected.asReadonly();\n\n #isShortcutsEnabled = signal(false);\n isShortcutsEnabled = this.#isShortcutsEnabled.asReadonly();\n\n #aggregatedItems = computed(() => {\n const registries = this.#registries();\n const defaults = this.#config?.defaultItems ?? [];\n let aggregated: ShipSpotlightItem[] = [...defaults];\n\n for (const entry of registries) {\n if (entry.overwrite) {\n aggregated = [...entry.items];\n } else {\n aggregated.push(...entry.items);\n }\n }\n return aggregated;\n });\n\n hasOverwriteItems = computed(() => this.#registries().some((r) => r.overwrite));\n\n constructor() {\n if (this.#config?.enableShortcuts !== false) {\n this.enableGlobalShortcuts();\n }\n }\n\n registerItems(items: ShipSpotlightItem[], overwrite = false): () => void {\n const id = this.#nextId++;\n this.#registries.update((regs) => [...regs, { id, items, overwrite }]);\n\n const cleanup = () => {\n this.#registries.update((regs) => regs.filter((r) => r.id !== id));\n };\n\n try {\n const destroyRef = inject(DestroyRef);\n destroyRef.onDestroy(cleanup);\n } catch {\n // Ignore if not called in injection context\n }\n\n return cleanup;\n }\n\n #contextualRegistryId: number | null = null;\n\n setContextualItems(items: ShipSpotlightItem[], overwrite = false) {\n if (this.#contextualRegistryId !== null) {\n const oldId = this.#contextualRegistryId;\n this.#registries.update((regs) => regs.filter((r) => r.id !== oldId));\n }\n const id = this.#nextId++;\n this.#contextualRegistryId = id;\n this.#registries.update((regs) => [...regs, { id, items, overwrite }]);\n }\n\n clearContextualItems() {\n if (this.#contextualRegistryId !== null) {\n const oldId = this.#contextualRegistryId;\n this.#registries.update((regs) => regs.filter((r) => r.id !== oldId));\n this.#contextualRegistryId = null;\n }\n }\n\n #globalShortcutListener: ((event: KeyboardEvent) => void) | null = null;\n #globalShortcutOptions: Partial<ShipSpotlightServiceOptions> | null = null;\n\n enableGlobalShortcuts(options?: Partial<ShipSpotlightServiceOptions>): void {\n if (this.#globalShortcutListener) {\n this.disableGlobalShortcuts();\n }\n \n if (options) {\n this.#globalShortcutOptions = options;\n }\n\n this.#isShortcutsEnabled.set(true);\n\n this.#globalShortcutListener = (event: KeyboardEvent) => {\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'k') {\n event.preventDefault();\n\n const instance = this.open(this.#globalShortcutOptions || undefined);\n\n const sub = instance.itemSelected.subscribe((item) => {\n this.#globalItemSelected.set(item);\n });\n\n instance.closed.subscribe(() => sub.unsubscribe());\n }\n };\n\n this.#document.addEventListener('keydown', this.#globalShortcutListener);\n }\n\n disableGlobalShortcuts(): void {\n if (this.#globalShortcutListener) {\n this.#document.removeEventListener('keydown', this.#globalShortcutListener);\n this.#globalShortcutListener = null;\n }\n this.#isShortcutsEnabled.set(false);\n }\n\n open(options?: ShipSpotlightServiceOptions): ShipSpotlightInstance {\n const finalOptions = {\n ...options,\n items: options?.items ?? this.#aggregatedItems(),\n };\n\n const dialogRef = this.#dialogService.open(ShipSpotlight, {\n data: finalOptions,\n class: 'spotlight-dialog',\n closeOnOutsideClick: true,\n closeOnEsc: true,\n width: '600px',\n maxWidth: '90vw',\n });\n\n return {\n close: () => dialogRef.close(),\n itemSelected: dialogRef.component.itemSelected,\n closed: dialogRef.closed,\n };\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ship-ui/core",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "0.22.
|
|
4
|
+
"version": "0.22.7",
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"@angular/common": ">=20",
|
|
7
7
|
"@angular/core": ">=20",
|
|
@@ -142,6 +142,10 @@
|
|
|
142
142
|
"types": "./types/ship-ui-core-ship-icon.d.ts",
|
|
143
143
|
"default": "./fesm2022/ship-ui-core-ship-icon.mjs"
|
|
144
144
|
},
|
|
145
|
+
"./ship-kbd": {
|
|
146
|
+
"types": "./types/ship-ui-core-ship-kbd.d.ts",
|
|
147
|
+
"default": "./fesm2022/ship-ui-core-ship-kbd.mjs"
|
|
148
|
+
},
|
|
145
149
|
"./ship-list": {
|
|
146
150
|
"types": "./types/ship-ui-core-ship-list.d.ts",
|
|
147
151
|
"default": "./fesm2022/ship-ui-core-ship-list.mjs"
|
|
@@ -182,6 +186,10 @@
|
|
|
182
186
|
"types": "./types/ship-ui-core-ship-spinner.d.ts",
|
|
183
187
|
"default": "./fesm2022/ship-ui-core-ship-spinner.mjs"
|
|
184
188
|
},
|
|
189
|
+
"./ship-spotlight": {
|
|
190
|
+
"types": "./types/ship-ui-core-ship-spotlight.d.ts",
|
|
191
|
+
"default": "./fesm2022/ship-ui-core-ship-spotlight.mjs"
|
|
192
|
+
},
|
|
185
193
|
"./ship-stepper": {
|
|
186
194
|
"types": "./types/ship-ui-core-ship-stepper.d.ts",
|
|
187
195
|
"default": "./fesm2022/ship-ui-core-ship-stepper.mjs"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
|
|
3
|
+
declare class ShipKbd {
|
|
4
|
+
#private;
|
|
5
|
+
meta: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
6
|
+
shift: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
7
|
+
alt: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
8
|
+
ctrl: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
9
|
+
enter: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
10
|
+
escape: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
11
|
+
backspace: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
12
|
+
isMac: _angular_core.Signal<boolean>;
|
|
13
|
+
hasContent: _angular_core.Signal<boolean>;
|
|
14
|
+
displayKeys: _angular_core.Signal<string[]>;
|
|
15
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ShipKbd, never>;
|
|
16
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ShipKbd, "sh-kbd, [sh-kbd]", never, { "meta": { "alias": "meta"; "required": false; "isSignal": true; }; "shift": { "alias": "shift"; "required": false; "isSignal": true; }; "alt": { "alias": "alt"; "required": false; "isSignal": true; }; "ctrl": { "alias": "ctrl"; "required": false; "isSignal": true; }; "enter": { "alias": "enter"; "required": false; "isSignal": true; }; "escape": { "alias": "escape"; "required": false; "isSignal": true; }; "backspace": { "alias": "backspace"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { ShipKbd };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { InjectionToken, ElementRef, Provider, OutputEmitterRef } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
interface ShipSpotlightItem {
|
|
5
|
+
id: string;
|
|
6
|
+
label: string;
|
|
7
|
+
category?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
icon?: string;
|
|
10
|
+
shortcut?: string;
|
|
11
|
+
data?: any;
|
|
12
|
+
}
|
|
13
|
+
interface ShipSpotlightServiceOptions {
|
|
14
|
+
items?: ShipSpotlightItem[];
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
shortcut?: string;
|
|
17
|
+
customFilter?: boolean;
|
|
18
|
+
searchQuery?: string;
|
|
19
|
+
}
|
|
20
|
+
interface ShipSpotlightConfig {
|
|
21
|
+
defaultItems?: ShipSpotlightItem[];
|
|
22
|
+
enableShortcuts?: boolean;
|
|
23
|
+
}
|
|
24
|
+
declare const SHIP_SPOTLIGHT_CONFIG: InjectionToken<ShipSpotlightConfig>;
|
|
25
|
+
declare function provideShipSpotlight(config: ShipSpotlightConfig): Provider;
|
|
26
|
+
declare class ShipSpotlight {
|
|
27
|
+
#private;
|
|
28
|
+
inputRef: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
|
|
29
|
+
resultsRef: _angular_core.Signal<ElementRef<HTMLDivElement> | undefined>;
|
|
30
|
+
data: _angular_core.InputSignal<ShipSpotlightServiceOptions | undefined>;
|
|
31
|
+
items: _angular_core.InputSignal<ShipSpotlightItem[]>;
|
|
32
|
+
placeholder: _angular_core.InputSignal<string>;
|
|
33
|
+
customFilter: _angular_core.InputSignal<boolean>;
|
|
34
|
+
searchQuery: _angular_core.ModelSignal<string>;
|
|
35
|
+
itemSelected: _angular_core.OutputEmitterRef<ShipSpotlightItem>;
|
|
36
|
+
closed: _angular_core.OutputEmitterRef<void>;
|
|
37
|
+
mergedItems: _angular_core.Signal<ShipSpotlightItem[]>;
|
|
38
|
+
mergedPlaceholder: _angular_core.Signal<string>;
|
|
39
|
+
mergedCustomFilter: _angular_core.Signal<boolean>;
|
|
40
|
+
activeOptionIndex: _angular_core.WritableSignal<number>;
|
|
41
|
+
flatFilteredItems: _angular_core.Signal<ShipSpotlightItem[]>;
|
|
42
|
+
groupedFilteredItems: _angular_core.Signal<{
|
|
43
|
+
category: string;
|
|
44
|
+
items: {
|
|
45
|
+
item: ShipSpotlightItem;
|
|
46
|
+
flatIndex: number;
|
|
47
|
+
}[];
|
|
48
|
+
}[]>;
|
|
49
|
+
constructor();
|
|
50
|
+
validateItemsEffect: _angular_core.EffectRef;
|
|
51
|
+
onSearchInput(event: Event): void;
|
|
52
|
+
clearSearch(): void;
|
|
53
|
+
onKeyDown(event: KeyboardEvent): void;
|
|
54
|
+
selectItem(item: ShipSpotlightItem): void;
|
|
55
|
+
scrollToActiveItem(): void;
|
|
56
|
+
parseShortcutKeys(shortcut: string): string[];
|
|
57
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ShipSpotlight, never>;
|
|
58
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ShipSpotlight, "sh-spotlight", never, { "data": { "alias": "data"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "customFilter": { "alias": "customFilter"; "required": false; "isSignal": true; }; "searchQuery": { "alias": "searchQuery"; "required": false; "isSignal": true; }; }, { "searchQuery": "searchQueryChange"; "itemSelected": "itemSelected"; "closed": "closed"; }, never, never, true, never>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface ShipSpotlightInstance {
|
|
62
|
+
close: () => void;
|
|
63
|
+
itemSelected: OutputEmitterRef<ShipSpotlightItem>;
|
|
64
|
+
closed: OutputEmitterRef<any>;
|
|
65
|
+
}
|
|
66
|
+
declare class ShipSpotlightService {
|
|
67
|
+
#private;
|
|
68
|
+
globalItemSelected: _angular_core.Signal<ShipSpotlightItem | null>;
|
|
69
|
+
isShortcutsEnabled: _angular_core.Signal<boolean>;
|
|
70
|
+
hasOverwriteItems: _angular_core.Signal<boolean>;
|
|
71
|
+
constructor();
|
|
72
|
+
registerItems(items: ShipSpotlightItem[], overwrite?: boolean): () => void;
|
|
73
|
+
setContextualItems(items: ShipSpotlightItem[], overwrite?: boolean): void;
|
|
74
|
+
clearContextualItems(): void;
|
|
75
|
+
enableGlobalShortcuts(options?: Partial<ShipSpotlightServiceOptions>): void;
|
|
76
|
+
disableGlobalShortcuts(): void;
|
|
77
|
+
open(options?: ShipSpotlightServiceOptions): ShipSpotlightInstance;
|
|
78
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ShipSpotlightService, never>;
|
|
79
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<ShipSpotlightService>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { SHIP_SPOTLIGHT_CONFIG, ShipSpotlight, ShipSpotlightService, provideShipSpotlight };
|
|
83
|
+
export type { ShipSpotlightConfig, ShipSpotlightInstance, ShipSpotlightItem, ShipSpotlightServiceOptions };
|