KeyItem event bindings
This commit is contained in:
parent
2a8d0269b8
commit
88918c7a57
|
@ -0,0 +1 @@
|
|||
cache
|
|
@ -0,0 +1,31 @@
|
|||
# Source files
|
||||
src/
|
||||
*.ts
|
||||
!*.d.ts
|
||||
|
||||
# Development files
|
||||
tsconfig.*.json
|
||||
ng-package.json
|
||||
karma.conf.js
|
||||
*.spec.ts
|
||||
|
||||
# Build files
|
||||
node_modules/
|
||||
coverage/
|
||||
.nyc_output/
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
|
@ -0,0 +1,55 @@
|
|||
Workshack Input Library License
|
||||
|
||||
Copyright (c) 2025 Workshack Team
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to use,
|
||||
copy, modify, merge, publish, and distribute the Software, subject to the
|
||||
following conditions:
|
||||
|
||||
NON-COMMERCIAL USE:
|
||||
For non-commercial applications (applications that do not generate revenue,
|
||||
do not contain paid features, subscriptions, advertisements, or any form of
|
||||
monetization), the Software may be used freely without any additional
|
||||
requirements.
|
||||
|
||||
COMMERCIAL USE:
|
||||
For commercial applications (applications that generate revenue through sales,
|
||||
subscriptions, advertisements, in-app purchases, or any other form of
|
||||
monetization), the following additional requirement applies:
|
||||
|
||||
- The application MUST include attribution to the Workshack Input Library in a
|
||||
publicly accessible location within the application. This can be:
|
||||
* An "About" page or section
|
||||
* A "Credits" or "Acknowledgments" page
|
||||
* A "For Developers" page
|
||||
* Any other location where users can reasonably find it
|
||||
|
||||
The attribution must include:
|
||||
- The name "Workshack Input Library"
|
||||
- A link to the library's repository or npm package page
|
||||
- The copyright notice "© 2025 Workshack Team"
|
||||
|
||||
Example attribution:
|
||||
"This application uses Workshack Input Library (https://www.npmjs.com/package/@workshack/input) © 2025 Workshack Team"
|
||||
|
||||
GENERAL CONDITIONS:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
DEFINITIONS:
|
||||
- "Commercial application" means any software application, website, or service
|
||||
that generates revenue or is intended to generate revenue through any means
|
||||
including but not limited to: sales, subscriptions, advertisements, in-app
|
||||
purchases, premium features, or commercial licensing.
|
||||
- "Non-commercial application" means any software application, website, or
|
||||
service that is provided free of charge with no revenue generation or
|
||||
monetization of any kind.
|
507
README.md
507
README.md
|
@ -1,135 +1,454 @@
|
|||
# @ngshack/input
|
||||
# @workshack/input
|
||||
|
||||
Biblioteka komponentów input i nawigacji dla aplikacji Webland z obsługą gamepadów.
|
||||
Workshack input components library with gamepad and keyboard navigation support for Angular applications.
|
||||
|
||||
## Instalacja
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @ngshack/input
|
||||
npm install @workshack/input
|
||||
```
|
||||
|
||||
## Development
|
||||
## Services
|
||||
|
||||
### Prerequisites
|
||||
- Node.js 18+
|
||||
- Angular CLI 17+
|
||||
### InputService
|
||||
|
||||
### Setup
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### Generate Components
|
||||
```bash
|
||||
# Generate new component
|
||||
ng generate component components/my-component --project=input
|
||||
|
||||
# Generate service
|
||||
ng generate service services/my-service --project=input
|
||||
|
||||
# Generate module
|
||||
ng generate module modules/my-module --project=input
|
||||
```
|
||||
|
||||
### Build Library
|
||||
```bash
|
||||
ng build input
|
||||
```
|
||||
|
||||
### Test
|
||||
```bash
|
||||
ng test input
|
||||
```
|
||||
|
||||
### Publish
|
||||
```bash
|
||||
npm run build:libs
|
||||
npm publish dist/input
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Navigation Module
|
||||
**Description:** Core service for managing input devices, actions, and schemes.
|
||||
|
||||
**Usage:**
|
||||
```typescript
|
||||
import { NavigationModule } from '@ngshack/input';
|
||||
import { InputService } from '@workshack/input';
|
||||
|
||||
@Component({
|
||||
imports: [NavigationModule],
|
||||
template: `
|
||||
<div inputActionBinding="confirm" (action)="onConfirm()">
|
||||
<button>Confirm</button>
|
||||
</div>
|
||||
`
|
||||
// ...
|
||||
})
|
||||
export class MyComponent {
|
||||
onConfirm() {
|
||||
console.log('Confirmed!');
|
||||
constructor(private inputService: InputService) {
|
||||
// Define custom actions
|
||||
const jumpAction = this.inputService.defineAction('jump');
|
||||
jumpAction.onDown(() => console.log('Jump pressed!'));
|
||||
jumpAction.onUp(() => console.log('Jump released!'));
|
||||
|
||||
// Create input scheme
|
||||
const gameScheme = this.inputService.defineScheme('game');
|
||||
|
||||
// Listen for device changes
|
||||
this.inputService.deviceListChanged.subscribe(devices => {
|
||||
console.log('Available devices:', devices);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Action Binding Directive
|
||||
**Methods:**
|
||||
- `defineAction(name: string): InputAction` - Creates a new input action
|
||||
- `defineScheme(name: string): InputScheme` - Creates a new input scheme
|
||||
- `getDevices(): InputDevice[]` - Returns list of available input devices
|
||||
|
||||
**Properties:**
|
||||
- `actions: InputAction[]` - Array of defined actions
|
||||
- `schemes: InputScheme[]` - Array of defined schemes
|
||||
- `devices: InputDevice[]` - Array of connected devices
|
||||
- `deviceListChanged: BehaviorSubject<InputDevice[]>` - Observable for device changes
|
||||
|
||||
---
|
||||
|
||||
### ControlService (Example Integration)
|
||||
|
||||
**Description:** Higher-level service that integrates with InputService to provide common navigation actions.
|
||||
|
||||
**Usage:**
|
||||
```typescript
|
||||
import { ActionBindingDirective } from '@ngshack/input';
|
||||
import { ControlService } from 'your-app/services/control.service';
|
||||
|
||||
@Component({
|
||||
imports: [ActionBindingDirective],
|
||||
template: `
|
||||
<div inputActionBinding="back" (action)="goBack()">
|
||||
Back Button
|
||||
</div>
|
||||
`
|
||||
// ...
|
||||
})
|
||||
export class MyComponent {
|
||||
constructor(private controlService: ControlService) {
|
||||
// Service automatically sets up common actions:
|
||||
// - Left, Right, Up, Down navigation
|
||||
// - Accept, Back, Exit actions
|
||||
// - Hint/Help action
|
||||
|
||||
// Get key names for display
|
||||
const keyNames = this.controlService.getKeyNames('Enter', 'Escape');
|
||||
console.log('Key names:', keyNames); // ['Enter', 'Escape'] or themed names
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Static Properties:**
|
||||
- `keyLeft: InputAction` - Left navigation action
|
||||
- `keyRight: InputAction` - Right navigation action
|
||||
- `keyUp: InputAction` - Up navigation action
|
||||
- `keyDown: InputAction` - Down navigation action
|
||||
- `keyAccept: InputAction` - Accept/confirm action
|
||||
- `keyBack: InputAction` - Back/cancel action
|
||||
- `keyExit: InputAction` - Exit action
|
||||
- `keyHint: InputAction` - Hint/help action
|
||||
|
||||
**Methods:**
|
||||
- `getKeyNames(...names): string[]` - Get themed key names for display
|
||||
- `clearKeyBindings()` - Clear all key bindings from schemes
|
||||
- `bindActionsToScheme(device: InputDevice)` - Bind actions to device scheme
|
||||
|
||||
## Directives
|
||||
|
||||
### ActionBindingDirective
|
||||
|
||||
**Selector:** `[inputActionBinding]`
|
||||
**Description:** Binds an action name to an HTML element.
|
||||
|
||||
**Usage:**
|
||||
```html
|
||||
<button inputActionBinding="confirm">Confirm</button>
|
||||
<div inputActionBinding="back">Back</div>
|
||||
```
|
||||
|
||||
**Properties:**
|
||||
- `inputActionBinding: string` - Action name to bind to the element
|
||||
|
||||
**Features:**
|
||||
- Automatically sets `action` attribute on the element
|
||||
- Works with keyboard and gamepad navigation
|
||||
|
||||
---
|
||||
|
||||
### KeyItemDirective
|
||||
|
||||
**Selector:** `[inputKeyItem]`
|
||||
**Description:** Makes an element navigable with keyboard/gamepad and handles focus states.
|
||||
|
||||
**Usage:**
|
||||
```html
|
||||
<button
|
||||
inputKeyItem
|
||||
[active]="'focused'"
|
||||
[actionBindings]="{
|
||||
Accept: () => onClick(),
|
||||
Back: () => onCancel()
|
||||
}"
|
||||
(activated)="onActivated()"
|
||||
(focused)="onFocused()"
|
||||
(blurred)="onBlurred()">
|
||||
Click me
|
||||
</button>
|
||||
```
|
||||
|
||||
**Properties:**
|
||||
- `active: string` - CSS class name for active/focused state (default: 'active')
|
||||
- `actionBindings: ActionBindings` - Object mapping action names to callback functions
|
||||
|
||||
**Events:**
|
||||
- `activated: EventEmitter<void>` - Emitted when item is activated
|
||||
- `deactivated: EventEmitter<void>` - Emitted when item is deactivated
|
||||
- `focused: EventEmitter<void>` - Emitted when item receives focus
|
||||
- `blurred: EventEmitter<void>` - Emitted when item loses focus
|
||||
|
||||
**Static Methods:**
|
||||
- `FireAction(action: string): boolean` - Fires action on currently focused item
|
||||
- `ActivateCurrentItem()` - Activates the currently focused item
|
||||
- `SelectNexItem(fromAngle: number, toAngle: number)` - Selects next item in direction
|
||||
|
||||
---
|
||||
|
||||
### KeyItemGroupDirective
|
||||
|
||||
**Selector:** `[inputKeyItemGroup]`
|
||||
**Description:** Groups KeyItem elements for scoped navigation.
|
||||
|
||||
**Usage:**
|
||||
```html
|
||||
<div inputKeyItemGroup>
|
||||
<button inputKeyItem>Button 1</button>
|
||||
<button inputKeyItem>Button 2</button>
|
||||
<button inputKeyItem>Button 3</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Navigation is scoped to items within the group
|
||||
- Automatically manages focus within the group
|
||||
- Supports nested groups
|
||||
|
||||
## Models
|
||||
|
||||
### InputAction
|
||||
|
||||
**Description:** Represents a bindable input action (e.g., "jump", "fire", "menu").
|
||||
|
||||
**Usage:**
|
||||
```typescript
|
||||
const jumpAction = new InputAction('jump');
|
||||
|
||||
// Bind callbacks
|
||||
jumpAction.onDown((value, data, angle, timePressed) => {
|
||||
console.log('Jump started!', { value, data, angle, timePressed });
|
||||
});
|
||||
|
||||
jumpAction.onUp((value, data, angle, timePressed) => {
|
||||
console.log('Jump ended!', { value, data, angle, timePressed });
|
||||
});
|
||||
|
||||
jumpAction.onChange((value, data, angle, timePressed) => {
|
||||
console.log('Jump value changed:', value);
|
||||
});
|
||||
|
||||
// Fire the action
|
||||
jumpAction.fire(1.0); // Press
|
||||
jumpAction.fire(0.0); // Release
|
||||
```
|
||||
|
||||
**Methods:**
|
||||
- `onDown(callback: ActionCallback)` - Register callback for action press
|
||||
- `onUp(callback: ActionCallback)` - Register callback for action release
|
||||
- `onChange(callback: ActionCallback)` - Register callback for value changes
|
||||
- `fire(value: number, data?: unknown, angle?: number, timePressed?: number)` - Fire the action
|
||||
- `mapKeysToScheme(scheme: InputScheme, keys: (string|number)[])` - Map keys to scheme
|
||||
|
||||
---
|
||||
|
||||
### InputDevice
|
||||
|
||||
**Description:** Base class for input devices (keyboard, gamepad).
|
||||
|
||||
**Properties:**
|
||||
- `name: string` - Device name
|
||||
- `type: string` - Device type ('keyboard', 'gamepad')
|
||||
|
||||
**Methods:**
|
||||
- `hasScheme(): boolean` - Check if device has an input scheme
|
||||
- `mapKey(action: InputAction, keys: (string|number)[])` - Map keys to action
|
||||
|
||||
---
|
||||
|
||||
### InputKeyboard
|
||||
|
||||
**Description:** Keyboard input device implementation.
|
||||
|
||||
**Usage:**
|
||||
```typescript
|
||||
const keyboard = new InputKeyboard('Main Keyboard');
|
||||
keyboard.mapKey(jumpAction, ['Space', 'KeyW']);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### InputGamepad
|
||||
|
||||
**Description:** Gamepad input device implementation with automatic detection.
|
||||
|
||||
**Static Properties:**
|
||||
- `DeviceConnected: Subject<InputGamepad>` - Observable for gamepad connections
|
||||
- `DeviceDisconnected: Subject<InputGamepad>` - Observable for gamepad disconnections
|
||||
|
||||
**Static Methods:**
|
||||
- `Init()` - Initialize gamepad detection
|
||||
|
||||
**Usage:**
|
||||
```typescript
|
||||
// Listen for gamepad events
|
||||
InputGamepad.DeviceConnected.subscribe(gamepad => {
|
||||
console.log('Gamepad connected:', gamepad.name);
|
||||
gamepad.mapKey(jumpAction, [0]); // Map to button 0
|
||||
});
|
||||
|
||||
InputGamepad.DeviceDisconnected.subscribe(gamepad => {
|
||||
console.log('Gamepad disconnected:', gamepad.name);
|
||||
});
|
||||
|
||||
// Initialize detection
|
||||
InputGamepad.Init();
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
```typescript
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import {
|
||||
InputService,
|
||||
NavigationModule,
|
||||
KeyItemDirective,
|
||||
KeyItemGroupDirective,
|
||||
ActionBindingDirective
|
||||
} from '@workshack/input';
|
||||
|
||||
@Component({
|
||||
selector: 'app-game-menu',
|
||||
imports: [
|
||||
NavigationModule,
|
||||
KeyItemDirective,
|
||||
KeyItemGroupDirective,
|
||||
ActionBindingDirective
|
||||
],
|
||||
template: `
|
||||
<div class="game-menu" inputKeyItemGroup>
|
||||
<h2>Game Menu</h2>
|
||||
|
||||
<button
|
||||
inputKeyItem
|
||||
[actionBindings]="{
|
||||
Accept: () => startGame(),
|
||||
Back: () => goBack()
|
||||
}"
|
||||
(focused)="playHoverSound()"
|
||||
class="menu-item">
|
||||
Start Game
|
||||
</button>
|
||||
|
||||
<button
|
||||
inputKeyItem
|
||||
[actionBindings]="{
|
||||
Accept: () => showOptions(),
|
||||
Back: () => goBack()
|
||||
}"
|
||||
(focused)="playHoverSound()"
|
||||
class="menu-item">
|
||||
Options
|
||||
</button>
|
||||
|
||||
<button
|
||||
inputKeyItem
|
||||
[actionBindings]="{
|
||||
Accept: () => exitGame(),
|
||||
Back: () => goBack()
|
||||
}"
|
||||
(focused)="playHoverSound()"
|
||||
class="menu-item">
|
||||
Exit
|
||||
</button>
|
||||
|
||||
<div class="controls-hint">
|
||||
<span>Use arrow keys or gamepad to navigate</span>
|
||||
<span>Press Enter or A to select</span>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
styles: [`
|
||||
.game-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
padding: 1rem 2rem;
|
||||
background: #333;
|
||||
color: white;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.menu-item.active,
|
||||
.menu-item:hover {
|
||||
background: #555;
|
||||
border-color: #007bff;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.controls-hint {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
font-size: 0.8rem;
|
||||
color: #666;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
`]
|
||||
})
|
||||
export class GameMenuComponent implements OnInit {
|
||||
|
||||
constructor(private inputService: InputService) {}
|
||||
|
||||
ngOnInit() {
|
||||
// Set up custom actions
|
||||
const menuAction = this.inputService.defineAction('menu');
|
||||
menuAction.onUp(() => this.toggleMenu());
|
||||
|
||||
// Listen for device changes
|
||||
this.inputService.deviceListChanged.subscribe(devices => {
|
||||
console.log('Input devices:', devices.map(d => d.name));
|
||||
});
|
||||
}
|
||||
|
||||
startGame() {
|
||||
console.log('Starting game...');
|
||||
}
|
||||
|
||||
showOptions() {
|
||||
console.log('Showing options...');
|
||||
}
|
||||
|
||||
exitGame() {
|
||||
console.log('Exiting game...');
|
||||
}
|
||||
|
||||
goBack() {
|
||||
// Handle back action
|
||||
console.log('Going back...');
|
||||
return false; // Prevent default navigation
|
||||
}
|
||||
|
||||
playHoverSound() {
|
||||
// Play hover sound effect
|
||||
console.log('Hover sound');
|
||||
}
|
||||
|
||||
toggleMenu() {
|
||||
console.log('Toggle menu');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- 🎮 Gamepad support
|
||||
- ⌨️ Keyboard navigation
|
||||
- 🖱️ Mouse/touch support
|
||||
- 🎯 Action binding system
|
||||
- 📱 Responsive design
|
||||
- 🎨 Gaming console theme
|
||||
- 🎮 **Gamepad Support** - Automatic detection and mapping for standard gamepads
|
||||
- ⌨️ **Keyboard Navigation** - Full keyboard navigation with customizable key bindings
|
||||
- 🖱️ **Mouse/Touch Support** - Works seamlessly with mouse and touch interactions
|
||||
- 🎯 **Action Binding System** - Flexible system for binding actions to inputs
|
||||
- 📐 **Directional Navigation** - Smart directional navigation based on element positions
|
||||
- 🎨 **Customizable Themes** - Support for different key name themes (PlayStation, Xbox, etc.)
|
||||
- 🔄 **Hot-plugging** - Automatic detection of connected/disconnected devices
|
||||
- 🎛️ **Multiple Schemes** - Support for multiple input schemes per device
|
||||
|
||||
## Publishing the Library
|
||||
|
||||
Once the project is built, you can publish your library by following these steps:
|
||||
|
||||
1. Navigate to the `dist` directory:
|
||||
```bash
|
||||
cd dist/input
|
||||
```
|
||||
|
||||
2. Run the `npm publish` command to publish your library to the npm registry:
|
||||
```bash
|
||||
npm publish
|
||||
```
|
||||
|
||||
## Running unit tests
|
||||
|
||||
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
|
||||
## Development
|
||||
|
||||
### Building
|
||||
```bash
|
||||
ng test
|
||||
npm run build:input
|
||||
```
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
For end-to-end (e2e) testing, run:
|
||||
|
||||
### Watching for changes
|
||||
```bash
|
||||
ng e2e
|
||||
npm run watch:input
|
||||
```
|
||||
|
||||
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
||||
### Testing
|
||||
```bash
|
||||
npm run test:input
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
### Publishing
|
||||
```bash
|
||||
npm run publish:input
|
||||
```
|
||||
|
||||
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
||||
## License
|
||||
|
||||
This library is licensed under a custom license that allows:
|
||||
|
||||
- **Free use** for non-commercial applications (no revenue, no ads, no paid features)
|
||||
- **Commercial use** with attribution requirement - you must credit the library in your app (e.g., on an "About" or "For Developers" page)
|
||||
|
||||
For full license terms, see the [LICENSE](LICENSE) file.
|
||||
|
||||
### Attribution Example for Commercial Use
|
||||
|
||||
```
|
||||
This application uses Workshack Input Library
|
||||
(https://www.npmjs.com/package/@workshack/input)
|
||||
© 2025 Workshack Team
|
||||
```
|
||||
|
|
38
package.json
38
package.json
|
@ -1,35 +1,25 @@
|
|||
{
|
||||
"name": "@ngshack/input",
|
||||
"version": "0.0.1",
|
||||
"description": "Webland input components library",
|
||||
"author": "Webland Team",
|
||||
"license": "MIT",
|
||||
"keywords": ["angular", "input", "forms", "components", "webland"],
|
||||
"name": "@workshack/input",
|
||||
"version": "1.0.0",
|
||||
"description": "Workshack input components library with gamepad and keyboard navigation support",
|
||||
"author": "Workshack Team",
|
||||
"license": "SEE LICENSE IN LICENSE",
|
||||
"keywords": ["angular", "input", "forms", "components", "workshack", "gamepad", "navigation", "gaming"],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/webland/webland.git",
|
||||
"directory": "app/packages/input"
|
||||
"url": "https://git.fufle.net/workshack/input.git",
|
||||
"directory": "."
|
||||
},
|
||||
"homepage": "https://github.com/webland/webland#readme",
|
||||
"homepage": "https://git.fufle.net/workshack/input",
|
||||
"bugs": {
|
||||
"url": "https://github.com/webland/webland/issues"
|
||||
"url": "https://git.fufle.net/workshack/input/issues"
|
||||
},
|
||||
"main": "bundles/webland-input.umd.js",
|
||||
"module": "fesm2022/webland-input.mjs",
|
||||
"main": "bundles/workshack-input.umd.js",
|
||||
"module": "fesm2022/workshack-input.mjs",
|
||||
"typings": "index.d.ts",
|
||||
"exports": {
|
||||
"./package.json": {
|
||||
"default": "./package.json"
|
||||
},
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"esm": "./fesm2022/webland-input.mjs",
|
||||
"default": "./fesm2022/webland-input.mjs"
|
||||
}
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^20.1.0",
|
||||
"@angular/core": "^20.1.0"
|
||||
"@angular/common": "^20.1.3",
|
||||
"@angular/core": "^20.1.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Directive, ElementRef, HostListener, Input, OnDestroy, OnInit, Optional, Host } from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener, Input, OnDestroy, OnInit, Optional, Host, EventEmitter, Output } from '@angular/core';
|
||||
import { KeyItemGroupDirective } from './key-item-group.directive';
|
||||
|
||||
export interface ActionBindings {
|
||||
|
@ -28,11 +28,11 @@ interface HTMLKeyItemEntryElement extends HTMLElement {
|
|||
export class KeyItemDirective implements OnInit, OnDestroy {
|
||||
|
||||
@Input() active = 'active';
|
||||
@Input() activate: () => any = () => {};
|
||||
@Input() deactivate: () => any = () => {};
|
||||
@Input() focus: () => any = () => {};
|
||||
@Input() blur: () => any = () => {};
|
||||
@Input() actionBindings: ActionBindings = {};
|
||||
@Output() activated = new EventEmitter<void>();
|
||||
@Output() deactivated = new EventEmitter<void>();
|
||||
@Output() focused = new EventEmitter<void>();
|
||||
@Output() blurred = new EventEmitter<void>();
|
||||
private static allItems: KeyItemEntry[] = [];
|
||||
private static current?: KeyItemEntry;
|
||||
private element: HTMLKeyItemEntryElement;
|
||||
|
@ -40,7 +40,8 @@ export class KeyItemDirective implements OnInit, OnDestroy {
|
|||
private id = KeyItemDirective.NextId++;
|
||||
|
||||
constructor(
|
||||
@Optional() private group: KeyItemGroupDirective,
|
||||
@Optional()
|
||||
private group: KeyItemGroupDirective,
|
||||
elementRef: ElementRef,
|
||||
) {
|
||||
this.element = elementRef.nativeElement as HTMLKeyItemEntryElement;
|
||||
|
@ -57,12 +58,12 @@ export class KeyItemDirective implements OnInit, OnDestroy {
|
|||
|
||||
ngOnInit() {
|
||||
this.element.active = this.active;
|
||||
this.element.activate = this.activate;
|
||||
this.element.deactivate = this.deactivate;
|
||||
this.element.activate = () => this.activated.emit();
|
||||
this.element.deactivate = () => this.deactivated.emit();
|
||||
this.element.keyId = this.id;
|
||||
this.element.actionBindings = this.actionBindings;
|
||||
this.element.focus = this.focus;
|
||||
this.element.blur = this.blur;
|
||||
this.element.focus = () => this.focused.emit();
|
||||
this.element.blur = () => this.blurred.emit();
|
||||
const position = this.element.getBoundingClientRect();
|
||||
const item = {
|
||||
element: this.element,
|
||||
|
@ -100,7 +101,7 @@ export class KeyItemDirective implements OnInit, OnDestroy {
|
|||
this.element.classList.add(this.active);
|
||||
}
|
||||
|
||||
this.focus();
|
||||
this.focused.emit();
|
||||
|
||||
const item = KeyItemDirective.allItems.find(item => item.element.keyId === this.id);
|
||||
KeyItemDirective.SetCurrentItem(item);
|
||||
|
@ -112,7 +113,7 @@ export class KeyItemDirective implements OnInit, OnDestroy {
|
|||
this.element.classList.remove(this.active);
|
||||
}
|
||||
|
||||
this.blur();
|
||||
this.blurred.emit();
|
||||
}
|
||||
|
||||
static ActivateCurrentItem() {
|
||||
|
|
Loading…
Reference in New Issue