Welcome, AI assistant. Follow these guidelines when contributing to this repository.
php artisan boost:add-skill pentiminax/ux-driver
Save this content to: AGENTS.md
# AI Contribution Guidelines
Welcome, AI assistant. Follow these guidelines when contributing to this repository.
## Project Overview
UX Driver is a third-party Symfony UX bundle that integrates [Driver.js](https://driverjs.com/) with
Symfony applications. It provides product tours, standalone highlights, and hints, authored either
with Twig Components, the `create_tour()` / `create_hints()` Twig builders, or the autowired PHP
builders.
**Requirements:** PHP 8.2+, Symfony 7.x/8.x, Symfony StimulusBundle 2.x/3.x, Symfony UX
TwigComponent 2.x/3.x, Twig 3.8+, Driver.js 1.8+
**PHP namespace:** `Pentiminax\UX\Driver\` maps to `src/`
**Test namespace:** `Pentiminax\UX\Driver\Tests\` maps to `tests/`
## General Rules
- Use American English for code, comments, documentation, commits, and branches.
- Use single quotes for PHP and TypeScript strings unless interpolation or escaping makes double
quotes clearer.
- Keep changes focused, reviewable, and backward compatible.
- Treat popover titles and descriptions as a security boundary. Driver.js writes them with
`innerHTML`, so they are escaped in PHP by `Html\PopoverContent`. Never bypass that treatment,
and keep `Twig\Markup` / `ux_driver_html()` as the only opt-out for trusted markup.
- Keep the three authoring modes behaviorally identical. A feature added to Twig Components,
Twig builders, or PHP builders must produce the same serialized payload in the others.
- Add dependencies only when the task explicitly requires them.
### Do Not Edit Directly
- `vendor/`, any `node_modules/` directory, and `var/` are managed dependencies or runtime output.
- `docs/dist/` and `docs/.astro/` are generated by Astro.
- `assets/dist/` is generated but versioned. Change `assets/src/`, then rebuild it with
`npm run build` from `assets/`; never hand-edit compiled files or source maps. CI enforces this
with `git diff --exit-code dist`.
- Update lock files only through their package manager. Keep the tracked `docs/package-lock.json`
and `assets/package-lock.json` synchronized with their `package.json`.
## Architecture
### Core Data Flow
```text
Twig Components
twig:Driver:Tour / twig:Driver:Step
-> Twig\Components\* + templates/components/*.html.twig
-> data-tour-* attributes (PopoverContent escaping)
-> Stimulus controller (assets/src/controller.ts)
-> driver.js
Builders (Twig create_tour() / PHP TourBuilder)
-> Model\Tour + Model\Step
-> UXDriverExtension::renderTour() + stimulus.helper
-> serialized steps and options values
-> Stimulus controller (assets/src/controller.ts)
-> driver.js
Hints
twig:Driver:Hints / create_hints() / HintsBuilder
-> Model\Hints + Model\Hint
-> assets/src/hints-controller.ts + hint-utils.ts
-> driver.js/hints
```
Declarative tours collect their steps from Stimulus `step` targets in DOM order; builder-driven
tours embed the whole step list in the serialized `steps` value. Both paths converge on the same
Stimulus controller and the same driver.js configuration.
### Main Boundaries
- **User configuration** (`src/Model/`, `src/Builder/`, `src/Enum/`): `Tour`, `Step`, `Hints`,
`Hint`, the fluent builders, and the option enums are the primary user-facing surface.
- **Twig integration** (`src/Twig/`, `templates/`): the Twig functions, the four Twig Components,
and their templates. `UXDriverExtension` is the single place where Stimulus attributes are
produced.
- **HTML safety** (`src/Html/PopoverContent.php`): the one treatment point for popover content in
both authoring modes.
- **Bundle wiring** (`src/DriverBundle.php`, `config/services.php`, `config/reference.php`):
services are registered explicitly; no implicit autowiring assumptions.
- **Frontend** (`assets/src/`): the tour controller, the hints controller, and their pure utility
modules (`tour-utils.ts`, `hint-utils.ts`) which hold the persistence and resolution logic.
### Public API and Backward Compatibility
Treat documented entry points and downstream-consumed behavior as public contracts. This includes
`Tour`, `Step`, `Hints`, `Hint`, `TourBuilder`, `HintsBuilder`, the enums, the Twig functions
(`create_tour`, `ux_tour`, `ux_tour_action`, `ux_highlight`, `create_hints`, `ux_hints`,
`ux_hints_action`, `ux_driver_html`), the `Driver:*` component keys and their props, the emitted
`data-*` attribute names, the serialized frontend values, the dispatched Stimulus events, and the
published JavaScript entrypoints declared in `assets/package.json`.
- Prefer additive, backward-compatible changes.
- Deprecate an existing path before removing it, and document its replacement.
- Do not expose internal runtime objects or implementation details through user configuration.
- Keep fluent configuration consistent: chainable methods returning `static` or the model itself.
- Consider payload shape and the Stimulus values contract when changing PHP or TypeScript APIs.
- Keep `peerDependencies` and `symfony.importmap` driver.js ranges aligned; `tests/PackageMetadataTest.php`
asserts it.
- Keep stylesheets out of the built controllers; they travel through the StimulusBundle
`autoimport` declaration, as asserted by `tests/AssetsDistTest.php`.
## Commands
Use the repository manifests and CI workflows as the source of truth.
### Setup
```bash
composer install
cd assets
npm install
cd ../docs
npm ci
```
### PHP
```bash
composer audit
composer fix
composer analyse
vendor/bin/phpunit
vendor/bin/phpunit tests/Model/TourTest.php
vendor/bin/phpunit --filter=test_name
```
`composer fix` rewrites PHP files. Review its diff before committing.
### Frontend
Run from `assets/`:
```bash
npm run typecheck
npm test
npm run build
```
### Documentation
Run from `docs/`:
```bash
npm run check
npm run build
npm run test:build
```
### Before Creating a Pull Request
Run the relevant checks for every changed area:
| Changed area | Required checks |
| --- | --- |
| PHP source, config, or tests | `composer fix`, `composer audit`, `composer analyse`, `vendor/bin/phpunit` |
| TypeScript or frontend tests | `npm run typecheck`, `npm test`, `npm run build` in `assets/`, then commit `assets/dist/` |
| Twig templates or serialized payloads | Relevant PHPUnit tests and affected frontend tests |
| Astro/MDX documentation | `npm run check`, `npm run build`, `npm run test:build` in `docs/` |
| Contribution documentation | `git diff --check` and a manual diff review |
## PHP Code Standards
PHP-CS-Fixer (`.php-cs-fixer.dist.php`) is the formatting source of truth. Its rules include PSR-12,
Symfony conventions, strict types, single quotes, ordered imports, native function invocation, and
snake_case PHPUnit method names. PHPStan runs at level 8 over `src/` and `tests/`.
- Add `declare(strict_types=1);` to PHP files.
- Use PHP 8.2+ syntax and native types. Prefer constructor property promotion where it improves
clarity. Do not use syntax that PHP 8.2 does not support.
- Register bundle services explicitly in `config/services.php`; do not introduce implicit
autowiring assumptions.
- Prefer enums over groups of constants for closed sets of values, as `src/Enum/` already does.
- Return or throw early instead of nesting control flow.
- Handle exceptions explicitly; never add silent catches.
- Start exception messages with a capital letter and end them with a period.
- Add comments only for non-obvious constraints or decisions. Do not use comments as section
separators.
- Keep properties before methods, then order methods public, protected, and private.
- Use PHPDoc for useful generic, iterable, array-shape, or behavioral information; PHPStan level 8
relies on the declared array shapes. Avoid repeating native type declarations.
## TypeScript and Frontend Standards
- Use TypeScript and ES modules; `assets/src/` compiles to `assets/dist/` with `tsc`.
- Use 4-space indentation and single quotes, matching the existing controllers.
- Use `camelCase` for variables and functions and `UpperCamelCase` for classes and types.
- Import driver.js types rather than redeclaring them; when driver.js does not export a type,
derive it from the public signature as `controller.ts` does for `HookOpts`.
- Keep controllers thin: resolution, persistence, and pure logic belong in `tour-utils.ts` and
`hint-utils.ts`, which is where they are unit tested.
- Guard `localStorage` access; persistence must never break a tour when storage is unavailable.
- Add or update Vitest coverage for behavior changes.
- Rebuild and commit `assets/dist/` whenever published frontend source changes.
## Twig and Components
- Keep Twig auto-escaping enabled. Use raw HTML only when the value is intentionally trusted and
already passed through `PopoverContent` or `ux_driver_html()`.
- Use semantic HTML, labels, and appropriate `aria-*` attributes for interactive controls.
- Emit Stimulus attributes through `stimulus.helper` and the `ux_tour_action()` /
`ux_hints_action()` helpers instead of hardcoding controller identifiers in templates.
- Reuse the existing component templates before adding new variants.
- Keep component props aligned with the matching model setters so both authoring modes accept the
same option names.
## Documentation
Documentation lives in `docs/` and uses Astro with MDX.
- Write concise American English for an international audience.
- Prefer realistic Symfony and driver.js examples over placeholder code.
- Include imports and relevant configuration context in code examples.
- Show the authoring modes consistently: Twig Component, Twig builder, and PHP builder.
- Keep security-sensitive examples aligned with the documented escaping boundary.
- Nav and section order come from the content collection frontmatter `order`; do not reintroduce a
hand-maintained navigation list.
- Keep each subject on a single home page and link to it from the others instead of duplicating
version matrices, event lists, or option tables.
- Keep `README.md` and the docs site in sync on requirements and supported ranges.
## Git and Pull Requests
- Keep commits small and focused on one decision.
- Lead the commit message with intent, then record meaningful constraints, rejected alternatives,
and verification.
- Document completed checks with `Tested:` and any known gaps with `Not-tested:`.
- Do not introduce a project-specific branch naming scheme in this file.
Welcome, AI assistant. Follow these guidelines when contributing to this repository.
UX Driver is a third-party Symfony UX bundle that integrates Driver.js with
Symfony applications. It provides product tours, standalone highlights, and hints, authored either
with Twig Components, the create_tour() / create_hints() Twig builders, or the autowired PHP
builders.
Requirements: PHP 8.2+, Symfony 7.x/8.x, Symfony StimulusBundle 2.x/3.x, Symfony UX TwigComponent 2.x/3.x, Twig 3.8+, Driver.js 1.8+
PHP namespace: Pentiminax\UX\Driver\ maps to src/
Test namespace: Pentiminax\UX\Driver\Tests\ maps to tests/
innerHTML, so they are escaped in PHP by Html\PopoverContent. Never bypass that treatment,
and keep Twig\Markup / ux_driver_html() as the only opt-out for trusted markup.vendor/, any node_modules/ directory, and var/ are managed dependencies or runtime output.docs/dist/ and docs/.astro/ are generated by Astro.assets/dist/ is generated but versioned. Change assets/src/, then rebuild it with
npm run build from assets/; never hand-edit compiled files or source maps. CI enforces this
with git diff --exit-code dist.docs/package-lock.json
and assets/package-lock.json synchronized with their package.json.Twig Components
twig:Driver:Tour / twig:Driver:Step
-> Twig\Components\* + templates/components/*.html.twig
-> data-tour-* attributes (PopoverContent escaping)
-> Stimulus controller (assets/src/controller.ts)
-> driver.js
Builders (Twig create_tour() / PHP TourBuilder)
-> Model\Tour + Model\Step
-> UXDriverExtension::renderTour() + stimulus.helper
-> serialized steps and options values
-> Stimulus controller (assets/src/controller.ts)
-> driver.js
Hints
twig:Driver:Hints / create_hints() / HintsBuilder
-> Model\Hints + Model\Hint
-> assets/src/hints-controller.ts + hint-utils.ts
-> driver.js/hints
Declarative tours collect their steps from Stimulus step targets in DOM order; builder-driven
tours embed the whole step list in the serialized steps value. Both paths converge on the same
Stimulus controller and the same driver.js configuration.
src/Model/, src/Builder/, src/Enum/): Tour, Step, Hints,
Hint, the fluent builders, and the option enums are the primary user-facing surface.src/Twig/, templates/): the Twig functions, the four Twig Components,
and their templates. UXDriverExtension is the single place where Stimulus attributes are
produced.src/Html/PopoverContent.php): the one treatment point for popover content in
both authoring modes.src/DriverBundle.php, config/services.php, config/reference.php):
services are registered explicitly; no implicit autowiring assumptions.assets/src/): the tour controller, the hints controller, and their pure utility
modules (tour-utils.ts, hint-utils.ts) which hold the persistence and resolution logic.Treat documented entry points and downstream-consumed behavior as public contracts. This includes
Tour, Step, Hints, Hint, TourBuilder, HintsBuilder, the enums, the Twig functions
(create_tour, ux_tour, ux_tour_action, ux_highlight, create_hints, ux_hints,
ux_hints_action, ux_driver_html), the Driver:* component keys and their props, the emitted
data-* attribute names, the serialized frontend values, the dispatched Stimulus events, and the
published JavaScript entrypoints declared in assets/package.json.
static or the model itself.peerDependencies and symfony.importmap driver.js ranges aligned; tests/PackageMetadataTest.php
asserts it.autoimport declaration, as asserted by tests/AssetsDistTest.php.Use the repository manifests and CI workflows as the source of truth.
composer install
cd assets
npm install
cd ../docs
npm ci
composer audit
composer fix
composer analyse
vendor/bin/phpunit
vendor/bin/phpunit tests/Model/TourTest.php
vendor/bin/phpunit --filter=test_name
composer fix rewrites PHP files. Review its diff before committing.
Run from assets/:
npm run typecheck
npm test
npm run build
Run from docs/:
npm run check
npm run build
npm run test:build
Run the relevant checks for every changed area:
| Changed area | Required checks |
|---|---|
| PHP source, config, or tests | composer fix, composer audit, composer analyse, vendor/bin/phpunit |
| TypeScript or frontend tests | npm run typecheck, npm test, npm run build in assets/, then commit assets/dist/ |
| Twig templates or serialized payloads | Relevant PHPUnit tests and affected frontend tests |
| Astro/MDX documentation | npm run check, npm run build, npm run test:build in docs/ |
| Contribution documentation | git diff --check and a manual diff review |
PHP-CS-Fixer (.php-cs-fixer.dist.php) is the formatting source of truth. Its rules include PSR-12,
Symfony conventions, strict types, single quotes, ordered imports, native function invocation, and
snake_case PHPUnit method names. PHPStan runs at level 8 over src/ and tests/.
declare(strict_types=1); to PHP files.config/services.php; do not introduce implicit
autowiring assumptions.src/Enum/ already does.assets/src/ compiles to assets/dist/ with tsc.camelCase for variables and functions and UpperCamelCase for classes and types.controller.ts does for HookOpts.tour-utils.ts and
hint-utils.ts, which is where they are unit tested.localStorage access; persistence must never break a tour when storage is unavailable.assets/dist/ whenever published frontend source changes.PopoverContent or ux_driver_html().aria-* attributes for interactive controls.stimulus.helper and the ux_tour_action() /
ux_hints_action() helpers instead of hardcoding controller identifiers in templates.Documentation lives in docs/ and uses Astro with MDX.
order; do not reintroduce a
hand-maintained navigation list.README.md and the docs site in sync on requirements and supported ranges.Tested: and any known gaps with Not-tested:.How can I help you explore Laravel packages today?