Skip to content

Commit 341d6d6

Browse files
authored
feat: rich editor jump anchor plugin (#37)
* feat: jump anchor plugin * docs: updated readme * chore: remove dosc from gitignore * feat: add jump anchor docs * tests: jump anchor test (wip) * wip * change icon * add span with id * Fix styling * let user select attribute * fix: tests * Fix styling * fix: rendering issues * docs: update * fix: imports and change submit action label * Fix styling * remove impossible custom data attribute for now * wip * Fix styling * disable helperText for now * fix: tests * Fix styling * wip * Fix styling * wip * Delete .phpunit.cache/test-results * fix: editing current anchor --------- Co-authored-by: Baspa <[email protected]>
1 parent 85851bd commit 341d6d6

File tree

14 files changed

+865
-45
lines changed

14 files changed

+865
-45
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
build
66
composer.lock
77
coverage
8-
docs
98
node_modules
109
phpunit.xml
1110
phpstan.neon

README.md

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,31 @@ This package aims to help you add dynamic, configurable fields to your Filament
1515

1616
## Features
1717

18-
- 🎯 **Easy Integration**: Seamlessly integrates with your Filament resources
19-
- 🔧 **Configurable Fields**: Add and manage custom fields for your models
20-
- 🎨 **Built-in Field Types**: Includes common Filament form fields like:
21-
- Text
22-
- Textarea
23-
- Rich Text Editor
24-
- Select
25-
- Checkbox
26-
- Checkbox List
27-
- Key-Value
28-
- Radio
29-
- Toggle
30-
- Color Picker
31-
- DateTime
32-
- Tags
33-
-**Extensible**: Create your own custom field types
34-
- 🔄 **Data Mutation**: Hooks to modify field data before filling forms or saving
35-
- 🏢 **Multi-tenant Support**: Built-in support for multi-tenant applications
18+
- 🎯 **Easy Integration**: Seamlessly integrates with your Filament resources
19+
- 🔧 **Configurable Fields**: Add and manage custom fields for your models
20+
- 🎨 **Built-in Field Types**: Includes common Filament form fields like:
21+
- Text
22+
- Textarea
23+
- Rich Text Editor (with Jump Anchor plugin)
24+
- Select
25+
- Checkbox
26+
- Checkbox List
27+
- Key-Value
28+
- Radio
29+
- Toggle
30+
- Color Picker
31+
- DateTime
32+
- Tags
33+
- **Extensible**: Create your own custom field types
34+
- 🔄 **Data Mutation**: Hooks to modify field data before filling forms or saving
35+
- 🏢 **Multi-tenant Support**: Built-in support for multi-tenant applications
3636

3737
This package is perfect for scenarios where you need to:
38-
- Add dynamic custom fields to your models
39-
- Allow users to configure form fields through the admin panel
40-
- Build flexible content management systems
41-
- Create customizable settings pages
4238

39+
- Add dynamic custom fields to your models
40+
- Allow users to configure form fields through the admin panel
41+
- Build flexible content management systems
42+
- Create customizable settings pages
4343

4444
## Installation
4545

@@ -63,7 +63,7 @@ The content of the `fields.php` file is as follows:
6363
<?php
6464

6565
return [
66-
66+
6767
'tenancy' => [
6868
'is_tenant_aware' => true,
6969

@@ -168,7 +168,7 @@ class EditContent extends EditRecord
168168
public function mutateFormDataBeforeSave(array $data): array
169169
{
170170
$this->mutateBeforeSave($data);
171-
171+
172172
return $data;
173173
}
174174
}
@@ -223,7 +223,7 @@ When using select fields, you may want to populate the options with relations in
223223
```php
224224
return [
225225
// ...
226-
226+
227227
'selectable_resources' => [
228228
App\Filament\Resources\ContentResource::class,
229229
]
@@ -247,10 +247,10 @@ class CustomField extends Base
247247
public static function make(string $name, ?Field $field = null): TextInput
248248
{
249249
$input = self::applyDefaultSettings(TextInput::make($name), $field);
250-
250+
251251
// Add your custom field logic here
252252
$input->placeholder('Custom placeholder');
253-
253+
254254
return $input;
255255
}
256256

@@ -299,21 +299,22 @@ class RepeaterField extends Base
299299
```
300300

301301
Available base fields that can be excluded:
302-
- `required` - Required field toggle
303-
- `disabled` - Disabled field toggle
304-
- `hidden` - Hidden field toggle
305-
- `helperText` - Helper text input
306-
- `hint` - Hint text input
307-
- `hintColor` - Hint color picker
308-
- `hintIcon` - Hint icon input
309-
- `defaultValue` - Default value input
302+
303+
- `required` - Required field toggle
304+
- `disabled` - Disabled field toggle
305+
- `hidden` - Hidden field toggle
306+
- `helperText` - Helper text input
307+
- `hint` - Hint text input
308+
- `hintColor` - Hint color picker
309+
- `hintIcon` - Hint icon input
310+
- `defaultValue` - Default value input
310311

311312
#### Best practices for field exclusion
312313

313-
- **Only exclude what doesn't apply**: Don't exclude fields just because you don't use them - only exclude fields that conceptually don't make sense for your field type
314-
- **Document your exclusions**: Add comments explaining why certain fields are excluded
315-
- **Test thoroughly**: Make sure your field still works correctly after excluding base fields
316-
- **Consider inheritance**: If your field extends another custom field, make sure to call `parent::excludeFromBaseSchema()` if you need to add more exclusions
314+
- **Only exclude what doesn't apply**: Don't exclude fields just because you don't use them - only exclude fields that conceptually don't make sense for your field type
315+
- **Document your exclusions**: Add comments explaining why certain fields are excluded
316+
- **Test thoroughly**: Make sure your field still works correctly after excluding base fields
317+
- **Consider inheritance**: If your field extends another custom field, make sure to call `parent::excludeFromBaseSchema()` if you need to add more exclusions
317318

318319
Example of a field that excludes multiple base fields:
319320

@@ -342,6 +343,14 @@ To register your own fields, you can add them to the `fields.fields` config arra
342343
],
343344
```
344345

346+
## Documentation
347+
348+
### Rich Editor Plugins
349+
350+
The package includes a powerful Rich Editor with custom plugins:
351+
352+
- **[Jump Anchor Plugin](docs/jump-anchor-plugin.md)** - Add anchor links to selected text for navigation and jumping to specific sections
353+
345354
## Testing
346355

347356
```bash
@@ -362,8 +371,8 @@ Please review [our security policy](../../security/policy) on how to report secu
362371

363372
## Credits
364373

365-
- [Baspa](https://github.com/Backstage)
366-
- [All Contributors](../../contributors)
374+
- [Baspa](https://github.com/Backstage)
375+
- [All Contributors](../../contributors)
367376

368377
## License
369378

bin/build-rich-editor-plugins.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import * as esbuild from 'esbuild'
2+
import { readdir } from 'fs/promises'
3+
import { join } from 'path'
4+
5+
async function buildRichEditorPlugins() {
6+
try {
7+
// Find all JavaScript plugin files
8+
const pluginsDir = './resources/js/filament/rich-content-plugins'
9+
const files = await readdir(pluginsDir)
10+
const pluginFiles = files.filter(file => file.endsWith('.js'))
11+
12+
if (pluginFiles.length === 0) {
13+
console.log('No rich editor plugin files found to build.')
14+
return
15+
}
16+
17+
console.log(`Found ${pluginFiles.length} plugin file(s) to build:`)
18+
pluginFiles.forEach(file => console.log(` - ${file}`))
19+
20+
// Create entry points for each plugin
21+
const entryPoints = {}
22+
pluginFiles.forEach(file => {
23+
const fileName = file.replace('.js', '')
24+
entryPoints[`filament/rich-content-plugins/${fileName}`] = join(pluginsDir, file)
25+
})
26+
27+
const context = await esbuild.context({
28+
define: {
29+
'process.env.NODE_ENV': `'production'`,
30+
},
31+
bundle: true,
32+
mainFields: ['module', 'main'],
33+
platform: 'neutral',
34+
sourcemap: false,
35+
sourcesContent: false,
36+
treeShaking: true,
37+
target: ['es2020'],
38+
minify: true,
39+
entryPoints,
40+
outdir: './resources/js/dist',
41+
format: 'esm',
42+
})
43+
44+
await context.rebuild()
45+
await context.dispose()
46+
47+
console.log('✅ Rich editor plugins built successfully!')
48+
console.log('Built files:')
49+
Object.keys(entryPoints).forEach(key => {
50+
console.log(` - resources/js/dist/${key}.js`)
51+
})
52+
} catch (error) {
53+
console.error('❌ Error building rich editor plugins:', error)
54+
process.exit(1)
55+
}
56+
}
57+
58+
buildRichEditorPlugins()

docs/jump-anchor-plugin.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Jump Anchor Plugin
2+
3+
Add anchor links to rich editor content for navigation.
4+
5+
## Features
6+
7+
- Add anchor links to selected text
8+
- Uses standard HTML `id` attributes
9+
- Hashtag icon in the toolbar
10+
- Modal interface for configuration
11+
- Automatic ID generation
12+
13+
## Usage
14+
15+
1. Build the JavaScript extension:
16+
17+
```bash
18+
node bin/build-rich-editor-plugins.js
19+
```
20+
21+
2. Publish assets:
22+
23+
```bash
24+
php artisan filament:assets
25+
```
26+
27+
3. Use in rich editor:
28+
- Select text
29+
- Click hashtag button in toolbar
30+
- Enter anchor ID
31+
32+
## HTML Output
33+
34+
```html
35+
<span id="section-1">Selected Text</span>
36+
```
37+
38+
## Validation
39+
40+
Anchor IDs must contain only letters, numbers, hyphens, and underscores.
41+
42+
## Troubleshooting
43+
44+
- Build extension: `node bin/build-rich-editor-plugins.js`
45+
- Publish assets: `php artisan filament:assets`
46+
- Clear caches: `php artisan cache:clear`

0 commit comments

Comments
 (0)